aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Kconfig2
-rw-r--r--drivers/Makefile3
-rw-r--r--drivers/acorn/block/mfmhd.c1
-rw-r--r--drivers/acorn/char/i2c.c3
-rw-r--r--drivers/acpi/Kconfig47
-rw-r--r--drivers/acpi/Makefile6
-rw-r--r--drivers/acpi/ac.c9
-rw-r--r--drivers/acpi/acpi_memhotplug.c9
-rw-r--r--drivers/acpi/asus_acpi.c36
-rw-r--r--drivers/acpi/battery.c28
-rw-r--r--drivers/acpi/bay.c397
-rw-r--r--drivers/acpi/blacklist.c29
-rw-r--r--drivers/acpi/bus.c74
-rw-r--r--drivers/acpi/button.c9
-rw-r--r--drivers/acpi/cm_sbs.c2
-rw-r--r--drivers/acpi/container.c15
-rw-r--r--drivers/acpi/debug.c64
-rw-r--r--drivers/acpi/dispatcher/dsfield.c32
-rw-r--r--drivers/acpi/dispatcher/dsinit.c25
-rw-r--r--drivers/acpi/dispatcher/dsmethod.c67
-rw-r--r--drivers/acpi/dispatcher/dsmthdat.c2
-rw-r--r--drivers/acpi/dispatcher/dsobject.c78
-rw-r--r--drivers/acpi/dispatcher/dsopcode.c6
-rw-r--r--drivers/acpi/dispatcher/dsutils.c2
-rw-r--r--drivers/acpi/dispatcher/dswexec.c12
-rw-r--r--drivers/acpi/dispatcher/dswload.c19
-rw-r--r--drivers/acpi/dispatcher/dswscope.c2
-rw-r--r--drivers/acpi/dispatcher/dswstate.c2
-rw-r--r--drivers/acpi/dock.c24
-rw-r--r--drivers/acpi/ec.c22
-rw-r--r--drivers/acpi/event.c2
-rw-r--r--drivers/acpi/events/evevent.c17
-rw-r--r--drivers/acpi/events/evgpe.c84
-rw-r--r--drivers/acpi/events/evgpeblk.c64
-rw-r--r--drivers/acpi/events/evmisc.c212
-rw-r--r--drivers/acpi/events/evregion.c17
-rw-r--r--drivers/acpi/events/evrgnini.c168
-rw-r--r--drivers/acpi/events/evsci.c14
-rw-r--r--drivers/acpi/events/evxface.c8
-rw-r--r--drivers/acpi/events/evxfevnt.c27
-rw-r--r--drivers/acpi/events/evxfregn.c2
-rw-r--r--drivers/acpi/executer/exconfig.c235
-rw-r--r--drivers/acpi/executer/exconvrt.c2
-rw-r--r--drivers/acpi/executer/excreate.c21
-rw-r--r--drivers/acpi/executer/exdump.c31
-rw-r--r--drivers/acpi/executer/exfield.c2
-rw-r--r--drivers/acpi/executer/exfldio.c7
-rw-r--r--drivers/acpi/executer/exmisc.c2
-rw-r--r--drivers/acpi/executer/exmutex.c110
-rw-r--r--drivers/acpi/executer/exnames.c2
-rw-r--r--drivers/acpi/executer/exoparg1.c4
-rw-r--r--drivers/acpi/executer/exoparg2.c2
-rw-r--r--drivers/acpi/executer/exoparg3.c2
-rw-r--r--drivers/acpi/executer/exoparg6.c2
-rw-r--r--drivers/acpi/executer/exprep.c2
-rw-r--r--drivers/acpi/executer/exregion.c16
-rw-r--r--drivers/acpi/executer/exresnte.c2
-rw-r--r--drivers/acpi/executer/exresolv.c10
-rw-r--r--drivers/acpi/executer/exresop.c12
-rw-r--r--drivers/acpi/executer/exstore.c2
-rw-r--r--drivers/acpi/executer/exstoren.c2
-rw-r--r--drivers/acpi/executer/exstorob.c2
-rw-r--r--drivers/acpi/executer/exsystem.c110
-rw-r--r--drivers/acpi/executer/exutils.c106
-rw-r--r--drivers/acpi/fan.c17
-rw-r--r--drivers/acpi/glue.c185
-rw-r--r--drivers/acpi/hardware/hwacpi.c56
-rw-r--r--drivers/acpi/hardware/hwgpe.c15
-rw-r--r--drivers/acpi/hardware/hwregs.c98
-rw-r--r--drivers/acpi/hardware/hwsleep.c94
-rw-r--r--drivers/acpi/hardware/hwtimer.c9
-rw-r--r--drivers/acpi/hotkey.c1042
-rw-r--r--drivers/acpi/i2c_ec.c7
-rw-r--r--drivers/acpi/ibm_acpi.c26
-rw-r--r--drivers/acpi/motherboard.c191
-rw-r--r--drivers/acpi/namespace/nsaccess.c36
-rw-r--r--drivers/acpi/namespace/nsalloc.c14
-rw-r--r--drivers/acpi/namespace/nsdump.c13
-rw-r--r--drivers/acpi/namespace/nsdumpdv.c2
-rw-r--r--drivers/acpi/namespace/nseval.c13
-rw-r--r--drivers/acpi/namespace/nsinit.c18
-rw-r--r--drivers/acpi/namespace/nsload.c160
-rw-r--r--drivers/acpi/namespace/nsnames.c2
-rw-r--r--drivers/acpi/namespace/nsobject.c2
-rw-r--r--drivers/acpi/namespace/nsparse.c52
-rw-r--r--drivers/acpi/namespace/nssearch.c9
-rw-r--r--drivers/acpi/namespace/nsutils.c9
-rw-r--r--drivers/acpi/namespace/nswalk.c65
-rw-r--r--drivers/acpi/namespace/nsxfeval.c13
-rw-r--r--drivers/acpi/namespace/nsxfname.c47
-rw-r--r--drivers/acpi/namespace/nsxfobj.c2
-rw-r--r--drivers/acpi/numa.c87
-rw-r--r--drivers/acpi/osl.c130
-rw-r--r--drivers/acpi/parser/psargs.c2
-rw-r--r--drivers/acpi/parser/psloop.c1408
-rw-r--r--drivers/acpi/parser/psopcode.c2
-rw-r--r--drivers/acpi/parser/psparse.c7
-rw-r--r--drivers/acpi/parser/psscope.c2
-rw-r--r--drivers/acpi/parser/pstree.c2
-rw-r--r--drivers/acpi/parser/psutils.c2
-rw-r--r--drivers/acpi/parser/pswalk.c2
-rw-r--r--drivers/acpi/parser/psxface.c116
-rw-r--r--drivers/acpi/pci_bind.c2
-rw-r--r--drivers/acpi/pci_irq.c2
-rw-r--r--drivers/acpi/pci_link.c9
-rw-r--r--drivers/acpi/pci_root.c43
-rw-r--r--drivers/acpi/power.c156
-rw-r--r--drivers/acpi/processor_core.c198
-rw-r--r--drivers/acpi/processor_idle.c177
-rw-r--r--drivers/acpi/processor_perflib.c30
-rw-r--r--drivers/acpi/processor_thermal.c3
-rw-r--r--drivers/acpi/processor_throttling.c7
-rw-r--r--drivers/acpi/resources/rsaddr.c2
-rw-r--r--drivers/acpi/resources/rscalc.c2
-rw-r--r--drivers/acpi/resources/rscreate.c2
-rw-r--r--drivers/acpi/resources/rsdump.c2
-rw-r--r--drivers/acpi/resources/rsinfo.c2
-rw-r--r--drivers/acpi/resources/rsio.c2
-rw-r--r--drivers/acpi/resources/rsirq.c2
-rw-r--r--drivers/acpi/resources/rslist.c2
-rw-r--r--drivers/acpi/resources/rsmemory.c2
-rw-r--r--drivers/acpi/resources/rsmisc.c2
-rw-r--r--drivers/acpi/resources/rsutils.c2
-rw-r--r--drivers/acpi/resources/rsxface.c2
-rw-r--r--drivers/acpi/sbs.c25
-rw-r--r--drivers/acpi/scan.c1268
-rw-r--r--drivers/acpi/sleep/main.c3
-rw-r--r--drivers/acpi/sleep/poweroff.c1
-rw-r--r--drivers/acpi/sleep/proc.c36
-rw-r--r--drivers/acpi/system.c42
-rw-r--r--drivers/acpi/tables.c536
-rw-r--r--drivers/acpi/tables/Makefile3
-rw-r--r--drivers/acpi/tables/tbconvrt.c622
-rw-r--r--drivers/acpi/tables/tbfadt.c434
-rw-r--r--drivers/acpi/tables/tbfind.c126
-rw-r--r--drivers/acpi/tables/tbget.c471
-rw-r--r--drivers/acpi/tables/tbgetall.c311
-rw-r--r--drivers/acpi/tables/tbinstal.c664
-rw-r--r--drivers/acpi/tables/tbrsdt.c307
-rw-r--r--drivers/acpi/tables/tbutils.c513
-rw-r--r--drivers/acpi/tables/tbxface.c676
-rw-r--r--drivers/acpi/tables/tbxfroot.c552
-rw-r--r--drivers/acpi/thermal.c44
-rw-r--r--drivers/acpi/toshiba_acpi.c13
-rw-r--r--drivers/acpi/utilities/utalloc.c11
-rw-r--r--drivers/acpi/utilities/utcache.c10
-rw-r--r--drivers/acpi/utilities/utcopy.c11
-rw-r--r--drivers/acpi/utilities/utdebug.c7
-rw-r--r--drivers/acpi/utilities/utdelete.c15
-rw-r--r--drivers/acpi/utilities/uteval.c2
-rw-r--r--drivers/acpi/utilities/utglobal.c199
-rw-r--r--drivers/acpi/utilities/utinit.c114
-rw-r--r--drivers/acpi/utilities/utmath.c2
-rw-r--r--drivers/acpi/utilities/utmisc.c102
-rw-r--r--drivers/acpi/utilities/utmutex.c2
-rw-r--r--drivers/acpi/utilities/utobject.c2
-rw-r--r--drivers/acpi/utilities/utresrc.c2
-rw-r--r--drivers/acpi/utilities/utstate.c2
-rw-r--r--drivers/acpi/utilities/utxface.c29
-rw-r--r--drivers/acpi/utils.c2
-rw-r--r--drivers/acpi/video.c163
-rw-r--r--drivers/ata/Kconfig54
-rw-r--r--drivers/ata/Makefile5
-rw-r--r--drivers/ata/ahci.c239
-rw-r--r--drivers/ata/ata_generic.c8
-rw-r--r--drivers/ata/ata_piix.c56
-rw-r--r--drivers/ata/libata-acpi.c698
-rw-r--r--drivers/ata/libata-core.c616
-rw-r--r--drivers/ata/libata-eh.c7
-rw-r--r--drivers/ata/libata-scsi.c98
-rw-r--r--drivers/ata/libata-sff.c641
-rw-r--r--drivers/ata/libata.h19
-rw-r--r--drivers/ata/pata_ali.c32
-rw-r--r--drivers/ata/pata_amd.c36
-rw-r--r--drivers/ata/pata_artop.c12
-rw-r--r--drivers/ata/pata_atiixp.c6
-rw-r--r--drivers/ata/pata_cmd64x.c18
-rw-r--r--drivers/ata/pata_cs5520.c41
-rw-r--r--drivers/ata/pata_cs5530.c41
-rw-r--r--drivers/ata/pata_cs5535.c6
-rw-r--r--drivers/ata/pata_cypress.c6
-rw-r--r--drivers/ata/pata_efar.c6
-rw-r--r--drivers/ata/pata_hpt366.c26
-rw-r--r--drivers/ata/pata_hpt37x.c61
-rw-r--r--drivers/ata/pata_hpt3x2n.c26
-rw-r--r--drivers/ata/pata_hpt3x3.c8
-rw-r--r--drivers/ata/pata_isapnp.c21
-rw-r--r--drivers/ata/pata_it8213.c354
-rw-r--r--drivers/ata/pata_it821x.c58
-rw-r--r--drivers/ata/pata_ixp4xx_cf.c50
-rw-r--r--drivers/ata/pata_jmicron.c8
-rw-r--r--drivers/ata/pata_legacy.c177
-rw-r--r--drivers/ata/pata_marvell.c12
-rw-r--r--drivers/ata/pata_mpc52xx.c536
-rw-r--r--drivers/ata/pata_mpiix.c113
-rw-r--r--drivers/ata/pata_netcell.c6
-rw-r--r--drivers/ata/pata_ns87410.c6
-rw-r--r--drivers/ata/pata_oldpiix.c24
-rw-r--r--drivers/ata/pata_opti.c24
-rw-r--r--drivers/ata/pata_optidma.c40
-rw-r--r--drivers/ata/pata_pcmcia.c29
-rw-r--r--drivers/ata/pata_pdc2027x.c124
-rw-r--r--drivers/ata/pata_pdc202xx_old.c41
-rw-r--r--drivers/ata/pata_platform.c67
-rw-r--r--drivers/ata/pata_qdi.c54
-rw-r--r--drivers/ata/pata_radisys.c6
-rw-r--r--drivers/ata/pata_rz1000.c6
-rw-r--r--drivers/ata/pata_sc1200.c6
-rw-r--r--drivers/ata/pata_serverworks.c31
-rw-r--r--drivers/ata/pata_sil680.c8
-rw-r--r--drivers/ata/pata_sis.c70
-rw-r--r--drivers/ata/pata_sl82c105.c13
-rw-r--r--drivers/ata/pata_triflex.c6
-rw-r--r--drivers/ata/pata_via.c22
-rw-r--r--drivers/ata/pata_winbond.c49
-rw-r--r--drivers/ata/pdc_adma.c121
-rw-r--r--drivers/ata/sata_inic162x.c781
-rw-r--r--drivers/ata/sata_mv.c201
-rw-r--r--drivers/ata/sata_nv.c633
-rw-r--r--drivers/ata/sata_promise.c444
-rw-r--r--drivers/ata/sata_qstor.c139
-rw-r--r--drivers/ata/sata_sil.c99
-rw-r--r--drivers/ata/sata_sil24.c178
-rw-r--r--drivers/ata/sata_sis.c161
-rw-r--r--drivers/ata/sata_svw.c133
-rw-r--r--drivers/ata/sata_sx4.c208
-rw-r--r--drivers/ata/sata_uli.c66
-rw-r--r--drivers/ata/sata_via.c193
-rw-r--r--drivers/ata/sata_vsc.c142
-rw-r--r--drivers/atm/adummy.c1
-rw-r--r--drivers/atm/eni.c1
-rw-r--r--drivers/atm/fore200e.c1
-rw-r--r--drivers/atm/he.c2
-rw-r--r--drivers/atm/idt77105.c1
-rw-r--r--drivers/atm/idt77252.c8
-rw-r--r--drivers/atm/nicstarmac.c4
-rw-r--r--drivers/atm/uPD98402.c1
-rw-r--r--drivers/atm/zatm.c1
-rw-r--r--drivers/auxdisplay/Kconfig109
-rw-r--r--drivers/auxdisplay/Makefile6
-rw-r--r--drivers/auxdisplay/cfag12864b.c402
-rw-r--r--drivers/auxdisplay/cfag12864bfb.c188
-rw-r--r--drivers/auxdisplay/ks0108.c178
-rw-r--r--drivers/base/Kconfig12
-rw-r--r--drivers/base/Makefile1
-rw-r--r--drivers/base/base.h1
-rw-r--r--drivers/base/bus.c22
-rw-r--r--drivers/base/class.c54
-rw-r--r--drivers/base/core.c250
-rw-r--r--drivers/base/cpu.c2
-rw-r--r--drivers/base/dd.c24
-rw-r--r--drivers/base/devres.c644
-rw-r--r--drivers/base/dma-mapping.c218
-rw-r--r--drivers/base/dmapool.c59
-rw-r--r--drivers/base/firmware_class.c2
-rw-r--r--drivers/base/node.c11
-rw-r--r--drivers/base/platform.c11
-rw-r--r--drivers/block/DAC960.c101
-rw-r--r--drivers/block/DAC960.h495
-rw-r--r--drivers/block/Kconfig4
-rw-r--r--drivers/block/acsi.c1
-rw-r--r--drivers/block/acsi_slm.c2
-rw-r--r--drivers/block/aoe/aoechr.c2
-rw-r--r--drivers/block/floppy.c12
-rw-r--r--drivers/block/paride/Kconfig8
-rw-r--r--drivers/block/paride/pd.c1
-rw-r--r--drivers/block/paride/pg.c2
-rw-r--r--drivers/block/paride/pt.c2
-rw-r--r--drivers/block/pktcdvd.c34
-rw-r--r--drivers/block/umem.c1
-rw-r--r--drivers/bluetooth/bcm203x.c2
-rw-r--r--drivers/bluetooth/bfusb.c2
-rw-r--r--drivers/bluetooth/bt3c_cs.c2
-rw-r--r--drivers/bluetooth/btuart_cs.c1
-rw-r--r--drivers/bluetooth/dtl1_cs.c1
-rw-r--r--drivers/bluetooth/hci_bcsp.c1
-rw-r--r--drivers/bluetooth/hci_h4.c1
-rw-r--r--drivers/bluetooth/hci_ldisc.c1
-rw-r--r--drivers/bluetooth/hci_usb.c1
-rw-r--r--drivers/bluetooth/hci_vhci.c2
-rw-r--r--drivers/cdrom/aztcd.c1
-rw-r--r--drivers/cdrom/cdrom.c4
-rw-r--r--drivers/cdrom/cm206.c1
-rw-r--r--drivers/cdrom/gscd.c1
-rw-r--r--drivers/cdrom/sjcd.c1
-rw-r--r--drivers/cdrom/viocd.c2
-rw-r--r--drivers/char/Kconfig11
-rw-r--r--drivers/char/Makefile3
-rw-r--r--drivers/char/agp/Makefile2
-rw-r--r--drivers/char/agp/agp.h20
-rw-r--r--drivers/char/agp/ali-agp.c8
-rw-r--r--drivers/char/agp/alpha-agp.c4
-rw-r--r--drivers/char/agp/amd-k7-agp.c7
-rw-r--r--drivers/char/agp/amd64-agp.c15
-rw-r--r--drivers/char/agp/ati-agp.c5
-rw-r--r--drivers/char/agp/backend.c2
-rw-r--r--drivers/char/agp/compat_ioctl.c282
-rw-r--r--drivers/char/agp/compat_ioctl.h105
-rw-r--r--drivers/char/agp/efficeon-agp.c7
-rw-r--r--drivers/char/agp/frontend.c34
-rw-r--r--drivers/char/agp/generic.c127
-rw-r--r--drivers/char/agp/hp-agp.c3
-rw-r--r--drivers/char/agp/i460-agp.c11
-rw-r--r--drivers/char/agp/intel-agp.c240
-rw-r--r--drivers/char/agp/nvidia-agp.c7
-rw-r--r--drivers/char/agp/parisc-agp.c3
-rw-r--r--drivers/char/agp/sgi-agp.c3
-rw-r--r--drivers/char/agp/sis-agp.c3
-rw-r--r--drivers/char/agp/sworks-agp.c7
-rw-r--r--drivers/char/agp/uninorth-agp.c10
-rw-r--r--drivers/char/agp/via-agp.c8
-rw-r--r--drivers/char/amiserial.c8
-rw-r--r--drivers/char/apm-emulation.c672
-rw-r--r--drivers/char/briq_panel.c3
-rw-r--r--drivers/char/cyclades.c24
-rw-r--r--drivers/char/drm/drmP.h36
-rw-r--r--drivers/char/drm/drm_bufs.c19
-rw-r--r--drivers/char/drm/drm_drv.c2
-rw-r--r--drivers/char/drm/drm_memory.c94
-rw-r--r--drivers/char/drm/drm_memory.h20
-rw-r--r--drivers/char/drm/drm_memory_debug.h70
-rw-r--r--drivers/char/drm/drm_mm.c183
-rw-r--r--drivers/char/drm/drm_pciids.h4
-rw-r--r--drivers/char/drm/drm_proc.c4
-rw-r--r--drivers/char/drm/drm_sman.c3
-rw-r--r--drivers/char/drm/drm_vm.c16
-rw-r--r--drivers/char/drm/ffb_context.c1
-rw-r--r--drivers/char/drm/ffb_drv.c1
-rw-r--r--drivers/char/drm/i810_dma.c36
-rw-r--r--drivers/char/drm/i810_drv.h2
-rw-r--r--drivers/char/drm/i830_dma.c34
-rw-r--r--drivers/char/drm/i830_drv.h2
-rw-r--r--drivers/char/drm/via_dma.c9
-rw-r--r--drivers/char/drm/via_dmablit.c16
-rw-r--r--drivers/char/drm/via_drv.h11
-rw-r--r--drivers/char/drm/via_irq.c16
-rw-r--r--drivers/char/drm/via_map.c3
-rw-r--r--drivers/char/drm/via_verifier.c50
-rw-r--r--drivers/char/drm/via_verifier.h1
-rw-r--r--drivers/char/ds1302.c2
-rw-r--r--drivers/char/ds1620.c1
-rw-r--r--drivers/char/dsp56k.c1
-rw-r--r--drivers/char/dtlk.c8
-rw-r--r--drivers/char/epca.c3
-rw-r--r--drivers/char/generic_nvram.c2
-rw-r--r--drivers/char/generic_serial.c1
-rw-r--r--drivers/char/hangcheck-timer.c2
-rw-r--r--drivers/char/hpet.c6
-rw-r--r--drivers/char/hvc_beat.c134
-rw-r--r--drivers/char/hvsi.c1
-rw-r--r--drivers/char/hw_random/intel-rng.c76
-rw-r--r--drivers/char/ip2/i2lib.c40
-rw-r--r--drivers/char/ip2/ip2main.c4
-rw-r--r--drivers/char/ipmi/ipmi_devintf.c1
-rw-r--r--drivers/char/ipmi/ipmi_msghandler.c31
-rw-r--r--drivers/char/ipmi/ipmi_poweroff.c2
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c18
-rw-r--r--drivers/char/isicom.c108
-rw-r--r--drivers/char/istallion.c1
-rw-r--r--drivers/char/keyboard.c11
-rw-r--r--drivers/char/lcd.c168
-rw-r--r--drivers/char/lcd.h32
-rw-r--r--drivers/char/mbcs.c2
-rw-r--r--drivers/char/moxa.c927
-rw-r--r--drivers/char/mspec.c6
-rw-r--r--drivers/char/mwave/3780i.c14
-rw-r--r--drivers/char/mxser.c11
-rw-r--r--drivers/char/mxser.h8
-rw-r--r--drivers/char/mxser_new.c236
-rw-r--r--drivers/char/mxser_new.h477
-rw-r--r--drivers/char/n_r3964.c2095
-rw-r--r--drivers/char/n_tty.c14
-rw-r--r--drivers/char/nvram.c1
-rw-r--r--drivers/char/nwbutton.c13
-rw-r--r--drivers/char/nwflash.c1
-rw-r--r--drivers/char/pcmcia/cm4000_cs.c10
-rw-r--r--drivers/char/pcmcia/cm4040_cs.c3
-rw-r--r--drivers/char/pcmcia/synclink_cs.c14
-rw-r--r--drivers/char/pty.c1
-rw-r--r--drivers/char/random.c4
-rw-r--r--drivers/char/raw.c2
-rw-r--r--drivers/char/rio/rio_linux.c14
-rw-r--r--drivers/char/rio/riointr.c9
-rw-r--r--drivers/char/riscom8.c5
-rw-r--r--drivers/char/rocket.c13
-rw-r--r--drivers/char/rtc.c20
-rw-r--r--drivers/char/scan_keyb.c149
-rw-r--r--drivers/char/scan_keyb.h15
-rw-r--r--drivers/char/ser_a2232.c1
-rw-r--r--drivers/char/serial167.c3322
-rw-r--r--drivers/char/sonypi.c1
-rw-r--r--drivers/char/specialix.c18
-rw-r--r--drivers/char/synclink.c15
-rw-r--r--drivers/char/synclink_gt.c24
-rw-r--r--drivers/char/synclinkmp.c27
-rw-r--r--drivers/char/sysrq.c19
-rw-r--r--drivers/char/tlclk.c1
-rw-r--r--drivers/char/toshiba.c36
-rw-r--r--drivers/char/tpm/tpm.c6
-rw-r--r--drivers/char/tpm/tpm_bios.c12
-rw-r--r--drivers/char/tty_io.c254
-rw-r--r--drivers/char/tty_ioctl.c45
-rw-r--r--drivers/char/vc_screen.c1
-rw-r--r--drivers/char/viotape.c2
-rw-r--r--drivers/char/vme_scc.c1
-rw-r--r--drivers/char/vt.c12
-rw-r--r--drivers/char/vt_ioctl.c28
-rw-r--r--drivers/char/watchdog/acquirewdt.c155
-rw-r--r--drivers/char/watchdog/advantechwdt.c142
-rw-r--r--drivers/char/watchdog/alim1535_wdt.c2
-rw-r--r--drivers/char/watchdog/alim7101_wdt.c21
-rw-r--r--drivers/char/watchdog/booke_wdt.c20
-rw-r--r--drivers/char/watchdog/cpu5wdt.c13
-rw-r--r--drivers/char/watchdog/eurotechwdt.c2
-rw-r--r--drivers/char/watchdog/i6300esb.c2
-rw-r--r--drivers/char/watchdog/i8xx_tco.c2
-rw-r--r--drivers/char/watchdog/iTCO_wdt.c8
-rw-r--r--drivers/char/watchdog/ib700wdt.c192
-rw-r--r--drivers/char/watchdog/ibmasr.c2
-rw-r--r--drivers/char/watchdog/indydog.c2
-rw-r--r--drivers/char/watchdog/machzwd.c18
-rw-r--r--drivers/char/watchdog/mixcomwd.c16
-rw-r--r--drivers/char/watchdog/omap_wdt.c2
-rw-r--r--drivers/char/watchdog/pc87413_wdt.c4
-rw-r--r--drivers/char/watchdog/pcwd.c32
-rw-r--r--drivers/char/watchdog/pcwd_pci.c34
-rw-r--r--drivers/char/watchdog/pcwd_usb.c63
-rw-r--r--drivers/char/watchdog/pnx4008_wdt.c5
-rw-r--r--drivers/char/watchdog/rm9k_wdt.c4
-rw-r--r--drivers/char/watchdog/s3c2410_wdt.c62
-rw-r--r--drivers/char/watchdog/sbc60xxwdt.c14
-rw-r--r--drivers/char/watchdog/sbc8360.c2
-rw-r--r--drivers/char/watchdog/sbc_epx_c3.c2
-rw-r--r--drivers/char/watchdog/sc1200wdt.c2
-rw-r--r--drivers/char/watchdog/sc520_wdt.c14
-rw-r--r--drivers/char/watchdog/shwdt.c8
-rw-r--r--drivers/char/watchdog/smsc37b787_wdt.c4
-rw-r--r--drivers/char/watchdog/softdog.c2
-rw-r--r--drivers/char/watchdog/w83627hf_wdt.c2
-rw-r--r--drivers/char/watchdog/w83697hf_wdt.c4
-rw-r--r--drivers/char/watchdog/w83877f_wdt.c14
-rw-r--r--drivers/char/watchdog/w83977f_wdt.c2
-rw-r--r--drivers/char/watchdog/wafer5823wdt.c2
-rw-r--r--drivers/char/watchdog/wdt.c2
-rw-r--r--drivers/char/watchdog/wdt977.c2
-rw-r--r--drivers/char/watchdog/wdt_pci.c2
-rw-r--r--drivers/clocksource/acpi_pm.c20
-rw-r--r--drivers/clocksource/cyclone.c2
-rw-r--r--drivers/clocksource/scx200_hrt.c2
-rw-r--r--drivers/cpufreq/Kconfig2
-rw-r--r--drivers/cpufreq/cpufreq.c258
-rw-r--r--drivers/cpufreq/cpufreq_conservative.c3
-rw-r--r--drivers/cpufreq/cpufreq_ondemand.c64
-rw-r--r--drivers/cpufreq/cpufreq_stats.c2
-rw-r--r--drivers/cpufreq/cpufreq_userspace.c2
-rw-r--r--drivers/crypto/Kconfig2
-rw-r--r--drivers/crypto/geode-aes.c3
-rw-r--r--drivers/edac/e752x_edac.c40
-rw-r--r--drivers/edac/edac_mc.c175
-rw-r--r--drivers/edac/edac_mc.h28
-rw-r--r--drivers/fc4/fc_syms.c1
-rw-r--r--drivers/fc4/soc.c1
-rw-r--r--drivers/fc4/socal.c1
-rw-r--r--drivers/firmware/edd.c8
-rw-r--r--drivers/firmware/pcdp.c2
-rw-r--r--drivers/hid/Kconfig14
-rw-r--r--drivers/hid/Makefile11
-rw-r--r--drivers/hid/hid-core.c9
-rw-r--r--drivers/hid/hid-debug.c764
-rw-r--r--drivers/hid/hid-input.c35
-rw-r--r--drivers/hwmon/Kconfig11
-rw-r--r--drivers/hwmon/Makefile1
-rw-r--r--drivers/hwmon/abituguru.c30
-rw-r--r--drivers/hwmon/adm1026.c1
-rw-r--r--drivers/hwmon/adm1029.c508
-rw-r--r--drivers/hwmon/ams/ams-input.c2
-rw-r--r--drivers/hwmon/f71805f.c30
-rw-r--r--drivers/hwmon/hwmon.c2
-rw-r--r--drivers/hwmon/it87.c84
-rw-r--r--drivers/hwmon/lm70.c2
-rw-r--r--drivers/hwmon/lm78.c6
-rw-r--r--drivers/hwmon/lm85.c8
-rw-r--r--drivers/hwmon/sis5595.c6
-rw-r--r--drivers/hwmon/via686a.c5
-rw-r--r--drivers/hwmon/vt1211.c58
-rw-r--r--drivers/hwmon/vt8231.c1
-rw-r--r--drivers/hwmon/w83627ehf.c54
-rw-r--r--drivers/hwmon/w83627hf.c5
-rw-r--r--drivers/hwmon/w83781d.c10
-rw-r--r--drivers/i2c/busses/Kconfig13
-rw-r--r--drivers/i2c/busses/Makefile1
-rw-r--r--drivers/i2c/busses/i2c-ali1535.c4
-rw-r--r--drivers/i2c/busses/i2c-ali1563.c58
-rw-r--r--drivers/i2c/busses/i2c-ali15x3.c4
-rw-r--r--drivers/i2c/busses/i2c-amd756-s4882.c2
-rw-r--r--drivers/i2c/busses/i2c-amd756.c4
-rw-r--r--drivers/i2c/busses/i2c-amd8111.c74
-rw-r--r--drivers/i2c/busses/i2c-i801.c6
-rw-r--r--drivers/i2c/busses/i2c-i810.c2
-rw-r--r--drivers/i2c/busses/i2c-ibm_iic.c1
-rw-r--r--drivers/i2c/busses/i2c-iop3xx.c3
-rw-r--r--drivers/i2c/busses/i2c-isa.c1
-rw-r--r--drivers/i2c/busses/i2c-mv64xxx.c1
-rw-r--r--drivers/i2c/busses/i2c-nforce2.c4
-rw-r--r--drivers/i2c/busses/i2c-ocores.c1
-rw-r--r--drivers/i2c/busses/i2c-parport.h8
-rw-r--r--drivers/i2c/busses/i2c-pasemi.c426
-rw-r--r--drivers/i2c/busses/i2c-piix4.c7
-rw-r--r--drivers/i2c/busses/i2c-powermac.c1
-rw-r--r--drivers/i2c/busses/i2c-pxa.c241
-rw-r--r--drivers/i2c/busses/i2c-s3c2410.c1
-rw-r--r--drivers/i2c/busses/i2c-savage4.c1
-rw-r--r--drivers/i2c/busses/i2c-sis5595.c3
-rw-r--r--drivers/i2c/busses/i2c-sis630.c3
-rw-r--r--drivers/i2c/busses/i2c-sis96x.c4
-rw-r--r--drivers/i2c/busses/i2c-via.c3
-rw-r--r--drivers/i2c/busses/i2c-viapro.c7
-rw-r--r--drivers/i2c/busses/i2c-voodoo3.c2
-rw-r--r--drivers/i2c/busses/scx200_acb.c7
-rw-r--r--drivers/i2c/busses/scx200_i2c.c1
-rw-r--r--drivers/i2c/chips/eeprom.c1
-rw-r--r--drivers/i2c/chips/isp1301_omap.c2
-rw-r--r--drivers/i2c/chips/tps65010.c2
-rw-r--r--drivers/i2c/i2c-core.c71
-rw-r--r--drivers/i2c/i2c-dev.c2
-rw-r--r--drivers/ide/Kconfig35
-rw-r--r--drivers/ide/Makefile2
-rw-r--r--drivers/ide/arm/icside.c25
-rw-r--r--drivers/ide/arm/rapide.c2
-rw-r--r--drivers/ide/cris/ide-cris.c34
-rw-r--r--drivers/ide/h8300/ide-h8300.c4
-rw-r--r--drivers/ide/ide-acpi.c697
-rw-r--r--drivers/ide/ide-cd.c44
-rw-r--r--drivers/ide/ide-disk.c14
-rw-r--r--drivers/ide/ide-dma.c105
-rw-r--r--drivers/ide/ide-floppy.c29
-rw-r--r--drivers/ide/ide-io.c15
-rw-r--r--drivers/ide/ide-iops.c34
-rw-r--r--drivers/ide/ide-lib.c20
-rw-r--r--drivers/ide/ide-probe.c7
-rw-r--r--drivers/ide/ide-proc.c4
-rw-r--r--drivers/ide/ide-tape.c14
-rw-r--r--drivers/ide/ide.c60
-rw-r--r--drivers/ide/legacy/buddha.c2
-rw-r--r--drivers/ide/legacy/gayle.c2
-rw-r--r--drivers/ide/legacy/ht6560b.c14
-rw-r--r--drivers/ide/legacy/ide-cs.c1
-rw-r--r--drivers/ide/legacy/macide.c2
-rw-r--r--drivers/ide/legacy/q40ide.c2
-rw-r--r--drivers/ide/mips/au1xxx-ide.c41
-rw-r--r--drivers/ide/mips/swarm.c2
-rw-r--r--drivers/ide/pci/Makefile4
-rw-r--r--drivers/ide/pci/aec62xx.c32
-rw-r--r--drivers/ide/pci/alim15x3.c15
-rw-r--r--drivers/ide/pci/amd74xx.c5
-rw-r--r--drivers/ide/pci/atiixp.c41
-rw-r--r--drivers/ide/pci/cmd64x.c47
-rw-r--r--drivers/ide/pci/cs5520.c5
-rw-r--r--drivers/ide/pci/cs5530.c41
-rw-r--r--drivers/ide/pci/cs5535.c19
-rw-r--r--drivers/ide/pci/cy82c693.c33
-rw-r--r--drivers/ide/pci/delkin_cb.c140
-rw-r--r--drivers/ide/pci/hpt34x.c42
-rw-r--r--drivers/ide/pci/hpt366.c1599
-rw-r--r--drivers/ide/pci/it8213.c360
-rw-r--r--drivers/ide/pci/it821x.c14
-rw-r--r--drivers/ide/pci/jmicron.c14
-rw-r--r--drivers/ide/pci/ns87415.c13
-rw-r--r--drivers/ide/pci/opti621.c63
-rw-r--r--drivers/ide/pci/pdc202xx_new.c78
-rw-r--r--drivers/ide/pci/pdc202xx_old.c131
-rw-r--r--drivers/ide/pci/piix.c150
-rw-r--r--drivers/ide/pci/sc1200.c11
-rw-r--r--drivers/ide/pci/serverworks.c59
-rw-r--r--drivers/ide/pci/sgiioc4.c125
-rw-r--r--drivers/ide/pci/siimage.c113
-rw-r--r--drivers/ide/pci/sis5513.c59
-rw-r--r--drivers/ide/pci/sl82c105.c39
-rw-r--r--drivers/ide/pci/slc90e66.c75
-rw-r--r--drivers/ide/pci/tc86c001.c299
-rw-r--r--drivers/ide/pci/triflex.c24
-rw-r--r--drivers/ide/pci/trm290.c42
-rw-r--r--drivers/ide/pci/via82cxxx.c5
-rw-r--r--drivers/ide/ppc/mpc8xx.c1
-rw-r--r--drivers/ide/ppc/pmac.c17
-rw-r--r--drivers/ide/ppc/scc_pata.c831
-rw-r--r--drivers/ide/setup-pci.c7
-rw-r--r--drivers/ieee1394/.gitignore1
-rw-r--r--drivers/ieee1394/Kconfig21
-rw-r--r--drivers/ieee1394/Makefile10
-rw-r--r--drivers/ieee1394/csr1212.c15
-rw-r--r--drivers/ieee1394/dv1394.c48
-rw-r--r--drivers/ieee1394/eth1394.c1
-rw-r--r--drivers/ieee1394/hosts.c13
-rw-r--r--drivers/ieee1394/hosts.h7
-rw-r--r--drivers/ieee1394/ieee1394-ioctl.h2
-rw-r--r--drivers/ieee1394/ieee1394_core.c66
-rw-r--r--drivers/ieee1394/ieee1394_core.h3
-rw-r--r--drivers/ieee1394/iso.c1
-rw-r--r--drivers/ieee1394/nodemgr.c66
-rw-r--r--drivers/ieee1394/nodemgr.h3
-rw-r--r--drivers/ieee1394/ohci1394.c20
-rw-r--r--drivers/ieee1394/oui.db7048
-rw-r--r--drivers/ieee1394/oui2c.sh22
-rw-r--r--drivers/ieee1394/pcilynx.c1
-rw-r--r--drivers/ieee1394/raw1394.c70
-rw-r--r--drivers/ieee1394/raw1394.h10
-rw-r--r--drivers/ieee1394/sbp2.c23
-rw-r--r--drivers/ieee1394/video1394.c10
-rw-r--r--drivers/infiniband/Kconfig1
-rw-r--r--drivers/infiniband/Makefile1
-rw-r--r--drivers/infiniband/core/Makefile2
-rw-r--r--drivers/infiniband/core/addr.c5
-rw-r--r--drivers/infiniband/core/cache.c1
-rw-r--r--drivers/infiniband/core/cma.c427
-rw-r--r--drivers/infiniband/core/device.c3
-rw-r--r--drivers/infiniband/core/fmr_pool.c4
-rw-r--r--drivers/infiniband/core/iwcm.c47
-rw-r--r--drivers/infiniband/core/mad.c11
-rw-r--r--drivers/infiniband/core/multicast.c837
-rw-r--r--drivers/infiniband/core/sa.h66
-rw-r--r--drivers/infiniband/core/sa_query.c30
-rw-r--r--drivers/infiniband/core/sysfs.c2
-rw-r--r--drivers/infiniband/core/ucm.c2
-rw-r--r--drivers/infiniband/core/ucma.c206
-rw-r--r--drivers/infiniband/core/user_mad.c4
-rw-r--r--drivers/infiniband/core/uverbs_cmd.c2
-rw-r--r--drivers/infiniband/core/uverbs_main.c6
-rw-r--r--drivers/infiniband/hw/amso1100/c2.c2
-rw-r--r--drivers/infiniband/hw/amso1100/c2_cq.c2
-rw-r--r--drivers/infiniband/hw/cxgb3/Kconfig27
-rw-r--r--drivers/infiniband/hw/cxgb3/Makefile12
-rw-r--r--drivers/infiniband/hw/cxgb3/cxio_dbg.c206
-rw-r--r--drivers/infiniband/hw/cxgb3/cxio_hal.c1279
-rw-r--r--drivers/infiniband/hw/cxgb3/cxio_hal.h200
-rw-r--r--drivers/infiniband/hw/cxgb3/cxio_resource.c330
-rw-r--r--drivers/infiniband/hw/cxgb3/cxio_resource.h69
-rw-r--r--drivers/infiniband/hw/cxgb3/cxio_wr.h684
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch.c188
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch.h176
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_cm.c2080
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_cm.h222
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_cq.c224
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_ev.c230
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_mem.c171
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_provider.c1202
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_provider.h366
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_qp.c1008
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_user.h66
-rw-r--r--drivers/infiniband/hw/cxgb3/tcb.h632
-rw-r--r--drivers/infiniband/hw/ehca/Kconfig8
-rw-r--r--drivers/infiniband/hw/ehca/ehca_classes.h48
-rw-r--r--drivers/infiniband/hw/ehca/ehca_cq.c68
-rw-r--r--drivers/infiniband/hw/ehca/ehca_eq.c5
-rw-r--r--drivers/infiniband/hw/ehca/ehca_hca.c3
-rw-r--r--drivers/infiniband/hw/ehca/ehca_irq.c309
-rw-r--r--drivers/infiniband/hw/ehca/ehca_irq.h1
-rw-r--r--drivers/infiniband/hw/ehca/ehca_iverbs.h8
-rw-r--r--drivers/infiniband/hw/ehca/ehca_main.c34
-rw-r--r--drivers/infiniband/hw/ehca/ehca_mrmw.c6
-rw-r--r--drivers/infiniband/hw/ehca/ehca_pd.c3
-rw-r--r--drivers/infiniband/hw/ehca/ehca_qp.c81
-rw-r--r--drivers/infiniband/hw/ehca/ehca_reqs.c2
-rw-r--r--drivers/infiniband/hw/ehca/ehca_uverbs.c395
-rw-r--r--drivers/infiniband/hw/ehca/ipz_pt_fn.h11
-rw-r--r--drivers/infiniband/hw/ipath/ipath_diag.c4
-rw-r--r--drivers/infiniband/hw/ipath/ipath_dma.c4
-rw-r--r--drivers/infiniband/hw/ipath/ipath_file_ops.c6
-rw-r--r--drivers/infiniband/hw/ipath/ipath_fs.c14
-rw-r--r--drivers/infiniband/hw/ipath/ipath_iba6110.c2
-rw-r--r--drivers/infiniband/hw/ipath/ipath_iba6120.c2
-rw-r--r--drivers/infiniband/hw/ipath/ipath_kernel.h2
-rw-r--r--drivers/infiniband/hw/ipath/ipath_qp.c2
-rw-r--r--drivers/infiniband/hw/ipath/ipath_rc.c8
-rw-r--r--drivers/infiniband/hw/ipath/ipath_ruc.c8
-rw-r--r--drivers/infiniband/hw/ipath/ipath_uc.c4
-rw-r--r--drivers/infiniband/hw/ipath/ipath_ud.c8
-rw-r--r--drivers/infiniband/hw/mthca/mthca_cmd.c8
-rw-r--r--drivers/infiniband/hw/mthca/mthca_cq.c2
-rw-r--r--drivers/infiniband/hw/mthca/mthca_dev.h2
-rw-r--r--drivers/infiniband/hw/mthca/mthca_main.c40
-rw-r--r--drivers/infiniband/hw/mthca/mthca_memfree.c129
-rw-r--r--drivers/infiniband/hw/mthca/mthca_memfree.h9
-rw-r--r--drivers/infiniband/hw/mthca/mthca_mr.c110
-rw-r--r--drivers/infiniband/hw/mthca/mthca_profile.c2
-rw-r--r--drivers/infiniband/hw/mthca/mthca_provider.c14
-rw-r--r--drivers/infiniband/hw/mthca/mthca_provider.h1
-rw-r--r--drivers/infiniband/hw/mthca/mthca_qp.c7
-rw-r--r--drivers/infiniband/hw/mthca/mthca_srq.c9
-rw-r--r--drivers/infiniband/ulp/ipoib/Kconfig16
-rw-r--r--drivers/infiniband/ulp/ipoib/Makefile1
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib.h215
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_cm.c1237
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_fs.c4
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_ib.c29
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_main.c96
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_multicast.c199
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_verbs.c40
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_vlan.c13
-rw-r--r--drivers/infiniband/ulp/iser/iser_initiator.c4
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.c7
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.h1
-rw-r--r--drivers/input/ff-memless.c2
-rw-r--r--drivers/input/gameport/ns558.c1
-rw-r--r--drivers/input/input.c24
-rw-r--r--drivers/input/joystick/amijoy.c2
-rw-r--r--drivers/input/joystick/analog.c2
-rw-r--r--drivers/input/joystick/db9.c4
-rw-r--r--drivers/input/joystick/gamecon.c6
-rw-r--r--drivers/input/joystick/turbografx.c4
-rw-r--r--drivers/input/keyboard/Kconfig19
-rw-r--r--drivers/input/keyboard/Makefile5
-rw-r--r--drivers/input/keyboard/atkbd.c4
-rw-r--r--drivers/input/keyboard/gpio_keys.c148
-rw-r--r--drivers/input/keyboard/hilkbd.c116
-rw-r--r--drivers/input/misc/Kconfig10
-rw-r--r--drivers/input/misc/Makefile1
-rw-r--r--drivers/input/misc/atlas_btns.c170
-rw-r--r--drivers/input/misc/hp_sdc_rtc.c2
-rw-r--r--drivers/input/misc/uinput.c2
-rw-r--r--drivers/input/misc/wistron_btns.c20
-rw-r--r--drivers/input/mouse/inport.c4
-rw-r--r--drivers/input/mouse/logibm.c2
-rw-r--r--drivers/input/mouse/pc110pad.c2
-rw-r--r--drivers/input/mouse/psmouse-base.c34
-rw-r--r--drivers/input/mouse/psmouse.h1
-rw-r--r--drivers/input/mouse/rpcmouse.c1
-rw-r--r--drivers/input/mouse/synaptics.c1
-rw-r--r--drivers/input/serio/hil_mlc.c1
-rw-r--r--drivers/input/serio/hp_sdc.c1
-rw-r--r--drivers/input/serio/i8042.c75
-rw-r--r--drivers/input/serio/libps2.c2
-rw-r--r--drivers/input/serio/serio.c42
-rw-r--r--drivers/input/serio/serio_raw.c2
-rw-r--r--drivers/input/touchscreen/Kconfig9
-rw-r--r--drivers/input/touchscreen/ads7846.c582
-rw-r--r--drivers/input/touchscreen/ucb1400_ts.c2
-rw-r--r--drivers/input/tsdev.c4
-rw-r--r--drivers/isdn/capi/capi.c41
-rw-r--r--drivers/isdn/capi/capidrv.c5
-rw-r--r--drivers/isdn/capi/kcapi_proc.c10
-rw-r--r--drivers/isdn/divert/divert_procfs.c2
-rw-r--r--drivers/isdn/gigaset/Kconfig25
-rw-r--r--drivers/isdn/gigaset/Makefile6
-rw-r--r--drivers/isdn/gigaset/asyncdata.c7
-rw-r--r--drivers/isdn/gigaset/bas-gigaset.c4
-rw-r--r--drivers/isdn/gigaset/common.c24
-rw-r--r--drivers/isdn/gigaset/ev-layer.c2
-rw-r--r--drivers/isdn/gigaset/interface.c17
-rw-r--r--drivers/isdn/gigaset/isocdata.c4
-rw-r--r--drivers/isdn/gigaset/ser-gigaset.c837
-rw-r--r--drivers/isdn/hardware/avm/avm_cs.c1
-rw-r--r--drivers/isdn/hardware/avm/b1dma.c14
-rw-r--r--drivers/isdn/hardware/avm/c4.c16
-rw-r--r--drivers/isdn/hardware/eicon/capifunc.c4
-rw-r--r--drivers/isdn/hardware/eicon/debug.c30
-rw-r--r--drivers/isdn/hardware/eicon/di.c16
-rw-r--r--drivers/isdn/hardware/eicon/divamnt.c3
-rw-r--r--drivers/isdn/hardware/eicon/divasi.c2
-rw-r--r--drivers/isdn/hardware/eicon/divasmain.c3
-rw-r--r--drivers/isdn/hardware/eicon/divasproc.c2
-rw-r--r--drivers/isdn/hardware/eicon/message.c383
-rw-r--r--drivers/isdn/hardware/eicon/os_pri.c4
-rw-r--r--drivers/isdn/hardware/eicon/platform.h12
-rw-r--r--drivers/isdn/hisax/Kconfig2
-rw-r--r--drivers/isdn/hisax/Makefile1
-rw-r--r--drivers/isdn/hisax/avma1_cs.c1
-rw-r--r--drivers/isdn/hisax/config.c11
-rw-r--r--drivers/isdn/hisax/elsa_cs.c1
-rw-r--r--drivers/isdn/hisax/elsa_ser.c8
-rw-r--r--drivers/isdn/hisax/hfc4s8s_l1.c48
-rw-r--r--drivers/isdn/hisax/hfc_usb.c41
-rw-r--r--drivers/isdn/hisax/hfc_usb.h3
-rw-r--r--drivers/isdn/hisax/hisax.h25
-rw-r--r--drivers/isdn/hisax/isar.c1
-rw-r--r--drivers/isdn/hisax/isdnl1.h17
-rw-r--r--drivers/isdn/hisax/isdnl3.c12
-rw-r--r--drivers/isdn/hisax/isdnl3.h26
-rw-r--r--drivers/isdn/hisax/sedlbauer_cs.c1
-rw-r--r--drivers/isdn/hisax/teles_cs.c1
-rw-r--r--drivers/isdn/hysdn/boardergo.c1
-rw-r--r--drivers/isdn/hysdn/hysdn_procconf.c2
-rw-r--r--drivers/isdn/hysdn/hysdn_proclog.c2
-rw-r--r--drivers/isdn/hysdn/hysdn_sched.c1
-rw-r--r--drivers/isdn/i4l/isdn_bsdcomp.c1
-rw-r--r--drivers/isdn/i4l/isdn_common.c2
-rw-r--r--drivers/isdn/i4l/isdn_ppp.c2
-rw-r--r--drivers/isdn/i4l/isdn_tty.c1
-rw-r--r--drivers/isdn/pcbit/callbacks.c1
-rw-r--r--drivers/isdn/pcbit/capi.c1
-rw-r--r--drivers/isdn/pcbit/drv.c5
-rw-r--r--drivers/isdn/pcbit/edss1.c7
-rw-r--r--drivers/isdn/pcbit/edss1.h7
-rw-r--r--drivers/isdn/pcbit/layer2.c17
-rw-r--r--drivers/isdn/pcbit/module.c4
-rw-r--r--drivers/isdn/pcbit/pcbit.h8
-rw-r--r--drivers/isdn/sc/card.h30
-rw-r--r--drivers/isdn/sc/command.c17
-rw-r--r--drivers/isdn/sc/event.c3
-rw-r--r--drivers/isdn/sc/init.c6
-rw-r--r--drivers/isdn/sc/interrupt.c10
-rw-r--r--drivers/isdn/sc/ioctl.c10
-rw-r--r--drivers/isdn/sc/message.c10
-rw-r--r--drivers/isdn/sc/packet.c10
-rw-r--r--drivers/isdn/sc/scioc.h6
-rw-r--r--drivers/isdn/sc/shmem.c6
-rw-r--r--drivers/isdn/sc/timer.c8
-rw-r--r--drivers/kvm/kvm.h4
-rw-r--r--drivers/kvm/kvm_main.c186
-rw-r--r--drivers/kvm/mmu.c2
-rw-r--r--drivers/kvm/paging_tmpl.h28
-rw-r--r--drivers/kvm/svm.c23
-rw-r--r--drivers/kvm/vmx.c57
-rw-r--r--drivers/kvm/vmx.h1
-rw-r--r--drivers/leds/Kconfig12
-rw-r--r--drivers/leds/Makefile2
-rw-r--r--drivers/leds/leds-cobalt.c43
-rw-r--r--drivers/leds/leds-h1940.c163
-rw-r--r--drivers/macintosh/Kconfig2
-rw-r--r--drivers/macintosh/adb.c2
-rw-r--r--drivers/macintosh/adbhid.c4
-rw-r--r--drivers/macintosh/ans-lcd.c2
-rw-r--r--drivers/macintosh/apm_emu.c4
-rw-r--r--drivers/macintosh/mac_hid.c6
-rw-r--r--drivers/macintosh/macio-adb.c1
-rw-r--r--drivers/macintosh/nvram.c2
-rw-r--r--drivers/macintosh/rack-meter.c6
-rw-r--r--drivers/macintosh/smu.c2
-rw-r--r--drivers/macintosh/therm_adt746x.c6
-rw-r--r--drivers/macintosh/via-cuda.c3
-rw-r--r--drivers/macintosh/via-macii.c11
-rw-r--r--drivers/macintosh/via-maciisi.c7
-rw-r--r--drivers/macintosh/via-pmu-backlight.c33
-rw-r--r--drivers/macintosh/via-pmu.c16
-rw-r--r--drivers/macintosh/via-pmu68k.c7
-rw-r--r--drivers/macintosh/windfarm_core.c6
-rw-r--r--drivers/md/bitmap.c24
-rw-r--r--drivers/md/dm-ioctl.c2
-rw-r--r--drivers/md/md.c4
-rw-r--r--drivers/md/raid5.c42
-rw-r--r--drivers/media/Kconfig1
-rw-r--r--drivers/media/common/Kconfig4
-rw-r--r--drivers/media/common/ir-functions.c110
-rw-r--r--drivers/media/common/ir-keymaps.c172
-rw-r--r--drivers/media/common/saa7146_fops.c4
-rw-r--r--drivers/media/dvb/b2c2/flexcop-fe-tuner.c90
-rw-r--r--drivers/media/dvb/b2c2/flexcop-i2c.c1
-rw-r--r--drivers/media/dvb/bt8xx/bt878.c1
-rw-r--r--drivers/media/dvb/bt8xx/dst.c2
-rw-r--r--drivers/media/dvb/bt8xx/dvb-bt8xx.c3
-rw-r--r--drivers/media/dvb/cinergyT2/cinergyT2.c5
-rw-r--r--drivers/media/dvb/dvb-core/dmxdev.c1
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.c73
-rw-r--r--drivers/media/dvb/dvb-core/dvbdev.c18
-rw-r--r--drivers/media/dvb/dvb-usb/Kconfig28
-rw-r--r--drivers/media/dvb/dvb-usb/Makefile9
-rw-r--r--drivers/media/dvb/dvb-usb/au6610.c255
-rw-r--r--drivers/media/dvb/dvb-usb/au6610.h19
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-i2c.c1
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-ids.h5
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-remote.c2
-rw-r--r--drivers/media/dvb/dvb-usb/gl861.c231
-rw-r--r--drivers/media/dvb/dvb-usb/gl861.h15
-rw-r--r--drivers/media/dvb/dvb-usb/m920x.c541
-rw-r--r--drivers/media/dvb/dvb-usb/m920x.h35
-rw-r--r--drivers/media/dvb/frontends/Kconfig7
-rw-r--r--drivers/media/dvb/frontends/Makefile1
-rw-r--r--drivers/media/dvb/frontends/cx24110.c4
-rw-r--r--drivers/media/dvb/frontends/cx24123.c6
-rw-r--r--drivers/media/dvb/frontends/dib3000mb.c2
-rw-r--r--drivers/media/dvb/frontends/dib3000mc.c2
-rw-r--r--drivers/media/dvb/frontends/qt1010.c485
-rw-r--r--drivers/media/dvb/frontends/qt1010.h53
-rw-r--r--drivers/media/dvb/frontends/qt1010_priv.h105
-rw-r--r--drivers/media/dvb/frontends/stv0297.c19
-rw-r--r--drivers/media/dvb/frontends/stv0299.c2
-rw-r--r--drivers/media/dvb/frontends/tda10021.c2
-rw-r--r--drivers/media/dvb/frontends/tda1004x.c2
-rw-r--r--drivers/media/dvb/frontends/zl10353.c103
-rw-r--r--drivers/media/dvb/frontends/zl10353.h3
-rw-r--r--drivers/media/dvb/frontends/zl10353_priv.h36
-rw-r--r--drivers/media/dvb/ttpci/av7110.c57
-rw-r--r--drivers/media/dvb/ttpci/av7110.h2
-rw-r--r--drivers/media/dvb/ttpci/av7110_av.c43
-rw-r--r--drivers/media/dvb/ttpci/av7110_ca.c23
-rw-r--r--drivers/media/dvb/ttpci/av7110_hw.c1
-rw-r--r--drivers/media/dvb/ttpci/av7110_ir.c18
-rw-r--r--drivers/media/dvb/ttpci/av7110_v4l.c31
-rw-r--r--drivers/media/dvb/ttpci/budget-av.c3
-rw-r--r--drivers/media/dvb/ttpci/budget-ci.c55
-rw-r--r--drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c1
-rw-r--r--drivers/media/dvb/ttusb-dec/ttusb_dec.c4
-rw-r--r--drivers/media/radio/dsbr100.c2
-rw-r--r--drivers/media/radio/miropcm20-radio.c2
-rw-r--r--drivers/media/radio/miropcm20-rds.c3
-rw-r--r--drivers/media/radio/radio-aimslab.c2
-rw-r--r--drivers/media/radio/radio-aztech.c280
-rw-r--r--drivers/media/radio/radio-cadet.c2
-rw-r--r--drivers/media/radio/radio-gemtek-pci.c20
-rw-r--r--drivers/media/radio/radio-gemtek.c2
-rw-r--r--drivers/media/radio/radio-maestro.c3
-rw-r--r--drivers/media/radio/radio-maxiradio.c357
-rw-r--r--drivers/media/radio/radio-rtrack2.c2
-rw-r--r--drivers/media/radio/radio-sf16fmi.c2
-rw-r--r--drivers/media/radio/radio-sf16fmr2.c2
-rw-r--r--drivers/media/radio/radio-terratec.c2
-rw-r--r--drivers/media/radio/radio-trust.c2
-rw-r--r--drivers/media/radio/radio-typhoon.c2
-rw-r--r--drivers/media/radio/radio-zoltrix.c2
-rw-r--r--drivers/media/video/Kconfig2
-rw-r--r--drivers/media/video/Makefile1
-rw-r--r--drivers/media/video/adv7170.c1
-rw-r--r--drivers/media/video/adv7175.c1
-rw-r--r--drivers/media/video/arv.c2
-rw-r--r--drivers/media/video/bt819.c1
-rw-r--r--drivers/media/video/bt856.c1
-rw-r--r--drivers/media/video/bt8xx/bttv-cards.c23
-rw-r--r--drivers/media/video/bt8xx/bttv-driver.c897
-rw-r--r--drivers/media/video/bt8xx/bttv-input.c157
-rw-r--r--drivers/media/video/bt8xx/bttv-risc.c171
-rw-r--r--drivers/media/video/bt8xx/bttv-vbi.c369
-rw-r--r--drivers/media/video/bt8xx/bttv.h27
-rw-r--r--drivers/media/video/bt8xx/bttvp.h90
-rw-r--r--drivers/media/video/bw-qcam.c2
-rw-r--r--drivers/media/video/c-qcam.c2
-rw-r--r--drivers/media/video/cafe_ccic.c9
-rw-r--r--drivers/media/video/cpia.c13
-rw-r--r--drivers/media/video/cpia2/cpia2_v4l.c2
-rw-r--r--drivers/media/video/cx2341x.c17
-rw-r--r--drivers/media/video/cx25840/cx25840-core.c22
-rw-r--r--drivers/media/video/cx88/Makefile5
-rw-r--r--drivers/media/video/cx88/cx88-blackbird.c569
-rw-r--r--drivers/media/video/cx88/cx88-cards.c6
-rw-r--r--drivers/media/video/cx88/cx88-core.c102
-rw-r--r--drivers/media/video/cx88/cx88-dvb.c10
-rw-r--r--drivers/media/video/cx88/cx88-i2c.c2
-rw-r--r--drivers/media/video/cx88/cx88-tvaudio.c50
-rw-r--r--drivers/media/video/cx88/cx88-vbi.c11
-rw-r--r--drivers/media/video/cx88/cx88-video.c1170
-rw-r--r--drivers/media/video/cx88/cx88.h54
-rw-r--r--drivers/media/video/dabusb.c2
-rw-r--r--drivers/media/video/em28xx/em28xx-input.c1
-rw-r--r--drivers/media/video/em28xx/em28xx-video.c2
-rw-r--r--drivers/media/video/et61x251/et61x251.h5
-rw-r--r--drivers/media/video/et61x251/et61x251_core.c131
-rw-r--r--drivers/media/video/et61x251/et61x251_sensor.h4
-rw-r--r--drivers/media/video/et61x251/et61x251_tas5130d1b.c2
-rw-r--r--drivers/media/video/indycam.c1
-rw-r--r--drivers/media/video/ir-kbd-i2c.c1
-rw-r--r--drivers/media/video/meye.c3
-rw-r--r--drivers/media/video/ov511.c2
-rw-r--r--drivers/media/video/pms.c3
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-audio.c48
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-context.c3
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-ctrl.c45
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c29
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-debugifc.c4
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-eeprom.c5
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-encoder.c269
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h62
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h36
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw.c501
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw.h39
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c16
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c69
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h3
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-i2c-core.c42
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-i2c-core.h3
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-io.c3
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-ioread.c3
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-std.c32
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-sysfs.c52
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-tuner.c5
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-v4l2.c337
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-video-v4l.c31
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-wm8775.c30
-rw-r--r--drivers/media/video/pwc/Makefile8
-rw-r--r--drivers/media/video/pwc/pwc-if.c10
-rw-r--r--drivers/media/video/pwc/pwc-v4l.c2
-rw-r--r--drivers/media/video/pwc/pwc.h9
-rw-r--r--drivers/media/video/saa5246a.c13
-rw-r--r--drivers/media/video/saa5246a.h9
-rw-r--r--drivers/media/video/saa5249.c43
-rw-r--r--drivers/media/video/saa7111.c1
-rw-r--r--drivers/media/video/saa7114.c1
-rw-r--r--drivers/media/video/saa7115.c57
-rw-r--r--drivers/media/video/saa711x.c1
-rw-r--r--drivers/media/video/saa7127.c18
-rw-r--r--drivers/media/video/saa7134/Makefile4
-rw-r--r--drivers/media/video/saa7134/saa6752hs.c1
-rw-r--r--drivers/media/video/saa7134/saa7134-cards.c140
-rw-r--r--drivers/media/video/saa7134/saa7134-dvb.c12
-rw-r--r--drivers/media/video/saa7134/saa7134-empress.c2
-rw-r--r--drivers/media/video/saa7134/saa7134-i2c.c24
-rw-r--r--drivers/media/video/saa7134/saa7134-input.c94
-rw-r--r--drivers/media/video/saa7134/saa7134-oss.c4
-rw-r--r--drivers/media/video/saa7134/saa7134-video.c4
-rw-r--r--drivers/media/video/saa7134/saa7134.h34
-rw-r--r--drivers/media/video/saa7185.c1
-rw-r--r--drivers/media/video/saa7191.c1
-rw-r--r--drivers/media/video/se401.c2
-rw-r--r--drivers/media/video/sn9c102/Kconfig4
-rw-r--r--drivers/media/video/sn9c102/Makefile2
-rw-r--r--drivers/media/video/sn9c102/sn9c102.h57
-rw-r--r--drivers/media/video/sn9c102/sn9c102_config.h86
-rw-r--r--drivers/media/video/sn9c102/sn9c102_core.c721
-rw-r--r--drivers/media/video/sn9c102/sn9c102_devtable.h142
-rw-r--r--drivers/media/video/sn9c102/sn9c102_hv7131d.c7
-rw-r--r--drivers/media/video/sn9c102/sn9c102_mi0343.c7
-rw-r--r--drivers/media/video/sn9c102/sn9c102_ov7630.c336
-rw-r--r--drivers/media/video/sn9c102/sn9c102_ov7660.c592
-rw-r--r--drivers/media/video/sn9c102/sn9c102_pas106b.c7
-rw-r--r--drivers/media/video/sn9c102/sn9c102_pas202bca.c238
-rw-r--r--drivers/media/video/sn9c102/sn9c102_pas202bcb.c97
-rw-r--r--drivers/media/video/sn9c102/sn9c102_sensor.h168
-rw-r--r--drivers/media/video/sn9c102/sn9c102_tas5110c1b.c8
-rw-r--r--drivers/media/video/sn9c102/sn9c102_tas5130d1b.c8
-rw-r--r--drivers/media/video/stradis.c2
-rw-r--r--drivers/media/video/stv680.c2
-rw-r--r--drivers/media/video/tda7432.c1
-rw-r--r--drivers/media/video/tda9875.c1
-rw-r--r--drivers/media/video/tuner-core.c1
-rw-r--r--drivers/media/video/tvmixer.c6
-rw-r--r--drivers/media/video/tvp5150.c18
-rw-r--r--drivers/media/video/upd64031a.c20
-rw-r--r--drivers/media/video/upd64083.c20
-rw-r--r--drivers/media/video/usbvideo/ibmcam.c1
-rw-r--r--drivers/media/video/usbvideo/ultracam.c1
-rw-r--r--drivers/media/video/usbvideo/usbvideo.c2
-rw-r--r--drivers/media/video/usbvideo/vicam.c2
-rw-r--r--drivers/media/video/usbvision/Kconfig2
-rw-r--r--drivers/media/video/usbvision/usbvision-core.c71
-rw-r--r--drivers/media/video/usbvision/usbvision-i2c.c2
-rw-r--r--drivers/media/video/usbvision/usbvision-video.c181
-rw-r--r--drivers/media/video/usbvision/usbvision.h11
-rw-r--r--drivers/media/video/v4l1-compat.c2
-rw-r--r--drivers/media/video/v4l2-common.c592
-rw-r--r--drivers/media/video/video-buf.c3
-rw-r--r--drivers/media/video/videodev.c25
-rw-r--r--drivers/media/video/vino.c2
-rw-r--r--drivers/media/video/vivi.c104
-rw-r--r--drivers/media/video/w9966.c2
-rw-r--r--drivers/media/video/w9968cf.c5
-rw-r--r--drivers/media/video/zc0301/zc0301.h4
-rw-r--r--drivers/media/video/zc0301/zc0301_core.c57
-rw-r--r--drivers/media/video/zc0301/zc0301_pas202bcb.c4
-rw-r--r--drivers/media/video/zc0301/zc0301_pb0330.c4
-rw-r--r--drivers/media/video/zc0301/zc0301_sensor.h13
-rw-r--r--drivers/media/video/zoran_card.c1
-rw-r--r--drivers/media/video/zoran_driver.c3
-rw-r--r--drivers/media/video/zoran_procfs.c2
-rw-r--r--drivers/message/fusion/Kconfig2
-rw-r--r--drivers/message/fusion/Makefile7
-rw-r--r--drivers/message/fusion/lsi/mpi.h7
-rw-r--r--drivers/message/fusion/lsi/mpi_cnfg.h131
-rw-r--r--drivers/message/fusion/lsi/mpi_history.txt77
-rw-r--r--drivers/message/fusion/lsi/mpi_init.h7
-rw-r--r--drivers/message/fusion/lsi/mpi_ioc.h75
-rw-r--r--drivers/message/fusion/lsi/mpi_log_sas.h284
-rw-r--r--drivers/message/fusion/lsi/mpi_sas.h9
-rw-r--r--drivers/message/fusion/mptbase.c875
-rw-r--r--drivers/message/fusion/mptbase.h47
-rw-r--r--drivers/message/fusion/mptctl.c165
-rw-r--r--drivers/message/fusion/mptctl.h2
-rw-r--r--drivers/message/fusion/mptfc.c54
-rw-r--r--drivers/message/fusion/mptlan.c1
-rw-r--r--drivers/message/fusion/mptlan.h1
-rw-r--r--drivers/message/fusion/mptsas.c720
-rw-r--r--drivers/message/fusion/mptscsih.c998
-rw-r--r--drivers/message/fusion/mptscsih.h44
-rw-r--r--drivers/message/fusion/mptspi.c528
-rw-r--r--drivers/message/i2o/i2o_config.c2
-rw-r--r--drivers/message/i2o/i2o_proc.c38
-rw-r--r--drivers/mfd/Kconfig14
-rw-r--r--drivers/mfd/Makefile2
-rw-r--r--drivers/mfd/sm501.c1148
-rw-r--r--drivers/misc/Kconfig36
-rw-r--r--drivers/misc/Makefile2
-rw-r--r--drivers/misc/asus-laptop.c1149
-rw-r--r--drivers/misc/hdpuftrs/hdpu_cpustate.c2
-rw-r--r--drivers/misc/hdpuftrs/hdpu_nexus.c2
-rw-r--r--drivers/misc/ibmasm/ibmasmfs.c10
-rw-r--r--drivers/misc/ioc4.c6
-rw-r--r--drivers/misc/lkdtm.c4
-rw-r--r--drivers/misc/msi-laptop.c10
-rw-r--r--drivers/misc/sony-laptop.c564
-rw-r--r--drivers/misc/tifm_7xx1.c404
-rw-r--r--drivers/misc/tifm_core.c65
-rw-r--r--drivers/mmc/Kconfig2
-rw-r--r--drivers/mmc/at91_mci.c49
-rw-r--r--drivers/mmc/au1xmmc.c13
-rw-r--r--drivers/mmc/imxmmc.c4
-rw-r--r--drivers/mmc/mmc.c182
-rw-r--r--drivers/mmc/mmc_block.c16
-rw-r--r--drivers/mmc/mmc_queue.c2
-rw-r--r--drivers/mmc/mmc_sysfs.c2
-rw-r--r--drivers/mmc/mmci.c15
-rw-r--r--drivers/mmc/omap.c6
-rw-r--r--drivers/mmc/pxamci.c10
-rw-r--r--drivers/mmc/sdhci.c131
-rw-r--r--drivers/mmc/sdhci.h2
-rw-r--r--drivers/mmc/tifm_sd.c494
-rw-r--r--drivers/mmc/wbsd.c108
-rw-r--r--drivers/mmc/wbsd.h1
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0001.c26
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0020.c2
-rw-r--r--drivers/mtd/chips/cfi_util.c1
-rw-r--r--drivers/mtd/devices/block2mtd.c3
-rw-r--r--drivers/mtd/devices/doc2000.c1
-rw-r--r--drivers/mtd/devices/doc2001.c2
-rw-r--r--drivers/mtd/devices/doc2001plus.c2
-rw-r--r--drivers/mtd/devices/docecc.c1
-rw-r--r--drivers/mtd/devices/pmc551.c1
-rw-r--r--drivers/mtd/devices/slram.c1
-rw-r--r--drivers/mtd/ftl.c1
-rw-r--r--drivers/mtd/inftlmount.c1
-rw-r--r--drivers/mtd/maps/Kconfig2
-rw-r--r--drivers/mtd/maps/amd76xrom.c4
-rw-r--r--drivers/mtd/maps/ck804xrom.c6
-rw-r--r--drivers/mtd/maps/esb2rom.c4
-rw-r--r--drivers/mtd/maps/ichxrom.c4
-rw-r--r--drivers/mtd/maps/netsc520.c4
-rw-r--r--drivers/mtd/maps/sc520cdp.c5
-rw-r--r--drivers/mtd/mtdchar.c7
-rw-r--r--drivers/mtd/mtdconcat.c4
-rw-r--r--drivers/mtd/mtdcore.c1
-rw-r--r--drivers/mtd/mtdpart.c2
-rw-r--r--drivers/mtd/nand/Kconfig14
-rw-r--r--drivers/mtd/nand/Makefile1
-rw-r--r--drivers/mtd/nand/cafe.c92
-rw-r--r--drivers/mtd/nand/cafe_ecc.c2
-rw-r--r--drivers/mtd/nand/excite_nandflash.c248
-rw-r--r--drivers/mtd/nand/nand_base.c47
-rw-r--r--drivers/mtd/nand/s3c2410.c96
-rw-r--r--drivers/mtd/nftlcore.c1
-rw-r--r--drivers/mtd/onenand/onenand_base.c596
-rw-r--r--drivers/mtd/onenand/onenand_bbt.c27
-rw-r--r--drivers/mtd/redboot.c19
-rw-r--r--drivers/net/3c503.c3
-rw-r--r--drivers/net/3c59x.c3
-rw-r--r--drivers/net/7990.c2
-rw-r--r--drivers/net/8139too.c40
-rw-r--r--drivers/net/Kconfig141
-rw-r--r--drivers/net/Makefile7
-rw-r--r--drivers/net/Space.c4
-rw-r--r--drivers/net/ac3200.c3
-rw-r--r--drivers/net/amd8111e.c3
-rw-r--r--drivers/net/arcnet/arc-rawmode.c4
-rw-r--r--drivers/net/arcnet/arcnet.c2
-rw-r--r--drivers/net/arcnet/com20020-pci.c3
-rw-r--r--drivers/net/arcnet/com20020.c5
-rw-r--r--drivers/net/arm/at91_ether.c2
-rw-r--r--drivers/net/arm/ether1.c1
-rw-r--r--drivers/net/arm/ether3.c1
-rw-r--r--drivers/net/arm/etherh.c3
-rw-r--r--drivers/net/atl1/Makefile2
-rw-r--r--drivers/net/atl1/atl1.h283
-rw-r--r--drivers/net/atl1/atl1_ethtool.c508
-rw-r--r--drivers/net/atl1/atl1_hw.c723
-rw-r--r--drivers/net/atl1/atl1_hw.h951
-rw-r--r--drivers/net/atl1/atl1_main.c2467
-rw-r--r--drivers/net/atl1/atl1_param.c206
-rw-r--r--drivers/net/au1000_eth.c1
-rw-r--r--drivers/net/b44.c27
-rw-r--r--drivers/net/b44.h10
-rw-r--r--drivers/net/bmac.c20
-rw-r--r--drivers/net/bnx2.c16
-rw-r--r--drivers/net/bonding/bond_alb.c4
-rw-r--r--drivers/net/bonding/bond_main.c30
-rw-r--r--drivers/net/bonding/bond_sysfs.c303
-rw-r--r--drivers/net/bonding/bonding.h9
-rw-r--r--drivers/net/chelsio/common.h2
-rw-r--r--drivers/net/chelsio/cpl5_cmd.h18
-rw-r--r--drivers/net/chelsio/cxgb2.c149
-rw-r--r--drivers/net/chelsio/elmer0.h40
-rw-r--r--drivers/net/chelsio/espi.c44
-rw-r--r--drivers/net/chelsio/fpga_defs.h6
-rw-r--r--drivers/net/chelsio/gmac.h11
-rw-r--r--drivers/net/chelsio/ixf1010.c100
-rw-r--r--drivers/net/chelsio/mv88e1xxx.c27
-rw-r--r--drivers/net/chelsio/my3126.c16
-rw-r--r--drivers/net/chelsio/pm3393.c91
-rw-r--r--drivers/net/chelsio/sge.c328
-rw-r--r--drivers/net/chelsio/subr.c89
-rw-r--r--drivers/net/chelsio/tp.c62
-rw-r--r--drivers/net/chelsio/vsc7326.c139
-rw-r--r--drivers/net/chelsio/vsc7326_reg.h139
-rw-r--r--drivers/net/chelsio/vsc8244.c41
-rw-r--r--drivers/net/cris/eth_v10.c1
-rw-r--r--drivers/net/cxgb3/Makefile8
-rw-r--r--drivers/net/cxgb3/adapter.h279
-rw-r--r--drivers/net/cxgb3/ael1002.c251
-rw-r--r--drivers/net/cxgb3/common.h729
-rw-r--r--drivers/net/cxgb3/cxgb3_ctl_defs.h164
-rw-r--r--drivers/net/cxgb3/cxgb3_defs.h98
-rw-r--r--drivers/net/cxgb3/cxgb3_ioctl.h185
-rw-r--r--drivers/net/cxgb3/cxgb3_main.c2520
-rw-r--r--drivers/net/cxgb3/cxgb3_offload.c1221
-rw-r--r--drivers/net/cxgb3/cxgb3_offload.h192
-rw-r--r--drivers/net/cxgb3/firmware_exports.h177
-rw-r--r--drivers/net/cxgb3/l2t.c449
-rw-r--r--drivers/net/cxgb3/l2t.h142
-rw-r--r--drivers/net/cxgb3/mc5.c473
-rw-r--r--drivers/net/cxgb3/regs.h2195
-rw-r--r--drivers/net/cxgb3/sge.c2681
-rw-r--r--drivers/net/cxgb3/sge_defs.h251
-rw-r--r--drivers/net/cxgb3/t3_cpl.h1444
-rw-r--r--drivers/net/cxgb3/t3_hw.c3375
-rw-r--r--drivers/net/cxgb3/t3cdev.h72
-rw-r--r--drivers/net/cxgb3/version.h39
-rw-r--r--drivers/net/cxgb3/vsc8211.c228
-rw-r--r--drivers/net/cxgb3/xgmac.c409
-rw-r--r--drivers/net/declance.c164
-rw-r--r--drivers/net/defxx.c928
-rw-r--r--drivers/net/defxx.h58
-rw-r--r--drivers/net/e1000/e1000.h8
-rw-r--r--drivers/net/e1000/e1000_ethtool.c8
-rw-r--r--drivers/net/e1000/e1000_hw.h2
-rw-r--r--drivers/net/e1000/e1000_main.c188
-rw-r--r--drivers/net/e1000/e1000_osdep.h4
-rw-r--r--drivers/net/e1000/e1000_param.c15
-rw-r--r--drivers/net/e2100.c3
-rw-r--r--drivers/net/eexpress.c7
-rw-r--r--drivers/net/ehea/ehea.h2
-rw-r--r--drivers/net/ehea/ehea_main.c16
-rw-r--r--drivers/net/ehea/ehea_phyp.c10
-rw-r--r--drivers/net/ehea/ehea_phyp.h3
-rw-r--r--drivers/net/ehea/ehea_qmr.c42
-rw-r--r--drivers/net/ehea/ehea_qmr.h5
-rw-r--r--drivers/net/es3210.c2
-rw-r--r--drivers/net/fec_8xx/fec_8xx-netta.c1
-rw-r--r--drivers/net/fec_8xx/fec_main.c1
-rw-r--r--drivers/net/fec_8xx/fec_mii.c1
-rw-r--r--drivers/net/forcedeth.c1342
-rw-r--r--drivers/net/fs_enet/fs_enet-main.c1
-rw-r--r--drivers/net/fs_enet/fs_enet.h1
-rw-r--r--drivers/net/fs_enet/mac-fcc.c1
-rw-r--r--drivers/net/fs_enet/mac-fec.c1
-rw-r--r--drivers/net/fs_enet/mac-scc.c1
-rw-r--r--drivers/net/fs_enet/mii-bitbang.c1
-rw-r--r--drivers/net/fs_enet/mii-fec.c1
-rw-r--r--drivers/net/gianfar.c86
-rw-r--r--drivers/net/gianfar_ethtool.c3
-rw-r--r--drivers/net/gianfar_mii.c1
-rw-r--r--drivers/net/gianfar_sysfs.c109
-rw-r--r--drivers/net/hamradio/Kconfig3
-rw-r--r--drivers/net/hamradio/baycom_epp.c13
-rw-r--r--drivers/net/hamradio/bpqether.c2
-rw-r--r--drivers/net/hamradio/hdlcdrv.c13
-rw-r--r--drivers/net/hamradio/scc.c2
-rw-r--r--drivers/net/hamradio/yam.c13
-rw-r--r--drivers/net/hp100.c2
-rw-r--r--drivers/net/ibm_emac/ibm_emac_core.c1
-rw-r--r--drivers/net/ibmveth.c2
-rw-r--r--drivers/net/ioc3-eth.c16
-rw-r--r--drivers/net/irda/ma600-sir.c1
-rw-r--r--drivers/net/irda/vlsi_ir.c2
-rw-r--r--drivers/net/iseries_veth.c2
-rw-r--r--drivers/net/ixgb/ixgb.h2
-rw-r--r--drivers/net/ixgb/ixgb_ethtool.c6
-rw-r--r--drivers/net/ixgb/ixgb_main.c6
-rw-r--r--drivers/net/macb.c87
-rw-r--r--drivers/net/macb.h8
-rw-r--r--drivers/net/mace.c16
-rw-r--r--drivers/net/macmace.c18
-rw-r--r--drivers/net/macsonic.c7
-rw-r--r--drivers/net/meth.c27
-rw-r--r--drivers/net/mipsnet.c1
-rw-r--r--drivers/net/mv643xx_eth.c1
-rw-r--r--drivers/net/myri10ge/myri10ge.c10
-rw-r--r--drivers/net/natsemi.c43
-rw-r--r--drivers/net/netxen/netxen_nic.h26
-rw-r--r--drivers/net/netxen/netxen_nic_ethtool.c105
-rw-r--r--drivers/net/netxen/netxen_nic_hw.c2
-rw-r--r--drivers/net/netxen/netxen_nic_init.c291
-rw-r--r--drivers/net/netxen/netxen_nic_main.c7
-rw-r--r--drivers/net/netxen/netxen_nic_niu.c2
-rw-r--r--drivers/net/oaknet.c666
-rw-r--r--drivers/net/pasemi_mac.c1019
-rw-r--r--drivers/net/pasemi_mac.h460
-rw-r--r--drivers/net/pcmcia/3c574_cs.c2
-rw-r--r--drivers/net/pcmcia/smc91c92_cs.c2
-rw-r--r--drivers/net/phy/cicada.c1
-rw-r--r--drivers/net/phy/davicom.c1
-rw-r--r--drivers/net/phy/fixed.c1
-rw-r--r--drivers/net/phy/lxt.c1
-rw-r--r--drivers/net/phy/marvell.c157
-rw-r--r--drivers/net/phy/mdio_bus.c1
-rw-r--r--drivers/net/phy/phy.c1
-rw-r--r--drivers/net/phy/phy_device.c5
-rw-r--r--drivers/net/phy/qsemi.c1
-rw-r--r--drivers/net/ppp_generic.c4
-rw-r--r--drivers/net/pppoe.c2
-rwxr-xr-x[-rw-r--r--]drivers/net/qla3xxx.c367
-rwxr-xr-x[-rw-r--r--]drivers/net/qla3xxx.h88
-rw-r--r--drivers/net/r8169.c29
-rw-r--r--drivers/net/s2io-regs.h7
-rw-r--r--drivers/net/s2io.c1202
-rw-r--r--drivers/net/s2io.h227
-rw-r--r--drivers/net/sc92031.c1620
-rw-r--r--drivers/net/sis190.c7
-rw-r--r--drivers/net/sk98lin/skge.c3
-rw-r--r--drivers/net/sk_mca.c1216
-rw-r--r--drivers/net/sk_mca.h170
-rw-r--r--drivers/net/skfp/can.c83
-rw-r--r--drivers/net/skfp/drvfbi.c24
-rw-r--r--drivers/net/skfp/fplustm.c4
-rw-r--r--drivers/net/skfp/smt.c10
-rw-r--r--drivers/net/skge.c244
-rw-r--r--drivers/net/skge.h2
-rw-r--r--drivers/net/sky2.c638
-rw-r--r--drivers/net/sky2.h88
-rw-r--r--drivers/net/slip.c5
-rw-r--r--drivers/net/smc-mca.c3
-rw-r--r--drivers/net/smc-ultra.c3
-rw-r--r--drivers/net/smc-ultra32.c3
-rw-r--r--drivers/net/smc911x.c2
-rw-r--r--drivers/net/smc91x.c2
-rw-r--r--drivers/net/spider_net.c315
-rw-r--r--drivers/net/spider_net.h20
-rw-r--r--drivers/net/spider_net_ethtool.c4
-rw-r--r--drivers/net/sungem_phy.c1
-rw-r--r--drivers/net/tg3.c108
-rw-r--r--drivers/net/tg3.h3
-rw-r--r--drivers/net/tsi108_eth.c1
-rw-r--r--drivers/net/tun.c2
-rw-r--r--drivers/net/ucc_geth.c106
-rw-r--r--drivers/net/ucc_geth_phy.c3
-rw-r--r--drivers/net/wan/Kconfig26
-rw-r--r--drivers/net/wan/Makefile1
-rw-r--r--drivers/net/wan/cosa.c2
-rw-r--r--drivers/net/wan/cycx_drv.c1
-rw-r--r--drivers/net/wan/hdlc.c3
-rw-r--r--drivers/net/wan/pc300too.c565
-rw-r--r--drivers/net/wan/pci200syn.c1
-rw-r--r--drivers/net/wan/z85230.c14
-rw-r--r--drivers/net/wd.c2
-rw-r--r--drivers/net/wireless/airo.c20
-rw-r--r--drivers/net/wireless/arlan-proc.c4
-rw-r--r--drivers/net/wireless/atmel.c1
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx.h16
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c12
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_dma.c171
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_ilt.c15
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_ilt.h1
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_leds.c11
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_main.c81
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_phy.c195
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_radio.c15
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_radio.h16
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_wx.c29
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_xmit.h10
-rw-r--r--drivers/net/wireless/hostap/hostap.h3
-rw-r--r--drivers/net/wireless/hostap/hostap_main.c2
-rw-r--r--drivers/net/wireless/ipw2100.c30
-rw-r--r--drivers/net/wireless/ipw2200.c4
-rw-r--r--drivers/net/wireless/orinoco.c6
-rw-r--r--drivers/net/wireless/orinoco_cs.c2
-rw-r--r--drivers/net/wireless/prism54/isl_ioctl.c8
-rw-r--r--drivers/net/wireless/prism54/islpci_dev.c13
-rw-r--r--drivers/net/wireless/prism54/islpci_dev.h4
-rw-r--r--drivers/net/wireless/prism54/islpci_hotplug.c3
-rw-r--r--drivers/net/wireless/prism54/oid_mgt.c4
-rw-r--r--drivers/net/wireless/spectrum_cs.c2
-rw-r--r--drivers/net/wireless/strip.c2
-rw-r--r--drivers/net/wireless/wavelan.c14
-rw-r--r--drivers/net/wireless/wavelan.p.h3
-rw-r--r--drivers/net/wireless/wavelan_cs.c8
-rw-r--r--drivers/net/wireless/zd1211rw/zd_chip.c128
-rw-r--r--drivers/net/wireless/zd1211rw/zd_chip.h158
-rw-r--r--drivers/net/wireless/zd1211rw/zd_def.h2
-rw-r--r--drivers/net/wireless/zd1211rw/zd_ieee80211.h1
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.c44
-rw-r--r--drivers/net/wireless/zd1211rw/zd_rf.h2
-rw-r--r--drivers/net/wireless/zd1211rw/zd_types.h71
-rw-r--r--drivers/net/wireless/zd1211rw/zd_usb.c140
-rw-r--r--drivers/net/wireless/zd1211rw/zd_usb.h6
-rw-r--r--drivers/oprofile/event_buffer.c2
-rw-r--r--drivers/oprofile/event_buffer.h2
-rw-r--r--drivers/oprofile/oprofile_files.c10
-rw-r--r--drivers/oprofile/oprofilefs.c6
-rw-r--r--drivers/parisc/ccio-dma.c4
-rw-r--r--drivers/parisc/eisa.c1
-rw-r--r--drivers/parisc/eisa_eeprom.c2
-rw-r--r--drivers/parisc/led.c2
-rw-r--r--drivers/parisc/sba_iommu.c4
-rw-r--r--drivers/parport/parport_cs.c1
-rw-r--r--drivers/parport/parport_gsc.c1
-rw-r--r--drivers/parport/parport_pc.c6
-rw-r--r--drivers/parport/procfs.c270
-rw-r--r--drivers/pci/Kconfig2
-rw-r--r--drivers/pci/hotplug/Kconfig9
-rw-r--r--drivers/pci/hotplug/acpiphp_glue.c10
-rw-r--r--drivers/pci/hotplug/cpqphp_sysfs.c2
-rw-r--r--drivers/pci/hotplug/ibmphp_ebda.c1
-rw-r--r--drivers/pci/hotplug/pciehp.h194
-rw-r--r--drivers/pci/hotplug/pciehp_core.c292
-rw-r--r--drivers/pci/hotplug/pciehp_ctrl.c223
-rw-r--r--drivers/pci/hotplug/pciehp_hpc.c827
-rw-r--r--drivers/pci/hotplug/sgi_hotplug.c155
-rw-r--r--drivers/pci/hotplug/shpchp.h4
-rw-r--r--drivers/pci/hotplug/shpchp_core.c4
-rw-r--r--drivers/pci/hotplug/shpchp_ctrl.c20
-rw-r--r--drivers/pci/hotplug/shpchp_hpc.c185
-rw-r--r--drivers/pci/msi.c325
-rw-r--r--drivers/pci/pci-driver.c8
-rw-r--r--drivers/pci/pci-sysfs.c11
-rw-r--r--drivers/pci/pci.c308
-rw-r--r--drivers/pci/pci.h14
-rw-r--r--drivers/pci/pcie/aer/aerdrv.c2
-rw-r--r--drivers/pci/pcie/aer/aerdrv.h2
-rw-r--r--drivers/pci/probe.c70
-rw-r--r--drivers/pci/proc.c4
-rw-r--r--drivers/pci/quirks.c133
-rw-r--r--drivers/pci/search.c38
-rw-r--r--drivers/pci/setup-bus.c27
-rw-r--r--drivers/pci/setup-irq.c18
-rw-r--r--drivers/pci/syscall.c1
-rw-r--r--drivers/pcmcia/at91_cf.c3
-rw-r--r--drivers/pcmcia/cardbus.c2
-rw-r--r--drivers/pcmcia/cistpl.c1
-rw-r--r--drivers/pcmcia/cs.c34
-rw-r--r--drivers/pcmcia/cs_internal.h4
-rw-r--r--drivers/pcmcia/ds.c14
-rw-r--r--drivers/pcmcia/hd64465_ss.c2
-rw-r--r--drivers/pcmcia/i82092.c2
-rw-r--r--drivers/pcmcia/i82365.c3
-rw-r--r--drivers/pcmcia/m32r_cfc.c3
-rw-r--r--drivers/pcmcia/m32r_pcc.c3
-rw-r--r--drivers/pcmcia/m8xx_pcmcia.c3
-rw-r--r--drivers/pcmcia/omap_cf.c3
-rw-r--r--drivers/pcmcia/pcmcia_ioctl.c3
-rw-r--r--drivers/pcmcia/pcmcia_resource.c1
-rw-r--r--drivers/pcmcia/pd6729.c2
-rw-r--r--drivers/pcmcia/pxa2xx_lubbock.c1
-rw-r--r--drivers/pcmcia/rsrc_mgr.c2
-rw-r--r--drivers/pcmcia/rsrc_nonstatic.c56
-rw-r--r--drivers/pcmcia/sa1100_badge4.c1
-rw-r--r--drivers/pcmcia/sa1100_cerf.c1
-rw-r--r--drivers/pcmcia/sa1100_h3600.c1
-rw-r--r--drivers/pcmcia/sa1100_jornada720.c1
-rw-r--r--drivers/pcmcia/sa1100_neponset.c1
-rw-r--r--drivers/pcmcia/sa1100_shannon.c1
-rw-r--r--drivers/pcmcia/sa1100_simpad.c1
-rw-r--r--drivers/pcmcia/soc_common.c10
-rw-r--r--drivers/pcmcia/socket_sysfs.c104
-rw-r--r--drivers/pcmcia/tcic.c2
-rw-r--r--drivers/pcmcia/vrc4171_card.c3
-rw-r--r--drivers/pcmcia/yenta_socket.c3
-rw-r--r--drivers/pnp/base.h1
-rw-r--r--drivers/pnp/isapnp/proc.c2
-rw-r--r--drivers/pnp/pnpacpi/Kconfig16
-rw-r--r--drivers/pnp/pnpbios/rsparser.c1
-rw-r--r--drivers/pnp/system.c52
-rw-r--r--drivers/ps3/Makefile3
-rw-r--r--drivers/ps3/ps3av.c974
-rw-r--r--drivers/ps3/ps3av_cmd.c1020
-rw-r--r--drivers/ps3/sys-manager.c604
-rw-r--r--drivers/ps3/system-bus.c362
-rw-r--r--drivers/ps3/vuart.c417
-rw-r--r--drivers/ps3/vuart.h40
-rw-r--r--drivers/rapidio/rio-scan.c118
-rw-r--r--drivers/rapidio/rio-sysfs.c1
-rw-r--r--drivers/rtc/Kconfig25
-rw-r--r--drivers/rtc/Makefile1
-rw-r--r--drivers/rtc/rtc-at91rm9200.c19
-rw-r--r--drivers/rtc/rtc-cmos.c725
-rw-r--r--drivers/rtc/rtc-dev.c4
-rw-r--r--drivers/rtc/rtc-ds1553.c2
-rw-r--r--drivers/rtc/rtc-ds1672.c2
-rw-r--r--drivers/rtc/rtc-ds1742.c2
-rw-r--r--drivers/rtc/rtc-omap.c4
-rw-r--r--drivers/rtc/rtc-pcf8563.c42
-rw-r--r--drivers/rtc/rtc-proc.c2
-rw-r--r--drivers/rtc/rtc-rs5c372.c2
-rw-r--r--drivers/rtc/rtc-s3c.c4
-rw-r--r--drivers/rtc/rtc-sa1100.c12
-rw-r--r--drivers/rtc/rtc-sysfs.c103
-rw-r--r--drivers/rtc/rtc-x1205.c2
-rw-r--r--drivers/s390/Kconfig8
-rw-r--r--drivers/s390/Makefile2
-rw-r--r--drivers/s390/block/dasd.c33
-rw-r--r--drivers/s390/block/dasd_3990_erp.c5
-rw-r--r--drivers/s390/block/dasd_devmap.c6
-rw-r--r--drivers/s390/block/dasd_diag.c8
-rw-r--r--drivers/s390/block/dasd_eckd.c95
-rw-r--r--drivers/s390/block/dasd_eer.c26
-rw-r--r--drivers/s390/block/dasd_erp.c80
-rw-r--r--drivers/s390/block/dasd_fba.c4
-rw-r--r--drivers/s390/block/dasd_genhd.c2
-rw-r--r--drivers/s390/block/dasd_int.h1
-rw-r--r--drivers/s390/block/dasd_proc.c10
-rw-r--r--drivers/s390/block/dcssblk.c6
-rw-r--r--drivers/s390/char/Makefile4
-rw-r--r--drivers/s390/char/con3215.c2
-rw-r--r--drivers/s390/char/con3270.c3
-rw-r--r--drivers/s390/char/defkeymap.c2
-rw-r--r--drivers/s390/char/fs3270.c6
-rw-r--r--drivers/s390/char/keyboard.c2
-rw-r--r--drivers/s390/char/monreader.c220
-rw-r--r--drivers/s390/char/monwriter.c6
-rw-r--r--drivers/s390/char/raw3270.c4
-rw-r--r--drivers/s390/char/sclp.c93
-rw-r--r--drivers/s390/char/sclp.h18
-rw-r--r--drivers/s390/char/sclp_con.c2
-rw-r--r--drivers/s390/char/sclp_cpi.c2
-rw-r--r--drivers/s390/char/sclp_info.c57
-rw-r--r--drivers/s390/char/sclp_quiesce.c1
-rw-r--r--drivers/s390/char/sclp_rw.c2
-rw-r--r--drivers/s390/char/sclp_tty.c3
-rw-r--r--drivers/s390/char/sclp_vt220.c5
-rw-r--r--drivers/s390/char/tape.h22
-rw-r--r--drivers/s390/char/tape_3590.c479
-rw-r--r--drivers/s390/char/tape_3590.h53
-rw-r--r--drivers/s390/char/tape_block.c4
-rw-r--r--drivers/s390/char/tape_char.c29
-rw-r--r--drivers/s390/char/tape_class.c2
-rw-r--r--drivers/s390/char/tape_class.h2
-rw-r--r--drivers/s390/char/tape_core.c69
-rw-r--r--drivers/s390/char/tape_proc.c2
-rw-r--r--drivers/s390/char/tty3270.c13
-rw-r--r--drivers/s390/char/vmcp.c2
-rw-r--r--drivers/s390/char/vmlogrdr.c286
-rw-r--r--drivers/s390/char/vmwatchdog.c2
-rw-r--r--drivers/s390/cio/blacklist.c12
-rw-r--r--drivers/s390/cio/ccwgroup.c6
-rw-r--r--drivers/s390/cio/chsc.c270
-rw-r--r--drivers/s390/cio/chsc.h11
-rw-r--r--drivers/s390/cio/cio.c40
-rw-r--r--drivers/s390/cio/cmf.c4
-rw-r--r--drivers/s390/cio/css.c13
-rw-r--r--drivers/s390/cio/css.h2
-rw-r--r--drivers/s390/cio/device.c12
-rw-r--r--drivers/s390/cio/device.h2
-rw-r--r--drivers/s390/cio/device_fsm.c8
-rw-r--r--drivers/s390/cio/device_id.c3
-rw-r--r--drivers/s390/cio/device_ops.c34
-rw-r--r--drivers/s390/cio/device_status.c8
-rw-r--r--drivers/s390/cio/qdio.c79
-rw-r--r--drivers/s390/crypto/ap_bus.c8
-rw-r--r--drivers/s390/crypto/zcrypt_api.c23
-rw-r--r--drivers/s390/crypto/zcrypt_pcica.c8
-rw-r--r--drivers/s390/crypto/zcrypt_pcixcc.c3
-rw-r--r--drivers/s390/net/Kconfig7
-rw-r--r--drivers/s390/net/Makefile1
-rw-r--r--drivers/s390/net/claw.c16
-rw-r--r--drivers/s390/net/ctcmain.c9
-rw-r--r--drivers/s390/net/cu3088.c2
-rw-r--r--drivers/s390/net/iucv.c2540
-rw-r--r--drivers/s390/net/iucv.h849
-rw-r--r--drivers/s390/net/lcs.c12
-rw-r--r--drivers/s390/net/netiucv.c1319
-rw-r--r--drivers/s390/net/qeth_eddp.c28
-rw-r--r--drivers/s390/net/qeth_main.c92
-rw-r--r--drivers/s390/net/qeth_proc.c4
-rw-r--r--drivers/s390/net/qeth_sys.c30
-rw-r--r--drivers/s390/net/smsgiucv.c147
-rw-r--r--drivers/s390/s390mach.c37
-rw-r--r--drivers/s390/s390mach.h3
-rw-r--r--drivers/s390/scsi/zfcp_aux.c27
-rw-r--r--drivers/s390/scsi/zfcp_dbf.c44
-rw-r--r--drivers/s390/scsi/zfcp_erp.c29
-rw-r--r--drivers/s390/scsi/zfcp_ext.h6
-rw-r--r--drivers/s390/scsi/zfcp_fsf.c25
-rw-r--r--drivers/s390/scsi/zfcp_qdio.c38
-rw-r--r--drivers/s390/scsi/zfcp_scsi.c18
-rw-r--r--drivers/s390/sysinfo.c63
-rw-r--r--drivers/sbus/char/Kconfig7
-rw-r--r--drivers/sbus/char/Makefile1
-rw-r--r--drivers/sbus/char/aurora.c2364
-rw-r--r--drivers/sbus/char/aurora.h276
-rw-r--r--drivers/sbus/char/bbc_i2c.c17
-rw-r--r--drivers/sbus/char/bpp.c2
-rw-r--r--drivers/sbus/char/cd180.h240
-rw-r--r--drivers/sbus/char/cpwatchdog.c3
-rw-r--r--drivers/sbus/char/display7seg.c2
-rw-r--r--drivers/sbus/char/envctrl.c2
-rw-r--r--drivers/sbus/char/flash.c2
-rw-r--r--drivers/sbus/char/jsflash.c2
-rw-r--r--drivers/sbus/char/openprom.c3
-rw-r--r--drivers/sbus/char/riowatchdog.c2
-rw-r--r--drivers/sbus/char/rtc.c2
-rw-r--r--drivers/sbus/char/uctrl.c11
-rw-r--r--drivers/sbus/char/vfc_dev.c5
-rw-r--r--drivers/sbus/char/vfc_i2c.c2
-rw-r--r--drivers/sbus/sbus.c18
-rw-r--r--drivers/scsi/3w-9xxx.c2
-rw-r--r--drivers/scsi/3w-xxxx.c2
-rw-r--r--drivers/scsi/53c700.c25
-rw-r--r--drivers/scsi/53c700.h2
-rw-r--r--drivers/scsi/53c7xx.c5
-rw-r--r--drivers/scsi/BusLogic.c46
-rw-r--r--drivers/scsi/BusLogic.h300
-rw-r--r--drivers/scsi/FlashPoint.c4
-rw-r--r--drivers/scsi/Kconfig14
-rw-r--r--drivers/scsi/Makefile1
-rw-r--r--drivers/scsi/NCR53C9x.c8
-rw-r--r--drivers/scsi/NCR53C9x.h2
-rw-r--r--drivers/scsi/NCR53c406a.c1
-rw-r--r--drivers/scsi/NCR_D700.c1
-rw-r--r--drivers/scsi/a100u2w.c2
-rw-r--r--drivers/scsi/a2091.c1
-rw-r--r--drivers/scsi/a3000.c1
-rw-r--r--drivers/scsi/aacraid/Makefile2
-rw-r--r--drivers/scsi/aacraid/aachba.c603
-rw-r--r--drivers/scsi/aacraid/aacraid.h46
-rw-r--r--drivers/scsi/aacraid/commctrl.c1
-rw-r--r--drivers/scsi/aacraid/comminit.c15
-rw-r--r--drivers/scsi/aacraid/commsup.c40
-rw-r--r--drivers/scsi/aacraid/dpcsup.c1
-rw-r--r--drivers/scsi/aacraid/linit.c19
-rw-r--r--drivers/scsi/aacraid/nark.c87
-rw-r--r--drivers/scsi/aacraid/rkt.c64
-rw-r--r--drivers/scsi/aacraid/rx.c264
-rw-r--r--drivers/scsi/aacraid/sa.c34
-rw-r--r--drivers/scsi/advansys.c7
-rw-r--r--drivers/scsi/aha152x.c1
-rw-r--r--drivers/scsi/aic7xxx/aic79xx.h3
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_core.c5
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm.c10
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm.h2
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm_pci.c19
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_pci.c2
-rw-r--r--drivers/scsi/aic7xxx_old.c1
-rw-r--r--drivers/scsi/aic94xx/aic94xx_dev.c16
-rw-r--r--drivers/scsi/aic94xx/aic94xx_dump.c2
-rw-r--r--drivers/scsi/aic94xx/aic94xx_hwi.c3
-rw-r--r--drivers/scsi/aic94xx/aic94xx_init.c51
-rw-r--r--drivers/scsi/aic94xx/aic94xx_reg_def.h5
-rw-r--r--drivers/scsi/aic94xx/aic94xx_sas.h1
-rw-r--r--drivers/scsi/aic94xx/aic94xx_scb.c122
-rw-r--r--drivers/scsi/aic94xx/aic94xx_sds.c10
-rw-r--r--drivers/scsi/aic94xx/aic94xx_seq.c58
-rw-r--r--drivers/scsi/aic94xx/aic94xx_seq.h2
-rw-r--r--drivers/scsi/aic94xx/aic94xx_task.c9
-rw-r--r--drivers/scsi/aic94xx/aic94xx_tmf.c4
-rw-r--r--drivers/scsi/amiga7xx.c1
-rw-r--r--drivers/scsi/arcmsr/arcmsr_hba.c2
-rw-r--r--drivers/scsi/arm/acornscsi.c1
-rw-r--r--drivers/scsi/arm/arxescsi.c1
-rw-r--r--drivers/scsi/arm/cumana_1.c1
-rw-r--r--drivers/scsi/arm/cumana_2.c1
-rw-r--r--drivers/scsi/arm/ecoscsi.c1
-rw-r--r--drivers/scsi/arm/eesox.c3
-rw-r--r--drivers/scsi/arm/fas216.c1
-rw-r--r--drivers/scsi/arm/oak.c1
-rw-r--r--drivers/scsi/arm/powertec.c1
-rw-r--r--drivers/scsi/atari_scsi.c1
-rw-r--r--drivers/scsi/blz1230.c3
-rw-r--r--drivers/scsi/blz2060.c2
-rw-r--r--drivers/scsi/bvme6000.c1
-rw-r--r--drivers/scsi/ch.c3
-rw-r--r--drivers/scsi/cyberstorm.c2
-rw-r--r--drivers/scsi/cyberstormII.c2
-rw-r--r--drivers/scsi/dec_esp.c355
-rw-r--r--drivers/scsi/dpt_i2o.c2
-rw-r--r--drivers/scsi/dtc.c1
-rw-r--r--drivers/scsi/eata_pio.c1
-rw-r--r--drivers/scsi/fastlane.c2
-rw-r--r--drivers/scsi/g_NCR5380.c1
-rw-r--r--drivers/scsi/gdth.c3
-rw-r--r--drivers/scsi/gvp11.c1
-rw-r--r--drivers/scsi/ibmvscsi/ibmvstgt.c2
-rw-r--r--drivers/scsi/ide-scsi.c8
-rw-r--r--drivers/scsi/initio.c1
-rw-r--r--drivers/scsi/ipr.c94
-rw-r--r--drivers/scsi/ipr.h4
-rw-r--r--drivers/scsi/iscsi_tcp.c2
-rw-r--r--drivers/scsi/jazz_esp.c2
-rw-r--r--drivers/scsi/lasi700.c2
-rw-r--r--drivers/scsi/libiscsi.c40
-rw-r--r--drivers/scsi/libsas/sas_discover.c62
-rw-r--r--drivers/scsi/libsas/sas_event.c6
-rw-r--r--drivers/scsi/libsas/sas_expander.c48
-rw-r--r--drivers/scsi/libsas/sas_init.c52
-rw-r--r--drivers/scsi/libsas/sas_internal.h9
-rw-r--r--drivers/scsi/libsas/sas_port.c14
-rw-r--r--drivers/scsi/libsas/sas_scsi_host.c290
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c97
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c12
-rw-r--r--drivers/scsi/mac_esp.c2
-rw-r--r--drivers/scsi/mac_scsi.c1
-rw-r--r--drivers/scsi/mca_53c9x.c2
-rw-r--r--drivers/scsi/megaraid.c4
-rw-r--r--drivers/scsi/megaraid/mbox_defs.h2
-rw-r--r--drivers/scsi/megaraid/mega_common.h122
-rw-r--r--drivers/scsi/megaraid/megaraid_ioctl.h36
-rw-r--r--drivers/scsi/megaraid/megaraid_mbox.c421
-rw-r--r--drivers/scsi/megaraid/megaraid_mbox.h46
-rw-r--r--drivers/scsi/megaraid/megaraid_mm.c67
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.c92
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.h20
-rw-r--r--drivers/scsi/mvme147.c1
-rw-r--r--drivers/scsi/mvme16x.c1
-rw-r--r--drivers/scsi/nsp32.c1
-rw-r--r--drivers/scsi/oktagon_esp.c2
-rw-r--r--drivers/scsi/osst.c22
-rw-r--r--drivers/scsi/osst.h68
-rw-r--r--drivers/scsi/pas16.c1
-rw-r--r--drivers/scsi/pcmcia/aha152x_stub.c1
-rw-r--r--drivers/scsi/pcmcia/fdomain_stub.c1
-rw-r--r--drivers/scsi/pcmcia/nsp_cs.c1
-rw-r--r--drivers/scsi/pcmcia/nsp_cs.h66
-rw-r--r--drivers/scsi/pcmcia/qlogic_stub.c1
-rw-r--r--drivers/scsi/pcmcia/sym53c500_cs.c1
-rw-r--r--drivers/scsi/qla1280.c1
-rw-r--r--drivers/scsi/qla2xxx/qla_attr.c68
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h38
-rw-r--r--drivers/scsi/qla2xxx/qla_gbl.h6
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c218
-rw-r--r--drivers/scsi/qla2xxx/qla_isr.c245
-rw-r--r--drivers/scsi/qla2xxx/qla_mbx.c18
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c24
-rw-r--r--drivers/scsi/qla2xxx/qla_sup.c348
-rw-r--r--drivers/scsi/qla2xxx/qla_version.h2
-rw-r--r--drivers/scsi/qla4xxx/ql4_os.c2
-rw-r--r--drivers/scsi/scsi.c22
-rw-r--r--drivers/scsi/scsi_debug.c43
-rw-r--r--drivers/scsi/scsi_error.c256
-rw-r--r--drivers/scsi/scsi_lib.c7
-rw-r--r--drivers/scsi/scsi_priv.h6
-rw-r--r--drivers/scsi/scsi_proc.c7
-rw-r--r--drivers/scsi/scsi_scan.c18
-rw-r--r--drivers/scsi/scsi_sysctl.c2
-rw-r--r--drivers/scsi/scsi_sysfs.c2
-rw-r--r--drivers/scsi/scsi_tgt_if.c10
-rw-r--r--drivers/scsi/scsi_transport_fc.c3
-rw-r--r--drivers/scsi/scsi_transport_sas.c122
-rw-r--r--drivers/scsi/scsi_transport_spi.c1
-rw-r--r--drivers/scsi/sd.c12
-rw-r--r--drivers/scsi/sgiwd93.c5
-rw-r--r--drivers/scsi/sim710.c1
-rw-r--r--drivers/scsi/sni_53c710.c159
-rw-r--r--drivers/scsi/sr.c1
-rw-r--r--drivers/scsi/sr_ioctl.c1
-rw-r--r--drivers/scsi/st.c63
-rw-r--r--drivers/scsi/st.h3
-rw-r--r--drivers/scsi/stex.c1
-rw-r--r--drivers/scsi/sun3_scsi.c1
-rw-r--r--drivers/scsi/sun3_scsi_vme.c1
-rw-r--r--drivers/scsi/sun3x_esp.c2
-rw-r--r--drivers/scsi/sym53c416.c1
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_fw1.h4
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_fw2.h4
-rw-r--r--drivers/scsi/t128.c1
-rw-r--r--drivers/scsi/tmscsim.c1
-rw-r--r--drivers/scsi/wd33c93.c322
-rw-r--r--drivers/scsi/wd33c93.h6
-rw-r--r--drivers/serial/8250.c188
-rw-r--r--drivers/serial/8250_acorn.c3
-rw-r--r--drivers/serial/8250_pci.c33
-rw-r--r--drivers/serial/8250_pnp.c8
-rw-r--r--drivers/serial/Kconfig34
-rw-r--r--drivers/serial/Makefile2
-rw-r--r--drivers/serial/atmel_serial.c57
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_cpm1.c15
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_cpm1.h3
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_cpm2.c2
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_cpm2.h3
-rw-r--r--drivers/serial/crisv10.c14
-rw-r--r--drivers/serial/icom.c5
-rw-r--r--drivers/serial/imx.c14
-rw-r--r--drivers/serial/ioc3_serial.c6
-rw-r--r--drivers/serial/ioc4_serial.c15
-rw-r--r--drivers/serial/ip22zilog.c9
-rw-r--r--drivers/serial/jsm/jsm_driver.c6
-rw-r--r--drivers/serial/jsm/jsm_tty.c12
-rw-r--r--drivers/serial/mpc52xx_uart.c9
-rw-r--r--drivers/serial/of_serial.c143
-rw-r--r--drivers/serial/pnx8xxx_uart.c852
-rw-r--r--drivers/serial/serial_core.c18
-rw-r--r--drivers/serial/serial_cs.c9
-rw-r--r--drivers/serial/serial_txx9.c293
-rw-r--r--drivers/serial/sunsab.c1
-rw-r--r--drivers/serial/sunsu.c1
-rw-r--r--drivers/serial/sunzilog.c1
-rw-r--r--drivers/serial/uartlite.c6
-rw-r--r--drivers/sn/ioc3.c6
-rw-r--r--drivers/spi/Kconfig45
-rw-r--r--drivers/spi/Makefile4
-rw-r--r--drivers/spi/at25.c381
-rw-r--r--drivers/spi/atmel_spi.c682
-rw-r--r--drivers/spi/atmel_spi.h167
-rw-r--r--drivers/spi/omap_uwire.c572
-rw-r--r--drivers/spi/pxa2xx_spi.c4
-rw-r--r--drivers/spi/spi.c2
-rw-r--r--drivers/spi/spi_bitbang.c11
-rw-r--r--drivers/spi/spi_imx.c1768
-rw-r--r--drivers/spi/spi_s3c24xx_gpio.c15
-rw-r--r--drivers/tc/Makefile2
-rw-r--r--drivers/tc/lk201.c1
-rw-r--r--drivers/tc/tc-driver.c110
-rw-r--r--drivers/tc/tc.c339
-rw-r--r--drivers/tc/zs.c4
-rw-r--r--drivers/telephony/ixj.c41
-rw-r--r--drivers/telephony/ixj.h4
-rw-r--r--drivers/telephony/ixj_pcmcia.c1
-rw-r--r--drivers/telephony/phonedev.c2
-rw-r--r--drivers/usb/Makefile1
-rw-r--r--drivers/usb/atm/speedtch.c2
-rw-r--r--drivers/usb/atm/ueagle-atm.c1
-rw-r--r--drivers/usb/class/cdc-acm.c33
-rw-r--r--drivers/usb/class/usblp.c16
-rw-r--r--drivers/usb/core/Kconfig13
-rw-r--r--drivers/usb/core/Makefile2
-rw-r--r--drivers/usb/core/buffer.c36
-rw-r--r--drivers/usb/core/devices.c31
-rw-r--r--drivers/usb/core/devio.c29
-rw-r--r--drivers/usb/core/driver.c105
-rw-r--r--drivers/usb/core/endpoint.c2
-rw-r--r--drivers/usb/core/file.c13
-rw-r--r--drivers/usb/core/generic.c30
-rw-r--r--drivers/usb/core/hcd.c137
-rw-r--r--drivers/usb/core/hcd.h6
-rw-r--r--drivers/usb/core/hub.c98
-rw-r--r--drivers/usb/core/message.c34
-rw-r--r--drivers/usb/core/otg_whitelist.h2
-rw-r--r--drivers/usb/core/quirks.c77
-rw-r--r--drivers/usb/core/sysfs.c209
-rw-r--r--drivers/usb/core/urb.c21
-rw-r--r--drivers/usb/core/usb.c108
-rw-r--r--drivers/usb/core/usb.h9
-rw-r--r--drivers/usb/gadget/at91_udc.c41
-rw-r--r--drivers/usb/gadget/at91_udc.h1
-rw-r--r--drivers/usb/gadget/config.c2
-rw-r--r--drivers/usb/gadget/dummy_hcd.c1
-rw-r--r--drivers/usb/gadget/epautoconf.c2
-rw-r--r--drivers/usb/gadget/ether.c149
-rw-r--r--drivers/usb/gadget/file_storage.c35
-rw-r--r--drivers/usb/gadget/gadget_chips.h8
-rw-r--r--drivers/usb/gadget/gmidi.c2
-rw-r--r--drivers/usb/gadget/goku_udc.c3
-rw-r--r--drivers/usb/gadget/inode.c243
-rw-r--r--drivers/usb/gadget/lh7a40x_udc.h2
-rw-r--r--drivers/usb/gadget/net2280.c3
-rw-r--r--drivers/usb/gadget/omap_udc.c3
-rw-r--r--drivers/usb/gadget/pxa2xx_udc.c21
-rw-r--r--drivers/usb/gadget/pxa2xx_udc.h15
-rw-r--r--drivers/usb/gadget/rndis.c1
-rw-r--r--drivers/usb/gadget/serial.c4
-rw-r--r--drivers/usb/gadget/usbstring.c2
-rw-r--r--drivers/usb/gadget/zero.c3
-rw-r--r--drivers/usb/host/Kconfig38
-rw-r--r--drivers/usb/host/ehci-dbg.c26
-rw-r--r--drivers/usb/host/ehci-fsl.c8
-rw-r--r--drivers/usb/host/ehci-hcd.c151
-rw-r--r--drivers/usb/host/ehci-hub.c326
-rw-r--r--drivers/usb/host/ehci-pci.c38
-rw-r--r--drivers/usb/host/ehci-ps3.c193
-rw-r--r--drivers/usb/host/ehci-q.c16
-rw-r--r--drivers/usb/host/ehci-sched.c22
-rw-r--r--drivers/usb/host/ehci.h46
-rw-r--r--drivers/usb/host/hc_crisv10.c4
-rw-r--r--drivers/usb/host/isp116x-hcd.c2
-rw-r--r--drivers/usb/host/ohci-at91.c73
-rw-r--r--drivers/usb/host/ohci-au1xxx.c16
-rw-r--r--drivers/usb/host/ohci-ep93xx.c14
-rw-r--r--drivers/usb/host/ohci-hcd.c136
-rw-r--r--drivers/usb/host/ohci-lh7a404.c16
-rw-r--r--drivers/usb/host/ohci-omap.c19
-rw-r--r--drivers/usb/host/ohci-pci.c219
-rw-r--r--drivers/usb/host/ohci-pnx4008.c14
-rw-r--r--drivers/usb/host/ohci-pnx8550.c18
-rw-r--r--drivers/usb/host/ohci-ppc-of.c232
-rw-r--r--drivers/usb/host/ohci-ppc-soc.c18
-rw-r--r--drivers/usb/host/ohci-ps3.c196
-rw-r--r--drivers/usb/host/ohci-pxa27x.c16
-rw-r--r--drivers/usb/host/ohci-s3c2410.c12
-rw-r--r--drivers/usb/host/ohci-sa1111.c16
-rw-r--r--drivers/usb/host/ohci.h155
-rw-r--r--drivers/usb/host/sl811_cs.c1
-rw-r--r--drivers/usb/host/uhci-debug.c124
-rw-r--r--drivers/usb/host/uhci-hcd.c102
-rw-r--r--drivers/usb/host/uhci-hcd.h90
-rw-r--r--drivers/usb/host/uhci-q.c479
-rw-r--r--drivers/usb/image/mdc800.c4
-rw-r--r--drivers/usb/image/microtek.c1
-rw-r--r--drivers/usb/input/Kconfig26
-rw-r--r--drivers/usb/input/Makefile4
-rw-r--r--drivers/usb/input/aiptek.c1
-rw-r--r--drivers/usb/input/gtco.c1104
-rw-r--r--drivers/usb/input/hid-core.c125
-rw-r--r--drivers/usb/input/hid-ff.c7
-rw-r--r--drivers/usb/input/hid-lgff.c17
-rw-r--r--drivers/usb/input/hid-pidff.c1
-rw-r--r--drivers/usb/input/hid-plff.c129
-rw-r--r--drivers/usb/input/usbkbd.c4
-rw-r--r--drivers/usb/input/usbmouse.c4
-rw-r--r--drivers/usb/input/wacom_wac.c103
-rw-r--r--drivers/usb/input/wacom_wac.h1
-rw-r--r--drivers/usb/misc/Kconfig25
-rw-r--r--drivers/usb/misc/Makefile2
-rw-r--r--drivers/usb/misc/adutux.c2
-rw-r--r--drivers/usb/misc/appledisplay.c20
-rw-r--r--drivers/usb/misc/berry_charge.c140
-rw-r--r--drivers/usb/misc/ftdi-elan.c2
-rw-r--r--drivers/usb/misc/idmouse.c10
-rw-r--r--drivers/usb/misc/iowarrior.c925
-rw-r--r--drivers/usb/misc/rio500.c54
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb.c1
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb_con.c1
-rw-r--r--drivers/usb/mon/Makefile2
-rw-r--r--drivers/usb/mon/mon_bin.c1172
-rw-r--r--drivers/usb/mon/mon_dma.c39
-rw-r--r--drivers/usb/mon/mon_main.c97
-rw-r--r--drivers/usb/mon/mon_text.c67
-rw-r--r--drivers/usb/mon/usb_mon.h30
-rw-r--r--drivers/usb/net/Kconfig26
-rw-r--r--drivers/usb/net/Makefile1
-rw-r--r--drivers/usb/net/asix.c21
-rw-r--r--drivers/usb/net/cdc_ether.c61
-rw-r--r--drivers/usb/net/cdc_subset.c22
-rw-r--r--drivers/usb/net/dm9601.c606
-rw-r--r--drivers/usb/net/gl620a.c27
-rw-r--r--drivers/usb/net/kaweth.c38
-rw-r--r--drivers/usb/net/net1080.c1
-rw-r--r--drivers/usb/net/pegasus.h4
-rw-r--r--drivers/usb/net/plusb.c1
-rw-r--r--drivers/usb/net/rndis_host.c82
-rw-r--r--drivers/usb/net/rtl8150.c1
-rw-r--r--drivers/usb/net/usbnet.c30
-rw-r--r--drivers/usb/net/zaurus.c1
-rw-r--r--drivers/usb/serial/aircable.c21
-rw-r--r--drivers/usb/serial/airprime.c36
-rw-r--r--drivers/usb/serial/ark3116.c2
-rw-r--r--drivers/usb/serial/belkin_sa.c1
-rw-r--r--drivers/usb/serial/bus.c45
-rw-r--r--drivers/usb/serial/cp2101.c10
-rw-r--r--drivers/usb/serial/cyberjack.c3
-rw-r--r--drivers/usb/serial/cypress_m8.c3
-rw-r--r--drivers/usb/serial/digi_acceleport.c12
-rw-r--r--drivers/usb/serial/empeg.c1
-rw-r--r--drivers/usb/serial/ftdi_sio.c3
-rw-r--r--drivers/usb/serial/ftdi_sio.h7
-rw-r--r--drivers/usb/serial/funsoft.c1
-rw-r--r--drivers/usb/serial/garmin_gps.c1
-rw-r--r--drivers/usb/serial/generic.c137
-rw-r--r--drivers/usb/serial/hp4x.c1
-rw-r--r--drivers/usb/serial/io_edgeport.c417
-rw-r--r--drivers/usb/serial/io_edgeport.h6
-rw-r--r--drivers/usb/serial/io_tables.h61
-rw-r--r--drivers/usb/serial/io_ti.c2
-rw-r--r--drivers/usb/serial/io_usbvend.h5
-rw-r--r--drivers/usb/serial/ipaq.c1
-rw-r--r--drivers/usb/serial/ipw.c1
-rw-r--r--drivers/usb/serial/ir-usb.c1
-rw-r--r--drivers/usb/serial/keyspan.c49
-rw-r--r--drivers/usb/serial/keyspan.h7
-rw-r--r--drivers/usb/serial/keyspan_pda.c10
-rw-r--r--drivers/usb/serial/kl5kusb105.c1
-rw-r--r--drivers/usb/serial/kobil_sct.c1
-rw-r--r--drivers/usb/serial/mct_u232.c1
-rw-r--r--drivers/usb/serial/mos7720.c30
-rw-r--r--drivers/usb/serial/mos7840.c30
-rw-r--r--drivers/usb/serial/navman.c1
-rw-r--r--drivers/usb/serial/omninet.c1
-rw-r--r--drivers/usb/serial/option.c122
-rw-r--r--drivers/usb/serial/pl2303.c2
-rw-r--r--drivers/usb/serial/pl2303.h5
-rw-r--r--drivers/usb/serial/safe_serial.c1
-rw-r--r--drivers/usb/serial/sierra.c29
-rw-r--r--drivers/usb/serial/ti_usb_3410_5052.c2
-rw-r--r--drivers/usb/serial/usb-serial.c102
-rw-r--r--drivers/usb/serial/visor.c6
-rw-r--r--drivers/usb/serial/visor.h1
-rw-r--r--drivers/usb/serial/whiteheat.c2
-rw-r--r--drivers/usb/storage/datafab.c1
-rw-r--r--drivers/usb/storage/initializers.c1
-rw-r--r--drivers/usb/storage/jumpshot.c1
-rw-r--r--drivers/usb/storage/onetouch.c1
-rw-r--r--drivers/usb/storage/scsiglue.c37
-rw-r--r--drivers/usb/storage/sddr09.c1
-rw-r--r--drivers/usb/storage/shuttle_usbat.c1
-rw-r--r--drivers/usb/storage/unusual_devs.h35
-rw-r--r--drivers/usb/storage/usb.c23
-rw-r--r--drivers/usb/usb-skeleton.c10
-rw-r--r--drivers/video/Kconfig186
-rw-r--r--drivers/video/Makefile11
-rw-r--r--drivers/video/S3triofb.c790
-rw-r--r--drivers/video/atafb.c1
-rw-r--r--drivers/video/aty/aty128fb.c102
-rw-r--r--drivers/video/aty/atyfb_base.c104
-rw-r--r--drivers/video/aty/mach64_accel.c1
-rw-r--r--drivers/video/aty/mach64_gx.c1
-rw-r--r--drivers/video/aty/radeon_backlight.c59
-rw-r--r--drivers/video/aty/radeon_base.c3
-rw-r--r--drivers/video/aty/radeon_i2c.c1
-rw-r--r--drivers/video/au1100fb.c6
-rw-r--r--drivers/video/backlight/Kconfig23
-rw-r--r--drivers/video/backlight/Makefile1
-rw-r--r--drivers/video/backlight/backlight.c123
-rw-r--r--drivers/video/backlight/corgi_bl.c54
-rw-r--r--drivers/video/backlight/hp680_bl.c50
-rw-r--r--drivers/video/backlight/lcd.c83
-rw-r--r--drivers/video/backlight/locomolcd.c13
-rw-r--r--drivers/video/backlight/progear_bl.c153
-rw-r--r--drivers/video/chipsfb.c26
-rw-r--r--drivers/video/console/fbcon.c12
-rw-r--r--drivers/video/console/fbcon.h2
-rw-r--r--drivers/video/console/mdacon.c1
-rw-r--r--drivers/video/console/vgacon.c1
-rw-r--r--drivers/video/controlfb.c3
-rw-r--r--drivers/video/cyber2000fb.c19
-rw-r--r--drivers/video/cyberfb.c2295
-rw-r--r--drivers/video/cyberfb.h415
-rw-r--r--drivers/video/fbmem.c1
-rw-r--r--drivers/video/fbsysfs.c16
-rw-r--r--drivers/video/g364fb.c1
-rw-r--r--drivers/video/geode/gx1fb_core.c29
-rw-r--r--drivers/video/hitfb.c1
-rw-r--r--drivers/video/hpfb.c1
-rw-r--r--drivers/video/i810/i810-i2c.c1
-rw-r--r--drivers/video/i810/i810.h3
-rw-r--r--drivers/video/i810/i810_main.c34
-rw-r--r--drivers/video/igafb.c8
-rw-r--r--drivers/video/imxfb.c1
-rw-r--r--drivers/video/intelfb/intelfb_i2c.c1
-rw-r--r--drivers/video/intelfb/intelfbdrv.c3
-rw-r--r--drivers/video/intelfb/intelfbhw.c3
-rw-r--r--drivers/video/kyro/fbdev.c1
-rw-r--r--drivers/video/macfb.c1
-rw-r--r--drivers/video/matrox/i2c-matroxfb.c5
-rw-r--r--drivers/video/matrox/matroxfb_crtc2.c3
-rw-r--r--drivers/video/maxinefb.c1
-rw-r--r--drivers/video/mbx/mbxdebugfs.c12
-rw-r--r--drivers/video/modedb.c48
-rw-r--r--drivers/video/neofb.c22
-rw-r--r--drivers/video/nvidia/nv_backlight.c92
-rw-r--r--drivers/video/nvidia/nv_i2c.c1
-rw-r--r--drivers/video/nvidia/nv_of.c1
-rw-r--r--drivers/video/nvidia/nv_proto.h2
-rw-r--r--drivers/video/nvidia/nvidia.c21
-rw-r--r--drivers/video/output.c129
-rw-r--r--drivers/video/pm3fb.c29
-rw-r--r--drivers/video/pmag-aa-fb.c1
-rw-r--r--drivers/video/pmag-ba-fb.c95
-rw-r--r--drivers/video/pmagb-b-fb.c98
-rw-r--r--drivers/video/ps3fb.c1229
-rw-r--r--drivers/video/retz3fb.c1588
-rw-r--r--drivers/video/retz3fb.h286
-rw-r--r--drivers/video/riva/fbdev.c127
-rw-r--r--drivers/video/riva/rivafb-i2c.c1
-rw-r--r--drivers/video/riva/rivafb.h3
-rw-r--r--drivers/video/s3c2410fb.c2
-rw-r--r--drivers/video/s3fb.c1180
-rw-r--r--drivers/video/sa1100fb.h4
-rw-r--r--drivers/video/savage/savagefb-i2c.c1
-rw-r--r--drivers/video/savage/savagefb_driver.c12
-rw-r--r--drivers/video/sis/init.c140
-rw-r--r--drivers/video/sis/init.h36
-rw-r--r--drivers/video/sis/init301.c260
-rw-r--r--drivers/video/sis/init301.h14
-rw-r--r--drivers/video/sis/initextlfb.c18
-rw-r--r--drivers/video/sis/sis.h2
-rw-r--r--drivers/video/sis/sis_main.c214
-rw-r--r--drivers/video/sis/sis_main.h112
-rw-r--r--drivers/video/sis/vgatypes.h12
-rw-r--r--drivers/video/sis/vstruct.h44
-rw-r--r--drivers/video/sm501fb.c1786
-rw-r--r--drivers/video/sun3fb.c702
-rw-r--r--drivers/video/svgalib.c632
-rw-r--r--drivers/video/tgafb.c186
-rw-r--r--drivers/video/vga16fb.c23
-rw-r--r--drivers/video/virgefb.c2526
-rw-r--r--drivers/video/virgefb.h288
-rw-r--r--drivers/w1/slaves/w1_therm.c6
-rw-r--r--drivers/zorro/proc.c2
2067 files changed, 123678 insertions, 68103 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig
index e7da9fa724e..050323fd79e 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -80,6 +80,8 @@ source "drivers/rtc/Kconfig"
source "drivers/dma/Kconfig"
+source "drivers/auxdisplay/Kconfig"
+
source "drivers/kvm/Kconfig"
endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 0dd96d1afd3..3a718f51350 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -30,7 +30,7 @@ obj-$(CONFIG_PARPORT) += parport/
obj-y += base/ block/ misc/ mfd/ net/ media/
obj-$(CONFIG_NUBUS) += nubus/
obj-$(CONFIG_ATM) += atm/
-obj-$(CONFIG_PPC_PMAC) += macintosh/
+obj-y += macintosh/
obj-$(CONFIG_IDE) += ide/
obj-$(CONFIG_FC4) += fc4/
obj-$(CONFIG_SCSI) += scsi/
@@ -38,6 +38,7 @@ obj-$(CONFIG_ATA) += ata/
obj-$(CONFIG_FUSION) += message/
obj-$(CONFIG_IEEE1394) += ieee1394/
obj-y += cdrom/
+obj-y += auxdisplay/
obj-$(CONFIG_MTD) += mtd/
obj-$(CONFIG_SPI) += spi/
obj-$(CONFIG_PCCARD) += pcmcia/
diff --git a/drivers/acorn/block/mfmhd.c b/drivers/acorn/block/mfmhd.c
index 7fde8f4daeb..689a4c3542b 100644
--- a/drivers/acorn/block/mfmhd.c
+++ b/drivers/acorn/block/mfmhd.c
@@ -99,7 +99,6 @@
*/
#include <linux/module.h>
-#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
diff --git a/drivers/acorn/char/i2c.c b/drivers/acorn/char/i2c.c
index 9e584a7af43..d276fd14d63 100644
--- a/drivers/acorn/char/i2c.c
+++ b/drivers/acorn/char/i2c.c
@@ -14,7 +14,6 @@
*/
#include <linux/capability.h>
#include <linux/init.h>
-#include <linux/sched.h>
#include <linux/time.h>
#include <linux/miscdevice.h>
#include <linux/rtc.h>
@@ -238,7 +237,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file,
return -EINVAL;
}
-static struct file_operations rtc_fops = {
+static const struct file_operations rtc_fops = {
.ioctl = rtc_ioctl,
};
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index f4f000abc4e..e942ffe8b57 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -3,6 +3,7 @@
#
menu "ACPI (Advanced Configuration and Power Interface) Support"
+ depends on !X86_NUMAQ
depends on !X86_VISWS
depends on !IA64_HP_SIM
depends on IA64 || X86
@@ -12,6 +13,7 @@ config ACPI
depends on IA64 || X86
depends on PCI
depends on PM
+ select PNP
default y
---help---
Advanced Configuration and Power Interface (ACPI) support for
@@ -77,6 +79,20 @@ config ACPI_SLEEP_PROC_SLEEP
Create /proc/acpi/sleep
Deprecated by /sys/power/state
+config ACPI_PROCFS
+ bool "Procfs interface (deprecated)"
+ depends on ACPI
+ default y
+ ---help---
+ Procfs interface for ACPI is made optional for back-compatible.
+ As the same functions are duplicated in sysfs interface
+ and this proc interface will be removed some time later,
+ it's marked as deprecated.
+ ( /proc/acpi/debug_layer && debug_level are deprecated by
+ /sys/module/acpi/parameters/debug_layer && debug_level.
+ /proc/acpi/info is deprecated by
+ /sys/module/acpi/parameters/acpica_version )
+
config ACPI_AC
tristate "AC Adapter"
depends on X86
@@ -107,7 +123,7 @@ config ACPI_BUTTON
config ACPI_VIDEO
tristate "Video"
- depends on X86
+ depends on X86 && BACKLIGHT_CLASS_DEVICE
help
This driver implement the ACPI Extensions For Display Adapters
for integrated graphics devices on motherboard, as specified in
@@ -117,15 +133,6 @@ config ACPI_VIDEO
Note that this is an ref. implementation only. It may or may not work
for your integrated video device.
-config ACPI_HOTKEY
- tristate "Generic Hotkey (EXPERIMENTAL)"
- depends on EXPERIMENTAL
- depends on X86
- default n
- help
- Experimental consolidated hotkey driver.
- If you are unsure, say N.
-
config ACPI_FAN
tristate "Fan"
default y
@@ -139,6 +146,13 @@ config ACPI_DOCK
help
This driver adds support for ACPI controlled docking stations
+config ACPI_BAY
+ tristate "Removable Drive Bay (EXPERIMENTAL)"
+ depends on EXPERIMENTAL
+ help
+ This driver adds support for ACPI controlled removable drive
+ bays such as the IBM ultrabay or the Dell Module Bay.
+
config ACPI_PROCESSOR
tristate "Processor"
default y
@@ -186,19 +200,22 @@ config ACPI_ASUS
Note: display switching code is currently considered EXPERIMENTAL,
toying with these values may even lock your machine.
-
+
All settings are changed via /proc/acpi/asus directory entries. Owner
and group for these entries can be set with asus_uid and asus_gid
parameters.
-
+
More information and a userspace daemon for handling the extra buttons
at <http://sourceforge.net/projects/acpi4asus/>.
-
+
If you have an ACPI-compatible ASUS laptop, say Y or M here. This
driver is still under development, so if your laptop is unsupported or
something works not quite as expected, please use the mailing list
- available on the above page (acpi4asus-user@lists.sourceforge.net)
-
+ available on the above page (acpi4asus-user@lists.sourceforge.net).
+
+ NOTE: This driver is deprecated and will probably be removed soon,
+ use asus-laptop instead.
+
config ACPI_IBM
tristate "IBM ThinkPad Laptop Extras"
depends on X86
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index bce7ca27b42..5956e9f64a8 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -37,14 +37,15 @@ endif
obj-y += sleep/
obj-y += bus.o glue.o
+obj-y += scan.o
obj-$(CONFIG_ACPI_AC) += ac.o
obj-$(CONFIG_ACPI_BATTERY) += battery.o
obj-$(CONFIG_ACPI_BUTTON) += button.o
obj-$(CONFIG_ACPI_EC) += ec.o
obj-$(CONFIG_ACPI_FAN) += fan.o
obj-$(CONFIG_ACPI_DOCK) += dock.o
-obj-$(CONFIG_ACPI_VIDEO) += video.o
-obj-$(CONFIG_ACPI_HOTKEY) += hotkey.o
+obj-$(CONFIG_ACPI_BAY) += bay.o
+obj-$(CONFIG_ACPI_VIDEO) += video.o
obj-y += pci_root.o pci_link.o pci_irq.o pci_bind.o
obj-$(CONFIG_ACPI_POWER) += power.o
obj-$(CONFIG_ACPI_PROCESSOR) += processor.o
@@ -56,7 +57,6 @@ obj-$(CONFIG_ACPI_NUMA) += numa.o
obj-$(CONFIG_ACPI_ASUS) += asus_acpi.o
obj-$(CONFIG_ACPI_IBM) += ibm_acpi.o
obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o
-obj-y += scan.o motherboard.o
obj-$(CONFIG_ACPI_HOTPLUG_MEMORY) += acpi_memhotplug.o
obj-y += cm_sbs.o
obj-$(CONFIG_ACPI_SBS) += i2c_ec.o sbs.o
diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c
index 6daeace796a..37c7dc4f9fe 100644
--- a/drivers/acpi/ac.c
+++ b/drivers/acpi/ac.c
@@ -35,7 +35,6 @@
#define ACPI_AC_COMPONENT 0x00020000
#define ACPI_AC_CLASS "ac_adapter"
#define ACPI_AC_HID "ACPI0003"
-#define ACPI_AC_DRIVER_NAME "ACPI AC Adapter Driver"
#define ACPI_AC_DEVICE_NAME "AC Adapter"
#define ACPI_AC_FILE_STATE "state"
#define ACPI_AC_NOTIFY_STATUS 0x80
@@ -44,10 +43,10 @@
#define ACPI_AC_STATUS_UNKNOWN 0xFF
#define _COMPONENT ACPI_AC_COMPONENT
-ACPI_MODULE_NAME("acpi_ac")
+ACPI_MODULE_NAME("ac");
- MODULE_AUTHOR("Paul Diefenbaugh");
-MODULE_DESCRIPTION(ACPI_AC_DRIVER_NAME);
+MODULE_AUTHOR("Paul Diefenbaugh");
+MODULE_DESCRIPTION("ACPI AC Adapter Driver");
MODULE_LICENSE("GPL");
extern struct proc_dir_entry *acpi_lock_ac_dir(void);
@@ -58,7 +57,7 @@ static int acpi_ac_remove(struct acpi_device *device, int type);
static int acpi_ac_open_fs(struct inode *inode, struct file *file);
static struct acpi_driver acpi_ac_driver = {
- .name = ACPI_AC_DRIVER_NAME,
+ .name = "ac",
.class = ACPI_AC_CLASS,
.ids = ACPI_AC_HID,
.ops = {
diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c
index cd946ed192d..c26172671fd 100644
--- a/drivers/acpi/acpi_memhotplug.c
+++ b/drivers/acpi/acpi_memhotplug.c
@@ -35,14 +35,13 @@
#define ACPI_MEMORY_DEVICE_COMPONENT 0x08000000UL
#define ACPI_MEMORY_DEVICE_CLASS "memory"
#define ACPI_MEMORY_DEVICE_HID "PNP0C80"
-#define ACPI_MEMORY_DEVICE_DRIVER_NAME "Hotplug Mem Driver"
#define ACPI_MEMORY_DEVICE_NAME "Hotplug Mem Device"
#define _COMPONENT ACPI_MEMORY_DEVICE_COMPONENT
-ACPI_MODULE_NAME("acpi_memory")
- MODULE_AUTHOR("Naveen B S <naveen.b.s@intel.com>");
-MODULE_DESCRIPTION(ACPI_MEMORY_DEVICE_DRIVER_NAME);
+ACPI_MODULE_NAME("acpi_memhotplug");
+MODULE_AUTHOR("Naveen B S <naveen.b.s@intel.com>");
+MODULE_DESCRIPTION("Hotplug Mem Driver");
MODULE_LICENSE("GPL");
/* ACPI _STA method values */
@@ -60,7 +59,7 @@ static int acpi_memory_device_remove(struct acpi_device *device, int type);
static int acpi_memory_device_start(struct acpi_device *device);
static struct acpi_driver acpi_memory_device_driver = {
- .name = ACPI_MEMORY_DEVICE_DRIVER_NAME,
+ .name = "acpi_memhotplug",
.class = ACPI_MEMORY_DEVICE_CLASS,
.ids = ACPI_MEMORY_DEVICE_HID,
.ops = {
diff --git a/drivers/acpi/asus_acpi.c b/drivers/acpi/asus_acpi.c
index 396140bbbe5..b770deab968 100644
--- a/drivers/acpi/asus_acpi.c
+++ b/drivers/acpi/asus_acpi.c
@@ -26,7 +26,7 @@
* Pontus Fuchs - Helper functions, cleanup
* Johann Wiesner - Small compile fixes
* John Belmonte - ACPI code for Toshiba laptop was a good starting point.
- * Éric Burghard - LED display support for W1N
+ * �ic Burghard - LED display support for W1N
*
*/
@@ -141,6 +141,7 @@ struct asus_hotk {
W5A, //W5A
W3V, //W3030V
xxN, //M2400N, M3700N, M5200N, M6800N, S1300N, S5200N
+ A4S, //Z81sp
//(Centrino)
END_MODEL
} model; //Models currently supported
@@ -397,7 +398,16 @@ static struct model_data model_conf[END_MODEL] = {
.brightness_set = "SPLV",
.brightness_get = "GPLV",
.display_set = "SDSP",
- .display_get = "\\ADVG"}
+ .display_get = "\\ADVG"},
+
+ {
+ .name = "A4S",
+ .brightness_set = "SPLV",
+ .brightness_get = "GPLV",
+ .mt_bt_switch = "BLED",
+ .mt_wled = "WLED"
+ }
+
};
/* procdir we use */
@@ -421,7 +431,7 @@ static struct asus_hotk *hotk;
static int asus_hotk_add(struct acpi_device *device);
static int asus_hotk_remove(struct acpi_device *device, int type);
static struct acpi_driver asus_hotk_driver = {
- .name = ACPI_HOTK_NAME,
+ .name = "asus_acpi",
.class = ACPI_HOTK_CLASS,
.ids = ACPI_HOTK_HID,
.ops = {
@@ -838,7 +848,7 @@ out:
static int set_brightness_status(struct backlight_device *bd)
{
- return set_brightness(bd->props->brightness);
+ return set_brightness(bd->props.brightness);
}
static int
@@ -1117,6 +1127,8 @@ static int asus_model_match(char *model)
return W3V;
else if (strncmp(model, "W5A", 3) == 0)
return W5A;
+ else if (strncmp(model, "A4S", 3) == 0)
+ return A4S;
else
return END_MODEL;
}
@@ -1128,7 +1140,6 @@ static int asus_model_match(char *model)
static int asus_hotk_get_info(void)
{
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
- struct acpi_buffer dsdt = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *model = NULL;
int bsts_result;
char *string = NULL;
@@ -1142,11 +1153,9 @@ static int asus_hotk_get_info(void)
* HID), this bit will be moved. A global variable asus_info contains
* the DSDT header.
*/
- status = acpi_get_table(ACPI_TABLE_ID_DSDT, 1, &dsdt);
+ status = acpi_get_table(ACPI_SIG_DSDT, 1, &asus_info);
if (ACPI_FAILURE(status))
printk(KERN_WARNING " Couldn't get the DSDT table header\n");
- else
- asus_info = dsdt.pointer;
/* We have to write 0 on init this far for all ASUS models */
if (!write_acpi_int(hotk->handle, "INIT", 0, &buffer)) {
@@ -1343,11 +1352,9 @@ static int asus_hotk_remove(struct acpi_device *device, int type)
return 0;
}
-static struct backlight_properties asus_backlight_data = {
- .owner = THIS_MODULE,
+static struct backlight_ops asus_backlight_data = {
.get_brightness = read_brightness,
.update_status = set_brightness_status,
- .max_brightness = 15,
};
static void __exit asus_acpi_exit(void)
@@ -1358,8 +1365,6 @@ static void __exit asus_acpi_exit(void)
acpi_bus_unregister_driver(&asus_hotk_driver);
remove_proc_entry(PROC_ASUS, acpi_root_dir);
- kfree(asus_info);
-
return;
}
@@ -1370,10 +1375,6 @@ static int __init asus_acpi_init(void)
if (acpi_disabled)
return -ENODEV;
- if (!acpi_specific_hotkey_enabled) {
- printk(KERN_ERR "Using generic hotkey driver\n");
- return -ENODEV;
- }
asus_proc_dir = proc_mkdir(PROC_ASUS, acpi_root_dir);
if (!asus_proc_dir) {
printk(KERN_ERR "Asus ACPI: Unable to create /proc entry\n");
@@ -1407,6 +1408,7 @@ static int __init asus_acpi_init(void)
asus_backlight_device = NULL;
asus_acpi_exit();
}
+ asus_backlight_device->props.max_brightness = 15;
return 0;
}
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index 5f43e0d1489..e64c76c8b72 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -42,7 +42,6 @@
#define ACPI_BATTERY_COMPONENT 0x00040000
#define ACPI_BATTERY_CLASS "battery"
#define ACPI_BATTERY_HID "PNP0C0A"
-#define ACPI_BATTERY_DRIVER_NAME "ACPI Battery Driver"
#define ACPI_BATTERY_DEVICE_NAME "Battery"
#define ACPI_BATTERY_FILE_INFO "info"
#define ACPI_BATTERY_FILE_STATUS "state"
@@ -53,10 +52,10 @@
#define ACPI_BATTERY_UNITS_AMPS "mA"
#define _COMPONENT ACPI_BATTERY_COMPONENT
-ACPI_MODULE_NAME("acpi_battery")
+ACPI_MODULE_NAME("battery");
- MODULE_AUTHOR("Paul Diefenbaugh");
-MODULE_DESCRIPTION(ACPI_BATTERY_DRIVER_NAME);
+MODULE_AUTHOR("Paul Diefenbaugh");
+MODULE_DESCRIPTION("ACPI Battery Driver");
MODULE_LICENSE("GPL");
extern struct proc_dir_entry *acpi_lock_battery_dir(void);
@@ -64,10 +63,10 @@ extern void *acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir);
static int acpi_battery_add(struct acpi_device *device);
static int acpi_battery_remove(struct acpi_device *device, int type);
-static int acpi_battery_resume(struct acpi_device *device, int status);
+static int acpi_battery_resume(struct acpi_device *device);
static struct acpi_driver acpi_battery_driver = {
- .name = ACPI_BATTERY_DRIVER_NAME,
+ .name = "battery",
.class = ACPI_BATTERY_CLASS,
.ids = ACPI_BATTERY_HID,
.ops = {
@@ -324,6 +323,13 @@ static int acpi_battery_check(struct acpi_battery *battery)
return result;
}
+static void acpi_battery_check_present(struct acpi_battery *battery)
+{
+ if (!battery->flags.present) {
+ acpi_battery_check(battery);
+ }
+}
+
/* --------------------------------------------------------------------------
FS Interface (/proc)
-------------------------------------------------------------------------- */
@@ -340,6 +346,8 @@ static int acpi_battery_read_info(struct seq_file *seq, void *offset)
if (!battery)
goto end;
+ acpi_battery_check_present(battery);
+
if (battery->flags.present)
seq_printf(seq, "present: yes\n");
else {
@@ -424,6 +432,8 @@ static int acpi_battery_read_state(struct seq_file *seq, void *offset)
if (!battery)
goto end;
+ acpi_battery_check_present(battery);
+
if (battery->flags.present)
seq_printf(seq, "present: yes\n");
else {
@@ -499,6 +509,8 @@ static int acpi_battery_read_alarm(struct seq_file *seq, void *offset)
if (!battery)
goto end;
+ acpi_battery_check_present(battery);
+
if (!battery->flags.present) {
seq_printf(seq, "present: no\n");
goto end;
@@ -536,6 +548,8 @@ acpi_battery_write_alarm(struct file *file,
if (!battery || (count > sizeof(alarm_string) - 1))
return -EINVAL;
+ acpi_battery_check_present(battery);
+
if (!battery->flags.present)
return -ENODEV;
@@ -753,7 +767,7 @@ static int acpi_battery_remove(struct acpi_device *device, int type)
}
/* this is needed to learn about changes made in suspended state */
-static int acpi_battery_resume(struct acpi_device *device, int state)
+static int acpi_battery_resume(struct acpi_device *device)
{
struct acpi_battery *battery;
diff --git a/drivers/acpi/bay.c b/drivers/acpi/bay.c
new file mode 100644
index 00000000000..fb3f31b5e69
--- /dev/null
+++ b/drivers/acpi/bay.c
@@ -0,0 +1,397 @@
+/*
+ * bay.c - ACPI removable drive bay driver
+ *
+ * Copyright (C) 2006 Kristen Carlson Accardi <kristen.c.accardi@intel.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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/notifier.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+#include <linux/seq_file.h>
+#include <asm/uaccess.h>
+#include <linux/platform_device.h>
+
+ACPI_MODULE_NAME("bay");
+MODULE_AUTHOR("Kristen Carlson Accardi");
+MODULE_DESCRIPTION("ACPI Removable Drive Bay Driver");
+MODULE_LICENSE("GPL");
+#define ACPI_BAY_CLASS "bay"
+#define ACPI_BAY_COMPONENT 0x10000000
+#define _COMPONENT ACPI_BAY_COMPONENT
+#define bay_dprintk(h,s) {\
+ char prefix[80] = {'\0'};\
+ struct acpi_buffer buffer = {sizeof(prefix), prefix};\
+ acpi_get_name(h, ACPI_FULL_PATHNAME, &buffer);\
+ printk(KERN_DEBUG PREFIX "%s: %s\n", prefix, s); }
+static void bay_notify(acpi_handle handle, u32 event, void *data);
+
+struct bay {
+ acpi_handle handle;
+ char *name;
+ struct list_head list;
+ struct platform_device *pdev;
+};
+
+static LIST_HEAD(drive_bays);
+
+
+/*****************************************************************************
+ * Drive Bay functions *
+ *****************************************************************************/
+/**
+ * is_ejectable - see if a device is ejectable
+ * @handle: acpi handle of the device
+ *
+ * If an acpi object has a _EJ0 method, then it is ejectable
+ */
+static int is_ejectable(acpi_handle handle)
+{
+ acpi_status status;
+ acpi_handle tmp;
+
+ status = acpi_get_handle(handle, "_EJ0", &tmp);
+ if (ACPI_FAILURE(status))
+ return 0;
+ return 1;
+}
+
+/**
+ * bay_present - see if the bay device is present
+ * @bay: the drive bay
+ *
+ * execute the _STA method.
+ */
+static int bay_present(struct bay *bay)
+{
+ unsigned long sta;
+ acpi_status status;
+
+ if (bay) {
+ status = acpi_evaluate_integer(bay->handle, "_STA", NULL, &sta);
+ if (ACPI_SUCCESS(status) && sta)
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * eject_device - respond to an eject request
+ * @handle - the device to eject
+ *
+ * Call this devices _EJ0 method.
+ */
+static void eject_device(acpi_handle handle)
+{
+ struct acpi_object_list arg_list;
+ union acpi_object arg;
+
+ bay_dprintk(handle, "Ejecting device");
+
+ arg_list.count = 1;
+ arg_list.pointer = &arg;
+ arg.type = ACPI_TYPE_INTEGER;
+ arg.integer.value = 1;
+
+ if (ACPI_FAILURE(acpi_evaluate_object(handle, "_EJ0",
+ &arg_list, NULL)))
+ pr_debug("Failed to evaluate _EJ0!\n");
+}
+
+/*
+ * show_present - read method for "present" file in sysfs
+ */
+static ssize_t show_present(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct bay *bay = dev_get_drvdata(dev);
+ return snprintf(buf, PAGE_SIZE, "%d\n", bay_present(bay));
+
+}
+DEVICE_ATTR(present, S_IRUGO, show_present, NULL);
+
+/*
+ * write_eject - write method for "eject" file in sysfs
+ */
+static ssize_t write_eject(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct bay *bay = dev_get_drvdata(dev);
+
+ if (!count)
+ return -EINVAL;
+
+ eject_device(bay->handle);
+ return count;
+}
+DEVICE_ATTR(eject, S_IWUSR, NULL, write_eject);
+
+/**
+ * is_ata - see if a device is an ata device
+ * @handle: acpi handle of the device
+ *
+ * If an acpi object has one of 4 ATA ACPI methods defined,
+ * then it is an ATA device
+ */
+static int is_ata(acpi_handle handle)
+{
+ acpi_handle tmp;
+
+ if ((ACPI_SUCCESS(acpi_get_handle(handle, "_GTF", &tmp))) ||
+ (ACPI_SUCCESS(acpi_get_handle(handle, "_GTM", &tmp))) ||
+ (ACPI_SUCCESS(acpi_get_handle(handle, "_STM", &tmp))) ||
+ (ACPI_SUCCESS(acpi_get_handle(handle, "_SDD", &tmp))))
+ return 1;
+
+ return 0;
+}
+
+/**
+ * parent_is_ata(acpi_handle handle)
+ *
+ */
+static int parent_is_ata(acpi_handle handle)
+{
+ acpi_handle phandle;
+
+ if (acpi_get_parent(handle, &phandle))
+ return 0;
+
+ return is_ata(phandle);
+}
+
+/**
+ * is_ejectable_bay - see if a device is an ejectable drive bay
+ * @handle: acpi handle of the device
+ *
+ * If an acpi object is ejectable and has one of the ACPI ATA
+ * methods defined, then we can safely call it an ejectable
+ * drive bay
+ */
+static int is_ejectable_bay(acpi_handle handle)
+{
+ if ((is_ata(handle) || parent_is_ata(handle)) && is_ejectable(handle))
+ return 1;
+ return 0;
+}
+
+/**
+ * eject_removable_drive - try to eject this drive
+ * @dev : the device structure of the drive
+ *
+ * If a device is a removable drive that requires an _EJ0 method
+ * to be executed in order to safely remove from the system, do
+ * it. ATM - always returns success
+ */
+int eject_removable_drive(struct device *dev)
+{
+ acpi_handle handle = DEVICE_ACPI_HANDLE(dev);
+
+ if (handle) {
+ bay_dprintk(handle, "Got device handle");
+ if (is_ejectable_bay(handle))
+ eject_device(handle);
+ } else {
+ printk("No acpi handle for device\n");
+ }
+
+ /* should I return an error code? */
+ return 0;
+}
+EXPORT_SYMBOL_GPL(eject_removable_drive);
+
+static int acpi_bay_add_fs(struct bay *bay)
+{
+ int ret;
+ struct device *dev = &bay->pdev->dev;
+
+ ret = device_create_file(dev, &dev_attr_present);
+ if (ret)
+ goto add_fs_err;
+ ret = device_create_file(dev, &dev_attr_eject);
+ if (ret) {
+ device_remove_file(dev, &dev_attr_present);
+ goto add_fs_err;
+ }
+ return 0;
+
+ add_fs_err:
+ bay_dprintk(bay->handle, "Error adding sysfs files\n");
+ return ret;
+}
+
+static void acpi_bay_remove_fs(struct bay *bay)
+{
+ struct device *dev = &bay->pdev->dev;
+
+ /* cleanup sysfs */
+ device_remove_file(dev, &dev_attr_present);
+ device_remove_file(dev, &dev_attr_eject);
+}
+
+static int bay_is_dock_device(acpi_handle handle)
+{
+ acpi_handle parent;
+
+ acpi_get_parent(handle, &parent);
+
+ /* if the device or it's parent is dependent on the
+ * dock, then we are a dock device
+ */
+ return (is_dock_device(handle) || is_dock_device(parent));
+}
+
+static int bay_add(acpi_handle handle, int id)
+{
+ acpi_status status;
+ struct bay *new_bay;
+ struct platform_device *pdev;
+ struct acpi_buffer nbuffer = {ACPI_ALLOCATE_BUFFER, NULL};
+ acpi_get_name(handle, ACPI_FULL_PATHNAME, &nbuffer);
+
+ bay_dprintk(handle, "Adding notify handler");
+
+ /*
+ * Initialize bay device structure
+ */
+ new_bay = kzalloc(sizeof(*new_bay), GFP_ATOMIC);
+ INIT_LIST_HEAD(&new_bay->list);
+ new_bay->handle = handle;
+ new_bay->name = (char *)nbuffer.pointer;
+
+ /* initialize platform device stuff */
+ pdev = platform_device_register_simple(ACPI_BAY_CLASS, id, NULL, 0);
+ if (IS_ERR(pdev)) {
+ printk(KERN_ERR PREFIX "Error registering bay device\n");
+ goto bay_add_err;
+ }
+ new_bay->pdev = pdev;
+ platform_set_drvdata(pdev, new_bay);
+
+ if (acpi_bay_add_fs(new_bay)) {
+ platform_device_unregister(new_bay->pdev);
+ goto bay_add_err;
+ }
+
+ /* register for events on this device */
+ status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
+ bay_notify, new_bay);
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_ERR PREFIX "Error installing bay notify handler\n");
+ }
+
+ /* if we are on a dock station, we should register for dock
+ * notifications.
+ */
+ if (bay_is_dock_device(handle)) {
+ bay_dprintk(handle, "Is dependent on dock\n");
+ register_hotplug_dock_device(handle, bay_notify, new_bay);
+ }
+ list_add(&new_bay->list, &drive_bays);
+ printk(KERN_INFO PREFIX "Bay [%s] Added\n", new_bay->name);
+ return 0;
+
+bay_add_err:
+ kfree(new_bay->name);
+ kfree(new_bay);
+ return -ENODEV;
+}
+
+/**
+ * bay_notify - act upon an acpi bay notification
+ * @handle: the bay handle
+ * @event: the acpi event
+ * @data: our driver data struct
+ *
+ */
+static void bay_notify(acpi_handle handle, u32 event, void *data)
+{
+ struct bay *bay_dev = (struct bay *)data;
+ struct device *dev = &bay_dev->pdev->dev;
+
+ bay_dprintk(handle, "Bay event");
+
+ switch(event) {
+ case ACPI_NOTIFY_BUS_CHECK:
+ case ACPI_NOTIFY_DEVICE_CHECK:
+ case ACPI_NOTIFY_EJECT_REQUEST:
+ kobject_uevent(&dev->kobj, KOBJ_CHANGE);
+ break;
+ default:
+ printk(KERN_ERR PREFIX "Bay: unknown event %d\n", event);
+ }
+}
+
+static acpi_status
+find_bay(acpi_handle handle, u32 lvl, void *context, void **rv)
+{
+ int *count = (int *)context;
+
+ /*
+ * there could be more than one ejectable bay.
+ * so, just return AE_OK always so that every object
+ * will be checked.
+ */
+ if (is_ejectable_bay(handle)) {
+ bay_dprintk(handle, "found ejectable bay");
+ if (!bay_add(handle, *count))
+ (*count)++;
+ }
+ return AE_OK;
+}
+
+static int __init bay_init(void)
+{
+ int bays = 0;
+
+ INIT_LIST_HEAD(&drive_bays);
+
+ /* look for dockable drive bays */
+ acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+ ACPI_UINT32_MAX, find_bay, &bays, NULL);
+
+ if (!bays)
+ return -ENODEV;
+
+ return 0;
+}
+
+static void __exit bay_exit(void)
+{
+ struct bay *bay, *tmp;
+
+ list_for_each_entry_safe(bay, tmp, &drive_bays, list) {
+ if (is_dock_device(bay->handle))
+ unregister_hotplug_dock_device(bay->handle);
+ acpi_bay_remove_fs(bay);
+ acpi_remove_notify_handler(bay->handle, ACPI_SYSTEM_NOTIFY,
+ bay_notify);
+ platform_device_unregister(bay->pdev);
+ kfree(bay->name);
+ kfree(bay);
+ }
+}
+
+postcore_initcall(bay_init);
+module_exit(bay_exit);
+
diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c
index f9c972b26f4..f289fd41e77 100644
--- a/drivers/acpi/blacklist.c
+++ b/drivers/acpi/blacklist.c
@@ -44,7 +44,7 @@ struct acpi_blacklist_item {
char oem_id[7];
char oem_table_id[9];
u32 oem_revision;
- acpi_table_type table;
+ char *table;
enum acpi_blacklist_predicates oem_revision_predicate;
char *reason;
u32 is_critical_error;
@@ -56,18 +56,18 @@ struct acpi_blacklist_item {
*/
static struct acpi_blacklist_item acpi_blacklist[] __initdata = {
/* Compaq Presario 1700 */
- {"PTLTD ", " DSDT ", 0x06040000, ACPI_DSDT, less_than_or_equal,
+ {"PTLTD ", " DSDT ", 0x06040000, ACPI_SIG_DSDT, less_than_or_equal,
"Multiple problems", 1},
/* Sony FX120, FX140, FX150? */
- {"SONY ", "U0 ", 0x20010313, ACPI_DSDT, less_than_or_equal,
+ {"SONY ", "U0 ", 0x20010313, ACPI_SIG_DSDT, less_than_or_equal,
"ACPI driver problem", 1},
/* Compaq Presario 800, Insyde BIOS */
- {"INT440", "SYSFexxx", 0x00001001, ACPI_DSDT, less_than_or_equal,
+ {"INT440", "SYSFexxx", 0x00001001, ACPI_SIG_DSDT, less_than_or_equal,
"Does not use _REG to protect EC OpRegions", 1},
/* IBM 600E - _ADR should return 7, but it returns 1 */
- {"IBM ", "TP600E ", 0x00000105, ACPI_DSDT, less_than_or_equal,
+ {"IBM ", "TP600E ", 0x00000105, ACPI_SIG_DSDT, less_than_or_equal,
"Incorrect _ADR", 1},
- {"ASUS\0\0", "P2B-S ", 0, ACPI_DSDT, all_versions,
+ {"ASUS\0\0", "P2B-S ", 0, ACPI_SIG_DSDT, all_versions,
"Bogus PCI routing", 1},
{""}
@@ -79,7 +79,7 @@ static int __init blacklist_by_year(void)
{
int year = dmi_get_year(DMI_BIOS_DATE);
/* Doesn't exist? Likely an old system */
- if (year == -1)
+ if (year == -1)
return 1;
/* 0? Likely a buggy new BIOS */
if (year == 0)
@@ -103,22 +103,21 @@ int __init acpi_blacklisted(void)
{
int i = 0;
int blacklisted = 0;
- struct acpi_table_header *table_header;
+ struct acpi_table_header table_header;
while (acpi_blacklist[i].oem_id[0] != '\0') {
- if (acpi_get_table_header_early
- (acpi_blacklist[i].table, &table_header)) {
+ if (acpi_get_table_header(acpi_blacklist[i].table, 0, &table_header)) {
i++;
continue;
}
- if (strncmp(acpi_blacklist[i].oem_id, table_header->oem_id, 6)) {
+ if (strncmp(acpi_blacklist[i].oem_id, table_header.oem_id, 6)) {
i++;
continue;
}
if (strncmp
- (acpi_blacklist[i].oem_table_id, table_header->oem_table_id,
+ (acpi_blacklist[i].oem_table_id, table_header.oem_table_id,
8)) {
i++;
continue;
@@ -127,14 +126,14 @@ int __init acpi_blacklisted(void)
if ((acpi_blacklist[i].oem_revision_predicate == all_versions)
|| (acpi_blacklist[i].oem_revision_predicate ==
less_than_or_equal
- && table_header->oem_revision <=
+ && table_header.oem_revision <=
acpi_blacklist[i].oem_revision)
|| (acpi_blacklist[i].oem_revision_predicate ==
greater_than_or_equal
- && table_header->oem_revision >=
+ && table_header.oem_revision >=
acpi_blacklist[i].oem_revision)
|| (acpi_blacklist[i].oem_revision_predicate == equal
- && table_header->oem_revision ==
+ && table_header.oem_revision ==
acpi_blacklist[i].oem_revision)) {
printk(KERN_ERR PREFIX
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 766332e4559..dd49ea0d0ed 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -39,14 +39,11 @@
#include <acpi/acpi_drivers.h>
#define _COMPONENT ACPI_BUS_COMPONENT
-ACPI_MODULE_NAME("acpi_bus")
+ACPI_MODULE_NAME("bus");
#ifdef CONFIG_X86
extern void __init acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger);
#endif
-struct fadt_descriptor acpi_fadt;
-EXPORT_SYMBOL(acpi_fadt);
-
struct acpi_device *acpi_root;
struct proc_dir_entry *acpi_root_dir;
EXPORT_SYMBOL(acpi_root_dir);
@@ -150,7 +147,7 @@ int acpi_bus_get_power(acpi_handle handle, int *state)
*state = ACPI_STATE_D0;
} else {
/*
- * Get the device's power state either directly (via _PSC) or
+ * Get the device's power state either directly (via _PSC) or
* indirectly (via power resources).
*/
if (device->power.flags.explicit_get) {
@@ -195,22 +192,21 @@ int acpi_bus_set_power(acpi_handle handle, int state)
if (!device->flags.power_manageable) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device `[%s]' is not power manageable\n",
- device->kobj.name));
+ device->dev.kobj.name));
return -ENODEV;
}
/*
* Get device's current power state if it's unknown
* This means device power state isn't initialized or previous setting failed
*/
- if (!device->flags.force_power_state) {
- if (device->power.state == ACPI_STATE_UNKNOWN)
- acpi_bus_get_power(device->handle, &device->power.state);
- if (state == device->power.state) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n",
- state));
- return 0;
- }
+ if ((device->power.state == ACPI_STATE_UNKNOWN) || device->flags.force_power_state)
+ acpi_bus_get_power(device->handle, &device->power.state);
+ if ((state == device->power.state) && !device->flags.force_power_state) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n",
+ state));
+ return 0;
}
+
if (!device->power.states[state].flags.valid) {
printk(KERN_WARNING PREFIX "Device does not support D%d\n", state);
return -ENODEV;
@@ -465,7 +461,7 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
"Received BUS CHECK notification for device [%s]\n",
device->pnp.bus_id));
result = acpi_bus_check_scope(device);
- /*
+ /*
* TBD: We'll need to outsource certain events to non-ACPI
* drivers via the device manager (device.c).
*/
@@ -476,7 +472,7 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
"Received DEVICE CHECK notification for device [%s]\n",
device->pnp.bus_id));
result = acpi_bus_check_device(device, NULL);
- /*
+ /*
* TBD: We'll need to outsource certain events to non-ACPI
* drivers via the device manager (device.c).
*/
@@ -546,7 +542,7 @@ static int __init acpi_bus_init_irq(void)
char *message = NULL;
- /*
+ /*
* Let the system know what interrupt model we are using by
* evaluating the \_PIC object, if exists.
*/
@@ -582,11 +578,12 @@ static int __init acpi_bus_init_irq(void)
return 0;
}
+acpi_native_uint acpi_gbl_permanent_mmap;
+
+
void __init acpi_early_init(void)
{
acpi_status status = AE_OK;
- struct acpi_buffer buffer = { sizeof(acpi_fadt), &acpi_fadt };
-
if (acpi_disabled)
return;
@@ -597,6 +594,15 @@ void __init acpi_early_init(void)
if (!acpi_strict)
acpi_gbl_enable_interpreter_slack = TRUE;
+ acpi_gbl_permanent_mmap = 1;
+
+ status = acpi_reallocate_root_table();
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_ERR PREFIX
+ "Unable to reallocate ACPI tables\n");
+ goto error0;
+ }
+
status = acpi_initialize_subsystem();
if (ACPI_FAILURE(status)) {
printk(KERN_ERR PREFIX
@@ -611,32 +617,25 @@ void __init acpi_early_init(void)
goto error0;
}
- /*
- * Get a separate copy of the FADT for use by other drivers.
- */
- status = acpi_get_table(ACPI_TABLE_ID_FADT, 1, &buffer);
- if (ACPI_FAILURE(status)) {
- printk(KERN_ERR PREFIX "Unable to get the FADT\n");
- goto error0;
- }
#ifdef CONFIG_X86
if (!acpi_ioapic) {
- extern acpi_interrupt_flags acpi_sci_flags;
+ extern u8 acpi_sci_flags;
/* compatible (0) means level (3) */
- if (acpi_sci_flags.trigger == 0)
- acpi_sci_flags.trigger = 3;
-
+ if (!(acpi_sci_flags & ACPI_MADT_TRIGGER_MASK)) {
+ acpi_sci_flags &= ~ACPI_MADT_TRIGGER_MASK;
+ acpi_sci_flags |= ACPI_MADT_TRIGGER_LEVEL;
+ }
/* Set PIC-mode SCI trigger type */
- acpi_pic_sci_set_trigger(acpi_fadt.sci_int,
- acpi_sci_flags.trigger);
+ acpi_pic_sci_set_trigger(acpi_gbl_FADT.sci_interrupt,
+ (acpi_sci_flags & ACPI_MADT_TRIGGER_MASK) >> 2);
} else {
extern int acpi_sci_override_gsi;
/*
- * now that acpi_fadt is initialized,
+ * now that acpi_gbl_FADT is initialized,
* update it with result from INT_SRC_OVR parsing
*/
- acpi_fadt.sci_int = acpi_sci_override_gsi;
+ acpi_gbl_FADT.sci_interrupt = acpi_sci_override_gsi;
}
#endif
@@ -684,7 +683,7 @@ static int __init acpi_bus_init(void)
* the EC device is found in the namespace (i.e. before acpi_initialize_objects()
* is called).
*
- * This is accomplished by looking for the ECDT table, and getting
+ * This is accomplished by looking for the ECDT table, and getting
* the EC parameters out of that.
*/
status = acpi_ec_ecdt_probe();
@@ -699,6 +698,9 @@ static int __init acpi_bus_init(void)
printk(KERN_INFO PREFIX "Interpreter enabled\n");
+ /* Initialize sleep structures */
+ acpi_sleep_init();
+
/*
* Get the system interrupt model and evaluate \_PIC.
*/
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index ac860583c20..cb4110b50cd 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -34,7 +34,6 @@
#include <acpi/acpi_drivers.h>
#define ACPI_BUTTON_COMPONENT 0x00080000
-#define ACPI_BUTTON_DRIVER_NAME "ACPI Button Driver"
#define ACPI_BUTTON_CLASS "button"
#define ACPI_BUTTON_FILE_INFO "info"
#define ACPI_BUTTON_FILE_STATE "state"
@@ -61,10 +60,10 @@
#define ACPI_BUTTON_TYPE_LID 0x05
#define _COMPONENT ACPI_BUTTON_COMPONENT
-ACPI_MODULE_NAME("acpi_button")
+ACPI_MODULE_NAME("button");
MODULE_AUTHOR("Paul Diefenbaugh");
-MODULE_DESCRIPTION(ACPI_BUTTON_DRIVER_NAME);
+MODULE_DESCRIPTION("ACPI Button Driver");
MODULE_LICENSE("GPL");
static int acpi_button_add(struct acpi_device *device);
@@ -73,9 +72,9 @@ static int acpi_button_info_open_fs(struct inode *inode, struct file *file);
static int acpi_button_state_open_fs(struct inode *inode, struct file *file);
static struct acpi_driver acpi_button_driver = {
- .name = ACPI_BUTTON_DRIVER_NAME,
+ .name = "button",
.class = ACPI_BUTTON_CLASS,
- .ids = "ACPI_FPB,ACPI_FSB,PNP0C0D,PNP0C0C,PNP0C0E",
+ .ids = "button_power,button_sleep,PNP0C0D,PNP0C0C,PNP0C0E",
.ops = {
.add = acpi_button_add,
.remove = acpi_button_remove,
diff --git a/drivers/acpi/cm_sbs.c b/drivers/acpi/cm_sbs.c
index 4a9b7bf6f44..f9db4f444bd 100644
--- a/drivers/acpi/cm_sbs.c
+++ b/drivers/acpi/cm_sbs.c
@@ -31,7 +31,7 @@
#include <acpi/actypes.h>
#include <acpi/acutils.h>
-ACPI_MODULE_NAME("cm_sbs")
+ACPI_MODULE_NAME("cm_sbs");
#define ACPI_AC_CLASS "ac_adapter"
#define ACPI_BATTERY_CLASS "battery"
#define ACPI_SBS_COMPONENT 0x00080000
diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c
index 0a1863ec91f..0930d9413df 100644
--- a/drivers/acpi/container.c
+++ b/drivers/acpi/container.c
@@ -35,7 +35,6 @@
#include <acpi/acpi_drivers.h>
#include <acpi/container.h>
-#define ACPI_CONTAINER_DRIVER_NAME "ACPI container driver"
#define ACPI_CONTAINER_DEVICE_NAME "ACPI container device"
#define ACPI_CONTAINER_CLASS "container"
@@ -44,10 +43,10 @@
#define ACPI_CONTAINER_COMPONENT 0x01000000
#define _COMPONENT ACPI_CONTAINER_COMPONENT
-ACPI_MODULE_NAME("acpi_container")
+ACPI_MODULE_NAME("container");
- MODULE_AUTHOR("Anil S Keshavamurthy");
-MODULE_DESCRIPTION(ACPI_CONTAINER_DRIVER_NAME);
+MODULE_AUTHOR("Anil S Keshavamurthy");
+MODULE_DESCRIPTION("ACPI container driver");
MODULE_LICENSE("GPL");
#define ACPI_STA_PRESENT (0x00000001)
@@ -56,7 +55,7 @@ static int acpi_container_add(struct acpi_device *device);
static int acpi_container_remove(struct acpi_device *device, int type);
static struct acpi_driver acpi_container_driver = {
- .name = ACPI_CONTAINER_DRIVER_NAME,
+ .name = "container",
.class = ACPI_CONTAINER_CLASS,
.ids = "ACPI0004,PNP0A05,PNP0A06",
.ops = {
@@ -167,7 +166,7 @@ static void container_notify_cb(acpi_handle handle, u32 type, void *context)
if (ACPI_FAILURE(status) || !device) {
result = container_device_add(&device, handle);
if (!result)
- kobject_uevent(&device->kobj,
+ kobject_uevent(&device->dev.kobj,
KOBJ_ONLINE);
else
printk("Failed to add container\n");
@@ -175,13 +174,13 @@ static void container_notify_cb(acpi_handle handle, u32 type, void *context)
} else {
if (ACPI_SUCCESS(status)) {
/* device exist and this is a remove request */
- kobject_uevent(&device->kobj, KOBJ_OFFLINE);
+ kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
}
}
break;
case ACPI_NOTIFY_EJECT_REQUEST:
if (!acpi_bus_get_device(handle, &device) && device) {
- kobject_uevent(&device->kobj, KOBJ_OFFLINE);
+ kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
}
break;
default:
diff --git a/drivers/acpi/debug.c b/drivers/acpi/debug.c
index 35c6af8a83c..bf513e07b77 100644
--- a/drivers/acpi/debug.c
+++ b/drivers/acpi/debug.c
@@ -12,15 +12,12 @@
#include <acpi/acglobal.h>
#define _COMPONENT ACPI_SYSTEM_COMPONENT
-ACPI_MODULE_NAME("debug")
-#define ACPI_SYSTEM_FILE_DEBUG_LAYER "debug_layer"
-#define ACPI_SYSTEM_FILE_DEBUG_LEVEL "debug_level"
+ACPI_MODULE_NAME("debug");
+
#ifdef MODULE_PARAM_PREFIX
#undef MODULE_PARAM_PREFIX
#endif
-#define MODULE_PARAM_PREFIX
- module_param(acpi_dbg_layer, uint, 0400);
-module_param(acpi_dbg_level, uint, 0400);
+#define MODULE_PARAM_PREFIX "acpi."
struct acpi_dlayer {
const char *name;
@@ -86,6 +83,60 @@ static const struct acpi_dlevel acpi_debug_levels[] = {
ACPI_DEBUG_INIT(ACPI_LV_EVENTS),
};
+/* --------------------------------------------------------------------------
+ FS Interface (/sys)
+ -------------------------------------------------------------------------- */
+static int param_get_debug_layer(char *buffer, struct kernel_param *kp) {
+ int result = 0;
+ int i;
+
+ result = sprintf(buffer, "%-25s\tHex SET\n", "Description");
+
+ for(i = 0; i <ARRAY_SIZE(acpi_debug_layers); i++) {
+ result += sprintf(buffer+result, "%-25s\t0x%08lX [%c]\n",
+ acpi_debug_layers[i].name,
+ acpi_debug_layers[i].value,
+ (acpi_dbg_layer & acpi_debug_layers[i].value) ? '*' : ' ');
+ }
+ result += sprintf(buffer+result, "%-25s\t0x%08X [%c]\n", "ACPI_ALL_DRIVERS",
+ ACPI_ALL_DRIVERS,
+ (acpi_dbg_layer & ACPI_ALL_DRIVERS) ==
+ ACPI_ALL_DRIVERS ? '*' : (acpi_dbg_layer &
+ ACPI_ALL_DRIVERS) == 0 ? ' ' : '-');
+ result += sprintf(buffer+result, "--\ndebug_layer = 0x%08X ( * = enabled)\n", acpi_dbg_layer);
+
+ return result;
+}
+
+static int param_get_debug_level(char *buffer, struct kernel_param *kp) {
+ int result = 0;
+ int i;
+
+ result = sprintf(buffer, "%-25s\tHex SET\n", "Description");
+
+ for (i = 0; i < ARRAY_SIZE(acpi_debug_levels); i++) {
+ result += sprintf(buffer+result, "%-25s\t0x%08lX [%c]\n",
+ acpi_debug_levels[i].name,
+ acpi_debug_levels[i].value,
+ (acpi_dbg_level & acpi_debug_levels[i].
+ value) ? '*' : ' ');
+ }
+ result += sprintf(buffer+result, "--\ndebug_level = 0x%08X (* = enabled)\n",
+ acpi_dbg_level);
+
+ return result;
+}
+
+module_param_call(debug_layer, param_set_uint, param_get_debug_layer, &acpi_dbg_layer, 0644);
+module_param_call(debug_level, param_set_uint, param_get_debug_level, &acpi_dbg_level, 0644);
+
+/* --------------------------------------------------------------------------
+ FS Interface (/proc)
+ -------------------------------------------------------------------------- */
+#ifdef CONFIG_ACPI_PROCFS
+#define ACPI_SYSTEM_FILE_DEBUG_LAYER "debug_layer"
+#define ACPI_SYSTEM_FILE_DEBUG_LEVEL "debug_level"
+
static int
acpi_system_read_debug(char *page,
char **start, off_t off, int count, int *eof, void *data)
@@ -221,3 +272,4 @@ static int __init acpi_debug_init(void)
}
subsys_initcall(acpi_debug_init);
+#endif
diff --git a/drivers/acpi/dispatcher/dsfield.c b/drivers/acpi/dispatcher/dsfield.c
index a6d77efb41a..f049639bac3 100644
--- a/drivers/acpi/dispatcher/dsfield.c
+++ b/drivers/acpi/dispatcher/dsfield.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -133,7 +133,8 @@ acpi_ds_create_buffer_field(union acpi_parse_object *op,
}
}
- /* We could put the returned object (Node) on the object stack for later,
+ /*
+ * We could put the returned object (Node) on the object stack for later,
* but for now, we will put it in the "op" object that the parser uses,
* so we can get it again at the end of this scope
*/
@@ -514,8 +515,33 @@ acpi_ds_create_bank_field(union acpi_parse_object *op,
/* Third arg is the bank_value */
+ /* TBD: This arg is a term_arg, not a constant, and must be evaluated */
+
arg = arg->common.next;
- info.bank_value = (u32) arg->common.value.integer;
+
+ /* Currently, only the following constants are supported */
+
+ switch (arg->common.aml_opcode) {
+ case AML_ZERO_OP:
+ info.bank_value = 0;
+ break;
+
+ case AML_ONE_OP:
+ info.bank_value = 1;
+ break;
+
+ case AML_BYTE_OP:
+ case AML_WORD_OP:
+ case AML_DWORD_OP:
+ case AML_QWORD_OP:
+ info.bank_value = (u32) arg->common.value.integer;
+ break;
+
+ default:
+ info.bank_value = 0;
+ ACPI_ERROR((AE_INFO,
+ "Non-constant BankValue for BankField is not implemented"));
+ }
/* Fourth arg is the field flags */
diff --git a/drivers/acpi/dispatcher/dsinit.c b/drivers/acpi/dispatcher/dsinit.c
index 1888c055d10..af923c38852 100644
--- a/drivers/acpi/dispatcher/dsinit.c
+++ b/drivers/acpi/dispatcher/dsinit.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -44,6 +44,7 @@
#include <acpi/acpi.h>
#include <acpi/acdispat.h>
#include <acpi/acnamesp.h>
+#include <acpi/actables.h>
#define _COMPONENT ACPI_DISPATCHER
ACPI_MODULE_NAME("dsinit")
@@ -90,7 +91,7 @@ acpi_ds_init_one_object(acpi_handle obj_handle,
* We are only interested in NS nodes owned by the table that
* was just loaded
*/
- if (node->owner_id != info->table_desc->owner_id) {
+ if (node->owner_id != info->owner_id) {
return (AE_OK);
}
@@ -150,14 +151,21 @@ acpi_ds_init_one_object(acpi_handle obj_handle,
******************************************************************************/
acpi_status
-acpi_ds_initialize_objects(struct acpi_table_desc * table_desc,
+acpi_ds_initialize_objects(acpi_native_uint table_index,
struct acpi_namespace_node * start_node)
{
acpi_status status;
struct acpi_init_walk_info info;
+ struct acpi_table_header *table;
+ acpi_owner_id owner_id;
ACPI_FUNCTION_TRACE(ds_initialize_objects);
+ status = acpi_tb_get_owner_id(table_index, &owner_id);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
"**** Starting initialization of namespace objects ****\n"));
ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, "Parsing all Control Methods:"));
@@ -166,7 +174,8 @@ acpi_ds_initialize_objects(struct acpi_table_desc * table_desc,
info.op_region_count = 0;
info.object_count = 0;
info.device_count = 0;
- info.table_desc = table_desc;
+ info.table_index = table_index;
+ info.owner_id = owner_id;
/* Walk entire namespace from the supplied root */
@@ -176,10 +185,14 @@ acpi_ds_initialize_objects(struct acpi_table_desc * table_desc,
ACPI_EXCEPTION((AE_INFO, status, "During WalkNamespace"));
}
+ status = acpi_get_table_by_index(table_index, &table);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
"\nTable [%4.4s](id %4.4X) - %hd Objects with %hd Devices %hd Methods %hd Regions\n",
- table_desc->pointer->signature,
- table_desc->owner_id, info.object_count,
+ table->signature, owner_id, info.object_count,
info.device_count, info.method_count,
info.op_region_count));
diff --git a/drivers/acpi/dispatcher/dsmethod.c b/drivers/acpi/dispatcher/dsmethod.c
index cf888add319..1683e5c5b94 100644
--- a/drivers/acpi/dispatcher/dsmethod.c
+++ b/drivers/acpi/dispatcher/dsmethod.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -231,10 +231,8 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node,
* Obtain the method mutex if necessary. Do not acquire mutex for a
* recursive call.
*/
- if (!walk_state ||
- !obj_desc->method.mutex->mutex.owner_thread ||
- (walk_state->thread !=
- obj_desc->method.mutex->mutex.owner_thread)) {
+ if (acpi_os_get_thread_id() !=
+ obj_desc->method.mutex->mutex.owner_thread_id) {
/*
* Acquire the method mutex. This releases the interpreter if we
* block (and reacquires it before it returns)
@@ -248,14 +246,14 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node,
}
/* Update the mutex and walk info and save the original sync_level */
+ obj_desc->method.mutex->mutex.owner_thread_id =
+ acpi_os_get_thread_id();
if (walk_state) {
obj_desc->method.mutex->mutex.
original_sync_level =
walk_state->thread->current_sync_level;
- obj_desc->method.mutex->mutex.owner_thread =
- walk_state->thread;
walk_state->thread->current_sync_level =
obj_desc->method.sync_level;
} else {
@@ -327,7 +325,7 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread,
ACPI_FUNCTION_TRACE_PTR(ds_call_control_method, this_walk_state);
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
- "Execute method %p, currentstate=%p\n",
+ "Calling method %p, currentstate=%p\n",
this_walk_state->prev_op, this_walk_state));
/*
@@ -351,49 +349,7 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread,
return_ACPI_STATUS(status);
}
- /*
- * 1) Parse the method. All "normal" methods are parsed for each execution.
- * Internal methods (_OSI, etc.) do not require parsing.
- */
- if (!(obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY)) {
-
- /* Create a new walk state for the parse */
-
- next_walk_state =
- acpi_ds_create_walk_state(obj_desc->method.owner_id, op,
- obj_desc, NULL);
- if (!next_walk_state) {
- status = AE_NO_MEMORY;
- goto cleanup;
- }
-
- /* Create and init a parse tree root */
-
- op = acpi_ps_create_scope_op();
- if (!op) {
- status = AE_NO_MEMORY;
- goto cleanup;
- }
-
- status = acpi_ds_init_aml_walk(next_walk_state, op, method_node,
- obj_desc->method.aml_start,
- obj_desc->method.aml_length,
- NULL, 1);
- if (ACPI_FAILURE(status)) {
- acpi_ps_delete_parse_tree(op);
- goto cleanup;
- }
-
- /* Begin AML parse (deletes next_walk_state) */
-
- status = acpi_ps_parse_aml(next_walk_state);
- acpi_ps_delete_parse_tree(op);
- if (ACPI_FAILURE(status)) {
- goto cleanup;
- }
- }
-
- /* 2) Begin method execution. Create a new walk state */
+ /* Begin method parse/execution. Create a new walk state */
next_walk_state = acpi_ds_create_walk_state(obj_desc->method.owner_id,
NULL, obj_desc, thread);
@@ -424,7 +380,8 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread,
status = acpi_ds_init_aml_walk(next_walk_state, NULL, method_node,
obj_desc->method.aml_start,
- obj_desc->method.aml_length, info, 3);
+ obj_desc->method.aml_length, info,
+ ACPI_IMODE_EXECUTE);
ACPI_FREE(info);
if (ACPI_FAILURE(status)) {
@@ -445,8 +402,8 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread,
this_walk_state->num_operands = 0;
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
- "Starting nested execution, newstate=%p\n",
- next_walk_state));
+ "**** Begin nested execution of [%4.4s] **** WalkState=%p\n",
+ method_node->name.ascii, next_walk_state));
/* Invoke an internal method if necessary */
@@ -610,7 +567,7 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc,
acpi_os_release_mutex(method_desc->method.mutex->mutex.
os_mutex);
- method_desc->method.mutex->mutex.owner_thread = NULL;
+ method_desc->method.mutex->mutex.owner_thread_id = ACPI_MUTEX_NOT_ACQUIRED;
}
}
diff --git a/drivers/acpi/dispatcher/dsmthdat.c b/drivers/acpi/dispatcher/dsmthdat.c
index 459160ff905..ba4626e06a5 100644
--- a/drivers/acpi/dispatcher/dsmthdat.c
+++ b/drivers/acpi/dispatcher/dsmthdat.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/dispatcher/dsobject.c b/drivers/acpi/dispatcher/dsobject.c
index 72190abb1d5..a474ca2334d 100644
--- a/drivers/acpi/dispatcher/dsobject.c
+++ b/drivers/acpi/dispatcher/dsobject.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -260,7 +260,7 @@ acpi_ds_build_internal_buffer_obj(struct acpi_walk_state *walk_state,
}
obj_desc->buffer.flags |= AOPOBJ_DATA_VALID;
- op->common.node = (struct acpi_namespace_node *)obj_desc;
+ op->common.node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_desc);
return_ACPI_STATUS(AE_OK);
}
@@ -270,7 +270,8 @@ acpi_ds_build_internal_buffer_obj(struct acpi_walk_state *walk_state,
*
* PARAMETERS: walk_state - Current walk state
* Op - Parser object to be translated
- * package_length - Number of elements in the package
+ * element_count - Number of elements in the package - this is
+ * the num_elements argument to Package()
* obj_desc_ptr - Where the ACPI internal object is returned
*
* RETURN: Status
@@ -278,18 +279,29 @@ acpi_ds_build_internal_buffer_obj(struct acpi_walk_state *walk_state,
* DESCRIPTION: Translate a parser Op package object to the equivalent
* namespace object
*
+ * NOTE: The number of elements in the package will be always be the num_elements
+ * count, regardless of the number of elements in the package list. If
+ * num_elements is smaller, only that many package list elements are used.
+ * if num_elements is larger, the Package object is padded out with
+ * objects of type Uninitialized (as per ACPI spec.)
+ *
+ * Even though the ASL compilers do not allow num_elements to be smaller
+ * than the Package list length (for the fixed length package opcode), some
+ * BIOS code modifies the AML on the fly to adjust the num_elements, and
+ * this code compensates for that. This also provides compatibility with
+ * other AML interpreters.
+ *
******************************************************************************/
acpi_status
acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state,
union acpi_parse_object *op,
- u32 package_length,
+ u32 element_count,
union acpi_operand_object **obj_desc_ptr)
{
union acpi_parse_object *arg;
union acpi_parse_object *parent;
union acpi_operand_object *obj_desc = NULL;
- u32 package_list_length;
acpi_status status = AE_OK;
acpi_native_uint i;
@@ -318,32 +330,13 @@ acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state,
obj_desc->package.node = parent->common.node;
}
- obj_desc->package.count = package_length;
-
- /* Count the number of items in the package list */
-
- arg = op->common.value.arg;
- arg = arg->common.next;
- for (package_list_length = 0; arg; package_list_length++) {
- arg = arg->common.next;
- }
-
- /*
- * The package length (number of elements) will be the greater
- * of the specified length and the length of the initializer list
- */
- if (package_list_length > package_length) {
- obj_desc->package.count = package_list_length;
- }
-
/*
- * Allocate the pointer array (array of pointers to the
- * individual objects). Add an extra pointer slot so
- * that the list is always null terminated.
+ * Allocate the element array (array of pointers to the individual
+ * objects) based on the num_elements parameter. Add an extra pointer slot
+ * so that the list is always null terminated.
*/
obj_desc->package.elements = ACPI_ALLOCATE_ZEROED(((acpi_size)
- obj_desc->package.
- count +
+ element_count +
1) * sizeof(void *));
if (!obj_desc->package.elements) {
@@ -351,15 +344,20 @@ acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state,
return_ACPI_STATUS(AE_NO_MEMORY);
}
+ obj_desc->package.count = element_count;
+
/*
- * Initialize all elements of the package
+ * Initialize the elements of the package, up to the num_elements count.
+ * Package is automatically padded with uninitialized (NULL) elements
+ * if num_elements is greater than the package list length. Likewise,
+ * Package is truncated if num_elements is less than the list length.
*/
arg = op->common.value.arg;
arg = arg->common.next;
- for (i = 0; arg; i++) {
+ for (i = 0; arg && (i < element_count); i++) {
if (arg->common.aml_opcode == AML_INT_RETURN_VALUE_OP) {
- /* Object (package or buffer) is already built */
+ /* This package element is already built, just get it */
obj_desc->package.elements[i] =
ACPI_CAST_PTR(union acpi_operand_object,
@@ -373,8 +371,14 @@ acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state,
arg = arg->common.next;
}
+ if (!arg) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Package List length larger than NumElements count (%X), truncated\n",
+ element_count));
+ }
+
obj_desc->package.flags |= AOPOBJ_DATA_VALID;
- op->common.node = (struct acpi_namespace_node *)obj_desc;
+ op->common.node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_desc);
return_ACPI_STATUS(status);
}
@@ -488,8 +492,9 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state,
/*
* Defer evaluation of Buffer term_arg operand
*/
- obj_desc->buffer.node = (struct acpi_namespace_node *)
- walk_state->operands[0];
+ obj_desc->buffer.node =
+ ACPI_CAST_PTR(struct acpi_namespace_node,
+ walk_state->operands[0]);
obj_desc->buffer.aml_start = op->named.data;
obj_desc->buffer.aml_length = op->named.length;
break;
@@ -499,8 +504,9 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state,
/*
* Defer evaluation of Package term_arg operand
*/
- obj_desc->package.node = (struct acpi_namespace_node *)
- walk_state->operands[0];
+ obj_desc->package.node =
+ ACPI_CAST_PTR(struct acpi_namespace_node,
+ walk_state->operands[0]);
obj_desc->package.aml_start = op->named.data;
obj_desc->package.aml_length = op->named.length;
break;
diff --git a/drivers/acpi/dispatcher/dsopcode.c b/drivers/acpi/dispatcher/dsopcode.c
index 5b974a8fe61..6c6104a7a24 100644
--- a/drivers/acpi/dispatcher/dsopcode.c
+++ b/drivers/acpi/dispatcher/dsopcode.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -114,7 +114,7 @@ acpi_ds_execute_arguments(struct acpi_namespace_node *node,
}
status = acpi_ds_init_aml_walk(walk_state, op, NULL, aml_start,
- aml_length, NULL, 1);
+ aml_length, NULL, ACPI_IMODE_LOAD_PASS1);
if (ACPI_FAILURE(status)) {
acpi_ds_delete_walk_state(walk_state);
goto cleanup;
@@ -157,7 +157,7 @@ acpi_ds_execute_arguments(struct acpi_namespace_node *node,
/* Execute the opcode and arguments */
status = acpi_ds_init_aml_walk(walk_state, op, NULL, aml_start,
- aml_length, NULL, 3);
+ aml_length, NULL, ACPI_IMODE_EXECUTE);
if (ACPI_FAILURE(status)) {
acpi_ds_delete_walk_state(walk_state);
goto cleanup;
diff --git a/drivers/acpi/dispatcher/dsutils.c b/drivers/acpi/dispatcher/dsutils.c
index 05230baf5de..e4073e05a75 100644
--- a/drivers/acpi/dispatcher/dsutils.c
+++ b/drivers/acpi/dispatcher/dsutils.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/dispatcher/dswexec.c b/drivers/acpi/dispatcher/dswexec.c
index d7a616c3104..69693fa0722 100644
--- a/drivers/acpi/dispatcher/dswexec.c
+++ b/drivers/acpi/dispatcher/dswexec.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -219,7 +219,7 @@ acpi_ds_exec_begin_op(struct acpi_walk_state *walk_state,
if (!op) {
status = acpi_ds_load2_begin_op(walk_state, out_op);
if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ goto error_exit;
}
op = *out_op;
@@ -238,7 +238,7 @@ acpi_ds_exec_begin_op(struct acpi_walk_state *walk_state,
status = acpi_ds_scope_stack_pop(walk_state);
if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ goto error_exit;
}
}
}
@@ -287,7 +287,7 @@ acpi_ds_exec_begin_op(struct acpi_walk_state *walk_state,
status = acpi_ds_result_stack_push(walk_state);
if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ goto error_exit;
}
status = acpi_ds_exec_begin_control_op(walk_state, op);
@@ -328,6 +328,10 @@ acpi_ds_exec_begin_op(struct acpi_walk_state *walk_state,
/* Nothing to do here during method execution */
return_ACPI_STATUS(status);
+
+ error_exit:
+ status = acpi_ds_method_error(status, walk_state);
+ return_ACPI_STATUS(status);
}
/*****************************************************************************
diff --git a/drivers/acpi/dispatcher/dswload.c b/drivers/acpi/dispatcher/dswload.c
index e3ca7f6539c..8ab9d1b29a4 100644
--- a/drivers/acpi/dispatcher/dswload.c
+++ b/drivers/acpi/dispatcher/dswload.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -196,6 +196,7 @@ acpi_ds_load1_begin_op(struct acpi_walk_state * walk_state,
* one of the opcodes that actually opens a scope
*/
switch (node->type) {
+ case ACPI_TYPE_ANY:
case ACPI_TYPE_LOCAL_SCOPE: /* Scope */
case ACPI_TYPE_DEVICE:
case ACPI_TYPE_POWER:
@@ -546,6 +547,7 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state,
acpi_status status;
acpi_object_type object_type;
char *buffer_ptr;
+ u32 flags;
ACPI_FUNCTION_TRACE(ds_load2_begin_op);
@@ -669,6 +671,7 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state,
* one of the opcodes that actually opens a scope
*/
switch (node->type) {
+ case ACPI_TYPE_ANY:
case ACPI_TYPE_LOCAL_SCOPE: /* Scope */
case ACPI_TYPE_DEVICE:
case ACPI_TYPE_POWER:
@@ -750,12 +753,20 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state,
break;
}
- /* Add new entry into namespace */
+ flags = ACPI_NS_NO_UPSEARCH;
+ if (walk_state->pass_number == ACPI_IMODE_EXECUTE) {
+
+ /* Execution mode, node cannot already exist, node is temporary */
+
+ flags |= (ACPI_NS_ERROR_IF_FOUND | ACPI_NS_TEMPORARY);
+ }
+
+ /* Add new entry or lookup existing entry */
status =
acpi_ns_lookup(walk_state->scope_info, buffer_ptr,
- object_type, ACPI_IMODE_LOAD_PASS2,
- ACPI_NS_NO_UPSEARCH, walk_state, &(node));
+ object_type, ACPI_IMODE_LOAD_PASS2, flags,
+ walk_state, &node);
break;
}
diff --git a/drivers/acpi/dispatcher/dswscope.c b/drivers/acpi/dispatcher/dswscope.c
index c9228972f5f..3927c495e4b 100644
--- a/drivers/acpi/dispatcher/dswscope.c
+++ b/drivers/acpi/dispatcher/dswscope.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/dispatcher/dswstate.c b/drivers/acpi/dispatcher/dswstate.c
index 7817e552267..16c8e38b51e 100644
--- a/drivers/acpi/dispatcher/dswstate.c
+++ b/drivers/acpi/dispatcher/dswstate.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c
index 90990a4b652..54a697f9aa1 100644
--- a/drivers/acpi/dock.c
+++ b/drivers/acpi/dock.c
@@ -32,11 +32,11 @@
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
-#define ACPI_DOCK_DRIVER_NAME "ACPI Dock Station Driver"
+#define ACPI_DOCK_DRIVER_DESCRIPTION "ACPI Dock Station Driver"
-ACPI_MODULE_NAME("dock")
+ACPI_MODULE_NAME("dock");
MODULE_AUTHOR("Kristen Carlson Accardi");
-MODULE_DESCRIPTION(ACPI_DOCK_DRIVER_NAME);
+MODULE_DESCRIPTION(ACPI_DOCK_DRIVER_DESCRIPTION);
MODULE_LICENSE("GPL");
static struct atomic_notifier_head dock_notifier_list;
@@ -615,20 +615,28 @@ static acpi_status
find_dock_devices(acpi_handle handle, u32 lvl, void *context, void **rv)
{
acpi_status status;
- acpi_handle tmp;
+ acpi_handle tmp, parent;
struct dock_station *ds = context;
struct dock_dependent_device *dd;
status = acpi_bus_get_ejd(handle, &tmp);
- if (ACPI_FAILURE(status))
- return AE_OK;
+ if (ACPI_FAILURE(status)) {
+ /* try the parent device as well */
+ status = acpi_get_parent(handle, &parent);
+ if (ACPI_FAILURE(status))
+ goto fdd_out;
+ /* see if parent is dependent on dock */
+ status = acpi_bus_get_ejd(parent, &tmp);
+ if (ACPI_FAILURE(status))
+ goto fdd_out;
+ }
if (tmp == ds->handle) {
dd = alloc_dock_dependent_device(handle);
if (dd)
add_dock_dependent_device(ds, dd);
}
-
+fdd_out:
return AE_OK;
}
@@ -733,7 +741,7 @@ static int dock_add(acpi_handle handle)
goto dock_add_err;
}
- printk(KERN_INFO PREFIX "%s \n", ACPI_DOCK_DRIVER_NAME);
+ printk(KERN_INFO PREFIX "%s \n", ACPI_DOCK_DRIVER_DESCRIPTION);
return 0;
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index cbdf031f3c0..ab688837379 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -38,11 +38,10 @@
#include <acpi/actypes.h>
#define _COMPONENT ACPI_EC_COMPONENT
-ACPI_MODULE_NAME("acpi_ec")
+ACPI_MODULE_NAME("ec");
#define ACPI_EC_COMPONENT 0x00100000
#define ACPI_EC_CLASS "embedded_controller"
#define ACPI_EC_HID "PNP0C09"
-#define ACPI_EC_DRIVER_NAME "ACPI Embedded Controller Driver"
#define ACPI_EC_DEVICE_NAME "Embedded Controller"
#define ACPI_EC_FILE_INFO "info"
#undef PREFIX
@@ -80,7 +79,7 @@ static int acpi_ec_stop(struct acpi_device *device, int type);
static int acpi_ec_add(struct acpi_device *device);
static struct acpi_driver acpi_ec_driver = {
- .name = ACPI_EC_DRIVER_NAME,
+ .name = "ec",
.class = ACPI_EC_CLASS,
.ids = ACPI_EC_HID,
.ops = {
@@ -280,8 +279,10 @@ static int acpi_ec_transaction(struct acpi_ec *ec, u8 command,
mutex_lock(&ec->lock);
if (ec->global_lock) {
status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
- if (ACPI_FAILURE(status))
+ if (ACPI_FAILURE(status)) {
+ mutex_unlock(&ec->lock);
return -ENODEV;
+ }
}
/* Make sure GPE is enabled before doing transaction */
@@ -872,9 +873,8 @@ static int __init acpi_ec_get_real_ecdt(void)
acpi_status status;
struct acpi_table_ecdt *ecdt_ptr;
- status = acpi_get_firmware_table("ECDT", 1, ACPI_LOGICAL_ADDRESSING,
- (struct acpi_table_header **)
- &ecdt_ptr);
+ status = acpi_get_table(ACPI_SIG_ECDT, 1,
+ (struct acpi_table_header **)&ecdt_ptr);
if (ACPI_FAILURE(status))
return -ENODEV;
@@ -891,14 +891,14 @@ static int __init acpi_ec_get_real_ecdt(void)
if (acpi_ec_mode == EC_INTR) {
init_waitqueue_head(&ec_ecdt->wait);
}
- ec_ecdt->command_addr = ecdt_ptr->ec_control.address;
- ec_ecdt->data_addr = ecdt_ptr->ec_data.address;
- ec_ecdt->gpe = ecdt_ptr->gpe_bit;
+ ec_ecdt->command_addr = ecdt_ptr->control.address;
+ ec_ecdt->data_addr = ecdt_ptr->data.address;
+ ec_ecdt->gpe = ecdt_ptr->gpe;
/* use the GL just to be safe */
ec_ecdt->global_lock = TRUE;
ec_ecdt->uid = ecdt_ptr->uid;
- status = acpi_get_handle(NULL, ecdt_ptr->ec_id, &ec_ecdt->handle);
+ status = acpi_get_handle(NULL, ecdt_ptr->id, &ec_ecdt->handle);
if (ACPI_FAILURE(status)) {
goto error;
}
diff --git a/drivers/acpi/event.c b/drivers/acpi/event.c
index 959a893c8d1..3b23562e6f9 100644
--- a/drivers/acpi/event.c
+++ b/drivers/acpi/event.c
@@ -13,7 +13,7 @@
#include <acpi/acpi_drivers.h>
#define _COMPONENT ACPI_SYSTEM_COMPONENT
-ACPI_MODULE_NAME("event")
+ACPI_MODULE_NAME("event");
/* Global vars for handling event proc entry */
static DEFINE_SPINLOCK(acpi_system_event_lock);
diff --git a/drivers/acpi/events/evevent.c b/drivers/acpi/events/evevent.c
index 919037d6acf..a1f87b5def2 100644
--- a/drivers/acpi/events/evevent.c
+++ b/drivers/acpi/events/evevent.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -70,13 +70,6 @@ acpi_status acpi_ev_initialize_events(void)
ACPI_FUNCTION_TRACE(ev_initialize_events);
- /* Make sure we have ACPI tables */
-
- if (!acpi_gbl_DSDT) {
- ACPI_WARNING((AE_INFO, "No ACPI tables present!"));
- return_ACPI_STATUS(AE_NO_ACPI_TABLES);
- }
-
/*
* Initialize the Fixed and General Purpose Events. This is done prior to
* enabling SCIs to prevent interrupts from occurring before the handlers are
@@ -211,8 +204,7 @@ static acpi_status acpi_ev_fixed_event_initialize(void)
if (acpi_gbl_fixed_event_info[i].enable_register_id != 0xFF) {
status =
acpi_set_register(acpi_gbl_fixed_event_info[i].
- enable_register_id, 0,
- ACPI_MTX_LOCK);
+ enable_register_id, 0);
if (ACPI_FAILURE(status)) {
return (status);
}
@@ -298,7 +290,7 @@ static u32 acpi_ev_fixed_event_dispatch(u32 event)
/* Clear the status bit */
(void)acpi_set_register(acpi_gbl_fixed_event_info[event].
- status_register_id, 1, ACPI_MTX_DO_NOT_LOCK);
+ status_register_id, 1);
/*
* Make sure we've got a handler. If not, report an error.
@@ -306,8 +298,7 @@ static u32 acpi_ev_fixed_event_dispatch(u32 event)
*/
if (NULL == acpi_gbl_fixed_event_handlers[event].handler) {
(void)acpi_set_register(acpi_gbl_fixed_event_info[event].
- enable_register_id, 0,
- ACPI_MTX_DO_NOT_LOCK);
+ enable_register_id, 0);
ACPI_ERROR((AE_INFO,
"No installed handler for fixed event [%08X]",
diff --git a/drivers/acpi/events/evgpe.c b/drivers/acpi/events/evgpe.c
index c76c0583ca6..635ba449ebc 100644
--- a/drivers/acpi/events/evgpe.c
+++ b/drivers/acpi/events/evgpe.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -121,7 +121,9 @@ acpi_ev_update_gpe_enable_masks(struct acpi_gpe_event_info *gpe_event_info,
if (!gpe_register_info) {
return_ACPI_STATUS(AE_NOT_EXIST);
}
- register_bit = gpe_event_info->register_bit;
+ register_bit = (u8)
+ (1 <<
+ (gpe_event_info->gpe_number - gpe_register_info->base_gpe_number));
/* 1) Disable case. Simply clear all enable bits */
@@ -458,8 +460,7 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list)
/* Examine one GPE bit */
- if (enabled_status_byte &
- acpi_gbl_decode_to8bit[j]) {
+ if (enabled_status_byte & (1 << j)) {
/*
* Found an active GPE. Dispatch the event to a handler
* or method.
@@ -570,7 +571,7 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status,
- "While evaluating GPE method [%4.4s]",
+ "while evaluating GPE method [%4.4s]",
acpi_ut_get_node_name
(local_gpe_event_info.dispatch.
method_node)));
@@ -618,6 +619,8 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
ACPI_FUNCTION_TRACE(ev_gpe_dispatch);
+ acpi_gpe_count++;
+
/*
* If edge-triggered, clear the GPE status bit now. Note that
* level-triggered events are cleared after the GPE is serviced.
@@ -633,20 +636,12 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
}
}
- /* Save current system state */
-
- if (acpi_gbl_system_awake_and_running) {
- ACPI_SET_BIT(gpe_event_info->flags, ACPI_GPE_SYSTEM_RUNNING);
- } else {
- ACPI_CLEAR_BIT(gpe_event_info->flags, ACPI_GPE_SYSTEM_RUNNING);
- }
-
/*
- * Dispatch the GPE to either an installed handler, or the control
- * method associated with this GPE (_Lxx or _Exx).
- * If a handler exists, we invoke it and do not attempt to run the method.
- * If there is neither a handler nor a method, we disable the level to
- * prevent further events from coming in here.
+ * Dispatch the GPE to either an installed handler, or the control method
+ * associated with this GPE (_Lxx or _Exx). If a handler exists, we invoke
+ * it and do not attempt to run the method. If there is neither a handler
+ * nor a method, we disable this GPE to prevent further such pointless
+ * events from firing.
*/
switch (gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) {
case ACPI_GPE_DISPATCH_HANDLER:
@@ -677,8 +672,8 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
case ACPI_GPE_DISPATCH_METHOD:
/*
- * Disable GPE, so it doesn't keep firing before the method has a
- * chance to run.
+ * Disable the GPE, so it doesn't keep firing before the method has a
+ * chance to run (it runs asynchronously with interrupts enabled).
*/
status = acpi_ev_disable_gpe(gpe_event_info);
if (ACPI_FAILURE(status)) {
@@ -711,7 +706,7 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
gpe_number));
/*
- * Disable the GPE. The GPE will remain disabled until the ACPI
+ * Disable the GPE. The GPE will remain disabled until the ACPI
* Core Subsystem is restarted, or a handler is installed.
*/
status = acpi_ev_disable_gpe(gpe_event_info);
@@ -726,50 +721,3 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
return_UINT32(ACPI_INTERRUPT_HANDLED);
}
-
-#ifdef ACPI_GPE_NOTIFY_CHECK
-/*******************************************************************************
- * TBD: NOT USED, PROTOTYPE ONLY AND WILL PROBABLY BE REMOVED
- *
- * FUNCTION: acpi_ev_check_for_wake_only_gpe
- *
- * PARAMETERS: gpe_event_info - info for this GPE
- *
- * RETURN: Status
- *
- * DESCRIPTION: Determine if a a GPE is "wake-only".
- *
- * Called from Notify() code in interpreter when a "DeviceWake"
- * Notify comes in.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_ev_check_for_wake_only_gpe(struct acpi_gpe_event_info *gpe_event_info)
-{
- acpi_status status;
-
- ACPI_FUNCTION_TRACE(ev_check_for_wake_only_gpe);
-
- if ((gpe_event_info) && /* Only >0 for _Lxx/_Exx */
- ((gpe_event_info->flags & ACPI_GPE_SYSTEM_MASK) == ACPI_GPE_SYSTEM_RUNNING)) { /* System state at GPE time */
- /* This must be a wake-only GPE, disable it */
-
- status = acpi_ev_disable_gpe(gpe_event_info);
-
- /* Set GPE to wake-only. Do not change wake disabled/enabled status */
-
- acpi_ev_set_gpe_type(gpe_event_info, ACPI_GPE_TYPE_WAKE);
-
- ACPI_INFO((AE_INFO,
- "GPE %p was updated from wake/run to wake-only",
- gpe_event_info));
-
- /* This was a wake-only GPE */
-
- return_ACPI_STATUS(AE_WAKE_ONLY_GPE);
- }
-
- return_ACPI_STATUS(AE_OK);
-}
-#endif
diff --git a/drivers/acpi/events/evgpeblk.c b/drivers/acpi/events/evgpeblk.c
index 95ddeb48bc0..ad5bc76edf4 100644
--- a/drivers/acpi/events/evgpeblk.c
+++ b/drivers/acpi/events/evgpeblk.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -529,7 +529,7 @@ static struct acpi_gpe_xrupt_info *acpi_ev_get_gpe_xrupt_block(u32
/* Install new interrupt handler if not SCI_INT */
- if (interrupt_number != acpi_gbl_FADT->sci_int) {
+ if (interrupt_number != acpi_gbl_FADT.sci_interrupt) {
status = acpi_os_install_interrupt_handler(interrupt_number,
acpi_ev_gpe_xrupt_handler,
gpe_xrupt);
@@ -567,7 +567,7 @@ acpi_ev_delete_gpe_xrupt(struct acpi_gpe_xrupt_info *gpe_xrupt)
/* We never want to remove the SCI interrupt handler */
- if (gpe_xrupt->interrupt_number == acpi_gbl_FADT->sci_int) {
+ if (gpe_xrupt->interrupt_number == acpi_gbl_FADT.sci_interrupt) {
gpe_xrupt->gpe_block_list_head = NULL;
return_ACPI_STATUS(AE_OK);
}
@@ -796,30 +796,31 @@ acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block)
(u8) (gpe_block->block_base_number +
(i * ACPI_GPE_REGISTER_WIDTH));
- ACPI_STORE_ADDRESS(this_register->status_address.address,
- (gpe_block->block_address.address + i));
+ this_register->status_address.address =
+ gpe_block->block_address.address + i;
- ACPI_STORE_ADDRESS(this_register->enable_address.address,
- (gpe_block->block_address.address
- + i + gpe_block->register_count));
+ this_register->enable_address.address =
+ gpe_block->block_address.address + i +
+ gpe_block->register_count;
- this_register->status_address.address_space_id =
- gpe_block->block_address.address_space_id;
- this_register->enable_address.address_space_id =
- gpe_block->block_address.address_space_id;
- this_register->status_address.register_bit_width =
+ this_register->status_address.space_id =
+ gpe_block->block_address.space_id;
+ this_register->enable_address.space_id =
+ gpe_block->block_address.space_id;
+ this_register->status_address.bit_width =
ACPI_GPE_REGISTER_WIDTH;
- this_register->enable_address.register_bit_width =
+ this_register->enable_address.bit_width =
ACPI_GPE_REGISTER_WIDTH;
- this_register->status_address.register_bit_offset =
+ this_register->status_address.bit_offset =
ACPI_GPE_REGISTER_WIDTH;
- this_register->enable_address.register_bit_offset =
+ this_register->enable_address.bit_offset =
ACPI_GPE_REGISTER_WIDTH;
/* Init the event_info for each GPE within this register */
for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) {
- this_event->register_bit = acpi_gbl_decode_to8bit[j];
+ this_event->gpe_number =
+ (u8) (this_register->base_gpe_number + j);
this_event->register_info = this_register;
this_event++;
}
@@ -1109,11 +1110,12 @@ acpi_status acpi_ev_gpe_initialize(void)
* If EITHER the register length OR the block address are zero, then that
* particular block is not supported.
*/
- if (acpi_gbl_FADT->gpe0_blk_len && acpi_gbl_FADT->xgpe0_blk.address) {
+ if (acpi_gbl_FADT.gpe0_block_length &&
+ acpi_gbl_FADT.xgpe0_block.address) {
/* GPE block 0 exists (has both length and address > 0) */
- register_count0 = (u16) (acpi_gbl_FADT->gpe0_blk_len / 2);
+ register_count0 = (u16) (acpi_gbl_FADT.gpe0_block_length / 2);
gpe_number_max =
(register_count0 * ACPI_GPE_REGISTER_WIDTH) - 1;
@@ -1121,9 +1123,9 @@ acpi_status acpi_ev_gpe_initialize(void)
/* Install GPE Block 0 */
status = acpi_ev_create_gpe_block(acpi_gbl_fadt_gpe_device,
- &acpi_gbl_FADT->xgpe0_blk,
+ &acpi_gbl_FADT.xgpe0_block,
register_count0, 0,
- acpi_gbl_FADT->sci_int,
+ acpi_gbl_FADT.sci_interrupt,
&acpi_gbl_gpe_fadt_blocks[0]);
if (ACPI_FAILURE(status)) {
@@ -1132,20 +1134,21 @@ acpi_status acpi_ev_gpe_initialize(void)
}
}
- if (acpi_gbl_FADT->gpe1_blk_len && acpi_gbl_FADT->xgpe1_blk.address) {
+ if (acpi_gbl_FADT.gpe1_block_length &&
+ acpi_gbl_FADT.xgpe1_block.address) {
/* GPE block 1 exists (has both length and address > 0) */
- register_count1 = (u16) (acpi_gbl_FADT->gpe1_blk_len / 2);
+ register_count1 = (u16) (acpi_gbl_FADT.gpe1_block_length / 2);
/* Check for GPE0/GPE1 overlap (if both banks exist) */
if ((register_count0) &&
- (gpe_number_max >= acpi_gbl_FADT->gpe1_base)) {
+ (gpe_number_max >= acpi_gbl_FADT.gpe1_base)) {
ACPI_ERROR((AE_INFO,
"GPE0 block (GPE 0 to %d) overlaps the GPE1 block (GPE %d to %d) - Ignoring GPE1",
- gpe_number_max, acpi_gbl_FADT->gpe1_base,
- acpi_gbl_FADT->gpe1_base +
+ gpe_number_max, acpi_gbl_FADT.gpe1_base,
+ acpi_gbl_FADT.gpe1_base +
((register_count1 *
ACPI_GPE_REGISTER_WIDTH) - 1)));
@@ -1157,10 +1160,11 @@ acpi_status acpi_ev_gpe_initialize(void)
status =
acpi_ev_create_gpe_block(acpi_gbl_fadt_gpe_device,
- &acpi_gbl_FADT->xgpe1_blk,
+ &acpi_gbl_FADT.xgpe1_block,
register_count1,
- acpi_gbl_FADT->gpe1_base,
- acpi_gbl_FADT->sci_int,
+ acpi_gbl_FADT.gpe1_base,
+ acpi_gbl_FADT.
+ sci_interrupt,
&acpi_gbl_gpe_fadt_blocks
[1]);
@@ -1173,7 +1177,7 @@ acpi_status acpi_ev_gpe_initialize(void)
* GPE0 and GPE1 do not have to be contiguous in the GPE number
* space. However, GPE0 always starts at GPE number zero.
*/
- gpe_number_max = acpi_gbl_FADT->gpe1_base +
+ gpe_number_max = acpi_gbl_FADT.gpe1_base +
((register_count1 * ACPI_GPE_REGISTER_WIDTH) - 1);
}
}
diff --git a/drivers/acpi/events/evmisc.c b/drivers/acpi/events/evmisc.c
index bf63edc6608..d572700197f 100644
--- a/drivers/acpi/events/evmisc.c
+++ b/drivers/acpi/events/evmisc.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -63,14 +63,18 @@ static const char *acpi_notify_value_names[] = {
};
#endif
+/* Pointer to FACS needed for the Global Lock */
+
+static struct acpi_table_facs *facs = NULL;
+
/* Local prototypes */
static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context);
-static void ACPI_SYSTEM_XFACE acpi_ev_global_lock_thread(void *context);
-
static u32 acpi_ev_global_lock_handler(void *context);
+static acpi_status acpi_ev_remove_global_lock_handler(void);
+
/*******************************************************************************
*
* FUNCTION: acpi_ev_is_notify_object
@@ -192,12 +196,11 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node * node,
notify_info->notify.value = (u16) notify_value;
notify_info->notify.handler_obj = handler_obj;
- status =
- acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_ev_notify_dispatch,
- notify_info);
- if (ACPI_FAILURE(status)) {
- acpi_ut_delete_generic_state(notify_info);
- }
+ acpi_ex_relinquish_interpreter();
+
+ acpi_ev_notify_dispatch(notify_info);
+
+ acpi_ex_reacquire_interpreter();
}
if (!handler_obj) {
@@ -282,49 +285,19 @@ static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context)
/*******************************************************************************
*
- * FUNCTION: acpi_ev_global_lock_thread
- *
- * PARAMETERS: Context - From thread interface, not used
- *
- * RETURN: None
- *
- * DESCRIPTION: Invoked by SCI interrupt handler upon acquisition of the
- * Global Lock. Simply signal all threads that are waiting
- * for the lock.
- *
- ******************************************************************************/
-
-static void ACPI_SYSTEM_XFACE acpi_ev_global_lock_thread(void *context)
-{
- acpi_status status;
-
- /* Signal threads that are waiting for the lock */
-
- if (acpi_gbl_global_lock_thread_count) {
-
- /* Send sufficient units to the semaphore */
-
- status =
- acpi_os_signal_semaphore(acpi_gbl_global_lock_semaphore,
- acpi_gbl_global_lock_thread_count);
- if (ACPI_FAILURE(status)) {
- ACPI_ERROR((AE_INFO,
- "Could not signal Global Lock semaphore"));
- }
- }
-}
-
-/*******************************************************************************
- *
* FUNCTION: acpi_ev_global_lock_handler
*
* PARAMETERS: Context - From thread interface, not used
*
- * RETURN: ACPI_INTERRUPT_HANDLED or ACPI_INTERRUPT_NOT_HANDLED
+ * RETURN: ACPI_INTERRUPT_HANDLED
*
* DESCRIPTION: Invoked directly from the SCI handler when a global lock
- * release interrupt occurs. Grab the global lock and queue
- * the global lock thread for execution
+ * release interrupt occurs. Attempt to acquire the global lock,
+ * if successful, signal the thread waiting for the lock.
+ *
+ * NOTE: Assumes that the semaphore can be signaled from interrupt level. If
+ * this is not possible for some reason, a separate thread will have to be
+ * scheduled to do this.
*
******************************************************************************/
@@ -333,16 +306,24 @@ static u32 acpi_ev_global_lock_handler(void *context)
u8 acquired = FALSE;
/*
- * Attempt to get the lock
+ * Attempt to get the lock.
+ *
* If we don't get it now, it will be marked pending and we will
* take another interrupt when it becomes free.
*/
- ACPI_ACQUIRE_GLOBAL_LOCK(acpi_gbl_common_fACS.global_lock, acquired);
+ ACPI_ACQUIRE_GLOBAL_LOCK(facs, acquired);
if (acquired) {
/* Got the lock, now wake all threads waiting for it */
+
acpi_gbl_global_lock_acquired = TRUE;
- acpi_ev_global_lock_thread(context);
+ /* Send a unit to the semaphore */
+
+ if (ACPI_FAILURE(acpi_os_signal_semaphore(
+ acpi_gbl_global_lock_semaphore, 1))) {
+ ACPI_ERROR((AE_INFO,
+ "Could not signal Global Lock semaphore"));
+ }
}
return (ACPI_INTERRUPT_HANDLED);
@@ -366,6 +347,13 @@ acpi_status acpi_ev_init_global_lock_handler(void)
ACPI_FUNCTION_TRACE(ev_init_global_lock_handler);
+ status =
+ acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS,
+ (struct acpi_table_header **)&facs);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
acpi_gbl_global_lock_present = TRUE;
status = acpi_install_fixed_event_handler(ACPI_EVENT_GLOBAL,
acpi_ev_global_lock_handler,
@@ -389,6 +377,31 @@ acpi_status acpi_ev_init_global_lock_handler(void)
return_ACPI_STATUS(status);
}
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_remove_global_lock_handler
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Remove the handler for the Global Lock
+ *
+ ******************************************************************************/
+
+static acpi_status acpi_ev_remove_global_lock_handler(void)
+{
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE(ev_remove_global_lock_handler);
+
+ acpi_gbl_global_lock_present = FALSE;
+ status = acpi_remove_fixed_event_handler(ACPI_EVENT_GLOBAL,
+ acpi_ev_global_lock_handler);
+
+ return_ACPI_STATUS(status);
+}
+
/******************************************************************************
*
* FUNCTION: acpi_ev_acquire_global_lock
@@ -399,6 +412,16 @@ acpi_status acpi_ev_init_global_lock_handler(void)
*
* DESCRIPTION: Attempt to gain ownership of the Global Lock.
*
+ * MUTEX: Interpreter must be locked
+ *
+ * Note: The original implementation allowed multiple threads to "acquire" the
+ * Global Lock, and the OS would hold the lock until the last thread had
+ * released it. However, this could potentially starve the BIOS out of the
+ * lock, especially in the case where there is a tight handshake between the
+ * Embedded Controller driver and the BIOS. Therefore, this implementation
+ * allows only one thread to acquire the HW Global Lock at a time, and makes
+ * the global lock appear as a standard mutex on the OS side.
+ *
*****************************************************************************/
acpi_status acpi_ev_acquire_global_lock(u16 timeout)
@@ -408,53 +431,51 @@ acpi_status acpi_ev_acquire_global_lock(u16 timeout)
ACPI_FUNCTION_TRACE(ev_acquire_global_lock);
-#ifndef ACPI_APPLICATION
- /* Make sure that we actually have a global lock */
-
- if (!acpi_gbl_global_lock_present) {
- return_ACPI_STATUS(AE_NO_GLOBAL_LOCK);
+ /*
+ * Only one thread can acquire the GL at a time, the global_lock_mutex
+ * enforces this. This interface releases the interpreter if we must wait.
+ */
+ status = acpi_ex_system_wait_mutex(acpi_gbl_global_lock_mutex, timeout);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
}
-#endif
-
- /* One more thread wants the global lock */
-
- acpi_gbl_global_lock_thread_count++;
/*
- * If we (OS side vs. BIOS side) have the hardware lock already,
- * we are done
+ * Make sure that a global lock actually exists. If not, just treat
+ * the lock as a standard mutex.
*/
- if (acpi_gbl_global_lock_acquired) {
+ if (!acpi_gbl_global_lock_present) {
+ acpi_gbl_global_lock_acquired = TRUE;
return_ACPI_STATUS(AE_OK);
}
- /* We must acquire the actual hardware lock */
+ /* Attempt to acquire the actual hardware lock */
- ACPI_ACQUIRE_GLOBAL_LOCK(acpi_gbl_common_fACS.global_lock, acquired);
+ ACPI_ACQUIRE_GLOBAL_LOCK(facs, acquired);
if (acquired) {
/* We got the lock */
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "Acquired the HW Global Lock\n"));
+ "Acquired hardware Global Lock\n"));
acpi_gbl_global_lock_acquired = TRUE;
return_ACPI_STATUS(AE_OK);
}
/*
- * Did not get the lock. The pending bit was set above, and we must now
+ * Did not get the lock. The pending bit was set above, and we must now
* wait until we get the global lock released interrupt.
*/
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Waiting for the HW Global Lock\n"));
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Waiting for hardware Global Lock\n"));
/*
- * Acquire the global lock semaphore first.
- * Since this wait will block, we must release the interpreter
+ * Wait for handshake with the global lock interrupt handler.
+ * This interface releases the interpreter if we must wait.
*/
- status =
- acpi_ex_system_wait_semaphore(acpi_gbl_global_lock_semaphore,
- timeout);
+ status = acpi_ex_system_wait_semaphore(acpi_gbl_global_lock_semaphore,
+ ACPI_WAIT_FOREVER);
+
return_ACPI_STATUS(status);
}
@@ -477,38 +498,39 @@ acpi_status acpi_ev_release_global_lock(void)
ACPI_FUNCTION_TRACE(ev_release_global_lock);
- if (!acpi_gbl_global_lock_thread_count) {
+ /* Lock must be already acquired */
+
+ if (!acpi_gbl_global_lock_acquired) {
ACPI_WARNING((AE_INFO,
- "Cannot release HW Global Lock, it has not been acquired"));
+ "Cannot release the ACPI Global Lock, it has not been acquired"));
return_ACPI_STATUS(AE_NOT_ACQUIRED);
}
- /* One fewer thread has the global lock */
+ if (acpi_gbl_global_lock_present) {
- acpi_gbl_global_lock_thread_count--;
- if (acpi_gbl_global_lock_thread_count) {
+ /* Allow any thread to release the lock */
- /* There are still some threads holding the lock, cannot release */
+ ACPI_RELEASE_GLOBAL_LOCK(facs, pending);
- return_ACPI_STATUS(AE_OK);
+ /*
+ * If the pending bit was set, we must write GBL_RLS to the control
+ * register
+ */
+ if (pending) {
+ status =
+ acpi_set_register(ACPI_BITREG_GLOBAL_LOCK_RELEASE,
+ 1);
+ }
+
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+ "Released hardware Global Lock\n"));
}
- /*
- * No more threads holding lock, we can do the actual hardware
- * release
- */
- ACPI_RELEASE_GLOBAL_LOCK(acpi_gbl_common_fACS.global_lock, pending);
acpi_gbl_global_lock_acquired = FALSE;
- /*
- * If the pending bit was set, we must write GBL_RLS to the control
- * register
- */
- if (pending) {
- status = acpi_set_register(ACPI_BITREG_GLOBAL_LOCK_RELEASE,
- 1, ACPI_MTX_LOCK);
- }
+ /* Release the local GL mutex */
+ acpi_os_release_mutex(acpi_gbl_global_lock_mutex);
return_ACPI_STATUS(status);
}
@@ -558,6 +580,12 @@ void acpi_ev_terminate(void)
if (ACPI_FAILURE(status)) {
ACPI_ERROR((AE_INFO, "Could not remove SCI handler"));
}
+
+ status = acpi_ev_remove_global_lock_handler();
+ if (ACPI_FAILURE(status)) {
+ ACPI_ERROR((AE_INFO,
+ "Could not remove Global Lock handler"));
+ }
}
/* Deallocate all handler objects installed within GPE info structs */
diff --git a/drivers/acpi/events/evregion.c b/drivers/acpi/events/evregion.c
index 21caae04fe8..e99f0c435a4 100644
--- a/drivers/acpi/events/evregion.c
+++ b/drivers/acpi/events/evregion.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -291,7 +291,6 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
u32 bit_width, acpi_integer * value)
{
acpi_status status;
- acpi_status status2;
acpi_adr_space_handler handler;
acpi_adr_space_setup region_setup;
union acpi_operand_object *handler_desc;
@@ -345,7 +344,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
* setup will potentially execute control methods
* (e.g., _REG method for this region)
*/
- acpi_ex_exit_interpreter();
+ acpi_ex_relinquish_interpreter();
status = region_setup(region_obj, ACPI_REGION_ACTIVATE,
handler_desc->address_space.context,
@@ -353,10 +352,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
/* Re-enter the interpreter */
- status2 = acpi_ex_enter_interpreter();
- if (ACPI_FAILURE(status2)) {
- return_ACPI_STATUS(status2);
- }
+ acpi_ex_reacquire_interpreter();
/* Check for failure of the Region Setup */
@@ -409,7 +405,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
* exit the interpreter because the handler *might* block -- we don't
* know what it will do, so we can't hold the lock on the intepreter.
*/
- acpi_ex_exit_interpreter();
+ acpi_ex_relinquish_interpreter();
}
/* Call the handler */
@@ -430,10 +426,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
* We just returned from a non-default handler, we must re-enter the
* interpreter
*/
- status2 = acpi_ex_enter_interpreter();
- if (ACPI_FAILURE(status2)) {
- return_ACPI_STATUS(status2);
- }
+ acpi_ex_reacquire_interpreter();
}
return_ACPI_STATUS(status);
diff --git a/drivers/acpi/events/evrgnini.c b/drivers/acpi/events/evrgnini.c
index 203d1359190..a4fa7e6822a 100644
--- a/drivers/acpi/events/evrgnini.c
+++ b/drivers/acpi/events/evrgnini.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -48,6 +48,11 @@
#define _COMPONENT ACPI_EVENTS
ACPI_MODULE_NAME("evrgnini")
+/* Local prototypes */
+static u8 acpi_ev_match_pci_root_bridge(char *id);
+
+static u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node);
+
/*******************************************************************************
*
* FUNCTION: acpi_ev_system_memory_region_setup
@@ -62,6 +67,7 @@ ACPI_MODULE_NAME("evrgnini")
* DESCRIPTION: Setup a system_memory operation region
*
******************************************************************************/
+
acpi_status
acpi_ev_system_memory_region_setup(acpi_handle handle,
u32 function,
@@ -168,9 +174,9 @@ acpi_ev_pci_config_region_setup(acpi_handle handle,
union acpi_operand_object *handler_obj;
struct acpi_namespace_node *parent_node;
struct acpi_namespace_node *pci_root_node;
+ struct acpi_namespace_node *pci_device_node;
union acpi_operand_object *region_obj =
(union acpi_operand_object *)handle;
- struct acpi_device_id object_hID;
ACPI_FUNCTION_TRACE(ev_pci_config_region_setup);
@@ -215,45 +221,30 @@ acpi_ev_pci_config_region_setup(acpi_handle handle,
pci_root_node = parent_node;
while (pci_root_node != acpi_gbl_root_node) {
- status =
- acpi_ut_execute_HID(pci_root_node, &object_hID);
- if (ACPI_SUCCESS(status)) {
- /*
- * Got a valid _HID string, check if this is a PCI root.
- * New for ACPI 3.0: check for a PCI Express root also.
- */
- if (!
- (ACPI_STRNCMP
- (object_hID.value, PCI_ROOT_HID_STRING,
- sizeof(PCI_ROOT_HID_STRING)))
- ||
- !(ACPI_STRNCMP
- (object_hID.value,
- PCI_EXPRESS_ROOT_HID_STRING,
- sizeof(PCI_EXPRESS_ROOT_HID_STRING)))) {
-
- /* Install a handler for this PCI root bridge */
- status =
- acpi_install_address_space_handler((acpi_handle) pci_root_node, ACPI_ADR_SPACE_PCI_CONFIG, ACPI_DEFAULT_HANDLER, NULL, NULL);
- if (ACPI_FAILURE(status)) {
- if (status == AE_SAME_HANDLER) {
- /*
- * It is OK if the handler is already installed on the root
- * bridge. Still need to return a context object for the
- * new PCI_Config operation region, however.
- */
- status = AE_OK;
- } else {
- ACPI_EXCEPTION((AE_INFO,
- status,
- "Could not install PciConfig handler for Root Bridge %4.4s",
- acpi_ut_get_node_name
- (pci_root_node)));
- }
+ /* Get the _HID/_CID in order to detect a root_bridge */
+
+ if (acpi_ev_is_pci_root_bridge(pci_root_node)) {
+
+ /* Install a handler for this PCI root bridge */
+
+ status = acpi_install_address_space_handler((acpi_handle) pci_root_node, ACPI_ADR_SPACE_PCI_CONFIG, ACPI_DEFAULT_HANDLER, NULL, NULL);
+ if (ACPI_FAILURE(status)) {
+ if (status == AE_SAME_HANDLER) {
+ /*
+ * It is OK if the handler is already installed on the root
+ * bridge. Still need to return a context object for the
+ * new PCI_Config operation region, however.
+ */
+ status = AE_OK;
+ } else {
+ ACPI_EXCEPTION((AE_INFO, status,
+ "Could not install PciConfig handler for Root Bridge %4.4s",
+ acpi_ut_get_node_name
+ (pci_root_node)));
}
- break;
}
+ break;
}
pci_root_node = acpi_ns_get_parent_node(pci_root_node);
@@ -282,14 +273,25 @@ acpi_ev_pci_config_region_setup(acpi_handle handle,
/*
* For PCI_Config space access, we need the segment, bus,
* device and function numbers. Acquire them here.
+ *
+ * Find the parent device object. (This allows the operation region to be
+ * within a subscope under the device, such as a control method.)
*/
+ pci_device_node = region_obj->region.node;
+ while (pci_device_node && (pci_device_node->type != ACPI_TYPE_DEVICE)) {
+ pci_device_node = acpi_ns_get_parent_node(pci_device_node);
+ }
+
+ if (!pci_device_node) {
+ return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
+ }
/*
* Get the PCI device and function numbers from the _ADR object
* contained in the parent's scope.
*/
status =
- acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR, parent_node,
+ acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR, pci_device_node,
&pci_value);
/*
@@ -329,6 +331,91 @@ acpi_ev_pci_config_region_setup(acpi_handle handle,
/*******************************************************************************
*
+ * FUNCTION: acpi_ev_match_pci_root_bridge
+ *
+ * PARAMETERS: Id - The HID/CID in string format
+ *
+ * RETURN: TRUE if the Id is a match for a PCI/PCI-Express Root Bridge
+ *
+ * DESCRIPTION: Determine if the input ID is a PCI Root Bridge ID.
+ *
+ ******************************************************************************/
+
+static u8 acpi_ev_match_pci_root_bridge(char *id)
+{
+
+ /*
+ * Check if this is a PCI root.
+ * ACPI 3.0+: check for a PCI Express root also.
+ */
+ if (!(ACPI_STRNCMP(id,
+ PCI_ROOT_HID_STRING,
+ sizeof(PCI_ROOT_HID_STRING))) ||
+ !(ACPI_STRNCMP(id,
+ PCI_EXPRESS_ROOT_HID_STRING,
+ sizeof(PCI_EXPRESS_ROOT_HID_STRING)))) {
+ return (TRUE);
+ }
+
+ return (FALSE);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_is_pci_root_bridge
+ *
+ * PARAMETERS: Node - Device node being examined
+ *
+ * RETURN: TRUE if device is a PCI/PCI-Express Root Bridge
+ *
+ * DESCRIPTION: Determine if the input device represents a PCI Root Bridge by
+ * examining the _HID and _CID for the device.
+ *
+ ******************************************************************************/
+
+static u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node)
+{
+ acpi_status status;
+ struct acpi_device_id hid;
+ struct acpi_compatible_id_list *cid;
+ acpi_native_uint i;
+
+ /*
+ * Get the _HID and check for a PCI Root Bridge
+ */
+ status = acpi_ut_execute_HID(node, &hid);
+ if (ACPI_FAILURE(status)) {
+ return (FALSE);
+ }
+
+ if (acpi_ev_match_pci_root_bridge(hid.value)) {
+ return (TRUE);
+ }
+
+ /*
+ * The _HID did not match.
+ * Get the _CID and check for a PCI Root Bridge
+ */
+ status = acpi_ut_execute_CID(node, &cid);
+ if (ACPI_FAILURE(status)) {
+ return (FALSE);
+ }
+
+ /* Check all _CIDs in the returned list */
+
+ for (i = 0; i < cid->count; i++) {
+ if (acpi_ev_match_pci_root_bridge(cid->id[i].value)) {
+ ACPI_FREE(cid);
+ return (TRUE);
+ }
+ }
+
+ ACPI_FREE(cid);
+ return (FALSE);
+}
+
+/*******************************************************************************
+ *
* FUNCTION: acpi_ev_pci_bar_region_setup
*
* PARAMETERS: Handle - Region we are interested in
@@ -432,6 +519,9 @@ acpi_ev_default_region_setup(acpi_handle handle,
* a PCI address in the scope of the definition. This address is
* required to perform an access to PCI config space.
*
+ * MUTEX: Interpreter should be unlocked, because we may run the _REG
+ * method for this region.
+ *
******************************************************************************/
acpi_status
diff --git a/drivers/acpi/events/evsci.c b/drivers/acpi/events/evsci.c
index 8106215ad55..7e5d15ce239 100644
--- a/drivers/acpi/events/evsci.c
+++ b/drivers/acpi/events/evsci.c
@@ -6,7 +6,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -142,9 +142,10 @@ u32 acpi_ev_install_sci_handler(void)
ACPI_FUNCTION_TRACE(ev_install_sci_handler);
- status = acpi_os_install_interrupt_handler((u32) acpi_gbl_FADT->sci_int,
- acpi_ev_sci_xrupt_handler,
- acpi_gbl_gpe_xrupt_list_head);
+ status =
+ acpi_os_install_interrupt_handler((u32) acpi_gbl_FADT.sci_interrupt,
+ acpi_ev_sci_xrupt_handler,
+ acpi_gbl_gpe_xrupt_list_head);
return_ACPI_STATUS(status);
}
@@ -175,8 +176,9 @@ acpi_status acpi_ev_remove_sci_handler(void)
/* Just let the OS remove the handler and disable the level */
- status = acpi_os_remove_interrupt_handler((u32) acpi_gbl_FADT->sci_int,
- acpi_ev_sci_xrupt_handler);
+ status =
+ acpi_os_remove_interrupt_handler((u32) acpi_gbl_FADT.sci_interrupt,
+ acpi_ev_sci_xrupt_handler);
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/events/evxface.c b/drivers/acpi/events/evxface.c
index 923fd2b4695..685a103a358 100644
--- a/drivers/acpi/events/evxface.c
+++ b/drivers/acpi/events/evxface.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -768,11 +768,9 @@ acpi_status acpi_acquire_global_lock(u16 timeout, u32 * handle)
return (AE_BAD_PARAMETER);
}
- status = acpi_ex_enter_interpreter();
- if (ACPI_FAILURE(status)) {
- return (status);
- }
+ /* Must lock interpreter to prevent race conditions */
+ acpi_ex_enter_interpreter();
status = acpi_ev_acquire_global_lock(timeout);
acpi_ex_exit_interpreter();
diff --git a/drivers/acpi/events/evxfevnt.c b/drivers/acpi/events/evxfevnt.c
index 7ebc2efac93..17065e98807 100644
--- a/drivers/acpi/events/evxfevnt.c
+++ b/drivers/acpi/events/evxfevnt.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -44,6 +44,7 @@
#include <acpi/acpi.h>
#include <acpi/acevents.h>
#include <acpi/acnamesp.h>
+#include <acpi/actables.h>
#define _COMPONENT ACPI_EVENTS
ACPI_MODULE_NAME("evxfevnt")
@@ -65,13 +66,14 @@ acpi_status acpi_enable(void)
ACPI_FUNCTION_TRACE(acpi_enable);
- /* Make sure we have the FADT */
+ /* ACPI tables must be present */
- if (!acpi_gbl_FADT) {
- ACPI_WARNING((AE_INFO, "No FADT information present!"));
+ if (!acpi_tb_tables_loaded()) {
return_ACPI_STATUS(AE_NO_ACPI_TABLES);
}
+ /* Check current mode */
+
if (acpi_hw_get_mode() == ACPI_SYS_MODE_ACPI) {
ACPI_DEBUG_PRINT((ACPI_DB_INIT,
"System is already in ACPI mode\n"));
@@ -111,11 +113,6 @@ acpi_status acpi_disable(void)
ACPI_FUNCTION_TRACE(acpi_disable);
- if (!acpi_gbl_FADT) {
- ACPI_WARNING((AE_INFO, "No FADT information present!"));
- return_ACPI_STATUS(AE_NO_ACPI_TABLES);
- }
-
if (acpi_hw_get_mode() == ACPI_SYS_MODE_LEGACY) {
ACPI_DEBUG_PRINT((ACPI_DB_INIT,
"System is already in legacy (non-ACPI) mode\n"));
@@ -169,7 +166,7 @@ acpi_status acpi_enable_event(u32 event, u32 flags)
*/
status =
acpi_set_register(acpi_gbl_fixed_event_info[event].
- enable_register_id, 1, ACPI_MTX_LOCK);
+ enable_register_id, 1);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
@@ -178,7 +175,7 @@ acpi_status acpi_enable_event(u32 event, u32 flags)
status =
acpi_get_register(acpi_gbl_fixed_event_info[event].
- enable_register_id, &value, ACPI_MTX_LOCK);
+ enable_register_id, &value);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
@@ -368,14 +365,14 @@ acpi_status acpi_disable_event(u32 event, u32 flags)
*/
status =
acpi_set_register(acpi_gbl_fixed_event_info[event].
- enable_register_id, 0, ACPI_MTX_LOCK);
+ enable_register_id, 0);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
status =
acpi_get_register(acpi_gbl_fixed_event_info[event].
- enable_register_id, &value, ACPI_MTX_LOCK);
+ enable_register_id, &value);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
@@ -421,7 +418,7 @@ acpi_status acpi_clear_event(u32 event)
*/
status =
acpi_set_register(acpi_gbl_fixed_event_info[event].
- status_register_id, 1, ACPI_MTX_LOCK);
+ status_register_id, 1);
return_ACPI_STATUS(status);
}
@@ -510,7 +507,7 @@ acpi_status acpi_get_event_status(u32 event, acpi_event_status * event_status)
status =
acpi_get_register(acpi_gbl_fixed_event_info[event].
- status_register_id, event_status, ACPI_MTX_LOCK);
+ status_register_id, event_status);
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/events/evxfregn.c b/drivers/acpi/events/evxfregn.c
index 83b12a9afa3..7bf09c5fb24 100644
--- a/drivers/acpi/events/evxfregn.c
+++ b/drivers/acpi/events/evxfregn.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exconfig.c b/drivers/acpi/executer/exconfig.c
index c8341fa5fe0..25802f302ff 100644
--- a/drivers/acpi/executer/exconfig.c
+++ b/drivers/acpi/executer/exconfig.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -54,7 +54,7 @@ ACPI_MODULE_NAME("exconfig")
/* Local prototypes */
static acpi_status
-acpi_ex_add_table(struct acpi_table_header *table,
+acpi_ex_add_table(acpi_native_uint table_index,
struct acpi_namespace_node *parent_node,
union acpi_operand_object **ddb_handle);
@@ -74,12 +74,11 @@ acpi_ex_add_table(struct acpi_table_header *table,
******************************************************************************/
static acpi_status
-acpi_ex_add_table(struct acpi_table_header *table,
+acpi_ex_add_table(acpi_native_uint table_index,
struct acpi_namespace_node *parent_node,
union acpi_operand_object **ddb_handle)
{
acpi_status status;
- struct acpi_table_desc table_info;
union acpi_operand_object *obj_desc;
ACPI_FUNCTION_TRACE(ex_add_table);
@@ -98,42 +97,16 @@ acpi_ex_add_table(struct acpi_table_header *table,
/* Install the new table into the local data structures */
- ACPI_MEMSET(&table_info, 0, sizeof(struct acpi_table_desc));
-
- table_info.type = ACPI_TABLE_ID_SSDT;
- table_info.pointer = table;
- table_info.length = (acpi_size) table->length;
- table_info.allocation = ACPI_MEM_ALLOCATED;
-
- status = acpi_tb_install_table(&table_info);
- obj_desc->reference.object = table_info.installed_desc;
-
- if (ACPI_FAILURE(status)) {
- if (status == AE_ALREADY_EXISTS) {
-
- /* Table already exists, just return the handle */
-
- return_ACPI_STATUS(AE_OK);
- }
- goto cleanup;
- }
+ obj_desc->reference.object = ACPI_CAST_PTR(void, table_index);
/* Add the table to the namespace */
- status = acpi_ns_load_table(table_info.installed_desc, parent_node);
+ status = acpi_ns_load_table(table_index, parent_node);
if (ACPI_FAILURE(status)) {
-
- /* Uninstall table on error */
-
- (void)acpi_tb_uninstall_table(table_info.installed_desc);
- goto cleanup;
+ acpi_ut_remove_reference(obj_desc);
+ *ddb_handle = NULL;
}
- return_ACPI_STATUS(AE_OK);
-
- cleanup:
- acpi_ut_remove_reference(obj_desc);
- *ddb_handle = NULL;
return_ACPI_STATUS(status);
}
@@ -146,7 +119,7 @@ acpi_ex_add_table(struct acpi_table_header *table,
*
* RETURN: Status
*
- * DESCRIPTION: Load an ACPI table
+ * DESCRIPTION: Load an ACPI table from the RSDT/XSDT
*
******************************************************************************/
@@ -156,33 +129,20 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state,
{
acpi_status status;
union acpi_operand_object **operand = &walk_state->operands[0];
- struct acpi_table_header *table;
+ acpi_native_uint table_index;
struct acpi_namespace_node *parent_node;
struct acpi_namespace_node *start_node;
struct acpi_namespace_node *parameter_node = NULL;
union acpi_operand_object *ddb_handle;
+ struct acpi_table_header *table;
ACPI_FUNCTION_TRACE(ex_load_table_op);
-#if 0
- /*
- * Make sure that the signature does not match one of the tables that
- * is already loaded.
- */
- status = acpi_tb_match_signature(operand[0]->string.pointer, NULL);
- if (status == AE_OK) {
-
- /* Signature matched -- don't allow override */
-
- return_ACPI_STATUS(AE_ALREADY_EXISTS);
- }
-#endif
-
- /* Find the ACPI table */
+ /* Find the ACPI table in the RSDT/XSDT */
status = acpi_tb_find_table(operand[0]->string.pointer,
operand[1]->string.pointer,
- operand[2]->string.pointer, &table);
+ operand[2]->string.pointer, &table_index);
if (ACPI_FAILURE(status)) {
if (status != AE_NOT_FOUND) {
return_ACPI_STATUS(status);
@@ -245,7 +205,7 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state,
/* Load the table into the namespace */
- status = acpi_ex_add_table(table, parent_node, &ddb_handle);
+ status = acpi_ex_add_table(table_index, parent_node, &ddb_handle);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
@@ -266,9 +226,13 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state,
}
}
- ACPI_INFO((AE_INFO,
- "Dynamic OEM Table Load - [%4.4s] OemId [%6.6s] OemTableId [%8.8s]",
- table->signature, table->oem_id, table->oem_table_id));
+ status = acpi_get_table_by_index(table_index, &table);
+ if (ACPI_SUCCESS(status)) {
+ ACPI_INFO((AE_INFO,
+ "Dynamic OEM Table Load - [%4.4s] OemId [%6.6s] OemTableId [%8.8s]",
+ table->signature, table->oem_id,
+ table->oem_table_id));
+ }
*return_desc = ddb_handle;
return_ACPI_STATUS(status);
@@ -278,7 +242,7 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state,
*
* FUNCTION: acpi_ex_load_op
*
- * PARAMETERS: obj_desc - Region or Field where the table will be
+ * PARAMETERS: obj_desc - Region or Buffer/Field where the table will be
* obtained
* Target - Where a handle to the table will be stored
* walk_state - Current state
@@ -287,6 +251,12 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state,
*
* DESCRIPTION: Load an ACPI table from a field or operation region
*
+ * NOTE: Region Fields (Field, bank_field, index_fields) are resolved to buffer
+ * objects before this code is reached.
+ *
+ * If source is an operation region, it must refer to system_memory, as
+ * per the ACPI specification.
+ *
******************************************************************************/
acpi_status
@@ -294,22 +264,26 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
union acpi_operand_object *target,
struct acpi_walk_state *walk_state)
{
- acpi_status status;
union acpi_operand_object *ddb_handle;
- union acpi_operand_object *buffer_desc = NULL;
- struct acpi_table_header *table_ptr = NULL;
- acpi_physical_address address;
- struct acpi_table_header table_header;
- acpi_integer temp;
- u32 i;
+ struct acpi_table_desc table_desc;
+ acpi_native_uint table_index;
+ acpi_status status;
ACPI_FUNCTION_TRACE(ex_load_op);
- /* Object can be either an op_region or a Field */
+ ACPI_MEMSET(&table_desc, 0, sizeof(struct acpi_table_desc));
+
+ /* Source Object can be either an op_region or a Buffer/Field */
switch (ACPI_GET_OBJECT_TYPE(obj_desc)) {
case ACPI_TYPE_REGION:
+ /* Region must be system_memory (from ACPI spec) */
+
+ if (obj_desc->region.space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) {
+ return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
+ }
+
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Load from Region %p %s\n",
obj_desc,
acpi_ut_get_object_type_name(obj_desc)));
@@ -325,113 +299,41 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
}
}
- /* Get the base physical address of the region */
-
- address = obj_desc->region.address;
-
- /* Get part of the table header to get the table length */
-
- table_header.length = 0;
- for (i = 0; i < 8; i++) {
- status =
- acpi_ev_address_space_dispatch(obj_desc, ACPI_READ,
- (acpi_physical_address)
- (i + address), 8,
- &temp);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- /* Get the one valid byte of the returned 64-bit value */
-
- ACPI_CAST_PTR(u8, &table_header)[i] = (u8) temp;
- }
-
- /* Sanity check the table length */
-
- if (table_header.length < sizeof(struct acpi_table_header)) {
- return_ACPI_STATUS(AE_BAD_HEADER);
- }
-
- /* Allocate a buffer for the entire table */
-
- table_ptr = ACPI_ALLOCATE(table_header.length);
- if (!table_ptr) {
- return_ACPI_STATUS(AE_NO_MEMORY);
- }
-
- /* Get the entire table from the op region */
-
- for (i = 0; i < table_header.length; i++) {
- status =
- acpi_ev_address_space_dispatch(obj_desc, ACPI_READ,
- (acpi_physical_address)
- (i + address), 8,
- &temp);
- if (ACPI_FAILURE(status)) {
- goto cleanup;
- }
-
- /* Get the one valid byte of the returned 64-bit value */
-
- ACPI_CAST_PTR(u8, table_ptr)[i] = (u8) temp;
- }
+ table_desc.address = obj_desc->region.address;
+ table_desc.length = obj_desc->region.length;
+ table_desc.flags = ACPI_TABLE_ORIGIN_MAPPED;
break;
- case ACPI_TYPE_LOCAL_REGION_FIELD:
- case ACPI_TYPE_LOCAL_BANK_FIELD:
- case ACPI_TYPE_LOCAL_INDEX_FIELD:
+ case ACPI_TYPE_BUFFER: /* Buffer or resolved region_field */
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Load from Field %p %s\n",
- obj_desc,
- acpi_ut_get_object_type_name(obj_desc)));
+ /* Simply extract the buffer from the buffer object */
- /*
- * The length of the field must be at least as large as the table.
- * Read the entire field and thus the entire table. Buffer is
- * allocated during the read.
- */
- status =
- acpi_ex_read_data_from_field(walk_state, obj_desc,
- &buffer_desc);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- table_ptr = ACPI_CAST_PTR(struct acpi_table_header,
- buffer_desc->buffer.pointer);
-
- /* All done with the buffer_desc, delete it */
-
- buffer_desc->buffer.pointer = NULL;
- acpi_ut_remove_reference(buffer_desc);
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+ "Load from Buffer or Field %p %s\n", obj_desc,
+ acpi_ut_get_object_type_name(obj_desc)));
- /* Sanity check the table length */
+ table_desc.pointer = ACPI_CAST_PTR(struct acpi_table_header,
+ obj_desc->buffer.pointer);
+ table_desc.length = table_desc.pointer->length;
+ table_desc.flags = ACPI_TABLE_ORIGIN_ALLOCATED;
- if (table_ptr->length < sizeof(struct acpi_table_header)) {
- status = AE_BAD_HEADER;
- goto cleanup;
- }
+ obj_desc->buffer.pointer = NULL;
break;
default:
return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
}
- /* The table must be either an SSDT or a PSDT */
-
- if ((!ACPI_COMPARE_NAME(table_ptr->signature, PSDT_SIG)) &&
- (!ACPI_COMPARE_NAME(table_ptr->signature, SSDT_SIG))) {
- ACPI_ERROR((AE_INFO,
- "Table has invalid signature [%4.4s], must be SSDT or PSDT",
- table_ptr->signature));
- status = AE_BAD_SIGNATURE;
+ /*
+ * Install the new table into the local data structures
+ */
+ status = acpi_tb_add_table(&table_desc, &table_index);
+ if (ACPI_FAILURE(status)) {
goto cleanup;
}
- /* Install the new table into the local data structures */
-
- status = acpi_ex_add_table(table_ptr, acpi_gbl_root_node, &ddb_handle);
+ status =
+ acpi_ex_add_table(table_index, acpi_gbl_root_node, &ddb_handle);
if (ACPI_FAILURE(status)) {
/* On error, table_ptr was deallocated above */
@@ -450,13 +352,9 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
return_ACPI_STATUS(status);
}
- ACPI_INFO((AE_INFO,
- "Dynamic SSDT Load - OemId [%6.6s] OemTableId [%8.8s]",
- table_ptr->oem_id, table_ptr->oem_table_id));
-
cleanup:
if (ACPI_FAILURE(status)) {
- ACPI_FREE(table_ptr);
+ acpi_tb_delete_table(&table_desc);
}
return_ACPI_STATUS(status);
}
@@ -477,7 +375,7 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle)
{
acpi_status status = AE_OK;
union acpi_operand_object *table_desc = ddb_handle;
- struct acpi_table_desc *table_info;
+ acpi_native_uint table_index;
ACPI_FUNCTION_TRACE(ex_unload_table);
@@ -493,19 +391,18 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle)
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
- /* Get the actual table descriptor from the ddb_handle */
+ /* Get the table index from the ddb_handle */
- table_info = (struct acpi_table_desc *)table_desc->reference.object;
+ table_index = (acpi_native_uint) table_desc->reference.object;
/*
* Delete the entire namespace under this table Node
* (Offset contains the table_id)
*/
- acpi_ns_delete_namespace_by_owner(table_info->owner_id);
-
- /* Delete the table itself */
+ acpi_tb_delete_namespace_by_owner(table_index);
+ acpi_tb_release_owner_id(table_index);
- (void)acpi_tb_uninstall_table(table_info->installed_desc);
+ acpi_tb_set_table_loaded_flag(table_index, FALSE);
/* Delete the table descriptor (ddb_handle) */
diff --git a/drivers/acpi/executer/exconvrt.c b/drivers/acpi/executer/exconvrt.c
index 544e81a6a43..d470e8b1f4e 100644
--- a/drivers/acpi/executer/exconvrt.c
+++ b/drivers/acpi/executer/exconvrt.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/excreate.c b/drivers/acpi/executer/excreate.c
index 34eec82c1b1..7c38528a7e8 100644
--- a/drivers/acpi/executer/excreate.c
+++ b/drivers/acpi/executer/excreate.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -359,8 +359,9 @@ acpi_status acpi_ex_create_table_region(struct acpi_walk_state *walk_state)
union acpi_operand_object **operand = &walk_state->operands[0];
union acpi_operand_object *obj_desc;
struct acpi_namespace_node *node;
- struct acpi_table_header *table;
union acpi_operand_object *region_obj2;
+ acpi_native_uint table_index;
+ struct acpi_table_header *table;
ACPI_FUNCTION_TRACE(ex_create_table_region);
@@ -380,7 +381,7 @@ acpi_status acpi_ex_create_table_region(struct acpi_walk_state *walk_state)
status = acpi_tb_find_table(operand[1]->string.pointer,
operand[2]->string.pointer,
- operand[3]->string.pointer, &table);
+ operand[3]->string.pointer, &table_index);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
@@ -395,6 +396,11 @@ acpi_status acpi_ex_create_table_region(struct acpi_walk_state *walk_state)
region_obj2 = obj_desc->common.next_object;
region_obj2->extra.region_context = NULL;
+ status = acpi_get_table_by_index(table_index, &table);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
/* Init the region from the operands */
obj_desc->region.space_id = REGION_DATA_TABLE;
@@ -553,7 +559,8 @@ acpi_ex_create_method(u8 * aml_start,
obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_METHOD);
if (!obj_desc) {
- return_ACPI_STATUS(AE_NO_MEMORY);
+ status = AE_NO_MEMORY;
+ goto exit;
}
/* Save the method's AML pointer and length */
@@ -576,10 +583,7 @@ acpi_ex_create_method(u8 * aml_start,
* Get the sync_level. If method is serialized, a mutex will be
* created for this method when it is parsed.
*/
- if (acpi_gbl_all_methods_serialized) {
- obj_desc->method.sync_level = 0;
- obj_desc->method.method_flags |= AML_METHOD_SERIALIZED;
- } else if (method_flags & AML_METHOD_SERIALIZED) {
+ if (method_flags & AML_METHOD_SERIALIZED) {
/*
* ACPI 1.0: sync_level = 0
* ACPI 2.0: sync_level = sync_level in method declaration
@@ -597,6 +601,7 @@ acpi_ex_create_method(u8 * aml_start,
acpi_ut_remove_reference(obj_desc);
+ exit:
/* Remove a reference to the operand */
acpi_ut_remove_reference(operand[1]);
diff --git a/drivers/acpi/executer/exdump.c b/drivers/acpi/executer/exdump.c
index 2450943add3..1a73c14df2c 100644
--- a/drivers/acpi/executer/exdump.c
+++ b/drivers/acpi/executer/exdump.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -59,8 +59,6 @@ static void acpi_ex_out_string(char *title, char *value);
static void acpi_ex_out_pointer(char *title, void *value);
-static void acpi_ex_out_address(char *title, acpi_physical_address value);
-
static void
acpi_ex_dump_object(union acpi_operand_object *obj_desc,
struct acpi_exdump_info *info);
@@ -92,10 +90,11 @@ static struct acpi_exdump_info acpi_ex_dump_string[4] = {
{ACPI_EXD_STRING, 0, NULL}
};
-static struct acpi_exdump_info acpi_ex_dump_buffer[4] = {
+static struct acpi_exdump_info acpi_ex_dump_buffer[5] = {
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_buffer), NULL},
{ACPI_EXD_UINT32, ACPI_EXD_OFFSET(buffer.length), "Length"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(buffer.pointer), "Pointer"},
+ {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(buffer.node), "Parent Node"},
{ACPI_EXD_BUFFER, 0, NULL}
};
@@ -135,7 +134,7 @@ static struct acpi_exdump_info acpi_ex_dump_method[8] = {
static struct acpi_exdump_info acpi_ex_dump_mutex[5] = {
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_mutex), NULL},
{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(mutex.sync_level), "Sync Level"},
- {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(mutex.owner_thread), "Owner Thread"},
+ {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(mutex.owner_thread_id), "Owner Thread"},
{ACPI_EXD_UINT16, ACPI_EXD_OFFSET(mutex.acquisition_depth),
"Acquire Depth"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(mutex.os_mutex), "OsMutex"}
@@ -165,8 +164,8 @@ static struct acpi_exdump_info acpi_ex_dump_power[5] = {
static struct acpi_exdump_info acpi_ex_dump_processor[7] = {
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_processor), NULL},
- {ACPI_EXD_UINT32, ACPI_EXD_OFFSET(processor.proc_id), "Processor ID"},
- {ACPI_EXD_UINT32, ACPI_EXD_OFFSET(processor.length), "Length"},
+ {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(processor.proc_id), "Processor ID"},
+ {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(processor.length), "Length"},
{ACPI_EXD_ADDRESS, ACPI_EXD_OFFSET(processor.address), "Address"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(processor.system_notify),
"System Notify"},
@@ -379,18 +378,12 @@ acpi_ex_dump_object(union acpi_operand_object *obj_desc,
break;
case ACPI_EXD_POINTER:
+ case ACPI_EXD_ADDRESS:
acpi_ex_out_pointer(name,
*ACPI_CAST_PTR(void *, target));
break;
- case ACPI_EXD_ADDRESS:
-
- acpi_ex_out_address(name,
- *ACPI_CAST_PTR
- (acpi_physical_address, target));
- break;
-
case ACPI_EXD_STRING:
acpi_ut_print_string(obj_desc->string.pointer,
@@ -834,16 +827,6 @@ static void acpi_ex_out_pointer(char *title, void *value)
acpi_os_printf("%20s : %p\n", title, value);
}
-static void acpi_ex_out_address(char *title, acpi_physical_address value)
-{
-
-#if ACPI_MACHINE_WIDTH == 16
- acpi_os_printf("%20s : %p\n", title, value);
-#else
- acpi_os_printf("%20s : %8.8X%8.8X\n", title, ACPI_FORMAT_UINT64(value));
-#endif
-}
-
/*******************************************************************************
*
* FUNCTION: acpi_ex_dump_namespace_node
diff --git a/drivers/acpi/executer/exfield.c b/drivers/acpi/executer/exfield.c
index 9ea9c3a67ca..2d88a3d8d1a 100644
--- a/drivers/acpi/executer/exfield.c
+++ b/drivers/acpi/executer/exfield.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exfldio.c b/drivers/acpi/executer/exfldio.c
index 40f0bee6faa..65a48b6170e 100644
--- a/drivers/acpi/executer/exfldio.c
+++ b/drivers/acpi/executer/exfldio.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -257,14 +257,13 @@ acpi_ex_access_region(union acpi_operand_object *obj_desc,
}
ACPI_DEBUG_PRINT_RAW((ACPI_DB_BFIELD,
- " Region [%s:%X], Width %X, ByteBase %X, Offset %X at %8.8X%8.8X\n",
+ " Region [%s:%X], Width %X, ByteBase %X, Offset %X at %p\n",
acpi_ut_get_region_name(rgn_desc->region.
space_id),
rgn_desc->region.space_id,
obj_desc->common_field.access_byte_width,
obj_desc->common_field.base_byte_offset,
- field_datum_byte_offset,
- ACPI_FORMAT_UINT64(address)));
+ field_datum_byte_offset, (void *)address));
/* Invoke the appropriate address_space/op_region handler */
diff --git a/drivers/acpi/executer/exmisc.c b/drivers/acpi/executer/exmisc.c
index bd98aab017c..f13d1cec2d6 100644
--- a/drivers/acpi/executer/exmisc.c
+++ b/drivers/acpi/executer/exmisc.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exmutex.c b/drivers/acpi/executer/exmutex.c
index bf90f04f2c6..4eb883bda6a 100644
--- a/drivers/acpi/executer/exmutex.c
+++ b/drivers/acpi/executer/exmutex.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -44,6 +44,7 @@
#include <acpi/acpi.h>
#include <acpi/acinterp.h>
+#include <acpi/acevents.h>
#define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME("exmutex")
@@ -65,10 +66,9 @@ acpi_ex_link_mutex(union acpi_operand_object *obj_desc,
*
******************************************************************************/
-void acpi_ex_unlink_mutex(union acpi_operand_object *obj_desc)
+void acpi_ex_unlink_mutex(union acpi_operand_object *obj_desc,
+ struct acpi_thread_state *thread)
{
- struct acpi_thread_state *thread = obj_desc->mutex.owner_thread;
-
if (!thread) {
return;
}
@@ -150,7 +150,7 @@ acpi_ex_acquire_mutex(union acpi_operand_object *time_desc,
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
- /* Sanity check -- we must have a valid thread ID */
+ /* Sanity check: we must have a valid thread ID */
if (!walk_state->thread) {
ACPI_ERROR((AE_INFO,
@@ -173,25 +173,26 @@ acpi_ex_acquire_mutex(union acpi_operand_object *time_desc,
/* Support for multiple acquires by the owning thread */
- if (obj_desc->mutex.owner_thread) {
+ if (obj_desc->mutex.owner_thread_id == acpi_os_get_thread_id()) {
+ /*
+ * The mutex is already owned by this thread, just increment the
+ * acquisition depth
+ */
+ obj_desc->mutex.acquisition_depth++;
+ return_ACPI_STATUS(AE_OK);
+ }
- /* Special case for Global Lock, allow all threads */
+ /* Acquire the mutex, wait if necessary. Special case for Global Lock */
- if ((obj_desc->mutex.owner_thread->thread_id ==
- walk_state->thread->thread_id) ||
- (obj_desc->mutex.os_mutex == ACPI_GLOBAL_LOCK)) {
- /*
- * The mutex is already owned by this thread,
- * just increment the acquisition depth
- */
- obj_desc->mutex.acquisition_depth++;
- return_ACPI_STATUS(AE_OK);
- }
+ if (obj_desc->mutex.os_mutex == acpi_gbl_global_lock_mutex) {
+ status =
+ acpi_ev_acquire_global_lock((u16) time_desc->integer.value);
+ } else {
+ status = acpi_ex_system_wait_mutex(obj_desc->mutex.os_mutex,
+ (u16) time_desc->integer.
+ value);
}
- /* Acquire the mutex, wait if necessary */
-
- status = acpi_ex_system_acquire_mutex(time_desc, obj_desc);
if (ACPI_FAILURE(status)) {
/* Includes failure from a timeout on time_desc */
@@ -201,7 +202,7 @@ acpi_ex_acquire_mutex(union acpi_operand_object *time_desc,
/* Have the mutex: update mutex and walk info and save the sync_level */
- obj_desc->mutex.owner_thread = walk_state->thread;
+ obj_desc->mutex.owner_thread_id = acpi_os_get_thread_id();
obj_desc->mutex.acquisition_depth = 1;
obj_desc->mutex.original_sync_level =
walk_state->thread->current_sync_level;
@@ -211,7 +212,6 @@ acpi_ex_acquire_mutex(union acpi_operand_object *time_desc,
/* Link the mutex to the current thread for force-unlock at method exit */
acpi_ex_link_mutex(obj_desc, walk_state->thread);
-
return_ACPI_STATUS(AE_OK);
}
@@ -232,7 +232,7 @@ acpi_status
acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
struct acpi_walk_state *walk_state)
{
- acpi_status status;
+ acpi_status status = AE_OK;
ACPI_FUNCTION_TRACE(ex_release_mutex);
@@ -242,14 +242,14 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
/* The mutex must have been previously acquired in order to release it */
- if (!obj_desc->mutex.owner_thread) {
+ if (!obj_desc->mutex.owner_thread_id) {
ACPI_ERROR((AE_INFO,
"Cannot release Mutex [%4.4s], not acquired",
acpi_ut_get_node_name(obj_desc->mutex.node)));
return_ACPI_STATUS(AE_AML_MUTEX_NOT_ACQUIRED);
}
- /* Sanity check -- we must have a valid thread ID */
+ /* Sanity check: we must have a valid thread ID */
if (!walk_state->thread) {
ACPI_ERROR((AE_INFO,
@@ -262,20 +262,20 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
* The Mutex is owned, but this thread must be the owner.
* Special case for Global Lock, any thread can release
*/
- if ((obj_desc->mutex.owner_thread->thread_id !=
+ if ((obj_desc->mutex.owner_thread_id !=
walk_state->thread->thread_id)
- && (obj_desc->mutex.os_mutex != ACPI_GLOBAL_LOCK)) {
+ && (obj_desc->mutex.os_mutex != acpi_gbl_global_lock_mutex)) {
ACPI_ERROR((AE_INFO,
"Thread %lX cannot release Mutex [%4.4s] acquired by thread %lX",
(unsigned long)walk_state->thread->thread_id,
acpi_ut_get_node_name(obj_desc->mutex.node),
- (unsigned long)obj_desc->mutex.owner_thread->thread_id));
+ (unsigned long)obj_desc->mutex.owner_thread_id));
return_ACPI_STATUS(AE_AML_NOT_OWNER);
}
/*
- * The sync level of the mutex must be less than or
- * equal to the current sync level
+ * The sync level of the mutex must be less than or equal to the current
+ * sync level
*/
if (obj_desc->mutex.sync_level > walk_state->thread->current_sync_level) {
ACPI_ERROR((AE_INFO,
@@ -296,15 +296,19 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
/* Unlink the mutex from the owner's list */
- acpi_ex_unlink_mutex(obj_desc);
+ acpi_ex_unlink_mutex(obj_desc, walk_state->thread);
- /* Release the mutex */
+ /* Release the mutex, special case for Global Lock */
- status = acpi_ex_system_release_mutex(obj_desc);
+ if (obj_desc->mutex.os_mutex == acpi_gbl_global_lock_mutex) {
+ status = acpi_ev_release_global_lock();
+ } else {
+ acpi_os_release_mutex(obj_desc->mutex.os_mutex);
+ }
- /* Update the mutex and walk state, restore sync_level before acquire */
+ /* Update the mutex and restore sync_level */
- obj_desc->mutex.owner_thread = NULL;
+ obj_desc->mutex.owner_thread_id = ACPI_MUTEX_NOT_ACQUIRED;
walk_state->thread->current_sync_level =
obj_desc->mutex.original_sync_level;
@@ -321,39 +325,49 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
*
* DESCRIPTION: Release all mutexes held by this thread
*
+ * NOTE: This function is called as the thread is exiting the interpreter.
+ * Mutexes are not released when an individual control method is exited, but
+ * only when the parent thread actually exits the interpreter. This allows one
+ * method to acquire a mutex, and a different method to release it, as long as
+ * this is performed underneath a single parent control method.
+ *
******************************************************************************/
void acpi_ex_release_all_mutexes(struct acpi_thread_state *thread)
{
union acpi_operand_object *next = thread->acquired_mutex_list;
- union acpi_operand_object *this;
- acpi_status status;
+ union acpi_operand_object *obj_desc;
ACPI_FUNCTION_ENTRY();
/* Traverse the list of owned mutexes, releasing each one */
while (next) {
- this = next;
- next = this->mutex.next;
+ obj_desc = next;
+ next = obj_desc->mutex.next;
+
+ obj_desc->mutex.prev = NULL;
+ obj_desc->mutex.next = NULL;
+ obj_desc->mutex.acquisition_depth = 0;
+
+ /* Release the mutex, special case for Global Lock */
- this->mutex.acquisition_depth = 1;
- this->mutex.prev = NULL;
- this->mutex.next = NULL;
+ if (obj_desc->mutex.os_mutex == acpi_gbl_global_lock_mutex) {
- /* Release the mutex */
+ /* Ignore errors */
- status = acpi_ex_system_release_mutex(this);
- if (ACPI_FAILURE(status)) {
- continue;
+ (void)acpi_ev_release_global_lock();
+ } else {
+ acpi_os_release_mutex(obj_desc->mutex.os_mutex);
}
/* Mark mutex unowned */
- this->mutex.owner_thread = NULL;
+ obj_desc->mutex.owner_thread_id = ACPI_MUTEX_NOT_ACQUIRED;
/* Update Thread sync_level (Last mutex is the important one) */
- thread->current_sync_level = this->mutex.original_sync_level;
+ thread->current_sync_level =
+ obj_desc->mutex.original_sync_level;
}
}
diff --git a/drivers/acpi/executer/exnames.c b/drivers/acpi/executer/exnames.c
index d3d70364626..1ee4fb1175c 100644
--- a/drivers/acpi/executer/exnames.c
+++ b/drivers/acpi/executer/exnames.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exoparg1.c b/drivers/acpi/executer/exoparg1.c
index 6374d8be88e..252f10acbbc 100644
--- a/drivers/acpi/executer/exoparg1.c
+++ b/drivers/acpi/executer/exoparg1.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -104,9 +104,7 @@ acpi_status acpi_ex_opcode_0A_0T_1R(struct acpi_walk_state *walk_state)
status = AE_NO_MEMORY;
goto cleanup;
}
-#if ACPI_MACHINE_WIDTH != 16
return_desc->integer.value = acpi_os_get_timer();
-#endif
break;
default: /* Unknown opcode */
diff --git a/drivers/acpi/executer/exoparg2.c b/drivers/acpi/executer/exoparg2.c
index 7d2cbc11316..17e652e6537 100644
--- a/drivers/acpi/executer/exoparg2.c
+++ b/drivers/acpi/executer/exoparg2.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exoparg3.c b/drivers/acpi/executer/exoparg3.c
index e2d945dfd50..7fe67cf82ce 100644
--- a/drivers/acpi/executer/exoparg3.c
+++ b/drivers/acpi/executer/exoparg3.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exoparg6.c b/drivers/acpi/executer/exoparg6.c
index f0c0ba6eb40..bd80a9cb3d6 100644
--- a/drivers/acpi/executer/exoparg6.c
+++ b/drivers/acpi/executer/exoparg6.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exprep.c b/drivers/acpi/executer/exprep.c
index 44d064f427b..a6696621ff1 100644
--- a/drivers/acpi/executer/exprep.c
+++ b/drivers/acpi/executer/exprep.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exregion.c b/drivers/acpi/executer/exregion.c
index 3cc97ba48b3..2e9ce94798c 100644
--- a/drivers/acpi/executer/exregion.c
+++ b/drivers/acpi/executer/exregion.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -155,16 +155,15 @@ acpi_ex_system_memory_space_handler(u32 function,
/* Create a new mapping starting at the address given */
- status = acpi_os_map_memory(address, window_size,
- (void **)&mem_info->
- mapped_logical_address);
- if (ACPI_FAILURE(status)) {
+ mem_info->mapped_logical_address =
+ acpi_os_map_memory((acpi_native_uint) address, window_size);
+ if (!mem_info->mapped_logical_address) {
ACPI_ERROR((AE_INFO,
"Could not map memory at %8.8X%8.8X, size %X",
ACPI_FORMAT_UINT64(address),
(u32) window_size));
mem_info->mapped_length = 0;
- return_ACPI_STATUS(status);
+ return_ACPI_STATUS(AE_NO_MEMORY);
}
/* Save the physical address and mapping size */
@@ -210,11 +209,10 @@ acpi_ex_system_memory_space_handler(u32 function,
*value = (acpi_integer) ACPI_GET32(logical_addr_ptr);
break;
-#if ACPI_MACHINE_WIDTH != 16
case 64:
*value = (acpi_integer) ACPI_GET64(logical_addr_ptr);
break;
-#endif
+
default:
/* bit_width was already validated */
break;
@@ -236,11 +234,9 @@ acpi_ex_system_memory_space_handler(u32 function,
ACPI_SET32(logical_addr_ptr) = (u32) * value;
break;
-#if ACPI_MACHINE_WIDTH != 16
case 64:
ACPI_SET64(logical_addr_ptr) = (u64) * value;
break;
-#endif
default:
/* bit_width was already validated */
diff --git a/drivers/acpi/executer/exresnte.c b/drivers/acpi/executer/exresnte.c
index 3089b05a136..2b3a01cc492 100644
--- a/drivers/acpi/executer/exresnte.c
+++ b/drivers/acpi/executer/exresnte.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exresolv.c b/drivers/acpi/executer/exresolv.c
index 6499de87801..6c64e55dab0 100644
--- a/drivers/acpi/executer/exresolv.c
+++ b/drivers/acpi/executer/exresolv.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -141,7 +141,7 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr,
acpi_status status = AE_OK;
union acpi_operand_object *stack_desc;
void *temp_node;
- union acpi_operand_object *obj_desc;
+ union acpi_operand_object *obj_desc = NULL;
u16 opcode;
ACPI_FUNCTION_TRACE(ex_resolve_object_to_value);
@@ -299,8 +299,6 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr,
status = acpi_ds_get_package_arguments(stack_desc);
break;
- /* These cases may never happen here, but just in case.. */
-
case ACPI_TYPE_BUFFER_FIELD:
case ACPI_TYPE_LOCAL_REGION_FIELD:
case ACPI_TYPE_LOCAL_BANK_FIELD:
@@ -314,6 +312,10 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr,
status =
acpi_ex_read_data_from_field(walk_state, stack_desc,
&obj_desc);
+
+ /* Remove a reference to the original operand, then override */
+
+ acpi_ut_remove_reference(*stack_ptr);
*stack_ptr = (void *)obj_desc;
break;
diff --git a/drivers/acpi/executer/exresop.c b/drivers/acpi/executer/exresop.c
index 4c93d097233..ba761862a59 100644
--- a/drivers/acpi/executer/exresop.c
+++ b/drivers/acpi/executer/exresop.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -611,22 +611,20 @@ acpi_ex_resolve_operands(u16 opcode,
}
goto next_operand;
- case ARGI_REGION_OR_FIELD:
+ case ARGI_REGION_OR_BUFFER: /* Used by Load() only */
- /* Need an operand of type REGION or a FIELD in a region */
+ /* Need an operand of type REGION or a BUFFER (which could be a resolved region field) */
switch (ACPI_GET_OBJECT_TYPE(obj_desc)) {
+ case ACPI_TYPE_BUFFER:
case ACPI_TYPE_REGION:
- case ACPI_TYPE_LOCAL_REGION_FIELD:
- case ACPI_TYPE_LOCAL_BANK_FIELD:
- case ACPI_TYPE_LOCAL_INDEX_FIELD:
/* Valid operand */
break;
default:
ACPI_ERROR((AE_INFO,
- "Needed [Region/RegionField], found [%s] %p",
+ "Needed [Region/Buffer], found [%s] %p",
acpi_ut_get_object_type_name
(obj_desc), obj_desc));
diff --git a/drivers/acpi/executer/exstore.c b/drivers/acpi/executer/exstore.c
index 0456405ba01..f4b69a63782 100644
--- a/drivers/acpi/executer/exstore.c
+++ b/drivers/acpi/executer/exstore.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exstoren.c b/drivers/acpi/executer/exstoren.c
index 591aaf0e18b..1d622c625c6 100644
--- a/drivers/acpi/executer/exstoren.c
+++ b/drivers/acpi/executer/exstoren.c
@@ -7,7 +7,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exstorob.c b/drivers/acpi/executer/exstorob.c
index 99ebe5adfcd..8233d40178e 100644
--- a/drivers/acpi/executer/exstorob.c
+++ b/drivers/acpi/executer/exstorob.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exsystem.c b/drivers/acpi/executer/exsystem.c
index 28aef3e69ec..9460baff303 100644
--- a/drivers/acpi/executer/exsystem.c
+++ b/drivers/acpi/executer/exsystem.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -66,7 +66,6 @@ ACPI_MODULE_NAME("exsystem")
acpi_status acpi_ex_system_wait_semaphore(acpi_semaphore semaphore, u16 timeout)
{
acpi_status status;
- acpi_status status2;
ACPI_FUNCTION_TRACE(ex_system_wait_semaphore);
@@ -79,7 +78,7 @@ acpi_status acpi_ex_system_wait_semaphore(acpi_semaphore semaphore, u16 timeout)
/* We must wait, so unlock the interpreter */
- acpi_ex_exit_interpreter();
+ acpi_ex_relinquish_interpreter();
status = acpi_os_wait_semaphore(semaphore, 1, timeout);
@@ -89,13 +88,7 @@ acpi_status acpi_ex_system_wait_semaphore(acpi_semaphore semaphore, u16 timeout)
/* Reacquire the interpreter */
- status2 = acpi_ex_enter_interpreter();
- if (ACPI_FAILURE(status2)) {
-
- /* Report fatal error, could not acquire interpreter */
-
- return_ACPI_STATUS(status2);
- }
+ acpi_ex_reacquire_interpreter();
}
return_ACPI_STATUS(status);
@@ -119,7 +112,6 @@ acpi_status acpi_ex_system_wait_semaphore(acpi_semaphore semaphore, u16 timeout)
acpi_status acpi_ex_system_wait_mutex(acpi_mutex mutex, u16 timeout)
{
acpi_status status;
- acpi_status status2;
ACPI_FUNCTION_TRACE(ex_system_wait_mutex);
@@ -132,7 +124,7 @@ acpi_status acpi_ex_system_wait_mutex(acpi_mutex mutex, u16 timeout)
/* We must wait, so unlock the interpreter */
- acpi_ex_exit_interpreter();
+ acpi_ex_relinquish_interpreter();
status = acpi_os_acquire_mutex(mutex, timeout);
@@ -142,13 +134,7 @@ acpi_status acpi_ex_system_wait_mutex(acpi_mutex mutex, u16 timeout)
/* Reacquire the interpreter */
- status2 = acpi_ex_enter_interpreter();
- if (ACPI_FAILURE(status2)) {
-
- /* Report fatal error, could not acquire interpreter */
-
- return_ACPI_STATUS(status2);
- }
+ acpi_ex_reacquire_interpreter();
}
return_ACPI_STATUS(status);
@@ -209,96 +195,18 @@ acpi_status acpi_ex_system_do_stall(u32 how_long)
acpi_status acpi_ex_system_do_suspend(acpi_integer how_long)
{
- acpi_status status;
-
ACPI_FUNCTION_ENTRY();
/* Since this thread will sleep, we must release the interpreter */
- acpi_ex_exit_interpreter();
+ acpi_ex_relinquish_interpreter();
acpi_os_sleep(how_long);
/* And now we must get the interpreter again */
- status = acpi_ex_enter_interpreter();
- return (status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ex_system_acquire_mutex
- *
- * PARAMETERS: time_desc - Maximum time to wait for the mutex
- * obj_desc - The object descriptor for this op
- *
- * RETURN: Status
- *
- * DESCRIPTION: Provides an access point to perform synchronization operations
- * within the AML. This function will cause a lock to be generated
- * for the Mutex pointed to by obj_desc.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_ex_system_acquire_mutex(union acpi_operand_object * time_desc,
- union acpi_operand_object * obj_desc)
-{
- acpi_status status = AE_OK;
-
- ACPI_FUNCTION_TRACE_PTR(ex_system_acquire_mutex, obj_desc);
-
- if (!obj_desc) {
- return_ACPI_STATUS(AE_BAD_PARAMETER);
- }
-
- /* Support for the _GL_ Mutex object -- go get the global lock */
-
- if (obj_desc->mutex.os_mutex == ACPI_GLOBAL_LOCK) {
- status =
- acpi_ev_acquire_global_lock((u16) time_desc->integer.value);
- return_ACPI_STATUS(status);
- }
-
- status = acpi_ex_system_wait_mutex(obj_desc->mutex.os_mutex,
- (u16) time_desc->integer.value);
- return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ex_system_release_mutex
- *
- * PARAMETERS: obj_desc - The object descriptor for this op
- *
- * RETURN: Status
- *
- * DESCRIPTION: Provides an access point to perform synchronization operations
- * within the AML. This operation is a request to release a
- * previously acquired Mutex. If the Mutex variable is set then
- * it will be decremented.
- *
- ******************************************************************************/
-
-acpi_status acpi_ex_system_release_mutex(union acpi_operand_object *obj_desc)
-{
- acpi_status status = AE_OK;
-
- ACPI_FUNCTION_TRACE(ex_system_release_mutex);
-
- if (!obj_desc) {
- return_ACPI_STATUS(AE_BAD_PARAMETER);
- }
-
- /* Support for the _GL_ Mutex object -- release the global lock */
-
- if (obj_desc->mutex.os_mutex == ACPI_GLOBAL_LOCK) {
- status = acpi_ev_release_global_lock();
- return_ACPI_STATUS(status);
- }
-
- acpi_os_release_mutex(obj_desc->mutex.os_mutex);
- return_ACPI_STATUS(AE_OK);
+ acpi_ex_reacquire_interpreter();
+ return (AE_OK);
}
/*******************************************************************************
@@ -314,7 +222,7 @@ acpi_status acpi_ex_system_release_mutex(union acpi_operand_object *obj_desc)
*
******************************************************************************/
-acpi_status acpi_ex_system_signal_event(union acpi_operand_object *obj_desc)
+acpi_status acpi_ex_system_signal_event(union acpi_operand_object * obj_desc)
{
acpi_status status = AE_OK;
diff --git a/drivers/acpi/executer/exutils.c b/drivers/acpi/executer/exutils.c
index 982c8b65876..6b0aeccbb69 100644
--- a/drivers/acpi/executer/exutils.c
+++ b/drivers/acpi/executer/exutils.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -76,14 +76,15 @@ static u32 acpi_ex_digits_needed(acpi_integer value, u32 base);
*
* PARAMETERS: None
*
- * RETURN: Status
+ * RETURN: None
*
- * DESCRIPTION: Enter the interpreter execution region. Failure to enter
- * the interpreter region is a fatal system error
+ * DESCRIPTION: Enter the interpreter execution region. Failure to enter
+ * the interpreter region is a fatal system error. Used in
+ * conjunction with exit_interpreter.
*
******************************************************************************/
-acpi_status acpi_ex_enter_interpreter(void)
+void acpi_ex_enter_interpreter(void)
{
acpi_status status;
@@ -91,31 +92,55 @@ acpi_status acpi_ex_enter_interpreter(void)
status = acpi_ut_acquire_mutex(ACPI_MTX_INTERPRETER);
if (ACPI_FAILURE(status)) {
- ACPI_ERROR((AE_INFO, "Could not acquire interpreter mutex"));
+ ACPI_ERROR((AE_INFO,
+ "Could not acquire AML Interpreter mutex"));
}
- return_ACPI_STATUS(status);
+ return_VOID;
}
/*******************************************************************************
*
- * FUNCTION: acpi_ex_exit_interpreter
+ * FUNCTION: acpi_ex_reacquire_interpreter
*
* PARAMETERS: None
*
* RETURN: None
*
- * DESCRIPTION: Exit the interpreter execution region
+ * DESCRIPTION: Reacquire the interpreter execution region from within the
+ * interpreter code. Failure to enter the interpreter region is a
+ * fatal system error. Used in conjuction with
+ * relinquish_interpreter
+ *
+ ******************************************************************************/
+
+void acpi_ex_reacquire_interpreter(void)
+{
+ ACPI_FUNCTION_TRACE(ex_reacquire_interpreter);
+
+ /*
+ * If the global serialized flag is set, do not release the interpreter,
+ * since it was not actually released by acpi_ex_relinquish_interpreter.
+ * This forces the interpreter to be single threaded.
+ */
+ if (!acpi_gbl_all_methods_serialized) {
+ acpi_ex_enter_interpreter();
+ }
+
+ return_VOID;
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_exit_interpreter
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: None
*
- * Cases where the interpreter is unlocked:
- * 1) Completion of the execution of a control method
- * 2) Method blocked on a Sleep() AML opcode
- * 3) Method blocked on an Acquire() AML opcode
- * 4) Method blocked on a Wait() AML opcode
- * 5) Method blocked to acquire the global lock
- * 6) Method blocked to execute a serialized control method that is
- * already executing
- * 7) About to invoke a user-installed opregion handler
+ * DESCRIPTION: Exit the interpreter execution region. This is the top level
+ * routine used to exit the interpreter when all processing has
+ * been completed.
*
******************************************************************************/
@@ -127,7 +152,46 @@ void acpi_ex_exit_interpreter(void)
status = acpi_ut_release_mutex(ACPI_MTX_INTERPRETER);
if (ACPI_FAILURE(status)) {
- ACPI_ERROR((AE_INFO, "Could not release interpreter mutex"));
+ ACPI_ERROR((AE_INFO,
+ "Could not release AML Interpreter mutex"));
+ }
+
+ return_VOID;
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_relinquish_interpreter
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Exit the interpreter execution region, from within the
+ * interpreter - before attempting an operation that will possibly
+ * block the running thread.
+ *
+ * Cases where the interpreter is unlocked internally
+ * 1) Method to be blocked on a Sleep() AML opcode
+ * 2) Method to be blocked on an Acquire() AML opcode
+ * 3) Method to be blocked on a Wait() AML opcode
+ * 4) Method to be blocked to acquire the global lock
+ * 5) Method to be blocked waiting to execute a serialized control method
+ * that is currently executing
+ * 6) About to invoke a user-installed opregion handler
+ *
+ ******************************************************************************/
+
+void acpi_ex_relinquish_interpreter(void)
+{
+ ACPI_FUNCTION_TRACE(ex_relinquish_interpreter);
+
+ /*
+ * If the global serialized flag is set, do not release the interpreter.
+ * This forces the interpreter to be single threaded.
+ */
+ if (!acpi_gbl_all_methods_serialized) {
+ acpi_ex_exit_interpreter();
}
return_VOID;
@@ -141,8 +205,8 @@ void acpi_ex_exit_interpreter(void)
*
* RETURN: none
*
- * DESCRIPTION: Truncate a number to 32-bits if the currently executing method
- * belongs to a 32-bit ACPI table.
+ * DESCRIPTION: Truncate an ACPI Integer to 32 bits if the execution mode is
+ * 32-bit, as determined by the revision of the DSDT.
*
******************************************************************************/
diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c
index f305a826ca2..ec655c53949 100644
--- a/drivers/acpi/fan.c
+++ b/drivers/acpi/fan.c
@@ -36,23 +36,22 @@
#define ACPI_FAN_COMPONENT 0x00200000
#define ACPI_FAN_CLASS "fan"
-#define ACPI_FAN_DRIVER_NAME "ACPI Fan Driver"
#define ACPI_FAN_FILE_STATE "state"
#define _COMPONENT ACPI_FAN_COMPONENT
-ACPI_MODULE_NAME("acpi_fan")
+ACPI_MODULE_NAME("fan");
- MODULE_AUTHOR("Paul Diefenbaugh");
-MODULE_DESCRIPTION(ACPI_FAN_DRIVER_NAME);
+MODULE_AUTHOR("Paul Diefenbaugh");
+MODULE_DESCRIPTION("ACPI Fan Driver");
MODULE_LICENSE("GPL");
static int acpi_fan_add(struct acpi_device *device);
static int acpi_fan_remove(struct acpi_device *device, int type);
-static int acpi_fan_suspend(struct acpi_device *device, int state);
-static int acpi_fan_resume(struct acpi_device *device, int state);
+static int acpi_fan_suspend(struct acpi_device *device, pm_message_t state);
+static int acpi_fan_resume(struct acpi_device *device);
static struct acpi_driver acpi_fan_driver = {
- .name = ACPI_FAN_DRIVER_NAME,
+ .name = "fan",
.class = ACPI_FAN_CLASS,
.ids = "PNP0C0B",
.ops = {
@@ -237,7 +236,7 @@ static int acpi_fan_remove(struct acpi_device *device, int type)
return 0;
}
-static int acpi_fan_suspend(struct acpi_device *device, int state)
+static int acpi_fan_suspend(struct acpi_device *device, pm_message_t state)
{
if (!device)
return -EINVAL;
@@ -247,7 +246,7 @@ static int acpi_fan_suspend(struct acpi_device *device, int state)
return AE_OK;
}
-static int acpi_fan_resume(struct acpi_device *device, int state)
+static int acpi_fan_resume(struct acpi_device *device)
{
int result = 0;
int power_state = 0;
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index 8a0324b43e5..4334c208841 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -86,129 +86,6 @@ static int acpi_find_bridge_device(struct device *dev, acpi_handle * handle)
return ret;
}
-/* Get PCI root bridge's handle from its segment and bus number */
-struct acpi_find_pci_root {
- unsigned int seg;
- unsigned int bus;
- acpi_handle handle;
-};
-
-static acpi_status
-do_root_bridge_busnr_callback(struct acpi_resource *resource, void *data)
-{
- unsigned long *busnr = data;
- struct acpi_resource_address64 address;
-
- if (resource->type != ACPI_RESOURCE_TYPE_ADDRESS16 &&
- resource->type != ACPI_RESOURCE_TYPE_ADDRESS32 &&
- resource->type != ACPI_RESOURCE_TYPE_ADDRESS64)
- return AE_OK;
-
- acpi_resource_to_address64(resource, &address);
- if ((address.address_length > 0) &&
- (address.resource_type == ACPI_BUS_NUMBER_RANGE))
- *busnr = address.minimum;
-
- return AE_OK;
-}
-
-static int get_root_bridge_busnr(acpi_handle handle)
-{
- acpi_status status;
- unsigned long bus, bbn;
- struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
-
- acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
-
- status = acpi_evaluate_integer(handle, METHOD_NAME__BBN, NULL,
- &bbn);
- if (status == AE_NOT_FOUND) {
- /* Assume bus = 0 */
- printk(KERN_INFO PREFIX
- "Assume root bridge [%s] bus is 0\n",
- (char *)buffer.pointer);
- status = AE_OK;
- bbn = 0;
- }
- if (ACPI_FAILURE(status)) {
- bbn = -ENODEV;
- goto exit;
- }
- if (bbn > 0)
- goto exit;
-
- /* _BBN in some systems return 0 for all root bridges */
- bus = -1;
- status = acpi_walk_resources(handle, METHOD_NAME__CRS,
- do_root_bridge_busnr_callback, &bus);
- /* If _CRS failed, we just use _BBN */
- if (ACPI_FAILURE(status) || (bus == -1))
- goto exit;
- /* We select _CRS */
- if (bbn != bus) {
- printk(KERN_INFO PREFIX
- "_BBN and _CRS returns different value for %s. Select _CRS\n",
- (char *)buffer.pointer);
- bbn = bus;
- }
- exit:
- kfree(buffer.pointer);
- return (int)bbn;
-}
-
-static acpi_status
-find_pci_rootbridge(acpi_handle handle, u32 lvl, void *context, void **rv)
-{
- struct acpi_find_pci_root *find = (struct acpi_find_pci_root *)context;
- unsigned long seg, bus;
- acpi_status status;
- int tmp;
- struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
-
- acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
-
- status = acpi_evaluate_integer(handle, METHOD_NAME__SEG, NULL, &seg);
- if (status == AE_NOT_FOUND) {
- /* Assume seg = 0 */
- status = AE_OK;
- seg = 0;
- }
- if (ACPI_FAILURE(status)) {
- status = AE_CTRL_DEPTH;
- goto exit;
- }
-
- tmp = get_root_bridge_busnr(handle);
- if (tmp < 0) {
- printk(KERN_ERR PREFIX
- "Find root bridge failed for %s\n",
- (char *)buffer.pointer);
- status = AE_CTRL_DEPTH;
- goto exit;
- }
- bus = tmp;
-
- if (seg == find->seg && bus == find->bus)
- {
- find->handle = handle;
- status = AE_CTRL_TERMINATE;
- }
- else
- status = AE_OK;
- exit:
- kfree(buffer.pointer);
- return status;
-}
-
-acpi_handle acpi_get_pci_rootbridge_handle(unsigned int seg, unsigned int bus)
-{
- struct acpi_find_pci_root find = { seg, bus, NULL };
-
- acpi_get_devices(PCI_ROOT_HID_STRING, find_pci_rootbridge, &find, NULL);
- return find.handle;
-}
-EXPORT_SYMBOL_GPL(acpi_get_pci_rootbridge_handle);
-
/* Get device's handler per its address under its parent */
struct acpi_find_child {
acpi_handle handle;
@@ -364,3 +241,65 @@ static int __init init_acpi_device_notify(void)
}
arch_initcall(init_acpi_device_notify);
+
+
+#if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE)
+
+/* Every ACPI platform has a mc146818 compatible "cmos rtc". Here we find
+ * its device node and pass extra config data. This helps its driver use
+ * capabilities that the now-obsolete mc146818 didn't have, and informs it
+ * that this board's RTC is wakeup-capable (per ACPI spec).
+ */
+#include <linux/mc146818rtc.h>
+
+static struct cmos_rtc_board_info rtc_info;
+
+
+/* PNP devices are registered in a subsys_initcall();
+ * ACPI specifies the PNP IDs to use.
+ */
+#include <linux/pnp.h>
+
+static int __init pnp_match(struct device *dev, void *data)
+{
+ static const char *ids[] = { "PNP0b00", "PNP0b01", "PNP0b02", };
+ struct pnp_dev *pnp = to_pnp_dev(dev);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ids); i++) {
+ if (compare_pnp_id(pnp->id, ids[i]) != 0)
+ return 1;
+ }
+ return 0;
+}
+
+static struct device *__init get_rtc_dev(void)
+{
+ return bus_find_device(&pnp_bus_type, NULL, NULL, pnp_match);
+}
+
+static int __init acpi_rtc_init(void)
+{
+ struct device *dev = get_rtc_dev();
+
+ if (dev) {
+ rtc_info.rtc_day_alarm = acpi_gbl_FADT.day_alarm;
+ rtc_info.rtc_mon_alarm = acpi_gbl_FADT.month_alarm;
+ rtc_info.rtc_century = acpi_gbl_FADT.century;
+
+ /* NOTE: acpi_gbl_FADT->rtcs4 is NOT currently useful */
+
+ dev->platform_data = &rtc_info;
+
+ /* RTC always wakes from S1/S2/S3, and often S4/STD */
+ device_init_wakeup(dev, 1);
+
+ put_device(dev);
+ } else
+ pr_debug("ACPI: RTC unavailable?\n");
+ return 0;
+}
+/* do this between RTC subsys_initcall() and rtc_cmos driver_initcall() */
+fs_initcall(acpi_rtc_init);
+
+#endif
diff --git a/drivers/acpi/hardware/hwacpi.c b/drivers/acpi/hardware/hwacpi.c
index de50fab2a91..6031ca13dd2 100644
--- a/drivers/acpi/hardware/hwacpi.c
+++ b/drivers/acpi/hardware/hwacpi.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -49,41 +49,6 @@ ACPI_MODULE_NAME("hwacpi")
/******************************************************************************
*
- * FUNCTION: acpi_hw_initialize
- *
- * PARAMETERS: None
- *
- * RETURN: Status
- *
- * DESCRIPTION: Initialize and validate the various ACPI registers defined in
- * the FADT.
- *
- ******************************************************************************/
-acpi_status acpi_hw_initialize(void)
-{
- acpi_status status;
-
- ACPI_FUNCTION_TRACE(hw_initialize);
-
- /* We must have the ACPI tables by the time we get here */
-
- if (!acpi_gbl_FADT) {
- ACPI_ERROR((AE_INFO, "No FADT is present"));
- return_ACPI_STATUS(AE_NO_ACPI_TABLES);
- }
-
- /* Sanity check the FADT for valid values */
-
- status = acpi_ut_validate_fadt();
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- return_ACPI_STATUS(AE_OK);
-}
-
-/******************************************************************************
- *
* FUNCTION: acpi_hw_set_mode
*
* PARAMETERS: Mode - SYS_MODE_ACPI or SYS_MODE_LEGACY
@@ -93,7 +58,6 @@ acpi_status acpi_hw_initialize(void)
* DESCRIPTION: Transitions the system into the requested mode.
*
******************************************************************************/
-
acpi_status acpi_hw_set_mode(u32 mode)
{
@@ -106,7 +70,7 @@ acpi_status acpi_hw_set_mode(u32 mode)
* ACPI 2.0 clarified that if SMI_CMD in FADT is zero,
* system does not support mode transition.
*/
- if (!acpi_gbl_FADT->smi_cmd) {
+ if (!acpi_gbl_FADT.smi_command) {
ACPI_ERROR((AE_INFO,
"No SMI_CMD in FADT, mode transition failed"));
return_ACPI_STATUS(AE_NO_HARDWARE_RESPONSE);
@@ -119,7 +83,7 @@ acpi_status acpi_hw_set_mode(u32 mode)
* we make sure both the numbers are zero to determine these
* transitions are not supported.
*/
- if (!acpi_gbl_FADT->acpi_enable && !acpi_gbl_FADT->acpi_disable) {
+ if (!acpi_gbl_FADT.acpi_enable && !acpi_gbl_FADT.acpi_disable) {
ACPI_ERROR((AE_INFO,
"No ACPI mode transition supported in this system (enable/disable both zero)"));
return_ACPI_STATUS(AE_OK);
@@ -130,9 +94,8 @@ acpi_status acpi_hw_set_mode(u32 mode)
/* BIOS should have disabled ALL fixed and GP events */
- status = acpi_os_write_port(acpi_gbl_FADT->smi_cmd,
- (u32) acpi_gbl_FADT->acpi_enable,
- 8);
+ status = acpi_os_write_port(acpi_gbl_FADT.smi_command,
+ (u32) acpi_gbl_FADT.acpi_enable, 8);
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Attempting to enable ACPI mode\n"));
break;
@@ -143,8 +106,8 @@ acpi_status acpi_hw_set_mode(u32 mode)
* BIOS should clear all fixed status bits and restore fixed event
* enable bits to default
*/
- status = acpi_os_write_port(acpi_gbl_FADT->smi_cmd,
- (u32) acpi_gbl_FADT->acpi_disable,
+ status = acpi_os_write_port(acpi_gbl_FADT.smi_command,
+ (u32) acpi_gbl_FADT.acpi_disable,
8);
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Attempting to enable Legacy (non-ACPI) mode\n"));
@@ -204,12 +167,11 @@ u32 acpi_hw_get_mode(void)
* ACPI 2.0 clarified that if SMI_CMD in FADT is zero,
* system does not support mode transition.
*/
- if (!acpi_gbl_FADT->smi_cmd) {
+ if (!acpi_gbl_FADT.smi_command) {
return_UINT32(ACPI_SYS_MODE_ACPI);
}
- status =
- acpi_get_register(ACPI_BITREG_SCI_ENABLE, &value, ACPI_MTX_LOCK);
+ status = acpi_get_register(ACPI_BITREG_SCI_ENABLE, &value);
if (ACPI_FAILURE(status)) {
return_UINT32(ACPI_SYS_MODE_LEGACY);
}
diff --git a/drivers/acpi/hardware/hwgpe.c b/drivers/acpi/hardware/hwgpe.c
index 608a3a60ee1..117a05cadaa 100644
--- a/drivers/acpi/hardware/hwgpe.c
+++ b/drivers/acpi/hardware/hwgpe.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -105,14 +105,20 @@ acpi_hw_write_gpe_enable_reg(struct acpi_gpe_event_info *gpe_event_info)
acpi_status acpi_hw_clear_gpe(struct acpi_gpe_event_info * gpe_event_info)
{
acpi_status status;
+ u8 register_bit;
ACPI_FUNCTION_ENTRY();
+ register_bit = (u8)
+ (1 <<
+ (gpe_event_info->gpe_number -
+ gpe_event_info->register_info->base_gpe_number));
+
/*
* Write a one to the appropriate bit in the status register to
* clear this GPE.
*/
- status = acpi_hw_low_level_write(8, gpe_event_info->register_bit,
+ status = acpi_hw_low_level_write(8, register_bit,
&gpe_event_info->register_info->
status_address);
@@ -155,7 +161,10 @@ acpi_hw_get_gpe_status(struct acpi_gpe_event_info * gpe_event_info,
/* Get the register bitmask for this GPE */
- register_bit = gpe_event_info->register_bit;
+ register_bit = (u8)
+ (1 <<
+ (gpe_event_info->gpe_number -
+ gpe_event_info->register_info->base_gpe_number));
/* GPE currently enabled? (enabled for runtime?) */
diff --git a/drivers/acpi/hardware/hwregs.c b/drivers/acpi/hardware/hwregs.c
index fa58c1edce1..1d371fa663f 100644
--- a/drivers/acpi/hardware/hwregs.c
+++ b/drivers/acpi/hardware/hwregs.c
@@ -7,7 +7,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -54,17 +54,15 @@ ACPI_MODULE_NAME("hwregs")
*
* FUNCTION: acpi_hw_clear_acpi_status
*
- * PARAMETERS: Flags - Lock the hardware or not
+ * PARAMETERS: None
*
- * RETURN: none
+ * RETURN: None
*
* DESCRIPTION: Clears all fixed and general purpose status bits
* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
*
- * NOTE: TBD: Flags parameter is obsolete, to be removed
- *
******************************************************************************/
-acpi_status acpi_hw_clear_acpi_status(u32 flags)
+acpi_status acpi_hw_clear_acpi_status(void)
{
acpi_status status;
acpi_cpu_flags lock_flags = 0;
@@ -73,7 +71,7 @@ acpi_status acpi_hw_clear_acpi_status(u32 flags)
ACPI_DEBUG_PRINT((ACPI_DB_IO, "About to write %04X to %04X\n",
ACPI_BITMASK_ALL_FIXED_STATUS,
- (u16) acpi_gbl_FADT->xpm1a_evt_blk.address));
+ (u16) acpi_gbl_FADT.xpm1a_event_block.address));
lock_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock);
@@ -86,10 +84,10 @@ acpi_status acpi_hw_clear_acpi_status(u32 flags)
/* Clear the fixed events */
- if (acpi_gbl_FADT->xpm1b_evt_blk.address) {
+ if (acpi_gbl_FADT.xpm1b_event_block.address) {
status =
acpi_hw_low_level_write(16, ACPI_BITMASK_ALL_FIXED_STATUS,
- &acpi_gbl_FADT->xpm1b_evt_blk);
+ &acpi_gbl_FADT.xpm1b_event_block);
if (ACPI_FAILURE(status)) {
goto unlock_and_exit;
}
@@ -253,18 +251,15 @@ struct acpi_bit_register_info *acpi_hw_get_bit_register_info(u32 register_id)
*
* PARAMETERS: register_id - ID of ACPI bit_register to access
* return_value - Value that was read from the register
- * Flags - Lock the hardware or not
*
* RETURN: Status and the value read from specified Register. Value
* returned is normalized to bit0 (is shifted all the way right)
*
* DESCRIPTION: ACPI bit_register read function.
*
- * NOTE: TBD: Flags parameter is obsolete, to be removed
- *
******************************************************************************/
-acpi_status acpi_get_register(u32 register_id, u32 * return_value, u32 flags)
+acpi_status acpi_get_register(u32 register_id, u32 * return_value)
{
u32 register_value = 0;
struct acpi_bit_register_info *bit_reg_info;
@@ -312,16 +307,13 @@ ACPI_EXPORT_SYMBOL(acpi_get_register)
* PARAMETERS: register_id - ID of ACPI bit_register to access
* Value - (only used on write) value to write to the
* Register, NOT pre-normalized to the bit pos
- * Flags - Lock the hardware or not
*
* RETURN: Status
*
* DESCRIPTION: ACPI Bit Register write function.
*
- * NOTE: TBD: Flags parameter is obsolete, to be removed
- *
******************************************************************************/
-acpi_status acpi_set_register(u32 register_id, u32 value, u32 flags)
+acpi_status acpi_set_register(u32 register_id, u32 value)
{
u32 register_value = 0;
struct acpi_bit_register_info *bit_reg_info;
@@ -422,8 +414,9 @@ acpi_status acpi_set_register(u32 register_id, u32 value, u32 flags)
ACPI_DEBUG_PRINT((ACPI_DB_IO,
"PM2 control: Read %X from %8.8X%8.8X\n",
register_value,
- ACPI_FORMAT_UINT64(acpi_gbl_FADT->
- xpm2_cnt_blk.address)));
+ ACPI_FORMAT_UINT64(acpi_gbl_FADT.
+ xpm2_control_block.
+ address)));
ACPI_REGISTER_INSERT_VALUE(register_value,
bit_reg_info->bit_position,
@@ -433,8 +426,9 @@ acpi_status acpi_set_register(u32 register_id, u32 value, u32 flags)
ACPI_DEBUG_PRINT((ACPI_DB_IO,
"About to write %4.4X to %8.8X%8.8X\n",
register_value,
- ACPI_FORMAT_UINT64(acpi_gbl_FADT->
- xpm2_cnt_blk.address)));
+ ACPI_FORMAT_UINT64(acpi_gbl_FADT.
+ xpm2_control_block.
+ address)));
status = acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK,
ACPI_REGISTER_PM2_CONTROL,
@@ -495,7 +489,7 @@ acpi_hw_register_read(u8 use_lock, u32 register_id, u32 * return_value)
status =
acpi_hw_low_level_read(16, &value1,
- &acpi_gbl_FADT->xpm1a_evt_blk);
+ &acpi_gbl_FADT.xpm1a_event_block);
if (ACPI_FAILURE(status)) {
goto unlock_and_exit;
}
@@ -504,7 +498,7 @@ acpi_hw_register_read(u8 use_lock, u32 register_id, u32 * return_value)
status =
acpi_hw_low_level_read(16, &value2,
- &acpi_gbl_FADT->xpm1b_evt_blk);
+ &acpi_gbl_FADT.xpm1b_event_block);
value1 |= value2;
break;
@@ -527,14 +521,14 @@ acpi_hw_register_read(u8 use_lock, u32 register_id, u32 * return_value)
status =
acpi_hw_low_level_read(16, &value1,
- &acpi_gbl_FADT->xpm1a_cnt_blk);
+ &acpi_gbl_FADT.xpm1a_control_block);
if (ACPI_FAILURE(status)) {
goto unlock_and_exit;
}
status =
acpi_hw_low_level_read(16, &value2,
- &acpi_gbl_FADT->xpm1b_cnt_blk);
+ &acpi_gbl_FADT.xpm1b_control_block);
value1 |= value2;
break;
@@ -542,19 +536,20 @@ acpi_hw_register_read(u8 use_lock, u32 register_id, u32 * return_value)
status =
acpi_hw_low_level_read(8, &value1,
- &acpi_gbl_FADT->xpm2_cnt_blk);
+ &acpi_gbl_FADT.xpm2_control_block);
break;
case ACPI_REGISTER_PM_TIMER: /* 32-bit access */
status =
acpi_hw_low_level_read(32, &value1,
- &acpi_gbl_FADT->xpm_tmr_blk);
+ &acpi_gbl_FADT.xpm_timer_block);
break;
case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */
- status = acpi_os_read_port(acpi_gbl_FADT->smi_cmd, &value1, 8);
+ status =
+ acpi_os_read_port(acpi_gbl_FADT.smi_command, &value1, 8);
break;
default:
@@ -635,7 +630,7 @@ acpi_status acpi_hw_register_write(u8 use_lock, u32 register_id, u32 value)
status =
acpi_hw_low_level_write(16, value,
- &acpi_gbl_FADT->xpm1a_evt_blk);
+ &acpi_gbl_FADT.xpm1a_event_block);
if (ACPI_FAILURE(status)) {
goto unlock_and_exit;
}
@@ -644,7 +639,7 @@ acpi_status acpi_hw_register_write(u8 use_lock, u32 register_id, u32 value)
status =
acpi_hw_low_level_write(16, value,
- &acpi_gbl_FADT->xpm1b_evt_blk);
+ &acpi_gbl_FADT.xpm1b_event_block);
break;
case ACPI_REGISTER_PM1_ENABLE: /* 16-bit access */
@@ -682,49 +677,50 @@ acpi_status acpi_hw_register_write(u8 use_lock, u32 register_id, u32 value)
status =
acpi_hw_low_level_write(16, value,
- &acpi_gbl_FADT->xpm1a_cnt_blk);
+ &acpi_gbl_FADT.xpm1a_control_block);
if (ACPI_FAILURE(status)) {
goto unlock_and_exit;
}
status =
acpi_hw_low_level_write(16, value,
- &acpi_gbl_FADT->xpm1b_cnt_blk);
+ &acpi_gbl_FADT.xpm1b_control_block);
break;
case ACPI_REGISTER_PM1A_CONTROL: /* 16-bit access */
status =
acpi_hw_low_level_write(16, value,
- &acpi_gbl_FADT->xpm1a_cnt_blk);
+ &acpi_gbl_FADT.xpm1a_control_block);
break;
case ACPI_REGISTER_PM1B_CONTROL: /* 16-bit access */
status =
acpi_hw_low_level_write(16, value,
- &acpi_gbl_FADT->xpm1b_cnt_blk);
+ &acpi_gbl_FADT.xpm1b_control_block);
break;
case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */
status =
acpi_hw_low_level_write(8, value,
- &acpi_gbl_FADT->xpm2_cnt_blk);
+ &acpi_gbl_FADT.xpm2_control_block);
break;
case ACPI_REGISTER_PM_TIMER: /* 32-bit access */
status =
acpi_hw_low_level_write(32, value,
- &acpi_gbl_FADT->xpm_tmr_blk);
+ &acpi_gbl_FADT.xpm_timer_block);
break;
case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */
/* SMI_CMD is currently always in IO space */
- status = acpi_os_write_port(acpi_gbl_FADT->smi_cmd, value, 8);
+ status =
+ acpi_os_write_port(acpi_gbl_FADT.smi_command, value, 8);
break;
default:
@@ -783,7 +779,7 @@ acpi_hw_low_level_read(u32 width, u32 * value, struct acpi_generic_address *reg)
* Two address spaces supported: Memory or IO.
* PCI_Config is not supported here because the GAS struct is insufficient
*/
- switch (reg->address_space_id) {
+ switch (reg->space_id) {
case ACPI_ADR_SPACE_SYSTEM_MEMORY:
status = acpi_os_read_memory((acpi_physical_address) address,
@@ -792,22 +788,20 @@ acpi_hw_low_level_read(u32 width, u32 * value, struct acpi_generic_address *reg)
case ACPI_ADR_SPACE_SYSTEM_IO:
- status = acpi_os_read_port((acpi_io_address) address,
- value, width);
+ status =
+ acpi_os_read_port((acpi_io_address) address, value, width);
break;
default:
ACPI_ERROR((AE_INFO,
- "Unsupported address space: %X",
- reg->address_space_id));
+ "Unsupported address space: %X", reg->space_id));
return (AE_BAD_PARAMETER);
}
ACPI_DEBUG_PRINT((ACPI_DB_IO,
"Read: %8.8X width %2d from %8.8X%8.8X (%s)\n",
- *value, width,
- ACPI_FORMAT_UINT64(address),
- acpi_ut_get_region_name(reg->address_space_id)));
+ *value, width, ACPI_FORMAT_UINT64(address),
+ acpi_ut_get_region_name(reg->space_id)));
return (status);
}
@@ -854,7 +848,7 @@ acpi_hw_low_level_write(u32 width, u32 value, struct acpi_generic_address * reg)
* Two address spaces supported: Memory or IO.
* PCI_Config is not supported here because the GAS struct is insufficient
*/
- switch (reg->address_space_id) {
+ switch (reg->space_id) {
case ACPI_ADR_SPACE_SYSTEM_MEMORY:
status = acpi_os_write_memory((acpi_physical_address) address,
@@ -863,22 +857,20 @@ acpi_hw_low_level_write(u32 width, u32 value, struct acpi_generic_address * reg)
case ACPI_ADR_SPACE_SYSTEM_IO:
- status = acpi_os_write_port((acpi_io_address) address,
- value, width);
+ status = acpi_os_write_port((acpi_io_address) address, value,
+ width);
break;
default:
ACPI_ERROR((AE_INFO,
- "Unsupported address space: %X",
- reg->address_space_id));
+ "Unsupported address space: %X", reg->space_id));
return (AE_BAD_PARAMETER);
}
ACPI_DEBUG_PRINT((ACPI_DB_IO,
"Wrote: %8.8X width %2d to %8.8X%8.8X (%s)\n",
- value, width,
- ACPI_FORMAT_UINT64(address),
- acpi_ut_get_region_name(reg->address_space_id)));
+ value, width, ACPI_FORMAT_UINT64(address),
+ acpi_ut_get_region_name(reg->space_id)));
return (status);
}
diff --git a/drivers/acpi/hardware/hwsleep.c b/drivers/acpi/hardware/hwsleep.c
index 8bb43cae60c..8fa93125fd4 100644
--- a/drivers/acpi/hardware/hwsleep.c
+++ b/drivers/acpi/hardware/hwsleep.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -43,6 +43,7 @@
*/
#include <acpi/acpi.h>
+#include <acpi/actables.h>
#define _COMPONENT ACPI_HARDWARE
ACPI_MODULE_NAME("hwsleep")
@@ -62,17 +63,32 @@ ACPI_MODULE_NAME("hwsleep")
acpi_status
acpi_set_firmware_waking_vector(acpi_physical_address physical_address)
{
+ struct acpi_table_facs *facs;
+ acpi_status status;
ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vector);
+ /* Get the FACS */
+
+ status =
+ acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS,
+ (struct acpi_table_header **)&facs);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
/* Set the vector */
- if (acpi_gbl_common_fACS.vector_width == 32) {
- *(ACPI_CAST_PTR
- (u32, acpi_gbl_common_fACS.firmware_waking_vector))
- = (u32) physical_address;
+ if ((facs->length < 32) || (!(facs->xfirmware_waking_vector))) {
+ /*
+ * ACPI 1.0 FACS or short table or optional X_ field is zero
+ */
+ facs->firmware_waking_vector = (u32) physical_address;
} else {
- *acpi_gbl_common_fACS.firmware_waking_vector = physical_address;
+ /*
+ * ACPI 2.0 FACS with valid X_ field
+ */
+ facs->xfirmware_waking_vector = physical_address;
}
return_ACPI_STATUS(AE_OK);
@@ -97,6 +113,8 @@ ACPI_EXPORT_SYMBOL(acpi_set_firmware_waking_vector)
acpi_status
acpi_get_firmware_waking_vector(acpi_physical_address * physical_address)
{
+ struct acpi_table_facs *facs;
+ acpi_status status;
ACPI_FUNCTION_TRACE(acpi_get_firmware_waking_vector);
@@ -104,16 +122,29 @@ acpi_get_firmware_waking_vector(acpi_physical_address * physical_address)
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
+ /* Get the FACS */
+
+ status =
+ acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS,
+ (struct acpi_table_header **)&facs);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
/* Get the vector */
- if (acpi_gbl_common_fACS.vector_width == 32) {
- *physical_address = (acpi_physical_address)
- *
- (ACPI_CAST_PTR
- (u32, acpi_gbl_common_fACS.firmware_waking_vector));
+ if ((facs->length < 32) || (!(facs->xfirmware_waking_vector))) {
+ /*
+ * ACPI 1.0 FACS or short table or optional X_ field is zero
+ */
+ *physical_address =
+ (acpi_physical_address) facs->firmware_waking_vector;
} else {
+ /*
+ * ACPI 2.0 FACS with valid X_ field
+ */
*physical_address =
- *acpi_gbl_common_fACS.firmware_waking_vector;
+ (acpi_physical_address) facs->xfirmware_waking_vector;
}
return_ACPI_STATUS(AE_OK);
@@ -204,6 +235,14 @@ acpi_status acpi_enter_sleep_state_prep(u8 sleep_state)
"While executing method _SST"));
}
+ /*
+ * 1) Disable/Clear all GPEs
+ */
+ status = acpi_hw_disable_all_gpes();
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
return_ACPI_STATUS(AE_OK);
}
@@ -246,27 +285,21 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state)
/* Clear wake status */
- status =
- acpi_set_register(ACPI_BITREG_WAKE_STATUS, 1, ACPI_MTX_DO_NOT_LOCK);
+ status = acpi_set_register(ACPI_BITREG_WAKE_STATUS, 1);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
/* Clear all fixed and general purpose status bits */
- status = acpi_hw_clear_acpi_status(ACPI_MTX_DO_NOT_LOCK);
+ status = acpi_hw_clear_acpi_status();
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
/*
- * 1) Disable/Clear all GPEs
* 2) Enable all wakeup GPEs
*/
- status = acpi_hw_disable_all_gpes();
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
acpi_gbl_system_awake_and_running = FALSE;
status = acpi_hw_enable_all_wakeup_gpes();
@@ -367,8 +400,7 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state)
/* Wait until we enter sleep state */
do {
- status = acpi_get_register(ACPI_BITREG_WAKE_STATUS, &in_value,
- ACPI_MTX_DO_NOT_LOCK);
+ status = acpi_get_register(ACPI_BITREG_WAKE_STATUS, &in_value);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
@@ -401,13 +433,12 @@ acpi_status asmlinkage acpi_enter_sleep_state_s4bios(void)
ACPI_FUNCTION_TRACE(acpi_enter_sleep_state_s4bios);
- status =
- acpi_set_register(ACPI_BITREG_WAKE_STATUS, 1, ACPI_MTX_DO_NOT_LOCK);
+ status = acpi_set_register(ACPI_BITREG_WAKE_STATUS, 1);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
- status = acpi_hw_clear_acpi_status(ACPI_MTX_DO_NOT_LOCK);
+ status = acpi_hw_clear_acpi_status();
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
@@ -429,13 +460,12 @@ acpi_status asmlinkage acpi_enter_sleep_state_s4bios(void)
ACPI_FLUSH_CPU_CACHE();
- status = acpi_os_write_port(acpi_gbl_FADT->smi_cmd,
- (u32) acpi_gbl_FADT->S4bios_req, 8);
+ status = acpi_os_write_port(acpi_gbl_FADT.smi_command,
+ (u32) acpi_gbl_FADT.S4bios_request, 8);
do {
acpi_os_stall(1000);
- status = acpi_get_register(ACPI_BITREG_WAKE_STATUS, &in_value,
- ACPI_MTX_DO_NOT_LOCK);
+ status = acpi_get_register(ACPI_BITREG_WAKE_STATUS, &in_value);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
@@ -568,13 +598,11 @@ acpi_status acpi_leave_sleep_state(u8 sleep_state)
(void)
acpi_set_register(acpi_gbl_fixed_event_info
- [ACPI_EVENT_POWER_BUTTON].enable_register_id, 1,
- ACPI_MTX_DO_NOT_LOCK);
+ [ACPI_EVENT_POWER_BUTTON].enable_register_id, 1);
(void)
acpi_set_register(acpi_gbl_fixed_event_info
- [ACPI_EVENT_POWER_BUTTON].status_register_id, 1,
- ACPI_MTX_DO_NOT_LOCK);
+ [ACPI_EVENT_POWER_BUTTON].status_register_id, 1);
arg.integer.value = ACPI_SST_WORKING;
status = acpi_evaluate_object(NULL, METHOD_NAME__SST, &arg_list, NULL);
diff --git a/drivers/acpi/hardware/hwtimer.c b/drivers/acpi/hardware/hwtimer.c
index c4ec47c939f..c32eab696ac 100644
--- a/drivers/acpi/hardware/hwtimer.c
+++ b/drivers/acpi/hardware/hwtimer.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -66,7 +66,7 @@ acpi_status acpi_get_timer_resolution(u32 * resolution)
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
- if (acpi_gbl_FADT->tmr_val_ext == 0) {
+ if ((acpi_gbl_FADT.flags & ACPI_FADT_32BIT_TIMER) == 0) {
*resolution = 24;
} else {
*resolution = 32;
@@ -98,7 +98,8 @@ acpi_status acpi_get_timer(u32 * ticks)
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
- status = acpi_hw_low_level_read(32, ticks, &acpi_gbl_FADT->xpm_tmr_blk);
+ status =
+ acpi_hw_low_level_read(32, ticks, &acpi_gbl_FADT.xpm_timer_block);
return_ACPI_STATUS(status);
}
@@ -153,7 +154,7 @@ acpi_get_timer_duration(u32 start_ticks, u32 end_ticks, u32 * time_elapsed)
if (start_ticks < end_ticks) {
delta_ticks = end_ticks - start_ticks;
} else if (start_ticks > end_ticks) {
- if (acpi_gbl_FADT->tmr_val_ext == 0) {
+ if ((acpi_gbl_FADT.flags & ACPI_FADT_32BIT_TIMER) == 0) {
/* 24-bit Timer */
diff --git a/drivers/acpi/hotkey.c b/drivers/acpi/hotkey.c
deleted file mode 100644
index 8edfb92f7ed..00000000000
--- a/drivers/acpi/hotkey.c
+++ /dev/null
@@ -1,1042 +0,0 @@
-/*
- * hotkey.c - ACPI Hotkey Driver ($Revision: 0.2 $)
- *
- * Copyright (C) 2004 Luming Yu <luming.yu@intel.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/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/proc_fs.h>
-#include <linux/sched.h>
-#include <linux/kmod.h>
-#include <linux/seq_file.h>
-#include <acpi/acpi_drivers.h>
-#include <acpi/acpi_bus.h>
-#include <asm/uaccess.h>
-
-#define HOTKEY_ACPI_VERSION "0.1"
-
-#define HOTKEY_PROC "hotkey"
-#define HOTKEY_EV_CONFIG "event_config"
-#define HOTKEY_PL_CONFIG "poll_config"
-#define HOTKEY_ACTION "action"
-#define HOTKEY_INFO "info"
-
-#define ACPI_HOTK_NAME "Generic Hotkey Driver"
-#define ACPI_HOTK_CLASS "Hotkey"
-#define ACPI_HOTK_DEVICE_NAME "Hotkey"
-#define ACPI_HOTK_HID "Unknown?"
-#define ACPI_HOTKEY_COMPONENT 0x20000000
-
-#define ACPI_HOTKEY_EVENT 0x1
-#define ACPI_HOTKEY_POLLING 0x2
-#define ACPI_UNDEFINED_EVENT 0xf
-
-#define RESULT_STR_LEN 80
-
-#define ACTION_METHOD 0
-#define POLL_METHOD 1
-
-#define IS_EVENT(e) ((e) <= 10000 && (e) >0)
-#define IS_POLL(e) ((e) > 10000)
-#define IS_OTHERS(e) ((e)<=0 || (e)>=20000)
-#define _COMPONENT ACPI_HOTKEY_COMPONENT
-ACPI_MODULE_NAME("acpi_hotkey")
-
- MODULE_AUTHOR("luming.yu@intel.com");
-MODULE_DESCRIPTION(ACPI_HOTK_NAME);
-MODULE_LICENSE("GPL");
-
-/* standardized internal hotkey number/event */
-enum {
- /* Video Extension event */
- HK_EVENT_CYCLE_OUTPUT_DEVICE = 0x80,
- HK_EVENT_OUTPUT_DEVICE_STATUS_CHANGE,
- HK_EVENT_CYCLE_DISPLAY_OUTPUT,
- HK_EVENT_NEXT_DISPLAY_OUTPUT,
- HK_EVENT_PREVIOUS_DISPLAY_OUTPUT,
- HK_EVENT_CYCLE_BRIGHTNESS,
- HK_EVENT_INCREASE_BRIGHTNESS,
- HK_EVENT_DECREASE_BRIGHTNESS,
- HK_EVENT_ZERO_BRIGHTNESS,
- HK_EVENT_DISPLAY_DEVICE_OFF,
-
- /* Snd Card event */
- HK_EVENT_VOLUME_MUTE,
- HK_EVENT_VOLUME_INCLREASE,
- HK_EVENT_VOLUME_DECREASE,
-
- /* running state control */
- HK_EVENT_ENTERRING_S3,
- HK_EVENT_ENTERRING_S4,
- HK_EVENT_ENTERRING_S5,
-};
-
-enum conf_entry_enum {
- bus_handle = 0,
- bus_method = 1,
- action_handle = 2,
- method = 3,
- LAST_CONF_ENTRY
-};
-
-/* procdir we use */
-static struct proc_dir_entry *hotkey_proc_dir;
-static struct proc_dir_entry *hotkey_config;
-static struct proc_dir_entry *hotkey_poll_config;
-static struct proc_dir_entry *hotkey_action;
-static struct proc_dir_entry *hotkey_info;
-
-/* linkage for all type of hotkey */
-struct acpi_hotkey_link {
- struct list_head entries;
- int hotkey_type; /* event or polling based hotkey */
- int hotkey_standard_num; /* standardized hotkey(event) number */
-};
-
-/* event based hotkey */
-struct acpi_event_hotkey {
- struct acpi_hotkey_link hotkey_link;
- int flag;
- acpi_handle bus_handle; /* bus to install notify handler */
- int external_hotkey_num; /* external hotkey/event number */
- acpi_handle action_handle; /* acpi handle attached aml action method */
- char *action_method; /* action method */
-};
-
-/*
- * There are two ways to poll status
- * 1. directy call read_xxx method, without any arguments passed in
- * 2. call write_xxx method, with arguments passed in, you need
- * the result is saved in acpi_polling_hotkey.poll_result.
- * anthoer read command through polling interface.
- *
- */
-
-/* polling based hotkey */
-struct acpi_polling_hotkey {
- struct acpi_hotkey_link hotkey_link;
- int flag;
- acpi_handle poll_handle; /* acpi handle attached polling method */
- char *poll_method; /* poll method */
- acpi_handle action_handle; /* acpi handle attached action method */
- char *action_method; /* action method */
- union acpi_object *poll_result; /* polling_result */
- struct proc_dir_entry *proc;
-};
-
-/* hotkey object union */
-union acpi_hotkey {
- struct list_head entries;
- struct acpi_hotkey_link link;
- struct acpi_event_hotkey event_hotkey;
- struct acpi_polling_hotkey poll_hotkey;
-};
-
-/* hotkey object list */
-struct acpi_hotkey_list {
- struct list_head *entries;
- int count;
-};
-
-static int auto_hotkey_add(struct acpi_device *device);
-static int auto_hotkey_remove(struct acpi_device *device, int type);
-
-static struct acpi_driver hotkey_driver = {
- .name = ACPI_HOTK_NAME,
- .class = ACPI_HOTK_CLASS,
- .ids = ACPI_HOTK_HID,
- .ops = {
- .add = auto_hotkey_add,
- .remove = auto_hotkey_remove,
- },
-};
-
-static void free_hotkey_device(union acpi_hotkey *key);
-static void free_hotkey_buffer(union acpi_hotkey *key);
-static void free_poll_hotkey_buffer(union acpi_hotkey *key);
-static int hotkey_open_config(struct inode *inode, struct file *file);
-static int hotkey_poll_open_config(struct inode *inode, struct file *file);
-static ssize_t hotkey_write_config(struct file *file,
- const char __user * buffer,
- size_t count, loff_t * data);
-static int hotkey_info_open_fs(struct inode *inode, struct file *file);
-static int hotkey_action_open_fs(struct inode *inode, struct file *file);
-static ssize_t hotkey_execute_aml_method(struct file *file,
- const char __user * buffer,
- size_t count, loff_t * data);
-static int hotkey_config_seq_show(struct seq_file *seq, void *offset);
-static int hotkey_poll_config_seq_show(struct seq_file *seq, void *offset);
-static int hotkey_polling_open_fs(struct inode *inode, struct file *file);
-static union acpi_hotkey *get_hotkey_by_event(struct
- acpi_hotkey_list
- *hotkey_list, int event);
-
-/* event based config */
-static const struct file_operations hotkey_config_fops = {
- .open = hotkey_open_config,
- .read = seq_read,
- .write = hotkey_write_config,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-/* polling based config */
-static const struct file_operations hotkey_poll_config_fops = {
- .open = hotkey_poll_open_config,
- .read = seq_read,
- .write = hotkey_write_config,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-/* hotkey driver info */
-static const struct file_operations hotkey_info_fops = {
- .open = hotkey_info_open_fs,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-/* action */
-static const struct file_operations hotkey_action_fops = {
- .open = hotkey_action_open_fs,
- .read = seq_read,
- .write = hotkey_execute_aml_method,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-/* polling results */
-static const struct file_operations hotkey_polling_fops = {
- .open = hotkey_polling_open_fs,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-struct acpi_hotkey_list global_hotkey_list; /* link all ev or pl hotkey */
-struct list_head hotkey_entries; /* head of the list of hotkey_list */
-
-static int hotkey_info_seq_show(struct seq_file *seq, void *offset)
-{
-
- seq_printf(seq, "Hotkey generic driver ver: %s\n", HOTKEY_ACPI_VERSION);
-
- return 0;
-}
-
-static int hotkey_info_open_fs(struct inode *inode, struct file *file)
-{
- return single_open(file, hotkey_info_seq_show, PDE(inode)->data);
-}
-
-static char *format_result(union acpi_object *object)
-{
- char *buf;
-
- buf = kzalloc(RESULT_STR_LEN, GFP_KERNEL);
- if (!buf)
- return NULL;
- /* Now, just support integer type */
- if (object->type == ACPI_TYPE_INTEGER)
- sprintf(buf, "%d\n", (u32) object->integer.value);
- return buf;
-}
-
-static int hotkey_polling_seq_show(struct seq_file *seq, void *offset)
-{
- struct acpi_polling_hotkey *poll_hotkey = seq->private;
- char *buf;
-
-
- if (poll_hotkey->poll_result) {
- buf = format_result(poll_hotkey->poll_result);
- if (buf)
- seq_printf(seq, "%s", buf);
- kfree(buf);
- }
- return 0;
-}
-
-static int hotkey_polling_open_fs(struct inode *inode, struct file *file)
-{
- return single_open(file, hotkey_polling_seq_show, PDE(inode)->data);
-}
-
-static int hotkey_action_open_fs(struct inode *inode, struct file *file)
-{
- return single_open(file, hotkey_info_seq_show, PDE(inode)->data);
-}
-
-/* Mapping external hotkey number to standardized hotkey event num */
-static int hotkey_get_internal_event(int event, struct acpi_hotkey_list *list)
-{
- struct list_head *entries;
- int val = -1;
-
-
- list_for_each(entries, list->entries) {
- union acpi_hotkey *key =
- container_of(entries, union acpi_hotkey, entries);
- if (key->link.hotkey_type == ACPI_HOTKEY_EVENT
- && key->event_hotkey.external_hotkey_num == event) {
- val = key->link.hotkey_standard_num;
- break;
- }
- }
-
- return val;
-}
-
-static void
-acpi_hotkey_notify_handler(acpi_handle handle, u32 event, void *data)
-{
- struct acpi_device *device = NULL;
- u32 internal_event;
-
-
- if (acpi_bus_get_device(handle, &device))
- return;
-
- internal_event = hotkey_get_internal_event(event, &global_hotkey_list);
- acpi_bus_generate_event(device, internal_event, 0);
-
- return;
-}
-
-/* Need to invent automatically hotkey add method */
-static int auto_hotkey_add(struct acpi_device *device)
-{
- /* Implement me */
- return 0;
-}
-
-/* Need to invent automatically hotkey remove method */
-static int auto_hotkey_remove(struct acpi_device *device, int type)
-{
- /* Implement me */
- return 0;
-}
-
-/* Create a proc file for each polling method */
-static int create_polling_proc(union acpi_hotkey *device)
-{
- struct proc_dir_entry *proc;
- char proc_name[80];
- mode_t mode;
-
- mode = S_IFREG | S_IRUGO | S_IWUGO;
-
- sprintf(proc_name, "%d", device->link.hotkey_standard_num);
- /*
- strcat(proc_name, device->poll_hotkey.poll_method);
- */
- proc = create_proc_entry(proc_name, mode, hotkey_proc_dir);
-
- if (!proc) {
- return -ENODEV;
- } else {
- proc->proc_fops = &hotkey_polling_fops;
- proc->owner = THIS_MODULE;
- proc->data = device;
- proc->uid = 0;
- proc->gid = 0;
- device->poll_hotkey.proc = proc;
- }
- return 0;
-}
-
-static int hotkey_add(union acpi_hotkey *device)
-{
- int status = 0;
- struct acpi_device *dev = NULL;
-
-
- if (device->link.hotkey_type == ACPI_HOTKEY_EVENT) {
- acpi_bus_get_device(device->event_hotkey.bus_handle, &dev);
- status = acpi_install_notify_handler(dev->handle,
- ACPI_DEVICE_NOTIFY,
- acpi_hotkey_notify_handler,
- dev);
- } else /* Add polling hotkey */
- create_polling_proc(device);
-
- global_hotkey_list.count++;
-
- list_add_tail(&device->link.entries, global_hotkey_list.entries);
-
- return status;
-}
-
-static int hotkey_remove(union acpi_hotkey *device)
-{
- struct list_head *entries, *next;
-
-
- list_for_each_safe(entries, next, global_hotkey_list.entries) {
- union acpi_hotkey *key =
- container_of(entries, union acpi_hotkey, entries);
- if (key->link.hotkey_standard_num ==
- device->link.hotkey_standard_num) {
- list_del(&key->link.entries);
- free_hotkey_device(key);
- global_hotkey_list.count--;
- break;
- }
- }
- kfree(device);
- return 0;
-}
-
-static int hotkey_update(union acpi_hotkey *key)
-{
- struct list_head *entries;
-
-
- list_for_each(entries, global_hotkey_list.entries) {
- union acpi_hotkey *tmp =
- container_of(entries, union acpi_hotkey, entries);
- if (tmp->link.hotkey_standard_num ==
- key->link.hotkey_standard_num) {
- if (key->link.hotkey_type == ACPI_HOTKEY_EVENT) {
- free_hotkey_buffer(tmp);
- tmp->event_hotkey.bus_handle =
- key->event_hotkey.bus_handle;
- tmp->event_hotkey.external_hotkey_num =
- key->event_hotkey.external_hotkey_num;
- tmp->event_hotkey.action_handle =
- key->event_hotkey.action_handle;
- tmp->event_hotkey.action_method =
- key->event_hotkey.action_method;
- kfree(key);
- } else {
- /*
- char proc_name[80];
-
- sprintf(proc_name, "%d", tmp->link.hotkey_standard_num);
- strcat(proc_name, tmp->poll_hotkey.poll_method);
- remove_proc_entry(proc_name,hotkey_proc_dir);
- */
- free_poll_hotkey_buffer(tmp);
- tmp->poll_hotkey.poll_handle =
- key->poll_hotkey.poll_handle;
- tmp->poll_hotkey.poll_method =
- key->poll_hotkey.poll_method;
- tmp->poll_hotkey.action_handle =
- key->poll_hotkey.action_handle;
- tmp->poll_hotkey.action_method =
- key->poll_hotkey.action_method;
- tmp->poll_hotkey.poll_result =
- key->poll_hotkey.poll_result;
- /*
- create_polling_proc(tmp);
- */
- kfree(key);
- }
- return 0;
- break;
- }
- }
-
- return -ENODEV;
-}
-
-static void free_hotkey_device(union acpi_hotkey *key)
-{
- struct acpi_device *dev;
-
-
- if (key->link.hotkey_type == ACPI_HOTKEY_EVENT) {
- acpi_bus_get_device(key->event_hotkey.bus_handle, &dev);
- if (dev->handle)
- acpi_remove_notify_handler(dev->handle,
- ACPI_DEVICE_NOTIFY,
- acpi_hotkey_notify_handler);
- free_hotkey_buffer(key);
- } else {
- char proc_name[80];
-
- sprintf(proc_name, "%d", key->link.hotkey_standard_num);
- /*
- strcat(proc_name, key->poll_hotkey.poll_method);
- */
- remove_proc_entry(proc_name, hotkey_proc_dir);
- free_poll_hotkey_buffer(key);
- }
- kfree(key);
- return;
-}
-
-static void free_hotkey_buffer(union acpi_hotkey *key)
-{
- /* key would never be null, action method could be */
- kfree(key->event_hotkey.action_method);
-}
-
-static void free_poll_hotkey_buffer(union acpi_hotkey *key)
-{
- /* key would never be null, others could be*/
- kfree(key->poll_hotkey.action_method);
- kfree(key->poll_hotkey.poll_method);
- kfree(key->poll_hotkey.poll_result);
-}
-static int
-init_hotkey_device(union acpi_hotkey *key, char **config_entry,
- int std_num, int external_num)
-{
- acpi_handle tmp_handle;
- acpi_status status = AE_OK;
-
- if (std_num < 0 || IS_POLL(std_num) || !key)
- goto do_fail;
-
- if (!config_entry[bus_handle] || !config_entry[action_handle]
- || !config_entry[method])
- goto do_fail;
-
- key->link.hotkey_type = ACPI_HOTKEY_EVENT;
- key->link.hotkey_standard_num = std_num;
- key->event_hotkey.flag = 0;
- key->event_hotkey.action_method = config_entry[method];
-
- status = acpi_get_handle(NULL, config_entry[bus_handle],
- &(key->event_hotkey.bus_handle));
- if (ACPI_FAILURE(status))
- goto do_fail_zero;
- key->event_hotkey.external_hotkey_num = external_num;
- status = acpi_get_handle(NULL, config_entry[action_handle],
- &(key->event_hotkey.action_handle));
- if (ACPI_FAILURE(status))
- goto do_fail_zero;
- status = acpi_get_handle(key->event_hotkey.action_handle,
- config_entry[method], &tmp_handle);
- if (ACPI_FAILURE(status))
- goto do_fail_zero;
- return AE_OK;
-do_fail_zero:
- key->event_hotkey.action_method = NULL;
-do_fail:
- return -ENODEV;
-}
-
-static int
-init_poll_hotkey_device(union acpi_hotkey *key, char **config_entry,
- int std_num)
-{
- acpi_status status = AE_OK;
- acpi_handle tmp_handle;
-
- if (std_num < 0 || IS_EVENT(std_num) || !key)
- goto do_fail;
- if (!config_entry[bus_handle] ||!config_entry[bus_method] ||
- !config_entry[action_handle] || !config_entry[method])
- goto do_fail;
-
- key->link.hotkey_type = ACPI_HOTKEY_POLLING;
- key->link.hotkey_standard_num = std_num;
- key->poll_hotkey.flag = 0;
- key->poll_hotkey.poll_method = config_entry[bus_method];
- key->poll_hotkey.action_method = config_entry[method];
-
- status = acpi_get_handle(NULL, config_entry[bus_handle],
- &(key->poll_hotkey.poll_handle));
- if (ACPI_FAILURE(status))
- goto do_fail_zero;
- status = acpi_get_handle(key->poll_hotkey.poll_handle,
- config_entry[bus_method], &tmp_handle);
- if (ACPI_FAILURE(status))
- goto do_fail_zero;
- status =
- acpi_get_handle(NULL, config_entry[action_handle],
- &(key->poll_hotkey.action_handle));
- if (ACPI_FAILURE(status))
- goto do_fail_zero;
- status = acpi_get_handle(key->poll_hotkey.action_handle,
- config_entry[method], &tmp_handle);
- if (ACPI_FAILURE(status))
- goto do_fail_zero;
- key->poll_hotkey.poll_result =
- kmalloc(sizeof(union acpi_object), GFP_KERNEL);
- if (!key->poll_hotkey.poll_result)
- goto do_fail_zero;
- return AE_OK;
-
-do_fail_zero:
- key->poll_hotkey.poll_method = NULL;
- key->poll_hotkey.action_method = NULL;
-do_fail:
- return -ENODEV;
-}
-
-static int hotkey_open_config(struct inode *inode, struct file *file)
-{
- return (single_open
- (file, hotkey_config_seq_show, PDE(inode)->data));
-}
-
-static int hotkey_poll_open_config(struct inode *inode, struct file *file)
-{
- return (single_open
- (file, hotkey_poll_config_seq_show, PDE(inode)->data));
-}
-
-static int hotkey_config_seq_show(struct seq_file *seq, void *offset)
-{
- struct acpi_hotkey_list *hotkey_list = &global_hotkey_list;
- struct list_head *entries;
- char bus_name[ACPI_PATHNAME_MAX] = { 0 };
- char action_name[ACPI_PATHNAME_MAX] = { 0 };
- struct acpi_buffer bus = { ACPI_PATHNAME_MAX, bus_name };
- struct acpi_buffer act = { ACPI_PATHNAME_MAX, action_name };
-
-
- list_for_each(entries, hotkey_list->entries) {
- union acpi_hotkey *key =
- container_of(entries, union acpi_hotkey, entries);
- if (key->link.hotkey_type == ACPI_HOTKEY_EVENT) {
- acpi_get_name(key->event_hotkey.bus_handle,
- ACPI_NAME_TYPE_MAX, &bus);
- acpi_get_name(key->event_hotkey.action_handle,
- ACPI_NAME_TYPE_MAX, &act);
- seq_printf(seq, "%s:%s:%s:%d:%d\n", bus_name,
- action_name,
- key->event_hotkey.action_method,
- key->link.hotkey_standard_num,
- key->event_hotkey.external_hotkey_num);
- }
- }
- seq_puts(seq, "\n");
- return 0;
-}
-
-static int hotkey_poll_config_seq_show(struct seq_file *seq, void *offset)
-{
- struct acpi_hotkey_list *hotkey_list = &global_hotkey_list;
- struct list_head *entries;
- char bus_name[ACPI_PATHNAME_MAX] = { 0 };
- char action_name[ACPI_PATHNAME_MAX] = { 0 };
- struct acpi_buffer bus = { ACPI_PATHNAME_MAX, bus_name };
- struct acpi_buffer act = { ACPI_PATHNAME_MAX, action_name };
-
-
- list_for_each(entries, hotkey_list->entries) {
- union acpi_hotkey *key =
- container_of(entries, union acpi_hotkey, entries);
- if (key->link.hotkey_type == ACPI_HOTKEY_POLLING) {
- acpi_get_name(key->poll_hotkey.poll_handle,
- ACPI_NAME_TYPE_MAX, &bus);
- acpi_get_name(key->poll_hotkey.action_handle,
- ACPI_NAME_TYPE_MAX, &act);
- seq_printf(seq, "%s:%s:%s:%s:%d\n", bus_name,
- key->poll_hotkey.poll_method,
- action_name,
- key->poll_hotkey.action_method,
- key->link.hotkey_standard_num);
- }
- }
- seq_puts(seq, "\n");
- return 0;
-}
-
-static int
-get_parms(char *config_record, int *cmd, char **config_entry,
- int *internal_event_num, int *external_event_num)
-{
-/* the format of *config_record =
- * "1:\d+:*" : "cmd:internal_event_num"
- * "\d+:\w+:\w+:\w+:\w+:\d+:\d+" :
- * "cmd:bus_handle:bus_method:action_handle:method:internal_event_num:external_event_num"
- */
- char *tmp, *tmp1, count;
- int i;
-
- sscanf(config_record, "%d", cmd);
- if (*cmd == 1) {
- if (sscanf(config_record, "%d:%d", cmd, internal_event_num) !=
- 2)
- goto do_fail;
- else
- return (6);
- }
- tmp = strchr(config_record, ':');
- if (!tmp)
- goto do_fail;
- tmp++;
- for (i = 0; i < LAST_CONF_ENTRY; i++) {
- tmp1 = strchr(tmp, ':');
- if (!tmp1) {
- goto do_fail;
- }
- count = tmp1 - tmp;
- config_entry[i] = kzalloc(count + 1, GFP_KERNEL);
- if (!config_entry[i])
- goto handle_failure;
- strncpy(config_entry[i], tmp, count);
- tmp = tmp1 + 1;
- }
- if (sscanf(tmp, "%d:%d", internal_event_num, external_event_num) <= 0)
- goto handle_failure;
- if (!IS_OTHERS(*internal_event_num)) {
- return 6;
- }
-handle_failure:
- while (i-- > 0)
- kfree(config_entry[i]);
-do_fail:
- return -1;
-}
-
-/* count is length for one input record */
-static ssize_t hotkey_write_config(struct file *file,
- const char __user * buffer,
- size_t count, loff_t * data)
-{
- char *config_record = NULL;
- char *config_entry[LAST_CONF_ENTRY];
- int cmd, internal_event_num, external_event_num;
- int ret = 0;
- union acpi_hotkey *key = kzalloc(sizeof(union acpi_hotkey), GFP_KERNEL);
-
- if (!key)
- return -ENOMEM;
-
- config_record = kzalloc(count + 1, GFP_KERNEL);
- if (!config_record) {
- kfree(key);
- return -ENOMEM;
- }
-
- if (copy_from_user(config_record, buffer, count)) {
- kfree(config_record);
- kfree(key);
- printk(KERN_ERR PREFIX "Invalid data\n");
- return -EINVAL;
- }
- ret = get_parms(config_record, &cmd, config_entry,
- &internal_event_num, &external_event_num);
- kfree(config_record);
- if (ret != 6) {
- printk(KERN_ERR PREFIX "Invalid data format ret=%d\n", ret);
- return -EINVAL;
- }
-
- if (cmd == 1) {
- union acpi_hotkey *tmp = NULL;
- tmp = get_hotkey_by_event(&global_hotkey_list,
- internal_event_num);
- if (!tmp)
- printk(KERN_ERR PREFIX "Invalid key\n");
- else
- memcpy(key, tmp, sizeof(union acpi_hotkey));
- goto cont_cmd;
- }
- if (IS_EVENT(internal_event_num)) {
- if (init_hotkey_device(key, config_entry,
- internal_event_num, external_event_num))
- goto init_hotkey_fail;
- } else {
- if (init_poll_hotkey_device(key, config_entry,
- internal_event_num))
- goto init_poll_hotkey_fail;
- }
-cont_cmd:
- switch (cmd) {
- case 0:
- if (get_hotkey_by_event(&global_hotkey_list,
- key->link.hotkey_standard_num))
- goto fail_out;
- else
- hotkey_add(key);
- break;
- case 1:
- hotkey_remove(key);
- break;
- case 2:
- /* key is kfree()ed if matched*/
- if (hotkey_update(key))
- goto fail_out;
- break;
- default:
- goto fail_out;
- break;
- }
- return count;
-
-init_poll_hotkey_fail: /* failed init_poll_hotkey_device */
- kfree(config_entry[bus_method]);
- config_entry[bus_method] = NULL;
-init_hotkey_fail: /* failed init_hotkey_device */
- kfree(config_entry[method]);
-fail_out:
- kfree(config_entry[bus_handle]);
- kfree(config_entry[action_handle]);
- /* No double free since elements =NULL for error cases */
- if (IS_EVENT(internal_event_num)) {
- if (config_entry[bus_method])
- kfree(config_entry[bus_method]);
- free_hotkey_buffer(key); /* frees [method] */
- } else
- free_poll_hotkey_buffer(key); /* frees [bus_method]+[method] */
- kfree(key);
- printk(KERN_ERR PREFIX "invalid key\n");
- return -EINVAL;
-}
-
-/*
- * 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
- * of the method is written is output, which can also be NULL
- *
- * returns 1 if write is successful, 0 else.
- */
-static int write_acpi_int(acpi_handle handle, const char *method, int val,
- struct acpi_buffer *output)
-{
- struct acpi_object_list params; /* list of input parameters (an int here) */
- union acpi_object in_obj; /* the only param we use */
- acpi_status status;
-
- params.count = 1;
- params.pointer = &in_obj;
- in_obj.type = ACPI_TYPE_INTEGER;
- in_obj.integer.value = val;
-
- status = acpi_evaluate_object(handle, (char *)method, &params, output);
-
- return (status == AE_OK);
-}
-
-static int read_acpi_int(acpi_handle handle, const char *method,
- union acpi_object *val)
-{
- struct acpi_buffer output;
- union acpi_object out_obj;
- acpi_status status;
-
- output.length = sizeof(out_obj);
- output.pointer = &out_obj;
-
- status = acpi_evaluate_object(handle, (char *)method, NULL, &output);
- if (val) {
- val->integer.value = out_obj.integer.value;
- val->type = out_obj.type;
- } else
- printk(KERN_ERR PREFIX "null val pointer\n");
- return ((status == AE_OK)
- && (out_obj.type == ACPI_TYPE_INTEGER));
-}
-
-static union acpi_hotkey *get_hotkey_by_event(struct
- acpi_hotkey_list
- *hotkey_list, int event)
-{
- struct list_head *entries;
-
- list_for_each(entries, hotkey_list->entries) {
- union acpi_hotkey *key =
- container_of(entries, union acpi_hotkey, entries);
- if (key->link.hotkey_standard_num == event) {
- return (key);
- }
- }
- return (NULL);
-}
-
-/*
- * user call AML method interface:
- * Call convention:
- * echo "event_num: arg type : value"
- * example: echo "1:1:30" > /proc/acpi/action
- * Just support 1 integer arg passing to AML method
- */
-
-static ssize_t hotkey_execute_aml_method(struct file *file,
- const char __user * buffer,
- size_t count, loff_t * data)
-{
- struct acpi_hotkey_list *hotkey_list = &global_hotkey_list;
- char *arg;
- int event, method_type, type, value;
- union acpi_hotkey *key;
-
-
- arg = kzalloc(count + 1, GFP_KERNEL);
- if (!arg)
- return -ENOMEM;
-
- if (copy_from_user(arg, buffer, count)) {
- kfree(arg);
- printk(KERN_ERR PREFIX "Invalid argument 2\n");
- return -EINVAL;
- }
-
- if (sscanf(arg, "%d:%d:%d:%d", &event, &method_type, &type, &value) !=
- 4) {
- kfree(arg);
- printk(KERN_ERR PREFIX "Invalid argument 3\n");
- return -EINVAL;
- }
- kfree(arg);
- if (type == ACPI_TYPE_INTEGER) {
- key = get_hotkey_by_event(hotkey_list, event);
- if (!key)
- goto do_fail;
- if (IS_EVENT(event))
- write_acpi_int(key->event_hotkey.action_handle,
- key->event_hotkey.action_method, value,
- NULL);
- else if (IS_POLL(event)) {
- if (method_type == POLL_METHOD)
- read_acpi_int(key->poll_hotkey.poll_handle,
- key->poll_hotkey.poll_method,
- key->poll_hotkey.poll_result);
- else if (method_type == ACTION_METHOD)
- write_acpi_int(key->poll_hotkey.action_handle,
- key->poll_hotkey.action_method,
- value, NULL);
- else
- goto do_fail;
-
- }
- } else {
- printk(KERN_WARNING "Not supported\n");
- return -EINVAL;
- }
- return count;
- do_fail:
- return -EINVAL;
-
-}
-
-static int __init hotkey_init(void)
-{
- int result;
- mode_t mode = S_IFREG | S_IRUGO | S_IWUGO;
-
-
- if (acpi_disabled)
- return -ENODEV;
-
- if (acpi_specific_hotkey_enabled) {
- printk("Using specific hotkey driver\n");
- return -ENODEV;
- }
-
- hotkey_proc_dir = proc_mkdir(HOTKEY_PROC, acpi_root_dir);
- if (!hotkey_proc_dir) {
- return (-ENODEV);
- }
- hotkey_proc_dir->owner = THIS_MODULE;
-
- hotkey_config =
- create_proc_entry(HOTKEY_EV_CONFIG, mode, hotkey_proc_dir);
- if (!hotkey_config) {
- goto do_fail1;
- } else {
- hotkey_config->proc_fops = &hotkey_config_fops;
- hotkey_config->data = &global_hotkey_list;
- hotkey_config->owner = THIS_MODULE;
- hotkey_config->uid = 0;
- hotkey_config->gid = 0;
- }
-
- hotkey_poll_config =
- create_proc_entry(HOTKEY_PL_CONFIG, mode, hotkey_proc_dir);
- if (!hotkey_poll_config) {
- goto do_fail2;
- } else {
- hotkey_poll_config->proc_fops = &hotkey_poll_config_fops;
- hotkey_poll_config->data = &global_hotkey_list;
- hotkey_poll_config->owner = THIS_MODULE;
- hotkey_poll_config->uid = 0;
- hotkey_poll_config->gid = 0;
- }
-
- hotkey_action = create_proc_entry(HOTKEY_ACTION, mode, hotkey_proc_dir);
- if (!hotkey_action) {
- goto do_fail3;
- } else {
- hotkey_action->proc_fops = &hotkey_action_fops;
- hotkey_action->owner = THIS_MODULE;
- hotkey_action->uid = 0;
- hotkey_action->gid = 0;
- }
-
- hotkey_info = create_proc_entry(HOTKEY_INFO, mode, hotkey_proc_dir);
- if (!hotkey_info) {
- goto do_fail4;
- } else {
- hotkey_info->proc_fops = &hotkey_info_fops;
- hotkey_info->owner = THIS_MODULE;
- hotkey_info->uid = 0;
- hotkey_info->gid = 0;
- }
-
- result = acpi_bus_register_driver(&hotkey_driver);
- if (result < 0)
- goto do_fail5;
- global_hotkey_list.count = 0;
- global_hotkey_list.entries = &hotkey_entries;
-
- INIT_LIST_HEAD(&hotkey_entries);
-
- return (0);
-
- do_fail5:
- remove_proc_entry(HOTKEY_INFO, hotkey_proc_dir);
- do_fail4:
- remove_proc_entry(HOTKEY_ACTION, hotkey_proc_dir);
- do_fail3:
- remove_proc_entry(HOTKEY_PL_CONFIG, hotkey_proc_dir);
- do_fail2:
- remove_proc_entry(HOTKEY_EV_CONFIG, hotkey_proc_dir);
- do_fail1:
- remove_proc_entry(HOTKEY_PROC, acpi_root_dir);
- return (-ENODEV);
-}
-
-static void __exit hotkey_exit(void)
-{
- struct list_head *entries, *next;
-
-
- list_for_each_safe(entries, next, global_hotkey_list.entries) {
- union acpi_hotkey *key =
- container_of(entries, union acpi_hotkey, entries);
-
- acpi_os_wait_events_complete(NULL);
- list_del(&key->link.entries);
- global_hotkey_list.count--;
- free_hotkey_device(key);
- }
- acpi_bus_unregister_driver(&hotkey_driver);
- remove_proc_entry(HOTKEY_EV_CONFIG, hotkey_proc_dir);
- remove_proc_entry(HOTKEY_PL_CONFIG, hotkey_proc_dir);
- remove_proc_entry(HOTKEY_ACTION, hotkey_proc_dir);
- remove_proc_entry(HOTKEY_INFO, hotkey_proc_dir);
- remove_proc_entry(HOTKEY_PROC, acpi_root_dir);
- return;
-}
-
-module_init(hotkey_init);
-module_exit(hotkey_exit);
diff --git a/drivers/acpi/i2c_ec.c b/drivers/acpi/i2c_ec.c
index 8338be0990b..acab4a48189 100644
--- a/drivers/acpi/i2c_ec.c
+++ b/drivers/acpi/i2c_ec.c
@@ -14,7 +14,6 @@
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/stddef.h>
-#include <linux/sched.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/acpi.h>
@@ -28,18 +27,17 @@
#define ACPI_EC_HC_COMPONENT 0x00080000
#define ACPI_EC_HC_CLASS "ec_hc_smbus"
#define ACPI_EC_HC_HID "ACPI0001"
-#define ACPI_EC_HC_DRIVER_NAME "ACPI EC HC smbus driver"
#define ACPI_EC_HC_DEVICE_NAME "EC HC smbus"
#define _COMPONENT ACPI_EC_HC_COMPONENT
-ACPI_MODULE_NAME("acpi_smbus")
+ACPI_MODULE_NAME("i2c_ec");
static int acpi_ec_hc_add(struct acpi_device *device);
static int acpi_ec_hc_remove(struct acpi_device *device, int type);
static struct acpi_driver acpi_ec_hc_driver = {
- .name = ACPI_EC_HC_DRIVER_NAME,
+ .name = "i2c_ec",
.class = ACPI_EC_HC_CLASS,
.ids = ACPI_EC_HC_HID,
.ops = {
@@ -340,6 +338,7 @@ static int acpi_ec_hc_add(struct acpi_device *device)
smbus->adapter.owner = THIS_MODULE;
smbus->adapter.algo = &acpi_ec_smbus_algorithm;
smbus->adapter.algo_data = smbus;
+ smbus->adapter.dev.parent = &device->dev;
if (i2c_add_adapter(&smbus->adapter)) {
ACPI_DEBUG_PRINT((ACPI_DB_WARN,
diff --git a/drivers/acpi/ibm_acpi.c b/drivers/acpi/ibm_acpi.c
index c6144ca6663..4cc534e36e8 100644
--- a/drivers/acpi/ibm_acpi.c
+++ b/drivers/acpi/ibm_acpi.c
@@ -496,6 +496,10 @@ static int ibm_acpi_driver_init(void)
printk(IBM_INFO "%s v%s\n", IBM_DESC, IBM_VERSION);
printk(IBM_INFO "%s\n", IBM_URL);
+ if (ibm_thinkpad_ec_found)
+ printk(IBM_INFO "ThinkPad EC firmware %s\n",
+ ibm_thinkpad_ec_found);
+
return 0;
}
@@ -1697,14 +1701,12 @@ static int brightness_write(char *buf)
static int brightness_update_status(struct backlight_device *bd)
{
- return brightness_set(bd->props->brightness);
+ return brightness_set(bd->props.brightness);
}
-static struct backlight_properties ibm_backlight_data = {
- .owner = THIS_MODULE,
+static struct backlight_ops ibm_backlight_data = {
.get_brightness = brightness_get,
.update_status = brightness_update_status,
- .max_brightness = 7,
};
static int brightness_init(void)
@@ -1716,6 +1718,8 @@ static int brightness_init(void)
return PTR_ERR(ibm_backlight_device);
}
+ ibm_backlight_device->props.max_brightness = 7;
+
return 0;
}
@@ -2617,7 +2621,7 @@ static void __init ibm_handle_init(char *name,
ibm_handle_init(#object, &object##_handle, *object##_parent, \
object##_paths, ARRAY_SIZE(object##_paths), &object##_path)
-static int set_ibm_param(const char *val, struct kernel_param *kp)
+static int __init set_ibm_param(const char *val, struct kernel_param *kp)
{
unsigned int i;
@@ -2659,7 +2663,8 @@ static void acpi_ibm_exit(void)
for (i = ARRAY_SIZE(ibms) - 1; i >= 0; i--)
ibm_exit(&ibms[i]);
- remove_proc_entry(IBM_DIR, acpi_root_dir);
+ if (proc_dir)
+ remove_proc_entry(IBM_DIR, acpi_root_dir);
if (ibm_thinkpad_ec_found)
kfree(ibm_thinkpad_ec_found);
@@ -2696,11 +2701,6 @@ static int __init acpi_ibm_init(void)
if (acpi_disabled)
return -ENODEV;
- if (!acpi_specific_hotkey_enabled) {
- printk(IBM_ERR "using generic hotkey driver\n");
- return -ENODEV;
- }
-
/* ec is required because many other handles are relative to it */
IBM_HANDLE_INIT(ec);
if (!ec_handle) {
@@ -2710,9 +2710,6 @@ static int __init acpi_ibm_init(void)
/* Models with newer firmware report the EC in DMI */
ibm_thinkpad_ec_found = check_dmi_for_ec();
- if (ibm_thinkpad_ec_found)
- printk(IBM_INFO "ThinkPad EC firmware %s\n",
- ibm_thinkpad_ec_found);
/* these handles are not required */
IBM_HANDLE_INIT(vid);
@@ -2742,6 +2739,7 @@ static int __init acpi_ibm_init(void)
proc_dir = proc_mkdir(IBM_DIR, acpi_root_dir);
if (!proc_dir) {
printk(IBM_ERR "unable to create proc dir %s", IBM_DIR);
+ acpi_ibm_exit();
return -ENODEV;
}
proc_dir->owner = THIS_MODULE;
diff --git a/drivers/acpi/motherboard.c b/drivers/acpi/motherboard.c
deleted file mode 100644
index 2e17ec75af0..00000000000
--- a/drivers/acpi/motherboard.c
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; 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.
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- */
-
-/* Purpose: Prevent PCMCIA cards from using motherboard resources. */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/ioport.h>
-#include <asm/io.h>
-
-#include <acpi/acpi_bus.h>
-#include <acpi/acpi_drivers.h>
-
-#define _COMPONENT ACPI_SYSTEM_COMPONENT
-ACPI_MODULE_NAME("acpi_motherboard")
-
-/* Dell use PNP0C01 instead of PNP0C02 */
-#define ACPI_MB_HID1 "PNP0C01"
-#define ACPI_MB_HID2 "PNP0C02"
-/**
- * Doesn't care about legacy IO ports, only IO ports beyond 0x1000 are reserved
- * Doesn't care about the failure of 'request_region', since other may reserve
- * the io ports as well
- */
-#define IS_RESERVED_ADDR(base, len) \
- (((len) > 0) && ((base) > 0) && ((base) + (len) < IO_SPACE_LIMIT) \
- && ((base) + (len) > PCIBIOS_MIN_IO))
-/*
- * Clearing the flag (IORESOURCE_BUSY) allows drivers to use
- * the io ports if they really know they can use it, while
- * still preventing hotplug PCI devices from using it.
- */
-
-/*
- * When CONFIG_PNP is enabled, pnp/system.c binds to PNP0C01
- * and PNP0C02, redundant with acpi_reserve_io_ranges().
- * But acpi_reserve_io_ranges() is necessary for !CONFIG_PNP.
- */
-static acpi_status acpi_reserve_io_ranges(struct acpi_resource *res, void *data)
-{
- struct resource *requested_res = NULL;
-
-
- if (res->type == ACPI_RESOURCE_TYPE_IO) {
- struct acpi_resource_io *io_res = &res->data.io;
-
- if (io_res->minimum != io_res->maximum)
- return AE_OK;
- if (IS_RESERVED_ADDR
- (io_res->minimum, io_res->address_length)) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Motherboard resources 0x%08x - 0x%08x\n",
- io_res->minimum,
- io_res->minimum +
- io_res->address_length));
- requested_res =
- request_region(io_res->minimum,
- io_res->address_length, "motherboard");
- }
- } else if (res->type == ACPI_RESOURCE_TYPE_FIXED_IO) {
- struct acpi_resource_fixed_io *fixed_io_res =
- &res->data.fixed_io;
-
- if (IS_RESERVED_ADDR
- (fixed_io_res->address, fixed_io_res->address_length)) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Motherboard resources 0x%08x - 0x%08x\n",
- fixed_io_res->address,
- fixed_io_res->address +
- fixed_io_res->address_length));
- requested_res =
- request_region(fixed_io_res->address,
- fixed_io_res->address_length,
- "motherboard");
- }
- } else {
- /* Memory mapped IO? */
- }
-
- if (requested_res)
- requested_res->flags &= ~IORESOURCE_BUSY;
- return AE_OK;
-}
-
-static int acpi_motherboard_add(struct acpi_device *device)
-{
- if (!device)
- return -EINVAL;
- acpi_walk_resources(device->handle, METHOD_NAME__CRS,
- acpi_reserve_io_ranges, NULL);
-
- return 0;
-}
-
-static struct acpi_driver acpi_motherboard_driver1 = {
- .name = "motherboard",
- .class = "",
- .ids = ACPI_MB_HID1,
- .ops = {
- .add = acpi_motherboard_add,
- },
-};
-
-static struct acpi_driver acpi_motherboard_driver2 = {
- .name = "motherboard",
- .class = "",
- .ids = ACPI_MB_HID2,
- .ops = {
- .add = acpi_motherboard_add,
- },
-};
-
-static void __init acpi_request_region (struct acpi_generic_address *addr,
- unsigned int length, char *desc)
-{
- if (!addr->address || !length)
- return;
-
- if (addr->address_space_id == ACPI_ADR_SPACE_SYSTEM_IO)
- request_region(addr->address, length, desc);
- else if (addr->address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
- request_mem_region(addr->address, length, desc);
-}
-
-static void __init acpi_reserve_resources(void)
-{
- acpi_request_region(&acpi_gbl_FADT->xpm1a_evt_blk,
- acpi_gbl_FADT->pm1_evt_len, "ACPI PM1a_EVT_BLK");
-
- acpi_request_region(&acpi_gbl_FADT->xpm1b_evt_blk,
- acpi_gbl_FADT->pm1_evt_len, "ACPI PM1b_EVT_BLK");
-
- acpi_request_region(&acpi_gbl_FADT->xpm1a_cnt_blk,
- acpi_gbl_FADT->pm1_cnt_len, "ACPI PM1a_CNT_BLK");
-
- acpi_request_region(&acpi_gbl_FADT->xpm1b_cnt_blk,
- acpi_gbl_FADT->pm1_cnt_len, "ACPI PM1b_CNT_BLK");
-
- if (acpi_gbl_FADT->pm_tm_len == 4)
- acpi_request_region(&acpi_gbl_FADT->xpm_tmr_blk, 4, "ACPI PM_TMR");
-
- acpi_request_region(&acpi_gbl_FADT->xpm2_cnt_blk,
- acpi_gbl_FADT->pm2_cnt_len, "ACPI PM2_CNT_BLK");
-
- /* Length of GPE blocks must be a non-negative multiple of 2 */
-
- if (!(acpi_gbl_FADT->gpe0_blk_len & 0x1))
- acpi_request_region(&acpi_gbl_FADT->xgpe0_blk,
- acpi_gbl_FADT->gpe0_blk_len, "ACPI GPE0_BLK");
-
- if (!(acpi_gbl_FADT->gpe1_blk_len & 0x1))
- acpi_request_region(&acpi_gbl_FADT->xgpe1_blk,
- acpi_gbl_FADT->gpe1_blk_len, "ACPI GPE1_BLK");
-}
-
-static int __init acpi_motherboard_init(void)
-{
- acpi_bus_register_driver(&acpi_motherboard_driver1);
- acpi_bus_register_driver(&acpi_motherboard_driver2);
- /*
- * Guarantee motherboard IO reservation first
- * This module must run after scan.c
- */
- if (!acpi_disabled)
- acpi_reserve_resources();
- return 0;
-}
-
-/**
- * Reserve motherboard resources after PCI claim BARs,
- * but before PCI assign resources for uninitialized PCI devices
- */
-fs_initcall(acpi_motherboard_init);
diff --git a/drivers/acpi/namespace/nsaccess.c b/drivers/acpi/namespace/nsaccess.c
index c1c6c236df9..57faf598bad 100644
--- a/drivers/acpi/namespace/nsaccess.c
+++ b/drivers/acpi/namespace/nsaccess.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -195,31 +195,27 @@ acpi_status acpi_ns_root_initialize(void)
obj_desc->mutex.sync_level =
(u8) (ACPI_TO_INTEGER(val) - 1);
- if (ACPI_STRCMP(init_val->name, "_GL_") == 0) {
+ /* Create a mutex */
- /* Create a counting semaphore for the global lock */
+ status =
+ acpi_os_create_mutex(&obj_desc->mutex.
+ os_mutex);
+ if (ACPI_FAILURE(status)) {
+ acpi_ut_remove_reference(obj_desc);
+ goto unlock_and_exit;
+ }
- status =
- acpi_os_create_semaphore
- (ACPI_NO_UNIT_LIMIT, 1,
- &acpi_gbl_global_lock_semaphore);
- if (ACPI_FAILURE(status)) {
- acpi_ut_remove_reference
- (obj_desc);
- goto unlock_and_exit;
- }
+ /* Special case for ACPI Global Lock */
- /* Mark this mutex as very special */
+ if (ACPI_STRCMP(init_val->name, "_GL_") == 0) {
+ acpi_gbl_global_lock_mutex =
+ obj_desc->mutex.os_mutex;
- obj_desc->mutex.os_mutex =
- ACPI_GLOBAL_LOCK;
- } else {
- /* Create a mutex */
+ /* Create additional counting semaphore for global lock */
status =
- acpi_os_create_mutex(&obj_desc->
- mutex.
- os_mutex);
+ acpi_os_create_semaphore(1, 0,
+ &acpi_gbl_global_lock_semaphore);
if (ACPI_FAILURE(status)) {
acpi_ut_remove_reference
(obj_desc);
diff --git a/drivers/acpi/namespace/nsalloc.c b/drivers/acpi/namespace/nsalloc.c
index 55b407aae26..1d693d8ad2d 100644
--- a/drivers/acpi/namespace/nsalloc.c
+++ b/drivers/acpi/namespace/nsalloc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -61,6 +61,9 @@ ACPI_MODULE_NAME("nsalloc")
struct acpi_namespace_node *acpi_ns_create_node(u32 name)
{
struct acpi_namespace_node *node;
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+ u32 temp;
+#endif
ACPI_FUNCTION_TRACE(ns_create_node);
@@ -71,6 +74,15 @@ struct acpi_namespace_node *acpi_ns_create_node(u32 name)
ACPI_MEM_TRACKING(acpi_gbl_ns_node_list->total_allocated++);
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+ temp =
+ acpi_gbl_ns_node_list->total_allocated -
+ acpi_gbl_ns_node_list->total_freed;
+ if (temp > acpi_gbl_ns_node_list->max_occupied) {
+ acpi_gbl_ns_node_list->max_occupied = temp;
+ }
+#endif
+
node->name.integer = name;
ACPI_SET_DESCRIPTOR_TYPE(node, ACPI_DESC_TYPE_NAMED);
return_PTR(node);
diff --git a/drivers/acpi/namespace/nsdump.c b/drivers/acpi/namespace/nsdump.c
index d72df66aa96..1fc4f86676e 100644
--- a/drivers/acpi/namespace/nsdump.c
+++ b/drivers/acpi/namespace/nsdump.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -205,7 +205,7 @@ acpi_ns_dump_one_object(acpi_handle obj_handle,
if (!acpi_ut_valid_acpi_name(this_node->name.integer)) {
this_node->name.integer =
- acpi_ut_repair_name(this_node->name.integer);
+ acpi_ut_repair_name(this_node->name.ascii);
ACPI_WARNING((AE_INFO, "Invalid ACPI Name %08X",
this_node->name.integer));
@@ -226,6 +226,12 @@ acpi_ns_dump_one_object(acpi_handle obj_handle,
obj_desc = acpi_ns_get_attached_object(this_node);
acpi_dbg_level = dbg_level;
+ /* Temp nodes are those nodes created by a control method */
+
+ if (this_node->flags & ANOBJ_TEMPORARY) {
+ acpi_os_printf("(T) ");
+ }
+
switch (info->display_type & ACPI_DISPLAY_MASK) {
case ACPI_DISPLAY_SUMMARY:
@@ -623,7 +629,8 @@ acpi_ns_dump_objects(acpi_object_type type,
info.display_type = display_type;
(void)acpi_ns_walk_namespace(type, start_handle, max_depth,
- ACPI_NS_WALK_NO_UNLOCK,
+ ACPI_NS_WALK_NO_UNLOCK |
+ ACPI_NS_WALK_TEMP_NODES,
acpi_ns_dump_one_object, (void *)&info,
NULL);
}
diff --git a/drivers/acpi/namespace/nsdumpdv.c b/drivers/acpi/namespace/nsdumpdv.c
index c6bf5d30fca..5097e167939 100644
--- a/drivers/acpi/namespace/nsdumpdv.c
+++ b/drivers/acpi/namespace/nsdumpdv.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/namespace/nseval.c b/drivers/acpi/namespace/nseval.c
index 4b0a4a8c984..aa6370c67ec 100644
--- a/drivers/acpi/namespace/nseval.c
+++ b/drivers/acpi/namespace/nseval.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -154,11 +154,7 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info *info)
* Execute the method via the interpreter. The interpreter is locked
* here before calling into the AML parser
*/
- status = acpi_ex_enter_interpreter();
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
+ acpi_ex_enter_interpreter();
status = acpi_ps_execute_method(info);
acpi_ex_exit_interpreter();
} else {
@@ -182,10 +178,7 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info *info)
* resolution, we must lock it because we could access an opregion.
* The opregion access code assumes that the interpreter is locked.
*/
- status = acpi_ex_enter_interpreter();
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
+ acpi_ex_enter_interpreter();
/* Function has a strange interface */
diff --git a/drivers/acpi/namespace/nsinit.c b/drivers/acpi/namespace/nsinit.c
index aec8488c001..33db2241044 100644
--- a/drivers/acpi/namespace/nsinit.c
+++ b/drivers/acpi/namespace/nsinit.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -45,6 +45,7 @@
#include <acpi/acnamesp.h>
#include <acpi/acdispat.h>
#include <acpi/acinterp.h>
+#include <linux/nmi.h>
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME("nsinit")
@@ -213,7 +214,7 @@ acpi_ns_init_one_object(acpi_handle obj_handle,
u32 level, void *context, void **return_value)
{
acpi_object_type type;
- acpi_status status;
+ acpi_status status = AE_OK;
struct acpi_init_walk_info *info =
(struct acpi_init_walk_info *)context;
struct acpi_namespace_node *node =
@@ -267,10 +268,7 @@ acpi_ns_init_one_object(acpi_handle obj_handle,
/*
* Must lock the interpreter before executing AML code
*/
- status = acpi_ex_enter_interpreter();
- if (ACPI_FAILURE(status)) {
- return (status);
- }
+ acpi_ex_enter_interpreter();
/*
* Each of these types can contain executable AML code within the
@@ -537,7 +535,15 @@ acpi_ns_init_one_device(acpi_handle obj_handle,
info->parameter_type = ACPI_PARAM_ARGS;
info->flags = ACPI_IGNORE_RETURN_VALUE;
+ /*
+ * Some hardware relies on this being executed as atomically
+ * as possible (without an NMI being received in the middle of
+ * this) - so disable NMIs and initialize the device:
+ */
+ acpi_nmi_disable();
status = acpi_ns_evaluate(info);
+ acpi_nmi_enable();
+
if (ACPI_SUCCESS(status)) {
walk_info->num_INI++;
diff --git a/drivers/acpi/namespace/nsload.c b/drivers/acpi/namespace/nsload.c
index fe75d888e18..d4f9654fd20 100644
--- a/drivers/acpi/namespace/nsload.c
+++ b/drivers/acpi/namespace/nsload.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -44,13 +44,12 @@
#include <acpi/acpi.h>
#include <acpi/acnamesp.h>
#include <acpi/acdispat.h>
+#include <acpi/actables.h>
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME("nsload")
/* Local prototypes */
-static acpi_status acpi_ns_load_table_by_type(acpi_table_type table_type);
-
#ifdef ACPI_FUTURE_IMPLEMENTATION
acpi_status acpi_ns_unload_namespace(acpi_handle handle);
@@ -62,7 +61,7 @@ static acpi_status acpi_ns_delete_subtree(acpi_handle start_handle);
*
* FUNCTION: acpi_ns_load_table
*
- * PARAMETERS: table_desc - Descriptor for table to be loaded
+ * PARAMETERS: table_index - Index for table to be loaded
* Node - Owning NS node
*
* RETURN: Status
@@ -72,42 +71,13 @@ static acpi_status acpi_ns_delete_subtree(acpi_handle start_handle);
******************************************************************************/
acpi_status
-acpi_ns_load_table(struct acpi_table_desc *table_desc,
+acpi_ns_load_table(acpi_native_uint table_index,
struct acpi_namespace_node *node)
{
acpi_status status;
ACPI_FUNCTION_TRACE(ns_load_table);
- /* Check if table contains valid AML (must be DSDT, PSDT, SSDT, etc.) */
-
- if (!
- (acpi_gbl_table_data[table_desc->type].
- flags & ACPI_TABLE_EXECUTABLE)) {
-
- /* Just ignore this table */
-
- return_ACPI_STATUS(AE_OK);
- }
-
- /* Check validity of the AML start and length */
-
- if (!table_desc->aml_start) {
- ACPI_ERROR((AE_INFO, "Null AML pointer"));
- return_ACPI_STATUS(AE_BAD_PARAMETER);
- }
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "AML block at %p\n",
- table_desc->aml_start));
-
- /* Ignore table if there is no AML contained within */
-
- if (!table_desc->aml_length) {
- ACPI_WARNING((AE_INFO, "Zero-length AML block in table [%4.4s]",
- table_desc->pointer->signature));
- return_ACPI_STATUS(AE_OK);
- }
-
/*
* Parse the table and load the namespace with all named
* objects found within. Control methods are NOT parsed
@@ -117,15 +87,34 @@ acpi_ns_load_table(struct acpi_table_desc *table_desc,
* to another control method, we can't continue parsing
* because we don't know how many arguments to parse next!
*/
+ status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ /* If table already loaded into namespace, just return */
+
+ if (acpi_tb_is_table_loaded(table_index)) {
+ status = AE_ALREADY_EXISTS;
+ goto unlock;
+ }
+
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"**** Loading table into namespace ****\n"));
- status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
+ status = acpi_tb_allocate_owner_id(table_index);
if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ goto unlock;
+ }
+
+ status = acpi_ns_parse_table(table_index, node->child);
+ if (ACPI_SUCCESS(status)) {
+ acpi_tb_set_table_loaded_flag(table_index, TRUE);
+ } else {
+ acpi_tb_release_owner_id(table_index);
}
- status = acpi_ns_parse_table(table_desc, node->child);
+ unlock:
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE(status)) {
@@ -141,7 +130,7 @@ acpi_ns_load_table(struct acpi_table_desc *table_desc,
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"**** Begin Table Method Parsing and Object Initialization ****\n"));
- status = acpi_ds_initialize_objects(table_desc, node);
+ status = acpi_ds_initialize_objects(table_index, node);
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"**** Completed Table Method Parsing and Object Initialization ****\n"));
@@ -149,99 +138,7 @@ acpi_ns_load_table(struct acpi_table_desc *table_desc,
return_ACPI_STATUS(status);
}
-/*******************************************************************************
- *
- * FUNCTION: acpi_ns_load_table_by_type
- *
- * PARAMETERS: table_type - Id of the table type to load
- *
- * RETURN: Status
- *
- * DESCRIPTION: Load an ACPI table or tables into the namespace. All tables
- * of the given type are loaded. The mechanism allows this
- * routine to be called repeatedly.
- *
- ******************************************************************************/
-
-static acpi_status acpi_ns_load_table_by_type(acpi_table_type table_type)
-{
- u32 i;
- acpi_status status;
- struct acpi_table_desc *table_desc;
-
- ACPI_FUNCTION_TRACE(ns_load_table_by_type);
-
- status = acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- /*
- * Table types supported are:
- * DSDT (one), SSDT/PSDT (multiple)
- */
- switch (table_type) {
- case ACPI_TABLE_ID_DSDT:
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Namespace load: DSDT\n"));
-
- table_desc = acpi_gbl_table_lists[ACPI_TABLE_ID_DSDT].next;
-
- /* If table already loaded into namespace, just return */
-
- if (table_desc->loaded_into_namespace) {
- goto unlock_and_exit;
- }
-
- /* Now load the single DSDT */
-
- status = acpi_ns_load_table(table_desc, acpi_gbl_root_node);
- if (ACPI_SUCCESS(status)) {
- table_desc->loaded_into_namespace = TRUE;
- }
- break;
-
- case ACPI_TABLE_ID_SSDT:
- case ACPI_TABLE_ID_PSDT:
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Namespace load: %d SSDT or PSDTs\n",
- acpi_gbl_table_lists[table_type].count));
-
- /*
- * Traverse list of SSDT or PSDT tables
- */
- table_desc = acpi_gbl_table_lists[table_type].next;
- for (i = 0; i < acpi_gbl_table_lists[table_type].count; i++) {
- /*
- * Only attempt to load table into namespace if it is not
- * already loaded!
- */
- if (!table_desc->loaded_into_namespace) {
- status =
- acpi_ns_load_table(table_desc,
- acpi_gbl_root_node);
- if (ACPI_FAILURE(status)) {
- break;
- }
-
- table_desc->loaded_into_namespace = TRUE;
- }
-
- table_desc = table_desc->next;
- }
- break;
-
- default:
- status = AE_SUPPORT;
- break;
- }
-
- unlock_and_exit:
- (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
- return_ACPI_STATUS(status);
-}
-
+#ifdef ACPI_OBSOLETE_FUNCTIONS
/*******************************************************************************
*
* FUNCTION: acpi_load_namespace
@@ -288,6 +185,7 @@ acpi_status acpi_ns_load_namespace(void)
return_ACPI_STATUS(status);
}
+#endif
#ifdef ACPI_FUTURE_IMPLEMENTATION
/*******************************************************************************
diff --git a/drivers/acpi/namespace/nsnames.c b/drivers/acpi/namespace/nsnames.c
index 97b8332c974..cbd94af08cc 100644
--- a/drivers/acpi/namespace/nsnames.c
+++ b/drivers/acpi/namespace/nsnames.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/namespace/nsobject.c b/drivers/acpi/namespace/nsobject.c
index aabe8794b90..d9d7377bc6e 100644
--- a/drivers/acpi/namespace/nsobject.c
+++ b/drivers/acpi/namespace/nsobject.c
@@ -6,7 +6,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/namespace/nsparse.c b/drivers/acpi/namespace/nsparse.c
index 155505a4ef6..e696aa84799 100644
--- a/drivers/acpi/namespace/nsparse.c
+++ b/drivers/acpi/namespace/nsparse.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -45,6 +45,7 @@
#include <acpi/acnamesp.h>
#include <acpi/acparser.h>
#include <acpi/acdispat.h>
+#include <acpi/actables.h>
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME("nsparse")
@@ -62,14 +63,24 @@ ACPI_MODULE_NAME("nsparse")
*
******************************************************************************/
acpi_status
-acpi_ns_one_complete_parse(u8 pass_number, struct acpi_table_desc *table_desc)
+acpi_ns_one_complete_parse(acpi_native_uint pass_number,
+ acpi_native_uint table_index)
{
union acpi_parse_object *parse_root;
acpi_status status;
+ acpi_native_uint aml_length;
+ u8 *aml_start;
struct acpi_walk_state *walk_state;
+ struct acpi_table_header *table;
+ acpi_owner_id owner_id;
ACPI_FUNCTION_TRACE(ns_one_complete_parse);
+ status = acpi_tb_get_owner_id(table_index, &owner_id);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
/* Create and init a Root Node */
parse_root = acpi_ps_create_scope_op();
@@ -79,26 +90,41 @@ acpi_ns_one_complete_parse(u8 pass_number, struct acpi_table_desc *table_desc)
/* Create and initialize a new walk state */
- walk_state = acpi_ds_create_walk_state(table_desc->owner_id,
- NULL, NULL, NULL);
+ walk_state = acpi_ds_create_walk_state(owner_id, NULL, NULL, NULL);
if (!walk_state) {
acpi_ps_free_op(parse_root);
return_ACPI_STATUS(AE_NO_MEMORY);
}
- status = acpi_ds_init_aml_walk(walk_state, parse_root, NULL,
- table_desc->aml_start,
- table_desc->aml_length, NULL,
- pass_number);
+ status = acpi_get_table_by_index(table_index, &table);
+ if (ACPI_FAILURE(status)) {
+ acpi_ds_delete_walk_state(walk_state);
+ acpi_ps_free_op(parse_root);
+ return_ACPI_STATUS(status);
+ }
+
+ /* Table must consist of at least a complete header */
+
+ if (table->length < sizeof(struct acpi_table_header)) {
+ status = AE_BAD_HEADER;
+ } else {
+ aml_start = (u8 *) table + sizeof(struct acpi_table_header);
+ aml_length = table->length - sizeof(struct acpi_table_header);
+ status = acpi_ds_init_aml_walk(walk_state, parse_root, NULL,
+ aml_start, aml_length, NULL,
+ (u8) pass_number);
+ }
+
if (ACPI_FAILURE(status)) {
acpi_ds_delete_walk_state(walk_state);
+ acpi_ps_delete_parse_tree(parse_root);
return_ACPI_STATUS(status);
}
/* Parse the AML */
ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "*PARSE* pass %d parse\n",
- pass_number));
+ (unsigned)pass_number));
status = acpi_ps_parse_aml(walk_state);
acpi_ps_delete_parse_tree(parse_root);
@@ -119,7 +145,7 @@ acpi_ns_one_complete_parse(u8 pass_number, struct acpi_table_desc *table_desc)
******************************************************************************/
acpi_status
-acpi_ns_parse_table(struct acpi_table_desc *table_desc,
+acpi_ns_parse_table(acpi_native_uint table_index,
struct acpi_namespace_node *start_node)
{
acpi_status status;
@@ -134,10 +160,10 @@ acpi_ns_parse_table(struct acpi_table_desc *table_desc,
* each Parser Op subtree is deleted when it is finished. This saves
* a great deal of memory, and allows a small cache of parse objects
* to service the entire parse. The second pass of the parse then
- * performs another complete parse of the AML..
+ * performs another complete parse of the AML.
*/
ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "**** Start pass 1\n"));
- status = acpi_ns_one_complete_parse(1, table_desc);
+ status = acpi_ns_one_complete_parse(ACPI_IMODE_LOAD_PASS1, table_index);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
@@ -152,7 +178,7 @@ acpi_ns_parse_table(struct acpi_table_desc *table_desc,
* parse objects are all cached.
*/
ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "**** Start pass 2\n"));
- status = acpi_ns_one_complete_parse(2, table_desc);
+ status = acpi_ns_one_complete_parse(ACPI_IMODE_LOAD_PASS2, table_index);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/namespace/nssearch.c b/drivers/acpi/namespace/nssearch.c
index 500e2bbcfaf..e863be665ce 100644
--- a/drivers/acpi/namespace/nssearch.c
+++ b/drivers/acpi/namespace/nssearch.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -321,7 +321,8 @@ acpi_ns_search_and_enter(u32 target_name,
* even though there are a few bad names.
*/
if (!acpi_ut_valid_acpi_name(target_name)) {
- target_name = acpi_ut_repair_name(target_name);
+ target_name =
+ acpi_ut_repair_name(ACPI_CAST_PTR(char, &target_name));
/* Report warning only if in strict mode or debug mode */
@@ -401,6 +402,10 @@ acpi_ns_search_and_enter(u32 target_name,
}
#endif
+ if (flags & ACPI_NS_TEMPORARY) {
+ new_node->flags |= ANOBJ_TEMPORARY;
+ }
+
/* Install the new object into the parent's list of children */
acpi_ns_install_node(walk_state, node, new_node, type);
diff --git a/drivers/acpi/namespace/nsutils.c b/drivers/acpi/namespace/nsutils.c
index aa4e799d9a8..90fd059615f 100644
--- a/drivers/acpi/namespace/nsutils.c
+++ b/drivers/acpi/namespace/nsutils.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -770,13 +770,6 @@ void acpi_ns_terminate(void)
}
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Namespace freed\n"));
-
- /*
- * 2) Now we can delete the ACPI tables
- */
- acpi_tb_delete_all_tables();
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "ACPI Tables freed\n"));
-
return_VOID;
}
diff --git a/drivers/acpi/namespace/nswalk.c b/drivers/acpi/namespace/nswalk.c
index c8f6bef16ed..94eb8f332d9 100644
--- a/drivers/acpi/namespace/nswalk.c
+++ b/drivers/acpi/namespace/nswalk.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -126,7 +126,7 @@ struct acpi_namespace_node *acpi_ns_get_next_node(acpi_object_type type,
* PARAMETERS: Type - acpi_object_type to search for
* start_node - Handle in namespace where search begins
* max_depth - Depth to which search is to reach
- * unlock_before_callback- Whether to unlock the NS before invoking
+ * Flags - Whether to unlock the NS before invoking
* the callback routine
* user_function - Called when an object of "Type" is found
* Context - Passed to user function
@@ -153,7 +153,7 @@ acpi_status
acpi_ns_walk_namespace(acpi_object_type type,
acpi_handle start_node,
u32 max_depth,
- u8 unlock_before_callback,
+ u32 flags,
acpi_walk_callback user_function,
void *context, void **return_value)
{
@@ -193,20 +193,34 @@ acpi_ns_walk_namespace(acpi_object_type type,
acpi_ns_get_next_node(ACPI_TYPE_ANY, parent_node,
child_node);
if (child_node) {
- /*
- * Found node, Get the type if we are not
- * searching for ANY
- */
+
+ /* Found next child, get the type if we are not searching for ANY */
+
if (type != ACPI_TYPE_ANY) {
child_type = child_node->type;
}
- if (child_type == type) {
+ /*
+ * Ignore all temporary namespace nodes (created during control
+ * method execution) unless told otherwise. These temporary nodes
+ * can cause a race condition because they can be deleted during the
+ * execution of the user function (if the namespace is unlocked before
+ * invocation of the user function.) Only the debugger namespace dump
+ * will examine the temporary nodes.
+ */
+ if ((child_node->flags & ANOBJ_TEMPORARY) &&
+ !(flags & ACPI_NS_WALK_TEMP_NODES)) {
+ status = AE_CTRL_DEPTH;
+ }
+
+ /* Type must match requested type */
+
+ else if (child_type == type) {
/*
- * Found a matching node, invoke the user
- * callback function
+ * Found a matching node, invoke the user callback function.
+ * Unlock the namespace if flag is set.
*/
- if (unlock_before_callback) {
+ if (flags & ACPI_NS_WALK_UNLOCK) {
mutex_status =
acpi_ut_release_mutex
(ACPI_MTX_NAMESPACE);
@@ -216,10 +230,11 @@ acpi_ns_walk_namespace(acpi_object_type type,
}
}
- status = user_function(child_node, level,
- context, return_value);
+ status =
+ user_function(child_node, level, context,
+ return_value);
- if (unlock_before_callback) {
+ if (flags & ACPI_NS_WALK_UNLOCK) {
mutex_status =
acpi_ut_acquire_mutex
(ACPI_MTX_NAMESPACE);
@@ -251,20 +266,17 @@ acpi_ns_walk_namespace(acpi_object_type type,
}
/*
- * Depth first search:
- * Attempt to go down another level in the namespace
- * if we are allowed to. Don't go any further if we
- * have reached the caller specified maximum depth
- * or if the user function has specified that the
- * maximum depth has been reached.
+ * Depth first search: Attempt to go down another level in the
+ * namespace if we are allowed to. Don't go any further if we have
+ * reached the caller specified maximum depth or if the user
+ * function has specified that the maximum depth has been reached.
*/
if ((level < max_depth) && (status != AE_CTRL_DEPTH)) {
if (acpi_ns_get_next_node
(ACPI_TYPE_ANY, child_node, NULL)) {
- /*
- * There is at least one child of this
- * node, visit the onde
- */
+
+ /* There is at least one child of this node, visit it */
+
level++;
parent_node = child_node;
child_node = NULL;
@@ -272,9 +284,8 @@ acpi_ns_walk_namespace(acpi_object_type type,
}
} else {
/*
- * No more children of this node (acpi_ns_get_next_node
- * failed), go back upwards in the namespace tree to
- * the node's parent.
+ * No more children of this node (acpi_ns_get_next_node failed), go
+ * back upwards in the namespace tree to the node's parent.
*/
level--;
child_node = parent_node;
diff --git a/drivers/acpi/namespace/nsxfeval.c b/drivers/acpi/namespace/nsxfeval.c
index dca6799ac67..7ac6ace5005 100644
--- a/drivers/acpi/namespace/nsxfeval.c
+++ b/drivers/acpi/namespace/nsxfeval.c
@@ -6,7 +6,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -170,7 +170,6 @@ acpi_evaluate_object(acpi_handle handle,
struct acpi_buffer *return_buffer)
{
acpi_status status;
- acpi_status status2;
struct acpi_evaluate_info *info;
acpi_size buffer_space_needed;
u32 i;
@@ -329,14 +328,12 @@ acpi_evaluate_object(acpi_handle handle,
* Delete the internal return object. NOTE: Interpreter must be
* locked to avoid race condition.
*/
- status2 = acpi_ex_enter_interpreter();
- if (ACPI_SUCCESS(status2)) {
+ acpi_ex_enter_interpreter();
- /* Remove one reference on the return object (should delete it) */
+ /* Remove one reference on the return object (should delete it) */
- acpi_ut_remove_reference(info->return_object);
- acpi_ex_exit_interpreter();
- }
+ acpi_ut_remove_reference(info->return_object);
+ acpi_ex_exit_interpreter();
}
cleanup:
diff --git a/drivers/acpi/namespace/nsxfname.c b/drivers/acpi/namespace/nsxfname.c
index 978213a6c19..b489781b22a 100644
--- a/drivers/acpi/namespace/nsxfname.c
+++ b/drivers/acpi/namespace/nsxfname.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -84,38 +84,41 @@ acpi_get_handle(acpi_handle parent,
/* Convert a parent handle to a prefix node */
if (parent) {
- status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
- if (ACPI_FAILURE(status)) {
- return (status);
- }
-
prefix_node = acpi_ns_map_handle_to_node(parent);
if (!prefix_node) {
- (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
return (AE_BAD_PARAMETER);
}
+ }
+
+ /*
+ * Valid cases are:
+ * 1) Fully qualified pathname
+ * 2) Parent + Relative pathname
+ *
+ * Error for <null Parent + relative path>
+ */
+ if (acpi_ns_valid_root_prefix(pathname[0])) {
- status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
- if (ACPI_FAILURE(status)) {
- return (status);
+ /* Pathname is fully qualified (starts with '\') */
+
+ /* Special case for root-only, since we can't search for it */
+
+ if (!ACPI_STRCMP(pathname, ACPI_NS_ROOT_PATH)) {
+ *ret_handle =
+ acpi_ns_convert_entry_to_handle(acpi_gbl_root_node);
+ return (AE_OK);
}
- }
+ } else if (!prefix_node) {
- /* Special case for root, since we can't search for it */
+ /* Relative path with null prefix is disallowed */
- if (ACPI_STRCMP(pathname, ACPI_NS_ROOT_PATH) == 0) {
- *ret_handle =
- acpi_ns_convert_entry_to_handle(acpi_gbl_root_node);
- return (AE_OK);
+ return (AE_BAD_PARAMETER);
}
- /*
- * Find the Node and convert to a handle
- */
- status = acpi_ns_get_node(prefix_node, pathname, ACPI_NS_NO_UPSEARCH,
- &node);
+ /* Find the Node and convert to a handle */
- *ret_handle = NULL;
+ status =
+ acpi_ns_get_node(prefix_node, pathname, ACPI_NS_NO_UPSEARCH, &node);
if (ACPI_SUCCESS(status)) {
*ret_handle = acpi_ns_convert_entry_to_handle(node);
}
diff --git a/drivers/acpi/namespace/nsxfobj.c b/drivers/acpi/namespace/nsxfobj.c
index a18b1c22312..faa37588720 100644
--- a/drivers/acpi/namespace/nsxfobj.c
+++ b/drivers/acpi/namespace/nsxfobj.c
@@ -6,7 +6,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c
index bd96a704592..8fcd6a15517 100644
--- a/drivers/acpi/numa.c
+++ b/drivers/acpi/numa.c
@@ -33,7 +33,7 @@
#define ACPI_NUMA 0x80000000
#define _COMPONENT ACPI_NUMA
-ACPI_MODULE_NAME("numa")
+ACPI_MODULE_NAME("numa");
static nodemask_t nodes_found_map = NODE_MASK_NONE;
#define PXM_INVAL -1
@@ -45,12 +45,6 @@ int __cpuinitdata pxm_to_node_map[MAX_PXM_DOMAINS]
int __cpuinitdata node_to_pxm_map[MAX_NUMNODES]
= { [0 ... MAX_NUMNODES - 1] = PXM_INVAL };
-extern int __init acpi_table_parse_madt_family(enum acpi_table_id id,
- unsigned long madt_size,
- int entry_id,
- acpi_madt_entry_handler handler,
- unsigned int max_entries);
-
int __cpuinit pxm_to_node(int pxm)
{
if (pxm < 0)
@@ -89,7 +83,7 @@ void __cpuinit acpi_unmap_pxm_to_node(int node)
node_clear(node, nodes_found_map);
}
-void __init acpi_table_print_srat_entry(acpi_table_entry_header * header)
+void __init acpi_table_print_srat_entry(struct acpi_subtable_header * header)
{
ACPI_FUNCTION_NAME("acpi_table_print_srat_entry");
@@ -99,36 +93,35 @@ void __init acpi_table_print_srat_entry(acpi_table_entry_header * header)
switch (header->type) {
- case ACPI_SRAT_PROCESSOR_AFFINITY:
+ case ACPI_SRAT_TYPE_CPU_AFFINITY:
#ifdef ACPI_DEBUG_OUTPUT
{
- struct acpi_table_processor_affinity *p =
- (struct acpi_table_processor_affinity *)header;
+ struct acpi_srat_cpu_affinity *p =
+ (struct acpi_srat_cpu_affinity *)header;
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"SRAT Processor (id[0x%02x] eid[0x%02x]) in proximity domain %d %s\n",
- p->apic_id, p->lsapic_eid,
- p->proximity_domain,
- p->flags.
- enabled ? "enabled" : "disabled"));
+ p->apic_id, p->local_sapic_eid,
+ p->proximity_domain_lo,
+ (p->flags & ACPI_SRAT_CPU_ENABLED)?
+ "enabled" : "disabled"));
}
#endif /* ACPI_DEBUG_OUTPUT */
break;
- case ACPI_SRAT_MEMORY_AFFINITY:
+ case ACPI_SRAT_TYPE_MEMORY_AFFINITY:
#ifdef ACPI_DEBUG_OUTPUT
{
- struct acpi_table_memory_affinity *p =
- (struct acpi_table_memory_affinity *)header;
+ struct acpi_srat_mem_affinity *p =
+ (struct acpi_srat_mem_affinity *)header;
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "SRAT Memory (0x%08x%08x length 0x%08x%08x type 0x%x) in proximity domain %d %s%s\n",
- p->base_addr_hi, p->base_addr_lo,
- p->length_hi, p->length_lo,
+ "SRAT Memory (0x%lx length 0x%lx type 0x%x) in proximity domain %d %s%s\n",
+ (unsigned long)p->base_address,
+ (unsigned long)p->length,
p->memory_type, p->proximity_domain,
- p->flags.
- enabled ? "enabled" : "disabled",
- p->flags.
- hot_pluggable ? " hot-pluggable" :
- ""));
+ (p->flags & ACPI_SRAT_MEM_ENABLED)?
+ "enabled" : "disabled",
+ (p->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE)?
+ " hot-pluggable" : ""));
}
#endif /* ACPI_DEBUG_OUTPUT */
break;
@@ -141,18 +134,18 @@ void __init acpi_table_print_srat_entry(acpi_table_entry_header * header)
}
}
-static int __init acpi_parse_slit(unsigned long phys_addr, unsigned long size)
+static int __init acpi_parse_slit(struct acpi_table_header *table)
{
struct acpi_table_slit *slit;
u32 localities;
- if (!phys_addr || !size)
+ if (!table)
return -EINVAL;
- slit = (struct acpi_table_slit *)__va(phys_addr);
+ slit = (struct acpi_table_slit *)table;
/* downcast just for %llu vs %lu for i386/ia64 */
- localities = (u32) slit->localities;
+ localities = (u32) slit->locality_count;
acpi_numa_slit_init(slit);
@@ -160,12 +153,12 @@ static int __init acpi_parse_slit(unsigned long phys_addr, unsigned long size)
}
static int __init
-acpi_parse_processor_affinity(acpi_table_entry_header * header,
+acpi_parse_processor_affinity(struct acpi_subtable_header * header,
const unsigned long end)
{
- struct acpi_table_processor_affinity *processor_affinity;
+ struct acpi_srat_cpu_affinity *processor_affinity;
- processor_affinity = (struct acpi_table_processor_affinity *)header;
+ processor_affinity = (struct acpi_srat_cpu_affinity *)header;
if (!processor_affinity)
return -EINVAL;
@@ -178,12 +171,12 @@ acpi_parse_processor_affinity(acpi_table_entry_header * header,
}
static int __init
-acpi_parse_memory_affinity(acpi_table_entry_header * header,
+acpi_parse_memory_affinity(struct acpi_subtable_header * header,
const unsigned long end)
{
- struct acpi_table_memory_affinity *memory_affinity;
+ struct acpi_srat_mem_affinity *memory_affinity;
- memory_affinity = (struct acpi_table_memory_affinity *)header;
+ memory_affinity = (struct acpi_srat_mem_affinity *)header;
if (!memory_affinity)
return -EINVAL;
@@ -195,23 +188,23 @@ acpi_parse_memory_affinity(acpi_table_entry_header * header,
return 0;
}
-static int __init acpi_parse_srat(unsigned long phys_addr, unsigned long size)
+static int __init acpi_parse_srat(struct acpi_table_header *table)
{
struct acpi_table_srat *srat;
- if (!phys_addr || !size)
+ if (!table)
return -EINVAL;
- srat = (struct acpi_table_srat *)__va(phys_addr);
+ srat = (struct acpi_table_srat *)table;
return 0;
}
int __init
-acpi_table_parse_srat(enum acpi_srat_entry_id id,
- acpi_madt_entry_handler handler, unsigned int max_entries)
+acpi_table_parse_srat(enum acpi_srat_type id,
+ acpi_table_entry_handler handler, unsigned int max_entries)
{
- return acpi_table_parse_madt_family(ACPI_SRAT,
+ return acpi_table_parse_entries(ACPI_SIG_SRAT,
sizeof(struct acpi_table_srat), id,
handler, max_entries);
}
@@ -221,17 +214,15 @@ int __init acpi_numa_init(void)
int result;
/* SRAT: Static Resource Affinity Table */
- result = acpi_table_parse(ACPI_SRAT, acpi_parse_srat);
-
- if (result > 0) {
- result = acpi_table_parse_srat(ACPI_SRAT_PROCESSOR_AFFINITY,
+ if (!acpi_table_parse(ACPI_SIG_SRAT, acpi_parse_srat)) {
+ result = acpi_table_parse_srat(ACPI_SRAT_TYPE_CPU_AFFINITY,
acpi_parse_processor_affinity,
NR_CPUS);
- result = acpi_table_parse_srat(ACPI_SRAT_MEMORY_AFFINITY, acpi_parse_memory_affinity, NR_NODE_MEMBLKS); // IA64 specific
+ result = acpi_table_parse_srat(ACPI_SRAT_TYPE_MEMORY_AFFINITY, acpi_parse_memory_affinity, NR_NODE_MEMBLKS); // IA64 specific
}
/* SLIT: System Locality Information Table */
- result = acpi_table_parse(ACPI_SLIT, acpi_parse_slit);
+ acpi_table_parse(ACPI_SIG_SLIT, acpi_parse_slit);
acpi_numa_arch_fixup();
return 0;
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 57ae1e5cde0..971eca4864f 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -36,6 +36,7 @@
#include <linux/delay.h>
#include <linux/workqueue.h>
#include <linux/nmi.h>
+#include <linux/acpi.h>
#include <acpi/acpi.h>
#include <asm/io.h>
#include <acpi/acpi_bus.h>
@@ -45,7 +46,7 @@
#include <linux/efi.h>
#define _COMPONENT ACPI_OS_SERVICES
-ACPI_MODULE_NAME("osl")
+ACPI_MODULE_NAME("osl");
#define PREFIX "ACPI: "
struct acpi_os_dpc {
acpi_osd_exec_callback function;
@@ -67,14 +68,59 @@ EXPORT_SYMBOL(acpi_in_debugger);
extern char line_buf[80];
#endif /*ENABLE_DEBUGGER */
-int acpi_specific_hotkey_enabled = TRUE;
-EXPORT_SYMBOL(acpi_specific_hotkey_enabled);
-
static unsigned int acpi_irq_irq;
static acpi_osd_handler acpi_irq_handler;
static void *acpi_irq_context;
static struct workqueue_struct *kacpid_wq;
+static void __init acpi_request_region (struct acpi_generic_address *addr,
+ unsigned int length, char *desc)
+{
+ struct resource *res;
+
+ if (!addr->address || !length)
+ return;
+
+ if (addr->space_id == ACPI_ADR_SPACE_SYSTEM_IO)
+ res = request_region(addr->address, length, desc);
+ else if (addr->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
+ res = request_mem_region(addr->address, length, desc);
+}
+
+static int __init acpi_reserve_resources(void)
+{
+ acpi_request_region(&acpi_gbl_FADT.xpm1a_event_block, acpi_gbl_FADT.pm1_event_length,
+ "ACPI PM1a_EVT_BLK");
+
+ acpi_request_region(&acpi_gbl_FADT.xpm1b_event_block, acpi_gbl_FADT.pm1_event_length,
+ "ACPI PM1b_EVT_BLK");
+
+ acpi_request_region(&acpi_gbl_FADT.xpm1a_control_block, acpi_gbl_FADT.pm1_control_length,
+ "ACPI PM1a_CNT_BLK");
+
+ acpi_request_region(&acpi_gbl_FADT.xpm1b_control_block, acpi_gbl_FADT.pm1_control_length,
+ "ACPI PM1b_CNT_BLK");
+
+ if (acpi_gbl_FADT.pm_timer_length == 4)
+ acpi_request_region(&acpi_gbl_FADT.xpm_timer_block, 4, "ACPI PM_TMR");
+
+ acpi_request_region(&acpi_gbl_FADT.xpm2_control_block, acpi_gbl_FADT.pm2_control_length,
+ "ACPI PM2_CNT_BLK");
+
+ /* Length of GPE blocks must be a non-negative multiple of 2 */
+
+ if (!(acpi_gbl_FADT.gpe0_block_length & 0x1))
+ acpi_request_region(&acpi_gbl_FADT.xgpe0_block,
+ acpi_gbl_FADT.gpe0_block_length, "ACPI GPE0_BLK");
+
+ if (!(acpi_gbl_FADT.gpe1_block_length & 0x1))
+ acpi_request_region(&acpi_gbl_FADT.xgpe1_block,
+ acpi_gbl_FADT.gpe1_block_length, "ACPI GPE1_BLK");
+
+ return 0;
+}
+device_initcall(acpi_reserve_resources);
+
acpi_status acpi_os_initialize(void)
{
return AE_OK;
@@ -136,53 +182,43 @@ void acpi_os_vprintf(const char *fmt, va_list args)
#endif
}
-acpi_status acpi_os_get_root_pointer(u32 flags, struct acpi_pointer *addr)
+acpi_physical_address __init acpi_os_get_root_pointer(void)
{
if (efi_enabled) {
- addr->pointer_type = ACPI_PHYSICAL_POINTER;
if (efi.acpi20 != EFI_INVALID_TABLE_ADDR)
- addr->pointer.physical = efi.acpi20;
+ return efi.acpi20;
else if (efi.acpi != EFI_INVALID_TABLE_ADDR)
- addr->pointer.physical = efi.acpi;
+ return efi.acpi;
else {
printk(KERN_ERR PREFIX
"System description tables not found\n");
- return AE_NOT_FOUND;
+ return 0;
}
- } else {
- if (ACPI_FAILURE(acpi_find_root_pointer(flags, addr))) {
- printk(KERN_ERR PREFIX
- "System description tables not found\n");
- return AE_NOT_FOUND;
- }
- }
-
- return AE_OK;
+ } else
+ return acpi_find_rsdp();
}
-acpi_status
-acpi_os_map_memory(acpi_physical_address phys, acpi_size size,
- void __iomem ** virt)
+void __iomem *acpi_os_map_memory(acpi_physical_address phys, acpi_size size)
{
if (phys > ULONG_MAX) {
printk(KERN_ERR PREFIX "Cannot map memory that high\n");
- return AE_BAD_PARAMETER;
+ return NULL;
}
- /*
- * ioremap checks to ensure this is in reserved space
- */
- *virt = ioremap((unsigned long)phys, size);
-
- if (!*virt)
- return AE_NO_MEMORY;
-
- return AE_OK;
+ if (acpi_gbl_permanent_mmap)
+ /*
+ * ioremap checks to ensure this is in reserved space
+ */
+ return ioremap((unsigned long)phys, size);
+ else
+ return __acpi_map_table((unsigned long)phys, size);
}
EXPORT_SYMBOL_GPL(acpi_os_map_memory);
void acpi_os_unmap_memory(void __iomem * virt, acpi_size size)
{
- iounmap(virt);
+ if (acpi_gbl_permanent_mmap) {
+ iounmap(virt);
+ }
}
EXPORT_SYMBOL_GPL(acpi_os_unmap_memory);
@@ -254,7 +290,7 @@ acpi_os_install_interrupt_handler(u32 gsi, acpi_osd_handler handler,
* FADT. It may not be the same if an interrupt source override exists
* for the SCI.
*/
- gsi = acpi_fadt.sci_int;
+ gsi = acpi_gbl_FADT.sci_interrupt;
if (acpi_gsi_to_irq(gsi, &irq) < 0) {
printk(KERN_ERR PREFIX "SCI (ACPI GSI %d) not registered\n",
gsi);
@@ -851,26 +887,6 @@ u32 acpi_os_get_line(char *buffer)
}
#endif /* ACPI_FUTURE_USAGE */
-/* Assumes no unreadable holes inbetween */
-u8 acpi_os_readable(void *ptr, acpi_size len)
-{
-#if defined(__i386__) || defined(__x86_64__)
- char tmp;
- return !__get_user(tmp, (char __user *)ptr)
- && !__get_user(tmp, (char __user *)ptr + len - 1);
-#endif
- return 1;
-}
-
-#ifdef ACPI_FUTURE_USAGE
-u8 acpi_os_writable(void *ptr, acpi_size len)
-{
- /* could do dummy write (racy) or a kernel page table lookup.
- The later may be difficult at early boot when kmap doesn't work yet. */
- return 1;
-}
-#endif
-
acpi_status acpi_os_signal(u32 function, void *info)
{
switch (function) {
@@ -973,14 +989,6 @@ static int __init acpi_wake_gpes_always_on_setup(char *str)
__setup("acpi_wake_gpes_always_on", acpi_wake_gpes_always_on_setup);
-static int __init acpi_hotkey_setup(char *str)
-{
- acpi_specific_hotkey_enabled = FALSE;
- return 1;
-}
-
-__setup("acpi_generic_hotkey", acpi_hotkey_setup);
-
/*
* max_cstate is defined in the base kernel so modules can
* change it w/o depending on the state of the processor module.
diff --git a/drivers/acpi/parser/psargs.c b/drivers/acpi/parser/psargs.c
index bf88e076c3e..c2b9835c890 100644
--- a/drivers/acpi/parser/psargs.c
+++ b/drivers/acpi/parser/psargs.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/parser/psloop.c b/drivers/acpi/parser/psloop.c
index e1541db3753..773aee82fbb 100644
--- a/drivers/acpi/parser/psloop.c
+++ b/drivers/acpi/parser/psloop.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -42,12 +42,11 @@
*/
/*
- * Parse the AML and build an operation tree as most interpreters,
- * like Perl, do. Parsing is done by hand rather than with a YACC
- * generated parser to tightly constrain stack and dynamic memory
- * usage. At the same time, parsing is kept flexible and the code
- * fairly compact by parsing based on a list of AML opcode
- * templates in aml_op_info[]
+ * Parse the AML and build an operation tree as most interpreters, (such as
+ * Perl) do. Parsing is done by hand rather than with a YACC generated parser
+ * to tightly constrain stack and dynamic memory usage. Parsing is kept
+ * flexible and the code fairly compact by parsing based on a list of AML
+ * opcode templates in aml_op_info[].
*/
#include <acpi/acpi.h>
@@ -60,766 +59,679 @@ ACPI_MODULE_NAME("psloop")
static u32 acpi_gbl_depth = 0;
+/* Local prototypes */
+
+static acpi_status acpi_ps_get_aml_opcode(struct acpi_walk_state *walk_state);
+
+static acpi_status
+acpi_ps_build_named_op(struct acpi_walk_state *walk_state,
+ u8 * aml_op_start,
+ union acpi_parse_object *unnamed_op,
+ union acpi_parse_object **op);
+
+static acpi_status
+acpi_ps_create_op(struct acpi_walk_state *walk_state,
+ u8 * aml_op_start, union acpi_parse_object **new_op);
+
+static acpi_status
+acpi_ps_get_arguments(struct acpi_walk_state *walk_state,
+ u8 * aml_op_start, union acpi_parse_object *op);
+
+static acpi_status
+acpi_ps_complete_op(struct acpi_walk_state *walk_state,
+ union acpi_parse_object **op, acpi_status status);
+
+static acpi_status
+acpi_ps_complete_final_op(struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op, acpi_status status);
+
/*******************************************************************************
*
- * FUNCTION: acpi_ps_parse_loop
+ * FUNCTION: acpi_ps_get_aml_opcode
*
* PARAMETERS: walk_state - Current state
*
* RETURN: Status
*
- * DESCRIPTION: Parse AML (pointed to by the current parser state) and return
- * a tree of ops.
+ * DESCRIPTION: Extract the next AML opcode from the input stream.
*
******************************************************************************/
-acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state)
+static acpi_status acpi_ps_get_aml_opcode(struct acpi_walk_state *walk_state)
{
- acpi_status status = AE_OK;
- acpi_status status2;
- union acpi_parse_object *op = NULL; /* current op */
- union acpi_parse_object *arg = NULL;
- union acpi_parse_object *pre_op = NULL;
- struct acpi_parse_state *parser_state;
- u8 *aml_op_start = NULL;
- ACPI_FUNCTION_TRACE_PTR(ps_parse_loop, walk_state);
+ ACPI_FUNCTION_TRACE_PTR(ps_get_aml_opcode, walk_state);
- if (walk_state->descending_callback == NULL) {
- return_ACPI_STATUS(AE_BAD_PARAMETER);
- }
+ walk_state->aml_offset =
+ (u32) ACPI_PTR_DIFF(walk_state->parser_state.aml,
+ walk_state->parser_state.aml_start);
+ walk_state->opcode = acpi_ps_peek_opcode(&(walk_state->parser_state));
- parser_state = &walk_state->parser_state;
- walk_state->arg_types = 0;
+ /*
+ * First cut to determine what we have found:
+ * 1) A valid AML opcode
+ * 2) A name string
+ * 3) An unknown/invalid opcode
+ */
+ walk_state->op_info = acpi_ps_get_opcode_info(walk_state->opcode);
-#if (!defined (ACPI_NO_METHOD_EXECUTION) && !defined (ACPI_CONSTANT_EVAL_ONLY))
+ switch (walk_state->op_info->class) {
+ case AML_CLASS_ASCII:
+ case AML_CLASS_PREFIX:
+ /*
+ * Starts with a valid prefix or ASCII char, this is a name
+ * string. Convert the bare name string to a namepath.
+ */
+ walk_state->opcode = AML_INT_NAMEPATH_OP;
+ walk_state->arg_types = ARGP_NAMESTRING;
+ break;
- if (walk_state->walk_type & ACPI_WALK_METHOD_RESTART) {
+ case AML_CLASS_UNKNOWN:
- /* We are restarting a preempted control method */
+ /* The opcode is unrecognized. Just skip unknown opcodes */
- if (acpi_ps_has_completed_scope(parser_state)) {
- /*
- * We must check if a predicate to an IF or WHILE statement
- * was just completed
- */
- if ((parser_state->scope->parse_scope.op) &&
- ((parser_state->scope->parse_scope.op->common.
- aml_opcode == AML_IF_OP)
- || (parser_state->scope->parse_scope.op->common.
- aml_opcode == AML_WHILE_OP))
- && (walk_state->control_state)
- && (walk_state->control_state->common.state ==
- ACPI_CONTROL_PREDICATE_EXECUTING)) {
- /*
- * A predicate was just completed, get the value of the
- * predicate and branch based on that value
- */
- walk_state->op = NULL;
- status =
- acpi_ds_get_predicate_value(walk_state,
- ACPI_TO_POINTER
- (TRUE));
- if (ACPI_FAILURE(status)
- && ((status & AE_CODE_MASK) !=
- AE_CODE_CONTROL)) {
- if (status == AE_AML_NO_RETURN_VALUE) {
- ACPI_EXCEPTION((AE_INFO, status,
- "Invoked method did not return a value"));
+ ACPI_ERROR((AE_INFO,
+ "Found unknown opcode %X at AML address %p offset %X, ignoring",
+ walk_state->opcode, walk_state->parser_state.aml,
+ walk_state->aml_offset));
- }
- ACPI_EXCEPTION((AE_INFO, status,
- "GetPredicate Failed"));
- return_ACPI_STATUS(status);
- }
+ ACPI_DUMP_BUFFER(walk_state->parser_state.aml, 128);
- status =
- acpi_ps_next_parse_state(walk_state, op,
- status);
- }
+ /* Assume one-byte bad opcode */
- acpi_ps_pop_scope(parser_state, &op,
- &walk_state->arg_types,
- &walk_state->arg_count);
- ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
- "Popped scope, Op=%p\n", op));
- } else if (walk_state->prev_op) {
+ walk_state->parser_state.aml++;
+ return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE);
- /* We were in the middle of an op */
+ default:
- op = walk_state->prev_op;
- walk_state->arg_types = walk_state->prev_arg_types;
- }
+ /* Found opcode info, this is a normal opcode */
+
+ walk_state->parser_state.aml +=
+ acpi_ps_get_opcode_size(walk_state->opcode);
+ walk_state->arg_types = walk_state->op_info->parse_args;
+ break;
}
-#endif
- /* Iterative parsing loop, while there is more AML to process: */
+ return_ACPI_STATUS(AE_OK);
+}
- while ((parser_state->aml < parser_state->aml_end) || (op)) {
- aml_op_start = parser_state->aml;
- if (!op) {
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_build_named_op
+ *
+ * PARAMETERS: walk_state - Current state
+ * aml_op_start - Begin of named Op in AML
+ * unnamed_op - Early Op (not a named Op)
+ * Op - Returned Op
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Parse a named Op
+ *
+ ******************************************************************************/
- /* Get the next opcode from the AML stream */
+static acpi_status
+acpi_ps_build_named_op(struct acpi_walk_state *walk_state,
+ u8 * aml_op_start,
+ union acpi_parse_object *unnamed_op,
+ union acpi_parse_object **op)
+{
+ acpi_status status = AE_OK;
+ union acpi_parse_object *arg = NULL;
- walk_state->aml_offset =
- (u32) ACPI_PTR_DIFF(parser_state->aml,
- parser_state->aml_start);
- walk_state->opcode = acpi_ps_peek_opcode(parser_state);
+ ACPI_FUNCTION_TRACE_PTR(ps_build_named_op, walk_state);
- /*
- * First cut to determine what we have found:
- * 1) A valid AML opcode
- * 2) A name string
- * 3) An unknown/invalid opcode
- */
- walk_state->op_info =
- acpi_ps_get_opcode_info(walk_state->opcode);
- switch (walk_state->op_info->class) {
- case AML_CLASS_ASCII:
- case AML_CLASS_PREFIX:
- /*
- * Starts with a valid prefix or ASCII char, this is a name
- * string. Convert the bare name string to a namepath.
- */
- walk_state->opcode = AML_INT_NAMEPATH_OP;
- walk_state->arg_types = ARGP_NAMESTRING;
- break;
+ unnamed_op->common.value.arg = NULL;
+ unnamed_op->common.aml_opcode = walk_state->opcode;
- case AML_CLASS_UNKNOWN:
+ /*
+ * Get and append arguments until we find the node that contains
+ * the name (the type ARGP_NAME).
+ */
+ while (GET_CURRENT_ARG_TYPE(walk_state->arg_types) &&
+ (GET_CURRENT_ARG_TYPE(walk_state->arg_types) != ARGP_NAME)) {
+ status =
+ acpi_ps_get_next_arg(walk_state,
+ &(walk_state->parser_state),
+ GET_CURRENT_ARG_TYPE(walk_state->
+ arg_types), &arg);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
- /* The opcode is unrecognized. Just skip unknown opcodes */
+ acpi_ps_append_arg(unnamed_op, arg);
+ INCREMENT_ARG_LIST(walk_state->arg_types);
+ }
- ACPI_ERROR((AE_INFO,
- "Found unknown opcode %X at AML address %p offset %X, ignoring",
- walk_state->opcode,
- parser_state->aml,
- walk_state->aml_offset));
+ /*
+ * Make sure that we found a NAME and didn't run out of arguments
+ */
+ if (!GET_CURRENT_ARG_TYPE(walk_state->arg_types)) {
+ return_ACPI_STATUS(AE_AML_NO_OPERAND);
+ }
- ACPI_DUMP_BUFFER(parser_state->aml, 128);
+ /* We know that this arg is a name, move to next arg */
- /* Assume one-byte bad opcode */
+ INCREMENT_ARG_LIST(walk_state->arg_types);
- parser_state->aml++;
- continue;
+ /*
+ * Find the object. This will either insert the object into
+ * the namespace or simply look it up
+ */
+ walk_state->op = NULL;
- default:
+ status = walk_state->descending_callback(walk_state, op);
+ if (ACPI_FAILURE(status)) {
+ ACPI_EXCEPTION((AE_INFO, status, "During name lookup/catalog"));
+ return_ACPI_STATUS(status);
+ }
- /* Found opcode info, this is a normal opcode */
+ if (!*op) {
+ return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE);
+ }
- parser_state->aml +=
- acpi_ps_get_opcode_size(walk_state->opcode);
- walk_state->arg_types =
- walk_state->op_info->parse_args;
- break;
- }
+ status = acpi_ps_next_parse_state(walk_state, *op, status);
+ if (ACPI_FAILURE(status)) {
+ if (status == AE_CTRL_PENDING) {
+ return_ACPI_STATUS(AE_CTRL_PARSE_PENDING);
+ }
+ return_ACPI_STATUS(status);
+ }
- /* Create Op structure and append to parent's argument list */
+ acpi_ps_append_arg(*op, unnamed_op->common.value.arg);
+ acpi_gbl_depth++;
- if (walk_state->op_info->flags & AML_NAMED) {
+ if ((*op)->common.aml_opcode == AML_REGION_OP) {
+ /*
+ * Defer final parsing of an operation_region body, because we don't
+ * have enough info in the first pass to parse it correctly (i.e.,
+ * there may be method calls within the term_arg elements of the body.)
+ *
+ * However, we must continue parsing because the opregion is not a
+ * standalone package -- we don't know where the end is at this point.
+ *
+ * (Length is unknown until parse of the body complete)
+ */
+ (*op)->named.data = aml_op_start;
+ (*op)->named.length = 0;
+ }
- /* Allocate a new pre_op if necessary */
+ return_ACPI_STATUS(AE_OK);
+}
- if (!pre_op) {
- pre_op =
- acpi_ps_alloc_op(walk_state->
- opcode);
- if (!pre_op) {
- status = AE_NO_MEMORY;
- goto close_this_op;
- }
- }
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_create_op
+ *
+ * PARAMETERS: walk_state - Current state
+ * aml_op_start - Op start in AML
+ * new_op - Returned Op
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Get Op from AML
+ *
+ ******************************************************************************/
- pre_op->common.value.arg = NULL;
- pre_op->common.aml_opcode = walk_state->opcode;
+static acpi_status
+acpi_ps_create_op(struct acpi_walk_state *walk_state,
+ u8 * aml_op_start, union acpi_parse_object **new_op)
+{
+ acpi_status status = AE_OK;
+ union acpi_parse_object *op;
+ union acpi_parse_object *named_op = NULL;
- /*
- * Get and append arguments until we find the node that contains
- * the name (the type ARGP_NAME).
- */
- while (GET_CURRENT_ARG_TYPE
- (walk_state->arg_types)
- &&
- (GET_CURRENT_ARG_TYPE
- (walk_state->arg_types) != ARGP_NAME)) {
- status =
- acpi_ps_get_next_arg(walk_state,
- parser_state,
- GET_CURRENT_ARG_TYPE
- (walk_state->
- arg_types),
- &arg);
- if (ACPI_FAILURE(status)) {
- goto close_this_op;
- }
+ ACPI_FUNCTION_TRACE_PTR(ps_create_op, walk_state);
- acpi_ps_append_arg(pre_op, arg);
- INCREMENT_ARG_LIST(walk_state->
- arg_types);
- }
+ status = acpi_ps_get_aml_opcode(walk_state);
+ if (status == AE_CTRL_PARSE_CONTINUE) {
+ return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE);
+ }
- /*
- * Make sure that we found a NAME and didn't run out of
- * arguments
- */
- if (!GET_CURRENT_ARG_TYPE
- (walk_state->arg_types)) {
- status = AE_AML_NO_OPERAND;
- goto close_this_op;
- }
+ /* Create Op structure and append to parent's argument list */
- /* We know that this arg is a name, move to next arg */
+ walk_state->op_info = acpi_ps_get_opcode_info(walk_state->opcode);
+ op = acpi_ps_alloc_op(walk_state->opcode);
+ if (!op) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
+ }
- INCREMENT_ARG_LIST(walk_state->arg_types);
+ if (walk_state->op_info->flags & AML_NAMED) {
+ status =
+ acpi_ps_build_named_op(walk_state, aml_op_start, op,
+ &named_op);
+ acpi_ps_free_op(op);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
- /*
- * Find the object. This will either insert the object into
- * the namespace or simply look it up
- */
- walk_state->op = NULL;
+ *new_op = named_op;
+ return_ACPI_STATUS(AE_OK);
+ }
- status =
- walk_state->descending_callback(walk_state,
- &op);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status,
- "During name lookup/catalog"));
- goto close_this_op;
- }
+ /* Not a named opcode, just allocate Op and append to parent */
- if (!op) {
- continue;
- }
+ if (walk_state->op_info->flags & AML_CREATE) {
+ /*
+ * Backup to beginning of create_xXXfield declaration
+ * body_length is unknown until we parse the body
+ */
+ op->named.data = aml_op_start;
+ op->named.length = 0;
+ }
- status =
- acpi_ps_next_parse_state(walk_state, op,
- status);
- if (status == AE_CTRL_PENDING) {
- status = AE_OK;
- goto close_this_op;
- }
+ acpi_ps_append_arg(acpi_ps_get_parent_scope
+ (&(walk_state->parser_state)), op);
- if (ACPI_FAILURE(status)) {
- goto close_this_op;
- }
+ if (walk_state->descending_callback != NULL) {
+ /*
+ * Find the object. This will either insert the object into
+ * the namespace or simply look it up
+ */
+ walk_state->op = *new_op = op;
- acpi_ps_append_arg(op,
- pre_op->common.value.arg);
- acpi_gbl_depth++;
-
- if (op->common.aml_opcode == AML_REGION_OP) {
- /*
- * Defer final parsing of an operation_region body,
- * because we don't have enough info in the first pass
- * to parse it correctly (i.e., there may be method
- * calls within the term_arg elements of the body.)
- *
- * However, we must continue parsing because
- * the opregion is not a standalone package --
- * we don't know where the end is at this point.
- *
- * (Length is unknown until parse of the body complete)
- */
- op->named.data = aml_op_start;
- op->named.length = 0;
- }
- } else {
- /* Not a named opcode, just allocate Op and append to parent */
+ status = walk_state->descending_callback(walk_state, &op);
+ status = acpi_ps_next_parse_state(walk_state, op, status);
+ if (status == AE_CTRL_PENDING) {
+ status = AE_CTRL_PARSE_PENDING;
+ }
+ }
- walk_state->op_info =
- acpi_ps_get_opcode_info(walk_state->opcode);
- op = acpi_ps_alloc_op(walk_state->opcode);
- if (!op) {
- status = AE_NO_MEMORY;
- goto close_this_op;
- }
+ return_ACPI_STATUS(status);
+}
- if (walk_state->op_info->flags & AML_CREATE) {
- /*
- * Backup to beginning of create_xXXfield declaration
- * body_length is unknown until we parse the body
- */
- op->named.data = aml_op_start;
- op->named.length = 0;
- }
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_get_arguments
+ *
+ * PARAMETERS: walk_state - Current state
+ * aml_op_start - Op start in AML
+ * Op - Current Op
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Get arguments for passed Op.
+ *
+ ******************************************************************************/
- acpi_ps_append_arg(acpi_ps_get_parent_scope
- (parser_state), op);
+static acpi_status
+acpi_ps_get_arguments(struct acpi_walk_state *walk_state,
+ u8 * aml_op_start, union acpi_parse_object *op)
+{
+ acpi_status status = AE_OK;
+ union acpi_parse_object *arg = NULL;
- if ((walk_state->descending_callback != NULL)) {
- /*
- * Find the object. This will either insert the object into
- * the namespace or simply look it up
- */
- walk_state->op = op;
+ ACPI_FUNCTION_TRACE_PTR(ps_get_arguments, walk_state);
- status =
- walk_state->
- descending_callback(walk_state,
- &op);
- status =
- acpi_ps_next_parse_state(walk_state,
- op,
- status);
- if (status == AE_CTRL_PENDING) {
- status = AE_OK;
- goto close_this_op;
- }
+ switch (op->common.aml_opcode) {
+ case AML_BYTE_OP: /* AML_BYTEDATA_ARG */
+ case AML_WORD_OP: /* AML_WORDDATA_ARG */
+ case AML_DWORD_OP: /* AML_DWORDATA_ARG */
+ case AML_QWORD_OP: /* AML_QWORDATA_ARG */
+ case AML_STRING_OP: /* AML_ASCIICHARLIST_ARG */
- if (ACPI_FAILURE(status)) {
- goto close_this_op;
- }
- }
- }
+ /* Fill in constant or string argument directly */
- op->common.aml_offset = walk_state->aml_offset;
+ acpi_ps_get_next_simple_arg(&(walk_state->parser_state),
+ GET_CURRENT_ARG_TYPE(walk_state->
+ arg_types),
+ op);
+ break;
- if (walk_state->op_info) {
- ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
- "Opcode %4.4X [%s] Op %p Aml %p AmlOffset %5.5X\n",
- (u32) op->common.aml_opcode,
- walk_state->op_info->name, op,
- parser_state->aml,
- op->common.aml_offset));
- }
+ case AML_INT_NAMEPATH_OP: /* AML_NAMESTRING_ARG */
+
+ status =
+ acpi_ps_get_next_namepath(walk_state,
+ &(walk_state->parser_state), op,
+ 1);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
}
+ walk_state->arg_types = 0;
+ break;
+
+ default:
/*
- * Start arg_count at zero because we don't know if there are
- * any args yet
+ * Op is not a constant or string, append each argument to the Op
*/
- walk_state->arg_count = 0;
-
- /* Are there any arguments that must be processed? */
-
- if (walk_state->arg_types) {
-
- /* Get arguments */
-
- switch (op->common.aml_opcode) {
- case AML_BYTE_OP: /* AML_BYTEDATA_ARG */
- case AML_WORD_OP: /* AML_WORDDATA_ARG */
- case AML_DWORD_OP: /* AML_DWORDATA_ARG */
- case AML_QWORD_OP: /* AML_QWORDATA_ARG */
- case AML_STRING_OP: /* AML_ASCIICHARLIST_ARG */
-
- /* Fill in constant or string argument directly */
-
- acpi_ps_get_next_simple_arg(parser_state,
- GET_CURRENT_ARG_TYPE
- (walk_state->
- arg_types), op);
- break;
-
- case AML_INT_NAMEPATH_OP: /* AML_NAMESTRING_ARG */
-
- status =
- acpi_ps_get_next_namepath(walk_state,
- parser_state, op,
- 1);
- if (ACPI_FAILURE(status)) {
- goto close_this_op;
- }
-
- walk_state->arg_types = 0;
- break;
+ while (GET_CURRENT_ARG_TYPE(walk_state->arg_types)
+ && !walk_state->arg_count) {
+ walk_state->aml_offset =
+ (u32) ACPI_PTR_DIFF(walk_state->parser_state.aml,
+ walk_state->parser_state.
+ aml_start);
- default:
- /*
- * Op is not a constant or string, append each argument
- * to the Op
- */
- while (GET_CURRENT_ARG_TYPE
- (walk_state->arg_types)
- && !walk_state->arg_count) {
- walk_state->aml_offset = (u32)
- ACPI_PTR_DIFF(parser_state->aml,
- parser_state->
- aml_start);
+ status =
+ acpi_ps_get_next_arg(walk_state,
+ &(walk_state->parser_state),
+ GET_CURRENT_ARG_TYPE
+ (walk_state->arg_types), &arg);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
- status =
- acpi_ps_get_next_arg(walk_state,
- parser_state,
- GET_CURRENT_ARG_TYPE
- (walk_state->
- arg_types),
- &arg);
- if (ACPI_FAILURE(status)) {
- goto close_this_op;
- }
+ if (arg) {
+ arg->common.aml_offset = walk_state->aml_offset;
+ acpi_ps_append_arg(op, arg);
+ }
- if (arg) {
- arg->common.aml_offset =
- walk_state->aml_offset;
- acpi_ps_append_arg(op, arg);
- }
- INCREMENT_ARG_LIST(walk_state->
- arg_types);
- }
+ INCREMENT_ARG_LIST(walk_state->arg_types);
+ }
- /* Special processing for certain opcodes */
+ /* Special processing for certain opcodes */
- /* TBD (remove): Temporary mechanism to disable this code if needed */
+ /* TBD (remove): Temporary mechanism to disable this code if needed */
#ifdef ACPI_ENABLE_MODULE_LEVEL_CODE
- if ((walk_state->pass_number <=
- ACPI_IMODE_LOAD_PASS1)
- &&
- ((walk_state->
- parse_flags & ACPI_PARSE_DISASSEMBLE) ==
- 0)) {
- /*
- * We want to skip If/Else/While constructs during Pass1
- * because we want to actually conditionally execute the
- * code during Pass2.
- *
- * Except for disassembly, where we always want to
- * walk the If/Else/While packages
- */
- switch (op->common.aml_opcode) {
- case AML_IF_OP:
- case AML_ELSE_OP:
- case AML_WHILE_OP:
-
- ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
- "Pass1: Skipping an If/Else/While body\n"));
-
- /* Skip body of if/else/while in pass 1 */
-
- parser_state->aml =
- parser_state->pkg_end;
- walk_state->arg_count = 0;
- break;
-
- default:
- break;
- }
- }
-#endif
- switch (op->common.aml_opcode) {
- case AML_METHOD_OP:
-
- /*
- * Skip parsing of control method
- * because we don't have enough info in the first pass
- * to parse it correctly.
- *
- * Save the length and address of the body
- */
- op->named.data = parser_state->aml;
- op->named.length =
- (u32) (parser_state->pkg_end -
- parser_state->aml);
-
- /* Skip body of method */
-
- parser_state->aml =
- parser_state->pkg_end;
- walk_state->arg_count = 0;
- break;
-
- case AML_BUFFER_OP:
- case AML_PACKAGE_OP:
- case AML_VAR_PACKAGE_OP:
-
- if ((op->common.parent) &&
- (op->common.parent->common.
- aml_opcode == AML_NAME_OP)
- && (walk_state->pass_number <=
- ACPI_IMODE_LOAD_PASS2)) {
- /*
- * Skip parsing of Buffers and Packages
- * because we don't have enough info in the first pass
- * to parse them correctly.
- */
- op->named.data = aml_op_start;
- op->named.length =
- (u32) (parser_state->
- pkg_end -
- aml_op_start);
-
- /* Skip body */
-
- parser_state->aml =
- parser_state->pkg_end;
- walk_state->arg_count = 0;
- }
- break;
+ if ((walk_state->pass_number <= ACPI_IMODE_LOAD_PASS1) &&
+ ((walk_state->parse_flags & ACPI_PARSE_DISASSEMBLE) == 0)) {
+ /*
+ * We want to skip If/Else/While constructs during Pass1 because we
+ * want to actually conditionally execute the code during Pass2.
+ *
+ * Except for disassembly, where we always want to walk the
+ * If/Else/While packages
+ */
+ switch (op->common.aml_opcode) {
+ case AML_IF_OP:
+ case AML_ELSE_OP:
+ case AML_WHILE_OP:
- case AML_WHILE_OP:
+ ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
+ "Pass1: Skipping an If/Else/While body\n"));
- if (walk_state->control_state) {
- walk_state->control_state->
- control.package_end =
- parser_state->pkg_end;
- }
- break;
+ /* Skip body of if/else/while in pass 1 */
- default:
+ walk_state->parser_state.aml =
+ walk_state->parser_state.pkg_end;
+ walk_state->arg_count = 0;
+ break;
- /* No action for all other opcodes */
- break;
- }
+ default:
break;
}
}
+#endif
- /* Check for arguments that need to be processed */
-
- if (walk_state->arg_count) {
+ switch (op->common.aml_opcode) {
+ case AML_METHOD_OP:
/*
- * There are arguments (complex ones), push Op and
- * prepare for argument
+ * Skip parsing of control method because we don't have enough
+ * info in the first pass to parse it correctly.
+ *
+ * Save the length and address of the body
*/
- status = acpi_ps_push_scope(parser_state, op,
- walk_state->arg_types,
- walk_state->arg_count);
- if (ACPI_FAILURE(status)) {
- goto close_this_op;
- }
- op = NULL;
- continue;
- }
+ op->named.data = walk_state->parser_state.aml;
+ op->named.length = (u32)
+ (walk_state->parser_state.pkg_end -
+ walk_state->parser_state.aml);
- /*
- * All arguments have been processed -- Op is complete,
- * prepare for next
- */
- walk_state->op_info =
- acpi_ps_get_opcode_info(op->common.aml_opcode);
- if (walk_state->op_info->flags & AML_NAMED) {
- if (acpi_gbl_depth) {
- acpi_gbl_depth--;
- }
+ /* Skip body of method */
- if (op->common.aml_opcode == AML_REGION_OP) {
+ walk_state->parser_state.aml =
+ walk_state->parser_state.pkg_end;
+ walk_state->arg_count = 0;
+ break;
+
+ case AML_BUFFER_OP:
+ case AML_PACKAGE_OP:
+ case AML_VAR_PACKAGE_OP:
+
+ if ((op->common.parent) &&
+ (op->common.parent->common.aml_opcode ==
+ AML_NAME_OP)
+ && (walk_state->pass_number <=
+ ACPI_IMODE_LOAD_PASS2)) {
/*
- * Skip parsing of control method or opregion body,
- * because we don't have enough info in the first pass
- * to parse them correctly.
- *
- * Completed parsing an op_region declaration, we now
- * know the length.
+ * Skip parsing of Buffers and Packages because we don't have
+ * enough info in the first pass to parse them correctly.
*/
- op->named.length =
- (u32) (parser_state->aml - op->named.data);
- }
- }
+ op->named.data = aml_op_start;
+ op->named.length = (u32)
+ (walk_state->parser_state.pkg_end -
+ aml_op_start);
- if (walk_state->op_info->flags & AML_CREATE) {
- /*
- * Backup to beginning of create_xXXfield declaration (1 for
- * Opcode)
- *
- * body_length is unknown until we parse the body
- */
- op->named.length =
- (u32) (parser_state->aml - op->named.data);
- }
+ /* Skip body */
- /* This op complete, notify the dispatcher */
+ walk_state->parser_state.aml =
+ walk_state->parser_state.pkg_end;
+ walk_state->arg_count = 0;
+ }
+ break;
- if (walk_state->ascending_callback != NULL) {
- walk_state->op = op;
- walk_state->opcode = op->common.aml_opcode;
+ case AML_WHILE_OP:
- status = walk_state->ascending_callback(walk_state);
- status =
- acpi_ps_next_parse_state(walk_state, op, status);
- if (status == AE_CTRL_PENDING) {
- status = AE_OK;
- goto close_this_op;
+ if (walk_state->control_state) {
+ walk_state->control_state->control.package_end =
+ walk_state->parser_state.pkg_end;
}
- }
-
- close_this_op:
- /*
- * Finished one argument of the containing scope
- */
- parser_state->scope->parse_scope.arg_count--;
+ break;
- /* Finished with pre_op */
+ default:
- if (pre_op) {
- acpi_ps_free_op(pre_op);
- pre_op = NULL;
+ /* No action for all other opcodes */
+ break;
}
- /* Close this Op (will result in parse subtree deletion) */
+ break;
+ }
- status2 = acpi_ps_complete_this_op(walk_state, op);
- if (ACPI_FAILURE(status2)) {
- return_ACPI_STATUS(status2);
- }
- op = NULL;
+ return_ACPI_STATUS(AE_OK);
+}
- switch (status) {
- case AE_OK:
- break;
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_complete_op
+ *
+ * PARAMETERS: walk_state - Current state
+ * Op - Returned Op
+ * Status - Parse status before complete Op
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Complete Op
+ *
+ ******************************************************************************/
- case AE_CTRL_TRANSFER:
+static acpi_status
+acpi_ps_complete_op(struct acpi_walk_state *walk_state,
+ union acpi_parse_object **op, acpi_status status)
+{
+ acpi_status status2;
- /* We are about to transfer to a called method. */
+ ACPI_FUNCTION_TRACE_PTR(ps_complete_op, walk_state);
- walk_state->prev_op = op;
- walk_state->prev_arg_types = walk_state->arg_types;
- return_ACPI_STATUS(status);
+ /*
+ * Finished one argument of the containing scope
+ */
+ walk_state->parser_state.scope->parse_scope.arg_count--;
- case AE_CTRL_END:
+ /* Close this Op (will result in parse subtree deletion) */
- acpi_ps_pop_scope(parser_state, &op,
- &walk_state->arg_types,
- &walk_state->arg_count);
+ status2 = acpi_ps_complete_this_op(walk_state, *op);
+ if (ACPI_FAILURE(status2)) {
+ return_ACPI_STATUS(status2);
+ }
- if (op) {
- walk_state->op = op;
- walk_state->op_info =
- acpi_ps_get_opcode_info(op->common.
- aml_opcode);
- walk_state->opcode = op->common.aml_opcode;
+ *op = NULL;
- status =
- walk_state->ascending_callback(walk_state);
- status =
- acpi_ps_next_parse_state(walk_state, op,
- status);
+ switch (status) {
+ case AE_OK:
+ break;
- status2 =
- acpi_ps_complete_this_op(walk_state, op);
- if (ACPI_FAILURE(status2)) {
- return_ACPI_STATUS(status2);
- }
- op = NULL;
- }
- status = AE_OK;
- break;
+ case AE_CTRL_TRANSFER:
- case AE_CTRL_BREAK:
- case AE_CTRL_CONTINUE:
+ /* We are about to transfer to a called method */
- /* Pop off scopes until we find the While */
+ walk_state->prev_op = NULL;
+ walk_state->prev_arg_types = walk_state->arg_types;
+ return_ACPI_STATUS(status);
- while (!op || (op->common.aml_opcode != AML_WHILE_OP)) {
- acpi_ps_pop_scope(parser_state, &op,
- &walk_state->arg_types,
- &walk_state->arg_count);
+ case AE_CTRL_END:
- if (op->common.aml_opcode != AML_WHILE_OP) {
- status2 =
- acpi_ds_result_stack_pop
- (walk_state);
- if (ACPI_FAILURE(status2)) {
- return_ACPI_STATUS(status2);
- }
- }
- }
-
- /* Close this iteration of the While loop */
+ acpi_ps_pop_scope(&(walk_state->parser_state), op,
+ &walk_state->arg_types,
+ &walk_state->arg_count);
- walk_state->op = op;
+ if (*op) {
+ walk_state->op = *op;
walk_state->op_info =
- acpi_ps_get_opcode_info(op->common.aml_opcode);
- walk_state->opcode = op->common.aml_opcode;
+ acpi_ps_get_opcode_info((*op)->common.aml_opcode);
+ walk_state->opcode = (*op)->common.aml_opcode;
status = walk_state->ascending_callback(walk_state);
status =
- acpi_ps_next_parse_state(walk_state, op, status);
+ acpi_ps_next_parse_state(walk_state, *op, status);
- status2 = acpi_ps_complete_this_op(walk_state, op);
+ status2 = acpi_ps_complete_this_op(walk_state, *op);
if (ACPI_FAILURE(status2)) {
return_ACPI_STATUS(status2);
}
- op = NULL;
-
- status = AE_OK;
- break;
+ }
- case AE_CTRL_TERMINATE:
+ status = AE_OK;
+ break;
- status = AE_OK;
+ case AE_CTRL_BREAK:
+ case AE_CTRL_CONTINUE:
- /* Clean up */
- do {
- if (op) {
- status2 =
- acpi_ps_complete_this_op(walk_state,
- op);
- if (ACPI_FAILURE(status2)) {
- return_ACPI_STATUS(status2);
- }
+ /* Pop off scopes until we find the While */
- status2 =
- acpi_ds_result_stack_pop
- (walk_state);
- if (ACPI_FAILURE(status2)) {
- return_ACPI_STATUS(status2);
- }
+ while (!(*op) || ((*op)->common.aml_opcode != AML_WHILE_OP)) {
+ acpi_ps_pop_scope(&(walk_state->parser_state), op,
+ &walk_state->arg_types,
+ &walk_state->arg_count);
- acpi_ut_delete_generic_state
- (acpi_ut_pop_generic_state
- (&walk_state->control_state));
+ if ((*op)->common.aml_opcode != AML_WHILE_OP) {
+ status2 = acpi_ds_result_stack_pop(walk_state);
+ if (ACPI_FAILURE(status2)) {
+ return_ACPI_STATUS(status2);
}
+ }
+ }
- acpi_ps_pop_scope(parser_state, &op,
- &walk_state->arg_types,
- &walk_state->arg_count);
+ /* Close this iteration of the While loop */
- } while (op);
+ walk_state->op = *op;
+ walk_state->op_info =
+ acpi_ps_get_opcode_info((*op)->common.aml_opcode);
+ walk_state->opcode = (*op)->common.aml_opcode;
- return_ACPI_STATUS(status);
+ status = walk_state->ascending_callback(walk_state);
+ status = acpi_ps_next_parse_state(walk_state, *op, status);
- default: /* All other non-AE_OK status */
+ status2 = acpi_ps_complete_this_op(walk_state, *op);
+ if (ACPI_FAILURE(status2)) {
+ return_ACPI_STATUS(status2);
+ }
- do {
- if (op) {
- status2 =
- acpi_ps_complete_this_op(walk_state,
- op);
- if (ACPI_FAILURE(status2)) {
- return_ACPI_STATUS(status2);
- }
+ status = AE_OK;
+ break;
+
+ case AE_CTRL_TERMINATE:
+
+ /* Clean up */
+ do {
+ if (*op) {
+ status2 =
+ acpi_ps_complete_this_op(walk_state, *op);
+ if (ACPI_FAILURE(status2)) {
+ return_ACPI_STATUS(status2);
+ }
+ status2 = acpi_ds_result_stack_pop(walk_state);
+ if (ACPI_FAILURE(status2)) {
+ return_ACPI_STATUS(status2);
}
- acpi_ps_pop_scope(parser_state, &op,
- &walk_state->arg_types,
- &walk_state->arg_count);
+ acpi_ut_delete_generic_state
+ (acpi_ut_pop_generic_state
+ (&walk_state->control_state));
+ }
- } while (op);
+ acpi_ps_pop_scope(&(walk_state->parser_state), op,
+ &walk_state->arg_types,
+ &walk_state->arg_count);
- /*
- * TBD: Cleanup parse ops on error
- */
-#if 0
- if (op == NULL) {
- acpi_ps_pop_scope(parser_state, &op,
- &walk_state->arg_types,
- &walk_state->arg_count);
+ } while (*op);
+
+ return_ACPI_STATUS(AE_OK);
+
+ default: /* All other non-AE_OK status */
+
+ do {
+ if (*op) {
+ status2 =
+ acpi_ps_complete_this_op(walk_state, *op);
+ if (ACPI_FAILURE(status2)) {
+ return_ACPI_STATUS(status2);
+ }
}
-#endif
- walk_state->prev_op = op;
- walk_state->prev_arg_types = walk_state->arg_types;
- return_ACPI_STATUS(status);
- }
- /* This scope complete? */
+ acpi_ps_pop_scope(&(walk_state->parser_state), op,
+ &walk_state->arg_types,
+ &walk_state->arg_count);
- if (acpi_ps_has_completed_scope(parser_state)) {
- acpi_ps_pop_scope(parser_state, &op,
+ } while (*op);
+
+#if 0
+ /*
+ * TBD: Cleanup parse ops on error
+ */
+ if (*op == NULL) {
+ acpi_ps_pop_scope(parser_state, op,
&walk_state->arg_types,
&walk_state->arg_count);
- ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
- "Popped scope, Op=%p\n", op));
- } else {
- op = NULL;
}
+#endif
+ walk_state->prev_op = NULL;
+ walk_state->prev_arg_types = walk_state->arg_types;
+ return_ACPI_STATUS(status);
+ }
- } /* while parser_state->Aml */
+ /* This scope complete? */
+
+ if (acpi_ps_has_completed_scope(&(walk_state->parser_state))) {
+ acpi_ps_pop_scope(&(walk_state->parser_state), op,
+ &walk_state->arg_types,
+ &walk_state->arg_count);
+ ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "Popped scope, Op=%p\n", *op));
+ } else {
+ *op = NULL;
+ }
+
+ return_ACPI_STATUS(AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_complete_final_op
+ *
+ * PARAMETERS: walk_state - Current state
+ * Op - Current Op
+ * Status - Current parse status before complete last
+ * Op
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Complete last Op.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ps_complete_final_op(struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op, acpi_status status)
+{
+ acpi_status status2;
+
+ ACPI_FUNCTION_TRACE_PTR(ps_complete_final_op, walk_state);
/*
* Complete the last Op (if not completed), and clear the scope stack.
* It is easily possible to end an AML "package" with an unbounded number
* of open scopes (such as when several ASL blocks are closed with
- * sequential closing braces). We want to terminate each one cleanly.
+ * sequential closing braces). We want to terminate each one cleanly.
*/
ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "AML package complete at Op %p\n",
op));
@@ -838,8 +750,12 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state)
acpi_ps_next_parse_state(walk_state, op,
status);
if (status == AE_CTRL_PENDING) {
- status = AE_OK;
- goto close_this_op;
+ status =
+ acpi_ps_complete_op(walk_state, &op,
+ AE_OK);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
}
if (status == AE_CTRL_TERMINATE) {
@@ -858,7 +774,9 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state)
}
}
- acpi_ps_pop_scope(parser_state,
+ acpi_ps_pop_scope(&
+ (walk_state->
+ parser_state),
&op,
&walk_state->
arg_types,
@@ -887,10 +805,252 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state)
}
}
- acpi_ps_pop_scope(parser_state, &op, &walk_state->arg_types,
+ acpi_ps_pop_scope(&(walk_state->parser_state), &op,
+ &walk_state->arg_types,
&walk_state->arg_count);
} while (op);
return_ACPI_STATUS(status);
}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_parse_loop
+ *
+ * PARAMETERS: walk_state - Current state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Parse AML (pointed to by the current parser state) and return
+ * a tree of ops.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state)
+{
+ acpi_status status = AE_OK;
+ union acpi_parse_object *op = NULL; /* current op */
+ struct acpi_parse_state *parser_state;
+ u8 *aml_op_start = NULL;
+
+ ACPI_FUNCTION_TRACE_PTR(ps_parse_loop, walk_state);
+
+ if (walk_state->descending_callback == NULL) {
+ return_ACPI_STATUS(AE_BAD_PARAMETER);
+ }
+
+ parser_state = &walk_state->parser_state;
+ walk_state->arg_types = 0;
+
+#if (!defined (ACPI_NO_METHOD_EXECUTION) && !defined (ACPI_CONSTANT_EVAL_ONLY))
+
+ if (walk_state->walk_type & ACPI_WALK_METHOD_RESTART) {
+
+ /* We are restarting a preempted control method */
+
+ if (acpi_ps_has_completed_scope(parser_state)) {
+ /*
+ * We must check if a predicate to an IF or WHILE statement
+ * was just completed
+ */
+ if ((parser_state->scope->parse_scope.op) &&
+ ((parser_state->scope->parse_scope.op->common.
+ aml_opcode == AML_IF_OP)
+ || (parser_state->scope->parse_scope.op->common.
+ aml_opcode == AML_WHILE_OP))
+ && (walk_state->control_state)
+ && (walk_state->control_state->common.state ==
+ ACPI_CONTROL_PREDICATE_EXECUTING)) {
+ /*
+ * A predicate was just completed, get the value of the
+ * predicate and branch based on that value
+ */
+ walk_state->op = NULL;
+ status =
+ acpi_ds_get_predicate_value(walk_state,
+ ACPI_TO_POINTER
+ (TRUE));
+ if (ACPI_FAILURE(status)
+ && ((status & AE_CODE_MASK) !=
+ AE_CODE_CONTROL)) {
+ if (status == AE_AML_NO_RETURN_VALUE) {
+ ACPI_EXCEPTION((AE_INFO, status,
+ "Invoked method did not return a value"));
+
+ }
+
+ ACPI_EXCEPTION((AE_INFO, status,
+ "GetPredicate Failed"));
+ return_ACPI_STATUS(status);
+ }
+
+ status =
+ acpi_ps_next_parse_state(walk_state, op,
+ status);
+ }
+
+ acpi_ps_pop_scope(parser_state, &op,
+ &walk_state->arg_types,
+ &walk_state->arg_count);
+ ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
+ "Popped scope, Op=%p\n", op));
+ } else if (walk_state->prev_op) {
+
+ /* We were in the middle of an op */
+
+ op = walk_state->prev_op;
+ walk_state->arg_types = walk_state->prev_arg_types;
+ }
+ }
+#endif
+
+ /* Iterative parsing loop, while there is more AML to process: */
+
+ while ((parser_state->aml < parser_state->aml_end) || (op)) {
+ aml_op_start = parser_state->aml;
+ if (!op) {
+ status =
+ acpi_ps_create_op(walk_state, aml_op_start, &op);
+ if (ACPI_FAILURE(status)) {
+ if (status == AE_CTRL_PARSE_CONTINUE) {
+ continue;
+ }
+
+ if (status == AE_CTRL_PARSE_PENDING) {
+ status = AE_OK;
+ }
+
+ status =
+ acpi_ps_complete_op(walk_state, &op,
+ status);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ continue;
+ }
+
+ op->common.aml_offset = walk_state->aml_offset;
+
+ if (walk_state->op_info) {
+ ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
+ "Opcode %4.4X [%s] Op %p Aml %p AmlOffset %5.5X\n",
+ (u32) op->common.aml_opcode,
+ walk_state->op_info->name, op,
+ parser_state->aml,
+ op->common.aml_offset));
+ }
+ }
+
+ /*
+ * Start arg_count at zero because we don't know if there are
+ * any args yet
+ */
+ walk_state->arg_count = 0;
+
+ /* Are there any arguments that must be processed? */
+
+ if (walk_state->arg_types) {
+
+ /* Get arguments */
+
+ status =
+ acpi_ps_get_arguments(walk_state, aml_op_start, op);
+ if (ACPI_FAILURE(status)) {
+ status =
+ acpi_ps_complete_op(walk_state, &op,
+ status);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ continue;
+ }
+ }
+
+ /* Check for arguments that need to be processed */
+
+ if (walk_state->arg_count) {
+ /*
+ * There are arguments (complex ones), push Op and
+ * prepare for argument
+ */
+ status = acpi_ps_push_scope(parser_state, op,
+ walk_state->arg_types,
+ walk_state->arg_count);
+ if (ACPI_FAILURE(status)) {
+ status =
+ acpi_ps_complete_op(walk_state, &op,
+ status);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ continue;
+ }
+
+ op = NULL;
+ continue;
+ }
+
+ /*
+ * All arguments have been processed -- Op is complete,
+ * prepare for next
+ */
+ walk_state->op_info =
+ acpi_ps_get_opcode_info(op->common.aml_opcode);
+ if (walk_state->op_info->flags & AML_NAMED) {
+ if (acpi_gbl_depth) {
+ acpi_gbl_depth--;
+ }
+
+ if (op->common.aml_opcode == AML_REGION_OP) {
+ /*
+ * Skip parsing of control method or opregion body,
+ * because we don't have enough info in the first pass
+ * to parse them correctly.
+ *
+ * Completed parsing an op_region declaration, we now
+ * know the length.
+ */
+ op->named.length =
+ (u32) (parser_state->aml - op->named.data);
+ }
+ }
+
+ if (walk_state->op_info->flags & AML_CREATE) {
+ /*
+ * Backup to beginning of create_xXXfield declaration (1 for
+ * Opcode)
+ *
+ * body_length is unknown until we parse the body
+ */
+ op->named.length =
+ (u32) (parser_state->aml - op->named.data);
+ }
+
+ /* This op complete, notify the dispatcher */
+
+ if (walk_state->ascending_callback != NULL) {
+ walk_state->op = op;
+ walk_state->opcode = op->common.aml_opcode;
+
+ status = walk_state->ascending_callback(walk_state);
+ status =
+ acpi_ps_next_parse_state(walk_state, op, status);
+ if (status == AE_CTRL_PENDING) {
+ status = AE_OK;
+ }
+ }
+
+ status = acpi_ps_complete_op(walk_state, &op, status);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ } /* while parser_state->Aml */
+
+ status = acpi_ps_complete_final_op(walk_state, op, status);
+ return_ACPI_STATUS(status);
+}
diff --git a/drivers/acpi/parser/psopcode.c b/drivers/acpi/parser/psopcode.c
index 4bd25e32769..16d8b6cc3c2 100644
--- a/drivers/acpi/parser/psopcode.c
+++ b/drivers/acpi/parser/psopcode.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/parser/psparse.c b/drivers/acpi/parser/psparse.c
index a02aa62fe1e..5d63f48e56b 100644
--- a/drivers/acpi/parser/psparse.c
+++ b/drivers/acpi/parser/psparse.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -540,6 +540,11 @@ acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state)
if ((status == AE_ALREADY_EXISTS) &&
(!walk_state->method_desc->method.mutex)) {
+ ACPI_INFO((AE_INFO,
+ "Marking method %4.4s as Serialized",
+ walk_state->method_node->name.
+ ascii));
+
/*
* Method tried to create an object twice. The probable cause is
* that the method cannot handle reentrancy.
diff --git a/drivers/acpi/parser/psscope.c b/drivers/acpi/parser/psscope.c
index a3e0314de24..77cfa4ed0cf 100644
--- a/drivers/acpi/parser/psscope.c
+++ b/drivers/acpi/parser/psscope.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/parser/pstree.c b/drivers/acpi/parser/pstree.c
index 0015717ef09..966e7ea2a0c 100644
--- a/drivers/acpi/parser/pstree.c
+++ b/drivers/acpi/parser/pstree.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/parser/psutils.c b/drivers/acpi/parser/psutils.c
index d405387b741..8ca52002db5 100644
--- a/drivers/acpi/parser/psutils.c
+++ b/drivers/acpi/parser/psutils.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/parser/pswalk.c b/drivers/acpi/parser/pswalk.c
index a84a547a0f1..49f9757434e 100644
--- a/drivers/acpi/parser/pswalk.c
+++ b/drivers/acpi/parser/pswalk.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/parser/psxface.c b/drivers/acpi/parser/psxface.c
index 5d996c1140a..94103bced75 100644
--- a/drivers/acpi/parser/psxface.c
+++ b/drivers/acpi/parser/psxface.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -54,8 +54,6 @@ static void acpi_ps_start_trace(struct acpi_evaluate_info *info);
static void acpi_ps_stop_trace(struct acpi_evaluate_info *info);
-static acpi_status acpi_ps_execute_pass(struct acpi_evaluate_info *info);
-
static void
acpi_ps_update_parameter_list(struct acpi_evaluate_info *info, u16 action);
@@ -215,6 +213,8 @@ static void acpi_ps_stop_trace(struct acpi_evaluate_info *info)
acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info)
{
acpi_status status;
+ union acpi_parse_object *op;
+ struct acpi_walk_state *walk_state;
ACPI_FUNCTION_TRACE(ps_execute_method);
@@ -234,8 +234,7 @@ acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info)
}
/*
- * The caller "owns" the parameters, so give each one an extra
- * reference
+ * The caller "owns" the parameters, so give each one an extra reference
*/
acpi_ps_update_parameter_list(info, REF_INCREMENT);
@@ -244,30 +243,50 @@ acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info)
acpi_ps_start_trace(info);
/*
- * 1) Perform the first pass parse of the method to enter any
- * named objects that it creates into the namespace
+ * Execute the method. Performs parse simultaneously
*/
ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
- "**** Begin Method Parse **** Entry=%p obj=%p\n",
- info->resolved_node, info->obj_desc));
+ "**** Begin Method Parse/Execute [%4.4s] **** Node=%p Obj=%p\n",
+ info->resolved_node->name.ascii, info->resolved_node,
+ info->obj_desc));
+
+ /* Create and init a Root Node */
+
+ op = acpi_ps_create_scope_op();
+ if (!op) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ /* Create and initialize a new walk state */
+
+ info->pass_number = ACPI_IMODE_EXECUTE;
+ walk_state =
+ acpi_ds_create_walk_state(info->obj_desc->method.owner_id, NULL,
+ NULL, NULL);
+ if (!walk_state) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
- info->pass_number = 1;
- status = acpi_ps_execute_pass(info);
+ status = acpi_ds_init_aml_walk(walk_state, op, info->resolved_node,
+ info->obj_desc->method.aml_start,
+ info->obj_desc->method.aml_length, info,
+ info->pass_number);
if (ACPI_FAILURE(status)) {
+ acpi_ds_delete_walk_state(walk_state);
goto cleanup;
}
- /*
- * 2) Execute the method. Performs second pass parse simultaneously
- */
- ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
- "**** Begin Method Execution **** Entry=%p obj=%p\n",
- info->resolved_node, info->obj_desc));
+ /* Parse the AML */
- info->pass_number = 3;
- status = acpi_ps_execute_pass(info);
+ status = acpi_ps_parse_aml(walk_state);
+
+ /* walk_state was deleted by parse_aml */
cleanup:
+ acpi_ps_delete_parse_tree(op);
+
/* End optional tracing */
acpi_ps_stop_trace(info);
@@ -330,62 +349,3 @@ acpi_ps_update_parameter_list(struct acpi_evaluate_info *info, u16 action)
}
}
}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ps_execute_pass
- *
- * PARAMETERS: Info - See struct acpi_evaluate_info
- * (Used: pass_number, Node, and obj_desc)
- *
- * RETURN: Status
- *
- * DESCRIPTION: Single AML pass: Parse or Execute a control method
- *
- ******************************************************************************/
-
-static acpi_status acpi_ps_execute_pass(struct acpi_evaluate_info *info)
-{
- acpi_status status;
- union acpi_parse_object *op;
- struct acpi_walk_state *walk_state;
-
- ACPI_FUNCTION_TRACE(ps_execute_pass);
-
- /* Create and init a Root Node */
-
- op = acpi_ps_create_scope_op();
- if (!op) {
- return_ACPI_STATUS(AE_NO_MEMORY);
- }
-
- /* Create and initialize a new walk state */
-
- walk_state =
- acpi_ds_create_walk_state(info->obj_desc->method.owner_id, NULL,
- NULL, NULL);
- if (!walk_state) {
- status = AE_NO_MEMORY;
- goto cleanup;
- }
-
- status = acpi_ds_init_aml_walk(walk_state, op, info->resolved_node,
- info->obj_desc->method.aml_start,
- info->obj_desc->method.aml_length,
- info->pass_number == 1 ? NULL : info,
- info->pass_number);
- if (ACPI_FAILURE(status)) {
- acpi_ds_delete_walk_state(walk_state);
- goto cleanup;
- }
-
- /* Parse the AML */
-
- status = acpi_ps_parse_aml(walk_state);
-
- /* Walk state was deleted by parse_aml */
-
- cleanup:
- acpi_ps_delete_parse_tree(op);
- return_ACPI_STATUS(status);
-}
diff --git a/drivers/acpi/pci_bind.c b/drivers/acpi/pci_bind.c
index 55f57a61c55..028969370bb 100644
--- a/drivers/acpi/pci_bind.c
+++ b/drivers/acpi/pci_bind.c
@@ -36,7 +36,7 @@
#include <acpi/acpi_drivers.h>
#define _COMPONENT ACPI_PCI_COMPONENT
-ACPI_MODULE_NAME("pci_bind")
+ACPI_MODULE_NAME("pci_bind");
struct acpi_pci_data {
struct acpi_pci_id id;
diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c
index fe7d007833a..dd3186abe07 100644
--- a/drivers/acpi/pci_irq.c
+++ b/drivers/acpi/pci_irq.c
@@ -38,7 +38,7 @@
#include <acpi/acpi_drivers.h>
#define _COMPONENT ACPI_PCI_COMPONENT
-ACPI_MODULE_NAME("pci_irq")
+ACPI_MODULE_NAME("pci_irq");
static struct acpi_prt_list acpi_prt;
static DEFINE_SPINLOCK(acpi_prt_lock);
diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c
index 481e633bbf4..acc59477137 100644
--- a/drivers/acpi/pci_link.c
+++ b/drivers/acpi/pci_link.c
@@ -44,10 +44,9 @@
#include <acpi/acpi_drivers.h>
#define _COMPONENT ACPI_PCI_COMPONENT
-ACPI_MODULE_NAME("pci_link")
+ACPI_MODULE_NAME("pci_link");
#define ACPI_PCI_LINK_CLASS "pci_irq_routing"
#define ACPI_PCI_LINK_HID "PNP0C0F"
-#define ACPI_PCI_LINK_DRIVER_NAME "ACPI PCI Interrupt Link Driver"
#define ACPI_PCI_LINK_DEVICE_NAME "PCI Interrupt Link"
#define ACPI_PCI_LINK_FILE_INFO "info"
#define ACPI_PCI_LINK_FILE_STATUS "state"
@@ -56,7 +55,7 @@ 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_driver acpi_pci_link_driver = {
- .name = ACPI_PCI_LINK_DRIVER_NAME,
+ .name = "pci_link",
.class = ACPI_PCI_LINK_CLASS,
.ids = ACPI_PCI_LINK_HID,
.ops = {
@@ -513,7 +512,7 @@ int __init acpi_irq_penalty_init(void)
}
}
/* Add a penalty for the SCI */
- acpi_irq_penalty[acpi_fadt.sci_int] += PIRQ_PENALTY_PCI_USING;
+ acpi_irq_penalty[acpi_gbl_FADT.sci_interrupt] += PIRQ_PENALTY_PCI_USING;
return 0;
}
@@ -785,7 +784,7 @@ static int irqrouter_resume(struct sys_device *dev)
/* Make sure SCI is enabled again (Apple firmware bug?) */
- acpi_set_register(ACPI_BITREG_SCI_ENABLE, 1, ACPI_MTX_DO_NOT_LOCK);
+ acpi_set_register(ACPI_BITREG_SCI_ENABLE, 1);
list_for_each(node, &acpi_link.entries) {
link = list_entry(node, struct acpi_pci_link, node);
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index a860efa2c56..ad4145a3778 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -36,17 +36,16 @@
#include <acpi/acpi_drivers.h>
#define _COMPONENT ACPI_PCI_COMPONENT
-ACPI_MODULE_NAME("pci_root")
+ACPI_MODULE_NAME("pci_root");
#define ACPI_PCI_ROOT_CLASS "pci_bridge"
#define ACPI_PCI_ROOT_HID "PNP0A03"
-#define ACPI_PCI_ROOT_DRIVER_NAME "ACPI PCI Root Bridge Driver"
#define ACPI_PCI_ROOT_DEVICE_NAME "PCI Root Bridge"
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_driver acpi_pci_root_driver = {
- .name = ACPI_PCI_ROOT_DRIVER_NAME,
+ .name = "pci_root",
.class = ACPI_PCI_ROOT_CLASS,
.ids = ACPI_PCI_ROOT_HID,
.ops = {
@@ -117,6 +116,19 @@ void acpi_pci_unregister_driver(struct acpi_pci_driver *driver)
EXPORT_SYMBOL(acpi_pci_unregister_driver);
+acpi_handle acpi_get_pci_rootbridge_handle(unsigned int seg, unsigned int bus)
+{
+ struct acpi_pci_root *tmp;
+
+ list_for_each_entry(tmp, &acpi_pci_roots, node) {
+ if ((tmp->id.segment == (u16) seg) && (tmp->id.bus == (u16) bus))
+ return tmp->device->handle;
+ }
+ return NULL;
+}
+
+EXPORT_SYMBOL_GPL(acpi_get_pci_rootbridge_handle);
+
static acpi_status
get_root_bridge_busnr_callback(struct acpi_resource *resource, void *data)
{
@@ -152,6 +164,21 @@ static acpi_status try_get_root_bridge_busnr(acpi_handle handle, int *busnum)
return AE_OK;
}
+static void acpi_pci_bridge_scan(struct acpi_device *device)
+{
+ int status;
+ struct acpi_device *child = NULL;
+
+ if (device->flags.bus_address)
+ if (device->parent && device->parent->ops.bind) {
+ status = device->parent->ops.bind(device);
+ if (!status) {
+ list_for_each_entry(child, &device->children, node)
+ acpi_pci_bridge_scan(child);
+ }
+ }
+}
+
static int acpi_pci_root_add(struct acpi_device *device)
{
int result = 0;
@@ -160,6 +187,7 @@ static int acpi_pci_root_add(struct acpi_device *device)
acpi_status status = AE_OK;
unsigned long value = 0;
acpi_handle handle = NULL;
+ struct acpi_device *child;
if (!device)
@@ -175,9 +203,6 @@ static int acpi_pci_root_add(struct acpi_device *device)
strcpy(acpi_device_class(device), ACPI_PCI_ROOT_CLASS);
acpi_driver_data(device) = root;
- /*
- * TBD: Doesn't the bus driver automatically set this?
- */
device->ops.bind = acpi_pci_bind;
/*
@@ -299,6 +324,12 @@ static int acpi_pci_root_add(struct acpi_device *device)
result = acpi_pci_irq_add_prt(device->handle, root->id.segment,
root->id.bus);
+ /*
+ * Scan and bind all _ADR-Based Devices
+ */
+ list_for_each_entry(child, &device->children, node)
+ acpi_pci_bridge_scan(child);
+
end:
if (result) {
if (!list_empty(&root->node))
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
index 0ba7dfbbb2e..1ef338545df 100644
--- a/drivers/acpi/power.c
+++ b/drivers/acpi/power.c
@@ -45,10 +45,9 @@
#include <acpi/acpi_drivers.h>
#define _COMPONENT ACPI_POWER_COMPONENT
-ACPI_MODULE_NAME("acpi_power")
+ACPI_MODULE_NAME("power");
#define ACPI_POWER_COMPONENT 0x00800000
#define ACPI_POWER_CLASS "power_resource"
-#define ACPI_POWER_DRIVER_NAME "ACPI Power Resource Driver"
#define ACPI_POWER_DEVICE_NAME "Power Resource"
#define ACPI_POWER_FILE_INFO "info"
#define ACPI_POWER_FILE_STATUS "state"
@@ -57,25 +56,33 @@ ACPI_MODULE_NAME("acpi_power")
#define ACPI_POWER_RESOURCE_STATE_UNKNOWN 0xFF
static int acpi_power_add(struct acpi_device *device);
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_driver acpi_power_driver = {
- .name = ACPI_POWER_DRIVER_NAME,
+ .name = "power",
.class = ACPI_POWER_CLASS,
.ids = ACPI_POWER_HID,
.ops = {
.add = acpi_power_add,
.remove = acpi_power_remove,
+ .resume = acpi_power_resume,
},
};
+struct acpi_power_reference {
+ struct list_head node;
+ struct acpi_device *device;
+};
+
struct acpi_power_resource {
struct acpi_device * device;
acpi_bus_id name;
u32 system_level;
u32 order;
int state;
- int references;
+ struct mutex resource_lock;
+ struct list_head reference;
};
static struct list_head acpi_power_resource_list;
@@ -171,22 +178,47 @@ static int acpi_power_get_list_state(struct acpi_handle_list *list, int *state)
return result;
}
-static int acpi_power_on(acpi_handle handle)
+static int acpi_power_on(acpi_handle handle, struct acpi_device *dev)
{
int result = 0;
+ int found = 0;
acpi_status status = AE_OK;
- struct acpi_device *device = NULL;
struct acpi_power_resource *resource = NULL;
+ struct list_head *node, *next;
+ struct acpi_power_reference *ref;
result = acpi_power_get_context(handle, &resource);
if (result)
return result;
- resource->references++;
+ mutex_lock(&resource->resource_lock);
+ list_for_each_safe(node, next, &resource->reference) {
+ ref = container_of(node, struct acpi_power_reference, node);
+ if (dev->handle == ref->device->handle) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] already referenced by resource [%s]\n",
+ dev->pnp.bus_id, resource->name));
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ ref = kmalloc(sizeof (struct acpi_power_reference),
+ irqs_disabled() ? GFP_ATOMIC : GFP_KERNEL);
+ if (!ref) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "kmalloc() failed\n"));
+ mutex_unlock(&resource->resource_lock);
+ return -ENOMEM;
+ }
+ list_add_tail(&ref->node, &resource->reference);
+ ref->device = dev;
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] added to resource [%s] references\n",
+ dev->pnp.bus_id, resource->name));
+ }
+ mutex_unlock(&resource->resource_lock);
- if ((resource->references > 1)
- || (resource->state == ACPI_POWER_RESOURCE_STATE_ON)) {
+ if (resource->state == ACPI_POWER_RESOURCE_STATE_ON) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] already on\n",
resource->name));
return 0;
@@ -203,38 +235,49 @@ static int acpi_power_on(acpi_handle handle)
return -ENOEXEC;
/* Update the power resource's _device_ power state */
- device = resource->device;
resource->device->power.state = ACPI_STATE_D0;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] turned on\n",
resource->name));
-
return 0;
}
-static int acpi_power_off_device(acpi_handle handle)
+static int acpi_power_off_device(acpi_handle handle, struct acpi_device *dev)
{
int result = 0;
acpi_status status = AE_OK;
struct acpi_power_resource *resource = NULL;
+ struct list_head *node, *next;
+ struct acpi_power_reference *ref;
+
result = acpi_power_get_context(handle, &resource);
if (result)
return result;
- if (resource->references)
- resource->references--;
+ mutex_lock(&resource->resource_lock);
+ list_for_each_safe(node, next, &resource->reference) {
+ ref = container_of(node, struct acpi_power_reference, node);
+ if (dev->handle == ref->device->handle) {
+ list_del(&ref->node);
+ kfree(ref);
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] removed from resource [%s] references\n",
+ dev->pnp.bus_id, resource->name));
+ break;
+ }
+ }
- if (resource->references) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Resource [%s] is still in use, dereferencing\n",
- resource->device->pnp.bus_id));
+ if (!list_empty(&resource->reference)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Cannot turn resource [%s] off - resource is in use\n",
+ resource->name));
+ mutex_unlock(&resource->resource_lock);
return 0;
}
+ mutex_unlock(&resource->resource_lock);
if (resource->state == ACPI_POWER_RESOURCE_STATE_OFF) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] already off\n",
- resource->device->pnp.bus_id));
+ resource->name));
return 0;
}
@@ -276,7 +319,7 @@ int acpi_enable_wakeup_device_power(struct acpi_device *dev)
arg.integer.value = 1;
/* Open power resource */
for (i = 0; i < dev->wakeup.resources.count; i++) {
- ret = acpi_power_on(dev->wakeup.resources.handles[i]);
+ ret = acpi_power_on(dev->wakeup.resources.handles[i], dev);
if (ret) {
printk(KERN_ERR PREFIX "Transition power state\n");
dev->wakeup.flags.valid = 0;
@@ -323,7 +366,7 @@ int acpi_disable_wakeup_device_power(struct acpi_device *dev)
/* Close power resource */
for (i = 0; i < dev->wakeup.resources.count; i++) {
- ret = acpi_power_off_device(dev->wakeup.resources.handles[i]);
+ ret = acpi_power_off_device(dev->wakeup.resources.handles[i], dev);
if (ret) {
printk(KERN_ERR PREFIX "Transition power state\n");
dev->wakeup.flags.valid = 0;
@@ -407,16 +450,20 @@ int acpi_power_transition(struct acpi_device *device, int state)
* (e.g. so the device doesn't lose power while transitioning).
*/
for (i = 0; i < tl->count; i++) {
- result = acpi_power_on(tl->handles[i]);
+ result = acpi_power_on(tl->handles[i], device);
if (result)
goto end;
}
+ if (device->power.state == state) {
+ goto end;
+ }
+
/*
* Then we dereference all power resources used in the current list.
*/
for (i = 0; i < cl->count; i++) {
- result = acpi_power_off_device(cl->handles[i]);
+ result = acpi_power_off_device(cl->handles[i], device);
if (result)
goto end;
}
@@ -439,7 +486,11 @@ static struct proc_dir_entry *acpi_power_dir;
static int acpi_power_seq_show(struct seq_file *seq, void *offset)
{
+ int count = 0;
+ int result = 0;
struct acpi_power_resource *resource = NULL;
+ struct list_head *node, *next;
+ struct acpi_power_reference *ref;
resource = seq->private;
@@ -447,6 +498,10 @@ static int acpi_power_seq_show(struct seq_file *seq, void *offset)
if (!resource)
goto end;
+ result = acpi_power_get_state(resource);
+ if (result)
+ goto end;
+
seq_puts(seq, "state: ");
switch (resource->state) {
case ACPI_POWER_RESOURCE_STATE_ON:
@@ -460,11 +515,18 @@ static int acpi_power_seq_show(struct seq_file *seq, void *offset)
break;
}
+ mutex_lock(&resource->resource_lock);
+ list_for_each_safe(node, next, &resource->reference) {
+ ref = container_of(node, struct acpi_power_reference, node);
+ count++;
+ }
+ mutex_unlock(&resource->resource_lock);
+
seq_printf(seq, "system level: S%d\n"
"order: %d\n"
"reference count: %d\n",
resource->system_level,
- resource->order, resource->references);
+ resource->order, count);
end:
return 0;
@@ -537,6 +599,8 @@ static int acpi_power_add(struct acpi_device *device)
return -ENOMEM;
resource->device = device;
+ mutex_init(&resource->resource_lock);
+ INIT_LIST_HEAD(&resource->reference);
strcpy(resource->name, device->pnp.bus_id);
strcpy(acpi_device_name(device), ACPI_POWER_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_POWER_CLASS);
@@ -584,6 +648,7 @@ static int acpi_power_add(struct acpi_device *device)
static int acpi_power_remove(struct acpi_device *device, int type)
{
struct acpi_power_resource *resource = NULL;
+ struct list_head *node, *next;
if (!device || !acpi_driver_data(device))
@@ -593,11 +658,54 @@ static int acpi_power_remove(struct acpi_device *device, int type)
acpi_power_remove_fs(device);
+ mutex_lock(&resource->resource_lock);
+ list_for_each_safe(node, next, &resource->reference) {
+ struct acpi_power_reference *ref = container_of(node, struct acpi_power_reference, node);
+ list_del(&ref->node);
+ kfree(ref);
+ }
+ mutex_unlock(&resource->resource_lock);
+
kfree(resource);
return 0;
}
+static int acpi_power_resume(struct acpi_device *device)
+{
+ int result = 0;
+ struct acpi_power_resource *resource = NULL;
+ struct acpi_power_reference *ref;
+
+ if (!device || !acpi_driver_data(device))
+ return -EINVAL;
+
+ resource = (struct acpi_power_resource *)acpi_driver_data(device);
+
+ result = acpi_power_get_state(resource);
+ if (result)
+ return result;
+
+ mutex_lock(&resource->resource_lock);
+ if ((resource->state == ACPI_POWER_RESOURCE_STATE_ON) &&
+ list_empty(&resource->reference)) {
+ mutex_unlock(&resource->resource_lock);
+ result = acpi_power_off_device(device->handle, NULL);
+ return result;
+ }
+
+ if ((resource->state == ACPI_POWER_RESOURCE_STATE_OFF) &&
+ !list_empty(&resource->reference)) {
+ ref = container_of(resource->reference.next, struct acpi_power_reference, node);
+ mutex_unlock(&resource->resource_lock);
+ result = acpi_power_on(device->handle, ref->device);
+ return result;
+ }
+
+ mutex_unlock(&resource->resource_lock);
+ return 0;
+}
+
static int __init acpi_power_init(void)
{
int result = 0;
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index 5f9496d59ed..99d1516d1e7 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -60,7 +60,6 @@
#define ACPI_PROCESSOR_COMPONENT 0x01000000
#define ACPI_PROCESSOR_CLASS "processor"
-#define ACPI_PROCESSOR_DRIVER_NAME "ACPI Processor Driver"
#define ACPI_PROCESSOR_DEVICE_NAME "Processor"
#define ACPI_PROCESSOR_FILE_INFO "info"
#define ACPI_PROCESSOR_FILE_THROTTLING "throttling"
@@ -74,10 +73,10 @@
#define ACPI_STA_PRESENT 0x00000001
#define _COMPONENT ACPI_PROCESSOR_COMPONENT
-ACPI_MODULE_NAME("acpi_processor")
+ACPI_MODULE_NAME("processor_core");
- MODULE_AUTHOR("Paul Diefenbaugh");
-MODULE_DESCRIPTION(ACPI_PROCESSOR_DRIVER_NAME);
+MODULE_AUTHOR("Paul Diefenbaugh");
+MODULE_DESCRIPTION("ACPI Processor Driver");
MODULE_LICENSE("GPL");
static int acpi_processor_add(struct acpi_device *device);
@@ -89,7 +88,7 @@ static acpi_status acpi_processor_hotadd_init(acpi_handle handle, int *p_cpu);
static int acpi_processor_handle_eject(struct acpi_processor *pr);
static struct acpi_driver acpi_processor_driver = {
- .name = ACPI_PROCESSOR_DRIVER_NAME,
+ .name = "processor",
.class = ACPI_PROCESSOR_CLASS,
.ids = ACPI_PROCESSOR_HID,
.ops = {
@@ -375,30 +374,126 @@ static int acpi_processor_remove_fs(struct acpi_device *device)
}
/* Use the acpiid in MADT to map cpus in case of SMP */
+
#ifndef CONFIG_SMP
-#define convert_acpiid_to_cpu(acpi_id) (-1)
+static int get_cpu_id(acpi_handle handle, u32 acpi_id) {return -1;}
#else
+static struct acpi_table_madt *madt;
+
+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;
+}
+
+static int map_lsapic_id(struct acpi_subtable_header *entry,
+ u32 acpi_id, int *apic_id)
+{
+ struct acpi_madt_local_sapic *lsapic =
+ (struct acpi_madt_local_sapic *)entry;
+ /* Only check enabled APICs*/
+ if (lsapic->lapic_flags & ACPI_MADT_ENABLED) {
+ /* First check against id */
+ if (lsapic->processor_id == acpi_id) {
+ *apic_id = (lsapic->id << 8) | lsapic->eid;
+ return 1;
+ /* Check against optional uid */
+ } else if (entry->length >= 16 &&
+ lsapic->uid == acpi_id) {
+ *apic_id = lsapic->uid;
+ return 1;
+ }
+ }
+ return 0;
+}
+
#ifdef CONFIG_IA64
-#define arch_acpiid_to_apicid ia64_acpiid_to_sapicid
#define arch_cpu_to_apicid ia64_cpu_to_sapicid
-#define ARCH_BAD_APICID (0xffff)
#else
-#define arch_acpiid_to_apicid x86_acpiid_to_apicid
#define arch_cpu_to_apicid x86_cpu_to_apicid
-#define ARCH_BAD_APICID (0xff)
#endif
-static int convert_acpiid_to_cpu(u8 acpi_id)
+static int map_madt_entry(u32 acpi_id)
+{
+ unsigned long madt_end, entry;
+ int apic_id = -1;
+
+ if (!madt)
+ return apic_id;
+
+ entry = (unsigned long)madt;
+ madt_end = entry + madt->header.length;
+
+ /* Parse all entries looking for a match. */
+
+ entry += sizeof(struct acpi_table_madt);
+ while (entry + sizeof(struct acpi_subtable_header) < madt_end) {
+ struct acpi_subtable_header *header =
+ (struct acpi_subtable_header *)entry;
+ if (header->type == ACPI_MADT_TYPE_LOCAL_APIC) {
+ if (map_lapic_id(header, acpi_id, &apic_id))
+ break;
+ } else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC) {
+ if (map_lsapic_id(header, acpi_id, &apic_id))
+ break;
+ }
+ entry += header->length;
+ }
+ return apic_id;
+}
+
+static int map_mat_entry(acpi_handle handle, u32 acpi_id)
+{
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object *obj;
+ struct acpi_subtable_header *header;
+ int apic_id = -1;
+
+ if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer)))
+ goto exit;
+
+ if (!buffer.length || !buffer.pointer)
+ goto exit;
+
+ obj = buffer.pointer;
+ if (obj->type != ACPI_TYPE_BUFFER ||
+ obj->buffer.length < sizeof(struct acpi_subtable_header)) {
+ goto exit;
+ }
+
+ header = (struct acpi_subtable_header *)obj->buffer.pointer;
+ if (header->type == ACPI_MADT_TYPE_LOCAL_APIC) {
+ map_lapic_id(header, acpi_id, &apic_id);
+ } else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC) {
+ map_lsapic_id(header, acpi_id, &apic_id);
+ }
+
+exit:
+ if (buffer.pointer)
+ kfree(buffer.pointer);
+ return apic_id;
+}
+
+static int get_cpu_id(acpi_handle handle, u32 acpi_id)
{
- u16 apic_id;
int i;
+ int apic_id = -1;
- apic_id = arch_acpiid_to_apicid[acpi_id];
- if (apic_id == ARCH_BAD_APICID)
- return -1;
+ apic_id = map_mat_entry(handle, acpi_id);
+ if (apic_id == -1)
+ apic_id = map_madt_entry(acpi_id);
+ if (apic_id == -1)
+ return apic_id;
- for (i = 0; i < NR_CPUS; i++) {
+ for (i = 0; i < NR_CPUS; ++i) {
if (arch_cpu_to_apicid[i] == apic_id)
return i;
}
@@ -410,7 +505,7 @@ static int convert_acpiid_to_cpu(u8 acpi_id)
Driver Interface
-------------------------------------------------------------------------- */
-static int acpi_processor_get_info(struct acpi_processor *pr)
+static int acpi_processor_get_info(struct acpi_processor *pr, unsigned has_uid)
{
acpi_status status = 0;
union acpi_object object = { 0 };
@@ -431,7 +526,7 @@ static int acpi_processor_get_info(struct acpi_processor *pr)
* Check to see if we have bus mastering arbitration control. This
* is required for proper C3 usage (to maintain cache coherency).
*/
- if (acpi_fadt.V1_pm2_cnt_blk && acpi_fadt.pm2_cnt_len) {
+ 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"));
@@ -439,24 +534,35 @@ static int acpi_processor_get_info(struct acpi_processor *pr)
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"No bus mastering arbitration control\n"));
- /*
- * Evalute the processor object. Note that it is common on SMP to
- * have the first (boot) processor with a valid PBLK address while
- * all others have a NULL address.
- */
- 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;
+ /* Check if it is a Device with HID and UID */
+ if (has_uid) {
+ unsigned long value;
+ status = acpi_evaluate_integer(pr->handle, METHOD_NAME__UID,
+ NULL, &value);
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_ERR PREFIX "Evaluating processor _UID\n");
+ return -ENODEV;
+ }
+ pr->acpi_id = value;
+ } else {
+ /*
+ * Evalute the processor object. Note that it is common on SMP to
+ * have the first (boot) processor with a valid PBLK address while
+ * all others have a NULL address.
+ */
+ status = acpi_evaluate_object(pr->handle, NULL, NULL, &buffer);
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_ERR PREFIX "Evaluating processor object\n");
+ return -ENODEV;
+ }
- cpu_index = convert_acpiid_to_cpu(pr->acpi_id);
+ /*
+ * 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;
+ }
+ cpu_index = get_cpu_id(pr->handle, pr->acpi_id);
/* Handle UP system running SMP kernel, with no LAPIC in MADT */
if (!cpu0_initialized && (cpu_index == -1) &&
@@ -473,7 +579,7 @@ static int acpi_processor_get_info(struct acpi_processor *pr)
* less than the max # of CPUs. They should be ignored _iff
* they are physically not present.
*/
- if (cpu_index == -1) {
+ if (pr->id == -1) {
if (ACPI_FAILURE
(acpi_processor_hotadd_init(pr->handle, &pr->id))) {
return -ENODEV;
@@ -490,8 +596,8 @@ static int acpi_processor_get_info(struct acpi_processor *pr)
object.processor.pblk_length);
else {
pr->throttling.address = object.processor.pblk_address;
- pr->throttling.duty_offset = acpi_fadt.duty_offset;
- pr->throttling.duty_width = acpi_fadt.duty_width;
+ pr->throttling.duty_offset = acpi_gbl_FADT.duty_offset;
+ pr->throttling.duty_width = acpi_gbl_FADT.duty_width;
pr->pblk = object.processor.pblk_address;
@@ -525,7 +631,7 @@ static int __cpuinit acpi_processor_start(struct acpi_device *device)
pr = acpi_driver_data(device);
- result = acpi_processor_get_info(pr);
+ result = acpi_processor_get_info(pr, device->flags.unique_id);
if (result) {
/* Processor is physically not present */
return 0;
@@ -707,7 +813,7 @@ int acpi_processor_device_add(acpi_handle handle, struct acpi_device **device)
return -ENODEV;
if ((pr->id >= 0) && (pr->id < NR_CPUS)) {
- kobject_uevent(&(*device)->kobj, KOBJ_ONLINE);
+ kobject_uevent(&(*device)->dev.kobj, KOBJ_ONLINE);
}
return 0;
}
@@ -745,13 +851,13 @@ acpi_processor_hotplug_notify(acpi_handle handle, u32 event, void *data)
}
if (pr->id >= 0 && (pr->id < NR_CPUS)) {
- kobject_uevent(&device->kobj, KOBJ_OFFLINE);
+ kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
break;
}
result = acpi_processor_start(device);
if ((!result) && ((pr->id >= 0) && (pr->id < NR_CPUS))) {
- kobject_uevent(&device->kobj, KOBJ_ONLINE);
+ kobject_uevent(&device->dev.kobj, KOBJ_ONLINE);
} else {
printk(KERN_ERR PREFIX "Device [%s] failed to start\n",
acpi_device_bid(device));
@@ -774,7 +880,7 @@ acpi_processor_hotplug_notify(acpi_handle handle, u32 event, void *data)
}
if ((pr->id < NR_CPUS) && (cpu_present(pr->id)))
- kobject_uevent(&device->kobj, KOBJ_OFFLINE);
+ kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
break;
default:
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
@@ -895,6 +1001,12 @@ static int __init acpi_processor_init(void)
memset(&processors, 0, sizeof(processors));
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
+
acpi_processor_dir = proc_mkdir(ACPI_PROCESSOR_CLASS, acpi_root_dir);
if (!acpi_processor_dir)
return -ENOMEM;
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 3f30af21574..60773005b8a 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -39,6 +39,25 @@
#include <linux/moduleparam.h>
#include <linux/sched.h> /* need_resched() */
#include <linux/latency.h>
+#include <linux/clockchips.h>
+
+/*
+ * Include the apic definitions for x86 to have the APIC timer related defines
+ * available also for UP (on SMP it gets magically included via linux/smp.h).
+ * asm/acpi.h is not an option, as it would require more include magic. Also
+ * creating an empty asm-ia64/apic.h would just trade pest vs. cholera.
+ */
+#ifdef CONFIG_X86
+#include <asm/apic.h>
+#endif
+
+/*
+ * Include the apic definitions for x86 to have the APIC timer related defines
+ * available also for UP (on SMP it gets magically included via linux/smp.h).
+ */
+#ifdef CONFIG_X86
+#include <asm/apic.h>
+#endif
#include <asm/io.h>
#include <asm/uaccess.h>
@@ -48,9 +67,8 @@
#define ACPI_PROCESSOR_COMPONENT 0x01000000
#define ACPI_PROCESSOR_CLASS "processor"
-#define ACPI_PROCESSOR_DRIVER_NAME "ACPI Processor Driver"
#define _COMPONENT ACPI_PROCESSOR_COMPONENT
-ACPI_MODULE_NAME("acpi_processor")
+ACPI_MODULE_NAME("processor_idle");
#define ACPI_PROCESSOR_FILE_POWER "power"
#define US_TO_PM_TIMER_TICKS(t) ((t * (PM_TIMER_FREQUENCY/1000)) / 1000)
#define C2_OVERHEAD 4 /* 1us (3.579 ticks per us) */
@@ -160,7 +178,7 @@ static inline u32 ticks_elapsed(u32 t1, u32 t2)
{
if (t2 >= t1)
return (t2 - t1);
- else if (!acpi_fadt.tmr_val_ext)
+ else if (!(acpi_gbl_FADT.flags & ACPI_FADT_32BIT_TIMER))
return (((0x00FFFFFF - t1) + t2) & 0x00FFFFFF);
else
return ((0xFFFFFFFF - t1) + t2);
@@ -187,8 +205,7 @@ acpi_processor_power_activate(struct acpi_processor *pr,
case ACPI_STATE_C3:
/* Disable bus master reload */
if (new->type != ACPI_STATE_C3 && pr->flags.bm_check)
- acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0,
- ACPI_MTX_DO_NOT_LOCK);
+ acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0);
break;
}
}
@@ -198,8 +215,7 @@ acpi_processor_power_activate(struct acpi_processor *pr,
case ACPI_STATE_C3:
/* Enable bus master reload */
if (old->type != ACPI_STATE_C3 && pr->flags.bm_check)
- acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 1,
- ACPI_MTX_DO_NOT_LOCK);
+ acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 1);
break;
}
@@ -236,10 +252,85 @@ static void acpi_cstate_enter(struct acpi_processor_cx *cstate)
/* Dummy wait op - must do something useless after P_LVL2 read
because chipsets cannot guarantee that STPCLK# signal
gets asserted in time to freeze execution properly. */
- unused = inl(acpi_fadt.xpm_tmr_blk.address);
+ unused = inl(acpi_gbl_FADT.xpm_timer_block.address);
}
}
+#ifdef ARCH_APICTIMER_STOPS_ON_C3
+
+/*
+ * Some BIOS implementations switch to C3 in the published C2 state.
+ * This seems to be a common problem on AMD boxen, but other vendors
+ * are affected too. We pick the most conservative approach: we assume
+ * that the local APIC stops in both C2 and C3.
+ */
+static void acpi_timer_check_state(int state, struct acpi_processor *pr,
+ struct acpi_processor_cx *cx)
+{
+ struct acpi_processor_power *pwr = &pr->power;
+
+ /*
+ * Check, if one of the previous states already marked the lapic
+ * unstable
+ */
+ if (pwr->timer_broadcast_on_state < state)
+ return;
+
+ if (cx->type >= ACPI_STATE_C2)
+ pr->power.timer_broadcast_on_state = state;
+}
+
+static void acpi_propagate_timer_broadcast(struct acpi_processor *pr)
+{
+#ifdef CONFIG_GENERIC_CLOCKEVENTS
+ unsigned long reason;
+
+ reason = pr->power.timer_broadcast_on_state < INT_MAX ?
+ CLOCK_EVT_NOTIFY_BROADCAST_ON : CLOCK_EVT_NOTIFY_BROADCAST_OFF;
+
+ clockevents_notify(reason, &pr->id);
+#else
+ cpumask_t mask = cpumask_of_cpu(pr->id);
+
+ if (pr->power.timer_broadcast_on_state < INT_MAX)
+ on_each_cpu(switch_APIC_timer_to_ipi, &mask, 1, 1);
+ else
+ on_each_cpu(switch_ipi_to_APIC_timer, &mask, 1, 1);
+#endif
+}
+
+/* Power(C) State timer broadcast control */
+static void acpi_state_timer_broadcast(struct acpi_processor *pr,
+ struct acpi_processor_cx *cx,
+ int broadcast)
+{
+#ifdef CONFIG_GENERIC_CLOCKEVENTS
+
+ int state = cx - pr->power.states;
+
+ if (state >= pr->power.timer_broadcast_on_state) {
+ unsigned long reason;
+
+ reason = broadcast ? CLOCK_EVT_NOTIFY_BROADCAST_ENTER :
+ CLOCK_EVT_NOTIFY_BROADCAST_EXIT;
+ clockevents_notify(reason, &pr->id);
+ }
+#endif
+}
+
+#else
+
+static void acpi_timer_check_state(int state, struct acpi_processor *pr,
+ struct acpi_processor_cx *cstate) { }
+static void acpi_propagate_timer_broadcast(struct acpi_processor *pr) { }
+static void acpi_state_timer_broadcast(struct acpi_processor *pr,
+ struct acpi_processor_cx *cx,
+ int broadcast)
+{
+}
+
+#endif
+
static void acpi_processor_idle(void)
{
struct acpi_processor *pr = NULL;
@@ -291,12 +382,10 @@ static void acpi_processor_idle(void)
pr->power.bm_activity <<= diff;
- acpi_get_register(ACPI_BITREG_BUS_MASTER_STATUS,
- &bm_status, ACPI_MTX_DO_NOT_LOCK);
+ acpi_get_register(ACPI_BITREG_BUS_MASTER_STATUS, &bm_status);
if (bm_status) {
pr->power.bm_activity |= 0x1;
- acpi_set_register(ACPI_BITREG_BUS_MASTER_STATUS,
- 1, ACPI_MTX_DO_NOT_LOCK);
+ acpi_set_register(ACPI_BITREG_BUS_MASTER_STATUS, 1);
}
/*
* PIIX4 Erratum #18: Note that BM_STS doesn't always reflect
@@ -338,7 +427,7 @@ static void acpi_processor_idle(void)
* detection phase, to work cleanly with logical CPU hotplug.
*/
if ((cx->type != ACPI_STATE_C1) && (num_online_cpus() > 1) &&
- !pr->flags.has_cst && !acpi_fadt.plvl2_up)
+ !pr->flags.has_cst && !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED))
cx = &pr->power.states[ACPI_STATE_C1];
#endif
@@ -384,11 +473,12 @@ static void acpi_processor_idle(void)
case ACPI_STATE_C2:
/* Get start time (ticks) */
- t1 = inl(acpi_fadt.xpm_tmr_blk.address);
+ t1 = inl(acpi_gbl_FADT.xpm_timer_block.address);
/* Invoke C2 */
+ acpi_state_timer_broadcast(pr, cx, 1);
acpi_cstate_enter(cx);
/* Get end time (ticks) */
- t2 = inl(acpi_fadt.xpm_tmr_blk.address);
+ t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
#ifdef CONFIG_GENERIC_TIME
/* TSC halts in C2, so notify users */
@@ -400,6 +490,7 @@ static void acpi_processor_idle(void)
/* Compute time (ticks) that we were actually asleep */
sleep_ticks =
ticks_elapsed(t1, t2) - cx->latency_ticks - C2_OVERHEAD;
+ acpi_state_timer_broadcast(pr, cx, 0);
break;
case ACPI_STATE_C3:
@@ -411,8 +502,7 @@ static void acpi_processor_idle(void)
* All CPUs are trying to go to C3
* Disable bus master arbitration
*/
- acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1,
- ACPI_MTX_DO_NOT_LOCK);
+ acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1);
}
} else {
/* SMP with no shared cache... Invalidate cache */
@@ -420,16 +510,16 @@ static void acpi_processor_idle(void)
}
/* Get start time (ticks) */
- t1 = inl(acpi_fadt.xpm_tmr_blk.address);
+ t1 = inl(acpi_gbl_FADT.xpm_timer_block.address);
/* Invoke C3 */
+ acpi_state_timer_broadcast(pr, cx, 1);
acpi_cstate_enter(cx);
/* Get end time (ticks) */
- t2 = inl(acpi_fadt.xpm_tmr_blk.address);
+ t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
if (pr->flags.bm_check) {
/* Enable bus master arbitration */
atomic_dec(&c3_cpu_count);
- acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0,
- ACPI_MTX_DO_NOT_LOCK);
+ acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0);
}
#ifdef CONFIG_GENERIC_TIME
@@ -442,6 +532,7 @@ static void acpi_processor_idle(void)
/* Compute time (ticks) that we were actually asleep */
sleep_ticks =
ticks_elapsed(t1, t2) - cx->latency_ticks - C3_OVERHEAD;
+ acpi_state_timer_broadcast(pr, cx, 0);
break;
default:
@@ -457,7 +548,7 @@ static void acpi_processor_idle(void)
#ifdef CONFIG_HOTPLUG_CPU
/* Don't do promotion/demotion */
if ((cx->type == ACPI_STATE_C1) && (num_online_cpus() > 1) &&
- !pr->flags.has_cst && !acpi_fadt.plvl2_up) {
+ !pr->flags.has_cst && !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED)) {
next_state = cx;
goto end;
}
@@ -627,7 +718,8 @@ static int acpi_processor_get_power_info_fadt(struct acpi_processor *pr)
* Check for P_LVL2_UP flag before entering C2 and above on
* an SMP system.
*/
- if ((num_online_cpus() > 1) && !acpi_fadt.plvl2_up)
+ if ((num_online_cpus() > 1) &&
+ !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED))
return -ENODEV;
#endif
@@ -636,8 +728,8 @@ static int acpi_processor_get_power_info_fadt(struct acpi_processor *pr)
pr->power.states[ACPI_STATE_C3].address = pr->pblk + 5;
/* determine latencies from FADT */
- pr->power.states[ACPI_STATE_C2].latency = acpi_fadt.plvl2_lat;
- pr->power.states[ACPI_STATE_C3].latency = acpi_fadt.plvl3_lat;
+ pr->power.states[ACPI_STATE_C2].latency = acpi_gbl_FADT.C2latency;
+ pr->power.states[ACPI_STATE_C3].latency = acpi_gbl_FADT.C3latency;
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"lvl2[0x%08x] lvl3[0x%08x]\n",
@@ -883,14 +975,13 @@ static void acpi_processor_power_verify_c3(struct acpi_processor *pr,
* WBINVD should be set in fadt, for C3 state to be
* supported on when bm_check is not required.
*/
- if (acpi_fadt.wb_invd != 1) {
+ if (!(acpi_gbl_FADT.flags & ACPI_FADT_WBINVD)) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Cache invalidation should work properly"
" for C3 to be enabled on SMP systems\n"));
return;
}
- acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD,
- 0, ACPI_MTX_DO_NOT_LOCK);
+ acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0);
}
/*
@@ -910,11 +1001,7 @@ static int acpi_processor_power_verify(struct acpi_processor *pr)
unsigned int i;
unsigned int working = 0;
-#ifdef ARCH_APICTIMER_STOPS_ON_C3
- int timer_broadcast = 0;
- cpumask_t mask = cpumask_of_cpu(pr->id);
- on_each_cpu(switch_ipi_to_APIC_timer, &mask, 1, 1);
-#endif
+ pr->power.timer_broadcast_on_state = INT_MAX;
for (i = 1; i < ACPI_PROCESSOR_MAX_POWER; i++) {
struct acpi_processor_cx *cx = &pr->power.states[i];
@@ -926,21 +1013,14 @@ static int acpi_processor_power_verify(struct acpi_processor *pr)
case ACPI_STATE_C2:
acpi_processor_power_verify_c2(cx);
-#ifdef ARCH_APICTIMER_STOPS_ON_C3
- /* Some AMD systems fake C3 as C2, but still
- have timer troubles */
- if (cx->valid &&
- boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
- timer_broadcast++;
-#endif
+ if (cx->valid)
+ acpi_timer_check_state(i, pr, cx);
break;
case ACPI_STATE_C3:
acpi_processor_power_verify_c3(pr, cx);
-#ifdef ARCH_APICTIMER_STOPS_ON_C3
if (cx->valid)
- timer_broadcast++;
-#endif
+ acpi_timer_check_state(i, pr, cx);
break;
}
@@ -948,10 +1028,7 @@ static int acpi_processor_power_verify(struct acpi_processor *pr)
working++;
}
-#ifdef ARCH_APICTIMER_STOPS_ON_C3
- if (timer_broadcast)
- on_each_cpu(switch_APIC_timer_to_ipi, &mask, 1, 1);
-#endif
+ acpi_propagate_timer_broadcast(pr);
return (working);
}
@@ -1096,7 +1173,7 @@ static int acpi_processor_power_seq_show(struct seq_file *seq, void *offset)
seq_printf(seq, "latency[%03d] usage[%08d] duration[%020llu]\n",
pr->power.states[i].latency,
pr->power.states[i].usage,
- pr->power.states[i].time);
+ (unsigned long long)pr->power.states[i].time);
}
end:
@@ -1164,9 +1241,9 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr,
if (!pr)
return -EINVAL;
- if (acpi_fadt.cst_cnt && !nocst) {
+ if (acpi_gbl_FADT.cst_control && !nocst) {
status =
- acpi_os_write_port(acpi_fadt.smi_cmd, acpi_fadt.cst_cnt, 8);
+ acpi_os_write_port(acpi_gbl_FADT.smi_command, acpi_gbl_FADT.cst_control, 8);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status,
"Notifying BIOS of _CST ability failed"));
diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c
index cbb6f0814ce..2f2e7964226 100644
--- a/drivers/acpi/processor_perflib.c
+++ b/drivers/acpi/processor_perflib.c
@@ -44,10 +44,9 @@
#define ACPI_PROCESSOR_COMPONENT 0x01000000
#define ACPI_PROCESSOR_CLASS "processor"
-#define ACPI_PROCESSOR_DRIVER_NAME "ACPI Processor Driver"
#define ACPI_PROCESSOR_FILE_PERFORMANCE "performance"
#define _COMPONENT ACPI_PROCESSOR_COMPONENT
-ACPI_MODULE_NAME("acpi_processor")
+ACPI_MODULE_NAME("processor_perflib");
static DEFINE_MUTEX(performance_mutex);
@@ -352,31 +351,24 @@ int acpi_processor_notify_smm(struct module *calling_module)
is_done = -EIO;
- /* Can't write pstate_cnt to smi_cmd if either value is zero */
- if ((!acpi_fadt.smi_cmd) || (!acpi_fadt.pstate_cnt)) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No SMI port or pstate_cnt\n"));
+ /* Can't write pstate_control to smi_command if either value is zero */
+ if ((!acpi_gbl_FADT.smi_command) || (!acpi_gbl_FADT.pstate_control)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No SMI port or pstate_control\n"));
module_put(calling_module);
return 0;
}
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Writing pstate_cnt [0x%x] to smi_cmd [0x%x]\n",
- acpi_fadt.pstate_cnt, acpi_fadt.smi_cmd));
+ "Writing pstate_control [0x%x] to smi_command [0x%x]\n",
+ acpi_gbl_FADT.pstate_control, acpi_gbl_FADT.smi_command));
- /* FADT v1 doesn't support pstate_cnt, many BIOS vendors use
- * it anyway, so we need to support it... */
- if (acpi_fadt_is_v1) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Using v1.0 FADT reserved value for pstate_cnt\n"));
- }
-
- status = acpi_os_write_port(acpi_fadt.smi_cmd,
- (u32) acpi_fadt.pstate_cnt, 8);
+ status = acpi_os_write_port(acpi_gbl_FADT.smi_command,
+ (u32) acpi_gbl_FADT.pstate_control, 8);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status,
- "Failed to write pstate_cnt [0x%x] to "
- "smi_cmd [0x%x]", acpi_fadt.pstate_cnt,
- acpi_fadt.smi_cmd));
+ "Failed to write pstate_control [0x%x] to "
+ "smi_command [0x%x]", acpi_gbl_FADT.pstate_control,
+ acpi_gbl_FADT.smi_command));
module_put(calling_module);
return status;
}
diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c
index 40fecd67ad8..06e6f3fb882 100644
--- a/drivers/acpi/processor_thermal.c
+++ b/drivers/acpi/processor_thermal.c
@@ -41,9 +41,8 @@
#define ACPI_PROCESSOR_COMPONENT 0x01000000
#define ACPI_PROCESSOR_CLASS "processor"
-#define ACPI_PROCESSOR_DRIVER_NAME "ACPI Processor Driver"
#define _COMPONENT ACPI_PROCESSOR_COMPONENT
-ACPI_MODULE_NAME("acpi_processor")
+ACPI_MODULE_NAME("processor_thermal");
/* --------------------------------------------------------------------------
Limit Interface
diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c
index 0ec7dcde006..b33486009f4 100644
--- a/drivers/acpi/processor_throttling.c
+++ b/drivers/acpi/processor_throttling.c
@@ -41,9 +41,8 @@
#define ACPI_PROCESSOR_COMPONENT 0x01000000
#define ACPI_PROCESSOR_CLASS "processor"
-#define ACPI_PROCESSOR_DRIVER_NAME "ACPI Processor Driver"
#define _COMPONENT ACPI_PROCESSOR_COMPONENT
-ACPI_MODULE_NAME("acpi_processor")
+ACPI_MODULE_NAME("processor_throttling");
/* --------------------------------------------------------------------------
Throttling Control
@@ -125,7 +124,7 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, int state)
/* Used to clear all duty_value bits */
duty_mask = pr->throttling.state_count - 1;
- duty_mask <<= acpi_fadt.duty_offset;
+ duty_mask <<= acpi_gbl_FADT.duty_offset;
duty_mask = ~duty_mask;
}
@@ -208,7 +207,7 @@ int acpi_processor_get_throttling_info(struct acpi_processor *pr)
return 0;
}
- pr->throttling.state_count = 1 << acpi_fadt.duty_width;
+ pr->throttling.state_count = 1 << acpi_gbl_FADT.duty_width;
/*
* Compute state values. Note that throttling displays a linear power/
diff --git a/drivers/acpi/resources/rsaddr.c b/drivers/acpi/resources/rsaddr.c
index 8fa3213ce00..271e61509ee 100644
--- a/drivers/acpi/resources/rsaddr.c
+++ b/drivers/acpi/resources/rsaddr.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/resources/rscalc.c b/drivers/acpi/resources/rscalc.c
index cf87b023002..8c6d3fdec38 100644
--- a/drivers/acpi/resources/rscalc.c
+++ b/drivers/acpi/resources/rscalc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/resources/rscreate.c b/drivers/acpi/resources/rscreate.c
index 008058acdd3..1358c06a969 100644
--- a/drivers/acpi/resources/rscreate.c
+++ b/drivers/acpi/resources/rscreate.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/resources/rsdump.c b/drivers/acpi/resources/rsdump.c
index 9c99a723a86..de20a5d6dec 100644
--- a/drivers/acpi/resources/rsdump.c
+++ b/drivers/acpi/resources/rsdump.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/resources/rsinfo.c b/drivers/acpi/resources/rsinfo.c
index 9e7ae2f8a1d..7e3c335ab32 100644
--- a/drivers/acpi/resources/rsinfo.c
+++ b/drivers/acpi/resources/rsinfo.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/resources/rsio.c b/drivers/acpi/resources/rsio.c
index ea567167c4f..b297bc3e441 100644
--- a/drivers/acpi/resources/rsio.c
+++ b/drivers/acpi/resources/rsio.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/resources/rsirq.c b/drivers/acpi/resources/rsirq.c
index 1fa63bc2e36..5657f7b9503 100644
--- a/drivers/acpi/resources/rsirq.c
+++ b/drivers/acpi/resources/rsirq.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/resources/rslist.c b/drivers/acpi/resources/rslist.c
index 29423ce030c..a92755c8877 100644
--- a/drivers/acpi/resources/rslist.c
+++ b/drivers/acpi/resources/rslist.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/resources/rsmemory.c b/drivers/acpi/resources/rsmemory.c
index a5131936d69..521eab7dd8d 100644
--- a/drivers/acpi/resources/rsmemory.c
+++ b/drivers/acpi/resources/rsmemory.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/resources/rsmisc.c b/drivers/acpi/resources/rsmisc.c
index faf6e106b78..3b63b561b94 100644
--- a/drivers/acpi/resources/rsmisc.c
+++ b/drivers/acpi/resources/rsmisc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/resources/rsutils.c b/drivers/acpi/resources/rsutils.c
index a9cbee8e8b4..2442a8f8df5 100644
--- a/drivers/acpi/resources/rsutils.c
+++ b/drivers/acpi/resources/rsutils.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/resources/rsxface.c b/drivers/acpi/resources/rsxface.c
index 1999e2ab7da..991f8901498 100644
--- a/drivers/acpi/resources/rsxface.c
+++ b/drivers/acpi/resources/rsxface.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c
index f58fc7447ab..59640d9a0ac 100644
--- a/drivers/acpi/sbs.c
+++ b/drivers/acpi/sbs.c
@@ -59,7 +59,6 @@ extern void acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir);
#define ACPI_AC_CLASS "ac_adapter"
#define ACPI_BATTERY_CLASS "battery"
#define ACPI_SBS_HID "ACPI0002"
-#define ACPI_SBS_DRIVER_NAME "ACPI Smart Battery System Driver"
#define ACPI_SBS_DEVICE_NAME "Smart Battery System"
#define ACPI_SBS_FILE_INFO "info"
#define ACPI_SBS_FILE_STATE "state"
@@ -78,7 +77,7 @@ extern void acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir);
#define MAX_SBS_BAT 4
#define MAX_SMBUS_ERR 1
-ACPI_MODULE_NAME("acpi_sbs");
+ACPI_MODULE_NAME("sbs");
MODULE_AUTHOR("Rich Townsend");
MODULE_DESCRIPTION("Smart Battery System ACPI interface driver");
@@ -110,7 +109,7 @@ static void acpi_battery_smbus_err_handler(struct acpi_ec_smbus *smbus);
static void acpi_sbs_update_queue(void *data);
static struct acpi_driver acpi_sbs_driver = {
- .name = ACPI_SBS_DRIVER_NAME,
+ .name = "sbs",
.class = ACPI_SBS_CLASS,
.ids = ACPI_SBS_HID,
.ops = {
@@ -1034,21 +1033,19 @@ static int acpi_battery_read_state(struct seq_file *seq, void *offset)
} else {
seq_printf(seq, "capacity state: ok\n");
}
+
+ foo = (s16) battery->state.amperage * battery->info.ipscale;
+ if (battery->info.capacity_mode) {
+ foo = foo * battery->info.design_voltage / 1000;
+ }
if (battery->state.amperage < 0) {
seq_printf(seq, "charging state: discharging\n");
- foo = battery->state.remaining_capacity * cscale * 60 /
- (battery->state.average_time_to_empty == 0 ? 1 :
- battery->state.average_time_to_empty);
- seq_printf(seq, "present rate: %i%s\n",
- foo, battery->info.capacity_mode ? "0 mW" : " mA");
+ seq_printf(seq, "present rate: %d %s\n",
+ -foo, battery->info.capacity_mode ? "mW" : "mA");
} else if (battery->state.amperage > 0) {
seq_printf(seq, "charging state: charging\n");
- foo = (battery->info.full_charge_capacity -
- battery->state.remaining_capacity) * cscale * 60 /
- (battery->state.average_time_to_full == 0 ? 1 :
- battery->state.average_time_to_full);
- seq_printf(seq, "present rate: %i%s\n",
- foo, battery->info.capacity_mode ? "0 mW" : " mA");
+ seq_printf(seq, "present rate: %d %s\n",
+ foo, battery->info.capacity_mode ? "mW" : "mA");
} else {
seq_printf(seq, "charging state: charged\n");
seq_printf(seq, "present rate: 0 %s\n",
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 283d87522c5..bb0e0da39fb 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -11,111 +11,314 @@
#include <acpi/acinterp.h> /* for acpi_ex_eisa_id_to_string() */
#define _COMPONENT ACPI_BUS_COMPONENT
-ACPI_MODULE_NAME("scan")
+ACPI_MODULE_NAME("scan");
#define STRUCT_TO_INT(s) (*((int*)&s))
extern struct acpi_device *acpi_root;
#define ACPI_BUS_CLASS "system_bus"
#define ACPI_BUS_HID "ACPI_BUS"
-#define ACPI_BUS_DRIVER_NAME "ACPI Bus Driver"
#define ACPI_BUS_DEVICE_NAME "System Bus"
static LIST_HEAD(acpi_device_list);
+static LIST_HEAD(acpi_bus_id_list);
DEFINE_SPINLOCK(acpi_device_lock);
LIST_HEAD(acpi_wakeup_device_list);
+struct acpi_device_bus_id{
+ char bus_id[15];
+ unsigned int instance_no;
+ struct list_head node;
+};
+static int acpi_eject_operation(acpi_handle handle, int lockable)
+{
+ struct acpi_object_list arg_list;
+ union acpi_object arg;
+ acpi_status status = AE_OK;
+
+ /*
+ * TBD: evaluate _PS3?
+ */
+
+ if (lockable) {
+ arg_list.count = 1;
+ arg_list.pointer = &arg;
+ arg.type = ACPI_TYPE_INTEGER;
+ arg.integer.value = 0;
+ acpi_evaluate_object(handle, "_LCK", &arg_list, NULL);
+ }
+
+ arg_list.count = 1;
+ arg_list.pointer = &arg;
+ arg.type = ACPI_TYPE_INTEGER;
+ arg.integer.value = 1;
+
+ /*
+ * TBD: _EJD support.
+ */
+
+ status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL);
+ if (ACPI_FAILURE(status)) {
+ return (-ENODEV);
+ }
+
+ return (0);
+}
-static void acpi_device_release(struct kobject *kobj)
+static ssize_t
+acpi_eject_store(struct device *d, struct device_attribute *attr,
+ const char *buf, size_t count)
{
- struct acpi_device *dev = container_of(kobj, struct acpi_device, kobj);
- kfree(dev->pnp.cid_list);
- kfree(dev);
+ int result;
+ int ret = count;
+ int islockable;
+ acpi_status status;
+ acpi_handle handle;
+ acpi_object_type type = 0;
+ struct acpi_device *acpi_device = to_acpi_device(d);
+
+ if ((!count) || (buf[0] != '1')) {
+ return -EINVAL;
+ }
+#ifndef FORCE_EJECT
+ if (acpi_device->driver == NULL) {
+ ret = -ENODEV;
+ goto err;
+ }
+#endif
+ status = acpi_get_type(acpi_device->handle, &type);
+ if (ACPI_FAILURE(status) || (!acpi_device->flags.ejectable)) {
+ ret = -ENODEV;
+ goto err;
+ }
+
+ islockable = acpi_device->flags.lockable;
+ handle = acpi_device->handle;
+
+ result = acpi_bus_trim(acpi_device, 1);
+
+ if (!result)
+ result = acpi_eject_operation(handle, islockable);
+
+ if (result) {
+ ret = -EBUSY;
+ }
+ err:
+ return ret;
}
-struct acpi_device_attribute {
- struct attribute attr;
- ssize_t(*show) (struct acpi_device *, char *);
- ssize_t(*store) (struct acpi_device *, const char *, size_t);
-};
+static DEVICE_ATTR(eject, 0200, NULL, acpi_eject_store);
+
+static ssize_t
+acpi_device_hid_show(struct device *dev, struct device_attribute *attr, char *buf) {
+ struct acpi_device *acpi_dev = to_acpi_device(dev);
+
+ return sprintf(buf, "%s\n", acpi_dev->pnp.hardware_id);
+}
+static DEVICE_ATTR(hid, 0444, acpi_device_hid_show, NULL);
+
+static ssize_t
+acpi_device_path_show(struct device *dev, struct device_attribute *attr, char *buf) {
+ struct acpi_device *acpi_dev = to_acpi_device(dev);
+ struct acpi_buffer path = {ACPI_ALLOCATE_BUFFER, NULL};
+ int result;
+
+ result = acpi_get_name(acpi_dev->handle, ACPI_FULL_PATHNAME, &path);
+ if(result)
+ goto end;
+
+ result = sprintf(buf, "%s\n", (char*)path.pointer);
+ kfree(path.pointer);
+ end:
+ return result;
+}
+static DEVICE_ATTR(path, 0444, acpi_device_path_show, NULL);
+
+static int acpi_device_setup_files(struct acpi_device *dev)
+{
+ acpi_status status;
+ acpi_handle temp;
+ int result = 0;
+
+ /*
+ * Devices gotten from FADT don't have a "path" attribute
+ */
+ if(dev->handle) {
+ result = device_create_file(&dev->dev, &dev_attr_path);
+ if(result)
+ goto end;
+ }
-typedef void acpi_device_sysfs_files(struct kobject *,
- const struct attribute *);
+ if(dev->flags.hardware_id) {
+ result = device_create_file(&dev->dev, &dev_attr_hid);
+ if(result)
+ goto end;
+ }
-static void setup_sys_fs_device_files(struct acpi_device *dev,
- acpi_device_sysfs_files * func);
+ /*
+ * If device has _EJ0, 'eject' file is created that is used to trigger
+ * hot-removal function from userland.
+ */
+ status = acpi_get_handle(dev->handle, "_EJ0", &temp);
+ if (ACPI_SUCCESS(status))
+ result = device_create_file(&dev->dev, &dev_attr_eject);
+ end:
+ return result;
+}
-#define create_sysfs_device_files(dev) \
- setup_sys_fs_device_files(dev, (acpi_device_sysfs_files *)&sysfs_create_file)
-#define remove_sysfs_device_files(dev) \
- setup_sys_fs_device_files(dev, (acpi_device_sysfs_files *)&sysfs_remove_file)
+static void acpi_device_remove_files(struct acpi_device *dev)
+{
+ acpi_status status;
+ acpi_handle temp;
-#define to_acpi_device(n) container_of(n, struct acpi_device, kobj)
-#define to_handle_attr(n) container_of(n, struct acpi_device_attribute, attr);
+ /*
+ * If device has _EJ0, 'eject' file is created that is used to trigger
+ * hot-removal function from userland.
+ */
+ status = acpi_get_handle(dev->handle, "_EJ0", &temp);
+ if (ACPI_SUCCESS(status))
+ device_remove_file(&dev->dev, &dev_attr_eject);
-static ssize_t acpi_device_attr_show(struct kobject *kobj,
- struct attribute *attr, char *buf)
+ if(dev->flags.hardware_id)
+ device_remove_file(&dev->dev, &dev_attr_hid);
+ if(dev->handle)
+ device_remove_file(&dev->dev, &dev_attr_path);
+}
+/* --------------------------------------------------------------------------
+ ACPI Bus operations
+ -------------------------------------------------------------------------- */
+static void acpi_device_release(struct device *dev)
{
- struct acpi_device *device = to_acpi_device(kobj);
- struct acpi_device_attribute *attribute = to_handle_attr(attr);
- return attribute->show ? attribute->show(device, buf) : -EIO;
+ struct acpi_device *acpi_dev = to_acpi_device(dev);
+
+ kfree(acpi_dev->pnp.cid_list);
+ kfree(acpi_dev);
}
-static ssize_t acpi_device_attr_store(struct kobject *kobj,
- struct attribute *attr, const char *buf,
- size_t len)
+
+static int acpi_device_suspend(struct device *dev, pm_message_t state)
{
- struct acpi_device *device = to_acpi_device(kobj);
- struct acpi_device_attribute *attribute = to_handle_attr(attr);
- return attribute->store ? attribute->store(device, buf, len) : -EIO;
+ struct acpi_device *acpi_dev = to_acpi_device(dev);
+ struct acpi_driver *acpi_drv = acpi_dev->driver;
+
+ if (acpi_drv && acpi_drv->ops.suspend)
+ return acpi_drv->ops.suspend(acpi_dev, state);
+ return 0;
}
-static struct sysfs_ops acpi_device_sysfs_ops = {
- .show = acpi_device_attr_show,
- .store = acpi_device_attr_store,
-};
+static int acpi_device_resume(struct device *dev)
+{
+ struct acpi_device *acpi_dev = to_acpi_device(dev);
+ struct acpi_driver *acpi_drv = acpi_dev->driver;
-static struct kobj_type ktype_acpi_ns = {
- .sysfs_ops = &acpi_device_sysfs_ops,
- .release = acpi_device_release,
-};
+ if (acpi_drv && acpi_drv->ops.resume)
+ return acpi_drv->ops.resume(acpi_dev);
+ return 0;
+}
-static int namespace_uevent(struct kset *kset, struct kobject *kobj,
- char **envp, int num_envp, char *buffer,
- int buffer_size)
+static int acpi_bus_match(struct device *dev, struct device_driver *drv)
{
- struct acpi_device *dev = to_acpi_device(kobj);
- int i = 0;
- int len = 0;
+ struct acpi_device *acpi_dev = to_acpi_device(dev);
+ struct acpi_driver *acpi_drv = to_acpi_driver(drv);
- if (!dev->driver)
- return 0;
+ return !acpi_match_ids(acpi_dev, acpi_drv->ids);
+}
- if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
- "PHYSDEVDRIVER=%s", dev->driver->name))
+static int acpi_device_uevent(struct device *dev, char **envp, int num_envp,
+ char *buffer, int buffer_size)
+{
+ struct acpi_device *acpi_dev = to_acpi_device(dev);
+ int i = 0, length = 0, ret = 0;
+
+ if (acpi_dev->flags.hardware_id)
+ ret = add_uevent_var(envp, num_envp, &i,
+ buffer, buffer_size, &length,
+ "HWID=%s", acpi_dev->pnp.hardware_id);
+ if (ret)
return -ENOMEM;
+ if (acpi_dev->flags.compatible_ids) {
+ int j;
+ struct acpi_compatible_id_list *cid_list;
+
+ cid_list = acpi_dev->pnp.cid_list;
+
+ for (j = 0; j < cid_list->count; j++) {
+ ret = add_uevent_var(envp, num_envp, &i, buffer,
+ buffer_size, &length, "COMPTID=%s",
+ cid_list->id[j].value);
+ if (ret)
+ return -ENOMEM;
+ }
+ }
envp[i] = NULL;
+ return 0;
+}
+
+static int acpi_bus_driver_init(struct acpi_device *, struct acpi_driver *);
+static int acpi_start_single_object(struct acpi_device *);
+static int acpi_device_probe(struct device * dev)
+{
+ struct acpi_device *acpi_dev = to_acpi_device(dev);
+ struct acpi_driver *acpi_drv = to_acpi_driver(dev->driver);
+ int ret;
+
+ ret = acpi_bus_driver_init(acpi_dev, acpi_drv);
+ if (!ret) {
+ if (acpi_dev->bus_ops.acpi_op_start)
+ acpi_start_single_object(acpi_dev);
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Found driver [%s] for device [%s]\n",
+ acpi_drv->name, acpi_dev->pnp.bus_id));
+ get_device(dev);
+ }
+ return ret;
+}
+static int acpi_device_remove(struct device * dev)
+{
+ struct acpi_device *acpi_dev = to_acpi_device(dev);
+ struct acpi_driver *acpi_drv = acpi_dev->driver;
+
+ if (acpi_drv) {
+ if (acpi_drv->ops.stop)
+ acpi_drv->ops.stop(acpi_dev, acpi_dev->removal_type);
+ if (acpi_drv->ops.remove)
+ acpi_drv->ops.remove(acpi_dev, acpi_dev->removal_type);
+ }
+ acpi_dev->driver = NULL;
+ acpi_driver_data(dev) = NULL;
+
+ put_device(dev);
return 0;
}
-static struct kset_uevent_ops namespace_uevent_ops = {
- .uevent = &namespace_uevent,
-};
+static void acpi_device_shutdown(struct device *dev)
+{
+ struct acpi_device *acpi_dev = to_acpi_device(dev);
+ struct acpi_driver *acpi_drv = acpi_dev->driver;
+
+ if (acpi_drv && acpi_drv->ops.shutdown)
+ acpi_drv->ops.shutdown(acpi_dev);
-static struct kset acpi_namespace_kset = {
- .kobj = {
- .name = "namespace",
- },
- .subsys = &acpi_subsys,
- .ktype = &ktype_acpi_ns,
- .uevent_ops = &namespace_uevent_ops,
+ return ;
+}
+
+static struct bus_type acpi_bus_type = {
+ .name = "acpi",
+ .suspend = acpi_device_suspend,
+ .resume = acpi_device_resume,
+ .shutdown = acpi_device_shutdown,
+ .match = acpi_bus_match,
+ .probe = acpi_device_probe,
+ .remove = acpi_device_remove,
+ .uevent = acpi_device_uevent,
};
-static void acpi_device_register(struct acpi_device *device,
+static int acpi_device_register(struct acpi_device *device,
struct acpi_device *parent)
{
- int err;
-
+ int result;
+ struct acpi_device_bus_id *acpi_device_bus_id, *new_bus_id;
+ int found = 0;
/*
* Linkage
* -------
@@ -126,7 +329,33 @@ static void acpi_device_register(struct acpi_device *device,
INIT_LIST_HEAD(&device->g_list);
INIT_LIST_HEAD(&device->wakeup_list);
+ new_bus_id = kzalloc(sizeof(struct acpi_device_bus_id), GFP_KERNEL);
+ if (!new_bus_id) {
+ printk(KERN_ERR PREFIX "Memory allocation error\n");
+ return -ENOMEM;
+ }
+
spin_lock(&acpi_device_lock);
+ /*
+ * Find suitable bus_id and instance number in acpi_bus_id_list
+ * If failed, create one and link it into acpi_bus_id_list
+ */
+ list_for_each_entry(acpi_device_bus_id, &acpi_bus_id_list, node) {
+ if(!strcmp(acpi_device_bus_id->bus_id, device->flags.hardware_id? device->pnp.hardware_id : "device")) {
+ acpi_device_bus_id->instance_no ++;
+ found = 1;
+ kfree(new_bus_id);
+ break;
+ }
+ }
+ if(!found) {
+ acpi_device_bus_id = new_bus_id;
+ strcpy(acpi_device_bus_id->bus_id, device->flags.hardware_id ? device->pnp.hardware_id : "device");
+ acpi_device_bus_id->instance_no = 0;
+ list_add_tail(&acpi_device_bus_id->node, &acpi_bus_id_list);
+ }
+ sprintf(device->dev.bus_id, "%s:%02x", acpi_device_bus_id->bus_id, acpi_device_bus_id->instance_no);
+
if (device->parent) {
list_add_tail(&device->node, &device->parent->children);
list_add_tail(&device->g_list, &device->parent->g_list);
@@ -136,16 +365,33 @@ static void acpi_device_register(struct acpi_device *device,
list_add_tail(&device->wakeup_list, &acpi_wakeup_device_list);
spin_unlock(&acpi_device_lock);
- strlcpy(device->kobj.name, device->pnp.bus_id, KOBJ_NAME_LEN);
- if (parent)
- device->kobj.parent = &parent->kobj;
- device->kobj.ktype = &ktype_acpi_ns;
- device->kobj.kset = &acpi_namespace_kset;
- err = kobject_register(&device->kobj);
- if (err < 0)
- printk(KERN_WARNING "%s: kobject_register error: %d\n",
- __FUNCTION__, err);
- create_sysfs_device_files(device);
+ if (device->parent)
+ device->dev.parent = &parent->dev;
+ device->dev.bus = &acpi_bus_type;
+ device_initialize(&device->dev);
+ device->dev.release = &acpi_device_release;
+ result = device_add(&device->dev);
+ if(result) {
+ printk("Error adding device %s", device->dev.bus_id);
+ goto end;
+ }
+
+ result = acpi_device_setup_files(device);
+ if(result)
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error creating sysfs interface for device %s\n", device->dev.bus_id));
+
+ device->removal_type = ACPI_BUS_REMOVAL_NORMAL;
+ return 0;
+ end:
+ spin_lock(&acpi_device_lock);
+ if (device->parent) {
+ list_del(&device->node);
+ list_del(&device->g_list);
+ } else
+ list_del(&device->g_list);
+ list_del(&device->wakeup_list);
+ spin_unlock(&acpi_device_lock);
+ return result;
}
static void acpi_device_unregister(struct acpi_device *device, int type)
@@ -158,81 +404,143 @@ static void acpi_device_unregister(struct acpi_device *device, int type)
list_del(&device->g_list);
list_del(&device->wakeup_list);
-
spin_unlock(&acpi_device_lock);
acpi_detach_data(device->handle, acpi_bus_data_handler);
- remove_sysfs_device_files(device);
- kobject_unregister(&device->kobj);
+
+ acpi_device_remove_files(device);
+ device_unregister(&device->dev);
}
-void acpi_bus_data_handler(acpi_handle handle, u32 function, void *context)
+/* --------------------------------------------------------------------------
+ Driver Management
+ -------------------------------------------------------------------------- */
+/**
+ * acpi_bus_driver_init - add a device to a driver
+ * @device: the device to add and initialize
+ * @driver: driver for the device
+ *
+ * Used to initialize a device via its device driver. Called whenever a
+ * driver is bound to a device. Invokes the driver's add() ops.
+ */
+static int
+acpi_bus_driver_init(struct acpi_device *device, struct acpi_driver *driver)
{
+ int result = 0;
- /* TBD */
- return;
-}
+ if (!device || !driver)
+ return -EINVAL;
-static int acpi_bus_get_power_flags(struct acpi_device *device)
-{
- acpi_status status = 0;
- acpi_handle handle = NULL;
- u32 i = 0;
+ if (!driver->ops.add)
+ return -ENOSYS;
+ result = driver->ops.add(device);
+ if (result) {
+ device->driver = NULL;
+ acpi_driver_data(device) = NULL;
+ return result;
+ }
- /*
- * Power Management Flags
- */
- status = acpi_get_handle(device->handle, "_PSC", &handle);
- if (ACPI_SUCCESS(status))
- device->power.flags.explicit_get = 1;
- status = acpi_get_handle(device->handle, "_IRC", &handle);
- if (ACPI_SUCCESS(status))
- device->power.flags.inrush_current = 1;
+ device->driver = driver;
/*
- * Enumerate supported power management states
+ * TBD - Configuration Management: Assign resources to device based
+ * upon possible configuration and currently allocated resources.
*/
- for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3; i++) {
- struct acpi_device_power_state *ps = &device->power.states[i];
- char object_name[5] = { '_', 'P', 'R', '0' + i, '\0' };
- /* Evaluate "_PRx" to se if power resources are referenced */
- acpi_evaluate_reference(device->handle, object_name, NULL,
- &ps->resources);
- if (ps->resources.count) {
- device->power.flags.power_resources = 1;
- ps->flags.valid = 1;
- }
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Driver successfully bound to device\n"));
+ return 0;
+}
- /* Evaluate "_PSx" to see if we can do explicit sets */
- object_name[2] = 'S';
- status = acpi_get_handle(device->handle, object_name, &handle);
- if (ACPI_SUCCESS(status)) {
- ps->flags.explicit_set = 1;
- ps->flags.valid = 1;
- }
+static int acpi_start_single_object(struct acpi_device *device)
+{
+ int result = 0;
+ struct acpi_driver *driver;
- /* State is valid if we have some power control */
- if (ps->resources.count || ps->flags.explicit_set)
- ps->flags.valid = 1;
- ps->power = -1; /* Unknown - driver assigned */
- ps->latency = -1; /* Unknown - driver assigned */
+ if (!(driver = device->driver))
+ return 0;
+
+ if (driver->ops.start) {
+ result = driver->ops.start(device);
+ if (result && driver->ops.remove)
+ driver->ops.remove(device, ACPI_BUS_REMOVAL_NORMAL);
}
- /* Set defaults for D0 and D3 states (always valid) */
- device->power.states[ACPI_STATE_D0].flags.valid = 1;
- device->power.states[ACPI_STATE_D0].power = 100;
- device->power.states[ACPI_STATE_D3].flags.valid = 1;
- device->power.states[ACPI_STATE_D3].power = 0;
+ return result;
+}
- /* TBD: System wake support and resource requirements. */
+/**
+ * acpi_bus_register_driver - register a driver with the ACPI bus
+ * @driver: driver being registered
+ *
+ * Registers a driver with the ACPI bus. Searches the namespace for all
+ * devices that match the driver's criteria and binds. Returns zero for
+ * success or a negative error status for failure.
+ */
+int acpi_bus_register_driver(struct acpi_driver *driver)
+{
+ int ret;
- device->power.state = ACPI_STATE_UNKNOWN;
+ if (acpi_disabled)
+ return -ENODEV;
+ driver->drv.name = driver->name;
+ driver->drv.bus = &acpi_bus_type;
+ driver->drv.owner = driver->owner;
- return 0;
+ ret = driver_register(&driver->drv);
+ return ret;
+}
+
+EXPORT_SYMBOL(acpi_bus_register_driver);
+
+/**
+ * acpi_bus_unregister_driver - unregisters a driver with the APIC bus
+ * @driver: driver to unregister
+ *
+ * Unregisters a driver with the ACPI bus. Searches the namespace for all
+ * devices that match the driver's criteria and unbinds.
+ */
+void acpi_bus_unregister_driver(struct acpi_driver *driver)
+{
+ driver_unregister(&driver->drv);
+}
+
+EXPORT_SYMBOL(acpi_bus_unregister_driver);
+
+/* --------------------------------------------------------------------------
+ Device Enumeration
+ -------------------------------------------------------------------------- */
+acpi_status
+acpi_bus_get_ejd(acpi_handle handle, acpi_handle *ejd)
+{
+ acpi_status status;
+ acpi_handle tmp;
+ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+ union acpi_object *obj;
+
+ status = acpi_get_handle(handle, "_EJD", &tmp);
+ if (ACPI_FAILURE(status))
+ return status;
+
+ status = acpi_evaluate_object(handle, "_EJD", NULL, &buffer);
+ if (ACPI_SUCCESS(status)) {
+ obj = buffer.pointer;
+ status = acpi_get_handle(NULL, obj->string.pointer, ejd);
+ kfree(buffer.pointer);
+ }
+ return status;
+}
+EXPORT_SYMBOL_GPL(acpi_bus_get_ejd);
+
+void acpi_bus_data_handler(acpi_handle handle, u32 function, void *context)
+{
+
+ /* TBD */
+
+ return;
}
int acpi_match_ids(struct acpi_device *device, char *ids)
@@ -254,6 +562,12 @@ int acpi_match_ids(struct acpi_device *device, char *ids)
return -ENOENT;
}
+static int acpi_bus_get_perf_flags(struct acpi_device *device)
+{
+ device->performance.state = ACPI_STATE_UNKNOWN;
+ return 0;
+}
+
static acpi_status
acpi_bus_extract_wakeup_device_power_package(struct acpi_device *device,
union acpi_object *package)
@@ -338,359 +652,66 @@ static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
return 0;
}
-/* --------------------------------------------------------------------------
- ACPI sysfs device file support
- -------------------------------------------------------------------------- */
-static ssize_t acpi_eject_store(struct acpi_device *device,
- const char *buf, size_t count);
-
-#define ACPI_DEVICE_ATTR(_name,_mode,_show,_store) \
-static struct acpi_device_attribute acpi_device_attr_##_name = \
- __ATTR(_name, _mode, _show, _store)
-
-ACPI_DEVICE_ATTR(eject, 0200, NULL, acpi_eject_store);
-
-/**
- * setup_sys_fs_device_files - sets up the device files under device namespace
- * @dev: acpi_device object
- * @func: function pointer to create or destroy the device file
- */
-static void
-setup_sys_fs_device_files(struct acpi_device *dev,
- acpi_device_sysfs_files * func)
-{
- acpi_status status;
- acpi_handle temp = NULL;
-
- /*
- * If device has _EJ0, 'eject' file is created that is used to trigger
- * hot-removal function from userland.
- */
- status = acpi_get_handle(dev->handle, "_EJ0", &temp);
- if (ACPI_SUCCESS(status))
- (*(func)) (&dev->kobj, &acpi_device_attr_eject.attr);
-}
-
-static int acpi_eject_operation(acpi_handle handle, int lockable)
+static int acpi_bus_get_power_flags(struct acpi_device *device)
{
- struct acpi_object_list arg_list;
- union acpi_object arg;
- acpi_status status = AE_OK;
-
- /*
- * TBD: evaluate _PS3?
- */
-
- if (lockable) {
- arg_list.count = 1;
- arg_list.pointer = &arg;
- arg.type = ACPI_TYPE_INTEGER;
- arg.integer.value = 0;
- acpi_evaluate_object(handle, "_LCK", &arg_list, NULL);
- }
+ acpi_status status = 0;
+ acpi_handle handle = NULL;
+ u32 i = 0;
- arg_list.count = 1;
- arg_list.pointer = &arg;
- arg.type = ACPI_TYPE_INTEGER;
- arg.integer.value = 1;
/*
- * TBD: _EJD support.
+ * Power Management Flags
*/
-
- status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL);
- if (ACPI_FAILURE(status)) {
- return (-ENODEV);
- }
-
- return (0);
-}
-
-static ssize_t
-acpi_eject_store(struct acpi_device *device, const char *buf, size_t count)
-{
- int result;
- int ret = count;
- int islockable;
- acpi_status status;
- acpi_handle handle;
- acpi_object_type type = 0;
-
- if ((!count) || (buf[0] != '1')) {
- return -EINVAL;
- }
-#ifndef FORCE_EJECT
- if (device->driver == NULL) {
- ret = -ENODEV;
- goto err;
- }
-#endif
- status = acpi_get_type(device->handle, &type);
- if (ACPI_FAILURE(status) || (!device->flags.ejectable)) {
- ret = -ENODEV;
- goto err;
- }
-
- islockable = device->flags.lockable;
- handle = device->handle;
-
- result = acpi_bus_trim(device, 1);
-
- if (!result)
- result = acpi_eject_operation(handle, islockable);
-
- if (result) {
- ret = -EBUSY;
- }
- err:
- return ret;
-}
-
-/* --------------------------------------------------------------------------
- Performance Management
- -------------------------------------------------------------------------- */
-
-static int acpi_bus_get_perf_flags(struct acpi_device *device)
-{
- device->performance.state = ACPI_STATE_UNKNOWN;
- return 0;
-}
-
-/* --------------------------------------------------------------------------
- Driver Management
- -------------------------------------------------------------------------- */
-
-static LIST_HEAD(acpi_bus_drivers);
-
-/**
- * acpi_bus_match - match device IDs to driver's supported IDs
- * @device: the device that we are trying to match to a driver
- * @driver: driver whose device id table is being checked
- *
- * Checks the device's hardware (_HID) or compatible (_CID) ids to see if it
- * matches the specified driver's criteria.
- */
-static int
-acpi_bus_match(struct acpi_device *device, struct acpi_driver *driver)
-{
- if (driver && driver->ops.match)
- return driver->ops.match(device, driver);
- return acpi_match_ids(device, driver->ids);
-}
-
-/**
- * acpi_bus_driver_init - add a device to a driver
- * @device: the device to add and initialize
- * @driver: driver for the device
- *
- * Used to initialize a device via its device driver. Called whenever a
- * driver is bound to a device. Invokes the driver's add() and start() ops.
- */
-static int
-acpi_bus_driver_init(struct acpi_device *device, struct acpi_driver *driver)
-{
- int result = 0;
-
-
- if (!device || !driver)
- return -EINVAL;
-
- if (!driver->ops.add)
- return -ENOSYS;
-
- result = driver->ops.add(device);
- if (result) {
- device->driver = NULL;
- acpi_driver_data(device) = NULL;
- return result;
- }
-
- device->driver = driver;
+ status = acpi_get_handle(device->handle, "_PSC", &handle);
+ if (ACPI_SUCCESS(status))
+ device->power.flags.explicit_get = 1;
+ status = acpi_get_handle(device->handle, "_IRC", &handle);
+ if (ACPI_SUCCESS(status))
+ device->power.flags.inrush_current = 1;
/*
- * TBD - Configuration Management: Assign resources to device based
- * upon possible configuration and currently allocated resources.
+ * Enumerate supported power management states
*/
+ for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3; i++) {
+ struct acpi_device_power_state *ps = &device->power.states[i];
+ char object_name[5] = { '_', 'P', 'R', '0' + i, '\0' };
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Driver successfully bound to device\n"));
- return 0;
-}
-
-static int acpi_start_single_object(struct acpi_device *device)
-{
- int result = 0;
- struct acpi_driver *driver;
-
-
- if (!(driver = device->driver))
- return 0;
-
- if (driver->ops.start) {
- result = driver->ops.start(device);
- if (result && driver->ops.remove)
- driver->ops.remove(device, ACPI_BUS_REMOVAL_NORMAL);
- }
-
- return result;
-}
-
-static void acpi_driver_attach(struct acpi_driver *drv)
-{
- struct list_head *node, *next;
-
-
- spin_lock(&acpi_device_lock);
- list_for_each_safe(node, next, &acpi_device_list) {
- struct acpi_device *dev =
- container_of(node, struct acpi_device, g_list);
-
- if (dev->driver || !dev->status.present)
- continue;
- spin_unlock(&acpi_device_lock);
-
- if (!acpi_bus_match(dev, drv)) {
- if (!acpi_bus_driver_init(dev, drv)) {
- acpi_start_single_object(dev);
- atomic_inc(&drv->references);
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Found driver [%s] for device [%s]\n",
- drv->name, dev->pnp.bus_id));
- }
+ /* Evaluate "_PRx" to se if power resources are referenced */
+ acpi_evaluate_reference(device->handle, object_name, NULL,
+ &ps->resources);
+ if (ps->resources.count) {
+ device->power.flags.power_resources = 1;
+ ps->flags.valid = 1;
}
- spin_lock(&acpi_device_lock);
- }
- spin_unlock(&acpi_device_lock);
-}
-
-static void acpi_driver_detach(struct acpi_driver *drv)
-{
- struct list_head *node, *next;
-
- spin_lock(&acpi_device_lock);
- list_for_each_safe(node, next, &acpi_device_list) {
- struct acpi_device *dev =
- container_of(node, struct acpi_device, g_list);
-
- if (dev->driver == drv) {
- spin_unlock(&acpi_device_lock);
- if (drv->ops.remove)
- drv->ops.remove(dev, ACPI_BUS_REMOVAL_NORMAL);
- spin_lock(&acpi_device_lock);
- dev->driver = NULL;
- dev->driver_data = NULL;
- atomic_dec(&drv->references);
+ /* Evaluate "_PSx" to see if we can do explicit sets */
+ object_name[2] = 'S';
+ status = acpi_get_handle(device->handle, object_name, &handle);
+ if (ACPI_SUCCESS(status)) {
+ ps->flags.explicit_set = 1;
+ ps->flags.valid = 1;
}
- }
- spin_unlock(&acpi_device_lock);
-}
-
-/**
- * acpi_bus_register_driver - register a driver with the ACPI bus
- * @driver: driver being registered
- *
- * Registers a driver with the ACPI bus. Searches the namespace for all
- * devices that match the driver's criteria and binds. Returns zero for
- * success or a negative error status for failure.
- */
-int acpi_bus_register_driver(struct acpi_driver *driver)
-{
-
- if (acpi_disabled)
- return -ENODEV;
-
- spin_lock(&acpi_device_lock);
- list_add_tail(&driver->node, &acpi_bus_drivers);
- spin_unlock(&acpi_device_lock);
- acpi_driver_attach(driver);
-
- return 0;
-}
-
-EXPORT_SYMBOL(acpi_bus_register_driver);
-
-/**
- * acpi_bus_unregister_driver - unregisters a driver with the APIC bus
- * @driver: driver to unregister
- *
- * Unregisters a driver with the ACPI bus. Searches the namespace for all
- * devices that match the driver's criteria and unbinds.
- */
-void acpi_bus_unregister_driver(struct acpi_driver *driver)
-{
- acpi_driver_detach(driver);
-
- if (!atomic_read(&driver->references)) {
- spin_lock(&acpi_device_lock);
- list_del_init(&driver->node);
- spin_unlock(&acpi_device_lock);
- }
- return;
-}
-
-EXPORT_SYMBOL(acpi_bus_unregister_driver);
-
-/**
- * acpi_bus_find_driver - check if there is a driver installed for the device
- * @device: device that we are trying to find a supporting driver for
- *
- * Parses the list of registered drivers looking for a driver applicable for
- * the specified device.
- */
-static int acpi_bus_find_driver(struct acpi_device *device)
-{
- int result = 0;
- struct list_head *node, *next;
+ /* State is valid if we have some power control */
+ if (ps->resources.count || ps->flags.explicit_set)
+ ps->flags.valid = 1;
- spin_lock(&acpi_device_lock);
- list_for_each_safe(node, next, &acpi_bus_drivers) {
- struct acpi_driver *driver =
- container_of(node, struct acpi_driver, node);
-
- atomic_inc(&driver->references);
- spin_unlock(&acpi_device_lock);
- if (!acpi_bus_match(device, driver)) {
- result = acpi_bus_driver_init(device, driver);
- if (!result)
- goto Done;
- }
- atomic_dec(&driver->references);
- spin_lock(&acpi_device_lock);
+ ps->power = -1; /* Unknown - driver assigned */
+ ps->latency = -1; /* Unknown - driver assigned */
}
- spin_unlock(&acpi_device_lock);
-
- Done:
- return result;
-}
-/* --------------------------------------------------------------------------
- Device Enumeration
- -------------------------------------------------------------------------- */
+ /* Set defaults for D0 and D3 states (always valid) */
+ device->power.states[ACPI_STATE_D0].flags.valid = 1;
+ device->power.states[ACPI_STATE_D0].power = 100;
+ device->power.states[ACPI_STATE_D3].flags.valid = 1;
+ device->power.states[ACPI_STATE_D3].power = 0;
-acpi_status
-acpi_bus_get_ejd(acpi_handle handle, acpi_handle *ejd)
-{
- acpi_status status;
- acpi_handle tmp;
- struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
- union acpi_object *obj;
+ /* TBD: System wake support and resource requirements. */
- status = acpi_get_handle(handle, "_EJD", &tmp);
- if (ACPI_FAILURE(status))
- return status;
+ device->power.state = ACPI_STATE_UNKNOWN;
- status = acpi_evaluate_object(handle, "_EJD", NULL, &buffer);
- if (ACPI_SUCCESS(status)) {
- obj = buffer.pointer;
- status = acpi_get_handle(NULL, obj->string.pointer, ejd);
- kfree(buffer.pointer);
- }
- return status;
+ return 0;
}
-EXPORT_SYMBOL_GPL(acpi_bus_get_ejd);
-
static int acpi_bus_get_flags(struct acpi_device *device)
{
@@ -782,6 +803,75 @@ static void acpi_device_get_busid(struct acpi_device *device,
}
}
+static int
+acpi_video_bus_match(struct acpi_device *device)
+{
+ acpi_handle h_dummy1;
+ acpi_handle h_dummy2;
+ acpi_handle h_dummy3;
+
+
+ if (!device)
+ return -EINVAL;
+
+ /* Since there is no HID, CID for ACPI Video drivers, we have
+ * to check well known required nodes for each feature we support.
+ */
+
+ /* Does this device able to support video switching ? */
+ if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy1)) &&
+ ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy2)))
+ return 0;
+
+ /* Does this device able to retrieve a video ROM ? */
+ if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy1)))
+ return 0;
+
+ /* Does this device able to configure which video head to be POSTed ? */
+ if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_VPO", &h_dummy1)) &&
+ ACPI_SUCCESS(acpi_get_handle(device->handle, "_GPD", &h_dummy2)) &&
+ ACPI_SUCCESS(acpi_get_handle(device->handle, "_SPD", &h_dummy3)))
+ return 0;
+
+ return -ENODEV;
+}
+
+/*
+ * acpi_bay_match - see if a device is an ejectable driver bay
+ *
+ * If an acpi object is ejectable and has one of the ACPI ATA methods defined,
+ * then we can safely call it an ejectable drive bay
+ */
+static int acpi_bay_match(struct acpi_device *device){
+ acpi_status status;
+ acpi_handle handle;
+ acpi_handle tmp;
+ acpi_handle phandle;
+
+ handle = device->handle;
+
+ status = acpi_get_handle(handle, "_EJ0", &tmp);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+
+ if ((ACPI_SUCCESS(acpi_get_handle(handle, "_GTF", &tmp))) ||
+ (ACPI_SUCCESS(acpi_get_handle(handle, "_GTM", &tmp))) ||
+ (ACPI_SUCCESS(acpi_get_handle(handle, "_STM", &tmp))) ||
+ (ACPI_SUCCESS(acpi_get_handle(handle, "_SDD", &tmp))))
+ return 0;
+
+ if (acpi_get_parent(handle, &phandle))
+ return -ENODEV;
+
+ if ((ACPI_SUCCESS(acpi_get_handle(phandle, "_GTF", &tmp))) ||
+ (ACPI_SUCCESS(acpi_get_handle(phandle, "_GTM", &tmp))) ||
+ (ACPI_SUCCESS(acpi_get_handle(phandle, "_STM", &tmp))) ||
+ (ACPI_SUCCESS(acpi_get_handle(phandle, "_SDD", &tmp))))
+ return 0;
+
+ return -ENODEV;
+}
+
static void acpi_device_set_id(struct acpi_device *device,
struct acpi_device *parent, acpi_handle handle,
int type)
@@ -812,6 +902,16 @@ static void acpi_device_set_id(struct acpi_device *device,
device->pnp.bus_address = info->address;
device->flags.bus_address = 1;
}
+
+ if(!(info->valid & (ACPI_VALID_HID | ACPI_VALID_CID))){
+ status = acpi_video_bus_match(device);
+ if(ACPI_SUCCESS(status))
+ hid = ACPI_VIDEO_HID;
+
+ status = acpi_bay_match(device);
+ if (ACPI_SUCCESS(status))
+ hid = ACPI_BAY_HID;
+ }
break;
case ACPI_BUS_TYPE_POWER:
hid = ACPI_POWER_HID;
@@ -888,86 +988,24 @@ static int acpi_device_set_context(struct acpi_device *device, int type)
return result;
}
-static void acpi_device_get_debug_info(struct acpi_device *device,
- acpi_handle handle, int type)
-{
-#ifdef CONFIG_ACPI_DEBUG_OUTPUT
- char *type_string = NULL;
- char name[80] = { '?', '\0' };
- struct acpi_buffer buffer = { sizeof(name), name };
-
- switch (type) {
- case ACPI_BUS_TYPE_DEVICE:
- type_string = "Device";
- acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
- break;
- case ACPI_BUS_TYPE_POWER:
- type_string = "Power Resource";
- acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
- break;
- case ACPI_BUS_TYPE_PROCESSOR:
- type_string = "Processor";
- acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
- break;
- case ACPI_BUS_TYPE_SYSTEM:
- type_string = "System";
- acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
- break;
- case ACPI_BUS_TYPE_THERMAL:
- type_string = "Thermal Zone";
- acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
- break;
- case ACPI_BUS_TYPE_POWER_BUTTON:
- type_string = "Power Button";
- sprintf(name, "PWRB");
- break;
- case ACPI_BUS_TYPE_SLEEP_BUTTON:
- type_string = "Sleep Button";
- sprintf(name, "SLPB");
- break;
- }
-
- printk(KERN_DEBUG "Found %s %s [%p]\n", type_string, name, handle);
-#endif /*CONFIG_ACPI_DEBUG_OUTPUT */
-}
-
static int acpi_bus_remove(struct acpi_device *dev, int rmdevice)
{
- int result = 0;
- struct acpi_driver *driver;
-
-
if (!dev)
return -EINVAL;
- driver = dev->driver;
-
- if ((driver) && (driver->ops.remove)) {
-
- if (driver->ops.stop) {
- result = driver->ops.stop(dev, ACPI_BUS_REMOVAL_EJECT);
- if (result)
- return result;
- }
-
- result = dev->driver->ops.remove(dev, ACPI_BUS_REMOVAL_EJECT);
- if (result) {
- return result;
- }
-
- atomic_dec(&dev->driver->references);
- dev->driver = NULL;
- acpi_driver_data(dev) = NULL;
- }
+ dev->removal_type = ACPI_BUS_REMOVAL_EJECT;
+ device_release_driver(&dev->dev);
if (!rmdevice)
return 0;
+ /*
+ * unbind _ADR-Based Devices when hot removal
+ */
if (dev->flags.bus_address) {
if ((dev->parent) && (dev->parent->ops.unbind))
dev->parent->ops.unbind(dev);
}
-
acpi_device_unregister(dev, ACPI_BUS_REMOVAL_EJECT);
return 0;
@@ -975,7 +1013,8 @@ static int acpi_bus_remove(struct acpi_device *dev, int rmdevice)
static int
acpi_add_single_object(struct acpi_device **child,
- struct acpi_device *parent, acpi_handle handle, int type)
+ struct acpi_device *parent, acpi_handle handle, int type,
+ struct acpi_bus_ops *ops)
{
int result = 0;
struct acpi_device *device = NULL;
@@ -992,6 +1031,8 @@ acpi_add_single_object(struct acpi_device **child,
device->handle = handle;
device->parent = parent;
+ device->bus_ops = *ops; /* workround for not call .start */
+
acpi_device_get_busid(device, handle, type);
@@ -1076,33 +1117,16 @@ acpi_add_single_object(struct acpi_device **child,
if ((result = acpi_device_set_context(device, type)))
goto end;
- acpi_device_get_debug_info(device, handle, type);
-
- acpi_device_register(device, parent);
+ result = acpi_device_register(device, parent);
/*
- * Bind _ADR-Based Devices
- * -----------------------
- * If there's a a bus address (_ADR) then we utilize the parent's
- * 'bind' function (if exists) to bind the ACPI- and natively-
- * enumerated device representations.
+ * Bind _ADR-Based Devices when hot add
*/
if (device->flags.bus_address) {
if (device->parent && device->parent->ops.bind)
device->parent->ops.bind(device);
}
- /*
- * Locate & Attach Driver
- * ----------------------
- * If there's a hardware id (_HID) or compatible ids (_CID) we check
- * to see if there's a driver installed for this kind of device. Note
- * that drivers can install before or after a device is enumerated.
- *
- * TBD: Assumes LDM provides driver hot-plug capability.
- */
- acpi_bus_find_driver(device);
-
end:
if (!result)
*child = device;
@@ -1188,14 +1212,14 @@ static int acpi_bus_scan(struct acpi_device *start, struct acpi_bus_ops *ops)
if (ops->acpi_op_add)
status = acpi_add_single_object(&child, parent,
- chandle, type);
+ chandle, type, ops);
else
status = acpi_bus_get_device(chandle, &child);
if (ACPI_FAILURE(status))
continue;
- if (ops->acpi_op_start) {
+ if (ops->acpi_op_start && !(ops->acpi_op_add)) {
status = acpi_start_single_object(child);
if (ACPI_FAILURE(status))
continue;
@@ -1233,13 +1257,13 @@ acpi_bus_add(struct acpi_device **child,
int result;
struct acpi_bus_ops ops;
+ memset(&ops, 0, sizeof(ops));
+ ops.acpi_op_add = 1;
- result = acpi_add_single_object(child, parent, handle, type);
- if (!result) {
- memset(&ops, 0, sizeof(ops));
- ops.acpi_op_add = 1;
+ result = acpi_add_single_object(child, parent, handle, type, &ops);
+ if (!result)
result = acpi_bus_scan(*child, &ops);
- }
+
return result;
}
@@ -1325,127 +1349,35 @@ static int acpi_bus_scan_fixed(struct acpi_device *root)
{
int result = 0;
struct acpi_device *device = NULL;
-
+ struct acpi_bus_ops ops;
if (!root)
return -ENODEV;
+ memset(&ops, 0, sizeof(ops));
+ ops.acpi_op_add = 1;
+ ops.acpi_op_start = 1;
+
/*
* Enumerate all fixed-feature devices.
*/
- if (acpi_fadt.pwr_button == 0) {
+ if ((acpi_gbl_FADT.flags & ACPI_FADT_POWER_BUTTON) == 0) {
result = acpi_add_single_object(&device, acpi_root,
NULL,
- ACPI_BUS_TYPE_POWER_BUTTON);
- if (!result)
- result = acpi_start_single_object(device);
+ ACPI_BUS_TYPE_POWER_BUTTON,
+ &ops);
}
- if (acpi_fadt.sleep_button == 0) {
+ if ((acpi_gbl_FADT.flags & ACPI_FADT_SLEEP_BUTTON) == 0) {
result = acpi_add_single_object(&device, acpi_root,
NULL,
- ACPI_BUS_TYPE_SLEEP_BUTTON);
- if (!result)
- result = acpi_start_single_object(device);
+ ACPI_BUS_TYPE_SLEEP_BUTTON,
+ &ops);
}
return result;
}
-
-static inline struct acpi_device * to_acpi_dev(struct device * dev)
-{
- return container_of(dev, struct acpi_device, dev);
-}
-
-
-static int root_suspend(struct acpi_device * acpi_dev, pm_message_t state)
-{
- struct acpi_device * dev, * next;
- int result;
-
- spin_lock(&acpi_device_lock);
- list_for_each_entry_safe_reverse(dev, next, &acpi_device_list, g_list) {
- if (dev->driver && dev->driver->ops.suspend) {
- spin_unlock(&acpi_device_lock);
- result = dev->driver->ops.suspend(dev, 0);
- if (result) {
- printk(KERN_ERR PREFIX "[%s - %s] Suspend failed: %d\n",
- acpi_device_name(dev),
- acpi_device_bid(dev), result);
- }
- spin_lock(&acpi_device_lock);
- }
- }
- spin_unlock(&acpi_device_lock);
- return 0;
-}
-
-
-static int acpi_device_suspend(struct device * dev, pm_message_t state)
-{
- struct acpi_device * acpi_dev = to_acpi_dev(dev);
-
- /*
- * For now, we should only register 1 generic device -
- * the ACPI root device - and from there, we walk the
- * tree of ACPI devices to suspend each one using the
- * ACPI driver methods.
- */
- if (acpi_dev->handle == ACPI_ROOT_OBJECT)
- root_suspend(acpi_dev, state);
- return 0;
-}
-
-
-
-static int root_resume(struct acpi_device * acpi_dev)
-{
- struct acpi_device * dev, * next;
- int result;
-
- spin_lock(&acpi_device_lock);
- list_for_each_entry_safe(dev, next, &acpi_device_list, g_list) {
- if (dev->driver && dev->driver->ops.resume) {
- spin_unlock(&acpi_device_lock);
- result = dev->driver->ops.resume(dev, 0);
- if (result) {
- printk(KERN_ERR PREFIX "[%s - %s] resume failed: %d\n",
- acpi_device_name(dev),
- acpi_device_bid(dev), result);
- }
- spin_lock(&acpi_device_lock);
- }
- }
- spin_unlock(&acpi_device_lock);
- return 0;
-}
-
-
-static int acpi_device_resume(struct device * dev)
-{
- struct acpi_device * acpi_dev = to_acpi_dev(dev);
-
- /*
- * For now, we should only register 1 generic device -
- * the ACPI root device - and from there, we walk the
- * tree of ACPI devices to resume each one using the
- * ACPI driver methods.
- */
- if (acpi_dev->handle == ACPI_ROOT_OBJECT)
- root_resume(acpi_dev);
- return 0;
-}
-
-
-static struct bus_type acpi_bus_type = {
- .name = "acpi",
- .suspend = acpi_device_suspend,
- .resume = acpi_device_resume,
-};
-
-
-
static int __init acpi_scan_init(void)
{
int result;
@@ -1455,9 +1387,9 @@ static int __init acpi_scan_init(void)
if (acpi_disabled)
return 0;
- result = kset_register(&acpi_namespace_kset);
- if (result < 0)
- printk(KERN_ERR PREFIX "kset_register error: %d\n", result);
+ memset(&ops, 0, sizeof(ops));
+ ops.acpi_op_add = 1;
+ ops.acpi_op_start = 1;
result = bus_register(&acpi_bus_type);
if (result) {
@@ -1469,32 +1401,16 @@ static int __init acpi_scan_init(void)
* Create the root device in the bus's device tree
*/
result = acpi_add_single_object(&acpi_root, NULL, ACPI_ROOT_OBJECT,
- ACPI_BUS_TYPE_SYSTEM);
+ ACPI_BUS_TYPE_SYSTEM, &ops);
if (result)
goto Done;
- result = acpi_start_single_object(acpi_root);
- if (result)
- goto Done;
-
- acpi_root->dev.bus = &acpi_bus_type;
- snprintf(acpi_root->dev.bus_id, BUS_ID_SIZE, "%s", acpi_bus_type.name);
- result = device_register(&acpi_root->dev);
- if (result) {
- /* We don't want to quit even if we failed to add suspend/resume */
- printk(KERN_ERR PREFIX "Could not register device\n");
- }
-
/*
* Enumerate devices in the ACPI namespace.
*/
result = acpi_bus_scan_fixed(acpi_root);
- if (!result) {
- memset(&ops, 0, sizeof(ops));
- ops.acpi_op_add = 1;
- ops.acpi_op_start = 1;
+ if (!result)
result = acpi_bus_scan(acpi_root, &ops);
- }
if (result)
acpi_device_unregister(acpi_root, ACPI_BUS_REMOVAL_NORMAL);
diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c
index 62ce87d7165..37a0930fc0a 100644
--- a/drivers/acpi/sleep/main.c
+++ b/drivers/acpi/sleep/main.c
@@ -200,7 +200,7 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
{},
};
-static int __init acpi_sleep_init(void)
+int __init acpi_sleep_init(void)
{
int i = 0;
@@ -229,4 +229,3 @@ static int __init acpi_sleep_init(void)
return 0;
}
-late_initcall(acpi_sleep_init);
diff --git a/drivers/acpi/sleep/poweroff.c b/drivers/acpi/sleep/poweroff.c
index 47fb4b394ee..d9801eff648 100644
--- a/drivers/acpi/sleep/poweroff.c
+++ b/drivers/acpi/sleep/poweroff.c
@@ -12,7 +12,6 @@
#include <linux/pm.h>
#include <linux/init.h>
#include <acpi/acpi_bus.h>
-#include <linux/sched.h>
#include <linux/sysdev.h>
#include <asm/io.h>
#include "sleep.h"
diff --git a/drivers/acpi/sleep/proc.c b/drivers/acpi/sleep/proc.c
index 34962578039..ccc11b33d89 100644
--- a/drivers/acpi/sleep/proc.c
+++ b/drivers/acpi/sleep/proc.c
@@ -73,7 +73,7 @@ acpi_system_write_sleep(struct file *file,
static int acpi_system_alarm_seq_show(struct seq_file *seq, void *offset)
{
u32 sec, min, hr;
- u32 day, mo, yr;
+ u32 day, mo, yr, cent = 0;
unsigned char rtc_control = 0;
unsigned long flags;
@@ -87,20 +87,19 @@ static int acpi_system_alarm_seq_show(struct seq_file *seq, void *offset)
rtc_control = CMOS_READ(RTC_CONTROL);
/* If we ever get an FACP with proper values... */
- if (acpi_gbl_FADT->day_alrm)
+ if (acpi_gbl_FADT.day_alarm)
/* ACPI spec: only low 6 its should be cared */
- day = CMOS_READ(acpi_gbl_FADT->day_alrm) & 0x3F;
+ day = CMOS_READ(acpi_gbl_FADT.day_alarm) & 0x3F;
else
day = CMOS_READ(RTC_DAY_OF_MONTH);
- if (acpi_gbl_FADT->mon_alrm)
- mo = CMOS_READ(acpi_gbl_FADT->mon_alrm);
+ if (acpi_gbl_FADT.month_alarm)
+ mo = CMOS_READ(acpi_gbl_FADT.month_alarm);
else
mo = CMOS_READ(RTC_MONTH);
- if (acpi_gbl_FADT->century)
- yr = CMOS_READ(acpi_gbl_FADT->century) * 100 +
- CMOS_READ(RTC_YEAR);
- else
- yr = CMOS_READ(RTC_YEAR);
+ if (acpi_gbl_FADT.century)
+ cent = CMOS_READ(acpi_gbl_FADT.century);
+
+ yr = CMOS_READ(RTC_YEAR);
spin_unlock_irqrestore(&rtc_lock, flags);
@@ -111,10 +110,11 @@ static int acpi_system_alarm_seq_show(struct seq_file *seq, void *offset)
BCD_TO_BIN(day);
BCD_TO_BIN(mo);
BCD_TO_BIN(yr);
+ BCD_TO_BIN(cent);
}
/* we're trusting the FADT (see above) */
- if (!acpi_gbl_FADT->century)
+ if (!acpi_gbl_FADT.century)
/* If we're not trusting the FADT, we should at least make it
* right for _this_ century... ehm, what is _this_ century?
*
@@ -134,6 +134,8 @@ static int acpi_system_alarm_seq_show(struct seq_file *seq, void *offset)
*
*/
yr += 2000;
+ else
+ yr += cent * 100;
seq_printf(seq, "%4.4u-", yr);
(mo > 12) ? seq_puts(seq, "**-") : seq_printf(seq, "%2.2u-", mo);
@@ -317,12 +319,12 @@ acpi_system_write_alarm(struct file *file,
* offsets into the CMOS RAM here -- which for some reason are pointing
* to the RTC area of memory.
*/
- if (acpi_gbl_FADT->day_alrm)
- CMOS_WRITE(day, acpi_gbl_FADT->day_alrm);
- if (acpi_gbl_FADT->mon_alrm)
- CMOS_WRITE(mo, acpi_gbl_FADT->mon_alrm);
- if (acpi_gbl_FADT->century)
- CMOS_WRITE(yr / 100, acpi_gbl_FADT->century);
+ if (acpi_gbl_FADT.day_alarm)
+ CMOS_WRITE(day, acpi_gbl_FADT.day_alarm);
+ if (acpi_gbl_FADT.month_alarm)
+ CMOS_WRITE(mo, acpi_gbl_FADT.month_alarm);
+ if (acpi_gbl_FADT.century)
+ CMOS_WRITE(yr / 100, acpi_gbl_FADT.century);
/* enable the rtc alarm interrupt */
rtc_control |= RTC_AIE;
CMOS_WRITE(rtc_control, RTC_CONTROL);
diff --git a/drivers/acpi/system.c b/drivers/acpi/system.c
index d86dcb3c236..83a8d309790 100644
--- a/drivers/acpi/system.c
+++ b/drivers/acpi/system.c
@@ -31,19 +31,36 @@
#include <acpi/acpi_drivers.h>
#define _COMPONENT ACPI_SYSTEM_COMPONENT
-ACPI_MODULE_NAME("acpi_system")
+ACPI_MODULE_NAME("system");
+#ifdef MODULE_PARAM_PREFIX
+#undef MODULE_PARAM_PREFIX
+#endif
+#define MODULE_PARAM_PREFIX "acpi."
+
#define ACPI_SYSTEM_CLASS "system"
-#define ACPI_SYSTEM_DRIVER_NAME "ACPI System Driver"
#define ACPI_SYSTEM_DEVICE_NAME "System"
#define ACPI_SYSTEM_FILE_INFO "info"
#define ACPI_SYSTEM_FILE_EVENT "event"
#define ACPI_SYSTEM_FILE_DSDT "dsdt"
#define ACPI_SYSTEM_FILE_FADT "fadt"
-extern struct fadt_descriptor acpi_fadt;
+
+/*
+ * Make ACPICA version work as module param
+ */
+static int param_get_acpica_version(char *buffer, struct kernel_param *kp) {
+ int result;
+
+ result = sprintf(buffer, "%x", ACPI_CA_VERSION);
+
+ return result;
+}
+
+module_param_call(acpica_version, NULL, param_get_acpica_version, NULL, 0444);
/* --------------------------------------------------------------------------
FS Interface (/proc)
-------------------------------------------------------------------------- */
+#ifdef CONFIG_ACPI_PROCFS
static int acpi_system_read_info(struct seq_file *seq, void *offset)
{
@@ -63,6 +80,7 @@ static const struct file_operations acpi_system_info_ops = {
.llseek = seq_lseek,
.release = single_release,
};
+#endif
static ssize_t acpi_system_read_dsdt(struct file *, char __user *, size_t,
loff_t *);
@@ -76,17 +94,16 @@ acpi_system_read_dsdt(struct file *file,
char __user * buffer, size_t count, loff_t * ppos)
{
acpi_status status = AE_OK;
- struct acpi_buffer dsdt = { ACPI_ALLOCATE_BUFFER, NULL };
+ struct acpi_table_header *dsdt = NULL;
ssize_t res;
- status = acpi_get_table(ACPI_TABLE_ID_DSDT, 1, &dsdt);
+ status = acpi_get_table(ACPI_SIG_DSDT, 1, &dsdt);
if (ACPI_FAILURE(status))
return -ENODEV;
res = simple_read_from_buffer(buffer, count, ppos,
- dsdt.pointer, dsdt.length);
- kfree(dsdt.pointer);
+ dsdt, dsdt->length);
return res;
}
@@ -103,17 +120,16 @@ acpi_system_read_fadt(struct file *file,
char __user * buffer, size_t count, loff_t * ppos)
{
acpi_status status = AE_OK;
- struct acpi_buffer fadt = { ACPI_ALLOCATE_BUFFER, NULL };
+ struct acpi_table_header *fadt = NULL;
ssize_t res;
- status = acpi_get_table(ACPI_TABLE_ID_FADT, 1, &fadt);
+ status = acpi_get_table(ACPI_SIG_FADT, 1, &fadt);
if (ACPI_FAILURE(status))
return -ENODEV;
res = simple_read_from_buffer(buffer, count, ppos,
- fadt.pointer, fadt.length);
- kfree(fadt.pointer);
+ fadt, fadt->length);
return res;
}
@@ -128,6 +144,7 @@ static int __init acpi_system_init(void)
if (acpi_disabled)
return 0;
+#ifdef CONFIG_ACPI_PROCFS
/* 'info' [R] */
name = ACPI_SYSTEM_FILE_INFO;
entry = create_proc_entry(name, S_IRUGO, acpi_root_dir);
@@ -136,6 +153,7 @@ static int __init acpi_system_init(void)
else {
entry->proc_fops = &acpi_system_info_ops;
}
+#endif
/* 'dsdt' [R] */
name = ACPI_SYSTEM_FILE_DSDT;
@@ -159,7 +177,9 @@ static int __init acpi_system_init(void)
Error:
remove_proc_entry(ACPI_SYSTEM_FILE_FADT, acpi_root_dir);
remove_proc_entry(ACPI_SYSTEM_FILE_DSDT, acpi_root_dir);
+#ifdef CONFIG_ACPI_PROCFS
remove_proc_entry(ACPI_SYSTEM_FILE_INFO, acpi_root_dir);
+#endif
error = -EFAULT;
goto Done;
diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c
index ffa30c9fccb..849e2c36180 100644
--- a/drivers/acpi/tables.c
+++ b/drivers/acpi/tables.c
@@ -25,7 +25,6 @@
#include <linux/init.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/smp.h>
#include <linux/string.h>
#include <linux/types.h>
@@ -38,154 +37,97 @@
#define ACPI_MAX_TABLES 128
-static char *acpi_table_signatures[ACPI_TABLE_COUNT] = {
- [ACPI_TABLE_UNKNOWN] = "????",
- [ACPI_APIC] = "APIC",
- [ACPI_BOOT] = "BOOT",
- [ACPI_DBGP] = "DBGP",
- [ACPI_DSDT] = "DSDT",
- [ACPI_ECDT] = "ECDT",
- [ACPI_ETDT] = "ETDT",
- [ACPI_FADT] = "FACP",
- [ACPI_FACS] = "FACS",
- [ACPI_OEMX] = "OEM",
- [ACPI_PSDT] = "PSDT",
- [ACPI_SBST] = "SBST",
- [ACPI_SLIT] = "SLIT",
- [ACPI_SPCR] = "SPCR",
- [ACPI_SRAT] = "SRAT",
- [ACPI_SSDT] = "SSDT",
- [ACPI_SPMI] = "SPMI",
- [ACPI_HPET] = "HPET",
- [ACPI_MCFG] = "MCFG",
-};
-
static char *mps_inti_flags_polarity[] = { "dfl", "high", "res", "low" };
static char *mps_inti_flags_trigger[] = { "dfl", "edge", "res", "level" };
-/* System Description Table (RSDT/XSDT) */
-struct acpi_table_sdt {
- unsigned long pa;
- enum acpi_table_id id;
- unsigned long size;
-} __attribute__ ((packed));
-
-static unsigned long sdt_pa; /* Physical Address */
-static unsigned long sdt_count; /* Table count */
+static struct acpi_table_desc initial_tables[ACPI_MAX_TABLES] __initdata;
-static struct acpi_table_sdt sdt_entry[ACPI_MAX_TABLES] __initdata;
-
-void acpi_table_print(struct acpi_table_header *header, unsigned long phys_addr)
-{
- char *name = NULL;
-
- if (!header)
- return;
-
- /* Some table signatures aren't good table names */
-
- if (!strncmp((char *)&header->signature,
- acpi_table_signatures[ACPI_APIC],
- sizeof(header->signature))) {
- name = "MADT";
- } else if (!strncmp((char *)&header->signature,
- acpi_table_signatures[ACPI_FADT],
- sizeof(header->signature))) {
- name = "FADT";
- } else
- name = header->signature;
-
- printk(KERN_DEBUG PREFIX
- "%.4s (v%3.3d %6.6s %8.8s 0x%08x %.4s 0x%08x) @ 0x%p\n", name,
- header->revision, header->oem_id, header->oem_table_id,
- header->oem_revision, header->asl_compiler_id,
- header->asl_compiler_revision, (void *)phys_addr);
-}
-
-void acpi_table_print_madt_entry(acpi_table_entry_header * header)
+void acpi_table_print_madt_entry(struct acpi_subtable_header * header)
{
if (!header)
return;
switch (header->type) {
- case ACPI_MADT_LAPIC:
+ case ACPI_MADT_TYPE_LOCAL_APIC:
{
- struct acpi_table_lapic *p =
- (struct acpi_table_lapic *)header;
+ struct acpi_madt_local_apic *p =
+ (struct acpi_madt_local_apic *)header;
printk(KERN_INFO PREFIX
"LAPIC (acpi_id[0x%02x] lapic_id[0x%02x] %s)\n",
- p->acpi_id, p->id,
- p->flags.enabled ? "enabled" : "disabled");
+ p->processor_id, p->id,
+ (p->lapic_flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled");
}
break;
- case ACPI_MADT_IOAPIC:
+ case ACPI_MADT_TYPE_IO_APIC:
{
- struct acpi_table_ioapic *p =
- (struct acpi_table_ioapic *)header;
+ struct acpi_madt_io_apic *p =
+ (struct acpi_madt_io_apic *)header;
printk(KERN_INFO PREFIX
"IOAPIC (id[0x%02x] address[0x%08x] gsi_base[%d])\n",
p->id, p->address, p->global_irq_base);
}
break;
- case ACPI_MADT_INT_SRC_OVR:
+ case ACPI_MADT_TYPE_INTERRUPT_OVERRIDE:
{
- struct acpi_table_int_src_ovr *p =
- (struct acpi_table_int_src_ovr *)header;
+ struct acpi_madt_interrupt_override *p =
+ (struct acpi_madt_interrupt_override *)header;
printk(KERN_INFO PREFIX
"INT_SRC_OVR (bus %d bus_irq %d global_irq %d %s %s)\n",
- p->bus, p->bus_irq, p->global_irq,
- mps_inti_flags_polarity[p->flags.polarity],
- mps_inti_flags_trigger[p->flags.trigger]);
- if (p->flags.reserved)
+ p->bus, p->source_irq, p->global_irq,
+ mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK],
+ mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2]);
+ if (p->inti_flags &
+ ~(ACPI_MADT_POLARITY_MASK | ACPI_MADT_TRIGGER_MASK))
printk(KERN_INFO PREFIX
"INT_SRC_OVR unexpected reserved flags: 0x%x\n",
- p->flags.reserved);
+ p->inti_flags &
+ ~(ACPI_MADT_POLARITY_MASK | ACPI_MADT_TRIGGER_MASK));
}
break;
- case ACPI_MADT_NMI_SRC:
+ case ACPI_MADT_TYPE_NMI_SOURCE:
{
- struct acpi_table_nmi_src *p =
- (struct acpi_table_nmi_src *)header;
+ struct acpi_madt_nmi_source *p =
+ (struct acpi_madt_nmi_source *)header;
printk(KERN_INFO PREFIX
"NMI_SRC (%s %s global_irq %d)\n",
- mps_inti_flags_polarity[p->flags.polarity],
- mps_inti_flags_trigger[p->flags.trigger],
+ mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK],
+ mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2],
p->global_irq);
}
break;
- case ACPI_MADT_LAPIC_NMI:
+ case ACPI_MADT_TYPE_LOCAL_APIC_NMI:
{
- struct acpi_table_lapic_nmi *p =
- (struct acpi_table_lapic_nmi *)header;
+ struct acpi_madt_local_apic_nmi *p =
+ (struct acpi_madt_local_apic_nmi *)header;
printk(KERN_INFO PREFIX
"LAPIC_NMI (acpi_id[0x%02x] %s %s lint[0x%x])\n",
- p->acpi_id,
- mps_inti_flags_polarity[p->flags.polarity],
- mps_inti_flags_trigger[p->flags.trigger],
+ p->processor_id,
+ mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK ],
+ mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2],
p->lint);
}
break;
- case ACPI_MADT_LAPIC_ADDR_OVR:
+ case ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE:
{
- struct acpi_table_lapic_addr_ovr *p =
- (struct acpi_table_lapic_addr_ovr *)header;
+ struct acpi_madt_local_apic_override *p =
+ (struct acpi_madt_local_apic_override *)header;
printk(KERN_INFO PREFIX
"LAPIC_ADDR_OVR (address[%p])\n",
(void *)(unsigned long)p->address);
}
break;
- case ACPI_MADT_IOSAPIC:
+ case ACPI_MADT_TYPE_IO_SAPIC:
{
- struct acpi_table_iosapic *p =
- (struct acpi_table_iosapic *)header;
+ struct acpi_madt_io_sapic *p =
+ (struct acpi_madt_io_sapic *)header;
printk(KERN_INFO PREFIX
"IOSAPIC (id[0x%x] address[%p] gsi_base[%d])\n",
p->id, (void *)(unsigned long)p->address,
@@ -193,26 +135,26 @@ void acpi_table_print_madt_entry(acpi_table_entry_header * header)
}
break;
- case ACPI_MADT_LSAPIC:
+ case ACPI_MADT_TYPE_LOCAL_SAPIC:
{
- struct acpi_table_lsapic *p =
- (struct acpi_table_lsapic *)header;
+ struct acpi_madt_local_sapic *p =
+ (struct acpi_madt_local_sapic *)header;
printk(KERN_INFO PREFIX
"LSAPIC (acpi_id[0x%02x] lsapic_id[0x%02x] lsapic_eid[0x%02x] %s)\n",
- p->acpi_id, p->id, p->eid,
- p->flags.enabled ? "enabled" : "disabled");
+ p->processor_id, p->id, p->eid,
+ (p->lapic_flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled");
}
break;
- case ACPI_MADT_PLAT_INT_SRC:
+ case ACPI_MADT_TYPE_INTERRUPT_SOURCE:
{
- struct acpi_table_plat_int_src *p =
- (struct acpi_table_plat_int_src *)header;
+ struct acpi_madt_interrupt_source *p =
+ (struct acpi_madt_interrupt_source *)header;
printk(KERN_INFO PREFIX
"PLAT_INT_SRC (%s %s type[0x%x] id[0x%04x] eid[0x%x] iosapic_vector[0x%x] global_irq[0x%x]\n",
- mps_inti_flags_polarity[p->flags.polarity],
- mps_inti_flags_trigger[p->flags.trigger],
- p->type, p->id, p->eid, p->iosapic_vector,
+ mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK],
+ mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2],
+ p->type, p->id, p->eid, p->io_sapic_vector,
p->global_irq);
}
break;
@@ -225,342 +167,85 @@ void acpi_table_print_madt_entry(acpi_table_entry_header * header)
}
}
-static int
-acpi_table_compute_checksum(void *table_pointer, unsigned long length)
-{
- u8 *p = table_pointer;
- unsigned long remains = length;
- unsigned long sum = 0;
-
- if (!p || !length)
- return -EINVAL;
-
- while (remains--)
- sum += *p++;
-
- return (sum & 0xFF);
-}
-
-/*
- * acpi_get_table_header_early()
- * for acpi_blacklisted(), acpi_table_get_sdt()
- */
-int __init
-acpi_get_table_header_early(enum acpi_table_id id,
- struct acpi_table_header **header)
-{
- unsigned int i;
- enum acpi_table_id temp_id;
-
- /* DSDT is different from the rest */
- if (id == ACPI_DSDT)
- temp_id = ACPI_FADT;
- else
- temp_id = id;
-
- /* Locate the table. */
-
- for (i = 0; i < sdt_count; i++) {
- if (sdt_entry[i].id != temp_id)
- continue;
- *header = (void *)
- __acpi_map_table(sdt_entry[i].pa, sdt_entry[i].size);
- if (!*header) {
- printk(KERN_WARNING PREFIX "Unable to map %s\n",
- acpi_table_signatures[temp_id]);
- return -ENODEV;
- }
- break;
- }
-
- if (!*header) {
- printk(KERN_WARNING PREFIX "%s not present\n",
- acpi_table_signatures[id]);
- return -ENODEV;
- }
-
- /* Map the DSDT header via the pointer in the FADT */
- if (id == ACPI_DSDT) {
- struct fadt_descriptor *fadt =
- (struct fadt_descriptor *)*header;
-
- if (fadt->revision == 3 && fadt->Xdsdt) {
- *header = (void *)__acpi_map_table(fadt->Xdsdt,
- sizeof(struct
- acpi_table_header));
- } else if (fadt->V1_dsdt) {
- *header = (void *)__acpi_map_table(fadt->V1_dsdt,
- sizeof(struct
- acpi_table_header));
- } else
- *header = NULL;
-
- if (!*header) {
- printk(KERN_WARNING PREFIX "Unable to map DSDT\n");
- return -ENODEV;
- }
- }
-
- return 0;
-}
int __init
-acpi_table_parse_madt_family(enum acpi_table_id id,
- unsigned long madt_size,
+acpi_table_parse_entries(char *id,
+ unsigned long table_size,
int entry_id,
- acpi_madt_entry_handler handler,
+ acpi_table_entry_handler handler,
unsigned int max_entries)
{
- void *madt = NULL;
- acpi_table_entry_header *entry;
+ struct acpi_table_header *table_header = NULL;
+ struct acpi_subtable_header *entry;
unsigned int count = 0;
- unsigned long madt_end;
- unsigned int i;
+ unsigned long table_end;
if (!handler)
return -EINVAL;
- /* Locate the MADT (if exists). There should only be one. */
-
- for (i = 0; i < sdt_count; i++) {
- if (sdt_entry[i].id != id)
- continue;
- madt = (void *)
- __acpi_map_table(sdt_entry[i].pa, sdt_entry[i].size);
- if (!madt) {
- printk(KERN_WARNING PREFIX "Unable to map %s\n",
- acpi_table_signatures[id]);
- return -ENODEV;
- }
- break;
- }
+ /* Locate the table (if exists). There should only be one. */
+ acpi_get_table(id, 0, &table_header);
- if (!madt) {
- printk(KERN_WARNING PREFIX "%s not present\n",
- acpi_table_signatures[id]);
+ if (!table_header) {
+ printk(KERN_WARNING PREFIX "%4.4s not present\n", id);
return -ENODEV;
}
- madt_end = (unsigned long)madt + sdt_entry[i].size;
+ table_end = (unsigned long)table_header + table_header->length;
/* Parse all entries looking for a match. */
- entry = (acpi_table_entry_header *)
- ((unsigned long)madt + madt_size);
+ entry = (struct acpi_subtable_header *)
+ ((unsigned long)table_header + table_size);
- while (((unsigned long)entry) + sizeof(acpi_table_entry_header) <
- madt_end) {
+ while (((unsigned long)entry) + sizeof(struct acpi_subtable_header) <
+ table_end) {
if (entry->type == entry_id
&& (!max_entries || count++ < max_entries))
- if (handler(entry, madt_end))
+ if (handler(entry, table_end))
return -EINVAL;
- entry = (acpi_table_entry_header *)
+ entry = (struct acpi_subtable_header *)
((unsigned long)entry + entry->length);
}
if (max_entries && count > max_entries) {
- printk(KERN_WARNING PREFIX "[%s:0x%02x] ignored %i entries of "
- "%i found\n", acpi_table_signatures[id], entry_id,
- count - max_entries, count);
+ printk(KERN_WARNING PREFIX "[%4.4s:0x%02x] ignored %i entries of "
+ "%i found\n", id, entry_id, count - max_entries, count);
}
return count;
}
int __init
-acpi_table_parse_madt(enum acpi_madt_entry_id id,
- acpi_madt_entry_handler handler, unsigned int max_entries)
+acpi_table_parse_madt(enum acpi_madt_type id,
+ acpi_table_entry_handler handler, unsigned int max_entries)
{
- return acpi_table_parse_madt_family(ACPI_APIC,
+ return acpi_table_parse_entries(ACPI_SIG_MADT,
sizeof(struct acpi_table_madt), id,
handler, max_entries);
}
-int __init acpi_table_parse(enum acpi_table_id id, acpi_table_handler handler)
+/**
+ * acpi_table_parse - find table with @id, run @handler on it
+ *
+ * @id: table id to find
+ * @handler: handler to run
+ *
+ * Scan the ACPI System Descriptor Table (STD) for a table matching @id,
+ * run @handler on it. Return 0 if table found, return on if not.
+ */
+int __init acpi_table_parse(char *id, acpi_table_handler handler)
{
- int count = 0;
- unsigned int i = 0;
-
+ struct acpi_table_header *table = NULL;
if (!handler)
return -EINVAL;
- for (i = 0; i < sdt_count; i++) {
- if (sdt_entry[i].id != id)
- continue;
- count++;
- if (count == 1)
- handler(sdt_entry[i].pa, sdt_entry[i].size);
-
- else
- printk(KERN_WARNING PREFIX
- "%d duplicate %s table ignored.\n", count,
- acpi_table_signatures[id]);
- }
-
- return count;
-}
-
-static int __init acpi_table_get_sdt(struct acpi_table_rsdp *rsdp)
-{
- struct acpi_table_header *header = NULL;
- unsigned int i, id = 0;
-
- if (!rsdp)
- return -EINVAL;
-
- /* First check XSDT (but only on ACPI 2.0-compatible systems) */
-
- if ((rsdp->revision >= 2) &&
- (((struct acpi20_table_rsdp *)rsdp)->xsdt_address)) {
-
- struct acpi_table_xsdt *mapped_xsdt = NULL;
-
- sdt_pa = ((struct acpi20_table_rsdp *)rsdp)->xsdt_address;
-
- /* map in just the header */
- header = (struct acpi_table_header *)
- __acpi_map_table(sdt_pa, sizeof(struct acpi_table_header));
-
- if (!header) {
- printk(KERN_WARNING PREFIX
- "Unable to map XSDT header\n");
- return -ENODEV;
- }
-
- /* remap in the entire table before processing */
- mapped_xsdt = (struct acpi_table_xsdt *)
- __acpi_map_table(sdt_pa, header->length);
- if (!mapped_xsdt) {
- printk(KERN_WARNING PREFIX "Unable to map XSDT\n");
- return -ENODEV;
- }
- header = &mapped_xsdt->header;
-
- if (strncmp(header->signature, "XSDT", 4)) {
- printk(KERN_WARNING PREFIX
- "XSDT signature incorrect\n");
- return -ENODEV;
- }
-
- if (acpi_table_compute_checksum(header, header->length)) {
- printk(KERN_WARNING PREFIX "Invalid XSDT checksum\n");
- return -ENODEV;
- }
-
- sdt_count =
- (header->length - sizeof(struct acpi_table_header)) >> 3;
- if (sdt_count > ACPI_MAX_TABLES) {
- printk(KERN_WARNING PREFIX
- "Truncated %lu XSDT entries\n",
- (sdt_count - ACPI_MAX_TABLES));
- sdt_count = ACPI_MAX_TABLES;
- }
-
- for (i = 0; i < sdt_count; i++)
- sdt_entry[i].pa = (unsigned long)mapped_xsdt->entry[i];
- }
-
- /* Then check RSDT */
-
- else if (rsdp->rsdt_address) {
-
- struct acpi_table_rsdt *mapped_rsdt = NULL;
-
- sdt_pa = rsdp->rsdt_address;
-
- /* map in just the header */
- header = (struct acpi_table_header *)
- __acpi_map_table(sdt_pa, sizeof(struct acpi_table_header));
- if (!header) {
- printk(KERN_WARNING PREFIX
- "Unable to map RSDT header\n");
- return -ENODEV;
- }
-
- /* remap in the entire table before processing */
- mapped_rsdt = (struct acpi_table_rsdt *)
- __acpi_map_table(sdt_pa, header->length);
- if (!mapped_rsdt) {
- printk(KERN_WARNING PREFIX "Unable to map RSDT\n");
- return -ENODEV;
- }
- header = &mapped_rsdt->header;
-
- if (strncmp(header->signature, "RSDT", 4)) {
- printk(KERN_WARNING PREFIX
- "RSDT signature incorrect\n");
- return -ENODEV;
- }
-
- if (acpi_table_compute_checksum(header, header->length)) {
- printk(KERN_WARNING PREFIX "Invalid RSDT checksum\n");
- return -ENODEV;
- }
-
- sdt_count =
- (header->length - sizeof(struct acpi_table_header)) >> 2;
- if (sdt_count > ACPI_MAX_TABLES) {
- printk(KERN_WARNING PREFIX
- "Truncated %lu RSDT entries\n",
- (sdt_count - ACPI_MAX_TABLES));
- sdt_count = ACPI_MAX_TABLES;
- }
-
- for (i = 0; i < sdt_count; i++)
- sdt_entry[i].pa = (unsigned long)mapped_rsdt->entry[i];
- }
-
- else {
- printk(KERN_WARNING PREFIX
- "No System Description Table (RSDT/XSDT) specified in RSDP\n");
- return -ENODEV;
- }
-
- acpi_table_print(header, sdt_pa);
-
- for (i = 0; i < sdt_count; i++) {
-
- /* map in just the header */
- header = (struct acpi_table_header *)
- __acpi_map_table(sdt_entry[i].pa,
- sizeof(struct acpi_table_header));
- if (!header)
- continue;
-
- /* remap in the entire table before processing */
- header = (struct acpi_table_header *)
- __acpi_map_table(sdt_entry[i].pa, header->length);
- if (!header)
- continue;
-
- acpi_table_print(header, sdt_entry[i].pa);
-
- if (acpi_table_compute_checksum(header, header->length)) {
- printk(KERN_WARNING " >>> ERROR: Invalid checksum\n");
- continue;
- }
-
- sdt_entry[i].size = header->length;
-
- for (id = 0; id < ACPI_TABLE_COUNT; id++) {
- if (!strncmp((char *)&header->signature,
- acpi_table_signatures[id],
- sizeof(header->signature))) {
- sdt_entry[i].id = id;
- }
- }
- }
-
- /*
- * The DSDT is *not* in the RSDT (why not? no idea.) but we want
- * to print its info, because this is what people usually blacklist
- * against. Unfortunately, we don't know the phys_addr, so just
- * print 0. Maybe no one will notice.
- */
- if (!acpi_get_table_header_early(ACPI_DSDT, &header))
- acpi_table_print(header, 0);
-
- return 0;
+ acpi_get_table(id, 0, &table);
+ if (table) {
+ handler(table);
+ return 0;
+ } else
+ return 1;
}
/*
@@ -568,54 +253,13 @@ static int __init acpi_table_get_sdt(struct acpi_table_rsdp *rsdp)
*
* find RSDP, find and checksum SDT/XSDT.
* checksum all tables, print SDT/XSDT
- *
+ *
* result: sdt_entry[] is initialized
*/
+
int __init acpi_table_init(void)
{
- struct acpi_table_rsdp *rsdp = NULL;
- unsigned long rsdp_phys = 0;
- int result = 0;
-
- /* Locate and map the Root System Description Table (RSDP) */
-
- rsdp_phys = acpi_find_rsdp();
- if (!rsdp_phys) {
- printk(KERN_ERR PREFIX "Unable to locate RSDP\n");
- return -ENODEV;
- }
-
- rsdp = (struct acpi_table_rsdp *)__acpi_map_table(rsdp_phys,
- sizeof(struct acpi_table_rsdp));
- if (!rsdp) {
- printk(KERN_WARNING PREFIX "Unable to map RSDP\n");
- return -ENODEV;
- }
-
- printk(KERN_DEBUG PREFIX
- "RSDP (v%3.3d %6.6s ) @ 0x%p\n",
- rsdp->revision, rsdp->oem_id, (void *)rsdp_phys);
-
- if (rsdp->revision < 2)
- result =
- acpi_table_compute_checksum(rsdp,
- sizeof(struct acpi_table_rsdp));
- else
- result =
- acpi_table_compute_checksum(rsdp,
- ((struct acpi20_table_rsdp *)
- rsdp)->length);
-
- if (result) {
- printk(KERN_WARNING " >>> ERROR: Invalid checksum\n");
- return -ENODEV;
- }
-
- /* Locate and map the System Description table (RSDT/XSDT) */
-
- if (acpi_table_get_sdt(rsdp))
- return -ENODEV;
-
+ acpi_initialize_tables(initial_tables, ACPI_MAX_TABLES, 0);
return 0;
}
diff --git a/drivers/acpi/tables/Makefile b/drivers/acpi/tables/Makefile
index aa4c69594d9..0a7d7afac25 100644
--- a/drivers/acpi/tables/Makefile
+++ b/drivers/acpi/tables/Makefile
@@ -2,7 +2,6 @@
# Makefile for all Linux ACPI interpreter subdirectories
#
-obj-y := tbconvrt.o tbget.o tbrsdt.o tbxface.o \
- tbgetall.o tbinstal.o tbutils.o tbxfroot.o
+obj-y := tbxface.o tbinstal.o tbutils.o tbfind.o tbfadt.o
EXTRA_CFLAGS += $(ACPI_CFLAGS)
diff --git a/drivers/acpi/tables/tbconvrt.c b/drivers/acpi/tables/tbconvrt.c
deleted file mode 100644
index d697fcb35d5..00000000000
--- a/drivers/acpi/tables/tbconvrt.c
+++ /dev/null
@@ -1,622 +0,0 @@
-/******************************************************************************
- *
- * Module Name: tbconvrt - ACPI Table conversion utilities
- *
- *****************************************************************************/
-
-/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions, and the following disclaimer,
- * without modification.
- * 2. Redistributions in binary form must reproduce at minimum a disclaimer
- * substantially similar to the "NO WARRANTY" disclaimer below
- * ("Disclaimer") and any redistribution must be conditioned upon
- * including a substantially similar Disclaimer requirement for further
- * binary redistribution.
- * 3. Neither the names of the above-listed copyright holders nor the names
- * of any contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * Alternatively, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2 as published by the Free
- * Software Foundation.
- *
- * NO WARRANTY
- * 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 MERCHANTIBILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
- */
-
-#include <acpi/acpi.h>
-#include <acpi/actables.h>
-
-#define _COMPONENT ACPI_TABLES
-ACPI_MODULE_NAME("tbconvrt")
-
-/* Local prototypes */
-static void
-acpi_tb_init_generic_address(struct acpi_generic_address *new_gas_struct,
- u8 register_bit_width,
- acpi_physical_address address);
-
-static void
-acpi_tb_convert_fadt1(struct fadt_descriptor *local_fadt,
- struct fadt_descriptor_rev1 *original_fadt);
-
-static void
-acpi_tb_convert_fadt2(struct fadt_descriptor *local_fadt,
- struct fadt_descriptor *original_fadt);
-
-u8 acpi_fadt_is_v1;
-ACPI_EXPORT_SYMBOL(acpi_fadt_is_v1)
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_get_table_count
- *
- * PARAMETERS: RSDP - Pointer to the RSDP
- * RSDT - Pointer to the RSDT/XSDT
- *
- * RETURN: The number of tables pointed to by the RSDT or XSDT.
- *
- * DESCRIPTION: Calculate the number of tables. Automatically handles either
- * an RSDT or XSDT.
- *
- ******************************************************************************/
-
-u32
-acpi_tb_get_table_count(struct rsdp_descriptor *RSDP,
- struct acpi_table_header *RSDT)
-{
- u32 pointer_size;
-
- ACPI_FUNCTION_ENTRY();
-
- /* RSDT pointers are 32 bits, XSDT pointers are 64 bits */
-
- if (acpi_gbl_root_table_type == ACPI_TABLE_TYPE_RSDT) {
- pointer_size = sizeof(u32);
- } else {
- pointer_size = sizeof(u64);
- }
-
- /*
- * Determine the number of tables pointed to by the RSDT/XSDT.
- * This is defined by the ACPI Specification to be the number of
- * pointers contained within the RSDT/XSDT. The size of the pointers
- * is architecture-dependent.
- */
- return ((RSDT->length -
- sizeof(struct acpi_table_header)) / pointer_size);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_convert_to_xsdt
- *
- * PARAMETERS: table_info - Info about the RSDT
- *
- * RETURN: Status
- *
- * DESCRIPTION: Convert an RSDT to an XSDT (internal common format)
- *
- ******************************************************************************/
-
-acpi_status acpi_tb_convert_to_xsdt(struct acpi_table_desc *table_info)
-{
- acpi_size table_size;
- u32 i;
- struct xsdt_descriptor *new_table;
-
- ACPI_FUNCTION_ENTRY();
-
- /* Compute size of the converted XSDT */
-
- table_size = ((acpi_size) acpi_gbl_rsdt_table_count * sizeof(u64)) +
- sizeof(struct acpi_table_header);
-
- /* Allocate an XSDT */
-
- new_table = ACPI_ALLOCATE_ZEROED(table_size);
- if (!new_table) {
- return (AE_NO_MEMORY);
- }
-
- /* Copy the header and set the length */
-
- ACPI_MEMCPY(new_table, table_info->pointer,
- sizeof(struct acpi_table_header));
- new_table->length = (u32) table_size;
-
- /* Copy the table pointers */
-
- for (i = 0; i < acpi_gbl_rsdt_table_count; i++) {
-
- /* RSDT pointers are 32 bits, XSDT pointers are 64 bits */
-
- if (acpi_gbl_root_table_type == ACPI_TABLE_TYPE_RSDT) {
- ACPI_STORE_ADDRESS(new_table->table_offset_entry[i],
- (ACPI_CAST_PTR
- (struct rsdt_descriptor,
- table_info->pointer))->
- table_offset_entry[i]);
- } else {
- new_table->table_offset_entry[i] =
- (ACPI_CAST_PTR(struct xsdt_descriptor,
- table_info->pointer))->
- table_offset_entry[i];
- }
- }
-
- /* Delete the original table (either mapped or in a buffer) */
-
- acpi_tb_delete_single_table(table_info);
-
- /* Point the table descriptor to the new table */
-
- table_info->pointer =
- ACPI_CAST_PTR(struct acpi_table_header, new_table);
- table_info->length = table_size;
- table_info->allocation = ACPI_MEM_ALLOCATED;
-
- return (AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_init_generic_address
- *
- * PARAMETERS: new_gas_struct - GAS struct to be initialized
- * register_bit_width - Width of this register
- * Address - Address of the register
- *
- * RETURN: None
- *
- * DESCRIPTION: Initialize a GAS structure.
- *
- ******************************************************************************/
-
-static void
-acpi_tb_init_generic_address(struct acpi_generic_address *new_gas_struct,
- u8 register_bit_width,
- acpi_physical_address address)
-{
-
- ACPI_STORE_ADDRESS(new_gas_struct->address, address);
-
- new_gas_struct->address_space_id = ACPI_ADR_SPACE_SYSTEM_IO;
- new_gas_struct->register_bit_width = register_bit_width;
- new_gas_struct->register_bit_offset = 0;
- new_gas_struct->access_width = 0;
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_convert_fadt1
- *
- * PARAMETERS: local_fadt - Pointer to new FADT
- * original_fadt - Pointer to old FADT
- *
- * RETURN: None, populates local_fadt
- *
- * DESCRIPTION: Convert an ACPI 1.0 FADT to common internal format
- *
- ******************************************************************************/
-
-static void
-acpi_tb_convert_fadt1(struct fadt_descriptor *local_fadt,
- struct fadt_descriptor_rev1 *original_fadt)
-{
-
- /* ACPI 1.0 FACS */
- /* The BIOS stored FADT should agree with Revision 1.0 */
- acpi_fadt_is_v1 = 1;
-
- /*
- * Copy the table header and the common part of the tables.
- *
- * The 2.0 table is an extension of the 1.0 table, so the entire 1.0
- * table can be copied first, then expand some fields to 64 bits.
- */
- ACPI_MEMCPY(local_fadt, original_fadt,
- sizeof(struct fadt_descriptor_rev1));
-
- /* Convert table pointers to 64-bit fields */
-
- ACPI_STORE_ADDRESS(local_fadt->xfirmware_ctrl,
- local_fadt->V1_firmware_ctrl);
- ACPI_STORE_ADDRESS(local_fadt->Xdsdt, local_fadt->V1_dsdt);
-
- /*
- * System Interrupt Model isn't used in ACPI 2.0
- * (local_fadt->Reserved1 = 0;)
- */
-
- /*
- * This field is set by the OEM to convey the preferred power management
- * profile to OSPM. It doesn't have any 1.0 equivalence. Since we don't
- * know what kind of 32-bit system this is, we will use "unspecified".
- */
- local_fadt->prefer_PM_profile = PM_UNSPECIFIED;
-
- /*
- * Processor Performance State Control. This is the value OSPM writes to
- * the SMI_CMD register to assume processor performance state control
- * responsibility. There isn't any equivalence in 1.0, but as many 1.x
- * ACPI tables contain _PCT and _PSS we also keep this value, unless
- * acpi_strict is set.
- */
- if (acpi_strict)
- local_fadt->pstate_cnt = 0;
-
- /*
- * Support for the _CST object and C States change notification.
- * This data item hasn't any 1.0 equivalence so leave it zero.
- */
- local_fadt->cst_cnt = 0;
-
- /*
- * FADT Rev 2 was an interim FADT released between ACPI 1.0 and ACPI 2.0.
- * It primarily adds the FADT reset mechanism.
- */
- if ((original_fadt->revision == 2) &&
- (original_fadt->length ==
- sizeof(struct fadt_descriptor_rev2_minus))) {
- /*
- * Grab the entire generic address struct, plus the 1-byte reset value
- * that immediately follows.
- */
- ACPI_MEMCPY(&local_fadt->reset_register,
- &(ACPI_CAST_PTR(struct fadt_descriptor_rev2_minus,
- original_fadt))->reset_register,
- sizeof(struct acpi_generic_address) + 1);
- } else {
- /*
- * Since there isn't any equivalence in 1.0 and since it is highly
- * likely that a 1.0 system has legacy support.
- */
- local_fadt->iapc_boot_arch = BAF_LEGACY_DEVICES;
- }
-
- /*
- * Convert the V1.0 block addresses to V2.0 GAS structures
- */
- acpi_tb_init_generic_address(&local_fadt->xpm1a_evt_blk,
- local_fadt->pm1_evt_len,
- (acpi_physical_address) local_fadt->
- V1_pm1a_evt_blk);
- acpi_tb_init_generic_address(&local_fadt->xpm1b_evt_blk,
- local_fadt->pm1_evt_len,
- (acpi_physical_address) local_fadt->
- V1_pm1b_evt_blk);
- acpi_tb_init_generic_address(&local_fadt->xpm1a_cnt_blk,
- local_fadt->pm1_cnt_len,
- (acpi_physical_address) local_fadt->
- V1_pm1a_cnt_blk);
- acpi_tb_init_generic_address(&local_fadt->xpm1b_cnt_blk,
- local_fadt->pm1_cnt_len,
- (acpi_physical_address) local_fadt->
- V1_pm1b_cnt_blk);
- acpi_tb_init_generic_address(&local_fadt->xpm2_cnt_blk,
- local_fadt->pm2_cnt_len,
- (acpi_physical_address) local_fadt->
- V1_pm2_cnt_blk);
- acpi_tb_init_generic_address(&local_fadt->xpm_tmr_blk,
- local_fadt->pm_tm_len,
- (acpi_physical_address) local_fadt->
- V1_pm_tmr_blk);
- acpi_tb_init_generic_address(&local_fadt->xgpe0_blk, 0,
- (acpi_physical_address) local_fadt->
- V1_gpe0_blk);
- acpi_tb_init_generic_address(&local_fadt->xgpe1_blk, 0,
- (acpi_physical_address) local_fadt->
- V1_gpe1_blk);
-
- /* Create separate GAS structs for the PM1 Enable registers */
-
- acpi_tb_init_generic_address(&acpi_gbl_xpm1a_enable,
- (u8) ACPI_DIV_2(acpi_gbl_FADT->
- pm1_evt_len),
- (acpi_physical_address)
- (local_fadt->xpm1a_evt_blk.address +
- ACPI_DIV_2(acpi_gbl_FADT->pm1_evt_len)));
-
- /* PM1B is optional; leave null if not present */
-
- if (local_fadt->xpm1b_evt_blk.address) {
- acpi_tb_init_generic_address(&acpi_gbl_xpm1b_enable,
- (u8) ACPI_DIV_2(acpi_gbl_FADT->
- pm1_evt_len),
- (acpi_physical_address)
- (local_fadt->xpm1b_evt_blk.
- address +
- ACPI_DIV_2(acpi_gbl_FADT->
- pm1_evt_len)));
- }
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_convert_fadt2
- *
- * PARAMETERS: local_fadt - Pointer to new FADT
- * original_fadt - Pointer to old FADT
- *
- * RETURN: None, populates local_fadt
- *
- * DESCRIPTION: Convert an ACPI 2.0 FADT to common internal format.
- * Handles optional "X" fields.
- *
- ******************************************************************************/
-
-static void
-acpi_tb_convert_fadt2(struct fadt_descriptor *local_fadt,
- struct fadt_descriptor *original_fadt)
-{
-
- /* We have an ACPI 2.0 FADT but we must copy it to our local buffer */
-
- ACPI_MEMCPY(local_fadt, original_fadt, sizeof(struct fadt_descriptor));
-
- /*
- * "X" fields are optional extensions to the original V1.0 fields, so
- * we must selectively expand V1.0 fields if the corresponding X field
- * is zero.
- */
- if (!(local_fadt->xfirmware_ctrl)) {
- ACPI_STORE_ADDRESS(local_fadt->xfirmware_ctrl,
- local_fadt->V1_firmware_ctrl);
- }
-
- if (!(local_fadt->Xdsdt)) {
- ACPI_STORE_ADDRESS(local_fadt->Xdsdt, local_fadt->V1_dsdt);
- }
-
- if (!(local_fadt->xpm1a_evt_blk.address)) {
- acpi_tb_init_generic_address(&local_fadt->xpm1a_evt_blk,
- local_fadt->pm1_evt_len,
- (acpi_physical_address)
- local_fadt->V1_pm1a_evt_blk);
- }
-
- if (!(local_fadt->xpm1b_evt_blk.address)) {
- acpi_tb_init_generic_address(&local_fadt->xpm1b_evt_blk,
- local_fadt->pm1_evt_len,
- (acpi_physical_address)
- local_fadt->V1_pm1b_evt_blk);
- }
-
- if (!(local_fadt->xpm1a_cnt_blk.address)) {
- acpi_tb_init_generic_address(&local_fadt->xpm1a_cnt_blk,
- local_fadt->pm1_cnt_len,
- (acpi_physical_address)
- local_fadt->V1_pm1a_cnt_blk);
- }
-
- if (!(local_fadt->xpm1b_cnt_blk.address)) {
- acpi_tb_init_generic_address(&local_fadt->xpm1b_cnt_blk,
- local_fadt->pm1_cnt_len,
- (acpi_physical_address)
- local_fadt->V1_pm1b_cnt_blk);
- }
-
- if (!(local_fadt->xpm2_cnt_blk.address)) {
- acpi_tb_init_generic_address(&local_fadt->xpm2_cnt_blk,
- local_fadt->pm2_cnt_len,
- (acpi_physical_address)
- local_fadt->V1_pm2_cnt_blk);
- }
-
- if (!(local_fadt->xpm_tmr_blk.address)) {
- acpi_tb_init_generic_address(&local_fadt->xpm_tmr_blk,
- local_fadt->pm_tm_len,
- (acpi_physical_address)
- local_fadt->V1_pm_tmr_blk);
- }
-
- if (!(local_fadt->xgpe0_blk.address)) {
- acpi_tb_init_generic_address(&local_fadt->xgpe0_blk,
- 0,
- (acpi_physical_address)
- local_fadt->V1_gpe0_blk);
- }
-
- if (!(local_fadt->xgpe1_blk.address)) {
- acpi_tb_init_generic_address(&local_fadt->xgpe1_blk,
- 0,
- (acpi_physical_address)
- local_fadt->V1_gpe1_blk);
- }
-
- /* Create separate GAS structs for the PM1 Enable registers */
-
- acpi_tb_init_generic_address(&acpi_gbl_xpm1a_enable,
- (u8) ACPI_DIV_2(acpi_gbl_FADT->
- pm1_evt_len),
- (acpi_physical_address)
- (local_fadt->xpm1a_evt_blk.address +
- ACPI_DIV_2(acpi_gbl_FADT->pm1_evt_len)));
-
- acpi_gbl_xpm1a_enable.address_space_id =
- local_fadt->xpm1a_evt_blk.address_space_id;
-
- /* PM1B is optional; leave null if not present */
-
- if (local_fadt->xpm1b_evt_blk.address) {
- acpi_tb_init_generic_address(&acpi_gbl_xpm1b_enable,
- (u8) ACPI_DIV_2(acpi_gbl_FADT->
- pm1_evt_len),
- (acpi_physical_address)
- (local_fadt->xpm1b_evt_blk.
- address +
- ACPI_DIV_2(acpi_gbl_FADT->
- pm1_evt_len)));
-
- acpi_gbl_xpm1b_enable.address_space_id =
- local_fadt->xpm1b_evt_blk.address_space_id;
- }
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_convert_table_fadt
- *
- * PARAMETERS: None
- *
- * RETURN: Status
- *
- * DESCRIPTION: Converts a BIOS supplied ACPI 1.0 FADT to a local
- * ACPI 2.0 FADT. If the BIOS supplied a 2.0 FADT then it is simply
- * copied to the local FADT. The ACPI CA software uses this
- * local FADT. Thus a significant amount of special #ifdef
- * type codeing is saved.
- *
- ******************************************************************************/
-
-acpi_status acpi_tb_convert_table_fadt(void)
-{
- struct fadt_descriptor *local_fadt;
- struct acpi_table_desc *table_desc;
-
- ACPI_FUNCTION_TRACE(tb_convert_table_fadt);
-
- /*
- * acpi_gbl_FADT is valid. Validate the FADT length. The table must be
- * at least as long as the version 1.0 FADT
- */
- if (acpi_gbl_FADT->length < sizeof(struct fadt_descriptor_rev1)) {
- ACPI_ERROR((AE_INFO, "FADT is invalid, too short: 0x%X",
- acpi_gbl_FADT->length));
- return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH);
- }
-
- /* Allocate buffer for the ACPI 2.0(+) FADT */
-
- local_fadt = ACPI_ALLOCATE_ZEROED(sizeof(struct fadt_descriptor));
- if (!local_fadt) {
- return_ACPI_STATUS(AE_NO_MEMORY);
- }
-
- if (acpi_gbl_FADT->revision >= FADT2_REVISION_ID) {
- if (acpi_gbl_FADT->length < sizeof(struct fadt_descriptor)) {
-
- /* Length is too short to be a V2.0 table */
-
- ACPI_WARNING((AE_INFO,
- "Inconsistent FADT length (0x%X) and revision (0x%X), using FADT V1.0 portion of table",
- acpi_gbl_FADT->length,
- acpi_gbl_FADT->revision));
-
- acpi_tb_convert_fadt1(local_fadt,
- (void *)acpi_gbl_FADT);
- } else {
- /* Valid V2.0 table */
-
- acpi_tb_convert_fadt2(local_fadt, acpi_gbl_FADT);
- }
- } else {
- /* Valid V1.0 table */
-
- acpi_tb_convert_fadt1(local_fadt, (void *)acpi_gbl_FADT);
- }
-
- /* Global FADT pointer will point to the new common V2.0 FADT */
-
- acpi_gbl_FADT = local_fadt;
- acpi_gbl_FADT->length = sizeof(struct fadt_descriptor);
-
- /* Free the original table */
-
- table_desc = acpi_gbl_table_lists[ACPI_TABLE_ID_FADT].next;
- acpi_tb_delete_single_table(table_desc);
-
- /* Install the new table */
-
- table_desc->pointer =
- ACPI_CAST_PTR(struct acpi_table_header, acpi_gbl_FADT);
- table_desc->allocation = ACPI_MEM_ALLOCATED;
- table_desc->length = sizeof(struct fadt_descriptor);
-
- /* Dump the entire FADT */
-
- ACPI_DEBUG_PRINT((ACPI_DB_TABLES,
- "Hex dump of common internal FADT, size %d (%X)\n",
- acpi_gbl_FADT->length, acpi_gbl_FADT->length));
-
- ACPI_DUMP_BUFFER(ACPI_CAST_PTR(u8, acpi_gbl_FADT),
- acpi_gbl_FADT->length);
-
- return_ACPI_STATUS(AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_build_common_facs
- *
- * PARAMETERS: table_info - Info for currently installed FACS
- *
- * RETURN: Status
- *
- * DESCRIPTION: Convert ACPI 1.0 and ACPI 2.0 FACS to a common internal
- * table format.
- *
- ******************************************************************************/
-
-acpi_status acpi_tb_build_common_facs(struct acpi_table_desc *table_info)
-{
-
- ACPI_FUNCTION_TRACE(tb_build_common_facs);
-
- /* Absolute minimum length is 24, but the ACPI spec says 64 */
-
- if (acpi_gbl_FACS->length < 24) {
- ACPI_ERROR((AE_INFO, "Invalid FACS table length: 0x%X",
- acpi_gbl_FACS->length));
- return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH);
- }
-
- if (acpi_gbl_FACS->length < 64) {
- ACPI_WARNING((AE_INFO,
- "FACS is shorter than the ACPI specification allows: 0x%X, using anyway",
- acpi_gbl_FACS->length));
- }
-
- /* Copy fields to the new FACS */
-
- acpi_gbl_common_fACS.global_lock = &(acpi_gbl_FACS->global_lock);
-
- if ((acpi_gbl_RSDP->revision < 2) ||
- (acpi_gbl_FACS->length < 32) ||
- (!(acpi_gbl_FACS->xfirmware_waking_vector))) {
-
- /* ACPI 1.0 FACS or short table or optional X_ field is zero */
-
- acpi_gbl_common_fACS.firmware_waking_vector = ACPI_CAST_PTR(u64,
- &
- (acpi_gbl_FACS->
- firmware_waking_vector));
- acpi_gbl_common_fACS.vector_width = 32;
- } else {
- /* ACPI 2.0 FACS with valid X_ field */
-
- acpi_gbl_common_fACS.firmware_waking_vector =
- &acpi_gbl_FACS->xfirmware_waking_vector;
- acpi_gbl_common_fACS.vector_width = 64;
- }
-
- return_ACPI_STATUS(AE_OK);
-}
diff --git a/drivers/acpi/tables/tbfadt.c b/drivers/acpi/tables/tbfadt.c
new file mode 100644
index 00000000000..807c7116e94
--- /dev/null
+++ b/drivers/acpi/tables/tbfadt.c
@@ -0,0 +1,434 @@
+/******************************************************************************
+ *
+ * Module Name: tbfadt - FADT table utilities
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2007, R. Byron Moore
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * 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 MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include <acpi/actables.h>
+
+#define _COMPONENT ACPI_TABLES
+ACPI_MODULE_NAME("tbfadt")
+
+/* Local prototypes */
+static void inline
+acpi_tb_init_generic_address(struct acpi_generic_address *generic_address,
+ u8 bit_width, u64 address);
+
+static void acpi_tb_convert_fadt(void);
+
+static void acpi_tb_validate_fadt(void);
+
+/* Table for conversion of FADT to common internal format and FADT validation */
+
+typedef struct acpi_fadt_info {
+ char *name;
+ u8 target;
+ u8 source;
+ u8 length;
+ u8 type;
+
+} acpi_fadt_info;
+
+#define ACPI_FADT_REQUIRED 1
+#define ACPI_FADT_SEPARATE_LENGTH 2
+
+static struct acpi_fadt_info fadt_info_table[] = {
+ {"Pm1aEventBlock", ACPI_FADT_OFFSET(xpm1a_event_block),
+ ACPI_FADT_OFFSET(pm1a_event_block),
+ ACPI_FADT_OFFSET(pm1_event_length), ACPI_FADT_REQUIRED},
+
+ {"Pm1bEventBlock", ACPI_FADT_OFFSET(xpm1b_event_block),
+ ACPI_FADT_OFFSET(pm1b_event_block),
+ ACPI_FADT_OFFSET(pm1_event_length), 0},
+
+ {"Pm1aControlBlock", ACPI_FADT_OFFSET(xpm1a_control_block),
+ ACPI_FADT_OFFSET(pm1a_control_block),
+ ACPI_FADT_OFFSET(pm1_control_length), ACPI_FADT_REQUIRED},
+
+ {"Pm1bControlBlock", ACPI_FADT_OFFSET(xpm1b_control_block),
+ ACPI_FADT_OFFSET(pm1b_control_block),
+ ACPI_FADT_OFFSET(pm1_control_length), 0},
+
+ {"Pm2ControlBlock", ACPI_FADT_OFFSET(xpm2_control_block),
+ ACPI_FADT_OFFSET(pm2_control_block),
+ ACPI_FADT_OFFSET(pm2_control_length), ACPI_FADT_SEPARATE_LENGTH},
+
+ {"PmTimerBlock", ACPI_FADT_OFFSET(xpm_timer_block),
+ ACPI_FADT_OFFSET(pm_timer_block),
+ ACPI_FADT_OFFSET(pm_timer_length), ACPI_FADT_REQUIRED},
+
+ {"Gpe0Block", ACPI_FADT_OFFSET(xgpe0_block),
+ ACPI_FADT_OFFSET(gpe0_block),
+ ACPI_FADT_OFFSET(gpe0_block_length), ACPI_FADT_SEPARATE_LENGTH},
+
+ {"Gpe1Block", ACPI_FADT_OFFSET(xgpe1_block),
+ ACPI_FADT_OFFSET(gpe1_block),
+ ACPI_FADT_OFFSET(gpe1_block_length), ACPI_FADT_SEPARATE_LENGTH}
+};
+
+#define ACPI_FADT_INFO_ENTRIES (sizeof (fadt_info_table) / sizeof (struct acpi_fadt_info))
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_init_generic_address
+ *
+ * PARAMETERS: generic_address - GAS struct to be initialized
+ * bit_width - Width of this register
+ * Address - Address of the register
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Initialize a Generic Address Structure (GAS)
+ * See the ACPI specification for a full description and
+ * definition of this structure.
+ *
+ ******************************************************************************/
+
+static void inline
+acpi_tb_init_generic_address(struct acpi_generic_address *generic_address,
+ u8 bit_width, u64 address)
+{
+
+ /*
+ * The 64-bit Address field is non-aligned in the byte packed
+ * GAS struct.
+ */
+ ACPI_MOVE_64_TO_64(&generic_address->address, &address);
+
+ /* All other fields are byte-wide */
+
+ generic_address->space_id = ACPI_ADR_SPACE_SYSTEM_IO;
+ generic_address->bit_width = bit_width;
+ generic_address->bit_offset = 0;
+ generic_address->access_width = 0;
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_parse_fadt
+ *
+ * PARAMETERS: table_index - Index for the FADT
+ * Flags - Flags
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Initialize the FADT, DSDT and FACS tables
+ * (FADT contains the addresses of the DSDT and FACS)
+ *
+ ******************************************************************************/
+
+void acpi_tb_parse_fadt(acpi_native_uint table_index, u8 flags)
+{
+ u32 length;
+ struct acpi_table_header *table;
+
+ /*
+ * The FADT has multiple versions with different lengths,
+ * and it contains pointers to both the DSDT and FACS tables.
+ *
+ * Get a local copy of the FADT and convert it to a common format
+ * Map entire FADT, assumed to be smaller than one page.
+ */
+ length = acpi_gbl_root_table_list.tables[table_index].length;
+
+ table =
+ acpi_os_map_memory(acpi_gbl_root_table_list.tables[table_index].
+ address, length);
+ if (!table) {
+ return;
+ }
+
+ /*
+ * Validate the FADT checksum before we copy the table. Ignore
+ * checksum error as we want to try to get the DSDT and FACS.
+ */
+ (void)acpi_tb_verify_checksum(table, length);
+
+ /* Obtain a local copy of the FADT in common ACPI 2.0+ format */
+
+ acpi_tb_create_local_fadt(table, length);
+
+ /* All done with the real FADT, unmap it */
+
+ acpi_os_unmap_memory(table, length);
+
+ /* Obtain the DSDT and FACS tables via their addresses within the FADT */
+
+ acpi_tb_install_table((acpi_physical_address) acpi_gbl_FADT.Xdsdt,
+ flags, ACPI_SIG_DSDT, ACPI_TABLE_INDEX_DSDT);
+
+ acpi_tb_install_table((acpi_physical_address) acpi_gbl_FADT.Xfacs,
+ flags, ACPI_SIG_FACS, ACPI_TABLE_INDEX_FACS);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_create_local_fadt
+ *
+ * PARAMETERS: Table - Pointer to BIOS FADT
+ * Length - Length of the table
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Get a local copy of the FADT and convert it to a common format.
+ * Performs validation on some important FADT fields.
+ *
+ ******************************************************************************/
+
+void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length)
+{
+
+ /*
+ * Check if the FADT is larger than what we know about (ACPI 2.0 version).
+ * Truncate the table, but make some noise.
+ */
+ if (length > sizeof(struct acpi_table_fadt)) {
+ ACPI_WARNING((AE_INFO,
+ "FADT (revision %u) is longer than ACPI 2.0 version, truncating length 0x%X to 0x%zX",
+ table->revision, (unsigned)length,
+ sizeof(struct acpi_table_fadt)));
+ }
+
+ /* Copy the entire FADT locally. Zero first for tb_convert_fadt */
+
+ ACPI_MEMSET(&acpi_gbl_FADT, 0, sizeof(struct acpi_table_fadt));
+
+ ACPI_MEMCPY(&acpi_gbl_FADT, table,
+ ACPI_MIN(length, sizeof(struct acpi_table_fadt)));
+
+ /*
+ * 1) Convert the local copy of the FADT to the common internal format
+ * 2) Validate some of the important values within the FADT
+ */
+ acpi_tb_convert_fadt();
+ acpi_tb_validate_fadt();
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_convert_fadt
+ *
+ * PARAMETERS: None, uses acpi_gbl_FADT
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Converts all versions of the FADT to a common internal format.
+ * -> Expand all 32-bit addresses to 64-bit.
+ *
+ * NOTE: acpi_gbl_FADT must be of size (struct acpi_table_fadt),
+ * and must contain a copy of the actual FADT.
+ *
+ * ACPICA will use the "X" fields of the FADT for all addresses.
+ *
+ * "X" fields are optional extensions to the original V1.0 fields. Even if
+ * they are present in the structure, they can be optionally not used by
+ * setting them to zero. Therefore, we must selectively expand V1.0 fields
+ * if the corresponding X field is zero.
+ *
+ * For ACPI 1.0 FADTs, all address fields are expanded to the corresponding
+ * "X" fields.
+ *
+ * For ACPI 2.0 FADTs, any "X" fields that are NULL are filled in by
+ * expanding the corresponding ACPI 1.0 field.
+ *
+ ******************************************************************************/
+
+static void acpi_tb_convert_fadt(void)
+{
+ u8 pm1_register_length;
+ struct acpi_generic_address *target;
+ acpi_native_uint i;
+
+ /* Update the local FADT table header length */
+
+ acpi_gbl_FADT.header.length = sizeof(struct acpi_table_fadt);
+
+ /* Expand the 32-bit FACS and DSDT addresses to 64-bit as necessary */
+
+ if (!acpi_gbl_FADT.Xfacs) {
+ acpi_gbl_FADT.Xfacs = (u64) acpi_gbl_FADT.facs;
+ }
+
+ if (!acpi_gbl_FADT.Xdsdt) {
+ acpi_gbl_FADT.Xdsdt = (u64) acpi_gbl_FADT.dsdt;
+ }
+
+ /*
+ * Expand the 32-bit V1.0 addresses to the 64-bit "X" generic address
+ * structures as necessary.
+ */
+ for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) {
+ target =
+ ACPI_ADD_PTR(struct acpi_generic_address, &acpi_gbl_FADT,
+ fadt_info_table[i].target);
+
+ /* Expand only if the X target is null */
+
+ if (!target->address) {
+ acpi_tb_init_generic_address(target,
+ *ACPI_ADD_PTR(u8,
+ &acpi_gbl_FADT,
+ fadt_info_table
+ [i].length),
+ (u64) * ACPI_ADD_PTR(u32,
+ &acpi_gbl_FADT,
+ fadt_info_table
+ [i].
+ source));
+ }
+ }
+
+ /*
+ * Calculate separate GAS structs for the PM1 Enable registers.
+ * These addresses do not appear (directly) in the FADT, so it is
+ * useful to calculate them once, here.
+ *
+ * The PM event blocks are split into two register blocks, first is the
+ * PM Status Register block, followed immediately by the PM Enable Register
+ * block. Each is of length (pm1_event_length/2)
+ */
+ pm1_register_length = (u8) ACPI_DIV_2(acpi_gbl_FADT.pm1_event_length);
+
+ /* The PM1A register block is required */
+
+ acpi_tb_init_generic_address(&acpi_gbl_xpm1a_enable,
+ pm1_register_length,
+ (acpi_gbl_FADT.xpm1a_event_block.address +
+ pm1_register_length));
+ /* Don't forget to copy space_id of the GAS */
+ acpi_gbl_xpm1a_enable.space_id = acpi_gbl_FADT.xpm1a_event_block.space_id;
+
+ /* The PM1B register block is optional, ignore if not present */
+
+ if (acpi_gbl_FADT.xpm1b_event_block.address) {
+ acpi_tb_init_generic_address(&acpi_gbl_xpm1b_enable,
+ pm1_register_length,
+ (acpi_gbl_FADT.xpm1b_event_block.
+ address + pm1_register_length));
+ /* Don't forget to copy space_id of the GAS */
+ acpi_gbl_xpm1b_enable.space_id = acpi_gbl_FADT.xpm1a_event_block.space_id;
+
+ }
+}
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_tb_validate_fadt
+ *
+ * PARAMETERS: Table - Pointer to the FADT to be validated
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Validate various important fields within the FADT. If a problem
+ * is found, issue a message, but no status is returned.
+ * Used by both the table manager and the disassembler.
+ *
+ * Possible additional checks:
+ * (acpi_gbl_FADT.pm1_event_length >= 4)
+ * (acpi_gbl_FADT.pm1_control_length >= 2)
+ * (acpi_gbl_FADT.pm_timer_length >= 4)
+ * Gpe block lengths must be multiple of 2
+ *
+ ******************************************************************************/
+
+static void acpi_tb_validate_fadt(void)
+{
+ u32 *address32;
+ struct acpi_generic_address *address64;
+ u8 length;
+ acpi_native_uint i;
+
+ /* Examine all of the 64-bit extended address fields (X fields) */
+
+ for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) {
+
+ /* Generate pointers to the 32-bit and 64-bit addresses and get the length */
+
+ address64 =
+ ACPI_ADD_PTR(struct acpi_generic_address, &acpi_gbl_FADT,
+ fadt_info_table[i].target);
+ address32 =
+ ACPI_ADD_PTR(u32, &acpi_gbl_FADT,
+ fadt_info_table[i].source);
+ length =
+ *ACPI_ADD_PTR(u8, &acpi_gbl_FADT,
+ fadt_info_table[i].length);
+
+ if (fadt_info_table[i].type & ACPI_FADT_REQUIRED) {
+ /*
+ * Field is required (Pm1a_event, Pm1a_control, pm_timer).
+ * Both the address and length must be non-zero.
+ */
+ if (!address64->address || !length) {
+ ACPI_ERROR((AE_INFO,
+ "Required field \"%s\" has zero address and/or length: %8.8X%8.8X/%X",
+ fadt_info_table[i].name,
+ ACPI_FORMAT_UINT64(address64->
+ address),
+ length));
+ }
+ } else if (fadt_info_table[i].type & ACPI_FADT_SEPARATE_LENGTH) {
+ /*
+ * Field is optional (PM2Control, GPE0, GPE1) AND has its own
+ * length field. If present, both the address and length must be valid.
+ */
+ if ((address64->address && !length)
+ || (!address64->address && length)) {
+ ACPI_WARNING((AE_INFO,
+ "Optional field \"%s\" has zero address or length: %8.8X%8.8X/%X",
+ fadt_info_table[i].name,
+ ACPI_FORMAT_UINT64(address64->
+ address),
+ length));
+ }
+ }
+
+ /* If both 32- and 64-bit addresses are valid (non-zero), they must match */
+
+ if (address64->address && *address32 &&
+ (address64->address != (u64) * address32)) {
+ ACPI_ERROR((AE_INFO,
+ "32/64X address mismatch in \"%s\": [%8.8X] [%8.8X%8.8X], using 64X",
+ fadt_info_table[i].name, *address32,
+ ACPI_FORMAT_UINT64(address64->address)));
+ }
+ }
+}
diff --git a/drivers/acpi/tables/tbfind.c b/drivers/acpi/tables/tbfind.c
new file mode 100644
index 00000000000..058c064948e
--- /dev/null
+++ b/drivers/acpi/tables/tbfind.c
@@ -0,0 +1,126 @@
+/******************************************************************************
+ *
+ * Module Name: tbfind - find table
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2007, R. Byron Moore
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * 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 MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include <acpi/actables.h>
+
+#define _COMPONENT ACPI_TABLES
+ACPI_MODULE_NAME("tbfind")
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_find_table
+ *
+ * PARAMETERS: Signature - String with ACPI table signature
+ * oem_id - String with the table OEM ID
+ * oem_table_id - String with the OEM Table ID
+ * table_index - Where the table index is returned
+ *
+ * RETURN: Status and table index
+ *
+ * DESCRIPTION: Find an ACPI table (in the RSDT/XSDT) that matches the
+ * Signature, OEM ID and OEM Table ID. Returns an index that can
+ * be used to get the table header or entire table.
+ *
+ ******************************************************************************/
+acpi_status
+acpi_tb_find_table(char *signature,
+ char *oem_id,
+ char *oem_table_id, acpi_native_uint * table_index)
+{
+ acpi_native_uint i;
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE(tb_find_table);
+
+ for (i = 0; i < acpi_gbl_root_table_list.count; ++i) {
+ if (ACPI_MEMCMP(&(acpi_gbl_root_table_list.tables[i].signature),
+ signature, ACPI_NAME_SIZE)) {
+
+ /* Not the requested table */
+
+ continue;
+ }
+
+ /* Table with matching signature has been found */
+
+ if (!acpi_gbl_root_table_list.tables[i].pointer) {
+
+ /* Table is not currently mapped, map it */
+
+ status =
+ acpi_tb_verify_table(&acpi_gbl_root_table_list.
+ tables[i]);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ if (!acpi_gbl_root_table_list.tables[i].pointer) {
+ continue;
+ }
+ }
+
+ /* Check for table match on all IDs */
+
+ if (!ACPI_MEMCMP
+ (acpi_gbl_root_table_list.tables[i].pointer->signature,
+ signature, ACPI_NAME_SIZE) && (!oem_id[0]
+ ||
+ !ACPI_MEMCMP
+ (acpi_gbl_root_table_list.
+ tables[i].pointer->oem_id,
+ oem_id, ACPI_OEM_ID_SIZE))
+ && (!oem_table_id[0]
+ || !ACPI_MEMCMP(acpi_gbl_root_table_list.tables[i].
+ pointer->oem_table_id, oem_table_id,
+ ACPI_OEM_TABLE_ID_SIZE))) {
+ *table_index = i;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_TABLES,
+ "Found table [%4.4s]\n", signature));
+ return_ACPI_STATUS(AE_OK);
+ }
+ }
+
+ return_ACPI_STATUS(AE_NOT_FOUND);
+}
diff --git a/drivers/acpi/tables/tbget.c b/drivers/acpi/tables/tbget.c
deleted file mode 100644
index 11e2d4454e0..00000000000
--- a/drivers/acpi/tables/tbget.c
+++ /dev/null
@@ -1,471 +0,0 @@
-/******************************************************************************
- *
- * Module Name: tbget - ACPI Table get* routines
- *
- *****************************************************************************/
-
-/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions, and the following disclaimer,
- * without modification.
- * 2. Redistributions in binary form must reproduce at minimum a disclaimer
- * substantially similar to the "NO WARRANTY" disclaimer below
- * ("Disclaimer") and any redistribution must be conditioned upon
- * including a substantially similar Disclaimer requirement for further
- * binary redistribution.
- * 3. Neither the names of the above-listed copyright holders nor the names
- * of any contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * Alternatively, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2 as published by the Free
- * Software Foundation.
- *
- * NO WARRANTY
- * 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 MERCHANTIBILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
- */
-
-#include <acpi/acpi.h>
-#include <acpi/actables.h>
-
-#define _COMPONENT ACPI_TABLES
-ACPI_MODULE_NAME("tbget")
-
-/* Local prototypes */
-static acpi_status
-acpi_tb_get_this_table(struct acpi_pointer *address,
- struct acpi_table_header *header,
- struct acpi_table_desc *table_info);
-
-static acpi_status
-acpi_tb_table_override(struct acpi_table_header *header,
- struct acpi_table_desc *table_info);
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_get_table
- *
- * PARAMETERS: Address - Address of table to retrieve. Can be
- * Logical or Physical
- * table_info - Where table info is returned
- *
- * RETURN: None
- *
- * DESCRIPTION: Get entire table of unknown size.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_tb_get_table(struct acpi_pointer *address,
- struct acpi_table_desc *table_info)
-{
- acpi_status status;
- struct acpi_table_header header;
-
- ACPI_FUNCTION_TRACE(tb_get_table);
-
- /* Get the header in order to get signature and table size */
-
- status = acpi_tb_get_table_header(address, &header);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- /* Get the entire table */
-
- status = acpi_tb_get_table_body(address, &header, table_info);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status,
- "Could not get ACPI table (size %X)",
- header.length));
- return_ACPI_STATUS(status);
- }
-
- return_ACPI_STATUS(AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_get_table_header
- *
- * PARAMETERS: Address - Address of table to retrieve. Can be
- * Logical or Physical
- * return_header - Where the table header is returned
- *
- * RETURN: Status
- *
- * DESCRIPTION: Get an ACPI table header. Works in both physical or virtual
- * addressing mode. Works with both physical or logical pointers.
- * Table is either copied or mapped, depending on the pointer
- * type and mode of the processor.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_tb_get_table_header(struct acpi_pointer *address,
- struct acpi_table_header *return_header)
-{
- acpi_status status = AE_OK;
- struct acpi_table_header *header = NULL;
-
- ACPI_FUNCTION_TRACE(tb_get_table_header);
-
- /*
- * Flags contains the current processor mode (Virtual or Physical
- * addressing) The pointer_type is either Logical or Physical
- */
- switch (address->pointer_type) {
- case ACPI_PHYSMODE_PHYSPTR:
- case ACPI_LOGMODE_LOGPTR:
-
- /* Pointer matches processor mode, copy the header */
-
- ACPI_MEMCPY(return_header, address->pointer.logical,
- sizeof(struct acpi_table_header));
- break;
-
- case ACPI_LOGMODE_PHYSPTR:
-
- /* Create a logical address for the physical pointer */
-
- status = acpi_os_map_memory(address->pointer.physical,
- sizeof(struct acpi_table_header),
- (void *)&header);
- if (ACPI_FAILURE(status)) {
- ACPI_ERROR((AE_INFO,
- "Could not map memory at %8.8X%8.8X for table header",
- ACPI_FORMAT_UINT64(address->pointer.
- physical)));
- return_ACPI_STATUS(status);
- }
-
- /* Copy header and delete mapping */
-
- ACPI_MEMCPY(return_header, header,
- sizeof(struct acpi_table_header));
- acpi_os_unmap_memory(header, sizeof(struct acpi_table_header));
- break;
-
- default:
-
- ACPI_ERROR((AE_INFO, "Invalid address flags %X",
- address->pointer_type));
- return_ACPI_STATUS(AE_BAD_PARAMETER);
- }
-
- ACPI_DEBUG_PRINT((ACPI_DB_TABLES, "Table Signature: [%4.4s]\n",
- return_header->signature));
-
- return_ACPI_STATUS(AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_get_table_body
- *
- * PARAMETERS: Address - Address of table to retrieve. Can be
- * Logical or Physical
- * Header - Header of the table to retrieve
- * table_info - Where the table info is returned
- *
- * RETURN: Status
- *
- * DESCRIPTION: Get an entire ACPI table with support to allow the host OS to
- * replace the table with a newer version (table override.)
- * Works in both physical or virtual
- * addressing mode. Works with both physical or logical pointers.
- * Table is either copied or mapped, depending on the pointer
- * type and mode of the processor.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_tb_get_table_body(struct acpi_pointer *address,
- struct acpi_table_header *header,
- struct acpi_table_desc *table_info)
-{
- acpi_status status;
-
- ACPI_FUNCTION_TRACE(tb_get_table_body);
-
- if (!table_info || !address) {
- return_ACPI_STATUS(AE_BAD_PARAMETER);
- }
-
- /* Attempt table override. */
-
- status = acpi_tb_table_override(header, table_info);
- if (ACPI_SUCCESS(status)) {
-
- /* Table was overridden by the host OS */
-
- return_ACPI_STATUS(status);
- }
-
- /* No override, get the original table */
-
- status = acpi_tb_get_this_table(address, header, table_info);
- return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_table_override
- *
- * PARAMETERS: Header - Pointer to table header
- * table_info - Return info if table is overridden
- *
- * RETURN: None
- *
- * DESCRIPTION: Attempts override of current table with a new one if provided
- * by the host OS.
- *
- ******************************************************************************/
-
-static acpi_status
-acpi_tb_table_override(struct acpi_table_header *header,
- struct acpi_table_desc *table_info)
-{
- struct acpi_table_header *new_table;
- acpi_status status;
- struct acpi_pointer address;
-
- ACPI_FUNCTION_TRACE(tb_table_override);
-
- /*
- * The OSL will examine the header and decide whether to override this
- * table. If it decides to override, a table will be returned in new_table,
- * which we will then copy.
- */
- status = acpi_os_table_override(header, &new_table);
- if (ACPI_FAILURE(status)) {
-
- /* Some severe error from the OSL, but we basically ignore it */
-
- ACPI_EXCEPTION((AE_INFO, status,
- "Could not override ACPI table"));
- return_ACPI_STATUS(status);
- }
-
- if (!new_table) {
-
- /* No table override */
-
- return_ACPI_STATUS(AE_NO_ACPI_TABLES);
- }
-
- /*
- * We have a new table to override the old one. Get a copy of
- * the new one. We know that the new table has a logical pointer.
- */
- address.pointer_type = ACPI_LOGICAL_POINTER | ACPI_LOGICAL_ADDRESSING;
- address.pointer.logical = new_table;
-
- status = acpi_tb_get_this_table(&address, new_table, table_info);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status, "Could not copy ACPI table"));
- return_ACPI_STATUS(status);
- }
-
- /* Copy the table info */
-
- ACPI_INFO((AE_INFO, "Table [%4.4s] replaced by host OS",
- table_info->pointer->signature));
-
- return_ACPI_STATUS(AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_get_this_table
- *
- * PARAMETERS: Address - Address of table to retrieve. Can be
- * Logical or Physical
- * Header - Header of the table to retrieve
- * table_info - Where the table info is returned
- *
- * RETURN: Status
- *
- * DESCRIPTION: Get an entire ACPI table. Works in both physical or virtual
- * addressing mode. Works with both physical or logical pointers.
- * Table is either copied or mapped, depending on the pointer
- * type and mode of the processor.
- *
- ******************************************************************************/
-
-static acpi_status
-acpi_tb_get_this_table(struct acpi_pointer *address,
- struct acpi_table_header *header,
- struct acpi_table_desc *table_info)
-{
- struct acpi_table_header *full_table = NULL;
- u8 allocation;
- acpi_status status = AE_OK;
-
- ACPI_FUNCTION_TRACE(tb_get_this_table);
-
- /* Validate minimum length */
-
- if (header->length < sizeof(struct acpi_table_header)) {
- ACPI_ERROR((AE_INFO,
- "Table length (%X) is smaller than minimum (%zX)",
- header->length, sizeof(struct acpi_table_header)));
-
- return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH);
- }
-
- /*
- * Flags contains the current processor mode (Virtual or Physical
- * addressing) The pointer_type is either Logical or Physical
- */
- switch (address->pointer_type) {
- case ACPI_PHYSMODE_PHYSPTR:
- case ACPI_LOGMODE_LOGPTR:
-
- /* Pointer matches processor mode, copy the table to a new buffer */
-
- full_table = ACPI_ALLOCATE(header->length);
- if (!full_table) {
- ACPI_ERROR((AE_INFO,
- "Could not allocate table memory for [%4.4s] length %X",
- header->signature, header->length));
- return_ACPI_STATUS(AE_NO_MEMORY);
- }
-
- /* Copy the entire table (including header) to the local buffer */
-
- ACPI_MEMCPY(full_table, address->pointer.logical,
- header->length);
-
- /* Save allocation type */
-
- allocation = ACPI_MEM_ALLOCATED;
- break;
-
- case ACPI_LOGMODE_PHYSPTR:
-
- /*
- * Just map the table's physical memory
- * into our address space.
- */
- status = acpi_os_map_memory(address->pointer.physical,
- (acpi_size) header->length,
- ACPI_CAST_PTR(void, &full_table));
- if (ACPI_FAILURE(status)) {
- ACPI_ERROR((AE_INFO,
- "Could not map memory for table [%4.4s] at %8.8X%8.8X for length %X",
- header->signature,
- ACPI_FORMAT_UINT64(address->pointer.
- physical),
- header->length));
- return (status);
- }
-
- /* Save allocation type */
-
- allocation = ACPI_MEM_MAPPED;
- break;
-
- default:
-
- ACPI_ERROR((AE_INFO, "Invalid address flags %X",
- address->pointer_type));
- return_ACPI_STATUS(AE_BAD_PARAMETER);
- }
-
- /*
- * Validate checksum for _most_ tables,
- * even the ones whose signature we don't recognize
- */
- if (table_info->type != ACPI_TABLE_ID_FACS) {
- status = acpi_tb_verify_table_checksum(full_table);
-
-#if (!ACPI_CHECKSUM_ABORT)
- if (ACPI_FAILURE(status)) {
-
- /* Ignore the error if configuration says so */
-
- status = AE_OK;
- }
-#endif
- }
-
- /* Return values */
-
- table_info->pointer = full_table;
- table_info->length = (acpi_size) header->length;
- table_info->allocation = allocation;
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Found table [%4.4s] at %8.8X%8.8X, mapped/copied to %p\n",
- full_table->signature,
- ACPI_FORMAT_UINT64(address->pointer.physical),
- full_table));
-
- return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_get_table_ptr
- *
- * PARAMETERS: table_type - one of the defined table types
- * Instance - Which table of this type
- * return_table - pointer to location to place the pointer for
- * return
- *
- * RETURN: Status
- *
- * DESCRIPTION: This function is called to get the pointer to an ACPI table.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_tb_get_table_ptr(acpi_table_type table_type,
- u32 instance, struct acpi_table_header **return_table)
-{
- struct acpi_table_desc *table_desc;
- u32 i;
-
- ACPI_FUNCTION_TRACE(tb_get_table_ptr);
-
- if (table_type > ACPI_TABLE_ID_MAX) {
- return_ACPI_STATUS(AE_BAD_PARAMETER);
- }
-
- /* Check for instance out of range of the current table count */
-
- if (instance > acpi_gbl_table_lists[table_type].count) {
- return_ACPI_STATUS(AE_NOT_EXIST);
- }
-
- /*
- * Walk the list to get the desired table
- * Note: Instance is one-based
- */
- table_desc = acpi_gbl_table_lists[table_type].next;
- for (i = 1; i < instance; i++) {
- table_desc = table_desc->next;
- }
-
- /* We are now pointing to the requested table's descriptor */
-
- *return_table = table_desc->pointer;
- return_ACPI_STATUS(AE_OK);
-}
diff --git a/drivers/acpi/tables/tbgetall.c b/drivers/acpi/tables/tbgetall.c
deleted file mode 100644
index ad982112e4c..00000000000
--- a/drivers/acpi/tables/tbgetall.c
+++ /dev/null
@@ -1,311 +0,0 @@
-/******************************************************************************
- *
- * Module Name: tbgetall - Get all required ACPI tables
- *
- *****************************************************************************/
-
-/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions, and the following disclaimer,
- * without modification.
- * 2. Redistributions in binary form must reproduce at minimum a disclaimer
- * substantially similar to the "NO WARRANTY" disclaimer below
- * ("Disclaimer") and any redistribution must be conditioned upon
- * including a substantially similar Disclaimer requirement for further
- * binary redistribution.
- * 3. Neither the names of the above-listed copyright holders nor the names
- * of any contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * Alternatively, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2 as published by the Free
- * Software Foundation.
- *
- * NO WARRANTY
- * 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 MERCHANTIBILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
- */
-
-#include <acpi/acpi.h>
-#include <acpi/actables.h>
-
-#define _COMPONENT ACPI_TABLES
-ACPI_MODULE_NAME("tbgetall")
-
-/* Local prototypes */
-static acpi_status
-acpi_tb_get_primary_table(struct acpi_pointer *address,
- struct acpi_table_desc *table_info);
-
-static acpi_status
-acpi_tb_get_secondary_table(struct acpi_pointer *address,
- acpi_string signature,
- struct acpi_table_desc *table_info);
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_get_primary_table
- *
- * PARAMETERS: Address - Physical address of table to retrieve
- * *table_info - Where the table info is returned
- *
- * RETURN: Status
- *
- * DESCRIPTION: Maps the physical address of table into a logical address
- *
- ******************************************************************************/
-
-static acpi_status
-acpi_tb_get_primary_table(struct acpi_pointer *address,
- struct acpi_table_desc *table_info)
-{
- acpi_status status;
- struct acpi_table_header header;
-
- ACPI_FUNCTION_TRACE(tb_get_primary_table);
-
- /* Ignore a NULL address in the RSDT */
-
- if (!address->pointer.value) {
- return_ACPI_STATUS(AE_OK);
- }
-
- /* Get the header in order to get signature and table size */
-
- status = acpi_tb_get_table_header(address, &header);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- /* Clear the table_info */
-
- ACPI_MEMSET(table_info, 0, sizeof(struct acpi_table_desc));
-
- /*
- * Check the table signature and make sure it is recognized.
- * Also checks the header checksum
- */
- table_info->pointer = &header;
- status = acpi_tb_recognize_table(table_info, ACPI_TABLE_PRIMARY);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- /* Get the entire table */
-
- status = acpi_tb_get_table_body(address, &header, table_info);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- /* Install the table */
-
- status = acpi_tb_install_table(table_info);
- return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_get_secondary_table
- *
- * PARAMETERS: Address - Physical address of table to retrieve
- * *table_info - Where the table info is returned
- *
- * RETURN: Status
- *
- * DESCRIPTION: Maps the physical address of table into a logical address
- *
- ******************************************************************************/
-
-static acpi_status
-acpi_tb_get_secondary_table(struct acpi_pointer *address,
- acpi_string signature,
- struct acpi_table_desc *table_info)
-{
- acpi_status status;
- struct acpi_table_header header;
-
- ACPI_FUNCTION_TRACE_STR(tb_get_secondary_table, signature);
-
- /* Get the header in order to match the signature */
-
- status = acpi_tb_get_table_header(address, &header);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- /* Signature must match request */
-
- if (!ACPI_COMPARE_NAME(header.signature, signature)) {
- ACPI_ERROR((AE_INFO,
- "Incorrect table signature - wanted [%s] found [%4.4s]",
- signature, header.signature));
- return_ACPI_STATUS(AE_BAD_SIGNATURE);
- }
-
- /*
- * Check the table signature and make sure it is recognized.
- * Also checks the header checksum
- */
- table_info->pointer = &header;
- status = acpi_tb_recognize_table(table_info, ACPI_TABLE_SECONDARY);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- /* Get the entire table */
-
- status = acpi_tb_get_table_body(address, &header, table_info);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- /* Install the table */
-
- status = acpi_tb_install_table(table_info);
- return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_get_required_tables
- *
- * PARAMETERS: None
- *
- * RETURN: Status
- *
- * DESCRIPTION: Load and validate tables other than the RSDT. The RSDT must
- * already be loaded and validated.
- *
- * Get the minimum set of ACPI tables, namely:
- *
- * 1) FADT (via RSDT in loop below)
- * 2) FACS (via FADT)
- * 3) DSDT (via FADT)
- *
- ******************************************************************************/
-
-acpi_status acpi_tb_get_required_tables(void)
-{
- acpi_status status = AE_OK;
- u32 i;
- struct acpi_table_desc table_info;
- struct acpi_pointer address;
-
- ACPI_FUNCTION_TRACE(tb_get_required_tables);
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%d ACPI tables in RSDT\n",
- acpi_gbl_rsdt_table_count));
-
- address.pointer_type = acpi_gbl_table_flags | ACPI_LOGICAL_ADDRESSING;
-
- /*
- * Loop through all table pointers found in RSDT.
- * This will NOT include the FACS and DSDT - we must get
- * them after the loop.
- *
- * The only tables we are interested in getting here is the FADT and
- * any SSDTs.
- */
- for (i = 0; i < acpi_gbl_rsdt_table_count; i++) {
-
- /* Get the table address from the common internal XSDT */
-
- address.pointer.value = acpi_gbl_XSDT->table_offset_entry[i];
-
- /*
- * Get the tables needed by this subsystem (FADT and any SSDTs).
- * NOTE: All other tables are completely ignored at this time.
- */
- status = acpi_tb_get_primary_table(&address, &table_info);
- if ((status != AE_OK) && (status != AE_TABLE_NOT_SUPPORTED)) {
- ACPI_WARNING((AE_INFO,
- "%s, while getting table at %8.8X%8.8X",
- acpi_format_exception(status),
- ACPI_FORMAT_UINT64(address.pointer.
- value)));
- }
- }
-
- /* We must have a FADT to continue */
-
- if (!acpi_gbl_FADT) {
- ACPI_ERROR((AE_INFO, "No FADT present in RSDT/XSDT"));
- return_ACPI_STATUS(AE_NO_ACPI_TABLES);
- }
-
- /*
- * Convert the FADT to a common format. This allows earlier revisions of
- * the table to coexist with newer versions, using common access code.
- */
- status = acpi_tb_convert_table_fadt();
- if (ACPI_FAILURE(status)) {
- ACPI_ERROR((AE_INFO,
- "Could not convert FADT to internal common format"));
- return_ACPI_STATUS(status);
- }
-
- /* Get the FACS (Pointed to by the FADT) */
-
- address.pointer.value = acpi_gbl_FADT->xfirmware_ctrl;
-
- status = acpi_tb_get_secondary_table(&address, FACS_SIG, &table_info);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status,
- "Could not get/install the FACS"));
- return_ACPI_STATUS(status);
- }
-
- /*
- * Create the common FACS pointer table
- * (Contains pointers to the original table)
- */
- status = acpi_tb_build_common_facs(&table_info);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- /* Get/install the DSDT (Pointed to by the FADT) */
-
- address.pointer.value = acpi_gbl_FADT->Xdsdt;
-
- status = acpi_tb_get_secondary_table(&address, DSDT_SIG, &table_info);
- if (ACPI_FAILURE(status)) {
- ACPI_ERROR((AE_INFO, "Could not get/install the DSDT"));
- return_ACPI_STATUS(status);
- }
-
- /* Set Integer Width (32/64) based upon DSDT revision */
-
- acpi_ut_set_integer_width(acpi_gbl_DSDT->revision);
-
- /* Dump the entire DSDT */
-
- ACPI_DEBUG_PRINT((ACPI_DB_TABLES,
- "Hex dump of entire DSDT, size %d (0x%X), Integer width = %d\n",
- acpi_gbl_DSDT->length, acpi_gbl_DSDT->length,
- acpi_gbl_integer_bit_width));
-
- ACPI_DUMP_BUFFER(ACPI_CAST_PTR(u8, acpi_gbl_DSDT),
- acpi_gbl_DSDT->length);
-
- /* Always delete the RSDP mapping, we are done with it */
-
- acpi_tb_delete_tables_by_type(ACPI_TABLE_ID_RSDP);
- return_ACPI_STATUS(status);
-}
diff --git a/drivers/acpi/tables/tbinstal.c b/drivers/acpi/tables/tbinstal.c
index 1668a232fb6..0e7b121a99c 100644
--- a/drivers/acpi/tables/tbinstal.c
+++ b/drivers/acpi/tables/tbinstal.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -42,510 +42,498 @@
*/
#include <acpi/acpi.h>
+#include <acpi/acnamesp.h>
#include <acpi/actables.h>
#define _COMPONENT ACPI_TABLES
ACPI_MODULE_NAME("tbinstal")
-/* Local prototypes */
-static acpi_status
-acpi_tb_match_signature(char *signature,
- struct acpi_table_desc *table_info, u8 search_type);
-
-/*******************************************************************************
+/******************************************************************************
*
- * FUNCTION: acpi_tb_match_signature
+ * FUNCTION: acpi_tb_verify_table
*
- * PARAMETERS: Signature - Table signature to match
- * table_info - Return data
- * search_type - Table type to match (primary/secondary)
+ * PARAMETERS: table_desc - table
*
* RETURN: Status
*
- * DESCRIPTION: Compare signature against the list of "ACPI-subsystem-owned"
- * tables (DSDT/FADT/SSDT, etc.) Returns the table_type_iD on match.
+ * DESCRIPTION: this function is called to verify and map table
*
- ******************************************************************************/
-
-static acpi_status
-acpi_tb_match_signature(char *signature,
- struct acpi_table_desc *table_info, u8 search_type)
+ *****************************************************************************/
+acpi_status acpi_tb_verify_table(struct acpi_table_desc *table_desc)
{
- acpi_native_uint i;
+ acpi_status status = AE_OK;
- ACPI_FUNCTION_TRACE(tb_match_signature);
+ ACPI_FUNCTION_TRACE(tb_verify_table);
- /* Search for a signature match among the known table types */
+ /* Map the table if necessary */
- for (i = 0; i < (ACPI_TABLE_ID_MAX + 1); i++) {
- if (!(acpi_gbl_table_data[i].flags & search_type)) {
- continue;
+ if (!table_desc->pointer) {
+ if ((table_desc->flags & ACPI_TABLE_ORIGIN_MASK) ==
+ ACPI_TABLE_ORIGIN_MAPPED) {
+ table_desc->pointer =
+ acpi_os_map_memory(table_desc->address,
+ table_desc->length);
}
+ if (!table_desc->pointer) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
+ }
+ }
- if (!ACPI_STRNCMP(signature, acpi_gbl_table_data[i].signature,
- acpi_gbl_table_data[i].sig_length)) {
-
- /* Found a signature match, return index if requested */
+ /* FACS is the odd table, has no standard ACPI header and no checksum */
- if (table_info) {
- table_info->type = (u8) i;
- }
+ if (!ACPI_COMPARE_NAME(&table_desc->signature, ACPI_SIG_FACS)) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Table [%4.4s] is an ACPI table consumed by the core subsystem\n",
- (char *)acpi_gbl_table_data[i].
- signature));
+ /* Always calculate checksum, ignore bad checksum if requested */
- return_ACPI_STATUS(AE_OK);
- }
+ status =
+ acpi_tb_verify_checksum(table_desc->pointer,
+ table_desc->length);
}
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Table [%4.4s] is not an ACPI table consumed by the core subsystem - ignored\n",
- (char *)signature));
-
- return_ACPI_STATUS(AE_TABLE_NOT_SUPPORTED);
+ return_ACPI_STATUS(status);
}
/*******************************************************************************
*
- * FUNCTION: acpi_tb_install_table
+ * FUNCTION: acpi_tb_add_table
*
- * PARAMETERS: table_info - Return value from acpi_tb_get_table_body
+ * PARAMETERS: table_desc - Table descriptor
+ * table_index - Where the table index is returned
*
* RETURN: Status
*
- * DESCRIPTION: Install the table into the global data structures.
+ * DESCRIPTION: This function is called to add the ACPI table
*
******************************************************************************/
-acpi_status acpi_tb_install_table(struct acpi_table_desc *table_info)
+acpi_status
+acpi_tb_add_table(struct acpi_table_desc *table_desc,
+ acpi_native_uint * table_index)
{
- acpi_status status;
-
- ACPI_FUNCTION_TRACE(tb_install_table);
+ acpi_native_uint i;
+ acpi_native_uint length;
+ acpi_status status = AE_OK;
- /* Lock tables while installing */
+ ACPI_FUNCTION_TRACE(tb_add_table);
- status = acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status,
- "Could not acquire table mutex"));
- return_ACPI_STATUS(status);
+ if (!table_desc->pointer) {
+ status = acpi_tb_verify_table(table_desc);
+ if (ACPI_FAILURE(status) || !table_desc->pointer) {
+ return_ACPI_STATUS(status);
+ }
}
- /*
- * Ignore a table that is already installed. For example, some BIOS
- * ASL code will repeatedly attempt to load the same SSDT.
- */
- status = acpi_tb_is_table_installed(table_info);
- if (ACPI_FAILURE(status)) {
- goto unlock_and_exit;
+ /* The table must be either an SSDT or a PSDT */
+
+ if ((!ACPI_COMPARE_NAME(table_desc->pointer->signature, ACPI_SIG_PSDT))
+ &&
+ (!ACPI_COMPARE_NAME(table_desc->pointer->signature, ACPI_SIG_SSDT)))
+ {
+ ACPI_ERROR((AE_INFO,
+ "Table has invalid signature [%4.4s], must be SSDT or PSDT",
+ table_desc->pointer->signature));
+ return_ACPI_STATUS(AE_BAD_SIGNATURE);
}
- /* Install the table into the global data structure */
+ (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+
+ /* Check if table is already registered */
+
+ for (i = 0; i < acpi_gbl_root_table_list.count; ++i) {
+ if (!acpi_gbl_root_table_list.tables[i].pointer) {
+ status =
+ acpi_tb_verify_table(&acpi_gbl_root_table_list.
+ tables[i]);
+ if (ACPI_FAILURE(status)
+ || !acpi_gbl_root_table_list.tables[i].pointer) {
+ continue;
+ }
+ }
+
+ length = ACPI_MIN(table_desc->length,
+ acpi_gbl_root_table_list.tables[i].length);
+ if (ACPI_MEMCMP(table_desc->pointer,
+ acpi_gbl_root_table_list.tables[i].pointer,
+ length)) {
+ continue;
+ }
+
+ /* Table is already registered */
+
+ acpi_tb_delete_table(table_desc);
+ *table_index = i;
+ goto release;
+ }
- status = acpi_tb_init_table_descriptor(table_info->type, table_info);
+ /*
+ * Add the table to the global table list
+ */
+ status = acpi_tb_store_table(table_desc->address, table_desc->pointer,
+ table_desc->length, table_desc->flags,
+ table_index);
if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status,
- "Could not install table [%4.4s]",
- table_info->pointer->signature));
+ goto release;
}
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s located at %p\n",
- acpi_gbl_table_data[table_info->type].name,
- table_info->pointer));
+ acpi_tb_print_table_header(table_desc->address, table_desc->pointer);
- unlock_and_exit:
+ release:
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
return_ACPI_STATUS(status);
}
/*******************************************************************************
*
- * FUNCTION: acpi_tb_recognize_table
+ * FUNCTION: acpi_tb_resize_root_table_list
*
- * PARAMETERS: table_info - Return value from acpi_tb_get_table_body
- * search_type - Table type to match (primary/secondary)
+ * PARAMETERS: None
*
* RETURN: Status
*
- * DESCRIPTION: Check a table signature for a match against known table types
- *
- * NOTE: All table pointers are validated as follows:
- * 1) Table pointer must point to valid physical memory
- * 2) Signature must be 4 ASCII chars, even if we don't recognize the
- * name
- * 3) Table must be readable for length specified in the header
- * 4) Table checksum must be valid (with the exception of the FACS
- * which has no checksum for some odd reason)
+ * DESCRIPTION: Expand the size of global table array
*
******************************************************************************/
-acpi_status
-acpi_tb_recognize_table(struct acpi_table_desc *table_info, u8 search_type)
+acpi_status acpi_tb_resize_root_table_list(void)
{
- struct acpi_table_header *table_header;
- acpi_status status;
+ struct acpi_table_desc *tables;
- ACPI_FUNCTION_TRACE(tb_recognize_table);
+ ACPI_FUNCTION_TRACE(tb_resize_root_table_list);
- /* Ensure that we have a valid table pointer */
+ /* allow_resize flag is a parameter to acpi_initialize_tables */
- table_header = (struct acpi_table_header *)table_info->pointer;
- if (!table_header) {
- return_ACPI_STATUS(AE_BAD_PARAMETER);
+ if (!(acpi_gbl_root_table_list.flags & ACPI_ROOT_ALLOW_RESIZE)) {
+ ACPI_ERROR((AE_INFO,
+ "Resize of Root Table Array is not allowed"));
+ return_ACPI_STATUS(AE_SUPPORT);
}
- /*
- * We only "recognize" a limited number of ACPI tables -- namely, the
- * ones that are used by the subsystem (DSDT, FADT, etc.)
- *
- * An AE_TABLE_NOT_SUPPORTED means that the table was not recognized.
- * This can be any one of many valid ACPI tables, it just isn't one of
- * the tables that is consumed by the core subsystem
- */
- status = acpi_tb_match_signature(table_header->signature,
- table_info, search_type);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ /* Increase the Table Array size */
+
+ tables = ACPI_ALLOCATE_ZEROED((acpi_gbl_root_table_list.size +
+ ACPI_ROOT_TABLE_SIZE_INCREMENT)
+ * sizeof(struct acpi_table_desc));
+ if (!tables) {
+ ACPI_ERROR((AE_INFO,
+ "Could not allocate new root table array"));
+ return_ACPI_STATUS(AE_NO_MEMORY);
}
- status = acpi_tb_validate_table_header(table_header);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ /* Copy and free the previous table array */
+
+ if (acpi_gbl_root_table_list.tables) {
+ ACPI_MEMCPY(tables, acpi_gbl_root_table_list.tables,
+ acpi_gbl_root_table_list.size *
+ sizeof(struct acpi_table_desc));
+
+ if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) {
+ ACPI_FREE(acpi_gbl_root_table_list.tables);
+ }
}
- /* Return the table type and length via the info struct */
+ acpi_gbl_root_table_list.tables = tables;
+ acpi_gbl_root_table_list.size += ACPI_ROOT_TABLE_SIZE_INCREMENT;
+ acpi_gbl_root_table_list.flags |= (u8) ACPI_ROOT_ORIGIN_ALLOCATED;
- table_info->length = (acpi_size) table_header->length;
- return_ACPI_STATUS(status);
+ return_ACPI_STATUS(AE_OK);
}
/*******************************************************************************
*
- * FUNCTION: acpi_tb_init_table_descriptor
+ * FUNCTION: acpi_tb_store_table
*
- * PARAMETERS: table_type - The type of the table
- * table_info - A table info struct
+ * PARAMETERS: Address - Table address
+ * Table - Table header
+ * Length - Table length
+ * Flags - flags
*
- * RETURN: None.
+ * RETURN: Status and table index.
*
- * DESCRIPTION: Install a table into the global data structs.
+ * DESCRIPTION: Add an ACPI table to the global table list
*
******************************************************************************/
acpi_status
-acpi_tb_init_table_descriptor(acpi_table_type table_type,
- struct acpi_table_desc *table_info)
+acpi_tb_store_table(acpi_physical_address address,
+ struct acpi_table_header *table,
+ u32 length, u8 flags, acpi_native_uint * table_index)
{
- struct acpi_table_list *list_head;
- struct acpi_table_desc *table_desc;
- acpi_status status;
-
- ACPI_FUNCTION_TRACE_U32(tb_init_table_descriptor, table_type);
+ acpi_status status = AE_OK;
- /* Allocate a descriptor for this table */
+ /* Ensure that there is room for the table in the Root Table List */
- table_desc = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_table_desc));
- if (!table_desc) {
- return_ACPI_STATUS(AE_NO_MEMORY);
+ if (acpi_gbl_root_table_list.count >= acpi_gbl_root_table_list.size) {
+ status = acpi_tb_resize_root_table_list();
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
}
- /* Get a new owner ID for the table */
+ /* Initialize added table */
+
+ acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list.count].
+ address = address;
+ acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list.count].
+ pointer = table;
+ acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list.count].length =
+ length;
+ acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list.count].
+ owner_id = 0;
+ acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list.count].flags =
+ flags;
+
+ ACPI_MOVE_32_TO_32(&
+ (acpi_gbl_root_table_list.
+ tables[acpi_gbl_root_table_list.count].signature),
+ table->signature);
+
+ *table_index = acpi_gbl_root_table_list.count;
+ acpi_gbl_root_table_list.count++;
+ return (status);
+}
- status = acpi_ut_allocate_owner_id(&table_desc->owner_id);
- if (ACPI_FAILURE(status)) {
- goto error_exit1;
- }
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_delete_table
+ *
+ * PARAMETERS: table_index - Table index
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Delete one internal ACPI table
+ *
+ ******************************************************************************/
- /* Install the table into the global data structure */
+void acpi_tb_delete_table(struct acpi_table_desc *table_desc)
+{
+ /* Table must be mapped or allocated */
+ if (!table_desc->pointer) {
+ return;
+ }
+ switch (table_desc->flags & ACPI_TABLE_ORIGIN_MASK) {
+ case ACPI_TABLE_ORIGIN_MAPPED:
+ acpi_os_unmap_memory(table_desc->pointer, table_desc->length);
+ break;
+ case ACPI_TABLE_ORIGIN_ALLOCATED:
+ ACPI_FREE(table_desc->pointer);
+ break;
+ default:;
+ }
- list_head = &acpi_gbl_table_lists[table_type];
+ table_desc->pointer = NULL;
+}
- /*
- * Two major types of tables: 1) Only one instance is allowed. This
- * includes most ACPI tables such as the DSDT. 2) Multiple instances of
- * the table are allowed. This includes SSDT and PSDTs.
- */
- if (ACPI_IS_SINGLE_TABLE(acpi_gbl_table_data[table_type].flags)) {
- /*
- * Only one table allowed, and a table has alread been installed
- * at this location, so return an error.
- */
- if (list_head->next) {
- status = AE_ALREADY_EXISTS;
- goto error_exit2;
- }
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_terminate
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Delete all internal ACPI tables
+ *
+ ******************************************************************************/
- table_desc->next = list_head->next;
- list_head->next = table_desc;
+void acpi_tb_terminate(void)
+{
+ acpi_native_uint i;
- if (table_desc->next) {
- table_desc->next->prev = table_desc;
- }
+ ACPI_FUNCTION_TRACE(tb_terminate);
- list_head->count++;
- } else {
- /*
- * Link the new table in to the list of tables of this type.
- * Insert at the end of the list, order IS IMPORTANT.
- *
- * table_desc->Prev & Next are already NULL from calloc()
- */
- list_head->count++;
-
- if (!list_head->next) {
- list_head->next = table_desc;
- } else {
- table_desc->next = list_head->next;
+ (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
- while (table_desc->next->next) {
- table_desc->next = table_desc->next->next;
- }
+ /* Delete the individual tables */
- table_desc->next->next = table_desc;
- table_desc->prev = table_desc->next;
- table_desc->next = NULL;
- }
+ for (i = 0; i < acpi_gbl_root_table_list.count; ++i) {
+ acpi_tb_delete_table(&acpi_gbl_root_table_list.tables[i]);
}
- /* Finish initialization of the table descriptor */
-
- table_desc->loaded_into_namespace = FALSE;
- table_desc->type = (u8) table_type;
- table_desc->pointer = table_info->pointer;
- table_desc->length = table_info->length;
- table_desc->allocation = table_info->allocation;
- table_desc->aml_start = (u8 *) (table_desc->pointer + 1),
- table_desc->aml_length = (u32)
- (table_desc->length - (u32) sizeof(struct acpi_table_header));
-
/*
- * Set the appropriate global pointer (if there is one) to point to the
- * newly installed table
+ * Delete the root table array if allocated locally. Array cannot be
+ * mapped, so we don't need to check for that flag.
*/
- if (acpi_gbl_table_data[table_type].global_ptr) {
- *(acpi_gbl_table_data[table_type].global_ptr) =
- table_info->pointer;
+ if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) {
+ ACPI_FREE(acpi_gbl_root_table_list.tables);
}
- /* Return Data */
-
- table_info->owner_id = table_desc->owner_id;
- table_info->installed_desc = table_desc;
- return_ACPI_STATUS(AE_OK);
-
- /* Error exit with cleanup */
-
- error_exit2:
-
- acpi_ut_release_owner_id(&table_desc->owner_id);
+ acpi_gbl_root_table_list.tables = NULL;
+ acpi_gbl_root_table_list.flags = 0;
+ acpi_gbl_root_table_list.count = 0;
- error_exit1:
-
- ACPI_FREE(table_desc);
- return_ACPI_STATUS(status);
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "ACPI Tables freed\n"));
+ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
}
/*******************************************************************************
*
- * FUNCTION: acpi_tb_delete_all_tables
+ * FUNCTION: acpi_tb_delete_namespace_by_owner
*
- * PARAMETERS: None.
+ * PARAMETERS: table_index - Table index
*
- * RETURN: None.
+ * RETURN: None
*
- * DESCRIPTION: Delete all internal ACPI tables
+ * DESCRIPTION: Delete all namespace objects created when this table was loaded.
*
******************************************************************************/
-void acpi_tb_delete_all_tables(void)
+void acpi_tb_delete_namespace_by_owner(acpi_native_uint table_index)
{
- acpi_table_type type;
+ acpi_owner_id owner_id;
- /*
- * Free memory allocated for ACPI tables
- * Memory can either be mapped or allocated
- */
- for (type = 0; type < (ACPI_TABLE_ID_MAX + 1); type++) {
- acpi_tb_delete_tables_by_type(type);
+ (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+ if (table_index < acpi_gbl_root_table_list.count) {
+ owner_id =
+ acpi_gbl_root_table_list.tables[table_index].owner_id;
+ } else {
+ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+ return;
}
+
+ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+ acpi_ns_delete_namespace_by_owner(owner_id);
}
/*******************************************************************************
*
- * FUNCTION: acpi_tb_delete_tables_by_type
+ * FUNCTION: acpi_tb_allocate_owner_id
*
- * PARAMETERS: Type - The table type to be deleted
+ * PARAMETERS: table_index - Table index
*
- * RETURN: None.
+ * RETURN: Status
*
- * DESCRIPTION: Delete an internal ACPI table
- * Locks the ACPI table mutex
+ * DESCRIPTION: Allocates owner_id in table_desc
*
******************************************************************************/
-void acpi_tb_delete_tables_by_type(acpi_table_type type)
+acpi_status acpi_tb_allocate_owner_id(acpi_native_uint table_index)
{
- struct acpi_table_desc *table_desc;
- u32 count;
- u32 i;
+ acpi_status status = AE_BAD_PARAMETER;
- ACPI_FUNCTION_TRACE_U32(tb_delete_tables_by_type, type);
+ ACPI_FUNCTION_TRACE(tb_allocate_owner_id);
- if (type > ACPI_TABLE_ID_MAX) {
- return_VOID;
- }
-
- if (ACPI_FAILURE(acpi_ut_acquire_mutex(ACPI_MTX_TABLES))) {
- return;
- }
-
- /* Clear the appropriate "typed" global table pointer */
-
- switch (type) {
- case ACPI_TABLE_ID_RSDP:
- acpi_gbl_RSDP = NULL;
- break;
-
- case ACPI_TABLE_ID_DSDT:
- acpi_gbl_DSDT = NULL;
- break;
-
- case ACPI_TABLE_ID_FADT:
- acpi_gbl_FADT = NULL;
- break;
-
- case ACPI_TABLE_ID_FACS:
- acpi_gbl_FACS = NULL;
- break;
-
- case ACPI_TABLE_ID_XSDT:
- acpi_gbl_XSDT = NULL;
- break;
-
- case ACPI_TABLE_ID_SSDT:
- case ACPI_TABLE_ID_PSDT:
- default:
- break;
- }
-
- /*
- * Free the table
- * 1) Get the head of the list
- */
- table_desc = acpi_gbl_table_lists[type].next;
- count = acpi_gbl_table_lists[type].count;
-
- /*
- * 2) Walk the entire list, deleting both the allocated tables
- * and the table descriptors
- */
- for (i = 0; i < count; i++) {
- table_desc = acpi_tb_uninstall_table(table_desc);
+ (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+ if (table_index < acpi_gbl_root_table_list.count) {
+ status = acpi_ut_allocate_owner_id
+ (&(acpi_gbl_root_table_list.tables[table_index].owner_id));
}
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
- return_VOID;
+ return_ACPI_STATUS(status);
}
/*******************************************************************************
*
- * FUNCTION: acpi_tb_delete_single_table
+ * FUNCTION: acpi_tb_release_owner_id
*
- * PARAMETERS: table_info - A table info struct
+ * PARAMETERS: table_index - Table index
*
- * RETURN: None.
+ * RETURN: Status
*
- * DESCRIPTION: Low-level free for a single ACPI table. Handles cases where
- * the table was allocated a buffer or was mapped.
+ * DESCRIPTION: Releases owner_id in table_desc
*
******************************************************************************/
-void acpi_tb_delete_single_table(struct acpi_table_desc *table_desc)
+acpi_status acpi_tb_release_owner_id(acpi_native_uint table_index)
{
+ acpi_status status = AE_BAD_PARAMETER;
- /* Must have a valid table descriptor and pointer */
+ ACPI_FUNCTION_TRACE(tb_release_owner_id);
- if ((!table_desc) || (!table_desc->pointer)) {
- return;
+ (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+ if (table_index < acpi_gbl_root_table_list.count) {
+ acpi_ut_release_owner_id(&
+ (acpi_gbl_root_table_list.
+ tables[table_index].owner_id));
+ status = AE_OK;
}
- /* Valid table, determine type of memory allocation */
-
- switch (table_desc->allocation) {
- case ACPI_MEM_NOT_ALLOCATED:
- break;
-
- case ACPI_MEM_ALLOCATED:
-
- ACPI_FREE(table_desc->pointer);
- break;
-
- case ACPI_MEM_MAPPED:
-
- acpi_os_unmap_memory(table_desc->pointer, table_desc->length);
- break;
-
- default:
- break;
- }
+ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+ return_ACPI_STATUS(status);
}
/*******************************************************************************
*
- * FUNCTION: acpi_tb_uninstall_table
+ * FUNCTION: acpi_tb_get_owner_id
*
- * PARAMETERS: table_info - A table info struct
+ * PARAMETERS: table_index - Table index
+ * owner_id - Where the table owner_id is returned
*
- * RETURN: Pointer to the next table in the list (of same type)
+ * RETURN: Status
*
- * DESCRIPTION: Free the memory associated with an internal ACPI table that
- * is either installed or has never been installed.
- * Table mutex should be locked.
+ * DESCRIPTION: returns owner_id for the ACPI table
*
******************************************************************************/
-struct acpi_table_desc *acpi_tb_uninstall_table(struct acpi_table_desc
- *table_desc)
+acpi_status
+acpi_tb_get_owner_id(acpi_native_uint table_index, acpi_owner_id * owner_id)
{
- struct acpi_table_desc *next_desc;
+ acpi_status status = AE_BAD_PARAMETER;
- ACPI_FUNCTION_TRACE_PTR(tb_uninstall_table, table_desc);
+ ACPI_FUNCTION_TRACE(tb_get_owner_id);
- if (!table_desc) {
- return_PTR(NULL);
+ (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+ if (table_index < acpi_gbl_root_table_list.count) {
+ *owner_id =
+ acpi_gbl_root_table_list.tables[table_index].owner_id;
+ status = AE_OK;
}
- /* Unlink the descriptor from the doubly linked list */
+ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+ return_ACPI_STATUS(status);
+}
- if (table_desc->prev) {
- table_desc->prev->next = table_desc->next;
- } else {
- /* Is first on list, update list head */
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_is_table_loaded
+ *
+ * PARAMETERS: table_index - Table index
+ *
+ * RETURN: Table Loaded Flag
+ *
+ ******************************************************************************/
- acpi_gbl_table_lists[table_desc->type].next = table_desc->next;
- }
+u8 acpi_tb_is_table_loaded(acpi_native_uint table_index)
+{
+ u8 is_loaded = FALSE;
- if (table_desc->next) {
- table_desc->next->prev = table_desc->prev;
+ (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+ if (table_index < acpi_gbl_root_table_list.count) {
+ is_loaded = (u8)
+ (acpi_gbl_root_table_list.tables[table_index].
+ flags & ACPI_TABLE_IS_LOADED);
}
- /* Free the memory allocated for the table itself */
-
- acpi_tb_delete_single_table(table_desc);
-
- /* Free the owner ID associated with this table */
-
- acpi_ut_release_owner_id(&table_desc->owner_id);
+ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+ return (is_loaded);
+}
- /* Free the table descriptor */
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_set_table_loaded_flag
+ *
+ * PARAMETERS: table_index - Table index
+ * is_loaded - TRUE if table is loaded, FALSE otherwise
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Sets the table loaded flag to either TRUE or FALSE.
+ *
+ ******************************************************************************/
- next_desc = table_desc->next;
- ACPI_FREE(table_desc);
+void acpi_tb_set_table_loaded_flag(acpi_native_uint table_index, u8 is_loaded)
+{
- /* Return pointer to the next descriptor */
+ (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+ if (table_index < acpi_gbl_root_table_list.count) {
+ if (is_loaded) {
+ acpi_gbl_root_table_list.tables[table_index].flags |=
+ ACPI_TABLE_IS_LOADED;
+ } else {
+ acpi_gbl_root_table_list.tables[table_index].flags &=
+ ~ACPI_TABLE_IS_LOADED;
+ }
+ }
- return_PTR(next_desc);
+ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
}
diff --git a/drivers/acpi/tables/tbrsdt.c b/drivers/acpi/tables/tbrsdt.c
deleted file mode 100644
index 86a5fca9b73..00000000000
--- a/drivers/acpi/tables/tbrsdt.c
+++ /dev/null
@@ -1,307 +0,0 @@
-/******************************************************************************
- *
- * Module Name: tbrsdt - ACPI RSDT table utilities
- *
- *****************************************************************************/
-
-/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions, and the following disclaimer,
- * without modification.
- * 2. Redistributions in binary form must reproduce at minimum a disclaimer
- * substantially similar to the "NO WARRANTY" disclaimer below
- * ("Disclaimer") and any redistribution must be conditioned upon
- * including a substantially similar Disclaimer requirement for further
- * binary redistribution.
- * 3. Neither the names of the above-listed copyright holders nor the names
- * of any contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * Alternatively, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2 as published by the Free
- * Software Foundation.
- *
- * NO WARRANTY
- * 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 MERCHANTIBILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
- */
-
-#include <acpi/acpi.h>
-#include <acpi/actables.h>
-
-#define _COMPONENT ACPI_TABLES
-ACPI_MODULE_NAME("tbrsdt")
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_verify_rsdp
- *
- * PARAMETERS: Address - RSDP (Pointer to RSDT)
- *
- * RETURN: Status
- *
- * DESCRIPTION: Load and validate the RSDP (ptr) and RSDT (table)
- *
- ******************************************************************************/
-acpi_status acpi_tb_verify_rsdp(struct acpi_pointer *address)
-{
- struct acpi_table_desc table_info;
- acpi_status status;
- struct rsdp_descriptor *rsdp;
-
- ACPI_FUNCTION_TRACE(tb_verify_rsdp);
-
- switch (address->pointer_type) {
- case ACPI_LOGICAL_POINTER:
-
- rsdp = address->pointer.logical;
- break;
-
- case ACPI_PHYSICAL_POINTER:
- /*
- * Obtain access to the RSDP structure
- */
- status = acpi_os_map_memory(address->pointer.physical,
- sizeof(struct rsdp_descriptor),
- ACPI_CAST_PTR(void, &rsdp));
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
- break;
-
- default:
- return_ACPI_STATUS(AE_BAD_PARAMETER);
- }
-
- /* Verify RSDP signature and checksum */
-
- status = acpi_tb_validate_rsdp(rsdp);
- if (ACPI_FAILURE(status)) {
- goto cleanup;
- }
-
- /* RSDP is ok. Init the table info */
-
- table_info.pointer = ACPI_CAST_PTR(struct acpi_table_header, rsdp);
- table_info.length = sizeof(struct rsdp_descriptor);
-
- if (address->pointer_type == ACPI_PHYSICAL_POINTER) {
- table_info.allocation = ACPI_MEM_MAPPED;
- } else {
- table_info.allocation = ACPI_MEM_NOT_ALLOCATED;
- }
-
- /* Save the table pointers and allocation info */
-
- status = acpi_tb_init_table_descriptor(ACPI_TABLE_ID_RSDP, &table_info);
- if (ACPI_FAILURE(status)) {
- goto cleanup;
- }
-
- /* Save the RSDP in a global for easy access */
-
- acpi_gbl_RSDP =
- ACPI_CAST_PTR(struct rsdp_descriptor, table_info.pointer);
- return_ACPI_STATUS(status);
-
- /* Error exit */
- cleanup:
-
- if (acpi_gbl_table_flags & ACPI_PHYSICAL_POINTER) {
- acpi_os_unmap_memory(rsdp, sizeof(struct rsdp_descriptor));
- }
- return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_get_rsdt_address
- *
- * PARAMETERS: out_address - Where the address is returned
- *
- * RETURN: None, Address
- *
- * DESCRIPTION: Extract the address of either the RSDT or XSDT, depending on the
- * version of the RSDP and whether the XSDT pointer is valid
- *
- ******************************************************************************/
-
-void acpi_tb_get_rsdt_address(struct acpi_pointer *out_address)
-{
-
- ACPI_FUNCTION_ENTRY();
-
- out_address->pointer_type =
- acpi_gbl_table_flags | ACPI_LOGICAL_ADDRESSING;
-
- /* Use XSDT if it is present */
-
- if ((acpi_gbl_RSDP->revision >= 2) &&
- acpi_gbl_RSDP->xsdt_physical_address) {
- out_address->pointer.value =
- acpi_gbl_RSDP->xsdt_physical_address;
- acpi_gbl_root_table_type = ACPI_TABLE_TYPE_XSDT;
- } else {
- /* No XSDT, use the RSDT */
-
- out_address->pointer.value =
- acpi_gbl_RSDP->rsdt_physical_address;
- acpi_gbl_root_table_type = ACPI_TABLE_TYPE_RSDT;
- }
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_validate_rsdt
- *
- * PARAMETERS: table_ptr - Addressable pointer to the RSDT.
- *
- * RETURN: Status
- *
- * DESCRIPTION: Validate signature for the RSDT or XSDT
- *
- ******************************************************************************/
-
-acpi_status acpi_tb_validate_rsdt(struct acpi_table_header *table_ptr)
-{
- char *signature;
-
- ACPI_FUNCTION_ENTRY();
-
- /* Validate minimum length */
-
- if (table_ptr->length < sizeof(struct acpi_table_header)) {
- ACPI_ERROR((AE_INFO,
- "RSDT/XSDT length (%X) is smaller than minimum (%zX)",
- table_ptr->length,
- sizeof(struct acpi_table_header)));
-
- return (AE_INVALID_TABLE_LENGTH);
- }
-
- /* Search for appropriate signature, RSDT or XSDT */
-
- if (acpi_gbl_root_table_type == ACPI_TABLE_TYPE_RSDT) {
- signature = RSDT_SIG;
- } else {
- signature = XSDT_SIG;
- }
-
- if (!ACPI_COMPARE_NAME(table_ptr->signature, signature)) {
-
- /* Invalid RSDT or XSDT signature */
-
- ACPI_ERROR((AE_INFO,
- "Invalid signature where RSDP indicates RSDT/XSDT should be located. RSDP:"));
-
- ACPI_DUMP_BUFFER(acpi_gbl_RSDP, 20);
-
- ACPI_ERROR((AE_INFO,
- "RSDT/XSDT signature at %X is invalid",
- acpi_gbl_RSDP->rsdt_physical_address));
-
- if (acpi_gbl_root_table_type == ACPI_TABLE_TYPE_RSDT) {
- ACPI_ERROR((AE_INFO, "Looking for RSDT"));
- } else {
- ACPI_ERROR((AE_INFO, "Looking for XSDT"));
- }
-
- ACPI_DUMP_BUFFER(ACPI_CAST_PTR(char, table_ptr), 48);
- return (AE_BAD_SIGNATURE);
- }
-
- return (AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_get_table_rsdt
- *
- * PARAMETERS: None
- *
- * RETURN: Status
- *
- * DESCRIPTION: Load and validate the RSDP (ptr) and RSDT (table)
- *
- ******************************************************************************/
-
-acpi_status acpi_tb_get_table_rsdt(void)
-{
- struct acpi_table_desc table_info;
- acpi_status status;
- struct acpi_pointer address;
-
- ACPI_FUNCTION_TRACE(tb_get_table_rsdt);
-
- /* Get the RSDT/XSDT via the RSDP */
-
- acpi_tb_get_rsdt_address(&address);
-
- table_info.type = ACPI_TABLE_ID_XSDT;
- status = acpi_tb_get_table(&address, &table_info);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status,
- "Could not get the RSDT/XSDT"));
- return_ACPI_STATUS(status);
- }
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "RSDP located at %p, points to RSDT physical=%8.8X%8.8X\n",
- acpi_gbl_RSDP,
- ACPI_FORMAT_UINT64(address.pointer.value)));
-
- /* Check the RSDT or XSDT signature */
-
- status = acpi_tb_validate_rsdt(table_info.pointer);
- if (ACPI_FAILURE(status)) {
- goto error_cleanup;
- }
-
- /* Get the number of tables defined in the RSDT or XSDT */
-
- acpi_gbl_rsdt_table_count = acpi_tb_get_table_count(acpi_gbl_RSDP,
- table_info.pointer);
-
- /* Convert and/or copy to an XSDT structure */
-
- status = acpi_tb_convert_to_xsdt(&table_info);
- if (ACPI_FAILURE(status)) {
- goto error_cleanup;
- }
-
- /* Save the table pointers and allocation info */
-
- status = acpi_tb_init_table_descriptor(ACPI_TABLE_ID_XSDT, &table_info);
- if (ACPI_FAILURE(status)) {
- goto error_cleanup;
- }
-
- acpi_gbl_XSDT =
- ACPI_CAST_PTR(struct xsdt_descriptor, table_info.pointer);
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "XSDT located at %p\n", acpi_gbl_XSDT));
- return_ACPI_STATUS(status);
-
- error_cleanup:
-
- /* Free table allocated by acpi_tb_get_table */
-
- acpi_tb_delete_single_table(&table_info);
-
- return_ACPI_STATUS(status);
-}
diff --git a/drivers/acpi/tables/tbutils.c b/drivers/acpi/tables/tbutils.c
index 209a401801e..1da64b4518c 100644
--- a/drivers/acpi/tables/tbutils.c
+++ b/drivers/acpi/tables/tbutils.c
@@ -1,11 +1,11 @@
/******************************************************************************
*
- * Module Name: tbutils - Table manipulation utilities
+ * Module Name: tbutils - table utilities
*
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -48,137 +48,119 @@
ACPI_MODULE_NAME("tbutils")
/* Local prototypes */
-#ifdef ACPI_OBSOLETE_FUNCTIONS
-acpi_status
-acpi_tb_handle_to_object(u16 table_id, struct acpi_table_desc **table_desc);
-#endif
+static acpi_physical_address
+acpi_tb_get_root_table_entry(u8 * table_entry,
+ acpi_native_uint table_entry_size);
/*******************************************************************************
*
- * FUNCTION: acpi_tb_is_table_installed
- *
- * PARAMETERS: new_table_desc - Descriptor for new table being installed
+ * FUNCTION: acpi_tb_tables_loaded
*
- * RETURN: Status - AE_ALREADY_EXISTS if the table is already installed
+ * PARAMETERS: None
*
- * DESCRIPTION: Determine if an ACPI table is already installed
+ * RETURN: TRUE if required ACPI tables are loaded
*
- * MUTEX: Table data structures should be locked
+ * DESCRIPTION: Determine if the minimum required ACPI tables are present
+ * (FADT, FACS, DSDT)
*
******************************************************************************/
-acpi_status acpi_tb_is_table_installed(struct acpi_table_desc *new_table_desc)
+u8 acpi_tb_tables_loaded(void)
{
- struct acpi_table_desc *table_desc;
-
- ACPI_FUNCTION_TRACE(tb_is_table_installed);
- /* Get the list descriptor and first table descriptor */
-
- table_desc = acpi_gbl_table_lists[new_table_desc->type].next;
+ if (acpi_gbl_root_table_list.count >= 3) {
+ return (TRUE);
+ }
- /* Examine all installed tables of this type */
+ return (FALSE);
+}
- while (table_desc) {
- /*
- * If the table lengths match, perform a full bytewise compare. This
- * means that we will allow tables with duplicate oem_table_id(s), as
- * long as the tables are different in some way.
- *
- * Checking if the table has been loaded into the namespace means that
- * we don't check for duplicate tables during the initial installation
- * of tables within the RSDT/XSDT.
- */
- if ((table_desc->loaded_into_namespace) &&
- (table_desc->pointer->length ==
- new_table_desc->pointer->length)
- &&
- (!ACPI_MEMCMP
- (table_desc->pointer, new_table_desc->pointer,
- new_table_desc->pointer->length))) {
-
- /* Match: this table is already installed */
-
- ACPI_DEBUG_PRINT((ACPI_DB_TABLES,
- "Table [%4.4s] already installed: Rev %X OemTableId [%8.8s]\n",
- new_table_desc->pointer->signature,
- new_table_desc->pointer->revision,
- new_table_desc->pointer->
- oem_table_id));
-
- new_table_desc->owner_id = table_desc->owner_id;
- new_table_desc->installed_desc = table_desc;
-
- return_ACPI_STATUS(AE_ALREADY_EXISTS);
- }
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_print_table_header
+ *
+ * PARAMETERS: Address - Table physical address
+ * Header - Table header
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Print an ACPI table header. Special cases for FACS and RSDP.
+ *
+ ******************************************************************************/
- /* Get next table on the list */
+void
+acpi_tb_print_table_header(acpi_physical_address address,
+ struct acpi_table_header *header)
+{
- table_desc = table_desc->next;
+ if (ACPI_COMPARE_NAME(header->signature, ACPI_SIG_FACS)) {
+
+ /* FACS only has signature and length fields of common table header */
+
+ ACPI_INFO((AE_INFO, "%4.4s %08lX, %04X",
+ header->signature, (unsigned long)address,
+ header->length));
+ } else if (ACPI_COMPARE_NAME(header->signature, ACPI_SIG_RSDP)) {
+
+ /* RSDP has no common fields */
+
+ ACPI_INFO((AE_INFO, "RSDP %08lX, %04X (r%d %6.6s)",
+ (unsigned long)address,
+ (ACPI_CAST_PTR(struct acpi_table_rsdp, header)->
+ revision >
+ 0) ? ACPI_CAST_PTR(struct acpi_table_rsdp,
+ header)->length : 20,
+ ACPI_CAST_PTR(struct acpi_table_rsdp,
+ header)->revision,
+ ACPI_CAST_PTR(struct acpi_table_rsdp,
+ header)->oem_id));
+ } else {
+ /* Standard ACPI table with full common header */
+
+ ACPI_INFO((AE_INFO,
+ "%4.4s %08lX, %04X (r%d %6.6s %8.8s %8X %4.4s %8X)",
+ header->signature, (unsigned long)address,
+ header->length, header->revision, header->oem_id,
+ header->oem_table_id, header->oem_revision,
+ header->asl_compiler_id,
+ header->asl_compiler_revision));
}
-
- return_ACPI_STATUS(AE_OK);
}
/*******************************************************************************
*
- * FUNCTION: acpi_tb_validate_table_header
+ * FUNCTION: acpi_tb_validate_checksum
*
- * PARAMETERS: table_header - Logical pointer to the table
+ * PARAMETERS: Table - ACPI table to verify
+ * Length - Length of entire table
*
* RETURN: Status
*
- * DESCRIPTION: Check an ACPI table header for validity
- *
- * NOTE: Table pointers are validated as follows:
- * 1) Table pointer must point to valid physical memory
- * 2) Signature must be 4 ASCII chars, even if we don't recognize the
- * name
- * 3) Table must be readable for length specified in the header
- * 4) Table checksum must be valid (with the exception of the FACS
- * which has no checksum because it contains variable fields)
+ * DESCRIPTION: Verifies that the table checksums to zero. Optionally returns
+ * exception on bad checksum.
*
******************************************************************************/
-acpi_status
-acpi_tb_validate_table_header(struct acpi_table_header *table_header)
+acpi_status acpi_tb_verify_checksum(struct acpi_table_header *table, u32 length)
{
- acpi_name signature;
-
- ACPI_FUNCTION_ENTRY();
-
- /* Verify that this is a valid address */
-
- if (!acpi_os_readable(table_header, sizeof(struct acpi_table_header))) {
- ACPI_ERROR((AE_INFO,
- "Cannot read table header at %p", table_header));
-
- return (AE_BAD_ADDRESS);
- }
+ u8 checksum;
- /* Ensure that the signature is 4 ASCII characters */
+ /* Compute the checksum on the table */
- ACPI_MOVE_32_TO_32(&signature, table_header->signature);
- if (!acpi_ut_valid_acpi_name(signature)) {
- ACPI_ERROR((AE_INFO, "Invalid table signature 0x%8.8X",
- signature));
+ checksum = acpi_tb_checksum(ACPI_CAST_PTR(u8, table), length);
- ACPI_DUMP_BUFFER(table_header,
- sizeof(struct acpi_table_header));
- return (AE_BAD_SIGNATURE);
- }
+ /* Checksum ok? (should be zero) */
- /* Validate the table length */
+ if (checksum) {
+ ACPI_WARNING((AE_INFO,
+ "Incorrect checksum in table [%4.4s] - %2.2X, should be %2.2X",
+ table->signature, table->checksum,
+ (u8) (table->checksum - checksum)));
- if (table_header->length < sizeof(struct acpi_table_header)) {
- ACPI_ERROR((AE_INFO,
- "Invalid length 0x%X in table with signature %4.4s",
- (u32) table_header->length,
- ACPI_CAST_PTR(char, &signature)));
+#if (ACPI_CHECKSUM_ABORT)
- ACPI_DUMP_BUFFER(table_header,
- sizeof(struct acpi_table_header));
- return (AE_BAD_HEADER);
+ return (AE_BAD_CHECKSUM);
+#endif
}
return (AE_OK);
@@ -186,157 +168,320 @@ acpi_tb_validate_table_header(struct acpi_table_header *table_header)
/*******************************************************************************
*
- * FUNCTION: acpi_tb_sum_table
+ * FUNCTION: acpi_tb_checksum
*
- * PARAMETERS: Buffer - Buffer to sum
- * Length - Size of the buffer
+ * PARAMETERS: Buffer - Pointer to memory region to be checked
+ * Length - Length of this memory region
*
- * RETURN: 8 bit sum of buffer
+ * RETURN: Checksum (u8)
*
- * DESCRIPTION: Computes an 8 bit sum of the buffer(length) and returns it.
+ * DESCRIPTION: Calculates circular checksum of memory region.
*
******************************************************************************/
-u8 acpi_tb_sum_table(void *buffer, u32 length)
+u8 acpi_tb_checksum(u8 * buffer, acpi_native_uint length)
{
- acpi_native_uint i;
u8 sum = 0;
+ u8 *end = buffer + length;
- if (!buffer || !length) {
- return (0);
+ while (buffer < end) {
+ sum = (u8) (sum + *(buffer++));
}
- for (i = 0; i < length; i++) {
- sum = (u8) (sum + ((u8 *) buffer)[i]);
- }
- return (sum);
+ return sum;
}
/*******************************************************************************
*
- * FUNCTION: acpi_tb_generate_checksum
+ * FUNCTION: acpi_tb_install_table
*
- * PARAMETERS: Table - Pointer to a valid ACPI table (with a
- * standard ACPI header)
+ * PARAMETERS: Address - Physical address of DSDT or FACS
+ * Flags - Flags
+ * Signature - Table signature, NULL if no need to
+ * match
+ * table_index - Index into root table array
*
- * RETURN: 8 bit checksum of buffer
+ * RETURN: None
*
- * DESCRIPTION: Computes an 8 bit checksum of the table.
+ * DESCRIPTION: Install an ACPI table into the global data structure.
*
******************************************************************************/
-u8 acpi_tb_generate_checksum(struct acpi_table_header * table)
+void
+acpi_tb_install_table(acpi_physical_address address,
+ u8 flags, char *signature, acpi_native_uint table_index)
{
- u8 checksum;
+ struct acpi_table_header *table;
+
+ if (!address) {
+ ACPI_ERROR((AE_INFO,
+ "Null physical address for ACPI table [%s]",
+ signature));
+ return;
+ }
+
+ /* Map just the table header */
+
+ table = acpi_os_map_memory(address, sizeof(struct acpi_table_header));
+ if (!table) {
+ return;
+ }
+
+ /* If a particular signature is expected, signature must match */
+
+ if (signature && !ACPI_COMPARE_NAME(table->signature, signature)) {
+ ACPI_ERROR((AE_INFO,
+ "Invalid signature 0x%X for ACPI table [%s]",
+ *ACPI_CAST_PTR(u32, table->signature), signature));
+ goto unmap_and_exit;
+ }
- /* Sum the entire table as-is */
+ /* Initialize the table entry */
- checksum = acpi_tb_sum_table(table, table->length);
+ acpi_gbl_root_table_list.tables[table_index].address = address;
+ acpi_gbl_root_table_list.tables[table_index].length = table->length;
+ acpi_gbl_root_table_list.tables[table_index].flags = flags;
- /* Subtract off the existing checksum value in the table */
+ ACPI_MOVE_32_TO_32(&
+ (acpi_gbl_root_table_list.tables[table_index].
+ signature), table->signature);
- checksum = (u8) (checksum - table->checksum);
+ acpi_tb_print_table_header(address, table);
- /* Compute the final checksum */
+ if (table_index == ACPI_TABLE_INDEX_DSDT) {
- checksum = (u8) (0 - checksum);
- return (checksum);
+ /* Global integer width is based upon revision of the DSDT */
+
+ acpi_ut_set_integer_width(table->revision);
+ }
+
+ unmap_and_exit:
+ acpi_os_unmap_memory(table, sizeof(struct acpi_table_header));
}
/*******************************************************************************
*
- * FUNCTION: acpi_tb_set_checksum
+ * FUNCTION: acpi_tb_get_root_table_entry
*
- * PARAMETERS: Table - Pointer to a valid ACPI table (with a
- * standard ACPI header)
+ * PARAMETERS: table_entry - Pointer to the RSDT/XSDT table entry
+ * table_entry_size - sizeof 32 or 64 (RSDT or XSDT)
*
- * RETURN: None. Sets the table checksum field
+ * RETURN: Physical address extracted from the root table
*
- * DESCRIPTION: Computes an 8 bit checksum of the table and inserts the
- * checksum into the table header.
+ * DESCRIPTION: Get one root table entry. Handles 32-bit and 64-bit cases on
+ * both 32-bit and 64-bit platforms
+ *
+ * NOTE: acpi_physical_address is 32-bit on 32-bit platforms, 64-bit on
+ * 64-bit platforms.
*
******************************************************************************/
-void acpi_tb_set_checksum(struct acpi_table_header *table)
+static acpi_physical_address
+acpi_tb_get_root_table_entry(u8 * table_entry,
+ acpi_native_uint table_entry_size)
{
+ u64 address64;
+
+ /*
+ * Get the table physical address (32-bit for RSDT, 64-bit for XSDT):
+ * Note: Addresses are 32-bit aligned (not 64) in both RSDT and XSDT
+ */
+ if (table_entry_size == sizeof(u32)) {
+ /*
+ * 32-bit platform, RSDT: Return 32-bit table entry
+ * 64-bit platform, RSDT: Expand 32-bit to 64-bit and return
+ */
+ return ((acpi_physical_address)
+ (*ACPI_CAST_PTR(u32, table_entry)));
+ } else {
+ /*
+ * 32-bit platform, XSDT: Truncate 64-bit to 32-bit and return
+ * 64-bit platform, XSDT: Move (unaligned) 64-bit to local, return 64-bit
+ */
+ ACPI_MOVE_64_TO_64(&address64, table_entry);
- table->checksum = acpi_tb_generate_checksum(table);
+#if ACPI_MACHINE_WIDTH == 32
+ if (address64 > ACPI_UINT32_MAX) {
+
+ /* Will truncate 64-bit address to 32 bits, issue warning */
+
+ ACPI_WARNING((AE_INFO,
+ "64-bit Physical Address in XSDT is too large (%8.8X%8.8X), truncating",
+ ACPI_FORMAT_UINT64(address64)));
+ }
+#endif
+ return ((acpi_physical_address) (address64));
+ }
}
/*******************************************************************************
*
- * FUNCTION: acpi_tb_verify_table_checksum
+ * FUNCTION: acpi_tb_parse_root_table
+ *
+ * PARAMETERS: Rsdp - Pointer to the RSDP
+ * Flags - Flags
*
- * PARAMETERS: *table_header - ACPI table to verify
+ * RETURN: Status
*
- * RETURN: 8 bit checksum of table
+ * DESCRIPTION: This function is called to parse the Root System Description
+ * Table (RSDT or XSDT)
*
- * DESCRIPTION: Generates an 8 bit checksum of table and returns and compares
- * it to the existing checksum value.
+ * NOTE: Tables are mapped (not copied) for efficiency. The FACS must
+ * be mapped and cannot be copied because it contains the actual
+ * memory location of the ACPI Global Lock.
*
******************************************************************************/
-acpi_status
-acpi_tb_verify_table_checksum(struct acpi_table_header *table_header)
+acpi_status __init
+acpi_tb_parse_root_table(acpi_physical_address rsdp_address, u8 flags)
{
- u8 checksum;
+ struct acpi_table_rsdp *rsdp;
+ acpi_native_uint table_entry_size;
+ acpi_native_uint i;
+ u32 table_count;
+ struct acpi_table_header *table;
+ acpi_physical_address address;
+ u32 length;
+ u8 *table_entry;
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE(tb_parse_root_table);
+
+ /*
+ * Map the entire RSDP and extract the address of the RSDT or XSDT
+ */
+ rsdp = acpi_os_map_memory(rsdp_address, sizeof(struct acpi_table_rsdp));
+ if (!rsdp) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
+ }
- ACPI_FUNCTION_TRACE(tb_verify_table_checksum);
+ acpi_tb_print_table_header(rsdp_address,
+ ACPI_CAST_PTR(struct acpi_table_header,
+ rsdp));
- /* Compute the checksum on the table */
+ /* Differentiate between RSDT and XSDT root tables */
- checksum = acpi_tb_generate_checksum(table_header);
+ if (rsdp->revision > 1 && rsdp->xsdt_physical_address) {
+ /*
+ * Root table is an XSDT (64-bit physical addresses). We must use the
+ * XSDT if the revision is > 1 and the XSDT pointer is present, as per
+ * the ACPI specification.
+ */
+ address = (acpi_physical_address) rsdp->xsdt_physical_address;
+ table_entry_size = sizeof(u64);
+ } else {
+ /* Root table is an RSDT (32-bit physical addresses) */
- /* Checksum ok? */
+ address = (acpi_physical_address) rsdp->rsdt_physical_address;
+ table_entry_size = sizeof(u32);
+ }
- if (checksum == table_header->checksum) {
- return_ACPI_STATUS(AE_OK);
+ /*
+ * It is not possible to map more than one entry in some environments,
+ * so unmap the RSDP here before mapping other tables
+ */
+ acpi_os_unmap_memory(rsdp, sizeof(struct acpi_table_rsdp));
+
+ /* Map the RSDT/XSDT table header to get the full table length */
+
+ table = acpi_os_map_memory(address, sizeof(struct acpi_table_header));
+ if (!table) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
}
- ACPI_WARNING((AE_INFO,
- "Incorrect checksum in table [%4.4s] - is %2.2X, should be %2.2X",
- table_header->signature, table_header->checksum,
- checksum));
+ acpi_tb_print_table_header(address, table);
- return_ACPI_STATUS(AE_BAD_CHECKSUM);
-}
+ /* Get the length of the full table, verify length and map entire table */
-#ifdef ACPI_OBSOLETE_FUNCTIONS
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_handle_to_object
- *
- * PARAMETERS: table_id - Id for which the function is searching
- * table_desc - Pointer to return the matching table
- * descriptor.
- *
- * RETURN: Search the tables to find one with a matching table_id and
- * return a pointer to that table descriptor.
- *
- ******************************************************************************/
+ length = table->length;
+ acpi_os_unmap_memory(table, sizeof(struct acpi_table_header));
-acpi_status
-acpi_tb_handle_to_object(u16 table_id,
- struct acpi_table_desc **return_table_desc)
-{
- u32 i;
- struct acpi_table_desc *table_desc;
+ if (length < sizeof(struct acpi_table_header)) {
+ ACPI_ERROR((AE_INFO, "Invalid length 0x%X in RSDT/XSDT",
+ length));
+ return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH);
+ }
- ACPI_FUNCTION_NAME(tb_handle_to_object);
+ table = acpi_os_map_memory(address, length);
+ if (!table) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
+ }
+
+ /* Validate the root table checksum */
+
+ status = acpi_tb_verify_checksum(table, length);
+ if (ACPI_FAILURE(status)) {
+ acpi_os_unmap_memory(table, length);
+ return_ACPI_STATUS(status);
+ }
- for (i = 0; i < ACPI_TABLE_MAX; i++) {
- table_desc = acpi_gbl_table_lists[i].next;
- while (table_desc) {
- if (table_desc->table_id == table_id) {
- *return_table_desc = table_desc;
- return (AE_OK);
+ /* Calculate the number of tables described in the root table */
+
+ table_count =
+ (u32) ((table->length -
+ sizeof(struct acpi_table_header)) / table_entry_size);
+
+ /*
+ * First two entries in the table array are reserved for the DSDT and FACS,
+ * which are not actually present in the RSDT/XSDT - they come from the FADT
+ */
+ table_entry =
+ ACPI_CAST_PTR(u8, table) + sizeof(struct acpi_table_header);
+ acpi_gbl_root_table_list.count = 2;
+
+ /*
+ * Initialize the root table array from the RSDT/XSDT
+ */
+ for (i = 0; i < table_count; i++) {
+ if (acpi_gbl_root_table_list.count >=
+ acpi_gbl_root_table_list.size) {
+
+ /* There is no more room in the root table array, attempt resize */
+
+ status = acpi_tb_resize_root_table_list();
+ if (ACPI_FAILURE(status)) {
+ ACPI_WARNING((AE_INFO,
+ "Truncating %u table entries!",
+ (unsigned)
+ (acpi_gbl_root_table_list.size -
+ acpi_gbl_root_table_list.
+ count)));
+ break;
}
+ }
+
+ /* Get the table physical address (32-bit for RSDT, 64-bit for XSDT) */
- table_desc = table_desc->next;
+ acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list.count].
+ address =
+ acpi_tb_get_root_table_entry(table_entry, table_entry_size);
+
+ table_entry += table_entry_size;
+ acpi_gbl_root_table_list.count++;
+ }
+
+ /*
+ * It is not possible to map more than one entry in some environments,
+ * so unmap the root table here before mapping other tables
+ */
+ acpi_os_unmap_memory(table, length);
+
+ /*
+ * Complete the initialization of the root table array by examining
+ * the header of each table
+ */
+ for (i = 2; i < acpi_gbl_root_table_list.count; i++) {
+ acpi_tb_install_table(acpi_gbl_root_table_list.tables[i].
+ address, flags, NULL, i);
+
+ /* Special case for FADT - get the DSDT and FACS */
+
+ if (ACPI_COMPARE_NAME
+ (&acpi_gbl_root_table_list.tables[i].signature,
+ ACPI_SIG_FADT)) {
+ acpi_tb_parse_fadt(i, flags);
}
}
- ACPI_ERROR((AE_INFO, "TableId=%X does not exist", table_id));
- return (AE_BAD_PARAMETER);
+ return_ACPI_STATUS(AE_OK);
}
-#endif
diff --git a/drivers/acpi/tables/tbxface.c b/drivers/acpi/tables/tbxface.c
index 5ba9303293a..417ef5fa766 100644
--- a/drivers/acpi/tables/tbxface.c
+++ b/drivers/acpi/tables/tbxface.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -49,80 +49,158 @@
#define _COMPONENT ACPI_TABLES
ACPI_MODULE_NAME("tbxface")
+/* Local prototypes */
+static acpi_status acpi_tb_load_namespace(void);
+
/*******************************************************************************
*
- * FUNCTION: acpi_load_tables
+ * FUNCTION: acpi_allocate_root_table
*
- * PARAMETERS: None
+ * PARAMETERS: initial_table_count - Size of initial_table_array, in number of
+ * struct acpi_table_desc structures
*
* RETURN: Status
*
- * DESCRIPTION: This function is called to load the ACPI tables from the
- * provided RSDT
+ * DESCRIPTION: Allocate a root table array. Used by i_aSL compiler and
+ * acpi_initialize_tables.
*
******************************************************************************/
-acpi_status acpi_load_tables(void)
+
+acpi_status acpi_allocate_root_table(u32 initial_table_count)
{
- struct acpi_pointer rsdp_address;
- acpi_status status;
- ACPI_FUNCTION_TRACE(acpi_load_tables);
+ acpi_gbl_root_table_list.size = initial_table_count;
+ acpi_gbl_root_table_list.flags = ACPI_ROOT_ALLOW_RESIZE;
- /* Get the RSDP */
+ return (acpi_tb_resize_root_table_list());
+}
- status = acpi_os_get_root_pointer(ACPI_LOGICAL_ADDRESSING,
- &rsdp_address);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status, "Could not get the RSDP"));
- goto error_exit;
- }
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_initialize_tables
+ *
+ * PARAMETERS: initial_table_array - Pointer to an array of pre-allocated
+ * struct acpi_table_desc structures. If NULL, the
+ * array is dynamically allocated.
+ * initial_table_count - Size of initial_table_array, in number of
+ * struct acpi_table_desc structures
+ * allow_realloc - Flag to tell Table Manager if resize of
+ * pre-allocated array is allowed. Ignored
+ * if initial_table_array is NULL.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Initialize the table manager, get the RSDP and RSDT/XSDT.
+ *
+ * NOTE: Allows static allocation of the initial table array in order
+ * to avoid the use of dynamic memory in confined environments
+ * such as the kernel boot sequence where it may not be available.
+ *
+ * If the host OS memory managers are initialized, use NULL for
+ * initial_table_array, and the table will be dynamically allocated.
+ *
+ ******************************************************************************/
- /* Map and validate the RSDP */
+acpi_status __init
+acpi_initialize_tables(struct acpi_table_desc * initial_table_array,
+ u32 initial_table_count, u8 allow_resize)
+{
+ acpi_physical_address rsdp_address;
+ acpi_status status;
- acpi_gbl_table_flags = rsdp_address.pointer_type;
+ ACPI_FUNCTION_TRACE(acpi_initialize_tables);
- status = acpi_tb_verify_rsdp(&rsdp_address);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status, "During RSDP validation"));
- goto error_exit;
+ /*
+ * Set up the Root Table Array
+ * Allocate the table array if requested
+ */
+ if (!initial_table_array) {
+ status = acpi_allocate_root_table(initial_table_count);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+ } else {
+ /* Root Table Array has been statically allocated by the host */
+
+ ACPI_MEMSET(initial_table_array, 0,
+ initial_table_count *
+ sizeof(struct acpi_table_desc));
+
+ acpi_gbl_root_table_list.tables = initial_table_array;
+ acpi_gbl_root_table_list.size = initial_table_count;
+ acpi_gbl_root_table_list.flags = ACPI_ROOT_ORIGIN_UNKNOWN;
+ if (allow_resize) {
+ acpi_gbl_root_table_list.flags |=
+ ACPI_ROOT_ALLOW_RESIZE;
+ }
}
- /* Get the RSDT via the RSDP */
+ /* Get the address of the RSDP */
- status = acpi_tb_get_table_rsdt();
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status, "Could not load RSDT"));
- goto error_exit;
+ rsdp_address = acpi_os_get_root_pointer();
+ if (!rsdp_address) {
+ return_ACPI_STATUS(AE_NOT_FOUND);
}
- /* Now get the tables needed by this subsystem (FADT, DSDT, etc.) */
+ /*
+ * Get the root table (RSDT or XSDT) and extract all entries to the local
+ * Root Table Array. This array contains the information of the RSDT/XSDT
+ * in a common, more useable format.
+ */
+ status =
+ acpi_tb_parse_root_table(rsdp_address, ACPI_TABLE_ORIGIN_MAPPED);
+ return_ACPI_STATUS(status);
+}
- status = acpi_tb_get_required_tables();
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status,
- "Could not get all required tables (DSDT/FADT/FACS)"));
- goto error_exit;
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_reallocate_root_table
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Reallocate Root Table List into dynamic memory. Copies the
+ * root list from the previously provided scratch area. Should
+ * be called once dynamic memory allocation is available in the
+ * kernel
+ *
+ ******************************************************************************/
+acpi_status acpi_reallocate_root_table(void)
+{
+ struct acpi_table_desc *tables;
+ acpi_size new_size;
+
+ ACPI_FUNCTION_TRACE(acpi_reallocate_root_table);
+
+ /*
+ * Only reallocate the root table if the host provided a static buffer
+ * for the table array in the call to acpi_initialize_tables.
+ */
+ if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) {
+ return_ACPI_STATUS(AE_SUPPORT);
}
- ACPI_DEBUG_PRINT((ACPI_DB_INIT, "ACPI Tables successfully acquired\n"));
+ new_size =
+ (acpi_gbl_root_table_list.count +
+ ACPI_ROOT_TABLE_SIZE_INCREMENT) * sizeof(struct acpi_table_desc);
- /* Load the namespace from the tables */
+ /* Create new array and copy the old array */
- status = acpi_ns_load_namespace();
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status, "Could not load namespace"));
- goto error_exit;
+ tables = ACPI_ALLOCATE_ZEROED(new_size);
+ if (!tables) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
}
- return_ACPI_STATUS(AE_OK);
+ ACPI_MEMCPY(tables, acpi_gbl_root_table_list.tables, new_size);
- error_exit:
- ACPI_EXCEPTION((AE_INFO, status, "Could not load tables"));
- return_ACPI_STATUS(status);
-}
-
-ACPI_EXPORT_SYMBOL(acpi_load_tables)
+ acpi_gbl_root_table_list.size = acpi_gbl_root_table_list.count;
+ acpi_gbl_root_table_list.tables = tables;
+ acpi_gbl_root_table_list.flags =
+ ACPI_ROOT_ORIGIN_ALLOCATED | ACPI_ROOT_ALLOW_RESIZE;
+ return_ACPI_STATUS(AE_OK);
+}
/*******************************************************************************
*
* FUNCTION: acpi_load_table
@@ -141,342 +219,406 @@ ACPI_EXPORT_SYMBOL(acpi_load_tables)
acpi_status acpi_load_table(struct acpi_table_header *table_ptr)
{
acpi_status status;
- struct acpi_table_desc table_info;
- struct acpi_pointer address;
-
- ACPI_FUNCTION_TRACE(acpi_load_table);
-
- if (!table_ptr) {
- return_ACPI_STATUS(AE_BAD_PARAMETER);
- }
-
- /* Copy the table to a local buffer */
+ acpi_native_uint table_index;
+ struct acpi_table_desc table_desc;
- address.pointer_type = ACPI_LOGICAL_POINTER | ACPI_LOGICAL_ADDRESSING;
- address.pointer.logical = table_ptr;
-
- status = acpi_tb_get_table_body(&address, table_ptr, &table_info);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- /* Check signature for a valid table type */
-
- status = acpi_tb_recognize_table(&table_info, ACPI_TABLE_ALL);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
+ if (!table_ptr)
+ return AE_BAD_PARAMETER;
- /* Install the new table into the local data structures */
+ ACPI_MEMSET(&table_desc, 0, sizeof(struct acpi_table_desc));
+ table_desc.pointer = table_ptr;
+ table_desc.length = table_ptr->length;
+ table_desc.flags = ACPI_TABLE_ORIGIN_UNKNOWN;
- status = acpi_tb_install_table(&table_info);
+ /*
+ * Install the new table into the local data structures
+ */
+ status = acpi_tb_add_table(&table_desc, &table_index);
if (ACPI_FAILURE(status)) {
- if (status == AE_ALREADY_EXISTS) {
-
- /* Table already exists, no error */
-
- status = AE_OK;
- }
-
- /* Free table allocated by acpi_tb_get_table_body */
-
- acpi_tb_delete_single_table(&table_info);
- return_ACPI_STATUS(status);
+ return status;
}
+ status = acpi_ns_load_table(table_index, acpi_gbl_root_node);
+ return status;
+}
- /* Convert the table to common format if necessary */
-
- switch (table_info.type) {
- case ACPI_TABLE_ID_FADT:
-
- status = acpi_tb_convert_table_fadt();
- break;
-
- case ACPI_TABLE_ID_FACS:
+ACPI_EXPORT_SYMBOL(acpi_load_table)
- status = acpi_tb_build_common_facs(&table_info);
- break;
+/******************************************************************************
+ *
+ * FUNCTION: acpi_get_table_header
+ *
+ * PARAMETERS: Signature - ACPI signature of needed table
+ * Instance - Which instance (for SSDTs)
+ * out_table_header - The pointer to the table header to fill
+ *
+ * RETURN: Status and pointer to mapped table header
+ *
+ * DESCRIPTION: Finds an ACPI table header.
+ *
+ * NOTE: Caller is responsible in unmapping the header with
+ * acpi_os_unmap_memory
+ *
+ *****************************************************************************/
+acpi_status
+acpi_get_table_header(char *signature,
+ acpi_native_uint instance,
+ struct acpi_table_header *out_table_header)
+{
+ acpi_native_uint i;
+ acpi_native_uint j;
+ struct acpi_table_header *header;
- default:
- /* Load table into namespace if it contains executable AML */
+ /* Parameter validation */
- status =
- acpi_ns_load_table(table_info.installed_desc,
- acpi_gbl_root_node);
- break;
+ if (!signature || !out_table_header) {
+ return (AE_BAD_PARAMETER);
}
- if (ACPI_FAILURE(status)) {
+ /*
+ * Walk the root table list
+ */
+ for (i = 0, j = 0; i < acpi_gbl_root_table_list.count; i++) {
+ if (!ACPI_COMPARE_NAME
+ (&(acpi_gbl_root_table_list.tables[i].signature),
+ signature)) {
+ continue;
+ }
- /* Uninstall table and free the buffer */
+ if (++j < instance) {
+ continue;
+ }
- (void)acpi_tb_uninstall_table(table_info.installed_desc);
+ if (!acpi_gbl_root_table_list.tables[i].pointer) {
+ if ((acpi_gbl_root_table_list.tables[i].
+ flags & ACPI_TABLE_ORIGIN_MASK) ==
+ ACPI_TABLE_ORIGIN_MAPPED) {
+ header =
+ acpi_os_map_memory(acpi_gbl_root_table_list.
+ tables[i].address,
+ sizeof(struct
+ acpi_table_header));
+ if (!header) {
+ return AE_NO_MEMORY;
+ }
+ ACPI_MEMCPY(out_table_header, header,
+ sizeof(struct acpi_table_header));
+ acpi_os_unmap_memory(header,
+ sizeof(struct
+ acpi_table_header));
+ } else {
+ return AE_NOT_FOUND;
+ }
+ } else {
+ ACPI_MEMCPY(out_table_header,
+ acpi_gbl_root_table_list.tables[i].pointer,
+ sizeof(struct acpi_table_header));
+ }
+ return (AE_OK);
}
- return_ACPI_STATUS(status);
+ return (AE_NOT_FOUND);
}
-ACPI_EXPORT_SYMBOL(acpi_load_table)
+ACPI_EXPORT_SYMBOL(acpi_get_table_header)
-/*******************************************************************************
+
+/******************************************************************************
*
* FUNCTION: acpi_unload_table_id
*
- * PARAMETERS: table_type - Type of table to be unloaded
- * id - Owner ID of the table to be removed.
+ * PARAMETERS: id - Owner ID of the table to be removed.
*
* RETURN: Status
*
* DESCRIPTION: This routine is used to force the unload of a table (by id)
*
******************************************************************************/
-acpi_status acpi_unload_table_id(acpi_table_type table_type, acpi_owner_id id)
+acpi_status acpi_unload_table_id(acpi_owner_id id)
{
- struct acpi_table_desc *table_desc;
- acpi_status status;
-
- ACPI_FUNCTION_TRACE(acpi_unload_table);
-
- /* Parameter validation */
- if (table_type > ACPI_TABLE_ID_MAX)
- return_ACPI_STATUS(AE_BAD_PARAMETER);
-
- /* Find table from the requested type list */
- table_desc = acpi_gbl_table_lists[table_type].next;
- while (table_desc && table_desc->owner_id != id)
- table_desc = table_desc->next;
-
- if (!table_desc)
- return_ACPI_STATUS(AE_NOT_EXIST);
-
- /*
- * Delete all namespace objects owned by this table. Note that these
- * objects can appear anywhere in the namespace by virtue of the AML
- * "Scope" operator. Thus, we need to track ownership by an ID, not
- * simply a position within the hierarchy
- */
- acpi_ns_delete_namespace_by_owner(table_desc->owner_id);
-
- status = acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
- if (ACPI_FAILURE(status))
- return_ACPI_STATUS(status);
-
- (void)acpi_tb_uninstall_table(table_desc);
+ int i;
+ acpi_status status = AE_NOT_EXIST;
- (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+ ACPI_FUNCTION_TRACE(acpi_unload_table_id);
- return_ACPI_STATUS(AE_OK);
+ /* Find table in the global table list */
+ for (i = 0; i < acpi_gbl_root_table_list.count; ++i) {
+ if (id != acpi_gbl_root_table_list.tables[i].owner_id) {
+ continue;
+ }
+ /*
+ * Delete all namespace objects owned by this table. Note that these
+ * objects can appear anywhere in the namespace by virtue of the AML
+ * "Scope" operator. Thus, we need to track ownership by an ID, not
+ * simply a position within the hierarchy
+ */
+ acpi_tb_delete_namespace_by_owner(i);
+ status = acpi_tb_release_owner_id(i);
+ acpi_tb_set_table_loaded_flag(i, FALSE);
+ break;
+ }
+ return_ACPI_STATUS(status);
}
ACPI_EXPORT_SYMBOL(acpi_unload_table_id)
-#ifdef ACPI_FUTURE_USAGE
/*******************************************************************************
*
- * FUNCTION: acpi_unload_table
+ * FUNCTION: acpi_get_table
*
- * PARAMETERS: table_type - Type of table to be unloaded
+ * PARAMETERS: Signature - ACPI signature of needed table
+ * Instance - Which instance (for SSDTs)
+ * out_table - Where the pointer to the table is returned
*
- * RETURN: Status
+ * RETURN: Status and pointer to table
*
- * DESCRIPTION: This routine is used to force the unload of a table
+ * DESCRIPTION: Finds and verifies an ACPI table.
*
- ******************************************************************************/
-acpi_status acpi_unload_table(acpi_table_type table_type)
+ *****************************************************************************/
+acpi_status
+acpi_get_table(char *signature,
+ acpi_native_uint instance, struct acpi_table_header ** out_table)
{
- struct acpi_table_desc *table_desc;
-
- ACPI_FUNCTION_TRACE(acpi_unload_table);
+ acpi_native_uint i;
+ acpi_native_uint j;
+ acpi_status status;
/* Parameter validation */
- if (table_type > ACPI_TABLE_ID_MAX) {
- return_ACPI_STATUS(AE_BAD_PARAMETER);
+ if (!signature || !out_table) {
+ return (AE_BAD_PARAMETER);
}
- /* Find all tables of the requested type */
+ /*
+ * Walk the root table list
+ */
+ for (i = 0, j = 0; i < acpi_gbl_root_table_list.count; i++) {
+ if (!ACPI_COMPARE_NAME
+ (&(acpi_gbl_root_table_list.tables[i].signature),
+ signature)) {
+ continue;
+ }
- table_desc = acpi_gbl_table_lists[table_type].next;
- if (!table_desc) {
- return_ACPI_STATUS(AE_NOT_EXIST);
- }
+ if (++j < instance) {
+ continue;
+ }
- while (table_desc) {
- /*
- * Delete all namespace objects owned by this table. Note that these
- * objects can appear anywhere in the namespace by virtue of the AML
- * "Scope" operator. Thus, we need to track ownership by an ID, not
- * simply a position within the hierarchy
- */
- acpi_ns_delete_namespace_by_owner(table_desc->owner_id);
- table_desc = table_desc->next;
- }
+ status =
+ acpi_tb_verify_table(&acpi_gbl_root_table_list.tables[i]);
+ if (ACPI_SUCCESS(status)) {
+ *out_table = acpi_gbl_root_table_list.tables[i].pointer;
+ }
- /* Delete (or unmap) all tables of this type */
+ if (!acpi_gbl_permanent_mmap) {
+ acpi_gbl_root_table_list.tables[i].pointer = NULL;
+ }
- acpi_tb_delete_tables_by_type(table_type);
- return_ACPI_STATUS(AE_OK);
+ return (status);
+ }
+
+ return (AE_NOT_FOUND);
}
-ACPI_EXPORT_SYMBOL(acpi_unload_table)
+ACPI_EXPORT_SYMBOL(acpi_get_table)
/*******************************************************************************
*
- * FUNCTION: acpi_get_table_header
+ * FUNCTION: acpi_get_table_by_index
*
- * PARAMETERS: table_type - one of the defined table types
- * Instance - the non zero instance of the table, allows
- * support for multiple tables of the same type
- * see acpi_gbl_acpi_table_flag
- * out_table_header - pointer to the struct acpi_table_header if successful
+ * PARAMETERS: table_index - Table index
+ * Table - Where the pointer to the table is returned
*
- * DESCRIPTION: This function is called to get an ACPI table header. The caller
- * supplies an pointer to a data area sufficient to contain an ACPI
- * struct acpi_table_header structure.
+ * RETURN: Status and pointer to the table
*
- * The header contains a length field that can be used to determine
- * the size of the buffer needed to contain the entire table. This
- * function is not valid for the RSD PTR table since it does not
- * have a standard header and is fixed length.
+ * DESCRIPTION: Obtain a table by an index into the global table list.
*
******************************************************************************/
acpi_status
-acpi_get_table_header(acpi_table_type table_type,
- u32 instance, struct acpi_table_header *out_table_header)
+acpi_get_table_by_index(acpi_native_uint table_index,
+ struct acpi_table_header ** table)
{
- struct acpi_table_header *tbl_ptr;
acpi_status status;
- ACPI_FUNCTION_TRACE(acpi_get_table_header);
+ ACPI_FUNCTION_TRACE(acpi_get_table_by_index);
- if ((instance == 0) ||
- (table_type == ACPI_TABLE_ID_RSDP) || (!out_table_header)) {
+ /* Parameter validation */
+
+ if (!table) {
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
- /* Check the table type and instance */
+ (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+
+ /* Validate index */
- if ((table_type > ACPI_TABLE_ID_MAX) ||
- (ACPI_IS_SINGLE_TABLE(acpi_gbl_table_data[table_type].flags) &&
- instance > 1)) {
+ if (table_index >= acpi_gbl_root_table_list.count) {
+ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
- /* Get a pointer to the entire table */
-
- status = acpi_tb_get_table_ptr(table_type, instance, &tbl_ptr);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
+ if (!acpi_gbl_root_table_list.tables[table_index].pointer) {
- /* The function will return a NULL pointer if the table is not loaded */
+ /* Table is not mapped, map it */
- if (tbl_ptr == NULL) {
- return_ACPI_STATUS(AE_NOT_EXIST);
+ status =
+ acpi_tb_verify_table(&acpi_gbl_root_table_list.
+ tables[table_index]);
+ if (ACPI_FAILURE(status)) {
+ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+ return_ACPI_STATUS(status);
+ }
}
- /* Copy the header to the caller's buffer */
-
- ACPI_MEMCPY(ACPI_CAST_PTR(void, out_table_header),
- ACPI_CAST_PTR(void, tbl_ptr),
- sizeof(struct acpi_table_header));
-
- return_ACPI_STATUS(status);
+ *table = acpi_gbl_root_table_list.tables[table_index].pointer;
+ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+ return_ACPI_STATUS(AE_OK);
}
-ACPI_EXPORT_SYMBOL(acpi_get_table_header)
-#endif /* ACPI_FUTURE_USAGE */
+ACPI_EXPORT_SYMBOL(acpi_get_table_by_index)
/*******************************************************************************
*
- * FUNCTION: acpi_get_table
+ * FUNCTION: acpi_tb_load_namespace
*
- * PARAMETERS: table_type - one of the defined table types
- * Instance - the non zero instance of the table, allows
- * support for multiple tables of the same type
- * see acpi_gbl_acpi_table_flag
- * ret_buffer - pointer to a structure containing a buffer to
- * receive the table
+ * PARAMETERS: None
*
* RETURN: Status
*
- * DESCRIPTION: This function is called to get an ACPI table. The caller
- * supplies an out_buffer large enough to contain the entire ACPI
- * table. The caller should call the acpi_get_table_header function
- * first to determine the buffer size needed. Upon completion
- * the out_buffer->Length field will indicate the number of bytes
- * copied into the out_buffer->buf_ptr buffer. This table will be
- * a complete table including the header.
+ * DESCRIPTION: Load the namespace from the DSDT and all SSDTs/PSDTs found in
+ * the RSDT/XSDT.
*
******************************************************************************/
-acpi_status
-acpi_get_table(acpi_table_type table_type,
- u32 instance, struct acpi_buffer *ret_buffer)
+static acpi_status acpi_tb_load_namespace(void)
{
- struct acpi_table_header *tbl_ptr;
acpi_status status;
- acpi_size table_length;
+ struct acpi_table_header *table;
+ acpi_native_uint i;
- ACPI_FUNCTION_TRACE(acpi_get_table);
+ ACPI_FUNCTION_TRACE(tb_load_namespace);
- /* Parameter validation */
+ (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
- if (instance == 0) {
- return_ACPI_STATUS(AE_BAD_PARAMETER);
+ /*
+ * Load the namespace. The DSDT is required, but any SSDT and PSDT tables
+ * are optional.
+ */
+ if (!acpi_gbl_root_table_list.count ||
+ !ACPI_COMPARE_NAME(&
+ (acpi_gbl_root_table_list.
+ tables[ACPI_TABLE_INDEX_DSDT].signature),
+ ACPI_SIG_DSDT)
+ ||
+ ACPI_FAILURE(acpi_tb_verify_table
+ (&acpi_gbl_root_table_list.
+ tables[ACPI_TABLE_INDEX_DSDT]))) {
+ status = AE_NO_ACPI_TABLES;
+ goto unlock_and_exit;
}
- status = acpi_ut_validate_buffer(ret_buffer);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ /*
+ * Find DSDT table
+ */
+ status =
+ acpi_os_table_override(acpi_gbl_root_table_list.
+ tables[ACPI_TABLE_INDEX_DSDT].pointer,
+ &table);
+ if (ACPI_SUCCESS(status) && table) {
+ /*
+ * DSDT table has been found
+ */
+ acpi_tb_delete_table(&acpi_gbl_root_table_list.
+ tables[ACPI_TABLE_INDEX_DSDT]);
+ acpi_gbl_root_table_list.tables[ACPI_TABLE_INDEX_DSDT].pointer =
+ table;
+ acpi_gbl_root_table_list.tables[ACPI_TABLE_INDEX_DSDT].length =
+ table->length;
+ acpi_gbl_root_table_list.tables[ACPI_TABLE_INDEX_DSDT].flags =
+ ACPI_TABLE_ORIGIN_UNKNOWN;
+
+ ACPI_INFO((AE_INFO, "Table DSDT replaced by host OS"));
+ acpi_tb_print_table_header(0, table);
}
- /* Check the table type and instance */
+ status =
+ acpi_tb_verify_table(&acpi_gbl_root_table_list.
+ tables[ACPI_TABLE_INDEX_DSDT]);
+ if (ACPI_FAILURE(status)) {
- if ((table_type > ACPI_TABLE_ID_MAX) ||
- (ACPI_IS_SINGLE_TABLE(acpi_gbl_table_data[table_type].flags) &&
- instance > 1)) {
- return_ACPI_STATUS(AE_BAD_PARAMETER);
+ /* A valid DSDT is required */
+
+ status = AE_NO_ACPI_TABLES;
+ goto unlock_and_exit;
}
- /* Get a pointer to the entire table */
+ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
- status = acpi_tb_get_table_ptr(table_type, instance, &tbl_ptr);
+ /*
+ * Load and parse tables.
+ */
+ status = acpi_ns_load_table(ACPI_TABLE_INDEX_DSDT, acpi_gbl_root_node);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
/*
- * acpi_tb_get_table_ptr will return a NULL pointer if the
- * table is not loaded.
+ * Load any SSDT or PSDT tables. Note: Loop leaves tables locked
*/
- if (tbl_ptr == NULL) {
- return_ACPI_STATUS(AE_NOT_EXIST);
+ (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+ for (i = 0; i < acpi_gbl_root_table_list.count; ++i) {
+ if ((!ACPI_COMPARE_NAME
+ (&(acpi_gbl_root_table_list.tables[i].signature),
+ ACPI_SIG_SSDT)
+ &&
+ !ACPI_COMPARE_NAME(&
+ (acpi_gbl_root_table_list.tables[i].
+ signature), ACPI_SIG_PSDT))
+ ||
+ ACPI_FAILURE(acpi_tb_verify_table
+ (&acpi_gbl_root_table_list.tables[i]))) {
+ continue;
+ }
+
+ /* Ignore errors while loading tables, get as many as possible */
+
+ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+ (void)acpi_ns_load_table(i, acpi_gbl_root_node);
+ (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
}
- /* Get the table length */
+ ACPI_DEBUG_PRINT((ACPI_DB_INIT, "ACPI Tables successfully acquired\n"));
- if (table_type == ACPI_TABLE_ID_RSDP) {
+ unlock_and_exit:
+ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+ return_ACPI_STATUS(status);
+}
- /* RSD PTR is the only "table" without a header */
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_load_tables
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Load the ACPI tables from the RSDT/XSDT
+ *
+ ******************************************************************************/
- table_length = sizeof(struct rsdp_descriptor);
- } else {
- table_length = (acpi_size) tbl_ptr->length;
- }
+acpi_status acpi_load_tables(void)
+{
+ acpi_status status;
- /* Validate/Allocate/Clear caller buffer */
+ ACPI_FUNCTION_TRACE(acpi_load_tables);
- status = acpi_ut_initialize_buffer(ret_buffer, table_length);
+ /*
+ * Load the namespace from the tables
+ */
+ status = acpi_tb_load_namespace();
if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ ACPI_EXCEPTION((AE_INFO, status,
+ "While loading namespace from ACPI tables"));
}
- /* Copy the table to the buffer */
-
- ACPI_MEMCPY(ACPI_CAST_PTR(void, ret_buffer->pointer),
- ACPI_CAST_PTR(void, tbl_ptr), table_length);
-
- return_ACPI_STATUS(AE_OK);
+ return_ACPI_STATUS(status);
}
-ACPI_EXPORT_SYMBOL(acpi_get_table)
+ACPI_EXPORT_SYMBOL(acpi_load_tables)
diff --git a/drivers/acpi/tables/tbxfroot.c b/drivers/acpi/tables/tbxfroot.c
index da2648bbdbc..cf8fa514189 100644
--- a/drivers/acpi/tables/tbxfroot.c
+++ b/drivers/acpi/tables/tbxfroot.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -48,16 +48,15 @@
ACPI_MODULE_NAME("tbxfroot")
/* Local prototypes */
-static acpi_status
-acpi_tb_find_rsdp(struct acpi_table_desc *table_info, u32 flags);
-
static u8 *acpi_tb_scan_memory_for_rsdp(u8 * start_address, u32 length);
+static acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp);
+
/*******************************************************************************
*
* FUNCTION: acpi_tb_validate_rsdp
*
- * PARAMETERS: Rsdp - Pointer to unvalidated RSDP
+ * PARAMETERS: Rsdp - Pointer to unvalidated RSDP
*
* RETURN: Status
*
@@ -65,14 +64,18 @@ static u8 *acpi_tb_scan_memory_for_rsdp(u8 * start_address, u32 length);
*
******************************************************************************/
-acpi_status acpi_tb_validate_rsdp(struct rsdp_descriptor *rsdp)
+static acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp)
{
ACPI_FUNCTION_ENTRY();
/*
- * The signature and checksum must both be correct
+ * The signature and checksum must both be correct
+ *
+ * Note: Sometimes there exists more than one RSDP in memory; the valid
+ * RSDP has a valid checksum, all others have an invalid checksum.
*/
- if (ACPI_STRNCMP((char *)rsdp, RSDP_SIG, sizeof(RSDP_SIG) - 1) != 0) {
+ if (ACPI_STRNCMP((char *)rsdp, ACPI_SIG_RSDP, sizeof(ACPI_SIG_RSDP) - 1)
+ != 0) {
/* Nope, BAD Signature */
@@ -81,14 +84,14 @@ acpi_status acpi_tb_validate_rsdp(struct rsdp_descriptor *rsdp)
/* Check the standard checksum */
- if (acpi_tb_sum_table(rsdp, ACPI_RSDP_CHECKSUM_LENGTH) != 0) {
+ if (acpi_tb_checksum((u8 *) rsdp, ACPI_RSDP_CHECKSUM_LENGTH) != 0) {
return (AE_BAD_CHECKSUM);
}
/* Check extended checksum if table version >= 2 */
if ((rsdp->revision >= 2) &&
- (acpi_tb_sum_table(rsdp, ACPI_RSDP_XCHECKSUM_LENGTH) != 0)) {
+ (acpi_tb_checksum((u8 *) rsdp, ACPI_RSDP_XCHECKSUM_LENGTH) != 0)) {
return (AE_BAD_CHECKSUM);
}
@@ -97,314 +100,123 @@ acpi_status acpi_tb_validate_rsdp(struct rsdp_descriptor *rsdp)
/*******************************************************************************
*
- * FUNCTION: acpi_tb_find_table
- *
- * PARAMETERS: Signature - String with ACPI table signature
- * oem_id - String with the table OEM ID
- * oem_table_id - String with the OEM Table ID
- * table_ptr - Where the table pointer is returned
- *
- * RETURN: Status
+ * FUNCTION: acpi_tb_find_rsdp
*
- * DESCRIPTION: Find an ACPI table (in the RSDT/XSDT) that matches the
- * Signature, OEM ID and OEM Table ID.
+ * PARAMETERS: table_address - Where the table pointer is returned
*
- ******************************************************************************/
-
-acpi_status
-acpi_tb_find_table(char *signature,
- char *oem_id,
- char *oem_table_id, struct acpi_table_header ** table_ptr)
-{
- acpi_status status;
- struct acpi_table_header *table;
-
- ACPI_FUNCTION_TRACE(tb_find_table);
-
- /* Validate string lengths */
-
- if ((ACPI_STRLEN(signature) > ACPI_NAME_SIZE) ||
- (ACPI_STRLEN(oem_id) > sizeof(table->oem_id)) ||
- (ACPI_STRLEN(oem_table_id) > sizeof(table->oem_table_id))) {
- return_ACPI_STATUS(AE_AML_STRING_LIMIT);
- }
-
- if (ACPI_COMPARE_NAME(signature, DSDT_SIG)) {
- /*
- * The DSDT pointer is contained in the FADT, not the RSDT.
- * This code should suffice, because the only code that would perform
- * a "find" on the DSDT is the data_table_region() AML opcode -- in
- * which case, the DSDT is guaranteed to be already loaded.
- * If this becomes insufficient, the FADT will have to be found first.
- */
- if (!acpi_gbl_DSDT) {
- return_ACPI_STATUS(AE_NO_ACPI_TABLES);
- }
- table = acpi_gbl_DSDT;
- } else {
- /* Find the table */
-
- status = acpi_get_firmware_table(signature, 1,
- ACPI_LOGICAL_ADDRESSING,
- &table);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
- }
-
- /* Check oem_id and oem_table_id */
-
- if ((oem_id[0] &&
- ACPI_STRNCMP(oem_id, table->oem_id,
- sizeof(table->oem_id))) ||
- (oem_table_id[0] &&
- ACPI_STRNCMP(oem_table_id, table->oem_table_id,
- sizeof(table->oem_table_id)))) {
- return_ACPI_STATUS(AE_AML_NAME_NOT_FOUND);
- }
-
- ACPI_DEBUG_PRINT((ACPI_DB_TABLES, "Found table [%4.4s]\n",
- table->signature));
-
- *table_ptr = table;
- return_ACPI_STATUS(AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_get_firmware_table
+ * RETURN: Status, RSDP physical address
*
- * PARAMETERS: Signature - Any ACPI table signature
- * Instance - the non zero instance of the table, allows
- * support for multiple tables of the same type
- * Flags - Physical/Virtual support
- * table_pointer - Where a buffer containing the table is
- * returned
+ * DESCRIPTION: Search lower 1_mbyte of memory for the root system descriptor
+ * pointer structure. If it is found, set *RSDP to point to it.
*
- * RETURN: Status
+ * NOTE1: The RSDP must be either in the first 1_k of the Extended
+ * BIOS Data Area or between E0000 and FFFFF (From ACPI Spec.)
+ * Only a 32-bit physical address is necessary.
*
- * DESCRIPTION: This function is called to get an ACPI table. A buffer is
- * allocated for the table and returned in table_pointer.
- * This table will be a complete table including the header.
+ * NOTE2: This function is always available, regardless of the
+ * initialization state of the rest of ACPI.
*
******************************************************************************/
-acpi_status
-acpi_get_firmware_table(acpi_string signature,
- u32 instance,
- u32 flags, struct acpi_table_header **table_pointer)
+acpi_status acpi_find_root_pointer(acpi_native_uint * table_address)
{
- acpi_status status;
- struct acpi_pointer address;
- struct acpi_table_header *header = NULL;
- struct acpi_table_desc *table_info = NULL;
- struct acpi_table_desc *rsdt_info;
- u32 table_count;
- u32 i;
- u32 j;
-
- ACPI_FUNCTION_TRACE(acpi_get_firmware_table);
-
- /*
- * Ensure that at least the table manager is initialized. We don't
- * require that the entire ACPI subsystem is up for this interface.
- * If we have a buffer, we must have a length too
- */
- if ((instance == 0) || (!signature) || (!table_pointer)) {
- return_ACPI_STATUS(AE_BAD_PARAMETER);
- }
-
- /* Ensure that we have a RSDP */
-
- if (!acpi_gbl_RSDP) {
-
- /* Get the RSDP */
-
- status = acpi_os_get_root_pointer(flags, &address);
- if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "RSDP not found\n"));
- return_ACPI_STATUS(AE_NO_ACPI_TABLES);
- }
-
- /* Map and validate the RSDP */
-
- if ((flags & ACPI_MEMORY_MODE) == ACPI_LOGICAL_ADDRESSING) {
- status = acpi_os_map_memory(address.pointer.physical,
- sizeof(struct
- rsdp_descriptor),
- (void *)&acpi_gbl_RSDP);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
- } else {
- acpi_gbl_RSDP = address.pointer.logical;
- }
-
- /* The RDSP signature and checksum must both be correct */
-
- status = acpi_tb_validate_rsdp(acpi_gbl_RSDP);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
- }
-
- /* Get the RSDT address via the RSDP */
-
- acpi_tb_get_rsdt_address(&address);
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "RSDP located at %p, RSDT physical=%8.8X%8.8X\n",
- acpi_gbl_RSDP,
- ACPI_FORMAT_UINT64(address.pointer.value)));
+ u8 *table_ptr;
+ u8 *mem_rover;
+ u32 physical_address;
- /* Insert processor_mode flags */
+ ACPI_FUNCTION_TRACE(acpi_find_root_pointer);
- address.pointer_type |= flags;
+ /* 1a) Get the location of the Extended BIOS Data Area (EBDA) */
- /* Get and validate the RSDT */
+ table_ptr = acpi_os_map_memory((acpi_physical_address)
+ ACPI_EBDA_PTR_LOCATION,
+ ACPI_EBDA_PTR_LENGTH);
+ if (!table_ptr) {
+ ACPI_ERROR((AE_INFO,
+ "Could not map memory at %8.8X for length %X",
+ ACPI_EBDA_PTR_LOCATION, ACPI_EBDA_PTR_LENGTH));
- rsdt_info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_table_desc));
- if (!rsdt_info) {
return_ACPI_STATUS(AE_NO_MEMORY);
}
- status = acpi_tb_get_table(&address, rsdt_info);
- if (ACPI_FAILURE(status)) {
- goto cleanup;
- }
-
- status = acpi_tb_validate_rsdt(rsdt_info->pointer);
- if (ACPI_FAILURE(status)) {
- goto cleanup;
- }
+ ACPI_MOVE_16_TO_32(&physical_address, table_ptr);
- /* Allocate a scratch table header and table descriptor */
+ /* Convert segment part to physical address */
- header = ACPI_ALLOCATE(sizeof(struct acpi_table_header));
- if (!header) {
- status = AE_NO_MEMORY;
- goto cleanup;
- }
+ physical_address <<= 4;
+ acpi_os_unmap_memory(table_ptr, ACPI_EBDA_PTR_LENGTH);
- table_info = ACPI_ALLOCATE(sizeof(struct acpi_table_desc));
- if (!table_info) {
- status = AE_NO_MEMORY;
- goto cleanup;
- }
+ /* EBDA present? */
- /* Get the number of table pointers within the RSDT */
-
- table_count =
- acpi_tb_get_table_count(acpi_gbl_RSDP, rsdt_info->pointer);
- address.pointer_type = acpi_gbl_table_flags | flags;
-
- /*
- * Search the RSDT/XSDT for the correct instance of the
- * requested table
- */
- for (i = 0, j = 0; i < table_count; i++) {
+ if (physical_address > 0x400) {
/*
- * Get the next table pointer, handle RSDT vs. XSDT
- * RSDT pointers are 32 bits, XSDT pointers are 64 bits
+ * 1b) Search EBDA paragraphs (EBDA is required to be a
+ * minimum of 1_k length)
*/
- if (acpi_gbl_root_table_type == ACPI_TABLE_TYPE_RSDT) {
- address.pointer.value =
- (ACPI_CAST_PTR
- (struct rsdt_descriptor,
- rsdt_info->pointer))->table_offset_entry[i];
- } else {
- address.pointer.value =
- (ACPI_CAST_PTR
- (struct xsdt_descriptor,
- rsdt_info->pointer))->table_offset_entry[i];
- }
-
- /* Get the table header */
+ table_ptr = acpi_os_map_memory((acpi_native_uint)
+ physical_address,
+ ACPI_EBDA_WINDOW_SIZE);
+ if (!table_ptr) {
+ ACPI_ERROR((AE_INFO,
+ "Could not map memory at %8.8X for length %X",
+ physical_address, ACPI_EBDA_WINDOW_SIZE));
- status = acpi_tb_get_table_header(&address, header);
- if (ACPI_FAILURE(status)) {
- goto cleanup;
+ return_ACPI_STATUS(AE_NO_MEMORY);
}
- /* Compare table signatures and table instance */
-
- if (ACPI_COMPARE_NAME(header->signature, signature)) {
-
- /* An instance of the table was found */
+ mem_rover =
+ acpi_tb_scan_memory_for_rsdp(table_ptr,
+ ACPI_EBDA_WINDOW_SIZE);
+ acpi_os_unmap_memory(table_ptr, ACPI_EBDA_WINDOW_SIZE);
- j++;
- if (j >= instance) {
+ if (mem_rover) {
- /* Found the correct instance, get the entire table */
+ /* Return the physical address */
- status =
- acpi_tb_get_table_body(&address, header,
- table_info);
- if (ACPI_FAILURE(status)) {
- goto cleanup;
- }
+ physical_address +=
+ (u32) ACPI_PTR_DIFF(mem_rover, table_ptr);
- *table_pointer = table_info->pointer;
- goto cleanup;
- }
+ *table_address = physical_address;
+ return_ACPI_STATUS(AE_OK);
}
}
- /* Did not find the table */
+ /*
+ * 2) Search upper memory: 16-byte boundaries in E0000h-FFFFFh
+ */
+ table_ptr = acpi_os_map_memory((acpi_physical_address)
+ ACPI_HI_RSDP_WINDOW_BASE,
+ ACPI_HI_RSDP_WINDOW_SIZE);
- status = AE_NOT_EXIST;
+ if (!table_ptr) {
+ ACPI_ERROR((AE_INFO,
+ "Could not map memory at %8.8X for length %X",
+ ACPI_HI_RSDP_WINDOW_BASE,
+ ACPI_HI_RSDP_WINDOW_SIZE));
- cleanup:
- if (rsdt_info->pointer) {
- acpi_os_unmap_memory(rsdt_info->pointer,
- (acpi_size) rsdt_info->pointer->length);
+ return_ACPI_STATUS(AE_NO_MEMORY);
}
- ACPI_FREE(rsdt_info);
- if (header) {
- ACPI_FREE(header);
- }
- if (table_info) {
- ACPI_FREE(table_info);
- }
- return_ACPI_STATUS(status);
-}
+ mem_rover =
+ acpi_tb_scan_memory_for_rsdp(table_ptr, ACPI_HI_RSDP_WINDOW_SIZE);
+ acpi_os_unmap_memory(table_ptr, ACPI_HI_RSDP_WINDOW_SIZE);
-ACPI_EXPORT_SYMBOL(acpi_get_firmware_table)
+ if (mem_rover) {
-/* TBD: Move to a new file */
-#if ACPI_MACHINE_WIDTH != 16
-/*******************************************************************************
- *
- * FUNCTION: acpi_find_root_pointer
- *
- * PARAMETERS: Flags - Logical/Physical addressing
- * rsdp_address - Where to place the RSDP address
- *
- * RETURN: Status, Physical address of the RSDP
- *
- * DESCRIPTION: Find the RSDP
- *
- ******************************************************************************/
-acpi_status acpi_find_root_pointer(u32 flags, struct acpi_pointer *rsdp_address)
-{
- struct acpi_table_desc table_info;
- acpi_status status;
-
- ACPI_FUNCTION_TRACE(acpi_find_root_pointer);
-
- /* Get the RSDP */
+ /* Return the physical address */
- status = acpi_tb_find_rsdp(&table_info, flags);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status,
- "RSDP structure not found - Flags=%X", flags));
+ physical_address = (u32)
+ (ACPI_HI_RSDP_WINDOW_BASE +
+ ACPI_PTR_DIFF(mem_rover, table_ptr));
- return_ACPI_STATUS(AE_NO_ACPI_TABLES);
+ *table_address = physical_address;
+ return_ACPI_STATUS(AE_OK);
}
- rsdp_address->pointer_type = ACPI_PHYSICAL_POINTER;
- rsdp_address->pointer.physical = table_info.physical_address;
- return_ACPI_STATUS(AE_OK);
+ /* A valid RSDP was not found */
+
+ ACPI_ERROR((AE_INFO, "A valid RSDP was not found"));
+ return_ACPI_STATUS(AE_NOT_FOUND);
}
ACPI_EXPORT_SYMBOL(acpi_find_root_pointer)
@@ -440,7 +252,7 @@ static u8 *acpi_tb_scan_memory_for_rsdp(u8 * start_address, u32 length)
status =
acpi_tb_validate_rsdp(ACPI_CAST_PTR
- (struct rsdp_descriptor, mem_rover));
+ (struct acpi_table_rsdp, mem_rover));
if (ACPI_SUCCESS(status)) {
/* Sig and checksum valid, we have found a real RSDP */
@@ -461,189 +273,3 @@ static u8 *acpi_tb_scan_memory_for_rsdp(u8 * start_address, u32 length)
start_address));
return_PTR(NULL);
}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_find_rsdp
- *
- * PARAMETERS: table_info - Where the table info is returned
- * Flags - Current memory mode (logical vs.
- * physical addressing)
- *
- * RETURN: Status, RSDP physical address
- *
- * DESCRIPTION: Search lower 1_mbyte of memory for the root system descriptor
- * pointer structure. If it is found, set *RSDP to point to it.
- *
- * NOTE1: The RSDP must be either in the first 1_k of the Extended
- * BIOS Data Area or between E0000 and FFFFF (From ACPI Spec.)
- * Only a 32-bit physical address is necessary.
- *
- * NOTE2: This function is always available, regardless of the
- * initialization state of the rest of ACPI.
- *
- ******************************************************************************/
-
-static acpi_status
-acpi_tb_find_rsdp(struct acpi_table_desc *table_info, u32 flags)
-{
- u8 *table_ptr;
- u8 *mem_rover;
- u32 physical_address;
- acpi_status status;
-
- ACPI_FUNCTION_TRACE(tb_find_rsdp);
-
- /*
- * Scan supports either logical addressing or physical addressing
- */
- if ((flags & ACPI_MEMORY_MODE) == ACPI_LOGICAL_ADDRESSING) {
-
- /* 1a) Get the location of the Extended BIOS Data Area (EBDA) */
-
- status = acpi_os_map_memory((acpi_physical_address)
- ACPI_EBDA_PTR_LOCATION,
- ACPI_EBDA_PTR_LENGTH,
- (void *)&table_ptr);
- if (ACPI_FAILURE(status)) {
- ACPI_ERROR((AE_INFO,
- "Could not map memory at %8.8X for length %X",
- ACPI_EBDA_PTR_LOCATION,
- ACPI_EBDA_PTR_LENGTH));
-
- return_ACPI_STATUS(status);
- }
-
- ACPI_MOVE_16_TO_32(&physical_address, table_ptr);
-
- /* Convert segment part to physical address */
-
- physical_address <<= 4;
- acpi_os_unmap_memory(table_ptr, ACPI_EBDA_PTR_LENGTH);
-
- /* EBDA present? */
-
- if (physical_address > 0x400) {
- /*
- * 1b) Search EBDA paragraphs (EBDA is required to be a
- * minimum of 1_k length)
- */
- status = acpi_os_map_memory((acpi_physical_address)
- physical_address,
- ACPI_EBDA_WINDOW_SIZE,
- (void *)&table_ptr);
- if (ACPI_FAILURE(status)) {
- ACPI_ERROR((AE_INFO,
- "Could not map memory at %8.8X for length %X",
- physical_address,
- ACPI_EBDA_WINDOW_SIZE));
-
- return_ACPI_STATUS(status);
- }
-
- mem_rover = acpi_tb_scan_memory_for_rsdp(table_ptr,
- ACPI_EBDA_WINDOW_SIZE);
- acpi_os_unmap_memory(table_ptr, ACPI_EBDA_WINDOW_SIZE);
-
- if (mem_rover) {
-
- /* Return the physical address */
-
- physical_address +=
- (u32) ACPI_PTR_DIFF(mem_rover, table_ptr);
-
- table_info->physical_address =
- (acpi_physical_address) physical_address;
- return_ACPI_STATUS(AE_OK);
- }
- }
-
- /*
- * 2) Search upper memory: 16-byte boundaries in E0000h-FFFFFh
- */
- status = acpi_os_map_memory((acpi_physical_address)
- ACPI_HI_RSDP_WINDOW_BASE,
- ACPI_HI_RSDP_WINDOW_SIZE,
- (void *)&table_ptr);
-
- if (ACPI_FAILURE(status)) {
- ACPI_ERROR((AE_INFO,
- "Could not map memory at %8.8X for length %X",
- ACPI_HI_RSDP_WINDOW_BASE,
- ACPI_HI_RSDP_WINDOW_SIZE));
-
- return_ACPI_STATUS(status);
- }
-
- mem_rover =
- acpi_tb_scan_memory_for_rsdp(table_ptr,
- ACPI_HI_RSDP_WINDOW_SIZE);
- acpi_os_unmap_memory(table_ptr, ACPI_HI_RSDP_WINDOW_SIZE);
-
- if (mem_rover) {
-
- /* Return the physical address */
-
- physical_address = (u32)
- (ACPI_HI_RSDP_WINDOW_BASE +
- ACPI_PTR_DIFF(mem_rover, table_ptr));
-
- table_info->physical_address =
- (acpi_physical_address) physical_address;
- return_ACPI_STATUS(AE_OK);
- }
- }
-
- /*
- * Physical addressing
- */
- else {
- /* 1a) Get the location of the EBDA */
-
- ACPI_MOVE_16_TO_32(&physical_address, ACPI_EBDA_PTR_LOCATION);
- physical_address <<= 4; /* Convert segment to physical address */
-
- /* EBDA present? */
-
- if (physical_address > 0x400) {
- /*
- * 1b) Search EBDA paragraphs (EBDA is required to be a minimum of
- * 1_k length)
- */
- mem_rover =
- acpi_tb_scan_memory_for_rsdp(ACPI_PHYSADDR_TO_PTR
- (physical_address),
- ACPI_EBDA_WINDOW_SIZE);
- if (mem_rover) {
-
- /* Return the physical address */
-
- table_info->physical_address =
- ACPI_TO_INTEGER(mem_rover);
- return_ACPI_STATUS(AE_OK);
- }
- }
-
- /* 2) Search upper memory: 16-byte boundaries in E0000h-FFFFFh */
-
- mem_rover =
- acpi_tb_scan_memory_for_rsdp(ACPI_PHYSADDR_TO_PTR
- (ACPI_HI_RSDP_WINDOW_BASE),
- ACPI_HI_RSDP_WINDOW_SIZE);
- if (mem_rover) {
-
- /* Found it, return the physical address */
-
- table_info->physical_address =
- ACPI_TO_INTEGER(mem_rover);
- return_ACPI_STATUS(AE_OK);
- }
- }
-
- /* A valid RSDP was not found */
-
- ACPI_ERROR((AE_INFO, "No valid RSDP was found"));
- return_ACPI_STATUS(AE_NOT_FOUND);
-}
-
-#endif
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 40ddb4dd963..0ae8b9310cb 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -36,7 +36,8 @@
#include <linux/init.h>
#include <linux/types.h>
#include <linux/proc_fs.h>
-#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/jiffies.h>
#include <linux/kmod.h>
#include <linux/seq_file.h>
#include <asm/uaccess.h>
@@ -46,7 +47,6 @@
#define ACPI_THERMAL_COMPONENT 0x04000000
#define ACPI_THERMAL_CLASS "thermal_zone"
-#define ACPI_THERMAL_DRIVER_NAME "ACPI Thermal Zone Driver"
#define ACPI_THERMAL_DEVICE_NAME "Thermal Zone"
#define ACPI_THERMAL_FILE_STATE "state"
#define ACPI_THERMAL_FILE_TEMPERATURE "temperature"
@@ -70,10 +70,10 @@
#define CELSIUS_TO_KELVIN(t) ((t+273)*10)
#define _COMPONENT ACPI_THERMAL_COMPONENT
-ACPI_MODULE_NAME("acpi_thermal")
+ACPI_MODULE_NAME("thermal");
MODULE_AUTHOR("Paul Diefenbaugh");
-MODULE_DESCRIPTION(ACPI_THERMAL_DRIVER_NAME);
+MODULE_DESCRIPTION("ACPI Thermal Zone Driver");
MODULE_LICENSE("GPL");
static int tzp;
@@ -82,7 +82,7 @@ MODULE_PARM_DESC(tzp, "Thermal zone polling frequency, in 1/10 seconds.\n");
static int acpi_thermal_add(struct acpi_device *device);
static int acpi_thermal_remove(struct acpi_device *device, int type);
-static int acpi_thermal_resume(struct acpi_device *device, int state);
+static int acpi_thermal_resume(struct acpi_device *device);
static int acpi_thermal_state_open_fs(struct inode *inode, struct file *file);
static int acpi_thermal_temp_open_fs(struct inode *inode, struct file *file);
static int acpi_thermal_trip_open_fs(struct inode *inode, struct file *file);
@@ -98,7 +98,7 @@ static ssize_t acpi_thermal_write_polling(struct file *, const char __user *,
size_t, loff_t *);
static struct acpi_driver acpi_thermal_driver = {
- .name = ACPI_THERMAL_DRIVER_NAME,
+ .name = "thermal",
.class = ACPI_THERMAL_CLASS,
.ids = ACPI_THERMAL_HID,
.ops = {
@@ -269,7 +269,7 @@ static int acpi_thermal_set_polling(struct acpi_thermal *tz, int seconds)
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Polling frequency set to %lu seconds\n",
- tz->polling_frequency));
+ tz->polling_frequency/10));
return 0;
}
@@ -1353,31 +1353,35 @@ static int acpi_thermal_remove(struct acpi_device *device, int type)
return 0;
}
-static int acpi_thermal_resume(struct acpi_device *device, int state)
+static int acpi_thermal_resume(struct acpi_device *device)
{
struct acpi_thermal *tz = NULL;
- int i;
+ int i, j, power_state, result;
+
if (!device || !acpi_driver_data(device))
return -EINVAL;
tz = acpi_driver_data(device);
- acpi_thermal_get_temperature(tz);
-
for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
- if (tz->trips.active[i].flags.valid) {
- tz->temperature = tz->trips.active[i].temperature;
- tz->trips.active[i].flags.enabled = 0;
-
- acpi_thermal_active(tz);
-
- tz->state.active |= tz->trips.active[i].flags.enabled;
- tz->state.active_index = i;
+ if (!(&tz->trips.active[i]))
+ break;
+ if (!tz->trips.active[i].flags.valid)
+ break;
+ tz->trips.active[i].flags.enabled = 1;
+ for (j = 0; j < tz->trips.active[i].devices.count; j++) {
+ result = acpi_bus_get_power(tz->trips.active[i].devices.
+ handles[j], &power_state);
+ if (result || (power_state != ACPI_STATE_D0)) {
+ tz->trips.active[i].flags.enabled = 0;
+ break;
+ }
}
+ tz->state.active |= tz->trips.active[i].flags.enabled;
}
- acpi_thermal_check(tz);
+ acpi_thermal_check(tz);
return AE_OK;
}
diff --git a/drivers/acpi/toshiba_acpi.c b/drivers/acpi/toshiba_acpi.c
index d9b651ffcdc..3906d47b978 100644
--- a/drivers/acpi/toshiba_acpi.c
+++ b/drivers/acpi/toshiba_acpi.c
@@ -125,7 +125,7 @@ static int write_acpi_int(const char *methodName, int val)
union acpi_object in_objs[1];
acpi_status status;
- params.count = sizeof(in_objs) / sizeof(in_objs[0]);
+ params.count = ARRAY_SIZE(in_objs);
params.pointer = in_objs;
in_objs[0].type = ACPI_TYPE_INTEGER;
in_objs[0].integer.value = val;
@@ -315,7 +315,7 @@ static int set_lcd(int value)
static int set_lcd_status(struct backlight_device *bd)
{
- return set_lcd(bd->props->brightness);
+ return set_lcd(bd->props.brightness);
}
static unsigned long write_lcd(const char *buffer, unsigned long count)
@@ -533,11 +533,9 @@ static acpi_status __exit remove_device(void)
return AE_OK;
}
-static struct backlight_properties toshiba_backlight_data = {
- .owner = THIS_MODULE,
+static struct backlight_ops toshiba_backlight_data = {
.get_brightness = get_lcd,
.update_status = set_lcd_status,
- .max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1,
};
static void __exit toshiba_acpi_exit(void)
@@ -561,10 +559,6 @@ static int __init toshiba_acpi_init(void)
if (acpi_disabled)
return -ENODEV;
- if (!acpi_specific_hotkey_enabled) {
- printk(MY_INFO "Using generic hotkey driver\n");
- return -ENODEV;
- }
/* simple device detection: look for HCI method */
if (is_valid_acpi_path(METHOD_HCI_1))
method_hci = METHOD_HCI_1;
@@ -601,6 +595,7 @@ static int __init toshiba_acpi_init(void)
toshiba_backlight_device = NULL;
toshiba_acpi_exit();
}
+ toshiba_backlight_device->props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1;
return (ACPI_SUCCESS(status)) ? 0 : -ENODEV;
}
diff --git a/drivers/acpi/utilities/utalloc.c b/drivers/acpi/utilities/utalloc.c
index f6cbc0b1bfd..55a76480749 100644
--- a/drivers/acpi/utilities/utalloc.c
+++ b/drivers/acpi/utilities/utalloc.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -42,6 +42,7 @@
*/
#include <acpi/acpi.h>
+#include <acpi/acdebug.h>
#define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME("utalloc")
@@ -142,6 +143,14 @@ acpi_status acpi_ut_create_caches(void)
acpi_status acpi_ut_delete_caches(void)
{
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+ char buffer[7];
+
+ if (acpi_gbl_display_final_mem_stats) {
+ ACPI_STRCPY(buffer, "MEMORY");
+ acpi_db_display_statistics(buffer);
+ }
+#endif
(void)acpi_os_delete_cache(acpi_gbl_namespace_cache);
acpi_gbl_namespace_cache = NULL;
diff --git a/drivers/acpi/utilities/utcache.c b/drivers/acpi/utilities/utcache.c
index 1a1f8109159..870f6edeb5f 100644
--- a/drivers/acpi/utilities/utcache.c
+++ b/drivers/acpi/utilities/utcache.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -289,6 +289,14 @@ void *acpi_os_acquire_object(struct acpi_memory_list *cache)
ACPI_MEM_TRACKING(cache->total_allocated++);
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+ if ((cache->total_allocated - cache->total_freed) >
+ cache->max_occupied) {
+ cache->max_occupied =
+ cache->total_allocated - cache->total_freed;
+ }
+#endif
+
/* Avoid deadlock with ACPI_ALLOCATE_ZEROED */
status = acpi_ut_release_mutex(ACPI_MTX_CACHES);
diff --git a/drivers/acpi/utilities/utcopy.c b/drivers/acpi/utilities/utcopy.c
index 5e1a80d1bc3..84d529db0a6 100644
--- a/drivers/acpi/utilities/utcopy.c
+++ b/drivers/acpi/utilities/utcopy.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -719,6 +719,15 @@ acpi_ut_copy_simple_object(union acpi_operand_object *source_desc,
acpi_ut_add_reference(source_desc->reference.object);
break;
+ case ACPI_TYPE_REGION:
+ /*
+ * We copied the Region Handler, so we now must add a reference
+ */
+ if (dest_desc->region.handler) {
+ acpi_ut_add_reference(dest_desc->region.handler);
+ }
+ break;
+
default:
/* Nothing to do for other simple objects */
break;
diff --git a/drivers/acpi/utilities/utdebug.c b/drivers/acpi/utilities/utdebug.c
index 9e9054e155c..61ad4f2daee 100644
--- a/drivers/acpi/utilities/utdebug.c
+++ b/drivers/acpi/utilities/utdebug.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -181,8 +181,7 @@ acpi_ut_debug_print(u32 requested_debug_level,
if (ACPI_LV_THREADS & acpi_dbg_level) {
acpi_os_printf
("\n**** Context Switch from TID %lX to TID %lX ****\n\n",
- (unsigned long) acpi_gbl_prev_thread_id,
- (unsigned long) thread_id);
+ (unsigned long)acpi_gbl_prev_thread_id, (unsigned long)thread_id);
}
acpi_gbl_prev_thread_id = thread_id;
@@ -195,7 +194,7 @@ acpi_ut_debug_print(u32 requested_debug_level,
acpi_os_printf("%8s-%04ld ", module_name, line_number);
if (ACPI_LV_THREADS & acpi_dbg_level) {
- acpi_os_printf("[%04lX] ", thread_id);
+ acpi_os_printf("[%04lX] ", (unsigned long)thread_id);
}
acpi_os_printf("[%02ld] %-22.22s: ",
diff --git a/drivers/acpi/utilities/utdelete.c b/drivers/acpi/utilities/utdelete.c
index 9d3f1149ba2..673a0caa407 100644
--- a/drivers/acpi/utilities/utdelete.c
+++ b/drivers/acpi/utilities/utdelete.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -158,16 +158,19 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object)
"***** Mutex %p, OS Mutex %p\n",
object, object->mutex.os_mutex));
- if (object->mutex.os_mutex != ACPI_GLOBAL_LOCK) {
- acpi_ex_unlink_mutex(object);
- acpi_os_delete_mutex(object->mutex.os_mutex);
- } else {
- /* Global Lock "mutex" is actually a counting semaphore */
+ if (object->mutex.os_mutex == acpi_gbl_global_lock_mutex) {
+
+ /* Global Lock has extra semaphore */
(void)
acpi_os_delete_semaphore
(acpi_gbl_global_lock_semaphore);
acpi_gbl_global_lock_semaphore = NULL;
+
+ acpi_os_delete_mutex(object->mutex.os_mutex);
+ acpi_gbl_global_lock_mutex = NULL;
+ } else {
+ acpi_os_delete_mutex(object->mutex.os_mutex);
}
break;
diff --git a/drivers/acpi/utilities/uteval.c b/drivers/acpi/utilities/uteval.c
index d6d7121583c..13d5879cd98 100644
--- a/drivers/acpi/utilities/uteval.c
+++ b/drivers/acpi/utilities/uteval.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/utilities/utglobal.c b/drivers/acpi/utilities/utglobal.c
index 014030af8b5..af33358a964 100644
--- a/drivers/acpi/utilities/utglobal.c
+++ b/drivers/acpi/utilities/utglobal.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -46,89 +46,9 @@
#include <acpi/acpi.h>
#include <acpi/acnamesp.h>
+ACPI_EXPORT_SYMBOL(acpi_gbl_FADT)
#define _COMPONENT ACPI_UTILITIES
-ACPI_MODULE_NAME("utglobal")
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_format_exception
- *
- * PARAMETERS: Status - The acpi_status code to be formatted
- *
- * RETURN: A string containing the exception text. A valid pointer is
- * always returned.
- *
- * DESCRIPTION: This function translates an ACPI exception into an ASCII string.
- *
- ******************************************************************************/
-const char *acpi_format_exception(acpi_status status)
-{
- acpi_status sub_status;
- const char *exception = NULL;
-
- ACPI_FUNCTION_ENTRY();
-
- /*
- * Status is composed of two parts, a "type" and an actual code
- */
- sub_status = (status & ~AE_CODE_MASK);
-
- switch (status & AE_CODE_MASK) {
- case AE_CODE_ENVIRONMENTAL:
-
- if (sub_status <= AE_CODE_ENV_MAX) {
- exception = acpi_gbl_exception_names_env[sub_status];
- }
- break;
-
- case AE_CODE_PROGRAMMER:
-
- if (sub_status <= AE_CODE_PGM_MAX) {
- exception =
- acpi_gbl_exception_names_pgm[sub_status - 1];
- }
- break;
-
- case AE_CODE_ACPI_TABLES:
-
- if (sub_status <= AE_CODE_TBL_MAX) {
- exception =
- acpi_gbl_exception_names_tbl[sub_status - 1];
- }
- break;
-
- case AE_CODE_AML:
-
- if (sub_status <= AE_CODE_AML_MAX) {
- exception =
- acpi_gbl_exception_names_aml[sub_status - 1];
- }
- break;
-
- case AE_CODE_CONTROL:
-
- if (sub_status <= AE_CODE_CTRL_MAX) {
- exception =
- acpi_gbl_exception_names_ctrl[sub_status - 1];
- }
- break;
-
- default:
- break;
- }
-
- if (!exception) {
-
- /* Exception code was not recognized */
-
- ACPI_ERROR((AE_INFO,
- "Unknown exception code: 0x%8.8X", status));
-
- exception = "UNKNOWN_STATUS_CODE";
- }
-
- return (ACPI_CAST_PTR(const char, exception));
-}
+ ACPI_MODULE_NAME("utglobal")
/*******************************************************************************
*
@@ -163,8 +83,6 @@ u32 acpi_gbl_startup_flags = 0;
u8 acpi_gbl_shutdown = TRUE;
-const u8 acpi_gbl_decode_to8bit[8] = { 1, 2, 4, 8, 16, 32, 64, 128 };
-
const char *acpi_gbl_sleep_state_names[ACPI_S_STATE_COUNT] = {
"\\_S0_",
"\\_S1_",
@@ -183,10 +101,45 @@ const char *acpi_gbl_highest_dstate_names[4] = {
/*******************************************************************************
*
- * Namespace globals
+ * FUNCTION: acpi_format_exception
+ *
+ * PARAMETERS: Status - The acpi_status code to be formatted
+ *
+ * RETURN: A string containing the exception text. A valid pointer is
+ * always returned.
+ *
+ * DESCRIPTION: This function translates an ACPI exception into an ASCII string
+ * It is here instead of utxface.c so it is always present.
*
******************************************************************************/
+const char *acpi_format_exception(acpi_status status)
+{
+ const char *exception = NULL;
+
+ ACPI_FUNCTION_ENTRY();
+
+ exception = acpi_ut_validate_exception(status);
+ if (!exception) {
+
+ /* Exception code was not recognized */
+
+ ACPI_ERROR((AE_INFO,
+ "Unknown exception code: 0x%8.8X", status));
+
+ exception = "UNKNOWN_STATUS_CODE";
+ }
+
+ return (ACPI_CAST_PTR(const char, exception));
+}
+
+ACPI_EXPORT_SYMBOL(acpi_format_exception)
+
+/*******************************************************************************
+ *
+ * Namespace globals
+ *
+ ******************************************************************************/
/*
* Predefined ACPI Names (Built-in to the Interpreter)
*
@@ -280,53 +233,6 @@ char acpi_ut_hex_to_ascii_char(acpi_integer integer, u32 position)
return (acpi_gbl_hex_to_ascii[(integer >> position) & 0xF]);
}
-/*******************************************************************************
- *
- * Table name globals
- *
- * NOTE: This table includes ONLY the ACPI tables that the subsystem consumes.
- * it is NOT an exhaustive list of all possible ACPI tables. All ACPI tables
- * that are not used by the subsystem are simply ignored.
- *
- * Do NOT add any table to this list that is not consumed directly by this
- * subsystem (No MADT, ECDT, SBST, etc.)
- *
- ******************************************************************************/
-
-struct acpi_table_list acpi_gbl_table_lists[ACPI_TABLE_ID_MAX + 1];
-
-struct acpi_table_support acpi_gbl_table_data[ACPI_TABLE_ID_MAX + 1] = {
- /*********** Name, Signature, Global typed pointer Signature size, Type How many allowed?, Contains valid AML? */
-
- /* RSDP 0 */ {RSDP_NAME, RSDP_SIG, NULL, sizeof(RSDP_SIG) - 1,
- ACPI_TABLE_ROOT | ACPI_TABLE_SINGLE}
- ,
- /* DSDT 1 */ {DSDT_SIG, DSDT_SIG, (void *)&acpi_gbl_DSDT,
- sizeof(DSDT_SIG) - 1,
- ACPI_TABLE_SECONDARY | ACPI_TABLE_SINGLE |
- ACPI_TABLE_EXECUTABLE}
- ,
- /* FADT 2 */ {FADT_SIG, FADT_SIG, (void *)&acpi_gbl_FADT,
- sizeof(FADT_SIG) - 1,
- ACPI_TABLE_PRIMARY | ACPI_TABLE_SINGLE}
- ,
- /* FACS 3 */ {FACS_SIG, FACS_SIG, (void *)&acpi_gbl_FACS,
- sizeof(FACS_SIG) - 1,
- ACPI_TABLE_SECONDARY | ACPI_TABLE_SINGLE}
- ,
- /* PSDT 4 */ {PSDT_SIG, PSDT_SIG, NULL, sizeof(PSDT_SIG) - 1,
- ACPI_TABLE_PRIMARY | ACPI_TABLE_MULTIPLE |
- ACPI_TABLE_EXECUTABLE}
- ,
- /* SSDT 5 */ {SSDT_SIG, SSDT_SIG, NULL, sizeof(SSDT_SIG) - 1,
- ACPI_TABLE_PRIMARY | ACPI_TABLE_MULTIPLE |
- ACPI_TABLE_EXECUTABLE}
- ,
- /* XSDT 6 */ {XSDT_SIG, XSDT_SIG, NULL, sizeof(RSDT_SIG) - 1,
- ACPI_TABLE_ROOT | ACPI_TABLE_SINGLE}
- ,
-};
-
/******************************************************************************
*
* Event and Hardware globals
@@ -612,7 +518,7 @@ char *acpi_ut_get_node_name(void *object)
/* Name must be a valid ACPI name */
if (!acpi_ut_valid_acpi_name(node->name.integer)) {
- node->name.integer = acpi_ut_repair_name(node->name.integer);
+ node->name.integer = acpi_ut_repair_name(node->name.ascii);
}
/* Return the name */
@@ -751,13 +657,6 @@ void acpi_ut_init_globals(void)
return;
}
- /* ACPI table structure */
-
- for (i = 0; i < (ACPI_TABLE_ID_MAX + 1); i++) {
- acpi_gbl_table_lists[i].next = NULL;
- acpi_gbl_table_lists[i].count = 0;
- }
-
/* Mutex locked flags */
for (i = 0; i < ACPI_NUM_MUTEX; i++) {
@@ -773,6 +672,7 @@ void acpi_ut_init_globals(void)
/* GPE support */
+ acpi_gpe_count = 0;
acpi_gbl_gpe_xrupt_list_head = NULL;
acpi_gbl_gpe_fadt_blocks[0] = NULL;
acpi_gbl_gpe_fadt_blocks[1] = NULL;
@@ -784,25 +684,15 @@ void acpi_ut_init_globals(void)
acpi_gbl_exception_handler = NULL;
acpi_gbl_init_handler = NULL;
- /* Global "typed" ACPI table pointers */
-
- acpi_gbl_RSDP = NULL;
- acpi_gbl_XSDT = NULL;
- acpi_gbl_FACS = NULL;
- acpi_gbl_FADT = NULL;
- acpi_gbl_DSDT = NULL;
-
/* Global Lock support */
acpi_gbl_global_lock_semaphore = NULL;
+ acpi_gbl_global_lock_mutex = NULL;
acpi_gbl_global_lock_acquired = FALSE;
- acpi_gbl_global_lock_thread_count = 0;
acpi_gbl_global_lock_handle = 0;
/* Miscellaneous variables */
- acpi_gbl_table_flags = ACPI_PHYSICAL_POINTER;
- acpi_gbl_rsdp_original_location = 0;
acpi_gbl_cm_single_step = FALSE;
acpi_gbl_db_terminate_threads = FALSE;
acpi_gbl_shutdown = FALSE;
@@ -837,8 +727,13 @@ void acpi_ut_init_globals(void)
acpi_gbl_lowest_stack_pointer = ACPI_SIZE_MAX;
#endif
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+ acpi_gbl_display_final_mem_stats = FALSE;
+#endif
+
return_VOID;
}
ACPI_EXPORT_SYMBOL(acpi_dbg_level)
ACPI_EXPORT_SYMBOL(acpi_dbg_layer)
+ACPI_EXPORT_SYMBOL(acpi_gpe_count)
diff --git a/drivers/acpi/utilities/utinit.c b/drivers/acpi/utilities/utinit.c
index ff76055eb7d..ad3c0d0a5cf 100644
--- a/drivers/acpi/utilities/utinit.c
+++ b/drivers/acpi/utilities/utinit.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -44,119 +44,14 @@
#include <acpi/acpi.h>
#include <acpi/acnamesp.h>
#include <acpi/acevents.h>
+#include <acpi/actables.h>
#define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME("utinit")
/* Local prototypes */
-static void
-acpi_ut_fadt_register_error(char *register_name, u32 value, u8 offset);
-
static void acpi_ut_terminate(void);
-/*******************************************************************************
- *
- * FUNCTION: acpi_ut_fadt_register_error
- *
- * PARAMETERS: register_name - Pointer to string identifying register
- * Value - Actual register contents value
- * Offset - Byte offset in the FADT
- *
- * RETURN: AE_BAD_VALUE
- *
- * DESCRIPTION: Display failure message
- *
- ******************************************************************************/
-
-static void
-acpi_ut_fadt_register_error(char *register_name, u32 value, u8 offset)
-{
-
- ACPI_WARNING((AE_INFO,
- "Invalid FADT value %s=%X at offset %X FADT=%p",
- register_name, value, offset, acpi_gbl_FADT));
-}
-
-/******************************************************************************
- *
- * FUNCTION: acpi_ut_validate_fadt
- *
- * PARAMETERS: None
- *
- * RETURN: Status
- *
- * DESCRIPTION: Validate various ACPI registers in the FADT
- *
- ******************************************************************************/
-
-acpi_status acpi_ut_validate_fadt(void)
-{
-
- /*
- * Verify Fixed ACPI Description Table fields,
- * but don't abort on any problems, just display error
- */
- if (acpi_gbl_FADT->pm1_evt_len < 4) {
- acpi_ut_fadt_register_error("PM1_EVT_LEN",
- (u32) acpi_gbl_FADT->pm1_evt_len,
- ACPI_FADT_OFFSET(pm1_evt_len));
- }
-
- if (!acpi_gbl_FADT->pm1_cnt_len) {
- acpi_ut_fadt_register_error("PM1_CNT_LEN", 0,
- ACPI_FADT_OFFSET(pm1_cnt_len));
- }
-
- if (!acpi_gbl_FADT->xpm1a_evt_blk.address) {
- acpi_ut_fadt_register_error("X_PM1a_EVT_BLK", 0,
- ACPI_FADT_OFFSET(xpm1a_evt_blk.
- address));
- }
-
- if (!acpi_gbl_FADT->xpm1a_cnt_blk.address) {
- acpi_ut_fadt_register_error("X_PM1a_CNT_BLK", 0,
- ACPI_FADT_OFFSET(xpm1a_cnt_blk.
- address));
- }
-
- if (!acpi_gbl_FADT->xpm_tmr_blk.address) {
- acpi_ut_fadt_register_error("X_PM_TMR_BLK", 0,
- ACPI_FADT_OFFSET(xpm_tmr_blk.
- address));
- }
-
- if ((acpi_gbl_FADT->xpm2_cnt_blk.address &&
- !acpi_gbl_FADT->pm2_cnt_len)) {
- acpi_ut_fadt_register_error("PM2_CNT_LEN",
- (u32) acpi_gbl_FADT->pm2_cnt_len,
- ACPI_FADT_OFFSET(pm2_cnt_len));
- }
-
- if (acpi_gbl_FADT->pm_tm_len < 4) {
- acpi_ut_fadt_register_error("PM_TM_LEN",
- (u32) acpi_gbl_FADT->pm_tm_len,
- ACPI_FADT_OFFSET(pm_tm_len));
- }
-
- /* Length of GPE blocks must be a multiple of 2 */
-
- if (acpi_gbl_FADT->xgpe0_blk.address &&
- (acpi_gbl_FADT->gpe0_blk_len & 1)) {
- acpi_ut_fadt_register_error("(x)GPE0_BLK_LEN",
- (u32) acpi_gbl_FADT->gpe0_blk_len,
- ACPI_FADT_OFFSET(gpe0_blk_len));
- }
-
- if (acpi_gbl_FADT->xgpe1_blk.address &&
- (acpi_gbl_FADT->gpe1_blk_len & 1)) {
- acpi_ut_fadt_register_error("(x)GPE1_BLK_LEN",
- (u32) acpi_gbl_FADT->gpe1_blk_len,
- ACPI_FADT_OFFSET(gpe1_blk_len));
- }
-
- return (AE_OK);
-}
-
/******************************************************************************
*
* FUNCTION: acpi_ut_terminate
@@ -178,7 +73,6 @@ static void acpi_ut_terminate(void)
ACPI_FUNCTION_TRACE(ut_terminate);
- /* Free global tables, etc. */
/* Free global GPE blocks and related info structures */
gpe_xrupt_info = acpi_gbl_gpe_xrupt_list_head;
@@ -239,6 +133,10 @@ void acpi_ut_subsystem_shutdown(void)
acpi_ns_terminate();
+ /* Delete the ACPI tables */
+
+ acpi_tb_terminate();
+
/* Close the globals */
acpi_ut_terminate();
diff --git a/drivers/acpi/utilities/utmath.c b/drivers/acpi/utilities/utmath.c
index 19d74bedce2..0c56a0d20b2 100644
--- a/drivers/acpi/utilities/utmath.c
+++ b/drivers/acpi/utilities/utmath.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/utilities/utmisc.c b/drivers/acpi/utilities/utmisc.c
index 6d8a8211be9..50133fffe42 100644
--- a/drivers/acpi/utilities/utmisc.c
+++ b/drivers/acpi/utilities/utmisc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -51,6 +51,78 @@ ACPI_MODULE_NAME("utmisc")
/*******************************************************************************
*
+ * FUNCTION: acpi_ut_validate_exception
+ *
+ * PARAMETERS: Status - The acpi_status code to be formatted
+ *
+ * RETURN: A string containing the exception text. NULL if exception is
+ * not valid.
+ *
+ * DESCRIPTION: This function validates and translates an ACPI exception into
+ * an ASCII string.
+ *
+ ******************************************************************************/
+const char *acpi_ut_validate_exception(acpi_status status)
+{
+ acpi_status sub_status;
+ const char *exception = NULL;
+
+ ACPI_FUNCTION_ENTRY();
+
+ /*
+ * Status is composed of two parts, a "type" and an actual code
+ */
+ sub_status = (status & ~AE_CODE_MASK);
+
+ switch (status & AE_CODE_MASK) {
+ case AE_CODE_ENVIRONMENTAL:
+
+ if (sub_status <= AE_CODE_ENV_MAX) {
+ exception = acpi_gbl_exception_names_env[sub_status];
+ }
+ break;
+
+ case AE_CODE_PROGRAMMER:
+
+ if (sub_status <= AE_CODE_PGM_MAX) {
+ exception =
+ acpi_gbl_exception_names_pgm[sub_status - 1];
+ }
+ break;
+
+ case AE_CODE_ACPI_TABLES:
+
+ if (sub_status <= AE_CODE_TBL_MAX) {
+ exception =
+ acpi_gbl_exception_names_tbl[sub_status - 1];
+ }
+ break;
+
+ case AE_CODE_AML:
+
+ if (sub_status <= AE_CODE_AML_MAX) {
+ exception =
+ acpi_gbl_exception_names_aml[sub_status - 1];
+ }
+ break;
+
+ case AE_CODE_CONTROL:
+
+ if (sub_status <= AE_CODE_CTRL_MAX) {
+ exception =
+ acpi_gbl_exception_names_ctrl[sub_status - 1];
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return (ACPI_CAST_PTR(const char, exception));
+}
+
+/*******************************************************************************
+ *
* FUNCTION: acpi_ut_is_aml_table
*
* PARAMETERS: Table - An ACPI table
@@ -62,14 +134,15 @@ ACPI_MODULE_NAME("utmisc")
* data tables that do not contain AML code.
*
******************************************************************************/
+
u8 acpi_ut_is_aml_table(struct acpi_table_header *table)
{
/* These are the only tables that contain executable AML */
- if (ACPI_COMPARE_NAME(table->signature, DSDT_SIG) ||
- ACPI_COMPARE_NAME(table->signature, PSDT_SIG) ||
- ACPI_COMPARE_NAME(table->signature, SSDT_SIG)) {
+ if (ACPI_COMPARE_NAME(table->signature, ACPI_SIG_DSDT) ||
+ ACPI_COMPARE_NAME(table->signature, ACPI_SIG_PSDT) ||
+ ACPI_COMPARE_NAME(table->signature, ACPI_SIG_SSDT)) {
return (TRUE);
}
@@ -418,7 +491,7 @@ u32 acpi_ut_dword_byte_swap(u32 value)
void acpi_ut_set_integer_width(u8 revision)
{
- if (revision <= 1) {
+ if (revision < 2) {
/* 32-bit case */
@@ -582,26 +655,25 @@ u8 acpi_ut_valid_acpi_name(u32 name)
*
******************************************************************************/
-acpi_name acpi_ut_repair_name(acpi_name name)
+acpi_name acpi_ut_repair_name(char *name)
{
- char *name_ptr = ACPI_CAST_PTR(char, &name);
- char new_name[ACPI_NAME_SIZE];
acpi_native_uint i;
+ char new_name[ACPI_NAME_SIZE];
for (i = 0; i < ACPI_NAME_SIZE; i++) {
- new_name[i] = name_ptr[i];
+ new_name[i] = name[i];
/*
* Replace a bad character with something printable, yet technically
* still invalid. This prevents any collisions with existing "good"
* names in the namespace.
*/
- if (!acpi_ut_valid_acpi_char(name_ptr[i], i)) {
+ if (!acpi_ut_valid_acpi_char(name[i], i)) {
new_name[i] = '*';
}
}
- return (*ACPI_CAST_PTR(u32, new_name));
+ return (*(u32 *) new_name);
}
/*******************************************************************************
@@ -996,9 +1068,13 @@ acpi_ut_info(char *module_name, u32 line_number, char *format, ...)
{
va_list args;
- acpi_os_printf("ACPI (%s-%04d): ", module_name, line_number);
+ /*
+ * Removed module_name, line_number, and acpica version, not needed
+ * for info output
+ */
+ acpi_os_printf("ACPI: ");
va_start(args, format);
acpi_os_vprintf(format, args);
- acpi_os_printf(" [%X]\n", ACPI_CA_VERSION);
+ acpi_os_printf("\n");
}
diff --git a/drivers/acpi/utilities/utmutex.c b/drivers/acpi/utilities/utmutex.c
index 180e73ceb6e..cbad2ef5987 100644
--- a/drivers/acpi/utilities/utmutex.c
+++ b/drivers/acpi/utilities/utmutex.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/utilities/utobject.c b/drivers/acpi/utilities/utobject.c
index ba7d8ac702d..4696124759e 100644
--- a/drivers/acpi/utilities/utobject.c
+++ b/drivers/acpi/utilities/utobject.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/utilities/utresrc.c b/drivers/acpi/utilities/utresrc.c
index 5a2de92831d..e8fe1ba6cc2 100644
--- a/drivers/acpi/utilities/utresrc.c
+++ b/drivers/acpi/utilities/utresrc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/utilities/utstate.c b/drivers/acpi/utilities/utstate.c
index eaa13d05c85..edcaafad0a3 100644
--- a/drivers/acpi/utilities/utstate.c
+++ b/drivers/acpi/utilities/utstate.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/utilities/utxface.c b/drivers/acpi/utilities/utxface.c
index 3538f69c82a..de3276f4f46 100644
--- a/drivers/acpi/utilities/utxface.c
+++ b/drivers/acpi/utilities/utxface.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -67,6 +67,7 @@ acpi_status acpi_initialize_subsystem(void)
ACPI_FUNCTION_TRACE(acpi_initialize_subsystem);
+ acpi_gbl_startup_flags = ACPI_SUBSYSTEM_INITIALIZE;
ACPI_DEBUG_EXEC(acpi_ut_init_stack_ptr_trace());
/* Initialize the OS-Dependent layer */
@@ -127,20 +128,6 @@ acpi_status acpi_enable_subsystem(u32 flags)
ACPI_FUNCTION_TRACE(acpi_enable_subsystem);
- /*
- * We must initialize the hardware before we can enable ACPI.
- * The values from the FADT are validated here.
- */
- if (!(flags & ACPI_NO_HARDWARE_INIT)) {
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "[Init] Initializing ACPI hardware\n"));
-
- status = acpi_hw_initialize();
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
- }
-
/* Enable ACPI mode */
if (!(flags & ACPI_NO_ACPI_ENABLE)) {
@@ -398,7 +385,6 @@ acpi_status acpi_get_system_info(struct acpi_buffer * out_buffer)
{
struct acpi_system_info *info_ptr;
acpi_status status;
- u32 i;
ACPI_FUNCTION_TRACE(acpi_get_system_info);
@@ -431,9 +417,7 @@ acpi_status acpi_get_system_info(struct acpi_buffer * out_buffer)
/* Timer resolution - 24 or 32 bits */
- if (!acpi_gbl_FADT) {
- info_ptr->timer_resolution = 0;
- } else if (acpi_gbl_FADT->tmr_val_ext == 0) {
+ if (acpi_gbl_FADT.flags & ACPI_FADT_32BIT_TIMER) {
info_ptr->timer_resolution = 24;
} else {
info_ptr->timer_resolution = 32;
@@ -449,13 +433,6 @@ acpi_status acpi_get_system_info(struct acpi_buffer * out_buffer)
info_ptr->debug_layer = acpi_dbg_layer;
info_ptr->debug_level = acpi_dbg_level;
- /* Current status of the ACPI tables, per table type */
-
- info_ptr->num_table_types = ACPI_TABLE_ID_MAX + 1;
- for (i = 0; i < (ACPI_TABLE_ID_MAX + 1); i++) {
- info_ptr->table_info[i].count = acpi_gbl_table_lists[i].count;
- }
-
return_ACPI_STATUS(AE_OK);
}
diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c
index 68a809fa7b1..34f15757108 100644
--- a/drivers/acpi/utils.c
+++ b/drivers/acpi/utils.c
@@ -31,7 +31,7 @@
#include <acpi/acpi_drivers.h>
#define _COMPONENT ACPI_BUS_COMPONENT
-ACPI_MODULE_NAME("acpi_utils")
+ACPI_MODULE_NAME("utils");
/* --------------------------------------------------------------------------
Object Evaluation Helpers
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index 3d54680d033..0771b434feb 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -32,6 +32,7 @@
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
+#include <linux/backlight.h>
#include <asm/uaccess.h>
#include <acpi/acpi_bus.h>
@@ -39,7 +40,6 @@
#define ACPI_VIDEO_COMPONENT 0x08000000
#define ACPI_VIDEO_CLASS "video"
-#define ACPI_VIDEO_DRIVER_NAME "ACPI Video Driver"
#define ACPI_VIDEO_BUS_NAME "Video Bus"
#define ACPI_VIDEO_DEVICE_NAME "Video Device"
#define ACPI_VIDEO_NOTIFY_SWITCH 0x80
@@ -56,26 +56,30 @@
#define ACPI_VIDEO_HEAD_INVALID (~0u - 1)
#define ACPI_VIDEO_HEAD_END (~0u)
+#define MAX_NAME_LEN 20
+
+#define ACPI_VIDEO_DISPLAY_CRT 1
+#define ACPI_VIDEO_DISPLAY_TV 2
+#define ACPI_VIDEO_DISPLAY_DVI 3
+#define ACPI_VIDEO_DISPLAY_LCD 4
#define _COMPONENT ACPI_VIDEO_COMPONENT
-ACPI_MODULE_NAME("acpi_video")
+ACPI_MODULE_NAME("video");
- MODULE_AUTHOR("Bruno Ducrot");
-MODULE_DESCRIPTION(ACPI_VIDEO_DRIVER_NAME);
+MODULE_AUTHOR("Bruno Ducrot");
+MODULE_DESCRIPTION("ACPI Video Driver");
MODULE_LICENSE("GPL");
static int acpi_video_bus_add(struct acpi_device *device);
static int acpi_video_bus_remove(struct acpi_device *device, int type);
-static int acpi_video_bus_match(struct acpi_device *device,
- struct acpi_driver *driver);
static struct acpi_driver acpi_video_bus = {
- .name = ACPI_VIDEO_DRIVER_NAME,
+ .name = "video",
.class = ACPI_VIDEO_CLASS,
+ .ids = ACPI_VIDEO_HID,
.ops = {
.add = acpi_video_bus_add,
.remove = acpi_video_bus_remove,
- .match = acpi_video_bus_match,
},
};
@@ -133,20 +137,21 @@ struct acpi_video_device_flags {
u8 crt:1;
u8 lcd:1;
u8 tvout:1;
+ u8 dvi:1;
u8 bios:1;
u8 unknown:1;
- u8 reserved:3;
+ u8 reserved:2;
};
struct acpi_video_device_cap {
u8 _ADR:1; /*Return the unique ID */
u8 _BCL:1; /*Query list of brightness control levels supported */
u8 _BCM:1; /*Set the brightness level */
+ u8 _BQC:1; /* Get current brightness level */
u8 _DDC:1; /*Return the EDID for this device */
u8 _DCS:1; /*Return status of output device */
u8 _DGS:1; /*Query graphics state */
u8 _DSS:1; /*Device state set */
- u8 _reserved:1;
};
struct acpi_video_device_brightness {
@@ -163,6 +168,7 @@ struct acpi_video_device {
struct acpi_video_bus *video;
struct acpi_device *dev;
struct acpi_video_device_brightness *brightness;
+ struct backlight_device *backlight;
};
/* bus */
@@ -257,11 +263,40 @@ static void acpi_video_device_bind(struct acpi_video_bus *video,
struct acpi_video_device *device);
static int acpi_video_device_enumerate(struct acpi_video_bus *video);
static int acpi_video_switch_output(struct acpi_video_bus *video, int event);
+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 *level);
static int acpi_video_get_next_level(struct acpi_video_device *device,
u32 level_current, u32 event);
static void acpi_video_switch_brightness(struct acpi_video_device *device,
int event);
+/*backlight device sysfs support*/
+static int acpi_video_get_brightness(struct backlight_device *bd)
+{
+ unsigned long cur_level;
+ struct acpi_video_device *vd =
+ (struct acpi_video_device *)class_get_devdata(&bd->class_dev);
+ acpi_video_device_lcd_get_level_current(vd, &cur_level);
+ return (int) cur_level;
+}
+
+static int acpi_video_set_brightness(struct backlight_device *bd)
+{
+ int request_level = bd->props.brightness;
+ struct acpi_video_device *vd =
+ (struct acpi_video_device *)class_get_devdata(&bd->class_dev);
+ acpi_video_device_lcd_set_level(vd, request_level);
+ return 0;
+}
+
+static struct backlight_ops acpi_backlight_ops = {
+ .get_brightness = acpi_video_get_brightness,
+ .update_status = acpi_video_set_brightness,
+};
+
/* --------------------------------------------------------------------------
Video Management
-------------------------------------------------------------------------- */
@@ -499,6 +534,7 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
acpi_integer status;
acpi_handle h_dummy1;
int i;
+ u32 max_level = 0;
union acpi_object *obj = NULL;
struct acpi_video_device_brightness *br = NULL;
@@ -514,6 +550,8 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_BCM", &h_dummy1))) {
device->cap._BCM = 1;
}
+ if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle,"_BQC",&h_dummy1)))
+ device->cap._BQC = 1;
if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_DDC", &h_dummy1))) {
device->cap._DDC = 1;
}
@@ -550,6 +588,8 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
continue;
}
br->levels[count] = (u32) o->integer.value;
+ if (br->levels[count] > max_level)
+ max_level = br->levels[count];
count++;
}
out:
@@ -568,6 +608,24 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
kfree(obj);
+ if (device->cap._BCL && device->cap._BCM && device->cap._BQC){
+ unsigned long tmp;
+ static int count = 0;
+ char *name;
+ name = kzalloc(MAX_NAME_LEN, GFP_KERNEL);
+ if (!name)
+ return;
+
+ sprintf(name, "acpi_video%d", count++);
+ acpi_video_device_lcd_get_level_current(device, &tmp);
+ device->backlight = backlight_device_register(name,
+ NULL, device, &acpi_backlight_ops);
+ device->backlight->props.max_brightness = max_level;
+ device->backlight->props.brightness = (int)tmp;
+ backlight_update_status(device->backlight);
+
+ kfree(name);
+ }
return;
}
@@ -668,6 +726,8 @@ static int acpi_video_device_info_seq_show(struct seq_file *seq, void *offset)
seq_printf(seq, "LCD\n");
else if (dev->flags.tvout)
seq_printf(seq, "TVOUT\n");
+ else if (dev->flags.dvi)
+ seq_printf(seq, "DVI\n");
else
seq_printf(seq, "UNKNOWN\n");
@@ -1242,6 +1302,16 @@ static int acpi_video_bus_remove_fs(struct acpi_device *device)
-------------------------------------------------------------------------- */
/* device interface */
+static struct acpi_video_device_attrib*
+acpi_video_get_device_attr(struct acpi_video_bus *video, unsigned long device_id)
+{
+ int count;
+
+ for(count = 0; count < video->attached_count; count++)
+ if((video->attached_array[count].value.int_val & 0xffff) == device_id)
+ return &(video->attached_array[count].value.attrib);
+ return NULL;
+}
static int
acpi_video_bus_get_one_device(struct acpi_device *device,
@@ -1250,7 +1320,7 @@ acpi_video_bus_get_one_device(struct acpi_device *device,
unsigned long device_id;
int status;
struct acpi_video_device *data;
-
+ struct acpi_video_device_attrib* attribute;
if (!device || !video)
return -EINVAL;
@@ -1271,20 +1341,30 @@ acpi_video_bus_get_one_device(struct acpi_device *device,
data->video = video;
data->dev = device;
- switch (device_id & 0xffff) {
- case 0x0100:
- data->flags.crt = 1;
- break;
- case 0x0400:
- data->flags.lcd = 1;
- break;
- case 0x0200:
- data->flags.tvout = 1;
- break;
- default:
+ attribute = acpi_video_get_device_attr(video, device_id);
+
+ if((attribute != NULL) && attribute->device_id_scheme) {
+ switch (attribute->display_type) {
+ case ACPI_VIDEO_DISPLAY_CRT:
+ data->flags.crt = 1;
+ break;
+ case ACPI_VIDEO_DISPLAY_TV:
+ data->flags.tvout = 1;
+ break;
+ case ACPI_VIDEO_DISPLAY_DVI:
+ data->flags.dvi = 1;
+ break;
+ case ACPI_VIDEO_DISPLAY_LCD:
+ data->flags.lcd = 1;
+ break;
+ default:
+ data->flags.unknown = 1;
+ break;
+ }
+ if(attribute->bios_can_detect)
+ data->flags.bios = 1;
+ } else
data->flags.unknown = 1;
- break;
- }
acpi_video_device_bind(video, data);
acpi_video_device_find_cap(data);
@@ -1588,7 +1668,7 @@ static int acpi_video_bus_put_one_device(struct acpi_video_device *device)
status = acpi_remove_notify_handler(device->dev->handle,
ACPI_DEVICE_NOTIFY,
acpi_video_device_notify);
-
+ backlight_device_unregister(device->backlight);
return 0;
}
@@ -1790,39 +1870,6 @@ static int acpi_video_bus_remove(struct acpi_device *device, int type)
return 0;
}
-static int
-acpi_video_bus_match(struct acpi_device *device, struct acpi_driver *driver)
-{
- acpi_handle h_dummy1;
- acpi_handle h_dummy2;
- acpi_handle h_dummy3;
-
-
- if (!device || !driver)
- return -EINVAL;
-
- /* Since there is no HID, CID for ACPI Video drivers, we have
- * to check well known required nodes for each feature we support.
- */
-
- /* Does this device able to support video switching ? */
- if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy1)) &&
- ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy2)))
- return 0;
-
- /* Does this device able to retrieve a video ROM ? */
- if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy1)))
- return 0;
-
- /* Does this device able to configure which video head to be POSTed ? */
- if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_VPO", &h_dummy1)) &&
- ACPI_SUCCESS(acpi_get_handle(device->handle, "_GPD", &h_dummy2)) &&
- ACPI_SUCCESS(acpi_get_handle(device->handle, "_SPD", &h_dummy3)))
- return 0;
-
- return -ENODEV;
-}
-
static int __init acpi_video_init(void)
{
int result = 0;
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 1c94b43d2c9..4af0a4bb578 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -41,12 +41,12 @@ config SATA_SVW
If unsure, say N.
config ATA_PIIX
- tristate "Intel PIIX/ICH SATA support"
+ tristate "Intel ESB, ICH, PIIX3, PIIX4 PATA/SATA support"
depends on PCI
help
This option enables support for ICH5/6/7/8 Serial ATA
- and support for PATA on the Intel PIIX3/PIIX4/ICH series
- PATA host controllers.
+ and support for PATA on the Intel ESB/ICH/PIIX3/PIIX4 series
+ host controllers.
If unsure, say N.
@@ -116,11 +116,14 @@ config SATA_SIL24
If unsure, say N.
config SATA_SIS
- tristate "SiS 964/180 SATA support"
+ tristate "SiS 964/965/966/180 SATA support"
depends on PCI
+ select PATA_SIS
help
- This option enables support for SiS Serial ATA 964/180.
-
+ This option enables support for SiS Serial ATA on
+ SiS 964/965/966/180 and Parallel ATA on SiS 180.
+ The PATA support for SiS 180 requires additionally to
+ enable the PATA_SIS driver in the config.
If unsure, say N.
config SATA_ULI
@@ -147,11 +150,30 @@ config SATA_VITESSE
If unsure, say N.
+config SATA_INIC162X
+ tristate "Initio 162x SATA support (HIGHLY EXPERIMENTAL)"
+ depends on PCI && EXPERIMENTAL
+ help
+ This option enables support for Initio 162x Serial ATA.
+
config SATA_INTEL_COMBINED
bool
depends on IDE=y && !BLK_DEV_IDE_SATA && (SATA_AHCI || ATA_PIIX)
default y
+config SATA_ACPI
+ bool
+ depends on ACPI && PCI
+ default y
+ help
+ This option adds support for SATA-related ACPI objects.
+ These ACPI objects add the ability to retrieve taskfiles
+ from the ACPI BIOS and write them to the disk controller.
+ These objects may be related to performance, security,
+ power management, or other areas.
+ You can disable this at kernel boot time by using the
+ option libata.noacpi=1
+
config PATA_ALI
tristate "ALi PATA support (Experimental)"
depends on PCI && EXPERIMENTAL
@@ -296,7 +318,7 @@ config PATA_ISAPNP
If unsure, say N.
config PATA_IT821X
- tristate "IT821x PATA support (Experimental)"
+ tristate "IT8211/2 PATA support (Experimental)"
depends on PCI && EXPERIMENTAL
help
This option enables support for the ITE 8211 and 8212
@@ -305,6 +327,15 @@ config PATA_IT821X
If unsure, say N.
+config PATA_IT8213
+ tristate "IT8213 PATA support (Experimental)"
+ depends on PCI && EXPERIMENTAL
+ help
+ This option enables support for the ITE 821 PATA
+ controllers via the new ATA layer.
+
+ If unsure, say N.
+
config PATA_JMICRON
tristate "JMicron PATA support"
depends on PCI
@@ -341,6 +372,15 @@ config PATA_MARVELL
If unsure, say N.
+config PATA_MPC52xx
+ tristate "Freescale MPC52xx SoC internal IDE"
+ depends on PPC_MPC52xx
+ help
+ This option enables support for integrated IDE controller
+ of the Freescale MPC52xx SoC.
+
+ If unsure, say N.
+
config PATA_MPIIX
tristate "Intel PATA MPIIX support"
depends on PCI
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index bc3d81ae757..74298afbbaa 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_SATA_SX4) += sata_sx4.o
obj-$(CONFIG_SATA_NV) += sata_nv.o
obj-$(CONFIG_SATA_ULI) += sata_uli.o
obj-$(CONFIG_SATA_MV) += sata_mv.o
+obj-$(CONFIG_SATA_INIC162X) += sata_inic162x.o
obj-$(CONFIG_PDC_ADMA) += pdc_adma.o
obj-$(CONFIG_PATA_ALI) += pata_ali.o
@@ -33,11 +34,13 @@ obj-$(CONFIG_PATA_HPT3X2N) += pata_hpt3x2n.o
obj-$(CONFIG_PATA_HPT3X3) += pata_hpt3x3.o
obj-$(CONFIG_PATA_ISAPNP) += pata_isapnp.o
obj-$(CONFIG_PATA_IT821X) += pata_it821x.o
+obj-$(CONFIG_PATA_IT8213) += pata_it8213.o
obj-$(CONFIG_PATA_JMICRON) += pata_jmicron.o
obj-$(CONFIG_PATA_NETCELL) += pata_netcell.o
obj-$(CONFIG_PATA_NS87410) += pata_ns87410.o
obj-$(CONFIG_PATA_OPTI) += pata_opti.o
obj-$(CONFIG_PATA_OPTIDMA) += pata_optidma.o
+obj-$(CONFIG_PATA_MPC52xx) += pata_mpc52xx.o
obj-$(CONFIG_PATA_MARVELL) += pata_marvell.o
obj-$(CONFIG_PATA_MPIIX) += pata_mpiix.o
obj-$(CONFIG_PATA_OLDPIIX) += pata_oldpiix.o
@@ -63,4 +66,4 @@ obj-$(CONFIG_ATA_GENERIC) += ata_generic.o
obj-$(CONFIG_PATA_LEGACY) += pata_legacy.o
libata-objs := libata-core.o libata-scsi.o libata-sff.o libata-eh.o
-
+libata-$(CONFIG_SATA_ACPI) += libata-acpi.o
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 48616c6fee9..6a3543e0624 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -39,13 +39,11 @@
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
-#include <linux/sched.h>
#include <linux/dma-mapping.h>
#include <linux/device.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_cmnd.h>
#include <linux/libata.h>
-#include <asm/io.h>
#define DRV_NAME "ahci"
#define DRV_VERSION "2.0"
@@ -166,9 +164,6 @@ 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 */
- /* hpriv->flags bits */
- AHCI_FLAG_MSI = (1 << 0),
-
/* ap->flags bits */
AHCI_FLAG_NO_NCQ = (1 << 24),
AHCI_FLAG_IGN_IRQ_IF_ERR = (1 << 25), /* ignore IRQ_IF_ERR */
@@ -191,7 +186,6 @@ struct ahci_sg {
};
struct ahci_host_priv {
- unsigned long flags;
u32 cap; /* cache of HOST_CAP register */
u32 port_map; /* cache of HOST_PORTS_IMPL reg */
};
@@ -229,7 +223,6 @@ static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg);
static int ahci_port_resume(struct ata_port *ap);
static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
static int ahci_pci_device_resume(struct pci_dev *pdev);
-static void ahci_remove_one (struct pci_dev *pdev);
static struct scsi_host_template ahci_sht = {
.module = THIS_MODULE,
@@ -266,6 +259,8 @@ static const struct ata_port_operations ahci_ops = {
.irq_handler = ahci_interrupt,
.irq_clear = ahci_irq_clear,
+ .irq_on = ata_dummy_irq_on,
+ .irq_ack = ata_dummy_irq_ack,
.scr_read = ahci_scr_read,
.scr_write = ahci_scr_write,
@@ -297,6 +292,8 @@ static const struct ata_port_operations ahci_vt8251_ops = {
.irq_handler = ahci_interrupt,
.irq_clear = ahci_irq_clear,
+ .irq_on = ata_dummy_irq_on,
+ .irq_ack = ata_dummy_irq_ack,
.scr_read = ahci_scr_read,
.scr_write = ahci_scr_write,
@@ -431,7 +428,7 @@ static const struct pci_device_id ahci_pci_tbl[] = {
/* Generic, PCI class code for AHCI */
{ PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
- 0x010601, 0xffffff, board_ahci },
+ PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci },
{ } /* terminate list */
};
@@ -441,9 +438,9 @@ static struct pci_driver ahci_pci_driver = {
.name = DRV_NAME,
.id_table = ahci_pci_tbl,
.probe = ahci_init_one,
+ .remove = ata_pci_remove_one,
.suspend = ahci_pci_device_suspend,
.resume = ahci_pci_device_resume,
- .remove = ahci_remove_one,
};
@@ -452,16 +449,12 @@ static inline int ahci_nr_ports(u32 cap)
return (cap & 0x1f) + 1;
}
-static inline unsigned long ahci_port_base_ul (unsigned long base, unsigned int port)
+static inline void __iomem *ahci_port_base(void __iomem *base,
+ unsigned int port)
{
return base + 0x100 + (port * 0x80);
}
-static inline void __iomem *ahci_port_base (void __iomem *base, unsigned int port)
-{
- return (void __iomem *) ahci_port_base_ul((unsigned long)base, port);
-}
-
static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg_in)
{
unsigned int sc_reg;
@@ -475,7 +468,7 @@ static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg_in)
return 0xffffffffU;
}
- return readl((void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
+ return readl(ap->ioaddr.scr_addr + (sc_reg * 4));
}
@@ -493,7 +486,7 @@ static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg_in,
return;
}
- writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
+ writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
}
static void ahci_start_engine(void __iomem *port_mmio)
@@ -735,7 +728,7 @@ static void ahci_init_controller(void __iomem *mmio, struct pci_dev *pdev,
static unsigned int ahci_dev_classify(struct ata_port *ap)
{
- void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
+ void __iomem *port_mmio = ap->ioaddr.cmd_addr;
struct ata_taskfile tf;
u32 tmp;
@@ -763,7 +756,7 @@ static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
static int ahci_clo(struct ata_port *ap)
{
- void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
+ void __iomem *port_mmio = ap->ioaddr.cmd_addr;
struct ahci_host_priv *hpriv = ap->host->private_data;
u32 tmp;
@@ -785,7 +778,7 @@ static int ahci_clo(struct ata_port *ap)
static int ahci_softreset(struct ata_port *ap, unsigned int *class)
{
struct ahci_port_priv *pp = ap->private_data;
- void __iomem *mmio = ap->host->mmio_base;
+ void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
const u32 cmd_fis_len = 5; /* five dwords */
const char *reason = NULL;
@@ -893,7 +886,7 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class)
struct ahci_port_priv *pp = ap->private_data;
u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
struct ata_taskfile tf;
- void __iomem *mmio = ap->host->mmio_base;
+ void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
int rc;
@@ -921,7 +914,7 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class)
static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class)
{
- void __iomem *mmio = ap->host->mmio_base;
+ void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
int rc;
@@ -946,7 +939,7 @@ static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class)
static void ahci_postreset(struct ata_port *ap, unsigned int *class)
{
- void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
+ void __iomem *port_mmio = ap->ioaddr.cmd_addr;
u32 new_tmp, tmp;
ata_std_postreset(ap, class);
@@ -965,7 +958,7 @@ static void ahci_postreset(struct ata_port *ap, unsigned int *class)
static u8 ahci_check_status(struct ata_port *ap)
{
- void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr;
+ void __iomem *mmio = ap->ioaddr.cmd_addr;
return readl(mmio + PORT_TFDATA) & 0xFF;
}
@@ -1111,7 +1104,7 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
static void ahci_host_intr(struct ata_port *ap)
{
- void __iomem *mmio = ap->host->mmio_base;
+ void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
struct ata_eh_info *ehi = &ap->eh_info;
struct ahci_port_priv *pp = ap->private_data;
@@ -1173,7 +1166,7 @@ static void ahci_host_intr(struct ata_port *ap)
* dangerous, we need to know more about them. Print
* more of it.
*/
- const u32 *f = pp->rx_fis + RX_FIS_SDB;
+ const __le32 *f = pp->rx_fis + RX_FIS_SDB;
ata_port_printk(ap, KERN_INFO, "Spurious SDB FIS during NCQ "
"issue=0x%x SAct=0x%x FIS=%08x:%08x%s\n",
@@ -1209,7 +1202,7 @@ static irqreturn_t ahci_interrupt(int irq, void *dev_instance)
VPRINTK("ENTER\n");
hpriv = host->private_data;
- mmio = host->mmio_base;
+ mmio = host->iomap[AHCI_PCI_BAR];
/* sigh. 0xffffffff is a valid return from h/w */
irq_stat = readl(mmio + HOST_IRQ_STAT);
@@ -1254,7 +1247,7 @@ static irqreturn_t ahci_interrupt(int irq, void *dev_instance)
static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
- void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
+ void __iomem *port_mmio = ap->ioaddr.cmd_addr;
if (qc->tf.protocol == ATA_PROT_NCQ)
writel(1 << qc->tag, port_mmio + PORT_SCR_ACT);
@@ -1266,7 +1259,7 @@ static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
static void ahci_freeze(struct ata_port *ap)
{
- void __iomem *mmio = ap->host->mmio_base;
+ void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
/* turn IRQ off */
@@ -1275,7 +1268,7 @@ static void ahci_freeze(struct ata_port *ap)
static void ahci_thaw(struct ata_port *ap)
{
- void __iomem *mmio = ap->host->mmio_base;
+ void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
u32 tmp;
@@ -1290,7 +1283,7 @@ static void ahci_thaw(struct ata_port *ap)
static void ahci_error_handler(struct ata_port *ap)
{
- void __iomem *mmio = ap->host->mmio_base;
+ void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
@@ -1306,7 +1299,7 @@ static void ahci_error_handler(struct ata_port *ap)
static void ahci_vt8251_error_handler(struct ata_port *ap)
{
- void __iomem *mmio = ap->host->mmio_base;
+ void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
@@ -1323,7 +1316,7 @@ static void ahci_vt8251_error_handler(struct ata_port *ap)
static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
- void __iomem *mmio = ap->host->mmio_base;
+ void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
if (qc->flags & ATA_QCFLAG_FAILED)
@@ -1340,7 +1333,7 @@ static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg)
{
struct ahci_host_priv *hpriv = ap->host->private_data;
struct ahci_port_priv *pp = ap->private_data;
- void __iomem *mmio = ap->host->mmio_base;
+ void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
const char *emsg = NULL;
int rc;
@@ -1361,7 +1354,7 @@ static int ahci_port_resume(struct ata_port *ap)
{
struct ahci_port_priv *pp = ap->private_data;
struct ahci_host_priv *hpriv = ap->host->private_data;
- void __iomem *mmio = ap->host->mmio_base;
+ void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
ahci_power_up(port_mmio, hpriv->cap);
@@ -1373,7 +1366,7 @@ static int ahci_port_resume(struct ata_port *ap)
static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
{
struct ata_host *host = dev_get_drvdata(&pdev->dev);
- void __iomem *mmio = host->mmio_base;
+ void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
u32 ctl;
if (mesg.event == PM_EVENT_SUSPEND) {
@@ -1394,10 +1387,12 @@ static int ahci_pci_device_resume(struct pci_dev *pdev)
{
struct ata_host *host = dev_get_drvdata(&pdev->dev);
struct ahci_host_priv *hpriv = host->private_data;
- void __iomem *mmio = host->mmio_base;
+ void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
int rc;
- ata_pci_device_do_resume(pdev);
+ rc = ata_pci_device_do_resume(pdev);
+ if (rc)
+ return rc;
if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
rc = ahci_reset_controller(mmio, pdev);
@@ -1418,29 +1413,24 @@ static int ahci_port_start(struct ata_port *ap)
struct device *dev = ap->host->dev;
struct ahci_host_priv *hpriv = ap->host->private_data;
struct ahci_port_priv *pp;
- void __iomem *mmio = ap->host->mmio_base;
+ void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
void *mem;
dma_addr_t mem_dma;
int rc;
- pp = kmalloc(sizeof(*pp), GFP_KERNEL);
+ pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
if (!pp)
return -ENOMEM;
- memset(pp, 0, sizeof(*pp));
rc = ata_pad_alloc(ap, dev);
- if (rc) {
- kfree(pp);
+ if (rc)
return rc;
- }
- mem = dma_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma, GFP_KERNEL);
- if (!mem) {
- ata_pad_free(ap, dev);
- kfree(pp);
+ mem = dmam_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma,
+ GFP_KERNEL);
+ if (!mem)
return -ENOMEM;
- }
memset(mem, 0, AHCI_PORT_PRIV_DMA_SZ);
/*
@@ -1482,10 +1472,8 @@ static int ahci_port_start(struct ata_port *ap)
static void ahci_port_stop(struct ata_port *ap)
{
- struct device *dev = ap->host->dev;
struct ahci_host_priv *hpriv = ap->host->private_data;
- struct ahci_port_priv *pp = ap->private_data;
- void __iomem *mmio = ap->host->mmio_base;
+ void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
const char *emsg = NULL;
int rc;
@@ -1494,19 +1482,13 @@ static void ahci_port_stop(struct ata_port *ap)
rc = ahci_deinit_port(port_mmio, hpriv->cap, &emsg);
if (rc)
ata_port_printk(ap, KERN_WARNING, "%s (%d)\n", emsg, rc);
-
- ap->private_data = NULL;
- dma_free_coherent(dev, AHCI_PORT_PRIV_DMA_SZ,
- pp->cmd_slot, pp->cmd_slot_dma);
- ata_pad_free(ap, dev);
- kfree(pp);
}
-static void ahci_setup_port(struct ata_ioports *port, unsigned long base,
+static void ahci_setup_port(struct ata_ioports *port, void __iomem *base,
unsigned int port_idx)
{
VPRINTK("ENTER, base==0x%lx, port_idx %u\n", base, port_idx);
- base = ahci_port_base_ul(base, port_idx);
+ base = ahci_port_base(base, port_idx);
VPRINTK("base now==0x%lx\n", base);
port->cmd_addr = base;
@@ -1519,7 +1501,7 @@ static int ahci_host_init(struct ata_probe_ent *probe_ent)
{
struct ahci_host_priv *hpriv = probe_ent->private_data;
struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
- void __iomem *mmio = probe_ent->mmio_base;
+ void __iomem *mmio = probe_ent->iomap[AHCI_PCI_BAR];
unsigned int i, cap_n_ports, using_dac;
int rc;
@@ -1586,7 +1568,7 @@ static int ahci_host_init(struct ata_probe_ent *probe_ent)
}
for (i = 0; i < probe_ent->n_ports; i++)
- ahci_setup_port(&probe_ent->port[i], (unsigned long) mmio, i);
+ ahci_setup_port(&probe_ent->port[i], mmio, i);
ahci_init_controller(mmio, pdev, probe_ent->n_ports,
probe_ent->port_flags, hpriv);
@@ -1600,7 +1582,7 @@ static void ahci_print_info(struct ata_probe_ent *probe_ent)
{
struct ahci_host_priv *hpriv = probe_ent->private_data;
struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
- void __iomem *mmio = probe_ent->mmio_base;
+ void __iomem *mmio = probe_ent->iomap[AHCI_PCI_BAR];
u32 vers, cap, impl, speed;
const char *speed_s;
u16 cc;
@@ -1619,11 +1601,11 @@ static void ahci_print_info(struct ata_probe_ent *probe_ent)
speed_s = "?";
pci_read_config_word(pdev, 0x0a, &cc);
- if (cc == 0x0101)
+ if (cc == PCI_CLASS_STORAGE_IDE)
scc_s = "IDE";
- else if (cc == 0x0106)
+ else if (cc == PCI_CLASS_STORAGE_SATA)
scc_s = "SATA";
- else if (cc == 0x0104)
+ else if (cc == PCI_CLASS_STORAGE_RAID)
scc_s = "RAID";
else
scc_s = "unknown";
@@ -1667,15 +1649,13 @@ static void ahci_print_info(struct ata_probe_ent *probe_ent)
);
}
-static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version;
- struct ata_probe_ent *probe_ent = NULL;
- struct ahci_host_priv *hpriv;
- unsigned long base;
- void __iomem *mmio_base;
unsigned int board_idx = (unsigned int) ent->driver_data;
- int have_msi, pci_dev_busy = 0;
+ struct device *dev = &pdev->dev;
+ struct ata_probe_ent *probe_ent;
+ struct ahci_host_priv *hpriv;
int rc;
VPRINTK("ENTER\n");
@@ -1685,57 +1665,36 @@ static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
- /* JMicron-specific fixup: make sure we're in AHCI mode */
- /* This is protected from races with ata_jmicron by the pci probe
- locking */
if (pdev->vendor == PCI_VENDOR_ID_JMICRON) {
- /* AHCI enable, AHCI on function 0 */
- pci_write_config_byte(pdev, 0x41, 0xa1);
- /* Function 1 is the PATA controller */
+ /* Function 1 is the PATA controller except on the 368, where
+ we are not AHCI anyway */
if (PCI_FUNC(pdev->devfn))
return -ENODEV;
}
- rc = pci_enable_device(pdev);
+ rc = pcim_enable_device(pdev);
if (rc)
return rc;
- rc = pci_request_regions(pdev, DRV_NAME);
- if (rc) {
- pci_dev_busy = 1;
- goto err_out;
- }
+ rc = pcim_iomap_regions(pdev, 1 << AHCI_PCI_BAR, DRV_NAME);
+ if (rc == -EBUSY)
+ pcim_pin_device(pdev);
+ if (rc)
+ return rc;
- if (pci_enable_msi(pdev) == 0)
- have_msi = 1;
- else {
+ if (pci_enable_msi(pdev))
pci_intx(pdev, 1);
- have_msi = 0;
- }
- probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
- if (probe_ent == NULL) {
- rc = -ENOMEM;
- goto err_out_msi;
- }
+ probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL);
+ if (probe_ent == NULL)
+ return -ENOMEM;
- memset(probe_ent, 0, sizeof(*probe_ent));
probe_ent->dev = pci_dev_to_dev(pdev);
INIT_LIST_HEAD(&probe_ent->node);
- mmio_base = pci_iomap(pdev, AHCI_PCI_BAR, 0);
- if (mmio_base == NULL) {
- rc = -ENOMEM;
- goto err_out_free_ent;
- }
- base = (unsigned long) mmio_base;
-
- hpriv = kmalloc(sizeof(*hpriv), GFP_KERNEL);
- if (!hpriv) {
- rc = -ENOMEM;
- goto err_out_iounmap;
- }
- memset(hpriv, 0, sizeof(*hpriv));
+ hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
+ if (!hpriv)
+ return -ENOMEM;
probe_ent->sht = ahci_port_info[board_idx].sht;
probe_ent->port_flags = ahci_port_info[board_idx].flags;
@@ -1745,16 +1704,13 @@ static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
probe_ent->irq = pdev->irq;
probe_ent->irq_flags = IRQF_SHARED;
- probe_ent->mmio_base = mmio_base;
+ probe_ent->iomap = pcim_iomap_table(pdev);
probe_ent->private_data = hpriv;
- if (have_msi)
- hpriv->flags |= AHCI_FLAG_MSI;
-
/* initialize adapter */
rc = ahci_host_init(probe_ent);
if (rc)
- goto err_out_hpriv;
+ return rc;
if (!(probe_ent->port_flags & AHCI_FLAG_NO_NCQ) &&
(hpriv->cap & HOST_CAP_NCQ))
@@ -1762,62 +1718,11 @@ static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
ahci_print_info(probe_ent);
- /* FIXME: check ata_device_add return value */
- ata_device_add(probe_ent);
- kfree(probe_ent);
+ if (!ata_device_add(probe_ent))
+ return -ENODEV;
+ devm_kfree(dev, probe_ent);
return 0;
-
-err_out_hpriv:
- kfree(hpriv);
-err_out_iounmap:
- pci_iounmap(pdev, mmio_base);
-err_out_free_ent:
- kfree(probe_ent);
-err_out_msi:
- if (have_msi)
- pci_disable_msi(pdev);
- else
- pci_intx(pdev, 0);
- pci_release_regions(pdev);
-err_out:
- if (!pci_dev_busy)
- pci_disable_device(pdev);
- return rc;
-}
-
-static void ahci_remove_one (struct pci_dev *pdev)
-{
- struct device *dev = pci_dev_to_dev(pdev);
- struct ata_host *host = dev_get_drvdata(dev);
- struct ahci_host_priv *hpriv = host->private_data;
- unsigned int i;
- int have_msi;
-
- for (i = 0; i < host->n_ports; i++)
- ata_port_detach(host->ports[i]);
-
- have_msi = hpriv->flags & AHCI_FLAG_MSI;
- free_irq(host->irq, host);
-
- for (i = 0; i < host->n_ports; i++) {
- struct ata_port *ap = host->ports[i];
-
- ata_scsi_release(ap->scsi_host);
- scsi_host_put(ap->scsi_host);
- }
-
- kfree(hpriv);
- pci_iounmap(pdev, host->mmio_base);
- kfree(host);
-
- if (have_msi)
- pci_disable_msi(pdev);
- else
- pci_intx(pdev, 0);
- pci_release_regions(pdev);
- pci_disable_device(pdev);
- dev_set_drvdata(dev, NULL);
}
static int __init ahci_init(void)
diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c
index 24af56081b5..be66ea08da5 100644
--- a/drivers/ata/ata_generic.c
+++ b/drivers/ata/ata_generic.c
@@ -79,7 +79,7 @@ static int generic_set_mode(struct ata_port *ap, struct ata_device **unused)
/* Bits 5 and 6 indicate if DMA is active on master/slave */
if (ap->ioaddr.bmdma_addr)
- dma_enabled = inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+ dma_enabled = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
for (i = 0; i < ATA_MAX_DEVICES; i++) {
struct ata_device *dev = &ap->device[i];
@@ -138,7 +138,7 @@ static struct ata_port_operations generic_port_ops = {
.bmdma_stop = ata_bmdma_stop,
.bmdma_status = ata_bmdma_status,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
@@ -150,10 +150,10 @@ static struct ata_port_operations generic_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
static int all_generic_ide; /* Set to claim all devices */
diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c
index 47701b286f8..4d716c7347e 100644
--- a/drivers/ata/ata_piix.c
+++ b/drivers/ata/ata_piix.c
@@ -118,7 +118,7 @@ enum {
PIIX_80C_SEC = (1 << 7) | (1 << 6),
/* controller IDs */
- piix_pata_33 = 0, /* PIIX3 or 4 at 33Mhz */
+ piix_pata_33 = 0, /* PIIX4 at 33Mhz */
ich_pata_33 = 1, /* ICH up to UDMA 33 only */
ich_pata_66 = 2, /* ICH up to 66 Mhz */
ich_pata_100 = 3, /* ICH up to UDMA 100 */
@@ -128,6 +128,7 @@ enum {
ich6_sata_ahci = 7,
ich6m_sata_ahci = 8,
ich8_sata_ahci = 9,
+ piix_pata_mwdma = 10, /* PIIX3 MWDMA only */
/* constants for mapping table */
P0 = 0, /* port 0 */
@@ -153,7 +154,6 @@ struct piix_host_priv {
static int piix_init_one (struct pci_dev *pdev,
const struct pci_device_id *ent);
-static void piix_host_stop(struct ata_host *host);
static void piix_pata_error_handler(struct ata_port *ap);
static void ich_pata_error_handler(struct ata_port *ap);
static void piix_sata_error_handler(struct ata_port *ap);
@@ -164,7 +164,8 @@ static void ich_set_dmamode (struct ata_port *ap, struct ata_device *adev);
static unsigned int in_module_init = 1;
static const struct pci_device_id piix_pci_tbl[] = {
-#ifdef ATA_ENABLE_PATA
+ /* Intel PIIX3 for the 430HX etc */
+ { 0x8086, 0x7010, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix_pata_mwdma },
/* Intel PIIX4 for the 430TX/440BX/MX chipset: UDMA 33 */
/* Also PIIX4E (fn3 rev 2) and PIIX4M (fn3 rev 3) */
{ 0x8086, 0x7111, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix_pata_33 },
@@ -202,7 +203,6 @@ static const struct pci_device_id piix_pci_tbl[] = {
/* ICH7/7-R (i945, i975) UDMA 100*/
{ 0x8086, 0x27DF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_133 },
{ 0x8086, 0x269E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
-#endif
/* NOTE: The following PCI ids must be kept in sync with the
* list in drivers/pci/quirks.c.
@@ -297,7 +297,7 @@ static const struct ata_port_operations piix_pata_ops = {
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
@@ -306,10 +306,10 @@ static const struct ata_port_operations piix_pata_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = piix_host_stop,
};
static const struct ata_port_operations ich_pata_ops = {
@@ -330,7 +330,7 @@ static const struct ata_port_operations ich_pata_ops = {
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
@@ -339,10 +339,10 @@ static const struct ata_port_operations ich_pata_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = piix_host_stop,
};
static const struct ata_port_operations piix_sata_ops = {
@@ -360,7 +360,7 @@ static const struct ata_port_operations piix_sata_ops = {
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
@@ -369,10 +369,10 @@ static const struct ata_port_operations piix_sata_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = piix_host_stop,
};
static const struct piix_map_db ich5_map_db = {
@@ -441,7 +441,7 @@ static const struct piix_map_db *piix_map_db_table[] = {
};
static struct ata_port_info piix_port_info[] = {
- /* piix_pata_33: 0: PIIX3 or 4 at 33MHz */
+ /* piix_pata_33: 0: PIIX4 at 33MHz */
{
.sht = &piix_sht,
.flags = PIIX_PATA_FLAGS,
@@ -543,6 +543,14 @@ static struct ata_port_info piix_port_info[] = {
.port_ops = &piix_sata_ops,
},
+ /* piix_pata_mwdma: 10: PIIX3 MWDMA only */
+ {
+ .sht = &piix_sht,
+ .flags = PIIX_PATA_FLAGS,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x06, /* mwdma1-2 ?? CHECK 0 should be ok but slow */
+ .port_ops = &piix_pata_ops,
+ },
};
static struct pci_bits piix_enable_bits[] = {
@@ -569,6 +577,7 @@ struct ich_laptop {
static const struct ich_laptop ich_laptop[] = {
/* devid, subvendor, subdev */
{ 0x27DF, 0x0005, 0x0280 }, /* ICH7 on Acer 5602WLMi */
+ { 0x27DF, 0x1025, 0x0110 }, /* ICH7 on Acer 3682WLMi */
/* end marker */
{ 0, }
};
@@ -632,7 +641,7 @@ static int piix_pata_prereset(struct ata_port *ap)
if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->port_no]))
return -ENOENT;
-
+
ap->cbl = ATA_CBL_PATA40;
return ata_std_prereset(ap);
}
@@ -776,7 +785,7 @@ static void do_pata_set_dmamode (struct ata_port *ap, struct ata_device *adev, i
u16 master_data;
u8 speed = adev->dma_mode;
int devid = adev->devno + 2 * ap->port_no;
- u8 udma_enable;
+ u8 udma_enable = 0;
static const /* ISP RTC */
u8 timings[][2] = { { 0, 0 },
@@ -786,7 +795,8 @@ static void do_pata_set_dmamode (struct ata_port *ap, struct ata_device *adev, i
{ 2, 3 }, };
pci_read_config_word(dev, master_port, &master_data);
- pci_read_config_byte(dev, 0x48, &udma_enable);
+ if (ap->udma_mask)
+ pci_read_config_byte(dev, 0x48, &udma_enable);
if (speed >= XFER_UDMA_0) {
unsigned int udma = adev->dma_mode - XFER_UDMA_0;
@@ -1059,6 +1069,7 @@ static void __devinit piix_init_sata_map(struct pci_dev *pdev,
static int piix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version;
+ struct device *dev = &pdev->dev;
struct ata_port_info port_info[2];
struct ata_port_info *ppinfo[2] = { &port_info[0], &port_info[1] };
struct piix_host_priv *hpriv;
@@ -1072,7 +1083,7 @@ static int piix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
if (!in_module_init)
return -ENODEV;
- hpriv = kzalloc(sizeof(*hpriv), GFP_KERNEL);
+ hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
if (!hpriv)
return -ENOMEM;
@@ -1122,15 +1133,6 @@ static int piix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
return ata_pci_init_one(pdev, ppinfo, 2);
}
-static void piix_host_stop(struct ata_host *host)
-{
- struct piix_host_priv *hpriv = host->private_data;
-
- ata_host_stop(host);
-
- kfree(hpriv);
-}
-
static int __init piix_init(void)
{
int rc;
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c
new file mode 100644
index 00000000000..b4e8be5d292
--- /dev/null
+++ b/drivers/ata/libata-acpi.c
@@ -0,0 +1,698 @@
+/*
+ * libata-acpi.c
+ * Provides ACPI support for PATA/SATA.
+ *
+ * Copyright (C) 2006 Intel Corp.
+ * Copyright (C) 2006 Randy Dunlap
+ */
+
+#include <linux/ata.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/acpi.h>
+#include <linux/libata.h>
+#include <linux/pci.h>
+#include "libata.h"
+
+#include <acpi/acpi_bus.h>
+#include <acpi/acnames.h>
+#include <acpi/acnamesp.h>
+#include <acpi/acparser.h>
+#include <acpi/acexcep.h>
+#include <acpi/acmacros.h>
+#include <acpi/actypes.h>
+
+#define SATA_ROOT_PORT(x) (((x) >> 16) & 0xffff)
+#define SATA_PORT_NUMBER(x) ((x) & 0xffff) /* or NO_PORT_MULT */
+#define NO_PORT_MULT 0xffff
+#define SATA_ADR_RSVD 0xffffffff
+
+#define REGS_PER_GTF 7
+struct taskfile_array {
+ u8 tfa[REGS_PER_GTF]; /* regs. 0x1f1 - 0x1f7 */
+};
+
+
+/**
+ * sata_get_dev_handle - finds acpi_handle and PCI device.function
+ * @dev: device to locate
+ * @handle: returned acpi_handle for @dev
+ * @pcidevfn: return PCI device.func for @dev
+ *
+ * This function is somewhat SATA-specific. Or at least the
+ * PATA & SATA versions of this function are different,
+ * so it's not entirely generic code.
+ *
+ * Returns 0 on success, <0 on error.
+ */
+static int sata_get_dev_handle(struct device *dev, acpi_handle *handle,
+ acpi_integer *pcidevfn)
+{
+ struct pci_dev *pci_dev;
+ acpi_integer addr;
+
+ pci_dev = to_pci_dev(dev); /* NOTE: PCI-specific */
+ /* Please refer to the ACPI spec for the syntax of _ADR. */
+ addr = (PCI_SLOT(pci_dev->devfn) << 16) | PCI_FUNC(pci_dev->devfn);
+ *pcidevfn = addr;
+ *handle = acpi_get_child(DEVICE_ACPI_HANDLE(dev->parent), addr);
+ if (!*handle)
+ return -ENODEV;
+ return 0;
+}
+
+/**
+ * pata_get_dev_handle - finds acpi_handle and PCI device.function
+ * @dev: device to locate
+ * @handle: returned acpi_handle for @dev
+ * @pcidevfn: return PCI device.func for @dev
+ *
+ * The PATA and SATA versions of this function are different.
+ *
+ * Returns 0 on success, <0 on error.
+ */
+static int pata_get_dev_handle(struct device *dev, acpi_handle *handle,
+ acpi_integer *pcidevfn)
+{
+ unsigned int bus, devnum, func;
+ acpi_integer addr;
+ acpi_handle dev_handle, parent_handle;
+ struct acpi_buffer buffer = {.length = ACPI_ALLOCATE_BUFFER,
+ .pointer = NULL};
+ acpi_status status;
+ struct acpi_device_info *dinfo = NULL;
+ int ret = -ENODEV;
+ struct pci_dev *pdev = to_pci_dev(dev);
+
+ bus = pdev->bus->number;
+ devnum = PCI_SLOT(pdev->devfn);
+ func = PCI_FUNC(pdev->devfn);
+
+ dev_handle = DEVICE_ACPI_HANDLE(dev);
+ parent_handle = DEVICE_ACPI_HANDLE(dev->parent);
+
+ status = acpi_get_object_info(parent_handle, &buffer);
+ if (ACPI_FAILURE(status))
+ goto err;
+
+ dinfo = buffer.pointer;
+ if (dinfo && (dinfo->valid & ACPI_VALID_ADR) &&
+ dinfo->address == bus) {
+ /* ACPI spec for _ADR for PCI bus: */
+ addr = (acpi_integer)(devnum << 16 | func);
+ *pcidevfn = addr;
+ *handle = dev_handle;
+ } else {
+ goto err;
+ }
+
+ if (!*handle)
+ goto err;
+ ret = 0;
+err:
+ kfree(dinfo);
+ return ret;
+}
+
+struct walk_info { /* can be trimmed some */
+ struct device *dev;
+ struct acpi_device *adev;
+ acpi_handle handle;
+ acpi_integer pcidevfn;
+ unsigned int drivenum;
+ acpi_handle obj_handle;
+ struct ata_port *ataport;
+ struct ata_device *atadev;
+ u32 sata_adr;
+ int status;
+ char basepath[ACPI_PATHNAME_MAX];
+ int basepath_len;
+};
+
+static acpi_status get_devices(acpi_handle handle,
+ u32 level, void *context, void **return_value)
+{
+ acpi_status status;
+ struct walk_info *winfo = context;
+ struct acpi_buffer namebuf = {ACPI_ALLOCATE_BUFFER, NULL};
+ char *pathname;
+ struct acpi_buffer buffer;
+ struct acpi_device_info *dinfo;
+
+ status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &namebuf);
+ if (status)
+ goto ret;
+ pathname = namebuf.pointer;
+
+ buffer.length = ACPI_ALLOCATE_BUFFER;
+ buffer.pointer = NULL;
+ status = acpi_get_object_info(handle, &buffer);
+ if (ACPI_FAILURE(status))
+ goto out2;
+
+ dinfo = buffer.pointer;
+
+ /* find full device path name for pcidevfn */
+ if (dinfo && (dinfo->valid & ACPI_VALID_ADR) &&
+ dinfo->address == winfo->pcidevfn) {
+ if (ata_msg_probe(winfo->ataport))
+ ata_dev_printk(winfo->atadev, KERN_DEBUG,
+ ":%s: matches pcidevfn (0x%llx)\n",
+ pathname, winfo->pcidevfn);
+ strlcpy(winfo->basepath, pathname,
+ sizeof(winfo->basepath));
+ winfo->basepath_len = strlen(pathname);
+ goto out;
+ }
+
+ /* if basepath is not yet known, ignore this object */
+ if (!winfo->basepath_len)
+ goto out;
+
+ /* if this object is in scope of basepath, maybe use it */
+ if (strncmp(pathname, winfo->basepath,
+ winfo->basepath_len) == 0) {
+ if (!(dinfo->valid & ACPI_VALID_ADR))
+ goto out;
+ if (ata_msg_probe(winfo->ataport))
+ ata_dev_printk(winfo->atadev, KERN_DEBUG,
+ "GOT ONE: (%s) root_port = 0x%llx,"
+ " port_num = 0x%llx\n", pathname,
+ SATA_ROOT_PORT(dinfo->address),
+ SATA_PORT_NUMBER(dinfo->address));
+ /* heuristics: */
+ if (SATA_PORT_NUMBER(dinfo->address) != NO_PORT_MULT)
+ if (ata_msg_probe(winfo->ataport))
+ ata_dev_printk(winfo->atadev,
+ KERN_DEBUG, "warning: don't"
+ " know how to handle SATA port"
+ " multiplier\n");
+ if (SATA_ROOT_PORT(dinfo->address) ==
+ winfo->ataport->port_no &&
+ SATA_PORT_NUMBER(dinfo->address) == NO_PORT_MULT) {
+ if (ata_msg_probe(winfo->ataport))
+ ata_dev_printk(winfo->atadev,
+ KERN_DEBUG,
+ "THIS ^^^^^ is the requested"
+ " SATA drive (handle = 0x%p)\n",
+ handle);
+ winfo->sata_adr = dinfo->address;
+ winfo->obj_handle = handle;
+ }
+ }
+out:
+ kfree(dinfo);
+out2:
+ kfree(pathname);
+
+ret:
+ return status;
+}
+
+/* Get the SATA drive _ADR object. */
+static int get_sata_adr(struct device *dev, acpi_handle handle,
+ acpi_integer pcidevfn, unsigned int drive,
+ struct ata_port *ap,
+ struct ata_device *atadev, u32 *dev_adr)
+{
+ acpi_status status;
+ struct walk_info *winfo;
+ int err = -ENOMEM;
+
+ winfo = kzalloc(sizeof(struct walk_info), GFP_KERNEL);
+ if (!winfo)
+ goto out;
+
+ winfo->dev = dev;
+ winfo->atadev = atadev;
+ winfo->ataport = ap;
+ if (acpi_bus_get_device(handle, &winfo->adev) < 0)
+ if (ata_msg_probe(ap))
+ ata_dev_printk(winfo->atadev, KERN_DEBUG,
+ "acpi_bus_get_device failed\n");
+ winfo->handle = handle;
+ winfo->pcidevfn = pcidevfn;
+ winfo->drivenum = drive;
+
+ status = acpi_get_devices(NULL, get_devices, winfo, NULL);
+ if (ACPI_FAILURE(status)) {
+ if (ata_msg_probe(ap))
+ ata_dev_printk(winfo->atadev, KERN_DEBUG,
+ "%s: acpi_get_devices failed\n",
+ __FUNCTION__);
+ err = -ENODEV;
+ } else {
+ *dev_adr = winfo->sata_adr;
+ atadev->obj_handle = winfo->obj_handle;
+ err = 0;
+ }
+ kfree(winfo);
+out:
+ return err;
+}
+
+/**
+ * do_drive_get_GTF - get the drive bootup default taskfile settings
+ * @ap: the ata_port for the drive
+ * @ix: target ata_device (drive) index
+ * @gtf_length: number of bytes of _GTF data returned at @gtf_address
+ * @gtf_address: buffer containing _GTF taskfile arrays
+ *
+ * This applies to both PATA and SATA drives.
+ *
+ * The _GTF method has no input parameters.
+ * It returns a variable number of register set values (registers
+ * hex 1F1..1F7, taskfiles).
+ * The <variable number> is not known in advance, so have ACPI-CA
+ * allocate the buffer as needed and return it, then free it later.
+ *
+ * The returned @gtf_length and @gtf_address are only valid if the
+ * function return value is 0.
+ */
+static int do_drive_get_GTF(struct ata_port *ap, int ix,
+ unsigned int *gtf_length, unsigned long *gtf_address,
+ unsigned long *obj_loc)
+{
+ acpi_status status;
+ acpi_handle dev_handle = NULL;
+ acpi_handle chan_handle, drive_handle;
+ acpi_integer pcidevfn = 0;
+ u32 dev_adr;
+ struct acpi_buffer output;
+ union acpi_object *out_obj;
+ struct device *dev = ap->host->dev;
+ struct ata_device *atadev = &ap->device[ix];
+ int err = -ENODEV;
+
+ *gtf_length = 0;
+ *gtf_address = 0UL;
+ *obj_loc = 0UL;
+
+ if (noacpi)
+ return 0;
+
+ if (ata_msg_probe(ap))
+ ata_dev_printk(atadev, KERN_DEBUG,
+ "%s: ENTER: ap->id: %d, port#: %d\n",
+ __FUNCTION__, ap->id, ap->port_no);
+
+ if (!ata_dev_enabled(atadev) || (ap->flags & ATA_FLAG_DISABLED)) {
+ if (ata_msg_probe(ap))
+ ata_dev_printk(atadev, KERN_DEBUG, "%s: ERR: "
+ "ata_dev_present: %d, PORT_DISABLED: %lu\n",
+ __FUNCTION__, ata_dev_enabled(atadev),
+ ap->flags & ATA_FLAG_DISABLED);
+ goto out;
+ }
+
+ /* Don't continue if device has no _ADR method.
+ * _GTF is intended for known motherboard devices. */
+ if (!(ap->cbl == ATA_CBL_SATA)) {
+ err = pata_get_dev_handle(dev, &dev_handle, &pcidevfn);
+ if (err < 0) {
+ if (ata_msg_probe(ap))
+ ata_dev_printk(atadev, KERN_DEBUG,
+ "%s: pata_get_dev_handle failed (%d)\n",
+ __FUNCTION__, err);
+ goto out;
+ }
+ } else {
+ err = sata_get_dev_handle(dev, &dev_handle, &pcidevfn);
+ if (err < 0) {
+ if (ata_msg_probe(ap))
+ ata_dev_printk(atadev, KERN_DEBUG,
+ "%s: sata_get_dev_handle failed (%d\n",
+ __FUNCTION__, err);
+ goto out;
+ }
+ }
+
+ /* Get this drive's _ADR info. if not already known. */
+ if (!atadev->obj_handle) {
+ if (!(ap->cbl == ATA_CBL_SATA)) {
+ /* get child objects of dev_handle == channel objects,
+ * + _their_ children == drive objects */
+ /* channel is ap->port_no */
+ chan_handle = acpi_get_child(dev_handle,
+ ap->port_no);
+ if (ata_msg_probe(ap))
+ ata_dev_printk(atadev, KERN_DEBUG,
+ "%s: chan adr=%d: chan_handle=0x%p\n",
+ __FUNCTION__, ap->port_no,
+ chan_handle);
+ if (!chan_handle) {
+ err = -ENODEV;
+ goto out;
+ }
+ /* TBD: could also check ACPI object VALID bits */
+ drive_handle = acpi_get_child(chan_handle, ix);
+ if (!drive_handle) {
+ err = -ENODEV;
+ goto out;
+ }
+ dev_adr = ix;
+ atadev->obj_handle = drive_handle;
+ } else { /* for SATA mode */
+ dev_adr = SATA_ADR_RSVD;
+ err = get_sata_adr(dev, dev_handle, pcidevfn, 0,
+ ap, atadev, &dev_adr);
+ }
+ if (err < 0 || dev_adr == SATA_ADR_RSVD ||
+ !atadev->obj_handle) {
+ if (ata_msg_probe(ap))
+ ata_dev_printk(atadev, KERN_DEBUG,
+ "%s: get_sata/pata_adr failed: "
+ "err=%d, dev_adr=%u, obj_handle=0x%p\n",
+ __FUNCTION__, err, dev_adr,
+ atadev->obj_handle);
+ goto out;
+ }
+ }
+
+ /* Setting up output buffer */
+ output.length = ACPI_ALLOCATE_BUFFER;
+ output.pointer = NULL; /* ACPI-CA sets this; save/free it later */
+
+ /* _GTF has no input parameters */
+ err = -EIO;
+ status = acpi_evaluate_object(atadev->obj_handle, "_GTF",
+ NULL, &output);
+ if (ACPI_FAILURE(status)) {
+ if (ata_msg_probe(ap))
+ ata_dev_printk(atadev, KERN_DEBUG,
+ "%s: Run _GTF error: status = 0x%x\n",
+ __FUNCTION__, status);
+ goto out;
+ }
+
+ if (!output.length || !output.pointer) {
+ if (ata_msg_probe(ap))
+ ata_dev_printk(atadev, KERN_DEBUG, "%s: Run _GTF: "
+ "length or ptr is NULL (0x%llx, 0x%p)\n",
+ __FUNCTION__,
+ (unsigned long long)output.length,
+ output.pointer);
+ kfree(output.pointer);
+ goto out;
+ }
+
+ out_obj = output.pointer;
+ if (out_obj->type != ACPI_TYPE_BUFFER) {
+ kfree(output.pointer);
+ if (ata_msg_probe(ap))
+ ata_dev_printk(atadev, KERN_DEBUG, "%s: Run _GTF: "
+ "error: expected object type of "
+ " ACPI_TYPE_BUFFER, got 0x%x\n",
+ __FUNCTION__, out_obj->type);
+ err = -ENOENT;
+ goto out;
+ }
+
+ if (!out_obj->buffer.length || !out_obj->buffer.pointer ||
+ out_obj->buffer.length % REGS_PER_GTF) {
+ if (ata_msg_drv(ap))
+ ata_dev_printk(atadev, KERN_ERR,
+ "%s: unexpected GTF length (%d) or addr (0x%p)\n",
+ __FUNCTION__, out_obj->buffer.length,
+ out_obj->buffer.pointer);
+ err = -ENOENT;
+ goto out;
+ }
+
+ *gtf_length = out_obj->buffer.length;
+ *gtf_address = (unsigned long)out_obj->buffer.pointer;
+ *obj_loc = (unsigned long)out_obj;
+ if (ata_msg_probe(ap))
+ ata_dev_printk(atadev, KERN_DEBUG, "%s: returning "
+ "gtf_length=%d, gtf_address=0x%lx, obj_loc=0x%lx\n",
+ __FUNCTION__, *gtf_length, *gtf_address, *obj_loc);
+ err = 0;
+out:
+ return err;
+}
+
+/**
+ * taskfile_load_raw - send taskfile registers to host controller
+ * @ap: Port to which output is sent
+ * @gtf: raw ATA taskfile register set (0x1f1 - 0x1f7)
+ *
+ * Outputs ATA taskfile to standard ATA host controller using MMIO
+ * or PIO as indicated by the ATA_FLAG_MMIO flag.
+ * Writes the control, feature, nsect, lbal, lbam, and lbah registers.
+ * Optionally (ATA_TFLAG_LBA48) writes hob_feature, hob_nsect,
+ * hob_lbal, hob_lbam, and hob_lbah.
+ *
+ * This function waits for idle (!BUSY and !DRQ) after writing
+ * registers. If the control register has a new value, this
+ * function also waits for idle after writing control and before
+ * writing the remaining registers.
+ *
+ * LOCKING: TBD:
+ * Inherited from caller.
+ */
+static void taskfile_load_raw(struct ata_port *ap,
+ struct ata_device *atadev,
+ const struct taskfile_array *gtf)
+{
+ if (ata_msg_probe(ap))
+ ata_dev_printk(atadev, KERN_DEBUG, "%s: (0x1f1-1f7): hex: "
+ "%02x %02x %02x %02x %02x %02x %02x\n",
+ __FUNCTION__,
+ gtf->tfa[0], gtf->tfa[1], gtf->tfa[2],
+ gtf->tfa[3], gtf->tfa[4], gtf->tfa[5], gtf->tfa[6]);
+
+ if ((gtf->tfa[0] == 0) && (gtf->tfa[1] == 0) && (gtf->tfa[2] == 0)
+ && (gtf->tfa[3] == 0) && (gtf->tfa[4] == 0) && (gtf->tfa[5] == 0)
+ && (gtf->tfa[6] == 0))
+ return;
+
+ if (ap->ops->qc_issue) {
+ struct ata_taskfile tf;
+ unsigned int err;
+
+ ata_tf_init(atadev, &tf);
+
+ /* convert gtf to tf */
+ tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; /* TBD */
+ tf.protocol = atadev->class == ATA_DEV_ATAPI ?
+ ATA_PROT_ATAPI_NODATA : ATA_PROT_NODATA;
+ tf.feature = gtf->tfa[0]; /* 0x1f1 */
+ tf.nsect = gtf->tfa[1]; /* 0x1f2 */
+ tf.lbal = gtf->tfa[2]; /* 0x1f3 */
+ tf.lbam = gtf->tfa[3]; /* 0x1f4 */
+ tf.lbah = gtf->tfa[4]; /* 0x1f5 */
+ tf.device = gtf->tfa[5]; /* 0x1f6 */
+ tf.command = gtf->tfa[6]; /* 0x1f7 */
+
+ err = ata_exec_internal(atadev, &tf, NULL, DMA_NONE, NULL, 0);
+ if (err && ata_msg_probe(ap))
+ ata_dev_printk(atadev, KERN_ERR,
+ "%s: ata_exec_internal failed: %u\n",
+ __FUNCTION__, err);
+ } else
+ if (ata_msg_warn(ap))
+ ata_dev_printk(atadev, KERN_WARNING,
+ "%s: SATA driver is missing qc_issue function"
+ " entry points\n",
+ __FUNCTION__);
+}
+
+/**
+ * do_drive_set_taskfiles - write the drive taskfile settings from _GTF
+ * @ap: the ata_port for the drive
+ * @atadev: target ata_device
+ * @gtf_length: total number of bytes of _GTF taskfiles
+ * @gtf_address: location of _GTF taskfile arrays
+ *
+ * This applies to both PATA and SATA drives.
+ *
+ * Write {gtf_address, length gtf_length} in groups of
+ * REGS_PER_GTF bytes.
+ */
+static int do_drive_set_taskfiles(struct ata_port *ap,
+ struct ata_device *atadev, unsigned int gtf_length,
+ unsigned long gtf_address)
+{
+ int err = -ENODEV;
+ int gtf_count = gtf_length / REGS_PER_GTF;
+ int ix;
+ struct taskfile_array *gtf;
+
+ if (ata_msg_probe(ap))
+ ata_dev_printk(atadev, KERN_DEBUG,
+ "%s: ENTER: ap->id: %d, port#: %d\n",
+ __FUNCTION__, ap->id, ap->port_no);
+
+ if (noacpi || !(ap->cbl == ATA_CBL_SATA))
+ return 0;
+
+ if (!ata_dev_enabled(atadev) || (ap->flags & ATA_FLAG_DISABLED))
+ goto out;
+ if (!gtf_count) /* shouldn't be here */
+ goto out;
+
+ if (gtf_length % REGS_PER_GTF) {
+ if (ata_msg_drv(ap))
+ ata_dev_printk(atadev, KERN_ERR,
+ "%s: unexpected GTF length (%d)\n",
+ __FUNCTION__, gtf_length);
+ goto out;
+ }
+
+ for (ix = 0; ix < gtf_count; ix++) {
+ gtf = (struct taskfile_array *)
+ (gtf_address + ix * REGS_PER_GTF);
+
+ /* send all TaskFile registers (0x1f1-0x1f7) *in*that*order* */
+ taskfile_load_raw(ap, atadev, gtf);
+ }
+
+ err = 0;
+out:
+ return err;
+}
+
+/**
+ * ata_acpi_exec_tfs - get then write drive taskfile settings
+ * @ap: the ata_port for the drive
+ *
+ * This applies to both PATA and SATA drives.
+ */
+int ata_acpi_exec_tfs(struct ata_port *ap)
+{
+ int ix;
+ int ret =0;
+ unsigned int gtf_length;
+ unsigned long gtf_address;
+ unsigned long obj_loc;
+
+ if (noacpi)
+ return 0;
+
+ for (ix = 0; ix < ATA_MAX_DEVICES; ix++) {
+ if (!ata_dev_enabled(&ap->device[ix]))
+ continue;
+
+ ret = do_drive_get_GTF(ap, ix,
+ &gtf_length, &gtf_address, &obj_loc);
+ if (ret < 0) {
+ if (ata_msg_probe(ap))
+ ata_port_printk(ap, KERN_DEBUG,
+ "%s: get_GTF error (%d)\n",
+ __FUNCTION__, ret);
+ break;
+ }
+
+ ret = do_drive_set_taskfiles(ap, &ap->device[ix],
+ gtf_length, gtf_address);
+ kfree((void *)obj_loc);
+ if (ret < 0) {
+ if (ata_msg_probe(ap))
+ ata_port_printk(ap, KERN_DEBUG,
+ "%s: set_taskfiles error (%d)\n",
+ __FUNCTION__, ret);
+ break;
+ }
+ }
+
+ return ret;
+}
+
+/**
+ * ata_acpi_push_id - send Identify data to drive
+ * @ap: the ata_port for the drive
+ * @ix: drive index
+ *
+ * _SDD ACPI object: for SATA mode only
+ * Must be after Identify (Packet) Device -- uses its data
+ * ATM this function never returns a failure. It is an optional
+ * method and if it fails for whatever reason, we should still
+ * just keep going.
+ */
+int ata_acpi_push_id(struct ata_port *ap, unsigned int ix)
+{
+ acpi_handle handle;
+ acpi_integer pcidevfn;
+ int err;
+ struct device *dev = ap->host->dev;
+ struct ata_device *atadev = &ap->device[ix];
+ u32 dev_adr;
+ acpi_status status;
+ struct acpi_object_list input;
+ union acpi_object in_params[1];
+
+ if (noacpi)
+ return 0;
+
+ if (ata_msg_probe(ap))
+ ata_dev_printk(atadev, KERN_DEBUG,
+ "%s: ap->id: %d, ix = %d, port#: %d\n",
+ __FUNCTION__, ap->id, ix, ap->port_no);
+
+ /* Don't continue if not a SATA device. */
+ if (!(ap->cbl == ATA_CBL_SATA)) {
+ if (ata_msg_probe(ap))
+ ata_dev_printk(atadev, KERN_DEBUG,
+ "%s: Not a SATA device\n", __FUNCTION__);
+ goto out;
+ }
+
+ /* Don't continue if device has no _ADR method.
+ * _SDD is intended for known motherboard devices. */
+ err = sata_get_dev_handle(dev, &handle, &pcidevfn);
+ if (err < 0) {
+ if (ata_msg_probe(ap))
+ ata_dev_printk(atadev, KERN_DEBUG,
+ "%s: sata_get_dev_handle failed (%d\n",
+ __FUNCTION__, err);
+ goto out;
+ }
+
+ /* Get this drive's _ADR info, if not already known */
+ if (!atadev->obj_handle) {
+ dev_adr = SATA_ADR_RSVD;
+ err = get_sata_adr(dev, handle, pcidevfn, ix, ap, atadev,
+ &dev_adr);
+ if (err < 0 || dev_adr == SATA_ADR_RSVD ||
+ !atadev->obj_handle) {
+ if (ata_msg_probe(ap))
+ ata_dev_printk(atadev, KERN_DEBUG,
+ "%s: get_sata_adr failed: "
+ "err=%d, dev_adr=%u, obj_handle=0x%p\n",
+ __FUNCTION__, err, dev_adr,
+ atadev->obj_handle);
+ goto out;
+ }
+ }
+
+ /* Give the drive Identify data to the drive via the _SDD method */
+ /* _SDD: set up input parameters */
+ input.count = 1;
+ input.pointer = in_params;
+ in_params[0].type = ACPI_TYPE_BUFFER;
+ in_params[0].buffer.length = sizeof(atadev->id[0]) * ATA_ID_WORDS;
+ in_params[0].buffer.pointer = (u8 *)atadev->id;
+ /* Output buffer: _SDD has no output */
+
+ /* It's OK for _SDD to be missing too. */
+ swap_buf_le16(atadev->id, ATA_ID_WORDS);
+ status = acpi_evaluate_object(atadev->obj_handle, "_SDD", &input, NULL);
+ swap_buf_le16(atadev->id, ATA_ID_WORDS);
+
+ err = ACPI_FAILURE(status) ? -EIO : 0;
+ if (err < 0) {
+ if (ata_msg_probe(ap))
+ ata_dev_printk(atadev, KERN_DEBUG,
+ "ata%u(%u): %s _SDD error: status = 0x%x\n",
+ ap->id, ap->device->devno,
+ __FUNCTION__, status);
+ }
+
+ /* always return success */
+out:
+ return 0;
+}
+
+
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 667acd28336..e900c5edefc 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -59,6 +59,9 @@
#include "libata.h"
+#define DRV_VERSION "2.10" /* must be exactly four chars */
+
+
/* debounce timing parameters in msecs { interval, duration, timeout } */
const unsigned long sata_deb_timing_normal[] = { 5, 100, 2000 };
const unsigned long sata_deb_timing_hotplug[] = { 25, 500, 2000 };
@@ -90,6 +93,10 @@ static int ata_probe_timeout = ATA_TMOUT_INTERNAL / HZ;
module_param(ata_probe_timeout, int, 0444);
MODULE_PARM_DESC(ata_probe_timeout, "Set ATA probing timeout (seconds)");
+int noacpi;
+module_param(noacpi, int, 0444);
+MODULE_PARM_DESC(noacpi, "Disables the use of ACPI in suspend/resume when set");
+
MODULE_AUTHOR("Jeff Garzik");
MODULE_DESCRIPTION("Library module for ATA devices");
MODULE_LICENSE("GPL");
@@ -598,51 +605,7 @@ void ata_dev_disable(struct ata_device *dev)
}
/**
- * ata_pio_devchk - PATA device presence detection
- * @ap: ATA channel to examine
- * @device: Device to examine (starting at zero)
- *
- * This technique was originally described in
- * Hale Landis's ATADRVR (www.ata-atapi.com), and
- * later found its way into the ATA/ATAPI spec.
- *
- * Write a pattern to the ATA shadow registers,
- * and if a device is present, it will respond by
- * correctly storing and echoing back the
- * ATA shadow register contents.
- *
- * LOCKING:
- * caller.
- */
-
-static unsigned int ata_pio_devchk(struct ata_port *ap,
- unsigned int device)
-{
- struct ata_ioports *ioaddr = &ap->ioaddr;
- u8 nsect, lbal;
-
- ap->ops->dev_select(ap, device);
-
- outb(0x55, ioaddr->nsect_addr);
- outb(0xaa, ioaddr->lbal_addr);
-
- outb(0xaa, ioaddr->nsect_addr);
- outb(0x55, ioaddr->lbal_addr);
-
- outb(0x55, ioaddr->nsect_addr);
- outb(0xaa, ioaddr->lbal_addr);
-
- nsect = inb(ioaddr->nsect_addr);
- lbal = inb(ioaddr->lbal_addr);
-
- if ((nsect == 0x55) && (lbal == 0xaa))
- return 1; /* we found a device */
-
- return 0; /* nothing found */
-}
-
-/**
- * ata_mmio_devchk - PATA device presence detection
+ * ata_devchk - PATA device presence detection
* @ap: ATA channel to examine
* @device: Device to examine (starting at zero)
*
@@ -659,25 +622,24 @@ static unsigned int ata_pio_devchk(struct ata_port *ap,
* caller.
*/
-static unsigned int ata_mmio_devchk(struct ata_port *ap,
- unsigned int device)
+static unsigned int ata_devchk(struct ata_port *ap, unsigned int device)
{
struct ata_ioports *ioaddr = &ap->ioaddr;
u8 nsect, lbal;
ap->ops->dev_select(ap, device);
- writeb(0x55, (void __iomem *) ioaddr->nsect_addr);
- writeb(0xaa, (void __iomem *) ioaddr->lbal_addr);
+ iowrite8(0x55, ioaddr->nsect_addr);
+ iowrite8(0xaa, ioaddr->lbal_addr);
- writeb(0xaa, (void __iomem *) ioaddr->nsect_addr);
- writeb(0x55, (void __iomem *) ioaddr->lbal_addr);
+ iowrite8(0xaa, ioaddr->nsect_addr);
+ iowrite8(0x55, ioaddr->lbal_addr);
- writeb(0x55, (void __iomem *) ioaddr->nsect_addr);
- writeb(0xaa, (void __iomem *) ioaddr->lbal_addr);
+ iowrite8(0x55, ioaddr->nsect_addr);
+ iowrite8(0xaa, ioaddr->lbal_addr);
- nsect = readb((void __iomem *) ioaddr->nsect_addr);
- lbal = readb((void __iomem *) ioaddr->lbal_addr);
+ nsect = ioread8(ioaddr->nsect_addr);
+ lbal = ioread8(ioaddr->lbal_addr);
if ((nsect == 0x55) && (lbal == 0xaa))
return 1; /* we found a device */
@@ -686,27 +648,6 @@ static unsigned int ata_mmio_devchk(struct ata_port *ap,
}
/**
- * ata_devchk - PATA device presence detection
- * @ap: ATA channel to examine
- * @device: Device to examine (starting at zero)
- *
- * Dispatch ATA device presence detection, depending
- * on whether we are using PIO or MMIO to talk to the
- * ATA shadow registers.
- *
- * LOCKING:
- * caller.
- */
-
-static unsigned int ata_devchk(struct ata_port *ap,
- unsigned int device)
-{
- if (ap->flags & ATA_FLAG_MMIO)
- return ata_mmio_devchk(ap, device);
- return ata_pio_devchk(ap, device);
-}
-
-/**
* ata_dev_classify - determine device type based on ATA-spec signature
* @tf: ATA taskfile register set for device to be identified
*
@@ -923,11 +864,7 @@ void ata_std_dev_select (struct ata_port *ap, unsigned int device)
else
tmp = ATA_DEVICE_OBS | ATA_DEV1;
- if (ap->flags & ATA_FLAG_MMIO) {
- writeb(tmp, (void __iomem *) ap->ioaddr.device_addr);
- } else {
- outb(tmp, ap->ioaddr.device_addr);
- }
+ iowrite8(tmp, ap->ioaddr.device_addr);
ata_pause(ap); /* needed; also flushes, for mmio */
}
@@ -1156,7 +1093,7 @@ void ata_port_flush_task(struct ata_port *ap)
ata_port_printk(ap, KERN_DEBUG, "%s: EXIT\n", __FUNCTION__);
}
-void ata_qc_complete_internal(struct ata_queued_cmd *qc)
+static void ata_qc_complete_internal(struct ata_queued_cmd *qc)
{
struct completion *waiting = qc->private_data;
@@ -1249,7 +1186,6 @@ unsigned ata_exec_internal_sg(struct ata_device *dev,
buflen += sg[i].length;
ata_sg_init(qc, sg, n_elem);
- qc->nsect = buflen / ATA_SECT_SIZE;
qc->nbytes = buflen;
}
@@ -1292,7 +1228,7 @@ unsigned ata_exec_internal_sg(struct ata_device *dev,
if (ap->ops->post_internal_cmd)
ap->ops->post_internal_cmd(qc);
- if (qc->flags & ATA_QCFLAG_FAILED && !qc->err_mask) {
+ if ((qc->flags & ATA_QCFLAG_FAILED) && !qc->err_mask) {
if (ata_msg_warn(ap))
ata_dev_printk(dev, KERN_WARNING,
"zero err_mask for failed "
@@ -1478,7 +1414,16 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
}
tf.protocol = ATA_PROT_PIO;
- tf.flags |= ATA_TFLAG_POLLING; /* for polling presence detection */
+
+ /* Some devices choke if TF registers contain garbage. Make
+ * sure those are properly initialized.
+ */
+ tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+
+ /* Device presence detection is unreliable on some
+ * controllers. Always poll IDENTIFY if available.
+ */
+ tf.flags |= ATA_TFLAG_POLLING;
err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE,
id, sizeof(id[0]) * ATA_ID_WORDS);
@@ -1608,6 +1553,8 @@ int ata_dev_configure(struct ata_device *dev)
const u16 *id = dev->id;
unsigned int xfer_mask;
char revbuf[7]; /* XYZ-99\0 */
+ char fwrevbuf[ATA_ID_FW_REV_LEN+1];
+ char modelbuf[ATA_ID_PROD_LEN+1];
int rc;
if (!ata_dev_enabled(dev) && ata_msg_info(ap)) {
@@ -1621,6 +1568,16 @@ int ata_dev_configure(struct ata_device *dev)
ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER, host %u, dev %u\n",
__FUNCTION__, ap->id, dev->devno);
+ /* set _SDD */
+ rc = ata_acpi_push_id(ap, dev->devno);
+ if (rc) {
+ ata_dev_printk(dev, KERN_WARNING, "failed to set _SDD(%d)\n",
+ rc);
+ }
+
+ /* retrieve and execute the ATA task file of _GTF */
+ ata_acpi_exec_tfs(ap);
+
/* print device capabilities */
if (ata_msg_probe(ap))
ata_dev_printk(dev, KERN_DEBUG,
@@ -1662,6 +1619,16 @@ int ata_dev_configure(struct ata_device *dev)
dev->n_sectors = ata_id_n_sectors(id);
+ /* SCSI only uses 4-char revisions, dump full 8 chars from ATA */
+ ata_id_c_string(dev->id, fwrevbuf, ATA_ID_FW_REV,
+ sizeof(fwrevbuf));
+
+ ata_id_c_string(dev->id, modelbuf, ATA_ID_PROD,
+ sizeof(modelbuf));
+
+ if (dev->id[59] & 0x100)
+ dev->multi_count = dev->id[59] & 0xff;
+
if (ata_id_has_lba(id)) {
const char *lba_desc;
char ncq_desc[20];
@@ -1681,13 +1648,16 @@ int ata_dev_configure(struct ata_device *dev)
ata_dev_config_ncq(dev, ncq_desc, sizeof(ncq_desc));
/* print device info to dmesg */
- if (ata_msg_drv(ap) && print_info)
- ata_dev_printk(dev, KERN_INFO, "%s, "
- "max %s, %Lu sectors: %s %s\n",
- revbuf,
- ata_mode_string(xfer_mask),
+ if (ata_msg_drv(ap) && print_info) {
+ ata_dev_printk(dev, KERN_INFO,
+ "%s: %s, %s, max %s\n",
+ revbuf, modelbuf, fwrevbuf,
+ ata_mode_string(xfer_mask));
+ ata_dev_printk(dev, KERN_INFO,
+ "%Lu sectors, multi %u: %s %s\n",
(unsigned long long)dev->n_sectors,
- lba_desc, ncq_desc);
+ dev->multi_count, lba_desc, ncq_desc);
+ }
} else {
/* CHS */
@@ -1704,22 +1674,17 @@ int ata_dev_configure(struct ata_device *dev)
}
/* print device info to dmesg */
- if (ata_msg_drv(ap) && print_info)
- ata_dev_printk(dev, KERN_INFO, "%s, "
- "max %s, %Lu sectors: CHS %u/%u/%u\n",
- revbuf,
- ata_mode_string(xfer_mask),
- (unsigned long long)dev->n_sectors,
- dev->cylinders, dev->heads,
- dev->sectors);
- }
-
- if (dev->id[59] & 0x100) {
- dev->multi_count = dev->id[59] & 0xff;
- if (ata_msg_drv(ap) && print_info)
+ if (ata_msg_drv(ap) && print_info) {
ata_dev_printk(dev, KERN_INFO,
- "ata%u: dev %u multi count %u\n",
- ap->id, dev->devno, dev->multi_count);
+ "%s: %s, %s, max %s\n",
+ revbuf, modelbuf, fwrevbuf,
+ ata_mode_string(xfer_mask));
+ ata_dev_printk(dev, KERN_INFO,
+ "%Lu sectors, multi %u, CHS %u/%u/%u\n",
+ (unsigned long long)dev->n_sectors,
+ dev->multi_count, dev->cylinders,
+ dev->heads, dev->sectors);
+ }
}
dev->cdb_len = 16;
@@ -2391,6 +2356,10 @@ static int ata_dev_set_mode(struct ata_device *dev)
dev->flags |= ATA_DFLAG_PIO;
err_mask = ata_dev_set_xfermode(dev);
+ /* Old CFA may refuse this command, which is just fine */
+ if (dev->xfer_shift == ATA_SHIFT_PIO && ata_id_is_cfa(dev->id))
+ err_mask &= ~AC_ERR_DEV;
+
if (err_mask) {
ata_dev_printk(dev, KERN_ERR, "failed to set xfermode "
"(err_mask=0x%x)\n", err_mask);
@@ -2493,7 +2462,7 @@ int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
for (i = 0; i < ATA_MAX_DEVICES; i++) {
dev = &ap->device[i];
- /* don't udpate suspended devices' xfer mode */
+ /* don't update suspended devices' xfer mode */
if (!ata_dev_ready(dev))
continue;
@@ -2614,13 +2583,8 @@ static void ata_bus_post_reset(struct ata_port *ap, unsigned int devmask)
u8 nsect, lbal;
ap->ops->dev_select(ap, 1);
- if (ap->flags & ATA_FLAG_MMIO) {
- nsect = readb((void __iomem *) ioaddr->nsect_addr);
- lbal = readb((void __iomem *) ioaddr->lbal_addr);
- } else {
- nsect = inb(ioaddr->nsect_addr);
- lbal = inb(ioaddr->lbal_addr);
- }
+ nsect = ioread8(ioaddr->nsect_addr);
+ lbal = ioread8(ioaddr->lbal_addr);
if ((nsect == 1) && (lbal == 1))
break;
if (time_after(jiffies, timeout)) {
@@ -2648,19 +2612,11 @@ static unsigned int ata_bus_softreset(struct ata_port *ap,
DPRINTK("ata%u: bus reset via SRST\n", ap->id);
/* software reset. causes dev0 to be selected */
- if (ap->flags & ATA_FLAG_MMIO) {
- writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr);
- udelay(20); /* FIXME: flush */
- writeb(ap->ctl | ATA_SRST, (void __iomem *) ioaddr->ctl_addr);
- udelay(20); /* FIXME: flush */
- writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr);
- } else {
- outb(ap->ctl, ioaddr->ctl_addr);
- udelay(10);
- outb(ap->ctl | ATA_SRST, ioaddr->ctl_addr);
- udelay(10);
- outb(ap->ctl, ioaddr->ctl_addr);
- }
+ iowrite8(ap->ctl, ioaddr->ctl_addr);
+ udelay(20); /* FIXME: flush */
+ iowrite8(ap->ctl | ATA_SRST, ioaddr->ctl_addr);
+ udelay(20); /* FIXME: flush */
+ iowrite8(ap->ctl, ioaddr->ctl_addr);
/* spec mandates ">= 2ms" before checking status.
* We wait 150ms, because that was the magic delay used for
@@ -2745,8 +2701,7 @@ void ata_bus_reset(struct ata_port *ap)
ap->device[1].class = ata_dev_try_classify(ap, 1, &err);
/* re-enable interrupts */
- if (ap->ioaddr.ctl_addr) /* FIXME: hack. create a hook instead */
- ata_irq_on(ap);
+ ap->ops->irq_on(ap);
/* is double-select really necessary? */
if (ap->device[1].class != ATA_DEV_NONE)
@@ -2761,10 +2716,7 @@ void ata_bus_reset(struct ata_port *ap)
if (ap->flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST)) {
/* set up device control for ATA_FLAG_SATA_RESET */
- if (ap->flags & ATA_FLAG_MMIO)
- writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr);
- else
- outb(ap->ctl, ioaddr->ctl_addr);
+ iowrite8(ap->ctl, ioaddr->ctl_addr);
}
DPRINTK("EXIT\n");
@@ -3098,6 +3050,9 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class)
return 0;
}
+ /* wait a while before checking status, see SRST for more info */
+ msleep(150);
+
if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) {
ata_port_printk(ap, KERN_ERR,
"COMRESET failed (device not ready)\n");
@@ -3138,11 +3093,8 @@ void ata_std_postreset(struct ata_port *ap, unsigned int *classes)
sata_scr_write(ap, SCR_ERROR, serror);
/* re-enable interrupts */
- if (!ap->ops->error_handler) {
- /* FIXME: hack. create a hook instead */
- if (ap->ioaddr.ctl_addr)
- ata_irq_on(ap);
- }
+ if (!ap->ops->error_handler)
+ ap->ops->irq_on(ap);
/* is double-select really necessary? */
if (classes[0] != ATA_DEV_NONE)
@@ -3157,12 +3109,8 @@ void ata_std_postreset(struct ata_port *ap, unsigned int *classes)
}
/* set up device control */
- if (ap->ioaddr.ctl_addr) {
- if (ap->flags & ATA_FLAG_MMIO)
- writeb(ap->ctl, (void __iomem *) ap->ioaddr.ctl_addr);
- else
- outb(ap->ctl, ap->ioaddr.ctl_addr);
- }
+ if (ap->ioaddr.ctl_addr)
+ iowrite8(ap->ctl, ap->ioaddr.ctl_addr);
DPRINTK("EXIT\n");
}
@@ -3187,7 +3135,8 @@ static int ata_dev_same_device(struct ata_device *dev, unsigned int new_class,
const u16 *new_id)
{
const u16 *old_id = dev->id;
- unsigned char model[2][41], serial[2][21];
+ unsigned char model[2][ATA_ID_PROD_LEN + 1];
+ unsigned char serial[2][ATA_ID_SERNO_LEN + 1];
u64 new_n_sectors;
if (dev->class != new_class) {
@@ -3196,10 +3145,10 @@ static int ata_dev_same_device(struct ata_device *dev, unsigned int new_class,
return 0;
}
- ata_id_c_string(old_id, model[0], ATA_ID_PROD_OFS, sizeof(model[0]));
- ata_id_c_string(new_id, model[1], ATA_ID_PROD_OFS, sizeof(model[1]));
- ata_id_c_string(old_id, serial[0], ATA_ID_SERNO_OFS, sizeof(serial[0]));
- ata_id_c_string(new_id, serial[1], ATA_ID_SERNO_OFS, sizeof(serial[1]));
+ ata_id_c_string(old_id, model[0], ATA_ID_PROD, sizeof(model[0]));
+ ata_id_c_string(new_id, model[1], ATA_ID_PROD, sizeof(model[1]));
+ ata_id_c_string(old_id, serial[0], ATA_ID_SERNO, sizeof(serial[0]));
+ ata_id_c_string(new_id, serial[1], ATA_ID_SERNO, sizeof(serial[1]));
new_n_sectors = ata_id_n_sectors(new_id);
if (strcmp(model[0], model[1])) {
@@ -3324,37 +3273,20 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
{ }
};
-static int ata_strim(char *s, size_t len)
-{
- len = strnlen(s, len);
-
- /* ATAPI specifies that empty space is blank-filled; remove blanks */
- while ((len > 0) && (s[len - 1] == ' ')) {
- len--;
- s[len] = 0;
- }
- return len;
-}
-
unsigned long ata_device_blacklisted(const struct ata_device *dev)
{
- unsigned char model_num[40];
- unsigned char model_rev[16];
- unsigned int nlen, rlen;
+ unsigned char model_num[ATA_ID_PROD_LEN + 1];
+ unsigned char model_rev[ATA_ID_FW_REV_LEN + 1];
const struct ata_blacklist_entry *ad = ata_device_blacklist;
- ata_id_string(dev->id, model_num, ATA_ID_PROD_OFS,
- sizeof(model_num));
- ata_id_string(dev->id, model_rev, ATA_ID_FW_REV_OFS,
- sizeof(model_rev));
- nlen = ata_strim(model_num, sizeof(model_num));
- rlen = ata_strim(model_rev, sizeof(model_rev));
+ ata_id_c_string(dev->id, model_num, ATA_ID_PROD, sizeof(model_num));
+ ata_id_c_string(dev->id, model_rev, ATA_ID_FW_REV, sizeof(model_rev));
while (ad->model_num) {
- if (!strncmp(ad->model_num, model_num, nlen)) {
+ if (!strcmp(ad->model_num, model_num)) {
if (ad->model_rev == NULL)
return ad->horkage;
- if (!strncmp(ad->model_rev, model_rev, rlen))
+ if (!strcmp(ad->model_rev, model_rev))
return ad->horkage;
}
ad++;
@@ -3894,53 +3826,7 @@ void swap_buf_le16(u16 *buf, unsigned int buf_words)
}
/**
- * ata_mmio_data_xfer - Transfer data by MMIO
- * @adev: device for this I/O
- * @buf: data buffer
- * @buflen: buffer length
- * @write_data: read/write
- *
- * Transfer data from/to the device data register by MMIO.
- *
- * LOCKING:
- * Inherited from caller.
- */
-
-void ata_mmio_data_xfer(struct ata_device *adev, unsigned char *buf,
- unsigned int buflen, int write_data)
-{
- struct ata_port *ap = adev->ap;
- unsigned int i;
- unsigned int words = buflen >> 1;
- u16 *buf16 = (u16 *) buf;
- void __iomem *mmio = (void __iomem *)ap->ioaddr.data_addr;
-
- /* Transfer multiple of 2 bytes */
- if (write_data) {
- for (i = 0; i < words; i++)
- writew(le16_to_cpu(buf16[i]), mmio);
- } else {
- for (i = 0; i < words; i++)
- buf16[i] = cpu_to_le16(readw(mmio));
- }
-
- /* Transfer trailing 1 byte, if any. */
- if (unlikely(buflen & 0x01)) {
- u16 align_buf[1] = { 0 };
- unsigned char *trailing_buf = buf + buflen - 1;
-
- if (write_data) {
- memcpy(align_buf, trailing_buf, 1);
- writew(le16_to_cpu(align_buf[0]), mmio);
- } else {
- align_buf[0] = cpu_to_le16(readw(mmio));
- memcpy(trailing_buf, align_buf, 1);
- }
- }
-}
-
-/**
- * ata_pio_data_xfer - Transfer data by PIO
+ * ata_data_xfer - Transfer data by PIO
* @adev: device to target
* @buf: data buffer
* @buflen: buffer length
@@ -3951,18 +3837,17 @@ void ata_mmio_data_xfer(struct ata_device *adev, unsigned char *buf,
* LOCKING:
* Inherited from caller.
*/
-
-void ata_pio_data_xfer(struct ata_device *adev, unsigned char *buf,
- unsigned int buflen, int write_data)
+void ata_data_xfer(struct ata_device *adev, unsigned char *buf,
+ unsigned int buflen, int write_data)
{
struct ata_port *ap = adev->ap;
unsigned int words = buflen >> 1;
/* Transfer multiple of 2 bytes */
if (write_data)
- outsw(ap->ioaddr.data_addr, buf, words);
+ iowrite16_rep(ap->ioaddr.data_addr, buf, words);
else
- insw(ap->ioaddr.data_addr, buf, words);
+ ioread16_rep(ap->ioaddr.data_addr, buf, words);
/* Transfer trailing 1 byte, if any. */
if (unlikely(buflen & 0x01)) {
@@ -3971,16 +3856,16 @@ void ata_pio_data_xfer(struct ata_device *adev, unsigned char *buf,
if (write_data) {
memcpy(align_buf, trailing_buf, 1);
- outw(le16_to_cpu(align_buf[0]), ap->ioaddr.data_addr);
+ iowrite16(le16_to_cpu(align_buf[0]), ap->ioaddr.data_addr);
} else {
- align_buf[0] = cpu_to_le16(inw(ap->ioaddr.data_addr));
+ align_buf[0] = cpu_to_le16(ioread16(ap->ioaddr.data_addr));
memcpy(trailing_buf, align_buf, 1);
}
}
}
/**
- * ata_pio_data_xfer_noirq - Transfer data by PIO
+ * ata_data_xfer_noirq - Transfer data by PIO
* @adev: device to target
* @buf: data buffer
* @buflen: buffer length
@@ -3992,13 +3877,12 @@ void ata_pio_data_xfer(struct ata_device *adev, unsigned char *buf,
* LOCKING:
* Inherited from caller.
*/
-
-void ata_pio_data_xfer_noirq(struct ata_device *adev, unsigned char *buf,
- unsigned int buflen, int write_data)
+void ata_data_xfer_noirq(struct ata_device *adev, unsigned char *buf,
+ unsigned int buflen, int write_data)
{
unsigned long flags;
local_irq_save(flags);
- ata_pio_data_xfer(adev, buf, buflen, write_data);
+ ata_data_xfer(adev, buf, buflen, write_data);
local_irq_restore(flags);
}
@@ -4022,11 +3906,11 @@ static void ata_pio_sector(struct ata_queued_cmd *qc)
unsigned int offset;
unsigned char *buf;
- if (qc->cursect == (qc->nsect - 1))
+ if (qc->curbytes == qc->nbytes - ATA_SECT_SIZE)
ap->hsm_task_state = HSM_ST_LAST;
page = sg[qc->cursg].page;
- offset = sg[qc->cursg].offset + qc->cursg_ofs * ATA_SECT_SIZE;
+ offset = sg[qc->cursg].offset + qc->cursg_ofs;
/* get the current page and offset */
page = nth_page(page, (offset >> PAGE_SHIFT));
@@ -4051,10 +3935,10 @@ static void ata_pio_sector(struct ata_queued_cmd *qc)
ap->ops->data_xfer(qc->dev, buf + offset, ATA_SECT_SIZE, do_write);
}
- qc->cursect++;
- qc->cursg_ofs++;
+ qc->curbytes += ATA_SECT_SIZE;
+ qc->cursg_ofs += ATA_SECT_SIZE;
- if ((qc->cursg_ofs * ATA_SECT_SIZE) == (&sg[qc->cursg])->length) {
+ if (qc->cursg_ofs == (&sg[qc->cursg])->length) {
qc->cursg++;
qc->cursg_ofs = 0;
}
@@ -4079,7 +3963,8 @@ static void ata_pio_sectors(struct ata_queued_cmd *qc)
WARN_ON(qc->dev->multi_count == 0);
- nsect = min(qc->nsect - qc->cursect, qc->dev->multi_count);
+ nsect = min((qc->nbytes - qc->curbytes) / ATA_SECT_SIZE,
+ qc->dev->multi_count);
while (nsect--)
ata_pio_sector(qc);
} else
@@ -4320,7 +4205,7 @@ static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq)
qc = ata_qc_from_tag(ap, qc->tag);
if (qc) {
if (likely(!(qc->err_mask & AC_ERR_HSM))) {
- ata_irq_on(ap);
+ ap->ops->irq_on(ap);
ata_qc_complete(qc);
} else
ata_port_freeze(ap);
@@ -4336,7 +4221,7 @@ static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq)
} else {
if (in_wq) {
spin_lock_irqsave(ap->lock, flags);
- ata_irq_on(ap);
+ ap->ops->irq_on(ap);
ata_qc_complete(qc);
spin_unlock_irqrestore(ap->lock, flags);
} else
@@ -5161,7 +5046,7 @@ idle_irq:
#ifdef ATA_IRQ_TRAP
if ((ap->stats.idle_irq % 1000) == 0) {
- ata_irq_ack(ap, 0); /* debug trap */
+ ap->ops->irq_ack(ap, 0); /* debug trap */
ata_port_printk(ap, KERN_WARNING, "irq trap\n");
return 1;
}
@@ -5502,54 +5387,25 @@ void ata_host_resume(struct ata_host *host)
* LOCKING:
* Inherited from caller.
*/
-
-int ata_port_start (struct ata_port *ap)
+int ata_port_start(struct ata_port *ap)
{
struct device *dev = ap->dev;
int rc;
- ap->prd = dma_alloc_coherent(dev, ATA_PRD_TBL_SZ, &ap->prd_dma, GFP_KERNEL);
+ ap->prd = dmam_alloc_coherent(dev, ATA_PRD_TBL_SZ, &ap->prd_dma,
+ GFP_KERNEL);
if (!ap->prd)
return -ENOMEM;
rc = ata_pad_alloc(ap, dev);
- if (rc) {
- dma_free_coherent(dev, ATA_PRD_TBL_SZ, ap->prd, ap->prd_dma);
+ if (rc)
return rc;
- }
-
- DPRINTK("prd alloc, virt %p, dma %llx\n", ap->prd, (unsigned long long) ap->prd_dma);
+ DPRINTK("prd alloc, virt %p, dma %llx\n", ap->prd,
+ (unsigned long long)ap->prd_dma);
return 0;
}
-
-/**
- * ata_port_stop - Undo ata_port_start()
- * @ap: Port to shut down
- *
- * Frees the PRD table.
- *
- * May be used as the port_stop() entry in ata_port_operations.
- *
- * LOCKING:
- * Inherited from caller.
- */
-
-void ata_port_stop (struct ata_port *ap)
-{
- struct device *dev = ap->dev;
-
- dma_free_coherent(dev, ATA_PRD_TBL_SZ, ap->prd, ap->prd_dma);
- ata_pad_free(ap, dev);
-}
-
-void ata_host_stop (struct ata_host *host)
-{
- if (host->mmio_base)
- iounmap(host->mmio_base);
-}
-
/**
* ata_dev_init - Initialize an ata_device structure
* @dev: Device structure to initialize
@@ -5723,6 +5579,27 @@ static struct ata_port * ata_port_add(const struct ata_probe_ent *ent,
return ap;
}
+static void ata_host_release(struct device *gendev, void *res)
+{
+ struct ata_host *host = dev_get_drvdata(gendev);
+ int i;
+
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+
+ if (!ap)
+ continue;
+
+ if (ap->ops->port_stop)
+ ap->ops->port_stop(ap);
+
+ scsi_host_put(ap->scsi_host);
+ }
+
+ if (host->ops->host_stop)
+ host->ops->host_stop(host);
+}
+
/**
* ata_sas_host_init - Initialize a host struct
* @host: host to initialize
@@ -5770,22 +5647,28 @@ int ata_device_add(const struct ata_probe_ent *ent)
int rc;
DPRINTK("ENTER\n");
-
+
if (ent->irq == 0) {
dev_printk(KERN_ERR, dev, "is not available: No interrupt assigned.\n");
return 0;
}
+
+ if (!devres_open_group(dev, ata_device_add, GFP_KERNEL))
+ return 0;
+
/* alloc a container for our list of ATA ports (buses) */
- host = kzalloc(sizeof(struct ata_host) +
- (ent->n_ports * sizeof(void *)), GFP_KERNEL);
+ host = devres_alloc(ata_host_release, sizeof(struct ata_host) +
+ (ent->n_ports * sizeof(void *)), GFP_KERNEL);
if (!host)
- return 0;
+ goto err_out;
+ devres_add(dev, host);
+ dev_set_drvdata(dev, host);
ata_host_init(host, dev, ent->_host_flags, ent->port_ops);
host->n_ports = ent->n_ports;
host->irq = ent->irq;
host->irq2 = ent->irq2;
- host->mmio_base = ent->mmio_base;
+ host->iomap = ent->iomap;
host->private_data = ent->private_data;
/* register each port bound to this device */
@@ -5823,8 +5706,8 @@ int ata_device_add(const struct ata_probe_ent *ent)
(ap->pio_mask << ATA_SHIFT_PIO);
/* print per-port info to dmesg */
- ata_port_printk(ap, KERN_INFO, "%cATA max %s cmd 0x%lX "
- "ctl 0x%lX bmdma 0x%lX irq %d\n",
+ ata_port_printk(ap, KERN_INFO, "%cATA max %s cmd 0x%p "
+ "ctl 0x%p bmdma 0x%p irq %d\n",
ap->flags & ATA_FLAG_SATA ? 'S' : 'P',
ata_mode_string(xfer_mode_mask),
ap->ioaddr.cmd_addr,
@@ -5837,8 +5720,8 @@ int ata_device_add(const struct ata_probe_ent *ent)
}
/* obtain irq, that may be shared between channels */
- rc = request_irq(ent->irq, ent->port_ops->irq_handler, ent->irq_flags,
- DRV_NAME, host);
+ rc = devm_request_irq(dev, ent->irq, ent->port_ops->irq_handler,
+ ent->irq_flags, DRV_NAME, host);
if (rc) {
dev_printk(KERN_ERR, dev, "irq %lu request failed: %d\n",
ent->irq, rc);
@@ -5851,15 +5734,19 @@ int ata_device_add(const struct ata_probe_ent *ent)
so trap it now */
BUG_ON(ent->irq == ent->irq2);
- rc = request_irq(ent->irq2, ent->port_ops->irq_handler, ent->irq_flags,
- DRV_NAME, host);
+ rc = devm_request_irq(dev, ent->irq2,
+ ent->port_ops->irq_handler, ent->irq_flags,
+ DRV_NAME, host);
if (rc) {
dev_printk(KERN_ERR, dev, "irq %lu request failed: %d\n",
ent->irq2, rc);
- goto err_out_free_irq;
+ goto err_out;
}
}
+ /* resource acquisition complete */
+ devres_remove_group(dev, ata_device_add);
+
/* perform each probe synchronously */
DPRINTK("probe begin\n");
for (i = 0; i < host->n_ports; i++) {
@@ -5928,24 +5815,13 @@ int ata_device_add(const struct ata_probe_ent *ent)
ata_scsi_scan_host(ap);
}
- dev_set_drvdata(dev, host);
-
VPRINTK("EXIT, returning %u\n", ent->n_ports);
return ent->n_ports; /* success */
-err_out_free_irq:
- free_irq(ent->irq, host);
-err_out:
- for (i = 0; i < host->n_ports; i++) {
- struct ata_port *ap = host->ports[i];
- if (ap) {
- ap->ops->port_stop(ap);
- scsi_host_put(ap->scsi_host);
- }
- }
-
- kfree(host);
- VPRINTK("EXIT, returning 0\n");
+ err_out:
+ devres_release_group(dev, ata_device_add);
+ dev_set_drvdata(dev, NULL);
+ VPRINTK("EXIT, returning %d\n", rc);
return 0;
}
@@ -6008,76 +5884,20 @@ void ata_port_detach(struct ata_port *ap)
}
/**
- * ata_host_remove - PCI layer callback for device removal
- * @host: ATA host set that was removed
+ * ata_host_detach - Detach all ports of an ATA host
+ * @host: Host to detach
*
- * Unregister all objects associated with this host set. Free those
- * objects.
+ * Detach all ports of @host.
*
* LOCKING:
- * Inherited from calling layer (may sleep).
+ * Kernel thread context (may sleep).
*/
-
-void ata_host_remove(struct ata_host *host)
+void ata_host_detach(struct ata_host *host)
{
- unsigned int i;
+ int i;
for (i = 0; i < host->n_ports; i++)
ata_port_detach(host->ports[i]);
-
- free_irq(host->irq, host);
- if (host->irq2)
- free_irq(host->irq2, host);
-
- for (i = 0; i < host->n_ports; i++) {
- struct ata_port *ap = host->ports[i];
-
- ata_scsi_release(ap->scsi_host);
-
- if ((ap->flags & ATA_FLAG_NO_LEGACY) == 0) {
- struct ata_ioports *ioaddr = &ap->ioaddr;
-
- /* FIXME: Add -ac IDE pci mods to remove these special cases */
- if (ioaddr->cmd_addr == ATA_PRIMARY_CMD)
- release_region(ATA_PRIMARY_CMD, 8);
- else if (ioaddr->cmd_addr == ATA_SECONDARY_CMD)
- release_region(ATA_SECONDARY_CMD, 8);
- }
-
- scsi_host_put(ap->scsi_host);
- }
-
- if (host->ops->host_stop)
- host->ops->host_stop(host);
-
- kfree(host);
-}
-
-/**
- * ata_scsi_release - SCSI layer callback hook for host unload
- * @shost: libata host to be unloaded
- *
- * Performs all duties necessary to shut down a libata port...
- * Kill port kthread, disable port, and release resources.
- *
- * LOCKING:
- * Inherited from SCSI layer.
- *
- * RETURNS:
- * One.
- */
-
-int ata_scsi_release(struct Scsi_Host *shost)
-{
- struct ata_port *ap = ata_shost_to_port(shost);
-
- DPRINTK("ENTER\n");
-
- ap->ops->port_disable(ap);
- ap->ops->port_stop(ap);
-
- DPRINTK("EXIT\n");
- return 1;
}
struct ata_probe_ent *
@@ -6085,7 +5905,11 @@ ata_probe_ent_alloc(struct device *dev, const struct ata_port_info *port)
{
struct ata_probe_ent *probe_ent;
- probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL);
+ /* XXX - the following if can go away once all LLDs are managed */
+ if (!list_empty(&dev->devres_head))
+ probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL);
+ else
+ probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL);
if (!probe_ent) {
printk(KERN_ERR DRV_NAME "(%s): out of memory\n",
kobject_name(&(dev->kobj)));
@@ -6135,37 +5959,23 @@ void ata_std_ports(struct ata_ioports *ioaddr)
#ifdef CONFIG_PCI
-void ata_pci_host_stop (struct ata_host *host)
-{
- struct pci_dev *pdev = to_pci_dev(host->dev);
-
- pci_iounmap(pdev, host->mmio_base);
-}
-
/**
* ata_pci_remove_one - PCI layer callback for device removal
* @pdev: PCI device that was removed
*
- * PCI layer indicates to libata via this hook that
- * hot-unplug or module unload event has occurred.
- * Handle this by unregistering all objects associated
- * with this PCI device. Free those objects. Then finally
- * release PCI resources and disable device.
+ * PCI layer indicates to libata via this hook that hot-unplug or
+ * module unload event has occurred. Detach all ports. Resource
+ * release is handled via devres.
*
* LOCKING:
* Inherited from PCI layer (may sleep).
*/
-
-void ata_pci_remove_one (struct pci_dev *pdev)
+void ata_pci_remove_one(struct pci_dev *pdev)
{
struct device *dev = pci_dev_to_dev(pdev);
struct ata_host *host = dev_get_drvdata(dev);
- ata_host_remove(host);
-
- pci_release_regions(pdev);
- pci_disable_device(pdev);
- dev_set_drvdata(dev, NULL);
+ ata_host_detach(host);
}
/* move to PCI subsystem */
@@ -6212,12 +6022,22 @@ void ata_pci_device_do_suspend(struct pci_dev *pdev, pm_message_t mesg)
}
}
-void ata_pci_device_do_resume(struct pci_dev *pdev)
+int ata_pci_device_do_resume(struct pci_dev *pdev)
{
+ int rc;
+
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
- pci_enable_device(pdev);
+
+ rc = pcim_enable_device(pdev);
+ if (rc) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "failed to enable device after resume (%d)\n", rc);
+ return rc;
+ }
+
pci_set_master(pdev);
+ return 0;
}
int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
@@ -6237,10 +6057,12 @@ int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
int ata_pci_device_resume(struct pci_dev *pdev)
{
struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ int rc;
- ata_pci_device_do_resume(pdev);
- ata_host_resume(host);
- return 0;
+ rc = ata_pci_device_do_resume(pdev);
+ if (rc == 0)
+ ata_host_resume(host);
+ return rc;
}
#endif /* CONFIG_PCI */
@@ -6386,8 +6208,7 @@ EXPORT_SYMBOL_GPL(ata_std_bios_param);
EXPORT_SYMBOL_GPL(ata_std_ports);
EXPORT_SYMBOL_GPL(ata_host_init);
EXPORT_SYMBOL_GPL(ata_device_add);
-EXPORT_SYMBOL_GPL(ata_port_detach);
-EXPORT_SYMBOL_GPL(ata_host_remove);
+EXPORT_SYMBOL_GPL(ata_host_detach);
EXPORT_SYMBOL_GPL(ata_sg_init);
EXPORT_SYMBOL_GPL(ata_sg_init_one);
EXPORT_SYMBOL_GPL(ata_hsm_move);
@@ -6404,12 +6225,9 @@ EXPORT_SYMBOL_GPL(ata_check_status);
EXPORT_SYMBOL_GPL(ata_altstatus);
EXPORT_SYMBOL_GPL(ata_exec_command);
EXPORT_SYMBOL_GPL(ata_port_start);
-EXPORT_SYMBOL_GPL(ata_port_stop);
-EXPORT_SYMBOL_GPL(ata_host_stop);
EXPORT_SYMBOL_GPL(ata_interrupt);
-EXPORT_SYMBOL_GPL(ata_mmio_data_xfer);
-EXPORT_SYMBOL_GPL(ata_pio_data_xfer);
-EXPORT_SYMBOL_GPL(ata_pio_data_xfer_noirq);
+EXPORT_SYMBOL_GPL(ata_data_xfer);
+EXPORT_SYMBOL_GPL(ata_data_xfer_noirq);
EXPORT_SYMBOL_GPL(ata_qc_prep);
EXPORT_SYMBOL_GPL(ata_noop_qc_prep);
EXPORT_SYMBOL_GPL(ata_bmdma_setup);
@@ -6446,7 +6264,6 @@ EXPORT_SYMBOL_GPL(ata_scsi_queuecmd);
EXPORT_SYMBOL_GPL(ata_scsi_slave_config);
EXPORT_SYMBOL_GPL(ata_scsi_slave_destroy);
EXPORT_SYMBOL_GPL(ata_scsi_change_queue_depth);
-EXPORT_SYMBOL_GPL(ata_scsi_release);
EXPORT_SYMBOL_GPL(ata_host_intr);
EXPORT_SYMBOL_GPL(sata_scr_valid);
EXPORT_SYMBOL_GPL(sata_scr_read);
@@ -6467,7 +6284,6 @@ EXPORT_SYMBOL_GPL(ata_timing_merge);
#ifdef CONFIG_PCI
EXPORT_SYMBOL_GPL(pci_test_config_bits);
-EXPORT_SYMBOL_GPL(ata_pci_host_stop);
EXPORT_SYMBOL_GPL(ata_pci_init_native_mode);
EXPORT_SYMBOL_GPL(ata_pci_init_one);
EXPORT_SYMBOL_GPL(ata_pci_remove_one);
@@ -6491,3 +6307,7 @@ EXPORT_SYMBOL_GPL(ata_eh_thaw_port);
EXPORT_SYMBOL_GPL(ata_eh_qc_complete);
EXPORT_SYMBOL_GPL(ata_eh_qc_retry);
EXPORT_SYMBOL_GPL(ata_do_eh);
+EXPORT_SYMBOL_GPL(ata_irq_on);
+EXPORT_SYMBOL_GPL(ata_dummy_irq_on);
+EXPORT_SYMBOL_GPL(ata_irq_ack);
+EXPORT_SYMBOL_GPL(ata_dummy_irq_ack);
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 748435807d6..52c85af7fe9 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -1443,15 +1443,10 @@ static void ata_eh_report(struct ata_port *ap)
};
struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag);
struct ata_taskfile *cmd = &qc->tf, *res = &qc->result_tf;
- unsigned int nbytes;
if (!(qc->flags & ATA_QCFLAG_FAILED) || !qc->err_mask)
continue;
- nbytes = qc->nbytes;
- if (!nbytes)
- nbytes = qc->nsect << 9;
-
ata_dev_printk(qc->dev, KERN_ERR,
"cmd %02x/%02x:%02x:%02x:%02x:%02x/%02x:%02x:%02x:%02x:%02x/%02x "
"tag %d cdb 0x%x data %u %s\n "
@@ -1461,7 +1456,7 @@ static void ata_eh_report(struct ata_port *ap)
cmd->lbal, cmd->lbam, cmd->lbah,
cmd->hob_feature, cmd->hob_nsect,
cmd->hob_lbal, cmd->hob_lbam, cmd->hob_lbah,
- cmd->device, qc->tag, qc->cdb[0], nbytes,
+ cmd->device, qc->tag, qc->cdb[0], qc->nbytes,
dma_str[qc->dma_dir],
res->command, res->feature, res->nsect,
res->lbal, res->lbam, res->lbah,
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index 73902d33576..0009818a430 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -149,6 +149,45 @@ int ata_std_bios_param(struct scsi_device *sdev, struct block_device *bdev,
}
/**
+ * ata_get_identity - Handler for HDIO_GET_IDENTITY ioctl
+ * @sdev: SCSI device to get identify data for
+ * @arg: User buffer area for identify data
+ *
+ * LOCKING:
+ * Defined by the SCSI layer. We don't really care.
+ *
+ * RETURNS:
+ * Zero on success, negative errno on error.
+ */
+static int ata_get_identity(struct scsi_device *sdev, void __user *arg)
+{
+ struct ata_port *ap = ata_shost_to_port(sdev->host);
+ struct ata_device *dev = ata_scsi_find_dev(ap, sdev);
+ u16 __user *dst = arg;
+ char buf[40];
+
+ if (!dev)
+ return -ENOMSG;
+
+ if (copy_to_user(dst, dev->id, ATA_ID_WORDS * sizeof(u16)))
+ return -EFAULT;
+
+ ata_id_string(dev->id, buf, ATA_ID_PROD, ATA_ID_PROD_LEN);
+ if (copy_to_user(dst + ATA_ID_PROD, buf, ATA_ID_PROD_LEN))
+ return -EFAULT;
+
+ ata_id_string(dev->id, buf, ATA_ID_FW_REV, ATA_ID_FW_REV_LEN);
+ if (copy_to_user(dst + ATA_ID_FW_REV, buf, ATA_ID_FW_REV_LEN))
+ return -EFAULT;
+
+ ata_id_string(dev->id, buf, ATA_ID_SERNO, ATA_ID_SERNO_LEN);
+ if (copy_to_user(dst + ATA_ID_SERNO, buf, ATA_ID_SERNO_LEN))
+ return -EFAULT;
+
+ return 0;
+}
+
+/**
* ata_cmd_ioctl - Handler for HDIO_DRIVE_CMD ioctl
* @scsidev: Device to which we are issuing command
* @arg: User provided data for issuing command
@@ -159,7 +198,6 @@ int ata_std_bios_param(struct scsi_device *sdev, struct block_device *bdev,
* RETURNS:
* Zero on success, negative errno on error.
*/
-
int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg)
{
int rc = 0;
@@ -359,6 +397,9 @@ int ata_scsi_ioctl(struct scsi_device *scsidev, int cmd, void __user *arg)
return -EINVAL;
return 0;
+ case HDIO_GET_IDENTITY:
+ return ata_get_identity(scsidev, arg);
+
case HDIO_DRIVE_CMD:
if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
return -EACCES;
@@ -397,9 +438,9 @@ int ata_scsi_ioctl(struct scsi_device *scsidev, int cmd, void __user *arg)
* RETURNS:
* Command allocated, or %NULL if none available.
*/
-struct ata_queued_cmd *ata_scsi_qc_new(struct ata_device *dev,
- struct scsi_cmnd *cmd,
- void (*done)(struct scsi_cmnd *))
+static struct ata_queued_cmd *ata_scsi_qc_new(struct ata_device *dev,
+ struct scsi_cmnd *cmd,
+ void (*done)(struct scsi_cmnd *))
{
struct ata_queued_cmd *qc;
@@ -435,7 +476,7 @@ struct ata_queued_cmd *ata_scsi_qc_new(struct ata_device *dev,
* LOCKING:
* inherited from caller
*/
-void ata_dump_status(unsigned id, struct ata_taskfile *tf)
+static void ata_dump_status(unsigned id, struct ata_taskfile *tf)
{
u8 stat = tf->command, err = tf->feature;
@@ -610,8 +651,8 @@ int ata_scsi_device_resume(struct scsi_device *sdev)
* LOCKING:
* spin_lock_irqsave(host lock)
*/
-void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk, u8 *asc,
- u8 *ascq, int verbose)
+static void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk,
+ u8 *asc, u8 *ascq, int verbose)
{
int i;
@@ -1359,7 +1400,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc)
goto nothing_to_do;
qc->flags |= ATA_QCFLAG_IO;
- qc->nsect = n_block;
+ qc->nbytes = n_block * ATA_SECT_SIZE;
rc = ata_build_rw_tf(&qc->tf, qc->dev, block, n_block, tf_flags,
qc->tag);
@@ -1698,8 +1739,8 @@ unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf,
if (buflen > 35) {
memcpy(&rbuf[8], "ATA ", 8);
- ata_id_string(args->id, &rbuf[16], ATA_ID_PROD_OFS, 16);
- ata_id_string(args->id, &rbuf[32], ATA_ID_FW_REV_OFS, 4);
+ ata_id_string(args->id, &rbuf[16], ATA_ID_PROD, 16);
+ ata_id_string(args->id, &rbuf[32], ATA_ID_FW_REV, 4);
if (rbuf[32] == 0 || rbuf[32] == ' ')
memcpy(&rbuf[32], "n/a ", 4);
}
@@ -1768,13 +1809,13 @@ unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf,
0,
0x80, /* this page code */
0,
- ATA_SERNO_LEN, /* page len */
+ ATA_ID_SERNO_LEN, /* page len */
};
memcpy(rbuf, hdr, sizeof(hdr));
- if (buflen > (ATA_SERNO_LEN + 4 - 1))
+ if (buflen > (ATA_ID_SERNO_LEN + 4 - 1))
ata_id_string(args->id, (unsigned char *) &rbuf[4],
- ATA_ID_SERNO_OFS, ATA_SERNO_LEN);
+ ATA_ID_SERNO, ATA_ID_SERNO_LEN);
return 0;
}
@@ -1799,19 +1840,18 @@ unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf,
{
int num;
const int sat_model_serial_desc_len = 68;
- const int ata_model_byte_len = 40;
rbuf[1] = 0x83; /* this page code */
num = 4;
- if (buflen > (ATA_SERNO_LEN + num + 3)) {
+ if (buflen > (ATA_ID_SERNO_LEN + num + 3)) {
/* piv=0, assoc=lu, code_set=ACSII, designator=vendor */
rbuf[num + 0] = 2;
- rbuf[num + 3] = ATA_SERNO_LEN;
+ rbuf[num + 3] = ATA_ID_SERNO_LEN;
num += 4;
ata_id_string(args->id, (unsigned char *) rbuf + num,
- ATA_ID_SERNO_OFS, ATA_SERNO_LEN);
- num += ATA_SERNO_LEN;
+ ATA_ID_SERNO, ATA_ID_SERNO_LEN);
+ num += ATA_ID_SERNO_LEN;
}
if (buflen > (sat_model_serial_desc_len + num + 3)) {
/* SAT defined lu model and serial numbers descriptor */
@@ -1823,11 +1863,11 @@ unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf,
memcpy(rbuf + num, "ATA ", 8);
num += 8;
ata_id_string(args->id, (unsigned char *) rbuf + num,
- ATA_ID_PROD_OFS, ata_model_byte_len);
- num += ata_model_byte_len;
+ ATA_ID_PROD, ATA_ID_PROD_LEN);
+ num += ATA_ID_PROD_LEN;
ata_id_string(args->id, (unsigned char *) rbuf + num,
- ATA_ID_SERNO_OFS, ATA_SERNO_LEN);
- num += ATA_SERNO_LEN;
+ ATA_ID_SERNO, ATA_ID_SERNO_LEN);
+ num += ATA_ID_SERNO_LEN;
}
rbuf[3] = num - 4; /* page len (assume less than 256 bytes) */
return 0;
@@ -1955,15 +1995,15 @@ static unsigned int ata_msense_rw_recovery(u8 **ptr_io, const u8 *last)
*/
static int ata_dev_supports_fua(u16 *id)
{
- unsigned char model[41], fw[9];
+ unsigned char model[ATA_ID_PROD_LEN + 1], fw[ATA_ID_FW_REV_LEN + 1];
if (!libata_fua)
return 0;
if (!ata_id_has_fua(id))
return 0;
- ata_id_c_string(id, model, ATA_ID_PROD_OFS, sizeof(model));
- ata_id_c_string(id, fw, ATA_ID_FW_REV_OFS, sizeof(fw));
+ ata_id_c_string(id, model, ATA_ID_PROD, sizeof(model));
+ ata_id_c_string(id, fw, ATA_ID_FW_REV, sizeof(fw));
if (strcmp(model, "Maxtor"))
return 1;
@@ -2661,7 +2701,7 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
* TODO: find out if we need to do more here to
* cover scatter/gather case.
*/
- qc->nsect = scmd->request_bufflen / ATA_SECT_SIZE;
+ qc->nbytes = scmd->request_bufflen;
/* request result TF */
qc->flags |= ATA_QCFLAG_RESULT_TF;
@@ -3059,7 +3099,8 @@ void ata_scsi_hotplug(struct work_struct *work)
for (i = 0; i < ATA_MAX_DEVICES; i++) {
struct ata_device *dev = &ap->device[i];
if (ata_dev_enabled(dev) && !dev->sdev) {
- queue_delayed_work(ata_aux_wq, &ap->hotplug_task, HZ);
+ queue_delayed_work(ata_aux_wq, &ap->hotplug_task,
+ round_jiffies_relative(HZ));
break;
}
}
@@ -3264,7 +3305,8 @@ EXPORT_SYMBOL_GPL(ata_sas_port_init);
void ata_sas_port_destroy(struct ata_port *ap)
{
- ap->ops->port_stop(ap);
+ if (ap->ops->port_stop)
+ ap->ops->port_stop(ap);
kfree(ap);
}
EXPORT_SYMBOL_GPL(ata_sas_port_destroy);
diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c
index 12c88c58803..16bc3e35bdd 100644
--- a/drivers/ata/libata-sff.c
+++ b/drivers/ata/libata-sff.c
@@ -56,10 +56,7 @@ u8 ata_irq_on(struct ata_port *ap)
ap->ctl &= ~ATA_NIEN;
ap->last_ctl = ap->ctl;
- if (ap->flags & ATA_FLAG_MMIO)
- writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr);
- else
- outb(ap->ctl, ioaddr->ctl_addr);
+ iowrite8(ap->ctl, ioaddr->ctl_addr);
tmp = ata_wait_idle(ap);
ap->ops->irq_clear(ap);
@@ -67,92 +64,74 @@ u8 ata_irq_on(struct ata_port *ap)
return tmp;
}
+u8 ata_dummy_irq_on (struct ata_port *ap) { return 0; }
+
/**
- * ata_tf_load_pio - send taskfile registers to host controller
- * @ap: Port to which output is sent
- * @tf: ATA taskfile register set
+ * ata_irq_ack - Acknowledge a device interrupt.
+ * @ap: Port on which interrupts are enabled.
*
- * Outputs ATA taskfile to standard ATA host controller.
+ * Wait up to 10 ms for legacy IDE device to become idle (BUSY
+ * or BUSY+DRQ clear). Obtain dma status and port status from
+ * device. Clear the interrupt. Return port status.
*
* LOCKING:
- * Inherited from caller.
*/
-static void ata_tf_load_pio(struct ata_port *ap, const struct ata_taskfile *tf)
+u8 ata_irq_ack(struct ata_port *ap, unsigned int chk_drq)
{
- struct ata_ioports *ioaddr = &ap->ioaddr;
- unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
+ unsigned int bits = chk_drq ? ATA_BUSY | ATA_DRQ : ATA_BUSY;
+ u8 host_stat, post_stat, status;
- if (tf->ctl != ap->last_ctl) {
- outb(tf->ctl, ioaddr->ctl_addr);
- ap->last_ctl = tf->ctl;
- ata_wait_idle(ap);
- }
+ status = ata_busy_wait(ap, bits, 1000);
+ if (status & bits)
+ if (ata_msg_err(ap))
+ printk(KERN_ERR "abnormal status 0x%X\n", status);
- if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
- outb(tf->hob_feature, ioaddr->feature_addr);
- outb(tf->hob_nsect, ioaddr->nsect_addr);
- outb(tf->hob_lbal, ioaddr->lbal_addr);
- outb(tf->hob_lbam, ioaddr->lbam_addr);
- outb(tf->hob_lbah, ioaddr->lbah_addr);
- VPRINTK("hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n",
- tf->hob_feature,
- tf->hob_nsect,
- tf->hob_lbal,
- tf->hob_lbam,
- tf->hob_lbah);
- }
+ /* get controller status; clear intr, err bits */
+ host_stat = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
+ iowrite8(host_stat | ATA_DMA_INTR | ATA_DMA_ERR,
+ ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
- if (is_addr) {
- outb(tf->feature, ioaddr->feature_addr);
- outb(tf->nsect, ioaddr->nsect_addr);
- outb(tf->lbal, ioaddr->lbal_addr);
- outb(tf->lbam, ioaddr->lbam_addr);
- outb(tf->lbah, ioaddr->lbah_addr);
- VPRINTK("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n",
- tf->feature,
- tf->nsect,
- tf->lbal,
- tf->lbam,
- tf->lbah);
- }
+ post_stat = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
- if (tf->flags & ATA_TFLAG_DEVICE) {
- outb(tf->device, ioaddr->device_addr);
- VPRINTK("device 0x%X\n", tf->device);
- }
+ if (ata_msg_intr(ap))
+ printk(KERN_INFO "%s: irq ack: host_stat 0x%X, new host_stat 0x%X, drv_stat 0x%X\n",
+ __FUNCTION__,
+ host_stat, post_stat, status);
- ata_wait_idle(ap);
+ return status;
}
+u8 ata_dummy_irq_ack(struct ata_port *ap, unsigned int chk_drq) { return 0; }
+
/**
- * ata_tf_load_mmio - send taskfile registers to host controller
+ * ata_tf_load - send taskfile registers to host controller
* @ap: Port to which output is sent
* @tf: ATA taskfile register set
*
- * Outputs ATA taskfile to standard ATA host controller using MMIO.
+ * Outputs ATA taskfile to standard ATA host controller.
*
* LOCKING:
* Inherited from caller.
*/
-static void ata_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
+void ata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
{
struct ata_ioports *ioaddr = &ap->ioaddr;
unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
if (tf->ctl != ap->last_ctl) {
- writeb(tf->ctl, (void __iomem *) ap->ioaddr.ctl_addr);
+ iowrite8(tf->ctl, ioaddr->ctl_addr);
ap->last_ctl = tf->ctl;
ata_wait_idle(ap);
}
if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
- writeb(tf->hob_feature, (void __iomem *) ioaddr->feature_addr);
- writeb(tf->hob_nsect, (void __iomem *) ioaddr->nsect_addr);
- writeb(tf->hob_lbal, (void __iomem *) ioaddr->lbal_addr);
- writeb(tf->hob_lbam, (void __iomem *) ioaddr->lbam_addr);
- writeb(tf->hob_lbah, (void __iomem *) ioaddr->lbah_addr);
+ iowrite8(tf->hob_feature, ioaddr->feature_addr);
+ iowrite8(tf->hob_nsect, ioaddr->nsect_addr);
+ iowrite8(tf->hob_lbal, ioaddr->lbal_addr);
+ iowrite8(tf->hob_lbam, ioaddr->lbam_addr);
+ iowrite8(tf->hob_lbah, ioaddr->lbah_addr);
VPRINTK("hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n",
tf->hob_feature,
tf->hob_nsect,
@@ -162,11 +141,11 @@ static void ata_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
}
if (is_addr) {
- writeb(tf->feature, (void __iomem *) ioaddr->feature_addr);
- writeb(tf->nsect, (void __iomem *) ioaddr->nsect_addr);
- writeb(tf->lbal, (void __iomem *) ioaddr->lbal_addr);
- writeb(tf->lbam, (void __iomem *) ioaddr->lbam_addr);
- writeb(tf->lbah, (void __iomem *) ioaddr->lbah_addr);
+ iowrite8(tf->feature, ioaddr->feature_addr);
+ iowrite8(tf->nsect, ioaddr->nsect_addr);
+ iowrite8(tf->lbal, ioaddr->lbal_addr);
+ iowrite8(tf->lbam, ioaddr->lbam_addr);
+ iowrite8(tf->lbah, ioaddr->lbah_addr);
VPRINTK("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n",
tf->feature,
tf->nsect,
@@ -176,108 +155,34 @@ static void ata_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
}
if (tf->flags & ATA_TFLAG_DEVICE) {
- writeb(tf->device, (void __iomem *) ioaddr->device_addr);
+ iowrite8(tf->device, ioaddr->device_addr);
VPRINTK("device 0x%X\n", tf->device);
}
ata_wait_idle(ap);
}
-
-/**
- * ata_tf_load - send taskfile registers to host controller
- * @ap: Port to which output is sent
- * @tf: ATA taskfile register set
- *
- * Outputs ATA taskfile to standard ATA host controller using MMIO
- * or PIO as indicated by the ATA_FLAG_MMIO flag.
- * Writes the control, feature, nsect, lbal, lbam, and lbah registers.
- * Optionally (ATA_TFLAG_LBA48) writes hob_feature, hob_nsect,
- * hob_lbal, hob_lbam, and hob_lbah.
- *
- * This function waits for idle (!BUSY and !DRQ) after writing
- * registers. If the control register has a new value, this
- * function also waits for idle after writing control and before
- * writing the remaining registers.
- *
- * May be used as the tf_load() entry in ata_port_operations.
- *
- * LOCKING:
- * Inherited from caller.
- */
-void ata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
-{
- if (ap->flags & ATA_FLAG_MMIO)
- ata_tf_load_mmio(ap, tf);
- else
- ata_tf_load_pio(ap, tf);
-}
-
/**
- * ata_exec_command_pio - issue ATA command to host controller
- * @ap: port to which command is being issued
- * @tf: ATA taskfile register set
- *
- * Issues PIO write to ATA command register, with proper
- * synchronization with interrupt handler / other threads.
- *
- * LOCKING:
- * spin_lock_irqsave(host lock)
- */
-
-static void ata_exec_command_pio(struct ata_port *ap, const struct ata_taskfile *tf)
-{
- DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command);
-
- outb(tf->command, ap->ioaddr.command_addr);
- ata_pause(ap);
-}
-
-
-/**
- * ata_exec_command_mmio - issue ATA command to host controller
+ * ata_exec_command - issue ATA command to host controller
* @ap: port to which command is being issued
* @tf: ATA taskfile register set
*
- * Issues MMIO write to ATA command register, with proper
- * synchronization with interrupt handler / other threads.
- *
- * FIXME: missing write posting for 400nS delay enforcement
+ * Issues ATA command, with proper synchronization with interrupt
+ * handler / other threads.
*
* LOCKING:
* spin_lock_irqsave(host lock)
*/
-
-static void ata_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
+void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf)
{
DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command);
- writeb(tf->command, (void __iomem *) ap->ioaddr.command_addr);
+ iowrite8(tf->command, ap->ioaddr.command_addr);
ata_pause(ap);
}
-
-/**
- * ata_exec_command - issue ATA command to host controller
- * @ap: port to which command is being issued
- * @tf: ATA taskfile register set
- *
- * Issues PIO/MMIO write to ATA command register, with proper
- * synchronization with interrupt handler / other threads.
- *
- * LOCKING:
- * spin_lock_irqsave(host lock)
- */
-void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf)
-{
- if (ap->flags & ATA_FLAG_MMIO)
- ata_exec_command_mmio(ap, tf);
- else
- ata_exec_command_pio(ap, tf);
-}
-
/**
- * ata_tf_read_pio - input device's ATA taskfile shadow registers
+ * ata_tf_read - input device's ATA taskfile shadow registers
* @ap: Port from which input is read
* @tf: ATA taskfile register set for storing input
*
@@ -287,121 +192,28 @@ void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf)
* LOCKING:
* Inherited from caller.
*/
-
-static void ata_tf_read_pio(struct ata_port *ap, struct ata_taskfile *tf)
-{
- struct ata_ioports *ioaddr = &ap->ioaddr;
-
- tf->command = ata_check_status(ap);
- tf->feature = inb(ioaddr->error_addr);
- tf->nsect = inb(ioaddr->nsect_addr);
- tf->lbal = inb(ioaddr->lbal_addr);
- tf->lbam = inb(ioaddr->lbam_addr);
- tf->lbah = inb(ioaddr->lbah_addr);
- tf->device = inb(ioaddr->device_addr);
-
- if (tf->flags & ATA_TFLAG_LBA48) {
- outb(tf->ctl | ATA_HOB, ioaddr->ctl_addr);
- tf->hob_feature = inb(ioaddr->error_addr);
- tf->hob_nsect = inb(ioaddr->nsect_addr);
- tf->hob_lbal = inb(ioaddr->lbal_addr);
- tf->hob_lbam = inb(ioaddr->lbam_addr);
- tf->hob_lbah = inb(ioaddr->lbah_addr);
- }
-}
-
-/**
- * ata_tf_read_mmio - input device's ATA taskfile shadow registers
- * @ap: Port from which input is read
- * @tf: ATA taskfile register set for storing input
- *
- * Reads ATA taskfile registers for currently-selected device
- * into @tf via MMIO.
- *
- * LOCKING:
- * Inherited from caller.
- */
-
-static void ata_tf_read_mmio(struct ata_port *ap, struct ata_taskfile *tf)
+void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
{
struct ata_ioports *ioaddr = &ap->ioaddr;
tf->command = ata_check_status(ap);
- tf->feature = readb((void __iomem *)ioaddr->error_addr);
- tf->nsect = readb((void __iomem *)ioaddr->nsect_addr);
- tf->lbal = readb((void __iomem *)ioaddr->lbal_addr);
- tf->lbam = readb((void __iomem *)ioaddr->lbam_addr);
- tf->lbah = readb((void __iomem *)ioaddr->lbah_addr);
- tf->device = readb((void __iomem *)ioaddr->device_addr);
+ tf->feature = ioread8(ioaddr->error_addr);
+ tf->nsect = ioread8(ioaddr->nsect_addr);
+ tf->lbal = ioread8(ioaddr->lbal_addr);
+ tf->lbam = ioread8(ioaddr->lbam_addr);
+ tf->lbah = ioread8(ioaddr->lbah_addr);
+ tf->device = ioread8(ioaddr->device_addr);
if (tf->flags & ATA_TFLAG_LBA48) {
- writeb(tf->ctl | ATA_HOB, (void __iomem *) ap->ioaddr.ctl_addr);
- tf->hob_feature = readb((void __iomem *)ioaddr->error_addr);
- tf->hob_nsect = readb((void __iomem *)ioaddr->nsect_addr);
- tf->hob_lbal = readb((void __iomem *)ioaddr->lbal_addr);
- tf->hob_lbam = readb((void __iomem *)ioaddr->lbam_addr);
- tf->hob_lbah = readb((void __iomem *)ioaddr->lbah_addr);
+ iowrite8(tf->ctl | ATA_HOB, ioaddr->ctl_addr);
+ tf->hob_feature = ioread8(ioaddr->error_addr);
+ tf->hob_nsect = ioread8(ioaddr->nsect_addr);
+ tf->hob_lbal = ioread8(ioaddr->lbal_addr);
+ tf->hob_lbam = ioread8(ioaddr->lbam_addr);
+ tf->hob_lbah = ioread8(ioaddr->lbah_addr);
}
}
-
-/**
- * ata_tf_read - input device's ATA taskfile shadow registers
- * @ap: Port from which input is read
- * @tf: ATA taskfile register set for storing input
- *
- * Reads ATA taskfile registers for currently-selected device
- * into @tf.
- *
- * Reads nsect, lbal, lbam, lbah, and device. If ATA_TFLAG_LBA48
- * is set, also reads the hob registers.
- *
- * May be used as the tf_read() entry in ata_port_operations.
- *
- * LOCKING:
- * Inherited from caller.
- */
-void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
-{
- if (ap->flags & ATA_FLAG_MMIO)
- ata_tf_read_mmio(ap, tf);
- else
- ata_tf_read_pio(ap, tf);
-}
-
-/**
- * ata_check_status_pio - Read device status reg & clear interrupt
- * @ap: port where the device is
- *
- * Reads ATA taskfile status register for currently-selected device
- * and return its value. This also clears pending interrupts
- * from this device
- *
- * LOCKING:
- * Inherited from caller.
- */
-static u8 ata_check_status_pio(struct ata_port *ap)
-{
- return inb(ap->ioaddr.status_addr);
-}
-
-/**
- * ata_check_status_mmio - Read device status reg & clear interrupt
- * @ap: port where the device is
- *
- * Reads ATA taskfile status register for currently-selected device
- * via MMIO and return its value. This also clears pending interrupts
- * from this device
- *
- * LOCKING:
- * Inherited from caller.
- */
-static u8 ata_check_status_mmio(struct ata_port *ap)
-{
- return readb((void __iomem *) ap->ioaddr.status_addr);
-}
-
-
/**
* ata_check_status - Read device status reg & clear interrupt
* @ap: port where the device is
@@ -410,19 +222,14 @@ static u8 ata_check_status_mmio(struct ata_port *ap)
* and return its value. This also clears pending interrupts
* from this device
*
- * May be used as the check_status() entry in ata_port_operations.
- *
* LOCKING:
* Inherited from caller.
*/
u8 ata_check_status(struct ata_port *ap)
{
- if (ap->flags & ATA_FLAG_MMIO)
- return ata_check_status_mmio(ap);
- return ata_check_status_pio(ap);
+ return ioread8(ap->ioaddr.status_addr);
}
-
/**
* ata_altstatus - Read device alternate status reg
* @ap: port where the device is
@@ -441,58 +248,52 @@ u8 ata_altstatus(struct ata_port *ap)
if (ap->ops->check_altstatus)
return ap->ops->check_altstatus(ap);
- if (ap->flags & ATA_FLAG_MMIO)
- return readb((void __iomem *)ap->ioaddr.altstatus_addr);
- return inb(ap->ioaddr.altstatus_addr);
+ return ioread8(ap->ioaddr.altstatus_addr);
}
/**
- * ata_bmdma_setup_mmio - Set up PCI IDE BMDMA transaction
+ * ata_bmdma_setup - Set up PCI IDE BMDMA transaction
* @qc: Info associated with this ATA transaction.
*
* LOCKING:
* spin_lock_irqsave(host lock)
*/
-
-static void ata_bmdma_setup_mmio (struct ata_queued_cmd *qc)
+void ata_bmdma_setup(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
u8 dmactl;
- void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr;
/* load PRD table addr. */
mb(); /* make sure PRD table writes are visible to controller */
- writel(ap->prd_dma, mmio + ATA_DMA_TABLE_OFS);
+ iowrite32(ap->prd_dma, ap->ioaddr.bmdma_addr + ATA_DMA_TABLE_OFS);
/* specify data direction, triple-check start bit is clear */
- dmactl = readb(mmio + ATA_DMA_CMD);
+ dmactl = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
dmactl &= ~(ATA_DMA_WR | ATA_DMA_START);
if (!rw)
dmactl |= ATA_DMA_WR;
- writeb(dmactl, mmio + ATA_DMA_CMD);
+ iowrite8(dmactl, ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
/* issue r/w command */
ap->ops->exec_command(ap, &qc->tf);
}
/**
- * ata_bmdma_start_mmio - Start a PCI IDE BMDMA transaction
+ * ata_bmdma_start - Start a PCI IDE BMDMA transaction
* @qc: Info associated with this ATA transaction.
*
* LOCKING:
* spin_lock_irqsave(host lock)
*/
-
-static void ata_bmdma_start_mmio (struct ata_queued_cmd *qc)
+void ata_bmdma_start (struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
- void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr;
u8 dmactl;
/* start host DMA transaction */
- dmactl = readb(mmio + ATA_DMA_CMD);
- writeb(dmactl | ATA_DMA_START, mmio + ATA_DMA_CMD);
+ dmactl = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+ iowrite8(dmactl | ATA_DMA_START, ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
/* Strictly, one may wish to issue a readb() here, to
* flush the mmio write. However, control also passes
@@ -508,96 +309,6 @@ static void ata_bmdma_start_mmio (struct ata_queued_cmd *qc)
}
/**
- * ata_bmdma_setup_pio - Set up PCI IDE BMDMA transaction (PIO)
- * @qc: Info associated with this ATA transaction.
- *
- * LOCKING:
- * spin_lock_irqsave(host lock)
- */
-
-static void ata_bmdma_setup_pio (struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
- u8 dmactl;
-
- /* load PRD table addr. */
- outl(ap->prd_dma, ap->ioaddr.bmdma_addr + ATA_DMA_TABLE_OFS);
-
- /* specify data direction, triple-check start bit is clear */
- dmactl = inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
- dmactl &= ~(ATA_DMA_WR | ATA_DMA_START);
- if (!rw)
- dmactl |= ATA_DMA_WR;
- outb(dmactl, ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
-
- /* issue r/w command */
- ap->ops->exec_command(ap, &qc->tf);
-}
-
-/**
- * ata_bmdma_start_pio - Start a PCI IDE BMDMA transaction (PIO)
- * @qc: Info associated with this ATA transaction.
- *
- * LOCKING:
- * spin_lock_irqsave(host lock)
- */
-
-static void ata_bmdma_start_pio (struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- u8 dmactl;
-
- /* start host DMA transaction */
- dmactl = inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
- outb(dmactl | ATA_DMA_START,
- ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
-}
-
-
-/**
- * ata_bmdma_start - Start a PCI IDE BMDMA transaction
- * @qc: Info associated with this ATA transaction.
- *
- * Writes the ATA_DMA_START flag to the DMA command register.
- *
- * May be used as the bmdma_start() entry in ata_port_operations.
- *
- * LOCKING:
- * spin_lock_irqsave(host lock)
- */
-void ata_bmdma_start(struct ata_queued_cmd *qc)
-{
- if (qc->ap->flags & ATA_FLAG_MMIO)
- ata_bmdma_start_mmio(qc);
- else
- ata_bmdma_start_pio(qc);
-}
-
-
-/**
- * ata_bmdma_setup - Set up PCI IDE BMDMA transaction
- * @qc: Info associated with this ATA transaction.
- *
- * Writes address of PRD table to device's PRD Table Address
- * register, sets the DMA control register, and calls
- * ops->exec_command() to start the transfer.
- *
- * May be used as the bmdma_setup() entry in ata_port_operations.
- *
- * LOCKING:
- * spin_lock_irqsave(host lock)
- */
-void ata_bmdma_setup(struct ata_queued_cmd *qc)
-{
- if (qc->ap->flags & ATA_FLAG_MMIO)
- ata_bmdma_setup_mmio(qc);
- else
- ata_bmdma_setup_pio(qc);
-}
-
-
-/**
* ata_bmdma_irq_clear - Clear PCI IDE BMDMA interrupt.
* @ap: Port associated with this ATA transaction.
*
@@ -608,23 +319,16 @@ void ata_bmdma_setup(struct ata_queued_cmd *qc)
* LOCKING:
* spin_lock_irqsave(host lock)
*/
-
void ata_bmdma_irq_clear(struct ata_port *ap)
{
- if (!ap->ioaddr.bmdma_addr)
+ void __iomem *mmio = ap->ioaddr.bmdma_addr;
+
+ if (!mmio)
return;
- if (ap->flags & ATA_FLAG_MMIO) {
- void __iomem *mmio =
- ((void __iomem *) ap->ioaddr.bmdma_addr) + ATA_DMA_STATUS;
- writeb(readb(mmio), mmio);
- } else {
- unsigned long addr = ap->ioaddr.bmdma_addr + ATA_DMA_STATUS;
- outb(inb(addr), addr);
- }
+ iowrite8(ioread8(mmio + ATA_DMA_STATUS), mmio + ATA_DMA_STATUS);
}
-
/**
* ata_bmdma_status - Read PCI IDE BMDMA status
* @ap: Port associated with this ATA transaction.
@@ -636,19 +340,11 @@ void ata_bmdma_irq_clear(struct ata_port *ap)
* LOCKING:
* spin_lock_irqsave(host lock)
*/
-
u8 ata_bmdma_status(struct ata_port *ap)
{
- u8 host_stat;
- if (ap->flags & ATA_FLAG_MMIO) {
- void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr;
- host_stat = readb(mmio + ATA_DMA_STATUS);
- } else
- host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
- return host_stat;
+ return ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
}
-
/**
* ata_bmdma_stop - Stop PCI IDE BMDMA transfer
* @qc: Command we are ending DMA for
@@ -660,21 +356,14 @@ u8 ata_bmdma_status(struct ata_port *ap)
* LOCKING:
* spin_lock_irqsave(host lock)
*/
-
void ata_bmdma_stop(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
- if (ap->flags & ATA_FLAG_MMIO) {
- void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr;
+ void __iomem *mmio = ap->ioaddr.bmdma_addr;
- /* clear start/stop bit */
- writeb(readb(mmio + ATA_DMA_CMD) & ~ATA_DMA_START,
- mmio + ATA_DMA_CMD);
- } else {
- /* clear start/stop bit */
- outb(inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD) & ~ATA_DMA_START,
- ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
- }
+ /* clear start/stop bit */
+ iowrite8(ioread8(mmio + ATA_DMA_CMD) & ~ATA_DMA_START,
+ mmio + ATA_DMA_CMD);
/* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */
ata_altstatus(ap); /* dummy read */
@@ -696,10 +385,7 @@ void ata_bmdma_freeze(struct ata_port *ap)
ap->ctl |= ATA_NIEN;
ap->last_ctl = ap->ctl;
- if (ap->flags & ATA_FLAG_MMIO)
- writeb(ap->ctl, (void __iomem *)ioaddr->ctl_addr);
- else
- outb(ap->ctl, ioaddr->ctl_addr);
+ iowrite8(ap->ctl, ioaddr->ctl_addr);
/* Under certain circumstances, some controllers raise IRQ on
* ATA_NIEN manipulation. Also, many controllers fail to mask
@@ -724,8 +410,7 @@ void ata_bmdma_thaw(struct ata_port *ap)
/* clear & re-enable interrupts */
ata_chk_status(ap);
ap->ops->irq_clear(ap);
- if (ap->ioaddr.ctl_addr) /* FIXME: hack. create a hook instead */
- ata_irq_on(ap);
+ ap->ops->irq_on(ap);
}
/**
@@ -775,7 +460,7 @@ void ata_bmdma_drive_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
* really a timeout event, adjust error mask and
* cancel frozen state.
*/
- if (qc->err_mask == AC_ERR_TIMEOUT && host_stat & ATA_DMA_ERR) {
+ if (qc->err_mask == AC_ERR_TIMEOUT && (host_stat & ATA_DMA_ERR)) {
qc->err_mask = AC_ERR_HOST_BUS;
thaw = 1;
}
@@ -832,6 +517,21 @@ void ata_bmdma_post_internal_cmd(struct ata_queued_cmd *qc)
}
#ifdef CONFIG_PCI
+
+static int ata_resources_present(struct pci_dev *pdev, int port)
+{
+ int i;
+
+ /* Check the PCI resources for this channel are enabled */
+ port = port * 2;
+ for (i = 0; i < 2; i ++) {
+ if (pci_resource_start(pdev, port + i) == 0 ||
+ pci_resource_len(pdev, port + i) == 0)
+ return 0;
+ }
+ return 1;
+}
+
/**
* ata_pci_init_native_mode - Initialize native-mode driver
* @pdev: pci device to be initialized
@@ -853,45 +553,62 @@ void ata_bmdma_post_internal_cmd(struct ata_queued_cmd *qc)
struct ata_probe_ent *
ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int ports)
{
- struct ata_probe_ent *probe_ent =
- ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[0]);
- int p = 0;
- unsigned long bmdma;
+ struct ata_probe_ent *probe_ent;
+ int i, p = 0;
+ void __iomem * const *iomap;
+
+ /* iomap BARs */
+ for (i = 0; i < 4; i++) {
+ if (pcim_iomap(pdev, i, 0) == NULL) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "failed to iomap PCI BAR %d\n", i);
+ return NULL;
+ }
+ }
+ pcim_iomap(pdev, 4, 0); /* may fail */
+ iomap = pcim_iomap_table(pdev);
+
+ /* alloc and init probe_ent */
+ probe_ent = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[0]);
if (!probe_ent)
return NULL;
probe_ent->irq = pdev->irq;
probe_ent->irq_flags = IRQF_SHARED;
+
+ /* Discard disabled ports. Some controllers show their
+ unused channels this way */
+ if (ata_resources_present(pdev, 0) == 0)
+ ports &= ~ATA_PORT_PRIMARY;
+ if (ata_resources_present(pdev, 1) == 0)
+ ports &= ~ATA_PORT_SECONDARY;
if (ports & ATA_PORT_PRIMARY) {
- probe_ent->port[p].cmd_addr = pci_resource_start(pdev, 0);
+ probe_ent->port[p].cmd_addr = iomap[0];
probe_ent->port[p].altstatus_addr =
- probe_ent->port[p].ctl_addr =
- pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS;
- bmdma = pci_resource_start(pdev, 4);
- if (bmdma) {
+ probe_ent->port[p].ctl_addr = (void __iomem *)
+ ((unsigned long)iomap[1] | ATA_PCI_CTL_OFS);
+ if (iomap[4]) {
if ((!(port[p]->flags & ATA_FLAG_IGN_SIMPLEX)) &&
- (inb(bmdma + 2) & 0x80))
+ (ioread8(iomap[4] + 2) & 0x80))
probe_ent->_host_flags |= ATA_HOST_SIMPLEX;
- probe_ent->port[p].bmdma_addr = bmdma;
+ probe_ent->port[p].bmdma_addr = iomap[4];
}
ata_std_ports(&probe_ent->port[p]);
p++;
}
if (ports & ATA_PORT_SECONDARY) {
- probe_ent->port[p].cmd_addr = pci_resource_start(pdev, 2);
+ probe_ent->port[p].cmd_addr = iomap[2];
probe_ent->port[p].altstatus_addr =
- probe_ent->port[p].ctl_addr =
- pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS;
- bmdma = pci_resource_start(pdev, 4);
- if (bmdma) {
- bmdma += 8;
+ probe_ent->port[p].ctl_addr = (void __iomem *)
+ ((unsigned long)iomap[3] | ATA_PCI_CTL_OFS);
+ if (iomap[4]) {
if ((!(port[p]->flags & ATA_FLAG_IGN_SIMPLEX)) &&
- (inb(bmdma + 2) & 0x80))
+ (ioread8(iomap[4] + 10) & 0x80))
probe_ent->_host_flags |= ATA_HOST_SIMPLEX;
- probe_ent->port[p].bmdma_addr = bmdma;
+ probe_ent->port[p].bmdma_addr = iomap[4] + 8;
}
ata_std_ports(&probe_ent->port[p]);
probe_ent->pinfo2 = port[1];
@@ -902,13 +619,29 @@ ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int
return probe_ent;
}
-
static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev,
struct ata_port_info **port, int port_mask)
{
struct ata_probe_ent *probe_ent;
- unsigned long bmdma = pci_resource_start(pdev, 4);
+ void __iomem *iomap[5] = { }, *bmdma;
+
+ if (port_mask & ATA_PORT_PRIMARY) {
+ iomap[0] = devm_ioport_map(&pdev->dev, ATA_PRIMARY_CMD, 8);
+ iomap[1] = devm_ioport_map(&pdev->dev, ATA_PRIMARY_CTL, 1);
+ if (!iomap[0] || !iomap[1])
+ return NULL;
+ }
+
+ if (port_mask & ATA_PORT_SECONDARY) {
+ iomap[2] = devm_ioport_map(&pdev->dev, ATA_SECONDARY_CMD, 8);
+ iomap[3] = devm_ioport_map(&pdev->dev, ATA_SECONDARY_CTL, 1);
+ if (!iomap[2] || !iomap[3])
+ return NULL;
+ }
+ bmdma = pcim_iomap(pdev, 4, 16); /* may fail */
+
+ /* alloc and init probe_ent */
probe_ent = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[0]);
if (!probe_ent)
return NULL;
@@ -918,13 +651,13 @@ static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev,
if (port_mask & ATA_PORT_PRIMARY) {
probe_ent->irq = ATA_PRIMARY_IRQ(pdev);
- probe_ent->port[0].cmd_addr = ATA_PRIMARY_CMD;
+ probe_ent->port[0].cmd_addr = iomap[0];
probe_ent->port[0].altstatus_addr =
- probe_ent->port[0].ctl_addr = ATA_PRIMARY_CTL;
+ probe_ent->port[0].ctl_addr = iomap[1];
if (bmdma) {
probe_ent->port[0].bmdma_addr = bmdma;
if ((!(port[0]->flags & ATA_FLAG_IGN_SIMPLEX)) &&
- (inb(bmdma + 2) & 0x80))
+ (ioread8(bmdma + 2) & 0x80))
probe_ent->_host_flags |= ATA_HOST_SIMPLEX;
}
ata_std_ports(&probe_ent->port[0]);
@@ -936,13 +669,13 @@ static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev,
probe_ent->irq2 = ATA_SECONDARY_IRQ(pdev);
else
probe_ent->irq = ATA_SECONDARY_IRQ(pdev);
- probe_ent->port[1].cmd_addr = ATA_SECONDARY_CMD;
+ probe_ent->port[1].cmd_addr = iomap[2];
probe_ent->port[1].altstatus_addr =
- probe_ent->port[1].ctl_addr = ATA_SECONDARY_CTL;
+ probe_ent->port[1].ctl_addr = iomap[3];
if (bmdma) {
probe_ent->port[1].bmdma_addr = bmdma + 8;
if ((!(port[1]->flags & ATA_FLAG_IGN_SIMPLEX)) &&
- (inb(bmdma + 10) & 0x80))
+ (ioread8(bmdma + 10) & 0x80))
probe_ent->_host_flags |= ATA_HOST_SIMPLEX;
}
ata_std_ports(&probe_ent->port[1]);
@@ -984,15 +717,18 @@ static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev,
int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
unsigned int n_ports)
{
+ struct device *dev = &pdev->dev;
struct ata_probe_ent *probe_ent = NULL;
struct ata_port_info *port[2];
u8 mask;
unsigned int legacy_mode = 0;
- int disable_dev_on_err = 1;
int rc;
DPRINTK("ENTER\n");
+ if (!devres_open_group(dev, NULL, GFP_KERNEL))
+ return -ENOMEM;
+
BUG_ON(n_ports < 1 || n_ports > 2);
port[0] = port_info[0];
@@ -1009,9 +745,9 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
boot for the primary video which is BIOS enabled
*/
- rc = pci_enable_device(pdev);
+ rc = pcim_enable_device(pdev);
if (rc)
- return rc;
+ goto err_out;
if ((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
u8 tmp8;
@@ -1027,7 +763,8 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
left a device in compatibility mode */
if (legacy_mode) {
printk(KERN_ERR "ata: Compatibility mode ATA is not supported on this platform, skipping.\n");
- return -EOPNOTSUPP;
+ rc = -EOPNOTSUPP;
+ goto err_out;
}
#endif
}
@@ -1035,13 +772,13 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
if (!legacy_mode) {
rc = pci_request_regions(pdev, DRV_NAME);
if (rc) {
- disable_dev_on_err = 0;
+ pcim_pin_device(pdev);
goto err_out;
}
} else {
/* Deal with combined mode hack. This side of the logic all
goes away once the combined mode hack is killed in 2.6.21 */
- if (!request_region(ATA_PRIMARY_CMD, 8, "libata")) {
+ if (!devm_request_region(dev, ATA_PRIMARY_CMD, 8, "libata")) {
struct resource *conflict, res;
res.start = ATA_PRIMARY_CMD;
res.end = ATA_PRIMARY_CMD + 8 - 1;
@@ -1051,7 +788,7 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
if (!strcmp(conflict->name, "libata"))
legacy_mode |= ATA_PORT_PRIMARY;
else {
- disable_dev_on_err = 0;
+ pcim_pin_device(pdev);
printk(KERN_WARNING "ata: 0x%0X IDE port busy\n" \
"ata: conflict with %s\n",
ATA_PRIMARY_CMD,
@@ -1060,7 +797,7 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
} else
legacy_mode |= ATA_PORT_PRIMARY;
- if (!request_region(ATA_SECONDARY_CMD, 8, "libata")) {
+ if (!devm_request_region(dev, ATA_SECONDARY_CMD, 8, "libata")) {
struct resource *conflict, res;
res.start = ATA_SECONDARY_CMD;
res.end = ATA_SECONDARY_CMD + 8 - 1;
@@ -1070,7 +807,7 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
if (!strcmp(conflict->name, "libata"))
legacy_mode |= ATA_PORT_SECONDARY;
else {
- disable_dev_on_err = 0;
+ pcim_pin_device(pdev);
printk(KERN_WARNING "ata: 0x%X IDE port busy\n" \
"ata: conflict with %s\n",
ATA_SECONDARY_CMD,
@@ -1090,16 +827,16 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
/* we have legacy mode, but all ports are unavailable */
if (legacy_mode == (1 << 3)) {
rc = -EBUSY;
- goto err_out_regions;
+ goto err_out;
}
/* TODO: If we get no DMA mask we should fall back to PIO */
rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
if (rc)
- goto err_out_regions;
+ goto err_out;
rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
if (rc)
- goto err_out_regions;
+ goto err_out;
if (legacy_mode) {
probe_ent = ata_pci_init_legacy_port(pdev, port, legacy_mode);
@@ -1111,40 +848,22 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
}
if (!probe_ent) {
rc = -ENOMEM;
- goto err_out_regions;
+ goto err_out;
}
pci_set_master(pdev);
if (!ata_device_add(probe_ent)) {
rc = -ENODEV;
- goto err_out_ent;
+ goto err_out;
}
- kfree(probe_ent);
-
+ devm_kfree(dev, probe_ent);
+ devres_remove_group(dev, NULL);
return 0;
-err_out_ent:
- kfree(probe_ent);
-err_out_regions:
- /* All this conditional stuff is needed for the combined mode hack
- until 2.6.21 when it can go */
- if (legacy_mode) {
- pci_release_region(pdev, 4);
- if (legacy_mode & ATA_PORT_PRIMARY) {
- release_region(ATA_PRIMARY_CMD, 8);
- pci_release_region(pdev, 1);
- }
- if (legacy_mode & ATA_PORT_SECONDARY) {
- release_region(ATA_SECONDARY_CMD, 8);
- pci_release_region(pdev, 3);
- }
- } else
- pci_release_regions(pdev);
err_out:
- if (disable_dev_on_err)
- pci_disable_device(pdev);
+ devres_release_group(dev, NULL);
return rc;
}
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index 81ae41d5f23..0ad7781d72a 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -29,7 +29,6 @@
#define __LIBATA_H__
#define DRV_NAME "libata"
-#define DRV_VERSION "2.00" /* must be exactly four chars */
struct ata_scsi_args {
struct ata_device *dev;
@@ -48,6 +47,7 @@ extern struct workqueue_struct *ata_aux_wq;
extern int atapi_enabled;
extern int atapi_dmadir;
extern int libata_fua;
+extern int noacpi;
extern struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev);
extern int ata_build_rw_tf(struct ata_taskfile *tf, struct ata_device *dev,
u64 block, u32 n_block, unsigned int tf_flags,
@@ -88,6 +88,20 @@ extern void ata_port_init(struct ata_port *ap, struct ata_host *host,
extern struct ata_probe_ent *ata_probe_ent_alloc(struct device *dev,
const struct ata_port_info *port);
+/* libata-acpi.c */
+#ifdef CONFIG_SATA_ACPI
+extern int ata_acpi_exec_tfs(struct ata_port *ap);
+extern int ata_acpi_push_id(struct ata_port *ap, unsigned int ix);
+#else
+static inline int ata_acpi_exec_tfs(struct ata_port *ap)
+{
+ return 0;
+}
+static inline int ata_acpi_push_id(struct ata_port *ap, unsigned int ix)
+{
+ return 0;
+}
+#endif
/* libata-scsi.c */
extern struct scsi_transport_template ata_scsi_transport_template;
@@ -136,4 +150,7 @@ extern void ata_qc_schedule_eh(struct ata_queued_cmd *qc);
/* libata-sff.c */
extern u8 ata_irq_on(struct ata_port *ap);
+/* pata_sis.c */
+extern struct ata_port_info sis_info133;
+
#endif /* __LIBATA_H__ */
diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c
index c5d61d1911a..ab44d18850f 100644
--- a/drivers/ata/pata_ali.c
+++ b/drivers/ata/pata_ali.c
@@ -153,11 +153,11 @@ static void ali_early_error_handler(struct ata_port *ap)
static unsigned long ali_20_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long mask)
{
- char model_num[40];
+ char model_num[ATA_ID_PROD_LEN + 1];
/* No DMA on anything but a disk for now */
if (adev->class != ATA_DEV_ATA)
mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA);
- ata_id_string(adev->id, model_num, ATA_ID_PROD_OFS, sizeof(model_num));
+ ata_id_c_string(adev->id, model_num, ATA_ID_PROD, sizeof(model_num));
if (strstr(model_num, "WDC"))
return mask &= ~ATA_MASK_UDMA;
return ata_pci_default_filter(ap, adev, mask);
@@ -370,14 +370,14 @@ static struct ata_port_operations ali_early_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
/*
@@ -411,14 +411,14 @@ static struct ata_port_operations ali_20_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
/*
@@ -449,14 +449,14 @@ static struct ata_port_operations ali_c2_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
/*
@@ -486,14 +486,14 @@ static struct ata_port_operations ali_c5_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
@@ -504,7 +504,7 @@ static struct ata_port_operations ali_c5_port_ops = {
* Perform the setup on the device that must be done both at boot
* and at resume time.
*/
-
+
static void ali_init_chipset(struct pci_dev *pdev)
{
u8 rev, tmp;
@@ -655,7 +655,7 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
port_info[0] = port_info[1] = &info_c5;
ali_init_chipset(pdev);
-
+
isa_bridge = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL);
if (isa_bridge && rev >= 0x20 && rev < 0xC2) {
/* Are we paired with a UDMA capable chip */
diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c
index a6b330089f2..619e44b0403 100644
--- a/drivers/ata/pata_amd.c
+++ b/drivers/ata/pata_amd.c
@@ -362,14 +362,14 @@ static struct ata_port_operations amd33_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
static struct ata_port_operations amd66_port_ops = {
@@ -396,14 +396,14 @@ static struct ata_port_operations amd66_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
static struct ata_port_operations amd100_port_ops = {
@@ -430,14 +430,14 @@ static struct ata_port_operations amd100_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
static struct ata_port_operations amd133_port_ops = {
@@ -464,14 +464,14 @@ static struct ata_port_operations amd133_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
static struct ata_port_operations nv100_port_ops = {
@@ -498,14 +498,14 @@ static struct ata_port_operations nv100_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
static struct ata_port_operations nv133_port_ops = {
@@ -532,14 +532,14 @@ static struct ata_port_operations nv133_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
diff --git a/drivers/ata/pata_artop.c b/drivers/ata/pata_artop.c
index 37bc1323bda..21c30282717 100644
--- a/drivers/ata/pata_artop.c
+++ b/drivers/ata/pata_artop.c
@@ -341,14 +341,14 @@ static const struct ata_port_operations artop6210_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop,
};
static const struct ata_port_operations artop6260_ops = {
@@ -373,14 +373,14 @@ static const struct ata_port_operations artop6260_ops = {
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop,
};
diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c
index 504e1dbfffd..c3eb40c91c8 100644
--- a/drivers/ata/pata_atiixp.c
+++ b/drivers/ata/pata_atiixp.c
@@ -252,14 +252,14 @@ static struct ata_port_operations atiixp_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
static int atiixp_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c
index 449162cbf93..da098282b5f 100644
--- a/drivers/ata/pata_cmd64x.c
+++ b/drivers/ata/pata_cmd64x.c
@@ -313,14 +313,14 @@ static struct ata_port_operations cmd64x_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
static struct ata_port_operations cmd646r1_port_ops = {
@@ -347,14 +347,14 @@ static struct ata_port_operations cmd646r1_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
static struct ata_port_operations cmd648_port_ops = {
@@ -381,14 +381,14 @@ static struct ata_port_operations cmd648_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
diff --git a/drivers/ata/pata_cs5520.c b/drivers/ata/pata_cs5520.c
index 9f165a8e032..1ce8fcfd782 100644
--- a/drivers/ata/pata_cs5520.c
+++ b/drivers/ata/pata_cs5520.c
@@ -99,9 +99,9 @@ static void cs5520_set_timings(struct ata_port *ap, struct ata_device *adev, int
static void cs5520_enable_dma(struct ata_port *ap, struct ata_device *adev)
{
/* Set the DMA enable/disable flag */
- u8 reg = inb(ap->ioaddr.bmdma_addr + 0x02);
+ u8 reg = ioread8(ap->ioaddr.bmdma_addr + 0x02);
reg |= 1<<(adev->devno + 5);
- outb(reg, ap->ioaddr.bmdma_addr + 0x02);
+ iowrite8(reg, ap->ioaddr.bmdma_addr + 0x02);
}
/**
@@ -193,19 +193,20 @@ static struct ata_port_operations cs5520_port_ops = {
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop,
};
static int __devinit cs5520_init_one(struct pci_dev *dev, const struct pci_device_id *id)
{
u8 pcicfg;
+ void *iomap[5];
static struct ata_probe_ent probe[2];
int ports = 0;
@@ -236,6 +237,16 @@ static int __devinit cs5520_init_one(struct pci_dev *dev, const struct pci_devic
return -ENODEV;
}
+ /* Map IO ports */
+ iomap[0] = devm_ioport_map(&dev->dev, 0x1F0, 8);
+ iomap[1] = devm_ioport_map(&dev->dev, 0x3F6, 1);
+ iomap[2] = devm_ioport_map(&dev->dev, 0x170, 8);
+ iomap[3] = devm_ioport_map(&dev->dev, 0x376, 1);
+ iomap[4] = pcim_iomap(dev, 2, 0);
+
+ if (!iomap[0] || !iomap[1] || !iomap[2] || !iomap[3] || !iomap[4])
+ return -ENOMEM;
+
/* We have to do our own plumbing as the PCI setup for this
chipset is non-standard so we can't punt to the libata code */
@@ -249,10 +260,10 @@ static int __devinit cs5520_init_one(struct pci_dev *dev, const struct pci_devic
probe[0].irq_flags = 0;
probe[0].port_flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST;
probe[0].n_ports = 1;
- probe[0].port[0].cmd_addr = 0x1F0;
- probe[0].port[0].ctl_addr = 0x3F6;
- probe[0].port[0].altstatus_addr = 0x3F6;
- probe[0].port[0].bmdma_addr = pci_resource_start(dev, 2);
+ probe[0].port[0].cmd_addr = iomap[0];
+ probe[0].port[0].ctl_addr = iomap[1];
+ probe[0].port[0].altstatus_addr = iomap[1];
+ probe[0].port[0].bmdma_addr = iomap[4];
/* The secondary lurks at different addresses but is otherwise
the same beastie */
@@ -260,10 +271,10 @@ static int __devinit cs5520_init_one(struct pci_dev *dev, const struct pci_devic
probe[1] = probe[0];
INIT_LIST_HEAD(&probe[1].node);
probe[1].irq = 15;
- probe[1].port[0].cmd_addr = 0x170;
- probe[1].port[0].ctl_addr = 0x376;
- probe[1].port[0].altstatus_addr = 0x376;
- probe[1].port[0].bmdma_addr = pci_resource_start(dev, 2) + 8;
+ probe[1].port[0].cmd_addr = iomap[2];
+ probe[1].port[0].ctl_addr = iomap[3];
+ probe[1].port[0].altstatus_addr = iomap[3];
+ probe[1].port[0].bmdma_addr = iomap[4] + 8;
/* Let libata fill in the port details */
ata_std_ports(&probe[0].port[0]);
@@ -294,7 +305,7 @@ static void __devexit cs5520_remove_one(struct pci_dev *pdev)
struct device *dev = pci_dev_to_dev(pdev);
struct ata_host *host = dev_get_drvdata(dev);
- ata_host_remove(host);
+ ata_host_detach(host);
dev_set_drvdata(dev, NULL);
}
@@ -305,7 +316,7 @@ static void __devexit cs5520_remove_one(struct pci_dev *pdev)
* Do any reconfiguration work needed by a resume from RAM. We need
* to restore DMA mode support on BIOSen which disabled it
*/
-
+
static int cs5520_reinit_one(struct pci_dev *pdev)
{
u8 pcicfg;
diff --git a/drivers/ata/pata_cs5530.c b/drivers/ata/pata_cs5530.c
index b1ca207e354..3d7b7d87ec6 100644
--- a/drivers/ata/pata_cs5530.c
+++ b/drivers/ata/pata_cs5530.c
@@ -37,6 +37,13 @@
#define DRV_NAME "pata_cs5530"
#define DRV_VERSION "0.7.1"
+static void __iomem *cs5530_port_base(struct ata_port *ap)
+{
+ unsigned long bmdma = (unsigned long)ap->ioaddr.bmdma_addr;
+
+ return (void __iomem *)((bmdma & ~0x0F) + 0x20 + 0x10 * ap->port_no);
+}
+
/**
* cs5530_set_piomode - PIO setup
* @ap: ATA interface
@@ -52,19 +59,19 @@ static void cs5530_set_piomode(struct ata_port *ap, struct ata_device *adev)
{0x00009172, 0x00012171, 0x00020080, 0x00032010, 0x00040010},
{0xd1329172, 0x71212171, 0x30200080, 0x20102010, 0x00100010}
};
- unsigned long base = ( ap->ioaddr.bmdma_addr & ~0x0F) + 0x20 + 0x10 * ap->port_no;
+ void __iomem *base = cs5530_port_base(ap);
u32 tuning;
int format;
/* Find out which table to use */
- tuning = inl(base + 0x04);
+ tuning = ioread32(base + 0x04);
format = (tuning & 0x80000000UL) ? 1 : 0;
/* Now load the right timing register */
if (adev->devno)
base += 0x08;
- outl(cs5530_pio_timings[format][adev->pio_mode - XFER_PIO_0], base);
+ iowrite32(cs5530_pio_timings[format][adev->pio_mode - XFER_PIO_0], base);
}
/**
@@ -79,12 +86,12 @@ static void cs5530_set_piomode(struct ata_port *ap, struct ata_device *adev)
static void cs5530_set_dmamode(struct ata_port *ap, struct ata_device *adev)
{
- unsigned long base = ( ap->ioaddr.bmdma_addr & ~0x0F) + 0x20 + 0x10 * ap->port_no;
+ void __iomem *base = cs5530_port_base(ap);
u32 tuning, timing = 0;
u8 reg;
/* Find out which table to use */
- tuning = inl(base + 0x04);
+ tuning = ioread32(base + 0x04);
switch(adev->dma_mode) {
case XFER_UDMA_0:
@@ -105,20 +112,20 @@ static void cs5530_set_dmamode(struct ata_port *ap, struct ata_device *adev)
/* Merge in the PIO format bit */
timing |= (tuning & 0x80000000UL);
if (adev->devno == 0) /* Master */
- outl(timing, base + 0x04);
+ iowrite32(timing, base + 0x04);
else {
if (timing & 0x00100000)
tuning |= 0x00100000; /* UDMA for both */
else
tuning &= ~0x00100000; /* MWDMA for both */
- outl(tuning, base + 0x04);
- outl(timing, base + 0x0C);
+ iowrite32(tuning, base + 0x04);
+ iowrite32(timing, base + 0x0C);
}
/* Set the DMA capable bit in the BMDMA area */
- reg = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
+ reg = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
reg |= (1 << (5 + adev->devno));
- outb(reg, ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
+ iowrite8(reg, ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
/* Remember the last DMA setup we did */
@@ -210,14 +217,14 @@ static struct ata_port_operations cs5530_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = cs5530_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
static struct dmi_system_id palmax_dmi_table[] = {
@@ -247,7 +254,7 @@ static int cs5530_is_palmax(void)
* Perform the chip initialisation work that is shared between both
* setup and resume paths
*/
-
+
static int cs5530_init_chip(void)
{
struct pci_dev *master_0 = NULL, *cs5530_0 = NULL, *dev = NULL;
@@ -357,11 +364,11 @@ static int cs5530_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
.port_ops = &cs5530_port_ops
};
static struct ata_port_info *port_info[2] = { &info, &info };
-
+
/* Chip initialisation */
if (cs5530_init_chip())
return -ENODEV;
-
+
if (cs5530_is_palmax())
port_info[1] = &info_palmax_secondary;
@@ -376,7 +383,7 @@ static int cs5530_reinit_one(struct pci_dev *pdev)
BUG();
return ata_pci_device_resume(pdev);
}
-
+
static const struct pci_device_id cs5530[] = {
{ PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5530_IDE), },
diff --git a/drivers/ata/pata_cs5535.c b/drivers/ata/pata_cs5535.c
index e3efec4ffc7..17bc693cc51 100644
--- a/drivers/ata/pata_cs5535.c
+++ b/drivers/ata/pata_cs5535.c
@@ -214,14 +214,14 @@ static struct ata_port_operations cs5535_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
/**
diff --git a/drivers/ata/pata_cypress.c b/drivers/ata/pata_cypress.c
index e2a95699bae..63f48f08763 100644
--- a/drivers/ata/pata_cypress.c
+++ b/drivers/ata/pata_cypress.c
@@ -165,14 +165,14 @@ static struct ata_port_operations cy82c693_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
static int cy82c693_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
diff --git a/drivers/ata/pata_efar.c b/drivers/ata/pata_efar.c
index edf8a63f50a..c19b6a8a7dc 100644
--- a/drivers/ata/pata_efar.c
+++ b/drivers/ata/pata_efar.c
@@ -261,14 +261,14 @@ static const struct ata_port_operations efar_ops = {
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop,
};
diff --git a/drivers/ata/pata_hpt366.c b/drivers/ata/pata_hpt366.c
index 2663599a7c0..27d724b5eea 100644
--- a/drivers/ata/pata_hpt366.c
+++ b/drivers/ata/pata_hpt366.c
@@ -151,23 +151,13 @@ static const char *bad_ata66_3[] = {
static int hpt_dma_blacklisted(const struct ata_device *dev, char *modestr, const char *list[])
{
- unsigned char model_num[40];
- char *s;
- unsigned int len;
+ unsigned char model_num[ATA_ID_PROD_LEN + 1];
int i = 0;
- ata_id_string(dev->id, model_num, ATA_ID_PROD_OFS, sizeof(model_num));
- s = &model_num[0];
- len = strnlen(s, sizeof(model_num));
+ ata_id_c_string(dev->id, model_num, ATA_ID_PROD, sizeof(model_num));
- /* ATAPI specifies that empty space is blank-filled; remove blanks */
- while ((len > 0) && (s[len - 1] == ' ')) {
- len--;
- s[len] = 0;
- }
-
- while(list[i] != NULL) {
- if (!strncmp(list[i], s, len)) {
+ while (list[i] != NULL) {
+ if (!strcmp(list[i], model_num)) {
printk(KERN_WARNING DRV_NAME ": %s is not supported for %s.\n",
modestr, list[i]);
return 1;
@@ -232,7 +222,7 @@ static int hpt36x_pre_reset(struct ata_port *ap)
if (!pci_test_config_bits(pdev, &hpt36x_enable_bits[ap->port_no]))
return -ENOENT;
-
+
pci_read_config_byte(pdev, 0x5A, &ata66);
if (ata66 & (1 << ap->port_no))
ap->cbl = ATA_CBL_PATA40;
@@ -371,14 +361,14 @@ static struct ata_port_operations hpt366_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
/**
diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c
index dfb306057cf..4ffc392052c 100644
--- a/drivers/ata/pata_hpt37x.c
+++ b/drivers/ata/pata_hpt37x.c
@@ -349,24 +349,13 @@ static u32 hpt37x_find_mode(struct ata_port *ap, int speed)
static int hpt_dma_blacklisted(const struct ata_device *dev, char *modestr, const char *list[])
{
- unsigned char model_num[40];
- char *s;
- unsigned int len;
+ unsigned char model_num[ATA_ID_PROD_LEN + 1];
int i = 0;
- ata_id_string(dev->id, model_num, ATA_ID_PROD_OFS,
- sizeof(model_num));
- s = &model_num[0];
- len = strnlen(s, sizeof(model_num));
+ ata_id_c_string(dev->id, model_num, ATA_ID_PROD, sizeof(model_num));
- /* ATAPI specifies that empty space is blank-filled; remove blanks */
- while ((len > 0) && (s[len - 1] == ' ')) {
- len--;
- s[len] = 0;
- }
-
- while(list[i] != NULL) {
- if (!strncmp(list[i], s, len)) {
+ while (list[i] != NULL) {
+ if (!strcmp(list[i], model_num)) {
printk(KERN_WARNING DRV_NAME ": %s is not supported for %s.\n",
modestr, list[i]);
return 1;
@@ -459,7 +448,7 @@ static int hpt37x_pre_reset(struct ata_port *ap)
};
if (!pci_test_config_bits(pdev, &hpt37x_enable_bits[ap->port_no]))
return -ENOENT;
-
+
pci_read_config_byte(pdev, 0x5B, &scr2);
pci_write_config_byte(pdev, 0x5B, scr2 & ~0x01);
/* Cable register now active */
@@ -504,7 +493,7 @@ static int hpt374_pre_reset(struct ata_port *ap)
if (!pci_test_config_bits(pdev, &hpt37x_enable_bits[ap->port_no]))
return -ENOENT;
-
+
/* Do the extra channel work */
pci_read_config_word(pdev, 0x52, &mcr3);
pci_read_config_word(pdev, 0x56, &mcr6);
@@ -645,24 +634,24 @@ 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 = inb(ap->ioaddr.bmdma_addr + 2);
+ u8 dma_stat = ioread8(ap->ioaddr.bmdma_addr + 2);
u8 dma_cmd;
- unsigned long bmdma = ap->ioaddr.bmdma_addr;
+ void __iomem *bmdma = ap->ioaddr.bmdma_addr;
if (dma_stat & 0x01) {
udelay(20);
- dma_stat = inb(bmdma + 2);
+ dma_stat = ioread8(bmdma + 2);
}
if (dma_stat & 0x01) {
/* Clear the engine */
pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37);
udelay(10);
/* Stop DMA */
- dma_cmd = inb(bmdma );
- outb(dma_cmd & 0xFE, bmdma);
+ dma_cmd = ioread8(bmdma );
+ iowrite8(dma_cmd & 0xFE, bmdma);
/* Clear Error */
- dma_stat = inb(bmdma + 2);
- outb(dma_stat | 0x06 , bmdma + 2);
+ dma_stat = ioread8(bmdma + 2);
+ iowrite8(dma_stat | 0x06 , bmdma + 2);
/* Clear the engine */
pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37);
udelay(10);
@@ -807,14 +796,14 @@ static struct ata_port_operations hpt370_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
/*
@@ -846,14 +835,14 @@ static struct ata_port_operations hpt370a_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
/*
@@ -886,14 +875,14 @@ static struct ata_port_operations hpt372_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
/*
@@ -926,14 +915,14 @@ static struct ata_port_operations hpt374_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
/**
diff --git a/drivers/ata/pata_hpt3x2n.c b/drivers/ata/pata_hpt3x2n.c
index 886fab9aa62..65f2e180e7f 100644
--- a/drivers/ata/pata_hpt3x2n.c
+++ b/drivers/ata/pata_hpt3x2n.c
@@ -263,26 +263,26 @@ static void hpt3x2n_bmdma_stop(struct ata_queued_cmd *qc)
static void hpt3x2n_set_clock(struct ata_port *ap, int source)
{
- unsigned long bmdma = ap->ioaddr.bmdma_addr;
+ void __iomem *bmdma = ap->ioaddr.bmdma_addr;
/* Tristate the bus */
- outb(0x80, bmdma+0x73);
- outb(0x80, bmdma+0x77);
+ iowrite8(0x80, bmdma+0x73);
+ iowrite8(0x80, bmdma+0x77);
/* Switch clock and reset channels */
- outb(source, bmdma+0x7B);
- outb(0xC0, bmdma+0x79);
+ iowrite8(source, bmdma+0x7B);
+ iowrite8(0xC0, bmdma+0x79);
/* Reset state machines */
- outb(0x37, bmdma+0x70);
- outb(0x37, bmdma+0x74);
+ iowrite8(0x37, bmdma+0x70);
+ iowrite8(0x37, bmdma+0x74);
/* Complete reset */
- outb(0x00, bmdma+0x79);
+ iowrite8(0x00, bmdma+0x79);
/* Reconnect channels to bus */
- outb(0x00, bmdma+0x73);
- outb(0x00, bmdma+0x77);
+ iowrite8(0x00, bmdma+0x73);
+ iowrite8(0x00, bmdma+0x77);
}
/* Check if our partner interface is busy */
@@ -373,14 +373,14 @@ static struct ata_port_operations hpt3x2n_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = hpt3x2n_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
/**
diff --git a/drivers/ata/pata_hpt3x3.c b/drivers/ata/pata_hpt3x3.c
index 5f1d385eb59..483ce7c12c9 100644
--- a/drivers/ata/pata_hpt3x3.c
+++ b/drivers/ata/pata_hpt3x3.c
@@ -148,14 +148,14 @@ static struct ata_port_operations hpt3x3_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
/**
@@ -164,7 +164,7 @@ static struct ata_port_operations hpt3x3_port_ops = {
*
* Perform the setup required at boot and on resume.
*/
-
+
static void hpt3x3_init_chipset(struct pci_dev *dev)
{
u16 cmd;
diff --git a/drivers/ata/pata_isapnp.c b/drivers/ata/pata_isapnp.c
index a97d55ae95c..1bf5ec18b2e 100644
--- a/drivers/ata/pata_isapnp.c
+++ b/drivers/ata/pata_isapnp.c
@@ -53,14 +53,14 @@ static struct ata_port_operations isapnp_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
/**
@@ -75,6 +75,7 @@ static struct ata_port_operations isapnp_port_ops = {
static int isapnp_init_one(struct pnp_dev *idev, const struct pnp_device_id *dev_id)
{
struct ata_probe_ent ae;
+ void __iomem *cmd_addr, *ctl_addr;
if (pnp_port_valid(idev, 0) == 0)
return -ENODEV;
@@ -83,6 +84,10 @@ static int isapnp_init_one(struct pnp_dev *idev, const struct pnp_device_id *dev
if (pnp_irq_valid(idev, 0) == 0)
return -ENODEV;
+ cmd_addr = devm_ioport_map(&idev->dev, pnp_port_start(idev, 0), 8);
+ if (!cmd_addr)
+ return -ENOMEM;
+
memset(&ae, 0, sizeof(struct ata_probe_ent));
INIT_LIST_HEAD(&ae.node);
ae.dev = &idev->dev;
@@ -93,11 +98,13 @@ static int isapnp_init_one(struct pnp_dev *idev, const struct pnp_device_id *dev
ae.irq = pnp_irq(idev, 0);
ae.irq_flags = 0;
ae.port_flags = ATA_FLAG_SLAVE_POSS;
- ae.port[0].cmd_addr = pnp_port_start(idev, 0);
+ ae.port[0].cmd_addr = cmd_addr;
if (pnp_port_valid(idev, 1) == 0) {
- ae.port[0].altstatus_addr = pnp_port_start(idev, 1);
- ae.port[0].ctl_addr = pnp_port_start(idev, 1);
+ ctl_addr = devm_ioport_map(&idev->dev,
+ pnp_port_start(idev, 1), 1);
+ ae.port[0].altstatus_addr = ctl_addr;
+ ae.port[0].ctl_addr = ctl_addr;
ae.port_flags |= ATA_FLAG_SRST;
}
ata_std_ports(&ae.port[0]);
@@ -120,7 +127,7 @@ static void isapnp_remove_one(struct pnp_dev *idev)
struct device *dev = &idev->dev;
struct ata_host *host = dev_get_drvdata(dev);
- ata_host_remove(host);
+ ata_host_detach(host);
dev_set_drvdata(dev, NULL);
}
diff --git a/drivers/ata/pata_it8213.c b/drivers/ata/pata_it8213.c
new file mode 100644
index 00000000000..7eac869dfcd
--- /dev/null
+++ b/drivers/ata/pata_it8213.c
@@ -0,0 +1,354 @@
+/*
+ * pata_it8213.c - iTE Tech. Inc. IT8213 PATA driver
+ *
+ * The IT8213 is a very Intel ICH like device for timing purposes, having
+ * a similar register layout and the same split clock arrangement. Cable
+ * detection is different, and it does not have slave channels or all the
+ * clutter of later ICH/SATA setups.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+#include <linux/ata.h>
+
+#define DRV_NAME "pata_it8213"
+#define DRV_VERSION "0.0.2"
+
+/**
+ * it8213_pre_reset - check for 40/80 pin
+ * @ap: Port
+ *
+ * Perform cable detection for the 8213 ATA interface. This is
+ * different to the PIIX arrangement
+ */
+
+static int it8213_pre_reset(struct ata_port *ap)
+{
+ static const struct pci_bits it8213_enable_bits[] = {
+ { 0x41U, 1U, 0x80UL, 0x80UL }, /* port 0 */
+ };
+
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u8 tmp;
+
+ if (!pci_test_config_bits(pdev, &it8213_enable_bits[ap->port_no]))
+ return -ENOENT;
+
+ pci_read_config_byte(pdev, 0x42, &tmp);
+ if (tmp & 2) /* The initial docs are incorrect */
+ ap->cbl = ATA_CBL_PATA40;
+ else
+ ap->cbl = ATA_CBL_PATA80;
+ return ata_std_prereset(ap);
+}
+
+/**
+ * it8213_probe_reset - Probe specified port on PATA host controller
+ * @ap: Port to probe
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void it8213_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, it8213_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+/**
+ * it8213_set_piomode - Initialize host controller PATA PIO timings
+ * @ap: Port whose timings we are configuring
+ * @adev: um
+ *
+ * Set PIO mode for device, in host controller PCI config space.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void it8213_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;
+ u16 idetm_data;
+ int control = 0;
+
+ /*
+ * See Intel Document 298600-004 for the timing programing rules
+ * for PIIX/ICH. The 8213 is a clone so very similar
+ */
+
+ static const /* ISP RTC */
+ u8 timings[][2] = { { 0, 0 },
+ { 0, 0 },
+ { 1, 0 },
+ { 2, 1 },
+ { 2, 3 }, };
+
+ if (pio > 2)
+ control |= 1; /* TIME1 enable */
+ if (ata_pio_need_iordy(adev)) /* PIO 3/4 require IORDY */
+ control |= 2; /* IORDY enable */
+ /* Bit 2 is set for ATAPI on the IT8213 - reverse of ICH/PIIX */
+ if (adev->class != ATA_DEV_ATA)
+ control |= 4;
+
+ pci_read_config_word(dev, idetm_port, &idetm_data);
+
+ /* Enable PPE, IE and TIME as appropriate */
+
+ if (adev->devno == 0) {
+ idetm_data &= 0xCCF0;
+ idetm_data |= control;
+ idetm_data |= (timings[pio][0] << 12) |
+ (timings[pio][1] << 8);
+ } else {
+ u8 slave_data;
+
+ idetm_data &= 0xCC0F;
+ idetm_data |= (control << 4);
+
+ /* Slave timing in seperate register */
+ pci_read_config_byte(dev, 0x44, &slave_data);
+ slave_data &= 0xF0;
+ slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) << 4;
+ pci_write_config_byte(dev, 0x44, slave_data);
+ }
+
+ idetm_data |= 0x4000; /* Ensure SITRE is enabled */
+ pci_write_config_word(dev, idetm_port, idetm_data);
+}
+
+/**
+ * it8213_set_dmamode - Initialize host controller PATA DMA timings
+ * @ap: Port whose timings we are configuring
+ * @adev: Device to program
+ *
+ * Set UDMA/MWDMA mode for device, in host controller PCI config space.
+ * This device is basically an ICH alike.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void it8213_set_dmamode (struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *dev = to_pci_dev(ap->host->dev);
+ u16 master_data;
+ u8 speed = adev->dma_mode;
+ int devid = adev->devno;
+ u8 udma_enable;
+
+ static const /* ISP RTC */
+ u8 timings[][2] = { { 0, 0 },
+ { 0, 0 },
+ { 1, 0 },
+ { 2, 1 },
+ { 2, 3 }, };
+
+ pci_read_config_word(dev, 0x40, &master_data);
+ pci_read_config_byte(dev, 0x48, &udma_enable);
+
+ if (speed >= XFER_UDMA_0) {
+ unsigned int udma = adev->dma_mode - XFER_UDMA_0;
+ u16 udma_timing;
+ u16 ideconf;
+ int u_clock, u_speed;
+
+ /* Clocks follow the PIIX style */
+ u_speed = min(2 - (udma & 1), udma);
+ if (udma == 5)
+ u_clock = 0x1000; /* 100Mhz */
+ else if (udma > 2)
+ u_clock = 1; /* 66Mhz */
+ else
+ u_clock = 0; /* 33Mhz */
+
+ udma_enable |= (1 << devid);
+
+ /* Load the UDMA mode number */
+ pci_read_config_word(dev, 0x4A, &udma_timing);
+ udma_timing &= ~(3 << (4 * devid));
+ udma_timing |= (udma & 3) << (4 * devid);
+ pci_write_config_word(dev, 0x4A, udma_timing);
+
+ /* Load the clock selection */
+ pci_read_config_word(dev, 0x54, &ideconf);
+ ideconf &= ~(0x1001 << devid);
+ ideconf |= u_clock << devid;
+ pci_write_config_word(dev, 0x54, ideconf);
+ } else {
+ /*
+ * MWDMA is driven by the PIO timings. We must also enable
+ * IORDY unconditionally along with TIME1. PPE has already
+ * been set when the PIO timing was set.
+ */
+ unsigned int mwdma = adev->dma_mode - XFER_MW_DMA_0;
+ unsigned int control;
+ u8 slave_data;
+ static const unsigned int needed_pio[3] = {
+ XFER_PIO_0, XFER_PIO_3, XFER_PIO_4
+ };
+ int pio = needed_pio[mwdma] - XFER_PIO_0;
+
+ control = 3; /* IORDY|TIME1 */
+
+ /* If the drive MWDMA is faster than it can do PIO then
+ we must force PIO into PIO0 */
+
+ if (adev->pio_mode < needed_pio[mwdma])
+ /* Enable DMA timing only */
+ control |= 8; /* PIO cycles in PIO0 */
+
+ if (devid) { /* Slave */
+ master_data &= 0xFF4F; /* Mask out IORDY|TIME1|DMAONLY */
+ master_data |= control << 4;
+ pci_read_config_byte(dev, 0x44, &slave_data);
+ slave_data &= (0x0F + 0xE1 * ap->port_no);
+ /* Load the matching timing */
+ slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) << (ap->port_no ? 4 : 0);
+ pci_write_config_byte(dev, 0x44, slave_data);
+ } else { /* Master */
+ master_data &= 0xCCF4; /* Mask out IORDY|TIME1|DMAONLY
+ and master timing bits */
+ master_data |= control;
+ master_data |=
+ (timings[pio][0] << 12) |
+ (timings[pio][1] << 8);
+ }
+ udma_enable &= ~(1 << devid);
+ pci_write_config_word(dev, 0x40, master_data);
+ }
+ pci_write_config_byte(dev, 0x48, udma_enable);
+}
+
+static struct scsi_host_template it8213_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+ .resume = ata_scsi_device_resume,
+ .suspend = ata_scsi_device_suspend,
+};
+
+static const struct ata_port_operations it8213_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = it8213_set_piomode,
+ .set_dmamode = it8213_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = it8213_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .data_xfer = ata_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
+
+ .port_start = ata_port_start,
+};
+
+
+/**
+ * it8213_init_one - Register 8213 ATA PCI device with kernel services
+ * @pdev: PCI device to register
+ * @ent: Entry in it8213_pci_tbl matching with @pdev
+ *
+ * Called from kernel PCI layer.
+ *
+ * LOCKING:
+ * Inherited from PCI layer (may sleep).
+ *
+ * RETURNS:
+ * Zero on success, or -ERRNO value.
+ */
+
+static int it8213_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ static int printed_version;
+ static struct ata_port_info info = {
+ .sht = &it8213_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .udma_mask = 0x1f, /* UDMA 100 */
+ .port_ops = &it8213_ops,
+ };
+ static struct ata_port_info *port_info[2] = { &info, &info };
+
+ if (!printed_version++)
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "version " DRV_VERSION "\n");
+
+ /* Current IT8213 stuff is single port */
+ return ata_pci_init_one(pdev, port_info, 1);
+}
+
+static const struct pci_device_id it8213_pci_tbl[] = {
+ { PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8213), },
+
+ { } /* terminate list */
+};
+
+static struct pci_driver it8213_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = it8213_pci_tbl,
+ .probe = it8213_init_one,
+ .remove = ata_pci_remove_one,
+ .suspend = ata_pci_device_suspend,
+ .resume = ata_pci_device_resume,
+};
+
+static int __init it8213_init(void)
+{
+ return pci_register_driver(&it8213_pci_driver);
+}
+
+static void __exit it8213_exit(void)
+{
+ pci_unregister_driver(&it8213_pci_driver);
+}
+
+module_init(it8213_init);
+module_exit(it8213_exit);
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("SCSI low-level driver for the ITE 8213");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, it8213_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c
index e8afd486434..73394c75be4 100644
--- a/drivers/ata/pata_it821x.c
+++ b/drivers/ata/pata_it821x.c
@@ -492,7 +492,7 @@ static int it821x_smart_set_mode(struct ata_port *ap, struct ata_device **unused
/* Bits 5 and 6 indicate if DMA is active on master/slave */
/* It is possible that BMDMA isn't allocated */
if (ap->ioaddr.bmdma_addr)
- dma_enabled = inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+ dma_enabled = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
for (i = 0; i < ATA_MAX_DEVICES; i++) {
struct ata_device *dev = &ap->device[i];
@@ -531,23 +531,9 @@ static int it821x_smart_set_mode(struct ata_port *ap, struct ata_device **unused
static void it821x_dev_config(struct ata_port *ap, struct ata_device *adev)
{
- unsigned char model_num[40];
- char *s;
- unsigned int len;
-
- /* This block ought to be a library routine as it is in several
- drivers now */
-
- ata_id_string(adev->id, model_num, ATA_ID_PROD_OFS,
- sizeof(model_num));
- s = &model_num[0];
- len = strnlen(s, sizeof(model_num));
-
- /* ATAPI specifies that empty space is blank-filled; remove blanks */
- while ((len > 0) && (s[len - 1] == ' ')) {
- len--;
- s[len] = 0;
- }
+ unsigned char model_num[ATA_ID_PROD_LEN + 1];
+
+ ata_id_c_string(adev->id, model_num, ATA_ID_PROD, sizeof(model_num));
if (adev->max_sectors > 255)
adev->max_sectors = 255;
@@ -608,14 +594,10 @@ static int it821x_port_start(struct ata_port *ap)
if (ret < 0)
return ret;
- ap->private_data = kmalloc(sizeof(struct it821x_dev), GFP_KERNEL);
- if (ap->private_data == NULL) {
- ata_port_stop(ap);
+ itdev = devm_kzalloc(&pdev->dev, sizeof(struct it821x_dev), GFP_KERNEL);
+ if (itdev == NULL)
return -ENOMEM;
- }
-
- itdev = ap->private_data;
- memset(itdev, 0, sizeof(struct it821x_dev));
+ ap->private_data = itdev;
pci_read_config_byte(pdev, 0x50, &conf);
@@ -646,20 +628,6 @@ static int it821x_port_start(struct ata_port *ap)
return 0;
}
-/**
- * it821x_port_stop - port shutdown
- * @ap: ATA port being removed
- *
- * Release the private objects we added in it821x_port_start
- */
-
-static void it821x_port_stop(struct ata_port *ap) {
- kfree(ap->private_data);
- ap->private_data = NULL; /* We want an OOPS if we reuse this
- too late! */
- ata_port_stop(ap);
-}
-
static struct scsi_host_template it821x_sht = {
.module = THIS_MODULE,
.name = DRV_NAME,
@@ -706,14 +674,14 @@ static struct ata_port_operations it821x_smart_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = it821x_smart_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = it821x_port_start,
- .port_stop = it821x_port_stop,
- .host_stop = ata_host_stop
};
static struct ata_port_operations it821x_passthru_port_ops = {
@@ -742,14 +710,14 @@ static struct ata_port_operations it821x_passthru_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = it821x_passthru_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_clear = ata_bmdma_irq_clear,
.irq_handler = ata_interrupt,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = it821x_port_start,
- .port_stop = it821x_port_stop,
- .host_stop = ata_host_stop
};
static void __devinit it821x_disable_raid(struct pci_dev *pdev)
diff --git a/drivers/ata/pata_ixp4xx_cf.c b/drivers/ata/pata_ixp4xx_cf.c
index 23b8aab3ebd..3222ac7b945 100644
--- a/drivers/ata/pata_ixp4xx_cf.c
+++ b/drivers/ata/pata_ixp4xx_cf.c
@@ -95,14 +95,6 @@ static void ixp4xx_irq_clear(struct ata_port *ap)
{
}
-static void ixp4xx_host_stop (struct ata_host *host)
-{
- struct ixp4xx_pata_data *data = host->dev->platform_data;
-
- iounmap(data->cs0);
- iounmap(data->cs1);
-}
-
static struct scsi_host_template ixp4xx_sht = {
.module = THIS_MODULE,
.name = DRV_NAME,
@@ -139,10 +131,10 @@ static struct ata_port_operations ixp4xx_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ixp4xx_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ixp4xx_host_stop,
.phy_reset = ixp4xx_phy_reset,
};
@@ -150,9 +142,9 @@ static struct ata_port_operations ixp4xx_port_ops = {
static void ixp4xx_setup_port(struct ata_ioports *ioaddr,
struct ixp4xx_pata_data *data)
{
- ioaddr->cmd_addr = (unsigned long) data->cs0;
- ioaddr->altstatus_addr = (unsigned long) data->cs1 + 0x06;
- ioaddr->ctl_addr = (unsigned long) data->cs1 + 0x06;
+ ioaddr->cmd_addr = data->cs0;
+ ioaddr->altstatus_addr = data->cs1 + 0x06;
+ ioaddr->ctl_addr = data->cs1 + 0x06;
ata_std_ports(ioaddr);
@@ -162,19 +154,19 @@ static void ixp4xx_setup_port(struct ata_ioports *ioaddr,
* ixp4xx in little endian mode.
*/
- ioaddr->data_addr ^= 0x02;
- ioaddr->cmd_addr ^= 0x03;
- ioaddr->altstatus_addr ^= 0x03;
- ioaddr->ctl_addr ^= 0x03;
- ioaddr->error_addr ^= 0x03;
- ioaddr->feature_addr ^= 0x03;
- ioaddr->nsect_addr ^= 0x03;
- ioaddr->lbal_addr ^= 0x03;
- ioaddr->lbam_addr ^= 0x03;
- ioaddr->lbah_addr ^= 0x03;
- ioaddr->device_addr ^= 0x03;
- ioaddr->status_addr ^= 0x03;
- ioaddr->command_addr ^= 0x03;
+ *(unsigned long *)&ioaddr->data_addr ^= 0x02;
+ *(unsigned long *)&ioaddr->cmd_addr ^= 0x03;
+ *(unsigned long *)&ioaddr->altstatus_addr ^= 0x03;
+ *(unsigned long *)&ioaddr->ctl_addr ^= 0x03;
+ *(unsigned long *)&ioaddr->error_addr ^= 0x03;
+ *(unsigned long *)&ioaddr->feature_addr ^= 0x03;
+ *(unsigned long *)&ioaddr->nsect_addr ^= 0x03;
+ *(unsigned long *)&ioaddr->lbal_addr ^= 0x03;
+ *(unsigned long *)&ioaddr->lbam_addr ^= 0x03;
+ *(unsigned long *)&ioaddr->lbah_addr ^= 0x03;
+ *(unsigned long *)&ioaddr->device_addr ^= 0x03;
+ *(unsigned long *)&ioaddr->status_addr ^= 0x03;
+ *(unsigned long *)&ioaddr->command_addr ^= 0x03;
#endif
}
@@ -195,8 +187,8 @@ static __devinit int ixp4xx_pata_probe(struct platform_device *pdev)
pdev->dev.coherent_dma_mask = DMA_32BIT_MASK;
- data->cs0 = ioremap(cs0->start, 0x1000);
- data->cs1 = ioremap(cs1->start, 0x1000);
+ data->cs0 = devm_ioremap(&pdev->dev, cs0->start, 0x1000);
+ data->cs1 = devm_ioremap(&pdev->dev, cs1->start, 0x1000);
irq = platform_get_irq(pdev, 0);
if (irq)
@@ -238,7 +230,7 @@ static __devexit int ixp4xx_pata_remove(struct platform_device *dev)
{
struct ata_host *host = platform_get_drvdata(dev);
- ata_host_remove(host);
+ ata_host_detach(host);
platform_set_drvdata(dev, NULL);
return 0;
diff --git a/drivers/ata/pata_jmicron.c b/drivers/ata/pata_jmicron.c
index d50264af284..7a635dd326f 100644
--- a/drivers/ata/pata_jmicron.c
+++ b/drivers/ata/pata_jmicron.c
@@ -161,16 +161,16 @@ static const struct ata_port_operations jmicron_ops = {
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
/* IRQ-related hooks */
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
/* Generic PATA PCI ATA helpers */
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop,
};
@@ -221,7 +221,7 @@ static int jmicron_init_one (struct pci_dev *pdev, const struct pci_device_id *i
static int jmicron_reinit_one(struct pci_dev *pdev)
{
u32 reg;
-
+
switch(pdev->device) {
case PCI_DEVICE_ID_JMICRON_JMB368:
break;
diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c
index 581cb33c6f4..98c1fee4b30 100644
--- a/drivers/ata/pata_legacy.c
+++ b/drivers/ata/pata_legacy.c
@@ -89,9 +89,10 @@ static int probe_all; /* Set to check all ISA port ranges */
static int ht6560a; /* HT 6560A on primary 1, secondary 2, both 3 */
static int ht6560b; /* HT 6560A on primary 1, secondary 2, both 3 */
static int opti82c611a; /* Opti82c611A on primary 1, secondary 2, both 3 */
-static int opti82c46x; /* Opti 82c465MV present (pri/sec autodetect) */
+static int opti82c46x; /* Opti 82c465MV present (pri/sec autodetect) */
static int autospeed; /* Chip present which snoops speed changes */
static int pio_mask = 0x1F; /* PIO range for autospeed devices */
+static int iordy_mask = 0xFFFFFFFF; /* Use iordy if available */
/**
* legacy_set_mode - mode setting
@@ -113,6 +114,7 @@ static int legacy_set_mode(struct ata_port *ap, struct ata_device **unused)
for (i = 0; i < ATA_MAX_DEVICES; i++) {
struct ata_device *dev = &ap->device[i];
if (ata_dev_enabled(dev)) {
+ ata_dev_printk(dev, KERN_INFO, "configured for PIO\n");
dev->pio_mode = XFER_PIO_0;
dev->xfer_mode = XFER_PIO_0;
dev->xfer_shift = ATA_SHIFT_PIO;
@@ -164,14 +166,14 @@ static struct ata_port_operations simple_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer_noirq,
+ .data_xfer = ata_data_xfer_noirq,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
static struct ata_port_operations legacy_port_ops = {
@@ -189,14 +191,14 @@ static struct ata_port_operations legacy_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer_noirq,
+ .data_xfer = ata_data_xfer_noirq,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
/*
@@ -257,31 +259,33 @@ static void pdc_data_xfer_vlb(struct ata_device *adev, unsigned char *buf, unsig
local_irq_save(flags);
/* Perform the 32bit I/O synchronization sequence */
- inb(ap->ioaddr.nsect_addr);
- inb(ap->ioaddr.nsect_addr);
- inb(ap->ioaddr.nsect_addr);
+ ioread8(ap->ioaddr.nsect_addr);
+ ioread8(ap->ioaddr.nsect_addr);
+ ioread8(ap->ioaddr.nsect_addr);
/* Now the data */
if (write_data)
- outsl(ap->ioaddr.data_addr, buf, buflen >> 2);
+ iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
else
- insl(ap->ioaddr.data_addr, buf, buflen >> 2);
+ ioread32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
if (unlikely(slop)) {
u32 pad;
if (write_data) {
memcpy(&pad, buf + buflen - slop, slop);
- outl(le32_to_cpu(pad), ap->ioaddr.data_addr);
+ pad = le32_to_cpu(pad);
+ iowrite32(pad, ap->ioaddr.data_addr);
} else {
- pad = cpu_to_le16(inl(ap->ioaddr.data_addr));
+ pad = ioread32(ap->ioaddr.data_addr);
+ pad = cpu_to_le16(pad);
memcpy(buf + buflen - slop, &pad, slop);
}
}
local_irq_restore(flags);
}
else
- ata_pio_data_xfer_noirq(adev, buf, buflen, write_data);
+ ata_data_xfer_noirq(adev, buf, buflen, write_data);
}
static struct ata_port_operations pdc20230_port_ops = {
@@ -303,10 +307,10 @@ static struct ata_port_operations pdc20230_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
/*
@@ -332,8 +336,8 @@ static void ht6560a_set_piomode(struct ata_port *ap, struct ata_device *adev)
inb(0x3E6);
inb(0x3E6);
- outb(recover << 4 | active, ap->ioaddr.device_addr);
- inb(ap->ioaddr.status_addr);
+ iowrite8(recover << 4 | active, ap->ioaddr.device_addr);
+ ioread8(ap->ioaddr.status_addr);
}
static struct ata_port_operations ht6560a_port_ops = {
@@ -351,14 +355,14 @@ static struct ata_port_operations ht6560a_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer, /* Check vlb/noirq */
+ .data_xfer = ata_data_xfer, /* Check vlb/noirq */
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
/*
@@ -387,7 +391,7 @@ static void ht6560b_set_piomode(struct ata_port *ap, struct ata_device *adev)
inb(0x3E6);
inb(0x3E6);
- outb(recover << 4 | active, ap->ioaddr.device_addr);
+ iowrite8(recover << 4 | active, ap->ioaddr.device_addr);
if (adev->class != ATA_DEV_ATA) {
u8 rconf = inb(0x3E6);
@@ -396,7 +400,7 @@ static void ht6560b_set_piomode(struct ata_port *ap, struct ata_device *adev)
outb(rconf, 0x3E6);
}
}
- inb(ap->ioaddr.status_addr);
+ ioread8(ap->ioaddr.status_addr);
}
static struct ata_port_operations ht6560b_port_ops = {
@@ -414,14 +418,14 @@ static struct ata_port_operations ht6560b_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer, /* FIXME: Check 32bit and noirq */
+ .data_xfer = ata_data_xfer, /* FIXME: Check 32bit and noirq */
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
/*
@@ -464,12 +468,12 @@ static void opti82c611a_set_piomode(struct ata_port *ap, struct ata_device *adev
u8 rc;
/* Enter configuration mode */
- inw(ap->ioaddr.error_addr);
- inw(ap->ioaddr.error_addr);
- outb(3, ap->ioaddr.nsect_addr);
+ ioread16(ap->ioaddr.error_addr);
+ ioread16(ap->ioaddr.error_addr);
+ iowrite8(3, ap->ioaddr.nsect_addr);
/* Read VLB clock strapping */
- clock = 1000000000 / khz[inb(ap->ioaddr.lbah_addr) & 0x03];
+ clock = 1000000000 / khz[ioread8(ap->ioaddr.lbah_addr) & 0x03];
/* Get the timing data in cycles */
ata_timing_compute(adev, adev->pio_mode, &t, clock, 1000);
@@ -487,33 +491,33 @@ static void opti82c611a_set_piomode(struct ata_port *ap, struct ata_device *adev
setup = FIT(t.setup, 1, 4) - 1;
/* Select the right timing bank for write timing */
- rc = inb(ap->ioaddr.lbal_addr);
+ rc = ioread8(ap->ioaddr.lbal_addr);
rc &= 0x7F;
rc |= (adev->devno << 7);
- outb(rc, ap->ioaddr.lbal_addr);
+ iowrite8(rc, ap->ioaddr.lbal_addr);
/* Write the timings */
- outb(active << 4 | recover, ap->ioaddr.error_addr);
+ iowrite8(active << 4 | recover, ap->ioaddr.error_addr);
/* Select the right bank for read timings, also
load the shared timings for address */
- rc = inb(ap->ioaddr.device_addr);
+ rc = ioread8(ap->ioaddr.device_addr);
rc &= 0xC0;
rc |= adev->devno; /* Index select */
rc |= (setup << 4) | 0x04;
- outb(rc, ap->ioaddr.device_addr);
+ iowrite8(rc, ap->ioaddr.device_addr);
/* Load the read timings */
- outb(active << 4 | recover, ap->ioaddr.data_addr);
+ iowrite8(active << 4 | recover, ap->ioaddr.data_addr);
/* Ensure the timing register mode is right */
- rc = inb (ap->ioaddr.lbal_addr);
+ rc = ioread8(ap->ioaddr.lbal_addr);
rc &= 0x73;
rc |= 0x84;
- outb(rc, ap->ioaddr.lbal_addr);
+ iowrite8(rc, ap->ioaddr.lbal_addr);
/* Exit command mode */
- outb(0x83, ap->ioaddr.nsect_addr);
+ iowrite8(0x83, ap->ioaddr.nsect_addr);
}
@@ -532,14 +536,14 @@ static struct ata_port_operations opti82c611a_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
/*
@@ -563,9 +567,9 @@ static void opti82c46x_set_piomode(struct ata_port *ap, struct ata_device *adev)
sysclk = opti_syscfg(0xAC) & 0xC0; /* BIOS set */
/* Enter configuration mode */
- inw(ap->ioaddr.error_addr);
- inw(ap->ioaddr.error_addr);
- outb(3, ap->ioaddr.nsect_addr);
+ ioread16(ap->ioaddr.error_addr);
+ ioread16(ap->ioaddr.error_addr);
+ iowrite8(3, ap->ioaddr.nsect_addr);
/* Read VLB clock strapping */
clock = 1000000000 / khz[sysclk];
@@ -586,33 +590,33 @@ static void opti82c46x_set_piomode(struct ata_port *ap, struct ata_device *adev)
setup = FIT(t.setup, 1, 4) - 1;
/* Select the right timing bank for write timing */
- rc = inb(ap->ioaddr.lbal_addr);
+ rc = ioread8(ap->ioaddr.lbal_addr);
rc &= 0x7F;
rc |= (adev->devno << 7);
- outb(rc, ap->ioaddr.lbal_addr);
+ iowrite8(rc, ap->ioaddr.lbal_addr);
/* Write the timings */
- outb(active << 4 | recover, ap->ioaddr.error_addr);
+ iowrite8(active << 4 | recover, ap->ioaddr.error_addr);
/* Select the right bank for read timings, also
load the shared timings for address */
- rc = inb(ap->ioaddr.device_addr);
+ rc = ioread8(ap->ioaddr.device_addr);
rc &= 0xC0;
rc |= adev->devno; /* Index select */
rc |= (setup << 4) | 0x04;
- outb(rc, ap->ioaddr.device_addr);
+ iowrite8(rc, ap->ioaddr.device_addr);
/* Load the read timings */
- outb(active << 4 | recover, ap->ioaddr.data_addr);
+ iowrite8(active << 4 | recover, ap->ioaddr.data_addr);
/* Ensure the timing register mode is right */
- rc = inb (ap->ioaddr.lbal_addr);
+ rc = ioread8(ap->ioaddr.lbal_addr);
rc &= 0x73;
rc |= 0x84;
- outb(rc, ap->ioaddr.lbal_addr);
+ iowrite8(rc, ap->ioaddr.lbal_addr);
/* Exit command mode */
- outb(0x83, ap->ioaddr.nsect_addr);
+ iowrite8(0x83, ap->ioaddr.nsect_addr);
/* We need to know this for quad device on the MVB */
ap->host->private_data = ap;
@@ -662,14 +666,14 @@ static struct ata_port_operations opti82c46x_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = opti82c46x_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
@@ -689,25 +693,32 @@ static __init int legacy_init_one(int port, unsigned long io, unsigned long ctrl
struct legacy_data *ld = &legacy_data[nr_legacy_host];
struct ata_probe_ent ae;
struct platform_device *pdev;
- int ret = -EBUSY;
struct ata_port_operations *ops = &legacy_port_ops;
+ void __iomem *io_addr, *ctrl_addr;
int pio_modes = pio_mask;
u32 mask = (1 << port);
-
- if (request_region(io, 8, "pata_legacy") == NULL)
- return -EBUSY;
- if (request_region(ctrl, 1, "pata_legacy") == NULL)
- goto fail_io;
+ u32 iordy = (iordy_mask & mask) ? 0: ATA_FLAG_NO_IORDY;
+ int ret;
pdev = platform_device_register_simple(DRV_NAME, nr_legacy_host, NULL, 0);
- if (IS_ERR(pdev)) {
- ret = PTR_ERR(pdev);
- goto fail_dev;
- }
+ if (IS_ERR(pdev))
+ return PTR_ERR(pdev);
+
+ ret = -EBUSY;
+ if (devm_request_region(&pdev->dev, io, 8, "pata_legacy") == NULL ||
+ devm_request_region(&pdev->dev, ctrl, 1, "pata_legacy") == NULL)
+ goto fail;
+
+ ret = -ENOMEM;
+ io_addr = devm_ioport_map(&pdev->dev, io, 8);
+ ctrl_addr = devm_ioport_map(&pdev->dev, ctrl, 1);
+ if (!io_addr || !ctrl_addr)
+ goto fail;
if (ht6560a & mask) {
ops = &ht6560a_port_ops;
pio_modes = 0x07;
+ iordy = ATA_FLAG_NO_IORDY;
}
if (ht6560b & mask) {
ops = &ht6560b_port_ops;
@@ -743,6 +754,7 @@ static __init int legacy_init_one(int port, unsigned long io, unsigned long ctrl
printk(KERN_INFO "PDC20230-C/20630 VLB ATA controller detected.\n");
pio_modes = 0x07;
ops = &pdc20230_port_ops;
+ iordy = ATA_FLAG_NO_IORDY;
udelay(100);
inb(0x1F5);
} else {
@@ -760,6 +772,7 @@ static __init int legacy_init_one(int port, unsigned long io, unsigned long ctrl
/* Chip does mode setting by command snooping */
if (ops == &legacy_port_ops && (autospeed & mask))
ops = &simple_port_ops;
+
memset(&ae, 0, sizeof(struct ata_probe_ent));
INIT_LIST_HEAD(&ae.node);
ae.dev = &pdev->dev;
@@ -769,28 +782,23 @@ static __init int legacy_init_one(int port, unsigned long io, unsigned long ctrl
ae.pio_mask = pio_modes;
ae.irq = irq;
ae.irq_flags = 0;
- ae.port_flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST;
- ae.port[0].cmd_addr = io;
- ae.port[0].altstatus_addr = ctrl;
- ae.port[0].ctl_addr = ctrl;
+ ae.port_flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST|iordy;
+ ae.port[0].cmd_addr = io_addr;
+ ae.port[0].altstatus_addr = ctrl_addr;
+ ae.port[0].ctl_addr = ctrl_addr;
ata_std_ports(&ae.port[0]);
ae.private_data = ld;
- ret = ata_device_add(&ae);
- if (ret == 0) {
- ret = -ENODEV;
+ ret = -ENODEV;
+ if (!ata_device_add(&ae))
goto fail;
- }
+
legacy_host[nr_legacy_host++] = dev_get_drvdata(&pdev->dev);
ld->platform_dev = pdev;
return 0;
fail:
platform_device_unregister(pdev);
-fail_dev:
- release_region(ctrl, 1);
-fail_io:
- release_region(io, 8);
return ret;
}
@@ -923,15 +931,11 @@ static __exit void legacy_exit(void)
for (i = 0; i < nr_legacy_host; i++) {
struct legacy_data *ld = &legacy_data[i];
- struct ata_port *ap =legacy_host[i]->ports[0];
- unsigned long io = ap->ioaddr.cmd_addr;
- unsigned long ctrl = ap->ioaddr.ctl_addr;
- ata_host_remove(legacy_host[i]);
+
+ ata_host_detach(legacy_host[i]);
platform_device_unregister(ld->platform_dev);
if (ld->timing)
release_region(ld->timing, 2);
- release_region(io, 8);
- release_region(ctrl, 1);
}
}
@@ -947,6 +951,7 @@ module_param(ht6560b, int, 0);
module_param(opti82c611a, int, 0);
module_param(opti82c46x, int, 0);
module_param(pio_mask, int, 0);
+module_param(iordy_mask, int, 0);
module_init(legacy_init);
module_exit(legacy_exit);
diff --git a/drivers/ata/pata_marvell.c b/drivers/ata/pata_marvell.c
index 1c810ea0025..13a70ac6f1d 100644
--- a/drivers/ata/pata_marvell.c
+++ b/drivers/ata/pata_marvell.c
@@ -45,10 +45,10 @@ static int marvell_pre_reset(struct ata_port *ap)
for(i = 0; i <= 0x0F; i++)
printk("%02X:%02X ", i, readb(barp + i));
printk("\n");
-
+
devices = readl(barp + 0x0C);
pci_iounmap(pdev, barp);
-
+
if ((pdev->device == 0x6145) && (ap->port_no == 0) &&
(!(devices & 0x10))) /* PATA enable ? */
return -ENOENT;
@@ -57,7 +57,7 @@ static int marvell_pre_reset(struct ata_port *ap)
switch(ap->port_no)
{
case 0:
- if (inb(ap->ioaddr.bmdma_addr + 1) & 1)
+ if (ioread8(ap->ioaddr.bmdma_addr + 1) & 1)
ap->cbl = ATA_CBL_PATA40;
else
ap->cbl = ATA_CBL_PATA80;
@@ -129,16 +129,16 @@ static const struct ata_port_operations marvell_ops = {
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
/* Timeout handling */
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
/* Generic PATA PCI ATA helpers */
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop,
};
diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c
new file mode 100644
index 00000000000..29e1809e5ec
--- /dev/null
+++ b/drivers/ata/pata_mpc52xx.c
@@ -0,0 +1,536 @@
+/*
+ * drivers/ata/pata_mpc52xx.c
+ *
+ * libata driver for the Freescale MPC52xx on-chip IDE interface
+ *
+ * Copyright (C) 2006 Sylvain Munaut <tnt@246tNt.com>
+ * Copyright (C) 2003 Mipsys - Benjamin Herrenschmidt
+ *
+ * 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/slab.h>
+#include <linux/delay.h>
+#include <linux/libata.h>
+
+#include <asm/types.h>
+#include <asm/prom.h>
+#include <asm/of_platform.h>
+#include <asm/mpc52xx.h>
+
+
+#define DRV_NAME "mpc52xx_ata"
+#define DRV_VERSION "0.1.0"
+
+
+/* Private structures used by the driver */
+struct mpc52xx_ata_timings {
+ u32 pio1;
+ u32 pio2;
+};
+
+struct mpc52xx_ata_priv {
+ unsigned int ipb_period;
+ struct mpc52xx_ata __iomem * ata_regs;
+ int ata_irq;
+ struct mpc52xx_ata_timings timings[2];
+ int csel;
+};
+
+
+/* ATAPI-4 PIO specs (in ns) */
+static const int ataspec_t0[5] = {600, 383, 240, 180, 120};
+static const int ataspec_t1[5] = { 70, 50, 30, 30, 25};
+static const int ataspec_t2_8[5] = {290, 290, 290, 80, 70};
+static const int ataspec_t2_16[5] = {165, 125, 100, 80, 70};
+static const int ataspec_t2i[5] = { 0, 0, 0, 70, 25};
+static const int ataspec_t4[5] = { 30, 20, 15, 10, 10};
+static const int ataspec_ta[5] = { 35, 35, 35, 35, 35};
+
+#define CALC_CLKCYC(c,v) ((((v)+(c)-1)/(c)))
+
+
+/* Bit definitions inside the registers */
+#define MPC52xx_ATA_HOSTCONF_SMR 0x80000000UL /* State machine reset */
+#define MPC52xx_ATA_HOSTCONF_FR 0x40000000UL /* FIFO Reset */
+#define MPC52xx_ATA_HOSTCONF_IE 0x02000000UL /* Enable interrupt in PIO */
+#define MPC52xx_ATA_HOSTCONF_IORDY 0x01000000UL /* Drive supports IORDY protocol */
+
+#define MPC52xx_ATA_HOSTSTAT_TIP 0x80000000UL /* Transaction in progress */
+#define MPC52xx_ATA_HOSTSTAT_UREP 0x40000000UL /* UDMA Read Extended Pause */
+#define MPC52xx_ATA_HOSTSTAT_RERR 0x02000000UL /* Read Error */
+#define MPC52xx_ATA_HOSTSTAT_WERR 0x01000000UL /* Write Error */
+
+#define MPC52xx_ATA_FIFOSTAT_EMPTY 0x01 /* FIFO Empty */
+
+#define MPC52xx_ATA_DMAMODE_WRITE 0x01 /* Write DMA */
+#define MPC52xx_ATA_DMAMODE_READ 0x02 /* Read DMA */
+#define MPC52xx_ATA_DMAMODE_UDMA 0x04 /* UDMA enabled */
+#define MPC52xx_ATA_DMAMODE_IE 0x08 /* Enable drive interrupt to CPU in DMA mode */
+#define MPC52xx_ATA_DMAMODE_FE 0x10 /* FIFO Flush enable in Rx mode */
+#define MPC52xx_ATA_DMAMODE_FR 0x20 /* FIFO Reset */
+#define MPC52xx_ATA_DMAMODE_HUT 0x40 /* Host UDMA burst terminate */
+
+
+/* Structure of the hardware registers */
+struct mpc52xx_ata {
+
+ /* Host interface registers */
+ u32 config; /* ATA + 0x00 Host configuration */
+ u32 host_status; /* ATA + 0x04 Host controller status */
+ u32 pio1; /* ATA + 0x08 PIO Timing 1 */
+ u32 pio2; /* ATA + 0x0c PIO Timing 2 */
+ u32 mdma1; /* ATA + 0x10 MDMA Timing 1 */
+ u32 mdma2; /* ATA + 0x14 MDMA Timing 2 */
+ u32 udma1; /* ATA + 0x18 UDMA Timing 1 */
+ u32 udma2; /* ATA + 0x1c UDMA Timing 2 */
+ u32 udma3; /* ATA + 0x20 UDMA Timing 3 */
+ u32 udma4; /* ATA + 0x24 UDMA Timing 4 */
+ u32 udma5; /* ATA + 0x28 UDMA Timing 5 */
+ u32 share_cnt; /* ATA + 0x2c ATA share counter */
+ u32 reserved0[3];
+
+ /* FIFO registers */
+ u32 fifo_data; /* ATA + 0x3c */
+ u8 fifo_status_frame; /* ATA + 0x40 */
+ u8 fifo_status; /* ATA + 0x41 */
+ u16 reserved7[1];
+ u8 fifo_control; /* ATA + 0x44 */
+ u8 reserved8[5];
+ u16 fifo_alarm; /* ATA + 0x4a */
+ u16 reserved9;
+ u16 fifo_rdp; /* ATA + 0x4e */
+ u16 reserved10;
+ u16 fifo_wrp; /* ATA + 0x52 */
+ u16 reserved11;
+ u16 fifo_lfrdp; /* ATA + 0x56 */
+ u16 reserved12;
+ u16 fifo_lfwrp; /* ATA + 0x5a */
+
+ /* Drive TaskFile registers */
+ u8 tf_control; /* ATA + 0x5c TASKFILE Control/Alt Status */
+ u8 reserved13[3];
+ u16 tf_data; /* ATA + 0x60 TASKFILE Data */
+ u16 reserved14;
+ u8 tf_features; /* ATA + 0x64 TASKFILE Features/Error */
+ u8 reserved15[3];
+ u8 tf_sec_count; /* ATA + 0x68 TASKFILE Sector Count */
+ u8 reserved16[3];
+ u8 tf_sec_num; /* ATA + 0x6c TASKFILE Sector Number */
+ u8 reserved17[3];
+ u8 tf_cyl_low; /* ATA + 0x70 TASKFILE Cylinder Low */
+ u8 reserved18[3];
+ u8 tf_cyl_high; /* ATA + 0x74 TASKFILE Cylinder High */
+ u8 reserved19[3];
+ u8 tf_dev_head; /* ATA + 0x78 TASKFILE Device/Head */
+ u8 reserved20[3];
+ u8 tf_command; /* ATA + 0x7c TASKFILE Command/Status */
+ u8 dma_mode; /* ATA + 0x7d ATA Host DMA Mode configuration */
+ u8 reserved21[2];
+};
+
+
+/* ======================================================================== */
+/* Aux fns */
+/* ======================================================================== */
+
+
+/* MPC52xx low level hw control */
+
+static int
+mpc52xx_ata_compute_pio_timings(struct mpc52xx_ata_priv *priv, int dev, int pio)
+{
+ struct mpc52xx_ata_timings *timing = &priv->timings[dev];
+ unsigned int ipb_period = priv->ipb_period;
+ unsigned int t0, t1, t2_8, t2_16, t2i, t4, ta;
+
+ if ((pio<0) || (pio>4))
+ return -EINVAL;
+
+ t0 = CALC_CLKCYC(ipb_period, 1000 * ataspec_t0[pio]);
+ t1 = CALC_CLKCYC(ipb_period, 1000 * ataspec_t1[pio]);
+ t2_8 = CALC_CLKCYC(ipb_period, 1000 * ataspec_t2_8[pio]);
+ t2_16 = CALC_CLKCYC(ipb_period, 1000 * ataspec_t2_16[pio]);
+ t2i = CALC_CLKCYC(ipb_period, 1000 * ataspec_t2i[pio]);
+ t4 = CALC_CLKCYC(ipb_period, 1000 * ataspec_t4[pio]);
+ ta = CALC_CLKCYC(ipb_period, 1000 * ataspec_ta[pio]);
+
+ timing->pio1 = (t0 << 24) | (t2_8 << 16) | (t2_16 << 8) | (t2i);
+ timing->pio2 = (t4 << 24) | (t1 << 16) | (ta << 8);
+
+ return 0;
+}
+
+static void
+mpc52xx_ata_apply_timings(struct mpc52xx_ata_priv *priv, int device)
+{
+ struct mpc52xx_ata __iomem *regs = priv->ata_regs;
+ struct mpc52xx_ata_timings *timing = &priv->timings[device];
+
+ out_be32(&regs->pio1, timing->pio1);
+ out_be32(&regs->pio2, timing->pio2);
+ out_be32(&regs->mdma1, 0);
+ out_be32(&regs->mdma2, 0);
+ out_be32(&regs->udma1, 0);
+ out_be32(&regs->udma2, 0);
+ out_be32(&regs->udma3, 0);
+ out_be32(&regs->udma4, 0);
+ out_be32(&regs->udma5, 0);
+
+ priv->csel = device;
+}
+
+static int
+mpc52xx_ata_hw_init(struct mpc52xx_ata_priv *priv)
+{
+ struct mpc52xx_ata __iomem *regs = priv->ata_regs;
+ int tslot;
+
+ /* Clear share_cnt (all sample code do this ...) */
+ out_be32(&regs->share_cnt, 0);
+
+ /* Configure and reset host */
+ out_be32(&regs->config,
+ MPC52xx_ATA_HOSTCONF_IE |
+ MPC52xx_ATA_HOSTCONF_IORDY |
+ MPC52xx_ATA_HOSTCONF_SMR |
+ MPC52xx_ATA_HOSTCONF_FR);
+
+ udelay(10);
+
+ out_be32(&regs->config,
+ MPC52xx_ATA_HOSTCONF_IE |
+ MPC52xx_ATA_HOSTCONF_IORDY);
+
+ /* Set the time slot to 1us */
+ tslot = CALC_CLKCYC(priv->ipb_period, 1000000);
+ out_be32(&regs->share_cnt, tslot << 16 );
+
+ /* Init timings to PIO0 */
+ memset(priv->timings, 0x00, 2*sizeof(struct mpc52xx_ata_timings));
+
+ mpc52xx_ata_compute_pio_timings(priv, 0, 0);
+ mpc52xx_ata_compute_pio_timings(priv, 1, 0);
+
+ mpc52xx_ata_apply_timings(priv, 0);
+
+ return 0;
+}
+
+
+/* ======================================================================== */
+/* libata driver */
+/* ======================================================================== */
+
+static void
+mpc52xx_ata_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct mpc52xx_ata_priv *priv = ap->host->private_data;
+ int pio, rv;
+
+ pio = adev->pio_mode - XFER_PIO_0;
+
+ rv = mpc52xx_ata_compute_pio_timings(priv, adev->devno, pio);
+
+ if (rv) {
+ printk(KERN_ERR DRV_NAME
+ ": Trying to select invalid PIO mode %d\n", pio);
+ return;
+ }
+
+ mpc52xx_ata_apply_timings(priv, adev->devno);
+}
+static void
+mpc52xx_ata_dev_select(struct ata_port *ap, unsigned int device)
+{
+ struct mpc52xx_ata_priv *priv = ap->host->private_data;
+
+ if (device != priv->csel)
+ mpc52xx_ata_apply_timings(priv, device);
+
+ ata_std_dev_select(ap,device);
+}
+
+static void
+mpc52xx_ata_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset, NULL,
+ ata_std_postreset);
+}
+
+
+
+static struct scsi_host_template mpc52xx_ata_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations mpc52xx_ata_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = mpc52xx_ata_set_piomode,
+ .dev_select = mpc52xx_ata_dev_select,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = mpc52xx_ata_error_handler,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .data_xfer = ata_data_xfer,
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
+ .port_start = ata_port_start,
+};
+
+static struct ata_probe_ent mpc52xx_ata_probe_ent = {
+ .port_ops = &mpc52xx_ata_port_ops,
+ .sht = &mpc52xx_ata_sht,
+ .n_ports = 1,
+ .pio_mask = 0x1f, /* Up to PIO4 */
+ .mwdma_mask = 0x00, /* No MWDMA */
+ .udma_mask = 0x00, /* No UDMA */
+ .port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .irq_flags = 0,
+};
+
+static int __devinit
+mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv)
+{
+ struct ata_probe_ent *ae = &mpc52xx_ata_probe_ent;
+ struct ata_ioports *aio = &ae->port[0];
+ int rv;
+
+ INIT_LIST_HEAD(&ae->node);
+ ae->dev = dev;
+ ae->irq = priv->ata_irq;
+
+ aio->cmd_addr = 0; /* Don't have a classic reg block */
+ aio->altstatus_addr = &priv->ata_regs->tf_control;
+ aio->ctl_addr = &priv->ata_regs->tf_control;
+ aio->data_addr = &priv->ata_regs->tf_data;
+ aio->error_addr = &priv->ata_regs->tf_features;
+ aio->feature_addr = &priv->ata_regs->tf_features;
+ aio->nsect_addr = &priv->ata_regs->tf_sec_count;
+ aio->lbal_addr = &priv->ata_regs->tf_sec_num;
+ aio->lbam_addr = &priv->ata_regs->tf_cyl_low;
+ aio->lbah_addr = &priv->ata_regs->tf_cyl_high;
+ aio->device_addr = &priv->ata_regs->tf_dev_head;
+ aio->status_addr = &priv->ata_regs->tf_command;
+ aio->command_addr = &priv->ata_regs->tf_command;
+
+ ae->private_data = priv;
+
+ rv = ata_device_add(ae);
+
+ return rv ? 0 : -EINVAL;
+}
+
+static struct mpc52xx_ata_priv *
+mpc52xx_ata_remove_one(struct device *dev)
+{
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct mpc52xx_ata_priv *priv = host->private_data;
+
+ ata_host_detach(host);
+
+ return priv;
+}
+
+
+/* ======================================================================== */
+/* OF Platform driver */
+/* ======================================================================== */
+
+static int __devinit
+mpc52xx_ata_probe(struct of_device *op, const struct of_device_id *match)
+{
+ unsigned int ipb_freq;
+ struct resource res_mem;
+ int ata_irq = NO_IRQ;
+ struct mpc52xx_ata __iomem *ata_regs;
+ struct mpc52xx_ata_priv *priv;
+ int rv;
+
+ /* Get ipb frequency */
+ ipb_freq = mpc52xx_find_ipb_freq(op->node);
+ if (!ipb_freq) {
+ printk(KERN_ERR DRV_NAME ": "
+ "Unable to find IPB Bus frequency\n" );
+ return -ENODEV;
+ }
+
+ /* Get IRQ and register */
+ rv = of_address_to_resource(op->node, 0, &res_mem);
+ if (rv) {
+ printk(KERN_ERR DRV_NAME ": "
+ "Error while parsing device node resource\n" );
+ return rv;
+ }
+
+ ata_irq = irq_of_parse_and_map(op->node, 0);
+ if (ata_irq == NO_IRQ) {
+ printk(KERN_ERR DRV_NAME ": "
+ "Error while mapping the irq\n");
+ return -EINVAL;
+ }
+
+ /* Request mem region */
+ if (!devm_request_mem_region(&op->dev, res_mem.start,
+ sizeof(struct mpc52xx_ata), DRV_NAME)) {
+ printk(KERN_ERR DRV_NAME ": "
+ "Error while requesting mem region\n");
+ rv = -EBUSY;
+ goto err;
+ }
+
+ /* Remap registers */
+ ata_regs = devm_ioremap(&op->dev, res_mem.start,
+ sizeof(struct mpc52xx_ata));
+ if (!ata_regs) {
+ printk(KERN_ERR DRV_NAME ": "
+ "Error while mapping register set\n");
+ rv = -ENOMEM;
+ goto err;
+ }
+
+ /* Prepare our private structure */
+ priv = devm_kzalloc(&op->dev, sizeof(struct mpc52xx_ata_priv),
+ GFP_ATOMIC);
+ if (!priv) {
+ printk(KERN_ERR DRV_NAME ": "
+ "Error while allocating private structure\n");
+ rv = -ENOMEM;
+ goto err;
+ }
+
+ priv->ipb_period = 1000000000 / (ipb_freq / 1000);
+ priv->ata_regs = ata_regs;
+ priv->ata_irq = ata_irq;
+ priv->csel = -1;
+
+ /* Init the hw */
+ rv = mpc52xx_ata_hw_init(priv);
+ if (rv) {
+ printk(KERN_ERR DRV_NAME ": Error during HW init\n");
+ goto err;
+ }
+
+ /* Register ourselves to libata */
+ rv = mpc52xx_ata_init_one(&op->dev, priv);
+ if (rv) {
+ printk(KERN_ERR DRV_NAME ": "
+ "Error while registering to ATA layer\n");
+ return rv;
+ }
+
+ /* Done */
+ return 0;
+
+ /* Error path */
+err:
+ irq_dispose_mapping(ata_irq);
+ return rv;
+}
+
+static int
+mpc52xx_ata_remove(struct of_device *op)
+{
+ struct mpc52xx_ata_priv *priv;
+
+ priv = mpc52xx_ata_remove_one(&op->dev);
+ irq_dispose_mapping(priv->ata_irq);
+
+ return 0;
+}
+
+
+#ifdef CONFIG_PM
+
+static int
+mpc52xx_ata_suspend(struct of_device *op, pm_message_t state)
+{
+ return 0; /* FIXME : What to do here ? */
+}
+
+static int
+mpc52xx_ata_resume(struct of_device *op)
+{
+ return 0; /* FIXME : What to do here ? */
+}
+
+#endif
+
+
+static struct of_device_id mpc52xx_ata_of_match[] = {
+ {
+ .type = "ata",
+ .compatible = "mpc5200-ata",
+ },
+ {},
+};
+
+
+static struct of_platform_driver mpc52xx_ata_of_platform_driver = {
+ .owner = THIS_MODULE,
+ .name = DRV_NAME,
+ .match_table = mpc52xx_ata_of_match,
+ .probe = mpc52xx_ata_probe,
+ .remove = mpc52xx_ata_remove,
+#ifdef CONFIG_PM
+ .suspend = mpc52xx_ata_suspend,
+ .resume = mpc52xx_ata_resume,
+#endif
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+
+/* ======================================================================== */
+/* Module */
+/* ======================================================================== */
+
+static int __init
+mpc52xx_ata_init(void)
+{
+ printk(KERN_INFO "ata: MPC52xx IDE/ATA libata driver\n");
+ return of_register_platform_driver(&mpc52xx_ata_of_platform_driver);
+}
+
+static void __exit
+mpc52xx_ata_exit(void)
+{
+ of_unregister_platform_driver(&mpc52xx_ata_of_platform_driver);
+}
+
+module_init(mpc52xx_ata_init);
+module_exit(mpc52xx_ata_exit);
+
+MODULE_AUTHOR("Sylvain Munaut <tnt@246tNt.com>");
+MODULE_DESCRIPTION("Freescale MPC52xx IDE/ATA libata driver");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(of, mpc52xx_ata_of_match);
+MODULE_VERSION(DRV_VERSION);
+
diff --git a/drivers/ata/pata_mpiix.c b/drivers/ata/pata_mpiix.c
index 4ccca938675..f2e7115f7ab 100644
--- a/drivers/ata/pata_mpiix.c
+++ b/drivers/ata/pata_mpiix.c
@@ -35,7 +35,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_mpiix"
-#define DRV_VERSION "0.7.3"
+#define DRV_VERSION "0.7.5"
enum {
IDETIM = 0x6C, /* IDE control register */
@@ -49,12 +49,9 @@ enum {
static int mpiix_pre_reset(struct ata_port *ap)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- static const struct pci_bits mpiix_enable_bits[] = {
- { 0x6D, 1, 0x80, 0x80 },
- { 0x6F, 1, 0x80, 0x80 }
- };
+ static const struct pci_bits mpiix_enable_bits = { 0x6D, 1, 0x80, 0x80 };
- if (!pci_test_config_bits(pdev, &mpiix_enable_bits[ap->port_no]))
+ if (!pci_test_config_bits(pdev, &mpiix_enable_bits))
return -ENOENT;
ap->cbl = ATA_CBL_PATA40;
return ata_std_prereset(ap);
@@ -80,8 +77,8 @@ static void mpiix_error_handler(struct ata_port *ap)
* @adev: ATA device
*
* Called to do the PIO mode setup. The MPIIX allows us to program the
- * IORDY sample point (2-5 clocks), recovery 1-4 clocks and whether
- * prefetching or iordy are used.
+ * IORDY sample point (2-5 clocks), recovery (1-4 clocks) and whether
+ * prefetching or IORDY are used.
*
* This would get very ugly because we can only program timing for one
* device at a time, the other gets PIO0. Fortunately libata calls
@@ -103,18 +100,19 @@ static void mpiix_set_piomode(struct ata_port *ap, struct ata_device *adev)
{ 2, 3 }, };
pci_read_config_word(pdev, IDETIM, &idetim);
- /* Mask the IORDY/TIME/PPE0 bank for this device */
+
+ /* Mask the IORDY/TIME/PPE for this device */
if (adev->class == ATA_DEV_ATA)
- control |= PPE; /* PPE enable for disk */
+ control |= PPE; /* Enable prefetch/posting for disk */
if (ata_pio_need_iordy(adev))
- control |= IORDY; /* IORDY */
- if (pio > 0)
+ control |= IORDY;
+ if (pio > 1)
control |= FTIM; /* This drive is on the fast timing bank */
/* Mask out timing and clear both TIME bank selects */
idetim &= 0xCCEE;
- idetim &= ~(0x07 << (2 * adev->devno));
- idetim |= (control << (2 * adev->devno));
+ idetim &= ~(0x07 << (4 * adev->devno));
+ idetim |= control << (4 * adev->devno);
idetim |= (timings[pio][0] << 12) | (timings[pio][1] << 8);
pci_write_config_word(pdev, IDETIM, idetim);
@@ -188,23 +186,24 @@ static struct ata_port_operations mpiix_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = mpiix_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id)
{
/* Single threaded by the PCI probe logic */
- static struct ata_probe_ent probe[2];
+ static struct ata_probe_ent probe;
static int printed_version;
+ void __iomem *cmd_addr, *ctl_addr;
u16 idetim;
- int enabled;
+ int irq;
if (!printed_version++)
dev_printk(KERN_DEBUG, &dev->dev, "version " DRV_VERSION "\n");
@@ -217,65 +216,49 @@ static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id)
if (!(idetim & ENABLED))
return -ENODEV;
+ /* See if it's primary or secondary channel... */
+ if (!(idetim & SECONDARY)) {
+ irq = 14;
+ cmd_addr = devm_ioport_map(&dev->dev, 0x1F0, 8);
+ ctl_addr = devm_ioport_map(&dev->dev, 0x3F6, 1);
+ } else {
+ irq = 15;
+ cmd_addr = devm_ioport_map(&dev->dev, 0x170, 8);
+ ctl_addr = devm_ioport_map(&dev->dev, 0x376, 1);
+ }
+
+ if (!cmd_addr || !ctl_addr)
+ return -ENOMEM;
+
/* We do our own plumbing to avoid leaking special cases for whacko
ancient hardware into the core code. There are two issues to
worry about. #1 The chip is a bridge so if in legacy mode and
without BARs set fools the setup. #2 If you pci_disable_device
the MPIIX your box goes castors up */
- INIT_LIST_HEAD(&probe[0].node);
- probe[0].dev = pci_dev_to_dev(dev);
- probe[0].port_ops = &mpiix_port_ops;
- probe[0].sht = &mpiix_sht;
- probe[0].pio_mask = 0x1F;
- probe[0].irq = 14;
- probe[0].irq_flags = SA_SHIRQ;
- probe[0].port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST;
- probe[0].n_ports = 1;
- probe[0].port[0].cmd_addr = 0x1F0;
- probe[0].port[0].ctl_addr = 0x3F6;
- probe[0].port[0].altstatus_addr = 0x3F6;
-
- /* The secondary lurks at different addresses but is otherwise
- the same beastie */
-
- INIT_LIST_HEAD(&probe[1].node);
- probe[1] = probe[0];
- probe[1].irq = 15;
- probe[1].port[0].cmd_addr = 0x170;
- probe[1].port[0].ctl_addr = 0x376;
- probe[1].port[0].altstatus_addr = 0x376;
+ INIT_LIST_HEAD(&probe.node);
+ probe.dev = pci_dev_to_dev(dev);
+ probe.port_ops = &mpiix_port_ops;
+ probe.sht = &mpiix_sht;
+ probe.pio_mask = 0x1F;
+ probe.irq_flags = IRQF_SHARED;
+ probe.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST;
+ probe.n_ports = 1;
+
+ probe.irq = irq;
+ probe.port[0].cmd_addr = cmd_addr;
+ probe.port[0].ctl_addr = ctl_addr;
+ probe.port[0].altstatus_addr = ctl_addr;
/* Let libata fill in the port details */
- ata_std_ports(&probe[0].port[0]);
- ata_std_ports(&probe[1].port[0]);
+ ata_std_ports(&probe.port[0]);
/* Now add the port that is active */
- enabled = (idetim & SECONDARY) ? 1 : 0;
-
- if (ata_device_add(&probe[enabled]))
+ if (ata_device_add(&probe))
return 0;
return -ENODEV;
}
-/**
- * mpiix_remove_one - device unload
- * @pdev: PCI device being removed
- *
- * Handle an unplug/unload event for a PCI device. Unload the
- * PCI driver but do not use the default handler as we *MUST NOT*
- * disable the device as it has other functions.
- */
-
-static void __devexit mpiix_remove_one(struct pci_dev *pdev)
-{
- struct device *dev = pci_dev_to_dev(pdev);
- struct ata_host *host = dev_get_drvdata(dev);
-
- ata_host_remove(host);
- dev_set_drvdata(dev, NULL);
-}
-
static const struct pci_device_id mpiix[] = {
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82371MX), },
@@ -286,7 +269,7 @@ static struct pci_driver mpiix_pci_driver = {
.name = DRV_NAME,
.id_table = mpiix,
.probe = mpiix_init_one,
- .remove = mpiix_remove_one,
+ .remove = ata_pci_remove_one,
.suspend = ata_pci_device_suspend,
.resume = ata_pci_device_resume,
};
diff --git a/drivers/ata/pata_netcell.c b/drivers/ata/pata_netcell.c
index cf7fe037471..e8393e19be4 100644
--- a/drivers/ata/pata_netcell.c
+++ b/drivers/ata/pata_netcell.c
@@ -89,16 +89,16 @@ static const struct ata_port_operations netcell_ops = {
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
/* IRQ-related hooks */
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
/* Generic PATA PCI ATA helpers */
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop,
};
diff --git a/drivers/ata/pata_ns87410.c b/drivers/ata/pata_ns87410.c
index c3032eb9010..3d1fa487c48 100644
--- a/drivers/ata/pata_ns87410.c
+++ b/drivers/ata/pata_ns87410.c
@@ -179,14 +179,14 @@ static struct ata_port_operations ns87410_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ns87410_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
static int ns87410_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ata/pata_oldpiix.c b/drivers/ata/pata_oldpiix.c
index 10ac3cc1018..45215aa05e7 100644
--- a/drivers/ata/pata_oldpiix.c
+++ b/drivers/ata/pata_oldpiix.c
@@ -25,7 +25,7 @@
#include <linux/ata.h>
#define DRV_NAME "pata_oldpiix"
-#define DRV_VERSION "0.5.2"
+#define DRV_VERSION "0.5.3"
/**
* oldpiix_pre_reset - probe begin
@@ -94,19 +94,21 @@ static void oldpiix_set_piomode (struct ata_port *ap, struct ata_device *adev)
{ 2, 1 },
{ 2, 3 }, };
- if (pio > 2)
- control |= 1; /* TIME1 enable */
+ if (pio > 1)
+ control |= 1; /* TIME */
if (ata_pio_need_iordy(adev))
- control |= 2; /* IE IORDY */
+ control |= 2; /* IE */
- /* Intel specifies that the PPE functionality is for disk only */
+ /* Intel specifies that the prefetch/posting is for disk only */
if (adev->class == ATA_DEV_ATA)
- control |= 4; /* PPE enable */
+ control |= 4; /* PPE */
pci_read_config_word(dev, idetm_port, &idetm_data);
- /* Enable PPE, IE and TIME as appropriate. Clear the other
- drive timing bits */
+ /*
+ * Set PPE, IE and TIME as appropriate.
+ * Clear the other drive's timing bits.
+ */
if (adev->devno == 0) {
idetm_data &= 0xCCE0;
idetm_data |= control;
@@ -259,14 +261,14 @@ static const struct ata_port_operations oldpiix_pata_ops = {
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = oldpiix_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop,
};
diff --git a/drivers/ata/pata_opti.c b/drivers/ata/pata_opti.c
index c2988b0aa8e..da1aa148b37 100644
--- a/drivers/ata/pata_opti.c
+++ b/drivers/ata/pata_opti.c
@@ -95,18 +95,18 @@ static void opti_error_handler(struct ata_port *ap)
static void opti_write_reg(struct ata_port *ap, u8 val, int reg)
{
- unsigned long regio = ap->ioaddr.cmd_addr;
+ void __iomem *regio = ap->ioaddr.cmd_addr;
/* These 3 unlock the control register access */
- inw(regio + 1);
- inw(regio + 1);
- outb(3, regio + 2);
+ ioread16(regio + 1);
+ ioread16(regio + 1);
+ iowrite8(3, regio + 2);
/* Do the I/O */
- outb(val, regio + reg);
+ iowrite8(val, regio + reg);
/* Relock */
- outb(0x83, regio + 2);
+ iowrite8(0x83, regio + 2);
}
/**
@@ -124,7 +124,7 @@ static void opti_set_piomode(struct ata_port *ap, struct ata_device *adev)
struct ata_device *pair = ata_dev_pair(adev);
int clock;
int pio = adev->pio_mode - XFER_PIO_0;
- unsigned long regio = ap->ioaddr.cmd_addr;
+ void __iomem *regio = ap->ioaddr.cmd_addr;
u8 addr;
/* Address table precomputed with prefetch off and a DCLK of 2 */
@@ -137,8 +137,8 @@ static void opti_set_piomode(struct ata_port *ap, struct ata_device *adev)
{ 0x58, 0x44, 0x32, 0x22, 0x21 }
};
- outb(0xff, regio + 5);
- clock = inw(regio + 5) & 1;
+ iowrite8(0xff, regio + 5);
+ clock = ioread16(regio + 5) & 1;
/*
* As with many controllers the address setup time is shared
@@ -205,14 +205,14 @@ static struct ata_port_operations opti_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
static int opti_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ata/pata_optidma.c b/drivers/ata/pata_optidma.c
index 80d111c569d..d80b36e209c 100644
--- a/drivers/ata/pata_optidma.c
+++ b/drivers/ata/pata_optidma.c
@@ -91,12 +91,12 @@ static void optidma_error_handler(struct ata_port *ap)
static void optidma_unlock(struct ata_port *ap)
{
- unsigned long regio = ap->ioaddr.cmd_addr;
+ void __iomem *regio = ap->ioaddr.cmd_addr;
/* These 3 unlock the control register access */
- inw(regio + 1);
- inw(regio + 1);
- outb(3, regio + 2);
+ ioread16(regio + 1);
+ ioread16(regio + 1);
+ iowrite8(3, regio + 2);
}
/**
@@ -108,10 +108,10 @@ static void optidma_unlock(struct ata_port *ap)
static void optidma_lock(struct ata_port *ap)
{
- unsigned long regio = ap->ioaddr.cmd_addr;
+ void __iomem *regio = ap->ioaddr.cmd_addr;
/* Relock */
- outb(0x83, regio + 2);
+ iowrite8(0x83, regio + 2);
}
/**
@@ -133,7 +133,7 @@ static void optidma_set_mode(struct ata_port *ap, struct ata_device *adev, u8 mo
struct ata_device *pair = ata_dev_pair(adev);
int pio = adev->pio_mode - XFER_PIO_0;
int dma = adev->dma_mode - XFER_MW_DMA_0;
- unsigned long regio = ap->ioaddr.cmd_addr;
+ void __iomem *regio = ap->ioaddr.cmd_addr;
u8 addr;
/* Address table precomputed with a DCLK of 2 */
@@ -178,20 +178,20 @@ static void optidma_set_mode(struct ata_port *ap, struct ata_device *adev, u8 mo
/* Commence primary programming sequence */
/* First we load the device number into the timing select */
- outb(adev->devno, regio + MISC_REG);
+ iowrite8(adev->devno, regio + MISC_REG);
/* Now we load the data timings into read data/write data */
if (mode < XFER_MW_DMA_0) {
- outb(data_rec_timing[pci_clock][pio], regio + READ_REG);
- outb(data_rec_timing[pci_clock][pio], regio + WRITE_REG);
+ iowrite8(data_rec_timing[pci_clock][pio], regio + READ_REG);
+ iowrite8(data_rec_timing[pci_clock][pio], regio + WRITE_REG);
} else if (mode < XFER_UDMA_0) {
- outb(dma_data_rec_timing[pci_clock][dma], regio + READ_REG);
- outb(dma_data_rec_timing[pci_clock][dma], regio + WRITE_REG);
+ iowrite8(dma_data_rec_timing[pci_clock][dma], regio + READ_REG);
+ iowrite8(dma_data_rec_timing[pci_clock][dma], regio + WRITE_REG);
}
/* Finally we load the address setup into the misc register */
- outb(addr | adev->devno, regio + MISC_REG);
+ iowrite8(addr | adev->devno, regio + MISC_REG);
/* Programming sequence complete, timing 0 dev 0, timing 1 dev 1 */
- outb(0x85, regio + CNTRL_REG);
+ iowrite8(0x85, regio + CNTRL_REG);
/* Switch back to IDE mode */
optidma_lock(ap);
@@ -389,14 +389,14 @@ static struct ata_port_operations optidma_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
static struct ata_port_operations optiplus_port_ops = {
@@ -424,14 +424,14 @@ static struct ata_port_operations optiplus_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
/**
diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c
index 9ed7f58424a..36468ec6454 100644
--- a/drivers/ata/pata_pcmcia.c
+++ b/drivers/ata/pata_pcmcia.c
@@ -88,14 +88,14 @@ static struct ata_port_operations pcmcia_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer_noirq,
+ .data_xfer = ata_data_xfer_noirq,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
#define CS_CHECK(fn, ret) \
@@ -123,6 +123,7 @@ static int pcmcia_init_one(struct pcmcia_device *pdev)
cistpl_cftable_entry_t *cfg;
int pass, last_ret = 0, last_fn = 0, is_kme = 0, ret = -ENOMEM;
unsigned long io_base, ctl_base;
+ void __iomem *io_addr, *ctl_addr;
info = kzalloc(sizeof(*info), GFP_KERNEL);
if (info == NULL)
@@ -233,10 +234,17 @@ next_entry:
CS_CHECK(RequestIRQ, pcmcia_request_irq(pdev, &pdev->irq));
CS_CHECK(RequestConfiguration, pcmcia_request_configuration(pdev, &pdev->conf));
+ /* iomap */
+ ret = -ENOMEM;
+ io_addr = devm_ioport_map(&pdev->dev, io_base, 8);
+ ctl_addr = devm_ioport_map(&pdev->dev, ctl_base, 1);
+ if (!io_addr || !ctl_addr)
+ goto failed;
+
/* Success. Disable the IRQ nIEN line, do quirks */
- outb(0x02, ctl_base);
+ iowrite8(0x02, ctl_addr);
if (is_kme)
- outb(0x81, ctl_base + 0x01);
+ iowrite8(0x81, ctl_addr + 0x01);
/* FIXME: Could be more ports at base + 0x10 but we only deal with
one right now */
@@ -256,13 +264,14 @@ next_entry:
ae.n_ports = 1;
ae.pio_mask = 1; /* ISA so PIO 0 cycles */
ae.irq = pdev->irq.AssignedIRQ;
- ae.irq_flags = SA_SHIRQ;
+ ae.irq_flags = IRQF_SHARED;
ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST;
- ae.port[0].cmd_addr = io_base;
- ae.port[0].altstatus_addr = ctl_base;
- ae.port[0].ctl_addr = ctl_base;
+ ae.port[0].cmd_addr = io_addr;
+ ae.port[0].altstatus_addr = ctl_addr;
+ ae.port[0].ctl_addr = ctl_addr;
ata_std_ports(&ae.port[0]);
+ ret = -ENODEV;
if (ata_device_add(&ae) == 0)
goto failed;
@@ -298,7 +307,7 @@ static void pcmcia_remove_one(struct pcmcia_device *pdev)
/* If we have attached the device to the ATA layer, detach it */
if (info->ndev) {
struct ata_host *host = dev_get_drvdata(dev);
- ata_host_remove(host);
+ ata_host_detach(host);
dev_set_drvdata(dev, NULL);
}
info->ndev = 0;
diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c
index 76dd1c935db..61537873d28 100644
--- a/drivers/ata/pata_pdc2027x.c
+++ b/drivers/ata/pata_pdc2027x.c
@@ -33,7 +33,6 @@
#include <scsi/scsi_host.h>
#include <scsi/scsi_cmnd.h>
#include <linux/libata.h>
-#include <asm/io.h>
#define DRV_NAME "pata_pdc2027x"
#define DRV_VERSION "0.74-ac5"
@@ -46,6 +45,8 @@
#endif
enum {
+ PDC_MMIO_BAR = 5,
+
PDC_UDMA_100 = 0,
PDC_UDMA_133 = 1,
@@ -62,7 +63,6 @@ enum {
};
static int pdc2027x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
-static void pdc2027x_remove_one(struct pci_dev *pdev);
static void pdc2027x_error_handler(struct ata_port *ap);
static void pdc2027x_set_piomode(struct ata_port *ap, struct ata_device *adev);
static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev);
@@ -123,7 +123,7 @@ static struct pci_driver pdc2027x_pci_driver = {
.name = DRV_NAME,
.id_table = pdc2027x_pci_tbl,
.probe = pdc2027x_init_one,
- .remove = __devexit_p(pdc2027x_remove_one),
+ .remove = ata_pci_remove_one,
};
static struct scsi_host_template pdc2027x_sht = {
@@ -160,7 +160,7 @@ static struct ata_port_operations pdc2027x_pata100_ops = {
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_mmio_data_xfer,
+ .data_xfer = ata_data_xfer,
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
@@ -169,10 +169,10 @@ static struct ata_port_operations pdc2027x_pata100_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_pci_host_stop,
};
static struct ata_port_operations pdc2027x_pata133_ops = {
@@ -194,7 +194,7 @@ static struct ata_port_operations pdc2027x_pata133_ops = {
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_mmio_data_xfer,
+ .data_xfer = ata_data_xfer,
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
@@ -203,10 +203,10 @@ static struct ata_port_operations pdc2027x_pata133_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_pci_host_stop,
};
static struct ata_port_info pdc2027x_port_info[] = {
@@ -245,7 +245,7 @@ MODULE_DEVICE_TABLE(pci, pdc2027x_pci_tbl);
*/
static inline void __iomem *port_mmio(struct ata_port *ap, unsigned int offset)
{
- return ap->host->mmio_base + ap->port_no * 0x100 + offset;
+ return ap->host->iomap[PDC_MMIO_BAR] + ap->port_no * 0x100 + offset;
}
/**
@@ -526,18 +526,19 @@ static int pdc2027x_check_atapi_dma(struct ata_queued_cmd *qc)
static long pdc_read_counter(struct ata_probe_ent *probe_ent)
{
+ void __iomem *mmio_base = probe_ent->iomap[PDC_MMIO_BAR];
long counter;
int retry = 1;
u32 bccrl, bccrh, bccrlv, bccrhv;
retry:
- bccrl = readl(probe_ent->mmio_base + PDC_BYTE_COUNT) & 0xffff;
- bccrh = readl(probe_ent->mmio_base + PDC_BYTE_COUNT + 0x100) & 0xffff;
+ bccrl = readl(mmio_base + PDC_BYTE_COUNT) & 0xffff;
+ bccrh = readl(mmio_base + PDC_BYTE_COUNT + 0x100) & 0xffff;
rmb();
/* Read the counter values again for verification */
- bccrlv = readl(probe_ent->mmio_base + PDC_BYTE_COUNT) & 0xffff;
- bccrhv = readl(probe_ent->mmio_base + PDC_BYTE_COUNT + 0x100) & 0xffff;
+ bccrlv = readl(mmio_base + PDC_BYTE_COUNT) & 0xffff;
+ bccrhv = readl(mmio_base + PDC_BYTE_COUNT + 0x100) & 0xffff;
rmb();
counter = (bccrh << 15) | bccrl;
@@ -568,7 +569,7 @@ retry:
*/
static void pdc_adjust_pll(struct ata_probe_ent *probe_ent, long pll_clock, unsigned int board_idx)
{
-
+ void __iomem *mmio_base = probe_ent->iomap[PDC_MMIO_BAR];
u16 pll_ctl;
long pll_clock_khz = pll_clock / 1000;
long pout_required = board_idx? PDC_133_MHZ:PDC_100_MHZ;
@@ -587,7 +588,7 @@ static void pdc_adjust_pll(struct ata_probe_ent *probe_ent, long pll_clock, unsi
/* Show the current clock value of PLL control register
* (maybe already configured by the firmware)
*/
- pll_ctl = readw(probe_ent->mmio_base + PDC_PLL_CTL);
+ pll_ctl = readw(mmio_base + PDC_PLL_CTL);
PDPRINTK("pll_ctl[%X]\n", pll_ctl);
#endif
@@ -627,8 +628,8 @@ static void pdc_adjust_pll(struct ata_probe_ent *probe_ent, long pll_clock, unsi
PDPRINTK("Writing pll_ctl[%X]\n", pll_ctl);
- writew(pll_ctl, probe_ent->mmio_base + PDC_PLL_CTL);
- readw(probe_ent->mmio_base + PDC_PLL_CTL); /* flush */
+ writew(pll_ctl, mmio_base + PDC_PLL_CTL);
+ readw(mmio_base + PDC_PLL_CTL); /* flush */
/* Wait the PLL circuit to be stable */
mdelay(30);
@@ -638,7 +639,7 @@ static void pdc_adjust_pll(struct ata_probe_ent *probe_ent, long pll_clock, unsi
* Show the current clock value of PLL control register
* (maybe configured by the firmware)
*/
- pll_ctl = readw(probe_ent->mmio_base + PDC_PLL_CTL);
+ pll_ctl = readw(mmio_base + PDC_PLL_CTL);
PDPRINTK("pll_ctl[%X]\n", pll_ctl);
#endif
@@ -654,6 +655,7 @@ static void pdc_adjust_pll(struct ata_probe_ent *probe_ent, long pll_clock, unsi
*/
static long pdc_detect_pll_input_clock(struct ata_probe_ent *probe_ent)
{
+ void __iomem *mmio_base = probe_ent->iomap[PDC_MMIO_BAR];
u32 scr;
long start_count, end_count;
long pll_clock;
@@ -662,10 +664,10 @@ static long pdc_detect_pll_input_clock(struct ata_probe_ent *probe_ent)
start_count = pdc_read_counter(probe_ent);
/* Start the test mode */
- scr = readl(probe_ent->mmio_base + PDC_SYS_CTL);
+ scr = readl(mmio_base + PDC_SYS_CTL);
PDPRINTK("scr[%X]\n", scr);
- writel(scr | (0x01 << 14), probe_ent->mmio_base + PDC_SYS_CTL);
- readl(probe_ent->mmio_base + PDC_SYS_CTL); /* flush */
+ writel(scr | (0x01 << 14), mmio_base + PDC_SYS_CTL);
+ readl(mmio_base + PDC_SYS_CTL); /* flush */
/* Let the counter run for 100 ms. */
mdelay(100);
@@ -674,10 +676,10 @@ static long pdc_detect_pll_input_clock(struct ata_probe_ent *probe_ent)
end_count = pdc_read_counter(probe_ent);
/* Stop the test mode */
- scr = readl(probe_ent->mmio_base + PDC_SYS_CTL);
+ scr = readl(mmio_base + PDC_SYS_CTL);
PDPRINTK("scr[%X]\n", scr);
- writel(scr & ~(0x01 << 14), probe_ent->mmio_base + PDC_SYS_CTL);
- readl(probe_ent->mmio_base + PDC_SYS_CTL); /* flush */
+ writel(scr & ~(0x01 << 14), mmio_base + PDC_SYS_CTL);
+ readl(mmio_base + PDC_SYS_CTL); /* flush */
/* calculate the input clock in Hz */
pll_clock = (start_count - end_count) * 10;
@@ -722,7 +724,7 @@ static int pdc_hardware_init(struct pci_dev *pdev, struct ata_probe_ent *pe, uns
* @port: ata ioports to setup
* @base: base address
*/
-static void pdc_ata_setup_port(struct ata_ioports *port, unsigned long base)
+static void pdc_ata_setup_port(struct ata_ioports *port, void __iomem *base)
{
port->cmd_addr =
port->data_addr = base;
@@ -755,48 +757,37 @@ static int __devinit pdc2027x_init_one(struct pci_dev *pdev, const struct pci_de
static int printed_version;
unsigned int board_idx = (unsigned int) ent->driver_data;
- struct ata_probe_ent *probe_ent = NULL;
- unsigned long base;
+ struct ata_probe_ent *probe_ent;
void __iomem *mmio_base;
int rc;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
- rc = pci_enable_device(pdev);
+ rc = pcim_enable_device(pdev);
if (rc)
return rc;
- rc = pci_request_regions(pdev, DRV_NAME);
+ rc = pcim_iomap_regions(pdev, 1 << PDC_MMIO_BAR, DRV_NAME);
if (rc)
- goto err_out;
+ return rc;
rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
if (rc)
- goto err_out_regions;
+ return rc;
rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
if (rc)
- goto err_out_regions;
+ return rc;
/* Prepare the probe entry */
- probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL);
- if (probe_ent == NULL) {
- rc = -ENOMEM;
- goto err_out_regions;
- }
+ probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL);
+ if (probe_ent == NULL)
+ return -ENOMEM;
probe_ent->dev = pci_dev_to_dev(pdev);
INIT_LIST_HEAD(&probe_ent->node);
- mmio_base = pci_iomap(pdev, 5, 0);
- if (!mmio_base) {
- rc = -ENOMEM;
- goto err_out_free_ent;
- }
-
- base = (unsigned long) mmio_base;
-
probe_ent->sht = pdc2027x_port_info[board_idx].sht;
probe_ent->port_flags = pdc2027x_port_info[board_idx].flags;
probe_ent->pio_mask = pdc2027x_port_info[board_idx].pio_mask;
@@ -805,13 +796,15 @@ static int __devinit pdc2027x_init_one(struct pci_dev *pdev, const struct pci_de
probe_ent->port_ops = pdc2027x_port_info[board_idx].port_ops;
probe_ent->irq = pdev->irq;
- probe_ent->irq_flags = SA_SHIRQ;
- probe_ent->mmio_base = mmio_base;
+ probe_ent->irq_flags = IRQF_SHARED;
+ probe_ent->iomap = pcim_iomap_table(pdev);
- pdc_ata_setup_port(&probe_ent->port[0], base + 0x17c0);
- probe_ent->port[0].bmdma_addr = base + 0x1000;
- pdc_ata_setup_port(&probe_ent->port[1], base + 0x15c0);
- probe_ent->port[1].bmdma_addr = base + 0x1008;
+ mmio_base = probe_ent->iomap[PDC_MMIO_BAR];
+
+ pdc_ata_setup_port(&probe_ent->port[0], mmio_base + 0x17c0);
+ probe_ent->port[0].bmdma_addr = mmio_base + 0x1000;
+ pdc_ata_setup_port(&probe_ent->port[1], mmio_base + 0x15c0);
+ probe_ent->port[1].bmdma_addr = mmio_base + 0x1008;
probe_ent->n_ports = 2;
@@ -820,32 +813,13 @@ static int __devinit pdc2027x_init_one(struct pci_dev *pdev, const struct pci_de
/* initialize adapter */
if (pdc_hardware_init(pdev, probe_ent, board_idx) != 0)
- goto err_out_free_ent;
+ return -EIO;
- ata_device_add(probe_ent);
- kfree(probe_ent);
+ if (!ata_device_add(probe_ent))
+ return -ENODEV;
+ devm_kfree(&pdev->dev, probe_ent);
return 0;
-
-err_out_free_ent:
- kfree(probe_ent);
-err_out_regions:
- pci_release_regions(pdev);
-err_out:
- pci_disable_device(pdev);
- return rc;
-}
-
-/**
- * pdc2027x_remove_one - Called to remove a single instance of the
- * adapter.
- *
- * @dev: The PCI device to remove.
- * FIXME: module load/unload not working yet
- */
-static void __devexit pdc2027x_remove_one(struct pci_dev *pdev)
-{
- ata_pci_remove_one(pdev);
}
/**
diff --git a/drivers/ata/pata_pdc202xx_old.c b/drivers/ata/pata_pdc202xx_old.c
index ad691b9e774..6dd63413a52 100644
--- a/drivers/ata/pata_pdc202xx_old.c
+++ b/drivers/ata/pata_pdc202xx_old.c
@@ -170,17 +170,17 @@ static void pdc2026x_bmdma_start(struct ata_queued_cmd *qc)
struct ata_taskfile *tf = &qc->tf;
int sel66 = ap->port_no ? 0x08: 0x02;
- unsigned long master = ap->host->ports[0]->ioaddr.bmdma_addr;
- unsigned long clock = master + 0x11;
- unsigned long atapi_reg = master + 0x20 + (4 * ap->port_no);
+ void __iomem *master = ap->host->ports[0]->ioaddr.bmdma_addr;
+ void __iomem *clock = master + 0x11;
+ void __iomem *atapi_reg = master + 0x20 + (4 * ap->port_no);
u32 len;
/* Check we keep host level locking here */
if (adev->dma_mode >= XFER_UDMA_2)
- outb(inb(clock) | sel66, clock);
+ iowrite8(ioread8(clock) | sel66, clock);
else
- outb(inb(clock) & ~sel66, clock);
+ iowrite8(ioread8(clock) & ~sel66, clock);
/* The DMA clocks may have been trashed by a reset. FIXME: make conditional
and move to qc_issue ? */
@@ -189,17 +189,14 @@ static void pdc2026x_bmdma_start(struct ata_queued_cmd *qc)
/* Cases the state machine will not complete correctly without help */
if ((tf->flags & ATA_TFLAG_LBA48) || tf->protocol == ATA_PROT_ATAPI_DMA)
{
- if (tf->flags & ATA_TFLAG_LBA48)
- len = qc->nsect * 512;
- else
- len = qc->nbytes;
+ len = qc->nbytes;
if (tf->flags & ATA_TFLAG_WRITE)
len |= 0x06000000;
else
len |= 0x05000000;
- outl(len, atapi_reg);
+ iowrite32(len, atapi_reg);
}
/* Activate DMA */
@@ -222,19 +219,19 @@ static void pdc2026x_bmdma_stop(struct ata_queued_cmd *qc)
int sel66 = ap->port_no ? 0x08: 0x02;
/* The clock bits are in the same register for both channels */
- unsigned long master = ap->host->ports[0]->ioaddr.bmdma_addr;
- unsigned long clock = master + 0x11;
- unsigned long atapi_reg = master + 0x20 + (4 * ap->port_no);
+ void __iomem *master = ap->host->ports[0]->ioaddr.bmdma_addr;
+ void __iomem *clock = master + 0x11;
+ void __iomem *atapi_reg = master + 0x20 + (4 * ap->port_no);
/* Cases the state machine will not complete correctly */
if (tf->protocol == ATA_PROT_ATAPI_DMA || ( tf->flags & ATA_TFLAG_LBA48)) {
- outl(0, atapi_reg);
- outb(inb(clock) & ~sel66, clock);
+ iowrite32(0, atapi_reg);
+ iowrite8(ioread8(clock) & ~sel66, clock);
}
/* Check we keep host level locking here */
/* Flip back to 33Mhz for PIO */
if (adev->dma_mode >= XFER_UDMA_2)
- outb(inb(clock) & ~sel66, clock);
+ iowrite8(ioread8(clock) & ~sel66, clock);
ata_bmdma_stop(qc);
}
@@ -297,14 +294,14 @@ static struct ata_port_operations pdc2024x_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
static struct ata_port_operations pdc2026x_port_ops = {
@@ -331,14 +328,14 @@ static struct ata_port_operations pdc2026x_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
static int pdc202xx_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c
index 40ae11cbfda..479a326114e 100644
--- a/drivers/ata/pata_platform.c
+++ b/drivers/ata/pata_platform.c
@@ -47,23 +47,6 @@ static int pata_platform_set_mode(struct ata_port *ap, struct ata_device **unuse
return 0;
}
-static void pata_platform_host_stop(struct ata_host *host)
-{
- int i;
-
- /*
- * Unmap the bases for MMIO
- */
- for (i = 0; i < host->n_ports; i++) {
- struct ata_port *ap = host->ports[i];
-
- if (ap->flags & ATA_FLAG_MMIO) {
- iounmap((void __iomem *)ap->ioaddr.ctl_addr);
- iounmap((void __iomem *)ap->ioaddr.cmd_addr);
- }
- }
-}
-
static struct scsi_host_template pata_platform_sht = {
.module = THIS_MODULE,
.name = DRV_NAME,
@@ -100,14 +83,14 @@ static struct ata_port_operations pata_platform_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer_noirq,
+ .data_xfer = ata_data_xfer_noirq,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = pata_platform_host_stop
};
static void pata_platform_setup_port(struct ata_ioports *ioaddr,
@@ -153,7 +136,6 @@ static int __devinit pata_platform_probe(struct platform_device *pdev)
struct resource *io_res, *ctl_res;
struct ata_probe_ent ae;
unsigned int mmio;
- int ret;
/*
* Simple resource validation ..
@@ -207,46 +189,29 @@ static int __devinit pata_platform_probe(struct platform_device *pdev)
* Handle the MMIO case
*/
if (mmio) {
- ae.port_flags |= ATA_FLAG_MMIO;
-
- ae.port[0].cmd_addr = (unsigned long)ioremap(io_res->start,
+ ae.port[0].cmd_addr = devm_ioremap(&pdev->dev, io_res->start,
io_res->end - io_res->start + 1);
- if (unlikely(!ae.port[0].cmd_addr)) {
- dev_err(&pdev->dev, "failed to remap IO base\n");
- return -ENXIO;
- }
-
- ae.port[0].ctl_addr = (unsigned long)ioremap(ctl_res->start,
+ ae.port[0].ctl_addr = devm_ioremap(&pdev->dev, ctl_res->start,
ctl_res->end - ctl_res->start + 1);
- if (unlikely(!ae.port[0].ctl_addr)) {
- dev_err(&pdev->dev, "failed to remap CTL base\n");
- ret = -ENXIO;
- goto bad_remap;
- }
} else {
- ae.port[0].cmd_addr = io_res->start;
- ae.port[0].ctl_addr = ctl_res->start;
+ ae.port[0].cmd_addr = devm_ioport_map(&pdev->dev, io_res->start,
+ io_res->end - io_res->start + 1);
+ ae.port[0].ctl_addr = devm_ioport_map(&pdev->dev, ctl_res->start,
+ ctl_res->end - ctl_res->start + 1);
+ }
+ if (!ae.port[0].cmd_addr || !ae.port[0].ctl_addr) {
+ dev_err(&pdev->dev, "failed to map IO/CTL base\n");
+ return -ENOMEM;
}
ae.port[0].altstatus_addr = ae.port[0].ctl_addr;
pata_platform_setup_port(&ae.port[0], pdev->dev.platform_data);
- if (unlikely(ata_device_add(&ae) == 0)) {
- ret = -ENODEV;
- goto add_failed;
- }
+ if (unlikely(ata_device_add(&ae) == 0))
+ return -ENODEV;
return 0;
-
-add_failed:
- if (ae.port[0].ctl_addr && mmio)
- iounmap((void __iomem *)ae.port[0].ctl_addr);
-bad_remap:
- if (ae.port[0].cmd_addr && mmio)
- iounmap((void __iomem *)ae.port[0].cmd_addr);
-
- return ret;
}
/**
@@ -261,7 +226,7 @@ static int __devexit pata_platform_remove(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct ata_host *host = dev_get_drvdata(dev);
- ata_host_remove(host);
+ ata_host_detach(host);
dev_set_drvdata(dev, NULL);
return 0;
diff --git a/drivers/ata/pata_qdi.c b/drivers/ata/pata_qdi.c
index afc0d990e7d..4362141976a 100644
--- a/drivers/ata/pata_qdi.c
+++ b/drivers/ata/pata_qdi.c
@@ -131,22 +131,24 @@ static void qdi_data_xfer(struct ata_device *adev, unsigned char *buf, unsigned
if (ata_id_has_dword_io(adev->id)) {
if (write_data)
- outsl(ap->ioaddr.data_addr, buf, buflen >> 2);
+ iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
else
- insl(ap->ioaddr.data_addr, buf, buflen >> 2);
+ ioread32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
if (unlikely(slop)) {
u32 pad;
if (write_data) {
memcpy(&pad, buf + buflen - slop, slop);
- outl(le32_to_cpu(pad), ap->ioaddr.data_addr);
+ pad = le32_to_cpu(pad);
+ iowrite32(pad, ap->ioaddr.data_addr);
} else {
- pad = cpu_to_le32(inl(ap->ioaddr.data_addr));
+ pad = ioread32(ap->ioaddr.data_addr);
+ pad = cpu_to_le32(pad);
memcpy(buf + buflen - slop, &pad, slop);
}
}
} else
- ata_pio_data_xfer(adev, buf, buflen, write_data);
+ ata_data_xfer(adev, buf, buflen, write_data);
}
static struct scsi_host_template qdi_sht = {
@@ -189,10 +191,10 @@ static struct ata_port_operations qdi6500_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
static struct ata_port_operations qdi6580_port_ops = {
@@ -217,10 +219,10 @@ static struct ata_port_operations qdi6580_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
/**
@@ -238,10 +240,9 @@ static __init int qdi_init_one(unsigned long port, int type, unsigned long io, i
{
struct ata_probe_ent ae;
struct platform_device *pdev;
+ void __iomem *io_addr, *ctl_addr;
int ret;
- unsigned long ctrl = io + 0x206;
-
/*
* Fill in a probe structure first of all
*/
@@ -250,6 +251,12 @@ static __init int qdi_init_one(unsigned long port, int type, unsigned long io, i
if (IS_ERR(pdev))
return PTR_ERR(pdev);
+ ret = -ENOMEM;
+ io_addr = devm_ioport_map(&pdev->dev, io, 8);
+ ctl_addr = devm_ioport_map(&pdev->dev, io + 0x206, 1);
+ if (!io_addr || !ctl_addr)
+ goto fail;
+
memset(&ae, 0, sizeof(struct ata_probe_ent));
INIT_LIST_HEAD(&ae.node);
ae.dev = &pdev->dev;
@@ -257,19 +264,21 @@ static __init int qdi_init_one(unsigned long port, int type, unsigned long io, i
if (type == 6580) {
ae.port_ops = &qdi6580_port_ops;
ae.pio_mask = 0x1F;
+ ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST;
} else {
ae.port_ops = &qdi6500_port_ops;
ae.pio_mask = 0x07; /* Actually PIO3 !IORDY is possible */
+ ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST |
+ ATA_FLAG_NO_IORDY;
}
ae.sht = &qdi_sht;
ae.n_ports = 1;
ae.irq = irq;
ae.irq_flags = 0;
- ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST;
- ae.port[0].cmd_addr = io;
- ae.port[0].altstatus_addr = ctrl;
- ae.port[0].ctl_addr = ctrl;
+ ae.port[0].cmd_addr = io_addr;
+ ae.port[0].altstatus_addr = ctl_addr;
+ ae.port[0].ctl_addr = ctl_addr;
ata_std_ports(&ae.port[0]);
/*
@@ -282,14 +291,17 @@ static __init int qdi_init_one(unsigned long port, int type, unsigned long io, i
qdi_data[nr_qdi_host].platform_dev = pdev;
printk(KERN_INFO DRV_NAME": qd%d at 0x%lx.\n", type, io);
- ret = ata_device_add(&ae);
- if (ret == 0) {
- platform_device_unregister(pdev);
- return -ENODEV;
- }
+
+ ret = -ENODEV;
+ if (!ata_device_add(&ae))
+ goto fail;
qdi_host[nr_qdi_host++] = dev_get_drvdata(&pdev->dev);
return 0;
+
+ fail:
+ platform_device_unregister(pdev);
+ return ret;
}
/**
@@ -382,7 +394,7 @@ static __exit void qdi_exit(void)
int i;
for (i = 0; i < nr_qdi_host; i++) {
- ata_host_remove(qdi_host[i]);
+ ata_host_detach(qdi_host[i]);
/* Free the control resource. The 6580 dual channel has the resources
* claimed as a pair of 2 byte resources so we need no special cases...
*/
diff --git a/drivers/ata/pata_radisys.c b/drivers/ata/pata_radisys.c
index 065541d034a..0d1e571ef63 100644
--- a/drivers/ata/pata_radisys.c
+++ b/drivers/ata/pata_radisys.c
@@ -255,14 +255,14 @@ static const struct ata_port_operations radisys_pata_ops = {
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = radisys_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop,
};
diff --git a/drivers/ata/pata_rz1000.c b/drivers/ata/pata_rz1000.c
index cec0729225e..71a2bac09e0 100644
--- a/drivers/ata/pata_rz1000.c
+++ b/drivers/ata/pata_rz1000.c
@@ -115,7 +115,7 @@ static struct ata_port_operations rz1000_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
@@ -124,10 +124,10 @@ static struct ata_port_operations rz1000_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
static int rz1000_fifo_disable(struct pci_dev *pdev)
diff --git a/drivers/ata/pata_sc1200.c b/drivers/ata/pata_sc1200.c
index a3b35bc5039..58e42fbd14f 100644
--- a/drivers/ata/pata_sc1200.c
+++ b/drivers/ata/pata_sc1200.c
@@ -220,14 +220,14 @@ static struct ata_port_operations sc1200_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = sc1200_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
/**
diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c
index f02b6a3b0f1..ad5b43fef3d 100644
--- a/drivers/ata/pata_serverworks.c
+++ b/drivers/ata/pata_serverworks.c
@@ -218,25 +218,18 @@ static unsigned long serverworks_osb4_filter(const struct ata_port *ap, struct a
static unsigned long serverworks_csb_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long mask)
{
const char *p;
- char model_num[40];
- int len, i;
+ char model_num[ATA_ID_PROD_LEN + 1];
+ int i;
/* Disk, UDMA */
if (adev->class != ATA_DEV_ATA)
return ata_pci_default_filter(ap, adev, mask);
/* Actually do need to check */
- ata_id_string(adev->id, model_num, ATA_ID_PROD_OFS, sizeof(model_num));
- /* Precuationary - why not do this in the libata core ?? */
+ ata_id_c_string(adev->id, model_num, ATA_ID_PROD, sizeof(model_num));
- len = strlen(model_num);
- while ((len > 0) && (model_num[len - 1] == ' ')) {
- len--;
- model_num[len] = 0;
- }
-
- for(i = 0; (p = csb_bad_ata100[i]) != NULL; i++) {
- if (!strncmp(p, model_num, len))
+ for (i = 0; (p = csb_bad_ata100[i]) != NULL; i++) {
+ if (!strcmp(p, model_num))
mask &= ~(0x1F << ATA_SHIFT_UDMA);
}
return ata_pci_default_filter(ap, adev, mask);
@@ -355,14 +348,14 @@ static struct ata_port_operations serverworks_osb4_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
static struct ata_port_operations serverworks_csb_port_ops = {
@@ -390,14 +383,14 @@ static struct ata_port_operations serverworks_csb_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
static int serverworks_fixup_osb4(struct pci_dev *pdev)
@@ -559,7 +552,7 @@ static int serverworks_reinit_one(struct pci_dev *pdev)
{
/* Force master latency timer to 64 PCI clocks */
pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x40);
-
+
switch (pdev->device)
{
case PCI_DEVICE_ID_SERVERWORKS_OSB4IDE:
diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c
index e8dfd8fc3ff..ed79fabe025 100644
--- a/drivers/ata/pata_sil680.c
+++ b/drivers/ata/pata_sil680.c
@@ -252,14 +252,14 @@ static struct ata_port_operations sil680_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
/**
@@ -270,7 +270,7 @@ static struct ata_port_operations sil680_port_ops = {
* is powered up on boot and when we resume in case we resumed from RAM.
* Returns the final clock settings.
*/
-
+
static u8 sil680_init_chip(struct pci_dev *pdev)
{
u32 class_rev = 0;
diff --git a/drivers/ata/pata_sis.c b/drivers/ata/pata_sis.c
index 916cedb3d75..560103d55b2 100644
--- a/drivers/ata/pata_sis.c
+++ b/drivers/ata/pata_sis.c
@@ -32,7 +32,9 @@
#include <scsi/scsi_host.h>
#include <linux/libata.h>
#include <linux/ata.h>
+#include "libata.h"
+#undef DRV_NAME /* already defined in libata.h, for libata-core */
#define DRV_NAME "pata_sis"
#define DRV_VERSION "0.4.5"
@@ -43,6 +45,34 @@ struct sis_chipset {
up code later */
};
+struct sis_laptop {
+ u16 device;
+ u16 subvendor;
+ u16 subdevice;
+};
+
+static const struct sis_laptop sis_laptop[] = {
+ /* devid, subvendor, subdev */
+ { 0x5513, 0x1043, 0x1107 }, /* ASUS A6K */
+ /* end marker */
+ { 0, }
+};
+
+static int sis_short_ata40(struct pci_dev *dev)
+{
+ const struct sis_laptop *lap = &sis_laptop[0];
+
+ while (lap->device) {
+ if (lap->device == dev->device &&
+ lap->subvendor == dev->subsystem_vendor &&
+ lap->subdevice == dev->subsystem_device)
+ return 1;
+ lap++;
+ }
+
+ return 0;
+}
+
/**
* sis_port_base - return PCI configuration base for dev
* @adev: device
@@ -79,7 +109,7 @@ static int sis_133_pre_reset(struct ata_port *ap)
/* The top bit of this register is the cable detect bit */
pci_read_config_word(pdev, 0x50 + 2 * ap->port_no, &tmp);
- if (tmp & 0x8000)
+ if ((tmp & 0x8000) && !sis_short_ata40(pdev))
ap->cbl = ATA_CBL_PATA40;
else
ap->cbl = ATA_CBL_PATA80;
@@ -127,7 +157,7 @@ static int sis_66_pre_reset(struct ata_port *ap)
/* Older chips keep cable detect in bits 4/5 of reg 0x48 */
pci_read_config_byte(pdev, 0x48, &tmp);
tmp >>= ap->port_no;
- if (tmp & 0x10)
+ if ((tmp & 0x10) && !sis_short_ata40(pdev))
ap->cbl = ATA_CBL_PATA40;
else
ap->cbl = ATA_CBL_PATA80;
@@ -573,14 +603,14 @@ static const struct ata_port_operations sis_133_ops = {
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop,
};
static const struct ata_port_operations sis_133_early_ops = {
@@ -606,14 +636,14 @@ static const struct ata_port_operations sis_133_early_ops = {
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop,
};
static const struct ata_port_operations sis_100_ops = {
@@ -640,14 +670,14 @@ static const struct ata_port_operations sis_100_ops = {
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop,
};
static const struct ata_port_operations sis_66_ops = {
@@ -673,14 +703,14 @@ static const struct ata_port_operations sis_66_ops = {
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop,
};
static const struct ata_port_operations sis_old_ops = {
@@ -706,14 +736,14 @@ static const struct ata_port_operations sis_old_ops = {
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop,
};
static struct ata_port_info sis_info = {
@@ -753,7 +783,7 @@ static struct ata_port_info sis_info100_early = {
.pio_mask = 0x1f, /* pio0-4 */
.port_ops = &sis_66_ops,
};
-static struct ata_port_info sis_info133 = {
+struct ata_port_info sis_info133 = {
.sht = &sis_sht,
.flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
.pio_mask = 0x1f, /* pio0-4 */
@@ -768,6 +798,8 @@ static struct ata_port_info sis_info133_early = {
.port_ops = &sis_133_early_ops,
};
+/* Privately shared with the SiS180 SATA driver, not for use elsewhere */
+EXPORT_SYMBOL_GPL(sis_info133);
static void sis_fixup(struct pci_dev *pdev, struct sis_chipset *sis)
{
@@ -847,7 +879,7 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
struct sis_chipset *chipset = NULL;
static struct sis_chipset sis_chipsets[] = {
-
+
{ 0x0968, &sis_info133 },
{ 0x0966, &sis_info133 },
{ 0x0965, &sis_info133 },
diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c
index e94f515ef54..96e890fd645 100644
--- a/drivers/ata/pata_sl82c105.c
+++ b/drivers/ata/pata_sl82c105.c
@@ -139,13 +139,13 @@ static void sl82c105_set_dmamode(struct ata_port *ap, struct ata_device *adev)
{
switch(adev->dma_mode) {
case XFER_MW_DMA_0:
- sl82c105_configure_piomode(ap, adev, 1);
+ sl82c105_configure_piomode(ap, adev, 0);
break;
case XFER_MW_DMA_1:
sl82c105_configure_piomode(ap, adev, 3);
break;
case XFER_MW_DMA_2:
- sl82c105_configure_piomode(ap, adev, 3);
+ sl82c105_configure_piomode(ap, adev, 4);
break;
default:
BUG();
@@ -187,7 +187,9 @@ static void sl82c105_bmdma_start(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
+ udelay(100);
sl82c105_reset_engine(ap);
+ udelay(100);
/* Set the clocks for DMA */
sl82c105_configure_dmamode(ap, qc->dev);
@@ -216,6 +218,7 @@ static void sl82c105_bmdma_stop(struct ata_queued_cmd *qc)
ata_bmdma_stop(qc);
sl82c105_reset_engine(ap);
+ udelay(100);
/* This will redo the initial setup of the DMA device to matching
PIO timings */
@@ -262,14 +265,14 @@ static struct ata_port_operations sl82c105_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
/**
diff --git a/drivers/ata/pata_triflex.c b/drivers/ata/pata_triflex.c
index a142971f130..453ab90b721 100644
--- a/drivers/ata/pata_triflex.c
+++ b/drivers/ata/pata_triflex.c
@@ -221,14 +221,14 @@ static struct ata_port_operations triflex_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
static int triflex_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c
index f0b6c3b7142..220fcd6c549 100644
--- a/drivers/ata/pata_via.c
+++ b/drivers/ata/pata_via.c
@@ -334,14 +334,14 @@ static struct ata_port_operations via_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
static struct ata_port_operations via_port_ops_noirq = {
@@ -369,14 +369,14 @@ static struct ata_port_operations via_port_ops_noirq = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer_noirq,
+ .data_xfer = ata_data_xfer_noirq,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
/**
@@ -391,11 +391,11 @@ static struct ata_port_operations via_port_ops_noirq = {
static void via_config_fifo(struct pci_dev *pdev, unsigned int flags)
{
u8 enable;
-
+
/* 0x40 low bits indicate enabled channels */
pci_read_config_byte(pdev, 0x40 , &enable);
enable &= 3;
-
+
if (flags & VIA_SET_FIFO) {
static const u8 fifo_setting[4] = {0x00, 0x60, 0x00, 0x20};
u8 fifo;
@@ -516,7 +516,7 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
/* Initialise the FIFO for the enabled channels. */
via_config_fifo(pdev, config->flags);
-
+
/* Clock set up */
switch(config->flags & VIA_UDMA) {
case VIA_UDMA_NONE:
@@ -575,7 +575,7 @@ static int via_reinit_one(struct pci_dev *pdev)
u32 timing;
struct ata_host *host = dev_get_drvdata(&pdev->dev);
const struct via_isa_bridge *config = host->private_data;
-
+
via_config_fifo(pdev, config->flags);
if ((config->flags & VIA_UDMA) == VIA_UDMA_66) {
@@ -590,7 +590,7 @@ static int via_reinit_one(struct pci_dev *pdev)
timing &= ~0x80008;
pci_write_config_dword(pdev, 0x50, timing);
}
- return ata_pci_device_resume(pdev);
+ return ata_pci_device_resume(pdev);
}
static const struct pci_device_id via[] = {
diff --git a/drivers/ata/pata_winbond.c b/drivers/ata/pata_winbond.c
index 5d1f518e1cc..0888b4f19f4 100644
--- a/drivers/ata/pata_winbond.c
+++ b/drivers/ata/pata_winbond.c
@@ -5,7 +5,7 @@
* Support for the Winbond 83759A when operating in advanced mode.
* Multichip mode is not currently supported.
*/
-
+
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
@@ -69,7 +69,7 @@ static void winbond_set_piomode(struct ata_port *ap, struct ata_device *adev)
int timing = 0x88 + (ap->port_no * 4) + (adev->devno * 2);
reg = winbond_readcfg(winbond->config, 0x81);
-
+
/* Get the timing data in cycles */
if (reg & 0x40) /* Fast VLB bus, assume 50MHz */
ata_timing_compute(adev, adev->pio_mode, &t, 20000, 1000);
@@ -80,9 +80,9 @@ static void winbond_set_piomode(struct ata_port *ap, struct ata_device *adev)
recovery = (FIT(t.recover, 1, 15) + 1) & 0x0F;
timing = (active << 4) | recovery;
winbond_writecfg(winbond->config, timing, reg);
-
+
/* Load the setup timing */
-
+
reg = 0x35;
if (adev->class != ATA_DEV_ATA)
reg |= 0x08; /* FIFO off */
@@ -100,22 +100,24 @@ static void winbond_data_xfer(struct ata_device *adev, unsigned char *buf, unsig
if (ata_id_has_dword_io(adev->id)) {
if (write_data)
- outsl(ap->ioaddr.data_addr, buf, buflen >> 2);
+ iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
else
- insl(ap->ioaddr.data_addr, buf, buflen >> 2);
+ ioread32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
if (unlikely(slop)) {
u32 pad;
if (write_data) {
memcpy(&pad, buf + buflen - slop, slop);
- outl(le32_to_cpu(pad), ap->ioaddr.data_addr);
+ pad = le32_to_cpu(pad);
+ iowrite32(pad, ap->ioaddr.data_addr);
} else {
- pad = cpu_to_le16(inl(ap->ioaddr.data_addr));
+ pad = ioread32(ap->ioaddr.data_addr);
+ pad = cpu_to_le16(pad);
memcpy(buf + buflen - slop, &pad, slop);
}
}
} else
- ata_pio_data_xfer(adev, buf, buflen, write_data);
+ ata_data_xfer(adev, buf, buflen, write_data);
}
static struct scsi_host_template winbond_sht = {
@@ -158,10 +160,10 @@ static struct ata_port_operations winbond_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop
};
/**
@@ -194,13 +196,15 @@ static __init int winbond_init_one(unsigned long port)
winbond_writecfg(port, 0x85, reg);
reg = winbond_readcfg(port, 0x81);
-
+
if (!(reg & 0x03)) /* Disabled */
return 0;
for (i = 0; i < 2 ; i ++) {
+ unsigned long cmd_port = 0x1F0 - (0x80 * i);
+ void __iomem *cmd_addr, *ctl_addr;
- if (reg & (1 << i)) {
+ if (reg & (1 << i)) {
/*
* Fill in a probe structure first of all
*/
@@ -209,6 +213,13 @@ static __init int winbond_init_one(unsigned long port)
if (IS_ERR(pdev))
return PTR_ERR(pdev);
+ cmd_addr = devm_ioport_map(&pdev->dev, cmd_port, 8);
+ ctl_addr = devm_ioport_map(&pdev->dev, cmd_port + 0x0206, 1);
+ if (!cmd_addr || !ctl_addr) {
+ platform_device_unregister(pdev);
+ return -ENOMEM;
+ }
+
memset(&ae, 0, sizeof(struct ata_probe_ent));
INIT_LIST_HEAD(&ae.node);
ae.dev = &pdev->dev;
@@ -217,14 +228,14 @@ static __init int winbond_init_one(unsigned long port)
ae.pio_mask = 0x1F;
ae.sht = &winbond_sht;
-
+
ae.n_ports = 1;
ae.irq = 14 + i;
ae.irq_flags = 0;
ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST;
- ae.port[0].cmd_addr = 0x1F0 - (0x80 * i);
- ae.port[0].altstatus_addr = ae.port[0].cmd_addr + 0x0206;
- ae.port[0].ctl_addr = ae.port[0].altstatus_addr;
+ ae.port[0].cmd_addr = cmd_addr;
+ ae.port[0].altstatus_addr = ctl_addr;
+ ae.port[0].ctl_addr = ctl_addr;
ata_std_ports(&ae.port[0]);
/*
* Hook in a private data structure per channel
@@ -257,7 +268,7 @@ static __init int winbond_init(void)
int ct = 0;
int i;
-
+
if (probe_winbond == 0)
return -ENODEV;
@@ -288,7 +299,7 @@ static __exit void winbond_exit(void)
int i;
for (i = 0; i < nr_winbond_host; i++) {
- ata_host_remove(winbond_host[i]);
+ ata_host_detach(winbond_host[i]);
release_region(winbond_data[i].config, 2);
platform_device_unregister(winbond_data[i].platform_dev);
}
diff --git a/drivers/ata/pdc_adma.c b/drivers/ata/pdc_adma.c
index 90786d7a20b..857ac23217a 100644
--- a/drivers/ata/pdc_adma.c
+++ b/drivers/ata/pdc_adma.c
@@ -39,10 +39,8 @@
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
-#include <linux/sched.h>
#include <linux/device.h>
#include <scsi/scsi_host.h>
-#include <asm/io.h>
#include <linux/libata.h>
#define DRV_NAME "pdc_adma"
@@ -52,9 +50,15 @@
#define ADMA_ATA_REGS(base,port_no) ((base) + ((port_no) * 0x40))
/* macro to calculate base address for ADMA regs */
-#define ADMA_REGS(base,port_no) ((base) + 0x80 + ((port_no) * 0x20))
+#define ADMA_REGS(base,port_no) ((base) + 0x80 + ((port_no) * 0x20))
+
+/* macro to obtain addresses from ata_host */
+#define ADMA_HOST_REGS(host,port_no) \
+ ADMA_REGS((host)->iomap[ADMA_MMIO_BAR], port_no)
enum {
+ ADMA_MMIO_BAR = 4,
+
ADMA_PORTS = 2,
ADMA_CPB_BYTES = 40,
ADMA_PRD_BYTES = LIBATA_MAX_PRD * 16,
@@ -167,9 +171,11 @@ static const struct ata_port_operations adma_ata_ops = {
.qc_prep = adma_qc_prep,
.qc_issue = adma_qc_issue,
.eng_timeout = adma_eng_timeout,
- .data_xfer = ata_mmio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = adma_intr,
.irq_clear = adma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = adma_port_start,
.port_stop = adma_port_stop,
.host_stop = adma_host_stop,
@@ -235,11 +241,10 @@ static void adma_reset_engine(void __iomem *chan)
static void adma_reinit_engine(struct ata_port *ap)
{
struct adma_port_priv *pp = ap->private_data;
- void __iomem *mmio_base = ap->host->mmio_base;
- void __iomem *chan = ADMA_REGS(mmio_base, ap->port_no);
+ void __iomem *chan = ADMA_HOST_REGS(ap->host, ap->port_no);
/* mask/clear ATA interrupts */
- writeb(ATA_NIEN, (void __iomem *)ap->ioaddr.ctl_addr);
+ writeb(ATA_NIEN, ap->ioaddr.ctl_addr);
ata_check_status(ap);
/* reset the ADMA engine */
@@ -263,7 +268,7 @@ static void adma_reinit_engine(struct ata_port *ap)
static inline void adma_enter_reg_mode(struct ata_port *ap)
{
- void __iomem *chan = ADMA_REGS(ap->host->mmio_base, ap->port_no);
+ void __iomem *chan = ADMA_HOST_REGS(ap->host, ap->port_no);
writew(aPIOMD4, chan + ADMA_CONTROL);
readb(chan + ADMA_STATUS); /* flush */
@@ -410,7 +415,7 @@ static void adma_qc_prep(struct ata_queued_cmd *qc)
static inline void adma_packet_start(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
- void __iomem *chan = ADMA_REGS(ap->host->mmio_base, ap->port_no);
+ void __iomem *chan = ADMA_HOST_REGS(ap->host, ap->port_no);
VPRINTK("ENTER, ap %p\n", ap);
@@ -443,13 +448,12 @@ static unsigned int adma_qc_issue(struct ata_queued_cmd *qc)
static inline unsigned int adma_intr_pkt(struct ata_host *host)
{
unsigned int handled = 0, port_no;
- u8 __iomem *mmio_base = host->mmio_base;
for (port_no = 0; port_no < host->n_ports; ++port_no) {
struct ata_port *ap = host->ports[port_no];
struct adma_port_priv *pp;
struct ata_queued_cmd *qc;
- void __iomem *chan = ADMA_REGS(mmio_base, port_no);
+ void __iomem *chan = ADMA_HOST_REGS(host, port_no);
u8 status = readb(chan + ADMA_STATUS);
if (status == 0)
@@ -523,7 +527,7 @@ static irqreturn_t adma_intr(int irq, void *dev_instance)
return IRQ_RETVAL(handled);
}
-static void adma_ata_setup_port(struct ata_ioports *port, unsigned long base)
+static void adma_ata_setup_port(struct ata_ioports *port, void __iomem *base)
{
port->cmd_addr =
port->data_addr = base + 0x000;
@@ -550,48 +554,28 @@ static int adma_port_start(struct ata_port *ap)
if (rc)
return rc;
adma_enter_reg_mode(ap);
- rc = -ENOMEM;
- pp = kzalloc(sizeof(*pp), GFP_KERNEL);
+ pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
if (!pp)
- goto err_out;
- pp->pkt = dma_alloc_coherent(dev, ADMA_PKT_BYTES, &pp->pkt_dma,
- GFP_KERNEL);
+ return -ENOMEM;
+ pp->pkt = dmam_alloc_coherent(dev, ADMA_PKT_BYTES, &pp->pkt_dma,
+ GFP_KERNEL);
if (!pp->pkt)
- goto err_out_kfree;
+ return -ENOMEM;
/* paranoia? */
if ((pp->pkt_dma & 7) != 0) {
printk("bad alignment for pp->pkt_dma: %08x\n",
(u32)pp->pkt_dma);
- dma_free_coherent(dev, ADMA_PKT_BYTES,
- pp->pkt, pp->pkt_dma);
- goto err_out_kfree;
+ return -ENOMEM;
}
memset(pp->pkt, 0, ADMA_PKT_BYTES);
ap->private_data = pp;
adma_reinit_engine(ap);
return 0;
-
-err_out_kfree:
- kfree(pp);
-err_out:
- ata_port_stop(ap);
- return rc;
}
static void adma_port_stop(struct ata_port *ap)
{
- struct device *dev = ap->host->dev;
- struct adma_port_priv *pp = ap->private_data;
-
- adma_reset_engine(ADMA_REGS(ap->host->mmio_base, ap->port_no));
- if (pp != NULL) {
- ap->private_data = NULL;
- if (pp->pkt != NULL)
- dma_free_coherent(dev, ADMA_PKT_BYTES,
- pp->pkt, pp->pkt_dma);
- kfree(pp);
- }
- ata_port_stop(ap);
+ adma_reset_engine(ADMA_HOST_REGS(ap->host, ap->port_no));
}
static void adma_host_stop(struct ata_host *host)
@@ -599,16 +583,14 @@ static void adma_host_stop(struct ata_host *host)
unsigned int port_no;
for (port_no = 0; port_no < ADMA_PORTS; ++port_no)
- adma_reset_engine(ADMA_REGS(host->mmio_base, port_no));
-
- ata_pci_host_stop(host);
+ adma_reset_engine(ADMA_HOST_REGS(host, port_no));
}
static void adma_host_init(unsigned int chip_id,
struct ata_probe_ent *probe_ent)
{
unsigned int port_no;
- void __iomem *mmio_base = probe_ent->mmio_base;
+ void __iomem *mmio_base = probe_ent->iomap[ADMA_MMIO_BAR];
/* enable/lock aGO operation */
writeb(7, mmio_base + ADMA_MODE_LOCK);
@@ -638,7 +620,7 @@ static int adma_set_dma_masks(struct pci_dev *pdev, void __iomem *mmio_base)
}
static int adma_ata_init_one(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *ent)
{
static int printed_version;
struct ata_probe_ent *probe_ent = NULL;
@@ -649,34 +631,25 @@ static int adma_ata_init_one(struct pci_dev *pdev,
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
- rc = pci_enable_device(pdev);
+ rc = pcim_enable_device(pdev);
if (rc)
return rc;
- rc = pci_request_regions(pdev, DRV_NAME);
- if (rc)
- goto err_out;
-
- if ((pci_resource_flags(pdev, 4) & IORESOURCE_MEM) == 0) {
- rc = -ENODEV;
- goto err_out_regions;
- }
+ if ((pci_resource_flags(pdev, 4) & IORESOURCE_MEM) == 0)
+ return -ENODEV;
- mmio_base = pci_iomap(pdev, 4, 0);
- if (mmio_base == NULL) {
- rc = -ENOMEM;
- goto err_out_regions;
- }
+ rc = pcim_iomap_regions(pdev, 1 << ADMA_MMIO_BAR, DRV_NAME);
+ if (rc)
+ return rc;
+ mmio_base = pcim_iomap_table(pdev)[ADMA_MMIO_BAR];
rc = adma_set_dma_masks(pdev, mmio_base);
if (rc)
- goto err_out_iounmap;
+ return rc;
- probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL);
- if (probe_ent == NULL) {
- rc = -ENOMEM;
- goto err_out_iounmap;
- }
+ probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL);
+ if (probe_ent == NULL)
+ return -ENOMEM;
probe_ent->dev = pci_dev_to_dev(pdev);
INIT_LIST_HEAD(&probe_ent->node);
@@ -690,12 +663,12 @@ static int adma_ata_init_one(struct pci_dev *pdev,
probe_ent->irq = pdev->irq;
probe_ent->irq_flags = IRQF_SHARED;
- probe_ent->mmio_base = mmio_base;
probe_ent->n_ports = ADMA_PORTS;
+ probe_ent->iomap = pcim_iomap_table(pdev);
for (port_no = 0; port_no < probe_ent->n_ports; ++port_no) {
adma_ata_setup_port(&probe_ent->port[port_no],
- ADMA_ATA_REGS((unsigned long)mmio_base, port_no));
+ ADMA_ATA_REGS(mmio_base, port_no));
}
pci_set_master(pdev);
@@ -703,19 +676,11 @@ static int adma_ata_init_one(struct pci_dev *pdev,
/* initialize adapter */
adma_host_init(board_idx, probe_ent);
- rc = ata_device_add(probe_ent);
- kfree(probe_ent);
- if (rc != ADMA_PORTS)
- goto err_out_iounmap;
- return 0;
+ if (!ata_device_add(probe_ent))
+ return -ENODEV;
-err_out_iounmap:
- pci_iounmap(pdev, mmio_base);
-err_out_regions:
- pci_release_regions(pdev);
-err_out:
- pci_disable_device(pdev);
- return rc;
+ devm_kfree(&pdev->dev, probe_ent);
+ return 0;
}
static int __init adma_ata_init(void)
diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c
new file mode 100644
index 00000000000..31b636fac98
--- /dev/null
+++ b/drivers/ata/sata_inic162x.c
@@ -0,0 +1,781 @@
+/*
+ * sata_inic162x.c - Driver for Initio 162x SATA controllers
+ *
+ * Copyright 2006 SUSE Linux Products GmbH
+ * Copyright 2006 Tejun Heo <teheo@novell.com>
+ *
+ * This file is released under GPL v2.
+ *
+ * This controller is eccentric and easily locks up if something isn't
+ * right. Documentation is available at initio's website but it only
+ * documents registers (not programming model).
+ *
+ * - ATA disks work.
+ * - Hotplug works.
+ * - ATAPI read works but burning doesn't. This thing is really
+ * peculiar about ATAPI and I couldn't figure out how ATAPI PIO and
+ * ATAPI DMA WRITE should be programmed. If you've got a clue, be
+ * my guest.
+ * - Both STR and STD work.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+#include <linux/blkdev.h>
+#include <scsi/scsi_device.h>
+
+#define DRV_NAME "sata_inic162x"
+#define DRV_VERSION "0.1"
+
+enum {
+ MMIO_BAR = 5,
+
+ NR_PORTS = 2,
+
+ HOST_CTL = 0x7c,
+ HOST_STAT = 0x7e,
+ HOST_IRQ_STAT = 0xbc,
+ HOST_IRQ_MASK = 0xbe,
+
+ PORT_SIZE = 0x40,
+
+ /* registers for ATA TF operation */
+ PORT_TF = 0x00,
+ PORT_ALT_STAT = 0x08,
+ PORT_IRQ_STAT = 0x09,
+ PORT_IRQ_MASK = 0x0a,
+ PORT_PRD_CTL = 0x0b,
+ PORT_PRD_ADDR = 0x0c,
+ PORT_PRD_XFERLEN = 0x10,
+
+ /* IDMA register */
+ PORT_IDMA_CTL = 0x14,
+
+ PORT_SCR = 0x20,
+
+ /* HOST_CTL bits */
+ HCTL_IRQOFF = (1 << 8), /* global IRQ off */
+ HCTL_PWRDWN = (1 << 13), /* power down PHYs */
+ HCTL_SOFTRST = (1 << 13), /* global reset (no phy reset) */
+ HCTL_RPGSEL = (1 << 15), /* register page select */
+
+ HCTL_KNOWN_BITS = HCTL_IRQOFF | HCTL_PWRDWN | HCTL_SOFTRST |
+ HCTL_RPGSEL,
+
+ /* HOST_IRQ_(STAT|MASK) bits */
+ HIRQ_PORT0 = (1 << 0),
+ HIRQ_PORT1 = (1 << 1),
+ HIRQ_SOFT = (1 << 14),
+ HIRQ_GLOBAL = (1 << 15), /* STAT only */
+
+ /* PORT_IRQ_(STAT|MASK) bits */
+ PIRQ_OFFLINE = (1 << 0), /* device unplugged */
+ PIRQ_ONLINE = (1 << 1), /* device plugged */
+ PIRQ_COMPLETE = (1 << 2), /* completion interrupt */
+ PIRQ_FATAL = (1 << 3), /* fatal error */
+ PIRQ_ATA = (1 << 4), /* ATA interrupt */
+ PIRQ_REPLY = (1 << 5), /* reply FIFO not empty */
+ PIRQ_PENDING = (1 << 7), /* port IRQ pending (STAT only) */
+
+ PIRQ_ERR = PIRQ_OFFLINE | PIRQ_ONLINE | PIRQ_FATAL,
+
+ PIRQ_MASK_DMA_READ = PIRQ_REPLY | PIRQ_ATA,
+ PIRQ_MASK_OTHER = PIRQ_REPLY | PIRQ_COMPLETE,
+ PIRQ_MASK_FREEZE = 0xff,
+
+ /* PORT_PRD_CTL bits */
+ PRD_CTL_START = (1 << 0),
+ PRD_CTL_WR = (1 << 3),
+ PRD_CTL_DMAEN = (1 << 7), /* DMA enable */
+
+ /* PORT_IDMA_CTL bits */
+ IDMA_CTL_RST_ATA = (1 << 2), /* hardreset ATA bus */
+ IDMA_CTL_RST_IDMA = (1 << 5), /* reset IDMA machinary */
+ IDMA_CTL_GO = (1 << 7), /* IDMA mode go */
+ IDMA_CTL_ATA_NIEN = (1 << 8), /* ATA IRQ disable */
+};
+
+struct inic_host_priv {
+ u16 cached_hctl;
+};
+
+struct inic_port_priv {
+ u8 dfl_prdctl;
+ u8 cached_prdctl;
+ u8 cached_pirq_mask;
+};
+
+static int inic_slave_config(struct scsi_device *sdev)
+{
+ /* This controller is braindamaged. dma_boundary is 0xffff
+ * like others but it will lock up the whole machine HARD if
+ * 65536 byte PRD entry is fed. Reduce maximum segment size.
+ */
+ blk_queue_max_segment_size(sdev->request_queue, 65536 - 512);
+
+ return ata_scsi_slave_config(sdev);
+}
+
+static struct scsi_host_template inic_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = inic_slave_config,
+ .slave_destroy = ata_scsi_slave_destroy,
+ .bios_param = ata_std_bios_param,
+ .suspend = ata_scsi_device_suspend,
+ .resume = ata_scsi_device_resume,
+};
+
+static const int scr_map[] = {
+ [SCR_STATUS] = 0,
+ [SCR_ERROR] = 1,
+ [SCR_CONTROL] = 2,
+};
+
+static void __iomem * inic_port_base(struct ata_port *ap)
+{
+ return ap->host->iomap[MMIO_BAR] + ap->port_no * PORT_SIZE;
+}
+
+static void __inic_set_pirq_mask(struct ata_port *ap, u8 mask)
+{
+ void __iomem *port_base = inic_port_base(ap);
+ struct inic_port_priv *pp = ap->private_data;
+
+ writeb(mask, port_base + PORT_IRQ_MASK);
+ pp->cached_pirq_mask = mask;
+}
+
+static void inic_set_pirq_mask(struct ata_port *ap, u8 mask)
+{
+ struct inic_port_priv *pp = ap->private_data;
+
+ if (pp->cached_pirq_mask != mask)
+ __inic_set_pirq_mask(ap, mask);
+}
+
+static void inic_reset_port(void __iomem *port_base)
+{
+ void __iomem *idma_ctl = port_base + PORT_IDMA_CTL;
+ u16 ctl;
+
+ ctl = readw(idma_ctl);
+ ctl &= ~(IDMA_CTL_RST_IDMA | IDMA_CTL_ATA_NIEN | IDMA_CTL_GO);
+
+ /* mask IRQ and assert reset */
+ writew(ctl | IDMA_CTL_RST_IDMA | IDMA_CTL_ATA_NIEN, idma_ctl);
+ readw(idma_ctl); /* flush */
+
+ /* give it some time */
+ msleep(1);
+
+ /* release reset */
+ writew(ctl | IDMA_CTL_ATA_NIEN, idma_ctl);
+
+ /* clear irq */
+ writeb(0xff, port_base + PORT_IRQ_STAT);
+
+ /* reenable ATA IRQ, turn off IDMA mode */
+ writew(ctl, idma_ctl);
+}
+
+static u32 inic_scr_read(struct ata_port *ap, unsigned sc_reg)
+{
+ void __iomem *scr_addr = (void __iomem *)ap->ioaddr.scr_addr;
+ void __iomem *addr;
+ u32 val;
+
+ if (unlikely(sc_reg >= ARRAY_SIZE(scr_map)))
+ return 0xffffffffU;
+
+ addr = scr_addr + scr_map[sc_reg] * 4;
+ val = readl(scr_addr + scr_map[sc_reg] * 4);
+
+ /* this controller has stuck DIAG.N, ignore it */
+ if (sc_reg == SCR_ERROR)
+ val &= ~SERR_PHYRDY_CHG;
+ return val;
+}
+
+static void inic_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val)
+{
+ void __iomem *scr_addr = (void __iomem *)ap->ioaddr.scr_addr;
+ void __iomem *addr;
+
+ if (unlikely(sc_reg >= ARRAY_SIZE(scr_map)))
+ return;
+
+ addr = scr_addr + scr_map[sc_reg] * 4;
+ writel(val, scr_addr + scr_map[sc_reg] * 4);
+}
+
+/*
+ * In TF mode, inic162x is very similar to SFF device. TF registers
+ * function the same. DMA engine behaves similary using the same PRD
+ * format as BMDMA but different command register, interrupt and event
+ * notification methods are used. The following inic_bmdma_*()
+ * functions do the impedance matching.
+ */
+static void inic_bmdma_setup(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct inic_port_priv *pp = ap->private_data;
+ void __iomem *port_base = inic_port_base(ap);
+ int rw = qc->tf.flags & ATA_TFLAG_WRITE;
+
+ /* make sure device sees PRD table writes */
+ wmb();
+
+ /* load transfer length */
+ writel(qc->nbytes, port_base + PORT_PRD_XFERLEN);
+
+ /* turn on DMA and specify data direction */
+ pp->cached_prdctl = pp->dfl_prdctl | PRD_CTL_DMAEN;
+ if (!rw)
+ pp->cached_prdctl |= PRD_CTL_WR;
+ writeb(pp->cached_prdctl, port_base + PORT_PRD_CTL);
+
+ /* issue r/w command */
+ ap->ops->exec_command(ap, &qc->tf);
+}
+
+static void inic_bmdma_start(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct inic_port_priv *pp = ap->private_data;
+ void __iomem *port_base = inic_port_base(ap);
+
+ /* start host DMA transaction */
+ pp->cached_prdctl |= PRD_CTL_START;
+ writeb(pp->cached_prdctl, port_base + PORT_PRD_CTL);
+}
+
+static void inic_bmdma_stop(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct inic_port_priv *pp = ap->private_data;
+ void __iomem *port_base = inic_port_base(ap);
+
+ /* stop DMA engine */
+ writeb(pp->dfl_prdctl, port_base + PORT_PRD_CTL);
+}
+
+static u8 inic_bmdma_status(struct ata_port *ap)
+{
+ /* event is already verified by the interrupt handler */
+ return ATA_DMA_INTR;
+}
+
+static void inic_irq_clear(struct ata_port *ap)
+{
+ /* noop */
+}
+
+static void inic_host_intr(struct ata_port *ap)
+{
+ void __iomem *port_base = inic_port_base(ap);
+ struct ata_eh_info *ehi = &ap->eh_info;
+ u8 irq_stat;
+
+ /* fetch and clear irq */
+ irq_stat = readb(port_base + PORT_IRQ_STAT);
+ writeb(irq_stat, port_base + PORT_IRQ_STAT);
+
+ if (likely(!(irq_stat & PIRQ_ERR))) {
+ struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag);
+
+ if (unlikely(!qc || (qc->tf.flags & ATA_TFLAG_POLLING))) {
+ ata_chk_status(ap); /* clear ATA interrupt */
+ return;
+ }
+
+ if (likely(ata_host_intr(ap, qc)))
+ return;
+
+ ata_chk_status(ap); /* clear ATA interrupt */
+ ata_port_printk(ap, KERN_WARNING, "unhandled "
+ "interrupt, irq_stat=%x\n", irq_stat);
+ return;
+ }
+
+ /* error */
+ ata_ehi_push_desc(ehi, "irq_stat=0x%x", irq_stat);
+
+ if (irq_stat & (PIRQ_OFFLINE | PIRQ_ONLINE)) {
+ ata_ehi_hotplugged(ehi);
+ ata_port_freeze(ap);
+ } else
+ ata_port_abort(ap);
+}
+
+static irqreturn_t inic_interrupt(int irq, void *dev_instance)
+{
+ struct ata_host *host = dev_instance;
+ void __iomem *mmio_base = host->iomap[MMIO_BAR];
+ u16 host_irq_stat;
+ int i, handled = 0;;
+
+ host_irq_stat = readw(mmio_base + HOST_IRQ_STAT);
+
+ if (unlikely(!(host_irq_stat & HIRQ_GLOBAL)))
+ goto out;
+
+ spin_lock(&host->lock);
+
+ for (i = 0; i < NR_PORTS; i++) {
+ struct ata_port *ap = host->ports[i];
+
+ if (!(host_irq_stat & (HIRQ_PORT0 << i)))
+ continue;
+
+ if (likely(ap && !(ap->flags & ATA_FLAG_DISABLED))) {
+ inic_host_intr(ap);
+ handled++;
+ } else {
+ if (ata_ratelimit())
+ dev_printk(KERN_ERR, host->dev, "interrupt "
+ "from disabled port %d (0x%x)\n",
+ i, host_irq_stat);
+ }
+ }
+
+ spin_unlock(&host->lock);
+
+ out:
+ return IRQ_RETVAL(handled);
+}
+
+static unsigned int inic_qc_issue(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+
+ /* ATA IRQ doesn't wait for DMA transfer completion and vice
+ * versa. Mask IRQ selectively to detect command completion.
+ * Without it, ATA DMA read command can cause data corruption.
+ *
+ * Something similar might be needed for ATAPI writes. I
+ * tried a lot of combinations but couldn't find the solution.
+ */
+ if (qc->tf.protocol == ATA_PROT_DMA &&
+ !(qc->tf.flags & ATA_TFLAG_WRITE))
+ inic_set_pirq_mask(ap, PIRQ_MASK_DMA_READ);
+ else
+ inic_set_pirq_mask(ap, PIRQ_MASK_OTHER);
+
+ /* Issuing a command to yet uninitialized port locks up the
+ * controller. Most of the time, this happens for the first
+ * command after reset which are ATA and ATAPI IDENTIFYs.
+ * Fast fail if stat is 0x7f or 0xff for those commands.
+ */
+ if (unlikely(qc->tf.command == ATA_CMD_ID_ATA ||
+ qc->tf.command == ATA_CMD_ID_ATAPI)) {
+ u8 stat = ata_chk_status(ap);
+ if (stat == 0x7f || stat == 0xff)
+ return AC_ERR_HSM;
+ }
+
+ return ata_qc_issue_prot(qc);
+}
+
+static void inic_freeze(struct ata_port *ap)
+{
+ void __iomem *port_base = inic_port_base(ap);
+
+ __inic_set_pirq_mask(ap, PIRQ_MASK_FREEZE);
+
+ ata_chk_status(ap);
+ writeb(0xff, port_base + PORT_IRQ_STAT);
+
+ readb(port_base + PORT_IRQ_STAT); /* flush */
+}
+
+static void inic_thaw(struct ata_port *ap)
+{
+ void __iomem *port_base = inic_port_base(ap);
+
+ ata_chk_status(ap);
+ writeb(0xff, port_base + PORT_IRQ_STAT);
+
+ __inic_set_pirq_mask(ap, PIRQ_MASK_OTHER);
+
+ readb(port_base + PORT_IRQ_STAT); /* flush */
+}
+
+/*
+ * SRST and SControl hardreset don't give valid signature on this
+ * controller. Only controller specific hardreset mechanism works.
+ */
+static int inic_hardreset(struct ata_port *ap, unsigned int *class)
+{
+ void __iomem *port_base = inic_port_base(ap);
+ void __iomem *idma_ctl = port_base + PORT_IDMA_CTL;
+ const unsigned long *timing = sata_ehc_deb_timing(&ap->eh_context);
+ u16 val;
+ int rc;
+
+ /* hammer it into sane state */
+ inic_reset_port(port_base);
+
+ val = readw(idma_ctl);
+ writew(val | IDMA_CTL_RST_ATA, idma_ctl);
+ readw(idma_ctl); /* flush */
+ msleep(1);
+ writew(val & ~IDMA_CTL_RST_ATA, idma_ctl);
+
+ rc = sata_phy_resume(ap, timing);
+ if (rc) {
+ ata_port_printk(ap, KERN_WARNING, "failed to resume "
+ "link after reset (errno=%d)\n", rc);
+ return rc;
+ }
+
+ *class = ATA_DEV_NONE;
+ if (ata_port_online(ap)) {
+ struct ata_taskfile tf;
+
+ /* wait a while before checking status */
+ msleep(150);
+
+ if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) {
+ ata_port_printk(ap, KERN_WARNING,
+ "device busy after hardreset\n");
+ return -EIO;
+ }
+
+ ata_tf_read(ap, &tf);
+ *class = ata_dev_classify(&tf);
+ if (*class == ATA_DEV_UNKNOWN)
+ *class = ATA_DEV_NONE;
+ }
+
+ return 0;
+}
+
+static void inic_error_handler(struct ata_port *ap)
+{
+ void __iomem *port_base = inic_port_base(ap);
+ struct inic_port_priv *pp = ap->private_data;
+ unsigned long flags;
+
+ /* reset PIO HSM and stop DMA engine */
+ inic_reset_port(port_base);
+
+ spin_lock_irqsave(ap->lock, flags);
+ ap->hsm_task_state = HSM_ST_IDLE;
+ writeb(pp->dfl_prdctl, port_base + PORT_PRD_CTL);
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ /* PIO and DMA engines have been stopped, perform recovery */
+ ata_do_eh(ap, ata_std_prereset, NULL, inic_hardreset,
+ ata_std_postreset);
+}
+
+static void inic_post_internal_cmd(struct ata_queued_cmd *qc)
+{
+ /* make DMA engine forget about the failed command */
+ if (qc->err_mask)
+ inic_reset_port(inic_port_base(qc->ap));
+}
+
+static void inic_dev_config(struct ata_port *ap, struct ata_device *dev)
+{
+ /* inic can only handle upto LBA28 max sectors */
+ if (dev->max_sectors > ATA_MAX_SECTORS)
+ dev->max_sectors = ATA_MAX_SECTORS;
+}
+
+static void init_port(struct ata_port *ap)
+{
+ void __iomem *port_base = inic_port_base(ap);
+
+ /* Setup PRD address */
+ writel(ap->prd_dma, port_base + PORT_PRD_ADDR);
+}
+
+static int inic_port_resume(struct ata_port *ap)
+{
+ init_port(ap);
+ return 0;
+}
+
+static int inic_port_start(struct ata_port *ap)
+{
+ void __iomem *port_base = inic_port_base(ap);
+ struct inic_port_priv *pp;
+ u8 tmp;
+ int rc;
+
+ /* alloc and initialize private data */
+ pp = devm_kzalloc(ap->host->dev, sizeof(*pp), GFP_KERNEL);
+ if (!pp)
+ return -ENOMEM;
+ ap->private_data = pp;
+
+ /* default PRD_CTL value, DMAEN, WR and START off */
+ tmp = readb(port_base + PORT_PRD_CTL);
+ tmp &= ~(PRD_CTL_DMAEN | PRD_CTL_WR | PRD_CTL_START);
+ pp->dfl_prdctl = tmp;
+
+ /* Alloc resources */
+ rc = ata_port_start(ap);
+ if (rc) {
+ kfree(pp);
+ return rc;
+ }
+
+ init_port(ap);
+
+ return 0;
+}
+
+static struct ata_port_operations inic_port_ops = {
+ .port_disable = ata_port_disable,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .scr_read = inic_scr_read,
+ .scr_write = inic_scr_write,
+
+ .bmdma_setup = inic_bmdma_setup,
+ .bmdma_start = inic_bmdma_start,
+ .bmdma_stop = inic_bmdma_stop,
+ .bmdma_status = inic_bmdma_status,
+
+ .irq_handler = inic_interrupt,
+ .irq_clear = inic_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = inic_qc_issue,
+ .data_xfer = ata_data_xfer,
+
+ .freeze = inic_freeze,
+ .thaw = inic_thaw,
+ .error_handler = inic_error_handler,
+ .post_internal_cmd = inic_post_internal_cmd,
+ .dev_config = inic_dev_config,
+
+ .port_resume = inic_port_resume,
+
+ .port_start = inic_port_start,
+};
+
+static struct ata_port_info inic_port_info = {
+ .sht = &inic_sht,
+ /* For some reason, ATA_PROT_ATAPI is broken on this
+ * controller, and no, PIO_POLLING does't fix it. It somehow
+ * manages to report the wrong ireason and ignoring ireason
+ * results in machine lock up. Tell libata to always prefer
+ * DMA.
+ */
+ .flags = ATA_FLAG_SATA | ATA_FLAG_PIO_DMA,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .udma_mask = 0x7f, /* udma0-6 */
+ .port_ops = &inic_port_ops
+};
+
+static int init_controller(void __iomem *mmio_base, u16 hctl)
+{
+ int i;
+ u16 val;
+
+ hctl &= ~HCTL_KNOWN_BITS;
+
+ /* Soft reset whole controller. Spec says reset duration is 3
+ * PCI clocks, be generous and give it 10ms.
+ */
+ writew(hctl | HCTL_SOFTRST, mmio_base + HOST_CTL);
+ readw(mmio_base + HOST_CTL); /* flush */
+
+ for (i = 0; i < 10; i++) {
+ msleep(1);
+ val = readw(mmio_base + HOST_CTL);
+ if (!(val & HCTL_SOFTRST))
+ break;
+ }
+
+ if (val & HCTL_SOFTRST)
+ return -EIO;
+
+ /* mask all interrupts and reset ports */
+ for (i = 0; i < NR_PORTS; i++) {
+ void __iomem *port_base = mmio_base + i * PORT_SIZE;
+
+ writeb(0xff, port_base + PORT_IRQ_MASK);
+ inic_reset_port(port_base);
+ }
+
+ /* port IRQ is masked now, unmask global IRQ */
+ writew(hctl & ~HCTL_IRQOFF, mmio_base + HOST_CTL);
+ val = readw(mmio_base + HOST_IRQ_MASK);
+ val &= ~(HIRQ_PORT0 | HIRQ_PORT1);
+ writew(val, mmio_base + HOST_IRQ_MASK);
+
+ return 0;
+}
+
+static int inic_pci_device_resume(struct pci_dev *pdev)
+{
+ struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct inic_host_priv *hpriv = host->private_data;
+ void __iomem *mmio_base = host->iomap[MMIO_BAR];
+ int rc;
+
+ ata_pci_device_do_resume(pdev);
+
+ if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
+ printk("XXX\n");
+ rc = init_controller(mmio_base, hpriv->cached_hctl);
+ if (rc)
+ return rc;
+ }
+
+ ata_host_resume(host);
+
+ return 0;
+}
+
+static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ static int printed_version;
+ struct ata_port_info *pinfo = &inic_port_info;
+ struct ata_probe_ent *probe_ent;
+ struct inic_host_priv *hpriv;
+ void __iomem * const *iomap;
+ int i, rc;
+
+ if (!printed_version++)
+ dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+
+ rc = pcim_enable_device(pdev);
+ if (rc)
+ return rc;
+
+ rc = pci_request_regions(pdev, DRV_NAME);
+ if (rc)
+ return rc;
+
+ rc = pcim_iomap_regions(pdev, 0x3f, DRV_NAME);
+ if (rc)
+ return rc;
+ iomap = pcim_iomap_table(pdev);
+
+ /* Set dma_mask. This devices doesn't support 64bit addressing. */
+ rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ if (rc) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "32-bit DMA enable failed\n");
+ return rc;
+ }
+
+ rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+ if (rc) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "32-bit consistent DMA enable failed\n");
+ return rc;
+ }
+
+ probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL);
+ hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL);
+ if (!probe_ent || !hpriv)
+ return -ENOMEM;
+
+ probe_ent->dev = &pdev->dev;
+ INIT_LIST_HEAD(&probe_ent->node);
+
+ probe_ent->sht = pinfo->sht;
+ probe_ent->port_flags = pinfo->flags;
+ probe_ent->pio_mask = pinfo->pio_mask;
+ probe_ent->mwdma_mask = pinfo->mwdma_mask;
+ probe_ent->udma_mask = pinfo->udma_mask;
+ probe_ent->port_ops = pinfo->port_ops;
+ probe_ent->n_ports = NR_PORTS;
+
+ probe_ent->irq = pdev->irq;
+ probe_ent->irq_flags = IRQF_SHARED;
+
+ probe_ent->iomap = iomap;
+
+ for (i = 0; i < NR_PORTS; i++) {
+ struct ata_ioports *port = &probe_ent->port[i];
+ void __iomem *port_base = iomap[MMIO_BAR] + i * PORT_SIZE;
+
+ port->cmd_addr = iomap[2 * i];
+ port->altstatus_addr =
+ port->ctl_addr = (void __iomem *)
+ ((unsigned long)iomap[2 * i + 1] | ATA_PCI_CTL_OFS);
+ port->scr_addr = port_base + PORT_SCR;
+
+ ata_std_ports(port);
+ }
+
+ probe_ent->private_data = hpriv;
+ hpriv->cached_hctl = readw(iomap[MMIO_BAR] + HOST_CTL);
+
+ rc = init_controller(iomap[MMIO_BAR], hpriv->cached_hctl);
+ if (rc) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "failed to initialize controller\n");
+ return rc;
+ }
+
+ pci_set_master(pdev);
+
+ if (!ata_device_add(probe_ent))
+ return -ENODEV;
+
+ devm_kfree(&pdev->dev, probe_ent);
+
+ return 0;
+}
+
+static const struct pci_device_id inic_pci_tbl[] = {
+ { PCI_VDEVICE(INIT, 0x1622), },
+ { },
+};
+
+static struct pci_driver inic_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = inic_pci_tbl,
+ .suspend = ata_pci_device_suspend,
+ .resume = inic_pci_device_resume,
+ .probe = inic_init_one,
+ .remove = ata_pci_remove_one,
+};
+
+static int __init inic_init(void)
+{
+ return pci_register_driver(&inic_pci_driver);
+}
+
+static void __exit inic_exit(void)
+{
+ pci_unregister_driver(&inic_pci_driver);
+}
+
+MODULE_AUTHOR("Tejun Heo");
+MODULE_DESCRIPTION("low-level driver for Initio 162x SATA");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(pci, inic_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(inic_init);
+module_exit(inic_exit);
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index aae0b5201c1..d689df52eae 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -28,13 +28,11 @@
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
-#include <linux/sched.h>
#include <linux/dma-mapping.h>
#include <linux/device.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_cmnd.h>
#include <linux/libata.h>
-#include <asm/io.h>
#define DRV_NAME "sata_mv"
#define DRV_VERSION "0.7"
@@ -342,7 +340,6 @@ static u32 mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in);
static void mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
static void mv_phy_reset(struct ata_port *ap);
static void __mv_phy_reset(struct ata_port *ap, int can_sleep);
-static void mv_host_stop(struct ata_host *host);
static int mv_port_start(struct ata_port *ap);
static void mv_port_stop(struct ata_port *ap);
static void mv_qc_prep(struct ata_queued_cmd *qc);
@@ -406,19 +403,20 @@ static const struct ata_port_operations mv5_ops = {
.qc_prep = mv_qc_prep,
.qc_issue = mv_qc_issue,
- .data_xfer = ata_mmio_data_xfer,
+ .data_xfer = ata_data_xfer,
.eng_timeout = mv_eng_timeout,
.irq_handler = mv_interrupt,
.irq_clear = mv_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.scr_read = mv5_scr_read,
.scr_write = mv5_scr_write,
.port_start = mv_port_start,
.port_stop = mv_port_stop,
- .host_stop = mv_host_stop,
};
static const struct ata_port_operations mv6_ops = {
@@ -434,19 +432,20 @@ static const struct ata_port_operations mv6_ops = {
.qc_prep = mv_qc_prep,
.qc_issue = mv_qc_issue,
- .data_xfer = ata_mmio_data_xfer,
+ .data_xfer = ata_data_xfer,
.eng_timeout = mv_eng_timeout,
.irq_handler = mv_interrupt,
.irq_clear = mv_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.scr_read = mv_scr_read,
.scr_write = mv_scr_write,
.port_start = mv_port_start,
.port_stop = mv_port_stop,
- .host_stop = mv_host_stop,
};
static const struct ata_port_operations mv_iie_ops = {
@@ -462,19 +461,20 @@ static const struct ata_port_operations mv_iie_ops = {
.qc_prep = mv_qc_prep_iie,
.qc_issue = mv_qc_issue,
- .data_xfer = ata_mmio_data_xfer,
+ .data_xfer = ata_data_xfer,
.eng_timeout = mv_eng_timeout,
.irq_handler = mv_interrupt,
.irq_clear = mv_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.scr_read = mv_scr_read,
.scr_write = mv_scr_write,
.port_start = mv_port_start,
.port_stop = mv_port_stop,
- .host_stop = mv_host_stop,
};
static const struct ata_port_info mv_port_info[] = {
@@ -620,7 +620,7 @@ static inline void __iomem *mv_port_base(void __iomem *base, unsigned int port)
static inline void __iomem *mv_ap_base(struct ata_port *ap)
{
- return mv_port_base(ap->host->mmio_base, ap->port_no);
+ return mv_port_base(ap->host->iomap[MV_PRIMARY_BAR], ap->port_no);
}
static inline int mv_get_hc_count(unsigned long port_flags)
@@ -809,35 +809,6 @@ static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
}
}
-/**
- * mv_host_stop - Host specific cleanup/stop routine.
- * @host: host data structure
- *
- * Disable ints, cleanup host memory, call general purpose
- * host_stop.
- *
- * LOCKING:
- * Inherited from caller.
- */
-static void mv_host_stop(struct ata_host *host)
-{
- struct mv_host_priv *hpriv = host->private_data;
- struct pci_dev *pdev = to_pci_dev(host->dev);
-
- if (hpriv->hp_flags & MV_HP_FLAG_MSI) {
- pci_disable_msi(pdev);
- } else {
- pci_intx(pdev, 0);
- }
- kfree(hpriv);
- ata_host_stop(host);
-}
-
-static inline void mv_priv_free(struct mv_port_priv *pp, struct device *dev)
-{
- dma_free_coherent(dev, MV_PORT_PRIV_DMA_SZ, pp->crpb, pp->crpb_dma);
-}
-
static void mv_edma_cfg(struct mv_host_priv *hpriv, void __iomem *port_mmio)
{
u32 cfg = readl(port_mmio + EDMA_CFG_OFS);
@@ -883,22 +854,21 @@ static int mv_port_start(struct ata_port *ap)
void __iomem *port_mmio = mv_ap_base(ap);
void *mem;
dma_addr_t mem_dma;
- int rc = -ENOMEM;
+ int rc;
- pp = kmalloc(sizeof(*pp), GFP_KERNEL);
+ pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
if (!pp)
- goto err_out;
- memset(pp, 0, sizeof(*pp));
+ return -ENOMEM;
- mem = dma_alloc_coherent(dev, MV_PORT_PRIV_DMA_SZ, &mem_dma,
- GFP_KERNEL);
+ mem = dmam_alloc_coherent(dev, MV_PORT_PRIV_DMA_SZ, &mem_dma,
+ GFP_KERNEL);
if (!mem)
- goto err_out_pp;
+ return -ENOMEM;
memset(mem, 0, MV_PORT_PRIV_DMA_SZ);
rc = ata_pad_alloc(ap, dev);
if (rc)
- goto err_out_priv;
+ return rc;
/* First item in chunk of DMA memory:
* 32-slot command request table (CRQB), 32 bytes each in size
@@ -951,13 +921,6 @@ static int mv_port_start(struct ata_port *ap)
*/
ap->private_data = pp;
return 0;
-
-err_out_priv:
- mv_priv_free(pp, dev);
-err_out_pp:
- kfree(pp);
-err_out:
- return rc;
}
/**
@@ -971,18 +934,11 @@ err_out:
*/
static void mv_port_stop(struct ata_port *ap)
{
- struct device *dev = ap->host->dev;
- struct mv_port_priv *pp = ap->private_data;
unsigned long flags;
spin_lock_irqsave(&ap->host->lock, flags);
mv_stop_dma(ap);
spin_unlock_irqrestore(&ap->host->lock, flags);
-
- ap->private_data = NULL;
- ata_pad_free(ap, dev);
- mv_priv_free(pp, dev);
- kfree(pp);
}
/**
@@ -1348,7 +1304,7 @@ static void mv_err_intr(struct ata_port *ap, int reset_allowed)
*/
static void mv_host_intr(struct ata_host *host, u32 relevant, unsigned int hc)
{
- void __iomem *mmio = host->mmio_base;
+ void __iomem *mmio = host->iomap[MV_PRIMARY_BAR];
void __iomem *hc_mmio = mv_hc_base(mmio, hc);
struct ata_queued_cmd *qc;
u32 hc_irq_cause;
@@ -1391,8 +1347,7 @@ static void mv_host_intr(struct ata_host *host, u32 relevant, unsigned int hc)
} else {
/* PIO: check for device (drive) interrupt */
if ((DEV_IRQ << hard_port) & hc_irq_cause) {
- ata_status = readb((void __iomem *)
- ap->ioaddr.status_addr);
+ ata_status = readb(ap->ioaddr.status_addr);
handled = 1;
/* ignore spurious intr if drive still BUSY */
if (ata_status & ATA_BUSY) {
@@ -1452,7 +1407,7 @@ static irqreturn_t mv_interrupt(int irq, void *dev_instance)
{
struct ata_host *host = dev_instance;
unsigned int hc, handled = 0, n_hcs;
- void __iomem *mmio = host->mmio_base;
+ void __iomem *mmio = host->iomap[MV_PRIMARY_BAR];
struct mv_host_priv *hpriv;
u32 irq_stat;
@@ -1528,22 +1483,24 @@ static unsigned int mv5_scr_offset(unsigned int sc_reg_in)
static u32 mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in)
{
- void __iomem *mmio = mv5_phy_base(ap->host->mmio_base, ap->port_no);
+ void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
+ void __iomem *addr = mv5_phy_base(mmio, ap->port_no);
unsigned int ofs = mv5_scr_offset(sc_reg_in);
if (ofs != 0xffffffffU)
- return readl(mmio + ofs);
+ return readl(addr + ofs);
else
return (u32) ofs;
}
static void mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
{
- void __iomem *mmio = mv5_phy_base(ap->host->mmio_base, ap->port_no);
+ void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
+ void __iomem *addr = mv5_phy_base(mmio, ap->port_no);
unsigned int ofs = mv5_scr_offset(sc_reg_in);
if (ofs != 0xffffffffU)
- writelfl(val, mmio + ofs);
+ writelfl(val, addr + ofs);
}
static void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio)
@@ -1905,7 +1862,7 @@ static void mv_channel_reset(struct mv_host_priv *hpriv, void __iomem *mmio,
static void mv_stop_and_reset(struct ata_port *ap)
{
struct mv_host_priv *hpriv = ap->host->private_data;
- void __iomem *mmio = ap->host->mmio_base;
+ void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
mv_stop_dma(ap);
@@ -2003,10 +1960,10 @@ comreset_retry:
break;
}
- tf.lbah = readb((void __iomem *) ap->ioaddr.lbah_addr);
- tf.lbam = readb((void __iomem *) ap->ioaddr.lbam_addr);
- tf.lbal = readb((void __iomem *) ap->ioaddr.lbal_addr);
- tf.nsect = readb((void __iomem *) ap->ioaddr.nsect_addr);
+ tf.lbah = readb(ap->ioaddr.lbah_addr);
+ tf.lbam = readb(ap->ioaddr.lbam_addr);
+ tf.lbal = readb(ap->ioaddr.lbal_addr);
+ tf.nsect = readb(ap->ioaddr.nsect_addr);
dev->class = ata_dev_classify(&tf);
if (!ata_dev_enabled(dev)) {
@@ -2038,17 +1995,17 @@ static void mv_phy_reset(struct ata_port *ap)
*/
static void mv_eng_timeout(struct ata_port *ap)
{
+ void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
struct ata_queued_cmd *qc;
unsigned long flags;
ata_port_printk(ap, KERN_ERR, "Entering mv_eng_timeout\n");
DPRINTK("All regs @ start of eng_timeout\n");
- mv_dump_all_regs(ap->host->mmio_base, ap->port_no,
- to_pci_dev(ap->host->dev));
+ mv_dump_all_regs(mmio, ap->port_no, to_pci_dev(ap->host->dev));
qc = ata_qc_from_tag(ap, ap->active_tag);
printk(KERN_ERR "mmio_base %p ap %p qc %p scsi_cmnd %p &cmnd %p\n",
- ap->host->mmio_base, ap, qc, qc->scsicmd, &qc->scsicmd->cmnd);
+ mmio, ap, qc, qc->scsicmd, &qc->scsicmd->cmnd);
spin_lock_irqsave(&ap->host->lock, flags);
mv_err_intr(ap, 0);
@@ -2076,7 +2033,7 @@ static void mv_eng_timeout(struct ata_port *ap)
*/
static void mv_port_init(struct ata_ioports *port, void __iomem *port_mmio)
{
- unsigned long shd_base = (unsigned long) port_mmio + SHD_BLK_OFS;
+ void __iomem *shd_base = port_mmio + SHD_BLK_OFS;
unsigned serr_ofs;
/* PIO related setup
@@ -2224,7 +2181,7 @@ static int mv_init_host(struct pci_dev *pdev, struct ata_probe_ent *probe_ent,
unsigned int board_idx)
{
int rc = 0, n_hc, port, hc;
- void __iomem *mmio = probe_ent->mmio_base;
+ void __iomem *mmio = probe_ent->iomap[MV_PRIMARY_BAR];
struct mv_host_priv *hpriv = probe_ent->private_data;
/* global interrupt mask */
@@ -2342,49 +2299,36 @@ static void mv_print_info(struct ata_probe_ent *probe_ent)
static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version = 0;
- struct ata_probe_ent *probe_ent = NULL;
+ struct device *dev = &pdev->dev;
+ struct ata_probe_ent *probe_ent;
struct mv_host_priv *hpriv;
unsigned int board_idx = (unsigned int)ent->driver_data;
- void __iomem *mmio_base;
- int pci_dev_busy = 0, rc;
+ int rc;
if (!printed_version++)
dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
- rc = pci_enable_device(pdev);
- if (rc) {
+ rc = pcim_enable_device(pdev);
+ if (rc)
return rc;
- }
pci_set_master(pdev);
- rc = pci_request_regions(pdev, DRV_NAME);
- if (rc) {
- pci_dev_busy = 1;
- goto err_out;
- }
+ rc = pcim_iomap_regions(pdev, 1 << MV_PRIMARY_BAR, DRV_NAME);
+ if (rc == -EBUSY)
+ pcim_pin_device(pdev);
+ if (rc)
+ return rc;
- probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
- if (probe_ent == NULL) {
- rc = -ENOMEM;
- goto err_out_regions;
- }
+ probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL);
+ if (probe_ent == NULL)
+ return -ENOMEM;
- memset(probe_ent, 0, sizeof(*probe_ent));
probe_ent->dev = pci_dev_to_dev(pdev);
INIT_LIST_HEAD(&probe_ent->node);
- mmio_base = pci_iomap(pdev, MV_PRIMARY_BAR, 0);
- if (mmio_base == NULL) {
- rc = -ENOMEM;
- goto err_out_free_ent;
- }
-
- hpriv = kmalloc(sizeof(*hpriv), GFP_KERNEL);
- if (!hpriv) {
- rc = -ENOMEM;
- goto err_out_iounmap;
- }
- memset(hpriv, 0, sizeof(*hpriv));
+ hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
+ if (!hpriv)
+ return -ENOMEM;
probe_ent->sht = mv_port_info[board_idx].sht;
probe_ent->port_flags = mv_port_info[board_idx].flags;
@@ -2394,53 +2338,26 @@ static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
probe_ent->irq = pdev->irq;
probe_ent->irq_flags = IRQF_SHARED;
- probe_ent->mmio_base = mmio_base;
+ probe_ent->iomap = pcim_iomap_table(pdev);
probe_ent->private_data = hpriv;
/* initialize adapter */
rc = mv_init_host(pdev, probe_ent, board_idx);
- if (rc) {
- goto err_out_hpriv;
- }
+ if (rc)
+ return rc;
/* Enable interrupts */
- if (msi && pci_enable_msi(pdev) == 0) {
- hpriv->hp_flags |= MV_HP_FLAG_MSI;
- } else {
+ if (msi && !pci_enable_msi(pdev))
pci_intx(pdev, 1);
- }
mv_dump_pci_cfg(pdev, 0x68);
mv_print_info(probe_ent);
- if (ata_device_add(probe_ent) == 0) {
- rc = -ENODEV; /* No devices discovered */
- goto err_out_dev_add;
- }
+ if (ata_device_add(probe_ent) == 0)
+ return -ENODEV;
- kfree(probe_ent);
+ devm_kfree(dev, probe_ent);
return 0;
-
-err_out_dev_add:
- if (MV_HP_FLAG_MSI & hpriv->hp_flags) {
- pci_disable_msi(pdev);
- } else {
- pci_intx(pdev, 0);
- }
-err_out_hpriv:
- kfree(hpriv);
-err_out_iounmap:
- pci_iounmap(pdev, mmio_base);
-err_out_free_ent:
- kfree(probe_ent);
-err_out_regions:
- pci_release_regions(pdev);
-err_out:
- if (!pci_dev_busy) {
- pci_disable_device(pdev);
- }
-
- return rc;
}
static int __init mv_init(void)
diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c
index f7a963eb1f0..ab92f208dae 100644
--- a/drivers/ata/sata_nv.c
+++ b/drivers/ata/sata_nv.c
@@ -49,11 +49,13 @@
#include <linux/libata.h>
#define DRV_NAME "sata_nv"
-#define DRV_VERSION "3.2"
+#define DRV_VERSION "3.3"
#define NV_ADMA_DMA_BOUNDARY 0xffffffffUL
enum {
+ NV_MMIO_BAR = 5,
+
NV_PORTS = 2,
NV_PIO_MASK = 0x1f,
NV_MWDMA_MASK = 0x07,
@@ -213,12 +215,21 @@ struct nv_adma_port_priv {
dma_addr_t cpb_dma;
struct nv_adma_prd *aprd;
dma_addr_t aprd_dma;
+ void __iomem * ctl_block;
+ void __iomem * gen_block;
+ void __iomem * notifier_clear_block;
u8 flags;
};
+struct nv_host_priv {
+ unsigned long type;
+};
+
#define NV_ADMA_CHECK_INTR(GCTL, PORT) ((GCTL) & ( 1 << (19 + (12 * (PORT)))))
static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+static void nv_remove_one (struct pci_dev *pdev);
+static int nv_pci_device_resume(struct pci_dev *pdev);
static void nv_ck804_host_stop(struct ata_host *host);
static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance);
static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance);
@@ -239,6 +250,8 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance);
static void nv_adma_irq_clear(struct ata_port *ap);
static int nv_adma_port_start(struct ata_port *ap);
static void nv_adma_port_stop(struct ata_port *ap);
+static int nv_adma_port_suspend(struct ata_port *ap, pm_message_t mesg);
+static int nv_adma_port_resume(struct ata_port *ap);
static void nv_adma_error_handler(struct ata_port *ap);
static void nv_adma_host_stop(struct ata_host *host);
static void nv_adma_bmdma_setup(struct ata_queued_cmd *qc);
@@ -284,7 +297,9 @@ static struct pci_driver nv_pci_driver = {
.name = DRV_NAME,
.id_table = nv_pci_tbl,
.probe = nv_init_one,
- .remove = ata_pci_remove_one,
+ .suspend = ata_pci_device_suspend,
+ .resume = nv_pci_device_resume,
+ .remove = nv_remove_one,
};
static struct scsi_host_template nv_sht = {
@@ -303,6 +318,8 @@ static struct scsi_host_template nv_sht = {
.slave_configure = ata_scsi_slave_config,
.slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
+ .suspend = ata_scsi_device_suspend,
+ .resume = ata_scsi_device_resume,
};
static struct scsi_host_template nv_adma_sht = {
@@ -321,6 +338,8 @@ static struct scsi_host_template nv_adma_sht = {
.slave_configure = nv_adma_slave_config,
.slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
+ .suspend = ata_scsi_device_suspend,
+ .resume = ata_scsi_device_resume,
};
static const struct ata_port_operations nv_generic_ops = {
@@ -340,14 +359,14 @@ static const struct ata_port_operations nv_generic_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = nv_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = nv_generic_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.scr_read = nv_scr_read,
.scr_write = nv_scr_write,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_pci_host_stop,
};
static const struct ata_port_operations nv_nf2_ops = {
@@ -367,14 +386,14 @@ static const struct ata_port_operations nv_nf2_ops = {
.thaw = nv_nf2_thaw,
.error_handler = nv_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = nv_nf2_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.scr_read = nv_scr_read,
.scr_write = nv_scr_write,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_pci_host_stop,
};
static const struct ata_port_operations nv_ck804_ops = {
@@ -394,13 +413,14 @@ static const struct ata_port_operations nv_ck804_ops = {
.thaw = nv_ck804_thaw,
.error_handler = nv_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = nv_ck804_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.scr_read = nv_scr_read,
.scr_write = nv_scr_write,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
.host_stop = nv_ck804_host_stop,
};
@@ -422,13 +442,17 @@ static const struct ata_port_operations nv_adma_ops = {
.thaw = nv_ck804_thaw,
.error_handler = nv_adma_error_handler,
.post_internal_cmd = nv_adma_bmdma_stop,
- .data_xfer = ata_mmio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = nv_adma_interrupt,
.irq_clear = nv_adma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.scr_read = nv_scr_read,
.scr_write = nv_scr_write,
.port_start = nv_adma_port_start,
.port_stop = nv_adma_port_stop,
+ .port_suspend = nv_adma_port_suspend,
+ .port_resume = nv_adma_port_resume,
.host_stop = nv_adma_host_stop,
};
@@ -467,6 +491,7 @@ static struct ata_port_info nv_port_info[] = {
{
.sht = &nv_adma_sht,
.flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+ ATA_FLAG_HRST_TO_RESUME |
ATA_FLAG_MMIO | ATA_FLAG_NCQ,
.pio_mask = NV_PIO_MASK,
.mwdma_mask = NV_MWDMA_MASK,
@@ -483,57 +508,72 @@ MODULE_VERSION(DRV_VERSION);
static int adma_enabled = 1;
-static inline void __iomem *__nv_adma_ctl_block(void __iomem *mmio,
- unsigned int port_no)
-{
- mmio += NV_ADMA_PORT + port_no * NV_ADMA_PORT_SIZE;
- return mmio;
-}
-
-static inline void __iomem *nv_adma_ctl_block(struct ata_port *ap)
-{
- return __nv_adma_ctl_block(ap->host->mmio_base, ap->port_no);
-}
-
-static inline void __iomem *nv_adma_gen_block(struct ata_port *ap)
-{
- return (ap->host->mmio_base + NV_ADMA_GEN);
-}
-
-static inline void __iomem *nv_adma_notifier_clear_block(struct ata_port *ap)
-{
- return (nv_adma_gen_block(ap) + NV_ADMA_NOTIFIER_CLEAR + (4 * ap->port_no));
-}
-
static void nv_adma_register_mode(struct ata_port *ap)
{
- void __iomem *mmio = nv_adma_ctl_block(ap);
struct nv_adma_port_priv *pp = ap->private_data;
- u16 tmp;
+ void __iomem *mmio = pp->ctl_block;
+ u16 tmp, status;
+ int count = 0;
if (pp->flags & NV_ADMA_PORT_REGISTER_MODE)
return;
+ status = readw(mmio + NV_ADMA_STAT);
+ while(!(status & NV_ADMA_STAT_IDLE) && count < 20) {
+ ndelay(50);
+ status = readw(mmio + NV_ADMA_STAT);
+ count++;
+ }
+ if(count == 20)
+ ata_port_printk(ap, KERN_WARNING,
+ "timeout waiting for ADMA IDLE, stat=0x%hx\n",
+ status);
+
tmp = readw(mmio + NV_ADMA_CTL);
writew(tmp & ~NV_ADMA_CTL_GO, mmio + NV_ADMA_CTL);
+ count = 0;
+ status = readw(mmio + NV_ADMA_STAT);
+ while(!(status & NV_ADMA_STAT_LEGACY) && count < 20) {
+ ndelay(50);
+ status = readw(mmio + NV_ADMA_STAT);
+ count++;
+ }
+ if(count == 20)
+ ata_port_printk(ap, KERN_WARNING,
+ "timeout waiting for ADMA LEGACY, stat=0x%hx\n",
+ status);
+
pp->flags |= NV_ADMA_PORT_REGISTER_MODE;
}
static void nv_adma_mode(struct ata_port *ap)
{
- void __iomem *mmio = nv_adma_ctl_block(ap);
struct nv_adma_port_priv *pp = ap->private_data;
- u16 tmp;
+ void __iomem *mmio = pp->ctl_block;
+ u16 tmp, status;
+ int count = 0;
if (!(pp->flags & NV_ADMA_PORT_REGISTER_MODE))
return;
-
+
WARN_ON(pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE);
tmp = readw(mmio + NV_ADMA_CTL);
writew(tmp | NV_ADMA_CTL_GO, mmio + NV_ADMA_CTL);
+ status = readw(mmio + NV_ADMA_STAT);
+ while(((status & NV_ADMA_STAT_LEGACY) ||
+ !(status & NV_ADMA_STAT_IDLE)) && count < 20) {
+ ndelay(50);
+ status = readw(mmio + NV_ADMA_STAT);
+ count++;
+ }
+ if(count == 20)
+ ata_port_printk(ap, KERN_WARNING,
+ "timeout waiting for ADMA LEGACY clear and IDLE, stat=0x%hx\n",
+ status);
+
pp->flags &= ~NV_ADMA_PORT_REGISTER_MODE;
}
@@ -568,7 +608,7 @@ static int nv_adma_slave_config(struct scsi_device *sdev)
/* Subtract 1 since an extra entry may be needed for padding, see
libata-scsi.c */
sg_tablesize = LIBATA_MAX_PRD - 1;
-
+
/* Since the legacy DMA engine is in use, we need to disable ADMA
on the port. */
adma_enable = 0;
@@ -580,7 +620,7 @@ static int nv_adma_slave_config(struct scsi_device *sdev)
sg_tablesize = NV_ADMA_SGTBL_TOTAL_LEN;
adma_enable = 1;
}
-
+
pci_read_config_dword(pdev, NV_MCP_SATA_CFG_20, &current_reg);
if(ap->port_no == 1)
@@ -589,7 +629,7 @@ static int nv_adma_slave_config(struct scsi_device *sdev)
else
config_mask = NV_MCP_SATA_CFG_20_PORT0_EN |
NV_MCP_SATA_CFG_20_PORT0_PWB_EN;
-
+
if(adma_enable) {
new_reg = current_reg | config_mask;
pp->flags &= ~NV_ADMA_ATAPI_SETUP_COMPLETE;
@@ -598,10 +638,10 @@ static int nv_adma_slave_config(struct scsi_device *sdev)
new_reg = current_reg & ~config_mask;
pp->flags |= NV_ADMA_ATAPI_SETUP_COMPLETE;
}
-
+
if(current_reg != new_reg)
pci_write_config_dword(pdev, NV_MCP_SATA_CFG_20, new_reg);
-
+
blk_queue_bounce_limit(sdev->request_queue, bounce_limit);
blk_queue_segment_boundary(sdev->request_queue, segment_boundary);
blk_queue_max_hw_segments(sdev->request_queue, sg_tablesize);
@@ -648,53 +688,62 @@ static unsigned int nv_adma_tf_to_cpb(struct ata_taskfile *tf, __le16 *cpb)
return idx;
}
-static void nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err)
+static int nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err)
{
struct nv_adma_port_priv *pp = ap->private_data;
- int complete = 0, have_err = 0;
u8 flags = pp->cpb[cpb_num].resp_flags;
VPRINTK("CPB %d, flags=0x%x\n", cpb_num, flags);
- if (flags & NV_CPB_RESP_DONE) {
- VPRINTK("CPB flags done, flags=0x%x\n", flags);
- complete = 1;
- }
- if (flags & NV_CPB_RESP_ATA_ERR) {
- ata_port_printk(ap, KERN_ERR, "CPB flags ATA err, flags=0x%x\n", flags);
- have_err = 1;
- complete = 1;
- }
- if (flags & NV_CPB_RESP_CMD_ERR) {
- ata_port_printk(ap, KERN_ERR, "CPB flags CMD err, flags=0x%x\n", flags);
- have_err = 1;
- complete = 1;
- }
- if (flags & NV_CPB_RESP_CPB_ERR) {
- ata_port_printk(ap, KERN_ERR, "CPB flags CPB err, flags=0x%x\n", flags);
- have_err = 1;
- complete = 1;
+ if (unlikely((force_err ||
+ flags & (NV_CPB_RESP_ATA_ERR |
+ NV_CPB_RESP_CMD_ERR |
+ NV_CPB_RESP_CPB_ERR)))) {
+ struct ata_eh_info *ehi = &ap->eh_info;
+ int freeze = 0;
+
+ ata_ehi_clear_desc(ehi);
+ ata_ehi_push_desc(ehi, "CPB resp_flags 0x%x", flags );
+ if (flags & NV_CPB_RESP_ATA_ERR) {
+ ata_ehi_push_desc(ehi, ": ATA error");
+ ehi->err_mask |= AC_ERR_DEV;
+ } else if (flags & NV_CPB_RESP_CMD_ERR) {
+ ata_ehi_push_desc(ehi, ": CMD error");
+ ehi->err_mask |= AC_ERR_DEV;
+ } else if (flags & NV_CPB_RESP_CPB_ERR) {
+ ata_ehi_push_desc(ehi, ": CPB error");
+ ehi->err_mask |= AC_ERR_SYSTEM;
+ freeze = 1;
+ } else {
+ /* notifier error, but no error in CPB flags? */
+ ehi->err_mask |= AC_ERR_OTHER;
+ freeze = 1;
+ }
+ /* Kill all commands. EH will determine what actually failed. */
+ if (freeze)
+ ata_port_freeze(ap);
+ else
+ ata_port_abort(ap);
+ return 1;
}
- if(complete || force_err)
- {
+
+ if (flags & NV_CPB_RESP_DONE) {
struct ata_queued_cmd *qc = ata_qc_from_tag(ap, cpb_num);
- if(likely(qc)) {
- u8 ata_status = 0;
- /* Only use the ATA port status for non-NCQ commands.
+ VPRINTK("CPB flags done, flags=0x%x\n", flags);
+ if (likely(qc)) {
+ /* Grab the ATA port status for non-NCQ commands.
For NCQ commands the current status may have nothing to do with
the command just completed. */
- if(qc->tf.protocol != ATA_PROT_NCQ)
- ata_status = readb(nv_adma_ctl_block(ap) + (ATA_REG_STATUS * 4));
-
- if(have_err || force_err)
- ata_status |= ATA_ERR;
-
- qc->err_mask |= ac_err_mask(ata_status);
+ if (qc->tf.protocol != ATA_PROT_NCQ) {
+ u8 ata_status = readb(pp->ctl_block + (ATA_REG_STATUS * 4));
+ qc->err_mask |= ac_err_mask(ata_status);
+ }
DPRINTK("Completing qc from tag %d with err_mask %u\n",cpb_num,
qc->err_mask);
ata_qc_complete(qc);
}
}
+ return 0;
}
static int nv_host_intr(struct ata_port *ap, u8 irq_stat)
@@ -735,15 +784,14 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
if (ap && !(ap->flags & ATA_FLAG_DISABLED)) {
struct nv_adma_port_priv *pp = ap->private_data;
- void __iomem *mmio = nv_adma_ctl_block(ap);
+ void __iomem *mmio = pp->ctl_block;
u16 status;
u32 gen_ctl;
- int have_global_err = 0;
u32 notifier, notifier_error;
/* if in ATA register mode, use standard ata interrupt handler */
if (pp->flags & NV_ADMA_PORT_REGISTER_MODE) {
- u8 irq_stat = readb(host->mmio_base + NV_INT_STATUS_CK804)
+ u8 irq_stat = readb(host->iomap[NV_MMIO_BAR] + NV_INT_STATUS_CK804)
>> (NV_INT_PORT_SHIFT * i);
if(ata_tag_valid(ap->active_tag))
/** NV_INT_DEV indication seems unreliable at times
@@ -758,7 +806,7 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
notifier_error = readl(mmio + NV_ADMA_NOTIFIER_ERROR);
notifier_clears[i] = notifier | notifier_error;
- gen_ctl = readl(nv_adma_gen_block(ap) + NV_ADMA_GEN_CTL);
+ gen_ctl = readl(pp->gen_block + NV_ADMA_GEN_CTL);
if( !NV_ADMA_CHECK_INTR(gen_ctl, ap->port_no) && !notifier &&
!notifier_error)
@@ -774,52 +822,64 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
readw(mmio + NV_ADMA_STAT); /* flush posted write */
rmb();
- /* freeze if hotplugged */
- if (unlikely(status & (NV_ADMA_STAT_HOTPLUG | NV_ADMA_STAT_HOTUNPLUG))) {
- ata_port_printk(ap, KERN_NOTICE, "Hotplug event, freezing\n");
+ handled++; /* irq handled if we got here */
+
+ /* freeze if hotplugged or controller error */
+ if (unlikely(status & (NV_ADMA_STAT_HOTPLUG |
+ NV_ADMA_STAT_HOTUNPLUG |
+ NV_ADMA_STAT_TIMEOUT |
+ NV_ADMA_STAT_SERROR))) {
+ struct ata_eh_info *ehi = &ap->eh_info;
+
+ ata_ehi_clear_desc(ehi);
+ ata_ehi_push_desc(ehi, "ADMA status 0x%08x", status );
+ if (status & NV_ADMA_STAT_TIMEOUT) {
+ ehi->err_mask |= AC_ERR_SYSTEM;
+ ata_ehi_push_desc(ehi, ": timeout");
+ } else if (status & NV_ADMA_STAT_HOTPLUG) {
+ ata_ehi_hotplugged(ehi);
+ ata_ehi_push_desc(ehi, ": hotplug");
+ } else if (status & NV_ADMA_STAT_HOTUNPLUG) {
+ ata_ehi_hotplugged(ehi);
+ ata_ehi_push_desc(ehi, ": hot unplug");
+ } else if (status & NV_ADMA_STAT_SERROR) {
+ /* let libata analyze SError and figure out the cause */
+ ata_ehi_push_desc(ehi, ": SError");
+ }
ata_port_freeze(ap);
- handled++;
continue;
}
- if (status & NV_ADMA_STAT_TIMEOUT) {
- ata_port_printk(ap, KERN_ERR, "timeout, stat=0x%x\n", status);
- have_global_err = 1;
- }
- if (status & NV_ADMA_STAT_CPBERR) {
- ata_port_printk(ap, KERN_ERR, "CPB error, stat=0x%x\n", status);
- have_global_err = 1;
- }
- if ((status & NV_ADMA_STAT_DONE) || have_global_err) {
+ if (status & (NV_ADMA_STAT_DONE |
+ NV_ADMA_STAT_CPBERR)) {
/** Check CPBs for completed commands */
- if(ata_tag_valid(ap->active_tag))
+ if (ata_tag_valid(ap->active_tag)) {
/* Non-NCQ command */
- nv_adma_check_cpb(ap, ap->active_tag, have_global_err ||
- (notifier_error & (1 << ap->active_tag)));
- else {
- int pos;
+ nv_adma_check_cpb(ap, ap->active_tag,
+ notifier_error & (1 << ap->active_tag));
+ } else {
+ int pos, error = 0;
u32 active = ap->sactive;
- while( (pos = ffs(active)) ) {
+
+ while ((pos = ffs(active)) && !error) {
pos--;
- nv_adma_check_cpb(ap, pos, have_global_err ||
- (notifier_error & (1 << pos)) );
+ error = nv_adma_check_cpb(ap, pos,
+ notifier_error & (1 << pos) );
active &= ~(1 << pos );
}
}
}
-
- handled++; /* irq handled if we got here */
}
}
-
+
if(notifier_clears[0] || notifier_clears[1]) {
/* Note: Both notifier clear registers must be written
if either is set, even if one is zero, according to NVIDIA. */
- writel(notifier_clears[0],
- nv_adma_notifier_clear_block(host->ports[0]));
- writel(notifier_clears[1],
- nv_adma_notifier_clear_block(host->ports[1]));
+ struct nv_adma_port_priv *pp = host->ports[0]->private_data;
+ writel(notifier_clears[0], pp->notifier_clear_block);
+ pp = host->ports[1]->private_data;
+ writel(notifier_clears[1], pp->notifier_clear_block);
}
spin_unlock(&host->lock);
@@ -829,19 +889,20 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
static void nv_adma_irq_clear(struct ata_port *ap)
{
- void __iomem *mmio = nv_adma_ctl_block(ap);
+ struct nv_adma_port_priv *pp = ap->private_data;
+ void __iomem *mmio = pp->ctl_block;
u16 status = readw(mmio + NV_ADMA_STAT);
u32 notifier = readl(mmio + NV_ADMA_NOTIFIER);
u32 notifier_error = readl(mmio + NV_ADMA_NOTIFIER_ERROR);
- unsigned long dma_stat_addr = ap->ioaddr.bmdma_addr + ATA_DMA_STATUS;
+ void __iomem *dma_stat_addr = ap->ioaddr.bmdma_addr + ATA_DMA_STATUS;
/* clear ADMA status */
writew(status, mmio + NV_ADMA_STAT);
writel(notifier | notifier_error,
- nv_adma_notifier_clear_block(ap));
+ pp->notifier_clear_block);
/** clear legacy status */
- outb(inb(dma_stat_addr), dma_stat_addr);
+ iowrite8(ioread8(dma_stat_addr), dma_stat_addr);
}
static void nv_adma_bmdma_setup(struct ata_queued_cmd *qc)
@@ -857,15 +918,15 @@ static void nv_adma_bmdma_setup(struct ata_queued_cmd *qc)
}
/* load PRD table addr. */
- outl(ap->prd_dma, ap->ioaddr.bmdma_addr + ATA_DMA_TABLE_OFS);
+ iowrite32(ap->prd_dma, ap->ioaddr.bmdma_addr + ATA_DMA_TABLE_OFS);
/* specify data direction, triple-check start bit is clear */
- dmactl = inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+ dmactl = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
dmactl &= ~(ATA_DMA_WR | ATA_DMA_START);
if (!rw)
dmactl |= ATA_DMA_WR;
- outb(dmactl, ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+ iowrite8(dmactl, ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
/* issue r/w command */
ata_exec_command(ap, &qc->tf);
@@ -883,9 +944,9 @@ static void nv_adma_bmdma_start(struct ata_queued_cmd *qc)
}
/* start host DMA transaction */
- dmactl = inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
- outb(dmactl | ATA_DMA_START,
- ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+ dmactl = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+ iowrite8(dmactl | ATA_DMA_START,
+ ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
}
static void nv_adma_bmdma_stop(struct ata_queued_cmd *qc)
@@ -897,8 +958,8 @@ static void nv_adma_bmdma_stop(struct ata_queued_cmd *qc)
return;
/* clear start/stop bit */
- outb(inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD) & ~ATA_DMA_START,
- ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+ iowrite8(ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD) & ~ATA_DMA_START,
+ ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
/* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */
ata_altstatus(ap); /* dummy read */
@@ -910,7 +971,7 @@ static u8 nv_adma_bmdma_status(struct ata_port *ap)
WARN_ON(!(pp->flags & NV_ADMA_PORT_REGISTER_MODE));
- return inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
+ return ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
}
static int nv_adma_port_start(struct ata_port *ap)
@@ -920,7 +981,7 @@ static int nv_adma_port_start(struct ata_port *ap)
int rc;
void *mem;
dma_addr_t mem_dma;
- void __iomem *mmio = nv_adma_ctl_block(ap);
+ void __iomem *mmio;
u16 tmp;
VPRINTK("ENTER\n");
@@ -929,19 +990,21 @@ static int nv_adma_port_start(struct ata_port *ap)
if (rc)
return rc;
- pp = kzalloc(sizeof(*pp), GFP_KERNEL);
- if (!pp) {
- rc = -ENOMEM;
- goto err_out;
- }
-
- mem = dma_alloc_coherent(dev, NV_ADMA_PORT_PRIV_DMA_SZ,
- &mem_dma, GFP_KERNEL);
-
- if (!mem) {
- rc = -ENOMEM;
- goto err_out_kfree;
- }
+ pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
+ if (!pp)
+ return -ENOMEM;
+
+ mmio = ap->host->iomap[NV_MMIO_BAR] + NV_ADMA_PORT +
+ ap->port_no * NV_ADMA_PORT_SIZE;
+ pp->ctl_block = mmio;
+ pp->gen_block = ap->host->iomap[NV_MMIO_BAR] + NV_ADMA_GEN;
+ pp->notifier_clear_block = pp->gen_block +
+ NV_ADMA_NOTIFIER_CLEAR + (4 * ap->port_no);
+
+ mem = dmam_alloc_coherent(dev, NV_ADMA_PORT_PRIV_DMA_SZ,
+ &mem_dma, GFP_KERNEL);
+ if (!mem)
+ return -ENOMEM;
memset(mem, 0, NV_ADMA_PORT_PRIV_DMA_SZ);
/*
@@ -975,9 +1038,9 @@ static int nv_adma_port_start(struct ata_port *ap)
/* clear CPB fetch count */
writew(0, mmio + NV_ADMA_CPB_COUNT);
- /* clear GO for register mode */
+ /* clear GO for register mode, enable interrupt */
tmp = readw(mmio + NV_ADMA_CTL);
- writew(tmp & ~NV_ADMA_CTL_GO, mmio + NV_ADMA_CTL);
+ writew( (tmp & ~NV_ADMA_CTL_GO) | NV_ADMA_CTL_AIEN, mmio + NV_ADMA_CTL);
tmp = readw(mmio + NV_ADMA_CTL);
writew(tmp | NV_ADMA_CTL_CHANNEL_RESET, mmio + NV_ADMA_CTL);
@@ -987,53 +1050,89 @@ static int nv_adma_port_start(struct ata_port *ap)
readl( mmio + NV_ADMA_CTL ); /* flush posted write */
return 0;
-
-err_out_kfree:
- kfree(pp);
-err_out:
- ata_port_stop(ap);
- return rc;
}
static void nv_adma_port_stop(struct ata_port *ap)
{
- struct device *dev = ap->host->dev;
struct nv_adma_port_priv *pp = ap->private_data;
- void __iomem *mmio = nv_adma_ctl_block(ap);
+ void __iomem *mmio = pp->ctl_block;
VPRINTK("ENTER\n");
+ writew(0, mmio + NV_ADMA_CTL);
+}
+
+static int nv_adma_port_suspend(struct ata_port *ap, pm_message_t mesg)
+{
+ struct nv_adma_port_priv *pp = ap->private_data;
+ void __iomem *mmio = pp->ctl_block;
+ /* Go to register mode - clears GO */
+ nv_adma_register_mode(ap);
+
+ /* clear CPB fetch count */
+ writew(0, mmio + NV_ADMA_CPB_COUNT);
+
+ /* disable interrupt, shut down port */
writew(0, mmio + NV_ADMA_CTL);
- ap->private_data = NULL;
- dma_free_coherent(dev, NV_ADMA_PORT_PRIV_DMA_SZ, pp->cpb, pp->cpb_dma);
- kfree(pp);
- ata_port_stop(ap);
+ return 0;
}
+static int nv_adma_port_resume(struct ata_port *ap)
+{
+ struct nv_adma_port_priv *pp = ap->private_data;
+ void __iomem *mmio = pp->ctl_block;
+ u16 tmp;
+
+ /* set CPB block location */
+ writel(pp->cpb_dma & 0xFFFFFFFF, mmio + NV_ADMA_CPB_BASE_LOW);
+ writel((pp->cpb_dma >> 16 ) >> 16, mmio + NV_ADMA_CPB_BASE_HIGH);
+
+ /* clear any outstanding interrupt conditions */
+ writew(0xffff, mmio + NV_ADMA_STAT);
+
+ /* initialize port variables */
+ pp->flags |= NV_ADMA_PORT_REGISTER_MODE;
+
+ /* clear CPB fetch count */
+ writew(0, mmio + NV_ADMA_CPB_COUNT);
+
+ /* clear GO for register mode, enable interrupt */
+ tmp = readw(mmio + NV_ADMA_CTL);
+ writew((tmp & ~NV_ADMA_CTL_GO) | NV_ADMA_CTL_AIEN, mmio + NV_ADMA_CTL);
+
+ tmp = readw(mmio + NV_ADMA_CTL);
+ writew(tmp | NV_ADMA_CTL_CHANNEL_RESET, mmio + NV_ADMA_CTL);
+ readl( mmio + NV_ADMA_CTL ); /* flush posted write */
+ udelay(1);
+ writew(tmp & ~NV_ADMA_CTL_CHANNEL_RESET, mmio + NV_ADMA_CTL);
+ readl( mmio + NV_ADMA_CTL ); /* flush posted write */
+
+ return 0;
+}
static void nv_adma_setup_port(struct ata_probe_ent *probe_ent, unsigned int port)
{
- void __iomem *mmio = probe_ent->mmio_base;
+ void __iomem *mmio = probe_ent->iomap[NV_MMIO_BAR];
struct ata_ioports *ioport = &probe_ent->port[port];
VPRINTK("ENTER\n");
mmio += NV_ADMA_PORT + port * NV_ADMA_PORT_SIZE;
- ioport->cmd_addr = (unsigned long) mmio;
- ioport->data_addr = (unsigned long) mmio + (ATA_REG_DATA * 4);
+ ioport->cmd_addr = mmio;
+ ioport->data_addr = mmio + (ATA_REG_DATA * 4);
ioport->error_addr =
- ioport->feature_addr = (unsigned long) mmio + (ATA_REG_ERR * 4);
- ioport->nsect_addr = (unsigned long) mmio + (ATA_REG_NSECT * 4);
- ioport->lbal_addr = (unsigned long) mmio + (ATA_REG_LBAL * 4);
- ioport->lbam_addr = (unsigned long) mmio + (ATA_REG_LBAM * 4);
- ioport->lbah_addr = (unsigned long) mmio + (ATA_REG_LBAH * 4);
- ioport->device_addr = (unsigned long) mmio + (ATA_REG_DEVICE * 4);
+ ioport->feature_addr = mmio + (ATA_REG_ERR * 4);
+ ioport->nsect_addr = mmio + (ATA_REG_NSECT * 4);
+ ioport->lbal_addr = mmio + (ATA_REG_LBAL * 4);
+ ioport->lbam_addr = mmio + (ATA_REG_LBAM * 4);
+ ioport->lbah_addr = mmio + (ATA_REG_LBAH * 4);
+ ioport->device_addr = mmio + (ATA_REG_DEVICE * 4);
ioport->status_addr =
- ioport->command_addr = (unsigned long) mmio + (ATA_REG_STATUS * 4);
+ ioport->command_addr = mmio + (ATA_REG_STATUS * 4);
ioport->altstatus_addr =
- ioport->ctl_addr = (unsigned long) mmio + 0x20;
+ ioport->ctl_addr = mmio + 0x20;
}
static int nv_adma_host_init(struct ata_probe_ent *probe_ent)
@@ -1056,15 +1155,6 @@ static int nv_adma_host_init(struct ata_probe_ent *probe_ent)
for (i = 0; i < probe_ent->n_ports; i++)
nv_adma_setup_port(probe_ent, i);
- for (i = 0; i < probe_ent->n_ports; i++) {
- void __iomem *mmio = __nv_adma_ctl_block(probe_ent->mmio_base, i);
- u16 tmp;
-
- /* enable interrupt, clear reset if not already clear */
- tmp = readw(mmio + NV_ADMA_CTL);
- writew(tmp | NV_ADMA_CTL_AIEN, mmio + NV_ADMA_CTL);
- }
-
return 0;
}
@@ -1110,18 +1200,31 @@ static void nv_adma_fill_sg(struct ata_queued_cmd *qc, struct nv_adma_cpb *cpb)
cpb->next_aprd = cpu_to_le64(((u64)(pp->aprd_dma + NV_ADMA_SGTBL_SZ * qc->tag)));
}
+static int nv_adma_use_reg_mode(struct ata_queued_cmd *qc)
+{
+ struct nv_adma_port_priv *pp = qc->ap->private_data;
+
+ /* ADMA engine can only be used for non-ATAPI DMA commands,
+ or interrupt-driven no-data commands. */
+ if((pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE) ||
+ (qc->tf.flags & ATA_TFLAG_POLLING))
+ return 1;
+
+ if((qc->flags & ATA_QCFLAG_DMAMAP) ||
+ (qc->tf.protocol == ATA_PROT_NODATA))
+ return 0;
+
+ return 1;
+}
+
static void nv_adma_qc_prep(struct ata_queued_cmd *qc)
{
struct nv_adma_port_priv *pp = qc->ap->private_data;
struct nv_adma_cpb *cpb = &pp->cpb[qc->tag];
u8 ctl_flags = NV_CPB_CTL_CPB_VALID |
- NV_CPB_CTL_APRD_VALID |
NV_CPB_CTL_IEN;
- VPRINTK("qc->flags = 0x%lx\n", qc->flags);
-
- if (!(qc->flags & ATA_QCFLAG_DMAMAP) ||
- (pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE)) {
+ if (nv_adma_use_reg_mode(qc)) {
nv_adma_register_mode(qc->ap);
ata_qc_prep(qc);
return;
@@ -1137,9 +1240,15 @@ static void nv_adma_qc_prep(struct ata_queued_cmd *qc)
if (qc->tf.protocol == ATA_PROT_NCQ)
ctl_flags |= NV_CPB_CTL_QUEUE | NV_CPB_CTL_FPDMA;
+ VPRINTK("qc->flags = 0x%lx\n", qc->flags);
+
nv_adma_tf_to_cpb(&qc->tf, cpb->tf);
- nv_adma_fill_sg(qc, cpb);
+ if(qc->flags & ATA_QCFLAG_DMAMAP) {
+ nv_adma_fill_sg(qc, cpb);
+ ctl_flags |= NV_CPB_CTL_APRD_VALID;
+ } else
+ memset(&cpb->aprd[0], 0, sizeof(struct nv_adma_prd) * 5);
/* Be paranoid and don't let the device see NV_CPB_CTL_CPB_VALID until we are
finished filling in all of the contents */
@@ -1150,14 +1259,13 @@ static void nv_adma_qc_prep(struct ata_queued_cmd *qc)
static unsigned int nv_adma_qc_issue(struct ata_queued_cmd *qc)
{
struct nv_adma_port_priv *pp = qc->ap->private_data;
- void __iomem *mmio = nv_adma_ctl_block(qc->ap);
+ void __iomem *mmio = pp->ctl_block;
VPRINTK("ENTER\n");
- if (!(qc->flags & ATA_QCFLAG_DMAMAP) ||
- (pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE)) {
+ if (nv_adma_use_reg_mode(qc)) {
/* use ATA register mode */
- VPRINTK("no dmamap or ATAPI, using ATA register mode: 0x%lx\n", qc->flags);
+ VPRINTK("using ATA register mode: 0x%lx\n", qc->flags);
nv_adma_register_mode(qc->ap);
return ata_qc_issue_prot(qc);
} else
@@ -1229,7 +1337,7 @@ static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance)
irqreturn_t ret;
spin_lock(&host->lock);
- irq_stat = inb(host->ports[0]->ioaddr.scr_addr + NV_INT_STATUS);
+ irq_stat = ioread8(host->ports[0]->ioaddr.scr_addr + NV_INT_STATUS);
ret = nv_do_interrupt(host, irq_stat);
spin_unlock(&host->lock);
@@ -1243,7 +1351,7 @@ static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance)
irqreturn_t ret;
spin_lock(&host->lock);
- irq_stat = readb(host->mmio_base + NV_INT_STATUS_CK804);
+ irq_stat = readb(host->iomap[NV_MMIO_BAR] + NV_INT_STATUS_CK804);
ret = nv_do_interrupt(host, irq_stat);
spin_unlock(&host->lock);
@@ -1255,7 +1363,7 @@ static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg)
if (sc_reg > SCR_CONTROL)
return 0xffffffffU;
- return ioread32((void __iomem *)ap->ioaddr.scr_addr + (sc_reg * 4));
+ return ioread32(ap->ioaddr.scr_addr + (sc_reg * 4));
}
static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
@@ -1263,36 +1371,36 @@ static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
if (sc_reg > SCR_CONTROL)
return;
- iowrite32(val, (void __iomem *)ap->ioaddr.scr_addr + (sc_reg * 4));
+ iowrite32(val, ap->ioaddr.scr_addr + (sc_reg * 4));
}
static void nv_nf2_freeze(struct ata_port *ap)
{
- unsigned long scr_addr = ap->host->ports[0]->ioaddr.scr_addr;
+ void __iomem *scr_addr = ap->host->ports[0]->ioaddr.scr_addr;
int shift = ap->port_no * NV_INT_PORT_SHIFT;
u8 mask;
- mask = inb(scr_addr + NV_INT_ENABLE);
+ mask = ioread8(scr_addr + NV_INT_ENABLE);
mask &= ~(NV_INT_ALL << shift);
- outb(mask, scr_addr + NV_INT_ENABLE);
+ iowrite8(mask, scr_addr + NV_INT_ENABLE);
}
static void nv_nf2_thaw(struct ata_port *ap)
{
- unsigned long scr_addr = ap->host->ports[0]->ioaddr.scr_addr;
+ void __iomem *scr_addr = ap->host->ports[0]->ioaddr.scr_addr;
int shift = ap->port_no * NV_INT_PORT_SHIFT;
u8 mask;
- outb(NV_INT_ALL << shift, scr_addr + NV_INT_STATUS);
+ iowrite8(NV_INT_ALL << shift, scr_addr + NV_INT_STATUS);
- mask = inb(scr_addr + NV_INT_ENABLE);
+ mask = ioread8(scr_addr + NV_INT_ENABLE);
mask |= (NV_INT_MASK << shift);
- outb(mask, scr_addr + NV_INT_ENABLE);
+ iowrite8(mask, scr_addr + NV_INT_ENABLE);
}
static void nv_ck804_freeze(struct ata_port *ap)
{
- void __iomem *mmio_base = ap->host->mmio_base;
+ void __iomem *mmio_base = ap->host->iomap[NV_MMIO_BAR];
int shift = ap->port_no * NV_INT_PORT_SHIFT;
u8 mask;
@@ -1303,7 +1411,7 @@ static void nv_ck804_freeze(struct ata_port *ap)
static void nv_ck804_thaw(struct ata_port *ap)
{
- void __iomem *mmio_base = ap->host->mmio_base;
+ void __iomem *mmio_base = ap->host->iomap[NV_MMIO_BAR];
int shift = ap->port_no * NV_INT_PORT_SHIFT;
u8 mask;
@@ -1335,32 +1443,13 @@ static void nv_adma_error_handler(struct ata_port *ap)
{
struct nv_adma_port_priv *pp = ap->private_data;
if(!(pp->flags & NV_ADMA_PORT_REGISTER_MODE)) {
- void __iomem *mmio = nv_adma_ctl_block(ap);
+ void __iomem *mmio = pp->ctl_block;
int i;
u16 tmp;
- u32 notifier = readl(mmio + NV_ADMA_NOTIFIER);
- u32 notifier_error = readl(mmio + NV_ADMA_NOTIFIER_ERROR);
- u32 gen_ctl = readl(nv_adma_gen_block(ap) + NV_ADMA_GEN_CTL);
- u32 status = readw(mmio + NV_ADMA_STAT);
-
- ata_port_printk(ap, KERN_ERR, "EH in ADMA mode, notifier 0x%X "
- "notifier_error 0x%X gen_ctl 0x%X status 0x%X\n",
- notifier, notifier_error, gen_ctl, status);
-
- for( i=0;i<NV_ADMA_MAX_CPBS;i++) {
- struct nv_adma_cpb *cpb = &pp->cpb[i];
- if( cpb->ctl_flags || cpb->resp_flags )
- ata_port_printk(ap, KERN_ERR,
- "CPB %d: ctl_flags 0x%x, resp_flags 0x%x\n",
- i, cpb->ctl_flags, cpb->resp_flags);
- }
-
/* Push us back into port register mode for error handling. */
nv_adma_register_mode(ap);
- ata_port_printk(ap, KERN_ERR, "Resetting port\n");
-
/* Mark all of the CPBs as invalid to prevent them from being executed */
for( i=0;i<NV_ADMA_MAX_CPBS;i++)
pp->cpb[i].ctl_flags &= ~NV_CPB_CTL_CPB_VALID;
@@ -1386,10 +1475,10 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
static int printed_version = 0;
struct ata_port_info *ppi[2];
struct ata_probe_ent *probe_ent;
- int pci_dev_busy = 0;
+ struct nv_host_priv *hpriv;
int rc;
u32 bar;
- unsigned long base;
+ void __iomem *base;
unsigned long type = ent->driver_data;
int mask_set = 0;
@@ -1400,17 +1489,17 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
if (pci_resource_start(pdev, bar) == 0)
return -ENODEV;
- if ( !printed_version++)
+ if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
- rc = pci_enable_device(pdev);
+ rc = pcim_enable_device(pdev);
if (rc)
- goto err_out;
+ return rc;
rc = pci_request_regions(pdev, DRV_NAME);
if (rc) {
- pci_dev_busy = 1;
- goto err_out_disable;
+ pcim_pin_device(pdev);
+ return rc;
}
if(type >= CK804 && adma_enabled) {
@@ -1424,27 +1513,31 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
if(!mask_set) {
rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
if (rc)
- goto err_out_regions;
+ return rc;
rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
if (rc)
- goto err_out_regions;
+ return rc;
}
rc = -ENOMEM;
+ hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL);
+ if (!hpriv)
+ return -ENOMEM;
+
ppi[0] = ppi[1] = &nv_port_info[type];
probe_ent = ata_pci_init_native_mode(pdev, ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
if (!probe_ent)
- goto err_out_regions;
+ return -ENOMEM;
- probe_ent->mmio_base = pci_iomap(pdev, 5, 0);
- if (!probe_ent->mmio_base) {
- rc = -EIO;
- goto err_out_free_ent;
- }
+ if (!pcim_iomap(pdev, NV_MMIO_BAR, 0))
+ return -EIO;
+ probe_ent->iomap = pcim_iomap_table(pdev);
- base = (unsigned long)probe_ent->mmio_base;
+ probe_ent->private_data = hpriv;
+ hpriv->type = type;
+ base = probe_ent->iomap[NV_MMIO_BAR];
probe_ent->port[0].scr_addr = base + NV_PORT0_SCR_REG_OFFSET;
probe_ent->port[1].scr_addr = base + NV_PORT1_SCR_REG_OFFSET;
@@ -1462,28 +1555,72 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
if (type == ADMA) {
rc = nv_adma_host_init(probe_ent);
if (rc)
- goto err_out_iounmap;
+ return rc;
}
rc = ata_device_add(probe_ent);
if (rc != NV_PORTS)
- goto err_out_iounmap;
-
- kfree(probe_ent);
+ return -ENODEV;
+ devm_kfree(&pdev->dev, probe_ent);
return 0;
+}
-err_out_iounmap:
- pci_iounmap(pdev, probe_ent->mmio_base);
-err_out_free_ent:
- kfree(probe_ent);
-err_out_regions:
- pci_release_regions(pdev);
-err_out_disable:
- if (!pci_dev_busy)
- pci_disable_device(pdev);
-err_out:
- return rc;
+static void nv_remove_one (struct pci_dev *pdev)
+{
+ struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct nv_host_priv *hpriv = host->private_data;
+
+ ata_pci_remove_one(pdev);
+ kfree(hpriv);
+}
+
+static int nv_pci_device_resume(struct pci_dev *pdev)
+{
+ struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct nv_host_priv *hpriv = host->private_data;
+ int rc;
+
+ rc = ata_pci_device_do_resume(pdev);
+ if(rc)
+ return rc;
+
+ if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
+ if(hpriv->type >= CK804) {
+ u8 regval;
+
+ pci_read_config_byte(pdev, NV_MCP_SATA_CFG_20, &regval);
+ regval |= NV_MCP_SATA_CFG_20_SATA_SPACE_EN;
+ pci_write_config_byte(pdev, NV_MCP_SATA_CFG_20, regval);
+ }
+ if(hpriv->type == ADMA) {
+ u32 tmp32;
+ struct nv_adma_port_priv *pp;
+ /* enable/disable ADMA on the ports appropriately */
+ pci_read_config_dword(pdev, NV_MCP_SATA_CFG_20, &tmp32);
+
+ pp = host->ports[0]->private_data;
+ if(pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE)
+ tmp32 &= ~(NV_MCP_SATA_CFG_20_PORT0_EN |
+ NV_MCP_SATA_CFG_20_PORT0_PWB_EN);
+ else
+ tmp32 |= (NV_MCP_SATA_CFG_20_PORT0_EN |
+ NV_MCP_SATA_CFG_20_PORT0_PWB_EN);
+ pp = host->ports[1]->private_data;
+ if(pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE)
+ tmp32 &= ~(NV_MCP_SATA_CFG_20_PORT1_EN |
+ NV_MCP_SATA_CFG_20_PORT1_PWB_EN);
+ else
+ tmp32 |= (NV_MCP_SATA_CFG_20_PORT1_EN |
+ NV_MCP_SATA_CFG_20_PORT1_PWB_EN);
+
+ pci_write_config_dword(pdev, NV_MCP_SATA_CFG_20, tmp32);
+ }
+ }
+
+ ata_host_resume(host);
+
+ return 0;
}
static void nv_ck804_host_stop(struct ata_host *host)
@@ -1495,25 +1632,13 @@ static void nv_ck804_host_stop(struct ata_host *host)
pci_read_config_byte(pdev, NV_MCP_SATA_CFG_20, &regval);
regval &= ~NV_MCP_SATA_CFG_20_SATA_SPACE_EN;
pci_write_config_byte(pdev, NV_MCP_SATA_CFG_20, regval);
-
- ata_pci_host_stop(host);
}
static void nv_adma_host_stop(struct ata_host *host)
{
struct pci_dev *pdev = to_pci_dev(host->dev);
- int i;
u32 tmp32;
- for (i = 0; i < host->n_ports; i++) {
- void __iomem *mmio = __nv_adma_ctl_block(host->mmio_base, i);
- u16 tmp;
-
- /* disable interrupt */
- tmp = readw(mmio + NV_ADMA_CTL);
- writew(tmp & ~NV_ADMA_CTL_AIEN, mmio + NV_ADMA_CTL);
- }
-
/* disable ADMA on the ports */
pci_read_config_dword(pdev, NV_MCP_SATA_CFG_20, &tmp32);
tmp32 &= ~(NV_MCP_SATA_CFG_20_PORT0_EN |
diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c
index f055874a6ec..cf9ed8c3930 100644
--- a/drivers/ata/sata_promise.c
+++ b/drivers/ata/sata_promise.c
@@ -37,12 +37,11 @@
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
-#include <linux/sched.h>
#include <linux/device.h>
+#include <scsi/scsi.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_cmnd.h>
#include <linux/libata.h>
-#include <asm/io.h>
#include "sata_promise.h"
#define DRV_NAME "sata_promise"
@@ -50,6 +49,17 @@
enum {
+ PDC_MMIO_BAR = 3,
+
+ /* register offsets */
+ PDC_FEATURE = 0x04, /* Feature/Error reg (per port) */
+ PDC_SECTOR_COUNT = 0x08, /* Sector count reg (per port) */
+ PDC_SECTOR_NUMBER = 0x0C, /* Sector number reg (per port) */
+ PDC_CYLINDER_LOW = 0x10, /* Cylinder low reg (per port) */
+ PDC_CYLINDER_HIGH = 0x14, /* Cylinder high reg (per port) */
+ PDC_DEVICE = 0x18, /* Device/Head reg (per port) */
+ PDC_COMMAND = 0x1C, /* Command/status reg (per port) */
+ PDC_ALTSTATUS = 0x38, /* Alternate-status/device-control reg (per port) */
PDC_PKT_SUBMIT = 0x40, /* Command packet pointer addr */
PDC_INT_SEQMASK = 0x40, /* Mask of asserted SEQ INTs */
PDC_FLASH_CTL = 0x44, /* Flash control register */
@@ -71,13 +81,23 @@ enum {
PDC_HAS_PATA = (1 << 1), /* PDC20375/20575 has PATA */
+ /* Sequence counter control registers bit definitions */
+ PDC_SEQCNTRL_INT_MASK = (1 << 5), /* Sequence Interrupt Mask */
+
+ /* Feature register values */
+ PDC_FEATURE_ATAPI_PIO = 0x00, /* ATAPI data xfer by PIO */
+ PDC_FEATURE_ATAPI_DMA = 0x01, /* ATAPI data xfer by DMA */
+
+ /* Device/Head register values */
+ PDC_DEVICE_SATA = 0xE0, /* Device/Head value for SATA devices */
+
/* PDC_CTLSTAT bit definitions */
PDC_DMA_ENABLE = (1 << 7),
PDC_IRQ_DISABLE = (1 << 10),
PDC_RESET = (1 << 11), /* HDMA reset */
PDC_COMMON_FLAGS = ATA_FLAG_NO_LEGACY |
- ATA_FLAG_MMIO | ATA_FLAG_NO_ATAPI |
+ ATA_FLAG_MMIO |
ATA_FLAG_PIO_POLLING,
/* hp->flags bits */
@@ -92,22 +112,21 @@ struct pdc_port_priv {
struct pdc_host_priv {
unsigned long flags;
+ unsigned long port_flags[ATA_MAX_PORTS];
};
static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg);
static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
static irqreturn_t pdc_interrupt (int irq, void *dev_instance);
-static void pdc_eng_timeout(struct ata_port *ap);
static int pdc_port_start(struct ata_port *ap);
-static void pdc_port_stop(struct ata_port *ap);
-static void pdc_pata_phy_reset(struct ata_port *ap);
static void pdc_qc_prep(struct ata_queued_cmd *qc);
static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
+static int pdc_check_atapi_dma(struct ata_queued_cmd *qc);
+static int pdc_old_check_atapi_dma(struct ata_queued_cmd *qc);
static void pdc_irq_clear(struct ata_port *ap);
static unsigned int pdc_qc_issue_prot(struct ata_queued_cmd *qc);
-static void pdc_host_stop(struct ata_host *host);
static void pdc_freeze(struct ata_port *ap);
static void pdc_thaw(struct ata_port *ap);
static void pdc_error_handler(struct ata_port *ap);
@@ -139,6 +158,7 @@ static const struct ata_port_operations pdc_sata_ops = {
.check_status = ata_check_status,
.exec_command = pdc_exec_command_mmio,
.dev_select = ata_std_dev_select,
+ .check_atapi_dma = pdc_check_atapi_dma,
.qc_prep = pdc_qc_prep,
.qc_issue = pdc_qc_issue_prot,
@@ -146,48 +166,76 @@ static const struct ata_port_operations pdc_sata_ops = {
.thaw = pdc_thaw,
.error_handler = pdc_error_handler,
.post_internal_cmd = pdc_post_internal_cmd,
- .data_xfer = ata_mmio_data_xfer,
+ .data_xfer = ata_data_xfer,
.irq_handler = pdc_interrupt,
.irq_clear = pdc_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.scr_read = pdc_sata_scr_read,
.scr_write = pdc_sata_scr_write,
.port_start = pdc_port_start,
- .port_stop = pdc_port_stop,
- .host_stop = pdc_host_stop,
};
-static const struct ata_port_operations pdc_pata_ops = {
+/* First-generation chips need a more restrictive ->check_atapi_dma op */
+static const struct ata_port_operations pdc_old_sata_ops = {
.port_disable = ata_port_disable,
.tf_load = pdc_tf_load_mmio,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
.exec_command = pdc_exec_command_mmio,
.dev_select = ata_std_dev_select,
+ .check_atapi_dma = pdc_old_check_atapi_dma,
- .phy_reset = pdc_pata_phy_reset,
+ .qc_prep = pdc_qc_prep,
+ .qc_issue = pdc_qc_issue_prot,
+ .freeze = pdc_freeze,
+ .thaw = pdc_thaw,
+ .error_handler = pdc_error_handler,
+ .post_internal_cmd = pdc_post_internal_cmd,
+ .data_xfer = ata_data_xfer,
+ .irq_handler = pdc_interrupt,
+ .irq_clear = pdc_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
+
+ .scr_read = pdc_sata_scr_read,
+ .scr_write = pdc_sata_scr_write,
+ .port_start = pdc_port_start,
+};
+
+static const struct ata_port_operations pdc_pata_ops = {
+ .port_disable = ata_port_disable,
+ .tf_load = pdc_tf_load_mmio,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = pdc_exec_command_mmio,
+ .dev_select = ata_std_dev_select,
+ .check_atapi_dma = pdc_check_atapi_dma,
.qc_prep = pdc_qc_prep,
.qc_issue = pdc_qc_issue_prot,
- .data_xfer = ata_mmio_data_xfer,
- .eng_timeout = pdc_eng_timeout,
+ .freeze = pdc_freeze,
+ .thaw = pdc_thaw,
+ .error_handler = pdc_error_handler,
+ .data_xfer = ata_data_xfer,
.irq_handler = pdc_interrupt,
.irq_clear = pdc_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = pdc_port_start,
- .port_stop = pdc_port_stop,
- .host_stop = pdc_host_stop,
};
static const struct ata_port_info pdc_port_info[] = {
/* board_2037x */
{
.sht = &pdc_ata_sht,
- .flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA,
+ .flags = PDC_COMMON_FLAGS,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x7f, /* udma0-6 ; FIXME */
- .port_ops = &pdc_sata_ops,
+ .port_ops = &pdc_old_sata_ops,
},
/* board_20319 */
@@ -197,13 +245,13 @@ static const struct ata_port_info pdc_port_info[] = {
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x7f, /* udma0-6 ; FIXME */
- .port_ops = &pdc_sata_ops,
+ .port_ops = &pdc_old_sata_ops,
},
/* board_20619 */
{
.sht = &pdc_ata_sht,
- .flags = PDC_COMMON_FLAGS | ATA_FLAG_SRST | ATA_FLAG_SLAVE_POSS,
+ .flags = PDC_COMMON_FLAGS | ATA_FLAG_SLAVE_POSS,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x7f, /* udma0-6 ; FIXME */
@@ -213,7 +261,7 @@ static const struct ata_port_info pdc_port_info[] = {
/* board_2057x */
{
.sht = &pdc_ata_sht,
- .flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA,
+ .flags = PDC_COMMON_FLAGS,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x7f, /* udma0-6 ; FIXME */
@@ -271,21 +319,22 @@ static int pdc_port_start(struct ata_port *ap)
struct pdc_port_priv *pp;
int rc;
+ /* fix up port flags and cable type for SATA+PATA chips */
+ ap->flags |= hp->port_flags[ap->port_no];
+ if (ap->flags & ATA_FLAG_SATA)
+ ap->cbl = ATA_CBL_SATA;
+
rc = ata_port_start(ap);
if (rc)
return rc;
- pp = kzalloc(sizeof(*pp), GFP_KERNEL);
- if (!pp) {
- rc = -ENOMEM;
- goto err_out;
- }
+ pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
+ if (!pp)
+ return -ENOMEM;
- pp->pkt = dma_alloc_coherent(dev, 128, &pp->pkt_dma, GFP_KERNEL);
- if (!pp->pkt) {
- rc = -ENOMEM;
- goto err_out_kfree;
- }
+ pp->pkt = dmam_alloc_coherent(dev, 128, &pp->pkt_dma, GFP_KERNEL);
+ if (!pp->pkt)
+ return -ENOMEM;
ap->private_data = pp;
@@ -300,40 +349,11 @@ static int pdc_port_start(struct ata_port *ap)
}
return 0;
-
-err_out_kfree:
- kfree(pp);
-err_out:
- ata_port_stop(ap);
- return rc;
}
-
-static void pdc_port_stop(struct ata_port *ap)
-{
- struct device *dev = ap->host->dev;
- struct pdc_port_priv *pp = ap->private_data;
-
- ap->private_data = NULL;
- dma_free_coherent(dev, 128, pp->pkt, pp->pkt_dma);
- kfree(pp);
- ata_port_stop(ap);
-}
-
-
-static void pdc_host_stop(struct ata_host *host)
-{
- struct pdc_host_priv *hp = host->private_data;
-
- ata_pci_host_stop(host);
-
- kfree(hp);
-}
-
-
static void pdc_reset_port(struct ata_port *ap)
{
- void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr + PDC_CTLSTAT;
+ void __iomem *mmio = ap->ioaddr.cmd_addr + PDC_CTLSTAT;
unsigned int i;
u32 tmp;
@@ -367,28 +387,104 @@ static void pdc_pata_cbl_detect(struct ata_port *ap)
ap->cbl = ATA_CBL_PATA80;
}
-static void pdc_pata_phy_reset(struct ata_port *ap)
-{
- pdc_pata_cbl_detect(ap);
- pdc_reset_port(ap);
- ata_port_probe(ap);
- ata_bus_reset(ap);
-}
-
static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
{
- if (sc_reg > SCR_CONTROL)
+ if (sc_reg > SCR_CONTROL || ap->cbl != ATA_CBL_SATA)
return 0xffffffffU;
- return readl((void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
+ return readl(ap->ioaddr.scr_addr + (sc_reg * 4));
}
static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg,
u32 val)
{
- if (sc_reg > SCR_CONTROL)
+ if (sc_reg > SCR_CONTROL || ap->cbl != ATA_CBL_SATA)
return;
- writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
+ writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+}
+
+static void pdc_atapi_pkt(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ dma_addr_t sg_table = ap->prd_dma;
+ unsigned int cdb_len = qc->dev->cdb_len;
+ u8 *cdb = qc->cdb;
+ struct pdc_port_priv *pp = ap->private_data;
+ u8 *buf = pp->pkt;
+ u32 *buf32 = (u32 *) buf;
+ unsigned int dev_sel, feature, nbytes;
+
+ /* set control bits (byte 0), zero delay seq id (byte 3),
+ * and seq id (byte 2)
+ */
+ switch (qc->tf.protocol) {
+ case ATA_PROT_ATAPI_DMA:
+ if (!(qc->tf.flags & ATA_TFLAG_WRITE))
+ buf32[0] = cpu_to_le32(PDC_PKT_READ);
+ else
+ buf32[0] = 0;
+ break;
+ case ATA_PROT_ATAPI_NODATA:
+ buf32[0] = cpu_to_le32(PDC_PKT_NODATA);
+ break;
+ default:
+ BUG();
+ break;
+ }
+ buf32[1] = cpu_to_le32(sg_table); /* S/G table addr */
+ buf32[2] = 0; /* no next-packet */
+
+ /* select drive */
+ if (sata_scr_valid(ap)) {
+ dev_sel = PDC_DEVICE_SATA;
+ } else {
+ dev_sel = ATA_DEVICE_OBS;
+ if (qc->dev->devno != 0)
+ dev_sel |= ATA_DEV1;
+ }
+ buf[12] = (1 << 5) | ATA_REG_DEVICE;
+ buf[13] = dev_sel;
+ buf[14] = (1 << 5) | ATA_REG_DEVICE | PDC_PKT_CLEAR_BSY;
+ buf[15] = dev_sel; /* once more, waiting for BSY to clear */
+
+ buf[16] = (1 << 5) | ATA_REG_NSECT;
+ buf[17] = 0x00;
+ buf[18] = (1 << 5) | ATA_REG_LBAL;
+ buf[19] = 0x00;
+
+ /* set feature and byte counter registers */
+ if (qc->tf.protocol != ATA_PROT_ATAPI_DMA) {
+ feature = PDC_FEATURE_ATAPI_PIO;
+ /* set byte counter register to real transfer byte count */
+ nbytes = qc->nbytes;
+ if (nbytes > 0xffff)
+ nbytes = 0xffff;
+ } else {
+ feature = PDC_FEATURE_ATAPI_DMA;
+ /* set byte counter register to 0 */
+ nbytes = 0;
+ }
+ buf[20] = (1 << 5) | ATA_REG_FEATURE;
+ buf[21] = feature;
+ buf[22] = (1 << 5) | ATA_REG_BYTEL;
+ buf[23] = nbytes & 0xFF;
+ buf[24] = (1 << 5) | ATA_REG_BYTEH;
+ buf[25] = (nbytes >> 8) & 0xFF;
+
+ /* send ATAPI packet command 0xA0 */
+ buf[26] = (1 << 5) | ATA_REG_CMD;
+ buf[27] = ATA_CMD_PACKET;
+
+ /* select drive and check DRQ */
+ buf[28] = (1 << 5) | ATA_REG_DEVICE | PDC_PKT_WAIT_DRDY;
+ buf[29] = dev_sel;
+
+ /* we can represent cdb lengths 2/4/6/8/10/12/14/16 */
+ BUG_ON(cdb_len & ~0x1E);
+
+ /* append the CDB as the final part */
+ buf[30] = (((cdb_len >> 1) & 7) << 5) | ATA_REG_DATA | PDC_LAST_REG;
+ memcpy(buf+31, cdb, cdb_len);
}
static void pdc_qc_prep(struct ata_queued_cmd *qc)
@@ -415,6 +511,17 @@ static void pdc_qc_prep(struct ata_queued_cmd *qc)
pdc_pkt_footer(&qc->tf, pp->pkt, i);
break;
+ case ATA_PROT_ATAPI:
+ ata_qc_prep(qc);
+ break;
+
+ case ATA_PROT_ATAPI_DMA:
+ ata_qc_prep(qc);
+ /*FALLTHROUGH*/
+ case ATA_PROT_ATAPI_NODATA:
+ pdc_atapi_pkt(qc);
+ break;
+
default:
break;
}
@@ -447,6 +554,13 @@ static void pdc_thaw(struct ata_port *ap)
readl(mmio + PDC_CTLSTAT); /* flush */
}
+static int pdc_pre_reset(struct ata_port *ap)
+{
+ if (!sata_scr_valid(ap))
+ pdc_pata_cbl_detect(ap);
+ return ata_std_prereset(ap);
+}
+
static void pdc_error_handler(struct ata_port *ap)
{
ata_reset_fn_t hardreset;
@@ -459,7 +573,7 @@ static void pdc_error_handler(struct ata_port *ap)
hardreset = sata_std_hardreset;
/* perform recovery */
- ata_do_eh(ap, ata_std_prereset, ata_std_softreset, hardreset,
+ ata_do_eh(ap, pdc_pre_reset, ata_std_softreset, hardreset,
ata_std_postreset);
}
@@ -475,49 +589,12 @@ static void pdc_post_internal_cmd(struct ata_queued_cmd *qc)
pdc_reset_port(ap);
}
-static void pdc_eng_timeout(struct ata_port *ap)
-{
- struct ata_host *host = ap->host;
- u8 drv_stat;
- struct ata_queued_cmd *qc;
- unsigned long flags;
-
- DPRINTK("ENTER\n");
-
- spin_lock_irqsave(&host->lock, flags);
-
- qc = ata_qc_from_tag(ap, ap->active_tag);
-
- switch (qc->tf.protocol) {
- case ATA_PROT_DMA:
- case ATA_PROT_NODATA:
- ata_port_printk(ap, KERN_ERR, "command timeout\n");
- drv_stat = ata_wait_idle(ap);
- qc->err_mask |= __ac_err_mask(drv_stat);
- break;
-
- default:
- drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
-
- ata_port_printk(ap, KERN_ERR,
- "unknown timeout, cmd 0x%x stat 0x%x\n",
- qc->tf.command, drv_stat);
-
- qc->err_mask |= ac_err_mask(drv_stat);
- break;
- }
-
- spin_unlock_irqrestore(&host->lock, flags);
- ata_eh_qc_complete(qc);
- DPRINTK("EXIT\n");
-}
-
static inline unsigned int pdc_host_intr( struct ata_port *ap,
struct ata_queued_cmd *qc)
{
unsigned int handled = 0;
u32 tmp;
- void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr + PDC_GLOBAL_CTL;
+ void __iomem *mmio = ap->ioaddr.cmd_addr + PDC_GLOBAL_CTL;
tmp = readl(mmio);
if (tmp & PDC_ERR_MASK) {
@@ -528,6 +605,8 @@ static inline unsigned int pdc_host_intr( struct ata_port *ap,
switch (qc->tf.protocol) {
case ATA_PROT_DMA:
case ATA_PROT_NODATA:
+ case ATA_PROT_ATAPI_DMA:
+ case ATA_PROT_ATAPI_NODATA:
qc->err_mask |= ac_err_mask(ata_wait_idle(ap));
ata_qc_complete(qc);
handled = 1;
@@ -544,7 +623,7 @@ static inline unsigned int pdc_host_intr( struct ata_port *ap,
static void pdc_irq_clear(struct ata_port *ap)
{
struct ata_host *host = ap->host;
- void __iomem *mmio = host->mmio_base;
+ void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
readl(mmio + PDC_INT_SEQMASK);
}
@@ -560,12 +639,12 @@ static irqreturn_t pdc_interrupt (int irq, void *dev_instance)
VPRINTK("ENTER\n");
- if (!host || !host->mmio_base) {
+ if (!host || !host->iomap[PDC_MMIO_BAR]) {
VPRINTK("QUICK EXIT\n");
return IRQ_NONE;
}
- mmio_base = host->mmio_base;
+ mmio_base = host->iomap[PDC_MMIO_BAR];
/* reading should also clear interrupts */
mask = readl(mmio_base + PDC_INT_SEQMASK);
@@ -610,32 +689,34 @@ static inline void pdc_packet_start(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
struct pdc_port_priv *pp = ap->private_data;
+ void __iomem *mmio = ap->host->iomap[PDC_MMIO_BAR];
unsigned int port_no = ap->port_no;
u8 seq = (u8) (port_no + 1);
VPRINTK("ENTER, ap %p\n", ap);
- writel(0x00000001, ap->host->mmio_base + (seq * 4));
- readl(ap->host->mmio_base + (seq * 4)); /* flush */
+ writel(0x00000001, mmio + (seq * 4));
+ readl(mmio + (seq * 4)); /* flush */
pp->pkt[2] = seq;
wmb(); /* flush PRD, pkt writes */
- writel(pp->pkt_dma, (void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
- readl((void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); /* flush */
+ writel(pp->pkt_dma, ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
+ readl(ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); /* flush */
}
static unsigned int pdc_qc_issue_prot(struct ata_queued_cmd *qc)
{
switch (qc->tf.protocol) {
+ case ATA_PROT_ATAPI_NODATA:
+ if (qc->dev->flags & ATA_DFLAG_CDB_INTR)
+ break;
+ /*FALLTHROUGH*/
+ case ATA_PROT_ATAPI_DMA:
case ATA_PROT_DMA:
case ATA_PROT_NODATA:
pdc_packet_start(qc);
return 0;
- case ATA_PROT_ATAPI_DMA:
- BUG();
- break;
-
default:
break;
}
@@ -658,8 +739,44 @@ static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile
ata_exec_command(ap, tf);
}
+static int pdc_check_atapi_dma(struct ata_queued_cmd *qc)
+{
+ u8 *scsicmd = qc->scsicmd->cmnd;
+ int pio = 1; /* atapi dma off by default */
+
+ /* Whitelist commands that may use DMA. */
+ switch (scsicmd[0]) {
+ case WRITE_12:
+ case WRITE_10:
+ case WRITE_6:
+ case READ_12:
+ case READ_10:
+ case READ_6:
+ case 0xad: /* READ_DVD_STRUCTURE */
+ case 0xbe: /* READ_CD */
+ pio = 0;
+ }
+ /* -45150 (FFFF4FA2) to -1 (FFFFFFFF) shall use PIO mode */
+ if (scsicmd[0] == WRITE_10) {
+ unsigned int lba;
+ lba = (scsicmd[2] << 24) | (scsicmd[3] << 16) | (scsicmd[4] << 8) | scsicmd[5];
+ if (lba >= 0xFFFF4FA2)
+ pio = 1;
+ }
+ return pio;
+}
+
+static int pdc_old_check_atapi_dma(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+
+ /* First generation chips cannot use ATAPI DMA on SATA ports */
+ if (sata_scr_valid(ap))
+ return 1;
+ return pdc_check_atapi_dma(qc);
+}
-static void pdc_ata_setup_port(struct ata_ioports *port, unsigned long base)
+static void pdc_ata_setup_port(struct ata_ioports *port, void __iomem *base)
{
port->cmd_addr = base;
port->data_addr = base;
@@ -679,7 +796,7 @@ static void pdc_ata_setup_port(struct ata_ioports *port, unsigned long base)
static void pdc_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
{
- void __iomem *mmio = pe->mmio_base;
+ void __iomem *mmio = pe->iomap[PDC_MMIO_BAR];
struct pdc_host_priv *hp = pe->private_data;
int hotplug_offset;
u32 tmp;
@@ -733,55 +850,43 @@ static void pdc_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version;
- struct ata_probe_ent *probe_ent = NULL;
+ struct ata_probe_ent *probe_ent;
struct pdc_host_priv *hp;
- unsigned long base;
- void __iomem *mmio_base;
+ void __iomem *base;
unsigned int board_idx = (unsigned int) ent->driver_data;
- int pci_dev_busy = 0;
int rc;
+ u8 tmp;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
- rc = pci_enable_device(pdev);
+ rc = pcim_enable_device(pdev);
if (rc)
return rc;
- rc = pci_request_regions(pdev, DRV_NAME);
- if (rc) {
- pci_dev_busy = 1;
- goto err_out;
- }
+ rc = pcim_iomap_regions(pdev, 1 << PDC_MMIO_BAR, DRV_NAME);
+ if (rc == -EBUSY)
+ pcim_pin_device(pdev);
+ if (rc)
+ return rc;
rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
if (rc)
- goto err_out_regions;
+ return rc;
rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
if (rc)
- goto err_out_regions;
+ return rc;
- probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL);
- if (probe_ent == NULL) {
- rc = -ENOMEM;
- goto err_out_regions;
- }
+ probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL);
+ if (probe_ent == NULL)
+ return -ENOMEM;
probe_ent->dev = pci_dev_to_dev(pdev);
INIT_LIST_HEAD(&probe_ent->node);
- mmio_base = pci_iomap(pdev, 3, 0);
- if (mmio_base == NULL) {
- rc = -ENOMEM;
- goto err_out_free_ent;
- }
- base = (unsigned long) mmio_base;
-
- hp = kzalloc(sizeof(*hp), GFP_KERNEL);
- if (hp == NULL) {
- rc = -ENOMEM;
- goto err_out_free_ent;
- }
+ hp = devm_kzalloc(&pdev->dev, sizeof(*hp), GFP_KERNEL);
+ if (hp == NULL)
+ return -ENOMEM;
probe_ent->private_data = hp;
@@ -794,7 +899,9 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
probe_ent->irq = pdev->irq;
probe_ent->irq_flags = IRQF_SHARED;
- probe_ent->mmio_base = mmio_base;
+ probe_ent->iomap = pcim_iomap_table(pdev);
+
+ base = probe_ent->iomap[PDC_MMIO_BAR];
pdc_ata_setup_port(&probe_ent->port[0], base + 0x200);
pdc_ata_setup_port(&probe_ent->port[1], base + 0x280);
@@ -820,7 +927,17 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
hp->flags |= PDC_FLAG_GEN_II;
/* Fall through */
case board_2037x:
- probe_ent->n_ports = 2;
+ /* TX2plus boards also have a PATA port */
+ tmp = readb(base + PDC_FLASH_CTL+1);
+ if (!(tmp & 0x80)) {
+ probe_ent->n_ports = 3;
+ pdc_ata_setup_port(&probe_ent->port[2], base + 0x300);
+ hp->port_flags[2] = ATA_FLAG_SLAVE_POSS;
+ printk(KERN_INFO DRV_NAME " PATA port found\n");
+ } else
+ probe_ent->n_ports = 2;
+ hp->port_flags[0] = ATA_FLAG_SATA;
+ hp->port_flags[1] = ATA_FLAG_SATA;
break;
case board_20619:
probe_ent->n_ports = 4;
@@ -841,22 +958,11 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
/* initialize adapter */
pdc_host_init(board_idx, probe_ent);
- /* FIXME: Need any other frees than hp? */
if (!ata_device_add(probe_ent))
- kfree(hp);
-
- kfree(probe_ent);
+ return -ENODEV;
+ devm_kfree(&pdev->dev, probe_ent);
return 0;
-
-err_out_free_ent:
- kfree(probe_ent);
-err_out_regions:
- pci_release_regions(pdev);
-err_out:
- if (!pci_dev_busy)
- pci_disable_device(pdev);
- return rc;
}
diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c
index 710909df4ea..6097d8f2a0c 100644
--- a/drivers/ata/sata_qstor.c
+++ b/drivers/ata/sata_qstor.c
@@ -34,16 +34,16 @@
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
-#include <linux/sched.h>
#include <linux/device.h>
#include <scsi/scsi_host.h>
-#include <asm/io.h>
#include <linux/libata.h>
#define DRV_NAME "sata_qstor"
#define DRV_VERSION "0.06"
enum {
+ QS_MMIO_BAR = 4,
+
QS_PORTS = 4,
QS_MAX_PRD = LIBATA_MAX_PRD,
QS_CPB_ORDER = 6,
@@ -117,7 +117,6 @@ static int qs_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *en
static irqreturn_t qs_intr (int irq, void *dev_instance);
static int qs_port_start(struct ata_port *ap);
static void qs_host_stop(struct ata_host *host);
-static void qs_port_stop(struct ata_port *ap);
static void qs_phy_reset(struct ata_port *ap);
static void qs_qc_prep(struct ata_queued_cmd *qc);
static unsigned int qs_qc_issue(struct ata_queued_cmd *qc);
@@ -157,14 +156,15 @@ static const struct ata_port_operations qs_ata_ops = {
.phy_reset = qs_phy_reset,
.qc_prep = qs_qc_prep,
.qc_issue = qs_qc_issue,
- .data_xfer = ata_mmio_data_xfer,
+ .data_xfer = ata_data_xfer,
.eng_timeout = qs_eng_timeout,
.irq_handler = qs_intr,
.irq_clear = qs_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.scr_read = qs_scr_read,
.scr_write = qs_scr_write,
.port_start = qs_port_start,
- .port_stop = qs_port_stop,
.host_stop = qs_host_stop,
.bmdma_stop = qs_bmdma_stop,
.bmdma_status = qs_bmdma_status,
@@ -197,6 +197,11 @@ static struct pci_driver qs_ata_pci_driver = {
.remove = ata_pci_remove_one,
};
+static void __iomem *qs_mmio_base(struct ata_host *host)
+{
+ return host->iomap[QS_MMIO_BAR];
+}
+
static int qs_check_atapi_dma(struct ata_queued_cmd *qc)
{
return 1; /* ATAPI DMA not supported */
@@ -219,7 +224,7 @@ static void qs_irq_clear(struct ata_port *ap)
static inline void qs_enter_reg_mode(struct ata_port *ap)
{
- u8 __iomem *chan = ap->host->mmio_base + (ap->port_no * 0x4000);
+ u8 __iomem *chan = qs_mmio_base(ap->host) + (ap->port_no * 0x4000);
writeb(QS_CTR0_REG, chan + QS_CCT_CTR0);
readb(chan + QS_CCT_CTR0); /* flush */
@@ -227,7 +232,7 @@ static inline void qs_enter_reg_mode(struct ata_port *ap)
static inline void qs_reset_channel_logic(struct ata_port *ap)
{
- u8 __iomem *chan = ap->host->mmio_base + (ap->port_no * 0x4000);
+ u8 __iomem *chan = qs_mmio_base(ap->host) + (ap->port_no * 0x4000);
writeb(QS_CTR1_RCHN, chan + QS_CCT_CTR1);
readb(chan + QS_CCT_CTR0); /* flush */
@@ -257,14 +262,14 @@ static u32 qs_scr_read (struct ata_port *ap, unsigned int sc_reg)
{
if (sc_reg > SCR_CONTROL)
return ~0U;
- return readl((void __iomem *)(ap->ioaddr.scr_addr + (sc_reg * 8)));
+ return readl(ap->ioaddr.scr_addr + (sc_reg * 8));
}
static void qs_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
{
if (sc_reg > SCR_CONTROL)
return;
- writel(val, (void __iomem *)(ap->ioaddr.scr_addr + (sc_reg * 8)));
+ writel(val, ap->ioaddr.scr_addr + (sc_reg * 8));
}
static unsigned int qs_fill_sg(struct ata_queued_cmd *qc)
@@ -325,7 +330,7 @@ static void qs_qc_prep(struct ata_queued_cmd *qc)
/* host control block (HCB) */
buf[ 0] = QS_HCB_HDR;
buf[ 1] = hflags;
- *(__le32 *)(&buf[ 4]) = cpu_to_le32(qc->nsect * ATA_SECT_SIZE);
+ *(__le32 *)(&buf[ 4]) = cpu_to_le32(qc->nbytes);
*(__le32 *)(&buf[ 8]) = cpu_to_le32(nelem);
addr = ((u64)pp->pkt_dma) + QS_CPB_BYTES;
*(__le64 *)(&buf[16]) = cpu_to_le64(addr);
@@ -341,7 +346,7 @@ static void qs_qc_prep(struct ata_queued_cmd *qc)
static inline void qs_packet_start(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
- u8 __iomem *chan = ap->host->mmio_base + (ap->port_no * 0x4000);
+ u8 __iomem *chan = qs_mmio_base(ap->host) + (ap->port_no * 0x4000);
VPRINTK("ENTER, ap %p\n", ap);
@@ -378,7 +383,7 @@ static inline unsigned int qs_intr_pkt(struct ata_host *host)
{
unsigned int handled = 0;
u8 sFFE;
- u8 __iomem *mmio_base = host->mmio_base;
+ u8 __iomem *mmio_base = qs_mmio_base(host);
do {
u32 sff0 = readl(mmio_base + QS_HST_SFF);
@@ -470,7 +475,7 @@ static irqreturn_t qs_intr(int irq, void *dev_instance)
return IRQ_RETVAL(handled);
}
-static void qs_ata_setup_port(struct ata_ioports *port, unsigned long base)
+static void qs_ata_setup_port(struct ata_ioports *port, void __iomem *base)
{
port->cmd_addr =
port->data_addr = base + 0x400;
@@ -492,7 +497,7 @@ static int qs_port_start(struct ata_port *ap)
{
struct device *dev = ap->host->dev;
struct qs_port_priv *pp;
- void __iomem *mmio_base = ap->host->mmio_base;
+ void __iomem *mmio_base = qs_mmio_base(ap->host);
void __iomem *chan = mmio_base + (ap->port_no * 0x4000);
u64 addr;
int rc;
@@ -501,17 +506,13 @@ static int qs_port_start(struct ata_port *ap)
if (rc)
return rc;
qs_enter_reg_mode(ap);
- pp = kzalloc(sizeof(*pp), GFP_KERNEL);
- if (!pp) {
- rc = -ENOMEM;
- goto err_out;
- }
- pp->pkt = dma_alloc_coherent(dev, QS_PKT_BYTES, &pp->pkt_dma,
- GFP_KERNEL);
- if (!pp->pkt) {
- rc = -ENOMEM;
- goto err_out_kfree;
- }
+ pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
+ if (!pp)
+ return -ENOMEM;
+ pp->pkt = dmam_alloc_coherent(dev, QS_PKT_BYTES, &pp->pkt_dma,
+ GFP_KERNEL);
+ if (!pp->pkt)
+ return -ENOMEM;
memset(pp->pkt, 0, QS_PKT_BYTES);
ap->private_data = pp;
@@ -519,43 +520,19 @@ static int qs_port_start(struct ata_port *ap)
writel((u32) addr, chan + QS_CCF_CPBA);
writel((u32)(addr >> 32), chan + QS_CCF_CPBA + 4);
return 0;
-
-err_out_kfree:
- kfree(pp);
-err_out:
- ata_port_stop(ap);
- return rc;
-}
-
-static void qs_port_stop(struct ata_port *ap)
-{
- struct device *dev = ap->host->dev;
- struct qs_port_priv *pp = ap->private_data;
-
- if (pp != NULL) {
- ap->private_data = NULL;
- if (pp->pkt != NULL)
- dma_free_coherent(dev, QS_PKT_BYTES, pp->pkt,
- pp->pkt_dma);
- kfree(pp);
- }
- ata_port_stop(ap);
}
static void qs_host_stop(struct ata_host *host)
{
- void __iomem *mmio_base = host->mmio_base;
- struct pci_dev *pdev = to_pci_dev(host->dev);
+ void __iomem *mmio_base = qs_mmio_base(host);
writeb(0, mmio_base + QS_HCT_CTRL); /* disable host interrupts */
writeb(QS_CNFG3_GSRST, mmio_base + QS_HCF_CNFG3); /* global reset */
-
- pci_iounmap(pdev, mmio_base);
}
static void qs_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
{
- void __iomem *mmio_base = pe->mmio_base;
+ void __iomem *mmio_base = pe->iomap[QS_MMIO_BAR];
unsigned int port_no;
writeb(0, mmio_base + QS_HCT_CTRL); /* disable host interrupts */
@@ -630,44 +607,34 @@ static int qs_ata_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
static int printed_version;
- struct ata_probe_ent *probe_ent = NULL;
- void __iomem *mmio_base;
+ struct ata_probe_ent *probe_ent;
+ void __iomem * const *iomap;
unsigned int board_idx = (unsigned int) ent->driver_data;
int rc, port_no;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
- rc = pci_enable_device(pdev);
+ rc = pcim_enable_device(pdev);
if (rc)
return rc;
- rc = pci_request_regions(pdev, DRV_NAME);
- if (rc)
- goto err_out;
-
- if ((pci_resource_flags(pdev, 4) & IORESOURCE_MEM) == 0) {
- rc = -ENODEV;
- goto err_out_regions;
- }
+ if ((pci_resource_flags(pdev, QS_MMIO_BAR) & IORESOURCE_MEM) == 0)
+ return -ENODEV;
- mmio_base = pci_iomap(pdev, 4, 0);
- if (mmio_base == NULL) {
- rc = -ENOMEM;
- goto err_out_regions;
- }
+ rc = pcim_iomap_regions(pdev, 1 << QS_MMIO_BAR, DRV_NAME);
+ if (rc)
+ return rc;
+ iomap = pcim_iomap_table(pdev);
- rc = qs_set_dma_masks(pdev, mmio_base);
+ rc = qs_set_dma_masks(pdev, iomap[QS_MMIO_BAR]);
if (rc)
- goto err_out_iounmap;
+ return rc;
- probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
- if (probe_ent == NULL) {
- rc = -ENOMEM;
- goto err_out_iounmap;
- }
+ probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL);
+ if (probe_ent == NULL)
+ return -ENOMEM;
- memset(probe_ent, 0, sizeof(*probe_ent));
probe_ent->dev = pci_dev_to_dev(pdev);
INIT_LIST_HEAD(&probe_ent->node);
@@ -680,12 +647,12 @@ static int qs_ata_init_one(struct pci_dev *pdev,
probe_ent->irq = pdev->irq;
probe_ent->irq_flags = IRQF_SHARED;
- probe_ent->mmio_base = mmio_base;
+ probe_ent->iomap = iomap;
probe_ent->n_ports = QS_PORTS;
for (port_no = 0; port_no < probe_ent->n_ports; ++port_no) {
- unsigned long chan = (unsigned long)mmio_base +
- (port_no * 0x4000);
+ void __iomem *chan =
+ probe_ent->iomap[QS_MMIO_BAR] + (port_no * 0x4000);
qs_ata_setup_port(&probe_ent->port[port_no], chan);
}
@@ -694,19 +661,11 @@ static int qs_ata_init_one(struct pci_dev *pdev,
/* initialize adapter */
qs_host_init(board_idx, probe_ent);
- rc = ata_device_add(probe_ent);
- kfree(probe_ent);
- if (rc != QS_PORTS)
- goto err_out_iounmap;
- return 0;
+ if (ata_device_add(probe_ent) != QS_PORTS)
+ return -EIO;
-err_out_iounmap:
- pci_iounmap(pdev, mmio_base);
-err_out_regions:
- pci_release_regions(pdev);
-err_out:
- pci_disable_device(pdev);
- return rc;
+ devm_kfree(&pdev->dev, probe_ent);
+ return 0;
}
static int __init qs_ata_init(void)
diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c
index 7808d0369d9..dca3d3749f0 100644
--- a/drivers/ata/sata_sil.c
+++ b/drivers/ata/sata_sil.c
@@ -49,6 +49,8 @@
#define DRV_VERSION "2.0"
enum {
+ SIL_MMIO_BAR = 5,
+
/*
* host flags
*/
@@ -200,18 +202,18 @@ static const struct ata_port_operations sil_ops = {
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_mmio_data_xfer,
+ .data_xfer = ata_data_xfer,
.freeze = sil_freeze,
.thaw = sil_thaw,
.error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
.irq_handler = sil_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.scr_read = sil_scr_read,
.scr_write = sil_scr_write,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_pci_host_stop,
};
static const struct ata_port_info sil_port_info[] = {
@@ -297,7 +299,8 @@ static void sil_post_set_mode (struct ata_port *ap)
{
struct ata_host *host = ap->host;
struct ata_device *dev;
- void __iomem *addr = host->mmio_base + sil_port[ap->port_no].xfer_mode;
+ void __iomem *mmio_base = host->iomap[SIL_MMIO_BAR];
+ void __iomem *addr = mmio_base + sil_port[ap->port_no].xfer_mode;
u32 tmp, dev_mode[2];
unsigned int i;
@@ -320,9 +323,9 @@ static void sil_post_set_mode (struct ata_port *ap)
readl(addr); /* flush */
}
-static inline unsigned long sil_scr_addr(struct ata_port *ap, unsigned int sc_reg)
+static inline void __iomem *sil_scr_addr(struct ata_port *ap, unsigned int sc_reg)
{
- unsigned long offset = ap->ioaddr.scr_addr;
+ void __iomem *offset = ap->ioaddr.scr_addr;
switch (sc_reg) {
case SCR_STATUS:
@@ -341,7 +344,7 @@ static inline unsigned long sil_scr_addr(struct ata_port *ap, unsigned int sc_re
static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg)
{
- void __iomem *mmio = (void __iomem *) sil_scr_addr(ap, sc_reg);
+ void __iomem *mmio = sil_scr_addr(ap, sc_reg);
if (mmio)
return readl(mmio);
return 0xffffffffU;
@@ -349,7 +352,7 @@ static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg)
static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
{
- void __iomem *mmio = (void __iomem *) sil_scr_addr(ap, sc_reg);
+ void __iomem *mmio = sil_scr_addr(ap, sc_reg);
if (mmio)
writel(val, mmio);
}
@@ -444,7 +447,7 @@ static void sil_host_intr(struct ata_port *ap, u32 bmdma2)
static irqreturn_t sil_interrupt(int irq, void *dev_instance)
{
struct ata_host *host = dev_instance;
- void __iomem *mmio_base = host->mmio_base;
+ void __iomem *mmio_base = host->iomap[SIL_MMIO_BAR];
int handled = 0;
int i;
@@ -476,7 +479,7 @@ static irqreturn_t sil_interrupt(int irq, void *dev_instance)
static void sil_freeze(struct ata_port *ap)
{
- void __iomem *mmio_base = ap->host->mmio_base;
+ void __iomem *mmio_base = ap->host->iomap[SIL_MMIO_BAR];
u32 tmp;
/* global IRQ mask doesn't block SATA IRQ, turn off explicitly */
@@ -491,7 +494,7 @@ static void sil_freeze(struct ata_port *ap)
static void sil_thaw(struct ata_port *ap)
{
- void __iomem *mmio_base = ap->host->mmio_base;
+ void __iomem *mmio_base = ap->host->iomap[SIL_MMIO_BAR];
u32 tmp;
/* clear IRQ */
@@ -541,9 +544,9 @@ static void sil_dev_config(struct ata_port *ap, struct ata_device *dev)
{
int print_info = ap->eh_context.i.flags & ATA_EHI_PRINTINFO;
unsigned int n, quirks = 0;
- unsigned char model_num[41];
+ unsigned char model_num[ATA_ID_PROD_LEN + 1];
- ata_id_c_string(dev->id, model_num, ATA_ID_PROD_OFS, sizeof(model_num));
+ ata_id_c_string(dev->id, model_num, ATA_ID_PROD, sizeof(model_num));
for (n = 0; sil_blacklist[n].product; n++)
if (!strcmp(sil_blacklist[n].product, model_num)) {
@@ -621,38 +624,35 @@ static void sil_init_controller(struct pci_dev *pdev,
static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version;
- struct ata_probe_ent *probe_ent = NULL;
- unsigned long base;
+ struct device *dev = &pdev->dev;
+ struct ata_probe_ent *probe_ent;
void __iomem *mmio_base;
int rc;
unsigned int i;
- int pci_dev_busy = 0;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
- rc = pci_enable_device(pdev);
+ rc = pcim_enable_device(pdev);
if (rc)
return rc;
- rc = pci_request_regions(pdev, DRV_NAME);
- if (rc) {
- pci_dev_busy = 1;
- goto err_out;
- }
+ rc = pcim_iomap_regions(pdev, 1 << SIL_MMIO_BAR, DRV_NAME);
+ if (rc == -EBUSY)
+ pcim_pin_device(pdev);
+ if (rc)
+ return rc;
rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
if (rc)
- goto err_out_regions;
+ return rc;
rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
if (rc)
- goto err_out_regions;
+ return rc;
- probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL);
- if (probe_ent == NULL) {
- rc = -ENOMEM;
- goto err_out_regions;
- }
+ probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL);
+ if (probe_ent == NULL)
+ return -ENOMEM;
INIT_LIST_HEAD(&probe_ent->node);
probe_ent->dev = pci_dev_to_dev(pdev);
@@ -666,22 +666,16 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
probe_ent->irq_flags = IRQF_SHARED;
probe_ent->port_flags = sil_port_info[ent->driver_data].flags;
- mmio_base = pci_iomap(pdev, 5, 0);
- if (mmio_base == NULL) {
- rc = -ENOMEM;
- goto err_out_free_ent;
- }
-
- probe_ent->mmio_base = mmio_base;
+ probe_ent->iomap = pcim_iomap_table(pdev);
- base = (unsigned long) mmio_base;
+ mmio_base = probe_ent->iomap[SIL_MMIO_BAR];
for (i = 0; i < probe_ent->n_ports; i++) {
- probe_ent->port[i].cmd_addr = base + sil_port[i].tf;
+ probe_ent->port[i].cmd_addr = mmio_base + sil_port[i].tf;
probe_ent->port[i].altstatus_addr =
- probe_ent->port[i].ctl_addr = base + sil_port[i].ctl;
- probe_ent->port[i].bmdma_addr = base + sil_port[i].bmdma;
- probe_ent->port[i].scr_addr = base + sil_port[i].scr;
+ probe_ent->port[i].ctl_addr = mmio_base + sil_port[i].ctl;
+ probe_ent->port[i].bmdma_addr = mmio_base + sil_port[i].bmdma;
+ probe_ent->port[i].scr_addr = mmio_base + sil_port[i].scr;
ata_std_ports(&probe_ent->port[i]);
}
@@ -690,30 +684,25 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
pci_set_master(pdev);
- /* FIXME: check ata_device_add return value */
- ata_device_add(probe_ent);
- kfree(probe_ent);
+ if (!ata_device_add(probe_ent))
+ return -ENODEV;
+ devm_kfree(dev, probe_ent);
return 0;
-
-err_out_free_ent:
- kfree(probe_ent);
-err_out_regions:
- pci_release_regions(pdev);
-err_out:
- if (!pci_dev_busy)
- pci_disable_device(pdev);
- return rc;
}
#ifdef CONFIG_PM
static int sil_pci_device_resume(struct pci_dev *pdev)
{
struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ int rc;
+
+ rc = ata_pci_device_do_resume(pdev);
+ if (rc)
+ return rc;
- ata_pci_device_do_resume(pdev);
sil_init_controller(pdev, host->n_ports, host->ports[0]->flags,
- host->mmio_base);
+ host->iomap[SIL_MMIO_BAR]);
ata_host_resume(host);
return 0;
diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c
index 5aa288d2fb8..e65e8d55da3 100644
--- a/drivers/ata/sata_sil24.c
+++ b/drivers/ata/sata_sil24.c
@@ -28,7 +28,6 @@
#include <scsi/scsi_host.h>
#include <scsi/scsi_cmnd.h>
#include <linux/libata.h>
-#include <asm/io.h>
#define DRV_NAME "sata_sil24"
#define DRV_VERSION "0.3"
@@ -61,6 +60,9 @@ struct sil24_port_multiplier {
};
enum {
+ SIL24_HOST_BAR = 0,
+ SIL24_PORT_BAR = 2,
+
/*
* Global controller registers (128 bytes @ BAR0)
*/
@@ -321,12 +323,6 @@ struct sil24_port_priv {
struct ata_taskfile tf; /* Cached taskfile registers */
};
-/* ap->host->private_data */
-struct sil24_host_priv {
- void __iomem *host_base; /* global controller control (128 bytes @BAR0) */
- void __iomem *port_base; /* port registers (4 * 8192 bytes @BAR2) */
-};
-
static void sil24_dev_config(struct ata_port *ap, struct ata_device *dev);
static u8 sil24_check_status(struct ata_port *ap);
static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg);
@@ -341,8 +337,6 @@ static void sil24_thaw(struct ata_port *ap);
static void sil24_error_handler(struct ata_port *ap);
static void sil24_post_internal_cmd(struct ata_queued_cmd *qc);
static int sil24_port_start(struct ata_port *ap);
-static void sil24_port_stop(struct ata_port *ap);
-static void sil24_host_stop(struct ata_host *host);
static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
#ifdef CONFIG_PM
static int sil24_pci_device_resume(struct pci_dev *pdev);
@@ -362,7 +356,7 @@ static struct pci_driver sil24_pci_driver = {
.name = DRV_NAME,
.id_table = sil24_pci_tbl,
.probe = sil24_init_one,
- .remove = ata_pci_remove_one, /* safe? */
+ .remove = ata_pci_remove_one,
#ifdef CONFIG_PM
.suspend = ata_pci_device_suspend,
.resume = sil24_pci_device_resume,
@@ -406,6 +400,8 @@ static const struct ata_port_operations sil24_ops = {
.irq_handler = sil24_interrupt,
.irq_clear = sil24_irq_clear,
+ .irq_on = ata_dummy_irq_on,
+ .irq_ack = ata_dummy_irq_ack,
.scr_read = sil24_scr_read,
.scr_write = sil24_scr_write,
@@ -416,8 +412,6 @@ static const struct ata_port_operations sil24_ops = {
.post_internal_cmd = sil24_post_internal_cmd,
.port_start = sil24_port_start,
- .port_stop = sil24_port_stop,
- .host_stop = sil24_host_stop,
};
/*
@@ -467,7 +461,7 @@ static int sil24_tag(int tag)
static void sil24_dev_config(struct ata_port *ap, struct ata_device *dev)
{
- void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
+ void __iomem *port = ap->ioaddr.cmd_addr;
if (dev->cdb_len == 16)
writel(PORT_CS_CDB16, port + PORT_CTRL_STAT);
@@ -478,7 +472,7 @@ static void sil24_dev_config(struct ata_port *ap, struct ata_device *dev)
static inline void sil24_update_tf(struct ata_port *ap)
{
struct sil24_port_priv *pp = ap->private_data;
- void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
+ void __iomem *port = ap->ioaddr.cmd_addr;
struct sil24_prb __iomem *prb = port;
u8 fis[6 * 4];
@@ -501,7 +495,7 @@ static int sil24_scr_map[] = {
static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg)
{
- void __iomem *scr_addr = (void __iomem *)ap->ioaddr.scr_addr;
+ void __iomem *scr_addr = ap->ioaddr.scr_addr;
if (sc_reg < ARRAY_SIZE(sil24_scr_map)) {
void __iomem *addr;
addr = scr_addr + sil24_scr_map[sc_reg] * 4;
@@ -512,7 +506,7 @@ static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg)
static void sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val)
{
- void __iomem *scr_addr = (void __iomem *)ap->ioaddr.scr_addr;
+ void __iomem *scr_addr = ap->ioaddr.scr_addr;
if (sc_reg < ARRAY_SIZE(sil24_scr_map)) {
void __iomem *addr;
addr = scr_addr + sil24_scr_map[sc_reg] * 4;
@@ -528,7 +522,7 @@ static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
static int sil24_init_port(struct ata_port *ap)
{
- void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
+ void __iomem *port = ap->ioaddr.cmd_addr;
u32 tmp;
writel(PORT_CS_INIT, port + PORT_CTRL_STAT);
@@ -544,7 +538,7 @@ static int sil24_init_port(struct ata_port *ap)
static int sil24_softreset(struct ata_port *ap, unsigned int *class)
{
- void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
+ void __iomem *port = ap->ioaddr.cmd_addr;
struct sil24_port_priv *pp = ap->private_data;
struct sil24_prb *prb = &pp->cmd_block[0].ata.prb;
dma_addr_t paddr = pp->cmd_block_dma;
@@ -604,7 +598,7 @@ static int sil24_softreset(struct ata_port *ap, unsigned int *class)
static int sil24_hardreset(struct ata_port *ap, unsigned int *class)
{
- void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
+ void __iomem *port = ap->ioaddr.cmd_addr;
const char *reason;
int tout_msec, rc;
u32 tmp;
@@ -721,7 +715,7 @@ static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
struct sil24_port_priv *pp = ap->private_data;
- void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
+ void __iomem *port = ap->ioaddr.cmd_addr;
unsigned int tag = sil24_tag(qc->tag);
dma_addr_t paddr;
void __iomem *activate;
@@ -742,7 +736,7 @@ static void sil24_irq_clear(struct ata_port *ap)
static void sil24_freeze(struct ata_port *ap)
{
- void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
+ void __iomem *port = ap->ioaddr.cmd_addr;
/* Port-wide IRQ mask in HOST_CTRL doesn't really work, clear
* PORT_IRQ_ENABLE instead.
@@ -752,7 +746,7 @@ static void sil24_freeze(struct ata_port *ap)
static void sil24_thaw(struct ata_port *ap)
{
- void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
+ void __iomem *port = ap->ioaddr.cmd_addr;
u32 tmp;
/* clear IRQ */
@@ -765,7 +759,7 @@ static void sil24_thaw(struct ata_port *ap)
static void sil24_error_intr(struct ata_port *ap)
{
- void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
+ void __iomem *port = ap->ioaddr.cmd_addr;
struct ata_eh_info *ehi = &ap->eh_info;
int freeze = 0;
u32 irq_stat;
@@ -843,7 +837,7 @@ static void sil24_finish_qc(struct ata_queued_cmd *qc)
static inline void sil24_host_intr(struct ata_port *ap)
{
- void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
+ void __iomem *port = ap->ioaddr.cmd_addr;
u32 slot_stat, qc_active;
int rc;
@@ -878,12 +872,12 @@ static inline void sil24_host_intr(struct ata_port *ap)
static irqreturn_t sil24_interrupt(int irq, void *dev_instance)
{
struct ata_host *host = dev_instance;
- struct sil24_host_priv *hpriv = host->private_data;
+ void __iomem *host_base = host->iomap[SIL24_HOST_BAR];
unsigned handled = 0;
u32 status;
int i;
- status = readl(hpriv->host_base + HOST_IRQ_STAT);
+ status = readl(host_base + HOST_IRQ_STAT);
if (status == 0xffffffff) {
printk(KERN_ERR DRV_NAME ": IRQ status == 0xffffffff, "
@@ -938,13 +932,6 @@ static void sil24_post_internal_cmd(struct ata_queued_cmd *qc)
sil24_init_port(ap);
}
-static inline void sil24_cblk_free(struct sil24_port_priv *pp, struct device *dev)
-{
- const size_t cb_size = sizeof(*pp->cmd_block) * SIL24_MAX_CMDS;
-
- dma_free_coherent(dev, cb_size, pp->cmd_block, pp->cmd_block_dma);
-}
-
static int sil24_port_start(struct ata_port *ap)
{
struct device *dev = ap->host->dev;
@@ -952,22 +939,22 @@ static int sil24_port_start(struct ata_port *ap)
union sil24_cmd_block *cb;
size_t cb_size = sizeof(*cb) * SIL24_MAX_CMDS;
dma_addr_t cb_dma;
- int rc = -ENOMEM;
+ int rc;
- pp = kzalloc(sizeof(*pp), GFP_KERNEL);
+ pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
if (!pp)
- goto err_out;
+ return -ENOMEM;
pp->tf.command = ATA_DRDY;
- cb = dma_alloc_coherent(dev, cb_size, &cb_dma, GFP_KERNEL);
+ cb = dmam_alloc_coherent(dev, cb_size, &cb_dma, GFP_KERNEL);
if (!cb)
- goto err_out_pp;
+ return -ENOMEM;
memset(cb, 0, cb_size);
rc = ata_pad_alloc(ap, dev);
if (rc)
- goto err_out_pad;
+ return rc;
pp->cmd_block = cb;
pp->cmd_block_dma = cb_dma;
@@ -975,33 +962,6 @@ static int sil24_port_start(struct ata_port *ap)
ap->private_data = pp;
return 0;
-
-err_out_pad:
- sil24_cblk_free(pp, dev);
-err_out_pp:
- kfree(pp);
-err_out:
- return rc;
-}
-
-static void sil24_port_stop(struct ata_port *ap)
-{
- struct device *dev = ap->host->dev;
- struct sil24_port_priv *pp = ap->private_data;
-
- sil24_cblk_free(pp, dev);
- ata_pad_free(ap, dev);
- kfree(pp);
-}
-
-static void sil24_host_stop(struct ata_host *host)
-{
- struct sil24_host_priv *hpriv = host->private_data;
- struct pci_dev *pdev = to_pci_dev(host->dev);
-
- pci_iounmap(pdev, hpriv->host_base);
- pci_iounmap(pdev, hpriv->port_base);
- kfree(hpriv);
}
static void sil24_init_controller(struct pci_dev *pdev, int n_ports,
@@ -1066,43 +1026,32 @@ static void sil24_init_controller(struct pci_dev *pdev, int n_ports,
static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version = 0;
+ struct device *dev = &pdev->dev;
unsigned int board_id = (unsigned int)ent->driver_data;
struct ata_port_info *pinfo = &sil24_port_info[board_id];
- struct ata_probe_ent *probe_ent = NULL;
- struct sil24_host_priv *hpriv = NULL;
- void __iomem *host_base = NULL;
- void __iomem *port_base = NULL;
+ struct ata_probe_ent *probe_ent;
+ void __iomem *host_base;
+ void __iomem *port_base;
int i, rc;
u32 tmp;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
- rc = pci_enable_device(pdev);
+ rc = pcim_enable_device(pdev);
if (rc)
return rc;
- rc = pci_request_regions(pdev, DRV_NAME);
+ rc = pcim_iomap_regions(pdev,
+ (1 << SIL24_HOST_BAR) | (1 << SIL24_PORT_BAR),
+ DRV_NAME);
if (rc)
- goto out_disable;
-
- rc = -ENOMEM;
- /* map mmio registers */
- host_base = pci_iomap(pdev, 0, 0);
- if (!host_base)
- goto out_free;
- port_base = pci_iomap(pdev, 2, 0);
- if (!port_base)
- goto out_free;
-
- /* allocate & init probe_ent and hpriv */
- probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL);
- if (!probe_ent)
- goto out_free;
+ return rc;
- hpriv = kzalloc(sizeof(*hpriv), GFP_KERNEL);
- if (!hpriv)
- goto out_free;
+ /* allocate & init probe_ent */
+ probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL);
+ if (!probe_ent)
+ return -ENOMEM;
probe_ent->dev = pci_dev_to_dev(pdev);
INIT_LIST_HEAD(&probe_ent->node);
@@ -1117,10 +1066,10 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
probe_ent->irq = pdev->irq;
probe_ent->irq_flags = IRQF_SHARED;
- probe_ent->private_data = hpriv;
+ probe_ent->iomap = pcim_iomap_table(pdev);
- hpriv->host_base = host_base;
- hpriv->port_base = port_base;
+ host_base = probe_ent->iomap[SIL24_HOST_BAR];
+ port_base = probe_ent->iomap[SIL24_PORT_BAR];
/*
* Configure the device
@@ -1132,7 +1081,7 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (rc) {
dev_printk(KERN_ERR, &pdev->dev,
"64-bit DMA enable failed\n");
- goto out_free;
+ return rc;
}
}
} else {
@@ -1140,13 +1089,13 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (rc) {
dev_printk(KERN_ERR, &pdev->dev,
"32-bit DMA enable failed\n");
- goto out_free;
+ return rc;
}
rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
if (rc) {
dev_printk(KERN_ERR, &pdev->dev,
"32-bit consistent DMA enable failed\n");
- goto out_free;
+ return rc;
}
}
@@ -1162,11 +1111,10 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
}
for (i = 0; i < probe_ent->n_ports; i++) {
- unsigned long portu =
- (unsigned long)port_base + i * PORT_REGS_SIZE;
+ void __iomem *port = port_base + i * PORT_REGS_SIZE;
- probe_ent->port[i].cmd_addr = portu;
- probe_ent->port[i].scr_addr = portu + PORT_SCONTROL;
+ probe_ent->port[i].cmd_addr = port;
+ probe_ent->port[i].scr_addr = port + PORT_SCONTROL;
ata_std_ports(&probe_ent->port[i]);
}
@@ -1176,38 +1124,30 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
pci_set_master(pdev);
- /* FIXME: check ata_device_add return value */
- ata_device_add(probe_ent);
+ if (!ata_device_add(probe_ent))
+ return -ENODEV;
- kfree(probe_ent);
+ devm_kfree(dev, probe_ent);
return 0;
-
- out_free:
- if (host_base)
- pci_iounmap(pdev, host_base);
- if (port_base)
- pci_iounmap(pdev, port_base);
- kfree(probe_ent);
- kfree(hpriv);
- pci_release_regions(pdev);
- out_disable:
- pci_disable_device(pdev);
- return rc;
}
#ifdef CONFIG_PM
static int sil24_pci_device_resume(struct pci_dev *pdev)
{
struct ata_host *host = dev_get_drvdata(&pdev->dev);
- struct sil24_host_priv *hpriv = host->private_data;
+ void __iomem *host_base = host->iomap[SIL24_HOST_BAR];
+ void __iomem *port_base = host->iomap[SIL24_PORT_BAR];
+ int rc;
- ata_pci_device_do_resume(pdev);
+ rc = ata_pci_device_do_resume(pdev);
+ if (rc)
+ return rc;
if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND)
- writel(HOST_CTRL_GLOBAL_RST, hpriv->host_base + HOST_CTRL);
+ writel(HOST_CTRL_GLOBAL_RST, host_base + HOST_CTRL);
sil24_init_controller(pdev, host->n_ports, host->ports[0]->flags,
- hpriv->host_base, hpriv->port_base);
+ host_base, port_base);
ata_host_resume(host);
diff --git a/drivers/ata/sata_sis.c b/drivers/ata/sata_sis.c
index 9c25a1e9173..49c9e2bd706 100644
--- a/drivers/ata/sata_sis.c
+++ b/drivers/ata/sata_sis.c
@@ -40,9 +40,11 @@
#include <linux/device.h>
#include <scsi/scsi_host.h>
#include <linux/libata.h>
+#include "libata.h"
+#undef DRV_NAME /* already defined in libata.h, for libata-core */
#define DRV_NAME "sata_sis"
-#define DRV_VERSION "0.6"
+#define DRV_VERSION "0.7"
enum {
sis_180 = 0,
@@ -67,9 +69,12 @@ static u32 sis_scr_read (struct ata_port *ap, unsigned int sc_reg);
static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
static const struct pci_device_id sis_pci_tbl[] = {
- { PCI_VDEVICE(SI, 0x180), sis_180 },
- { PCI_VDEVICE(SI, 0x181), sis_180 },
- { PCI_VDEVICE(SI, 0x182), sis_180 },
+ { PCI_VDEVICE(SI, 0x0180), sis_180 }, /* SiS 964/180 */
+ { PCI_VDEVICE(SI, 0x0181), sis_180 }, /* SiS 964/180 */
+ { PCI_VDEVICE(SI, 0x0182), sis_180 }, /* SiS 965/965L */
+ { PCI_VDEVICE(SI, 0x0183), sis_180 }, /* SiS 965/965L */
+ { PCI_VDEVICE(SI, 0x1182), sis_180 }, /* SiS 966/966L */
+ { PCI_VDEVICE(SI, 0x1183), sis_180 }, /* SiS 966/966L */
{ } /* terminate list */
};
@@ -112,18 +117,18 @@ static const struct ata_port_operations sis_ops = {
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
.error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.scr_read = sis_scr_read,
.scr_write = sis_scr_write,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop,
};
static struct ata_port_info sis_port_info = {
@@ -135,31 +140,42 @@ static struct ata_port_info sis_port_info = {
.port_ops = &sis_ops,
};
-
MODULE_AUTHOR("Uwe Koziolek");
MODULE_DESCRIPTION("low-level driver for Silicon Integratad Systems SATA controller");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, sis_pci_tbl);
MODULE_VERSION(DRV_VERSION);
-static unsigned int get_scr_cfg_addr(unsigned int port_no, unsigned int sc_reg, int device)
+static unsigned int get_scr_cfg_addr(struct ata_port *ap, unsigned int sc_reg)
{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
unsigned int addr = SIS_SCR_BASE + (4 * sc_reg);
+ u8 pmr;
- if (port_no) {
- if (device == 0x182)
- addr += SIS182_SATA1_OFS;
- else
- addr += SIS180_SATA1_OFS;
+ if (ap->port_no) {
+ switch (pdev->device) {
+ case 0x0180:
+ case 0x0181:
+ pci_read_config_byte(pdev, SIS_PMR, &pmr);
+ if ((pmr & SIS_PMR_COMBINED) == 0)
+ addr += SIS180_SATA1_OFS;
+ break;
+
+ case 0x0182:
+ case 0x0183:
+ case 0x1182:
+ case 0x1183:
+ addr += SIS182_SATA1_OFS;
+ break;
+ }
}
-
return addr;
}
static u32 sis_scr_cfg_read (struct ata_port *ap, unsigned int sc_reg)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- unsigned int cfg_addr = get_scr_cfg_addr(ap->port_no, sc_reg, pdev->device);
+ unsigned int cfg_addr = get_scr_cfg_addr(ap, sc_reg);
u32 val, val2 = 0;
u8 pmr;
@@ -170,26 +186,28 @@ static u32 sis_scr_cfg_read (struct ata_port *ap, unsigned int sc_reg)
pci_read_config_dword(pdev, cfg_addr, &val);
- if ((pdev->device == 0x182) || (pmr & SIS_PMR_COMBINED))
+ if ((pdev->device == 0x0182) || (pdev->device == 0x0183) || (pdev->device == 0x1182) ||
+ (pdev->device == 0x1183) || (pmr & SIS_PMR_COMBINED))
pci_read_config_dword(pdev, cfg_addr+0x10, &val2);
return (val|val2) & 0xfffffffb; /* avoid problems with powerdowned ports */
}
-static void sis_scr_cfg_write (struct ata_port *ap, unsigned int scr, u32 val)
+static void sis_scr_cfg_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- unsigned int cfg_addr = get_scr_cfg_addr(ap->port_no, scr, pdev->device);
+ unsigned int cfg_addr = get_scr_cfg_addr(ap, sc_reg);
u8 pmr;
- if (scr == SCR_ERROR) /* doesn't exist in PCI cfg space */
+ if (sc_reg == SCR_ERROR) /* doesn't exist in PCI cfg space */
return;
pci_read_config_byte(pdev, SIS_PMR, &pmr);
pci_write_config_dword(pdev, cfg_addr, val);
- if ((pdev->device == 0x182) || (pmr & SIS_PMR_COMBINED))
+ if ((pdev->device == 0x0182) || (pdev->device == 0x0183) || (pdev->device == 0x1182) ||
+ (pdev->device == 0x1183) || (pmr & SIS_PMR_COMBINED))
pci_write_config_dword(pdev, cfg_addr+0x10, val);
}
@@ -207,10 +225,11 @@ static u32 sis_scr_read (struct ata_port *ap, unsigned int sc_reg)
pci_read_config_byte(pdev, SIS_PMR, &pmr);
- val = inl(ap->ioaddr.scr_addr + (sc_reg * 4));
+ val = ioread32(ap->ioaddr.scr_addr + (sc_reg * 4));
- if ((pdev->device == 0x182) || (pmr & SIS_PMR_COMBINED))
- val2 = inl(ap->ioaddr.scr_addr + (sc_reg * 4) + 0x10);
+ if ((pdev->device == 0x0182) || (pdev->device == 0x0183) || (pdev->device == 0x1182) ||
+ (pdev->device == 0x1183) || (pmr & SIS_PMR_COMBINED))
+ val2 = ioread32(ap->ioaddr.scr_addr + (sc_reg * 4) + 0x10);
return (val | val2) & 0xfffffffb;
}
@@ -228,9 +247,10 @@ static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
if (ap->flags & SIS_FLAG_CFGSCR)
sis_scr_cfg_write(ap, sc_reg, val);
else {
- outl(val, ap->ioaddr.scr_addr + (sc_reg * 4));
- if ((pdev->device == 0x182) || (pmr & SIS_PMR_COMBINED))
- outl(val, ap->ioaddr.scr_addr + (sc_reg * 4)+0x10);
+ iowrite32(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+ if ((pdev->device == 0x0182) || (pdev->device == 0x0183) || (pdev->device == 0x1182) ||
+ (pdev->device == 0x1183) || (pmr & SIS_PMR_COMBINED))
+ iowrite32(val, ap->ioaddr.scr_addr + (sc_reg * 4)+0x10);
}
}
@@ -241,29 +261,28 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
int rc;
u32 genctl, val;
struct ata_port_info pi = sis_port_info, *ppi[2] = { &pi, &pi };
- int pci_dev_busy = 0;
u8 pmr;
- u8 port2_start;
+ u8 port2_start = 0x20;
if (!printed_version++)
dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
- rc = pci_enable_device(pdev);
+ rc = pcim_enable_device(pdev);
if (rc)
return rc;
rc = pci_request_regions(pdev, DRV_NAME);
if (rc) {
- pci_dev_busy = 1;
- goto err_out;
+ pcim_pin_device(pdev);
+ return rc;
}
rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
if (rc)
- goto err_out_regions;
+ return rc;
rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
if (rc)
- goto err_out_regions;
+ return rc;
/* check and see if the SCRs are in IO space or PCI cfg space */
pci_read_config_dword(pdev, SIS_GENCTL, &genctl);
@@ -282,60 +301,79 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
}
pci_read_config_byte(pdev, SIS_PMR, &pmr);
- if (ent->device != 0x182) {
+ switch (ent->device) {
+ case 0x0180:
+ case 0x0181:
+
+ /* The PATA-handling is provided by pata_sis */
+ switch (pmr & 0x30) {
+ case 0x10:
+ ppi[1] = &sis_info133;
+ break;
+
+ case 0x30:
+ ppi[0] = &sis_info133;
+ break;
+ }
if ((pmr & SIS_PMR_COMBINED) == 0) {
dev_printk(KERN_INFO, &pdev->dev,
"Detected SiS 180/181/964 chipset in SATA mode\n");
port2_start = 64;
- }
- else {
+ } else {
dev_printk(KERN_INFO, &pdev->dev,
"Detected SiS 180/181 chipset in combined mode\n");
port2_start=0;
pi.flags |= ATA_FLAG_SLAVE_POSS;
}
- }
- else {
+ break;
+
+ case 0x0182:
+ case 0x0183:
pci_read_config_dword ( pdev, 0x6C, &val);
if (val & (1L << 31)) {
dev_printk(KERN_INFO, &pdev->dev, "Detected SiS 182/965 chipset\n");
pi.flags |= ATA_FLAG_SLAVE_POSS;
- }
- else
+ } else {
dev_printk(KERN_INFO, &pdev->dev, "Detected SiS 182/965L chipset\n");
- port2_start = 0x20;
+ }
+ break;
+
+ case 0x1182:
+ case 0x1183:
+ pci_read_config_dword(pdev, 0x64, &val);
+ if (val & 0x10000000) {
+ dev_printk(KERN_INFO, &pdev->dev, "Detected SiS 1182/1183/966L SATA controller\n");
+ } else {
+ dev_printk(KERN_INFO, &pdev->dev, "Detected SiS 1182/1183/966 SATA controller\n");
+ pi.flags |= ATA_FLAG_SLAVE_POSS;
+ }
+ break;
}
probe_ent = ata_pci_init_native_mode(pdev, ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
- if (!probe_ent) {
- rc = -ENOMEM;
- goto err_out_regions;
- }
+ if (!probe_ent)
+ return -ENOMEM;
if (!(probe_ent->port_flags & SIS_FLAG_CFGSCR)) {
- probe_ent->port[0].scr_addr =
- pci_resource_start(pdev, SIS_SCR_PCI_BAR);
- probe_ent->port[1].scr_addr =
- pci_resource_start(pdev, SIS_SCR_PCI_BAR) + port2_start;
+ void *mmio;
+
+ mmio = pcim_iomap(pdev, SIS_SCR_PCI_BAR, 0);
+ if (!mmio)
+ return -ENOMEM;
+
+ probe_ent->port[0].scr_addr = mmio;
+ probe_ent->port[1].scr_addr = mmio + port2_start;
}
pci_set_master(pdev);
pci_intx(pdev, 1);
- /* FIXME: check ata_device_add return value */
- ata_device_add(probe_ent);
- kfree(probe_ent);
+ if (!ata_device_add(probe_ent))
+ return -EIO;
+ devm_kfree(&pdev->dev, probe_ent);
return 0;
-err_out_regions:
- pci_release_regions(pdev);
-
-err_out:
- if (!pci_dev_busy)
- pci_disable_device(pdev);
- return rc;
-
}
static int __init sis_init(void)
@@ -350,4 +388,3 @@ static void __exit sis_exit(void)
module_init(sis_init);
module_exit(sis_exit);
-
diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c
index 46d8a94669b..4e428999420 100644
--- a/drivers/ata/sata_svw.c
+++ b/drivers/ata/sata_svw.c
@@ -116,7 +116,7 @@ static u32 k2_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
{
if (sc_reg > SCR_CONTROL)
return 0xffffffffU;
- return readl((void *) ap->ioaddr.scr_addr + (sc_reg * 4));
+ return readl((void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
}
@@ -125,7 +125,7 @@ static void k2_sata_scr_write (struct ata_port *ap, unsigned int sc_reg,
{
if (sc_reg > SCR_CONTROL)
return;
- writel(val, (void *) ap->ioaddr.scr_addr + (sc_reg * 4));
+ writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
}
@@ -135,31 +135,31 @@ static void k2_sata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
if (tf->ctl != ap->last_ctl) {
- writeb(tf->ctl, (void __iomem *) ioaddr->ctl_addr);
+ writeb(tf->ctl, ioaddr->ctl_addr);
ap->last_ctl = tf->ctl;
ata_wait_idle(ap);
}
if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
writew(tf->feature | (((u16)tf->hob_feature) << 8),
- (void __iomem *) ioaddr->feature_addr);
+ ioaddr->feature_addr);
writew(tf->nsect | (((u16)tf->hob_nsect) << 8),
- (void __iomem *) ioaddr->nsect_addr);
+ ioaddr->nsect_addr);
writew(tf->lbal | (((u16)tf->hob_lbal) << 8),
- (void __iomem *) ioaddr->lbal_addr);
+ ioaddr->lbal_addr);
writew(tf->lbam | (((u16)tf->hob_lbam) << 8),
- (void __iomem *) ioaddr->lbam_addr);
+ ioaddr->lbam_addr);
writew(tf->lbah | (((u16)tf->hob_lbah) << 8),
- (void __iomem *) ioaddr->lbah_addr);
+ ioaddr->lbah_addr);
} else if (is_addr) {
- writew(tf->feature, (void __iomem *) ioaddr->feature_addr);
- writew(tf->nsect, (void __iomem *) ioaddr->nsect_addr);
- writew(tf->lbal, (void __iomem *) ioaddr->lbal_addr);
- writew(tf->lbam, (void __iomem *) ioaddr->lbam_addr);
- writew(tf->lbah, (void __iomem *) ioaddr->lbah_addr);
+ writew(tf->feature, ioaddr->feature_addr);
+ writew(tf->nsect, ioaddr->nsect_addr);
+ writew(tf->lbal, ioaddr->lbal_addr);
+ writew(tf->lbam, ioaddr->lbam_addr);
+ writew(tf->lbah, ioaddr->lbah_addr);
}
if (tf->flags & ATA_TFLAG_DEVICE)
- writeb(tf->device, (void __iomem *) ioaddr->device_addr);
+ writeb(tf->device, ioaddr->device_addr);
ata_wait_idle(ap);
}
@@ -171,12 +171,12 @@ static void k2_sata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
u16 nsect, lbal, lbam, lbah, feature;
tf->command = k2_stat_check_status(ap);
- tf->device = readw((void __iomem *)ioaddr->device_addr);
- feature = readw((void __iomem *)ioaddr->error_addr);
- nsect = readw((void __iomem *)ioaddr->nsect_addr);
- lbal = readw((void __iomem *)ioaddr->lbal_addr);
- lbam = readw((void __iomem *)ioaddr->lbam_addr);
- lbah = readw((void __iomem *)ioaddr->lbah_addr);
+ tf->device = readw(ioaddr->device_addr);
+ feature = readw(ioaddr->error_addr);
+ nsect = readw(ioaddr->nsect_addr);
+ lbal = readw(ioaddr->lbal_addr);
+ lbam = readw(ioaddr->lbam_addr);
+ lbah = readw(ioaddr->lbah_addr);
tf->feature = feature;
tf->nsect = nsect;
@@ -262,7 +262,7 @@ static void k2_bmdma_start_mmio (struct ata_queued_cmd *qc)
static u8 k2_stat_check_status(struct ata_port *ap)
{
- return readl((void *) ap->ioaddr.status_addr);
+ return readl((void __iomem *) ap->ioaddr.status_addr);
}
#ifdef CONFIG_PPC_OF
@@ -349,21 +349,21 @@ static const struct ata_port_operations k2_sata_ops = {
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_mmio_data_xfer,
+ .data_xfer = ata_data_xfer,
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
.error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.scr_read = k2_sata_scr_read,
.scr_write = k2_sata_scr_write,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_pci_host_stop,
};
-static void k2_sata_setup_port(struct ata_ioports *port, unsigned long base)
+static void k2_sata_setup_port(struct ata_ioports *port, void __iomem *base)
{
port->cmd_addr = base + K2_SATA_TF_CMD_OFFSET;
port->data_addr = base + K2_SATA_TF_DATA_OFFSET;
@@ -386,12 +386,11 @@ static void k2_sata_setup_port(struct ata_ioports *port, unsigned long base)
static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version;
- struct ata_probe_ent *probe_ent = NULL;
- unsigned long base;
+ struct device *dev = &pdev->dev;
+ struct ata_probe_ent *probe_ent;
void __iomem *mmio_base;
const struct k2_board_info *board_info =
&k2_board_info[ent->driver_data];
- int pci_dev_busy = 0;
int rc;
int i;
@@ -402,7 +401,7 @@ static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
* If this driver happens to only be useful on Apple's K2, then
* we should check that here as it has a normal Serverworks ID
*/
- rc = pci_enable_device(pdev);
+ rc = pcim_enable_device(pdev);
if (rc)
return rc;
/*
@@ -412,48 +411,27 @@ static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
if (pci_resource_len(pdev, 5) == 0)
return -ENODEV;
- /* Request PCI regions */
- rc = pci_request_regions(pdev, DRV_NAME);
- if (rc) {
- pci_dev_busy = 1;
- goto err_out;
- }
+ /* Request and iomap PCI regions */
+ rc = pcim_iomap_regions(pdev, 1 << 5, DRV_NAME);
+ if (rc == -EBUSY)
+ pcim_pin_device(pdev);
+ if (rc)
+ return rc;
rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
if (rc)
- goto err_out_regions;
+ return rc;
rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
if (rc)
- goto err_out_regions;
+ return rc;
- probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
- if (probe_ent == NULL) {
- rc = -ENOMEM;
- goto err_out_regions;
- }
+ probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL);
+ if (probe_ent == NULL)
+ return -ENOMEM;
- memset(probe_ent, 0, sizeof(*probe_ent));
probe_ent->dev = pci_dev_to_dev(pdev);
INIT_LIST_HEAD(&probe_ent->node);
- mmio_base = pci_iomap(pdev, 5, 0);
- if (mmio_base == NULL) {
- rc = -ENOMEM;
- goto err_out_free_ent;
- }
- base = (unsigned long) mmio_base;
-
- /* Clear a magic bit in SCR1 according to Darwin, those help
- * some funky seagate drives (though so far, those were already
- * set by the firmware on the machines I had access to)
- */
- writel(readl(mmio_base + K2_SATA_SICR1_OFFSET) & ~0x00040000,
- mmio_base + K2_SATA_SICR1_OFFSET);
-
- /* Clear SATA error & interrupts we don't use */
- writel(0xffffffff, mmio_base + K2_SATA_SCR_ERROR_OFFSET);
- writel(0x0, mmio_base + K2_SATA_SIM_OFFSET);
-
probe_ent->sht = &k2_sata_sht;
probe_ent->port_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
ATA_FLAG_MMIO | board_info->port_flags;
@@ -461,7 +439,7 @@ static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
probe_ent->n_ports = 4;
probe_ent->irq = pdev->irq;
probe_ent->irq_flags = IRQF_SHARED;
- probe_ent->mmio_base = mmio_base;
+ probe_ent->iomap = pcim_iomap_table(pdev);
/* We don't care much about the PIO/UDMA masks, but the core won't like us
* if we don't fill these
@@ -470,28 +448,33 @@ static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
probe_ent->mwdma_mask = 0x7;
probe_ent->udma_mask = 0x7f;
+ mmio_base = probe_ent->iomap[5];
+
/* different controllers have different number of ports - currently 4 or 8 */
/* All ports are on the same function. Multi-function device is no
* longer available. This should not be seen in any system. */
for (i = 0; i < board_info->n_ports; i++)
- k2_sata_setup_port(&probe_ent->port[i], base + i * K2_SATA_PORT_OFFSET);
+ k2_sata_setup_port(&probe_ent->port[i],
+ mmio_base + i * K2_SATA_PORT_OFFSET);
+
+ /* Clear a magic bit in SCR1 according to Darwin, those help
+ * some funky seagate drives (though so far, those were already
+ * set by the firmware on the machines I had access to)
+ */
+ writel(readl(mmio_base + K2_SATA_SICR1_OFFSET) & ~0x00040000,
+ mmio_base + K2_SATA_SICR1_OFFSET);
+
+ /* Clear SATA error & interrupts we don't use */
+ writel(0xffffffff, mmio_base + K2_SATA_SCR_ERROR_OFFSET);
+ writel(0x0, mmio_base + K2_SATA_SIM_OFFSET);
pci_set_master(pdev);
- /* FIXME: check ata_device_add return value */
- ata_device_add(probe_ent);
- kfree(probe_ent);
+ if (!ata_device_add(probe_ent))
+ return -ENODEV;
+ devm_kfree(dev, probe_ent);
return 0;
-
-err_out_free_ent:
- kfree(probe_ent);
-err_out_regions:
- pci_release_regions(pdev);
-err_out:
- if (!pci_dev_busy)
- pci_disable_device(pdev);
- return rc;
}
/* 0x240 is device ID for Apple K2 device
diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c
index ae7992de4b0..0ebd77b080d 100644
--- a/drivers/ata/sata_sx4.c
+++ b/drivers/ata/sata_sx4.c
@@ -37,12 +37,10 @@
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
-#include <linux/sched.h>
#include <linux/device.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_cmnd.h>
#include <linux/libata.h>
-#include <asm/io.h>
#include "sata_promise.h"
#define DRV_NAME "sata_sx4"
@@ -50,6 +48,9 @@
enum {
+ PDC_MMIO_BAR = 3,
+ PDC_DIMM_BAR = 4,
+
PDC_PRD_TBL = 0x44, /* Direct command DMA table addr */
PDC_PKT_SUBMIT = 0x40, /* Command packet pointer addr */
@@ -138,8 +139,6 @@ struct pdc_port_priv {
};
struct pdc_host_priv {
- void __iomem *dimm_mmio;
-
unsigned int doing_hdma;
unsigned int hdma_prod;
unsigned int hdma_cons;
@@ -156,11 +155,9 @@ static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance);
static void pdc_eng_timeout(struct ata_port *ap);
static void pdc_20621_phy_reset (struct ata_port *ap);
static int pdc_port_start(struct ata_port *ap);
-static void pdc_port_stop(struct ata_port *ap);
static void pdc20621_qc_prep(struct ata_queued_cmd *qc);
static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
-static void pdc20621_host_stop(struct ata_host *host);
static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe);
static int pdc20621_detect_dimm(struct ata_probe_ent *pe);
static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe,
@@ -205,13 +202,13 @@ static const struct ata_port_operations pdc_20621_ops = {
.phy_reset = pdc_20621_phy_reset,
.qc_prep = pdc20621_qc_prep,
.qc_issue = pdc20621_qc_issue_prot,
- .data_xfer = ata_mmio_data_xfer,
+ .data_xfer = ata_data_xfer,
.eng_timeout = pdc_eng_timeout,
.irq_handler = pdc20621_interrupt,
.irq_clear = pdc20621_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = pdc_port_start,
- .port_stop = pdc_port_stop,
- .host_stop = pdc20621_host_stop,
};
static const struct ata_port_info pdc_port_info[] = {
@@ -243,18 +240,6 @@ static struct pci_driver pdc_sata_pci_driver = {
};
-static void pdc20621_host_stop(struct ata_host *host)
-{
- struct pci_dev *pdev = to_pci_dev(host->dev);
- struct pdc_host_priv *hpriv = host->private_data;
- void __iomem *dimm_mmio = hpriv->dimm_mmio;
-
- pci_iounmap(pdev, dimm_mmio);
- kfree(hpriv);
-
- pci_iounmap(pdev, host->mmio_base);
-}
-
static int pdc_port_start(struct ata_port *ap)
{
struct device *dev = ap->host->dev;
@@ -265,43 +250,19 @@ static int pdc_port_start(struct ata_port *ap)
if (rc)
return rc;
- pp = kmalloc(sizeof(*pp), GFP_KERNEL);
- if (!pp) {
- rc = -ENOMEM;
- goto err_out;
- }
- memset(pp, 0, sizeof(*pp));
+ pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
+ if (!pp)
+ return -ENOMEM;
- pp->pkt = dma_alloc_coherent(dev, 128, &pp->pkt_dma, GFP_KERNEL);
- if (!pp->pkt) {
- rc = -ENOMEM;
- goto err_out_kfree;
- }
+ pp->pkt = dmam_alloc_coherent(dev, 128, &pp->pkt_dma, GFP_KERNEL);
+ if (!pp->pkt)
+ return -ENOMEM;
ap->private_data = pp;
return 0;
-
-err_out_kfree:
- kfree(pp);
-err_out:
- ata_port_stop(ap);
- return rc;
-}
-
-
-static void pdc_port_stop(struct ata_port *ap)
-{
- struct device *dev = ap->host->dev;
- struct pdc_port_priv *pp = ap->private_data;
-
- ap->private_data = NULL;
- dma_free_coherent(dev, 128, pp->pkt, pp->pkt_dma);
- kfree(pp);
- ata_port_stop(ap);
}
-
static void pdc_20621_phy_reset (struct ata_port *ap)
{
VPRINTK("ENTER\n");
@@ -452,9 +413,8 @@ static void pdc20621_dma_prep(struct ata_queued_cmd *qc)
struct scatterlist *sg;
struct ata_port *ap = qc->ap;
struct pdc_port_priv *pp = ap->private_data;
- void __iomem *mmio = ap->host->mmio_base;
- struct pdc_host_priv *hpriv = ap->host->private_data;
- void __iomem *dimm_mmio = hpriv->dimm_mmio;
+ void __iomem *mmio = ap->host->iomap[PDC_MMIO_BAR];
+ void __iomem *dimm_mmio = ap->host->iomap[PDC_DIMM_BAR];
unsigned int portno = ap->port_no;
unsigned int i, idx, total_len = 0, sgt_len;
u32 *buf = (u32 *) &pp->dimm_buf[PDC_DIMM_HEADER_SZ];
@@ -513,9 +473,8 @@ static void pdc20621_nodata_prep(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
struct pdc_port_priv *pp = ap->private_data;
- void __iomem *mmio = ap->host->mmio_base;
- struct pdc_host_priv *hpriv = ap->host->private_data;
- void __iomem *dimm_mmio = hpriv->dimm_mmio;
+ void __iomem *mmio = ap->host->iomap[PDC_MMIO_BAR];
+ void __iomem *dimm_mmio = ap->host->iomap[PDC_DIMM_BAR];
unsigned int portno = ap->port_no;
unsigned int i;
@@ -565,7 +524,7 @@ static void __pdc20621_push_hdma(struct ata_queued_cmd *qc,
{
struct ata_port *ap = qc->ap;
struct ata_host *host = ap->host;
- void __iomem *mmio = host->mmio_base;
+ void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
/* hard-code chip #0 */
mmio += PDC_CHIP0_OFS;
@@ -619,8 +578,7 @@ static void pdc20621_dump_hdma(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
unsigned int port_no = ap->port_no;
- struct pdc_host_priv *hpriv = ap->host->private_data;
- void *dimm_mmio = hpriv->dimm_mmio;
+ void __iomem *dimm_mmio = ap->host->iomap[PDC_DIMM_BAR];
dimm_mmio += (port_no * PDC_DIMM_WINDOW_STEP);
dimm_mmio += PDC_DIMM_HOST_PKT;
@@ -639,7 +597,7 @@ static void pdc20621_packet_start(struct ata_queued_cmd *qc)
struct ata_port *ap = qc->ap;
struct ata_host *host = ap->host;
unsigned int port_no = ap->port_no;
- void __iomem *mmio = host->mmio_base;
+ void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
u8 seq = (u8) (port_no + 1);
unsigned int port_ofs;
@@ -668,8 +626,8 @@ static void pdc20621_packet_start(struct ata_queued_cmd *qc)
readl(mmio + PDC_20621_SEQCTL + (seq * 4)); /* flush */
writel(port_ofs + PDC_DIMM_ATA_PKT,
- (void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
- readl((void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
+ ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
+ readl(ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
VPRINTK("submitted ofs 0x%x (%u), seq %u\n",
port_ofs + PDC_DIMM_ATA_PKT,
port_ofs + PDC_DIMM_ATA_PKT,
@@ -747,8 +705,8 @@ static inline unsigned int pdc20621_host_intr( struct ata_port *ap,
writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4));
readl(mmio + PDC_20621_SEQCTL + (seq * 4));
writel(port_ofs + PDC_DIMM_ATA_PKT,
- (void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
- readl((void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
+ ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
+ readl(ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
}
/* step two - execute ATA command */
@@ -781,7 +739,7 @@ static inline unsigned int pdc20621_host_intr( struct ata_port *ap,
static void pdc20621_irq_clear(struct ata_port *ap)
{
struct ata_host *host = ap->host;
- void __iomem *mmio = host->mmio_base;
+ void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
mmio += PDC_CHIP0_OFS;
@@ -799,12 +757,12 @@ static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance)
VPRINTK("ENTER\n");
- if (!host || !host->mmio_base) {
+ if (!host || !host->iomap[PDC_MMIO_BAR]) {
VPRINTK("QUICK EXIT\n");
return IRQ_NONE;
}
- mmio_base = host->mmio_base;
+ mmio_base = host->iomap[PDC_MMIO_BAR];
/* reading should also clear interrupts */
mmio_base += PDC_CHIP0_OFS;
@@ -905,7 +863,7 @@ static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile
}
-static void pdc_sata_setup_port(struct ata_ioports *port, unsigned long base)
+static void pdc_sata_setup_port(struct ata_ioports *port, void __iomem *base)
{
port->cmd_addr = base;
port->data_addr = base;
@@ -931,9 +889,8 @@ static void pdc20621_get_from_dimm(struct ata_probe_ent *pe, void *psource,
u16 idx;
u8 page_mask;
long dist;
- void __iomem *mmio = pe->mmio_base;
- struct pdc_host_priv *hpriv = pe->private_data;
- void __iomem *dimm_mmio = hpriv->dimm_mmio;
+ void __iomem *mmio = pe->iomap[PDC_MMIO_BAR];
+ void __iomem *dimm_mmio = pe->iomap[PDC_DIMM_BAR];
/* hard-code chip #0 */
mmio += PDC_CHIP0_OFS;
@@ -987,9 +944,8 @@ static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, void *psource,
u16 idx;
u8 page_mask;
long dist;
- void __iomem *mmio = pe->mmio_base;
- struct pdc_host_priv *hpriv = pe->private_data;
- void __iomem *dimm_mmio = hpriv->dimm_mmio;
+ void __iomem *mmio = pe->iomap[PDC_MMIO_BAR];
+ void __iomem *dimm_mmio = pe->iomap[PDC_DIMM_BAR];
/* hard-code chip #0 */
mmio += PDC_CHIP0_OFS;
@@ -1034,7 +990,7 @@ static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, void *psource,
static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe, u32 device,
u32 subaddr, u32 *pdata)
{
- void __iomem *mmio = pe->mmio_base;
+ void __iomem *mmio = pe->iomap[PDC_MMIO_BAR];
u32 i2creg = 0;
u32 status;
u32 count =0;
@@ -1093,7 +1049,7 @@ static int pdc20621_prog_dimm0(struct ata_probe_ent *pe)
u32 data = 0;
int size, i;
u8 bdimmsize;
- void __iomem *mmio = pe->mmio_base;
+ void __iomem *mmio = pe->iomap[PDC_MMIO_BAR];
static const struct {
unsigned int reg;
unsigned int ofs;
@@ -1155,8 +1111,8 @@ static int pdc20621_prog_dimm0(struct ata_probe_ent *pe)
static unsigned int pdc20621_prog_dimm_global(struct ata_probe_ent *pe)
{
u32 data, spd0;
- int error, i;
- void __iomem *mmio = pe->mmio_base;
+ int error, i;
+ void __iomem *mmio = pe->iomap[PDC_MMIO_BAR];
/* hard-code chip #0 */
mmio += PDC_CHIP0_OFS;
@@ -1210,7 +1166,7 @@ static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe)
u32 ticks=0;
u32 clock=0;
u32 fparam=0;
- void __iomem *mmio = pe->mmio_base;
+ void __iomem *mmio = pe->iomap[PDC_MMIO_BAR];
/* hard-code chip #0 */
mmio += PDC_CHIP0_OFS;
@@ -1334,7 +1290,7 @@ static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe)
static void pdc_20621_init(struct ata_probe_ent *pe)
{
u32 tmp;
- void __iomem *mmio = pe->mmio_base;
+ void __iomem *mmio = pe->iomap[PDC_MMIO_BAR];
/* hard-code chip #0 */
mmio += PDC_CHIP0_OFS;
@@ -1365,67 +1321,43 @@ static void pdc_20621_init(struct ata_probe_ent *pe)
static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version;
- struct ata_probe_ent *probe_ent = NULL;
- unsigned long base;
- void __iomem *mmio_base;
- void __iomem *dimm_mmio = NULL;
- struct pdc_host_priv *hpriv = NULL;
+ struct ata_probe_ent *probe_ent;
+ void __iomem *base;
+ struct pdc_host_priv *hpriv;
unsigned int board_idx = (unsigned int) ent->driver_data;
- int pci_dev_busy = 0;
int rc;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
- rc = pci_enable_device(pdev);
+ rc = pcim_enable_device(pdev);
if (rc)
return rc;
- rc = pci_request_regions(pdev, DRV_NAME);
- if (rc) {
- pci_dev_busy = 1;
- goto err_out;
- }
+ rc = pcim_iomap_regions(pdev, (1 << PDC_MMIO_BAR) | (1 << PDC_DIMM_BAR),
+ DRV_NAME);
+ if (rc == -EBUSY)
+ pcim_pin_device(pdev);
+ if (rc)
+ return rc;
rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
if (rc)
- goto err_out_regions;
+ return rc;
rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
if (rc)
- goto err_out_regions;
+ return rc;
- probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
- if (probe_ent == NULL) {
- rc = -ENOMEM;
- goto err_out_regions;
- }
+ probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL);
+ if (probe_ent == NULL)
+ return -ENOMEM;
- memset(probe_ent, 0, sizeof(*probe_ent));
probe_ent->dev = pci_dev_to_dev(pdev);
INIT_LIST_HEAD(&probe_ent->node);
- mmio_base = pci_iomap(pdev, 3, 0);
- if (mmio_base == NULL) {
- rc = -ENOMEM;
- goto err_out_free_ent;
- }
- base = (unsigned long) mmio_base;
-
- hpriv = kmalloc(sizeof(*hpriv), GFP_KERNEL);
- if (!hpriv) {
- rc = -ENOMEM;
- goto err_out_iounmap;
- }
- memset(hpriv, 0, sizeof(*hpriv));
-
- dimm_mmio = pci_iomap(pdev, 4, 0);
- if (!dimm_mmio) {
- kfree(hpriv);
- rc = -ENOMEM;
- goto err_out_iounmap;
- }
-
- hpriv->dimm_mmio = dimm_mmio;
+ hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL);
+ if (!hpriv)
+ return -ENOMEM;
probe_ent->sht = pdc_port_info[board_idx].sht;
probe_ent->port_flags = pdc_port_info[board_idx].flags;
@@ -1436,10 +1368,10 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *
probe_ent->irq = pdev->irq;
probe_ent->irq_flags = IRQF_SHARED;
- probe_ent->mmio_base = mmio_base;
+ probe_ent->iomap = pcim_iomap_table(pdev);
probe_ent->private_data = hpriv;
- base += PDC_CHIP0_OFS;
+ base = probe_ent->iomap[PDC_MMIO_BAR] + PDC_CHIP0_OFS;
probe_ent->n_ports = 4;
pdc_sata_setup_port(&probe_ent->port[0], base + 0x200);
@@ -1451,31 +1383,15 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *
/* initialize adapter */
/* initialize local dimm */
- if (pdc20621_dimm_init(probe_ent)) {
- rc = -ENOMEM;
- goto err_out_iounmap_dimm;
- }
+ if (pdc20621_dimm_init(probe_ent))
+ return -ENOMEM;
pdc_20621_init(probe_ent);
- /* FIXME: check ata_device_add return value */
- ata_device_add(probe_ent);
- kfree(probe_ent);
+ if (!ata_device_add(probe_ent))
+ return -ENODEV;
+ devm_kfree(&pdev->dev, probe_ent);
return 0;
-
-err_out_iounmap_dimm: /* only get to this label if 20621 */
- kfree(hpriv);
- pci_iounmap(pdev, dimm_mmio);
-err_out_iounmap:
- pci_iounmap(pdev, mmio_base);
-err_out_free_ent:
- kfree(probe_ent);
-err_out_regions:
- pci_release_regions(pdev);
-err_out:
- if (!pci_dev_busy)
- pci_disable_device(pdev);
- return rc;
}
diff --git a/drivers/ata/sata_uli.c b/drivers/ata/sata_uli.c
index a43aec62d50..80131eec68f 100644
--- a/drivers/ata/sata_uli.c
+++ b/drivers/ata/sata_uli.c
@@ -108,7 +108,7 @@ static const struct ata_port_operations uli_ops = {
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
@@ -117,13 +117,13 @@ static const struct ata_port_operations uli_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.scr_read = uli_scr_read,
.scr_write = uli_scr_write,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop,
};
static struct ata_port_info uli_port_info = {
@@ -189,62 +189,60 @@ static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
struct ata_port_info *ppi[2];
int rc;
unsigned int board_idx = (unsigned int) ent->driver_data;
- int pci_dev_busy = 0;
struct uli_priv *hpriv;
+ void __iomem * const *iomap;
if (!printed_version++)
dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
- rc = pci_enable_device(pdev);
+ rc = pcim_enable_device(pdev);
if (rc)
return rc;
rc = pci_request_regions(pdev, DRV_NAME);
if (rc) {
- pci_dev_busy = 1;
- goto err_out;
+ pcim_pin_device(pdev);
+ return rc;
}
rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
if (rc)
- goto err_out_regions;
+ return rc;
rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
if (rc)
- goto err_out_regions;
+ return rc;
ppi[0] = ppi[1] = &uli_port_info;
probe_ent = ata_pci_init_native_mode(pdev, ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
- if (!probe_ent) {
- rc = -ENOMEM;
- goto err_out_regions;
- }
+ if (!probe_ent)
+ return -ENOMEM;
- hpriv = kzalloc(sizeof(*hpriv), GFP_KERNEL);
- if (!hpriv) {
- rc = -ENOMEM;
- goto err_out_probe_ent;
- }
+ hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL);
+ if (!hpriv)
+ return -ENOMEM;
probe_ent->private_data = hpriv;
+ iomap = pcim_iomap_table(pdev);
+
switch (board_idx) {
case uli_5287:
hpriv->scr_cfg_addr[0] = ULI5287_BASE;
hpriv->scr_cfg_addr[1] = ULI5287_BASE + ULI5287_OFFS;
probe_ent->n_ports = 4;
- probe_ent->port[2].cmd_addr = pci_resource_start(pdev, 0) + 8;
+ probe_ent->port[2].cmd_addr = iomap[0] + 8;
probe_ent->port[2].altstatus_addr =
- probe_ent->port[2].ctl_addr =
- (pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS) + 4;
- probe_ent->port[2].bmdma_addr = pci_resource_start(pdev, 4) + 16;
+ probe_ent->port[2].ctl_addr = (void __iomem *)
+ ((unsigned long)iomap[1] | ATA_PCI_CTL_OFS) + 4;
+ probe_ent->port[2].bmdma_addr = iomap[4] + 16;
hpriv->scr_cfg_addr[2] = ULI5287_BASE + ULI5287_OFFS*4;
- probe_ent->port[3].cmd_addr = pci_resource_start(pdev, 2) + 8;
+ probe_ent->port[3].cmd_addr = iomap[2] + 8;
probe_ent->port[3].altstatus_addr =
- probe_ent->port[3].ctl_addr =
- (pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS) + 4;
- probe_ent->port[3].bmdma_addr = pci_resource_start(pdev, 4) + 24;
+ probe_ent->port[3].ctl_addr = (void __iomem *)
+ ((unsigned long)iomap[3] | ATA_PCI_CTL_OFS) + 4;
+ probe_ent->port[3].bmdma_addr = iomap[4] + 24;
hpriv->scr_cfg_addr[3] = ULI5287_BASE + ULI5287_OFFS*5;
ata_std_ports(&probe_ent->port[2]);
@@ -269,21 +267,11 @@ static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
pci_set_master(pdev);
pci_intx(pdev, 1);
- /* FIXME: check ata_device_add return value */
- ata_device_add(probe_ent);
- kfree(probe_ent);
+ if (!ata_device_add(probe_ent))
+ return -ENODEV;
+ devm_kfree(&pdev->dev, probe_ent);
return 0;
-
-err_out_probe_ent:
- kfree(probe_ent);
-err_out_regions:
- pci_release_regions(pdev);
-err_out:
- if (!pci_dev_busy)
- pci_disable_device(pdev);
- return rc;
-
}
static int __init uli_init(void)
diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c
index d3d5c0d5703..baca6d79bb0 100644
--- a/drivers/ata/sata_via.c
+++ b/drivers/ata/sata_via.c
@@ -44,7 +44,6 @@
#include <linux/device.h>
#include <scsi/scsi_host.h>
#include <linux/libata.h>
-#include <asm/io.h>
#define DRV_NAME "sata_via"
#define DRV_VERSION "2.0"
@@ -59,11 +58,14 @@ enum {
SATA_INT_GATE = 0x41, /* SATA interrupt gating */
SATA_NATIVE_MODE = 0x42, /* Native mode enable */
SATA_PATA_SHARING = 0x49, /* PATA/SATA sharing func ctrl */
-
+ PATA_UDMA_TIMING = 0xB3, /* PATA timing for DMA/ cable detect */
+ PATA_PIO_TIMING = 0xAB, /* PATA timing register */
+
PORT0 = (1 << 1),
PORT1 = (1 << 0),
ALL_PORTS = PORT0 | PORT1,
- N_PORTS = 2,
+ PATA_PORT = 2, /* PATA is port 2 */
+ N_PORTS = 3,
NATIVE_MODE_ALL = (1 << 7) | (1 << 6) | (1 << 5) | (1 << 4),
@@ -76,6 +78,11 @@ static u32 svia_scr_read (struct ata_port *ap, unsigned int sc_reg);
static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
static void svia_noop_freeze(struct ata_port *ap);
static void vt6420_error_handler(struct ata_port *ap);
+static void vt6421_sata_error_handler(struct ata_port *ap);
+static void vt6421_pata_error_handler(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);
+static int vt6421_port_start(struct ata_port *ap);
static const struct pci_device_id svia_pci_tbl[] = {
{ PCI_VDEVICE(VIA, 0x5337), vt6420 },
@@ -127,7 +134,7 @@ static const struct ata_port_operations vt6420_sata_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.freeze = svia_noop_freeze,
.thaw = ata_bmdma_thaw,
@@ -136,15 +143,49 @@ static const struct ata_port_operations vt6420_sata_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop,
};
-static const struct ata_port_operations vt6421_sata_ops = {
+static const struct ata_port_operations vt6421_pata_ops = {
.port_disable = ata_port_disable,
+
+ .set_piomode = vt6421_set_pio_mode,
+ .set_dmamode = vt6421_set_dma_mode,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .data_xfer = ata_data_xfer,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = vt6421_pata_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
+
+ .port_start = vt6421_port_start,
+};
+
+static const struct ata_port_operations vt6421_sata_ops = {
+ .port_disable = ata_port_disable,
+
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -158,22 +199,22 @@ static const struct ata_port_operations vt6421_sata_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_data_xfer,
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
- .error_handler = ata_bmdma_error_handler,
+ .error_handler = vt6421_sata_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.scr_read = svia_scr_read,
.scr_write = svia_scr_write,
- .port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_host_stop,
+ .port_start = vt6421_port_start,
};
static struct ata_port_info vt6420_port_info = {
@@ -195,14 +236,14 @@ static u32 svia_scr_read (struct ata_port *ap, unsigned int sc_reg)
{
if (sc_reg > SCR_CONTROL)
return 0xffffffffU;
- return inl(ap->ioaddr.scr_addr + (4 * sc_reg));
+ return ioread32(ap->ioaddr.scr_addr + (4 * sc_reg));
}
static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
{
if (sc_reg > SCR_CONTROL)
return;
- outl(val, ap->ioaddr.scr_addr + (4 * sc_reg));
+ iowrite32(val, ap->ioaddr.scr_addr + (4 * sc_reg));
}
static void svia_noop_freeze(struct ata_port *ap)
@@ -289,6 +330,61 @@ static void vt6420_error_handler(struct ata_port *ap)
NULL, ata_std_postreset);
}
+static int vt6421_pata_prereset(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u8 tmp;
+
+ pci_read_config_byte(pdev, PATA_UDMA_TIMING, &tmp);
+ if (tmp & 0x10)
+ ap->cbl = ATA_CBL_PATA40;
+ else
+ ap->cbl = ATA_CBL_PATA80;
+ return 0;
+}
+
+static void vt6421_pata_error_handler(struct ata_port *ap)
+{
+ return ata_bmdma_drive_eh(ap, vt6421_pata_prereset, ata_std_softreset,
+ NULL, ata_std_postreset);
+}
+
+static int vt6421_sata_prereset(struct ata_port *ap)
+{
+ ap->cbl = ATA_CBL_SATA;
+ return 0;
+}
+
+static void vt6421_sata_error_handler(struct ata_port *ap)
+{
+ return ata_bmdma_drive_eh(ap, vt6421_sata_prereset, ata_std_softreset,
+ NULL, ata_std_postreset);
+}
+
+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]);
+}
+
+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->pio_mode - XFER_UDMA_0]);
+}
+
+static int vt6421_port_start(struct ata_port *ap)
+{
+ if (ap->port_no == PATA_PORT) {
+ ap->ops = &vt6421_pata_ops;
+ ap->mwdma_mask = 0;
+ ap->flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_NO_LEGACY | ATA_FLAG_SRST;
+ }
+ return ata_port_start(ap);
+}
+
static const unsigned int svia_bar_sizes[] = {
8, 4, 8, 4, 16, 256
};
@@ -297,31 +393,28 @@ static const unsigned int vt6421_bar_sizes[] = {
16, 16, 16, 16, 32, 128
};
-static unsigned long svia_scr_addr(unsigned long addr, unsigned int port)
+static void __iomem * svia_scr_addr(void __iomem *addr, unsigned int port)
{
return addr + (port * 128);
}
-static unsigned long vt6421_scr_addr(unsigned long addr, unsigned int port)
+static void __iomem * vt6421_scr_addr(void __iomem *addr, unsigned int port)
{
return addr + (port * 64);
}
static void vt6421_init_addrs(struct ata_probe_ent *probe_ent,
- struct pci_dev *pdev,
- unsigned int port)
+ void __iomem * const *iomap, unsigned int port)
{
- unsigned long reg_addr = pci_resource_start(pdev, port);
- unsigned long bmdma_addr = pci_resource_start(pdev, 4) + (port * 8);
- unsigned long scr_addr;
+ void __iomem *reg_addr = iomap[port];
+ void __iomem *bmdma_addr = iomap[4] + (port * 8);
probe_ent->port[port].cmd_addr = reg_addr;
probe_ent->port[port].altstatus_addr =
- probe_ent->port[port].ctl_addr = (reg_addr + 8) | ATA_PCI_CTL_OFS;
+ probe_ent->port[port].ctl_addr = (void __iomem *)
+ ((unsigned long)(reg_addr + 8) | ATA_PCI_CTL_OFS);
probe_ent->port[port].bmdma_addr = bmdma_addr;
-
- scr_addr = vt6421_scr_addr(pci_resource_start(pdev, 5), port);
- probe_ent->port[port].scr_addr = scr_addr;
+ probe_ent->port[port].scr_addr = vt6421_scr_addr(iomap[5], port);
ata_std_ports(&probe_ent->port[port]);
}
@@ -330,16 +423,16 @@ static struct ata_probe_ent *vt6420_init_probe_ent(struct pci_dev *pdev)
{
struct ata_probe_ent *probe_ent;
struct ata_port_info *ppi[2];
-
+ void __iomem * const *iomap;
+
ppi[0] = ppi[1] = &vt6420_port_info;
probe_ent = ata_pci_init_native_mode(pdev, ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
if (!probe_ent)
return NULL;
- probe_ent->port[0].scr_addr =
- svia_scr_addr(pci_resource_start(pdev, 5), 0);
- probe_ent->port[1].scr_addr =
- svia_scr_addr(pci_resource_start(pdev, 5), 1);
+ iomap = pcim_iomap_table(pdev);
+ probe_ent->port[0].scr_addr = svia_scr_addr(iomap[5], 0);
+ probe_ent->port[1].scr_addr = svia_scr_addr(iomap[5], 1);
return probe_ent;
}
@@ -349,7 +442,7 @@ static struct ata_probe_ent *vt6421_init_probe_ent(struct pci_dev *pdev)
struct ata_probe_ent *probe_ent;
unsigned int i;
- probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
+ probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL);
if (!probe_ent)
return NULL;
@@ -368,7 +461,7 @@ static struct ata_probe_ent *vt6421_init_probe_ent(struct pci_dev *pdev)
probe_ent->udma_mask = 0x7f;
for (i = 0; i < N_PORTS; i++)
- vt6421_init_addrs(probe_ent, pdev, i);
+ vt6421_init_addrs(probe_ent, pcim_iomap_table(pdev), i);
return probe_ent;
}
@@ -420,20 +513,19 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
struct ata_probe_ent *probe_ent;
int board_id = (int) ent->driver_data;
const int *bar_sizes;
- int pci_dev_busy = 0;
u8 tmp8;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
- rc = pci_enable_device(pdev);
+ rc = pcim_enable_device(pdev);
if (rc)
return rc;
- rc = pci_request_regions(pdev, DRV_NAME);
+ rc = pcim_iomap_regions(pdev, 0x1f, DRV_NAME);
if (rc) {
- pci_dev_busy = 1;
- goto err_out;
+ pcim_pin_device(pdev);
+ return rc;
}
if (board_id == vt6420) {
@@ -442,8 +534,7 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
dev_printk(KERN_ERR, &pdev->dev,
"SATA master/slave not supported (0x%x)\n",
(int) tmp8);
- rc = -EIO;
- goto err_out_regions;
+ return -EIO;
}
bar_sizes = &svia_bar_sizes[0];
@@ -459,16 +550,15 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
i,
(unsigned long long)pci_resource_start(pdev, i),
(unsigned long long)pci_resource_len(pdev, i));
- rc = -ENODEV;
- goto err_out_regions;
+ return -ENODEV;
}
rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
if (rc)
- goto err_out_regions;
+ return rc;
rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
if (rc)
- goto err_out_regions;
+ return rc;
if (board_id == vt6420)
probe_ent = vt6420_init_probe_ent(pdev);
@@ -477,26 +567,18 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
if (!probe_ent) {
dev_printk(KERN_ERR, &pdev->dev, "out of memory\n");
- rc = -ENOMEM;
- goto err_out_regions;
+ return -ENOMEM;
}
svia_configure(pdev);
pci_set_master(pdev);
- /* FIXME: check ata_device_add return value */
- ata_device_add(probe_ent);
- kfree(probe_ent);
+ if (!ata_device_add(probe_ent))
+ return -ENODEV;
+ devm_kfree(&pdev->dev, probe_ent);
return 0;
-
-err_out_regions:
- pci_release_regions(pdev);
-err_out:
- if (!pci_dev_busy)
- pci_disable_device(pdev);
- return rc;
}
static int __init svia_init(void)
@@ -511,4 +593,3 @@ static void __exit svia_exit(void)
module_init(svia_init);
module_exit(svia_exit);
-
diff --git a/drivers/ata/sata_vsc.c b/drivers/ata/sata_vsc.c
index 0fa1b89f76d..2fd037bde09 100644
--- a/drivers/ata/sata_vsc.c
+++ b/drivers/ata/sata_vsc.c
@@ -50,6 +50,8 @@
#define DRV_VERSION "2.0"
enum {
+ VSC_MMIO_BAR = 0,
+
/* Interrupt register offsets (from chip base address) */
VSC_SATA_INT_STAT_OFFSET = 0x00,
VSC_SATA_INT_MASK_OFFSET = 0x04,
@@ -96,7 +98,6 @@ enum {
VSC_SATA_INT_PHY_CHANGE),
};
-
#define is_vsc_sata_int_err(port_idx, int_status) \
(int_status & (VSC_SATA_INT_ERROR << (8 * port_idx)))
@@ -105,7 +106,7 @@ static u32 vsc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
{
if (sc_reg > SCR_CONTROL)
return 0xffffffffU;
- return readl((void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
+ return readl(ap->ioaddr.scr_addr + (sc_reg * 4));
}
@@ -114,7 +115,7 @@ static void vsc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg,
{
if (sc_reg > SCR_CONTROL)
return;
- writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
+ writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
}
@@ -123,7 +124,7 @@ static void vsc_intr_mask_update(struct ata_port *ap, u8 ctl)
void __iomem *mask_addr;
u8 mask;
- mask_addr = ap->host->mmio_base +
+ mask_addr = ap->host->iomap[VSC_MMIO_BAR] +
VSC_SATA_INT_MASK_OFFSET + ap->port_no;
mask = readb(mask_addr);
if (ctl & ATA_NIEN)
@@ -150,25 +151,25 @@ static void vsc_sata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
}
if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
writew(tf->feature | (((u16)tf->hob_feature) << 8),
- (void __iomem *) ioaddr->feature_addr);
+ ioaddr->feature_addr);
writew(tf->nsect | (((u16)tf->hob_nsect) << 8),
- (void __iomem *) ioaddr->nsect_addr);
+ ioaddr->nsect_addr);
writew(tf->lbal | (((u16)tf->hob_lbal) << 8),
- (void __iomem *) ioaddr->lbal_addr);
+ ioaddr->lbal_addr);
writew(tf->lbam | (((u16)tf->hob_lbam) << 8),
- (void __iomem *) ioaddr->lbam_addr);
+ ioaddr->lbam_addr);
writew(tf->lbah | (((u16)tf->hob_lbah) << 8),
- (void __iomem *) ioaddr->lbah_addr);
+ ioaddr->lbah_addr);
} else if (is_addr) {
- writew(tf->feature, (void __iomem *) ioaddr->feature_addr);
- writew(tf->nsect, (void __iomem *) ioaddr->nsect_addr);
- writew(tf->lbal, (void __iomem *) ioaddr->lbal_addr);
- writew(tf->lbam, (void __iomem *) ioaddr->lbam_addr);
- writew(tf->lbah, (void __iomem *) ioaddr->lbah_addr);
+ writew(tf->feature, ioaddr->feature_addr);
+ writew(tf->nsect, ioaddr->nsect_addr);
+ writew(tf->lbal, ioaddr->lbal_addr);
+ writew(tf->lbam, ioaddr->lbam_addr);
+ writew(tf->lbah, ioaddr->lbah_addr);
}
if (tf->flags & ATA_TFLAG_DEVICE)
- writeb(tf->device, (void __iomem *) ioaddr->device_addr);
+ writeb(tf->device, ioaddr->device_addr);
ata_wait_idle(ap);
}
@@ -180,12 +181,12 @@ static void vsc_sata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
u16 nsect, lbal, lbam, lbah, feature;
tf->command = ata_check_status(ap);
- tf->device = readw((void __iomem *) ioaddr->device_addr);
- feature = readw((void __iomem *) ioaddr->error_addr);
- nsect = readw((void __iomem *) ioaddr->nsect_addr);
- lbal = readw((void __iomem *) ioaddr->lbal_addr);
- lbam = readw((void __iomem *) ioaddr->lbam_addr);
- lbah = readw((void __iomem *) ioaddr->lbah_addr);
+ tf->device = readw(ioaddr->device_addr);
+ feature = readw(ioaddr->error_addr);
+ nsect = readw(ioaddr->nsect_addr);
+ lbal = readw(ioaddr->lbal_addr);
+ lbam = readw(ioaddr->lbam_addr);
+ lbah = readw(ioaddr->lbah_addr);
tf->feature = feature;
tf->nsect = nsect;
@@ -217,7 +218,8 @@ static irqreturn_t vsc_sata_interrupt (int irq, void *dev_instance)
spin_lock(&host->lock);
- int_status = readl(host->mmio_base + VSC_SATA_INT_STAT_OFFSET);
+ int_status = readl(host->iomap[VSC_MMIO_BAR] +
+ VSC_SATA_INT_STAT_OFFSET);
for (i = 0; i < host->n_ports; i++) {
if (int_status & ((u32) 0xFF << (8 * i))) {
@@ -301,21 +303,22 @@ static const struct ata_port_operations vsc_sata_ops = {
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_mmio_data_xfer,
+ .data_xfer = ata_data_xfer,
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
.error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
.irq_handler = vsc_sata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
.scr_read = vsc_sata_scr_read,
.scr_write = vsc_sata_scr_write,
.port_start = ata_port_start,
- .port_stop = ata_port_stop,
- .host_stop = ata_pci_host_stop,
};
-static void __devinit vsc_sata_setup_port(struct ata_ioports *port, unsigned long base)
+static void __devinit vsc_sata_setup_port(struct ata_ioports *port,
+ void __iomem *base)
{
port->cmd_addr = base + VSC_SATA_TF_CMD_OFFSET;
port->data_addr = base + VSC_SATA_TF_DATA_OFFSET;
@@ -332,71 +335,66 @@ static void __devinit vsc_sata_setup_port(struct ata_ioports *port, unsigned lon
port->ctl_addr = base + VSC_SATA_TF_CTL_OFFSET;
port->bmdma_addr = base + VSC_SATA_DMA_CMD_OFFSET;
port->scr_addr = base + VSC_SATA_SCR_STATUS_OFFSET;
- writel(0, (void __iomem *) base + VSC_SATA_UP_DESCRIPTOR_OFFSET);
- writel(0, (void __iomem *) base + VSC_SATA_UP_DATA_BUFFER_OFFSET);
+ writel(0, base + VSC_SATA_UP_DESCRIPTOR_OFFSET);
+ writel(0, base + VSC_SATA_UP_DATA_BUFFER_OFFSET);
}
static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version;
- struct ata_probe_ent *probe_ent = NULL;
- unsigned long base;
- int pci_dev_busy = 0;
+ struct ata_probe_ent *probe_ent;
void __iomem *mmio_base;
int rc;
+ u8 cls;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
- rc = pci_enable_device(pdev);
+ rc = pcim_enable_device(pdev);
if (rc)
return rc;
/*
* Check if we have needed resource mapped.
*/
- if (pci_resource_len(pdev, 0) == 0) {
- rc = -ENODEV;
- goto err_out;
- }
+ if (pci_resource_len(pdev, 0) == 0)
+ return -ENODEV;
- rc = pci_request_regions(pdev, DRV_NAME);
- if (rc) {
- pci_dev_busy = 1;
- goto err_out;
- }
+ rc = pcim_iomap_regions(pdev, 1 << VSC_MMIO_BAR, DRV_NAME);
+ if (rc == -EBUSY)
+ pcim_pin_device(pdev);
+ if (rc)
+ return rc;
/*
* Use 32 bit DMA mask, because 64 bit address support is poor.
*/
rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
if (rc)
- goto err_out_regions;
+ return rc;
rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
if (rc)
- goto err_out_regions;
+ return rc;
- probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
- if (probe_ent == NULL) {
- rc = -ENOMEM;
- goto err_out_regions;
- }
- memset(probe_ent, 0, sizeof(*probe_ent));
+ probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL);
+ if (probe_ent == NULL)
+ return -ENOMEM;
probe_ent->dev = pci_dev_to_dev(pdev);
INIT_LIST_HEAD(&probe_ent->node);
- mmio_base = pci_iomap(pdev, 0, 0);
- if (mmio_base == NULL) {
- rc = -ENOMEM;
- goto err_out_free_ent;
- }
- base = (unsigned long) mmio_base;
-
/*
- * Due to a bug in the chip, the default cache line size can't be used
+ * Due to a bug in the chip, the default cache line size can't be
+ * used (unless the default is non-zero).
*/
- pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x80);
+ pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cls);
+ if (cls == 0x00)
+ pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x80);
+
+ if (pci_enable_msi(pdev) == 0)
+ pci_intx(pdev, 0);
+ else
+ probe_ent->irq_flags = IRQF_SHARED;
probe_ent->sht = &vsc_sata_sht;
probe_ent->port_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
@@ -404,8 +402,7 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d
probe_ent->port_ops = &vsc_sata_ops;
probe_ent->n_ports = 4;
probe_ent->irq = pdev->irq;
- probe_ent->irq_flags = IRQF_SHARED;
- probe_ent->mmio_base = mmio_base;
+ probe_ent->iomap = pcim_iomap_table(pdev);
/* We don't care much about the PIO/UDMA masks, but the core won't like us
* if we don't fill these
@@ -414,11 +411,13 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d
probe_ent->mwdma_mask = 0x07;
probe_ent->udma_mask = 0x7f;
+ mmio_base = probe_ent->iomap[VSC_MMIO_BAR];
+
/* We have 4 ports per PCI function */
- vsc_sata_setup_port(&probe_ent->port[0], base + 1 * VSC_SATA_PORT_OFFSET);
- vsc_sata_setup_port(&probe_ent->port[1], base + 2 * VSC_SATA_PORT_OFFSET);
- vsc_sata_setup_port(&probe_ent->port[2], base + 3 * VSC_SATA_PORT_OFFSET);
- vsc_sata_setup_port(&probe_ent->port[3], base + 4 * VSC_SATA_PORT_OFFSET);
+ vsc_sata_setup_port(&probe_ent->port[0], mmio_base + 1 * VSC_SATA_PORT_OFFSET);
+ vsc_sata_setup_port(&probe_ent->port[1], mmio_base + 2 * VSC_SATA_PORT_OFFSET);
+ vsc_sata_setup_port(&probe_ent->port[2], mmio_base + 3 * VSC_SATA_PORT_OFFSET);
+ vsc_sata_setup_port(&probe_ent->port[3], mmio_base + 4 * VSC_SATA_PORT_OFFSET);
pci_set_master(pdev);
@@ -430,20 +429,11 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d
*/
pci_write_config_dword(pdev, 0x98, 0);
- /* FIXME: check ata_device_add return value */
- ata_device_add(probe_ent);
- kfree(probe_ent);
+ if (!ata_device_add(probe_ent))
+ return -ENODEV;
+ devm_kfree(&pdev->dev, probe_ent);
return 0;
-
-err_out_free_ent:
- kfree(probe_ent);
-err_out_regions:
- pci_release_regions(pdev);
-err_out:
- if (!pci_dev_busy)
- pci_disable_device(pdev);
- return rc;
}
static const struct pci_device_id vsc_sata_pci_tbl[] = {
diff --git a/drivers/atm/adummy.c b/drivers/atm/adummy.c
index ac2c10822be..8d60c4eb54f 100644
--- a/drivers/atm/adummy.c
+++ b/drivers/atm/adummy.c
@@ -13,7 +13,6 @@
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/mm.h>
-#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/interrupt.h>
#include <asm/io.h>
diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c
index 5aab7bd473a..8fccf018f16 100644
--- a/drivers/atm/eni.c
+++ b/drivers/atm/eni.c
@@ -912,7 +912,6 @@ static int start_rx(struct atm_dev *dev)
free_page((unsigned long) eni_dev->free_list);
return -ENOMEM;
}
- memset(eni_dev->rx_map,0,PAGE_SIZE);
eni_dev->rx_mult = DEFAULT_RX_MULT;
eni_dev->fast = eni_dev->last_fast = NULL;
eni_dev->slow = eni_dev->last_slow = NULL;
diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c
index 4aeb3d062ff..a7c0ed3107e 100644
--- a/drivers/atm/fore200e.c
+++ b/drivers/atm/fore200e.c
@@ -29,7 +29,6 @@
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/capability.h>
-#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/bitops.h>
#include <linux/pci.h>
diff --git a/drivers/atm/he.c b/drivers/atm/he.c
index db33f6f4dd2..8510026b690 100644
--- a/drivers/atm/he.c
+++ b/drivers/atm/he.c
@@ -3017,7 +3017,7 @@ read_prom_byte(struct he_dev *he_dev, int addr)
he_writel(he_dev, val, HOST_CNTL);
/* Send READ instruction */
- for (i = 0; i < sizeof(readtab)/sizeof(readtab[0]); i++) {
+ for (i = 0; i < ARRAY_SIZE(readtab); i++) {
he_writel(he_dev, val | readtab[i], HOST_CNTL);
udelay(EEPROM_DELAY);
}
diff --git a/drivers/atm/idt77105.c b/drivers/atm/idt77105.c
index 325325afabe..0bd657f5dd2 100644
--- a/drivers/atm/idt77105.c
+++ b/drivers/atm/idt77105.c
@@ -4,7 +4,6 @@
#include <linux/module.h>
-#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/errno.h>
diff --git a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c
index f4078612194..b4b80140c39 100644
--- a/drivers/atm/idt77252.c
+++ b/drivers/atm/idt77252.c
@@ -388,7 +388,7 @@ idt77252_eeprom_read_status(struct idt77252_dev *card)
gp = idt77252_read_gp(card) & ~(SAR_GP_EESCLK|SAR_GP_EECS|SAR_GP_EEDO);
- for (i = 0; i < sizeof(rdsrtab)/sizeof(rdsrtab[0]); i++) {
+ for (i = 0; i < ARRAY_SIZE(rdsrtab); i++) {
idt77252_write_gp(card, gp | rdsrtab[i]);
udelay(5);
}
@@ -422,7 +422,7 @@ idt77252_eeprom_read_byte(struct idt77252_dev *card, u8 offset)
gp = idt77252_read_gp(card) & ~(SAR_GP_EESCLK|SAR_GP_EECS|SAR_GP_EEDO);
- for (i = 0; i < sizeof(rdtab)/sizeof(rdtab[0]); i++) {
+ for (i = 0; i < ARRAY_SIZE(rdtab); i++) {
idt77252_write_gp(card, gp | rdtab[i]);
udelay(5);
}
@@ -469,14 +469,14 @@ idt77252_eeprom_write_byte(struct idt77252_dev *card, u8 offset, u8 data)
gp = idt77252_read_gp(card) & ~(SAR_GP_EESCLK|SAR_GP_EECS|SAR_GP_EEDO);
- for (i = 0; i < sizeof(wrentab)/sizeof(wrentab[0]); i++) {
+ for (i = 0; i < ARRAY_SIZE(wrentab); i++) {
idt77252_write_gp(card, gp | wrentab[i]);
udelay(5);
}
idt77252_write_gp(card, gp | SAR_GP_EECS);
udelay(5);
- for (i = 0; i < sizeof(wrtab)/sizeof(wrtab[0]); i++) {
+ for (i = 0; i < ARRAY_SIZE(wrtab); i++) {
idt77252_write_gp(card, gp | wrtab[i]);
udelay(5);
}
diff --git a/drivers/atm/nicstarmac.c b/drivers/atm/nicstarmac.c
index 2c5e3ae7750..480947f4e01 100644
--- a/drivers/atm/nicstarmac.c
+++ b/drivers/atm/nicstarmac.c
@@ -7,6 +7,8 @@
* Read this ForeRunner's MAC address from eprom/eeprom
*/
+#include <linux/kernel.h>
+
typedef void __iomem *virt_addr_t;
#define CYCLE_DELAY 5
@@ -176,7 +178,7 @@ read_eprom_byte(virt_addr_t base, u_int8_t offset)
val = NICSTAR_REG_READ( base, NICSTAR_REG_GENERAL_PURPOSE ) & 0xFFFFFFF0;
/* Send READ instruction */
- for (i=0; i<sizeof readtab/sizeof readtab[0]; i++)
+ for (i=0; i<ARRAY_SIZE(readtab); i++)
{
NICSTAR_REG_WRITE( base, NICSTAR_REG_GENERAL_PURPOSE,
(val | readtab[i]) );
diff --git a/drivers/atm/uPD98402.c b/drivers/atm/uPD98402.c
index 9504cce51bf..fc8cb07c247 100644
--- a/drivers/atm/uPD98402.c
+++ b/drivers/atm/uPD98402.c
@@ -4,7 +4,6 @@
#include <linux/module.h>
-#include <linux/sched.h> /* for jiffies */
#include <linux/mm.h>
#include <linux/errno.h>
#include <linux/atmdev.h>
diff --git a/drivers/atm/zatm.c b/drivers/atm/zatm.c
index 756d4f760da..0d7091e2077 100644
--- a/drivers/atm/zatm.c
+++ b/drivers/atm/zatm.c
@@ -4,7 +4,6 @@
#include <linux/module.h>
-#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/pci.h>
diff --git a/drivers/auxdisplay/Kconfig b/drivers/auxdisplay/Kconfig
new file mode 100644
index 00000000000..0300e7f54cc
--- /dev/null
+++ b/drivers/auxdisplay/Kconfig
@@ -0,0 +1,109 @@
+#
+# For a description of the syntax of this configuration file,
+# see Documentation/kbuild/kconfig-language.txt.
+#
+# Auxiliary display drivers configuration.
+#
+
+menu "Auxiliary Display support"
+
+config KS0108
+ tristate "KS0108 LCD Controller"
+ depends on PARPORT_PC
+ default n
+ ---help---
+ If you have a LCD controlled by one or more KS0108
+ controllers, say Y. You will need also another more specific
+ driver for your LCD.
+
+ Depends on Parallel Port support. If you say Y at
+ parport, you will be able to compile this as a module (M)
+ and built-in as well (Y).
+
+ To compile this as a module, choose M here:
+ the module will be called ks0108.
+
+ If unsure, say N.
+
+config KS0108_PORT
+ hex "Parallel port where the LCD is connected"
+ depends on KS0108
+ default 0x378
+ ---help---
+ The address of the parallel port where the LCD is connected.
+
+ The first standard parallel port address is 0x378.
+ The second standard parallel port address is 0x278.
+ The third standard parallel port address is 0x3BC.
+
+ You can specify a different address if you need.
+
+ If you don't know what I'm talking about, load the parport module,
+ and execute "dmesg" or "cat /proc/ioports". You can see there how
+ many parallel ports are present and which address each one has.
+
+ Usually you only need to use 0x378.
+
+ If you compile this as a module, you can still override this
+ using the module parameters.
+
+config KS0108_DELAY
+ int "Delay between each control writing (microseconds)"
+ depends on KS0108
+ default "2"
+ ---help---
+ Amount of time the ks0108 should wait between each control write
+ to the parallel port.
+
+ If your driver seems to miss random writings, increment this.
+
+ If you don't know what I'm talking about, ignore it.
+
+ If you compile this as a module, you can still override this
+ value using the module parameters.
+
+config CFAG12864B
+ tristate "CFAG12864B LCD"
+ depends on X86
+ depends on FB
+ depends on KS0108
+ default n
+ ---help---
+ If you have a Crystalfontz 128x64 2-color LCD, cfag12864b Series,
+ say Y. You also need the ks0108 LCD Controller driver.
+
+ For help about how to wire your LCD to the parallel port,
+ check Documentation/auxdisplay/cfag12864b
+
+ Depends on the x86 arch and the framebuffer support.
+
+ The LCD framebuffer driver can be attached to a console.
+ It will work fine. However, you can't attach it to the fbdev driver
+ of the xorg server.
+
+ To compile this as a module, choose M here:
+ the modules will be called cfag12864b and cfag12864bfb.
+
+ If unsure, say N.
+
+config CFAG12864B_RATE
+ int "Refresh rate (hertz)"
+ depends on CFAG12864B
+ default "20"
+ ---help---
+ Refresh rate of the LCD.
+
+ As the LCD is not memory mapped, the driver has to make the work by
+ software. This means you should be careful setting this value higher.
+ If your CPUs are really slow or you feel the system is slowed down,
+ decrease the value.
+
+ Be careful modifying this value to a very high value:
+ You can freeze the computer, or the LCD maybe can't draw as fast as you
+ are requesting.
+
+ If you don't know what I'm talking about, ignore it.
+
+ If you compile this as a module, you can still override this
+ value using the module parameters.
+endmenu
diff --git a/drivers/auxdisplay/Makefile b/drivers/auxdisplay/Makefile
new file mode 100644
index 00000000000..8a8936a468b
--- /dev/null
+++ b/drivers/auxdisplay/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the kernel auxiliary displays device drivers.
+#
+
+obj-$(CONFIG_KS0108) += ks0108.o
+obj-$(CONFIG_CFAG12864B) += cfag12864b.o cfag12864bfb.o
diff --git a/drivers/auxdisplay/cfag12864b.c b/drivers/auxdisplay/cfag12864b.c
new file mode 100644
index 00000000000..cb44cb4f6a4
--- /dev/null
+++ b/drivers/auxdisplay/cfag12864b.c
@@ -0,0 +1,402 @@
+/*
+ * Filename: cfag12864b.c
+ * Version: 0.1.0
+ * Description: cfag12864b LCD driver
+ * License: GPLv2
+ * Depends: ks0108
+ *
+ * Author: Copyright (C) Miguel Ojeda Sandonis <maxextreme@gmail.com>
+ * Date: 2006-10-31
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/jiffies.h>
+#include <linux/mutex.h>
+#include <linux/uaccess.h>
+#include <linux/vmalloc.h>
+#include <linux/workqueue.h>
+#include <linux/ks0108.h>
+#include <linux/cfag12864b.h>
+
+
+#define CFAG12864B_NAME "cfag12864b"
+
+/*
+ * Module Parameters
+ */
+
+static unsigned int cfag12864b_rate = CONFIG_CFAG12864B_RATE;
+module_param(cfag12864b_rate, uint, S_IRUGO);
+MODULE_PARM_DESC(cfag12864b_rate,
+ "Refresh rate (hertzs)");
+
+unsigned int cfag12864b_getrate(void)
+{
+ return cfag12864b_rate;
+}
+
+/*
+ * cfag12864b Commands
+ *
+ * E = Enable signal
+ * Everytime E switch from low to high,
+ * cfag12864b/ks0108 reads the command/data.
+ *
+ * CS1 = First ks0108controller.
+ * If high, the first ks0108 controller receives commands/data.
+ *
+ * CS2 = Second ks0108 controller
+ * If high, the second ks0108 controller receives commands/data.
+ *
+ * DI = Data/Instruction
+ * If low, cfag12864b will expect commands.
+ * If high, cfag12864b will expect data.
+ *
+ */
+
+#define bit(n) (((unsigned char)1)<<(n))
+
+#define CFAG12864B_BIT_E (0)
+#define CFAG12864B_BIT_CS1 (2)
+#define CFAG12864B_BIT_CS2 (1)
+#define CFAG12864B_BIT_DI (3)
+
+static unsigned char cfag12864b_state;
+
+static void cfag12864b_set(void)
+{
+ ks0108_writecontrol(cfag12864b_state);
+}
+
+static void cfag12864b_setbit(unsigned char state, unsigned char n)
+{
+ if (state)
+ cfag12864b_state |= bit(n);
+ else
+ cfag12864b_state &= ~bit(n);
+}
+
+static void cfag12864b_e(unsigned char state)
+{
+ cfag12864b_setbit(state, CFAG12864B_BIT_E);
+ cfag12864b_set();
+}
+
+static void cfag12864b_cs1(unsigned char state)
+{
+ cfag12864b_setbit(state, CFAG12864B_BIT_CS1);
+}
+
+static void cfag12864b_cs2(unsigned char state)
+{
+ cfag12864b_setbit(state, CFAG12864B_BIT_CS2);
+}
+
+static void cfag12864b_di(unsigned char state)
+{
+ cfag12864b_setbit(state, CFAG12864B_BIT_DI);
+}
+
+static void cfag12864b_setcontrollers(unsigned char first,
+ unsigned char second)
+{
+ if (first)
+ cfag12864b_cs1(0);
+ else
+ cfag12864b_cs1(1);
+
+ if (second)
+ cfag12864b_cs2(0);
+ else
+ cfag12864b_cs2(1);
+}
+
+static void cfag12864b_controller(unsigned char which)
+{
+ if (which == 0)
+ cfag12864b_setcontrollers(1, 0);
+ else if (which == 1)
+ cfag12864b_setcontrollers(0, 1);
+}
+
+static void cfag12864b_displaystate(unsigned char state)
+{
+ cfag12864b_di(0);
+ cfag12864b_e(1);
+ ks0108_displaystate(state);
+ cfag12864b_e(0);
+}
+
+static void cfag12864b_address(unsigned char address)
+{
+ cfag12864b_di(0);
+ cfag12864b_e(1);
+ ks0108_address(address);
+ cfag12864b_e(0);
+}
+
+static void cfag12864b_page(unsigned char page)
+{
+ cfag12864b_di(0);
+ cfag12864b_e(1);
+ ks0108_page(page);
+ cfag12864b_e(0);
+}
+
+static void cfag12864b_startline(unsigned char startline)
+{
+ cfag12864b_di(0);
+ cfag12864b_e(1);
+ ks0108_startline(startline);
+ cfag12864b_e(0);
+}
+
+static void cfag12864b_writebyte(unsigned char byte)
+{
+ cfag12864b_di(1);
+ cfag12864b_e(1);
+ ks0108_writedata(byte);
+ cfag12864b_e(0);
+}
+
+static void cfag12864b_nop(void)
+{
+ cfag12864b_startline(0);
+}
+
+/*
+ * cfag12864b Internal Commands
+ */
+
+static void cfag12864b_on(void)
+{
+ cfag12864b_setcontrollers(1, 1);
+ cfag12864b_displaystate(1);
+}
+
+static void cfag12864b_off(void)
+{
+ cfag12864b_setcontrollers(1, 1);
+ cfag12864b_displaystate(0);
+}
+
+static void cfag12864b_clear(void)
+{
+ unsigned char i, j;
+
+ cfag12864b_setcontrollers(1, 1);
+ for (i = 0; i < CFAG12864B_PAGES; i++) {
+ cfag12864b_page(i);
+ cfag12864b_address(0);
+ for (j = 0; j < CFAG12864B_ADDRESSES; j++)
+ cfag12864b_writebyte(0);
+ }
+}
+
+/*
+ * Update work
+ */
+
+unsigned char *cfag12864b_buffer;
+static unsigned char *cfag12864b_cache;
+static DEFINE_MUTEX(cfag12864b_mutex);
+static unsigned char cfag12864b_updating;
+static void cfag12864b_update(struct work_struct *delayed_work);
+static struct workqueue_struct *cfag12864b_workqueue;
+static DECLARE_DELAYED_WORK(cfag12864b_work, cfag12864b_update);
+
+static void cfag12864b_queue(void)
+{
+ queue_delayed_work(cfag12864b_workqueue, &cfag12864b_work,
+ HZ / cfag12864b_rate);
+}
+
+unsigned char cfag12864b_enable(void)
+{
+ unsigned char ret;
+
+ mutex_lock(&cfag12864b_mutex);
+
+ if (!cfag12864b_updating) {
+ cfag12864b_updating = 1;
+ cfag12864b_queue();
+ ret = 0;
+ } else
+ ret = 1;
+
+ mutex_unlock(&cfag12864b_mutex);
+
+ return ret;
+}
+
+void cfag12864b_disable(void)
+{
+ mutex_lock(&cfag12864b_mutex);
+
+ if (cfag12864b_updating) {
+ cfag12864b_updating = 0;
+ cancel_delayed_work(&cfag12864b_work);
+ flush_workqueue(cfag12864b_workqueue);
+ }
+
+ mutex_unlock(&cfag12864b_mutex);
+}
+
+unsigned char cfag12864b_isenabled(void)
+{
+ return cfag12864b_updating;
+}
+
+static void cfag12864b_update(struct work_struct *work)
+{
+ unsigned char c;
+ unsigned short i, j, k, b;
+
+ if (memcmp(cfag12864b_cache, cfag12864b_buffer, CFAG12864B_SIZE)) {
+ for (i = 0; i < CFAG12864B_CONTROLLERS; i++) {
+ cfag12864b_controller(i);
+ cfag12864b_nop();
+ for (j = 0; j < CFAG12864B_PAGES; j++) {
+ cfag12864b_page(j);
+ cfag12864b_nop();
+ cfag12864b_address(0);
+ cfag12864b_nop();
+ for (k = 0; k < CFAG12864B_ADDRESSES; k++) {
+ for (c = 0, b = 0; b < 8; b++)
+ if (cfag12864b_buffer
+ [i * CFAG12864B_ADDRESSES / 8
+ + k / 8 + (j * 8 + b) *
+ CFAG12864B_WIDTH / 8]
+ & bit(k % 8))
+ c |= bit(b);
+ cfag12864b_writebyte(c);
+ }
+ }
+ }
+
+ memcpy(cfag12864b_cache, cfag12864b_buffer, CFAG12864B_SIZE);
+ }
+
+ if (cfag12864b_updating)
+ cfag12864b_queue();
+}
+
+/*
+ * cfag12864b Exported Symbols
+ */
+
+EXPORT_SYMBOL_GPL(cfag12864b_buffer);
+EXPORT_SYMBOL_GPL(cfag12864b_getrate);
+EXPORT_SYMBOL_GPL(cfag12864b_enable);
+EXPORT_SYMBOL_GPL(cfag12864b_disable);
+EXPORT_SYMBOL_GPL(cfag12864b_isenabled);
+
+/*
+ * Is the module inited?
+ */
+
+static unsigned char cfag12864b_inited;
+unsigned char cfag12864b_isinited(void)
+{
+ return cfag12864b_inited;
+}
+EXPORT_SYMBOL_GPL(cfag12864b_isinited);
+
+/*
+ * Module Init & Exit
+ */
+
+static int __init cfag12864b_init(void)
+{
+ int ret = -EINVAL;
+
+ /* ks0108_init() must be called first */
+ if (!ks0108_isinited()) {
+ printk(KERN_ERR CFAG12864B_NAME ": ERROR: "
+ "ks0108 is not initialized\n");
+ goto none;
+ }
+
+ if (PAGE_SIZE < CFAG12864B_SIZE) {
+ printk(KERN_ERR CFAG12864B_NAME ": ERROR: "
+ "page size (%i) < cfag12864b size (%i)\n",
+ (unsigned int)PAGE_SIZE, CFAG12864B_SIZE);
+ ret = -ENOMEM;
+ goto none;
+ }
+
+ cfag12864b_buffer = (unsigned char *) __get_free_page(GFP_KERNEL);
+ if (cfag12864b_buffer == NULL) {
+ printk(KERN_ERR CFAG12864B_NAME ": ERROR: "
+ "can't get a free page\n");
+ ret = -ENOMEM;
+ goto none;
+ }
+
+ cfag12864b_cache = kmalloc(sizeof(unsigned char) *
+ CFAG12864B_SIZE, GFP_KERNEL);
+ if (cfag12864b_buffer == NULL) {
+ printk(KERN_ERR CFAG12864B_NAME ": ERROR: "
+ "can't alloc cache buffer (%i bytes)\n",
+ CFAG12864B_SIZE);
+ ret = -ENOMEM;
+ goto bufferalloced;
+ }
+
+ cfag12864b_workqueue = create_singlethread_workqueue(CFAG12864B_NAME);
+ if (cfag12864b_workqueue == NULL)
+ goto cachealloced;
+
+ memset(cfag12864b_buffer, 0, CFAG12864B_SIZE);
+
+ cfag12864b_clear();
+ cfag12864b_on();
+
+ cfag12864b_inited = 1;
+ return 0;
+
+cachealloced:
+ kfree(cfag12864b_cache);
+
+bufferalloced:
+ free_page((unsigned long) cfag12864b_buffer);
+
+none:
+ return ret;
+}
+
+static void __exit cfag12864b_exit(void)
+{
+ cfag12864b_disable();
+ cfag12864b_off();
+ destroy_workqueue(cfag12864b_workqueue);
+ kfree(cfag12864b_cache);
+ free_page((unsigned long) cfag12864b_buffer);
+}
+
+module_init(cfag12864b_init);
+module_exit(cfag12864b_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Miguel Ojeda Sandonis <maxextreme@gmail.com>");
+MODULE_DESCRIPTION("cfag12864b LCD driver");
diff --git a/drivers/auxdisplay/cfag12864bfb.c b/drivers/auxdisplay/cfag12864bfb.c
new file mode 100644
index 00000000000..66fafbb1d08
--- /dev/null
+++ b/drivers/auxdisplay/cfag12864bfb.c
@@ -0,0 +1,188 @@
+/*
+ * Filename: cfag12864bfb.c
+ * Version: 0.1.0
+ * Description: cfag12864b LCD framebuffer driver
+ * License: GPLv2
+ * Depends: cfag12864b
+ *
+ * Author: Copyright (C) Miguel Ojeda Sandonis <maxextreme@gmail.com>
+ * Date: 2006-10-31
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fb.h>
+#include <linux/mm.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/uaccess.h>
+#include <linux/cfag12864b.h>
+
+#define CFAG12864BFB_NAME "cfag12864bfb"
+
+static struct fb_fix_screeninfo cfag12864bfb_fix __initdata = {
+ .id = "cfag12864b",
+ .type = FB_TYPE_PACKED_PIXELS,
+ .visual = FB_VISUAL_MONO10,
+ .xpanstep = 0,
+ .ypanstep = 0,
+ .ywrapstep = 0,
+ .line_length = CFAG12864B_WIDTH / 8,
+ .accel = FB_ACCEL_NONE,
+};
+
+static struct fb_var_screeninfo cfag12864bfb_var __initdata = {
+ .xres = CFAG12864B_WIDTH,
+ .yres = CFAG12864B_HEIGHT,
+ .xres_virtual = CFAG12864B_WIDTH,
+ .yres_virtual = CFAG12864B_HEIGHT,
+ .bits_per_pixel = 1,
+ .red = { 0, 1, 0 },
+ .green = { 0, 1, 0 },
+ .blue = { 0, 1, 0 },
+ .left_margin = 0,
+ .right_margin = 0,
+ .upper_margin = 0,
+ .lower_margin = 0,
+ .vmode = FB_VMODE_NONINTERLACED,
+};
+
+static int cfag12864bfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+ return vm_insert_page(vma, vma->vm_start,
+ virt_to_page(cfag12864b_buffer));
+}
+
+static struct fb_ops cfag12864bfb_ops = {
+ .owner = THIS_MODULE,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+ .fb_mmap = cfag12864bfb_mmap,
+};
+
+static int __init cfag12864bfb_probe(struct platform_device *device)
+{
+ int ret = -EINVAL;
+ struct fb_info *info = framebuffer_alloc(0, &device->dev);
+
+ if (!info)
+ goto none;
+
+ info->screen_base = (char __iomem *) cfag12864b_buffer;
+ info->screen_size = CFAG12864B_SIZE;
+ info->fbops = &cfag12864bfb_ops;
+ info->fix = cfag12864bfb_fix;
+ info->var = cfag12864bfb_var;
+ info->pseudo_palette = NULL;
+ info->par = NULL;
+ info->flags = FBINFO_FLAG_DEFAULT;
+
+ if (register_framebuffer(info) < 0)
+ goto fballoced;
+
+ platform_set_drvdata(device, info);
+
+ printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
+ info->fix.id);
+
+ return 0;
+
+fballoced:
+ framebuffer_release(info);
+
+none:
+ return ret;
+}
+
+static int cfag12864bfb_remove(struct platform_device *device)
+{
+ struct fb_info *info = platform_get_drvdata(device);
+
+ if (info) {
+ unregister_framebuffer(info);
+ framebuffer_release(info);
+ }
+
+ return 0;
+}
+
+static struct platform_driver cfag12864bfb_driver = {
+ .probe = cfag12864bfb_probe,
+ .remove = cfag12864bfb_remove,
+ .driver = {
+ .name = CFAG12864BFB_NAME,
+ },
+};
+
+static struct platform_device *cfag12864bfb_device;
+
+static int __init cfag12864bfb_init(void)
+{
+ int ret = -EINVAL;
+
+ /* cfag12864b_init() must be called first */
+ if (!cfag12864b_isinited()) {
+ printk(KERN_ERR CFAG12864BFB_NAME ": ERROR: "
+ "cfag12864b is not initialized\n");
+ goto none;
+ }
+
+ if (cfag12864b_enable()) {
+ printk(KERN_ERR CFAG12864BFB_NAME ": ERROR: "
+ "can't enable cfag12864b refreshing (being used)\n");
+ return -ENODEV;
+ }
+
+ ret = platform_driver_register(&cfag12864bfb_driver);
+
+ if (!ret) {
+ cfag12864bfb_device =
+ platform_device_alloc(CFAG12864BFB_NAME, 0);
+
+ if (cfag12864bfb_device)
+ ret = platform_device_add(cfag12864bfb_device);
+ else
+ ret = -ENOMEM;
+
+ if (ret) {
+ platform_device_put(cfag12864bfb_device);
+ platform_driver_unregister(&cfag12864bfb_driver);
+ }
+ }
+
+none:
+ return ret;
+}
+
+static void __exit cfag12864bfb_exit(void)
+{
+ platform_device_unregister(cfag12864bfb_device);
+ platform_driver_unregister(&cfag12864bfb_driver);
+ cfag12864b_disable();
+}
+
+module_init(cfag12864bfb_init);
+module_exit(cfag12864bfb_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Miguel Ojeda Sandonis <maxextreme@gmail.com>");
+MODULE_DESCRIPTION("cfag12864b LCD framebuffer driver");
diff --git a/drivers/auxdisplay/ks0108.c b/drivers/auxdisplay/ks0108.c
new file mode 100644
index 00000000000..e6c3646ef18
--- /dev/null
+++ b/drivers/auxdisplay/ks0108.c
@@ -0,0 +1,178 @@
+/*
+ * Filename: ks0108.c
+ * Version: 0.1.0
+ * Description: ks0108 LCD Controller driver
+ * License: GPLv2
+ * Depends: parport
+ *
+ * Author: Copyright (C) Miguel Ojeda Sandonis <maxextreme@gmail.com>
+ * Date: 2006-10-31
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/io.h>
+#include <linux/parport.h>
+#include <linux/uaccess.h>
+#include <linux/ks0108.h>
+
+#define KS0108_NAME "ks0108"
+
+/*
+ * Module Parameters
+ */
+
+static unsigned int ks0108_port = CONFIG_KS0108_PORT;
+module_param(ks0108_port, uint, S_IRUGO);
+MODULE_PARM_DESC(ks0108_port, "Parallel port where the LCD is connected");
+
+static unsigned int ks0108_delay = CONFIG_KS0108_DELAY;
+module_param(ks0108_delay, uint, S_IRUGO);
+MODULE_PARM_DESC(ks0108_delay, "Delay between each control writing (microseconds)");
+
+/*
+ * Device
+ */
+
+static struct parport *ks0108_parport;
+static struct pardevice *ks0108_pardevice;
+
+/*
+ * ks0108 Exported Commands (don't lock)
+ *
+ * You _should_ lock in the top driver: This functions _should not_
+ * get race conditions in any way. Locking for each byte here would be
+ * so slow and useless.
+ *
+ * There are not bit definitions because they are not flags,
+ * just arbitrary combinations defined by the documentation for each
+ * function in the ks0108 LCD controller. If you want to know what means
+ * a specific combination, look at the function's name.
+ *
+ * The ks0108_writecontrol bits need to be reverted ^(0,1,3) because
+ * the parallel port also revert them using a "not" logic gate.
+ */
+
+#define bit(n) (((unsigned char)1)<<(n))
+
+void ks0108_writedata(unsigned char byte)
+{
+ parport_write_data(ks0108_parport, byte);
+}
+
+void ks0108_writecontrol(unsigned char byte)
+{
+ udelay(ks0108_delay);
+ parport_write_control(ks0108_parport, byte ^ (bit(0) | bit(1) | bit(3)));
+}
+
+void ks0108_displaystate(unsigned char state)
+{
+ ks0108_writedata((state ? bit(0) : 0) | bit(1) | bit(2) | bit(3) | bit(4) | bit(5));
+}
+
+void ks0108_startline(unsigned char startline)
+{
+ ks0108_writedata(min(startline,(unsigned char)63) | bit(6) | bit(7));
+}
+
+void ks0108_address(unsigned char address)
+{
+ ks0108_writedata(min(address,(unsigned char)63) | bit(6));
+}
+
+void ks0108_page(unsigned char page)
+{
+ ks0108_writedata(min(page,(unsigned char)7) | bit(3) | bit(4) | bit(5) | bit(7));
+}
+
+EXPORT_SYMBOL_GPL(ks0108_writedata);
+EXPORT_SYMBOL_GPL(ks0108_writecontrol);
+EXPORT_SYMBOL_GPL(ks0108_displaystate);
+EXPORT_SYMBOL_GPL(ks0108_startline);
+EXPORT_SYMBOL_GPL(ks0108_address);
+EXPORT_SYMBOL_GPL(ks0108_page);
+
+/*
+ * Is the module inited?
+ */
+
+static unsigned char ks0108_inited;
+unsigned char ks0108_isinited(void)
+{
+ return ks0108_inited;
+}
+EXPORT_SYMBOL_GPL(ks0108_isinited);
+
+/*
+ * Module Init & Exit
+ */
+
+static int __init ks0108_init(void)
+{
+ int result;
+ int ret = -EINVAL;
+
+ ks0108_parport = parport_find_base(ks0108_port);
+ if (ks0108_parport == NULL) {
+ printk(KERN_ERR KS0108_NAME ": ERROR: "
+ "parport didn't find %i port\n", ks0108_port);
+ goto none;
+ }
+
+ ks0108_pardevice = parport_register_device(ks0108_parport, KS0108_NAME,
+ NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
+ if (ks0108_pardevice == NULL) {
+ printk(KERN_ERR KS0108_NAME ": ERROR: "
+ "parport didn't register new device\n");
+ goto none;
+ }
+
+ result = parport_claim(ks0108_pardevice);
+ if (result != 0) {
+ printk(KERN_ERR KS0108_NAME ": ERROR: "
+ "can't claim %i parport, maybe in use\n", ks0108_port);
+ ret = result;
+ goto registered;
+ }
+
+ ks0108_inited = 1;
+ return 0;
+
+registered:
+ parport_unregister_device(ks0108_pardevice);
+
+none:
+ return ret;
+}
+
+static void __exit ks0108_exit(void)
+{
+ parport_release(ks0108_pardevice);
+ parport_unregister_device(ks0108_pardevice);
+}
+
+module_init(ks0108_init);
+module_exit(ks0108_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Miguel Ojeda Sandonis <maxextreme@gmail.com>");
+MODULE_DESCRIPTION("ks0108 LCD Controller driver");
+
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
index 1429f3a2629..5d6312e3349 100644
--- a/drivers/base/Kconfig
+++ b/drivers/base/Kconfig
@@ -37,6 +37,18 @@ config DEBUG_DRIVER
If you are unsure about this, say N here.
+config DEBUG_DEVRES
+ bool "Managed device resources verbose debug messages"
+ depends on DEBUG_KERNEL
+ help
+ This option enables kernel parameter devres.log. If set to
+ non-zero, devres debug messages are printed. Select this if
+ you are having a problem with devres or want to debug
+ resource management for a managed device. devres.log can be
+ switched on and off from sysfs node.
+
+ If you are unsure about this, Say N here.
+
config SYS_HYPERVISOR
bool
default n
diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index 7bbb9eeda23..e9eb7382ac3 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -3,6 +3,7 @@
obj-y := core.o sys.o bus.o dd.o \
driver.o class.o platform.o \
cpu.o firmware.o init.o map.o dmapool.o \
+ dma-mapping.o devres.o \
attribute_container.o transport_class.o
obj-y += power/
obj-$(CONFIG_ISA) += isa.o
diff --git a/drivers/base/base.h b/drivers/base/base.h
index d26644a5953..de7e1442ce6 100644
--- a/drivers/base/base.h
+++ b/drivers/base/base.h
@@ -44,3 +44,4 @@ struct class_device_attribute *to_class_dev_attr(struct attribute *_attr)
extern char *make_class_name(const char *name, struct kobject *kobj);
+extern void devres_release_all(struct device *dev);
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index 472810f8e6e..253868e03c7 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -324,27 +324,25 @@ int bus_for_each_drv(struct bus_type * bus, struct device_driver * start,
return error;
}
-static int device_add_attrs(struct bus_type * bus, struct device * dev)
+static int device_add_attrs(struct bus_type *bus, struct device *dev)
{
int error = 0;
int i;
- if (bus->dev_attrs) {
- for (i = 0; attr_name(bus->dev_attrs[i]); i++) {
- error = device_create_file(dev,&bus->dev_attrs[i]);
- if (error)
- goto Err;
+ if (!bus->dev_attrs)
+ return 0;
+
+ for (i = 0; attr_name(bus->dev_attrs[i]); i++) {
+ error = device_create_file(dev,&bus->dev_attrs[i]);
+ if (error) {
+ while (--i >= 0)
+ device_remove_file(dev, &bus->dev_attrs[i]);
+ break;
}
}
- Done:
return error;
- Err:
- while (--i >= 0)
- device_remove_file(dev,&bus->dev_attrs[i]);
- goto Done;
}
-
static void device_remove_attrs(struct bus_type * bus, struct device * dev)
{
int i;
diff --git a/drivers/base/class.c b/drivers/base/class.c
index 8bf2ca2e56b..d5968128be2 100644
--- a/drivers/base/class.c
+++ b/drivers/base/class.c
@@ -163,8 +163,7 @@ int class_register(struct class * cls)
void class_unregister(struct class * cls)
{
pr_debug("device class '%s': unregistering\n", cls->name);
- if (cls->virtual_dir)
- kobject_unregister(cls->virtual_dir);
+ kobject_unregister(cls->virtual_dir);
remove_class_attrs(cls);
subsystem_unregister(&cls->subsys);
}
@@ -364,7 +363,7 @@ char *make_class_name(const char *name, struct kobject *kobj)
class_name = kmalloc(size, GFP_KERNEL);
if (!class_name)
- return ERR_PTR(-ENOMEM);
+ return NULL;
strcpy(class_name, name);
strcat(class_name, ":");
@@ -411,8 +410,11 @@ static int make_deprecated_class_device_links(struct class_device *class_dev)
return 0;
class_name = make_class_name(class_dev->class->name, &class_dev->kobj);
- error = sysfs_create_link(&class_dev->dev->kobj, &class_dev->kobj,
- class_name);
+ if (class_name)
+ error = sysfs_create_link(&class_dev->dev->kobj,
+ &class_dev->kobj, class_name);
+ else
+ error = -ENOMEM;
kfree(class_name);
return error;
}
@@ -425,7 +427,8 @@ static void remove_deprecated_class_device_links(struct class_device *class_dev)
return;
class_name = make_class_name(class_dev->class->name, &class_dev->kobj);
- sysfs_remove_link(&class_dev->dev->kobj, class_name);
+ if (class_name)
+ sysfs_remove_link(&class_dev->dev->kobj, class_name);
kfree(class_name);
}
#else
@@ -837,45 +840,6 @@ void class_device_destroy(struct class *cls, dev_t devt)
class_device_unregister(class_dev);
}
-int class_device_rename(struct class_device *class_dev, char *new_name)
-{
- int error = 0;
- char *old_class_name = NULL, *new_class_name = NULL;
-
- class_dev = class_device_get(class_dev);
- if (!class_dev)
- return -EINVAL;
-
- pr_debug("CLASS: renaming '%s' to '%s'\n", class_dev->class_id,
- new_name);
-
-#ifdef CONFIG_SYSFS_DEPRECATED
- if (class_dev->dev)
- old_class_name = make_class_name(class_dev->class->name,
- &class_dev->kobj);
-#endif
-
- strlcpy(class_dev->class_id, new_name, KOBJ_NAME_LEN);
-
- error = kobject_rename(&class_dev->kobj, new_name);
-
-#ifdef CONFIG_SYSFS_DEPRECATED
- if (class_dev->dev) {
- new_class_name = make_class_name(class_dev->class->name,
- &class_dev->kobj);
- sysfs_create_link(&class_dev->dev->kobj, &class_dev->kobj,
- new_class_name);
- sysfs_remove_link(&class_dev->dev->kobj, old_class_name);
- }
-#endif
- class_device_put(class_dev);
-
- kfree(old_class_name);
- kfree(new_class_name);
-
- return error;
-}
-
struct class_device * class_device_get(struct class_device *class_dev)
{
if (class_dev)
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 67b79a7592a..cf2a398aaaa 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -28,6 +28,20 @@ int (*platform_notify)(struct device * dev) = NULL;
int (*platform_notify_remove)(struct device * dev) = NULL;
/*
+ * Detect the LANANA-assigned LOCAL/EXPERIMENTAL majors
+ */
+bool is_lanana_major(unsigned int major)
+{
+ if (major >= 60 && major <= 63)
+ return 1;
+ if (major >= 120 && major <= 127)
+ return 1;
+ if (major >= 240 && major <= 254)
+ return 1;
+ return 0;
+}
+
+/*
* sysfs bindings for devices.
*/
@@ -95,6 +109,8 @@ static void device_release(struct kobject * kobj)
if (dev->release)
dev->release(dev);
+ else if (dev->type && dev->type->release)
+ dev->type->release(dev);
else if (dev->class && dev->class->dev_release)
dev->class->dev_release(dev);
else {
@@ -154,25 +170,47 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp,
"MINOR=%u", MINOR(dev->devt));
}
-#ifdef CONFIG_SYSFS_DEPRECATED
- /* add bus name (same as SUBSYSTEM, deprecated) */
- if (dev->bus)
- add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "PHYSDEVBUS=%s", dev->bus->name);
-#endif
-
- /* add driver name (PHYSDEV* values are deprecated)*/
- if (dev->driver) {
+ if (dev->driver)
add_uevent_var(envp, num_envp, &i,
buffer, buffer_size, &length,
"DRIVER=%s", dev->driver->name);
+
#ifdef CONFIG_SYSFS_DEPRECATED
+ if (dev->class) {
+ struct device *parent = dev->parent;
+
+ /* find first bus device in parent chain */
+ while (parent && !parent->bus)
+ parent = parent->parent;
+ if (parent && parent->bus) {
+ const char *path;
+
+ path = kobject_get_path(&parent->kobj, GFP_KERNEL);
+ add_uevent_var(envp, num_envp, &i,
+ buffer, buffer_size, &length,
+ "PHYSDEVPATH=%s", path);
+ kfree(path);
+
+ add_uevent_var(envp, num_envp, &i,
+ buffer, buffer_size, &length,
+ "PHYSDEVBUS=%s", parent->bus->name);
+
+ if (parent->driver)
+ add_uevent_var(envp, num_envp, &i,
+ buffer, buffer_size, &length,
+ "PHYSDEVDRIVER=%s", parent->driver->name);
+ }
+ } else if (dev->bus) {
add_uevent_var(envp, num_envp, &i,
buffer, buffer_size, &length,
- "PHYSDEVDRIVER=%s", dev->driver->name);
-#endif
+ "PHYSDEVBUS=%s", dev->bus->name);
+
+ if (dev->driver)
+ add_uevent_var(envp, num_envp, &i,
+ buffer, buffer_size, &length,
+ "PHYSDEVDRIVER=%s", dev->driver->name);
}
+#endif
/* terminate, set to next free slot, shrink available space */
envp[i] = NULL;
@@ -184,19 +222,25 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp,
if (dev->bus && dev->bus->uevent) {
/* have the bus specific function add its stuff */
retval = dev->bus->uevent(dev, envp, num_envp, buffer, buffer_size);
- if (retval) {
- pr_debug ("%s - uevent() returned %d\n",
+ if (retval)
+ pr_debug ("%s: bus uevent() returned %d\n",
__FUNCTION__, retval);
- }
}
if (dev->class && dev->class->dev_uevent) {
/* have the class specific function add its stuff */
retval = dev->class->dev_uevent(dev, envp, num_envp, buffer, buffer_size);
- if (retval) {
- pr_debug("%s - dev_uevent() returned %d\n",
- __FUNCTION__, retval);
- }
+ if (retval)
+ pr_debug("%s: class uevent() returned %d\n",
+ __FUNCTION__, retval);
+ }
+
+ if (dev->type && dev->type->uevent) {
+ /* have the device type specific fuction add its stuff */
+ retval = dev->type->uevent(dev, envp, num_envp, buffer, buffer_size);
+ if (retval)
+ pr_debug("%s: dev_type uevent() returned %d\n",
+ __FUNCTION__, retval);
}
return retval;
@@ -247,37 +291,50 @@ static void device_remove_groups(struct device *dev)
static int device_add_attrs(struct device *dev)
{
struct class *class = dev->class;
+ struct device_type *type = dev->type;
int error = 0;
int i;
- if (!class)
- return 0;
-
- if (class->dev_attrs) {
+ if (class && class->dev_attrs) {
for (i = 0; attr_name(class->dev_attrs[i]); i++) {
error = device_create_file(dev, &class->dev_attrs[i]);
if (error)
break;
}
+ if (error)
+ while (--i >= 0)
+ device_remove_file(dev, &class->dev_attrs[i]);
}
- if (error)
- while (--i >= 0)
- device_remove_file(dev, &class->dev_attrs[i]);
+
+ if (type && type->attrs) {
+ for (i = 0; attr_name(type->attrs[i]); i++) {
+ error = device_create_file(dev, &type->attrs[i]);
+ if (error)
+ break;
+ }
+ if (error)
+ while (--i >= 0)
+ device_remove_file(dev, &type->attrs[i]);
+ }
+
return error;
}
static void device_remove_attrs(struct device *dev)
{
struct class *class = dev->class;
+ struct device_type *type = dev->type;
int i;
- if (!class)
- return;
-
- if (class->dev_attrs) {
+ if (class && class->dev_attrs) {
for (i = 0; attr_name(class->dev_attrs[i]); i++)
device_remove_file(dev, &class->dev_attrs[i]);
}
+
+ if (type && type->attrs) {
+ for (i = 0; attr_name(type->attrs[i]); i++)
+ device_remove_file(dev, &type->attrs[i]);
+ }
}
@@ -385,27 +442,30 @@ void device_initialize(struct device *dev)
INIT_LIST_HEAD(&dev->dma_pools);
INIT_LIST_HEAD(&dev->node);
init_MUTEX(&dev->sem);
+ spin_lock_init(&dev->devres_lock);
+ INIT_LIST_HEAD(&dev->devres_head);
device_init_wakeup(dev, 0);
set_dev_node(dev, -1);
}
#ifdef CONFIG_SYSFS_DEPRECATED
-static int setup_parent(struct device *dev, struct device *parent)
+static struct kobject * get_device_parent(struct device *dev,
+ struct device *parent)
{
/* Set the parent to the class, not the parent device */
/* this keeps sysfs from having a symlink to make old udevs happy */
if (dev->class)
- dev->kobj.parent = &dev->class->subsys.kset.kobj;
+ return &dev->class->subsys.kset.kobj;
else if (parent)
- dev->kobj.parent = &parent->kobj;
+ return &parent->kobj;
- return 0;
+ return NULL;
}
#else
-static int virtual_device_parent(struct device *dev)
+static struct kobject * virtual_device_parent(struct device *dev)
{
if (!dev->class)
- return -ENODEV;
+ return ERR_PTR(-ENODEV);
if (!dev->class->virtual_dir) {
static struct kobject *virtual_dir = NULL;
@@ -415,25 +475,31 @@ static int virtual_device_parent(struct device *dev)
dev->class->virtual_dir = kobject_add_dir(virtual_dir, dev->class->name);
}
- dev->kobj.parent = dev->class->virtual_dir;
- return 0;
+ return dev->class->virtual_dir;
}
-static int setup_parent(struct device *dev, struct device *parent)
+static struct kobject * get_device_parent(struct device *dev,
+ struct device *parent)
{
- int error;
-
/* if this is a class device, and has no parent, create one */
if ((dev->class) && (parent == NULL)) {
- error = virtual_device_parent(dev);
- if (error)
- return error;
+ return virtual_device_parent(dev);
} else if (parent)
- dev->kobj.parent = &parent->kobj;
+ return &parent->kobj;
+ return NULL;
+}
+#endif
+static int setup_parent(struct device *dev, struct device *parent)
+{
+ struct kobject *kobj;
+ kobj = get_device_parent(dev, parent);
+ if (IS_ERR(kobj))
+ return PTR_ERR(kobj);
+ if (kobj)
+ dev->kobj.parent = kobj;
return 0;
}
-#endif
/**
* device_add - add device to device hierarchy.
@@ -520,9 +586,13 @@ int device_add(struct device *dev)
&dev->kobj, dev->bus_id);
#ifdef CONFIG_SYSFS_DEPRECATED
if (parent) {
- sysfs_create_link(&dev->kobj, &dev->parent->kobj, "device");
- class_name = make_class_name(dev->class->name, &dev->kobj);
- sysfs_create_link(&dev->parent->kobj, &dev->kobj, class_name);
+ sysfs_create_link(&dev->kobj, &dev->parent->kobj,
+ "device");
+ class_name = make_class_name(dev->class->name,
+ &dev->kobj);
+ if (class_name)
+ sysfs_create_link(&dev->parent->kobj,
+ &dev->kobj, class_name);
}
#endif
}
@@ -535,7 +605,8 @@ int device_add(struct device *dev)
goto PMError;
if ((error = bus_add_device(dev)))
goto BusError;
- kobject_uevent(&dev->kobj, KOBJ_ADD);
+ if (!dev->uevent_suppress)
+ kobject_uevent(&dev->kobj, KOBJ_ADD);
if ((error = bus_attach_device(dev)))
goto AttachError;
if (parent)
@@ -566,12 +637,41 @@ int device_add(struct device *dev)
BUS_NOTIFY_DEL_DEVICE, dev);
device_remove_groups(dev);
GroupError:
- device_remove_attrs(dev);
+ device_remove_attrs(dev);
AttrsError:
if (dev->devt_attr) {
device_remove_file(dev, dev->devt_attr);
kfree(dev->devt_attr);
}
+
+ if (dev->class) {
+ sysfs_remove_link(&dev->kobj, "subsystem");
+ /* If this is not a "fake" compatible device, remove the
+ * symlink from the class to the device. */
+ if (dev->kobj.parent != &dev->class->subsys.kset.kobj)
+ sysfs_remove_link(&dev->class->subsys.kset.kobj,
+ dev->bus_id);
+#ifdef CONFIG_SYSFS_DEPRECATED
+ if (parent) {
+ char *class_name = make_class_name(dev->class->name,
+ &dev->kobj);
+ if (class_name)
+ sysfs_remove_link(&dev->parent->kobj,
+ class_name);
+ kfree(class_name);
+ sysfs_remove_link(&dev->kobj, "device");
+ }
+#endif
+
+ down(&dev->class->sem);
+ /* notify any interfaces that the device is now gone */
+ list_for_each_entry(class_intf, &dev->class->interfaces, node)
+ if (class_intf->remove_dev)
+ class_intf->remove_dev(dev, class_intf);
+ /* remove the device from the class list */
+ list_del_init(&dev->node);
+ up(&dev->class->sem);
+ }
ueventattrError:
device_remove_file(dev, &dev->uevent_attr);
attrError:
@@ -665,7 +765,9 @@ void device_del(struct device * dev)
if (parent) {
char *class_name = make_class_name(dev->class->name,
&dev->kobj);
- sysfs_remove_link(&dev->parent->kobj, class_name);
+ if (class_name)
+ sysfs_remove_link(&dev->parent->kobj,
+ class_name);
kfree(class_name);
sysfs_remove_link(&dev->kobj, "device");
}
@@ -968,20 +1070,25 @@ static int device_move_class_links(struct device *dev,
class_name = make_class_name(dev->class->name, &dev->kobj);
if (!class_name) {
- error = PTR_ERR(class_name);
- class_name = NULL;
+ error = -ENOMEM;
goto out;
}
if (old_parent) {
sysfs_remove_link(&dev->kobj, "device");
sysfs_remove_link(&old_parent->kobj, class_name);
}
- error = sysfs_create_link(&dev->kobj, &new_parent->kobj, "device");
- if (error)
- goto out;
- error = sysfs_create_link(&new_parent->kobj, &dev->kobj, class_name);
- if (error)
- sysfs_remove_link(&dev->kobj, "device");
+ if (new_parent) {
+ error = sysfs_create_link(&dev->kobj, &new_parent->kobj,
+ "device");
+ if (error)
+ goto out;
+ error = sysfs_create_link(&new_parent->kobj, &dev->kobj,
+ class_name);
+ if (error)
+ sysfs_remove_link(&dev->kobj, "device");
+ }
+ else
+ error = 0;
out:
kfree(class_name);
return error;
@@ -993,29 +1100,28 @@ out:
/**
* device_move - moves a device to a new parent
* @dev: the pointer to the struct device to be moved
- * @new_parent: the new parent of the device
+ * @new_parent: the new parent of the device (can by NULL)
*/
int device_move(struct device *dev, struct device *new_parent)
{
int error;
struct device *old_parent;
+ struct kobject *new_parent_kobj;
dev = get_device(dev);
if (!dev)
return -EINVAL;
- if (!device_is_registered(dev)) {
- error = -EINVAL;
- goto out;
- }
new_parent = get_device(new_parent);
- if (!new_parent) {
- error = -EINVAL;
+ new_parent_kobj = get_device_parent (dev, new_parent);
+ if (IS_ERR(new_parent_kobj)) {
+ error = PTR_ERR(new_parent_kobj);
+ put_device(new_parent);
goto out;
}
pr_debug("DEVICE: moving '%s' to '%s'\n", dev->bus_id,
- new_parent->bus_id);
- error = kobject_move(&dev->kobj, &new_parent->kobj);
+ new_parent ? new_parent->bus_id : "<NULL>");
+ error = kobject_move(&dev->kobj, new_parent_kobj);
if (error) {
put_device(new_parent);
goto out;
@@ -1024,7 +1130,8 @@ int device_move(struct device *dev, struct device *new_parent)
dev->parent = new_parent;
if (old_parent)
klist_remove(&dev->knode_parent);
- klist_add_tail(&dev->knode_parent, &new_parent->klist_children);
+ if (new_parent)
+ klist_add_tail(&dev->knode_parent, &new_parent->klist_children);
if (!dev->class)
goto out_put;
error = device_move_class_links(dev, old_parent, new_parent);
@@ -1032,7 +1139,8 @@ int device_move(struct device *dev, struct device *new_parent)
/* We ignore errors on cleanup since we're hosed anyway... */
device_move_class_links(dev, new_parent, old_parent);
if (!kobject_move(&dev->kobj, &old_parent->kobj)) {
- klist_remove(&dev->knode_parent);
+ if (new_parent)
+ klist_remove(&dev->knode_parent);
if (old_parent)
klist_add_tail(&dev->knode_parent,
&old_parent->klist_children);
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index 7fd095efaeb..fe7ef339414 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -103,7 +103,7 @@ static SYSDEV_ATTR(crash_notes, 0400, show_crash_notes, NULL);
#endif
/*
- * register_cpu - Setup a driverfs device for a CPU.
+ * register_cpu - Setup a sysfs device for a CPU.
* @cpu - cpu->hotpluggable field set to 1 will generate a control file in
* sysfs for this CPU.
* @num - CPU number to use when creating the device.
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index 510e7884975..6a48824e43f 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -86,8 +86,12 @@ static void driver_sysfs_remove(struct device *dev)
*/
int device_bind_driver(struct device *dev)
{
- driver_bound(dev);
- return driver_sysfs_add(dev);
+ int ret;
+
+ ret = driver_sysfs_add(dev);
+ if (!ret)
+ driver_bound(dev);
+ return ret;
}
struct stupid_thread_structure {
@@ -108,6 +112,7 @@ static int really_probe(void *void_data)
atomic_inc(&probe_count);
pr_debug("%s: Probing driver %s with device %s\n",
drv->bus->name, drv->name, dev->bus_id);
+ WARN_ON(!list_empty(&dev->devres_head));
dev->driver = drv;
if (driver_sysfs_add(dev)) {
@@ -133,21 +138,21 @@ static int really_probe(void *void_data)
goto done;
probe_failed:
+ devres_release_all(dev);
driver_sysfs_remove(dev);
dev->driver = NULL;
- if (ret == -ENODEV || ret == -ENXIO) {
- /* Driver matched, but didn't support device
- * or device not found.
- * Not an error; keep going.
- */
- ret = 0;
- } else {
+ if (ret != -ENODEV && ret != -ENXIO) {
/* driver matched but the probe failed */
printk(KERN_WARNING
"%s: probe of %s failed with error %d\n",
drv->name, dev->bus_id, ret);
}
+ /*
+ * Ignore errors returned by ->probe so that the next driver can try
+ * its luck.
+ */
+ ret = 0;
done:
kfree(data);
atomic_dec(&probe_count);
@@ -324,6 +329,7 @@ static void __device_release_driver(struct device * dev)
dev->bus->remove(dev);
else if (drv->remove)
drv->remove(dev);
+ devres_release_all(dev);
dev->driver = NULL;
put_driver(drv);
}
diff --git a/drivers/base/devres.c b/drivers/base/devres.c
new file mode 100644
index 00000000000..e177c9533b6
--- /dev/null
+++ b/drivers/base/devres.c
@@ -0,0 +1,644 @@
+/*
+ * drivers/base/devres.c - device resource management
+ *
+ * Copyright (c) 2006 SUSE Linux Products GmbH
+ * Copyright (c) 2006 Tejun Heo <teheo@suse.de>
+ *
+ * This file is released under the GPLv2.
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+
+struct devres_node {
+ struct list_head entry;
+ dr_release_t release;
+#ifdef CONFIG_DEBUG_DEVRES
+ const char *name;
+ size_t size;
+#endif
+};
+
+struct devres {
+ struct devres_node node;
+ /* -- 3 pointers */
+ unsigned long long data[]; /* guarantee ull alignment */
+};
+
+struct devres_group {
+ struct devres_node node[2];
+ void *id;
+ int color;
+ /* -- 8 pointers */
+};
+
+#ifdef CONFIG_DEBUG_DEVRES
+static int log_devres = 0;
+module_param_named(log, log_devres, int, S_IRUGO | S_IWUSR);
+
+static void set_node_dbginfo(struct devres_node *node, const char *name,
+ size_t size)
+{
+ node->name = name;
+ node->size = size;
+}
+
+static void devres_log(struct device *dev, struct devres_node *node,
+ const char *op)
+{
+ if (unlikely(log_devres))
+ dev_printk(KERN_ERR, dev, "DEVRES %3s %p %s (%lu bytes)\n",
+ op, node, node->name, (unsigned long)node->size);
+}
+#else /* CONFIG_DEBUG_DEVRES */
+#define set_node_dbginfo(node, n, s) do {} while (0)
+#define devres_log(dev, node, op) do {} while (0)
+#endif /* CONFIG_DEBUG_DEVRES */
+
+/*
+ * Release functions for devres group. These callbacks are used only
+ * for identification.
+ */
+static void group_open_release(struct device *dev, void *res)
+{
+ /* noop */
+}
+
+static void group_close_release(struct device *dev, void *res)
+{
+ /* noop */
+}
+
+static struct devres_group * node_to_group(struct devres_node *node)
+{
+ if (node->release == &group_open_release)
+ return container_of(node, struct devres_group, node[0]);
+ if (node->release == &group_close_release)
+ return container_of(node, struct devres_group, node[1]);
+ return NULL;
+}
+
+static __always_inline struct devres * alloc_dr(dr_release_t release,
+ size_t size, gfp_t gfp)
+{
+ size_t tot_size = sizeof(struct devres) + size;
+ struct devres *dr;
+
+ dr = kmalloc_track_caller(tot_size, gfp);
+ if (unlikely(!dr))
+ return NULL;
+
+ memset(dr, 0, tot_size);
+ INIT_LIST_HEAD(&dr->node.entry);
+ dr->node.release = release;
+ return dr;
+}
+
+static void add_dr(struct device *dev, struct devres_node *node)
+{
+ devres_log(dev, node, "ADD");
+ BUG_ON(!list_empty(&node->entry));
+ list_add_tail(&node->entry, &dev->devres_head);
+}
+
+/**
+ * devres_alloc - Allocate device resource data
+ * @release: Release function devres will be associated with
+ * @size: Allocation size
+ * @gfp: Allocation flags
+ *
+ * allocate devres of @size bytes. The allocated area is zeroed, then
+ * associated with @release. The returned pointer can be passed to
+ * other devres_*() functions.
+ *
+ * RETURNS:
+ * Pointer to allocated devres on success, NULL on failure.
+ */
+#ifdef CONFIG_DEBUG_DEVRES
+void * __devres_alloc(dr_release_t release, size_t size, gfp_t gfp,
+ const char *name)
+{
+ struct devres *dr;
+
+ dr = alloc_dr(release, size, gfp);
+ if (unlikely(!dr))
+ return NULL;
+ set_node_dbginfo(&dr->node, name, size);
+ return dr->data;
+}
+EXPORT_SYMBOL_GPL(__devres_alloc);
+#else
+void * devres_alloc(dr_release_t release, size_t size, gfp_t gfp)
+{
+ struct devres *dr;
+
+ dr = alloc_dr(release, size, gfp);
+ if (unlikely(!dr))
+ return NULL;
+ return dr->data;
+}
+EXPORT_SYMBOL_GPL(devres_alloc);
+#endif
+
+/**
+ * devres_free - Free device resource data
+ * @res: Pointer to devres data to free
+ *
+ * Free devres created with devres_alloc().
+ */
+void devres_free(void *res)
+{
+ if (res) {
+ struct devres *dr = container_of(res, struct devres, data);
+
+ BUG_ON(!list_empty(&dr->node.entry));
+ kfree(dr);
+ }
+}
+EXPORT_SYMBOL_GPL(devres_free);
+
+/**
+ * devres_add - Register device resource
+ * @dev: Device to add resource to
+ * @res: Resource to register
+ *
+ * Register devres @res to @dev. @res should have been allocated
+ * using devres_alloc(). On driver detach, the associated release
+ * function will be invoked and devres will be freed automatically.
+ */
+void devres_add(struct device *dev, void *res)
+{
+ struct devres *dr = container_of(res, struct devres, data);
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->devres_lock, flags);
+ add_dr(dev, &dr->node);
+ spin_unlock_irqrestore(&dev->devres_lock, flags);
+}
+EXPORT_SYMBOL_GPL(devres_add);
+
+static struct devres *find_dr(struct device *dev, dr_release_t release,
+ dr_match_t match, void *match_data)
+{
+ struct devres_node *node;
+
+ list_for_each_entry_reverse(node, &dev->devres_head, entry) {
+ struct devres *dr = container_of(node, struct devres, node);
+
+ if (node->release != release)
+ continue;
+ if (match && !match(dev, dr->data, match_data))
+ continue;
+ return dr;
+ }
+
+ return NULL;
+}
+
+/**
+ * devres_find - Find device resource
+ * @dev: Device to lookup resource from
+ * @release: Look for resources associated with this release function
+ * @match: Match function (optional)
+ * @match_data: Data for the match function
+ *
+ * Find the latest devres of @dev which is associated with @release
+ * and for which @match returns 1. If @match is NULL, it's considered
+ * to match all.
+ *
+ * RETURNS:
+ * Pointer to found devres, NULL if not found.
+ */
+void * devres_find(struct device *dev, dr_release_t release,
+ dr_match_t match, void *match_data)
+{
+ struct devres *dr;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->devres_lock, flags);
+ dr = find_dr(dev, release, match, match_data);
+ spin_unlock_irqrestore(&dev->devres_lock, flags);
+
+ if (dr)
+ return dr->data;
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(devres_find);
+
+/**
+ * devres_get - Find devres, if non-existent, add one atomically
+ * @dev: Device to lookup or add devres for
+ * @new_res: Pointer to new initialized devres to add if not found
+ * @match: Match function (optional)
+ * @match_data: Data for the match function
+ *
+ * Find the latest devres of @dev which has the same release function
+ * as @new_res and for which @match return 1. If found, @new_res is
+ * freed; otherwise, @new_res is added atomically.
+ *
+ * RETURNS:
+ * Pointer to found or added devres.
+ */
+void * devres_get(struct device *dev, void *new_res,
+ dr_match_t match, void *match_data)
+{
+ struct devres *new_dr = container_of(new_res, struct devres, data);
+ struct devres *dr;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->devres_lock, flags);
+ dr = find_dr(dev, new_dr->node.release, match, match_data);
+ if (!dr) {
+ add_dr(dev, &new_dr->node);
+ dr = new_dr;
+ new_dr = NULL;
+ }
+ spin_unlock_irqrestore(&dev->devres_lock, flags);
+ devres_free(new_dr);
+
+ return dr->data;
+}
+EXPORT_SYMBOL_GPL(devres_get);
+
+/**
+ * devres_remove - Find a device resource and remove it
+ * @dev: Device to find resource from
+ * @release: Look for resources associated with this release function
+ * @match: Match function (optional)
+ * @match_data: Data for the match function
+ *
+ * Find the latest devres of @dev associated with @release and for
+ * which @match returns 1. If @match is NULL, it's considered to
+ * match all. If found, the resource is removed atomically and
+ * returned.
+ *
+ * RETURNS:
+ * Pointer to removed devres on success, NULL if not found.
+ */
+void * devres_remove(struct device *dev, dr_release_t release,
+ dr_match_t match, void *match_data)
+{
+ struct devres *dr;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->devres_lock, flags);
+ dr = find_dr(dev, release, match, match_data);
+ if (dr) {
+ list_del_init(&dr->node.entry);
+ devres_log(dev, &dr->node, "REM");
+ }
+ spin_unlock_irqrestore(&dev->devres_lock, flags);
+
+ if (dr)
+ return dr->data;
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(devres_remove);
+
+/**
+ * devres_destroy - Find a device resource and destroy it
+ * @dev: Device to find resource from
+ * @release: Look for resources associated with this release function
+ * @match: Match function (optional)
+ * @match_data: Data for the match function
+ *
+ * Find the latest devres of @dev associated with @release and for
+ * which @match returns 1. If @match is NULL, it's considered to
+ * match all. If found, the resource is removed atomically and freed.
+ *
+ * RETURNS:
+ * 0 if devres is found and freed, -ENOENT if not found.
+ */
+int devres_destroy(struct device *dev, dr_release_t release,
+ dr_match_t match, void *match_data)
+{
+ void *res;
+
+ res = devres_remove(dev, release, match, match_data);
+ if (unlikely(!res))
+ return -ENOENT;
+
+ devres_free(res);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(devres_destroy);
+
+static int remove_nodes(struct device *dev,
+ struct list_head *first, struct list_head *end,
+ struct list_head *todo)
+{
+ int cnt = 0, nr_groups = 0;
+ struct list_head *cur;
+
+ /* First pass - move normal devres entries to @todo and clear
+ * devres_group colors.
+ */
+ cur = first;
+ while (cur != end) {
+ struct devres_node *node;
+ struct devres_group *grp;
+
+ node = list_entry(cur, struct devres_node, entry);
+ cur = cur->next;
+
+ grp = node_to_group(node);
+ if (grp) {
+ /* clear color of group markers in the first pass */
+ grp->color = 0;
+ nr_groups++;
+ } else {
+ /* regular devres entry */
+ if (&node->entry == first)
+ first = first->next;
+ list_move_tail(&node->entry, todo);
+ cnt++;
+ }
+ }
+
+ if (!nr_groups)
+ return cnt;
+
+ /* Second pass - Scan groups and color them. A group gets
+ * color value of two iff the group is wholly contained in
+ * [cur, end). That is, for a closed group, both opening and
+ * closing markers should be in the range, while just the
+ * opening marker is enough for an open group.
+ */
+ cur = first;
+ while (cur != end) {
+ struct devres_node *node;
+ struct devres_group *grp;
+
+ node = list_entry(cur, struct devres_node, entry);
+ cur = cur->next;
+
+ grp = node_to_group(node);
+ BUG_ON(!grp || list_empty(&grp->node[0].entry));
+
+ grp->color++;
+ if (list_empty(&grp->node[1].entry))
+ grp->color++;
+
+ BUG_ON(grp->color <= 0 || grp->color > 2);
+ if (grp->color == 2) {
+ /* No need to update cur or end. The removed
+ * nodes are always before both.
+ */
+ list_move_tail(&grp->node[0].entry, todo);
+ list_del_init(&grp->node[1].entry);
+ }
+ }
+
+ return cnt;
+}
+
+static int release_nodes(struct device *dev, struct list_head *first,
+ struct list_head *end, unsigned long flags)
+{
+ LIST_HEAD(todo);
+ int cnt;
+ struct devres *dr, *tmp;
+
+ cnt = remove_nodes(dev, first, end, &todo);
+
+ spin_unlock_irqrestore(&dev->devres_lock, flags);
+
+ /* Release. Note that both devres and devres_group are
+ * handled as devres in the following loop. This is safe.
+ */
+ list_for_each_entry_safe_reverse(dr, tmp, &todo, node.entry) {
+ devres_log(dev, &dr->node, "REL");
+ dr->node.release(dev, dr->data);
+ kfree(dr);
+ }
+
+ return cnt;
+}
+
+/**
+ * devres_release_all - Release all resources
+ * @dev: Device to release resources for
+ *
+ * Release all resources associated with @dev. This function is
+ * called on driver detach.
+ */
+int devres_release_all(struct device *dev)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->devres_lock, flags);
+ return release_nodes(dev, dev->devres_head.next, &dev->devres_head,
+ flags);
+}
+
+/**
+ * devres_open_group - Open a new devres group
+ * @dev: Device to open devres group for
+ * @id: Separator ID
+ * @gfp: Allocation flags
+ *
+ * Open a new devres group for @dev with @id. For @id, using a
+ * pointer to an object which won't be used for another group is
+ * recommended. If @id is NULL, address-wise unique ID is created.
+ *
+ * RETURNS:
+ * ID of the new group, NULL on failure.
+ */
+void * devres_open_group(struct device *dev, void *id, gfp_t gfp)
+{
+ struct devres_group *grp;
+ unsigned long flags;
+
+ grp = kmalloc(sizeof(*grp), gfp);
+ if (unlikely(!grp))
+ return NULL;
+
+ grp->node[0].release = &group_open_release;
+ grp->node[1].release = &group_close_release;
+ INIT_LIST_HEAD(&grp->node[0].entry);
+ INIT_LIST_HEAD(&grp->node[1].entry);
+ set_node_dbginfo(&grp->node[0], "grp<", 0);
+ set_node_dbginfo(&grp->node[1], "grp>", 0);
+ grp->id = grp;
+ if (id)
+ grp->id = id;
+
+ spin_lock_irqsave(&dev->devres_lock, flags);
+ add_dr(dev, &grp->node[0]);
+ spin_unlock_irqrestore(&dev->devres_lock, flags);
+ return grp->id;
+}
+EXPORT_SYMBOL_GPL(devres_open_group);
+
+/* Find devres group with ID @id. If @id is NULL, look for the latest. */
+static struct devres_group * find_group(struct device *dev, void *id)
+{
+ struct devres_node *node;
+
+ list_for_each_entry_reverse(node, &dev->devres_head, entry) {
+ struct devres_group *grp;
+
+ if (node->release != &group_open_release)
+ continue;
+
+ grp = container_of(node, struct devres_group, node[0]);
+
+ if (id) {
+ if (grp->id == id)
+ return grp;
+ } else if (list_empty(&grp->node[1].entry))
+ return grp;
+ }
+
+ return NULL;
+}
+
+/**
+ * devres_close_group - Close a devres group
+ * @dev: Device to close devres group for
+ * @id: ID of target group, can be NULL
+ *
+ * Close the group identified by @id. If @id is NULL, the latest open
+ * group is selected.
+ */
+void devres_close_group(struct device *dev, void *id)
+{
+ struct devres_group *grp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->devres_lock, flags);
+
+ grp = find_group(dev, id);
+ if (grp)
+ add_dr(dev, &grp->node[1]);
+ else
+ WARN_ON(1);
+
+ spin_unlock_irqrestore(&dev->devres_lock, flags);
+}
+EXPORT_SYMBOL_GPL(devres_close_group);
+
+/**
+ * devres_remove_group - Remove a devres group
+ * @dev: Device to remove group for
+ * @id: ID of target group, can be NULL
+ *
+ * Remove the group identified by @id. If @id is NULL, the latest
+ * open group is selected. Note that removing a group doesn't affect
+ * any other resources.
+ */
+void devres_remove_group(struct device *dev, void *id)
+{
+ struct devres_group *grp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->devres_lock, flags);
+
+ grp = find_group(dev, id);
+ if (grp) {
+ list_del_init(&grp->node[0].entry);
+ list_del_init(&grp->node[1].entry);
+ devres_log(dev, &grp->node[0], "REM");
+ } else
+ WARN_ON(1);
+
+ spin_unlock_irqrestore(&dev->devres_lock, flags);
+
+ kfree(grp);
+}
+EXPORT_SYMBOL_GPL(devres_remove_group);
+
+/**
+ * devres_release_group - Release resources in a devres group
+ * @dev: Device to release group for
+ * @id: ID of target group, can be NULL
+ *
+ * Release all resources in the group identified by @id. If @id is
+ * NULL, the latest open group is selected. The selected group and
+ * groups properly nested inside the selected group are removed.
+ *
+ * RETURNS:
+ * The number of released non-group resources.
+ */
+int devres_release_group(struct device *dev, void *id)
+{
+ struct devres_group *grp;
+ unsigned long flags;
+ int cnt = 0;
+
+ spin_lock_irqsave(&dev->devres_lock, flags);
+
+ grp = find_group(dev, id);
+ if (grp) {
+ struct list_head *first = &grp->node[0].entry;
+ struct list_head *end = &dev->devres_head;
+
+ if (!list_empty(&grp->node[1].entry))
+ end = grp->node[1].entry.next;
+
+ cnt = release_nodes(dev, first, end, flags);
+ } else {
+ WARN_ON(1);
+ spin_unlock_irqrestore(&dev->devres_lock, flags);
+ }
+
+ return cnt;
+}
+EXPORT_SYMBOL_GPL(devres_release_group);
+
+/*
+ * Managed kzalloc/kfree
+ */
+static void devm_kzalloc_release(struct device *dev, void *res)
+{
+ /* noop */
+}
+
+static int devm_kzalloc_match(struct device *dev, void *res, void *data)
+{
+ return res == data;
+}
+
+/**
+ * devm_kzalloc - Managed kzalloc
+ * @dev: Device to allocate memory for
+ * @size: Allocation size
+ * @gfp: Allocation gfp flags
+ *
+ * Managed kzalloc. Memory allocated with this function is
+ * automatically freed on driver detach. Like all other devres
+ * resources, guaranteed alignment is unsigned long long.
+ *
+ * RETURNS:
+ * Pointer to allocated memory on success, NULL on failure.
+ */
+void * devm_kzalloc(struct device *dev, size_t size, gfp_t gfp)
+{
+ struct devres *dr;
+
+ /* use raw alloc_dr for kmalloc caller tracing */
+ dr = alloc_dr(devm_kzalloc_release, size, gfp);
+ if (unlikely(!dr))
+ return NULL;
+
+ set_node_dbginfo(&dr->node, "devm_kzalloc_release", size);
+ devres_add(dev, dr->data);
+ return dr->data;
+}
+EXPORT_SYMBOL_GPL(devm_kzalloc);
+
+/**
+ * devm_kfree - Managed kfree
+ * @dev: Device this memory belongs to
+ * @p: Memory to free
+ *
+ * Free memory allocated with dev_kzalloc().
+ */
+void devm_kfree(struct device *dev, void *p)
+{
+ int rc;
+
+ rc = devres_destroy(dev, devm_kzalloc_release, devm_kzalloc_match, p);
+ WARN_ON(rc);
+}
+EXPORT_SYMBOL_GPL(devm_kfree);
diff --git a/drivers/base/dma-mapping.c b/drivers/base/dma-mapping.c
new file mode 100644
index 00000000000..ca9186f70a6
--- /dev/null
+++ b/drivers/base/dma-mapping.c
@@ -0,0 +1,218 @@
+/*
+ * drivers/base/dma-mapping.c - arch-independent dma-mapping routines
+ *
+ * Copyright (c) 2006 SUSE Linux Products GmbH
+ * Copyright (c) 2006 Tejun Heo <teheo@suse.de>
+ *
+ * This file is released under the GPLv2.
+ */
+
+#include <linux/dma-mapping.h>
+
+/*
+ * Managed DMA API
+ */
+struct dma_devres {
+ size_t size;
+ void *vaddr;
+ dma_addr_t dma_handle;
+};
+
+static void dmam_coherent_release(struct device *dev, void *res)
+{
+ struct dma_devres *this = res;
+
+ dma_free_coherent(dev, this->size, this->vaddr, this->dma_handle);
+}
+
+static void dmam_noncoherent_release(struct device *dev, void *res)
+{
+ struct dma_devres *this = res;
+
+ dma_free_noncoherent(dev, this->size, this->vaddr, this->dma_handle);
+}
+
+static int dmam_match(struct device *dev, void *res, void *match_data)
+{
+ struct dma_devres *this = res, *match = match_data;
+
+ if (this->vaddr == match->vaddr) {
+ WARN_ON(this->size != match->size ||
+ this->dma_handle != match->dma_handle);
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * dmam_alloc_coherent - Managed dma_alloc_coherent()
+ * @dev: Device to allocate coherent memory for
+ * @size: Size of allocation
+ * @dma_handle: Out argument for allocated DMA handle
+ * @gfp: Allocation flags
+ *
+ * Managed dma_alloc_coherent(). Memory allocated using this function
+ * will be automatically released on driver detach.
+ *
+ * RETURNS:
+ * Pointer to allocated memory on success, NULL on failure.
+ */
+void * dmam_alloc_coherent(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t gfp)
+{
+ struct dma_devres *dr;
+ void *vaddr;
+
+ dr = devres_alloc(dmam_coherent_release, sizeof(*dr), gfp);
+ if (!dr)
+ return NULL;
+
+ vaddr = dma_alloc_coherent(dev, size, dma_handle, gfp);
+ if (!vaddr) {
+ devres_free(dr);
+ return NULL;
+ }
+
+ dr->vaddr = vaddr;
+ dr->dma_handle = *dma_handle;
+ dr->size = size;
+
+ devres_add(dev, dr);
+
+ return vaddr;
+}
+EXPORT_SYMBOL(dmam_alloc_coherent);
+
+/**
+ * dmam_free_coherent - Managed dma_free_coherent()
+ * @dev: Device to free coherent memory for
+ * @size: Size of allocation
+ * @vaddr: Virtual address of the memory to free
+ * @dma_handle: DMA handle of the memory to free
+ *
+ * Managed dma_free_coherent().
+ */
+void dmam_free_coherent(struct device *dev, size_t size, void *vaddr,
+ dma_addr_t dma_handle)
+{
+ struct dma_devres match_data = { size, vaddr, dma_handle };
+
+ dma_free_coherent(dev, size, vaddr, dma_handle);
+ WARN_ON(devres_destroy(dev, dmam_coherent_release, dmam_match,
+ &match_data));
+}
+EXPORT_SYMBOL(dmam_free_coherent);
+
+/**
+ * dmam_alloc_non_coherent - Managed dma_alloc_non_coherent()
+ * @dev: Device to allocate non_coherent memory for
+ * @size: Size of allocation
+ * @dma_handle: Out argument for allocated DMA handle
+ * @gfp: Allocation flags
+ *
+ * Managed dma_alloc_non_coherent(). Memory allocated using this
+ * function will be automatically released on driver detach.
+ *
+ * RETURNS:
+ * Pointer to allocated memory on success, NULL on failure.
+ */
+void *dmam_alloc_noncoherent(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t gfp)
+{
+ struct dma_devres *dr;
+ void *vaddr;
+
+ dr = devres_alloc(dmam_noncoherent_release, sizeof(*dr), gfp);
+ if (!dr)
+ return NULL;
+
+ vaddr = dma_alloc_noncoherent(dev, size, dma_handle, gfp);
+ if (!vaddr) {
+ devres_free(dr);
+ return NULL;
+ }
+
+ dr->vaddr = vaddr;
+ dr->dma_handle = *dma_handle;
+ dr->size = size;
+
+ devres_add(dev, dr);
+
+ return vaddr;
+}
+EXPORT_SYMBOL(dmam_alloc_noncoherent);
+
+/**
+ * dmam_free_coherent - Managed dma_free_noncoherent()
+ * @dev: Device to free noncoherent memory for
+ * @size: Size of allocation
+ * @vaddr: Virtual address of the memory to free
+ * @dma_handle: DMA handle of the memory to free
+ *
+ * Managed dma_free_noncoherent().
+ */
+void dmam_free_noncoherent(struct device *dev, size_t size, void *vaddr,
+ dma_addr_t dma_handle)
+{
+ struct dma_devres match_data = { size, vaddr, dma_handle };
+
+ dma_free_noncoherent(dev, size, vaddr, dma_handle);
+ WARN_ON(!devres_destroy(dev, dmam_noncoherent_release, dmam_match,
+ &match_data));
+}
+EXPORT_SYMBOL(dmam_free_noncoherent);
+
+#ifdef ARCH_HAS_DMA_DECLARE_COHERENT_MEMORY
+
+static void dmam_coherent_decl_release(struct device *dev, void *res)
+{
+ dma_release_declared_memory(dev);
+}
+
+/**
+ * dmam_declare_coherent_memory - Managed dma_declare_coherent_memory()
+ * @dev: Device to declare coherent memory for
+ * @bus_addr: Bus address of coherent memory to be declared
+ * @device_addr: Device address of coherent memory to be declared
+ * @size: Size of coherent memory to be declared
+ * @flags: Flags
+ *
+ * Managed dma_declare_coherent_memory().
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+int dmam_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr,
+ dma_addr_t device_addr, size_t size, int flags)
+{
+ void *res;
+ int rc;
+
+ res = devres_alloc(dmam_coherent_decl_release, 0, GFP_KERNEL);
+ if (!res)
+ return -ENOMEM;
+
+ rc = dma_declare_coherent_memory(dev, bus_addr, device_addr, size,
+ flags);
+ if (rc == 0)
+ devres_add(dev, res);
+ else
+ devres_free(res);
+
+ return rc;
+}
+EXPORT_SYMBOL(dmam_declare_coherent_memory);
+
+/**
+ * dmam_release_declared_memory - Managed dma_release_declared_memory().
+ * @dev: Device to release declared coherent memory for
+ *
+ * Managed dmam_release_declared_memory().
+ */
+void dmam_release_declared_memory(struct device *dev)
+{
+ WARN_ON(devres_destroy(dev, dmam_coherent_decl_release, NULL, NULL));
+}
+EXPORT_SYMBOL(dmam_release_declared_memory);
+
+#endif
diff --git a/drivers/base/dmapool.c b/drivers/base/dmapool.c
index f95d5027727..cd467c9f33b 100644
--- a/drivers/base/dmapool.c
+++ b/drivers/base/dmapool.c
@@ -415,8 +415,67 @@ dma_pool_free (struct dma_pool *pool, void *vaddr, dma_addr_t dma)
spin_unlock_irqrestore (&pool->lock, flags);
}
+/*
+ * Managed DMA pool
+ */
+static void dmam_pool_release(struct device *dev, void *res)
+{
+ struct dma_pool *pool = *(struct dma_pool **)res;
+
+ dma_pool_destroy(pool);
+}
+
+static int dmam_pool_match(struct device *dev, void *res, void *match_data)
+{
+ return *(struct dma_pool **)res == match_data;
+}
+
+/**
+ * dmam_pool_create - Managed dma_pool_create()
+ * @name: name of pool, for diagnostics
+ * @dev: device that will be doing the DMA
+ * @size: size of the blocks in this pool.
+ * @align: alignment requirement for blocks; must be a power of two
+ * @allocation: returned blocks won't cross this boundary (or zero)
+ *
+ * Managed dma_pool_create(). DMA pool created with this function is
+ * automatically destroyed on driver detach.
+ */
+struct dma_pool *dmam_pool_create(const char *name, struct device *dev,
+ size_t size, size_t align, size_t allocation)
+{
+ struct dma_pool **ptr, *pool;
+
+ ptr = devres_alloc(dmam_pool_release, sizeof(*ptr), GFP_KERNEL);
+ if (!ptr)
+ return NULL;
+
+ pool = *ptr = dma_pool_create(name, dev, size, align, allocation);
+ if (pool)
+ devres_add(dev, ptr);
+ else
+ devres_free(ptr);
+
+ return pool;
+}
+
+/**
+ * dmam_pool_destroy - Managed dma_pool_destroy()
+ * @pool: dma pool that will be destroyed
+ *
+ * Managed dma_pool_destroy().
+ */
+void dmam_pool_destroy(struct dma_pool *pool)
+{
+ struct device *dev = pool->dev;
+
+ dma_pool_destroy(pool);
+ WARN_ON(devres_destroy(dev, dmam_pool_release, dmam_pool_match, pool));
+}
EXPORT_SYMBOL (dma_pool_create);
EXPORT_SYMBOL (dma_pool_destroy);
EXPORT_SYMBOL (dma_pool_alloc);
EXPORT_SYMBOL (dma_pool_free);
+EXPORT_SYMBOL (dmam_pool_create);
+EXPORT_SYMBOL (dmam_pool_destroy);
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 64558f45e6b..c0a979a5074 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -35,7 +35,7 @@ enum {
FW_STATUS_READY_NOHOTPLUG,
};
-static int loading_timeout = 10; /* In seconds */
+static int loading_timeout = 60; /* In seconds */
/* fw_lock could be moved to 'struct firmware_priv' but since it is just
* guarding for corner cases a global lock should be OK */
diff --git a/drivers/base/node.c b/drivers/base/node.c
index 001e6f6b9c1..cae346ef1b2 100644
--- a/drivers/base/node.c
+++ b/drivers/base/node.c
@@ -40,13 +40,8 @@ static ssize_t node_read_meminfo(struct sys_device * dev, char * buf)
int n;
int nid = dev->id;
struct sysinfo i;
- unsigned long inactive;
- unsigned long active;
- unsigned long free;
si_meminfo_node(&i, nid);
- __get_zone_counts(&active, &inactive, &free, NODE_DATA(nid));
-
n = sprintf(buf, "\n"
"Node %d MemTotal: %8lu kB\n"
@@ -74,8 +69,8 @@ static ssize_t node_read_meminfo(struct sys_device * dev, char * buf)
nid, K(i.totalram),
nid, K(i.freeram),
nid, K(i.totalram - i.freeram),
- nid, K(active),
- nid, K(inactive),
+ nid, node_page_state(nid, NR_ACTIVE),
+ nid, node_page_state(nid, NR_INACTIVE),
#ifdef CONFIG_HIGHMEM
nid, K(i.totalhigh),
nid, K(i.freehigh),
@@ -138,7 +133,7 @@ static SYSDEV_ATTR(distance, S_IRUGO, node_read_distance, NULL);
/*
- * register_node - Setup a driverfs device for a node.
+ * register_node - Setup a sysfs device for a node.
* @num - Node number to use when creating the device.
*
* Initialize and register the node device.
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index f9c903ba9fc..30480f6f2af 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -611,8 +611,15 @@ EXPORT_SYMBOL_GPL(platform_bus_type);
int __init platform_bus_init(void)
{
- device_register(&platform_bus);
- return bus_register(&platform_bus_type);
+ int error;
+
+ error = device_register(&platform_bus);
+ if (error)
+ return error;
+ error = bus_register(&platform_bus_type);
+ if (error)
+ device_unregister(&platform_bus);
+ return error;
}
#ifndef ARCH_HAS_DMA_GET_REQUIRED_MASK
diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c
index 8d81a3a64c0..92bf868ca05 100644
--- a/drivers/block/DAC960.c
+++ b/drivers/block/DAC960.c
@@ -177,7 +177,7 @@ static void DAC960_AnnounceDriver(DAC960_Controller_T *Controller)
DAC960_Failure prints a standardized error message, and then returns false.
*/
-static boolean DAC960_Failure(DAC960_Controller_T *Controller,
+static bool DAC960_Failure(DAC960_Controller_T *Controller,
unsigned char *ErrorMessage)
{
DAC960_Error("While configuring DAC960 PCI RAID Controller at\n",
@@ -206,7 +206,7 @@ static boolean DAC960_Failure(DAC960_Controller_T *Controller,
that are passed in.
*/
-static boolean init_dma_loaf(struct pci_dev *dev, struct dma_loaf *loaf,
+static bool init_dma_loaf(struct pci_dev *dev, struct dma_loaf *loaf,
size_t len)
{
void *cpu_addr;
@@ -250,7 +250,7 @@ static void free_dma_loaf(struct pci_dev *dev, struct dma_loaf *loaf_handle)
failure.
*/
-static boolean DAC960_CreateAuxiliaryStructures(DAC960_Controller_T *Controller)
+static bool DAC960_CreateAuxiliaryStructures(DAC960_Controller_T *Controller)
{
int CommandAllocationLength, CommandAllocationGroupSize;
int CommandsRemaining = 0, CommandIdentifier, CommandGroupByteCount;
@@ -790,7 +790,7 @@ static void DAC960_ExecuteCommand(DAC960_Command_T *Command)
on failure.
*/
-static boolean DAC960_V1_ExecuteType3(DAC960_Controller_T *Controller,
+static bool DAC960_V1_ExecuteType3(DAC960_Controller_T *Controller,
DAC960_V1_CommandOpcode_T CommandOpcode,
dma_addr_t DataDMA)
{
@@ -814,7 +814,7 @@ static boolean DAC960_V1_ExecuteType3(DAC960_Controller_T *Controller,
on failure.
*/
-static boolean DAC960_V1_ExecuteType3B(DAC960_Controller_T *Controller,
+static bool DAC960_V1_ExecuteType3B(DAC960_Controller_T *Controller,
DAC960_V1_CommandOpcode_T CommandOpcode,
unsigned char CommandOpcode2,
dma_addr_t DataDMA)
@@ -840,7 +840,7 @@ static boolean DAC960_V1_ExecuteType3B(DAC960_Controller_T *Controller,
on failure.
*/
-static boolean DAC960_V1_ExecuteType3D(DAC960_Controller_T *Controller,
+static bool DAC960_V1_ExecuteType3D(DAC960_Controller_T *Controller,
DAC960_V1_CommandOpcode_T CommandOpcode,
unsigned char Channel,
unsigned char TargetID,
@@ -870,7 +870,7 @@ static boolean DAC960_V1_ExecuteType3D(DAC960_Controller_T *Controller,
Return data in The controller's HealthStatusBuffer, which is dma-able memory
*/
-static boolean DAC960_V2_GeneralInfo(DAC960_Controller_T *Controller)
+static bool DAC960_V2_GeneralInfo(DAC960_Controller_T *Controller)
{
DAC960_Command_T *Command = DAC960_AllocateCommand(Controller);
DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox;
@@ -908,7 +908,7 @@ static boolean DAC960_V2_GeneralInfo(DAC960_Controller_T *Controller)
memory buffer.
*/
-static boolean DAC960_V2_NewControllerInfo(DAC960_Controller_T *Controller)
+static bool DAC960_V2_NewControllerInfo(DAC960_Controller_T *Controller)
{
DAC960_Command_T *Command = DAC960_AllocateCommand(Controller);
DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox;
@@ -946,7 +946,7 @@ static boolean DAC960_V2_NewControllerInfo(DAC960_Controller_T *Controller)
Data is returned in the controller's V2.NewLogicalDeviceInformation
*/
-static boolean DAC960_V2_NewLogicalDeviceInfo(DAC960_Controller_T *Controller,
+static bool DAC960_V2_NewLogicalDeviceInfo(DAC960_Controller_T *Controller,
unsigned short LogicalDeviceNumber)
{
DAC960_Command_T *Command = DAC960_AllocateCommand(Controller);
@@ -997,7 +997,7 @@ static boolean DAC960_V2_NewLogicalDeviceInfo(DAC960_Controller_T *Controller,
*/
-static boolean DAC960_V2_NewPhysicalDeviceInfo(DAC960_Controller_T *Controller,
+static bool DAC960_V2_NewPhysicalDeviceInfo(DAC960_Controller_T *Controller,
unsigned char Channel,
unsigned char TargetID,
unsigned char LogicalUnit)
@@ -1082,7 +1082,7 @@ static void DAC960_V2_ConstructNewUnitSerialNumber(
memory buffer.
*/
-static boolean DAC960_V2_NewInquiryUnitSerialNumber(DAC960_Controller_T *Controller,
+static bool DAC960_V2_NewInquiryUnitSerialNumber(DAC960_Controller_T *Controller,
int Channel, int TargetID, int LogicalUnit)
{
DAC960_Command_T *Command;
@@ -1110,7 +1110,7 @@ static boolean DAC960_V2_NewInquiryUnitSerialNumber(DAC960_Controller_T *Control
success and false on failure.
*/
-static boolean DAC960_V2_DeviceOperation(DAC960_Controller_T *Controller,
+static bool DAC960_V2_DeviceOperation(DAC960_Controller_T *Controller,
DAC960_V2_IOCTL_Opcode_T IOCTL_Opcode,
DAC960_V2_OperationDevice_T
OperationDevice)
@@ -1142,7 +1142,7 @@ static boolean DAC960_V2_DeviceOperation(DAC960_Controller_T *Controller,
other dma mapped memory.
*/
-static boolean DAC960_V1_EnableMemoryMailboxInterface(DAC960_Controller_T
+static bool DAC960_V1_EnableMemoryMailboxInterface(DAC960_Controller_T
*Controller)
{
void __iomem *ControllerBaseAddress = Controller->BaseAddress;
@@ -1348,7 +1348,7 @@ skip_mailboxes:
the structures that are contained in that region.
*/
-static boolean DAC960_V2_EnableMemoryMailboxInterface(DAC960_Controller_T
+static bool DAC960_V2_EnableMemoryMailboxInterface(DAC960_Controller_T
*Controller)
{
void __iomem *ControllerBaseAddress = Controller->BaseAddress;
@@ -1373,8 +1373,7 @@ static boolean DAC960_V2_EnableMemoryMailboxInterface(DAC960_Controller_T
Controller->BounceBufferLimit = DAC690_V2_PciDmaMask;
/* This is a temporary dma mapping, used only in the scope of this function */
- CommandMailbox =
- (DAC960_V2_CommandMailbox_T *)pci_alloc_consistent( PCI_Device,
+ CommandMailbox = pci_alloc_consistent(PCI_Device,
sizeof(DAC960_V2_CommandMailbox_T), &CommandMailboxDMA);
if (CommandMailbox == NULL)
return false;
@@ -1526,7 +1525,7 @@ static boolean DAC960_V2_EnableMemoryMailboxInterface(DAC960_Controller_T
from DAC960 V1 Firmware Controllers and initializes the Controller structure.
*/
-static boolean DAC960_V1_ReadControllerConfiguration(DAC960_Controller_T
+static bool DAC960_V1_ReadControllerConfiguration(DAC960_Controller_T
*Controller)
{
DAC960_V1_Enquiry2_T *Enquiry2;
@@ -1767,7 +1766,7 @@ static boolean DAC960_V1_ReadControllerConfiguration(DAC960_Controller_T
from DAC960 V2 Firmware Controllers and initializes the Controller structure.
*/
-static boolean DAC960_V2_ReadControllerConfiguration(DAC960_Controller_T
+static bool DAC960_V2_ReadControllerConfiguration(DAC960_Controller_T
*Controller)
{
DAC960_V2_ControllerInfo_T *ControllerInfo =
@@ -1879,8 +1878,8 @@ static boolean DAC960_V2_ReadControllerConfiguration(DAC960_Controller_T
if (NewLogicalDeviceInfo->LogicalDeviceState !=
DAC960_V2_LogicalDevice_Offline)
Controller->LogicalDriveInitiallyAccessible[LogicalDeviceNumber] = true;
- LogicalDeviceInfo = (DAC960_V2_LogicalDeviceInfo_T *)
- kmalloc(sizeof(DAC960_V2_LogicalDeviceInfo_T), GFP_ATOMIC);
+ LogicalDeviceInfo = kmalloc(sizeof(DAC960_V2_LogicalDeviceInfo_T),
+ GFP_ATOMIC);
if (LogicalDeviceInfo == NULL)
return DAC960_Failure(Controller, "LOGICAL DEVICE ALLOCATION");
Controller->V2.LogicalDeviceInformation[LogicalDeviceNumber] =
@@ -1898,7 +1897,7 @@ static boolean DAC960_V2_ReadControllerConfiguration(DAC960_Controller_T
for Controller.
*/
-static boolean DAC960_ReportControllerConfiguration(DAC960_Controller_T
+static bool DAC960_ReportControllerConfiguration(DAC960_Controller_T
*Controller)
{
DAC960_Info("Configuring Mylex %s PCI RAID Controller\n",
@@ -1947,7 +1946,7 @@ static boolean DAC960_ReportControllerConfiguration(DAC960_Controller_T
Controller.
*/
-static boolean DAC960_V1_ReadDeviceConfiguration(DAC960_Controller_T
+static bool DAC960_V1_ReadDeviceConfiguration(DAC960_Controller_T
*Controller)
{
struct dma_loaf local_dma;
@@ -2095,7 +2094,7 @@ static boolean DAC960_V1_ReadDeviceConfiguration(DAC960_Controller_T
device connected to Controller.
*/
-static boolean DAC960_V2_ReadDeviceConfiguration(DAC960_Controller_T
+static bool DAC960_V2_ReadDeviceConfiguration(DAC960_Controller_T
*Controller)
{
unsigned char Channel = 0, TargetID = 0, LogicalUnit = 0;
@@ -2113,8 +2112,8 @@ static boolean DAC960_V2_ReadDeviceConfiguration(DAC960_Controller_T
if (!DAC960_V2_NewPhysicalDeviceInfo(Controller, Channel, TargetID, LogicalUnit))
break;
- PhysicalDeviceInfo = (DAC960_V2_PhysicalDeviceInfo_T *)
- kmalloc(sizeof(DAC960_V2_PhysicalDeviceInfo_T), GFP_ATOMIC);
+ PhysicalDeviceInfo = kmalloc(sizeof(DAC960_V2_PhysicalDeviceInfo_T),
+ GFP_ATOMIC);
if (PhysicalDeviceInfo == NULL)
return DAC960_Failure(Controller, "PHYSICAL DEVICE ALLOCATION");
Controller->V2.PhysicalDeviceInformation[PhysicalDeviceIndex] =
@@ -2122,8 +2121,8 @@ static boolean DAC960_V2_ReadDeviceConfiguration(DAC960_Controller_T
memcpy(PhysicalDeviceInfo, NewPhysicalDeviceInfo,
sizeof(DAC960_V2_PhysicalDeviceInfo_T));
- InquiryUnitSerialNumber = (DAC960_SCSI_Inquiry_UnitSerialNumber_T *)
- kmalloc(sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T), GFP_ATOMIC);
+ InquiryUnitSerialNumber = kmalloc(
+ sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T), GFP_ATOMIC);
if (InquiryUnitSerialNumber == NULL) {
kfree(PhysicalDeviceInfo);
return DAC960_Failure(Controller, "SERIAL NUMBER ALLOCATION");
@@ -2219,7 +2218,7 @@ static void DAC960_SanitizeInquiryData(DAC960_SCSI_Inquiry_T
Information for DAC960 V1 Firmware Controllers.
*/
-static boolean DAC960_V1_ReportDeviceConfiguration(DAC960_Controller_T
+static bool DAC960_V1_ReportDeviceConfiguration(DAC960_Controller_T
*Controller)
{
int LogicalDriveNumber, Channel, TargetID;
@@ -2316,7 +2315,7 @@ static boolean DAC960_V1_ReportDeviceConfiguration(DAC960_Controller_T
Information for DAC960 V2 Firmware Controllers.
*/
-static boolean DAC960_V2_ReportDeviceConfiguration(DAC960_Controller_T
+static bool DAC960_V2_ReportDeviceConfiguration(DAC960_Controller_T
*Controller)
{
int PhysicalDeviceIndex, LogicalDriveNumber;
@@ -2501,7 +2500,7 @@ static boolean DAC960_V2_ReportDeviceConfiguration(DAC960_Controller_T
associated with Controller.
*/
-static boolean DAC960_RegisterBlockDevice(DAC960_Controller_T *Controller)
+static bool DAC960_RegisterBlockDevice(DAC960_Controller_T *Controller)
{
int MajorNumber = DAC960_MAJOR + Controller->ControllerNumber;
int n;
@@ -2582,7 +2581,7 @@ static void DAC960_ComputeGenericDiskInfo(DAC960_Controller_T *Controller)
It returns true for fatal errors and false otherwise.
*/
-static boolean DAC960_ReportErrorStatus(DAC960_Controller_T *Controller,
+static bool DAC960_ReportErrorStatus(DAC960_Controller_T *Controller,
unsigned char ErrorStatus,
unsigned char Parameter0,
unsigned char Parameter1)
@@ -3048,7 +3047,7 @@ Failure:
DAC960_InitializeController initializes Controller.
*/
-static boolean
+static bool
DAC960_InitializeController(DAC960_Controller_T *Controller)
{
if (DAC960_ReadControllerConfiguration(Controller) &&
@@ -3445,8 +3444,8 @@ static void DAC960_RequestFunction(struct request_queue *RequestQueue)
individual Buffer.
*/
-static inline boolean DAC960_ProcessCompletedRequest(DAC960_Command_T *Command,
- boolean SuccessfulIO)
+static inline bool DAC960_ProcessCompletedRequest(DAC960_Command_T *Command,
+ bool SuccessfulIO)
{
struct request *Request = Command->Request;
int UpToDate;
@@ -3572,7 +3571,7 @@ static void DAC960_V1_ProcessCompletedCommand(DAC960_Command_T *Command)
else if (CommandType == DAC960_ReadRetryCommand ||
CommandType == DAC960_WriteRetryCommand)
{
- boolean normal_completion;
+ bool normal_completion;
#ifdef FORCE_RETRY_FAILURE_DEBUG
static int retry_count = 1;
#endif
@@ -4659,7 +4658,7 @@ static void DAC960_V2_ProcessCompletedCommand(DAC960_Command_T *Command)
else if (CommandType == DAC960_ReadRetryCommand ||
CommandType == DAC960_WriteRetryCommand)
{
- boolean normal_completion;
+ bool normal_completion;
#ifdef FORCE_RETRY_FAILURE_DEBUG
static int retry_count = 1;
@@ -4949,8 +4948,8 @@ static void DAC960_V2_ProcessCompletedCommand(DAC960_Command_T *Command)
PhysicalDevice.LogicalUnit = NewLogicalDeviceInfo->LogicalUnit;
Controller->V2.LogicalDriveToVirtualDevice[LogicalDeviceNumber] =
PhysicalDevice;
- LogicalDeviceInfo = (DAC960_V2_LogicalDeviceInfo_T *)
- kmalloc(sizeof(DAC960_V2_LogicalDeviceInfo_T), GFP_ATOMIC);
+ LogicalDeviceInfo = kmalloc(sizeof(DAC960_V2_LogicalDeviceInfo_T),
+ GFP_ATOMIC);
Controller->V2.LogicalDeviceInformation[LogicalDeviceNumber] =
LogicalDeviceInfo;
DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) "
@@ -5632,7 +5631,7 @@ static void DAC960_MonitoringTimerFunction(unsigned long TimerData)
&Controller->V2.ControllerInformation;
unsigned int StatusChangeCounter =
Controller->V2.HealthStatusBuffer->StatusChangeCounter;
- boolean ForceMonitoringCommand = false;
+ bool ForceMonitoringCommand = false;
if (time_after(jiffies, Controller->SecondaryMonitoringTime
+ DAC960_SecondaryMonitoringInterval))
{
@@ -5696,7 +5695,7 @@ static void DAC960_MonitoringTimerFunction(unsigned long TimerData)
necessary. It returns true if there is enough room and false otherwise.
*/
-static boolean DAC960_CheckStatusBuffer(DAC960_Controller_T *Controller,
+static bool DAC960_CheckStatusBuffer(DAC960_Controller_T *Controller,
unsigned int ByteCount)
{
unsigned char *NewStatusBuffer;
@@ -5709,14 +5708,14 @@ static boolean DAC960_CheckStatusBuffer(DAC960_Controller_T *Controller,
unsigned int NewStatusBufferLength = DAC960_InitialStatusBufferSize;
while (NewStatusBufferLength < ByteCount)
NewStatusBufferLength *= 2;
- Controller->CombinedStatusBuffer =
- (unsigned char *) kmalloc(NewStatusBufferLength, GFP_ATOMIC);
+ Controller->CombinedStatusBuffer = kmalloc(NewStatusBufferLength,
+ GFP_ATOMIC);
if (Controller->CombinedStatusBuffer == NULL) return false;
Controller->CombinedStatusBufferLength = NewStatusBufferLength;
return true;
}
- NewStatusBuffer = (unsigned char *)
- kmalloc(2 * Controller->CombinedStatusBufferLength, GFP_ATOMIC);
+ NewStatusBuffer = kmalloc(2 * Controller->CombinedStatusBufferLength,
+ GFP_ATOMIC);
if (NewStatusBuffer == NULL)
{
DAC960_Warning("Unable to expand Combined Status Buffer - Truncating\n",
@@ -5744,7 +5743,7 @@ static void DAC960_Message(DAC960_MessageLevel_T MessageLevel,
...)
{
static unsigned char Buffer[DAC960_LineBufferSize];
- static boolean BeginningOfLine = true;
+ static bool BeginningOfLine = true;
va_list Arguments;
int Length = 0;
va_start(Arguments, Controller);
@@ -5837,7 +5836,7 @@ static void DAC960_Message(DAC960_MessageLevel_T MessageLevel,
Channel and TargetID and returns true on success and false on failure.
*/
-static boolean DAC960_ParsePhysicalDevice(DAC960_Controller_T *Controller,
+static bool DAC960_ParsePhysicalDevice(DAC960_Controller_T *Controller,
char *UserCommandString,
unsigned char *Channel,
unsigned char *TargetID)
@@ -5870,7 +5869,7 @@ static boolean DAC960_ParsePhysicalDevice(DAC960_Controller_T *Controller,
returns true on success and false on failure.
*/
-static boolean DAC960_ParseLogicalDrive(DAC960_Controller_T *Controller,
+static bool DAC960_ParseLogicalDrive(DAC960_Controller_T *Controller,
char *UserCommandString,
unsigned char *LogicalDriveNumber)
{
@@ -5951,7 +5950,7 @@ static void DAC960_V1_SetDeviceState(DAC960_Controller_T *Controller,
Controllers.
*/
-static boolean DAC960_V1_ExecuteUserCommand(DAC960_Controller_T *Controller,
+static bool DAC960_V1_ExecuteUserCommand(DAC960_Controller_T *Controller,
unsigned char *UserCommand)
{
DAC960_Command_T *Command;
@@ -6166,7 +6165,7 @@ failure:
on failure.
*/
-static boolean DAC960_V2_TranslatePhysicalDevice(DAC960_Command_T *Command,
+static bool DAC960_V2_TranslatePhysicalDevice(DAC960_Command_T *Command,
unsigned char Channel,
unsigned char TargetID,
unsigned short
@@ -6213,7 +6212,7 @@ static boolean DAC960_V2_TranslatePhysicalDevice(DAC960_Command_T *Command,
Controllers.
*/
-static boolean DAC960_V2_ExecuteUserCommand(DAC960_Controller_T *Controller,
+static bool DAC960_V2_ExecuteUserCommand(DAC960_Controller_T *Controller,
unsigned char *UserCommand)
{
DAC960_Command_T *Command;
@@ -7025,7 +7024,7 @@ static int DAC960_gam_ioctl(struct inode *inode, struct file *file,
return -EINVAL;
}
-static struct file_operations DAC960_gam_fops = {
+static const struct file_operations DAC960_gam_fops = {
.owner = THIS_MODULE,
.ioctl = DAC960_gam_ioctl
};
diff --git a/drivers/block/DAC960.h b/drivers/block/DAC960.h
index 6148073532b..f5e2436c39a 100644
--- a/drivers/block/DAC960.h
+++ b/drivers/block/DAC960.h
@@ -68,13 +68,6 @@
#define DAC690_V2_PciDmaMask 0xffffffffffffffffULL
/*
- Define a Boolean data type.
-*/
-
-typedef bool boolean;
-
-
-/*
Define a 32/64 bit I/O Address data type.
*/
@@ -139,25 +132,25 @@ typedef struct DAC960_SCSI_Inquiry
unsigned char PeripheralDeviceType:5; /* Byte 0 Bits 0-4 */
unsigned char PeripheralQualifier:3; /* Byte 0 Bits 5-7 */
unsigned char DeviceTypeModifier:7; /* Byte 1 Bits 0-6 */
- boolean RMB:1; /* Byte 1 Bit 7 */
+ bool RMB:1; /* Byte 1 Bit 7 */
unsigned char ANSI_ApprovedVersion:3; /* Byte 2 Bits 0-2 */
unsigned char ECMA_Version:3; /* Byte 2 Bits 3-5 */
unsigned char ISO_Version:2; /* Byte 2 Bits 6-7 */
unsigned char ResponseDataFormat:4; /* Byte 3 Bits 0-3 */
unsigned char :2; /* Byte 3 Bits 4-5 */
- boolean TrmIOP:1; /* Byte 3 Bit 6 */
- boolean AENC:1; /* Byte 3 Bit 7 */
+ bool TrmIOP:1; /* Byte 3 Bit 6 */
+ bool AENC:1; /* Byte 3 Bit 7 */
unsigned char AdditionalLength; /* Byte 4 */
unsigned char :8; /* Byte 5 */
unsigned char :8; /* Byte 6 */
- boolean SftRe:1; /* Byte 7 Bit 0 */
- boolean CmdQue:1; /* Byte 7 Bit 1 */
- boolean :1; /* Byte 7 Bit 2 */
- boolean Linked:1; /* Byte 7 Bit 3 */
- boolean Sync:1; /* Byte 7 Bit 4 */
- boolean WBus16:1; /* Byte 7 Bit 5 */
- boolean WBus32:1; /* Byte 7 Bit 6 */
- boolean RelAdr:1; /* Byte 7 Bit 7 */
+ bool SftRe:1; /* Byte 7 Bit 0 */
+ bool CmdQue:1; /* Byte 7 Bit 1 */
+ bool :1; /* Byte 7 Bit 2 */
+ bool Linked:1; /* Byte 7 Bit 3 */
+ bool Sync:1; /* Byte 7 Bit 4 */
+ bool WBus16:1; /* Byte 7 Bit 5 */
+ bool WBus32:1; /* Byte 7 Bit 6 */
+ bool RelAdr:1; /* Byte 7 Bit 7 */
unsigned char VendorIdentification[8]; /* Bytes 8-15 */
unsigned char ProductIdentification[16]; /* Bytes 16-31 */
unsigned char ProductRevisionLevel[4]; /* Bytes 32-35 */
@@ -215,13 +208,13 @@ DAC960_SCSI_RequestSenseKey_T;
typedef struct DAC960_SCSI_RequestSense
{
unsigned char ErrorCode:7; /* Byte 0 Bits 0-6 */
- boolean Valid:1; /* Byte 0 Bit 7 */
+ bool Valid:1; /* Byte 0 Bit 7 */
unsigned char SegmentNumber; /* Byte 1 */
DAC960_SCSI_RequestSenseKey_T SenseKey:4; /* Byte 2 Bits 0-3 */
unsigned char :1; /* Byte 2 Bit 4 */
- boolean ILI:1; /* Byte 2 Bit 5 */
- boolean EOM:1; /* Byte 2 Bit 6 */
- boolean Filemark:1; /* Byte 2 Bit 7 */
+ bool ILI:1; /* Byte 2 Bit 5 */
+ bool EOM:1; /* Byte 2 Bit 6 */
+ bool Filemark:1; /* Byte 2 Bit 7 */
unsigned char Information[4]; /* Bytes 3-6 */
unsigned char AdditionalSenseLength; /* Byte 7 */
unsigned char CommandSpecificInformation[4]; /* Bytes 8-11 */
@@ -381,8 +374,8 @@ typedef struct DAC960_V1_Enquiry
unsigned int LogicalDriveSizes[32]; /* Bytes 4-131 */
unsigned short FlashAge; /* Bytes 132-133 */
struct {
- boolean DeferredWriteError:1; /* Byte 134 Bit 0 */
- boolean BatteryLow:1; /* Byte 134 Bit 1 */
+ bool DeferredWriteError:1; /* Byte 134 Bit 0 */
+ bool BatteryLow:1; /* Byte 134 Bit 1 */
unsigned char :6; /* Byte 134 Bits 2-7 */
} StatusFlags;
unsigned char :8; /* Byte 135 */
@@ -410,7 +403,7 @@ typedef struct DAC960_V1_Enquiry
unsigned char RebuildCount; /* Byte 150 */
struct {
unsigned char :3; /* Byte 151 Bits 0-2 */
- boolean BatteryBackupUnitPresent:1; /* Byte 151 Bit 3 */
+ bool BatteryBackupUnitPresent:1; /* Byte 151 Bit 3 */
unsigned char :3; /* Byte 151 Bits 4-6 */
unsigned char :1; /* Byte 151 Bit 7 */
} MiscFlags;
@@ -492,8 +485,8 @@ typedef struct DAC960_V1_Enquiry2
DAC960_V1_ErrorCorrection_ECC = 0x2,
DAC960_V1_ErrorCorrection_Last = 0x7
} __attribute__ ((packed)) ErrorCorrection:3; /* Byte 40 Bits 3-5 */
- boolean FastPageMode:1; /* Byte 40 Bit 6 */
- boolean LowPowerMemory:1; /* Byte 40 Bit 7 */
+ bool FastPageMode:1; /* Byte 40 Bit 6 */
+ bool LowPowerMemory:1; /* Byte 40 Bit 7 */
unsigned char :8; /* Bytes 41 */
} MemoryType;
unsigned short ClockSpeed; /* Bytes 42-43 */
@@ -538,7 +531,7 @@ typedef struct DAC960_V1_Enquiry2
DAC960_V1_Ultra = 0x1,
DAC960_V1_Ultra2 = 0x2
} __attribute__ ((packed)) BusSpeed:2; /* Byte 106 Bits 2-3 */
- boolean Differential:1; /* Byte 106 Bit 4 */
+ bool Differential:1; /* Byte 106 Bit 4 */
unsigned char :3; /* Byte 106 Bits 5-7 */
} SCSICapability;
unsigned char :8; /* Byte 107 */
@@ -554,10 +547,10 @@ typedef struct DAC960_V1_Enquiry2
} __attribute__ ((packed)) FaultManagementType; /* Byte 114 */
unsigned char :8; /* Byte 115 */
struct {
- boolean Clustering:1; /* Byte 116 Bit 0 */
- boolean MylexOnlineRAIDExpansion:1; /* Byte 116 Bit 1 */
- boolean ReadAhead:1; /* Byte 116 Bit 2 */
- boolean BackgroundInitialization:1; /* Byte 116 Bit 3 */
+ bool Clustering:1; /* Byte 116 Bit 0 */
+ bool MylexOnlineRAIDExpansion:1; /* Byte 116 Bit 1 */
+ bool ReadAhead:1; /* Byte 116 Bit 2 */
+ bool BackgroundInitialization:1; /* Byte 116 Bit 3 */
unsigned int :28; /* Bytes 116-119 */
} FirmwareFeatures;
unsigned int :32; /* Bytes 120-123 */
@@ -589,7 +582,7 @@ typedef struct DAC960_V1_LogicalDriveInformation
unsigned int LogicalDriveSize; /* Bytes 0-3 */
DAC960_V1_LogicalDriveState_T LogicalDriveState; /* Byte 4 */
unsigned char RAIDLevel:7; /* Byte 5 Bits 0-6 */
- boolean WriteBack:1; /* Byte 5 Bit 7 */
+ bool WriteBack:1; /* Byte 5 Bit 7 */
unsigned short :16; /* Bytes 6-7 */
}
DAC960_V1_LogicalDriveInformation_T;
@@ -630,13 +623,13 @@ typedef struct DAC960_V1_EventLogEntry
unsigned char :2; /* Byte 3 Bits 6-7 */
unsigned short SequenceNumber; /* Bytes 4-5 */
unsigned char ErrorCode:7; /* Byte 6 Bits 0-6 */
- boolean Valid:1; /* Byte 6 Bit 7 */
+ bool Valid:1; /* Byte 6 Bit 7 */
unsigned char SegmentNumber; /* Byte 7 */
DAC960_SCSI_RequestSenseKey_T SenseKey:4; /* Byte 8 Bits 0-3 */
unsigned char :1; /* Byte 8 Bit 4 */
- boolean ILI:1; /* Byte 8 Bit 5 */
- boolean EOM:1; /* Byte 8 Bit 6 */
- boolean Filemark:1; /* Byte 8 Bit 7 */
+ bool ILI:1; /* Byte 8 Bit 5 */
+ bool EOM:1; /* Byte 8 Bit 6 */
+ bool Filemark:1; /* Byte 8 Bit 7 */
unsigned char Information[4]; /* Bytes 9-12 */
unsigned char AdditionalSenseLength; /* Byte 13 */
unsigned char CommandSpecificInformation[4]; /* Bytes 14-17 */
@@ -670,7 +663,7 @@ DAC960_V1_PhysicalDeviceState_T;
typedef struct DAC960_V1_DeviceState
{
- boolean Present:1; /* Byte 0 Bit 0 */
+ bool Present:1; /* Byte 0 Bit 0 */
unsigned char :7; /* Byte 0 Bits 1-7 */
enum {
DAC960_V1_OtherType = 0x0,
@@ -678,12 +671,12 @@ typedef struct DAC960_V1_DeviceState
DAC960_V1_SequentialType = 0x2,
DAC960_V1_CDROM_or_WORM_Type = 0x3
} __attribute__ ((packed)) DeviceType:2; /* Byte 1 Bits 0-1 */
- boolean :1; /* Byte 1 Bit 2 */
- boolean Fast20:1; /* Byte 1 Bit 3 */
- boolean Sync:1; /* Byte 1 Bit 4 */
- boolean Fast:1; /* Byte 1 Bit 5 */
- boolean Wide:1; /* Byte 1 Bit 6 */
- boolean TaggedQueuingSupported:1; /* Byte 1 Bit 7 */
+ bool :1; /* Byte 1 Bit 2 */
+ bool Fast20:1; /* Byte 1 Bit 3 */
+ bool Sync:1; /* Byte 1 Bit 4 */
+ bool Fast:1; /* Byte 1 Bit 5 */
+ bool Wide:1; /* Byte 1 Bit 6 */
+ bool TaggedQueuingSupported:1; /* Byte 1 Bit 7 */
DAC960_V1_PhysicalDeviceState_T DeviceState; /* Byte 2 */
unsigned char :8; /* Byte 3 */
unsigned char SynchronousMultiplier; /* Byte 4 */
@@ -765,15 +758,15 @@ DAC960_V1_ErrorTable_T;
typedef struct DAC960_V1_Config2
{
unsigned char :1; /* Byte 0 Bit 0 */
- boolean ActiveNegationEnabled:1; /* Byte 0 Bit 1 */
+ bool ActiveNegationEnabled:1; /* Byte 0 Bit 1 */
unsigned char :5; /* Byte 0 Bits 2-6 */
- boolean NoRescanIfResetReceivedDuringScan:1; /* Byte 0 Bit 7 */
- boolean StorageWorksSupportEnabled:1; /* Byte 1 Bit 0 */
- boolean HewlettPackardSupportEnabled:1; /* Byte 1 Bit 1 */
- boolean NoDisconnectOnFirstCommand:1; /* Byte 1 Bit 2 */
+ bool NoRescanIfResetReceivedDuringScan:1; /* Byte 0 Bit 7 */
+ bool StorageWorksSupportEnabled:1; /* Byte 1 Bit 0 */
+ bool HewlettPackardSupportEnabled:1; /* Byte 1 Bit 1 */
+ bool NoDisconnectOnFirstCommand:1; /* Byte 1 Bit 2 */
unsigned char :2; /* Byte 1 Bits 3-4 */
- boolean AEMI_ARM:1; /* Byte 1 Bit 5 */
- boolean AEMI_OFM:1; /* Byte 1 Bit 6 */
+ bool AEMI_ARM:1; /* Byte 1 Bit 5 */
+ bool AEMI_OFM:1; /* Byte 1 Bit 6 */
unsigned char :1; /* Byte 1 Bit 7 */
enum {
DAC960_V1_OEMID_Mylex = 0x00,
@@ -787,13 +780,13 @@ typedef struct DAC960_V1_Config2
unsigned char PhysicalSector; /* Byte 4 */
unsigned char LogicalSector; /* Byte 5 */
unsigned char BlockFactor; /* Byte 6 */
- boolean ReadAheadEnabled:1; /* Byte 7 Bit 0 */
- boolean LowBIOSDelay:1; /* Byte 7 Bit 1 */
+ bool ReadAheadEnabled:1; /* Byte 7 Bit 0 */
+ bool LowBIOSDelay:1; /* Byte 7 Bit 1 */
unsigned char :2; /* Byte 7 Bits 2-3 */
- boolean ReassignRestrictedToOneSector:1; /* Byte 7 Bit 4 */
+ bool ReassignRestrictedToOneSector:1; /* Byte 7 Bit 4 */
unsigned char :1; /* Byte 7 Bit 5 */
- boolean ForceUnitAccessDuringWriteRecovery:1; /* Byte 7 Bit 6 */
- boolean EnableLeftSymmetricRAID5Algorithm:1; /* Byte 7 Bit 7 */
+ bool ForceUnitAccessDuringWriteRecovery:1; /* Byte 7 Bit 6 */
+ bool EnableLeftSymmetricRAID5Algorithm:1; /* Byte 7 Bit 7 */
unsigned char DefaultRebuildRate; /* Byte 8 */
unsigned char :8; /* Byte 9 */
unsigned char BlocksPerCacheLine; /* Byte 10 */
@@ -805,10 +798,10 @@ typedef struct DAC960_V1_Config2
DAC960_V1_Sync_5MHz = 0x2,
DAC960_V1_Sync_10or20MHz = 0x3 /* Byte 11 Bits 0-1 */
} __attribute__ ((packed)) Speed:2;
- boolean Force8Bit:1; /* Byte 11 Bit 2 */
- boolean DisableFast20:1; /* Byte 11 Bit 3 */
+ bool Force8Bit:1; /* Byte 11 Bit 2 */
+ bool DisableFast20:1; /* Byte 11 Bit 3 */
unsigned char :3; /* Byte 11 Bits 4-6 */
- boolean EnableTaggedQueuing:1; /* Byte 11 Bit 7 */
+ bool EnableTaggedQueuing:1; /* Byte 11 Bit 7 */
} __attribute__ ((packed)) ChannelParameters[6]; /* Bytes 12-17 */
unsigned char SCSIInitiatorID; /* Byte 18 */
unsigned char :8; /* Byte 19 */
@@ -819,8 +812,8 @@ typedef struct DAC960_V1_Config2
unsigned char SimultaneousDeviceSpinUpCount; /* Byte 21 */
unsigned char SecondsDelayBetweenSpinUps; /* Byte 22 */
unsigned char Reserved1[29]; /* Bytes 23-51 */
- boolean BIOSDisabled:1; /* Byte 52 Bit 0 */
- boolean CDROMBootEnabled:1; /* Byte 52 Bit 1 */
+ bool BIOSDisabled:1; /* Byte 52 Bit 0 */
+ bool CDROMBootEnabled:1; /* Byte 52 Bit 1 */
unsigned char :3; /* Byte 52 Bits 2-4 */
enum {
DAC960_V1_Geometry_128_32 = 0x0,
@@ -849,7 +842,7 @@ typedef struct DAC960_V1_DCDB
DAC960_V1_DCDB_DataTransferSystemToDevice = 2,
DAC960_V1_DCDB_IllegalDataTransfer = 3
} __attribute__ ((packed)) Direction:2; /* Byte 1 Bits 0-1 */
- boolean EarlyStatus:1; /* Byte 1 Bit 2 */
+ bool EarlyStatus:1; /* Byte 1 Bit 2 */
unsigned char :1; /* Byte 1 Bit 3 */
enum {
DAC960_V1_DCDB_Timeout_24_hours = 0,
@@ -857,8 +850,8 @@ typedef struct DAC960_V1_DCDB
DAC960_V1_DCDB_Timeout_60_seconds = 2,
DAC960_V1_DCDB_Timeout_10_minutes = 3
} __attribute__ ((packed)) Timeout:2; /* Byte 1 Bits 4-5 */
- boolean NoAutomaticRequestSense:1; /* Byte 1 Bit 6 */
- boolean DisconnectPermitted:1; /* Byte 1 Bit 7 */
+ bool NoAutomaticRequestSense:1; /* Byte 1 Bit 6 */
+ bool DisconnectPermitted:1; /* Byte 1 Bit 7 */
unsigned short TransferLength; /* Bytes 2-3 */
DAC960_BusAddress32_T BusAddress; /* Bytes 4-7 */
unsigned char CDBLength:4; /* Byte 8 Bits 0-3 */
@@ -920,7 +913,7 @@ typedef union DAC960_V1_CommandMailbox
DAC960_V1_CommandIdentifier_T CommandIdentifier; /* Byte 1 */
unsigned char Dummy1[5]; /* Bytes 2-6 */
unsigned char LogicalDriveNumber:6; /* Byte 7 Bits 0-6 */
- boolean AutoRestore:1; /* Byte 7 Bit 7 */
+ bool AutoRestore:1; /* Byte 7 Bit 7 */
unsigned char Dummy2[8]; /* Bytes 8-15 */
} __attribute__ ((packed)) Type3C;
struct {
@@ -1070,9 +1063,9 @@ typedef struct DAC960_V2_MemoryType
DAC960_V2_MemoryType_SDRAM = 0x04,
DAC960_V2_MemoryType_Last = 0x1F
} __attribute__ ((packed)) MemoryType:5; /* Byte 0 Bits 0-4 */
- boolean :1; /* Byte 0 Bit 5 */
- boolean MemoryParity:1; /* Byte 0 Bit 6 */
- boolean MemoryECC:1; /* Byte 0 Bit 7 */
+ bool :1; /* Byte 0 Bit 5 */
+ bool MemoryParity:1; /* Byte 0 Bit 6 */
+ bool MemoryECC:1; /* Byte 0 Bit 7 */
}
DAC960_V2_MemoryType_T;
@@ -1187,13 +1180,13 @@ typedef struct DAC960_V2_ControllerInfo
unsigned char OEM_Code; /* Byte 131 */
unsigned char VendorName[16]; /* Bytes 132-147 */
/* Other Physical/Controller/Operation Information */
- boolean BBU_Present:1; /* Byte 148 Bit 0 */
- boolean ActiveActiveClusteringMode:1; /* Byte 148 Bit 1 */
+ bool BBU_Present:1; /* Byte 148 Bit 0 */
+ bool ActiveActiveClusteringMode:1; /* Byte 148 Bit 1 */
unsigned char :6; /* Byte 148 Bits 2-7 */
unsigned char :8; /* Byte 149 */
unsigned short :16; /* Bytes 150-151 */
/* Physical Device Scan Information */
- boolean PhysicalScanActive:1; /* Byte 152 Bit 0 */
+ bool PhysicalScanActive:1; /* Byte 152 Bit 0 */
unsigned char :7; /* Byte 152 Bits 1-7 */
unsigned char PhysicalDeviceChannelNumber; /* Byte 153 */
unsigned char PhysicalDeviceTargetID; /* Byte 154 */
@@ -1305,8 +1298,8 @@ typedef struct DAC960_V2_ControllerInfo
unsigned int FreeIOP; /* Bytes 468-471 */
unsigned short MaximumCombLengthInBlocks; /* Bytes 472-473 */
unsigned short NumberOfConfigurationGroups; /* Bytes 474-475 */
- boolean InstallationAbortStatus:1; /* Byte 476 Bit 0 */
- boolean MaintenanceModeStatus:1; /* Byte 476 Bit 1 */
+ bool InstallationAbortStatus:1; /* Byte 476 Bit 0 */
+ bool MaintenanceModeStatus:1; /* Byte 476 Bit 1 */
unsigned int :24; /* Bytes 476-479 */
unsigned char Reserved10[32]; /* Bytes 480-511 */
unsigned char Reserved11[512]; /* Bytes 512-1023 */
@@ -1357,33 +1350,33 @@ typedef struct DAC960_V2_LogicalDeviceInfo
DAC960_V2_IntelligentWriteCacheEnabled = 0x3,
DAC960_V2_WriteCache_Last = 0x7
} __attribute__ ((packed)) WriteCache:3; /* Byte 8 Bits 3-5 */
- boolean :1; /* Byte 8 Bit 6 */
- boolean LogicalDeviceInitialized:1; /* Byte 8 Bit 7 */
+ bool :1; /* Byte 8 Bit 6 */
+ bool LogicalDeviceInitialized:1; /* Byte 8 Bit 7 */
} LogicalDeviceControl; /* Byte 8 */
/* Logical Device Operations Status */
- boolean ConsistencyCheckInProgress:1; /* Byte 9 Bit 0 */
- boolean RebuildInProgress:1; /* Byte 9 Bit 1 */
- boolean BackgroundInitializationInProgress:1; /* Byte 9 Bit 2 */
- boolean ForegroundInitializationInProgress:1; /* Byte 9 Bit 3 */
- boolean DataMigrationInProgress:1; /* Byte 9 Bit 4 */
- boolean PatrolOperationInProgress:1; /* Byte 9 Bit 5 */
+ bool ConsistencyCheckInProgress:1; /* Byte 9 Bit 0 */
+ bool RebuildInProgress:1; /* Byte 9 Bit 1 */
+ bool BackgroundInitializationInProgress:1; /* Byte 9 Bit 2 */
+ bool ForegroundInitializationInProgress:1; /* Byte 9 Bit 3 */
+ bool DataMigrationInProgress:1; /* Byte 9 Bit 4 */
+ bool PatrolOperationInProgress:1; /* Byte 9 Bit 5 */
unsigned char :2; /* Byte 9 Bits 6-7 */
unsigned char RAID5WriteUpdate; /* Byte 10 */
unsigned char RAID5Algorithm; /* Byte 11 */
unsigned short LogicalDeviceNumber; /* Bytes 12-13 */
/* BIOS Info */
- boolean BIOSDisabled:1; /* Byte 14 Bit 0 */
- boolean CDROMBootEnabled:1; /* Byte 14 Bit 1 */
- boolean DriveCoercionEnabled:1; /* Byte 14 Bit 2 */
- boolean WriteSameDisabled:1; /* Byte 14 Bit 3 */
- boolean HBA_ModeEnabled:1; /* Byte 14 Bit 4 */
+ bool BIOSDisabled:1; /* Byte 14 Bit 0 */
+ bool CDROMBootEnabled:1; /* Byte 14 Bit 1 */
+ bool DriveCoercionEnabled:1; /* Byte 14 Bit 2 */
+ bool WriteSameDisabled:1; /* Byte 14 Bit 3 */
+ bool HBA_ModeEnabled:1; /* Byte 14 Bit 4 */
enum {
DAC960_V2_Geometry_128_32 = 0x0,
DAC960_V2_Geometry_255_63 = 0x1,
DAC960_V2_Geometry_Reserved1 = 0x2,
DAC960_V2_Geometry_Reserved2 = 0x3
} __attribute__ ((packed)) DriveGeometry:2; /* Byte 14 Bits 5-6 */
- boolean SuperReadAheadEnabled:1; /* Byte 14 Bit 7 */
+ bool SuperReadAheadEnabled:1; /* Byte 14 Bit 7 */
unsigned char :8; /* Byte 15 */
/* Error Counters */
unsigned short SoftErrors; /* Bytes 16-17 */
@@ -1446,13 +1439,13 @@ typedef struct DAC960_V2_PhysicalDeviceInfo
unsigned char TargetID; /* Byte 2 */
unsigned char LogicalUnit; /* Byte 3 */
/* Configuration Status Bits */
- boolean PhysicalDeviceFaultTolerant:1; /* Byte 4 Bit 0 */
- boolean PhysicalDeviceConnected:1; /* Byte 4 Bit 1 */
- boolean PhysicalDeviceLocalToController:1; /* Byte 4 Bit 2 */
+ bool PhysicalDeviceFaultTolerant:1; /* Byte 4 Bit 0 */
+ bool PhysicalDeviceConnected:1; /* Byte 4 Bit 1 */
+ bool PhysicalDeviceLocalToController:1; /* Byte 4 Bit 2 */
unsigned char :5; /* Byte 4 Bits 3-7 */
/* Multiple Host/Controller Status Bits */
- boolean RemoteHostSystemDead:1; /* Byte 5 Bit 0 */
- boolean RemoteControllerDead:1; /* Byte 5 Bit 1 */
+ bool RemoteHostSystemDead:1; /* Byte 5 Bit 0 */
+ bool RemoteControllerDead:1; /* Byte 5 Bit 1 */
unsigned char :6; /* Byte 5 Bits 2-7 */
DAC960_V2_PhysicalDeviceState_T PhysicalDeviceState; /* Byte 6 */
unsigned char NegotiatedDataWidthBits; /* Byte 7 */
@@ -1464,12 +1457,12 @@ typedef struct DAC960_V2_PhysicalDeviceInfo
unsigned char NetworkAddress[16]; /* Bytes 16-31 */
unsigned short MaximumTags; /* Bytes 32-33 */
/* Physical Device Operations Status */
- boolean ConsistencyCheckInProgress:1; /* Byte 34 Bit 0 */
- boolean RebuildInProgress:1; /* Byte 34 Bit 1 */
- boolean MakingDataConsistentInProgress:1; /* Byte 34 Bit 2 */
- boolean PhysicalDeviceInitializationInProgress:1; /* Byte 34 Bit 3 */
- boolean DataMigrationInProgress:1; /* Byte 34 Bit 4 */
- boolean PatrolOperationInProgress:1; /* Byte 34 Bit 5 */
+ bool ConsistencyCheckInProgress:1; /* Byte 34 Bit 0 */
+ bool RebuildInProgress:1; /* Byte 34 Bit 1 */
+ bool MakingDataConsistentInProgress:1; /* Byte 34 Bit 2 */
+ bool PhysicalDeviceInitializationInProgress:1; /* Byte 34 Bit 3 */
+ bool DataMigrationInProgress:1; /* Byte 34 Bit 4 */
+ bool PatrolOperationInProgress:1; /* Byte 34 Bit 5 */
unsigned char :2; /* Byte 34 Bits 6-7 */
unsigned char LongOperationStatus; /* Byte 35 */
unsigned char ParityErrors; /* Byte 36 */
@@ -1555,14 +1548,14 @@ DAC960_V2_Event_T;
typedef struct DAC960_V2_CommandControlBits
{
- boolean ForceUnitAccess:1; /* Byte 0 Bit 0 */
- boolean DisablePageOut:1; /* Byte 0 Bit 1 */
- boolean :1; /* Byte 0 Bit 2 */
- boolean AdditionalScatterGatherListMemory:1; /* Byte 0 Bit 3 */
- boolean DataTransferControllerToHost:1; /* Byte 0 Bit 4 */
- boolean :1; /* Byte 0 Bit 5 */
- boolean NoAutoRequestSense:1; /* Byte 0 Bit 6 */
- boolean DisconnectProhibited:1; /* Byte 0 Bit 7 */
+ bool ForceUnitAccess:1; /* Byte 0 Bit 0 */
+ bool DisablePageOut:1; /* Byte 0 Bit 1 */
+ bool :1; /* Byte 0 Bit 2 */
+ bool AdditionalScatterGatherListMemory:1; /* Byte 0 Bit 3 */
+ bool DataTransferControllerToHost:1; /* Byte 0 Bit 4 */
+ bool :1; /* Byte 0 Bit 5 */
+ bool NoAutoRequestSense:1; /* Byte 0 Bit 6 */
+ bool DisconnectProhibited:1; /* Byte 0 Bit 7 */
}
DAC960_V2_CommandControlBits_T;
@@ -1825,8 +1818,8 @@ typedef union DAC960_V2_CommandMailbox
DAC960_V2_CommandTimeout_T CommandTimeout; /* Byte 19 */
unsigned char RequestSenseSize; /* Byte 20 */
unsigned char IOCTL_Opcode; /* Byte 21 */
- boolean RestoreConsistency:1; /* Byte 22 Bit 0 */
- boolean InitializedAreaOnly:1; /* Byte 22 Bit 1 */
+ bool RestoreConsistency:1; /* Byte 22 Bit 0 */
+ bool InitializedAreaOnly:1; /* Byte 22 Bit 1 */
unsigned char :6; /* Byte 22 Bits 2-7 */
unsigned char Reserved[9]; /* Bytes 23-31 */
DAC960_V2_DataTransferMemoryAddress_T
@@ -2190,7 +2183,7 @@ typedef union DAC960_V1_StatusMailbox
struct {
DAC960_V1_CommandIdentifier_T CommandIdentifier; /* Byte 0 */
unsigned char :7; /* Byte 1 Bits 0-6 */
- boolean Valid:1; /* Byte 1 Bit 7 */
+ bool Valid:1; /* Byte 1 Bit 7 */
DAC960_V1_CommandStatus_T CommandStatus; /* Bytes 2-3 */
} Fields;
}
@@ -2322,12 +2315,12 @@ typedef struct DAC960_Controller
unsigned long ShutdownMonitoringTimer;
unsigned long LastProgressReportTime;
unsigned long LastCurrentStatusTime;
- boolean ControllerInitialized;
- boolean MonitoringCommandDeferred;
- boolean EphemeralProgressMessage;
- boolean DriveSpinUpMessageDisplayed;
- boolean MonitoringAlertMode;
- boolean SuppressEnclosureMessages;
+ bool ControllerInitialized;
+ bool MonitoringCommandDeferred;
+ bool EphemeralProgressMessage;
+ bool DriveSpinUpMessageDisplayed;
+ bool MonitoringAlertMode;
+ bool SuppressEnclosureMessages;
struct timer_list MonitoringTimer;
struct gendisk *disks[DAC960_MaxLogicalDrives];
struct pci_pool *ScatterGatherPool;
@@ -2342,11 +2335,11 @@ typedef struct DAC960_Controller
DAC960_Command_T InitialCommand;
DAC960_Command_T *Commands[DAC960_MaxDriverQueueDepth];
struct proc_dir_entry *ControllerProcEntry;
- boolean LogicalDriveInitiallyAccessible[DAC960_MaxLogicalDrives];
+ bool LogicalDriveInitiallyAccessible[DAC960_MaxLogicalDrives];
void (*QueueCommand)(DAC960_Command_T *Command);
- boolean (*ReadControllerConfiguration)(struct DAC960_Controller *);
- boolean (*ReadDeviceConfiguration)(struct DAC960_Controller *);
- boolean (*ReportDeviceConfiguration)(struct DAC960_Controller *);
+ bool (*ReadControllerConfiguration)(struct DAC960_Controller *);
+ bool (*ReadDeviceConfiguration)(struct DAC960_Controller *);
+ bool (*ReportDeviceConfiguration)(struct DAC960_Controller *);
void (*QueueReadWriteCommand)(DAC960_Command_T *Command);
union {
struct {
@@ -2359,21 +2352,21 @@ typedef struct DAC960_Controller
unsigned short OldEventLogSequenceNumber;
unsigned short DeviceStateChannel;
unsigned short DeviceStateTargetID;
- boolean DualModeMemoryMailboxInterface;
- boolean BackgroundInitializationStatusSupported;
- boolean SAFTE_EnclosureManagementEnabled;
- boolean NeedLogicalDriveInformation;
- boolean NeedErrorTableInformation;
- boolean NeedDeviceStateInformation;
- boolean NeedDeviceInquiryInformation;
- boolean NeedDeviceSerialNumberInformation;
- boolean NeedRebuildProgress;
- boolean NeedConsistencyCheckProgress;
- boolean NeedBackgroundInitializationStatus;
- boolean StartDeviceStateScan;
- boolean RebuildProgressFirst;
- boolean RebuildFlagPending;
- boolean RebuildStatusPending;
+ bool DualModeMemoryMailboxInterface;
+ bool BackgroundInitializationStatusSupported;
+ bool SAFTE_EnclosureManagementEnabled;
+ bool NeedLogicalDriveInformation;
+ bool NeedErrorTableInformation;
+ bool NeedDeviceStateInformation;
+ bool NeedDeviceInquiryInformation;
+ bool NeedDeviceSerialNumberInformation;
+ bool NeedRebuildProgress;
+ bool NeedConsistencyCheckProgress;
+ bool NeedBackgroundInitializationStatus;
+ bool StartDeviceStateScan;
+ bool RebuildProgressFirst;
+ bool RebuildFlagPending;
+ bool RebuildStatusPending;
dma_addr_t FirstCommandMailboxDMA;
DAC960_V1_CommandMailbox_T *FirstCommandMailbox;
@@ -2432,17 +2425,17 @@ typedef struct DAC960_Controller
dma_addr_t NewInquiryUnitSerialNumberDMA;
int DeviceResetCount[DAC960_V1_MaxChannels][DAC960_V1_MaxTargets];
- boolean DirectCommandActive[DAC960_V1_MaxChannels][DAC960_V1_MaxTargets];
+ bool DirectCommandActive[DAC960_V1_MaxChannels][DAC960_V1_MaxTargets];
} V1;
struct {
unsigned int StatusChangeCounter;
unsigned int NextEventSequenceNumber;
unsigned int PhysicalDeviceIndex;
- boolean NeedLogicalDeviceInformation;
- boolean NeedPhysicalDeviceInformation;
- boolean NeedDeviceSerialNumberInformation;
- boolean StartLogicalDeviceInformationScan;
- boolean StartPhysicalDeviceInformationScan;
+ bool NeedLogicalDeviceInformation;
+ bool NeedPhysicalDeviceInformation;
+ bool NeedDeviceSerialNumberInformation;
+ bool StartLogicalDeviceInformationScan;
+ bool StartPhysicalDeviceInformationScan;
struct pci_pool *RequestSensePool;
dma_addr_t FirstCommandMailboxDMA;
@@ -2487,7 +2480,7 @@ typedef struct DAC960_Controller
DAC960_V2_PhysicalDevice_T
LogicalDriveToVirtualDevice[DAC960_MaxLogicalDrives];
- boolean LogicalDriveFoundDuringScan[DAC960_MaxLogicalDrives];
+ bool LogicalDriveFoundDuringScan[DAC960_MaxLogicalDrives];
} V2;
} FW;
unsigned char ProgressBuffer[DAC960_ProgressBufferSize];
@@ -2572,17 +2565,17 @@ typedef union DAC960_GEM_InboundDoorBellRegister
unsigned int All;
struct {
unsigned int :24;
- boolean HardwareMailboxNewCommand:1;
- boolean AcknowledgeHardwareMailboxStatus:1;
- boolean GenerateInterrupt:1;
- boolean ControllerReset:1;
- boolean MemoryMailboxNewCommand:1;
+ bool HardwareMailboxNewCommand:1;
+ bool AcknowledgeHardwareMailboxStatus:1;
+ bool GenerateInterrupt:1;
+ bool ControllerReset:1;
+ bool MemoryMailboxNewCommand:1;
unsigned int :3;
} Write;
struct {
unsigned int :24;
- boolean HardwareMailboxFull:1;
- boolean InitializationInProgress:1;
+ bool HardwareMailboxFull:1;
+ bool InitializationInProgress:1;
unsigned int :6;
} Read;
}
@@ -2596,14 +2589,14 @@ typedef union DAC960_GEM_OutboundDoorBellRegister
unsigned int All;
struct {
unsigned int :24;
- boolean AcknowledgeHardwareMailboxInterrupt:1;
- boolean AcknowledgeMemoryMailboxInterrupt:1;
+ bool AcknowledgeHardwareMailboxInterrupt:1;
+ bool AcknowledgeMemoryMailboxInterrupt:1;
unsigned int :6;
} Write;
struct {
unsigned int :24;
- boolean HardwareMailboxStatusAvailable:1;
- boolean MemoryMailboxStatusAvailable:1;
+ bool HardwareMailboxStatusAvailable:1;
+ bool MemoryMailboxStatusAvailable:1;
unsigned int :6;
} Read;
}
@@ -2635,7 +2628,7 @@ typedef union DAC960_GEM_ErrorStatusRegister
struct {
unsigned int :24;
unsigned int :5;
- boolean ErrorStatusPending:1;
+ bool ErrorStatusPending:1;
unsigned int :2;
} Bits;
}
@@ -2697,7 +2690,7 @@ void DAC960_GEM_MemoryMailboxNewCommand(void __iomem *ControllerBaseAddress)
}
static inline
-boolean DAC960_GEM_HardwareMailboxFullP(void __iomem *ControllerBaseAddress)
+bool DAC960_GEM_HardwareMailboxFullP(void __iomem *ControllerBaseAddress)
{
DAC960_GEM_InboundDoorBellRegister_T InboundDoorBellRegister;
InboundDoorBellRegister.All =
@@ -2707,7 +2700,7 @@ boolean DAC960_GEM_HardwareMailboxFullP(void __iomem *ControllerBaseAddress)
}
static inline
-boolean DAC960_GEM_InitializationInProgressP(void __iomem *ControllerBaseAddress)
+bool DAC960_GEM_InitializationInProgressP(void __iomem *ControllerBaseAddress)
{
DAC960_GEM_InboundDoorBellRegister_T InboundDoorBellRegister;
InboundDoorBellRegister.All =
@@ -2748,7 +2741,7 @@ void DAC960_GEM_AcknowledgeInterrupt(void __iomem *ControllerBaseAddress)
}
static inline
-boolean DAC960_GEM_HardwareMailboxStatusAvailableP(void __iomem *ControllerBaseAddress)
+bool DAC960_GEM_HardwareMailboxStatusAvailableP(void __iomem *ControllerBaseAddress)
{
DAC960_GEM_OutboundDoorBellRegister_T OutboundDoorBellRegister;
OutboundDoorBellRegister.All =
@@ -2758,7 +2751,7 @@ boolean DAC960_GEM_HardwareMailboxStatusAvailableP(void __iomem *ControllerBaseA
}
static inline
-boolean DAC960_GEM_MemoryMailboxStatusAvailableP(void __iomem *ControllerBaseAddress)
+bool DAC960_GEM_MemoryMailboxStatusAvailableP(void __iomem *ControllerBaseAddress)
{
DAC960_GEM_OutboundDoorBellRegister_T OutboundDoorBellRegister;
OutboundDoorBellRegister.All =
@@ -2790,7 +2783,7 @@ void DAC960_GEM_DisableInterrupts(void __iomem *ControllerBaseAddress)
}
static inline
-boolean DAC960_GEM_InterruptsEnabledP(void __iomem *ControllerBaseAddress)
+bool DAC960_GEM_InterruptsEnabledP(void __iomem *ControllerBaseAddress)
{
DAC960_GEM_InterruptMaskRegister_T InterruptMaskRegister;
InterruptMaskRegister.All =
@@ -2834,7 +2827,7 @@ DAC960_GEM_ReadCommandStatus(void __iomem *ControllerBaseAddress)
return readw(ControllerBaseAddress + DAC960_GEM_CommandStatusOffset + 2);
}
-static inline boolean
+static inline bool
DAC960_GEM_ReadErrorStatus(void __iomem *ControllerBaseAddress,
unsigned char *ErrorStatus,
unsigned char *Parameter0,
@@ -2882,16 +2875,16 @@ typedef union DAC960_BA_InboundDoorBellRegister
{
unsigned char All;
struct {
- boolean HardwareMailboxNewCommand:1; /* Bit 0 */
- boolean AcknowledgeHardwareMailboxStatus:1; /* Bit 1 */
- boolean GenerateInterrupt:1; /* Bit 2 */
- boolean ControllerReset:1; /* Bit 3 */
- boolean MemoryMailboxNewCommand:1; /* Bit 4 */
+ bool HardwareMailboxNewCommand:1; /* Bit 0 */
+ bool AcknowledgeHardwareMailboxStatus:1; /* Bit 1 */
+ bool GenerateInterrupt:1; /* Bit 2 */
+ bool ControllerReset:1; /* Bit 3 */
+ bool MemoryMailboxNewCommand:1; /* Bit 4 */
unsigned char :3; /* Bits 5-7 */
} Write;
struct {
- boolean HardwareMailboxEmpty:1; /* Bit 0 */
- boolean InitializationNotInProgress:1; /* Bit 1 */
+ bool HardwareMailboxEmpty:1; /* Bit 0 */
+ bool InitializationNotInProgress:1; /* Bit 1 */
unsigned char :6; /* Bits 2-7 */
} Read;
}
@@ -2906,13 +2899,13 @@ typedef union DAC960_BA_OutboundDoorBellRegister
{
unsigned char All;
struct {
- boolean AcknowledgeHardwareMailboxInterrupt:1; /* Bit 0 */
- boolean AcknowledgeMemoryMailboxInterrupt:1; /* Bit 1 */
+ bool AcknowledgeHardwareMailboxInterrupt:1; /* Bit 0 */
+ bool AcknowledgeMemoryMailboxInterrupt:1; /* Bit 1 */
unsigned char :6; /* Bits 2-7 */
} Write;
struct {
- boolean HardwareMailboxStatusAvailable:1; /* Bit 0 */
- boolean MemoryMailboxStatusAvailable:1; /* Bit 1 */
+ bool HardwareMailboxStatusAvailable:1; /* Bit 0 */
+ bool MemoryMailboxStatusAvailable:1; /* Bit 1 */
unsigned char :6; /* Bits 2-7 */
} Read;
}
@@ -2928,8 +2921,8 @@ typedef union DAC960_BA_InterruptMaskRegister
unsigned char All;
struct {
unsigned int :2; /* Bits 0-1 */
- boolean DisableInterrupts:1; /* Bit 2 */
- boolean DisableInterruptsI2O:1; /* Bit 3 */
+ bool DisableInterrupts:1; /* Bit 2 */
+ bool DisableInterruptsI2O:1; /* Bit 3 */
unsigned int :4; /* Bits 4-7 */
} Bits;
}
@@ -2945,7 +2938,7 @@ typedef union DAC960_BA_ErrorStatusRegister
unsigned char All;
struct {
unsigned int :2; /* Bits 0-1 */
- boolean ErrorStatusPending:1; /* Bit 2 */
+ bool ErrorStatusPending:1; /* Bit 2 */
unsigned int :5; /* Bits 3-7 */
} Bits;
}
@@ -3008,7 +3001,7 @@ void DAC960_BA_MemoryMailboxNewCommand(void __iomem *ControllerBaseAddress)
}
static inline
-boolean DAC960_BA_HardwareMailboxFullP(void __iomem *ControllerBaseAddress)
+bool DAC960_BA_HardwareMailboxFullP(void __iomem *ControllerBaseAddress)
{
DAC960_BA_InboundDoorBellRegister_T InboundDoorBellRegister;
InboundDoorBellRegister.All =
@@ -3017,7 +3010,7 @@ boolean DAC960_BA_HardwareMailboxFullP(void __iomem *ControllerBaseAddress)
}
static inline
-boolean DAC960_BA_InitializationInProgressP(void __iomem *ControllerBaseAddress)
+bool DAC960_BA_InitializationInProgressP(void __iomem *ControllerBaseAddress)
{
DAC960_BA_InboundDoorBellRegister_T InboundDoorBellRegister;
InboundDoorBellRegister.All =
@@ -3057,7 +3050,7 @@ void DAC960_BA_AcknowledgeInterrupt(void __iomem *ControllerBaseAddress)
}
static inline
-boolean DAC960_BA_HardwareMailboxStatusAvailableP(void __iomem *ControllerBaseAddress)
+bool DAC960_BA_HardwareMailboxStatusAvailableP(void __iomem *ControllerBaseAddress)
{
DAC960_BA_OutboundDoorBellRegister_T OutboundDoorBellRegister;
OutboundDoorBellRegister.All =
@@ -3066,7 +3059,7 @@ boolean DAC960_BA_HardwareMailboxStatusAvailableP(void __iomem *ControllerBaseAd
}
static inline
-boolean DAC960_BA_MemoryMailboxStatusAvailableP(void __iomem *ControllerBaseAddress)
+bool DAC960_BA_MemoryMailboxStatusAvailableP(void __iomem *ControllerBaseAddress)
{
DAC960_BA_OutboundDoorBellRegister_T OutboundDoorBellRegister;
OutboundDoorBellRegister.All =
@@ -3097,7 +3090,7 @@ void DAC960_BA_DisableInterrupts(void __iomem *ControllerBaseAddress)
}
static inline
-boolean DAC960_BA_InterruptsEnabledP(void __iomem *ControllerBaseAddress)
+bool DAC960_BA_InterruptsEnabledP(void __iomem *ControllerBaseAddress)
{
DAC960_BA_InterruptMaskRegister_T InterruptMaskRegister;
InterruptMaskRegister.All =
@@ -3140,7 +3133,7 @@ DAC960_BA_ReadCommandStatus(void __iomem *ControllerBaseAddress)
return readw(ControllerBaseAddress + DAC960_BA_CommandStatusOffset + 2);
}
-static inline boolean
+static inline bool
DAC960_BA_ReadErrorStatus(void __iomem *ControllerBaseAddress,
unsigned char *ErrorStatus,
unsigned char *Parameter0,
@@ -3188,16 +3181,16 @@ typedef union DAC960_LP_InboundDoorBellRegister
{
unsigned char All;
struct {
- boolean HardwareMailboxNewCommand:1; /* Bit 0 */
- boolean AcknowledgeHardwareMailboxStatus:1; /* Bit 1 */
- boolean GenerateInterrupt:1; /* Bit 2 */
- boolean ControllerReset:1; /* Bit 3 */
- boolean MemoryMailboxNewCommand:1; /* Bit 4 */
+ bool HardwareMailboxNewCommand:1; /* Bit 0 */
+ bool AcknowledgeHardwareMailboxStatus:1; /* Bit 1 */
+ bool GenerateInterrupt:1; /* Bit 2 */
+ bool ControllerReset:1; /* Bit 3 */
+ bool MemoryMailboxNewCommand:1; /* Bit 4 */
unsigned char :3; /* Bits 5-7 */
} Write;
struct {
- boolean HardwareMailboxFull:1; /* Bit 0 */
- boolean InitializationInProgress:1; /* Bit 1 */
+ bool HardwareMailboxFull:1; /* Bit 0 */
+ bool InitializationInProgress:1; /* Bit 1 */
unsigned char :6; /* Bits 2-7 */
} Read;
}
@@ -3212,13 +3205,13 @@ typedef union DAC960_LP_OutboundDoorBellRegister
{
unsigned char All;
struct {
- boolean AcknowledgeHardwareMailboxInterrupt:1; /* Bit 0 */
- boolean AcknowledgeMemoryMailboxInterrupt:1; /* Bit 1 */
+ bool AcknowledgeHardwareMailboxInterrupt:1; /* Bit 0 */
+ bool AcknowledgeMemoryMailboxInterrupt:1; /* Bit 1 */
unsigned char :6; /* Bits 2-7 */
} Write;
struct {
- boolean HardwareMailboxStatusAvailable:1; /* Bit 0 */
- boolean MemoryMailboxStatusAvailable:1; /* Bit 1 */
+ bool HardwareMailboxStatusAvailable:1; /* Bit 0 */
+ bool MemoryMailboxStatusAvailable:1; /* Bit 1 */
unsigned char :6; /* Bits 2-7 */
} Read;
}
@@ -3234,7 +3227,7 @@ typedef union DAC960_LP_InterruptMaskRegister
unsigned char All;
struct {
unsigned int :2; /* Bits 0-1 */
- boolean DisableInterrupts:1; /* Bit 2 */
+ bool DisableInterrupts:1; /* Bit 2 */
unsigned int :5; /* Bits 3-7 */
} Bits;
}
@@ -3250,7 +3243,7 @@ typedef union DAC960_LP_ErrorStatusRegister
unsigned char All;
struct {
unsigned int :2; /* Bits 0-1 */
- boolean ErrorStatusPending:1; /* Bit 2 */
+ bool ErrorStatusPending:1; /* Bit 2 */
unsigned int :5; /* Bits 3-7 */
} Bits;
}
@@ -3313,7 +3306,7 @@ void DAC960_LP_MemoryMailboxNewCommand(void __iomem *ControllerBaseAddress)
}
static inline
-boolean DAC960_LP_HardwareMailboxFullP(void __iomem *ControllerBaseAddress)
+bool DAC960_LP_HardwareMailboxFullP(void __iomem *ControllerBaseAddress)
{
DAC960_LP_InboundDoorBellRegister_T InboundDoorBellRegister;
InboundDoorBellRegister.All =
@@ -3322,7 +3315,7 @@ boolean DAC960_LP_HardwareMailboxFullP(void __iomem *ControllerBaseAddress)
}
static inline
-boolean DAC960_LP_InitializationInProgressP(void __iomem *ControllerBaseAddress)
+bool DAC960_LP_InitializationInProgressP(void __iomem *ControllerBaseAddress)
{
DAC960_LP_InboundDoorBellRegister_T InboundDoorBellRegister;
InboundDoorBellRegister.All =
@@ -3362,7 +3355,7 @@ void DAC960_LP_AcknowledgeInterrupt(void __iomem *ControllerBaseAddress)
}
static inline
-boolean DAC960_LP_HardwareMailboxStatusAvailableP(void __iomem *ControllerBaseAddress)
+bool DAC960_LP_HardwareMailboxStatusAvailableP(void __iomem *ControllerBaseAddress)
{
DAC960_LP_OutboundDoorBellRegister_T OutboundDoorBellRegister;
OutboundDoorBellRegister.All =
@@ -3371,7 +3364,7 @@ boolean DAC960_LP_HardwareMailboxStatusAvailableP(void __iomem *ControllerBaseAd
}
static inline
-boolean DAC960_LP_MemoryMailboxStatusAvailableP(void __iomem *ControllerBaseAddress)
+bool DAC960_LP_MemoryMailboxStatusAvailableP(void __iomem *ControllerBaseAddress)
{
DAC960_LP_OutboundDoorBellRegister_T OutboundDoorBellRegister;
OutboundDoorBellRegister.All =
@@ -3400,7 +3393,7 @@ void DAC960_LP_DisableInterrupts(void __iomem *ControllerBaseAddress)
}
static inline
-boolean DAC960_LP_InterruptsEnabledP(void __iomem *ControllerBaseAddress)
+bool DAC960_LP_InterruptsEnabledP(void __iomem *ControllerBaseAddress)
{
DAC960_LP_InterruptMaskRegister_T InterruptMaskRegister;
InterruptMaskRegister.All =
@@ -3442,7 +3435,7 @@ DAC960_LP_ReadCommandStatus(void __iomem *ControllerBaseAddress)
return readw(ControllerBaseAddress + DAC960_LP_CommandStatusOffset + 2);
}
-static inline boolean
+static inline bool
DAC960_LP_ReadErrorStatus(void __iomem *ControllerBaseAddress,
unsigned char *ErrorStatus,
unsigned char *Parameter0,
@@ -3502,16 +3495,16 @@ typedef union DAC960_LA_InboundDoorBellRegister
{
unsigned char All;
struct {
- boolean HardwareMailboxNewCommand:1; /* Bit 0 */
- boolean AcknowledgeHardwareMailboxStatus:1; /* Bit 1 */
- boolean GenerateInterrupt:1; /* Bit 2 */
- boolean ControllerReset:1; /* Bit 3 */
- boolean MemoryMailboxNewCommand:1; /* Bit 4 */
+ bool HardwareMailboxNewCommand:1; /* Bit 0 */
+ bool AcknowledgeHardwareMailboxStatus:1; /* Bit 1 */
+ bool GenerateInterrupt:1; /* Bit 2 */
+ bool ControllerReset:1; /* Bit 3 */
+ bool MemoryMailboxNewCommand:1; /* Bit 4 */
unsigned char :3; /* Bits 5-7 */
} Write;
struct {
- boolean HardwareMailboxEmpty:1; /* Bit 0 */
- boolean InitializationNotInProgress:1; /* Bit 1 */
+ bool HardwareMailboxEmpty:1; /* Bit 0 */
+ bool InitializationNotInProgress:1; /* Bit 1 */
unsigned char :6; /* Bits 2-7 */
} Read;
}
@@ -3526,13 +3519,13 @@ typedef union DAC960_LA_OutboundDoorBellRegister
{
unsigned char All;
struct {
- boolean AcknowledgeHardwareMailboxInterrupt:1; /* Bit 0 */
- boolean AcknowledgeMemoryMailboxInterrupt:1; /* Bit 1 */
+ bool AcknowledgeHardwareMailboxInterrupt:1; /* Bit 0 */
+ bool AcknowledgeMemoryMailboxInterrupt:1; /* Bit 1 */
unsigned char :6; /* Bits 2-7 */
} Write;
struct {
- boolean HardwareMailboxStatusAvailable:1; /* Bit 0 */
- boolean MemoryMailboxStatusAvailable:1; /* Bit 1 */
+ bool HardwareMailboxStatusAvailable:1; /* Bit 0 */
+ bool MemoryMailboxStatusAvailable:1; /* Bit 1 */
unsigned char :6; /* Bits 2-7 */
} Read;
}
@@ -3548,7 +3541,7 @@ typedef union DAC960_LA_InterruptMaskRegister
unsigned char All;
struct {
unsigned char :2; /* Bits 0-1 */
- boolean DisableInterrupts:1; /* Bit 2 */
+ bool DisableInterrupts:1; /* Bit 2 */
unsigned char :5; /* Bits 3-7 */
} Bits;
}
@@ -3564,7 +3557,7 @@ typedef union DAC960_LA_ErrorStatusRegister
unsigned char All;
struct {
unsigned int :2; /* Bits 0-1 */
- boolean ErrorStatusPending:1; /* Bit 2 */
+ bool ErrorStatusPending:1; /* Bit 2 */
unsigned int :5; /* Bits 3-7 */
} Bits;
}
@@ -3627,7 +3620,7 @@ void DAC960_LA_MemoryMailboxNewCommand(void __iomem *ControllerBaseAddress)
}
static inline
-boolean DAC960_LA_HardwareMailboxFullP(void __iomem *ControllerBaseAddress)
+bool DAC960_LA_HardwareMailboxFullP(void __iomem *ControllerBaseAddress)
{
DAC960_LA_InboundDoorBellRegister_T InboundDoorBellRegister;
InboundDoorBellRegister.All =
@@ -3636,7 +3629,7 @@ boolean DAC960_LA_HardwareMailboxFullP(void __iomem *ControllerBaseAddress)
}
static inline
-boolean DAC960_LA_InitializationInProgressP(void __iomem *ControllerBaseAddress)
+bool DAC960_LA_InitializationInProgressP(void __iomem *ControllerBaseAddress)
{
DAC960_LA_InboundDoorBellRegister_T InboundDoorBellRegister;
InboundDoorBellRegister.All =
@@ -3676,7 +3669,7 @@ void DAC960_LA_AcknowledgeInterrupt(void __iomem *ControllerBaseAddress)
}
static inline
-boolean DAC960_LA_HardwareMailboxStatusAvailableP(void __iomem *ControllerBaseAddress)
+bool DAC960_LA_HardwareMailboxStatusAvailableP(void __iomem *ControllerBaseAddress)
{
DAC960_LA_OutboundDoorBellRegister_T OutboundDoorBellRegister;
OutboundDoorBellRegister.All =
@@ -3685,7 +3678,7 @@ boolean DAC960_LA_HardwareMailboxStatusAvailableP(void __iomem *ControllerBaseAd
}
static inline
-boolean DAC960_LA_MemoryMailboxStatusAvailableP(void __iomem *ControllerBaseAddress)
+bool DAC960_LA_MemoryMailboxStatusAvailableP(void __iomem *ControllerBaseAddress)
{
DAC960_LA_OutboundDoorBellRegister_T OutboundDoorBellRegister;
OutboundDoorBellRegister.All =
@@ -3714,7 +3707,7 @@ void DAC960_LA_DisableInterrupts(void __iomem *ControllerBaseAddress)
}
static inline
-boolean DAC960_LA_InterruptsEnabledP(void __iomem *ControllerBaseAddress)
+bool DAC960_LA_InterruptsEnabledP(void __iomem *ControllerBaseAddress)
{
DAC960_LA_InterruptMaskRegister_T InterruptMaskRegister;
InterruptMaskRegister.All =
@@ -3763,7 +3756,7 @@ DAC960_LA_ReadStatusRegister(void __iomem *ControllerBaseAddress)
return readw(ControllerBaseAddress + DAC960_LA_StatusRegisterOffset);
}
-static inline boolean
+static inline bool
DAC960_LA_ReadErrorStatus(void __iomem *ControllerBaseAddress,
unsigned char *ErrorStatus,
unsigned char *Parameter0,
@@ -3822,16 +3815,16 @@ typedef union DAC960_PG_InboundDoorBellRegister
{
unsigned int All;
struct {
- boolean HardwareMailboxNewCommand:1; /* Bit 0 */
- boolean AcknowledgeHardwareMailboxStatus:1; /* Bit 1 */
- boolean GenerateInterrupt:1; /* Bit 2 */
- boolean ControllerReset:1; /* Bit 3 */
- boolean MemoryMailboxNewCommand:1; /* Bit 4 */
+ bool HardwareMailboxNewCommand:1; /* Bit 0 */
+ bool AcknowledgeHardwareMailboxStatus:1; /* Bit 1 */
+ bool GenerateInterrupt:1; /* Bit 2 */
+ bool ControllerReset:1; /* Bit 3 */
+ bool MemoryMailboxNewCommand:1; /* Bit 4 */
unsigned int :27; /* Bits 5-31 */
} Write;
struct {
- boolean HardwareMailboxFull:1; /* Bit 0 */
- boolean InitializationInProgress:1; /* Bit 1 */
+ bool HardwareMailboxFull:1; /* Bit 0 */
+ bool InitializationInProgress:1; /* Bit 1 */
unsigned int :30; /* Bits 2-31 */
} Read;
}
@@ -3846,13 +3839,13 @@ typedef union DAC960_PG_OutboundDoorBellRegister
{
unsigned int All;
struct {
- boolean AcknowledgeHardwareMailboxInterrupt:1; /* Bit 0 */
- boolean AcknowledgeMemoryMailboxInterrupt:1; /* Bit 1 */
+ bool AcknowledgeHardwareMailboxInterrupt:1; /* Bit 0 */
+ bool AcknowledgeMemoryMailboxInterrupt:1; /* Bit 1 */
unsigned int :30; /* Bits 2-31 */
} Write;
struct {
- boolean HardwareMailboxStatusAvailable:1; /* Bit 0 */
- boolean MemoryMailboxStatusAvailable:1; /* Bit 1 */
+ bool HardwareMailboxStatusAvailable:1; /* Bit 0 */
+ bool MemoryMailboxStatusAvailable:1; /* Bit 1 */
unsigned int :30; /* Bits 2-31 */
} Read;
}
@@ -3868,7 +3861,7 @@ typedef union DAC960_PG_InterruptMaskRegister
unsigned int All;
struct {
unsigned int MessageUnitInterruptMask1:2; /* Bits 0-1 */
- boolean DisableInterrupts:1; /* Bit 2 */
+ bool DisableInterrupts:1; /* Bit 2 */
unsigned int MessageUnitInterruptMask2:5; /* Bits 3-7 */
unsigned int Reserved0:24; /* Bits 8-31 */
} Bits;
@@ -3885,7 +3878,7 @@ typedef union DAC960_PG_ErrorStatusRegister
unsigned char All;
struct {
unsigned int :2; /* Bits 0-1 */
- boolean ErrorStatusPending:1; /* Bit 2 */
+ bool ErrorStatusPending:1; /* Bit 2 */
unsigned int :5; /* Bits 3-7 */
} Bits;
}
@@ -3948,7 +3941,7 @@ void DAC960_PG_MemoryMailboxNewCommand(void __iomem *ControllerBaseAddress)
}
static inline
-boolean DAC960_PG_HardwareMailboxFullP(void __iomem *ControllerBaseAddress)
+bool DAC960_PG_HardwareMailboxFullP(void __iomem *ControllerBaseAddress)
{
DAC960_PG_InboundDoorBellRegister_T InboundDoorBellRegister;
InboundDoorBellRegister.All =
@@ -3957,7 +3950,7 @@ boolean DAC960_PG_HardwareMailboxFullP(void __iomem *ControllerBaseAddress)
}
static inline
-boolean DAC960_PG_InitializationInProgressP(void __iomem *ControllerBaseAddress)
+bool DAC960_PG_InitializationInProgressP(void __iomem *ControllerBaseAddress)
{
DAC960_PG_InboundDoorBellRegister_T InboundDoorBellRegister;
InboundDoorBellRegister.All =
@@ -3997,7 +3990,7 @@ void DAC960_PG_AcknowledgeInterrupt(void __iomem *ControllerBaseAddress)
}
static inline
-boolean DAC960_PG_HardwareMailboxStatusAvailableP(void __iomem *ControllerBaseAddress)
+bool DAC960_PG_HardwareMailboxStatusAvailableP(void __iomem *ControllerBaseAddress)
{
DAC960_PG_OutboundDoorBellRegister_T OutboundDoorBellRegister;
OutboundDoorBellRegister.All =
@@ -4006,7 +3999,7 @@ boolean DAC960_PG_HardwareMailboxStatusAvailableP(void __iomem *ControllerBaseAd
}
static inline
-boolean DAC960_PG_MemoryMailboxStatusAvailableP(void __iomem *ControllerBaseAddress)
+bool DAC960_PG_MemoryMailboxStatusAvailableP(void __iomem *ControllerBaseAddress)
{
DAC960_PG_OutboundDoorBellRegister_T OutboundDoorBellRegister;
OutboundDoorBellRegister.All =
@@ -4039,7 +4032,7 @@ void DAC960_PG_DisableInterrupts(void __iomem *ControllerBaseAddress)
}
static inline
-boolean DAC960_PG_InterruptsEnabledP(void __iomem *ControllerBaseAddress)
+bool DAC960_PG_InterruptsEnabledP(void __iomem *ControllerBaseAddress)
{
DAC960_PG_InterruptMaskRegister_T InterruptMaskRegister;
InterruptMaskRegister.All =
@@ -4088,7 +4081,7 @@ DAC960_PG_ReadStatusRegister(void __iomem *ControllerBaseAddress)
return readw(ControllerBaseAddress + DAC960_PG_StatusRegisterOffset);
}
-static inline boolean
+static inline bool
DAC960_PG_ReadErrorStatus(void __iomem *ControllerBaseAddress,
unsigned char *ErrorStatus,
unsigned char *Parameter0,
@@ -4147,15 +4140,15 @@ typedef union DAC960_PD_InboundDoorBellRegister
{
unsigned char All;
struct {
- boolean NewCommand:1; /* Bit 0 */
- boolean AcknowledgeStatus:1; /* Bit 1 */
- boolean GenerateInterrupt:1; /* Bit 2 */
- boolean ControllerReset:1; /* Bit 3 */
+ bool NewCommand:1; /* Bit 0 */
+ bool AcknowledgeStatus:1; /* Bit 1 */
+ bool GenerateInterrupt:1; /* Bit 2 */
+ bool ControllerReset:1; /* Bit 3 */
unsigned char :4; /* Bits 4-7 */
} Write;
struct {
- boolean MailboxFull:1; /* Bit 0 */
- boolean InitializationInProgress:1; /* Bit 1 */
+ bool MailboxFull:1; /* Bit 0 */
+ bool InitializationInProgress:1; /* Bit 1 */
unsigned char :6; /* Bits 2-7 */
} Read;
}
@@ -4170,11 +4163,11 @@ typedef union DAC960_PD_OutboundDoorBellRegister
{
unsigned char All;
struct {
- boolean AcknowledgeInterrupt:1; /* Bit 0 */
+ bool AcknowledgeInterrupt:1; /* Bit 0 */
unsigned char :7; /* Bits 1-7 */
} Write;
struct {
- boolean StatusAvailable:1; /* Bit 0 */
+ bool StatusAvailable:1; /* Bit 0 */
unsigned char :7; /* Bits 1-7 */
} Read;
}
@@ -4189,7 +4182,7 @@ typedef union DAC960_PD_InterruptEnableRegister
{
unsigned char All;
struct {
- boolean EnableInterrupts:1; /* Bit 0 */
+ bool EnableInterrupts:1; /* Bit 0 */
unsigned char :7; /* Bits 1-7 */
} Bits;
}
@@ -4205,7 +4198,7 @@ typedef union DAC960_PD_ErrorStatusRegister
unsigned char All;
struct {
unsigned int :2; /* Bits 0-1 */
- boolean ErrorStatusPending:1; /* Bit 2 */
+ bool ErrorStatusPending:1; /* Bit 2 */
unsigned int :5; /* Bits 3-7 */
} Bits;
}
@@ -4258,7 +4251,7 @@ void DAC960_PD_ControllerReset(void __iomem *ControllerBaseAddress)
}
static inline
-boolean DAC960_PD_MailboxFullP(void __iomem *ControllerBaseAddress)
+bool DAC960_PD_MailboxFullP(void __iomem *ControllerBaseAddress)
{
DAC960_PD_InboundDoorBellRegister_T InboundDoorBellRegister;
InboundDoorBellRegister.All =
@@ -4267,7 +4260,7 @@ boolean DAC960_PD_MailboxFullP(void __iomem *ControllerBaseAddress)
}
static inline
-boolean DAC960_PD_InitializationInProgressP(void __iomem *ControllerBaseAddress)
+bool DAC960_PD_InitializationInProgressP(void __iomem *ControllerBaseAddress)
{
DAC960_PD_InboundDoorBellRegister_T InboundDoorBellRegister;
InboundDoorBellRegister.All =
@@ -4286,7 +4279,7 @@ void DAC960_PD_AcknowledgeInterrupt(void __iomem *ControllerBaseAddress)
}
static inline
-boolean DAC960_PD_StatusAvailableP(void __iomem *ControllerBaseAddress)
+bool DAC960_PD_StatusAvailableP(void __iomem *ControllerBaseAddress)
{
DAC960_PD_OutboundDoorBellRegister_T OutboundDoorBellRegister;
OutboundDoorBellRegister.All =
@@ -4315,7 +4308,7 @@ void DAC960_PD_DisableInterrupts(void __iomem *ControllerBaseAddress)
}
static inline
-boolean DAC960_PD_InterruptsEnabledP(void __iomem *ControllerBaseAddress)
+bool DAC960_PD_InterruptsEnabledP(void __iomem *ControllerBaseAddress)
{
DAC960_PD_InterruptEnableRegister_T InterruptEnableRegister;
InterruptEnableRegister.All =
@@ -4350,7 +4343,7 @@ DAC960_PD_ReadStatusRegister(void __iomem *ControllerBaseAddress)
return readw(ControllerBaseAddress + DAC960_PD_StatusRegisterOffset);
}
-static inline boolean
+static inline bool
DAC960_PD_ReadErrorStatus(void __iomem *ControllerBaseAddress,
unsigned char *ErrorStatus,
unsigned char *Parameter0,
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index 58c1debf86f..cacb1c816e3 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -417,8 +417,10 @@ config BLK_DEV_INITRD
etc. See <file:Documentation/initrd.txt> for details.
If RAM disk support (BLK_DEV_RAM) is also included, this
- also enables initial RAM disk (initrd) support.
+ also enables initial RAM disk (initrd) support and adds
+ 15 Kbytes (more on some other architectures) to the kernel size.
+ If unsure say Y.
config CDROM_PKTCDVD
tristate "Packet writing on CD/DVD media"
diff --git a/drivers/block/acsi.c b/drivers/block/acsi.c
index 706cdc6a69e..e3d9152e231 100644
--- a/drivers/block/acsi.c
+++ b/drivers/block/acsi.c
@@ -46,7 +46,6 @@
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/signal.h>
-#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/fs.h>
#include <linux/kernel.h>
diff --git a/drivers/block/acsi_slm.c b/drivers/block/acsi_slm.c
index e04be94d195..e2e04329096 100644
--- a/drivers/block/acsi_slm.c
+++ b/drivers/block/acsi_slm.c
@@ -269,7 +269,7 @@ static int slm_get_pagesize( int device, int *w, int *h );
static DEFINE_TIMER(slm_timer, slm_test_ready, 0, 0);
-static struct file_operations slm_fops = {
+static const struct file_operations slm_fops = {
.owner = THIS_MODULE,
.read = slm_read,
.write = slm_write,
diff --git a/drivers/block/aoe/aoechr.c b/drivers/block/aoe/aoechr.c
index e22b4c9520a..39e563ea087 100644
--- a/drivers/block/aoe/aoechr.c
+++ b/drivers/block/aoe/aoechr.c
@@ -233,7 +233,7 @@ loop:
}
}
-static struct file_operations aoe_fops = {
+static const struct file_operations aoe_fops = {
.write = aoechr_write,
.read = aoechr_read,
.open = aoechr_open,
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index 3f1b38276e9..5231ed7e723 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -297,17 +297,17 @@ static int initialising = 1;
#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 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 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 DPRINT(format, args...) printk(DEVICE_NAME "%d: " format, current_drive , ## args)
diff --git a/drivers/block/paride/Kconfig b/drivers/block/paride/Kconfig
index c0d2854dd09..28cf3082d44 100644
--- a/drivers/block/paride/Kconfig
+++ b/drivers/block/paride/Kconfig
@@ -2,14 +2,8 @@
# PARIDE configuration
#
# PARIDE doesn't need PARPORT, but if PARPORT is configured as a module,
-# PARIDE must also be a module. The bogus CONFIG_PARIDE_PARPORT option
-# controls the choices given to the user ...
+# PARIDE must also be a module.
# PARIDE only supports PC style parports. Tough for USB or other parports...
-config PARIDE_PARPORT
- tristate
- depends on PARIDE!=n
- default m if PARPORT_PC=m
- default y if PARPORT_PC!=m
comment "Parallel IDE high-level drivers"
depends on PARIDE
diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c
index 9d9bff23f42..99e2c8ce1cc 100644
--- a/drivers/block/paride/pd.c
+++ b/drivers/block/paride/pd.c
@@ -153,7 +153,6 @@ enum {D_PRT, D_PRO, D_UNI, D_MOD, D_GEO, D_SBY, D_DLY, D_SLV};
#include <linux/blkpg.h>
#include <linux/kernel.h>
#include <asm/uaccess.h>
-#include <linux/sched.h>
#include <linux/workqueue.h>
static DEFINE_SPINLOCK(pd_lock);
diff --git a/drivers/block/paride/pg.c b/drivers/block/paride/pg.c
index 9970aedbb5d..d89e7d32a3b 100644
--- a/drivers/block/paride/pg.c
+++ b/drivers/block/paride/pg.c
@@ -227,7 +227,7 @@ static struct class *pg_class;
/* kernel glue structures */
-static struct file_operations pg_fops = {
+static const struct file_operations pg_fops = {
.owner = THIS_MODULE,
.read = pg_read,
.write = pg_write,
diff --git a/drivers/block/paride/pt.c b/drivers/block/paride/pt.c
index c902b25e486..9f4e67ee1eb 100644
--- a/drivers/block/paride/pt.c
+++ b/drivers/block/paride/pt.c
@@ -232,7 +232,7 @@ static char pt_scratch[512]; /* scratch block buffer */
/* kernel glue structures */
-static struct file_operations pt_fops = {
+static const struct file_operations pt_fops = {
.owner = THIS_MODULE,
.read = pt_read,
.write = pt_write,
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
index 62462190e07..a4fb7038318 100644
--- a/drivers/block/pktcdvd.c
+++ b/drivers/block/pktcdvd.c
@@ -190,15 +190,6 @@ static struct attribute *kobj_pkt_attrs_wqueue[] = {
NULL
};
-/* declares a char buffer[64] _dbuf, copies data from
- * _b with length _l into it and ensures that _dbuf ends
- * with a \0 character.
- */
-#define DECLARE_BUF_AS_STRING(_dbuf, _b, _l) \
- char _dbuf[64]; int dlen = (_l) < 0 ? 0 : (_l); \
- if (dlen >= sizeof(_dbuf)) dlen = sizeof(_dbuf)-1; \
- memcpy(_dbuf, _b, dlen); _dbuf[dlen] = 0
-
static ssize_t kobj_pkt_show(struct kobject *kobj,
struct attribute *attr, char *data)
{
@@ -264,9 +255,8 @@ static ssize_t kobj_pkt_store(struct kobject *kobj,
{
struct pktcdvd_device *pd = to_pktcdvdkobj(kobj)->pd;
int val;
- DECLARE_BUF_AS_STRING(dbuf, data, len); /* ensure sscanf scans a string */
- if (strcmp(attr->name, "reset") == 0 && dlen > 0) {
+ if (strcmp(attr->name, "reset") == 0 && len > 0) {
pd->stats.pkt_started = 0;
pd->stats.pkt_ended = 0;
pd->stats.secs_w = 0;
@@ -274,7 +264,7 @@ static ssize_t kobj_pkt_store(struct kobject *kobj,
pd->stats.secs_r = 0;
} else if (strcmp(attr->name, "congestion_off") == 0
- && sscanf(dbuf, "%d", &val) == 1) {
+ && sscanf(data, "%d", &val) == 1) {
spin_lock(&pd->lock);
pd->write_congestion_off = val;
init_write_congestion_marks(&pd->write_congestion_off,
@@ -282,7 +272,7 @@ static ssize_t kobj_pkt_store(struct kobject *kobj,
spin_unlock(&pd->lock);
} else if (strcmp(attr->name, "congestion_on") == 0
- && sscanf(dbuf, "%d", &val) == 1) {
+ && sscanf(data, "%d", &val) == 1) {
spin_lock(&pd->lock);
pd->write_congestion_on = val;
init_write_congestion_marks(&pd->write_congestion_off,
@@ -369,8 +359,7 @@ static ssize_t class_pktcdvd_store_add(struct class *c, const char *buf,
size_t count)
{
unsigned int major, minor;
- DECLARE_BUF_AS_STRING(dbuf, buf, count);
- if (sscanf(dbuf, "%u:%u", &major, &minor) == 2) {
+ if (sscanf(buf, "%u:%u", &major, &minor) == 2) {
pkt_setup_dev(MKDEV(major, minor), NULL);
return count;
}
@@ -381,8 +370,7 @@ static ssize_t class_pktcdvd_store_remove(struct class *c, const char *buf,
size_t count)
{
unsigned int major, minor;
- DECLARE_BUF_AS_STRING(dbuf, buf, count);
- if (sscanf(dbuf, "%u:%u", &major, &minor) == 2) {
+ if (sscanf(buf, "%u:%u", &major, &minor) == 2) {
pkt_remove_dev(MKDEV(major, minor));
return count;
}
@@ -447,7 +435,7 @@ static int pkt_debugfs_fops_open(struct inode *inode, struct file *file)
return single_open(file, pkt_debugfs_seq_show, inode->i_private);
}
-static struct file_operations debug_fops = {
+static const struct file_operations debug_fops = {
.open = pkt_debugfs_fops_open,
.read = seq_read,
.llseek = seq_lseek,
@@ -777,7 +765,7 @@ static int pkt_generic_packet(struct pktcdvd_device *pd, struct packet_command *
goto out;
}
- rq->cmd_len = COMMAND_SIZE(rq->cmd[0]);
+ rq->cmd_len = COMMAND_SIZE(cgc->cmd[0]);
memcpy(rq->cmd, cgc->cmd, CDROM_PACKET_SIZE);
if (sizeof(rq->cmd) > CDROM_PACKET_SIZE)
memset(rq->cmd + CDROM_PACKET_SIZE, 0, sizeof(rq->cmd) - CDROM_PACKET_SIZE);
@@ -1377,7 +1365,7 @@ try_next_bio:
&& pd->bio_queue_size <= pd->write_congestion_off);
spin_unlock(&pd->lock);
if (wakeup)
- blk_clear_queue_congested(pd->disk->queue, WRITE);
+ clear_bdi_congested(&pd->disk->queue->backing_dev_info, WRITE);
pkt->sleep_time = max(PACKET_WAIT_TIME, 1);
pkt_set_state(pkt, PACKET_WAITING_STATE);
@@ -2598,7 +2586,7 @@ static int pkt_make_request(request_queue_t *q, struct bio *bio)
spin_lock(&pd->lock);
if (pd->write_congestion_on > 0
&& pd->bio_queue_size >= pd->write_congestion_on) {
- blk_set_queue_congested(q, WRITE);
+ set_bdi_congested(&q->backing_dev_info, WRITE);
do {
spin_unlock(&pd->lock);
congestion_wait(WRITE, HZ);
@@ -2737,7 +2725,7 @@ static int pkt_seq_open(struct inode *inode, struct file *file)
return single_open(file, pkt_seq_show, PDE(inode)->data);
}
-static struct file_operations pkt_proc_fops = {
+static const struct file_operations pkt_proc_fops = {
.open = pkt_seq_open,
.read = seq_read,
.llseek = seq_lseek,
@@ -3064,7 +3052,7 @@ static int pkt_ctl_ioctl(struct inode *inode, struct file *file, unsigned int cm
}
-static struct file_operations pkt_ctl_fops = {
+static const struct file_operations pkt_ctl_fops = {
.ioctl = pkt_ctl_ioctl,
.owner = THIS_MODULE,
};
diff --git a/drivers/block/umem.c b/drivers/block/umem.c
index 30f16bd8365..dff3766f117 100644
--- a/drivers/block/umem.c
+++ b/drivers/block/umem.c
@@ -35,7 +35,6 @@
*/
//#define DEBUG /* uncomment if you want debugging info (pr_debug) */
-#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/bio.h>
#include <linux/kernel.h>
diff --git a/drivers/bluetooth/bcm203x.c b/drivers/bluetooth/bcm203x.c
index 9256985cbe3..8919ccf8274 100644
--- a/drivers/bluetooth/bcm203x.c
+++ b/drivers/bluetooth/bcm203x.c
@@ -307,3 +307,5 @@ MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
MODULE_DESCRIPTION("Broadcom Blutonium firmware driver ver " VERSION);
MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL");
+MODULE_FIRMWARE("BCM2033-MD.hex");
+MODULE_FIRMWARE("BCM2033-FW.bin");
diff --git a/drivers/bluetooth/bfusb.c b/drivers/bluetooth/bfusb.c
index 31ade991aa9..4c766f36d88 100644
--- a/drivers/bluetooth/bfusb.c
+++ b/drivers/bluetooth/bfusb.c
@@ -27,7 +27,6 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/types.h>
-#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/skbuff.h>
@@ -802,3 +801,4 @@ MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
MODULE_DESCRIPTION("BlueFRITZ! USB driver ver " VERSION);
MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL");
+MODULE_FIRMWARE("bfubase.frm");
diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c
index aae3abace58..18b0f3992c5 100644
--- a/drivers/bluetooth/bt3c_cs.c
+++ b/drivers/bluetooth/bt3c_cs.c
@@ -27,7 +27,6 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/types.h>
-#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/ptrace.h>
@@ -64,6 +63,7 @@
MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>, Jose Orlando Pereira <jop@di.uminho.pt>");
MODULE_DESCRIPTION("Bluetooth driver for the 3Com Bluetooth PCMCIA card");
MODULE_LICENSE("GPL");
+MODULE_FIRMWARE("BT3CPCC.bin");
diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c
index 92648ef2f5d..c1bce75148f 100644
--- a/drivers/bluetooth/btuart_cs.c
+++ b/drivers/bluetooth/btuart_cs.c
@@ -26,7 +26,6 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/types.h>
-#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/ptrace.h>
diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c
index 77b99eecbc4..459aa97937a 100644
--- a/drivers/bluetooth/dtl1_cs.c
+++ b/drivers/bluetooth/dtl1_cs.c
@@ -26,7 +26,6 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/types.h>
-#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/ptrace.h>
diff --git a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c
index 5e2c3188200..d66064ccb31 100644
--- a/drivers/bluetooth/hci_bcsp.c
+++ b/drivers/bluetooth/hci_bcsp.c
@@ -26,7 +26,6 @@
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/sched.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/interrupt.h>
diff --git a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c
index ad62abbbb73..34f0afc4240 100644
--- a/drivers/bluetooth/hci_h4.c
+++ b/drivers/bluetooth/hci_h4.c
@@ -27,7 +27,6 @@
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/sched.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/interrupt.h>
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index 420b645c4c9..0f4203b499a 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -27,7 +27,6 @@
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/sched.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/interrupt.h>
diff --git a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c
index 6bdf593081d..406af579ac3 100644
--- a/drivers/bluetooth/hci_usb.c
+++ b/drivers/bluetooth/hci_usb.c
@@ -35,7 +35,6 @@
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/sched.h>
#include <linux/unistd.h>
#include <linux/types.h>
#include <linux/interrupt.h>
diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c
index a278d98a915..b71a5ccc587 100644
--- a/drivers/bluetooth/hci_vhci.c
+++ b/drivers/bluetooth/hci_vhci.c
@@ -332,7 +332,7 @@ static int vhci_fasync(int fd, struct file *file, int on)
return 0;
}
-static struct file_operations vhci_fops = {
+static const struct file_operations vhci_fops = {
.owner = THIS_MODULE,
.llseek = vhci_llseek,
.read = vhci_read,
diff --git a/drivers/cdrom/aztcd.c b/drivers/cdrom/aztcd.c
index ec469497c10..1f9fb7a9670 100644
--- a/drivers/cdrom/aztcd.c
+++ b/drivers/cdrom/aztcd.c
@@ -170,7 +170,6 @@
#include <linux/module.h>
#include <linux/errno.h>
-#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/timer.h>
#include <linux/fs.h>
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
index 3105dddf59f..b36f44d4d1b 100644
--- a/drivers/cdrom/cdrom.c
+++ b/drivers/cdrom/cdrom.c
@@ -3553,9 +3553,7 @@ static void cdrom_sysctl_register(void)
if (initialized == 1)
return;
- cdrom_sysctl_header = register_sysctl_table(cdrom_root_table, 1);
- if (cdrom_root_table->ctl_name && cdrom_root_table->child->de)
- cdrom_root_table->child->de->owner = THIS_MODULE;
+ cdrom_sysctl_header = register_sysctl_table(cdrom_root_table);
/* set the defaults */
cdrom_sysctl_settings.autoclose = autoclose;
diff --git a/drivers/cdrom/cm206.c b/drivers/cdrom/cm206.c
index b6c61bbb20e..23013116324 100644
--- a/drivers/cdrom/cm206.c
+++ b/drivers/cdrom/cm206.c
@@ -183,7 +183,6 @@ History:
#include <linux/errno.h> /* These include what we really need */
#include <linux/delay.h>
#include <linux/string.h>
-#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/timer.h>
#include <linux/cdrom.h>
diff --git a/drivers/cdrom/gscd.c b/drivers/cdrom/gscd.c
index fa708248976..b3ab6e9b8df 100644
--- a/drivers/cdrom/gscd.c
+++ b/drivers/cdrom/gscd.c
@@ -53,7 +53,6 @@
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/signal.h>
-#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/fs.h>
#include <linux/mm.h>
diff --git a/drivers/cdrom/sjcd.c b/drivers/cdrom/sjcd.c
index bf5aef4e555..5409fca5bbf 100644
--- a/drivers/cdrom/sjcd.c
+++ b/drivers/cdrom/sjcd.c
@@ -60,7 +60,6 @@
#include <linux/module.h>
#include <linux/errno.h>
-#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/timer.h>
#include <linux/fs.h>
diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c
index 93fbf84dcc4..dc13ebacedf 100644
--- a/drivers/cdrom/viocd.c
+++ b/drivers/cdrom/viocd.c
@@ -176,7 +176,7 @@ static int proc_viocd_open(struct inode *inode, struct file *file)
return single_open(file, proc_viocd_show, NULL);
}
-static struct file_operations proc_viocd_operations = {
+static const struct file_operations proc_viocd_operations = {
.open = proc_viocd_open,
.read = seq_read,
.llseek = seq_lseek,
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 9e43e39dc35..d0a6dc53213 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -191,7 +191,7 @@ config MOXA_INTELLIO
module will be called moxa.
config MOXA_SMARTIO
- tristate "Moxa SmartIO support"
+ tristate "Moxa SmartIO support (OBSOLETE)"
depends on SERIAL_NONSTANDARD
help
Say Y here if you have a Moxa SmartIO multiport serial card.
@@ -202,7 +202,7 @@ config MOXA_SMARTIO
here.
config MOXA_SMARTIO_NEW
- tristate "Moxa SmartIO support v. 2.0 (EXPERIMENTAL)"
+ tristate "Moxa SmartIO support v. 2.0"
depends on SERIAL_NONSTANDARD && (PCI || EISA || ISA)
help
Say Y here if you have a Moxa SmartIO multiport serial card and/or
@@ -610,6 +610,13 @@ config HVC_RTAS
help
IBM Console device driver which makes use of RTAS
+config HVC_BEAT
+ bool "Toshiba's Beat Hypervisor Console support"
+ depends on PPC_CELLEB
+ select HVC_DRIVER
+ help
+ Toshiba's Cell Reference Set Beat Console device driver
+
config HVCS
tristate "IBM Hypervisor Virtual Console Server support"
depends on PPC_PSERIES
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index fc110637ced..ae8567cc529 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -45,6 +45,7 @@ obj-$(CONFIG_RIO) += rio/ generic_serial.o
obj-$(CONFIG_HVC_CONSOLE) += hvc_vio.o hvsi.o
obj-$(CONFIG_HVC_ISERIES) += hvc_iseries.o
obj-$(CONFIG_HVC_RTAS) += hvc_rtas.o
+obj-$(CONFIG_HVC_BEAT) += hvc_beat.o
obj-$(CONFIG_HVC_DRIVER) += hvc_console.o
obj-$(CONFIG_RAW_DRIVER) += raw.o
obj-$(CONFIG_SGI_SNSC) += snsc.o snsc_event.o
@@ -59,6 +60,8 @@ obj-$(CONFIG_BRIQ_PANEL) += briq_panel.o
obj-$(CONFIG_PRINTER) += lp.o
obj-$(CONFIG_TIPAR) += tipar.o
+obj-$(CONFIG_APM_EMULATION) += apm-emulation.o
+
obj-$(CONFIG_DTLK) += dtlk.o
obj-$(CONFIG_R3964) += n_r3964.o
obj-$(CONFIG_APPLICOM) += applicom.o
diff --git a/drivers/char/agp/Makefile b/drivers/char/agp/Makefile
index 3e581603d0a..627f542827c 100644
--- a/drivers/char/agp/Makefile
+++ b/drivers/char/agp/Makefile
@@ -1,5 +1,7 @@
agpgart-y := backend.o frontend.o generic.o isoch.o
+agpgart-$(CONFIG_COMPAT) += compat_ioctl.o
+
obj-$(CONFIG_AGP) += agpgart.o
obj-$(CONFIG_AGP_ALI) += ali-agp.o
obj-$(CONFIG_AGP_ATI) += ati-agp.o
diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h
index 1d59e2a5b9a..fdbca25a394 100644
--- a/drivers/char/agp/agp.h
+++ b/drivers/char/agp/agp.h
@@ -93,12 +93,12 @@ struct aper_size_info_fixed {
struct agp_bridge_driver {
struct module *owner;
- void *aperture_sizes;
+ const void *aperture_sizes;
int num_aperture_sizes;
enum aper_size_type size_type;
int cant_use_aperture;
int needs_scratch_page;
- struct gatt_mask *masks;
+ const struct gatt_mask *masks;
int (*fetch_size)(void);
int (*configure)(void);
void (*agp_enable)(struct agp_bridge_data *, u32);
@@ -114,11 +114,12 @@ struct agp_bridge_driver {
void (*free_by_type)(struct agp_memory *);
void *(*agp_alloc_page)(struct agp_bridge_data *);
void (*agp_destroy_page)(void *);
+ int (*agp_type_to_mask_type) (struct agp_bridge_data *, int);
};
struct agp_bridge_data {
const struct agp_version *version;
- struct agp_bridge_driver *driver;
+ const struct agp_bridge_driver *driver;
struct vm_operations_struct *vm_ops;
void *previous_size;
void *current_size;
@@ -218,6 +219,7 @@ struct agp_bridge_data {
#define I810_PTE_MAIN_UNCACHED 0x00000000
#define I810_PTE_LOCAL 0x00000002
#define I810_PTE_VALID 0x00000001
+#define I830_PTE_SYSTEM_CACHED 0x00000006
#define I810_SMRAM_MISCC 0x70
#define I810_GFX_MEM_WIN_SIZE 0x00010000
#define I810_GFX_MEM_WIN_32M 0x00010000
@@ -270,8 +272,16 @@ void global_cache_flush(void);
void get_agp_version(struct agp_bridge_data *bridge);
unsigned long agp_generic_mask_memory(struct agp_bridge_data *bridge,
unsigned long addr, int type);
+int agp_generic_type_to_mask_type(struct agp_bridge_data *bridge,
+ int type);
struct agp_bridge_data *agp_generic_find_bridge(struct pci_dev *pdev);
+/* generic functions for user-populated AGP memory types */
+struct agp_memory *agp_generic_alloc_user(size_t page_count, int type);
+void agp_alloc_page_array(size_t size, struct agp_memory *mem);
+void agp_free_page_array(struct agp_memory *mem);
+
+
/* generic routines for agp>=3 */
int agp3_generic_fetch_size(void);
void agp3_generic_tlbflush(struct agp_memory *mem);
@@ -280,7 +290,7 @@ void agp3_generic_cleanup(void);
/* aperture sizes have been standardised since v3 */
#define AGP_GENERIC_SIZES_ENTRIES 11
-extern struct aper_size_info_16 agp3_generic_sizes[];
+extern const struct aper_size_info_16 agp3_generic_sizes[];
#define virt_to_gart(x) (phys_to_gart(virt_to_phys(x)))
#define gart_to_virt(x) (phys_to_virt(gart_to_phys(x)))
@@ -288,6 +298,8 @@ extern struct aper_size_info_16 agp3_generic_sizes[];
extern int agp_off;
extern int agp_try_unsupported_boot;
+long compat_agp_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
+
/* Chipset independant registers (from AGP Spec) */
#define AGP_APBASE 0x10
diff --git a/drivers/char/agp/ali-agp.c b/drivers/char/agp/ali-agp.c
index 5a31ec7c62f..5b684fddcc0 100644
--- a/drivers/char/agp/ali-agp.c
+++ b/drivers/char/agp/ali-agp.c
@@ -182,7 +182,7 @@ static void m1541_destroy_page(void * addr)
/* Setup function */
-static struct aper_size_info_32 ali_generic_sizes[7] =
+static const struct aper_size_info_32 ali_generic_sizes[7] =
{
{256, 65536, 6, 10},
{128, 32768, 5, 9},
@@ -193,7 +193,7 @@ static struct aper_size_info_32 ali_generic_sizes[7] =
{4, 1024, 0, 3}
};
-static struct agp_bridge_driver ali_generic_bridge = {
+static const struct agp_bridge_driver ali_generic_bridge = {
.owner = THIS_MODULE,
.aperture_sizes = ali_generic_sizes,
.size_type = U32_APER_SIZE,
@@ -214,9 +214,10 @@ static struct agp_bridge_driver ali_generic_bridge = {
.free_by_type = agp_generic_free_by_type,
.agp_alloc_page = agp_generic_alloc_page,
.agp_destroy_page = ali_destroy_page,
+ .agp_type_to_mask_type = agp_generic_type_to_mask_type,
};
-static struct agp_bridge_driver ali_m1541_bridge = {
+static const struct agp_bridge_driver ali_m1541_bridge = {
.owner = THIS_MODULE,
.aperture_sizes = ali_generic_sizes,
.size_type = U32_APER_SIZE,
@@ -237,6 +238,7 @@ static struct agp_bridge_driver ali_m1541_bridge = {
.free_by_type = agp_generic_free_by_type,
.agp_alloc_page = m1541_alloc_page,
.agp_destroy_page = m1541_destroy_page,
+ .agp_type_to_mask_type = agp_generic_type_to_mask_type,
};
diff --git a/drivers/char/agp/alpha-agp.c b/drivers/char/agp/alpha-agp.c
index b4e00a343da..b0acf41c0db 100644
--- a/drivers/char/agp/alpha-agp.c
+++ b/drivers/char/agp/alpha-agp.c
@@ -91,6 +91,9 @@ static int alpha_core_agp_insert_memory(struct agp_memory *mem, off_t pg_start,
int num_entries, status;
void *temp;
+ if (type >= AGP_USER_TYPES || mem->type >= AGP_USER_TYPES)
+ return -EINVAL;
+
temp = agp_bridge->current_size;
num_entries = A_SIZE_FIX(temp)->num_entries;
if ((pg_start + mem->page_count) > num_entries)
@@ -142,6 +145,7 @@ struct agp_bridge_driver alpha_core_agp_driver = {
.free_by_type = agp_generic_free_by_type,
.agp_alloc_page = agp_generic_alloc_page,
.agp_destroy_page = agp_generic_destroy_page,
+ .agp_type_to_mask_type = agp_generic_type_to_mask_type,
};
struct agp_bridge_data *alpha_bridge;
diff --git a/drivers/char/agp/amd-k7-agp.c b/drivers/char/agp/amd-k7-agp.c
index c85c8cadb6d..e6c534e6284 100644
--- a/drivers/char/agp/amd-k7-agp.c
+++ b/drivers/char/agp/amd-k7-agp.c
@@ -344,7 +344,7 @@ static int amd_remove_memory(struct agp_memory *mem, off_t pg_start, int type)
return 0;
}
-static struct aper_size_info_lvl2 amd_irongate_sizes[7] =
+static const struct aper_size_info_lvl2 amd_irongate_sizes[7] =
{
{2048, 524288, 0x0000000c},
{1024, 262144, 0x0000000a},
@@ -355,12 +355,12 @@ static struct aper_size_info_lvl2 amd_irongate_sizes[7] =
{32, 8192, 0x00000000}
};
-static struct gatt_mask amd_irongate_masks[] =
+static const struct gatt_mask amd_irongate_masks[] =
{
{.mask = 1, .type = 0}
};
-static struct agp_bridge_driver amd_irongate_driver = {
+static const struct agp_bridge_driver amd_irongate_driver = {
.owner = THIS_MODULE,
.aperture_sizes = amd_irongate_sizes,
.size_type = LVL2_APER_SIZE,
@@ -381,6 +381,7 @@ static struct agp_bridge_driver amd_irongate_driver = {
.free_by_type = agp_generic_free_by_type,
.agp_alloc_page = agp_generic_alloc_page,
.agp_destroy_page = agp_generic_destroy_page,
+ .agp_type_to_mask_type = agp_generic_type_to_mask_type,
};
static struct agp_device_ids amd_agp_device_ids[] __devinitdata =
diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c
index 93d2209fee4..485720486d6 100644
--- a/drivers/char/agp/amd64-agp.c
+++ b/drivers/char/agp/amd64-agp.c
@@ -62,12 +62,18 @@ static int amd64_insert_memory(struct agp_memory *mem, off_t pg_start, int type)
{
int i, j, num_entries;
long long tmp;
+ int mask_type;
+ struct agp_bridge_data *bridge = mem->bridge;
u32 pte;
num_entries = agp_num_entries();
- if (type != 0 || mem->type != 0)
+ if (type != mem->type)
return -EINVAL;
+ mask_type = bridge->driver->agp_type_to_mask_type(bridge, type);
+ if (mask_type != 0)
+ return -EINVAL;
+
/* Make sure we can fit the range in the gatt table. */
/* FIXME: could wrap */
@@ -90,7 +96,7 @@ static int amd64_insert_memory(struct agp_memory *mem, off_t pg_start, int type)
for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
tmp = agp_bridge->driver->mask_memory(agp_bridge,
- mem->memory[i], mem->type);
+ mem->memory[i], mask_type);
BUG_ON(tmp & 0xffffff0000000ffcULL);
pte = (tmp & 0x000000ff00000000ULL) >> 28;
@@ -186,7 +192,7 @@ static u64 amd64_configure (struct pci_dev *hammer, u64 gatt_table)
}
-static struct aper_size_info_32 amd_8151_sizes[7] =
+static const struct aper_size_info_32 amd_8151_sizes[7] =
{
{2048, 524288, 9, 0x00000000 }, /* 0 0 0 0 0 0 */
{1024, 262144, 8, 0x00000400 }, /* 1 0 0 0 0 0 */
@@ -226,7 +232,7 @@ static void amd64_cleanup(void)
}
-static struct agp_bridge_driver amd_8151_driver = {
+static const struct agp_bridge_driver amd_8151_driver = {
.owner = THIS_MODULE,
.aperture_sizes = amd_8151_sizes,
.size_type = U32_APER_SIZE,
@@ -247,6 +253,7 @@ static struct agp_bridge_driver amd_8151_driver = {
.free_by_type = agp_generic_free_by_type,
.agp_alloc_page = agp_generic_alloc_page,
.agp_destroy_page = agp_generic_destroy_page,
+ .agp_type_to_mask_type = agp_generic_type_to_mask_type,
};
/* Some basic sanity checks for the aperture. */
diff --git a/drivers/char/agp/ati-agp.c b/drivers/char/agp/ati-agp.c
index 9987dc2e0c3..780e59e588a 100644
--- a/drivers/char/agp/ati-agp.c
+++ b/drivers/char/agp/ati-agp.c
@@ -24,7 +24,7 @@
#define ATI_GART_CACHE_ENTRY_CNTRL 0x10
-static struct aper_size_info_lvl2 ati_generic_sizes[7] =
+static const struct aper_size_info_lvl2 ati_generic_sizes[7] =
{
{2048, 524288, 0x0000000c},
{1024, 262144, 0x0000000a},
@@ -410,7 +410,7 @@ static int ati_free_gatt_table(struct agp_bridge_data *bridge)
return 0;
}
-static struct agp_bridge_driver ati_generic_bridge = {
+static const struct agp_bridge_driver ati_generic_bridge = {
.owner = THIS_MODULE,
.aperture_sizes = ati_generic_sizes,
.size_type = LVL2_APER_SIZE,
@@ -431,6 +431,7 @@ static struct agp_bridge_driver ati_generic_bridge = {
.free_by_type = agp_generic_free_by_type,
.agp_alloc_page = agp_generic_alloc_page,
.agp_destroy_page = agp_generic_destroy_page,
+ .agp_type_to_mask_type = agp_generic_type_to_mask_type,
};
diff --git a/drivers/char/agp/backend.c b/drivers/char/agp/backend.c
index d59e037ddd1..ebdd6dd66ed 100644
--- a/drivers/char/agp/backend.c
+++ b/drivers/char/agp/backend.c
@@ -43,7 +43,7 @@
* fix some real stupidity. It's only by chance we can bump
* past 0.99 at all due to some boolean logic error. */
#define AGPGART_VERSION_MAJOR 0
-#define AGPGART_VERSION_MINOR 101
+#define AGPGART_VERSION_MINOR 102
static const struct agp_version agp_current_version =
{
.major = AGPGART_VERSION_MAJOR,
diff --git a/drivers/char/agp/compat_ioctl.c b/drivers/char/agp/compat_ioctl.c
new file mode 100644
index 00000000000..fcb4b1bf0d4
--- /dev/null
+++ b/drivers/char/agp/compat_ioctl.c
@@ -0,0 +1,282 @@
+/*
+ * AGPGART driver frontend compatibility ioctls
+ * Copyright (C) 2004 Silicon Graphics, Inc.
+ * Copyright (C) 2002-2003 Dave Jones
+ * Copyright (C) 1999 Jeff Hartmann
+ * Copyright (C) 1999 Precision Insight, Inc.
+ * Copyright (C) 1999 Xi Graphics, 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
+ * JEFF HARTMANN, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
+ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/agpgart.h>
+#include <asm/uaccess.h>
+#include "agp.h"
+#include "compat_ioctl.h"
+
+static int compat_agpioc_info_wrap(struct agp_file_private *priv, void __user *arg)
+{
+ struct agp_info32 userinfo;
+ struct agp_kern_info kerninfo;
+
+ agp_copy_info(agp_bridge, &kerninfo);
+
+ userinfo.version.major = kerninfo.version.major;
+ userinfo.version.minor = kerninfo.version.minor;
+ userinfo.bridge_id = kerninfo.device->vendor |
+ (kerninfo.device->device << 16);
+ userinfo.agp_mode = kerninfo.mode;
+ userinfo.aper_base = (compat_long_t)kerninfo.aper_base;
+ userinfo.aper_size = kerninfo.aper_size;
+ userinfo.pg_total = userinfo.pg_system = kerninfo.max_memory;
+ userinfo.pg_used = kerninfo.current_memory;
+
+ if (copy_to_user(arg, &userinfo, sizeof(userinfo)))
+ return -EFAULT;
+
+ return 0;
+}
+
+static int compat_agpioc_reserve_wrap(struct agp_file_private *priv, void __user *arg)
+{
+ struct agp_region32 ureserve;
+ struct agp_region kreserve;
+ struct agp_client *client;
+ struct agp_file_private *client_priv;
+
+ DBG("");
+ if (copy_from_user(&ureserve, arg, sizeof(ureserve)))
+ return -EFAULT;
+
+ if ((unsigned) ureserve.seg_count >= ~0U/sizeof(struct agp_segment32))
+ return -EFAULT;
+
+ kreserve.pid = ureserve.pid;
+ kreserve.seg_count = ureserve.seg_count;
+
+ client = agp_find_client_by_pid(kreserve.pid);
+
+ if (kreserve.seg_count == 0) {
+ /* remove a client */
+ client_priv = agp_find_private(kreserve.pid);
+
+ if (client_priv != NULL) {
+ set_bit(AGP_FF_IS_CLIENT, &client_priv->access_flags);
+ set_bit(AGP_FF_IS_VALID, &client_priv->access_flags);
+ }
+ if (client == NULL) {
+ /* client is already removed */
+ return 0;
+ }
+ return agp_remove_client(kreserve.pid);
+ } else {
+ struct agp_segment32 *usegment;
+ struct agp_segment *ksegment;
+ int seg;
+
+ if (ureserve.seg_count >= 16384)
+ return -EINVAL;
+
+ usegment = kmalloc(sizeof(*usegment) * ureserve.seg_count, GFP_KERNEL);
+ if (!usegment)
+ return -ENOMEM;
+
+ ksegment = kmalloc(sizeof(*ksegment) * kreserve.seg_count, GFP_KERNEL);
+ if (!ksegment) {
+ kfree(usegment);
+ return -ENOMEM;
+ }
+
+ if (copy_from_user(usegment, (void __user *) ureserve.seg_list,
+ sizeof(*usegment) * ureserve.seg_count)) {
+ kfree(usegment);
+ kfree(ksegment);
+ return -EFAULT;
+ }
+
+ for (seg = 0; seg < ureserve.seg_count; seg++) {
+ ksegment[seg].pg_start = usegment[seg].pg_start;
+ ksegment[seg].pg_count = usegment[seg].pg_count;
+ ksegment[seg].prot = usegment[seg].prot;
+ }
+
+ kfree(usegment);
+ kreserve.seg_list = ksegment;
+
+ if (client == NULL) {
+ /* Create the client and add the segment */
+ client = agp_create_client(kreserve.pid);
+
+ if (client == NULL) {
+ kfree(ksegment);
+ return -ENOMEM;
+ }
+ client_priv = agp_find_private(kreserve.pid);
+
+ if (client_priv != NULL) {
+ set_bit(AGP_FF_IS_CLIENT, &client_priv->access_flags);
+ set_bit(AGP_FF_IS_VALID, &client_priv->access_flags);
+ }
+ }
+ return agp_create_segment(client, &kreserve);
+ }
+ /* Will never really happen */
+ return -EINVAL;
+}
+
+static int compat_agpioc_allocate_wrap(struct agp_file_private *priv, void __user *arg)
+{
+ struct agp_memory *memory;
+ struct agp_allocate32 alloc;
+
+ DBG("");
+ if (copy_from_user(&alloc, arg, sizeof(alloc)))
+ return -EFAULT;
+
+ memory = agp_allocate_memory_wrap(alloc.pg_count, alloc.type);
+
+ if (memory == NULL)
+ return -ENOMEM;
+
+ alloc.key = memory->key;
+ alloc.physical = memory->physical;
+
+ if (copy_to_user(arg, &alloc, sizeof(alloc))) {
+ agp_free_memory_wrap(memory);
+ return -EFAULT;
+ }
+ return 0;
+}
+
+static int compat_agpioc_bind_wrap(struct agp_file_private *priv, void __user *arg)
+{
+ struct agp_bind32 bind_info;
+ struct agp_memory *memory;
+
+ DBG("");
+ if (copy_from_user(&bind_info, arg, sizeof(bind_info)))
+ return -EFAULT;
+
+ memory = agp_find_mem_by_key(bind_info.key);
+
+ if (memory == NULL)
+ return -EINVAL;
+
+ return agp_bind_memory(memory, bind_info.pg_start);
+}
+
+static int compat_agpioc_unbind_wrap(struct agp_file_private *priv, void __user *arg)
+{
+ struct agp_memory *memory;
+ struct agp_unbind32 unbind;
+
+ DBG("");
+ if (copy_from_user(&unbind, arg, sizeof(unbind)))
+ return -EFAULT;
+
+ memory = agp_find_mem_by_key(unbind.key);
+
+ if (memory == NULL)
+ return -EINVAL;
+
+ return agp_unbind_memory(memory);
+}
+
+long compat_agp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct agp_file_private *curr_priv = file->private_data;
+ int ret_val = -ENOTTY;
+
+ mutex_lock(&(agp_fe.agp_mutex));
+
+ if ((agp_fe.current_controller == NULL) &&
+ (cmd != AGPIOC_ACQUIRE32)) {
+ ret_val = -EINVAL;
+ goto ioctl_out;
+ }
+ if ((agp_fe.backend_acquired != TRUE) &&
+ (cmd != AGPIOC_ACQUIRE32)) {
+ ret_val = -EBUSY;
+ goto ioctl_out;
+ }
+ if (cmd != AGPIOC_ACQUIRE32) {
+ if (!(test_bit(AGP_FF_IS_CONTROLLER, &curr_priv->access_flags))) {
+ ret_val = -EPERM;
+ goto ioctl_out;
+ }
+ /* Use the original pid of the controller,
+ * in case it's threaded */
+
+ if (agp_fe.current_controller->pid != curr_priv->my_pid) {
+ ret_val = -EBUSY;
+ goto ioctl_out;
+ }
+ }
+
+ switch (cmd) {
+ case AGPIOC_INFO32:
+ ret_val = compat_agpioc_info_wrap(curr_priv, (void __user *) arg);
+ break;
+
+ case AGPIOC_ACQUIRE32:
+ ret_val = agpioc_acquire_wrap(curr_priv);
+ break;
+
+ case AGPIOC_RELEASE32:
+ ret_val = agpioc_release_wrap(curr_priv);
+ break;
+
+ case AGPIOC_SETUP32:
+ ret_val = agpioc_setup_wrap(curr_priv, (void __user *) arg);
+ break;
+
+ case AGPIOC_RESERVE32:
+ ret_val = compat_agpioc_reserve_wrap(curr_priv, (void __user *) arg);
+ break;
+
+ case AGPIOC_PROTECT32:
+ ret_val = agpioc_protect_wrap(curr_priv);
+ break;
+
+ case AGPIOC_ALLOCATE32:
+ ret_val = compat_agpioc_allocate_wrap(curr_priv, (void __user *) arg);
+ break;
+
+ case AGPIOC_DEALLOCATE32:
+ ret_val = agpioc_deallocate_wrap(curr_priv, (int) arg);
+ break;
+
+ case AGPIOC_BIND32:
+ ret_val = compat_agpioc_bind_wrap(curr_priv, (void __user *) arg);
+ break;
+
+ case AGPIOC_UNBIND32:
+ ret_val = compat_agpioc_unbind_wrap(curr_priv, (void __user *) arg);
+ break;
+ }
+
+ioctl_out:
+ DBG("ioctl returns %d\n", ret_val);
+ mutex_unlock(&(agp_fe.agp_mutex));
+ return ret_val;
+}
+
diff --git a/drivers/char/agp/compat_ioctl.h b/drivers/char/agp/compat_ioctl.h
new file mode 100644
index 00000000000..71939d63723
--- /dev/null
+++ b/drivers/char/agp/compat_ioctl.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 1999 Jeff Hartmann
+ * Copyright (C) 1999 Precision Insight, Inc.
+ * Copyright (C) 1999 Xi Graphics, 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
+ * JEFF HARTMANN, OR ANY OTHER CONTRIBUTORS 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.
+ *
+ */
+
+#ifndef _AGP_COMPAT_IOCTL_H
+#define _AGP_COMPAT_IOCTL_H
+
+#include <linux/compat.h>
+#include <linux/agpgart.h>
+
+#define AGPIOC_INFO32 _IOR (AGPIOC_BASE, 0, compat_uptr_t)
+#define AGPIOC_ACQUIRE32 _IO (AGPIOC_BASE, 1)
+#define AGPIOC_RELEASE32 _IO (AGPIOC_BASE, 2)
+#define AGPIOC_SETUP32 _IOW (AGPIOC_BASE, 3, compat_uptr_t)
+#define AGPIOC_RESERVE32 _IOW (AGPIOC_BASE, 4, compat_uptr_t)
+#define AGPIOC_PROTECT32 _IOW (AGPIOC_BASE, 5, compat_uptr_t)
+#define AGPIOC_ALLOCATE32 _IOWR(AGPIOC_BASE, 6, compat_uptr_t)
+#define AGPIOC_DEALLOCATE32 _IOW (AGPIOC_BASE, 7, compat_int_t)
+#define AGPIOC_BIND32 _IOW (AGPIOC_BASE, 8, compat_uptr_t)
+#define AGPIOC_UNBIND32 _IOW (AGPIOC_BASE, 9, compat_uptr_t)
+
+struct agp_info32 {
+ struct agp_version version; /* version of the driver */
+ u32 bridge_id; /* bridge vendor/device */
+ u32 agp_mode; /* mode info of bridge */
+ compat_long_t aper_base; /* base of aperture */
+ compat_size_t aper_size; /* size of aperture */
+ compat_size_t pg_total; /* max pages (swap + system) */
+ compat_size_t pg_system; /* max pages (system) */
+ compat_size_t pg_used; /* current pages used */
+};
+
+/*
+ * The "prot" down below needs still a "sleep" flag somehow ...
+ */
+struct agp_segment32 {
+ compat_off_t pg_start; /* starting page to populate */
+ compat_size_t pg_count; /* number of pages */
+ compat_int_t prot; /* prot flags for mmap */
+};
+
+struct agp_region32 {
+ compat_pid_t pid; /* pid of process */
+ compat_size_t seg_count; /* number of segments */
+ struct agp_segment32 *seg_list;
+};
+
+struct agp_allocate32 {
+ compat_int_t key; /* tag of allocation */
+ compat_size_t pg_count; /* number of pages */
+ u32 type; /* 0 == normal, other devspec */
+ u32 physical; /* device specific (some devices
+ * need a phys address of the
+ * actual page behind the gatt
+ * table) */
+};
+
+struct agp_bind32 {
+ compat_int_t key; /* tag of allocation */
+ compat_off_t pg_start; /* starting page to populate */
+};
+
+struct agp_unbind32 {
+ compat_int_t key; /* tag of allocation */
+ u32 priority; /* priority for paging out */
+};
+
+extern struct agp_front_data agp_fe;
+
+int agpioc_acquire_wrap(struct agp_file_private *priv);
+int agpioc_release_wrap(struct agp_file_private *priv);
+int agpioc_protect_wrap(struct agp_file_private *priv);
+int agpioc_setup_wrap(struct agp_file_private *priv, void __user *arg);
+int agpioc_deallocate_wrap(struct agp_file_private *priv, int arg);
+struct agp_file_private *agp_find_private(pid_t pid);
+struct agp_client *agp_create_client(pid_t id);
+int agp_remove_client(pid_t id);
+int agp_create_segment(struct agp_client *client, struct agp_region *region);
+void agp_free_memory_wrap(struct agp_memory *memory);
+struct agp_memory *agp_allocate_memory_wrap(size_t pg_count, u32 type);
+struct agp_memory *agp_find_mem_by_key(int key);
+struct agp_client *agp_find_client_by_pid(pid_t id);
+
+#endif /* _AGP_COMPAT_H */
diff --git a/drivers/char/agp/efficeon-agp.c b/drivers/char/agp/efficeon-agp.c
index 30f730ff81c..df8da726285 100644
--- a/drivers/char/agp/efficeon-agp.c
+++ b/drivers/char/agp/efficeon-agp.c
@@ -59,7 +59,7 @@ static struct _efficeon_private {
unsigned long l1_table[EFFICEON_L1_SIZE];
} efficeon_private;
-static struct gatt_mask efficeon_generic_masks[] =
+static const struct gatt_mask efficeon_generic_masks[] =
{
{.mask = 0x00000001, .type = 0}
};
@@ -70,7 +70,7 @@ static inline unsigned long efficeon_mask_memory(unsigned long addr)
return addr | 0x00000001;
}
-static struct aper_size_info_lvl2 efficeon_generic_sizes[4] =
+static const struct aper_size_info_lvl2 efficeon_generic_sizes[4] =
{
{256, 65536, 0},
{128, 32768, 32},
@@ -309,7 +309,7 @@ static int efficeon_remove_memory(struct agp_memory * mem, off_t pg_start, int t
}
-static struct agp_bridge_driver efficeon_driver = {
+static const struct agp_bridge_driver efficeon_driver = {
.owner = THIS_MODULE,
.aperture_sizes = efficeon_generic_sizes,
.size_type = LVL2_APER_SIZE,
@@ -335,6 +335,7 @@ static struct agp_bridge_driver efficeon_driver = {
.free_by_type = agp_generic_free_by_type,
.agp_alloc_page = agp_generic_alloc_page,
.agp_destroy_page = agp_generic_destroy_page,
+ .agp_type_to_mask_type = agp_generic_type_to_mask_type,
};
static int __devinit agp_efficeon_probe(struct pci_dev *pdev,
diff --git a/drivers/char/agp/frontend.c b/drivers/char/agp/frontend.c
index 0f2ed2aa2d8..679d7f97243 100644
--- a/drivers/char/agp/frontend.c
+++ b/drivers/char/agp/frontend.c
@@ -41,9 +41,9 @@
#include <asm/pgtable.h>
#include "agp.h"
-static struct agp_front_data agp_fe;
+struct agp_front_data agp_fe;
-static struct agp_memory *agp_find_mem_by_key(int key)
+struct agp_memory *agp_find_mem_by_key(int key)
{
struct agp_memory *curr;
@@ -159,7 +159,7 @@ static pgprot_t agp_convert_mmap_flags(int prot)
return vm_get_page_prot(prot_bits);
}
-static int agp_create_segment(struct agp_client *client, struct agp_region *region)
+int agp_create_segment(struct agp_client *client, struct agp_region *region)
{
struct agp_segment_priv **ret_seg;
struct agp_segment_priv *seg;
@@ -211,7 +211,7 @@ static void agp_insert_into_pool(struct agp_memory * temp)
/* File private list routines */
-static struct agp_file_private *agp_find_private(pid_t pid)
+struct agp_file_private *agp_find_private(pid_t pid)
{
struct agp_file_private *curr;
@@ -266,13 +266,13 @@ static void agp_remove_file_private(struct agp_file_private * priv)
* Wrappers for agp_free_memory & agp_allocate_memory
* These make sure that internal lists are kept updated.
*/
-static void agp_free_memory_wrap(struct agp_memory *memory)
+void agp_free_memory_wrap(struct agp_memory *memory)
{
agp_remove_from_pool(memory);
agp_free_memory(memory);
}
-static struct agp_memory *agp_allocate_memory_wrap(size_t pg_count, u32 type)
+struct agp_memory *agp_allocate_memory_wrap(size_t pg_count, u32 type)
{
struct agp_memory *memory;
@@ -484,7 +484,7 @@ static struct agp_controller *agp_find_controller_for_client(pid_t id)
return NULL;
}
-static struct agp_client *agp_find_client_by_pid(pid_t id)
+struct agp_client *agp_find_client_by_pid(pid_t id)
{
struct agp_client *temp;
@@ -509,7 +509,7 @@ static void agp_insert_client(struct agp_client *client)
agp_fe.current_controller->num_clients++;
}
-static struct agp_client *agp_create_client(pid_t id)
+struct agp_client *agp_create_client(pid_t id)
{
struct agp_client *new_client;
@@ -522,7 +522,7 @@ static struct agp_client *agp_create_client(pid_t id)
return new_client;
}
-static int agp_remove_client(pid_t id)
+int agp_remove_client(pid_t id)
{
struct agp_client *client;
struct agp_client *prev_client;
@@ -746,7 +746,7 @@ static int agpioc_info_wrap(struct agp_file_private *priv, void __user *arg)
return 0;
}
-static int agpioc_acquire_wrap(struct agp_file_private *priv)
+int agpioc_acquire_wrap(struct agp_file_private *priv)
{
struct agp_controller *controller;
@@ -789,14 +789,14 @@ static int agpioc_acquire_wrap(struct agp_file_private *priv)
return 0;
}
-static int agpioc_release_wrap(struct agp_file_private *priv)
+int agpioc_release_wrap(struct agp_file_private *priv)
{
DBG("");
agp_controller_release_current(agp_fe.current_controller, priv);
return 0;
}
-static int agpioc_setup_wrap(struct agp_file_private *priv, void __user *arg)
+int agpioc_setup_wrap(struct agp_file_private *priv, void __user *arg)
{
struct agp_setup mode;
@@ -876,7 +876,7 @@ static int agpioc_reserve_wrap(struct agp_file_private *priv, void __user *arg)
return -EINVAL;
}
-static int agpioc_protect_wrap(struct agp_file_private *priv)
+int agpioc_protect_wrap(struct agp_file_private *priv)
{
DBG("");
/* This function is not currently implemented */
@@ -892,6 +892,9 @@ static int agpioc_allocate_wrap(struct agp_file_private *priv, void __user *arg)
if (copy_from_user(&alloc, arg, sizeof(struct agp_allocate)))
return -EFAULT;
+ if (alloc.type >= AGP_USER_TYPES)
+ return -EINVAL;
+
memory = agp_allocate_memory_wrap(alloc.pg_count, alloc.type);
if (memory == NULL)
@@ -907,7 +910,7 @@ static int agpioc_allocate_wrap(struct agp_file_private *priv, void __user *arg)
return 0;
}
-static int agpioc_deallocate_wrap(struct agp_file_private *priv, int arg)
+int agpioc_deallocate_wrap(struct agp_file_private *priv, int arg)
{
struct agp_memory *memory;
@@ -1043,6 +1046,9 @@ static const struct file_operations agp_fops =
.read = agp_read,
.write = agp_write,
.ioctl = agp_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = compat_agp_ioctl,
+#endif
.mmap = agp_mmap,
.open = agp_open,
.release = agp_release,
diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c
index 3491d6f84bc..f902d71947b 100644
--- a/drivers/char/agp/generic.c
+++ b/drivers/char/agp/generic.c
@@ -101,6 +101,63 @@ static int agp_get_key(void)
return -1;
}
+/*
+ * Use kmalloc if possible for the page list. Otherwise fall back to
+ * vmalloc. This speeds things up and also saves memory for small AGP
+ * regions.
+ */
+
+void agp_alloc_page_array(size_t size, struct agp_memory *mem)
+{
+ mem->memory = NULL;
+ mem->vmalloc_flag = 0;
+
+ if (size <= 2*PAGE_SIZE)
+ mem->memory = kmalloc(size, GFP_KERNEL | __GFP_NORETRY);
+ if (mem->memory == NULL) {
+ mem->memory = vmalloc(size);
+ mem->vmalloc_flag = 1;
+ }
+}
+EXPORT_SYMBOL(agp_alloc_page_array);
+
+void agp_free_page_array(struct agp_memory *mem)
+{
+ if (mem->vmalloc_flag) {
+ vfree(mem->memory);
+ } else {
+ kfree(mem->memory);
+ }
+}
+EXPORT_SYMBOL(agp_free_page_array);
+
+
+static struct agp_memory *agp_create_user_memory(unsigned long num_agp_pages)
+{
+ struct agp_memory *new;
+ unsigned long alloc_size = num_agp_pages*sizeof(struct page *);
+
+ new = kzalloc(sizeof(struct agp_memory), GFP_KERNEL);
+ if (new == NULL)
+ return NULL;
+
+ new->key = agp_get_key();
+
+ if (new->key < 0) {
+ kfree(new);
+ return NULL;
+ }
+
+ agp_alloc_page_array(alloc_size, new);
+
+ if (new->memory == NULL) {
+ agp_free_key(new->key);
+ kfree(new);
+ return NULL;
+ }
+ new->num_scratch_pages = 0;
+ return new;
+}
struct agp_memory *agp_create_memory(int scratch_pages)
{
@@ -116,7 +173,8 @@ struct agp_memory *agp_create_memory(int scratch_pages)
kfree(new);
return NULL;
}
- new->memory = vmalloc(PAGE_SIZE * scratch_pages);
+
+ agp_alloc_page_array(PAGE_SIZE * scratch_pages, new);
if (new->memory == NULL) {
agp_free_key(new->key);
@@ -124,6 +182,7 @@ struct agp_memory *agp_create_memory(int scratch_pages)
return NULL;
}
new->num_scratch_pages = scratch_pages;
+ new->type = AGP_NORMAL_MEMORY;
return new;
}
EXPORT_SYMBOL(agp_create_memory);
@@ -146,6 +205,11 @@ void agp_free_memory(struct agp_memory *curr)
if (curr->is_bound == TRUE)
agp_unbind_memory(curr);
+ if (curr->type >= AGP_USER_TYPES) {
+ agp_generic_free_by_type(curr);
+ return;
+ }
+
if (curr->type != 0) {
curr->bridge->driver->free_by_type(curr);
return;
@@ -157,7 +221,7 @@ void agp_free_memory(struct agp_memory *curr)
flush_agp_mappings();
}
agp_free_key(curr->key);
- vfree(curr->memory);
+ agp_free_page_array(curr);
kfree(curr);
}
EXPORT_SYMBOL(agp_free_memory);
@@ -188,6 +252,13 @@ struct agp_memory *agp_allocate_memory(struct agp_bridge_data *bridge,
if ((atomic_read(&bridge->current_memory_agp) + page_count) > bridge->max_memory_agp)
return NULL;
+ if (type >= AGP_USER_TYPES) {
+ new = agp_generic_alloc_user(page_count, type);
+ if (new)
+ new->bridge = bridge;
+ return new;
+ }
+
if (type != 0) {
new = bridge->driver->alloc_by_type(page_count, type);
if (new)
@@ -960,6 +1031,7 @@ int agp_generic_insert_memory(struct agp_memory * mem, off_t pg_start, int type)
off_t j;
void *temp;
struct agp_bridge_data *bridge;
+ int mask_type;
bridge = mem->bridge;
if (!bridge)
@@ -995,7 +1067,11 @@ int agp_generic_insert_memory(struct agp_memory * mem, off_t pg_start, int type)
num_entries -= agp_memory_reserved/PAGE_SIZE;
if (num_entries < 0) num_entries = 0;
- if (type != 0 || mem->type != 0) {
+ if (type != mem->type)
+ return -EINVAL;
+
+ mask_type = bridge->driver->agp_type_to_mask_type(bridge, type);
+ if (mask_type != 0) {
/* The generic routines know nothing of memory types */
return -EINVAL;
}
@@ -1018,7 +1094,8 @@ int agp_generic_insert_memory(struct agp_memory * mem, off_t pg_start, int type)
}
for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
- writel(bridge->driver->mask_memory(bridge, mem->memory[i], mem->type), bridge->gatt_table+j);
+ writel(bridge->driver->mask_memory(bridge, mem->memory[i], mask_type),
+ bridge->gatt_table+j);
}
readl(bridge->gatt_table+j-1); /* PCI Posting. */
@@ -1032,6 +1109,7 @@ int agp_generic_remove_memory(struct agp_memory *mem, off_t pg_start, int type)
{
size_t i;
struct agp_bridge_data *bridge;
+ int mask_type;
bridge = mem->bridge;
if (!bridge)
@@ -1040,7 +1118,11 @@ int agp_generic_remove_memory(struct agp_memory *mem, off_t pg_start, int type)
if (mem->page_count == 0)
return 0;
- if (type != 0 || mem->type != 0) {
+ if (type != mem->type)
+ return -EINVAL;
+
+ mask_type = bridge->driver->agp_type_to_mask_type(bridge, type);
+ if (mask_type != 0) {
/* The generic routines know nothing of memory types */
return -EINVAL;
}
@@ -1056,22 +1138,40 @@ int agp_generic_remove_memory(struct agp_memory *mem, off_t pg_start, int type)
}
EXPORT_SYMBOL(agp_generic_remove_memory);
-
struct agp_memory *agp_generic_alloc_by_type(size_t page_count, int type)
{
return NULL;
}
EXPORT_SYMBOL(agp_generic_alloc_by_type);
-
void agp_generic_free_by_type(struct agp_memory *curr)
{
- vfree(curr->memory);
+ agp_free_page_array(curr);
agp_free_key(curr->key);
kfree(curr);
}
EXPORT_SYMBOL(agp_generic_free_by_type);
+struct agp_memory *agp_generic_alloc_user(size_t page_count, int type)
+{
+ struct agp_memory *new;
+ int i;
+ int pages;
+
+ pages = (page_count + ENTRIES_PER_PAGE - 1) / ENTRIES_PER_PAGE;
+ new = agp_create_user_memory(page_count);
+ if (new == NULL)
+ return NULL;
+
+ for (i = 0; i < page_count; i++)
+ new->memory[i] = 0;
+ new->page_count = 0;
+ new->type = type;
+ new->num_scratch_pages = pages;
+
+ return new;
+}
+EXPORT_SYMBOL(agp_generic_alloc_user);
/*
* Basic Page Allocation Routines -
@@ -1165,6 +1265,15 @@ unsigned long agp_generic_mask_memory(struct agp_bridge_data *bridge,
}
EXPORT_SYMBOL(agp_generic_mask_memory);
+int agp_generic_type_to_mask_type(struct agp_bridge_data *bridge,
+ int type)
+{
+ if (type >= AGP_USER_TYPES)
+ return 0;
+ return type;
+}
+EXPORT_SYMBOL(agp_generic_type_to_mask_type);
+
/*
* These functions are implemented according to the AGPv3 spec,
* which covers implementation details that had previously been
@@ -1231,7 +1340,7 @@ void agp3_generic_cleanup(void)
}
EXPORT_SYMBOL(agp3_generic_cleanup);
-struct aper_size_info_16 agp3_generic_sizes[AGP_GENERIC_SIZES_ENTRIES] =
+const struct aper_size_info_16 agp3_generic_sizes[AGP_GENERIC_SIZES_ENTRIES] =
{
{4096, 1048576, 10,0x000},
{2048, 524288, 9, 0x800},
diff --git a/drivers/char/agp/hp-agp.c b/drivers/char/agp/hp-agp.c
index 907fb66ec4a..79f7c01db75 100644
--- a/drivers/char/agp/hp-agp.c
+++ b/drivers/char/agp/hp-agp.c
@@ -419,7 +419,7 @@ hp_zx1_enable (struct agp_bridge_data *bridge, u32 mode)
agp_device_command(command, (mode & AGP8X_MODE) != 0);
}
-struct agp_bridge_driver hp_zx1_driver = {
+struct const agp_bridge_driver hp_zx1_driver = {
.owner = THIS_MODULE,
.size_type = FIXED_APER_SIZE,
.configure = hp_zx1_configure,
@@ -438,6 +438,7 @@ struct agp_bridge_driver hp_zx1_driver = {
.free_by_type = agp_generic_free_by_type,
.agp_alloc_page = agp_generic_alloc_page,
.agp_destroy_page = agp_generic_destroy_page,
+ .agp_type_to_mask_type = agp_generic_type_to_mask_type,
.cant_use_aperture = 1,
};
diff --git a/drivers/char/agp/i460-agp.c b/drivers/char/agp/i460-agp.c
index 91769443d8f..1cde376a45e 100644
--- a/drivers/char/agp/i460-agp.c
+++ b/drivers/char/agp/i460-agp.c
@@ -78,7 +78,7 @@ static struct {
} *lp_desc;
} i460;
-static struct aper_size_info_8 i460_sizes[3] =
+static const struct aper_size_info_8 i460_sizes[3] =
{
/*
* The 32GB aperture is only available with a 4M GART page size. Due to the
@@ -293,6 +293,9 @@ static int i460_insert_memory_small_io_page (struct agp_memory *mem,
pr_debug("i460_insert_memory_small_io_page(mem=%p, pg_start=%ld, type=%d, paddr0=0x%lx)\n",
mem, pg_start, type, mem->memory[0]);
+ if (type >= AGP_USER_TYPES || mem->type >= AGP_USER_TYPES)
+ return -EINVAL;
+
io_pg_start = I460_IOPAGES_PER_KPAGE * pg_start;
temp = agp_bridge->current_size;
@@ -396,6 +399,9 @@ static int i460_insert_memory_large_io_page (struct agp_memory *mem,
struct lp_desc *start, *end, *lp;
void *temp;
+ if (type >= AGP_USER_TYPES || mem->type >= AGP_USER_TYPES)
+ return -EINVAL;
+
temp = agp_bridge->current_size;
num_entries = A_SIZE_8(temp)->num_entries;
@@ -544,7 +550,7 @@ static unsigned long i460_mask_memory (struct agp_bridge_data *bridge,
| (((addr & ~((1 << I460_IO_PAGE_SHIFT) - 1)) & 0xfffff000) >> 12);
}
-struct agp_bridge_driver intel_i460_driver = {
+struct const agp_bridge_driver intel_i460_driver = {
.owner = THIS_MODULE,
.aperture_sizes = i460_sizes,
.size_type = U8_APER_SIZE,
@@ -572,6 +578,7 @@ struct agp_bridge_driver intel_i460_driver = {
#endif
.alloc_by_type = agp_generic_alloc_by_type,
.free_by_type = agp_generic_free_by_type,
+ .agp_type_to_mask_type = agp_generic_type_to_mask_type,
.cant_use_aperture = 1,
};
diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c
index a3011de51f7..e542a628f1c 100644
--- a/drivers/char/agp/intel-agp.c
+++ b/drivers/char/agp/intel-agp.c
@@ -5,6 +5,7 @@
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/init.h>
+#include <linux/kernel.h>
#include <linux/pagemap.h>
#include <linux/agp_backend.h>
#include "agp.h"
@@ -24,6 +25,9 @@
agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965G_HB)
+extern int agp_memory_reserved;
+
+
/* Intel 815 register */
#define INTEL_815_APCONT 0x51
#define INTEL_815_ATTBASE_MASK ~0x1FFFFFFF
@@ -59,7 +63,7 @@
#define INTEL_I7505_AGPCTRL 0x70
#define INTEL_I7505_MCHCFG 0x50
-static struct aper_size_info_fixed intel_i810_sizes[] =
+static const struct aper_size_info_fixed intel_i810_sizes[] =
{
{64, 16384, 4},
/* The 32M mode still requires a 64k gatt */
@@ -68,12 +72,15 @@ static struct aper_size_info_fixed intel_i810_sizes[] =
#define AGP_DCACHE_MEMORY 1
#define AGP_PHYS_MEMORY 2
+#define INTEL_AGP_CACHED_MEMORY 3
static struct gatt_mask intel_i810_masks[] =
{
{.mask = I810_PTE_VALID, .type = 0},
{.mask = (I810_PTE_VALID | I810_PTE_LOCAL), .type = AGP_DCACHE_MEMORY},
- {.mask = I810_PTE_VALID, .type = 0}
+ {.mask = I810_PTE_VALID, .type = 0},
+ {.mask = I810_PTE_VALID | I830_PTE_SYSTEM_CACHED,
+ .type = INTEL_AGP_CACHED_MEMORY}
};
static struct _intel_i810_private {
@@ -117,13 +124,15 @@ static int intel_i810_configure(void)
current_size = A_SIZE_FIX(agp_bridge->current_size);
- pci_read_config_dword(intel_i810_private.i810_dev, I810_MMADDR, &temp);
- temp &= 0xfff80000;
-
- intel_i810_private.registers = ioremap(temp, 128 * 4096);
if (!intel_i810_private.registers) {
- printk(KERN_ERR PFX "Unable to remap memory.\n");
- return -ENOMEM;
+ pci_read_config_dword(intel_i810_private.i810_dev, I810_MMADDR, &temp);
+ temp &= 0xfff80000;
+
+ intel_i810_private.registers = ioremap(temp, 128 * 4096);
+ if (!intel_i810_private.registers) {
+ printk(KERN_ERR PFX "Unable to remap memory.\n");
+ return -ENOMEM;
+ }
}
if ((readl(intel_i810_private.registers+I810_DRAM_CTL)
@@ -201,62 +210,79 @@ static void i8xx_destroy_pages(void *addr)
atomic_dec(&agp_bridge->current_memory_agp);
}
+static int intel_i830_type_to_mask_type(struct agp_bridge_data *bridge,
+ int type)
+{
+ if (type < AGP_USER_TYPES)
+ return type;
+ else if (type == AGP_USER_CACHED_MEMORY)
+ return INTEL_AGP_CACHED_MEMORY;
+ else
+ return 0;
+}
+
static int intel_i810_insert_entries(struct agp_memory *mem, off_t pg_start,
int type)
{
int i, j, num_entries;
void *temp;
+ int ret = -EINVAL;
+ int mask_type;
if (mem->page_count == 0)
- return 0;
+ goto out;
temp = agp_bridge->current_size;
num_entries = A_SIZE_FIX(temp)->num_entries;
if ((pg_start + mem->page_count) > num_entries)
- return -EINVAL;
+ goto out_err;
- for (j = pg_start; j < (pg_start + mem->page_count); j++) {
- if (!PGE_EMPTY(agp_bridge, readl(agp_bridge->gatt_table+j)))
- return -EBUSY;
- }
- if (type != 0 || mem->type != 0) {
- if ((type == AGP_DCACHE_MEMORY) && (mem->type == AGP_DCACHE_MEMORY)) {
- /* special insert */
- if (!mem->is_flushed) {
- global_cache_flush();
- mem->is_flushed = TRUE;
- }
-
- for (i = pg_start; i < (pg_start + mem->page_count); i++) {
- writel((i*4096)|I810_PTE_LOCAL|I810_PTE_VALID, intel_i810_private.registers+I810_PTE_BASE+(i*4));
- }
- readl(intel_i810_private.registers+I810_PTE_BASE+((i-1)*4)); /* PCI Posting. */
-
- agp_bridge->driver->tlb_flush(mem);
- return 0;
+ for (j = pg_start; j < (pg_start + mem->page_count); j++) {
+ if (!PGE_EMPTY(agp_bridge, readl(agp_bridge->gatt_table+j))) {
+ ret = -EBUSY;
+ goto out_err;
}
- if ((type == AGP_PHYS_MEMORY) && (mem->type == AGP_PHYS_MEMORY))
- goto insert;
- return -EINVAL;
}
-insert:
- if (!mem->is_flushed) {
- global_cache_flush();
- mem->is_flushed = TRUE;
- }
+ if (type != mem->type)
+ goto out_err;
- for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
- writel(agp_bridge->driver->mask_memory(agp_bridge,
- mem->memory[i], mem->type),
- intel_i810_private.registers+I810_PTE_BASE+(j*4));
+ mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type);
+
+ switch (mask_type) {
+ case AGP_DCACHE_MEMORY:
+ if (!mem->is_flushed)
+ global_cache_flush();
+ for (i = pg_start; i < (pg_start + mem->page_count); i++) {
+ writel((i*4096)|I810_PTE_LOCAL|I810_PTE_VALID,
+ intel_i810_private.registers+I810_PTE_BASE+(i*4));
+ }
+ readl(intel_i810_private.registers+I810_PTE_BASE+((i-1)*4));
+ break;
+ case AGP_PHYS_MEMORY:
+ case AGP_NORMAL_MEMORY:
+ if (!mem->is_flushed)
+ global_cache_flush();
+ for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
+ writel(agp_bridge->driver->mask_memory(agp_bridge,
+ mem->memory[i],
+ mask_type),
+ intel_i810_private.registers+I810_PTE_BASE+(j*4));
+ }
+ readl(intel_i810_private.registers+I810_PTE_BASE+((j-1)*4));
+ break;
+ default:
+ goto out_err;
}
- readl(intel_i810_private.registers+I810_PTE_BASE+((j-1)*4)); /* PCI Posting. */
agp_bridge->driver->tlb_flush(mem);
- return 0;
+out:
+ ret = 0;
+out_err:
+ mem->is_flushed = 1;
+ return ret;
}
static int intel_i810_remove_entries(struct agp_memory *mem, off_t pg_start,
@@ -337,12 +363,11 @@ static struct agp_memory *intel_i810_alloc_by_type(size_t pg_count, int type)
new->type = AGP_DCACHE_MEMORY;
new->page_count = pg_count;
new->num_scratch_pages = 0;
- vfree(new->memory);
+ agp_free_page_array(new);
return new;
}
if (type == AGP_PHYS_MEMORY)
return alloc_agpphysmem_i8xx(pg_count, type);
-
return NULL;
}
@@ -357,7 +382,7 @@ static void intel_i810_free_by_type(struct agp_memory *curr)
gart_to_virt(curr->memory[0]));
global_flush_tlb();
}
- vfree(curr->memory);
+ agp_free_page_array(curr);
}
kfree(curr);
}
@@ -619,9 +644,11 @@ static int intel_i830_insert_entries(struct agp_memory *mem,off_t pg_start, int
{
int i,j,num_entries;
void *temp;
+ int ret = -EINVAL;
+ int mask_type;
if (mem->page_count == 0)
- return 0;
+ goto out;
temp = agp_bridge->current_size;
num_entries = A_SIZE_FIX(temp)->num_entries;
@@ -631,34 +658,41 @@ static int intel_i830_insert_entries(struct agp_memory *mem,off_t pg_start, int
pg_start,intel_i830_private.gtt_entries);
printk (KERN_INFO PFX "Trying to insert into local/stolen memory\n");
- return -EINVAL;
+ goto out_err;
}
if ((pg_start + mem->page_count) > num_entries)
- return -EINVAL;
+ goto out_err;
/* The i830 can't check the GTT for entries since its read only,
* depend on the caller to make the correct offset decisions.
*/
- if ((type != 0 && type != AGP_PHYS_MEMORY) ||
- (mem->type != 0 && mem->type != AGP_PHYS_MEMORY))
- return -EINVAL;
+ if (type != mem->type)
+ goto out_err;
+
+ mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type);
- if (!mem->is_flushed) {
+ if (mask_type != 0 && mask_type != AGP_PHYS_MEMORY &&
+ mask_type != INTEL_AGP_CACHED_MEMORY)
+ goto out_err;
+
+ if (!mem->is_flushed)
global_cache_flush();
- mem->is_flushed = TRUE;
- }
for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
writel(agp_bridge->driver->mask_memory(agp_bridge,
- mem->memory[i], mem->type),
- intel_i830_private.registers+I810_PTE_BASE+(j*4));
+ mem->memory[i], mask_type),
+ intel_i830_private.registers+I810_PTE_BASE+(j*4));
}
readl(intel_i830_private.registers+I810_PTE_BASE+((j-1)*4));
-
agp_bridge->driver->tlb_flush(mem);
- return 0;
+
+out:
+ ret = 0;
+out_err:
+ mem->is_flushed = 1;
+ return ret;
}
static int intel_i830_remove_entries(struct agp_memory *mem,off_t pg_start,
@@ -687,7 +721,6 @@ static struct agp_memory *intel_i830_alloc_by_type(size_t pg_count,int type)
{
if (type == AGP_PHYS_MEMORY)
return alloc_agpphysmem_i8xx(pg_count, type);
-
/* always return NULL for other allocation types for now */
return NULL;
}
@@ -734,9 +767,11 @@ static int intel_i915_insert_entries(struct agp_memory *mem,off_t pg_start,
{
int i,j,num_entries;
void *temp;
+ int ret = -EINVAL;
+ int mask_type;
if (mem->page_count == 0)
- return 0;
+ goto out;
temp = agp_bridge->current_size;
num_entries = A_SIZE_FIX(temp)->num_entries;
@@ -746,33 +781,41 @@ static int intel_i915_insert_entries(struct agp_memory *mem,off_t pg_start,
pg_start,intel_i830_private.gtt_entries);
printk (KERN_INFO PFX "Trying to insert into local/stolen memory\n");
- return -EINVAL;
+ goto out_err;
}
if ((pg_start + mem->page_count) > num_entries)
- return -EINVAL;
+ goto out_err;
- /* The i830 can't check the GTT for entries since its read only,
+ /* The i915 can't check the GTT for entries since its read only,
* depend on the caller to make the correct offset decisions.
*/
- if ((type != 0 && type != AGP_PHYS_MEMORY) ||
- (mem->type != 0 && mem->type != AGP_PHYS_MEMORY))
- return -EINVAL;
+ if (type != mem->type)
+ goto out_err;
+
+ mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type);
- if (!mem->is_flushed) {
+ if (mask_type != 0 && mask_type != AGP_PHYS_MEMORY &&
+ mask_type != INTEL_AGP_CACHED_MEMORY)
+ goto out_err;
+
+ if (!mem->is_flushed)
global_cache_flush();
- mem->is_flushed = TRUE;
- }
for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
writel(agp_bridge->driver->mask_memory(agp_bridge,
- mem->memory[i], mem->type), intel_i830_private.gtt+j);
+ mem->memory[i], mask_type), intel_i830_private.gtt+j);
}
- readl(intel_i830_private.gtt+j-1);
+ readl(intel_i830_private.gtt+j-1);
agp_bridge->driver->tlb_flush(mem);
- return 0;
+
+ out:
+ ret = 0;
+ out_err:
+ mem->is_flushed = 1;
+ return ret;
}
static int intel_i915_remove_entries(struct agp_memory *mem,off_t pg_start,
@@ -803,7 +846,7 @@ static int intel_i915_remove_entries(struct agp_memory *mem,off_t pg_start,
*/
static int intel_i9xx_fetch_size(void)
{
- int num_sizes = sizeof(intel_i830_sizes) / sizeof(*intel_i830_sizes);
+ int num_sizes = ARRAY_SIZE(intel_i830_sizes);
int aper_size; /* size in megabytes */
int i;
@@ -1322,18 +1365,18 @@ static int intel_7505_configure(void)
}
/* Setup function */
-static struct gatt_mask intel_generic_masks[] =
+static const struct gatt_mask intel_generic_masks[] =
{
{.mask = 0x00000017, .type = 0}
};
-static struct aper_size_info_8 intel_815_sizes[2] =
+static const struct aper_size_info_8 intel_815_sizes[2] =
{
{64, 16384, 4, 0},
{32, 8192, 3, 8},
};
-static struct aper_size_info_8 intel_8xx_sizes[7] =
+static const struct aper_size_info_8 intel_8xx_sizes[7] =
{
{256, 65536, 6, 0},
{128, 32768, 5, 32},
@@ -1344,7 +1387,7 @@ static struct aper_size_info_8 intel_8xx_sizes[7] =
{4, 1024, 0, 63}
};
-static struct aper_size_info_16 intel_generic_sizes[7] =
+static const struct aper_size_info_16 intel_generic_sizes[7] =
{
{256, 65536, 6, 0},
{128, 32768, 5, 32},
@@ -1355,7 +1398,7 @@ static struct aper_size_info_16 intel_generic_sizes[7] =
{4, 1024, 0, 63}
};
-static struct aper_size_info_8 intel_830mp_sizes[4] =
+static const struct aper_size_info_8 intel_830mp_sizes[4] =
{
{256, 65536, 6, 0},
{128, 32768, 5, 32},
@@ -1363,7 +1406,7 @@ static struct aper_size_info_8 intel_830mp_sizes[4] =
{32, 8192, 3, 56}
};
-static struct agp_bridge_driver intel_generic_driver = {
+static const struct agp_bridge_driver intel_generic_driver = {
.owner = THIS_MODULE,
.aperture_sizes = intel_generic_sizes,
.size_type = U16_APER_SIZE,
@@ -1384,9 +1427,10 @@ static struct agp_bridge_driver intel_generic_driver = {
.free_by_type = agp_generic_free_by_type,
.agp_alloc_page = agp_generic_alloc_page,
.agp_destroy_page = agp_generic_destroy_page,
+ .agp_type_to_mask_type = agp_generic_type_to_mask_type,
};
-static struct agp_bridge_driver intel_810_driver = {
+static const struct agp_bridge_driver intel_810_driver = {
.owner = THIS_MODULE,
.aperture_sizes = intel_i810_sizes,
.size_type = FIXED_APER_SIZE,
@@ -1408,9 +1452,10 @@ static struct agp_bridge_driver intel_810_driver = {
.free_by_type = intel_i810_free_by_type,
.agp_alloc_page = agp_generic_alloc_page,
.agp_destroy_page = agp_generic_destroy_page,
+ .agp_type_to_mask_type = agp_generic_type_to_mask_type,
};
-static struct agp_bridge_driver intel_815_driver = {
+static const struct agp_bridge_driver intel_815_driver = {
.owner = THIS_MODULE,
.aperture_sizes = intel_815_sizes,
.size_type = U8_APER_SIZE,
@@ -1431,9 +1476,10 @@ static struct agp_bridge_driver intel_815_driver = {
.free_by_type = agp_generic_free_by_type,
.agp_alloc_page = agp_generic_alloc_page,
.agp_destroy_page = agp_generic_destroy_page,
+ .agp_type_to_mask_type = agp_generic_type_to_mask_type,
};
-static struct agp_bridge_driver intel_830_driver = {
+static const struct agp_bridge_driver intel_830_driver = {
.owner = THIS_MODULE,
.aperture_sizes = intel_i830_sizes,
.size_type = FIXED_APER_SIZE,
@@ -1455,9 +1501,10 @@ static struct agp_bridge_driver intel_830_driver = {
.free_by_type = intel_i810_free_by_type,
.agp_alloc_page = agp_generic_alloc_page,
.agp_destroy_page = agp_generic_destroy_page,
+ .agp_type_to_mask_type = intel_i830_type_to_mask_type,
};
-static struct agp_bridge_driver intel_820_driver = {
+static const struct agp_bridge_driver intel_820_driver = {
.owner = THIS_MODULE,
.aperture_sizes = intel_8xx_sizes,
.size_type = U8_APER_SIZE,
@@ -1478,9 +1525,10 @@ static struct agp_bridge_driver intel_820_driver = {
.free_by_type = agp_generic_free_by_type,
.agp_alloc_page = agp_generic_alloc_page,
.agp_destroy_page = agp_generic_destroy_page,
+ .agp_type_to_mask_type = agp_generic_type_to_mask_type,
};
-static struct agp_bridge_driver intel_830mp_driver = {
+static const struct agp_bridge_driver intel_830mp_driver = {
.owner = THIS_MODULE,
.aperture_sizes = intel_830mp_sizes,
.size_type = U8_APER_SIZE,
@@ -1501,9 +1549,10 @@ static struct agp_bridge_driver intel_830mp_driver = {
.free_by_type = agp_generic_free_by_type,
.agp_alloc_page = agp_generic_alloc_page,
.agp_destroy_page = agp_generic_destroy_page,
+ .agp_type_to_mask_type = agp_generic_type_to_mask_type,
};
-static struct agp_bridge_driver intel_840_driver = {
+static const struct agp_bridge_driver intel_840_driver = {
.owner = THIS_MODULE,
.aperture_sizes = intel_8xx_sizes,
.size_type = U8_APER_SIZE,
@@ -1524,9 +1573,10 @@ static struct agp_bridge_driver intel_840_driver = {
.free_by_type = agp_generic_free_by_type,
.agp_alloc_page = agp_generic_alloc_page,
.agp_destroy_page = agp_generic_destroy_page,
+ .agp_type_to_mask_type = agp_generic_type_to_mask_type,
};
-static struct agp_bridge_driver intel_845_driver = {
+static const struct agp_bridge_driver intel_845_driver = {
.owner = THIS_MODULE,
.aperture_sizes = intel_8xx_sizes,
.size_type = U8_APER_SIZE,
@@ -1547,9 +1597,10 @@ static struct agp_bridge_driver intel_845_driver = {
.free_by_type = agp_generic_free_by_type,
.agp_alloc_page = agp_generic_alloc_page,
.agp_destroy_page = agp_generic_destroy_page,
+ .agp_type_to_mask_type = agp_generic_type_to_mask_type,
};
-static struct agp_bridge_driver intel_850_driver = {
+static const struct agp_bridge_driver intel_850_driver = {
.owner = THIS_MODULE,
.aperture_sizes = intel_8xx_sizes,
.size_type = U8_APER_SIZE,
@@ -1570,9 +1621,10 @@ static struct agp_bridge_driver intel_850_driver = {
.free_by_type = agp_generic_free_by_type,
.agp_alloc_page = agp_generic_alloc_page,
.agp_destroy_page = agp_generic_destroy_page,
+ .agp_type_to_mask_type = agp_generic_type_to_mask_type,
};
-static struct agp_bridge_driver intel_860_driver = {
+static const struct agp_bridge_driver intel_860_driver = {
.owner = THIS_MODULE,
.aperture_sizes = intel_8xx_sizes,
.size_type = U8_APER_SIZE,
@@ -1593,9 +1645,10 @@ static struct agp_bridge_driver intel_860_driver = {
.free_by_type = agp_generic_free_by_type,
.agp_alloc_page = agp_generic_alloc_page,
.agp_destroy_page = agp_generic_destroy_page,
+ .agp_type_to_mask_type = agp_generic_type_to_mask_type,
};
-static struct agp_bridge_driver intel_915_driver = {
+static const struct agp_bridge_driver intel_915_driver = {
.owner = THIS_MODULE,
.aperture_sizes = intel_i830_sizes,
.size_type = FIXED_APER_SIZE,
@@ -1617,9 +1670,10 @@ static struct agp_bridge_driver intel_915_driver = {
.free_by_type = intel_i810_free_by_type,
.agp_alloc_page = agp_generic_alloc_page,
.agp_destroy_page = agp_generic_destroy_page,
+ .agp_type_to_mask_type = intel_i830_type_to_mask_type,
};
-static struct agp_bridge_driver intel_i965_driver = {
+static const struct agp_bridge_driver intel_i965_driver = {
.owner = THIS_MODULE,
.aperture_sizes = intel_i830_sizes,
.size_type = FIXED_APER_SIZE,
@@ -1641,9 +1695,10 @@ static struct agp_bridge_driver intel_i965_driver = {
.free_by_type = intel_i810_free_by_type,
.agp_alloc_page = agp_generic_alloc_page,
.agp_destroy_page = agp_generic_destroy_page,
+ .agp_type_to_mask_type = intel_i830_type_to_mask_type,
};
-static struct agp_bridge_driver intel_7505_driver = {
+static const struct agp_bridge_driver intel_7505_driver = {
.owner = THIS_MODULE,
.aperture_sizes = intel_8xx_sizes,
.size_type = U8_APER_SIZE,
@@ -1664,6 +1719,7 @@ static struct agp_bridge_driver intel_7505_driver = {
.free_by_type = agp_generic_free_by_type,
.agp_alloc_page = agp_generic_alloc_page,
.agp_destroy_page = agp_generic_destroy_page,
+ .agp_type_to_mask_type = agp_generic_type_to_mask_type,
};
static int find_i810(u16 device)
diff --git a/drivers/char/agp/nvidia-agp.c b/drivers/char/agp/nvidia-agp.c
index df7f37b2739..0c9dab557c9 100644
--- a/drivers/char/agp/nvidia-agp.c
+++ b/drivers/char/agp/nvidia-agp.c
@@ -272,7 +272,7 @@ static void nvidia_tlbflush(struct agp_memory *mem)
}
-static struct aper_size_info_8 nvidia_generic_sizes[5] =
+static const struct aper_size_info_8 nvidia_generic_sizes[5] =
{
{512, 131072, 7, 0},
{256, 65536, 6, 8},
@@ -283,13 +283,13 @@ static struct aper_size_info_8 nvidia_generic_sizes[5] =
};
-static struct gatt_mask nvidia_generic_masks[] =
+static const struct gatt_mask nvidia_generic_masks[] =
{
{ .mask = 1, .type = 0}
};
-static struct agp_bridge_driver nvidia_driver = {
+static const struct agp_bridge_driver nvidia_driver = {
.owner = THIS_MODULE,
.aperture_sizes = nvidia_generic_sizes,
.size_type = U8_APER_SIZE,
@@ -310,6 +310,7 @@ static struct agp_bridge_driver nvidia_driver = {
.free_by_type = agp_generic_free_by_type,
.agp_alloc_page = agp_generic_alloc_page,
.agp_destroy_page = agp_generic_destroy_page,
+ .agp_type_to_mask_type = agp_generic_type_to_mask_type,
};
static int __devinit agp_nvidia_probe(struct pci_dev *pdev,
diff --git a/drivers/char/agp/parisc-agp.c b/drivers/char/agp/parisc-agp.c
index 30cc7aeae9a..3c8f3d63362 100644
--- a/drivers/char/agp/parisc-agp.c
+++ b/drivers/char/agp/parisc-agp.c
@@ -210,7 +210,7 @@ parisc_agp_enable(struct agp_bridge_data *bridge, u32 mode)
agp_device_command(command, (mode & AGP8X_MODE) != 0);
}
-struct agp_bridge_driver parisc_agp_driver = {
+struct const agp_bridge_driver parisc_agp_driver = {
.owner = THIS_MODULE,
.size_type = FIXED_APER_SIZE,
.configure = parisc_agp_configure,
@@ -228,6 +228,7 @@ struct agp_bridge_driver parisc_agp_driver = {
.free_by_type = agp_generic_free_by_type,
.agp_alloc_page = agp_generic_alloc_page,
.agp_destroy_page = agp_generic_destroy_page,
+ .agp_type_to_mask_type = agp_generic_type_to_mask_type,
.cant_use_aperture = 1,
};
diff --git a/drivers/char/agp/sgi-agp.c b/drivers/char/agp/sgi-agp.c
index 902648db7ef..e12773acf3d 100644
--- a/drivers/char/agp/sgi-agp.c
+++ b/drivers/char/agp/sgi-agp.c
@@ -247,7 +247,7 @@ static struct agp_bridge_data *sgi_tioca_find_bridge(struct pci_dev *pdev)
return bridge;
}
-struct agp_bridge_driver sgi_tioca_driver = {
+struct const agp_bridge_driver sgi_tioca_driver = {
.owner = THIS_MODULE,
.size_type = U16_APER_SIZE,
.configure = sgi_tioca_configure,
@@ -265,6 +265,7 @@ struct agp_bridge_driver sgi_tioca_driver = {
.free_by_type = agp_generic_free_by_type,
.agp_alloc_page = sgi_tioca_alloc_page,
.agp_destroy_page = agp_generic_destroy_page,
+ .agp_type_to_mask_type = agp_generic_type_to_mask_type,
.cant_use_aperture = 1,
.needs_scratch_page = 0,
.num_aperture_sizes = 1,
diff --git a/drivers/char/agp/sis-agp.c b/drivers/char/agp/sis-agp.c
index a00fd48a6f0..125f4282d95 100644
--- a/drivers/char/agp/sis-agp.c
+++ b/drivers/char/agp/sis-agp.c
@@ -108,7 +108,7 @@ static void sis_delayed_enable(struct agp_bridge_data *bridge, u32 mode)
}
}
-static struct aper_size_info_8 sis_generic_sizes[7] =
+static const struct aper_size_info_8 sis_generic_sizes[7] =
{
{256, 65536, 6, 99},
{128, 32768, 5, 83},
@@ -140,6 +140,7 @@ static struct agp_bridge_driver sis_driver = {
.free_by_type = agp_generic_free_by_type,
.agp_alloc_page = agp_generic_alloc_page,
.agp_destroy_page = agp_generic_destroy_page,
+ .agp_type_to_mask_type = agp_generic_type_to_mask_type,
};
static struct agp_device_ids sis_agp_device_ids[] __devinitdata =
diff --git a/drivers/char/agp/sworks-agp.c b/drivers/char/agp/sworks-agp.c
index 4f2d7d99902..55212a3811f 100644
--- a/drivers/char/agp/sworks-agp.c
+++ b/drivers/char/agp/sworks-agp.c
@@ -385,12 +385,12 @@ static int serverworks_remove_memory(struct agp_memory *mem, off_t pg_start,
return 0;
}
-static struct gatt_mask serverworks_masks[] =
+static const struct gatt_mask serverworks_masks[] =
{
{.mask = 1, .type = 0}
};
-static struct aper_size_info_lvl2 serverworks_sizes[7] =
+static const struct aper_size_info_lvl2 serverworks_sizes[7] =
{
{2048, 524288, 0x80000000},
{1024, 262144, 0xc0000000},
@@ -423,7 +423,7 @@ static void serverworks_agp_enable(struct agp_bridge_data *bridge, u32 mode)
agp_device_command(command, 0);
}
-static struct agp_bridge_driver sworks_driver = {
+static const struct agp_bridge_driver sworks_driver = {
.owner = THIS_MODULE,
.aperture_sizes = serverworks_sizes,
.size_type = LVL2_APER_SIZE,
@@ -444,6 +444,7 @@ static struct agp_bridge_driver sworks_driver = {
.free_by_type = agp_generic_free_by_type,
.agp_alloc_page = agp_generic_alloc_page,
.agp_destroy_page = agp_generic_destroy_page,
+ .agp_type_to_mask_type = agp_generic_type_to_mask_type,
};
static int __devinit agp_serverworks_probe(struct pci_dev *pdev,
diff --git a/drivers/char/agp/uninorth-agp.c b/drivers/char/agp/uninorth-agp.c
index dffc19382f7..292b4ad1ae3 100644
--- a/drivers/char/agp/uninorth-agp.c
+++ b/drivers/char/agp/uninorth-agp.c
@@ -460,7 +460,7 @@ void null_cache_flush(void)
/* Setup function */
-static struct aper_size_info_32 uninorth_sizes[7] =
+static const struct aper_size_info_32 uninorth_sizes[7] =
{
#if 0 /* Not sure uninorth supports that high aperture sizes */
{256, 65536, 6, 64},
@@ -477,7 +477,7 @@ static struct aper_size_info_32 uninorth_sizes[7] =
* Not sure that u3 supports that high aperture sizes but it
* would strange if it did not :)
*/
-static struct aper_size_info_32 u3_sizes[8] =
+static const struct aper_size_info_32 u3_sizes[8] =
{
{512, 131072, 7, 128},
{256, 65536, 6, 64},
@@ -489,7 +489,7 @@ static struct aper_size_info_32 u3_sizes[8] =
{4, 1024, 0, 1}
};
-struct agp_bridge_driver uninorth_agp_driver = {
+struct const agp_bridge_driver uninorth_agp_driver = {
.owner = THIS_MODULE,
.aperture_sizes = (void *)uninorth_sizes,
.size_type = U32_APER_SIZE,
@@ -510,10 +510,11 @@ struct agp_bridge_driver uninorth_agp_driver = {
.free_by_type = agp_generic_free_by_type,
.agp_alloc_page = agp_generic_alloc_page,
.agp_destroy_page = agp_generic_destroy_page,
+ .agp_type_to_mask_type = agp_generic_type_to_mask_type,
.cant_use_aperture = 1,
};
-struct agp_bridge_driver u3_agp_driver = {
+struct const agp_bridge_driver u3_agp_driver = {
.owner = THIS_MODULE,
.aperture_sizes = (void *)u3_sizes,
.size_type = U32_APER_SIZE,
@@ -534,6 +535,7 @@ struct agp_bridge_driver u3_agp_driver = {
.free_by_type = agp_generic_free_by_type,
.agp_alloc_page = agp_generic_alloc_page,
.agp_destroy_page = agp_generic_destroy_page,
+ .agp_type_to_mask_type = agp_generic_type_to_mask_type,
.cant_use_aperture = 1,
.needs_scratch_page = 1,
};
diff --git a/drivers/char/agp/via-agp.c b/drivers/char/agp/via-agp.c
index 2ded7a280d7..a2bb4eccaab 100644
--- a/drivers/char/agp/via-agp.c
+++ b/drivers/char/agp/via-agp.c
@@ -89,7 +89,7 @@ static void via_tlbflush(struct agp_memory *mem)
}
-static struct aper_size_info_8 via_generic_sizes[9] =
+static const struct aper_size_info_8 via_generic_sizes[9] =
{
{256, 65536, 6, 0},
{128, 32768, 5, 128},
@@ -170,7 +170,7 @@ static void via_tlbflush_agp3(struct agp_memory *mem)
}
-static struct agp_bridge_driver via_agp3_driver = {
+static const struct agp_bridge_driver via_agp3_driver = {
.owner = THIS_MODULE,
.aperture_sizes = agp3_generic_sizes,
.size_type = U8_APER_SIZE,
@@ -191,9 +191,10 @@ static struct agp_bridge_driver via_agp3_driver = {
.free_by_type = agp_generic_free_by_type,
.agp_alloc_page = agp_generic_alloc_page,
.agp_destroy_page = agp_generic_destroy_page,
+ .agp_type_to_mask_type = agp_generic_type_to_mask_type,
};
-static struct agp_bridge_driver via_driver = {
+static const struct agp_bridge_driver via_driver = {
.owner = THIS_MODULE,
.aperture_sizes = via_generic_sizes,
.size_type = U8_APER_SIZE,
@@ -214,6 +215,7 @@ static struct agp_bridge_driver via_driver = {
.free_by_type = agp_generic_free_by_type,
.agp_alloc_page = agp_generic_alloc_page,
.agp_destroy_page = agp_generic_destroy_page,
+ .agp_type_to_mask_type = agp_generic_type_to_mask_type,
};
static struct agp_device_ids via_agp_device_ids[] __devinitdata =
diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c
index feb4ac802a0..0e2b72f2b88 100644
--- a/drivers/char/amiserial.c
+++ b/drivers/char/amiserial.c
@@ -527,10 +527,8 @@ static void do_softint(unsigned long private_)
if (!tty)
return;
- if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
+ if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event))
tty_wakeup(tty);
- wake_up_interruptible(&tty->write_wait);
- }
}
/*
@@ -904,8 +902,7 @@ static int rs_write(struct tty_struct * tty, const unsigned char *buf, int count
if (!info->xmit.buf)
return 0;
- local_save_flags(flags);
- local_irq_disable();
+ local_irq_save(flags);
while (1) {
c = CIRC_SPACE_TO_END(info->xmit.head,
info->xmit.tail,
@@ -968,7 +965,6 @@ static void rs_flush_buffer(struct tty_struct *tty)
local_irq_save(flags);
info->xmit.head = info->xmit.tail = 0;
local_irq_restore(flags);
- wake_up_interruptible(&tty->write_wait);
tty_wakeup(tty);
}
diff --git a/drivers/char/apm-emulation.c b/drivers/char/apm-emulation.c
new file mode 100644
index 00000000000..179c7a3b6e7
--- /dev/null
+++ b/drivers/char/apm-emulation.c
@@ -0,0 +1,672 @@
+/*
+ * bios-less APM driver for ARM Linux
+ * Jamey Hicks <jamey@crl.dec.com>
+ * adapted from the APM BIOS driver for Linux by Stephen Rothwell (sfr@linuxcare.com)
+ *
+ * APM 1.2 Reference:
+ * Intel Corporation, Microsoft Corporation. Advanced Power Management
+ * (APM) BIOS Interface Specification, Revision 1.2, February 1996.
+ *
+ * [This document is available from Microsoft at:
+ * http://www.microsoft.com/hwdev/busbios/amp_12.htm]
+ */
+#include <linux/module.h>
+#include <linux/poll.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include <linux/miscdevice.h>
+#include <linux/apm_bios.h>
+#include <linux/capability.h>
+#include <linux/sched.h>
+#include <linux/pm.h>
+#include <linux/apm-emulation.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/init.h>
+#include <linux/completion.h>
+#include <linux/kthread.h>
+#include <linux/delay.h>
+
+#include <asm/system.h>
+
+/*
+ * The apm_bios device is one of the misc char devices.
+ * This is its minor number.
+ */
+#define APM_MINOR_DEV 134
+
+/*
+ * See Documentation/Config.help for the configuration options.
+ *
+ * Various options can be changed at boot time as follows:
+ * (We allow underscores for compatibility with the modules code)
+ * apm=on/off enable/disable APM
+ */
+
+/*
+ * Maximum number of events stored
+ */
+#define APM_MAX_EVENTS 16
+
+struct apm_queue {
+ unsigned int event_head;
+ unsigned int event_tail;
+ apm_event_t events[APM_MAX_EVENTS];
+};
+
+/*
+ * The per-file APM data
+ */
+struct apm_user {
+ struct list_head list;
+
+ unsigned int suser: 1;
+ unsigned int writer: 1;
+ unsigned int reader: 1;
+
+ int suspend_result;
+ unsigned int suspend_state;
+#define SUSPEND_NONE 0 /* no suspend pending */
+#define SUSPEND_PENDING 1 /* suspend pending read */
+#define SUSPEND_READ 2 /* suspend read, pending ack */
+#define SUSPEND_ACKED 3 /* suspend acked */
+#define SUSPEND_WAIT 4 /* waiting for suspend */
+#define SUSPEND_DONE 5 /* suspend completed */
+
+ struct apm_queue queue;
+};
+
+/*
+ * Local variables
+ */
+static int suspends_pending;
+static int apm_disabled;
+static struct task_struct *kapmd_tsk;
+
+static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue);
+static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue);
+
+/*
+ * This is a list of everyone who has opened /dev/apm_bios
+ */
+static DECLARE_RWSEM(user_list_lock);
+static LIST_HEAD(apm_user_list);
+
+/*
+ * kapmd info. kapmd provides us a process context to handle
+ * "APM" events within - specifically necessary if we're going
+ * to be suspending the system.
+ */
+static DECLARE_WAIT_QUEUE_HEAD(kapmd_wait);
+static DEFINE_SPINLOCK(kapmd_queue_lock);
+static struct apm_queue kapmd_queue;
+
+static DEFINE_MUTEX(state_lock);
+
+static const char driver_version[] = "1.13"; /* no spaces */
+
+
+
+/*
+ * Compatibility cruft until the IPAQ people move over to the new
+ * interface.
+ */
+static void __apm_get_power_status(struct apm_power_info *info)
+{
+}
+
+/*
+ * This allows machines to provide their own "apm get power status" function.
+ */
+void (*apm_get_power_status)(struct apm_power_info *) = __apm_get_power_status;
+EXPORT_SYMBOL(apm_get_power_status);
+
+
+/*
+ * APM event queue management.
+ */
+static inline int queue_empty(struct apm_queue *q)
+{
+ return q->event_head == q->event_tail;
+}
+
+static inline apm_event_t queue_get_event(struct apm_queue *q)
+{
+ q->event_tail = (q->event_tail + 1) % APM_MAX_EVENTS;
+ return q->events[q->event_tail];
+}
+
+static void queue_add_event(struct apm_queue *q, apm_event_t event)
+{
+ q->event_head = (q->event_head + 1) % APM_MAX_EVENTS;
+ if (q->event_head == q->event_tail) {
+ static int notified;
+
+ if (notified++ == 0)
+ printk(KERN_ERR "apm: an event queue overflowed\n");
+ q->event_tail = (q->event_tail + 1) % APM_MAX_EVENTS;
+ }
+ q->events[q->event_head] = event;
+}
+
+static void queue_event(apm_event_t event)
+{
+ struct apm_user *as;
+
+ down_read(&user_list_lock);
+ list_for_each_entry(as, &apm_user_list, list) {
+ if (as->reader)
+ queue_add_event(&as->queue, event);
+ }
+ up_read(&user_list_lock);
+ wake_up_interruptible(&apm_waitqueue);
+}
+
+/*
+ * queue_suspend_event - queue an APM suspend event.
+ *
+ * Check that we're in a state where we can suspend. If not,
+ * return -EBUSY. Otherwise, queue an event to all "writer"
+ * users. If there are no "writer" users, return '1' to
+ * indicate that we can immediately suspend.
+ */
+static int queue_suspend_event(apm_event_t event, struct apm_user *sender)
+{
+ struct apm_user *as;
+ int ret = 1;
+
+ mutex_lock(&state_lock);
+ down_read(&user_list_lock);
+
+ /*
+ * If a thread is still processing, we can't suspend, so reject
+ * the request.
+ */
+ list_for_each_entry(as, &apm_user_list, list) {
+ if (as != sender && as->reader && as->writer && as->suser &&
+ as->suspend_state != SUSPEND_NONE) {
+ ret = -EBUSY;
+ goto out;
+ }
+ }
+
+ list_for_each_entry(as, &apm_user_list, list) {
+ if (as != sender && as->reader && as->writer && as->suser) {
+ as->suspend_state = SUSPEND_PENDING;
+ suspends_pending++;
+ queue_add_event(&as->queue, event);
+ ret = 0;
+ }
+ }
+ out:
+ up_read(&user_list_lock);
+ mutex_unlock(&state_lock);
+ wake_up_interruptible(&apm_waitqueue);
+ return ret;
+}
+
+static void apm_suspend(void)
+{
+ struct apm_user *as;
+ int err = pm_suspend(PM_SUSPEND_MEM);
+
+ /*
+ * Anyone on the APM queues will think we're still suspended.
+ * Send a message so everyone knows we're now awake again.
+ */
+ queue_event(APM_NORMAL_RESUME);
+
+ /*
+ * Finally, wake up anyone who is sleeping on the suspend.
+ */
+ mutex_lock(&state_lock);
+ down_read(&user_list_lock);
+ list_for_each_entry(as, &apm_user_list, list) {
+ if (as->suspend_state == SUSPEND_WAIT ||
+ as->suspend_state == SUSPEND_ACKED) {
+ as->suspend_result = err;
+ as->suspend_state = SUSPEND_DONE;
+ }
+ }
+ up_read(&user_list_lock);
+ mutex_unlock(&state_lock);
+
+ wake_up(&apm_suspend_waitqueue);
+}
+
+static ssize_t apm_read(struct file *fp, char __user *buf, size_t count, loff_t *ppos)
+{
+ struct apm_user *as = fp->private_data;
+ apm_event_t event;
+ int i = count, ret = 0;
+
+ if (count < sizeof(apm_event_t))
+ return -EINVAL;
+
+ if (queue_empty(&as->queue) && fp->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+
+ wait_event_interruptible(apm_waitqueue, !queue_empty(&as->queue));
+
+ while ((i >= sizeof(event)) && !queue_empty(&as->queue)) {
+ event = queue_get_event(&as->queue);
+
+ ret = -EFAULT;
+ if (copy_to_user(buf, &event, sizeof(event)))
+ break;
+
+ mutex_lock(&state_lock);
+ if (as->suspend_state == SUSPEND_PENDING &&
+ (event == APM_SYS_SUSPEND || event == APM_USER_SUSPEND))
+ as->suspend_state = SUSPEND_READ;
+ mutex_unlock(&state_lock);
+
+ buf += sizeof(event);
+ i -= sizeof(event);
+ }
+
+ if (i < count)
+ ret = count - i;
+
+ return ret;
+}
+
+static unsigned int apm_poll(struct file *fp, poll_table * wait)
+{
+ struct apm_user *as = fp->private_data;
+
+ poll_wait(fp, &apm_waitqueue, wait);
+ return queue_empty(&as->queue) ? 0 : POLLIN | POLLRDNORM;
+}
+
+/*
+ * apm_ioctl - handle APM ioctl
+ *
+ * APM_IOC_SUSPEND
+ * This IOCTL is overloaded, and performs two functions. It is used to:
+ * - initiate a suspend
+ * - acknowledge a suspend read from /dev/apm_bios.
+ * Only when everyone who has opened /dev/apm_bios with write permission
+ * has acknowledge does the actual suspend happen.
+ */
+static int
+apm_ioctl(struct inode * inode, struct file *filp, u_int cmd, u_long arg)
+{
+ struct apm_user *as = filp->private_data;
+ unsigned long flags;
+ int err = -EINVAL;
+
+ if (!as->suser || !as->writer)
+ return -EPERM;
+
+ switch (cmd) {
+ case APM_IOC_SUSPEND:
+ mutex_lock(&state_lock);
+
+ as->suspend_result = -EINTR;
+
+ if (as->suspend_state == SUSPEND_READ) {
+ int pending;
+
+ /*
+ * If we read a suspend command from /dev/apm_bios,
+ * then the corresponding APM_IOC_SUSPEND ioctl is
+ * interpreted as an acknowledge.
+ */
+ as->suspend_state = SUSPEND_ACKED;
+ suspends_pending--;
+ pending = suspends_pending == 0;
+ mutex_unlock(&state_lock);
+
+ /*
+ * If there are no further acknowledges required,
+ * suspend the system.
+ */
+ if (pending)
+ apm_suspend();
+
+ /*
+ * Wait for the suspend/resume to complete. If there
+ * are pending acknowledges, we wait here for them.
+ *
+ * Note: we need to ensure that the PM subsystem does
+ * not kick us out of the wait when it suspends the
+ * threads.
+ */
+ flags = current->flags;
+ current->flags |= PF_NOFREEZE;
+
+ wait_event(apm_suspend_waitqueue,
+ as->suspend_state == SUSPEND_DONE);
+ } else {
+ as->suspend_state = SUSPEND_WAIT;
+ mutex_unlock(&state_lock);
+
+ /*
+ * Otherwise it is a request to suspend the system.
+ * Queue an event for all readers, and expect an
+ * acknowledge from all writers who haven't already
+ * acknowledged.
+ */
+ err = queue_suspend_event(APM_USER_SUSPEND, as);
+ if (err < 0) {
+ /*
+ * Avoid taking the lock here - this
+ * should be fine.
+ */
+ as->suspend_state = SUSPEND_NONE;
+ break;
+ }
+
+ if (err > 0)
+ apm_suspend();
+
+ /*
+ * Wait for the suspend/resume to complete. If there
+ * are pending acknowledges, we wait here for them.
+ *
+ * Note: we need to ensure that the PM subsystem does
+ * not kick us out of the wait when it suspends the
+ * threads.
+ */
+ flags = current->flags;
+ current->flags |= PF_NOFREEZE;
+
+ wait_event_interruptible(apm_suspend_waitqueue,
+ as->suspend_state == SUSPEND_DONE);
+ }
+
+ current->flags = flags;
+
+ mutex_lock(&state_lock);
+ err = as->suspend_result;
+ as->suspend_state = SUSPEND_NONE;
+ mutex_unlock(&state_lock);
+ break;
+ }
+
+ return err;
+}
+
+static int apm_release(struct inode * inode, struct file * filp)
+{
+ struct apm_user *as = filp->private_data;
+ int pending = 0;
+
+ filp->private_data = NULL;
+
+ down_write(&user_list_lock);
+ list_del(&as->list);
+ up_write(&user_list_lock);
+
+ /*
+ * We are now unhooked from the chain. As far as new
+ * events are concerned, we no longer exist. However, we
+ * need to balance suspends_pending, which means the
+ * possibility of sleeping.
+ */
+ mutex_lock(&state_lock);
+ if (as->suspend_state != SUSPEND_NONE) {
+ suspends_pending -= 1;
+ pending = suspends_pending == 0;
+ }
+ mutex_unlock(&state_lock);
+ if (pending)
+ apm_suspend();
+
+ kfree(as);
+ return 0;
+}
+
+static int apm_open(struct inode * inode, struct file * filp)
+{
+ struct apm_user *as;
+
+ as = kzalloc(sizeof(*as), GFP_KERNEL);
+ if (as) {
+ /*
+ * XXX - this is a tiny bit broken, when we consider BSD
+ * process accounting. If the device is opened by root, we
+ * instantly flag that we used superuser privs. Who knows,
+ * we might close the device immediately without doing a
+ * privileged operation -- cevans
+ */
+ as->suser = capable(CAP_SYS_ADMIN);
+ as->writer = (filp->f_mode & FMODE_WRITE) == FMODE_WRITE;
+ as->reader = (filp->f_mode & FMODE_READ) == FMODE_READ;
+
+ down_write(&user_list_lock);
+ list_add(&as->list, &apm_user_list);
+ up_write(&user_list_lock);
+
+ filp->private_data = as;
+ }
+
+ return as ? 0 : -ENOMEM;
+}
+
+static struct file_operations apm_bios_fops = {
+ .owner = THIS_MODULE,
+ .read = apm_read,
+ .poll = apm_poll,
+ .ioctl = apm_ioctl,
+ .open = apm_open,
+ .release = apm_release,
+};
+
+static struct miscdevice apm_device = {
+ .minor = APM_MINOR_DEV,
+ .name = "apm_bios",
+ .fops = &apm_bios_fops
+};
+
+
+#ifdef CONFIG_PROC_FS
+/*
+ * Arguments, with symbols from linux/apm_bios.h.
+ *
+ * 0) Linux driver version (this will change if format changes)
+ * 1) APM BIOS Version. Usually 1.0, 1.1 or 1.2.
+ * 2) APM flags from APM Installation Check (0x00):
+ * bit 0: APM_16_BIT_SUPPORT
+ * bit 1: APM_32_BIT_SUPPORT
+ * bit 2: APM_IDLE_SLOWS_CLOCK
+ * bit 3: APM_BIOS_DISABLED
+ * bit 4: APM_BIOS_DISENGAGED
+ * 3) AC line status
+ * 0x00: Off-line
+ * 0x01: On-line
+ * 0x02: On backup power (BIOS >= 1.1 only)
+ * 0xff: Unknown
+ * 4) Battery status
+ * 0x00: High
+ * 0x01: Low
+ * 0x02: Critical
+ * 0x03: Charging
+ * 0x04: Selected battery not present (BIOS >= 1.2 only)
+ * 0xff: Unknown
+ * 5) Battery flag
+ * bit 0: High
+ * bit 1: Low
+ * bit 2: Critical
+ * bit 3: Charging
+ * bit 7: No system battery
+ * 0xff: Unknown
+ * 6) Remaining battery life (percentage of charge):
+ * 0-100: valid
+ * -1: Unknown
+ * 7) Remaining battery life (time units):
+ * Number of remaining minutes or seconds
+ * -1: Unknown
+ * 8) min = minutes; sec = seconds
+ */
+static int apm_get_info(char *buf, char **start, off_t fpos, int length)
+{
+ struct apm_power_info info;
+ char *units;
+ int ret;
+
+ info.ac_line_status = 0xff;
+ info.battery_status = 0xff;
+ info.battery_flag = 0xff;
+ info.battery_life = -1;
+ info.time = -1;
+ info.units = -1;
+
+ if (apm_get_power_status)
+ apm_get_power_status(&info);
+
+ switch (info.units) {
+ default: units = "?"; break;
+ case 0: units = "min"; break;
+ case 1: units = "sec"; break;
+ }
+
+ ret = sprintf(buf, "%s 1.2 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n",
+ driver_version, APM_32_BIT_SUPPORT,
+ info.ac_line_status, info.battery_status,
+ info.battery_flag, info.battery_life,
+ info.time, units);
+
+ return ret;
+}
+#endif
+
+static int kapmd(void *arg)
+{
+ do {
+ apm_event_t event;
+ int ret;
+
+ wait_event_interruptible(kapmd_wait,
+ !queue_empty(&kapmd_queue) || kthread_should_stop());
+
+ if (kthread_should_stop())
+ break;
+
+ spin_lock_irq(&kapmd_queue_lock);
+ event = 0;
+ if (!queue_empty(&kapmd_queue))
+ event = queue_get_event(&kapmd_queue);
+ spin_unlock_irq(&kapmd_queue_lock);
+
+ switch (event) {
+ case 0:
+ break;
+
+ case APM_LOW_BATTERY:
+ case APM_POWER_STATUS_CHANGE:
+ queue_event(event);
+ break;
+
+ case APM_USER_SUSPEND:
+ case APM_SYS_SUSPEND:
+ ret = queue_suspend_event(event, NULL);
+ if (ret < 0) {
+ /*
+ * We were busy. Try again in 50ms.
+ */
+ queue_add_event(&kapmd_queue, event);
+ msleep(50);
+ }
+ if (ret > 0)
+ apm_suspend();
+ break;
+
+ case APM_CRITICAL_SUSPEND:
+ apm_suspend();
+ break;
+ }
+ } while (1);
+
+ return 0;
+}
+
+static int __init apm_init(void)
+{
+ int ret;
+
+ if (apm_disabled) {
+ printk(KERN_NOTICE "apm: disabled on user request.\n");
+ return -ENODEV;
+ }
+
+ kapmd_tsk = kthread_create(kapmd, NULL, "kapmd");
+ if (IS_ERR(kapmd_tsk)) {
+ ret = PTR_ERR(kapmd_tsk);
+ kapmd_tsk = NULL;
+ return ret;
+ }
+ kapmd_tsk->flags |= PF_NOFREEZE;
+ wake_up_process(kapmd_tsk);
+
+#ifdef CONFIG_PROC_FS
+ create_proc_info_entry("apm", 0, NULL, apm_get_info);
+#endif
+
+ ret = misc_register(&apm_device);
+ if (ret != 0) {
+ remove_proc_entry("apm", NULL);
+ kthread_stop(kapmd_tsk);
+ }
+
+ return ret;
+}
+
+static void __exit apm_exit(void)
+{
+ misc_deregister(&apm_device);
+ remove_proc_entry("apm", NULL);
+
+ kthread_stop(kapmd_tsk);
+}
+
+module_init(apm_init);
+module_exit(apm_exit);
+
+MODULE_AUTHOR("Stephen Rothwell");
+MODULE_DESCRIPTION("Advanced Power Management");
+MODULE_LICENSE("GPL");
+
+#ifndef MODULE
+static int __init apm_setup(char *str)
+{
+ while ((str != NULL) && (*str != '\0')) {
+ if (strncmp(str, "off", 3) == 0)
+ apm_disabled = 1;
+ if (strncmp(str, "on", 2) == 0)
+ apm_disabled = 0;
+ str = strchr(str, ',');
+ if (str != NULL)
+ str += strspn(str, ", \t");
+ }
+ return 1;
+}
+
+__setup("apm=", apm_setup);
+#endif
+
+/**
+ * apm_queue_event - queue an APM event for kapmd
+ * @event: APM event
+ *
+ * Queue an APM event for kapmd to process and ultimately take the
+ * appropriate action. Only a subset of events are handled:
+ * %APM_LOW_BATTERY
+ * %APM_POWER_STATUS_CHANGE
+ * %APM_USER_SUSPEND
+ * %APM_SYS_SUSPEND
+ * %APM_CRITICAL_SUSPEND
+ */
+void apm_queue_event(apm_event_t event)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&kapmd_queue_lock, flags);
+ queue_add_event(&kapmd_queue, event);
+ spin_unlock_irqrestore(&kapmd_queue_lock, flags);
+
+ wake_up_interruptible(&kapmd_wait);
+}
+EXPORT_SYMBOL(apm_queue_event);
diff --git a/drivers/char/briq_panel.c b/drivers/char/briq_panel.c
index 9f8082f8dd2..8dcf9d20f44 100644
--- a/drivers/char/briq_panel.c
+++ b/drivers/char/briq_panel.c
@@ -8,7 +8,6 @@
#include <linux/types.h>
#include <linux/errno.h>
-#include <linux/sched.h>
#include <linux/tty.h>
#include <linux/timer.h>
#include <linux/kernel.h>
@@ -187,7 +186,7 @@ static ssize_t briq_panel_write(struct file *file, const char __user *buf, size_
return len;
}
-static struct file_operations briq_panel_fops = {
+static const struct file_operations briq_panel_fops = {
.owner = THIS_MODULE,
.read = briq_panel_read,
.write = briq_panel_write,
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c
index 3ffa0807754..54df35527bc 100644
--- a/drivers/char/cyclades.c
+++ b/drivers/char/cyclades.c
@@ -829,17 +829,18 @@ static unsigned short cy_pci_nboard;
static unsigned short cy_isa_nboard;
static unsigned short cy_nboard;
#ifdef CONFIG_PCI
-static unsigned short cy_pci_dev_id[] = {
- PCI_DEVICE_ID_CYCLOM_Y_Lo, /* PCI < 1Mb */
- PCI_DEVICE_ID_CYCLOM_Y_Hi, /* PCI > 1Mb */
- PCI_DEVICE_ID_CYCLOM_4Y_Lo, /* 4Y PCI < 1Mb */
- PCI_DEVICE_ID_CYCLOM_4Y_Hi, /* 4Y PCI > 1Mb */
- PCI_DEVICE_ID_CYCLOM_8Y_Lo, /* 8Y PCI < 1Mb */
- PCI_DEVICE_ID_CYCLOM_8Y_Hi, /* 8Y PCI > 1Mb */
- PCI_DEVICE_ID_CYCLOM_Z_Lo, /* Z PCI < 1Mb */
- PCI_DEVICE_ID_CYCLOM_Z_Hi, /* Z PCI > 1Mb */
- 0 /* end of table */
+static struct pci_device_id cy_pci_dev_id[] __devinitdata = {
+ { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Y_Lo) }, /* PCI < 1Mb */
+ { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Y_Hi) }, /* PCI > 1Mb */
+ { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_4Y_Lo) }, /* 4Y PCI < 1Mb */
+ { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_4Y_Hi) }, /* 4Y PCI > 1Mb */
+ { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_8Y_Lo) }, /* 8Y PCI < 1Mb */
+ { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_8Y_Hi) }, /* 8Y PCI > 1Mb */
+ { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Z_Lo) }, /* Z PCI < 1Mb */
+ { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Z_Hi) }, /* Z PCI > 1Mb */
+ { } /* end of table */
};
+MODULE_DEVICE_TABLE(pci, cy_pci_dev_id);
#endif
static void cy_start(struct tty_struct *);
@@ -4488,7 +4489,6 @@ static void cy_flush_buffer(struct tty_struct *tty)
CY_UNLOCK(info, flags);
}
tty_wakeup(tty);
- wake_up_interruptible(&tty->write_wait);
} /* cy_flush_buffer */
/*
@@ -4759,7 +4759,7 @@ static int __init cy_detect_pci(void)
for (i = 0; i < NR_CARDS; i++) {
/* look for a Cyclades card by vendor and device id */
- while ((device_id = cy_pci_dev_id[dev_index]) != 0) {
+ while ((device_id = cy_pci_dev_id[dev_index].device) != 0) {
if ((pdev = pci_get_device(PCI_VENDOR_ID_CYCLADES,
device_id, pdev)) == NULL) {
dev_index++; /* try next device id */
diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h
index 6dcdceb8120..85d99e21e18 100644
--- a/drivers/char/drm/drmP.h
+++ b/drivers/char/drm/drmP.h
@@ -532,11 +532,13 @@ typedef struct drm_mm_node {
int free;
unsigned long start;
unsigned long size;
+ struct drm_mm *mm;
void *private;
} drm_mm_node_t;
typedef struct drm_mm {
- drm_mm_node_t root_node;
+ struct list_head fl_entry;
+ struct list_head ml_entry;
} drm_mm_t;
/**
@@ -843,9 +845,6 @@ extern void drm_mem_init(void);
extern int drm_mem_info(char *buf, char **start, off_t offset,
int request, int *eof, void *data);
extern void *drm_realloc(void *oldpt, size_t oldsize, size_t size, int area);
-extern void *drm_ioremap(unsigned long offset, unsigned long size,
- drm_device_t * dev);
-extern void drm_ioremapfree(void *pt, unsigned long size, drm_device_t * dev);
extern DRM_AGP_MEM *drm_alloc_agp(drm_device_t * dev, int pages, u32 type);
extern int drm_free_agp(DRM_AGP_MEM * handle, int pages);
@@ -1053,33 +1052,18 @@ extern void drm_sysfs_device_remove(struct class_device *class_dev);
extern drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent,
unsigned long size,
unsigned alignment);
-extern void drm_mm_put_block(drm_mm_t *mm, drm_mm_node_t *cur);
+void drm_mm_put_block(drm_mm_node_t * cur);
extern drm_mm_node_t *drm_mm_search_free(const drm_mm_t *mm, unsigned long size,
unsigned alignment, int best_match);
extern int drm_mm_init(drm_mm_t *mm, unsigned long start, unsigned long size);
extern void drm_mm_takedown(drm_mm_t *mm);
+extern int drm_mm_clean(drm_mm_t *mm);
+extern unsigned long drm_mm_tail_space(drm_mm_t *mm);
+extern int drm_mm_remove_space_from_tail(drm_mm_t *mm, unsigned long size);
+extern int drm_mm_add_space_to_tail(drm_mm_t *mm, unsigned long size);
-/* Inline replacements for DRM_IOREMAP macros */
-static __inline__ void drm_core_ioremap(struct drm_map *map,
- struct drm_device *dev)
-{
- map->handle = drm_ioremap(map->offset, map->size, dev);
-}
-
-#if 0
-static __inline__ void drm_core_ioremap_nocache(struct drm_map *map,
- struct drm_device *dev)
-{
- map->handle = drm_ioremap_nocache(map->offset, map->size, dev);
-}
-#endif /* 0 */
-
-static __inline__ void drm_core_ioremapfree(struct drm_map *map,
- struct drm_device *dev)
-{
- if (map->handle && map->size)
- drm_ioremapfree(map->handle, map->size, dev);
-}
+extern void drm_core_ioremap(struct drm_map *map, struct drm_device *dev);
+extern void drm_core_ioremapfree(struct drm_map *map, struct drm_device *dev);
static __inline__ struct drm_map *drm_core_findmap(struct drm_device *dev,
unsigned int token)
diff --git a/drivers/char/drm/drm_bufs.c b/drivers/char/drm/drm_bufs.c
index 9f65f5697ba..a6828cc14e5 100644
--- a/drivers/char/drm/drm_bufs.c
+++ b/drivers/char/drm/drm_bufs.c
@@ -79,14 +79,14 @@ static int drm_map_handle(drm_device_t *dev, drm_hash_item_t *hash,
if (!use_hashed_handle) {
int ret;
- hash->key = user_token;
+ hash->key = user_token >> PAGE_SHIFT;
ret = drm_ht_insert_item(&dev->map_hash, hash);
if (ret != -EINVAL)
return ret;
}
return drm_ht_just_insert_please(&dev->map_hash, hash,
user_token, 32 - PAGE_SHIFT - 3,
- PAGE_SHIFT, DRM_MAP_HASH_OFFSET);
+ 0, DRM_MAP_HASH_OFFSET >> PAGE_SHIFT);
}
/**
@@ -178,11 +178,11 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset,
}
}
if (map->type == _DRM_REGISTERS)
- map->handle = drm_ioremap(map->offset, map->size, dev);
+ map->handle = ioremap(map->offset, map->size);
break;
case _DRM_SHM:
- map->handle = vmalloc_32(map->size);
+ map->handle = vmalloc_user(map->size);
DRM_DEBUG("%lu %d %p\n",
map->size, drm_order(map->size), map->handle);
if (!map->handle) {
@@ -238,7 +238,7 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset,
list = drm_alloc(sizeof(*list), DRM_MEM_MAPS);
if (!list) {
if (map->type == _DRM_REGISTERS)
- drm_ioremapfree(map->handle, map->size, dev);
+ iounmap(map->handle);
drm_free(map, sizeof(*map), DRM_MEM_MAPS);
return -EINVAL;
}
@@ -255,14 +255,14 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset,
ret = drm_map_handle(dev, &list->hash, user_token, 0);
if (ret) {
if (map->type == _DRM_REGISTERS)
- drm_ioremapfree(map->handle, map->size, dev);
+ iounmap(map->handle);
drm_free(map, sizeof(*map), DRM_MEM_MAPS);
drm_free(list, sizeof(*list), DRM_MEM_MAPS);
mutex_unlock(&dev->struct_mutex);
return ret;
}
- list->user_token = list->hash.key;
+ list->user_token = list->hash.key << PAGE_SHIFT;
mutex_unlock(&dev->struct_mutex);
*maplist = list;
@@ -347,7 +347,8 @@ int drm_rmmap_locked(drm_device_t *dev, drm_local_map_t *map)
if (r_list->map == map) {
list_del(list);
- drm_ht_remove_key(&dev->map_hash, r_list->user_token);
+ drm_ht_remove_key(&dev->map_hash,
+ r_list->user_token >> PAGE_SHIFT);
drm_free(list, sizeof(*list), DRM_MEM_MAPS);
break;
}
@@ -362,7 +363,7 @@ int drm_rmmap_locked(drm_device_t *dev, drm_local_map_t *map)
switch (map->type) {
case _DRM_REGISTERS:
- drm_ioremapfree(map->handle, map->size, dev);
+ iounmap(map->handle);
/* FALLTHROUGH */
case _DRM_FRAME_BUFFER:
if (drm_core_has_MTRR(dev) && map->mtrr >= 0) {
diff --git a/drivers/char/drm/drm_drv.c b/drivers/char/drm/drm_drv.c
index a70af0de445..f5b9b2480c1 100644
--- a/drivers/char/drm/drm_drv.c
+++ b/drivers/char/drm/drm_drv.c
@@ -371,7 +371,7 @@ void drm_exit(struct drm_driver *driver)
EXPORT_SYMBOL(drm_exit);
/** File operations structure */
-static struct file_operations drm_stub_fops = {
+static const struct file_operations drm_stub_fops = {
.owner = THIS_MODULE,
.open = drm_stub_open
};
diff --git a/drivers/char/drm/drm_memory.c b/drivers/char/drm/drm_memory.c
index 5681cae1d40..92a86708237 100644
--- a/drivers/char/drm/drm_memory.c
+++ b/drivers/char/drm/drm_memory.c
@@ -79,28 +79,6 @@ void *drm_realloc(void *oldpt, size_t oldsize, size_t size, int area)
}
#if __OS_HAS_AGP
-/*
- * Find the drm_map that covers the range [offset, offset+size).
- */
-static drm_map_t *drm_lookup_map(unsigned long offset,
- unsigned long size, drm_device_t * dev)
-{
- struct list_head *list;
- drm_map_list_t *r_list;
- drm_map_t *map;
-
- list_for_each(list, &dev->maplist->head) {
- r_list = (drm_map_list_t *) list;
- map = r_list->map;
- if (!map)
- continue;
- if (map->offset <= offset
- && (offset + size) <= (map->offset + map->size))
- return map;
- }
- return NULL;
-}
-
static void *agp_remap(unsigned long offset, unsigned long size,
drm_device_t * dev)
{
@@ -169,13 +147,6 @@ int drm_unbind_agp(DRM_AGP_MEM * handle)
}
#else /* __OS_HAS_AGP */
-
-static inline drm_map_t *drm_lookup_map(unsigned long offset,
- unsigned long size, drm_device_t * dev)
-{
- return NULL;
-}
-
static inline void *agp_remap(unsigned long offset, unsigned long size,
drm_device_t * dev)
{
@@ -184,57 +155,28 @@ static inline void *agp_remap(unsigned long offset, unsigned long size,
#endif /* agp */
-void *drm_ioremap(unsigned long offset, unsigned long size,
- drm_device_t * dev)
-{
- if (drm_core_has_AGP(dev) && dev->agp && dev->agp->cant_use_aperture) {
- drm_map_t *map = drm_lookup_map(offset, size, dev);
-
- if (map && map->type == _DRM_AGP)
- return agp_remap(offset, size, dev);
- }
- return ioremap(offset, size);
-}
-EXPORT_SYMBOL(drm_ioremap);
+#endif /* debug_memory */
-#if 0
-void *drm_ioremap_nocache(unsigned long offset,
- unsigned long size, drm_device_t * dev)
+void drm_core_ioremap(struct drm_map *map, struct drm_device *dev)
{
- if (drm_core_has_AGP(dev) && dev->agp && dev->agp->cant_use_aperture) {
- drm_map_t *map = drm_lookup_map(offset, size, dev);
-
- if (map && map->type == _DRM_AGP)
- return agp_remap(offset, size, dev);
- }
- return ioremap_nocache(offset, size);
+ if (drm_core_has_AGP(dev) &&
+ dev->agp && dev->agp->cant_use_aperture && map->type == _DRM_AGP)
+ map->handle = agp_remap(map->offset, map->size, dev);
+ else
+ map->handle = ioremap(map->offset, map->size);
}
-#endif /* 0 */
+EXPORT_SYMBOL(drm_core_ioremap);
-void drm_ioremapfree(void *pt, unsigned long size,
- drm_device_t * dev)
+void drm_core_ioremapfree(struct drm_map *map, struct drm_device *dev)
{
- /*
- * This is a bit ugly. It would be much cleaner if the DRM API would use separate
- * routines for handling mappings in the AGP space. Hopefully this can be done in
- * a future revision of the interface...
- */
- if (drm_core_has_AGP(dev) && dev->agp && dev->agp->cant_use_aperture
- && ((unsigned long)pt >= VMALLOC_START
- && (unsigned long)pt < VMALLOC_END)) {
- unsigned long offset;
- drm_map_t *map;
-
- offset = drm_follow_page(pt) | ((unsigned long)pt & ~PAGE_MASK);
- map = drm_lookup_map(offset, size, dev);
- if (map && map->type == _DRM_AGP) {
- vunmap(pt);
- return;
- }
- }
-
- iounmap(pt);
+ if (!map->handle || !map->size)
+ return;
+
+ if (drm_core_has_AGP(dev) &&
+ dev->agp && dev->agp->cant_use_aperture && map->type == _DRM_AGP)
+ vunmap(map->handle);
+ else
+ iounmap(map->handle);
}
-EXPORT_SYMBOL(drm_ioremapfree);
+EXPORT_SYMBOL(drm_core_ioremapfree);
-#endif /* debug_memory */
diff --git a/drivers/char/drm/drm_memory.h b/drivers/char/drm/drm_memory.h
index f1b97aff10c..63e425b5ea8 100644
--- a/drivers/char/drm/drm_memory.h
+++ b/drivers/char/drm/drm_memory.h
@@ -56,26 +56,6 @@
# endif
#endif
-static inline unsigned long drm_follow_page(void *vaddr)
-{
- pgd_t *pgd = pgd_offset_k((unsigned long)vaddr);
- pud_t *pud = pud_offset(pgd, (unsigned long)vaddr);
- pmd_t *pmd = pmd_offset(pud, (unsigned long)vaddr);
- pte_t *ptep = pte_offset_kernel(pmd, (unsigned long)vaddr);
- return pte_pfn(*ptep) << PAGE_SHIFT;
-}
-
#else /* __OS_HAS_AGP */
-static inline unsigned long drm_follow_page(void *vaddr)
-{
- return 0;
-}
-
#endif
-
-void *drm_ioremap(unsigned long offset, unsigned long size,
- drm_device_t * dev);
-
-void drm_ioremapfree(void *pt, unsigned long size,
- drm_device_t * dev);
diff --git a/drivers/char/drm/drm_memory_debug.h b/drivers/char/drm/drm_memory_debug.h
index 74581af806e..6463271deea 100644
--- a/drivers/char/drm/drm_memory_debug.h
+++ b/drivers/char/drm/drm_memory_debug.h
@@ -205,76 +205,6 @@ void drm_free (void *pt, size_t size, int area) {
}
}
-void *drm_ioremap (unsigned long offset, unsigned long size,
- drm_device_t * dev) {
- void *pt;
-
- if (!size) {
- DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
- "Mapping 0 bytes at 0x%08lx\n", offset);
- return NULL;
- }
-
- if (!(pt = drm_ioremap(offset, size, dev))) {
- spin_lock(&drm_mem_lock);
- ++drm_mem_stats[DRM_MEM_MAPPINGS].fail_count;
- spin_unlock(&drm_mem_lock);
- return NULL;
- }
- spin_lock(&drm_mem_lock);
- ++drm_mem_stats[DRM_MEM_MAPPINGS].succeed_count;
- drm_mem_stats[DRM_MEM_MAPPINGS].bytes_allocated += size;
- spin_unlock(&drm_mem_lock);
- return pt;
-}
-
-#if 0
-void *drm_ioremap_nocache (unsigned long offset, unsigned long size,
- drm_device_t * dev) {
- void *pt;
-
- if (!size) {
- DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
- "Mapping 0 bytes at 0x%08lx\n", offset);
- return NULL;
- }
-
- if (!(pt = drm_ioremap_nocache(offset, size, dev))) {
- spin_lock(&drm_mem_lock);
- ++drm_mem_stats[DRM_MEM_MAPPINGS].fail_count;
- spin_unlock(&drm_mem_lock);
- return NULL;
- }
- spin_lock(&drm_mem_lock);
- ++drm_mem_stats[DRM_MEM_MAPPINGS].succeed_count;
- drm_mem_stats[DRM_MEM_MAPPINGS].bytes_allocated += size;
- spin_unlock(&drm_mem_lock);
- return pt;
-}
-#endif /* 0 */
-
-void drm_ioremapfree (void *pt, unsigned long size, drm_device_t * dev) {
- int alloc_count;
- int free_count;
-
- if (!pt)
- DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
- "Attempt to free NULL pointer\n");
- else
- drm_ioremapfree(pt, size, dev);
-
- spin_lock(&drm_mem_lock);
- drm_mem_stats[DRM_MEM_MAPPINGS].bytes_freed += size;
- free_count = ++drm_mem_stats[DRM_MEM_MAPPINGS].free_count;
- alloc_count = drm_mem_stats[DRM_MEM_MAPPINGS].succeed_count;
- spin_unlock(&drm_mem_lock);
- if (free_count > alloc_count) {
- DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
- "Excess frees: %d frees, %d allocs\n",
- free_count, alloc_count);
- }
-}
-
#if __OS_HAS_AGP
DRM_AGP_MEM *drm_alloc_agp (drm_device_t *dev, int pages, u32 type) {
diff --git a/drivers/char/drm/drm_mm.c b/drivers/char/drm/drm_mm.c
index 617526bd5b0..9b46b85027d 100644
--- a/drivers/char/drm/drm_mm.c
+++ b/drivers/char/drm/drm_mm.c
@@ -42,36 +42,131 @@
*/
#include "drmP.h"
+#include <linux/slab.h>
+
+unsigned long drm_mm_tail_space(drm_mm_t *mm)
+{
+ struct list_head *tail_node;
+ drm_mm_node_t *entry;
+
+ tail_node = mm->ml_entry.prev;
+ entry = list_entry(tail_node, drm_mm_node_t, ml_entry);
+ if (!entry->free)
+ return 0;
+
+ return entry->size;
+}
+
+int drm_mm_remove_space_from_tail(drm_mm_t *mm, unsigned long size)
+{
+ struct list_head *tail_node;
+ drm_mm_node_t *entry;
+
+ tail_node = mm->ml_entry.prev;
+ entry = list_entry(tail_node, drm_mm_node_t, ml_entry);
+ if (!entry->free)
+ return -ENOMEM;
+
+ if (entry->size <= size)
+ return -ENOMEM;
+
+ entry->size -= size;
+ return 0;
+}
+
+
+static int drm_mm_create_tail_node(drm_mm_t *mm,
+ unsigned long start,
+ unsigned long size)
+{
+ drm_mm_node_t *child;
+
+ child = (drm_mm_node_t *)
+ drm_alloc(sizeof(*child), DRM_MEM_MM);
+ if (!child)
+ return -ENOMEM;
+
+ child->free = 1;
+ child->size = size;
+ child->start = start;
+ child->mm = mm;
+
+ list_add_tail(&child->ml_entry, &mm->ml_entry);
+ list_add_tail(&child->fl_entry, &mm->fl_entry);
+
+ return 0;
+}
+
+
+int drm_mm_add_space_to_tail(drm_mm_t *mm, unsigned long size)
+{
+ struct list_head *tail_node;
+ drm_mm_node_t *entry;
+
+ tail_node = mm->ml_entry.prev;
+ entry = list_entry(tail_node, drm_mm_node_t, ml_entry);
+ if (!entry->free) {
+ return drm_mm_create_tail_node(mm, entry->start + entry->size, size);
+ }
+ entry->size += size;
+ return 0;
+}
+
+static drm_mm_node_t *drm_mm_split_at_start(drm_mm_node_t *parent,
+ unsigned long size)
+{
+ drm_mm_node_t *child;
+
+ child = (drm_mm_node_t *)
+ drm_alloc(sizeof(*child), DRM_MEM_MM);
+ if (!child)
+ return NULL;
+
+ INIT_LIST_HEAD(&child->fl_entry);
+
+ child->free = 0;
+ child->size = size;
+ child->start = parent->start;
+ child->mm = parent->mm;
+
+ list_add_tail(&child->ml_entry, &parent->ml_entry);
+ INIT_LIST_HEAD(&child->fl_entry);
+
+ parent->size -= size;
+ parent->start += size;
+ return child;
+}
+
+
drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent,
unsigned long size, unsigned alignment)
{
+ drm_mm_node_t *align_splitoff = NULL;
drm_mm_node_t *child;
+ unsigned tmp = 0;
if (alignment)
- size += alignment - 1;
+ tmp = parent->start % alignment;
+
+ if (tmp) {
+ align_splitoff = drm_mm_split_at_start(parent, alignment - tmp);
+ if (!align_splitoff)
+ return NULL;
+ }
if (parent->size == size) {
list_del_init(&parent->fl_entry);
parent->free = 0;
return parent;
} else {
- child = (drm_mm_node_t *) drm_alloc(sizeof(*child), DRM_MEM_MM);
- if (!child)
- return NULL;
-
- INIT_LIST_HEAD(&child->ml_entry);
- INIT_LIST_HEAD(&child->fl_entry);
+ child = drm_mm_split_at_start(parent, size);
+ }
- child->free = 0;
- child->size = size;
- child->start = parent->start;
+ if (align_splitoff)
+ drm_mm_put_block(align_splitoff);
- list_add_tail(&child->ml_entry, &parent->ml_entry);
- parent->size -= size;
- parent->start += size;
- }
return child;
}
@@ -80,12 +175,12 @@ drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent,
* Otherwise add to the free stack.
*/
-void drm_mm_put_block(drm_mm_t * mm, drm_mm_node_t * cur)
+void drm_mm_put_block(drm_mm_node_t * cur)
{
- drm_mm_node_t *list_root = &mm->root_node;
+ drm_mm_t *mm = cur->mm;
struct list_head *cur_head = &cur->ml_entry;
- struct list_head *root_head = &list_root->ml_entry;
+ struct list_head *root_head = &mm->ml_entry;
drm_mm_node_t *prev_node = NULL;
drm_mm_node_t *next_node;
@@ -116,7 +211,7 @@ void drm_mm_put_block(drm_mm_t * mm, drm_mm_node_t * cur)
}
if (!merged) {
cur->free = 1;
- list_add(&cur->fl_entry, &list_root->fl_entry);
+ list_add(&cur->fl_entry, &mm->fl_entry);
} else {
list_del(&cur->ml_entry);
drm_free(cur, sizeof(*cur), DRM_MEM_MM);
@@ -128,20 +223,30 @@ drm_mm_node_t *drm_mm_search_free(const drm_mm_t * mm,
unsigned alignment, int best_match)
{
struct list_head *list;
- const struct list_head *free_stack = &mm->root_node.fl_entry;
+ const struct list_head *free_stack = &mm->fl_entry;
drm_mm_node_t *entry;
drm_mm_node_t *best;
unsigned long best_size;
+ unsigned wasted;
best = NULL;
best_size = ~0UL;
- if (alignment)
- size += alignment - 1;
-
list_for_each(list, free_stack) {
entry = list_entry(list, drm_mm_node_t, fl_entry);
- if (entry->size >= size) {
+ wasted = 0;
+
+ if (entry->size < size)
+ continue;
+
+ if (alignment) {
+ register unsigned tmp = entry->start % alignment;
+ if (tmp)
+ wasted += alignment - tmp;
+ }
+
+
+ if (entry->size >= size + wasted) {
if (!best_match)
return entry;
if (size < best_size) {
@@ -154,40 +259,32 @@ drm_mm_node_t *drm_mm_search_free(const drm_mm_t * mm,
return best;
}
-int drm_mm_init(drm_mm_t * mm, unsigned long start, unsigned long size)
+int drm_mm_clean(drm_mm_t * mm)
{
- drm_mm_node_t *child;
-
- INIT_LIST_HEAD(&mm->root_node.ml_entry);
- INIT_LIST_HEAD(&mm->root_node.fl_entry);
- child = (drm_mm_node_t *) drm_alloc(sizeof(*child), DRM_MEM_MM);
- if (!child)
- return -ENOMEM;
-
- INIT_LIST_HEAD(&child->ml_entry);
- INIT_LIST_HEAD(&child->fl_entry);
+ struct list_head *head = &mm->ml_entry;
- child->start = start;
- child->size = size;
- child->free = 1;
+ return (head->next->next == head);
+}
- list_add(&child->fl_entry, &mm->root_node.fl_entry);
- list_add(&child->ml_entry, &mm->root_node.ml_entry);
+int drm_mm_init(drm_mm_t * mm, unsigned long start, unsigned long size)
+{
+ INIT_LIST_HEAD(&mm->ml_entry);
+ INIT_LIST_HEAD(&mm->fl_entry);
- return 0;
+ return drm_mm_create_tail_node(mm, start, size);
}
EXPORT_SYMBOL(drm_mm_init);
void drm_mm_takedown(drm_mm_t * mm)
{
- struct list_head *bnode = mm->root_node.fl_entry.next;
+ struct list_head *bnode = mm->fl_entry.next;
drm_mm_node_t *entry;
entry = list_entry(bnode, drm_mm_node_t, fl_entry);
- if (entry->ml_entry.next != &mm->root_node.ml_entry ||
- entry->fl_entry.next != &mm->root_node.fl_entry) {
+ if (entry->ml_entry.next != &mm->ml_entry ||
+ entry->fl_entry.next != &mm->fl_entry) {
DRM_ERROR("Memory manager not clean. Delaying takedown\n");
return;
}
diff --git a/drivers/char/drm/drm_pciids.h b/drivers/char/drm/drm_pciids.h
index 09398d5fbd3..ad54b845978 100644
--- a/drivers/char/drm/drm_pciids.h
+++ b/drivers/char/drm/drm_pciids.h
@@ -226,12 +226,14 @@
{0x1106, 0x3022, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x1106, 0x3118, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VIA_PRO_GROUP_A}, \
{0x1106, 0x3122, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+ {0x1106, 0x7204, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x1106, 0x7205, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x1106, 0x3108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x1106, 0x3304, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x1106, 0x3157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x1106, 0x3344, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
- {0x1106, 0x7204, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+ {0x1106, 0x3343, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+ {0x1106, 0x3230, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VIA_DX9_0}, \
{0, 0, 0}
#define i810_PCI_IDS \
diff --git a/drivers/char/drm/drm_proc.c b/drivers/char/drm/drm_proc.c
index 62d5fe15f04..7fd0da71214 100644
--- a/drivers/char/drm/drm_proc.c
+++ b/drivers/char/drm/drm_proc.c
@@ -500,7 +500,7 @@ static int drm__vma_info(char *buf, char **start, off_t offset, int request,
for (pt = dev->vmalist; pt; pt = pt->next) {
if (!(vma = pt->vma))
continue;
- DRM_PROC_PRINT("\n%5d 0x%08lx-0x%08lx %c%c%c%c%c%c 0x%08lx",
+ DRM_PROC_PRINT("\n%5d 0x%08lx-0x%08lx %c%c%c%c%c%c 0x%08lx000",
pt->pid,
vma->vm_start,
vma->vm_end,
@@ -510,7 +510,7 @@ static int drm__vma_info(char *buf, char **start, off_t offset, int request,
vma->vm_flags & VM_MAYSHARE ? 's' : 'p',
vma->vm_flags & VM_LOCKED ? 'l' : '-',
vma->vm_flags & VM_IO ? 'i' : '-',
- vma->vm_pgoff << PAGE_SHIFT);
+ vma->vm_pgoff);
#if defined(__i386__)
pgprot = pgprot_val(vma->vm_page_prot);
diff --git a/drivers/char/drm/drm_sman.c b/drivers/char/drm/drm_sman.c
index 19c81d2e13d..e15db6d6bea 100644
--- a/drivers/char/drm/drm_sman.c
+++ b/drivers/char/drm/drm_sman.c
@@ -101,10 +101,9 @@ static void *drm_sman_mm_allocate(void *private, unsigned long size,
static void drm_sman_mm_free(void *private, void *ref)
{
- drm_mm_t *mm = (drm_mm_t *) private;
drm_mm_node_t *node = (drm_mm_node_t *) ref;
- drm_mm_put_block(mm, node);
+ drm_mm_put_block(node);
}
static void drm_sman_mm_destroy(void *private)
diff --git a/drivers/char/drm/drm_vm.c b/drivers/char/drm/drm_vm.c
index b9cfc077f6b..54a63284895 100644
--- a/drivers/char/drm/drm_vm.c
+++ b/drivers/char/drm/drm_vm.c
@@ -70,7 +70,7 @@ static __inline__ struct page *drm_do_vm_nopage(struct vm_area_struct *vma,
if (!dev->agp || !dev->agp->cant_use_aperture)
goto vm_nopage_error;
- if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff << PAGE_SHIFT, &hash))
+ if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff, &hash))
goto vm_nopage_error;
r_list = drm_hash_entry(hash, drm_map_list_t, hash);
@@ -227,7 +227,7 @@ static void drm_vm_shm_close(struct vm_area_struct *vma)
map->size);
DRM_DEBUG("mtrr_del = %d\n", retcode);
}
- drm_ioremapfree(map->handle, map->size, dev);
+ iounmap(map->handle);
break;
case _DRM_SHM:
vfree(map->handle);
@@ -463,8 +463,8 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma)
lock_kernel();
dev = priv->head->dev;
dma = dev->dma;
- DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n",
- vma->vm_start, vma->vm_end, vma->vm_pgoff << PAGE_SHIFT);
+ DRM_DEBUG("start = 0x%lx, end = 0x%lx, page offset = 0x%lx\n",
+ vma->vm_start, vma->vm_end, vma->vm_pgoff);
/* Length must match exact page count */
if (!dma || (length >> PAGE_SHIFT) != dma->page_count) {
@@ -537,8 +537,8 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
unsigned long offset = 0;
drm_hash_item_t *hash;
- DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n",
- vma->vm_start, vma->vm_end, vma->vm_pgoff << PAGE_SHIFT);
+ DRM_DEBUG("start = 0x%lx, end = 0x%lx, page offset = 0x%lx\n",
+ vma->vm_start, vma->vm_end, vma->vm_pgoff);
if (!priv->authenticated)
return -EACCES;
@@ -547,7 +547,7 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
* the AGP mapped at physical address 0
* --BenH.
*/
- if (!(vma->vm_pgoff << PAGE_SHIFT)
+ if (!vma->vm_pgoff
#if __OS_HAS_AGP
&& (!dev->agp
|| dev->agp->agp_info.device->vendor != PCI_VENDOR_ID_APPLE)
@@ -555,7 +555,7 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
)
return drm_mmap_dma(filp, vma);
- if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff << PAGE_SHIFT, &hash)) {
+ if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff, &hash)) {
DRM_ERROR("Could not find map\n");
return -EINVAL;
}
diff --git a/drivers/char/drm/ffb_context.c b/drivers/char/drm/ffb_context.c
index 1383727b443..ac9ab40d57a 100644
--- a/drivers/char/drm/ffb_context.c
+++ b/drivers/char/drm/ffb_context.c
@@ -7,7 +7,6 @@
* for authors.
*/
-#include <linux/sched.h>
#include <asm/upa.h>
#include "ffb.h"
diff --git a/drivers/char/drm/ffb_drv.c b/drivers/char/drm/ffb_drv.c
index dd45111a485..9a19879e3b6 100644
--- a/drivers/char/drm/ffb_drv.c
+++ b/drivers/char/drm/ffb_drv.c
@@ -9,7 +9,6 @@
#include "ffb_drv.h"
-#include <linux/sched.h>
#include <linux/smp_lock.h>
#include <asm/shmparam.h>
#include <asm/oplib.h>
diff --git a/drivers/char/drm/i810_dma.c b/drivers/char/drm/i810_dma.c
index fa2de70f740..603d17fd2d6 100644
--- a/drivers/char/drm/i810_dma.c
+++ b/drivers/char/drm/i810_dma.c
@@ -112,7 +112,7 @@ static int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma)
return 0;
}
-static struct file_operations i810_buffer_fops = {
+static const struct file_operations i810_buffer_fops = {
.open = drm_open,
.release = drm_release,
.ioctl = drm_ioctl,
@@ -219,8 +219,7 @@ static int i810_dma_cleanup(drm_device_t * dev)
(drm_i810_private_t *) dev->dev_private;
if (dev_priv->ring.virtual_start) {
- drm_ioremapfree((void *)dev_priv->ring.virtual_start,
- dev_priv->ring.Size, dev);
+ drm_core_ioremapfree(&dev_priv->ring.map, dev);
}
if (dev_priv->hw_status_page) {
pci_free_consistent(dev->pdev, PAGE_SIZE,
@@ -236,9 +235,9 @@ static int i810_dma_cleanup(drm_device_t * dev)
for (i = 0; i < dma->buf_count; i++) {
drm_buf_t *buf = dma->buflist[i];
drm_i810_buf_priv_t *buf_priv = buf->dev_private;
+
if (buf_priv->kernel_virtual && buf->total)
- drm_ioremapfree(buf_priv->kernel_virtual,
- buf->total, dev);
+ drm_core_ioremapfree(&buf_priv->map, dev);
}
}
return 0;
@@ -311,8 +310,15 @@ static int i810_freelist_init(drm_device_t * dev, drm_i810_private_t * dev_priv)
*buf_priv->in_use = I810_BUF_FREE;
- buf_priv->kernel_virtual = drm_ioremap(buf->bus_address,
- buf->total, dev);
+ buf_priv->map.offset = buf->bus_address;
+ buf_priv->map.size = buf->total;
+ buf_priv->map.type = _DRM_AGP;
+ buf_priv->map.flags = 0;
+ buf_priv->map.mtrr = 0;
+
+ drm_core_ioremap(&buf_priv->map, dev);
+ buf_priv->kernel_virtual = buf_priv->map.handle;
+
}
return 0;
}
@@ -363,18 +369,24 @@ static int i810_dma_initialize(drm_device_t * dev,
dev_priv->ring.End = init->ring_end;
dev_priv->ring.Size = init->ring_size;
- dev_priv->ring.virtual_start = drm_ioremap(dev->agp->base +
- init->ring_start,
- init->ring_size, dev);
+ dev_priv->ring.map.offset = dev->agp->base + init->ring_start;
+ dev_priv->ring.map.size = init->ring_size;
+ dev_priv->ring.map.type = _DRM_AGP;
+ dev_priv->ring.map.flags = 0;
+ dev_priv->ring.map.mtrr = 0;
- if (dev_priv->ring.virtual_start == NULL) {
+ drm_core_ioremap(&dev_priv->ring.map, dev);
+
+ if (dev_priv->ring.map.handle == NULL) {
dev->dev_private = (void *)dev_priv;
i810_dma_cleanup(dev);
DRM_ERROR("can not ioremap virtual address for"
" ring buffer\n");
- return -ENOMEM;
+ return DRM_ERR(ENOMEM);
}
+ dev_priv->ring.virtual_start = dev_priv->ring.map.handle;
+
dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
dev_priv->w = init->w;
diff --git a/drivers/char/drm/i810_drv.h b/drivers/char/drm/i810_drv.h
index e8cf3ff606f..e6df49f4928 100644
--- a/drivers/char/drm/i810_drv.h
+++ b/drivers/char/drm/i810_drv.h
@@ -61,6 +61,7 @@ typedef struct drm_i810_buf_priv {
int currently_mapped;
void *virtual;
void *kernel_virtual;
+ drm_local_map_t map;
} drm_i810_buf_priv_t;
typedef struct _drm_i810_ring_buffer {
@@ -72,6 +73,7 @@ typedef struct _drm_i810_ring_buffer {
int head;
int tail;
int space;
+ drm_local_map_t map;
} drm_i810_ring_buffer_t;
typedef struct drm_i810_private {
diff --git a/drivers/char/drm/i830_dma.c b/drivers/char/drm/i830_dma.c
index 4f0e5746ab3..3314a9fea9e 100644
--- a/drivers/char/drm/i830_dma.c
+++ b/drivers/char/drm/i830_dma.c
@@ -114,7 +114,7 @@ static int i830_mmap_buffers(struct file *filp, struct vm_area_struct *vma)
return 0;
}
-static struct file_operations i830_buffer_fops = {
+static const struct file_operations i830_buffer_fops = {
.open = drm_open,
.release = drm_release,
.ioctl = drm_ioctl,
@@ -223,8 +223,7 @@ static int i830_dma_cleanup(drm_device_t * dev)
(drm_i830_private_t *) dev->dev_private;
if (dev_priv->ring.virtual_start) {
- drm_ioremapfree((void *)dev_priv->ring.virtual_start,
- dev_priv->ring.Size, dev);
+ drm_core_ioremapfree(&dev_priv->ring.map, dev);
}
if (dev_priv->hw_status_page) {
pci_free_consistent(dev->pdev, PAGE_SIZE,
@@ -242,8 +241,7 @@ static int i830_dma_cleanup(drm_device_t * dev)
drm_buf_t *buf = dma->buflist[i];
drm_i830_buf_priv_t *buf_priv = buf->dev_private;
if (buf_priv->kernel_virtual && buf->total)
- drm_ioremapfree(buf_priv->kernel_virtual,
- buf->total, dev);
+ drm_core_ioremapfree(&buf_priv->map, dev);
}
}
return 0;
@@ -320,8 +318,14 @@ static int i830_freelist_init(drm_device_t * dev, drm_i830_private_t * dev_priv)
*buf_priv->in_use = I830_BUF_FREE;
- buf_priv->kernel_virtual = drm_ioremap(buf->bus_address,
- buf->total, dev);
+ buf_priv->map.offset = buf->bus_address;
+ buf_priv->map.size = buf->total;
+ buf_priv->map.type = _DRM_AGP;
+ buf_priv->map.flags = 0;
+ buf_priv->map.mtrr = 0;
+
+ drm_core_ioremap(&buf_priv->map, dev);
+ buf_priv->kernel_virtual = buf_priv->map.handle;
}
return 0;
}
@@ -373,18 +377,24 @@ static int i830_dma_initialize(drm_device_t * dev,
dev_priv->ring.End = init->ring_end;
dev_priv->ring.Size = init->ring_size;
- dev_priv->ring.virtual_start = drm_ioremap(dev->agp->base +
- init->ring_start,
- init->ring_size, dev);
+ dev_priv->ring.map.offset = dev->agp->base + init->ring_start;
+ dev_priv->ring.map.size = init->ring_size;
+ dev_priv->ring.map.type = _DRM_AGP;
+ dev_priv->ring.map.flags = 0;
+ dev_priv->ring.map.mtrr = 0;
+
+ drm_core_ioremap(&dev_priv->ring.map, dev);
- if (dev_priv->ring.virtual_start == NULL) {
+ if (dev_priv->ring.map.handle == NULL) {
dev->dev_private = (void *)dev_priv;
i830_dma_cleanup(dev);
DRM_ERROR("can not ioremap virtual address for"
" ring buffer\n");
- return -ENOMEM;
+ return DRM_ERR(ENOMEM);
}
+ dev_priv->ring.virtual_start = dev_priv->ring.map.handle;
+
dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
dev_priv->w = init->w;
diff --git a/drivers/char/drm/i830_drv.h b/drivers/char/drm/i830_drv.h
index 85bc5be6f91..e91f94afb4b 100644
--- a/drivers/char/drm/i830_drv.h
+++ b/drivers/char/drm/i830_drv.h
@@ -68,6 +68,7 @@ typedef struct drm_i830_buf_priv {
int currently_mapped;
void __user *virtual;
void *kernel_virtual;
+ drm_local_map_t map;
} drm_i830_buf_priv_t;
typedef struct _drm_i830_ring_buffer {
@@ -79,6 +80,7 @@ typedef struct _drm_i830_ring_buffer {
int head;
int tail;
int space;
+ drm_local_map_t map;
} drm_i830_ring_buffer_t;
typedef struct drm_i830_private {
diff --git a/drivers/char/drm/via_dma.c b/drivers/char/drm/via_dma.c
index a691ae74129..c0539c6299c 100644
--- a/drivers/char/drm/via_dma.c
+++ b/drivers/char/drm/via_dma.c
@@ -190,6 +190,11 @@ static int via_initialize(drm_device_t * dev,
return DRM_ERR(EFAULT);
}
+ if (dev_priv->chipset == VIA_DX9_0) {
+ DRM_ERROR("AGP DMA is not supported on this chip\n");
+ return DRM_ERR(EINVAL);
+ }
+
dev_priv->ring.map.offset = dev->agp->base + init->offset;
dev_priv->ring.map.size = init->size;
dev_priv->ring.map.type = 0;
@@ -480,6 +485,7 @@ static int via_hook_segment(drm_via_private_t * dev_priv,
VIA_WRITE(VIA_REG_TRANSET, (HC_ParaType_PreCR << 16));
VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_hi);
VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_lo);
+ VIA_READ(VIA_REG_TRANSPACE);
}
}
return paused;
@@ -557,8 +563,9 @@ static void via_cmdbuf_start(drm_via_private_t * dev_priv)
VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_hi);
VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_lo);
-
+ DRM_WRITEMEMORYBARRIER();
VIA_WRITE(VIA_REG_TRANSPACE, command | HC_HAGPCMNT_MASK);
+ VIA_READ(VIA_REG_TRANSPACE);
}
static void via_pad_cache(drm_via_private_t * dev_priv, int qwords)
diff --git a/drivers/char/drm/via_dmablit.c b/drivers/char/drm/via_dmablit.c
index 806f9ce5f47..2881a06b6f5 100644
--- a/drivers/char/drm/via_dmablit.c
+++ b/drivers/char/drm/via_dmablit.c
@@ -218,7 +218,9 @@ via_fire_dmablit(drm_device_t *dev, drm_via_sg_info_t *vsg, int engine)
VIA_WRITE(VIA_PCI_DMA_MR0 + engine*0x04, VIA_DMA_MR_CM | VIA_DMA_MR_TDIE);
VIA_WRITE(VIA_PCI_DMA_BCR0 + engine*0x10, 0);
VIA_WRITE(VIA_PCI_DMA_DPR0 + engine*0x10, vsg->chain_start);
+ DRM_WRITEMEMORYBARRIER();
VIA_WRITE(VIA_PCI_DMA_CSR0 + engine*0x04, VIA_DMA_CSR_DE | VIA_DMA_CSR_TS);
+ VIA_READ(VIA_PCI_DMA_CSR0 + engine*0x04);
}
/*
@@ -374,10 +376,8 @@ via_dmablit_handler(drm_device_t *dev, int engine, int from_irq)
blitq->cur = cur;
blitq->num_outstanding--;
blitq->end = jiffies + DRM_HZ;
- if (!timer_pending(&blitq->poll_timer)) {
- blitq->poll_timer.expires = jiffies+1;
- add_timer(&blitq->poll_timer);
- }
+ if (!timer_pending(&blitq->poll_timer))
+ mod_timer(&blitq->poll_timer, jiffies + 1);
} else {
if (timer_pending(&blitq->poll_timer)) {
del_timer(&blitq->poll_timer);
@@ -476,8 +476,7 @@ via_dmablit_timer(unsigned long data)
via_dmablit_handler(dev, engine, 0);
if (!timer_pending(&blitq->poll_timer)) {
- blitq->poll_timer.expires = jiffies+1;
- add_timer(&blitq->poll_timer);
+ mod_timer(&blitq->poll_timer, jiffies + 1);
/*
* Rerun handler to delete timer if engines are off, and
@@ -572,9 +571,8 @@ via_init_dmablit(drm_device_t *dev)
}
DRM_INIT_WAITQUEUE(&blitq->busy_queue);
INIT_WORK(&blitq->wq, via_dmablit_workqueue);
- init_timer(&blitq->poll_timer);
- blitq->poll_timer.function = &via_dmablit_timer;
- blitq->poll_timer.data = (unsigned long) blitq;
+ setup_timer(&blitq->poll_timer, via_dmablit_timer,
+ (unsigned long)blitq);
}
}
diff --git a/drivers/char/drm/via_drv.h b/drivers/char/drm/via_drv.h
index d21b5b75da0..8b8778d4a42 100644
--- a/drivers/char/drm/via_drv.h
+++ b/drivers/char/drm/via_drv.h
@@ -29,10 +29,10 @@
#define DRIVER_NAME "via"
#define DRIVER_DESC "VIA Unichrome / Pro"
-#define DRIVER_DATE "20060529"
+#define DRIVER_DATE "20061227"
#define DRIVER_MAJOR 2
-#define DRIVER_MINOR 10
+#define DRIVER_MINOR 11
#define DRIVER_PATCHLEVEL 0
#include "via_verifier.h"
@@ -79,7 +79,7 @@ typedef struct drm_via_private {
char pci_buf[VIA_PCI_BUF_SIZE];
const uint32_t *fire_offsets[VIA_FIRE_BUF_SIZE];
uint32_t num_fire_offsets;
- int pro_group_a;
+ int chipset;
drm_via_irq_t via_irqs[VIA_NUM_IRQS];
unsigned num_irqs;
maskarray_t *irq_masks;
@@ -96,8 +96,9 @@ typedef struct drm_via_private {
} drm_via_private_t;
enum via_family {
- VIA_OTHER = 0,
- VIA_PRO_GROUP_A,
+ VIA_OTHER = 0, /* Baseline */
+ VIA_PRO_GROUP_A, /* Another video engine and DMA commands */
+ VIA_DX9_0 /* Same video as pro_group_a, but 3D is unsupported */
};
/* VIA MMIO register access */
diff --git a/drivers/char/drm/via_irq.c b/drivers/char/drm/via_irq.c
index c33d068cde1..1ac5941ad23 100644
--- a/drivers/char/drm/via_irq.c
+++ b/drivers/char/drm/via_irq.c
@@ -258,12 +258,16 @@ void via_driver_irq_preinstall(drm_device_t * dev)
dev_priv->irq_enable_mask = VIA_IRQ_VBLANK_ENABLE;
dev_priv->irq_pending_mask = VIA_IRQ_VBLANK_PENDING;
- dev_priv->irq_masks = (dev_priv->pro_group_a) ?
- via_pro_group_a_irqs : via_unichrome_irqs;
- dev_priv->num_irqs = (dev_priv->pro_group_a) ?
- via_num_pro_group_a : via_num_unichrome;
- dev_priv->irq_map = (dev_priv->pro_group_a) ?
- via_irqmap_pro_group_a : via_irqmap_unichrome;
+ if (dev_priv->chipset == VIA_PRO_GROUP_A ||
+ dev_priv->chipset == VIA_DX9_0) {
+ dev_priv->irq_masks = via_pro_group_a_irqs;
+ dev_priv->num_irqs = via_num_pro_group_a;
+ dev_priv->irq_map = via_irqmap_pro_group_a;
+ } else {
+ dev_priv->irq_masks = via_unichrome_irqs;
+ dev_priv->num_irqs = via_num_unichrome;
+ dev_priv->irq_map = via_irqmap_unichrome;
+ }
for (i = 0; i < dev_priv->num_irqs; ++i) {
atomic_set(&cur_irq->irq_received, 0);
diff --git a/drivers/char/drm/via_map.c b/drivers/char/drm/via_map.c
index 782011e0a58..4e3fc072aa3 100644
--- a/drivers/char/drm/via_map.c
+++ b/drivers/char/drm/via_map.c
@@ -106,8 +106,7 @@ int via_driver_load(drm_device_t *dev, unsigned long chipset)
dev->dev_private = (void *)dev_priv;
- if (chipset == VIA_PRO_GROUP_A)
- dev_priv->pro_group_a = 1;
+ dev_priv->chipset = chipset;
ret = drm_sman_init(&dev_priv->sman, 2, 12, 8);
if (ret) {
diff --git a/drivers/char/drm/via_verifier.c b/drivers/char/drm/via_verifier.c
index 70c897c8876..2e7e0807828 100644
--- a/drivers/char/drm/via_verifier.c
+++ b/drivers/char/drm/via_verifier.c
@@ -306,6 +306,7 @@ static __inline__ int finish_current_sequence(drm_via_state_t * cur_seq)
unsigned long lo = ~0, hi = 0, tmp;
uint32_t *addr, *pitch, *height, tex;
unsigned i;
+ int npot;
if (end > 9)
end = 9;
@@ -316,12 +317,15 @@ static __inline__ int finish_current_sequence(drm_via_state_t * cur_seq)
&(cur_seq->t_addr[tex = cur_seq->texture][start]);
pitch = &(cur_seq->pitch[tex][start]);
height = &(cur_seq->height[tex][start]);
-
+ npot = cur_seq->tex_npot[tex];
for (i = start; i <= end; ++i) {
tmp = *addr++;
if (tmp < lo)
lo = tmp;
- tmp += (*height++ << *pitch++);
+ if (i == 0 && npot)
+ tmp += (*height++ * *pitch++);
+ else
+ tmp += (*height++ << *pitch++);
if (tmp > hi)
hi = tmp;
}
@@ -443,13 +447,21 @@ investigate_hazard(uint32_t cmd, hazard_t hz, drm_via_state_t * cur_seq)
return 0;
case check_texture_addr3:
cur_seq->unfinished = tex_address;
- tmp = ((cmd >> 24) - 0x2B);
- cur_seq->pitch[cur_seq->texture][tmp] =
- (cmd & 0x00F00000) >> 20;
- if (!tmp && (cmd & 0x000FFFFF)) {
- DRM_ERROR
- ("Unimplemented texture level 0 pitch mode.\n");
- return 2;
+ tmp = ((cmd >> 24) - HC_SubA_HTXnL0Pit);
+ if (tmp == 0 &&
+ (cmd & HC_HTXnEnPit_MASK)) {
+ cur_seq->pitch[cur_seq->texture][tmp] =
+ (cmd & HC_HTXnLnPit_MASK);
+ cur_seq->tex_npot[cur_seq->texture] = 1;
+ } else {
+ cur_seq->pitch[cur_seq->texture][tmp] =
+ (cmd & HC_HTXnLnPitE_MASK) >> HC_HTXnLnPitE_SHIFT;
+ cur_seq->tex_npot[cur_seq->texture] = 0;
+ if (cmd & 0x000FFFFF) {
+ DRM_ERROR
+ ("Unimplemented texture level 0 pitch mode.\n");
+ return 2;
+ }
}
return 0;
case check_texture_addr4:
@@ -961,7 +973,13 @@ via_verify_command_stream(const uint32_t * buf, unsigned int size,
uint32_t cmd;
const uint32_t *buf_end = buf + (size >> 2);
verifier_state_t state = state_command;
- int pro_group_a = dev_priv->pro_group_a;
+ int cme_video;
+ int supported_3d;
+
+ cme_video = (dev_priv->chipset == VIA_PRO_GROUP_A ||
+ dev_priv->chipset == VIA_DX9_0);
+
+ supported_3d = dev_priv->chipset != VIA_DX9_0;
hc_state->dev = dev;
hc_state->unfinished = no_sequence;
@@ -986,17 +1004,21 @@ via_verify_command_stream(const uint32_t * buf, unsigned int size,
state = via_check_vheader6(&buf, buf_end);
break;
case state_command:
- if (HALCYON_HEADER2 == (cmd = *buf))
+ if ((HALCYON_HEADER2 == (cmd = *buf)) &&
+ supported_3d)
state = state_header2;
else if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1)
state = state_header1;
- else if (pro_group_a
+ else if (cme_video
&& (cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5)
state = state_vheader5;
- else if (pro_group_a
+ else if (cme_video
&& (cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6)
state = state_vheader6;
- else {
+ else if ((cmd == HALCYON_HEADER2) && !supported_3d) {
+ DRM_ERROR("Accelerated 3D is not supported on this chipset yet.\n");
+ state = state_error;
+ } else {
DRM_ERROR
("Invalid / Unimplemented DMA HEADER command. 0x%x\n",
cmd);
diff --git a/drivers/char/drm/via_verifier.h b/drivers/char/drm/via_verifier.h
index 256590fcc22..b77f59df027 100644
--- a/drivers/char/drm/via_verifier.h
+++ b/drivers/char/drm/via_verifier.h
@@ -43,6 +43,7 @@ typedef struct {
uint32_t tex_level_lo[2];
uint32_t tex_level_hi[2];
uint32_t tex_palette_size[2];
+ uint32_t tex_npot[2];
drm_via_sequence_t unfinished;
int agp_texture;
int multitex;
diff --git a/drivers/char/ds1302.c b/drivers/char/ds1302.c
index bcdb107aa96..fada6ddefba 100644
--- a/drivers/char/ds1302.c
+++ b/drivers/char/ds1302.c
@@ -120,7 +120,6 @@ get_rtc_time(struct rtc_time *rtc_tm)
unsigned long flags;
local_irq_save(flags);
- local_irq_disable();
rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS);
rtc_tm->tm_min = CMOS_READ(RTC_MINUTES);
@@ -219,7 +218,6 @@ rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
BIN_TO_BCD(yrs);
local_irq_save(flags);
- local_irq_disable();
CMOS_WRITE(yrs, RTC_YEAR);
CMOS_WRITE(mon, RTC_MONTH);
CMOS_WRITE(day, RTC_DAY_OF_MONTH);
diff --git a/drivers/char/ds1620.c b/drivers/char/ds1620.c
index 48cb8f0e8eb..3d7efc26aad 100644
--- a/drivers/char/ds1620.c
+++ b/drivers/char/ds1620.c
@@ -3,7 +3,6 @@
* thermometer driver (as used in the Rebel.com NetWinder)
*/
#include <linux/module.h>
-#include <linux/sched.h>
#include <linux/miscdevice.h>
#include <linux/smp_lock.h>
#include <linux/delay.h>
diff --git a/drivers/char/dsp56k.c b/drivers/char/dsp56k.c
index 06f2dbf1771..db984e481d4 100644
--- a/drivers/char/dsp56k.c
+++ b/drivers/char/dsp56k.c
@@ -25,7 +25,6 @@
#include <linux/module.h>
#include <linux/slab.h> /* for kmalloc() and kfree() */
-#include <linux/sched.h> /* for struct wait_queue etc */
#include <linux/major.h>
#include <linux/types.h>
#include <linux/errno.h>
diff --git a/drivers/char/dtlk.c b/drivers/char/dtlk.c
index d4005e94fe5..d8dbdb91623 100644
--- a/drivers/char/dtlk.c
+++ b/drivers/char/dtlk.c
@@ -72,6 +72,7 @@
#define TRACE_RET ((void) 0)
#endif /* TRACING */
+static void dtlk_timer_tick(unsigned long data);
static int dtlk_major;
static int dtlk_port_lpc;
@@ -81,7 +82,7 @@ static int dtlk_has_indexing;
static unsigned int dtlk_portlist[] =
{0x25e, 0x29e, 0x2de, 0x31e, 0x35e, 0x39e, 0};
static wait_queue_head_t dtlk_process_list;
-static struct timer_list dtlk_timer;
+static DEFINE_TIMER(dtlk_timer, dtlk_timer_tick, 0, 0);
/* prototypes for file_operations struct */
static ssize_t dtlk_read(struct file *, char __user *,
@@ -117,7 +118,6 @@ static char dtlk_write_tts(char);
/*
static void dtlk_handle_error(char, char, unsigned int);
*/
-static void dtlk_timer_tick(unsigned long data);
static ssize_t dtlk_read(struct file *file, char __user *buf,
size_t count, loff_t * ppos)
@@ -318,7 +318,7 @@ static int dtlk_release(struct inode *inode, struct file *file)
}
TRACE_RET;
- del_timer(&dtlk_timer);
+ del_timer_sync(&dtlk_timer);
return 0;
}
@@ -336,8 +336,6 @@ static int __init dtlk_init(void)
if (dtlk_dev_probe() == 0)
printk(", MAJOR %d\n", dtlk_major);
- init_timer(&dtlk_timer);
- dtlk_timer.function = dtlk_timer_tick;
init_waitqueue_head(&dtlk_process_list);
return 0;
diff --git a/drivers/char/epca.c b/drivers/char/epca.c
index a0f822c9d74..88fc24fc439 100644
--- a/drivers/char/epca.c
+++ b/drivers/char/epca.c
@@ -844,7 +844,6 @@ static void pc_flush_buffer(struct tty_struct *tty)
fepcmd(ch, STOUT, (unsigned) tail, 0, 0, 0);
memoff(ch);
spin_unlock_irqrestore(&epca_lock, flags);
- wake_up_interruptible(&tty->write_wait);
tty_wakeup(tty);
} /* End pc_flush_buffer */
@@ -1795,7 +1794,6 @@ static void doevent(int crd)
{ /* Begin if LOWWAIT */
ch->statusflags &= ~LOWWAIT;
tty_wakeup(tty);
- wake_up_interruptible(&tty->write_wait);
} /* End if LOWWAIT */
} else if (event & EMPTYTX_IND) { /* Begin EMPTYTX_IND */
/* This event is generated by setup_empty_event */
@@ -1803,7 +1801,6 @@ static void doevent(int crd)
if (ch->statusflags & EMPTYWAIT) { /* Begin if EMPTYWAIT */
ch->statusflags &= ~EMPTYWAIT;
tty_wakeup(tty);
- wake_up_interruptible(&tty->write_wait);
} /* End if EMPTYWAIT */
} /* End EMPTYTX_IND */
} /* End if valid tty */
diff --git a/drivers/char/generic_nvram.c b/drivers/char/generic_nvram.c
index 43ff5981651..2398e864c28 100644
--- a/drivers/char/generic_nvram.c
+++ b/drivers/char/generic_nvram.c
@@ -117,7 +117,7 @@ static int nvram_ioctl(struct inode *inode, struct file *file,
return 0;
}
-struct file_operations nvram_fops = {
+const struct file_operations nvram_fops = {
.owner = THIS_MODULE,
.llseek = nvram_llseek,
.read = read_nvram,
diff --git a/drivers/char/generic_serial.c b/drivers/char/generic_serial.c
index e769811e741..337bbcdcf13 100644
--- a/drivers/char/generic_serial.c
+++ b/drivers/char/generic_serial.c
@@ -382,7 +382,6 @@ void gs_flush_buffer(struct tty_struct *tty)
port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
spin_unlock_irqrestore (&port->driver_lock, flags);
- wake_up_interruptible(&tty->write_wait);
tty_wakeup(tty);
func_exit ();
}
diff --git a/drivers/char/hangcheck-timer.c b/drivers/char/hangcheck-timer.c
index 1aa93a752a9..ae76a9ffe89 100644
--- a/drivers/char/hangcheck-timer.c
+++ b/drivers/char/hangcheck-timer.c
@@ -117,7 +117,7 @@ __setup("hcheck_reboot", hangcheck_parse_reboot);
__setup("hcheck_dump_tasks", hangcheck_parse_dump_tasks);
#endif /* not MODULE */
-#if defined(CONFIG_X86_64) || defined(CONFIG_S390)
+#if defined(CONFIG_S390)
# define HAVE_MONOTONIC
# define TIMER_FREQ 1000000000ULL
#elif defined(CONFIG_IA64)
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
index 20dc3be5ecf..0be700f4e8f 100644
--- a/drivers/char/hpet.c
+++ b/drivers/char/hpet.c
@@ -703,7 +703,7 @@ int hpet_control(struct hpet_task *tp, unsigned int cmd, unsigned long arg)
static ctl_table hpet_table[] = {
{
- .ctl_name = 1,
+ .ctl_name = CTL_UNNUMBERED,
.procname = "max-user-freq",
.data = &hpet_max_freq,
.maxlen = sizeof(int),
@@ -715,7 +715,7 @@ static ctl_table hpet_table[] = {
static ctl_table hpet_root[] = {
{
- .ctl_name = 1,
+ .ctl_name = CTL_UNNUMBERED,
.procname = "hpet",
.maxlen = 0,
.mode = 0555,
@@ -1018,7 +1018,7 @@ static int __init hpet_init(void)
if (result < 0)
return -ENODEV;
- sysctl_header = register_sysctl_table(dev_root, 0);
+ sysctl_header = register_sysctl_table(dev_root);
result = acpi_bus_register_driver(&hpet_acpi_driver);
if (result < 0) {
diff --git a/drivers/char/hvc_beat.c b/drivers/char/hvc_beat.c
new file mode 100644
index 00000000000..6f019f19be7
--- /dev/null
+++ b/drivers/char/hvc_beat.c
@@ -0,0 +1,134 @@
+/*
+ * Beat hypervisor console driver
+ *
+ * (C) Copyright 2006 TOSHIBA CORPORATION
+ *
+ * This code is based on drivers/char/hvc_rtas.c:
+ * (C) Copyright IBM Corporation 2001-2005
+ * (C) Copyright Red Hat, Inc. 2005
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under 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.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/string.h>
+#include <linux/console.h>
+#include <asm/prom.h>
+#include <asm/hvconsole.h>
+#include <asm/firmware.h>
+
+#include "hvc_console.h"
+
+extern int64_t beat_get_term_char(uint64_t, uint64_t *, uint64_t *, uint64_t *);
+extern int64_t beat_put_term_char(uint64_t, uint64_t, uint64_t, uint64_t);
+
+struct hvc_struct *hvc_beat_dev = NULL;
+
+/* bug: only one queue is available regardless of vtermno */
+static int hvc_beat_get_chars(uint32_t vtermno, char *buf, int cnt)
+{
+ static unsigned char q[sizeof(unsigned long) * 2]
+ __attribute__((aligned(sizeof(unsigned long))));
+ static int qlen = 0;
+ unsigned long got;
+
+again:
+ if (qlen) {
+ if (qlen > cnt) {
+ memcpy(buf, q, cnt);
+ qlen -= cnt;
+ memmove(q + cnt, q, qlen);
+ return cnt;
+ } else { /* qlen <= cnt */
+ int r;
+
+ memcpy(buf, q, qlen);
+ r = qlen;
+ qlen = 0;
+ return r;
+ }
+ }
+ if (beat_get_term_char(vtermno, &got,
+ ((unsigned long *)q), ((unsigned long *)q) + 1) == 0) {
+ qlen = got;
+ goto again;
+ }
+ return 0;
+}
+
+static int hvc_beat_put_chars(uint32_t vtermno, const char *buf, int cnt)
+{
+ unsigned long kb[2];
+ int rest, nlen;
+
+ for (rest = cnt; rest > 0; rest -= nlen) {
+ nlen = (rest > 16) ? 16 : rest;
+ memcpy(kb, buf, nlen);
+ beat_put_term_char(vtermno, rest, kb[0], kb[1]);
+ rest -= nlen;
+ }
+ return cnt;
+}
+
+static struct hv_ops hvc_beat_get_put_ops = {
+ .get_chars = hvc_beat_get_chars,
+ .put_chars = hvc_beat_put_chars,
+};
+
+static int hvc_beat_useit = 1;
+
+static int hvc_beat_config(char *p)
+{
+ hvc_beat_useit = simple_strtoul(p, NULL, 0);
+ return 0;
+}
+
+static int hvc_beat_console_init(void)
+{
+ if (hvc_beat_useit && machine_is_compatible("Beat")) {
+ hvc_instantiate(0, 0, &hvc_beat_get_put_ops);
+ }
+ return 0;
+}
+
+/* temp */
+static int hvc_beat_init(void)
+{
+ struct hvc_struct *hp;
+
+ if (!firmware_has_feature(FW_FEATURE_BEAT))
+ return -ENODEV;
+
+ hp = hvc_alloc(0, NO_IRQ, &hvc_beat_get_put_ops, 16);
+ if (IS_ERR(hp))
+ return PTR_ERR(hp);
+ hvc_beat_dev = hp;
+ return 0;
+}
+
+static void __exit hvc_beat_exit(void)
+{
+ if (hvc_beat_dev)
+ hvc_remove(hvc_beat_dev);
+}
+
+module_init(hvc_beat_init);
+module_exit(hvc_beat_exit);
+
+__setup("hvc_beat=", hvc_beat_config);
+
+console_initcall(hvc_beat_console_init);
diff --git a/drivers/char/hvsi.c b/drivers/char/hvsi.c
index d7806834fc1..50315d6364f 100644
--- a/drivers/char/hvsi.c
+++ b/drivers/char/hvsi.c
@@ -39,7 +39,6 @@
#include <linux/module.h>
#include <linux/major.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/sysrq.h>
#include <linux/tty.h>
diff --git a/drivers/char/hw_random/intel-rng.c b/drivers/char/hw_random/intel-rng.c
index f22e78e3c70..cc1046e6ee0 100644
--- a/drivers/char/hw_random/intel-rng.c
+++ b/drivers/char/hw_random/intel-rng.c
@@ -96,49 +96,49 @@
*/
static const struct pci_device_id pci_tbl[] = {
/* AA
- { 0x8086, 0x2418, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, */
- { 0x8086, 0x2410, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* AA */
+ { PCI_DEVICE(0x8086, 0x2418) }, */
+ { PCI_DEVICE(0x8086, 0x2410) }, /* AA */
/* AB
- { 0x8086, 0x2428, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, */
- { 0x8086, 0x2420, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* AB */
+ { PCI_DEVICE(0x8086, 0x2428) }, */
+ { PCI_DEVICE(0x8086, 0x2420) }, /* AB */
/* ??
- { 0x8086, 0x2430, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, */
+ { PCI_DEVICE(0x8086, 0x2430) }, */
/* BAM, CAM, DBM, FBM, GxM
- { 0x8086, 0x2448, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, */
- { 0x8086, 0x244c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* BAM */
- { 0x8086, 0x248c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* CAM */
- { 0x8086, 0x24cc, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* DBM */
- { 0x8086, 0x2641, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* FBM */
- { 0x8086, 0x27b9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* GxM */
- { 0x8086, 0x27bd, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* GxM DH */
+ { PCI_DEVICE(0x8086, 0x2448) }, */
+ { PCI_DEVICE(0x8086, 0x244c) }, /* BAM */
+ { PCI_DEVICE(0x8086, 0x248c) }, /* CAM */
+ { PCI_DEVICE(0x8086, 0x24cc) }, /* DBM */
+ { PCI_DEVICE(0x8086, 0x2641) }, /* FBM */
+ { PCI_DEVICE(0x8086, 0x27b9) }, /* GxM */
+ { PCI_DEVICE(0x8086, 0x27bd) }, /* GxM DH */
/* BA, CA, DB, Ex, 6300, Fx, 631x/632x, Gx
- { 0x8086, 0x244e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, */
- { 0x8086, 0x2440, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* BA */
- { 0x8086, 0x2480, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* CA */
- { 0x8086, 0x24c0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* DB */
- { 0x8086, 0x24d0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* Ex */
- { 0x8086, 0x25a1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 6300 */
- { 0x8086, 0x2640, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* Fx */
- { 0x8086, 0x2670, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
- { 0x8086, 0x2671, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
- { 0x8086, 0x2672, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
- { 0x8086, 0x2673, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
- { 0x8086, 0x2674, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
- { 0x8086, 0x2675, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
- { 0x8086, 0x2676, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
- { 0x8086, 0x2677, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
- { 0x8086, 0x2678, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
- { 0x8086, 0x2679, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
- { 0x8086, 0x267a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
- { 0x8086, 0x267b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
- { 0x8086, 0x267c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
- { 0x8086, 0x267d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
- { 0x8086, 0x267e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
- { 0x8086, 0x267f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
- { 0x8086, 0x27b8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* Gx */
+ { PCI_DEVICE(0x8086, 0x244e) }, */
+ { PCI_DEVICE(0x8086, 0x2440) }, /* BA */
+ { PCI_DEVICE(0x8086, 0x2480) }, /* CA */
+ { PCI_DEVICE(0x8086, 0x24c0) }, /* DB */
+ { PCI_DEVICE(0x8086, 0x24d0) }, /* Ex */
+ { PCI_DEVICE(0x8086, 0x25a1) }, /* 6300 */
+ { PCI_DEVICE(0x8086, 0x2640) }, /* Fx */
+ { PCI_DEVICE(0x8086, 0x2670) }, /* 631x/632x */
+ { PCI_DEVICE(0x8086, 0x2671) }, /* 631x/632x */
+ { PCI_DEVICE(0x8086, 0x2672) }, /* 631x/632x */
+ { PCI_DEVICE(0x8086, 0x2673) }, /* 631x/632x */
+ { PCI_DEVICE(0x8086, 0x2674) }, /* 631x/632x */
+ { PCI_DEVICE(0x8086, 0x2675) }, /* 631x/632x */
+ { PCI_DEVICE(0x8086, 0x2676) }, /* 631x/632x */
+ { PCI_DEVICE(0x8086, 0x2677) }, /* 631x/632x */
+ { PCI_DEVICE(0x8086, 0x2678) }, /* 631x/632x */
+ { PCI_DEVICE(0x8086, 0x2679) }, /* 631x/632x */
+ { PCI_DEVICE(0x8086, 0x267a) }, /* 631x/632x */
+ { PCI_DEVICE(0x8086, 0x267b) }, /* 631x/632x */
+ { PCI_DEVICE(0x8086, 0x267c) }, /* 631x/632x */
+ { PCI_DEVICE(0x8086, 0x267d) }, /* 631x/632x */
+ { PCI_DEVICE(0x8086, 0x267e) }, /* 631x/632x */
+ { PCI_DEVICE(0x8086, 0x267f) }, /* 631x/632x */
+ { PCI_DEVICE(0x8086, 0x27b8) }, /* Gx */
/* E
- { 0x8086, 0x245e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, */
- { 0x8086, 0x2450, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* E */
+ { PCI_DEVICE(0x8086, 0x245e) }, */
+ { PCI_DEVICE(0x8086, 0x2450) }, /* E */
{ 0, }, /* terminate list */
};
MODULE_DEVICE_TABLE(pci, pci_tbl);
diff --git a/drivers/char/ip2/i2lib.c b/drivers/char/ip2/i2lib.c
index 78045767ec3..e46120d05b6 100644
--- a/drivers/char/ip2/i2lib.c
+++ b/drivers/char/ip2/i2lib.c
@@ -150,6 +150,13 @@ i2Validate ( i2ChanStrPtr pCh )
== (CHANNEL_MAGIC | CHANNEL_SUPPORT));
}
+static void iiSendPendingMail_t(unsigned long data)
+{
+ i2eBordStrPtr pB = (i2eBordStrPtr)data;
+
+ iiSendPendingMail(pB);
+}
+
//******************************************************************************
// Function: iiSendPendingMail(pB)
// Parameters: Pointer to a board structure
@@ -159,7 +166,7 @@ i2Validate ( i2ChanStrPtr pCh )
// If any outgoing mail bits are set and there is outgoing mailbox is empty,
// send the mail and clear the bits.
//******************************************************************************
-static inline void
+static void
iiSendPendingMail(i2eBordStrPtr pB)
{
if (pB->i2eOutMailWaiting && (!pB->i2eWaitingForEmptyFifo) )
@@ -184,12 +191,9 @@ iiSendPendingMail(i2eBordStrPtr pB)
/\/\|=mhw=|\/\/ */
if( ++pB->SendPendingRetry < 16 ) {
-
- init_timer( &(pB->SendPendingTimer) );
- pB->SendPendingTimer.expires = jiffies + 1;
- pB->SendPendingTimer.function = (void*)(unsigned long)iiSendPendingMail;
- pB->SendPendingTimer.data = (unsigned long)pB;
- add_timer( &(pB->SendPendingTimer) );
+ setup_timer(&pB->SendPendingTimer,
+ iiSendPendingMail_t, (unsigned long)pB);
+ mod_timer(&pB->SendPendingTimer, jiffies + 1);
} else {
printk( KERN_ERR "IP2: iiSendPendingMail unable to queue outbound mail\n" );
}
@@ -1265,8 +1269,10 @@ i2RetryFlushOutput(i2ChanStrPtr pCh)
// soon as all the data is completely sent.
//******************************************************************************
static void
-i2DrainWakeup(i2ChanStrPtr pCh)
+i2DrainWakeup(unsigned long d)
{
+ i2ChanStrPtr pCh = (i2ChanStrPtr)d;
+
ip2trace (CHANN, ITRC_DRAIN, 10, 1, pCh->BookmarkTimer.expires );
pCh->BookmarkTimer.expires = 0;
@@ -1292,14 +1298,12 @@ i2DrainOutput(i2ChanStrPtr pCh, int timeout)
}
if ((timeout > 0) && (pCh->BookmarkTimer.expires == 0 )) {
// One per customer (channel)
- init_timer( &(pCh->BookmarkTimer) );
- pCh->BookmarkTimer.expires = jiffies + timeout;
- pCh->BookmarkTimer.function = (void*)(unsigned long)i2DrainWakeup;
- pCh->BookmarkTimer.data = (unsigned long)pCh;
+ setup_timer(&pCh->BookmarkTimer, i2DrainWakeup,
+ (unsigned long)pCh);
ip2trace (CHANN, ITRC_DRAIN, 1, 1, pCh->BookmarkTimer.expires );
- add_timer( &(pCh->BookmarkTimer) );
+ mod_timer(&pCh->BookmarkTimer, jiffies + timeout);
}
i2QueueCommands( PTYPE_INLINE, pCh, -1, 1, CMD_BMARK_REQ );
@@ -1373,15 +1377,7 @@ ip2_owake( PTTY tp)
ip2trace (CHANN, ITRC_SICMD, 10, 2, tp->flags,
(1 << TTY_DO_WRITE_WAKEUP) );
- wake_up_interruptible ( &tp->write_wait );
- if ( ( tp->flags & (1 << TTY_DO_WRITE_WAKEUP) )
- && tp->ldisc.write_wakeup )
- {
- (tp->ldisc.write_wakeup) ( tp );
-
- ip2trace (CHANN, ITRC_SICMD, 11, 0 );
-
- }
+ tty_wakeup(tp);
}
static inline void
diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c
index 7c70310a49b..83c7258d358 100644
--- a/drivers/char/ip2/ip2main.c
+++ b/drivers/char/ip2/ip2main.c
@@ -1271,8 +1271,8 @@ static void do_input(struct work_struct *work)
// code duplicated from n_tty (ldisc)
static inline void isig(int sig, struct tty_struct *tty, int flush)
{
- if (tty->pgrp > 0)
- kill_pg(tty->pgrp, sig, 1);
+ if (tty->pgrp)
+ kill_pgrp(tty->pgrp, sig, 1);
if (flush || !L_NOFLSH(tty)) {
if ( tty->ldisc.flush_buffer )
tty->ldisc.flush_buffer(tty);
diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c
index ff2d052177c..c2aa44ee6eb 100644
--- a/drivers/char/ipmi/ipmi_devintf.c
+++ b/drivers/char/ipmi/ipmi_devintf.c
@@ -35,7 +35,6 @@
#include <linux/moduleparam.h>
#include <linux/errno.h>
#include <asm/system.h>
-#include <linux/sched.h>
#include <linux/poll.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index 53582b53da9..8e222f2b80c 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -34,7 +34,6 @@
#include <linux/module.h>
#include <linux/errno.h>
#include <asm/system.h>
-#include <linux/sched.h>
#include <linux/poll.h>
#include <linux/spinlock.h>
#include <linux/mutex.h>
@@ -406,13 +405,14 @@ static void clean_up_interface_data(ipmi_smi_t intf)
free_smi_msg_list(&intf->waiting_msgs);
free_recv_msg_list(&intf->waiting_events);
- /* Wholesale remove all the entries from the list in the
- * interface and wait for RCU to know that none are in use. */
+ /*
+ * Wholesale remove all the entries from the list in the
+ * interface and wait for RCU to know that none are in use.
+ */
mutex_lock(&intf->cmd_rcvrs_mutex);
- list_add_rcu(&list, &intf->cmd_rcvrs);
- list_del_rcu(&intf->cmd_rcvrs);
+ INIT_LIST_HEAD(&list);
+ list_splice_init_rcu(&intf->cmd_rcvrs, &list, synchronize_rcu);
mutex_unlock(&intf->cmd_rcvrs_mutex);
- synchronize_rcu();
list_for_each_entry_safe(rcvr, rcvr2, &list, link)
kfree(rcvr);
@@ -451,7 +451,7 @@ int ipmi_smi_watcher_register(struct ipmi_smi_watcher *watcher)
mutex_lock(&ipmi_interfaces_mutex);
/* Build a list of things to deliver. */
- list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
+ list_for_each_entry(intf, &ipmi_interfaces, link) {
if (intf->intf_num == -1)
continue;
e = kmalloc(sizeof(*e), GFP_KERNEL);
@@ -1886,7 +1886,6 @@ int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name,
kfree(entry);
rv = -ENOMEM;
} else {
- file->nlink = 1;
file->data = data;
file->read_proc = read_proc;
file->write_proc = write_proc;
@@ -2760,9 +2759,15 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
synchronize_rcu();
kref_put(&intf->refcount, intf_free);
} else {
- /* After this point the interface is legal to use. */
+ /*
+ * Keep memory order straight for RCU readers. Make
+ * sure everything else is committed to memory before
+ * setting intf_num to mark the interface valid.
+ */
+ smp_wmb();
intf->intf_num = i;
mutex_unlock(&ipmi_interfaces_mutex);
+ /* After this point the interface is legal to use. */
call_smi_watchers(i, intf->si_dev);
mutex_unlock(&smi_watchers_mutex);
}
@@ -3923,6 +3928,14 @@ static void send_panic_events(char *str)
/* Interface was not ready yet. */
continue;
+ /*
+ * intf_num is used as an marker to tell if the
+ * interface is valid. Thus we need a read barrier to
+ * make sure data fetched before checking intf_num
+ * won't be used.
+ */
+ smp_rmb();
+
/* First job here is to figure out where to send the
OEM events. There's no way in IPMI to send OEM
events using an event send command, so we have to
diff --git a/drivers/char/ipmi/ipmi_poweroff.c b/drivers/char/ipmi/ipmi_poweroff.c
index 9d23136e598..e02893b7b30 100644
--- a/drivers/char/ipmi/ipmi_poweroff.c
+++ b/drivers/char/ipmi/ipmi_poweroff.c
@@ -686,7 +686,7 @@ static int ipmi_poweroff_init (void)
printk(KERN_INFO PFX "Power cycle is enabled.\n");
#ifdef CONFIG_PROC_FS
- ipmi_table_header = register_sysctl_table(ipmi_root_table, 1);
+ ipmi_table_header = register_sysctl_table(ipmi_root_table);
if (!ipmi_table_header) {
printk(KERN_ERR PFX "Unable to register powercycle sysctl\n");
rv = -ENOMEM;
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index f1afd26a509..a7b33d2f599 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -1802,7 +1802,7 @@ static __devinit int try_init_acpi(struct SPMITable *spmi)
return -ENODEV;
}
- if (spmi->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
+ if (spmi->addr.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
addr_space = IPMI_MEM_ADDR_SPACE;
else
addr_space = IPMI_IO_ADDR_SPACE;
@@ -1848,19 +1848,19 @@ static __devinit int try_init_acpi(struct SPMITable *spmi)
info->irq_setup = NULL;
}
- if (spmi->addr.register_bit_width) {
+ if (spmi->addr.bit_width) {
/* A (hopefully) properly formed register bit width. */
- info->io.regspacing = spmi->addr.register_bit_width / 8;
+ info->io.regspacing = spmi->addr.bit_width / 8;
} else {
info->io.regspacing = DEFAULT_REGSPACING;
}
info->io.regsize = info->io.regspacing;
- info->io.regshift = spmi->addr.register_bit_offset;
+ info->io.regshift = spmi->addr.bit_offset;
- if (spmi->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
+ if (spmi->addr.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
info->io_setup = mem_setup;
info->io.addr_type = IPMI_IO_ADDR_SPACE;
- } else if (spmi->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
+ } else if (spmi->addr.space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
info->io_setup = port_setup;
info->io.addr_type = IPMI_MEM_ADDR_SPACE;
} else {
@@ -1888,10 +1888,8 @@ static __devinit void acpi_find_bmc(void)
return;
for (i = 0; ; i++) {
- status = acpi_get_firmware_table("SPMI", i+1,
- ACPI_LOGICAL_ADDRESSING,
- (struct acpi_table_header **)
- &spmi);
+ status = acpi_get_table(ACPI_SIG_SPMI, i+1,
+ (struct acpi_table_header **)&spmi);
if (status != AE_OK)
return;
diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c
index 01084abffdd..43ab9edc76f 100644
--- a/drivers/char/isicom.c
+++ b/drivers/char/isicom.c
@@ -183,7 +183,7 @@ static DEFINE_TIMER(tx, isicom_tx, 0, 0);
/* baud index mappings from linux defns to isi */
static signed char linuxb_to_isib[] = {
- -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 13, 15, 16, 17, 18, 19
+ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 13, 15, 16, 17, 18, 19, 20, 21
};
struct isi_board {
@@ -213,8 +213,6 @@ struct isi_port {
struct tty_struct * tty;
wait_queue_head_t close_wait;
wait_queue_head_t open_wait;
- struct work_struct hangup_tq;
- struct work_struct bh_tqueue;
unsigned char * xmit_buf;
int xmit_head;
int xmit_tail;
@@ -510,7 +508,7 @@ static void isicom_tx(unsigned long _data)
if (port->xmit_cnt <= 0)
port->status &= ~ISI_TXOK;
if (port->xmit_cnt <= WAKEUP_CHARS)
- schedule_work(&port->bh_tqueue);
+ tty_wakeup(tty);
unlock_card(&isi_card[card]);
}
@@ -524,21 +522,6 @@ sched_again:
mod_timer(&tx, jiffies + msecs_to_jiffies(10));
}
-/* Interrupt handlers */
-
-
-static void isicom_bottomhalf(struct work_struct *work)
-{
- struct isi_port *port = container_of(work, struct isi_port, bh_tqueue);
- struct tty_struct *tty = port->tty;
-
- if (!tty)
- return;
-
- tty_wakeup(tty);
- wake_up_interruptible(&tty->write_wait);
-}
-
/*
* Main interrupt handler routine
*/
@@ -557,6 +540,11 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
return IRQ_NONE;
base = card->base;
+
+ /* did the card interrupt us? */
+ if (!(inw(base + 0x0e) & 0x02))
+ return IRQ_NONE;
+
spin_lock(&card->card_lock);
/*
@@ -581,6 +569,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
port = card->ports + channel;
if (!(port->flags & ASYNC_INITIALIZED)) {
outw(0x0000, base+0x04); /* enable interrupts */
+ spin_unlock(&card->card_lock);
return IRQ_HANDLED;
}
@@ -609,7 +598,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
pr_dbg("interrupt: DCD->low.\n"
);
port->status &= ~ISI_DCD;
- schedule_work(&port->hangup_tq);
+ tty_hangup(tty);
}
} else if (header & ISI_DCD) {
/* Carrier has been detected */
@@ -631,7 +620,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
/* start tx ing */
port->status |= (ISI_TXOK
| ISI_CTS);
- schedule_work(&port->bh_tqueue);
+ tty_wakeup(tty);
}
} else if (!(header & ISI_CTS)) {
port->tty->hw_stopped = 1;
@@ -695,6 +684,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
tty_flip_buffer_push(tty);
}
outw(0x0000, base+0x04); /* enable interrupts */
+ spin_unlock(&card->card_lock);
return IRQ_HANDLED;
}
@@ -720,7 +710,8 @@ static void isicom_config_port(struct isi_port *port)
* respectively.
*/
- if (baud < 1 || baud > 2)
+ /* 1,2,3,4 => 57.6, 115.2, 230, 460 kbps resp. */
+ if (baud < 1 || baud > 4)
port->tty->termios->c_cflag &= ~CBAUDEX;
else
baud += 15;
@@ -736,6 +727,10 @@ static void isicom_config_port(struct isi_port *port)
baud++; /* 57.6 Kbps */
if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
baud +=2; /* 115 Kbps */
+ if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+ baud += 3; /* 230 kbps*/
+ if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+ baud += 4; /* 460 kbps*/
}
if (linuxb_to_isib[baud] == -1) {
/* hang up */
@@ -1460,17 +1455,6 @@ static void isicom_start(struct tty_struct *tty)
port->status |= ISI_TXOK;
}
-/* hangup et all */
-static void do_isicom_hangup(struct work_struct *work)
-{
- struct isi_port *port = container_of(work, struct isi_port, hangup_tq);
- struct tty_struct *tty;
-
- tty = port->tty;
- if (tty)
- tty_hangup(tty);
-}
-
static void isicom_hangup(struct tty_struct *tty)
{
struct isi_port *port = tty->driver_data;
@@ -1503,7 +1487,6 @@ static void isicom_flush_buffer(struct tty_struct *tty)
port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
spin_unlock_irqrestore(&card->card_lock, flags);
- wake_up_interruptible(&tty->write_wait);
tty_wakeup(tty);
}
@@ -1536,7 +1519,7 @@ static int __devinit reset_card(struct pci_dev *pdev,
{
struct isi_board *board = pci_get_drvdata(pdev);
unsigned long base = board->base;
- unsigned int portcount = 0;
+ unsigned int sig, portcount = 0;
int retval = 0;
dev_dbg(&pdev->dev, "ISILoad:Resetting Card%d at 0x%lx\n", card + 1,
@@ -1544,27 +1527,35 @@ static int __devinit reset_card(struct pci_dev *pdev,
inw(base + 0x8);
- mdelay(10);
+ msleep(10);
outw(0, base + 0x8); /* Reset */
- msleep(3000);
+ msleep(1000);
- *signature = inw(base + 0x4) & 0xff;
+ sig = inw(base + 0x4) & 0xff;
+
+ if (sig != 0xa5 && sig != 0xbb && sig != 0xcc && sig != 0xdd &&
+ sig != 0xee) {
+ dev_warn(&pdev->dev, "ISILoad:Card%u reset failure (Possible "
+ "bad I/O Port Address 0x%lx).\n", card + 1, base);
+ dev_dbg(&pdev->dev, "Sig=0x%x\n", sig);
+ retval = -EIO;
+ goto end;
+ }
+
+ msleep(10);
portcount = inw(base + 0x2);
- if (!(inw(base + 0xe) & 0x1) || ((portcount != 0) &&
- (portcount != 4) && (portcount != 8))) {
- dev_dbg(&pdev->dev, "base+0x2=0x%lx, base+0xe=0x%lx\n",
- inw(base + 0x2), inw(base + 0xe));
- dev_err(&pdev->dev, "ISILoad:PCI Card%d reset failure "
- "(Possible bad I/O Port Address 0x%lx).\n",
- card + 1, base);
+ if (!inw(base + 0xe) & 0x1 || (portcount != 0 && portcount != 4 &&
+ portcount != 8 && portcount != 16)) {
+ dev_err(&pdev->dev, "ISILoad:PCI Card%d reset failure.",
+ card + 1);
retval = -EIO;
goto end;
}
- switch (*signature) {
+ switch (sig) {
case 0xa5:
case 0xbb:
case 0xdd:
@@ -1572,16 +1563,13 @@ static int __devinit reset_card(struct pci_dev *pdev,
board->shift_count = 12;
break;
case 0xcc:
+ case 0xee:
board->port_count = 16;
board->shift_count = 11;
break;
- default:
- dev_warn(&pdev->dev, "ISILoad:Card%d reset failure (Possible "
- "bad I/O Port Address 0x%lx).\n", card + 1, base);
- dev_dbg(&pdev->dev, "Sig=0x%lx\n", signature);
- retval = -EIO;
}
dev_info(&pdev->dev, "-Done\n");
+ *signature = sig;
end:
return retval;
@@ -1757,7 +1745,7 @@ end:
/*
* Insmod can set static symbols so keep these static
*/
-static int card;
+static unsigned int card_count;
static int __devinit isicom_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
@@ -1767,7 +1755,7 @@ static int __devinit isicom_probe(struct pci_dev *pdev,
u8 pciirq;
struct isi_board *board = NULL;
- if (card >= BOARD_COUNT)
+ if (card_count >= BOARD_COUNT)
goto err;
ioaddr = pci_resource_start(pdev, 3);
@@ -1785,7 +1773,7 @@ static int __devinit isicom_probe(struct pci_dev *pdev,
board->index = index;
board->base = ioaddr;
board->irq = pciirq;
- card++;
+ card_count++;
pci_set_drvdata(pdev, board);
@@ -1795,7 +1783,7 @@ static int __devinit isicom_probe(struct pci_dev *pdev,
"will be disabled.\n", board->base, board->base + 15,
index + 1);
retval = -EBUSY;
- goto err;
+ goto errdec;
}
retval = request_irq(board->irq, isicom_interrupt,
@@ -1824,8 +1812,10 @@ errunri:
free_irq(board->irq, board);
errunrr:
pci_release_region(pdev, 3);
-err:
+errdec:
board->base = 0;
+ card_count--;
+err:
return retval;
}
@@ -1839,6 +1829,8 @@ static void __devexit isicom_remove(struct pci_dev *pdev)
free_irq(board->irq, board);
pci_release_region(pdev, 3);
+ board->base = 0;
+ card_count--;
}
static int __init isicom_init(void)
@@ -1846,8 +1838,6 @@ static int __init isicom_init(void)
int retval, idx, channel;
struct isi_port *port;
- card = 0;
-
for(idx = 0; idx < BOARD_COUNT; idx++) {
port = &isi_ports[idx * 16];
isi_card[idx].ports = port;
@@ -1858,8 +1848,6 @@ static int __init isicom_init(void)
port->channel = channel;
port->close_delay = 50 * HZ/100;
port->closing_wait = 3000 * HZ/100;
- INIT_WORK(&port->hangup_tq, do_isicom_hangup);
- INIT_WORK(&port->bh_tqueue, isicom_bottomhalf);
port->status = 0;
init_waitqueue_head(&port->open_wait);
init_waitqueue_head(&port->close_wait);
diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c
index 68645d35187..7b279d1de4a 100644
--- a/drivers/char/istallion.c
+++ b/drivers/char/istallion.c
@@ -2424,7 +2424,6 @@ static int stli_hostcmd(struct stlibrd *brdp, struct stliport *portp)
if (tty != NULL) {
tty_wakeup(tty);
EBRDENABLE(brdp);
- wake_up_interruptible(&tty->write_wait);
}
}
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
index 7a6c1c0b7a9..cb8d691576d 100644
--- a/drivers/char/keyboard.c
+++ b/drivers/char/keyboard.c
@@ -595,15 +595,8 @@ static void fn_spawn_con(struct vc_data *vc)
static void fn_SAK(struct vc_data *vc)
{
- struct tty_struct *tty = vc->vc_tty;
-
- /*
- * SAK should also work in all raw modes and reset
- * them properly.
- */
- if (tty)
- do_SAK(tty);
- reset_vc(vc);
+ struct work_struct *SAK_work = &vc_cons[fg_console].SAK_work;
+ schedule_work(SAK_work);
}
static void fn_null(struct vc_data *vc)
diff --git a/drivers/char/lcd.c b/drivers/char/lcd.c
index d649abbf085..5f4fdcf7c96 100644
--- a/drivers/char/lcd.c
+++ b/drivers/char/lcd.c
@@ -409,138 +409,6 @@ static int lcd_ioctl(struct inode *inode, struct file *file,
break;
}
-// Erase the flash
-
- case FLASH_Erase:{
-
- int ctr = 0;
-
- if ( !capable(CAP_SYS_ADMIN) ) return -EPERM;
-
- pr_info(LCD "Erasing Flash\n");
-
- // Chip Erase Sequence
- WRITE_FLASH(kFlash_Addr1, kFlash_Data1);
- WRITE_FLASH(kFlash_Addr2, kFlash_Data2);
- WRITE_FLASH(kFlash_Addr1, kFlash_Erase3);
- WRITE_FLASH(kFlash_Addr1, kFlash_Data1);
- WRITE_FLASH(kFlash_Addr2, kFlash_Data2);
- WRITE_FLASH(kFlash_Addr1, kFlash_Erase6);
-
- while ((!dqpoll(0x00000000, 0xFF))
- && (!timeout(0x00000000))) {
- ctr++;
- }
-
- if (READ_FLASH(0x07FFF0) == 0xFF) {
- pr_info(LCD "Erase Successful\n");
- } else if (timeout) {
- pr_info(LCD "Erase Timed Out\n");
- }
-
- break;
- }
-
-// burn the flash
-
- case FLASH_Burn:{
-
- volatile unsigned long burn_addr;
- unsigned long flags;
- unsigned int i, index;
- unsigned char *rom;
-
-
- struct lcd_display display;
-
- if ( !capable(CAP_SYS_ADMIN) ) return -EPERM;
-
- if (copy_from_user
- (&display, (struct lcd_display *) arg,
- sizeof(struct lcd_display)))
- return -EFAULT;
- rom = kmalloc((128), GFP_ATOMIC);
- if (rom == NULL) {
- printk(KERN_ERR LCD "kmalloc() failed in %s\n",
- __FUNCTION__);
- return -ENOMEM;
- }
-
- pr_info(LCD "Starting Flash burn\n");
- for (i = 0; i < FLASH_SIZE; i = i + 128) {
-
- if (copy_from_user
- (rom, display.RomImage + i, 128)) {
- kfree(rom);
- return -EFAULT;
- }
- burn_addr = kFlashBase + i;
- spin_lock_irqsave(&lcd_lock, flags);
- for (index = 0; index < (128); index++) {
-
- WRITE_FLASH(kFlash_Addr1,
- kFlash_Data1);
- WRITE_FLASH(kFlash_Addr2,
- kFlash_Data2);
- WRITE_FLASH(kFlash_Addr1,
- kFlash_Prog);
- *((volatile unsigned char *)burn_addr) =
- (volatile unsigned char) rom[index];
-
- while ((!dqpoll (burn_addr,
- (volatile unsigned char)
- rom[index])) &&
- (!timeout(burn_addr))) { }
- burn_addr++;
- }
- spin_unlock_irqrestore(&lcd_lock, flags);
- if (* ((volatile unsigned char *)
- (burn_addr - 1)) ==
- (volatile unsigned char)
- rom[index - 1]) {
- } else if (timeout) {
- pr_info(LCD "Flash burn timed out\n");
- }
-
-
- }
- kfree(rom);
-
- pr_info(LCD "Flash successfully burned\n");
-
- break;
- }
-
-// read the flash all at once
-
- case FLASH_Read:{
-
- unsigned char *user_bytes;
- volatile unsigned long read_addr;
- unsigned int i;
-
- user_bytes =
- &(((struct lcd_display *) arg)->RomImage[0]);
-
- if (!access_ok
- (VERIFY_WRITE, user_bytes, FLASH_SIZE))
- return -EFAULT;
-
- pr_info(LCD "Reading Flash");
- for (i = 0; i < FLASH_SIZE; i++) {
- unsigned char tmp_byte;
- read_addr = kFlashBase + i;
- tmp_byte =
- *((volatile unsigned char *)
- read_addr);
- if (__put_user(tmp_byte, &user_bytes[i]))
- return -EFAULT;
- }
-
-
- break;
- }
-
default:
return -EINVAL;
@@ -644,42 +512,6 @@ static void __exit lcd_exit(void)
misc_deregister(&lcd_dev);
}
-//
-// Function: dqpoll
-//
-// Description: Polls the data lines to see if the flash is busy
-//
-// In: address, byte data
-//
-// Out: 0 = busy, 1 = write or erase complete
-//
-//
-
-static int dqpoll(volatile unsigned long address, volatile unsigned char data)
-{
- volatile unsigned char dq7;
-
- dq7 = data & 0x80;
-
- return ((READ_FLASH(address) & 0x80) == dq7);
-}
-
-//
-// Function: timeout
-//
-// Description: Checks to see if erase or write has timed out
-// By polling dq5
-//
-// In: address
-//
-//
-// Out: 0 = not timed out, 1 = timed out
-
-static int timeout(volatile unsigned long address)
-{
- return (READ_FLASH(address) & 0x20) == 0x20;
-}
-
module_init(lcd_init);
module_exit(lcd_exit);
diff --git a/drivers/char/lcd.h b/drivers/char/lcd.h
index a8d4ae73715..290b3ff23b0 100644
--- a/drivers/char/lcd.h
+++ b/drivers/char/lcd.h
@@ -14,11 +14,7 @@
// function headers
-static int dqpoll(volatile unsigned long, volatile unsigned char );
-static int timeout(volatile unsigned long);
-
#define LCD_CHARS_PER_LINE 40
-#define FLASH_SIZE 524288
#define MAX_IDLE_TIME 120
struct lcd_display {
@@ -54,26 +50,6 @@ struct lcd_display {
#define LCDTimeoutValue 0xfff
-// Flash definitions AMD 29F040
-#define kFlashBase 0x0FC00000
-
-#define kFlash_Addr1 0x5555
-#define kFlash_Addr2 0x2AAA
-#define kFlash_Data1 0xAA
-#define kFlash_Data2 0x55
-#define kFlash_Prog 0xA0
-#define kFlash_Erase3 0x80
-#define kFlash_Erase6 0x10
-#define kFlash_Read 0xF0
-
-#define kFlash_ID 0x90
-#define kFlash_VenAddr 0x00
-#define kFlash_DevAddr 0x01
-#define kFlash_VenID 0x01
-#define kFlash_DevID 0xA4 // 29F040
-//#define kFlash_DevID 0xAD // 29F016
-
-
// Macros
#define LCDWriteData(x) outl((x << 24), kLCD_DR)
@@ -89,9 +65,6 @@ struct lcd_display {
#define WRITE_GAL(x,y) outl(y, 0x04000000 | (x))
#define BusyCheck() while ((LCDReadInst & 0x80) == 0x80)
-#define WRITE_FLASH(x,y) outb((char)y, kFlashBase | (x))
-#define READ_FLASH(x) (inb(kFlashBase | (x)))
-
/*
@@ -124,11 +97,6 @@ struct lcd_display {
// Button defs
#define BUTTON_Read 50
-// Flash command codes
-#define FLASH_Erase 60
-#define FLASH_Burn 61
-#define FLASH_Read 62
-
// Ethernet LINK check hackaroo
#define LINK_Check 90
diff --git a/drivers/char/mbcs.c b/drivers/char/mbcs.c
index 0afb7ba999c..57f9115a456 100644
--- a/drivers/char/mbcs.c
+++ b/drivers/char/mbcs.c
@@ -46,7 +46,7 @@ LIST_HEAD(soft_list);
/*
* file operations
*/
-struct file_operations mbcs_ops = {
+const struct file_operations mbcs_ops = {
.open = mbcs_open,
.llseek = mbcs_sram_llseek,
.read = mbcs_sram_read,
diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c
index f391a24a1b4..7dbaee8d940 100644
--- a/drivers/char/moxa.c
+++ b/drivers/char/moxa.c
@@ -11,15 +11,6 @@
* it under 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.
*/
/*
@@ -55,36 +46,20 @@
#include <asm/io.h>
#include <asm/uaccess.h>
-#define MOXA_VERSION "5.1k"
+#define MOXA_VERSION "5.1k"
-#define MOXAMAJOR 172
-#define MOXACUMAJOR 173
+#define MOXAMAJOR 172
+#define MOXACUMAJOR 173
-#define put_to_user(arg1, arg2) put_user(arg1, (unsigned long *)arg2)
-#define get_from_user(arg1, arg2) get_user(arg1, (unsigned int *)arg2)
-
-#define MAX_BOARDS 4 /* Don't change this value */
+#define MAX_BOARDS 4 /* Don't change this value */
#define MAX_PORTS_PER_BOARD 32 /* Don't change this value */
-#define MAX_PORTS 128 /* Don't change this value */
+#define MAX_PORTS (MAX_BOARDS * MAX_PORTS_PER_BOARD)
/*
* Define the Moxa PCI vendor and device IDs.
*/
-#define MOXA_BUS_TYPE_ISA 0
-#define MOXA_BUS_TYPE_PCI 1
-
-#ifndef PCI_VENDOR_ID_MOXA
-#define PCI_VENDOR_ID_MOXA 0x1393
-#endif
-#ifndef PCI_DEVICE_ID_CP204J
-#define PCI_DEVICE_ID_CP204J 0x2040
-#endif
-#ifndef PCI_DEVICE_ID_C218
-#define PCI_DEVICE_ID_C218 0x2180
-#endif
-#ifndef PCI_DEVICE_ID_C320
-#define PCI_DEVICE_ID_C320 0x3200
-#endif
+#define MOXA_BUS_TYPE_ISA 0
+#define MOXA_BUS_TYPE_PCI 1
enum {
MOXA_BOARD_C218_PCI = 1,
@@ -105,47 +80,56 @@ static char *moxa_brdname[] =
#ifdef CONFIG_PCI
static struct pci_device_id moxa_pcibrds[] = {
- { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_C218, PCI_ANY_ID, PCI_ANY_ID,
- 0, 0, MOXA_BOARD_C218_PCI },
- { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_C320, PCI_ANY_ID, PCI_ANY_ID,
- 0, 0, MOXA_BOARD_C320_PCI },
- { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_CP204J, PCI_ANY_ID, PCI_ANY_ID,
- 0, 0, MOXA_BOARD_CP204J },
+ { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C218),
+ .driver_data = MOXA_BOARD_C218_PCI },
+ { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C320),
+ .driver_data = MOXA_BOARD_C320_PCI },
+ { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP204J),
+ .driver_data = MOXA_BOARD_CP204J },
{ 0 }
};
MODULE_DEVICE_TABLE(pci, moxa_pcibrds);
#endif /* CONFIG_PCI */
-typedef struct _moxa_isa_board_conf {
+struct moxa_isa_board_conf {
int boardType;
int numPorts;
unsigned long baseAddr;
-} moxa_isa_board_conf;
+};
-static moxa_isa_board_conf moxa_isa_boards[] =
+static struct moxa_isa_board_conf moxa_isa_boards[] =
{
/* {MOXA_BOARD_C218_ISA,8,0xDC000}, */
};
-typedef struct _moxa_pci_devinfo {
- ushort busNum;
- ushort devNum;
- struct pci_dev *pdev;
-} moxa_pci_devinfo;
-
-typedef struct _moxa_board_conf {
+static struct moxa_board_conf {
int boardType;
int numPorts;
unsigned long baseAddr;
int busType;
- moxa_pci_devinfo pciInfo;
-} moxa_board_conf;
-static moxa_board_conf moxa_boards[MAX_BOARDS];
-static void __iomem *moxaBaseAddr[MAX_BOARDS];
-static int loadstat[MAX_BOARDS];
+ int loadstat;
+
+ void __iomem *basemem;
+ void __iomem *intNdx;
+ void __iomem *intPend;
+ void __iomem *intTable;
+} moxa_boards[MAX_BOARDS];
+
+struct mxser_mstatus {
+ tcflag_t cflag;
+ int cts;
+ int dsr;
+ int ri;
+ int dcd;
+};
+
+struct moxaq_str {
+ int inq;
+ int outq;
+};
-struct moxa_str {
+struct moxa_port {
int type;
int port;
int close_delay;
@@ -159,18 +143,18 @@ struct moxa_str {
int cflag;
wait_queue_head_t open_wait;
wait_queue_head_t close_wait;
- struct work_struct tqueue;
-};
-struct mxser_mstatus {
- tcflag_t cflag;
- int cts;
- int dsr;
- int ri;
- int dcd;
-};
+ struct timer_list emptyTimer;
-static struct mxser_mstatus GMStatus[MAX_PORTS];
+ char chkPort;
+ char lineCtrl;
+ void __iomem *tableAddr;
+ long curBaud;
+ char DCDState;
+ char lowChkFlag;
+
+ ushort breakCnt;
+};
/* statusflags */
#define TXSTOPPED 0x1
@@ -178,25 +162,17 @@ static struct mxser_mstatus GMStatus[MAX_PORTS];
#define EMPTYWAIT 0x4
#define THROTTLE 0x8
-/* event */
-#define MOXA_EVENT_HANGUP 1
-
#define SERIAL_DO_RESTART
-
-#define SERIAL_TYPE_NORMAL 1
-
#define WAKEUP_CHARS 256
-#define PORTNO(x) ((x)->index)
-
static int verbose = 0;
static int ttymajor = MOXAMAJOR;
/* Variables for insmod */
#ifdef MODULE
-static int baseaddr[] = {0, 0, 0, 0};
-static int type[] = {0, 0, 0, 0};
-static int numports[] = {0, 0, 0, 0};
+static int baseaddr[4];
+static int type[4];
+static int numports[4];
#endif
MODULE_AUTHOR("William Chen");
@@ -210,19 +186,9 @@ module_param_array(numports, int, NULL, 0);
module_param(ttymajor, int, 0);
module_param(verbose, bool, 0644);
-static struct tty_driver *moxaDriver;
-static struct moxa_str moxaChannels[MAX_PORTS];
-static unsigned char *moxaXmitBuff;
-static int moxaTimer_on;
-static struct timer_list moxaTimer;
-static int moxaEmptyTimer_on[MAX_PORTS];
-static struct timer_list moxaEmptyTimer[MAX_PORTS];
-static struct semaphore moxaBuffSem;
-
/*
* static functions:
*/
-static void do_moxa_softint(struct work_struct *);
static int moxa_open(struct tty_struct *, struct file *);
static void moxa_close(struct tty_struct *, struct file *);
static int moxa_write(struct tty_struct *, const unsigned char *, int);
@@ -244,11 +210,11 @@ static int moxa_tiocmset(struct tty_struct *tty, struct file *file,
static void moxa_poll(unsigned long);
static void set_tty_param(struct tty_struct *);
static int block_till_ready(struct tty_struct *, struct file *,
- struct moxa_str *);
+ struct moxa_port *);
static void setup_empty_event(struct tty_struct *);
static void check_xmit_empty(unsigned long);
-static void shut_down(struct moxa_str *);
-static void receive_data(struct moxa_str *);
+static void shut_down(struct moxa_port *);
+static void receive_data(struct moxa_port *);
/*
* moxa board interface functions:
*/
@@ -278,8 +244,8 @@ static void MoxaPortTxDisable(int);
static void MoxaPortTxEnable(int);
static int MoxaPortResetBrkCnt(int);
static void MoxaPortSendBreak(int, int);
-static int moxa_get_serial_info(struct moxa_str *, struct serial_struct __user *);
-static int moxa_set_serial_info(struct moxa_str *, struct serial_struct __user *);
+static int moxa_get_serial_info(struct moxa_port *, struct serial_struct __user *);
+static int moxa_set_serial_info(struct moxa_port *, struct serial_struct __user *);
static void MoxaSetFifo(int port, int enable);
static const struct tty_operations moxa_ops = {
@@ -302,12 +268,41 @@ static const struct tty_operations moxa_ops = {
.tiocmset = moxa_tiocmset,
};
+static struct tty_driver *moxaDriver;
+static struct moxa_port moxa_ports[MAX_PORTS];
+static DEFINE_TIMER(moxaTimer, moxa_poll, 0, 0);
static DEFINE_SPINLOCK(moxa_lock);
#ifdef CONFIG_PCI
-static int moxa_get_PCI_conf(struct pci_dev *p, int board_type, moxa_board_conf * board)
+static int __devinit moxa_pci_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
- board->baseAddr = pci_resource_start (p, 2);
+ struct moxa_board_conf *board;
+ unsigned int i;
+ int board_type = ent->driver_data;
+ int retval;
+
+ retval = pci_enable_device(pdev);
+ if (retval)
+ goto err;
+
+ for (i = 0; i < MAX_BOARDS; i++)
+ if (moxa_boards[i].basemem == NULL)
+ break;
+
+ retval = -ENODEV;
+ if (i >= MAX_BOARDS) {
+ if (verbose)
+ printk("More than %d MOXA Intellio family boards "
+ "found. Board is ignored.\n", MAX_BOARDS);
+ goto err;
+ }
+
+ board = &moxa_boards[i];
+ board->basemem = pci_iomap(pdev, 2, 0x4000);
+ if (board->basemem == NULL)
+ goto err;
+
board->boardType = board_type;
switch (board_type) {
case MOXA_BOARD_C218_ISA:
@@ -323,27 +318,40 @@ static int moxa_get_PCI_conf(struct pci_dev *p, int board_type, moxa_board_conf
break;
}
board->busType = MOXA_BUS_TYPE_PCI;
- board->pciInfo.busNum = p->bus->number;
- board->pciInfo.devNum = p->devfn >> 3;
- board->pciInfo.pdev = p;
- /* don't lose the reference in the next pci_get_device iteration */
- pci_dev_get(p);
+
+ pci_set_drvdata(pdev, board);
return (0);
+err:
+ return retval;
}
+
+static void __devexit moxa_pci_remove(struct pci_dev *pdev)
+{
+ struct moxa_board_conf *brd = pci_get_drvdata(pdev);
+
+ pci_iounmap(pdev, brd->basemem);
+ brd->basemem = NULL;
+}
+
+static struct pci_driver moxa_pci_driver = {
+ .name = "moxa",
+ .id_table = moxa_pcibrds,
+ .probe = moxa_pci_probe,
+ .remove = __devexit_p(moxa_pci_remove)
+};
#endif /* CONFIG_PCI */
static int __init moxa_init(void)
{
- int i, numBoards;
- struct moxa_str *ch;
+ int i, numBoards, retval = 0;
+ struct moxa_port *ch;
printk(KERN_INFO "MOXA Intellio family driver version %s\n", MOXA_VERSION);
moxaDriver = alloc_tty_driver(MAX_PORTS + 1);
if (!moxaDriver)
return -ENOMEM;
- init_MUTEX(&moxaBuffSem);
moxaDriver->owner = THIS_MODULE;
moxaDriver->name = "ttyMX";
moxaDriver->major = ttymajor;
@@ -351,40 +359,25 @@ static int __init moxa_init(void)
moxaDriver->type = TTY_DRIVER_TYPE_SERIAL;
moxaDriver->subtype = SERIAL_TYPE_NORMAL;
moxaDriver->init_termios = tty_std_termios;
- moxaDriver->init_termios.c_iflag = 0;
- moxaDriver->init_termios.c_oflag = 0;
moxaDriver->init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
- moxaDriver->init_termios.c_lflag = 0;
moxaDriver->init_termios.c_ispeed = 9600;
moxaDriver->init_termios.c_ospeed = 9600;
moxaDriver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(moxaDriver, &moxa_ops);
- moxaXmitBuff = NULL;
-
- for (i = 0, ch = moxaChannels; i < MAX_PORTS; i++, ch++) {
+ for (i = 0, ch = moxa_ports; i < MAX_PORTS; i++, ch++) {
ch->type = PORT_16550A;
ch->port = i;
- INIT_WORK(&ch->tqueue, do_moxa_softint);
- ch->tty = NULL;
ch->close_delay = 5 * HZ / 10;
ch->closing_wait = 30 * HZ;
- ch->count = 0;
- ch->blocked_open = 0;
ch->cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
init_waitqueue_head(&ch->open_wait);
init_waitqueue_head(&ch->close_wait);
- }
- for (i = 0; i < MAX_BOARDS; i++) {
- moxa_boards[i].boardType = 0;
- moxa_boards[i].numPorts = 0;
- moxa_boards[i].baseAddr = 0;
- moxa_boards[i].busType = 0;
- moxa_boards[i].pciInfo.busNum = 0;
- moxa_boards[i].pciInfo.devNum = 0;
+ setup_timer(&ch->emptyTimer, check_xmit_empty,
+ (unsigned long)ch);
}
- MoxaDriverInit();
+
printk("Tty devices major number = %d\n", ttymajor);
if (tty_register_driver(moxaDriver)) {
@@ -392,18 +385,8 @@ static int __init moxa_init(void)
put_tty_driver(moxaDriver);
return -1;
}
- for (i = 0; i < MAX_PORTS; i++) {
- init_timer(&moxaEmptyTimer[i]);
- moxaEmptyTimer[i].function = check_xmit_empty;
- moxaEmptyTimer[i].data = (unsigned long) & moxaChannels[i];
- moxaEmptyTimer_on[i] = 0;
- }
- init_timer(&moxaTimer);
- moxaTimer.function = moxa_poll;
- moxaTimer.expires = jiffies + (HZ / 50);
- moxaTimer_on = 1;
- add_timer(&moxaTimer);
+ mod_timer(&moxaTimer, jiffies + HZ / 50);
/* Find the boards defined in source code */
numBoards = 0;
@@ -451,35 +434,22 @@ static int __init moxa_init(void)
}
}
#endif
- /* Find PCI boards here */
+
#ifdef CONFIG_PCI
- {
- struct pci_dev *p = NULL;
- int n = ARRAY_SIZE(moxa_pcibrds) - 1;
- i = 0;
- while (i < n) {
- while ((p = pci_get_device(moxa_pcibrds[i].vendor, moxa_pcibrds[i].device, p))!=NULL)
- {
- if (pci_enable_device(p))
- continue;
- if (numBoards >= MAX_BOARDS) {
- if (verbose)
- printk("More than %d MOXA Intellio family boards found. Board is ignored.", MAX_BOARDS);
- } else {
- moxa_get_PCI_conf(p, moxa_pcibrds[i].driver_data,
- &moxa_boards[numBoards]);
- numBoards++;
- }
- }
- i++;
- }
+ retval = pci_register_driver(&moxa_pci_driver);
+ if (retval) {
+ printk(KERN_ERR "Can't register moxa pci driver!\n");
+ if (numBoards)
+ retval = 0;
}
#endif
+
for (i = 0; i < numBoards; i++) {
- moxaBaseAddr[i] = ioremap((unsigned long) moxa_boards[i].baseAddr, 0x4000);
+ moxa_boards[i].basemem = ioremap(moxa_boards[i].baseAddr,
+ 0x4000);
}
- return (0);
+ return retval;
}
static void __exit moxa_exit(void)
@@ -489,23 +459,22 @@ static void __exit moxa_exit(void)
if (verbose)
printk("Unloading module moxa ...\n");
- if (moxaTimer_on)
- del_timer(&moxaTimer);
+ del_timer_sync(&moxaTimer);
for (i = 0; i < MAX_PORTS; i++)
- if (moxaEmptyTimer_on[i])
- del_timer(&moxaEmptyTimer[i]);
+ del_timer_sync(&moxa_ports[i].emptyTimer);
if (tty_unregister_driver(moxaDriver))
printk("Couldn't unregister MOXA Intellio family serial driver\n");
put_tty_driver(moxaDriver);
- for (i = 0; i < MAX_BOARDS; i++) {
- if (moxaBaseAddr[i])
- iounmap(moxaBaseAddr[i]);
- if (moxa_boards[i].busType == MOXA_BUS_TYPE_PCI)
- pci_dev_put(moxa_boards[i].pciInfo.pdev);
- }
+#ifdef CONFIG_PCI
+ pci_unregister_driver(&moxa_pci_driver);
+#endif
+
+ for (i = 0; i < MAX_BOARDS; i++)
+ if (moxa_boards[i].basemem)
+ iounmap(moxa_boards[i].basemem);
if (verbose)
printk("Done\n");
@@ -514,28 +483,13 @@ static void __exit moxa_exit(void)
module_init(moxa_init);
module_exit(moxa_exit);
-static void do_moxa_softint(struct work_struct *work)
-{
- struct moxa_str *ch = container_of(work, struct moxa_str, tqueue);
- struct tty_struct *tty;
-
- if (ch && (tty = ch->tty)) {
- if (test_and_clear_bit(MOXA_EVENT_HANGUP, &ch->event)) {
- tty_hangup(tty); /* FIXME: module removal race here - AKPM */
- wake_up_interruptible(&ch->open_wait);
- ch->asyncflags &= ~ASYNC_NORMAL_ACTIVE;
- }
- }
-}
-
static int moxa_open(struct tty_struct *tty, struct file *filp)
{
- struct moxa_str *ch;
+ struct moxa_port *ch;
int port;
int retval;
- unsigned long page;
- port = PORTNO(tty);
+ port = tty->index;
if (port == MAX_PORTS) {
return (0);
}
@@ -543,23 +497,8 @@ static int moxa_open(struct tty_struct *tty, struct file *filp)
tty->driver_data = NULL;
return (-ENODEV);
}
- down(&moxaBuffSem);
- if (!moxaXmitBuff) {
- page = get_zeroed_page(GFP_KERNEL);
- if (!page) {
- up(&moxaBuffSem);
- return (-ENOMEM);
- }
- /* This test is guarded by the BuffSem so no longer needed
- delete me in 2.5 */
- if (moxaXmitBuff)
- free_page(page);
- else
- moxaXmitBuff = (unsigned char *) page;
- }
- up(&moxaBuffSem);
- ch = &moxaChannels[port];
+ ch = &moxa_ports[port];
ch->count++;
tty->driver_data = ch;
ch->tty = tty;
@@ -585,10 +524,10 @@ static int moxa_open(struct tty_struct *tty, struct file *filp)
static void moxa_close(struct tty_struct *tty, struct file *filp)
{
- struct moxa_str *ch;
+ struct moxa_port *ch;
int port;
- port = PORTNO(tty);
+ port = tty->index;
if (port == MAX_PORTS) {
return;
}
@@ -605,7 +544,7 @@ static void moxa_close(struct tty_struct *tty, struct file *filp)
if (tty_hung_up_p(filp)) {
return;
}
- ch = (struct moxa_str *) tty->driver_data;
+ ch = (struct moxa_port *) tty->driver_data;
if ((tty->count == 1) && (ch->count != 1)) {
printk("moxa_close: bad serial port count; tty->count is 1, "
@@ -626,8 +565,7 @@ static void moxa_close(struct tty_struct *tty, struct file *filp)
if (ch->asyncflags & ASYNC_INITIALIZED) {
setup_empty_event(tty);
tty_wait_until_sent(tty, 30 * HZ); /* 30 seconds timeout */
- moxaEmptyTimer_on[ch->port] = 0;
- del_timer(&moxaEmptyTimer[ch->port]);
+ del_timer_sync(&moxa_ports[ch->port].emptyTimer);
}
shut_down(ch);
MoxaPortFlushData(port, 2);
@@ -652,11 +590,11 @@ static void moxa_close(struct tty_struct *tty, struct file *filp)
static int moxa_write(struct tty_struct *tty,
const unsigned char *buf, int count)
{
- struct moxa_str *ch;
+ struct moxa_port *ch;
int len, port;
unsigned long flags;
- ch = (struct moxa_str *) tty->driver_data;
+ ch = (struct moxa_port *) tty->driver_data;
if (ch == NULL)
return (0);
port = ch->port;
@@ -675,11 +613,11 @@ static int moxa_write(struct tty_struct *tty,
static int moxa_write_room(struct tty_struct *tty)
{
- struct moxa_str *ch;
+ struct moxa_port *ch;
if (tty->stopped)
return (0);
- ch = (struct moxa_str *) tty->driver_data;
+ ch = (struct moxa_port *) tty->driver_data;
if (ch == NULL)
return (0);
return (MoxaPortTxFree(ch->port));
@@ -687,7 +625,7 @@ static int moxa_write_room(struct tty_struct *tty)
static void moxa_flush_buffer(struct tty_struct *tty)
{
- struct moxa_str *ch = (struct moxa_str *) tty->driver_data;
+ struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
if (ch == NULL)
return;
@@ -698,7 +636,7 @@ static void moxa_flush_buffer(struct tty_struct *tty)
static int moxa_chars_in_buffer(struct tty_struct *tty)
{
int chars;
- struct moxa_str *ch = (struct moxa_str *) tty->driver_data;
+ struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
/*
* Sigh...I have to check if driver_data is NULL here, because
@@ -730,17 +668,16 @@ static void moxa_flush_chars(struct tty_struct *tty)
static void moxa_put_char(struct tty_struct *tty, unsigned char c)
{
- struct moxa_str *ch;
+ struct moxa_port *ch;
int port;
unsigned long flags;
- ch = (struct moxa_str *) tty->driver_data;
+ ch = (struct moxa_port *) tty->driver_data;
if (ch == NULL)
return;
port = ch->port;
spin_lock_irqsave(&moxa_lock, flags);
- moxaXmitBuff[0] = c;
- MoxaPortWriteData(port, moxaXmitBuff, 1);
+ MoxaPortWriteData(port, &c, 1);
spin_unlock_irqrestore(&moxa_lock, flags);
/************************************************
if ( !(ch->statusflags & LOWWAIT) && (MoxaPortTxFree(port) <= 100) )
@@ -750,11 +687,11 @@ static void moxa_put_char(struct tty_struct *tty, unsigned char c)
static int moxa_tiocmget(struct tty_struct *tty, struct file *file)
{
- struct moxa_str *ch = (struct moxa_str *) tty->driver_data;
+ struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
int port;
int flag = 0, dtr, rts;
- port = PORTNO(tty);
+ port = tty->index;
if ((port != MAX_PORTS) && (!ch))
return (-EINVAL);
@@ -776,11 +713,11 @@ static int moxa_tiocmget(struct tty_struct *tty, struct file *file)
static int moxa_tiocmset(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear)
{
- struct moxa_str *ch = (struct moxa_str *) tty->driver_data;
+ struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
int port;
int dtr, rts;
- port = PORTNO(tty);
+ port = tty->index;
if ((port != MAX_PORTS) && (!ch))
return (-EINVAL);
@@ -800,12 +737,12 @@ static int moxa_tiocmset(struct tty_struct *tty, struct file *file,
static int moxa_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg)
{
- struct moxa_str *ch = (struct moxa_str *) tty->driver_data;
+ struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
register int port;
void __user *argp = (void __user *)arg;
int retval;
- port = PORTNO(tty);
+ port = tty->index;
if ((port != MAX_PORTS) && (!ch))
return (-EINVAL);
@@ -853,14 +790,14 @@ static int moxa_ioctl(struct tty_struct *tty, struct file *file,
static void moxa_throttle(struct tty_struct *tty)
{
- struct moxa_str *ch = (struct moxa_str *) tty->driver_data;
+ struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
ch->statusflags |= THROTTLE;
}
static void moxa_unthrottle(struct tty_struct *tty)
{
- struct moxa_str *ch = (struct moxa_str *) tty->driver_data;
+ struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
ch->statusflags &= ~THROTTLE;
}
@@ -868,7 +805,7 @@ static void moxa_unthrottle(struct tty_struct *tty)
static void moxa_set_termios(struct tty_struct *tty,
struct ktermios *old_termios)
{
- struct moxa_str *ch = (struct moxa_str *) tty->driver_data;
+ struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
if (ch == NULL)
return;
@@ -880,7 +817,7 @@ static void moxa_set_termios(struct tty_struct *tty,
static void moxa_stop(struct tty_struct *tty)
{
- struct moxa_str *ch = (struct moxa_str *) tty->driver_data;
+ struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
if (ch == NULL)
return;
@@ -891,7 +828,7 @@ static void moxa_stop(struct tty_struct *tty)
static void moxa_start(struct tty_struct *tty)
{
- struct moxa_str *ch = (struct moxa_str *) tty->driver_data;
+ struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
if (ch == NULL)
return;
@@ -905,7 +842,7 @@ static void moxa_start(struct tty_struct *tty)
static void moxa_hangup(struct tty_struct *tty)
{
- struct moxa_str *ch = (struct moxa_str *) tty->driver_data;
+ struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
moxa_flush_buffer(tty);
shut_down(ch);
@@ -919,24 +856,20 @@ static void moxa_hangup(struct tty_struct *tty)
static void moxa_poll(unsigned long ignored)
{
register int card;
- struct moxa_str *ch;
+ struct moxa_port *ch;
struct tty_struct *tp;
int i, ports;
- moxaTimer_on = 0;
del_timer(&moxaTimer);
if (MoxaDriverPoll() < 0) {
- moxaTimer.function = moxa_poll;
- moxaTimer.expires = jiffies + (HZ / 50);
- moxaTimer_on = 1;
- add_timer(&moxaTimer);
+ mod_timer(&moxaTimer, jiffies + HZ / 50);
return;
}
for (card = 0; card < MAX_BOARDS; card++) {
if ((ports = MoxaPortsOfCard(card)) <= 0)
continue;
- ch = &moxaChannels[card * MAX_PORTS_PER_BOARD];
+ ch = &moxa_ports[card * MAX_PORTS_PER_BOARD];
for (i = 0; i < ports; i++, ch++) {
if ((ch->asyncflags & ASYNC_INITIALIZED) == 0)
continue;
@@ -962,18 +895,16 @@ static void moxa_poll(unsigned long ignored)
if (MoxaPortDCDON(ch->port))
wake_up_interruptible(&ch->open_wait);
else {
- set_bit(MOXA_EVENT_HANGUP, &ch->event);
- schedule_work(&ch->tqueue);
+ tty_hangup(tp);
+ wake_up_interruptible(&ch->open_wait);
+ ch->asyncflags &= ~ASYNC_NORMAL_ACTIVE;
}
}
}
}
}
- moxaTimer.function = moxa_poll;
- moxaTimer.expires = jiffies + (HZ / 50);
- moxaTimer_on = 1;
- add_timer(&moxaTimer);
+ mod_timer(&moxaTimer, jiffies + HZ / 50);
}
/******************************************************************************/
@@ -981,10 +912,10 @@ static void moxa_poll(unsigned long ignored)
static void set_tty_param(struct tty_struct *tty)
{
register struct ktermios *ts;
- struct moxa_str *ch;
+ struct moxa_port *ch;
int rts, cts, txflow, rxflow, xany;
- ch = (struct moxa_str *) tty->driver_data;
+ ch = (struct moxa_port *) tty->driver_data;
ts = tty->termios;
if (ts->c_cflag & CLOCAL)
ch->asyncflags &= ~ASYNC_CHECK_CD;
@@ -1004,7 +935,7 @@ static void set_tty_param(struct tty_struct *tty)
}
static int block_till_ready(struct tty_struct *tty, struct file *filp,
- struct moxa_str *ch)
+ struct moxa_port *ch)
{
DECLARE_WAITQUEUE(wait,current);
unsigned long flags;
@@ -1095,40 +1026,33 @@ static int block_till_ready(struct tty_struct *tty, struct file *filp,
static void setup_empty_event(struct tty_struct *tty)
{
- struct moxa_str *ch = tty->driver_data;
+ struct moxa_port *ch = tty->driver_data;
unsigned long flags;
spin_lock_irqsave(&moxa_lock, flags);
ch->statusflags |= EMPTYWAIT;
- moxaEmptyTimer_on[ch->port] = 0;
- del_timer(&moxaEmptyTimer[ch->port]);
- moxaEmptyTimer[ch->port].expires = jiffies + HZ;
- moxaEmptyTimer_on[ch->port] = 1;
- add_timer(&moxaEmptyTimer[ch->port]);
+ mod_timer(&moxa_ports[ch->port].emptyTimer, jiffies + HZ);
spin_unlock_irqrestore(&moxa_lock, flags);
}
static void check_xmit_empty(unsigned long data)
{
- struct moxa_str *ch;
+ struct moxa_port *ch;
- ch = (struct moxa_str *) data;
- moxaEmptyTimer_on[ch->port] = 0;
- del_timer(&moxaEmptyTimer[ch->port]);
+ ch = (struct moxa_port *) data;
+ del_timer_sync(&moxa_ports[ch->port].emptyTimer);
if (ch->tty && (ch->statusflags & EMPTYWAIT)) {
if (MoxaPortTxQueue(ch->port) == 0) {
ch->statusflags &= ~EMPTYWAIT;
tty_wakeup(ch->tty);
return;
}
- moxaEmptyTimer[ch->port].expires = jiffies + HZ;
- moxaEmptyTimer_on[ch->port] = 1;
- add_timer(&moxaEmptyTimer[ch->port]);
+ mod_timer(&moxa_ports[ch->port].emptyTimer, jiffies + HZ);
} else
ch->statusflags &= ~EMPTYWAIT;
}
-static void shut_down(struct moxa_str *ch)
+static void shut_down(struct moxa_port *ch)
{
struct tty_struct *tp;
@@ -1148,7 +1072,7 @@ static void shut_down(struct moxa_str *ch)
ch->asyncflags &= ~ASYNC_INITIALIZED;
}
-static void receive_data(struct moxa_str *ch)
+static void receive_data(struct moxa_port *ch)
{
struct tty_struct *tp;
struct ktermios *ts;
@@ -1465,35 +1389,21 @@ static void receive_data(struct moxa_str *ch)
/*
* Query
*/
-#define QueryPort MAX_PORTS
-
-
struct mon_str {
int tick;
int rxcnt[MAX_PORTS];
int txcnt[MAX_PORTS];
};
-typedef struct mon_str mon_st;
#define DCD_changed 0x01
#define DCD_oldstate 0x80
static unsigned char moxaBuff[10240];
-static void __iomem *moxaIntNdx[MAX_BOARDS];
-static void __iomem *moxaIntPend[MAX_BOARDS];
-static void __iomem *moxaIntTable[MAX_BOARDS];
-static char moxaChkPort[MAX_PORTS];
-static char moxaLineCtrl[MAX_PORTS];
-static void __iomem *moxaTableAddr[MAX_PORTS];
-static long moxaCurBaud[MAX_PORTS];
-static char moxaDCDState[MAX_PORTS];
-static char moxaLowChkFlag[MAX_PORTS];
static int moxaLowWaterChk;
static int moxaCard;
-static mon_st moxaLog;
-static int moxaFuncTout;
-static ushort moxaBreakCnt[MAX_PORTS];
+static struct mon_str moxaLog;
+static int moxaFuncTout = HZ / 2;
static void moxadelay(int);
static void moxafunc(void __iomem *, int, ushort);
@@ -1514,16 +1424,18 @@ static int moxaloadc320(int, void __iomem *, int, int *);
*****************************************************************************/
void MoxaDriverInit(void)
{
- int i;
+ struct moxa_port *p;
+ unsigned int i;
moxaFuncTout = HZ / 2; /* 500 mini-seconds */
moxaCard = 0;
moxaLog.tick = 0;
moxaLowWaterChk = 0;
for (i = 0; i < MAX_PORTS; i++) {
- moxaChkPort[i] = 0;
- moxaLowChkFlag[i] = 0;
- moxaLineCtrl[i] = 0;
+ p = &moxa_ports[i];
+ p->chkPort = 0;
+ p->lowChkFlag = 0;
+ p->lineCtrl = 0;
moxaLog.rxcnt[i] = 0;
moxaLog.txcnt[i] = 0;
}
@@ -1545,19 +1457,12 @@ void MoxaDriverInit(void)
#define MOXA_GET_CUMAJOR (MOXA + 64)
#define MOXA_GETMSTATUS (MOXA + 65)
-
-struct moxaq_str {
- int inq;
- int outq;
-};
-
struct dl_str {
char __user *buf;
int len;
int cardno;
};
-static struct moxaq_str temp_queue[MAX_PORTS];
static struct dl_str dltmp;
void MoxaPortFlushData(int port, int mode)
@@ -1565,10 +1470,10 @@ void MoxaPortFlushData(int port, int mode)
void __iomem *ofsAddr;
if ((mode < 0) || (mode > 2))
return;
- ofsAddr = moxaTableAddr[port];
+ ofsAddr = moxa_ports[port].tableAddr;
moxafunc(ofsAddr, FC_FlushQueue, mode);
if (mode != 1) {
- moxaLowChkFlag[port] = 0;
+ moxa_ports[port].lowChkFlag = 0;
low_water_check(ofsAddr);
}
}
@@ -1580,7 +1485,7 @@ int MoxaDriverIoctl(unsigned int cmd, unsigned long arg, int port)
int MoxaPortTxQueue(int), MoxaPortRxQueue(int);
void __user *argp = (void __user *)arg;
- if (port == QueryPort) {
+ if (port == MAX_PORTS) {
if ((cmd != MOXA_GET_CONF) && (cmd != MOXA_INIT_DRIVER) &&
(cmd != MOXA_LOAD_BIOS) && (cmd != MOXA_FIND_BOARD) && (cmd != MOXA_LOAD_C320B) &&
(cmd != MOXA_LOAD_CODE) && (cmd != MOXA_GETDATACOUNT) &&
@@ -1590,7 +1495,8 @@ int MoxaDriverIoctl(unsigned int cmd, unsigned long arg, int port)
}
switch (cmd) {
case MOXA_GET_CONF:
- if(copy_to_user(argp, &moxa_boards, MAX_BOARDS * sizeof(moxa_board_conf)))
+ if(copy_to_user(argp, &moxa_boards, MAX_BOARDS *
+ sizeof(struct moxa_board_conf)))
return -EFAULT;
return (0);
case MOXA_INIT_DRIVER:
@@ -1599,23 +1505,27 @@ int MoxaDriverIoctl(unsigned int cmd, unsigned long arg, int port)
return (0);
case MOXA_GETDATACOUNT:
moxaLog.tick = jiffies;
- if(copy_to_user(argp, &moxaLog, sizeof(mon_st)))
+ if(copy_to_user(argp, &moxaLog, sizeof(struct mon_str)))
return -EFAULT;
return (0);
case MOXA_FLUSH_QUEUE:
MoxaPortFlushData(port, arg);
return (0);
- case MOXA_GET_IOQUEUE:
- for (i = 0; i < MAX_PORTS; i++) {
- if (moxaChkPort[i]) {
- temp_queue[i].inq = MoxaPortRxQueue(i);
- temp_queue[i].outq = MoxaPortTxQueue(i);
+ case MOXA_GET_IOQUEUE: {
+ struct moxaq_str __user *argm = argp;
+ struct moxaq_str tmp;
+
+ for (i = 0; i < MAX_PORTS; i++, argm++) {
+ memset(&tmp, 0, sizeof(tmp));
+ if (moxa_ports[i].chkPort) {
+ tmp.inq = MoxaPortRxQueue(i);
+ tmp.outq = MoxaPortTxQueue(i);
}
+ if (copy_to_user(argm, &tmp, sizeof(tmp)))
+ return -EFAULT;
}
- if(copy_to_user(argp, temp_queue, sizeof(struct moxaq_str) * MAX_PORTS))
- return -EFAULT;
return (0);
- case MOXA_GET_OQUEUE:
+ } case MOXA_GET_OQUEUE:
i = MoxaPortTxQueue(port);
return put_user(i, (unsigned long __user *)argp);
case MOXA_GET_IQUEUE:
@@ -1630,33 +1540,36 @@ int MoxaDriverIoctl(unsigned int cmd, unsigned long arg, int port)
if(copy_to_user(argp, &i, sizeof(int)))
return -EFAULT;
return 0;
- case MOXA_GETMSTATUS:
- for (i = 0; i < MAX_PORTS; i++) {
- GMStatus[i].ri = 0;
- GMStatus[i].dcd = 0;
- GMStatus[i].dsr = 0;
- GMStatus[i].cts = 0;
- if (!moxaChkPort[i]) {
- continue;
+ case MOXA_GETMSTATUS: {
+ struct mxser_mstatus __user *argm = argp;
+ struct mxser_mstatus tmp;
+ struct moxa_port *p;
+
+ for (i = 0; i < MAX_PORTS; i++, argm++) {
+ p = &moxa_ports[i];
+ memset(&tmp, 0, sizeof(tmp));
+ if (!p->chkPort) {
+ goto copy;
} else {
- status = MoxaPortLineStatus(moxaChannels[i].port);
+ status = MoxaPortLineStatus(p->port);
if (status & 1)
- GMStatus[i].cts = 1;
+ tmp.cts = 1;
if (status & 2)
- GMStatus[i].dsr = 1;
+ tmp.dsr = 1;
if (status & 4)
- GMStatus[i].dcd = 1;
+ tmp.dcd = 1;
}
- if (!moxaChannels[i].tty || !moxaChannels[i].tty->termios)
- GMStatus[i].cflag = moxaChannels[i].cflag;
+ if (!p->tty || !p->tty->termios)
+ tmp.cflag = p->cflag;
else
- GMStatus[i].cflag = moxaChannels[i].tty->termios->c_cflag;
+ tmp.cflag = p->tty->termios->c_cflag;
+copy:
+ if (copy_to_user(argm, &tmp, sizeof(tmp)))
+ return -EFAULT;
}
- if(copy_to_user(argp, GMStatus, sizeof(struct mxser_mstatus) * MAX_PORTS))
- return -EFAULT;
return 0;
- default:
+ } default:
return (-ENOIOCTLCMD);
case MOXA_LOAD_BIOS:
case MOXA_FIND_BOARD:
@@ -1694,6 +1607,7 @@ int MoxaDriverIoctl(unsigned int cmd, unsigned long arg, int port)
int MoxaDriverPoll(void)
{
+ struct moxa_board_conf *brd;
register ushort temp;
register int card;
void __iomem *ofsAddr;
@@ -1703,43 +1617,44 @@ int MoxaDriverPoll(void)
if (moxaCard == 0)
return (-1);
for (card = 0; card < MAX_BOARDS; card++) {
- if (loadstat[card] == 0)
+ brd = &moxa_boards[card];
+ if (brd->loadstat == 0)
continue;
- if ((ports = moxa_boards[card].numPorts) == 0)
+ if ((ports = brd->numPorts) == 0)
continue;
- if (readb(moxaIntPend[card]) == 0xff) {
- ip = moxaIntTable[card] + readb(moxaIntNdx[card]);
+ if (readb(brd->intPend) == 0xff) {
+ ip = brd->intTable + readb(brd->intNdx);
p = card * MAX_PORTS_PER_BOARD;
ports <<= 1;
for (port = 0; port < ports; port += 2, p++) {
if ((temp = readw(ip + port)) != 0) {
writew(0, ip + port);
- ofsAddr = moxaTableAddr[p];
+ ofsAddr = moxa_ports[p].tableAddr;
if (temp & IntrTx)
writew(readw(ofsAddr + HostStat) & ~WakeupTx, ofsAddr + HostStat);
if (temp & IntrBreak) {
- moxaBreakCnt[p]++;
+ moxa_ports[p].breakCnt++;
}
if (temp & IntrLine) {
if (readb(ofsAddr + FlagStat) & DCD_state) {
- if ((moxaDCDState[p] & DCD_oldstate) == 0)
- moxaDCDState[p] = (DCD_oldstate |
+ if ((moxa_ports[p].DCDState & DCD_oldstate) == 0)
+ moxa_ports[p].DCDState = (DCD_oldstate |
DCD_changed);
} else {
- if (moxaDCDState[p] & DCD_oldstate)
- moxaDCDState[p] = DCD_changed;
+ if (moxa_ports[p].DCDState & DCD_oldstate)
+ moxa_ports[p].DCDState = DCD_changed;
}
}
}
}
- writeb(0, moxaIntPend[card]);
+ writeb(0, brd->intPend);
}
if (moxaLowWaterChk) {
p = card * MAX_PORTS_PER_BOARD;
for (port = 0; port < ports; port++, p++) {
- if (moxaLowChkFlag[p]) {
- moxaLowChkFlag[p] = 0;
- ofsAddr = moxaTableAddr[p];
+ if (moxa_ports[p].lowChkFlag) {
+ moxa_ports[p].lowChkFlag = 0;
+ ofsAddr = moxa_ports[p].tableAddr;
low_water_check(ofsAddr);
}
}
@@ -1767,9 +1682,7 @@ int MoxaPortsOfCard(int cardno)
* 2. MoxaPortEnable(int port); *
* 3. MoxaPortDisable(int port); *
* 4. MoxaPortGetMaxBaud(int port); *
- * 5. MoxaPortGetCurBaud(int port); *
* 6. MoxaPortSetBaud(int port, long baud); *
- * 7. MoxaPortSetMode(int port, int databit, int stopbit, int parity); *
* 8. MoxaPortSetTermio(int port, unsigned char *termio); *
* 9. MoxaPortGetLineOut(int port, int *dtrState, int *rtsState); *
* 10. MoxaPortLineCtrl(int port, int dtrState, int rtsState); *
@@ -1780,18 +1693,12 @@ int MoxaPortsOfCard(int cardno)
* 15. MoxaPortFlushData(int port, int mode); *
* 16. MoxaPortWriteData(int port, unsigned char * buffer, int length); *
* 17. MoxaPortReadData(int port, struct tty_struct *tty); *
- * 18. MoxaPortTxBufSize(int port); *
- * 19. MoxaPortRxBufSize(int port); *
* 20. MoxaPortTxQueue(int port); *
* 21. MoxaPortTxFree(int port); *
* 22. MoxaPortRxQueue(int port); *
- * 23. MoxaPortRxFree(int port); *
* 24. MoxaPortTxDisable(int port); *
* 25. MoxaPortTxEnable(int port); *
- * 26. MoxaPortGetBrkCnt(int port); *
* 27. MoxaPortResetBrkCnt(int port); *
- * 28. MoxaPortSetXonXoff(int port, int xonValue, int xoffValue); *
- * 29. MoxaPortIsTxHold(int port); *
* 30. MoxaPortSendBreak(int port, int ticks); *
*****************************************************************************/
/*
@@ -1878,15 +1785,6 @@ int MoxaPortsOfCard(int cardno)
* 38400/57600/115200 bps
*
*
- * Function 9: Get the current baud rate of this port.
- * Syntax:
- * long MoxaPortGetCurBaud(int port);
- * int port : port number (0 - 127)
- *
- * return: 0 : this port is invalid
- * 50 - 115200 bps
- *
- *
* Function 10: Setting baud rate of this port.
* Syntax:
* long MoxaPortSetBaud(int port, long baud);
@@ -1900,18 +1798,6 @@ int MoxaPortsOfCard(int cardno)
* baud rate will be the maximun baud rate.
*
*
- * Function 11: Setting the data-bits/stop-bits/parity of this port
- * Syntax:
- * int MoxaPortSetMode(int port, int databits, int stopbits, int parity);
- * int port : port number (0 - 127)
- * int databits : data bits (8/7/6/5)
- * int stopbits : stop bits (2/1/0, 0 show 1.5 stop bits)
- int parity : parity (0:None,1:Odd,2:Even,3:Mark,4:Space)
- *
- * return: -1 : invalid parameter
- * 0 : setting O.K.
- *
- *
* Function 12: Configure the port.
* Syntax:
* int MoxaPortSetTermio(int port, struct ktermios *termio, speed_t baud);
@@ -2016,22 +1902,6 @@ int MoxaPortsOfCard(int cardno)
* return: 0 - length : real read data length
*
*
- * Function 22: Get the Tx buffer size of this port
- * Syntax:
- * int MoxaPortTxBufSize(int port);
- * int port : port number (0 - 127)
- *
- * return: .. : Tx buffer size
- *
- *
- * Function 23: Get the Rx buffer size of this port
- * Syntax:
- * int MoxaPortRxBufSize(int port);
- * int port : port number (0 - 127)
- *
- * return: .. : Rx buffer size
- *
- *
* Function 24: Get the Tx buffer current queued data bytes
* Syntax:
* int MoxaPortTxQueue(int port);
@@ -2056,14 +1926,6 @@ int MoxaPortsOfCard(int cardno)
* return: .. : Rx buffer current queued data bytes
*
*
- * Function 27: Get the Rx buffer current free space
- * Syntax:
- * int MoxaPortRxFree(int port);
- * int port : port number (0 - 127)
- *
- * return: .. : Rx buffer current free space
- *
- *
* Function 28: Disable port data transmission.
* Syntax:
* void MoxaPortTxDisable(int port);
@@ -2076,14 +1938,6 @@ int MoxaPortsOfCard(int cardno)
* int port : port number (0 - 127)
*
*
- * Function 30: Get the received BREAK signal count.
- * Syntax:
- * int MoxaPortGetBrkCnt(int port);
- * int port : port number (0 - 127)
- *
- * return: 0 - .. : BREAK signal count
- *
- *
* Function 31: Get the received BREAK signal count and reset it.
* Syntax:
* int MoxaPortResetBrkCnt(int port);
@@ -2092,25 +1946,6 @@ int MoxaPortsOfCard(int cardno)
* return: 0 - .. : BREAK signal count
*
*
- * Function 32: Set the S/W flow control new XON/XOFF value, default
- * XON is 0x11 & XOFF is 0x13.
- * Syntax:
- * void MoxaPortSetXonXoff(int port, int xonValue, int xoffValue);
- * int port : port number (0 - 127)
- * int xonValue : new XON value (0 - 255)
- * int xoffValue : new XOFF value (0 - 255)
- *
- *
- * Function 33: Check this port's transmission is hold by remote site
- * because the flow control.
- * Syntax:
- * int MoxaPortIsTxHold(int port);
- * int port : port number (0 - 127)
- *
- * return: 0 : normal
- * 1 : hold by remote site
- *
- *
* Function 34: Send out a BREAK signal.
* Syntax:
* void MoxaPortSendBreak(int port, int ms100);
@@ -2125,7 +1960,7 @@ int MoxaPortIsValid(int port)
if (moxaCard == 0)
return (0);
- if (moxaChkPort[port] == 0)
+ if (moxa_ports[port].chkPort == 0)
return (0);
return (1);
}
@@ -2136,9 +1971,9 @@ void MoxaPortEnable(int port)
int MoxaPortLineStatus(int);
short lowwater = 512;
- ofsAddr = moxaTableAddr[port];
+ ofsAddr = moxa_ports[port].tableAddr;
writew(lowwater, ofsAddr + Low_water);
- moxaBreakCnt[port] = 0;
+ moxa_ports[port].breakCnt = 0;
if ((moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_ISA) ||
(moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_PCI)) {
moxafunc(ofsAddr, FC_SetBreakIrq, 0);
@@ -2155,7 +1990,7 @@ void MoxaPortEnable(int port)
void MoxaPortDisable(int port)
{
- void __iomem *ofsAddr = moxaTableAddr[port];
+ void __iomem *ofsAddr = moxa_ports[port].tableAddr;
moxafunc(ofsAddr, FC_SetFlowCtl, 0); /* disable flow control */
moxafunc(ofsAddr, FC_ClrLineIrq, Magic_code);
@@ -2181,7 +2016,7 @@ long MoxaPortSetBaud(int port, long baud)
if ((baud < 50L) || ((max = MoxaPortGetMaxBaud(port)) == 0))
return (0);
- ofsAddr = moxaTableAddr[port];
+ ofsAddr = moxa_ports[port].tableAddr;
if (baud > max)
baud = max;
if (max == 38400L)
@@ -2193,7 +2028,7 @@ long MoxaPortSetBaud(int port, long baud)
val = clock / baud;
moxafunc(ofsAddr, FC_SetBaud, val);
baud = clock / val;
- moxaCurBaud[port] = baud;
+ moxa_ports[port].curBaud = baud;
return (baud);
}
@@ -2203,9 +2038,9 @@ int MoxaPortSetTermio(int port, struct ktermios *termio, speed_t baud)
tcflag_t cflag;
tcflag_t mode = 0;
- if (moxaChkPort[port] == 0 || termio == 0)
+ if (moxa_ports[port].chkPort == 0 || termio == 0)
return (-1);
- ofsAddr = moxaTableAddr[port];
+ ofsAddr = moxa_ports[port].tableAddr;
cflag = termio->c_cflag; /* termio->c_cflag */
mode = termio->c_cflag & CSIZE;
@@ -2259,13 +2094,13 @@ int MoxaPortGetLineOut(int port, int *dtrState, int *rtsState)
if (!MoxaPortIsValid(port))
return (-1);
if (dtrState) {
- if (moxaLineCtrl[port] & DTR_ON)
+ if (moxa_ports[port].lineCtrl & DTR_ON)
*dtrState = 1;
else
*dtrState = 0;
}
if (rtsState) {
- if (moxaLineCtrl[port] & RTS_ON)
+ if (moxa_ports[port].lineCtrl & RTS_ON)
*rtsState = 1;
else
*rtsState = 0;
@@ -2278,13 +2113,13 @@ void MoxaPortLineCtrl(int port, int dtr, int rts)
void __iomem *ofsAddr;
int mode;
- ofsAddr = moxaTableAddr[port];
+ ofsAddr = moxa_ports[port].tableAddr;
mode = 0;
if (dtr)
mode |= DTR_ON;
if (rts)
mode |= RTS_ON;
- moxaLineCtrl[port] = mode;
+ moxa_ports[port].lineCtrl = mode;
moxafunc(ofsAddr, FC_LineControl, mode);
}
@@ -2293,7 +2128,7 @@ void MoxaPortFlowCtrl(int port, int rts, int cts, int txflow, int rxflow, int tx
void __iomem *ofsAddr;
int mode;
- ofsAddr = moxaTableAddr[port];
+ ofsAddr = moxa_ports[port].tableAddr;
mode = 0;
if (rts)
mode |= RTS_FlowCtl;
@@ -2313,7 +2148,7 @@ int MoxaPortLineStatus(int port)
void __iomem *ofsAddr;
int val;
- ofsAddr = moxaTableAddr[port];
+ ofsAddr = moxa_ports[port].tableAddr;
if ((moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_ISA) ||
(moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_PCI)) {
moxafunc(ofsAddr, FC_LineStatus, 0);
@@ -2324,11 +2159,11 @@ int MoxaPortLineStatus(int port)
val &= 0x0B;
if (val & 8) {
val |= 4;
- if ((moxaDCDState[port] & DCD_oldstate) == 0)
- moxaDCDState[port] = (DCD_oldstate | DCD_changed);
+ if ((moxa_ports[port].DCDState & DCD_oldstate) == 0)
+ moxa_ports[port].DCDState = (DCD_oldstate | DCD_changed);
} else {
- if (moxaDCDState[port] & DCD_oldstate)
- moxaDCDState[port] = DCD_changed;
+ if (moxa_ports[port].DCDState & DCD_oldstate)
+ moxa_ports[port].DCDState = DCD_changed;
}
val &= 7;
return (val);
@@ -2338,10 +2173,10 @@ int MoxaPortDCDChange(int port)
{
int n;
- if (moxaChkPort[port] == 0)
+ if (moxa_ports[port].chkPort == 0)
return (0);
- n = moxaDCDState[port];
- moxaDCDState[port] &= ~DCD_changed;
+ n = moxa_ports[port].DCDState;
+ moxa_ports[port].DCDState &= ~DCD_changed;
n &= DCD_changed;
return (n);
}
@@ -2350,32 +2185,15 @@ int MoxaPortDCDON(int port)
{
int n;
- if (moxaChkPort[port] == 0)
+ if (moxa_ports[port].chkPort == 0)
return (0);
- if (moxaDCDState[port] & DCD_oldstate)
+ if (moxa_ports[port].DCDState & DCD_oldstate)
n = 1;
else
n = 0;
return (n);
}
-
-/*
- int MoxaDumpMem(int port, unsigned char * buffer, int len)
- {
- int i;
- unsigned long baseAddr,ofsAddr,ofs;
-
- baseAddr = moxaBaseAddr[port / MAX_PORTS_PER_BOARD];
- ofs = baseAddr + DynPage_addr + pageofs;
- if (len > 0x2000L)
- len = 0x2000L;
- for (i = 0; i < len; i++)
- buffer[i] = readb(ofs+i);
- }
- */
-
-
int MoxaPortWriteData(int port, unsigned char * buffer, int len)
{
int c, total, i;
@@ -2385,8 +2203,8 @@ int MoxaPortWriteData(int port, unsigned char * buffer, int len)
ushort pageno, pageofs, bufhead;
void __iomem *baseAddr, *ofsAddr, *ofs;
- ofsAddr = moxaTableAddr[port];
- baseAddr = moxaBaseAddr[port / MAX_PORTS_PER_BOARD];
+ ofsAddr = moxa_ports[port].tableAddr;
+ baseAddr = moxa_boards[port / MAX_PORTS_PER_BOARD].basemem;
tx_mask = readw(ofsAddr + TX_mask);
spage = readw(ofsAddr + Page_txb);
epage = readw(ofsAddr + EndPage_txb);
@@ -2448,8 +2266,8 @@ int MoxaPortReadData(int port, struct tty_struct *tty)
ushort pageno, bufhead;
void __iomem *baseAddr, *ofsAddr, *ofs;
- ofsAddr = moxaTableAddr[port];
- baseAddr = moxaBaseAddr[port / MAX_PORTS_PER_BOARD];
+ ofsAddr = moxa_ports[port].tableAddr;
+ baseAddr = moxa_boards[port / MAX_PORTS_PER_BOARD].basemem;
head = readw(ofsAddr + RXrptr);
tail = readw(ofsAddr + RXwptr);
rx_mask = readw(ofsAddr + RX_mask);
@@ -2504,7 +2322,7 @@ int MoxaPortReadData(int port, struct tty_struct *tty)
}
if ((readb(ofsAddr + FlagStat) & Xoff_state) && (remain < LowWater)) {
moxaLowWaterChk = 1;
- moxaLowChkFlag[port] = 1;
+ moxa_ports[port].lowChkFlag = 1;
}
return (total);
}
@@ -2516,7 +2334,7 @@ int MoxaPortTxQueue(int port)
ushort rptr, wptr, mask;
int len;
- ofsAddr = moxaTableAddr[port];
+ ofsAddr = moxa_ports[port].tableAddr;
rptr = readw(ofsAddr + TXrptr);
wptr = readw(ofsAddr + TXwptr);
mask = readw(ofsAddr + TX_mask);
@@ -2530,7 +2348,7 @@ int MoxaPortTxFree(int port)
ushort rptr, wptr, mask;
int len;
- ofsAddr = moxaTableAddr[port];
+ ofsAddr = moxa_ports[port].tableAddr;
rptr = readw(ofsAddr + TXrptr);
wptr = readw(ofsAddr + TXwptr);
mask = readw(ofsAddr + TX_mask);
@@ -2544,7 +2362,7 @@ int MoxaPortRxQueue(int port)
ushort rptr, wptr, mask;
int len;
- ofsAddr = moxaTableAddr[port];
+ ofsAddr = moxa_ports[port].tableAddr;
rptr = readw(ofsAddr + RXrptr);
wptr = readw(ofsAddr + RXwptr);
mask = readw(ofsAddr + RX_mask);
@@ -2557,7 +2375,7 @@ void MoxaPortTxDisable(int port)
{
void __iomem *ofsAddr;
- ofsAddr = moxaTableAddr[port];
+ ofsAddr = moxa_ports[port].tableAddr;
moxafunc(ofsAddr, FC_SetXoffState, Magic_code);
}
@@ -2565,7 +2383,7 @@ void MoxaPortTxEnable(int port)
{
void __iomem *ofsAddr;
- ofsAddr = moxaTableAddr[port];
+ ofsAddr = moxa_ports[port].tableAddr;
moxafunc(ofsAddr, FC_SetXonState, Magic_code);
}
@@ -2573,8 +2391,8 @@ void MoxaPortTxEnable(int port)
int MoxaPortResetBrkCnt(int port)
{
ushort cnt;
- cnt = moxaBreakCnt[port];
- moxaBreakCnt[port] = 0;
+ cnt = moxa_ports[port].breakCnt;
+ moxa_ports[port].breakCnt = 0;
return (cnt);
}
@@ -2583,7 +2401,7 @@ void MoxaPortSendBreak(int port, int ms100)
{
void __iomem *ofsAddr;
- ofsAddr = moxaTableAddr[port];
+ ofsAddr = moxa_ports[port].tableAddr;
if (ms100) {
moxafunc(ofsAddr, FC_SendBreak, Magic_code);
moxadelay(ms100 * (HZ / 10));
@@ -2594,7 +2412,7 @@ void MoxaPortSendBreak(int port, int ms100)
moxafunc(ofsAddr, FC_StopBreak, Magic_code);
}
-static int moxa_get_serial_info(struct moxa_str *info,
+static int moxa_get_serial_info(struct moxa_port *info,
struct serial_struct __user *retinfo)
{
struct serial_struct tmp;
@@ -2616,7 +2434,7 @@ static int moxa_get_serial_info(struct moxa_str *info,
}
-static int moxa_set_serial_info(struct moxa_str *info,
+static int moxa_set_serial_info(struct moxa_port *info,
struct serial_struct __user *new_info)
{
struct serial_struct new_serial;
@@ -2713,7 +2531,7 @@ static int moxaloadbios(int cardno, unsigned char __user *tmp, int len)
if(copy_from_user(moxaBuff, tmp, len))
return -EFAULT;
- baseAddr = moxaBaseAddr[cardno];
+ baseAddr = moxa_boards[cardno].basemem;
writeb(HW_reset, baseAddr + Control_reg); /* reset */
moxadelay(1); /* delay 10 ms */
for (i = 0; i < 4096; i++)
@@ -2729,7 +2547,7 @@ static int moxafindcard(int cardno)
void __iomem *baseAddr;
ushort tmp;
- baseAddr = moxaBaseAddr[cardno];
+ baseAddr = moxa_boards[cardno].basemem;
switch (moxa_boards[cardno].boardType) {
case MOXA_BOARD_C218_ISA:
case MOXA_BOARD_C218_PCI:
@@ -2762,7 +2580,7 @@ static int moxaload320b(int cardno, unsigned char __user *tmp, int len)
return -EINVAL;
if(copy_from_user(moxaBuff, tmp, len))
return -EFAULT;
- baseAddr = moxaBaseAddr[cardno];
+ baseAddr = moxa_boards[cardno].basemem;
writew(len - 7168 - 2, baseAddr + C320bapi_len);
writeb(1, baseAddr + Control_reg); /* Select Page 1 */
for (i = 0; i < 7168; i++)
@@ -2780,7 +2598,7 @@ static int moxaloadcode(int cardno, unsigned char __user *tmp, int len)
if(copy_from_user(moxaBuff, tmp, len))
return -EFAULT;
- baseAddr = moxaBaseAddr[cardno];
+ baseAddr = moxa_boards[cardno].basemem;
switch (moxa_boards[cardno].boardType) {
case MOXA_BOARD_C218_ISA:
case MOXA_BOARD_C218_PCI:
@@ -2790,11 +2608,13 @@ static int moxaloadcode(int cardno, unsigned char __user *tmp, int len)
return (retval);
port = cardno * MAX_PORTS_PER_BOARD;
for (i = 0; i < moxa_boards[cardno].numPorts; i++, port++) {
- moxaChkPort[port] = 1;
- moxaCurBaud[port] = 9600L;
- moxaDCDState[port] = 0;
- moxaTableAddr[port] = baseAddr + Extern_table + Extern_size * i;
- ofsAddr = moxaTableAddr[port];
+ struct moxa_port *p = &moxa_ports[port];
+
+ p->chkPort = 1;
+ p->curBaud = 9600L;
+ p->DCDState = 0;
+ p->tableAddr = baseAddr + Extern_table + Extern_size * i;
+ ofsAddr = p->tableAddr;
writew(C218rx_mask, ofsAddr + RX_mask);
writew(C218tx_mask, ofsAddr + TX_mask);
writew(C218rx_spage + i * C218buf_pageno, ofsAddr + Page_rxb);
@@ -2812,11 +2632,13 @@ static int moxaloadcode(int cardno, unsigned char __user *tmp, int len)
return (retval);
port = cardno * MAX_PORTS_PER_BOARD;
for (i = 0; i < moxa_boards[cardno].numPorts; i++, port++) {
- moxaChkPort[port] = 1;
- moxaCurBaud[port] = 9600L;
- moxaDCDState[port] = 0;
- moxaTableAddr[port] = baseAddr + Extern_table + Extern_size * i;
- ofsAddr = moxaTableAddr[port];
+ struct moxa_port *p = &moxa_ports[port];
+
+ p->chkPort = 1;
+ p->curBaud = 9600L;
+ p->DCDState = 0;
+ p->tableAddr = baseAddr + Extern_table + Extern_size * i;
+ ofsAddr = p->tableAddr;
if (moxa_boards[cardno].numPorts == 8) {
writew(C320p8rx_mask, ofsAddr + RX_mask);
writew(C320p8tx_mask, ofsAddr + TX_mask);
@@ -2852,7 +2674,7 @@ static int moxaloadcode(int cardno, unsigned char __user *tmp, int len)
}
break;
}
- loadstat[cardno] = 1;
+ moxa_boards[cardno].loadstat = 1;
return (0);
}
@@ -2926,9 +2748,9 @@ static int moxaloadc218(int cardno, void __iomem *baseAddr, int len)
return (-1);
}
moxaCard = 1;
- moxaIntNdx[cardno] = baseAddr + IRQindex;
- moxaIntPend[cardno] = baseAddr + IRQpending;
- moxaIntTable[cardno] = baseAddr + IRQtable;
+ moxa_boards[cardno].intNdx = baseAddr + IRQindex;
+ moxa_boards[cardno].intPend = baseAddr + IRQpending;
+ moxa_boards[cardno].intTable = baseAddr + IRQtable;
return (0);
}
@@ -3021,25 +2843,15 @@ static int moxaloadc320(int cardno, void __iomem *baseAddr, int len, int *numPor
if (readw(baseAddr + Magic_no) != Magic_code)
return (-102);
moxaCard = 1;
- moxaIntNdx[cardno] = baseAddr + IRQindex;
- moxaIntPend[cardno] = baseAddr + IRQpending;
- moxaIntTable[cardno] = baseAddr + IRQtable;
+ moxa_boards[cardno].intNdx = baseAddr + IRQindex;
+ moxa_boards[cardno].intPend = baseAddr + IRQpending;
+ moxa_boards[cardno].intTable = baseAddr + IRQtable;
return (0);
}
-#if 0
-long MoxaPortGetCurBaud(int port)
-{
-
- if (moxaChkPort[port] == 0)
- return (0);
- return (moxaCurBaud[port]);
-}
-#endif /* 0 */
-
static void MoxaSetFifo(int port, int enable)
{
- void __iomem *ofsAddr = moxaTableAddr[port];
+ void __iomem *ofsAddr = moxa_ports[port].tableAddr;
if (!enable) {
moxafunc(ofsAddr, FC_SetRxFIFOTrig, 0);
@@ -3049,132 +2861,3 @@ static void MoxaSetFifo(int port, int enable)
moxafunc(ofsAddr, FC_SetTxFIFOCnt, 16);
}
}
-
-#if 0
-int MoxaPortSetMode(int port, int databits, int stopbits, int parity)
-{
- void __iomem *ofsAddr;
- int val;
-
- val = 0;
- switch (databits) {
- case 5:
- val |= 0;
- break;
- case 6:
- val |= 1;
- break;
- case 7:
- val |= 2;
- break;
- case 8:
- val |= 3;
- break;
- default:
- return (-1);
- }
- switch (stopbits) {
- case 0:
- val |= 0;
- break; /* stop bits 1.5 */
- case 1:
- val |= 0;
- break;
- case 2:
- val |= 4;
- break;
- default:
- return (-1);
- }
- switch (parity) {
- case 0:
- val |= 0x00;
- break; /* None */
- case 1:
- val |= 0x08;
- break; /* Odd */
- case 2:
- val |= 0x18;
- break; /* Even */
- case 3:
- val |= 0x28;
- break; /* Mark */
- case 4:
- val |= 0x38;
- break; /* Space */
- default:
- return (-1);
- }
- ofsAddr = moxaTableAddr[port];
- moxafunc(ofsAddr, FC_SetMode, val);
- return (0);
-}
-
-int MoxaPortTxBufSize(int port)
-{
- void __iomem *ofsAddr;
- int size;
-
- ofsAddr = moxaTableAddr[port];
- size = readw(ofsAddr + TX_mask);
- return (size);
-}
-
-int MoxaPortRxBufSize(int port)
-{
- void __iomem *ofsAddr;
- int size;
-
- ofsAddr = moxaTableAddr[port];
- size = readw(ofsAddr + RX_mask);
- return (size);
-}
-
-int MoxaPortRxFree(int port)
-{
- void __iomem *ofsAddr;
- ushort rptr, wptr, mask;
- int len;
-
- ofsAddr = moxaTableAddr[port];
- rptr = readw(ofsAddr + RXrptr);
- wptr = readw(ofsAddr + RXwptr);
- mask = readw(ofsAddr + RX_mask);
- len = mask - ((wptr - rptr) & mask);
- return (len);
-}
-int MoxaPortGetBrkCnt(int port)
-{
- return (moxaBreakCnt[port]);
-}
-
-void MoxaPortSetXonXoff(int port, int xonValue, int xoffValue)
-{
- void __iomem *ofsAddr;
-
- ofsAddr = moxaTableAddr[port];
- writew(xonValue, ofsAddr + FuncArg);
- writew(xoffValue, ofsAddr + FuncArg1);
- writew(FC_SetXonXoff, ofsAddr + FuncCode);
- wait_finish(ofsAddr);
-}
-
-int MoxaPortIsTxHold(int port)
-{
- void __iomem *ofsAddr;
- int val;
-
- ofsAddr = moxaTableAddr[port];
- if ((moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_ISA) ||
- (moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_PCI)) {
- moxafunc(ofsAddr, FC_GetCCSR, 0);
- val = readw(ofsAddr + FuncArg);
- if (val & 0x04)
- return (1);
- } else {
- if (readw(ofsAddr + FlagStat) & Tx_flowOff)
- return (1);
- }
- return (0);
-}
-#endif
diff --git a/drivers/char/mspec.c b/drivers/char/mspec.c
index 235e8922611..7ac30612068 100644
--- a/drivers/char/mspec.c
+++ b/drivers/char/mspec.c
@@ -291,7 +291,7 @@ uncached_mmap(struct file *file, struct vm_area_struct *vma)
return mspec_mmap(file, vma, MSPEC_UNCACHED);
}
-static struct file_operations fetchop_fops = {
+static const struct file_operations fetchop_fops = {
.owner = THIS_MODULE,
.mmap = fetchop_mmap
};
@@ -302,7 +302,7 @@ static struct miscdevice fetchop_miscdev = {
.fops = &fetchop_fops
};
-static struct file_operations cached_fops = {
+static const struct file_operations cached_fops = {
.owner = THIS_MODULE,
.mmap = cached_mmap
};
@@ -313,7 +313,7 @@ static struct miscdevice cached_miscdev = {
.fops = &cached_fops
};
-static struct file_operations uncached_fops = {
+static const struct file_operations uncached_fops = {
.owner = THIS_MODULE,
.mmap = uncached_mmap
};
diff --git a/drivers/char/mwave/3780i.c b/drivers/char/mwave/3780i.c
index 4e4865e90e5..492dbfb2efd 100644
--- a/drivers/char/mwave/3780i.c
+++ b/drivers/char/mwave/3780i.c
@@ -63,8 +63,6 @@
#include "3780i.h"
static DEFINE_SPINLOCK(dsp_lock);
-static unsigned long flags;
-
static void PaceMsaAccess(unsigned short usDspBaseIO)
{
@@ -76,6 +74,7 @@ static void PaceMsaAccess(unsigned short usDspBaseIO)
unsigned short dsp3780I_ReadMsaCfg(unsigned short usDspBaseIO,
unsigned long ulMsaAddr)
{
+ unsigned long flags;
unsigned short val;
PRINTK_3(TRACE_3780I,
@@ -96,6 +95,7 @@ unsigned short dsp3780I_ReadMsaCfg(unsigned short usDspBaseIO,
void dsp3780I_WriteMsaCfg(unsigned short usDspBaseIO,
unsigned long ulMsaAddr, unsigned short usValue)
{
+ unsigned long flags;
PRINTK_4(TRACE_3780I,
"3780i::dsp3780i_WriteMsaCfg entry usDspBaseIO %x ulMsaAddr %lx usValue %x\n",
@@ -175,6 +175,7 @@ int dsp3780I_EnableDSP(DSP_3780I_CONFIG_SETTINGS * pSettings,
unsigned short *pIrqMap,
unsigned short *pDmaMap)
{
+ unsigned long flags;
unsigned short usDspBaseIO = pSettings->usDspBaseIO;
int i;
DSP_UART_CFG_1 rUartCfg1;
@@ -354,6 +355,7 @@ int dsp3780I_EnableDSP(DSP_3780I_CONFIG_SETTINGS * pSettings,
int dsp3780I_DisableDSP(DSP_3780I_CONFIG_SETTINGS * pSettings)
{
+ unsigned long flags;
unsigned short usDspBaseIO = pSettings->usDspBaseIO;
DSP_ISA_SLAVE_CONTROL rSlaveControl;
@@ -383,6 +385,7 @@ int dsp3780I_DisableDSP(DSP_3780I_CONFIG_SETTINGS * pSettings)
int dsp3780I_Reset(DSP_3780I_CONFIG_SETTINGS * pSettings)
{
+ unsigned long flags;
unsigned short usDspBaseIO = pSettings->usDspBaseIO;
DSP_BOOT_DOMAIN rBootDomain;
DSP_HBRIDGE_CONTROL rHBridgeControl;
@@ -427,6 +430,7 @@ int dsp3780I_Reset(DSP_3780I_CONFIG_SETTINGS * pSettings)
int dsp3780I_Run(DSP_3780I_CONFIG_SETTINGS * pSettings)
{
+ unsigned long flags;
unsigned short usDspBaseIO = pSettings->usDspBaseIO;
DSP_BOOT_DOMAIN rBootDomain;
DSP_HBRIDGE_CONTROL rHBridgeControl;
@@ -473,6 +477,7 @@ int dsp3780I_Run(DSP_3780I_CONFIG_SETTINGS * pSettings)
int dsp3780I_ReadDStore(unsigned short usDspBaseIO, void __user *pvBuffer,
unsigned uCount, unsigned long ulDSPAddr)
{
+ unsigned long flags;
unsigned short __user *pusBuffer = pvBuffer;
unsigned short val;
@@ -514,6 +519,7 @@ int dsp3780I_ReadAndClearDStore(unsigned short usDspBaseIO,
void __user *pvBuffer, unsigned uCount,
unsigned long ulDSPAddr)
{
+ unsigned long flags;
unsigned short __user *pusBuffer = pvBuffer;
unsigned short val;
@@ -555,6 +561,7 @@ int dsp3780I_ReadAndClearDStore(unsigned short usDspBaseIO,
int dsp3780I_WriteDStore(unsigned short usDspBaseIO, void __user *pvBuffer,
unsigned uCount, unsigned long ulDSPAddr)
{
+ unsigned long flags;
unsigned short __user *pusBuffer = pvBuffer;
@@ -596,6 +603,7 @@ int dsp3780I_WriteDStore(unsigned short usDspBaseIO, void __user *pvBuffer,
int dsp3780I_ReadIStore(unsigned short usDspBaseIO, void __user *pvBuffer,
unsigned uCount, unsigned long ulDSPAddr)
{
+ unsigned long flags;
unsigned short __user *pusBuffer = pvBuffer;
PRINTK_5(TRACE_3780I,
@@ -643,6 +651,7 @@ int dsp3780I_ReadIStore(unsigned short usDspBaseIO, void __user *pvBuffer,
int dsp3780I_WriteIStore(unsigned short usDspBaseIO, void __user *pvBuffer,
unsigned uCount, unsigned long ulDSPAddr)
{
+ unsigned long flags;
unsigned short __user *pusBuffer = pvBuffer;
PRINTK_5(TRACE_3780I,
@@ -691,6 +700,7 @@ int dsp3780I_WriteIStore(unsigned short usDspBaseIO, void __user *pvBuffer,
int dsp3780I_GetIPCSource(unsigned short usDspBaseIO,
unsigned short *pusIPCSource)
{
+ unsigned long flags;
DSP_HBRIDGE_CONTROL rHBridgeControl;
unsigned short temp;
diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c
index 83f604b1929..a61fb6da5d0 100644
--- a/drivers/char/mxser.c
+++ b/drivers/char/mxser.c
@@ -321,8 +321,6 @@ struct mxser_struct {
unsigned long event;
int count; /* # of fd on device */
int blocked_open; /* # of blocked opens */
- long session; /* Session of opening process */
- long pgrp; /* pgrp of opening process */
unsigned char *xmit_buf;
int xmit_head;
int xmit_tail;
@@ -1001,15 +999,12 @@ static int mxser_open(struct tty_struct *tty, struct file *filp)
mxser_change_speed(info, NULL);
}
- info->session = process_session(current);
- info->pgrp = process_group(current);
-
/*
status = mxser_get_msr(info->base, 0, info->port);
mxser_check_modem_status(info, status);
*/
-/* unmark here for very high baud rate (ex. 921600 bps) used */
+ /* unmark here for very high baud rate (ex. 921600 bps) used */
tty->low_latency = 1;
return 0;
}
@@ -1254,9 +1249,7 @@ static void mxser_flush_buffer(struct tty_struct *tty)
spin_unlock_irqrestore(&info->slock, flags);
/* above added by shinhay */
- wake_up_interruptible(&tty->write_wait);
- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
- (tty->ldisc.write_wakeup) (tty);
+ tty_wakeup(tty);
}
static int mxser_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
diff --git a/drivers/char/mxser.h b/drivers/char/mxser.h
index 7e188a4d602..9fe28497eae 100644
--- a/drivers/char/mxser.h
+++ b/drivers/char/mxser.h
@@ -439,12 +439,4 @@
#define READ_MOXA_MUST_GDL(baseio) inb((baseio)+MOXA_MUST_GDL_REGISTER)
-
-#ifndef INIT_WORK
-#define INIT_WORK(_work, _func, _data){ \
- _data->tqueue.routine = _func;\
- _data->tqueue.data = _data;\
- }
-#endif
-
#endif
diff --git a/drivers/char/mxser_new.c b/drivers/char/mxser_new.c
index 1bb030b3a51..9af07e4999d 100644
--- a/drivers/char/mxser_new.c
+++ b/drivers/char/mxser_new.c
@@ -49,22 +49,25 @@
#include "mxser_new.h"
-#define MXSER_VERSION "2.0"
+#define MXSER_VERSION "2.0.1" /* 1.9.15 */
#define MXSERMAJOR 174
#define MXSERCUMAJOR 175
-#define MXSER_EVENT_TXLOW 1
-
#define MXSER_BOARDS 4 /* Max. boards */
#define MXSER_PORTS_PER_BOARD 8 /* Max. ports per board */
#define MXSER_PORTS (MXSER_BOARDS * MXSER_PORTS_PER_BOARD)
-#define MXSER_ISR_PASS_LIMIT 99999L
+#define MXSER_ISR_PASS_LIMIT 100
#define MXSER_ERR_IOADDR -1
#define MXSER_ERR_IRQ -2
#define MXSER_ERR_IRQ_CONFLIT -3
#define MXSER_ERR_VECTOR -4
+/*CheckIsMoxaMust return value*/
+#define MOXA_OTHER_UART 0x00
+#define MOXA_MUST_MU150_HWID 0x01
+#define MOXA_MUST_MU860_HWID 0x02
+
#define WAKEUP_CHARS 256
#define UART_MCR_AFE 0x20
@@ -176,6 +179,18 @@ static struct pci_device_id mxser_pcibrds[] = {
};
MODULE_DEVICE_TABLE(pci, mxser_pcibrds);
+static int mxvar_baud_table[] = {
+ 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400,
+ 4800, 9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600
+};
+static unsigned int mxvar_baud_table1[] = {
+ 0, B50, B75, B110, B134, B150, B200, B300, B600, B1200, B1800, B2400,
+ B4800, B9600, B19200, B38400, B57600, B115200, B230400, B460800, B921600
+};
+#define BAUD_TABLE_NO ARRAY_SIZE(mxvar_baud_table)
+
+#define B_SPEC B2000000
+
static int ioaddr[MXSER_BOARDS] = { 0, 0, 0, 0 };
static int ttymajor = MXSERMAJOR;
static int calloutmajor = MXSERCUMAJOR;
@@ -237,8 +252,7 @@ struct mxser_port {
long realbaud;
int type; /* UART type */
int flags; /* defined in tty.h */
- long session; /* Session of opening process */
- long pgrp; /* pgrp of opening process */
+ int speed;
int x_char; /* xon/xoff character */
int IER; /* Interrupt Enable Register */
@@ -267,14 +281,11 @@ struct mxser_port {
int xmit_cnt;
struct ktermios normal_termios;
- struct ktermios callout_termios;
struct mxser_mon mon_data;
spinlock_t slock;
- struct work_struct tqueue;
wait_queue_head_t open_wait;
- wait_queue_head_t close_wait;
wait_queue_head_t delta_msr_wait;
};
@@ -313,10 +324,9 @@ static int mxvar_diagflag;
static unsigned char mxser_msr[MXSER_PORTS + 1];
static struct mxser_mon_ext mon_data_ext;
static int mxser_set_baud_method[MXSER_PORTS + 1];
-static spinlock_t gm_lock;
#ifdef CONFIG_PCI
-static int CheckIsMoxaMust(int io)
+static int __devinit CheckIsMoxaMust(int io)
{
u8 oldmcr, hwid;
int i;
@@ -360,15 +370,6 @@ static void process_txrx_fifo(struct mxser_port *info)
}
}
-static void mxser_do_softint(struct work_struct *work)
-{
- struct mxser_port *info = container_of(work, struct mxser_port, tqueue);
- struct tty_struct *tty = info->tty;
-
- if (test_and_clear_bit(MXSER_EVENT_TXLOW, &info->event))
- tty_wakeup(tty);
-}
-
static unsigned char mxser_get_msr(int baseaddr, int mode, int port)
{
unsigned char status = 0;
@@ -456,10 +457,10 @@ static int mxser_block_til_ready(struct tty_struct *tty, struct file *filp,
static int mxser_set_baud(struct mxser_port *info, long newspd)
{
+ unsigned int i;
int quot = 0;
unsigned char cval;
int ret = 0;
- unsigned long flags;
if (!info->tty || !info->tty->termios)
return ret;
@@ -471,29 +472,34 @@ static int mxser_set_baud(struct mxser_port *info, long newspd)
return 0;
info->realbaud = newspd;
- if (newspd == 134) {
- quot = (2 * info->baud_base / 269);
- } else if (newspd) {
- quot = info->baud_base / newspd;
- if (quot == 0)
- quot = 1;
+ for (i = 0; i < BAUD_TABLE_NO; i++)
+ if (newspd == mxvar_baud_table[i])
+ break;
+ if (i == BAUD_TABLE_NO) {
+ quot = info->baud_base / info->speed;
+ if (info->speed <= 0 || info->speed > info->max_baud)
+ quot = 0;
} else {
- quot = 0;
+ if (newspd == 134) {
+ quot = (2 * info->baud_base / 269);
+ } else if (newspd) {
+ quot = info->baud_base / newspd;
+ if (quot == 0)
+ quot = 1;
+ } else {
+ quot = 0;
+ }
}
info->timeout = ((info->xmit_fifo_size * HZ * 10 * quot) / info->baud_base);
info->timeout += HZ / 50; /* Add .02 seconds of slop */
if (quot) {
- spin_lock_irqsave(&info->slock, flags);
info->MCR |= UART_MCR_DTR;
outb(info->MCR, info->ioaddr + UART_MCR);
- spin_unlock_irqrestore(&info->slock, flags);
} else {
- spin_lock_irqsave(&info->slock, flags);
info->MCR &= ~UART_MCR_DTR;
outb(info->MCR, info->ioaddr + UART_MCR);
- spin_unlock_irqrestore(&info->slock, flags);
return ret;
}
@@ -505,6 +511,18 @@ static int mxser_set_baud(struct mxser_port *info, long newspd)
outb(quot >> 8, info->ioaddr + UART_DLM); /* MS of divisor */
outb(cval, info->ioaddr + UART_LCR); /* reset DLAB */
+ if (i == BAUD_TABLE_NO) {
+ quot = info->baud_base % info->speed;
+ quot *= 8;
+ if ((quot % info->speed) > (info->speed / 2)) {
+ quot /= info->speed;
+ quot++;
+ } else {
+ quot /= info->speed;
+ }
+ SET_MOXA_MUST_ENUM_VALUE(info->ioaddr, quot);
+ } else
+ SET_MOXA_MUST_ENUM_VALUE(info->ioaddr, 0);
return ret;
}
@@ -520,7 +538,6 @@ static int mxser_change_speed(struct mxser_port *info,
int ret = 0;
unsigned char status;
long baud;
- unsigned long flags;
if (!info->tty || !info->tty->termios)
return ret;
@@ -529,7 +546,10 @@ static int mxser_change_speed(struct mxser_port *info,
return ret;
if (mxser_set_baud_method[info->tty->index] == 0) {
- baud = tty_get_baud_rate(info->tty);
+ if ((cflag & CBAUD) == B_SPEC)
+ baud = info->speed;
+ else
+ baud = tty_get_baud_rate(info->tty);
mxser_set_baud(info, baud);
}
@@ -612,8 +632,8 @@ static int mxser_change_speed(struct mxser_port *info,
outb(info->IER, info->ioaddr +
UART_IER);
}
- set_bit(MXSER_EVENT_TXLOW, &info->event);
- schedule_work(&info->tqueue); }
+ tty_wakeup(info->tty);
+ }
} else {
if (!(status & UART_MSR_CTS)) {
info->tty->hw_stopped = 1;
@@ -668,7 +688,6 @@ static int mxser_change_speed(struct mxser_port *info,
}
}
if (info->board->chip_flag) {
- spin_lock_irqsave(&info->slock, flags);
SET_MOXA_MUST_XON1_VALUE(info->ioaddr, START_CHAR(info->tty));
SET_MOXA_MUST_XOFF1_VALUE(info->ioaddr, STOP_CHAR(info->tty));
if (I_IXON(info->tty)) {
@@ -681,7 +700,6 @@ static int mxser_change_speed(struct mxser_port *info,
} else {
DISABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(info->ioaddr);
}
- spin_unlock_irqrestore(&info->slock, flags);
}
@@ -708,7 +726,6 @@ static void mxser_check_modem_status(struct mxser_port *port, int status)
if ((port->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) {
if (status & UART_MSR_DCD)
wake_up_interruptible(&port->open_wait);
- schedule_work(&port->tqueue);
}
if (port->flags & ASYNC_CTS_FLOW) {
@@ -724,8 +741,7 @@ static void mxser_check_modem_status(struct mxser_port *port, int status)
outb(port->IER, port->ioaddr +
UART_IER);
}
- set_bit(MXSER_EVENT_TXLOW, &port->event);
- schedule_work(&port->tqueue);
+ tty_wakeup(port->tty);
}
} else {
if (!(status & UART_MSR_CTS)) {
@@ -836,10 +852,10 @@ static int mxser_startup(struct mxser_port *info)
/*
* and set the speed of the serial port
*/
- spin_unlock_irqrestore(&info->slock, flags);
mxser_change_speed(info, NULL);
-
info->flags |= ASYNC_INITIALIZED;
+ spin_unlock_irqrestore(&info->slock, flags);
+
return 0;
}
@@ -909,11 +925,9 @@ static void mxser_shutdown(struct mxser_port *info)
static int mxser_open(struct tty_struct *tty, struct file *filp)
{
struct mxser_port *info;
+ unsigned long flags;
int retval, line;
- /* initialize driver_data in case something fails */
- tty->driver_data = NULL;
-
line = tty->index;
if (line == MXSER_PORTS)
return 0;
@@ -928,7 +942,9 @@ static int mxser_open(struct tty_struct *tty, struct file *filp)
/*
* Start up serial port
*/
+ spin_lock_irqsave(&info->slock, flags);
info->count++;
+ spin_unlock_irqrestore(&info->slock, flags);
retval = mxser_startup(info);
if (retval)
return retval;
@@ -937,17 +953,6 @@ static int mxser_open(struct tty_struct *tty, struct file *filp)
if (retval)
return retval;
- if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) {
- if (tty->driver->subtype == SERIAL_TYPE_NORMAL)
- *tty->termios = info->normal_termios;
- else
- *tty->termios = info->callout_termios;
- mxser_change_speed(info, NULL);
- }
-
- info->session = process_session(current);
- info->pgrp = process_group(current);
-
/* unmark here for very high baud rate (ex. 921600 bps) used */
tty->low_latency = 1;
return 0;
@@ -1054,8 +1059,6 @@ static void mxser_close(struct tty_struct *tty, struct file *filp)
}
info->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
- wake_up_interruptible(&info->close_wait);
-
}
static int mxser_write(struct tty_struct *tty, const unsigned char *buf, int count)
@@ -1222,6 +1225,7 @@ static int mxser_set_serial_info(struct mxser_port *info,
struct serial_struct __user *new_info)
{
struct serial_struct new_serial;
+ unsigned long sl_flags;
unsigned int flags;
int retval = 0;
@@ -1264,8 +1268,11 @@ static int mxser_set_serial_info(struct mxser_port *info,
process_txrx_fifo(info);
if (info->flags & ASYNC_INITIALIZED) {
- if (flags != (info->flags & ASYNC_SPD_MASK))
+ if (flags != (info->flags & ASYNC_SPD_MASK)) {
+ spin_lock_irqsave(&info->slock, sl_flags);
mxser_change_speed(info, NULL);
+ spin_unlock_irqrestore(&info->slock, sl_flags);
+ }
} else
retval = mxser_startup(info);
@@ -1373,11 +1380,10 @@ static int mxser_tiocmset(struct tty_struct *tty, struct file *file,
return 0;
}
-static int mxser_program_mode(int port)
+static int __init mxser_program_mode(int port)
{
int id, i, j, n;
- spin_lock(&gm_lock);
outb(0, port);
outb(0, port);
outb(0, port);
@@ -1385,7 +1391,6 @@ static int mxser_program_mode(int port)
(void)inb(port);
outb(0, port);
(void)inb(port);
- spin_unlock(&gm_lock);
id = inb(port + 1) & 0x1F;
if ((id != C168_ASIC_ID) &&
@@ -1410,7 +1415,7 @@ static int mxser_program_mode(int port)
return id;
}
-static void mxser_normal_mode(int port)
+static void __init mxser_normal_mode(int port)
{
int i, n;
@@ -1443,7 +1448,7 @@ static void mxser_normal_mode(int port)
#define EN0_PORT 0x010 /* Rcv missed frame error counter RD */
#define ENC_PAGE0 0x000 /* Select page 0 of chip registers */
#define ENC_PAGE3 0x0C0 /* Select page 3 of chip registers */
-static int mxser_read_register(int port, unsigned short *regs)
+static int __init mxser_read_register(int port, unsigned short *regs)
{
int i, k, value, id;
unsigned int j;
@@ -1644,6 +1649,7 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
struct serial_icounter_struct __user *p_cuser;
unsigned long templ;
unsigned long flags;
+ unsigned int i;
void __user *argp = (void __user *)arg;
int retval;
@@ -1682,6 +1688,36 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
return 0;
}
+ if (cmd == MOXA_SET_SPECIAL_BAUD_RATE) {
+ int speed;
+
+ if (get_user(speed, (int __user *)argp))
+ return -EFAULT;
+ if (speed <= 0 || speed > info->max_baud)
+ return -EFAULT;
+ if (!info->tty || !info->tty->termios || !info->ioaddr)
+ return 0;
+ info->tty->termios->c_cflag &= ~(CBAUD | CBAUDEX);
+ for (i = 0; i < BAUD_TABLE_NO; i++)
+ if (speed == mxvar_baud_table[i])
+ break;
+ if (i == BAUD_TABLE_NO) {
+ info->tty->termios->c_cflag |= B_SPEC;
+ } else if (speed != 0)
+ info->tty->termios->c_cflag |= mxvar_baud_table1[i];
+
+ info->speed = speed;
+ spin_lock_irqsave(&info->slock, flags);
+ mxser_change_speed(info, NULL);
+ spin_unlock_irqrestore(&info->slock, flags);
+
+ return 0;
+ } else if (cmd == MOXA_GET_SPECIAL_BAUD_RATE) {
+ if (copy_to_user(argp, &info->speed, sizeof(int)))
+ return -EFAULT;
+ return 0;
+ }
+
if (cmd != TIOCGSERIAL && cmd != TIOCMIWAIT && cmd != TIOCGICOUNT &&
test_bit(TTY_IO_ERROR, &tty->flags))
return -EIO;
@@ -1799,7 +1835,9 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
long baud;
if (get_user(baud, (long __user *)argp))
return -EFAULT;
+ spin_lock_irqsave(&info->slock, flags);
mxser_set_baud(info, baud);
+ spin_unlock_irqrestore(&info->slock, flags);
return 0;
}
case MOXA_ASPP_GETBAUD:
@@ -1976,7 +2014,9 @@ static void mxser_set_termios(struct tty_struct *tty, struct ktermios *old_termi
if ((tty->termios->c_cflag != old_termios->c_cflag) ||
(RELEVANT_IFLAG(tty->termios->c_iflag) != RELEVANT_IFLAG(old_termios->c_iflag))) {
+ spin_lock_irqsave(&info->slock, flags);
mxser_change_speed(info, old_termios);
+ spin_unlock_irqrestore(&info->slock, flags);
if ((old_termios->c_cflag & CRTSCTS) &&
!(tty->termios->c_cflag & CRTSCTS)) {
@@ -2066,7 +2106,7 @@ static void mxser_wait_until_sent(struct tty_struct *tty, int timeout)
/*
* This routine is called by tty_hangup() when a hangup is signaled.
*/
-void mxser_hangup(struct tty_struct *tty)
+static void mxser_hangup(struct tty_struct *tty)
{
struct mxser_port *info = tty->driver_data;
@@ -2105,9 +2145,6 @@ static void mxser_receive_chars(struct mxser_port *port, int *status)
int cnt = 0;
int recv_room;
int max = 256;
- unsigned long flags;
-
- spin_lock_irqsave(&port->slock, flags);
recv_room = tty->receive_room;
if ((recv_room == 0) && (!port->ldisc_stop_rx))
@@ -2169,7 +2206,8 @@ intr_old:
} else if (*status & UART_LSR_OE) {
flag = TTY_OVERRUN;
port->icount.overrun++;
- }
+ } else
+ flag = TTY_BREAK;
}
tty_insert_flip_char(tty, ch, flag);
cnt++;
@@ -2191,7 +2229,6 @@ end_intr:
mxvar_log.rxcnt[port->tty->index] += cnt;
port->mon_data.rxcnt += cnt;
port->mon_data.up_rxcnt += cnt;
- spin_unlock_irqrestore(&port->slock, flags);
tty_flip_buffer_push(tty);
}
@@ -2199,9 +2236,6 @@ end_intr:
static void mxser_transmit_chars(struct mxser_port *port)
{
int count, cnt;
- unsigned long flags;
-
- spin_lock_irqsave(&port->slock, flags);
if (port->x_char) {
outb(port->x_char, port->ioaddr + UART_TX);
@@ -2210,11 +2244,11 @@ static void mxser_transmit_chars(struct mxser_port *port)
port->mon_data.txcnt++;
port->mon_data.up_txcnt++;
port->icount.tx++;
- goto unlock;
+ return;
}
if (port->xmit_buf == 0)
- goto unlock;
+ return;
if ((port->xmit_cnt <= 0) || port->tty->stopped ||
(port->tty->hw_stopped &&
@@ -2222,7 +2256,7 @@ static void mxser_transmit_chars(struct mxser_port *port)
(!port->board->chip_flag))) {
port->IER &= ~UART_IER_THRI;
outb(port->IER, port->ioaddr + UART_IER);
- goto unlock;
+ return;
}
cnt = port->xmit_cnt;
@@ -2240,16 +2274,13 @@ static void mxser_transmit_chars(struct mxser_port *port)
port->mon_data.up_txcnt += (cnt - port->xmit_cnt);
port->icount.tx += (cnt - port->xmit_cnt);
- if (port->xmit_cnt < WAKEUP_CHARS) {
- set_bit(MXSER_EVENT_TXLOW, &port->event);
- schedule_work(&port->tqueue);
- }
+ if (port->xmit_cnt < WAKEUP_CHARS)
+ tty_wakeup(port->tty);
+
if (port->xmit_cnt <= 0) {
port->IER &= ~UART_IER_THRI;
outb(port->IER, port->ioaddr + UART_IER);
}
-unlock:
- spin_unlock_irqrestore(&port->slock, flags);
}
/*
@@ -2261,8 +2292,7 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id)
struct mxser_board *brd = NULL;
struct mxser_port *port;
int max, irqbits, bits, msr;
- int pass_counter = 0;
- unsigned int int_cnt;
+ unsigned int int_cnt, pass_counter = 0;
int handled = IRQ_NONE;
for (i = 0; i < MXSER_BOARDS; i++)
@@ -2276,7 +2306,7 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id)
if (brd == NULL)
goto irq_stop;
max = brd->info->nports;
- while (1) {
+ while (pass_counter++ < MXSER_ISR_PASS_LIMIT) {
irqbits = inb(brd->vector) & brd->vector_mask;
if (irqbits == brd->vector_mask)
break;
@@ -2290,12 +2320,16 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id)
port = &brd->ports[i];
int_cnt = 0;
+ spin_lock(&port->slock);
do {
iir = inb(port->ioaddr + UART_IIR);
if (iir & UART_IIR_NO_INT)
break;
iir &= MOXA_MUST_IIR_MASK;
- if (!port->tty) {
+ if (!port->tty ||
+ (port->flags & ASYNC_CLOSING) ||
+ !(port->flags &
+ ASYNC_INITIALIZED)) {
status = inb(port->ioaddr + UART_LSR);
outb(0x27, port->ioaddr + UART_FCR);
inb(port->ioaddr + UART_MSR);
@@ -2341,9 +2375,8 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id)
mxser_transmit_chars(port);
}
} while (int_cnt++ < MXSER_ISR_PASS_LIMIT);
+ spin_unlock(&port->slock);
}
- if (pass_counter++ > MXSER_ISR_PASS_LIMIT)
- break; /* Prevent infinite loops */
}
irq_stop:
@@ -2385,7 +2418,6 @@ static void mxser_release_res(struct mxser_board *brd, struct pci_dev *pdev,
#ifdef CONFIG_PCI
pci_release_region(pdev, 2);
pci_release_region(pdev, 3);
- pci_dev_put(pdev);
#endif
} else {
release_region(brd->ports[0].ioaddr, 8 * brd->info->nports);
@@ -2420,11 +2452,10 @@ static int __devinit mxser_initbrd(struct mxser_board *brd,
info->custom_divisor = info->baud_base * 16;
info->close_delay = 5 * HZ / 10;
info->closing_wait = 30 * HZ;
- INIT_WORK(&info->tqueue, mxser_do_softint);
info->normal_termios = mxvar_sdriver->init_termios;
init_waitqueue_head(&info->open_wait);
- init_waitqueue_head(&info->close_wait);
init_waitqueue_head(&info->delta_msr_wait);
+ info->speed = 9600;
memset(&info->mon_data, 0, sizeof(struct mxser_mon));
info->err_shadow = 0;
spin_lock_init(&info->slock);
@@ -2433,22 +2464,17 @@ static int __devinit mxser_initbrd(struct mxser_board *brd,
outb(inb(info->ioaddr + UART_IER) & 0xf0,
info->ioaddr + UART_IER);
}
- /*
- * Allocate the IRQ if necessary
- */
- retval = request_irq(brd->irq, mxser_interrupt,
- (brd->ports[0].flags & ASYNC_SHARE_IRQ) ? IRQF_SHARED :
- IRQF_DISABLED, "mxser", brd);
+ retval = request_irq(brd->irq, mxser_interrupt, IRQF_SHARED, "mxser",
+ brd);
if (retval) {
printk(KERN_ERR "Board %s: Request irq failed, IRQ (%d) may "
"conflict with another device.\n",
brd->info->name, brd->irq);
/* We hold resources, we need to release them. */
mxser_release_res(brd, pdev, 0);
- return retval;
}
- return 0;
+ return retval;
}
static int __init mxser_get_ISA_conf(int cap, struct mxser_board *brd)
@@ -2633,8 +2659,9 @@ static int __devinit mxser_probe(struct pci_dev *pdev,
}
/* mxser_initbrd will hook ISR. */
- if (mxser_initbrd(brd, pdev) < 0)
- goto err_relvec;
+ retval = mxser_initbrd(brd, pdev);
+ if (retval)
+ goto err_null;
for (i = 0; i < brd->info->nports; i++)
tty_register_device(mxvar_sdriver, brd->idx + i, &pdev->dev);
@@ -2642,10 +2669,9 @@ static int __devinit mxser_probe(struct pci_dev *pdev,
pci_set_drvdata(pdev, brd);
return 0;
-err_relvec:
- pci_release_region(pdev, 3);
err_relio:
pci_release_region(pdev, 2);
+err_null:
brd->info = NULL;
err:
return retval;
@@ -2663,6 +2689,7 @@ static void __devexit mxser_remove(struct pci_dev *pdev)
tty_unregister_device(mxvar_sdriver, brd->idx + i);
mxser_release_res(brd, pdev, 1);
+ brd->info = NULL;
}
static struct pci_driver mxser_driver = {
@@ -2684,7 +2711,6 @@ static int __init mxser_module_init(void)
mxvar_sdriver = alloc_tty_driver(MXSER_PORTS + 1);
if (!mxvar_sdriver)
return -ENOMEM;
- spin_lock_init(&gm_lock);
printk(KERN_INFO "MOXA Smartio/Industio family driver version %s\n",
MXSER_VERSION);
diff --git a/drivers/char/mxser_new.h b/drivers/char/mxser_new.h
index a08f0ecb09b..d42f7766c65 100644
--- a/drivers/char/mxser_new.h
+++ b/drivers/char/mxser_new.h
@@ -26,18 +26,8 @@
#define RS422_MODE 2
#define RS485_4WIRE_MODE 3
#define OP_MODE_MASK 3
-// above add by Victor Yu. 01-05-2004
-
-#define TTY_THRESHOLD_THROTTLE 128
-
-#define LO_WATER (TTY_FLIPBUF_SIZE)
-#define HI_WATER (TTY_FLIPBUF_SIZE*2*3/4)
-
-// added by James. 03-11-2004.
-#define MOXA_SDS_GETICOUNTER (MOXA + 68)
-#define MOXA_SDS_RSTICOUNTER (MOXA + 69)
-// (above) added by James.
+#define MOXA_SDS_RSTICOUNTER (MOXA + 69)
#define MOXA_ASPP_OQUEUE (MOXA + 70)
#define MOXA_ASPP_SETBAUD (MOXA + 71)
#define MOXA_ASPP_GETBAUD (MOXA + 72)
@@ -45,7 +35,8 @@
#define MOXA_ASPP_LSTATUS (MOXA + 74)
#define MOXA_ASPP_MON_EXT (MOXA + 75)
#define MOXA_SET_BAUD_METHOD (MOXA + 76)
-
+#define MOXA_SET_SPECIAL_BAUD_RATE (MOXA + 77)
+#define MOXA_GET_SPECIAL_BAUD_RATE (MOXA + 78)
/* --------------------------------------------------- */
@@ -55,51 +46,46 @@
#define NPPI_NOTIFY_SW_OVERRUN 0x08
#define NPPI_NOTIFY_BREAK 0x10
-#define NPPI_NOTIFY_CTSHOLD 0x01 // Tx hold by CTS low
-#define NPPI_NOTIFY_DSRHOLD 0x02 // Tx hold by DSR low
-#define NPPI_NOTIFY_XOFFHOLD 0x08 // Tx hold by Xoff received
-#define NPPI_NOTIFY_XOFFXENT 0x10 // Xoff Sent
-
-//CheckIsMoxaMust return value
-#define MOXA_OTHER_UART 0x00
-#define MOXA_MUST_MU150_HWID 0x01
-#define MOXA_MUST_MU860_HWID 0x02
-
-// follow just for Moxa Must chip define.
-//
-// when LCR register (offset 0x03) write following value,
-// the Must chip will enter enchance mode. And write value
-// on EFR (offset 0x02) bit 6,7 to change bank.
+#define NPPI_NOTIFY_CTSHOLD 0x01 /* Tx hold by CTS low */
+#define NPPI_NOTIFY_DSRHOLD 0x02 /* Tx hold by DSR low */
+#define NPPI_NOTIFY_XOFFHOLD 0x08 /* Tx hold by Xoff received */
+#define NPPI_NOTIFY_XOFFXENT 0x10 /* Xoff Sent */
+
+/* follow just for Moxa Must chip define. */
+/* */
+/* when LCR register (offset 0x03) write following value, */
+/* the Must chip will enter enchance mode. And write value */
+/* on EFR (offset 0x02) bit 6,7 to change bank. */
#define MOXA_MUST_ENTER_ENCHANCE 0xBF
-// when enhance mode enable, access on general bank register
+/* when enhance mode enable, access on general bank register */
#define MOXA_MUST_GDL_REGISTER 0x07
#define MOXA_MUST_GDL_MASK 0x7F
#define MOXA_MUST_GDL_HAS_BAD_DATA 0x80
-#define MOXA_MUST_LSR_RERR 0x80 // error in receive FIFO
-// enchance register bank select and enchance mode setting register
-// when LCR register equal to 0xBF
+#define MOXA_MUST_LSR_RERR 0x80 /* error in receive FIFO */
+/* enchance register bank select and enchance mode setting register */
+/* when LCR register equal to 0xBF */
#define MOXA_MUST_EFR_REGISTER 0x02
-// enchance mode enable
+/* enchance mode enable */
#define MOXA_MUST_EFR_EFRB_ENABLE 0x10
-// enchance reister bank set 0, 1, 2
+/* enchance reister bank set 0, 1, 2 */
#define MOXA_MUST_EFR_BANK0 0x00
#define MOXA_MUST_EFR_BANK1 0x40
#define MOXA_MUST_EFR_BANK2 0x80
#define MOXA_MUST_EFR_BANK3 0xC0
#define MOXA_MUST_EFR_BANK_MASK 0xC0
-// set XON1 value register, when LCR=0xBF and change to bank0
+/* set XON1 value register, when LCR=0xBF and change to bank0 */
#define MOXA_MUST_XON1_REGISTER 0x04
-// set XON2 value register, when LCR=0xBF and change to bank0
+/* set XON2 value register, when LCR=0xBF and change to bank0 */
#define MOXA_MUST_XON2_REGISTER 0x05
-// set XOFF1 value register, when LCR=0xBF and change to bank0
+/* set XOFF1 value register, when LCR=0xBF and change to bank0 */
#define MOXA_MUST_XOFF1_REGISTER 0x06
-// set XOFF2 value register, when LCR=0xBF and change to bank0
+/* set XOFF2 value register, when LCR=0xBF and change to bank0 */
#define MOXA_MUST_XOFF2_REGISTER 0x07
#define MOXA_MUST_RBRTL_REGISTER 0x04
@@ -111,32 +97,32 @@
#define MOXA_MUST_ECR_REGISTER 0x06
#define MOXA_MUST_CSR_REGISTER 0x07
-// good data mode enable
+/* good data mode enable */
#define MOXA_MUST_FCR_GDA_MODE_ENABLE 0x20
-// only good data put into RxFIFO
+/* only good data put into RxFIFO */
#define MOXA_MUST_FCR_GDA_ONLY_ENABLE 0x10
-// enable CTS interrupt
+/* enable CTS interrupt */
#define MOXA_MUST_IER_ECTSI 0x80
-// enable RTS interrupt
+/* enable RTS interrupt */
#define MOXA_MUST_IER_ERTSI 0x40
-// enable Xon/Xoff interrupt
+/* enable Xon/Xoff interrupt */
#define MOXA_MUST_IER_XINT 0x20
-// enable GDA interrupt
+/* enable GDA interrupt */
#define MOXA_MUST_IER_EGDAI 0x10
#define MOXA_MUST_RECV_ISR (UART_IER_RDI | MOXA_MUST_IER_EGDAI)
-// GDA interrupt pending
+/* GDA interrupt pending */
#define MOXA_MUST_IIR_GDA 0x1C
#define MOXA_MUST_IIR_RDA 0x04
#define MOXA_MUST_IIR_RTO 0x0C
#define MOXA_MUST_IIR_LSR 0x06
-// recieved Xon/Xoff or specical interrupt pending
+/* recieved Xon/Xoff or specical interrupt pending */
#define MOXA_MUST_IIR_XSC 0x10
-// RTS/CTS change state interrupt pending
+/* RTS/CTS change state interrupt pending */
#define MOXA_MUST_IIR_RTSCTS 0x20
#define MOXA_MUST_IIR_MASK 0x3E
@@ -144,307 +130,164 @@
#define MOXA_MUST_MCR_XON_ANY 0x80
#define MOXA_MUST_MCR_TX_XON 0x08
-
-// software flow control on chip mask value
+/* software flow control on chip mask value */
#define MOXA_MUST_EFR_SF_MASK 0x0F
-// send Xon1/Xoff1
+/* send Xon1/Xoff1 */
#define MOXA_MUST_EFR_SF_TX1 0x08
-// send Xon2/Xoff2
+/* send Xon2/Xoff2 */
#define MOXA_MUST_EFR_SF_TX2 0x04
-// send Xon1,Xon2/Xoff1,Xoff2
+/* send Xon1,Xon2/Xoff1,Xoff2 */
#define MOXA_MUST_EFR_SF_TX12 0x0C
-// don't send Xon/Xoff
+/* don't send Xon/Xoff */
#define MOXA_MUST_EFR_SF_TX_NO 0x00
-// Tx software flow control mask
+/* Tx software flow control mask */
#define MOXA_MUST_EFR_SF_TX_MASK 0x0C
-// don't receive Xon/Xoff
+/* don't receive Xon/Xoff */
#define MOXA_MUST_EFR_SF_RX_NO 0x00
-// receive Xon1/Xoff1
+/* receive Xon1/Xoff1 */
#define MOXA_MUST_EFR_SF_RX1 0x02
-// receive Xon2/Xoff2
+/* receive Xon2/Xoff2 */
#define MOXA_MUST_EFR_SF_RX2 0x01
-// receive Xon1,Xon2/Xoff1,Xoff2
+/* receive Xon1,Xon2/Xoff1,Xoff2 */
#define MOXA_MUST_EFR_SF_RX12 0x03
-// Rx software flow control mask
+/* Rx software flow control mask */
#define MOXA_MUST_EFR_SF_RX_MASK 0x03
-//#define MOXA_MUST_MIN_XOFFLIMIT 66
-//#define MOXA_MUST_MIN_XONLIMIT 20
-//#define ID1_RX_TRIG 120
-
-
-#define CHECK_MOXA_MUST_XOFFLIMIT(info) { \
- if ( (info)->IsMoxaMustChipFlag && \
- (info)->HandFlow.XoffLimit < MOXA_MUST_MIN_XOFFLIMIT ) { \
- (info)->HandFlow.XoffLimit = MOXA_MUST_MIN_XOFFLIMIT; \
- (info)->HandFlow.XonLimit = MOXA_MUST_MIN_XONLIMIT; \
- } \
-}
-
-#define ENABLE_MOXA_MUST_ENCHANCE_MODE(baseio) { \
- u8 __oldlcr, __efr; \
- __oldlcr = inb((baseio)+UART_LCR); \
+#define ENABLE_MOXA_MUST_ENCHANCE_MODE(baseio) do { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
- __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
- __efr |= MOXA_MUST_EFR_EFRB_ENABLE; \
- outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
- outb(__oldlcr, (baseio)+UART_LCR); \
-}
-
-#define DISABLE_MOXA_MUST_ENCHANCE_MODE(baseio) { \
- u8 __oldlcr, __efr; \
- __oldlcr = inb((baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr |= MOXA_MUST_EFR_EFRB_ENABLE; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+} while (0)
+
+#define DISABLE_MOXA_MUST_ENCHANCE_MODE(baseio) do { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
- __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
- __efr &= ~MOXA_MUST_EFR_EFRB_ENABLE; \
- outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
- outb(__oldlcr, (baseio)+UART_LCR); \
-}
-
-#define SET_MOXA_MUST_XON1_VALUE(baseio, Value) { \
- u8 __oldlcr, __efr; \
- __oldlcr = inb((baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_EFRB_ENABLE; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+} while (0)
+
+#define SET_MOXA_MUST_XON1_VALUE(baseio, Value) do { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
- __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
- __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
- __efr |= MOXA_MUST_EFR_BANK0; \
- outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
+ __efr |= MOXA_MUST_EFR_BANK0; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
outb((u8)(Value), (baseio)+MOXA_MUST_XON1_REGISTER); \
- outb(__oldlcr, (baseio)+UART_LCR); \
-}
+ outb(__oldlcr, (baseio)+UART_LCR); \
+} while (0)
-#define SET_MOXA_MUST_XON2_VALUE(baseio, Value) { \
- u8 __oldlcr, __efr; \
- __oldlcr = inb((baseio)+UART_LCR); \
+#define SET_MOXA_MUST_XOFF1_VALUE(baseio, Value) do { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
- __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
- __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
- __efr |= MOXA_MUST_EFR_BANK0; \
- outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
- outb((u8)(Value), (baseio)+MOXA_MUST_XON2_REGISTER); \
- outb(__oldlcr, (baseio)+UART_LCR); \
-}
-
-#define SET_MOXA_MUST_XOFF1_VALUE(baseio, Value) { \
- u8 __oldlcr, __efr; \
- __oldlcr = inb((baseio)+UART_LCR); \
- outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
- __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
- __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
- __efr |= MOXA_MUST_EFR_BANK0; \
- outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
+ __efr |= MOXA_MUST_EFR_BANK0; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
outb((u8)(Value), (baseio)+MOXA_MUST_XOFF1_REGISTER); \
- outb(__oldlcr, (baseio)+UART_LCR); \
-}
+ outb(__oldlcr, (baseio)+UART_LCR); \
+} while (0)
-#define SET_MOXA_MUST_XOFF2_VALUE(baseio, Value) { \
- u8 __oldlcr, __efr; \
- __oldlcr = inb((baseio)+UART_LCR); \
- outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
- __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
- __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
- __efr |= MOXA_MUST_EFR_BANK0; \
- outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
- outb((u8)(Value), (baseio)+MOXA_MUST_XOFF2_REGISTER); \
- outb(__oldlcr, (baseio)+UART_LCR); \
-}
-
-#define SET_MOXA_MUST_RBRTL_VALUE(baseio, Value) { \
- u8 __oldlcr, __efr; \
- __oldlcr = inb((baseio)+UART_LCR); \
- outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
- __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
- __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
- __efr |= MOXA_MUST_EFR_BANK1; \
- outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
- outb((u8)(Value), (baseio)+MOXA_MUST_RBRTL_REGISTER); \
- outb(__oldlcr, (baseio)+UART_LCR); \
-}
-
-#define SET_MOXA_MUST_RBRTH_VALUE(baseio, Value) { \
- u8 __oldlcr, __efr; \
- __oldlcr = inb((baseio)+UART_LCR); \
- outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
- __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
- __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
- __efr |= MOXA_MUST_EFR_BANK1; \
- outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
- outb((u8)(Value), (baseio)+MOXA_MUST_RBRTH_REGISTER); \
- outb(__oldlcr, (baseio)+UART_LCR); \
-}
-
-#define SET_MOXA_MUST_RBRTI_VALUE(baseio, Value) { \
- u8 __oldlcr, __efr; \
- __oldlcr = inb((baseio)+UART_LCR); \
- outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
- __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
- __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
- __efr |= MOXA_MUST_EFR_BANK1; \
- outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
- outb((u8)(Value), (baseio)+MOXA_MUST_RBRTI_REGISTER); \
- outb(__oldlcr, (baseio)+UART_LCR); \
-}
-
-#define SET_MOXA_MUST_THRTL_VALUE(baseio, Value) { \
- u8 __oldlcr, __efr; \
- __oldlcr = inb((baseio)+UART_LCR); \
- outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
- __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
- __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
- __efr |= MOXA_MUST_EFR_BANK1; \
- outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
- outb((u8)(Value), (baseio)+MOXA_MUST_THRTL_REGISTER); \
- outb(__oldlcr, (baseio)+UART_LCR); \
-}
-
-//#define MOXA_MUST_RBRL_VALUE 4
-#define SET_MOXA_MUST_FIFO_VALUE(info) { \
- u8 __oldlcr, __efr; \
- __oldlcr = inb((info)->ioaddr+UART_LCR); \
- outb(MOXA_MUST_ENTER_ENCHANCE, (info)->ioaddr+UART_LCR); \
+#define SET_MOXA_MUST_FIFO_VALUE(info) do { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((info)->ioaddr+UART_LCR); \
+ outb(MOXA_MUST_ENTER_ENCHANCE, (info)->ioaddr+UART_LCR);\
__efr = inb((info)->ioaddr+MOXA_MUST_EFR_REGISTER); \
- __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
- __efr |= MOXA_MUST_EFR_BANK1; \
+ __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
+ __efr |= MOXA_MUST_EFR_BANK1; \
outb(__efr, (info)->ioaddr+MOXA_MUST_EFR_REGISTER); \
- outb((u8)((info)->rx_high_water), (info)->ioaddr+MOXA_MUST_RBRTH_REGISTER); \
- outb((u8)((info)->rx_trigger), (info)->ioaddr+MOXA_MUST_RBRTI_REGISTER); \
- outb((u8)((info)->rx_low_water), (info)->ioaddr+MOXA_MUST_RBRTL_REGISTER); \
- outb(__oldlcr, (info)->ioaddr+UART_LCR); \
-}
-
-
-
-#define SET_MOXA_MUST_ENUM_VALUE(baseio, Value) { \
- u8 __oldlcr, __efr; \
- __oldlcr = inb((baseio)+UART_LCR); \
+ outb((u8)((info)->rx_high_water), (info)->ioaddr+ \
+ MOXA_MUST_RBRTH_REGISTER); \
+ outb((u8)((info)->rx_trigger), (info)->ioaddr+ \
+ MOXA_MUST_RBRTI_REGISTER); \
+ outb((u8)((info)->rx_low_water), (info)->ioaddr+ \
+ MOXA_MUST_RBRTL_REGISTER); \
+ outb(__oldlcr, (info)->ioaddr+UART_LCR); \
+} while (0)
+
+#define SET_MOXA_MUST_ENUM_VALUE(baseio, Value) do { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
- __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
- __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
- __efr |= MOXA_MUST_EFR_BANK2; \
- outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
+ __efr |= MOXA_MUST_EFR_BANK2; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
outb((u8)(Value), (baseio)+MOXA_MUST_ENUM_REGISTER); \
- outb(__oldlcr, (baseio)+UART_LCR); \
-}
+ outb(__oldlcr, (baseio)+UART_LCR); \
+} while (0)
-#define GET_MOXA_MUST_HARDWARE_ID(baseio, pId) { \
- u8 __oldlcr, __efr; \
- __oldlcr = inb((baseio)+UART_LCR); \
- outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
- __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
- __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
- __efr |= MOXA_MUST_EFR_BANK2; \
- outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
- *pId = inb((baseio)+MOXA_MUST_HWID_REGISTER); \
- outb(__oldlcr, (baseio)+UART_LCR); \
-}
-
-#define SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(baseio) { \
- u8 __oldlcr, __efr; \
- __oldlcr = inb((baseio)+UART_LCR); \
- outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
- __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
- __efr &= ~MOXA_MUST_EFR_SF_MASK; \
- outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
- outb(__oldlcr, (baseio)+UART_LCR); \
-}
-
-#define SET_MOXA_MUST_JUST_TX_SOFTWARE_FLOW_CONTROL(baseio) { \
- u8 __oldlcr, __efr; \
- __oldlcr = inb((baseio)+UART_LCR); \
+#define GET_MOXA_MUST_HARDWARE_ID(baseio, pId) do { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
- __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
- __efr &= ~MOXA_MUST_EFR_SF_MASK; \
- __efr |= MOXA_MUST_EFR_SF_TX1; \
- outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
- outb(__oldlcr, (baseio)+UART_LCR); \
-}
-
-#define ENABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(baseio) { \
- u8 __oldlcr, __efr; \
- __oldlcr = inb((baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
+ __efr |= MOXA_MUST_EFR_BANK2; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ *pId = inb((baseio)+MOXA_MUST_HWID_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+} while (0)
+
+#define SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(baseio) do { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
- __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
- __efr &= ~MOXA_MUST_EFR_SF_TX_MASK; \
- __efr |= MOXA_MUST_EFR_SF_TX1; \
- outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
- outb(__oldlcr, (baseio)+UART_LCR); \
-}
-
-#define DISABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(baseio) { \
- u8 __oldlcr, __efr; \
- __oldlcr = inb((baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_SF_MASK; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+} while (0)
+
+#define ENABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(baseio) do { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
- __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
- __efr &= ~MOXA_MUST_EFR_SF_TX_MASK; \
- outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
- outb(__oldlcr, (baseio)+UART_LCR); \
-}
-
-#define SET_MOXA_MUST_JUST_RX_SOFTWARE_FLOW_CONTROL(baseio) { \
- u8 __oldlcr, __efr; \
- __oldlcr = inb((baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_SF_TX_MASK; \
+ __efr |= MOXA_MUST_EFR_SF_TX1; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+} while (0)
+
+#define DISABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(baseio) do { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
- __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
- __efr &= ~MOXA_MUST_EFR_SF_MASK; \
- __efr |= MOXA_MUST_EFR_SF_RX1; \
- outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
- outb(__oldlcr, (baseio)+UART_LCR); \
-}
-
-#define ENABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(baseio) { \
- u8 __oldlcr, __efr; \
- __oldlcr = inb((baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_SF_TX_MASK; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+} while (0)
+
+#define ENABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(baseio) do { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
- __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
- __efr &= ~MOXA_MUST_EFR_SF_RX_MASK; \
- __efr |= MOXA_MUST_EFR_SF_RX1; \
- outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
- outb(__oldlcr, (baseio)+UART_LCR); \
-}
-
-#define DISABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(baseio) { \
- u8 __oldlcr, __efr; \
- __oldlcr = inb((baseio)+UART_LCR); \
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_SF_RX_MASK; \
+ __efr |= MOXA_MUST_EFR_SF_RX1; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+} while (0)
+
+#define DISABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(baseio) do { \
+ u8 __oldlcr, __efr; \
+ __oldlcr = inb((baseio)+UART_LCR); \
outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
- __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
- __efr &= ~MOXA_MUST_EFR_SF_RX_MASK; \
- outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
- outb(__oldlcr, (baseio)+UART_LCR); \
-}
-
-#define ENABLE_MOXA_MUST_TX_RX_SOFTWARE_FLOW_CONTROL(baseio) { \
- u8 __oldlcr, __efr; \
- __oldlcr = inb((baseio)+UART_LCR); \
- outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
- __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
- __efr &= ~MOXA_MUST_EFR_SF_MASK; \
- __efr |= (MOXA_MUST_EFR_SF_RX1|MOXA_MUST_EFR_SF_TX1); \
- outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
- outb(__oldlcr, (baseio)+UART_LCR); \
-}
-
-#define ENABLE_MOXA_MUST_XON_ANY_FLOW_CONTROL(baseio) { \
- u8 __oldmcr; \
- __oldmcr = inb((baseio)+UART_MCR); \
- __oldmcr |= MOXA_MUST_MCR_XON_ANY; \
- outb(__oldmcr, (baseio)+UART_MCR); \
-}
-
-#define DISABLE_MOXA_MUST_XON_ANY_FLOW_CONTROL(baseio) { \
- u8 __oldmcr; \
- __oldmcr = inb((baseio)+UART_MCR); \
- __oldmcr &= ~MOXA_MUST_MCR_XON_ANY; \
- outb(__oldmcr, (baseio)+UART_MCR); \
-}
-
-#define READ_MOXA_MUST_GDL(baseio) inb((baseio)+MOXA_MUST_GDL_REGISTER)
-
-
-#ifndef INIT_WORK
-#define INIT_WORK(_work, _func, _data){ \
- _data->tqueue.routine = _func;\
- _data->tqueue.data = _data;\
- }
-#endif
+ __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
+ __efr &= ~MOXA_MUST_EFR_SF_RX_MASK; \
+ outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
+ outb(__oldlcr, (baseio)+UART_LCR); \
+} while (0)
#endif
diff --git a/drivers/char/n_r3964.c b/drivers/char/n_r3964.c
index dc6d4184145..65f2d3a96b8 100644
--- a/drivers/char/n_r3964.c
+++ b/drivers/char/n_r3964.c
@@ -60,62 +60,56 @@
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/errno.h>
-#include <linux/string.h> /* used in new tty drivers */
-#include <linux/signal.h> /* used in new tty drivers */
+#include <linux/string.h> /* used in new tty drivers */
+#include <linux/signal.h> /* used in new tty drivers */
#include <linux/ioctl.h>
#include <linux/n_r3964.h>
#include <linux/poll.h>
#include <linux/init.h>
#include <asm/uaccess.h>
-
-//#define DEBUG_QUEUE
+/*#define DEBUG_QUEUE*/
/* Log successful handshake and protocol operations */
-//#define DEBUG_PROTO_S
+/*#define DEBUG_PROTO_S*/
/* Log handshake and protocol errors: */
-//#define DEBUG_PROTO_E
+/*#define DEBUG_PROTO_E*/
/* Log Linediscipline operations (open, close, read, write...): */
-//#define DEBUG_LDISC
+/*#define DEBUG_LDISC*/
/* Log module and memory operations (init, cleanup; kmalloc, kfree): */
-//#define DEBUG_MODUL
+/*#define DEBUG_MODUL*/
/* Macro helpers for debug output: */
-#define TRACE(format, args...) printk("r3964: " format "\n" , ## args);
+#define TRACE(format, args...) printk("r3964: " format "\n" , ## args)
#ifdef DEBUG_MODUL
-#define TRACE_M(format, args...) printk("r3964: " format "\n" , ## args);
+#define TRACE_M(format, args...) printk("r3964: " format "\n" , ## args)
#else
-#define TRACE_M(fmt, arg...) /**/
+#define TRACE_M(fmt, arg...) do {} while (0)
#endif
-
#ifdef DEBUG_PROTO_S
-#define TRACE_PS(format, args...) printk("r3964: " format "\n" , ## args);
+#define TRACE_PS(format, args...) printk("r3964: " format "\n" , ## args)
#else
-#define TRACE_PS(fmt, arg...) /**/
+#define TRACE_PS(fmt, arg...) do {} while (0)
#endif
-
#ifdef DEBUG_PROTO_E
-#define TRACE_PE(format, args...) printk("r3964: " format "\n" , ## args);
+#define TRACE_PE(format, args...) printk("r3964: " format "\n" , ## args)
#else
-#define TRACE_PE(fmt, arg...) /**/
+#define TRACE_PE(fmt, arg...) do {} while (0)
#endif
-
#ifdef DEBUG_LDISC
-#define TRACE_L(format, args...) printk("r3964: " format "\n" , ## args);
+#define TRACE_L(format, args...) printk("r3964: " format "\n" , ## args)
#else
-#define TRACE_L(fmt, arg...) /**/
+#define TRACE_L(fmt, arg...) do {} while (0)
#endif
-
#ifdef DEBUG_QUEUE
-#define TRACE_Q(format, args...) printk("r3964: " format "\n" , ## args);
+#define TRACE_Q(format, args...) printk("r3964: " format "\n" , ## args)
#else
-#define TRACE_Q(fmt, arg...) /**/
+#define TRACE_Q(fmt, arg...) do {} while (0)
#endif
-
static void add_tx_queue(struct r3964_info *, struct r3964_block_header *);
static void remove_from_tx_queue(struct r3964_info *pInfo, int error_code);
static void put_char(struct r3964_info *pInfo, unsigned char ch);
@@ -126,937 +120,830 @@ static void receive_char(struct r3964_info *pInfo, const unsigned char c);
static void receive_error(struct r3964_info *pInfo, const char flag);
static void on_timeout(unsigned long priv);
static int enable_signals(struct r3964_info *pInfo, struct pid *pid, int arg);
-static int read_telegram(struct r3964_info *pInfo, struct pid *pid, unsigned char __user *buf);
+static int read_telegram(struct r3964_info *pInfo, struct pid *pid,
+ unsigned char __user * buf);
static void add_msg(struct r3964_client_info *pClient, int msg_id, int arg,
- int error_code, struct r3964_block_header *pBlock);
-static struct r3964_message* remove_msg(struct r3964_info *pInfo,
- struct r3964_client_info *pClient);
-static void remove_client_block(struct r3964_info *pInfo,
- struct r3964_client_info *pClient);
+ int error_code, struct r3964_block_header *pBlock);
+static struct r3964_message *remove_msg(struct r3964_info *pInfo,
+ struct r3964_client_info *pClient);
+static void remove_client_block(struct r3964_info *pInfo,
+ struct r3964_client_info *pClient);
-static int r3964_open(struct tty_struct *tty);
+static int r3964_open(struct tty_struct *tty);
static void r3964_close(struct tty_struct *tty);
static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
- unsigned char __user *buf, size_t nr);
-static ssize_t r3964_write(struct tty_struct * tty, struct file * file,
- const unsigned char * buf, size_t nr);
-static int r3964_ioctl(struct tty_struct * tty, struct file * file,
- unsigned int cmd, unsigned long arg);
-static void r3964_set_termios(struct tty_struct *tty, struct ktermios * old);
-static unsigned int r3964_poll(struct tty_struct * tty, struct file * file,
- struct poll_table_struct *wait);
+ unsigned char __user * buf, size_t nr);
+static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
+ const unsigned char *buf, size_t nr);
+static int r3964_ioctl(struct tty_struct *tty, struct file *file,
+ unsigned int cmd, unsigned long arg);
+static void r3964_set_termios(struct tty_struct *tty, struct ktermios *old);
+static unsigned int r3964_poll(struct tty_struct *tty, struct file *file,
+ struct poll_table_struct *wait);
static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp,
- char *fp, int count);
+ char *fp, int count);
static struct tty_ldisc tty_ldisc_N_R3964 = {
- .owner = THIS_MODULE,
- .magic = TTY_LDISC_MAGIC,
- .name = "R3964",
- .open = r3964_open,
- .close = r3964_close,
- .read = r3964_read,
- .write = r3964_write,
- .ioctl = r3964_ioctl,
+ .owner = THIS_MODULE,
+ .magic = TTY_LDISC_MAGIC,
+ .name = "R3964",
+ .open = r3964_open,
+ .close = r3964_close,
+ .read = r3964_read,
+ .write = r3964_write,
+ .ioctl = r3964_ioctl,
.set_termios = r3964_set_termios,
- .poll = r3964_poll,
+ .poll = r3964_poll,
.receive_buf = r3964_receive_buf,
};
-
-
static void dump_block(const unsigned char *block, unsigned int length)
{
- unsigned int i,j;
- char linebuf[16*3+1];
-
- for(i=0;i<length;i+=16)
- {
- for(j=0;(j<16) && (j+i<length);j++)
- {
- sprintf(linebuf+3*j,"%02x ",block[i+j]);
- }
- linebuf[3*j]='\0';
- TRACE_PS("%s",linebuf);
- }
+ unsigned int i, j;
+ char linebuf[16 * 3 + 1];
+
+ for (i = 0; i < length; i += 16) {
+ for (j = 0; (j < 16) && (j + i < length); j++) {
+ sprintf(linebuf + 3 * j, "%02x ", block[i + j]);
+ }
+ linebuf[3 * j] = '\0';
+ TRACE_PS("%s", linebuf);
+ }
}
-
-
-
/*************************************************************
* Driver initialisation
*************************************************************/
-
/*************************************************************
* Module support routines
*************************************************************/
static void __exit r3964_exit(void)
{
- int status;
-
- TRACE_M ("cleanup_module()");
-
- status=tty_unregister_ldisc(N_R3964);
-
- if(status!=0)
- {
- printk(KERN_ERR "r3964: error unregistering linediscipline: %d\n", status);
- }
- else
- {
- TRACE_L("linediscipline successfully unregistered");
- }
-
+ int status;
+
+ TRACE_M("cleanup_module()");
+
+ status = tty_unregister_ldisc(N_R3964);
+
+ if (status != 0) {
+ printk(KERN_ERR "r3964: error unregistering linediscipline: "
+ "%d\n", status);
+ } else {
+ TRACE_L("linediscipline successfully unregistered");
+ }
}
static int __init r3964_init(void)
{
- int status;
-
- printk ("r3964: Philips r3964 Driver $Revision: 1.10 $\n");
-
- /*
- * Register the tty line discipline
- */
-
- status = tty_register_ldisc (N_R3964, &tty_ldisc_N_R3964);
- if (status == 0)
- {
- TRACE_L("line discipline %d registered", N_R3964);
- TRACE_L("flags=%x num=%x", tty_ldisc_N_R3964.flags,
- tty_ldisc_N_R3964.num);
- TRACE_L("open=%p", tty_ldisc_N_R3964.open);
- TRACE_L("tty_ldisc_N_R3964 = %p", &tty_ldisc_N_R3964);
- }
- else
- {
- printk (KERN_ERR "r3964: error registering line discipline: %d\n", status);
- }
- return status;
+ int status;
+
+ printk("r3964: Philips r3964 Driver $Revision: 1.10 $\n");
+
+ /*
+ * Register the tty line discipline
+ */
+
+ status = tty_register_ldisc(N_R3964, &tty_ldisc_N_R3964);
+ if (status == 0) {
+ TRACE_L("line discipline %d registered", N_R3964);
+ TRACE_L("flags=%x num=%x", tty_ldisc_N_R3964.flags,
+ tty_ldisc_N_R3964.num);
+ TRACE_L("open=%p", tty_ldisc_N_R3964.open);
+ TRACE_L("tty_ldisc_N_R3964 = %p", &tty_ldisc_N_R3964);
+ } else {
+ printk(KERN_ERR "r3964: error registering line discipline: "
+ "%d\n", status);
+ }
+ return status;
}
module_init(r3964_init);
module_exit(r3964_exit);
-
/*************************************************************
* Protocol implementation routines
*************************************************************/
-static void add_tx_queue(struct r3964_info *pInfo, struct r3964_block_header *pHeader)
+static void add_tx_queue(struct r3964_info *pInfo,
+ struct r3964_block_header *pHeader)
{
- unsigned long flags;
-
- spin_lock_irqsave(&pInfo->lock, flags);
-
- pHeader->next = NULL;
-
- if(pInfo->tx_last == NULL)
- {
- pInfo->tx_first = pInfo->tx_last = pHeader;
- }
- else
- {
- pInfo->tx_last->next = pHeader;
- pInfo->tx_last = pHeader;
- }
-
- spin_unlock_irqrestore(&pInfo->lock, flags);
-
- TRACE_Q("add_tx_queue %p, length %d, tx_first = %p",
- pHeader, pHeader->length, pInfo->tx_first );
+ unsigned long flags;
+
+ spin_lock_irqsave(&pInfo->lock, flags);
+
+ pHeader->next = NULL;
+
+ if (pInfo->tx_last == NULL) {
+ pInfo->tx_first = pInfo->tx_last = pHeader;
+ } else {
+ pInfo->tx_last->next = pHeader;
+ pInfo->tx_last = pHeader;
+ }
+
+ spin_unlock_irqrestore(&pInfo->lock, flags);
+
+ TRACE_Q("add_tx_queue %p, length %d, tx_first = %p",
+ pHeader, pHeader->length, pInfo->tx_first);
}
static void remove_from_tx_queue(struct r3964_info *pInfo, int error_code)
{
- struct r3964_block_header *pHeader;
- unsigned long flags;
+ struct r3964_block_header *pHeader;
+ unsigned long flags;
#ifdef DEBUG_QUEUE
- struct r3964_block_header *pDump;
+ struct r3964_block_header *pDump;
#endif
-
- pHeader = pInfo->tx_first;
- if(pHeader==NULL)
- return;
+ pHeader = pInfo->tx_first;
+
+ if (pHeader == NULL)
+ return;
#ifdef DEBUG_QUEUE
- printk("r3964: remove_from_tx_queue: %p, length %u - ",
- pHeader, pHeader->length );
- for(pDump=pHeader;pDump;pDump=pDump->next)
- printk("%p ", pDump);
- printk("\n");
+ printk("r3964: remove_from_tx_queue: %p, length %u - ",
+ pHeader, pHeader->length);
+ for (pDump = pHeader; pDump; pDump = pDump->next)
+ printk("%p ", pDump);
+ printk("\n");
#endif
+ if (pHeader->owner) {
+ if (error_code) {
+ add_msg(pHeader->owner, R3964_MSG_ACK, 0,
+ error_code, NULL);
+ } else {
+ add_msg(pHeader->owner, R3964_MSG_ACK, pHeader->length,
+ error_code, NULL);
+ }
+ wake_up_interruptible(&pInfo->read_wait);
+ }
+
+ spin_lock_irqsave(&pInfo->lock, flags);
+
+ pInfo->tx_first = pHeader->next;
+ if (pInfo->tx_first == NULL) {
+ pInfo->tx_last = NULL;
+ }
+
+ spin_unlock_irqrestore(&pInfo->lock, flags);
+
+ kfree(pHeader);
+ TRACE_M("remove_from_tx_queue - kfree %p", pHeader);
- if(pHeader->owner)
- {
- if(error_code)
- {
- add_msg(pHeader->owner, R3964_MSG_ACK, 0,
- error_code, NULL);
- }
- else
- {
- add_msg(pHeader->owner, R3964_MSG_ACK, pHeader->length,
- error_code, NULL);
- }
- wake_up_interruptible (&pInfo->read_wait);
- }
-
- spin_lock_irqsave(&pInfo->lock, flags);
-
- pInfo->tx_first = pHeader->next;
- if(pInfo->tx_first==NULL)
- {
- pInfo->tx_last = NULL;
- }
-
- spin_unlock_irqrestore(&pInfo->lock, flags);
-
- kfree(pHeader);
- TRACE_M("remove_from_tx_queue - kfree %p",pHeader);
-
- TRACE_Q("remove_from_tx_queue: tx_first = %p, tx_last = %p",
- pInfo->tx_first, pInfo->tx_last );
+ TRACE_Q("remove_from_tx_queue: tx_first = %p, tx_last = %p",
+ pInfo->tx_first, pInfo->tx_last);
}
-static void add_rx_queue(struct r3964_info *pInfo, struct r3964_block_header *pHeader)
+static void add_rx_queue(struct r3964_info *pInfo,
+ struct r3964_block_header *pHeader)
{
- unsigned long flags;
-
- spin_lock_irqsave(&pInfo->lock, flags);
-
- pHeader->next = NULL;
-
- if(pInfo->rx_last == NULL)
- {
- pInfo->rx_first = pInfo->rx_last = pHeader;
- }
- else
- {
- pInfo->rx_last->next = pHeader;
- pInfo->rx_last = pHeader;
- }
- pInfo->blocks_in_rx_queue++;
-
- spin_unlock_irqrestore(&pInfo->lock, flags);
-
- TRACE_Q("add_rx_queue: %p, length = %d, rx_first = %p, count = %d",
- pHeader, pHeader->length,
- pInfo->rx_first, pInfo->blocks_in_rx_queue);
+ unsigned long flags;
+
+ spin_lock_irqsave(&pInfo->lock, flags);
+
+ pHeader->next = NULL;
+
+ if (pInfo->rx_last == NULL) {
+ pInfo->rx_first = pInfo->rx_last = pHeader;
+ } else {
+ pInfo->rx_last->next = pHeader;
+ pInfo->rx_last = pHeader;
+ }
+ pInfo->blocks_in_rx_queue++;
+
+ spin_unlock_irqrestore(&pInfo->lock, flags);
+
+ TRACE_Q("add_rx_queue: %p, length = %d, rx_first = %p, count = %d",
+ pHeader, pHeader->length,
+ pInfo->rx_first, pInfo->blocks_in_rx_queue);
}
static void remove_from_rx_queue(struct r3964_info *pInfo,
- struct r3964_block_header *pHeader)
+ struct r3964_block_header *pHeader)
{
- unsigned long flags;
- struct r3964_block_header *pFind;
-
- if(pHeader==NULL)
- return;
-
- TRACE_Q("remove_from_rx_queue: rx_first = %p, rx_last = %p, count = %d",
- pInfo->rx_first, pInfo->rx_last, pInfo->blocks_in_rx_queue );
- TRACE_Q("remove_from_rx_queue: %p, length %u",
- pHeader, pHeader->length );
-
- spin_lock_irqsave(&pInfo->lock, flags);
-
- if(pInfo->rx_first == pHeader)
- {
- /* Remove the first block in the linked list: */
- pInfo->rx_first = pHeader->next;
-
- if(pInfo->rx_first==NULL)
- {
- pInfo->rx_last = NULL;
- }
- pInfo->blocks_in_rx_queue--;
- }
- else
- {
- /* Find block to remove: */
- for(pFind=pInfo->rx_first; pFind; pFind=pFind->next)
- {
- if(pFind->next == pHeader)
- {
- /* Got it. */
- pFind->next = pHeader->next;
- pInfo->blocks_in_rx_queue--;
- if(pFind->next==NULL)
- {
- /* Oh, removed the last one! */
- pInfo->rx_last = pFind;
- }
- break;
- }
- }
- }
-
- spin_unlock_irqrestore(&pInfo->lock, flags);
-
- kfree(pHeader);
- TRACE_M("remove_from_rx_queue - kfree %p",pHeader);
-
- TRACE_Q("remove_from_rx_queue: rx_first = %p, rx_last = %p, count = %d",
- pInfo->rx_first, pInfo->rx_last, pInfo->blocks_in_rx_queue );
+ unsigned long flags;
+ struct r3964_block_header *pFind;
+
+ if (pHeader == NULL)
+ return;
+
+ TRACE_Q("remove_from_rx_queue: rx_first = %p, rx_last = %p, count = %d",
+ pInfo->rx_first, pInfo->rx_last, pInfo->blocks_in_rx_queue);
+ TRACE_Q("remove_from_rx_queue: %p, length %u",
+ pHeader, pHeader->length);
+
+ spin_lock_irqsave(&pInfo->lock, flags);
+
+ if (pInfo->rx_first == pHeader) {
+ /* Remove the first block in the linked list: */
+ pInfo->rx_first = pHeader->next;
+
+ if (pInfo->rx_first == NULL) {
+ pInfo->rx_last = NULL;
+ }
+ pInfo->blocks_in_rx_queue--;
+ } else {
+ /* Find block to remove: */
+ for (pFind = pInfo->rx_first; pFind; pFind = pFind->next) {
+ if (pFind->next == pHeader) {
+ /* Got it. */
+ pFind->next = pHeader->next;
+ pInfo->blocks_in_rx_queue--;
+ if (pFind->next == NULL) {
+ /* Oh, removed the last one! */
+ pInfo->rx_last = pFind;
+ }
+ break;
+ }
+ }
+ }
+
+ spin_unlock_irqrestore(&pInfo->lock, flags);
+
+ kfree(pHeader);
+ TRACE_M("remove_from_rx_queue - kfree %p", pHeader);
+
+ TRACE_Q("remove_from_rx_queue: rx_first = %p, rx_last = %p, count = %d",
+ pInfo->rx_first, pInfo->rx_last, pInfo->blocks_in_rx_queue);
}
static void put_char(struct r3964_info *pInfo, unsigned char ch)
{
- struct tty_struct *tty = pInfo->tty;
+ struct tty_struct *tty = pInfo->tty;
- if(tty==NULL)
- return;
+ if (tty == NULL)
+ return;
- if(tty->driver->put_char)
- {
- tty->driver->put_char(tty, ch);
- }
- pInfo->bcc ^= ch;
+ if (tty->driver->put_char) {
+ tty->driver->put_char(tty, ch);
+ }
+ pInfo->bcc ^= ch;
}
static void flush(struct r3964_info *pInfo)
{
- struct tty_struct *tty = pInfo->tty;
+ struct tty_struct *tty = pInfo->tty;
- if(tty==NULL)
- return;
+ if (tty == NULL)
+ return;
- if(tty->driver->flush_chars)
- {
- tty->driver->flush_chars(tty);
- }
+ if (tty->driver->flush_chars) {
+ tty->driver->flush_chars(tty);
+ }
}
static void trigger_transmit(struct r3964_info *pInfo)
{
- unsigned long flags;
-
+ unsigned long flags;
- spin_lock_irqsave(&pInfo->lock, flags);
+ spin_lock_irqsave(&pInfo->lock, flags);
- if((pInfo->state == R3964_IDLE) && (pInfo->tx_first!=NULL))
- {
- pInfo->state = R3964_TX_REQUEST;
- pInfo->nRetry=0;
- pInfo->flags &= ~R3964_ERROR;
- mod_timer(&pInfo->tmr, jiffies + R3964_TO_QVZ);
+ if ((pInfo->state == R3964_IDLE) && (pInfo->tx_first != NULL)) {
+ pInfo->state = R3964_TX_REQUEST;
+ pInfo->nRetry = 0;
+ pInfo->flags &= ~R3964_ERROR;
+ mod_timer(&pInfo->tmr, jiffies + R3964_TO_QVZ);
- spin_unlock_irqrestore(&pInfo->lock, flags);
+ spin_unlock_irqrestore(&pInfo->lock, flags);
- TRACE_PS("trigger_transmit - sent STX");
+ TRACE_PS("trigger_transmit - sent STX");
- put_char(pInfo, STX);
- flush(pInfo);
+ put_char(pInfo, STX);
+ flush(pInfo);
- pInfo->bcc = 0;
- }
- else
- {
- spin_unlock_irqrestore(&pInfo->lock, flags);
- }
+ pInfo->bcc = 0;
+ } else {
+ spin_unlock_irqrestore(&pInfo->lock, flags);
+ }
}
static void retry_transmit(struct r3964_info *pInfo)
{
- if(pInfo->nRetry<R3964_MAX_RETRIES)
- {
- TRACE_PE("transmission failed. Retry #%d",
- pInfo->nRetry);
- pInfo->bcc = 0;
- put_char(pInfo, STX);
- flush(pInfo);
- pInfo->state = R3964_TX_REQUEST;
- pInfo->nRetry++;
- mod_timer(&pInfo->tmr, jiffies + R3964_TO_QVZ);
- }
- else
- {
- TRACE_PE("transmission failed after %d retries",
- R3964_MAX_RETRIES);
-
- remove_from_tx_queue(pInfo, R3964_TX_FAIL);
-
- put_char(pInfo, NAK);
- flush(pInfo);
- pInfo->state = R3964_IDLE;
-
- trigger_transmit(pInfo);
- }
+ if (pInfo->nRetry < R3964_MAX_RETRIES) {
+ TRACE_PE("transmission failed. Retry #%d", pInfo->nRetry);
+ pInfo->bcc = 0;
+ put_char(pInfo, STX);
+ flush(pInfo);
+ pInfo->state = R3964_TX_REQUEST;
+ pInfo->nRetry++;
+ mod_timer(&pInfo->tmr, jiffies + R3964_TO_QVZ);
+ } else {
+ TRACE_PE("transmission failed after %d retries",
+ R3964_MAX_RETRIES);
+
+ remove_from_tx_queue(pInfo, R3964_TX_FAIL);
+
+ put_char(pInfo, NAK);
+ flush(pInfo);
+ pInfo->state = R3964_IDLE;
+
+ trigger_transmit(pInfo);
+ }
}
-
static void transmit_block(struct r3964_info *pInfo)
{
- struct tty_struct *tty = pInfo->tty;
- struct r3964_block_header *pBlock = pInfo->tx_first;
- int room=0;
-
- if((tty==NULL) || (pBlock==NULL))
- {
- return;
- }
-
- if(tty->driver->write_room)
- room=tty->driver->write_room(tty);
-
- TRACE_PS("transmit_block %p, room %d, length %d",
- pBlock, room, pBlock->length);
-
- while(pInfo->tx_position < pBlock->length)
- {
- if(room<2)
- break;
-
- if(pBlock->data[pInfo->tx_position]==DLE)
- {
- /* send additional DLE char: */
- put_char(pInfo, DLE);
- }
- put_char(pInfo, pBlock->data[pInfo->tx_position++]);
-
- room--;
- }
-
- if((pInfo->tx_position == pBlock->length) && (room>=3))
- {
- put_char(pInfo, DLE);
- put_char(pInfo, ETX);
- if(pInfo->flags & R3964_BCC)
- {
- put_char(pInfo, pInfo->bcc);
- }
- pInfo->state = R3964_WAIT_FOR_TX_ACK;
- mod_timer(&pInfo->tmr, jiffies + R3964_TO_QVZ);
- }
- flush(pInfo);
+ struct tty_struct *tty = pInfo->tty;
+ struct r3964_block_header *pBlock = pInfo->tx_first;
+ int room = 0;
+
+ if ((tty == NULL) || (pBlock == NULL)) {
+ return;
+ }
+
+ if (tty->driver->write_room)
+ room = tty->driver->write_room(tty);
+
+ TRACE_PS("transmit_block %p, room %d, length %d",
+ pBlock, room, pBlock->length);
+
+ while (pInfo->tx_position < pBlock->length) {
+ if (room < 2)
+ break;
+
+ if (pBlock->data[pInfo->tx_position] == DLE) {
+ /* send additional DLE char: */
+ put_char(pInfo, DLE);
+ }
+ put_char(pInfo, pBlock->data[pInfo->tx_position++]);
+
+ room--;
+ }
+
+ if ((pInfo->tx_position == pBlock->length) && (room >= 3)) {
+ put_char(pInfo, DLE);
+ put_char(pInfo, ETX);
+ if (pInfo->flags & R3964_BCC) {
+ put_char(pInfo, pInfo->bcc);
+ }
+ pInfo->state = R3964_WAIT_FOR_TX_ACK;
+ mod_timer(&pInfo->tmr, jiffies + R3964_TO_QVZ);
+ }
+ flush(pInfo);
}
static void on_receive_block(struct r3964_info *pInfo)
{
- unsigned int length;
- struct r3964_client_info *pClient;
- struct r3964_block_header *pBlock;
-
- length=pInfo->rx_position;
-
- /* compare byte checksum characters: */
- if(pInfo->flags & R3964_BCC)
- {
- if(pInfo->bcc!=pInfo->last_rx)
- {
- TRACE_PE("checksum error - got %x but expected %x",
- pInfo->last_rx, pInfo->bcc);
- pInfo->flags |= R3964_CHECKSUM;
- }
- }
-
- /* check for errors (parity, overrun,...): */
- if(pInfo->flags & R3964_ERROR)
- {
- TRACE_PE("on_receive_block - transmission failed error %x",
- pInfo->flags & R3964_ERROR);
-
- put_char(pInfo, NAK);
- flush(pInfo);
- if(pInfo->nRetry<R3964_MAX_RETRIES)
- {
- pInfo->state=R3964_WAIT_FOR_RX_REPEAT;
- pInfo->nRetry++;
- mod_timer(&pInfo->tmr, jiffies + R3964_TO_RX_PANIC);
- }
- else
- {
- TRACE_PE("on_receive_block - failed after max retries");
- pInfo->state=R3964_IDLE;
- }
- return;
- }
-
-
- /* received block; submit DLE: */
- put_char(pInfo, DLE);
- flush(pInfo);
- del_timer_sync(&pInfo->tmr);
- TRACE_PS(" rx success: got %d chars", length);
-
- /* prepare struct r3964_block_header: */
- pBlock = kmalloc(length+sizeof(struct r3964_block_header), GFP_KERNEL);
- TRACE_M("on_receive_block - kmalloc %p",pBlock);
-
- if(pBlock==NULL)
- return;
-
- pBlock->length = length;
- pBlock->data = ((unsigned char*)pBlock)+sizeof(struct r3964_block_header);
- pBlock->locks = 0;
- pBlock->next = NULL;
- pBlock->owner = NULL;
-
- memcpy(pBlock->data, pInfo->rx_buf, length);
-
- /* queue block into rx_queue: */
- add_rx_queue(pInfo, pBlock);
-
- /* notify attached client processes: */
- for(pClient=pInfo->firstClient; pClient; pClient=pClient->next)
- {
- if(pClient->sig_flags & R3964_SIG_DATA)
- {
- add_msg(pClient, R3964_MSG_DATA, length, R3964_OK, pBlock);
- }
- }
- wake_up_interruptible (&pInfo->read_wait);
-
- pInfo->state = R3964_IDLE;
-
- trigger_transmit(pInfo);
-}
+ unsigned int length;
+ struct r3964_client_info *pClient;
+ struct r3964_block_header *pBlock;
+
+ length = pInfo->rx_position;
+
+ /* compare byte checksum characters: */
+ if (pInfo->flags & R3964_BCC) {
+ if (pInfo->bcc != pInfo->last_rx) {
+ TRACE_PE("checksum error - got %x but expected %x",
+ pInfo->last_rx, pInfo->bcc);
+ pInfo->flags |= R3964_CHECKSUM;
+ }
+ }
+
+ /* check for errors (parity, overrun,...): */
+ if (pInfo->flags & R3964_ERROR) {
+ TRACE_PE("on_receive_block - transmission failed error %x",
+ pInfo->flags & R3964_ERROR);
+
+ put_char(pInfo, NAK);
+ flush(pInfo);
+ if (pInfo->nRetry < R3964_MAX_RETRIES) {
+ pInfo->state = R3964_WAIT_FOR_RX_REPEAT;
+ pInfo->nRetry++;
+ mod_timer(&pInfo->tmr, jiffies + R3964_TO_RX_PANIC);
+ } else {
+ TRACE_PE("on_receive_block - failed after max retries");
+ pInfo->state = R3964_IDLE;
+ }
+ return;
+ }
+
+ /* received block; submit DLE: */
+ put_char(pInfo, DLE);
+ flush(pInfo);
+ del_timer_sync(&pInfo->tmr);
+ TRACE_PS(" rx success: got %d chars", length);
+
+ /* prepare struct r3964_block_header: */
+ pBlock = kmalloc(length + sizeof(struct r3964_block_header),
+ GFP_KERNEL);
+ TRACE_M("on_receive_block - kmalloc %p", pBlock);
+
+ if (pBlock == NULL)
+ return;
+
+ pBlock->length = length;
+ pBlock->data = ((unsigned char *)pBlock) +
+ sizeof(struct r3964_block_header);
+ pBlock->locks = 0;
+ pBlock->next = NULL;
+ pBlock->owner = NULL;
+
+ memcpy(pBlock->data, pInfo->rx_buf, length);
+
+ /* queue block into rx_queue: */
+ add_rx_queue(pInfo, pBlock);
+
+ /* notify attached client processes: */
+ for (pClient = pInfo->firstClient; pClient; pClient = pClient->next) {
+ if (pClient->sig_flags & R3964_SIG_DATA) {
+ add_msg(pClient, R3964_MSG_DATA, length, R3964_OK,
+ pBlock);
+ }
+ }
+ wake_up_interruptible(&pInfo->read_wait);
+ pInfo->state = R3964_IDLE;
+
+ trigger_transmit(pInfo);
+}
static void receive_char(struct r3964_info *pInfo, const unsigned char c)
{
- switch(pInfo->state)
- {
- case R3964_TX_REQUEST:
- if(c==DLE)
- {
- TRACE_PS("TX_REQUEST - got DLE");
-
- pInfo->state = R3964_TRANSMITTING;
- pInfo->tx_position = 0;
-
- transmit_block(pInfo);
- }
- else if(c==STX)
- {
- if(pInfo->nRetry==0)
- {
- TRACE_PE("TX_REQUEST - init conflict");
- if(pInfo->priority == R3964_SLAVE)
- {
- goto start_receiving;
- }
- }
- else
- {
- TRACE_PE("TX_REQUEST - secondary init conflict!?"
- " Switching to SLAVE mode for next rx.");
- goto start_receiving;
- }
- }
- else
- {
- TRACE_PE("TX_REQUEST - char != DLE: %x", c);
- retry_transmit(pInfo);
- }
- break;
- case R3964_TRANSMITTING:
- if(c==NAK)
- {
- TRACE_PE("TRANSMITTING - got NAK");
- retry_transmit(pInfo);
- }
- else
- {
- TRACE_PE("TRANSMITTING - got invalid char");
-
- pInfo->state = R3964_WAIT_ZVZ_BEFORE_TX_RETRY;
- mod_timer(&pInfo->tmr, jiffies + R3964_TO_ZVZ);
- }
- break;
- case R3964_WAIT_FOR_TX_ACK:
- if(c==DLE)
- {
- TRACE_PS("WAIT_FOR_TX_ACK - got DLE");
- remove_from_tx_queue(pInfo, R3964_OK);
-
- pInfo->state = R3964_IDLE;
- trigger_transmit(pInfo);
- }
- else
- {
- retry_transmit(pInfo);
- }
- break;
- case R3964_WAIT_FOR_RX_REPEAT:
- /* FALLTROUGH */
- case R3964_IDLE:
- if(c==STX)
- {
- /* Prevent rx_queue from overflow: */
- if(pInfo->blocks_in_rx_queue >= R3964_MAX_BLOCKS_IN_RX_QUEUE)
- {
- TRACE_PE("IDLE - got STX but no space in rx_queue!");
- pInfo->state=R3964_WAIT_FOR_RX_BUF;
- mod_timer(&pInfo->tmr, jiffies + R3964_TO_NO_BUF);
- break;
- }
+ switch (pInfo->state) {
+ case R3964_TX_REQUEST:
+ if (c == DLE) {
+ TRACE_PS("TX_REQUEST - got DLE");
+
+ pInfo->state = R3964_TRANSMITTING;
+ pInfo->tx_position = 0;
+
+ transmit_block(pInfo);
+ } else if (c == STX) {
+ if (pInfo->nRetry == 0) {
+ TRACE_PE("TX_REQUEST - init conflict");
+ if (pInfo->priority == R3964_SLAVE) {
+ goto start_receiving;
+ }
+ } else {
+ TRACE_PE("TX_REQUEST - secondary init "
+ "conflict!? Switching to SLAVE mode "
+ "for next rx.");
+ goto start_receiving;
+ }
+ } else {
+ TRACE_PE("TX_REQUEST - char != DLE: %x", c);
+ retry_transmit(pInfo);
+ }
+ break;
+ case R3964_TRANSMITTING:
+ if (c == NAK) {
+ TRACE_PE("TRANSMITTING - got NAK");
+ retry_transmit(pInfo);
+ } else {
+ TRACE_PE("TRANSMITTING - got invalid char");
+
+ pInfo->state = R3964_WAIT_ZVZ_BEFORE_TX_RETRY;
+ mod_timer(&pInfo->tmr, jiffies + R3964_TO_ZVZ);
+ }
+ break;
+ case R3964_WAIT_FOR_TX_ACK:
+ if (c == DLE) {
+ TRACE_PS("WAIT_FOR_TX_ACK - got DLE");
+ remove_from_tx_queue(pInfo, R3964_OK);
+
+ pInfo->state = R3964_IDLE;
+ trigger_transmit(pInfo);
+ } else {
+ retry_transmit(pInfo);
+ }
+ break;
+ case R3964_WAIT_FOR_RX_REPEAT:
+ /* FALLTROUGH */
+ case R3964_IDLE:
+ if (c == STX) {
+ /* Prevent rx_queue from overflow: */
+ if (pInfo->blocks_in_rx_queue >=
+ R3964_MAX_BLOCKS_IN_RX_QUEUE) {
+ TRACE_PE("IDLE - got STX but no space in "
+ "rx_queue!");
+ pInfo->state = R3964_WAIT_FOR_RX_BUF;
+ mod_timer(&pInfo->tmr,
+ jiffies + R3964_TO_NO_BUF);
+ break;
+ }
start_receiving:
- /* Ok, start receiving: */
- TRACE_PS("IDLE - got STX");
- pInfo->rx_position = 0;
- pInfo->last_rx = 0;
- pInfo->flags &= ~R3964_ERROR;
- pInfo->state=R3964_RECEIVING;
- mod_timer(&pInfo->tmr, jiffies + R3964_TO_ZVZ);
- pInfo->nRetry = 0;
- put_char(pInfo, DLE);
- flush(pInfo);
- pInfo->bcc = 0;
- }
- break;
- case R3964_RECEIVING:
- if(pInfo->rx_position < RX_BUF_SIZE)
- {
- pInfo->bcc ^= c;
-
- if(c==DLE)
- {
- if(pInfo->last_rx==DLE)
- {
- pInfo->last_rx = 0;
- goto char_to_buf;
- }
- pInfo->last_rx = DLE;
- break;
- }
- else if((c==ETX) && (pInfo->last_rx==DLE))
- {
- if(pInfo->flags & R3964_BCC)
- {
- pInfo->state = R3964_WAIT_FOR_BCC;
- mod_timer(&pInfo->tmr, jiffies + R3964_TO_ZVZ);
- }
- else
- {
- on_receive_block(pInfo);
- }
- }
- else
- {
- pInfo->last_rx = c;
+ /* Ok, start receiving: */
+ TRACE_PS("IDLE - got STX");
+ pInfo->rx_position = 0;
+ pInfo->last_rx = 0;
+ pInfo->flags &= ~R3964_ERROR;
+ pInfo->state = R3964_RECEIVING;
+ mod_timer(&pInfo->tmr, jiffies + R3964_TO_ZVZ);
+ pInfo->nRetry = 0;
+ put_char(pInfo, DLE);
+ flush(pInfo);
+ pInfo->bcc = 0;
+ }
+ break;
+ case R3964_RECEIVING:
+ if (pInfo->rx_position < RX_BUF_SIZE) {
+ pInfo->bcc ^= c;
+
+ if (c == DLE) {
+ if (pInfo->last_rx == DLE) {
+ pInfo->last_rx = 0;
+ goto char_to_buf;
+ }
+ pInfo->last_rx = DLE;
+ break;
+ } else if ((c == ETX) && (pInfo->last_rx == DLE)) {
+ if (pInfo->flags & R3964_BCC) {
+ pInfo->state = R3964_WAIT_FOR_BCC;
+ mod_timer(&pInfo->tmr,
+ jiffies + R3964_TO_ZVZ);
+ } else {
+ on_receive_block(pInfo);
+ }
+ } else {
+ pInfo->last_rx = c;
char_to_buf:
- pInfo->rx_buf[pInfo->rx_position++] = c;
- mod_timer(&pInfo->tmr, jiffies + R3964_TO_ZVZ);
- }
- }
- /* else: overflow-msg? BUF_SIZE>MTU; should not happen? */
- break;
- case R3964_WAIT_FOR_BCC:
- pInfo->last_rx = c;
- on_receive_block(pInfo);
- break;
- }
+ pInfo->rx_buf[pInfo->rx_position++] = c;
+ mod_timer(&pInfo->tmr, jiffies + R3964_TO_ZVZ);
+ }
+ }
+ /* else: overflow-msg? BUF_SIZE>MTU; should not happen? */
+ break;
+ case R3964_WAIT_FOR_BCC:
+ pInfo->last_rx = c;
+ on_receive_block(pInfo);
+ break;
+ }
}
static void receive_error(struct r3964_info *pInfo, const char flag)
{
- switch (flag)
- {
- case TTY_NORMAL:
- break;
- case TTY_BREAK:
- TRACE_PE("received break")
- pInfo->flags |= R3964_BREAK;
- break;
- case TTY_PARITY:
- TRACE_PE("parity error")
- pInfo->flags |= R3964_PARITY;
- break;
- case TTY_FRAME:
- TRACE_PE("frame error")
- pInfo->flags |= R3964_FRAME;
- break;
- case TTY_OVERRUN:
- TRACE_PE("frame overrun")
- pInfo->flags |= R3964_OVERRUN;
- break;
- default:
- TRACE_PE("receive_error - unknown flag %d", flag);
- pInfo->flags |= R3964_UNKNOWN;
- break;
- }
+ switch (flag) {
+ case TTY_NORMAL:
+ break;
+ case TTY_BREAK:
+ TRACE_PE("received break");
+ pInfo->flags |= R3964_BREAK;
+ break;
+ case TTY_PARITY:
+ TRACE_PE("parity error");
+ pInfo->flags |= R3964_PARITY;
+ break;
+ case TTY_FRAME:
+ TRACE_PE("frame error");
+ pInfo->flags |= R3964_FRAME;
+ break;
+ case TTY_OVERRUN:
+ TRACE_PE("frame overrun");
+ pInfo->flags |= R3964_OVERRUN;
+ break;
+ default:
+ TRACE_PE("receive_error - unknown flag %d", flag);
+ pInfo->flags |= R3964_UNKNOWN;
+ break;
+ }
}
static void on_timeout(unsigned long priv)
{
- struct r3964_info *pInfo = (void *)priv;
-
- switch(pInfo->state)
- {
- case R3964_TX_REQUEST:
- TRACE_PE("TX_REQUEST - timeout");
- retry_transmit(pInfo);
- break;
- case R3964_WAIT_ZVZ_BEFORE_TX_RETRY:
- put_char(pInfo, NAK);
- flush(pInfo);
- retry_transmit(pInfo);
- break;
- case R3964_WAIT_FOR_TX_ACK:
- TRACE_PE("WAIT_FOR_TX_ACK - timeout");
- retry_transmit(pInfo);
- break;
- case R3964_WAIT_FOR_RX_BUF:
- TRACE_PE("WAIT_FOR_RX_BUF - timeout");
- put_char(pInfo, NAK);
- flush(pInfo);
- pInfo->state=R3964_IDLE;
- break;
- case R3964_RECEIVING:
- TRACE_PE("RECEIVING - timeout after %d chars",
- pInfo->rx_position);
- put_char(pInfo, NAK);
- flush(pInfo);
- pInfo->state=R3964_IDLE;
- break;
- case R3964_WAIT_FOR_RX_REPEAT:
- TRACE_PE("WAIT_FOR_RX_REPEAT - timeout");
- pInfo->state=R3964_IDLE;
- break;
- case R3964_WAIT_FOR_BCC:
- TRACE_PE("WAIT_FOR_BCC - timeout");
- put_char(pInfo, NAK);
- flush(pInfo);
- pInfo->state=R3964_IDLE;
- break;
- }
+ struct r3964_info *pInfo = (void *)priv;
+
+ switch (pInfo->state) {
+ case R3964_TX_REQUEST:
+ TRACE_PE("TX_REQUEST - timeout");
+ retry_transmit(pInfo);
+ break;
+ case R3964_WAIT_ZVZ_BEFORE_TX_RETRY:
+ put_char(pInfo, NAK);
+ flush(pInfo);
+ retry_transmit(pInfo);
+ break;
+ case R3964_WAIT_FOR_TX_ACK:
+ TRACE_PE("WAIT_FOR_TX_ACK - timeout");
+ retry_transmit(pInfo);
+ break;
+ case R3964_WAIT_FOR_RX_BUF:
+ TRACE_PE("WAIT_FOR_RX_BUF - timeout");
+ put_char(pInfo, NAK);
+ flush(pInfo);
+ pInfo->state = R3964_IDLE;
+ break;
+ case R3964_RECEIVING:
+ TRACE_PE("RECEIVING - timeout after %d chars",
+ pInfo->rx_position);
+ put_char(pInfo, NAK);
+ flush(pInfo);
+ pInfo->state = R3964_IDLE;
+ break;
+ case R3964_WAIT_FOR_RX_REPEAT:
+ TRACE_PE("WAIT_FOR_RX_REPEAT - timeout");
+ pInfo->state = R3964_IDLE;
+ break;
+ case R3964_WAIT_FOR_BCC:
+ TRACE_PE("WAIT_FOR_BCC - timeout");
+ put_char(pInfo, NAK);
+ flush(pInfo);
+ pInfo->state = R3964_IDLE;
+ break;
+ }
}
-static struct r3964_client_info *findClient(
- struct r3964_info *pInfo, struct pid *pid)
+static struct r3964_client_info *findClient(struct r3964_info *pInfo,
+ struct pid *pid)
{
- struct r3964_client_info *pClient;
-
- for(pClient=pInfo->firstClient; pClient; pClient=pClient->next)
- {
- if(pClient->pid == pid)
- {
- return pClient;
- }
- }
- return NULL;
+ struct r3964_client_info *pClient;
+
+ for (pClient = pInfo->firstClient; pClient; pClient = pClient->next) {
+ if (pClient->pid == pid) {
+ return pClient;
+ }
+ }
+ return NULL;
}
static int enable_signals(struct r3964_info *pInfo, struct pid *pid, int arg)
{
- struct r3964_client_info *pClient;
- struct r3964_client_info **ppClient;
- struct r3964_message *pMsg;
-
- if((arg & R3964_SIG_ALL)==0)
- {
- /* Remove client from client list */
- for(ppClient=&pInfo->firstClient; *ppClient; ppClient=&(*ppClient)->next)
- {
- pClient = *ppClient;
-
- if(pClient->pid == pid)
- {
- TRACE_PS("removing client %d from client list", pid_nr(pid));
- *ppClient = pClient->next;
- while(pClient->msg_count)
- {
- pMsg=remove_msg(pInfo, pClient);
- if(pMsg)
- {
- kfree(pMsg);
- TRACE_M("enable_signals - msg kfree %p",pMsg);
- }
- }
- put_pid(pClient->pid);
- kfree(pClient);
- TRACE_M("enable_signals - kfree %p",pClient);
- return 0;
- }
- }
- return -EINVAL;
- }
- else
- {
- pClient=findClient(pInfo, pid);
- if(pClient)
- {
- /* update signal options */
- pClient->sig_flags=arg;
- }
- else
- {
- /* add client to client list */
- pClient=kmalloc(sizeof(struct r3964_client_info), GFP_KERNEL);
- TRACE_M("enable_signals - kmalloc %p",pClient);
- if(pClient==NULL)
- return -ENOMEM;
-
- TRACE_PS("add client %d to client list", pid_nr(pid));
- spin_lock_init(&pClient->lock);
- pClient->sig_flags=arg;
- pClient->pid = get_pid(pid);
- pClient->next=pInfo->firstClient;
- pClient->first_msg = NULL;
- pClient->last_msg = NULL;
- pClient->next_block_to_read = NULL;
- pClient->msg_count = 0;
- pInfo->firstClient=pClient;
- }
- }
-
- return 0;
+ struct r3964_client_info *pClient;
+ struct r3964_client_info **ppClient;
+ struct r3964_message *pMsg;
+
+ if ((arg & R3964_SIG_ALL) == 0) {
+ /* Remove client from client list */
+ for (ppClient = &pInfo->firstClient; *ppClient;
+ ppClient = &(*ppClient)->next) {
+ pClient = *ppClient;
+
+ if (pClient->pid == pid) {
+ TRACE_PS("removing client %d from client list",
+ pid_nr(pid));
+ *ppClient = pClient->next;
+ while (pClient->msg_count) {
+ pMsg = remove_msg(pInfo, pClient);
+ if (pMsg) {
+ kfree(pMsg);
+ TRACE_M("enable_signals - msg "
+ "kfree %p", pMsg);
+ }
+ }
+ put_pid(pClient->pid);
+ kfree(pClient);
+ TRACE_M("enable_signals - kfree %p", pClient);
+ return 0;
+ }
+ }
+ return -EINVAL;
+ } else {
+ pClient = findClient(pInfo, pid);
+ if (pClient) {
+ /* update signal options */
+ pClient->sig_flags = arg;
+ } else {
+ /* add client to client list */
+ pClient = kmalloc(sizeof(struct r3964_client_info),
+ GFP_KERNEL);
+ TRACE_M("enable_signals - kmalloc %p", pClient);
+ if (pClient == NULL)
+ return -ENOMEM;
+
+ TRACE_PS("add client %d to client list", pid_nr(pid));
+ spin_lock_init(&pClient->lock);
+ pClient->sig_flags = arg;
+ pClient->pid = get_pid(pid);
+ pClient->next = pInfo->firstClient;
+ pClient->first_msg = NULL;
+ pClient->last_msg = NULL;
+ pClient->next_block_to_read = NULL;
+ pClient->msg_count = 0;
+ pInfo->firstClient = pClient;
+ }
+ }
+
+ return 0;
}
-static int read_telegram(struct r3964_info *pInfo, struct pid *pid, unsigned char __user *buf)
+static int read_telegram(struct r3964_info *pInfo, struct pid *pid,
+ unsigned char __user * buf)
{
- struct r3964_client_info *pClient;
- struct r3964_block_header *block;
-
- if(!buf)
- {
- return -EINVAL;
- }
-
- pClient=findClient(pInfo,pid);
- if(pClient==NULL)
- {
- return -EINVAL;
- }
-
- block=pClient->next_block_to_read;
- if(!block)
- {
- return 0;
- }
- else
- {
- if (copy_to_user (buf, block->data, block->length))
- return -EFAULT;
-
- remove_client_block(pInfo, pClient);
- return block->length;
- }
-
- return -EINVAL;
+ struct r3964_client_info *pClient;
+ struct r3964_block_header *block;
+
+ if (!buf) {
+ return -EINVAL;
+ }
+
+ pClient = findClient(pInfo, pid);
+ if (pClient == NULL) {
+ return -EINVAL;
+ }
+
+ block = pClient->next_block_to_read;
+ if (!block) {
+ return 0;
+ } else {
+ if (copy_to_user(buf, block->data, block->length))
+ return -EFAULT;
+
+ remove_client_block(pInfo, pClient);
+ return block->length;
+ }
+
+ return -EINVAL;
}
static void add_msg(struct r3964_client_info *pClient, int msg_id, int arg,
- int error_code, struct r3964_block_header *pBlock)
+ int error_code, struct r3964_block_header *pBlock)
{
- struct r3964_message *pMsg;
- unsigned long flags;
-
- if(pClient->msg_count<R3964_MAX_MSG_COUNT-1)
- {
+ struct r3964_message *pMsg;
+ unsigned long flags;
+
+ if (pClient->msg_count < R3964_MAX_MSG_COUNT - 1) {
queue_the_message:
- pMsg = kmalloc(sizeof(struct r3964_message),
- error_code?GFP_ATOMIC:GFP_KERNEL);
- TRACE_M("add_msg - kmalloc %p",pMsg);
- if(pMsg==NULL) {
- return;
- }
-
- spin_lock_irqsave(&pClient->lock, flags);
-
- pMsg->msg_id = msg_id;
- pMsg->arg = arg;
- pMsg->error_code = error_code;
- pMsg->block = pBlock;
- pMsg->next = NULL;
-
- if(pClient->last_msg==NULL)
- {
- pClient->first_msg=pClient->last_msg=pMsg;
- }
- else
- {
- pClient->last_msg->next = pMsg;
- pClient->last_msg=pMsg;
- }
-
- pClient->msg_count++;
-
- if(pBlock!=NULL)
- {
- pBlock->locks++;
- }
- spin_unlock_irqrestore(&pClient->lock, flags);
- }
- else
- {
- if((pClient->last_msg->msg_id == R3964_MSG_ACK)
- && (pClient->last_msg->error_code==R3964_OVERFLOW))
- {
- pClient->last_msg->arg++;
- TRACE_PE("add_msg - inc prev OVERFLOW-msg");
- }
- else
- {
- msg_id = R3964_MSG_ACK;
- arg = 0;
- error_code = R3964_OVERFLOW;
- pBlock = NULL;
- TRACE_PE("add_msg - queue OVERFLOW-msg");
- goto queue_the_message;
- }
- }
- /* Send SIGIO signal to client process: */
- if(pClient->sig_flags & R3964_USE_SIGIO)
- {
- kill_pid(pClient->pid, SIGIO, 1);
- }
+ pMsg = kmalloc(sizeof(struct r3964_message),
+ error_code ? GFP_ATOMIC : GFP_KERNEL);
+ TRACE_M("add_msg - kmalloc %p", pMsg);
+ if (pMsg == NULL) {
+ return;
+ }
+
+ spin_lock_irqsave(&pClient->lock, flags);
+
+ pMsg->msg_id = msg_id;
+ pMsg->arg = arg;
+ pMsg->error_code = error_code;
+ pMsg->block = pBlock;
+ pMsg->next = NULL;
+
+ if (pClient->last_msg == NULL) {
+ pClient->first_msg = pClient->last_msg = pMsg;
+ } else {
+ pClient->last_msg->next = pMsg;
+ pClient->last_msg = pMsg;
+ }
+
+ pClient->msg_count++;
+
+ if (pBlock != NULL) {
+ pBlock->locks++;
+ }
+ spin_unlock_irqrestore(&pClient->lock, flags);
+ } else {
+ if ((pClient->last_msg->msg_id == R3964_MSG_ACK)
+ && (pClient->last_msg->error_code == R3964_OVERFLOW)) {
+ pClient->last_msg->arg++;
+ TRACE_PE("add_msg - inc prev OVERFLOW-msg");
+ } else {
+ msg_id = R3964_MSG_ACK;
+ arg = 0;
+ error_code = R3964_OVERFLOW;
+ pBlock = NULL;
+ TRACE_PE("add_msg - queue OVERFLOW-msg");
+ goto queue_the_message;
+ }
+ }
+ /* Send SIGIO signal to client process: */
+ if (pClient->sig_flags & R3964_USE_SIGIO) {
+ kill_pid(pClient->pid, SIGIO, 1);
+ }
}
static struct r3964_message *remove_msg(struct r3964_info *pInfo,
- struct r3964_client_info *pClient)
+ struct r3964_client_info *pClient)
{
- struct r3964_message *pMsg=NULL;
- unsigned long flags;
-
- if(pClient->first_msg)
- {
- spin_lock_irqsave(&pClient->lock, flags);
-
- pMsg = pClient->first_msg;
- pClient->first_msg = pMsg->next;
- if(pClient->first_msg==NULL)
- {
- pClient->last_msg = NULL;
- }
-
- pClient->msg_count--;
- if(pMsg->block)
- {
- remove_client_block(pInfo, pClient);
- pClient->next_block_to_read = pMsg->block;
- }
- spin_unlock_irqrestore(&pClient->lock, flags);
- }
- return pMsg;
+ struct r3964_message *pMsg = NULL;
+ unsigned long flags;
+
+ if (pClient->first_msg) {
+ spin_lock_irqsave(&pClient->lock, flags);
+
+ pMsg = pClient->first_msg;
+ pClient->first_msg = pMsg->next;
+ if (pClient->first_msg == NULL) {
+ pClient->last_msg = NULL;
+ }
+
+ pClient->msg_count--;
+ if (pMsg->block) {
+ remove_client_block(pInfo, pClient);
+ pClient->next_block_to_read = pMsg->block;
+ }
+ spin_unlock_irqrestore(&pClient->lock, flags);
+ }
+ return pMsg;
}
-static void remove_client_block(struct r3964_info *pInfo,
- struct r3964_client_info *pClient)
+static void remove_client_block(struct r3964_info *pInfo,
+ struct r3964_client_info *pClient)
{
- struct r3964_block_header *block;
-
- TRACE_PS("remove_client_block PID %d", pid_nr(pClient->pid));
-
- block=pClient->next_block_to_read;
- if(block)
- {
- block->locks--;
- if(block->locks==0)
- {
- remove_from_rx_queue(pInfo, block);
- }
- }
- pClient->next_block_to_read = NULL;
-}
+ struct r3964_block_header *block;
+
+ TRACE_PS("remove_client_block PID %d", pid_nr(pClient->pid));
+ block = pClient->next_block_to_read;
+ if (block) {
+ block->locks--;
+ if (block->locks == 0) {
+ remove_from_rx_queue(pInfo, block);
+ }
+ }
+ pClient->next_block_to_read = NULL;
+}
/*************************************************************
* Line discipline routines
@@ -1064,342 +951,318 @@ static void remove_client_block(struct r3964_info *pInfo,
static int r3964_open(struct tty_struct *tty)
{
- struct r3964_info *pInfo;
-
- TRACE_L("open");
- TRACE_L("tty=%p, PID=%d, disc_data=%p",
- tty, current->pid, tty->disc_data);
-
- pInfo=kmalloc(sizeof(struct r3964_info), GFP_KERNEL);
- TRACE_M("r3964_open - info kmalloc %p",pInfo);
-
- if(!pInfo)
- {
- printk(KERN_ERR "r3964: failed to alloc info structure\n");
- return -ENOMEM;
- }
-
- pInfo->rx_buf = kmalloc(RX_BUF_SIZE, GFP_KERNEL);
- TRACE_M("r3964_open - rx_buf kmalloc %p",pInfo->rx_buf);
-
- if(!pInfo->rx_buf)
- {
- printk(KERN_ERR "r3964: failed to alloc receive buffer\n");
- kfree(pInfo);
- TRACE_M("r3964_open - info kfree %p",pInfo);
- return -ENOMEM;
- }
-
- pInfo->tx_buf = kmalloc(TX_BUF_SIZE, GFP_KERNEL);
- TRACE_M("r3964_open - tx_buf kmalloc %p",pInfo->tx_buf);
-
- if(!pInfo->tx_buf)
- {
- printk(KERN_ERR "r3964: failed to alloc transmit buffer\n");
- kfree(pInfo->rx_buf);
- TRACE_M("r3964_open - rx_buf kfree %p",pInfo->rx_buf);
- kfree(pInfo);
- TRACE_M("r3964_open - info kfree %p",pInfo);
- return -ENOMEM;
- }
-
- spin_lock_init(&pInfo->lock);
- pInfo->tty = tty;
- init_waitqueue_head (&pInfo->read_wait);
- pInfo->priority = R3964_MASTER;
- pInfo->rx_first = pInfo->rx_last = NULL;
- pInfo->tx_first = pInfo->tx_last = NULL;
- pInfo->rx_position = 0;
- pInfo->tx_position = 0;
- pInfo->last_rx = 0;
- pInfo->blocks_in_rx_queue = 0;
- pInfo->firstClient=NULL;
- pInfo->state=R3964_IDLE;
- pInfo->flags = R3964_DEBUG;
- pInfo->nRetry = 0;
-
- tty->disc_data = pInfo;
- tty->receive_room = 65536;
-
- init_timer(&pInfo->tmr);
- pInfo->tmr.data = (unsigned long)pInfo;
- pInfo->tmr.function = on_timeout;
-
- return 0;
+ struct r3964_info *pInfo;
+
+ TRACE_L("open");
+ TRACE_L("tty=%p, PID=%d, disc_data=%p",
+ tty, current->pid, tty->disc_data);
+
+ pInfo = kmalloc(sizeof(struct r3964_info), GFP_KERNEL);
+ TRACE_M("r3964_open - info kmalloc %p", pInfo);
+
+ if (!pInfo) {
+ printk(KERN_ERR "r3964: failed to alloc info structure\n");
+ return -ENOMEM;
+ }
+
+ pInfo->rx_buf = kmalloc(RX_BUF_SIZE, GFP_KERNEL);
+ TRACE_M("r3964_open - rx_buf kmalloc %p", pInfo->rx_buf);
+
+ if (!pInfo->rx_buf) {
+ printk(KERN_ERR "r3964: failed to alloc receive buffer\n");
+ kfree(pInfo);
+ TRACE_M("r3964_open - info kfree %p", pInfo);
+ return -ENOMEM;
+ }
+
+ pInfo->tx_buf = kmalloc(TX_BUF_SIZE, GFP_KERNEL);
+ TRACE_M("r3964_open - tx_buf kmalloc %p", pInfo->tx_buf);
+
+ if (!pInfo->tx_buf) {
+ printk(KERN_ERR "r3964: failed to alloc transmit buffer\n");
+ kfree(pInfo->rx_buf);
+ TRACE_M("r3964_open - rx_buf kfree %p", pInfo->rx_buf);
+ kfree(pInfo);
+ TRACE_M("r3964_open - info kfree %p", pInfo);
+ return -ENOMEM;
+ }
+
+ spin_lock_init(&pInfo->lock);
+ pInfo->tty = tty;
+ init_waitqueue_head(&pInfo->read_wait);
+ pInfo->priority = R3964_MASTER;
+ pInfo->rx_first = pInfo->rx_last = NULL;
+ pInfo->tx_first = pInfo->tx_last = NULL;
+ pInfo->rx_position = 0;
+ pInfo->tx_position = 0;
+ pInfo->last_rx = 0;
+ pInfo->blocks_in_rx_queue = 0;
+ pInfo->firstClient = NULL;
+ pInfo->state = R3964_IDLE;
+ pInfo->flags = R3964_DEBUG;
+ pInfo->nRetry = 0;
+
+ tty->disc_data = pInfo;
+ tty->receive_room = 65536;
+
+ setup_timer(&pInfo->tmr, on_timeout, (unsigned long)pInfo);
+
+ return 0;
}
static void r3964_close(struct tty_struct *tty)
{
- struct r3964_info *pInfo=(struct r3964_info*)tty->disc_data;
- struct r3964_client_info *pClient, *pNext;
- struct r3964_message *pMsg;
- struct r3964_block_header *pHeader, *pNextHeader;
- unsigned long flags;
-
- TRACE_L("close");
-
- /*
- * Make sure that our task queue isn't activated. If it
- * is, take it out of the linked list.
- */
- del_timer_sync(&pInfo->tmr);
-
- /* Remove client-structs and message queues: */
- pClient=pInfo->firstClient;
- while(pClient)
- {
- pNext=pClient->next;
- while(pClient->msg_count)
- {
- pMsg=remove_msg(pInfo, pClient);
- if(pMsg)
- {
- kfree(pMsg);
- TRACE_M("r3964_close - msg kfree %p",pMsg);
- }
- }
- put_pid(pClient->pid);
- kfree(pClient);
- TRACE_M("r3964_close - client kfree %p",pClient);
- pClient=pNext;
- }
- /* Remove jobs from tx_queue: */
- spin_lock_irqsave(&pInfo->lock, flags);
- pHeader=pInfo->tx_first;
- pInfo->tx_first=pInfo->tx_last=NULL;
+ struct r3964_info *pInfo = (struct r3964_info *)tty->disc_data;
+ struct r3964_client_info *pClient, *pNext;
+ struct r3964_message *pMsg;
+ struct r3964_block_header *pHeader, *pNextHeader;
+ unsigned long flags;
+
+ TRACE_L("close");
+
+ /*
+ * Make sure that our task queue isn't activated. If it
+ * is, take it out of the linked list.
+ */
+ del_timer_sync(&pInfo->tmr);
+
+ /* Remove client-structs and message queues: */
+ pClient = pInfo->firstClient;
+ while (pClient) {
+ pNext = pClient->next;
+ while (pClient->msg_count) {
+ pMsg = remove_msg(pInfo, pClient);
+ if (pMsg) {
+ kfree(pMsg);
+ TRACE_M("r3964_close - msg kfree %p", pMsg);
+ }
+ }
+ put_pid(pClient->pid);
+ kfree(pClient);
+ TRACE_M("r3964_close - client kfree %p", pClient);
+ pClient = pNext;
+ }
+ /* Remove jobs from tx_queue: */
+ spin_lock_irqsave(&pInfo->lock, flags);
+ pHeader = pInfo->tx_first;
+ pInfo->tx_first = pInfo->tx_last = NULL;
spin_unlock_irqrestore(&pInfo->lock, flags);
-
- while(pHeader)
- {
- pNextHeader=pHeader->next;
- kfree(pHeader);
- pHeader=pNextHeader;
+
+ while (pHeader) {
+ pNextHeader = pHeader->next;
+ kfree(pHeader);
+ pHeader = pNextHeader;
}
- /* Free buffers: */
- wake_up_interruptible(&pInfo->read_wait);
- kfree(pInfo->rx_buf);
- TRACE_M("r3964_close - rx_buf kfree %p",pInfo->rx_buf);
- kfree(pInfo->tx_buf);
- TRACE_M("r3964_close - tx_buf kfree %p",pInfo->tx_buf);
- kfree(pInfo);
- TRACE_M("r3964_close - info kfree %p",pInfo);
+ /* Free buffers: */
+ wake_up_interruptible(&pInfo->read_wait);
+ kfree(pInfo->rx_buf);
+ TRACE_M("r3964_close - rx_buf kfree %p", pInfo->rx_buf);
+ kfree(pInfo->tx_buf);
+ TRACE_M("r3964_close - tx_buf kfree %p", pInfo->tx_buf);
+ kfree(pInfo);
+ TRACE_M("r3964_close - info kfree %p", pInfo);
}
static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
- unsigned char __user *buf, size_t nr)
+ unsigned char __user * buf, size_t nr)
{
- struct r3964_info *pInfo=(struct r3964_info*)tty->disc_data;
- struct r3964_client_info *pClient;
- struct r3964_message *pMsg;
- struct r3964_client_message theMsg;
- DECLARE_WAITQUEUE (wait, current);
-
- int count;
-
- TRACE_L("read()");
-
- pClient=findClient(pInfo, task_pid(current));
- if(pClient)
- {
- pMsg = remove_msg(pInfo, pClient);
- if(pMsg==NULL)
- {
- /* no messages available. */
- if (file->f_flags & O_NONBLOCK)
- {
- return -EAGAIN;
- }
- /* block until there is a message: */
- add_wait_queue(&pInfo->read_wait, &wait);
+ struct r3964_info *pInfo = (struct r3964_info *)tty->disc_data;
+ struct r3964_client_info *pClient;
+ struct r3964_message *pMsg;
+ struct r3964_client_message theMsg;
+ DECLARE_WAITQUEUE(wait, current);
+
+ int count;
+
+ TRACE_L("read()");
+
+ pClient = findClient(pInfo, task_pid(current));
+ if (pClient) {
+ pMsg = remove_msg(pInfo, pClient);
+ if (pMsg == NULL) {
+ /* no messages available. */
+ if (file->f_flags & O_NONBLOCK) {
+ return -EAGAIN;
+ }
+ /* block until there is a message: */
+ add_wait_queue(&pInfo->read_wait, &wait);
repeat:
- current->state = TASK_INTERRUPTIBLE;
- pMsg = remove_msg(pInfo, pClient);
- if (!pMsg && !signal_pending(current))
- {
- schedule();
- goto repeat;
- }
- current->state = TASK_RUNNING;
- remove_wait_queue(&pInfo->read_wait, &wait);
- }
-
- /* If we still haven't got a message, we must have been signalled */
-
- if (!pMsg) return -EINTR;
-
- /* deliver msg to client process: */
- theMsg.msg_id = pMsg->msg_id;
- theMsg.arg = pMsg->arg;
- theMsg.error_code = pMsg->error_code;
- count = sizeof(struct r3964_client_message);
-
- kfree(pMsg);
- TRACE_M("r3964_read - msg kfree %p",pMsg);
-
- if (copy_to_user(buf,&theMsg, count))
- return -EFAULT;
-
- TRACE_PS("read - return %d", count);
- return count;
- }
- return -EPERM;
+ current->state = TASK_INTERRUPTIBLE;
+ pMsg = remove_msg(pInfo, pClient);
+ if (!pMsg && !signal_pending(current)) {
+ schedule();
+ goto repeat;
+ }
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&pInfo->read_wait, &wait);
+ }
+
+ /* If we still haven't got a message, we must have been signalled */
+
+ if (!pMsg)
+ return -EINTR;
+
+ /* deliver msg to client process: */
+ theMsg.msg_id = pMsg->msg_id;
+ theMsg.arg = pMsg->arg;
+ theMsg.error_code = pMsg->error_code;
+ count = sizeof(struct r3964_client_message);
+
+ kfree(pMsg);
+ TRACE_M("r3964_read - msg kfree %p", pMsg);
+
+ if (copy_to_user(buf, &theMsg, count))
+ return -EFAULT;
+
+ TRACE_PS("read - return %d", count);
+ return count;
+ }
+ return -EPERM;
}
-static ssize_t r3964_write(struct tty_struct * tty, struct file * file,
+static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
const unsigned char *data, size_t count)
{
- struct r3964_info *pInfo=(struct r3964_info*)tty->disc_data;
- struct r3964_block_header *pHeader;
- struct r3964_client_info *pClient;
- unsigned char *new_data;
-
- TRACE_L("write request, %d characters", count);
+ struct r3964_info *pInfo = (struct r3964_info *)tty->disc_data;
+ struct r3964_block_header *pHeader;
+ struct r3964_client_info *pClient;
+ unsigned char *new_data;
+
+ TRACE_L("write request, %d characters", count);
/*
* Verify the pointers
*/
- if(!pInfo)
- return -EIO;
+ if (!pInfo)
+ return -EIO;
/*
* Ensure that the caller does not wish to send too much.
*/
- if (count > R3964_MTU)
- {
- if (pInfo->flags & R3964_DEBUG)
- {
- TRACE_L (KERN_WARNING
- "r3964_write: truncating user packet "
- "from %u to mtu %d", count, R3964_MTU);
- }
- count = R3964_MTU;
- }
+ if (count > R3964_MTU) {
+ if (pInfo->flags & R3964_DEBUG) {
+ TRACE_L(KERN_WARNING "r3964_write: truncating user "
+ "packet from %u to mtu %d", count, R3964_MTU);
+ }
+ count = R3964_MTU;
+ }
/*
* Allocate a buffer for the data and copy it from the buffer with header prepended
*/
- new_data = kmalloc (count+sizeof(struct r3964_block_header), GFP_KERNEL);
- TRACE_M("r3964_write - kmalloc %p",new_data);
- if (new_data == NULL) {
- if (pInfo->flags & R3964_DEBUG)
- {
- printk (KERN_ERR
- "r3964_write: no memory\n");
- }
- return -ENOSPC;
- }
-
- pHeader = (struct r3964_block_header *)new_data;
- pHeader->data = new_data + sizeof(struct r3964_block_header);
- pHeader->length = count;
- pHeader->locks = 0;
- pHeader->owner = NULL;
-
- pClient=findClient(pInfo, task_pid(current));
- if(pClient)
- {
- pHeader->owner = pClient;
- }
-
- memcpy(pHeader->data, data, count); /* We already verified this */
-
- if(pInfo->flags & R3964_DEBUG)
- {
- dump_block(pHeader->data, count);
- }
+ new_data = kmalloc(count + sizeof(struct r3964_block_header),
+ GFP_KERNEL);
+ TRACE_M("r3964_write - kmalloc %p", new_data);
+ if (new_data == NULL) {
+ if (pInfo->flags & R3964_DEBUG) {
+ printk(KERN_ERR "r3964_write: no memory\n");
+ }
+ return -ENOSPC;
+ }
+
+ pHeader = (struct r3964_block_header *)new_data;
+ pHeader->data = new_data + sizeof(struct r3964_block_header);
+ pHeader->length = count;
+ pHeader->locks = 0;
+ pHeader->owner = NULL;
+
+ pClient = findClient(pInfo, task_pid(current));
+ if (pClient) {
+ pHeader->owner = pClient;
+ }
+
+ memcpy(pHeader->data, data, count); /* We already verified this */
+
+ if (pInfo->flags & R3964_DEBUG) {
+ dump_block(pHeader->data, count);
+ }
/*
* Add buffer to transmit-queue:
*/
- add_tx_queue(pInfo, pHeader);
- trigger_transmit(pInfo);
-
- return 0;
+ add_tx_queue(pInfo, pHeader);
+ trigger_transmit(pInfo);
+
+ return 0;
}
-static int r3964_ioctl(struct tty_struct * tty, struct file * file,
- unsigned int cmd, unsigned long arg)
+static int r3964_ioctl(struct tty_struct *tty, struct file *file,
+ unsigned int cmd, unsigned long arg)
{
- struct r3964_info *pInfo=(struct r3964_info*)tty->disc_data;
- if(pInfo==NULL)
- return -EINVAL;
- switch(cmd)
- {
- case R3964_ENABLE_SIGNALS:
- return enable_signals(pInfo, task_pid(current), arg);
- case R3964_SETPRIORITY:
- if(arg<R3964_MASTER || arg>R3964_SLAVE)
- return -EINVAL;
- pInfo->priority = arg & 0xff;
- return 0;
- case R3964_USE_BCC:
- if(arg)
- pInfo->flags |= R3964_BCC;
- else
- pInfo->flags &= ~R3964_BCC;
- return 0;
- case R3964_READ_TELEGRAM:
- return read_telegram(pInfo, task_pid(current), (unsigned char __user *)arg);
- default:
- return -ENOIOCTLCMD;
- }
+ struct r3964_info *pInfo = (struct r3964_info *)tty->disc_data;
+ if (pInfo == NULL)
+ return -EINVAL;
+ switch (cmd) {
+ case R3964_ENABLE_SIGNALS:
+ return enable_signals(pInfo, task_pid(current), arg);
+ case R3964_SETPRIORITY:
+ if (arg < R3964_MASTER || arg > R3964_SLAVE)
+ return -EINVAL;
+ pInfo->priority = arg & 0xff;
+ return 0;
+ case R3964_USE_BCC:
+ if (arg)
+ pInfo->flags |= R3964_BCC;
+ else
+ pInfo->flags &= ~R3964_BCC;
+ return 0;
+ case R3964_READ_TELEGRAM:
+ return read_telegram(pInfo, task_pid(current),
+ (unsigned char __user *)arg);
+ default:
+ return -ENOIOCTLCMD;
+ }
}
-static void r3964_set_termios(struct tty_struct *tty, struct ktermios * old)
+static void r3964_set_termios(struct tty_struct *tty, struct ktermios *old)
{
- TRACE_L("set_termios");
+ TRACE_L("set_termios");
}
/* Called without the kernel lock held - fine */
-static unsigned int r3964_poll(struct tty_struct * tty, struct file * file,
- struct poll_table_struct *wait)
+static unsigned int r3964_poll(struct tty_struct *tty, struct file *file,
+ struct poll_table_struct *wait)
{
- struct r3964_info *pInfo=(struct r3964_info*)tty->disc_data;
- struct r3964_client_info *pClient;
- struct r3964_message *pMsg=NULL;
- unsigned long flags;
- int result = POLLOUT;
-
- TRACE_L("POLL");
-
- pClient=findClient(pInfo, task_pid(current));
- if(pClient)
- {
- poll_wait(file, &pInfo->read_wait, wait);
- spin_lock_irqsave(&pInfo->lock, flags);
- pMsg=pClient->first_msg;
- spin_unlock_irqrestore(&pInfo->lock, flags);
- if(pMsg)
- result |= POLLIN | POLLRDNORM;
- }
- else
- {
- result = -EINVAL;
- }
- return result;
+ struct r3964_info *pInfo = (struct r3964_info *)tty->disc_data;
+ struct r3964_client_info *pClient;
+ struct r3964_message *pMsg = NULL;
+ unsigned long flags;
+ int result = POLLOUT;
+
+ TRACE_L("POLL");
+
+ pClient = findClient(pInfo, task_pid(current));
+ if (pClient) {
+ poll_wait(file, &pInfo->read_wait, wait);
+ spin_lock_irqsave(&pInfo->lock, flags);
+ pMsg = pClient->first_msg;
+ spin_unlock_irqrestore(&pInfo->lock, flags);
+ if (pMsg)
+ result |= POLLIN | POLLRDNORM;
+ } else {
+ result = -EINVAL;
+ }
+ return result;
}
static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp,
- char *fp, int count)
+ char *fp, int count)
{
- struct r3964_info *pInfo=(struct r3964_info*)tty->disc_data;
- const unsigned char *p;
- char *f, flags = 0;
- int i;
-
- for (i=count, p = cp, f = fp; i; i--, p++) {
- if (f)
- flags = *f++;
- if(flags==TTY_NORMAL)
- {
- receive_char(pInfo, *p);
- }
- else
- {
- receive_error(pInfo, flags);
- }
-
- }
+ struct r3964_info *pInfo = (struct r3964_info *)tty->disc_data;
+ const unsigned char *p;
+ char *f, flags = 0;
+ int i;
+
+ for (i = count, p = cp, f = fp; i; i--, p++) {
+ if (f)
+ flags = *f++;
+ if (flags == TTY_NORMAL) {
+ receive_char(pInfo, *p);
+ } else {
+ receive_error(pInfo, flags);
+ }
+
+ }
}
MODULE_LICENSE("GPL");
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c
index 2bdb0144a22..6ac3ca4c723 100644
--- a/drivers/char/n_tty.c
+++ b/drivers/char/n_tty.c
@@ -579,8 +579,8 @@ static void eraser(unsigned char c, struct tty_struct *tty)
static inline void isig(int sig, struct tty_struct *tty, int flush)
{
- if (tty->pgrp > 0)
- kill_pg(tty->pgrp, sig, 1);
+ if (tty->pgrp)
+ kill_pgrp(tty->pgrp, sig, 1);
if (flush || !L_NOFLSH(tty)) {
n_tty_flush_buffer(tty);
if (tty->driver->flush_buffer)
@@ -1184,13 +1184,13 @@ static int job_control(struct tty_struct *tty, struct file *file)
/* don't stop on /dev/console */
if (file->f_op->write != redirected_tty_write &&
current->signal->tty == tty) {
- if (tty->pgrp <= 0)
- printk("read_chan: tty->pgrp <= 0!\n");
- else if (process_group(current) != tty->pgrp) {
+ if (!tty->pgrp)
+ printk("read_chan: no tty->pgrp!\n");
+ else if (task_pgrp(current) != tty->pgrp) {
if (is_ignored(SIGTTIN) ||
- is_orphaned_pgrp(process_group(current)))
+ is_current_pgrp_orphaned())
return -EIO;
- kill_pg(process_group(current), SIGTTIN, 1);
+ kill_pgrp(task_pgrp(current), SIGTTIN, 1);
return -ERESTARTSYS;
}
}
diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c
index a39f19c35a6..204deaa0de8 100644
--- a/drivers/char/nvram.c
+++ b/drivers/char/nvram.c
@@ -37,7 +37,6 @@
#define NVRAM_VERSION "1.2"
#include <linux/module.h>
-#include <linux/sched.h>
#include <linux/smp_lock.h>
#include <linux/nvram.h>
diff --git a/drivers/char/nwbutton.c b/drivers/char/nwbutton.c
index 2d264971d83..2604246501e 100644
--- a/drivers/char/nwbutton.c
+++ b/drivers/char/nwbutton.c
@@ -23,8 +23,11 @@
#define __NWBUTTON_C /* Tell the header file who we are */
#include "nwbutton.h"
+static void button_sequence_finished (unsigned long parameters);
+
static int button_press_count; /* The count of button presses */
-static struct timer_list button_timer; /* Times for the end of a sequence */
+/* Times for the end of a sequence */
+static DEFINE_TIMER(button_timer, button_sequence_finished, 0, 0);
static DECLARE_WAIT_QUEUE_HEAD(button_wait_queue); /* Used for blocking read */
static char button_output_buffer[32]; /* Stores data to write out of device */
static int bcount; /* The number of bytes in the buffer */
@@ -146,14 +149,8 @@ static void button_sequence_finished (unsigned long parameters)
static irqreturn_t button_handler (int irq, void *dev_id)
{
- if (button_press_count) {
- del_timer (&button_timer);
- }
button_press_count++;
- init_timer (&button_timer);
- button_timer.function = button_sequence_finished;
- button_timer.expires = (jiffies + bdelay);
- add_timer (&button_timer);
+ mod_timer(&button_timer, jiffies + bdelay);
return IRQ_HANDLED;
}
diff --git a/drivers/char/nwflash.c b/drivers/char/nwflash.c
index 206cf6f5069..ba012c2bdf7 100644
--- a/drivers/char/nwflash.c
+++ b/drivers/char/nwflash.c
@@ -21,7 +21,6 @@
#include <linux/mm.h>
#include <linux/delay.h>
#include <linux/proc_fs.h>
-#include <linux/sched.h>
#include <linux/miscdevice.h>
#include <linux/spinlock.h>
#include <linux/rwsem.h>
diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c
index 211c93fda6f..e91b43a014b 100644
--- a/drivers/char/pcmcia/cm4000_cs.c
+++ b/drivers/char/pcmcia/cm4000_cs.c
@@ -946,8 +946,7 @@ release_io:
return_with_timer:
DEBUGP(7, dev, "<- monitor_card (returns with timer)\n");
- dev->timer.expires = jiffies + dev->mdelay;
- add_timer(&dev->timer);
+ mod_timer(&dev->timer, jiffies + dev->mdelay);
clear_bit(LOCK_MONITOR, &dev->flags);
}
@@ -1406,12 +1405,9 @@ static void start_monitor(struct cm4000_dev *dev)
DEBUGP(3, dev, "-> start_monitor\n");
if (!dev->monitor_running) {
DEBUGP(5, dev, "create, init and add timer\n");
- init_timer(&dev->timer);
+ setup_timer(&dev->timer, monitor_card, (unsigned long)dev);
dev->monitor_running = 1;
- dev->timer.expires = jiffies;
- dev->timer.data = (unsigned long) dev;
- dev->timer.function = monitor_card;
- add_timer(&dev->timer);
+ mod_timer(&dev->timer, jiffies);
} else
DEBUGP(5, dev, "monitor already running\n");
DEBUGP(3, dev, "<- start_monitor\n");
diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c
index 9b1ff7e8f89..0e82968c2f3 100644
--- a/drivers/char/pcmcia/cm4040_cs.c
+++ b/drivers/char/pcmcia/cm4040_cs.c
@@ -632,8 +632,7 @@ static int reader_probe(struct pcmcia_device *link)
init_waitqueue_head(&dev->poll_wait);
init_waitqueue_head(&dev->read_wait);
init_waitqueue_head(&dev->write_wait);
- init_timer(&dev->poll_timer);
- dev->poll_timer.function = &cm4040_do_poll;
+ setup_timer(&dev->poll_timer, cm4040_do_poll, 0);
ret = reader_config(link, i);
if (ret)
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index f108c136800..8d025e9b5bc 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -887,10 +887,8 @@ static void bh_transmit(MGSLPC_INFO *info)
if (debug_level >= DEBUG_LEVEL_BH)
printk("bh_transmit() entry on %s\n", info->device_name);
- if (tty) {
+ if (tty)
tty_wakeup(tty);
- wake_up_interruptible(&tty->write_wait);
- }
}
static void bh_status(MGSLPC_INFO *info)
@@ -1363,9 +1361,7 @@ static int startup(MGSLPC_INFO * info)
memset(&info->icount, 0, sizeof(info->icount));
- init_timer(&info->tx_timer);
- info->tx_timer.data = (unsigned long)info;
- info->tx_timer.function = tx_timeout;
+ setup_timer(&info->tx_timer, tx_timeout, (unsigned long)info);
/* Allocate and claim adapter resources */
retval = claim_resources(info);
@@ -1410,7 +1406,7 @@ static void shutdown(MGSLPC_INFO * info)
wake_up_interruptible(&info->status_event_wait_q);
wake_up_interruptible(&info->event_wait_q);
- del_timer(&info->tx_timer);
+ del_timer_sync(&info->tx_timer);
if (info->tx_buf) {
free_page((unsigned long) info->tx_buf);
@@ -3551,8 +3547,8 @@ static void tx_start(MGSLPC_INFO *info)
} else {
info->tx_active = 1;
tx_ready(info);
- info->tx_timer.expires = jiffies + msecs_to_jiffies(5000);
- add_timer(&info->tx_timer);
+ mod_timer(&info->tx_timer, jiffies +
+ msecs_to_jiffies(5000));
}
}
diff --git a/drivers/char/pty.c b/drivers/char/pty.c
index c07a1b5cd05..de14aea34e1 100644
--- a/drivers/char/pty.c
+++ b/drivers/char/pty.c
@@ -14,7 +14,6 @@
#include <linux/module.h> /* For EXPORT_SYMBOL */
#include <linux/errno.h>
-#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
diff --git a/drivers/char/random.c b/drivers/char/random.c
index 13d0b1350a6..b9dc7aa1dfb 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -1117,14 +1117,14 @@ random_ioctl(struct inode * inode, struct file * file,
}
}
-struct file_operations random_fops = {
+const struct file_operations random_fops = {
.read = random_read,
.write = random_write,
.poll = random_poll,
.ioctl = random_ioctl,
};
-struct file_operations urandom_fops = {
+const struct file_operations urandom_fops = {
.read = urandom_read,
.write = random_write,
.ioctl = random_ioctl,
diff --git a/drivers/char/raw.c b/drivers/char/raw.c
index 645e20a06ec..1f0d7c60c94 100644
--- a/drivers/char/raw.c
+++ b/drivers/char/raw.c
@@ -154,7 +154,7 @@ static int raw_ctl_ioctl(struct inode *inode, struct file *filp,
goto out;
}
- if (rq.raw_minor < 0 || rq.raw_minor >= MAX_RAW_MINORS) {
+ if (rq.raw_minor <= 0 || rq.raw_minor >= MAX_RAW_MINORS) {
err = -EINVAL;
goto out;
}
diff --git a/drivers/char/rio/rio_linux.c b/drivers/char/rio/rio_linux.c
index e79b2ede851..294e9cb0c44 100644
--- a/drivers/char/rio/rio_linux.c
+++ b/drivers/char/rio/rio_linux.c
@@ -418,8 +418,7 @@ static void rio_pollfunc(unsigned long data)
func_enter();
rio_interrupt(0, &p->RIOHosts[data]);
- p->RIOHosts[data].timer.expires = jiffies + rio_poll;
- add_timer(&p->RIOHosts[data].timer);
+ mod_timer(&p->RIOHosts[data].timer, jiffies + rio_poll);
func_exit();
}
@@ -1147,20 +1146,17 @@ static int __init rio_init(void)
rio_dprintk(RIO_DEBUG_INIT, "Enabling interrupts on rio card.\n");
hp->Mode |= RIO_PCI_INT_ENABLE;
} else
- hp->Mode &= !RIO_PCI_INT_ENABLE;
+ hp->Mode &= ~RIO_PCI_INT_ENABLE;
rio_dprintk(RIO_DEBUG_INIT, "New Mode: %x\n", hp->Mode);
rio_start_card_running(hp);
}
/* Init the timer "always" to make sure that it can safely be
deleted when we unload... */
- init_timer(&hp->timer);
+ setup_timer(&hp->timer, rio_pollfunc, i);
if (!hp->Ivec) {
rio_dprintk(RIO_DEBUG_INIT, "Starting polling at %dj intervals.\n", rio_poll);
- hp->timer.data = i;
- hp->timer.function = rio_pollfunc;
- hp->timer.expires = jiffies + rio_poll;
- add_timer(&hp->timer);
+ mod_timer(&hp->timer, jiffies + rio_poll);
}
}
@@ -1191,7 +1187,7 @@ static void __exit rio_exit(void)
rio_dprintk(RIO_DEBUG_INIT, "freed irq %d.\n", hp->Ivec);
}
/* It is safe/allowed to del_timer a non-active timer */
- del_timer(&hp->timer);
+ del_timer_sync(&hp->timer);
if (hp->Caddr)
iounmap(hp->Caddr);
if (hp->Type == RIO_PCI)
diff --git a/drivers/char/rio/riointr.c b/drivers/char/rio/riointr.c
index eeda40c5e18..ebc76342712 100644
--- a/drivers/char/rio/riointr.c
+++ b/drivers/char/rio/riointr.c
@@ -162,13 +162,8 @@ void RIOTxEnable(char *en)
rio_spin_unlock_irqrestore(&PortP->portSem, flags);
- if (PortP->gs.xmit_cnt <= (PortP->gs.wakeup_chars + 2 * PKT_MAX_DATA_LEN)) {
- rio_dprintk(RIO_DEBUG_INTR, "Waking up.... ldisc:%d (%d/%d)....", (int) (PortP->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)), PortP->gs.wakeup_chars, PortP->gs.xmit_cnt);
- if ((PortP->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && PortP->gs.tty->ldisc.write_wakeup)
- (PortP->gs.tty->ldisc.write_wakeup) (PortP->gs.tty);
- rio_dprintk(RIO_DEBUG_INTR, "(%d/%d)\n", PortP->gs.wakeup_chars, PortP->gs.xmit_cnt);
- wake_up_interruptible(&PortP->gs.tty->write_wait);
- }
+ if (PortP->gs.xmit_cnt <= (PortP->gs.wakeup_chars + 2 * PKT_MAX_DATA_LEN))
+ tty_wakeup(PortP->gs.tty);
}
diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c
index e2a94bfb2a4..70145254fb9 100644
--- a/drivers/char/riscom8.c
+++ b/drivers/char/riscom8.c
@@ -1229,7 +1229,6 @@ static void rc_flush_buffer(struct tty_struct *tty)
port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
restore_flags(flags);
- wake_up_interruptible(&tty->write_wait);
tty_wakeup(tty);
}
@@ -1570,10 +1569,8 @@ static void do_softint(struct work_struct *ugly_api)
if(!(tty = port->tty))
return;
- if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) {
+ if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event))
tty_wakeup(tty);
- wake_up_interruptible(&tty->write_wait);
- }
}
static const struct tty_operations riscom_ops = {
diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c
index e94a62e30fc..76357c855ce 100644
--- a/drivers/char/rocket.c
+++ b/drivers/char/rocket.c
@@ -106,6 +106,8 @@
/****** RocketPort Local Variables ******/
+static void rp_do_poll(unsigned long dummy);
+
static struct tty_driver *rocket_driver;
static struct rocket_version driver_version = {
@@ -116,7 +118,7 @@ static struct r_port *rp_table[MAX_RP_PORTS]; /* The main repository of
static unsigned int xmit_flags[NUM_BOARDS]; /* Bit significant, indicates port had data to transmit. */
/* eg. Bit 0 indicates port 0 has xmit data, ... */
static atomic_t rp_num_ports_open; /* Number of serial ports open */
-static struct timer_list rocket_timer;
+static DEFINE_TIMER(rocket_timer, rp_do_poll, 0, 0);
static unsigned long board1; /* ISA addresses, retrieved from rocketport.conf */
static unsigned long board2;
@@ -474,7 +476,6 @@ static void rp_do_transmit(struct r_port *info)
if (info->xmit_cnt < WAKEUP_CHARS) {
tty_wakeup(tty);
- wake_up_interruptible(&tty->write_wait);
#ifdef ROCKETPORT_HAVE_POLL_WAIT
wake_up_interruptible(&tty->poll_wait);
#endif
@@ -1772,7 +1773,6 @@ static int rp_write(struct tty_struct *tty,
end:
if (info->xmit_cnt < WAKEUP_CHARS) {
tty_wakeup(tty);
- wake_up_interruptible(&tty->write_wait);
#ifdef ROCKETPORT_HAVE_POLL_WAIT
wake_up_interruptible(&tty->poll_wait);
#endif
@@ -1841,7 +1841,6 @@ static void rp_flush_buffer(struct tty_struct *tty)
info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
spin_unlock_irqrestore(&info->slock, flags);
- wake_up_interruptible(&tty->write_wait);
#ifdef ROCKETPORT_HAVE_POLL_WAIT
wake_up_interruptible(&tty->poll_wait);
#endif
@@ -2371,12 +2370,6 @@ static int __init rp_init(void)
return -ENOMEM;
/*
- * Set up the timer channel.
- */
- init_timer(&rocket_timer);
- rocket_timer.function = rp_do_poll;
-
- /*
* Initialize the array of pointers to our own internal state
* structures.
*/
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index 664f36c98e6..c7dac9b1335 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -135,7 +135,9 @@ static struct fasync_struct *rtc_async_queue;
static DECLARE_WAIT_QUEUE_HEAD(rtc_wait);
#ifdef RTC_IRQ
-static struct timer_list rtc_irq_timer;
+static void rtc_dropped_irq(unsigned long data);
+
+static DEFINE_TIMER(rtc_irq_timer, rtc_dropped_irq, 0, 0);
#endif
static ssize_t rtc_read(struct file *file, char __user *buf,
@@ -150,8 +152,6 @@ static unsigned int rtc_poll(struct file *file, poll_table *wait);
static void get_rtc_alm_time (struct rtc_time *alm_tm);
#ifdef RTC_IRQ
-static void rtc_dropped_irq(unsigned long data);
-
static void set_rtc_irq_bit_locked(unsigned char bit);
static void mask_rtc_irq_bit_locked(unsigned char bit);
@@ -282,7 +282,7 @@ irqreturn_t rtc_interrupt(int irq, void *dev_id)
*/
static ctl_table rtc_table[] = {
{
- .ctl_name = 1,
+ .ctl_name = CTL_UNNUMBERED,
.procname = "max-user-freq",
.data = &rtc_max_user_freq,
.maxlen = sizeof(int),
@@ -294,9 +294,8 @@ static ctl_table rtc_table[] = {
static ctl_table rtc_root[] = {
{
- .ctl_name = 1,
+ .ctl_name = CTL_UNNUMBERED,
.procname = "rtc",
- .maxlen = 0,
.mode = 0555,
.child = rtc_table,
},
@@ -307,7 +306,6 @@ static ctl_table dev_root[] = {
{
.ctl_name = CTL_DEV,
.procname = "dev",
- .maxlen = 0,
.mode = 0555,
.child = rtc_root,
},
@@ -318,7 +316,7 @@ static struct ctl_table_header *sysctl_header;
static int __init init_sysctl(void)
{
- sysctl_header = register_sysctl_table(dev_root, 0);
+ sysctl_header = register_sysctl_table(dev_root);
return 0;
}
@@ -454,8 +452,8 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel)
spin_lock_irqsave (&rtc_lock, flags);
if (!(rtc_status & RTC_TIMER_ON)) {
- rtc_irq_timer.expires = jiffies + HZ/rtc_freq + 2*HZ/100;
- add_timer(&rtc_irq_timer);
+ mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq +
+ 2*HZ/100);
rtc_status |= RTC_TIMER_ON;
}
set_rtc_irq_bit_locked(RTC_PIE);
@@ -1084,8 +1082,6 @@ no_irq:
if (rtc_has_irq == 0)
goto no_irq2;
- init_timer(&rtc_irq_timer);
- rtc_irq_timer.function = rtc_dropped_irq;
spin_lock_irq(&rtc_lock);
rtc_freq = 1024;
if (!hpet_set_periodic_freq(rtc_freq)) {
diff --git a/drivers/char/scan_keyb.c b/drivers/char/scan_keyb.c
deleted file mode 100644
index 2b5bb4f5754..00000000000
--- a/drivers/char/scan_keyb.c
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * $Id: scan_keyb.c,v 1.2 2000/07/04 06:24:42 yaegashi Exp $
- * Copyright (C) 2000 YAEGASHI Takeshi
- * Generic scan keyboard driver
- */
-
-#include <linux/spinlock.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/mm.h>
-#include <linux/signal.h>
-#include <linux/init.h>
-#include <linux/kbd_ll.h>
-#include <linux/delay.h>
-#include <linux/random.h>
-#include <linux/poll.h>
-#include <linux/miscdevice.h>
-#include <linux/slab.h>
-#include <linux/kbd_kern.h>
-#include <linux/timer.h>
-
-#define SCANHZ (HZ/20)
-
-struct scan_keyboard {
- struct scan_keyboard *next;
- int (*scan)(unsigned char *buffer);
- const unsigned char *table;
- unsigned char *s0, *s1;
- int length;
-};
-
-static int scan_jiffies=0;
-static struct scan_keyboard *keyboards=NULL;
-struct timer_list scan_timer;
-
-static void check_kbd(const unsigned char *table,
- unsigned char *new, unsigned char *old, int length)
-{
- int need_tasklet_schedule=0;
- unsigned int xor, bit;
-
- while(length-->0) {
- if((xor=*new^*old)==0) {
- table+=8;
- }
- else {
- for(bit=0x01; bit<0x100; bit<<=1) {
- if(xor&bit) {
- handle_scancode(*table, !(*new&bit));
- need_tasklet_schedule=1;
-#if 0
- printk("0x%x %s\n", *table, (*new&bit)?"released":"pressed");
-#endif
- }
- table++;
- }
- }
- new++; old++;
- }
-
- if(need_tasklet_schedule)
- tasklet_schedule(&keyboard_tasklet);
-}
-
-
-static void scan_kbd(unsigned long dummy)
-{
- struct scan_keyboard *kbd;
-
- scan_jiffies++;
-
- for(kbd=keyboards; kbd!=NULL; kbd=kbd->next) {
- if(scan_jiffies&1) {
- if(!kbd->scan(kbd->s0))
- check_kbd(kbd->table,
- kbd->s0, kbd->s1, kbd->length);
- else
- memcpy(kbd->s0, kbd->s1, kbd->length);
- }
- else {
- if(!kbd->scan(kbd->s1))
- check_kbd(kbd->table,
- kbd->s1, kbd->s0, kbd->length);
- else
- memcpy(kbd->s1, kbd->s0, kbd->length);
- }
-
- }
-
- init_timer(&scan_timer);
- scan_timer.expires = jiffies + SCANHZ;
- scan_timer.data = 0;
- scan_timer.function = scan_kbd;
- add_timer(&scan_timer);
-}
-
-
-int register_scan_keyboard(int (*scan)(unsigned char *buffer),
- const unsigned char *table,
- int length)
-{
- struct scan_keyboard *kbd;
-
- kbd = kmalloc(sizeof(struct scan_keyboard), GFP_KERNEL);
- if (kbd == NULL)
- goto error_out;
-
- kbd->scan=scan;
- kbd->table=table;
- kbd->length=length;
-
- kbd->s0 = kmalloc(length, GFP_KERNEL);
- if (kbd->s0 == NULL)
- goto error_free_kbd;
-
- kbd->s1 = kmalloc(length, GFP_KERNEL);
- if (kbd->s1 == NULL)
- goto error_free_s0;
-
- memset(kbd->s0, -1, kbd->length);
- memset(kbd->s1, -1, kbd->length);
-
- kbd->next=keyboards;
- keyboards=kbd;
-
- return 0;
-
- error_free_s0:
- kfree(kbd->s0);
-
- error_free_kbd:
- kfree(kbd);
-
- error_out:
- return -ENOMEM;
-}
-
-
-void __init scan_kbd_init(void)
-{
- init_timer(&scan_timer);
- scan_timer.expires = jiffies + SCANHZ;
- scan_timer.data = 0;
- scan_timer.function = scan_kbd;
- add_timer(&scan_timer);
-
- printk(KERN_INFO "Generic scan keyboard driver initialized\n");
-}
diff --git a/drivers/char/scan_keyb.h b/drivers/char/scan_keyb.h
deleted file mode 100644
index b4b611290a0..00000000000
--- a/drivers/char/scan_keyb.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef __DRIVER_CHAR_SCAN_KEYB_H
-#define __DRIVER_CHAR_SCAN_KEYB_H
-/*
- * $Id: scan_keyb.h,v 1.1 2000/06/10 21:45:30 yaegashi Exp $
- * Copyright (C) 2000 YAEGASHI Takeshi
- * Generic scan keyboard driver
- */
-
-int register_scan_keyboard(int (*scan)(unsigned char *buffer),
- const unsigned char *table,
- int length);
-
-void __init scan_kbd_init(void);
-
-#endif
diff --git a/drivers/char/ser_a2232.c b/drivers/char/ser_a2232.c
index 75de5f66517..3c869145bfd 100644
--- a/drivers/char/ser_a2232.c
+++ b/drivers/char/ser_a2232.c
@@ -86,7 +86,6 @@
#include <linux/module.h>
#include <linux/types.h>
-#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/errno.h>
diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c
index af50d32ae2c..5fd314adc1f 100644
--- a/drivers/char/serial167.c
+++ b/drivers/char/serial167.c
@@ -111,12 +111,13 @@ u_char initial_console_speed;
/* This is the per-port data structure */
struct cyclades_port cy_port[] = {
- /* CARD# */
- {-1 }, /* ttyS0 */
- {-1 }, /* ttyS1 */
- {-1 }, /* ttyS2 */
- {-1 }, /* ttyS3 */
+ /* CARD# */
+ {-1}, /* ttyS0 */
+ {-1}, /* ttyS1 */
+ {-1}, /* ttyS2 */
+ {-1}, /* ttyS3 */
};
+
#define NR_PORTS ARRAY_SIZE(cy_port)
/*
@@ -128,42 +129,46 @@ struct cyclades_port cy_port[] = {
* HI VHI
*/
static int baud_table[] = {
- 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200,
- 1800, 2400, 4800, 9600, 19200, 38400, 57600, 76800,115200,150000,
- 0};
+ 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200,
+ 1800, 2400, 4800, 9600, 19200, 38400, 57600, 76800, 115200, 150000,
+ 0
+};
#if 0
-static char baud_co[] = { /* 25 MHz clock option table */
- /* value => 00 01 02 03 04 */
- /* divide by 8 32 128 512 2048 */
- 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x02,
- 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+static char baud_co[] = { /* 25 MHz clock option table */
+ /* value => 00 01 02 03 04 */
+ /* divide by 8 32 128 512 2048 */
+ 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x02,
+ 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
-static char baud_bpr[] = { /* 25 MHz baud rate period table */
- 0x00, 0xf5, 0xa3, 0x6f, 0x5c, 0x51, 0xf5, 0xa3, 0x51, 0xa3,
- 0x6d, 0x51, 0xa3, 0x51, 0xa3, 0x51, 0x36, 0x29, 0x1b, 0x15};
+static char baud_bpr[] = { /* 25 MHz baud rate period table */
+ 0x00, 0xf5, 0xa3, 0x6f, 0x5c, 0x51, 0xf5, 0xa3, 0x51, 0xa3,
+ 0x6d, 0x51, 0xa3, 0x51, 0xa3, 0x51, 0x36, 0x29, 0x1b, 0x15
+};
#endif
/* I think 166 brd clocks 2401 at 20MHz.... */
/* These values are written directly to tcor, and >> 5 for writing to rcor */
-static u_char baud_co[] = { /* 20 MHz clock option table */
- 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x60, 0x60, 0x40,
- 0x40, 0x40, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+static u_char baud_co[] = { /* 20 MHz clock option table */
+ 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x60, 0x60, 0x40,
+ 0x40, 0x40, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
/* These values written directly to tbpr/rbpr */
-static u_char baud_bpr[] = { /* 20 MHz baud rate period table */
- 0x00, 0xc0, 0x80, 0x58, 0x6c, 0x40, 0xc0, 0x81, 0x40, 0x81,
- 0x57, 0x40, 0x81, 0x40, 0x81, 0x40, 0x2b, 0x20, 0x15, 0x10};
-
-static u_char baud_cor4[] = { /* receive threshold */
- 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
- 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x07};
-
+static u_char baud_bpr[] = { /* 20 MHz baud rate period table */
+ 0x00, 0xc0, 0x80, 0x58, 0x6c, 0x40, 0xc0, 0x81, 0x40, 0x81,
+ 0x57, 0x40, 0x81, 0x40, 0x81, 0x40, 0x2b, 0x20, 0x15, 0x10
+};
+static u_char baud_cor4[] = { /* receive threshold */
+ 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
+ 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x07
+};
static void shutdown(struct cyclades_port *);
-static int startup (struct cyclades_port *);
+static int startup(struct cyclades_port *);
static void cy_throttle(struct tty_struct *);
static void cy_unthrottle(struct tty_struct *);
static void config_setup(struct cyclades_port *);
@@ -174,16 +179,16 @@ static void show_status(int);
#ifdef CONFIG_REMOTE_DEBUG
static void debug_setup(void);
-void queueDebugChar (int c);
+void queueDebugChar(int c);
int getDebugChar(void);
#define DEBUG_PORT 1
#define DEBUG_LEN 256
typedef struct {
- int in;
- int out;
- unsigned char buf[DEBUG_LEN];
+ int in;
+ int out;
+ unsigned char buf[DEBUG_LEN];
} debugq;
debugq debugiq;
@@ -196,7 +201,7 @@ debugq debugiq;
* delay, but this wild guess will do for now.
*/
-void my_udelay (long us)
+void my_udelay(long us)
{
u_char x;
volatile u_char *p = &x;
@@ -207,62 +212,73 @@ void my_udelay (long us)
x |= *p;
}
-static inline int
-serial_paranoia_check(struct cyclades_port *info, char *name,
- const char *routine)
+static inline int serial_paranoia_check(struct cyclades_port *info, char *name,
+ const char *routine)
{
#ifdef SERIAL_PARANOIA_CHECK
- static const char *badmagic =
- "Warning: bad magic number for serial struct (%s) in %s\n";
- static const char *badinfo =
- "Warning: null cyclades_port for (%s) in %s\n";
- static const char *badrange =
- "Warning: cyclades_port out of range for (%s) in %s\n";
-
- if (!info) {
- printk(badinfo, name, routine);
- return 1;
- }
-
- if( (long)info < (long)(&cy_port[0])
- || (long)(&cy_port[NR_PORTS]) < (long)info ){
- printk(badrange, name, routine);
- return 1;
- }
-
- if (info->magic != CYCLADES_MAGIC) {
- printk(badmagic, name, routine);
- return 1;
- }
+ if (!info) {
+ printk("Warning: null cyclades_port for (%s) in %s\n", name,
+ routine);
+ return 1;
+ }
+
+ if ((long)info < (long)(&cy_port[0])
+ || (long)(&cy_port[NR_PORTS]) < (long)info) {
+ printk("Warning: cyclades_port out of range for (%s) in %s\n",
+ name, routine);
+ return 1;
+ }
+
+ if (info->magic != CYCLADES_MAGIC) {
+ printk("Warning: bad magic number for serial struct (%s) in "
+ "%s\n", name, routine);
+ return 1;
+ }
#endif
return 0;
-} /* serial_paranoia_check */
+} /* serial_paranoia_check */
#if 0
/* The following diagnostic routines allow the driver to spew
information on the screen, even (especially!) during interrupts.
*/
-void
-SP(char *data){
- unsigned long flags;
- local_irq_save(flags);
- console_print(data);
- local_irq_restore(flags);
+void SP(char *data)
+{
+ unsigned long flags;
+ local_irq_save(flags);
+ console_print(data);
+ local_irq_restore(flags);
}
+
char scrn[2];
-void
-CP(char data){
- unsigned long flags;
- local_irq_save(flags);
- scrn[0] = data;
- console_print(scrn);
- local_irq_restore(flags);
-}/* CP */
+void CP(char data)
+{
+ unsigned long flags;
+ local_irq_save(flags);
+ scrn[0] = data;
+ console_print(scrn);
+ local_irq_restore(flags);
+} /* CP */
-void CP1(int data) { (data<10)? CP(data+'0'): CP(data+'A'-10); }/* CP1 */
-void CP2(int data) { CP1((data>>4) & 0x0f); CP1( data & 0x0f); }/* CP2 */
-void CP4(int data) { CP2((data>>8) & 0xff); CP2(data & 0xff); }/* CP4 */
-void CP8(long data) { CP4((data>>16) & 0xffff); CP4(data & 0xffff); }/* CP8 */
+void CP1(int data)
+{
+ (data < 10) ? CP(data + '0') : CP(data + 'A' - 10);
+} /* CP1 */
+void CP2(int data)
+{
+ CP1((data >> 4) & 0x0f);
+ CP1(data & 0x0f);
+} /* CP2 */
+void CP4(int data)
+{
+ CP2((data >> 8) & 0xff);
+ CP2(data & 0xff);
+} /* CP4 */
+void CP8(long data)
+{
+ CP4((data >> 16) & 0xffff);
+ CP4(data & 0xffff);
+} /* CP8 */
#endif
/* This routine waits up to 1000 micro-seconds for the previous
@@ -270,87 +286,78 @@ void CP8(long data) { CP4((data>>16) & 0xffff); CP4(data & 0xffff); }/* CP8 */
new command. An error is returned if the previous command
didn't finish within the time limit.
*/
-u_short
-write_cy_cmd(volatile u_char *base_addr, u_char cmd)
+u_short write_cy_cmd(volatile u_char * base_addr, u_char cmd)
{
- unsigned long flags;
- volatile int i;
+ unsigned long flags;
+ volatile int i;
- local_irq_save(flags);
+ local_irq_save(flags);
/* Check to see that the previous command has completed */
- for(i = 0 ; i < 100 ; i++){
- if (base_addr[CyCCR] == 0){
- break;
- }
- my_udelay(10L);
+ for (i = 0; i < 100; i++) {
+ if (base_addr[CyCCR] == 0) {
+ break;
+ }
+ my_udelay(10L);
}
/* if the CCR never cleared, the previous command
- didn't finish within the "reasonable time" */
- if ( i == 10 ) {
- local_irq_restore(flags);
- return (-1);
+ didn't finish within the "reasonable time" */
+ if (i == 10) {
+ local_irq_restore(flags);
+ return (-1);
}
/* Issue the new command */
base_addr[CyCCR] = cmd;
- local_irq_restore(flags);
- return(0);
-} /* write_cy_cmd */
-
+ local_irq_restore(flags);
+ return (0);
+} /* write_cy_cmd */
/* cy_start and cy_stop provide software output flow control as a
function of XON/XOFF, software CTS, and other such stuff. */
-static void
-cy_stop(struct tty_struct *tty)
+static void cy_stop(struct tty_struct *tty)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
- volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
- int channel;
- unsigned long flags;
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
+ int channel;
+ unsigned long flags;
#ifdef SERIAL_DEBUG_OTHER
- printk("cy_stop %s\n", tty->name); /* */
+ printk("cy_stop %s\n", tty->name); /* */
#endif
- if (serial_paranoia_check(info, tty->name, "cy_stop"))
- return;
-
- channel = info->line;
+ if (serial_paranoia_check(info, tty->name, "cy_stop"))
+ return;
- local_irq_save(flags);
- base_addr[CyCAR] = (u_char)(channel); /* index channel */
- base_addr[CyIER] &= ~(CyTxMpty|CyTxRdy);
- local_irq_restore(flags);
+ channel = info->line;
- return;
-} /* cy_stop */
+ local_irq_save(flags);
+ base_addr[CyCAR] = (u_char) (channel); /* index channel */
+ base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy);
+ local_irq_restore(flags);
+} /* cy_stop */
-static void
-cy_start(struct tty_struct *tty)
+static void cy_start(struct tty_struct *tty)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
- volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
- int channel;
- unsigned long flags;
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
+ int channel;
+ unsigned long flags;
#ifdef SERIAL_DEBUG_OTHER
- printk("cy_start %s\n", tty->name); /* */
+ printk("cy_start %s\n", tty->name); /* */
#endif
- if (serial_paranoia_check(info, tty->name, "cy_start"))
- return;
-
- channel = info->line;
+ if (serial_paranoia_check(info, tty->name, "cy_start"))
+ return;
- local_irq_save(flags);
- base_addr[CyCAR] = (u_char)(channel);
- base_addr[CyIER] |= CyTxMpty;
- local_irq_restore(flags);
-
- return;
-} /* cy_start */
+ channel = info->line;
+ local_irq_save(flags);
+ base_addr[CyCAR] = (u_char) (channel);
+ base_addr[CyIER] |= CyTxMpty;
+ local_irq_restore(flags);
+} /* cy_start */
/*
* This routine is used by the interrupt handler to schedule
@@ -358,332 +365,332 @@ cy_start(struct tty_struct *tty)
* (also known as the "bottom half"). This can be called any
* number of times for any channel without harm.
*/
-static inline void
-cy_sched_event(struct cyclades_port *info, int event)
+static inline void cy_sched_event(struct cyclades_port *info, int event)
{
- info->event |= 1 << event; /* remember what kind of event and who */
- schedule_work(&info->tqueue);
-} /* cy_sched_event */
-
+ info->event |= 1 << event; /* remember what kind of event and who */
+ schedule_work(&info->tqueue);
+} /* cy_sched_event */
/* The real interrupt service routines are called
whenever the card wants its hand held--chars
received, out buffer empty, modem change, etc.
*/
-static irqreturn_t
-cd2401_rxerr_interrupt(int irq, void *dev_id)
+static irqreturn_t cd2401_rxerr_interrupt(int irq, void *dev_id)
{
- struct tty_struct *tty;
- struct cyclades_port *info;
- volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
- unsigned char err, rfoc;
- int channel;
- char data;
-
- /* determine the channel and change to that context */
- channel = (u_short ) (base_addr[CyLICR] >> 2);
- info = &cy_port[channel];
- info->last_active = jiffies;
-
- if ((err = base_addr[CyRISR]) & CyTIMEOUT) {
- /* This is a receive timeout interrupt, ignore it */
- base_addr[CyREOIR] = CyNOTRANS;
- return IRQ_HANDLED;
- }
-
- /* Read a byte of data if there is any - assume the error
- * is associated with this character */
+ struct tty_struct *tty;
+ struct cyclades_port *info;
+ volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
+ unsigned char err, rfoc;
+ int channel;
+ char data;
+
+ /* determine the channel and change to that context */
+ channel = (u_short) (base_addr[CyLICR] >> 2);
+ info = &cy_port[channel];
+ info->last_active = jiffies;
+
+ if ((err = base_addr[CyRISR]) & CyTIMEOUT) {
+ /* This is a receive timeout interrupt, ignore it */
+ base_addr[CyREOIR] = CyNOTRANS;
+ return IRQ_HANDLED;
+ }
- if ((rfoc = base_addr[CyRFOC]) != 0)
- data = base_addr[CyRDR];
- else
- data = 0;
+ /* Read a byte of data if there is any - assume the error
+ * is associated with this character */
- /* if there is nowhere to put the data, discard it */
- if(info->tty == 0) {
+ if ((rfoc = base_addr[CyRFOC]) != 0)
+ data = base_addr[CyRDR];
+ else
+ data = 0;
+
+ /* if there is nowhere to put the data, discard it */
+ if (info->tty == 0) {
+ base_addr[CyREOIR] = rfoc ? 0 : CyNOTRANS;
+ return IRQ_HANDLED;
+ } else { /* there is an open port for this data */
+ tty = info->tty;
+ if (err & info->ignore_status_mask) {
+ base_addr[CyREOIR] = rfoc ? 0 : CyNOTRANS;
+ return IRQ_HANDLED;
+ }
+ if (tty_buffer_request_room(tty, 1) != 0) {
+ if (err & info->read_status_mask) {
+ if (err & CyBREAK) {
+ tty_insert_flip_char(tty, data,
+ TTY_BREAK);
+ if (info->flags & ASYNC_SAK) {
+ do_SAK(tty);
+ }
+ } else if (err & CyFRAME) {
+ tty_insert_flip_char(tty, data,
+ TTY_FRAME);
+ } else if (err & CyPARITY) {
+ tty_insert_flip_char(tty, data,
+ TTY_PARITY);
+ } else if (err & CyOVERRUN) {
+ tty_insert_flip_char(tty, 0,
+ TTY_OVERRUN);
+ /*
+ If the flip buffer itself is
+ overflowing, we still loose
+ the next incoming character.
+ */
+ if (tty_buffer_request_room(tty, 1) !=
+ 0) {
+ tty_insert_flip_char(tty, data,
+ TTY_FRAME);
+ }
+ /* These two conditions may imply */
+ /* a normal read should be done. */
+ /* else if(data & CyTIMEOUT) */
+ /* else if(data & CySPECHAR) */
+ } else {
+ tty_insert_flip_char(tty, 0,
+ TTY_NORMAL);
+ }
+ } else {
+ tty_insert_flip_char(tty, data, TTY_NORMAL);
+ }
+ } else {
+ /* there was a software buffer overrun
+ and nothing could be done about it!!! */
+ }
+ }
+ tty_schedule_flip(tty);
+ /* end of service */
base_addr[CyREOIR] = rfoc ? 0 : CyNOTRANS;
return IRQ_HANDLED;
- }
- else { /* there is an open port for this data */
- tty = info->tty;
- if(err & info->ignore_status_mask){
- base_addr[CyREOIR] = rfoc ? 0 : CyNOTRANS;
- return IRQ_HANDLED;
- }
- if (tty_buffer_request_room(tty, 1) != 0){
- if (err & info->read_status_mask){
- if(err & CyBREAK){
- tty_insert_flip_char(tty, data, TTY_BREAK);
- if (info->flags & ASYNC_SAK){
- do_SAK(tty);
- }
- }else if(err & CyFRAME){
- tty_insert_flip_char(tty, data, TTY_FRAME);
- }else if(err & CyPARITY){
- tty_insert_flip_char(tty, data, TTY_PARITY);
- }else if(err & CyOVERRUN){
- tty_insert_flip_char(tty, 0, TTY_OVERRUN);
- /*
- If the flip buffer itself is
- overflowing, we still loose
- the next incoming character.
- */
- if (tty_buffer_request_room(tty, 1) != 0){
- tty_insert_flip_char(tty, data, TTY_FRAME);
- }
- /* These two conditions may imply */
- /* a normal read should be done. */
- /* else if(data & CyTIMEOUT) */
- /* else if(data & CySPECHAR) */
- }else{
- tty_insert_flip_char(tty, 0, TTY_NORMAL);
- }
- }else{
- tty_insert_flip_char(tty, data, TTY_NORMAL);
- }
- }else{
- /* there was a software buffer overrun
- and nothing could be done about it!!! */
- }
- }
- tty_schedule_flip(tty);
- /* end of service */
- base_addr[CyREOIR] = rfoc ? 0 : CyNOTRANS;
- return IRQ_HANDLED;
-} /* cy_rxerr_interrupt */
-
-static irqreturn_t
-cd2401_modem_interrupt(int irq, void *dev_id)
+} /* cy_rxerr_interrupt */
+
+static irqreturn_t cd2401_modem_interrupt(int irq, void *dev_id)
{
- struct cyclades_port *info;
- volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
- int channel;
- int mdm_change;
- int mdm_status;
-
-
- /* determine the channel and change to that context */
- channel = (u_short ) (base_addr[CyLICR] >> 2);
- info = &cy_port[channel];
- info->last_active = jiffies;
-
- mdm_change = base_addr[CyMISR];
- mdm_status = base_addr[CyMSVR1];
-
- if(info->tty == 0){ /* nowhere to put the data, ignore it */
- ;
- }else{
- if((mdm_change & CyDCD)
- && (info->flags & ASYNC_CHECK_CD)){
- if(mdm_status & CyDCD){
+ struct cyclades_port *info;
+ volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
+ int channel;
+ int mdm_change;
+ int mdm_status;
+
+ /* determine the channel and change to that context */
+ channel = (u_short) (base_addr[CyLICR] >> 2);
+ info = &cy_port[channel];
+ info->last_active = jiffies;
+
+ mdm_change = base_addr[CyMISR];
+ mdm_status = base_addr[CyMSVR1];
+
+ if (info->tty == 0) { /* nowhere to put the data, ignore it */
+ ;
+ } else {
+ if ((mdm_change & CyDCD)
+ && (info->flags & ASYNC_CHECK_CD)) {
+ if (mdm_status & CyDCD) {
/* CP('!'); */
- cy_sched_event(info, Cy_EVENT_OPEN_WAKEUP);
- } else {
+ cy_sched_event(info, Cy_EVENT_OPEN_WAKEUP);
+ } else {
/* CP('@'); */
- cy_sched_event(info, Cy_EVENT_HANGUP);
- }
- }
- if((mdm_change & CyCTS)
- && (info->flags & ASYNC_CTS_FLOW)){
- if(info->tty->stopped){
- if(mdm_status & CyCTS){
- /* !!! cy_start isn't used because... */
- info->tty->stopped = 0;
- base_addr[CyIER] |= CyTxMpty;
- cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP);
+ cy_sched_event(info, Cy_EVENT_HANGUP);
+ }
}
- }else{
- if(!(mdm_status & CyCTS)){
- /* !!! cy_stop isn't used because... */
- info->tty->stopped = 1;
- base_addr[CyIER] &= ~(CyTxMpty|CyTxRdy);
+ if ((mdm_change & CyCTS)
+ && (info->flags & ASYNC_CTS_FLOW)) {
+ if (info->tty->stopped) {
+ if (mdm_status & CyCTS) {
+ /* !!! cy_start isn't used because... */
+ info->tty->stopped = 0;
+ base_addr[CyIER] |= CyTxMpty;
+ cy_sched_event(info,
+ Cy_EVENT_WRITE_WAKEUP);
+ }
+ } else {
+ if (!(mdm_status & CyCTS)) {
+ /* !!! cy_stop isn't used because... */
+ info->tty->stopped = 1;
+ base_addr[CyIER] &=
+ ~(CyTxMpty | CyTxRdy);
+ }
+ }
+ }
+ if (mdm_status & CyDSR) {
}
- }
- }
- if(mdm_status & CyDSR){
}
- }
- base_addr[CyMEOIR] = 0;
- return IRQ_HANDLED;
-} /* cy_modem_interrupt */
+ base_addr[CyMEOIR] = 0;
+ return IRQ_HANDLED;
+} /* cy_modem_interrupt */
-static irqreturn_t
-cd2401_tx_interrupt(int irq, void *dev_id)
+static irqreturn_t cd2401_tx_interrupt(int irq, void *dev_id)
{
- struct cyclades_port *info;
- volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
- int channel;
- int char_count, saved_cnt;
- int outch;
+ struct cyclades_port *info;
+ volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
+ int channel;
+ int char_count, saved_cnt;
+ int outch;
- /* determine the channel and change to that context */
- channel = (u_short ) (base_addr[CyLICR] >> 2);
+ /* determine the channel and change to that context */
+ channel = (u_short) (base_addr[CyLICR] >> 2);
#ifdef CONFIG_REMOTE_DEBUG
- if (channel == DEBUG_PORT) {
- panic ("TxInt on debug port!!!");
- }
+ if (channel == DEBUG_PORT) {
+ panic("TxInt on debug port!!!");
+ }
#endif
- info = &cy_port[channel];
+ info = &cy_port[channel];
- /* validate the port number (as configured and open) */
- if( (channel < 0) || (NR_PORTS <= channel) ){
- base_addr[CyIER] &= ~(CyTxMpty|CyTxRdy);
- base_addr[CyTEOIR] = CyNOTRANS;
- return IRQ_HANDLED;
- }
- info->last_active = jiffies;
- if(info->tty == 0){
- base_addr[CyIER] &= ~(CyTxMpty|CyTxRdy);
- if (info->xmit_cnt < WAKEUP_CHARS) {
- cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP);
- }
- base_addr[CyTEOIR] = CyNOTRANS;
- return IRQ_HANDLED;
- }
-
- /* load the on-chip space available for outbound data */
- saved_cnt = char_count = base_addr[CyTFTC];
-
- if(info->x_char) { /* send special char */
- outch = info->x_char;
- base_addr[CyTDR] = outch;
- char_count--;
- info->x_char = 0;
- }
-
- if (info->x_break){
- /* The Cirrus chip requires the "Embedded Transmit
- Commands" of start break, delay, and end break
- sequences to be sent. The duration of the
- break is given in TICs, which runs at HZ
- (typically 100) and the PPR runs at 200 Hz,
- so the delay is duration * 200/HZ, and thus a
- break can run from 1/100 sec to about 5/4 sec.
- Need to check these values - RGH 141095.
- */
- base_addr[CyTDR] = 0; /* start break */
- base_addr[CyTDR] = 0x81;
- base_addr[CyTDR] = 0; /* delay a bit */
- base_addr[CyTDR] = 0x82;
- base_addr[CyTDR] = info->x_break*200/HZ;
- base_addr[CyTDR] = 0; /* terminate break */
- base_addr[CyTDR] = 0x83;
- char_count -= 7;
- info->x_break = 0;
- }
-
- while (char_count > 0){
- if (!info->xmit_cnt){
- base_addr[CyIER] &= ~(CyTxMpty|CyTxRdy);
- break;
- }
- if (info->xmit_buf == 0){
- base_addr[CyIER] &= ~(CyTxMpty|CyTxRdy);
- break;
- }
- if (info->tty->stopped || info->tty->hw_stopped){
- base_addr[CyIER] &= ~(CyTxMpty|CyTxRdy);
- break;
- }
- /* Because the Embedded Transmit Commands have been
- enabled, we must check to see if the escape
- character, NULL, is being sent. If it is, we
- must ensure that there is room for it to be
- doubled in the output stream. Therefore we
- no longer advance the pointer when the character
- is fetched, but rather wait until after the check
- for a NULL output character. (This is necessary
- because there may not be room for the two chars
- needed to send a NULL.
- */
- outch = info->xmit_buf[info->xmit_tail];
- if( outch ){
- info->xmit_cnt--;
- info->xmit_tail = (info->xmit_tail + 1)
- & (PAGE_SIZE - 1);
- base_addr[CyTDR] = outch;
- char_count--;
- }else{
- if(char_count > 1){
- info->xmit_cnt--;
- info->xmit_tail = (info->xmit_tail + 1)
- & (PAGE_SIZE - 1);
+ /* validate the port number (as configured and open) */
+ if ((channel < 0) || (NR_PORTS <= channel)) {
+ base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy);
+ base_addr[CyTEOIR] = CyNOTRANS;
+ return IRQ_HANDLED;
+ }
+ info->last_active = jiffies;
+ if (info->tty == 0) {
+ base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy);
+ if (info->xmit_cnt < WAKEUP_CHARS) {
+ cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP);
+ }
+ base_addr[CyTEOIR] = CyNOTRANS;
+ return IRQ_HANDLED;
+ }
+
+ /* load the on-chip space available for outbound data */
+ saved_cnt = char_count = base_addr[CyTFTC];
+
+ if (info->x_char) { /* send special char */
+ outch = info->x_char;
base_addr[CyTDR] = outch;
- base_addr[CyTDR] = 0;
char_count--;
- char_count--;
- }else{
- break;
- }
+ info->x_char = 0;
}
- }
- if (info->xmit_cnt < WAKEUP_CHARS) {
- cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP);
- }
- base_addr[CyTEOIR] = (char_count != saved_cnt) ? 0 : CyNOTRANS;
- return IRQ_HANDLED;
-} /* cy_tx_interrupt */
+ if (info->x_break) {
+ /* The Cirrus chip requires the "Embedded Transmit
+ Commands" of start break, delay, and end break
+ sequences to be sent. The duration of the
+ break is given in TICs, which runs at HZ
+ (typically 100) and the PPR runs at 200 Hz,
+ so the delay is duration * 200/HZ, and thus a
+ break can run from 1/100 sec to about 5/4 sec.
+ Need to check these values - RGH 141095.
+ */
+ base_addr[CyTDR] = 0; /* start break */
+ base_addr[CyTDR] = 0x81;
+ base_addr[CyTDR] = 0; /* delay a bit */
+ base_addr[CyTDR] = 0x82;
+ base_addr[CyTDR] = info->x_break * 200 / HZ;
+ base_addr[CyTDR] = 0; /* terminate break */
+ base_addr[CyTDR] = 0x83;
+ char_count -= 7;
+ info->x_break = 0;
+ }
+
+ while (char_count > 0) {
+ if (!info->xmit_cnt) {
+ base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy);
+ break;
+ }
+ if (info->xmit_buf == 0) {
+ base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy);
+ break;
+ }
+ if (info->tty->stopped || info->tty->hw_stopped) {
+ base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy);
+ break;
+ }
+ /* Because the Embedded Transmit Commands have been
+ enabled, we must check to see if the escape
+ character, NULL, is being sent. If it is, we
+ must ensure that there is room for it to be
+ doubled in the output stream. Therefore we
+ no longer advance the pointer when the character
+ is fetched, but rather wait until after the check
+ for a NULL output character. (This is necessary
+ because there may not be room for the two chars
+ needed to send a NULL.
+ */
+ outch = info->xmit_buf[info->xmit_tail];
+ if (outch) {
+ info->xmit_cnt--;
+ info->xmit_tail = (info->xmit_tail + 1)
+ & (PAGE_SIZE - 1);
+ base_addr[CyTDR] = outch;
+ char_count--;
+ } else {
+ if (char_count > 1) {
+ info->xmit_cnt--;
+ info->xmit_tail = (info->xmit_tail + 1)
+ & (PAGE_SIZE - 1);
+ base_addr[CyTDR] = outch;
+ base_addr[CyTDR] = 0;
+ char_count--;
+ char_count--;
+ } else {
+ break;
+ }
+ }
+ }
+
+ if (info->xmit_cnt < WAKEUP_CHARS) {
+ cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP);
+ }
+ base_addr[CyTEOIR] = (char_count != saved_cnt) ? 0 : CyNOTRANS;
+ return IRQ_HANDLED;
+} /* cy_tx_interrupt */
-static irqreturn_t
-cd2401_rx_interrupt(int irq, void *dev_id)
+static irqreturn_t cd2401_rx_interrupt(int irq, void *dev_id)
{
- struct tty_struct *tty;
- struct cyclades_port *info;
- volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
- int channel;
- char data;
- int char_count;
- int save_cnt;
- int len;
-
- /* determine the channel and change to that context */
- channel = (u_short ) (base_addr[CyLICR] >> 2);
- info = &cy_port[channel];
- info->last_active = jiffies;
- save_cnt = char_count = base_addr[CyRFOC];
+ struct tty_struct *tty;
+ struct cyclades_port *info;
+ volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
+ int channel;
+ char data;
+ int char_count;
+ int save_cnt;
+ int len;
+
+ /* determine the channel and change to that context */
+ channel = (u_short) (base_addr[CyLICR] >> 2);
+ info = &cy_port[channel];
+ info->last_active = jiffies;
+ save_cnt = char_count = base_addr[CyRFOC];
#ifdef CONFIG_REMOTE_DEBUG
- if (channel == DEBUG_PORT) {
- while (char_count--) {
- data = base_addr[CyRDR];
- queueDebugChar(data);
- }
- }
- else
+ if (channel == DEBUG_PORT) {
+ while (char_count--) {
+ data = base_addr[CyRDR];
+ queueDebugChar(data);
+ }
+ } else
#endif
- /* if there is nowhere to put the data, discard it */
- if(info->tty == 0){
- while(char_count--){
- data = base_addr[CyRDR];
- }
- }else{ /* there is an open port for this data */
- tty = info->tty;
- /* load # characters available from the chip */
+ /* if there is nowhere to put the data, discard it */
+ if (info->tty == 0) {
+ while (char_count--) {
+ data = base_addr[CyRDR];
+ }
+ } else { /* there is an open port for this data */
+ tty = info->tty;
+ /* load # characters available from the chip */
#ifdef CYCLOM_ENABLE_MONITORING
- ++info->mon.int_count;
- info->mon.char_count += char_count;
- if (char_count > info->mon.char_max)
- info->mon.char_max = char_count;
- info->mon.char_last = char_count;
-#endif
- len = tty_buffer_request_room(tty, char_count);
- while(len--){
- data = base_addr[CyRDR];
- tty_insert_flip_char(tty, data, TTY_NORMAL);
+ ++info->mon.int_count;
+ info->mon.char_count += char_count;
+ if (char_count > info->mon.char_max)
+ info->mon.char_max = char_count;
+ info->mon.char_last = char_count;
+#endif
+ len = tty_buffer_request_room(tty, char_count);
+ while (len--) {
+ data = base_addr[CyRDR];
+ tty_insert_flip_char(tty, data, TTY_NORMAL);
#ifdef CYCLOM_16Y_HACK
- udelay(10L);
+ udelay(10L);
#endif
- }
- tty_schedule_flip(tty);
- }
- /* end of service */
- base_addr[CyREOIR] = save_cnt ? 0 : CyNOTRANS;
- return IRQ_HANDLED;
-} /* cy_rx_interrupt */
+ }
+ tty_schedule_flip(tty);
+ }
+ /* end of service */
+ base_addr[CyREOIR] = save_cnt ? 0 : CyNOTRANS;
+ return IRQ_HANDLED;
+} /* cy_rx_interrupt */
/*
* This routine is used to handle the "bottom half" processing for the
@@ -705,192 +712,188 @@ cd2401_rx_interrupt(int irq, void *dev_id)
* structure) to the bottom half of the driver. Previous kernels
* had to poll every port to see if that port needed servicing.
*/
-static void
-do_softint(struct work_struct *ugly_api)
+static void do_softint(struct work_struct *ugly_api)
{
- struct cyclades_port *info = container_of(ugly_api, struct cyclades_port, tqueue);
- struct tty_struct *tty;
-
- tty = info->tty;
- if (!tty)
- return;
+ struct cyclades_port *info =
+ container_of(ugly_api, struct cyclades_port, tqueue);
+ struct tty_struct *tty;
- if (test_and_clear_bit(Cy_EVENT_HANGUP, &info->event)) {
- tty_hangup(info->tty);
- wake_up_interruptible(&info->open_wait);
- info->flags &= ~ASYNC_NORMAL_ACTIVE;
- }
- if (test_and_clear_bit(Cy_EVENT_OPEN_WAKEUP, &info->event)) {
- wake_up_interruptible(&info->open_wait);
- }
- if (test_and_clear_bit(Cy_EVENT_WRITE_WAKEUP, &info->event)) {
- tty_wakeup(tty);
- }
-} /* do_softint */
+ tty = info->tty;
+ if (!tty)
+ return;
+ if (test_and_clear_bit(Cy_EVENT_HANGUP, &info->event)) {
+ tty_hangup(info->tty);
+ wake_up_interruptible(&info->open_wait);
+ info->flags &= ~ASYNC_NORMAL_ACTIVE;
+ }
+ if (test_and_clear_bit(Cy_EVENT_OPEN_WAKEUP, &info->event)) {
+ wake_up_interruptible(&info->open_wait);
+ }
+ if (test_and_clear_bit(Cy_EVENT_WRITE_WAKEUP, &info->event)) {
+ tty_wakeup(tty);
+ }
+} /* do_softint */
/* This is called whenever a port becomes active;
interrupts are enabled and DTR & RTS are turned on.
*/
-static int
-startup(struct cyclades_port * info)
+static int startup(struct cyclades_port *info)
{
- unsigned long flags;
- volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
- int channel;
+ unsigned long flags;
+ volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
+ int channel;
- if (info->flags & ASYNC_INITIALIZED){
- return 0;
- }
+ if (info->flags & ASYNC_INITIALIZED) {
+ return 0;
+ }
- if (!info->type){
- if (info->tty){
- set_bit(TTY_IO_ERROR, &info->tty->flags);
+ if (!info->type) {
+ if (info->tty) {
+ set_bit(TTY_IO_ERROR, &info->tty->flags);
+ }
+ return 0;
}
- return 0;
- }
- if (!info->xmit_buf){
- info->xmit_buf = (unsigned char *) get_zeroed_page (GFP_KERNEL);
- if (!info->xmit_buf){
- return -ENOMEM;
+ if (!info->xmit_buf) {
+ info->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
+ if (!info->xmit_buf) {
+ return -ENOMEM;
+ }
}
- }
- config_setup(info);
+ config_setup(info);
- channel = info->line;
+ channel = info->line;
#ifdef SERIAL_DEBUG_OPEN
- printk("startup channel %d\n", channel);
+ printk("startup channel %d\n", channel);
#endif
- local_irq_save(flags);
- base_addr[CyCAR] = (u_char)channel;
- write_cy_cmd(base_addr,CyENB_RCVR|CyENB_XMTR);
+ local_irq_save(flags);
+ base_addr[CyCAR] = (u_char) channel;
+ write_cy_cmd(base_addr, CyENB_RCVR | CyENB_XMTR);
- base_addr[CyCAR] = (u_char)channel; /* !!! Is this needed? */
+ base_addr[CyCAR] = (u_char) channel; /* !!! Is this needed? */
base_addr[CyMSVR1] = CyRTS;
/* CP('S');CP('1'); */
base_addr[CyMSVR2] = CyDTR;
#ifdef SERIAL_DEBUG_DTR
- printk("cyc: %d: raising DTR\n", __LINE__);
- printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1], base_addr[CyMSVR2]);
+ printk("cyc: %d: raising DTR\n", __LINE__);
+ printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
+ base_addr[CyMSVR2]);
#endif
base_addr[CyIER] |= CyRxData;
info->flags |= ASYNC_INITIALIZED;
- if (info->tty){
- clear_bit(TTY_IO_ERROR, &info->tty->flags);
+ if (info->tty) {
+ clear_bit(TTY_IO_ERROR, &info->tty->flags);
}
info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
- local_irq_restore(flags);
+ local_irq_restore(flags);
#ifdef SERIAL_DEBUG_OPEN
- printk(" done\n");
+ printk(" done\n");
#endif
- return 0;
-} /* startup */
+ return 0;
+} /* startup */
-void
-start_xmit( struct cyclades_port *info )
+void start_xmit(struct cyclades_port *info)
{
- unsigned long flags;
- volatile unsigned char *base_addr = (u_char *)BASE_ADDR;
- int channel;
+ unsigned long flags;
+ volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
+ int channel;
- channel = info->line;
- local_irq_save(flags);
+ channel = info->line;
+ local_irq_save(flags);
base_addr[CyCAR] = channel;
base_addr[CyIER] |= CyTxMpty;
- local_irq_restore(flags);
-} /* start_xmit */
+ local_irq_restore(flags);
+} /* start_xmit */
/*
* This routine shuts down a serial port; interrupts are disabled,
* and DTR is dropped if the hangup on close termio flag is on.
*/
-static void
-shutdown(struct cyclades_port * info)
+static void shutdown(struct cyclades_port *info)
{
- unsigned long flags;
- volatile unsigned char *base_addr = (u_char *)BASE_ADDR;
- int channel;
+ unsigned long flags;
+ volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
+ int channel;
- if (!(info->flags & ASYNC_INITIALIZED)){
+ if (!(info->flags & ASYNC_INITIALIZED)) {
/* CP('$'); */
- return;
- }
+ return;
+ }
- channel = info->line;
+ channel = info->line;
#ifdef SERIAL_DEBUG_OPEN
- printk("shutdown channel %d\n", channel);
+ printk("shutdown channel %d\n", channel);
#endif
- /* !!! REALLY MUST WAIT FOR LAST CHARACTER TO BE
- SENT BEFORE DROPPING THE LINE !!! (Perhaps
- set some flag that is read when XMTY happens.)
- Other choices are to delay some fixed interval
- or schedule some later processing.
- */
- local_irq_save(flags);
- if (info->xmit_buf){
- free_page((unsigned long) info->xmit_buf);
- info->xmit_buf = NULL;
+ /* !!! REALLY MUST WAIT FOR LAST CHARACTER TO BE
+ SENT BEFORE DROPPING THE LINE !!! (Perhaps
+ set some flag that is read when XMTY happens.)
+ Other choices are to delay some fixed interval
+ or schedule some later processing.
+ */
+ local_irq_save(flags);
+ if (info->xmit_buf) {
+ free_page((unsigned long)info->xmit_buf);
+ info->xmit_buf = NULL;
}
- base_addr[CyCAR] = (u_char)channel;
+ base_addr[CyCAR] = (u_char) channel;
if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
- base_addr[CyMSVR1] = 0;
+ base_addr[CyMSVR1] = 0;
/* CP('C');CP('1'); */
- base_addr[CyMSVR2] = 0;
+ base_addr[CyMSVR2] = 0;
#ifdef SERIAL_DEBUG_DTR
- printk("cyc: %d: dropping DTR\n", __LINE__);
- printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1], base_addr[CyMSVR2]);
+ printk("cyc: %d: dropping DTR\n", __LINE__);
+ printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
+ base_addr[CyMSVR2]);
#endif
- }
- write_cy_cmd(base_addr,CyDIS_RCVR);
- /* it may be appropriate to clear _XMIT at
- some later date (after testing)!!! */
+ }
+ write_cy_cmd(base_addr, CyDIS_RCVR);
+ /* it may be appropriate to clear _XMIT at
+ some later date (after testing)!!! */
- if (info->tty){
- set_bit(TTY_IO_ERROR, &info->tty->flags);
+ if (info->tty) {
+ set_bit(TTY_IO_ERROR, &info->tty->flags);
}
info->flags &= ~ASYNC_INITIALIZED;
- local_irq_restore(flags);
+ local_irq_restore(flags);
#ifdef SERIAL_DEBUG_OPEN
- printk(" done\n");
+ printk(" done\n");
#endif
- return;
-} /* shutdown */
+} /* shutdown */
/*
* This routine finds or computes the various line characteristics.
*/
-static void
-config_setup(struct cyclades_port * info)
+static void config_setup(struct cyclades_port *info)
{
- unsigned long flags;
- volatile unsigned char *base_addr = (u_char *)BASE_ADDR;
- int channel;
- unsigned cflag;
- int i;
- unsigned char ti, need_init_chan = 0;
-
- if (!info->tty || !info->tty->termios){
- return;
- }
- if (info->line == -1){
- return;
- }
- cflag = info->tty->termios->c_cflag;
-
- /* baud rate */
- i = cflag & CBAUD;
+ unsigned long flags;
+ volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
+ int channel;
+ unsigned cflag;
+ int i;
+ unsigned char ti, need_init_chan = 0;
+
+ if (!info->tty || !info->tty->termios) {
+ return;
+ }
+ if (info->line == -1) {
+ return;
+ }
+ cflag = info->tty->termios->c_cflag;
+
+ /* baud rate */
+ i = cflag & CBAUD;
#ifdef CBAUDEX
/* Starting with kernel 1.1.65, there is direct support for
higher baud rates. The following code supports those
@@ -900,120 +903,123 @@ config_setup(struct cyclades_port * info)
is still the possibility of supporting 75 kbit/sec with
the Cyclades board.)
*/
- if (i & CBAUDEX) {
- if (i == B57600)
- i = 16;
- else if(i == B115200)
- i = 18;
+ if (i & CBAUDEX) {
+ if (i == B57600)
+ i = 16;
+ else if (i == B115200)
+ i = 18;
#ifdef B78600
- else if(i == B78600)
- i = 17;
+ else if (i == B78600)
+ i = 17;
#endif
- else
- info->tty->termios->c_cflag &= ~CBAUDEX;
- }
-#endif
- if (i == 15) {
- if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
- i += 1;
- if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
- i += 3;
- }
- /* Don't ever change the speed of the console port. It will
- * run at the speed specified in bootinfo, or at 19.2K */
- /* Actually, it should run at whatever speed 166Bug was using */
- /* Note info->timeout isn't used at present */
- if (info != serial_console_info) {
- info->tbpr = baud_bpr[i]; /* Tx BPR */
- info->tco = baud_co[i]; /* Tx CO */
- info->rbpr = baud_bpr[i]; /* Rx BPR */
- info->rco = baud_co[i] >> 5; /* Rx CO */
- if (baud_table[i] == 134) {
- info->timeout = (info->xmit_fifo_size*HZ*30/269) + 2;
- /* get it right for 134.5 baud */
- } else if (baud_table[i]) {
- info->timeout = (info->xmit_fifo_size*HZ*15/baud_table[i]) + 2;
- /* this needs to be propagated into the card info */
+ else
+ info->tty->termios->c_cflag &= ~CBAUDEX;
+ }
+#endif
+ if (i == 15) {
+ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+ i += 1;
+ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+ i += 3;
+ }
+ /* Don't ever change the speed of the console port. It will
+ * run at the speed specified in bootinfo, or at 19.2K */
+ /* Actually, it should run at whatever speed 166Bug was using */
+ /* Note info->timeout isn't used at present */
+ if (info != serial_console_info) {
+ info->tbpr = baud_bpr[i]; /* Tx BPR */
+ info->tco = baud_co[i]; /* Tx CO */
+ info->rbpr = baud_bpr[i]; /* Rx BPR */
+ info->rco = baud_co[i] >> 5; /* Rx CO */
+ if (baud_table[i] == 134) {
+ info->timeout =
+ (info->xmit_fifo_size * HZ * 30 / 269) + 2;
+ /* get it right for 134.5 baud */
+ } else if (baud_table[i]) {
+ info->timeout =
+ (info->xmit_fifo_size * HZ * 15 / baud_table[i]) +
+ 2;
+ /* this needs to be propagated into the card info */
+ } else {
+ info->timeout = 0;
+ }
+ }
+ /* By tradition (is it a standard?) a baud rate of zero
+ implies the line should be/has been closed. A bit
+ later in this routine such a test is performed. */
+
+ /* byte size and parity */
+ info->cor7 = 0;
+ info->cor6 = 0;
+ info->cor5 = 0;
+ info->cor4 = (info->default_threshold ? info->default_threshold : baud_cor4[i]); /* receive threshold */
+ /* Following two lines added 101295, RGH. */
+ /* It is obviously wrong to access CyCORx, and not info->corx here,
+ * try and remember to fix it later! */
+ channel = info->line;
+ base_addr[CyCAR] = (u_char) channel;
+ if (C_CLOCAL(info->tty)) {
+ if (base_addr[CyIER] & CyMdmCh)
+ base_addr[CyIER] &= ~CyMdmCh; /* without modem intr */
+ /* ignore 1->0 modem transitions */
+ if (base_addr[CyCOR4] & (CyDSR | CyCTS | CyDCD))
+ base_addr[CyCOR4] &= ~(CyDSR | CyCTS | CyDCD);
+ /* ignore 0->1 modem transitions */
+ if (base_addr[CyCOR5] & (CyDSR | CyCTS | CyDCD))
+ base_addr[CyCOR5] &= ~(CyDSR | CyCTS | CyDCD);
} else {
- info->timeout = 0;
- }
- }
- /* By tradition (is it a standard?) a baud rate of zero
- implies the line should be/has been closed. A bit
- later in this routine such a test is performed. */
-
- /* byte size and parity */
- info->cor7 = 0;
- info->cor6 = 0;
- info->cor5 = 0;
- info->cor4 = (info->default_threshold
- ? info->default_threshold
- : baud_cor4[i]); /* receive threshold */
- /* Following two lines added 101295, RGH. */
- /* It is obviously wrong to access CyCORx, and not info->corx here,
- * try and remember to fix it later! */
- channel = info->line;
- base_addr[CyCAR] = (u_char)channel;
- if (C_CLOCAL(info->tty)) {
- if (base_addr[CyIER] & CyMdmCh)
- base_addr[CyIER] &= ~CyMdmCh; /* without modem intr */
- /* ignore 1->0 modem transitions */
- if (base_addr[CyCOR4] & (CyDSR|CyCTS|CyDCD))
- base_addr[CyCOR4] &= ~(CyDSR|CyCTS|CyDCD);
- /* ignore 0->1 modem transitions */
- if (base_addr[CyCOR5] & (CyDSR|CyCTS|CyDCD))
- base_addr[CyCOR5] &= ~(CyDSR|CyCTS|CyDCD);
- } else {
- if ((base_addr[CyIER] & CyMdmCh) != CyMdmCh)
- base_addr[CyIER] |= CyMdmCh; /* with modem intr */
- /* act on 1->0 modem transitions */
- if ((base_addr[CyCOR4] & (CyDSR|CyCTS|CyDCD)) != (CyDSR|CyCTS|CyDCD))
- base_addr[CyCOR4] |= CyDSR|CyCTS|CyDCD;
- /* act on 0->1 modem transitions */
- if ((base_addr[CyCOR5] & (CyDSR|CyCTS|CyDCD)) != (CyDSR|CyCTS|CyDCD))
- base_addr[CyCOR5] |= CyDSR|CyCTS|CyDCD;
- }
- info->cor3 = (cflag & CSTOPB) ? Cy_2_STOP : Cy_1_STOP;
- info->cor2 = CyETC;
- switch(cflag & CSIZE){
- case CS5:
- info->cor1 = Cy_5_BITS;
- break;
- case CS6:
- info->cor1 = Cy_6_BITS;
- break;
- case CS7:
- info->cor1 = Cy_7_BITS;
- break;
- case CS8:
- info->cor1 = Cy_8_BITS;
- break;
- }
- if (cflag & PARENB){
- if (cflag & PARODD){
- info->cor1 |= CyPARITY_O;
- }else{
- info->cor1 |= CyPARITY_E;
- }
- }else{
- info->cor1 |= CyPARITY_NONE;
- }
-
- /* CTS flow control flag */
+ if ((base_addr[CyIER] & CyMdmCh) != CyMdmCh)
+ base_addr[CyIER] |= CyMdmCh; /* with modem intr */
+ /* act on 1->0 modem transitions */
+ if ((base_addr[CyCOR4] & (CyDSR | CyCTS | CyDCD)) !=
+ (CyDSR | CyCTS | CyDCD))
+ base_addr[CyCOR4] |= CyDSR | CyCTS | CyDCD;
+ /* act on 0->1 modem transitions */
+ if ((base_addr[CyCOR5] & (CyDSR | CyCTS | CyDCD)) !=
+ (CyDSR | CyCTS | CyDCD))
+ base_addr[CyCOR5] |= CyDSR | CyCTS | CyDCD;
+ }
+ info->cor3 = (cflag & CSTOPB) ? Cy_2_STOP : Cy_1_STOP;
+ info->cor2 = CyETC;
+ switch (cflag & CSIZE) {
+ case CS5:
+ info->cor1 = Cy_5_BITS;
+ break;
+ case CS6:
+ info->cor1 = Cy_6_BITS;
+ break;
+ case CS7:
+ info->cor1 = Cy_7_BITS;
+ break;
+ case CS8:
+ info->cor1 = Cy_8_BITS;
+ break;
+ }
+ if (cflag & PARENB) {
+ if (cflag & PARODD) {
+ info->cor1 |= CyPARITY_O;
+ } else {
+ info->cor1 |= CyPARITY_E;
+ }
+ } else {
+ info->cor1 |= CyPARITY_NONE;
+ }
+
+ /* CTS flow control flag */
#if 0
- /* Don't complcate matters for now! RGH 141095 */
- if (cflag & CRTSCTS){
- info->flags |= ASYNC_CTS_FLOW;
- info->cor2 |= CyCtsAE;
- }else{
- info->flags &= ~ASYNC_CTS_FLOW;
- info->cor2 &= ~CyCtsAE;
- }
-#endif
- if (cflag & CLOCAL)
- info->flags &= ~ASYNC_CHECK_CD;
- else
- info->flags |= ASYNC_CHECK_CD;
+ /* Don't complcate matters for now! RGH 141095 */
+ if (cflag & CRTSCTS) {
+ info->flags |= ASYNC_CTS_FLOW;
+ info->cor2 |= CyCtsAE;
+ } else {
+ info->flags &= ~ASYNC_CTS_FLOW;
+ info->cor2 &= ~CyCtsAE;
+ }
+#endif
+ if (cflag & CLOCAL)
+ info->flags &= ~ASYNC_CHECK_CD;
+ else
+ info->flags |= ASYNC_CHECK_CD;
/***********************************************
The hardware option, CyRtsAO, presents RTS when
@@ -1025,149 +1031,146 @@ config_setup(struct cyclades_port * info)
cable. Contact Marcio Saito for details.
***********************************************/
- channel = info->line;
+ channel = info->line;
- local_irq_save(flags);
- base_addr[CyCAR] = (u_char)channel;
+ local_irq_save(flags);
+ base_addr[CyCAR] = (u_char) channel;
/* CyCMR set once only in mvme167_init_serial() */
if (base_addr[CyLICR] != channel << 2)
- base_addr[CyLICR] = channel << 2;
+ base_addr[CyLICR] = channel << 2;
if (base_addr[CyLIVR] != 0x5c)
- base_addr[CyLIVR] = 0x5c;
+ base_addr[CyLIVR] = 0x5c;
- /* tx and rx baud rate */
+ /* tx and rx baud rate */
if (base_addr[CyCOR1] != info->cor1)
- need_init_chan = 1;
+ need_init_chan = 1;
if (base_addr[CyTCOR] != info->tco)
- base_addr[CyTCOR] = info->tco;
+ base_addr[CyTCOR] = info->tco;
if (base_addr[CyTBPR] != info->tbpr)
- base_addr[CyTBPR] = info->tbpr;
+ base_addr[CyTBPR] = info->tbpr;
if (base_addr[CyRCOR] != info->rco)
- base_addr[CyRCOR] = info->rco;
+ base_addr[CyRCOR] = info->rco;
if (base_addr[CyRBPR] != info->rbpr)
- base_addr[CyRBPR] = info->rbpr;
+ base_addr[CyRBPR] = info->rbpr;
/* set line characteristics according configuration */
if (base_addr[CySCHR1] != START_CHAR(info->tty))
- base_addr[CySCHR1] = START_CHAR(info->tty);
+ base_addr[CySCHR1] = START_CHAR(info->tty);
if (base_addr[CySCHR2] != STOP_CHAR(info->tty))
- base_addr[CySCHR2] = STOP_CHAR(info->tty);
+ base_addr[CySCHR2] = STOP_CHAR(info->tty);
if (base_addr[CySCRL] != START_CHAR(info->tty))
- base_addr[CySCRL] = START_CHAR(info->tty);
+ base_addr[CySCRL] = START_CHAR(info->tty);
if (base_addr[CySCRH] != START_CHAR(info->tty))
- base_addr[CySCRH] = START_CHAR(info->tty);
+ base_addr[CySCRH] = START_CHAR(info->tty);
if (base_addr[CyCOR1] != info->cor1)
- base_addr[CyCOR1] = info->cor1;
+ base_addr[CyCOR1] = info->cor1;
if (base_addr[CyCOR2] != info->cor2)
- base_addr[CyCOR2] = info->cor2;
+ base_addr[CyCOR2] = info->cor2;
if (base_addr[CyCOR3] != info->cor3)
- base_addr[CyCOR3] = info->cor3;
+ base_addr[CyCOR3] = info->cor3;
if (base_addr[CyCOR4] != info->cor4)
- base_addr[CyCOR4] = info->cor4;
+ base_addr[CyCOR4] = info->cor4;
if (base_addr[CyCOR5] != info->cor5)
- base_addr[CyCOR5] = info->cor5;
+ base_addr[CyCOR5] = info->cor5;
if (base_addr[CyCOR6] != info->cor6)
- base_addr[CyCOR6] = info->cor6;
+ base_addr[CyCOR6] = info->cor6;
if (base_addr[CyCOR7] != info->cor7)
- base_addr[CyCOR7] = info->cor7;
+ base_addr[CyCOR7] = info->cor7;
if (need_init_chan)
- write_cy_cmd(base_addr,CyINIT_CHAN);
+ write_cy_cmd(base_addr, CyINIT_CHAN);
- base_addr[CyCAR] = (u_char)channel; /* !!! Is this needed? */
+ base_addr[CyCAR] = (u_char) channel; /* !!! Is this needed? */
/* 2ms default rx timeout */
ti = info->default_timeout ? info->default_timeout : 0x02;
if (base_addr[CyRTPRL] != ti)
- base_addr[CyRTPRL] = ti;
+ base_addr[CyRTPRL] = ti;
if (base_addr[CyRTPRH] != 0)
- base_addr[CyRTPRH] = 0;
+ base_addr[CyRTPRH] = 0;
/* Set up RTS here also ????? RGH 141095 */
- if(i == 0){ /* baud rate is zero, turn off line */
- if ((base_addr[CyMSVR2] & CyDTR) == CyDTR)
- base_addr[CyMSVR2] = 0;
+ if (i == 0) { /* baud rate is zero, turn off line */
+ if ((base_addr[CyMSVR2] & CyDTR) == CyDTR)
+ base_addr[CyMSVR2] = 0;
#ifdef SERIAL_DEBUG_DTR
- printk("cyc: %d: dropping DTR\n", __LINE__);
- printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1], base_addr[CyMSVR2]);
+ printk("cyc: %d: dropping DTR\n", __LINE__);
+ printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
+ base_addr[CyMSVR2]);
#endif
- }else{
- if ((base_addr[CyMSVR2] & CyDTR) != CyDTR)
- base_addr[CyMSVR2] = CyDTR;
+ } else {
+ if ((base_addr[CyMSVR2] & CyDTR) != CyDTR)
+ base_addr[CyMSVR2] = CyDTR;
#ifdef SERIAL_DEBUG_DTR
- printk("cyc: %d: raising DTR\n", __LINE__);
- printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1], base_addr[CyMSVR2]);
+ printk("cyc: %d: raising DTR\n", __LINE__);
+ printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
+ base_addr[CyMSVR2]);
#endif
}
- if (info->tty){
- clear_bit(TTY_IO_ERROR, &info->tty->flags);
+ if (info->tty) {
+ clear_bit(TTY_IO_ERROR, &info->tty->flags);
}
- local_irq_restore(flags);
-
-} /* config_setup */
+ local_irq_restore(flags);
+} /* config_setup */
-static void
-cy_put_char(struct tty_struct *tty, unsigned char ch)
+static void cy_put_char(struct tty_struct *tty, unsigned char ch)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
- unsigned long flags;
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ unsigned long flags;
#ifdef SERIAL_DEBUG_IO
- printk("cy_put_char %s(0x%02x)\n", tty->name, ch);
+ printk("cy_put_char %s(0x%02x)\n", tty->name, ch);
#endif
- if (serial_paranoia_check(info, tty->name, "cy_put_char"))
- return;
+ if (serial_paranoia_check(info, tty->name, "cy_put_char"))
+ return;
- if (!info->xmit_buf)
- return;
+ if (!info->xmit_buf)
+ return;
- local_irq_save(flags);
+ local_irq_save(flags);
if (info->xmit_cnt >= PAGE_SIZE - 1) {
- local_irq_restore(flags);
- return;
+ local_irq_restore(flags);
+ return;
}
info->xmit_buf[info->xmit_head++] = ch;
info->xmit_head &= PAGE_SIZE - 1;
info->xmit_cnt++;
- local_irq_restore(flags);
-} /* cy_put_char */
-
+ local_irq_restore(flags);
+} /* cy_put_char */
-static void
-cy_flush_chars(struct tty_struct *tty)
+static void cy_flush_chars(struct tty_struct *tty)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
- unsigned long flags;
- volatile unsigned char *base_addr = (u_char *)BASE_ADDR;
- int channel;
-
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ unsigned long flags;
+ volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
+ int channel;
+
#ifdef SERIAL_DEBUG_IO
- printk("cy_flush_chars %s\n", tty->name); /* */
+ printk("cy_flush_chars %s\n", tty->name); /* */
#endif
- if (serial_paranoia_check(info, tty->name, "cy_flush_chars"))
- return;
+ if (serial_paranoia_check(info, tty->name, "cy_flush_chars"))
+ return;
- if (info->xmit_cnt <= 0 || tty->stopped
- || tty->hw_stopped || !info->xmit_buf)
- return;
+ if (info->xmit_cnt <= 0 || tty->stopped
+ || tty->hw_stopped || !info->xmit_buf)
+ return;
- channel = info->line;
+ channel = info->line;
- local_irq_save(flags);
+ local_irq_save(flags);
base_addr[CyCAR] = channel;
base_addr[CyIER] |= CyTxMpty;
- local_irq_restore(flags);
-} /* cy_flush_chars */
-
+ local_irq_restore(flags);
+} /* cy_flush_chars */
/* This routine gets called when tty_write has put something into
the write_queue. If the port is not already transmitting stuff,
@@ -1175,650 +1178,616 @@ cy_flush_chars(struct tty_struct *tty)
routine will then ensure that the characters are sent. If the
port is already active, there is no need to kick it.
*/
-static int
-cy_write(struct tty_struct * tty,
- const unsigned char *buf, int count)
+static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
- unsigned long flags;
- int c, total = 0;
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ unsigned long flags;
+ int c, total = 0;
#ifdef SERIAL_DEBUG_IO
- printk("cy_write %s\n", tty->name); /* */
+ printk("cy_write %s\n", tty->name); /* */
#endif
- if (serial_paranoia_check(info, tty->name, "cy_write")){
- return 0;
- }
-
- if (!info->xmit_buf){
- return 0;
- }
-
- while (1) {
- local_irq_save(flags);
- c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
- SERIAL_XMIT_SIZE - info->xmit_head));
- if (c <= 0) {
- local_irq_restore(flags);
- break;
- }
-
- memcpy(info->xmit_buf + info->xmit_head, buf, c);
- info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
- info->xmit_cnt += c;
- local_irq_restore(flags);
-
- buf += c;
- count -= c;
- total += c;
- }
-
- if (info->xmit_cnt
- && !tty->stopped
- && !tty->hw_stopped ) {
- start_xmit(info);
- }
- return total;
-} /* cy_write */
+ if (serial_paranoia_check(info, tty->name, "cy_write")) {
+ return 0;
+ }
+ if (!info->xmit_buf) {
+ return 0;
+ }
-static int
-cy_write_room(struct tty_struct *tty)
+ while (1) {
+ local_irq_save(flags);
+ c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+ SERIAL_XMIT_SIZE - info->xmit_head));
+ if (c <= 0) {
+ local_irq_restore(flags);
+ break;
+ }
+
+ memcpy(info->xmit_buf + info->xmit_head, buf, c);
+ info->xmit_head =
+ (info->xmit_head + c) & (SERIAL_XMIT_SIZE - 1);
+ info->xmit_cnt += c;
+ local_irq_restore(flags);
+
+ buf += c;
+ count -= c;
+ total += c;
+ }
+
+ if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) {
+ start_xmit(info);
+ }
+ return total;
+} /* cy_write */
+
+static int cy_write_room(struct tty_struct *tty)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
- int ret;
-
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ int ret;
+
#ifdef SERIAL_DEBUG_IO
- printk("cy_write_room %s\n", tty->name); /* */
+ printk("cy_write_room %s\n", tty->name); /* */
#endif
- if (serial_paranoia_check(info, tty->name, "cy_write_room"))
- return 0;
- ret = PAGE_SIZE - info->xmit_cnt - 1;
- if (ret < 0)
- ret = 0;
- return ret;
-} /* cy_write_room */
-
+ if (serial_paranoia_check(info, tty->name, "cy_write_room"))
+ return 0;
+ ret = PAGE_SIZE - info->xmit_cnt - 1;
+ if (ret < 0)
+ ret = 0;
+ return ret;
+} /* cy_write_room */
-static int
-cy_chars_in_buffer(struct tty_struct *tty)
+static int cy_chars_in_buffer(struct tty_struct *tty)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
-
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+
#ifdef SERIAL_DEBUG_IO
- printk("cy_chars_in_buffer %s %d\n", tty->name, info->xmit_cnt); /* */
+ printk("cy_chars_in_buffer %s %d\n", tty->name, info->xmit_cnt); /* */
#endif
- if (serial_paranoia_check(info, tty->name, "cy_chars_in_buffer"))
- return 0;
-
- return info->xmit_cnt;
-} /* cy_chars_in_buffer */
+ if (serial_paranoia_check(info, tty->name, "cy_chars_in_buffer"))
+ return 0;
+ return info->xmit_cnt;
+} /* cy_chars_in_buffer */
-static void
-cy_flush_buffer(struct tty_struct *tty)
+static void cy_flush_buffer(struct tty_struct *tty)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
- unsigned long flags;
-
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ unsigned long flags;
+
#ifdef SERIAL_DEBUG_IO
- printk("cy_flush_buffer %s\n", tty->name); /* */
+ printk("cy_flush_buffer %s\n", tty->name); /* */
#endif
- if (serial_paranoia_check(info, tty->name, "cy_flush_buffer"))
- return;
- local_irq_save(flags);
+ if (serial_paranoia_check(info, tty->name, "cy_flush_buffer"))
+ return;
+ local_irq_save(flags);
info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
- local_irq_restore(flags);
- tty_wakeup(tty);
-} /* cy_flush_buffer */
-
+ local_irq_restore(flags);
+ tty_wakeup(tty);
+} /* cy_flush_buffer */
/* This routine is called by the upper-layer tty layer to signal
that incoming characters should be throttled or that the
throttle should be released.
*/
-static void
-cy_throttle(struct tty_struct * tty)
+static void cy_throttle(struct tty_struct *tty)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
- unsigned long flags;
- volatile unsigned char *base_addr = (u_char *)BASE_ADDR;
- int channel;
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ unsigned long flags;
+ volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
+ int channel;
#ifdef SERIAL_DEBUG_THROTTLE
- char buf[64];
-
- printk("throttle %s: %d....\n", tty_name(tty, buf),
- tty->ldisc.chars_in_buffer(tty));
- printk("cy_throttle %s\n", tty->name);
+ char buf[64];
+
+ printk("throttle %s: %d....\n", tty_name(tty, buf),
+ tty->ldisc.chars_in_buffer(tty));
+ printk("cy_throttle %s\n", tty->name);
#endif
- if (serial_paranoia_check(info, tty->name, "cy_nthrottle")){
- return;
- }
+ if (serial_paranoia_check(info, tty->name, "cy_nthrottle")) {
+ return;
+ }
- if (I_IXOFF(tty)) {
- info->x_char = STOP_CHAR(tty);
- /* Should use the "Send Special Character" feature!!! */
- }
+ if (I_IXOFF(tty)) {
+ info->x_char = STOP_CHAR(tty);
+ /* Should use the "Send Special Character" feature!!! */
+ }
- channel = info->line;
+ channel = info->line;
- local_irq_save(flags);
- base_addr[CyCAR] = (u_char)channel;
+ local_irq_save(flags);
+ base_addr[CyCAR] = (u_char) channel;
base_addr[CyMSVR1] = 0;
- local_irq_restore(flags);
-
- return;
-} /* cy_throttle */
-
+ local_irq_restore(flags);
+} /* cy_throttle */
-static void
-cy_unthrottle(struct tty_struct * tty)
+static void cy_unthrottle(struct tty_struct *tty)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
- unsigned long flags;
- volatile unsigned char *base_addr = (u_char *)BASE_ADDR;
- int channel;
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ unsigned long flags;
+ volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
+ int channel;
#ifdef SERIAL_DEBUG_THROTTLE
- char buf[64];
-
- printk("throttle %s: %d....\n", tty_name(tty, buf),
- tty->ldisc.chars_in_buffer(tty));
- printk("cy_unthrottle %s\n", tty->name);
+ char buf[64];
+
+ printk("throttle %s: %d....\n", tty_name(tty, buf),
+ tty->ldisc.chars_in_buffer(tty));
+ printk("cy_unthrottle %s\n", tty->name);
#endif
- if (serial_paranoia_check(info, tty->name, "cy_nthrottle")){
- return;
- }
+ if (serial_paranoia_check(info, tty->name, "cy_nthrottle")) {
+ return;
+ }
- if (I_IXOFF(tty)) {
- info->x_char = START_CHAR(tty);
- /* Should use the "Send Special Character" feature!!! */
- }
+ if (I_IXOFF(tty)) {
+ info->x_char = START_CHAR(tty);
+ /* Should use the "Send Special Character" feature!!! */
+ }
- channel = info->line;
+ channel = info->line;
- local_irq_save(flags);
- base_addr[CyCAR] = (u_char)channel;
+ local_irq_save(flags);
+ base_addr[CyCAR] = (u_char) channel;
base_addr[CyMSVR1] = CyRTS;
- local_irq_restore(flags);
-
- return;
-} /* cy_unthrottle */
+ local_irq_restore(flags);
+} /* cy_unthrottle */
static int
-get_serial_info(struct cyclades_port * info,
- struct serial_struct __user * retinfo)
+get_serial_info(struct cyclades_port *info,
+ struct serial_struct __user * retinfo)
{
- struct serial_struct tmp;
+ struct serial_struct tmp;
/* CP('g'); */
- if (!retinfo)
- return -EFAULT;
- memset(&tmp, 0, sizeof(tmp));
- tmp.type = info->type;
- tmp.line = info->line;
- tmp.port = info->line;
- tmp.irq = 0;
- tmp.flags = info->flags;
- tmp.baud_base = 0; /*!!!*/
- tmp.close_delay = info->close_delay;
- tmp.custom_divisor = 0; /*!!!*/
- tmp.hub6 = 0; /*!!!*/
- return copy_to_user(retinfo,&tmp,sizeof(*retinfo)) ? -EFAULT : 0;
-} /* get_serial_info */
+ if (!retinfo)
+ return -EFAULT;
+ memset(&tmp, 0, sizeof(tmp));
+ tmp.type = info->type;
+ tmp.line = info->line;
+ tmp.port = info->line;
+ tmp.irq = 0;
+ tmp.flags = info->flags;
+ tmp.baud_base = 0; /*!!! */
+ tmp.close_delay = info->close_delay;
+ tmp.custom_divisor = 0; /*!!! */
+ tmp.hub6 = 0; /*!!! */
+ return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
+} /* get_serial_info */
static int
-set_serial_info(struct cyclades_port * info,
- struct serial_struct __user * new_info)
+set_serial_info(struct cyclades_port *info,
+ struct serial_struct __user * new_info)
{
- struct serial_struct new_serial;
- struct cyclades_port old_info;
+ struct serial_struct new_serial;
+ struct cyclades_port old_info;
/* CP('s'); */
- if (!new_info)
- return -EFAULT;
- if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
- return -EFAULT;
- old_info = *info;
+ if (!new_info)
+ return -EFAULT;
+ if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
+ return -EFAULT;
+ old_info = *info;
+
+ if (!capable(CAP_SYS_ADMIN)) {
+ if ((new_serial.close_delay != info->close_delay) ||
+ ((new_serial.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK) !=
+ (info->flags & ASYNC_FLAGS & ~ASYNC_USR_MASK)))
+ return -EPERM;
+ info->flags = ((info->flags & ~ASYNC_USR_MASK) |
+ (new_serial.flags & ASYNC_USR_MASK));
+ goto check_and_exit;
+ }
- if (!capable(CAP_SYS_ADMIN)) {
- if ((new_serial.close_delay != info->close_delay) ||
- ((new_serial.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK) !=
- (info->flags & ASYNC_FLAGS & ~ASYNC_USR_MASK)))
- return -EPERM;
- info->flags = ((info->flags & ~ASYNC_USR_MASK) |
- (new_serial.flags & ASYNC_USR_MASK));
- goto check_and_exit;
- }
+ /*
+ * OK, past this point, all the error checking has been done.
+ * At this point, we start making changes.....
+ */
+ info->flags = ((info->flags & ~ASYNC_FLAGS) |
+ (new_serial.flags & ASYNC_FLAGS));
+ info->close_delay = new_serial.close_delay;
- /*
- * OK, past this point, all the error checking has been done.
- * At this point, we start making changes.....
- */
+check_and_exit:
+ if (info->flags & ASYNC_INITIALIZED) {
+ config_setup(info);
+ return 0;
+ }
+ return startup(info);
+} /* set_serial_info */
- info->flags = ((info->flags & ~ASYNC_FLAGS) |
- (new_serial.flags & ASYNC_FLAGS));
- info->close_delay = new_serial.close_delay;
+static int cy_tiocmget(struct tty_struct *tty, struct file *file)
+{
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ int channel;
+ volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
+ unsigned long flags;
+ unsigned char status;
+ channel = info->line;
-check_and_exit:
- if (info->flags & ASYNC_INITIALIZED){
- config_setup(info);
- return 0;
- }else{
- return startup(info);
- }
-} /* set_serial_info */
+ local_irq_save(flags);
+ base_addr[CyCAR] = (u_char) channel;
+ status = base_addr[CyMSVR1] | base_addr[CyMSVR2];
+ local_irq_restore(flags);
-static int
-cy_tiocmget(struct tty_struct *tty, struct file *file)
-{
- struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;
- int channel;
- volatile unsigned char *base_addr = (u_char *)BASE_ADDR;
- unsigned long flags;
- unsigned char status;
-
- channel = info->line;
-
- local_irq_save(flags);
- base_addr[CyCAR] = (u_char)channel;
- status = base_addr[CyMSVR1] | base_addr[CyMSVR2];
- local_irq_restore(flags);
-
- return ((status & CyRTS) ? TIOCM_RTS : 0)
- | ((status & CyDTR) ? TIOCM_DTR : 0)
- | ((status & CyDCD) ? TIOCM_CAR : 0)
- | ((status & CyDSR) ? TIOCM_DSR : 0)
- | ((status & CyCTS) ? TIOCM_CTS : 0);
-} /* cy_tiocmget */
+ return ((status & CyRTS) ? TIOCM_RTS : 0)
+ | ((status & CyDTR) ? TIOCM_DTR : 0)
+ | ((status & CyDCD) ? TIOCM_CAR : 0)
+ | ((status & CyDSR) ? TIOCM_DSR : 0)
+ | ((status & CyCTS) ? TIOCM_CTS : 0);
+} /* cy_tiocmget */
static int
cy_tiocmset(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear)
{
- struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;
- int channel;
- volatile unsigned char *base_addr = (u_char *)BASE_ADDR;
- unsigned long flags;
-
- channel = info->line;
-
- if (set & TIOCM_RTS){
- local_irq_save(flags);
- base_addr[CyCAR] = (u_char)channel;
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ int channel;
+ volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
+ unsigned long flags;
+
+ channel = info->line;
+
+ if (set & TIOCM_RTS) {
+ local_irq_save(flags);
+ base_addr[CyCAR] = (u_char) channel;
base_addr[CyMSVR1] = CyRTS;
- local_irq_restore(flags);
+ local_irq_restore(flags);
}
- if (set & TIOCM_DTR){
- local_irq_save(flags);
- base_addr[CyCAR] = (u_char)channel;
+ if (set & TIOCM_DTR) {
+ local_irq_save(flags);
+ base_addr[CyCAR] = (u_char) channel;
/* CP('S');CP('2'); */
- base_addr[CyMSVR2] = CyDTR;
+ base_addr[CyMSVR2] = CyDTR;
#ifdef SERIAL_DEBUG_DTR
- printk("cyc: %d: raising DTR\n", __LINE__);
- printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1], base_addr[CyMSVR2]);
+ printk("cyc: %d: raising DTR\n", __LINE__);
+ printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
+ base_addr[CyMSVR2]);
#endif
- local_irq_restore(flags);
+ local_irq_restore(flags);
}
- if (clear & TIOCM_RTS){
- local_irq_save(flags);
- base_addr[CyCAR] = (u_char)channel;
+ if (clear & TIOCM_RTS) {
+ local_irq_save(flags);
+ base_addr[CyCAR] = (u_char) channel;
base_addr[CyMSVR1] = 0;
- local_irq_restore(flags);
+ local_irq_restore(flags);
}
- if (clear & TIOCM_DTR){
- local_irq_save(flags);
- base_addr[CyCAR] = (u_char)channel;
+ if (clear & TIOCM_DTR) {
+ local_irq_save(flags);
+ base_addr[CyCAR] = (u_char) channel;
/* CP('C');CP('2'); */
- base_addr[CyMSVR2] = 0;
+ base_addr[CyMSVR2] = 0;
#ifdef SERIAL_DEBUG_DTR
- printk("cyc: %d: dropping DTR\n", __LINE__);
- printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1], base_addr[CyMSVR2]);
+ printk("cyc: %d: dropping DTR\n", __LINE__);
+ printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
+ base_addr[CyMSVR2]);
#endif
- local_irq_restore(flags);
+ local_irq_restore(flags);
}
- return 0;
-} /* set_modem_info */
-
-static void
-send_break( struct cyclades_port * info, int duration)
-{ /* Let the transmit ISR take care of this (since it
- requires stuffing characters into the output stream).
- */
- info->x_break = duration;
- if (!info->xmit_cnt ) {
- start_xmit(info);
- }
-} /* send_break */
+ return 0;
+} /* set_modem_info */
+
+static void send_break(struct cyclades_port *info, int duration)
+{ /* Let the transmit ISR take care of this (since it
+ requires stuffing characters into the output stream).
+ */
+ info->x_break = duration;
+ if (!info->xmit_cnt) {
+ start_xmit(info);
+ }
+} /* send_break */
static int
-get_mon_info(struct cyclades_port * info, struct cyclades_monitor __user * mon)
+get_mon_info(struct cyclades_port *info, struct cyclades_monitor __user * mon)
{
- if (copy_to_user(mon, &info->mon, sizeof(struct cyclades_monitor)))
- return -EFAULT;
- info->mon.int_count = 0;
- info->mon.char_count = 0;
- info->mon.char_max = 0;
- info->mon.char_last = 0;
- return 0;
+ if (copy_to_user(mon, &info->mon, sizeof(struct cyclades_monitor)))
+ return -EFAULT;
+ info->mon.int_count = 0;
+ info->mon.char_count = 0;
+ info->mon.char_max = 0;
+ info->mon.char_last = 0;
+ return 0;
}
-static int
-set_threshold(struct cyclades_port * info, unsigned long __user *arg)
+static int set_threshold(struct cyclades_port *info, unsigned long __user * arg)
{
- volatile unsigned char *base_addr = (u_char *)BASE_ADDR;
- unsigned long value;
- int channel;
-
- if (get_user(value, arg))
- return -EFAULT;
-
- channel = info->line;
- info->cor4 &= ~CyREC_FIFO;
- info->cor4 |= value & CyREC_FIFO;
- base_addr[CyCOR4] = info->cor4;
- return 0;
+ volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
+ unsigned long value;
+ int channel;
+
+ if (get_user(value, arg))
+ return -EFAULT;
+
+ channel = info->line;
+ info->cor4 &= ~CyREC_FIFO;
+ info->cor4 |= value & CyREC_FIFO;
+ base_addr[CyCOR4] = info->cor4;
+ return 0;
}
static int
-get_threshold(struct cyclades_port * info, unsigned long __user *value)
+get_threshold(struct cyclades_port *info, unsigned long __user * value)
{
- volatile unsigned char *base_addr = (u_char *)BASE_ADDR;
- int channel;
- unsigned long tmp;
-
- channel = info->line;
-
- tmp = base_addr[CyCOR4] & CyREC_FIFO;
- return put_user(tmp,value);
+ volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
+ int channel;
+ unsigned long tmp;
+
+ channel = info->line;
+
+ tmp = base_addr[CyCOR4] & CyREC_FIFO;
+ return put_user(tmp, value);
}
static int
-set_default_threshold(struct cyclades_port * info, unsigned long __user *arg)
+set_default_threshold(struct cyclades_port *info, unsigned long __user * arg)
{
- unsigned long value;
+ unsigned long value;
- if (get_user(value, arg))
- return -EFAULT;
+ if (get_user(value, arg))
+ return -EFAULT;
- info->default_threshold = value & 0x0f;
- return 0;
+ info->default_threshold = value & 0x0f;
+ return 0;
}
static int
-get_default_threshold(struct cyclades_port * info, unsigned long __user *value)
+get_default_threshold(struct cyclades_port *info, unsigned long __user * value)
{
- return put_user(info->default_threshold,value);
+ return put_user(info->default_threshold, value);
}
-static int
-set_timeout(struct cyclades_port * info, unsigned long __user *arg)
+static int set_timeout(struct cyclades_port *info, unsigned long __user * arg)
{
- volatile unsigned char *base_addr = (u_char *)BASE_ADDR;
- int channel;
- unsigned long value;
-
- if (get_user(value, arg))
- return -EFAULT;
-
- channel = info->line;
-
- base_addr[CyRTPRL] = value & 0xff;
- base_addr[CyRTPRH] = (value >> 8) & 0xff;
- return 0;
+ volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
+ int channel;
+ unsigned long value;
+
+ if (get_user(value, arg))
+ return -EFAULT;
+
+ channel = info->line;
+
+ base_addr[CyRTPRL] = value & 0xff;
+ base_addr[CyRTPRH] = (value >> 8) & 0xff;
+ return 0;
}
-static int
-get_timeout(struct cyclades_port * info, unsigned long __user *value)
+static int get_timeout(struct cyclades_port *info, unsigned long __user * value)
{
- volatile unsigned char *base_addr = (u_char *)BASE_ADDR;
- int channel;
- unsigned long tmp;
-
- channel = info->line;
-
- tmp = base_addr[CyRTPRL];
- return put_user(tmp,value);
+ volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
+ int channel;
+ unsigned long tmp;
+
+ channel = info->line;
+
+ tmp = base_addr[CyRTPRL];
+ return put_user(tmp, value);
}
-static int
-set_default_timeout(struct cyclades_port * info, unsigned long value)
+static int set_default_timeout(struct cyclades_port *info, unsigned long value)
{
- info->default_timeout = value & 0xff;
- return 0;
+ info->default_timeout = value & 0xff;
+ return 0;
}
static int
-get_default_timeout(struct cyclades_port * info, unsigned long __user *value)
+get_default_timeout(struct cyclades_port *info, unsigned long __user * value)
{
- return put_user(info->default_timeout,value);
+ return put_user(info->default_timeout, value);
}
static int
-cy_ioctl(struct tty_struct *tty, struct file * file,
- unsigned int cmd, unsigned long arg)
+cy_ioctl(struct tty_struct *tty, struct file *file,
+ unsigned int cmd, unsigned long arg)
{
- unsigned long val;
- struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;
- int ret_val = 0;
- void __user *argp = (void __user *)arg;
+ unsigned long val;
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ int ret_val = 0;
+ void __user *argp = (void __user *)arg;
#ifdef SERIAL_DEBUG_OTHER
- printk("cy_ioctl %s, cmd = %x arg = %lx\n", tty->name, cmd, arg); /* */
-#endif
-
- switch (cmd) {
- case CYGETMON:
- ret_val = get_mon_info(info, argp);
- break;
- case CYGETTHRESH:
- ret_val = get_threshold(info, argp);
- break;
- case CYSETTHRESH:
- ret_val = set_threshold(info, argp);
- break;
- case CYGETDEFTHRESH:
- ret_val = get_default_threshold(info, argp);
- break;
- case CYSETDEFTHRESH:
- ret_val = set_default_threshold(info, argp);
- break;
- case CYGETTIMEOUT:
- ret_val = get_timeout(info, argp);
- break;
- case CYSETTIMEOUT:
- ret_val = set_timeout(info, argp);
- break;
- case CYGETDEFTIMEOUT:
- ret_val = get_default_timeout(info, argp);
- break;
- case CYSETDEFTIMEOUT:
- ret_val = set_default_timeout(info, (unsigned long)arg);
- break;
- case TCSBRK: /* SVID version: non-zero arg --> no break */
- ret_val = tty_check_change(tty);
- if (ret_val)
- break;
- tty_wait_until_sent(tty,0);
- if (!arg)
- send_break(info, HZ/4); /* 1/4 second */
- break;
- case TCSBRKP: /* support for POSIX tcsendbreak() */
- ret_val = tty_check_change(tty);
- if (ret_val)
+ printk("cy_ioctl %s, cmd = %x arg = %lx\n", tty->name, cmd, arg); /* */
+#endif
+
+ switch (cmd) {
+ case CYGETMON:
+ ret_val = get_mon_info(info, argp);
+ break;
+ case CYGETTHRESH:
+ ret_val = get_threshold(info, argp);
+ break;
+ case CYSETTHRESH:
+ ret_val = set_threshold(info, argp);
+ break;
+ case CYGETDEFTHRESH:
+ ret_val = get_default_threshold(info, argp);
+ break;
+ case CYSETDEFTHRESH:
+ ret_val = set_default_threshold(info, argp);
+ break;
+ case CYGETTIMEOUT:
+ ret_val = get_timeout(info, argp);
+ break;
+ case CYSETTIMEOUT:
+ ret_val = set_timeout(info, argp);
+ break;
+ case CYGETDEFTIMEOUT:
+ ret_val = get_default_timeout(info, argp);
+ break;
+ case CYSETDEFTIMEOUT:
+ ret_val = set_default_timeout(info, (unsigned long)arg);
+ break;
+ case TCSBRK: /* SVID version: non-zero arg --> no break */
+ ret_val = tty_check_change(tty);
+ if (ret_val)
+ break;
+ tty_wait_until_sent(tty, 0);
+ if (!arg)
+ send_break(info, HZ / 4); /* 1/4 second */
+ break;
+ case TCSBRKP: /* support for POSIX tcsendbreak() */
+ ret_val = tty_check_change(tty);
+ if (ret_val)
+ break;
+ tty_wait_until_sent(tty, 0);
+ send_break(info, arg ? arg * (HZ / 10) : HZ / 4);
break;
- tty_wait_until_sent(tty,0);
- send_break(info, arg ? arg*(HZ/10) : HZ/4);
- break;
/* The following commands are incompletely implemented!!! */
- case TIOCGSOFTCAR:
- ret_val = put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long __user *) argp);
- break;
- case TIOCSSOFTCAR:
- ret_val = get_user(val, (unsigned long __user *) argp);
- if (ret_val)
- break;
- tty->termios->c_cflag =
- ((tty->termios->c_cflag & ~CLOCAL) | (val ? CLOCAL : 0));
- break;
- case TIOCGSERIAL:
- ret_val = get_serial_info(info, argp);
- break;
- case TIOCSSERIAL:
- ret_val = set_serial_info(info, argp);
- break;
- default:
- ret_val = -ENOIOCTLCMD;
- }
+ case TIOCGSOFTCAR:
+ ret_val =
+ put_user(C_CLOCAL(tty) ? 1 : 0,
+ (unsigned long __user *)argp);
+ break;
+ case TIOCSSOFTCAR:
+ ret_val = get_user(val, (unsigned long __user *)argp);
+ if (ret_val)
+ break;
+ tty->termios->c_cflag =
+ ((tty->termios->c_cflag & ~CLOCAL) | (val ? CLOCAL : 0));
+ break;
+ case TIOCGSERIAL:
+ ret_val = get_serial_info(info, argp);
+ break;
+ case TIOCSSERIAL:
+ ret_val = set_serial_info(info, argp);
+ break;
+ default:
+ ret_val = -ENOIOCTLCMD;
+ }
#ifdef SERIAL_DEBUG_OTHER
- printk("cy_ioctl done\n");
+ printk("cy_ioctl done\n");
#endif
- return ret_val;
-} /* cy_ioctl */
-
+ return ret_val;
+} /* cy_ioctl */
-
-
-static void
-cy_set_termios(struct tty_struct *tty, struct ktermios * old_termios)
+static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
#ifdef SERIAL_DEBUG_OTHER
- printk("cy_set_termios %s\n", tty->name);
+ printk("cy_set_termios %s\n", tty->name);
#endif
- if (tty->termios->c_cflag == old_termios->c_cflag)
- return;
- config_setup(info);
+ if (tty->termios->c_cflag == old_termios->c_cflag)
+ return;
+ config_setup(info);
- if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios->c_cflag & CRTSCTS)) {
- tty->stopped = 0;
- cy_start(tty);
- }
+ if ((old_termios->c_cflag & CRTSCTS) &&
+ !(tty->termios->c_cflag & CRTSCTS)) {
+ tty->stopped = 0;
+ cy_start(tty);
+ }
#ifdef tytso_patch_94Nov25_1726
- if (!(old_termios->c_cflag & CLOCAL) &&
- (tty->termios->c_cflag & CLOCAL))
- wake_up_interruptible(&info->open_wait);
+ if (!(old_termios->c_cflag & CLOCAL) &&
+ (tty->termios->c_cflag & CLOCAL))
+ wake_up_interruptible(&info->open_wait);
#endif
+} /* cy_set_termios */
- return;
-} /* cy_set_termios */
-
-
-static void
-cy_close(struct tty_struct * tty, struct file * filp)
+static void cy_close(struct tty_struct *tty, struct file *filp)
{
- struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
/* CP('C'); */
#ifdef SERIAL_DEBUG_OTHER
- printk("cy_close %s\n", tty->name);
+ printk("cy_close %s\n", tty->name);
#endif
- if (!info
- || serial_paranoia_check(info, tty->name, "cy_close")){
- return;
- }
+ if (!info || serial_paranoia_check(info, tty->name, "cy_close")) {
+ return;
+ }
#ifdef SERIAL_DEBUG_OPEN
- printk("cy_close %s, count = %d\n", tty->name, info->count);
-#endif
-
- if ((tty->count == 1) && (info->count != 1)) {
- /*
- * Uh, oh. tty->count is 1, which means that the tty
- * structure will be freed. Info->count should always
- * be one in these conditions. If it's greater than
- * one, we've got real problems, since it means the
- * serial port won't be shutdown.
- */
- printk("cy_close: bad serial port count; tty->count is 1, "
- "info->count is %d\n", info->count);
- info->count = 1;
- }
+ printk("cy_close %s, count = %d\n", tty->name, info->count);
+#endif
+
+ if ((tty->count == 1) && (info->count != 1)) {
+ /*
+ * Uh, oh. tty->count is 1, which means that the tty
+ * structure will be freed. Info->count should always
+ * be one in these conditions. If it's greater than
+ * one, we've got real problems, since it means the
+ * serial port won't be shutdown.
+ */
+ printk("cy_close: bad serial port count; tty->count is 1, "
+ "info->count is %d\n", info->count);
+ info->count = 1;
+ }
#ifdef SERIAL_DEBUG_COUNT
- printk("cyc: %d: decrementing count to %d\n", __LINE__, info->count - 1);
+ printk("cyc: %d: decrementing count to %d\n", __LINE__,
+ info->count - 1);
#endif
- if (--info->count < 0) {
- printk("cy_close: bad serial port count for ttys%d: %d\n",
- info->line, info->count);
+ if (--info->count < 0) {
+ printk("cy_close: bad serial port count for ttys%d: %d\n",
+ info->line, info->count);
#ifdef SERIAL_DEBUG_COUNT
- printk("cyc: %d: setting count to 0\n", __LINE__);
+ printk("cyc: %d: setting count to 0\n", __LINE__);
#endif
- info->count = 0;
- }
- if (info->count)
- return;
- info->flags |= ASYNC_CLOSING;
- if (info->flags & ASYNC_INITIALIZED)
- tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */
- shutdown(info);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
- tty_ldisc_flush(tty);
- info->event = 0;
- info->tty = NULL;
- if (info->blocked_open) {
- if (info->close_delay) {
- msleep_interruptible(jiffies_to_msecs(info->close_delay));
+ info->count = 0;
}
- wake_up_interruptible(&info->open_wait);
- }
- info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
- wake_up_interruptible(&info->close_wait);
+ if (info->count)
+ return;
+ info->flags |= ASYNC_CLOSING;
+ if (info->flags & ASYNC_INITIALIZED)
+ tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */
+ shutdown(info);
+ if (tty->driver->flush_buffer)
+ tty->driver->flush_buffer(tty);
+ tty_ldisc_flush(tty);
+ info->event = 0;
+ info->tty = NULL;
+ if (info->blocked_open) {
+ if (info->close_delay) {
+ msleep_interruptible(jiffies_to_msecs
+ (info->close_delay));
+ }
+ wake_up_interruptible(&info->open_wait);
+ }
+ info->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
+ wake_up_interruptible(&info->close_wait);
#ifdef SERIAL_DEBUG_OTHER
- printk("cy_close done\n");
+ printk("cy_close done\n");
#endif
-
- return;
-} /* cy_close */
+} /* cy_close */
/*
* cy_hangup() --- called by tty_hangup() when a hangup is signaled.
*/
-void
-cy_hangup(struct tty_struct *tty)
+void cy_hangup(struct tty_struct *tty)
{
- struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;
-
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+
#ifdef SERIAL_DEBUG_OTHER
- printk("cy_hangup %s\n", tty->name); /* */
+ printk("cy_hangup %s\n", tty->name); /* */
#endif
- if (serial_paranoia_check(info, tty->name, "cy_hangup"))
- return;
-
- shutdown(info);
+ if (serial_paranoia_check(info, tty->name, "cy_hangup"))
+ return;
+
+ shutdown(info);
#if 0
- info->event = 0;
- info->count = 0;
+ info->event = 0;
+ info->count = 0;
#ifdef SERIAL_DEBUG_COUNT
- printk("cyc: %d: setting count to 0\n", __LINE__);
+ printk("cyc: %d: setting count to 0\n", __LINE__);
#endif
- info->tty = 0;
+ info->tty = 0;
#endif
- info->flags &= ~ASYNC_NORMAL_ACTIVE;
- wake_up_interruptible(&info->open_wait);
-} /* cy_hangup */
-
-
+ info->flags &= ~ASYNC_NORMAL_ACTIVE;
+ wake_up_interruptible(&info->open_wait);
+} /* cy_hangup */
/*
* ------------------------------------------------------------
@@ -1827,177 +1796,180 @@ cy_hangup(struct tty_struct *tty)
*/
static int
-block_til_ready(struct tty_struct *tty, struct file * filp,
- struct cyclades_port *info)
+block_til_ready(struct tty_struct *tty, struct file *filp,
+ struct cyclades_port *info)
{
- DECLARE_WAITQUEUE(wait, current);
- unsigned long flags;
- int channel;
- int retval;
- volatile u_char *base_addr = (u_char *)BASE_ADDR;
-
- /*
- * If the device is in the middle of being closed, then block
- * until it's done, and then try again.
- */
- if (info->flags & ASYNC_CLOSING) {
- interruptible_sleep_on(&info->close_wait);
- if (info->flags & ASYNC_HUP_NOTIFY){
- return -EAGAIN;
- }else{
- return -ERESTARTSYS;
- }
- }
-
- /*
- * If non-blocking mode is set, then make the check up front
- * and then exit.
- */
- if (filp->f_flags & O_NONBLOCK) {
- info->flags |= ASYNC_NORMAL_ACTIVE;
- return 0;
- }
-
- /*
- * Block waiting for the carrier detect and the line to become
- * free (i.e., not in use by the callout). While we are in
- * this loop, info->count is dropped by one, so that
- * cy_close() knows when to free things. We restore it upon
- * exit, either normal or abnormal.
- */
- retval = 0;
- add_wait_queue(&info->open_wait, &wait);
+ DECLARE_WAITQUEUE(wait, current);
+ unsigned long flags;
+ int channel;
+ int retval;
+ volatile u_char *base_addr = (u_char *) BASE_ADDR;
+
+ /*
+ * If the device is in the middle of being closed, then block
+ * until it's done, and then try again.
+ */
+ if (info->flags & ASYNC_CLOSING) {
+ interruptible_sleep_on(&info->close_wait);
+ if (info->flags & ASYNC_HUP_NOTIFY) {
+ return -EAGAIN;
+ } else {
+ return -ERESTARTSYS;
+ }
+ }
+
+ /*
+ * If non-blocking mode is set, then make the check up front
+ * and then exit.
+ */
+ if (filp->f_flags & O_NONBLOCK) {
+ info->flags |= ASYNC_NORMAL_ACTIVE;
+ return 0;
+ }
+
+ /*
+ * Block waiting for the carrier detect and the line to become
+ * free (i.e., not in use by the callout). While we are in
+ * this loop, info->count is dropped by one, so that
+ * cy_close() knows when to free things. We restore it upon
+ * exit, either normal or abnormal.
+ */
+ retval = 0;
+ add_wait_queue(&info->open_wait, &wait);
#ifdef SERIAL_DEBUG_OPEN
- printk("block_til_ready before block: %s, count = %d\n",
- tty->name, info->count);/**/
+ printk("block_til_ready before block: %s, count = %d\n",
+ tty->name, info->count);
+ /**/
#endif
- info->count--;
+ info->count--;
#ifdef SERIAL_DEBUG_COUNT
- printk("cyc: %d: decrementing count to %d\n", __LINE__, info->count);
+ printk("cyc: %d: decrementing count to %d\n", __LINE__, info->count);
#endif
- info->blocked_open++;
+ info->blocked_open++;
- channel = info->line;
+ channel = info->line;
- while (1) {
- local_irq_save(flags);
- base_addr[CyCAR] = (u_char)channel;
- base_addr[CyMSVR1] = CyRTS;
+ while (1) {
+ local_irq_save(flags);
+ base_addr[CyCAR] = (u_char) channel;
+ base_addr[CyMSVR1] = CyRTS;
/* CP('S');CP('4'); */
- base_addr[CyMSVR2] = CyDTR;
+ base_addr[CyMSVR2] = CyDTR;
#ifdef SERIAL_DEBUG_DTR
- printk("cyc: %d: raising DTR\n", __LINE__);
- printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1], base_addr[CyMSVR2]);
-#endif
- local_irq_restore(flags);
- set_current_state(TASK_INTERRUPTIBLE);
- if (tty_hung_up_p(filp)
- || !(info->flags & ASYNC_INITIALIZED) ){
- if (info->flags & ASYNC_HUP_NOTIFY) {
- retval = -EAGAIN;
- }else{
- retval = -ERESTARTSYS;
- }
- break;
- }
- local_irq_save(flags);
- base_addr[CyCAR] = (u_char)channel;
+ printk("cyc: %d: raising DTR\n", __LINE__);
+ printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1],
+ base_addr[CyMSVR2]);
+#endif
+ local_irq_restore(flags);
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (tty_hung_up_p(filp)
+ || !(info->flags & ASYNC_INITIALIZED)) {
+ if (info->flags & ASYNC_HUP_NOTIFY) {
+ retval = -EAGAIN;
+ } else {
+ retval = -ERESTARTSYS;
+ }
+ break;
+ }
+ local_irq_save(flags);
+ base_addr[CyCAR] = (u_char) channel;
/* CP('L');CP1(1 && C_CLOCAL(tty)); CP1(1 && (base_addr[CyMSVR1] & CyDCD) ); */
- if (!(info->flags & ASYNC_CLOSING)
- && (C_CLOCAL(tty)
- || (base_addr[CyMSVR1] & CyDCD))) {
- local_irq_restore(flags);
- break;
- }
- local_irq_restore(flags);
- if (signal_pending(current)) {
- retval = -ERESTARTSYS;
- break;
- }
+ if (!(info->flags & ASYNC_CLOSING)
+ && (C_CLOCAL(tty)
+ || (base_addr[CyMSVR1] & CyDCD))) {
+ local_irq_restore(flags);
+ break;
+ }
+ local_irq_restore(flags);
+ if (signal_pending(current)) {
+ retval = -ERESTARTSYS;
+ break;
+ }
#ifdef SERIAL_DEBUG_OPEN
- printk("block_til_ready blocking: %s, count = %d\n",
- tty->name, info->count);/**/
-#endif
- schedule();
- }
- current->state = TASK_RUNNING;
- remove_wait_queue(&info->open_wait, &wait);
- if (!tty_hung_up_p(filp)){
- info->count++;
+ printk("block_til_ready blocking: %s, count = %d\n",
+ tty->name, info->count);
+ /**/
+#endif
+ schedule();
+ }
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&info->open_wait, &wait);
+ if (!tty_hung_up_p(filp)) {
+ info->count++;
#ifdef SERIAL_DEBUG_COUNT
- printk("cyc: %d: incrementing count to %d\n", __LINE__, info->count);
+ printk("cyc: %d: incrementing count to %d\n", __LINE__,
+ info->count);
#endif
- }
- info->blocked_open--;
+ }
+ info->blocked_open--;
#ifdef SERIAL_DEBUG_OPEN
- printk("block_til_ready after blocking: %s, count = %d\n",
- tty->name, info->count);/**/
+ printk("block_til_ready after blocking: %s, count = %d\n",
+ tty->name, info->count);
+ /**/
#endif
- if (retval)
- return retval;
- info->flags |= ASYNC_NORMAL_ACTIVE;
- return 0;
-} /* block_til_ready */
+ if (retval)
+ return retval;
+ info->flags |= ASYNC_NORMAL_ACTIVE;
+ return 0;
+} /* block_til_ready */
/*
* This routine is called whenever a serial port is opened. It
* performs the serial-specific initialization for the tty structure.
*/
-int
-cy_open(struct tty_struct *tty, struct file * filp)
+int cy_open(struct tty_struct *tty, struct file *filp)
{
- struct cyclades_port *info;
- int retval, line;
+ struct cyclades_port *info;
+ int retval, line;
/* CP('O'); */
- line = tty->index;
- if ((line < 0) || (NR_PORTS <= line)){
- return -ENODEV;
- }
- info = &cy_port[line];
- if (info->line < 0){
- return -ENODEV;
- }
+ line = tty->index;
+ if ((line < 0) || (NR_PORTS <= line)) {
+ return -ENODEV;
+ }
+ info = &cy_port[line];
+ if (info->line < 0) {
+ return -ENODEV;
+ }
#ifdef SERIAL_DEBUG_OTHER
- printk("cy_open %s\n", tty->name); /* */
+ printk("cy_open %s\n", tty->name); /* */
#endif
- if (serial_paranoia_check(info, tty->name, "cy_open")){
- return -ENODEV;
- }
+ if (serial_paranoia_check(info, tty->name, "cy_open")) {
+ return -ENODEV;
+ }
#ifdef SERIAL_DEBUG_OPEN
- printk("cy_open %s, count = %d\n", tty->name, info->count);/**/
+ printk("cy_open %s, count = %d\n", tty->name, info->count);
+ /**/
#endif
- info->count++;
+ info->count++;
#ifdef SERIAL_DEBUG_COUNT
- printk("cyc: %d: incrementing count to %d\n", __LINE__, info->count);
+ printk("cyc: %d: incrementing count to %d\n", __LINE__, info->count);
#endif
- tty->driver_data = info;
- info->tty = tty;
+ tty->driver_data = info;
+ info->tty = tty;
- /*
- * Start up serial port
- */
- retval = startup(info);
- if (retval){
- return retval;
- }
+ /*
+ * Start up serial port
+ */
+ retval = startup(info);
+ if (retval) {
+ return retval;
+ }
- retval = block_til_ready(tty, filp, info);
- if (retval) {
+ retval = block_til_ready(tty, filp, info);
+ if (retval) {
#ifdef SERIAL_DEBUG_OPEN
- printk("cy_open returning after block_til_ready with %d\n",
- retval);
+ printk("cy_open returning after block_til_ready with %d\n",
+ retval);
#endif
- return retval;
- }
-
+ return retval;
+ }
#ifdef SERIAL_DEBUG_OPEN
- printk("cy_open done\n");/**/
+ printk("cy_open done\n");
+ /**/
#endif
- return 0;
-} /* cy_open */
-
-
+ return 0;
+} /* cy_open */
/*
* ---------------------------------------------------------------------
@@ -2012,11 +1984,10 @@ cy_open(struct tty_struct *tty, struct file * filp)
* number, and identifies which options were configured into this
* driver.
*/
-static void
-show_version(void)
+static void show_version(void)
{
- printk("MVME166/167 cd2401 driver\n");
-} /* show_version */
+ printk("MVME166/167 cd2401 driver\n");
+} /* show_version */
/* initialize chips on card -- return number of valid
chips (which is number of ports/4) */
@@ -2030,10 +2001,9 @@ show_version(void)
* ... I wonder what I should do if this fails ...
*/
-void
-mvme167_serial_console_setup(int cflag)
+void mvme167_serial_console_setup(int cflag)
{
- volatile unsigned char* base_addr = (u_char *)BASE_ADDR;
+ volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
int ch;
u_char spd;
u_char rcor, rbpr, badspeed = 0;
@@ -2062,21 +2032,21 @@ mvme167_serial_console_setup(int cflag)
/* OK, we have chosen a speed, now reset and reinitialise */
- my_udelay(20000L); /* Allow time for any active o/p to complete */
- if(base_addr[CyCCR] != 0x00){
- local_irq_restore(flags);
- /* printk(" chip is never idle (CCR != 0)\n"); */
- return;
- }
+ my_udelay(20000L); /* Allow time for any active o/p to complete */
+ if (base_addr[CyCCR] != 0x00) {
+ local_irq_restore(flags);
+ /* printk(" chip is never idle (CCR != 0)\n"); */
+ return;
+ }
- base_addr[CyCCR] = CyCHIP_RESET; /* Reset the chip */
- my_udelay(1000L);
+ base_addr[CyCCR] = CyCHIP_RESET; /* Reset the chip */
+ my_udelay(1000L);
- if(base_addr[CyGFRCR] == 0x00){
- local_irq_restore(flags);
- /* printk(" chip is not responding (GFRCR stayed 0)\n"); */
- return;
- }
+ if (base_addr[CyGFRCR] == 0x00) {
+ local_irq_restore(flags);
+ /* printk(" chip is not responding (GFRCR stayed 0)\n"); */
+ return;
+ }
/*
* System clock is 20Mhz, divided by 2048, so divide by 10 for a 1.0ms
@@ -2085,9 +2055,9 @@ mvme167_serial_console_setup(int cflag)
base_addr[CyTPR] = 10;
- base_addr[CyPILR1] = 0x01; /* Interrupt level for modem change */
- base_addr[CyPILR2] = 0x02; /* Interrupt level for tx ints */
- base_addr[CyPILR3] = 0x03; /* Interrupt level for rx ints */
+ base_addr[CyPILR1] = 0x01; /* Interrupt level for modem change */
+ base_addr[CyPILR2] = 0x02; /* Interrupt level for tx ints */
+ base_addr[CyPILR3] = 0x03; /* Interrupt level for rx ints */
/*
* Attempt to set up all channels to something reasonable, and
@@ -2095,11 +2065,11 @@ mvme167_serial_console_setup(int cflag)
* the ammount of fiddling we have to do in normal running.
*/
- for (ch = 3; ch >= 0 ; ch--) {
- base_addr[CyCAR] = (u_char)ch;
+ for (ch = 3; ch >= 0; ch--) {
+ base_addr[CyCAR] = (u_char) ch;
base_addr[CyIER] = 0;
base_addr[CyCMR] = CyASYNC;
- base_addr[CyLICR] = (u_char)ch << 2;
+ base_addr[CyLICR] = (u_char) ch << 2;
base_addr[CyLIVR] = 0x5c;
base_addr[CyTCOR] = baud_co[spd];
base_addr[CyTBPR] = baud_bpr[spd];
@@ -2118,29 +2088,30 @@ mvme167_serial_console_setup(int cflag)
base_addr[CyCOR7] = 0;
base_addr[CyRTPRL] = 2;
base_addr[CyRTPRH] = 0;
- base_addr[CyMSVR1] = 0;
- base_addr[CyMSVR2] = 0;
- write_cy_cmd(base_addr,CyINIT_CHAN|CyDIS_RCVR|CyDIS_XMTR);
+ base_addr[CyMSVR1] = 0;
+ base_addr[CyMSVR2] = 0;
+ write_cy_cmd(base_addr, CyINIT_CHAN | CyDIS_RCVR | CyDIS_XMTR);
}
/*
* Now do specials for channel zero....
*/
- base_addr[CyMSVR1] = CyRTS;
- base_addr[CyMSVR2] = CyDTR;
+ base_addr[CyMSVR1] = CyRTS;
+ base_addr[CyMSVR2] = CyDTR;
base_addr[CyIER] = CyRxData;
- write_cy_cmd(base_addr,CyENB_RCVR|CyENB_XMTR);
+ write_cy_cmd(base_addr, CyENB_RCVR | CyENB_XMTR);
local_irq_restore(flags);
my_udelay(20000L); /* Let it all settle down */
- printk("CD2401 initialised, chip is rev 0x%02x\n", base_addr[CyGFRCR]);
+ printk("CD2401 initialised, chip is rev 0x%02x\n", base_addr[CyGFRCR]);
if (badspeed)
- printk(" WARNING: Failed to identify line speed, rcor=%02x,rbpr=%02x\n",
- rcor >> 5, rbpr);
-} /* serial_console_init */
+ printk
+ (" WARNING: Failed to identify line speed, rcor=%02x,rbpr=%02x\n",
+ rcor >> 5, rbpr);
+} /* serial_console_init */
static const struct tty_operations cy_ops = {
.open = cy_open,
@@ -2161,6 +2132,7 @@ static const struct tty_operations cy_ops = {
.tiocmget = cy_tiocmget,
.tiocmset = cy_tiocmset,
};
+
/* The serial driver boot-time initialization code!
Hardware I/O ports are mapped to character special devices on a
first found, first allocated manner. That is, this code searches
@@ -2177,214 +2149,214 @@ static const struct tty_operations cy_ops = {
If there are more cards with more ports than have been statically
allocated above, a warning is printed and the extra ports are ignored.
*/
-static int __init
-serial167_init(void)
+static int __init serial167_init(void)
{
- struct cyclades_port *info;
- int ret = 0;
- int good_ports = 0;
- int port_num = 0;
- int index;
- int DefSpeed;
+ struct cyclades_port *info;
+ int ret = 0;
+ int good_ports = 0;
+ int port_num = 0;
+ int index;
+ int DefSpeed;
#ifdef notyet
- struct sigaction sa;
+ struct sigaction sa;
#endif
- if (!(mvme16x_config &MVME16x_CONFIG_GOT_CD2401))
- return 0;
+ if (!(mvme16x_config & MVME16x_CONFIG_GOT_CD2401))
+ return 0;
- cy_serial_driver = alloc_tty_driver(NR_PORTS);
- if (!cy_serial_driver)
- return -ENOMEM;
+ cy_serial_driver = alloc_tty_driver(NR_PORTS);
+ if (!cy_serial_driver)
+ return -ENOMEM;
#if 0
-scrn[1] = '\0';
+ scrn[1] = '\0';
#endif
- show_version();
+ show_version();
- /* Has "console=0,9600n8" been used in bootinfo to change speed? */
- if (serial_console_cflag)
- DefSpeed = serial_console_cflag & 0017;
- else {
- DefSpeed = initial_console_speed;
- serial_console_info = &cy_port[0];
- serial_console_cflag = DefSpeed | CS8;
+ /* Has "console=0,9600n8" been used in bootinfo to change speed? */
+ if (serial_console_cflag)
+ DefSpeed = serial_console_cflag & 0017;
+ else {
+ DefSpeed = initial_console_speed;
+ serial_console_info = &cy_port[0];
+ serial_console_cflag = DefSpeed | CS8;
#if 0
- serial_console = 64; /*callout_driver.minor_start*/
-#endif
- }
-
- /* Initialize the tty_driver structure */
-
- cy_serial_driver->owner = THIS_MODULE;
- cy_serial_driver->name = "ttyS";
- cy_serial_driver->major = TTY_MAJOR;
- cy_serial_driver->minor_start = 64;
- cy_serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
- cy_serial_driver->subtype = SERIAL_TYPE_NORMAL;
- cy_serial_driver->init_termios = tty_std_termios;
- cy_serial_driver->init_termios.c_cflag =
- B9600 | CS8 | CREAD | HUPCL | CLOCAL;
- cy_serial_driver->flags = TTY_DRIVER_REAL_RAW;
- tty_set_operations(cy_serial_driver, &cy_ops);
+ serial_console = 64; /*callout_driver.minor_start */
+#endif
+ }
- ret = tty_register_driver(cy_serial_driver);
- if (ret) {
- printk(KERN_ERR "Couldn't register MVME166/7 serial driver\n");
- put_tty_driver(cy_serial_driver);
- return ret;
- }
+ /* Initialize the tty_driver structure */
- port_num = 0;
- info = cy_port;
- for (index = 0; index < 1; index++) {
+ cy_serial_driver->owner = THIS_MODULE;
+ cy_serial_driver->name = "ttyS";
+ cy_serial_driver->major = TTY_MAJOR;
+ cy_serial_driver->minor_start = 64;
+ cy_serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
+ cy_serial_driver->subtype = SERIAL_TYPE_NORMAL;
+ cy_serial_driver->init_termios = tty_std_termios;
+ cy_serial_driver->init_termios.c_cflag =
+ B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ cy_serial_driver->flags = TTY_DRIVER_REAL_RAW;
+ tty_set_operations(cy_serial_driver, &cy_ops);
+
+ ret = tty_register_driver(cy_serial_driver);
+ if (ret) {
+ printk(KERN_ERR "Couldn't register MVME166/7 serial driver\n");
+ put_tty_driver(cy_serial_driver);
+ return ret;
+ }
- good_ports = 4;
+ port_num = 0;
+ info = cy_port;
+ for (index = 0; index < 1; index++) {
- if(port_num < NR_PORTS){
- while( good_ports-- && port_num < NR_PORTS){
+ good_ports = 4;
+
+ if (port_num < NR_PORTS) {
+ while (good_ports-- && port_num < NR_PORTS) {
/*** initialize port ***/
- info->magic = CYCLADES_MAGIC;
- info->type = PORT_CIRRUS;
- info->card = index;
- info->line = port_num;
- info->flags = STD_COM_FLAGS;
- info->tty = NULL;
- info->xmit_fifo_size = 12;
- info->cor1 = CyPARITY_NONE|Cy_8_BITS;
- info->cor2 = CyETC;
- info->cor3 = Cy_1_STOP;
- info->cor4 = 0x08; /* _very_ small receive threshold */
- info->cor5 = 0;
- info->cor6 = 0;
- info->cor7 = 0;
- info->tbpr = baud_bpr[DefSpeed]; /* Tx BPR */
- info->tco = baud_co[DefSpeed]; /* Tx CO */
- info->rbpr = baud_bpr[DefSpeed]; /* Rx BPR */
- info->rco = baud_co[DefSpeed] >> 5; /* Rx CO */
- info->close_delay = 0;
- info->x_char = 0;
- info->event = 0;
- info->count = 0;
+ info->magic = CYCLADES_MAGIC;
+ info->type = PORT_CIRRUS;
+ info->card = index;
+ info->line = port_num;
+ info->flags = STD_COM_FLAGS;
+ info->tty = NULL;
+ info->xmit_fifo_size = 12;
+ info->cor1 = CyPARITY_NONE | Cy_8_BITS;
+ info->cor2 = CyETC;
+ info->cor3 = Cy_1_STOP;
+ info->cor4 = 0x08; /* _very_ small receive threshold */
+ info->cor5 = 0;
+ info->cor6 = 0;
+ info->cor7 = 0;
+ info->tbpr = baud_bpr[DefSpeed]; /* Tx BPR */
+ info->tco = baud_co[DefSpeed]; /* Tx CO */
+ info->rbpr = baud_bpr[DefSpeed]; /* Rx BPR */
+ info->rco = baud_co[DefSpeed] >> 5; /* Rx CO */
+ info->close_delay = 0;
+ info->x_char = 0;
+ info->event = 0;
+ info->count = 0;
#ifdef SERIAL_DEBUG_COUNT
- printk("cyc: %d: setting count to 0\n", __LINE__);
-#endif
- info->blocked_open = 0;
- info->default_threshold = 0;
- info->default_timeout = 0;
- INIT_WORK(&info->tqueue, do_softint);
- init_waitqueue_head(&info->open_wait);
- init_waitqueue_head(&info->close_wait);
- /* info->session */
- /* info->pgrp */
+ printk("cyc: %d: setting count to 0\n",
+ __LINE__);
+#endif
+ info->blocked_open = 0;
+ info->default_threshold = 0;
+ info->default_timeout = 0;
+ INIT_WORK(&info->tqueue, do_softint);
+ init_waitqueue_head(&info->open_wait);
+ init_waitqueue_head(&info->close_wait);
+ /* info->session */
+ /* info->pgrp */
/*** !!!!!!!! this may expose new bugs !!!!!!!!! *********/
- info->read_status_mask = CyTIMEOUT| CySPECHAR| CyBREAK
- | CyPARITY| CyFRAME| CyOVERRUN;
- /* info->timeout */
-
- printk("ttyS%d ", info->line);
- port_num++;info++;
- if(!(port_num & 7)){
- printk("\n ");
+ info->read_status_mask =
+ CyTIMEOUT | CySPECHAR | CyBREAK | CyPARITY |
+ CyFRAME | CyOVERRUN;
+ /* info->timeout */
+
+ printk("ttyS%d ", info->line);
+ port_num++;
+ info++;
+ if (!(port_num & 7)) {
+ printk("\n ");
+ }
+ }
}
- }
- }
- printk("\n");
- }
- while( port_num < NR_PORTS){
- info->line = -1;
- port_num++;info++;
- }
+ printk("\n");
+ }
+ while (port_num < NR_PORTS) {
+ info->line = -1;
+ port_num++;
+ info++;
+ }
#ifdef CONFIG_REMOTE_DEBUG
- debug_setup();
-#endif
- ret = request_irq(MVME167_IRQ_SER_ERR, cd2401_rxerr_interrupt, 0,
- "cd2401_errors", cd2401_rxerr_interrupt);
- if (ret) {
- printk(KERN_ERR "Could't get cd2401_errors IRQ");
- goto cleanup_serial_driver;
- }
-
- ret = request_irq(MVME167_IRQ_SER_MODEM, cd2401_modem_interrupt, 0,
- "cd2401_modem", cd2401_modem_interrupt);
- if (ret) {
- printk(KERN_ERR "Could't get cd2401_modem IRQ");
- goto cleanup_irq_cd2401_errors;
- }
-
- ret = request_irq(MVME167_IRQ_SER_TX, cd2401_tx_interrupt, 0,
- "cd2401_txints", cd2401_tx_interrupt);
- if (ret) {
- printk(KERN_ERR "Could't get cd2401_txints IRQ");
- goto cleanup_irq_cd2401_modem;
- }
-
- ret = request_irq(MVME167_IRQ_SER_RX, cd2401_rx_interrupt, 0,
- "cd2401_rxints", cd2401_rx_interrupt);
- if (ret) {
- printk(KERN_ERR "Could't get cd2401_rxints IRQ");
- goto cleanup_irq_cd2401_txints;
- }
-
- /* Now we have registered the interrupt handlers, allow the interrupts */
-
- pcc2chip[PccSCCMICR] = 0x15; /* Serial ints are level 5 */
- pcc2chip[PccSCCTICR] = 0x15;
- pcc2chip[PccSCCRICR] = 0x15;
-
- pcc2chip[PccIMLR] = 3; /* Allow PCC2 ints above 3!? */
-
- return 0;
+ debug_setup();
+#endif
+ ret = request_irq(MVME167_IRQ_SER_ERR, cd2401_rxerr_interrupt, 0,
+ "cd2401_errors", cd2401_rxerr_interrupt);
+ if (ret) {
+ printk(KERN_ERR "Could't get cd2401_errors IRQ");
+ goto cleanup_serial_driver;
+ }
+
+ ret = request_irq(MVME167_IRQ_SER_MODEM, cd2401_modem_interrupt, 0,
+ "cd2401_modem", cd2401_modem_interrupt);
+ if (ret) {
+ printk(KERN_ERR "Could't get cd2401_modem IRQ");
+ goto cleanup_irq_cd2401_errors;
+ }
+
+ ret = request_irq(MVME167_IRQ_SER_TX, cd2401_tx_interrupt, 0,
+ "cd2401_txints", cd2401_tx_interrupt);
+ if (ret) {
+ printk(KERN_ERR "Could't get cd2401_txints IRQ");
+ goto cleanup_irq_cd2401_modem;
+ }
+
+ ret = request_irq(MVME167_IRQ_SER_RX, cd2401_rx_interrupt, 0,
+ "cd2401_rxints", cd2401_rx_interrupt);
+ if (ret) {
+ printk(KERN_ERR "Could't get cd2401_rxints IRQ");
+ goto cleanup_irq_cd2401_txints;
+ }
+
+ /* Now we have registered the interrupt handlers, allow the interrupts */
+
+ pcc2chip[PccSCCMICR] = 0x15; /* Serial ints are level 5 */
+ pcc2chip[PccSCCTICR] = 0x15;
+ pcc2chip[PccSCCRICR] = 0x15;
+
+ pcc2chip[PccIMLR] = 3; /* Allow PCC2 ints above 3!? */
+
+ return 0;
cleanup_irq_cd2401_txints:
- free_irq(MVME167_IRQ_SER_TX, cd2401_tx_interrupt);
+ free_irq(MVME167_IRQ_SER_TX, cd2401_tx_interrupt);
cleanup_irq_cd2401_modem:
- free_irq(MVME167_IRQ_SER_MODEM, cd2401_modem_interrupt);
+ free_irq(MVME167_IRQ_SER_MODEM, cd2401_modem_interrupt);
cleanup_irq_cd2401_errors:
- free_irq(MVME167_IRQ_SER_ERR, cd2401_rxerr_interrupt);
+ free_irq(MVME167_IRQ_SER_ERR, cd2401_rxerr_interrupt);
cleanup_serial_driver:
- if (tty_unregister_driver(cy_serial_driver))
- printk(KERN_ERR "Couldn't unregister MVME166/7 serial driver\n");
- put_tty_driver(cy_serial_driver);
- return ret;
-} /* serial167_init */
+ if (tty_unregister_driver(cy_serial_driver))
+ printk(KERN_ERR
+ "Couldn't unregister MVME166/7 serial driver\n");
+ put_tty_driver(cy_serial_driver);
+ return ret;
+} /* serial167_init */
module_init(serial167_init);
-
#ifdef CYCLOM_SHOW_STATUS
-static void
-show_status(int line_num)
+static void show_status(int line_num)
{
- volatile unsigned char *base_addr = (u_char *)BASE_ADDR;
- int channel;
- struct cyclades_port * info;
- unsigned long flags;
-
- info = &cy_port[line_num];
- channel = info->line;
- printk(" channel %d\n", channel);/**/
-
- printk(" cy_port\n");
- printk(" card line flags = %d %d %x\n",
- info->card, info->line, info->flags);
- printk(" *tty read_status_mask timeout xmit_fifo_size = %lx %x %x %x\n",
- (long)info->tty, info->read_status_mask,
- info->timeout, info->xmit_fifo_size);
- printk(" cor1,cor2,cor3,cor4,cor5,cor6,cor7 = %x %x %x %x %x %x %x\n",
- info->cor1, info->cor2, info->cor3, info->cor4, info->cor5,
- info->cor6, info->cor7);
- printk(" tbpr,tco,rbpr,rco = %d %d %d %d\n",
- info->tbpr, info->tco, info->rbpr, info->rco);
- printk(" close_delay event count = %d %d %d\n",
- info->close_delay, info->event, info->count);
- printk(" x_char blocked_open = %x %x\n",
- info->x_char, info->blocked_open);
- printk(" open_wait = %lx %lx %lx\n",
- (long)info->open_wait);
-
-
- local_irq_save(flags);
+ volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
+ int channel;
+ struct cyclades_port *info;
+ unsigned long flags;
+
+ info = &cy_port[line_num];
+ channel = info->line;
+ printk(" channel %d\n", channel);
+ /**/ printk(" cy_port\n");
+ printk(" card line flags = %d %d %x\n",
+ info->card, info->line, info->flags);
+ printk
+ (" *tty read_status_mask timeout xmit_fifo_size = %lx %x %x %x\n",
+ (long)info->tty, info->read_status_mask, info->timeout,
+ info->xmit_fifo_size);
+ printk(" cor1,cor2,cor3,cor4,cor5,cor6,cor7 = %x %x %x %x %x %x %x\n",
+ info->cor1, info->cor2, info->cor3, info->cor4, info->cor5,
+ info->cor6, info->cor7);
+ printk(" tbpr,tco,rbpr,rco = %d %d %d %d\n", info->tbpr, info->tco,
+ info->rbpr, info->rco);
+ printk(" close_delay event count = %d %d %d\n", info->close_delay,
+ info->event, info->count);
+ printk(" x_char blocked_open = %x %x\n", info->x_char,
+ info->blocked_open);
+ printk(" open_wait = %lx %lx %lx\n", (long)info->open_wait);
+
+ local_irq_save(flags);
/* Global Registers */
@@ -2398,7 +2370,7 @@ show_status(int line_num)
printk(" CyMIR %x\n", base_addr[CyMIR]);
printk(" CyTPR %x\n", base_addr[CyTPR]);
- base_addr[CyCAR] = (u_char)channel;
+ base_addr[CyCAR] = (u_char) channel;
/* Virtual Registers */
@@ -2442,11 +2414,10 @@ show_status(int line_num)
printk(" CyTBPR %x\n", base_addr[CyTBPR]);
printk(" CyTCOR %x\n", base_addr[CyTCOR]);
- local_irq_restore(flags);
-} /* show_status */
+ local_irq_restore(flags);
+} /* show_status */
#endif
-
#if 0
/* Dummy routine in mvme16x/config.c for now */
@@ -2459,61 +2430,67 @@ void console_setup(char *str, int *ints)
int cflag = 0;
/* Sanity check. */
- if (ints[0] > 3 || ints[1] > 3) return;
+ if (ints[0] > 3 || ints[1] > 3)
+ return;
/* Get baud, bits and parity */
baud = 2400;
bits = 8;
parity = 'n';
- if (ints[2]) baud = ints[2];
+ if (ints[2])
+ baud = ints[2];
if ((s = strchr(str, ','))) {
do {
s++;
- } while(*s >= '0' && *s <= '9');
- if (*s) parity = *s++;
- if (*s) bits = *s - '0';
+ } while (*s >= '0' && *s <= '9');
+ if (*s)
+ parity = *s++;
+ if (*s)
+ bits = *s - '0';
}
/* Now construct a cflag setting. */
- switch(baud) {
- case 1200:
- cflag |= B1200;
- break;
- case 9600:
- cflag |= B9600;
- break;
- case 19200:
- cflag |= B19200;
- break;
- case 38400:
- cflag |= B38400;
- break;
- case 2400:
- default:
- cflag |= B2400;
- break;
+ switch (baud) {
+ case 1200:
+ cflag |= B1200;
+ break;
+ case 9600:
+ cflag |= B9600;
+ break;
+ case 19200:
+ cflag |= B19200;
+ break;
+ case 38400:
+ cflag |= B38400;
+ break;
+ case 2400:
+ default:
+ cflag |= B2400;
+ break;
}
- switch(bits) {
- case 7:
- cflag |= CS7;
- break;
- default:
- case 8:
- cflag |= CS8;
- break;
+ switch (bits) {
+ case 7:
+ cflag |= CS7;
+ break;
+ default:
+ case 8:
+ cflag |= CS8;
+ break;
}
- switch(parity) {
- case 'o': case 'O':
- cflag |= PARODD;
- break;
- case 'e': case 'E':
- cflag |= PARENB;
- break;
+ switch (parity) {
+ case 'o':
+ case 'O':
+ cflag |= PARODD;
+ break;
+ case 'e':
+ case 'E':
+ cflag |= PARENB;
+ break;
}
serial_console_info = &cy_port[ints[1]];
serial_console_cflag = cflag;
- serial_console = ints[1] + 64; /*callout_driver.minor_start*/
+ serial_console = ints[1] + 64; /*callout_driver.minor_start */
}
#endif
@@ -2532,9 +2509,10 @@ void console_setup(char *str, int *ints)
* The console must be locked when we get here.
*/
-void serial167_console_write(struct console *co, const char *str, unsigned count)
+void serial167_console_write(struct console *co, const char *str,
+ unsigned count)
{
- volatile unsigned char *base_addr = (u_char *)BASE_ADDR;
+ volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
unsigned long flags;
volatile u_char sink;
u_char ier;
@@ -2547,7 +2525,7 @@ void serial167_console_write(struct console *co, const char *str, unsigned count
/* Ensure transmitter is enabled! */
port = 0;
- base_addr[CyCAR] = (u_char)port;
+ base_addr[CyCAR] = (u_char) port;
while (base_addr[CyCCR])
;
base_addr[CyCCR] = CyENB_XMTR;
@@ -2556,8 +2534,7 @@ void serial167_console_write(struct console *co, const char *str, unsigned count
base_addr[CyIER] = CyTxMpty;
while (1) {
- if (pcc2chip[PccSCCTICR] & 0x20)
- {
+ if (pcc2chip[PccSCCTICR] & 0x20) {
/* We have a Tx int. Acknowledge it */
sink = pcc2chip[PccTPIACKR];
if ((base_addr[CyLICR] >> 2) == port) {
@@ -2571,18 +2548,15 @@ void serial167_console_write(struct console *co, const char *str, unsigned count
str++;
i++;
do_lf = 0;
- }
- else if (*str == '\n') {
+ } else if (*str == '\n') {
base_addr[CyTDR] = '\r';
do_lf = 1;
- }
- else {
+ } else {
base_addr[CyTDR] = *str++;
i++;
}
base_addr[CyTEOIR] = 0;
- }
- else
+ } else
base_addr[CyTEOIR] = CyNOTRANS;
}
}
@@ -2592,45 +2566,44 @@ void serial167_console_write(struct console *co, const char *str, unsigned count
local_irq_restore(flags);
}
-static struct tty_driver *serial167_console_device(struct console *c, int *index)
+static struct tty_driver *serial167_console_device(struct console *c,
+ int *index)
{
*index = c->index;
return cy_serial_driver;
}
-
static int __init serial167_console_setup(struct console *co, char *options)
{
return 0;
}
-
static struct console sercons = {
- .name = "ttyS",
- .write = serial167_console_write,
- .device = serial167_console_device,
- .setup = serial167_console_setup,
- .flags = CON_PRINTBUFFER,
- .index = -1,
+ .name = "ttyS",
+ .write = serial167_console_write,
+ .device = serial167_console_device,
+ .setup = serial167_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
};
-
static int __init serial167_console_init(void)
{
if (vme_brdtype == VME_TYPE_MVME166 ||
- vme_brdtype == VME_TYPE_MVME167 ||
- vme_brdtype == VME_TYPE_MVME177) {
+ vme_brdtype == VME_TYPE_MVME167 ||
+ vme_brdtype == VME_TYPE_MVME177) {
mvme167_serial_console_setup(0);
register_console(&sercons);
}
return 0;
}
+
console_initcall(serial167_console_init);
#ifdef CONFIG_REMOTE_DEBUG
-void putDebugChar (int c)
+void putDebugChar(int c)
{
- volatile unsigned char *base_addr = (u_char *)BASE_ADDR;
+ volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
unsigned long flags;
volatile u_char sink;
u_char ier;
@@ -2641,7 +2614,7 @@ void putDebugChar (int c)
/* Ensure transmitter is enabled! */
port = DEBUG_PORT;
- base_addr[CyCAR] = (u_char)port;
+ base_addr[CyCAR] = (u_char) port;
while (base_addr[CyCCR])
;
base_addr[CyCCR] = CyENB_XMTR;
@@ -2650,16 +2623,14 @@ void putDebugChar (int c)
base_addr[CyIER] = CyTxMpty;
while (1) {
- if (pcc2chip[PccSCCTICR] & 0x20)
- {
+ if (pcc2chip[PccSCCTICR] & 0x20) {
/* We have a Tx int. Acknowledge it */
sink = pcc2chip[PccTPIACKR];
if ((base_addr[CyLICR] >> 2) == port) {
base_addr[CyTDR] = c;
base_addr[CyTEOIR] = 0;
break;
- }
- else
+ } else
base_addr[CyTEOIR] = CyNOTRANS;
}
}
@@ -2671,7 +2642,7 @@ void putDebugChar (int c)
int getDebugChar()
{
- volatile unsigned char *base_addr = (u_char *)BASE_ADDR;
+ volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
unsigned long flags;
volatile u_char sink;
u_char ier;
@@ -2693,7 +2664,7 @@ int getDebugChar()
/* Ensure receiver is enabled! */
port = DEBUG_PORT;
- base_addr[CyCAR] = (u_char)port;
+ base_addr[CyCAR] = (u_char) port;
#if 0
while (base_addr[CyCCR])
;
@@ -2703,31 +2674,30 @@ int getDebugChar()
base_addr[CyIER] = CyRxData;
while (1) {
- if (pcc2chip[PccSCCRICR] & 0x20)
- {
+ if (pcc2chip[PccSCCRICR] & 0x20) {
/* We have a Rx int. Acknowledge it */
sink = pcc2chip[PccRPIACKR];
if ((base_addr[CyLICR] >> 2) == port) {
int cnt = base_addr[CyRFOC];
- while (cnt-- > 0)
- {
+ while (cnt-- > 0) {
c = base_addr[CyRDR];
if (c == 0)
- printk ("!! debug char is null (cnt=%d) !!", cnt);
+ printk
+ ("!! debug char is null (cnt=%d) !!",
+ cnt);
else
- queueDebugChar (c);
+ queueDebugChar(c);
}
base_addr[CyREOIR] = 0;
i = debugiq.out;
if (i == debugiq.in)
- panic ("Debug input queue empty!");
+ panic("Debug input queue empty!");
c = debugiq.buf[i];
if (++i == DEBUG_LEN)
i = 0;
debugiq.out = i;
break;
- }
- else
+ } else
base_addr[CyREOIR] = CyNOTRANS;
}
}
@@ -2739,7 +2709,7 @@ int getDebugChar()
return (c);
}
-void queueDebugChar (int c)
+void queueDebugChar(int c)
{
int i;
@@ -2751,73 +2721,71 @@ void queueDebugChar (int c)
debugiq.in = i;
}
-static void
-debug_setup()
+static void debug_setup()
{
- unsigned long flags;
- volatile unsigned char *base_addr = (u_char *)BASE_ADDR;
- int i, cflag;
+ unsigned long flags;
+ volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
+ int i, cflag;
- cflag = B19200;
+ cflag = B19200;
- local_irq_save(flags);
+ local_irq_save(flags);
- for (i = 0; i < 4; i++)
- {
- base_addr[CyCAR] = i;
- base_addr[CyLICR] = i << 2;
- }
+ for (i = 0; i < 4; i++) {
+ base_addr[CyCAR] = i;
+ base_addr[CyLICR] = i << 2;
+ }
- debugiq.in = debugiq.out = 0;
+ debugiq.in = debugiq.out = 0;
- base_addr[CyCAR] = DEBUG_PORT;
+ base_addr[CyCAR] = DEBUG_PORT;
- /* baud rate */
- i = cflag & CBAUD;
+ /* baud rate */
+ i = cflag & CBAUD;
- base_addr[CyIER] = 0;
+ base_addr[CyIER] = 0;
- base_addr[CyCMR] = CyASYNC;
- base_addr[CyLICR] = DEBUG_PORT << 2;
- base_addr[CyLIVR] = 0x5c;
+ base_addr[CyCMR] = CyASYNC;
+ base_addr[CyLICR] = DEBUG_PORT << 2;
+ base_addr[CyLIVR] = 0x5c;
- /* tx and rx baud rate */
+ /* tx and rx baud rate */
- base_addr[CyTCOR] = baud_co[i];
- base_addr[CyTBPR] = baud_bpr[i];
- base_addr[CyRCOR] = baud_co[i] >> 5;
- base_addr[CyRBPR] = baud_bpr[i];
+ base_addr[CyTCOR] = baud_co[i];
+ base_addr[CyTBPR] = baud_bpr[i];
+ base_addr[CyRCOR] = baud_co[i] >> 5;
+ base_addr[CyRBPR] = baud_bpr[i];
- /* set line characteristics according configuration */
+ /* set line characteristics according configuration */
- base_addr[CySCHR1] = 0;
- base_addr[CySCHR2] = 0;
- base_addr[CySCRL] = 0;
- base_addr[CySCRH] = 0;
- base_addr[CyCOR1] = Cy_8_BITS | CyPARITY_NONE;
- base_addr[CyCOR2] = 0;
- base_addr[CyCOR3] = Cy_1_STOP;
- base_addr[CyCOR4] = baud_cor4[i];
- base_addr[CyCOR5] = 0;
- base_addr[CyCOR6] = 0;
- base_addr[CyCOR7] = 0;
+ base_addr[CySCHR1] = 0;
+ base_addr[CySCHR2] = 0;
+ base_addr[CySCRL] = 0;
+ base_addr[CySCRH] = 0;
+ base_addr[CyCOR1] = Cy_8_BITS | CyPARITY_NONE;
+ base_addr[CyCOR2] = 0;
+ base_addr[CyCOR3] = Cy_1_STOP;
+ base_addr[CyCOR4] = baud_cor4[i];
+ base_addr[CyCOR5] = 0;
+ base_addr[CyCOR6] = 0;
+ base_addr[CyCOR7] = 0;
- write_cy_cmd(base_addr,CyINIT_CHAN);
- write_cy_cmd(base_addr,CyENB_RCVR);
+ write_cy_cmd(base_addr, CyINIT_CHAN);
+ write_cy_cmd(base_addr, CyENB_RCVR);
- base_addr[CyCAR] = DEBUG_PORT; /* !!! Is this needed? */
+ base_addr[CyCAR] = DEBUG_PORT; /* !!! Is this needed? */
- base_addr[CyRTPRL] = 2;
- base_addr[CyRTPRH] = 0;
+ base_addr[CyRTPRL] = 2;
+ base_addr[CyRTPRH] = 0;
- base_addr[CyMSVR1] = CyRTS;
- base_addr[CyMSVR2] = CyDTR;
+ base_addr[CyMSVR1] = CyRTS;
+ base_addr[CyMSVR2] = CyDTR;
- base_addr[CyIER] = CyRxData;
+ base_addr[CyIER] = CyRxData;
- local_irq_restore(flags);
+ local_irq_restore(flags);
-} /* debug_setup */
+} /* debug_setup */
#endif
diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c
index 17d54e1331b..78237577b05 100644
--- a/drivers/char/sonypi.c
+++ b/drivers/char/sonypi.c
@@ -36,7 +36,6 @@
#include <linux/module.h>
#include <linux/input.h>
#include <linux/pci.h>
-#include <linux/sched.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/miscdevice.h>
diff --git a/drivers/char/specialix.c b/drivers/char/specialix.c
index 20946f5127e..baf7234b6e6 100644
--- a/drivers/char/specialix.c
+++ b/drivers/char/specialix.c
@@ -459,10 +459,9 @@ void missed_irq (unsigned long data)
if (irq) {
printk (KERN_INFO "Missed interrupt... Calling int from timer. \n");
sx_interrupt (((struct specialix_board *)data)->irq,
- (void*)data, NULL);
+ (void*)data);
}
- missed_irq_timer.expires = jiffies + sx_poll;
- add_timer (&missed_irq_timer);
+ mod_timer(&missed_irq_timer, jiffies + sx_poll);
}
#endif
@@ -597,11 +596,8 @@ static int sx_probe(struct specialix_board *bp)
dprintk (SX_DEBUG_INIT, " GFCR = 0x%02x\n", sx_in_off(bp, CD186x_GFRCR) );
#ifdef SPECIALIX_TIMER
- init_timer (&missed_irq_timer);
- missed_irq_timer.function = missed_irq;
- missed_irq_timer.data = (unsigned long) bp;
- missed_irq_timer.expires = jiffies + sx_poll;
- add_timer (&missed_irq_timer);
+ setup_timer(&missed_irq_timer, missed_irq, (unsigned long)bp);
+ mod_timer(&missed_irq_timer, jiffies + sx_poll);
#endif
printk(KERN_INFO"sx%d: specialix IO8+ board detected at 0x%03x, IRQ %d, CD%d Rev. %c.\n",
@@ -2350,10 +2346,8 @@ static void do_softint(struct work_struct *work)
return;
}
- if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) {
+ if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event))
tty_wakeup(tty);
- //wake_up_interruptible(&tty->write_wait);
- }
func_exit();
}
@@ -2561,7 +2555,7 @@ static void __exit specialix_exit_module(void)
if (sx_board[i].flags & SX_BOARD_PRESENT)
sx_release_io_range(&sx_board[i]);
#ifdef SPECIALIX_TIMER
- del_timer (&missed_irq_timer);
+ del_timer_sync(&missed_irq_timer);
#endif
func_exit();
diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c
index 3fa625db9e4..ce4db6f5236 100644
--- a/drivers/char/synclink.c
+++ b/drivers/char/synclink.c
@@ -1148,10 +1148,8 @@ static void mgsl_bh_transmit(struct mgsl_struct *info)
printk( "%s(%d):mgsl_bh_transmit() entry on %s\n",
__FILE__,__LINE__,info->device_name);
- if (tty) {
+ if (tty)
tty_wakeup(tty);
- wake_up_interruptible(&tty->write_wait);
- }
/* if transmitter idle and loopmode_send_done_requested
* then start echoing RxD to TxD
@@ -1800,9 +1798,7 @@ static int startup(struct mgsl_struct * info)
memset(&info->icount, 0, sizeof(info->icount));
- init_timer(&info->tx_timer);
- info->tx_timer.data = (unsigned long)info;
- info->tx_timer.function = mgsl_tx_timeout;
+ setup_timer(&info->tx_timer, mgsl_tx_timeout, (unsigned long)info);
/* Allocate and claim adapter resources */
retval = mgsl_claim_resources(info);
@@ -1853,7 +1849,7 @@ static void shutdown(struct mgsl_struct * info)
wake_up_interruptible(&info->status_event_wait_q);
wake_up_interruptible(&info->event_wait_q);
- del_timer(&info->tx_timer);
+ del_timer_sync(&info->tx_timer);
if (info->xmit_buf) {
free_page((unsigned long) info->xmit_buf);
@@ -2340,7 +2336,6 @@ static void mgsl_flush_buffer(struct tty_struct *tty)
del_timer(&info->tx_timer);
spin_unlock_irqrestore(&info->irq_spinlock,flags);
- wake_up_interruptible(&tty->write_wait);
tty_wakeup(tty);
}
@@ -5713,8 +5708,8 @@ static void usc_start_transmitter( struct mgsl_struct *info )
usc_TCmd( info, TCmd_SendFrame );
- info->tx_timer.expires = jiffies + msecs_to_jiffies(5000);
- add_timer(&info->tx_timer);
+ mod_timer(&info->tx_timer, jiffies +
+ msecs_to_jiffies(5000));
}
info->tx_active = 1;
}
diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c
index 792c79c315e..0a367cd4121 100644
--- a/drivers/char/synclink_gt.c
+++ b/drivers/char/synclink_gt.c
@@ -1045,7 +1045,6 @@ static void flush_buffer(struct tty_struct *tty)
info->tx_count = 0;
spin_unlock_irqrestore(&info->lock,flags);
- wake_up_interruptible(&tty->write_wait);
tty_wakeup(tty);
}
@@ -1826,8 +1825,7 @@ static void rx_async(struct slgt_info *info)
if (i < count) {
/* receive buffer not completed */
info->rbuf_index += i;
- info->rx_timer.expires = jiffies + 1;
- add_timer(&info->rx_timer);
+ mod_timer(&info->rx_timer, jiffies + 1);
break;
}
@@ -1933,10 +1931,8 @@ static void bh_transmit(struct slgt_info *info)
struct tty_struct *tty = info->tty;
DBGBH(("%s bh_transmit\n", info->device_name));
- if (tty) {
+ if (tty)
tty_wakeup(tty);
- wake_up_interruptible(&tty->write_wait);
- }
}
static void dsr_change(struct slgt_info *info)
@@ -3343,13 +3339,8 @@ static struct slgt_info *alloc_dev(int adapter_num, int port_num, struct pci_dev
info->adapter_num = adapter_num;
info->port_num = port_num;
- init_timer(&info->tx_timer);
- info->tx_timer.data = (unsigned long)info;
- info->tx_timer.function = tx_timeout;
-
- init_timer(&info->rx_timer);
- info->rx_timer.data = (unsigned long)info;
- info->rx_timer.function = rx_timeout;
+ setup_timer(&info->tx_timer, tx_timeout, (unsigned long)info);
+ setup_timer(&info->rx_timer, rx_timeout, (unsigned long)info);
/* Copy configuration info to device instance data */
info->pdev = pdev;
@@ -3797,10 +3788,9 @@ static void tx_start(struct slgt_info *info)
}
}
- if (info->params.mode == MGSL_MODE_HDLC) {
- info->tx_timer.expires = jiffies + msecs_to_jiffies(5000);
- add_timer(&info->tx_timer);
- }
+ if (info->params.mode == MGSL_MODE_HDLC)
+ mod_timer(&info->tx_timer, jiffies +
+ msecs_to_jiffies(5000));
} else {
tdma_reset(info);
/* set 1st descriptor address */
diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c
index 8f4d67afe5b..ef93d055bdd 100644
--- a/drivers/char/synclinkmp.c
+++ b/drivers/char/synclinkmp.c
@@ -1258,7 +1258,6 @@ static void flush_buffer(struct tty_struct *tty)
del_timer(&info->tx_timer);
spin_unlock_irqrestore(&info->lock,flags);
- wake_up_interruptible(&tty->write_wait);
tty_wakeup(tty);
}
@@ -2127,10 +2126,8 @@ void bh_transmit(SLMP_INFO *info)
printk( "%s(%d):%s bh_transmit() entry\n",
__FILE__,__LINE__,info->device_name);
- if (tty) {
+ if (tty)
tty_wakeup(tty);
- wake_up_interruptible(&tty->write_wait);
- }
}
void bh_status(SLMP_INFO *info)
@@ -2747,8 +2744,7 @@ static int startup(SLMP_INFO * info)
change_params(info);
- info->status_timer.expires = jiffies + msecs_to_jiffies(10);
- add_timer(&info->status_timer);
+ mod_timer(&info->status_timer, jiffies + msecs_to_jiffies(10));
if (info->tty)
clear_bit(TTY_IO_ERROR, &info->tty->flags);
@@ -3844,13 +3840,9 @@ static SLMP_INFO *alloc_dev(int adapter_num, int port_num, struct pci_dev *pdev)
info->bus_type = MGSL_BUS_TYPE_PCI;
info->irq_flags = IRQF_SHARED;
- init_timer(&info->tx_timer);
- info->tx_timer.data = (unsigned long)info;
- info->tx_timer.function = tx_timeout;
-
- init_timer(&info->status_timer);
- info->status_timer.data = (unsigned long)info;
- info->status_timer.function = status_timeout;
+ setup_timer(&info->tx_timer, tx_timeout, (unsigned long)info);
+ setup_timer(&info->status_timer, status_timeout,
+ (unsigned long)info);
/* Store the PCI9050 misc control register value because a flaw
* in the PCI9050 prevents LCR registers from being read if
@@ -4294,8 +4286,8 @@ void tx_start(SLMP_INFO *info)
write_reg(info, TXDMA + DIR, 0x40); /* enable Tx DMA interrupts (EOM) */
write_reg(info, TXDMA + DSR, 0xf2); /* clear Tx DMA IRQs, enable Tx DMA */
- info->tx_timer.expires = jiffies + msecs_to_jiffies(5000);
- add_timer(&info->tx_timer);
+ mod_timer(&info->tx_timer, jiffies +
+ msecs_to_jiffies(5000));
}
else {
tx_load_fifo(info);
@@ -5577,10 +5569,7 @@ void status_timeout(unsigned long context)
if (status)
isr_io_pin(info,status);
- info->status_timer.data = (unsigned long)info;
- info->status_timer.function = status_timeout;
- info->status_timer.expires = jiffies + msecs_to_jiffies(10);
- add_timer(&info->status_timer);
+ mod_timer(&info->status_timer, jiffies + msecs_to_jiffies(10));
}
diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c
index 7fd3cd5ddf2..1d8c4ae6155 100644
--- a/drivers/char/sysrq.c
+++ b/drivers/char/sysrq.c
@@ -36,6 +36,7 @@
#include <linux/workqueue.h>
#include <linux/kexec.h>
#include <linux/irq.h>
+#include <linux/hrtimer.h>
#include <asm/ptrace.h>
#include <asm/irq_regs.h>
@@ -88,9 +89,8 @@ static struct sysrq_key_op sysrq_loglevel_op = {
#ifdef CONFIG_VT
static void sysrq_handle_SAK(int key, struct tty_struct *tty)
{
- if (tty)
- do_SAK(tty);
- reset_vc(vc_cons[fg_console].d);
+ struct work_struct *SAK_work = &vc_cons[fg_console].SAK_work;
+ schedule_work(SAK_work);
}
static struct sysrq_key_op sysrq_SAK_op = {
.handler = sysrq_handle_SAK,
@@ -159,6 +159,17 @@ static struct sysrq_key_op sysrq_sync_op = {
.enable_mask = SYSRQ_ENABLE_SYNC,
};
+static void sysrq_handle_show_timers(int key, struct tty_struct *tty)
+{
+ sysrq_timer_list_show();
+}
+
+static struct sysrq_key_op sysrq_show_timers_op = {
+ .handler = sysrq_handle_show_timers,
+ .help_msg = "show-all-timers(Q)",
+ .action_msg = "Show Pending Timers",
+};
+
static void sysrq_handle_mountro(int key, struct tty_struct *tty)
{
emergency_remount();
@@ -336,7 +347,7 @@ static struct sysrq_key_op *sysrq_key_table[36] = {
/* o: This will often be registered as 'Off' at init time */
NULL, /* o */
&sysrq_showregs_op, /* p */
- NULL, /* q */
+ &sysrq_show_timers_op, /* q */
&sysrq_unraw_op, /* r */
&sysrq_sync_op, /* s */
&sysrq_showstate_op, /* t */
diff --git a/drivers/char/tlclk.c b/drivers/char/tlclk.c
index 4fac2bdf621..35e58030d29 100644
--- a/drivers/char/tlclk.c
+++ b/drivers/char/tlclk.c
@@ -29,7 +29,6 @@
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/sched.h>
#include <linux/kernel.h> /* printk() */
#include <linux/fs.h> /* everything... */
#include <linux/errno.h> /* error codes */
diff --git a/drivers/char/toshiba.c b/drivers/char/toshiba.c
index 07067c31c4e..5422f999636 100644
--- a/drivers/char/toshiba.c
+++ b/drivers/char/toshiba.c
@@ -58,7 +58,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/miscdevice.h>
@@ -68,6 +67,7 @@
#include <linux/init.h>
#include <linux/stat.h>
#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
#include <linux/toshiba.h>
@@ -298,12 +298,10 @@ static int tosh_ioctl(struct inode *ip, struct file *fp, unsigned int cmd,
* Print the information for /proc/toshiba
*/
#ifdef CONFIG_PROC_FS
-static int tosh_get_info(char *buffer, char **start, off_t fpos, int length)
+static int proc_toshiba_show(struct seq_file *m, void *v)
{
- char *temp;
int key;
- temp = buffer;
key = tosh_fn_status();
/* Arguments
@@ -314,8 +312,7 @@ static int tosh_get_info(char *buffer, char **start, off_t fpos, int length)
4) BIOS date (in SCI date format)
5) Fn Key status
*/
-
- temp += sprintf(temp, "1.1 0x%04x %d.%d %d.%d 0x%04x 0x%02x\n",
+ seq_printf(m, "1.1 0x%04x %d.%d %d.%d 0x%04x 0x%02x\n",
tosh_id,
(tosh_sci & 0xff00)>>8,
tosh_sci & 0xff,
@@ -323,9 +320,21 @@ static int tosh_get_info(char *buffer, char **start, off_t fpos, int length)
tosh_bios & 0xff,
tosh_date,
key);
+ return 0;
+}
- return temp-buffer;
+static int proc_toshiba_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, proc_toshiba_show, NULL);
}
+
+static const struct file_operations proc_toshiba_fops = {
+ .owner = THIS_MODULE,
+ .open = proc_toshiba_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
#endif
@@ -508,10 +517,15 @@ static int __init toshiba_init(void)
return retval;
#ifdef CONFIG_PROC_FS
- /* register the proc entry */
- if (create_proc_info_entry("toshiba", 0, NULL, tosh_get_info) == NULL) {
- misc_deregister(&tosh_device);
- return -ENOMEM;
+ {
+ struct proc_dir_entry *pde;
+
+ pde = create_proc_entry("toshiba", 0, NULL);
+ if (!pde) {
+ misc_deregister(&tosh_device);
+ return -ENOMEM;
+ }
+ pde->proc_fops = &proc_toshiba_fops;
}
#endif
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c
index 33e1f66e39c..e5a254a434f 100644
--- a/drivers/char/tpm/tpm.c
+++ b/drivers/char/tpm/tpm.c
@@ -23,7 +23,6 @@
*
*/
-#include <linux/sched.h>
#include <linux/poll.h>
#include <linux/spinlock.h>
#include "tpm.h"
@@ -1107,9 +1106,8 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vend
INIT_WORK(&chip->work, timeout_work);
- init_timer(&chip->user_read_timer);
- chip->user_read_timer.function = user_reader_timeout;
- chip->user_read_timer.data = (unsigned long) chip;
+ setup_timer(&chip->user_read_timer, user_reader_timeout,
+ (unsigned long)chip);
memcpy(&chip->vendor, entry, sizeof(struct tpm_vendor_specific));
diff --git a/drivers/char/tpm/tpm_bios.c b/drivers/char/tpm/tpm_bios.c
index a611972024e..4eba32b23b2 100644
--- a/drivers/char/tpm/tpm_bios.c
+++ b/drivers/char/tpm/tpm_bios.c
@@ -372,10 +372,8 @@ static int read_log(struct tpm_bios_log *log)
}
/* Find TCPA entry in RSDT (ACPI_LOGICAL_ADDRESSING) */
- status = acpi_get_firmware_table(ACPI_TCPA_SIG, 1,
- ACPI_LOGICAL_ADDRESSING,
- (struct acpi_table_header **)
- &buff);
+ status = acpi_get_table(ACPI_SIG_TCPA, 1,
+ (struct acpi_table_header **)&buff);
if (ACPI_FAILURE(status)) {
printk(KERN_ERR "%s: ERROR - Could not get TCPA table\n",
@@ -409,7 +407,7 @@ static int read_log(struct tpm_bios_log *log)
log->bios_event_log_end = log->bios_event_log + len;
- acpi_os_map_memory(start, len, (void *) &virt);
+ virt = acpi_os_map_memory(start, len);
memcpy(log->bios_event_log, virt, len);
@@ -443,7 +441,7 @@ static int tpm_ascii_bios_measurements_open(struct inode *inode,
return err;
}
-struct file_operations tpm_ascii_bios_measurements_ops = {
+const struct file_operations tpm_ascii_bios_measurements_ops = {
.open = tpm_ascii_bios_measurements_open,
.read = seq_read,
.llseek = seq_lseek,
@@ -476,7 +474,7 @@ static int tpm_binary_bios_measurements_open(struct inode *inode,
return err;
}
-struct file_operations tpm_binary_bios_measurements_ops = {
+const struct file_operations tpm_binary_bios_measurements_ops = {
.open = tpm_binary_bios_measurements_open,
.read = seq_read,
.llseek = seq_lseek,
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 47a6eacb10b..f24c26d2dba 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -154,7 +154,9 @@ static int tty_release(struct inode *, struct file *);
int tty_ioctl(struct inode * inode, struct file * file,
unsigned int cmd, unsigned long arg);
static int tty_fasync(int fd, struct file * filp, int on);
-static void release_mem(struct tty_struct *tty, int idx);
+static void release_tty(struct tty_struct *tty, int idx);
+static struct pid *__proc_set_tty(struct task_struct *tsk,
+ struct tty_struct *tty);
/**
* alloc_tty_struct - allocate a tty object
@@ -1109,17 +1111,17 @@ int tty_check_change(struct tty_struct * tty)
{
if (current->signal->tty != tty)
return 0;
- if (tty->pgrp <= 0) {
- printk(KERN_WARNING "tty_check_change: tty->pgrp <= 0!\n");
+ if (!tty->pgrp) {
+ printk(KERN_WARNING "tty_check_change: tty->pgrp == NULL!\n");
return 0;
}
- if (process_group(current) == tty->pgrp)
+ if (task_pgrp(current) == tty->pgrp)
return 0;
if (is_ignored(SIGTTOU))
return 0;
- if (is_orphaned_pgrp(process_group(current)))
+ if (is_current_pgrp_orphaned())
return -EIO;
- (void) kill_pg(process_group(current), SIGTTOU, 1);
+ (void) kill_pgrp(task_pgrp(current), SIGTTOU, 1);
return -ERESTARTSYS;
}
@@ -1354,8 +1356,8 @@ static void do_tty_hangup(struct work_struct *work)
tty_release is called */
read_lock(&tasklist_lock);
- if (tty->session > 0) {
- do_each_task_pid(tty->session, PIDTYPE_SID, p) {
+ if (tty->session) {
+ do_each_pid_task(tty->session, PIDTYPE_SID, p) {
spin_lock_irq(&p->sighand->siglock);
if (p->signal->tty == tty)
p->signal->tty = NULL;
@@ -1365,16 +1367,17 @@ static void do_tty_hangup(struct work_struct *work)
}
__group_send_sig_info(SIGHUP, SEND_SIG_PRIV, p);
__group_send_sig_info(SIGCONT, SEND_SIG_PRIV, p);
- if (tty->pgrp > 0)
- p->signal->tty_old_pgrp = tty->pgrp;
+ put_pid(p->signal->tty_old_pgrp); /* A noop */
+ if (tty->pgrp)
+ p->signal->tty_old_pgrp = get_pid(tty->pgrp);
spin_unlock_irq(&p->sighand->siglock);
- } while_each_task_pid(tty->session, PIDTYPE_SID, p);
+ } while_each_pid_task(tty->session, PIDTYPE_SID, p);
}
read_unlock(&tasklist_lock);
tty->flags = 0;
- tty->session = 0;
- tty->pgrp = -1;
+ tty->session = NULL;
+ tty->pgrp = NULL;
tty->ctrl_status = 0;
/*
* If one of the devices matches a console pointer, we
@@ -1459,12 +1462,12 @@ int tty_hung_up_p(struct file * filp)
EXPORT_SYMBOL(tty_hung_up_p);
-static void session_clear_tty(pid_t session)
+static void session_clear_tty(struct pid *session)
{
struct task_struct *p;
- do_each_task_pid(session, PIDTYPE_SID, p) {
+ do_each_pid_task(session, PIDTYPE_SID, p) {
proc_clear_tty(p);
- } while_each_task_pid(session, PIDTYPE_SID, p);
+ } while_each_pid_task(session, PIDTYPE_SID, p);
}
/**
@@ -1494,46 +1497,54 @@ static void session_clear_tty(pid_t session)
void disassociate_ctty(int on_exit)
{
struct tty_struct *tty;
- int tty_pgrp = -1;
- int session;
+ struct pid *tty_pgrp = NULL;
lock_kernel();
mutex_lock(&tty_mutex);
tty = get_current_tty();
if (tty) {
- tty_pgrp = tty->pgrp;
+ tty_pgrp = get_pid(tty->pgrp);
mutex_unlock(&tty_mutex);
/* XXX: here we race, there is nothing protecting tty */
if (on_exit && tty->driver->type != TTY_DRIVER_TYPE_PTY)
tty_vhangup(tty);
- } else {
- pid_t old_pgrp = current->signal->tty_old_pgrp;
+ } else if (on_exit) {
+ struct pid *old_pgrp;
+ spin_lock_irq(&current->sighand->siglock);
+ old_pgrp = current->signal->tty_old_pgrp;
+ current->signal->tty_old_pgrp = NULL;
+ spin_unlock_irq(&current->sighand->siglock);
if (old_pgrp) {
- kill_pg(old_pgrp, SIGHUP, on_exit);
- kill_pg(old_pgrp, SIGCONT, on_exit);
+ kill_pgrp(old_pgrp, SIGHUP, on_exit);
+ kill_pgrp(old_pgrp, SIGCONT, on_exit);
+ put_pid(old_pgrp);
}
mutex_unlock(&tty_mutex);
unlock_kernel();
return;
}
- if (tty_pgrp > 0) {
- kill_pg(tty_pgrp, SIGHUP, on_exit);
+ if (tty_pgrp) {
+ kill_pgrp(tty_pgrp, SIGHUP, on_exit);
if (!on_exit)
- kill_pg(tty_pgrp, SIGCONT, on_exit);
+ kill_pgrp(tty_pgrp, SIGCONT, on_exit);
+ put_pid(tty_pgrp);
}
spin_lock_irq(&current->sighand->siglock);
- current->signal->tty_old_pgrp = 0;
- session = process_session(current);
+ tty_pgrp = current->signal->tty_old_pgrp;
+ current->signal->tty_old_pgrp = NULL;
spin_unlock_irq(&current->sighand->siglock);
+ put_pid(tty_pgrp);
mutex_lock(&tty_mutex);
/* It is possible that do_tty_hangup has free'd this tty */
tty = get_current_tty();
if (tty) {
- tty->session = 0;
- tty->pgrp = 0;
+ put_pid(tty->session);
+ put_pid(tty->pgrp);
+ tty->session = NULL;
+ tty->pgrp = NULL;
} else {
#ifdef TTY_DEBUG_HANGUP
printk(KERN_DEBUG "error attempted to write to tty [0x%p]"
@@ -1544,7 +1555,7 @@ void disassociate_ctty(int on_exit)
/* Now clear signal->tty under the lock */
read_lock(&tasklist_lock);
- session_clear_tty(session);
+ session_clear_tty(task_session(current));
read_unlock(&tasklist_lock);
unlock_kernel();
}
@@ -1612,7 +1623,6 @@ void start_tty(struct tty_struct *tty)
/* If we have a running line discipline it may need kicking */
tty_wakeup(tty);
- wake_up_interruptible(&tty->write_wait);
}
EXPORT_SYMBOL(start_tty);
@@ -2003,7 +2013,7 @@ static int init_dev(struct tty_driver *driver, int idx,
/*
* All structures have been allocated, so now we install them.
- * Failures after this point use release_mem to clean up, so
+ * Failures after this point use release_tty to clean up, so
* there's no need to null out the local pointers.
*/
if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM)) {
@@ -2024,8 +2034,8 @@ static int init_dev(struct tty_driver *driver, int idx,
/*
* Structures all installed ... call the ldisc open routines.
- * If we fail here just call release_mem to clean up. No need
- * to decrement the use counts, as release_mem doesn't care.
+ * If we fail here just call release_tty to clean up. No need
+ * to decrement the use counts, as release_tty doesn't care.
*/
if (tty->ldisc.open) {
@@ -2095,17 +2105,17 @@ fail_no_mem:
retval = -ENOMEM;
goto end_init;
- /* call the tty release_mem routine to clean out this slot */
+ /* call the tty release_tty routine to clean out this slot */
release_mem_out:
if (printk_ratelimit())
printk(KERN_INFO "init_dev: ldisc open failed, "
"clearing slot %d\n", idx);
- release_mem(tty, idx);
+ release_tty(tty, idx);
goto end_init;
}
/**
- * release_mem - release tty structure memory
+ * release_one_tty - release tty structure memory
*
* Releases memory associated with a tty structure, and clears out the
* driver table slots. This function is called when a device is no longer
@@ -2117,37 +2127,14 @@ release_mem_out:
* of ttys that the driver keeps.
* FIXME: should we require tty_mutex is held here ??
*/
-
-static void release_mem(struct tty_struct *tty, int idx)
+static void release_one_tty(struct tty_struct *tty, int idx)
{
- struct tty_struct *o_tty;
- struct ktermios *tp;
int devpts = tty->driver->flags & TTY_DRIVER_DEVPTS_MEM;
-
- if ((o_tty = tty->link) != NULL) {
- if (!devpts)
- o_tty->driver->ttys[idx] = NULL;
- if (o_tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) {
- tp = o_tty->termios;
- if (!devpts)
- o_tty->driver->termios[idx] = NULL;
- kfree(tp);
-
- tp = o_tty->termios_locked;
- if (!devpts)
- o_tty->driver->termios_locked[idx] = NULL;
- kfree(tp);
- }
- o_tty->magic = 0;
- o_tty->driver->refcount--;
- file_list_lock();
- list_del_init(&o_tty->tty_files);
- file_list_unlock();
- free_tty_struct(o_tty);
- }
+ struct ktermios *tp;
if (!devpts)
tty->driver->ttys[idx] = NULL;
+
if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) {
tp = tty->termios;
if (!devpts)
@@ -2160,15 +2147,39 @@ static void release_mem(struct tty_struct *tty, int idx)
kfree(tp);
}
+
tty->magic = 0;
tty->driver->refcount--;
+
file_list_lock();
list_del_init(&tty->tty_files);
file_list_unlock();
- module_put(tty->driver->owner);
+
free_tty_struct(tty);
}
+/**
+ * release_tty - release tty structure memory
+ *
+ * Release both @tty and a possible linked partner (think pty pair),
+ * and decrement the refcount of the backing module.
+ *
+ * Locking:
+ * tty_mutex - sometimes only
+ * takes the file list lock internally when working on the list
+ * of ttys that the driver keeps.
+ * FIXME: should we require tty_mutex is held here ??
+ */
+static void release_tty(struct tty_struct *tty, int idx)
+{
+ struct tty_driver *driver = tty->driver;
+
+ if (tty->link)
+ release_one_tty(tty->link, idx);
+ release_one_tty(tty, idx);
+ module_put(driver->owner);
+}
+
/*
* Even releasing the tty structures is a tricky business.. We have
* to be very careful that the structures are all released at the
@@ -2436,10 +2447,10 @@ static void release_dev(struct file * filp)
tty_set_termios_ldisc(o_tty,N_TTY);
}
/*
- * The release_mem function takes care of the details of clearing
+ * The release_tty function takes care of the details of clearing
* the slots and preserving the termios structure.
*/
- release_mem(tty, idx);
+ release_tty(tty, idx);
#ifdef CONFIG_UNIX98_PTYS
/* Make this pty number available for reallocation */
@@ -2481,6 +2492,7 @@ static int tty_open(struct inode * inode, struct file * filp)
int index;
dev_t device = inode->i_rdev;
unsigned short saved_flags = filp->f_flags;
+ struct pid *old_pgrp;
nonseekable_open(inode, filp);
@@ -2574,15 +2586,17 @@ got_driver:
goto retry_open;
}
+ old_pgrp = NULL;
mutex_lock(&tty_mutex);
spin_lock_irq(&current->sighand->siglock);
if (!noctty &&
current->signal->leader &&
!current->signal->tty &&
- tty->session == 0)
- __proc_set_tty(current, tty);
+ tty->session == NULL)
+ old_pgrp = __proc_set_tty(current, tty);
spin_unlock_irq(&current->sighand->siglock);
mutex_unlock(&tty_mutex);
+ put_pid(old_pgrp);
return 0;
}
@@ -2721,9 +2735,18 @@ static int tty_fasync(int fd, struct file * filp, int on)
return retval;
if (on) {
+ enum pid_type type;
+ struct pid *pid;
if (!waitqueue_active(&tty->read_wait))
tty->minimum_to_wake = 1;
- retval = f_setown(filp, (-tty->pgrp) ? : current->pid, 0);
+ if (tty->pgrp) {
+ pid = tty->pgrp;
+ type = PIDTYPE_PGID;
+ } else {
+ pid = task_pid(current);
+ type = PIDTYPE_PID;
+ }
+ retval = __f_setown(filp, pid, type, 0);
if (retval)
return retval;
} else {
@@ -2825,10 +2848,10 @@ static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty,
}
}
#endif
- if (tty->pgrp > 0)
- kill_pg(tty->pgrp, SIGWINCH, 1);
- if ((real_tty->pgrp != tty->pgrp) && (real_tty->pgrp > 0))
- kill_pg(real_tty->pgrp, SIGWINCH, 1);
+ if (tty->pgrp)
+ kill_pgrp(tty->pgrp, SIGWINCH, 1);
+ if ((real_tty->pgrp != tty->pgrp) && real_tty->pgrp)
+ kill_pgrp(real_tty->pgrp, SIGWINCH, 1);
tty->winsize = tmp_ws;
real_tty->winsize = tmp_ws;
done:
@@ -2913,8 +2936,7 @@ static int fionbio(struct file *file, int __user *p)
static int tiocsctty(struct tty_struct *tty, int arg)
{
int ret = 0;
- if (current->signal->leader &&
- (process_session(current) == tty->session))
+ if (current->signal->leader && (task_session(current) == tty->session))
return ret;
mutex_lock(&tty_mutex);
@@ -2927,7 +2949,7 @@ static int tiocsctty(struct tty_struct *tty, int arg)
goto unlock;
}
- if (tty->session > 0) {
+ if (tty->session) {
/*
* This tty is already the controlling
* tty for another session group!
@@ -2970,7 +2992,7 @@ static int tiocgpgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t
*/
if (tty == real_tty && current->signal->tty != real_tty)
return -ENOTTY;
- return put_user(real_tty->pgrp, p);
+ return put_user(pid_nr(real_tty->pgrp), p);
}
/**
@@ -2987,7 +3009,8 @@ static int tiocgpgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t
static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
{
- pid_t pgrp;
+ struct pid *pgrp;
+ pid_t pgrp_nr;
int retval = tty_check_change(real_tty);
if (retval == -EIO)
@@ -2996,16 +3019,26 @@ static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t
return retval;
if (!current->signal->tty ||
(current->signal->tty != real_tty) ||
- (real_tty->session != process_session(current)))
+ (real_tty->session != task_session(current)))
return -ENOTTY;
- if (get_user(pgrp, p))
+ if (get_user(pgrp_nr, p))
return -EFAULT;
- if (pgrp < 0)
+ if (pgrp_nr < 0)
return -EINVAL;
- if (session_of_pgrp(pgrp) != process_session(current))
- return -EPERM;
- real_tty->pgrp = pgrp;
- return 0;
+ rcu_read_lock();
+ pgrp = find_pid(pgrp_nr);
+ retval = -ESRCH;
+ if (!pgrp)
+ goto out_unlock;
+ retval = -EPERM;
+ if (session_of_pgrp(pgrp) != task_session(current))
+ goto out_unlock;
+ retval = 0;
+ put_pid(real_tty->pgrp);
+ real_tty->pgrp = get_pid(pgrp);
+out_unlock:
+ rcu_read_unlock();
+ return retval;
}
/**
@@ -3028,9 +3061,9 @@ static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t _
*/
if (tty == real_tty && current->signal->tty != real_tty)
return -ENOTTY;
- if (real_tty->session <= 0)
+ if (!real_tty->session)
return -ENOTTY;
- return put_user(real_tty->session, p);
+ return put_user(pid_nr(real_tty->session), p);
}
/**
@@ -3324,15 +3357,13 @@ int tty_ioctl(struct inode * inode, struct file * file,
* Nasty bug: do_SAK is being called in interrupt context. This can
* deadlock. We punt it up to process context. AKPM - 16Mar2001
*/
-static void __do_SAK(struct work_struct *work)
+void __do_SAK(struct tty_struct *tty)
{
- struct tty_struct *tty =
- container_of(work, struct tty_struct, SAK_work);
#ifdef TTY_SOFT_SAK
tty_hangup(tty);
#else
struct task_struct *g, *p;
- int session;
+ struct pid *session;
int i;
struct file *filp;
struct fdtable *fdt;
@@ -3348,12 +3379,12 @@ static void __do_SAK(struct work_struct *work)
read_lock(&tasklist_lock);
/* Kill the entire session */
- do_each_task_pid(session, PIDTYPE_SID, p) {
+ do_each_pid_task(session, PIDTYPE_SID, p) {
printk(KERN_NOTICE "SAK: killed process %d"
" (%s): process_session(p)==tty->session\n",
p->pid, p->comm);
send_sig(SIGKILL, p, 1);
- } while_each_task_pid(session, PIDTYPE_SID, p);
+ } while_each_pid_task(session, PIDTYPE_SID, p);
/* Now kill any processes that happen to have the
* tty open.
*/
@@ -3394,6 +3425,13 @@ static void __do_SAK(struct work_struct *work)
#endif
}
+static void do_SAK_work(struct work_struct *work)
+{
+ struct tty_struct *tty =
+ container_of(work, struct tty_struct, SAK_work);
+ __do_SAK(tty);
+}
+
/*
* The tq handling here is a little racy - tty->SAK_work may already be queued.
* Fortunately we don't need to worry, because if ->SAK_work is already queued,
@@ -3404,7 +3442,6 @@ void do_SAK(struct tty_struct *tty)
{
if (!tty)
return;
- PREPARE_WORK(&tty->SAK_work, __do_SAK);
schedule_work(&tty->SAK_work);
}
@@ -3515,7 +3552,8 @@ static void initialize_tty_struct(struct tty_struct *tty)
memset(tty, 0, sizeof(struct tty_struct));
tty->magic = TTY_MAGIC;
tty_ldisc_assign(tty, tty_ldisc_get(N_TTY));
- tty->pgrp = -1;
+ tty->session = NULL;
+ tty->pgrp = NULL;
tty->overrun_time = jiffies;
tty->buf.head = tty->buf.tail = NULL;
tty_buffer_init(tty);
@@ -3529,7 +3567,7 @@ static void initialize_tty_struct(struct tty_struct *tty)
mutex_init(&tty->atomic_write_lock);
spin_lock_init(&tty->read_lock);
INIT_LIST_HEAD(&tty->tty_files);
- INIT_WORK(&tty->SAK_work, NULL);
+ INIT_WORK(&tty->SAK_work, do_SAK_work);
}
/*
@@ -3675,15 +3713,14 @@ int tty_register_driver(struct tty_driver *driver)
if (!driver->major) {
error = alloc_chrdev_region(&dev, driver->minor_start, driver->num,
- (char*)driver->name);
+ driver->name);
if (!error) {
driver->major = MAJOR(dev);
driver->minor_start = MINOR(dev);
}
} else {
dev = MKDEV(driver->major, driver->minor_start);
- error = register_chrdev_region(dev, driver->num,
- (char*)driver->name);
+ error = register_chrdev_region(dev, driver->num, driver->name);
}
if (error < 0) {
kfree(p);
@@ -3786,21 +3823,28 @@ void proc_clear_tty(struct task_struct *p)
}
EXPORT_SYMBOL(proc_clear_tty);
-void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
+static struct pid *__proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
{
+ struct pid *old_pgrp;
if (tty) {
- tty->session = process_session(tsk);
- tty->pgrp = process_group(tsk);
+ tty->session = get_pid(task_session(tsk));
+ tty->pgrp = get_pid(task_pgrp(tsk));
}
+ old_pgrp = tsk->signal->tty_old_pgrp;
tsk->signal->tty = tty;
- tsk->signal->tty_old_pgrp = 0;
+ tsk->signal->tty_old_pgrp = NULL;
+ return old_pgrp;
}
void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
{
+ struct pid *old_pgrp;
+
spin_lock_irq(&tsk->sighand->siglock);
- __proc_set_tty(tsk, tty);
+ old_pgrp = __proc_set_tty(tsk, tty);
spin_unlock_irq(&tsk->sighand->siglock);
+
+ put_pid(old_pgrp);
}
struct tty_struct *get_current_tty(void)
diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c
index dee47f40c6a..fd471cb3338 100644
--- a/drivers/char/tty_ioctl.c
+++ b/drivers/char/tty_ioctl.c
@@ -225,7 +225,7 @@ EXPORT_SYMBOL(tty_termios_input_baud_rate);
/**
* tty_termios_encode_baud_rate
- * @termios: termios structure
+ * @termios: ktermios structure holding user requested state
* @ispeed: input speed
* @ospeed: output speed
*
@@ -233,7 +233,10 @@ EXPORT_SYMBOL(tty_termios_input_baud_rate);
* used as a library helper for drivers os that they can report back
* the actual speed selected when it differs from the speed requested
*
- * For now input and output speed must agree.
+ * For maximal back compatibility with legacy SYS5/POSIX *nix behaviour
+ * we need to carefully set the bits when the user does not get the
+ * desired speed. We allow small margins and preserve as much of possible
+ * of the input intent to keep compatiblity.
*
* Locking: Caller should hold termios lock. This is already held
* when calling this function from the driver termios handler.
@@ -242,32 +245,44 @@ EXPORT_SYMBOL(tty_termios_input_baud_rate);
void tty_termios_encode_baud_rate(struct ktermios *termios, speed_t ibaud, speed_t obaud)
{
int i = 0;
- int ifound = 0, ofound = 0;
+ int ifound = -1, ofound = -1;
+ int iclose = ibaud/50, oclose = obaud/50;
+ int ibinput = 0;
termios->c_ispeed = ibaud;
termios->c_ospeed = obaud;
+ /* If the user asked for a precise weird speed give a precise weird
+ answer. If they asked for a Bfoo speed they many have problems
+ digesting non-exact replies so fuzz a bit */
+
+ if ((termios->c_cflag & CBAUD) == BOTHER)
+ oclose = 0;
+ if (((termios->c_cflag >> IBSHIFT) & CBAUD) == BOTHER)
+ iclose = 0;
+ if ((termios->c_cflag >> IBSHIFT) & CBAUD)
+ ibinput = 1; /* An input speed was specified */
+
termios->c_cflag &= ~CBAUD;
- /* Identical speed means no input encoding (ie B0 << IBSHIFT)*/
- if (termios->c_ispeed == termios->c_ospeed)
- ifound = 1;
do {
- if (obaud == baud_table[i]) {
+ if (obaud - oclose >= baud_table[i] && obaud + oclose <= baud_table[i]) {
termios->c_cflag |= baud_bits[i];
- ofound = 1;
- /* So that if ibaud == obaud we don't set it */
- continue;
+ ofound = i;
}
- if (ibaud == baud_table[i]) {
- termios->c_cflag |= (baud_bits[i] << IBSHIFT);
- ifound = 1;
+ if (ibaud - iclose >= baud_table[i] && ibaud + iclose <= baud_table[i]) {
+ /* For the case input == output don't set IBAUD bits if the user didn't do so */
+ if (ofound != i || ibinput)
+ termios->c_cflag |= (baud_bits[i] << IBSHIFT);
+ ifound = i;
}
}
while(++i < n_baud_table);
- if (!ofound)
+ if (ofound == -1)
termios->c_cflag |= BOTHER;
- if (!ifound)
+ /* Set exact input bits only if the input and output differ or the
+ user already did */
+ if (ifound == -1 && (ibaud != obaud || ibinput))
termios->c_cflag |= (BOTHER << IBSHIFT);
}
diff --git a/drivers/char/vc_screen.c b/drivers/char/vc_screen.c
index 26776517f04..791930320a1 100644
--- a/drivers/char/vc_screen.c
+++ b/drivers/char/vc_screen.c
@@ -25,7 +25,6 @@
#include <linux/major.h>
#include <linux/errno.h>
#include <linux/tty.h>
-#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/mm.h>
#include <linux/init.h>
diff --git a/drivers/char/viotape.c b/drivers/char/viotape.c
index 9438512b17f..13faf8d1748 100644
--- a/drivers/char/viotape.c
+++ b/drivers/char/viotape.c
@@ -872,7 +872,7 @@ free_op:
return ret;
}
-struct file_operations viotap_fops = {
+const struct file_operations viotap_fops = {
owner: THIS_MODULE,
read: viotap_read,
write: viotap_write,
diff --git a/drivers/char/vme_scc.c b/drivers/char/vme_scc.c
index e01317cb1a0..bef6d886d4f 100644
--- a/drivers/char/vme_scc.c
+++ b/drivers/char/vme_scc.c
@@ -17,7 +17,6 @@
#include <linux/kdev_t.h>
#include <asm/io.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/errno.h>
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index 06c32a3e3ca..c3f8e383933 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -136,9 +136,6 @@ const struct consw *conswitchp;
#define DEFAULT_BELL_PITCH 750
#define DEFAULT_BELL_DURATION (HZ/8)
-extern void vcs_make_sysfs(struct tty_struct *tty);
-extern void vcs_remove_sysfs(struct tty_struct *tty);
-
struct vc vc_cons [MAX_NR_CONSOLES];
#ifndef VT_SINGLE_DRIVER
@@ -213,7 +210,7 @@ static int scrollback_delta;
*/
int (*console_blank_hook)(int);
-static struct timer_list console_timer;
+static DEFINE_TIMER(console_timer, blank_screen_t, 0, 0);
static int blank_state;
static int blank_timer_expired;
enum {
@@ -869,8 +866,8 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines)
ws.ws_col = vc->vc_cols;
ws.ws_ypixel = vc->vc_scan_lines;
if ((ws.ws_row != cws->ws_row || ws.ws_col != cws->ws_col) &&
- vc->vc_tty->pgrp > 0)
- kill_pg(vc->vc_tty->pgrp, SIGWINCH, 1);
+ vc->vc_tty->pgrp)
+ kill_pgrp(vc->vc_tty->pgrp, SIGWINCH, 1);
*cws = ws;
}
@@ -2628,8 +2625,6 @@ static int __init con_init(void)
for (i = 0; i < MAX_NR_CONSOLES; i++)
con_driver_map[i] = conswitchp;
- init_timer(&console_timer);
- console_timer.function = blank_screen_t;
if (blankinterval) {
blank_state = blank_normal_wait;
mod_timer(&console_timer, jiffies + blankinterval);
@@ -2640,6 +2635,7 @@ static int __init con_init(void)
*/
for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) {
vc_cons[currcons].d = vc = alloc_bootmem(sizeof(struct vc_data));
+ INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK);
visual_init(vc, currcons, 1);
vc->vc_screenbuf = (unsigned short *)alloc_bootmem(vc->vc_screenbuf_size);
vc->vc_kmalloced = 0;
diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c
index dc8368ebb1a..3a5d301e783 100644
--- a/drivers/char/vt_ioctl.c
+++ b/drivers/char/vt_ioctl.c
@@ -672,7 +672,8 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
vc->vt_mode = tmp;
/* the frsig is ignored, so we set it to 0 */
vc->vt_mode.frsig = 0;
- put_pid(xchg(&vc->vt_pid, get_pid(task_pid(current))));
+ put_pid(vc->vt_pid);
+ vc->vt_pid = get_pid(task_pid(current));
/* no switch is required -- saw@shade.msu.ru */
vc->vt_newvt = -1;
release_console_sem();
@@ -1063,12 +1064,35 @@ void reset_vc(struct vc_data *vc)
vc->vt_mode.relsig = 0;
vc->vt_mode.acqsig = 0;
vc->vt_mode.frsig = 0;
- put_pid(xchg(&vc->vt_pid, NULL));
+ put_pid(vc->vt_pid);
+ vc->vt_pid = NULL;
vc->vt_newvt = -1;
if (!in_interrupt()) /* Via keyboard.c:SAK() - akpm */
reset_palette(vc);
}
+void vc_SAK(struct work_struct *work)
+{
+ struct vc *vc_con =
+ container_of(work, struct vc, SAK_work);
+ struct vc_data *vc;
+ struct tty_struct *tty;
+
+ acquire_console_sem();
+ vc = vc_con->d;
+ if (vc) {
+ tty = vc->vc_tty;
+ /*
+ * SAK should also work in all raw modes and reset
+ * them properly.
+ */
+ if (tty)
+ __do_SAK(tty);
+ reset_vc(vc);
+ }
+ release_console_sem();
+}
+
/*
* Performs the back end of a vt switch
*/
diff --git a/drivers/char/watchdog/acquirewdt.c b/drivers/char/watchdog/acquirewdt.c
index 154d67e591e..85269c365a1 100644
--- a/drivers/char/watchdog/acquirewdt.c
+++ b/drivers/char/watchdog/acquirewdt.c
@@ -48,46 +48,52 @@
* It can be 1, 2, 10, 20, 110 or 220 seconds.
*/
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/types.h>
-#include <linux/miscdevice.h>
-#include <linux/watchdog.h>
-#include <linux/fs.h>
-#include <linux/ioport.h>
-#include <linux/notifier.h>
-#include <linux/reboot.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
+/*
+ * Includes, defines, variables, module parameters, ...
+ */
+/* Includes */
+#include <linux/module.h> /* For module specific items */
+#include <linux/moduleparam.h> /* For new moduleparam's */
+#include <linux/types.h> /* For standard types (like size_t) */
+#include <linux/errno.h> /* For the -ENODEV/... values */
+#include <linux/kernel.h> /* For printk/panic/... */
+#include <linux/miscdevice.h> /* For MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR) */
+#include <linux/watchdog.h> /* For the watchdog specific items */
+#include <linux/fs.h> /* For file operations */
+#include <linux/ioport.h> /* For io-port access */
+#include <linux/platform_device.h> /* For platform_driver framework */
+#include <linux/init.h> /* For __init/__exit/... */
+
+#include <asm/uaccess.h> /* For copy_to_user/put_user/... */
+#include <asm/io.h> /* For inb/outb/... */
+
+/* Module information */
+#define DRV_NAME "acquirewdt"
+#define PFX DRV_NAME ": "
#define WATCHDOG_NAME "Acquire WDT"
-#define PFX WATCHDOG_NAME ": "
#define WATCHDOG_HEARTBEAT 0 /* There is no way to see what the correct time-out period is */
+/* internal variables */
+static struct platform_device *acq_platform_device; /* the watchdog platform device */
static unsigned long acq_is_open;
static char expect_close;
-/*
- * You must set these - there is no sane way to probe for this board.
- */
-
-static int wdt_stop = 0x43;
+/* module parameters */
+static int wdt_stop = 0x43; /* You must set this - there is no sane way to probe for this board. */
module_param(wdt_stop, int, 0);
MODULE_PARM_DESC(wdt_stop, "Acquire WDT 'stop' io port (default 0x43)");
-static int wdt_start = 0x443;
+static int wdt_start = 0x443; /* You must set this - there is no sane way to probe for this board. */
module_param(wdt_start, int, 0);
MODULE_PARM_DESC(wdt_start, "Acquire WDT 'start' io port (default 0x443)");
static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0);
-MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
/*
- * Kernel methods.
+ * Watchdog Operations
*/
static void acq_keepalive(void)
@@ -103,7 +109,7 @@ static void acq_stop(void)
}
/*
- * /dev/watchdog handling.
+ * /dev/watchdog handling
*/
static ssize_t acq_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
@@ -143,7 +149,7 @@ static int acq_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
{
.options = WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
.firmware_version = 1,
- .identity = "Acquire WDT",
+ .identity = WATCHDOG_NAME,
};
switch(cmd)
@@ -214,20 +220,6 @@ static int acq_close(struct inode *inode, struct file *file)
}
/*
- * Notifier for system down
- */
-
-static int acq_notify_sys(struct notifier_block *this, unsigned long code,
- void *unused)
-{
- if(code==SYS_DOWN || code==SYS_HALT) {
- /* Turn the WDT off */
- acq_stop();
- }
- return NOTIFY_DONE;
-}
-
-/*
* Kernel Interfaces
*/
@@ -240,29 +232,20 @@ static const struct file_operations acq_fops = {
.release = acq_close,
};
-static struct miscdevice acq_miscdev=
-{
- .minor = WATCHDOG_MINOR,
- .name = "watchdog",
- .fops = &acq_fops,
+static struct miscdevice acq_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &acq_fops,
};
/*
- * The WDT card needs to learn about soft shutdowns in order to
- * turn the timebomb registers off.
+ * Init & exit routines
*/
-static struct notifier_block acq_notifier =
-{
- .notifier_call = acq_notify_sys,
-};
-
-static int __init acq_init(void)
+static int __devinit acq_probe(struct platform_device *dev)
{
int ret;
- printk(KERN_INFO "WDT driver for Acquire single board computer initialising.\n");
-
if (wdt_stop != wdt_start) {
if (!request_region(wdt_stop, 1, WATCHDOG_NAME)) {
printk (KERN_ERR PFX "I/O address 0x%04x already in use\n",
@@ -279,18 +262,11 @@ static int __init acq_init(void)
goto unreg_stop;
}
- ret = register_reboot_notifier(&acq_notifier);
- if (ret != 0) {
- printk (KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
- ret);
- goto unreg_regions;
- }
-
ret = misc_register(&acq_miscdev);
if (ret != 0) {
printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret);
- goto unreg_reboot;
+ goto unreg_regions;
}
printk (KERN_INFO PFX "initialized. (nowayout=%d)\n",
@@ -298,8 +274,6 @@ static int __init acq_init(void)
return 0;
-unreg_reboot:
- unregister_reboot_notifier(&acq_notifier);
unreg_regions:
release_region(wdt_start, 1);
unreg_stop:
@@ -309,13 +283,60 @@ out:
return ret;
}
-static void __exit acq_exit(void)
+static int __devexit acq_remove(struct platform_device *dev)
{
misc_deregister(&acq_miscdev);
- unregister_reboot_notifier(&acq_notifier);
+ release_region(wdt_start,1);
if(wdt_stop != wdt_start)
release_region(wdt_stop,1);
- release_region(wdt_start,1);
+
+ return 0;
+}
+
+static void acq_shutdown(struct platform_device *dev)
+{
+ /* Turn the WDT off if we have a soft shutdown */
+ acq_stop();
+}
+
+static struct platform_driver acquirewdt_driver = {
+ .probe = acq_probe,
+ .remove = __devexit_p(acq_remove),
+ .shutdown = acq_shutdown,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRV_NAME,
+ },
+};
+
+static int __init acq_init(void)
+{
+ int err;
+
+ printk(KERN_INFO "WDT driver for Acquire single board computer initialising.\n");
+
+ err = platform_driver_register(&acquirewdt_driver);
+ if (err)
+ return err;
+
+ acq_platform_device = platform_device_register_simple(DRV_NAME, -1, NULL, 0);
+ if (IS_ERR(acq_platform_device)) {
+ err = PTR_ERR(acq_platform_device);
+ goto unreg_platform_driver;
+ }
+
+ return 0;
+
+unreg_platform_driver:
+ platform_driver_unregister(&acquirewdt_driver);
+ return err;
+}
+
+static void __exit acq_exit(void)
+{
+ platform_device_unregister(acq_platform_device);
+ platform_driver_unregister(&acquirewdt_driver);
+ printk(KERN_INFO PFX "Watchdog Module Unloaded.\n");
}
module_init(acq_init);
diff --git a/drivers/char/watchdog/advantechwdt.c b/drivers/char/watchdog/advantechwdt.c
index 9d732769ba0..8121cc24734 100644
--- a/drivers/char/watchdog/advantechwdt.c
+++ b/drivers/char/watchdog/advantechwdt.c
@@ -35,18 +35,19 @@
#include <linux/watchdog.h>
#include <linux/fs.h>
#include <linux/ioport.h>
-#include <linux/notifier.h>
-#include <linux/reboot.h>
+#include <linux/platform_device.h>
#include <linux/init.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/system.h>
+#define DRV_NAME "advantechwdt"
+#define PFX DRV_NAME ": "
#define WATCHDOG_NAME "Advantech WDT"
-#define PFX WATCHDOG_NAME ": "
#define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */
+static struct platform_device *advwdt_platform_device; /* the watchdog platform device */
static unsigned long advwdt_is_open;
static char adv_expect_close;
@@ -75,10 +76,10 @@ MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1<= timeout <=63, defaul
static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0);
-MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
/*
- * Kernel methods.
+ * Watchdog Operations
*/
static void
@@ -94,6 +95,20 @@ advwdt_disable(void)
inb_p(wdt_stop);
}
+static int
+advwdt_set_heartbeat(int t)
+{
+ if ((t < 1) || (t > 63))
+ return -EINVAL;
+
+ timeout = t;
+ return 0;
+}
+
+/*
+ * /dev/watchdog handling
+ */
+
static ssize_t
advwdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
@@ -126,7 +141,7 @@ advwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
static struct watchdog_info ident = {
.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
.firmware_version = 1,
- .identity = "Advantech WDT",
+ .identity = WATCHDOG_NAME,
};
switch (cmd) {
@@ -146,9 +161,8 @@ advwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
case WDIOC_SETTIMEOUT:
if (get_user(new_timeout, p))
return -EFAULT;
- if ((new_timeout < 1) || (new_timeout > 63))
+ if (advwdt_set_heartbeat(new_timeout))
return -EINVAL;
- timeout = new_timeout;
advwdt_ping();
/* Fall */
@@ -209,21 +223,6 @@ advwdt_close(struct inode *inode, struct file *file)
}
/*
- * Notifier for system down
- */
-
-static int
-advwdt_notify_sys(struct notifier_block *this, unsigned long code,
- void *unused)
-{
- if (code == SYS_DOWN || code == SYS_HALT) {
- /* Turn the WDT off */
- advwdt_disable();
- }
- return NOTIFY_DONE;
-}
-
-/*
* Kernel Interfaces
*/
@@ -237,33 +236,20 @@ static const struct file_operations advwdt_fops = {
};
static struct miscdevice advwdt_miscdev = {
- .minor = WATCHDOG_MINOR,
- .name = "watchdog",
- .fops = &advwdt_fops,
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &advwdt_fops,
};
/*
- * The WDT needs to learn about soft shutdowns in order to
- * turn the timebomb registers off.
+ * Init & exit routines
*/
-static struct notifier_block advwdt_notifier = {
- .notifier_call = advwdt_notify_sys,
-};
-
-static int __init
-advwdt_init(void)
+static int __devinit
+advwdt_probe(struct platform_device *dev)
{
int ret;
- printk(KERN_INFO "WDT driver for Advantech single board computer initialising.\n");
-
- if (timeout < 1 || timeout > 63) {
- timeout = WATCHDOG_TIMEOUT;
- printk (KERN_INFO PFX "timeout value must be 1<=x<=63, using %d\n",
- timeout);
- }
-
if (wdt_stop != wdt_start) {
if (!request_region(wdt_stop, 1, WATCHDOG_NAME)) {
printk (KERN_ERR PFX "I/O address 0x%04x already in use\n",
@@ -280,18 +266,18 @@ advwdt_init(void)
goto unreg_stop;
}
- ret = register_reboot_notifier(&advwdt_notifier);
- if (ret != 0) {
- printk (KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
- ret);
- goto unreg_regions;
+ /* Check that the heartbeat value is within it's range ; if not reset to the default */
+ if (advwdt_set_heartbeat(timeout)) {
+ advwdt_set_heartbeat(WATCHDOG_TIMEOUT);
+ printk (KERN_INFO PFX "timeout value must be 1<=x<=63, using %d\n",
+ timeout);
}
ret = misc_register(&advwdt_miscdev);
if (ret != 0) {
printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret);
- goto unreg_reboot;
+ goto unreg_regions;
}
printk (KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n",
@@ -299,8 +285,6 @@ advwdt_init(void)
out:
return ret;
-unreg_reboot:
- unregister_reboot_notifier(&advwdt_notifier);
unreg_regions:
release_region(wdt_start, 1);
unreg_stop:
@@ -309,14 +293,64 @@ unreg_stop:
goto out;
}
-static void __exit
-advwdt_exit(void)
+static int __devexit
+advwdt_remove(struct platform_device *dev)
{
misc_deregister(&advwdt_miscdev);
- unregister_reboot_notifier(&advwdt_notifier);
+ release_region(wdt_start,1);
if(wdt_stop != wdt_start)
release_region(wdt_stop,1);
- release_region(wdt_start,1);
+
+ return 0;
+}
+
+static void
+advwdt_shutdown(struct platform_device *dev)
+{
+ /* Turn the WDT off if we have a soft shutdown */
+ advwdt_disable();
+}
+
+static struct platform_driver advwdt_driver = {
+ .probe = advwdt_probe,
+ .remove = __devexit_p(advwdt_remove),
+ .shutdown = advwdt_shutdown,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRV_NAME,
+ },
+};
+
+static int __init
+advwdt_init(void)
+{
+ int err;
+
+ printk(KERN_INFO "WDT driver for Advantech single board computer initialising.\n");
+
+ err = platform_driver_register(&advwdt_driver);
+ if (err)
+ return err;
+
+ advwdt_platform_device = platform_device_register_simple(DRV_NAME, -1, NULL, 0);
+ if (IS_ERR(advwdt_platform_device)) {
+ err = PTR_ERR(advwdt_platform_device);
+ goto unreg_platform_driver;
+ }
+
+ return 0;
+
+unreg_platform_driver:
+ platform_driver_unregister(&advwdt_driver);
+ return err;
+}
+
+static void __exit
+advwdt_exit(void)
+{
+ platform_device_unregister(advwdt_platform_device);
+ platform_driver_unregister(&advwdt_driver);
+ printk(KERN_INFO PFX "Watchdog Module Unloaded.\n");
}
module_init(advwdt_init);
diff --git a/drivers/char/watchdog/alim1535_wdt.c b/drivers/char/watchdog/alim1535_wdt.c
index 01b0d132ee4..e3f6a7d0c83 100644
--- a/drivers/char/watchdog/alim1535_wdt.c
+++ b/drivers/char/watchdog/alim1535_wdt.c
@@ -40,7 +40,7 @@ MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (0<timeout<18000, defaul
static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0);
-MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
/*
* ali_start - start watchdog countdown
diff --git a/drivers/char/watchdog/alim7101_wdt.c b/drivers/char/watchdog/alim7101_wdt.c
index bf25d0a55a9..67aed9f8c36 100644
--- a/drivers/char/watchdog/alim7101_wdt.c
+++ b/drivers/char/watchdog/alim7101_wdt.c
@@ -69,7 +69,7 @@ module_param(use_gpio, int, 0);
MODULE_PARM_DESC(use_gpio, "Use the gpio watchdog. (required by old cobalt boards)");
static void wdt_timer_ping(unsigned long);
-static struct timer_list timer;
+static DEFINE_TIMER(timer, wdt_timer_ping, 0, 1);
static unsigned long next_heartbeat;
static unsigned long wdt_is_open;
static char wdt_expect_close;
@@ -78,7 +78,7 @@ static struct pci_dev *alim7101_pmu;
static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
- __stringify(CONFIG_WATCHDOG_NOWAYOUT) ")");
+ __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
/*
* Whack the dog
@@ -108,8 +108,7 @@ static void wdt_timer_ping(unsigned long data)
printk(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n");
}
/* Re-set the timer interval */
- timer.expires = jiffies + WDT_INTERVAL;
- add_timer(&timer);
+ mod_timer(&timer, jiffies + WDT_INTERVAL);
}
/*
@@ -147,9 +146,7 @@ static void wdt_startup(void)
wdt_change(WDT_ENABLE);
/* Start the timer */
- timer.expires = jiffies + WDT_INTERVAL;
- add_timer(&timer);
-
+ mod_timer(&timer, jiffies + WDT_INTERVAL);
printk(KERN_INFO PFX "Watchdog timer is now enabled.\n");
}
@@ -380,10 +377,6 @@ static int __init alim7101_wdt_init(void)
timeout);
}
- init_timer(&timer);
- timer.function = wdt_timer_ping;
- timer.data = 1;
-
rc = misc_register(&wdt_miscdev);
if (rc) {
printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
@@ -417,10 +410,8 @@ module_init(alim7101_wdt_init);
module_exit(alim7101_wdt_unload);
static struct pci_device_id alim7101_pci_tbl[] __devinitdata = {
- { PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533) },
+ { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101) },
{ }
};
diff --git a/drivers/char/watchdog/booke_wdt.c b/drivers/char/watchdog/booke_wdt.c
index 488902231cc..0e23f29f71a 100644
--- a/drivers/char/watchdog/booke_wdt.c
+++ b/drivers/char/watchdog/booke_wdt.c
@@ -35,7 +35,7 @@
#ifdef CONFIG_FSL_BOOKE
#define WDT_PERIOD_DEFAULT 63 /* Ex. wdt_period=28 bus=333Mhz , reset=~40sec */
#else
-#define WDT_PERIOD_DEFAULT 4 /* Refer to the PPC40x and PPC4xx manuals */
+#define WDT_PERIOD_DEFAULT 3 /* Refer to the PPC40x and PPC4xx manuals */
#endif /* for timing information */
u32 booke_wdt_enabled = 0;
@@ -48,12 +48,22 @@ u32 booke_wdt_period = WDT_PERIOD_DEFAULT;
#endif
/*
+ * booke_wdt_ping:
+ */
+static __inline__ void booke_wdt_ping(void)
+{
+ mtspr(SPRN_TSR, TSR_ENW|TSR_WIS);
+}
+
+/*
* booke_wdt_enable:
*/
static __inline__ void booke_wdt_enable(void)
{
u32 val;
+ /* clear status before enabling watchdog */
+ booke_wdt_ping();
val = mfspr(SPRN_TCR);
val |= (TCR_WIE|TCR_WRC(WRC_CHIP)|WDTP(booke_wdt_period));
@@ -61,14 +71,6 @@ static __inline__ void booke_wdt_enable(void)
}
/*
- * booke_wdt_ping:
- */
-static __inline__ void booke_wdt_ping(void)
-{
- mtspr(SPRN_TSR, TSR_ENW|TSR_WIS);
-}
-
-/*
* booke_wdt_write:
*/
static ssize_t booke_wdt_write (struct file *file, const char __user *buf,
diff --git a/drivers/char/watchdog/cpu5wdt.c b/drivers/char/watchdog/cpu5wdt.c
index 00bdabb90f2..bcd7e36ca0a 100644
--- a/drivers/char/watchdog/cpu5wdt.c
+++ b/drivers/char/watchdog/cpu5wdt.c
@@ -80,10 +80,8 @@ static void cpu5wdt_trigger(unsigned long unused)
outb(1, port + CPU5WDT_TRIGGER_REG);
/* requeue?? */
- if( cpu5wdt_device.queue && ticks ) {
- cpu5wdt_device.timer.expires = jiffies + CPU5WDT_INTERVAL;
- add_timer(&cpu5wdt_device.timer);
- }
+ if (cpu5wdt_device.queue && ticks)
+ mod_timer(&cpu5wdt_device.timer, jiffies + CPU5WDT_INTERVAL);
else {
/* ticks doesn't matter anyway */
complete(&cpu5wdt_device.stop);
@@ -109,8 +107,7 @@ static void cpu5wdt_start(void)
outb(1, port + CPU5WDT_MODE_REG);
outb(0, port + CPU5WDT_RESET_REG);
outb(0, port + CPU5WDT_ENABLE_REG);
- cpu5wdt_device.timer.expires = jiffies + CPU5WDT_INTERVAL;
- add_timer(&cpu5wdt_device.timer);
+ mod_timer(&cpu5wdt_device.timer, jiffies + CPU5WDT_INTERVAL);
}
/* if process dies, counter is not decremented */
cpu5wdt_device.running++;
@@ -245,9 +242,7 @@ static int __devinit cpu5wdt_init(void)
clear_bit(0, &cpu5wdt_device.inuse);
- init_timer(&cpu5wdt_device.timer);
- cpu5wdt_device.timer.function = cpu5wdt_trigger;
- cpu5wdt_device.timer.data = 0;
+ setup_timer(&cpu5wdt_device.timer, cpu5wdt_trigger, 0);
cpu5wdt_device.default_ticks = ticks;
diff --git a/drivers/char/watchdog/eurotechwdt.c b/drivers/char/watchdog/eurotechwdt.c
index e228d6e173c..f70387f01b2 100644
--- a/drivers/char/watchdog/eurotechwdt.c
+++ b/drivers/char/watchdog/eurotechwdt.c
@@ -73,7 +73,7 @@ static char *ev = "int";
static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0);
-MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
/*
* Some symbolic names
diff --git a/drivers/char/watchdog/i6300esb.c b/drivers/char/watchdog/i6300esb.c
index fb64df4d7c8..c5982502c03 100644
--- a/drivers/char/watchdog/i6300esb.c
+++ b/drivers/char/watchdog/i6300esb.c
@@ -91,7 +91,7 @@ MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (1<heartbeat<2046, d
static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0);
-MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
/*
* Some i6300ESB specific functions
diff --git a/drivers/char/watchdog/i8xx_tco.c b/drivers/char/watchdog/i8xx_tco.c
index e0627d79707..a62ef48a15a 100644
--- a/drivers/char/watchdog/i8xx_tco.c
+++ b/drivers/char/watchdog/i8xx_tco.c
@@ -109,7 +109,7 @@ MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (2<heartbeat<39, def
static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0);
-MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
/*
* Some TCO specific functions
diff --git a/drivers/char/watchdog/iTCO_wdt.c b/drivers/char/watchdog/iTCO_wdt.c
index 7eac922df86..3c9684ccd2f 100644
--- a/drivers/char/watchdog/iTCO_wdt.c
+++ b/drivers/char/watchdog/iTCO_wdt.c
@@ -1,7 +1,7 @@
/*
* intel TCO Watchdog Driver (Used in i82801 and i6300ESB chipsets)
*
- * (c) Copyright 2006 Wim Van Sebroeck <wim@iguana.be>.
+ * (c) Copyright 2006-2007 Wim Van Sebroeck <wim@iguana.be>.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -49,7 +49,7 @@
/* Module and version information */
#define DRV_NAME "iTCO_wdt"
#define DRV_VERSION "1.01"
-#define DRV_RELDATE "11-Nov-2006"
+#define DRV_RELDATE "21-Jan-2007"
#define PFX DRV_NAME ": "
/* Includes */
@@ -187,7 +187,7 @@ MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (2<heartbeat<39 (TCO
static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0);
-MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
/* iTCO Vendor Specific Support hooks */
#ifdef CONFIG_ITCO_VENDOR_SUPPORT
@@ -539,7 +539,7 @@ static int iTCO_wdt_ioctl (struct inode *inode, struct file *file,
* Kernel Interfaces
*/
-static struct file_operations iTCO_wdt_fops = {
+static const struct file_operations iTCO_wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = iTCO_wdt_write,
diff --git a/drivers/char/watchdog/ib700wdt.c b/drivers/char/watchdog/ib700wdt.c
index c1ed209a138..c3a60f52ccb 100644
--- a/drivers/char/watchdog/ib700wdt.c
+++ b/drivers/char/watchdog/ib700wdt.c
@@ -3,8 +3,8 @@
*
* (c) Copyright 2001 Charles Howes <chowes@vsol.net>
*
- * Based on advantechwdt.c which is based on acquirewdt.c which
- * is based on wdt.c.
+ * Based on advantechwdt.c which is based on acquirewdt.c which
+ * is based on wdt.c.
*
* (c) Copyright 2000-2001 Marek Michalkiewicz <marekm@linux.org.pl>
*
@@ -25,9 +25,9 @@
*
* (c) Copyright 1995 Alan Cox <alan@redhat.com>
*
- * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
- * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
- * Added timeout module option to override default
+ * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
+ * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
+ * Added timeout module option to override default
*
*/
@@ -36,22 +36,24 @@
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
#include <linux/ioport.h>
-#include <linux/notifier.h>
#include <linux/fs.h>
-#include <linux/reboot.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/system.h>
+static struct platform_device *ibwdt_platform_device;
static unsigned long ibwdt_is_open;
static spinlock_t ibwdt_lock;
static char expect_close;
-#define PFX "ib700wdt: "
+/* Module information */
+#define DRV_NAME "ib700wdt"
+#define PFX DRV_NAME ": "
/*
*
@@ -118,20 +120,51 @@ static int wd_margin = WD_TIMO;
static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0);
-MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
/*
- * Kernel methods.
+ * Watchdog Operations
*/
static void
ibwdt_ping(void)
{
+ spin_lock(&ibwdt_lock);
+
/* Write a watchdog value */
outb_p(wd_margin, WDT_START);
+
+ spin_unlock(&ibwdt_lock);
}
+static void
+ibwdt_disable(void)
+{
+ spin_lock(&ibwdt_lock);
+ outb_p(0, WDT_STOP);
+ spin_unlock(&ibwdt_lock);
+}
+
+static int
+ibwdt_set_heartbeat(int t)
+{
+ int i;
+
+ if ((t < 0) || (t > 30))
+ return -EINVAL;
+
+ for (i = 0x0F; i > -1; i--)
+ if (wd_times[i] > t)
+ break;
+ wd_margin = i;
+ return 0;
+}
+
+/*
+ * /dev/watchdog handling
+ */
+
static ssize_t
ibwdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
@@ -159,7 +192,7 @@ static int
ibwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg)
{
- int i, new_margin;
+ int new_margin;
void __user *argp = (void __user *)arg;
int __user *p = argp;
@@ -176,6 +209,7 @@ ibwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
break;
case WDIOC_GETSTATUS:
+ case WDIOC_GETBOOTSTATUS:
return put_user(0, p);
case WDIOC_KEEPALIVE:
@@ -185,18 +219,33 @@ ibwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
case WDIOC_SETTIMEOUT:
if (get_user(new_margin, p))
return -EFAULT;
- if ((new_margin < 0) || (new_margin > 30))
+ if (ibwdt_set_heartbeat(new_margin))
return -EINVAL;
- for (i = 0x0F; i > -1; i--)
- if (wd_times[i] > new_margin)
- break;
- wd_margin = i;
ibwdt_ping();
/* Fall */
case WDIOC_GETTIMEOUT:
return put_user(wd_times[wd_margin], p);
- break;
+
+ case WDIOC_SETOPTIONS:
+ {
+ int options, retval = -EINVAL;
+
+ if (get_user(options, p))
+ return -EFAULT;
+
+ if (options & WDIOS_DISABLECARD) {
+ ibwdt_disable();
+ retval = 0;
+ }
+
+ if (options & WDIOS_ENABLECARD) {
+ ibwdt_ping();
+ retval = 0;
+ }
+
+ return retval;
+ }
default:
return -ENOTTY;
@@ -207,9 +256,7 @@ ibwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
static int
ibwdt_open(struct inode *inode, struct file *file)
{
- spin_lock(&ibwdt_lock);
if (test_and_set_bit(0, &ibwdt_is_open)) {
- spin_unlock(&ibwdt_lock);
return -EBUSY;
}
if (nowayout)
@@ -217,41 +264,24 @@ ibwdt_open(struct inode *inode, struct file *file)
/* Activate */
ibwdt_ping();
- spin_unlock(&ibwdt_lock);
return nonseekable_open(inode, file);
}
static int
ibwdt_close(struct inode *inode, struct file *file)
{
- spin_lock(&ibwdt_lock);
- if (expect_close == 42)
- outb_p(0, WDT_STOP);
- else
+ if (expect_close == 42) {
+ ibwdt_disable();
+ } else {
printk(KERN_CRIT PFX "WDT device closed unexpectedly. WDT will not stop!\n");
-
+ ibwdt_ping();
+ }
clear_bit(0, &ibwdt_is_open);
expect_close = 0;
- spin_unlock(&ibwdt_lock);
return 0;
}
/*
- * Notifier for system down
- */
-
-static int
-ibwdt_notify_sys(struct notifier_block *this, unsigned long code,
- void *unused)
-{
- if (code == SYS_DOWN || code == SYS_HALT) {
- /* Turn the WDT off */
- outb_p(0, WDT_STOP);
- }
- return NOTIFY_DONE;
-}
-
-/*
* Kernel Interfaces
*/
@@ -271,26 +301,14 @@ static struct miscdevice ibwdt_miscdev = {
};
/*
- * The WDT needs to learn about soft shutdowns in order to
- * turn the timebomb registers off.
+ * Init & exit routines
*/
-static struct notifier_block ibwdt_notifier = {
- .notifier_call = ibwdt_notify_sys,
-};
-
-static int __init ibwdt_init(void)
+static int __devinit ibwdt_probe(struct platform_device *dev)
{
int res;
- printk(KERN_INFO PFX "WDT driver for IB700 single board computer initialising.\n");
-
spin_lock_init(&ibwdt_lock);
- res = misc_register(&ibwdt_miscdev);
- if (res) {
- printk (KERN_ERR PFX "failed to register misc device\n");
- goto out_nomisc;
- }
#if WDT_START != WDT_STOP
if (!request_region(WDT_STOP, 1, "IB700 WDT")) {
@@ -305,34 +323,78 @@ static int __init ibwdt_init(void)
res = -EIO;
goto out_nostartreg;
}
- res = register_reboot_notifier(&ibwdt_notifier);
+
+ res = misc_register(&ibwdt_miscdev);
if (res) {
- printk (KERN_ERR PFX "Failed to register reboot notifier.\n");
- goto out_noreboot;
+ printk (KERN_ERR PFX "failed to register misc device\n");
+ goto out_nomisc;
}
return 0;
-out_noreboot:
+out_nomisc:
release_region(WDT_START, 1);
out_nostartreg:
#if WDT_START != WDT_STOP
release_region(WDT_STOP, 1);
#endif
out_nostopreg:
- misc_deregister(&ibwdt_miscdev);
-out_nomisc:
return res;
}
-static void __exit
-ibwdt_exit(void)
+static int __devexit ibwdt_remove(struct platform_device *dev)
{
misc_deregister(&ibwdt_miscdev);
- unregister_reboot_notifier(&ibwdt_notifier);
+ release_region(WDT_START,1);
#if WDT_START != WDT_STOP
release_region(WDT_STOP,1);
#endif
- release_region(WDT_START,1);
+ return 0;
+}
+
+static void ibwdt_shutdown(struct platform_device *dev)
+{
+ /* Turn the WDT off if we have a soft shutdown */
+ ibwdt_disable();
+}
+
+static struct platform_driver ibwdt_driver = {
+ .probe = ibwdt_probe,
+ .remove = __devexit_p(ibwdt_remove),
+ .shutdown = ibwdt_shutdown,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRV_NAME,
+ },
+};
+
+static int __init ibwdt_init(void)
+{
+ int err;
+
+ printk(KERN_INFO PFX "WDT driver for IB700 single board computer initialising.\n");
+
+ err = platform_driver_register(&ibwdt_driver);
+ if (err)
+ return err;
+
+ ibwdt_platform_device = platform_device_register_simple(DRV_NAME, -1, NULL, 0);
+ if (IS_ERR(ibwdt_platform_device)) {
+ err = PTR_ERR(ibwdt_platform_device);
+ goto unreg_platform_driver;
+ }
+
+ return 0;
+
+unreg_platform_driver:
+ platform_driver_unregister(&ibwdt_driver);
+ return err;
+}
+
+static void __exit ibwdt_exit(void)
+{
+ platform_device_unregister(ibwdt_platform_device);
+ platform_driver_unregister(&ibwdt_driver);
+ printk(KERN_INFO PFX "Watchdog Module Unloaded.\n");
}
module_init(ibwdt_init);
diff --git a/drivers/char/watchdog/ibmasr.c b/drivers/char/watchdog/ibmasr.c
index dd6760f1a23..8195f5023d8 100644
--- a/drivers/char/watchdog/ibmasr.c
+++ b/drivers/char/watchdog/ibmasr.c
@@ -396,7 +396,7 @@ module_init(ibmasr_init);
module_exit(ibmasr_exit);
module_param(nowayout, int, 0);
-MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
MODULE_DESCRIPTION("IBM Automatic Server Restart driver");
MODULE_AUTHOR("Andrey Panin");
diff --git a/drivers/char/watchdog/indydog.c b/drivers/char/watchdog/indydog.c
index 0bc23930898..788245bdaa7 100644
--- a/drivers/char/watchdog/indydog.c
+++ b/drivers/char/watchdog/indydog.c
@@ -32,7 +32,7 @@ static int indydog_alive;
static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0);
-MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
static void indydog_start(void)
{
diff --git a/drivers/char/watchdog/machzwd.c b/drivers/char/watchdog/machzwd.c
index 276577d08fb..4a328ba0d26 100644
--- a/drivers/char/watchdog/machzwd.c
+++ b/drivers/char/watchdog/machzwd.c
@@ -95,7 +95,7 @@ MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0);
-MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
#define PFX "machzwd"
@@ -118,12 +118,14 @@ static int action = 0;
module_param(action, int, 0);
MODULE_PARM_DESC(action, "after watchdog resets, generate: 0 = RESET(*) 1 = SMI 2 = NMI 3 = SCI");
+static void zf_ping(unsigned long data);
+
static int zf_action = GEN_RESET;
static unsigned long zf_is_open;
static char zf_expect_close;
static spinlock_t zf_lock;
static spinlock_t zf_port_lock;
-static struct timer_list zf_timer;
+static DEFINE_TIMER(zf_timer, zf_ping, 0, 0);
static unsigned long next_heartbeat = 0;
@@ -220,9 +222,7 @@ static void zf_timer_on(void)
next_heartbeat = jiffies + ZF_USER_TIMEO;
/* start the timer for internal ping */
- zf_timer.expires = jiffies + ZF_HW_TIMEO;
-
- add_timer(&zf_timer);
+ mod_timer(&zf_timer, jiffies + ZF_HW_TIMEO);
/* start watchdog timer */
ctrl_reg = zf_get_control();
@@ -260,8 +260,7 @@ static void zf_ping(unsigned long data)
zf_set_control(ctrl_reg);
spin_unlock_irqrestore(&zf_port_lock, flags);
- zf_timer.expires = jiffies + ZF_HW_TIMEO;
- add_timer(&zf_timer);
+ mod_timer(&zf_timer, jiffies + ZF_HW_TIMEO);
}else{
printk(KERN_CRIT PFX ": I will reset your machine\n");
}
@@ -465,11 +464,6 @@ static int __init zf_init(void)
zf_set_status(0);
zf_set_control(0);
- /* this is the timer that will do the hard work */
- init_timer(&zf_timer);
- zf_timer.function = zf_ping;
- zf_timer.data = 0;
-
return 0;
no_reboot:
diff --git a/drivers/char/watchdog/mixcomwd.c b/drivers/char/watchdog/mixcomwd.c
index c2dac0aa1d6..f35e2848aa3 100644
--- a/drivers/char/watchdog/mixcomwd.c
+++ b/drivers/char/watchdog/mixcomwd.c
@@ -56,16 +56,18 @@ static int mixcomwd_ioports[] = { 0x180, 0x280, 0x380, 0x000 };
#define FLASHCOM_WATCHDOG_OFFSET 0x4
#define FLASHCOM_ID 0x18
+static void mixcomwd_timerfun(unsigned long d);
+
static unsigned long mixcomwd_opened; /* long req'd for setbit --RR */
static int watchdog_port;
static int mixcomwd_timer_alive;
-static DEFINE_TIMER(mixcomwd_timer, NULL, 0, 0);
+static DEFINE_TIMER(mixcomwd_timer, mixcomwd_timerfun, 0, 0);
static char expect_close;
static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0);
-MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
static void mixcomwd_ping(void)
{
@@ -77,7 +79,7 @@ static void mixcomwd_timerfun(unsigned long d)
{
mixcomwd_ping();
- mod_timer(&mixcomwd_timer,jiffies+ 5*HZ);
+ mod_timer(&mixcomwd_timer, jiffies + 5 * HZ);
}
/*
@@ -114,12 +116,8 @@ static int mixcomwd_release(struct inode *inode, struct file *file)
printk(KERN_ERR "mixcomwd: release called while internal timer alive");
return -EBUSY;
}
- init_timer(&mixcomwd_timer);
- mixcomwd_timer.expires=jiffies + 5 * HZ;
- mixcomwd_timer.function=mixcomwd_timerfun;
- mixcomwd_timer.data=0;
mixcomwd_timer_alive=1;
- add_timer(&mixcomwd_timer);
+ mod_timer(&mixcomwd_timer, jiffies + 5 * HZ);
} else {
printk(KERN_CRIT "mixcomwd: WDT device closed unexpectedly. WDT will not stop!\n");
}
@@ -285,7 +283,7 @@ static void __exit mixcomwd_exit(void)
if(mixcomwd_timer_alive) {
printk(KERN_WARNING "mixcomwd: I quit now, hardware will"
" probably reboot!\n");
- del_timer(&mixcomwd_timer);
+ del_timer_sync(&mixcomwd_timer);
mixcomwd_timer_alive=0;
}
}
diff --git a/drivers/char/watchdog/omap_wdt.c b/drivers/char/watchdog/omap_wdt.c
index 6c6f97332db..84074a697dc 100644
--- a/drivers/char/watchdog/omap_wdt.c
+++ b/drivers/char/watchdog/omap_wdt.c
@@ -230,7 +230,7 @@ omap_wdt_ioctl(struct inode *inode, struct file *file,
}
}
-static struct file_operations omap_wdt_fops = {
+static const struct file_operations omap_wdt_fops = {
.owner = THIS_MODULE,
.write = omap_wdt_write,
.ioctl = omap_wdt_ioctl,
diff --git a/drivers/char/watchdog/pc87413_wdt.c b/drivers/char/watchdog/pc87413_wdt.c
index 1d447e32af4..3d3deae0d64 100644
--- a/drivers/char/watchdog/pc87413_wdt.c
+++ b/drivers/char/watchdog/pc87413_wdt.c
@@ -526,7 +526,7 @@ static int pc87413_notify_sys(struct notifier_block *this,
/* -- Module's structures ---------------------------------------*/
-static struct file_operations pc87413_fops = {
+static const struct file_operations pc87413_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = pc87413_write,
@@ -631,5 +631,5 @@ module_param(timeout, int, 0);
MODULE_PARM_DESC(timeout, "Watchdog timeout in minutes (default=" __MODULE_STRING(timeout) ").");
module_param(nowayout, int, 0);
-MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
diff --git a/drivers/char/watchdog/pcwd.c b/drivers/char/watchdog/pcwd.c
index 8e1e6e48e0a..6e8b5705b5b 100644
--- a/drivers/char/watchdog/pcwd.c
+++ b/drivers/char/watchdog/pcwd.c
@@ -2,7 +2,7 @@
* PC Watchdog Driver
* by Ken Hollis (khollis@bitgate.com)
*
- * Permission granted from Simon Machell (73244.1270@compuserve.com)
+ * Permission granted from Simon Machell (smachell@berkprod.com)
* Written for the Linux Kernel, and GPLed by Ken Hollis
*
* 960107 Added request_region routines, modulized the whole thing.
@@ -70,8 +70,8 @@
#include <asm/io.h> /* For inb/outb/... */
/* Module and version information */
-#define WATCHDOG_VERSION "1.17"
-#define WATCHDOG_DATE "12 Feb 2006"
+#define WATCHDOG_VERSION "1.18"
+#define WATCHDOG_DATE "21 Jan 2007"
#define WATCHDOG_DRIVER_NAME "ISA-PC Watchdog"
#define WATCHDOG_NAME "pcwd"
#define PFX WATCHDOG_NAME ": "
@@ -132,6 +132,18 @@
#define CMD_ISA_DELAY_TIME_8SECS 0x0C
#define CMD_ISA_RESET_RELAYS 0x0D
+/* Watchdog's Dip Switch heartbeat values */
+static const int heartbeat_tbl [] = {
+ 20, /* OFF-OFF-OFF = 20 Sec */
+ 40, /* OFF-OFF-ON = 40 Sec */
+ 60, /* OFF-ON-OFF = 1 Min */
+ 300, /* OFF-ON-ON = 5 Min */
+ 600, /* ON-OFF-OFF = 10 Min */
+ 1800, /* ON-OFF-ON = 30 Min */
+ 3600, /* ON-ON-OFF = 1 Hour */
+ 7200, /* ON-ON-ON = 2 hour */
+};
+
/*
* We are using an kernel timer to do the pinging of the watchdog
* every ~500ms. We try to set the internal heartbeat of the
@@ -167,14 +179,14 @@ static int debug = QUIET;
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "Debug level: 0=Quiet, 1=Verbose, 2=Debug (default=0)");
-#define WATCHDOG_HEARTBEAT 60 /* 60 sec default heartbeat */
+#define WATCHDOG_HEARTBEAT 0 /* default heartbeat = delay-time from dip-switches */
static int heartbeat = WATCHDOG_HEARTBEAT;
module_param(heartbeat, int, 0);
-MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (2<=heartbeat<=7200, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (2<=heartbeat<=7200 or 0=delay-time from dip-switches, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0);
-MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
/*
* Internal functions
@@ -831,9 +843,7 @@ static int __devinit pcwatchdog_init(int base_addr)
/* clear the "card caused reboot" flag */
pcwd_clear_status();
- init_timer(&pcwd_private.timer);
- pcwd_private.timer.function = pcwd_timer_ping;
- pcwd_private.timer.data = 0;
+ setup_timer(&pcwd_private.timer, pcwd_timer_ping, 0);
/* Disable the board */
pcwd_stop();
@@ -844,6 +854,10 @@ static int __devinit pcwatchdog_init(int base_addr)
/* Show info about the card itself */
pcwd_show_card_info();
+ /* If heartbeat = 0 then we use the heartbeat from the dip-switches */
+ if (heartbeat == 0)
+ heartbeat = heartbeat_tbl[(pcwd_get_option_switches() & 0x07)];
+
/* Check that the heartbeat value is within it's range ; if not reset to the default */
if (pcwd_set_heartbeat(heartbeat)) {
pcwd_set_heartbeat(WATCHDOG_HEARTBEAT);
diff --git a/drivers/char/watchdog/pcwd_pci.c b/drivers/char/watchdog/pcwd_pci.c
index f4872c87106..61a89e95964 100644
--- a/drivers/char/watchdog/pcwd_pci.c
+++ b/drivers/char/watchdog/pcwd_pci.c
@@ -1,7 +1,7 @@
/*
* Berkshire PCI-PC Watchdog Card Driver
*
- * (c) Copyright 2003-2005 Wim Van Sebroeck <wim@iguana.be>.
+ * (c) Copyright 2003-2007 Wim Van Sebroeck <wim@iguana.be>.
*
* Based on source code of the following authors:
* Ken Hollis <kenji@bitgate.com>,
@@ -51,8 +51,8 @@
#include <asm/io.h> /* For inb/outb/... */
/* Module and version information */
-#define WATCHDOG_VERSION "1.02"
-#define WATCHDOG_DATE "03 Sep 2005"
+#define WATCHDOG_VERSION "1.03"
+#define WATCHDOG_DATE "21 Jan 2007"
#define WATCHDOG_DRIVER_NAME "PCI-PC Watchdog"
#define WATCHDOG_NAME "pcwd_pci"
#define PFX WATCHDOG_NAME ": "
@@ -96,6 +96,18 @@
#define CMD_WRITE_WATCHDOG_TIMEOUT 0x19
#define CMD_GET_CLEAR_RESET_COUNT 0x84
+/* Watchdog's Dip Switch heartbeat values */
+static const int heartbeat_tbl [] = {
+ 5, /* OFF-OFF-OFF = 5 Sec */
+ 10, /* OFF-OFF-ON = 10 Sec */
+ 30, /* OFF-ON-OFF = 30 Sec */
+ 60, /* OFF-ON-ON = 1 Min */
+ 300, /* ON-OFF-OFF = 5 Min */
+ 600, /* ON-OFF-ON = 10 Min */
+ 1800, /* ON-ON-OFF = 30 Min */
+ 3600, /* ON-ON-ON = 1 hour */
+};
+
/* We can only use 1 card due to the /dev/watchdog restriction */
static int cards_found;
@@ -119,14 +131,14 @@ static int debug = QUIET;
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "Debug level: 0=Quiet, 1=Verbose, 2=Debug (default=0)");
-#define WATCHDOG_HEARTBEAT 2 /* 2 sec default heartbeat */
+#define WATCHDOG_HEARTBEAT 0 /* default heartbeat = delay-time from dip-switches */
static int heartbeat = WATCHDOG_HEARTBEAT;
module_param(heartbeat, int, 0);
-MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (0<heartbeat<65536, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (0<heartbeat<65536 or 0=delay-time from dip-switches, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0);
-MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
/*
* Internal functions
@@ -286,7 +298,9 @@ static int pcipcwd_stop(void)
static int pcipcwd_keepalive(void)
{
/* Re-trigger watchdog by writing to port 0 */
+ spin_lock(&pcipcwd_private.io_lock);
outb_p(0x42, pcipcwd_private.io_addr); /* send out any data */
+ spin_unlock(&pcipcwd_private.io_lock);
if (debug >= DEBUG)
printk(KERN_DEBUG PFX "Watchdog keepalive signal send\n");
@@ -373,7 +387,9 @@ static int pcipcwd_get_temperature(int *temperature)
if (!pcipcwd_private.supports_temp)
return -ENODEV;
+ spin_lock(&pcipcwd_private.io_lock);
*temperature = inb_p(pcipcwd_private.io_addr);
+ spin_unlock(&pcipcwd_private.io_lock);
/*
* Convert celsius to fahrenheit, since this was
@@ -711,6 +727,10 @@ static int __devinit pcipcwd_card_init(struct pci_dev *pdev,
/* Show info about the card itself */
pcipcwd_show_card_info();
+ /* If heartbeat = 0 then we use the heartbeat from the dip-switches */
+ if (heartbeat == 0)
+ heartbeat = heartbeat_tbl[(pcipcwd_get_option_switches() & 0x07)];
+
/* Check that the heartbeat value is within it's range ; if not reset to the default */
if (pcipcwd_set_heartbeat(heartbeat)) {
pcipcwd_set_heartbeat(WATCHDOG_HEARTBEAT);
@@ -798,6 +818,8 @@ static int __init pcipcwd_init_module(void)
static void __exit pcipcwd_cleanup_module(void)
{
pci_unregister_driver(&pcipcwd_driver);
+
+ printk(KERN_INFO PFX "Watchdog Module Unloaded.\n");
}
module_init(pcipcwd_init_module);
diff --git a/drivers/char/watchdog/pcwd_usb.c b/drivers/char/watchdog/pcwd_usb.c
index 2da5ac99687..31037f9c9ff 100644
--- a/drivers/char/watchdog/pcwd_usb.c
+++ b/drivers/char/watchdog/pcwd_usb.c
@@ -1,7 +1,7 @@
/*
* Berkshire USB-PC Watchdog Card Driver
*
- * (c) Copyright 2004 Wim Van Sebroeck <wim@iguana.be>.
+ * (c) Copyright 2004-2007 Wim Van Sebroeck <wim@iguana.be>.
*
* Based on source code of the following authors:
* Ken Hollis <kenji@bitgate.com>,
@@ -24,26 +24,25 @@
* http://www.berkprod.com/ or http://www.pcwatchdog.com/
*/
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/types.h>
-#include <linux/delay.h>
-#include <linux/miscdevice.h>
-#include <linux/watchdog.h>
-#include <linux/notifier.h>
-#include <linux/reboot.h>
-#include <linux/fs.h>
-#include <linux/smp_lock.h>
-#include <linux/completion.h>
-#include <asm/uaccess.h>
-#include <linux/usb.h>
-#include <linux/mutex.h>
+#include <linux/module.h> /* For module specific items */
+#include <linux/moduleparam.h> /* For new moduleparam's */
+#include <linux/types.h> /* For standard types (like size_t) */
+#include <linux/errno.h> /* For the -ENODEV/... values */
+#include <linux/kernel.h> /* For printk/panic/... */
+#include <linux/delay.h> /* For mdelay function */
+#include <linux/miscdevice.h> /* For MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR) */
+#include <linux/watchdog.h> /* For the watchdog specific items */
+#include <linux/notifier.h> /* For notifier support */
+#include <linux/reboot.h> /* For reboot_notifier stuff */
+#include <linux/init.h> /* For __init/__exit/... */
+#include <linux/fs.h> /* For file operations */
+#include <linux/usb.h> /* For USB functions */
+#include <linux/slab.h> /* For kmalloc, ... */
+#include <linux/mutex.h> /* For mutex locking */
#include <linux/hid.h> /* For HID_REQ_SET_REPORT & HID_DT_REPORT */
+#include <asm/uaccess.h> /* For copy_to_user/put_user/... */
+
#ifdef CONFIG_USB_DEBUG
static int debug = 1;
@@ -57,8 +56,8 @@
/* Module and Version Information */
-#define DRIVER_VERSION "1.01"
-#define DRIVER_DATE "15 Mar 2005"
+#define DRIVER_VERSION "1.02"
+#define DRIVER_DATE "21 Jan 2007"
#define DRIVER_AUTHOR "Wim Van Sebroeck <wim@iguana.be>"
#define DRIVER_DESC "Berkshire USB-PC Watchdog driver"
#define DRIVER_LICENSE "GPL"
@@ -75,14 +74,14 @@ MODULE_ALIAS_MISCDEV(TEMP_MINOR);
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "Debug enabled or not");
-#define WATCHDOG_HEARTBEAT 2 /* 2 sec default heartbeat */
+#define WATCHDOG_HEARTBEAT 0 /* default heartbeat = delay-time from dip-switches */
static int heartbeat = WATCHDOG_HEARTBEAT;
module_param(heartbeat, int, 0);
-MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (0<heartbeat<65536, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (0<heartbeat<65536 or 0=delay-time from dip-switches, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0);
-MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
/* The vendor and product id's for the USB-PC Watchdog card */
#define USB_PCWD_VENDOR_ID 0x0c98
@@ -110,6 +109,18 @@ MODULE_DEVICE_TABLE (usb, usb_pcwd_table);
#define CMD_ENABLE_WATCHDOG 0x30 /* Enable / Disable Watchdog */
#define CMD_DISABLE_WATCHDOG CMD_ENABLE_WATCHDOG
+/* Watchdog's Dip Switch heartbeat values */
+static const int heartbeat_tbl [] = {
+ 5, /* OFF-OFF-OFF = 5 Sec */
+ 10, /* OFF-OFF-ON = 10 Sec */
+ 30, /* OFF-ON-OFF = 30 Sec */
+ 60, /* OFF-ON-ON = 1 Min */
+ 300, /* ON-OFF-OFF = 5 Min */
+ 600, /* ON-OFF-ON = 10 Min */
+ 1800, /* ON-ON-OFF = 30 Min */
+ 3600, /* ON-ON-ON = 1 hour */
+};
+
/* We can only use 1 card due to the /dev/watchdog restriction */
static int cards_found;
@@ -682,6 +693,10 @@ static int usb_pcwd_probe(struct usb_interface *interface, const struct usb_devi
((option_switches & 0x10) ? "ON" : "OFF"),
((option_switches & 0x08) ? "ON" : "OFF"));
+ /* If heartbeat = 0 then we use the heartbeat from the dip-switches */
+ if (heartbeat == 0)
+ heartbeat = heartbeat_tbl[(option_switches & 0x07)];
+
/* Check that the heartbeat value is within it's range ; if not reset to the default */
if (usb_pcwd_set_heartbeat(usb_pcwd, heartbeat)) {
usb_pcwd_set_heartbeat(usb_pcwd, WATCHDOG_HEARTBEAT);
diff --git a/drivers/char/watchdog/pnx4008_wdt.c b/drivers/char/watchdog/pnx4008_wdt.c
index 3a55fc6abcd..5991add702b 100644
--- a/drivers/char/watchdog/pnx4008_wdt.c
+++ b/drivers/char/watchdog/pnx4008_wdt.c
@@ -238,7 +238,7 @@ static int pnx4008_wdt_release(struct inode *inode, struct file *file)
return 0;
}
-static struct file_operations pnx4008_wdt_fops = {
+static const struct file_operations pnx4008_wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = pnx4008_wdt_write,
@@ -283,7 +283,8 @@ static int pnx4008_wdt_probe(struct platform_device *pdev)
wdt_base = (void __iomem *)IO_ADDRESS(res->start);
wdt_clk = clk_get(&pdev->dev, "wdt_ck");
- if (!wdt_clk) {
+ if (IS_ERR(wdt_clk)) {
+ ret = PTR_ERR(wdt_clk);
release_resource(wdt_mem);
kfree(wdt_mem);
goto out;
diff --git a/drivers/char/watchdog/rm9k_wdt.c b/drivers/char/watchdog/rm9k_wdt.c
index 7576a13e86b..5c921e47156 100644
--- a/drivers/char/watchdog/rm9k_wdt.c
+++ b/drivers/char/watchdog/rm9k_wdt.c
@@ -95,7 +95,7 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be disabled once started");
/* Kernel interfaces */
-static struct file_operations fops = {
+static const struct file_operations fops = {
.owner = THIS_MODULE,
.open = wdt_gpi_open,
.release = wdt_gpi_release,
@@ -192,7 +192,7 @@ static int wdt_gpi_open(struct inode *inode, struct file *file)
locked = 0;
}
- res = request_irq(wd_irq, wdt_gpi_irqhdl, SA_SHIRQ | SA_INTERRUPT,
+ res = request_irq(wd_irq, wdt_gpi_irqhdl, IRQF_SHARED | IRQF_DISABLED,
wdt_gpi_name, &miscdev);
if (unlikely(res))
return res;
diff --git a/drivers/char/watchdog/s3c2410_wdt.c b/drivers/char/watchdog/s3c2410_wdt.c
index 18cb050c386..dff6cb5dc9a 100644
--- a/drivers/char/watchdog/s3c2410_wdt.c
+++ b/drivers/char/watchdog/s3c2410_wdt.c
@@ -78,7 +78,7 @@ MODULE_PARM_DESC(tmr_margin, "Watchdog tmr_margin in seconds. default=" __MODULE
MODULE_PARM_DESC(tmr_atboot, "Watchdog is started at boot time if set to 1, default=" __MODULE_STRING(CONFIG_S3C2410_WATCHDOG_ATBOOT));
-MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
MODULE_PARM_DESC(soft_noboot, "Watchdog action, set to 1 to ignore reboots, 0 to reboot (default depends on ONLY_TESTING)");
@@ -366,13 +366,15 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
wdt_mem = request_mem_region(res->start, size, pdev->name);
if (wdt_mem == NULL) {
printk(KERN_INFO PFX "failed to get memory region\n");
- return -ENOENT;
+ ret = -ENOENT;
+ goto err_req;
}
wdt_base = ioremap(res->start, size);
if (wdt_base == 0) {
printk(KERN_INFO PFX "failed to ioremap() region\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto err_req;
}
DBG("probe: mapped wdt_base=%p\n", wdt_base);
@@ -380,22 +382,21 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (res == NULL) {
printk(KERN_INFO PFX "failed to get irq resource\n");
- iounmap(wdt_base);
- return -ENOENT;
+ ret = -ENOENT;
+ goto err_map;
}
ret = request_irq(res->start, s3c2410wdt_irq, 0, pdev->name, pdev);
if (ret != 0) {
printk(KERN_INFO PFX "failed to install irq (%d)\n", ret);
- iounmap(wdt_base);
- return ret;
+ goto err_map;
}
wdt_clock = clk_get(&pdev->dev, "watchdog");
- if (wdt_clock == NULL) {
+ if (IS_ERR(wdt_clock)) {
printk(KERN_INFO PFX "failed to find watchdog clock source\n");
- iounmap(wdt_base);
- return -ENOENT;
+ ret = PTR_ERR(wdt_clock);
+ goto err_irq;
}
clk_enable(wdt_clock);
@@ -418,8 +419,7 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
if (ret) {
printk (KERN_ERR PFX "cannot register miscdev on minor=%d (%d)\n",
WATCHDOG_MINOR, ret);
- iounmap(wdt_base);
- return ret;
+ goto err_clk;
}
if (tmr_atboot && started == 0) {
@@ -434,26 +434,36 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
}
return 0;
+
+ err_clk:
+ clk_disable(wdt_clock);
+ clk_put(wdt_clock);
+
+ err_irq:
+ free_irq(wdt_irq->start, pdev);
+
+ err_map:
+ iounmap(wdt_base);
+
+ err_req:
+ release_resource(wdt_mem);
+ kfree(wdt_mem);
+
+ return ret;
}
static int s3c2410wdt_remove(struct platform_device *dev)
{
- if (wdt_mem != NULL) {
- release_resource(wdt_mem);
- kfree(wdt_mem);
- wdt_mem = NULL;
- }
+ release_resource(wdt_mem);
+ kfree(wdt_mem);
+ wdt_mem = NULL;
- if (wdt_irq != NULL) {
- free_irq(wdt_irq->start, dev);
- wdt_irq = NULL;
- }
+ free_irq(wdt_irq->start, dev);
+ wdt_irq = NULL;
- if (wdt_clock != NULL) {
- clk_disable(wdt_clock);
- clk_put(wdt_clock);
- wdt_clock = NULL;
- }
+ clk_disable(wdt_clock);
+ clk_put(wdt_clock);
+ wdt_clock = NULL;
iounmap(wdt_base);
misc_deregister(&s3c2410wdt_miscdev);
diff --git a/drivers/char/watchdog/sbc60xxwdt.c b/drivers/char/watchdog/sbc60xxwdt.c
index c7b2045bc76..b6282039198 100644
--- a/drivers/char/watchdog/sbc60xxwdt.c
+++ b/drivers/char/watchdog/sbc60xxwdt.c
@@ -100,10 +100,10 @@ MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (1<=timeout<=3600, defau
static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0);
-MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
static void wdt_timer_ping(unsigned long);
-static struct timer_list timer;
+static DEFINE_TIMER(timer, wdt_timer_ping, 0, 0);
static unsigned long next_heartbeat;
static unsigned long wdt_is_open;
static char wdt_expect_close;
@@ -122,8 +122,7 @@ static void wdt_timer_ping(unsigned long data)
/* Ping the WDT by reading from wdt_start */
inb_p(wdt_start);
/* Re-set the timer interval */
- timer.expires = jiffies + WDT_INTERVAL;
- add_timer(&timer);
+ mod_timer(&timer, jiffies + WDT_INTERVAL);
} else {
printk(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n");
}
@@ -138,8 +137,7 @@ static void wdt_startup(void)
next_heartbeat = jiffies + (timeout * HZ);
/* Start the timer */
- timer.expires = jiffies + WDT_INTERVAL;
- add_timer(&timer);
+ mod_timer(&timer, jiffies + WDT_INTERVAL);
printk(KERN_INFO PFX "Watchdog timer is now enabled.\n");
}
@@ -363,10 +361,6 @@ static int __init sbc60xxwdt_init(void)
}
}
- init_timer(&timer);
- timer.function = wdt_timer_ping;
- timer.data = 0;
-
rc = misc_register(&wdt_miscdev);
if (rc)
{
diff --git a/drivers/char/watchdog/sbc8360.c b/drivers/char/watchdog/sbc8360.c
index 41fc6f80c49..67ae42685e7 100644
--- a/drivers/char/watchdog/sbc8360.c
+++ b/drivers/char/watchdog/sbc8360.c
@@ -204,7 +204,7 @@ module_param(timeout, int, 0);
MODULE_PARM_DESC(timeout, "Index into timeout table (0-63) (default=27 (60s))");
module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout,
- "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+ "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
/*
* Kernel methods.
diff --git a/drivers/char/watchdog/sbc_epx_c3.c b/drivers/char/watchdog/sbc_epx_c3.c
index 8882b427d24..82cbd8809a6 100644
--- a/drivers/char/watchdog/sbc_epx_c3.c
+++ b/drivers/char/watchdog/sbc_epx_c3.c
@@ -35,7 +35,7 @@ static int epx_c3_alive;
static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0);
-MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
#define EPXC3_WATCHDOG_CTL_REG 0x1ee /* write 1 to enable, 0 to disable */
#define EPXC3_WATCHDOG_PET_REG 0x1ef /* write anything to pet once enabled */
diff --git a/drivers/char/watchdog/sc1200wdt.c b/drivers/char/watchdog/sc1200wdt.c
index e3239833e4b..1e4a8d751a7 100644
--- a/drivers/char/watchdog/sc1200wdt.c
+++ b/drivers/char/watchdog/sc1200wdt.c
@@ -92,7 +92,7 @@ MODULE_PARM_DESC(timeout, "range is 0-255 minutes, default is 1");
static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0);
-MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
diff --git a/drivers/char/watchdog/sc520_wdt.c b/drivers/char/watchdog/sc520_wdt.c
index caec37ba750..2676a43895a 100644
--- a/drivers/char/watchdog/sc520_wdt.c
+++ b/drivers/char/watchdog/sc520_wdt.c
@@ -97,7 +97,7 @@ MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (1<=timeout<=3600, defau
static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0);
-MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
/*
* AMD Elan SC520 - Watchdog Timer Registers
@@ -121,7 +121,7 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CON
static __u16 __iomem *wdtmrctl;
static void wdt_timer_ping(unsigned long);
-static struct timer_list timer;
+static DEFINE_TIMER(timer, wdt_timer_ping, 0, 0);
static unsigned long next_heartbeat;
static unsigned long wdt_is_open;
static char wdt_expect_close;
@@ -145,8 +145,7 @@ static void wdt_timer_ping(unsigned long data)
spin_unlock(&wdt_spinlock);
/* Re-set the timer interval */
- timer.expires = jiffies + WDT_INTERVAL;
- add_timer(&timer);
+ mod_timer(&timer, jiffies + WDT_INTERVAL);
} else {
printk(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n");
}
@@ -179,8 +178,7 @@ static int wdt_startup(void)
next_heartbeat = jiffies + (timeout * HZ);
/* Start the timer */
- timer.expires = jiffies + WDT_INTERVAL;
- add_timer(&timer);
+ mod_timer(&timer, jiffies + WDT_INTERVAL);
/* Start the watchdog */
wdt_config(WDT_ENB | WDT_WRST_ENB | WDT_EXP_SEL_04);
@@ -389,10 +387,6 @@ static int __init sc520_wdt_init(void)
spin_lock_init(&wdt_spinlock);
- init_timer(&timer);
- timer.function = wdt_timer_ping;
- timer.data = 0;
-
/* Check that the timeout value is within it's range ; if not reset to the default */
if (wdt_set_heartbeat(timeout)) {
wdt_set_heartbeat(WATCHDOG_TIMEOUT);
diff --git a/drivers/char/watchdog/shwdt.c b/drivers/char/watchdog/shwdt.c
index dc403629aeb..cecbedd473a 100644
--- a/drivers/char/watchdog/shwdt.c
+++ b/drivers/char/watchdog/shwdt.c
@@ -65,10 +65,12 @@ static int clock_division_ratio = WTCSR_CKS_4096;
#define next_ping_period(cks) msecs_to_jiffies(cks - 4)
+static void sh_wdt_ping(unsigned long data);
+
static unsigned long shwdt_is_open;
static struct watchdog_info sh_wdt_info;
static char shwdt_expect_close;
-static struct timer_list timer;
+static DEFINE_TIMER(timer, sh_wdt_ping, 0, 0);
static unsigned long next_heartbeat;
#define WATCHDOG_HEARTBEAT 30 /* 30 sec default heartbeat */
@@ -433,10 +435,6 @@ static int __init sh_wdt_init(void)
"be 1<=x<=3600, using %d\n", heartbeat);
}
- init_timer(&timer);
- timer.function = sh_wdt_ping;
- timer.data = 0;
-
rc = register_reboot_notifier(&sh_wdt_notifier);
if (unlikely(rc)) {
printk(KERN_ERR PFX "Can't register reboot notifier (err=%d)\n",
diff --git a/drivers/char/watchdog/smsc37b787_wdt.c b/drivers/char/watchdog/smsc37b787_wdt.c
index 9f56913b484..d3cb0a76602 100644
--- a/drivers/char/watchdog/smsc37b787_wdt.c
+++ b/drivers/char/watchdog/smsc37b787_wdt.c
@@ -510,7 +510,7 @@ static int wb_smsc_wdt_notify_sys(struct notifier_block *this, unsigned long cod
/* -- Module's structures ---------------------------------------*/
-static struct file_operations wb_smsc_wdt_fops =
+static const struct file_operations wb_smsc_wdt_fops =
{
.owner = THIS_MODULE,
.llseek = no_llseek,
@@ -624,4 +624,4 @@ module_param(timeout, int, 0);
MODULE_PARM_DESC(timeout, "range is 1-255 units, default is 60");
module_param(nowayout, int, 0);
-MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
diff --git a/drivers/char/watchdog/softdog.c b/drivers/char/watchdog/softdog.c
index 4067e1f8a36..9c369490924 100644
--- a/drivers/char/watchdog/softdog.c
+++ b/drivers/char/watchdog/softdog.c
@@ -59,7 +59,7 @@ MODULE_PARM_DESC(soft_margin, "Watchdog soft_margin in seconds. (0<soft_margin<6
static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0);
-MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
#ifdef ONLY_TESTING
static int soft_noboot = 1;
diff --git a/drivers/char/watchdog/w83627hf_wdt.c b/drivers/char/watchdog/w83627hf_wdt.c
index 07d4bff2722..337ee42c90d 100644
--- a/drivers/char/watchdog/w83627hf_wdt.c
+++ b/drivers/char/watchdog/w83627hf_wdt.c
@@ -58,7 +58,7 @@ MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1<= timeout <=63, defaul
static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0);
-MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
/*
* Kernel methods.
diff --git a/drivers/char/watchdog/w83697hf_wdt.c b/drivers/char/watchdog/w83697hf_wdt.c
index 7768b55487c..d9e821d08de 100644
--- a/drivers/char/watchdog/w83697hf_wdt.c
+++ b/drivers/char/watchdog/w83697hf_wdt.c
@@ -60,7 +60,7 @@ MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1<= timeout <=255, defau
static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0);
-MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
/*
* Kernel methods.
@@ -323,7 +323,7 @@ wdt_notify_sys(struct notifier_block *this, unsigned long code,
* Kernel Interfaces
*/
-static struct file_operations wdt_fops = {
+static const struct file_operations wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = wdt_write,
diff --git a/drivers/char/watchdog/w83877f_wdt.c b/drivers/char/watchdog/w83877f_wdt.c
index b0e5f84d6ba..3c88fe18f4f 100644
--- a/drivers/char/watchdog/w83877f_wdt.c
+++ b/drivers/char/watchdog/w83877f_wdt.c
@@ -87,10 +87,10 @@ MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (1<=timeout<=3600, defau
static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0);
-MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
static void wdt_timer_ping(unsigned long);
-static struct timer_list timer;
+static DEFINE_TIMER(timer, wdt_timer_ping, 0, 0);
static unsigned long next_heartbeat;
static unsigned long wdt_is_open;
static char wdt_expect_close;
@@ -114,8 +114,7 @@ static void wdt_timer_ping(unsigned long data)
inb_p(WDT_PING);
/* Re-set the timer interval */
- timer.expires = jiffies + WDT_INTERVAL;
- add_timer(&timer);
+ mod_timer(&timer, jiffies + WDT_INTERVAL);
spin_unlock(&wdt_spinlock);
@@ -155,8 +154,7 @@ static void wdt_startup(void)
next_heartbeat = jiffies + (timeout * HZ);
/* Start the timer */
- timer.expires = jiffies + WDT_INTERVAL;
- add_timer(&timer);
+ mod_timer(&timer, jiffies + WDT_INTERVAL);
wdt_change(WDT_ENABLE);
@@ -377,10 +375,6 @@ static int __init w83877f_wdt_init(void)
goto err_out_region1;
}
- init_timer(&timer);
- timer.function = wdt_timer_ping;
- timer.data = 0;
-
rc = misc_register(&wdt_miscdev);
if (rc)
{
diff --git a/drivers/char/watchdog/w83977f_wdt.c b/drivers/char/watchdog/w83977f_wdt.c
index 2c8d5d8bd4e..15796844289 100644
--- a/drivers/char/watchdog/w83977f_wdt.c
+++ b/drivers/char/watchdog/w83977f_wdt.c
@@ -59,7 +59,7 @@ MODULE_PARM_DESC(testmode,"Watchdog testmode (1 = no reboot), default=0");
static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0);
-MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
/*
* Start the watchdog
diff --git a/drivers/char/watchdog/wafer5823wdt.c b/drivers/char/watchdog/wafer5823wdt.c
index 163e028ef9e..950905d3c39 100644
--- a/drivers/char/watchdog/wafer5823wdt.c
+++ b/drivers/char/watchdog/wafer5823wdt.c
@@ -65,7 +65,7 @@ MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1<= timeout <=255, defau
static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0);
-MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
static void wafwdt_ping(void)
{
diff --git a/drivers/char/watchdog/wdt.c b/drivers/char/watchdog/wdt.c
index 517fbd8643f..0a3de6a0244 100644
--- a/drivers/char/watchdog/wdt.c
+++ b/drivers/char/watchdog/wdt.c
@@ -64,7 +64,7 @@ MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (0<heartbeat<65536,
static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0);
-MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
/* You must set these - there is no sane way to probe for this board. */
static int io=0x240;
diff --git a/drivers/char/watchdog/wdt977.c b/drivers/char/watchdog/wdt977.c
index 6253041b235..7d300ff7ab0 100644
--- a/drivers/char/watchdog/wdt977.c
+++ b/drivers/char/watchdog/wdt977.c
@@ -68,7 +68,7 @@ MODULE_PARM_DESC(testmode,"Watchdog testmode (1 = no reboot), default=0");
static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0);
-MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
/*
* Start the watchdog
diff --git a/drivers/char/watchdog/wdt_pci.c b/drivers/char/watchdog/wdt_pci.c
index ce1261c5cbc..6baf4ae42c9 100644
--- a/drivers/char/watchdog/wdt_pci.c
+++ b/drivers/char/watchdog/wdt_pci.c
@@ -90,7 +90,7 @@ MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (0<heartbeat<65536,
static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0);
-MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
#ifdef CONFIG_WDT_501_PCI
/* Support for the Fan Tachometer on the PCI-WDT501 */
diff --git a/drivers/clocksource/acpi_pm.c b/drivers/clocksource/acpi_pm.c
index b6bcdbbf57b..ccaa6a39cb4 100644
--- a/drivers/clocksource/acpi_pm.c
+++ b/drivers/clocksource/acpi_pm.c
@@ -16,15 +16,13 @@
* This file is licensed under the GPL v2.
*/
+#include <linux/acpi_pmtmr.h>
#include <linux/clocksource.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <asm/io.h>
-/* Number of PMTMR ticks expected during calibration run */
-#define PMTMR_TICKS_PER_SEC 3579545
-
/*
* The I/O port the PMTMR resides at.
* The location is detected during setup_arch(),
@@ -32,15 +30,13 @@
*/
u32 pmtmr_ioport __read_mostly;
-#define ACPI_PM_MASK CLOCKSOURCE_MASK(24) /* limit it to 24 bits */
-
static inline u32 read_pmtmr(void)
{
/* mask the output to 24 bits */
return inl(pmtmr_ioport) & ACPI_PM_MASK;
}
-static cycle_t acpi_pm_read_verified(void)
+u32 acpi_pm_read_verified(void)
{
u32 v1 = 0, v2 = 0, v3 = 0;
@@ -57,7 +53,12 @@ static cycle_t acpi_pm_read_verified(void)
} while (unlikely((v1 > v2 && v1 < v3) || (v2 > v3 && v2 < v1)
|| (v3 > v1 && v3 < v2)));
- return (cycle_t)v2;
+ return v2;
+}
+
+static cycle_t acpi_pm_read_slow(void)
+{
+ return (cycle_t)acpi_pm_read_verified();
}
static cycle_t acpi_pm_read(void)
@@ -72,7 +73,8 @@ static struct clocksource clocksource_acpi_pm = {
.mask = (cycle_t)ACPI_PM_MASK,
.mult = 0, /*to be caluclated*/
.shift = 22,
- .is_continuous = 1,
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+
};
@@ -87,7 +89,7 @@ __setup("acpi_pm_good", acpi_pm_good_setup);
static inline void acpi_pm_need_workaround(void)
{
- clocksource_acpi_pm.read = acpi_pm_read_verified;
+ clocksource_acpi_pm.read = acpi_pm_read_slow;
clocksource_acpi_pm.rating = 110;
}
diff --git a/drivers/clocksource/cyclone.c b/drivers/clocksource/cyclone.c
index bf4d3d50d1c..4f3925ceb36 100644
--- a/drivers/clocksource/cyclone.c
+++ b/drivers/clocksource/cyclone.c
@@ -31,7 +31,7 @@ static struct clocksource clocksource_cyclone = {
.mask = CYCLONE_TIMER_MASK,
.mult = 10,
.shift = 0,
- .is_continuous = 1,
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
static int __init init_cyclone_clocksource(void)
diff --git a/drivers/clocksource/scx200_hrt.c b/drivers/clocksource/scx200_hrt.c
index 22915cc46ba..b92da677aa5 100644
--- a/drivers/clocksource/scx200_hrt.c
+++ b/drivers/clocksource/scx200_hrt.c
@@ -57,7 +57,7 @@ static struct clocksource cs_hrt = {
.rating = 250,
.read = read_hrt,
.mask = CLOCKSOURCE_MASK(32),
- .is_continuous = 1,
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
/* mult, shift are set based on mhz27 flag */
};
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
index 491779af8d5..d155e81b5c9 100644
--- a/drivers/cpufreq/Kconfig
+++ b/drivers/cpufreq/Kconfig
@@ -16,7 +16,7 @@ config CPU_FREQ
if CPU_FREQ
config CPU_FREQ_TABLE
- def_tristate m
+ tristate
config CPU_FREQ_DEBUG
bool "Enable CPUfreq debugging"
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index a45cc89e387..f52facc570f 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -41,8 +41,67 @@ static struct cpufreq_driver *cpufreq_driver;
static struct cpufreq_policy *cpufreq_cpu_data[NR_CPUS];
static DEFINE_SPINLOCK(cpufreq_driver_lock);
+/*
+ * cpu_policy_rwsem is a per CPU reader-writer semaphore designed to cure
+ * all cpufreq/hotplug/workqueue/etc related lock issues.
+ *
+ * The rules for this semaphore:
+ * - Any routine that wants to read from the policy structure will
+ * do a down_read on this semaphore.
+ * - Any routine that will write to the policy structure and/or may take away
+ * the policy altogether (eg. CPU hotplug), will hold this lock in write
+ * mode before doing so.
+ *
+ * Additional rules:
+ * - All holders of the lock should check to make sure that the CPU they
+ * are concerned with are online after they get the lock.
+ * - Governor routines that can be called in cpufreq hotplug path should not
+ * take this sem as top level hotplug notifier handler takes this.
+ */
+static DEFINE_PER_CPU(int, policy_cpu);
+static DEFINE_PER_CPU(struct rw_semaphore, cpu_policy_rwsem);
+
+#define lock_policy_rwsem(mode, cpu) \
+int lock_policy_rwsem_##mode \
+(int cpu) \
+{ \
+ int policy_cpu = per_cpu(policy_cpu, cpu); \
+ BUG_ON(policy_cpu == -1); \
+ down_##mode(&per_cpu(cpu_policy_rwsem, policy_cpu)); \
+ if (unlikely(!cpu_online(cpu))) { \
+ up_##mode(&per_cpu(cpu_policy_rwsem, policy_cpu)); \
+ return -1; \
+ } \
+ \
+ return 0; \
+}
+
+lock_policy_rwsem(read, cpu);
+EXPORT_SYMBOL_GPL(lock_policy_rwsem_read);
+
+lock_policy_rwsem(write, cpu);
+EXPORT_SYMBOL_GPL(lock_policy_rwsem_write);
+
+void unlock_policy_rwsem_read(int cpu)
+{
+ int policy_cpu = per_cpu(policy_cpu, cpu);
+ BUG_ON(policy_cpu == -1);
+ up_read(&per_cpu(cpu_policy_rwsem, policy_cpu));
+}
+EXPORT_SYMBOL_GPL(unlock_policy_rwsem_read);
+
+void unlock_policy_rwsem_write(int cpu)
+{
+ int policy_cpu = per_cpu(policy_cpu, cpu);
+ BUG_ON(policy_cpu == -1);
+ up_write(&per_cpu(cpu_policy_rwsem, policy_cpu));
+}
+EXPORT_SYMBOL_GPL(unlock_policy_rwsem_write);
+
+
/* internal prototypes */
static int __cpufreq_governor(struct cpufreq_policy *policy, unsigned int event);
+static unsigned int __cpufreq_get(unsigned int cpu);
static void handle_update(struct work_struct *work);
/**
@@ -415,12 +474,8 @@ static ssize_t store_##file_name \
if (ret != 1) \
return -EINVAL; \
\
- lock_cpu_hotplug(); \
- mutex_lock(&policy->lock); \
ret = __cpufreq_set_policy(policy, &new_policy); \
policy->user_policy.object = policy->object; \
- mutex_unlock(&policy->lock); \
- unlock_cpu_hotplug(); \
\
return ret ? ret : count; \
}
@@ -434,7 +489,7 @@ store_one(scaling_max_freq,max);
static ssize_t show_cpuinfo_cur_freq (struct cpufreq_policy * policy,
char *buf)
{
- unsigned int cur_freq = cpufreq_get(policy->cpu);
+ unsigned int cur_freq = __cpufreq_get(policy->cpu);
if (!cur_freq)
return sprintf(buf, "<unknown>");
return sprintf(buf, "%u\n", cur_freq);
@@ -479,18 +534,12 @@ static ssize_t store_scaling_governor (struct cpufreq_policy * policy,
&new_policy.governor))
return -EINVAL;
- lock_cpu_hotplug();
-
/* Do not use cpufreq_set_policy here or the user_policy.max
will be wrongly overridden */
- mutex_lock(&policy->lock);
ret = __cpufreq_set_policy(policy, &new_policy);
policy->user_policy.policy = policy->policy;
policy->user_policy.governor = policy->governor;
- mutex_unlock(&policy->lock);
-
- unlock_cpu_hotplug();
if (ret)
return ret;
@@ -595,11 +644,17 @@ static ssize_t show(struct kobject * kobj, struct attribute * attr ,char * buf)
policy = cpufreq_cpu_get(policy->cpu);
if (!policy)
return -EINVAL;
+
+ if (lock_policy_rwsem_read(policy->cpu) < 0)
+ return -EINVAL;
+
if (fattr->show)
ret = fattr->show(policy, buf);
else
ret = -EIO;
+ unlock_policy_rwsem_read(policy->cpu);
+
cpufreq_cpu_put(policy);
return ret;
}
@@ -613,11 +668,17 @@ static ssize_t store(struct kobject * kobj, struct attribute * attr,
policy = cpufreq_cpu_get(policy->cpu);
if (!policy)
return -EINVAL;
+
+ if (lock_policy_rwsem_write(policy->cpu) < 0)
+ return -EINVAL;
+
if (fattr->store)
ret = fattr->store(policy, buf, count);
else
ret = -EIO;
+ unlock_policy_rwsem_write(policy->cpu);
+
cpufreq_cpu_put(policy);
return ret;
}
@@ -691,8 +752,10 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
policy->cpu = cpu;
policy->cpus = cpumask_of_cpu(cpu);
- mutex_init(&policy->lock);
- mutex_lock(&policy->lock);
+ /* Initially set CPU itself as the policy_cpu */
+ per_cpu(policy_cpu, cpu) = cpu;
+ lock_policy_rwsem_write(cpu);
+
init_completion(&policy->kobj_unregister);
INIT_WORK(&policy->update, handle_update);
@@ -702,7 +765,7 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
ret = cpufreq_driver->init(policy);
if (ret) {
dprintk("initialization failed\n");
- mutex_unlock(&policy->lock);
+ unlock_policy_rwsem_write(cpu);
goto err_out;
}
@@ -716,6 +779,14 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
*/
managed_policy = cpufreq_cpu_get(j);
if (unlikely(managed_policy)) {
+
+ /* Set proper policy_cpu */
+ unlock_policy_rwsem_write(cpu);
+ per_cpu(policy_cpu, cpu) = managed_policy->cpu;
+
+ if (lock_policy_rwsem_write(cpu) < 0)
+ goto err_out_driver_exit;
+
spin_lock_irqsave(&cpufreq_driver_lock, flags);
managed_policy->cpus = policy->cpus;
cpufreq_cpu_data[cpu] = managed_policy;
@@ -726,13 +797,13 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
&managed_policy->kobj,
"cpufreq");
if (ret) {
- mutex_unlock(&policy->lock);
+ unlock_policy_rwsem_write(cpu);
goto err_out_driver_exit;
}
cpufreq_debug_enable_ratelimit();
- mutex_unlock(&policy->lock);
ret = 0;
+ unlock_policy_rwsem_write(cpu);
goto err_out_driver_exit; /* call driver->exit() */
}
}
@@ -746,7 +817,7 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
ret = kobject_register(&policy->kobj);
if (ret) {
- mutex_unlock(&policy->lock);
+ unlock_policy_rwsem_write(cpu);
goto err_out_driver_exit;
}
/* set up files for this cpu device */
@@ -761,8 +832,10 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
sysfs_create_file(&policy->kobj, &scaling_cur_freq.attr);
spin_lock_irqsave(&cpufreq_driver_lock, flags);
- for_each_cpu_mask(j, policy->cpus)
+ for_each_cpu_mask(j, policy->cpus) {
cpufreq_cpu_data[j] = policy;
+ per_cpu(policy_cpu, j) = policy->cpu;
+ }
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
/* symlink affected CPUs */
@@ -778,14 +851,14 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
ret = sysfs_create_link(&cpu_sys_dev->kobj, &policy->kobj,
"cpufreq");
if (ret) {
- mutex_unlock(&policy->lock);
+ unlock_policy_rwsem_write(cpu);
goto err_out_unregister;
}
}
policy->governor = NULL; /* to assure that the starting sequence is
* run in cpufreq_set_policy */
- mutex_unlock(&policy->lock);
+ unlock_policy_rwsem_write(cpu);
/* set default policy */
ret = cpufreq_set_policy(&new_policy);
@@ -826,11 +899,13 @@ module_out:
/**
- * cpufreq_remove_dev - remove a CPU device
+ * __cpufreq_remove_dev - remove a CPU device
*
* Removes the cpufreq interface for a CPU device.
+ * Caller should already have policy_rwsem in write mode for this CPU.
+ * This routine frees the rwsem before returning.
*/
-static int cpufreq_remove_dev (struct sys_device * sys_dev)
+static int __cpufreq_remove_dev (struct sys_device * sys_dev)
{
unsigned int cpu = sys_dev->id;
unsigned long flags;
@@ -849,6 +924,7 @@ static int cpufreq_remove_dev (struct sys_device * sys_dev)
if (!data) {
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
cpufreq_debug_enable_ratelimit();
+ unlock_policy_rwsem_write(cpu);
return -EINVAL;
}
cpufreq_cpu_data[cpu] = NULL;
@@ -865,6 +941,7 @@ static int cpufreq_remove_dev (struct sys_device * sys_dev)
sysfs_remove_link(&sys_dev->kobj, "cpufreq");
cpufreq_cpu_put(data);
cpufreq_debug_enable_ratelimit();
+ unlock_policy_rwsem_write(cpu);
return 0;
}
#endif
@@ -873,6 +950,7 @@ static int cpufreq_remove_dev (struct sys_device * sys_dev)
if (!kobject_get(&data->kobj)) {
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
cpufreq_debug_enable_ratelimit();
+ unlock_policy_rwsem_write(cpu);
return -EFAULT;
}
@@ -906,10 +984,10 @@ static int cpufreq_remove_dev (struct sys_device * sys_dev)
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
#endif
- mutex_lock(&data->lock);
if (cpufreq_driver->target)
__cpufreq_governor(data, CPUFREQ_GOV_STOP);
- mutex_unlock(&data->lock);
+
+ unlock_policy_rwsem_write(cpu);
kobject_unregister(&data->kobj);
@@ -933,6 +1011,18 @@ static int cpufreq_remove_dev (struct sys_device * sys_dev)
}
+static int cpufreq_remove_dev (struct sys_device * sys_dev)
+{
+ unsigned int cpu = sys_dev->id;
+ int retval;
+ if (unlikely(lock_policy_rwsem_write(cpu)))
+ BUG();
+
+ retval = __cpufreq_remove_dev(sys_dev);
+ return retval;
+}
+
+
static void handle_update(struct work_struct *work)
{
struct cpufreq_policy *policy =
@@ -980,9 +1070,12 @@ unsigned int cpufreq_quick_get(unsigned int cpu)
unsigned int ret_freq = 0;
if (policy) {
- mutex_lock(&policy->lock);
+ if (unlikely(lock_policy_rwsem_read(cpu)))
+ return ret_freq;
+
ret_freq = policy->cur;
- mutex_unlock(&policy->lock);
+
+ unlock_policy_rwsem_read(cpu);
cpufreq_cpu_put(policy);
}
@@ -991,24 +1084,13 @@ unsigned int cpufreq_quick_get(unsigned int cpu)
EXPORT_SYMBOL(cpufreq_quick_get);
-/**
- * cpufreq_get - get the current CPU frequency (in kHz)
- * @cpu: CPU number
- *
- * Get the CPU current (static) CPU frequency
- */
-unsigned int cpufreq_get(unsigned int cpu)
+static unsigned int __cpufreq_get(unsigned int cpu)
{
- struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
+ struct cpufreq_policy *policy = cpufreq_cpu_data[cpu];
unsigned int ret_freq = 0;
- if (!policy)
- return 0;
-
if (!cpufreq_driver->get)
- goto out;
-
- mutex_lock(&policy->lock);
+ return (ret_freq);
ret_freq = cpufreq_driver->get(cpu);
@@ -1022,11 +1104,33 @@ unsigned int cpufreq_get(unsigned int cpu)
}
}
- mutex_unlock(&policy->lock);
+ return (ret_freq);
+}
-out:
- cpufreq_cpu_put(policy);
+/**
+ * cpufreq_get - get the current CPU frequency (in kHz)
+ * @cpu: CPU number
+ *
+ * Get the CPU current (static) CPU frequency
+ */
+unsigned int cpufreq_get(unsigned int cpu)
+{
+ unsigned int ret_freq = 0;
+ struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
+
+ if (!policy)
+ goto out;
+
+ if (unlikely(lock_policy_rwsem_read(cpu)))
+ goto out_policy;
+
+ ret_freq = __cpufreq_get(cpu);
+ unlock_policy_rwsem_read(cpu);
+
+out_policy:
+ cpufreq_cpu_put(policy);
+out:
return (ret_freq);
}
EXPORT_SYMBOL(cpufreq_get);
@@ -1278,7 +1382,6 @@ EXPORT_SYMBOL(cpufreq_unregister_notifier);
*********************************************************************/
-/* Must be called with lock_cpu_hotplug held */
int __cpufreq_driver_target(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
@@ -1304,20 +1407,19 @@ int cpufreq_driver_target(struct cpufreq_policy *policy,
if (!policy)
return -EINVAL;
- lock_cpu_hotplug();
- mutex_lock(&policy->lock);
+ if (unlikely(lock_policy_rwsem_write(policy->cpu)))
+ return -EINVAL;
ret = __cpufreq_driver_target(policy, target_freq, relation);
- mutex_unlock(&policy->lock);
- unlock_cpu_hotplug();
+ unlock_policy_rwsem_write(policy->cpu);
cpufreq_cpu_put(policy);
return ret;
}
EXPORT_SYMBOL_GPL(cpufreq_driver_target);
-int cpufreq_driver_getavg(struct cpufreq_policy *policy)
+int __cpufreq_driver_getavg(struct cpufreq_policy *policy)
{
int ret = 0;
@@ -1325,20 +1427,15 @@ int cpufreq_driver_getavg(struct cpufreq_policy *policy)
if (!policy)
return -EINVAL;
- mutex_lock(&policy->lock);
-
if (cpu_online(policy->cpu) && cpufreq_driver->getavg)
ret = cpufreq_driver->getavg(policy->cpu);
- mutex_unlock(&policy->lock);
-
cpufreq_cpu_put(policy);
return ret;
}
-EXPORT_SYMBOL_GPL(cpufreq_driver_getavg);
+EXPORT_SYMBOL_GPL(__cpufreq_driver_getavg);
/*
- * Locking: Must be called with the lock_cpu_hotplug() lock held
* when "event" is CPUFREQ_GOV_LIMITS
*/
@@ -1420,9 +1517,7 @@ int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu)
if (!cpu_policy)
return -EINVAL;
- mutex_lock(&cpu_policy->lock);
memcpy(policy, cpu_policy, sizeof(struct cpufreq_policy));
- mutex_unlock(&cpu_policy->lock);
cpufreq_cpu_put(cpu_policy);
return 0;
@@ -1433,7 +1528,6 @@ EXPORT_SYMBOL(cpufreq_get_policy);
/*
* data : current policy.
* policy : policy to be set.
- * Locking: Must be called with the lock_cpu_hotplug() lock held
*/
static int __cpufreq_set_policy(struct cpufreq_policy *data,
struct cpufreq_policy *policy)
@@ -1539,10 +1633,9 @@ int cpufreq_set_policy(struct cpufreq_policy *policy)
if (!data)
return -EINVAL;
- lock_cpu_hotplug();
+ if (unlikely(lock_policy_rwsem_write(policy->cpu)))
+ return -EINVAL;
- /* lock this CPU */
- mutex_lock(&data->lock);
ret = __cpufreq_set_policy(data, policy);
data->user_policy.min = data->min;
@@ -1550,9 +1643,8 @@ int cpufreq_set_policy(struct cpufreq_policy *policy)
data->user_policy.policy = data->policy;
data->user_policy.governor = data->governor;
- mutex_unlock(&data->lock);
+ unlock_policy_rwsem_write(policy->cpu);
- unlock_cpu_hotplug();
cpufreq_cpu_put(data);
return ret;
@@ -1576,8 +1668,8 @@ int cpufreq_update_policy(unsigned int cpu)
if (!data)
return -ENODEV;
- lock_cpu_hotplug();
- mutex_lock(&data->lock);
+ if (unlikely(lock_policy_rwsem_write(cpu)))
+ return -EINVAL;
dprintk("updating policy for CPU %u\n", cpu);
memcpy(&policy, data, sizeof(struct cpufreq_policy));
@@ -1602,8 +1694,8 @@ int cpufreq_update_policy(unsigned int cpu)
ret = __cpufreq_set_policy(data, &policy);
- mutex_unlock(&data->lock);
- unlock_cpu_hotplug();
+ unlock_policy_rwsem_write(cpu);
+
cpufreq_cpu_put(data);
return ret;
}
@@ -1613,31 +1705,28 @@ static int cpufreq_cpu_callback(struct notifier_block *nfb,
unsigned long action, void *hcpu)
{
unsigned int cpu = (unsigned long)hcpu;
- struct cpufreq_policy *policy;
struct sys_device *sys_dev;
+ struct cpufreq_policy *policy;
sys_dev = get_cpu_sysdev(cpu);
-
if (sys_dev) {
switch (action) {
case CPU_ONLINE:
cpufreq_add_dev(sys_dev);
break;
case CPU_DOWN_PREPARE:
- /*
- * We attempt to put this cpu in lowest frequency
- * possible before going down. This will permit
- * hardware-managed P-State to switch other related
- * threads to min or higher speeds if possible.
- */
+ if (unlikely(lock_policy_rwsem_write(cpu)))
+ BUG();
+
policy = cpufreq_cpu_data[cpu];
if (policy) {
- cpufreq_driver_target(policy, policy->min,
+ __cpufreq_driver_target(policy, policy->min,
CPUFREQ_RELATION_H);
}
+ __cpufreq_remove_dev(sys_dev);
break;
- case CPU_DEAD:
- cpufreq_remove_dev(sys_dev);
+ case CPU_DOWN_FAILED:
+ cpufreq_add_dev(sys_dev);
break;
}
}
@@ -1751,3 +1840,16 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver)
return 0;
}
EXPORT_SYMBOL_GPL(cpufreq_unregister_driver);
+
+static int __init cpufreq_core_init(void)
+{
+ int cpu;
+
+ for_each_possible_cpu(cpu) {
+ per_cpu(policy_cpu, cpu) = -1;
+ init_rwsem(&per_cpu(cpu_policy_rwsem, cpu));
+ }
+ return 0;
+}
+
+core_initcall(cpufreq_core_init);
diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c
index eef0270c6f3..26f440ccc3f 100644
--- a/drivers/cpufreq/cpufreq_conservative.c
+++ b/drivers/cpufreq/cpufreq_conservative.c
@@ -23,7 +23,6 @@
#include <linux/fs.h>
#include <linux/sysfs.h>
#include <linux/cpu.h>
-#include <linux/sched.h>
#include <linux/kmod.h>
#include <linux/workqueue.h>
#include <linux/jiffies.h>
@@ -430,14 +429,12 @@ static void dbs_check_cpu(int cpu)
static void do_dbs_timer(struct work_struct *work)
{
int i;
- lock_cpu_hotplug();
mutex_lock(&dbs_mutex);
for_each_online_cpu(i)
dbs_check_cpu(i);
schedule_delayed_work(&dbs_work,
usecs_to_jiffies(dbs_tuners_ins.sampling_rate));
mutex_unlock(&dbs_mutex);
- unlock_cpu_hotplug();
}
static inline void dbs_timer_init(void)
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index f697449327c..d60bcb9d14c 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -52,19 +52,20 @@ static unsigned int def_sampling_rate;
static void do_dbs_timer(struct work_struct *work);
/* Sampling types */
-enum dbs_sample {DBS_NORMAL_SAMPLE, DBS_SUB_SAMPLE};
+enum {DBS_NORMAL_SAMPLE, DBS_SUB_SAMPLE};
struct cpu_dbs_info_s {
cputime64_t prev_cpu_idle;
cputime64_t prev_cpu_wall;
struct cpufreq_policy *cur_policy;
struct delayed_work work;
- enum dbs_sample sample_type;
- unsigned int enable;
struct cpufreq_frequency_table *freq_table;
unsigned int freq_lo;
unsigned int freq_lo_jiffies;
unsigned int freq_hi_jiffies;
+ int cpu;
+ unsigned int enable:1,
+ sample_type:1;
};
static DEFINE_PER_CPU(struct cpu_dbs_info_s, cpu_dbs_info);
@@ -402,7 +403,7 @@ static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info)
if (load < (dbs_tuners_ins.up_threshold - 10)) {
unsigned int freq_next, freq_cur;
- freq_cur = cpufreq_driver_getavg(policy);
+ freq_cur = __cpufreq_driver_getavg(policy);
if (!freq_cur)
freq_cur = policy->cur;
@@ -423,9 +424,11 @@ static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info)
static void do_dbs_timer(struct work_struct *work)
{
- unsigned int cpu = smp_processor_id();
- struct cpu_dbs_info_s *dbs_info = &per_cpu(cpu_dbs_info, cpu);
- enum dbs_sample sample_type = dbs_info->sample_type;
+ struct cpu_dbs_info_s *dbs_info =
+ container_of(work, struct cpu_dbs_info_s, work.work);
+ unsigned int cpu = dbs_info->cpu;
+ int sample_type = dbs_info->sample_type;
+
/* We want all CPUs to do sampling nearly on same jiffy */
int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
@@ -434,15 +437,19 @@ static void do_dbs_timer(struct work_struct *work)
delay -= jiffies % delay;
- if (!dbs_info->enable)
+ if (lock_policy_rwsem_write(cpu) < 0)
+ return;
+
+ if (!dbs_info->enable) {
+ unlock_policy_rwsem_write(cpu);
return;
+ }
+
/* Common NORMAL_SAMPLE setup */
dbs_info->sample_type = DBS_NORMAL_SAMPLE;
if (!dbs_tuners_ins.powersave_bias ||
sample_type == DBS_NORMAL_SAMPLE) {
- lock_cpu_hotplug();
dbs_check_cpu(dbs_info);
- unlock_cpu_hotplug();
if (dbs_info->freq_lo) {
/* Setup timer for SUB_SAMPLE */
dbs_info->sample_type = DBS_SUB_SAMPLE;
@@ -454,26 +461,27 @@ static void do_dbs_timer(struct work_struct *work)
CPUFREQ_RELATION_H);
}
queue_delayed_work_on(cpu, kondemand_wq, &dbs_info->work, delay);
+ unlock_policy_rwsem_write(cpu);
}
-static inline void dbs_timer_init(unsigned int cpu)
+static inline void dbs_timer_init(struct cpu_dbs_info_s *dbs_info)
{
- struct cpu_dbs_info_s *dbs_info = &per_cpu(cpu_dbs_info, cpu);
/* We want all CPUs to do sampling nearly on same jiffy */
int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
delay -= jiffies % delay;
+ dbs_info->enable = 1;
ondemand_powersave_bias_init();
- INIT_DELAYED_WORK_NAR(&dbs_info->work, do_dbs_timer);
dbs_info->sample_type = DBS_NORMAL_SAMPLE;
- queue_delayed_work_on(cpu, kondemand_wq, &dbs_info->work, delay);
+ INIT_DELAYED_WORK_NAR(&dbs_info->work, do_dbs_timer);
+ queue_delayed_work_on(dbs_info->cpu, kondemand_wq, &dbs_info->work,
+ delay);
}
static inline void dbs_timer_exit(struct cpu_dbs_info_s *dbs_info)
{
dbs_info->enable = 0;
cancel_delayed_work(&dbs_info->work);
- flush_workqueue(kondemand_wq);
}
static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
@@ -502,21 +510,9 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
mutex_lock(&dbs_mutex);
dbs_enable++;
- if (dbs_enable == 1) {
- kondemand_wq = create_workqueue("kondemand");
- if (!kondemand_wq) {
- printk(KERN_ERR
- "Creation of kondemand failed\n");
- dbs_enable--;
- mutex_unlock(&dbs_mutex);
- return -ENOSPC;
- }
- }
rc = sysfs_create_group(&policy->kobj, &dbs_attr_group);
if (rc) {
- if (dbs_enable == 1)
- destroy_workqueue(kondemand_wq);
dbs_enable--;
mutex_unlock(&dbs_mutex);
return rc;
@@ -530,7 +526,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
j_dbs_info->prev_cpu_idle = get_cpu_idle_time(j);
j_dbs_info->prev_cpu_wall = get_jiffies_64();
}
- this_dbs_info->enable = 1;
+ this_dbs_info->cpu = cpu;
/*
* Start the timerschedule work, when this governor
* is used for first time
@@ -550,7 +546,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
dbs_tuners_ins.sampling_rate = def_sampling_rate;
}
- dbs_timer_init(policy->cpu);
+ dbs_timer_init(this_dbs_info);
mutex_unlock(&dbs_mutex);
break;
@@ -560,9 +556,6 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
dbs_timer_exit(this_dbs_info);
sysfs_remove_group(&policy->kobj, &dbs_attr_group);
dbs_enable--;
- if (dbs_enable == 0)
- destroy_workqueue(kondemand_wq);
-
mutex_unlock(&dbs_mutex);
break;
@@ -591,12 +584,18 @@ static struct cpufreq_governor cpufreq_gov_dbs = {
static int __init cpufreq_gov_dbs_init(void)
{
+ kondemand_wq = create_workqueue("kondemand");
+ if (!kondemand_wq) {
+ printk(KERN_ERR "Creation of kondemand failed\n");
+ return -EFAULT;
+ }
return cpufreq_register_governor(&cpufreq_gov_dbs);
}
static void __exit cpufreq_gov_dbs_exit(void)
{
cpufreq_unregister_governor(&cpufreq_gov_dbs);
+ destroy_workqueue(kondemand_wq);
}
@@ -608,3 +607,4 @@ MODULE_LICENSE("GPL");
module_init(cpufreq_gov_dbs_init);
module_exit(cpufreq_gov_dbs_exit);
+
diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
index 91ad342a605..d1c7cac9316 100644
--- a/drivers/cpufreq/cpufreq_stats.c
+++ b/drivers/cpufreq/cpufreq_stats.c
@@ -370,12 +370,10 @@ __exit cpufreq_stats_exit(void)
cpufreq_unregister_notifier(&notifier_trans_block,
CPUFREQ_TRANSITION_NOTIFIER);
unregister_hotcpu_notifier(&cpufreq_stat_cpu_notifier);
- lock_cpu_hotplug();
for_each_online_cpu(cpu) {
cpufreq_stat_cpu_callback(&cpufreq_stat_cpu_notifier,
CPU_DEAD, (void *)(long)cpu);
}
- unlock_cpu_hotplug();
}
MODULE_AUTHOR ("Zou Nan hai <nanhai.zou@intel.com>");
diff --git a/drivers/cpufreq/cpufreq_userspace.c b/drivers/cpufreq/cpufreq_userspace.c
index 2a4eb0bfaf3..860345c7799 100644
--- a/drivers/cpufreq/cpufreq_userspace.c
+++ b/drivers/cpufreq/cpufreq_userspace.c
@@ -71,7 +71,6 @@ static int cpufreq_set(unsigned int freq, struct cpufreq_policy *policy)
dprintk("cpufreq_set for cpu %u, freq %u kHz\n", policy->cpu, freq);
- lock_cpu_hotplug();
mutex_lock(&userspace_mutex);
if (!cpu_is_managed[policy->cpu])
goto err;
@@ -94,7 +93,6 @@ static int cpufreq_set(unsigned int freq, struct cpufreq_policy *policy)
err:
mutex_unlock(&userspace_mutex);
- unlock_cpu_hotplug();
return ret;
}
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 879250d3d06..ff8c4beaace 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -51,6 +51,8 @@ config CRYPTO_DEV_PADLOCK_SHA
If unsure say M. The compiled module will be
called padlock-sha.ko
+source "arch/s390/crypto/Kconfig"
+
config CRYPTO_DEV_GEODE
tristate "Support for the Geode LX AES engine"
depends on CRYPTO && X86_32 && PCI
diff --git a/drivers/crypto/geode-aes.c b/drivers/crypto/geode-aes.c
index 43a68398656..0eb62841e9b 100644
--- a/drivers/crypto/geode-aes.c
+++ b/drivers/crypto/geode-aes.c
@@ -8,7 +8,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/pci.h>
#include <linux/pci_ids.h>
#include <linux/crypto.h>
@@ -457,7 +456,7 @@ static struct pci_driver geode_aes_driver = {
static int __init
geode_aes_init(void)
{
- return pci_module_init(&geode_aes_driver);
+ return pci_register_driver(&geode_aes_driver);
}
static void __exit
diff --git a/drivers/edac/e752x_edac.c b/drivers/edac/e752x_edac.c
index c82bc0ed7f1..8bcc887692a 100644
--- a/drivers/edac/e752x_edac.c
+++ b/drivers/edac/e752x_edac.c
@@ -285,8 +285,9 @@ static void do_process_ce(struct mem_ctl_info *mci, u16 error_one,
if (!pvt->map_type)
row = 7 - row;
- edac_mc_handle_ce(mci, page, 0, sec1_syndrome, row, channel,
- "e752x CE");
+ /* e752x mc reads 34:6 of the DRAM linear address */
+ edac_mc_handle_ce(mci, page, offset_in_page(sec1_add << 4),
+ sec1_syndrome, row, channel, "e752x CE");
}
static inline void process_ce(struct mem_ctl_info *mci, u16 error_one,
@@ -319,8 +320,10 @@ static void do_process_ue(struct mem_ctl_info *mci, u16 error_one,
((block_page >> 1) & 3) :
edac_mc_find_csrow_by_page(mci, block_page);
- edac_mc_handle_ue(mci, block_page, 0, row,
- "e752x UE from Read");
+ /* e752x mc reads 34:6 of the DRAM linear address */
+ edac_mc_handle_ue(mci, block_page,
+ offset_in_page(error_2b << 4),
+ row, "e752x UE from Read");
}
if (error_one & 0x0404) {
error_2b = scrb_add;
@@ -333,8 +336,10 @@ static void do_process_ue(struct mem_ctl_info *mci, u16 error_one,
((block_page >> 1) & 3) :
edac_mc_find_csrow_by_page(mci, block_page);
- edac_mc_handle_ue(mci, block_page, 0, row,
- "e752x UE from Scruber");
+ /* e752x mc reads 34:6 of the DRAM linear address */
+ edac_mc_handle_ue(mci, block_page,
+ offset_in_page(error_2b << 4),
+ row, "e752x UE from Scruber");
}
}
@@ -556,17 +561,17 @@ static void e752x_check_sysbus(struct e752x_error_info *info,
error32 = (stat32 >> 16) & 0x3ff;
stat32 = stat32 & 0x3ff;
- if(stat32 & 0x083)
- sysbus_error(1, stat32 & 0x083, error_found, handle_error);
+ if(stat32 & 0x087)
+ sysbus_error(1, stat32 & 0x087, error_found, handle_error);
- if(stat32 & 0x37c)
- sysbus_error(0, stat32 & 0x37c, error_found, handle_error);
+ if(stat32 & 0x378)
+ sysbus_error(0, stat32 & 0x378, error_found, handle_error);
- if(error32 & 0x083)
- sysbus_error(1, error32 & 0x083, error_found, handle_error);
+ if(error32 & 0x087)
+ sysbus_error(1, error32 & 0x087, error_found, handle_error);
- if(error32 & 0x37c)
- sysbus_error(0, error32 & 0x37c, error_found, handle_error);
+ if(error32 & 0x378)
+ sysbus_error(0, error32 & 0x378, error_found, handle_error);
}
static void e752x_check_membuf (struct e752x_error_info *info,
@@ -782,7 +787,12 @@ static void e752x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
u8 value;
u32 dra, drc, cumul_size;
- pci_read_config_dword(pdev, E752X_DRA, &dra);
+ dra = 0;
+ for (index=0; index < 4; index++) {
+ u8 dra_reg;
+ pci_read_config_byte(pdev, E752X_DRA+index, &dra_reg);
+ dra |= dra_reg << (index * 8);
+ }
pci_read_config_dword(pdev, E752X_DRC, &drc);
drc_chan = dual_channel_active(ddrcsr);
drc_drbg = drc_chan + 1; /* 128 in dual mode, 64 in single */
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c
index 1b4fc922180..7b622300d0e 100644
--- a/drivers/edac/edac_mc.c
+++ b/drivers/edac/edac_mc.c
@@ -927,6 +927,57 @@ static ssize_t mci_reset_counters_store(struct mem_ctl_info *mci,
return count;
}
+/* memory scrubbing */
+static ssize_t mci_sdram_scrub_rate_store(struct mem_ctl_info *mci,
+ const char *data, size_t count)
+{
+ u32 bandwidth = -1;
+
+ if (mci->set_sdram_scrub_rate) {
+
+ memctrl_int_store(&bandwidth, data, count);
+
+ if (!(*mci->set_sdram_scrub_rate)(mci, &bandwidth)) {
+ edac_printk(KERN_DEBUG, EDAC_MC,
+ "Scrub rate set successfully, applied: %d\n",
+ bandwidth);
+ } else {
+ /* FIXME: error codes maybe? */
+ edac_printk(KERN_DEBUG, EDAC_MC,
+ "Scrub rate set FAILED, could not apply: %d\n",
+ bandwidth);
+ }
+ } else {
+ /* FIXME: produce "not implemented" ERROR for user-side. */
+ edac_printk(KERN_WARNING, EDAC_MC,
+ "Memory scrubbing 'set'control is not implemented!\n");
+ }
+ return count;
+}
+
+static ssize_t mci_sdram_scrub_rate_show(struct mem_ctl_info *mci, char *data)
+{
+ u32 bandwidth = -1;
+
+ if (mci->get_sdram_scrub_rate) {
+ if (!(*mci->get_sdram_scrub_rate)(mci, &bandwidth)) {
+ edac_printk(KERN_DEBUG, EDAC_MC,
+ "Scrub rate successfully, fetched: %d\n",
+ bandwidth);
+ } else {
+ /* FIXME: error codes maybe? */
+ edac_printk(KERN_DEBUG, EDAC_MC,
+ "Scrub rate fetch FAILED, got: %d\n",
+ bandwidth);
+ }
+ } else {
+ /* FIXME: produce "not implemented" ERROR for user-side. */
+ edac_printk(KERN_WARNING, EDAC_MC,
+ "Memory scrubbing 'get' control is not implemented!\n");
+ }
+ return sprintf(data, "%d\n", bandwidth);
+}
+
/* default attribute files for the MCI object */
static ssize_t mci_ue_count_show(struct mem_ctl_info *mci, char *data)
{
@@ -1033,6 +1084,9 @@ MCIDEV_ATTR(ce_noinfo_count,S_IRUGO,mci_ce_noinfo_show,NULL);
MCIDEV_ATTR(ue_count,S_IRUGO,mci_ue_count_show,NULL);
MCIDEV_ATTR(ce_count,S_IRUGO,mci_ce_count_show,NULL);
+/* memory scrubber attribute file */
+MCIDEV_ATTR(sdram_scrub_rate,S_IRUGO|S_IWUSR,mci_sdram_scrub_rate_show,mci_sdram_scrub_rate_store);
+
static struct mcidev_attribute *mci_attr[] = {
&mci_attr_reset_counters,
&mci_attr_mc_name,
@@ -1042,6 +1096,7 @@ static struct mcidev_attribute *mci_attr[] = {
&mci_attr_ce_noinfo_count,
&mci_attr_ue_count,
&mci_attr_ce_count,
+ &mci_attr_sdram_scrub_rate,
NULL
};
@@ -1442,11 +1497,11 @@ int edac_mc_add_mc(struct mem_ctl_info *mci, int mc_idx)
/* set load time so that error rate can be tracked */
mci->start_time = jiffies;
- if (edac_create_sysfs_mci_device(mci)) {
- edac_mc_printk(mci, KERN_WARNING,
+ if (edac_create_sysfs_mci_device(mci)) {
+ edac_mc_printk(mci, KERN_WARNING,
"failed to create sysfs device\n");
- goto fail1;
- }
+ goto fail1;
+ }
/* Report action taken */
edac_mc_printk(mci, KERN_INFO, "Giving out device to %s %s: DEV %s\n",
@@ -1703,6 +1758,116 @@ void edac_mc_handle_ue_no_info(struct mem_ctl_info *mci, const char *msg)
EXPORT_SYMBOL_GPL(edac_mc_handle_ue_no_info);
+/*************************************************************
+ * On Fully Buffered DIMM modules, this help function is
+ * called to process UE events
+ */
+void edac_mc_handle_fbd_ue(struct mem_ctl_info *mci,
+ unsigned int csrow,
+ unsigned int channela,
+ unsigned int channelb,
+ char *msg)
+{
+ int len = EDAC_MC_LABEL_LEN * 4;
+ char labels[len + 1];
+ char *pos = labels;
+ int chars;
+
+ if (csrow >= mci->nr_csrows) {
+ /* something is wrong */
+ edac_mc_printk(mci, KERN_ERR,
+ "INTERNAL ERROR: row out of range (%d >= %d)\n",
+ csrow, mci->nr_csrows);
+ edac_mc_handle_ue_no_info(mci, "INTERNAL ERROR");
+ return;
+ }
+
+ if (channela >= mci->csrows[csrow].nr_channels) {
+ /* something is wrong */
+ edac_mc_printk(mci, KERN_ERR,
+ "INTERNAL ERROR: channel-a out of range "
+ "(%d >= %d)\n",
+ channela, mci->csrows[csrow].nr_channels);
+ edac_mc_handle_ue_no_info(mci, "INTERNAL ERROR");
+ return;
+ }
+
+ if (channelb >= mci->csrows[csrow].nr_channels) {
+ /* something is wrong */
+ edac_mc_printk(mci, KERN_ERR,
+ "INTERNAL ERROR: channel-b out of range "
+ "(%d >= %d)\n",
+ channelb, mci->csrows[csrow].nr_channels);
+ edac_mc_handle_ue_no_info(mci, "INTERNAL ERROR");
+ return;
+ }
+
+ mci->ue_count++;
+ mci->csrows[csrow].ue_count++;
+
+ /* Generate the DIMM labels from the specified channels */
+ chars = snprintf(pos, len + 1, "%s",
+ mci->csrows[csrow].channels[channela].label);
+ len -= chars; pos += chars;
+ chars = snprintf(pos, len + 1, "-%s",
+ mci->csrows[csrow].channels[channelb].label);
+
+ if (log_ue)
+ edac_mc_printk(mci, KERN_EMERG,
+ "UE row %d, channel-a= %d channel-b= %d "
+ "labels \"%s\": %s\n", csrow, channela, channelb,
+ labels, msg);
+
+ if (panic_on_ue)
+ panic("UE row %d, channel-a= %d channel-b= %d "
+ "labels \"%s\": %s\n", csrow, channela,
+ channelb, labels, msg);
+}
+EXPORT_SYMBOL(edac_mc_handle_fbd_ue);
+
+/*************************************************************
+ * On Fully Buffered DIMM modules, this help function is
+ * called to process CE events
+ */
+void edac_mc_handle_fbd_ce(struct mem_ctl_info *mci,
+ unsigned int csrow,
+ unsigned int channel,
+ char *msg)
+{
+
+ /* Ensure boundary values */
+ if (csrow >= mci->nr_csrows) {
+ /* something is wrong */
+ edac_mc_printk(mci, KERN_ERR,
+ "INTERNAL ERROR: row out of range (%d >= %d)\n",
+ csrow, mci->nr_csrows);
+ edac_mc_handle_ce_no_info(mci, "INTERNAL ERROR");
+ return;
+ }
+ if (channel >= mci->csrows[csrow].nr_channels) {
+ /* something is wrong */
+ edac_mc_printk(mci, KERN_ERR,
+ "INTERNAL ERROR: channel out of range (%d >= %d)\n",
+ channel, mci->csrows[csrow].nr_channels);
+ edac_mc_handle_ce_no_info(mci, "INTERNAL ERROR");
+ return;
+ }
+
+ if (log_ce)
+ /* FIXME - put in DIMM location */
+ edac_mc_printk(mci, KERN_WARNING,
+ "CE row %d, channel %d, label \"%s\": %s\n",
+ csrow, channel,
+ mci->csrows[csrow].channels[channel].label,
+ msg);
+
+ mci->ce_count++;
+ mci->csrows[csrow].ce_count++;
+ mci->csrows[csrow].channels[channel].ce_count++;
+}
+EXPORT_SYMBOL(edac_mc_handle_fbd_ce);
+
+
/*
* Iterate over all MC instances and check for ECC, et al, errors
*/
@@ -1806,7 +1971,7 @@ static void __exit edac_mc_exit(void)
debugf0("%s()\n", __func__);
kthread_stop(edac_thread);
- /* tear down the sysfs device */
+ /* tear down the sysfs device */
edac_sysfs_memctrl_teardown();
edac_sysfs_pci_teardown();
}
diff --git a/drivers/edac/edac_mc.h b/drivers/edac/edac_mc.h
index a1cfd4e3c97..713444cc410 100644
--- a/drivers/edac/edac_mc.h
+++ b/drivers/edac/edac_mc.h
@@ -123,7 +123,9 @@ enum mem_type {
MEM_RDR, /* Registered single data rate SDRAM */
MEM_DDR, /* Double data rate SDRAM */
MEM_RDDR, /* Registered Double data rate SDRAM */
- MEM_RMBS /* Rambus DRAM */
+ MEM_RMBS, /* Rambus DRAM */
+ MEM_DDR2, /* DDR2 RAM */
+ MEM_FB_DDR2, /* fully buffered DDR2 */
};
#define MEM_FLAG_EMPTY BIT(MEM_EMPTY)
@@ -137,6 +139,8 @@ enum mem_type {
#define MEM_FLAG_DDR BIT(MEM_DDR)
#define MEM_FLAG_RDDR BIT(MEM_RDDR)
#define MEM_FLAG_RMBS BIT(MEM_RMBS)
+#define MEM_FLAG_DDR2 BIT(MEM_DDR2)
+#define MEM_FLAG_FB_DDR2 BIT(MEM_FB_DDR2)
/* chipset Error Detection and Correction capabilities and mode */
enum edac_type {
@@ -315,8 +319,21 @@ struct mem_ctl_info {
unsigned long scrub_cap; /* chipset scrub capabilities */
enum scrub_type scrub_mode; /* current scrub mode */
+ /* Translates sdram memory scrub rate given in bytes/sec to the
+ internal representation and configures whatever else needs
+ to be configured.
+ */
+ int (*set_sdram_scrub_rate) (struct mem_ctl_info *mci, u32 *bw);
+
+ /* Get the current sdram memory scrub rate from the internal
+ representation and converts it to the closest matching
+ bandwith in bytes/sec.
+ */
+ int (*get_sdram_scrub_rate) (struct mem_ctl_info *mci, u32 *bw);
+
/* pointer to edac checking routine */
void (*edac_check) (struct mem_ctl_info * mci);
+
/*
* Remaps memory pages: controller pages to physical pages.
* For most MC's, this will be NULL.
@@ -441,6 +458,15 @@ extern void edac_mc_handle_ue(struct mem_ctl_info *mci,
int row, const char *msg);
extern void edac_mc_handle_ue_no_info(struct mem_ctl_info *mci,
const char *msg);
+extern void edac_mc_handle_fbd_ue(struct mem_ctl_info *mci,
+ unsigned int csrow,
+ unsigned int channel0,
+ unsigned int channel1,
+ char *msg);
+extern void edac_mc_handle_fbd_ce(struct mem_ctl_info *mci,
+ unsigned int csrow,
+ unsigned int channel,
+ char *msg);
/*
* This kmalloc's and initializes all the structures.
diff --git a/drivers/fc4/fc_syms.c b/drivers/fc4/fc_syms.c
index 8700a8076d0..bd3918ddf7a 100644
--- a/drivers/fc4/fc_syms.c
+++ b/drivers/fc4/fc_syms.c
@@ -6,7 +6,6 @@
#ifdef CONFIG_MODULES
-#include <linux/sched.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/kernel.h>
diff --git a/drivers/fc4/soc.c b/drivers/fc4/soc.c
index b09dfc78e5a..d517734462e 100644
--- a/drivers/fc4/soc.c
+++ b/drivers/fc4/soc.c
@@ -22,7 +22,6 @@ static char *version =
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/interrupt.h>
diff --git a/drivers/fc4/socal.c b/drivers/fc4/socal.c
index a6b1ae256e1..c903ebfab52 100644
--- a/drivers/fc4/socal.c
+++ b/drivers/fc4/socal.c
@@ -17,7 +17,6 @@ static char *version =
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/interrupt.h>
diff --git a/drivers/firmware/edd.c b/drivers/firmware/edd.c
index 5c261e1f92b..d8806e4f182 100644
--- a/drivers/firmware/edd.c
+++ b/drivers/firmware/edd.c
@@ -233,6 +233,8 @@ edd_show_interface(struct edd_device *edev, char *buf)
/**
* edd_show_raw_data() - copies raw data to buffer for userspace to parse
+ * @edev: target edd_device
+ * @buf: output buffer
*
* Returns: number of bytes written, or -EINVAL on failure
*/
@@ -634,8 +636,8 @@ static decl_subsys(edd,&ktype_edd,NULL);
/**
* edd_dev_is_type() - is this EDD device a 'type' device?
- * @edev
- * @type - a host bus or interface identifier string per the EDD spec
+ * @edev: target edd_device
+ * @type: a host bus or interface identifier string per the EDD spec
*
* Returns 1 (TRUE) if it is a 'type' device, 0 otherwise.
*/
@@ -657,7 +659,7 @@ edd_dev_is_type(struct edd_device *edev, const char *type)
/**
* edd_get_pci_dev() - finds pci_dev that matches edev
- * @edev - edd_device
+ * @edev: edd_device
*
* Returns pci_dev if found, or NULL
*/
diff --git a/drivers/firmware/pcdp.c b/drivers/firmware/pcdp.c
index c2ad72fefd9..2b4b76e8bd7 100644
--- a/drivers/firmware/pcdp.c
+++ b/drivers/firmware/pcdp.c
@@ -26,7 +26,7 @@ setup_serial_console(struct pcdp_uart *uart)
static char options[64], *p = options;
char parity;
- mmio = (uart->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY);
+ mmio = (uart->addr.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY);
p += sprintf(p, "console=uart,%s,0x%lx",
mmio ? "mmio" : "io", uart->addr.address);
if (uart->baud) {
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index ec796ad087d..850788f4dd2 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -22,5 +22,19 @@ config HID
If unsure, say Y
+config HID_DEBUG
+ bool "HID debugging support"
+ depends on HID
+ ---help---
+ This option lets the HID layer output diagnostics about its internal
+ state, resolve HID usages, dump HID fields, etc. Individual HID drivers
+ use this debugging facility to output information about individual HID
+ devices, etc.
+
+ This feature is useful for those who are either debugging the HID parser
+ or any HID hardware device.
+
+ If unsure, say N
+
endmenu
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 6432392110b..52e97d8f3c9 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -1,15 +1,8 @@
#
# Makefile for the HID driver
#
-
-# Multipart objects.
-hid-objs := hid-core.o hid-input.o
-
-# Optional parts of multipart objects.
+hid-objs := hid-core.o hid-input.o
obj-$(CONFIG_HID) += hid.o
-
-ifeq ($(CONFIG_INPUT_DEBUG),y)
-EXTRA_CFLAGS += -DDEBUG
-endif
+hid-$(CONFIG_HID_DEBUG) += hid-debug.o
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 49f18f5b251..7452399501b 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -18,7 +18,6 @@
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/list.h>
#include <linux/mm.h>
#include <linux/smp_lock.h>
@@ -28,11 +27,9 @@
#include <linux/input.h>
#include <linux/wait.h>
-#undef DEBUG
-#undef DEBUG_DATA
-
#include <linux/hid.h>
#include <linux/hiddev.h>
+#include <linux/hid-debug.h>
/*
* Version Information
@@ -951,7 +948,7 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i
return -1;
}
-#ifdef DEBUG_DATA
+#ifdef CONFIG_HID_DEBUG
printk(KERN_DEBUG __FILE__ ": report (size %u) (%snumbered)\n", size, report_enum->numbered ? "" : "un");
#endif
@@ -961,7 +958,7 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i
size--;
}
-#ifdef DEBUG_DATA
+#ifdef CONFIG_HID_DEBUG
{
int i;
printk(KERN_DEBUG __FILE__ ": report %d (size %u) = ", n, size);
diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c
new file mode 100644
index 00000000000..89241be4ec9
--- /dev/null
+++ b/drivers/hid/hid-debug.c
@@ -0,0 +1,764 @@
+/*
+ * $Id: hid-debug.h,v 1.8 2001/09/25 09:37:57 vojtech Exp $
+ *
+ * (c) 1999 Andreas Gal <gal@cs.uni-magdeburg.de>
+ * (c) 2000-2001 Vojtech Pavlik <vojtech@ucw.cz>
+ * (c) 2007 Jiri Kosina
+ *
+ * Some debug stuff for the HID parser.
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under 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
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/hid.h>
+
+struct hid_usage_entry {
+ unsigned page;
+ unsigned usage;
+ char *description;
+};
+
+static const struct hid_usage_entry hid_usage_table[] = {
+ { 0, 0, "Undefined" },
+ { 1, 0, "GenericDesktop" },
+ {0, 0x01, "Pointer"},
+ {0, 0x02, "Mouse"},
+ {0, 0x04, "Joystick"},
+ {0, 0x05, "GamePad"},
+ {0, 0x06, "Keyboard"},
+ {0, 0x07, "Keypad"},
+ {0, 0x08, "MultiAxis"},
+ {0, 0x30, "X"},
+ {0, 0x31, "Y"},
+ {0, 0x32, "Z"},
+ {0, 0x33, "Rx"},
+ {0, 0x34, "Ry"},
+ {0, 0x35, "Rz"},
+ {0, 0x36, "Slider"},
+ {0, 0x37, "Dial"},
+ {0, 0x38, "Wheel"},
+ {0, 0x39, "HatSwitch"},
+ {0, 0x3a, "CountedBuffer"},
+ {0, 0x3b, "ByteCount"},
+ {0, 0x3c, "MotionWakeup"},
+ {0, 0x3d, "Start"},
+ {0, 0x3e, "Select"},
+ {0, 0x40, "Vx"},
+ {0, 0x41, "Vy"},
+ {0, 0x42, "Vz"},
+ {0, 0x43, "Vbrx"},
+ {0, 0x44, "Vbry"},
+ {0, 0x45, "Vbrz"},
+ {0, 0x46, "Vno"},
+ {0, 0x80, "SystemControl"},
+ {0, 0x81, "SystemPowerDown"},
+ {0, 0x82, "SystemSleep"},
+ {0, 0x83, "SystemWakeUp"},
+ {0, 0x84, "SystemContextMenu"},
+ {0, 0x85, "SystemMainMenu"},
+ {0, 0x86, "SystemAppMenu"},
+ {0, 0x87, "SystemMenuHelp"},
+ {0, 0x88, "SystemMenuExit"},
+ {0, 0x89, "SystemMenuSelect"},
+ {0, 0x8a, "SystemMenuRight"},
+ {0, 0x8b, "SystemMenuLeft"},
+ {0, 0x8c, "SystemMenuUp"},
+ {0, 0x8d, "SystemMenuDown"},
+ {0, 0x90, "D-PadUp"},
+ {0, 0x91, "D-PadDown"},
+ {0, 0x92, "D-PadRight"},
+ {0, 0x93, "D-PadLeft"},
+ { 2, 0, "Simulation" },
+ {0, 0xb0, "Aileron"},
+ {0, 0xb1, "AileronTrim"},
+ {0, 0xb2, "Anti-Torque"},
+ {0, 0xb3, "Autopilot"},
+ {0, 0xb4, "Chaff"},
+ {0, 0xb5, "Collective"},
+ {0, 0xb6, "DiveBrake"},
+ {0, 0xb7, "ElectronicCountermeasures"},
+ {0, 0xb8, "Elevator"},
+ {0, 0xb9, "ElevatorTrim"},
+ {0, 0xba, "Rudder"},
+ {0, 0xbb, "Throttle"},
+ {0, 0xbc, "FlightCommunications"},
+ {0, 0xbd, "FlareRelease"},
+ {0, 0xbe, "LandingGear"},
+ {0, 0xbf, "ToeBrake"},
+ { 7, 0, "Keyboard" },
+ { 8, 0, "LED" },
+ {0, 0x01, "NumLock"},
+ {0, 0x02, "CapsLock"},
+ {0, 0x03, "ScrollLock"},
+ {0, 0x04, "Compose"},
+ {0, 0x05, "Kana"},
+ {0, 0x4b, "GenericIndicator"},
+ { 9, 0, "Button" },
+ { 10, 0, "Ordinal" },
+ { 12, 0, "Consumer" },
+ {0, 0x238, "HorizontalWheel"},
+ { 13, 0, "Digitizers" },
+ {0, 0x01, "Digitizer"},
+ {0, 0x02, "Pen"},
+ {0, 0x03, "LightPen"},
+ {0, 0x04, "TouchScreen"},
+ {0, 0x05, "TouchPad"},
+ {0, 0x20, "Stylus"},
+ {0, 0x21, "Puck"},
+ {0, 0x22, "Finger"},
+ {0, 0x30, "TipPressure"},
+ {0, 0x31, "BarrelPressure"},
+ {0, 0x32, "InRange"},
+ {0, 0x33, "Touch"},
+ {0, 0x34, "UnTouch"},
+ {0, 0x35, "Tap"},
+ {0, 0x39, "TabletFunctionKey"},
+ {0, 0x3a, "ProgramChangeKey"},
+ {0, 0x3c, "Invert"},
+ {0, 0x42, "TipSwitch"},
+ {0, 0x43, "SecondaryTipSwitch"},
+ {0, 0x44, "BarrelSwitch"},
+ {0, 0x45, "Eraser"},
+ {0, 0x46, "TabletPick"},
+ { 15, 0, "PhysicalInterfaceDevice" },
+ {0, 0x00, "Undefined"},
+ {0, 0x01, "Physical_Interface_Device"},
+ {0, 0x20, "Normal"},
+ {0, 0x21, "Set_Effect_Report"},
+ {0, 0x22, "Effect_Block_Index"},
+ {0, 0x23, "Parameter_Block_Offset"},
+ {0, 0x24, "ROM_Flag"},
+ {0, 0x25, "Effect_Type"},
+ {0, 0x26, "ET_Constant_Force"},
+ {0, 0x27, "ET_Ramp"},
+ {0, 0x28, "ET_Custom_Force_Data"},
+ {0, 0x30, "ET_Square"},
+ {0, 0x31, "ET_Sine"},
+ {0, 0x32, "ET_Triangle"},
+ {0, 0x33, "ET_Sawtooth_Up"},
+ {0, 0x34, "ET_Sawtooth_Down"},
+ {0, 0x40, "ET_Spring"},
+ {0, 0x41, "ET_Damper"},
+ {0, 0x42, "ET_Inertia"},
+ {0, 0x43, "ET_Friction"},
+ {0, 0x50, "Duration"},
+ {0, 0x51, "Sample_Period"},
+ {0, 0x52, "Gain"},
+ {0, 0x53, "Trigger_Button"},
+ {0, 0x54, "Trigger_Repeat_Interval"},
+ {0, 0x55, "Axes_Enable"},
+ {0, 0x56, "Direction_Enable"},
+ {0, 0x57, "Direction"},
+ {0, 0x58, "Type_Specific_Block_Offset"},
+ {0, 0x59, "Block_Type"},
+ {0, 0x5A, "Set_Envelope_Report"},
+ {0, 0x5B, "Attack_Level"},
+ {0, 0x5C, "Attack_Time"},
+ {0, 0x5D, "Fade_Level"},
+ {0, 0x5E, "Fade_Time"},
+ {0, 0x5F, "Set_Condition_Report"},
+ {0, 0x60, "CP_Offset"},
+ {0, 0x61, "Positive_Coefficient"},
+ {0, 0x62, "Negative_Coefficient"},
+ {0, 0x63, "Positive_Saturation"},
+ {0, 0x64, "Negative_Saturation"},
+ {0, 0x65, "Dead_Band"},
+ {0, 0x66, "Download_Force_Sample"},
+ {0, 0x67, "Isoch_Custom_Force_Enable"},
+ {0, 0x68, "Custom_Force_Data_Report"},
+ {0, 0x69, "Custom_Force_Data"},
+ {0, 0x6A, "Custom_Force_Vendor_Defined_Data"},
+ {0, 0x6B, "Set_Custom_Force_Report"},
+ {0, 0x6C, "Custom_Force_Data_Offset"},
+ {0, 0x6D, "Sample_Count"},
+ {0, 0x6E, "Set_Periodic_Report"},
+ {0, 0x6F, "Offset"},
+ {0, 0x70, "Magnitude"},
+ {0, 0x71, "Phase"},
+ {0, 0x72, "Period"},
+ {0, 0x73, "Set_Constant_Force_Report"},
+ {0, 0x74, "Set_Ramp_Force_Report"},
+ {0, 0x75, "Ramp_Start"},
+ {0, 0x76, "Ramp_End"},
+ {0, 0x77, "Effect_Operation_Report"},
+ {0, 0x78, "Effect_Operation"},
+ {0, 0x79, "Op_Effect_Start"},
+ {0, 0x7A, "Op_Effect_Start_Solo"},
+ {0, 0x7B, "Op_Effect_Stop"},
+ {0, 0x7C, "Loop_Count"},
+ {0, 0x7D, "Device_Gain_Report"},
+ {0, 0x7E, "Device_Gain"},
+ {0, 0x7F, "PID_Pool_Report"},
+ {0, 0x80, "RAM_Pool_Size"},
+ {0, 0x81, "ROM_Pool_Size"},
+ {0, 0x82, "ROM_Effect_Block_Count"},
+ {0, 0x83, "Simultaneous_Effects_Max"},
+ {0, 0x84, "Pool_Alignment"},
+ {0, 0x85, "PID_Pool_Move_Report"},
+ {0, 0x86, "Move_Source"},
+ {0, 0x87, "Move_Destination"},
+ {0, 0x88, "Move_Length"},
+ {0, 0x89, "PID_Block_Load_Report"},
+ {0, 0x8B, "Block_Load_Status"},
+ {0, 0x8C, "Block_Load_Success"},
+ {0, 0x8D, "Block_Load_Full"},
+ {0, 0x8E, "Block_Load_Error"},
+ {0, 0x8F, "Block_Handle"},
+ {0, 0x90, "PID_Block_Free_Report"},
+ {0, 0x91, "Type_Specific_Block_Handle"},
+ {0, 0x92, "PID_State_Report"},
+ {0, 0x94, "Effect_Playing"},
+ {0, 0x95, "PID_Device_Control_Report"},
+ {0, 0x96, "PID_Device_Control"},
+ {0, 0x97, "DC_Enable_Actuators"},
+ {0, 0x98, "DC_Disable_Actuators"},
+ {0, 0x99, "DC_Stop_All_Effects"},
+ {0, 0x9A, "DC_Device_Reset"},
+ {0, 0x9B, "DC_Device_Pause"},
+ {0, 0x9C, "DC_Device_Continue"},
+ {0, 0x9F, "Device_Paused"},
+ {0, 0xA0, "Actuators_Enabled"},
+ {0, 0xA4, "Safety_Switch"},
+ {0, 0xA5, "Actuator_Override_Switch"},
+ {0, 0xA6, "Actuator_Power"},
+ {0, 0xA7, "Start_Delay"},
+ {0, 0xA8, "Parameter_Block_Size"},
+ {0, 0xA9, "Device_Managed_Pool"},
+ {0, 0xAA, "Shared_Parameter_Blocks"},
+ {0, 0xAB, "Create_New_Effect_Report"},
+ {0, 0xAC, "RAM_Pool_Available"},
+ { 0x84, 0, "Power Device" },
+ { 0x84, 0x02, "PresentStatus" },
+ { 0x84, 0x03, "ChangeStatus" },
+ { 0x84, 0x04, "UPS" },
+ { 0x84, 0x05, "PowerSupply" },
+ { 0x84, 0x10, "BatterySystem" },
+ { 0x84, 0x11, "BatterySystemID" },
+ { 0x84, 0x12, "Battery" },
+ { 0x84, 0x13, "BatteryID" },
+ { 0x84, 0x14, "Charger" },
+ { 0x84, 0x15, "ChargerID" },
+ { 0x84, 0x16, "PowerConverter" },
+ { 0x84, 0x17, "PowerConverterID" },
+ { 0x84, 0x18, "OutletSystem" },
+ { 0x84, 0x19, "OutletSystemID" },
+ { 0x84, 0x1a, "Input" },
+ { 0x84, 0x1b, "InputID" },
+ { 0x84, 0x1c, "Output" },
+ { 0x84, 0x1d, "OutputID" },
+ { 0x84, 0x1e, "Flow" },
+ { 0x84, 0x1f, "FlowID" },
+ { 0x84, 0x20, "Outlet" },
+ { 0x84, 0x21, "OutletID" },
+ { 0x84, 0x22, "Gang" },
+ { 0x84, 0x24, "PowerSummary" },
+ { 0x84, 0x25, "PowerSummaryID" },
+ { 0x84, 0x30, "Voltage" },
+ { 0x84, 0x31, "Current" },
+ { 0x84, 0x32, "Frequency" },
+ { 0x84, 0x33, "ApparentPower" },
+ { 0x84, 0x35, "PercentLoad" },
+ { 0x84, 0x40, "ConfigVoltage" },
+ { 0x84, 0x41, "ConfigCurrent" },
+ { 0x84, 0x43, "ConfigApparentPower" },
+ { 0x84, 0x53, "LowVoltageTransfer" },
+ { 0x84, 0x54, "HighVoltageTransfer" },
+ { 0x84, 0x56, "DelayBeforeStartup" },
+ { 0x84, 0x57, "DelayBeforeShutdown" },
+ { 0x84, 0x58, "Test" },
+ { 0x84, 0x5a, "AudibleAlarmControl" },
+ { 0x84, 0x60, "Present" },
+ { 0x84, 0x61, "Good" },
+ { 0x84, 0x62, "InternalFailure" },
+ { 0x84, 0x65, "Overload" },
+ { 0x84, 0x66, "OverCharged" },
+ { 0x84, 0x67, "OverTemperature" },
+ { 0x84, 0x68, "ShutdownRequested" },
+ { 0x84, 0x69, "ShutdownImminent" },
+ { 0x84, 0x6b, "SwitchOn/Off" },
+ { 0x84, 0x6c, "Switchable" },
+ { 0x84, 0x6d, "Used" },
+ { 0x84, 0x6e, "Boost" },
+ { 0x84, 0x73, "CommunicationLost" },
+ { 0x84, 0xfd, "iManufacturer" },
+ { 0x84, 0xfe, "iProduct" },
+ { 0x84, 0xff, "iSerialNumber" },
+ { 0x85, 0, "Battery System" },
+ { 0x85, 0x01, "SMBBatteryMode" },
+ { 0x85, 0x02, "SMBBatteryStatus" },
+ { 0x85, 0x03, "SMBAlarmWarning" },
+ { 0x85, 0x04, "SMBChargerMode" },
+ { 0x85, 0x05, "SMBChargerStatus" },
+ { 0x85, 0x06, "SMBChargerSpecInfo" },
+ { 0x85, 0x07, "SMBSelectorState" },
+ { 0x85, 0x08, "SMBSelectorPresets" },
+ { 0x85, 0x09, "SMBSelectorInfo" },
+ { 0x85, 0x29, "RemainingCapacityLimit" },
+ { 0x85, 0x2c, "CapacityMode" },
+ { 0x85, 0x42, "BelowRemainingCapacityLimit" },
+ { 0x85, 0x44, "Charging" },
+ { 0x85, 0x45, "Discharging" },
+ { 0x85, 0x4b, "NeedReplacement" },
+ { 0x85, 0x66, "RemainingCapacity" },
+ { 0x85, 0x68, "RunTimeToEmpty" },
+ { 0x85, 0x6a, "AverageTimeToFull" },
+ { 0x85, 0x83, "DesignCapacity" },
+ { 0x85, 0x85, "ManufacturerDate" },
+ { 0x85, 0x89, "iDeviceChemistry" },
+ { 0x85, 0x8b, "Rechargable" },
+ { 0x85, 0x8f, "iOEMInformation" },
+ { 0x85, 0x8d, "CapacityGranularity1" },
+ { 0x85, 0xd0, "ACPresent" },
+ /* pages 0xff00 to 0xffff are vendor-specific */
+ { 0xffff, 0, "Vendor-specific-FF" },
+ { 0, 0, NULL }
+};
+
+static void resolv_usage_page(unsigned page) {
+ const struct hid_usage_entry *p;
+
+ for (p = hid_usage_table; p->description; p++)
+ if (p->page == page) {
+ printk("%s", p->description);
+ return;
+ }
+ printk("%04x", page);
+}
+
+void hid_resolv_usage(unsigned usage) {
+ const struct hid_usage_entry *p;
+
+ resolv_usage_page(usage >> 16);
+ printk(".");
+ for (p = hid_usage_table; p->description; p++)
+ if (p->page == (usage >> 16)) {
+ for(++p; p->description && p->usage != 0; p++)
+ if (p->usage == (usage & 0xffff)) {
+ printk("%s", p->description);
+ return;
+ }
+ break;
+ }
+ printk("%04x", usage & 0xffff);
+}
+EXPORT_SYMBOL_GPL(hid_resolv_usage);
+
+__inline__ static void tab(int n) {
+ while (n--) printk(" ");
+}
+
+void hid_dump_field(struct hid_field *field, int n) {
+ int j;
+
+ if (field->physical) {
+ tab(n);
+ printk("Physical(");
+ hid_resolv_usage(field->physical); printk(")\n");
+ }
+ if (field->logical) {
+ tab(n);
+ printk("Logical(");
+ hid_resolv_usage(field->logical); printk(")\n");
+ }
+ tab(n); printk("Usage(%d)\n", field->maxusage);
+ for (j = 0; j < field->maxusage; j++) {
+ tab(n+2); hid_resolv_usage(field->usage[j].hid); printk("\n");
+ }
+ if (field->logical_minimum != field->logical_maximum) {
+ tab(n); printk("Logical Minimum(%d)\n", field->logical_minimum);
+ tab(n); printk("Logical Maximum(%d)\n", field->logical_maximum);
+ }
+ if (field->physical_minimum != field->physical_maximum) {
+ tab(n); printk("Physical Minimum(%d)\n", field->physical_minimum);
+ tab(n); printk("Physical Maximum(%d)\n", field->physical_maximum);
+ }
+ if (field->unit_exponent) {
+ tab(n); printk("Unit Exponent(%d)\n", field->unit_exponent);
+ }
+ if (field->unit) {
+ char *systems[5] = { "None", "SI Linear", "SI Rotation", "English Linear", "English Rotation" };
+ char *units[5][8] = {
+ { "None", "None", "None", "None", "None", "None", "None", "None" },
+ { "None", "Centimeter", "Gram", "Seconds", "Kelvin", "Ampere", "Candela", "None" },
+ { "None", "Radians", "Gram", "Seconds", "Kelvin", "Ampere", "Candela", "None" },
+ { "None", "Inch", "Slug", "Seconds", "Fahrenheit", "Ampere", "Candela", "None" },
+ { "None", "Degrees", "Slug", "Seconds", "Fahrenheit", "Ampere", "Candela", "None" }
+ };
+
+ int i;
+ int sys;
+ __u32 data = field->unit;
+
+ /* First nibble tells us which system we're in. */
+ sys = data & 0xf;
+ data >>= 4;
+
+ if(sys > 4) {
+ tab(n); printk("Unit(Invalid)\n");
+ }
+ else {
+ int earlier_unit = 0;
+
+ tab(n); printk("Unit(%s : ", systems[sys]);
+
+ for (i=1 ; i<sizeof(__u32)*2 ; i++) {
+ char nibble = data & 0xf;
+ data >>= 4;
+ if (nibble != 0) {
+ if(earlier_unit++ > 0)
+ printk("*");
+ printk("%s", units[sys][i]);
+ if(nibble != 1) {
+ /* This is a _signed_ nibble(!) */
+
+ int val = nibble & 0x7;
+ if(nibble & 0x08)
+ val = -((0x7 & ~val) +1);
+ printk("^%d", val);
+ }
+ }
+ }
+ printk(")\n");
+ }
+ }
+ tab(n); printk("Report Size(%u)\n", field->report_size);
+ tab(n); printk("Report Count(%u)\n", field->report_count);
+ tab(n); printk("Report Offset(%u)\n", field->report_offset);
+
+ tab(n); printk("Flags( ");
+ j = field->flags;
+ printk("%s", HID_MAIN_ITEM_CONSTANT & j ? "Constant " : "");
+ printk("%s", HID_MAIN_ITEM_VARIABLE & j ? "Variable " : "Array ");
+ printk("%s", HID_MAIN_ITEM_RELATIVE & j ? "Relative " : "Absolute ");
+ printk("%s", HID_MAIN_ITEM_WRAP & j ? "Wrap " : "");
+ printk("%s", HID_MAIN_ITEM_NONLINEAR & j ? "NonLinear " : "");
+ printk("%s", HID_MAIN_ITEM_NO_PREFERRED & j ? "NoPrefferedState " : "");
+ printk("%s", HID_MAIN_ITEM_NULL_STATE & j ? "NullState " : "");
+ printk("%s", HID_MAIN_ITEM_VOLATILE & j ? "Volatile " : "");
+ printk("%s", HID_MAIN_ITEM_BUFFERED_BYTE & j ? "BufferedByte " : "");
+ printk(")\n");
+}
+EXPORT_SYMBOL_GPL(hid_dump_field);
+
+void hid_dump_device(struct hid_device *device) {
+ struct hid_report_enum *report_enum;
+ struct hid_report *report;
+ struct list_head *list;
+ unsigned i,k;
+ static char *table[] = {"INPUT", "OUTPUT", "FEATURE"};
+
+ for (i = 0; i < HID_REPORT_TYPES; i++) {
+ report_enum = device->report_enum + i;
+ list = report_enum->report_list.next;
+ while (list != &report_enum->report_list) {
+ report = (struct hid_report *) list;
+ tab(2);
+ printk("%s", table[i]);
+ if (report->id)
+ printk("(%d)", report->id);
+ printk("[%s]", table[report->type]);
+ printk("\n");
+ for (k = 0; k < report->maxfield; k++) {
+ tab(4);
+ printk("Field(%d)\n", k);
+ hid_dump_field(report->field[k], 6);
+ }
+ list = list->next;
+ }
+ }
+}
+EXPORT_SYMBOL_GPL(hid_dump_device);
+
+void hid_dump_input(struct hid_usage *usage, __s32 value) {
+ printk("hid-debug: input ");
+ hid_resolv_usage(usage->hid);
+ printk(" = %d\n", value);
+}
+EXPORT_SYMBOL_GPL(hid_dump_input);
+
+static char *events[EV_MAX + 1] = {
+ [EV_SYN] = "Sync", [EV_KEY] = "Key",
+ [EV_REL] = "Relative", [EV_ABS] = "Absolute",
+ [EV_MSC] = "Misc", [EV_LED] = "LED",
+ [EV_SND] = "Sound", [EV_REP] = "Repeat",
+ [EV_FF] = "ForceFeedback", [EV_PWR] = "Power",
+ [EV_FF_STATUS] = "ForceFeedbackStatus",
+};
+
+static char *syncs[2] = {
+ [SYN_REPORT] = "Report", [SYN_CONFIG] = "Config",
+};
+static char *keys[KEY_MAX + 1] = {
+ [KEY_RESERVED] = "Reserved", [KEY_ESC] = "Esc",
+ [KEY_1] = "1", [KEY_2] = "2",
+ [KEY_3] = "3", [KEY_4] = "4",
+ [KEY_5] = "5", [KEY_6] = "6",
+ [KEY_7] = "7", [KEY_8] = "8",
+ [KEY_9] = "9", [KEY_0] = "0",
+ [KEY_MINUS] = "Minus", [KEY_EQUAL] = "Equal",
+ [KEY_BACKSPACE] = "Backspace", [KEY_TAB] = "Tab",
+ [KEY_Q] = "Q", [KEY_W] = "W",
+ [KEY_E] = "E", [KEY_R] = "R",
+ [KEY_T] = "T", [KEY_Y] = "Y",
+ [KEY_U] = "U", [KEY_I] = "I",
+ [KEY_O] = "O", [KEY_P] = "P",
+ [KEY_LEFTBRACE] = "LeftBrace", [KEY_RIGHTBRACE] = "RightBrace",
+ [KEY_ENTER] = "Enter", [KEY_LEFTCTRL] = "LeftControl",
+ [KEY_A] = "A", [KEY_S] = "S",
+ [KEY_D] = "D", [KEY_F] = "F",
+ [KEY_G] = "G", [KEY_H] = "H",
+ [KEY_J] = "J", [KEY_K] = "K",
+ [KEY_L] = "L", [KEY_SEMICOLON] = "Semicolon",
+ [KEY_APOSTROPHE] = "Apostrophe", [KEY_GRAVE] = "Grave",
+ [KEY_LEFTSHIFT] = "LeftShift", [KEY_BACKSLASH] = "BackSlash",
+ [KEY_Z] = "Z", [KEY_X] = "X",
+ [KEY_C] = "C", [KEY_V] = "V",
+ [KEY_B] = "B", [KEY_N] = "N",
+ [KEY_M] = "M", [KEY_COMMA] = "Comma",
+ [KEY_DOT] = "Dot", [KEY_SLASH] = "Slash",
+ [KEY_RIGHTSHIFT] = "RightShift", [KEY_KPASTERISK] = "KPAsterisk",
+ [KEY_LEFTALT] = "LeftAlt", [KEY_SPACE] = "Space",
+ [KEY_CAPSLOCK] = "CapsLock", [KEY_F1] = "F1",
+ [KEY_F2] = "F2", [KEY_F3] = "F3",
+ [KEY_F4] = "F4", [KEY_F5] = "F5",
+ [KEY_F6] = "F6", [KEY_F7] = "F7",
+ [KEY_F8] = "F8", [KEY_F9] = "F9",
+ [KEY_F10] = "F10", [KEY_NUMLOCK] = "NumLock",
+ [KEY_SCROLLLOCK] = "ScrollLock", [KEY_KP7] = "KP7",
+ [KEY_KP8] = "KP8", [KEY_KP9] = "KP9",
+ [KEY_KPMINUS] = "KPMinus", [KEY_KP4] = "KP4",
+ [KEY_KP5] = "KP5", [KEY_KP6] = "KP6",
+ [KEY_KPPLUS] = "KPPlus", [KEY_KP1] = "KP1",
+ [KEY_KP2] = "KP2", [KEY_KP3] = "KP3",
+ [KEY_KP0] = "KP0", [KEY_KPDOT] = "KPDot",
+ [KEY_ZENKAKUHANKAKU] = "Zenkaku/Hankaku", [KEY_102ND] = "102nd",
+ [KEY_F11] = "F11", [KEY_F12] = "F12",
+ [KEY_RO] = "RO", [KEY_KATAKANA] = "Katakana",
+ [KEY_HIRAGANA] = "HIRAGANA", [KEY_HENKAN] = "Henkan",
+ [KEY_KATAKANAHIRAGANA] = "Katakana/Hiragana", [KEY_MUHENKAN] = "Muhenkan",
+ [KEY_KPJPCOMMA] = "KPJpComma", [KEY_KPENTER] = "KPEnter",
+ [KEY_RIGHTCTRL] = "RightCtrl", [KEY_KPSLASH] = "KPSlash",
+ [KEY_SYSRQ] = "SysRq", [KEY_RIGHTALT] = "RightAlt",
+ [KEY_LINEFEED] = "LineFeed", [KEY_HOME] = "Home",
+ [KEY_UP] = "Up", [KEY_PAGEUP] = "PageUp",
+ [KEY_LEFT] = "Left", [KEY_RIGHT] = "Right",
+ [KEY_END] = "End", [KEY_DOWN] = "Down",
+ [KEY_PAGEDOWN] = "PageDown", [KEY_INSERT] = "Insert",
+ [KEY_DELETE] = "Delete", [KEY_MACRO] = "Macro",
+ [KEY_MUTE] = "Mute", [KEY_VOLUMEDOWN] = "VolumeDown",
+ [KEY_VOLUMEUP] = "VolumeUp", [KEY_POWER] = "Power",
+ [KEY_KPEQUAL] = "KPEqual", [KEY_KPPLUSMINUS] = "KPPlusMinus",
+ [KEY_PAUSE] = "Pause", [KEY_KPCOMMA] = "KPComma",
+ [KEY_HANGUEL] = "Hangeul", [KEY_HANJA] = "Hanja",
+ [KEY_YEN] = "Yen", [KEY_LEFTMETA] = "LeftMeta",
+ [KEY_RIGHTMETA] = "RightMeta", [KEY_COMPOSE] = "Compose",
+ [KEY_STOP] = "Stop", [KEY_AGAIN] = "Again",
+ [KEY_PROPS] = "Props", [KEY_UNDO] = "Undo",
+ [KEY_FRONT] = "Front", [KEY_COPY] = "Copy",
+ [KEY_OPEN] = "Open", [KEY_PASTE] = "Paste",
+ [KEY_FIND] = "Find", [KEY_CUT] = "Cut",
+ [KEY_HELP] = "Help", [KEY_MENU] = "Menu",
+ [KEY_CALC] = "Calc", [KEY_SETUP] = "Setup",
+ [KEY_SLEEP] = "Sleep", [KEY_WAKEUP] = "WakeUp",
+ [KEY_FILE] = "File", [KEY_SENDFILE] = "SendFile",
+ [KEY_DELETEFILE] = "DeleteFile", [KEY_XFER] = "X-fer",
+ [KEY_PROG1] = "Prog1", [KEY_PROG2] = "Prog2",
+ [KEY_WWW] = "WWW", [KEY_MSDOS] = "MSDOS",
+ [KEY_COFFEE] = "Coffee", [KEY_DIRECTION] = "Direction",
+ [KEY_CYCLEWINDOWS] = "CycleWindows", [KEY_MAIL] = "Mail",
+ [KEY_BOOKMARKS] = "Bookmarks", [KEY_COMPUTER] = "Computer",
+ [KEY_BACK] = "Back", [KEY_FORWARD] = "Forward",
+ [KEY_CLOSECD] = "CloseCD", [KEY_EJECTCD] = "EjectCD",
+ [KEY_EJECTCLOSECD] = "EjectCloseCD", [KEY_NEXTSONG] = "NextSong",
+ [KEY_PLAYPAUSE] = "PlayPause", [KEY_PREVIOUSSONG] = "PreviousSong",
+ [KEY_STOPCD] = "StopCD", [KEY_RECORD] = "Record",
+ [KEY_REWIND] = "Rewind", [KEY_PHONE] = "Phone",
+ [KEY_ISO] = "ISOKey", [KEY_CONFIG] = "Config",
+ [KEY_HOMEPAGE] = "HomePage", [KEY_REFRESH] = "Refresh",
+ [KEY_EXIT] = "Exit", [KEY_MOVE] = "Move",
+ [KEY_EDIT] = "Edit", [KEY_SCROLLUP] = "ScrollUp",
+ [KEY_SCROLLDOWN] = "ScrollDown", [KEY_KPLEFTPAREN] = "KPLeftParenthesis",
+ [KEY_KPRIGHTPAREN] = "KPRightParenthesis", [KEY_NEW] = "New",
+ [KEY_REDO] = "Redo", [KEY_F13] = "F13",
+ [KEY_F14] = "F14", [KEY_F15] = "F15",
+ [KEY_F16] = "F16", [KEY_F17] = "F17",
+ [KEY_F18] = "F18", [KEY_F19] = "F19",
+ [KEY_F20] = "F20", [KEY_F21] = "F21",
+ [KEY_F22] = "F22", [KEY_F23] = "F23",
+ [KEY_F24] = "F24", [KEY_PLAYCD] = "PlayCD",
+ [KEY_PAUSECD] = "PauseCD", [KEY_PROG3] = "Prog3",
+ [KEY_PROG4] = "Prog4", [KEY_SUSPEND] = "Suspend",
+ [KEY_CLOSE] = "Close", [KEY_PLAY] = "Play",
+ [KEY_FASTFORWARD] = "FastForward", [KEY_BASSBOOST] = "BassBoost",
+ [KEY_PRINT] = "Print", [KEY_HP] = "HP",
+ [KEY_CAMERA] = "Camera", [KEY_SOUND] = "Sound",
+ [KEY_QUESTION] = "Question", [KEY_EMAIL] = "Email",
+ [KEY_CHAT] = "Chat", [KEY_SEARCH] = "Search",
+ [KEY_CONNECT] = "Connect", [KEY_FINANCE] = "Finance",
+ [KEY_SPORT] = "Sport", [KEY_SHOP] = "Shop",
+ [KEY_ALTERASE] = "AlternateErase", [KEY_CANCEL] = "Cancel",
+ [KEY_BRIGHTNESSDOWN] = "BrightnessDown", [KEY_BRIGHTNESSUP] = "BrightnessUp",
+ [KEY_MEDIA] = "Media", [KEY_UNKNOWN] = "Unknown",
+ [BTN_0] = "Btn0", [BTN_1] = "Btn1",
+ [BTN_2] = "Btn2", [BTN_3] = "Btn3",
+ [BTN_4] = "Btn4", [BTN_5] = "Btn5",
+ [BTN_6] = "Btn6", [BTN_7] = "Btn7",
+ [BTN_8] = "Btn8", [BTN_9] = "Btn9",
+ [BTN_LEFT] = "LeftBtn", [BTN_RIGHT] = "RightBtn",
+ [BTN_MIDDLE] = "MiddleBtn", [BTN_SIDE] = "SideBtn",
+ [BTN_EXTRA] = "ExtraBtn", [BTN_FORWARD] = "ForwardBtn",
+ [BTN_BACK] = "BackBtn", [BTN_TASK] = "TaskBtn",
+ [BTN_TRIGGER] = "Trigger", [BTN_THUMB] = "ThumbBtn",
+ [BTN_THUMB2] = "ThumbBtn2", [BTN_TOP] = "TopBtn",
+ [BTN_TOP2] = "TopBtn2", [BTN_PINKIE] = "PinkieBtn",
+ [BTN_BASE] = "BaseBtn", [BTN_BASE2] = "BaseBtn2",
+ [BTN_BASE3] = "BaseBtn3", [BTN_BASE4] = "BaseBtn4",
+ [BTN_BASE5] = "BaseBtn5", [BTN_BASE6] = "BaseBtn6",
+ [BTN_DEAD] = "BtnDead", [BTN_A] = "BtnA",
+ [BTN_B] = "BtnB", [BTN_C] = "BtnC",
+ [BTN_X] = "BtnX", [BTN_Y] = "BtnY",
+ [BTN_Z] = "BtnZ", [BTN_TL] = "BtnTL",
+ [BTN_TR] = "BtnTR", [BTN_TL2] = "BtnTL2",
+ [BTN_TR2] = "BtnTR2", [BTN_SELECT] = "BtnSelect",
+ [BTN_START] = "BtnStart", [BTN_MODE] = "BtnMode",
+ [BTN_THUMBL] = "BtnThumbL", [BTN_THUMBR] = "BtnThumbR",
+ [BTN_TOOL_PEN] = "ToolPen", [BTN_TOOL_RUBBER] = "ToolRubber",
+ [BTN_TOOL_BRUSH] = "ToolBrush", [BTN_TOOL_PENCIL] = "ToolPencil",
+ [BTN_TOOL_AIRBRUSH] = "ToolAirbrush", [BTN_TOOL_FINGER] = "ToolFinger",
+ [BTN_TOOL_MOUSE] = "ToolMouse", [BTN_TOOL_LENS] = "ToolLens",
+ [BTN_TOUCH] = "Touch", [BTN_STYLUS] = "Stylus",
+ [BTN_STYLUS2] = "Stylus2", [BTN_TOOL_DOUBLETAP] = "ToolDoubleTap",
+ [BTN_TOOL_TRIPLETAP] = "ToolTripleTap", [BTN_GEAR_DOWN] = "WheelBtn",
+ [BTN_GEAR_UP] = "Gear up", [KEY_OK] = "Ok",
+ [KEY_SELECT] = "Select", [KEY_GOTO] = "Goto",
+ [KEY_CLEAR] = "Clear", [KEY_POWER2] = "Power2",
+ [KEY_OPTION] = "Option", [KEY_INFO] = "Info",
+ [KEY_TIME] = "Time", [KEY_VENDOR] = "Vendor",
+ [KEY_ARCHIVE] = "Archive", [KEY_PROGRAM] = "Program",
+ [KEY_CHANNEL] = "Channel", [KEY_FAVORITES] = "Favorites",
+ [KEY_EPG] = "EPG", [KEY_PVR] = "PVR",
+ [KEY_MHP] = "MHP", [KEY_LANGUAGE] = "Language",
+ [KEY_TITLE] = "Title", [KEY_SUBTITLE] = "Subtitle",
+ [KEY_ANGLE] = "Angle", [KEY_ZOOM] = "Zoom",
+ [KEY_MODE] = "Mode", [KEY_KEYBOARD] = "Keyboard",
+ [KEY_SCREEN] = "Screen", [KEY_PC] = "PC",
+ [KEY_TV] = "TV", [KEY_TV2] = "TV2",
+ [KEY_VCR] = "VCR", [KEY_VCR2] = "VCR2",
+ [KEY_SAT] = "Sat", [KEY_SAT2] = "Sat2",
+ [KEY_CD] = "CD", [KEY_TAPE] = "Tape",
+ [KEY_RADIO] = "Radio", [KEY_TUNER] = "Tuner",
+ [KEY_PLAYER] = "Player", [KEY_TEXT] = "Text",
+ [KEY_DVD] = "DVD", [KEY_AUX] = "Aux",
+ [KEY_MP3] = "MP3", [KEY_AUDIO] = "Audio",
+ [KEY_VIDEO] = "Video", [KEY_DIRECTORY] = "Directory",
+ [KEY_LIST] = "List", [KEY_MEMO] = "Memo",
+ [KEY_CALENDAR] = "Calendar", [KEY_RED] = "Red",
+ [KEY_GREEN] = "Green", [KEY_YELLOW] = "Yellow",
+ [KEY_BLUE] = "Blue", [KEY_CHANNELUP] = "ChannelUp",
+ [KEY_CHANNELDOWN] = "ChannelDown", [KEY_FIRST] = "First",
+ [KEY_LAST] = "Last", [KEY_AB] = "AB",
+ [KEY_NEXT] = "Next", [KEY_RESTART] = "Restart",
+ [KEY_SLOW] = "Slow", [KEY_SHUFFLE] = "Shuffle",
+ [KEY_BREAK] = "Break", [KEY_PREVIOUS] = "Previous",
+ [KEY_DIGITS] = "Digits", [KEY_TEEN] = "TEEN",
+ [KEY_TWEN] = "TWEN", [KEY_DEL_EOL] = "DeleteEOL",
+ [KEY_DEL_EOS] = "DeleteEOS", [KEY_INS_LINE] = "InsertLine",
+ [KEY_DEL_LINE] = "DeleteLine",
+ [KEY_SEND] = "Send", [KEY_REPLY] = "Reply",
+ [KEY_FORWARDMAIL] = "ForwardMail", [KEY_SAVE] = "Save",
+ [KEY_DOCUMENTS] = "Documents",
+ [KEY_FN] = "Fn", [KEY_FN_ESC] = "Fn+ESC",
+ [KEY_FN_1] = "Fn+1", [KEY_FN_2] = "Fn+2",
+ [KEY_FN_B] = "Fn+B", [KEY_FN_D] = "Fn+D",
+ [KEY_FN_E] = "Fn+E", [KEY_FN_F] = "Fn+F",
+ [KEY_FN_S] = "Fn+S",
+ [KEY_FN_F1] = "Fn+F1", [KEY_FN_F2] = "Fn+F2",
+ [KEY_FN_F3] = "Fn+F3", [KEY_FN_F4] = "Fn+F4",
+ [KEY_FN_F5] = "Fn+F5", [KEY_FN_F6] = "Fn+F6",
+ [KEY_FN_F7] = "Fn+F7", [KEY_FN_F8] = "Fn+F8",
+ [KEY_FN_F9] = "Fn+F9", [KEY_FN_F10] = "Fn+F10",
+ [KEY_FN_F11] = "Fn+F11", [KEY_FN_F12] = "Fn+F12",
+ [KEY_KBDILLUMTOGGLE] = "KbdIlluminationToggle",
+ [KEY_KBDILLUMDOWN] = "KbdIlluminationDown",
+ [KEY_KBDILLUMUP] = "KbdIlluminationUp",
+ [KEY_SWITCHVIDEOMODE] = "SwitchVideoMode",
+};
+
+static char *relatives[REL_MAX + 1] = {
+ [REL_X] = "X", [REL_Y] = "Y",
+ [REL_Z] = "Z", [REL_RX] = "Rx",
+ [REL_RY] = "Ry", [REL_RZ] = "Rz",
+ [REL_HWHEEL] = "HWheel", [REL_DIAL] = "Dial",
+ [REL_WHEEL] = "Wheel", [REL_MISC] = "Misc",
+};
+
+static char *absolutes[ABS_MAX + 1] = {
+ [ABS_X] = "X", [ABS_Y] = "Y",
+ [ABS_Z] = "Z", [ABS_RX] = "Rx",
+ [ABS_RY] = "Ry", [ABS_RZ] = "Rz",
+ [ABS_THROTTLE] = "Throttle", [ABS_RUDDER] = "Rudder",
+ [ABS_WHEEL] = "Wheel", [ABS_GAS] = "Gas",
+ [ABS_BRAKE] = "Brake", [ABS_HAT0X] = "Hat0X",
+ [ABS_HAT0Y] = "Hat0Y", [ABS_HAT1X] = "Hat1X",
+ [ABS_HAT1Y] = "Hat1Y", [ABS_HAT2X] = "Hat2X",
+ [ABS_HAT2Y] = "Hat2Y", [ABS_HAT3X] = "Hat3X",
+ [ABS_HAT3Y] = "Hat 3Y", [ABS_PRESSURE] = "Pressure",
+ [ABS_DISTANCE] = "Distance", [ABS_TILT_X] = "XTilt",
+ [ABS_TILT_Y] = "YTilt", [ABS_TOOL_WIDTH] = "Tool Width",
+ [ABS_VOLUME] = "Volume", [ABS_MISC] = "Misc",
+};
+
+static char *misc[MSC_MAX + 1] = {
+ [MSC_SERIAL] = "Serial", [MSC_PULSELED] = "Pulseled",
+ [MSC_GESTURE] = "Gesture", [MSC_RAW] = "RawData"
+};
+
+static char *leds[LED_MAX + 1] = {
+ [LED_NUML] = "NumLock", [LED_CAPSL] = "CapsLock",
+ [LED_SCROLLL] = "ScrollLock", [LED_COMPOSE] = "Compose",
+ [LED_KANA] = "Kana", [LED_SLEEP] = "Sleep",
+ [LED_SUSPEND] = "Suspend", [LED_MUTE] = "Mute",
+ [LED_MISC] = "Misc",
+};
+
+static char *repeats[REP_MAX + 1] = {
+ [REP_DELAY] = "Delay", [REP_PERIOD] = "Period"
+};
+
+static char *sounds[SND_MAX + 1] = {
+ [SND_CLICK] = "Click", [SND_BELL] = "Bell",
+ [SND_TONE] = "Tone"
+};
+
+static char **names[EV_MAX + 1] = {
+ [EV_SYN] = syncs, [EV_KEY] = keys,
+ [EV_REL] = relatives, [EV_ABS] = absolutes,
+ [EV_MSC] = misc, [EV_LED] = leds,
+ [EV_SND] = sounds, [EV_REP] = repeats,
+};
+
+void hid_resolv_event(__u8 type, __u16 code) {
+
+ printk("%s.%s", events[type] ? events[type] : "?",
+ names[type] ? (names[type][code] ? names[type][code] : "?") : "?");
+}
+EXPORT_SYMBOL_GPL(hid_resolv_event);
+
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index c7a6833f682..25d180a24fc 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -31,9 +31,8 @@
#include <linux/slab.h>
#include <linux/kernel.h>
-#undef DEBUG
-
#include <linux/hid.h>
+#include <linux/hid-debug.h>
static int hid_pb_fnmode = 1;
module_param_named(pb_fnmode, hid_pb_fnmode, int, 0644);
@@ -252,9 +251,9 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
field->hidinput = hidinput;
-#ifdef DEBUG
+#ifdef CONFIG_HID_DEBUG
printk(KERN_DEBUG "Mapping: ");
- resolv_usage(usage->hid);
+ hid_resolv_usage(usage->hid);
printk(" ---> ");
#endif
@@ -682,14 +681,14 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
field->dpad = usage->code;
}
-#ifdef DEBUG
- resolv_event(usage->type, usage->code);
+ hid_resolv_event(usage->type, usage->code);
+#ifdef CONFIG_HID_DEBUG
printk("\n");
#endif
return;
ignore:
-#ifdef DEBUG
+#ifdef CONFIG_HID_DEBUG
printk("IGNORED\n");
#endif
return;
@@ -804,6 +803,18 @@ int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int
}
EXPORT_SYMBOL_GPL(hidinput_find_field);
+static int hidinput_open(struct input_dev *dev)
+{
+ struct hid_device *hid = dev->private;
+ return hid->hid_open(hid);
+}
+
+static void hidinput_close(struct input_dev *dev)
+{
+ struct hid_device *hid = dev->private;
+ hid->hid_close(hid);
+}
+
/*
* Register the input device; print a message.
* Configure the input layer interface
@@ -816,6 +827,7 @@ int hidinput_connect(struct hid_device *hid)
struct hid_input *hidinput = NULL;
struct input_dev *input_dev;
int i, j, k;
+ int max_report_type = HID_OUTPUT_REPORT;
INIT_LIST_HEAD(&hid->inputs);
@@ -828,7 +840,10 @@ int hidinput_connect(struct hid_device *hid)
if (i == hid->maxcollection)
return -1;
- for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++)
+ if (hid->quirks & HID_QUIRK_SKIP_OUTPUT_REPORTS)
+ max_report_type = HID_INPUT_REPORT;
+
+ for (k = HID_INPUT_REPORT; k <= max_report_type; k++)
list_for_each_entry(report, &hid->report_enum[k].report_list, list) {
if (!report->maxfield)
@@ -846,8 +861,8 @@ int hidinput_connect(struct hid_device *hid)
input_dev->private = hid;
input_dev->event = hid->hidinput_input_event;
- input_dev->open = hid->hidinput_open;
- input_dev->close = hid->hidinput_close;
+ input_dev->open = hidinput_open;
+ input_dev->close = hidinput_close;
input_dev->name = hid->name;
input_dev->phys = hid->phys;
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 891ef6d0b1b..c3d4856fb61 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -73,6 +73,17 @@ config SENSORS_ADM1026
This driver can also be built as a module. If so, the module
will be called adm1026.
+config SENSORS_ADM1029
+ tristate "Analog Devices ADM1029"
+ depends on HWMON && I2C && EXPERIMENTAL
+ help
+ If you say yes here you get support for Analog Devices ADM1029
+ sensor chip.
+ Very rare chip, please let us know you use it.
+
+ This driver can also be built as a module. If so, the module
+ will be called adm1029.
+
config SENSORS_ADM1031
tristate "Analog Devices ADM1031 and compatibles"
depends on HWMON && I2C && EXPERIMENTAL
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 31661124271..4165c27a2f2 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_SENSORS_ABITUGURU) += abituguru.o
obj-$(CONFIG_SENSORS_ADM1021) += adm1021.o
obj-$(CONFIG_SENSORS_ADM1025) += adm1025.o
obj-$(CONFIG_SENSORS_ADM1026) += adm1026.o
+obj-$(CONFIG_SENSORS_ADM1029) += adm1029.o
obj-$(CONFIG_SENSORS_ADM1031) += adm1031.o
obj-$(CONFIG_SENSORS_ADM9240) += adm9240.o
obj-$(CONFIG_SENSORS_AMS) += ams/
diff --git a/drivers/hwmon/abituguru.c b/drivers/hwmon/abituguru.c
index b1dc63e4ac7..bede4d990ea 100644
--- a/drivers/hwmon/abituguru.c
+++ b/drivers/hwmon/abituguru.c
@@ -1267,30 +1267,42 @@ static int __devinit abituguru_probe(struct platform_device *pdev)
printk(KERN_INFO ABIT_UGURU_NAME ": found Abit uGuru\n");
/* Register sysfs hooks */
- data->class_dev = hwmon_device_register(&pdev->dev);
- if (IS_ERR(data->class_dev)) {
- res = PTR_ERR(data->class_dev);
- goto abituguru_probe_error;
- }
for (i = 0; i < sysfs_attr_i; i++)
- device_create_file(&pdev->dev, &data->sysfs_attr[i].dev_attr);
+ if (device_create_file(&pdev->dev,
+ &data->sysfs_attr[i].dev_attr))
+ goto abituguru_probe_error;
for (i = 0; i < ARRAY_SIZE(abituguru_sysfs_attr); i++)
- device_create_file(&pdev->dev,
- &abituguru_sysfs_attr[i].dev_attr);
+ if (device_create_file(&pdev->dev,
+ &abituguru_sysfs_attr[i].dev_attr))
+ goto abituguru_probe_error;
- return 0;
+ data->class_dev = hwmon_device_register(&pdev->dev);
+ if (!IS_ERR(data->class_dev))
+ return 0; /* success */
+ res = PTR_ERR(data->class_dev);
abituguru_probe_error:
+ for (i = 0; data->sysfs_attr[i].dev_attr.attr.name; i++)
+ device_remove_file(&pdev->dev, &data->sysfs_attr[i].dev_attr);
+ for (i = 0; i < ARRAY_SIZE(abituguru_sysfs_attr); i++)
+ device_remove_file(&pdev->dev,
+ &abituguru_sysfs_attr[i].dev_attr);
kfree(data);
return res;
}
static int __devexit abituguru_remove(struct platform_device *pdev)
{
+ int i;
struct abituguru_data *data = platform_get_drvdata(pdev);
platform_set_drvdata(pdev, NULL);
hwmon_device_unregister(data->class_dev);
+ for (i = 0; data->sysfs_attr[i].dev_attr.attr.name; i++)
+ device_remove_file(&pdev->dev, &data->sysfs_attr[i].dev_attr);
+ for (i = 0; i < ARRAY_SIZE(abituguru_sysfs_attr); i++)
+ device_remove_file(&pdev->dev,
+ &abituguru_sysfs_attr[i].dev_attr);
kfree(data);
return 0;
diff --git a/drivers/hwmon/adm1026.c b/drivers/hwmon/adm1026.c
index b4618b2705f..ba80cd3258c 100644
--- a/drivers/hwmon/adm1026.c
+++ b/drivers/hwmon/adm1026.c
@@ -261,7 +261,6 @@ struct pwm_data {
struct adm1026_data {
struct i2c_client client;
struct class_device *class_dev;
- struct mutex lock;
enum chips type;
struct mutex update_lock;
diff --git a/drivers/hwmon/adm1029.c b/drivers/hwmon/adm1029.c
new file mode 100644
index 00000000000..73ce31b3151
--- /dev/null
+++ b/drivers/hwmon/adm1029.c
@@ -0,0 +1,508 @@
+/*
+ * adm1029.c - Part of lm_sensors, Linux kernel modules for hardware monitoring
+ *
+ * Copyright (C) 2006 Corentin LABBE <corentin.labbe@geomatys.fr>
+ *
+ * Based on LM83 Driver by Jean Delvare <khali@linux-fr.org>
+ *
+ * Give only processor, motherboard temperatures and fan tachs
+ * Very rare chip please let me know if you use it
+ *
+ * http://www.analog.com/UploadedFiles/Data_Sheets/ADM1029.pdf
+ *
+ *
+ * This program is free software; 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.
+ *
+ * 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-sysfs.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+
+/*
+ * Addresses to scan
+ */
+
+static unsigned short normal_i2c[] = {
+ 0x28, 0x29, 0x2a,
+ 0x2b, 0x2c, 0x2d,
+ 0x2e, 0x2f, I2C_CLIENT_END
+};
+
+/*
+ * Insmod parameters
+ */
+
+I2C_CLIENT_INSMOD_1(adm1029);
+
+/*
+ * The ADM1029 registers
+ * Manufacturer ID is 0x41 for Analog Devices
+ */
+
+#define ADM1029_REG_MAN_ID 0x0D
+#define ADM1029_REG_CHIP_ID 0x0E
+#define ADM1029_REG_CONFIG 0x01
+#define ADM1029_REG_NB_FAN_SUPPORT 0x02
+
+#define ADM1029_REG_TEMP_DEVICES_INSTALLED 0x06
+
+#define ADM1029_REG_LOCAL_TEMP 0xA0
+#define ADM1029_REG_REMOTE1_TEMP 0xA1
+#define ADM1029_REG_REMOTE2_TEMP 0xA2
+
+#define ADM1029_REG_LOCAL_TEMP_HIGH 0x90
+#define ADM1029_REG_REMOTE1_TEMP_HIGH 0x91
+#define ADM1029_REG_REMOTE2_TEMP_HIGH 0x92
+
+#define ADM1029_REG_LOCAL_TEMP_LOW 0x98
+#define ADM1029_REG_REMOTE1_TEMP_LOW 0x99
+#define ADM1029_REG_REMOTE2_TEMP_LOW 0x9A
+
+#define ADM1029_REG_FAN1 0x70
+#define ADM1029_REG_FAN2 0x71
+
+#define ADM1029_REG_FAN1_MIN 0x78
+#define ADM1029_REG_FAN2_MIN 0x79
+
+#define ADM1029_REG_FAN1_CONFIG 0x68
+#define ADM1029_REG_FAN2_CONFIG 0x69
+
+#define TEMP_FROM_REG(val) ((val) * 1000)
+
+#define DIV_FROM_REG(val) ( 1 << (((val) >> 6) - 1))
+
+/* Registers to be checked by adm1029_update_device() */
+static const u8 ADM1029_REG_TEMP[] = {
+ ADM1029_REG_LOCAL_TEMP,
+ ADM1029_REG_REMOTE1_TEMP,
+ ADM1029_REG_REMOTE2_TEMP,
+ ADM1029_REG_LOCAL_TEMP_HIGH,
+ ADM1029_REG_REMOTE1_TEMP_HIGH,
+ ADM1029_REG_REMOTE2_TEMP_HIGH,
+ ADM1029_REG_LOCAL_TEMP_LOW,
+ ADM1029_REG_REMOTE1_TEMP_LOW,
+ ADM1029_REG_REMOTE2_TEMP_LOW,
+};
+
+static const u8 ADM1029_REG_FAN[] = {
+ ADM1029_REG_FAN1,
+ ADM1029_REG_FAN2,
+ ADM1029_REG_FAN1_MIN,
+ ADM1029_REG_FAN2_MIN,
+};
+
+static const u8 ADM1029_REG_FAN_DIV[] = {
+ ADM1029_REG_FAN1_CONFIG,
+ ADM1029_REG_FAN2_CONFIG,
+};
+
+/*
+ * Functions declaration
+ */
+
+static int adm1029_attach_adapter(struct i2c_adapter *adapter);
+static int adm1029_detect(struct i2c_adapter *adapter, int address, int kind);
+static int adm1029_detach_client(struct i2c_client *client);
+static struct adm1029_data *adm1029_update_device(struct device *dev);
+static int adm1029_init_client(struct i2c_client *client);
+
+/*
+ * Driver data (common to all clients)
+ */
+
+static struct i2c_driver adm1029_driver = {
+ .driver = {
+ .name = "adm1029",
+ },
+ .attach_adapter = adm1029_attach_adapter,
+ .detach_client = adm1029_detach_client,
+};
+
+/*
+ * Client data (each client gets its own)
+ */
+
+struct adm1029_data {
+ struct i2c_client client;
+ struct class_device *class_dev;
+ struct mutex update_lock;
+ char valid; /* zero until following fields are valid */
+ unsigned long last_updated; /* in jiffies */
+
+ /* registers values, signed for temperature, unsigned for other stuff */
+ s8 temp[ARRAY_SIZE(ADM1029_REG_TEMP)];
+ u8 fan[ARRAY_SIZE(ADM1029_REG_FAN)];
+ u8 fan_div[ARRAY_SIZE(ADM1029_REG_FAN_DIV)];
+};
+
+/*
+ * Sysfs stuff
+ */
+
+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 adm1029_data *data = adm1029_update_device(dev);
+ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index]));
+}
+
+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 adm1029_data *data = adm1029_update_device(dev);
+ u16 val;
+ if (data->fan[attr->index] == 0 || data->fan_div[attr->index] == 0
+ || data->fan[attr->index] == 255) {
+ return sprintf(buf, "0\n");
+ }
+
+ val = 1880 * 120 / DIV_FROM_REG(data->fan_div[attr->index])
+ / data->fan[attr->index];
+ return sprintf(buf, "%d\n", val);
+}
+
+static ssize_t
+show_fan_div(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct adm1029_data *data = adm1029_update_device(dev);
+ if (data->fan_div[attr->index] == 0)
+ return sprintf(buf, "0\n");
+ return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[attr->index]));
+}
+
+static ssize_t set_fan_div(struct device *dev,
+ struct device_attribute *devattr, const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adm1029_data *data = i2c_get_clientdata(client);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ long val = simple_strtol(buf, NULL, 10);
+ u8 reg;
+
+ mutex_lock(&data->update_lock);
+
+ /*Read actual config */
+ reg = i2c_smbus_read_byte_data(client,
+ ADM1029_REG_FAN_DIV[attr->index]);
+
+ switch (val) {
+ case 1:
+ val = 1;
+ break;
+ case 2:
+ val = 2;
+ break;
+ case 4:
+ val = 3;
+ break;
+ default:
+ mutex_unlock(&data->update_lock);
+ dev_err(&client->dev, "fan_div value %ld not "
+ "supported. Choose one of 1, 2 or 4!\n", val);
+ return -EINVAL;
+ }
+ /* Update the value */
+ reg = (reg & 0x3F) | (val << 6);
+
+ /* Write value */
+ i2c_smbus_write_byte_data(client,
+ ADM1029_REG_FAN_DIV[attr->index], reg);
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+/*
+Access rights on sysfs, S_IRUGO stand for Is Readable by User, Group and Others
+ S_IWUSR stand for Is Writable by User
+*/
+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_max, S_IRUGO, show_temp, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO, show_temp, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp3_max, S_IRUGO, show_temp, NULL, 5);
+
+static SENSOR_DEVICE_ATTR(temp1_min, S_IRUGO, show_temp, NULL, 6);
+static SENSOR_DEVICE_ATTR(temp2_min, S_IRUGO, show_temp, NULL, 7);
+static SENSOR_DEVICE_ATTR(temp3_min, S_IRUGO, show_temp, NULL, 8);
+
+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(fan1_min, S_IRUGO, show_fan, NULL, 2);
+static SENSOR_DEVICE_ATTR(fan2_min, S_IRUGO, show_fan, NULL, 3);
+
+static SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR,
+ show_fan_div, set_fan_div, 0);
+static SENSOR_DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR,
+ show_fan_div, set_fan_div, 1);
+
+static struct attribute *adm1029_attributes[] = {
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_min.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_min.dev_attr.attr,
+ &sensor_dev_attr_temp2_max.dev_attr.attr,
+ &sensor_dev_attr_temp3_input.dev_attr.attr,
+ &sensor_dev_attr_temp3_min.dev_attr.attr,
+ &sensor_dev_attr_temp3_max.dev_attr.attr,
+ &sensor_dev_attr_fan1_input.dev_attr.attr,
+ &sensor_dev_attr_fan2_input.dev_attr.attr,
+ &sensor_dev_attr_fan1_min.dev_attr.attr,
+ &sensor_dev_attr_fan2_min.dev_attr.attr,
+ &sensor_dev_attr_fan1_div.dev_attr.attr,
+ &sensor_dev_attr_fan2_div.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group adm1029_group = {
+ .attrs = adm1029_attributes,
+};
+
+/*
+ * Real code
+ */
+
+static int adm1029_attach_adapter(struct i2c_adapter *adapter)
+{
+ if (!(adapter->class & I2C_CLASS_HWMON))
+ return 0;
+ return i2c_probe(adapter, &addr_data, adm1029_detect);
+}
+
+/*
+ * The following function does more than just detection. If detection
+ * succeeds, it also registers the new chip.
+ */
+
+static int adm1029_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+ struct i2c_client *client;
+ struct adm1029_data *data;
+ int err = 0;
+ const char *name = "";
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ goto exit;
+
+ if (!(data = kzalloc(sizeof(struct adm1029_data), GFP_KERNEL))) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ client = &data->client;
+ i2c_set_clientdata(client, data);
+ client->addr = address;
+ client->adapter = adapter;
+ client->driver = &adm1029_driver;
+
+ /* Now we do the detection and identification. A negative kind
+ * means that the driver was loaded with no force parameter
+ * (default), so we must both detect and identify the chip
+ * (actually there is only one possible kind of chip for now, adm1029).
+ * A zero kind means that the driver was loaded with the force
+ * parameter, the detection step shall be skipped. A positive kind
+ * means that the driver was loaded with the force parameter and a
+ * given kind of chip is requested, so both the detection and the
+ * identification steps are skipped. */
+
+ /* Default to an adm1029 if forced */
+ if (kind == 0)
+ kind = adm1029;
+
+ /* ADM1029 doesn't have CHIP ID, check just MAN ID
+ * For better detection we check also ADM1029_TEMP_DEVICES_INSTALLED,
+ * ADM1029_REG_NB_FAN_SUPPORT and compare it with possible values
+ * documented
+ */
+
+ if (kind <= 0) { /* identification */
+ u8 man_id, chip_id, temp_devices_installed, nb_fan_support;
+
+ man_id = i2c_smbus_read_byte_data(client, ADM1029_REG_MAN_ID);
+ chip_id = i2c_smbus_read_byte_data(client, ADM1029_REG_CHIP_ID);
+ temp_devices_installed = i2c_smbus_read_byte_data(client,
+ ADM1029_REG_TEMP_DEVICES_INSTALLED);
+ nb_fan_support = i2c_smbus_read_byte_data(client,
+ ADM1029_REG_NB_FAN_SUPPORT);
+ /* 0x41 is Analog Devices */
+ if (man_id == 0x41 && (temp_devices_installed & 0xf9) == 0x01
+ && nb_fan_support == 0x03) {
+ if ((chip_id & 0xF0) == 0x00) {
+ kind = adm1029;
+ } else {
+ /* There are no "official" CHIP ID, so actually
+ * we use Major/Minor revision for that */
+ printk(KERN_INFO
+ "adm1029: Unknown major revision %x, "
+ "please let us know\n", chip_id);
+ }
+ }
+
+ if (kind <= 0) { /* identification failed */
+ pr_debug("adm1029: Unsupported chip (man_id=0x%02X, "
+ "chip_id=0x%02X)\n", man_id, chip_id);
+ goto exit_free;
+ }
+ }
+
+ if (kind == adm1029) {
+ name = "adm1029";
+ }
+
+ /* We can fill in the remaining client fields */
+ strlcpy(client->name, name, I2C_NAME_SIZE);
+ mutex_init(&data->update_lock);
+
+ /* Tell the I2C layer a new client has arrived */
+ if ((err = i2c_attach_client(client)))
+ goto exit_free;
+
+ /*
+ * Initialize the ADM1029 chip
+ * Check config register
+ */
+ if (adm1029_init_client(client) == 0)
+ goto exit_detach;
+
+ /* Register sysfs hooks */
+ if ((err = sysfs_create_group(&client->dev.kobj, &adm1029_group)))
+ goto exit_detach;
+
+ data->class_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_remove_files;
+ }
+
+ return 0;
+
+ exit_remove_files:
+ sysfs_remove_group(&client->dev.kobj, &adm1029_group);
+ exit_detach:
+ i2c_detach_client(client);
+ exit_free:
+ kfree(data);
+ exit:
+ return err;
+}
+
+static int adm1029_init_client(struct i2c_client *client)
+{
+ u8 config;
+ config = i2c_smbus_read_byte_data(client, ADM1029_REG_CONFIG);
+ if ((config & 0x10) == 0) {
+ i2c_smbus_write_byte_data(client, ADM1029_REG_CONFIG,
+ config | 0x10);
+ }
+ /* recheck config */
+ config = i2c_smbus_read_byte_data(client, ADM1029_REG_CONFIG);
+ if ((config & 0x10) == 0) {
+ dev_err(&client->dev, "Initialization failed!\n");
+ return 0;
+ }
+ return 1;
+}
+
+static int adm1029_detach_client(struct i2c_client *client)
+{
+ struct adm1029_data *data = i2c_get_clientdata(client);
+ int err;
+
+ hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &adm1029_group);
+
+ if ((err = i2c_detach_client(client)))
+ return err;
+
+ kfree(data);
+ return 0;
+}
+
+/*
+function that update the status of the chips (temperature for exemple)
+*/
+static struct adm1029_data *adm1029_update_device(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adm1029_data *data = i2c_get_clientdata(client);
+
+ mutex_lock(&data->update_lock);
+ /*
+ * Use the "cache" Luke, don't recheck values
+ * if there are already checked not a long time later
+ */
+ if (time_after(jiffies, data->last_updated + HZ * 2)
+ || !data->valid) {
+ int nr;
+
+ dev_dbg(&client->dev, "Updating adm1029 data\n");
+
+ for (nr = 0; nr < ARRAY_SIZE(ADM1029_REG_TEMP); nr++) {
+ data->temp[nr] =
+ i2c_smbus_read_byte_data(client,
+ ADM1029_REG_TEMP[nr]);
+ }
+ for (nr = 0; nr < ARRAY_SIZE(ADM1029_REG_FAN); nr++) {
+ data->fan[nr] =
+ i2c_smbus_read_byte_data(client,
+ ADM1029_REG_FAN[nr]);
+ }
+ for (nr = 0; nr < ARRAY_SIZE(ADM1029_REG_FAN_DIV); nr++) {
+ data->fan_div[nr] =
+ i2c_smbus_read_byte_data(client,
+ ADM1029_REG_FAN_DIV[nr]);
+ }
+
+ data->last_updated = jiffies;
+ data->valid = 1;
+ }
+
+ mutex_unlock(&data->update_lock);
+
+ return data;
+}
+
+/*
+ Common module stuff
+*/
+static int __init sensors_adm1029_init(void)
+{
+
+ return i2c_add_driver(&adm1029_driver);
+}
+
+static void __exit sensors_adm1029_exit(void)
+{
+
+ i2c_del_driver(&adm1029_driver);
+}
+
+MODULE_AUTHOR("Corentin LABBE <corentin.labbe@geomatys.fr>");
+MODULE_DESCRIPTION("adm1029 driver");
+MODULE_LICENSE("GPL v2");
+
+module_init(sensors_adm1029_init);
+module_exit(sensors_adm1029_exit);
diff --git a/drivers/hwmon/ams/ams-input.c b/drivers/hwmon/ams/ams-input.c
index f126aa48513..18210164e30 100644
--- a/drivers/hwmon/ams/ams-input.c
+++ b/drivers/hwmon/ams/ams-input.c
@@ -153,7 +153,7 @@ int ams_input_init(void)
}
/* Call with ams_info.lock held! */
-void ams_input_exit()
+void ams_input_exit(void)
{
ams_input_disable();
device_remove_file(&ams_info.of_dev->dev, &dev_attr_joystick);
diff --git a/drivers/hwmon/f71805f.c b/drivers/hwmon/f71805f.c
index a272cae8f60..7c297348712 100644
--- a/drivers/hwmon/f71805f.c
+++ b/drivers/hwmon/f71805f.c
@@ -146,7 +146,6 @@ superio_exit(int base)
struct f71805f_data {
unsigned short addr;
const char *name;
- struct mutex lock;
struct class_device *class_dev;
struct mutex update_lock;
@@ -271,50 +270,42 @@ static inline u8 temp_to_reg(long val)
* Device I/O access
*/
+/* Must be called with data->update_lock held, except during initialization */
static u8 f71805f_read8(struct f71805f_data *data, u8 reg)
{
- u8 val;
-
- mutex_lock(&data->lock);
outb(reg, data->addr + ADDR_REG_OFFSET);
- val = inb(data->addr + DATA_REG_OFFSET);
- mutex_unlock(&data->lock);
-
- return val;
+ return inb(data->addr + DATA_REG_OFFSET);
}
+/* Must be called with data->update_lock held, except during initialization */
static void f71805f_write8(struct f71805f_data *data, u8 reg, u8 val)
{
- mutex_lock(&data->lock);
outb(reg, data->addr + ADDR_REG_OFFSET);
outb(val, data->addr + DATA_REG_OFFSET);
- mutex_unlock(&data->lock);
}
/* It is important to read the MSB first, because doing so latches the
- value of the LSB, so we are sure both bytes belong to the same value. */
+ value of the LSB, so we are sure both bytes belong to the same value.
+ Must be called with data->update_lock held, except during initialization */
static u16 f71805f_read16(struct f71805f_data *data, u8 reg)
{
u16 val;
- mutex_lock(&data->lock);
outb(reg, data->addr + ADDR_REG_OFFSET);
val = inb(data->addr + DATA_REG_OFFSET) << 8;
outb(++reg, data->addr + ADDR_REG_OFFSET);
val |= inb(data->addr + DATA_REG_OFFSET);
- mutex_unlock(&data->lock);
return val;
}
+/* Must be called with data->update_lock held, except during initialization */
static void f71805f_write16(struct f71805f_data *data, u8 reg, u16 val)
{
- mutex_lock(&data->lock);
outb(reg, data->addr + ADDR_REG_OFFSET);
outb(val >> 8, data->addr + DATA_REG_OFFSET);
outb(++reg, data->addr + ADDR_REG_OFFSET);
outb(val & 0xff, data->addr + DATA_REG_OFFSET);
- mutex_unlock(&data->lock);
}
static struct f71805f_data *f71805f_update_device(struct device *dev)
@@ -1150,7 +1141,6 @@ static int __devinit f71805f_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
data->addr = res->start;
- mutex_init(&data->lock);
data->name = names[sio_data->kind];
mutex_init(&data->update_lock);
@@ -1300,14 +1290,11 @@ static int __init f71805f_device_add(unsigned short address,
if (err) {
printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
err);
- goto exit_kfree_data;
+ goto exit_device_put;
}
return 0;
-exit_kfree_data:
- kfree(pdev->dev.platform_data);
- pdev->dev.platform_data = NULL;
exit_device_put:
platform_device_put(pdev);
exit:
@@ -1400,10 +1387,7 @@ exit:
static void __exit f71805f_exit(void)
{
- kfree(pdev->dev.platform_data);
- pdev->dev.platform_data = NULL;
platform_device_unregister(pdev);
-
platform_driver_unregister(&f71805f_driver);
}
diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c
index 106fa01cdb6..affcc00764d 100644
--- a/drivers/hwmon/hwmon.c
+++ b/drivers/hwmon/hwmon.c
@@ -101,7 +101,7 @@ static void __exit hwmon_exit(void)
class_destroy(hwmon_class);
}
-module_init(hwmon_init);
+subsys_initcall(hwmon_init);
module_exit(hwmon_exit);
EXPORT_SYMBOL_GPL(hwmon_device_register);
diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index 1ed8b7e2c35..62afc63708a 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -202,15 +202,23 @@ static int DIV_TO_REG(int val)
}
#define DIV_FROM_REG(val) (1 << (val))
+static const unsigned int pwm_freq[8] = {
+ 48000000 / 128,
+ 24000000 / 128,
+ 12000000 / 128,
+ 8000000 / 128,
+ 6000000 / 128,
+ 3000000 / 128,
+ 1500000 / 128,
+ 750000 / 128,
+};
+
-/* For each registered IT87, we need to keep some data in memory. That
- data is pointed to by it87_list[NR]->data. The structure itself is
- dynamically allocated, at the same time when a new it87 client is
- allocated. */
+/* For each registered chip, we need to keep some data in memory.
+ The structure is dynamically allocated. */
struct it87_data {
struct i2c_client client;
struct class_device *class_dev;
- struct mutex lock;
enum chips type;
struct mutex update_lock;
@@ -232,6 +240,7 @@ struct it87_data {
u8 vrm;
u32 alarms; /* Register encoding, combined */
u8 fan_main_ctrl; /* Register value */
+ u8 fan_ctl; /* Register value */
u8 manual_pwm_ctl[3]; /* manual PWM value set by user */
};
@@ -519,6 +528,14 @@ static ssize_t show_pwm(struct device *dev, struct device_attribute *attr,
struct it87_data *data = it87_update_device(dev);
return sprintf(buf,"%d\n", data->manual_pwm_ctl[nr]);
}
+static ssize_t show_pwm_freq(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct it87_data *data = it87_update_device(dev);
+ int index = (data->fan_ctl >> 4) & 0x07;
+
+ return sprintf(buf, "%u\n", pwm_freq[index]);
+}
static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
@@ -528,9 +545,10 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
struct i2c_client *client = to_i2c_client(dev);
struct it87_data *data = i2c_get_clientdata(client);
int val = simple_strtol(buf, NULL, 10);
- u8 reg = it87_read_value(client, IT87_REG_FAN_DIV);
+ u8 reg;
mutex_lock(&data->update_lock);
+ reg = it87_read_value(client, 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;
@@ -639,6 +657,28 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
mutex_unlock(&data->update_lock);
return count;
}
+static ssize_t set_pwm_freq(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct it87_data *data = i2c_get_clientdata(client);
+ unsigned long val = simple_strtoul(buf, NULL, 10);
+ int i;
+
+ /* Search for the nearest available frequency */
+ for (i = 0; i < 7; i++) {
+ if (val > (pwm_freq[i] + pwm_freq[i+1]) / 2)
+ break;
+ }
+
+ mutex_lock(&data->update_lock);
+ data->fan_ctl = it87_read_value(client, IT87_REG_FAN_CTL) & 0x8f;
+ data->fan_ctl |= i << 4;
+ it87_write_value(client, IT87_REG_FAN_CTL, data->fan_ctl);
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
#define show_fan_offset(offset) \
static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \
@@ -656,7 +696,10 @@ show_fan_offset(3);
static SENSOR_DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \
show_pwm_enable, set_pwm_enable, offset - 1); \
static SENSOR_DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \
- show_pwm, set_pwm, offset - 1);
+ 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_offset(1);
show_pwm_offset(2);
@@ -904,7 +947,6 @@ static int it87_detect(struct i2c_adapter *adapter)
}
new_client = &data->client;
- mutex_init(&data->lock);
i2c_set_clientdata(new_client, data);
new_client->addr = isa_address;
new_client->adapter = adapter;
@@ -1021,7 +1063,13 @@ static int it87_detect(struct i2c_adapter *adapter)
|| (err = device_create_file(&new_client->dev,
&sensor_dev_attr_pwm2.dev_attr))
|| (err = device_create_file(&new_client->dev,
- &sensor_dev_attr_pwm3.dev_attr)))
+ &sensor_dev_attr_pwm3.dev_attr))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_pwm1_freq))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_pwm2_freq))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_pwm3_freq)))
goto ERROR4;
}
@@ -1076,33 +1124,22 @@ static int it87_detach_client(struct i2c_client *client)
return 0;
}
-/* ISA access must be locked explicitly!
+/* Must be called with data->update_lock held, except during initialization.
We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks,
would slow down the IT87 access and should not be necessary. */
static int it87_read_value(struct i2c_client *client, u8 reg)
{
- struct it87_data *data = i2c_get_clientdata(client);
- int res;
-
- mutex_lock(&data->lock);
outb_p(reg, client->addr + IT87_ADDR_REG_OFFSET);
- res = inb_p(client->addr + IT87_DATA_REG_OFFSET);
- mutex_unlock(&data->lock);
-
- return res;
+ return inb_p(client->addr + IT87_DATA_REG_OFFSET);
}
-/* ISA access must be locked explicitly!
+/* Must be called with data->update_lock held, except during initialization.
We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks,
would slow down the IT87 access and should not be necessary. */
static void it87_write_value(struct i2c_client *client, u8 reg, u8 value)
{
- struct it87_data *data = i2c_get_clientdata(client);
-
- mutex_lock(&data->lock);
outb_p(reg, client->addr + IT87_ADDR_REG_OFFSET);
outb_p(value, client->addr + IT87_DATA_REG_OFFSET);
- mutex_unlock(&data->lock);
}
/* Return 1 if and only if the PWM interface is safe to use */
@@ -1316,6 +1353,7 @@ static struct it87_data *it87_update_device(struct device *dev)
(it87_read_value(client, IT87_REG_ALARM2) << 8) |
(it87_read_value(client, IT87_REG_ALARM3) << 16);
data->fan_main_ctrl = it87_read_value(client, IT87_REG_FAN_MAIN_CTRL);
+ data->fan_ctl = it87_read_value(client, IT87_REG_FAN_CTL);
data->sensor = it87_read_value(client, IT87_REG_TEMP_ENABLE);
/* The 8705 does not have VID capability */
diff --git a/drivers/hwmon/lm70.c b/drivers/hwmon/lm70.c
index 6ba84731b9c..7eaae3834e1 100644
--- a/drivers/hwmon/lm70.c
+++ b/drivers/hwmon/lm70.c
@@ -126,7 +126,7 @@ out_dev_reg_failed:
return status;
}
-static int __exit lm70_remove(struct spi_device *spi)
+static int __devexit lm70_remove(struct spi_device *spi)
{
struct lm70 *p_lm70 = dev_get_drvdata(&spi->dev);
diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c
index 73bc2ffc598..886786c3391 100644
--- a/drivers/hwmon/lm78.c
+++ b/drivers/hwmon/lm78.c
@@ -125,10 +125,8 @@ static inline int TEMP_FROM_REG(s8 val)
bad. Quite a lot of bookkeeping is done. A real driver can often cut
some corners. */
-/* For each registered LM78, we need to keep some data in memory. That
- data is pointed to by lm78_list[NR]->data. The structure itself is
- dynamically allocated, at the same time when a new lm78 client is
- allocated. */
+/* For each registered chip, we need to keep some data in memory.
+ The structure is dynamically allocated. */
struct lm78_data {
struct i2c_client client;
struct class_device *class_dev;
diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c
index 2c3293cf69d..20a8c648280 100644
--- a/drivers/hwmon/lm85.c
+++ b/drivers/hwmon/lm85.c
@@ -298,11 +298,6 @@ static int ZONE_TO_REG( int zone )
#define LM85_DATA_INTERVAL (HZ + HZ / 2)
#define LM85_CONFIG_INTERVAL (1 * 60 * HZ)
-/* For each registered LM85, we need to keep some data in memory. That
- data is pointed to by lm85_list[NR]->data. The structure itself is
- dynamically allocated, at the same time when a new lm85 client is
- allocated. */
-
/* LM85 can automatically adjust fan speeds based on temperature
* This structure encapsulates an entire Zone config. There are
* three zones (one for each temperature input) on the lm85
@@ -329,10 +324,11 @@ struct lm85_autofan {
u8 min_off; /* Min PWM or OFF below "limit", flag */
};
+/* For each registered chip, we need to keep some data in memory.
+ The structure is dynamically allocated. */
struct lm85_data {
struct i2c_client client;
struct class_device *class_dev;
- struct mutex lock;
enum chips type;
struct mutex update_lock;
diff --git a/drivers/hwmon/sis5595.c b/drivers/hwmon/sis5595.c
index 95a4b5d9eaf..3f400263fc0 100644
--- a/drivers/hwmon/sis5595.c
+++ b/drivers/hwmon/sis5595.c
@@ -162,10 +162,8 @@ static inline u8 DIV_TO_REG(int val)
}
#define DIV_FROM_REG(val) (1 << (val))
-/* For the SIS5595, we need to keep some data in memory. That
- data is pointed to by sis5595_list[NR]->data. The structure itself is
- dynamically allocated, at the time when the new sis5595 client is
- allocated. */
+/* For each registered chip, we need to keep some data in memory.
+ The structure is dynamically allocated. */
struct sis5595_data {
struct i2c_client client;
struct class_device *class_dev;
diff --git a/drivers/hwmon/via686a.c b/drivers/hwmon/via686a.c
index f8acada0537..9a440c8cc52 100644
--- a/drivers/hwmon/via686a.c
+++ b/drivers/hwmon/via686a.c
@@ -292,9 +292,8 @@ static inline long TEMP_FROM_REG10(u16 val)
#define DIV_FROM_REG(val) (1 << (val))
#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1)
-/* For the VIA686A, we need to keep some data in memory.
- The structure is dynamically allocated, at the same time when a new
- via686a client is allocated. */
+/* For each registered chip, we need to keep some data in memory.
+ The structure is dynamically allocated. */
struct via686a_data {
struct i2c_client client;
struct class_device *class_dev;
diff --git a/drivers/hwmon/vt1211.c b/drivers/hwmon/vt1211.c
index 25cc56003d7..89c23d6add7 100644
--- a/drivers/hwmon/vt1211.c
+++ b/drivers/hwmon/vt1211.c
@@ -178,9 +178,10 @@ struct vt1211_data {
* Super-I/O constants and functions
* --------------------------------------------------------------------- */
-/* Configuration & data index port registers */
-#define SIO_REG_CIP 0x2e
-#define SIO_REG_DIP 0x2f
+/* Configuration index port registers
+ * The vt1211 can live at 2 different addresses so we need to probe both */
+#define SIO_REG_CIP1 0x2e
+#define SIO_REG_CIP2 0x4e
/* Configuration registers */
#define SIO_VT1211_LDN 0x07 /* logical device number */
@@ -193,33 +194,33 @@ struct vt1211_data {
/* VT1211 logical device numbers */
#define SIO_VT1211_LDN_HWMON 0x0b /* HW monitor */
-static inline void superio_outb(int reg, int val)
+static inline void superio_outb(int sio_cip, int reg, int val)
{
- outb(reg, SIO_REG_CIP);
- outb(val, SIO_REG_DIP);
+ outb(reg, sio_cip);
+ outb(val, sio_cip + 1);
}
-static inline int superio_inb(int reg)
+static inline int superio_inb(int sio_cip, int reg)
{
- outb(reg, SIO_REG_CIP);
- return inb(SIO_REG_DIP);
+ outb(reg, sio_cip);
+ return inb(sio_cip + 1);
}
-static inline void superio_select(int ldn)
+static inline void superio_select(int sio_cip, int ldn)
{
- outb(SIO_VT1211_LDN, SIO_REG_CIP);
- outb(ldn, SIO_REG_DIP);
+ outb(SIO_VT1211_LDN, sio_cip);
+ outb(ldn, sio_cip + 1);
}
-static inline void superio_enter(void)
+static inline void superio_enter(int sio_cip)
{
- outb(0x87, SIO_REG_CIP);
- outb(0x87, SIO_REG_CIP);
+ outb(0x87, sio_cip);
+ outb(0x87, sio_cip);
}
-static inline void superio_exit(void)
+static inline void superio_exit(int sio_cip)
{
- outb(0xaa, SIO_REG_CIP);
+ outb(0xaa, sio_cip);
}
/* ---------------------------------------------------------------------
@@ -1263,26 +1264,26 @@ EXIT:
return err;
}
-static int __init vt1211_find(unsigned short *address)
+static int __init vt1211_find(int sio_cip, unsigned short *address)
{
int err = -ENODEV;
- superio_enter();
+ superio_enter(sio_cip);
- if (superio_inb(SIO_VT1211_DEVID) != SIO_VT1211_ID) {
+ if (superio_inb(sio_cip, SIO_VT1211_DEVID) != SIO_VT1211_ID) {
goto EXIT;
}
- superio_select(SIO_VT1211_LDN_HWMON);
+ superio_select(sio_cip, SIO_VT1211_LDN_HWMON);
- if ((superio_inb(SIO_VT1211_ACTIVE) & 1) == 0) {
+ if ((superio_inb(sio_cip, SIO_VT1211_ACTIVE) & 1) == 0) {
printk(KERN_WARNING DRVNAME ": HW monitor is disabled, "
"skipping\n");
goto EXIT;
}
- *address = ((superio_inb(SIO_VT1211_BADDR) << 8) |
- (superio_inb(SIO_VT1211_BADDR + 1))) & 0xff00;
+ *address = ((superio_inb(sio_cip, SIO_VT1211_BADDR) << 8) |
+ (superio_inb(sio_cip, SIO_VT1211_BADDR + 1))) & 0xff00;
if (*address == 0) {
printk(KERN_WARNING DRVNAME ": Base address is not set, "
"skipping\n");
@@ -1291,10 +1292,11 @@ static int __init vt1211_find(unsigned short *address)
err = 0;
printk(KERN_INFO DRVNAME ": Found VT1211 chip at 0x%04x, "
- "revision %u\n", *address, superio_inb(SIO_VT1211_DEVREV));
+ "revision %u\n", *address,
+ superio_inb(sio_cip, SIO_VT1211_DEVREV));
EXIT:
- superio_exit();
+ superio_exit(sio_cip);
return err;
}
@@ -1303,8 +1305,8 @@ static int __init vt1211_init(void)
int err;
unsigned short address = 0;
- err = vt1211_find(&address);
- if (err) {
+ if ((err = vt1211_find(SIO_REG_CIP1, &address)) &&
+ (err = vt1211_find(SIO_REG_CIP2, &address))) {
goto EXIT;
}
diff --git a/drivers/hwmon/vt8231.c b/drivers/hwmon/vt8231.c
index 93f93d4fb8a..a6a4aa0eee1 100644
--- a/drivers/hwmon/vt8231.c
+++ b/drivers/hwmon/vt8231.c
@@ -727,7 +727,6 @@ int vt8231_detect(struct i2c_adapter *adapter)
client->addr = isa_address;
client->adapter = adapter;
client->driver = &vt8231_driver;
- client->dev.parent = &adapter->dev;
/* Fill in the remaining client fields and put into the global list */
strlcpy(client->name, "vt8231", I2C_NAME_SIZE);
diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c
index 212a1558c63..da5828f2dfc 100644
--- a/drivers/hwmon/w83627ehf.c
+++ b/drivers/hwmon/w83627ehf.c
@@ -32,8 +32,10 @@
Supports the following chips:
- Chip #vin #fan #pwm #temp chip_id man_id
- w83627ehf 10 5 4 3 0x88,0xa1 0x5ca3
+ Chip #vin #fan #pwm #temp chip IDs man ID
+ w83627ehf 10 5 4 3 0x8850 0x88 0x5ca3
+ 0x8860 0xa1
+ w83627dhg 9 5 4 3 0xa020 0xc1 0x5ca3
*/
#include <linux/module.h>
@@ -55,8 +57,18 @@ static unsigned short address;
* Super-I/O constants and functions
*/
+/*
+ * The three following globals are initialized in w83627ehf_find(), before
+ * the i2c-isa device is created. Otherwise, they could be stored in
+ * w83627ehf_data. This is ugly, but necessary, and when the driver is next
+ * updated to become a platform driver, the globals will disappear.
+ */
static int REG; /* The register to read/write */
static int VAL; /* The value to read/write */
+/* The w83627ehf/ehg have 10 voltage inputs, but the w83627dhg has 9. This
+ * value is also used in w83627ehf_detect() to export a device name in sysfs
+ * (e.g. w83627ehf or w83627dhg) */
+static int w83627ehf_num_in;
#define W83627EHF_LD_HWM 0x0b
@@ -65,8 +77,10 @@ static int VAL; /* The value to read/write */
#define SIO_REG_ENABLE 0x30 /* Logical device enable */
#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
-#define SIO_W83627EHF_ID 0x8840
-#define SIO_ID_MASK 0xFFC0
+#define SIO_W83627EHF_ID 0x8850
+#define SIO_W83627EHG_ID 0x8860
+#define SIO_W83627DHG_ID 0xa020
+#define SIO_ID_MASK 0xFFF0
static inline void
superio_outb(int reg, int val)
@@ -115,8 +129,12 @@ superio_exit(void)
#define W83627EHF_REG_BANK 0x4E
#define W83627EHF_REG_CONFIG 0x40
-#define W83627EHF_REG_CHIP_ID 0x49
-#define W83627EHF_REG_MAN_ID 0x4F
+
+/* Not currently used:
+ * REG_MAN_ID has the value 0x5ca3 for all supported chips.
+ * REG_CHIP_ID == 0x88/0xa1/0xc1 depending on chip model.
+ * REG_MAN_ID is at port 0x4f
+ * REG_CHIP_ID is at port 0x58 */
static const u16 W83627EHF_REG_FAN[] = { 0x28, 0x29, 0x2a, 0x3f, 0x553 };
static const u16 W83627EHF_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d, 0x3e, 0x55c };
@@ -429,7 +447,7 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
}
/* Measured voltages and limits */
- for (i = 0; i < 10; i++) {
+ for (i = 0; i < w83627ehf_num_in; i++) {
data->in[i] = w83627ehf_read_value(client,
W83627EHF_REG_IN(i));
data->in_min[i] = w83627ehf_read_value(client,
@@ -1121,7 +1139,7 @@ static void w83627ehf_device_remove_files(struct device *dev)
device_remove_file(dev, &sda_sf3_arrays[i].dev_attr);
for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++)
device_remove_file(dev, &sda_sf3_arrays_fan4[i].dev_attr);
- for (i = 0; i < 10; i++) {
+ for (i = 0; i < w83627ehf_num_in; i++) {
device_remove_file(dev, &sda_in_input[i].dev_attr);
device_remove_file(dev, &sda_in_alarm[i].dev_attr);
device_remove_file(dev, &sda_in_min[i].dev_attr);
@@ -1196,7 +1214,11 @@ static int w83627ehf_detect(struct i2c_adapter *adapter)
client->flags = 0;
dev = &client->dev;
- strlcpy(client->name, "w83627ehf", I2C_NAME_SIZE);
+ if (w83627ehf_num_in == 9)
+ strlcpy(client->name, "w83627dhg", I2C_NAME_SIZE);
+ else /* just say ehf. 627EHG is 627EHF in lead-free packaging. */
+ strlcpy(client->name, "w83627ehf", I2C_NAME_SIZE);
+
data->valid = 0;
mutex_init(&data->update_lock);
@@ -1246,7 +1268,7 @@ static int w83627ehf_detect(struct i2c_adapter *adapter)
goto exit_remove;
}
- for (i = 0; i < 10; i++)
+ for (i = 0; i < w83627ehf_num_in; i++)
if ((err = device_create_file(dev, &sda_in_input[i].dev_attr))
|| (err = device_create_file(dev,
&sda_in_alarm[i].dev_attr))
@@ -1340,7 +1362,17 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr)
val = (superio_inb(SIO_REG_DEVID) << 8)
| superio_inb(SIO_REG_DEVID + 1);
- if ((val & SIO_ID_MASK) != SIO_W83627EHF_ID) {
+ switch (val & SIO_ID_MASK) {
+ case SIO_W83627DHG_ID:
+ w83627ehf_num_in = 9;
+ break;
+ case SIO_W83627EHF_ID:
+ case SIO_W83627EHG_ID:
+ w83627ehf_num_in = 10;
+ break;
+ default:
+ printk(KERN_WARNING "w83627ehf: unsupported chip ID: 0x%04x\n",
+ val);
superio_exit();
return -ENODEV;
}
diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c
index dfdc29c7712..d7e240635b3 100644
--- a/drivers/hwmon/w83627hf.c
+++ b/drivers/hwmon/w83627hf.c
@@ -286,9 +286,8 @@ static inline u8 DIV_TO_REG(long val)
return ((u8) i);
}
-/* For each registered chip, we need to keep some data in memory. That
- data is pointed to by w83627hf_list[NR]->data. The structure itself is
- dynamically allocated, at the same time when a new client is allocated. */
+/* For each registered chip, we need to keep some data in memory.
+ The structure is dynamically allocated. */
struct w83627hf_data {
struct i2c_client client;
struct class_device *class_dev;
diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c
index 1232171c3aa..a47da3ec547 100644
--- a/drivers/hwmon/w83781d.c
+++ b/drivers/hwmon/w83781d.c
@@ -221,14 +221,8 @@ DIV_TO_REG(long val, enum chips type)
a bit - except if there could be more than one SMBus. Groan. No solution
for this yet. */
-/* This module may seem overly long and complicated. In fact, it is not so
- bad. Quite a lot of bookkeeping is done. A real driver can often cut
- some corners. */
-
-/* For each registered W83781D, we need to keep some data in memory. That
- data is pointed to by w83781d_list[NR]->data. The structure itself is
- dynamically allocated, at the same time when a new w83781d client is
- allocated. */
+/* For each registered chip, we need to keep some data in memory.
+ The structure is dynamically allocated. */
struct w83781d_data {
struct i2c_client client;
struct class_device *class_dev;
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 9367c4cfe93..4d44a2db29d 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -183,6 +183,7 @@ config I2C_PIIX4
ATI IXP200
ATI IXP300
ATI IXP400
+ ATI SB600
Serverworks OSB4
Serverworks CSB5
Serverworks CSB6
@@ -341,6 +342,13 @@ config I2C_PARPORT_LIGHT
This support is also available as a module. If so, the module
will be called i2c-parport-light.
+config I2C_PASEMI
+ tristate "PA Semi SMBus interface"
+# depends on PPC_PASEMI && I2C && PCI
+ depends on I2C && PCI
+ help
+ Supports the PA Semi PWRficient on-chip SMBus interfaces.
+
config I2C_PROSAVAGE
tristate "S3/VIA (Pro)Savage"
depends on I2C && PCI
@@ -499,11 +507,11 @@ config I2C_VIA
will be called i2c-via.
config I2C_VIAPRO
- tristate "VIA 82C596/82C686/82xx"
+ tristate "VIA VT82C596/82C686/82xx and CX700"
depends on I2C && PCI
help
If you say yes to this option, support will be included for the VIA
- 82C596/82C686/82xx I2C interfaces. Specifically, the following
+ VT82C596 and later SMBus interface. Specifically, the following
chipsets are supported:
VT82C596A/B
VT82C686A/B
@@ -512,6 +520,7 @@ config I2C_VIAPRO
VT8235
VT8237R/A
VT8251
+ CX700
This driver can also be built as a module. If so, the module
will be called i2c-viapro.
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 37196c1d079..03505aa44bb 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_I2C_OCORES) += i2c-ocores.o
obj-$(CONFIG_I2C_OMAP) += i2c-omap.o
obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o
obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o
+obj-$(CONFIG_I2C_PASEMI) += i2c-pasemi.o
obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o
obj-$(CONFIG_I2C_PIIX4) += i2c-piix4.o
obj-$(CONFIG_I2C_PNX) += i2c-pnx.o
diff --git a/drivers/i2c/busses/i2c-ali1535.c b/drivers/i2c/busses/i2c-ali1535.c
index e75d339a348..1e277ba5a9f 100644
--- a/drivers/i2c/busses/i2c-ali1535.c
+++ b/drivers/i2c/busses/i2c-ali1535.c
@@ -57,7 +57,6 @@
#include <linux/pci.h>
#include <linux/kernel.h>
#include <linux/stddef.h>
-#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/i2c.h>
@@ -475,6 +474,7 @@ static const struct i2c_algorithm smbus_algorithm = {
static struct i2c_adapter ali1535_adapter = {
.owner = THIS_MODULE,
+ .id = I2C_HW_SMBUS_ALI1535,
.class = I2C_CLASS_HWMON,
.algo = &smbus_algorithm,
};
@@ -494,7 +494,7 @@ static int __devinit ali1535_probe(struct pci_dev *dev, const struct pci_device_
return -ENODEV;
}
- /* set up the driverfs linkage to our parent device */
+ /* set up the sysfs linkage to our parent device */
ali1535_adapter.dev.parent = &dev->dev;
snprintf(ali1535_adapter.name, I2C_NAME_SIZE,
diff --git a/drivers/i2c/busses/i2c-ali1563.c b/drivers/i2c/busses/i2c-ali1563.c
index 8e1e3f8e40a..6b68074e518 100644
--- a/drivers/i2c/busses/i2c-ali1563.c
+++ b/drivers/i2c/busses/i2c-ali1563.c
@@ -314,35 +314,11 @@ static u32 ali1563_func(struct i2c_adapter * a)
}
-static void ali1563_enable(struct pci_dev * dev)
-{
- u16 ctrl;
-
- pci_read_config_word(dev,ALI1563_SMBBA,&ctrl);
- ctrl |= 0x7;
- pci_write_config_word(dev,ALI1563_SMBBA,ctrl);
-}
-
static int __devinit ali1563_setup(struct pci_dev * dev)
{
u16 ctrl;
pci_read_config_word(dev,ALI1563_SMBBA,&ctrl);
- printk("ali1563: SMBus control = %04x\n",ctrl);
-
- /* Check if device is even enabled first */
- if (!(ctrl & ALI1563_SMB_IOEN)) {
- dev_warn(&dev->dev,"I/O space not enabled, trying manually\n");
- ali1563_enable(dev);
- }
- if (!(ctrl & ALI1563_SMB_IOEN)) {
- dev_warn(&dev->dev,"I/O space still not enabled, giving up\n");
- goto Err;
- }
- if (!(ctrl & ALI1563_SMB_HOSTEN)) {
- dev_warn(&dev->dev,"Host Controller not enabled\n");
- goto Err;
- }
/* SMB I/O Base in high 12 bits and must be aligned with the
* size of the I/O space. */
@@ -351,11 +327,31 @@ static int __devinit ali1563_setup(struct pci_dev * dev)
dev_warn(&dev->dev,"ali1563_smba Uninitialized\n");
goto Err;
}
+
+ /* Check if device is enabled */
+ if (!(ctrl & ALI1563_SMB_HOSTEN)) {
+ dev_warn(&dev->dev, "Host Controller not enabled\n");
+ goto Err;
+ }
+ if (!(ctrl & ALI1563_SMB_IOEN)) {
+ dev_warn(&dev->dev, "I/O space not enabled, trying manually\n");
+ pci_write_config_word(dev, ALI1563_SMBBA,
+ ctrl | ALI1563_SMB_IOEN);
+ pci_read_config_word(dev, ALI1563_SMBBA, &ctrl);
+ if (!(ctrl & ALI1563_SMB_IOEN)) {
+ dev_err(&dev->dev, "I/O space still not enabled, "
+ "giving up\n");
+ goto Err;
+ }
+ }
+
if (!request_region(ali1563_smba, ALI1563_SMB_IOSIZE,
ali1563_pci_driver.name)) {
- dev_warn(&dev->dev,"Could not allocate I/O space");
+ dev_err(&dev->dev, "Could not allocate I/O space at 0x%04x\n",
+ ali1563_smba);
goto Err;
}
+ dev_info(&dev->dev, "Found ALi1563 SMBus at 0x%04x\n", ali1563_smba);
return 0;
Err:
@@ -374,6 +370,7 @@ static const struct i2c_algorithm ali1563_algorithm = {
static struct i2c_adapter ali1563_adapter = {
.owner = THIS_MODULE,
+ .id = I2C_HW_SMBUS_ALI1563,
.class = I2C_CLASS_HWMON,
.algo = &ali1563_algorithm,
};
@@ -384,13 +381,18 @@ static int __devinit ali1563_probe(struct pci_dev * dev,
int error;
if ((error = ali1563_setup(dev)))
- return error;
+ goto exit;
ali1563_adapter.dev.parent = &dev->dev;
sprintf(ali1563_adapter.name,"SMBus ALi 1563 Adapter @ %04x",
ali1563_smba);
if ((error = i2c_add_adapter(&ali1563_adapter)))
- ali1563_shutdown(dev);
- printk("%s: Returning %d\n",__FUNCTION__,error);
+ goto exit_shutdown;
+ return 0;
+
+exit_shutdown:
+ ali1563_shutdown(dev);
+exit:
+ dev_warn(&dev->dev, "ALi1563 SMBus probe failed (%d)\n", error);
return error;
}
diff --git a/drivers/i2c/busses/i2c-ali15x3.c b/drivers/i2c/busses/i2c-ali15x3.c
index 3f11b6e1a34..e47fe01bf42 100644
--- a/drivers/i2c/busses/i2c-ali15x3.c
+++ b/drivers/i2c/busses/i2c-ali15x3.c
@@ -64,7 +64,6 @@
#include <linux/pci.h>
#include <linux/kernel.h>
#include <linux/stddef.h>
-#include <linux/sched.h>
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/i2c.h>
@@ -470,6 +469,7 @@ static const struct i2c_algorithm smbus_algorithm = {
static struct i2c_adapter ali15x3_adapter = {
.owner = THIS_MODULE,
+ .id = I2C_HW_SMBUS_ALI15X3,
.class = I2C_CLASS_HWMON,
.algo = &smbus_algorithm,
};
@@ -489,7 +489,7 @@ static int __devinit ali15x3_probe(struct pci_dev *dev, const struct pci_device_
return -ENODEV;
}
- /* set up the driverfs linkage to our parent device */
+ /* set up the sysfs linkage to our parent device */
ali15x3_adapter.dev.parent = &dev->dev;
snprintf(ali15x3_adapter.name, I2C_NAME_SIZE,
diff --git a/drivers/i2c/busses/i2c-amd756-s4882.c b/drivers/i2c/busses/i2c-amd756-s4882.c
index 08e915730ca..e5e96c81756 100644
--- a/drivers/i2c/busses/i2c-amd756-s4882.c
+++ b/drivers/i2c/busses/i2c-amd756-s4882.c
@@ -184,12 +184,14 @@ static int __init amd756_s4882_init(void)
s4882_algo[0].smbus_xfer = amd756_access_virt0;
s4882_adapter[0] = amd756_smbus;
s4882_adapter[0].algo = s4882_algo;
+ s4882_adapter[0].dev.parent = amd756_smbus.dev.parent;
for (i = 1; i < 5; i++) {
s4882_algo[i] = *(amd756_smbus.algo);
s4882_adapter[i] = amd756_smbus;
sprintf(s4882_adapter[i].name,
"SMBus 8111 adapter (CPU%d)", i-1);
s4882_adapter[i].algo = s4882_algo+i;
+ s4882_adapter[i].dev.parent = amd756_smbus.dev.parent;
}
s4882_algo[1].smbus_xfer = amd756_access_virt1;
s4882_algo[2].smbus_xfer = amd756_access_virt2;
diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c
index 2d21afdc5b1..7490dc1771a 100644
--- a/drivers/i2c/busses/i2c-amd756.c
+++ b/drivers/i2c/busses/i2c-amd756.c
@@ -42,7 +42,6 @@
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/stddef.h>
-#include <linux/sched.h>
#include <linux/ioport.h>
#include <linux/i2c.h>
#include <linux/init.h>
@@ -301,6 +300,7 @@ static const struct i2c_algorithm smbus_algorithm = {
struct i2c_adapter amd756_smbus = {
.owner = THIS_MODULE,
+ .id = I2C_HW_SMBUS_AMD756,
.class = I2C_CLASS_HWMON,
.algo = &smbus_algorithm,
};
@@ -374,7 +374,7 @@ static int __devinit amd756_probe(struct pci_dev *pdev,
dev_dbg(&pdev->dev, "SMBREV = 0x%X\n", temp);
dev_dbg(&pdev->dev, "AMD756_smba = 0x%X\n", amd756_ioport);
- /* set up the driverfs linkage to our parent device */
+ /* set up the sysfs linkage to our parent device */
amd756_smbus.dev.parent = &pdev->dev;
sprintf(amd756_smbus.name, "SMBus %s adapter at %04x",
diff --git a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c
index 0fbc7186c91..e15f9e37716 100644
--- a/drivers/i2c/busses/i2c-amd8111.c
+++ b/drivers/i2c/busses/i2c-amd8111.c
@@ -12,7 +12,6 @@
#include <linux/pci.h>
#include <linux/kernel.h>
#include <linux/stddef.h>
-#include <linux/sched.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/i2c.h>
@@ -76,7 +75,8 @@ static unsigned int amd_ec_wait_write(struct amd_smbus *smbus)
udelay(1);
if (!timeout) {
- dev_warn(&smbus->dev->dev, "Timeout while waiting for IBF to clear\n");
+ dev_warn(&smbus->dev->dev,
+ "Timeout while waiting for IBF to clear\n");
return -1;
}
@@ -91,14 +91,16 @@ static unsigned int amd_ec_wait_read(struct amd_smbus *smbus)
udelay(1);
if (!timeout) {
- dev_warn(&smbus->dev->dev, "Timeout while waiting for OBF to set\n");
+ dev_warn(&smbus->dev->dev,
+ "Timeout while waiting for OBF to set\n");
return -1;
}
return 0;
}
-static unsigned int amd_ec_read(struct amd_smbus *smbus, unsigned char address, unsigned char *data)
+static unsigned int amd_ec_read(struct amd_smbus *smbus, unsigned char address,
+ unsigned char *data)
{
if (amd_ec_wait_write(smbus))
return -1;
@@ -115,7 +117,8 @@ static unsigned int amd_ec_read(struct amd_smbus *smbus, unsigned char address,
return 0;
}
-static unsigned int amd_ec_write(struct amd_smbus *smbus, unsigned char address, unsigned char data)
+static unsigned int amd_ec_write(struct amd_smbus *smbus, unsigned char address,
+ unsigned char data)
{
if (amd_ec_wait_write(smbus))
return -1;
@@ -175,18 +178,19 @@ static unsigned int amd_ec_write(struct amd_smbus *smbus, unsigned char address,
#define AMD_SMB_PRTCL_PEC 0x80
-static s32 amd8111_access(struct i2c_adapter * adap, u16 addr, unsigned short flags,
- char read_write, u8 command, int size, union i2c_smbus_data * data)
+static s32 amd8111_access(struct i2c_adapter * adap, u16 addr,
+ unsigned short flags, char read_write, u8 command, int size,
+ union i2c_smbus_data * data)
{
struct amd_smbus *smbus = adap->algo_data;
unsigned char protocol, len, pec, temp[2];
int i;
- protocol = (read_write == I2C_SMBUS_READ) ? AMD_SMB_PRTCL_READ : AMD_SMB_PRTCL_WRITE;
+ protocol = (read_write == I2C_SMBUS_READ) ? AMD_SMB_PRTCL_READ
+ : AMD_SMB_PRTCL_WRITE;
pec = (flags & I2C_CLIENT_PEC) ? AMD_SMB_PRTCL_PEC : 0;
switch (size) {
-
case I2C_SMBUS_QUICK:
protocol |= AMD_SMB_PRTCL_QUICK;
read_write = I2C_SMBUS_WRITE;
@@ -208,8 +212,10 @@ static s32 amd8111_access(struct i2c_adapter * adap, u16 addr, unsigned short fl
case I2C_SMBUS_WORD_DATA:
amd_ec_write(smbus, AMD_SMB_CMD, command);
if (read_write == I2C_SMBUS_WRITE) {
- amd_ec_write(smbus, AMD_SMB_DATA, data->word);
- amd_ec_write(smbus, AMD_SMB_DATA + 1, data->word >> 8);
+ amd_ec_write(smbus, AMD_SMB_DATA,
+ data->word & 0xff);
+ amd_ec_write(smbus, AMD_SMB_DATA + 1,
+ data->word >> 8);
}
protocol |= AMD_SMB_PRTCL_WORD_DATA | pec;
break;
@@ -217,27 +223,31 @@ static s32 amd8111_access(struct i2c_adapter * adap, u16 addr, unsigned short fl
case I2C_SMBUS_BLOCK_DATA:
amd_ec_write(smbus, AMD_SMB_CMD, command);
if (read_write == I2C_SMBUS_WRITE) {
- len = min_t(u8, data->block[0], 32);
+ len = min_t(u8, data->block[0],
+ I2C_SMBUS_BLOCK_MAX);
amd_ec_write(smbus, AMD_SMB_BCNT, len);
for (i = 0; i < len; i++)
- amd_ec_write(smbus, AMD_SMB_DATA + i, data->block[i + 1]);
+ amd_ec_write(smbus, AMD_SMB_DATA + i,
+ data->block[i + 1]);
}
protocol |= AMD_SMB_PRTCL_BLOCK_DATA | pec;
break;
case I2C_SMBUS_I2C_BLOCK_DATA:
- len = min_t(u8, data->block[0], 32);
+ len = min_t(u8, data->block[0],
+ I2C_SMBUS_BLOCK_MAX);
amd_ec_write(smbus, AMD_SMB_CMD, command);
amd_ec_write(smbus, AMD_SMB_BCNT, len);
if (read_write == I2C_SMBUS_WRITE)
for (i = 0; i < len; i++)
- amd_ec_write(smbus, AMD_SMB_DATA + i, data->block[i + 1]);
+ amd_ec_write(smbus, AMD_SMB_DATA + i,
+ data->block[i + 1]);
protocol |= AMD_SMB_PRTCL_I2C_BLOCK_DATA;
break;
case I2C_SMBUS_PROC_CALL:
amd_ec_write(smbus, AMD_SMB_CMD, command);
- amd_ec_write(smbus, AMD_SMB_DATA, data->word);
+ amd_ec_write(smbus, AMD_SMB_DATA, data->word & 0xff);
amd_ec_write(smbus, AMD_SMB_DATA + 1, data->word >> 8);
protocol = AMD_SMB_PRTCL_PROC_CALL | pec;
read_write = I2C_SMBUS_READ;
@@ -248,7 +258,8 @@ static s32 amd8111_access(struct i2c_adapter * adap, u16 addr, unsigned short fl
amd_ec_write(smbus, AMD_SMB_CMD, command);
amd_ec_write(smbus, AMD_SMB_BCNT, len);
for (i = 0; i < len; i++)
- amd_ec_write(smbus, AMD_SMB_DATA + i, data->block[i + 1]);
+ amd_ec_write(smbus, AMD_SMB_DATA + i,
+ data->block[i + 1]);
protocol = AMD_SMB_PRTCL_BLOCK_PROC_CALL | pec;
read_write = I2C_SMBUS_READ;
break;
@@ -280,7 +291,6 @@ static s32 amd8111_access(struct i2c_adapter * adap, u16 addr, unsigned short fl
return 0;
switch (size) {
-
case I2C_SMBUS_BYTE:
case I2C_SMBUS_BYTE_DATA:
amd_ec_read(smbus, AMD_SMB_DATA, &data->byte);
@@ -296,10 +306,11 @@ static s32 amd8111_access(struct i2c_adapter * adap, u16 addr, unsigned short fl
case I2C_SMBUS_BLOCK_DATA:
case I2C_SMBUS_BLOCK_PROC_CALL:
amd_ec_read(smbus, AMD_SMB_BCNT, &len);
- len = min_t(u8, len, 32);
+ len = min_t(u8, len, I2C_SMBUS_BLOCK_MAX);
case I2C_SMBUS_I2C_BLOCK_DATA:
for (i = 0; i < len; i++)
- amd_ec_read(smbus, AMD_SMB_DATA + i, data->block + i + 1);
+ amd_ec_read(smbus, AMD_SMB_DATA + i,
+ data->block + i + 1);
data->block[0] = len;
break;
}
@@ -310,7 +321,8 @@ static s32 amd8111_access(struct i2c_adapter * adap, u16 addr, unsigned short fl
static u32 amd8111_func(struct i2c_adapter *adapter)
{
- return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA |
+ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA |
I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA |
I2C_FUNC_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_SMBUS_HWPEC_CALC;
@@ -329,12 +341,13 @@ static struct pci_device_id amd8111_ids[] = {
MODULE_DEVICE_TABLE (pci, amd8111_ids);
-static int __devinit amd8111_probe(struct pci_dev *dev, const struct pci_device_id *id)
+static int __devinit amd8111_probe(struct pci_dev *dev,
+ const struct pci_device_id *id)
{
struct amd_smbus *smbus;
- int error = -ENODEV;
+ int error;
- if (~pci_resource_flags(dev, 0) & IORESOURCE_IO)
+ if (!(pci_resource_flags(dev, 0) & IORESOURCE_IO))
return -ENODEV;
smbus = kzalloc(sizeof(struct amd_smbus), GFP_KERNEL);
@@ -345,24 +358,27 @@ static int __devinit amd8111_probe(struct pci_dev *dev, const struct pci_device_
smbus->base = pci_resource_start(dev, 0);
smbus->size = pci_resource_len(dev, 0);
- if (!request_region(smbus->base, smbus->size, amd8111_driver.name))
+ if (!request_region(smbus->base, smbus->size, amd8111_driver.name)) {
+ error = -EBUSY;
goto out_kfree;
+ }
smbus->adapter.owner = THIS_MODULE;
snprintf(smbus->adapter.name, I2C_NAME_SIZE,
"SMBus2 AMD8111 adapter at %04x", smbus->base);
+ smbus->adapter.id = I2C_HW_SMBUS_AMD8111;
smbus->adapter.class = I2C_CLASS_HWMON;
smbus->adapter.algo = &smbus_algorithm;
smbus->adapter.algo_data = smbus;
- /* set up the driverfs linkage to our parent device */
+ /* set up the sysfs linkage to our parent device */
smbus->adapter.dev.parent = &dev->dev;
+ pci_write_config_dword(smbus->dev, AMD_PCI_MISC, 0);
error = i2c_add_adapter(&smbus->adapter);
if (error)
goto out_release_region;
- pci_write_config_dword(smbus->dev, AMD_PCI_MISC, 0);
pci_set_drvdata(dev, smbus);
return 0;
@@ -370,10 +386,9 @@ static int __devinit amd8111_probe(struct pci_dev *dev, const struct pci_device_
release_region(smbus->base, smbus->size);
out_kfree:
kfree(smbus);
- return -1;
+ return error;
}
-
static void __devexit amd8111_remove(struct pci_dev *dev)
{
struct amd_smbus *smbus = pci_get_drvdata(dev);
@@ -395,7 +410,6 @@ static int __init i2c_amd8111_init(void)
return pci_register_driver(&amd8111_driver);
}
-
static void __exit i2c_amd8111_exit(void)
{
pci_unregister_driver(&amd8111_driver);
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index ae625b85447..6569a36985b 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -48,7 +48,6 @@
#include <linux/kernel.h>
#include <linux/stddef.h>
#include <linux/delay.h>
-#include <linux/sched.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/i2c.h>
@@ -123,7 +122,7 @@ static int i801_transaction(void)
dev_dbg(&I801_dev->dev, "Failed! (%02x)\n", temp);
return -1;
} else {
- dev_dbg(&I801_dev->dev, "Successfull!\n");
+ dev_dbg(&I801_dev->dev, "Successful!\n");
}
}
@@ -442,6 +441,7 @@ static const struct i2c_algorithm smbus_algorithm = {
static struct i2c_adapter i801_adapter = {
.owner = THIS_MODULE,
+ .id = I2C_HW_SMBUS_I801,
.class = I2C_CLASS_HWMON,
.algo = &smbus_algorithm,
};
@@ -522,7 +522,7 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id
else
dev_dbg(&dev->dev, "SMBus using PCI Interrupt\n");
- /* set up the driverfs linkage to our parent device */
+ /* set up the sysfs linkage to our parent device */
i801_adapter.dev.parent = &dev->dev;
snprintf(i801_adapter.name, I2C_NAME_SIZE,
diff --git a/drivers/i2c/busses/i2c-i810.c b/drivers/i2c/busses/i2c-i810.c
index 10c98bc88aa..42e8d94c276 100644
--- a/drivers/i2c/busses/i2c-i810.c
+++ b/drivers/i2c/busses/i2c-i810.c
@@ -171,6 +171,7 @@ static struct i2c_algo_bit_data i810_i2c_bit_data = {
static struct i2c_adapter i810_i2c_adapter = {
.owner = THIS_MODULE,
+ .id = I2C_HW_B_I810,
.name = "I810/I815 I2C Adapter",
.algo_data = &i810_i2c_bit_data,
};
@@ -186,6 +187,7 @@ static struct i2c_algo_bit_data i810_ddc_bit_data = {
static struct i2c_adapter i810_ddc_adapter = {
.owner = THIS_MODULE,
+ .id = I2C_HW_B_I810,
.name = "I810/I815 DDC Adapter",
.algo_data = &i810_ddc_bit_data,
};
diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c
index 1898e998702..8b14d14e60c 100644
--- a/drivers/i2c/busses/i2c-ibm_iic.c
+++ b/drivers/i2c/busses/i2c-ibm_iic.c
@@ -727,6 +727,7 @@ static int __devinit iic_probe(struct ocp_device *ocp){
/* Register it with i2c layer */
adap = &dev->adap;
+ adap->dev.parent = &ocp->dev;
strcpy(adap->name, "IBM IIC");
i2c_set_adapdata(adap, dev);
adap->id = I2C_HW_OCP;
diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c
index d108ab4974c..90e2d9350c1 100644
--- a/drivers/i2c/busses/i2c-iop3xx.c
+++ b/drivers/i2c/busses/i2c-iop3xx.c
@@ -36,7 +36,6 @@
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/errno.h>
-#include <linux/sched.h>
#include <linux/platform_device.h>
#include <linux/i2c.h>
@@ -84,7 +83,7 @@ iop3xx_i2c_enable(struct i2c_algo_iop3xx_data *iop3xx_adap)
* Every time unit enable is asserted, GPOD needs to be cleared
* on IOP3XX to avoid data corruption on the bus.
*/
-#ifdef CONFIG_PLAT_IOP
+#if defined(CONFIG_ARCH_IOP32X) || defined(CONFIG_ARCH_IOP33X)
if (iop3xx_adap->id == 0) {
gpio_line_set(IOP3XX_GPIO_LINE(7), GPIO_LOW);
gpio_line_set(IOP3XX_GPIO_LINE(6), GPIO_LOW);
diff --git a/drivers/i2c/busses/i2c-isa.c b/drivers/i2c/busses/i2c-isa.c
index 8ed59a2dff5..5f33bc9c1e0 100644
--- a/drivers/i2c/busses/i2c-isa.c
+++ b/drivers/i2c/busses/i2c-isa.c
@@ -39,6 +39,7 @@
#include <linux/i2c.h>
#include <linux/i2c-isa.h>
#include <linux/platform_device.h>
+#include <linux/completion.h>
static u32 isa_func(struct i2c_adapter *adapter);
diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c
index 490173611d6..a3283b907eb 100644
--- a/drivers/i2c/busses/i2c-mv64xxx.c
+++ b/drivers/i2c/busses/i2c-mv64xxx.c
@@ -520,6 +520,7 @@ mv64xxx_i2c_probe(struct platform_device *pd)
rc = -ENXIO;
goto exit_unmap_regs;
}
+ drv_data->adapter.dev.parent = &pd->dev;
drv_data->adapter.id = I2C_HW_MV64XXX;
drv_data->adapter.algo = &mv64xxx_i2c_algo;
drv_data->adapter.owner = THIS_MODULE;
diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c
index ad37c10e7fe..1514ec5b77f 100644
--- a/drivers/i2c/busses/i2c-nforce2.c
+++ b/drivers/i2c/busses/i2c-nforce2.c
@@ -44,7 +44,6 @@
#include <linux/pci.h>
#include <linux/kernel.h>
#include <linux/stddef.h>
-#include <linux/sched.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/i2c.h>
@@ -57,7 +56,6 @@ MODULE_DESCRIPTION("nForce2/3/4/5xx SMBus driver");
struct nforce2_smbus {
- struct pci_dev *dev;
struct i2c_adapter adapter;
int base;
int size;
@@ -230,7 +228,6 @@ static int __devinit nforce2_probe_smb (struct pci_dev *dev, int bar,
smbus->base = iobase & PCI_BASE_ADDRESS_IO_MASK;
smbus->size = 64;
}
- smbus->dev = dev;
if (!request_region(smbus->base, smbus->size, nforce2_driver.name)) {
dev_err(&smbus->adapter.dev, "Error requesting region %02x .. %02X for %s\n",
@@ -238,6 +235,7 @@ static int __devinit nforce2_probe_smb (struct pci_dev *dev, int bar,
return -1;
}
smbus->adapter.owner = THIS_MODULE;
+ smbus->adapter.id = I2C_HW_SMBUS_NFORCE2;
smbus->adapter.class = I2C_CLASS_HWMON;
smbus->adapter.algo = &smbus_algorithm;
smbus->adapter.algo_data = smbus;
diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c
index f28a76d1c0a..e417c2c3ca2 100644
--- a/drivers/i2c/busses/i2c-ocores.c
+++ b/drivers/i2c/busses/i2c-ocores.c
@@ -11,7 +11,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/sched.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/platform_device.h>
diff --git a/drivers/i2c/busses/i2c-parport.h b/drivers/i2c/busses/i2c-parport.h
index 9ddd816d5d0..ed69d846cb9 100644
--- a/drivers/i2c/busses/i2c-parport.h
+++ b/drivers/i2c/busses/i2c-parport.h
@@ -88,6 +88,13 @@ static struct adapter_parm adapter_parm[] = {
.getscl = { 0x40, STAT, 0 },
.init = { 0xfc, DATA, 0 },
},
+ /* type 7: One For All JP1 parallel port adapter */
+ {
+ .setsda = { 0x01, DATA, 0 },
+ .setscl = { 0x02, DATA, 0 },
+ .getsda = { 0x80, STAT, 1 },
+ .init = { 0x04, DATA, 1 },
+ },
};
static int type = -1;
@@ -101,4 +108,5 @@ MODULE_PARM_DESC(type,
" 4 = ADM1032 evaluation board\n"
" 5 = ADM1025, ADM1030 and ADM1031 evaluation boards\n"
" 6 = Barco LPT->DVI (K5800236) adapter\n"
+ " 7 = One For All JP1 parallel port adapter\n"
);
diff --git a/drivers/i2c/busses/i2c-pasemi.c b/drivers/i2c/busses/i2c-pasemi.c
new file mode 100644
index 00000000000..f54fb5d65cc
--- /dev/null
+++ b/drivers/i2c/busses/i2c-pasemi.c
@@ -0,0 +1,426 @@
+/*
+ * Copyright (C) 2006-2007 PA Semi, Inc
+ *
+ * SMBus host driver for PA Semi PWRficient
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/sched.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+
+static struct pci_driver pasemi_smb_driver;
+
+struct pasemi_smbus {
+ struct pci_dev *dev;
+ struct i2c_adapter adapter;
+ unsigned long base;
+ int size;
+};
+
+/* Register offsets */
+#define REG_MTXFIFO 0x00
+#define REG_MRXFIFO 0x04
+#define REG_SMSTA 0x14
+#define REG_CTL 0x1c
+
+/* Register defs */
+#define MTXFIFO_READ 0x00000400
+#define MTXFIFO_STOP 0x00000200
+#define MTXFIFO_START 0x00000100
+#define MTXFIFO_DATA_M 0x000000ff
+
+#define MRXFIFO_EMPTY 0x00000100
+#define MRXFIFO_DATA_M 0x000000ff
+
+#define SMSTA_XEN 0x08000000
+
+#define CTL_MRR 0x00000400
+#define CTL_MTR 0x00000200
+#define CTL_CLK_M 0x000000ff
+
+#define CLK_100K_DIV 84
+#define CLK_400K_DIV 21
+
+static inline void reg_write(struct pasemi_smbus *smbus, int reg, int val)
+{
+ dev_dbg(&smbus->dev->dev, "smbus write reg %lx val %08x\n",
+ smbus->base + reg, val);
+ outl(val, smbus->base + reg);
+}
+
+static inline int reg_read(struct pasemi_smbus *smbus, int reg)
+{
+ int ret;
+ ret = inl(smbus->base + reg);
+ dev_dbg(&smbus->dev->dev, "smbus read reg %lx val %08x\n",
+ smbus->base + reg, ret);
+ return ret;
+}
+
+#define TXFIFO_WR(smbus, reg) reg_write((smbus), REG_MTXFIFO, (reg))
+#define RXFIFO_RD(smbus) reg_read((smbus), REG_MRXFIFO)
+
+static void pasemi_smb_clear(struct pasemi_smbus *smbus)
+{
+ unsigned int status;
+
+ status = reg_read(smbus, REG_SMSTA);
+ reg_write(smbus, REG_SMSTA, status);
+}
+
+static unsigned int pasemi_smb_waitready(struct pasemi_smbus *smbus)
+{
+ int timeout = 10;
+ unsigned int status;
+
+ status = reg_read(smbus, REG_SMSTA);
+
+ while (!(status & SMSTA_XEN) && timeout--) {
+ msleep(1);
+ status = reg_read(smbus, REG_SMSTA);
+ }
+
+ if (timeout < 0) {
+ dev_warn(&smbus->dev->dev, "Timeout, status 0x%08x\n", status);
+ reg_write(smbus, REG_SMSTA, status);
+ return -ETIME;
+ }
+
+ /* Clear XEN */
+ reg_write(smbus, REG_SMSTA, SMSTA_XEN);
+
+ return 0;
+}
+
+static int pasemi_i2c_xfer_msg(struct i2c_adapter *adapter,
+ struct i2c_msg *msg, int stop)
+{
+ struct pasemi_smbus *smbus = adapter->algo_data;
+ int read, i, err;
+ u32 rd;
+
+ read = msg->flags & I2C_M_RD ? 1 : 0;
+
+ TXFIFO_WR(smbus, MTXFIFO_START | (msg->addr << 1) | read);
+
+ if (read) {
+ TXFIFO_WR(smbus, msg->len | MTXFIFO_READ |
+ (stop ? MTXFIFO_STOP : 0));
+
+ err = pasemi_smb_waitready(smbus);
+ if (err)
+ goto reset_out;
+
+ for (i = 0; i < msg->len; i++) {
+ rd = RXFIFO_RD(smbus);
+ if (rd & MRXFIFO_EMPTY) {
+ err = -ENODATA;
+ goto reset_out;
+ }
+ msg->buf[i] = rd & MRXFIFO_DATA_M;
+ }
+ } else {
+ for (i = 0; i < msg->len - 1; i++)
+ TXFIFO_WR(smbus, msg->buf[i]);
+
+ TXFIFO_WR(smbus, msg->buf[msg->len] |
+ (stop ? MTXFIFO_STOP : 0));
+ }
+
+ return 0;
+
+ reset_out:
+ reg_write(smbus, REG_CTL, (CTL_MTR | CTL_MRR |
+ (CLK_100K_DIV & CTL_CLK_M)));
+ return err;
+}
+
+static int pasemi_i2c_xfer(struct i2c_adapter *adapter,
+ struct i2c_msg *msgs, int num)
+{
+ struct pasemi_smbus *smbus = adapter->algo_data;
+ int ret, i;
+
+ pasemi_smb_clear(smbus);
+
+ ret = 0;
+
+ for (i = 0; i < num && !ret; i++)
+ ret = pasemi_i2c_xfer_msg(adapter, &msgs[i], (i == (num - 1)));
+
+ return ret ? ret : num;
+}
+
+static int pasemi_smb_xfer(struct i2c_adapter *adapter,
+ u16 addr, unsigned short flags, char read_write, u8 command,
+ int size, union i2c_smbus_data *data)
+{
+ struct pasemi_smbus *smbus = adapter->algo_data;
+ unsigned int rd;
+ int read_flag, err;
+ int len = 0, i;
+
+ /* All our ops take 8-bit shifted addresses */
+ addr <<= 1;
+ read_flag = read_write == I2C_SMBUS_READ;
+
+ pasemi_smb_clear(smbus);
+
+ switch (size) {
+ case I2C_SMBUS_QUICK:
+ TXFIFO_WR(smbus, addr | read_flag | MTXFIFO_START |
+ MTXFIFO_STOP);
+ break;
+ case I2C_SMBUS_BYTE:
+ TXFIFO_WR(smbus, addr | read_flag | MTXFIFO_START);
+ if (read_write)
+ TXFIFO_WR(smbus, 1 | MTXFIFO_STOP | MTXFIFO_READ);
+ else
+ TXFIFO_WR(smbus, MTXFIFO_STOP | command);
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ TXFIFO_WR(smbus, addr | MTXFIFO_START);
+ TXFIFO_WR(smbus, command);
+ if (read_write) {
+ TXFIFO_WR(smbus, addr | I2C_SMBUS_READ | MTXFIFO_START);
+ TXFIFO_WR(smbus, 1 | MTXFIFO_READ | MTXFIFO_STOP);
+ } else {
+ TXFIFO_WR(smbus, MTXFIFO_STOP | data->byte);
+ }
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ TXFIFO_WR(smbus, addr | MTXFIFO_START);
+ TXFIFO_WR(smbus, command);
+ if (read_write) {
+ TXFIFO_WR(smbus, addr | I2C_SMBUS_READ | MTXFIFO_START);
+ TXFIFO_WR(smbus, 2 | MTXFIFO_READ | MTXFIFO_STOP);
+ } else {
+ TXFIFO_WR(smbus, data->word & MTXFIFO_DATA_M);
+ TXFIFO_WR(smbus, MTXFIFO_STOP | (data->word >> 8));
+ }
+ break;
+ case I2C_SMBUS_BLOCK_DATA:
+ TXFIFO_WR(smbus, addr | MTXFIFO_START);
+ TXFIFO_WR(smbus, command);
+ if (read_write) {
+ TXFIFO_WR(smbus, addr | I2C_SMBUS_READ | MTXFIFO_START);
+ TXFIFO_WR(smbus, 1 | MTXFIFO_READ);
+ rd = RXFIFO_RD(smbus);
+ len = min_t(u8, (rd & MRXFIFO_DATA_M),
+ I2C_SMBUS_BLOCK_MAX);
+ TXFIFO_WR(smbus, (len + 1) | MTXFIFO_READ |
+ MTXFIFO_STOP);
+ } else {
+ len = min_t(u8, data->block[0], I2C_SMBUS_BLOCK_MAX);
+ TXFIFO_WR(smbus, len);
+ for (i = 1; i < len; i++)
+ TXFIFO_WR(smbus, data->block[i]);
+ TXFIFO_WR(smbus, data->block[len] | MTXFIFO_STOP);
+ }
+ break;
+ case I2C_SMBUS_PROC_CALL:
+ read_write = I2C_SMBUS_READ;
+ TXFIFO_WR(smbus, addr | MTXFIFO_START);
+ TXFIFO_WR(smbus, command);
+ TXFIFO_WR(smbus, data->word & MTXFIFO_DATA_M);
+ TXFIFO_WR(smbus, (data->word >> 8) & MTXFIFO_DATA_M);
+ TXFIFO_WR(smbus, addr | I2C_SMBUS_READ | MTXFIFO_START);
+ TXFIFO_WR(smbus, 2 | MTXFIFO_STOP | MTXFIFO_READ);
+ break;
+ case I2C_SMBUS_BLOCK_PROC_CALL:
+ len = min_t(u8, data->block[0], I2C_SMBUS_BLOCK_MAX - 1);
+ read_write = I2C_SMBUS_READ;
+ TXFIFO_WR(smbus, addr | MTXFIFO_START);
+ TXFIFO_WR(smbus, command);
+ TXFIFO_WR(smbus, len);
+ for (i = 1; i <= len; i++)
+ TXFIFO_WR(smbus, data->block[i]);
+ TXFIFO_WR(smbus, addr | I2C_SMBUS_READ);
+ TXFIFO_WR(smbus, MTXFIFO_READ | 1);
+ rd = RXFIFO_RD(smbus);
+ len = min_t(u8, (rd & MRXFIFO_DATA_M),
+ I2C_SMBUS_BLOCK_MAX - len);
+ TXFIFO_WR(smbus, (len + 1) | MTXFIFO_READ | MTXFIFO_STOP);
+ break;
+
+ default:
+ dev_warn(&adapter->dev, "Unsupported transaction %d\n", size);
+ return -EINVAL;
+ }
+
+ err = pasemi_smb_waitready(smbus);
+ if (err)
+ goto reset_out;
+
+ if (read_write == I2C_SMBUS_WRITE)
+ return 0;
+
+ switch (size) {
+ case I2C_SMBUS_BYTE:
+ case I2C_SMBUS_BYTE_DATA:
+ rd = RXFIFO_RD(smbus);
+ if (rd & MRXFIFO_EMPTY) {
+ err = -ENODATA;
+ goto reset_out;
+ }
+ data->byte = rd & MRXFIFO_DATA_M;
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ case I2C_SMBUS_PROC_CALL:
+ rd = RXFIFO_RD(smbus);
+ if (rd & MRXFIFO_EMPTY) {
+ err = -ENODATA;
+ goto reset_out;
+ }
+ data->word = rd & MRXFIFO_DATA_M;
+ rd = RXFIFO_RD(smbus);
+ if (rd & MRXFIFO_EMPTY) {
+ err = -ENODATA;
+ goto reset_out;
+ }
+ data->word |= (rd & MRXFIFO_DATA_M) << 8;
+ break;
+ case I2C_SMBUS_BLOCK_DATA:
+ case I2C_SMBUS_BLOCK_PROC_CALL:
+ data->block[0] = len;
+ for (i = 1; i <= len; i ++) {
+ rd = RXFIFO_RD(smbus);
+ if (rd & MRXFIFO_EMPTY) {
+ err = -ENODATA;
+ goto reset_out;
+ }
+ data->block[i] = rd & MRXFIFO_DATA_M;
+ }
+ break;
+ }
+
+ return 0;
+
+ reset_out:
+ reg_write(smbus, REG_CTL, (CTL_MTR | CTL_MRR |
+ (CLK_100K_DIV & CTL_CLK_M)));
+ return err;
+}
+
+static u32 pasemi_smb_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_PROC_CALL |
+ I2C_FUNC_SMBUS_BLOCK_PROC_CALL | I2C_FUNC_I2C;
+}
+
+static const struct i2c_algorithm smbus_algorithm = {
+ .master_xfer = pasemi_i2c_xfer,
+ .smbus_xfer = pasemi_smb_xfer,
+ .functionality = pasemi_smb_func,
+};
+
+static int __devinit pasemi_smb_probe(struct pci_dev *dev,
+ const struct pci_device_id *id)
+{
+ struct pasemi_smbus *smbus;
+ int error;
+
+ if (!(pci_resource_flags(dev, 0) & IORESOURCE_IO))
+ return -ENODEV;
+
+ smbus = kzalloc(sizeof(struct pasemi_smbus), GFP_KERNEL);
+ if (!smbus)
+ return -ENOMEM;
+
+ smbus->dev = dev;
+ smbus->base = pci_resource_start(dev, 0);
+ smbus->size = pci_resource_len(dev, 0);
+
+ if (!request_region(smbus->base, smbus->size,
+ pasemi_smb_driver.name)) {
+ error = -EBUSY;
+ goto out_kfree;
+ }
+
+ smbus->adapter.owner = THIS_MODULE;
+ snprintf(smbus->adapter.name, I2C_NAME_SIZE,
+ "PA Semi SMBus adapter at 0x%lx", smbus->base);
+ smbus->adapter.class = I2C_CLASS_HWMON;
+ smbus->adapter.algo = &smbus_algorithm;
+ smbus->adapter.algo_data = smbus;
+
+ /* set up the driverfs linkage to our parent device */
+ smbus->adapter.dev.parent = &dev->dev;
+
+ reg_write(smbus, REG_CTL, (CTL_MTR | CTL_MRR |
+ (CLK_100K_DIV & CTL_CLK_M)));
+
+ error = i2c_add_adapter(&smbus->adapter);
+ if (error)
+ goto out_release_region;
+
+ pci_set_drvdata(dev, smbus);
+
+ return 0;
+
+ out_release_region:
+ release_region(smbus->base, smbus->size);
+ out_kfree:
+ kfree(smbus);
+ return error;
+}
+
+static void __devexit pasemi_smb_remove(struct pci_dev *dev)
+{
+ struct pasemi_smbus *smbus = pci_get_drvdata(dev);
+
+ i2c_del_adapter(&smbus->adapter);
+ release_region(smbus->base, smbus->size);
+ kfree(smbus);
+}
+
+static struct pci_device_id pasemi_smb_ids[] = {
+ { PCI_DEVICE(0x1959, 0xa003) },
+ { 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, pasemi_smb_ids);
+
+static struct pci_driver pasemi_smb_driver = {
+ .name = "i2c-pasemi",
+ .id_table = pasemi_smb_ids,
+ .probe = pasemi_smb_probe,
+ .remove = __devexit_p(pasemi_smb_remove),
+};
+
+static int __init pasemi_smb_init(void)
+{
+ return pci_register_driver(&pasemi_smb_driver);
+}
+
+static void __exit pasemi_smb_exit(void)
+{
+ pci_unregister_driver(&pasemi_smb_driver);
+}
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR ("Olof Johansson <olof@lixom.net>");
+MODULE_DESCRIPTION("PA Semi PWRficient SMBus driver");
+
+module_init(pasemi_smb_init);
+module_exit(pasemi_smb_exit);
diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c
index 30c7a1b38cb..21b18090408 100644
--- a/drivers/i2c/busses/i2c-piix4.c
+++ b/drivers/i2c/busses/i2c-piix4.c
@@ -23,6 +23,7 @@
Supports:
Intel PIIX4, 440MX
Serverworks OSB4, CSB5, CSB6, HT-1000
+ ATI IXP200, IXP300, IXP400, SB600
SMSC Victory66
Note: we assume there can only be one device, with one SMBus interface.
@@ -34,7 +35,6 @@
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/stddef.h>
-#include <linux/sched.h>
#include <linux/ioport.h>
#include <linux/i2c.h>
#include <linux/init.h>
@@ -383,6 +383,7 @@ static const struct i2c_algorithm smbus_algorithm = {
static struct i2c_adapter piix4_adapter = {
.owner = THIS_MODULE,
+ .id = I2C_HW_SMBUS_PIIX4,
.class = I2C_CLASS_HWMON,
.algo = &smbus_algorithm,
};
@@ -396,6 +397,8 @@ static struct pci_device_id piix4_ids[] = {
.driver_data = 0 },
{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_SMBUS),
.driver_data = 0 },
+ { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP600_SMBUS),
+ .driver_data = 0 },
{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4),
.driver_data = 0 },
{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5),
@@ -422,7 +425,7 @@ static int __devinit piix4_probe(struct pci_dev *dev,
if (retval)
return retval;
- /* set up the driverfs linkage to our parent device */
+ /* set up the sysfs linkage to our parent device */
piix4_adapter.dev.parent = &dev->dev;
snprintf(piix4_adapter.name, I2C_NAME_SIZE,
diff --git a/drivers/i2c/busses/i2c-powermac.c b/drivers/i2c/busses/i2c-powermac.c
index 648d55533d8..1425d2245c8 100644
--- a/drivers/i2c/busses/i2c-powermac.c
+++ b/drivers/i2c/busses/i2c-powermac.c
@@ -25,7 +25,6 @@
#include <linux/types.h>
#include <linux/i2c.h>
#include <linux/init.h>
-#include <linux/completion.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <asm/prom.h>
diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
index c3b1567c852..14e83d0aac8 100644
--- a/drivers/i2c/busses/i2c-pxa.c
+++ b/drivers/i2c/busses/i2c-pxa.c
@@ -34,6 +34,7 @@
#include <asm/hardware.h>
#include <asm/irq.h>
+#include <asm/io.h>
#include <asm/arch/i2c.h>
#include <asm/arch/pxa-regs.h>
@@ -54,8 +55,21 @@ struct pxa_i2c {
unsigned int irqlogidx;
u32 isrlog[32];
u32 icrlog[32];
+
+ void __iomem *reg_base;
+
+ unsigned long iobase;
+ unsigned long iosize;
+
+ int irq;
};
+#define _IBMR(i2c) ((i2c)->reg_base + 0)
+#define _IDBR(i2c) ((i2c)->reg_base + 8)
+#define _ICR(i2c) ((i2c)->reg_base + 0x10)
+#define _ISR(i2c) ((i2c)->reg_base + 0x18)
+#define _ISAR(i2c) ((i2c)->reg_base + 0x20)
+
/*
* I2C Slave mode address
*/
@@ -130,7 +144,8 @@ static unsigned int i2c_debug = DEBUG;
static void i2c_pxa_show_state(struct pxa_i2c *i2c, int lno, const char *fname)
{
- dev_dbg(&i2c->adap.dev, "state:%s:%d: ISR=%08x, ICR=%08x, IBMR=%02x\n", fname, lno, ISR, ICR, IBMR);
+ dev_dbg(&i2c->adap.dev, "state:%s:%d: ISR=%08x, ICR=%08x, IBMR=%02x\n", fname, lno,
+ readl(_ISR(i2c)), readl(_ICR(i2c)), readl(_IBMR(i2c)));
}
#define show_state(i2c) i2c_pxa_show_state(i2c, __LINE__, __FUNCTION__)
@@ -153,7 +168,7 @@ static void i2c_pxa_scream_blue_murder(struct pxa_i2c *i2c, const char *why)
printk("i2c: msg_num: %d msg_idx: %d msg_ptr: %d\n",
i2c->msg_num, i2c->msg_idx, i2c->msg_ptr);
printk("i2c: ICR: %08x ISR: %08x\n"
- "i2c: log: ", ICR, ISR);
+ "i2c: log: ", readl(_ICR(i2c)), readl(_ISR(i2c)));
for (i = 0; i < i2c->irqlogidx; i++)
printk("[%08x:%08x] ", i2c->isrlog[i], i2c->icrlog[i]);
printk("\n");
@@ -161,7 +176,7 @@ static void i2c_pxa_scream_blue_murder(struct pxa_i2c *i2c, const char *why)
static inline int i2c_pxa_is_slavemode(struct pxa_i2c *i2c)
{
- return !(ICR & ICR_SCLE);
+ return !(readl(_ICR(i2c)) & ICR_SCLE);
}
static void i2c_pxa_abort(struct pxa_i2c *i2c)
@@ -173,28 +188,29 @@ static void i2c_pxa_abort(struct pxa_i2c *i2c)
return;
}
- while (time_before(jiffies, timeout) && (IBMR & 0x1) == 0) {
- unsigned long icr = ICR;
+ while (time_before(jiffies, timeout) && (readl(_IBMR(i2c)) & 0x1) == 0) {
+ unsigned long icr = readl(_ICR(i2c));
icr &= ~ICR_START;
icr |= ICR_ACKNAK | ICR_STOP | ICR_TB;
- ICR = icr;
+ writel(icr, _ICR(i2c));
show_state(i2c);
msleep(1);
}
- ICR &= ~(ICR_MA | ICR_START | ICR_STOP);
+ writel(readl(_ICR(i2c)) & ~(ICR_MA | ICR_START | ICR_STOP),
+ _ICR(i2c));
}
static int i2c_pxa_wait_bus_not_busy(struct pxa_i2c *i2c)
{
int timeout = DEF_TIMEOUT;
- while (timeout-- && ISR & (ISR_IBB | ISR_UB)) {
- if ((ISR & ISR_SAD) != 0)
+ while (timeout-- && readl(_ISR(i2c)) & (ISR_IBB | ISR_UB)) {
+ if ((readl(_ISR(i2c)) & ISR_SAD) != 0)
timeout += 4;
msleep(2);
@@ -214,9 +230,9 @@ static int i2c_pxa_wait_master(struct pxa_i2c *i2c)
while (time_before(jiffies, timeout)) {
if (i2c_debug > 1)
dev_dbg(&i2c->adap.dev, "%s: %ld: ISR=%08x, ICR=%08x, IBMR=%02x\n",
- __func__, (long)jiffies, ISR, ICR, IBMR);
+ __func__, (long)jiffies, readl(_ISR(i2c)), readl(_ICR(i2c)), readl(_IBMR(i2c)));
- if (ISR & ISR_SAD) {
+ if (readl(_ISR(i2c)) & ISR_SAD) {
if (i2c_debug > 0)
dev_dbg(&i2c->adap.dev, "%s: Slave detected\n", __func__);
goto out;
@@ -226,7 +242,7 @@ static int i2c_pxa_wait_master(struct pxa_i2c *i2c)
* quick check of the i2c lines themselves to ensure they've
* gone high...
*/
- if ((ISR & (ISR_UB | ISR_IBB)) == 0 && IBMR == 3) {
+ if ((readl(_ISR(i2c)) & (ISR_UB | ISR_IBB)) == 0 && readl(_IBMR(i2c)) == 3) {
if (i2c_debug > 0)
dev_dbg(&i2c->adap.dev, "%s: done\n", __func__);
return 1;
@@ -246,7 +262,7 @@ static int i2c_pxa_set_master(struct pxa_i2c *i2c)
if (i2c_debug)
dev_dbg(&i2c->adap.dev, "setting to bus master\n");
- if ((ISR & (ISR_UB | ISR_IBB)) != 0) {
+ if ((readl(_ISR(i2c)) & (ISR_UB | ISR_IBB)) != 0) {
dev_dbg(&i2c->adap.dev, "%s: unit is busy\n", __func__);
if (!i2c_pxa_wait_master(i2c)) {
dev_dbg(&i2c->adap.dev, "%s: error: unit busy\n", __func__);
@@ -254,7 +270,7 @@ static int i2c_pxa_set_master(struct pxa_i2c *i2c)
}
}
- ICR |= ICR_SCLE;
+ writel(readl(_ICR(i2c)) | ICR_SCLE, _ICR(i2c));
return 0;
}
@@ -270,11 +286,11 @@ static int i2c_pxa_wait_slave(struct pxa_i2c *i2c)
while (time_before(jiffies, timeout)) {
if (i2c_debug > 1)
dev_dbg(&i2c->adap.dev, "%s: %ld: ISR=%08x, ICR=%08x, IBMR=%02x\n",
- __func__, (long)jiffies, ISR, ICR, IBMR);
+ __func__, (long)jiffies, readl(_ISR(i2c)), readl(_ICR(i2c)), readl(_IBMR(i2c)));
- if ((ISR & (ISR_UB|ISR_IBB)) == 0 ||
- (ISR & ISR_SAD) != 0 ||
- (ICR & ICR_SCLE) == 0) {
+ if ((readl(_ISR(i2c)) & (ISR_UB|ISR_IBB)) == 0 ||
+ (readl(_ISR(i2c)) & ISR_SAD) != 0 ||
+ (readl(_ICR(i2c)) & ICR_SCLE) == 0) {
if (i2c_debug > 1)
dev_dbg(&i2c->adap.dev, "%s: done\n", __func__);
return 1;
@@ -302,9 +318,9 @@ static void i2c_pxa_set_slave(struct pxa_i2c *i2c, int errcode)
/* we need to wait for the stop condition to end */
/* if we where in stop, then clear... */
- if (ICR & ICR_STOP) {
+ if (readl(_ICR(i2c)) & ICR_STOP) {
udelay(100);
- ICR &= ~ICR_STOP;
+ writel(readl(_ICR(i2c)) & ~ICR_STOP, _ICR(i2c));
}
if (!i2c_pxa_wait_slave(i2c)) {
@@ -314,12 +330,12 @@ static void i2c_pxa_set_slave(struct pxa_i2c *i2c, int errcode)
}
}
- ICR &= ~(ICR_STOP|ICR_ACKNAK|ICR_MA);
- ICR &= ~ICR_SCLE;
+ writel(readl(_ICR(i2c)) & ~(ICR_STOP|ICR_ACKNAK|ICR_MA), _ICR(i2c));
+ writel(readl(_ICR(i2c)) & ~ICR_SCLE, _ICR(i2c));
if (i2c_debug) {
- dev_dbg(&i2c->adap.dev, "ICR now %08x, ISR %08x\n", ICR, ISR);
- decode_ICR(ICR);
+ dev_dbg(&i2c->adap.dev, "ICR now %08x, ISR %08x\n", readl(_ICR(i2c)), readl(_ISR(i2c)));
+ decode_ICR(readl(_ICR(i2c)));
}
}
#else
@@ -334,24 +350,24 @@ static void i2c_pxa_reset(struct pxa_i2c *i2c)
i2c_pxa_abort(i2c);
/* reset according to 9.8 */
- ICR = ICR_UR;
- ISR = I2C_ISR_INIT;
- ICR &= ~ICR_UR;
+ writel(ICR_UR, _ICR(i2c));
+ writel(I2C_ISR_INIT, _ISR(i2c));
+ writel(readl(_ICR(i2c)) & ~ICR_UR, _ICR(i2c));
- ISAR = i2c->slave_addr;
+ writel(i2c->slave_addr, _ISAR(i2c));
/* set control register values */
- ICR = I2C_ICR_INIT;
+ writel(I2C_ICR_INIT, _ICR(i2c));
#ifdef CONFIG_I2C_PXA_SLAVE
dev_info(&i2c->adap.dev, "Enabling slave mode\n");
- ICR |= ICR_SADIE | ICR_ALDIE | ICR_SSDIE;
+ writel(readl(_ICR(i2c)) | ICR_SADIE | ICR_ALDIE | ICR_SSDIE, _ICR(i2c));
#endif
i2c_pxa_set_slave(i2c, 0);
/* enable unit */
- ICR |= ICR_IUE;
+ writel(readl(_ICR(i2c)) | ICR_IUE, _ICR(i2c));
udelay(100);
}
@@ -371,19 +387,19 @@ static void i2c_pxa_slave_txempty(struct pxa_i2c *i2c, u32 isr)
if (i2c->slave != NULL)
ret = i2c->slave->read(i2c->slave->data);
- IDBR = ret;
- ICR |= ICR_TB; /* allow next byte */
+ writel(ret, _IDBR(i2c));
+ writel(readl(_ICR(i2c)) | ICR_TB, _ICR(i2c)); /* allow next byte */
}
}
static void i2c_pxa_slave_rxfull(struct pxa_i2c *i2c, u32 isr)
{
- unsigned int byte = IDBR;
+ unsigned int byte = readl(_IDBR(i2c));
if (i2c->slave != NULL)
i2c->slave->write(i2c->slave->data, byte);
- ICR |= ICR_TB;
+ writel(readl(_ICR(i2c)) | ICR_TB, _ICR(i2c));
}
static void i2c_pxa_slave_start(struct pxa_i2c *i2c, u32 isr)
@@ -403,13 +419,13 @@ static void i2c_pxa_slave_start(struct pxa_i2c *i2c, u32 isr)
* start condition... if this happens, we'd better back off
* and stop holding the poor thing up
*/
- ICR &= ~(ICR_START|ICR_STOP);
- ICR |= ICR_TB;
+ writel(readl(_ICR(i2c)) & ~(ICR_START|ICR_STOP), _ICR(i2c));
+ writel(readl(_ICR(i2c)) | ICR_TB, _ICR(i2c));
timeout = 0x10000;
while (1) {
- if ((IBMR & 2) == 2)
+ if ((readl(_IBMR(i2c)) & 2) == 2)
break;
timeout--;
@@ -420,7 +436,7 @@ static void i2c_pxa_slave_start(struct pxa_i2c *i2c, u32 isr)
}
}
- ICR &= ~ICR_SCLE;
+ writel(readl(_ICR(i2c)) & ~ICR_SCLE, _ICR(i2c));
}
static void i2c_pxa_slave_stop(struct pxa_i2c *i2c)
@@ -447,14 +463,14 @@ static void i2c_pxa_slave_txempty(struct pxa_i2c *i2c, u32 isr)
if (isr & ISR_BED) {
/* what should we do here? */
} else {
- IDBR = 0;
- ICR |= ICR_TB;
+ writel(0, _IDBR(i2c));
+ writel(readl(_ICR(i2c)) | ICR_TB, _ICR(i2c));
}
}
static void i2c_pxa_slave_rxfull(struct pxa_i2c *i2c, u32 isr)
{
- ICR |= ICR_TB | ICR_ACKNAK;
+ writel(readl(_ICR(i2c)) | ICR_TB | ICR_ACKNAK, _ICR(i2c));
}
static void i2c_pxa_slave_start(struct pxa_i2c *i2c, u32 isr)
@@ -466,13 +482,13 @@ static void i2c_pxa_slave_start(struct pxa_i2c *i2c, u32 isr)
* start condition... if this happens, we'd better back off
* and stop holding the poor thing up
*/
- ICR &= ~(ICR_START|ICR_STOP);
- ICR |= ICR_TB | ICR_ACKNAK;
+ writel(readl(_ICR(i2c)) & ~(ICR_START|ICR_STOP), _ICR(i2c));
+ writel(readl(_ICR(i2c)) | ICR_TB | ICR_ACKNAK, _ICR(i2c));
timeout = 0x10000;
while (1) {
- if ((IBMR & 2) == 2)
+ if ((readl(_IBMR(i2c)) & 2) == 2)
break;
timeout--;
@@ -483,7 +499,7 @@ static void i2c_pxa_slave_start(struct pxa_i2c *i2c, u32 isr)
}
}
- ICR &= ~ICR_SCLE;
+ writel(readl(_ICR(i2c)) & ~ICR_SCLE, _ICR(i2c));
}
static void i2c_pxa_slave_stop(struct pxa_i2c *i2c)
@@ -514,13 +530,13 @@ static inline void i2c_pxa_start_message(struct pxa_i2c *i2c)
/*
* Step 1: target slave address into IDBR
*/
- IDBR = i2c_pxa_addr_byte(i2c->msg);
+ writel(i2c_pxa_addr_byte(i2c->msg), _IDBR(i2c));
/*
* Step 2: initiate the write.
*/
- icr = ICR & ~(ICR_STOP | ICR_ALDIE);
- ICR = icr | ICR_START | ICR_TB;
+ icr = readl(_ICR(i2c)) & ~(ICR_STOP | ICR_ALDIE);
+ writel(icr | ICR_START | ICR_TB, _ICR(i2c));
}
/*
@@ -594,7 +610,7 @@ static void i2c_pxa_master_complete(struct pxa_i2c *i2c, int ret)
static void i2c_pxa_irq_txempty(struct pxa_i2c *i2c, u32 isr)
{
- u32 icr = ICR & ~(ICR_START|ICR_STOP|ICR_ACKNAK|ICR_TB);
+ u32 icr = readl(_ICR(i2c)) & ~(ICR_START|ICR_STOP|ICR_ACKNAK|ICR_TB);
again:
/*
@@ -645,7 +661,7 @@ static void i2c_pxa_irq_txempty(struct pxa_i2c *i2c, u32 isr)
/*
* Write mode. Write the next data byte.
*/
- IDBR = i2c->msg->buf[i2c->msg_ptr++];
+ writel(i2c->msg->buf[i2c->msg_ptr++], _IDBR(i2c));
icr |= ICR_ALDIE | ICR_TB;
@@ -675,7 +691,7 @@ static void i2c_pxa_irq_txempty(struct pxa_i2c *i2c, u32 isr)
/*
* Write the next address.
*/
- IDBR = i2c_pxa_addr_byte(i2c->msg);
+ writel(i2c_pxa_addr_byte(i2c->msg), _IDBR(i2c));
/*
* And trigger a repeated start, and send the byte.
@@ -696,18 +712,18 @@ static void i2c_pxa_irq_txempty(struct pxa_i2c *i2c, u32 isr)
i2c->icrlog[i2c->irqlogidx-1] = icr;
- ICR = icr;
+ writel(icr, _ICR(i2c));
show_state(i2c);
}
static void i2c_pxa_irq_rxfull(struct pxa_i2c *i2c, u32 isr)
{
- u32 icr = ICR & ~(ICR_START|ICR_STOP|ICR_ACKNAK|ICR_TB);
+ u32 icr = readl(_ICR(i2c)) & ~(ICR_START|ICR_STOP|ICR_ACKNAK|ICR_TB);
/*
* Read the byte.
*/
- i2c->msg->buf[i2c->msg_ptr++] = IDBR;
+ i2c->msg->buf[i2c->msg_ptr++] = readl(_IDBR(i2c));
if (i2c->msg_ptr < i2c->msg->len) {
/*
@@ -724,17 +740,17 @@ static void i2c_pxa_irq_rxfull(struct pxa_i2c *i2c, u32 isr)
i2c->icrlog[i2c->irqlogidx-1] = icr;
- ICR = icr;
+ writel(icr, _ICR(i2c));
}
static irqreturn_t i2c_pxa_handler(int this_irq, void *dev_id)
{
struct pxa_i2c *i2c = dev_id;
- u32 isr = ISR;
+ u32 isr = readl(_ISR(i2c));
if (i2c_debug > 2 && 0) {
dev_dbg(&i2c->adap.dev, "%s: ISR=%08x, ICR=%08x, IBMR=%02x\n",
- __func__, isr, ICR, IBMR);
+ __func__, isr, readl(_ICR(i2c)), readl(_IBMR(i2c)));
decode_ISR(isr);
}
@@ -746,7 +762,7 @@ static irqreturn_t i2c_pxa_handler(int this_irq, void *dev_id)
/*
* Always clear all pending IRQs.
*/
- ISR = isr & (ISR_SSD|ISR_ALD|ISR_ITE|ISR_IRF|ISR_SAD|ISR_BED);
+ writel(isr & (ISR_SSD|ISR_ALD|ISR_ITE|ISR_IRF|ISR_SAD|ISR_BED), _ISR(i2c));
if (isr & ISR_SAD)
i2c_pxa_slave_start(i2c, isr);
@@ -779,7 +795,7 @@ static int i2c_pxa_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num
/* If the I2C controller is disabled we need to reset it (probably due
to a suspend/resume destroying state). We do this here as we can then
avoid worrying about resuming the controller before its users. */
- if (!(ICR & ICR_IUE))
+ if (!(readl(_ICR(i2c)) & ICR_IUE))
i2c_pxa_reset(i2c);
for (i = adap->retries; i >= 0; i--) {
@@ -810,28 +826,53 @@ static const struct i2c_algorithm i2c_pxa_algorithm = {
static struct pxa_i2c i2c_pxa = {
.lock = SPIN_LOCK_UNLOCKED,
- .wait = __WAIT_QUEUE_HEAD_INITIALIZER(i2c_pxa.wait),
.adap = {
.owner = THIS_MODULE,
.algo = &i2c_pxa_algorithm,
- .name = "pxa2xx-i2c",
+ .name = "pxa2xx-i2c.0",
.retries = 5,
},
};
+#define res_len(r) ((r)->end - (r)->start + 1)
static int i2c_pxa_probe(struct platform_device *dev)
{
struct pxa_i2c *i2c = &i2c_pxa;
+ struct resource *res;
#ifdef CONFIG_I2C_PXA_SLAVE
struct i2c_pxa_platform_data *plat = dev->dev.platform_data;
#endif
int ret;
+ int irq;
-#ifdef CONFIG_PXA27x
- pxa_gpio_mode(GPIO117_I2CSCL_MD);
- pxa_gpio_mode(GPIO118_I2CSDA_MD);
- udelay(100);
-#endif
+ res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ irq = platform_get_irq(dev, 0);
+ if (res == NULL || irq < 0)
+ return -ENODEV;
+
+ if (!request_mem_region(res->start, res_len(res), res->name))
+ return -ENOMEM;
+
+ i2c = kmalloc(sizeof(struct pxa_i2c), GFP_KERNEL);
+ if (!i2c) {
+ ret = -ENOMEM;
+ goto emalloc;
+ }
+
+ memcpy(i2c, &i2c_pxa, sizeof(struct pxa_i2c));
+ init_waitqueue_head(&i2c->wait);
+ i2c->adap.name[strlen(i2c->adap.name) - 1] = '0' + dev->id % 10;
+
+ i2c->reg_base = ioremap(res->start, res_len(res));
+ if (!i2c->reg_base) {
+ ret = -EIO;
+ goto eremap;
+ }
+
+ i2c->iobase = res->start;
+ i2c->iosize = res_len(res);
+
+ i2c->irq = irq;
i2c->slave_addr = I2C_PXA_SLAVE_ADDR;
@@ -842,11 +883,28 @@ static int i2c_pxa_probe(struct platform_device *dev)
}
#endif
- pxa_set_cken(CKEN14_I2C, 1);
- ret = request_irq(IRQ_I2C, i2c_pxa_handler, IRQF_DISABLED,
- "pxa2xx-i2c", i2c);
+ switch (dev->id) {
+ case 0:
+#ifdef CONFIG_PXA27x
+ pxa_gpio_mode(GPIO117_I2CSCL_MD);
+ pxa_gpio_mode(GPIO118_I2CSDA_MD);
+#endif
+ pxa_set_cken(CKEN14_I2C, 1);
+ break;
+#ifdef CONFIG_PXA27x
+ case 1:
+ local_irq_disable();
+ PCFR |= PCFR_PI2CEN;
+ local_irq_enable();
+ pxa_set_cken(CKEN15_PWRI2C, 1);
+#endif
+ }
+
+ ret = request_irq(irq, i2c_pxa_handler, IRQF_DISABLED,
+ i2c->adap.name, i2c);
if (ret)
- goto out;
+ goto ereqirq;
+
i2c_pxa_reset(i2c);
@@ -856,7 +914,7 @@ static int i2c_pxa_probe(struct platform_device *dev)
ret = i2c_add_adapter(&i2c->adap);
if (ret < 0) {
printk(KERN_INFO "I2C: Failed to add bus\n");
- goto err_irq;
+ goto eadapt;
}
platform_set_drvdata(dev, i2c);
@@ -870,9 +928,25 @@ static int i2c_pxa_probe(struct platform_device *dev)
#endif
return 0;
- err_irq:
- free_irq(IRQ_I2C, i2c);
- out:
+eadapt:
+ free_irq(irq, i2c);
+ereqirq:
+ switch (dev->id) {
+ case 0:
+ pxa_set_cken(CKEN14_I2C, 0);
+ break;
+#ifdef CONFIG_PXA27x
+ case 1:
+ pxa_set_cken(CKEN15_PWRI2C, 0);
+ local_irq_disable();
+ PCFR &= ~PCFR_PI2CEN;
+ local_irq_enable();
+#endif
+ }
+eremap:
+ kfree(i2c);
+emalloc:
+ release_mem_region(res->start, res_len(res));
return ret;
}
@@ -883,8 +957,21 @@ static int i2c_pxa_remove(struct platform_device *dev)
platform_set_drvdata(dev, NULL);
i2c_del_adapter(&i2c->adap);
- free_irq(IRQ_I2C, i2c);
- pxa_set_cken(CKEN14_I2C, 0);
+ free_irq(i2c->irq, i2c);
+ switch (dev->id) {
+ case 0:
+ pxa_set_cken(CKEN14_I2C, 0);
+ break;
+#ifdef CONFIG_PXA27x
+ case 1:
+ pxa_set_cken(CKEN15_PWRI2C, 0);
+ local_irq_disable();
+ PCFR &= ~PCFR_PI2CEN;
+ local_irq_enable();
+#endif
+ }
+ release_mem_region(i2c->iobase, i2c->iosize);
+ kfree(i2c);
return 0;
}
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c
index 4ca6de209b8..556f244aae7 100644
--- a/drivers/i2c/busses/i2c-s3c2410.c
+++ b/drivers/i2c/busses/i2c-s3c2410.c
@@ -28,7 +28,6 @@
#include <linux/init.h>
#include <linux/time.h>
#include <linux/interrupt.h>
-#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/err.h>
diff --git a/drivers/i2c/busses/i2c-savage4.c b/drivers/i2c/busses/i2c-savage4.c
index 844b4ff9089..b7fb65c3011 100644
--- a/drivers/i2c/busses/i2c-savage4.c
+++ b/drivers/i2c/busses/i2c-savage4.c
@@ -145,6 +145,7 @@ static struct i2c_algo_bit_data sav_i2c_bit_data = {
static struct i2c_adapter savage4_i2c_adapter = {
.owner = THIS_MODULE,
+ .id = I2C_HW_B_SAVAGE,
.name = "I2C Savage4 adapter",
.algo_data = &sav_i2c_bit_data,
};
diff --git a/drivers/i2c/busses/i2c-sis5595.c b/drivers/i2c/busses/i2c-sis5595.c
index 38bbfd840b6..a6feed449db 100644
--- a/drivers/i2c/busses/i2c-sis5595.c
+++ b/drivers/i2c/busses/i2c-sis5595.c
@@ -365,6 +365,7 @@ static const struct i2c_algorithm smbus_algorithm = {
static struct i2c_adapter sis5595_adapter = {
.owner = THIS_MODULE,
+ .id = I2C_HW_SMBUS_SIS5595,
.class = I2C_CLASS_HWMON,
.algo = &smbus_algorithm,
};
@@ -383,7 +384,7 @@ static int __devinit sis5595_probe(struct pci_dev *dev, const struct pci_device_
return -ENODEV;
}
- /* set up the driverfs linkage to our parent device */
+ /* set up the sysfs linkage to our parent device */
sis5595_adapter.dev.parent = &dev->dev;
sprintf(sis5595_adapter.name, "SMBus SIS5595 adapter at %04x",
diff --git a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c
index dec0bafb52a..5fd734f99ee 100644
--- a/drivers/i2c/busses/i2c-sis630.c
+++ b/drivers/i2c/busses/i2c-sis630.c
@@ -457,6 +457,7 @@ static const struct i2c_algorithm smbus_algorithm = {
static struct i2c_adapter sis630_adapter = {
.owner = THIS_MODULE,
+ .id = I2C_HW_SMBUS_SIS630,
.class = I2C_CLASS_HWMON,
.algo = &smbus_algorithm,
};
@@ -476,7 +477,7 @@ static int __devinit sis630_probe(struct pci_dev *dev, const struct pci_device_i
return -ENODEV;
}
- /* set up the driverfs linkage to our parent device */
+ /* set up the sysfs linkage to our parent device */
sis630_adapter.dev.parent = &dev->dev;
sprintf(sis630_adapter.name, "SMBus SIS630 adapter at %04x",
diff --git a/drivers/i2c/busses/i2c-sis96x.c b/drivers/i2c/busses/i2c-sis96x.c
index 7fd07fbac33..4157b0cd604 100644
--- a/drivers/i2c/busses/i2c-sis96x.c
+++ b/drivers/i2c/busses/i2c-sis96x.c
@@ -37,7 +37,6 @@
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/stddef.h>
-#include <linux/sched.h>
#include <linux/ioport.h>
#include <linux/i2c.h>
#include <linux/init.h>
@@ -249,6 +248,7 @@ static const struct i2c_algorithm smbus_algorithm = {
static struct i2c_adapter sis96x_adapter = {
.owner = THIS_MODULE,
+ .id = I2C_HW_SMBUS_SIS96X,
.class = I2C_CLASS_HWMON,
.algo = &smbus_algorithm,
};
@@ -297,7 +297,7 @@ static int __devinit sis96x_probe(struct pci_dev *dev,
return -EINVAL;
}
- /* set up the driverfs linkage to our parent device */
+ /* set up the sysfs linkage to our parent device */
sis96x_adapter.dev.parent = &dev->dev;
snprintf(sis96x_adapter.name, I2C_NAME_SIZE,
diff --git a/drivers/i2c/busses/i2c-via.c b/drivers/i2c/busses/i2c-via.c
index 15d7e00e47e..81520868797 100644
--- a/drivers/i2c/busses/i2c-via.c
+++ b/drivers/i2c/busses/i2c-via.c
@@ -86,6 +86,7 @@ static struct i2c_algo_bit_data bit_data = {
static struct i2c_adapter vt586b_adapter = {
.owner = THIS_MODULE,
+ .id = I2C_HW_B_VIA,
.class = I2C_CLASS_HWMON,
.name = "VIA i2c",
.algo_data = &bit_data,
@@ -137,7 +138,7 @@ static int __devinit vt586b_probe(struct pci_dev *dev, const struct pci_device_i
outb(inb(I2C_DIR) & ~(I2C_SDA | I2C_SCL), I2C_DIR);
outb(inb(I2C_OUT) & ~(I2C_SDA | I2C_SCL), I2C_OUT);
- /* set up the driverfs linkage to our parent device */
+ /* set up the sysfs linkage to our parent device */
vt586b_adapter.dev.parent = &dev->dev;
res = i2c_bit_add_bus(&vt586b_adapter);
diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c
index efc6bbf0cc0..03c5fc86854 100644
--- a/drivers/i2c/busses/i2c-viapro.c
+++ b/drivers/i2c/busses/i2c-viapro.c
@@ -4,7 +4,7 @@
Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl>,
Philip Edelbrock <phil@netroedge.com>, Kyösti Mälkki <kmalkki@cc.hut.fi>,
Mark D. Studebaker <mdsxyz123@yahoo.com>
- Copyright (C) 2005 Jean Delvare <khali@linux-fr.org>
+ 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
@@ -36,6 +36,7 @@
VT8237R 0x3227 yes
VT8237A 0x3337 yes
VT8251 0x3287 yes
+ CX700 0x8324 yes
Note: we assume there can only be one device, with one SMBus interface.
*/
@@ -306,6 +307,7 @@ static const struct i2c_algorithm smbus_algorithm = {
static struct i2c_adapter vt596_adapter = {
.owner = THIS_MODULE,
+ .id = I2C_HW_SMBUS_VIA2,
.class = I2C_CLASS_HWMON,
.algo = &smbus_algorithm,
};
@@ -383,6 +385,7 @@ found:
dev_dbg(&pdev->dev, "VT596_smba = 0x%X\n", vt596_smba);
switch (pdev->device) {
+ case PCI_DEVICE_ID_VIA_CX700:
case PCI_DEVICE_ID_VIA_8251:
case PCI_DEVICE_ID_VIA_8237:
case PCI_DEVICE_ID_VIA_8237A:
@@ -442,6 +445,8 @@ static struct pci_device_id vt596_ids[] = {
.driver_data = SMBBA1 },
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8251),
.driver_data = SMBBA3 },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_CX700),
+ .driver_data = SMBBA3 },
{ 0, }
};
diff --git a/drivers/i2c/busses/i2c-voodoo3.c b/drivers/i2c/busses/i2c-voodoo3.c
index b0377b81744..88a3447e11e 100644
--- a/drivers/i2c/busses/i2c-voodoo3.c
+++ b/drivers/i2c/busses/i2c-voodoo3.c
@@ -165,6 +165,7 @@ static struct i2c_algo_bit_data voo_i2c_bit_data = {
static struct i2c_adapter voodoo3_i2c_adapter = {
.owner = THIS_MODULE,
+ .id = I2C_HW_B_VOO,
.class = I2C_CLASS_TV_ANALOG,
.name = "I2C Voodoo3/Banshee adapter",
.algo_data = &voo_i2c_bit_data,
@@ -181,6 +182,7 @@ static struct i2c_algo_bit_data voo_ddc_bit_data = {
static struct i2c_adapter voodoo3_ddc_adapter = {
.owner = THIS_MODULE,
+ .id = I2C_HW_B_VOO,
.class = I2C_CLASS_DDC,
.name = "DDC Voodoo3/Banshee adapter",
.algo_data = &voo_ddc_bit_data,
diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c
index 714bae78095..0b082c5a019 100644
--- a/drivers/i2c/busses/scx200_acb.c
+++ b/drivers/i2c/busses/scx200_acb.c
@@ -428,7 +428,7 @@ static __init int scx200_acb_probe(struct scx200_acb_iface *iface)
}
static __init struct scx200_acb_iface *scx200_create_iface(const char *text,
- int index)
+ struct device *dev, int index)
{
struct scx200_acb_iface *iface;
struct i2c_adapter *adapter;
@@ -446,6 +446,7 @@ static __init struct scx200_acb_iface *scx200_create_iface(const char *text,
adapter->id = I2C_HW_SMBUS_SCX200;
adapter->algo = &scx200_acb_algorithm;
adapter->class = I2C_CLASS_HWMON;
+ adapter->dev.parent = dev;
mutex_init(&iface->mutex);
@@ -486,7 +487,7 @@ static __init int scx200_create_pci(const char *text, struct pci_dev *pdev,
struct scx200_acb_iface *iface;
int rc;
- iface = scx200_create_iface(text, 0);
+ iface = scx200_create_iface(text, &pdev->dev, 0);
if (iface == NULL)
return -ENOMEM;
@@ -524,7 +525,7 @@ static int __init scx200_create_isa(const char *text, unsigned long base,
struct scx200_acb_iface *iface;
int rc;
- iface = scx200_create_iface(text, index);
+ iface = scx200_create_iface(text, NULL, index);
if (iface == NULL)
return -ENOMEM;
diff --git a/drivers/i2c/busses/scx200_i2c.c b/drivers/i2c/busses/scx200_i2c.c
index 6cd96e43aa7..c3022a02344 100644
--- a/drivers/i2c/busses/scx200_i2c.c
+++ b/drivers/i2c/busses/scx200_i2c.c
@@ -81,6 +81,7 @@ static struct i2c_algo_bit_data scx200_i2c_data = {
static struct i2c_adapter scx200_i2c_ops = {
.owner = THIS_MODULE,
+ .id = I2C_HW_B_SCX200,
.algo_data = &scx200_i2c_data,
.name = "NatSemi SCx200 I2C",
};
diff --git a/drivers/i2c/chips/eeprom.c b/drivers/i2c/chips/eeprom.c
index cec3a0c3894..bfce13c8f1f 100644
--- a/drivers/i2c/chips/eeprom.c
+++ b/drivers/i2c/chips/eeprom.c
@@ -30,7 +30,6 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
-#include <linux/sched.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
diff --git a/drivers/i2c/chips/isp1301_omap.c b/drivers/i2c/chips/isp1301_omap.c
index ccdf3e90862..9fafadb9251 100644
--- a/drivers/i2c/chips/isp1301_omap.c
+++ b/drivers/i2c/chips/isp1301_omap.c
@@ -27,7 +27,7 @@
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include <linux/usb.h>
#include <linux/usb/otg.h>
diff --git a/drivers/i2c/chips/tps65010.c b/drivers/i2c/chips/tps65010.c
index 4ee56def61f..214fbb1423c 100644
--- a/drivers/i2c/chips/tps65010.c
+++ b/drivers/i2c/chips/tps65010.c
@@ -308,7 +308,7 @@ static int dbg_tps_open(struct inode *inode, struct file *file)
return single_open(file, dbg_show, inode->i_private);
}
-static struct file_operations debug_fops = {
+static const struct file_operations debug_fops = {
.open = dbg_tps_open,
.read = seq_read,
.llseek = seq_lseek,
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index b05378a3d67..21fe1406c8b 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -32,6 +32,7 @@
#include <linux/seq_file.h>
#include <linux/platform_device.h>
#include <linux/mutex.h>
+#include <linux/completion.h>
#include <asm/uaccess.h>
@@ -40,49 +41,72 @@ static LIST_HEAD(drivers);
static DEFINE_MUTEX(core_lists);
static DEFINE_IDR(i2c_adapter_idr);
+
+/* ------------------------------------------------------------------------- */
+
/* match always succeeds, as we want the probe() to tell if we really accept this match */
static int i2c_device_match(struct device *dev, struct device_driver *drv)
{
return 1;
}
-static int i2c_bus_suspend(struct device * dev, pm_message_t state)
+static int i2c_device_probe(struct device *dev)
{
- int rc = 0;
+ return -ENODEV;
+}
- if (dev->driver && dev->driver->suspend)
- rc = dev->driver->suspend(dev, state);
- return rc;
+static int i2c_device_remove(struct device *dev)
+{
+ return 0;
}
-static int i2c_bus_resume(struct device * dev)
+static void i2c_device_shutdown(struct device *dev)
{
- int rc = 0;
-
- if (dev->driver && dev->driver->resume)
- rc = dev->driver->resume(dev);
- return rc;
+ struct i2c_driver *driver;
+
+ if (!dev->driver)
+ return;
+ driver = to_i2c_driver(dev->driver);
+ if (driver->shutdown)
+ driver->shutdown(to_i2c_client(dev));
}
-static int i2c_device_probe(struct device *dev)
+static int i2c_device_suspend(struct device * dev, pm_message_t mesg)
{
- return -ENODEV;
+ struct i2c_driver *driver;
+
+ if (!dev->driver)
+ return 0;
+ driver = to_i2c_driver(dev->driver);
+ if (!driver->suspend)
+ return 0;
+ return driver->suspend(to_i2c_client(dev), mesg);
}
-static int i2c_device_remove(struct device *dev)
+static int i2c_device_resume(struct device * dev)
{
- return 0;
+ struct i2c_driver *driver;
+
+ if (!dev->driver)
+ return 0;
+ driver = to_i2c_driver(dev->driver);
+ if (!driver->resume)
+ return 0;
+ return driver->resume(to_i2c_client(dev));
}
struct bus_type i2c_bus_type = {
- .name = "i2c",
- .match = i2c_device_match,
- .probe = i2c_device_probe,
- .remove = i2c_device_remove,
- .suspend = i2c_bus_suspend,
- .resume = i2c_bus_resume,
+ .name = "i2c",
+ .match = i2c_device_match,
+ .probe = i2c_device_probe,
+ .remove = i2c_device_remove,
+ .shutdown = i2c_device_shutdown,
+ .suspend = i2c_device_suspend,
+ .resume = i2c_device_resume,
};
+/* ------------------------------------------------------------------------- */
+
void i2c_adapter_dev_release(struct device *dev)
{
struct i2c_adapter *adap = dev_to_i2c_adapter(dev);
@@ -193,9 +217,8 @@ int i2c_add_adapter(struct i2c_adapter *adap)
*/
if (adap->dev.parent == NULL) {
adap->dev.parent = &platform_bus;
- printk(KERN_WARNING "**WARNING** I2C adapter driver [%s] "
- "forgot to specify physical device; fix it!\n",
- adap->name);
+ pr_debug("I2C adapter driver [%s] forgot to specify "
+ "physical device\n", adap->name);
}
sprintf(adap->dev.bus_id, "i2c-%d", adap->nr);
adap->dev.driver = &i2c_adapter_driver;
diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
index ac5bd2a7ca9..cb4fa9bef8c 100644
--- a/drivers/i2c/i2c-dev.c
+++ b/drivers/i2c/i2c-dev.c
@@ -392,7 +392,7 @@ static int i2cdev_release(struct inode *inode, struct file *file)
return 0;
}
-static struct file_operations i2cdev_fops = {
+static const struct file_operations i2cdev_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = i2cdev_read,
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
index 3f828052f8d..49234e32fd1 100644
--- a/drivers/ide/Kconfig
+++ b/drivers/ide/Kconfig
@@ -167,6 +167,13 @@ config BLK_DEV_IDECS
Support for Compact Flash cards, outboard IDE disks, tape drives,
and CD-ROM drives connected through a PCMCIA card.
+config BLK_DEV_DELKIN
+ tristate "Cardbus IDE support (Delkin/ASKA/Workbit)"
+ depends on CARDBUS && PCI
+ help
+ Support for Delkin, ASKA, and Workbit Cardbus CompactFlash
+ Adapters. This may also work for similar SD and XD adapters.
+
config BLK_DEV_IDECD
tristate "Include IDE/ATAPI CDROM support"
---help---
@@ -264,6 +271,13 @@ config BLK_DEV_IDESCSI
If both this SCSI emulation and native ATAPI support are compiled
into the kernel, the native support will be used.
+config BLK_DEV_IDEACPI
+ bool "IDE ACPI support"
+ depends on ACPI
+ ---help---
+ Implement ACPI support for generic IDE devices. On modern
+ machines ACPI support is required to properly handle ACPI S3 states.
+
config IDE_TASK_IOCTL
bool "IDE Taskfile Access"
help
@@ -369,6 +383,9 @@ config BLK_DEV_OFFBOARD
config BLK_DEV_GENERIC
tristate "Generic PCI IDE Chipset Support"
depends on BLK_DEV_IDEPCI
+ help
+ This option provides generic support for various PCI IDE Chipsets
+ which otherwise might not be supported.
config BLK_DEV_OPTI621
tristate "OPTi 82C621 chipset enhanced support (EXPERIMENTAL)"
@@ -606,6 +623,11 @@ config BLK_DEV_PIIX
the kernel to change PIO, DMA and UDMA speeds and to configure
the chip to optimum performance.
+config BLK_DEV_IT8213
+ tristate "IT8213 IDE support"
+ help
+ This driver adds support for the ITE 8213 IDE controller.
+
config BLK_DEV_IT821X
tristate "IT821X IDE support"
help
@@ -742,6 +764,11 @@ config BLK_DEV_VIA82CXXX
This allows the kernel to change PIO, DMA and UDMA speeds and to
configure the chip to optimum performance.
+config BLK_DEV_TC86C001
+ tristate "Toshiba TC86C001 support"
+ help
+ This driver adds support for Toshiba TC86C001 GOKU-S chip.
+
endif
config BLK_DEV_IDE_PMAC
@@ -773,6 +800,14 @@ config BLK_DEV_IDEDMA_PMAC
to transfer data to and from memory. Saying Y is safe and improves
performance.
+config BLK_DEV_IDE_CELLEB
+ bool "Toshiba's Cell Reference Set IDE support"
+ depends on PPC_CELLEB
+ help
+ This driver provides support for the built-in IDE controller on
+ Toshiba Cell Reference Board.
+ If unsure, say Y.
+
config BLK_DEV_IDE_SWARM
tristate "IDE for Sibyte evaluation boards"
depends on SIBYTE_SB1xxx_SOC
diff --git a/drivers/ide/Makefile b/drivers/ide/Makefile
index 569fae71750..28feedfbd21 100644
--- a/drivers/ide/Makefile
+++ b/drivers/ide/Makefile
@@ -22,6 +22,7 @@ ide-core-$(CONFIG_BLK_DEV_IDEPCI) += setup-pci.o
ide-core-$(CONFIG_BLK_DEV_IDEDMA) += ide-dma.o
ide-core-$(CONFIG_PROC_FS) += ide-proc.o
ide-core-$(CONFIG_BLK_DEV_IDEPNP) += ide-pnp.o
+ide-core-$(CONFIG_BLK_DEV_IDEACPI) += ide-acpi.o
# built-in only drivers from arm/
ide-core-$(CONFIG_IDE_ARM) += arm/ide_arm.o
@@ -36,6 +37,7 @@ ide-core-$(CONFIG_BLK_DEV_Q40IDE) += legacy/q40ide.o
# built-in only drivers from ppc/
ide-core-$(CONFIG_BLK_DEV_MPC8xx_IDE) += ppc/mpc8xx.o
ide-core-$(CONFIG_BLK_DEV_IDE_PMAC) += ppc/pmac.o
+ide-core-$(CONFIG_BLK_DEV_IDE_CELLEB) += ppc/scc_pata.o
# built-in only drivers from h8300/
ide-core-$(CONFIG_H8300) += h8300/ide-h8300.o
diff --git a/drivers/ide/arm/icside.c b/drivers/ide/arm/icside.c
index 8a1c27f2869..40e5c66b81c 100644
--- a/drivers/ide/arm/icside.c
+++ b/drivers/ide/arm/icside.c
@@ -307,26 +307,24 @@ static int icside_set_speed(ide_drive_t *drive, u8 xfer_mode)
return on;
}
-static int icside_dma_host_off(ide_drive_t *drive)
+static void icside_dma_host_off(ide_drive_t *drive)
{
- return 0;
}
-static int icside_dma_off_quietly(ide_drive_t *drive)
+static void icside_dma_off_quietly(ide_drive_t *drive)
{
drive->using_dma = 0;
- return icside_dma_host_off(drive);
}
-static int icside_dma_host_on(ide_drive_t *drive)
+static void icside_dma_host_on(ide_drive_t *drive)
{
- return 0;
}
static int icside_dma_on(ide_drive_t *drive)
{
drive->using_dma = 1;
- return icside_dma_host_on(drive);
+
+ return 0;
}
static int icside_dma_check(ide_drive_t *drive)
@@ -365,10 +363,7 @@ static int icside_dma_check(ide_drive_t *drive)
out:
on = icside_set_speed(drive, xfer_mode);
- if (on)
- return icside_dma_on(drive);
- else
- return icside_dma_off_quietly(drive);
+ return on ? 0 : -1;
}
static int icside_dma_end(ide_drive_t *drive)
@@ -497,9 +492,9 @@ static void icside_dma_init(ide_hwif_t *hwif)
hwif->autodma = autodma;
hwif->ide_dma_check = icside_dma_check;
- hwif->ide_dma_host_off = icside_dma_host_off;
- hwif->ide_dma_off_quietly = icside_dma_off_quietly;
- hwif->ide_dma_host_on = icside_dma_host_on;
+ hwif->dma_host_off = icside_dma_host_off;
+ hwif->dma_off_quietly = icside_dma_off_quietly;
+ hwif->dma_host_on = icside_dma_host_on;
hwif->ide_dma_on = icside_dma_on;
hwif->dma_setup = icside_dma_setup;
hwif->dma_exec_cmd = icside_dma_exec_cmd;
@@ -556,7 +551,7 @@ icside_setup(void __iomem *base, struct cardinfo *info, struct expansion_card *e
* Ensure we're using MMIO
*/
default_hwif_mmiops(hwif);
- hwif->mmio = 2;
+ hwif->mmio = 1;
for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
hwif->hw.io_ports[i] = port;
diff --git a/drivers/ide/arm/rapide.c b/drivers/ide/arm/rapide.c
index 3058217767d..9c6c49fdd2b 100644
--- a/drivers/ide/arm/rapide.c
+++ b/drivers/ide/arm/rapide.c
@@ -46,7 +46,7 @@ rapide_locate_hwif(void __iomem *base, void __iomem *ctrl, unsigned int sz, int
hwif->hw.io_ports[IDE_CONTROL_OFFSET] = (unsigned long)ctrl;
hwif->io_ports[IDE_CONTROL_OFFSET] = (unsigned long)ctrl;
hwif->hw.irq = hwif->irq = irq;
- hwif->mmio = 2;
+ hwif->mmio = 1;
default_hwif_mmiops(hwif);
return hwif;
diff --git a/drivers/ide/cris/ide-cris.c b/drivers/ide/cris/ide-cris.c
index 5797e0b5a13..6b2d152351b 100644
--- a/drivers/ide/cris/ide-cris.c
+++ b/drivers/ide/cris/ide-cris.c
@@ -682,9 +682,12 @@ static void cris_ide_input_data (ide_drive_t *drive, void *, unsigned int);
static void cris_ide_output_data (ide_drive_t *drive, void *, unsigned int);
static void cris_atapi_input_bytes(ide_drive_t *drive, void *, unsigned int);
static void cris_atapi_output_bytes(ide_drive_t *drive, void *, unsigned int);
-static int cris_dma_off (ide_drive_t *drive);
static int cris_dma_on (ide_drive_t *drive);
+static void cris_dma_off(ide_drive_t *drive)
+{
+}
+
static void tune_cris_ide(ide_drive_t *drive, u8 pio)
{
int setup, strobe, hold;
@@ -795,7 +798,7 @@ init_e100_ide (void)
0, 0, cris_ide_ack_intr,
ide_default_irq(0));
ide_register_hw(&hw, &hwif);
- hwif->mmio = 2;
+ hwif->mmio = 1;
hwif->chipset = ide_etrax100;
hwif->tuneproc = &tune_cris_ide;
hwif->speedproc = &speed_cris_ide;
@@ -814,13 +817,16 @@ init_e100_ide (void)
hwif->OUTBSYNC = &cris_ide_outbsync;
hwif->INB = &cris_ide_inb;
hwif->INW = &cris_ide_inw;
- hwif->ide_dma_host_off = &cris_dma_off;
- hwif->ide_dma_host_on = &cris_dma_on;
- hwif->ide_dma_off_quietly = &cris_dma_off;
+ hwif->dma_host_off = &cris_dma_off;
+ hwif->dma_host_on = &cris_dma_on;
+ hwif->dma_off_quietly = &cris_dma_off;
hwif->udma_four = 0;
hwif->ultra_mask = cris_ultra_mask;
hwif->mwdma_mask = 0x07; /* Multiword DMA 0-2 */
hwif->swdma_mask = 0x07; /* Singleword DMA 0-2 */
+ hwif->autodma = 1;
+ hwif->drives[0].autodma = 1;
+ hwif->drives[1].autodma = 1;
}
/* Reset pulse */
@@ -835,11 +841,6 @@ init_e100_ide (void)
cris_ide_set_speed(TYPE_UDMA, ATA_UDMA2_CYC, ATA_UDMA2_DVS, 0);
}
-static int cris_dma_off (ide_drive_t *drive)
-{
- return 0;
-}
-
static int cris_dma_on (ide_drive_t *drive)
{
return 0;
@@ -1045,17 +1046,10 @@ static ide_startstop_t cris_dma_intr (ide_drive_t *drive)
static int cris_dma_check(ide_drive_t *drive)
{
- ide_hwif_t *hwif = drive->hwif;
- struct hd_driveid* id = drive->id;
-
- if (id && (id->capability & 1)) {
- if (ide_use_dma(drive)) {
- if (cris_config_drive_for_dma(drive))
- return hwif->ide_dma_on(drive);
- }
- }
+ if (ide_use_dma(drive) && cris_config_drive_for_dma(drive))
+ return 0;
- return hwif->ide_dma_off_quietly(drive);
+ return -1;
}
static int cris_dma_end(ide_drive_t *drive)
diff --git a/drivers/ide/h8300/ide-h8300.c b/drivers/ide/h8300/ide-h8300.c
index 608ca871744..88750a30033 100644
--- a/drivers/ide/h8300/ide-h8300.c
+++ b/drivers/ide/h8300/ide-h8300.c
@@ -76,13 +76,11 @@ static inline void hwif_setup(ide_hwif_t *hwif)
{
default_hwif_iops(hwif);
- hwif->mmio = 2;
+ hwif->mmio = 1;
hwif->OUTW = mm_outw;
hwif->OUTSW = mm_outsw;
hwif->INW = mm_inw;
hwif->INSW = mm_insw;
- hwif->OUTL = NULL;
- hwif->INL = NULL;
hwif->OUTSL = NULL;
hwif->INSL = NULL;
}
diff --git a/drivers/ide/ide-acpi.c b/drivers/ide/ide-acpi.c
new file mode 100644
index 00000000000..17aea65d7dd
--- /dev/null
+++ b/drivers/ide/ide-acpi.c
@@ -0,0 +1,697 @@
+/*
+ * ide-acpi.c
+ * Provides ACPI support for IDE drives.
+ *
+ * Copyright (C) 2005 Intel Corp.
+ * Copyright (C) 2005 Randy Dunlap
+ * Copyright (C) 2006 SUSE Linux Products GmbH
+ * Copyright (C) 2006 Hannes Reinecke
+ */
+
+#include <linux/ata.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <acpi/acpi.h>
+#include <linux/ide.h>
+#include <linux/pci.h>
+
+#include <acpi/acpi_bus.h>
+#include <acpi/acnames.h>
+#include <acpi/acnamesp.h>
+#include <acpi/acparser.h>
+#include <acpi/acexcep.h>
+#include <acpi/acmacros.h>
+#include <acpi/actypes.h>
+
+#define REGS_PER_GTF 7
+struct taskfile_array {
+ u8 tfa[REGS_PER_GTF]; /* regs. 0x1f1 - 0x1f7 */
+};
+
+struct GTM_buffer {
+ u32 PIO_speed0;
+ u32 DMA_speed0;
+ u32 PIO_speed1;
+ u32 DMA_speed1;
+ u32 GTM_flags;
+};
+
+struct ide_acpi_drive_link {
+ ide_drive_t *drive;
+ acpi_handle obj_handle;
+ u8 idbuff[512];
+};
+
+struct ide_acpi_hwif_link {
+ ide_hwif_t *hwif;
+ acpi_handle obj_handle;
+ struct GTM_buffer gtm;
+ struct ide_acpi_drive_link master;
+ struct ide_acpi_drive_link slave;
+};
+
+#undef DEBUGGING
+/* note: adds function name and KERN_DEBUG */
+#ifdef DEBUGGING
+#define DEBPRINT(fmt, args...) \
+ printk(KERN_DEBUG "%s: " fmt, __FUNCTION__, ## args)
+#else
+#define DEBPRINT(fmt, args...) do {} while (0)
+#endif /* DEBUGGING */
+
+extern int ide_noacpi;
+extern int ide_noacpitfs;
+extern int ide_noacpionboot;
+
+/**
+ * ide_get_dev_handle - finds acpi_handle and PCI device.function
+ * @dev: device to locate
+ * @handle: returned acpi_handle for @dev
+ * @pcidevfn: return PCI device.func for @dev
+ *
+ * Returns the ACPI object handle to the corresponding PCI device.
+ *
+ * Returns 0 on success, <0 on error.
+ */
+static int ide_get_dev_handle(struct device *dev, acpi_handle *handle,
+ acpi_integer *pcidevfn)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ unsigned int bus, devnum, func;
+ acpi_integer addr;
+ acpi_handle dev_handle;
+ struct acpi_buffer buffer = {.length = ACPI_ALLOCATE_BUFFER,
+ .pointer = NULL};
+ acpi_status status;
+ struct acpi_device_info *dinfo = NULL;
+ int ret = -ENODEV;
+
+ bus = pdev->bus->number;
+ devnum = PCI_SLOT(pdev->devfn);
+ func = PCI_FUNC(pdev->devfn);
+ /* ACPI _ADR encoding for PCI bus: */
+ addr = (acpi_integer)(devnum << 16 | func);
+
+ DEBPRINT("ENTER: pci %02x:%02x.%01x\n", bus, devnum, func);
+
+ dev_handle = DEVICE_ACPI_HANDLE(dev);
+ if (!dev_handle) {
+ DEBPRINT("no acpi handle for device\n");
+ goto err;
+ }
+
+ status = acpi_get_object_info(dev_handle, &buffer);
+ if (ACPI_FAILURE(status)) {
+ DEBPRINT("get_object_info for device failed\n");
+ goto err;
+ }
+ dinfo = buffer.pointer;
+ if (dinfo && (dinfo->valid & ACPI_VALID_ADR) &&
+ dinfo->address == addr) {
+ *pcidevfn = addr;
+ *handle = dev_handle;
+ } else {
+ DEBPRINT("get_object_info for device has wrong "
+ " address: %llu, should be %u\n",
+ dinfo ? (unsigned long long)dinfo->address : -1ULL,
+ (unsigned int)addr);
+ goto err;
+ }
+
+ DEBPRINT("for dev=0x%x.%x, addr=0x%llx, *handle=0x%p\n",
+ devnum, func, (unsigned long long)addr, *handle);
+ ret = 0;
+err:
+ kfree(dinfo);
+ return ret;
+}
+
+/**
+ * ide_acpi_hwif_get_handle - Get ACPI object handle for a given hwif
+ * @hwif: device to locate
+ *
+ * Retrieves the object handle for a given hwif.
+ *
+ * Returns handle on success, 0 on error.
+ */
+static acpi_handle ide_acpi_hwif_get_handle(ide_hwif_t *hwif)
+{
+ struct device *dev = hwif->gendev.parent;
+ acpi_handle dev_handle;
+ acpi_integer pcidevfn;
+ acpi_handle chan_handle;
+ int err;
+
+ DEBPRINT("ENTER: device %s\n", hwif->name);
+
+ if (!dev) {
+ DEBPRINT("no PCI device for %s\n", hwif->name);
+ return NULL;
+ }
+
+ err = ide_get_dev_handle(dev, &dev_handle, &pcidevfn);
+ if (err < 0) {
+ DEBPRINT("ide_get_dev_handle failed (%d)\n", err);
+ return NULL;
+ }
+
+ /* get child objects of dev_handle == channel objects,
+ * + _their_ children == drive objects */
+ /* channel is hwif->channel */
+ chan_handle = acpi_get_child(dev_handle, hwif->channel);
+ DEBPRINT("chan adr=%d: handle=0x%p\n",
+ hwif->channel, chan_handle);
+
+ return chan_handle;
+}
+
+/**
+ * ide_acpi_drive_get_handle - Get ACPI object handle for a given drive
+ * @drive: device to locate
+ *
+ * Retrieves the object handle of a given drive. According to the ACPI
+ * spec the drive is a child of the hwif.
+ *
+ * Returns handle on success, 0 on error.
+ */
+static acpi_handle ide_acpi_drive_get_handle(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ int port;
+ acpi_handle drive_handle;
+
+ if (!hwif->acpidata)
+ return NULL;
+
+ if (!hwif->acpidata->obj_handle)
+ return NULL;
+
+ port = hwif->channel ? drive->dn - 2: drive->dn;
+
+ DEBPRINT("ENTER: %s at channel#: %d port#: %d\n",
+ drive->name, hwif->channel, port);
+
+
+ /* TBD: could also check ACPI object VALID bits */
+ drive_handle = acpi_get_child(hwif->acpidata->obj_handle, port);
+ DEBPRINT("drive %s handle 0x%p\n", drive->name, drive_handle);
+
+ return drive_handle;
+}
+
+/**
+ * do_drive_get_GTF - get the drive bootup default taskfile settings
+ * @drive: the drive for which the taskfile settings should be retrieved
+ * @gtf_length: number of bytes of _GTF data returned at @gtf_address
+ * @gtf_address: buffer containing _GTF taskfile arrays
+ *
+ * The _GTF method has no input parameters.
+ * It returns a variable number of register set values (registers
+ * hex 1F1..1F7, taskfiles).
+ * The <variable number> is not known in advance, so have ACPI-CA
+ * allocate the buffer as needed and return it, then free it later.
+ *
+ * The returned @gtf_length and @gtf_address are only valid if the
+ * function return value is 0.
+ */
+static int do_drive_get_GTF(ide_drive_t *drive,
+ unsigned int *gtf_length, unsigned long *gtf_address,
+ unsigned long *obj_loc)
+{
+ acpi_status status;
+ struct acpi_buffer output;
+ union acpi_object *out_obj;
+ ide_hwif_t *hwif = HWIF(drive);
+ struct device *dev = hwif->gendev.parent;
+ int err = -ENODEV;
+ int port;
+
+ *gtf_length = 0;
+ *gtf_address = 0UL;
+ *obj_loc = 0UL;
+
+ if (ide_noacpi)
+ return 0;
+
+ if (!dev) {
+ DEBPRINT("no PCI device for %s\n", hwif->name);
+ goto out;
+ }
+
+ if (!hwif->acpidata) {
+ DEBPRINT("no ACPI data for %s\n", hwif->name);
+ goto out;
+ }
+
+ port = hwif->channel ? drive->dn - 2: drive->dn;
+
+ if (!drive->acpidata) {
+ if (port == 0) {
+ drive->acpidata = &hwif->acpidata->master;
+ hwif->acpidata->master.drive = drive;
+ } else {
+ drive->acpidata = &hwif->acpidata->slave;
+ hwif->acpidata->slave.drive = drive;
+ }
+ }
+
+ DEBPRINT("ENTER: %s at %s, port#: %d, hard_port#: %d\n",
+ hwif->name, dev->bus_id, port, hwif->channel);
+
+ if (!drive->present) {
+ DEBPRINT("%s drive %d:%d not present\n",
+ hwif->name, hwif->channel, port);
+ goto out;
+ }
+
+ /* Get this drive's _ADR info. if not already known. */
+ if (!drive->acpidata->obj_handle) {
+ drive->acpidata->obj_handle = ide_acpi_drive_get_handle(drive);
+ if (!drive->acpidata->obj_handle) {
+ DEBPRINT("No ACPI object found for %s\n",
+ drive->name);
+ goto out;
+ }
+ }
+
+ /* Setting up output buffer */
+ output.length = ACPI_ALLOCATE_BUFFER;
+ output.pointer = NULL; /* ACPI-CA sets this; save/free it later */
+
+ /* _GTF has no input parameters */
+ err = -EIO;
+ status = acpi_evaluate_object(drive->acpidata->obj_handle, "_GTF",
+ NULL, &output);
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_DEBUG
+ "%s: Run _GTF error: status = 0x%x\n",
+ __FUNCTION__, status);
+ goto out;
+ }
+
+ if (!output.length || !output.pointer) {
+ DEBPRINT("Run _GTF: "
+ "length or ptr is NULL (0x%llx, 0x%p)\n",
+ (unsigned long long)output.length,
+ output.pointer);
+ goto out;
+ }
+
+ out_obj = output.pointer;
+ if (out_obj->type != ACPI_TYPE_BUFFER) {
+ DEBPRINT("Run _GTF: error: "
+ "expected object type of ACPI_TYPE_BUFFER, "
+ "got 0x%x\n", out_obj->type);
+ err = -ENOENT;
+ kfree(output.pointer);
+ goto out;
+ }
+
+ if (!out_obj->buffer.length || !out_obj->buffer.pointer ||
+ out_obj->buffer.length % REGS_PER_GTF) {
+ printk(KERN_ERR
+ "%s: unexpected GTF length (%d) or addr (0x%p)\n",
+ __FUNCTION__, out_obj->buffer.length,
+ out_obj->buffer.pointer);
+ err = -ENOENT;
+ kfree(output.pointer);
+ goto out;
+ }
+
+ *gtf_length = out_obj->buffer.length;
+ *gtf_address = (unsigned long)out_obj->buffer.pointer;
+ *obj_loc = (unsigned long)out_obj;
+ DEBPRINT("returning gtf_length=%d, gtf_address=0x%lx, obj_loc=0x%lx\n",
+ *gtf_length, *gtf_address, *obj_loc);
+ err = 0;
+out:
+ return err;
+}
+
+/**
+ * taskfile_load_raw - send taskfile registers to drive
+ * @drive: drive to which output is sent
+ * @gtf: raw ATA taskfile register set (0x1f1 - 0x1f7)
+ *
+ * Outputs IDE taskfile to the drive.
+ */
+static int taskfile_load_raw(ide_drive_t *drive,
+ const struct taskfile_array *gtf)
+{
+ ide_task_t args;
+ int err = 0;
+
+ DEBPRINT("(0x1f1-1f7): hex: "
+ "%02x %02x %02x %02x %02x %02x %02x\n",
+ gtf->tfa[0], gtf->tfa[1], gtf->tfa[2],
+ gtf->tfa[3], gtf->tfa[4], gtf->tfa[5], gtf->tfa[6]);
+
+ memset(&args, 0, sizeof(ide_task_t));
+ args.command_type = IDE_DRIVE_TASK_NO_DATA;
+ args.data_phase = TASKFILE_IN;
+ args.handler = &task_no_data_intr;
+
+ /* convert gtf to IDE Taskfile */
+ args.tfRegister[1] = gtf->tfa[0]; /* 0x1f1 */
+ args.tfRegister[2] = gtf->tfa[1]; /* 0x1f2 */
+ args.tfRegister[3] = gtf->tfa[2]; /* 0x1f3 */
+ args.tfRegister[4] = gtf->tfa[3]; /* 0x1f4 */
+ args.tfRegister[5] = gtf->tfa[4]; /* 0x1f5 */
+ args.tfRegister[6] = gtf->tfa[5]; /* 0x1f6 */
+ args.tfRegister[7] = gtf->tfa[6]; /* 0x1f7 */
+
+ if (ide_noacpitfs) {
+ DEBPRINT("_GTF execution disabled\n");
+ return err;
+ }
+
+ err = ide_raw_taskfile(drive, &args, NULL);
+ if (err)
+ printk(KERN_ERR "%s: ide_raw_taskfile failed: %u\n",
+ __FUNCTION__, err);
+
+ return err;
+}
+
+/**
+ * do_drive_set_taskfiles - write the drive taskfile settings from _GTF
+ * @drive: the drive to which the taskfile command should be sent
+ * @gtf_length: total number of bytes of _GTF taskfiles
+ * @gtf_address: location of _GTF taskfile arrays
+ *
+ * Write {gtf_address, length gtf_length} in groups of
+ * REGS_PER_GTF bytes.
+ */
+static int do_drive_set_taskfiles(ide_drive_t *drive,
+ unsigned int gtf_length,
+ unsigned long gtf_address)
+{
+ int rc = -ENODEV, err;
+ int gtf_count = gtf_length / REGS_PER_GTF;
+ int ix;
+ struct taskfile_array *gtf;
+
+ if (ide_noacpi)
+ return 0;
+
+ DEBPRINT("ENTER: %s, hard_port#: %d\n", drive->name, drive->dn);
+
+ if (!drive->present)
+ goto out;
+ if (!gtf_count) /* shouldn't be here */
+ goto out;
+
+ DEBPRINT("total GTF bytes=%u (0x%x), gtf_count=%d, addr=0x%lx\n",
+ gtf_length, gtf_length, gtf_count, gtf_address);
+
+ if (gtf_length % REGS_PER_GTF) {
+ printk(KERN_ERR "%s: unexpected GTF length (%d)\n",
+ __FUNCTION__, gtf_length);
+ goto out;
+ }
+
+ rc = 0;
+ for (ix = 0; ix < gtf_count; ix++) {
+ gtf = (struct taskfile_array *)
+ (gtf_address + ix * REGS_PER_GTF);
+
+ /* send all TaskFile registers (0x1f1-0x1f7) *in*that*order* */
+ err = taskfile_load_raw(drive, gtf);
+ if (err)
+ rc = err;
+ }
+
+out:
+ return rc;
+}
+
+/**
+ * ide_acpi_exec_tfs - get then write drive taskfile settings
+ * @drive: the drive for which the taskfile settings should be
+ * written.
+ *
+ * According to the ACPI spec this should be called after _STM
+ * has been evaluated for the interface. Some ACPI vendors interpret
+ * that as a hard requirement and modify the taskfile according
+ * to the Identify Drive information passed down with _STM.
+ * So one should really make sure to call this only after _STM has
+ * been executed.
+ */
+int ide_acpi_exec_tfs(ide_drive_t *drive)
+{
+ int ret;
+ unsigned int gtf_length;
+ unsigned long gtf_address;
+ unsigned long obj_loc;
+
+ if (ide_noacpi)
+ return 0;
+
+ DEBPRINT("call get_GTF, drive=%s port=%d\n", drive->name, drive->dn);
+
+ ret = do_drive_get_GTF(drive, &gtf_length, &gtf_address, &obj_loc);
+ if (ret < 0) {
+ DEBPRINT("get_GTF error (%d)\n", ret);
+ return ret;
+ }
+
+ DEBPRINT("call set_taskfiles, drive=%s\n", drive->name);
+
+ ret = do_drive_set_taskfiles(drive, gtf_length, gtf_address);
+ kfree((void *)obj_loc);
+ if (ret < 0) {
+ DEBPRINT("set_taskfiles error (%d)\n", ret);
+ }
+
+ DEBPRINT("ret=%d\n", ret);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ide_acpi_exec_tfs);
+
+/**
+ * ide_acpi_get_timing - get the channel (controller) timings
+ * @hwif: target IDE interface (channel)
+ *
+ * This function executes the _GTM ACPI method for the target channel.
+ *
+ */
+void ide_acpi_get_timing(ide_hwif_t *hwif)
+{
+ acpi_status status;
+ struct acpi_buffer output;
+ union acpi_object *out_obj;
+
+ if (ide_noacpi)
+ return;
+
+ DEBPRINT("ENTER:\n");
+
+ if (!hwif->acpidata) {
+ DEBPRINT("no ACPI data for %s\n", hwif->name);
+ return;
+ }
+
+ /* Setting up output buffer for _GTM */
+ output.length = ACPI_ALLOCATE_BUFFER;
+ output.pointer = NULL; /* ACPI-CA sets this; save/free it later */
+
+ /* _GTM has no input parameters */
+ status = acpi_evaluate_object(hwif->acpidata->obj_handle, "_GTM",
+ NULL, &output);
+
+ DEBPRINT("_GTM status: %d, outptr: 0x%p, outlen: 0x%llx\n",
+ status, output.pointer,
+ (unsigned long long)output.length);
+
+ if (ACPI_FAILURE(status)) {
+ DEBPRINT("Run _GTM error: status = 0x%x\n", status);
+ return;
+ }
+
+ if (!output.length || !output.pointer) {
+ DEBPRINT("Run _GTM: length or ptr is NULL (0x%llx, 0x%p)\n",
+ (unsigned long long)output.length,
+ output.pointer);
+ kfree(output.pointer);
+ return;
+ }
+
+ out_obj = output.pointer;
+ if (out_obj->type != ACPI_TYPE_BUFFER) {
+ kfree(output.pointer);
+ DEBPRINT("Run _GTM: error: "
+ "expected object type of ACPI_TYPE_BUFFER, "
+ "got 0x%x\n", out_obj->type);
+ return;
+ }
+
+ if (!out_obj->buffer.length || !out_obj->buffer.pointer ||
+ out_obj->buffer.length != sizeof(struct GTM_buffer)) {
+ kfree(output.pointer);
+ printk(KERN_ERR
+ "%s: unexpected _GTM length (0x%x)[should be 0x%zx] or "
+ "addr (0x%p)\n",
+ __FUNCTION__, out_obj->buffer.length,
+ sizeof(struct GTM_buffer), out_obj->buffer.pointer);
+ return;
+ }
+
+ memcpy(&hwif->acpidata->gtm, out_obj->buffer.pointer,
+ sizeof(struct GTM_buffer));
+
+ DEBPRINT("_GTM info: ptr: 0x%p, len: 0x%x, exp.len: 0x%Zx\n",
+ out_obj->buffer.pointer, out_obj->buffer.length,
+ sizeof(struct GTM_buffer));
+
+ DEBPRINT("_GTM fields: 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n",
+ hwif->acpidata->gtm.PIO_speed0,
+ hwif->acpidata->gtm.DMA_speed0,
+ hwif->acpidata->gtm.PIO_speed1,
+ hwif->acpidata->gtm.DMA_speed1,
+ hwif->acpidata->gtm.GTM_flags);
+
+ kfree(output.pointer);
+}
+EXPORT_SYMBOL_GPL(ide_acpi_get_timing);
+
+/**
+ * ide_acpi_push_timing - set the channel (controller) timings
+ * @hwif: target IDE interface (channel)
+ *
+ * This function executes the _STM ACPI method for the target channel.
+ *
+ * _STM requires Identify Drive data, which has to passed as an argument.
+ * Unfortunately hd_driveid is a mangled version which we can't readily
+ * use; hence we'll get the information afresh.
+ */
+void ide_acpi_push_timing(ide_hwif_t *hwif)
+{
+ acpi_status status;
+ struct acpi_object_list input;
+ union acpi_object in_params[3];
+ struct ide_acpi_drive_link *master = &hwif->acpidata->master;
+ struct ide_acpi_drive_link *slave = &hwif->acpidata->slave;
+
+ if (ide_noacpi)
+ return;
+
+ DEBPRINT("ENTER:\n");
+
+ if (!hwif->acpidata) {
+ DEBPRINT("no ACPI data for %s\n", hwif->name);
+ return;
+ }
+
+ /* Give the GTM buffer + drive Identify data to the channel via the
+ * _STM method: */
+ /* setup input parameters buffer for _STM */
+ input.count = 3;
+ input.pointer = in_params;
+ in_params[0].type = ACPI_TYPE_BUFFER;
+ in_params[0].buffer.length = sizeof(struct GTM_buffer);
+ in_params[0].buffer.pointer = (u8 *)&hwif->acpidata->gtm;
+ in_params[1].type = ACPI_TYPE_BUFFER;
+ in_params[1].buffer.length = sizeof(struct hd_driveid);
+ in_params[1].buffer.pointer = (u8 *)&master->idbuff;
+ in_params[2].type = ACPI_TYPE_BUFFER;
+ in_params[2].buffer.length = sizeof(struct hd_driveid);
+ in_params[2].buffer.pointer = (u8 *)&slave->idbuff;
+ /* Output buffer: _STM has no output */
+
+ status = acpi_evaluate_object(hwif->acpidata->obj_handle, "_STM",
+ &input, NULL);
+
+ if (ACPI_FAILURE(status)) {
+ DEBPRINT("Run _STM error: status = 0x%x\n", status);
+ }
+ DEBPRINT("_STM status: %d\n", status);
+}
+EXPORT_SYMBOL_GPL(ide_acpi_push_timing);
+
+/**
+ * ide_acpi_init - initialize the ACPI link for an IDE interface
+ * @hwif: target IDE interface (channel)
+ *
+ * The ACPI spec is not quite clear when the drive identify buffer
+ * should be obtained. Calling IDENTIFY DEVICE during shutdown
+ * is not the best of ideas as the drive might already being put to
+ * sleep. And obviously we can't call it during resume.
+ * So we get the information during startup; but this means that
+ * any changes during run-time will be lost after resume.
+ */
+void ide_acpi_init(ide_hwif_t *hwif)
+{
+ int unit;
+ int err;
+ struct ide_acpi_drive_link *master;
+ struct ide_acpi_drive_link *slave;
+
+ hwif->acpidata = kzalloc(sizeof(struct ide_acpi_hwif_link), GFP_KERNEL);
+ if (!hwif->acpidata)
+ return;
+
+ hwif->acpidata->obj_handle = ide_acpi_hwif_get_handle(hwif);
+ if (!hwif->acpidata->obj_handle) {
+ DEBPRINT("no ACPI object for %s found\n", hwif->name);
+ kfree(hwif->acpidata);
+ hwif->acpidata = NULL;
+ return;
+ }
+
+ /*
+ * The ACPI spec mandates that we send information
+ * for both drives, regardless whether they are connected
+ * or not.
+ */
+ hwif->acpidata->master.drive = &hwif->drives[0];
+ hwif->drives[0].acpidata = &hwif->acpidata->master;
+ master = &hwif->acpidata->master;
+
+ hwif->acpidata->slave.drive = &hwif->drives[1];
+ hwif->drives[1].acpidata = &hwif->acpidata->slave;
+ slave = &hwif->acpidata->slave;
+
+
+ /*
+ * Send IDENTIFY for each drive
+ */
+ if (master->drive->present) {
+ err = taskfile_lib_get_identify(master->drive, master->idbuff);
+ if (err) {
+ DEBPRINT("identify device %s failed (%d)\n",
+ master->drive->name, err);
+ }
+ }
+
+ if (slave->drive->present) {
+ err = taskfile_lib_get_identify(slave->drive, slave->idbuff);
+ if (err) {
+ DEBPRINT("identify device %s failed (%d)\n",
+ slave->drive->name, err);
+ }
+ }
+
+ if (ide_noacpionboot) {
+ DEBPRINT("ACPI methods disabled on boot\n");
+ return;
+ }
+
+ /*
+ * ACPI requires us to call _STM on startup
+ */
+ ide_acpi_get_timing(hwif);
+ ide_acpi_push_timing(hwif);
+
+ for (unit = 0; unit < MAX_DRIVES; ++unit) {
+ ide_drive_t *drive = &hwif->drives[unit];
+
+ if (drive->present) {
+ /* Execute ACPI startup code */
+ ide_acpi_exec_tfs(drive);
+ }
+ }
+}
+EXPORT_SYMBOL_GPL(ide_acpi_init);
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
index 5969cec58dc..45a928c058c 100644
--- a/drivers/ide/ide-cd.c
+++ b/drivers/ide/ide-cd.c
@@ -687,15 +687,8 @@ static void ide_dump_status_no_sense(ide_drive_t *drive, const char *msg, u8 sta
static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
{
struct request *rq = HWGROUP(drive)->rq;
- ide_hwif_t *hwif = HWIF(drive);
int stat, err, sense_key;
- /* We may have bogus DMA interrupts in PIO state here */
- if (HWIF(drive)->dma_status && hwif->atapi_irq_bogon) {
- stat = hwif->INB(hwif->dma_status);
- /* Should we force the bit as well ? */
- hwif->OUTB(stat, hwif->dma_status);
- }
/* Check for errors. */
stat = HWIF(drive)->INB(IDE_STATUS_REG);
if (stat_ret)
@@ -930,6 +923,10 @@ static ide_startstop_t cdrom_start_packet_command(ide_drive_t *drive,
HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG);
if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
+ /* waiting for CDB interrupt, not DMA yet. */
+ if (info->dma)
+ drive->waiting_for_dma = 0;
+
/* packet command */
ide_execute_command(drive, WIN_PACKETCMD, handler, ATAPI_WAIT_PC, cdrom_timer_expiry);
return ide_started;
@@ -972,6 +969,10 @@ static ide_startstop_t cdrom_transfer_packet_command (ide_drive_t *drive,
/* Check for errors. */
if (cdrom_decode_status(drive, DRQ_STAT, NULL))
return ide_stopped;
+
+ /* Ok, next interrupt will be DMA interrupt. */
+ if (info->dma)
+ drive->waiting_for_dma = 1;
} else {
/* Otherwise, we must wait for DRQ to get set. */
if (ide_wait_stat(&startstop, drive, DRQ_STAT,
@@ -1103,7 +1104,7 @@ static ide_startstop_t cdrom_read_intr (ide_drive_t *drive)
if (dma) {
info->dma = 0;
if ((dma_error = HWIF(drive)->ide_dma_end(drive)))
- __ide_dma_off(drive);
+ ide_dma_off(drive);
}
if (cdrom_decode_status(drive, 0, &stat))
@@ -1699,7 +1700,7 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
if (dma) {
if (dma_error) {
printk(KERN_ERR "ide-cd: dma error\n");
- __ide_dma_off(drive);
+ ide_dma_off(drive);
return ide_error(drive, "dma error", stat);
}
@@ -1825,7 +1826,7 @@ static ide_startstop_t cdrom_write_intr(ide_drive_t *drive)
info->dma = 0;
if ((dma_error = HWIF(drive)->ide_dma_end(drive))) {
printk(KERN_ERR "ide-cd: write dma error\n");
- __ide_dma_off(drive);
+ ide_dma_off(drive);
}
}
@@ -3254,14 +3255,6 @@ int ide_cdrom_setup (ide_drive_t *drive)
if (drive->autotune == IDE_TUNE_DEFAULT ||
drive->autotune == IDE_TUNE_AUTO)
drive->dsc_overlap = (drive->next != drive);
-#if 0
- drive->dsc_overlap = (HWIF(drive)->no_dsc) ? 0 : 1;
- if (HWIF(drive)->no_dsc) {
- printk(KERN_INFO "ide-cd: %s: disabling DSC overlap\n",
- drive->name);
- drive->dsc_overlap = 0;
- }
-#endif
if (ide_cdrom_register(drive, nslots)) {
printk (KERN_ERR "%s: ide_cdrom_setup failed to register device with the cdrom driver.\n", drive->name);
@@ -3360,21 +3353,16 @@ static int idecd_open(struct inode * inode, struct file * file)
{
struct gendisk *disk = inode->i_bdev->bd_disk;
struct cdrom_info *info;
- ide_drive_t *drive;
int rc = -ENOMEM;
if (!(info = ide_cd_get(disk)))
return -ENXIO;
- drive = info->drive;
-
- drive->usage++;
-
if (!info->buffer)
- info->buffer = kmalloc(SECTOR_BUFFER_SIZE,
- GFP_KERNEL|__GFP_REPEAT);
- if (!info->buffer || (rc = cdrom_open(&info->devinfo, inode, file)))
- drive->usage--;
+ info->buffer = kmalloc(SECTOR_BUFFER_SIZE, GFP_KERNEL|__GFP_REPEAT);
+
+ if (info->buffer)
+ rc = cdrom_open(&info->devinfo, inode, file);
if (rc < 0)
ide_cd_put(info);
@@ -3386,10 +3374,8 @@ static int idecd_release(struct inode * inode, struct file * file)
{
struct gendisk *disk = inode->i_bdev->bd_disk;
struct cdrom_info *info = ide_cd_g(disk);
- ide_drive_t *drive = info->drive;
cdrom_release (&info->devinfo, file);
- drive->usage--;
ide_cd_put(info);
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
index 0a05a377d66..e2cea1889c4 100644
--- a/drivers/ide/ide-disk.c
+++ b/drivers/ide/ide-disk.c
@@ -77,6 +77,7 @@ struct ide_disk_obj {
ide_driver_t *driver;
struct gendisk *disk;
struct kref kref;
+ unsigned int openers; /* protected by BKL for now */
};
static DEFINE_MUTEX(idedisk_ref_mutex);
@@ -1081,8 +1082,9 @@ static int idedisk_open(struct inode *inode, struct file *filp)
drive = idkp->drive;
- drive->usage++;
- if (drive->removable && drive->usage == 1) {
+ idkp->openers++;
+
+ if (drive->removable && idkp->openers == 1) {
ide_task_t args;
memset(&args, 0, sizeof(ide_task_t));
args.tfRegister[IDE_COMMAND_OFFSET] = WIN_DOORLOCK;
@@ -1106,9 +1108,10 @@ static int idedisk_release(struct inode *inode, struct file *filp)
struct ide_disk_obj *idkp = ide_disk_g(disk);
ide_drive_t *drive = idkp->drive;
- if (drive->usage == 1)
+ if (idkp->openers == 1)
ide_cacheflush_p(drive);
- if (drive->removable && drive->usage == 1) {
+
+ if (drive->removable && idkp->openers == 1) {
ide_task_t args;
memset(&args, 0, sizeof(ide_task_t));
args.tfRegister[IDE_COMMAND_OFFSET] = WIN_DOORUNLOCK;
@@ -1117,7 +1120,8 @@ static int idedisk_release(struct inode *inode, struct file *filp)
if (drive->doorlocking && ide_raw_taskfile(drive, &args, NULL))
drive->doorlocking = 0;
}
- drive->usage--;
+
+ idkp->openers--;
ide_disk_put(idkp);
diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c
index 56efed6742d..08e7cd043bc 100644
--- a/drivers/ide/ide-dma.c
+++ b/drivers/ide/ide-dma.c
@@ -348,15 +348,14 @@ EXPORT_SYMBOL_GPL(ide_destroy_dmatable);
static int config_drive_for_dma (ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
- ide_hwif_t *hwif = HWIF(drive);
- if ((id->capability & 1) && hwif->autodma) {
+ if ((id->capability & 1) && drive->hwif->autodma) {
/*
* Enable DMA on any drive that has
* UltraDMA (mode 0/1/2/3/4/5/6) enabled
*/
if ((id->field_valid & 4) && ((id->dma_ultra >> 8) & 0x7f))
- return hwif->ide_dma_on(drive);
+ return 0;
/*
* Enable DMA on any drive that has mode2 DMA
* (multi or single) enabled
@@ -364,14 +363,14 @@ static int config_drive_for_dma (ide_drive_t *drive)
if (id->field_valid & 2) /* regular DMA */
if ((id->dma_mword & 0x404) == 0x404 ||
(id->dma_1word & 0x404) == 0x404)
- return hwif->ide_dma_on(drive);
+ return 0;
/* Consult the list of known "good" drives */
if (__ide_dma_good_drive(drive))
- return hwif->ide_dma_on(drive);
+ return 0;
}
-// if (hwif->tuneproc != NULL) hwif->tuneproc(drive, 255);
- return hwif->ide_dma_off_quietly(drive);
+
+ return -1;
}
/**
@@ -415,72 +414,68 @@ static int dma_timer_expiry (ide_drive_t *drive)
}
/**
- * __ide_dma_host_off - Generic DMA kill
+ * ide_dma_host_off - Generic DMA kill
* @drive: drive to control
*
* Perform the generic IDE controller DMA off operation. This
* works for most IDE bus mastering controllers
*/
-int __ide_dma_host_off (ide_drive_t *drive)
+void ide_dma_host_off(ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
u8 unit = (drive->select.b.unit & 0x01);
u8 dma_stat = hwif->INB(hwif->dma_status);
hwif->OUTB((dma_stat & ~(1<<(5+unit))), hwif->dma_status);
- return 0;
}
-EXPORT_SYMBOL(__ide_dma_host_off);
+EXPORT_SYMBOL(ide_dma_host_off);
/**
- * __ide_dma_host_off_quietly - Generic DMA kill
+ * ide_dma_off_quietly - Generic DMA kill
* @drive: drive to control
*
* Turn off the current DMA on this IDE controller.
*/
-int __ide_dma_off_quietly (ide_drive_t *drive)
+void ide_dma_off_quietly(ide_drive_t *drive)
{
drive->using_dma = 0;
ide_toggle_bounce(drive, 0);
- if (HWIF(drive)->ide_dma_host_off(drive))
- return 1;
-
- return 0;
+ drive->hwif->dma_host_off(drive);
}
-EXPORT_SYMBOL(__ide_dma_off_quietly);
+EXPORT_SYMBOL(ide_dma_off_quietly);
#endif /* CONFIG_BLK_DEV_IDEDMA_PCI */
/**
- * __ide_dma_off - disable DMA on a device
+ * ide_dma_off - disable DMA on a device
* @drive: drive to disable DMA on
*
* Disable IDE DMA for a device on this IDE controller.
* Inform the user that DMA has been disabled.
*/
-int __ide_dma_off (ide_drive_t *drive)
+void ide_dma_off(ide_drive_t *drive)
{
printk(KERN_INFO "%s: DMA disabled\n", drive->name);
- return HWIF(drive)->ide_dma_off_quietly(drive);
+ drive->hwif->dma_off_quietly(drive);
}
-EXPORT_SYMBOL(__ide_dma_off);
+EXPORT_SYMBOL(ide_dma_off);
#ifdef CONFIG_BLK_DEV_IDEDMA_PCI
/**
- * __ide_dma_host_on - Enable DMA on a host
+ * ide_dma_host_on - Enable DMA on a host
* @drive: drive to enable for DMA
*
* Enable DMA on an IDE controller following generic bus mastering
* IDE controller behaviour
*/
-
-int __ide_dma_host_on (ide_drive_t *drive)
+
+void ide_dma_host_on(ide_drive_t *drive)
{
if (drive->using_dma) {
ide_hwif_t *hwif = HWIF(drive);
@@ -488,12 +483,10 @@ int __ide_dma_host_on (ide_drive_t *drive)
u8 dma_stat = hwif->INB(hwif->dma_status);
hwif->OUTB((dma_stat|(1<<(5+unit))), hwif->dma_status);
- return 0;
}
- return 1;
}
-EXPORT_SYMBOL(__ide_dma_host_on);
+EXPORT_SYMBOL(ide_dma_host_on);
/**
* __ide_dma_on - Enable DMA on a device
@@ -511,8 +504,7 @@ int __ide_dma_on (ide_drive_t *drive)
drive->using_dma = 1;
ide_toggle_bounce(drive, 1);
- if (HWIF(drive)->ide_dma_host_on(drive))
- return 1;
+ drive->hwif->dma_host_on(drive);
return 0;
}
@@ -565,7 +557,10 @@ int ide_dma_setup(ide_drive_t *drive)
}
/* PRD table */
- hwif->OUTL(hwif->dmatable_dma, hwif->dma_prdtable);
+ if (hwif->mmio)
+ writel(hwif->dmatable_dma, (void __iomem *)hwif->dma_prdtable);
+ else
+ outl(hwif->dmatable_dma, hwif->dma_prdtable);
/* specify r/w */
hwif->OUTB(reading, hwif->dma_command);
@@ -680,6 +675,9 @@ int ide_use_dma(ide_drive_t *drive)
struct hd_driveid *id = drive->id;
ide_hwif_t *hwif = drive->hwif;
+ if ((id->capability & 1) == 0 || drive->autodma == 0)
+ return 0;
+
/* consult the list of known "bad" drives */
if (__ide_dma_bad_drive(drive))
return 0;
@@ -753,12 +751,37 @@ void ide_dma_verbose(ide_drive_t *drive)
return;
bug_dma_off:
printk(", BUG DMA OFF");
- hwif->ide_dma_off_quietly(drive);
+ hwif->dma_off_quietly(drive);
return;
}
EXPORT_SYMBOL(ide_dma_verbose);
+int ide_set_dma(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ int rc;
+
+ rc = hwif->ide_dma_check(drive);
+
+ switch(rc) {
+ case -1: /* DMA needs to be disabled */
+ hwif->dma_off_quietly(drive);
+ return 0;
+ case 0: /* DMA needs to be enabled */
+ return hwif->ide_dma_on(drive);
+ case 1: /* DMA setting cannot be changed */
+ break;
+ default:
+ BUG();
+ break;
+ }
+
+ return rc;
+}
+
+EXPORT_SYMBOL_GPL(ide_set_dma);
+
#ifdef CONFIG_BLK_DEV_IDEDMA_PCI
int __ide_dma_lostirq (ide_drive_t *drive)
{
@@ -809,7 +832,7 @@ int ide_release_dma(ide_hwif_t *hwif)
{
ide_release_dma_engine(hwif);
- if (hwif->mmio == 2)
+ if (hwif->mmio)
return 1;
else
return ide_release_iomio_dma(hwif);
@@ -878,9 +901,9 @@ static int ide_iomio_dma(ide_hwif_t *hwif, unsigned long base, unsigned int port
static int ide_dma_iobase(ide_hwif_t *hwif, unsigned long base, unsigned int ports)
{
- if (hwif->mmio == 2)
+ if (hwif->mmio)
return ide_mapped_mmio_dma(hwif, base,ports);
- BUG_ON(hwif->mmio == 1);
+
return ide_iomio_dma(hwif, base, ports);
}
@@ -908,14 +931,14 @@ void ide_setup_dma (ide_hwif_t *hwif, unsigned long dma_base, unsigned int num_p
if (!(hwif->dma_prdtable))
hwif->dma_prdtable = (hwif->dma_base + 4);
- if (!hwif->ide_dma_off_quietly)
- hwif->ide_dma_off_quietly = &__ide_dma_off_quietly;
- if (!hwif->ide_dma_host_off)
- hwif->ide_dma_host_off = &__ide_dma_host_off;
+ if (!hwif->dma_off_quietly)
+ hwif->dma_off_quietly = &ide_dma_off_quietly;
+ if (!hwif->dma_host_off)
+ hwif->dma_host_off = &ide_dma_host_off;
if (!hwif->ide_dma_on)
hwif->ide_dma_on = &__ide_dma_on;
- if (!hwif->ide_dma_host_on)
- hwif->ide_dma_host_on = &__ide_dma_host_on;
+ if (!hwif->dma_host_on)
+ hwif->dma_host_on = &ide_dma_host_on;
if (!hwif->ide_dma_check)
hwif->ide_dma_check = &__ide_dma_check;
if (!hwif->dma_setup)
diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c
index d33717c8afd..57cd21c5b2c 100644
--- a/drivers/ide/ide-floppy.c
+++ b/drivers/ide/ide-floppy.c
@@ -279,6 +279,7 @@ typedef struct ide_floppy_obj {
ide_driver_t *driver;
struct gendisk *disk;
struct kref kref;
+ unsigned int openers; /* protected by BKL for now */
/* Current packet command */
idefloppy_pc_t *pc;
@@ -866,7 +867,7 @@ static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
if (test_and_clear_bit(PC_DMA_IN_PROGRESS, &pc->flags)) {
printk(KERN_ERR "ide-floppy: The floppy wants to issue "
"more interrupts in DMA mode\n");
- (void)__ide_dma_off(drive);
+ ide_dma_off(drive);
return ide_do_reset(drive);
}
@@ -1096,9 +1097,9 @@ static ide_startstop_t idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *p
pc->current_position = pc->buffer;
bcount.all = min(pc->request_transfer, 63 * 1024);
- if (test_and_clear_bit(PC_DMA_ERROR, &pc->flags)) {
- (void)__ide_dma_off(drive);
- }
+ if (test_and_clear_bit(PC_DMA_ERROR, &pc->flags))
+ ide_dma_off(drive);
+
feature.all = 0;
if (test_bit(PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
@@ -1433,7 +1434,8 @@ static int idefloppy_get_capacity (ide_drive_t *drive)
drive->bios_cyl = 0;
drive->bios_head = drive->bios_sect = 0;
- floppy->blocks = floppy->bs_factor = 0;
+ floppy->blocks = 0;
+ floppy->bs_factor = 1;
set_capacity(floppy->disk, 0);
idefloppy_create_read_capacity_cmd(&pc);
@@ -1949,9 +1951,9 @@ static int idefloppy_open(struct inode *inode, struct file *filp)
drive = floppy->drive;
- drive->usage++;
+ floppy->openers++;
- if (drive->usage == 1) {
+ if (floppy->openers == 1) {
clear_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, &floppy->flags);
/* Just in case */
@@ -1969,13 +1971,11 @@ static int idefloppy_open(struct inode *inode, struct file *filp)
** capacity of the drive or begin the format - Sam
*/
) {
- drive->usage--;
ret = -EIO;
goto out_put_floppy;
}
if (floppy->wp && (filp->f_mode & 2)) {
- drive->usage--;
ret = -EROFS;
goto out_put_floppy;
}
@@ -1987,13 +1987,13 @@ static int idefloppy_open(struct inode *inode, struct file *filp)
}
check_disk_change(inode->i_bdev);
} else if (test_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, &floppy->flags)) {
- drive->usage--;
ret = -EBUSY;
goto out_put_floppy;
}
return 0;
out_put_floppy:
+ floppy->openers--;
ide_floppy_put(floppy);
return ret;
}
@@ -2007,7 +2007,7 @@ static int idefloppy_release(struct inode *inode, struct file *filp)
debug_log(KERN_INFO "Reached idefloppy_release\n");
- if (drive->usage == 1) {
+ if (floppy->openers == 1) {
/* IOMEGA Clik! drives do not support lock/unlock commands */
if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags)) {
idefloppy_create_prevent_cmd(&pc, 0);
@@ -2016,7 +2016,8 @@ static int idefloppy_release(struct inode *inode, struct file *filp)
clear_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, &floppy->flags);
}
- drive->usage--;
+
+ floppy->openers--;
ide_floppy_put(floppy);
@@ -2050,7 +2051,7 @@ static int idefloppy_ioctl(struct inode *inode, struct file *file,
prevent = 0;
/* fall through */
case CDROM_LOCKDOOR:
- if (drive->usage > 1)
+ if (floppy->openers > 1)
return -EBUSY;
/* The IOMEGA Clik! Drive doesn't support this command - no room for an eject mechanism */
@@ -2072,7 +2073,7 @@ static int idefloppy_ioctl(struct inode *inode, struct file *file,
if (!(file->f_mode & 2))
return -EPERM;
- if (drive->usage > 1) {
+ if (floppy->openers > 1) {
/* Don't format if someone is using the disk */
clear_bit(IDEFLOPPY_FORMAT_IN_PROGRESS,
diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
index 2614f41b507..c193553f6fe 100644
--- a/drivers/ide/ide-io.c
+++ b/drivers/ide/ide-io.c
@@ -226,7 +226,7 @@ static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *
break;
if (drive->hwif->ide_dma_check == NULL)
break;
- drive->hwif->ide_dma_check(drive);
+ ide_set_dma(drive);
break;
}
pm->pm_step = ide_pm_state_completed;
@@ -1351,7 +1351,7 @@ static ide_startstop_t ide_dma_timeout_retry(ide_drive_t *drive, int error)
*/
drive->retry_pio++;
drive->state = DMA_PIO_RETRY;
- (void) hwif->ide_dma_off_quietly(drive);
+ hwif->dma_off_quietly(drive);
/*
* un-busy drive etc (hwgroup->busy is cleared on return) and
@@ -1646,6 +1646,17 @@ irqreturn_t ide_intr (int irq, void *dev_id)
del_timer(&hwgroup->timer);
spin_unlock(&ide_lock);
+ /* Some controllers might set DMA INTR no matter DMA or PIO;
+ * bmdma status might need to be cleared even for
+ * PIO interrupts to prevent spurious/lost irq.
+ */
+ if (hwif->ide_dma_clear_irq && !(drive->waiting_for_dma))
+ /* ide_dma_end() needs bmdma status for error checking.
+ * So, skip clearing bmdma status here and leave it
+ * to ide_dma_end() if this is dma interrupt.
+ */
+ hwif->ide_dma_clear_irq(drive);
+
if (drive->unmask)
local_irq_enable_in_hardirq();
/* service this interrupt, may set handler for next interrupt */
diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c
index badde633177..c67b3b1e6f4 100644
--- a/drivers/ide/ide-iops.c
+++ b/drivers/ide/ide-iops.c
@@ -49,11 +49,6 @@ static void ide_insw (unsigned long port, void *addr, u32 count)
insw(port, addr, count);
}
-static u32 ide_inl (unsigned long port)
-{
- return (u32) inl(port);
-}
-
static void ide_insl (unsigned long port, void *addr, u32 count)
{
insl(port, addr, count);
@@ -79,11 +74,6 @@ static void ide_outsw (unsigned long port, void *addr, u32 count)
outsw(port, addr, count);
}
-static void ide_outl (u32 val, unsigned long port)
-{
- outl(val, port);
-}
-
static void ide_outsl (unsigned long port, void *addr, u32 count)
{
outsl(port, addr, count);
@@ -94,12 +84,10 @@ void default_hwif_iops (ide_hwif_t *hwif)
hwif->OUTB = ide_outb;
hwif->OUTBSYNC = ide_outbsync;
hwif->OUTW = ide_outw;
- hwif->OUTL = ide_outl;
hwif->OUTSW = ide_outsw;
hwif->OUTSL = ide_outsl;
hwif->INB = ide_inb;
hwif->INW = ide_inw;
- hwif->INL = ide_inl;
hwif->INSW = ide_insw;
hwif->INSL = ide_insl;
}
@@ -123,11 +111,6 @@ static void ide_mm_insw (unsigned long port, void *addr, u32 count)
__ide_mm_insw((void __iomem *) port, addr, count);
}
-static u32 ide_mm_inl (unsigned long port)
-{
- return (u32) readl((void __iomem *) port);
-}
-
static void ide_mm_insl (unsigned long port, void *addr, u32 count)
{
__ide_mm_insl((void __iomem *) port, addr, count);
@@ -153,11 +136,6 @@ static void ide_mm_outsw (unsigned long port, void *addr, u32 count)
__ide_mm_outsw((void __iomem *) port, addr, count);
}
-static void ide_mm_outl (u32 value, unsigned long port)
-{
- writel(value, (void __iomem *) port);
-}
-
static void ide_mm_outsl (unsigned long port, void *addr, u32 count)
{
__ide_mm_outsl((void __iomem *) port, addr, count);
@@ -170,12 +148,10 @@ void default_hwif_mmiops (ide_hwif_t *hwif)
this one is controller specific! */
hwif->OUTBSYNC = ide_mm_outbsync;
hwif->OUTW = ide_mm_outw;
- hwif->OUTL = ide_mm_outl;
hwif->OUTSW = ide_mm_outsw;
hwif->OUTSL = ide_mm_outsl;
hwif->INB = ide_mm_inb;
hwif->INW = ide_mm_inw;
- hwif->INL = ide_mm_inl;
hwif->INSW = ide_mm_insw;
hwif->INSL = ide_mm_insl;
}
@@ -777,7 +753,7 @@ int ide_config_drive_speed (ide_drive_t *drive, u8 speed)
#ifdef CONFIG_BLK_DEV_IDEDMA
if (hwif->ide_dma_check) /* check if host supports DMA */
- hwif->ide_dma_host_off(drive);
+ hwif->dma_host_off(drive);
#endif
/*
@@ -854,9 +830,9 @@ int ide_config_drive_speed (ide_drive_t *drive, u8 speed)
#ifdef CONFIG_BLK_DEV_IDEDMA
if (speed >= XFER_SW_DMA_0)
- hwif->ide_dma_host_on(drive);
+ hwif->dma_host_on(drive);
else if (hwif->ide_dma_check) /* check if host supports DMA */
- hwif->ide_dma_off_quietly(drive);
+ hwif->dma_off_quietly(drive);
#endif
switch(speed) {
@@ -1066,12 +1042,12 @@ static void check_dma_crc(ide_drive_t *drive)
{
#ifdef CONFIG_BLK_DEV_IDEDMA
if (drive->crc_count) {
- (void) HWIF(drive)->ide_dma_off_quietly(drive);
+ drive->hwif->dma_off_quietly(drive);
ide_set_xfer_rate(drive, ide_auto_reduce_xfer(drive));
if (drive->current_speed >= XFER_SW_DMA_0)
(void) HWIF(drive)->ide_dma_on(drive);
} else
- (void)__ide_dma_off(drive);
+ ide_dma_off(drive);
#endif
}
diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c
index 8237d89eec6..8afce4ceea3 100644
--- a/drivers/ide/ide-lib.c
+++ b/drivers/ide/ide-lib.c
@@ -205,6 +205,21 @@ int ide_dma_enable (ide_drive_t *drive)
EXPORT_SYMBOL(ide_dma_enable);
+int ide_use_fast_pio(ide_drive_t *drive)
+{
+ struct hd_driveid *id = drive->id;
+
+ if ((id->capability & 1) && drive->autodma)
+ return 1;
+
+ if ((id->capability & 8) || (id->field_valid & 2))
+ return 1;
+
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(ide_use_fast_pio);
+
/*
* Standard (generic) timings for PIO modes, from ATA2 specification.
* These timings are for access to the IDE data port register *only*.
@@ -349,7 +364,6 @@ u8 ide_get_best_pio_mode (ide_drive_t *drive, u8 mode_wanted, u8 max_mode, ide_p
int use_iordy = 0;
struct hd_driveid* id = drive->id;
int overridden = 0;
- int blacklisted = 0;
if (mode_wanted != 255) {
pio_mode = mode_wanted;
@@ -357,7 +371,6 @@ u8 ide_get_best_pio_mode (ide_drive_t *drive, u8 mode_wanted, u8 max_mode, ide_p
pio_mode = 0;
} else if ((pio_mode = ide_scan_pio_blacklist(id->model)) != -1) {
overridden = 1;
- blacklisted = 1;
use_iordy = (pio_mode > 2);
} else {
pio_mode = id->tPIO;
@@ -409,7 +422,6 @@ u8 ide_get_best_pio_mode (ide_drive_t *drive, u8 mode_wanted, u8 max_mode, ide_p
d->cycle_time = cycle_time ? cycle_time : ide_pio_timings[pio_mode].cycle_time;
d->use_iordy = use_iordy;
d->overridden = overridden;
- d->blacklisted = blacklisted;
}
return pio_mode;
}
@@ -462,8 +474,6 @@ int ide_set_xfer_rate(ide_drive_t *drive, u8 rate)
return -1;
}
-EXPORT_SYMBOL_GPL(ide_set_xfer_rate);
-
static void ide_dump_opcode(ide_drive_t *drive)
{
struct request *rq;
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
index 5a5c565a32a..8afbd6cb94b 100644
--- a/drivers/ide/ide-probe.c
+++ b/drivers/ide/ide-probe.c
@@ -853,11 +853,11 @@ static void probe_hwif(ide_hwif_t *hwif)
* things, if not checked and cleared.
* PARANOIA!!!
*/
- hwif->ide_dma_off_quietly(drive);
+ hwif->dma_off_quietly(drive);
#ifdef CONFIG_IDEDMA_ONLYDISK
if (drive->media == ide_disk)
#endif
- hwif->ide_dma_check(drive);
+ ide_set_dma(drive);
}
}
}
@@ -1384,6 +1384,9 @@ static int hwif_init(ide_hwif_t *hwif)
done:
init_gendisk(hwif);
+
+ ide_acpi_init(hwif);
+
hwif->present = 1; /* success */
return 1;
diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c
index aa049dab3d9..afb71c66b6f 100644
--- a/drivers/ide/ide-proc.c
+++ b/drivers/ide/ide-proc.c
@@ -26,7 +26,6 @@
#include <asm/uaccess.h>
#include <linux/errno.h>
-#include <linux/sched.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
#include <linux/mm.h>
@@ -413,7 +412,6 @@ void ide_add_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p, void
while (p->name != NULL) {
ent = create_proc_entry(p->name, p->mode, dir);
if (!ent) return;
- ent->nlink = 1;
ent->data = data;
ent->read_proc = p->read_proc;
ent->write_proc = p->write_proc;
@@ -549,7 +547,7 @@ static int ide_drivers_open(struct inode *inode, struct file *file)
return single_open(file, &ide_drivers_show, NULL);
}
-static struct file_operations ide_drivers_operations = {
+static const struct file_operations ide_drivers_operations = {
.open = ide_drivers_open,
.read = seq_read,
.llseek = seq_lseek,
diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
index b3bcd1d7315..4e59239fef7 100644
--- a/drivers/ide/ide-tape.c
+++ b/drivers/ide/ide-tape.c
@@ -1970,7 +1970,7 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
printk(KERN_ERR "ide-tape: The tape wants to issue more "
"interrupts in DMA mode\n");
printk(KERN_ERR "ide-tape: DMA disabled, reverting to PIO\n");
- (void)__ide_dma_off(drive);
+ ide_dma_off(drive);
return ide_do_reset(drive);
}
/* Get the number of bytes to transfer on this interrupt. */
@@ -2176,7 +2176,7 @@ static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape
if (test_and_clear_bit(PC_DMA_ERROR, &pc->flags)) {
printk(KERN_WARNING "ide-tape: DMA disabled, "
"reverting to PIO\n");
- (void)__ide_dma_off(drive);
+ ide_dma_off(drive);
}
if (test_bit(PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
dma_ok = !hwif->dma_setup(drive);
@@ -4779,7 +4779,7 @@ static ide_driver_t idetape_driver = {
/*
* Our character device supporting functions, passed to register_chrdev.
*/
-static struct file_operations idetape_fops = {
+static const struct file_operations idetape_fops = {
.owner = THIS_MODULE,
.read = idetape_chrdev_read,
.write = idetape_chrdev_write,
@@ -4792,15 +4792,10 @@ static int idetape_open(struct inode *inode, struct file *filp)
{
struct gendisk *disk = inode->i_bdev->bd_disk;
struct ide_tape_obj *tape;
- ide_drive_t *drive;
if (!(tape = ide_tape_get(disk)))
return -ENXIO;
- drive = tape->drive;
-
- drive->usage++;
-
return 0;
}
@@ -4808,9 +4803,6 @@ static int idetape_release(struct inode *inode, struct file *filp)
{
struct gendisk *disk = inode->i_bdev->bd_disk;
struct ide_tape_obj *tape = ide_tape_g(disk);
- ide_drive_t *drive = tape->drive;
-
- drive->usage--;
ide_tape_put(tape);
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
index 6c9bd5165bd..b3c0818c5c6 100644
--- a/drivers/ide/ide.c
+++ b/drivers/ide/ide.c
@@ -187,6 +187,12 @@ int noautodma = 1;
EXPORT_SYMBOL(noautodma);
+#ifdef CONFIG_BLK_DEV_IDEACPI
+int ide_noacpi = 0;
+int ide_noacpitfs = 1;
+int ide_noacpionboot = 1;
+#endif
+
/*
* This is declared extern in ide.h, for access by other IDE modules:
*/
@@ -383,9 +389,8 @@ int ide_hwif_request_regions(ide_hwif_t *hwif)
unsigned long addr;
unsigned int i;
- if (hwif->mmio == 2)
+ if (hwif->mmio)
return 0;
- BUG_ON(hwif->mmio == 1);
addr = hwif->io_ports[IDE_CONTROL_OFFSET];
if (addr && !hwif_request_region(hwif, addr, 1))
goto control_region_busy;
@@ -432,7 +437,7 @@ void ide_hwif_release_regions(ide_hwif_t *hwif)
{
u32 i = 0;
- if (hwif->mmio == 2)
+ if (hwif->mmio)
return;
if (hwif->io_ports[IDE_CONTROL_OFFSET])
release_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1);
@@ -501,23 +506,22 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
hwif->ide_dma_end = tmp_hwif->ide_dma_end;
hwif->ide_dma_check = tmp_hwif->ide_dma_check;
hwif->ide_dma_on = tmp_hwif->ide_dma_on;
- hwif->ide_dma_off_quietly = tmp_hwif->ide_dma_off_quietly;
+ hwif->dma_off_quietly = tmp_hwif->dma_off_quietly;
hwif->ide_dma_test_irq = tmp_hwif->ide_dma_test_irq;
- hwif->ide_dma_host_on = tmp_hwif->ide_dma_host_on;
- hwif->ide_dma_host_off = tmp_hwif->ide_dma_host_off;
+ hwif->ide_dma_clear_irq = tmp_hwif->ide_dma_clear_irq;
+ hwif->dma_host_on = tmp_hwif->dma_host_on;
+ hwif->dma_host_off = tmp_hwif->dma_host_off;
hwif->ide_dma_lostirq = tmp_hwif->ide_dma_lostirq;
hwif->ide_dma_timeout = tmp_hwif->ide_dma_timeout;
hwif->OUTB = tmp_hwif->OUTB;
hwif->OUTBSYNC = tmp_hwif->OUTBSYNC;
hwif->OUTW = tmp_hwif->OUTW;
- hwif->OUTL = tmp_hwif->OUTL;
hwif->OUTSW = tmp_hwif->OUTSW;
hwif->OUTSL = tmp_hwif->OUTSL;
hwif->INB = tmp_hwif->INB;
hwif->INW = tmp_hwif->INW;
- hwif->INL = tmp_hwif->INL;
hwif->INSW = tmp_hwif->INSW;
hwif->INSL = tmp_hwif->INSL;
@@ -545,7 +549,6 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
hwif->extra_ports = tmp_hwif->extra_ports;
hwif->autodma = tmp_hwif->autodma;
hwif->udma_four = tmp_hwif->udma_four;
- hwif->no_dsc = tmp_hwif->no_dsc;
hwif->hwif_data = tmp_hwif->hwif_data;
}
@@ -1132,12 +1135,11 @@ static int set_using_dma (ide_drive_t *drive, int arg)
if (HWIF(drive)->ide_dma_check == NULL)
return -EPERM;
if (arg) {
- if (HWIF(drive)->ide_dma_check(drive)) return -EIO;
- if (HWIF(drive)->ide_dma_on(drive)) return -EIO;
- } else {
- if (__ide_dma_off(drive))
+ if (ide_set_dma(drive))
return -EIO;
- }
+ if (HWIF(drive)->ide_dma_on(drive)) return -EIO;
+ } else
+ ide_dma_off(drive);
return 0;
#else
return -EPERM;
@@ -1214,10 +1216,15 @@ EXPORT_SYMBOL(system_bus_clock);
static int generic_ide_suspend(struct device *dev, pm_message_t mesg)
{
ide_drive_t *drive = dev->driver_data;
+ ide_hwif_t *hwif = HWIF(drive);
struct request rq;
struct request_pm_state rqpm;
ide_task_t args;
+ /* Call ACPI _GTM only once */
+ if (!(drive->dn % 2))
+ ide_acpi_get_timing(hwif);
+
memset(&rq, 0, sizeof(rq));
memset(&rqpm, 0, sizeof(rqpm));
memset(&args, 0, sizeof(args));
@@ -1235,10 +1242,17 @@ static int generic_ide_suspend(struct device *dev, pm_message_t mesg)
static int generic_ide_resume(struct device *dev)
{
ide_drive_t *drive = dev->driver_data;
+ ide_hwif_t *hwif = HWIF(drive);
struct request rq;
struct request_pm_state rqpm;
ide_task_t args;
+ /* Call ACPI _STM only once */
+ if (!(drive->dn % 2))
+ ide_acpi_push_timing(hwif);
+
+ ide_acpi_exec_tfs(drive);
+
memset(&rq, 0, sizeof(rq));
memset(&rqpm, 0, sizeof(rqpm));
memset(&args, 0, sizeof(args));
@@ -1543,6 +1557,24 @@ static int __init ide_setup(char *s)
}
#endif /* CONFIG_BLK_DEV_IDEPCI */
+#ifdef CONFIG_BLK_DEV_IDEACPI
+ if (!strcmp(s, "ide=noacpi")) {
+ //printk(" : Disable IDE ACPI support.\n");
+ ide_noacpi = 1;
+ return 1;
+ }
+ if (!strcmp(s, "ide=acpigtf")) {
+ //printk(" : Enable IDE ACPI _GTF support.\n");
+ ide_noacpitfs = 0;
+ return 1;
+ }
+ if (!strcmp(s, "ide=acpionboot")) {
+ //printk(" : Call IDE ACPI methods on boot.\n");
+ ide_noacpionboot = 0;
+ return 1;
+ }
+#endif /* CONFIG_BLK_DEV_IDEACPI */
+
/*
* Look for drive options: "hdx="
*/
diff --git a/drivers/ide/legacy/buddha.c b/drivers/ide/legacy/buddha.c
index 0391a312287..1ed224a01f7 100644
--- a/drivers/ide/legacy/buddha.c
+++ b/drivers/ide/legacy/buddha.c
@@ -215,7 +215,7 @@ fail_base2:
index = ide_register_hw(&hw, &hwif);
if (index != -1) {
- hwif->mmio = 2;
+ hwif->mmio = 1;
printk("ide%d: ", index);
switch(type) {
case BOARD_BUDDHA:
diff --git a/drivers/ide/legacy/gayle.c b/drivers/ide/legacy/gayle.c
index 64d42619ab0..dcfadbbf55d 100644
--- a/drivers/ide/legacy/gayle.c
+++ b/drivers/ide/legacy/gayle.c
@@ -167,7 +167,7 @@ found:
index = ide_register_hw(&hw, &hwif);
if (index != -1) {
- hwif->mmio = 2;
+ hwif->mmio = 1;
switch (i) {
case 0:
printk("ide%d: Gayle IDE interface (A%d style)\n", index,
diff --git a/drivers/ide/legacy/ht6560b.c b/drivers/ide/legacy/ht6560b.c
index c48e87e512d..19ccd006f20 100644
--- a/drivers/ide/legacy/ht6560b.c
+++ b/drivers/ide/legacy/ht6560b.c
@@ -143,16 +143,16 @@ static void ht6560b_selectproc (ide_drive_t *drive)
current_timing = timing;
if (drive->media != ide_disk || !drive->present)
select |= HT_PREFETCH_MODE;
- (void) HWIF(drive)->INB(HT_CONFIG_PORT);
- (void) HWIF(drive)->INB(HT_CONFIG_PORT);
- (void) HWIF(drive)->INB(HT_CONFIG_PORT);
- (void) HWIF(drive)->INB(HT_CONFIG_PORT);
- HWIF(drive)->OUTB(select, HT_CONFIG_PORT);
+ (void)inb(HT_CONFIG_PORT);
+ (void)inb(HT_CONFIG_PORT);
+ (void)inb(HT_CONFIG_PORT);
+ (void)inb(HT_CONFIG_PORT);
+ outb(select, HT_CONFIG_PORT);
/*
* Set timing for this drive:
*/
- HWIF(drive)->OUTB(timing, IDE_SELECT_REG);
- (void) HWIF(drive)->INB(IDE_STATUS_REG);
+ outb(timing, IDE_SELECT_REG);
+ (void)inb(IDE_STATUS_REG);
#ifdef DEBUG
printk("ht6560b: %s: select=%#x timing=%#x\n",
drive->name, select, timing);
diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c
index 7efd28ac21e..a5023cdbdc5 100644
--- a/drivers/ide/legacy/ide-cs.c
+++ b/drivers/ide/legacy/ide-cs.c
@@ -34,7 +34,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/sched.h>
#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/string.h>
diff --git a/drivers/ide/legacy/macide.c b/drivers/ide/legacy/macide.c
index b1730d7e414..4c0079ad52a 100644
--- a/drivers/ide/legacy/macide.c
+++ b/drivers/ide/legacy/macide.c
@@ -141,7 +141,7 @@ void macide_init(void)
}
if (index != -1) {
- hwif->mmio = 2;
+ hwif->mmio = 1;
if (macintosh_config->ide_type == MAC_IDE_QUADRA)
printk(KERN_INFO "ide%d: Macintosh Quadra IDE interface\n", index);
else if (macintosh_config->ide_type == MAC_IDE_PB)
diff --git a/drivers/ide/legacy/q40ide.c b/drivers/ide/legacy/q40ide.c
index 434a94faa3b..74f08124eab 100644
--- a/drivers/ide/legacy/q40ide.c
+++ b/drivers/ide/legacy/q40ide.c
@@ -145,7 +145,7 @@ void q40ide_init(void)
index = ide_register_hw(&hw, &hwif);
// **FIXME**
if (index != -1)
- hwif->mmio = 2;
+ hwif->mmio = 1;
}
}
diff --git a/drivers/ide/mips/au1xxx-ide.c b/drivers/ide/mips/au1xxx-ide.c
index c7854ea57b5..0a59d5ef159 100644
--- a/drivers/ide/mips/au1xxx-ide.c
+++ b/drivers/ide/mips/au1xxx-ide.c
@@ -181,12 +181,6 @@ static int auide_tune_chipset (ide_drive_t *drive, u8 speed)
{
int mem_sttime;
int mem_stcfg;
- unsigned long mode;
-
-#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
- if (ide_use_dma(drive))
- mode = ide_dma_speed(drive, 0);
-#endif
mem_sttime = 0;
mem_stcfg = au_readl(MEM_STCFG2);
@@ -195,7 +189,7 @@ static int auide_tune_chipset (ide_drive_t *drive, u8 speed)
auide_tune_drive(drive, speed - XFER_PIO_0);
return 0;
}
-
+
switch(speed) {
#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
case XFER_MW_DMA_2:
@@ -207,7 +201,6 @@ static int auide_tune_chipset (ide_drive_t *drive, u8 speed)
mem_stcfg &= ~TOECS_MASK;
mem_stcfg |= SBC_IDE_MDMA2_TCSOE | SBC_IDE_MDMA2_TOECS;
- mode = XFER_MW_DMA_2;
break;
case XFER_MW_DMA_1:
mem_sttime = SBC_IDE_TIMING(MDMA1);
@@ -218,7 +211,6 @@ static int auide_tune_chipset (ide_drive_t *drive, u8 speed)
mem_stcfg &= ~TOECS_MASK;
mem_stcfg |= SBC_IDE_MDMA1_TCSOE | SBC_IDE_MDMA1_TOECS;
- mode = XFER_MW_DMA_1;
break;
case XFER_MW_DMA_0:
mem_sttime = SBC_IDE_TIMING(MDMA0);
@@ -229,14 +221,13 @@ static int auide_tune_chipset (ide_drive_t *drive, u8 speed)
mem_stcfg &= ~TOECS_MASK;
mem_stcfg |= SBC_IDE_MDMA0_TCSOE | SBC_IDE_MDMA0_TOECS;
- mode = XFER_MW_DMA_0;
break;
#endif
default:
return 1;
}
-
- if (ide_config_drive_speed(drive, mode))
+
+ if (ide_config_drive_speed(drive, speed))
return 1;
au_writel(mem_sttime,MEM_STTIME2);
@@ -423,9 +414,9 @@ static int auide_dma_check(ide_drive_t *drive)
speed = ide_find_best_mode(drive, XFER_PIO | XFER_MWDMA);
if (drive->autodma && (speed & XFER_MODE) != XFER_PIO)
- return HWIF(drive)->ide_dma_on(drive);
+ return 0;
- return HWIF(drive)->ide_dma_off_quietly(drive);
+ return -1;
}
static int auide_dma_test_irq(ide_drive_t *drive)
@@ -447,27 +438,24 @@ static int auide_dma_test_irq(ide_drive_t *drive)
return 0;
}
-static int auide_dma_host_on(ide_drive_t *drive)
+static void auide_dma_host_on(ide_drive_t *drive)
{
- return 0;
}
static int auide_dma_on(ide_drive_t *drive)
{
drive->using_dma = 1;
- return auide_dma_host_on(drive);
-}
+ return 0;
+}
-static int auide_dma_host_off(ide_drive_t *drive)
+static void auide_dma_host_off(ide_drive_t *drive)
{
- return 0;
}
-static int auide_dma_off_quietly(ide_drive_t *drive)
+static void auide_dma_off_quietly(ide_drive_t *drive)
{
drive->using_dma = 0;
- return auide_dma_host_off(drive);
}
static int auide_dma_lostirq(ide_drive_t *drive)
@@ -717,7 +705,8 @@ static int au_ide_probe(struct device *dev)
/* hold should be on in all cases */
hwif->hold = 1;
- hwif->mmio = 2;
+
+ hwif->mmio = 1;
/* If the user has selected DDMA assisted copies,
then set up a few local I/O function entry points
@@ -732,7 +721,7 @@ static int au_ide_probe(struct device *dev)
hwif->speedproc = &auide_tune_chipset;
#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
- hwif->ide_dma_off_quietly = &auide_dma_off_quietly;
+ hwif->dma_off_quietly = &auide_dma_off_quietly;
hwif->ide_dma_timeout = &auide_dma_timeout;
hwif->ide_dma_check = &auide_dma_check;
@@ -741,8 +730,8 @@ static int au_ide_probe(struct device *dev)
hwif->ide_dma_end = &auide_dma_end;
hwif->dma_setup = &auide_dma_setup;
hwif->ide_dma_test_irq = &auide_dma_test_irq;
- hwif->ide_dma_host_off = &auide_dma_host_off;
- hwif->ide_dma_host_on = &auide_dma_host_on;
+ hwif->dma_host_off = &auide_dma_host_off;
+ hwif->dma_host_on = &auide_dma_host_on;
hwif->ide_dma_lostirq = &auide_dma_lostirq;
hwif->ide_dma_on = &auide_dma_on;
diff --git a/drivers/ide/mips/swarm.c b/drivers/ide/mips/swarm.c
index 09c9e7936b0..81fa06851b2 100644
--- a/drivers/ide/mips/swarm.c
+++ b/drivers/ide/mips/swarm.c
@@ -115,7 +115,7 @@ static int __devinit swarm_ide_probe(struct device *dev)
/* Setup MMIO ops. */
default_hwif_mmiops(hwif);
/* Prevent resource map manipulation. */
- hwif->mmio = 2;
+ hwif->mmio = 1;
hwif->noprobe = 0;
for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++)
diff --git a/drivers/ide/pci/Makefile b/drivers/ide/pci/Makefile
index fef08960aa4..6591ff4753c 100644
--- a/drivers/ide/pci/Makefile
+++ b/drivers/ide/pci/Makefile
@@ -9,9 +9,10 @@ obj-$(CONFIG_BLK_DEV_CS5530) += cs5530.o
obj-$(CONFIG_BLK_DEV_CS5535) += cs5535.o
obj-$(CONFIG_BLK_DEV_SC1200) += sc1200.o
obj-$(CONFIG_BLK_DEV_CY82C693) += cy82c693.o
+obj-$(CONFIG_BLK_DEV_DELKIN) += delkin_cb.o
obj-$(CONFIG_BLK_DEV_HPT34X) += hpt34x.o
obj-$(CONFIG_BLK_DEV_HPT366) += hpt366.o
-#obj-$(CONFIG_BLK_DEV_HPT37X) += hpt37x.o
+obj-$(CONFIG_BLK_DEV_IT8213) += it8213.o
obj-$(CONFIG_BLK_DEV_IT821X) += it821x.o
obj-$(CONFIG_BLK_DEV_JMICRON) += jmicron.o
obj-$(CONFIG_BLK_DEV_NS87415) += ns87415.o
@@ -26,6 +27,7 @@ obj-$(CONFIG_BLK_DEV_SIIMAGE) += siimage.o
obj-$(CONFIG_BLK_DEV_SIS5513) += sis5513.o
obj-$(CONFIG_BLK_DEV_SL82C105) += sl82c105.o
obj-$(CONFIG_BLK_DEV_SLC90E66) += slc90e66.o
+obj-$(CONFIG_BLK_DEV_TC86C001) += tc86c001.o
obj-$(CONFIG_BLK_DEV_TRIFLEX) += triflex.o
obj-$(CONFIG_BLK_DEV_TRM290) += trm290.o
obj-$(CONFIG_BLK_DEV_VIA82CXXX) += via82cxxx.o
diff --git a/drivers/ide/pci/aec62xx.c b/drivers/ide/pci/aec62xx.c
index d261bfbad22..990eafe5ea1 100644
--- a/drivers/ide/pci/aec62xx.c
+++ b/drivers/ide/pci/aec62xx.c
@@ -94,9 +94,9 @@ static u8 aec62xx_ratemask (ide_drive_t *drive)
switch(hwif->pci_dev->device) {
case PCI_DEVICE_ID_ARTOP_ATP865:
case PCI_DEVICE_ID_ARTOP_ATP865R:
- mode = (hwif->INB(((hwif->channel) ?
- hwif->mate->dma_status :
- hwif->dma_status)) & 0x10) ? 4 : 3;
+ mode = (inb(hwif->channel ?
+ hwif->mate->dma_status :
+ hwif->dma_status) & 0x10) ? 4 : 3;
break;
case PCI_DEVICE_ID_ARTOP_ATP860:
case PCI_DEVICE_ID_ARTOP_ATP860R:
@@ -209,25 +209,13 @@ static void aec62xx_tune_drive (ide_drive_t *drive, u8 pio)
static int aec62xx_config_drive_xfer_rate (ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
- struct hd_driveid *id = drive->id;
-
- if ((id->capability & 1) && drive->autodma) {
-
- if (ide_use_dma(drive)) {
- if (config_chipset_for_dma(drive))
- return hwif->ide_dma_on(drive);
- }
-
- goto fast_ata_pio;
+ if (ide_use_dma(drive) && config_chipset_for_dma(drive))
+ return 0;
- } else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
+ if (ide_use_fast_pio(drive))
aec62xx_tune_drive(drive, 5);
- return hwif->ide_dma_off_quietly(drive);
- }
- /* IORDY not supported */
- return 0;
+
+ return -1;
}
static int aec62xx_irq_timeout (ide_drive_t *drive)
@@ -286,10 +274,8 @@ static void __devinit init_hwif_aec62xx(ide_hwif_t *hwif)
hwif->tuneproc = &aec62xx_tune_drive;
hwif->speedproc = &aec62xx_tune_chipset;
- if (hwif->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) {
+ if (hwif->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF)
hwif->serialized = hwif->channel;
- hwif->no_dsc = 1;
- }
if (hwif->mate)
hwif->mate->serialized = hwif->serialized;
diff --git a/drivers/ide/pci/alim15x3.c b/drivers/ide/pci/alim15x3.c
index 68df77ec502..4debd18d52f 100644
--- a/drivers/ide/pci/alim15x3.c
+++ b/drivers/ide/pci/alim15x3.c
@@ -507,17 +507,15 @@ static int config_chipset_for_dma (ide_drive_t *drive)
*
* Configure a drive for DMA operation. If DMA is not possible we
* drop the drive into PIO mode instead.
- *
- * FIXME: exactly what are we trying to return here
*/
-
+
static int ali15x3_config_drive_for_dma(ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
struct hd_driveid *id = drive->id;
if ((m5229_revision<=0x20) && (drive->media!=ide_disk))
- return hwif->ide_dma_off_quietly(drive);
+ goto no_dma_set;
drive->init_speed = 0;
@@ -552,9 +550,10 @@ try_dma_modes:
ata_pio:
hwif->tuneproc(drive, 255);
no_dma_set:
- return hwif->ide_dma_off_quietly(drive);
+ return -1;
}
- return hwif->ide_dma_on(drive);
+
+ return 0;
}
/**
@@ -852,8 +851,8 @@ static void __devinit init_dma_ali15x3 (ide_hwif_t *hwif, unsigned long dmabase)
{
if (m5229_revision < 0x20)
return;
- if (!(hwif->channel))
- hwif->OUTB(hwif->INB(dmabase+2) & 0x60, dmabase+2);
+ if (!hwif->channel)
+ outb(inb(dmabase + 2) & 0x60, dmabase + 2);
ide_setup_dma(hwif, dmabase, 8);
}
diff --git a/drivers/ide/pci/amd74xx.c b/drivers/ide/pci/amd74xx.c
index a4336995a41..7989bdd842a 100644
--- a/drivers/ide/pci/amd74xx.c
+++ b/drivers/ide/pci/amd74xx.c
@@ -304,8 +304,9 @@ static int amd74xx_ide_dma_check(ide_drive_t *drive)
amd_set_drive(drive, speed);
if (drive->autodma && (speed & XFER_MODE) != XFER_PIO)
- return HWIF(drive)->ide_dma_on(drive);
- return HWIF(drive)->ide_dma_off_quietly(drive);
+ return 0;
+
+ return -1;
}
/*
diff --git a/drivers/ide/pci/atiixp.c b/drivers/ide/pci/atiixp.c
index 982ac31fa99..2d48af32e3f 100644
--- a/drivers/ide/pci/atiixp.c
+++ b/drivers/ide/pci/atiixp.c
@@ -101,7 +101,7 @@ static u8 atiixp_dma_2_pio(u8 xfer_rate) {
}
}
-static int atiixp_ide_dma_host_on(ide_drive_t *drive)
+static void atiixp_dma_host_on(ide_drive_t *drive)
{
struct pci_dev *dev = drive->hwif->pci_dev;
unsigned long flags;
@@ -118,10 +118,10 @@ static int atiixp_ide_dma_host_on(ide_drive_t *drive)
spin_unlock_irqrestore(&atiixp_lock, flags);
- return __ide_dma_host_on(drive);
+ ide_dma_host_on(drive);
}
-static int atiixp_ide_dma_host_off(ide_drive_t *drive)
+static void atiixp_dma_host_off(ide_drive_t *drive)
{
struct pci_dev *dev = drive->hwif->pci_dev;
unsigned long flags;
@@ -135,7 +135,7 @@ static int atiixp_ide_dma_host_off(ide_drive_t *drive)
spin_unlock_irqrestore(&atiixp_lock, flags);
- return __ide_dma_host_off(drive);
+ ide_dma_host_off(drive);
}
/**
@@ -235,11 +235,8 @@ static int atiixp_config_drive_for_dma(ide_drive_t *drive)
{
u8 speed = ide_dma_speed(drive, atiixp_ratemask(drive));
- /* If no DMA speed was available then disable DMA and use PIO. */
- if (!speed) {
- u8 tspeed = ide_get_best_pio_mode(drive, 255, 5, NULL);
- speed = atiixp_dma_2_pio(XFER_PIO_0 + tspeed) + XFER_PIO_0;
- }
+ if (!speed)
+ return 0;
(void) atiixp_speedproc(drive, speed);
return ide_dma_enable(drive);
@@ -255,30 +252,20 @@ static int atiixp_config_drive_for_dma(ide_drive_t *drive)
static int atiixp_dma_check(ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
- struct hd_driveid *id = drive->id;
u8 tspeed, speed;
drive->init_speed = 0;
- if ((id->capability & 1) && drive->autodma) {
-
- if (ide_use_dma(drive)) {
- if (atiixp_config_drive_for_dma(drive))
- return hwif->ide_dma_on(drive);
- }
-
- goto fast_ata_pio;
+ if (ide_use_dma(drive) && atiixp_config_drive_for_dma(drive))
+ return 0;
- } else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
+ if (ide_use_fast_pio(drive)) {
tspeed = ide_get_best_pio_mode(drive, 255, 5, NULL);
speed = atiixp_dma_2_pio(XFER_PIO_0 + tspeed) + XFER_PIO_0;
- hwif->speedproc(drive, speed);
- return hwif->ide_dma_off_quietly(drive);
+ atiixp_speedproc(drive, speed);
}
- /* IORDY not supported */
- return 0;
+
+ return -1;
}
/**
@@ -318,8 +305,8 @@ static void __devinit init_hwif_atiixp(ide_hwif_t *hwif)
else
hwif->udma_four = 0;
- hwif->ide_dma_host_on = &atiixp_ide_dma_host_on;
- hwif->ide_dma_host_off = &atiixp_ide_dma_host_off;
+ hwif->dma_host_on = &atiixp_dma_host_on;
+ hwif->dma_host_off = &atiixp_dma_host_off;
hwif->ide_dma_check = &atiixp_dma_check;
if (!noautodma)
hwif->autodma = 1;
diff --git a/drivers/ide/pci/cmd64x.c b/drivers/ide/pci/cmd64x.c
index aee947e8fc3..49df27513da 100644
--- a/drivers/ide/pci/cmd64x.c
+++ b/drivers/ide/pci/cmd64x.c
@@ -466,36 +466,21 @@ static int config_chipset_for_dma (ide_drive_t *drive)
if (!speed)
return 0;
- if(ide_set_xfer_rate(drive, speed))
- return 0;
-
- if (!drive->init_speed)
- drive->init_speed = speed;
+ if (cmd64x_tune_chipset(drive, speed))
+ return 0;
return ide_dma_enable(drive);
}
static int cmd64x_config_drive_for_dma (ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
- struct hd_driveid *id = drive->id;
-
- if ((id != NULL) && ((id->capability & 1) != 0) && drive->autodma) {
-
- if (ide_use_dma(drive)) {
- if (config_chipset_for_dma(drive))
- return hwif->ide_dma_on(drive);
- }
-
- goto fast_ata_pio;
+ if (ide_use_dma(drive) && config_chipset_for_dma(drive))
+ return 0;
- } else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
+ if (ide_use_fast_pio(drive))
config_chipset_for_pio(drive, 1);
- return hwif->ide_dma_off_quietly(drive);
- }
- /* IORDY not supported */
- return 0;
+
+ return -1;
}
static int cmd64x_alt_dma_status (struct pci_dev *dev)
@@ -518,13 +503,13 @@ static int cmd64x_ide_dma_end (ide_drive_t *drive)
drive->waiting_for_dma = 0;
/* read DMA command state */
- dma_cmd = hwif->INB(hwif->dma_command);
+ dma_cmd = inb(hwif->dma_command);
/* stop DMA */
- hwif->OUTB((dma_cmd & ~1), hwif->dma_command);
+ outb(dma_cmd & ~1, hwif->dma_command);
/* get DMA status */
- dma_stat = hwif->INB(hwif->dma_status);
+ dma_stat = inb(hwif->dma_status);
/* clear the INTR & ERROR bits */
- hwif->OUTB(dma_stat|6, hwif->dma_status);
+ outb(dma_stat | 6, hwif->dma_status);
if (cmd64x_alt_dma_status(dev)) {
u8 dma_intr = 0;
u8 dma_mask = (hwif->channel) ? ARTTIM23_INTR_CH1 :
@@ -546,7 +531,7 @@ static int cmd64x_ide_dma_test_irq (ide_drive_t *drive)
struct pci_dev *dev = hwif->pci_dev;
u8 dma_alt_stat = 0, mask = (hwif->channel) ? MRDMODE_INTR_CH1 :
MRDMODE_INTR_CH0;
- u8 dma_stat = hwif->INB(hwif->dma_status);
+ u8 dma_stat = inb(hwif->dma_status);
(void) pci_read_config_byte(dev, MRDMODE, &dma_alt_stat);
#ifdef DEBUG
@@ -576,13 +561,13 @@ static int cmd646_1_ide_dma_end (ide_drive_t *drive)
drive->waiting_for_dma = 0;
/* get DMA status */
- dma_stat = hwif->INB(hwif->dma_status);
+ dma_stat = inb(hwif->dma_status);
/* read DMA command state */
- dma_cmd = hwif->INB(hwif->dma_command);
+ dma_cmd = inb(hwif->dma_command);
/* stop DMA */
- hwif->OUTB((dma_cmd & ~1), hwif->dma_command);
+ outb(dma_cmd & ~1, hwif->dma_command);
/* clear the INTR & ERROR bits */
- hwif->OUTB(dma_stat|6, hwif->dma_status);
+ outb(dma_stat | 6, hwif->dma_status);
/* and free any DMA resources */
ide_destroy_dmatable(drive);
/* verify good DMA status */
diff --git a/drivers/ide/pci/cs5520.c b/drivers/ide/pci/cs5520.c
index ba6786aabf3..400859a839f 100644
--- a/drivers/ide/pci/cs5520.c
+++ b/drivers/ide/pci/cs5520.c
@@ -132,12 +132,11 @@ static void cs5520_tune_drive(ide_drive_t *drive, u8 pio)
static int cs5520_config_drive_xfer_rate(ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
-
/* Tune the drive for PIO modes up to PIO 4 */
cs5520_tune_drive(drive, 4);
+
/* Then tell the core to use DMA operations */
- return hwif->ide_dma_on(drive);
+ return 0;
}
/*
diff --git a/drivers/ide/pci/cs5530.c b/drivers/ide/pci/cs5530.c
index 9bf5fdfc5b1..b2d7c132ef4 100644
--- a/drivers/ide/pci/cs5530.c
+++ b/drivers/ide/pci/cs5530.c
@@ -81,8 +81,8 @@ static void cs5530_tuneproc (ide_drive_t *drive, u8 pio) /* pio=255 means "autot
pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
if (!cs5530_set_xfer_mode(drive, modes[pio])) {
- format = (hwif->INL(basereg+4) >> 31) & 1;
- hwif->OUTL(cs5530_pio_timings[format][pio],
+ format = (inl(basereg + 4) >> 31) & 1;
+ outl(cs5530_pio_timings[format][pio],
basereg+(drive->select.b.unit<<3));
}
}
@@ -103,16 +103,13 @@ static int cs5530_config_dma (ide_drive_t *drive)
int unit = drive->select.b.unit;
ide_drive_t *mate = &hwif->drives[unit^1];
struct hd_driveid *id = drive->id;
- unsigned int reg, timings;
+ unsigned int reg, timings = 0;
unsigned long basereg;
/*
* Default to DMA-off in case we run into trouble here.
*/
- hwif->ide_dma_off_quietly(drive);
- /* turn off DMA while we fiddle */
- hwif->ide_dma_host_off(drive);
- /* clear DMA_capable bit */
+ hwif->dma_off_quietly(drive);
/*
* The CS5530 specifies that two drives sharing a cable cannot
@@ -182,30 +179,24 @@ static int cs5530_config_dma (ide_drive_t *drive)
case XFER_MW_DMA_1: timings = 0x00012121; break;
case XFER_MW_DMA_2: timings = 0x00002020; break;
default:
- printk(KERN_ERR "%s: cs5530_config_dma: huh? mode=%02x\n",
- drive->name, mode);
- return 1; /* failure */
+ BUG();
+ break;
}
basereg = CS5530_BASEREG(hwif);
- reg = hwif->INL(basereg+4); /* get drive0 config register */
+ reg = inl(basereg + 4); /* get drive0 config register */
timings |= reg & 0x80000000; /* preserve PIO format bit */
if (unit == 0) { /* are we configuring drive0? */
- hwif->OUTL(timings, basereg+4); /* write drive0 config register */
+ outl(timings, basereg + 4); /* write drive0 config register */
} else {
if (timings & 0x00100000)
reg |= 0x00100000; /* enable UDMA timings for both drives */
else
reg &= ~0x00100000; /* disable UDMA timings for both drives */
- hwif->OUTL(reg, basereg+4); /* write drive0 config register */
- hwif->OUTL(timings, basereg+12); /* write drive1 config register */
+ outl(reg, basereg + 4); /* write drive0 config register */
+ outl(timings, basereg + 12); /* write drive1 config register */
}
- (void) hwif->ide_dma_host_on(drive);
- /* set DMA_capable bit */
- /*
- * Finally, turn DMA on in software, and exit.
- */
- return hwif->ide_dma_on(drive); /* success */
+ return 0; /* success */
}
/**
@@ -321,17 +312,17 @@ static void __devinit init_hwif_cs5530 (ide_hwif_t *hwif)
hwif->tuneproc = &cs5530_tuneproc;
basereg = CS5530_BASEREG(hwif);
- d0_timings = hwif->INL(basereg+0);
+ d0_timings = inl(basereg + 0);
if (CS5530_BAD_PIO(d0_timings)) {
/* PIO timings not initialized? */
- hwif->OUTL(cs5530_pio_timings[(d0_timings>>31)&1][0], basereg+0);
+ outl(cs5530_pio_timings[(d0_timings >> 31) & 1][0], basereg + 0);
if (!hwif->drives[0].autotune)
hwif->drives[0].autotune = 1;
/* needs autotuning later */
}
- if (CS5530_BAD_PIO(hwif->INL(basereg+8))) {
- /* PIO timings not initialized? */
- hwif->OUTL(cs5530_pio_timings[(d0_timings>>31)&1][0], basereg+8);
+ if (CS5530_BAD_PIO(inl(basereg + 8))) {
+ /* PIO timings not initialized? */
+ outl(cs5530_pio_timings[(d0_timings >> 31) & 1][0], basereg + 8);
if (!hwif->drives[1].autotune)
hwif->drives[1].autotune = 1;
/* needs autotuning later */
diff --git a/drivers/ide/pci/cs5535.c b/drivers/ide/pci/cs5535.c
index 5c5aec28e67..45f43efbf92 100644
--- a/drivers/ide/pci/cs5535.c
+++ b/drivers/ide/pci/cs5535.c
@@ -195,28 +195,19 @@ static int cs5535_config_drive_for_dma(ide_drive_t *drive)
static int cs5535_dma_check(ide_drive_t *drive)
{
- ide_hwif_t *hwif = drive->hwif;
- struct hd_driveid *id = drive->id;
u8 speed;
drive->init_speed = 0;
- if ((id->capability & 1) && drive->autodma) {
- if (ide_use_dma(drive)) {
- if (cs5535_config_drive_for_dma(drive))
- return hwif->ide_dma_on(drive);
- }
-
- goto fast_ata_pio;
+ if (ide_use_dma(drive) && cs5535_config_drive_for_dma(drive))
+ return 0;
- } else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
+ if (ide_use_fast_pio(drive)) {
speed = ide_get_best_pio_mode(drive, 255, 4, NULL);
cs5535_set_drive(drive, speed);
- return hwif->ide_dma_off_quietly(drive);
}
- /* IORDY not supported */
- return 0;
+
+ return -1;
}
static u8 __devinit cs5535_cable_detect(struct pci_dev *dev)
diff --git a/drivers/ide/pci/cy82c693.c b/drivers/ide/pci/cy82c693.c
index 9eafcbf444f..103b9db9785 100644
--- a/drivers/ide/pci/cy82c693.c
+++ b/drivers/ide/pci/cy82c693.c
@@ -197,8 +197,8 @@ static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single)
#if CY82C693_DEBUG_LOGS
/* for debug let's show the previous values */
- HWIF(drive)->OUTB(index, CY82_INDEX_PORT);
- data = HWIF(drive)->INB(CY82_DATA_PORT);
+ outb(index, CY82_INDEX_PORT);
+ data = inb(CY82_DATA_PORT);
printk (KERN_INFO "%s (ch=%d, dev=%d): DMA mode is %d (single=%d)\n",
drive->name, HWIF(drive)->channel, drive->select.b.unit,
@@ -207,8 +207,8 @@ static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single)
data = (u8)mode|(u8)(single<<2);
- HWIF(drive)->OUTB(index, CY82_INDEX_PORT);
- HWIF(drive)->OUTB(data, CY82_DATA_PORT);
+ outb(index, CY82_INDEX_PORT);
+ outb(data, CY82_DATA_PORT);
#if CY82C693_DEBUG_INFO
printk(KERN_INFO "%s (ch=%d, dev=%d): set DMA mode to %d (single=%d)\n",
@@ -227,8 +227,8 @@ static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single)
*/
data = BUSMASTER_TIMEOUT;
- HWIF(drive)->OUTB(CY82_INDEX_TIMEOUT, CY82_INDEX_PORT);
- HWIF(drive)->OUTB(data, CY82_DATA_PORT);
+ outb(CY82_INDEX_TIMEOUT, CY82_INDEX_PORT);
+ outb(data, CY82_DATA_PORT);
#if CY82C693_DEBUG_INFO
printk (KERN_INFO "%s: Set IDE Bus Master TimeOut Register to 0x%X\n",
@@ -478,21 +478,18 @@ static void __devinit init_iops_cy82c693(ide_hwif_t *hwif)
}
}
-static ide_pci_device_t cy82c693_chipsets[] __devinitdata = {
- { /* 0 */
- .name = "CY82C693",
- .init_chipset = init_chipset_cy82c693,
- .init_iops = init_iops_cy82c693,
- .init_hwif = init_hwif_cy82c693,
- .channels = 1,
- .autodma = AUTODMA,
- .bootable = ON_BOARD,
- }
+static ide_pci_device_t cy82c693_chipset __devinitdata = {
+ .name = "CY82C693",
+ .init_chipset = init_chipset_cy82c693,
+ .init_iops = init_iops_cy82c693,
+ .init_hwif = init_hwif_cy82c693,
+ .channels = 1,
+ .autodma = AUTODMA,
+ .bootable = ON_BOARD,
};
static int __devinit cy82c693_init_one(struct pci_dev *dev, const struct pci_device_id *id)
{
- ide_pci_device_t *d = &cy82c693_chipsets[id->driver_data];
struct pci_dev *dev2;
int ret = -ENODEV;
@@ -501,7 +498,7 @@ static int __devinit cy82c693_init_one(struct pci_dev *dev, const struct pci_dev
if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE &&
PCI_FUNC(dev->devfn) == 1) {
dev2 = pci_get_slot(dev->bus, dev->devfn + 1);
- ret = ide_setup_pci_devices(dev, dev2, d);
+ ret = ide_setup_pci_devices(dev, dev2, &cy82c693_chipset);
/* We leak pci refs here but thats ok - we can't be unloaded */
}
return ret;
diff --git a/drivers/ide/pci/delkin_cb.c b/drivers/ide/pci/delkin_cb.c
new file mode 100644
index 00000000000..e2672fc65d3
--- /dev/null
+++ b/drivers/ide/pci/delkin_cb.c
@@ -0,0 +1,140 @@
+/*
+ * linux/drivers/ide/pci/delkin_cb.c
+ *
+ * Created 20 Oct 2004 by Mark Lord
+ *
+ * Basic support for Delkin/ASKA/Workbit Cardbus CompactFlash adapter
+ *
+ * Modeled after the 16-bit PCMCIA driver: ide-cs.c
+ *
+ * This is slightly peculiar, in that it is a PCI driver,
+ * but is NOT an IDE PCI driver -- the IDE layer does not directly
+ * support hot insertion/removal of PCI interfaces, so this driver
+ * is unable to use the IDE PCI interfaces. Instead, it uses the
+ * same interfaces as the ide-cs (PCMCIA) driver uses.
+ * On the plus side, the driver is also smaller/simpler this way.
+ *
+ * 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.
+ */
+#include <linux/autoconf.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+
+/*
+ * No chip documentation has yet been found,
+ * so these configuration values were pulled from
+ * a running Win98 system using "debug".
+ * This gives around 3MByte/second read performance,
+ * which is about 2/3 of what the chip is capable of.
+ *
+ * There is also a 4KByte mmio region on the card,
+ * but its purpose has yet to be reverse-engineered.
+ */
+static const u8 setup[] = {
+ 0x00, 0x05, 0xbe, 0x01, 0x20, 0x8f, 0x00, 0x00,
+ 0xa4, 0x1f, 0xb3, 0x1b, 0x00, 0x00, 0x00, 0x80,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xa4, 0x83, 0x02, 0x13,
+};
+
+static int __devinit
+delkin_cb_probe (struct pci_dev *dev, const struct pci_device_id *id)
+{
+ unsigned long base;
+ hw_regs_t hw;
+ ide_hwif_t *hwif = NULL;
+ ide_drive_t *drive;
+ int i, rc;
+
+ rc = pci_enable_device(dev);
+ if (rc) {
+ printk(KERN_ERR "delkin_cb: pci_enable_device failed (%d)\n", rc);
+ return rc;
+ }
+ rc = pci_request_regions(dev, "delkin_cb");
+ if (rc) {
+ printk(KERN_ERR "delkin_cb: pci_request_regions failed (%d)\n", rc);
+ pci_disable_device(dev);
+ return rc;
+ }
+ base = pci_resource_start(dev, 0);
+ outb(0x02, base + 0x1e); /* set nIEN to block interrupts */
+ inb(base + 0x17); /* read status to clear interrupts */
+ for (i = 0; i < sizeof(setup); ++i) {
+ if (setup[i])
+ outb(setup[i], base + i);
+ }
+ pci_release_regions(dev); /* IDE layer handles regions itself */
+
+ memset(&hw, 0, sizeof(hw));
+ ide_std_init_ports(&hw, base + 0x10, base + 0x1e);
+ hw.irq = dev->irq;
+ hw.chipset = ide_pci; /* this enables IRQ sharing */
+
+ rc = ide_register_hw_with_fixup(&hw, &hwif, ide_undecoded_slave);
+ if (rc < 0) {
+ printk(KERN_ERR "delkin_cb: ide_register_hw failed (%d)\n", rc);
+ pci_disable_device(dev);
+ return -ENODEV;
+ }
+ pci_set_drvdata(dev, hwif);
+ hwif->pci_dev = dev;
+ drive = &hwif->drives[0];
+ if (drive->present) {
+ drive->io_32bit = 1;
+ drive->unmask = 1;
+ }
+ return 0;
+}
+
+static void
+delkin_cb_remove (struct pci_dev *dev)
+{
+ ide_hwif_t *hwif = pci_get_drvdata(dev);
+
+ if (hwif)
+ ide_unregister(hwif->index);
+ pci_disable_device(dev);
+}
+
+static struct pci_device_id delkin_cb_pci_tbl[] __devinitdata = {
+ { 0x1145, 0xf021, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, delkin_cb_pci_tbl);
+
+static struct pci_driver driver = {
+ .name = "Delkin-ASKA-Workbit Cardbus IDE",
+ .id_table = delkin_cb_pci_tbl,
+ .probe = delkin_cb_probe,
+ .remove = delkin_cb_remove,
+};
+
+static int
+delkin_cb_init (void)
+{
+ return pci_module_init(&driver);
+}
+
+static void
+delkin_cb_exit (void)
+{
+ pci_unregister_driver(&driver);
+}
+
+module_init(delkin_cb_init);
+module_exit(delkin_cb_exit);
+
+MODULE_AUTHOR("Mark Lord");
+MODULE_DESCRIPTION("Basic support for Delkin/ASKA/Workbit Cardbus IDE");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/ide/pci/hpt34x.c b/drivers/ide/pci/hpt34x.c
index ce7b08f08a0..924eaa3a570 100644
--- a/drivers/ide/pci/hpt34x.c
+++ b/drivers/ide/pci/hpt34x.c
@@ -48,19 +48,6 @@ static u8 hpt34x_ratemask (ide_drive_t *drive)
return 1;
}
-static void hpt34x_clear_chipset (ide_drive_t *drive)
-{
- struct pci_dev *dev = HWIF(drive)->pci_dev;
- u32 reg1 = 0, tmp1 = 0, reg2 = 0, tmp2 = 0;
-
- pci_read_config_dword(dev, 0x44, &reg1);
- pci_read_config_dword(dev, 0x48, &reg2);
- tmp1 = ((0x00 << (3*drive->dn)) | (reg1 & ~(7 << (3*drive->dn))));
- tmp2 = (reg2 & ~(0x11 << drive->dn));
- pci_write_config_dword(dev, 0x44, tmp1);
- pci_write_config_dword(dev, 0x48, tmp2);
-}
-
static int hpt34x_tune_chipset (ide_drive_t *drive, u8 xferspeed)
{
struct pci_dev *dev = HWIF(drive)->pci_dev;
@@ -81,7 +68,7 @@ static int hpt34x_tune_chipset (ide_drive_t *drive, u8 xferspeed)
pci_read_config_dword(dev, 0x44, &reg1);
pci_read_config_dword(dev, 0x48, &reg2);
tmp1 = ((lo_speed << (3*drive->dn)) | (reg1 & ~(7 << (3*drive->dn))));
- tmp2 = ((hi_speed << drive->dn) | reg2);
+ tmp2 = ((hi_speed << drive->dn) | (reg2 & ~(0x11 << drive->dn)));
pci_write_config_dword(dev, 0x44, tmp1);
pci_write_config_dword(dev, 0x48, tmp2);
@@ -99,7 +86,6 @@ static int hpt34x_tune_chipset (ide_drive_t *drive, u8 xferspeed)
static void hpt34x_tune_drive (ide_drive_t *drive, u8 pio)
{
pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
- hpt34x_clear_chipset(drive);
(void) hpt34x_tune_chipset(drive, (XFER_PIO_0 + pio));
}
@@ -117,38 +103,25 @@ static int config_chipset_for_dma (ide_drive_t *drive)
if (!(speed))
return 0;
- hpt34x_clear_chipset(drive);
(void) hpt34x_tune_chipset(drive, speed);
return ide_dma_enable(drive);
}
static int hpt34x_config_drive_xfer_rate (ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
- struct hd_driveid *id = drive->id;
-
drive->init_speed = 0;
- if (id && (id->capability & 1) && drive->autodma) {
-
- if (ide_use_dma(drive)) {
- if (config_chipset_for_dma(drive))
+ if (ide_use_dma(drive) && config_chipset_for_dma(drive))
#ifndef CONFIG_HPT34X_AUTODMA
- return hwif->ide_dma_off_quietly(drive);
+ return -1;
#else
- return hwif->ide_dma_on(drive);
+ return 0;
#endif
- }
-
- goto fast_ata_pio;
- } else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
+ if (ide_use_fast_pio(drive))
hpt34x_tune_drive(drive, 255);
- return hwif->ide_dma_off_quietly(drive);
- }
- /* IORDY not supported */
- return 0;
+
+ return -1;
}
/*
@@ -209,7 +182,6 @@ static void __devinit init_hwif_hpt34x(ide_hwif_t *hwif)
hwif->tuneproc = &hpt34x_tune_drive;
hwif->speedproc = &hpt34x_tune_chipset;
- hwif->no_dsc = 1;
hwif->drives[0].autotune = 1;
hwif->drives[1].autotune = 1;
diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c
index b486442dd5d..60ecdc258c7 100644
--- a/drivers/ide/pci/hpt366.c
+++ b/drivers/ide/pci/hpt366.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/ide/pci/hpt366.c Version 0.36 April 25, 2003
+ * linux/drivers/ide/pci/hpt366.c Version 1.01 Dec 23, 2006
*
* Copyright (C) 1999-2003 Andre Hedrick <andre@linux-ide.org>
* Portions Copyright (C) 2001 Sun Microsystems, Inc.
@@ -60,13 +60,10 @@
* channel caused the cached register value to get out of sync with the
* actual one, the channels weren't serialized, the turnaround shouldn't
* be done on 66 MHz PCI bus
- * - avoid calibrating PLL twice as the second time results in a wrong PCI
- * frequency and thus in the wrong timings for the secondary channel
- * - disable UltraATA/133 for HPT372 by default (50 MHz DPLL clock do not
- * allow for this speed anyway)
- * - add support for HPT302N and HPT371N clocking (the same as for HPT372N)
- * - HPT371/N are single channel chips, so avoid touching the primary channel
- * which exists only virtually (there's no pins for it)
+ * - disable UltraATA/100 for HPT370 by default as the 33 MHz clock being used
+ * does not allow for this speed anyway
+ * - avoid touching disabled channels (e.g. HPT371/N are single channel chips,
+ * their primary channel is kind of virtual, it isn't tied to any pins)
* - fix/remove bad/unused timing tables and use one set of tables for the whole
* HPT37x chip family; save space by introducing the separate transfer mode
* table in which the mode lookup is done
@@ -76,11 +73,47 @@
* and for HPT36x the obsolete HDIO_TRISTATE_HWIF handler was called instead
* - pass to init_chipset() handlers a copy of the IDE PCI device structure as
* they tamper with its fields
- * <source@mvista.com>
- *
+ * - pass to the init_setup handlers a copy of the ide_pci_device_t structure
+ * since they may tamper with its fields
+ * - prefix the driver startup messages with the real chip name
+ * - claim the extra 240 bytes of I/O space for all chips
+ * - optimize the rate masking/filtering and the drive list lookup code
+ * - use pci_get_slot() to get to the function 1 of HPT36x/374
+ * - cache offset of the channel's misc. control registers (MCRs) being used
+ * throughout the driver
+ * - only touch the relevant MCR when detecting the cable type on HPT374's
+ * function 1
+ * - rename all the register related variables consistently
+ * - move all the interrupt twiddling code from the speedproc handlers into
+ * init_hwif_hpt366(), also grouping all the DMA related code together there
+ * - merge two HPT37x speedproc handlers, fix the PIO timing register mask and
+ * separate the UltraDMA and MWDMA masks there to avoid changing PIO timings
+ * when setting an UltraDMA mode
+ * - fix hpt3xx_tune_drive() to set the PIO mode requested, not always select
+ * the best possible one
+ * - clean up DMA timeout handling for HPT370
+ * - switch to using the enumeration type to differ between the numerous chip
+ * variants, matching PCI device/revision ID with the chip type early, at the
+ * init_setup stage
+ * - extend the hpt_info structure to hold the DPLL and PCI clock frequencies,
+ * stop duplicating it for each channel by storing the pointer in the pci_dev
+ * structure: first, at the init_setup stage, point it to a static "template"
+ * with only the chip type and its specific base DPLL frequency, the highest
+ * supported DMA mode, and the chip settings table pointer filled, then, at
+ * the init_chipset stage, allocate per-chip instance and fill it with the
+ * rest of the necessary information
+ * - get rid of the constant thresholds in the HPT37x PCI clock detection code,
+ * switch to calculating PCI clock frequency based on the chip's base DPLL
+ * frequency
+ * - switch to using the DPLL clock and enable UltraATA/133 mode by default on
+ * anything newer than HPT370/A
+ * - fold PCI clock detection and DPLL setup code into init_chipset_hpt366(),
+ * also fixing the interchanged 25/40 MHz PCI clock cases for HPT36x chips;
+ * unify HPT36x/37x timing setup code and the speedproc handlers by joining
+ * the register setting lists into the table indexed by the clock selected
+ * Sergei Shtylyov, <sshtylyov@ru.mvista.com> or <source@mvista.com>
*/
-
#include <linux/types.h>
#include <linux/module.h>
#include <linux/kernel.h>
@@ -332,93 +365,159 @@ static u32 sixty_six_base_hpt37x[] = {
};
#define HPT366_DEBUG_DRIVE_INFO 0
-#define HPT374_ALLOW_ATA133_6 0
-#define HPT371_ALLOW_ATA133_6 0
-#define HPT302_ALLOW_ATA133_6 0
-#define HPT372_ALLOW_ATA133_6 0
-#define HPT370_ALLOW_ATA100_5 1
+#define HPT374_ALLOW_ATA133_6 1
+#define HPT371_ALLOW_ATA133_6 1
+#define HPT302_ALLOW_ATA133_6 1
+#define HPT372_ALLOW_ATA133_6 1
+#define HPT370_ALLOW_ATA100_5 0
#define HPT366_ALLOW_ATA66_4 1
#define HPT366_ALLOW_ATA66_3 1
#define HPT366_MAX_DEVS 8
-#define F_LOW_PCI_33 0x23
-#define F_LOW_PCI_40 0x29
-#define F_LOW_PCI_50 0x2d
-#define F_LOW_PCI_66 0x42
+/* Supported ATA clock frequencies */
+enum ata_clock {
+ ATA_CLOCK_25MHZ,
+ ATA_CLOCK_33MHZ,
+ ATA_CLOCK_40MHZ,
+ ATA_CLOCK_50MHZ,
+ ATA_CLOCK_66MHZ,
+ NUM_ATA_CLOCKS
+};
/*
- * Hold all the highpoint quirks and revision information in one
- * place.
+ * Hold all the HighPoint chip information in one place.
*/
-struct hpt_info
-{
+struct hpt_info {
+ u8 chip_type; /* Chip type */
u8 max_mode; /* Speeds allowed */
- int revision; /* Chipset revision */
- int flags; /* Chipset properties */
-#define PLL_MODE 1
-#define IS_3xxN 2
-#define PCI_66MHZ 4
- /* Speed table */
- u32 *speed;
+ u8 dpll_clk; /* DPLL clock in MHz */
+ u8 pci_clk; /* PCI clock in MHz */
+ u32 **settings; /* Chipset settings table */
};
-/*
- * This wants fixing so that we do everything not by classrev
- * (which breaks on the newest chips) but by creating an
- * enumeration of chip variants and using that
- */
+/* Supported HighPoint chips */
+enum {
+ HPT36x,
+ HPT370,
+ HPT370A,
+ HPT374,
+ HPT372,
+ HPT372A,
+ HPT302,
+ HPT371,
+ HPT372N,
+ HPT302N,
+ HPT371N
+};
+
+static u32 *hpt36x_settings[NUM_ATA_CLOCKS] = {
+ twenty_five_base_hpt36x,
+ thirty_three_base_hpt36x,
+ forty_base_hpt36x,
+ NULL,
+ NULL
+};
+
+static u32 *hpt37x_settings[NUM_ATA_CLOCKS] = {
+ NULL,
+ thirty_three_base_hpt37x,
+ NULL,
+ fifty_base_hpt37x,
+ sixty_six_base_hpt37x
+};
+
+static struct hpt_info hpt36x __devinitdata = {
+ .chip_type = HPT36x,
+ .max_mode = (HPT366_ALLOW_ATA66_4 || HPT366_ALLOW_ATA66_3) ? 2 : 1,
+ .dpll_clk = 0, /* no DPLL */
+ .settings = hpt36x_settings
+};
+
+static struct hpt_info hpt370 __devinitdata = {
+ .chip_type = HPT370,
+ .max_mode = HPT370_ALLOW_ATA100_5 ? 3 : 2,
+ .dpll_clk = 48,
+ .settings = hpt37x_settings
+};
+
+static struct hpt_info hpt370a __devinitdata = {
+ .chip_type = HPT370A,
+ .max_mode = HPT370_ALLOW_ATA100_5 ? 3 : 2,
+ .dpll_clk = 48,
+ .settings = hpt37x_settings
+};
+
+static struct hpt_info hpt374 __devinitdata = {
+ .chip_type = HPT374,
+ .max_mode = HPT374_ALLOW_ATA133_6 ? 4 : 3,
+ .dpll_clk = 48,
+ .settings = hpt37x_settings
+};
+
+static struct hpt_info hpt372 __devinitdata = {
+ .chip_type = HPT372,
+ .max_mode = HPT372_ALLOW_ATA133_6 ? 4 : 3,
+ .dpll_clk = 55,
+ .settings = hpt37x_settings
+};
+
+static struct hpt_info hpt372a __devinitdata = {
+ .chip_type = HPT372A,
+ .max_mode = HPT372_ALLOW_ATA133_6 ? 4 : 3,
+ .dpll_clk = 66,
+ .settings = hpt37x_settings
+};
-static __devinit u32 hpt_revision (struct pci_dev *dev)
+static struct hpt_info hpt302 __devinitdata = {
+ .chip_type = HPT302,
+ .max_mode = HPT302_ALLOW_ATA133_6 ? 4 : 3,
+ .dpll_clk = 66,
+ .settings = hpt37x_settings
+};
+
+static struct hpt_info hpt371 __devinitdata = {
+ .chip_type = HPT371,
+ .max_mode = HPT371_ALLOW_ATA133_6 ? 4 : 3,
+ .dpll_clk = 66,
+ .settings = hpt37x_settings
+};
+
+static struct hpt_info hpt372n __devinitdata = {
+ .chip_type = HPT372N,
+ .max_mode = HPT372_ALLOW_ATA133_6 ? 4 : 3,
+ .dpll_clk = 77,
+ .settings = hpt37x_settings
+};
+
+static struct hpt_info hpt302n __devinitdata = {
+ .chip_type = HPT302N,
+ .max_mode = HPT302_ALLOW_ATA133_6 ? 4 : 3,
+ .dpll_clk = 77,
+};
+
+static struct hpt_info hpt371n __devinitdata = {
+ .chip_type = HPT371N,
+ .max_mode = HPT371_ALLOW_ATA133_6 ? 4 : 3,
+ .dpll_clk = 77,
+ .settings = hpt37x_settings
+};
+
+static int check_in_drive_list(ide_drive_t *drive, const char **list)
{
- u32 class_rev;
- pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
- class_rev &= 0xff;
-
- switch(dev->device) {
- /* Remap new 372N onto 372 */
- case PCI_DEVICE_ID_TTI_HPT372N:
- class_rev = PCI_DEVICE_ID_TTI_HPT372; break;
- case PCI_DEVICE_ID_TTI_HPT374:
- class_rev = PCI_DEVICE_ID_TTI_HPT374; break;
- case PCI_DEVICE_ID_TTI_HPT371:
- class_rev = PCI_DEVICE_ID_TTI_HPT371; break;
- case PCI_DEVICE_ID_TTI_HPT302:
- class_rev = PCI_DEVICE_ID_TTI_HPT302; break;
- case PCI_DEVICE_ID_TTI_HPT372:
- class_rev = PCI_DEVICE_ID_TTI_HPT372; break;
- default:
- break;
- }
- return class_rev;
-}
+ struct hd_driveid *id = drive->id;
-static int check_in_drive_lists(ide_drive_t *drive, const char **list);
+ while (*list)
+ if (!strcmp(*list++,id->model))
+ return 1;
+ return 0;
+}
-static u8 hpt3xx_ratemask (ide_drive_t *drive)
+static u8 hpt3xx_ratemask(ide_drive_t *drive)
{
- ide_hwif_t *hwif = drive->hwif;
- struct hpt_info *info = ide_get_hwifdata(hwif);
- u8 mode = 0;
-
- /* FIXME: TODO - move this to set info->mode once at boot */
-
- if (info->revision >= 8) { /* HPT374 */
- mode = (HPT374_ALLOW_ATA133_6) ? 4 : 3;
- } else if (info->revision >= 7) { /* HPT371 */
- mode = (HPT371_ALLOW_ATA133_6) ? 4 : 3;
- } else if (info->revision >= 6) { /* HPT302 */
- mode = (HPT302_ALLOW_ATA133_6) ? 4 : 3;
- } else if (info->revision >= 5) { /* HPT372 */
- mode = (HPT372_ALLOW_ATA133_6) ? 4 : 3;
- } else if (info->revision >= 4) { /* HPT370A */
- mode = (HPT370_ALLOW_ATA100_5) ? 3 : 2;
- } else if (info->revision >= 3) { /* HPT370 */
- mode = (HPT370_ALLOW_ATA100_5) ? 3 : 2;
- mode = (check_in_drive_lists(drive, bad_ata33)) ? 0 : mode;
- } else { /* HPT366 and HPT368 */
- mode = (check_in_drive_lists(drive, bad_ata33)) ? 0 : 2;
- }
+ struct hpt_info *info = pci_get_drvdata(HWIF(drive)->pci_dev);
+ u8 mode = info->max_mode;
+
if (!eighty_ninty_three(drive) && mode)
mode = min(mode, (u8)1);
return mode;
@@ -429,75 +528,61 @@ static u8 hpt3xx_ratemask (ide_drive_t *drive)
* either PIO or UDMA modes 0,4,5
*/
-static u8 hpt3xx_ratefilter (ide_drive_t *drive, u8 speed)
+static u8 hpt3xx_ratefilter(ide_drive_t *drive, u8 speed)
{
- ide_hwif_t *hwif = drive->hwif;
- struct hpt_info *info = ide_get_hwifdata(hwif);
+ struct hpt_info *info = pci_get_drvdata(HWIF(drive)->pci_dev);
+ u8 chip_type = info->chip_type;
u8 mode = hpt3xx_ratemask(drive);
if (drive->media != ide_disk)
return min(speed, (u8)XFER_PIO_4);
- switch(mode) {
+ switch (mode) {
case 0x04:
- speed = min(speed, (u8)XFER_UDMA_6);
+ speed = min_t(u8, speed, XFER_UDMA_6);
break;
case 0x03:
- speed = min(speed, (u8)XFER_UDMA_5);
- if (info->revision >= 5)
+ speed = min_t(u8, speed, XFER_UDMA_5);
+ if (chip_type >= HPT374)
break;
- if (check_in_drive_lists(drive, bad_ata100_5))
- speed = min(speed, (u8)XFER_UDMA_4);
- break;
+ if (!check_in_drive_list(drive, bad_ata100_5))
+ goto check_bad_ata33;
+ /* fall thru */
case 0x02:
- speed = min(speed, (u8)XFER_UDMA_4);
- /*
- * CHECK ME, Does this need to be set to 5 ??
- */
- if (info->revision >= 3)
- break;
- if ((check_in_drive_lists(drive, bad_ata66_4)) ||
- (!(HPT366_ALLOW_ATA66_4)))
- speed = min(speed, (u8)XFER_UDMA_3);
- if ((check_in_drive_lists(drive, bad_ata66_3)) ||
- (!(HPT366_ALLOW_ATA66_3)))
- speed = min(speed, (u8)XFER_UDMA_2);
- break;
+ speed = min_t(u8, speed, XFER_UDMA_4);
+
+ /*
+ * CHECK ME, Does this need to be changed to HPT374 ??
+ */
+ if (chip_type >= HPT370)
+ goto check_bad_ata33;
+ if (HPT366_ALLOW_ATA66_4 &&
+ !check_in_drive_list(drive, bad_ata66_4))
+ goto check_bad_ata33;
+
+ speed = min_t(u8, speed, XFER_UDMA_3);
+ if (HPT366_ALLOW_ATA66_3 &&
+ !check_in_drive_list(drive, bad_ata66_3))
+ goto check_bad_ata33;
+ /* fall thru */
case 0x01:
- speed = min(speed, (u8)XFER_UDMA_2);
- /*
- * CHECK ME, Does this need to be set to 5 ??
- */
- if (info->revision >= 3)
+ speed = min_t(u8, speed, XFER_UDMA_2);
+
+ check_bad_ata33:
+ if (chip_type >= HPT370A)
break;
- if (check_in_drive_lists(drive, bad_ata33))
- speed = min(speed, (u8)XFER_MW_DMA_2);
- break;
+ if (!check_in_drive_list(drive, bad_ata33))
+ break;
+ /* fall thru */
case 0x00:
default:
- speed = min(speed, (u8)XFER_MW_DMA_2);
+ speed = min_t(u8, speed, XFER_MW_DMA_2);
break;
}
return speed;
}
-static int check_in_drive_lists (ide_drive_t *drive, const char **list)
-{
- struct hd_driveid *id = drive->id;
-
- if (quirk_drives == list) {
- while (*list)
- if (strstr(id->model, *list++))
- return 1;
- } else {
- while (*list)
- if (!strcmp(*list++,id->model))
- return 1;
- }
- return 0;
-}
-
-static u32 pci_bus_clock_list(u8 speed, u32 *chipset_table)
+static u32 get_speed_setting(u8 speed, struct hpt_info *info)
{
int i;
@@ -510,260 +595,201 @@ static u32 pci_bus_clock_list(u8 speed, u32 *chipset_table)
for (i = 0; i < ARRAY_SIZE(xfer_speeds) - 1; i++)
if (xfer_speeds[i] == speed)
break;
- return chipset_table[i];
+ /*
+ * NOTE: info->settings only points to the pointer
+ * to the list of the actual register values
+ */
+ return (*info->settings)[i];
}
static int hpt36x_tune_chipset(ide_drive_t *drive, u8 xferspeed)
{
- ide_hwif_t *hwif = drive->hwif;
- struct pci_dev *dev = hwif->pci_dev;
- struct hpt_info *info = ide_get_hwifdata(hwif);
- u8 speed = hpt3xx_ratefilter(drive, xferspeed);
- u8 regtime = (drive->select.b.unit & 0x01) ? 0x44 : 0x40;
- u8 regfast = (hwif->channel) ? 0x55 : 0x51;
- u8 drive_fast = 0;
- u32 reg1 = 0, reg2 = 0;
-
- /*
- * Disable the "fast interrupt" prediction.
- */
- pci_read_config_byte(dev, regfast, &drive_fast);
- if (drive_fast & 0x80)
- pci_write_config_byte(dev, regfast, drive_fast & ~0x80);
-
- reg2 = pci_bus_clock_list(speed, info->speed);
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ struct hpt_info *info = pci_get_drvdata(dev);
+ u8 speed = hpt3xx_ratefilter(drive, xferspeed);
+ u8 itr_addr = drive->dn ? 0x44 : 0x40;
+ u32 itr_mask = speed < XFER_MW_DMA_0 ? 0x30070000 :
+ (speed < XFER_UDMA_0 ? 0xc0070000 : 0xc03800ff);
+ u32 new_itr = get_speed_setting(speed, info);
+ u32 old_itr = 0;
/*
- * Disable on-chip PIO FIFO/buffer
- * (to avoid problems handling I/O errors later)
+ * Disable on-chip PIO FIFO/buffer (and PIO MST mode as well)
+ * to avoid problems handling I/O errors later
*/
- pci_read_config_dword(dev, regtime, &reg1);
- if (speed >= XFER_MW_DMA_0) {
- reg2 = (reg2 & ~0xc0000000) | (reg1 & 0xc0000000);
- } else {
- reg2 = (reg2 & ~0x30070000) | (reg1 & 0x30070000);
- }
- reg2 &= ~0x80000000;
+ pci_read_config_dword(dev, itr_addr, &old_itr);
+ new_itr = (new_itr & ~itr_mask) | (old_itr & itr_mask);
+ new_itr &= ~0xc0000000;
- pci_write_config_dword(dev, regtime, reg2);
+ pci_write_config_dword(dev, itr_addr, new_itr);
return ide_config_drive_speed(drive, speed);
}
-static int hpt370_tune_chipset(ide_drive_t *drive, u8 xferspeed)
+static int hpt37x_tune_chipset(ide_drive_t *drive, u8 xferspeed)
{
- ide_hwif_t *hwif = drive->hwif;
- struct pci_dev *dev = hwif->pci_dev;
- struct hpt_info *info = ide_get_hwifdata(hwif);
- u8 speed = hpt3xx_ratefilter(drive, xferspeed);
- u8 regfast = (drive->hwif->channel) ? 0x55 : 0x51;
- u8 drive_pci = 0x40 + (drive->dn * 4);
- u8 new_fast = 0, drive_fast = 0;
- u32 list_conf = 0, drive_conf = 0;
- u32 conf_mask = (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000;
-
- /*
- * Disable the "fast interrupt" prediction.
- * don't holdoff on interrupts. (== 0x01 despite what the docs say)
- */
- pci_read_config_byte(dev, regfast, &drive_fast);
- new_fast = drive_fast;
- if (new_fast & 0x02)
- new_fast &= ~0x02;
-
-#ifdef HPT_DELAY_INTERRUPT
- if (new_fast & 0x01)
- new_fast &= ~0x01;
-#else
- if ((new_fast & 0x01) == 0)
- new_fast |= 0x01;
-#endif
- if (new_fast != drive_fast)
- pci_write_config_byte(dev, regfast, new_fast);
-
- list_conf = pci_bus_clock_list(speed, info->speed);
-
- pci_read_config_dword(dev, drive_pci, &drive_conf);
- list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask);
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ struct hpt_info *info = pci_get_drvdata(dev);
+ u8 speed = hpt3xx_ratefilter(drive, xferspeed);
+ u8 itr_addr = 0x40 + (drive->dn * 4);
+ u32 itr_mask = speed < XFER_MW_DMA_0 ? 0x303c0000 :
+ (speed < XFER_UDMA_0 ? 0xc03c0000 : 0xc1c001ff);
+ u32 new_itr = get_speed_setting(speed, info);
+ u32 old_itr = 0;
+
+ pci_read_config_dword(dev, itr_addr, &old_itr);
+ new_itr = (new_itr & ~itr_mask) | (old_itr & itr_mask);
if (speed < XFER_MW_DMA_0)
- list_conf &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
- pci_write_config_dword(dev, drive_pci, list_conf);
+ new_itr &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
+ pci_write_config_dword(dev, itr_addr, new_itr);
return ide_config_drive_speed(drive, speed);
}
-static int hpt372_tune_chipset(ide_drive_t *drive, u8 xferspeed)
+static int hpt3xx_tune_chipset(ide_drive_t *drive, u8 speed)
{
- ide_hwif_t *hwif = drive->hwif;
- struct pci_dev *dev = hwif->pci_dev;
- struct hpt_info *info = ide_get_hwifdata(hwif);
- u8 speed = hpt3xx_ratefilter(drive, xferspeed);
- u8 regfast = (drive->hwif->channel) ? 0x55 : 0x51;
- u8 drive_fast = 0, drive_pci = 0x40 + (drive->dn * 4);
- u32 list_conf = 0, drive_conf = 0;
- u32 conf_mask = (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000;
-
- /*
- * Disable the "fast interrupt" prediction.
- * don't holdoff on interrupts. (== 0x01 despite what the docs say)
- */
- pci_read_config_byte(dev, regfast, &drive_fast);
- drive_fast &= ~0x07;
- pci_write_config_byte(dev, regfast, drive_fast);
-
- list_conf = pci_bus_clock_list(speed, info->speed);
- pci_read_config_dword(dev, drive_pci, &drive_conf);
- list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask);
- if (speed < XFER_MW_DMA_0)
- list_conf &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
- pci_write_config_dword(dev, drive_pci, list_conf);
-
- return ide_config_drive_speed(drive, speed);
-}
+ ide_hwif_t *hwif = HWIF(drive);
+ struct hpt_info *info = pci_get_drvdata(hwif->pci_dev);
-static int hpt3xx_tune_chipset (ide_drive_t *drive, u8 speed)
-{
- ide_hwif_t *hwif = drive->hwif;
- struct hpt_info *info = ide_get_hwifdata(hwif);
-
- if (info->revision >= 8)
- return hpt372_tune_chipset(drive, speed); /* not a typo */
- else if (info->revision >= 5)
- return hpt372_tune_chipset(drive, speed);
- else if (info->revision >= 3)
- return hpt370_tune_chipset(drive, speed);
+ if (info->chip_type >= HPT370)
+ return hpt37x_tune_chipset(drive, speed);
else /* hpt368: hpt_minimum_revision(dev, 2) */
return hpt36x_tune_chipset(drive, speed);
}
-static void hpt3xx_tune_drive (ide_drive_t *drive, u8 pio)
+static void hpt3xx_tune_drive(ide_drive_t *drive, u8 pio)
{
- pio = ide_get_best_pio_mode(drive, 255, pio, NULL);
- (void) hpt3xx_tune_chipset(drive, (XFER_PIO_0 + pio));
+ pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+ (void) hpt3xx_tune_chipset (drive, XFER_PIO_0 + pio);
}
/*
* This allows the configuration of ide_pci chipset registers
* for cards that learn about the drive's UDMA, DMA, PIO capabilities
- * after the drive is reported by the OS. Initially for designed for
+ * after the drive is reported by the OS. Initially designed for
* HPT366 UDMA chipset by HighPoint|Triones Technologies, Inc.
*
- * check_in_drive_lists(drive, bad_ata66_4)
- * check_in_drive_lists(drive, bad_ata66_3)
- * check_in_drive_lists(drive, bad_ata33)
- *
*/
-static int config_chipset_for_dma (ide_drive_t *drive)
+static int config_chipset_for_dma(ide_drive_t *drive)
{
u8 speed = ide_dma_speed(drive, hpt3xx_ratemask(drive));
- ide_hwif_t *hwif = drive->hwif;
- struct hpt_info *info = ide_get_hwifdata(hwif);
if (!speed)
return 0;
- /* If we don't have any timings we can't do a lot */
- if (info->speed == NULL)
- return 0;
-
(void) hpt3xx_tune_chipset(drive, speed);
return ide_dma_enable(drive);
}
-static int hpt3xx_quirkproc (ide_drive_t *drive)
+static int hpt3xx_quirkproc(ide_drive_t *drive)
{
- return ((int) check_in_drive_lists(drive, quirk_drives));
+ struct hd_driveid *id = drive->id;
+ const char **list = quirk_drives;
+
+ while (*list)
+ if (strstr(id->model, *list++))
+ return 1;
+ return 0;
}
-static void hpt3xx_intrproc (ide_drive_t *drive)
+static void hpt3xx_intrproc(ide_drive_t *drive)
{
- ide_hwif_t *hwif = drive->hwif;
+ ide_hwif_t *hwif = HWIF(drive);
if (drive->quirk_list)
return;
/* drives in the quirk_list may not like intr setups/cleanups */
- hwif->OUTB(drive->ctl|2, IDE_CONTROL_REG);
+ hwif->OUTB(drive->ctl | 2, IDE_CONTROL_REG);
}
-static void hpt3xx_maskproc (ide_drive_t *drive, int mask)
+static void hpt3xx_maskproc(ide_drive_t *drive, int mask)
{
- ide_hwif_t *hwif = drive->hwif;
- struct hpt_info *info = ide_get_hwifdata(hwif);
- struct pci_dev *dev = hwif->pci_dev;
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ struct hpt_info *info = pci_get_drvdata(dev);
if (drive->quirk_list) {
- if (info->revision >= 3) {
- u8 reg5a = 0;
- pci_read_config_byte(dev, 0x5a, &reg5a);
- if (((reg5a & 0x10) >> 4) != mask)
- pci_write_config_byte(dev, 0x5a, mask ? (reg5a | 0x10) : (reg5a & ~0x10));
+ if (info->chip_type >= HPT370) {
+ u8 scr1 = 0;
+
+ pci_read_config_byte(dev, 0x5a, &scr1);
+ if (((scr1 & 0x10) >> 4) != mask) {
+ if (mask)
+ scr1 |= 0x10;
+ else
+ scr1 &= ~0x10;
+ pci_write_config_byte(dev, 0x5a, scr1);
+ }
} else {
- if (mask) {
+ if (mask)
disable_irq(hwif->irq);
- } else {
- enable_irq(hwif->irq);
- }
+ else
+ enable_irq (hwif->irq);
}
- } else {
- if (IDE_CONTROL_REG)
- hwif->OUTB(mask ? (drive->ctl | 2) :
- (drive->ctl & ~2),
- IDE_CONTROL_REG);
- }
+ } else
+ hwif->OUTB(mask ? (drive->ctl | 2) : (drive->ctl & ~2),
+ IDE_CONTROL_REG);
}
-static int hpt366_config_drive_xfer_rate (ide_drive_t *drive)
+static int hpt366_config_drive_xfer_rate(ide_drive_t *drive)
{
- ide_hwif_t *hwif = drive->hwif;
- struct hd_driveid *id = drive->id;
-
drive->init_speed = 0;
- if ((id->capability & 1) && drive->autodma) {
-
- if (ide_use_dma(drive)) {
- if (config_chipset_for_dma(drive))
- return hwif->ide_dma_on(drive);
- }
+ if (ide_use_dma(drive) && config_chipset_for_dma(drive))
+ return 0;
- goto fast_ata_pio;
+ if (ide_use_fast_pio(drive))
+ hpt3xx_tune_drive(drive, 255);
- } else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
- hpt3xx_tune_drive(drive, 5);
- return hwif->ide_dma_off_quietly(drive);
- }
- /* IORDY not supported */
- return 0;
+ return -1;
}
/*
- * This is specific to the HPT366 UDMA bios chipset
+ * This is specific to the HPT366 UDMA chipset
* by HighPoint|Triones Technologies, Inc.
*/
-static int hpt366_ide_dma_lostirq (ide_drive_t *drive)
+static int hpt366_ide_dma_lostirq(ide_drive_t *drive)
{
- struct pci_dev *dev = HWIF(drive)->pci_dev;
- u8 reg50h = 0, reg52h = 0, reg5ah = 0;
-
- pci_read_config_byte(dev, 0x50, &reg50h);
- pci_read_config_byte(dev, 0x52, &reg52h);
- pci_read_config_byte(dev, 0x5a, &reg5ah);
- printk("%s: (%s) reg50h=0x%02x, reg52h=0x%02x, reg5ah=0x%02x\n",
- drive->name, __FUNCTION__, reg50h, reg52h, reg5ah);
- if (reg5ah & 0x10)
- pci_write_config_byte(dev, 0x5a, reg5ah & ~0x10);
+ struct pci_dev *dev = HWIF(drive)->pci_dev;
+ u8 mcr1 = 0, mcr3 = 0, scr1 = 0;
+
+ pci_read_config_byte(dev, 0x50, &mcr1);
+ pci_read_config_byte(dev, 0x52, &mcr3);
+ pci_read_config_byte(dev, 0x5a, &scr1);
+ printk("%s: (%s) mcr1=0x%02x, mcr3=0x%02x, scr1=0x%02x\n",
+ drive->name, __FUNCTION__, mcr1, mcr3, scr1);
+ if (scr1 & 0x10)
+ pci_write_config_byte(dev, 0x5a, scr1 & ~0x10);
return __ide_dma_lostirq(drive);
}
-static void hpt370_clear_engine (ide_drive_t *drive)
+static void hpt370_clear_engine(ide_drive_t *drive)
{
- u8 regstate = HWIF(drive)->channel ? 0x54 : 0x50;
- pci_write_config_byte(HWIF(drive)->pci_dev, regstate, 0x37);
+ ide_hwif_t *hwif = HWIF(drive);
+
+ pci_write_config_byte(hwif->pci_dev, hwif->select_data, 0x37);
udelay(10);
}
+static void hpt370_irq_timeout(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ u16 bfifo = 0;
+ u8 dma_cmd;
+
+ pci_read_config_word(hwif->pci_dev, hwif->select_data + 2, &bfifo);
+ printk(KERN_DEBUG "%s: %d bytes in FIFO\n", drive->name, bfifo & 0x1ff);
+
+ /* get DMA command mode */
+ dma_cmd = hwif->INB(hwif->dma_command);
+ /* stop DMA */
+ hwif->OUTB(dma_cmd & ~0x1, hwif->dma_command);
+ hpt370_clear_engine(drive);
+}
+
static void hpt370_ide_dma_start(ide_drive_t *drive)
{
#ifdef HPT_RESET_STATE_ENGINE
@@ -772,72 +798,43 @@ static void hpt370_ide_dma_start(ide_drive_t *drive)
ide_dma_start(drive);
}
-static int hpt370_ide_dma_end (ide_drive_t *drive)
+static int hpt370_ide_dma_end(ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
- u8 dma_stat = hwif->INB(hwif->dma_status);
+ u8 dma_stat = hwif->INB(hwif->dma_status);
if (dma_stat & 0x01) {
/* wait a little */
udelay(20);
dma_stat = hwif->INB(hwif->dma_status);
+ if (dma_stat & 0x01)
+ hpt370_irq_timeout(drive);
}
- if ((dma_stat & 0x01) != 0)
- /* fallthrough */
- (void) HWIF(drive)->ide_dma_timeout(drive);
-
return __ide_dma_end(drive);
}
-static void hpt370_lostirq_timeout (ide_drive_t *drive)
+static int hpt370_ide_dma_timeout(ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
- u8 bfifo = 0, reginfo = hwif->channel ? 0x56 : 0x52;
- u8 dma_stat = 0, dma_cmd = 0;
-
- pci_read_config_byte(HWIF(drive)->pci_dev, reginfo, &bfifo);
- printk(KERN_DEBUG "%s: %d bytes in FIFO\n", drive->name, bfifo);
- hpt370_clear_engine(drive);
- /* get dma command mode */
- dma_cmd = hwif->INB(hwif->dma_command);
- /* stop dma */
- hwif->OUTB(dma_cmd & ~0x1, hwif->dma_command);
- dma_stat = hwif->INB(hwif->dma_status);
- /* clear errors */
- hwif->OUTB(dma_stat | 0x6, hwif->dma_status);
-}
-
-static int hpt370_ide_dma_timeout (ide_drive_t *drive)
-{
- hpt370_lostirq_timeout(drive);
- hpt370_clear_engine(drive);
+ hpt370_irq_timeout(drive);
return __ide_dma_timeout(drive);
}
-static int hpt370_ide_dma_lostirq (ide_drive_t *drive)
-{
- hpt370_lostirq_timeout(drive);
- hpt370_clear_engine(drive);
- return __ide_dma_lostirq(drive);
-}
-
/* returns 1 if DMA IRQ issued, 0 otherwise */
static int hpt374_ide_dma_test_irq(ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
u16 bfifo = 0;
- u8 reginfo = hwif->channel ? 0x56 : 0x52;
- u8 dma_stat;
+ u8 dma_stat;
- pci_read_config_word(hwif->pci_dev, reginfo, &bfifo);
+ pci_read_config_word(hwif->pci_dev, hwif->select_data + 2, &bfifo);
if (bfifo & 0x1FF) {
// printk("%s: %d bytes in FIFO\n", drive->name, bfifo);
return 0;
}
- dma_stat = hwif->INB(hwif->dma_status);
+ dma_stat = inb(hwif->dma_status);
/* return 1 if INTR asserted */
- if ((dma_stat & 4) == 4)
+ if (dma_stat & 4)
return 1;
if (!drive->waiting_for_dma)
@@ -846,17 +843,17 @@ static int hpt374_ide_dma_test_irq(ide_drive_t *drive)
return 0;
}
-static int hpt374_ide_dma_end (ide_drive_t *drive)
+static int hpt374_ide_dma_end(ide_drive_t *drive)
{
- struct pci_dev *dev = HWIF(drive)->pci_dev;
ide_hwif_t *hwif = HWIF(drive);
- u8 msc_stat = 0, mscreg = hwif->channel ? 0x54 : 0x50;
- u8 bwsr_stat = 0, bwsr_mask = hwif->channel ? 0x02 : 0x01;
-
- pci_read_config_byte(dev, 0x6a, &bwsr_stat);
- pci_read_config_byte(dev, mscreg, &msc_stat);
- if ((bwsr_stat & bwsr_mask) == bwsr_mask)
- pci_write_config_byte(dev, mscreg, msc_stat|0x30);
+ struct pci_dev *dev = hwif->pci_dev;
+ u8 mcr = 0, mcr_addr = hwif->select_data;
+ u8 bwsr = 0, mask = hwif->channel ? 0x02 : 0x01;
+
+ pci_read_config_byte(dev, 0x6a, &bwsr);
+ pci_read_config_byte(dev, mcr_addr, &mcr);
+ if (bwsr & mask)
+ pci_write_config_byte(dev, mcr_addr, mcr | 0x30);
return __ide_dma_end(drive);
}
@@ -866,40 +863,37 @@ static int hpt374_ide_dma_end (ide_drive_t *drive)
* @mode: clocking mode (0x21 for write, 0x23 otherwise)
*
* Switch the DPLL clock on the HPT3xxN devices. This is a right mess.
- * NOTE: avoid touching the disabled primary channel on HPT371N -- it
- * doesn't physically exist anyway...
*/
static void hpt3xxn_set_clock(ide_hwif_t *hwif, u8 mode)
{
- u8 mcr1, scr2 = hwif->INB(hwif->dma_master + 0x7b);
+ u8 scr2 = hwif->INB(hwif->dma_master + 0x7b);
if ((scr2 & 0x7f) == mode)
return;
- /* MISC. control register 1 has the channel enable bit... */
- mcr1 = hwif->INB(hwif->dma_master + 0x70);
-
/* Tristate the bus */
- if (mcr1 & 0x04)
- hwif->OUTB(0x80, hwif->dma_master + 0x73);
+ hwif->OUTB(0x80, hwif->dma_master + 0x73);
hwif->OUTB(0x80, hwif->dma_master + 0x77);
/* Switch clock and reset channels */
hwif->OUTB(mode, hwif->dma_master + 0x7b);
hwif->OUTB(0xc0, hwif->dma_master + 0x79);
- /* Reset state machines */
- if (mcr1 & 0x04)
- hwif->OUTB(0x37, hwif->dma_master + 0x70);
- hwif->OUTB(0x37, hwif->dma_master + 0x74);
+ /*
+ * Reset the state machines.
+ * NOTE: avoid accidentally enabling the disabled channels.
+ */
+ hwif->OUTB(hwif->INB(hwif->dma_master + 0x70) | 0x32,
+ hwif->dma_master + 0x70);
+ hwif->OUTB(hwif->INB(hwif->dma_master + 0x74) | 0x32,
+ hwif->dma_master + 0x74);
/* Complete reset */
hwif->OUTB(0x00, hwif->dma_master + 0x79);
/* Reconnect channels to bus */
- if (mcr1 & 0x04)
- hwif->OUTB(0x00, hwif->dma_master + 0x73);
+ hwif->OUTB(0x00, hwif->dma_master + 0x73);
hwif->OUTB(0x00, hwif->dma_master + 0x77);
}
@@ -914,14 +908,12 @@ static void hpt3xxn_set_clock(ide_hwif_t *hwif, u8 mode)
static void hpt3xxn_rw_disk(ide_drive_t *drive, struct request *rq)
{
- ide_hwif_t *hwif = HWIF(drive);
- u8 wantclock = rq_data_dir(rq) ? 0x23 : 0x21;
-
- hpt3xxn_set_clock(hwif, wantclock);
+ hpt3xxn_set_clock(HWIF(drive), rq_data_dir(rq) ? 0x23 : 0x21);
}
/*
* Set/get power state for a drive.
+ * NOTE: affects both drives on each channel.
*
* When we turn the power back on, we need to re-initialize things.
*/
@@ -929,26 +921,18 @@ static void hpt3xxn_rw_disk(ide_drive_t *drive, struct request *rq)
static int hpt3xx_busproc(ide_drive_t *drive, int state)
{
- ide_hwif_t *hwif = drive->hwif;
+ ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
- u8 tristate, resetmask, bus_reg = 0;
- u16 tri_reg = 0;
+ u8 mcr_addr = hwif->select_data + 2;
+ u8 resetmask = hwif->channel ? 0x80 : 0x40;
+ u8 bsr2 = 0;
+ u16 mcr = 0;
hwif->bus_state = state;
- if (hwif->channel) {
- /* secondary channel */
- tristate = 0x56;
- resetmask = 0x80;
- } else {
- /* primary channel */
- tristate = 0x52;
- resetmask = 0x40;
- }
-
/* Grab the status. */
- pci_read_config_word(dev, tristate, &tri_reg);
- pci_read_config_byte(dev, 0x59, &bus_reg);
+ pci_read_config_word(dev, mcr_addr, &mcr);
+ pci_read_config_byte(dev, 0x59, &bsr2);
/*
* Set the state. We don't set it if we don't need to do so.
@@ -956,22 +940,22 @@ static int hpt3xx_busproc(ide_drive_t *drive, int state)
*/
switch (state) {
case BUSSTATE_ON:
- if (!(bus_reg & resetmask))
+ if (!(bsr2 & resetmask))
return 0;
hwif->drives[0].failures = hwif->drives[1].failures = 0;
- pci_write_config_byte(dev, 0x59, bus_reg & ~resetmask);
- pci_write_config_word(dev, tristate, tri_reg & ~TRISTATE_BIT);
+ pci_write_config_byte(dev, 0x59, bsr2 & ~resetmask);
+ pci_write_config_word(dev, mcr_addr, mcr & ~TRISTATE_BIT);
return 0;
case BUSSTATE_OFF:
- if ((bus_reg & resetmask) && !(tri_reg & TRISTATE_BIT))
+ if ((bsr2 & resetmask) && !(mcr & TRISTATE_BIT))
return 0;
- tri_reg &= ~TRISTATE_BIT;
+ mcr &= ~TRISTATE_BIT;
break;
case BUSSTATE_TRISTATE:
- if ((bus_reg & resetmask) && (tri_reg & TRISTATE_BIT))
+ if ((bsr2 & resetmask) && (mcr & TRISTATE_BIT))
return 0;
- tri_reg |= TRISTATE_BIT;
+ mcr |= TRISTATE_BIT;
break;
default:
return -EINVAL;
@@ -980,268 +964,320 @@ static int hpt3xx_busproc(ide_drive_t *drive, int state)
hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
- pci_write_config_word(dev, tristate, tri_reg);
- pci_write_config_byte(dev, 0x59, bus_reg | resetmask);
+ pci_write_config_word(dev, mcr_addr, mcr);
+ pci_write_config_byte(dev, 0x59, bsr2 | resetmask);
return 0;
}
-static void __devinit hpt366_clocking(ide_hwif_t *hwif)
+/**
+ * hpt37x_calibrate_dpll - calibrate the DPLL
+ * @dev: PCI device
+ *
+ * Perform a calibration cycle on the DPLL.
+ * Returns 1 if this succeeds
+ */
+static int __devinit hpt37x_calibrate_dpll(struct pci_dev *dev, u16 f_low, u16 f_high)
{
- u32 reg1 = 0;
- struct hpt_info *info = ide_get_hwifdata(hwif);
+ u32 dpll = (f_high << 16) | f_low | 0x100;
+ u8 scr2;
+ int i;
- pci_read_config_dword(hwif->pci_dev, 0x40, &reg1);
+ pci_write_config_dword(dev, 0x5c, dpll);
- /* detect bus speed by looking at control reg timing: */
- switch((reg1 >> 8) & 7) {
- case 5:
- info->speed = forty_base_hpt36x;
- break;
- case 9:
- info->speed = twenty_five_base_hpt36x;
- break;
- case 7:
- default:
- info->speed = thirty_three_base_hpt36x;
+ /* Wait for oscillator ready */
+ for(i = 0; i < 0x5000; ++i) {
+ udelay(50);
+ pci_read_config_byte(dev, 0x5b, &scr2);
+ if (scr2 & 0x80)
break;
}
+ /* See if it stays ready (we'll just bail out if it's not yet) */
+ for(i = 0; i < 0x1000; ++i) {
+ pci_read_config_byte(dev, 0x5b, &scr2);
+ /* DPLL destabilized? */
+ if(!(scr2 & 0x80))
+ return 0;
+ }
+ /* Turn off tuning, we have the DPLL set */
+ pci_read_config_dword (dev, 0x5c, &dpll);
+ pci_write_config_dword(dev, 0x5c, (dpll & ~0x100));
+ return 1;
}
-static void __devinit hpt37x_clocking(ide_hwif_t *hwif)
+static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const char *name)
{
- struct hpt_info *info = ide_get_hwifdata(hwif);
- struct pci_dev *dev = hwif->pci_dev;
- int adjust, i;
- u16 freq = 0;
- u32 pll, temp = 0;
- u8 reg5bh = 0, mcr1 = 0;
-
+ struct hpt_info *info = kmalloc(sizeof(struct hpt_info), GFP_KERNEL);
+ unsigned long io_base = pci_resource_start(dev, 4);
+ u8 pci_clk, dpll_clk = 0; /* PCI and DPLL clock in MHz */
+ enum ata_clock clock;
+
+ if (info == NULL) {
+ printk(KERN_ERR "%s: out of memory!\n", name);
+ return -ENOMEM;
+ }
+
/*
- * default to pci clock. make sure MA15/16 are set to output
- * to prevent drives having problems with 40-pin cables. Needed
- * for some drives such as IBM-DTLA which will not enter ready
- * state on reset when PDIAG is a input.
- *
- * ToDo: should we set 0x21 when using PLL mode ?
+ * Copy everything from a static "template" structure
+ * to just allocated per-chip hpt_info structure.
*/
- pci_write_config_byte(dev, 0x5b, 0x23);
+ *info = *(struct hpt_info *)pci_get_drvdata(dev);
/*
- * We'll have to read f_CNT value in order to determine
- * the PCI clock frequency according to the following ratio:
- *
- * f_CNT = Fpci * 192 / Fdpll
- *
- * First try reading the register in which the HighPoint BIOS
- * saves f_CNT value before reprogramming the DPLL from its
- * default setting (which differs for the various chips).
- * NOTE: This register is only accessible via I/O space.
- *
- * In case the signature check fails, we'll have to resort to
- * reading the f_CNT register itself in hopes that nobody has
- * touched the DPLL yet...
+ * FIXME: Not portable. Also, why do we enable the ROM in the first place?
+ * We don't seem to be using it.
*/
- temp = inl(pci_resource_start(dev, 4) + 0x90);
- if ((temp & 0xFFFFF000) != 0xABCDE000) {
- printk(KERN_WARNING "HPT37X: no clock data saved by BIOS\n");
-
- /* Calculate the average value of f_CNT */
- for (temp = i = 0; i < 128; i++) {
- pci_read_config_word(dev, 0x78, &freq);
- temp += freq & 0x1ff;
- mdelay(1);
- }
- freq = temp / 128;
- } else
- freq = temp & 0x1ff;
+ if (dev->resource[PCI_ROM_RESOURCE].start)
+ pci_write_config_dword(dev, PCI_ROM_ADDRESS,
+ dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
+
+ pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4));
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78);
+ pci_write_config_byte(dev, PCI_MIN_GNT, 0x08);
+ pci_write_config_byte(dev, PCI_MAX_LAT, 0x08);
/*
- * HPT3xxN chips use different PCI clock information.
- * Currently we always set up the PLL for them.
+ * First, try to estimate the PCI clock frequency...
*/
+ if (info->chip_type >= HPT370) {
+ u8 scr1 = 0;
+ u16 f_cnt = 0;
+ u32 temp = 0;
- if (info->flags & IS_3xxN) {
- if(freq < 0x55)
- pll = F_LOW_PCI_33;
- else if(freq < 0x70)
- pll = F_LOW_PCI_40;
- else if(freq < 0x7F)
- pll = F_LOW_PCI_50;
- else
- pll = F_LOW_PCI_66;
+ /* Interrupt force enable. */
+ pci_read_config_byte(dev, 0x5a, &scr1);
+ if (scr1 & 0x10)
+ pci_write_config_byte(dev, 0x5a, scr1 & ~0x10);
- printk(KERN_INFO "HPT3xxN detected, FREQ: %d, PLL: %d\n", freq, pll);
- }
- else
- {
- if(freq < 0x9C)
- pll = F_LOW_PCI_33;
- else if(freq < 0xb0)
- pll = F_LOW_PCI_40;
- else if(freq <0xc8)
- pll = F_LOW_PCI_50;
+ /*
+ * HighPoint does this for HPT372A.
+ * NOTE: This register is only writeable via I/O space.
+ */
+ if (info->chip_type == HPT372A)
+ outb(0x0e, io_base + 0x9c);
+
+ /*
+ * Default to PCI clock. Make sure MA15/16 are set to output
+ * to prevent drives having problems with 40-pin cables.
+ */
+ pci_write_config_byte(dev, 0x5b, 0x23);
+
+ /*
+ * We'll have to read f_CNT value in order to determine
+ * the PCI clock frequency according to the following ratio:
+ *
+ * f_CNT = Fpci * 192 / Fdpll
+ *
+ * First try reading the register in which the HighPoint BIOS
+ * saves f_CNT value before reprogramming the DPLL from its
+ * default setting (which differs for the various chips).
+ * NOTE: This register is only accessible via I/O space.
+ *
+ * In case the signature check fails, we'll have to resort to
+ * reading the f_CNT register itself in hopes that nobody has
+ * touched the DPLL yet...
+ */
+ temp = inl(io_base + 0x90);
+ if ((temp & 0xFFFFF000) != 0xABCDE000) {
+ int i;
+
+ printk(KERN_WARNING "%s: no clock data saved by BIOS\n",
+ name);
+
+ /* Calculate the average value of f_CNT. */
+ for (temp = i = 0; i < 128; i++) {
+ pci_read_config_word(dev, 0x78, &f_cnt);
+ temp += f_cnt & 0x1ff;
+ mdelay(1);
+ }
+ f_cnt = temp / 128;
+ } else
+ f_cnt = temp & 0x1ff;
+
+ dpll_clk = info->dpll_clk;
+ pci_clk = (f_cnt * dpll_clk) / 192;
+
+ /* Clamp PCI clock to bands. */
+ if (pci_clk < 40)
+ pci_clk = 33;
+ else if(pci_clk < 45)
+ pci_clk = 40;
+ else if(pci_clk < 55)
+ pci_clk = 50;
else
- pll = F_LOW_PCI_66;
-
- if (pll == F_LOW_PCI_33) {
- info->speed = thirty_three_base_hpt37x;
- printk(KERN_DEBUG "HPT37X: using 33MHz PCI clock\n");
- } else if (pll == F_LOW_PCI_40) {
- /* Unsupported */
- } else if (pll == F_LOW_PCI_50) {
- info->speed = fifty_base_hpt37x;
- printk(KERN_DEBUG "HPT37X: using 50MHz PCI clock\n");
- } else {
- info->speed = sixty_six_base_hpt37x;
- printk(KERN_DEBUG "HPT37X: using 66MHz PCI clock\n");
+ pci_clk = 66;
+
+ printk(KERN_INFO "%s: DPLL base: %d MHz, f_CNT: %d, "
+ "assuming %d MHz PCI\n", name, dpll_clk, f_cnt, pci_clk);
+ } else {
+ u32 itr1 = 0;
+
+ pci_read_config_dword(dev, 0x40, &itr1);
+
+ /* Detect PCI clock by looking at cmd_high_time. */
+ switch((itr1 >> 8) & 0x07) {
+ case 0x09:
+ pci_clk = 40;
+ break;
+ case 0x05:
+ pci_clk = 25;
+ break;
+ case 0x07:
+ default:
+ pci_clk = 33;
+ break;
}
}
- if (pll == F_LOW_PCI_66)
- info->flags |= PCI_66MHZ;
+ /* Let's assume we'll use PCI clock for the ATA clock... */
+ switch (pci_clk) {
+ case 25:
+ clock = ATA_CLOCK_25MHZ;
+ break;
+ case 33:
+ default:
+ clock = ATA_CLOCK_33MHZ;
+ break;
+ case 40:
+ clock = ATA_CLOCK_40MHZ;
+ break;
+ case 50:
+ clock = ATA_CLOCK_50MHZ;
+ break;
+ case 66:
+ clock = ATA_CLOCK_66MHZ;
+ break;
+ }
/*
- * only try the pll if we don't have a table for the clock
- * speed that we're running at. NOTE: the internal PLL will
- * result in slow reads when using a 33MHz PCI clock. we also
- * don't like to use the PLL because it will cause glitches
- * on PRST/SRST when the HPT state engine gets reset.
+ * Only try the DPLL if we don't have a table for the PCI clock that
+ * we are running at for HPT370/A, always use it for anything newer...
*
- * ToDo: Use 66MHz PLL when ATA133 devices are present on a
- * 372 device so we can get ATA133 support
+ * NOTE: Using the internal DPLL results in slow reads on 33 MHz PCI.
+ * We also don't like using the DPLL because this causes glitches
+ * on PRST-/SRST- when the state engine gets reset...
*/
- if (info->speed)
- goto init_hpt37X_done;
+ if (info->chip_type >= HPT374 || info->settings[clock] == NULL) {
+ u16 f_low, delta = pci_clk < 50 ? 2 : 4;
+ int adjust;
+
+ /*
+ * Select 66 MHz DPLL clock only if UltraATA/133 mode is
+ * supported/enabled, use 50 MHz DPLL clock otherwise...
+ */
+ if (info->max_mode == 0x04) {
+ dpll_clk = 66;
+ clock = ATA_CLOCK_66MHZ;
+ } else if (dpll_clk) { /* HPT36x chips don't have DPLL */
+ dpll_clk = 50;
+ clock = ATA_CLOCK_50MHZ;
+ }
- info->flags |= PLL_MODE;
-
- /*
- * Adjust the PLL based upon the PCI clock, enable it, and
- * wait for stabilization...
- */
- adjust = 0;
- freq = (pll < F_LOW_PCI_50) ? 2 : 4;
- while (adjust++ < 6) {
- pci_write_config_dword(dev, 0x5c, (freq + pll) << 16 |
- pll | 0x100);
-
- /* wait for clock stabilization */
- for (i = 0; i < 0x50000; i++) {
- pci_read_config_byte(dev, 0x5b, &reg5bh);
- if (reg5bh & 0x80) {
- /* spin looking for the clock to destabilize */
- for (i = 0; i < 0x1000; ++i) {
- pci_read_config_byte(dev, 0x5b,
- &reg5bh);
- if ((reg5bh & 0x80) == 0)
- goto pll_recal;
- }
- pci_read_config_dword(dev, 0x5c, &pll);
- pci_write_config_dword(dev, 0x5c,
- pll & ~0x100);
- pci_write_config_byte(dev, 0x5b, 0x21);
-
- info->speed = fifty_base_hpt37x;
- printk("HPT37X: using 50MHz internal PLL\n");
- goto init_hpt37X_done;
- }
+ if (info->settings[clock] == NULL) {
+ printk(KERN_ERR "%s: unknown bus timing!\n", name);
+ kfree(info);
+ return -EIO;
}
-pll_recal:
- if (adjust & 1)
- pll -= (adjust >> 1);
- else
- pll += (adjust >> 1);
- }
-init_hpt37X_done:
- if (!info->speed)
- printk(KERN_ERR "HPT37x%s: unknown bus timing [%d %d].\n",
- (info->flags & IS_3xxN) ? "N" : "", pll, freq);
- /*
- * Reset the state engines.
- * NOTE: avoid accidentally enabling the primary channel on HPT371N.
- */
- pci_read_config_byte(dev, 0x50, &mcr1);
- if (mcr1 & 0x04)
- pci_write_config_byte(dev, 0x50, 0x37);
- pci_write_config_byte(dev, 0x54, 0x37);
- udelay(100);
-}
+ /* Select the DPLL clock. */
+ pci_write_config_byte(dev, 0x5b, 0x21);
-static int __devinit init_hpt37x(struct pci_dev *dev)
-{
- u8 reg5ah;
+ /*
+ * Adjust the DPLL based upon PCI clock, enable it,
+ * and wait for stabilization...
+ */
+ f_low = (pci_clk * 48) / dpll_clk;
- pci_read_config_byte(dev, 0x5a, &reg5ah);
- /* interrupt force enable */
- pci_write_config_byte(dev, 0x5a, (reg5ah & ~0x10));
- return 0;
-}
+ for (adjust = 0; adjust < 8; adjust++) {
+ if(hpt37x_calibrate_dpll(dev, f_low, f_low + delta))
+ break;
-static int __devinit init_hpt366(struct pci_dev *dev)
-{
- u32 reg1 = 0;
- u8 drive_fast = 0;
+ /*
+ * See if it'll settle at a fractionally different clock
+ */
+ if (adjust & 1)
+ f_low -= adjust >> 1;
+ else
+ f_low += adjust >> 1;
+ }
+ if (adjust == 8) {
+ printk(KERN_ERR "%s: DPLL did not stabilize!\n", name);
+ kfree(info);
+ return -EIO;
+ }
- /*
- * Disable the "fast interrupt" prediction.
- */
- pci_read_config_byte(dev, 0x51, &drive_fast);
- if (drive_fast & 0x80)
- pci_write_config_byte(dev, 0x51, drive_fast & ~0x80);
- pci_read_config_dword(dev, 0x40, &reg1);
-
- return 0;
-}
+ printk("%s: using %d MHz DPLL clock\n", name, dpll_clk);
+ } else {
+ /* Mark the fact that we're not using the DPLL. */
+ dpll_clk = 0;
-static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const char *name)
-{
- int ret = 0;
+ printk("%s: using %d MHz PCI clock\n", name, pci_clk);
+ }
/*
- * FIXME: Not portable. Also, why do we enable the ROM in the first place?
- * We don't seem to be using it.
+ * Advance the table pointer to a slot which points to the list
+ * of the register values settings matching the clock being used.
*/
- if (dev->resource[PCI_ROM_RESOURCE].start)
- pci_write_config_dword(dev, PCI_ROM_ADDRESS,
- dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
+ info->settings += clock;
- pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4));
- pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78);
- pci_write_config_byte(dev, PCI_MIN_GNT, 0x08);
- pci_write_config_byte(dev, PCI_MAX_LAT, 0x08);
+ /* Store the clock frequencies. */
+ info->dpll_clk = dpll_clk;
+ info->pci_clk = pci_clk;
- if (hpt_revision(dev) >= 3)
- ret = init_hpt37x(dev);
- else
- ret = init_hpt366(dev);
+ /* Point to this chip's own instance of the hpt_info structure. */
+ pci_set_drvdata(dev, info);
- if (ret)
- return ret;
+ if (info->chip_type >= HPT370) {
+ u8 mcr1, mcr4;
+
+ /*
+ * Reset the state engines.
+ * NOTE: Avoid accidentally enabling the disabled channels.
+ */
+ pci_read_config_byte (dev, 0x50, &mcr1);
+ pci_read_config_byte (dev, 0x54, &mcr4);
+ pci_write_config_byte(dev, 0x50, (mcr1 | 0x32));
+ pci_write_config_byte(dev, 0x54, (mcr4 | 0x32));
+ udelay(100);
+ }
+
+ /*
+ * 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 (info->chip_type == HPT371N && clock == ATA_CLOCK_66MHZ)
+
+ outb(inb(io_base + 0x9c) | 0x04, io_base + 0x9c);
return dev->irq;
}
static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
{
- struct pci_dev *dev = hwif->pci_dev;
- struct hpt_info *info = ide_get_hwifdata(hwif);
- u8 ata66 = 0, regmask = (hwif->channel) ? 0x01 : 0x02;
+ struct pci_dev *dev = hwif->pci_dev;
+ struct hpt_info *info = pci_get_drvdata(dev);
int serialize = HPT_SERIALIZE_IO;
-
+ u8 scr1 = 0, ata66 = (hwif->channel) ? 0x01 : 0x02;
+ u8 chip_type = info->chip_type;
+ u8 new_mcr, old_mcr = 0;
+
+ /* Cache the channel's MISC. control registers' offset */
+ hwif->select_data = hwif->channel ? 0x54 : 0x50;
+
hwif->tuneproc = &hpt3xx_tune_drive;
hwif->speedproc = &hpt3xx_tune_chipset;
hwif->quirkproc = &hpt3xx_quirkproc;
hwif->intrproc = &hpt3xx_intrproc;
hwif->maskproc = &hpt3xx_maskproc;
-
+ hwif->busproc = &hpt3xx_busproc;
+
/*
* HPT3xxN chips have some complications:
*
* - on 33 MHz PCI we must clock switch
* - on 66 MHz PCI we must NOT use the PCI clock
*/
- if ((info->flags & (IS_3xxN | PCI_66MHZ)) == IS_3xxN) {
+ if (chip_type >= HPT372N && info->dpll_clk && info->pci_clk < 66) {
/*
* Clock is shared between the channels,
* so we'll have to serialize them... :-(
@@ -1250,200 +1286,168 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
hwif->rw_disk = &hpt3xxn_rw_disk;
}
+ /* Serialize access to this device if needed */
+ if (serialize && hwif->mate)
+ hwif->serialized = hwif->mate->serialized = 1;
+
+ /*
+ * Disable the "fast interrupt" prediction. Don't hold off
+ * on interrupts. (== 0x01 despite what the docs say)
+ */
+ pci_read_config_byte(dev, hwif->select_data + 1, &old_mcr);
+
+ if (info->chip_type >= HPT374)
+ new_mcr = old_mcr & ~0x07;
+ else if (info->chip_type >= HPT370) {
+ new_mcr = old_mcr;
+ new_mcr &= ~0x02;
+
+#ifdef HPT_DELAY_INTERRUPT
+ new_mcr &= ~0x01;
+#else
+ new_mcr |= 0x01;
+#endif
+ } else /* HPT366 and HPT368 */
+ new_mcr = old_mcr & ~0x80;
+
+ if (new_mcr != old_mcr)
+ pci_write_config_byte(dev, hwif->select_data + 1, new_mcr);
+
+ if (!hwif->dma_base) {
+ hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
+ return;
+ }
+
+ hwif->ultra_mask = 0x7f;
+ hwif->mwdma_mask = 0x07;
+
/*
* The HPT37x uses the CBLID pins as outputs for MA15/MA16
- * address lines to access an external eeprom. To read valid
+ * address lines to access an external EEPROM. To read valid
* cable detect state the pins must be enabled as inputs.
*/
- if (info->revision >= 8 && (PCI_FUNC(dev->devfn) & 1)) {
+ if (chip_type == HPT374 && (PCI_FUNC(dev->devfn) & 1)) {
/*
* HPT374 PCI function 1
* - set bit 15 of reg 0x52 to enable TCBLID as input
* - set bit 15 of reg 0x56 to enable FCBLID as input
*/
- u16 mcr3, mcr6;
- pci_read_config_word(dev, 0x52, &mcr3);
- pci_read_config_word(dev, 0x56, &mcr6);
- pci_write_config_word(dev, 0x52, mcr3 | 0x8000);
- pci_write_config_word(dev, 0x56, mcr6 | 0x8000);
+ u8 mcr_addr = hwif->select_data + 2;
+ u16 mcr;
+
+ pci_read_config_word (dev, mcr_addr, &mcr);
+ pci_write_config_word(dev, mcr_addr, (mcr | 0x8000));
/* now read cable id register */
- pci_read_config_byte(dev, 0x5a, &ata66);
- pci_write_config_word(dev, 0x52, mcr3);
- pci_write_config_word(dev, 0x56, mcr6);
- } else if (info->revision >= 3) {
+ pci_read_config_byte (dev, 0x5a, &scr1);
+ pci_write_config_word(dev, mcr_addr, mcr);
+ } else if (chip_type >= HPT370) {
/*
* HPT370/372 and 374 pcifn 0
- * - clear bit 0 of 0x5b to enable P/SCBLID as inputs
+ * - clear bit 0 of reg 0x5b to enable P/SCBLID as inputs
*/
- u8 scr2;
- pci_read_config_byte(dev, 0x5b, &scr2);
- pci_write_config_byte(dev, 0x5b, scr2 & ~1);
- /* now read cable id register */
- pci_read_config_byte(dev, 0x5a, &ata66);
- pci_write_config_byte(dev, 0x5b, scr2);
- } else {
- pci_read_config_byte(dev, 0x5a, &ata66);
- }
-
-#ifdef DEBUG
- printk("HPT366: reg5ah=0x%02x ATA-%s Cable Port%d\n",
- ata66, (ata66 & regmask) ? "33" : "66",
- PCI_FUNC(hwif->pci_dev->devfn));
-#endif /* DEBUG */
-
- /* Serialize access to this device */
- if (serialize && hwif->mate)
- hwif->serialized = hwif->mate->serialized = 1;
+ u8 scr2 = 0;
- /*
- * Set up ioctl for power status.
- * NOTE: power affects both drives on each channel.
- */
- hwif->busproc = &hpt3xx_busproc;
+ pci_read_config_byte (dev, 0x5b, &scr2);
+ pci_write_config_byte(dev, 0x5b, (scr2 & ~1));
+ /* now read cable id register */
+ pci_read_config_byte (dev, 0x5a, &scr1);
+ pci_write_config_byte(dev, 0x5b, scr2);
+ } else
+ pci_read_config_byte (dev, 0x5a, &scr1);
- if (!hwif->dma_base) {
- hwif->drives[0].autotune = 1;
- hwif->drives[1].autotune = 1;
- return;
- }
+ if (!hwif->udma_four)
+ hwif->udma_four = (scr1 & ata66) ? 0 : 1;
- hwif->ultra_mask = 0x7f;
- hwif->mwdma_mask = 0x07;
+ hwif->ide_dma_check = &hpt366_config_drive_xfer_rate;
- if (!(hwif->udma_four))
- hwif->udma_four = ((ata66 & regmask) ? 0 : 1);
- hwif->ide_dma_check = &hpt366_config_drive_xfer_rate;
-
- if (info->revision >= 8) {
- hwif->ide_dma_test_irq = &hpt374_ide_dma_test_irq;
- hwif->ide_dma_end = &hpt374_ide_dma_end;
- } else if (info->revision >= 5) {
- hwif->ide_dma_test_irq = &hpt374_ide_dma_test_irq;
- hwif->ide_dma_end = &hpt374_ide_dma_end;
- } else if (info->revision >= 3) {
- hwif->dma_start = &hpt370_ide_dma_start;
- hwif->ide_dma_end = &hpt370_ide_dma_end;
- hwif->ide_dma_timeout = &hpt370_ide_dma_timeout;
- hwif->ide_dma_lostirq = &hpt370_ide_dma_lostirq;
- } else if (info->revision >= 2)
- hwif->ide_dma_lostirq = &hpt366_ide_dma_lostirq;
- else
- hwif->ide_dma_lostirq = &hpt366_ide_dma_lostirq;
+ if (chip_type >= HPT374) {
+ hwif->ide_dma_test_irq = &hpt374_ide_dma_test_irq;
+ hwif->ide_dma_end = &hpt374_ide_dma_end;
+ } else if (chip_type >= HPT370) {
+ hwif->dma_start = &hpt370_ide_dma_start;
+ hwif->ide_dma_end = &hpt370_ide_dma_end;
+ hwif->ide_dma_timeout = &hpt370_ide_dma_timeout;
+ } else
+ hwif->ide_dma_lostirq = &hpt366_ide_dma_lostirq;
if (!noautodma)
hwif->autodma = 1;
- hwif->drives[0].autodma = hwif->autodma;
- hwif->drives[1].autodma = hwif->autodma;
+ hwif->drives[0].autodma = hwif->drives[1].autodma = hwif->autodma;
}
static void __devinit init_dma_hpt366(ide_hwif_t *hwif, unsigned long dmabase)
{
- struct hpt_info *info = ide_get_hwifdata(hwif);
- u8 masterdma = 0, slavedma = 0;
- u8 dma_new = 0, dma_old = 0;
- u8 primary = hwif->channel ? 0x4b : 0x43;
- u8 secondary = hwif->channel ? 0x4f : 0x47;
+ struct pci_dev *dev = hwif->pci_dev;
+ u8 masterdma = 0, slavedma = 0;
+ u8 dma_new = 0, dma_old = 0;
unsigned long flags;
- if (!dmabase)
- return;
-
- if(info->speed == NULL) {
- printk(KERN_WARNING "hpt366: no known IDE timings, disabling DMA.\n");
- return;
- }
-
- dma_old = hwif->INB(dmabase+2);
+ dma_old = hwif->INB(dmabase + 2);
local_irq_save(flags);
dma_new = dma_old;
- pci_read_config_byte(hwif->pci_dev, primary, &masterdma);
- pci_read_config_byte(hwif->pci_dev, secondary, &slavedma);
+ pci_read_config_byte(dev, hwif->channel ? 0x4b : 0x43, &masterdma);
+ pci_read_config_byte(dev, hwif->channel ? 0x4f : 0x47, &slavedma);
if (masterdma & 0x30) dma_new |= 0x20;
- if (slavedma & 0x30) dma_new |= 0x40;
+ if ( slavedma & 0x30) dma_new |= 0x40;
if (dma_new != dma_old)
- hwif->OUTB(dma_new, dmabase+2);
+ hwif->OUTB(dma_new, dmabase + 2);
local_irq_restore(flags);
ide_setup_dma(hwif, dmabase, 8);
}
-/*
- * We "borrow" this hook in order to set the data structures
- * up early enough before dma or init_hwif calls are made.
- */
-
-static void __devinit init_iops_hpt366(ide_hwif_t *hwif)
-{
- struct hpt_info *info = kzalloc(sizeof(struct hpt_info), GFP_KERNEL);
- struct pci_dev *dev = hwif->pci_dev;
- u16 did = dev->device;
- u8 rid = 0;
-
- if(info == NULL) {
- printk(KERN_WARNING "hpt366: out of memory.\n");
- return;
- }
- ide_set_hwifdata(hwif, info);
-
- /* Avoid doing the same thing twice. */
- if (hwif->channel && hwif->mate) {
- memcpy(info, ide_get_hwifdata(hwif->mate), sizeof(struct hpt_info));
- return;
- }
-
- pci_read_config_byte(dev, PCI_CLASS_REVISION, &rid);
-
- if (( did == PCI_DEVICE_ID_TTI_HPT366 && rid == 6) ||
- ((did == PCI_DEVICE_ID_TTI_HPT372 ||
- did == PCI_DEVICE_ID_TTI_HPT302 ||
- did == PCI_DEVICE_ID_TTI_HPT371) && rid > 1) ||
- did == PCI_DEVICE_ID_TTI_HPT372N)
- info->flags |= IS_3xxN;
-
- info->revision = hpt_revision(dev);
-
- if (info->revision >= 3)
- hpt37x_clocking(hwif);
- else
- hpt366_clocking(hwif);
-}
-
static int __devinit init_setup_hpt374(struct pci_dev *dev, ide_pci_device_t *d)
{
- struct pci_dev *findev = NULL;
+ struct pci_dev *dev2;
if (PCI_FUNC(dev->devfn) & 1)
return -ENODEV;
- while ((findev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, findev)) != NULL) {
- if ((findev->vendor == dev->vendor) &&
- (findev->device == dev->device) &&
- ((findev->devfn - dev->devfn) == 1) &&
- (PCI_FUNC(findev->devfn) & 1)) {
- if (findev->irq != dev->irq) {
- /* FIXME: we need a core pci_set_interrupt() */
- findev->irq = dev->irq;
- printk(KERN_WARNING "%s: pci-config space interrupt "
- "fixed.\n", d->name);
- }
- return ide_setup_pci_devices(dev, findev, d);
+ pci_set_drvdata(dev, &hpt374);
+
+ if ((dev2 = pci_get_slot(dev->bus, dev->devfn + 1)) != NULL) {
+ int ret;
+
+ pci_set_drvdata(dev2, &hpt374);
+
+ if (dev2->irq != dev->irq) {
+ /* FIXME: we need a core pci_set_interrupt() */
+ dev2->irq = dev->irq;
+ printk(KERN_WARNING "%s: PCI config space interrupt "
+ "fixed.\n", d->name);
}
+ ret = ide_setup_pci_devices(dev, dev2, d);
+ if (ret < 0)
+ pci_dev_put(dev2);
+ return ret;
}
return ide_setup_pci_device(dev, d);
}
-static int __devinit init_setup_hpt37x(struct pci_dev *dev, ide_pci_device_t *d)
+static int __devinit init_setup_hpt372n(struct pci_dev *dev, ide_pci_device_t *d)
{
+ pci_set_drvdata(dev, &hpt372n);
+
return ide_setup_pci_device(dev, d);
}
static int __devinit init_setup_hpt371(struct pci_dev *dev, ide_pci_device_t *d)
{
- u8 mcr1 = 0;
+ struct hpt_info *info;
+ u8 rev = 0, mcr1 = 0;
+
+ pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
+
+ if (rev > 1) {
+ d->name = "HPT371N";
+
+ info = &hpt371n;
+ } else
+ info = &hpt371;
/*
* HPT371 chips physically have only one channel, the secondary one,
@@ -1453,59 +1457,94 @@ static int __devinit init_setup_hpt371(struct pci_dev *dev, ide_pci_device_t *d)
*/
pci_read_config_byte(dev, 0x50, &mcr1);
if (mcr1 & 0x04)
- pci_write_config_byte(dev, 0x50, (mcr1 & ~0x04));
+ pci_write_config_byte(dev, 0x50, mcr1 & ~0x04);
+
+ pci_set_drvdata(dev, info);
+
+ return ide_setup_pci_device(dev, d);
+}
+
+static int __devinit init_setup_hpt372a(struct pci_dev *dev, ide_pci_device_t *d)
+{
+ struct hpt_info *info;
+ u8 rev = 0;
+
+ pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
+
+ if (rev > 1) {
+ d->name = "HPT372N";
+
+ info = &hpt372n;
+ } else
+ info = &hpt372a;
+ pci_set_drvdata(dev, info);
+
+ return ide_setup_pci_device(dev, d);
+}
+
+static int __devinit init_setup_hpt302(struct pci_dev *dev, ide_pci_device_t *d)
+{
+ struct hpt_info *info;
+ u8 rev = 0;
+
+ pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
+
+ if (rev > 1) {
+ d->name = "HPT302N";
+
+ info = &hpt302n;
+ } else
+ info = &hpt302;
+ pci_set_drvdata(dev, info);
return ide_setup_pci_device(dev, d);
}
static int __devinit init_setup_hpt366(struct pci_dev *dev, ide_pci_device_t *d)
{
- struct pci_dev *findev = NULL;
- u8 pin1 = 0, pin2 = 0;
- unsigned int class_rev;
- char *chipset_names[] = {"HPT366", "HPT366", "HPT368",
- "HPT370", "HPT370A", "HPT372",
- "HPT372N" };
+ struct pci_dev *dev2;
+ u8 rev = 0;
+ static char *chipset_names[] = { "HPT366", "HPT366", "HPT368",
+ "HPT370", "HPT370A", "HPT372",
+ "HPT372N" };
+ static struct hpt_info *info[] = { &hpt36x, &hpt36x, &hpt36x,
+ &hpt370, &hpt370a, &hpt372,
+ &hpt372n };
if (PCI_FUNC(dev->devfn) & 1)
return -ENODEV;
- pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
- class_rev &= 0xff;
+ pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
- if(dev->device == PCI_DEVICE_ID_TTI_HPT372N)
- class_rev = 6;
+ if (rev > 6)
+ rev = 6;
- if(class_rev <= 6)
- d->name = chipset_names[class_rev];
-
- switch(class_rev) {
- case 6:
- case 5:
- case 4:
- case 3:
- goto init_single;
- default:
- break;
- }
+ d->name = chipset_names[rev];
+
+ pci_set_drvdata(dev, info[rev]);
+
+ if (rev > 2)
+ goto init_single;
d->channels = 1;
- pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin1);
- while ((findev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, findev)) != NULL) {
- if ((findev->vendor == dev->vendor) &&
- (findev->device == dev->device) &&
- ((findev->devfn - dev->devfn) == 1) &&
- (PCI_FUNC(findev->devfn) & 1)) {
- pci_read_config_byte(findev, PCI_INTERRUPT_PIN, &pin2);
- if ((pin1 != pin2) && (dev->irq == findev->irq)) {
- d->bootable = ON_BOARD;
- printk("%s: onboard version of chipset, "
- "pin1=%d pin2=%d\n", d->name,
- pin1, pin2);
- }
- return ide_setup_pci_devices(dev, findev, d);
+ if ((dev2 = pci_get_slot(dev->bus, dev->devfn + 1)) != NULL) {
+ u8 pin1 = 0, pin2 = 0;
+ int ret;
+
+ pci_set_drvdata(dev2, info[rev]);
+
+ pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin1);
+ pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin2);
+ if (pin1 != pin2 && dev->irq == dev2->irq) {
+ d->bootable = ON_BOARD;
+ printk("%s: onboard version of chipset, pin1=%d pin2=%d\n",
+ d->name, pin1, pin2);
}
+ ret = ide_setup_pci_devices(dev, dev2, d);
+ if (ret < 0)
+ pci_dev_put(dev2);
+ return ret;
}
init_single:
return ide_setup_pci_device(dev, d);
@@ -1516,64 +1555,68 @@ static ide_pci_device_t hpt366_chipsets[] __devinitdata = {
.name = "HPT366",
.init_setup = init_setup_hpt366,
.init_chipset = init_chipset_hpt366,
- .init_iops = init_iops_hpt366,
.init_hwif = init_hwif_hpt366,
.init_dma = init_dma_hpt366,
.channels = 2,
.autodma = AUTODMA,
+ .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
.bootable = OFF_BOARD,
.extra = 240
},{ /* 1 */
.name = "HPT372A",
- .init_setup = init_setup_hpt37x,
+ .init_setup = init_setup_hpt372a,
.init_chipset = init_chipset_hpt366,
- .init_iops = init_iops_hpt366,
.init_hwif = init_hwif_hpt366,
.init_dma = init_dma_hpt366,
.channels = 2,
.autodma = AUTODMA,
+ .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
.bootable = OFF_BOARD,
+ .extra = 240
},{ /* 2 */
.name = "HPT302",
- .init_setup = init_setup_hpt37x,
+ .init_setup = init_setup_hpt302,
.init_chipset = init_chipset_hpt366,
- .init_iops = init_iops_hpt366,
.init_hwif = init_hwif_hpt366,
.init_dma = init_dma_hpt366,
.channels = 2,
.autodma = AUTODMA,
+ .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
.bootable = OFF_BOARD,
+ .extra = 240
},{ /* 3 */
.name = "HPT371",
.init_setup = init_setup_hpt371,
.init_chipset = init_chipset_hpt366,
- .init_iops = init_iops_hpt366,
.init_hwif = init_hwif_hpt366,
.init_dma = init_dma_hpt366,
.channels = 2,
.autodma = AUTODMA,
.enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
.bootable = OFF_BOARD,
+ .extra = 240
},{ /* 4 */
.name = "HPT374",
.init_setup = init_setup_hpt374,
.init_chipset = init_chipset_hpt366,
- .init_iops = init_iops_hpt366,
.init_hwif = init_hwif_hpt366,
.init_dma = init_dma_hpt366,
.channels = 2, /* 4 */
.autodma = AUTODMA,
+ .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
.bootable = OFF_BOARD,
+ .extra = 240
},{ /* 5 */
.name = "HPT372N",
- .init_setup = init_setup_hpt37x,
+ .init_setup = init_setup_hpt372n,
.init_chipset = init_chipset_hpt366,
- .init_iops = init_iops_hpt366,
.init_hwif = init_hwif_hpt366,
.init_dma = init_dma_hpt366,
.channels = 2, /* 4 */
.autodma = AUTODMA,
+ .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
.bootable = OFF_BOARD,
+ .extra = 240
}
};
diff --git a/drivers/ide/pci/it8213.c b/drivers/ide/pci/it8213.c
new file mode 100644
index 00000000000..424f00bb160
--- /dev/null
+++ b/drivers/ide/pci/it8213.c
@@ -0,0 +1,360 @@
+/*
+ * ITE 8213 IDE driver
+ *
+ * Copyright (C) 2006 Jack Lee
+ * Copyright (C) 2006 Alan Cox
+ * Copyright (C) 2007 Bartlomiej Zolnierkiewicz
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+/*
+ * it8213_ratemask - Compute available modes
+ * @drive: IDE drive
+ *
+ * Compute the available speeds for the devices on the interface. This
+ * is all modes to ATA133 clipped by drive cable setup.
+ */
+
+static u8 it8213_ratemask (ide_drive_t *drive)
+{
+ u8 mode = 4;
+ if (!eighty_ninty_three(drive))
+ mode = min_t(u8, mode, 1);
+ return mode;
+}
+
+/**
+ * it8213_dma_2_pio - return the PIO mode matching DMA
+ * @xfer_rate: transfer speed
+ *
+ * Returns the nearest equivalent PIO timing for the PIO or DMA
+ * mode requested by the controller.
+ */
+
+static u8 it8213_dma_2_pio (u8 xfer_rate) {
+ switch(xfer_rate) {
+ case XFER_UDMA_6:
+ case XFER_UDMA_5:
+ case XFER_UDMA_4:
+ case XFER_UDMA_3:
+ case XFER_UDMA_2:
+ case XFER_UDMA_1:
+ case XFER_UDMA_0:
+ case XFER_MW_DMA_2:
+ case XFER_PIO_4:
+ return 4;
+ case XFER_MW_DMA_1:
+ case XFER_PIO_3:
+ return 3;
+ case XFER_SW_DMA_2:
+ case XFER_PIO_2:
+ return 2;
+ case XFER_MW_DMA_0:
+ case XFER_SW_DMA_1:
+ case XFER_SW_DMA_0:
+ case XFER_PIO_1:
+ case XFER_PIO_0:
+ case XFER_PIO_SLOW:
+ default:
+ return 0;
+ }
+}
+
+/*
+ * it8213_tuneproc - tune a drive
+ * @drive: drive to tune
+ * @pio: desired PIO mode
+ *
+ * Set the interface PIO mode.
+ */
+
+static void it8213_tuneproc (ide_drive_t *drive, u8 pio)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ int is_slave = drive->dn & 1;
+ int master_port = 0x40;
+ int slave_port = 0x44;
+ unsigned long flags;
+ u16 master_data;
+ u8 slave_data;
+ static DEFINE_SPINLOCK(tune_lock);
+ int control = 0;
+
+ static const u8 timings[][2]= {
+ { 0, 0 },
+ { 0, 0 },
+ { 1, 0 },
+ { 2, 1 },
+ { 2, 3 }, };
+
+ pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+
+ spin_lock_irqsave(&tune_lock, flags);
+ pci_read_config_word(dev, master_port, &master_data);
+
+ if (pio > 1)
+ control |= 1; /* Programmable timing on */
+ if (drive->media != ide_disk)
+ control |= 4; /* ATAPI */
+ if (pio > 2)
+ control |= 2; /* IORDY */
+ if (is_slave) {
+ master_data |= 0x4000;
+ master_data &= ~0x0070;
+ if (pio > 1)
+ master_data = master_data | (control << 4);
+ pci_read_config_byte(dev, slave_port, &slave_data);
+ slave_data = slave_data & 0xf0;
+ slave_data = slave_data | (timings[pio][0] << 2) | timings[pio][1];
+ } else {
+ master_data &= ~0x3307;
+ if (pio > 1)
+ master_data = master_data | control;
+ master_data = master_data | (timings[pio][0] << 12) | (timings[pio][1] << 8);
+ }
+ pci_write_config_word(dev, master_port, master_data);
+ if (is_slave)
+ pci_write_config_byte(dev, slave_port, slave_data);
+ spin_unlock_irqrestore(&tune_lock, flags);
+}
+
+/**
+ * it8213_tune_chipset - set controller timings
+ * @drive: Drive to set up
+ * @xferspeed: speed we want to achieve
+ *
+ * Tune the ITE chipset for the desired mode. If we can't achieve
+ * the desired mode then tune for a lower one, but ultimately
+ * make the thing work.
+ */
+
+static int it8213_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ u8 maslave = 0x40;
+ u8 speed = ide_rate_filter(it8213_ratemask(drive), xferspeed);
+ int a_speed = 3 << (drive->dn * 4);
+ int u_flag = 1 << drive->dn;
+ int v_flag = 0x01 << drive->dn;
+ int w_flag = 0x10 << drive->dn;
+ int u_speed = 0;
+ u16 reg4042, reg4a;
+ u8 reg48, reg54, reg55;
+
+ pci_read_config_word(dev, maslave, &reg4042);
+ pci_read_config_byte(dev, 0x48, &reg48);
+ pci_read_config_word(dev, 0x4a, &reg4a);
+ pci_read_config_byte(dev, 0x54, &reg54);
+ pci_read_config_byte(dev, 0x55, &reg55);
+
+ switch(speed) {
+ case XFER_UDMA_6:
+ case XFER_UDMA_4:
+ case XFER_UDMA_2: u_speed = 2 << (drive->dn * 4); break;
+ case XFER_UDMA_5:
+ case XFER_UDMA_3:
+ case XFER_UDMA_1: u_speed = 1 << (drive->dn * 4); break;
+ case XFER_UDMA_0: u_speed = 0 << (drive->dn * 4); break;
+ break;
+ case XFER_MW_DMA_2:
+ case XFER_MW_DMA_1:
+ case XFER_SW_DMA_2:
+ break;
+ case XFER_PIO_4:
+ case XFER_PIO_3:
+ case XFER_PIO_2:
+ case XFER_PIO_1:
+ case XFER_PIO_0:
+ break;
+ default:
+ return -1;
+ }
+
+ if (speed >= XFER_UDMA_0) {
+ if (!(reg48 & u_flag))
+ pci_write_config_byte(dev, 0x48, reg48 | u_flag);
+ if (speed >= XFER_UDMA_5) {
+ pci_write_config_byte(dev, 0x55, (u8) reg55|w_flag);
+ } else {
+ pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
+ }
+
+ if ((reg4a & a_speed) != u_speed)
+ pci_write_config_word(dev, 0x4a, (reg4a & ~a_speed) | u_speed);
+ if (speed > XFER_UDMA_2) {
+ if (!(reg54 & v_flag))
+ pci_write_config_byte(dev, 0x54, reg54 | v_flag);
+ } else
+ pci_write_config_byte(dev, 0x54, reg54 & ~v_flag);
+ } else {
+ if (reg48 & u_flag)
+ pci_write_config_byte(dev, 0x48, reg48 & ~u_flag);
+ if (reg4a & a_speed)
+ pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
+ if (reg54 & v_flag)
+ pci_write_config_byte(dev, 0x54, reg54 & ~v_flag);
+ if (reg55 & w_flag)
+ pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
+ }
+ it8213_tuneproc(drive, it8213_dma_2_pio(speed));
+ return ide_config_drive_speed(drive, speed);
+}
+
+/*
+ * config_chipset_for_dma - configure for DMA
+ * @drive: drive to configure
+ *
+ * Called by the IDE layer when it wants the timings set up.
+ */
+
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+ u8 speed = ide_dma_speed(drive, it8213_ratemask(drive));
+
+ if (!speed)
+ return 0;
+
+ it8213_tune_chipset(drive, speed);
+
+ return ide_dma_enable(drive);
+}
+
+/**
+ * it8213_configure_drive_for_dma - set up for DMA transfers
+ * @drive: drive we are going to set up
+ *
+ * Set up the drive for DMA, tune the controller and drive as
+ * required. If the drive isn't suitable for DMA or we hit
+ * other problems then we will drop down to PIO and set up
+ * PIO appropriately
+ */
+
+static int it8213_config_drive_for_dma (ide_drive_t *drive)
+{
+ u8 pio;
+
+ if (ide_use_dma(drive) && config_chipset_for_dma(drive))
+ return 0;
+
+ pio = ide_get_best_pio_mode(drive, 255, 4, NULL);
+ it8213_tune_chipset(drive, XFER_PIO_0 + pio);
+
+ return -1;
+}
+
+/**
+ * init_hwif_it8213 - set up hwif structs
+ * @hwif: interface to set up
+ *
+ * We do the basic set up of the interface structure. The IT8212
+ * requires several custom handlers so we override the default
+ * ide DMA handlers appropriately
+ */
+
+static void __devinit init_hwif_it8213(ide_hwif_t *hwif)
+{
+ u8 reg42h = 0, ata66 = 0;
+
+ hwif->speedproc = &it8213_tune_chipset;
+ hwif->tuneproc = &it8213_tuneproc;
+
+ hwif->autodma = 0;
+
+ hwif->drives[0].autotune = 1;
+ hwif->drives[1].autotune = 1;
+
+ if (!hwif->dma_base)
+ return;
+
+ hwif->atapi_dma = 1;
+ hwif->ultra_mask = 0x7f;
+ hwif->mwdma_mask = 0x06;
+ hwif->swdma_mask = 0x04;
+
+ pci_read_config_byte(hwif->pci_dev, 0x42, &reg42h);
+ ata66 = (reg42h & 0x02) ? 0 : 1;
+
+ hwif->ide_dma_check = &it8213_config_drive_for_dma;
+ if (!(hwif->udma_four))
+ hwif->udma_four = ata66;
+
+ /*
+ * The BIOS often doesn't set up DMA on this controller
+ * so we always do it.
+ */
+ if (!noautodma)
+ hwif->autodma = 1;
+
+ hwif->drives[0].autodma = hwif->autodma;
+ hwif->drives[1].autodma = hwif->autodma;
+}
+
+
+#define DECLARE_ITE_DEV(name_str) \
+ { \
+ .name = name_str, \
+ .init_hwif = init_hwif_it8213, \
+ .channels = 1, \
+ .autodma = AUTODMA, \
+ .enablebits = {{0x41,0x80,0x80}}, \
+ .bootable = ON_BOARD, \
+ }
+
+static ide_pci_device_t it8213_chipsets[] __devinitdata = {
+ /* 0 */ DECLARE_ITE_DEV("IT8213"),
+};
+
+
+/**
+ * it8213_init_one - pci layer discovery entry
+ * @dev: PCI device
+ * @id: ident table entry
+ *
+ * Called by the PCI code when it finds an ITE8213 controller. As
+ * this device follows the standard interfaces we can use the
+ * standard helper functions to do almost all the work for us.
+ */
+
+static int __devinit it8213_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ ide_setup_pci_device(dev, &it8213_chipsets[id->driver_data]);
+ return 0;
+}
+
+
+static struct pci_device_id it8213_pci_tbl[] = {
+ { PCI_VENDOR_ID_ITE, 0x8213, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { 0, },
+};
+
+MODULE_DEVICE_TABLE(pci, it8213_pci_tbl);
+
+static struct pci_driver driver = {
+ .name = "ITE8213_IDE",
+ .id_table = it8213_pci_tbl,
+ .probe = it8213_init_one,
+};
+
+static int __init it8213_ide_init(void)
+{
+ return ide_pci_register_driver(&driver);
+}
+
+module_init(it8213_ide_init);
+
+MODULE_AUTHOR("Jack Lee, Alan Cox");
+MODULE_DESCRIPTION("PCI driver module for the ITE 8213");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/pci/it821x.c b/drivers/ide/pci/it821x.c
index e9bad185968..a132767f7d9 100644
--- a/drivers/ide/pci/it821x.c
+++ b/drivers/ide/pci/it821x.c
@@ -520,14 +520,12 @@ static int config_chipset_for_dma (ide_drive_t *drive)
static int it821x_config_drive_for_dma (ide_drive_t *drive)
{
- ide_hwif_t *hwif = drive->hwif;
+ if (ide_use_dma(drive) && config_chipset_for_dma(drive))
+ return 0;
- if (ide_use_dma(drive)) {
- if (config_chipset_for_dma(drive))
- return hwif->ide_dma_on(drive);
- }
config_it821x_chipset_for_pio(drive, 1);
- return hwif->ide_dma_off_quietly(drive);
+
+ return -1;
}
/**
@@ -608,11 +606,11 @@ static void __devinit it821x_fixups(ide_hwif_t *hwif)
printk(".\n");
/* Now the core code will have wrongly decided no DMA
so we need to fix this */
- hwif->ide_dma_off_quietly(drive);
+ hwif->dma_off_quietly(drive);
#ifdef CONFIG_IDEDMA_ONLYDISK
if (drive->media == ide_disk)
#endif
- hwif->ide_dma_check(drive);
+ ide_set_dma(drive);
} else {
/* Non RAID volume. Fixups to stop the core code
doing unsupported things */
diff --git a/drivers/ide/pci/jmicron.c b/drivers/ide/pci/jmicron.c
index f07bbbed177..53f25500c22 100644
--- a/drivers/ide/pci/jmicron.c
+++ b/drivers/ide/pci/jmicron.c
@@ -147,7 +147,9 @@ static int config_chipset_for_dma (ide_drive_t *drive)
{
u8 speed = ide_dma_speed(drive, jmicron_ratemask(drive));
- config_jmicron_chipset_for_pio(drive, !speed);
+ if (!speed)
+ return 0;
+
jmicron_tune_chipset(drive, speed);
return ide_dma_enable(drive);
}
@@ -162,14 +164,12 @@ static int config_chipset_for_dma (ide_drive_t *drive)
static int jmicron_config_drive_for_dma (ide_drive_t *drive)
{
- ide_hwif_t *hwif = drive->hwif;
+ if (ide_use_dma(drive) && config_chipset_for_dma(drive))
+ return 0;
- if (ide_use_dma(drive)) {
- if (config_chipset_for_dma(drive))
- return hwif->ide_dma_on(drive);
- }
config_jmicron_chipset_for_pio(drive, 1);
- return hwif->ide_dma_off_quietly(drive);
+
+ return -1;
}
/**
diff --git a/drivers/ide/pci/ns87415.c b/drivers/ide/pci/ns87415.c
index 8aaea4ea554..b310c4f5107 100644
--- a/drivers/ide/pci/ns87415.c
+++ b/drivers/ide/pci/ns87415.c
@@ -166,10 +166,10 @@ static int ns87415_ide_dma_end (ide_drive_t *drive)
/* get dma command mode */
dma_cmd = hwif->INB(hwif->dma_command);
/* stop DMA */
- hwif->OUTB(dma_cmd & ~1, hwif->dma_command);
+ outb(dma_cmd & ~1, hwif->dma_command);
/* from ERRATA: clear the INTR & ERROR bits */
dma_cmd = hwif->INB(hwif->dma_command);
- hwif->OUTB(dma_cmd|6, hwif->dma_command);
+ outb(dma_cmd | 6, hwif->dma_command);
/* and free any DMA resources */
ide_destroy_dmatable(drive);
/* verify good DMA status */
@@ -190,7 +190,8 @@ static int ns87415_ide_dma_setup(ide_drive_t *drive)
static int ns87415_ide_dma_check (ide_drive_t *drive)
{
if (drive->media != ide_disk)
- return HWIF(drive)->ide_dma_off_quietly(drive);
+ return -1;
+
return __ide_dma_check(drive);
}
@@ -243,9 +244,9 @@ static void __devinit init_hwif_ns87415 (ide_hwif_t *hwif)
* to SELECT_DRIVE() properly during first probe_hwif().
*/
timeout = 10000;
- hwif->OUTB(12, hwif->io_ports[IDE_CONTROL_OFFSET]);
+ outb(12, hwif->io_ports[IDE_CONTROL_OFFSET]);
udelay(10);
- hwif->OUTB(8, hwif->io_ports[IDE_CONTROL_OFFSET]);
+ outb(8, hwif->io_ports[IDE_CONTROL_OFFSET]);
do {
udelay(50);
stat = hwif->INB(hwif->io_ports[IDE_STATUS_OFFSET]);
@@ -263,7 +264,7 @@ static void __devinit init_hwif_ns87415 (ide_hwif_t *hwif)
if (!hwif->dma_base)
return;
- hwif->OUTB(0x60, hwif->dma_status);
+ outb(0x60, hwif->dma_status);
hwif->dma_setup = &ns87415_ide_dma_setup;
hwif->ide_dma_check = &ns87415_ide_dma_check;
hwif->ide_dma_end = &ns87415_ide_dma_end;
diff --git a/drivers/ide/pci/opti621.c b/drivers/ide/pci/opti621.c
index 22bbf613f94..9ca60dd2185 100644
--- a/drivers/ide/pci/opti621.c
+++ b/drivers/ide/pci/opti621.c
@@ -176,34 +176,35 @@ static int cmpt_clk(int time, int bus_speed)
return ((time*bus_speed+999)/1000);
}
-static void write_reg(ide_hwif_t *hwif, u8 value, int reg)
/* Write value to register reg, base of register
* is at reg_base (0x1f0 primary, 0x170 secondary,
* if not changed by PCI configuration).
* This is from setupvic.exe program.
*/
+static void write_reg(u8 value, int reg)
{
- hwif->INW(reg_base+1);
- hwif->INW(reg_base+1);
- hwif->OUTB(3, reg_base+2);
- hwif->OUTB(value, reg_base+reg);
- hwif->OUTB(0x83, reg_base+2);
+ inw(reg_base + 1);
+ inw(reg_base + 1);
+ outb(3, reg_base + 2);
+ outb(value, reg_base + reg);
+ outb(0x83, reg_base + 2);
}
-static u8 read_reg(ide_hwif_t *hwif, int reg)
/* Read value from register reg, base of register
* is at reg_base (0x1f0 primary, 0x170 secondary,
* if not changed by PCI configuration).
* This is from setupvic.exe program.
*/
+static u8 read_reg(int reg)
{
u8 ret = 0;
- hwif->INW(reg_base+1);
- hwif->INW(reg_base+1);
- hwif->OUTB(3, reg_base+2);
- ret = hwif->INB(reg_base+reg);
- hwif->OUTB(0x83, reg_base+2);
+ inw(reg_base + 1);
+ inw(reg_base + 1);
+ outb(3, reg_base + 2);
+ ret = inb(reg_base + reg);
+ outb(0x83, reg_base + 2);
+
return ret;
}
@@ -286,39 +287,39 @@ static void opti621_tune_drive (ide_drive_t *drive, u8 pio)
reg_base = hwif->io_ports[IDE_DATA_OFFSET];
/* allow Register-B */
- hwif->OUTB(0xc0, reg_base+CNTRL_REG);
+ outb(0xc0, reg_base + CNTRL_REG);
/* hmm, setupvic.exe does this ;-) */
- hwif->OUTB(0xff, reg_base+5);
+ outb(0xff, reg_base + 5);
/* if reads 0xff, adapter not exist? */
- (void) hwif->INB(reg_base+CNTRL_REG);
+ (void)inb(reg_base + CNTRL_REG);
/* if reads 0xc0, no interface exist? */
- read_reg(hwif, CNTRL_REG);
+ read_reg(CNTRL_REG);
/* read version, probably 0 */
- read_reg(hwif, STRAP_REG);
+ read_reg(STRAP_REG);
/* program primary drive */
- /* select Index-0 for Register-A */
- write_reg(hwif, 0, MISC_REG);
- /* set read cycle timings */
- write_reg(hwif, cycle1, READ_REG);
- /* set write cycle timings */
- write_reg(hwif, cycle1, WRITE_REG);
+ /* select Index-0 for Register-A */
+ write_reg(0, MISC_REG);
+ /* set read cycle timings */
+ write_reg(cycle1, READ_REG);
+ /* set write cycle timings */
+ write_reg(cycle1, WRITE_REG);
/* program secondary drive */
- /* select Index-1 for Register-B */
- write_reg(hwif, 1, MISC_REG);
- /* set read cycle timings */
- write_reg(hwif, cycle2, READ_REG);
- /* set write cycle timings */
- write_reg(hwif, cycle2, WRITE_REG);
+ /* select Index-1 for Register-B */
+ write_reg(1, MISC_REG);
+ /* set read cycle timings */
+ write_reg(cycle2, READ_REG);
+ /* set write cycle timings */
+ write_reg(cycle2, WRITE_REG);
/* use Register-A for drive 0 */
/* use Register-B for drive 1 */
- write_reg(hwif, 0x85, CNTRL_REG);
+ write_reg(0x85, CNTRL_REG);
/* set address setup, DRDY timings, */
/* and read prefetch for both drives */
- write_reg(hwif, misc, MISC_REG);
+ write_reg(misc, MISC_REG);
spin_unlock_irqrestore(&ide_lock, flags);
}
diff --git a/drivers/ide/pci/pdc202xx_new.c b/drivers/ide/pci/pdc202xx_new.c
index 77a9aaa7dab..6ceb25bc5a7 100644
--- a/drivers/ide/pci/pdc202xx_new.c
+++ b/drivers/ide/pci/pdc202xx_new.c
@@ -92,26 +92,6 @@ static u8 pdcnew_ratemask(ide_drive_t *drive)
return mode;
}
-static int check_in_drive_lists(ide_drive_t *drive, const char **list)
-{
- struct hd_driveid *id = drive->id;
-
- if (pdc_quirk_drives == list) {
- while (*list) {
- if (strstr(id->model, *list++)) {
- return 2;
- }
- }
- } else {
- while (*list) {
- if (!strcmp(*list++,id->model)) {
- return 1;
- }
- }
- }
- return 0;
-}
-
/**
* get_indexed_reg - Get indexed register
* @hwif: for the port address
@@ -121,8 +101,8 @@ static u8 get_indexed_reg(ide_hwif_t *hwif, u8 index)
{
u8 value;
- hwif->OUTB(index, hwif->dma_vendor1);
- value = hwif->INB(hwif->dma_vendor3);
+ outb(index, hwif->dma_vendor1);
+ value = inb(hwif->dma_vendor3);
DBG("index[%02X] value[%02X]\n", index, value);
return value;
@@ -135,8 +115,8 @@ static u8 get_indexed_reg(ide_hwif_t *hwif, u8 index)
*/
static void set_indexed_reg(ide_hwif_t *hwif, u8 index, u8 value)
{
- hwif->OUTB(index, hwif->dma_vendor1);
- hwif->OUTB(value, hwif->dma_vendor3);
+ outb(index, hwif->dma_vendor1);
+ outb(value, hwif->dma_vendor3);
DBG("index[%02X] value[%02X]\n", index, value);
}
@@ -249,13 +229,6 @@ static int pdcnew_tune_chipset(ide_drive_t *drive, u8 speed)
return err;
}
-/* 0 1 2 3 4 5 6 7 8
- * 960, 480, 390, 300, 240, 180, 120, 90, 60
- * 180, 150, 120, 90, 60
- * DMA_Speed
- * 180, 120, 90, 90, 90, 60, 30
- * 11, 5, 4, 3, 2, 1, 0
- */
static void pdcnew_tune_drive(ide_drive_t *drive, u8 pio)
{
pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
@@ -308,46 +281,25 @@ static int config_chipset_for_dma(ide_drive_t *drive)
static int pdcnew_config_drive_xfer_rate(ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
- struct hd_driveid *id = drive->id;
-
drive->init_speed = 0;
- if (id && (id->capability & 1) && drive->autodma) {
-
- if (ide_use_dma(drive)) {
- if (config_chipset_for_dma(drive))
- return hwif->ide_dma_on(drive);
- }
+ if (ide_use_dma(drive) && config_chipset_for_dma(drive))
+ return 0;
- goto fast_ata_pio;
+ if (ide_use_fast_pio(drive))
+ pdcnew_tune_drive(drive, 255);
- } else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
- hwif->tuneproc(drive, 255);
- return hwif->ide_dma_off_quietly(drive);
- }
- /* IORDY not supported */
- return 0;
+ return -1;
}
static int pdcnew_quirkproc(ide_drive_t *drive)
{
- return check_in_drive_lists(drive, pdc_quirk_drives);
-}
-
-static int pdcnew_ide_dma_lostirq(ide_drive_t *drive)
-{
- if (HWIF(drive)->resetproc != NULL)
- HWIF(drive)->resetproc(drive);
- return __ide_dma_lostirq(drive);
-}
+ const char **list, *model = drive->id->model;
-static int pdcnew_ide_dma_timeout(ide_drive_t *drive)
-{
- if (HWIF(drive)->resetproc != NULL)
- HWIF(drive)->resetproc(drive);
- return __ide_dma_timeout(drive);
+ for (list = pdc_quirk_drives; *list != NULL; list++)
+ if (strstr(model, *list) != NULL)
+ return 2;
+ return 0;
}
static void pdcnew_reset(ide_drive_t *drive)
@@ -599,8 +551,6 @@ static void __devinit init_hwif_pdc202new(ide_hwif_t *hwif)
hwif->err_stops_fifo = 1;
hwif->ide_dma_check = &pdcnew_config_drive_xfer_rate;
- hwif->ide_dma_lostirq = &pdcnew_ide_dma_lostirq;
- hwif->ide_dma_timeout = &pdcnew_ide_dma_timeout;
if (!hwif->udma_four)
hwif->udma_four = pdcnew_cable_detect(hwif) ? 0 : 1;
diff --git a/drivers/ide/pci/pdc202xx_old.c b/drivers/ide/pci/pdc202xx_old.c
index 143239c093d..a7a639fe1ea 100644
--- a/drivers/ide/pci/pdc202xx_old.c
+++ b/drivers/ide/pci/pdc202xx_old.c
@@ -2,6 +2,7 @@
* linux/drivers/ide/pci/pdc202xx_old.c Version 0.36 Sept 11, 2002
*
* Copyright (C) 1998-2002 Andre Hedrick <andre@linux-ide.org>
+ * Copyright (C) 2006-2007 MontaVista Software, Inc.
*
* Promise Ultra33 cards with BIOS v1.20 through 1.28 will need this
* compiled into the kernel if you have more than one card installed.
@@ -123,26 +124,6 @@ static u8 pdc202xx_ratemask (ide_drive_t *drive)
return mode;
}
-static int check_in_drive_lists (ide_drive_t *drive, const char **list)
-{
- struct hd_driveid *id = drive->id;
-
- if (pdc_quirk_drives == list) {
- while (*list) {
- if (strstr(id->model, *list++)) {
- return 2;
- }
- }
- } else {
- while (*list) {
- if (!strcmp(*list++,id->model)) {
- return 1;
- }
- }
- }
- return 0;
-}
-
static int pdc202xx_tune_chipset (ide_drive_t *drive, u8 xferspeed)
{
ide_hwif_t *hwif = HWIF(drive);
@@ -236,21 +217,10 @@ static int pdc202xx_tune_chipset (ide_drive_t *drive, u8 xferspeed)
}
-/* 0 1 2 3 4 5 6 7 8
- * 960, 480, 390, 300, 240, 180, 120, 90, 60
- * 180, 150, 120, 90, 60
- * DMA_Speed
- * 180, 120, 90, 90, 90, 60, 30
- * 11, 5, 4, 3, 2, 1, 0
- */
-static void config_chipset_for_pio (ide_drive_t *drive, u8 pio)
+static void pdc202xx_tune_drive(ide_drive_t *drive, u8 pio)
{
- u8 speed = 0;
-
- if (pio == 5) pio = 4;
- speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, pio, NULL);
-
- pdc202xx_tune_chipset(drive, speed);
+ pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+ pdc202xx_tune_chipset(drive, XFER_PIO_0 + pio);
}
static u8 pdc202xx_old_cable_detect (ide_hwif_t *hwif)
@@ -270,17 +240,17 @@ static u8 pdc202xx_old_cable_detect (ide_hwif_t *hwif)
static void pdc_old_enable_66MHz_clock(ide_hwif_t *hwif)
{
unsigned long clock_reg = hwif->dma_master + 0x11;
- u8 clock = hwif->INB(clock_reg);
+ u8 clock = inb(clock_reg);
- hwif->OUTB(clock | (hwif->channel ? 0x08 : 0x02), clock_reg);
+ outb(clock | (hwif->channel ? 0x08 : 0x02), clock_reg);
}
static void pdc_old_disable_66MHz_clock(ide_hwif_t *hwif)
{
unsigned long clock_reg = hwif->dma_master + 0x11;
- u8 clock = hwif->INB(clock_reg);
+ u8 clock = inb(clock_reg);
- hwif->OUTB(clock & ~(hwif->channel ? 0x08 : 0x02), clock_reg);
+ outb(clock & ~(hwif->channel ? 0x08 : 0x02), clock_reg);
}
static int config_chipset_for_dma (ide_drive_t *drive)
@@ -352,32 +322,25 @@ chipset_is_set:
static int pdc202xx_config_drive_xfer_rate (ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
- struct hd_driveid *id = drive->id;
-
drive->init_speed = 0;
- if (id && (id->capability & 1) && drive->autodma) {
-
- if (ide_use_dma(drive)) {
- if (config_chipset_for_dma(drive))
- return hwif->ide_dma_on(drive);
- }
+ if (ide_use_dma(drive) && config_chipset_for_dma(drive))
+ return 0;
- goto fast_ata_pio;
+ if (ide_use_fast_pio(drive))
+ pdc202xx_tune_drive(drive, 255);
- } else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
- hwif->tuneproc(drive, 5);
- return hwif->ide_dma_off_quietly(drive);
- }
- /* IORDY not supported */
- return 0;
+ return -1;
}
static int pdc202xx_quirkproc (ide_drive_t *drive)
{
- return ((int) check_in_drive_lists(drive, pdc_quirk_drives));
+ const char **list, *model = drive->id->model;
+
+ for (list = pdc_quirk_drives; *list != NULL; list++)
+ if (strstr(model, *list) != NULL)
+ return 2;
+ return 0;
}
static void pdc202xx_old_ide_dma_start(ide_drive_t *drive)
@@ -390,14 +353,14 @@ static void pdc202xx_old_ide_dma_start(ide_drive_t *drive)
unsigned long high_16 = hwif->dma_master;
unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x20);
u32 word_count = 0;
- u8 clock = hwif->INB(high_16 + 0x11);
+ u8 clock = inb(high_16 + 0x11);
- hwif->OUTB(clock|(hwif->channel ? 0x08 : 0x02), high_16+0x11);
+ outb(clock | (hwif->channel ? 0x08 : 0x02), high_16 + 0x11);
word_count = (rq->nr_sectors << 8);
word_count = (rq_data_dir(rq) == READ) ?
word_count | 0x05000000 :
word_count | 0x06000000;
- hwif->OUTL(word_count, atapi_reg);
+ outl(word_count, atapi_reg);
}
ide_dma_start(drive);
}
@@ -410,9 +373,9 @@ static int pdc202xx_old_ide_dma_end(ide_drive_t *drive)
unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x20);
u8 clock = 0;
- hwif->OUTL(0, atapi_reg); /* zero out extra */
- clock = hwif->INB(high_16 + 0x11);
- hwif->OUTB(clock & ~(hwif->channel ? 0x08:0x02), high_16+0x11);
+ outl(0, atapi_reg); /* zero out extra */
+ clock = inb(high_16 + 0x11);
+ outb(clock & ~(hwif->channel ? 0x08:0x02), high_16 + 0x11);
}
if (drive->current_speed > XFER_UDMA_2)
pdc_old_disable_66MHz_clock(drive->hwif);
@@ -423,8 +386,8 @@ static int pdc202xx_old_ide_dma_test_irq(ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
unsigned long high_16 = hwif->dma_master;
- u8 dma_stat = hwif->INB(hwif->dma_status);
- u8 sc1d = hwif->INB((high_16 + 0x001d));
+ u8 dma_stat = inb(hwif->dma_status);
+ u8 sc1d = inb(high_16 + 0x001d);
if (hwif->channel) {
/* bit7: Error, bit6: Interrupting, bit5: FIFO Full, bit4: FIFO Empty */
@@ -460,11 +423,11 @@ static int pdc202xx_ide_dma_timeout(ide_drive_t *drive)
static void pdc202xx_reset_host (ide_hwif_t *hwif)
{
unsigned long high_16 = hwif->dma_master;
- u8 udma_speed_flag = hwif->INB(high_16|0x001f);
+ u8 udma_speed_flag = inb(high_16 | 0x001f);
- hwif->OUTB((udma_speed_flag | 0x10), (high_16|0x001f));
+ outb(udma_speed_flag | 0x10, high_16 | 0x001f);
mdelay(100);
- hwif->OUTB((udma_speed_flag & ~0x10), (high_16|0x001f));
+ outb(udma_speed_flag & ~0x10, high_16 | 0x001f);
mdelay(2000); /* 2 seconds ?! */
printk(KERN_WARNING "PDC202XX: %s channel reset.\n",
@@ -478,7 +441,7 @@ static void pdc202xx_reset (ide_drive_t *drive)
pdc202xx_reset_host(hwif);
pdc202xx_reset_host(mate);
- hwif->tuneproc(drive, 5);
+ pdc202xx_tune_drive(drive, 255);
}
static unsigned int __devinit init_chipset_pdc202xx(struct pci_dev *dev,
@@ -505,7 +468,7 @@ static void __devinit init_hwif_pdc202xx(ide_hwif_t *hwif)
hwif->rqsize = 256;
hwif->autodma = 0;
- hwif->tuneproc = &config_chipset_for_pio;
+ hwif->tuneproc = &pdc202xx_tune_drive;
hwif->quirkproc = &pdc202xx_quirkproc;
if (hwif->pci_dev->device != PCI_DEVICE_ID_PROMISE_20246)
@@ -552,9 +515,9 @@ static void __devinit init_dma_pdc202xx(ide_hwif_t *hwif, unsigned long dmabase)
return;
}
- udma_speed_flag = hwif->INB((dmabase|0x1f));
- primary_mode = hwif->INB((dmabase|0x1a));
- secondary_mode = hwif->INB((dmabase|0x1b));
+ udma_speed_flag = inb(dmabase | 0x1f);
+ primary_mode = inb(dmabase | 0x1a);
+ secondary_mode = inb(dmabase | 0x1b);
printk(KERN_INFO "%s: (U)DMA Burst Bit %sABLED " \
"Primary %s Mode " \
"Secondary %s Mode.\n", hwif->cds->name,
@@ -567,30 +530,10 @@ static void __devinit init_dma_pdc202xx(ide_hwif_t *hwif, unsigned long dmabase)
printk(KERN_INFO "%s: FORCING BURST BIT 0x%02x->0x%02x ",
hwif->cds->name, udma_speed_flag,
(udma_speed_flag|1));
- hwif->OUTB(udma_speed_flag|1,(dmabase|0x1f));
- printk("%sACTIVE\n",
- (hwif->INB(dmabase|0x1f)&1) ? "":"IN");
+ outb(udma_speed_flag | 1, dmabase | 0x1f);
+ printk("%sACTIVE\n", (inb(dmabase | 0x1f) & 1) ? "" : "IN");
}
#endif /* CONFIG_PDC202XX_BURST */
-#ifdef CONFIG_PDC202XX_MASTER
- if (!(primary_mode & 1)) {
- printk(KERN_INFO "%s: FORCING PRIMARY MODE BIT "
- "0x%02x -> 0x%02x ", hwif->cds->name,
- primary_mode, (primary_mode|1));
- hwif->OUTB(primary_mode|1, (dmabase|0x1a));
- printk("%s\n",
- (hwif->INB((dmabase|0x1a)) & 1) ? "MASTER" : "PCI");
- }
-
- if (!(secondary_mode & 1)) {
- printk(KERN_INFO "%s: FORCING SECONDARY MODE BIT "
- "0x%02x -> 0x%02x ", hwif->cds->name,
- secondary_mode, (secondary_mode|1));
- hwif->OUTB(secondary_mode|1, (dmabase|0x1b));
- printk("%s\n",
- (hwif->INB((dmabase|0x1b)) & 1) ? "MASTER" : "PCI");
- }
-#endif /* CONFIG_PDC202XX_MASTER */
ide_setup_dma(hwif, dmabase, 8);
}
diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c
index edb37f3d558..569822f4cf5 100644
--- a/drivers/ide/pci/piix.c
+++ b/drivers/ide/pci/piix.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/ide/pci/piix.c Version 0.45 May 12, 2006
+ * linux/drivers/ide/pci/piix.c Version 0.46 December 3, 2006
*
* Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer
* Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
@@ -163,7 +163,7 @@ static u8 piix_ratemask (ide_drive_t *drive)
* if the drive cannot see an 80pin cable.
*/
if (!eighty_ninty_three(drive))
- mode = min(mode, (u8)1);
+ mode = min_t(u8, mode, 1);
return mode;
}
@@ -216,7 +216,7 @@ static void piix_tune_drive (ide_drive_t *drive, u8 pio)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
- int is_slave = (&hwif->drives[1] == drive);
+ int is_slave = drive->dn & 1;
int master_port = hwif->channel ? 0x42 : 0x40;
int slave_port = 0x44;
unsigned long flags;
@@ -225,7 +225,7 @@ static void piix_tune_drive (ide_drive_t *drive, u8 pio)
static DEFINE_SPINLOCK(tune_lock);
int control = 0;
- /* ISP RTC */
+ /* ISP RTC */
static const u8 timings[][2]= {
{ 0, 0 },
{ 0, 0 },
@@ -233,7 +233,7 @@ static void piix_tune_drive (ide_drive_t *drive, u8 pio)
{ 2, 1 },
{ 2, 3 }, };
- pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
+ pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
/*
* Master vs slave is synchronized above us but the slave register is
@@ -243,25 +243,24 @@ static void piix_tune_drive (ide_drive_t *drive, u8 pio)
spin_lock_irqsave(&tune_lock, flags);
pci_read_config_word(dev, master_port, &master_data);
- if (pio >= 2)
+ if (pio > 1)
control |= 1; /* Programmable timing on */
if (drive->media == ide_disk)
control |= 4; /* Prefetch, post write */
- if (pio >= 3)
+ if (pio > 2)
control |= 2; /* IORDY */
if (is_slave) {
- master_data = master_data | 0x4000;
+ master_data |= 0x4000;
+ master_data &= ~0x0070;
if (pio > 1) {
/* enable PPE, IE and TIME */
master_data = master_data | (control << 4);
- } else {
- master_data &= ~0x0070;
}
pci_read_config_byte(dev, slave_port, &slave_data);
slave_data = slave_data & (hwif->channel ? 0x0f : 0xf0);
slave_data = slave_data | (((timings[pio][0] << 2) | timings[pio][1]) << (hwif->channel ? 4 : 0));
} else {
- master_data = master_data & 0xccf8;
+ master_data &= ~0x3307;
if (pio > 1) {
/* enable PPE, IE and TIME */
master_data = master_data | control;
@@ -370,7 +369,7 @@ static int piix_config_drive_for_dma (ide_drive_t *drive)
* If no DMA speed was available or the chipset has DMA bugs
* then disable DMA and use PIO
*/
- if (!speed || no_piix_dma)
+ if (!speed)
return 0;
(void) piix_tune_chipset(drive, speed);
@@ -387,41 +386,28 @@ static int piix_config_drive_for_dma (ide_drive_t *drive)
static int piix_config_drive_xfer_rate (ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
- struct hd_driveid *id = drive->id;
-
drive->init_speed = 0;
- if ((id->capability & 1) && drive->autodma) {
-
- if (ide_use_dma(drive) && piix_config_drive_for_dma(drive))
- return hwif->ide_dma_on(drive);
-
- goto fast_ata_pio;
+ if (ide_use_dma(drive) && piix_config_drive_for_dma(drive))
+ return 0;
- } else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
+ if (ide_use_fast_pio(drive))
/* Find best PIO mode. */
- (void) hwif->speedproc(drive, XFER_PIO_0 +
- ide_get_best_pio_mode(drive, 255, 4, NULL));
- return hwif->ide_dma_off_quietly(drive);
- }
- /* IORDY not supported */
- return 0;
+ piix_tune_chipset(drive, XFER_PIO_0 +
+ ide_get_best_pio_mode(drive, 255, 4, NULL));
+
+ return -1;
}
/**
- * init_chipset_piix - set up the PIIX chipset
- * @dev: PCI device to set up
- * @name: Name of the device
+ * piix_is_ichx - check if ICHx
+ * @dev: PCI device to check
*
- * Initialize the PCI device as required. For the PIIX this turns
- * out to be nice and simple
+ * returns 1 if ICHx, 0 otherwise.
*/
-
-static unsigned int __devinit init_chipset_piix (struct pci_dev *dev, const char *name)
+static int piix_is_ichx(struct pci_dev *dev)
{
- switch(dev->device) {
+ switch (dev->device) {
case PCI_DEVICE_ID_INTEL_82801EB_1:
case PCI_DEVICE_ID_INTEL_82801AA_1:
case PCI_DEVICE_ID_INTEL_82801AB_1:
@@ -439,19 +425,61 @@ static unsigned int __devinit init_chipset_piix (struct pci_dev *dev, const char
case PCI_DEVICE_ID_INTEL_ICH7_21:
case PCI_DEVICE_ID_INTEL_ESB2_18:
case PCI_DEVICE_ID_INTEL_ICH8_6:
- {
- unsigned int extra = 0;
- pci_read_config_dword(dev, 0x54, &extra);
- pci_write_config_dword(dev, 0x54, extra|0x400);
- }
- default:
- break;
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * init_chipset_piix - set up the PIIX chipset
+ * @dev: PCI device to set up
+ * @name: Name of the device
+ *
+ * Initialize the PCI device as required. For the PIIX this turns
+ * out to be nice and simple
+ */
+
+static unsigned int __devinit init_chipset_piix (struct pci_dev *dev, const char *name)
+{
+ if (piix_is_ichx(dev)) {
+ unsigned int extra = 0;
+ pci_read_config_dword(dev, 0x54, &extra);
+ pci_write_config_dword(dev, 0x54, extra|0x400);
}
return 0;
}
/**
+ * piix_dma_clear_irq - clear BMDMA status
+ * @drive: IDE drive to clear
+ *
+ * Called from ide_intr() for PIO interrupts
+ * to clear BMDMA status as needed by ICHx
+ */
+static void piix_dma_clear_irq(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ u8 dma_stat;
+
+ /* clear the INTR & ERROR bits */
+ dma_stat = hwif->INB(hwif->dma_status);
+ /* Should we force the bit as well ? */
+ hwif->OUTB(dma_stat, hwif->dma_status);
+}
+
+static int __devinit piix_cable_detect(ide_hwif_t *hwif)
+{
+ struct pci_dev *dev = hwif->pci_dev;
+ u8 reg54h = 0, mask = hwif->channel ? 0xc0 : 0x30;
+
+ pci_read_config_byte(dev, 0x54, &reg54h);
+
+ return (reg54h & mask) ? 1 : 0;
+}
+
+/**
* init_hwif_piix - fill in the hwif for the PIIX
* @hwif: IDE interface
*
@@ -461,9 +489,6 @@ static unsigned int __devinit init_chipset_piix (struct pci_dev *dev, const char
static void __devinit init_hwif_piix(ide_hwif_t *hwif)
{
- u8 reg54h = 0, reg55h = 0, ata66 = 0;
- u8 mask = hwif->channel ? 0xc0 : 0x30;
-
#ifndef CONFIG_IA64
if (!hwif->irq)
hwif->irq = hwif->channel ? 15 : 14;
@@ -473,10 +498,6 @@ static void __devinit init_hwif_piix(ide_hwif_t *hwif)
/* This is a painful system best to let it self tune for now */
return;
}
- /* ESB2 appears to generate spurious DMA interrupts in PIO mode
- when in native mode */
- if (hwif->pci_dev->device == PCI_DEVICE_ID_INTEL_ESB2_18)
- hwif->atapi_irq_bogon = 1;
hwif->autodma = 0;
hwif->tuneproc = &piix_tune_drive;
@@ -487,15 +508,16 @@ static void __devinit init_hwif_piix(ide_hwif_t *hwif)
if (!hwif->dma_base)
return;
+ /* ICHx need to clear the bmdma status for all interrupts */
+ if (piix_is_ichx(hwif->pci_dev))
+ hwif->ide_dma_clear_irq = &piix_dma_clear_irq;
+
hwif->atapi_dma = 1;
hwif->ultra_mask = 0x3f;
hwif->mwdma_mask = 0x06;
hwif->swdma_mask = 0x04;
switch(hwif->pci_dev->device) {
- case PCI_DEVICE_ID_INTEL_82371MX:
- hwif->mwdma_mask = 0x80;
- hwif->swdma_mask = 0x80;
case PCI_DEVICE_ID_INTEL_82371FB_0:
case PCI_DEVICE_ID_INTEL_82371FB_1:
case PCI_DEVICE_ID_INTEL_82371SB_1:
@@ -508,14 +530,14 @@ static void __devinit init_hwif_piix(ide_hwif_t *hwif)
hwif->ultra_mask = 0x07;
break;
default:
- pci_read_config_byte(hwif->pci_dev, 0x54, &reg54h);
- pci_read_config_byte(hwif->pci_dev, 0x55, &reg55h);
- ata66 = (reg54h & mask) ? 1 : 0;
+ if (!hwif->udma_four)
+ hwif->udma_four = piix_cable_detect(hwif);
break;
}
- if (!(hwif->udma_four))
- hwif->udma_four = ata66;
+ if (no_piix_dma)
+ hwif->ultra_mask = hwif->mwdma_mask = hwif->swdma_mask = 0;
+
hwif->ide_dma_check = &piix_config_drive_xfer_rate;
if (!noautodma)
hwif->autodma = 1;
@@ -539,13 +561,19 @@ static ide_pci_device_t piix_pci_info[] __devinitdata = {
/* 0 */ DECLARE_PIIX_DEV("PIIXa"),
/* 1 */ DECLARE_PIIX_DEV("PIIXb"),
- { /* 2 */
+ /* 2 */
+ { /*
+ * MPIIX actually has only a single IDE channel mapped to
+ * the primary or secondary ports depending on the value
+ * of the bit 14 of the IDETIM register at offset 0x6c
+ */
.name = "MPIIX",
.init_hwif = init_hwif_piix,
.channels = 2,
.autodma = NODMA,
- .enablebits = {{0x6D,0x80,0x80}, {0x6F,0x80,0x80}},
+ .enablebits = {{0x6d,0xc0,0x80}, {0x6d,0xc0,0xc0}},
.bootable = ON_BOARD,
+ .flags = IDEPCI_FLAG_ISA_PORTS
},
/* 3 */ DECLARE_PIIX_DEV("PIIX3"),
diff --git a/drivers/ide/pci/sc1200.c b/drivers/ide/pci/sc1200.c
index 8d762d323f8..b5ae0c50e21 100644
--- a/drivers/ide/pci/sc1200.c
+++ b/drivers/ide/pci/sc1200.c
@@ -161,7 +161,7 @@ static int sc1200_config_dma2 (ide_drive_t *drive, int mode)
/*
* Default to DMA-off in case we run into trouble here.
*/
- hwif->ide_dma_off_quietly(drive); /* turn off DMA while we fiddle */
+ hwif->dma_off_quietly(drive); /* turn off DMA while we fiddle */
outb(inb(hwif->dma_base+2)&~(unit?0x40:0x20), hwif->dma_base+2); /* clear DMA_capable bit */
/*
@@ -241,10 +241,7 @@ static int sc1200_config_dma2 (ide_drive_t *drive, int mode)
outb(inb(hwif->dma_base+2)|(unit?0x40:0x20), hwif->dma_base+2); /* set DMA_capable bit */
- /*
- * Finally, turn DMA on in software, and exit.
- */
- return hwif->ide_dma_on(drive); /* success */
+ return 0; /* success */
}
/*
@@ -442,10 +439,10 @@ static int sc1200_resume (struct pci_dev *dev)
ide_drive_t *drive = &(hwif->drives[d]);
if (drive->present && !__ide_dma_bad_drive(drive)) {
int was_using_dma = drive->using_dma;
- hwif->ide_dma_off_quietly(drive);
+ hwif->dma_off_quietly(drive);
sc1200_config_dma(drive);
if (!was_using_dma && drive->using_dma) {
- hwif->ide_dma_off_quietly(drive);
+ hwif->dma_off_quietly(drive);
}
}
}
diff --git a/drivers/ide/pci/serverworks.c b/drivers/ide/pci/serverworks.c
index ea9a28a4585..dbcd37a0c65 100644
--- a/drivers/ide/pci/serverworks.c
+++ b/drivers/ide/pci/serverworks.c
@@ -160,7 +160,7 @@ static int svwks_tune_chipset (ide_drive_t *drive, u8 xferspeed)
if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
(dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) {
if (!drive->init_speed) {
- u8 dma_stat = hwif->INB(hwif->dma_status);
+ u8 dma_stat = inb(hwif->dma_status);
dma_pio:
if (((ultra_enable << (7-drive->dn) & 0x80) == 0x80) &&
@@ -315,35 +315,15 @@ static int config_chipset_for_dma (ide_drive_t *drive)
static int svwks_config_drive_xfer_rate (ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
- struct hd_driveid *id = drive->id;
-
drive->init_speed = 0;
- if ((id->capability & 1) && drive->autodma) {
-
- if (ide_use_dma(drive)) {
- if (config_chipset_for_dma(drive))
- return hwif->ide_dma_on(drive);
- }
-
- goto fast_ata_pio;
+ if (ide_use_dma(drive) && config_chipset_for_dma(drive))
+ return 0;
- } else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
+ if (ide_use_fast_pio(drive))
config_chipset_for_pio(drive);
- // hwif->tuneproc(drive, 5);
- return hwif->ide_dma_off_quietly(drive);
- }
- /* IORDY not supported */
- return 0;
-}
-
-/* This can go soon */
-static int svwks_ide_dma_end (ide_drive_t *drive)
-{
- return __ide_dma_end(drive);
+ return -1;
}
static unsigned int __devinit init_chipset_svwks (struct pci_dev *dev, const char *name)
@@ -537,35 +517,20 @@ static void __devinit init_hwif_svwks (ide_hwif_t *hwif)
}
hwif->ide_dma_check = &svwks_config_drive_xfer_rate;
- if (hwif->pci_dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE)
- hwif->ide_dma_end = &svwks_ide_dma_end;
- else if (!(hwif->udma_four))
- hwif->udma_four = ata66_svwks(hwif);
+ if (hwif->pci_dev->device != PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) {
+ if (!hwif->udma_four)
+ hwif->udma_four = ata66_svwks(hwif);
+ }
if (!noautodma)
hwif->autodma = 1;
- dma_stat = hwif->INB(hwif->dma_status);
+ dma_stat = inb(hwif->dma_status);
hwif->drives[0].autodma = (dma_stat & 0x20);
hwif->drives[1].autodma = (dma_stat & 0x40);
hwif->drives[0].autotune = (!(dma_stat & 0x20));
hwif->drives[1].autotune = (!(dma_stat & 0x40));
}
-/*
- * We allow the BM-DMA driver to only work on enabled interfaces.
- */
-static void __devinit init_dma_svwks (ide_hwif_t *hwif, unsigned long dmabase)
-{
- struct pci_dev *dev = hwif->pci_dev;
-
- if (((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
- (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) &&
- (!(PCI_FUNC(dev->devfn) & 1)) && (hwif->channel))
- return;
-
- ide_setup_dma(hwif, dmabase, 8);
-}
-
static int __devinit init_setup_svwks (struct pci_dev *dev, ide_pci_device_t *d)
{
return ide_setup_pci_device(dev, d);
@@ -600,7 +565,6 @@ static ide_pci_device_t serverworks_chipsets[] __devinitdata = {
.init_setup = init_setup_svwks,
.init_chipset = init_chipset_svwks,
.init_hwif = init_hwif_svwks,
- .init_dma = init_dma_svwks,
.channels = 2,
.autodma = AUTODMA,
.bootable = ON_BOARD,
@@ -609,7 +573,6 @@ static ide_pci_device_t serverworks_chipsets[] __devinitdata = {
.init_setup = init_setup_csb6,
.init_chipset = init_chipset_svwks,
.init_hwif = init_hwif_svwks,
- .init_dma = init_dma_svwks,
.channels = 2,
.autodma = AUTODMA,
.bootable = ON_BOARD,
@@ -618,7 +581,6 @@ static ide_pci_device_t serverworks_chipsets[] __devinitdata = {
.init_setup = init_setup_csb6,
.init_chipset = init_chipset_svwks,
.init_hwif = init_hwif_svwks,
- .init_dma = init_dma_svwks,
.channels = 1, /* 2 */
.autodma = AUTODMA,
.bootable = ON_BOARD,
@@ -627,7 +589,6 @@ static ide_pci_device_t serverworks_chipsets[] __devinitdata = {
.init_setup = init_setup_svwks,
.init_chipset = init_chipset_svwks,
.init_hwif = init_hwif_svwks,
- .init_dma = init_dma_svwks,
.channels = 1, /* 2 */
.autodma = AUTODMA,
.bootable = ON_BOARD,
diff --git a/drivers/ide/pci/sgiioc4.c b/drivers/ide/pci/sgiioc4.c
index b0bf0180927..fd09b295a69 100644
--- a/drivers/ide/pci/sgiioc4.c
+++ b/drivers/ide/pci/sgiioc4.c
@@ -110,24 +110,24 @@ sgiioc4_init_hwif_ports(hw_regs_t * hw, unsigned long data_port,
static void
sgiioc4_maskproc(ide_drive_t * drive, int mask)
{
- ide_hwif_t *hwif = HWIF(drive);
- hwif->OUTB(mask ? (drive->ctl | 2) : (drive->ctl & ~2),
- IDE_CONTROL_REG);
+ writeb(mask ? (drive->ctl | 2) : (drive->ctl & ~2),
+ (void __iomem *)IDE_CONTROL_REG);
}
static int
sgiioc4_checkirq(ide_hwif_t * hwif)
{
- u8 intr_reg =
- hwif->INL(hwif->io_ports[IDE_IRQ_OFFSET] + IOC4_INTR_REG * 4);
+ unsigned long intr_addr =
+ hwif->io_ports[IDE_IRQ_OFFSET] + IOC4_INTR_REG * 4;
- if (intr_reg & 0x03)
+ if ((u8)readl((void __iomem *)intr_addr) & 0x03)
return 1;
return 0;
}
+static u8 sgiioc4_INB(unsigned long);
static int
sgiioc4_clearirq(ide_drive_t * drive)
@@ -138,21 +138,21 @@ sgiioc4_clearirq(ide_drive_t * drive)
hwif->io_ports[IDE_IRQ_OFFSET] + (IOC4_INTR_REG << 2);
/* Code to check for PCI error conditions */
- intr_reg = hwif->INL(other_ir);
+ intr_reg = readl((void __iomem *)other_ir);
if (intr_reg & 0x03) { /* Valid IOC4-IDE interrupt */
/*
- * Using hwif->INB to read the IDE_STATUS_REG has a side effect
+ * Using sgiioc4_INB to read the IDE_STATUS_REG has a side effect
* of clearing the interrupt. The first read should clear it
* if it is set. The second read should return a "clear" status
* if it got cleared. If not, then spin for a bit trying to
* clear it.
*/
- u8 stat = hwif->INB(IDE_STATUS_REG);
+ u8 stat = sgiioc4_INB(IDE_STATUS_REG);
int count = 0;
- stat = hwif->INB(IDE_STATUS_REG);
+ stat = sgiioc4_INB(IDE_STATUS_REG);
while ((stat & 0x80) && (count++ < 100)) {
udelay(1);
- stat = hwif->INB(IDE_STATUS_REG);
+ stat = sgiioc4_INB(IDE_STATUS_REG);
}
if (intr_reg & 0x02) {
@@ -161,9 +161,9 @@ sgiioc4_clearirq(ide_drive_t * drive)
pci_stat_cmd_reg;
pci_err_addr_low =
- hwif->INL(hwif->io_ports[IDE_IRQ_OFFSET]);
+ readl((void __iomem *)hwif->io_ports[IDE_IRQ_OFFSET]);
pci_err_addr_high =
- hwif->INL(hwif->io_ports[IDE_IRQ_OFFSET] + 4);
+ readl((void __iomem *)(hwif->io_ports[IDE_IRQ_OFFSET] + 4));
pci_read_config_dword(hwif->pci_dev, PCI_COMMAND,
&pci_stat_cmd_reg);
printk(KERN_ERR
@@ -180,9 +180,9 @@ sgiioc4_clearirq(ide_drive_t * drive)
}
/* Clear the Interrupt, Error bits on the IOC4 */
- hwif->OUTL(0x03, other_ir);
+ writel(0x03, (void __iomem *)other_ir);
- intr_reg = hwif->INL(other_ir);
+ intr_reg = readl((void __iomem *)other_ir);
}
return intr_reg & 3;
@@ -191,23 +191,25 @@ sgiioc4_clearirq(ide_drive_t * drive)
static void sgiioc4_ide_dma_start(ide_drive_t * drive)
{
ide_hwif_t *hwif = HWIF(drive);
- unsigned int reg = hwif->INL(hwif->dma_base + IOC4_DMA_CTRL * 4);
+ unsigned long ioc4_dma_addr = hwif->dma_base + IOC4_DMA_CTRL * 4;
+ unsigned int reg = readl((void __iomem *)ioc4_dma_addr);
unsigned int temp_reg = reg | IOC4_S_DMA_START;
- hwif->OUTL(temp_reg, hwif->dma_base + IOC4_DMA_CTRL * 4);
+ writel(temp_reg, (void __iomem *)ioc4_dma_addr);
}
static u32
sgiioc4_ide_dma_stop(ide_hwif_t *hwif, u64 dma_base)
{
+ unsigned long ioc4_dma_addr = dma_base + IOC4_DMA_CTRL * 4;
u32 ioc4_dma;
int count;
count = 0;
- ioc4_dma = hwif->INL(dma_base + IOC4_DMA_CTRL * 4);
+ ioc4_dma = readl((void __iomem *)ioc4_dma_addr);
while ((ioc4_dma & IOC4_S_DMA_STOP) && (count++ < 200)) {
udelay(1);
- ioc4_dma = hwif->INL(dma_base + IOC4_DMA_CTRL * 4);
+ ioc4_dma = readl((void __iomem *)ioc4_dma_addr);
}
return ioc4_dma;
}
@@ -218,11 +220,11 @@ sgiioc4_ide_dma_end(ide_drive_t * drive)
{
u32 ioc4_dma, bc_dev, bc_mem, num, valid = 0, cnt = 0;
ide_hwif_t *hwif = HWIF(drive);
- u64 dma_base = hwif->dma_base;
+ unsigned long dma_base = hwif->dma_base;
int dma_stat = 0;
unsigned long *ending_dma = ide_get_hwifdata(hwif);
- hwif->OUTL(IOC4_S_DMA_STOP, dma_base + IOC4_DMA_CTRL * 4);
+ writel(IOC4_S_DMA_STOP, (void __iomem *)(dma_base + IOC4_DMA_CTRL * 4));
ioc4_dma = sgiioc4_ide_dma_stop(hwif, dma_base);
@@ -254,8 +256,8 @@ sgiioc4_ide_dma_end(ide_drive_t * drive)
dma_stat = 1;
}
- bc_dev = hwif->INL(dma_base + IOC4_BC_DEV * 4);
- bc_mem = hwif->INL(dma_base + IOC4_BC_MEM * 4);
+ bc_dev = readl((void __iomem *)(dma_base + IOC4_BC_DEV * 4));
+ bc_mem = readl((void __iomem *)(dma_base + IOC4_BC_MEM * 4));
if ((bc_dev & 0x01FF) || (bc_mem & 0x1FF)) {
if (bc_dev > bc_mem + 8) {
@@ -273,34 +275,29 @@ sgiioc4_ide_dma_end(ide_drive_t * drive)
}
static int
-sgiioc4_ide_dma_check(ide_drive_t * drive)
+sgiioc4_ide_dma_on(ide_drive_t * drive)
{
- if (ide_config_drive_speed(drive, XFER_MW_DMA_2) != 0) {
- printk(KERN_INFO
- "Couldnot set %s in Multimode-2 DMA mode | "
- "Drive %s using PIO instead\n",
- drive->name, drive->name);
- drive->using_dma = 0;
- } else
- drive->using_dma = 1;
+ drive->using_dma = 1;
return 0;
}
-static int
-sgiioc4_ide_dma_on(ide_drive_t * drive)
+static void sgiioc4_dma_off_quietly(ide_drive_t *drive)
{
- drive->using_dma = 1;
+ drive->using_dma = 0;
- return HWIF(drive)->ide_dma_host_on(drive);
+ drive->hwif->dma_host_off(drive);
}
-static int
-sgiioc4_ide_dma_off_quietly(ide_drive_t * drive)
+static int sgiioc4_ide_dma_check(ide_drive_t *drive)
{
- drive->using_dma = 0;
-
- return HWIF(drive)->ide_dma_host_off(drive);
+ /* FIXME: check for available DMA modes */
+ if (ide_config_drive_speed(drive, XFER_MW_DMA_2) != 0) {
+ printk(KERN_WARNING "%s: couldn't set MWDMA2 mode, "
+ "using PIO instead\n", drive->name);
+ return -1;
+ } else
+ return 0;
}
/* returns 1 if dma irq issued, 0 otherwise */
@@ -310,21 +307,13 @@ sgiioc4_ide_dma_test_irq(ide_drive_t * drive)
return sgiioc4_checkirq(HWIF(drive));
}
-static int
-sgiioc4_ide_dma_host_on(ide_drive_t * drive)
+static void sgiioc4_dma_host_on(ide_drive_t * drive)
{
- if (drive->using_dma)
- return 0;
-
- return 1;
}
-static int
-sgiioc4_ide_dma_host_off(ide_drive_t * drive)
+static void sgiioc4_dma_host_off(ide_drive_t * drive)
{
sgiioc4_clearirq(drive);
-
- return 0;
}
static int
@@ -436,16 +425,17 @@ sgiioc4_configure_for_dma(int dma_direction, ide_drive_t * drive)
{
u32 ioc4_dma;
ide_hwif_t *hwif = HWIF(drive);
- u64 dma_base = hwif->dma_base;
+ unsigned long dma_base = hwif->dma_base;
+ unsigned long ioc4_dma_addr = dma_base + IOC4_DMA_CTRL * 4;
u32 dma_addr, ending_dma_addr;
- ioc4_dma = hwif->INL(dma_base + IOC4_DMA_CTRL * 4);
+ ioc4_dma = readl((void __iomem *)ioc4_dma_addr);
if (ioc4_dma & IOC4_S_DMA_ACTIVE) {
printk(KERN_WARNING
"%s(%s):Warning!! DMA from previous transfer was still active\n",
__FUNCTION__, drive->name);
- hwif->OUTL(IOC4_S_DMA_STOP, dma_base + IOC4_DMA_CTRL * 4);
+ writel(IOC4_S_DMA_STOP, (void __iomem *)ioc4_dma_addr);
ioc4_dma = sgiioc4_ide_dma_stop(hwif, dma_base);
if (ioc4_dma & IOC4_S_DMA_STOP)
@@ -454,13 +444,13 @@ sgiioc4_configure_for_dma(int dma_direction, ide_drive_t * drive)
__FUNCTION__, drive->name);
}
- ioc4_dma = hwif->INL(dma_base + IOC4_DMA_CTRL * 4);
+ ioc4_dma = readl((void __iomem *)ioc4_dma_addr);
if (ioc4_dma & IOC4_S_DMA_ERROR) {
printk(KERN_WARNING
"%s(%s) : Warning!! - DMA Error during Previous"
" transfer | status 0x%x\n",
__FUNCTION__, drive->name, ioc4_dma);
- hwif->OUTL(IOC4_S_DMA_STOP, dma_base + IOC4_DMA_CTRL * 4);
+ writel(IOC4_S_DMA_STOP, (void __iomem *)ioc4_dma_addr);
ioc4_dma = sgiioc4_ide_dma_stop(hwif, dma_base);
if (ioc4_dma & IOC4_S_DMA_STOP)
@@ -471,14 +461,14 @@ sgiioc4_configure_for_dma(int dma_direction, ide_drive_t * drive)
/* Address of the Scatter Gather List */
dma_addr = cpu_to_le32(hwif->dmatable_dma);
- hwif->OUTL(dma_addr, dma_base + IOC4_DMA_PTR_L * 4);
+ writel(dma_addr, (void __iomem *)(dma_base + IOC4_DMA_PTR_L * 4));
/* Address of the Ending DMA */
memset(ide_get_hwifdata(hwif), 0, IOC4_IDE_CACHELINE_SIZE);
ending_dma_addr = cpu_to_le32(hwif->dma_status);
- hwif->OUTL(ending_dma_addr, dma_base + IOC4_DMA_END_ADDR * 4);
+ writel(ending_dma_addr, (void __iomem *)(dma_base + IOC4_DMA_END_ADDR * 4));
- hwif->OUTL(dma_direction, dma_base + IOC4_DMA_CTRL * 4);
+ writel(dma_direction, (void __iomem *)ioc4_dma_addr);
drive->waiting_for_dma = 1;
}
@@ -590,7 +580,7 @@ static int sgiioc4_ide_dma_setup(ide_drive_t *drive)
static void __devinit
ide_init_sgiioc4(ide_hwif_t * hwif)
{
- hwif->mmio = 2;
+ hwif->mmio = 1;
hwif->autodma = 1;
hwif->atapi_dma = 1;
hwif->ultra_mask = 0x0; /* Disable Ultra DMA */
@@ -613,10 +603,10 @@ ide_init_sgiioc4(ide_hwif_t * hwif)
hwif->ide_dma_end = &sgiioc4_ide_dma_end;
hwif->ide_dma_check = &sgiioc4_ide_dma_check;
hwif->ide_dma_on = &sgiioc4_ide_dma_on;
- hwif->ide_dma_off_quietly = &sgiioc4_ide_dma_off_quietly;
+ hwif->dma_off_quietly = &sgiioc4_dma_off_quietly;
hwif->ide_dma_test_irq = &sgiioc4_ide_dma_test_irq;
- hwif->ide_dma_host_on = &sgiioc4_ide_dma_host_on;
- hwif->ide_dma_host_off = &sgiioc4_ide_dma_host_off;
+ hwif->dma_host_on = &sgiioc4_dma_host_on;
+ hwif->dma_host_off = &sgiioc4_dma_host_off;
hwif->ide_dma_lostirq = &sgiioc4_ide_dma_lostirq;
hwif->ide_dma_timeout = &__ide_dma_timeout;
@@ -688,7 +678,7 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev, ide_pci_device_t * d)
default_hwif_mmiops(hwif);
/* Initializing chipset IRQ Registers */
- hwif->OUTL(0x03, irqport + IOC4_INTR_SET * 4);
+ writel(0x03, (void __iomem *)(irqport + IOC4_INTR_SET * 4));
ide_init_sgiioc4(hwif);
@@ -729,8 +719,7 @@ out:
return ret;
}
-static ide_pci_device_t sgiioc4_chipsets[] __devinitdata = {
- {
+static ide_pci_device_t sgiioc4_chipset __devinitdata = {
/* Channel 0 */
.name = "SGIIOC4",
.init_hwif = ide_init_sgiioc4,
@@ -739,7 +728,6 @@ static ide_pci_device_t sgiioc4_chipsets[] __devinitdata = {
.autodma = AUTODMA,
/* SGI IOC4 doesn't have enablebits. */
.bootable = ON_BOARD,
- }
};
int
@@ -751,8 +739,7 @@ ioc4_ide_attach_one(struct ioc4_driver_data *idd)
if (idd->idd_variant == IOC4_VARIANT_PCI_RT)
return 0;
- return pci_init_sgiioc4(idd->idd_pdev,
- &sgiioc4_chipsets[idd->idd_pci_id->driver_data]);
+ return pci_init_sgiioc4(idd->idd_pdev, &sgiioc4_chipset);
}
static struct ioc4_submodule ioc4_ide_submodule = {
diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c
index 4ff89c7d990..7b4c189a9d9 100644
--- a/drivers/ide/pci/siimage.c
+++ b/drivers/ide/pci/siimage.c
@@ -1,8 +1,9 @@
/*
- * linux/drivers/ide/pci/siimage.c Version 1.07 Nov 30, 2003
+ * linux/drivers/ide/pci/siimage.c Version 1.11 Jan 27, 2007
*
* Copyright (C) 2001-2002 Andre Hedrick <andre@linux-ide.org>
* Copyright (C) 2003 Red Hat <alan@redhat.com>
+ * Copyright (C) 2007 MontaVista Software, Inc.
*
* May be copied or modified under the terms of the GNU General Public License
*
@@ -205,41 +206,39 @@ static void siimage_tuneproc (ide_drive_t *drive, byte mode_wanted)
unsigned long tfaddr = siimage_selreg(hwif, 0x02);
/* cheat for now and use the docs */
- switch(mode_wanted) {
- case 4:
- speedp = 0x10c1;
- speedt = 0x10c1;
- break;
- case 3:
- speedp = 0x10C3;
- speedt = 0x10C3;
- break;
- case 2:
- speedp = 0x1104;
- speedt = 0x1281;
- break;
- case 1:
- speedp = 0x2283;
- speedt = 0x1281;
- break;
- case 0:
- default:
- speedp = 0x328A;
- speedt = 0x328A;
- break;
+ switch (mode_wanted) {
+ case 4:
+ speedp = 0x10c1;
+ speedt = 0x10c1;
+ break;
+ case 3:
+ speedp = 0x10c3;
+ speedt = 0x10c3;
+ break;
+ case 2:
+ speedp = 0x1104;
+ speedt = 0x1281;
+ break;
+ case 1:
+ speedp = 0x2283;
+ speedt = 0x2283;
+ break;
+ case 0:
+ default:
+ speedp = 0x328a;
+ speedt = 0x328a;
+ break;
}
- if (hwif->mmio)
- {
- hwif->OUTW(speedt, addr);
- hwif->OUTW(speedp, tfaddr);
+
+ if (hwif->mmio) {
+ hwif->OUTW(speedp, addr);
+ hwif->OUTW(speedt, tfaddr);
/* Now set up IORDY */
if(mode_wanted == 3 || mode_wanted == 4)
hwif->OUTW(hwif->INW(tfaddr-2)|0x200, tfaddr-2);
else
hwif->OUTW(hwif->INW(tfaddr-2)&~0x200, tfaddr-2);
- }
- else
- {
+ } else {
pci_write_config_word(hwif->pci_dev, addr, speedp);
pci_write_config_word(hwif->pci_dev, tfaddr, speedt);
pci_read_config_word(hwif->pci_dev, tfaddr-2, &speedp);
@@ -397,12 +396,9 @@ static int config_chipset_for_dma (ide_drive_t *drive)
if (!speed)
return 0;
- if (ide_set_xfer_rate(drive, speed))
+ if (siimage_tune_chipset(drive, speed))
return 0;
- if (!drive->init_speed)
- drive->init_speed = speed;
-
return ide_dma_enable(drive);
}
@@ -418,25 +414,13 @@ static int config_chipset_for_dma (ide_drive_t *drive)
static int siimage_config_drive_for_dma (ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
- struct hd_driveid *id = drive->id;
-
- if ((id->capability & 1) != 0 && drive->autodma) {
-
- if (ide_use_dma(drive)) {
- if (config_chipset_for_dma(drive))
- return hwif->ide_dma_on(drive);
- }
-
- goto fast_ata_pio;
+ if (ide_use_dma(drive) && config_chipset_for_dma(drive))
+ return 0;
- } else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
+ if (ide_use_fast_pio(drive))
config_chipset_for_pio(drive, 1);
- return hwif->ide_dma_off_quietly(drive);
- }
- /* IORDY not supported */
- return 0;
+
+ return -1;
}
/* returns 1 if dma irq issued, 0 otherwise */
@@ -472,11 +456,11 @@ static int siimage_mmio_ide_dma_test_irq (ide_drive_t *drive)
unsigned long addr = siimage_selreg(hwif, 0x1);
if (SATA_ERROR_REG) {
- u32 ext_stat = hwif->INL(base + 0x10);
+ u32 ext_stat = readl((void __iomem *)(base + 0x10));
u8 watchdog = 0;
if (ext_stat & ((hwif->channel) ? 0x40 : 0x10)) {
- u32 sata_error = hwif->INL(SATA_ERROR_REG);
- hwif->OUTL(sata_error, SATA_ERROR_REG);
+ u32 sata_error = readl((void __iomem *)SATA_ERROR_REG);
+ writel(sata_error, (void __iomem *)SATA_ERROR_REG);
watchdog = (sata_error & 0x00680000) ? 1 : 0;
printk(KERN_WARNING "%s: sata_error = 0x%08x, "
"watchdog = %d, %s\n",
@@ -493,11 +477,11 @@ static int siimage_mmio_ide_dma_test_irq (ide_drive_t *drive)
}
/* return 1 if INTR asserted */
- if ((hwif->INB(hwif->dma_status) & 0x04) == 0x04)
+ if ((readb((void __iomem *)hwif->dma_status) & 0x04) == 0x04)
return 1;
/* return 1 if Device INTR asserted */
- if ((hwif->INB(addr) & 8) == 8)
+ if ((readb((void __iomem *)addr) & 8) == 8)
return 0; //return 1;
return 0;
@@ -519,9 +503,9 @@ static int siimage_busproc (ide_drive_t * drive, int state)
u32 stat_config = 0;
unsigned long addr = siimage_selreg(hwif, 0);
- if (hwif->mmio) {
- stat_config = hwif->INL(addr);
- } else
+ if (hwif->mmio)
+ stat_config = readl((void __iomem *)addr);
+ else
pci_read_config_dword(hwif->pci_dev, addr, &stat_config);
switch (state) {
@@ -557,9 +541,10 @@ static int siimage_reset_poll (ide_drive_t *drive)
if (SATA_STATUS_REG) {
ide_hwif_t *hwif = HWIF(drive);
- if ((hwif->INL(SATA_STATUS_REG) & 0x03) != 0x03) {
+ /* SATA_STATUS_REG is valid only when in MMIO mode */
+ if ((readl((void __iomem *)SATA_STATUS_REG) & 0x03) != 0x03) {
printk(KERN_WARNING "%s: reset phy dead, status=0x%08x\n",
- hwif->name, hwif->INL(SATA_STATUS_REG));
+ hwif->name, readl((void __iomem *)SATA_STATUS_REG));
HWGROUP(drive)->polling = 0;
return ide_started;
}
@@ -619,7 +604,8 @@ static void siimage_reset (ide_drive_t *drive)
}
if (SATA_STATUS_REG) {
- u32 sata_stat = hwif->INL(SATA_STATUS_REG);
+ /* SATA_STATUS_REG is valid only when in MMIO mode */
+ u32 sata_stat = readl((void __iomem *)SATA_STATUS_REG);
printk(KERN_WARNING "%s: reset phy, status=0x%08x, %s\n",
hwif->name, sata_stat, __FUNCTION__);
if (!(sata_stat)) {
@@ -898,7 +884,8 @@ static void __devinit init_mmio_iops_siimage(ide_hwif_t *hwif)
base = (unsigned long) addr;
hwif->dma_base = base + (ch ? 0x08 : 0x00);
- hwif->mmio = 2;
+
+ hwif->mmio = 1;
}
static int is_dev_seagate_sata(ide_drive_t *drive)
diff --git a/drivers/ide/pci/sis5513.c b/drivers/ide/pci/sis5513.c
index 1afff659ab5..2ba0669f36a 100644
--- a/drivers/ide/pci/sis5513.c
+++ b/drivers/ide/pci/sis5513.c
@@ -667,67 +667,20 @@ static int config_chipset_for_dma (ide_drive_t *drive)
return ide_dma_enable(drive);
}
-static int sis5513_config_drive_xfer_rate (ide_drive_t *drive)
+static int sis5513_config_xfer_rate(ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
- struct hd_driveid *id = drive->id;
+ config_art_rwp_pio(drive, 5);
drive->init_speed = 0;
- if (id && (id->capability & 1) && drive->autodma) {
-
- if (ide_use_dma(drive)) {
- if (config_chipset_for_dma(drive))
- return hwif->ide_dma_on(drive);
- }
-
- goto fast_ata_pio;
+ if (ide_use_dma(drive) && config_chipset_for_dma(drive))
+ return 0;
- } else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
+ if (ide_use_fast_pio(drive))
sis5513_tune_drive(drive, 5);
- return hwif->ide_dma_off_quietly(drive);
- }
- /* IORDY not supported */
- return 0;
-}
-
-/* initiates/aborts (U)DMA read/write operations on a drive. */
-static int sis5513_config_xfer_rate (ide_drive_t *drive)
-{
- config_drive_art_rwp(drive);
- config_art_rwp_pio(drive, 5);
- return sis5513_config_drive_xfer_rate(drive);
-}
-
-/*
- Future simpler config_xfer_rate :
- When ide_find_best_mode is made bad-drive aware
- - remove config_drive_xfer_rate and config_chipset_for_dma,
- - replace config_xfer_rate with the following
-
-static int sis5513_config_xfer_rate (ide_drive_t *drive)
-{
- u16 w80 = HWIF(drive)->udma_four;
- u16 speed;
-
- config_drive_art_rwp(drive);
- config_art_rwp_pio(drive, 5);
-
- speed = ide_find_best_mode(drive,
- XFER_PIO | XFER_EPIO | XFER_SWDMA | XFER_MWDMA |
- (chipset_family >= ATA_33 ? XFER_UDMA : 0) |
- (w80 && chipset_family >= ATA_66 ? XFER_UDMA_66 : 0) |
- (w80 && chipset_family >= ATA_100a ? XFER_UDMA_100 : 0) |
- (w80 && chipset_family >= ATA_133a ? XFER_UDMA_133 : 0));
-
- sis5513_tune_chipset(drive, speed);
- if (drive->autodma && (speed & XFER_MODE) != XFER_PIO)
- return HWIF(drive)->ide_dma_on(drive);
- return HWIF(drive)->ide_dma_off_quietly(drive);
+ return -1;
}
-*/
/* Chip detection and general config */
static unsigned int __devinit init_chipset_sis5513 (struct pci_dev *dev, const char *name)
diff --git a/drivers/ide/pci/sl82c105.c b/drivers/ide/pci/sl82c105.c
index 170a2619905..3a8a76fc78c 100644
--- a/drivers/ide/pci/sl82c105.c
+++ b/drivers/ide/pci/sl82c105.c
@@ -161,14 +161,14 @@ static int sl82c105_check_drive (ide_drive_t *drive)
if (id->field_valid & 2) {
if ((id->dma_mword & hwif->mwdma_mask) ||
(id->dma_1word & hwif->swdma_mask))
- return hwif->ide_dma_on(drive);
+ return 0;
}
- if (__ide_dma_good_drive(drive))
- return hwif->ide_dma_on(drive);
+ if (__ide_dma_good_drive(drive) && id->eide_dma_time < 150)
+ return 0;
} while (0);
- return hwif->ide_dma_off_quietly(drive);
+ return -1;
}
/*
@@ -215,7 +215,7 @@ static int sl82c105_ide_dma_lost_irq(ide_drive_t *drive)
* Was DMA enabled? If so, disable it - we're resetting the
* host. The IDE layer will be handling the drive for us.
*/
- val = hwif->INB(dma_base);
+ val = inb(dma_base);
if (val & 1) {
outb(val & ~1, dma_base);
printk("sl82c105: DMA was enabled\n");
@@ -259,28 +259,22 @@ static int sl82c105_ide_dma_on (ide_drive_t *drive)
{
DBG(("sl82c105_ide_dma_on(drive:%s)\n", drive->name));
- if (config_for_dma(drive)) {
- config_for_pio(drive, 4, 0, 0);
- return HWIF(drive)->ide_dma_off_quietly(drive);
- }
+ if (config_for_dma(drive))
+ return 1;
printk(KERN_INFO "%s: DMA enabled\n", drive->name);
return __ide_dma_on(drive);
}
-static int sl82c105_ide_dma_off_quietly (ide_drive_t *drive)
+static void sl82c105_dma_off_quietly(ide_drive_t *drive)
{
u8 speed = XFER_PIO_0;
- int rc;
-
- DBG(("sl82c105_ide_dma_off_quietly(drive:%s)\n", drive->name));
- rc = __ide_dma_off_quietly(drive);
+ DBG(("sl82c105_dma_off_quietly(drive:%s)\n", drive->name));
+
+ ide_dma_off_quietly(drive);
if (drive->pio_speed)
speed = drive->pio_speed - XFER_PIO_0;
config_for_pio(drive, speed, 0, 1);
- drive->current_speed = drive->pio_speed;
-
- return rc;
}
/*
@@ -401,11 +395,9 @@ static unsigned int __devinit init_chipset_sl82c105(struct pci_dev *dev, const c
/*
* Initialise the chip
*/
-
static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif)
{
unsigned int rev;
- u8 dma_state;
DBG(("init_hwif_sl82c105(hwif: ide%d)\n", hwif->index));
@@ -431,7 +423,6 @@ static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif)
if (!hwif->dma_base)
return;
- dma_state = hwif->INB(hwif->dma_base + 2) & ~0x60;
rev = sl82c105_bridge_revision(hwif->pci_dev);
if (rev <= 5) {
/*
@@ -441,15 +432,12 @@ static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif)
printk(" %s: Winbond 553 bridge revision %d, BM-DMA disabled\n",
hwif->name, rev);
} else {
- dma_state |= 0x60;
-
hwif->atapi_dma = 1;
- hwif->mwdma_mask = 0x07;
- hwif->swdma_mask = 0x07;
+ hwif->mwdma_mask = 0x04;
hwif->ide_dma_check = &sl82c105_check_drive;
hwif->ide_dma_on = &sl82c105_ide_dma_on;
- hwif->ide_dma_off_quietly = &sl82c105_ide_dma_off_quietly;
+ hwif->dma_off_quietly = &sl82c105_dma_off_quietly;
hwif->ide_dma_lostirq = &sl82c105_ide_dma_lost_irq;
hwif->dma_start = &sl82c105_ide_dma_start;
hwif->ide_dma_timeout = &sl82c105_ide_dma_timeout;
@@ -462,7 +450,6 @@ static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif)
if (hwif->mate)
hwif->serialized = hwif->mate->serialized = 1;
}
- hwif->OUTB(dma_state, hwif->dma_base + 2);
}
static ide_pci_device_t sl82c105_chipset __devinitdata = {
diff --git a/drivers/ide/pci/slc90e66.c b/drivers/ide/pci/slc90e66.c
index 90e79c0844d..ae7eb58d961 100644
--- a/drivers/ide/pci/slc90e66.c
+++ b/drivers/ide/pci/slc90e66.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/ide/pci/slc90e66.c Version 0.12 May 12, 2006
+ * linux/drivers/ide/pci/slc90e66.c Version 0.13 December 30, 2006
*
* Copyright (C) 2000-2002 Andre Hedrick <andre@linux-ide.org>
* Copyright (C) 2006 MontaVista Software, Inc. <source@mvista.com>
@@ -26,7 +26,7 @@ static u8 slc90e66_ratemask (ide_drive_t *drive)
u8 mode = 2;
if (!eighty_ninty_three(drive))
- mode = min(mode, (u8)1);
+ mode = min_t(u8, mode, 1);
return mode;
}
@@ -65,36 +65,47 @@ static void slc90e66_tune_drive (ide_drive_t *drive, u8 pio)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
- int is_slave = (&hwif->drives[1] == drive);
+ int is_slave = drive->dn & 1;
int master_port = hwif->channel ? 0x42 : 0x40;
int slave_port = 0x44;
unsigned long flags;
u16 master_data;
u8 slave_data;
- /* ISP RTC */
+ int control = 0;
+ /* ISP RTC */
static const u8 timings[][2]= {
- { 0, 0 },
- { 0, 0 },
- { 1, 0 },
- { 2, 1 },
- { 2, 3 }, };
+ { 0, 0 },
+ { 0, 0 },
+ { 1, 0 },
+ { 2, 1 },
+ { 2, 3 }, };
- pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
+ pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
spin_lock_irqsave(&ide_lock, flags);
pci_read_config_word(dev, master_port, &master_data);
+
+ if (pio > 1)
+ control |= 1; /* Programmable timing on */
+ if (drive->media == ide_disk)
+ control |= 4; /* Prefetch, post write */
+ if (pio > 2)
+ control |= 2; /* IORDY */
if (is_slave) {
- master_data = master_data | 0x4000;
- if (pio > 1)
+ master_data |= 0x4000;
+ master_data &= ~0x0070;
+ if (pio > 1) {
/* enable PPE, IE and TIME */
- master_data = master_data | 0x0070;
+ master_data = master_data | (control << 4);
+ }
pci_read_config_byte(dev, slave_port, &slave_data);
slave_data = slave_data & (hwif->channel ? 0x0f : 0xf0);
slave_data = slave_data | (((timings[pio][0] << 2) | timings[pio][1]) << (hwif->channel ? 4 : 0));
} else {
- master_data = master_data & 0xccf8;
- if (pio > 1)
+ master_data &= ~0x3307;
+ if (pio > 1) {
/* enable PPE, IE and TIME */
- master_data = master_data | 0x0007;
+ master_data = master_data | control;
+ }
master_data = master_data | (timings[pio][0] << 12) | (timings[pio][1] << 8);
}
pci_write_config_word(dev, master_port, master_data);
@@ -168,26 +179,16 @@ static int slc90e66_config_drive_for_dma (ide_drive_t *drive)
static int slc90e66_config_drive_xfer_rate (ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
- struct hd_driveid *id = drive->id;
-
drive->init_speed = 0;
- if (id && (id->capability & 1) && drive->autodma) {
-
- if (ide_use_dma(drive) && slc90e66_config_drive_for_dma(drive))
- return hwif->ide_dma_on(drive);
+ if (ide_use_dma(drive) && slc90e66_config_drive_for_dma(drive))
+ return 0;
- goto fast_ata_pio;
+ if (ide_use_fast_pio(drive))
+ (void)slc90e66_tune_chipset(drive, XFER_PIO_0 +
+ ide_get_best_pio_mode(drive, 255, 4, NULL));
- } else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
- (void) hwif->speedproc(drive, XFER_PIO_0 +
- ide_get_best_pio_mode(drive, 255, 4, NULL));
- return hwif->ide_dma_off_quietly(drive);
- }
- /* IORDY not supported */
- return 0;
+ return -1;
}
static void __devinit init_hwif_slc90e66 (ide_hwif_t *hwif)
@@ -201,7 +202,7 @@ static void __devinit init_hwif_slc90e66 (ide_hwif_t *hwif)
hwif->irq = hwif->channel ? 15 : 14;
hwif->speedproc = &slc90e66_tune_chipset;
- hwif->tuneproc = &slc90e66_tune_drive;
+ hwif->tuneproc = &slc90e66_tune_drive;
pci_read_config_byte(hwif->pci_dev, 0x47, &reg47);
@@ -213,14 +214,16 @@ static void __devinit init_hwif_slc90e66 (ide_hwif_t *hwif)
hwif->atapi_dma = 1;
hwif->ultra_mask = 0x1f;
- hwif->mwdma_mask = 0x07;
- hwif->swdma_mask = 0x07;
+ hwif->mwdma_mask = 0x06;
+ hwif->swdma_mask = 0x04;
- if (!(hwif->udma_four))
+ if (!hwif->udma_four) {
/* bit[0(1)]: 0:80, 1:40 */
hwif->udma_four = (reg47 & mask) ? 0 : 1;
+ }
hwif->ide_dma_check = &slc90e66_config_drive_xfer_rate;
+
if (!noautodma)
hwif->autodma = 1;
hwif->drives[0].autodma = hwif->autodma;
diff --git a/drivers/ide/pci/tc86c001.c b/drivers/ide/pci/tc86c001.c
new file mode 100644
index 00000000000..0b6d81d6ce4
--- /dev/null
+++ b/drivers/ide/pci/tc86c001.c
@@ -0,0 +1,299 @@
+/*
+ * drivers/ide/pci/tc86c001.c Version 1.00 Dec 12, 2006
+ *
+ * Copyright (C) 2002 Toshiba Corporation
+ * Copyright (C) 2005-2006 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/types.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+static inline u8 tc86c001_ratemask(ide_drive_t *drive)
+{
+ return eighty_ninty_three(drive) ? 2 : 1;
+}
+
+static int tc86c001_tune_chipset(ide_drive_t *drive, u8 speed)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ unsigned long scr_port = hwif->config_data + (drive->dn ? 0x02 : 0x00);
+ u16 mode, scr = hwif->INW(scr_port);
+
+ speed = ide_rate_filter(tc86c001_ratemask(drive), speed);
+
+ switch (speed) {
+ case XFER_UDMA_4: mode = 0x00c0; break;
+ case XFER_UDMA_3: mode = 0x00b0; break;
+ case XFER_UDMA_2: mode = 0x00a0; break;
+ case XFER_UDMA_1: mode = 0x0090; break;
+ case XFER_UDMA_0: mode = 0x0080; break;
+ case XFER_MW_DMA_2: mode = 0x0070; break;
+ case XFER_MW_DMA_1: mode = 0x0060; break;
+ case XFER_MW_DMA_0: mode = 0x0050; break;
+ case XFER_PIO_4: mode = 0x0400; break;
+ case XFER_PIO_3: mode = 0x0300; break;
+ case XFER_PIO_2: mode = 0x0200; break;
+ case XFER_PIO_1: mode = 0x0100; break;
+ case XFER_PIO_0:
+ default: mode = 0x0000; break;
+ }
+
+ scr &= (speed < XFER_MW_DMA_0) ? 0xf8ff : 0xff0f;
+ scr |= mode;
+ outw(scr, scr_port);
+
+ return ide_config_drive_speed(drive, speed);
+}
+
+static void tc86c001_tune_drive(ide_drive_t *drive, u8 pio)
+{
+ pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+ (void) tc86c001_tune_chipset(drive, XFER_PIO_0 + pio);
+}
+
+/*
+ * HACKITY HACK
+ *
+ * This is a workaround for the limitation 5 of the TC86C001 IDE controller:
+ * if a DMA transfer terminates prematurely, the controller leaves the device's
+ * interrupt request (INTRQ) pending and does not generate a PCI interrupt (or
+ * set the interrupt bit in the DMA status register), thus no PCI interrupt
+ * will occur until a DMA transfer has been successfully completed.
+ *
+ * We work around this by initiating dummy, zero-length DMA transfer on
+ * a DMA timeout expiration. I found no better way to do this with the current
+ * IDE core than to temporarily replace a higher level driver's timer expiry
+ * handler with our own backing up to that handler in case our recovery fails.
+ */
+static int tc86c001_timer_expiry(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ ide_expiry_t *expiry = ide_get_hwifdata(hwif);
+ ide_hwgroup_t *hwgroup = HWGROUP(drive);
+ u8 dma_stat = hwif->INB(hwif->dma_status);
+
+ /* Restore a higher level driver's expiry handler first. */
+ hwgroup->expiry = expiry;
+
+ if ((dma_stat & 5) == 1) { /* DMA active and no interrupt */
+ unsigned long sc_base = hwif->config_data;
+ unsigned long twcr_port = sc_base + (drive->dn ? 0x06 : 0x04);
+ u8 dma_cmd = hwif->INB(hwif->dma_command);
+
+ printk(KERN_WARNING "%s: DMA interrupt possibly stuck, "
+ "attempting recovery...\n", drive->name);
+
+ /* Stop DMA */
+ outb(dma_cmd & ~0x01, hwif->dma_command);
+
+ /* Setup the dummy DMA transfer */
+ outw(0, sc_base + 0x0a); /* Sector Count */
+ outw(0, twcr_port); /* Transfer Word Count 1 or 2 */
+
+ /* Start the dummy DMA transfer */
+ outb(0x00, hwif->dma_command); /* clear R_OR_WCTR for write */
+ outb(0x01, hwif->dma_command); /* set START_STOPBM */
+
+ /*
+ * If an interrupt was pending, it should come thru shortly.
+ * If not, a higher level driver's expiry handler should
+ * eventually cause some kind of recovery from the DMA stall.
+ */
+ return WAIT_MIN_SLEEP;
+ }
+
+ /* Chain to the restored expiry handler if DMA wasn't active. */
+ if (likely(expiry != NULL))
+ return expiry(drive);
+
+ /* If there was no handler, "emulate" that for ide_timer_expiry()... */
+ return -1;
+}
+
+static void tc86c001_dma_start(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ ide_hwgroup_t *hwgroup = HWGROUP(drive);
+ unsigned long sc_base = hwif->config_data;
+ unsigned long twcr_port = sc_base + (drive->dn ? 0x06 : 0x04);
+ unsigned long nsectors = hwgroup->rq->nr_sectors;
+
+ /*
+ * We have to manually load the sector count and size into
+ * the appropriate system control registers for DMA to work
+ * with LBA48 and ATAPI devices...
+ */
+ outw(nsectors, sc_base + 0x0a); /* Sector Count */
+ outw(SECTOR_SIZE / 2, twcr_port); /* Transfer Word Count 1/2 */
+
+ /* Install our timeout expiry hook, saving the current handler... */
+ ide_set_hwifdata(hwif, hwgroup->expiry);
+ hwgroup->expiry = &tc86c001_timer_expiry;
+
+ ide_dma_start(drive);
+}
+
+static int tc86c001_busproc(ide_drive_t *drive, int state)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ unsigned long sc_base = hwif->config_data;
+ u16 scr1;
+
+ /* System Control 1 Register bit 11 (ATA Hard Reset) read */
+ scr1 = hwif->INW(sc_base + 0x00);
+
+ switch (state) {
+ case BUSSTATE_ON:
+ if (!(scr1 & 0x0800))
+ return 0;
+ scr1 &= ~0x0800;
+
+ hwif->drives[0].failures = hwif->drives[1].failures = 0;
+ break;
+ case BUSSTATE_OFF:
+ if (scr1 & 0x0800)
+ return 0;
+ scr1 |= 0x0800;
+
+ hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
+ hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* System Control 1 Register bit 11 (ATA Hard Reset) write */
+ outw(scr1, sc_base + 0x00);
+ return 0;
+}
+
+static int config_chipset_for_dma(ide_drive_t *drive)
+{
+ u8 speed = ide_dma_speed(drive, tc86c001_ratemask(drive));
+
+ if (!speed)
+ return 0;
+
+ (void) tc86c001_tune_chipset(drive, speed);
+ return ide_dma_enable(drive);
+}
+
+static int tc86c001_config_drive_xfer_rate(ide_drive_t *drive)
+{
+ if (ide_use_dma(drive) && config_chipset_for_dma(drive))
+ return 0;
+
+ if (ide_use_fast_pio(drive))
+ tc86c001_tune_drive(drive, 255);
+
+ return -1;
+}
+
+static void __devinit init_hwif_tc86c001(ide_hwif_t *hwif)
+{
+ unsigned long sc_base = pci_resource_start(hwif->pci_dev, 5);
+ u16 scr1 = hwif->INW(sc_base + 0x00);;
+
+ /* System Control 1 Register bit 15 (Soft Reset) set */
+ outw(scr1 | 0x8000, sc_base + 0x00);
+
+ /* System Control 1 Register bit 14 (FIFO Reset) set */
+ outw(scr1 | 0x4000, sc_base + 0x00);
+
+ /* System Control 1 Register: reset clear */
+ outw(scr1 & ~0xc000, sc_base + 0x00);
+
+ /* Store the system control register base for convenience... */
+ hwif->config_data = sc_base;
+
+ hwif->tuneproc = &tc86c001_tune_drive;
+ hwif->speedproc = &tc86c001_tune_chipset;
+ hwif->busproc = &tc86c001_busproc;
+
+ hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
+
+ if (!hwif->dma_base)
+ return;
+
+ /*
+ * Sector Count Control Register bits 0 and 1 set:
+ * software sets Sector Count Register for master and slave device
+ */
+ outw(0x0003, sc_base + 0x0c);
+
+ /* Sector Count Register limit */
+ hwif->rqsize = 0xffff;
+
+ hwif->atapi_dma = 1;
+ hwif->ultra_mask = 0x1f;
+ hwif->mwdma_mask = 0x07;
+
+ hwif->ide_dma_check = &tc86c001_config_drive_xfer_rate;
+ hwif->dma_start = &tc86c001_dma_start;
+
+ if (!hwif->udma_four) {
+ /*
+ * System Control 1 Register bit 13 (PDIAGN):
+ * 0=80-pin cable, 1=40-pin cable
+ */
+ scr1 = hwif->INW(sc_base + 0x00);
+ hwif->udma_four = (scr1 & 0x2000) ? 0 : 1;
+ }
+
+ if (!noautodma)
+ hwif->autodma = 1;
+ hwif->drives[0].autodma = hwif->drives[1].autodma = hwif->autodma;
+}
+
+static unsigned int __devinit init_chipset_tc86c001(struct pci_dev *dev,
+ const char *name)
+{
+ int err = pci_request_region(dev, 5, name);
+
+ if (err)
+ printk(KERN_ERR "%s: system control regs already in use", name);
+ return err;
+}
+
+static ide_pci_device_t tc86c001_chipset __devinitdata = {
+ .name = "TC86C001",
+ .init_chipset = init_chipset_tc86c001,
+ .init_hwif = init_hwif_tc86c001,
+ .channels = 1,
+ .autodma = AUTODMA,
+ .bootable = OFF_BOARD
+};
+
+static int __devinit tc86c001_init_one(struct pci_dev *dev,
+ const struct pci_device_id *id)
+{
+ return ide_setup_pci_device(dev, &tc86c001_chipset);
+}
+
+static struct pci_device_id tc86c001_pci_tbl[] = {
+ { PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC86C001_IDE,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { 0, }
+};
+MODULE_DEVICE_TABLE(pci, tc86c001_pci_tbl);
+
+static struct pci_driver driver = {
+ .name = "TC86C001",
+ .id_table = tc86c001_pci_tbl,
+ .probe = tc86c001_init_one
+};
+
+static int __init tc86c001_ide_init(void)
+{
+ return ide_pci_register_driver(&driver);
+}
+module_init(tc86c001_ide_init);
+
+MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>");
+MODULE_DESCRIPTION("PCI driver module for TC86C001 IDE");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/pci/triflex.c b/drivers/ide/pci/triflex.c
index b13cce1fd1a..5e06179c346 100644
--- a/drivers/ide/pci/triflex.c
+++ b/drivers/ide/pci/triflex.c
@@ -104,29 +104,21 @@ static int triflex_config_drive_for_dma(ide_drive_t *drive)
{
int speed = ide_dma_speed(drive, 0); /* No ultra speeds */
- if (!speed) {
- u8 pspeed = ide_get_best_pio_mode(drive, 255, 4, NULL);
- speed = XFER_PIO_0 + pspeed;
- }
-
+ if (!speed)
+ return 0;
+
(void) triflex_tune_chipset(drive, speed);
return ide_dma_enable(drive);
}
static int triflex_config_drive_xfer_rate(ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
- struct hd_driveid *id = drive->id;
-
- if ((id->capability & 1) && drive->autodma) {
- if (ide_use_dma(drive)) {
- if (triflex_config_drive_for_dma(drive))
- return hwif->ide_dma_on(drive);
- }
- }
+ if (ide_use_dma(drive) && triflex_config_drive_for_dma(drive))
+ return 0;
+
+ triflex_tune_drive(drive, 255);
- hwif->tuneproc(drive, 255);
- return hwif->ide_dma_off_quietly(drive);
+ return -1;
}
static void __devinit init_hwif_triflex(ide_hwif_t *hwif)
diff --git a/drivers/ide/pci/trm290.c b/drivers/ide/pci/trm290.c
index 174b88c4780..cbb1b11119a 100644
--- a/drivers/ide/pci/trm290.c
+++ b/drivers/ide/pci/trm290.c
@@ -157,16 +157,16 @@ static void trm290_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
if (reg != hwif->select_data) {
hwif->select_data = reg;
/* set PIO/DMA */
- hwif->OUTB(0x51|(hwif->channel<<3), hwif->config_data+1);
- hwif->OUTW(reg & 0xff, hwif->config_data);
+ outb(0x51 | (hwif->channel << 3), hwif->config_data + 1);
+ outw(reg & 0xff, hwif->config_data);
}
/* enable IRQ if not probing */
if (drive->present) {
- reg = hwif->INW(hwif->config_data + 3);
+ reg = inw(hwif->config_data + 3);
reg &= 0x13;
reg &= ~(1 << hwif->channel);
- hwif->OUTW(reg, hwif->config_data+3);
+ outw(reg, hwif->config_data + 3);
}
local_irq_restore(flags);
@@ -177,15 +177,12 @@ static void trm290_selectproc (ide_drive_t *drive)
trm290_prepare_drive(drive, drive->using_dma);
}
-#ifdef CONFIG_BLK_DEV_IDEDMA
static void trm290_ide_dma_exec_cmd(ide_drive_t *drive, u8 command)
{
- ide_hwif_t *hwif = HWIF(drive);
-
BUG_ON(HWGROUP(drive)->handler != NULL); /* paranoia check */
ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);
/* issue cmd to drive */
- hwif->OUTB(command, IDE_COMMAND_REG);
+ outb(command, IDE_COMMAND_REG);
}
static int trm290_ide_dma_setup(ide_drive_t *drive)
@@ -211,10 +208,10 @@ static int trm290_ide_dma_setup(ide_drive_t *drive)
}
/* select DMA xfer */
trm290_prepare_drive(drive, 1);
- hwif->OUTL(hwif->dmatable_dma|rw, hwif->dma_command);
+ outl(hwif->dmatable_dma | rw, hwif->dma_command);
drive->waiting_for_dma = 1;
/* start DMA */
- hwif->OUTW((count * 2) - 1, hwif->dma_status);
+ outw((count * 2) - 1, hwif->dma_status);
return 0;
}
@@ -230,7 +227,7 @@ static int trm290_ide_dma_end (ide_drive_t *drive)
drive->waiting_for_dma = 0;
/* purge DMA mappings */
ide_destroy_dmatable(drive);
- status = hwif->INW(hwif->dma_status);
+ status = inw(hwif->dma_status);
return (status != 0x00ff);
}
@@ -239,10 +236,9 @@ static int trm290_ide_dma_test_irq (ide_drive_t *drive)
ide_hwif_t *hwif = HWIF(drive);
u16 status = 0;
- status = hwif->INW(hwif->dma_status);
+ status = inw(hwif->dma_status);
return (status == 0x00ff);
}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
/*
* Invoked from ide-dma.c at boot time.
@@ -269,15 +265,15 @@ static void __devinit init_hwif_trm290(ide_hwif_t *hwif)
local_irq_save(flags);
/* put config reg into first byte of hwif->select_data */
- hwif->OUTB(0x51|(hwif->channel<<3), hwif->config_data+1);
+ outb(0x51 | (hwif->channel << 3), hwif->config_data + 1);
/* select PIO as default */
hwif->select_data = 0x21;
- hwif->OUTB(hwif->select_data, hwif->config_data);
+ outb(hwif->select_data, hwif->config_data);
/* get IRQ info */
- reg = hwif->INB(hwif->config_data+3);
+ reg = inb(hwif->config_data + 3);
/* mask IRQs for both ports */
reg = (reg & 0x10) | 0x03;
- hwif->OUTB(reg, hwif->config_data+3);
+ outb(reg, hwif->config_data + 3);
local_irq_restore(flags);
if ((reg & 0x10))
@@ -289,13 +285,11 @@ static void __devinit init_hwif_trm290(ide_hwif_t *hwif)
ide_setup_dma(hwif, (hwif->config_data + 4) ^ (hwif->channel ? 0x0080 : 0x0000), 3);
-#ifdef CONFIG_BLK_DEV_IDEDMA
hwif->dma_setup = &trm290_ide_dma_setup;
hwif->dma_exec_cmd = &trm290_ide_dma_exec_cmd;
hwif->dma_start = &trm290_ide_dma_start;
hwif->ide_dma_end = &trm290_ide_dma_end;
hwif->ide_dma_test_irq = &trm290_ide_dma_test_irq;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
hwif->selectproc = &trm290_selectproc;
hwif->autodma = 0; /* play it safe for now */
@@ -312,16 +306,16 @@ static void __devinit init_hwif_trm290(ide_hwif_t *hwif)
static u16 next_offset = 0;
u8 old_mask;
- hwif->OUTB(0x54|(hwif->channel<<3), hwif->config_data+1);
- old = hwif->INW(hwif->config_data);
+ outb(0x54 | (hwif->channel << 3), hwif->config_data + 1);
+ old = inw(hwif->config_data);
old &= ~1;
- old_mask = hwif->INB(old+2);
+ old_mask = inb(old + 2);
if (old != compat && old_mask == 0xff) {
/* leave lower 10 bits untouched */
compat += (next_offset += 0x400);
hwif->io_ports[IDE_CONTROL_OFFSET] = compat + 2;
- hwif->OUTW(compat|1, hwif->config_data);
- new = hwif->INW(hwif->config_data);
+ outw(compat | 1, hwif->config_data);
+ new = inw(hwif->config_data);
printk(KERN_INFO "%s: control basereg workaround: "
"old=0x%04x, new=0x%04x\n",
hwif->name, old, new & ~1);
diff --git a/drivers/ide/pci/via82cxxx.c b/drivers/ide/pci/via82cxxx.c
index 6fb6e50b823..a508550c409 100644
--- a/drivers/ide/pci/via82cxxx.c
+++ b/drivers/ide/pci/via82cxxx.c
@@ -240,8 +240,9 @@ static int via82cxxx_ide_dma_check (ide_drive_t *drive)
via_set_drive(drive, speed);
if (drive->autodma && (speed & XFER_MODE) != XFER_PIO)
- return hwif->ide_dma_on(drive);
- return hwif->ide_dma_off_quietly(drive);
+ return 0;
+
+ return -1;
}
static struct via_isa_bridge *via_config_find(struct pci_dev **isa)
diff --git a/drivers/ide/ppc/mpc8xx.c b/drivers/ide/ppc/mpc8xx.c
index 0ac9da3a737..82de2d781f2 100644
--- a/drivers/ide/ppc/mpc8xx.c
+++ b/drivers/ide/ppc/mpc8xx.c
@@ -12,7 +12,6 @@
*/
#include <linux/errno.h>
-#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/stddef.h>
diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c
index 91c5344a945..395d35253d5 100644
--- a/drivers/ide/ppc/pmac.c
+++ b/drivers/ide/ppc/pmac.c
@@ -24,7 +24,6 @@
*/
#include <linux/types.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/ide.h>
@@ -1238,7 +1237,7 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
hwif->OUTBSYNC = pmac_outbsync;
/* Tell common code _not_ to mess with resources */
- hwif->mmio = 2;
+ hwif->mmio = 1;
hwif->hwif_data = pmif;
pmac_ide_init_hwif_ports(&hwif->hw, pmif->regbase, 0, &hwif->irq);
memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
@@ -1980,16 +1979,12 @@ pmac_ide_dma_test_irq (ide_drive_t *drive)
return 1;
}
-static int
-pmac_ide_dma_host_off (ide_drive_t *drive)
+static void pmac_ide_dma_host_off(ide_drive_t *drive)
{
- return 0;
}
-static int
-pmac_ide_dma_host_on (ide_drive_t *drive)
+static int pmac_ide_dma_host_on(ide_drive_t *drive)
{
- return 0;
}
static int
@@ -2035,7 +2030,7 @@ pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
return;
}
- hwif->ide_dma_off_quietly = &__ide_dma_off_quietly;
+ hwif->dma_off_quietly = &ide_dma_off_quietly;
hwif->ide_dma_on = &__ide_dma_on;
hwif->ide_dma_check = &pmac_ide_dma_check;
hwif->dma_setup = &pmac_ide_dma_setup;
@@ -2043,8 +2038,8 @@ pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
hwif->dma_start = &pmac_ide_dma_start;
hwif->ide_dma_end = &pmac_ide_dma_end;
hwif->ide_dma_test_irq = &pmac_ide_dma_test_irq;
- hwif->ide_dma_host_off = &pmac_ide_dma_host_off;
- hwif->ide_dma_host_on = &pmac_ide_dma_host_on;
+ hwif->dma_host_off = &pmac_ide_dma_host_off;
+ hwif->dma_host_on = &pmac_ide_dma_host_on;
hwif->ide_dma_timeout = &__ide_dma_timeout;
hwif->ide_dma_lostirq = &pmac_ide_dma_lostirq;
diff --git a/drivers/ide/ppc/scc_pata.c b/drivers/ide/ppc/scc_pata.c
new file mode 100644
index 00000000000..de64b022478
--- /dev/null
+++ b/drivers/ide/ppc/scc_pata.c
@@ -0,0 +1,831 @@
+/*
+ * Support for IDE interfaces on Celleb platform
+ *
+ * (C) Copyright 2006 TOSHIBA CORPORATION
+ *
+ * This code is based on drivers/ide/pci/siimage.c:
+ * Copyright (C) 2001-2002 Andre Hedrick <andre@linux-ide.org>
+ * Copyright (C) 2003 Red Hat <alan@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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#define PCI_DEVICE_ID_TOSHIBA_SCC_ATA 0x01b4
+
+#define SCC_PATA_NAME "scc IDE"
+
+#define TDVHSEL_MASTER 0x00000001
+#define TDVHSEL_SLAVE 0x00000004
+
+#define MODE_JCUSFEN 0x00000080
+
+#define CCKCTRL_ATARESET 0x00040000
+#define CCKCTRL_BUFCNT 0x00020000
+#define CCKCTRL_CRST 0x00010000
+#define CCKCTRL_OCLKEN 0x00000100
+#define CCKCTRL_ATACLKOEN 0x00000002
+#define CCKCTRL_LCLKEN 0x00000001
+
+#define QCHCD_IOS_SS 0x00000001
+
+#define QCHSD_STPDIAG 0x00020000
+
+#define INTMASK_MSK 0xD1000012
+#define INTSTS_SERROR 0x80000000
+#define INTSTS_PRERR 0x40000000
+#define INTSTS_RERR 0x10000000
+#define INTSTS_ICERR 0x01000000
+#define INTSTS_BMSINT 0x00000010
+#define INTSTS_BMHE 0x00000008
+#define INTSTS_IOIRQS 0x00000004
+#define INTSTS_INTRQ 0x00000002
+#define INTSTS_ACTEINT 0x00000001
+
+#define ECMODE_VALUE 0x01
+
+static struct scc_ports {
+ unsigned long ctl, dma;
+ unsigned char hwif_id; /* for removing hwif from system */
+} scc_ports[MAX_HWIFS];
+
+/* PIO transfer mode table */
+/* JCHST */
+static unsigned long JCHSTtbl[2][7] = {
+ {0x0E, 0x05, 0x02, 0x03, 0x02, 0x00, 0x00}, /* 100MHz */
+ {0x13, 0x07, 0x04, 0x04, 0x03, 0x00, 0x00} /* 133MHz */
+};
+
+/* JCHHT */
+static unsigned long JCHHTtbl[2][7] = {
+ {0x0E, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00}, /* 100MHz */
+ {0x13, 0x03, 0x03, 0x03, 0x03, 0x00, 0x00} /* 133MHz */
+};
+
+/* JCHCT */
+static unsigned long JCHCTtbl[2][7] = {
+ {0x1D, 0x1D, 0x1C, 0x0B, 0x06, 0x00, 0x00}, /* 100MHz */
+ {0x27, 0x26, 0x26, 0x0E, 0x09, 0x00, 0x00} /* 133MHz */
+};
+
+
+/* DMA transfer mode table */
+/* JCHDCTM/JCHDCTS */
+static unsigned long JCHDCTxtbl[2][7] = {
+ {0x0A, 0x06, 0x04, 0x03, 0x01, 0x00, 0x00}, /* 100MHz */
+ {0x0E, 0x09, 0x06, 0x04, 0x02, 0x01, 0x00} /* 133MHz */
+};
+
+/* JCSTWTM/JCSTWTS */
+static unsigned long JCSTWTxtbl[2][7] = {
+ {0x06, 0x04, 0x03, 0x02, 0x02, 0x02, 0x00}, /* 100MHz */
+ {0x09, 0x06, 0x04, 0x02, 0x02, 0x02, 0x02} /* 133MHz */
+};
+
+/* JCTSS */
+static unsigned long JCTSStbl[2][7] = {
+ {0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x00}, /* 100MHz */
+ {0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05} /* 133MHz */
+};
+
+/* JCENVT */
+static unsigned long JCENVTtbl[2][7] = {
+ {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00}, /* 100MHz */
+ {0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02} /* 133MHz */
+};
+
+/* JCACTSELS/JCACTSELM */
+static unsigned long JCACTSELtbl[2][7] = {
+ {0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00}, /* 100MHz */
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01} /* 133MHz */
+};
+
+
+static u8 scc_ide_inb(unsigned long port)
+{
+ u32 data = in_be32((void*)port);
+ return (u8)data;
+}
+
+static u16 scc_ide_inw(unsigned long port)
+{
+ u32 data = in_be32((void*)port);
+ return (u16)data;
+}
+
+static void scc_ide_insw(unsigned long port, void *addr, u32 count)
+{
+ u16 *ptr = (u16 *)addr;
+ while (count--) {
+ *ptr++ = le16_to_cpu(in_be32((void*)port));
+ }
+}
+
+static void scc_ide_insl(unsigned long port, void *addr, u32 count)
+{
+ u16 *ptr = (u16 *)addr;
+ while (count--) {
+ *ptr++ = le16_to_cpu(in_be32((void*)port));
+ *ptr++ = le16_to_cpu(in_be32((void*)port));
+ }
+}
+
+static void scc_ide_outb(u8 addr, unsigned long port)
+{
+ out_be32((void*)port, addr);
+}
+
+static void scc_ide_outw(u16 addr, unsigned long port)
+{
+ out_be32((void*)port, addr);
+}
+
+static void
+scc_ide_outbsync(ide_drive_t * drive, u8 addr, unsigned long port)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+
+ out_be32((void*)port, addr);
+ __asm__ __volatile__("eieio":::"memory");
+ in_be32((void*)(hwif->dma_base + 0x01c));
+ __asm__ __volatile__("eieio":::"memory");
+}
+
+static void
+scc_ide_outsw(unsigned long port, void *addr, u32 count)
+{
+ u16 *ptr = (u16 *)addr;
+ while (count--) {
+ out_be32((void*)port, cpu_to_le16(*ptr++));
+ }
+}
+
+static void
+scc_ide_outsl(unsigned long port, void *addr, u32 count)
+{
+ u16 *ptr = (u16 *)addr;
+ while (count--) {
+ out_be32((void*)port, cpu_to_le16(*ptr++));
+ out_be32((void*)port, cpu_to_le16(*ptr++));
+ }
+}
+
+/**
+ * scc_ratemask - Compute available modes
+ * @drive: IDE drive
+ *
+ * Compute the available speeds for the devices on the interface.
+ * Enforce UDMA33 as a limit if there is no 80pin cable present.
+ */
+
+static u8 scc_ratemask(ide_drive_t *drive)
+{
+ u8 mode = 4;
+
+ if (!eighty_ninty_three(drive))
+ mode = min(mode, (u8)1);
+ return mode;
+}
+
+/**
+ * scc_tuneproc - tune a drive PIO mode
+ * @drive: drive to tune
+ * @mode_wanted: the target operating mode
+ *
+ * Load the timing settings for this device mode into the
+ * controller.
+ */
+
+static void scc_tuneproc(ide_drive_t *drive, byte mode_wanted)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct scc_ports *ports = ide_get_hwifdata(hwif);
+ unsigned long ctl_base = ports->ctl;
+ unsigned long cckctrl_port = ctl_base + 0xff0;
+ unsigned long piosht_port = ctl_base + 0x000;
+ unsigned long pioct_port = ctl_base + 0x004;
+ unsigned long reg;
+ unsigned char speed = XFER_PIO_0;
+ int offset;
+
+ mode_wanted = ide_get_best_pio_mode(drive, mode_wanted, 4, NULL);
+ switch (mode_wanted) {
+ case 4:
+ speed = XFER_PIO_4;
+ break;
+ case 3:
+ speed = XFER_PIO_3;
+ break;
+ case 2:
+ speed = XFER_PIO_2;
+ break;
+ case 1:
+ speed = XFER_PIO_1;
+ break;
+ case 0:
+ default:
+ speed = XFER_PIO_0;
+ break;
+ }
+
+ reg = in_be32((void __iomem *)cckctrl_port);
+ if (reg & CCKCTRL_ATACLKOEN) {
+ offset = 1; /* 133MHz */
+ } else {
+ offset = 0; /* 100MHz */
+ }
+ reg = JCHSTtbl[offset][mode_wanted] << 16 | JCHHTtbl[offset][mode_wanted];
+ out_be32((void __iomem *)piosht_port, reg);
+ reg = JCHCTtbl[offset][mode_wanted];
+ out_be32((void __iomem *)pioct_port, reg);
+
+ ide_config_drive_speed(drive, speed);
+}
+
+/**
+ * scc_tune_chipset - tune a drive DMA mode
+ * @drive: Drive to set up
+ * @xferspeed: speed we want to achieve
+ *
+ * Load the timing settings for this device mode into the
+ * controller.
+ */
+
+static int scc_tune_chipset(ide_drive_t *drive, byte xferspeed)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ u8 speed = ide_rate_filter(scc_ratemask(drive), xferspeed);
+ struct scc_ports *ports = ide_get_hwifdata(hwif);
+ unsigned long ctl_base = ports->ctl;
+ unsigned long cckctrl_port = ctl_base + 0xff0;
+ unsigned long mdmact_port = ctl_base + 0x008;
+ unsigned long mcrcst_port = ctl_base + 0x00c;
+ unsigned long sdmact_port = ctl_base + 0x010;
+ unsigned long scrcst_port = ctl_base + 0x014;
+ unsigned long udenvt_port = ctl_base + 0x018;
+ unsigned long tdvhsel_port = ctl_base + 0x020;
+ int is_slave = (&hwif->drives[1] == drive);
+ int offset, idx;
+ unsigned long reg;
+ unsigned long jcactsel;
+
+ reg = in_be32((void __iomem *)cckctrl_port);
+ if (reg & CCKCTRL_ATACLKOEN) {
+ offset = 1; /* 133MHz */
+ } else {
+ offset = 0; /* 100MHz */
+ }
+
+ switch (speed) {
+ case XFER_UDMA_6:
+ idx = 6;
+ break;
+ case XFER_UDMA_5:
+ idx = 5;
+ break;
+ case XFER_UDMA_4:
+ idx = 4;
+ break;
+ case XFER_UDMA_3:
+ idx = 3;
+ break;
+ case XFER_UDMA_2:
+ idx = 2;
+ break;
+ case XFER_UDMA_1:
+ idx = 1;
+ break;
+ case XFER_UDMA_0:
+ idx = 0;
+ break;
+ default:
+ return 1;
+ }
+
+ jcactsel = JCACTSELtbl[offset][idx];
+ if (is_slave) {
+ out_be32((void __iomem *)sdmact_port, JCHDCTxtbl[offset][idx]);
+ out_be32((void __iomem *)scrcst_port, JCSTWTxtbl[offset][idx]);
+ jcactsel = jcactsel << 2;
+ out_be32((void __iomem *)tdvhsel_port, (in_be32((void __iomem *)tdvhsel_port) & ~TDVHSEL_SLAVE) | jcactsel);
+ } else {
+ out_be32((void __iomem *)mdmact_port, JCHDCTxtbl[offset][idx]);
+ out_be32((void __iomem *)mcrcst_port, JCSTWTxtbl[offset][idx]);
+ out_be32((void __iomem *)tdvhsel_port, (in_be32((void __iomem *)tdvhsel_port) & ~TDVHSEL_MASTER) | jcactsel);
+ }
+ reg = JCTSStbl[offset][idx] << 16 | JCENVTtbl[offset][idx];
+ out_be32((void __iomem *)udenvt_port, reg);
+
+ return ide_config_drive_speed(drive, speed);
+}
+
+/**
+ * scc_config_chipset_for_dma - configure for DMA
+ * @drive: drive to configure
+ *
+ * Called by scc_config_drive_for_dma().
+ */
+
+static int scc_config_chipset_for_dma(ide_drive_t *drive)
+{
+ u8 speed = ide_dma_speed(drive, scc_ratemask(drive));
+
+ if (!speed)
+ return 0;
+
+ if (scc_tune_chipset(drive, speed))
+ return 0;
+
+ return ide_dma_enable(drive);
+}
+
+/**
+ * scc_configure_drive_for_dma - set up for DMA transfers
+ * @drive: drive we are going to set up
+ *
+ * Set up the drive for DMA, tune the controller and drive as
+ * required.
+ * If the drive isn't suitable for DMA or we hit other problems
+ * then we will drop down to PIO and set up PIO appropriately.
+ * (return 1)
+ */
+
+static int scc_config_drive_for_dma(ide_drive_t *drive)
+{
+ if (ide_use_dma(drive) && scc_config_chipset_for_dma(drive))
+ return 0;
+
+ if (ide_use_fast_pio(drive))
+ scc_tuneproc(drive, 4);
+
+ return -1;
+}
+
+/**
+ * scc_ide_dma_setup - begin a DMA phase
+ * @drive: target device
+ *
+ * Build an IDE DMA PRD (IDE speak for scatter gather table)
+ * and then set up the DMA transfer registers.
+ *
+ * Returns 0 on success. If a PIO fallback is required then 1
+ * is returned.
+ */
+
+static int scc_dma_setup(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct request *rq = HWGROUP(drive)->rq;
+ unsigned int reading;
+ u8 dma_stat;
+
+ if (rq_data_dir(rq))
+ reading = 0;
+ else
+ reading = 1 << 3;
+
+ /* fall back to pio! */
+ if (!ide_build_dmatable(drive, rq)) {
+ ide_map_sg(drive, rq);
+ return 1;
+ }
+
+ /* PRD table */
+ out_be32((void __iomem *)hwif->dma_prdtable, hwif->dmatable_dma);
+
+ /* specify r/w */
+ out_be32((void __iomem *)hwif->dma_command, reading);
+
+ /* read dma_status for INTR & ERROR flags */
+ dma_stat = in_be32((void __iomem *)hwif->dma_status);
+
+ /* clear INTR & ERROR flags */
+ out_be32((void __iomem *)hwif->dma_status, dma_stat|6);
+ drive->waiting_for_dma = 1;
+ return 0;
+}
+
+
+/**
+ * scc_ide_dma_end - Stop DMA
+ * @drive: IDE drive
+ *
+ * Check and clear INT Status register.
+ * Then call __ide_dma_end().
+ */
+
+static int scc_ide_dma_end(ide_drive_t * drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ unsigned long intsts_port = hwif->dma_base + 0x014;
+ u32 reg;
+
+ while (1) {
+ reg = in_be32((void __iomem *)intsts_port);
+
+ if (reg & INTSTS_SERROR) {
+ printk(KERN_WARNING "%s: SERROR\n", SCC_PATA_NAME);
+ out_be32((void __iomem *)intsts_port, INTSTS_SERROR|INTSTS_BMSINT);
+
+ out_be32((void __iomem *)hwif->dma_command, in_be32((void __iomem *)hwif->dma_command) & ~QCHCD_IOS_SS);
+ continue;
+ }
+
+ if (reg & INTSTS_PRERR) {
+ u32 maea0, maec0;
+ unsigned long ctl_base = hwif->config_data;
+
+ maea0 = in_be32((void __iomem *)(ctl_base + 0xF50));
+ maec0 = in_be32((void __iomem *)(ctl_base + 0xF54));
+
+ printk(KERN_WARNING "%s: PRERR [addr:%x cmd:%x]\n", SCC_PATA_NAME, maea0, maec0);
+
+ out_be32((void __iomem *)intsts_port, INTSTS_PRERR|INTSTS_BMSINT);
+
+ out_be32((void __iomem *)hwif->dma_command, in_be32((void __iomem *)hwif->dma_command) & ~QCHCD_IOS_SS);
+ continue;
+ }
+
+ if (reg & INTSTS_RERR) {
+ printk(KERN_WARNING "%s: Response Error\n", SCC_PATA_NAME);
+ out_be32((void __iomem *)intsts_port, INTSTS_RERR|INTSTS_BMSINT);
+
+ out_be32((void __iomem *)hwif->dma_command, in_be32((void __iomem *)hwif->dma_command) & ~QCHCD_IOS_SS);
+ continue;
+ }
+
+ if (reg & INTSTS_ICERR) {
+ out_be32((void __iomem *)hwif->dma_command, in_be32((void __iomem *)hwif->dma_command) & ~QCHCD_IOS_SS);
+
+ printk(KERN_WARNING "%s: Illegal Configuration\n", SCC_PATA_NAME);
+ out_be32((void __iomem *)intsts_port, INTSTS_ICERR|INTSTS_BMSINT);
+ continue;
+ }
+
+ if (reg & INTSTS_BMSINT) {
+ printk(KERN_WARNING "%s: Internal Bus Error\n", SCC_PATA_NAME);
+ out_be32((void __iomem *)intsts_port, INTSTS_BMSINT);
+
+ ide_do_reset(drive);
+ continue;
+ }
+
+ if (reg & INTSTS_BMHE) {
+ out_be32((void __iomem *)intsts_port, INTSTS_BMHE);
+ continue;
+ }
+
+ if (reg & INTSTS_ACTEINT) {
+ out_be32((void __iomem *)intsts_port, INTSTS_ACTEINT);
+ continue;
+ }
+
+ if (reg & INTSTS_IOIRQS) {
+ out_be32((void __iomem *)intsts_port, INTSTS_IOIRQS);
+ continue;
+ }
+ break;
+ }
+
+ return __ide_dma_end(drive);
+}
+
+/**
+ * setup_mmio_scc - map CTRL/BMID region
+ * @dev: PCI device we are configuring
+ * @name: device name
+ *
+ */
+
+static int setup_mmio_scc (struct pci_dev *dev, const char *name)
+{
+ unsigned long ctl_base = pci_resource_start(dev, 0);
+ unsigned long dma_base = pci_resource_start(dev, 1);
+ unsigned long ctl_size = pci_resource_len(dev, 0);
+ unsigned long dma_size = pci_resource_len(dev, 1);
+ void *ctl_addr;
+ void *dma_addr;
+ int i;
+
+ for (i = 0; i < MAX_HWIFS; i++) {
+ if (scc_ports[i].ctl == 0)
+ break;
+ }
+ if (i >= MAX_HWIFS)
+ return -ENOMEM;
+
+ if (!request_mem_region(ctl_base, ctl_size, name)) {
+ printk(KERN_WARNING "%s: IDE controller MMIO ports not available.\n", SCC_PATA_NAME);
+ goto fail_0;
+ }
+
+ if (!request_mem_region(dma_base, dma_size, name)) {
+ printk(KERN_WARNING "%s: IDE controller MMIO ports not available.\n", SCC_PATA_NAME);
+ goto fail_1;
+ }
+
+ if ((ctl_addr = ioremap(ctl_base, ctl_size)) == NULL)
+ goto fail_2;
+
+ if ((dma_addr = ioremap(dma_base, dma_size)) == NULL)
+ goto fail_3;
+
+ pci_set_master(dev);
+ scc_ports[i].ctl = (unsigned long)ctl_addr;
+ scc_ports[i].dma = (unsigned long)dma_addr;
+ pci_set_drvdata(dev, (void *) &scc_ports[i]);
+
+ return 1;
+
+ fail_3:
+ iounmap(ctl_addr);
+ fail_2:
+ release_mem_region(dma_base, dma_size);
+ fail_1:
+ release_mem_region(ctl_base, ctl_size);
+ fail_0:
+ return -ENOMEM;
+}
+
+/**
+ * init_setup_scc - set up an SCC PATA Controller
+ * @dev: PCI device
+ * @d: IDE PCI device
+ *
+ * Perform the initial set up for this device.
+ */
+
+static int __devinit init_setup_scc(struct pci_dev *dev, ide_pci_device_t *d)
+{
+ unsigned long ctl_base;
+ unsigned long dma_base;
+ unsigned long cckctrl_port;
+ unsigned long intmask_port;
+ unsigned long mode_port;
+ unsigned long ecmode_port;
+ unsigned long dma_status_port;
+ u32 reg = 0;
+ struct scc_ports *ports;
+ int rc;
+
+ rc = setup_mmio_scc(dev, d->name);
+ if (rc < 0) {
+ return rc;
+ }
+
+ ports = pci_get_drvdata(dev);
+ ctl_base = ports->ctl;
+ dma_base = ports->dma;
+ cckctrl_port = ctl_base + 0xff0;
+ intmask_port = dma_base + 0x010;
+ mode_port = ctl_base + 0x024;
+ ecmode_port = ctl_base + 0xf00;
+ dma_status_port = dma_base + 0x004;
+
+ /* controller initialization */
+ reg = 0;
+ out_be32((void*)cckctrl_port, reg);
+ reg |= CCKCTRL_ATACLKOEN;
+ out_be32((void*)cckctrl_port, reg);
+ reg |= CCKCTRL_LCLKEN | CCKCTRL_OCLKEN;
+ out_be32((void*)cckctrl_port, reg);
+ reg |= CCKCTRL_CRST;
+ out_be32((void*)cckctrl_port, reg);
+
+ for (;;) {
+ reg = in_be32((void*)cckctrl_port);
+ if (reg & CCKCTRL_CRST)
+ break;
+ udelay(5000);
+ }
+
+ reg |= CCKCTRL_ATARESET;
+ out_be32((void*)cckctrl_port, reg);
+
+ out_be32((void*)ecmode_port, ECMODE_VALUE);
+ out_be32((void*)mode_port, MODE_JCUSFEN);
+ out_be32((void*)intmask_port, INTMASK_MSK);
+
+ return ide_setup_pci_device(dev, d);
+}
+
+/**
+ * init_mmio_iops_scc - set up the iops for MMIO
+ * @hwif: interface to set up
+ *
+ */
+
+static void __devinit init_mmio_iops_scc(ide_hwif_t *hwif)
+{
+ struct pci_dev *dev = hwif->pci_dev;
+ struct scc_ports *ports = pci_get_drvdata(dev);
+ unsigned long dma_base = ports->dma;
+
+ ide_set_hwifdata(hwif, ports);
+
+ hwif->INB = scc_ide_inb;
+ hwif->INW = scc_ide_inw;
+ hwif->INSW = scc_ide_insw;
+ hwif->INSL = scc_ide_insl;
+ hwif->OUTB = scc_ide_outb;
+ hwif->OUTBSYNC = scc_ide_outbsync;
+ hwif->OUTW = scc_ide_outw;
+ hwif->OUTSW = scc_ide_outsw;
+ hwif->OUTSL = scc_ide_outsl;
+
+ hwif->io_ports[IDE_DATA_OFFSET] = dma_base + 0x20;
+ hwif->io_ports[IDE_ERROR_OFFSET] = dma_base + 0x24;
+ hwif->io_ports[IDE_NSECTOR_OFFSET] = dma_base + 0x28;
+ hwif->io_ports[IDE_SECTOR_OFFSET] = dma_base + 0x2c;
+ hwif->io_ports[IDE_LCYL_OFFSET] = dma_base + 0x30;
+ hwif->io_ports[IDE_HCYL_OFFSET] = dma_base + 0x34;
+ hwif->io_ports[IDE_SELECT_OFFSET] = dma_base + 0x38;
+ hwif->io_ports[IDE_STATUS_OFFSET] = dma_base + 0x3c;
+ hwif->io_ports[IDE_CONTROL_OFFSET] = dma_base + 0x40;
+
+ hwif->irq = hwif->pci_dev->irq;
+ hwif->dma_base = dma_base;
+ hwif->config_data = ports->ctl;
+ hwif->mmio = 1;
+}
+
+/**
+ * init_iops_scc - set up iops
+ * @hwif: interface to set up
+ *
+ * Do the basic setup for the SCC hardware interface
+ * and then do the MMIO setup.
+ */
+
+static void __devinit init_iops_scc(ide_hwif_t *hwif)
+{
+ struct pci_dev *dev = hwif->pci_dev;
+ hwif->hwif_data = NULL;
+ if (pci_get_drvdata(dev) == NULL)
+ return;
+ init_mmio_iops_scc(hwif);
+}
+
+/**
+ * init_hwif_scc - set up hwif
+ * @hwif: interface to set up
+ *
+ * We do the basic set up of the interface structure. The SCC
+ * requires several custom handlers so we override the default
+ * ide DMA handlers appropriately.
+ */
+
+static void __devinit init_hwif_scc(ide_hwif_t *hwif)
+{
+ struct scc_ports *ports = ide_get_hwifdata(hwif);
+
+ ports->hwif_id = hwif->index;
+
+ hwif->dma_command = hwif->dma_base;
+ hwif->dma_status = hwif->dma_base + 0x04;
+ hwif->dma_prdtable = hwif->dma_base + 0x08;
+
+ /* PTERADD */
+ out_be32((void __iomem *)(hwif->dma_base + 0x018), hwif->dmatable_dma);
+
+ hwif->dma_setup = scc_dma_setup;
+ hwif->ide_dma_end = scc_ide_dma_end;
+ hwif->speedproc = scc_tune_chipset;
+ hwif->tuneproc = scc_tuneproc;
+ hwif->ide_dma_check = scc_config_drive_for_dma;
+
+ hwif->drives[0].autotune = IDE_TUNE_AUTO;
+ hwif->drives[1].autotune = IDE_TUNE_AUTO;
+
+ if (in_be32((void __iomem *)(hwif->config_data + 0xff0)) & CCKCTRL_ATACLKOEN) {
+ hwif->ultra_mask = 0x7f; /* 133MHz */
+ } else {
+ hwif->ultra_mask = 0x3f; /* 100MHz */
+ }
+ hwif->mwdma_mask = 0x00;
+ hwif->swdma_mask = 0x00;
+ hwif->atapi_dma = 1;
+
+ /* we support 80c cable only. */
+ hwif->udma_four = 1;
+
+ hwif->autodma = 0;
+ if (!noautodma)
+ hwif->autodma = 1;
+ hwif->drives[0].autodma = hwif->autodma;
+ hwif->drives[1].autodma = hwif->autodma;
+}
+
+#define DECLARE_SCC_DEV(name_str) \
+ { \
+ .name = name_str, \
+ .init_setup = init_setup_scc, \
+ .init_iops = init_iops_scc, \
+ .init_hwif = init_hwif_scc, \
+ .channels = 1, \
+ .autodma = AUTODMA, \
+ .bootable = ON_BOARD, \
+ }
+
+static ide_pci_device_t scc_chipsets[] __devinitdata = {
+ /* 0 */ DECLARE_SCC_DEV("sccIDE"),
+};
+
+/**
+ * scc_init_one - pci layer discovery entry
+ * @dev: PCI device
+ * @id: ident table entry
+ *
+ * Called by the PCI code when it finds an SCC PATA controller.
+ * We then use the IDE PCI generic helper to do most of the work.
+ */
+
+static int __devinit scc_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ ide_pci_device_t *d = &scc_chipsets[id->driver_data];
+ return d->init_setup(dev, d);
+}
+
+/**
+ * scc_remove - pci layer remove entry
+ * @dev: PCI device
+ *
+ * Called by the PCI code when it removes an SCC PATA controller.
+ */
+
+static void __devexit scc_remove(struct pci_dev *dev)
+{
+ struct scc_ports *ports = pci_get_drvdata(dev);
+ ide_hwif_t *hwif = &ide_hwifs[ports->hwif_id];
+ unsigned long ctl_base = pci_resource_start(dev, 0);
+ unsigned long dma_base = pci_resource_start(dev, 1);
+ unsigned long ctl_size = pci_resource_len(dev, 0);
+ unsigned long dma_size = pci_resource_len(dev, 1);
+
+ if (hwif->dmatable_cpu) {
+ pci_free_consistent(hwif->pci_dev,
+ PRD_ENTRIES * PRD_BYTES,
+ hwif->dmatable_cpu,
+ hwif->dmatable_dma);
+ hwif->dmatable_cpu = NULL;
+ }
+
+ ide_unregister(hwif->index);
+
+ hwif->chipset = ide_unknown;
+ iounmap((void*)ports->dma);
+ iounmap((void*)ports->ctl);
+ release_mem_region(dma_base, dma_size);
+ release_mem_region(ctl_base, ctl_size);
+ memset(ports, 0, sizeof(*ports));
+}
+
+static struct pci_device_id scc_pci_tbl[] = {
+ { PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_SCC_ATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, scc_pci_tbl);
+
+static struct pci_driver driver = {
+ .name = "SCC IDE",
+ .id_table = scc_pci_tbl,
+ .probe = scc_init_one,
+ .remove = scc_remove,
+};
+
+static int scc_ide_init(void)
+{
+ return ide_pci_register_driver(&driver);
+}
+
+module_init(scc_ide_init);
+/* -- No exit code?
+static void scc_ide_exit(void)
+{
+ ide_pci_unregister_driver(&driver);
+}
+module_exit(scc_ide_exit);
+ */
+
+
+MODULE_DESCRIPTION("PCI driver module for Toshiba SCC IDE");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/setup-pci.c b/drivers/ide/setup-pci.c
index 695e23904d3..a52c80fe7d3 100644
--- a/drivers/ide/setup-pci.c
+++ b/drivers/ide/setup-pci.c
@@ -783,10 +783,11 @@ static LIST_HEAD(ide_pci_drivers);
* Returns are the same as for pci_register_driver
*/
-int __ide_pci_register_driver(struct pci_driver *driver, struct module *module)
+int __ide_pci_register_driver(struct pci_driver *driver, struct module *module,
+ const char *mod_name)
{
if(!pre_init)
- return __pci_register_driver(driver, module);
+ return __pci_register_driver(driver, module, mod_name);
driver->driver.owner = module;
list_add_tail(&driver->node, &ide_pci_drivers);
return 0;
@@ -862,6 +863,6 @@ void __init ide_scan_pcibus (int scan_direction)
{
list_del(l);
d = list_entry(l, struct pci_driver, node);
- __pci_register_driver(d, d->driver.owner);
+ __pci_register_driver(d, d->driver.owner, d->driver.mod_name);
}
}
diff --git a/drivers/ieee1394/.gitignore b/drivers/ieee1394/.gitignore
deleted file mode 100644
index 33da10a2532..00000000000
--- a/drivers/ieee1394/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-oui.c
diff --git a/drivers/ieee1394/Kconfig b/drivers/ieee1394/Kconfig
index e7d56573fe5..b8a47342cd2 100644
--- a/drivers/ieee1394/Kconfig
+++ b/drivers/ieee1394/Kconfig
@@ -35,20 +35,6 @@ config IEEE1394_VERBOSEDEBUG
Say Y if you really want or need the debugging output, everyone
else says N.
-config IEEE1394_OUI_DB
- bool "OUI Database built-in (deprecated)"
- depends on IEEE1394
- help
- If you say Y here, then an OUI list (vendor unique ID's) will be
- compiled into the ieee1394 module. This doesn't really do much
- except being able to display the vendor of a hardware node. The
- downside is that it adds about 300k to the size of the module,
- or kernel (depending on whether you compile ieee1394 as a
- module, or static in the kernel).
-
- This option is not needed for userspace programs like gscanbus
- to show this information.
-
config IEEE1394_EXTRA_CONFIG_ROMS
bool "Build in extra config rom entries for certain functionality"
depends on IEEE1394
@@ -66,13 +52,6 @@ config IEEE1394_CONFIG_ROM_IP1394
with MacOSX and WinXP IP-over-1394), enable this option and the
eth1394 option below.
-config IEEE1394_EXPORT_FULL_API
- bool "Export all symbols of ieee1394's API (deprecated)"
- depends on IEEE1394
- default n
- help
- This option will be removed soon. Don't worry, say N.
-
comment "Device Drivers"
depends on IEEE1394
diff --git a/drivers/ieee1394/Makefile b/drivers/ieee1394/Makefile
index d9650d3d77a..489c133664d 100644
--- a/drivers/ieee1394/Makefile
+++ b/drivers/ieee1394/Makefile
@@ -5,9 +5,6 @@
ieee1394-objs := ieee1394_core.o ieee1394_transactions.o hosts.o \
highlevel.o csr.o nodemgr.o dma.o iso.o \
csr1212.o config_roms.o
-ifdef CONFIG_IEEE1394_OUI_DB
-ieee1394-objs += oui.o
-endif
obj-$(CONFIG_IEEE1394) += ieee1394.o
obj-$(CONFIG_IEEE1394_PCILYNX) += pcilynx.o
@@ -18,10 +15,3 @@ obj-$(CONFIG_IEEE1394_SBP2) += sbp2.o
obj-$(CONFIG_IEEE1394_DV1394) += dv1394.o
obj-$(CONFIG_IEEE1394_ETH1394) += eth1394.o
-quiet_cmd_oui2c = OUI2C $@
- cmd_oui2c = $(CONFIG_SHELL) $(srctree)/$(src)/oui2c.sh < $< > $@
-
-targets := oui.c
-$(obj)/oui.o: $(obj)/oui.c
-$(obj)/oui.c: $(src)/oui.db $(src)/oui2c.sh FORCE
- $(call if_changed,oui2c)
diff --git a/drivers/ieee1394/csr1212.c b/drivers/ieee1394/csr1212.c
index 586f71e7346..c28f639823d 100644
--- a/drivers/ieee1394/csr1212.c
+++ b/drivers/ieee1394/csr1212.c
@@ -47,14 +47,14 @@
#define __D (1 << CSR1212_KV_TYPE_DIRECTORY)
#define __L (1 << CSR1212_KV_TYPE_LEAF)
static const u_int8_t csr1212_key_id_type_map[0x30] = {
- 0, /* Reserved */
+ __C, /* used by Apple iSight */
__D | __L, /* Descriptor */
__I | __D | __L, /* Bus_Dependent_Info */
__I | __D | __L, /* Vendor */
__I, /* Hardware_Version */
0, 0, /* Reserved */
- __D | __L, /* Module */
- 0, 0, 0, 0, /* Reserved */
+ __D | __L | __I, /* Module */
+ __I, 0, 0, 0, /* used by Apple iSight, Reserved */
__I, /* Node_Capabilities */
__L, /* EUI_64 */
0, 0, 0, /* Reserved */
@@ -1234,6 +1234,12 @@ static int csr1212_parse_bus_info_block(struct csr1212_csr *csr)
csr->private);
if (ret != CSR1212_SUCCESS)
return ret;
+
+ /* check ROM header's info_length */
+ if (i == 0 &&
+ CSR1212_BE32_TO_CPU(csr->cache_head->data[0]) >> 24 !=
+ bytes_to_quads(csr->bus_info_len) - 1)
+ return CSR1212_EINVAL;
}
bi = (struct csr1212_bus_info_block_img*)csr->cache_head->data;
@@ -1250,9 +1256,6 @@ static int csr1212_parse_bus_info_block(struct csr1212_csr *csr)
return ret;
}
- if (bytes_to_quads(csr->bus_info_len - sizeof(csr1212_quad_t)) != bi->length)
- return CSR1212_EINVAL;
-
#if 0
/* Apparently there are too many differnt wrong implementations of the
* CRC algorithm that verifying them is moot. */
diff --git a/drivers/ieee1394/dv1394.c b/drivers/ieee1394/dv1394.c
index 1084da4d88a..dee9529aa8e 100644
--- a/drivers/ieee1394/dv1394.c
+++ b/drivers/ieee1394/dv1394.c
@@ -2147,7 +2147,7 @@ out:
}
static struct cdev dv1394_cdev;
-static struct file_operations dv1394_fops=
+static const struct file_operations dv1394_fops=
{
.owner = THIS_MODULE,
.poll = dv1394_poll,
@@ -2255,49 +2255,37 @@ static int dv1394_init(struct ti_ohci *ohci, enum pal_or_ntsc format, enum modes
return 0;
}
-static void dv1394_un_init(struct video_card *video)
+static void dv1394_remove_host(struct hpsb_host *host)
{
- /* obviously nobody has the driver open at this point */
- do_dv1394_shutdown(video, 1);
- kfree(video);
-}
-
-
-static void dv1394_remove_host (struct hpsb_host *host)
-{
- struct video_card *video;
+ struct video_card *video, *tmp_video;
unsigned long flags;
- int id = host->id;
+ int found_ohci_card = 0;
- /* We only work with the OHCI-1394 driver */
- if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME))
- return;
-
- /* find the corresponding video_cards */
do {
- struct video_card *tmp_vid;
-
video = NULL;
-
spin_lock_irqsave(&dv1394_cards_lock, flags);
- list_for_each_entry(tmp_vid, &dv1394_cards, list) {
- if ((tmp_vid->id >> 2) == id) {
- list_del(&tmp_vid->list);
- video = tmp_vid;
+ list_for_each_entry(tmp_video, &dv1394_cards, list) {
+ if ((tmp_video->id >> 2) == host->id) {
+ list_del(&tmp_video->list);
+ video = tmp_video;
+ found_ohci_card = 1;
break;
}
}
spin_unlock_irqrestore(&dv1394_cards_lock, flags);
- if (video)
- dv1394_un_init(video);
- } while (video != NULL);
+ if (video) {
+ do_dv1394_shutdown(video, 1);
+ kfree(video);
+ }
+ } while (video);
- class_device_destroy(hpsb_protocol_class,
- MKDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_DV1394 * 16 + (id<<2)));
+ if (found_ohci_card)
+ class_device_destroy(hpsb_protocol_class, MKDEV(IEEE1394_MAJOR,
+ IEEE1394_MINOR_BLOCK_DV1394 * 16 + (host->id << 2)));
}
-static void dv1394_add_host (struct hpsb_host *host)
+static void dv1394_add_host(struct hpsb_host *host)
{
struct ti_ohci *ohci;
int id = host->id;
diff --git a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c
index 97e5c3dd044..a9531352198 100644
--- a/drivers/ieee1394/eth1394.c
+++ b/drivers/ieee1394/eth1394.c
@@ -43,7 +43,6 @@
#include <linux/module.h>
-#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/errno.h>
diff --git a/drivers/ieee1394/hosts.c b/drivers/ieee1394/hosts.c
index ee82a5320bf..32a13092193 100644
--- a/drivers/ieee1394/hosts.c
+++ b/drivers/ieee1394/hosts.c
@@ -190,14 +190,19 @@ int hpsb_add_host(struct hpsb_host *host)
{
if (hpsb_default_host_entry(host))
return -ENOMEM;
-
hpsb_add_extra_config_roms(host);
-
highlevel_add_host(host);
-
return 0;
}
+void hpsb_resume_host(struct hpsb_host *host)
+{
+ if (host->driver->set_hw_config_rom)
+ host->driver->set_hw_config_rom(host,
+ host->csr.rom->bus_info_data);
+ host->driver->devctl(host, RESET_BUS, SHORT_RESET);
+}
+
void hpsb_remove_host(struct hpsb_host *host)
{
host->is_shutdown = 1;
@@ -206,9 +211,7 @@ void hpsb_remove_host(struct hpsb_host *host)
flush_scheduled_work();
host->driver = &dummy_driver;
-
highlevel_remove_host(host);
-
hpsb_remove_extra_config_roms(host);
class_device_unregister(&host->class_dev);
diff --git a/drivers/ieee1394/hosts.h b/drivers/ieee1394/hosts.h
index d553e38c954..4bf4fb7f67b 100644
--- a/drivers/ieee1394/hosts.h
+++ b/drivers/ieee1394/hosts.h
@@ -61,9 +61,9 @@ struct hpsb_host {
struct device device;
struct class_device class_dev;
- int update_config_rom;
struct delayed_work delayed_reset;
- unsigned int config_roms;
+ unsigned config_roms:31;
+ unsigned update_config_rom:1;
struct list_head addr_space;
u64 low_addr_space; /* upper bound of physical DMA area */
@@ -200,7 +200,8 @@ struct hpsb_host_driver {
struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra,
struct device *dev);
int hpsb_add_host(struct hpsb_host *host);
-void hpsb_remove_host(struct hpsb_host *h);
+void hpsb_resume_host(struct hpsb_host *host);
+void hpsb_remove_host(struct hpsb_host *host);
/* Updates the configuration rom image of a host. rom_version must be the
* current version, otherwise it will fail with return value -1. If this
diff --git a/drivers/ieee1394/ieee1394-ioctl.h b/drivers/ieee1394/ieee1394-ioctl.h
index 8f207508ed1..46878fef136 100644
--- a/drivers/ieee1394/ieee1394-ioctl.h
+++ b/drivers/ieee1394/ieee1394-ioctl.h
@@ -100,5 +100,7 @@
_IO ('#', 0x28)
#define RAW1394_IOC_ISO_RECV_FLUSH \
_IO ('#', 0x29)
+#define RAW1394_IOC_GET_CYCLE_TIMER \
+ _IOR ('#', 0x30, struct raw1394_cycle_timer)
#endif /* __IEEE1394_IOCTL_H */
diff --git a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c
index 9a48ca20d1f..d791d08c743 100644
--- a/drivers/ieee1394/ieee1394_core.c
+++ b/drivers/ieee1394/ieee1394_core.c
@@ -33,7 +33,10 @@
#include <linux/skbuff.h>
#include <linux/suspend.h>
#include <linux/kthread.h>
+#include <linux/preempt.h>
+#include <linux/time.h>
+#include <asm/system.h>
#include <asm/byteorder.h>
#include "ieee1394_types.h"
@@ -186,6 +189,45 @@ int hpsb_reset_bus(struct hpsb_host *host, int type)
}
}
+/**
+ * hpsb_read_cycle_timer - read cycle timer register and system time
+ * @host: host whose isochronous cycle timer register is read
+ * @cycle_timer: address of bitfield to return the register contents
+ * @local_time: address to return the system time
+ *
+ * The format of * @cycle_timer, is described in OHCI 1.1 clause 5.13. This
+ * format is also read from non-OHCI controllers. * @local_time contains the
+ * system time in microseconds since the Epoch, read at the moment when the
+ * cycle timer was read.
+ *
+ * Return value: 0 for success or error number otherwise.
+ */
+int hpsb_read_cycle_timer(struct hpsb_host *host, u32 *cycle_timer,
+ u64 *local_time)
+{
+ int ctr;
+ struct timeval tv;
+ unsigned long flags;
+
+ if (!host || !cycle_timer || !local_time)
+ return -EINVAL;
+
+ preempt_disable();
+ local_irq_save(flags);
+
+ ctr = host->driver->devctl(host, GET_CYCLE_COUNTER, 0);
+ if (ctr)
+ do_gettimeofday(&tv);
+
+ local_irq_restore(flags);
+ preempt_enable();
+
+ if (!ctr)
+ return -EIO;
+ *cycle_timer = ctr;
+ *local_time = tv.tv_sec * 1000000ULL + tv.tv_usec;
+ return 0;
+}
int hpsb_bus_reset(struct hpsb_host *host)
{
@@ -1178,6 +1220,7 @@ module_exit(ieee1394_cleanup);
/** hosts.c **/
EXPORT_SYMBOL(hpsb_alloc_host);
EXPORT_SYMBOL(hpsb_add_host);
+EXPORT_SYMBOL(hpsb_resume_host);
EXPORT_SYMBOL(hpsb_remove_host);
EXPORT_SYMBOL(hpsb_update_config_rom_image);
@@ -1189,16 +1232,13 @@ EXPORT_SYMBOL(hpsb_alloc_packet);
EXPORT_SYMBOL(hpsb_free_packet);
EXPORT_SYMBOL(hpsb_send_packet);
EXPORT_SYMBOL(hpsb_reset_bus);
+EXPORT_SYMBOL(hpsb_read_cycle_timer);
EXPORT_SYMBOL(hpsb_bus_reset);
EXPORT_SYMBOL(hpsb_selfid_received);
EXPORT_SYMBOL(hpsb_selfid_complete);
EXPORT_SYMBOL(hpsb_packet_sent);
EXPORT_SYMBOL(hpsb_packet_received);
EXPORT_SYMBOL_GPL(hpsb_disable_irm);
-#ifdef CONFIG_IEEE1394_EXPORT_FULL_API
-EXPORT_SYMBOL(hpsb_send_phy_config);
-EXPORT_SYMBOL(hpsb_send_packet_and_wait);
-#endif
/** ieee1394_transactions.c **/
EXPORT_SYMBOL(hpsb_get_tlabel);
@@ -1229,20 +1269,12 @@ EXPORT_SYMBOL(hpsb_set_hostinfo_key);
EXPORT_SYMBOL(hpsb_get_hostinfo_bykey);
EXPORT_SYMBOL(hpsb_set_hostinfo);
EXPORT_SYMBOL(highlevel_host_reset);
-#ifdef CONFIG_IEEE1394_EXPORT_FULL_API
-EXPORT_SYMBOL(highlevel_add_host);
-EXPORT_SYMBOL(highlevel_remove_host);
-#endif
/** nodemgr.c **/
EXPORT_SYMBOL(hpsb_node_fill_packet);
EXPORT_SYMBOL(hpsb_node_write);
EXPORT_SYMBOL(__hpsb_register_protocol);
EXPORT_SYMBOL(hpsb_unregister_protocol);
-#ifdef CONFIG_IEEE1394_EXPORT_FULL_API
-EXPORT_SYMBOL(ieee1394_bus_type);
-EXPORT_SYMBOL(nodemgr_for_each_host);
-#endif
/** csr.c **/
EXPORT_SYMBOL(hpsb_update_config_rom);
@@ -1287,13 +1319,3 @@ EXPORT_SYMBOL(csr1212_read);
EXPORT_SYMBOL(csr1212_parse_keyval);
EXPORT_SYMBOL(_csr1212_read_keyval);
EXPORT_SYMBOL(_csr1212_destroy_keyval);
-#ifdef CONFIG_IEEE1394_EXPORT_FULL_API
-EXPORT_SYMBOL(csr1212_create_csr);
-EXPORT_SYMBOL(csr1212_init_local_csr);
-EXPORT_SYMBOL(csr1212_new_immediate);
-EXPORT_SYMBOL(csr1212_associate_keyval);
-EXPORT_SYMBOL(csr1212_new_string_descriptor_leaf);
-EXPORT_SYMBOL(csr1212_destroy_csr);
-EXPORT_SYMBOL(csr1212_generate_csr_image);
-EXPORT_SYMBOL(csr1212_parse_csr);
-#endif
diff --git a/drivers/ieee1394/ieee1394_core.h b/drivers/ieee1394/ieee1394_core.h
index 536ba3f580f..bd29d8ef5bb 100644
--- a/drivers/ieee1394/ieee1394_core.h
+++ b/drivers/ieee1394/ieee1394_core.h
@@ -127,6 +127,9 @@ int hpsb_send_packet_and_wait(struct hpsb_packet *packet);
* progress, 0 otherwise. */
int hpsb_reset_bus(struct hpsb_host *host, int type);
+int hpsb_read_cycle_timer(struct hpsb_host *host, u32 *cycle_timer,
+ u64 *local_time);
+
/*
* The following functions are exported for host driver module usage. All of
* them are safe to use in interrupt contexts, although some are quite
diff --git a/drivers/ieee1394/iso.c b/drivers/ieee1394/iso.c
index 08bd15d2a7b..c6227e51136 100644
--- a/drivers/ieee1394/iso.c
+++ b/drivers/ieee1394/iso.c
@@ -10,7 +10,6 @@
*/
#include <linux/pci.h>
-#include <linux/sched.h>
#include <linux/slab.h>
#include "hosts.h"
diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c
index 61307ca296a..c5ace190bfe 100644
--- a/drivers/ieee1394/nodemgr.c
+++ b/drivers/ieee1394/nodemgr.c
@@ -41,22 +41,6 @@ struct nodemgr_csr_info {
};
-static char *nodemgr_find_oui_name(int oui)
-{
-#ifdef CONFIG_IEEE1394_OUI_DB
- extern struct oui_list_struct {
- int oui;
- char *name;
- } oui_list[];
- int i;
-
- for (i = 0; oui_list[i].name; i++)
- if (oui_list[i].oui == oui)
- return oui_list[i].name;
-#endif
- return NULL;
-}
-
/*
* Correct the speed map entry. This is necessary
* - for nodes with link speed < phy speed,
@@ -274,7 +258,6 @@ static struct device_driver nodemgr_mid_layer_driver = {
struct device nodemgr_dev_template_host = {
.bus = &ieee1394_bus_type,
.release = nodemgr_release_host,
- .driver = &nodemgr_mid_layer_driver,
};
@@ -473,11 +456,9 @@ fw_attr(ne, struct node_entry, nodeid, unsigned int, "0x%04x\n")
fw_attr(ne, struct node_entry, vendor_id, unsigned int, "0x%06x\n")
fw_attr_td(ne, struct node_entry, vendor_name_kv)
-fw_attr(ne, struct node_entry, vendor_oui, const char *, "%s\n")
fw_attr(ne, struct node_entry, guid, unsigned long long, "0x%016Lx\n")
fw_attr(ne, struct node_entry, guid_vendor_id, unsigned int, "0x%06x\n")
-fw_attr(ne, struct node_entry, guid_vendor_oui, const char *, "%s\n")
fw_attr(ne, struct node_entry, in_limbo, int, "%d\n");
static struct device_attribute *const fw_ne_attrs[] = {
@@ -503,7 +484,6 @@ fw_attr(ud, struct unit_directory, model_id, unsigned int, "0x%06x\n")
fw_attr(ud, struct unit_directory, specifier_id, unsigned int, "0x%06x\n")
fw_attr(ud, struct unit_directory, version, unsigned int, "0x%06x\n")
fw_attr_td(ud, struct unit_directory, vendor_name_kv)
-fw_attr(ud, struct unit_directory, vendor_oui, const char *, "%s\n")
fw_attr_td(ud, struct unit_directory, model_name_kv)
static struct device_attribute *const fw_ud_attrs[] = {
@@ -865,7 +845,6 @@ static struct node_entry *nodemgr_create_node(octlet_t guid, struct csr1212_csr
ne->guid = guid;
ne->guid_vendor_id = (guid >> 40) & 0xffffff;
- ne->guid_vendor_oui = nodemgr_find_oui_name(ne->guid_vendor_id);
ne->csr = csr;
memcpy(&ne->device, &nodemgr_dev_template_ne,
@@ -885,9 +864,6 @@ static struct node_entry *nodemgr_create_node(octlet_t guid, struct csr1212_csr
goto fail_classdevreg;
get_device(&ne->device);
- if (ne->guid_vendor_oui &&
- device_create_file(&ne->device, &dev_attr_ne_guid_vendor_oui))
- goto fail_addoiu;
nodemgr_create_ne_dev_files(ne);
nodemgr_update_bus_options(ne);
@@ -898,8 +874,6 @@ static struct node_entry *nodemgr_create_node(octlet_t guid, struct csr1212_csr
return ne;
-fail_addoiu:
- put_device(&ne->device);
fail_classdevreg:
device_unregister(&ne->device);
fail_devreg:
@@ -975,15 +949,10 @@ static void nodemgr_register_device(struct node_entry *ne,
goto fail_classdevreg;
get_device(&ud->device);
- if (ud->vendor_oui &&
- device_create_file(&ud->device, &dev_attr_ud_vendor_oui))
- goto fail_addoui;
nodemgr_create_ud_dev_files(ud);
return;
-fail_addoui:
- put_device(&ud->device);
fail_classdevreg:
device_unregister(&ud->device);
fail_devreg:
@@ -1020,9 +989,6 @@ static struct unit_directory *nodemgr_process_unit_directory
if (kv->key.type == CSR1212_KV_TYPE_IMMEDIATE) {
ud->vendor_id = kv->value.immediate;
ud->flags |= UNIT_DIRECTORY_VENDOR_ID;
-
- if (ud->vendor_id)
- ud->vendor_oui = nodemgr_find_oui_name(ud->vendor_id);
}
break;
@@ -1153,9 +1119,6 @@ static void nodemgr_process_root_directory(struct host_info *hi, struct node_ent
switch (kv->key.id) {
case CSR1212_KV_ID_VENDOR:
ne->vendor_id = kv->value.immediate;
-
- if (ne->vendor_id)
- ne->vendor_oui = nodemgr_find_oui_name(ne->vendor_id);
break;
case CSR1212_KV_ID_NODE_CAPABILITIES:
@@ -1183,9 +1146,6 @@ static void nodemgr_process_root_directory(struct host_info *hi, struct node_ent
last_key_id = kv->key.id;
}
- if (ne->vendor_oui &&
- device_create_file(&ne->device, &dev_attr_ne_vendor_oui))
- goto fail;
if (ne->vendor_name_kv &&
device_create_file(&ne->device, &dev_attr_ne_vendor_name_kv))
goto fail;
@@ -1721,7 +1681,8 @@ static int nodemgr_host_thread(void *__hi)
for (;;) {
/* Sleep until next bus reset */
set_current_state(TASK_INTERRUPTIBLE);
- if (get_hpsb_generation(host) == generation)
+ if (get_hpsb_generation(host) == generation &&
+ !kthread_should_stop())
schedule();
__set_current_state(TASK_RUNNING);
@@ -1889,22 +1850,31 @@ int init_ieee1394_nodemgr(void)
error = class_register(&nodemgr_ne_class);
if (error)
- return error;
-
+ goto fail_ne;
error = class_register(&nodemgr_ud_class);
- if (error) {
- class_unregister(&nodemgr_ne_class);
- return error;
- }
+ if (error)
+ goto fail_ud;
error = driver_register(&nodemgr_mid_layer_driver);
+ if (error)
+ goto fail_ml;
+ /* This driver is not used if nodemgr is off (disable_nodemgr=1). */
+ nodemgr_dev_template_host.driver = &nodemgr_mid_layer_driver;
+
hpsb_register_highlevel(&nodemgr_highlevel);
return 0;
+
+fail_ml:
+ class_unregister(&nodemgr_ud_class);
+fail_ud:
+ class_unregister(&nodemgr_ne_class);
+fail_ne:
+ return error;
}
void cleanup_ieee1394_nodemgr(void)
{
hpsb_unregister_highlevel(&nodemgr_highlevel);
-
+ driver_unregister(&nodemgr_mid_layer_driver);
class_unregister(&nodemgr_ud_class);
class_unregister(&nodemgr_ne_class);
}
diff --git a/drivers/ieee1394/nodemgr.h b/drivers/ieee1394/nodemgr.h
index e25cbadb8be..4147303ad44 100644
--- a/drivers/ieee1394/nodemgr.h
+++ b/drivers/ieee1394/nodemgr.h
@@ -70,7 +70,6 @@ struct unit_directory {
quadlet_t vendor_id;
struct csr1212_keyval *vendor_name_kv;
- const char *vendor_oui;
quadlet_t model_id;
struct csr1212_keyval *model_name_kv;
@@ -93,7 +92,6 @@ struct unit_directory {
struct node_entry {
u64 guid; /* GUID of this node */
u32 guid_vendor_id; /* Top 24bits of guid */
- const char *guid_vendor_oui; /* OUI name of guid vendor id */
struct hpsb_host *host; /* Host this node is attached to */
nodeid_t nodeid; /* NodeID */
@@ -104,7 +102,6 @@ struct node_entry {
/* The following is read from the config rom */
u32 vendor_id;
struct csr1212_keyval *vendor_name_kv;
- const char *vendor_oui;
u32 capabilities;
diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c
index 628130a58af..06fac0d2126 100644
--- a/drivers/ieee1394/ohci1394.c
+++ b/drivers/ieee1394/ohci1394.c
@@ -102,7 +102,6 @@
#include <asm/pgtable.h>
#include <asm/page.h>
#include <asm/irq.h>
-#include <linux/sched.h>
#include <linux/types.h>
#include <linux/vmalloc.h>
#include <linux/init.h>
@@ -181,7 +180,7 @@ static int alloc_dma_trm_ctx(struct ti_ohci *ohci, struct dma_trm_ctx *d,
static void ohci1394_pci_remove(struct pci_dev *pdev);
#ifndef __LITTLE_ENDIAN
-const static size_t hdr_sizes[] = {
+static const size_t hdr_sizes[] = {
3, /* TCODE_WRITEQ */
4, /* TCODE_WRITEB */
3, /* TCODE_WRITE_RESPONSE */
@@ -3281,14 +3280,11 @@ static int __devinit ohci1394_pci_probe(struct pci_dev *dev,
PRINT(KERN_WARNING, "PCI resource length of 0x%llx too small!",
(unsigned long long)pci_resource_len(dev, 0));
- /* Seems PCMCIA handles this internally. Not sure why. Seems
- * pretty bogus to force a driver to special case this. */
-#ifndef PCMCIA
- if (!request_mem_region (ohci_base, OHCI1394_REGISTER_SIZE, OHCI1394_DRIVER_NAME))
+ if (!request_mem_region(ohci_base, OHCI1394_REGISTER_SIZE,
+ OHCI1394_DRIVER_NAME))
FAIL(-ENOMEM, "MMIO resource (0x%llx - 0x%llx) unavailable",
(unsigned long long)ohci_base,
(unsigned long long)ohci_base + OHCI1394_REGISTER_SIZE);
-#endif
ohci->init_state = OHCI_INIT_HAVE_MEM_REGION;
ohci->registers = ioremap(ohci_base, OHCI1394_REGISTER_SIZE);
@@ -3509,10 +3505,8 @@ static void ohci1394_pci_remove(struct pci_dev *pdev)
iounmap(ohci->registers);
case OHCI_INIT_HAVE_MEM_REGION:
-#ifndef PCMCIA
release_mem_region(pci_resource_start(ohci->dev, 0),
OHCI1394_REGISTER_SIZE);
-#endif
#ifdef CONFIG_PPC_PMAC
/* On UniNorth, power down the cable and turn off the chip clock
@@ -3541,9 +3535,6 @@ static int ohci1394_pci_suspend(struct pci_dev *pdev, pm_message_t state)
int err;
struct ti_ohci *ohci = pci_get_drvdata(pdev);
- printk(KERN_INFO "%s does not fully support suspend and resume yet\n",
- OHCI1394_DRIVER_NAME);
-
if (!ohci) {
printk(KERN_ERR "%s: tried to suspend nonexisting host\n",
OHCI1394_DRIVER_NAME);
@@ -3630,15 +3621,14 @@ static int ohci1394_pci_resume(struct pci_dev *pdev)
mdelay(50);
ohci_initialize(ohci);
+ hpsb_resume_host(ohci->host);
return 0;
}
#endif /* CONFIG_PM */
-#define PCI_CLASS_FIREWIRE_OHCI ((PCI_CLASS_SERIAL_FIREWIRE << 8) | 0x10)
-
static struct pci_device_id ohci1394_pci_tbl[] = {
{
- .class = PCI_CLASS_FIREWIRE_OHCI,
+ .class = PCI_CLASS_SERIAL_FIREWIRE_OHCI,
.class_mask = PCI_ANY_ID,
.vendor = PCI_ANY_ID,
.device = PCI_ANY_ID,
diff --git a/drivers/ieee1394/oui.db b/drivers/ieee1394/oui.db
deleted file mode 100644
index 592c8a60d01..00000000000
--- a/drivers/ieee1394/oui.db
+++ /dev/null
@@ -1,7048 +0,0 @@
-000000 XEROX CORPORATION
-000001 XEROX CORPORATION
-000002 XEROX CORPORATION
-000003 XEROX CORPORATION
-000004 XEROX CORPORATION
-000005 XEROX CORPORATION
-000006 XEROX CORPORATION
-000007 XEROX CORPORATION
-000008 XEROX CORPORATION
-000009 XEROX CORPORATION
-00000A OMRON TATEISI ELECTRONICS CO.
-00000B MATRIX CORPORATION
-00000C CISCO SYSTEMS, INC.
-00000D FIBRONICS LTD.
-00000E FUJITSU LIMITED
-00000F NEXT, INC.
-000010 SYTEK INC.
-000011 NORMEREL SYSTEMES
-000012 INFORMATION TECHNOLOGY LIMITED
-000013 CAMEX
-000014 NETRONIX
-000015 DATAPOINT CORPORATION
-000016 DU PONT PIXEL SYSTEMS .
-000017 TEKELEC
-000018 WEBSTER COMPUTER CORPORATION
-000019 APPLIED DYNAMICS INTERNATIONAL
-00001A ADVANCED MICRO DEVICES
-00001B NOVELL INC.
-00001C BELL TECHNOLOGIES
-00001D CABLETRON SYSTEMS, INC.
-00001E TELSIST INDUSTRIA ELECTRONICA
-00001F Telco Systems, Inc.
-000020 DATAINDUSTRIER DIAB AB
-000021 SUREMAN COMP. & COMMUN. CORP.
-000022 VISUAL TECHNOLOGY INC.
-000023 ABB INDUSTRIAL SYSTEMS AB
-000024 CONNECT AS
-000025 RAMTEK CORP.
-000026 SHA-KEN CO., LTD.
-000027 JAPAN RADIO COMPANY
-000028 PRODIGY SYSTEMS CORPORATION
-000029 IMC NETWORKS CORP.
-00002A TRW - SEDD/INP
-00002B CRISP AUTOMATION, INC
-00002C AUTOTOTE LIMITED
-00002D CHROMATICS INC
-00002E SOCIETE EVIRA
-00002F TIMEPLEX INC.
-000030 VG LABORATORY SYSTEMS LTD
-000031 QPSX COMMUNICATIONS PTY LTD
-000032 Marconi plc
-000033 EGAN MACHINERY COMPANY
-000034 NETWORK RESOURCES CORPORATION
-000035 SPECTRAGRAPHICS CORPORATION
-000036 ATARI CORPORATION
-000037 OXFORD METRICS LIMITED
-000038 CSS LABS
-000039 TOSHIBA CORPORATION
-00003A CHYRON CORPORATION
-00003B i Controls, Inc.
-00003C AUSPEX SYSTEMS INC.
-00003D UNISYS
-00003E SIMPACT
-00003F SYNTREX, INC.
-000040 APPLICON, INC.
-000041 ICE CORPORATION
-000042 METIER MANAGEMENT SYSTEMS LTD.
-000043 MICRO TECHNOLOGY
-000044 CASTELLE CORPORATION
-000045 FORD AEROSPACE & COMM. CORP.
-000046 OLIVETTI NORTH AMERICA
-000047 NICOLET INSTRUMENTS CORP.
-000048 SEIKO EPSON CORPORATION
-000049 APRICOT COMPUTERS, LTD
-00004A ADC CODENOLL TECHNOLOGY CORP.
-00004B ICL DATA OY
-00004C NEC CORPORATION
-00004D DCI CORPORATION
-00004E AMPEX CORPORATION
-00004F LOGICRAFT, INC.
-000050 RADISYS CORPORATION
-000051 HOB ELECTRONIC GMBH & CO. KG
-000052 Intrusion.com, Inc.
-000053 COMPUCORP
-000054 MODICON, INC.
-000055 COMMISSARIAT A L`ENERGIE ATOM.
-000056 DR. B. STRUCK
-000057 SCITEX CORPORATION LTD.
-000058 RACORE COMPUTER PRODUCTS INC.
-000059 HELLIGE GMBH
-00005A SysKonnect GmbH
-00005B ELTEC ELEKTRONIK AG
-00005C TELEMATICS INTERNATIONAL INC.
-00005D CS TELECOM
-00005E USC INFORMATION SCIENCES INST
-00005F SUMITOMO ELECTRIC IND., LTD.
-000060 KONTRON ELEKTRONIK GMBH
-000061 GATEWAY COMMUNICATIONS
-000062 BULL HN INFORMATION SYSTEMS
-000063 DR.ING.SEUFERT GMBH
-000064 YOKOGAWA DIGITAL COMPUTER CORP
-000065 NETWORK ASSOCIATES, INC.
-000066 TALARIS SYSTEMS, INC.
-000067 SOFT * RITE, INC.
-000068 ROSEMOUNT CONTROLS
-000069 CONCORD COMMUNICATIONS INC
-00006A COMPUTER CONSOLES INC.
-00006B SILICON GRAPHICS INC./MIPS
-00006D CRAY COMMUNICATIONS, LTD.
-00006E ARTISOFT, INC.
-00006F Madge Ltd.
-000070 HCL LIMITED
-000071 ADRA SYSTEMS INC.
-000072 MINIWARE TECHNOLOGY
-000073 SIECOR CORPORATION
-000074 RICOH COMPANY LTD.
-000075 Nortel Networks
-000076 ABEKAS VIDEO SYSTEM
-000077 INTERPHASE CORPORATION
-000078 LABTAM LIMITED
-000079 NETWORTH INCORPORATED
-00007A DANA COMPUTER INC.
-00007B RESEARCH MACHINES
-00007C AMPERE INCORPORATED
-00007D SUN MICROSYSTEMS, INC.
-00007E CLUSTRIX CORPORATION
-00007F LINOTYPE-HELL AG
-000080 CRAY COMMUNICATIONS A/S
-000081 BAY NETWORKS
-000082 LECTRA SYSTEMES SA
-000083 TADPOLE TECHNOLOGY PLC
-000084 SUPERNET
-000085 CANON INC.
-000086 MEGAHERTZ CORPORATION
-000087 HITACHI, LTD.
-000088 COMPUTER NETWORK TECH. CORP.
-000089 CAYMAN SYSTEMS INC.
-00008A DATAHOUSE INFORMATION SYSTEMS
-00008B INFOTRON
-00008C Alloy Computer Products (Australia) Pty Ltd
-00008D VERDIX CORPORATION
-00008E SOLBOURNE COMPUTER, INC.
-00008F RAYTHEON COMPANY
-000090 MICROCOM
-000091 ANRITSU CORPORATION
-000092 COGENT DATA TECHNOLOGIES
-000093 PROTEON INC.
-000094 ASANTE TECHNOLOGIES
-000095 SONY TEKTRONIX CORP.
-000096 MARCONI ELECTRONICS LTD.
-000097 EPOCH SYSTEMS
-000098 CROSSCOMM CORPORATION
-000099 MTX, INC.
-00009A RC COMPUTER A/S
-00009B INFORMATION INTERNATIONAL, INC
-00009C ROLM MIL-SPEC COMPUTERS
-00009D LOCUS COMPUTING CORPORATION
-00009E MARLI S.A.
-00009F AMERISTAR TECHNOLOGIES INC.
-0000A0 TOKYO SANYO ELECTRIC CO. LTD.
-0000A1 MARQUETTE ELECTRIC CO.
-0000A2 BAY NETWORKS
-0000A3 NETWORK APPLICATION TECHNOLOGY
-0000A4 ACORN COMPUTERS LIMITED
-0000A5 COMPATIBLE SYSTEMS CORP.
-0000A6 NETWORK GENERAL CORPORATION
-0000A7 NETWORK COMPUTING DEVICES INC.
-0000A8 STRATUS COMPUTER INC.
-0000A9 NETWORK SYSTEMS CORP.
-0000AA XEROX CORPORATION
-0000AB LOGIC MODELING CORPORATION
-0000AC CONWARE COMPUTER CONSULTING
-0000AD BRUKER INSTRUMENTS INC.
-0000AE DASSAULT ELECTRONIQUE
-0000AF NUCLEAR DATA INSTRUMENTATION
-0000B0 RND-RAD NETWORK DEVICES
-0000B1 ALPHA MICROSYSTEMS INC.
-0000B2 TELEVIDEO SYSTEMS, INC.
-0000B3 CIMLINC INCORPORATED
-0000B4 EDIMAX COMPUTER COMPANY
-0000B5 DATABILITY SOFTWARE SYS. INC.
-0000B6 MICRO-MATIC RESEARCH
-0000B7 DOVE COMPUTER CORPORATION
-0000B8 SEIKOSHA CO., LTD.
-0000B9 MCDONNELL DOUGLAS COMPUTER SYS
-0000BA SIIG, INC.
-0000BB TRI-DATA
-0000BC ALLEN-BRADLEY CO. INC.
-0000BD MITSUBISHI CABLE COMPANY
-0000BE THE NTI GROUP
-0000BF SYMMETRIC COMPUTER SYSTEMS
-0000C0 WESTERN DIGITAL CORPORATION
-0000C1 Madge Ltd.
-0000C2 INFORMATION PRESENTATION TECH.
-0000C3 HARRIS CORP COMPUTER SYS DIV
-0000C4 WATERS DIV. OF MILLIPORE
-0000C5 FARALLON COMPUTING/NETOPIA
-0000C6 EON SYSTEMS
-0000C7 ARIX CORPORATION
-0000C8 ALTOS COMPUTER SYSTEMS
-0000C9 EMULEX CORPORATION
-0000CA APPLITEK
-0000CB COMPU-SHACK ELECTRONIC GMBH
-0000CC DENSAN CO., LTD.
-0000CD Allied Telesyn Research Ltd.
-0000CE MEGADATA CORP.
-0000CF HAYES MICROCOMPUTER PRODUCTS
-0000D0 DEVELCON ELECTRONICS LTD.
-0000D1 ADAPTEC INCORPORATED
-0000D2 SBE, INC.
-0000D3 WANG LABORATORIES INC.
-0000D4 PURE DATA LTD.
-0000D5 MICROGNOSIS INTERNATIONAL
-0000D6 PUNCH LINE HOLDING
-0000D7 DARTMOUTH COLLEGE
-0000D8 NOVELL, INC.
-0000D9 NIPPON TELEGRAPH & TELEPHONE
-0000DA ATEX
-0000DB BRITISH TELECOMMUNICATIONS PLC
-0000DC HAYES MICROCOMPUTER PRODUCTS
-0000DD TCL INCORPORATED
-0000DE CETIA
-0000DF BELL & HOWELL PUB SYS DIV
-0000E0 QUADRAM CORP.
-0000E1 GRID SYSTEMS
-0000E2 ACER TECHNOLOGIES CORP.
-0000E3 INTEGRATED MICRO PRODUCTS LTD
-0000E4 IN2 GROUPE INTERTECHNIQUE
-0000E5 SIGMEX LTD.
-0000E6 APTOR PRODUITS DE COMM INDUST
-0000E7 STAR GATE TECHNOLOGIES
-0000E8 ACCTON TECHNOLOGY CORP.
-0000E9 ISICAD, INC.
-0000EA UPNOD AB
-0000EB MATSUSHITA COMM. IND. CO. LTD.
-0000EC MICROPROCESS
-0000ED APRIL
-0000EE NETWORK DESIGNERS, LTD.
-0000EF KTI
-0000F0 SAMSUNG ELECTRONICS CO., LTD.
-0000F1 MAGNA COMPUTER CORPORATION
-0000F2 SPIDER COMMUNICATIONS
-0000F3 GANDALF DATA LIMITED
-0000F4 ALLIED TELESYN INTERNATIONAL
-0000F5 DIAMOND SALES LIMITED
-0000F6 APPLIED MICROSYSTEMS CORP.
-0000F7 YOUTH KEEP ENTERPRISE CO LTD
-0000F8 DIGITAL EQUIPMENT CORPORATION
-0000F9 QUOTRON SYSTEMS INC.
-0000FA MICROSAGE COMPUTER SYSTEMS INC
-0000FB RECHNER ZUR KOMMUNIKATION
-0000FC MEIKO
-0000FD HIGH LEVEL HARDWARE
-0000FE ANNAPOLIS MICRO SYSTEMS
-0000FF CAMTEC ELECTRONICS LTD.
-000100 EQUIP'TRANS
-000102 3COM CORPORATION
-000103 3COM CORPORATION
-000104 DVICO Co., Ltd.
-000105 BECKHOFF GmbH
-000106 Tews Datentechnik GmbH
-000107 Leiser GmbH
-000108 AVLAB Technology, Inc.
-000109 Nagano Japan Radio Co., Ltd.
-00010A CIS TECHNOLOGY INC.
-00010B Space CyberLink, Inc.
-00010C System Talks Inc.
-00010D CORECO, INC.
-00010E Bri-Link Technologies Co., Ltd
-00010F Nishan Systems, Inc.
-000110 Gotham Networks
-000111 iDigm Inc.
-000112 Shark Multimedia Inc.
-000113 OLYMPUS CORPORATION
-000114 KANDA TSUSHIN KOGYO CO., LTD.
-000115 EXTRATECH CORPORATION
-000116 Netspect Technologies, Inc.
-000117 CANAL +
-000118 EZ Digital Co., Ltd.
-000119 Action Controls Pty. Ltd.
-00011A EEH DataLink GmbH
-00011B Unizone Technologies, Inc.
-00011C Universal Talkware Corporation
-00011D Centillium Communications
-00011E Precidia Technologies, Inc.
-00011F RC Networks, Inc.
-000120 OSCILLOQUARTZ S.A.
-000121 RapidStream Inc.
-000122 Trend Communications, Ltd.
-000123 DIGITAL ELECTRONICS CORP.
-000124 Acer Incorporated
-000125 YAESU MUSEN CO., LTD.
-000126 PAC Labs
-000127 The OPEN Group Limited
-000128 EnjoyWeb, Inc.
-000129 DFI Inc.
-00012A Telematica Sistems Inteligente
-00012B TELENET Co., Ltd.
-00012C Aravox Technologies, Inc.
-00012D Komodo Technology
-00012E PC Partner Ltd.
-00012F Twinhead International Corp
-000130 Extreme Networks
-000131 Detection Systems, Inc.
-000132 Dranetz - BMI
-000133 KYOWA Electronic Instruments C
-000134 SIG Positec Systems AG
-000135 KDC Corp.
-000136 CyberTAN Technology, Inc.
-000137 IT Farm Corporation
-000138 XAVi Technologies Corp.
-000139 Point Multimedia Systems
-00013A SHELCAD COMMUNICATIONS, LTD.
-00013B BNA SYSTEMS
-00013C TIW SYSTEMS
-00013D RiscStation Ltd.
-00013E Ascom Tateco AB
-00013F Neighbor World Co., Ltd.
-000140 Sendtek Corporation
-000141 CABLE PRINT
-000142 Cisco Systems, Inc.
-000143 Cisco Systems, Inc.
-000144 Cereva Networks, Inc.
-000145 WINSYSTEMS, INC.
-000146 Tesco Controls, Inc.
-000147 Zhone Technologies
-000148 X-traWeb Inc.
-000149 T.D.T. Transfer Data Test GmbH
-00014A SONY COMPUTER SCIENCE LABS., I
-00014B Ennovate Networks, Inc.
-00014C Berkeley Process Control
-00014D Shin Kin Enterprises Co., Ltd
-00014E WIN Enterprises, Inc.
-00014F LUMINOUS Networks, Inc.
-000150 GILAT COMMUNICATIONS, LTD.
-000151 Ensemble Communications
-000152 CHROMATEK INC.
-000153 ARCHTEK TELECOM CORPORATION
-000154 G3M Corporation
-000155 Promise Technology, Inc.
-000156 FIREWIREDIRECT.COM, INC.
-000157 SYSWAVE CO., LTD
-000158 Electro Industries/Gauge Tech
-000159 S1 Corporation
-00015A Digital Video Broadcasting
-00015B ITALTEL S.p.A/RF-UP-I
-00015C CADANT INC.
-00015D Sun Microsystems, Inc
-00015E BEST TECHNOLOGY CO., LTD.
-00015F DIGITAL DESIGN GmbH
-000160 ELMEX Co., LTD.
-000161 Meta Machine Technology
-000162 Cygnet Technologies, Inc.
-000163 Cisco Systems, Inc.
-000164 Cisco Systems, Inc.
-000165 AirSwitch Corporation
-000166 TC GROUP A/S
-000167 HIOKI E.E. CORPORATION
-000168 VITANA CORPORATION
-000169 Celestix Networks Pte Ltd.
-00016A ALITEC
-00016B LightChip, Inc.
-00016C FOXCONN
-00016D CarrierComm Inc.
-00016E Conklin Corporation
-00016F HAITAI ELECTRONICS CO., LTD.
-000170 ESE Embedded System Engineer'g
-000171 Allied Data Technologies
-000172 TechnoLand Co., LTD.
-000173 JNI Corporation
-000174 CyberOptics Corporation
-000175 Radiant Communications Corp.
-000176 Orient Silver Enterprises
-000177 EDSL
-000178 MARGI Systems, Inc.
-000179 WIRELESS TECHNOLOGY, INC.
-00017A Chengdu Maipu Electric Industrial Co., Ltd.
-00017B Heidelberger Druckmaschinen AG
-00017C AG-E GmbH
-00017D ThermoQuest
-00017E ADTEK System Science Co., Ltd.
-00017F Experience Music Project
-000180 AOpen, Inc.
-000181 Nortel Networks
-000182 DICA TECHNOLOGIES AG
-000183 ANITE TELECOMS
-000184 SIEB & MEYER AG
-000185 Aloka Co., Ltd.
-000186 DISCH GmbH
-000187 i2SE GmbH
-000188 LXCO Technologies ag
-000189 Refraction Technology, Inc.
-00018A ROI COMPUTER AG
-00018B NetLinks Co., Ltd.
-00018C Mega Vision
-00018D AudeSi Technologies
-00018E Logitec Corporation
-00018F Kenetec, Inc.
-000190 SMK-M
-000191 SYRED Data Systems
-000192 Texas Digital Systems
-000193 Hanbyul Telecom Co., Ltd.
-000194 Capital Equipment Corporation
-000195 Sena Technologies, Inc.
-000196 Cisco Systems, Inc.
-000197 Cisco Systems, Inc.
-000198 Darim Vision
-000199 HeiSei Electronics
-00019A LEUNIG GmbH
-00019B Kyoto Microcomputer Co., Ltd.
-00019C JDS Uniphase Inc.
-00019D E-Control Systems, Inc.
-00019E ESS Technology, Inc.
-00019F Phonex Broadband
-0001A0 Infinilink Corporation
-0001A1 Mag-Tek, Inc.
-0001A2 Logical Co., Ltd.
-0001A3 GENESYS LOGIC, INC.
-0001A4 Microlink Corporation
-0001A5 Nextcomm, Inc.
-0001A6 Scientific-Atlanta Arcodan A/S
-0001A7 UNEX TECHNOLOGY CORPORATION
-0001A8 Welltech Computer Co., Ltd.
-0001A9 BMW AG
-0001AA Airspan Communications, Ltd.
-0001AB Main Street Networks
-0001AC Sitara Networks, Inc.
-0001AD Coach Master International d.b.a. CMI Worldwide, Inc.
-0001AE Trex Enterprises
-0001AF Motorola Computer Group
-0001B0 Fulltek Technology Co., Ltd.
-0001B1 General Bandwidth
-0001B2 Digital Processing Systems, Inc.
-0001B3 Precision Electronic Manufacturing
-0001B4 Wayport, Inc.
-0001B5 Turin Networks, Inc.
-0001B6 SAEJIN T&M Co., Ltd.
-0001B7 Centos, Inc.
-0001B8 Netsensity, Inc.
-0001B9 SKF Condition Monitoring
-0001BA IC-Net, Inc.
-0001BB Frequentis
-0001BC Brains Corporation
-0001BD Peterson Electro-Musical Products, Inc.
-0001BE Gigalink Co., Ltd.
-0001BF Teleforce Co., Ltd.
-0001C0 CompuLab, Ltd.
-0001C1 Vitesse Semiconductor Corporation
-0001C2 ARK Research Corp.
-0001C3 Acromag, Inc.
-0001C4 NeoWave, Inc.
-0001C5 Simpler Networks
-0001C6 Quarry Technologies
-0001C7 Cisco Systems, Inc.
-0001C8 THOMAS CONRAD CORP.
-0001C8 CONRAD CORP.
-0001C9 Cisco Systems, Inc.
-0001CA Geocast Network Systems, Inc.
-0001CB NetGame, Ltd.
-0001CC Japan Total Design Communication Co., Ltd.
-0001CD ARtem
-0001CE Custom Micro Products, Ltd.
-0001CF Alpha Data Parallel Systems, Ltd.
-0001D0 VitalPoint, Inc.
-0001D1 CoNet Communications, Inc.
-0001D2 MacPower Peripherals, Ltd.
-0001D3 PAXCOMM, Inc.
-0001D4 Leisure Time, Inc.
-0001D5 HAEDONG INFO & COMM CO., LTD
-0001D6 MAN Roland Druckmaschinen AG
-0001D7 F5 Networks, Inc.
-0001D8 Teltronics, Inc.
-0001D9 Sigma, Inc.
-0001DA WINCOMM Corporation
-0001DB Freecom Technologies GmbH
-0001DC Activetelco
-0001DD Avail Networks
-0001DE Trango Systems, Inc.
-0001DF ISDN Communications, Ltd.
-0001E0 Fast Systems, Inc.
-0001E1 Kinpo Electronics, Inc.
-0001E2 Ando Electric Corporation
-0001E3 Siemens AG
-0001E4 Sitera, Inc.
-0001E5 Supernet, Inc.
-0001E6 Hewlett-Packard Company
-0001E7 Hewlett-Packard Company
-0001E8 Force10 Networks, Inc.
-0001E9 Litton Marine Systems B.V.
-0001EA Cirilium Corp.
-0001EB C-COM Corporation
-0001EC Ericsson Group
-0001ED SETA Corp.
-0001EE Comtrol Europe, Ltd.
-0001EF Camtel Technology Corp.
-0001F0 Tridium, Inc.
-0001F1 Innovative Concepts, Inc.
-0001F2 Mark of the Unicorn, Inc.
-0001F3 QPS, Inc.
-0001F4 Enterasys Networks
-0001F5 ERIM S.A.
-0001F6 Association of Musical Electronics Industry
-0001F7 Image Display Systems, Inc.
-0001F8 Adherent Systems, Ltd.
-0001F9 TeraGlobal Communications Corp.
-0001FA HOROSCAS
-0001FB DoTop Technology, Inc.
-0001FC Keyence Corporation
-0001FD Digital Voice Systems, Inc.
-0001FE DIGITAL EQUIPMENT CORPORATION
-0001FF Data Direct Networks, Inc.
-000200 Net & Sys Co., Ltd.
-000201 IFM Electronic gmbh
-000202 Amino Communications, Ltd.
-000203 Woonsang Telecom, Inc.
-000204 Bodmann Industries Elektronik GmbH
-000205 Hitachi Denshi, Ltd.
-000206 Telital R&D Denmark A/S
-000207 VisionGlobal Network Corp.
-000208 Unify Networks, Inc.
-000209 Shenzhen SED Information Technology Co., Ltd.
-00020A Gefran Spa
-00020B Native Networks, Inc.
-00020C Metro-Optix
-00020D Micronpc.com
-00020E Laurel Networks, Inc.
-00020F AATR
-000210 Fenecom
-000211 Nature Worldwide Technology Corp.
-000212 SierraCom
-000213 S.D.E.L.
-000214 DTVRO
-000215 Cotas Computer Technology A/B
-000216 Cisco Systems, Inc.
-000217 Cisco Systems, Inc.
-000218 Advanced Scientific Corp
-000219 Paralon Technologies
-00021A Zuma Networks
-00021B Kollmorgen-Servotronix
-00021C Network Elements, Inc.
-00021D Data General Communication Ltd.
-00021E SIMTEL S.R.L.
-00021F Aculab PLC
-000220 Canon Aptex, Inc.
-000221 DSP Application, Ltd.
-000222 Chromisys, Inc.
-000223 ClickTV
-000224 Lantern Communications, Inc.
-000225 Certus Technology, Inc.
-000226 XESystems, Inc.
-000227 ESD GmbH
-000228 Necsom, Ltd.
-000229 Adtec Corporation
-00022A Asound Electronic
-00022B Tamura Electric Works, Ltd.
-00022C ABB Bomem, Inc.
-00022D Agere Systems
-00022E TEAC Corp. R& D
-00022F P-Cube, Ltd.
-000230 Intersoft Electronics
-000231 Ingersoll-Rand
-000232 Avision, Inc.
-000233 Mantra Communications, Inc.
-000234 Imperial Technology, Inc.
-000235 Paragon Networks International
-000236 INIT GmbH
-000237 Cosmo Research Corp.
-000238 Serome Technology, Inc.
-000239 Visicom
-00023A ZSK Stickmaschinen GmbH
-00023B Redback Networks
-00023C Creative Technology, Ltd.
-00023D NuSpeed, Inc.
-00023E Selta Telematica S.p.a
-00023F Compal Electronics, Inc.
-000240 Seedek Co., Ltd.
-000241 Amer.com
-000242 Videoframe Systems
-000243 Raysis Co., Ltd.
-000244 SURECOM Technology Co.
-000245 Lampus Co, Ltd.
-000246 All-Win Tech Co., Ltd.
-000247 Great Dragon Information Technology (Group) Co., Ltd.
-000248 Pilz GmbH & Co.
-000249 Aviv Infocom Co, Ltd.
-00024A Cisco Systems, Inc.
-00024B Cisco Systems, Inc.
-00024C SiByte, Inc.
-00024D Mannesman Dematic Colby Pty. Ltd.
-00024E Datacard Group
-00024F IPM Datacom S.R.L.
-000250 Geyser Networks, Inc.
-000251 Soma Networks
-000252 Carrier Corporation
-000253 Televideo, Inc.
-000254 WorldGate
-000255 IBM Corporation
-000256 Alpha Processor, Inc.
-000257 Microcom Corp.
-000258 Flying Packets Communications
-000259 Tsann Kuen China (Shanghai)Enterprise Co., Ltd. IT Group
-00025A Catena Networks
-00025B Cambridge Silicon Radio
-00025C SCI Systems (Kunshan) Co., Ltd.
-00025D Calix Networks
-00025E High Technology Ltd
-00025F Nortel Networks
-000260 Accordion Networks, Inc.
-000261 i3 Micro Technology AB
-000262 Soyo Group Soyo Com Tech Co., Ltd
-000263 UPS Manufacturing SRL
-000264 AudioRamp.com
-000265 Virditech Co. Ltd.
-000266 Thermalogic Corporation
-000267 NODE RUNNER, INC.
-000268 Harris Government Communications
-000269 Nadatel Co., Ltd
-00026A Cocess Telecom Co., Ltd.
-00026B BCM Computers Co., Ltd.
-00026C Philips CFT
-00026D Adept Telecom
-00026E NeGeN Access, Inc.
-00026F Senao International Co., Ltd.
-000270 Crewave Co., Ltd.
-000271 Vpacket Communications
-000272 CC&C Technologies, Inc.
-000273 Coriolis Networks
-000274 Tommy Technologies Corp.
-000275 SMART Technologies, Inc.
-000276 Primax Electronics Ltd.
-000277 Cash Systemes Industrie
-000278 Samsung Electro-Mechanics Co., Ltd.
-000279 Control Applications, Ltd.
-00027A IOI Technology Corporation
-00027B Amplify Net, Inc.
-00027C Trilithic, Inc.
-00027D Cisco Systems, Inc.
-00027E Cisco Systems, Inc.
-00027F ask-technologies.com
-000280 Mu Net, Inc.
-000281 Madge Ltd.
-000282 ViaClix, Inc.
-000283 Spectrum Controls, Inc.
-000284 Alstom T&D P&C
-000285 Riverstone Networks
-000286 Occam Networks
-000287 Adapcom
-000288 GLOBAL VILLAGE COMMUNICATION
-000289 DNE Technologies
-00028A Ambit Microsystems Corporation
-00028B VDSL Systems OY
-00028C Micrel-Synergy Semiconductor
-00028D Movita Technologies, Inc.
-00028E Rapid 5 Networks, Inc.
-00028F Globetek, Inc.
-000290 Woorigisool, Inc.
-000291 Open Network Co., Ltd.
-000292 Logic Innovations, Inc.
-000293 Solid Data Systems
-000294 Tokyo Sokushin Co., Ltd.
-000295 IP.Access Limited
-000296 Lectron Co,. Ltd.
-000297 C-COR.net
-000298 Broadframe Corporation
-000299 Apex, Inc.
-00029A Storage Apps
-00029B Kreatel Communications AB
-00029C 3COM
-00029D Merix Corp.
-00029E Information Equipment Co., Ltd.
-00029F L-3 Communication Aviation Recorders
-0002A0 Flatstack Ltd.
-0002A1 World Wide Packets
-0002A2 Hilscher GmbH
-0002A3 ABB Power Automation
-0002A4 AddPac Technology Co., Ltd.
-0002A5 Compaq Computer Corporation
-0002A6 Effinet Systems Co., Ltd.
-0002A7 Vivace Networks
-0002A8 Air Link Technology
-0002A9 RACOM, s.r.o.
-0002AA PLcom Co., Ltd.
-0002AB CTC Union Technologies Co., Ltd.
-0002AC 3PAR data
-0002AD Pentax Corpotation
-0002AE Scannex Electronics Ltd.
-0002AF TeleCruz Technology, Inc.
-0002B0 Hokubu Communication & Industrial Co., Ltd.
-0002B1 Anritsu, Ltd.
-0002B2 Cablevision
-0002B3 Intel Corporation
-0002B4 DAPHNE
-0002B5 Avnet, Inc.
-0002B6 Acrosser Technology Co., Ltd.
-0002B7 Watanabe Electric Industry Co., Ltd.
-0002B8 WHI KONSULT AB
-0002B9 Cisco Systems, Inc.
-0002BA Cisco Systems, Inc.
-0002BB Continuous Computing
-0002BC LVL 7 Systems, Inc.
-0002BD Bionet Co., Ltd.
-0002BE Totsu Engineering, Inc.
-0002BF dotRocket, Inc.
-0002C0 Bencent Tzeng Industry Co., Ltd.
-0002C1 Innovative Electronic Designs, Inc.
-0002C2 Net Vision Telecom
-0002C3 Arelnet Ltd.
-0002C4 Vector International BUBA
-0002C5 Evertz Microsystems Ltd.
-0002C6 Data Track Technology PLC
-0002C7 ALPS ELECTRIC Co., Ltd.
-0002C8 Technocom Communications Technology (pte) Ltd
-0002C9 Mellanox Technologies
-0002CA EndPoints, Inc.
-0002CB TriState Ltd.
-0002CC M.C.C.I
-0002CD TeleDream, Inc.
-0002CE FoxJet, Inc.
-0002CF ZyGate Communications, Inc.
-0002D0 Comdial Corporation
-0002D1 Vivotek, Inc.
-0002D2 Workstation AG
-0002D3 NetBotz, Inc.
-0002D4 PDA Peripherals, Inc.
-0002D5 ACR
-0002D6 NICE Systems
-0002D7 EMPEG Ltd
-0002D8 BRECIS Communications Corporation
-0002D9 Reliable Controls
-0002DA ExiO Communications, Inc.
-0002DB NETSEC
-0002DC Fujitsu General Limited
-0002DD Bromax Communications, Ltd.
-0002DE Astrodesign, Inc.
-0002DF Net Com Systems, Inc.
-0002E0 ETAS GmbH
-0002E1 Integrated Network Corporation
-0002E2 NDC Infared Engineering
-0002E3 LITE-ON Communications, Inc.
-0002E4 JC HYUN Systems, Inc.
-0002E5 Timeware Ltd.
-0002E6 Gould Instrument Systems, Inc.
-0002E7 CAB GmbH & Co KG
-0002E8 E.D.&A.
-0002E9 CS Systemes De Securite - C3S
-0002EA Videonics, Inc.
-0002EB Pico Communications
-0002EC Maschoff Design Engineering
-0002ED DXO Telecom Co., Ltd.
-0002EE Nokia Danmark A/S
-0002EF CCC Network Systems Group Ltd.
-0002F0 AME Optimedia Technology Co., Ltd.
-0002F1 Pinetron Co., Ltd.
-0002F2 eDevice, Inc.
-0002F3 Media Serve Co., Ltd.
-0002F4 PCTEL, Inc.
-0002F5 VIVE Synergies, Inc.
-0002F6 Equipe Communications
-0002F7 ARM
-0002F8 SEAKR Engineering, Inc.
-0002F9 Mimos Semiconductor SDN BHD
-0002FA DX Antenna Co., Ltd.
-0002FB Baumuller Aulugen-Systemtechnik GmbH
-0002FC Cisco Systems, Inc.
-0002FD Cisco Systems, Inc.
-0002FE Viditec, Inc.
-0002FF Handan BroadInfoCom
-000300 NetContinuum, Inc.
-000301 Avantas Networks Corporation
-000302 Oasys Telecom, Inc.
-000303 JAMA Electronics Co., Ltd.
-000304 Pacific Broadband Communications
-000305 Smart Network Devices GmbH
-000306 Fusion In Tech Co., Ltd.
-000307 Secure Works, Inc.
-000308 AM Communications, Inc.
-000309 Texcel Technology PLC
-00030A Argus Technologies
-00030B Hunter Technology, Inc.
-00030C Telesoft Technologies Ltd.
-00030D Uniwill Computer Corp.
-00030E Core Communications Co., Ltd.
-00030F Digital China (Shanghai) Networks Ltd.
-000310 Link Evolution Corp.
-000311 Micro Technology Co., Ltd.
-000312 TR-Systemtechnik GmbH
-000313 Access Media SPA
-000314 Teleware Network Systems
-000315 Cidco Incorporated
-000316 Nobell Communications, Inc.
-000317 Merlin Systems, Inc.
-000318 Cyras Systems, Inc.
-000319 Infineon AG
-00031A Beijing Broad Telecom Ltd., China
-00031B Cellvision Systems, Inc.
-00031C Svenska Hardvarufabriken AB
-00031D Taiwan Commate Computer, Inc.
-00031E Optranet, Inc.
-00031F Condev Ltd.
-000320 Xpeed, Inc.
-000321 Reco Research Co., Ltd.
-000322 IDIS Co., Ltd.
-000323 Cornet Technology, Inc.
-000324 SANYO Multimedia Tottori Co., Ltd.
-000325 Arima Computer Corp.
-000326 Iwasaki Information Systems Co., Ltd.
-000327 ACT'L
-000328 Mace Group, Inc.
-000329 F3, Inc.
-00032A UniData Communication Systems, Inc.
-00032B GAI Datenfunksysteme GmbH
-00032C ABB Industrie AG
-00032D IBASE Technology, Inc.
-00032E Scope Information Management, Ltd.
-00032F Global Sun Technology, Inc.
-000330 Imagenics, Co., Ltd.
-000331 Cisco Systems, Inc.
-000332 Cisco Systems, Inc.
-000333 Digitel Co., Ltd.
-000334 Newport Electronics
-000335 Mirae Technology
-000336 Zetes Technologies
-000337 Vaone, Inc.
-000338 Oak Technology
-000339 Eurologic Systems, Ltd.
-00033A Silicon Wave, Inc.
-00033B TAMI Tech Co., Ltd.
-00033C Daiden Co., Ltd.
-00033D ILSHin Lab
-00033E Tateyama System Laboratory Co., Ltd.
-00033F BigBand Networks, Ltd.
-000340 Floware Wireless Systems, Ltd.
-000341 Axon Digital Design
-000342 Nortel Networks
-000343 Martin Professional A/S
-000344 Tietech.Co., Ltd.
-000345 Routrek Networks Corporation
-000346 Hitachi Kokusai Electric, Inc.
-000347 Intel Corporation
-000348 Norscan Instruments, Ltd.
-000349 Vidicode Datacommunicatie B.V.
-00034A RIAS Corporation
-00034B Nortel Networks
-00034C Shanghai DigiVision Technology Co., Ltd.
-00034D Chiaro Networks, Ltd.
-00034E Pos Data Company, Ltd.
-00034F Sur-Gard Security
-000350 BTICINO SPA
-000351 Diebold, Inc.
-000352 Colubris Networks
-000353 Mitac, Inc.
-000354 Fiber Logic Communications
-000355 TeraBeam Internet Systems
-000356 Wincor Nixdorf GmbH & Co KG
-000357 Intervoice-Brite, Inc.
-000358 iCable System Co., Ltd.
-000359 DigitalSis
-00035A Photron Limited
-00035B BridgeWave Communications
-00035C Saint Song Corp.
-00035D Bosung Hi-Net Co., Ltd.
-00035E Metropolitan Area Networks, Inc.
-00035F Prueftechnik Condition Monitoring GmbH & Co. KG
-000360 PAC Interactive Technology, Inc.
-000361 Widcomm, Inc.
-000362 Vodtel Communications, Inc.
-000363 Miraesys Co., Ltd.
-000364 Scenix Semiconductor, Inc.
-000365 Kira Information & Communications, Ltd.
-000366 ASM Pacific Technology
-000367 Jasmine Networks, Inc.
-000368 Embedone Co., Ltd.
-000369 Nippon Antenna Co., Ltd.
-00036A Mainnet, Ltd.
-00036B Cisco Systems, Inc.
-00036C Cisco Systems, Inc.
-00036D Runtop, Inc.
-00036E Nicon Systems (Pty) Limited
-00036F Telsey SPA
-000370 NXTV, Inc.
-000371 Acomz Networks Corp.
-000372 ULAN
-000373 Aselsan A.S
-000374 Hunter Watertech
-000375 NetMedia, Inc.
-000376 Graphtec Technology, Inc.
-000377 Gigabit Wireless
-000378 HUMAX Co., Ltd.
-000379 Proscend Communications, Inc.
-00037A Taiyo Yuden Co., Ltd.
-00037B IDEC IZUMI Corporation
-00037C Coax Media
-00037D Stellcom
-00037E PORTech Communications, Inc.
-00037F Atheros Communications, Inc.
-000380 SSH Communications Security Corp.
-000381 Ingenico International
-000382 A-One Co., Ltd.
-000383 Metera Networks, Inc.
-000384 AETA
-000385 Actelis Networks, Inc.
-000386 Ho Net, Inc.
-000387 Blaze Network Products
-000388 Fastfame Technology Co., Ltd.
-000389 Plantronics
-00038A America Online, Inc.
-00038B PLUS-ONE I&T, Inc.
-00038C Total Impact
-00038D PCS Revenue Control Systems, Inc.
-00038E Atoga Systems, Inc.
-00038F Weinschel Corporation
-000390 Digital Video Communications, Inc.
-000392 Hyundai Teletek Co., Ltd.
-000393 Apple Computer, Inc.
-000394 Connect One
-000395 California Amplifier
-000396 EZ Cast Co., Ltd.
-000397 Watchfront Electronics
-000398 WISI
-000399 Dongju Informations & Communications Co., Ltd.
-00039A nSine, Ltd.
-00039B NetChip Technology, Inc.
-00039C OptiMight Communications, Inc.
-00039D BENQ CORPORATION
-00039E Tera System Co., Ltd.
-00039F Cisco Systems, Inc.
-0003A0 Cisco Systems, Inc.
-0003A1 HIPER Information & Communication, Inc.
-0003A2 Catapult Communications
-0003A3 MAVIX, Ltd.
-0003A4 Data Storage and Information Management
-0003A5 Medea Corporation
-0003A7 Unixtar Technology, Inc.
-0003A8 IDOT Computers, Inc.
-0003A9 AXCENT Media AG
-0003AA Watlow
-0003AB Bridge Information Systems
-0003AC Fronius Schweissmaschinen
-0003AD Emerson Energy Systems AB
-0003AE Allied Advanced Manufacturing Pte, Ltd.
-0003AF Paragea Communications
-0003B0 Xsense Technology Corp.
-0003B1 Abbott Laboratories HPD
-0003B2 Radware
-0003B3 IA Link Systems Co., Ltd.
-0003B4 Macrotek International Corp.
-0003B5 Entra Technology Co.
-0003B6 QSI Corporation
-0003B7 ZACCESS Systems
-0003B8 NetKit Solutions, LLC
-0003B9 Hualong Telecom Co., Ltd.
-0003BA Sun Microsystems
-0003BB Signal Communications Limited
-0003BC COT GmbH
-0003BD OmniCluster Technologies, Inc.
-0003BE Netility
-0003BF Centerpoint Broadband Technologies, Inc.
-0003C0 RFTNC Co., Ltd.
-0003C1 Packet Dynamics Ltd
-0003C2 Solphone K.K.
-0003C3 Micronik Multimedia
-0003C4 Tomra Systems ASA
-0003C5 Mobotix AG
-0003C6 ICUE Systems, Inc.
-0003C7 hopf Elektronik GmbH
-0003C8 CML Emergency Services
-0003C9 TECOM Co., Ltd.
-0003CA MTS Systems Corp.
-0003CB Nippon Systems Development Co., Ltd.
-0003CC Momentum Computer, Inc.
-0003CD Clovertech, Inc.
-0003CE ETEN Technologies, Inc.
-0003CF Muxcom, Inc.
-0003D0 KOANKEISO Co., Ltd.
-0003D1 Takaya Corporation
-0003D2 Crossbeam Systems, Inc.
-0003D3 Internet Energy Systems, Inc.
-0003D4 Alloptic, Inc.
-0003D5 Advanced Communications Co., Ltd.
-0003D6 RADVision, Ltd.
-0003D7 NextNet Wireless, Inc.
-0003D8 iMPath Networks, Inc.
-0003D9 Secheron SA
-0003DA Takamisawa Cybernetics Co., Ltd.
-0003DB Apogee Electronics Corp.
-0003DC Lexar Media, Inc.
-0003DD Comark Corp.
-0003DE OTC Wireless
-0003DF Desana Systems
-0003E0 RadioFrame Networks, Inc.
-0003E1 Winmate Communication, Inc.
-0003E2 Comspace Corporation
-0003E3 Cisco Systems, Inc.
-0003E4 Cisco Systems, Inc.
-0003E5 Hermstedt SG
-0003E6 Entone Technologies, Inc.
-0003E7 Logostek Co. Ltd.
-0003E8 Wavelength Digital Limited
-0003E9 Akara Canada, Inc.
-0003EA Mega System Technologies, Inc.
-0003EB Atrica
-0003EC ICG Research, Inc.
-0003ED Shinkawa Electric Co., Ltd.
-0003EE MKNet Corporation
-0003EF Oneline AG
-0003F0 Redfern Broadband Networks
-0003F1 Cicada Semiconductor, Inc.
-0003F2 Seneca Networks
-0003F3 Dazzle Multimedia, Inc.
-0003F4 NetBurner
-0003F5 Chip2Chip
-0003F6 Allegro Networks, Inc.
-0003F7 Plast-Control GmbH
-0003F8 SanCastle Technologies, Inc.
-0003F9 Pleiades Communications, Inc.
-0003FA TiMetra Networks
-0003FB Toko Seiki Company, Ltd.
-0003FC Intertex Data AB
-0003FD Cisco Systems, Inc.
-0003FE Cisco Systems, Inc.
-0003FF Connectix
-000400 LEXMARK INTERNATIONAL, INC.
-000401 Osaki Electric Co., Ltd.
-000402 Nexsan Technologies, Ltd.
-000403 Nexsi Corporation
-000404 Makino Milling Machine Co., Ltd.
-000405 ACN Technologies
-000406 Fa. Metabox AG
-000407 Topcon Positioning Systems, Inc.
-000408 Sanko Electronics Co., Ltd.
-000409 Cratos Networks
-00040A Sage Systems
-00040B 3com Europe Ltd.
-00040C KANNO Work's Ltd.
-00040D Avaya, Inc.
-00040E AVM GmbH
-00040F Asus Network Technologies, Inc.
-000410 Spinnaker Networks, Inc.
-000411 Inkra Networks, Inc.
-000412 WaveSmith Networks, Inc.
-000413 SNOM Technology AG
-000414 Umezawa Musen Denki Co., Ltd.
-000415 Rasteme Systems Co., Ltd.
-000416 Parks S/A Comunicacoes Digitais
-000417 ELAU AG
-000418 Teltronic S.A.U.
-000419 Fibercycle Networks, Inc.
-00041A ines GmbH
-00041B Digital Interfaces Ltd.
-00041C ipDialog, Inc.
-00041D Corega of America
-00041E Shikoku Instrumentation Co., Ltd.
-00041F Sony Computer Entertainment, Inc.
-000420 Slim Devices, Inc.
-000421 Ocular Networks
-000422 Gordon Kapes, Inc.
-000423 Intel Corporation
-000424 TMC s.r.l.
-000425 Atmel Corporation
-000426 Autosys
-000427 Cisco Systems, Inc.
-000428 Cisco Systems, Inc.
-000429 Pixord Corporation
-00042A Wireless Networks, Inc.
-00042B IT Access Co., Ltd.
-00042C Minet, Inc.
-00042D Sarian Systems, Ltd.
-00042E Netous Technologies, Ltd.
-00042F International Communications Products, Inc.
-000430 Netgem
-000431 GlobalStreams, Inc.
-000432 Voyetra Turtle Beach, Inc.
-000433 Cyberboard A/S
-000434 Accelent Systems, Inc.
-000435 Comptek International, Inc.
-000436 ELANsat Technologies, Inc.
-000437 Powin Information Technology, Inc.
-000438 Nortel Networks
-000439 Rosco Entertainment Technology, Inc.
-00043A Intelligent Telecommunications, Inc.
-00043B Lava Computer Mfg., Inc.
-00043C SONOS Co., Ltd.
-00043D INDEL AG
-00043E Telencomm
-00043F Electronic Systems Technology, Inc.
-000440 cyberPIXIE, Inc.
-000441 Half Dome Systems, Inc.
-000442 NACT
-000443 Agilent Technologies, Inc.
-000444 Western Multiplex Corporation
-000445 LMS Skalar Instruments GmbH
-000446 CYZENTECH Co., Ltd.
-000447 Acrowave Systems Co., Ltd.
-000448 Polaroid Professional Imaging
-000449 Mapletree Networks
-00044A iPolicy Networks, Inc.
-00044B NVIDIA
-00044C JENOPTIK
-00044D Cisco Systems, Inc.
-00044E Cisco Systems, Inc.
-00044F Leukhardt Systemelektronik GmbH
-000450 DMD Computers SRL
-000451 Medrad, Inc.
-000452 RocketLogix, Inc.
-000453 YottaYotta, Inc.
-000454 Quadriga UK
-000455 ANTARA.net
-000456 PipingHot Networks
-000457 Universal Access Technology, Inc.
-000458 Fusion X Co., Ltd.
-000459 Veristar Corporation
-00045A The Linksys Group, Inc.
-00045B Techsan Electronics Co., Ltd.
-00045C Mobiwave Pte Ltd
-00045D BEKA Elektronik
-00045E PolyTrax Information Technology AG
-00045F Evalue Technology, Inc.
-000460 Knilink Technology, Inc.
-000461 EPOX Computer Co., Ltd.
-000462 DAKOS Data & Communication Co., Ltd.
-000463 Bosch Security Systems
-000464 Fantasma Networks, Inc.
-000465 i.s.t isdn-support technik GmbH
-000466 ARMITEL Co.
-000467 Wuhan Research Institute of MII
-000468 Vivity, Inc.
-000469 Innocom, Inc.
-00046A Navini Networks
-00046B Palm Wireless, Inc.
-00046C Cyber Technology Co., Ltd.
-00046D Cisco Systems, Inc.
-00046E Cisco Systems, Inc.
-00046F Digitel S/A Industria Eletronica
-000470 ipUnplugged AB
-000471 IPrad
-000472 Telelynx, Inc.
-000473 Photonex Corporation
-000474 LEGRAND
-000475 3 Com Corporation
-000476 3 Com Corporation
-000477 Scalant Systems, Inc.
-000478 G. Star Technology Corporation
-000479 Radius Co., Ltd.
-00047A AXXESSIT ASA
-00047B Schlumberger
-00047C Skidata AG
-00047D Pelco
-00047E NKF Electronics
-00047F Chr. Mayr GmbH & Co. KG
-000480 Foundry Networks, Inc.
-000481 Econolite Control Products, Inc.
-000482 Medialogic Corp.
-000483 Deltron Technology, Inc.
-000484 Amann GmbH
-000485 PicoLight
-000486 ITTC, University of Kansas
-000487 Cogency Semiconductor, Inc.
-000488 Eurotherm Action Incorporated.
-000489 YAFO Networks, Inc.
-00048A Temia Vertriebs GmbH
-00048B Poscon Corporation
-00048C Nayna Networks, Inc.
-00048D Tone Commander Systems, Inc.
-00048E Ohm Tech Labs, Inc.
-00048F TD Systems Corp.
-000490 Optical Access
-000491 Technovision, Inc.
-000492 Hive Internet, Ltd.
-000493 Tsinghua Unisplendour Co., Ltd.
-000494 Breezecom, Ltd.
-000495 Tejas Networks
-000496 Extreme Networks
-000497 MacroSystem Digital Video AG
-000499 Chino Corporation
-00049A Cisco Systems, Inc.
-00049B Cisco Systems, Inc.
-00049C Surgient Networks, Inc.
-00049D Ipanema Technologies
-00049E Wirelink Co., Ltd.
-00049F Metrowerks
-0004A0 Verity Instruments, Inc.
-0004A1 Pathway Connectivity
-0004A2 L.S.I. Japan Co., Ltd.
-0004A3 Microchip Technology, Inc.
-0004A4 NetEnabled, Inc.
-0004A5 Barco Projection Systems NV
-0004A6 SAF Tehnika Ltd.
-0004A7 FabiaTech Corporation
-0004A8 Broadmax Technologies, Inc.
-0004A9 SandStream Technologies, Inc.
-0004AA Jetstream Communications
-0004AB Comverse Network Systems, Inc.
-0004AC IBM CORP.
-0004AD Malibu Networks
-0004AE Liquid Metronics
-0004AF Digital Fountain, Inc.
-0004B0 ELESIGN Co., Ltd.
-0004B1 Signal Technology, Inc.
-0004B2 ESSEGI SRL
-0004B3 Videotek, Inc.
-0004B4 CIAC
-0004B5 Equitrac Corporation
-0004B6 Stratex Networks, Inc.
-0004B7 AMB i.t. Holding
-0004B8 Kumahira Co., Ltd.
-0004B9 S.I. Soubou, Inc.
-0004BA KDD Media Will Corporation
-0004BB Bardac Corporation
-0004BC Giantec, Inc.
-0004BD Motorola BCS
-0004BE OptXCon, Inc.
-0004BF VersaLogic Corp.
-0004C0 Cisco Systems, Inc.
-0004C1 Cisco Systems, Inc.
-0004C2 Magnipix, Inc.
-0004C3 CASTOR Informatique
-0004C4 Allen & Heath Limited
-0004C5 ASE Technologies, USA
-0004C6 Yamaha Motor Co., Ltd.
-0004C7 NetMount
-0004C8 LIBA Maschinenfabrik GmbH
-0004C9 Micro Electron Co., Ltd.
-0004CA FreeMs Corp.
-0004CB Tdsoft Communication, Ltd.
-0004CC Peek Traffic B.V.
-0004CD Informedia Research Group
-0004CE Patria Ailon
-0004CF Seagate Technology
-0004D0 Softlink s.r.o.
-0004D1 Drew Technologies, Inc.
-0004D2 Adcon Telemetry AG
-0004D3 Toyokeiki Co., Ltd.
-0004D4 Proview Electronics Co., Ltd.
-0004D5 Hitachi Communication Systems, Inc.
-0004D6 Takagi Industrial Co., Ltd.
-0004D7 Omitec Instrumentation Ltd.
-0004D8 IPWireless, Inc.
-0004D9 Titan Electronics, Inc.
-0004DA Relax Technology, Inc.
-0004DB Tellus Group Corp.
-0004DC Nortel Networks
-0004DD Cisco Systems, Inc.
-0004DE Cisco Systems, Inc.
-0004DF Teracom Telematica Ltda.
-0004E0 Procket Networks
-0004E1 Infinior Microsystems
-0004E2 SMC Networks, Inc.
-0004E3 Accton Technology Corp.
-0004E4 Daeryung Ind., Inc.
-0004E5 Glonet Systems, Inc.
-0004E6 Banyan Network Private Limited
-0004E7 Lightpointe Communications, Inc
-0004E8 IER, Inc.
-0004E9 Infiniswitch Corporation
-0004EA Hewlett-Packard Company
-0004EB Paxonet Communications, Inc.
-0004EC Memobox SA
-0004ED Billion Electric Co., Ltd.
-0004EE Lincoln Electric Company
-0004EF Polestar Corp.
-0004F0 International Computers, Ltd
-0004F1 WhereNet
-0004F2 Circa Communications, Ltd.
-0004F3 FS FORTH-SYSTEME GmbH
-0004F4 Infinite Electronics Inc.
-0004F5 SnowShore Networks, Inc.
-0004F6 Amphus
-0004F7 Omega Band, Inc.
-0004F8 QUALICABLE TV Industria E Com., Ltda
-0004F9 Xtera Communications, Inc.
-0004FA MIST Inc.
-0004FB Commtech, Inc.
-0004FC Stratus Computer (DE), Inc.
-0004FD Japan Control Engineering Co., Ltd.
-0004FE Pelago Networks
-0004FF Acronet Co., Ltd.
-000500 Cisco Systems, Inc.
-000501 Cisco Systems, Inc.
-000502 APPLE COMPUTER
-000503 ICONAG
-000504 Naray Information & Communication Enterprise
-000505 Systems Integration Solutions, Inc.
-000506 Reddo Networks AB
-000507 Fine Appliance Corp.
-000508 Inetcam, Inc.
-000509 AVOC Nishimura Ltd.
-00050A ICS Spa
-00050B SICOM Systems, Inc.
-00050C Network Photonics, Inc.
-00050D Midstream Technologies, Inc.
-00050E 3ware, Inc.
-00050F Tanaka S/S Ltd.
-000510 Infinite Shanghai Communication Terminals Ltd.
-000511 Complementary Technologies Ltd
-000512 MeshNetworks, Inc.
-000513 VTLinx Multimedia Systems, Inc.
-000514 KDT Systems Co., Ltd.
-000515 Nuark Co., Ltd.
-000516 SMART Modular Technologies
-000517 Shellcomm, Inc.
-000518 Jupiters Technology
-000519 Siemens Building Technologies AG,
-00051A 3Com Europe Ltd.
-00051B Magic Control Technology Corporation
-00051C Xnet Technology Corp.
-00051D Airocon, Inc.
-00051E Brocade Communications Systems, Inc.
-00051F Taijin Media Co., Ltd.
-000520 Smartronix, Inc.
-000521 Control Microsystems
-000522 LEA*D Corporation, Inc.
-000523 AVL List GmbH
-000524 BTL System (HK) Limited
-000525 Puretek Industrial Co., Ltd.
-000526 IPAS GmbH
-000527 SJ Tek Co. Ltd
-000528 New Focus, Inc.
-000529 Shanghai Broadan Communication Technology Co., Ltd
-00052A Ikegami Tsushinki Co., Ltd.
-00052B HORIBA, Ltd.
-00052C Supreme Magic Corporation
-00052D Zoltrix International Limited
-00052E Cinta Networks
-00052F Leviton Voice and Data
-000530 Andiamo Systems, Inc.
-000531 Cisco Systems, Inc.
-000532 Cisco Systems, Inc.
-000533 Sanera Systems, Inc.
-000534 Northstar Engineering Ltd.
-000535 Chip PC Ltd.
-000536 Danam Communications, Inc.
-000537 Nets Technology Co., Ltd.
-000538 Merilus, Inc.
-000539 A Brand New World in Sweden AB
-00053A Willowglen Services Pte Ltd
-00053B Harbour Networks Ltd., Co. Beijing
-00053C Xircom
-00053D Agere Systems
-00053E KID Systeme GmbH
-00053F VisionTek, Inc.
-000540 FAST Corporation
-000541 Advanced Systems Co., Ltd.
-000542 Otari, Inc.
-000543 IQ Wireless GmbH
-000544 Valley Technologies, Inc.
-000545 Internet Photonics
-000546 K-Solutions Inc.
-000547 Starent Networks
-000548 Disco Corporation
-000549 Salira Optical Network Systems
-00054A Ario Data Networks, Inc.
-00054B Micro Innovation AG
-00054C RF Innovations Pty Ltd
-00054D Brans Technologies, Inc.
-00054E Philips Components
-000550 Digi-Tech Communications Limited
-000551 F & S Elektronik Systeme GmbH
-000552 Xycotec Computer GmbH
-000553 DVC Company, Inc.
-000554 Rangestar Wireless
-000555 Japan Cash Machine Co., Ltd.
-000556 360 Systems
-000557 Agile TV Corporation
-000558 Synchronous, Inc.
-000559 Intracom S.A.
-00055A Power Dsine Ltd.
-00055B Charles Industries, Ltd.
-00055C Kowa Company, Ltd.
-00055D D-Link Systems, Inc.
-00055E Cisco Systems, Inc.
-00055F Cisco Systems, Inc.
-000560 LEADER COMM.CO., LTD
-000561 nac Image Technology, Inc.
-000562 Digital View Limited
-000563 J-Works, Inc.
-000564 Tsinghua Bitway Co., Ltd.
-000565 Tailyn Communication Company Ltd.
-000566 Secui.com Corporation
-000567 Etymonic Design, Inc.
-000568 Piltofish Networks AB
-000569 VMWARE, Inc.
-00056A Heuft Systemtechnik GmbH
-00056B C.P. Technology Co., Ltd.
-00056C Hung Chang Co., Ltd.
-00056D Pacific Corporation
-00056E National Enhance Technology, Inc.
-00056F Innomedia Technologies Pvt. Ltd.
-000570 Baydel Ltd.
-000571 Seiwa Electronics Co.
-000572 Deonet Co., Ltd.
-000573 Cisco Systems, Inc.
-000574 Cisco Systems, Inc.
-000575 CDS-Electronics BV
-000576 NSM Technology Ltd.
-000577 SM Information & Communication
-000579 Universal Control Solution Corp.
-00057A Hatteras Networks
-00057B Chung Nam Electronic Co., Ltd.
-00057C RCO Security AB
-00057D Sun Communications, Inc.
-00057E Eckelmann Steuerungstechnik GmbH
-00057F Acqis Technology
-000580 Fibrolan Ltd.
-000581 Snell & Wilcox Ltd.
-000582 ClearCube Technology
-000583 ImageCom Limited
-000584 AbsoluteValue Systems, Inc.
-000585 Juniper Networks, Inc.
-000586 Lucent Technologies
-000587 Locus, Incorporated
-000588 Sensoria Corp.
-000589 National Datacomputer
-00058A Netcom Co., Ltd.
-00058B IPmental, Inc.
-00058C Opentech Inc.
-00058D Lynx Photonic Networks, Inc.
-00058E Flextronics International GmbH & Co. Nfg. KG
-00058F CLCsoft co.
-000590 Swissvoice Ltd.
-000591 Active Silicon Ltd.
-000592 Pultek Corp.
-000593 Grammar Engine Inc.
-000594 IXXAT Automation GmbH
-000595 Alesis Corporation
-000596 Genotech Co., Ltd.
-000597 Eagle Traffic Control Systems
-000598 CRONOS S.r.l.
-000599 DRS Test and Energy Management or DRS-TEM
-00059A Cisco Systems, Inc.
-00059B Cisco Systems, Inc.
-00059C Kleinknecht GmbH, Ing. Buero
-00059D Daniel Computing Systems, Inc.
-00059E Zinwell Corporation
-00059F Yotta Networks, Inc.
-0005A0 MOBILINE Kft.
-0005A1 Zenocom
-0005A2 CELOX Networks
-0005A3 QEI, Inc.
-0005A4 Lucid Voice Ltd.
-0005A5 KOTT
-0005A6 Extron Electronics
-0005A7 Hyperchip, Inc.
-0005A8 WYLE ELECTRONICS
-0005A9 Princeton Networks, Inc.
-0005AA Moore Industries International Inc.
-0005AB Cyber Fone, Inc.
-0005AC Northern Digital, Inc.
-0005AD Topspin Communications, Inc.
-0005AE Mediaport USA
-0005AF InnoScan Computing A/S
-0005B0 Korea Computer Technology Co., Ltd.
-0005B1 ASB Technology BV
-0005B2 Medison Co., Ltd.
-0005B3 Asahi-Engineering Co., Ltd.
-0005B4 Aceex Corporation
-0005B5 Broadcom Technologies
-0005B6 INSYS Microelectronics GmbH
-0005B7 Arbor Technology Corp.
-0005B8 Electronic Design Associates, Inc.
-0005B9 Airvana, Inc.
-0005BA Area Netwoeks, Inc.
-0005BB Myspace AB
-0005BC Resorsys Ltd.
-0005BD ROAX BV
-0005BE Kongsberg Seatex AS
-0005BF JustEzy Technology, Inc.
-0005C0 Digital Network Alacarte Co., Ltd.
-0005C1 A-Kyung Motion, Inc.
-0005C2 Soronti, Inc.
-0005C3 Pacific Instruments, Inc.
-0005C4 Telect, Inc.
-0005C5 Flaga HF
-0005C6 Triz Communications
-0005C7 I/F-COM A/S
-0005C8 VERYTECH
-0005C9 LG Innotek
-0005CA Hitron Technology, Inc.
-0005CB ROIS Technologies, Inc.
-0005CC Sumtel Communications, Inc.
-0005CD Denon, Ltd.
-0005CE Prolink Microsystems Corporation
-0005CF Thunder River Technologies, Inc.
-0005D0 Solinet Systems
-0005D1 Metavector Technologies
-0005D2 DAP Technologies
-0005D3 eProduction Solutions, Inc.
-0005D4 FutureSmart Networks, Inc.
-0005D5 Speedcom Wireless
-0005D6 Titan Wireless
-0005D7 Vista Imaging, Inc.
-0005D8 Arescom, Inc.
-0005D9 Techno Valley, Inc.
-0005DA Apex Automationstechnik
-0005DB Nentec GmbH
-0005DC Cisco Systems, Inc.
-0005DD Cisco Systems, Inc.
-0005DE Gi Fone Korea, Inc.
-0005DF Electronic Innovation, Inc.
-0005E0 Empirix Corp.
-0005E1 Trellis Photonics, Ltd.
-0005E2 Creativ Network Technologies
-0005E3 LightSand Communications, Inc.
-0005E4 Red Lion Controls L.P.
-0005E5 Renishaw PLC
-0005E6 Egenera, Inc.
-0005E7 Netrake Corp.
-0005E8 TurboWave, Inc.
-0005E9 Unicess Network, Inc.
-0005EA Rednix
-0005EB Blue Ridge Networks, Inc.
-0005EC Mosaic Systems Inc.
-0005ED Technikum Joanneum GmbH
-0005EE BEWATOR Group
-0005EF ADOIR Digital Technology
-0005F0 SATEC
-0005F1 Vrcom, Inc.
-0005F2 Power R, Inc.
-0005F3 Weboyn
-0005F4 System Base Co., Ltd.
-0005F5 OYO Geospace Corp.
-0005F6 Young Chang Co. Ltd.
-0005F7 Analog Devices, Inc.
-0005F8 Real Time Access, Inc.
-0005F9 TOA Corporation
-0005FA IPOptical, Inc.
-0005FB ShareGate, Inc.
-0005FC Schenck Pegasus Corp.
-0005FD PacketLight Networks Ltd.
-0005FE Traficon N.V.
-0005FF SNS Solutions, Inc.
-000600 Tokyo Electronic Industry Co., Ltd.
-000601 Otanikeiki Co., Ltd.
-000602 Cirkitech Electronics Co.
-000603 Baker Hughes Inc.
-000604 @Track Communications, Inc.
-000605 Inncom International, Inc.
-000606 RapidWAN, Inc.
-000607 Omni Directional Control Technology Inc.
-000608 At-Sky SAS
-000609 Crossport Systems
-00060A Blue2space
-00060B Paceline Systems Corporation
-00060C Melco Industries, Inc.
-00060D Wave7 Optics
-00060E IGYS Systems, Inc.
-00060F Narad Networks Inc
-000610 Abeona Networks Inc
-000611 Zeus Wireless, Inc.
-000612 Accusys, Inc.
-000613 Kawasaki Microelectronics Incorporated
-000614 Prism Holdings
-000615 Kimoto Electric Co., Ltd.
-000616 Tel Net Co., Ltd.
-000617 Redswitch Inc.
-000618 DigiPower Manufacturing Inc.
-000619 Connection Technology Systems
-00061A Zetari Inc.
-00061B Portable Systems, IBM Japan Co, Ltd
-00061C Hoshino Metal Industries, Ltd.
-00061D MIP Telecom, Inc.
-00061E Maxan Systems
-00061F Vision Components GmbH
-000620 Serial System Ltd.
-000621 Hinox, Co., Ltd.
-000622 Chung Fu Chen Yeh Enterprise Corp.
-000623 MGE UPS Systems France
-000624 Gentner Communications Corp.
-000625 The Linksys Group, Inc.
-000626 MWE GmbH
-000627 Uniwide Technologies, Inc.
-000628 Cisco Systems, Inc.
-000629 IBM CORPORATION
-00062A Cisco Systems, Inc.
-00062B INTRASERVER TECHNOLOGY
-00062C Network Robots, Inc.
-00062D TouchStar Technologies, L.L.C.
-00062E Aristos Logic Corp.
-00062F Pivotech Systems Inc.
-000630 Adtranz Sweden
-000631 Optical Solutions, Inc.
-000632 Mesco Engineering GmbH
-000633 Heimann Biometric Systems GmbH
-000634 GTE Airfone Inc.
-000635 PacketAir Networks, Inc.
-000636 Jedai Broadband Networks
-000637 Toptrend-Meta Information (ShenZhen) Inc.
-000638 Sungjin C&C Co., Ltd.
-000639 Newtec
-00063A Dura Micro, Inc.
-00063B Arcturus Networks, Inc.
-00063C NMI Electronics Ltd
-00063D Microwave Data Systems Inc.
-00063E Opthos Inc.
-00063F Everex Communications Inc.
-000640 White Rock Networks
-000641 ITCN
-000642 Genetel Systems Inc.
-000643 SONO Computer Co., Ltd.
-000644 NEIX Inc.
-000645 Meisei Electric Co. Ltd.
-000646 ShenZhen XunBao Network Technology Co Ltd
-000647 Etrali S.A.
-000648 Seedsware, Inc.
-000649 Quante
-00064A Honeywell Co., Ltd. (KOREA)
-00064B Alexon Co., Ltd.
-00064C Invicta Networks, Inc.
-00064D Sencore
-00064E Broad Net Technology Inc.
-00064F PRO-NETS Technology Corporation
-000650 Tiburon Networks, Inc.
-000651 Aspen Networks Inc.
-000652 Cisco Systems, Inc.
-000653 Cisco Systems, Inc.
-000654 Maxxio Technologies
-000655 Yipee, Inc.
-000656 Tactel AB
-000657 Market Central, Inc.
-000658 Helmut Fischer GmbH & Co. KG
-000659 EAL (Apeldoorn) B.V.
-00065A Strix Systems
-00065B Dell Computer Corp.
-00065C Malachite Technologies, Inc.
-00065D Heidelberg Web Systems
-00065E Photuris, Inc.
-00065F ECI Telecom - NGTS Ltd.
-000660 NADEX Co., Ltd.
-000661 NIA Home Technologies Corp.
-000662 MBM Technology Ltd.
-000663 Human Technology Co., Ltd.
-000664 Fostex Corporation
-000665 Sunny Giken, Inc.
-000666 Roving Networks
-000667 Tripp Lite
-000668 Vicon Industries Inc.
-000669 Datasound Laboratories Ltd
-00066A InfiniCon Systems, Inc.
-00066B Sysmex Corporation
-00066C Robinson Corporation
-00066D Compuprint S.P.A.
-00066E Delta Electronics, Inc.
-00066F Korea Data Systems
-000670 Upponetti Oy
-000671 Softing AG
-000672 Netezza
-000673 Optelecom, Inc.
-000674 Spectrum Control, Inc.
-000675 Banderacom, Inc.
-000676 Novra Technologies Inc.
-000677 SICK AG
-000678 Marantz Japan, Inc.
-000679 Konami Corporation
-00067A JMP Systems
-00067B Toplink C&C Corporation
-00067C CISCO SYSTEMS, INC.
-00067D Takasago Ltd.
-00067E WinCom Systems, Inc.
-00067F Rearden Steel Technologies
-000680 Card Access, Inc.
-000681 Goepel Electronic GmbH
-000682 Convedia
-000683 Bravara Communications, Inc.
-000684 Biacore AB
-000685 NetNearU Corporation
-000686 ZARDCOM Co., Ltd.
-000687 Omnitron Systems Technology, Inc.
-000688 Telways Communication Co., Ltd.
-000689 yLez Technologies Pte Ltd
-00068A NeuronNet Co. Ltd. R&D Center
-00068B AirRunner Technologies, Inc.
-00068C 3Com Corporation
-00068D SANgate Systems
-00068E HID Corporation
-00068F Telemonitor, Inc.
-000690 Euracom Communication GmbH
-000691 PT Inovacao
-000692 Intruvert Networks, Inc.
-000693 Flexus Computer Technology, Inc.
-000694 Mobillian Corporation
-000695 Ensure Technologies, Inc.
-000696 Advent Networks
-000697 R & D Center
-000698 egnite Software GmbH
-000699 Vida Design Co.
-00069A e & Tel
-00069B AVT Audio Video Technologies GmbH
-00069C Transmode Systems AB
-00069D Petards Mobile Intelligence
-00069E UNIQA, Inc.
-00069F Kuokoa Networks
-0006A0 Mx Imaging
-0006A1 Celsian Technologies, Inc.
-0006A2 Microtune, Inc.
-0006A3 Bitran Corporation
-0006A4 INNOWELL Corp.
-0006A5 PINON Corp.
-0006A6 Artistic Licence (UK) Ltd
-0006A7 Primarion
-0006A8 KC Technology, Inc.
-0006A9 Universal Instruments Corp.
-0006AA Miltope Corporation
-0006AB W-Link Systems, Inc.
-0006AC Intersoft Co.
-0006AD KB Electronics Ltd.
-0006AE Himachal Futuristic Communications Ltd
-0006B0 Comtech EF Data Corp.
-0006B1 Sonicwall
-0006B2 Linxtek Co.
-0006B3 Diagraph Corporation
-0006B4 Vorne Industries, Inc.
-0006B5 Luminent, Inc.
-0006B6 Nir-Or Israel Ltd.
-0006B7 TELEM GmbH
-0006B8 Bandspeed Pty Ltd
-0006B9 A5TEK Corp.
-0006BA Westwave Communications
-0006BB ATI Technologies Inc.
-0006BC Macrolink, Inc.
-0006BD BNTECHNOLOGY Co., Ltd.
-0006BE Baumer Optronic GmbH
-0006BF Accella Technologies Co., Ltd.
-0006C0 United Internetworks, Inc.
-0006C1 CISCO SYSTEMS, INC.
-0006C2 Smartmatic Corporation
-0006C3 Schindler Elevators Ltd.
-0006C4 Piolink Inc.
-0006C5 INNOVI Technologies Limited
-0006C6 lesswire AG
-0006C7 RFNET Technologies Pte Ltd (S)
-0006C8 Sumitomo Metal Micro Devices, Inc.
-0006C9 Technical Marketing Research, Inc.
-0006CA American Computer & Digital Components, Inc. (ACDC)
-0006CB Jotron Electronics A/S
-0006CC JMI Electronics Co., Ltd.
-0006CD CreoScitex Corporation Ltd.
-0006CE DATENO
-0006CF Thales Avionics In-Flight Systems, LLC
-0006D0 Elgar Electronics Corp.
-0006D1 Tahoe Networks, Inc.
-0006D2 Tundra Semiconductor Corp.
-0006D3 Alpha Telecom, Inc. U.S.A.
-0006D4 Interactive Objects, Inc.
-0006D5 Diamond Systems Corp.
-0006D6 Cisco Systems, Inc.
-0006D7 Cisco Systems, Inc.
-0006D8 Maple Optical Systems
-0006D9 IPM-Net S.p.A.
-0006DA ITRAN Communications Ltd.
-0006DB ICHIPS Co., Ltd.
-0006DC Syabas Technology (Amquest)
-0006DD AT & T Laboratories - Cambridge Ltd
-0006DE Flash Technology
-0006DF AIDONIC Corporation
-0006E0 MAT Co., Ltd.
-0006E1 Techno Trade s.a
-0006E2 Ceemax Technology Co., Ltd.
-0006E3 Quantitative Imaging Corporation
-0006E4 Citel Technologies Ltd.
-0006E5 Fujian Newland Computer Ltd. Co.
-0006E6 DongYang Telecom Co., Ltd.
-0006E7 Bit Blitz Communications Inc.
-0006E8 Optical Network Testing, Inc.
-0006E9 Intime Corp.
-0006EA ELZET80 Mikrocomputer GmbH&Co. KG
-0006EB Global Data
-0006EC M/A COM Private Radio System Inc.
-0006ED Inara Networks
-0006EE Shenyang Neu-era Information & Technology Stock Co., Ltd
-0006EF Maxxan Systems, Inc.
-0006F0 Digeo, Inc.
-0006F1 Optillion
-0006F2 Platys Communications
-0006F3 AcceLight Networks
-0006F4 Prime Electronics & Satellitics Inc.
-0006F9 Mitsui Zosen Systems Research Inc.
-0006FA IP SQUARE Co, Ltd.
-0006FB Hitachi Printing Solutions, Ltd.
-0006FC Fnet Co., Ltd.
-0006FD Comjet Information Systems Corp.
-0006FE Celion Networks, Inc.
-0006FF Sheba Systems Co., Ltd.
-000700 Zettamedia Korea
-000701 RACAL-DATACOM
-000702 Varian Medical Systems
-000703 CSEE Transport
-000705 Endress & Hauser GmbH & Co
-000706 Sanritz Corporation
-000707 Interalia Inc.
-000708 Bitrage Inc.
-000709 Westerstrand Urfabrik AB
-00070A Unicom Automation Co., Ltd.
-00070B Octal, SA
-00070C SVA-Intrusion.com Co. Ltd.
-00070D Cisco Systems Inc.
-00070E Cisco Systems Inc.
-00070F Fujant, Inc.
-000710 Adax, Inc.
-000711 Acterna
-000712 JAL Information Technology
-000713 IP One, Inc.
-000714 Brightcom
-000715 General Research of Electronics, Inc.
-000716 J & S Marine Ltd.
-000717 Wieland Electric GmbH
-000718 iCanTek Co., Ltd.
-000719 Mobiis Co., Ltd.
-00071A Finedigital Inc.
-00071B Position Technology Inc.
-00071C AT&T Fixed Wireless Services
-00071D Satelsa Sistemas Y Aplicaciones De Telecomunicaciones, S.A.
-00071E Tri-M Engineering / Nupak Dev. Corp.
-00071F European Systems Integration
-000720 Trutzschler GmbH & Co. KG
-000721 Formac Elektronik GmbH
-000722 Nielsen Media Research
-000723 ELCON Systemtechnik GmbH
-000724 Telemax Co., Ltd.
-000725 Bematech International Corp.
-000727 Zi Corporation (HK) Ltd.
-000728 Neo Telecom
-000729 Kistler Instrumente AG
-00072A Innovance Networks
-00072B Jung Myung Telecom Co., Ltd.
-00072C Fabricom
-00072D CNSystems
-00072E North Node AB
-00072F Instransa, Inc.
-000730 Hutchison OPTEL Telecom Technology Co., Ltd.
-000731 Spiricon, Inc.
-000732 AAEON Technology Inc.
-000733 DANCONTROL Engineering
-000734 ONStor, Inc.
-000735 Flarion Technologies, Inc.
-000736 Data Video Technologies Co., Ltd.
-000737 Soriya Co. Ltd.
-000738 Young Technology Co., Ltd.
-000739 Motion Media Technology Ltd.
-00073A Inventel Systemes
-00073B Tenovis GmbH & Co KG
-00073C Telecom Design
-00073D Nanjing Postel Telecommunications Co., Ltd.
-00073E China Great-Wall Computer Shenzhen Co., Ltd.
-00073F Woojyun Systec Co., Ltd.
-000740 Melco Inc.
-000741 Sierra Automated Systems
-000742 Current Technologies
-000743 Chelsio Communications
-000744 Unico, Inc.
-000745 Radlan Computer Communications Ltd.
-000746 Interlink BT, LLC
-000747 Mecalc
-000748 The Imaging Source Europe
-000749 CENiX Inc.
-00074A Carl Valentin GmbH
-00074B Daihen Corporation
-00074C Beicom Inc.
-00074D Zebra Technologies Corp.
-00074E Naughty boy co., Ltd.
-00074F Cisco Systems, Inc.
-000750 Cisco Systems, Inc.
-000751 m.u.t. - GmbH
-000752 Rhythm Watch Co., Ltd.
-000753 Beijing Qxcomm Technology Co., Ltd.
-000754 Xyterra Computing, Inc.
-000755 Lafon SA
-000756 Juyoung Telecom
-000757 Topcall International AG
-000758 Dragonwave
-000759 Boris Manufacturing Corp.
-00075A Air Products and Chemicals, Inc.
-00075B Gibson Guitars
-00075C ENCAD, Inc.
-00075D Celleritas Inc.
-00075E Pulsar Technologies, Inc.
-00075F VCS Video Communication Systems AG
-000760 TOMIS Information & Telecom Corp.
-000761 Logitech SA
-000762 Group Sense Limited
-000763 Sunniwell Cyber Tech. Co., Ltd.
-000764 YoungWoo Telecom Co. Ltd.
-000765 Jade Quantum Technologies, Inc.
-000766 Chou Chin Industrial Co., Ltd.
-000767 Yuxing Electronics Company Limited
-000768 Danfoss A/S
-000769 Italiana Macchi SpA
-00076A NEXTEYE Co., Ltd.
-00076B Stralfors AB
-00076C Daehanet, Inc.
-00076D Flexlight Networks
-00076E Sinetica Corporation Ltd.
-00076F Synoptics Limited
-000770 Locusnetworks Corporation
-000771 Embedded System Corporation
-000772 Alcatel Shanghai Bell Co., Ltd.
-000773 Ascom Powerline Communications Ltd.
-000774 GuangZhou Thinker Technology Co. Ltd.
-000775 Valence Semiconductor, Inc.
-000776 Federal APD
-000777 Motah Ltd.
-000778 GERSTEL GmbH & Co. KG
-000779 Sungil Telecom Co., Ltd.
-00077A Infoware System Co., Ltd.
-00077B Millimetrix Broadband Networks
-00077C OnTime Networks
-00077E Elrest GmbH
-00077F J Communications Co., Ltd.
-000780 Bluegiga Technologies OY
-000781 Itron Inc.
-000782 Nauticus Networks, Inc.
-000783 SynCom Network, Inc.
-000784 Cisco Systems Inc.
-000785 Cisco Systems Inc.
-000786 Wireless Networks Inc.
-000787 Idea System Co., Ltd.
-000788 Clipcomm, Inc.
-000789 Eastel Systems Corporation
-00078A Mentor Data System Inc.
-00078B Wegener Communications, Inc.
-00078C Elektronikspecialisten i Borlange AB
-00078D NetEngines Ltd.
-00078E Garz & Friche GmbH
-00078F Emkay Innovative Products
-000790 Tri-M Technologies (s) Limited
-000791 International Data Communications, Inc.
-000792 Suetron Electronic GmbH
-000794 Simple Devices, Inc.
-000795 Elitegroup Computer System Co. (ECS)
-000796 LSI Systems, Inc.
-000797 Netpower Co., Ltd.
-000798 Selea SRL
-000799 Tipping Point Technologies, Inc.
-00079A SmartSight Networks Inc.
-00079B Aurora Networks
-00079C Golden Electronics Technology Co., Ltd.
-00079D Musashi Co., Ltd.
-00079E Ilinx Co., Ltd.
-00079F Action Digital Inc.
-0007A0 e-Watch Inc.
-0007A1 VIASYS Healthcare GmbH
-0007A2 Opteon Corporation
-0007A3 Ositis Software, Inc.
-0007A4 GN Netcom Ltd.
-0007A5 Y.D.K Co. Ltd.
-0007A6 Home Automation, Inc.
-0007A7 A-Z Inc.
-0007A8 Haier Group Technologies Ltd.
-0007A9 Novasonics
-0007AA Quantum Data Inc.
-0007AC Eolring
-0007AD Pentacon GmbH Foto-und Feinwerktechnik
-0007AE Layer N Networks
-0007AF N-Tron Corp.
-0007B0 Office Details, Inc.
-0007B1 Equator Technologies
-0007B2 Transaccess S.A.
-0007B3 Cisco Systems Inc.
-0007B4 Cisco Systems Inc.
-0007B5 Any One Wireless Ltd.
-0007B6 Telecom Technology Ltd.
-0007B7 Samurai Ind. Prods Eletronicos Ltda
-0007B8 American Predator Corp.
-0007B9 Ginganet Corporation
-0007BA Xebeo Communications, Inc.
-0007BB Candera Inc.
-0007BC Identix Inc.
-0007BD Radionet Ltd.
-0007BE DataLogic SpA
-0007BF Armillaire Technologies, Inc.
-0007C0 NetZerver Inc.
-0007C1 Overture Networks, Inc.
-0007C2 Netsys Telecom
-0007C3 Cirpack
-0007C4 JEAN Co. Ltd.
-0007C5 Gcom, Inc.
-0007C6 VDS Vosskuhler GmbH
-0007C7 Synectics Systems Limited
-0007C8 Brain21, Inc.
-0007C9 Technol Seven Co., Ltd.
-0007CA Creatix Polymedia Ges Fur Kommunikaitonssysteme
-0007CB Freebox SA
-0007CC Kaba Benzing GmbH
-0007CD NMTEL Co., Ltd.
-0007CE Cabletime Limited
-0007CF Anoto AB
-0007D0 Automat Engenharia de Automaoa Ltda.
-0007D1 Spectrum Signal Processing Inc.
-0007D2 Logopak Systeme
-0007D3 Stork Digital Imaging B.V.
-0007D4 Zhejiang Yutong Network Communication Co Ltd.
-0007D5 3e Technologies Int;., Inc.
-0007D6 Commil Ltd.
-0007D7 Caporis Networks AG
-0007D8 Hitron Systems Inc.
-0007D9 Splicecom
-0007DA Neuro Telecom Co., Ltd.
-0007DB Kirana Networks, Inc.
-0007DC Atek Co, Ltd.
-0007DD Cradle Technologies
-0007DE eCopilt AB
-0007DF Vbrick Systems Inc.
-0007E0 Palm Inc.
-0007E1 WIS Communications Co. Ltd.
-0007E2 Bitworks, Inc.
-0007E3 Navcom Technology, Inc.
-0007E4 SoftRadio Co., Ltd.
-0007E5 Coup Corporation
-0007E6 edgeflow Canada Inc.
-0007E7 FreeWave Technologies
-0007E8 St. Bernard Software
-0007E9 Intel Corporation
-0007EA Massana, Inc.
-0007EB Cisco Systems Inc.
-0007EC Cisco Systems Inc.
-0007ED Altera Corporation
-0007EE telco Informationssysteme GmbH
-0007EF Lockheed Martin Tactical Systems
-0007F0 LogiSync Corporation
-0007F1 TeraBurst Networks Inc.
-0007F2 IOA Corporation
-0007F3 Think Engine Networks
-0007F4 Eletex Co., Ltd.
-0007F5 Bridgeco Co AG
-0007F6 Qqest Software Systems
-0007F7 Galtronics
-0007F8 ITDevices, Inc.
-0007F9 Phonetics, Inc.
-0007FA ITT Co., Ltd.
-0007FB Giga Stream UMTS Technologies GmbH
-0007FC Adept Systems Inc.
-0007FD LANergy Ltd.
-0007FE Rigaku Corporation
-0007FF Gluon Networks
-000800 MULTITECH SYSTEMS, INC.
-000801 HighSpeed Surfing Inc.
-000802 Compaq Computer Corporation
-000803 Cos Tron
-000804 ICA Inc.
-000805 Techno-Holon Corporation
-000806 Raonet Systems, Inc.
-000807 Access Devices Limited
-000808 PPT Vision, Inc.
-000809 Systemonic AG
-00080A Espera-Werke GmbH
-00080B Birka BPA Informationssystem AB
-00080C VDA elettronica SrL
-00080D Toshiba
-00080E Motorola, BCS
-00080F Proximion Fiber Optics AB
-000810 Key Technology, Inc.
-000811 VOIX Corporation
-000812 GM-2 Corporation
-000813 Diskbank, Inc.
-000814 TIL Technologies
-000815 CATS Co., Ltd.
-000816 Bluetags A/S
-000817 EmergeCore Networks LLC
-000818 Pixelworks, Inc.
-000819 Banksys
-00081A Sanrad Intelligence Storage Communications (2000) Ltd.
-00081B Windigo Systems
-00081C @pos.com
-00081D Ipsil, Incorporated
-00081E Repeatit AB
-00081F Pou Yuen Tech Corp. Ltd.
-000820 Cisco Systems Inc.
-000821 Cisco Systems Inc.
-000822 InPro Comm
-000823 Texa Corp.
-000824 Promatek Industries Ltd.
-000825 Acme Packet
-000826 Colorado Med Tech
-000827 Pirelli Cables & Systems
-000828 Koei Engineering Ltd.
-000829 Aval Nagasaki Corporation
-00082A Powerwallz Network Security
-00082B Wooksung Electronics, Inc.
-00082C Homag AG
-00082D Indus Teqsite Private Limited
-00082E Multitone Electronics PLC
-00084E DivergeNet, Inc.
-00084F Qualstar Corporation
-000850 Arizona Instrument Corp.
-000851 Canadian Bank Note Company, Ltd.
-000852 Davolink Co. Inc.
-000853 Schleicher GmbH & Co. Relaiswerke KG
-000854 Netronix, Inc.
-000855 NASA-Goddard Space Flight Center
-000856 Gamatronic Electronic Industries Ltd.
-000857 Polaris Networks, Inc.
-000858 Novatechnology Inc.
-000859 ShenZhen Unitone Electronics Co., Ltd.
-00085A IntiGate Inc.
-00085B Hanbit Electronics Co., Ltd.
-00085C Shanghai Dare Technologies Co. Ltd.
-00085D Aastra
-00085E PCO AG
-00085F Picanol N.V.
-000860 LodgeNet Entertainment Corp.
-000861 SoftEnergy Co., Ltd.
-000862 NEC Eluminant Technologies, Inc.
-000863 Entrisphere Inc.
-000864 Fasy S.p.A.
-000865 JASCOM CO., LTD
-000866 DSX Access Systems, Inc.
-000867 Uptime Devices
-000868 PurOptix
-000869 Command-e Technology Co.,Ltd.
-00086A Industrie Technik IPS GmbH
-00086B MIPSYS
-00086C Plasmon LMS
-00086D Missouri FreeNet
-00086E Hyglo AB
-00086F Resources Computer Network Ltd.
-000870 Rasvia Systems, Inc.
-000871 NORTHDATA Co., Ltd.
-000872 Sorenson Technologies, Inc.
-000873 DAP Design B.V.
-000874 Dell Computer Corp.
-000875 Acorp Electronics Corp.
-000876 SDSystem
-000877 Liebert HIROSS S.p.A.
-000878 Benchmark Storage Innovations
-000879 CEM Corporation
-00087A Wipotec GmbH
-00087B RTX Telecom A/S
-00087C Cisco Systems, Inc.
-00087D Cisco Systems Inc.
-00087E Bon Electro-Telecom Inc.
-00087F SPAUN electronic GmbH & Co. KG
-000880 BroadTel Canada Communications inc.
-000881 DIGITAL HANDS CO.,LTD.
-000882 SIGMA CORPORATION
-000883 Hewlett-Packard Company
-000884 Index Braille AB
-000885 EMS Dr. Thomas Wuensche
-000886 Hansung Teliann, Inc.
-000887 Maschinenfabrik Reinhausen GmbH
-000888 OULLIM Information Technology Inc,.
-000889 Echostar Technologies Corp
-00088A Minds@Work
-00088B Tropic Networks Inc.
-00088C Quanta Network Systems Inc.
-00088D Sigma-Links Inc.
-00088E Nihon Computer Co., Ltd.
-00088F ADVANCED DIGITAL TECHNOLOGY
-000890 AVILINKS SA
-000891 Lyan Inc.
-000892 EM Solutions
-000894 InnoVISION Multimedia Ltd.
-000895 DIRC Technologie GmbH & Co.KG
-000896 Printronix, Inc.
-000897 Quake Technologies
-000898 Gigabit Optics Corporation
-000899 Netbind, Inc.
-00089A Alcatel Microelectronics
-00089B ICP Electronics Inc.
-00089C Elecs Industry Co., Ltd.
-00089D UHD-Elektronik
-00089E Beijing Enter-Net co.LTD
-00089F EFM Networks
-0008A0 Stotz Feinmesstechnik GmbH
-0008A1 CNet Technology Inc.
-0008A2 ADI Engineering, Inc.
-0008A3 Cisco Systems
-0008A4 Cisco Systems
-0008A5 Peninsula Systems Inc.
-0008A6 Multiware & Image Co., Ltd.
-0008A7 iLogic Inc.
-0008A8 Systec Co., Ltd.
-0008A9 SangSang Technology, Inc.
-0008AA KARAM
-0008AB EnerLinx.com, Inc.
-0008AD Toyo-Linx Co., Ltd.
-0008AE Packetfront
-0008AF Novatec Corporation
-0008B0 BKtel communications GmbH
-0008B1 ProQuent Systems
-0008B2 SHENZHEN COMPASS TECHNOLOGY DEVELOPMENT CO.,LTD
-0008B3 Fastwel
-0008B4 SYSPOL
-0008B5 TAI GUEN ENTERPRISE CO., LTD
-0008B6 RouteFree, Inc.
-0008B7 HIT Incorporated
-0008B8 E.F. Johnson
-0008B9 KAON MEDIA Co., Ltd.
-0008BA Erskine Systems Ltd
-0008BB NetExcell
-0008BC Ilevo AB
-0008BD TEPG-US
-0008BE XENPAK MSA Group
-0008BF Aptus Elektronik AB
-0008C0 ASA SYSTEMS
-0008C1 Avistar Communications Corporation
-0008C2 Cisco Systems
-0008C3 Contex A/S
-0008C4 Hikari Co.,Ltd.
-0008C5 Liontech Co., Ltd.
-0008C6 Philips Consumer Communications
-0008C7 COMPAQ COMPUTER CORPORATION
-0008C8 Soneticom, Inc.
-0008C9 TechniSat Digital GmbH
-0008CA TwinHan Technology Co.,Ltd
-0008CB Zeta Broadband Inc.
-0008CC Remotec, Inc.
-0008CD With-Net Inc
-0008CF Nippon Koei Power Systems Co., Ltd.
-0008D0 Musashi Engineering Co., LTD.
-0008D1 KAREL INC.
-0008D2 ZOOM Networks Inc.
-0008D3 Hercules Technologies S.A.
-0008D4 IneoQuest Technologies, Inc
-0008D5 Vanguard Managed Solutions
-0008D6 HASSNET Inc.
-0008D7 HOW CORPORATION
-0008D8 Dowkey Microwave
-0008D9 Mitadenshi Co.,LTD
-0008DA SofaWare Technologies Ltd.
-0008DB Corrigent Systems
-0008DC Wiznet
-0008DD Telena Communications, Inc.
-0008DE 3UP Systems
-0008DF Alistel Inc.
-0008E0 ATO Technology Ltd.
-0008E1 Barix AG
-0008E2 Cisco Systems
-0008E3 Cisco Systems
-0008E4 Envenergy Inc
-0008E5 IDK Corporation
-0008E6 Littlefeet
-0008E7 SHI ControlSystems,Ltd.
-0008E8 Excel Master Ltd.
-0008E9 NextGig
-0008EA Motion Control Engineering, Inc
-0008EB ROMWin Co.,Ltd.
-0008EC Zonu, Inc.
-0008ED ST&T Instrument Corp.
-0008EE Logic Product Development
-0008EF DIBAL,S.A.
-0008F0 Next Generation Systems, Inc.
-0008F1 Voltaire
-0008F2 C&S Technology
-0008F3 WANY
-0008F4 Bluetake Technology Co., Ltd.
-0008F5 YESTECHNOLOGY Co.,Ltd.
-0008F6 SUMITOMO ELECTRIC HIGHTECHS.co.,ltd.
-0008F7 Hitachi Ltd, Semiconductor &amp; Integrated Circuits Gr
-0008F8 Guardall Ltd
-0008F9 Padcom, Inc.
-0008FA Karl E.Brinkmann GmbH
-0008FB SonoSite, Inc.
-0008FC Gigaphoton Inc.
-0008FD BlueKorea Co., Ltd.
-0008FE UNIK C&C Co.,Ltd.
-0008FF Trilogy Broadcast (Holdings) Ltd
-000900 TMT
-000901 Shenzhen Shixuntong Information & Technoligy Co
-000902 Redline Communications Inc.
-000903 Panasas, Inc
-000904 MONDIAL electronic
-000905 iTEC Technologies Ltd.
-000906 Esteem Networks
-000907 Chrysalis Development
-000908 VTech Technology Corp.
-000909 Telenor Connect A/S
-00090A SnedFar Technology Co., Ltd.
-00090B MTL Instruments PLC
-00090C Mayekawa Mfg. Co. Ltd.
-00090D LEADER ELECTRONICS CORP.
-00090E Helix Technology Inc.
-00090F Fortinet Inc.
-000910 Simple Access Inc.
-000911 Cisco Systems
-000912 Cisco Systems
-000914 COMPUTROLS INC.
-000915 CAS Corp.
-000916 Listman Home Technologies, Inc.
-000917 WEM Technology Inc
-000918 SAMSUNG TECHWIN CO.,LTD
-000919 MDS Gateways
-00091A Macat Optics & Electronics Co., Ltd.
-00091B Digital Generation Inc.
-00091C CacheVision, Inc
-00091D Proteam Computer Corporation
-00091E Firstech Technology Corp.
-00091F A&amp;D Co., Ltd.
-000920 EpoX COMPUTER CO.,LTD.
-000921 Planmeca Oy
-000922 Touchless Sensor Technology AG
-000923 Heaman System Co., Ltd
-000924 Telebau GmbH
-000925 VSN Systemen BV
-000926 YODA COMMUNICATIONS, INC.
-000927 TOYOKEIKI CO.,LTD.
-000928 Telecore Inc
-000929 Sanyo Industries (UK) Limited
-00092A MYTECS Co.,Ltd.
-00092B iQstor Networks, Inc.
-00092C Hitpoint Inc.
-00092D High Tech Computer, Corp.
-00092E B&Tech System Inc.
-00092F Akom Technology Corporation
-000930 AeroConcierge Inc.
-000931 Future Internet, Inc.
-000932 Omnilux
-000933 OPTOVALLEY Co. Ltd.
-000934 Dream-Multimedia-Tv GmbH
-000935 Sandvine Incorporated
-000936 Ipetronik GmbH & Co.KG
-000937 Inventec Appliance Corp
-000938 Allot Communications
-000939 ShibaSoku Co.,Ltd.
-00093A Molex Fiber Optics
-00093B HYUNDAI NETWORKS INC.
-00093C Jacques Technologies P/L
-00093D Newisys,Inc.
-00093E C&I Technologies
-00093F Double-Win Enterpirse CO., LTD
-000940 AGFEO GmbH & Co. KG
-000941 Allied Telesis K.K.
-000942 CRESCO, LTD.
-000943 Cisco Systems
-000944 Cisco Systems
-000945 Palmmicro Communications Inc
-000946 Cluster Labs GmbH
-000947 Aztek, Inc.
-000948 Vista Control Systems, Corp.
-000949 Glyph Technologies Inc.
-00094A Homenet Communications
-00094B FillFactory NV
-00094C Communication Weaver Co.,Ltd.
-00094D Braintree Communications Pty Ltd
-00094E BARTECH SYSTEMS INTERNATIONAL, INC
-00094F elmegt GmbH & Co. KG
-000950 Independent Storage Corporation
-000951 Apogee Instruments, Inc
-000952 Auerswald GmbH & Co. KG
-000953 Linkage System Integration Co.Ltd.
-000954 AMiT spol. s. r. o.
-000955 Young Generation International Corp.
-000956 Network Systems Group, Ltd. (NSG)
-000957 Supercaller, Inc.
-000958 INTELNET S.A.
-000959 Sitecsoft
-00095A RACEWOOD TECHNOLOGY
-00095B Netgear, Inc.
-00095C Philips Medical Systems - Cardiac and Monitoring Systems (CM
-00095D Dialogue Technology Corp.
-00095E Masstech Group Inc.
-00095F Telebyte, Inc.
-000960 YOZAN Inc.
-000961 Switchgear and Instrumentation Ltd
-000962 Filetrac AS
-000963 Dominion Lasercom Inc.
-000964 Hi-Techniques
-000966 Thales Navigation
-000967 Tachyon, Inc
-000968 TECHNOVENTURE, INC.
-000969 Meret Optical Communications
-00096A Cloverleaf Communications Inc.
-00096B IBM Corporation
-00096C Imedia Semiconductor Corp.
-00096D Powernet Technologies Corp.
-00096E GIANT ELECTRONICS LTD.
-00096F Beijing Zhongqing Elegant Tech. Corp.,Limited
-000970 Vibration Research Corporation
-000971 Time Management, Inc.
-000972 Securebase,Inc
-000973 Lenten Technology Co., Ltd.
-000974 Innopia Technologies, Inc.
-000975 fSONA Communications Corporation
-000976 Datasoft ISDN Systems GmbH
-000977 Brunner Elektronik AG
-000978 AIJI System Co., Ltd.
-000979 Advanced Television Systems Committee, Inc.
-00097A Louis Design Labs.
-00097B Cisco Systems
-00097C Cisco Systems
-00097D SecWell Networks Oy
-00097E IMI TECHNOLOGY CO., LTD
-00097F Vsecure 2000 LTD.
-000980 Power Zenith Inc.
-000981 Newport Networks
-000982 Loewe Opta GmbH
-000983 Gvision Incorporated
-000984 MyCasa Network Inc.
-000985 Auto Telecom Company
-000986 Metalink LTD.
-000987 NISHI NIPPON ELECTRIC WIRE & CABLE CO.,LTD.
-000988 Nudian Electron Co., Ltd.
-000989 VividLogic Inc.
-00098A EqualLogic Inc
-00098B Entropic Communications, Inc.
-00098C Possio AB
-00098D DCT Ltd (Digital Communication Technologies Ltd)
-00098E ipcas GmbH
-00098F Cetacean Networks
-000990 ACKSYS Communications & systems
-000991 GE Fanuc Automation Manufacturing, Inc.
-000992 InterEpoch Technology,INC.
-000993 Visteon Corporation
-000994 Cronyx Engineering
-000995 Castle Technology Ltd
-000996 RDI
-000997 Nortel Networks
-000998 Capinfo Company Limited
-000999 CP GEORGES RENAULT
-00099A ELMO COMPANY, LIMITED
-00099B Western Telematic Inc.
-00099C Naval Research Laboratory
-00099D Haliplex Communications
-00099E Testech, Inc.
-00099F VIDEX INC.
-0009A0 Microtechno Corporation
-0009A1 Telewise Communications, Inc.
-0009A2 Interface Co., Ltd.
-0009A3 Leadfly Techologies Corp. Ltd.
-0009A4 HARTEC Corporation
-0009A5 HANSUNG ELETRONIC INDUSTRIES DEVELOPMENT CO., LTD
-0009A6 Ignis Optics, Inc.
-0009A7 Bang & Olufsen A/S
-0009A8 Eastmode Pte Ltd
-0009A9 Ikanos Communications
-0009AA Data Comm for Business, Inc.
-0009AB Netcontrol Oy
-0009AC LANVOICE
-0009AD HYUNDAI SYSCOMM, INC.
-0009AE OKANO ELECTRIC CO.,LTD
-0009AF e-generis
-0009B0 Onkyo Corporation
-0009B1 Kanematsu Electronics, Ltd.
-0009B2 L&F Inc.
-0009B3 MCM Systems Ltd
-0009B4 KISAN TELECOM CO., LTD.
-0009B5 3J Tech. Co., Ltd.
-0009B6 Cisco Systems
-0009B7 Cisco Systems
-0009B8 Entise Systems
-0009B9 Action Imaging Solutions
-0009BA MAKU Informationstechik GmbH
-0009BB MathStar, Inc.
-0009BC Digital Safety Technologies Inc.
-0009BD Epygi Technologies, Ltd.
-0009BE Mamiya-OP Co.,Ltd.
-0009BF Nintendo Co.,Ltd.
-0009C0 6WIND
-0009C1 PROCES-DATA A/S
-0009C3 NETAS
-0009C4 Medicore Co., Ltd
-0009C5 KINGENE Technology Corporation
-0009C6 Visionics Corporation
-0009C7 Movistec
-0009C8 SINAGAWA TSUSHIN KEISOU SERVICE
-0009C9 BlueWINC Co., Ltd.
-0009CA iMaxNetworks(Shenzhen)Limited.
-0009CB HBrain
-0009CC Moog GmbH
-0009CD HUDSON SOFT CO.,LTD.
-0009CE SpaceBridge Semiconductor Corp.
-0009CF iAd GmbH
-0009D0 Versatel Networks
-0009D1 SERANOA NETWORKS INC
-0009D2 Mai Logic Inc.
-0009D3 Western DataCom Co., Inc.
-0009D4 Transtech Networks
-0009D5 Signal Communication, Inc.
-0009D6 KNC One GmbH
-0009D7 DC Security Products
-0009D9 Neoscale Systems, Inc
-0009DA Control Module Inc.
-0009DB eSpace
-0009DC Galaxis Technology AG
-0009DD Mavin Technology Inc.
-0009DE Samjin Information & Communications Co., Ltd.
-0009DF Vestel Komunikasyon Sanayi ve Ticaret A.S.
-0009E0 XEMICS S.A.
-0009E1 Gemtek Technology Co., Ltd.
-0009E2 Sinbon Electronics Co., Ltd.
-0009E3 Angel Iglesias S.A.
-0009E4 K Tech Infosystem Inc.
-0009E5 Hottinger Baldwin Messtechnik GmbH
-0009E6 Cyber Switching Inc.
-0009E7 ADC Techonology
-0009E8 Cisco Systems
-0009E9 Cisco Systems
-0009EA YEM Inc.
-0009EB HuMANDATA LTD.
-0009EC Daktronics, Inc.
-0009ED CipherOptics
-0009EE MEIKYO ELECTRIC CO.,LTD
-0009EF Vocera Communications
-0009F0 Shimizu Technology Inc.
-0009F1 Yamaki Electric Corporation
-0009F2 Cohu, Inc., Electronics Division
-0009F3 WELL Communication Corp.
-0009F4 Alcon Laboratories, Inc.
-0009F5 Emerson Network Power Co.,Ltd
-0009F6 Shenzhen Eastern Digital Tech Ltd.
-0009F7 SED, a division of Calian
-0009F8 UNIMO TECHNOLOGY CO., LTD.
-0009F9 ART JAPAN CO., LTD.
-0009FB Philips Medizinsysteme Boeblingen GmbH
-0009FC IPFLEX Inc.
-0009FD Ubinetics Limited
-0009FE Daisy Technologies, Inc.
-0009FF X.net 2000 GmbH
-000A00 Mediatek Corp.
-000A01 SOHOware, Inc.
-000A02 ANNSO CO., LTD.
-000A03 ENDESA SERVICIOS, S.L.
-000A04 3Com Europe Ltd
-000A05 Widax Corp.
-000A06 Teledex LLC
-000A07 WebWayOne Ltd
-000A08 ALPINE ELECTRONICS, INC.
-000A09 TaraCom Integrated Products, Inc.
-000A0A SUNIX Co., Ltd.
-000A0B Sealevel Systems, Inc.
-000A0C Scientific Research Corporation
-000A0D MergeOptics GmbH
-000A0E Invivo Research Inc.
-000A0F Ilryung Telesys, Inc
-000A10 FAST media integrations AG
-000A11 ExPet Technologies, Inc
-000A12 Azylex Technology, Inc
-000A13 Silent Witness
-000A14 TECO a.s.
-000A15 Silicon Data, Inc
-000A16 Lassen Research
-000A17 NESTAR COMMUNICATIONS, INC
-000A18 Vichel Inc.
-000A19 Valere Power, Inc.
-000A1A Imerge Ltd
-000A1B Stream Labs
-000A1C Bridge Information Co., Ltd.
-000A1D Optical Communications Products Inc.
-000A1E Red-M (Communications) Limited
-000A1F ART WARE Telecommunication Co., Ltd.
-000A20 SVA Networks, Inc.
-000A21 Integra Telecom Co. Ltd
-000A22 Amperion Inc
-000A23 Parama Networks Inc
-000A24 Octave Communications
-000A25 CERAGON NETWORKS
-000A26 CEIA S.p.A.
-000A27 Apple Computer, Inc.
-000A28 Motorola
-000A29 Pan Dacom Networking AG
-000A2A QSI Systems Inc.
-000A2B Etherstuff
-000A2C Active Tchnology Corporation
-000A2E MAPLE NETWORKS CO., LTD
-000A2F Artnix Inc.
-000A30 Johnson Controls-ASG
-000A31 HCV Wireless
-000A32 Xsido Corporation
-000A33 Sierra Logic, Inc.
-000A34 Identicard Systems Incorporated
-000A35 Xilinx
-000A36 Synelec Telecom Multimedia
-000A37 Procera Networks, Inc.
-000A38 Netlock Technologies, Inc.
-000A39 LoPA Information Technology
-000A3A J-THREE INTERNATIONAL Holding Co., Ltd.
-000A3B GCT Semiconductor, Inc
-000A3C Enerpoint Ltd.
-000A3D Elo Sistemas Eletronicos S.A.
-000A3E EADS Telecom
-000A3F Data East Corporation
-000A40 Crown Audio
-000A41 Cisco Systems
-000A42 Cisco Systems
-000A43 Chunghwa Telecom Co., Ltd.
-000A44 Avery Dennison Deutschland GmbH
-000A45 Audio-Technica Corp.
-000A46 ARO Controls SAS
-000A47 Allied Vision Technologies
-000A48 Albatron Technology
-000A49 Acopia Networks
-000A4A Targa Systems Ltd.
-000A4B DataPower Technology, Inc.
-000A4C Molecular Devices Corporation
-000A4D Noritz Corporation
-000A4E UNITEK Electronics INC.
-000A4F Brain Boxes Limited
-000A50 REMOTEK CORPORATION
-000A51 GyroSignal Technology Co., Ltd.
-000A52 Venitek Co. Ltd.
-000A53 Intronics, Incorporated
-000A54 Laguna Hills, Inc.
-000A55 MARKEM Corporation
-000A56 HITACHI Maxell Ltd.
-000A57 Hewlett-Packard Company - Standards
-000A58 Ingenieur-Buero Freyer & Siegel
-000A59 HW server
-000A5A GreenNET Technologies Co.,Ltd.
-000A5B Power-One as
-000A5C Carel s.p.a.
-000A5D PUC Founder (MSC) Berhad
-000A5E 3COM Corporation
-000A5F almedio inc.
-000A60 Autostar Technology Pte Ltd
-000A61 Cellinx Systems Inc.
-000A62 Crinis Networks, Inc.
-000A63 DHD GmbH
-000A64 Eracom Technologies
-000A65 GentechMedia.co.,ltd.
-000A66 MITSUBISHI ELECTRIC SYSTEM & SERVICE CO.,LTD.
-000A67 OngCorp
-000A68 SolarFlare Communications, Inc.
-000A69 SUNNY bell Technology Co., Ltd.
-000A6A SVM Microwaves s.r.o.
-000A6B Tadiran Telecom Business Systems LTD
-000A6C Walchem Corporation
-000A6D EKS Elektronikservice GmbH
-000A6E Broadcast Technology Limited
-000A6F ZyTera Technologies Inc.
-000A70 MPLS Forum
-000A71 Avrio Technologies, Inc
-000A72 SimpleTech, Inc.
-000A73 Scientific Atlanta
-000A74 Manticom Networks Inc.
-000A75 Cat Electronics
-000A76 Beida Jade Bird Huaguang Technology Co.,Ltd
-000A77 Bluewire Technologies LLC
-000A78 OLITEC
-000A79 corega K.K.
-000A7A Kyoritsu Electric Co., Ltd.
-000A7B Cornelius Consult
-000A7C Tecton Ltd
-000A7D Valo, Inc.
-000A7E The Advantage Group
-000A7F Teradon Industries, Inc
-000A80 Telkonet Inc.
-000A81 TEIMA Audiotex S.L.
-000A82 TATSUTA SYSTEM ELECTRONICS CO.,LTD.
-000A83 SALTO SYSTEMS S.L.
-000A84 Rainsun Enterprise Co., Ltd.
-000A85 PLAT'C2,Inc
-000A86 Lenze
-000A87 Integrated Micromachines Inc.
-000A88 InCypher S.A.
-000A89 Creval Systems, Inc.
-000A8A Cisco Systems
-000A8B Cisco Systems
-000A8C Guardware Systems Ltd.
-000A8D EUROTHERM LIMITED
-000A8E Invacom Ltd
-000A8F Aska International Inc.
-000A90 Bayside Interactive, Inc.
-000A91 HemoCue AB
-000A92 Presonus Corporation
-000A93 W2 Networks, Inc.
-000A94 ShangHai cellink CO., LTD
-000A95 Apple Computer, Inc.
-000A96 MEWTEL TECHNOLOGY INC.
-000A97 SONICblue, Inc.
-000A98 M+F Gwinner GmbH & Co
-000A99 Dataradio Inc.
-000A9A Aiptek International Inc
-000A9B Towa Meccs Corporation
-000A9C Server Technology, Inc.
-000A9D King Young Technology Co. Ltd.
-000A9E BroadWeb Corportation
-000A9F Pannaway Technologies, Inc.
-000AA0 Cedar Point Communications
-000AA1 V V S Limited
-000AA2 SYSTEK INC.
-000AA3 SHIMAFUJI ELECTRIC CO.,LTD.
-000AA4 SHANGHAI SURVEILLANCE TECHNOLOGY CO,LTD
-000AA5 MAXLINK INDUSTRIES LIMITED
-000AA6 Hochiki Corporation
-000AA7 FEI Company
-000AA8 ePipe Pty. Ltd.
-000AA9 Brooks Automation GmbH
-000AAA AltiGen Communications Inc.
-000AAB TOYOTA MACS, INC.
-000AAC TerraTec Electronic GmbH
-000AAD Stargames Corporation
-000AAE Rosemount Process Analytical
-000AAF Pipal Systems
-000AB0 LOYTEC electronics GmbH
-000AB1 GENETEC Corporation
-000AB2 Fresnel Wireless Systems
-000AB3 Fa. GIRA
-000AB4 ETIC Telecommunications
-000AB5 Digital Electronic Network
-000AB6 COMPUNETIX, INC
-000AB7 Cisco Systems
-000AB8 Cisco Systems
-000AB9 Astera Technologies Corp.
-000ABA Arcon Technology Limited
-000ABB Taiwan Secom Co,. Ltd
-000ABC Seabridge Ltd.
-000ABD Rupprecht & Patashnick Co.
-000ABE OPNET Technologies CO., LTD.
-000ABF HIROTA SS
-000AC0 Fuyoh Video Industry CO., LTD.
-000AC1 Futuretel
-000AC2 FiberHome Telecommunication Technologies CO.,LTD
-000AC3 eM Technics Co., Ltd.
-000AC4 Daewoo Teletech Co., Ltd
-000AC5 Color Kinetics
-000AC7 Unication Group
-000AC8 ZPSYS CO.,LTD. (Planning&Management)
-000AC9 Zambeel Inc
-000ACA YOKOYAMA SHOKAI CO.,Ltd.
-000ACB XPAK MSA Group
-000ACC Winnow Networks, Inc.
-000ACD Sunrich Technology Limited
-000ACE RADIANTECH, INC.
-000ACF PROVIDEO Multimedia Co. Ltd.
-000AD0 Niigata Develoment Center, F.I.T. Co., Ltd.
-000AD1 MWS
-000AD2 JEPICO Corporation
-000AD3 INITECH Co., Ltd
-000AD4 CoreBell Systems Inc.
-000AD5 Brainchild Electronic Co., Ltd.
-000AD6 BeamReach Networks
-000AD8 IPCserv Technology Corp.
-000AD9 Sony Ericsson Mobile Communications AB
-000ADB SkyPilot Network, Inc
-000ADC RuggedCom Inc.
-000ADD InSciTek Microsystems, Inc.
-000ADE Happy Communication Co., Ltd.
-000ADF Gennum Corporation
-000AE0 Fujitsu Softek
-000AE1 EG Technology
-000AE2 Binatone Electronics International, Ltd
-000AE3 YANG MEI TECHNOLOGY CO., LTD
-000AE4 Wistron Corp.
-000AE5 ScottCare Corporation
-000AE6 Elitegroup Computer System Co. (ECS)
-000AE7 ELIOP S.A.
-000AE8 Cathay Roxus Information Technology Co. LTD
-000AE9 AirVast Technology Inc.
-000AEA ADAM ELEKTRONIK LTD.STI.
-000AEB Shenzhen Tp-link Technology Co; Ltd.
-000AEC Koatsu Gas Kogyo Co., Ltd.
-000AED HARTING Vending G.m.b.H. & CO KG
-000AEE GCD Hard- & Software GmbH
-000AEF OTRUM ASA
-000AF0 SHIN-OH ELECTRONICS CO., LTD. R&D
-000AF1 Clarity Design, Inc.
-000AF2 NeoAxiom Corp.
-000AF3 Cisco Systems
-000AF4 Cisco Systems
-000AF5 Airgo Networks, Inc.
-000AF6 Computer Process Controls
-000AF7 Broadcom Corp.
-000AF8 American Telecare Inc.
-000AFA Traverse Technologies Australia
-000AFB Ambri Limited
-000AFC Core Tec Communications, LLC
-000AFD Viking Electronic Services
-000AFE NovaPal Ltd
-000AFF Kilchherr Elektronik AG
-000B00 FUJIAN START COMPUTER EQUIPMENT CO.,LTD
-000B01 DAIICHI ELECTRONICS CO., LTD.
-000B02 Dallmeier electronic
-000B03 Taekwang Industrial Co., Ltd
-000B04 Volktek Corporation
-000B05 Pacific Broadband Networks
-000B06 Motorola BCS
-000B07 Voxpath Networks
-000B08 Pillar Data Systems
-000B09 Ifoundry Systems Singapore
-000B0A dBm Optics
-000B0B Corrent Corporation
-000B0C Agile Systems Inc.
-000B0D Air2U, Inc.
-000B0E Trapeze Networks
-000B0F Nyquist Industrial Control BV
-000B10 11wave Technonlogy Co.,Ltd
-000B11 HIMEJI ABC TRADING CO.,LTD.
-000B13 ZETRON INC
-000B14 ViewSonic Corporation
-000B15 Platypus Technology
-000B16 Communication Machinery Corporation
-000B17 MKS Instruments
-000B19 Vernier Networks, Inc.
-000B1A Teltone Corporation
-000B1B Systronix, Inc.
-000B1D LayerZero Power Systems, Inc.
-000B1E KAPPA opto-electronics GmbH
-000B1F I CON Computer Co.
-000B20 Hirata corporation
-000B21 G-Star Communications Inc.
-000B22 Environmental Systems and Services
-000B23 Efficient Networks, Inc.
-000B24 AirLogic
-000B25 Aeluros
-000B26 Wetek Corporation
-000B27 Scion Corporation
-000B28 Quatech Inc.
-000B29 LG Industrial Systems Co.,Ltd.
-000B2A HOWTEL Co., Ltd.
-000B2B HOSTNET CORPORATION
-000B2C Eiki Industrial Co. Ltd.
-000B2D Danfoss Inc.
-000B2E Cal-Comp Electronics (Thailand) Public Company Limited Taipe
-000B2F bplan GmbH
-000B30 Beijing Gongye Science & Technology Co.,Ltd
-000B31 Yantai ZhiYang Scientific and technology industry CO., LTD
-000B32 VORMETRIC, INC.
-000B33 Vivato
-000B34 ShangHai Broadband Technologies CO.LTD
-000B35 Quad Bit System co., Ltd.
-000B36 Productivity Systems, Inc.
-000B37 MANUFACTURE DES MONTRES ROLEX SA
-000B38 Knuerr AG
-000B39 Keisoku Giken Co.,Ltd.
-000B3A Fortel DTV, Inc.
-000B3B devolo AG
-000B3C Cygnal Integrated Products, Inc.
-000B3D CONTAL OK Ltd.
-000B3E BittWare, Inc
-000B3F Anthology Solutions Inc.
-000B40 OpNext Inc.
-000B41 Ing. Buero Dr. Beutlhauser
-000B42 commax Co., Ltd.
-000B43 Microscan Systems, Inc.
-000B44 Concord IDea Corp.
-000B45 Cisco
-000B46 Cisco
-000B47 Advanced Energy
-000B48 sofrel
-000B49 RF-Link System Inc.
-000B4A Visimetrics (UK) Ltd
-000B4B VISIOWAVE SA
-000B4C Clarion (M) Sdn Bhd
-000B4D Emuzed
-000B4E VertexRSI Antenna Products Division
-000B4F Verifone, INC.
-000B50 Oxygnet
-000B51 Micetek International Inc.
-000B52 JOYMAX ELECTRONICS CORP.
-000B53 INITIUM Co., Ltd.
-000B54 BiTMICRO Networks, Inc.
-000B55 ADInstruments
-000B56 Cybernetics
-000B57 Silicon Laboratories
-000B58 Astronautics C.A LTD
-000B59 ScriptPro, LLC
-000B5A HyperEdge
-000B5B Rincon Research Corporation
-000B5C Newtech Co.,Ltd
-000B5D FUJITSU LIMITED
-000B5E ATMAVA Ltd
-000B5F Cisco Systems
-000B60 Cisco Systems
-000B61 Friedrich Lütze GmbH &Co.
-000B62 Ingenieurbüro Ingo Mohnen
-000B64 Kieback & Peter GmbH & Co KG
-000B65 Sy.A.C. srl
-000B66 Teralink Communications
-000B67 Topview Technology Corporation
-000B68 Addvalue Communications Pte Ltd
-000B69 Franke Finland Oy
-000B6A Asiarock Incorporation
-000B6B Wistron Neweb Corp.
-000B6C Sychip Inc.
-000B6D SOLECTRON JAPAN NAKANIIDA
-000B6E Neff Instrument Corp.
-000B6F Media Streaming Networks Inc
-000B70 Load Technology, Inc.
-000B71 Litchfield Communications Inc.
-000B72 Lawo AG
-000B73 Kodeos Communications
-000B74 Kingwave Technology Co., Ltd.
-000B75 Iosoft Ltd.
-000B76 ET&T Co. Ltd.
-000B77 Cogent Systems, Inc.
-000B78 TAIFATECH INC.
-000B79 X-COM, Inc.
-000B7B Test-Um Inc.
-000B7C Telex Communications
-000B7D SOLOMON EXTREME INTERNATIONAL LTD.
-000B7E SAGINOMIYA Seisakusho Inc.
-000B7F OmniWerks
-000B81 Kaparel Corporation
-000B82 Grandstream Networks, Inc.
-000B83 DATAWATT B.V.
-000B84 BODET
-000B85 Airespace, Inc.
-000B86 Aruba Networks
-000B87 American Reliance Inc.
-000B88 Vidisco ltd.
-000B89 Top Global Technology, Ltd.
-000B8A MITEQ Inc.
-000B8B KERAJET, S.A.
-000B8C flextronics israel
-000B8D Avvio Networks
-000B8E Ascent Corporation
-000B8F AKITA ELECTRONICS SYSTEMS CO.,LTD.
-000B90 Covaro Networks, Inc.
-000B91 Aglaia Gesellschaft für Bildverarbeitung und Kommunikation m
-000B92 Ascom Danmark A/S
-000B93 Barmag Electronic
-000B94 Digital Monitoring Products, Inc.
-000B95 eBet Gaming Systems Pty Ltd
-000B96 Innotrac Diagnostics Oy
-000B97 Matsushita Electric Industrial Co.,Ltd.
-000B98 NiceTechVision
-000B99 SensAble Technologies, Inc.
-000B9A Shanghai Ulink Telecom Equipment Co. Ltd.
-000B9B Sirius System Co, Ltd.
-000B9C TriBeam Technologies, Inc.
-000B9D TwinMOS Technologies Inc.
-000B9E Yasing Technology Corp.
-000B9F Neue ELSA GmbH
-000BA0 T&L Information Inc.
-000BA1 SYSCOM Ltd.
-000BA2 Sumitomo Electric Networks, Inc
-000BA3 Siemens AG, I&S
-000BA4 Shiron Satellite Communications Ltd. (1996)
-000BA5 Quasar Cipta Mandiri, PT
-000BA6 Miyakawa Electric Works Ltd.
-000BA7 Maranti Networks
-000BA8 HANBACK ELECTRONICS CO., LTD.
-000BAA Aiphone co.,Ltd
-000BAB Advantech Technology (CHINA) Co., Ltd.
-000BAC 3Com Europe Ltd.
-000BAD PC-PoS Inc.
-000BAE Vitals System Inc.
-000BB0 Sysnet Telematica srl
-000BB1 Super Star Technology Co., Ltd.
-000BB2 SMALLBIG TECHNOLOGY
-000BB3 RiT technologies Ltd.
-000BB4 RDC Semiconductor Inc.,
-000BB5 nStor Technologies, Inc.
-000BB6 Mototech Inc.
-000BB7 Micro Systems Co.,Ltd.
-000BB8 Kihoku Electronic Co.
-000BB9 Imsys AB
-000BBA Harmonic Broadband Access Networks
-000BBB Etin Systems Co., Ltd
-000BBC En Garde Systems, Inc.
-000BBD Connexionz Limited
-000BBE Cisco Systems
-000BBF Cisco Systems
-000BC0 China IWNComm Co., Ltd.
-000BC1 Bay Microsystems, Inc.
-000BC2 Corinex Communication Corp.
-000BC3 Multiplex, Inc.
-000BC4 BIOTRONIK GmbH & Co
-000BC5 SMC Networks, Inc.
-000BC6 ISAC, Inc.
-000BC7 ICET S.p.A.
-000BC8 AirFlow Networks
-000BC9 Electroline Equipment
-000BCA DATAVAN International Corporation
-000BCB Fagor Automation , S. Coop
-000BCC JUSAN, S.A.
-000BCD Compaq (HP)
-000BCE Free2move AB
-000BCF AGFA NDT INC.
-000BD0 XiMeta Technology Americas Inc.
-000BD1 Aeronix, Inc.
-000BD2 Remopro Technology Inc.
-000BD3 cd3o
-000BD4 Beijing Wise Technology & Science Development Co.Ltd
-000BD5 Nvergence, Inc.
-000BD6 Paxton Access Ltd
-000BD7 MBB Gelma GmbH
-000BD8 Industrial Scientific Corp.
-000BD9 General Hydrogen
-000BDA EyeCross Co.,Inc.
-000BDB Dell ESG PCBA Test
-000BDC AKCP
-000BDD TOHOKU RICOH Co., LTD.
-000BDF Shenzhen RouterD Networks Limited
-000BE0 SercoNet Ltd.
-000BE2 Lumenera Corporation
-000BE3 Key Stream Co., Ltd.
-000BE4 Hosiden Corporation
-000BE5 HIMS Korea Co., Ltd.
-000BE6 Datel Electronics
-000BE7 COMFLUX TECHNOLOGY INC.
-000BE8 AOIP
-000BEA Zultys Technologies
-000BEB Systegra AG
-000BEC NIPPON ELECTRIC INSTRUMENT, INC.
-000BED ELM Inc.
-000BEE inc.jet, Incorporated
-000BEF Code Corporation
-000BF0 MoTEX Products Co., Ltd.
-000BF1 LAP Laser Applikations
-000BF2 Chih-Kan Technology Co., Ltd.
-000BF3 BAE SYSTEMS
-000BF5 Shanghai Sibo Telecom Technology Co.,Ltd
-000BF6 Nitgen Co., Ltd
-000BF7 NIDEK CO.,LTD
-000BF8 Infinera
-000BF9 Gemstone communications, Inc.
-000BFB D-NET International Corporation
-000BFC Cisco Systems
-000BFD Cisco Systems
-000BFE CASTEL Broadband Limited
-000BFF Berkeley Camera Engineering
-000C00 BEB Industrie-Elektronik AG
-000C01 Abatron AG
-000C02 ABB Oy
-000C03 HDMI Licensing, LLC
-000C04 Tecnova
-000C05 RPA Reserch Co., Ltd.
-000C06 Nixvue Systems Pte Ltd
-000C07 Iftest AG
-000C08 HUMEX Technologies Corp.
-000C09 Hitachi IE Systems Co., Ltd
-000C0A Guangdong Province Electronic Technology Research Institute
-000C0B Broadbus Technologies
-000C0C APPRO TECHNOLOGY INC.
-000C0D Communications & Power Industries / Satcom Division
-000C0E XtremeSpectrum, Inc.
-000C0F Techno-One Co., Ltd
-000C10 PNI Corporation
-000C11 NIPPON DEMPA CO.,LTD.
-000C12 Micro-Optronic-Messtechnik GmbH
-000C13 MediaQ
-000C14 Diagnostic Instruments, Inc.
-000C15 CyberPower Systems, Inc.
-000C16 Concorde Microsystems Inc.
-000C17 AJA Video Systems Inc
-000C18 Zenisu Keisoku Inc.
-000C19 Telio Communications GmbH
-000C1A Quest Technical Solutions Inc.
-000C1B ORACOM Co, Ltd.
-000C1C MicroWeb Co., Ltd.
-000C1D Mettler & Fuchs AG
-000C1E Global Cache
-000C1F Glimmerglass Networks
-000C20 Fi WIn, Inc.
-000C21 Faculty of Science and Technology, Keio University
-000C22 Double D Electronics Ltd
-000C23 Beijing Lanchuan Tech. Co., Ltd.
-000C25 Allied Telesyn Networks
-000C26 Weintek Labs. Inc.
-000C27 Sammy Corporation
-000C28 RIFATRON
-000C29 VMware, Inc.
-000C2A OCTTEL Communication Co., Ltd.
-000C2B ELIAS Technology, Inc.
-000C2C Enwiser Inc.
-000C2D FullWave Technology Co., Ltd.
-000C2E Openet information technology(shenzhen) Co., Ltd.
-000C2F SeorimTechnology Co.,Ltd.
-000C30 Cisco
-000C31 Cisco
-000C32 Avionic Design Development GmbH
-000C33 Compucase Enterprise Co. Ltd.
-000C34 Vixen Co., Ltd.
-000C35 KaVo Dental GmbH & Co. KG
-000C36 SHARP TAKAYA ELECTRONICS INDUSTRY CO.,LTD.
-000C37 Geomation, Inc.
-000C38 TelcoBridges Inc.
-000C39 Sentinel Wireless Inc.
-000C3A Oxance
-000C3B Orion Electric Co., Ltd.
-000C3C MediaChorus, Inc.
-000C3D Glsystech Co., Ltd.
-000C3E Crest Audio
-000C3F Cogent Defence & Security Networks,
-000C40 Altech Controls
-000C41 The Linksys Group, Inc.
-000C42 Routerboard.com
-000C43 Ralink Technology, Corp.
-000C44 Automated Interfaces, Inc.
-000C45 Animation Technologies Inc.
-000C46 Allied Telesyn Inc.
-000C47 SK Teletech(R&D Planning Team)
-000C48 QoStek Corporation
-000C49 Dangaard Telecom RTC Division A/S
-000C4A Cygnus Microsystems Private Limited
-000C4B Cheops Elektronik
-000C4C Arcor AG&Co.
-000C4D ACRA CONTROL
-000C4E Winbest Technology CO,LT
-000C4F UDTech Japan Corporation
-000C50 Seagate Technology
-000C51 Scientific Technologies Inc.
-000C52 Roll Systems Inc.
-000C54 Pedestal Networks, Inc
-000C55 Microlink Communications Inc.
-000C56 Megatel Computer (1986) Corp.
-000C57 MACKIE Engineering Services Belgium BVBA
-000C58 M&S Systems
-000C59 Indyme Electronics, Inc.
-000C5A IBSmm Industrieelektronik Multimedia
-000C5B HANWANG TECHNOLOGY CO.,LTD
-000C5C GTN Systems B.V.
-000C5D CHIC TECHNOLOGY (CHINA) CORP.
-000C5F Avtec, Inc.
-000C60 ACM Systems
-000C61 AC Tech corporation DBA Advanced Digital
-000C62 ABB Automation Technology Products AB, Control
-000C63 Zenith Electronics Corporation
-000C64 X2 MSA Group
-000C65 Sunin Telecom
-000C66 Pronto Networks Inc
-000C67 OYO ELECTRIC CO.,LTD
-000C68 Oasis Semiconductor, Inc.
-000C69 National Radio Astronomy Observatory
-000C6A MBARI
-000C6B Kurz Industrie-Elektronik GmbH
-000C6C Elgato Systems LLC
-000C6D BOC Edwards
-000C6E ASUSTEK COMPUTER INC.
-000C6F Amtek system co.,LTD.
-000C70 ACC GmbH
-000C71 Wybron, Inc
-000C72 Tempearl Industrial Co., Ltd.
-000C73 TELSON ELECTRONICS CO., LTD
-000C74 RIVERTEC CORPORATION
-000C75 Oriental integrated electronics. LTD
-000C76 MICRO-STAR INTERNATIONAL CO., LTD.
-000C77 Life Racing Ltd
-000C78 In-Tech Electronics Limited
-000C79 Extel Communications P/L
-000C7A DaTARIUS Technologies GmbH
-000C7B ALPHA PROJECT Co.,Ltd.
-000C7C Internet Information Image Inc.
-000C7D TEIKOKU ELECTRIC MFG. CO., LTD
-000C7E Tellium Incorporated
-000C7F synertronixx GmbH
-000C80 Opelcomm Inc.
-000C81 Nulec Industries Pty Ltd
-000C82 NETWORK TECHNOLOGIES INC
-000C83 Logical Solutions
-000C84 Eazix, Inc.
-000C85 Cisco Systems
-000C86 Cisco Systems
-000C87 ATI
-000C88 Apache Micro Peripherals, Inc.
-000C89 AC Electric Vehicles, Ltd.
-000C8A Bose Corporation
-000C8B Connect Tech Inc
-000C8C KODICOM CO.,LTD.
-000C8D MATRIX VISION GmbH
-000C8E Mentor Engineering Inc
-000C8F Nergal s.r.l.
-000C90 Octasic Inc.
-000C91 Riverhead Networks Inc.
-000C92 WolfVision Gmbh
-000C93 Xeline Co., Ltd.
-000C94 United Electronic Industries, Inc.
-000C95 PrimeNet
-000C96 OQO, Inc.
-000C97 NV ADB TTV Technologies SA
-000C98 LETEK Communications Inc.
-000C99 HITEL LINK Co.,Ltd
-000C9A Hitech Electronics Corp.
-000C9B EE Solutions, Inc
-000C9C Chongho information & communications
-000C9D AirWalk Communications, Inc.
-000C9E MemoryLink Corp.
-000C9F NKE Corporation
-000CA0 StorCase Technology, Inc.
-000CA1 SIGMACOM Co., LTD.
-000CA2 Scopus Network Technologies Ltd
-000CA3 Rancho Technology, Inc.
-000CA4 Prompttec Product Management GmbH
-000CA6 Mintera Corporation
-000CA7 Metro (Suzhou) Technologies Co., Ltd.
-000CA8 Garuda Networks Corporation
-000CA9 Ebtron Inc.
-000CAA Cubic Transportation Systems Inc
-000CAB COMMEND International
-000CAC Citizen Watch Co., Ltd.
-000CAD BTU International
-000CAE Ailocom Oy
-000CAF TRI TERM CO.,LTD.
-000CB0 Star Semiconductor Corporation
-000CB1 Salland Engineering (Europe) BV
-000CB2 safei Co., Ltd.
-000CB3 ROUND Co.,Ltd.
-000CB4 Propagate Networks, Inc
-000CB5 Premier Technolgies, Inc
-000CB6 NANJING SEU MOBILE & INTERNET TECHNOLOGY CO.,LTD
-000CB7 Nanjing Huazhuo Electronics Co., Ltd.
-000CB8 MEDION AG
-000CB9 LEA
-000CBA Jamex
-000CBB ISKRAEMECO
-000CBC Iscutum
-000CBD Interface Masters, Inc
-000CBF Holy Stone Ent. Co., Ltd.
-000CC0 Genera Oy
-000CC1 Cooper Industries Inc.
-000CC3 BeWAN systems
-000CC4 Tiptel AG
-000CC5 Nextlink Co., Ltd.
-000CC6 Ka-Ro electronics GmbH
-000CC7 Intelligent Computer Solutions Inc.
-000CC8 Integrated Digital Systems, Inc.
-000CC9 ILWOO DATA & TECHNOLOGY CO.,LTD
-000CCA Hitachi Global Storage Technologies
-000CCB Design Combus Ltd
-000CCC Bluesoft Ltd.
-000CCD IEC - TC57
-000CCE Cisco Systems
-000CCF Cisco Systems
-000CD0 Symetrix
-000CD1 SFOM Technology Corp.
-000CD2 Schaffner EMV AG
-000CD3 Prettl Elektronik Radeberg GmbH
-000CD4 Positron Public Safety Systems inc.
-000CD5 Passave Inc.
-000CD6 PARTNER TECH
-000CD7 Nallatech Ltd
-000CD8 M. K. Juchheim GmbH & Co
-000CD9 Itcare Co., Ltd
-000CDA FreeHand Systems, Inc.
-000CDB Foundry Networks
-000CDC BECS Technology, Inc
-000CDD AOS Technologies AG
-000CDE ABB STOTZ-KONTAKT GmbH
-000CDF PULNiX America, Inc
-000CE0 Trek Diagnostics Inc.
-000CE1 The Open Group
-000CE2 Rolls-Royce
-000CE3 Option International N.V.
-000CE4 NeuroCom International, Inc.
-000CE5 Motorola BCS
-000CE6 Meru Networks Inc
-000CE7 MediaTek Inc.
-000CE8 GuangZhou AnJuBao Co., Ltd
-000CE9 BLOOMBERG L.P.
-000CEA aphona Kommunikationssysteme
-000CEB CNMP Networks, Inc.
-000CEC Spectracom Corp.
-000CED Real Digital Media
-000CEE Q-Networks
-000CEF Open Networks Engineering Ltd
-000CF0 M & N GmbH
-000CF1 Intel Corporation
-000CF2 GAMESA EÓLICA
-000CF3 CALL IMAGE SA
-000CF4 AKATSUKI ELECTRIC MFG.CO.,LTD.
-000CF5 InfoExpress
-000CF6 Sitecom Europe BV
-000CF7 Nortel Networks
-000CF8 Nortel Networks
-000CF9 ITT Flygt AB
-000CFA Digital Systems Corp
-000CFB Korea Network Systems
-000CFC S2io Technologies Corp
-000CFE Grand Electronic Co., Ltd
-000CFF MRO-TEK LIMITED
-000D00 Seaway Networks Inc.
-000D01 P&E Microcomputer Systems, Inc.
-000D02 NEC Access Technica,Ltd
-000D03 Matrics, Inc.
-000D04 Foxboro Eckardt Development GmbH
-000D05 cybernet manufacturing inc.
-000D06 Compulogic Limited
-000D07 Calrec Audio Ltd
-000D08 AboveCable, Inc.
-000D09 Yuehua(Zhuhai) Electronic CO. LTD
-000D0A Projectiondesign as
-000D0B Melco Inc.
-000D0C MDI Security Systems
-000D0D ITSupported, LLC
-000D0E Inqnet Systems, Inc.
-000D0F Finlux Ltd
-000D10 Embedtronics Oy
-000D11 DENTSPLY - Gendex
-000D12 AXELL Corporation
-000D13 Wilhelm Rutenbeck GmbH&Co.
-000D14 Vtech Innovation LP dba Advanced American Telephones
-000D15 Voipac s.r.o.
-000D16 UHS Systems Pty Ltd
-000D17 Turbo Networks Co.Ltd
-000D18 Sunitec Enterprise Co., Ltd.
-000D19 ROBE Show lighting
-000D1A Mustek System Inc.
-000D1B Kyoto Electronics Manufacturing Co., Ltd.
-000D1C I2E TELECOM
-000D1D HIGH-TEK HARNESS ENT. CO., LTD.
-000D1E Control Techniques
-000D1F AV Digital
-000D20 ASAHIKASEI TECHNOSYSTEM CO.,LTD.
-000D21 WISCORE Inc.
-000D22 Unitronics
-000D23 Smart Solution, Inc
-000D24 SENTEC E&E CO., LTD.
-000D25 SANDEN CORPORATION
-000D26 Primagraphics Limited
-000D27 MICROPLEX Printware AG
-000D28 Cisco
-000D29 Cisco
-000D2A Scanmatic AS
-000D2B Racal Instruments
-000D2C Patapsco Designs Ltd
-000D2D NCT Deutschland GmbH
-000D2E Matsushita Avionics Systems Corporation
-000D2F AIN Comm.Tech.Co., LTD
-000D30 IceFyre Semiconductor
-000D31 Compellent Technologies, Inc.
-000D32 DispenseSource, Inc.
-000D33 Prediwave Corp.
-000D34 Shell International Exploration and Production, Inc.
-000D35 PAC International Ltd
-000D36 Wu Han Routon Electronic Co., Ltd
-000D37 WIPLUG
-000D38 NISSIN INC.
-000D39 Network Electronics
-000D3A Microsoft Corp.
-000D3B Microelectronics Technology Inc.
-000D3C i.Tech Dynamic Ltd
-000D3E APLUX Communications Ltd.
-000D3F VXI Technology
-000D40 Verint Loronix Video Solutions
-000D41 Siemens AG ICM MP UC RD IT KLF1
-000D42 Newbest Development Limited
-000D43 DRS Tactical Systems Inc.
-000D45 Tottori SANYO Electric Co., Ltd.
-000D46 Eurotherm Drives, Ltd.
-000D47 Collex
-000D48 AEWIN Technologies Co., Ltd.
-000D49 Triton Systems of Delaware, Inc.
-000D4A Steag ETA-Optik
-000D4B Roku, LLC
-000D4C Outline Electronics Ltd.
-000D4D Ninelanes
-000D4E NDR Co.,LTD.
-000D4F Kenwood Corporation
-000D50 Galazar Networks
-000D51 DIVR Systems, Inc.
-000D52 Comart system
-000D53 Beijing 5w Communication Corp.
-000D54 3Com Europe Ltd
-000D55 SANYCOM Technology Co.,Ltd
-000D56 Dell PCBA Test
-000D57 Fujitsu I-Network Systems Limited.
-000D59 Amity Systems, Inc.
-000D5A Tiesse SpA
-000D5B Smart Empire Investments Limited
-000D5C Robert Bosch GmbH, VT-ATMO
-000D5D Raritan Computer, Inc
-000D5E NEC CustomTechnica, Ltd.
-000D5F Minds Inc
-000D60 IBM Corporation
-000D61 Giga-Byte Technology Co., Ltd.
-000D62 Funkwerk Dabendorf GmbH
-000D63 DENT Instruments, Inc.
-000D64 COMAG Handels AG
-000D65 Cisco Systems
-000D66 Cisco Systems
-000D67 BelAir Networks Inc.
-000D68 Vinci Systems, Inc.
-000D69 TMT&D Corporation
-000D6A Redwood Technologies LTD
-000D6B Mita-Teknik A/S
-000D6C M-Audio
-000D6D K-Tech Devices Corp.
-000D6E K-Patents Oy
-000D6F Ember Corporation
-000D70 Datamax Corporation
-000D71 boca systems
-000D72 2Wire, Inc
-000D73 Technical Support, Inc.
-000D74 Sand Network Systems, Inc.
-000D75 Kobian Pte Ltd - Taiwan Branch
-000D76 Hokuto Denshi Co,. Ltd.
-000D77 FalconStor Software
-000D78 Engineering & Security
-000D79 Dynamic Solutions Co,.Ltd.
-000D7A DiGATTO Asia Pacific Pte Ltd
-000D7B Consensys Computers Inc.
-000D7C Codian Ltd
-000D7D Afco Systems
-000D7E Axiowave Networks, Inc.
-000D7F MIDAS COMMUNICATION TECHNOLOGIES PTE LTD ( Foreign Branch)
-000D80 Online Development Inc
-000D81 Pepperl+Fuchs GmbH
-000D82 PHS srl
-000D83 Sanmina-SCI Hungary Ltd.
-000D84 Seodu Inchip, Inc.
-000D85 Tapwave, Inc.
-000D86 Huber + Suhner AG
-000D87 Elitegroup Computer System Co. (ECS)
-000D88 D-Link Corporation
-000D89 Bils Technology Inc
-000D8A Winners Electronics Co., Ltd.
-000D8B T&D Corporation
-000D8C Shanghai Wedone Digital Ltd. CO.
-000D8D ProLinx Communication Gateways, Inc.
-000D8E Koden Electronics Co., Ltd.
-000D8F King Tsushin Kogyo Co., LTD.
-000D90 Factum Electronics AB
-000D91 Eclipse (HQ Espana) S.L.
-000D92 Arima Communication Corporation
-000D93 Apple Computer
-000D94 AFAR Communications,Inc
-000D96 Vtera Technology Inc.
-000D97 Tropos Networks, Inc.
-000D98 S.W.A.C. Schmitt-Walter Automation Consult GmbH
-000D99 Orbital Sciences Corp.; Launch Systems Group
-000D9A INFOTEC LTD
-000D9C Elan GmbH & Co KG
-000D9D Hewlett Packard
-000D9E TOKUDEN OHIZUMI SEISAKUSYO Co.,Ltd.
-000D9F RF Micro Devices
-000DA0 NEDAP N.V.
-000DA1 MIRAE ITS Co.,LTD.
-000DA2 Infrant Technologies, Inc.
-000DA3 Emerging Technologies Limited
-000DA4 DOSCH & AMAND SYSTEMS AG
-000DA5 Fabric7 Systems, Inc
-000DA6 Universal Switching Corporation
-000DA8 Teletronics Technology Corporation
-000DA9 T.E.A.M. S.L.
-000DAA S.A.Tehnology co.,Ltd.
-000DAB Parker Hannifin GmbH Electromechanical Division Europe
-000DAC Japan CBM Corporation
-000DAD Dataprobe Inc
-000DAE SAMSUNG HEAVY INDUSTRIES CO., LTD.
-000DAF Plexus Corp (UK) Ltd
-000DB0 Olym-tech Co.,Ltd.
-000DB1 Japan Network Service Co., Ltd.
-000DB2 Ammasso, Inc.
-000DB3 SDO Communication Corperation
-000DB4 NETASQ
-000DB5 GLOBALSAT TECHNOLOGY CORPORATION
-000DB6 Teknovus, Inc.
-000DB7 SANKO ELECTRIC CO,.LTD
-000DB8 SCHILLER AG
-000DB9 PC Engines GmbH
-000DBA Océ Document Technologies GmbH
-000DBB Nippon Dentsu Co.,Ltd.
-000DBC Cisco Systems
-000DBD Cisco Systems
-000DBE Bel Fuse Europe Ltd.,UK
-000DBF TekTone Sound & Signal Mfg., Inc.
-000DC0 Spagat AS
-000DC1 SafeWeb Inc
-000DC3 First Communication, Inc.
-000DC4 Emcore Corporation
-000DC5 EchoStar International Corporation
-000DC6 DigiRose Technology Co., Ltd.
-000DC7 COSMIC ENGINEERING INC.
-000DC8 AirMagnet, Inc
-000DC9 THALES Elektronik Systeme GmbH
-000DCA Tait Electronics
-000DCB Petcomkorea Co., Ltd.
-000DCC NEOSMART Corp.
-000DCD GROUPE TXCOM
-000DCE Dynavac Technology Pte Ltd
-000DCF Cidra Corp.
-000DD0 TetraTec Instruments GmbH
-000DD1 Stryker Corporation
-000DD2 Simrad Optronics ASA
-000DD3 SAMWOO Telecommunication Co.,Ltd.
-000DD4 Revivio Inc.
-000DD5 O'RITE TECHNOLOGY CO.,LTD
-000DD7 Bright
-000DD8 BBN
-000DD9 Anton Paar GmbH
-000DDA ALLIED TELESIS K.K.
-000DDB AIRWAVE TECHNOLOGIES INC.
-000DDC VAC
-000DDD PROFÝLO TELRA ELEKTRONÝK SANAYÝ VE TÝCARET A.Þ.
-000DDE Joyteck Co., Ltd.
-000DDF Japan Image & Network Inc.
-000DE0 ICPDAS Co.,LTD
-000DE1 Control Products, Inc.
-000DE2 CMZ Sistemi Elettronici
-000DE3 AT Sweden AB
-000DE4 DIGINICS, Inc.
-000DE5 Samsung Thales
-000DE6 YOUNGBO ENGINEERING CO.,LTD
-000DE7 Snap-on OEM Group
-000DE8 Nasaco Electronics Pte. Ltd
-000DE9 Napatech Aps
-000DEA Kingtel Telecommunication Corp.
-000DEB CompXs Limited
-000DEC Cisco Systems
-000DED Cisco Systems
-000DEF Soc. Coop. Bilanciai
-000DF0 QCOM TECHNOLOGY INC.
-000DF1 IONIX INC.
-000DF3 Asmax Solutions
-000DF4 Watertek Co.
-000DF5 Teletronics International Inc.
-000DF6 Technology Thesaurus Corp.
-000DF7 Space Dynamics Lab
-000DF8 ORGA Kartensysteme GmbH
-000DF9 NDS Limited
-000DFA Micro Control Systems Ltd.
-000DFB Komax AG
-000DFC ITFOR Inc. resarch and development
-000DFD Huges Hi-Tech Inc.,
-000DFE Hauppauge Computer Works, Inc.
-000DFF CHENMING MOLD INDUSTRY CORP.
-000E01 ASIP Technologies Inc.
-000E02 Advantech AMT Inc.
-000E03 Aarohi Communications, Inc.
-000E05 WIRELESS MATRIX CORP.
-000E06 Team Simoco Ltd
-000E07 Sony Ericsson Mobile Communications AB
-000E08 Sipura Technology, Inc.
-000E09 Shenzhen Coship Software Co.,LTD.
-000E0B Netac Technology Co., Ltd.
-000E0C Intel Corporation
-000E0D HESCH Schröder GmbH
-000E0E ESA elettronica S.P.A.
-000E0F ERMME
-000E11 BDT Büro- und Datentechnik GmbH & Co. KG
-000E12 Adaptive Micro Systems Inc.
-000E13 Accu-Sort Systems inc.
-000E14 Visionary Solutions, Inc.
-000E15 Tadlys LTD
-000E16 SouthWing
-000E18 MyA Technology
-000E19 LogicaCMG Pty Ltd
-000E1B IAV GmbH
-000E1C Hach Company
-000E1F TCL Networks Equipment Co., Ltd.
-000E20 PalmSource, Inc.
-000E21 MTU Friedrichshafen GmbH
-000E23 Incipient, Inc.
-000E25 Hannae Technology Co., Ltd
-000E26 Gincom Technology Corp.
-000E27 Crere Networks, Inc.
-000E28 Dynamic Ratings P/L
-000E29 Shester Communications Inc
-000E2B Safari Technologies
-000E2C Netcodec co.
-000E2D Hyundai Digital Technology Co.,Ltd.
-000E2E Edimax Technology Co., Ltd.
-000E2F Disetronic Medical Systems AG
-000E30 AERAS Networks, Inc.
-000E31 Olympus BioSystems GmbH
-000E32 Kontron Medical
-000E33 Shuko Electronics Co.,Ltd
-000E34 NexxGenCity
-000E35 Intel Corp
-000E36 HEINESYS, Inc.
-000E37 Harms & Wende GmbH & Co.KG
-000E38 Cisco Systems
-000E39 Cisco Systems
-000E3A Cirrus Logic
-000E3B Hawking Technologies, Inc.
-000E3C TransAct Technoloiges Inc.
-000E3D Televic N.V.
-000E3E Sun Optronics Inc
-000E3F Soronti, Inc.
-000E40 Nortel Networks
-000E41 NIHON MECHATRONICS CO.,LTD.
-000E42 Motic Incoporation Ltd.
-000E43 G-Tek Electronics Sdn. Bhd.
-000E44 Digital 5, Inc.
-000E45 Beijing Newtry Electronic Technology Ltd
-000E46 Niigata Seimitsu Co.,Ltd.
-000E47 NCI System Co.,Ltd.
-000E48 Lipman TransAction Solutions
-000E49 Forsway Scandinavia AB
-000E4A Changchun Huayu WEBPAD Co.,LTD
-000E4B atrium c and i
-000E4C Bermai Inc.
-000E4D Numesa Inc.
-000E4E Waveplus Technology Co., Ltd.
-000E4F Trajet GmbH
-000E50 Thomson Multi Media
-000E51 tecna elettronica srl
-000E52 Optium Corporation
-000E53 AV TECH CORPORATION
-000E54 AlphaCell Wireless Ltd.
-000E55 AUVITRAN
-000E56 4G Systems GmbH
-000E57 Iworld Networking, Inc.
-000E58 Rincon Networks
-000E5A TELEFIELD inc.
-000E5B ParkerVision - Direct2Data
-000E5C Motorola BCS
-000E5D Com-X Networks
-000E5E Beijing Raisecom Science & Technology Development Co.,Ltd
-000E5F activ-net GmbH & Co. KG
-000E60 360SUN Digital Broadband Corporation
-000E61 MICROTROL LIMITED
-000E62 Nortel Networks
-000E63 Lemke Diagnostics GmbH
-000E64 Elphel, Inc
-000E65 TransCore
-000E66 Hitachi Advanced Digital, Inc.
-000E67 Eltis Microelectronics Ltd.
-000E68 E-TOP Network Technology Inc.
-000E69 China Electric Power Research Institute
-000E6A 3COM EUROPE LTD
-000E6B Janitza electronics GmbH
-000E6C Device Drivers Limited
-000E6D Murata Manufacturing Co., Ltd.
-000E6E MICRELEC ELECTRONICS S.A
-000E6F IRIS Corporation Berhad
-000E70 in2 Networks
-000E71 Gemstar Technology Development Ltd.
-000E72 CTS electronics
-000E73 Tpack A/S
-000E74 Solar Telecom. Tech
-000E75 New York Air Brake Corp.
-000E76 GEMSOC INNOVISION INC.
-000E77 Decru, Inc.
-000E78 Amtelco
-000E79 Ample Communications Inc.
-000E7B Toshiba
-000E7D Electronics Line 3000 Ltd.
-000E7E Comprog Oy
-000E7F Hewlett Packard
-000E81 Instant802 Networks Inc.
-000E82 Commtech Wireless
-000E83 Cisco Systems
-000E84 Cisco Systems
-000E85 Catalyst Enterprises, Inc.
-000E86 Alcatel North America
-000E87 adp Gauselmann GmbH
-000E88 VIDEOTRON CORP.
-000E89 CLEMATIC
-000E8A Avara Technologies Pty. Ltd.
-000E8B Astarte Technology Co, Ltd.
-000E8C Siemens AG A&D ET
-000E8D Systems in Progress Holding GmbH
-000E8E SparkLAN Communications, Inc.
-000E8F Sercomm Corp.
-000E90 PONICO CORP.
-000E92 Millinet Co., Ltd.
-000E93 Milénio 3 Sistemas Electrónicos, Lda.
-000E94 Maas International BV
-000E95 Fujiya Denki Seisakusho Co.,Ltd.
-000E96 Cubic Defense Applications, Inc.
-000E97 Ultracker Technology CO., Inc
-000E98 Vitec CC, INC.
-000E99 Spectrum Digital, Inc
-000E9A BOE TECHNOLOGY GROUP CO.,LTD
-000E9C Pemstar
-000E9D Video Networks Ltd
-000E9E Topfield Co., Ltd
-000E9F TEMIC SDS GmbH
-000EA0 NetKlass Technology Inc.
-000EA1 Formosa Teletek Corporation
-000EA2 CyberGuard Corporation
-000EA3 CNCR-IT CO.,LTD,HangZhou P.R.CHINA
-000EA4 Certance Inc.
-000EA5 BLIP Systems
-000EA6 ASUSTEK COMPUTER INC.
-000EA7 Endace Inc Ltd.
-000EA8 United Technologists Europe Limited
-000EA9 Shanghai Xun Shi Communications Equipment Ltd. Co.
-000EAC MINTRON ENTERPRISE CO., LTD.
-000EAD Metanoia Technologies, Inc.
-000EAE GAWELL TECHNOLOGIES CORP.
-000EAF CASTEL
-000EB0 Solutions Radio BV
-000EB1 Newcotech,Ltd
-000EB2 Micro-Research Finland Oy
-000EB3 LeftHand Networks
-000EB4 GUANGZHOU GAOKE COMMUNICATIONS TECHNOLOGY CO.LTD.
-000EB5 Ecastle Electronics Co., Ltd.
-000EB6 Riverbed Technology, Inc.
-000EB7 Knovative, Inc.
-000EB8 Iiga co.,Ltd
-000EB9 HASHIMOTO Electronics Industry Co.,Ltd.
-000EBA HANMI SEMICONDUCTOR CO., LTD.
-000EBB Everbee Networks
-000EBC Cullmann GmbH
-000EBD Burdick, a Quinton Compny
-000EBE B&B Electronics Manufacturing Co.
-000EC0 Nortel Networks
-000EC1 MYNAH Technologies
-000EC2 Lowrance Electronics, Inc.
-000EC3 Logic Controls, Inc.
-000EC4 Iskra Transmission d.d.
-000EC6 ASIX ELECTRONICS CORP.
-000EC7 Appeal Telecom Co.,Ltd.
-000EC8 Zoran Corporation
-000EC9 YOKO Technology Corp.
-000ECB VineSys Technology
-000ECC Tableau
-000ECD SKOV A/S
-000ECE S.I.T.T.I. S.p.A.
-000ECF PROFIBUS Nutzerorganisation e.V.
-000ED0 Privaris, Inc.
-000ED1 Osaka Micro Computer.
-000ED2 Filtronic plc
-000ED3 Epicenter, Inc.
-000ED4 CRESITT INDUSTRIE
-000ED5 COPAN Systems Inc.
-000ED6 Cisco Systems
-000ED7 Cisco Systems
-000ED8 Aktino, Inc.
-000ED9 Aksys, Ltd.
-000EDA C-TECH UNITED CORP.
-000EDB XiNCOM Corp.
-000EDC Tellion INC.
-000EDD SHURE INCORPORATED
-000EDE REMEC, Inc.
-000EDF PLX Technology
-000EE0 Mcharge
-000EE1 ExtremeSpeed Inc.
-000EE2 Custom Engineering S.p.A.
-000EE3 Chiyu Technology Co.,Ltd
-000EE5 bitWallet, Inc.
-000EE6 Adimos Systems LTD
-000EE7 AAC ELECTRONICS CORP.
-000EE8 zioncom
-000EE9 WayTech Development, Inc.
-000EEA Shadong Luneng Jicheng Electronics,Co.,Ltd
-000EEB Sandmartin(zhong shan)Electronics Co.,Ltd
-000EEC Orban
-000EED Nokia Danmark A/S
-000EEE Muco Industrie BV
-000EF0 Festo AG & Co. KG
-000EF1 EZQUEST INC.
-000EF3 Smarthome
-000EF4 Shenzhen Kasda Digital Technology Co.,Ltd
-000EF5 iPAC Technology Co., Ltd.
-000EF6 E-TEN Information Systems Co., Ltd.
-000EF7 Vulcan Portals Inc
-000EF8 SBC ASI
-000EF9 REA Elektronik GmbH
-000EFA Optoway Technology Incorporation
-000EFB Macey Enterprises
-000EFC JTAG Technologies B.V.
-000EFD FUJI PHOTO OPTICAL CO., LTD.
-000EFE EndRun Technologies LLC
-000EFF Megasolution,Inc.
-000F00 Legra Systems, Inc.
-000F01 DIGITALKS INC
-000F02 Digicube Technology Co., Ltd
-000F03 COM&C CO., LTD
-000F04 cim-usa inc
-000F05 3B SYSTEM INC.
-000F06 Nortel Networks
-000F07 Mangrove Systems, Inc.
-000F08 Indagon Oy
-000F0B Kentima Technologies AB
-000F0C SYNCHRONIC ENGINEERING
-000F0D Hunt Electronic Co., Ltd.
-000F0E WaveSplitter Technologies, Inc.
-000F0F Real ID Technology Co., Ltd.
-000F10 RDM Corporation
-000F11 Prodrive B.V.
-000F12 Panasonic AVC Networks Germany GmbH
-000F13 Nisca corporation
-000F14 Mindray Co., Ltd.
-000F15 Kjaerulff1 A/S
-000F16 JAY HOW TECHNOLOGY CO.,
-000F17 Insta Elektro GmbH
-000F18 Industrial Control Systems
-000F19 Guidant Corporation
-000F1A Gaming Support B.V.
-000F1B Ego Systems Inc.
-000F1C DigitAll World Co., Ltd
-000F1D Cosmo Techs Co., Ltd.
-000F1E Chengdu KT Electric Co.of High & New Technology
-000F1F WW PCBA Test
-000F20 WW Ops
-000F21 Scientific Atlanta, Inc
-000F22 Helius, Inc.
-000F23 Cisco Systems
-000F24 Cisco Systems
-000F25 AimValley B.V.
-000F26 WorldAccxx LLC
-000F27 TEAL Electronics, Inc.
-000F28 Itronix Corporation
-000F29 Augmentix Corporation
-000F2A Cableware Electronics
-000F2B GREENBELL SYSTEMS
-000F2C Uplogix, Inc.
-001000 CABLE TELEVISION LABORATORIES, INC.
-001001 MCK COMMUNICATIONS
-001002 ACTIA
-001003 IMATRON, INC.
-001004 THE BRANTLEY COILE COMPANY,INC
-001005 UEC COMMERCIAL
-001006 Thales Contact Solutions Ltd.
-001007 CISCO SYSTEMS, INC.
-001008 VIENNA SYSTEMS CORPORATION
-001009 HORO QUARTZ
-00100A WILLIAMS COMMUNICATIONS GROUP
-00100B CISCO SYSTEMS, INC.
-00100C ITO CO., LTD.
-00100D CISCO SYSTEMS, INC.
-00100E MICRO LINEAR COPORATION
-00100F INDUSTRIAL CPU SYSTEMS
-001010 INITIO CORPORATION
-001011 CISCO SYSTEMS, INC.
-001012 PROCESSOR SYSTEMS (I) PVT LTD
-001013 INDUSTRIAL COMPUTER SOURCE
-001014 CISCO SYSTEMS, INC.
-001015 OOmon Inc.
-001016 T.SQWARE
-001017 MICOS GmbH
-001018 BROADCOM CORPORATION
-001019 SIRONA DENTAL SYSTEMS GmbH & Co. KG
-00101A PictureTel Corp.
-00101B CORNET TECHNOLOGY, INC.
-00101C OHM TECHNOLOGIES INTL, LLC
-00101D WINBOND ELECTRONICS CORP.
-00101E MATSUSHITA ELECTRONIC INSTRUMENTS CORP.
-00101F CISCO SYSTEMS, INC.
-001020 WELCH ALLYN, DATA COLLECTION
-001021 ENCANTO NETWORKS, INC.
-001022 SatCom Media Corporation
-001023 FLOWWISE NETWORKS, INC.
-001024 NAGOYA ELECTRIC WORKS CO., LTD
-001025 GRAYHILL INC.
-001026 ACCELERATED NETWORKS, INC.
-001027 L-3 COMMUNICATIONS EAST
-001028 COMPUTER TECHNICA, INC.
-001029 CISCO SYSTEMS, INC.
-00102A ZF MICROSYSTEMS, INC.
-00102B UMAX DATA SYSTEMS, INC.
-00102C Lasat Networks A/S
-00102D HITACHI SOFTWARE ENGINEERING
-00102E NETWORK SYSTEMS & TECHNOLOGIES PVT. LTD.
-00102F CISCO SYSTEMS, INC.
-001030 Wi-LAN, Inc.
-001031 OBJECTIVE COMMUNICATIONS, INC.
-001032 ALTA TECHNOLOGY
-001033 ACCESSLAN COMMUNICATIONS, INC.
-001034 GNP Computers
-001035 ELITEGROUP COMPUTER SYSTEMS CO., LTD
-001036 INTER-TEL INTEGRATED SYSTEMS
-001037 CYQ've Technology Co., Ltd.
-001038 MICRO RESEARCH INSTITUTE, INC.
-001039 Vectron Systems AG
-00103A DIAMOND NETWORK TECH
-00103B HIPPI NETWORKING FORUM
-00103C IC ENSEMBLE, INC.
-00103D PHASECOM, LTD.
-00103E NETSCHOOLS CORPORATION
-00103F TOLLGRADE COMMUNICATIONS, INC.
-001040 INTERMEC CORPORATION
-001041 BRISTOL BABCOCK, INC.
-001042 AlacriTech
-001043 A2 CORPORATION
-001044 InnoLabs Corporation
-001045 Nortel Networks
-001046 ALCORN MCBRIDE INC.
-001047 ECHO ELETRIC CO. LTD.
-001048 HTRC AUTOMATION, INC.
-001049 SHORELINE TELEWORKS, INC.
-00104A THE PARVUC CORPORATION
-00104B 3COM CORPORATION
-00104C COMPUTER ACCESS TECHNOLOGY
-00104D SURTEC INDUSTRIES, INC.
-00104E CEOLOGIC
-00104F STORAGE TECHNOLOGY CORPORATION
-001050 RION CO., LTD.
-001051 CMICRO CORPORATION
-001052 METTLER-TOLEDO (ALBSTADT) GMBH
-001053 COMPUTER TECHNOLOGY CORP.
-001054 CISCO SYSTEMS, INC.
-001055 FUJITSU MICROELECTRONICS, INC.
-001056 SODICK CO., LTD.
-001057 Rebel.com, Inc.
-001058 ArrowPoint Communications
-001059 DIABLO RESEARCH CO. LLC
-00105A 3COM CORPORATION
-00105B NET INSIGHT AB
-00105C QUANTUM DESIGNS (H.K.) LTD.
-00105D Draeger Medical
-00105E HEKIMIAN LABORATORIES, INC.
-00105F IN-SNEC
-001060 BILLIONTON SYSTEMS, INC.
-001061 HOSTLINK CORP.
-001062 NX SERVER, ILNC.
-001063 STARGUIDE DIGITAL NETWORKS
-001064 DIGITAL EQUIPMENT CORP.
-001065 RADYNE CORPORATION
-001066 ADVANCED CONTROL SYSTEMS, INC.
-001067 REDBACK NETWORKS, INC.
-001068 COMOS TELECOM
-001069 HELIOSS COMMUNICATIONS, INC.
-00106A DIGITAL MICROWAVE CORPORATION
-00106B SONUS NETWORKS, INC.
-00106C INFRATEC PLUS GmbH
-00106D INTEGRITY COMMUNICATIONS, INC.
-00106E TADIRAN COM. LTD.
-00106F TRENTON TECHNOLOGY INC.
-001070 CARADON TREND LTD.
-001071 ADVANET INC.
-001072 GVN TECHNOLOGIES, INC.
-001073 TECHNOBOX, INC.
-001074 ATEN INTERNATIONAL CO., LTD.
-001075 Maxtor Corporation
-001076 EUREM GmbH
-001077 SAF DRIVE SYSTEMS, LTD.
-001078 NUERA COMMUNICATIONS, INC.
-001079 CISCO SYSTEMS, INC.
-00107A AmbiCom, Inc.
-00107B CISCO SYSTEMS, INC.
-00107C P-COM, INC.
-00107D AURORA COMMUNICATIONS, LTD.
-00107E BACHMANN ELECTRONIC GmbH
-00107F CRESTRON ELECTRONICS, INC.
-001080 METAWAVE COMMUNICATIONS
-001081 DPS, INC.
-001082 JNA TELECOMMUNICATIONS LIMITED
-001083 HEWLETT-PACKARD COMPANY
-001084 K-BOT COMMUNICATIONS
-001085 POLARIS COMMUNICATIONS, INC.
-001086 ATTO TECHNOLOGY, INC.
-001087 Xstreamis PLC
-001088 AMERICAN NETWORKS INC.
-001089 WebSonic
-00108A TeraLogic, Inc.
-00108B LASERANIMATION SOLLINGER GmbH
-00108C FUJITSU TELECOMMUNICATIONS EUROPE, LTD.
-00108D JOHNSON CONTROLS, INC.
-00108E HUGH SYMONS CONCEPT Technologies Ltd.
-00108F RAPTOR SYSTEMS
-001090 CIMETRICS, INC.
-001091 NO WIRES NEEDED BV
-001092 NETCORE INC.
-001093 CMS COMPUTERS, LTD.
-001094 Performance Analysis Broadband, Spirent plc
-001095 Thomson Multimedia, Inc.
-001096 TRACEWELL SYSTEMS, INC.
-001097 WinNet Metropolitan Communications Systems, Inc.
-001098 STARNET TECHNOLOGIES, INC.
-001099 InnoMedia, Inc.
-00109A NETLINE
-00109B VIXEL CORPORATION
-00109C M-SYSTEM CO., LTD.
-00109D CLARINET SYSTEMS, INC.
-00109E AWARE, INC.
-00109F PAVO, INC.
-0010A0 INNOVEX TECHNOLOGIES, INC.
-0010A1 KENDIN SEMICONDUCTOR, INC.
-0010A2 TNS
-0010A3 OMNITRONIX, INC.
-0010A4 XIRCOM
-0010A5 OXFORD INSTRUMENTS
-0010A6 CISCO SYSTEMS, INC.
-0010A7 UNEX TECHNOLOGY CORPORATION
-0010A8 RELIANCE COMPUTER CORP.
-0010A9 ADHOC TECHNOLOGIES
-0010AA MEDIA4, INC.
-0010AB KOITO INDUSTRIES, LTD.
-0010AC IMCI TECHNOLOGIES
-0010AD SOFTRONICS USB, INC.
-0010AE SHINKO ELECTRIC INDUSTRIES CO.
-0010AF TAC SYSTEMS, INC.
-0010B0 MERIDIAN TECHNOLOGY CORP.
-0010B1 FOR-A CO., LTD.
-0010B2 COACTIVE AESTHETICS
-0010B3 NOKIA MULTIMEDIA TERMINALS
-0010B4 ATMOSPHERE NETWORKS
-0010B5 ACCTON TECHNOLOGY CORPORATION
-0010B6 ENTRATA COMMUNICATIONS CORP.
-0010B7 COYOTE TECHNOLOGIES, LLC
-0010B8 ISHIGAKI COMPUTER SYSTEM CO.
-0010B9 MAXTOR CORP.
-0010BA MARTINHO-DAVIS SYSTEMS, INC.
-0010BB DATA & INFORMATION TECHNOLOGY
-0010BC Aastra Telecom
-0010BD THE TELECOMMUNICATION TECHNOLOGY COMMITTEE
-0010BE TELEXIS CORP.
-0010BF InterAir Wireless
-0010C0 ARMA, INC.
-0010C1 OI ELECTRIC CO., LTD.
-0010C2 WILLNET, INC.
-0010C3 CSI-CONTROL SYSTEMS
-0010C4 MEDIA LINKS CO., LTD.
-0010C5 PROTOCOL TECHNOLOGIES, INC.
-0010C6 USI
-0010C7 DATA TRANSMISSION NETWORK
-0010C8 COMMUNICATIONS ELECTRONICS SECURITY GROUP
-0010C9 MITSUBISHI ELECTRONICS LOGISTIC SUPPORT CO.
-0010CA INTEGRAL ACCESS
-0010CB FACIT K.K.
-0010CC CLP COMPUTER LOGISTIK PLANUNG GmbH
-0010CD INTERFACE CONCEPT
-0010CE VOLAMP, LTD.
-0010CF FIBERLANE COMMUNICATIONS
-0010D0 WITCOM, LTD.
-0010D1 Top Layer Networks, Inc.
-0010D2 NITTO TSUSHINKI CO., LTD
-0010D3 GRIPS ELECTRONIC GMBH
-0010D4 STORAGE COMPUTER CORPORATION
-0010D5 IMASDE CANARIAS, S.A.
-0010D6 ITT - A/CD
-0010D7 ARGOSY RESEARCH INC.
-0010D8 CALISTA
-0010D9 IBM JAPAN, FUJISAWA MT+D
-0010DA MOTION ENGINEERING, INC.
-0010DB NetScreen Technologies, Inc.
-0010DC MICRO-STAR INTERNATIONAL CO., LTD.
-0010DD ENABLE SEMICONDUCTOR, INC.
-0010DE INTERNATIONAL DATACASTING CORPORATION
-0010DF RISE COMPUTER INC.
-0010E0 COBALT MICROSERVER, INC.
-0010E1 S.I. TECH, INC.
-0010E2 ArrayComm, Inc.
-0010E3 COMPAQ COMPUTER CORPORATION
-0010E4 NSI CORPORATION
-0010E5 SOLECTRON TEXAS
-0010E6 APPLIED INTELLIGENT SYSTEMS, INC.
-0010E7 BreezeCom
-0010E8 TELOCITY, INCORPORATED
-0010E9 RAIDTEC LTD.
-0010EA ADEPT TECHNOLOGY
-0010EB SELSIUS SYSTEMS, INC.
-0010EC RPCG, LLC
-0010ED SUNDANCE TECHNOLOGY, INC.
-0010EE CTI PRODUCTS, INC.
-0010EF DBTEL INCORPORATED
-0010F1 I-O CORPORATION
-0010F2 ANTEC
-0010F3 Nexcom International Co., Ltd.
-0010F4 VERTICAL NETWORKS, INC.
-0010F5 AMHERST SYSTEMS, INC.
-0010F6 CISCO SYSTEMS, INC.
-0010F7 IRIICHI TECHNOLOGIES Inc.
-0010F8 KENWOOD TMI CORPORATION
-0010F9 UNIQUE SYSTEMS, INC.
-0010FA ZAYANTE, INC.
-0010FB ZIDA TECHNOLOGIES LIMITED
-0010FC BROADBAND NETWORKS, INC.
-0010FD COCOM A/S
-0010FE DIGITAL EQUIPMENT CORPORATION
-0010FF CISCO SYSTEMS, INC.
-001C7C PERQ SYSTEMS CORPORATION
-002000 LEXMARK INTERNATIONAL, INC.
-002001 DSP SOLUTIONS, INC.
-002002 SERITECH ENTERPRISE CO., LTD.
-002003 PIXEL POWER LTD.
-002004 YAMATAKE-HONEYWELL CO., LTD.
-002005 SIMPLE TECHNOLOGY
-002006 GARRETT COMMUNICATIONS, INC.
-002007 SFA, INC.
-002008 CABLE & COMPUTER TECHNOLOGY
-002009 PACKARD BELL ELEC., INC.
-00200A SOURCE-COMM CORP.
-00200B OCTAGON SYSTEMS CORP.
-00200C ADASTRA SYSTEMS CORP.
-00200D CARL ZEISS
-00200E SATELLITE TECHNOLOGY MGMT, INC
-00200F TANBAC CO., LTD.
-002010 JEOL SYSTEM TECHNOLOGY CO. LTD
-002011 CANOPUS CO., LTD.
-002012 CAMTRONICS MEDICAL SYSTEMS
-002013 DIVERSIFIED TECHNOLOGY, INC.
-002014 GLOBAL VIEW CO., LTD.
-002015 ACTIS COMPUTER SA
-002016 SHOWA ELECTRIC WIRE & CABLE CO
-002017 ORBOTECH
-002018 CIS TECHNOLOGY INC.
-002019 OHLER GmbH
-00201A N-BASE SWITCH COMMUNICATIONS
-00201B NORTHERN TELECOM/NETWORK
-00201C EXCEL, INC.
-00201D KATANA PRODUCTS
-00201E NETQUEST CORPORATION
-00201F BEST POWER TECHNOLOGY, INC.
-002020 MEGATRON COMPUTER INDUSTRIES PTY, LTD.
-002021 ALGORITHMS SOFTWARE PVT. LTD.
-002022 TEKNIQUE, INC.
-002023 T.C. TECHNOLOGIES PTY. LTD
-002024 PACIFIC COMMUNICATION SCIENCES
-002025 CONTROL TECHNOLOGY, INC.
-002026 AMKLY SYSTEMS, INC.
-002027 MING FORTUNE INDUSTRY CO., LTD
-002028 WEST EGG SYSTEMS, INC.
-002029 TELEPROCESSING PRODUCTS, INC.
-00202A N.V. DZINE
-00202B ADVANCED TELECOMMUNICATIONS MODULES, LTD.
-00202C WELLTRONIX CO., LTD.
-00202D TAIYO CORPORATION
-00202E DAYSTAR DIGITAL
-00202F ZETA COMMUNICATIONS, LTD.
-002030 ANALOG & DIGITAL SYSTEMS
-002031 ERTEC GmbH
-002032 ALCATEL TAISEL
-002033 SYNAPSE TECHNOLOGIES, INC.
-002034 ROTEC INDUSTRIEAUTOMATION GMBH
-002035 IBM CORPORATION
-002036 BMC SOFTWARE
-002037 SEAGATE TECHNOLOGY
-002038 VME MICROSYSTEMS INTERNATIONAL CORPORATION
-002039 SCINETS
-00203A DIGITAL BI0METRICS INC.
-00203B WISDM LTD.
-00203C EUROTIME AB
-00203D NOVAR ELECTRONICS CORPORATION
-00203E LogiCan Technologies, Inc.
-00203F JUKI CORPORATION
-002040 Motorola Broadband Communications Sector
-002041 DATA NET
-002042 DATAMETRICS CORP.
-002043 NEURON COMPANY LIMITED
-002044 GENITECH PTY LTD
-002045 ION Networks, Inc.
-002046 CIPRICO, INC.
-002047 STEINBRECHER CORP.
-002048 Marconi Communications
-002049 COMTRON, INC.
-00204A PRONET GMBH
-00204B AUTOCOMPUTER CO., LTD.
-00204C MITRON COMPUTER PTE LTD.
-00204D INOVIS GMBH
-00204E NETWORK SECURITY SYSTEMS, INC.
-00204F DEUTSCHE AEROSPACE AG
-002050 KOREA COMPUTER INC.
-002051 Verilink Corporation
-002052 RAGULA SYSTEMS
-002053 HUNTSVILLE MICROSYSTEMS, INC.
-002054 EASTERN RESEARCH, INC.
-002055 ALTECH CO., LTD.
-002056 NEOPRODUCTS
-002057 TITZE DATENTECHNIK GmbH
-002058 ALLIED SIGNAL INC.
-002059 MIRO COMPUTER PRODUCTS AG
-00205A COMPUTER IDENTICS
-00205B SKYLINE TECHNOLOGY
-00205C InterNet Systems of Florida, Inc.
-00205D NANOMATIC OY
-00205E CASTLE ROCK, INC.
-00205F GAMMADATA COMPUTER GMBH
-002060 ALCATEL ITALIA S.p.A.
-002061 DYNATECH COMMUNICATIONS, INC.
-002062 SCORPION LOGIC, LTD.
-002063 WIPRO INFOTECH LTD.
-002064 PROTEC MICROSYSTEMS, INC.
-002065 SUPERNET NETWORKING INC.
-002066 GENERAL MAGIC, INC.
-002068 ISDYNE
-002069 ISDN SYSTEMS CORPORATION
-00206A OSAKA COMPUTER CORP.
-00206B KONICA MINOLTA HOLDINGS, INC.
-00206C EVERGREEN TECHNOLOGY CORP.
-00206D DATA RACE, INC.
-00206E XACT, INC.
-00206F FLOWPOINT CORPORATION
-002070 HYNET, LTD.
-002071 IBR GMBH
-002072 WORKLINK INNOVATIONS
-002073 FUSION SYSTEMS CORPORATION
-002074 SUNGWOON SYSTEMS
-002075 MOTOROLA COMMUNICATION ISRAEL
-002076 REUDO CORPORATION
-002077 KARDIOS SYSTEMS CORP.
-002078 RUNTOP, INC.
-002079 MIKRON GMBH
-00207A WiSE Communications, Inc.
-00207B Intel Corporation
-00207C AUTEC GmbH
-00207D ADVANCED COMPUTER APPLICATIONS
-00207E FINECOM Co., Ltd.
-00207F KYOEI SANGYO CO., LTD.
-002080 SYNERGY (UK) LTD.
-002081 TITAN ELECTRONICS
-002082 ONEAC CORPORATION
-002083 PRESTICOM INCORPORATED
-002084 OCE PRINTING SYSTEMS, GMBH
-002085 EXIDE ELECTRONICS
-002086 MICROTECH ELECTRONICS LIMITED
-002087 MEMOTEC COMMUNICATIONS CORP.
-002088 GLOBAL VILLAGE COMMUNICATION
-002089 T3PLUS NETWORKING, INC.
-00208A SONIX COMMUNICATIONS, LTD.
-00208B LAPIS TECHNOLOGIES, INC.
-00208C GALAXY NETWORKS, INC.
-00208D CMD TECHNOLOGY
-00208E CHEVIN SOFTWARE ENG. LTD.
-00208F ECI TELECOM LTD.
-002090 ADVANCED COMPRESSION TECHNOLOGY, INC.
-002091 J125, NATIONAL SECURITY AGENCY
-002092 CHESS ENGINEERING B.V.
-002093 LANDINGS TECHNOLOGY CORP.
-002094 CUBIX CORPORATION
-002095 RIVA ELECTRONICS
-002096 Invensys
-002097 APPLIED SIGNAL TECHNOLOGY
-002098 HECTRONIC AB
-002099 BON ELECTRIC CO., LTD.
-00209A THE 3DO COMPANY
-00209B ERSAT ELECTRONIC GMBH
-00209C PRIMARY ACCESS CORP.
-00209D LIPPERT AUTOMATIONSTECHNIK
-00209E BROWN'S OPERATING SYSTEM SERVICES, LTD.
-00209F MERCURY COMPUTER SYSTEMS, INC.
-0020A0 OA LABORATORY CO., LTD.
-0020A1 DOVATRON
-0020A2 GALCOM NETWORKING LTD.
-0020A3 DIVICOM INC.
-0020A4 MULTIPOINT NETWORKS
-0020A5 API ENGINEERING
-0020A6 PROXIM, INC.
-0020A7 PAIRGAIN TECHNOLOGIES, INC.
-0020A8 SAST TECHNOLOGY CORP.
-0020A9 WHITE HORSE INDUSTRIAL
-0020AA DIGIMEDIA VISION LTD.
-0020AB MICRO INDUSTRIES CORP.
-0020AC INTERFLEX DATENSYSTEME GMBH
-0020AD LINQ SYSTEMS
-0020AE ORNET DATA COMMUNICATION TECH.
-0020AF 3COM CORPORATION
-0020B0 GATEWAY DEVICES, INC.
-0020B1 COMTECH RESEARCH INC.
-0020B2 GKD Gesellschaft Fur Kommunikation Und Datentechnik
-0020B3 SCLTEC COMMUNICATIONS SYSTEMS
-0020B4 TERMA ELEKTRONIK AS
-0020B5 YASKAWA ELECTRIC CORPORATION
-0020B6 AGILE NETWORKS, INC.
-0020B7 NAMAQUA COMPUTERWARE
-0020B8 PRIME OPTION, INC.
-0020B9 METRICOM, INC.
-0020BA CENTER FOR HIGH PERFORMANCE
-0020BB ZAX CORPORATION
-0020BC JTEC PTY LTD.
-0020BD NIOBRARA R & D CORPORATION
-0020BE LAN ACCESS CORP.
-0020BF AEHR TEST SYSTEMS
-0020C0 PULSE ELECTRONICS, INC.
-0020C1 TAIKO ELECTRIC WORKS, LTD.
-0020C2 TEXAS MEMORY SYSTEMS, INC.
-0020C3 COUNTER SOLUTIONS LTD.
-0020C4 INET,INC.
-0020C5 EAGLE TECHNOLOGY
-0020C6 NECTEC
-0020C7 AKAI Professional M.I. Corp.
-0020C8 LARSCOM INCORPORATED
-0020C9 VICTRON BV
-0020CA DIGITAL OCEAN
-0020CB PRETEC ELECTRONICS CORP.
-0020CC DIGITAL SERVICES, LTD.
-0020CD HYBRID NETWORKS, INC.
-0020CE LOGICAL DESIGN GROUP, INC.
-0020CF TEST & MEASUREMENT SYSTEMS INC
-0020D0 VERSALYNX CORPORATION
-0020D1 MICROCOMPUTER SYSTEMS (M) SDN.
-0020D2 RAD DATA COMMUNICATIONS, LTD.
-0020D3 OST (OUEST STANDARD TELEMATIQU
-0020D4 CABLETRON - ZEITTNET INC.
-0020D5 VIPA GMBH
-0020D6 BREEZECOM
-0020D7 JAPAN MINICOMPUTER SYSTEMS CO., Ltd.
-0020D8 Nortel Networks
-0020D9 PANASONIC TECHNOLOGIES, INC./MIECO-US
-0020DA XYLAN CORPORATION
-0020DB XNET TECHNOLOGY, INC.
-0020DC DENSITRON TAIWAN LTD.
-0020DD Cybertec Pty Ltd
-0020DE JAPAN DIGITAL LABORAT'Y CO.LTD
-0020DF KYOSAN ELECTRIC MFG. CO., LTD.
-0020E0 PREMAX ELECTRONICS, INC.
-0020E1 ALAMAR ELECTRONICS
-0020E2 INFORMATION RESOURCE ENGINEERING
-0020E3 MCD KENCOM CORPORATION
-0020E4 HSING TECH ENTERPRISE CO., LTD
-0020E5 APEX DATA, INC.
-0020E6 LIDKOPING MACHINE TOOLS AB
-0020E7 B&W NUCLEAR SERVICE COMPANY
-0020E8 DATATREK CORPORATION
-0020E9 DANTEL
-0020EA EFFICIENT NETWORKS, INC.
-0020EB CINCINNATI MICROWAVE, INC.
-0020EC TECHWARE SYSTEMS CORP.
-0020ED GIGA-BYTE TECHNOLOGY CO., LTD.
-0020EE GTECH CORPORATION
-0020EF USC CORPORATION
-0020F0 UNIVERSAL MICROELECTRONICS CO.
-0020F1 ALTOS INDIA LIMITED
-0020F2 SUN MICROSYSTEMS, INC.
-0020F3 RAYNET CORPORATION
-0020F4 SPECTRIX CORPORATION
-0020F5 PANDATEL AG
-0020F6 NET TEK AND KARLNET, INC.
-0020F7 CYBERDATA
-0020F8 CARRERA COMPUTERS, INC.
-0020F9 PARALINK NETWORKS, INC.
-0020FA GDE SYSTEMS, INC.
-0020FB OCTEL COMMUNICATIONS CORP.
-0020FC MATROX
-0020FD ITV TECHNOLOGIES, INC.
-0020FE TOPWARE INC. / GRAND COMPUTER
-0020FF SYMMETRICAL TECHNOLOGIES
-003000 ALLWELL TECHNOLOGY CORP.
-003001 SMP
-003002 Expand Networks
-003003 Phasys Ltd.
-003004 LEADTEK RESEARCH INC.
-003005 Fujitsu Siemens Computers
-003006 SUPERPOWER COMPUTER
-003007 OPTI, INC.
-003008 AVIO DIGITAL, INC.
-003009 Tachion Networks, Inc.
-00300A AZTECH SYSTEMS LTD.
-00300B mPHASE Technologies, Inc.
-00300C CONGRUENCY, LTD.
-00300D MMC Technology, Inc.
-00300E Klotz Digital AG
-00300F IMT - Information Management T
-003010 VISIONETICS INTERNATIONAL
-003011 HMS FIELDBUS SYSTEMS AB
-003012 DIGITAL ENGINEERING LTD.
-003013 NEC Corporation
-003014 DIVIO, INC.
-003015 CP CLARE CORP.
-003016 ISHIDA CO., LTD.
-003017 TERASTACK LTD.
-003018 Jetway Information Co., Ltd.
-003019 CISCO SYSTEMS, INC.
-00301A SMARTBRIDGES PTE. LTD.
-00301B SHUTTLE, INC.
-00301C ALTVATER AIRDATA SYSTEMS
-00301D SKYSTREAM, INC.
-00301E 3COM Europe Ltd.
-00301F OPTICAL NETWORKS, INC.
-003020 TSI, Inc..
-003021 HSING TECH. ENTERPRISE CO.,LTD
-003022 Fong Kai Industrial Co., Ltd.
-003023 COGENT COMPUTER SYSTEMS, INC.
-003024 CISCO SYSTEMS, INC.
-003025 CHECKOUT COMPUTER SYSTEMS, LTD
-003026 HEITEL
-003027 KERBANGO, INC.
-003028 FASE Saldatura srl
-003029 OPICOM
-00302A SOUTHERN INFORMATION
-00302B INALP NETWORKS, INC.
-00302C SYLANTRO SYSTEMS CORPORATION
-00302D QUANTUM BRIDGE COMMUNICATIONS
-00302E Hoft & Wessel AG
-00302F Smiths Industries
-003030 HARMONIX CORPORATION
-003031 LIGHTWAVE COMMUNICATIONS, INC.
-003032 MagicRam, Inc.
-003033 ORIENT TELECOM CO., LTD.
-003036 RMP ELEKTRONIKSYSTEME GMBH
-003037 Packard Bell Nec Services
-003038 XCP, INC.
-003039 SOFTBOOK PRESS
-00303A MAATEL
-00303B PowerCom Technology
-00303C ONNTO CORP.
-00303D IVA CORPORATION
-00303E Radcom Ltd.
-00303F TurboComm Tech Inc.
-003040 CISCO SYSTEMS, INC.
-003041 SAEJIN T & M CO., LTD.
-003042 DeTeWe-Deutsche Telephonwerke
-003043 IDREAM TECHNOLOGIES, PTE. LTD.
-003044 Portsmith LLC
-003045 Village Networks, Inc. (VNI)
-003046 Controlled Electronic Manageme
-003047 NISSEI ELECTRIC CO., LTD.
-003048 Supermicro Computer, Inc.
-003049 BRYANT TECHNOLOGY, LTD.
-00304A FRAUNHOFER INSTITUTE IMS
-00304B ORBACOM SYSTEMS, INC.
-00304C APPIAN COMMUNICATIONS, INC.
-00304D ESI
-00304E BUSTEC PRODUCTION LTD.
-00304F PLANET Technology Corporation
-003050 Versa Technology
-003051 ORBIT AVIONIC & COMMUNICATION
-003052 ELASTIC NETWORKS
-003053 Basler AG
-003054 CASTLENET TECHNOLOGY, INC.
-003055 Hitachi Semiconductor America,
-003056 Beck IPC GmbH
-003057 E-Tel Corporation
-003058 API MOTION
-003059 DIGITAL-LOGIC AG
-00305A TELGEN CORPORATION
-00305B MODULE DEPARTMENT
-00305C SMAR Laboratories Corp.
-00305D DIGITRA SYSTEMS, INC.
-00305E Abelko Innovation
-00305F IMACON APS
-003060 STARMATIX, INC.
-003061 MobyTEL
-003062 PATH 1 NETWORK TECHNOL'S INC.
-003063 SANTERA SYSTEMS, INC.
-003064 ADLINK TECHNOLOGY, INC.
-003065 APPLE COMPUTER, INC.
-003066 DIGITAL WIRELESS CORPORATION
-003067 BIOSTAR MICROTECH INT'L CORP.
-003068 CYBERNETICS TECH. CO., LTD.
-003069 IMPACCT TECHNOLOGY CORP.
-00306A PENTA MEDIA CO., LTD.
-00306B CMOS SYSTEMS, INC.
-00306C Hitex Holding GmbH
-00306D LUCENT TECHNOLOGIES
-00306E HEWLETT PACKARD
-00306F SEYEON TECH. CO., LTD.
-003070 1Net Corporation
-003071 Cisco Systems, Inc.
-003072 INTELLIBYTE INC.
-003073 International Microsystems, In
-003074 EQUIINET LTD.
-003075 ADTECH
-003076 Akamba Corporation
-003077 ONPREM NETWORKS
-003078 Cisco Systems, Inc.
-003079 CQOS, INC.
-00307A Advanced Technology & Systems
-00307B Cisco Systems, Inc.
-00307C ADID SA
-00307D GRE AMERICA, INC.
-00307E Redflex Communication Systems
-00307F IRLAN LTD.
-003080 CISCO SYSTEMS, INC.
-003081 ALTOS C&C
-003082 TAIHAN ELECTRIC WIRE CO., LTD.
-003083 Ivron Systems
-003084 ALLIED TELESYN INTERNAIONAL
-003085 CISCO SYSTEMS, INC.
-003086 Transistor Devices, Inc.
-003087 VEGA GRIESHABER KG
-003088 Siara Systems, Inc.
-003089 Spectrapoint Wireless, LLC
-00308A NICOTRA SISTEMI S.P.A
-00308B Brix Networks
-00308C ADVANCED DIGITAL INFORMATION
-00308D PINNACLE SYSTEMS, INC.
-00308E CROSS MATCH TECHNOLOGIES, INC.
-00308F MICRILOR, Inc.
-003090 CYRA TECHNOLOGIES, INC.
-003091 TAIWAN FIRST LINE ELEC. CORP.
-003092 ModuNORM GmbH
-003093 SONNET TECHNOLOGIES, INC.
-003094 Cisco Systems, Inc.
-003095 Procomp Informatics, Ltd.
-003096 CISCO SYSTEMS, INC.
-003097 EXOMATIC AB
-003098 Global Converging Technologies
-003099 BOENIG UND KALLENBACH OHG
-00309A ASTRO TERRA CORP.
-00309B Smartware
-00309C Timing Applications, Inc.
-00309D Nimble Microsystems, Inc.
-00309E WORKBIT CORPORATION.
-00309F AMBER NETWORKS
-0030A0 TYCO SUBMARINE SYSTEMS, LTD.
-0030A1 WEBGATE Inc.
-0030A2 Lightner Engineering
-0030A3 CISCO SYSTEMS, INC.
-0030A4 Woodwind Communications System
-0030A5 ACTIVE POWER
-0030A6 VIANET TECHNOLOGIES, LTD.
-0030A7 SCHWEITZER ENGINEERING
-0030A8 OL'E COMMUNICATIONS, INC.
-0030A9 Netiverse, Inc.
-0030AA AXUS MICROSYSTEMS, INC.
-0030AB DELTA NETWORKS, INC.
-0030AC Systeme Lauer GmbH & Co., Ltd.
-0030AD SHANGHAI COMMUNICATION
-0030AE Times N System, Inc.
-0030AF Honeywell GmbH
-0030B0 Convergenet Technologies
-0030B1 GOC GESELLSCHAFT FUR OPTISCHE
-0030B2 WESCAM - HEALDSBURG
-0030B3 San Valley Systems, Inc.
-0030B4 INTERSIL CORP.
-0030B5 Tadiran Microwave Networks
-0030B6 CISCO SYSTEMS, INC.
-0030B7 Teletrol Systems, Inc.
-0030B8 RiverDelta Networks
-0030B9 ECTEL
-0030BA AC&T SYSTEM CO., LTD.
-0030BB CacheFlow, Inc.
-0030BC Optronic AG
-0030BD BELKIN COMPONENTS
-0030BE City-Net Technology, Inc.
-0030BF MULTIDATA GMBH
-0030C0 Lara Technology, Inc.
-0030C1 HEWLETT-PACKARD
-0030C2 COMONE
-0030C3 FLUECKIGER ELEKTRONIK AG
-0030C4 Niigata Canotec Co., Inc.
-0030C5 CADENCE DESIGN SYSTEMS
-0030C6 CONTROL SOLUTIONS, INC.
-0030C7 MACROMATE CORP.
-0030C8 GAD LINE, LTD.
-0030C9 LuxN, N
-0030CA Discovery Com
-0030CB OMNI FLOW COMPUTERS, INC.
-0030CC Tenor Networks, Inc.
-0030CD CONEXANT SYSTEMS, INC.
-0030CE Zaffire
-0030CF TWO TECHNOLOGIES, INC.
-0030D1 INOVA CORPORATION
-0030D2 WIN TECHNOLOGIES, CO., LTD.
-0030D3 Agilent Technologies
-0030D4 COMTIER
-0030D5 DResearch GmbH
-0030D6 MSC VERTRIEBS GMBH
-0030D7 Innovative Systems, L.L.C.
-0030D8 SITEK
-0030D9 DATACORE SOFTWARE CORP.
-0030DA COMTREND CO.
-0030DB Mindready Solutions, Inc.
-0030DC RIGHTECH CORPORATION
-0030DD INDIGITA CORPORATION
-0030DE WAGO Kontakttechnik GmbH
-0030DF KB/TEL TELECOMUNICACIONES
-0030E0 OXFORD SEMICONDUCTOR LTD.
-0030E1 ACROTRON SYSTEMS, INC.
-0030E2 GARNET SYSTEMS CO., LTD.
-0030E3 SEDONA NETWORKS CORP.
-0030E4 CHIYODA SYSTEM RIKEN
-0030E5 Amper Datos S.A.
-0030E6 SIEMENS MEDICAL SYSTEMS
-0030E7 CNF MOBILE SOLUTIONS, INC.
-0030E8 ENSIM CORP.
-0030E9 GMA COMMUNICATION MANUFACT'G
-0030EA TeraForce Technology Corporation
-0030EB TURBONET COMMUNICATIONS, INC.
-0030EC BORGARDT
-0030ED Expert Magnetics Corp.
-0030EE DSG Technology, Inc.
-0030EF NEON TECHNOLOGY, INC.
-0030F0 Uniform Industrial Corp.
-0030F1 Accton Technology Corp.
-0030F2 CISCO SYSTEMS, INC.
-0030F3 At Work Computers
-0030F4 STARDOT TECHNOLOGIES
-0030F5 Wild Lab. Ltd.
-0030F6 SECURELOGIX CORPORATION
-0030F7 RAMIX INC.
-0030F8 Dynapro Systems, Inc.
-0030F9 Sollae Systems Co., Ltd.
-0030FA TELICA, INC.
-0030FB AZS Technology AG
-0030FC Terawave Communications, Inc.
-0030FD INTEGRATED SYSTEMS DESIGN
-0030FE DSA GmbH
-0030FF DATAFAB SYSTEMS, INC.
-004000 PCI COMPONENTES DA AMZONIA LTD
-004001 ZYXEL COMMUNICATIONS, INC.
-004002 PERLE SYSTEMS LIMITED
-004003 WESTINGHOUSE PROCESS CONTROL
-004004 ICM CO. LTD.
-004005 ANI COMMUNICATIONS INC.
-004006 SAMPO TECHNOLOGY CORPORATION
-004007 TELMAT INFORMATIQUE
-004008 A PLUS INFO CORPORATION
-004009 TACHIBANA TECTRON CO., LTD.
-00400A PIVOTAL TECHNOLOGIES, INC.
-00400B CISCO SYSTEMS, INC.
-00400C GENERAL MICRO SYSTEMS, INC.
-00400D LANNET DATA COMMUNICATIONS,LTD
-00400E MEMOTEC COMMUNICATIONS, INC.
-00400F DATACOM TECHNOLOGIES
-004010 SONIC SYSTEMS, INC.
-004011 ANDOVER CONTROLS CORPORATION
-004012 WINDATA, INC.
-004013 NTT DATA COMM. SYSTEMS CORP.
-004014 COMSOFT GMBH
-004015 ASCOM INFRASYS AG
-004016 HADAX ELECTRONICS, INC.
-004017 XCD INC.
-004018 ADOBE SYSTEMS, INC.
-004019 AEON SYSTEMS, INC.
-00401A FUJI ELECTRIC CO., LTD.
-00401B PRINTER SYSTEMS CORP.
-00401C AST RESEARCH, INC.
-00401D INVISIBLE SOFTWARE, INC.
-00401E ICC
-00401F COLORGRAPH LTD
-004020 PINACL COMMUNICATION
-004021 RASTER GRAPHICS
-004022 KLEVER COMPUTERS, INC.
-004023 LOGIC CORPORATION
-004024 COMPAC INC.
-004025 MOLECULAR DYNAMICS
-004026 MELCO, INC.
-004027 SMC MASSACHUSETTS, INC.
-004028 NETCOMM LIMITED
-004029 COMPEX
-00402A CANOGA-PERKINS
-00402B TRIGEM COMPUTER, INC.
-00402C ISIS DISTRIBUTED SYSTEMS, INC.
-00402D HARRIS ADACOM CORPORATION
-00402E PRECISION SOFTWARE, INC.
-00402F XLNT DESIGNS INC.
-004030 GK COMPUTER
-004031 KOKUSAI ELECTRIC CO., LTD
-004032 DIGITAL COMMUNICATIONS
-004033 ADDTRON TECHNOLOGY CO., LTD.
-004034 BUSTEK CORPORATION
-004035 OPCOM
-004036 TRIBE COMPUTER WORKS, INC.
-004037 SEA-ILAN, INC.
-004038 TALENT ELECTRIC INCORPORATED
-004039 OPTEC DAIICHI DENKO CO., LTD.
-00403A IMPACT TECHNOLOGIES
-00403B SYNERJET INTERNATIONAL CORP.
-00403C FORKS, INC.
-00403D TERADATA
-00403E RASTER OPS CORPORATION
-00403F SSANGYONG COMPUTER SYSTEMS
-004040 RING ACCESS, INC.
-004041 FUJIKURA LTD.
-004042 N.A.T. GMBH
-004043 NOKIA TELECOMMUNICATIONS
-004044 QNIX COMPUTER CO., LTD.
-004045 TWINHEAD CORPORATION
-004046 UDC RESEARCH LIMITED
-004047 WIND RIVER SYSTEMS
-004048 SMD INFORMATICA S.A.
-004049 TEGIMENTA AG
-00404A WEST AUSTRALIAN DEPARTMENT
-00404B MAPLE COMPUTER SYSTEMS
-00404C HYPERTEC PTY LTD.
-00404D TELECOMMUNICATIONS TECHNIQUES
-00404E FLUENT, INC.
-00404F SPACE & NAVAL WARFARE SYSTEMS
-004050 IRONICS, INCORPORATED
-004051 GRACILIS, INC.
-004052 STAR TECHNOLOGIES, INC.
-004053 AMPRO COMPUTERS
-004054 CONNECTION MACHINES SERVICES
-004055 METRONIX GMBH
-004056 MCM JAPAN LTD.
-004057 LOCKHEED - SANDERS
-004058 KRONOS, INC.
-004059 YOSHIDA KOGYO K. K.
-00405A GOLDSTAR INFORMATION & COMM.
-00405B FUNASSET LIMITED
-00405C FUTURE SYSTEMS, INC.
-00405D STAR-TEK, INC.
-00405E NORTH HILLS ISRAEL
-00405F AFE COMPUTERS LTD.
-004060 COMENDEC LTD
-004061 DATATECH ENTERPRISES CO., LTD.
-004062 E-SYSTEMS, INC./GARLAND DIV.
-004063 VIA TECHNOLOGIES, INC.
-004064 KLA INSTRUMENTS CORPORATION
-004065 GTE SPACENET
-004066 HITACHI CABLE, LTD.
-004067 OMNIBYTE CORPORATION
-004068 EXTENDED SYSTEMS
-004069 LEMCOM SYSTEMS, INC.
-00406A KENTEK INFORMATION SYSTEMS,INC
-00406B SYSGEN
-00406C COPERNIQUE
-00406D LANCO, INC.
-00406E COROLLARY, INC.
-00406F SYNC RESEARCH INC.
-004070 INTERWARE CO., LTD.
-004071 ATM COMPUTER GMBH
-004072 Applied Innovation Inc.
-004073 BASS ASSOCIATES
-004074 CABLE AND WIRELESS
-004075 M-TRADE (UK) LTD
-004076 Sun Conversion Technologies
-004077 MAXTON TECHNOLOGY CORPORATION
-004078 WEARNES AUTOMATION PTE LTD
-004079 JUKO MANUFACTURE COMPANY, LTD.
-00407A SOCIETE D'EXPLOITATION DU CNIT
-00407B SCIENTIFIC ATLANTA
-00407C QUME CORPORATION
-00407D EXTENSION TECHNOLOGY CORP.
-00407E EVERGREEN SYSTEMS, INC.
-00407F FLIR Systems
-004080 ATHENIX CORPORATION
-004081 MANNESMANN SCANGRAPHIC GMBH
-004082 LABORATORY EQUIPMENT CORP.
-004083 TDA INDUSTRIA DE PRODUTOS
-004084 HONEYWELL INC.
-004085 SAAB INSTRUMENTS AB
-004086 MICHELS & KLEBERHOFF COMPUTER
-004087 UBITREX CORPORATION
-004088 MOBIUS TECHNOLOGIES, INC.
-004089 MEIDENSHA CORPORATION
-00408A TPS TELEPROCESSING SYS. GMBH
-00408B RAYLAN CORPORATION
-00408C AXIS COMMUNICATIONS AB
-00408D THE GOODYEAR TIRE & RUBBER CO.
-00408E DIGILOG, INC.
-00408F WM-DATA MINFO AB
-004090 ANSEL COMMUNICATIONS
-004091 PROCOMP INDUSTRIA ELETRONICA
-004092 ASP COMPUTER PRODUCTS, INC.
-004093 PAXDATA NETWORKS LTD.
-004094 SHOGRAPHICS, INC.
-004095 R.P.T. INTERGROUPS INT'L LTD.
-004096 Aironet Wireless Communication
-004097 DATEX DIVISION OF
-004098 DRESSLER GMBH & CO.
-004099 NEWGEN SYSTEMS CORP.
-00409A NETWORK EXPRESS, INC.
-00409B HAL COMPUTER SYSTEMS INC.
-00409C TRANSWARE
-00409D DIGIBOARD, INC.
-00409E CONCURRENT TECHNOLOGIES LTD.
-00409F LANCAST/CASAT TECHNOLOGY, INC.
-0040A0 GOLDSTAR CO., LTD.
-0040A1 ERGO COMPUTING
-0040A2 KINGSTAR TECHNOLOGY INC.
-0040A3 MICROUNITY SYSTEMS ENGINEERING
-0040A4 ROSE ELECTRONICS
-0040A5 CLINICOMP INTL.
-0040A6 Cray, Inc.
-0040A7 ITAUTEC PHILCO S.A.
-0040A8 IMF INTERNATIONAL LTD.
-0040A9 DATACOM INC.
-0040AA VALMET AUTOMATION INC.
-0040AB ROLAND DG CORPORATION
-0040AC SUPER WORKSTATION, INC.
-0040AD SMA REGELSYSTEME GMBH
-0040AE DELTA CONTROLS, INC.
-0040AF DIGITAL PRODUCTS, INC.
-0040B0 BYTEX CORPORATION, ENGINEERING
-0040B1 CODONICS INC.
-0040B2 SYSTEMFORSCHUNG
-0040B3 PAR MICROSYSTEMS CORPORATION
-0040B4 NEXTCOM K.K.
-0040B5 VIDEO TECHNOLOGY COMPUTERS LTD
-0040B6 COMPUTERM CORPORATION
-0040B7 STEALTH COMPUTER SYSTEMS
-0040B8 IDEA ASSOCIATES
-0040B9 MACQ ELECTRONIQUE SA
-0040BA ALLIANT COMPUTER SYSTEMS CORP.
-0040BB GOLDSTAR CABLE CO., LTD.
-0040BC ALGORITHMICS LTD.
-0040BD STARLIGHT NETWORKS, INC.
-0040BE BOEING DEFENSE & SPACE
-0040BF CHANNEL SYSTEMS INTERN'L INC.
-0040C0 VISTA CONTROLS CORPORATION
-0040C1 BIZERBA-WERKE WILHEIM KRAUT
-0040C2 APPLIED COMPUTING DEVICES
-0040C3 FISCHER AND PORTER CO.
-0040C4 KINKEI SYSTEM CORPORATION
-0040C5 MICOM COMMUNICATIONS INC.
-0040C6 FIBERNET RESEARCH, INC.
-0040C7 RUBY TECH CORPORATION
-0040C8 MILAN TECHNOLOGY CORPORATION
-0040C9 NCUBE
-0040CA FIRST INTERNAT'L COMPUTER, INC
-0040CB LANWAN TECHNOLOGIES
-0040CC SILCOM MANUF'G TECHNOLOGY INC.
-0040CD TERA MICROSYSTEMS, INC.
-0040CE NET-SOURCE, INC.
-0040CF STRAWBERRY TREE, INC.
-0040D0 MITAC INTERNATIONAL CORP.
-0040D1 FUKUDA DENSHI CO., LTD.
-0040D2 PAGINE CORPORATION
-0040D3 KIMPSION INTERNATIONAL CORP.
-0040D4 GAGE TALKER CORP.
-0040D5 SARTORIUS AG
-0040D6 LOCAMATION B.V.
-0040D7 STUDIO GEN INC.
-0040D8 OCEAN OFFICE AUTOMATION LTD.
-0040D9 AMERICAN MEGATRENDS INC.
-0040DA TELSPEC LTD
-0040DB ADVANCED TECHNICAL SOLUTIONS
-0040DC TRITEC ELECTRONIC GMBH
-0040DD HONG TECHNOLOGIES
-0040DE ELETTRONICA SAN GIORGIO
-0040DF DIGALOG SYSTEMS, INC.
-0040E0 ATOMWIDE LTD.
-0040E1 MARNER INTERNATIONAL, INC.
-0040E2 MESA RIDGE TECHNOLOGIES, INC.
-0040E3 QUIN SYSTEMS LTD
-0040E4 E-M TECHNOLOGY, INC.
-0040E5 SYBUS CORPORATION
-0040E6 C.A.E.N.
-0040E7 ARNOS INSTRUMENTS & COMPUTER
-0040E8 CHARLES RIVER DATA SYSTEMS,INC
-0040E9 ACCORD SYSTEMS, INC.
-0040EA PLAIN TREE SYSTEMS INC
-0040EB MARTIN MARIETTA CORPORATION
-0040EC MIKASA SYSTEM ENGINEERING
-0040ED NETWORK CONTROLS INT'NATL INC.
-0040EE OPTIMEM
-0040EF HYPERCOM, INC.
-0040F0 MICRO SYSTEMS, INC.
-0040F1 CHUO ELECTRONICS CO., LTD.
-0040F2 JANICH & KLASS COMPUTERTECHNIK
-0040F3 NETCOR
-0040F4 CAMEO COMMUNICATIONS, INC.
-0040F5 OEM ENGINES
-0040F6 KATRON COMPUTERS INC.
-0040F7 POLAROID MEDICAL IMAGING SYS.
-0040F8 SYSTEMHAUS DISCOM
-0040F9 COMBINET
-0040FA MICROBOARDS, INC.
-0040FB CASCADE COMMUNICATIONS CORP.
-0040FC IBR COMPUTER TECHNIK GMBH
-0040FD LXE
-0040FE SYMPLEX COMMUNICATIONS
-0040FF TELEBIT CORPORATION
-004252 RLX Technologies
-005000 NEXO COMMUNICATIONS, INC.
-005001 YAMASHITA SYSTEMS CORP.
-005002 OMNISEC AG
-005003 GRETAG MACBETH AG
-005004 3COM CORPORATION
-005006 TAC AB
-005007 SIEMENS TELECOMMUNICATION SYSTEMS LIMITED
-005008 TIVA MICROCOMPUTER CORP. (TMC)
-005009 PHILIPS BROADBAND NETWORKS
-00500A IRIS TECHNOLOGIES, INC.
-00500B CISCO SYSTEMS, INC.
-00500C e-Tek Labs, Inc.
-00500D SATORI ELECTORIC CO., LTD.
-00500E CHROMATIS NETWORKS, INC.
-00500F CISCO SYSTEMS, INC.
-005010 NovaNET Learning, Inc.
-005012 CBL - GMBH
-005013 Chaparral Network Storage
-005014 CISCO SYSTEMS, INC.
-005015 BRIGHT STAR ENGINEERING
-005016 SST/WOODHEAD INDUSTRIES
-005017 RSR S.R.L.
-005018 ADVANCED MULTIMEDIA INTERNET TECHNOLOGY INC.
-005019 SPRING TIDE NETWORKS, INC.
-00501A UISIQN
-00501B ABL CANADA, INC.
-00501C JATOM SYSTEMS, INC.
-00501E Miranda Technologies, Inc.
-00501F MRG SYSTEMS, LTD.
-005020 MEDIASTAR CO., LTD.
-005021 EIS INTERNATIONAL, INC.
-005022 ZONET TECHNOLOGY, INC.
-005023 PG DESIGN ELECTRONICS, INC.
-005024 NAVIC SYSTEMS, INC.
-005026 COSYSTEMS, INC.
-005027 GENICOM CORPORATION
-005028 AVAL COMMUNICATIONS
-005029 1394 PRINTER WORKING GROUP
-00502A CISCO SYSTEMS, INC.
-00502B GENRAD LTD.
-00502C SOYO COMPUTER, INC.
-00502D ACCEL, INC.
-00502E CAMBEX CORPORATION
-00502F TollBridge Technologies, Inc.
-005030 FUTURE PLUS SYSTEMS
-005031 AEROFLEX LABORATORIES, INC.
-005032 PICAZO COMMUNICATIONS, INC.
-005033 MAYAN NETWORKS
-005036 NETCAM, LTD.
-005037 KOGA ELECTRONICS CO.
-005038 DAIN TELECOM CO., LTD.
-005039 MARINER NETWORKS
-00503A DATONG ELECTRONICS LTD.
-00503B MEDIAFIRE CORPORATION
-00503C TSINGHUA NOVEL ELECTRONICS
-00503E CISCO SYSTEMS, INC.
-00503F ANCHOR GAMES
-005040 EMWARE, INC.
-005041 CTX OPTO ELECTRONIC CORP.
-005042 SCI MANUFACTURING SINGAPORE PTE, LTD.
-005043 MARVELL SEMICONDUCTOR, INC.
-005044 ASACA CORPORATION
-005045 RIOWORKS SOLUTIONS, INC.
-005046 MENICX INTERNATIONAL CO., LTD.
-005048 INFOLIBRIA
-005049 ELLACOYA NETWORKS, INC.
-00504A ELTECO A.S.
-00504B BARCONET N.V.
-00504C GALIL MOTION CONTROL, INC.
-00504D TOKYO ELECTRON DEVICE LTD.
-00504E SIERRA MONITOR CORP.
-00504F OLENCOM ELECTRONICS
-005050 CISCO SYSTEMS, INC.
-005051 IWATSU ELECTRIC CO., LTD.
-005052 TIARA NETWORKS, INC.
-005053 CISCO SYSTEMS, INC.
-005054 CISCO SYSTEMS, INC.
-005055 DOMS A/S
-005056 VMWare, Inc.
-005057 BROADBAND ACCESS SYSTEMS
-005058 VEGASTREAM LIMITED
-005059 SUITE TECHNOLOGY SYSTEMS NETWORK
-00505A NETWORK ALCHEMY, INC.
-00505B KAWASAKI LSI U.S.A., INC.
-00505C TUNDO CORPORATION
-00505E DIGITEK MICROLOGIC S.A.
-00505F BRAND INNOVATORS
-005060 TANDBERG TELECOM AS
-005062 KOUWELL ELECTRONICS CORP. **
-005063 OY COMSEL SYSTEM AB
-005064 CAE ELECTRONICS
-005065 DENSEI-LAMBAD Co., Ltd.
-005066 AtecoM GmbH advanced telecomunication modules
-005067 AEROCOMM, INC.
-005068 ELECTRONIC INDUSTRIES ASSOCIATION
-005069 PixStream Incorporated
-00506A EDEVA, INC.
-00506B SPX-ATEG
-00506C G & L BEIJER ELECTRONICS AB
-00506D VIDEOJET SYSTEMS
-00506E CORDER ENGINEERING CORPORATION
-00506F G-CONNECT
-005070 CHAINTECH COMPUTER CO., LTD.
-005071 AIWA CO., LTD.
-005072 CORVIS CORPORATION
-005073 CISCO SYSTEMS, INC.
-005074 ADVANCED HI-TECH CORP.
-005075 KESTREL SOLUTIONS
-005076 IBM
-005077 PROLIFIC TECHNOLOGY, INC.
-005078 MEGATON HOUSE, LTD.
-00507A XPEED, INC.
-00507B MERLOT COMMUNICATIONS
-00507C VIDEOCON AG
-00507D IFP
-00507E NEWER TECHNOLOGY
-00507F DrayTek Corp.
-005080 CISCO SYSTEMS, INC.
-005081 MURATA MACHINERY, LTD.
-005082 FORESSON CORPORATION
-005083 GILBARCO, INC.
-005084 ATL PRODUCTS
-005086 TELKOM SA, LTD.
-005087 TERASAKI ELECTRIC CO., LTD.
-005088 AMANO CORPORATION
-005089 SAFETY MANAGEMENT SYSTEMS
-00508B COMPAQ COMPUTER CORPORATION
-00508C RSI SYSTEMS
-00508D ABIT COMPUTER CORPORATION
-00508E OPTIMATION, INC.
-00508F ASITA TECHNOLOGIES INT'L LTD.
-005090 DCTRI
-005091 NETACCESS, INC.
-005092 RIGAKU INDUSTRIAL CORPORATION
-005093 BOEING
-005094 PACE MICRO TECHNOLOGY PLC
-005095 PERACOM NETWORKS
-005096 SALIX TECHNOLOGIES, INC.
-005097 MMC-EMBEDDED COMPUTERTECHNIK GmbH
-005098 GLOBALOOP, LTD.
-005099 3COM EUROPE, LTD.
-00509A TAG ELECTRONIC SYSTEMS
-00509B SWITCHCORE AB
-00509C BETA RESEARCH
-00509D THE INDUSTREE B.V.
-00509E Les Technologies SoftAcoustik Inc.
-00509F HORIZON COMPUTER
-0050A0 DELTA COMPUTER SYSTEMS, INC.
-0050A1 CARLO GAVAZZI, INC.
-0050A2 CISCO SYSTEMS, INC.
-0050A3 TransMedia Communications, Inc.
-0050A4 IO TECH, INC.
-0050A5 CAPITOL BUSINESS SYSTEMS, LTD.
-0050A6 OPTRONICS
-0050A7 CISCO SYSTEMS, INC.
-0050A8 OpenCon Systems, Inc.
-0050A9 MOLDAT WIRELESS TECHNOLGIES
-0050AA KONICA MINOLTA HOLDINGS, INC.
-0050AB NALTEC, INC.
-0050AC MAPLE COMPUTER CORPORATION
-0050AD CommUnique Wireless Corp.
-0050AE IWAKI ELECTRONICS CO., LTD.
-0050AF INTERGON, INC.
-0050B0 TECHNOLOGY ATLANTA CORPORATION
-0050B1 GIDDINGS & LEWIS
-0050B2 BRODEL AUTOMATION
-0050B3 VOICEBOARD CORPORATION
-0050B4 SATCHWELL CONTROL SYSTEMS, LTD
-0050B5 FICHET-BAUCHE
-0050B6 GOOD WAY IND. CO., LTD.
-0050B7 BOSER TECHNOLOGY CO., LTD.
-0050B8 INOVA COMPUTERS GMBH & CO. KG
-0050B9 XITRON TECHNOLOGIES, INC.
-0050BA D-LINK
-0050BB CMS TECHNOLOGIES
-0050BC HAMMER STORAGE SOLUTIONS
-0050BD CISCO SYSTEMS, INC.
-0050BE FAST MULTIMEDIA AG
-0050BF MOTOTECH INC.
-0050C0 GATAN, INC.
-0050C1 GEMFLEX NETWORKS, LTD.
-0050C2 IEEE REGISTRATION AUTHORITY
-0050C4 IMD
-0050C5 ADS TECHNOLOGIES, INC.
-0050C6 LOOP TELECOMMUNICATION INTERNATIONAL, INC.
-0050C8 ADDONICS COMMUNICATIONS, INC.
-0050C9 MASPRO DENKOH CORP.
-0050CA NET TO NET TECHNOLOGIES
-0050CB JETTER
-0050CC XYRATEX
-0050CD DIGIANSWER A/S
-0050CE LG INTERNATIONAL CORP.
-0050CF VANLINK COMMUNICATION TECHNOLOGY RESEARCH INSTITUTE
-0050D0 MINERVA SYSTEMS
-0050D1 CISCO SYSTEMS, INC.
-0050D2 BAE Systems Canada, Inc.
-0050D3 DIGITAL AUDIO PROCESSING PTY. LTD.
-0050D4 JOOHONG INFORMATION &
-0050D5 AD SYSTEMS CORP.
-0050D6 ATLAS COPCO TOOLS AB
-0050D7 TELSTRAT
-0050D8 UNICORN COMPUTER CORP.
-0050D9 ENGETRON-ENGENHARIA ELETRONICA IND. e COM. LTDA
-0050DA 3COM CORPORATION
-0050DB CONTEMPORARY CONTROL
-0050DC TAS TELEFONBAU A. SCHWABE GMBH & CO. KG
-0050DD SERRA SOLDADURA, S.A.
-0050DE SIGNUM SYSTEMS CORP.
-0050DF AirFiber, Inc.
-0050E1 NS TECH ELECTRONICS SDN BHD
-0050E2 CISCO SYSTEMS, INC.
-0050E3 Terayon Communications Systems
-0050E4 APPLE COMPUTER, INC.
-0050E6 HAKUSAN CORPORATION
-0050E7 PARADISE INNOVATIONS (ASIA)
-0050E8 NOMADIX INC.
-0050EA XEL COMMUNICATIONS, INC.
-0050EB ALPHA-TOP CORPORATION
-0050EC OLICOM A/S
-0050ED ANDA NETWORKS
-0050EE TEK DIGITEL CORPORATION
-0050EF SPE Systemhaus GmbH
-0050F0 CISCO SYSTEMS, INC.
-0050F1 LIBIT SIGNAL PROCESSING, LTD.
-0050F2 MICROSOFT CORP.
-0050F3 GLOBAL NET INFORMATION CO., Ltd.
-0050F4 SIGMATEK GMBH & CO. KG
-0050F6 PAN-INTERNATIONAL INDUSTRIAL CORP.
-0050F7 VENTURE MANUFACTURING (SINGAPORE) LTD.
-0050F8 ENTREGA TECHNOLOGIES, INC.
-0050FA OXTEL, LTD.
-0050FB VSK ELECTRONICS
-0050FC EDIMAX TECHNOLOGY CO., LTD.
-0050FD VISIONCOMM CO., LTD.
-0050FE PCTVnet ASA
-0050FF HAKKO ELECTRONICS CO., LTD.
-006000 XYCOM INC.
-006001 InnoSys, Inc.
-006002 SCREEN SUBTITLING SYSTEMS, LTD
-006003 TERAOKA WEIGH SYSTEM PTE, LTD.
-006004 COMPUTADORES MODULARES SA
-006005 FEEDBACK DATA LTD.
-006006 SOTEC CO., LTD
-006007 ACRES GAMING, INC.
-006008 3COM CORPORATION
-006009 CISCO SYSTEMS, INC.
-00600A SORD COMPUTER CORPORATION
-00600B LOGWARE GmbH
-00600C APPLIED DATA SYSTEMS, INC.
-00600D Digital Logic GmbH
-00600E WAVENET INTERNATIONAL, INC.
-00600F WESTELL, INC.
-006010 NETWORK MACHINES, INC.
-006011 CRYSTAL SEMICONDUCTOR CORP.
-006012 POWER COMPUTING CORPORATION
-006013 NETSTAL MASCHINEN AG
-006014 EDEC CO., LTD.
-006015 NET2NET CORPORATION
-006016 CLARIION
-006017 TOKIMEC INC.
-006018 STELLAR ONE CORPORATION
-006019 Roche Diagnostics
-00601A KEITHLEY INSTRUMENTS
-00601B MESA ELECTRONICS
-00601C TELXON CORPORATION
-00601D LUCENT TECHNOLOGIES
-00601E SOFTLAB, INC.
-00601F STALLION TECHNOLOGIES
-006020 PIVOTAL NETWORKING, INC.
-006021 DSC CORPORATION
-006022 VICOM SYSTEMS, INC.
-006023 PERICOM SEMICONDUCTOR CORP.
-006024 GRADIENT TECHNOLOGIES, INC.
-006025 ACTIVE IMAGING PLC
-006026 VIKING COMPONENTS, INC.
-006027 Superior Modular Products
-006028 MACROVISION CORPORATION
-006029 CARY PERIPHERALS INC.
-00602A SYMICRON COMPUTER COMMUNICATIONS, LTD.
-00602B PEAK AUDIO
-00602C LINX Data Terminals, Inc.
-00602D ALERTON TECHNOLOGIES, INC.
-00602E CYCLADES CORPORATION
-00602F CISCO SYSTEMS, INC.
-006030 VILLAGE TRONIC ENTWICKLUNG
-006031 HRK SYSTEMS
-006032 I-CUBE, INC.
-006033 ACUITY IMAGING, INC.
-006034 ROBERT BOSCH GmbH
-006035 DALLAS SEMICONDUCTOR, INC.
-006036 AUSTRIAN RESEARCH CENTER SEIBERSDORF
-006037 PHILIPS SEMICONDUCTORS
-006038 Nortel Networks
-006039 SanCom Technology, Inc.
-00603A QUICK CONTROLS LTD.
-00603B AMTEC spa
-00603C HAGIWARA SYS-COM CO., LTD.
-00603D 3CX
-00603E CISCO SYSTEMS, INC.
-00603F PATAPSCO DESIGNS
-006040 NETRO CORP.
-006041 Yokogawa Electric Corporation
-006042 TKS (USA), INC.
-006043 ComSoft Systems, Inc.
-006044 LITTON/POLY-SCIENTIFIC
-006045 PATHLIGHT TECHNOLOGIES
-006046 VMETRO, INC.
-006047 CISCO SYSTEMS, INC.
-006048 EMC CORPORATION
-006049 VINA TECHNOLOGIES
-00604A SAIC IDEAS GROUP
-00604B BIODATA GmbH
-00604C SAT
-00604D MMC NETWORKS, INC.
-00604E CYCLE COMPUTER CORPORATION, INC.
-00604F SUZUKI MFG. CO., LTD.
-006050 INTERNIX INC.
-006051 QUALITY SEMICONDUCTOR
-006052 PERIPHERALS ENTERPRISE CO., Ltd.
-006053 TOYODA MACHINE WORKS, LTD.
-006054 CONTROLWARE GMBH
-006055 CORNELL UNIVERSITY
-006056 NETWORK TOOLS, INC.
-006057 MURATA MANUFACTURING CO., LTD.
-006058 COPPER MOUNTAIN COMMUNICATIONS, INC.
-006059 TECHNICAL COMMUNICATIONS CORP.
-00605A CELCORE, INC.
-00605B IntraServer Technology, Inc.
-00605C CISCO SYSTEMS, INC.
-00605D SCANIVALVE CORP.
-00605E LIBERTY TECHNOLOGY NETWORKING
-00605F NIPPON UNISOFT CORPORATION
-006060 DAWNING TECHNOLOGIES, INC.
-006061 WHISTLE COMMUNICATIONS CORP.
-006062 TELESYNC, INC.
-006063 PSION DACOM PLC.
-006064 NETCOMM LIMITED
-006065 BERNECKER & RAINER INDUSTRIE-ELEKTRONIC GmbH
-006066 LACROIX TECHNOLGIE
-006067 ACER NETXUS INC.
-006068 EICON TECHNOLOGY CORPORATION
-006069 BROCADE COMMUNICATIONS SYSTEMS, Inc.
-00606A MITSUBISHI WIRELESS COMMUNICATIONS. INC.
-00606B Synclayer Inc.
-00606C ARESCOM
-00606D DIGITAL EQUIPMENT CORP.
-00606E DAVICOM SEMICONDUCTOR, INC.
-00606F CLARION CORPORATION OF AMERICA
-006070 CISCO SYSTEMS, INC.
-006071 MIDAS LAB, INC.
-006072 VXL INSTRUMENTS, LIMITED
-006073 REDCREEK COMMUNICATIONS, INC.
-006074 QSC AUDIO PRODUCTS
-006075 PENTEK, INC.
-006076 SCHLUMBERGER TECHNOLOGIES RETAIL PETROLEUM SYSTEMS
-006077 PRISA NETWORKS
-006078 POWER MEASUREMENT LTD.
-006079 Mainstream Data, Inc.
-00607A DVS GmbH
-00607B FORE SYSTEMS, INC.
-00607C WaveAccess, Ltd.
-00607D SENTIENT NETWORKS INC.
-00607E GIGALABS, INC.
-00607F AURORA TECHNOLOGIES, INC.
-006080 MICROTRONIX DATACOM LTD.
-006081 TV/COM INTERNATIONAL
-006082 NOVALINK TECHNOLOGIES, INC.
-006083 CISCO SYSTEMS, INC.
-006084 DIGITAL VIDEO
-006085 Storage Concepts
-006086 LOGIC REPLACEMENT TECH. LTD.
-006087 KANSAI ELECTRIC CO., LTD.
-006088 WHITE MOUNTAIN DSP, INC.
-006089 XATA
-00608A CITADEL COMPUTER
-00608B ConferTech International
-00608C 3COM CORPORATION
-00608D UNIPULSE CORP.
-00608E HE ELECTRONICS, TECHNOLOGIE & SYSTEMTECHNIK GmbH
-00608F TEKRAM TECHNOLOGY CO., LTD.
-006090 ABLE COMMUNICATIONS, INC.
-006091 FIRST PACIFIC NETWORKS, INC.
-006092 MICRO/SYS, INC.
-006093 VARIAN
-006094 IBM CORP.
-006095 ACCU-TIME SYSTEMS, INC.
-006096 T.S. MICROTECH INC.
-006097 3COM CORPORATION
-006098 HT COMMUNICATIONS
-006099 LAN MEDIA CORPORATION
-00609A NJK TECHNO CO.
-00609B ASTRO-MED, INC.
-00609C Perkin-Elmer Incorporated
-00609D PMI FOOD EQUIPMENT GROUP
-00609E ASC X3 - INFORMATION TECHNOLOGY STANDARDS SECRETARIATS
-00609F PHAST CORPORATION
-0060A0 SWITCHED NETWORK TECHNOLOGIES, INC.
-0060A1 VPNet, Inc.
-0060A2 NIHON UNISYS LIMITED CO.
-0060A3 CONTINUUM TECHNOLOGY CORP.
-0060A4 GRINAKER SYSTEM TECHNOLOGIES
-0060A5 PERFORMANCE TELECOM CORP.
-0060A6 PARTICLE MEASURING SYSTEMS
-0060A7 MICROSENS GmbH & CO. KG
-0060A8 TIDOMAT AB
-0060A9 GESYTEC MbH
-0060AA INTELLIGENT DEVICES INC. (IDI)
-0060AB LARSCOM INCORPORATED
-0060AC RESILIENCE CORPORATION
-0060AD MegaChips Corporation
-0060AE TRIO INFORMATION SYSTEMS AB
-0060AF PACIFIC MICRO DATA, INC.
-0060B0 HEWLETT-PACKARD CO.
-0060B1 INPUT/OUTPUT, INC.
-0060B2 PROCESS CONTROL CORP.
-0060B3 Z-COM, INC.
-0060B4 GLENAYRE R&D INC.
-0060B5 KEBA GmbH
-0060B6 LAND COMPUTER CO., LTD.
-0060B7 CHANNELMATIC, INC.
-0060B8 CORELIS INC.
-0060B9 NITSUKO CORPORATION
-0060BA SAHARA NETWORKS, INC.
-0060BB CABLETRON - NETLINK, INC.
-0060BC KeunYoung Electronics & Communication Co., Ltd.
-0060BD HUBBELL-PULSECOM
-0060BE WEBTRONICS
-0060BF MACRAIGOR SYSTEMS, INC.
-0060C0 NERA AS
-0060C1 WaveSpan Corporation
-0060C2 MPL AG
-0060C3 NETVISION CORPORATION
-0060C4 SOLITON SYSTEMS K.K.
-0060C5 ANCOT CORP.
-0060C6 DCS AG
-0060C7 AMATI COMMUNICATIONS CORP.
-0060C8 KUKA WELDING SYSTEMS & ROBOTS
-0060C9 ControlNet, Inc.
-0060CA HARMONIC SYSTEMS INCORPORATED
-0060CB HITACHI ZOSEN CORPORATION
-0060CC EMTRAK, INCORPORATED
-0060CD VideoServer, Inc.
-0060CE ACCLAIM COMMUNICATIONS
-0060CF ALTEON NETWORKS, INC.
-0060D0 SNMP RESEARCH INCORPORATED
-0060D1 CASCADE COMMUNICATIONS
-0060D2 LUCENT TECHNOLOGIES TAIWAN TELECOMMUNICATIONS CO., LTD.
-0060D3 AT&T
-0060D4 ELDAT COMMUNICATION LTD.
-0060D5 MIYACHI TECHNOS CORP.
-0060D6 NovAtel Wireless Technologies Ltd.
-0060D7 ECOLE POLYTECHNIQUE FEDERALE DE LAUSANNE (EPFL)
-0060D8 ELMIC SYSTEMS, INC.
-0060D9 TRANSYS NETWORKS INC.
-0060DA JBM ELECTRONICS CO.
-0060DB NTP ELEKTRONIK A/S
-0060DC TOYO COMMUNICATION EQUIPMENT Co., Ltd.
-0060DD MYRICOM, INC.
-0060DE KAYSER-THREDE GmbH
-0060DF CNT Corporation
-0060E0 AXIOM TECHNOLOGY CO., LTD.
-0060E1 ORCKIT COMMUNICATIONS LTD.
-0060E2 QUEST ENGINEERING & DEVELOPMENT
-0060E3 ARBIN INSTRUMENTS
-0060E4 COMPUSERVE, INC.
-0060E5 FUJI AUTOMATION CO., LTD.
-0060E6 SHOMITI SYSTEMS INCORPORATED
-0060E7 RANDATA
-0060E8 HITACHI COMPUTER PRODUCTS (AMERICA), INC.
-0060E9 ATOP TECHNOLOGIES, INC.
-0060EA StreamLogic
-0060EB FOURTHTRACK SYSTEMS
-0060EC HERMARY OPTO ELECTRONICS INC.
-0060ED RICARDO TEST AUTOMATION LTD.
-0060EE APOLLO
-0060EF FLYTECH TECHNOLOGY CO., LTD.
-0060F0 JOHNSON & JOHNSON MEDICAL, INC
-0060F1 EXP COMPUTER, INC.
-0060F2 LASERGRAPHICS, INC.
-0060F3 Performance Analysis Broadband, Spirent plc
-0060F4 ADVANCED COMPUTER SOLUTIONS, Inc.
-0060F5 ICON WEST, INC.
-0060F6 NEXTEST COMMUNICATIONS PRODUCTS, INC.
-0060F7 DATAFUSION SYSTEMS
-0060F8 Loran International Technologies Inc.
-0060F9 DIAMOND LANE COMMUNICATIONS
-0060FA EDUCATIONAL TECHNOLOGY RESOURCES, INC.
-0060FB PACKETEER, INC.
-0060FC CONSERVATION THROUGH INNOVATION LTD.
-0060FD NetICs, Inc.
-0060FE LYNX SYSTEM DEVELOPERS, INC.
-0060FF QuVis, Inc.
-0070B0 M/A-COM INC. COMPANIES
-0070B3 DATA RECALL LTD.
-008000 MULTITECH SYSTEMS, INC.
-008001 PERIPHONICS CORPORATION
-008002 SATELCOM (UK) LTD
-008003 HYTEC ELECTRONICS LTD.
-008004 ANTLOW COMMUNICATIONS, LTD.
-008005 CACTUS COMPUTER INC.
-008006 COMPUADD CORPORATION
-008007 DLOG NC-SYSTEME
-008008 DYNATECH COMPUTER SYSTEMS
-008009 JUPITER SYSTEMS, INC.
-00800A JAPAN COMPUTER CORP.
-00800B CSK CORPORATION
-00800C VIDECOM LIMITED
-00800D VOSSWINKEL F.U.
-00800E ATLANTIX CORPORATION
-00800F STANDARD MICROSYSTEMS
-008010 COMMODORE INTERNATIONAL
-008011 DIGITAL SYSTEMS INT'L. INC.
-008012 INTEGRATED MEASUREMENT SYSTEMS
-008013 THOMAS-CONRAD CORPORATION
-008014 ESPRIT SYSTEMS
-008015 SEIKO SYSTEMS, INC.
-008016 WANDEL AND GOLTERMANN
-008017 PFU LIMITED
-008018 KOBE STEEL, LTD.
-008019 DAYNA COMMUNICATIONS, INC.
-00801A BELL ATLANTIC
-00801B KODIAK TECHNOLOGY
-00801C NEWPORT SYSTEMS SOLUTIONS
-00801D INTEGRATED INFERENCE MACHINES
-00801E XINETRON, INC.
-00801F KRUPP ATLAS ELECTRONIK GMBH
-008020 NETWORK PRODUCTS
-008021 Alcatel Canada Inc.
-008022 SCAN-OPTICS
-008023 INTEGRATED BUSINESS NETWORKS
-008024 KALPANA, INC.
-008025 STOLLMANN GMBH
-008026 NETWORK PRODUCTS CORPORATION
-008027 ADAPTIVE SYSTEMS, INC.
-008028 TRADPOST (HK) LTD
-008029 EAGLE TECHNOLOGY, INC.
-00802A TEST SYSTEMS & SIMULATIONS INC
-00802B INTEGRATED MARKETING CO
-00802C THE SAGE GROUP PLC
-00802D XYLOGICS INC
-00802E CASTLE ROCK COMPUTING
-00802F NATIONAL INSTRUMENTS CORP.
-008030 NEXUS ELECTRONICS
-008031 BASYS, CORP.
-008032 ACCESS CO., LTD.
-008033 FORMATION, INC.
-008034 SMT GOUPIL
-008035 TECHNOLOGY WORKS, INC.
-008036 REFLEX MANUFACTURING SYSTEMS
-008037 Ericsson Group
-008038 DATA RESEARCH & APPLICATIONS
-008039 ALCATEL STC AUSTRALIA
-00803A VARITYPER, INC.
-00803B APT COMMUNICATIONS, INC.
-00803C TVS ELECTRONICS LTD
-00803D SURIGIKEN CO., LTD.
-00803E SYNERNETICS
-00803F TATUNG COMPANY
-008040 JOHN FLUKE MANUFACTURING CO.
-008041 VEB KOMBINAT ROBOTRON
-008042 FORCE COMPUTERS
-008043 NETWORLD, INC.
-008044 SYSTECH COMPUTER CORP.
-008045 MATSUSHITA ELECTRIC IND. CO
-008046 UNIVERSITY OF TORONTO
-008047 IN-NET CORP.
-008048 COMPEX INCORPORATED
-008049 NISSIN ELECTRIC CO., LTD.
-00804A PRO-LOG
-00804B EAGLE TECHNOLOGIES PTY.LTD.
-00804C CONTEC CO., LTD.
-00804D CYCLONE MICROSYSTEMS, INC.
-00804E APEX COMPUTER COMPANY
-00804F DAIKIN INDUSTRIES, LTD.
-008050 ZIATECH CORPORATION
-008051 FIBERMUX
-008052 TECHNICALLY ELITE CONCEPTS
-008053 INTELLICOM, INC.
-008054 FRONTIER TECHNOLOGIES CORP.
-008055 FERMILAB
-008056 SPHINX ELEKTRONIK GMBH
-008057 ADSOFT, LTD.
-008058 PRINTER SYSTEMS CORPORATION
-008059 STANLEY ELECTRIC CO., LTD
-00805A TULIP COMPUTERS INTERNAT'L B.V
-00805B CONDOR SYSTEMS, INC.
-00805C AGILIS CORPORATION
-00805D CANSTAR
-00805E LSI LOGIC CORPORATION
-00805F COMPAQ COMPUTER CORPORATION
-008060 NETWORK INTERFACE CORPORATION
-008061 LITTON SYSTEMS, INC.
-008062 INTERFACE CO.
-008063 RICHARD HIRSCHMANN GMBH & CO.
-008064 WYSE TECHNOLOGY
-008065 CYBERGRAPHIC SYSTEMS PTY LTD.
-008066 ARCOM CONTROL SYSTEMS, LTD.
-008067 SQUARE D COMPANY
-008068 YAMATECH SCIENTIFIC LTD.
-008069 COMPUTONE SYSTEMS
-00806A ERI (EMPAC RESEARCH INC.)
-00806B SCHMID TELECOMMUNICATION
-00806C CEGELEC PROJECTS LTD
-00806D CENTURY SYSTEMS CORP.
-00806E NIPPON STEEL CORPORATION
-00806F ONELAN LTD.
-008070 COMPUTADORAS MICRON
-008071 SAI TECHNOLOGY
-008072 MICROPLEX SYSTEMS LTD.
-008073 DWB ASSOCIATES
-008074 FISHER CONTROLS
-008075 PARSYTEC GMBH
-008076 MCNC
-008077 BROTHER INDUSTRIES, LTD.
-008078 PRACTICAL PERIPHERALS, INC.
-008079 MICROBUS DESIGNS LTD.
-00807A AITECH SYSTEMS LTD.
-00807B ARTEL COMMUNICATIONS CORP.
-00807C FIBERCOM, INC.
-00807D EQUINOX SYSTEMS INC.
-00807E SOUTHERN PACIFIC LTD.
-00807F DY-4 INCORPORATED
-008080 DATAMEDIA CORPORATION
-008081 KENDALL SQUARE RESEARCH CORP.
-008082 PEP MODULAR COMPUTERS GMBH
-008083 AMDAHL
-008084 THE CLOUD INC.
-008085 H-THREE SYSTEMS CORPORATION
-008086 COMPUTER GENERATION INC.
-008087 OKI ELECTRIC INDUSTRY CO., LTD
-008088 VICTOR COMPANY OF JAPAN, LTD.
-008089 TECNETICS (PTY) LTD.
-00808A SUMMIT MICROSYSTEMS CORP.
-00808B DACOLL LIMITED
-00808C NetScout Systems, Inc.
-00808D WESTCOAST TECHNOLOGY B.V.
-00808E RADSTONE TECHNOLOGY
-00808F C. ITOH ELECTRONICS, INC.
-008090 MICROTEK INTERNATIONAL, INC.
-008091 TOKYO ELECTRIC CO.,LTD
-008092 JAPAN COMPUTER INDUSTRY, INC.
-008093 XYRON CORPORATION
-008094 ALFA LAVAL AUTOMATION AB
-008095 BASIC MERTON HANDELSGES.M.B.H.
-008096 HUMAN DESIGNED SYSTEMS, INC.
-008097 CENTRALP AUTOMATISMES
-008098 TDK CORPORATION
-008099 KLOCKNER MOELLER IPC
-00809A NOVUS NETWORKS LTD
-00809B JUSTSYSTEM CORPORATION
-00809C LUXCOM, INC.
-00809D Commscraft Ltd.
-00809E DATUS GMBH
-00809F ALCATEL BUSINESS SYSTEMS
-0080A0 EDISA HEWLETT PACKARD S/A
-0080A1 MICROTEST, INC.
-0080A2 CREATIVE ELECTRONIC SYSTEMS
-0080A3 LANTRONIX
-0080A4 LIBERTY ELECTRONICS
-0080A5 SPEED INTERNATIONAL
-0080A6 REPUBLIC TECHNOLOGY, INC.
-0080A7 MEASUREX CORP.
-0080A8 VITACOM CORPORATION
-0080A9 CLEARPOINT RESEARCH
-0080AA MAXPEED
-0080AB DUKANE NETWORK INTEGRATION
-0080AC IMLOGIX, DIVISION OF GENESYS
-0080AD CNET TECHNOLOGY, INC.
-0080AE HUGHES NETWORK SYSTEMS
-0080AF ALLUMER CO., LTD.
-0080B0 ADVANCED INFORMATION
-0080B1 SOFTCOM A/S
-0080B2 NETWORK EQUIPMENT TECHNOLOGIES
-0080B3 AVAL DATA CORPORATION
-0080B4 SOPHIA SYSTEMS
-0080B5 UNITED NETWORKS INC.
-0080B6 THEMIS COMPUTER
-0080B7 STELLAR COMPUTER
-0080B8 BUG, INCORPORATED
-0080B9 ARCHE TECHNOLIGIES INC.
-0080BA SPECIALIX (ASIA) PTE, LTD
-0080BB HUGHES LAN SYSTEMS
-0080BC HITACHI ENGINEERING CO., LTD
-0080BD THE FURUKAWA ELECTRIC CO., LTD
-0080BE ARIES RESEARCH
-0080BF TAKAOKA ELECTRIC MFG. CO. LTD.
-0080C0 PENRIL DATACOMM
-0080C1 LANEX CORPORATION
-0080C2 IEEE 802.1 COMMITTEE
-0080C3 BICC INFORMATION SYSTEMS & SVC
-0080C4 DOCUMENT TECHNOLOGIES, INC.
-0080C5 NOVELLCO DE MEXICO
-0080C6 NATIONAL DATACOMM CORPORATION
-0080C7 XIRCOM
-0080C8 D-LINK SYSTEMS, INC.
-0080C9 ALBERTA MICROELECTRONIC CENTRE
-0080CA NETCOM RESEARCH INCORPORATED
-0080CB FALCO DATA PRODUCTS
-0080CC MICROWAVE BYPASS SYSTEMS
-0080CD MICRONICS COMPUTER, INC.
-0080CE BROADCAST TELEVISION SYSTEMS
-0080CF EMBEDDED PERFORMANCE INC.
-0080D0 COMPUTER PERIPHERALS, INC.
-0080D1 KIMTRON CORPORATION
-0080D2 SHINNIHONDENKO CO., LTD.
-0080D3 SHIVA CORP.
-0080D4 CHASE RESEARCH LTD.
-0080D5 CADRE TECHNOLOGIES
-0080D6 NUVOTECH, INC.
-0080D7 Fantum Engineering
-0080D8 NETWORK PERIPHERALS INC.
-0080D9 EMK ELEKTRONIK
-0080DA BRUEL & KJAER
-0080DB GRAPHON CORPORATION
-0080DC PICKER INTERNATIONAL
-0080DD GMX INC/GIMIX
-0080DE GIPSI S.A.
-0080DF ADC CODENOLL TECHNOLOGY CORP.
-0080E0 XTP SYSTEMS, INC.
-0080E1 STMICROELECTRONICS
-0080E2 T.D.I. CO., LTD.
-0080E3 CORAL NETWORK CORPORATION
-0080E4 NORTHWEST DIGITAL SYSTEMS, INC
-0080E5 MYLEX CORPORATION
-0080E6 PEER NETWORKS, INC.
-0080E7 LYNWOOD SCIENTIFIC DEV. LTD.
-0080E8 CUMULUS CORPORATIION
-0080E9 Madge Ltd.
-0080EA ADVA Optical Networking Ltd.
-0080EB COMPCONTROL B.V.
-0080EC SUPERCOMPUTING SOLUTIONS, INC.
-0080ED IQ TECHNOLOGIES, INC.
-0080EE THOMSON CSF
-0080EF RATIONAL
-0080F0 Panasonic Communications Co., Ltd.
-0080F1 OPUS SYSTEMS
-0080F2 RAYCOM SYSTEMS INC
-0080F3 SUN ELECTRONICS CORP.
-0080F4 TELEMECANIQUE ELECTRIQUE
-0080F5 QUANTEL LTD
-0080F6 SYNERGY MICROSYSTEMS
-0080F7 ZENITH ELECTRONICS
-0080F8 MIZAR, INC.
-0080F9 HEURIKON CORPORATION
-0080FA RWT GMBH
-0080FB BVM LIMITED
-0080FC AVATAR CORPORATION
-0080FD EXSCEED CORPRATION
-0080FE AZURE TECHNOLOGIES, INC.
-0080FF SOC. DE TELEINFORMATIQUE RTC
-009000 DIAMOND MULTIMEDIA
-009001 NISHIMU ELECTRONICS INDUSTRIES CO., LTD.
-009002 ALLGON AB
-009003 APLIO
-009004 3COM EUROPE LTD.
-009005 PROTECH SYSTEMS CO., LTD.
-009006 HAMAMATSU PHOTONICS K.K.
-009007 DOMEX TECHNOLOGY CORP.
-009008 HanA Systems Inc.
-009009 i Controls, Inc.
-00900A PROTON ELECTRONIC INDUSTRIAL CO., LTD.
-00900B LANNER ELECTRONICS, INC.
-00900C CISCO SYSTEMS, INC.
-00900D OVERLAND DATA INC.
-00900E HANDLINK TECHNOLOGIES, INC.
-00900F KAWASAKI HEAVY INDUSTRIES, LTD
-009010 SIMULATION LABORATORIES, INC.
-009011 WAVTrace, Inc.
-009012 GLOBESPAN SEMICONDUCTOR, INC.
-009013 SAMSAN CORP.
-009014 ROTORK INSTRUMENTS, LTD.
-009015 CENTIGRAM COMMUNICATIONS CORP.
-009016 ZAC
-009017 ZYPCOM, INC.
-009018 ITO ELECTRIC INDUSTRY CO, LTD.
-009019 HERMES ELECTRONICS CO., LTD.
-00901A UNISPHERE SOLUTIONS
-00901B DIGITAL CONTROLS
-00901C mps Software Gmbh
-00901D PEC (NZ) LTD.
-00901E SELESTA INGEGNE RIA S.P.A.
-00901F ADTEC PRODUCTIONS, INC.
-009020 PHILIPS ANALYTICAL X-RAY B.V.
-009021 CISCO SYSTEMS, INC.
-009022 IVEX
-009023 ZILOG INC.
-009024 PIPELINKS, INC.
-009025 VISION SYSTEMS LTD. PTY
-009026 ADVANCED SWITCHING COMMUNICATIONS, INC.
-009027 INTEL CORPORATION
-009028 NIPPON SIGNAL CO., LTD.
-009029 CRYPTO AG
-00902A COMMUNICATION DEVICES, INC.
-00902B CISCO SYSTEMS, INC.
-00902C DATA & CONTROL EQUIPMENT LTD.
-00902D DATA ELECTRONICS (AUST.) PTY, LTD.
-00902E NAMCO LIMITED
-00902F NETCORE SYSTEMS, INC.
-009030 HONEYWELL-DATING
-009031 MYSTICOM, LTD.
-009032 PELCOMBE GROUP LTD.
-009033 INNOVAPHONE GmbH
-009034 IMAGIC, INC.
-009035 ALPHA TELECOM, INC.
-009036 ens, inc.
-009037 ACUCOMM, INC.
-009038 FOUNTAIN TECHNOLOGIES, INC.
-009039 SHASTA NETWORKS
-00903A NIHON MEDIA TOOL INC.
-00903B TriEMS Research Lab, Inc.
-00903C ATLANTIC NETWORK SYSTEMS
-00903D BIOPAC SYSTEMS, INC.
-00903E N.V. PHILIPS INDUSTRIAL ACTIVITIES
-00903F AZTEC RADIOMEDIA
-009040 Siemens Network Convergence LLC
-009041 APPLIED DIGITAL ACCESS
-009042 ECCS, Inc.
-009043 NICHIBEI DENSHI CO., LTD.
-009044 ASSURED DIGITAL, INC.
-009045 Marconi Communications
-009046 DEXDYNE, LTD.
-009047 GIGA FAST E. LTD.
-009048 ZEAL CORPORATION
-009049 ENTRIDIA CORPORATION
-00904A CONCUR SYSTEM TECHNOLOGIES
-00904B GemTek Technology Co., Ltd.
-00904C EPIGRAM, INC.
-00904D SPEC S.A.
-00904E DELEM BV
-00904F ABB POWER T&D COMPANY, INC.
-009050 TELESTE OY
-009051 ULTIMATE TECHNOLOGY CORP.
-009052 SELCOM ELETTRONICA S.R.L.
-009053 DAEWOO ELECTRONICS CO., LTD.
-009054 INNOVATIVE SEMICONDUCTORS, INC
-009055 PARKER HANNIFIN CORPORATION COMPUMOTOR DIVISION
-009056 TELESTREAM, INC.
-009057 AANetcom, Inc.
-009058 Ultra Electronics Ltd., Command and Control Systems
-009059 TELECOM DEVICE K.K.
-00905A DEARBORN GROUP, INC.
-00905B RAYMOND AND LAE ENGINEERING
-00905C EDMI
-00905D NETCOM SICHERHEITSTECHNIK GmbH
-00905E RAULAND-BORG CORPORATION
-00905F CISCO SYSTEMS, INC.
-009060 SYSTEM CREATE CORP.
-009061 PACIFIC RESEARCH & ENGINEERING CORPORATION
-009062 ICP VORTEX COMPUTERSYSTEME GmbH
-009063 COHERENT COMMUNICATIONS SYSTEMS CORPORATION
-009064 THOMSON BROADCAST SYSTEMS
-009065 FINISAR CORPORATION
-009066 Troika Networks, Inc.
-009067 WalkAbout Computers, Inc.
-009068 DVT CORP.
-009069 JUNIPER NETWORKS, INC.
-00906A TURNSTONE SYSTEMS, INC.
-00906B APPLIED RESOURCES, INC.
-00906C GWT GLOBAL WEIGHING TECHNOLOGIES GmbH
-00906D CISCO SYSTEMS, INC.
-00906E PRAXON, INC.
-00906F CISCO SYSTEMS, INC.
-009070 NEO NETWORKS, INC.
-009071 Applied Innovation Inc.
-009072 SIMRAD AS
-009073 GAIO TECHNOLOGY
-009074 ARGON NETWORKS, INC.
-009075 NEC DO BRASIL S.A.
-009076 FMT AIRCRAFT GATE SUPPORT SYSTEMS AB
-009077 ADVANCED FIBRE COMMUNICATIONS
-009078 MER TELEMANAGEMENT SOLUTIONS, LTD.
-009079 ClearOne, Inc.
-00907A SPECTRALINK CORP.
-00907B E-TECH, INC.
-00907C DIGITALCAST, INC.
-00907D Lake Communications
-00907E VETRONIX CORP.
-00907F WatchGuard Technologies, Inc.
-009080 NOT LIMITED, INC.
-009081 ALOHA NETWORKS, INC.
-009082 FORCE INSTITUTE
-009083 TURBO COMMUNICATION, INC.
-009084 ATECH SYSTEM
-009085 GOLDEN ENTERPRISES, INC.
-009086 CISCO SYSTEMS, INC.
-009087 ITIS
-009088 BAXALL SECURITY LTD.
-009089 SOFTCOM MICROSYSTEMS, INC.
-00908A BAYLY COMMUNICATIONS, INC.
-00908B CELL COMPUTING, INC.
-00908C ETREND ELECTRONICS, INC.
-00908D VICKERS ELECTRONICS SYSTEMS
-00908E Nortel Networks Broadband Access
-00908F AUDIO CODES LTD.
-009090 I-BUS
-009091 DigitalScape, Inc.
-009092 CISCO SYSTEMS, INC.
-009093 NANAO CORPORATION
-009094 OSPREY TECHNOLOGIES, INC.
-009095 UNIVERSAL AVIONICS
-009096 ASKEY COMPUTER CORP.
-009097 SYCAMORE NETWORKS
-009098 SBC DESIGNS, INC.
-009099 ALLIED TELESIS, K.K.
-00909A ONE WORLD SYSTEMS, INC.
-00909B MARKPOINT AB
-00909C Terayon Communications Systems
-00909D GSE SYSTEMS, INC.
-00909E Critical IO, LLC
-00909F DIGI-DATA CORPORATION
-0090A0 8X8 INC.
-0090A1 FLYING PIG SYSTEMS, LTD.
-0090A2 CYBERTAN TECHNOLOGY, INC.
-0090A3 Corecess Inc.
-0090A4 ALTIGA NETWORKS
-0090A5 SPECTRA LOGIC
-0090A6 CISCO SYSTEMS, INC.
-0090A7 CLIENTEC CORPORATION
-0090A8 NineTiles Networks, Ltd.
-0090A9 WESTERN DIGITAL
-0090AA INDIGO ACTIVE VISION SYSTEMS LIMITED
-0090AB CISCO SYSTEMS, INC.
-0090AC OPTIVISION, INC.
-0090AD ASPECT ELECTRONICS, INC.
-0090AE ITALTEL S.p.A.
-0090AF J. MORITA MFG. CORP.
-0090B0 VADEM
-0090B1 CISCO SYSTEMS, INC.
-0090B2 AVICI SYSTEMS INC.
-0090B3 AGRANAT SYSTEMS
-0090B4 WILLOWBROOK TECHNOLOGIES
-0090B5 NIKON CORPORATION
-0090B6 FIBEX SYSTEMS
-0090B7 DIGITAL LIGHTWAVE, INC.
-0090B8 ROHDE & SCHWARZ GMBH & CO. KG
-0090B9 BERAN INSTRUMENTS LTD.
-0090BA VALID NETWORKS, INC.
-0090BB TAINET COMMUNICATION SYSTEM Corp.
-0090BC TELEMANN CO., LTD.
-0090BD OMNIA COMMUNICATIONS, INC.
-0090BE IBC/INTEGRATED BUSINESS COMPUTERS
-0090BF CISCO SYSTEMS, INC.
-0090C0 K.J. LAW ENGINEERS, INC.
-0090C1 Peco II, Inc.
-0090C2 JK microsystems, Inc.
-0090C3 TOPIC SEMICONDUCTOR CORP.
-0090C4 JAVELIN SYSTEMS, INC.
-0090C5 INTERNET MAGIC, INC.
-0090C6 OPTIM SYSTEMS, INC.
-0090C7 ICOM INC.
-0090C8 WAVERIDER COMMUNICATIONS (CANADA) INC.
-0090C9 DPAC Technologies
-0090CA ACCORD VIDEO TELECOMMUNICATIONS, LTD.
-0090CB Wireless OnLine, Inc.
-0090CC PLANET COMMUNICATIONS, INC.
-0090CD ENT-EMPRESA NACIONAL DE TELECOMMUNICACOES, S.A.
-0090CE TETRA GmbH
-0090CF NORTEL
-0090D0 Thomson Belgium
-0090D1 LEICHU ENTERPRISE CO., LTD.
-0090D2 ARTEL VIDEO SYSTEMS
-0090D3 GIESECKE & DEVRIENT GmbH
-0090D4 BindView Development Corp.
-0090D5 EUPHONIX, INC.
-0090D6 CRYSTAL GROUP
-0090D7 NetBoost Corp.
-0090D8 WHITECROSS SYSTEMS
-0090D9 CISCO SYSTEMS, INC.
-0090DA DYNARC, INC.
-0090DB NEXT LEVEL COMMUNICATIONS
-0090DC TECO INFORMATION SYSTEMS
-0090DD THE MIHARU COMMUNICATIONS CO., LTD.
-0090DE CARDKEY SYSTEMS, INC.
-0090DF MITSUBISHI CHEMICAL AMERICA, INC.
-0090E0 SYSTRAN CORP.
-0090E1 TELENA S.P.A.
-0090E2 DISTRIBUTED PROCESSING TECHNOLOGY
-0090E3 AVEX ELECTRONICS INC.
-0090E4 NEC AMERICA, INC.
-0090E5 TEKNEMA, INC.
-0090E6 ACER LABORATORIES, INC.
-0090E7 HORSCH ELEKTRONIK AG
-0090E8 MOXA TECHNOLOGIES CORP., LTD.
-0090E9 JANZ COMPUTER AG
-0090EA ALPHA TECHNOLOGIES, INC.
-0090EB SENTRY TELECOM SYSTEMS
-0090EC PYRESCOM
-0090ED CENTRAL SYSTEM RESEARCH CO., LTD.
-0090EE PERSONAL COMMUNICATIONS TECHNOLOGIES
-0090EF INTEGRIX, INC.
-0090F0 HARMONIC LIGHTWAVES, LTD.
-0090F1 DOT HILL SYSTEMS CORPORATION
-0090F2 CISCO SYSTEMS, INC.
-0090F3 ASPECT COMMUNICATIONS
-0090F4 LIGHTNING INSTRUMENTATION
-0090F5 CLEVO CO.
-0090F6 ESCALATE NETWORKS, INC.
-0090F7 NBASE COMMUNICATIONS LTD.
-0090F8 MEDIATRIX TELECOM
-0090F9 LEITCH
-0090FA GigaNet, Inc.
-0090FB PORTWELL, INC.
-0090FC NETWORK COMPUTING DEVICES
-0090FD CopperCom, Inc.
-0090FE ELECOM CO., LTD. (LANEED DIV.)
-0090FF TELLUS TECHNOLOGY INC.
-0091D6 Crystal Group, Inc.
-009D8E CARDIAC RECORDERS, INC.
-00A000 CENTILLION NETWORKS, INC.
-00A001 WATKINS-JOHNSON COMPANY
-00A002 LEEDS & NORTHRUP AUSTRALIA PTY LTD
-00A003 STAEFA CONTROL SYSTEM
-00A004 NETPOWER, INC.
-00A005 DANIEL INSTRUMENTS, LTD.
-00A006 IMAGE DATA PROCESSING SYSTEM GROUP
-00A007 APEXX TECHNOLOGY, INC.
-00A008 NETCORP
-00A009 WHITETREE NETWORK
-00A00A R.D.C. COMMUNICATION
-00A00B COMPUTEX CO., LTD.
-00A00C KINGMAX TECHNOLOGY, INC.
-00A00D THE PANDA PROJECT
-00A00E VISUAL NETWORKS, INC.
-00A00F Broadband Technologies
-00A010 SYSLOGIC DATENTECHNIK AG
-00A011 MUTOH INDUSTRIES LTD.
-00A012 B.A.T.M. ADVANCED TECHNOLOGIES
-00A013 TELTREND LTD.
-00A014 CSIR
-00A015 WYLE
-00A016 MICROPOLIS CORP.
-00A017 J B M CORPORATION
-00A018 CREATIVE CONTROLLERS, INC.
-00A019 NEBULA CONSULTANTS, INC.
-00A01A BINAR ELEKTRONIK AB
-00A01B PREMISYS COMMUNICATIONS, INC.
-00A01C NASCENT NETWORKS CORPORATION
-00A01D SIXNET
-00A01E EST CORPORATION
-00A01F TRICORD SYSTEMS, INC.
-00A020 CITICORP/TTI
-00A021 GENERAL DYNAMICS-
-00A022 CENTRE FOR DEVELOPMENT OF ADVANCED COMPUTING
-00A023 APPLIED CREATIVE TECHNOLOGY, INC.
-00A024 3COM CORPORATION
-00A025 REDCOM LABS INC.
-00A026 TELDAT, S.A.
-00A027 FIREPOWER SYSTEMS, INC.
-00A028 CONNER PERIPHERALS
-00A029 COULTER CORPORATION
-00A02A TRANCELL SYSTEMS
-00A02B TRANSITIONS RESEARCH CORP.
-00A02C interWAVE Communications
-00A02D 1394 Trade Association
-00A02E BRAND COMMUNICATIONS, LTD.
-00A02F PIRELLI CAVI
-00A030 CAPTOR NV/SA
-00A031 HAZELTINE CORPORATION, MS 1-17
-00A032 GES SINGAPORE PTE. LTD.
-00A033 imc MeBsysteme GmbH
-00A034 AXEL
-00A035 CYLINK CORPORATION
-00A036 APPLIED NETWORK TECHNOLOGY
-00A037 DATASCOPE CORPORATION
-00A038 EMAIL ELECTRONICS
-00A039 ROSS TECHNOLOGY, INC.
-00A03A KUBOTEK CORPORATION
-00A03B TOSHIN ELECTRIC CO., LTD.
-00A03C EG&G NUCLEAR INSTRUMENTS
-00A03D OPTO-22
-00A03E ATM FORUM
-00A03F COMPUTER SOCIETY MICROPROCESSOR & MICROPROCESSOR STANDARDS C
-00A040 APPLE COMPUTER
-00A041 LEYBOLD-INFICON
-00A042 SPUR PRODUCTS CORP.
-00A043 AMERICAN TECHNOLOGY LABS, INC.
-00A044 NTT IT CO., LTD.
-00A045 PHOENIX CONTACT GMBH & CO.
-00A046 SCITEX CORP. LTD.
-00A047 INTEGRATED FITNESS CORP.
-00A048 QUESTECH, LTD.
-00A049 DIGITECH INDUSTRIES, INC.
-00A04A NISSHIN ELECTRIC CO., LTD.
-00A04B TFL LAN INC.
-00A04C INNOVATIVE SYSTEMS & TECHNOLOGIES, INC.
-00A04D EDA INSTRUMENTS, INC.
-00A04E VOELKER TECHNOLOGIES, INC.
-00A04F AMERITEC CORP.
-00A050 CYPRESS SEMICONDUCTOR
-00A051 ANGIA COMMUNICATIONS. INC.
-00A052 STANILITE ELECTRONICS PTY. LTD
-00A053 COMPACT DEVICES, INC.
-00A055 Data Device Corporation
-00A056 MICROPROSS
-00A057 LANCOM Systems GmbH
-00A058 GLORY, LTD.
-00A059 HAMILTON HALLMARK
-00A05A KOFAX IMAGE PRODUCTS
-00A05B MARQUIP, INC.
-00A05C INVENTORY CONVERSION, INC./
-00A05D CS COMPUTER SYSTEME GmbH
-00A05E MYRIAD LOGIC INC.
-00A05F BTG ENGINEERING BV
-00A060 ACER PERIPHERALS, INC.
-00A061 PURITAN BENNETT
-00A062 AES PRODATA
-00A063 JRL SYSTEMS, INC.
-00A064 KVB/ANALECT
-00A065 NEXLAND, INC.
-00A066 ISA CO., LTD.
-00A067 NETWORK SERVICES GROUP
-00A068 BHP LIMITED
-00A069 Symmetricom, Inc.
-00A06A Verilink Corporation
-00A06B DMS DORSCH MIKROSYSTEM GMBH
-00A06C SHINDENGEN ELECTRIC MFG. CO., LTD.
-00A06D MANNESMANN TALLY CORPORATION
-00A06E AUSTRON, INC.
-00A06F THE APPCON GROUP, INC.
-00A070 COASTCOM
-00A071 VIDEO LOTTERY TECHNOLOGIES,INC
-00A072 OVATION SYSTEMS LTD.
-00A073 COM21, INC.
-00A074 PERCEPTION TECHNOLOGY
-00A075 MICRON TECHNOLOGY, INC.
-00A076 CARDWARE LAB, INC.
-00A077 FUJITSU NEXION, INC.
-00A078 Marconi Communications
-00A079 ALPS ELECTRIC (USA), INC.
-00A07A ADVANCED PERIPHERALS TECHNOLOGIES, INC.
-00A07B DAWN COMPUTER INCORPORATION
-00A07C TONYANG NYLON CO., LTD.
-00A07D SEEQ TECHNOLOGY, INC.
-00A07E AVID TECHNOLOGY, INC.
-00A07F GSM-SYNTEL, LTD.
-00A080 ANTARES MICROSYSTEMS
-00A081 ALCATEL DATA NETWORKS
-00A082 NKT ELEKTRONIK A/S
-00A083 ASIMMPHONY TURKEY
-00A084 DATAPLEX PTY. LTD.
-00A086 AMBER WAVE SYSTEMS, INC.
-00A087 Zarlink Semiconductor Ltd.
-00A088 ESSENTIAL COMMUNICATIONS
-00A089 XPOINT TECHNOLOGIES, INC.
-00A08A BROOKTROUT TECHNOLOGY, INC.
-00A08B ASTON ELECTRONIC DESIGNS LTD.
-00A08C MultiMedia LANs, Inc.
-00A08D JACOMO CORPORATION
-00A08E Nokia Internet Communications
-00A08F DESKNET SYSTEMS, INC.
-00A090 TimeStep Corporation
-00A091 APPLICOM INTERNATIONAL
-00A092 H. BOLLMANN MANUFACTURERS, LTD
-00A093 B/E AEROSPACE, Inc.
-00A094 COMSAT CORPORATION
-00A095 ACACIA NETWORKS, INC.
-00A096 MITUMI ELECTRIC CO., LTD.
-00A097 JC INFORMATION SYSTEMS
-00A098 NETWORK APPLIANCE CORP.
-00A099 K-NET LTD.
-00A09A NIHON KOHDEN AMERICA
-00A09B QPSX COMMUNICATIONS, LTD.
-00A09C Xyplex, Inc.
-00A09D JOHNATHON FREEMAN TECHNOLOGIES
-00A09E ICTV
-00A09F COMMVISION CORP.
-00A0A0 COMPACT DATA, LTD.
-00A0A1 EPIC DATA INC.
-00A0A2 DIGICOM S.P.A.
-00A0A3 RELIABLE POWER METERS
-00A0A4 MICROS SYSTEMS, INC.
-00A0A5 TEKNOR MICROSYSTEME, INC.
-00A0A6 M.I. SYSTEMS, K.K.
-00A0A7 VORAX CORPORATION
-00A0A8 RENEX CORPORATION
-00A0A9 GN NETTEST (CANADA) NAVTEL DIVISION
-00A0AA SPACELABS MEDICAL
-00A0AB NETCS INFORMATIONSTECHNIK GMBH
-00A0AC GILAT SATELLITE NETWORKS, LTD.
-00A0AD MARCONI SPA
-00A0AE NUCOM SYSTEMS, INC.
-00A0AF WMS INDUSTRIES
-00A0B0 I-O DATA DEVICE, INC.
-00A0B1 FIRST VIRTUAL CORPORATION
-00A0B2 SHIMA SEIKI
-00A0B3 ZYKRONIX
-00A0B4 TEXAS MICROSYSTEMS, INC.
-00A0B5 3H TECHNOLOGY
-00A0B6 SANRITZ AUTOMATION CO., LTD.
-00A0B7 CORDANT, INC.
-00A0B8 SYMBIOS LOGIC INC.
-00A0B9 EAGLE TECHNOLOGY, INC.
-00A0BA PATTON ELECTRONICS CO.
-00A0BB HILAN GMBH
-00A0BC VIASAT, INCORPORATED
-00A0BD I-TECH CORP.
-00A0BE INTEGRATED CIRCUIT SYSTEMS, INC. COMMUNICATIONS GROUP
-00A0BF WIRELESS DATA GROUP MOTOROLA
-00A0C0 DIGITAL LINK CORP.
-00A0C1 ORTIVUS MEDICAL AB
-00A0C2 R.A. SYSTEMS CO., LTD.
-00A0C3 UNICOMPUTER GMBH
-00A0C4 CRISTIE ELECTRONICS LTD.
-00A0C5 ZYXEL COMMUNICATION
-00A0C6 QUALCOMM INCORPORATED
-00A0C7 TADIRAN TELECOMMUNICATIONS
-00A0C8 ADTRAN INC.
-00A0C9 INTEL CORPORATION - HF1-06
-00A0CA FUJITSU DENSO LTD.
-00A0CB ARK TELECOMMUNICATIONS, INC.
-00A0CC LITE-ON COMMUNICATIONS, INC.
-00A0CD DR. JOHANNES HEIDENHAIN GmbH
-00A0CE ASTROCOM CORPORATION
-00A0CF SOTAS, INC.
-00A0D0 TEN X TECHNOLOGY, INC.
-00A0D1 INVENTEC CORPORATION
-00A0D2 ALLIED TELESIS INTERNATIONAL CORPORATION
-00A0D3 INSTEM COMPUTER SYSTEMS, LTD.
-00A0D4 RADIOLAN, INC.
-00A0D5 SIERRA WIRELESS INC.
-00A0D6 SBE, INC.
-00A0D7 KASTEN CHASE APPLIED RESEARCH
-00A0D8 SPECTRA - TEK
-00A0D9 CONVEX COMPUTER CORPORATION
-00A0DA INTEGRATED SYSTEMS Technology, Inc.
-00A0DB FISHER & PAYKEL PRODUCTION
-00A0DC O.N. ELECTRONIC CO., LTD.
-00A0DD AZONIX CORPORATION
-00A0DE YAMAHA CORPORATION
-00A0DF STS TECHNOLOGIES, INC.
-00A0E0 TENNYSON TECHNOLOGIES PTY LTD
-00A0E1 WESTPORT RESEARCH ASSOCIATES, INC.
-00A0E2 KEISOKU GIKEN CORP.
-00A0E3 XKL SYSTEMS CORP.
-00A0E4 OPTIQUEST
-00A0E5 NHC COMMUNICATIONS
-00A0E6 DIALOGIC CORPORATION
-00A0E7 CENTRAL DATA CORPORATION
-00A0E8 REUTERS HOLDINGS PLC
-00A0E9 ELECTRONIC RETAILING SYSTEMS INTERNATIONAL
-00A0EA ETHERCOM CORP.
-00A0EB Encore Networks
-00A0EC TRANSMITTON LTD.
-00A0ED PRI AUTOMATION
-00A0EE NASHOBA NETWORKS
-00A0EF LUCIDATA LTD.
-00A0F0 TORONTO MICROELECTRONICS INC.
-00A0F1 MTI
-00A0F2 INFOTEK COMMUNICATIONS, INC.
-00A0F3 STAUBLI
-00A0F4 GE
-00A0F5 RADGUARD LTD.
-00A0F6 AutoGas Systems Inc.
-00A0F7 V.I COMPUTER CORP.
-00A0F8 SYMBOL TECHNOLOGIES, INC.
-00A0F9 BINTEC COMMUNICATIONS GMBH
-00A0FA Marconi Communication GmbH
-00A0FB TORAY ENGINEERING CO., LTD.
-00A0FC IMAGE SCIENCES, INC.
-00A0FD SCITEX DIGITAL PRINTING, INC.
-00A0FE BOSTON TECHNOLOGY, INC.
-00A0FF TELLABS OPERATIONS, INC.
-00AA00 INTEL CORPORATION
-00AA01 INTEL CORPORATION
-00AA02 INTEL CORPORATION
-00AA3C OLIVETTI TELECOM SPA (OLTECO)
-00B009 Grass Valley Group
-00B017 InfoGear Technology Corp.
-00B019 Casi-Rusco
-00B01C Westport Technologies
-00B01E Rantic Labs, Inc.
-00B02A ORSYS GmbH
-00B02D ViaGate Technologies, Inc.
-00B03B HiQ Networks
-00B048 Marconi Communications Inc.
-00B04A Cisco Systems, Inc.
-00B052 Intellon Corporation
-00B064 Cisco Systems, Inc.
-00B069 Honewell Oy
-00B06D Jones Futurex Inc.
-00B080 Mannesmann Ipulsys B.V.
-00B086 LocSoft Limited
-00B08E Cisco Systems, Inc.
-00B091 Transmeta Corp.
-00B094 Alaris, Inc.
-00B09A Morrow Technologies Corp.
-00B09D Point Grey Research Inc.
-00B0AC SIAE-Microelettronica S.p.A.
-00B0AE Symmetricom
-00B0B3 Xstreamis PLC
-00B0C2 Cisco Systems, Inc.
-00B0C7 Tellabs Operations, Inc.
-00B0CE TECHNOLOGY RESCUE
-00B0D0 Dell Computer Corp.
-00B0DB Nextcell, Inc.
-00B0DF Reliable Data Technology, Inc.
-00B0E7 British Federal Ltd.
-00B0EC EACEM
-00B0EE Ajile Systems, Inc.
-00B0F0 CALY NETWORKS
-00B0F5 NetWorth Technologies, Inc.
-00BB01 OCTOTHORPE CORP.
-00BBF0 UNGERMANN-BASS INC.
-00C000 LANOPTICS, LTD.
-00C001 DIATEK PATIENT MANAGMENT
-00C002 SERCOMM CORPORATION
-00C003 GLOBALNET COMMUNICATIONS
-00C004 JAPAN BUSINESS COMPUTER CO.LTD
-00C005 LIVINGSTON ENTERPRISES, INC.
-00C006 NIPPON AVIONICS CO., LTD.
-00C007 PINNACLE DATA SYSTEMS, INC.
-00C008 SECO SRL
-00C009 KT TECHNOLOGY (S) PTE LTD
-00C00A MICRO CRAFT
-00C00B NORCONTROL A.S.
-00C00C RELIA TECHNOLGIES
-00C00D ADVANCED LOGIC RESEARCH, INC.
-00C00E PSITECH, INC.
-00C00F QUANTUM SOFTWARE SYSTEMS LTD.
-00C010 HIRAKAWA HEWTECH CORP.
-00C011 INTERACTIVE COMPUTING DEVICES
-00C012 NETSPAN CORPORATION
-00C013 NETRIX
-00C014 TELEMATICS CALABASAS INT'L,INC
-00C015 NEW MEDIA CORPORATION
-00C016 ELECTRONIC THEATRE CONTROLS
-00C017 FORTE NETWORKS
-00C018 LANART CORPORATION
-00C019 LEAP TECHNOLOGY, INC.
-00C01A COROMETRICS MEDICAL SYSTEMS
-00C01B SOCKET COMMUNICATIONS, INC.
-00C01C INTERLINK COMMUNICATIONS LTD.
-00C01D GRAND JUNCTION NETWORKS, INC.
-00C01E LA FRANCAISE DES JEUX
-00C01F S.E.R.C.E.L.
-00C020 ARCO ELECTRONIC, CONTROL LTD.
-00C021 NETEXPRESS
-00C022 LASERMASTER TECHNOLOGIES, INC.
-00C023 TUTANKHAMON ELECTRONICS
-00C024 EDEN SISTEMAS DE COMPUTACAO SA
-00C025 DATAPRODUCTS CORPORATION
-00C026 LANS TECHNOLOGY CO., LTD.
-00C027 CIPHER SYSTEMS, INC.
-00C028 JASCO CORPORATION
-00C029 Nexans Deutschland AG - ANS
-00C02A OHKURA ELECTRIC CO., LTD.
-00C02B GERLOFF GESELLSCHAFT FUR
-00C02C CENTRUM COMMUNICATIONS, INC.
-00C02D FUJI PHOTO FILM CO., LTD.
-00C02E NETWIZ
-00C02F OKUMA CORPORATION
-00C030 INTEGRATED ENGINEERING B. V.
-00C031 DESIGN RESEARCH SYSTEMS, INC.
-00C032 I-CUBED LIMITED
-00C033 TELEBIT COMMUNICATIONS APS
-00C034 TRANSACTION NETWORK
-00C035 QUINTAR COMPANY
-00C036 RAYTECH ELECTRONIC CORP.
-00C037 DYNATEM
-00C038 RASTER IMAGE PROCESSING SYSTEM
-00C039 TDK SEMICONDUCTOR CORPORATION
-00C03A MEN-MIKRO ELEKTRONIK GMBH
-00C03B MULTIACCESS COMPUTING CORP.
-00C03C TOWER TECH S.R.L.
-00C03D WIESEMANN & THEIS GMBH
-00C03E FA. GEBR. HELLER GMBH
-00C03F STORES AUTOMATED SYSTEMS, INC.
-00C040 ECCI
-00C041 DIGITAL TRANSMISSION SYSTEMS
-00C042 DATALUX CORP.
-00C043 STRATACOM
-00C044 EMCOM CORPORATION
-00C045 ISOLATION SYSTEMS, LTD.
-00C046 KEMITRON LTD.
-00C047 UNIMICRO SYSTEMS, INC.
-00C048 BAY TECHNICAL ASSOCIATES
-00C049 U.S. ROBOTICS, INC.
-00C04A GROUP 2000 AG
-00C04B CREATIVE MICROSYSTEMS
-00C04C DEPARTMENT OF FOREIGN AFFAIRS
-00C04D MITEC, INC.
-00C04E COMTROL CORPORATION
-00C04F DELL COMPUTER CORPORATION
-00C050 TOYO DENKI SEIZO K.K.
-00C051 ADVANCED INTEGRATION RESEARCH
-00C052 BURR-BROWN
-00C053 DAVOX CORPORATION
-00C054 NETWORK PERIPHERALS, LTD.
-00C055 MODULAR COMPUTING TECHNOLOGIES
-00C056 SOMELEC
-00C057 MYCO ELECTRONICS
-00C058 DATAEXPERT CORP.
-00C059 NIPPON DENSO CO., LTD.
-00C05A SEMAPHORE COMMUNICATIONS CORP.
-00C05B NETWORKS NORTHWEST, INC.
-00C05C ELONEX PLC
-00C05D L&N TECHNOLOGIES
-00C05E VARI-LITE, INC.
-00C05F FINE-PAL COMPANY LIMITED
-00C060 ID SCANDINAVIA AS
-00C061 SOLECTEK CORPORATION
-00C062 IMPULSE TECHNOLOGY
-00C063 MORNING STAR TECHNOLOGIES, INC
-00C064 GENERAL DATACOMM IND. INC.
-00C065 SCOPE COMMUNICATIONS, INC.
-00C066 DOCUPOINT, INC.
-00C067 UNITED BARCODE INDUSTRIES
-00C068 PHILIP DRAKE ELECTRONICS LTD.
-00C069 Axxcelera Broadband Wireless
-00C06A ZAHNER-ELEKTRIK GMBH & CO. KG
-00C06B OSI PLUS CORPORATION
-00C06C SVEC COMPUTER CORP.
-00C06D BOCA RESEARCH, INC.
-00C06E HAFT TECHNOLOGY, INC.
-00C06F KOMATSU LTD.
-00C070 SECTRA SECURE-TRANSMISSION AB
-00C071 AREANEX COMMUNICATIONS, INC.
-00C072 KNX LTD.
-00C073 XEDIA CORPORATION
-00C074 TOYODA AUTOMATIC LOOM
-00C075 XANTE CORPORATION
-00C076 I-DATA INTERNATIONAL A-S
-00C077 DAEWOO TELECOM LTD.
-00C078 COMPUTER SYSTEMS ENGINEERING
-00C079 FONSYS CO.,LTD.
-00C07A PRIVA B.V.
-00C07B ASCEND COMMUNICATIONS, INC.
-00C07C HIGHTECH INFORMATION
-00C07D RISC DEVELOPMENTS LTD.
-00C07E KUBOTA CORPORATION ELECTRONIC
-00C07F NUPON COMPUTING CORP.
-00C080 NETSTAR, INC.
-00C081 METRODATA LTD.
-00C082 MOORE PRODUCTS CO.
-00C083 TRACE MOUNTAIN PRODUCTS, INC.
-00C084 DATA LINK CORP. LTD.
-00C085 ELECTRONICS FOR IMAGING, INC.
-00C086 THE LYNK CORPORATION
-00C087 UUNET TECHNOLOGIES, INC.
-00C088 EKF ELEKTRONIK GMBH
-00C089 TELINDUS DISTRIBUTION
-00C08A LAUTERBACH DATENTECHNIK GMBH
-00C08B RISQ MODULAR SYSTEMS, INC.
-00C08C PERFORMANCE TECHNOLOGIES, INC.
-00C08D TRONIX PRODUCT DEVELOPMENT
-00C08E NETWORK INFORMATION TECHNOLOGY
-00C08F MATSUSHITA ELECTRIC WORKS, LTD
-00C090 PRAIM S.R.L.
-00C091 JABIL CIRCUIT, INC.
-00C092 MENNEN MEDICAL INC.
-00C093 ALTA RESEARCH CORP.
-00C094 VMX INC.
-00C095 ZNYX
-00C096 TAMURA CORPORATION
-00C097 ARCHIPEL SA
-00C098 CHUNTEX ELECTRONIC CO., LTD.
-00C099 YOSHIKI INDUSTRIAL CO.,LTD.
-00C09A PHOTONICS CORPORATION
-00C09B RELIANCE COMM/TEC, R-TEC
-00C09C TOA ELECTRONIC LTD.
-00C09D DISTRIBUTED SYSTEMS INT'L, INC
-00C09E CACHE COMPUTERS, INC.
-00C09F QUANTA COMPUTER, INC.
-00C0A0 ADVANCE MICRO RESEARCH, INC.
-00C0A1 TOKYO DENSHI SEKEI CO.
-00C0A2 INTERMEDIUM A/S
-00C0A3 DUAL ENTERPRISES CORPORATION
-00C0A4 UNIGRAF OY
-00C0A5 DICKENS DATA SYSTEMS
-00C0A6 EXICOM AUSTRALIA PTY. LTD
-00C0A7 SEEL LTD.
-00C0A8 GVC CORPORATION
-00C0A9 BARRON MCCANN LTD.
-00C0AA SILICON VALLEY COMPUTER
-00C0AB Telco Systems, Inc.
-00C0AC GAMBIT COMPUTER COMMUNICATIONS
-00C0AD MARBEN COMMUNICATION SYSTEMS
-00C0AE TOWERCOM CO. INC. DBA PC HOUSE
-00C0AF TEKLOGIX INC.
-00C0B0 GCC TECHNOLOGIES,INC.
-00C0B1 GENIUS NET CO.
-00C0B2 NORAND CORPORATION
-00C0B3 COMSTAT DATACOMM CORPORATION
-00C0B4 MYSON TECHNOLOGY, INC.
-00C0B5 CORPORATE NETWORK SYSTEMS,INC.
-00C0B6 Snap Appliance, Inc.
-00C0B7 AMERICAN POWER CONVERSION CORP
-00C0B8 FRASER'S HILL LTD.
-00C0B9 FUNK SOFTWARE, INC.
-00C0BA NETVANTAGE
-00C0BB FORVAL CREATIVE, INC.
-00C0BC TELECOM AUSTRALIA/CSSC
-00C0BD INEX TECHNOLOGIES, INC.
-00C0BE ALCATEL - SEL
-00C0BF TECHNOLOGY CONCEPTS, LTD.
-00C0C0 SHORE MICROSYSTEMS, INC.
-00C0C1 QUAD/GRAPHICS, INC.
-00C0C2 INFINITE NETWORKS LTD.
-00C0C3 ACUSON COMPUTED SONOGRAPHY
-00C0C4 COMPUTER OPERATIONAL
-00C0C5 SID INFORMATICA
-00C0C6 PERSONAL MEDIA CORP.
-00C0C7 SPARKTRUM MICROSYSTEMS, INC.
-00C0C8 MICRO BYTE PTY. LTD.
-00C0C9 ELSAG BAILEY PROCESS
-00C0CA ALFA, INC.
-00C0CB CONTROL TECHNOLOGY CORPORATION
-00C0CC TELESCIENCES CO SYSTEMS, INC.
-00C0CD COMELTA, S.A.
-00C0CE CEI SYSTEMS & ENGINEERING PTE
-00C0CF IMATRAN VOIMA OY
-00C0D0 RATOC SYSTEM INC.
-00C0D1 COMTREE TECHNOLOGY CORPORATION
-00C0D2 SYNTELLECT, INC.
-00C0D3 OLYMPUS IMAGE SYSTEMS, INC.
-00C0D4 AXON NETWORKS, INC.
-00C0D5 QUANCOM ELECTRONIC GMBH
-00C0D6 J1 SYSTEMS, INC.
-00C0D7 TAIWAN TRADING CENTER DBA
-00C0D8 UNIVERSAL DATA SYSTEMS
-00C0D9 QUINTE NETWORK CONFIDENTIALITY
-00C0DA NICE SYSTEMS LTD.
-00C0DB IPC CORPORATION (PTE) LTD.
-00C0DC EOS TECHNOLOGIES, INC.
-00C0DD QLogic Corporation
-00C0DE ZCOMM, INC.
-00C0DF KYE Systems Corp.
-00C0E0 DSC COMMUNICATION CORP.
-00C0E1 SONIC SOLUTIONS
-00C0E2 CALCOMP, INC.
-00C0E3 OSITECH COMMUNICATIONS, INC.
-00C0E4 SIEMENS BUILDING
-00C0E5 GESPAC, S.A.
-00C0E6 Verilink Corporation
-00C0E7 FIBERDATA AB
-00C0E8 PLEXCOM, INC.
-00C0E9 OAK SOLUTIONS, LTD.
-00C0EA ARRAY TECHNOLOGY LTD.
-00C0EB SEH COMPUTERTECHNIK GMBH
-00C0EC DAUPHIN TECHNOLOGY
-00C0ED US ARMY ELECTRONIC
-00C0EE KYOCERA CORPORATION
-00C0EF ABIT CORPORATION
-00C0F0 KINGSTON TECHNOLOGY CORP.
-00C0F1 SHINKO ELECTRIC CO., LTD.
-00C0F2 TRANSITION NETWORKS
-00C0F3 NETWORK COMMUNICATIONS CORP.
-00C0F4 INTERLINK SYSTEM CO., LTD.
-00C0F5 METACOMP, INC.
-00C0F6 CELAN TECHNOLOGY INC.
-00C0F7 ENGAGE COMMUNICATION, INC.
-00C0F8 ABOUT COMPUTING INC.
-00C0F9 HARRIS AND JEFFRIES, INC.
-00C0FA CANARY COMMUNICATIONS, INC.
-00C0FB ADVANCED TECHNOLOGY LABS
-00C0FC ELASTIC REALITY, INC.
-00C0FD PROSUM
-00C0FE APTEC COMPUTER SYSTEMS, INC.
-00C0FF DOT HILL SYSTEMS CORPORATION
-00CBBD Cambridge Broadband Ltd.
-00CF1C COMMUNICATION MACHINERY CORP.
-00D000 FERRAN SCIENTIFIC, INC.
-00D001 VST TECHNOLOGIES, INC.
-00D002 DITECH CORPORATION
-00D003 COMDA ENTERPRISES CORP.
-00D004 PENTACOM LTD.
-00D005 ZHS ZEITMANAGEMENTSYSTEME
-00D006 CISCO SYSTEMS, INC.
-00D007 MIC ASSOCIATES, INC.
-00D008 MACTELL CORPORATION
-00D009 HSING TECH. ENTERPRISE CO. LTD
-00D00A LANACCESS TELECOM S.A.
-00D00B RHK TECHNOLOGY, INC.
-00D00C SNIJDER MICRO SYSTEMS
-00D00D MICROMERITICS INSTRUMENT
-00D00E PLURIS, INC.
-00D00F SPEECH DESIGN GMBH
-00D010 CONVERGENT NETWORKS, INC.
-00D011 PRISM VIDEO, INC.
-00D012 GATEWORKS CORP.
-00D013 PRIMEX AEROSPACE COMPANY
-00D014 ROOT, INC.
-00D015 UNIVEX MICROTECHNOLOGY CORP.
-00D016 SCM MICROSYSTEMS, INC.
-00D017 SYNTECH INFORMATION CO., LTD.
-00D018 QWES. COM, INC.
-00D019 DAINIPPON SCREEN CORPORATE
-00D01A URMET SUD S.P.A.
-00D01B MIMAKI ENGINEERING CO., LTD.
-00D01C SBS TECHNOLOGIES,
-00D01D FURUNO ELECTRIC CO., LTD.
-00D01E PINGTEL CORP.
-00D01F CTAM PTY. LTD.
-00D020 AIM SYSTEM, INC.
-00D021 REGENT ELECTRONICS CORP.
-00D022 INCREDIBLE TECHNOLOGIES, INC.
-00D023 INFORTREND TECHNOLOGY, INC.
-00D024 Cognex Corporation
-00D025 XROSSTECH, INC.
-00D026 HIRSCHMANN AUSTRIA GMBH
-00D027 APPLIED AUTOMATION, INC.
-00D028 OMNEON VIDEO NETWORKS
-00D029 WAKEFERN FOOD CORPORATION
-00D02A Voxent Systems Ltd.
-00D02B JETCELL, INC.
-00D02C CAMPBELL SCIENTIFIC, INC.
-00D02D ADEMCO
-00D02E COMMUNICATION AUTOMATION CORP.
-00D02F VLSI TECHNOLOGY INC.
-00D030 SAFETRAN SYSTEMS CORP.
-00D031 INDUSTRIAL LOGIC CORPORATION
-00D032 YANO ELECTRIC CO., LTD.
-00D033 DALIAN DAXIAN NETWORK
-00D034 ORMEC SYSTEMS CORP.
-00D035 BEHAVIOR TECH. COMPUTER CORP.
-00D036 TECHNOLOGY ATLANTA CORP.
-00D037 PHILIPS-DVS-LO BDR
-00D038 FIVEMERE, LTD.
-00D039 UTILICOM, INC.
-00D03A ZONEWORX, INC.
-00D03B VISION PRODUCTS PTY. LTD.
-00D03C Vieo, Inc.
-00D03D GALILEO TECHNOLOGY, LTD.
-00D03E ROCKETCHIPS, INC.
-00D03F AMERICAN COMMUNICATION
-00D040 SYSMATE CO., LTD.
-00D041 AMIGO TECHNOLOGY CO., LTD.
-00D042 MAHLO GMBH & CO. UG
-00D043 ZONAL RETAIL DATA SYSTEMS
-00D044 ALIDIAN NETWORKS, INC.
-00D045 KVASER AB
-00D046 DOLBY LABORATORIES, INC.
-00D047 XN TECHNOLOGIES
-00D048 ECTON, INC.
-00D049 IMPRESSTEK CO., LTD.
-00D04A PRESENCE TECHNOLOGY GMBH
-00D04B LA CIE GROUP S.A.
-00D04C EUROTEL TELECOM LTD.
-00D04D DIV OF RESEARCH & STATISTICS
-00D04E LOGIBAG
-00D04F BITRONICS, INC.
-00D050 ISKRATEL
-00D051 O2 MICRO, INC.
-00D052 ASCEND COMMUNICATIONS, INC.
-00D053 CONNECTED SYSTEMS
-00D054 SAS INSTITUTE INC.
-00D055 KATHREIN-WERKE KG
-00D056 SOMAT CORPORATION
-00D057 ULTRAK, INC.
-00D058 CISCO SYSTEMS, INC.
-00D059 AMBIT MICROSYSTEMS CORP.
-00D05A SYMBIONICS, LTD.
-00D05B ACROLOOP MOTION CONTROL
-00D05C TECHNOTREND SYSTEMTECHNIK GMBH
-00D05D INTELLIWORXX, INC.
-00D05E STRATABEAM TECHNOLOGY, INC.
-00D05F VALCOM, INC.
-00D060 PANASONIC EUROPEAN
-00D061 TREMON ENTERPRISES CO., LTD.
-00D062 DIGIGRAM
-00D063 CISCO SYSTEMS, INC.
-00D064 MULTITEL
-00D065 TOKO ELECTRIC
-00D066 WINTRISS ENGINEERING CORP.
-00D067 CAMPIO COMMUNICATIONS
-00D068 IWILL CORPORATION
-00D069 TECHNOLOGIC SYSTEMS
-00D06A LINKUP SYSTEMS CORPORATION
-00D06B SR TELECOM INC.
-00D06C SHAREWAVE, INC.
-00D06D ACRISON, INC.
-00D06E TRENDVIEW RECORDERS LTD.
-00D06F KMC CONTROLS
-00D070 LONG WELL ELECTRONICS CORP.
-00D071 ECHELON CORP.
-00D072 BROADLOGIC
-00D073 ACN ADVANCED COMMUNICATIONS
-00D074 TAQUA SYSTEMS, INC.
-00D075 ALARIS MEDICAL SYSTEMS, INC.
-00D076 MERRILL LYNCH & CO., INC.
-00D077 LUCENT TECHNOLOGIES
-00D078 ELTEX OF SWEDEN AB
-00D079 CISCO SYSTEMS, INC.
-00D07A AMAQUEST COMPUTER CORP.
-00D07B COMCAM INTERNATIONAL LTD.
-00D07C KOYO ELECTRONICS INC. CO.,LTD.
-00D07D COSINE COMMUNICATIONS
-00D07E KEYCORP LTD.
-00D07F STRATEGY & TECHNOLOGY, LIMITED
-00D080 EXABYTE CORPORATION
-00D081 REAL TIME DEVICES USA, INC.
-00D082 IOWAVE INC.
-00D083 INVERTEX, INC.
-00D084 NEXCOMM SYSTEMS, INC.
-00D085 OTIS ELEVATOR COMPANY
-00D086 FOVEON, INC.
-00D087 MICROFIRST INC.
-00D088 Terayon Communications Systems
-00D089 DYNACOLOR, INC.
-00D08A PHOTRON USA
-00D08B ADVA Limited
-00D08C GENOA TECHNOLOGY, INC.
-00D08D PHOENIX GROUP, INC.
-00D08E NVISION INC.
-00D08F ARDENT TECHNOLOGIES, INC.
-00D090 CISCO SYSTEMS, INC.
-00D091 SMARTSAN SYSTEMS, INC.
-00D092 GLENAYRE WESTERN MULTIPLEX
-00D093 TQ - COMPONENTS GMBH
-00D094 TIMELINE VISTA, INC.
-00D095 XYLAN CORPORATION
-00D096 3COM EUROPE LTD.
-00D097 CISCO SYSTEMS, INC.
-00D098 Photon Dynamics Canada Inc.
-00D099 ELCARD OY
-00D09A FILANET CORPORATION
-00D09B SPECTEL LTD.
-00D09C KAPADIA COMMUNICATIONS
-00D09D VERIS INDUSTRIES
-00D09E 2WIRE, INC.
-00D09F NOVTEK TEST SYSTEMS
-00D0A0 MIPS DENMARK
-00D0A1 OSKAR VIERLING GMBH + CO. KG
-00D0A2 INTEGRATED DEVICE
-00D0A3 VOCAL DATA, INC.
-00D0A4 ALANTRO COMMUNICATIONS
-00D0A5 AMERICAN ARIUM
-00D0A6 LANBIRD TECHNOLOGY CO., LTD.
-00D0A7 TOKYO SOKKI KENKYUJO CO., LTD.
-00D0A8 NETWORK ENGINES, INC.
-00D0A9 SHINANO KENSHI CO., LTD.
-00D0AA CHASE COMMUNICATIONS
-00D0AB DELTAKABEL TELECOM CV
-00D0AC GRAYSON WIRELESS
-00D0AD TL INDUSTRIES
-00D0AE ORESIS COMMUNICATIONS, INC.
-00D0AF CUTLER-HAMMER, INC.
-00D0B0 BITSWITCH LTD.
-00D0B1 OMEGA ELECTRONICS SA
-00D0B2 XIOTECH CORPORATION
-00D0B3 DRS FLIGHT SAFETY AND
-00D0B4 KATSUJIMA CO., LTD.
-00D0B5 IPricot formerly DotCom
-00D0B6 CRESCENT NETWORKS, INC.
-00D0B7 INTEL CORPORATION
-00D0B8 IOMEGA CORP.
-00D0B9 MICROTEK INTERNATIONAL, INC.
-00D0BA CISCO SYSTEMS, INC.
-00D0BB CISCO SYSTEMS, INC.
-00D0BC CISCO SYSTEMS, INC.
-00D0BD SICAN GMBH
-00D0BE EMUTEC INC.
-00D0BF PIVOTAL TECHNOLOGIES
-00D0C0 CISCO SYSTEMS, INC.
-00D0C1 HARMONIC DATA SYSTEMS, LTD.
-00D0C2 BALTHAZAR TECHNOLOGY AB
-00D0C3 VIVID TECHNOLOGY PTE, LTD.
-00D0C4 TERATECH CORPORATION
-00D0C5 COMPUTATIONAL SYSTEMS, INC.
-00D0C6 THOMAS & BETTS CORP.
-00D0C7 PATHWAY, INC.
-00D0C8 I/O CONSULTING A/S
-00D0C9 ADVANTECH CO., LTD.
-00D0CA INTRINSYC SOFTWARE INC.
-00D0CB DASAN CO., LTD.
-00D0CC TECHNOLOGIES LYRE INC.
-00D0CD ATAN TECHNOLOGY INC.
-00D0CE ASYST ELECTRONIC
-00D0CF MORETON BAY
-00D0D0 ZHONGXING TELECOM LTD.
-00D0D1 SIROCCO SYSTEMS, INC.
-00D0D2 EPILOG CORPORATION
-00D0D3 CISCO SYSTEMS, INC.
-00D0D4 V-BITS, INC.
-00D0D5 GRUNDIG AG
-00D0D6 AETHRA TELECOMUNICAZIONI
-00D0D7 B2C2, INC.
-00D0D8 3Com Corporation
-00D0D9 DEDICATED MICROCOMPUTERS
-00D0DA TAICOM DATA SYSTEMS CO., LTD.
-00D0DB MCQUAY INTERNATIONAL
-00D0DC MODULAR MINING SYSTEMS, INC.
-00D0DD SUNRISE TELECOM, INC.
-00D0DE PHILIPS MULTIMEDIA NETWORK
-00D0DF KUZUMI ELECTRONICS, INC.
-00D0E0 DOOIN ELECTRONICS CO.
-00D0E1 AVIONITEK ISRAEL INC.
-00D0E2 MRT MICRO, INC.
-00D0E3 ELE-CHEM ENGINEERING CO., LTD.
-00D0E4 CISCO SYSTEMS, INC.
-00D0E5 SOLIDUM SYSTEMS CORP.
-00D0E6 IBOND INC.
-00D0E7 VCON TELECOMMUNICATION LTD.
-00D0E8 MAC SYSTEM CO., LTD.
-00D0E9 ADVANTAGE CENTURY
-00D0EA NEXTONE COMMUNICATIONS, INC.
-00D0EB LIGHTERA NETWORKS, INC.
-00D0EC NAKAYO TELECOMMUNICATIONS, INC
-00D0ED XIOX
-00D0EE DICTAPHONE CORPORATION
-00D0EF IGT
-00D0F0 CONVISION TECHNOLOGY GMBH
-00D0F1 SEGA ENTERPRISES, LTD.
-00D0F2 MONTEREY NETWORKS
-00D0F3 SOLARI DI UDINE SPA
-00D0F4 CARINTHIAN TECH INSTITUTE
-00D0F5 ORANGE MICRO, INC.
-00D0F6 Alcatel Canada
-00D0F7 NEXT NETS CORPORATION
-00D0F8 FUJIAN STAR TERMINAL
-00D0F9 ACUTE COMMUNICATIONS CORP.
-00D0FA RACAL GUARDATA
-00D0FB TEK MICROSYSTEMS, INCORPORATED
-00D0FC GRANITE MICROSYSTEMS
-00D0FD OPTIMA TELE.COM, INC.
-00D0FE ASTRAL POINT
-00D0FF CISCO SYSTEMS, INC.
-00DD00 UNGERMANN-BASS INC.
-00DD01 UNGERMANN-BASS INC.
-00DD02 UNGERMANN-BASS INC.
-00DD03 UNGERMANN-BASS INC.
-00DD04 UNGERMANN-BASS INC.
-00DD05 UNGERMANN-BASS INC.
-00DD06 UNGERMANN-BASS INC.
-00DD07 UNGERMANN-BASS INC.
-00DD08 UNGERMANN-BASS INC.
-00DD09 UNGERMANN-BASS INC.
-00DD0A UNGERMANN-BASS INC.
-00DD0B UNGERMANN-BASS INC.
-00DD0C UNGERMANN-BASS INC.
-00DD0D UNGERMANN-BASS INC.
-00DD0E UNGERMANN-BASS INC.
-00DD0F UNGERMANN-BASS INC.
-00E000 FUJITSU, LTD
-00E001 STRAND LIGHTING LIMITED
-00E002 CROSSROADS SYSTEMS, INC.
-00E003 NOKIA WIRELESS BUSINESS COMMUN
-00E004 PMC-SIERRA, INC.
-00E005 TECHNICAL CORP.
-00E006 SILICON INTEGRATED SYS. CORP.
-00E007 NETWORK ALCHEMY LTD.
-00E008 AMAZING CONTROLS! INC.
-00E009 MARATHON TECHNOLOGIES CORP.
-00E00A DIBA, INC.
-00E00B ROOFTOP COMMUNICATIONS CORP.
-00E00C MOTOROLA
-00E00D RADIANT SYSTEMS
-00E00E AVALON IMAGING SYSTEMS, INC.
-00E00F SHANGHAI BAUD DATA
-00E010 HESS SB-AUTOMATENBAU GmbH
-00E011 UNIDEN SAN DIEGO R&D CENTER, INC.
-00E012 PLUTO TECHNOLOGIES INTERNATIONAL INC.
-00E013 EASTERN ELECTRONIC CO., LTD.
-00E014 CISCO SYSTEMS, INC.
-00E015 HEIWA CORPORATION
-00E016 RAPID CITY COMMUNICATIONS
-00E017 EXXACT GmbH
-00E018 ASUSTEK COMPUTER INC.
-00E019 ING. GIORDANO ELETTRONICA
-00E01A COMTEC SYSTEMS. CO., LTD.
-00E01B SPHERE COMMUNICATIONS, INC.
-00E01C MOBILITY ELECTRONICSY
-00E01D WebTV NETWORKS, INC.
-00E01E CISCO SYSTEMS, INC.
-00E01F AVIDIA Systems, Inc.
-00E020 TECNOMEN OY
-00E021 FREEGATE CORP.
-00E022 MediaLight, Inc.
-00E023 TELRAD
-00E024 GADZOOX NETWORKS
-00E025 dit CO., LTD.
-00E026 EASTMAN KODAK CO.
-00E027 DUX, INC.
-00E028 APTIX CORPORATION
-00E029 STANDARD MICROSYSTEMS CORP.
-00E02A TANDBERG TELEVISION AS
-00E02B EXTREME NETWORKS
-00E02C AST COMPUTER
-00E02D InnoMediaLogic, Inc.
-00E02E SPC ELECTRONICS CORPORATION
-00E02F MCNS HOLDINGS, L.P.
-00E030 MELITA INTERNATIONAL CORP.
-00E031 HAGIWARA ELECTRIC CO., LTD.
-00E032 MISYS FINANCIAL SYSTEMS, LTD.
-00E033 E.E.P.D. GmbH
-00E034 CISCO SYSTEMS, INC.
-00E035 LOUGHBOROUGH SOUND IMAGES, PLC
-00E036 PIONEER CORPORATION
-00E037 CENTURY CORPORATION
-00E038 PROXIMA CORPORATION
-00E039 PARADYNE CORP.
-00E03A CABLETRON SYSTEMS, INC.
-00E03B PROMINET CORPORATION
-00E03C AdvanSys
-00E03D FOCON ELECTRONIC SYSTEMS A/S
-00E03E ALFATECH, INC.
-00E03F JATON CORPORATION
-00E040 DeskStation Technology, Inc.
-00E041 CSPI
-00E042 Pacom Systems Ltd.
-00E043 VitalCom
-00E044 LSICS CORPORATION
-00E045 TOUCHWAVE, INC.
-00E046 BENTLY NEVADA CORP.
-00E047 INFOCUS SYSTEMS
-00E048 SDL COMMUNICATIONS, INC.
-00E049 MICROWI ELECTRONIC GmbH
-00E04A ENHANCED MESSAGING SYSTEMS, INC
-00E04B JUMP INDUSTRIELLE COMPUTERTECHNIK GmbH
-00E04C REALTEK SEMICONDUCTOR CORP.
-00E04D INTERNET INITIATIVE JAPAN, INC
-00E04E SANYO DENKI CO., LTD.
-00E04F CISCO SYSTEMS, INC.
-00E050 EXECUTONE INFORMATION SYSTEMS, INC.
-00E051 TALX CORPORATION
-00E052 FOUNDRY NETWORKS, INC.
-00E053 CELLPORT LABS, INC.
-00E054 KODAI HITEC CO., LTD.
-00E055 INGENIERIA ELECTRONICA COMERCIAL INELCOM S.A.
-00E056 HOLONTECH CORPORATION
-00E057 HAN MICROTELECOM. CO., LTD.
-00E058 PHASE ONE DENMARK A/S
-00E059 CONTROLLED ENVIRONMENTS, LTD.
-00E05A GALEA NETWORK SECURITY
-00E05B WEST END SYSTEMS CORP.
-00E05C MATSUSHITA KOTOBUKI ELECTRONICS INDUSTRIES, LTD.
-00E05D UNITEC CO., LTD.
-00E05E JAPAN AVIATION ELECTRONICS INDUSTRY, LTD.
-00E05F e-Net, Inc.
-00E060 SHERWOOD
-00E061 EdgePoint Networks, Inc.
-00E062 HOST ENGINEERING
-00E063 CABLETRON - YAGO SYSTEMS, INC.
-00E064 SAMSUNG ELECTRONICS
-00E065 OPTICAL ACCESS INTERNATIONAL
-00E066 ProMax Systems, Inc.
-00E067 eac AUTOMATION-CONSULTING GmbH
-00E068 MERRIMAC SYSTEMS INC.
-00E069 JAYCOR
-00E06A KAPSCH AG
-00E06B W&G SPECIAL PRODUCTS
-00E06C AEP Systems International Ltd
-00E06D COMPUWARE CORPORATION
-00E06E FAR SYSTEMS S.p.A.
-00E06F Terayon Communications Systems
-00E070 DH TECHNOLOGY
-00E071 EPIS MICROCOMPUTER
-00E072 LYNK
-00E073 NATIONAL AMUSEMENT NETWORK, INC.
-00E074 TIERNAN COMMUNICATIONS, INC.
-00E075 Verilink Corporation
-00E076 DEVELOPMENT CONCEPTS, INC.
-00E077 WEBGEAR, INC.
-00E078 BERKELEY NETWORKS
-00E079 A.T.N.R.
-00E07A MIKRODIDAKT AB
-00E07B BAY NETWORKS
-00E07C METTLER-TOLEDO, INC.
-00E07D NETRONIX, INC.
-00E07E WALT DISNEY IMAGINEERING
-00E07F LOGISTISTEM s.r.l.
-00E080 CONTROL RESOURCES CORPORATION
-00E081 TYAN COMPUTER CORP.
-00E082 ANERMA
-00E083 JATO TECHNOLOGIES, INC.
-00E084 COMPULITE R&D
-00E085 GLOBAL MAINTECH, INC.
-00E086 CYBEX COMPUTER PRODUCTS
-00E087 LeCroy - Networking Productions Division
-00E088 LTX CORPORATION
-00E089 ION Networks, Inc.
-00E08A GEC AVERY, LTD.
-00E08B QLogic Corp.
-00E08C NEOPARADIGM LABS, INC.
-00E08D PRESSURE SYSTEMS, INC.
-00E08E UTSTARCOM
-00E08F CISCO SYSTEMS, INC.
-00E090 BECKMAN LAB. AUTOMATION DIV.
-00E091 LG ELECTRONICS, INC.
-00E092 ADMTEK INCORPORATED
-00E093 ACKFIN NETWORKS
-00E094 OSAI SRL
-00E095 ADVANCED-VISION TECHNOLGIES CORP.
-00E096 SHIMADZU CORPORATION
-00E097 CARRIER ACCESS CORPORATION
-00E098 AboCom Systems, Inc.
-00E099 SAMSON AG
-00E09A POSITRON INDUSTRIES, INC.
-00E09B ENGAGE NETWORKS, INC.
-00E09C MII
-00E09D SARNOFF CORPORATION
-00E09E QUANTUM CORPORATION
-00E09F PIXEL VISION
-00E0A0 WILTRON CO.
-00E0A1 HIMA PAUL HILDEBRANDT GmbH Co. KG
-00E0A2 MICROSLATE INC.
-00E0A3 CISCO SYSTEMS, INC.
-00E0A4 ESAOTE S.p.A.
-00E0A5 ComCore Semiconductor, Inc.
-00E0A6 TELOGY NETWORKS, INC.
-00E0A7 IPC INFORMATION SYSTEMS, INC.
-00E0A8 SAT GmbH & Co.
-00E0A9 FUNAI ELECTRIC CO., LTD.
-00E0AA ELECTROSONIC LTD.
-00E0AB DIMAT S.A.
-00E0AC MIDSCO, INC.
-00E0AD EES TECHNOLOGY, LTD.
-00E0AE XAQTI CORPORATION
-00E0AF GENERAL DYNAMICS INFORMATION SYSTEMS
-00E0B0 CISCO SYSTEMS, INC.
-00E0B1 PACKET ENGINES, INC.
-00E0B2 TELMAX COMMUNICATIONS CORP.
-00E0B3 EtherWAN Systems, Inc.
-00E0B4 TECHNO SCOPE CO., LTD.
-00E0B5 ARDENT COMMUNICATIONS CORP.
-00E0B6 Entrada Networks
-00E0B7 PI GROUP, LTD.
-00E0B8 GATEWAY 2000
-00E0B9 BYAS SYSTEMS
-00E0BA BERGHOF AUTOMATIONSTECHNIK GmbH
-00E0BB NBX CORPORATION
-00E0BC SYMON COMMUNICATIONS, INC.
-00E0BD INTERFACE SYSTEMS, INC.
-00E0BE GENROCO INTERNATIONAL, INC.
-00E0BF TORRENT NETWORKING TECHNOLOGIES CORP.
-00E0C0 SEIWA ELECTRIC MFG. CO., LTD.
-00E0C1 MEMOREX TELEX JAPAN, LTD.
-00E0C2 NECSY S.p.A.
-00E0C3 SAKAI SYSTEM DEVELOPMENT CORP.
-00E0C4 HORNER ELECTRIC, INC.
-00E0C5 BCOM ELECTRONICS INC.
-00E0C6 LINK2IT, L.L.C.
-00E0C7 EUROTECH SRL
-00E0C8 VIRTUAL ACCESS, LTD.
-00E0C9 AutomatedLogic Corporation
-00E0CA BEST DATA PRODUCTS
-00E0CB RESON, INC.
-00E0CC HERO SYSTEMS, LTD.
-00E0CD SENSIS CORPORATION
-00E0CE ARN
-00E0CF INTEGRATED DEVICE TECHNOLOGY, INC.
-00E0D0 NETSPEED, INC.
-00E0D1 TELSIS LIMITED
-00E0D2 VERSANET COMMUNICATIONS, INC.
-00E0D3 DATENTECHNIK GmbH
-00E0D4 EXCELLENT COMPUTER
-00E0D5 ARCXEL TECHNOLOGIES, INC.
-00E0D6 COMPUTER & COMMUNICATION RESEARCH LAB.
-00E0D7 SUNSHINE ELECTRONICS, INC.
-00E0D8 LANBit Computer, Inc.
-00E0D9 TAZMO CO., LTD.
-00E0DA ASSURED ACCESS TECHNOLOGY, INC.
-00E0DB ViaVideo Communications, Inc.
-00E0DC NEXWARE CORP.
-00E0DD ZENITH ELECTRONICS CORPORATION
-00E0DE DATAX NV
-00E0DF KE KOMMUNIKATIONS-ELECTRONIK
-00E0E0 SI ELECTRONICS, LTD.
-00E0E1 G2 NETWORKS, INC.
-00E0E2 INNOVA CORP.
-00E0E3 SK-ELEKTRONIK GmbH
-00E0E4 FANUC ROBOTICS NORTH AMERICA, Inc.
-00E0E5 CINCO NETWORKS, INC.
-00E0E6 INCAA DATACOM B.V.
-00E0E7 RAYTHEON E-SYSTEMS, INC.
-00E0E8 GRETACODER Data Systems AG
-00E0E9 DATA LABS, INC.
-00E0EA INNOVAT COMMUNICATIONS, INC.
-00E0EB DIGICOM SYSTEMS, INCORPORATED
-00E0EC CELESTICA INC.
-00E0ED SILICOM, LTD.
-00E0EE MAREL HF
-00E0EF DIONEX
-00E0F0 ABLER TECHNOLOGY, INC.
-00E0F1 THAT CORPORATION
-00E0F2 ARLOTTO COMNET, INC.
-00E0F3 WebSprint Communications, Inc.
-00E0F4 INSIDE Technology A/S
-00E0F5 TELES AG
-00E0F6 DECISION EUROPE
-00E0F7 CISCO SYSTEMS, INC.
-00E0F8 DICNA CONTROL AB
-00E0F9 CISCO SYSTEMS, INC.
-00E0FA TRL TECHNOLOGY, LTD.
-00E0FB LEIGHTRONIX, INC.
-00E0FC HUAWEI TECHNOLOGIES CO., LTD.
-00E0FD A-TREND TECHNOLOGY CO., LTD.
-00E0FE CISCO SYSTEMS, INC.
-00E0FF SECURITY DYNAMICS TECHNOLOGIES, Inc.
-00E6D3 NIXDORF COMPUTER CORP.
-020701 RACAL-DATACOM
-021C7C PERQ SYSTEMS CORPORATION
-026086 LOGIC REPLACEMENT TECH. LTD.
-02608C 3COM CORPORATION
-027001 RACAL-DATACOM
-0270B0 M/A-COM INC. COMPANIES
-0270B3 DATA RECALL LTD
-029D8E CARDIAC RECORDERS INC.
-02AA3C OLIVETTI TELECOMM SPA (OLTECO)
-02BB01 OCTOTHORPE CORP.
-02C08C 3COM CORPORATION
-02CF1C COMMUNICATION MACHINERY CORP.
-02E6D3 NIXDORF COMPUTER CORPORATION
-040AE0 XMIT AG COMPUTER NETWORKS
-04E0C4 TRIUMPH-ADLER AG
-080001 COMPUTERVISION CORPORATION
-080002 BRIDGE COMMUNICATIONS INC.
-080003 ADVANCED COMPUTER COMM.
-080004 CROMEMCO INCORPORATED
-080005 SYMBOLICS INC.
-080006 SIEMENS AG
-080007 APPLE COMPUTER INC.
-080008 BOLT BERANEK AND NEWMAN INC.
-080009 HEWLETT PACKARD
-08000A NESTAR SYSTEMS INCORPORATED
-08000B UNISYS CORPORATION
-08000C MIKLYN DEVELOPMENT CO.
-08000D INTERNATIONAL COMPUTERS LTD.
-08000E NCR CORPORATION
-08000F MITEL CORPORATION
-080011 TEKTRONIX INC.
-080012 BELL ATLANTIC INTEGRATED SYST.
-080013 EXXON
-080014 EXCELAN
-080015 STC BUSINESS SYSTEMS
-080016 BARRISTER INFO SYS CORP
-080017 NATIONAL SEMICONDUCTOR
-080018 PIRELLI FOCOM NETWORKS
-080019 GENERAL ELECTRIC CORPORATION
-08001A TIARA/ 10NET
-08001B DATA GENERAL
-08001C KDD-KOKUSAI DEBNSIN DENWA CO.
-08001D ABLE COMMUNICATIONS INC.
-08001E APOLLO COMPUTER INC.
-08001F SHARP CORPORATION
-080020 SUN MICROSYSTEMS INC.
-080021 3M COMPANY
-080022 NBI INC.
-080023 Panasonic Communications Co., Ltd.
-080024 10NET COMMUNICATIONS/DCA
-080025 CONTROL DATA
-080026 NORSK DATA A.S.
-080027 CADMUS COMPUTER SYSTEMS
-080028 Texas Instruments
-080029 MEGATEK CORPORATION
-08002A MOSAIC TECHNOLOGIES INC.
-08002B DIGITAL EQUIPMENT CORPORATION
-08002C BRITTON LEE INC.
-08002D LAN-TEC INC.
-08002E METAPHOR COMPUTER SYSTEMS
-08002F PRIME COMPUTER INC.
-080030 NETWORK RESEARCH CORPORATION
-080030 CERN
-080030 ROYAL MELBOURNE INST OF TECH
-080031 LITTLE MACHINES INC.
-080032 TIGAN INCORPORATED
-080033 BAUSCH & LOMB
-080034 FILENET CORPORATION
-080035 MICROFIVE CORPORATION
-080036 INTERGRAPH CORPORATION
-080037 FUJI-XEROX CO. LTD.
-080038 CII HONEYWELL BULL
-080039 SPIDER SYSTEMS LIMITED
-08003A ORCATECH INC.
-08003B TORUS SYSTEMS LIMITED
-08003C SCHLUMBERGER WELL SERVICES
-08003D CADNETIX CORPORATIONS
-08003E CODEX CORPORATION
-08003F FRED KOSCHARA ENTERPRISES
-080040 FERRANTI COMPUTER SYS. LIMITED
-080041 RACAL-MILGO INFORMATION SYS..
-080042 JAPAN MACNICS CORP.
-080043 PIXEL COMPUTER INC.
-080044 DAVID SYSTEMS INC.
-080045 CONCURRENT COMPUTER CORP.
-080046 SONY CORPORATION LTD.
-080047 SEQUENT COMPUTER SYSTEMS INC.
-080048 EUROTHERM GAUGING SYSTEMS
-080049 UNIVATION
-08004A BANYAN SYSTEMS INC.
-08004B PLANNING RESEARCH CORP.
-08004C HYDRA COMPUTER SYSTEMS INC.
-08004D CORVUS SYSTEMS INC.
-08004E 3COM EUROPE LTD.
-08004F CYGNET SYSTEMS
-080050 DAISY SYSTEMS CORP.
-080051 EXPERDATA
-080052 INSYSTEC
-080053 MIDDLE EAST TECH. UNIVERSITY
-080055 STANFORD TELECOMM. INC.
-080056 STANFORD LINEAR ACCEL. CENTER
-080057 EVANS & SUTHERLAND
-080058 SYSTEMS CONCEPTS
-080059 A/S MYCRON
-08005A IBM CORPORATION
-08005B VTA TECHNOLOGIES INC.
-08005C FOUR PHASE SYSTEMS
-08005D GOULD INC.
-08005E COUNTERPOINT COMPUTER INC.
-08005F SABER TECHNOLOGY CORP.
-080060 INDUSTRIAL NETWORKING INC.
-080061 JAROGATE LTD.
-080062 GENERAL DYNAMICS
-080063 PLESSEY
-080064 AUTOPHON AG
-080065 GENRAD INC.
-080066 AGFA CORPORATION
-080067 COMDESIGN
-080068 RIDGE COMPUTERS
-080069 SILICON GRAPHICS INC.
-08006A ATT BELL LABORATORIES
-08006B ACCEL TECHNOLOGIES INC.
-08006C SUNTEK TECHNOLOGY INT'L
-08006D WHITECHAPEL COMPUTER WORKS
-08006E MASSCOMP
-08006F PHILIPS APELDOORN B.V.
-080070 MITSUBISHI ELECTRIC CORP.
-080071 MATRA (DSIE)
-080072 XEROX CORP UNIV GRANT PROGRAM
-080073 TECMAR INC.
-080074 CASIO COMPUTER CO. LTD.
-080075 DANSK DATA ELECTRONIK
-080076 PC LAN TECHNOLOGIES
-080077 TSL COMMUNICATIONS LTD.
-080078 ACCELL CORPORATION
-080079 THE DROID WORKS
-08007A INDATA
-08007B SANYO ELECTRIC CO. LTD.
-08007C VITALINK COMMUNICATIONS CORP.
-08007E AMALGAMATED WIRELESS(AUS) LTD
-08007F CARNEGIE-MELLON UNIVERSITY
-080080 AES DATA INC.
-080081 ,ASTECH INC.
-080082 VERITAS SOFTWARE
-080083 Seiko Instruments Inc.
-080084 TOMEN ELECTRONICS CORP.
-080085 ELXSI
-080086 KONICA MINOLTA HOLDINGS, INC.
-080087 XYPLEX
-080088 MCDATA CORPORATION
-080089 KINETICS
-08008A PERFORMANCE TECHNOLOGY
-08008B PYRAMID TECHNOLOGY CORP.
-08008C NETWORK RESEARCH CORPORATION
-08008D XYVISION INC.
-08008E TANDEM COMPUTERS
-08008F CHIPCOM CORPORATION
-080090 SONOMA SYSTEMS
-081443 UNIBRAIN S.A.
-08BBCC AK-NORD EDV VERTRIEBSGES. mbH
-10005A IBM CORPORATION
-1000E8 NATIONAL SEMICONDUCTOR
-800010 ATT BELL LABORATORIES
-A06A00 Verilink Corporation
-AA0000 DIGITAL EQUIPMENT CORPORATION
-AA0001 DIGITAL EQUIPMENT CORPORATION
-AA0002 DIGITAL EQUIPMENT CORPORATION
-AA0003 DIGITAL EQUIPMENT CORPORATION
-AA0004 DIGITAL EQUIPMENT CORPORATION
diff --git a/drivers/ieee1394/oui2c.sh b/drivers/ieee1394/oui2c.sh
deleted file mode 100644
index b9d0e8f10ab..00000000000
--- a/drivers/ieee1394/oui2c.sh
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/bin/sh
-
-cat <<EOF
-/* Generated file for OUI database */
-
-
-#ifdef CONFIG_IEEE1394_OUI_DB
-struct oui_list_struct {
- int oui;
- char *name;
-} oui_list[] = {
-EOF
-
-while read oui name; do
- echo " { 0x$oui, \"$name\" },"
-done
-
-cat <<EOF
-};
-
-#endif /* CONFIG_IEEE1394_OUI_DB */
-EOF
diff --git a/drivers/ieee1394/pcilynx.c b/drivers/ieee1394/pcilynx.c
index fbb7f14ec50..0742befe922 100644
--- a/drivers/ieee1394/pcilynx.c
+++ b/drivers/ieee1394/pcilynx.c
@@ -1434,6 +1434,7 @@ static int __devinit add_card(struct pci_dev *dev,
i2c_adapter_data = bit_data;
i2c_ad->algo_data = &i2c_adapter_data;
i2c_adapter_data.data = lynx;
+ i2c_ad->dev.parent = &dev->dev;
PRINTD(KERN_DEBUG, lynx->id,"original eeprom control: %d",
reg_read(lynx, SERIAL_EEPROM_CONTROL));
diff --git a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c
index ad2108f27a0..bb897a37d9f 100644
--- a/drivers/ieee1394/raw1394.c
+++ b/drivers/ieee1394/raw1394.c
@@ -636,27 +636,32 @@ static int state_initialized(struct file_info *fi, struct pending_request *req)
case RAW1394_REQ_SET_CARD:
spin_lock_irqsave(&host_info_lock, flags);
- if (req->req.misc < host_count) {
- list_for_each_entry(hi, &host_info_list, list) {
- if (!req->req.misc--)
- break;
- }
- get_device(&hi->host->device); // XXX Need to handle failure case
- list_add_tail(&fi->list, &hi->file_info_list);
- fi->host = hi->host;
- fi->state = connected;
-
- req->req.error = RAW1394_ERROR_NONE;
- req->req.generation = get_hpsb_generation(fi->host);
- req->req.misc = (fi->host->node_id << 16)
- | fi->host->node_count;
- if (fi->protocol_version > 3) {
- req->req.misc |=
- NODEID_TO_NODE(fi->host->irm_id) << 8;
- }
- } else {
+ if (req->req.misc >= host_count) {
req->req.error = RAW1394_ERROR_INVALID_ARG;
+ goto out_set_card;
+ }
+ list_for_each_entry(hi, &host_info_list, list)
+ if (!req->req.misc--)
+ break;
+ get_device(&hi->host->device); /* FIXME handle failure case */
+ list_add_tail(&fi->list, &hi->file_info_list);
+
+ /* prevent unloading of the host's low-level driver */
+ if (!try_module_get(hi->host->driver->owner)) {
+ req->req.error = RAW1394_ERROR_ABORTED;
+ goto out_set_card;
}
+ WARN_ON(fi->host);
+ fi->host = hi->host;
+ fi->state = connected;
+
+ req->req.error = RAW1394_ERROR_NONE;
+ req->req.generation = get_hpsb_generation(fi->host);
+ req->req.misc = (fi->host->node_id << 16)
+ | fi->host->node_count;
+ if (fi->protocol_version > 3)
+ req->req.misc |= NODEID_TO_NODE(fi->host->irm_id) << 8;
+out_set_card:
spin_unlock_irqrestore(&host_info_lock, flags);
req->req.length = 0;
@@ -2664,6 +2669,18 @@ static void raw1394_iso_shutdown(struct file_info *fi)
fi->iso_state = RAW1394_ISO_INACTIVE;
}
+static int raw1394_read_cycle_timer(struct file_info *fi, void __user * uaddr)
+{
+ struct raw1394_cycle_timer ct;
+ int err;
+
+ err = hpsb_read_cycle_timer(fi->host, &ct.cycle_timer, &ct.local_time);
+ if (!err)
+ if (copy_to_user(uaddr, &ct, sizeof(ct)))
+ err = -EFAULT;
+ return err;
+}
+
/* mmap the rawiso xmit/recv buffer */
static int raw1394_mmap(struct file *file, struct vm_area_struct *vma)
{
@@ -2772,6 +2789,14 @@ static int raw1394_ioctl(struct inode *inode, struct file *file,
break;
}
+ /* state-independent commands */
+ switch(cmd) {
+ case RAW1394_IOC_GET_CYCLE_TIMER:
+ return raw1394_read_cycle_timer(fi, argp);
+ default:
+ break;
+ }
+
return -EINVAL;
}
@@ -2955,6 +2980,11 @@ static int raw1394_release(struct inode *inode, struct file *file)
put_device(&fi->host->device);
}
+ spin_lock_irqsave(&host_info_lock, flags);
+ if (fi->host)
+ module_put(fi->host->driver->owner);
+ spin_unlock_irqrestore(&host_info_lock, flags);
+
kfree(fi);
return 0;
@@ -3003,7 +3033,7 @@ static struct hpsb_highlevel raw1394_highlevel = {
};
static struct cdev raw1394_cdev;
-static struct file_operations raw1394_fops = {
+static const struct file_operations raw1394_fops = {
.owner = THIS_MODULE,
.read = raw1394_read,
.write = raw1394_write,
diff --git a/drivers/ieee1394/raw1394.h b/drivers/ieee1394/raw1394.h
index 35bfc38f013..7bd22ee1afb 100644
--- a/drivers/ieee1394/raw1394.h
+++ b/drivers/ieee1394/raw1394.h
@@ -178,4 +178,14 @@ struct raw1394_iso_status {
__s16 xmit_cycle;
};
+/* argument to RAW1394_IOC_GET_CYCLE_TIMER ioctl */
+struct raw1394_cycle_timer {
+ /* contents of Isochronous Cycle Timer register,
+ as in OHCI 1.1 clause 5.13 (also with non-OHCI hosts) */
+ __u32 cycle_timer;
+
+ /* local time in microseconds since Epoch,
+ simultaneously read with cycle timer */
+ __u64 local_time;
+};
#endif /* IEEE1394_RAW1394_H */
diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c
index 4325aac7733..4edfff46b1e 100644
--- a/drivers/ieee1394/sbp2.c
+++ b/drivers/ieee1394/sbp2.c
@@ -51,7 +51,6 @@
* Grep for inline FIXME comments below.
*/
-#include <linux/blkdev.h>
#include <linux/compiler.h>
#include <linux/delay.h>
#include <linux/device.h>
@@ -304,10 +303,11 @@ static struct scsi_host_template sbp2_shost_template = {
.use_clustering = ENABLE_CLUSTERING,
.cmd_per_lun = SBP2_MAX_CMDS,
.can_queue = SBP2_MAX_CMDS,
- .emulated = 1,
.sdev_attrs = sbp2_sysfs_sdev_attrs,
};
+/* for match-all entries in sbp2_workarounds_table */
+#define SBP2_ROM_VALUE_WILDCARD 0x1000000
/*
* List of devices with known bugs.
@@ -329,22 +329,14 @@ static const struct {
},
/* Initio bridges, actually only needed for some older ones */ {
.firmware_revision = 0x000200,
+ .model_id = SBP2_ROM_VALUE_WILDCARD,
.workarounds = SBP2_WORKAROUND_INQUIRY_36,
},
/* Symbios bridge */ {
.firmware_revision = 0xa0b800,
+ .model_id = SBP2_ROM_VALUE_WILDCARD,
.workarounds = SBP2_WORKAROUND_128K_MAX_TRANS,
},
- /*
- * Note about the following Apple iPod blacklist entries:
- *
- * There are iPods (2nd gen, 3rd gen) with model_id==0. Since our
- * matching logic treats 0 as a wildcard, we cannot match this ID
- * without rewriting the matching routine. Fortunately these iPods
- * do not feature the read_capacity bug according to one report.
- * Read_capacity behaviour as well as model_id could change due to
- * Apple-supplied firmware updates though.
- */
/* iPod 4th generation */ {
.firmware_revision = 0x0a2700,
.model_id = 0x000021,
@@ -1307,11 +1299,13 @@ static void sbp2_parse_unit_directory(struct sbp2_lu *lu,
if (!(workarounds & SBP2_WORKAROUND_OVERRIDE))
for (i = 0; i < ARRAY_SIZE(sbp2_workarounds_table); i++) {
- if (sbp2_workarounds_table[i].firmware_revision &&
+ if (sbp2_workarounds_table[i].firmware_revision !=
+ SBP2_ROM_VALUE_WILDCARD &&
sbp2_workarounds_table[i].firmware_revision !=
(firmware_revision & 0xffff00))
continue;
- if (sbp2_workarounds_table[i].model_id &&
+ if (sbp2_workarounds_table[i].model_id !=
+ SBP2_ROM_VALUE_WILDCARD &&
sbp2_workarounds_table[i].model_id != ud->model_id)
continue;
workarounds |= sbp2_workarounds_table[i].workarounds;
@@ -2017,7 +2011,6 @@ static int sbp2scsi_slave_configure(struct scsi_device *sdev)
{
struct sbp2_lu *lu = (struct sbp2_lu *)sdev->host->hostdata[0];
- blk_queue_dma_alignment(sdev->request_queue, (512 - 1));
sdev->use_10_for_rw = 1;
if (sdev->type == TYPE_ROM)
diff --git a/drivers/ieee1394/video1394.c b/drivers/ieee1394/video1394.c
index 598b19fc598..95ca26d7527 100644
--- a/drivers/ieee1394/video1394.c
+++ b/drivers/ieee1394/video1394.c
@@ -489,6 +489,9 @@ static void wakeup_dma_ir_ctx(unsigned long l)
reset_ir_status(d, i);
d->buffer_status[d->buffer_prg_assignment[i]] = VIDEO1394_BUFFER_READY;
do_gettimeofday(&d->buffer_time[d->buffer_prg_assignment[i]]);
+ dma_region_sync_for_cpu(&d->dma,
+ d->buffer_prg_assignment[i] * d->buf_size,
+ d->buf_size);
}
}
@@ -1096,6 +1099,8 @@ static long video1394_ioctl(struct file *file,
DBGMSG(ohci->host->id, "Starting iso transmit DMA ctx=%d",
d->ctx);
put_timestamp(ohci, d, d->last_buffer);
+ dma_region_sync_for_device(&d->dma,
+ v.buffer * d->buf_size, d->buf_size);
/* Tell the controller where the first program is */
reg_write(ohci, d->cmdPtr,
@@ -1111,6 +1116,9 @@ static long video1394_ioctl(struct file *file,
"Waking up iso transmit dma ctx=%d",
d->ctx);
put_timestamp(ohci, d, d->last_buffer);
+ dma_region_sync_for_device(&d->dma,
+ v.buffer * d->buf_size, d->buf_size);
+
reg_write(ohci, d->ctrlSet, 0x1000);
}
}
@@ -1269,7 +1277,7 @@ static long video1394_compat_ioctl(struct file *f, unsigned cmd, unsigned long a
#endif
static struct cdev video1394_cdev;
-static struct file_operations video1394_fops=
+static const struct file_operations video1394_fops=
{
.owner = THIS_MODULE,
.unlocked_ioctl = video1394_ioctl,
diff --git a/drivers/infiniband/Kconfig b/drivers/infiniband/Kconfig
index 9edfacee7d8..66b36de9fa6 100644
--- a/drivers/infiniband/Kconfig
+++ b/drivers/infiniband/Kconfig
@@ -38,6 +38,7 @@ source "drivers/infiniband/hw/mthca/Kconfig"
source "drivers/infiniband/hw/ipath/Kconfig"
source "drivers/infiniband/hw/ehca/Kconfig"
source "drivers/infiniband/hw/amso1100/Kconfig"
+source "drivers/infiniband/hw/cxgb3/Kconfig"
source "drivers/infiniband/ulp/ipoib/Kconfig"
diff --git a/drivers/infiniband/Makefile b/drivers/infiniband/Makefile
index 2b5d1098ef4..da2066c4f22 100644
--- a/drivers/infiniband/Makefile
+++ b/drivers/infiniband/Makefile
@@ -3,6 +3,7 @@ obj-$(CONFIG_INFINIBAND_MTHCA) += hw/mthca/
obj-$(CONFIG_INFINIBAND_IPATH) += hw/ipath/
obj-$(CONFIG_INFINIBAND_EHCA) += hw/ehca/
obj-$(CONFIG_INFINIBAND_AMSO1100) += hw/amso1100/
+obj-$(CONFIG_INFINIBAND_CXGB3) += hw/cxgb3/
obj-$(CONFIG_INFINIBAND_IPOIB) += ulp/ipoib/
obj-$(CONFIG_INFINIBAND_SRP) += ulp/srp/
obj-$(CONFIG_INFINIBAND_ISER) += ulp/iser/
diff --git a/drivers/infiniband/core/Makefile b/drivers/infiniband/core/Makefile
index 50fb1cd447b..189e5d4b9b1 100644
--- a/drivers/infiniband/core/Makefile
+++ b/drivers/infiniband/core/Makefile
@@ -12,7 +12,7 @@ ib_core-y := packer.o ud_header.o verbs.o sysfs.o \
ib_mad-y := mad.o smi.o agent.o mad_rmpp.o
-ib_sa-y := sa_query.o
+ib_sa-y := sa_query.o multicast.o
ib_cm-y := cm.o
diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c
index af939796750..a91001c59b6 100644
--- a/drivers/infiniband/core/addr.c
+++ b/drivers/infiniband/core/addr.c
@@ -360,8 +360,7 @@ static int netevent_callback(struct notifier_block *self, unsigned long event,
if (event == NETEVENT_NEIGH_UPDATE) {
struct neighbour *neigh = ctx;
- if (neigh->dev->type == ARPHRD_INFINIBAND &&
- (neigh->nud_state & NUD_VALID)) {
+ if (neigh->nud_state & NUD_VALID) {
set_timeout(jiffies);
}
}
@@ -374,7 +373,7 @@ static struct notifier_block nb = {
static int addr_init(void)
{
- addr_wq = create_singlethread_workqueue("ib_addr_wq");
+ addr_wq = create_singlethread_workqueue("ib_addr");
if (!addr_wq)
return -ENOMEM;
diff --git a/drivers/infiniband/core/cache.c b/drivers/infiniband/core/cache.c
index 98272fbbfb3..558c9a0fc8b 100644
--- a/drivers/infiniband/core/cache.c
+++ b/drivers/infiniband/core/cache.c
@@ -38,7 +38,6 @@
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/slab.h>
-#include <linux/sched.h> /* INIT_WORK, schedule_work(), flush_scheduled_work() */
#include <rdma/ib_cache.h>
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
index 9e0ab048c87..f8d69b3fa30 100644
--- a/drivers/infiniband/core/cma.c
+++ b/drivers/infiniband/core/cma.c
@@ -71,6 +71,8 @@ static struct workqueue_struct *cma_wq;
static DEFINE_IDR(sdp_ps);
static DEFINE_IDR(tcp_ps);
static DEFINE_IDR(udp_ps);
+static DEFINE_IDR(ipoib_ps);
+static int next_port;
struct cma_device {
struct list_head list;
@@ -115,6 +117,7 @@ struct rdma_id_private {
struct list_head list;
struct list_head listen_list;
struct cma_device *cma_dev;
+ struct list_head mc_list;
enum cma_state state;
spinlock_t lock;
@@ -133,10 +136,23 @@ struct rdma_id_private {
} cm_id;
u32 seq_num;
+ u32 qkey;
u32 qp_num;
u8 srq;
};
+struct cma_multicast {
+ struct rdma_id_private *id_priv;
+ union {
+ struct ib_sa_multicast *ib;
+ } multicast;
+ struct list_head list;
+ void *context;
+ struct sockaddr addr;
+ u8 pad[sizeof(struct sockaddr_in6) -
+ sizeof(struct sockaddr)];
+};
+
struct cma_work {
struct work_struct work;
struct rdma_id_private *id;
@@ -242,6 +258,11 @@ static inline void sdp_set_ip_ver(struct sdp_hh *hh, u8 ip_ver)
hh->ip_version = (ip_ver << 4) | (hh->ip_version & 0xF);
}
+static inline int cma_is_ud_ps(enum rdma_port_space ps)
+{
+ return (ps == RDMA_PS_UDP || ps == RDMA_PS_IPOIB);
+}
+
static void cma_attach_to_dev(struct rdma_id_private *id_priv,
struct cma_device *cma_dev)
{
@@ -264,19 +285,41 @@ static void cma_detach_from_dev(struct rdma_id_private *id_priv)
id_priv->cma_dev = NULL;
}
+static int cma_set_qkey(struct ib_device *device, u8 port_num,
+ enum rdma_port_space ps,
+ struct rdma_dev_addr *dev_addr, u32 *qkey)
+{
+ struct ib_sa_mcmember_rec rec;
+ int ret = 0;
+
+ switch (ps) {
+ case RDMA_PS_UDP:
+ *qkey = RDMA_UDP_QKEY;
+ break;
+ case RDMA_PS_IPOIB:
+ ib_addr_get_mgid(dev_addr, &rec.mgid);
+ ret = ib_sa_get_mcmember_rec(device, port_num, &rec.mgid, &rec);
+ *qkey = be32_to_cpu(rec.qkey);
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
static int cma_acquire_dev(struct rdma_id_private *id_priv)
{
- enum rdma_node_type dev_type = id_priv->id.route.addr.dev_addr.dev_type;
+ struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr;
struct cma_device *cma_dev;
union ib_gid gid;
int ret = -ENODEV;
- switch (rdma_node_get_transport(dev_type)) {
+ switch (rdma_node_get_transport(dev_addr->dev_type)) {
case RDMA_TRANSPORT_IB:
- ib_addr_get_sgid(&id_priv->id.route.addr.dev_addr, &gid);
+ ib_addr_get_sgid(dev_addr, &gid);
break;
case RDMA_TRANSPORT_IWARP:
- iw_addr_get_sgid(&id_priv->id.route.addr.dev_addr, &gid);
+ iw_addr_get_sgid(dev_addr, &gid);
break;
default:
return -ENODEV;
@@ -286,7 +329,12 @@ static int cma_acquire_dev(struct rdma_id_private *id_priv)
ret = ib_find_cached_gid(cma_dev->device, &gid,
&id_priv->id.port_num, NULL);
if (!ret) {
- cma_attach_to_dev(id_priv, cma_dev);
+ ret = cma_set_qkey(cma_dev->device,
+ id_priv->id.port_num,
+ id_priv->id.ps, dev_addr,
+ &id_priv->qkey);
+ if (!ret)
+ cma_attach_to_dev(id_priv, cma_dev);
break;
}
}
@@ -324,40 +372,50 @@ struct rdma_cm_id *rdma_create_id(rdma_cm_event_handler event_handler,
init_waitqueue_head(&id_priv->wait_remove);
atomic_set(&id_priv->dev_remove, 0);
INIT_LIST_HEAD(&id_priv->listen_list);
+ INIT_LIST_HEAD(&id_priv->mc_list);
get_random_bytes(&id_priv->seq_num, sizeof id_priv->seq_num);
return &id_priv->id;
}
EXPORT_SYMBOL(rdma_create_id);
-static int cma_init_ib_qp(struct rdma_id_private *id_priv, struct ib_qp *qp)
+static int cma_init_ud_qp(struct rdma_id_private *id_priv, struct ib_qp *qp)
{
struct ib_qp_attr qp_attr;
- struct rdma_dev_addr *dev_addr;
- int ret;
+ int qp_attr_mask, ret;
- dev_addr = &id_priv->id.route.addr.dev_addr;
- ret = ib_find_cached_pkey(id_priv->id.device, id_priv->id.port_num,
- ib_addr_get_pkey(dev_addr),
- &qp_attr.pkey_index);
+ qp_attr.qp_state = IB_QPS_INIT;
+ ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask);
if (ret)
return ret;
- qp_attr.qp_state = IB_QPS_INIT;
- qp_attr.qp_access_flags = 0;
- qp_attr.port_num = id_priv->id.port_num;
- return ib_modify_qp(qp, &qp_attr, IB_QP_STATE | IB_QP_ACCESS_FLAGS |
- IB_QP_PKEY_INDEX | IB_QP_PORT);
+ ret = ib_modify_qp(qp, &qp_attr, qp_attr_mask);
+ if (ret)
+ return ret;
+
+ qp_attr.qp_state = IB_QPS_RTR;
+ ret = ib_modify_qp(qp, &qp_attr, IB_QP_STATE);
+ if (ret)
+ return ret;
+
+ qp_attr.qp_state = IB_QPS_RTS;
+ qp_attr.sq_psn = 0;
+ ret = ib_modify_qp(qp, &qp_attr, IB_QP_STATE | IB_QP_SQ_PSN);
+
+ return ret;
}
-static int cma_init_iw_qp(struct rdma_id_private *id_priv, struct ib_qp *qp)
+static int cma_init_conn_qp(struct rdma_id_private *id_priv, struct ib_qp *qp)
{
struct ib_qp_attr qp_attr;
+ int qp_attr_mask, ret;
qp_attr.qp_state = IB_QPS_INIT;
- qp_attr.qp_access_flags = IB_ACCESS_LOCAL_WRITE;
+ ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask);
+ if (ret)
+ return ret;
- return ib_modify_qp(qp, &qp_attr, IB_QP_STATE | IB_QP_ACCESS_FLAGS);
+ return ib_modify_qp(qp, &qp_attr, qp_attr_mask);
}
int rdma_create_qp(struct rdma_cm_id *id, struct ib_pd *pd,
@@ -375,18 +433,10 @@ int rdma_create_qp(struct rdma_cm_id *id, struct ib_pd *pd,
if (IS_ERR(qp))
return PTR_ERR(qp);
- switch (rdma_node_get_transport(id->device->node_type)) {
- case RDMA_TRANSPORT_IB:
- ret = cma_init_ib_qp(id_priv, qp);
- break;
- case RDMA_TRANSPORT_IWARP:
- ret = cma_init_iw_qp(id_priv, qp);
- break;
- default:
- ret = -ENOSYS;
- break;
- }
-
+ if (cma_is_ud_ps(id_priv->id.ps))
+ ret = cma_init_ud_qp(id_priv, qp);
+ else
+ ret = cma_init_conn_qp(id_priv, qp);
if (ret)
goto err;
@@ -459,23 +509,55 @@ static int cma_modify_qp_err(struct rdma_cm_id *id)
return ib_modify_qp(id->qp, &qp_attr, IB_QP_STATE);
}
+static int cma_ib_init_qp_attr(struct rdma_id_private *id_priv,
+ struct ib_qp_attr *qp_attr, int *qp_attr_mask)
+{
+ struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr;
+ int ret;
+
+ ret = ib_find_cached_pkey(id_priv->id.device, id_priv->id.port_num,
+ ib_addr_get_pkey(dev_addr),
+ &qp_attr->pkey_index);
+ if (ret)
+ return ret;
+
+ qp_attr->port_num = id_priv->id.port_num;
+ *qp_attr_mask = IB_QP_STATE | IB_QP_PKEY_INDEX | IB_QP_PORT;
+
+ if (cma_is_ud_ps(id_priv->id.ps)) {
+ qp_attr->qkey = id_priv->qkey;
+ *qp_attr_mask |= IB_QP_QKEY;
+ } else {
+ qp_attr->qp_access_flags = 0;
+ *qp_attr_mask |= IB_QP_ACCESS_FLAGS;
+ }
+ return 0;
+}
+
int rdma_init_qp_attr(struct rdma_cm_id *id, struct ib_qp_attr *qp_attr,
int *qp_attr_mask)
{
struct rdma_id_private *id_priv;
- int ret;
+ int ret = 0;
id_priv = container_of(id, struct rdma_id_private, id);
switch (rdma_node_get_transport(id_priv->id.device->node_type)) {
case RDMA_TRANSPORT_IB:
- ret = ib_cm_init_qp_attr(id_priv->cm_id.ib, qp_attr,
- qp_attr_mask);
+ if (!id_priv->cm_id.ib || cma_is_ud_ps(id_priv->id.ps))
+ ret = cma_ib_init_qp_attr(id_priv, qp_attr, qp_attr_mask);
+ else
+ ret = ib_cm_init_qp_attr(id_priv->cm_id.ib, qp_attr,
+ qp_attr_mask);
if (qp_attr->qp_state == IB_QPS_RTR)
qp_attr->rq_psn = id_priv->seq_num;
break;
case RDMA_TRANSPORT_IWARP:
- ret = iw_cm_init_qp_attr(id_priv->cm_id.iw, qp_attr,
- qp_attr_mask);
+ if (!id_priv->cm_id.iw) {
+ qp_attr->qp_access_flags = IB_ACCESS_LOCAL_WRITE;
+ *qp_attr_mask = IB_QP_STATE | IB_QP_ACCESS_FLAGS;
+ } else
+ ret = iw_cm_init_qp_attr(id_priv->cm_id.iw, qp_attr,
+ qp_attr_mask);
break;
default:
ret = -ENOSYS;
@@ -697,6 +779,19 @@ static void cma_release_port(struct rdma_id_private *id_priv)
mutex_unlock(&lock);
}
+static void cma_leave_mc_groups(struct rdma_id_private *id_priv)
+{
+ struct cma_multicast *mc;
+
+ while (!list_empty(&id_priv->mc_list)) {
+ mc = container_of(id_priv->mc_list.next,
+ struct cma_multicast, list);
+ list_del(&mc->list);
+ ib_sa_free_multicast(mc->multicast.ib);
+ kfree(mc);
+ }
+}
+
void rdma_destroy_id(struct rdma_cm_id *id)
{
struct rdma_id_private *id_priv;
@@ -721,6 +816,7 @@ void rdma_destroy_id(struct rdma_cm_id *id)
default:
break;
}
+ cma_leave_mc_groups(id_priv);
mutex_lock(&lock);
cma_detach_from_dev(id_priv);
}
@@ -971,7 +1067,7 @@ static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
memset(&event, 0, sizeof event);
offset = cma_user_data_offset(listen_id->id.ps);
event.event = RDMA_CM_EVENT_CONNECT_REQUEST;
- if (listen_id->id.ps == RDMA_PS_UDP) {
+ if (cma_is_ud_ps(listen_id->id.ps)) {
conn_id = cma_new_udp_id(&listen_id->id, ib_event);
event.param.ud.private_data = ib_event->private_data + offset;
event.param.ud.private_data_len =
@@ -1722,33 +1818,74 @@ static int cma_alloc_port(struct idr *ps, struct rdma_id_private *id_priv,
unsigned short snum)
{
struct rdma_bind_list *bind_list;
- int port, start, ret;
+ int port, ret;
- bind_list = kzalloc(sizeof *bind_list, GFP_KERNEL);
+ bind_list = kmalloc(sizeof *bind_list, GFP_KERNEL);
if (!bind_list)
return -ENOMEM;
- start = snum ? snum : sysctl_local_port_range[0];
+ do {
+ ret = idr_get_new_above(ps, bind_list, snum, &port);
+ } while ((ret == -EAGAIN) && idr_pre_get(ps, GFP_KERNEL));
+
+ if (ret)
+ goto err1;
+ if (port != snum) {
+ ret = -EADDRNOTAVAIL;
+ goto err2;
+ }
+
+ bind_list->ps = ps;
+ bind_list->port = (unsigned short) port;
+ cma_bind_port(bind_list, id_priv);
+ return 0;
+err2:
+ idr_remove(ps, port);
+err1:
+ kfree(bind_list);
+ return ret;
+}
+
+static int cma_alloc_any_port(struct idr *ps, struct rdma_id_private *id_priv)
+{
+ struct rdma_bind_list *bind_list;
+ int port, ret;
+
+ bind_list = kzalloc(sizeof *bind_list, GFP_KERNEL);
+ if (!bind_list)
+ return -ENOMEM;
+
+retry:
do {
- ret = idr_get_new_above(ps, bind_list, start, &port);
+ ret = idr_get_new_above(ps, bind_list, next_port, &port);
} while ((ret == -EAGAIN) && idr_pre_get(ps, GFP_KERNEL));
if (ret)
- goto err;
+ goto err1;
- if ((snum && port != snum) ||
- (!snum && port > sysctl_local_port_range[1])) {
- idr_remove(ps, port);
+ if (port > sysctl_local_port_range[1]) {
+ if (next_port != sysctl_local_port_range[0]) {
+ idr_remove(ps, port);
+ next_port = sysctl_local_port_range[0];
+ goto retry;
+ }
ret = -EADDRNOTAVAIL;
- goto err;
+ goto err2;
}
+ if (port == sysctl_local_port_range[1])
+ next_port = sysctl_local_port_range[0];
+ else
+ next_port = port + 1;
+
bind_list->ps = ps;
bind_list->port = (unsigned short) port;
cma_bind_port(bind_list, id_priv);
return 0;
-err:
+err2:
+ idr_remove(ps, port);
+err1:
kfree(bind_list);
return ret;
}
@@ -1805,13 +1942,16 @@ static int cma_get_port(struct rdma_id_private *id_priv)
case RDMA_PS_UDP:
ps = &udp_ps;
break;
+ case RDMA_PS_IPOIB:
+ ps = &ipoib_ps;
+ break;
default:
return -EPROTONOSUPPORT;
}
mutex_lock(&lock);
if (cma_any_port(&id_priv->id.route.addr.src_addr))
- ret = cma_alloc_port(ps, id_priv, 0);
+ ret = cma_alloc_any_port(ps, id_priv);
else
ret = cma_use_port(ps, id_priv);
mutex_unlock(&lock);
@@ -1919,7 +2059,7 @@ static int cma_sidr_rep_handler(struct ib_cm_id *cm_id,
event.status = ib_event->param.sidr_rep_rcvd.status;
break;
}
- if (rep->qkey != RDMA_UD_QKEY) {
+ if (id_priv->qkey != rep->qkey) {
event.event = RDMA_CM_EVENT_UNREACHABLE;
event.status = -EINVAL;
break;
@@ -2118,7 +2258,7 @@ int rdma_connect(struct rdma_cm_id *id, struct rdma_conn_param *conn_param)
switch (rdma_node_get_transport(id->device->node_type)) {
case RDMA_TRANSPORT_IB:
- if (id->ps == RDMA_PS_UDP)
+ if (cma_is_ud_ps(id->ps))
ret = cma_resolve_ib_udp(id_priv, conn_param);
else
ret = cma_connect_ib(id_priv, conn_param);
@@ -2214,7 +2354,7 @@ static int cma_send_sidr_rep(struct rdma_id_private *id_priv,
rep.status = status;
if (status == IB_SIDR_SUCCESS) {
rep.qp_num = id_priv->qp_num;
- rep.qkey = RDMA_UD_QKEY;
+ rep.qkey = id_priv->qkey;
}
rep.private_data = private_data;
rep.private_data_len = private_data_len;
@@ -2238,7 +2378,7 @@ int rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param)
switch (rdma_node_get_transport(id->device->node_type)) {
case RDMA_TRANSPORT_IB:
- if (id->ps == RDMA_PS_UDP)
+ if (cma_is_ud_ps(id->ps))
ret = cma_send_sidr_rep(id_priv, IB_SIDR_SUCCESS,
conn_param->private_data,
conn_param->private_data_len);
@@ -2299,7 +2439,7 @@ int rdma_reject(struct rdma_cm_id *id, const void *private_data,
switch (rdma_node_get_transport(id->device->node_type)) {
case RDMA_TRANSPORT_IB:
- if (id->ps == RDMA_PS_UDP)
+ if (cma_is_ud_ps(id->ps))
ret = cma_send_sidr_rep(id_priv, IB_SIDR_REJECT,
private_data, private_data_len);
else
@@ -2350,6 +2490,178 @@ out:
}
EXPORT_SYMBOL(rdma_disconnect);
+static int cma_ib_mc_handler(int status, struct ib_sa_multicast *multicast)
+{
+ struct rdma_id_private *id_priv;
+ struct cma_multicast *mc = multicast->context;
+ struct rdma_cm_event event;
+ int ret;
+
+ id_priv = mc->id_priv;
+ atomic_inc(&id_priv->dev_remove);
+ if (!cma_comp(id_priv, CMA_ADDR_BOUND) &&
+ !cma_comp(id_priv, CMA_ADDR_RESOLVED))
+ goto out;
+
+ if (!status && id_priv->id.qp)
+ status = ib_attach_mcast(id_priv->id.qp, &multicast->rec.mgid,
+ multicast->rec.mlid);
+
+ memset(&event, 0, sizeof event);
+ event.status = status;
+ event.param.ud.private_data = mc->context;
+ if (!status) {
+ event.event = RDMA_CM_EVENT_MULTICAST_JOIN;
+ ib_init_ah_from_mcmember(id_priv->id.device,
+ id_priv->id.port_num, &multicast->rec,
+ &event.param.ud.ah_attr);
+ event.param.ud.qp_num = 0xFFFFFF;
+ event.param.ud.qkey = be32_to_cpu(multicast->rec.qkey);
+ } else
+ event.event = RDMA_CM_EVENT_MULTICAST_ERROR;
+
+ ret = id_priv->id.event_handler(&id_priv->id, &event);
+ if (ret) {
+ cma_exch(id_priv, CMA_DESTROYING);
+ cma_release_remove(id_priv);
+ rdma_destroy_id(&id_priv->id);
+ return 0;
+ }
+out:
+ cma_release_remove(id_priv);
+ return 0;
+}
+
+static void cma_set_mgid(struct rdma_id_private *id_priv,
+ struct sockaddr *addr, union ib_gid *mgid)
+{
+ unsigned char mc_map[MAX_ADDR_LEN];
+ struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr;
+ struct sockaddr_in *sin = (struct sockaddr_in *) addr;
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) addr;
+
+ if (cma_any_addr(addr)) {
+ memset(mgid, 0, sizeof *mgid);
+ } else if ((addr->sa_family == AF_INET6) &&
+ ((be32_to_cpu(sin6->sin6_addr.s6_addr32[0]) & 0xFF10A01B) ==
+ 0xFF10A01B)) {
+ /* IPv6 address is an SA assigned MGID. */
+ memcpy(mgid, &sin6->sin6_addr, sizeof *mgid);
+ } else {
+ ip_ib_mc_map(sin->sin_addr.s_addr, mc_map);
+ if (id_priv->id.ps == RDMA_PS_UDP)
+ mc_map[7] = 0x01; /* Use RDMA CM signature */
+ mc_map[8] = ib_addr_get_pkey(dev_addr) >> 8;
+ mc_map[9] = (unsigned char) ib_addr_get_pkey(dev_addr);
+ *mgid = *(union ib_gid *) (mc_map + 4);
+ }
+}
+
+static int cma_join_ib_multicast(struct rdma_id_private *id_priv,
+ struct cma_multicast *mc)
+{
+ struct ib_sa_mcmember_rec rec;
+ struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr;
+ ib_sa_comp_mask comp_mask;
+ int ret;
+
+ ib_addr_get_mgid(dev_addr, &rec.mgid);
+ ret = ib_sa_get_mcmember_rec(id_priv->id.device, id_priv->id.port_num,
+ &rec.mgid, &rec);
+ if (ret)
+ return ret;
+
+ cma_set_mgid(id_priv, &mc->addr, &rec.mgid);
+ if (id_priv->id.ps == RDMA_PS_UDP)
+ rec.qkey = cpu_to_be32(RDMA_UDP_QKEY);
+ ib_addr_get_sgid(dev_addr, &rec.port_gid);
+ rec.pkey = cpu_to_be16(ib_addr_get_pkey(dev_addr));
+ rec.join_state = 1;
+
+ comp_mask = IB_SA_MCMEMBER_REC_MGID | IB_SA_MCMEMBER_REC_PORT_GID |
+ IB_SA_MCMEMBER_REC_PKEY | IB_SA_MCMEMBER_REC_JOIN_STATE |
+ IB_SA_MCMEMBER_REC_QKEY | IB_SA_MCMEMBER_REC_SL |
+ IB_SA_MCMEMBER_REC_FLOW_LABEL |
+ IB_SA_MCMEMBER_REC_TRAFFIC_CLASS;
+
+ mc->multicast.ib = ib_sa_join_multicast(&sa_client, id_priv->id.device,
+ id_priv->id.port_num, &rec,
+ comp_mask, GFP_KERNEL,
+ cma_ib_mc_handler, mc);
+ if (IS_ERR(mc->multicast.ib))
+ return PTR_ERR(mc->multicast.ib);
+
+ return 0;
+}
+
+int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr,
+ void *context)
+{
+ struct rdma_id_private *id_priv;
+ struct cma_multicast *mc;
+ int ret;
+
+ id_priv = container_of(id, struct rdma_id_private, id);
+ if (!cma_comp(id_priv, CMA_ADDR_BOUND) &&
+ !cma_comp(id_priv, CMA_ADDR_RESOLVED))
+ return -EINVAL;
+
+ mc = kmalloc(sizeof *mc, GFP_KERNEL);
+ if (!mc)
+ return -ENOMEM;
+
+ memcpy(&mc->addr, addr, ip_addr_size(addr));
+ mc->context = context;
+ mc->id_priv = id_priv;
+
+ spin_lock(&id_priv->lock);
+ list_add(&mc->list, &id_priv->mc_list);
+ spin_unlock(&id_priv->lock);
+
+ switch (rdma_node_get_transport(id->device->node_type)) {
+ case RDMA_TRANSPORT_IB:
+ ret = cma_join_ib_multicast(id_priv, mc);
+ break;
+ default:
+ ret = -ENOSYS;
+ break;
+ }
+
+ if (ret) {
+ spin_lock_irq(&id_priv->lock);
+ list_del(&mc->list);
+ spin_unlock_irq(&id_priv->lock);
+ kfree(mc);
+ }
+ return ret;
+}
+EXPORT_SYMBOL(rdma_join_multicast);
+
+void rdma_leave_multicast(struct rdma_cm_id *id, struct sockaddr *addr)
+{
+ struct rdma_id_private *id_priv;
+ struct cma_multicast *mc;
+
+ id_priv = container_of(id, struct rdma_id_private, id);
+ spin_lock_irq(&id_priv->lock);
+ list_for_each_entry(mc, &id_priv->mc_list, list) {
+ if (!memcmp(&mc->addr, addr, ip_addr_size(addr))) {
+ list_del(&mc->list);
+ spin_unlock_irq(&id_priv->lock);
+
+ if (id->qp)
+ ib_detach_mcast(id->qp,
+ &mc->multicast.ib->rec.mgid,
+ mc->multicast.ib->rec.mlid);
+ ib_sa_free_multicast(mc->multicast.ib);
+ kfree(mc);
+ return;
+ }
+ }
+ spin_unlock_irq(&id_priv->lock);
+}
+EXPORT_SYMBOL(rdma_leave_multicast);
+
static void cma_add_one(struct ib_device *device)
{
struct cma_device *cma_dev;
@@ -2448,7 +2760,11 @@ static int cma_init(void)
{
int ret;
- cma_wq = create_singlethread_workqueue("rdma_cm_wq");
+ get_random_bytes(&next_port, sizeof next_port);
+ next_port = (next_port % (sysctl_local_port_range[1] -
+ sysctl_local_port_range[0])) +
+ sysctl_local_port_range[0];
+ cma_wq = create_singlethread_workqueue("rdma_cm");
if (!cma_wq)
return -ENOMEM;
@@ -2476,6 +2792,7 @@ static void cma_cleanup(void)
idr_destroy(&sdp_ps);
idr_destroy(&tcp_ps);
idr_destroy(&udp_ps);
+ idr_destroy(&ipoib_ps);
}
module_init(cma_init);
diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c
index 63d2a39fb82..7fabb425b03 100644
--- a/drivers/infiniband/core/device.c
+++ b/drivers/infiniband/core/device.c
@@ -36,6 +36,7 @@
#include <linux/module.h>
#include <linux/string.h>
#include <linux/errno.h>
+#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/mutex.h>
@@ -93,7 +94,7 @@ static int ib_device_check_mandatory(struct ib_device *device)
};
int i;
- for (i = 0; i < sizeof mandatory_table / sizeof mandatory_table[0]; ++i) {
+ for (i = 0; i < ARRAY_SIZE(mandatory_table); ++i) {
if (!*(void **) ((void *) device + mandatory_table[i].offset)) {
printk(KERN_WARNING "Device %s is missing mandatory function %s\n",
device->name, mandatory_table[i].name);
diff --git a/drivers/infiniband/core/fmr_pool.c b/drivers/infiniband/core/fmr_pool.c
index 8926a2bd4a8..1d796e7c819 100644
--- a/drivers/infiniband/core/fmr_pool.c
+++ b/drivers/infiniband/core/fmr_pool.c
@@ -301,7 +301,7 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd,
{
struct ib_pool_fmr *fmr;
- struct ib_fmr_attr attr = {
+ struct ib_fmr_attr fmr_attr = {
.max_pages = params->max_pages_per_fmr,
.max_maps = pool->max_remaps,
.page_shift = params->page_shift
@@ -321,7 +321,7 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd,
fmr->ref_count = 0;
INIT_HLIST_NODE(&fmr->cache_node);
- fmr->fmr = ib_alloc_fmr(pd, params->access, &attr);
+ fmr->fmr = ib_alloc_fmr(pd, params->access, &fmr_attr);
if (IS_ERR(fmr->fmr)) {
printk(KERN_WARNING "fmr_create failed for FMR %d", i);
kfree(fmr);
diff --git a/drivers/infiniband/core/iwcm.c b/drivers/infiniband/core/iwcm.c
index 1039ad57d53..891d1fa7b2e 100644
--- a/drivers/infiniband/core/iwcm.c
+++ b/drivers/infiniband/core/iwcm.c
@@ -146,6 +146,12 @@ static int copy_private_data(struct iw_cm_event *event)
return 0;
}
+static void free_cm_id(struct iwcm_id_private *cm_id_priv)
+{
+ dealloc_work_entries(cm_id_priv);
+ kfree(cm_id_priv);
+}
+
/*
* Release a reference on cm_id. If the last reference is being
* released, enable the waiting thread (in iw_destroy_cm_id) to
@@ -153,21 +159,14 @@ static int copy_private_data(struct iw_cm_event *event)
*/
static int iwcm_deref_id(struct iwcm_id_private *cm_id_priv)
{
- int ret = 0;
-
BUG_ON(atomic_read(&cm_id_priv->refcount)==0);
if (atomic_dec_and_test(&cm_id_priv->refcount)) {
BUG_ON(!list_empty(&cm_id_priv->work_list));
- if (waitqueue_active(&cm_id_priv->destroy_comp.wait)) {
- BUG_ON(cm_id_priv->state != IW_CM_STATE_DESTROYING);
- BUG_ON(test_bit(IWCM_F_CALLBACK_DESTROY,
- &cm_id_priv->flags));
- ret = 1;
- }
complete(&cm_id_priv->destroy_comp);
+ return 1;
}
- return ret;
+ return 0;
}
static void add_ref(struct iw_cm_id *cm_id)
@@ -181,7 +180,11 @@ static void rem_ref(struct iw_cm_id *cm_id)
{
struct iwcm_id_private *cm_id_priv;
cm_id_priv = container_of(cm_id, struct iwcm_id_private, id);
- iwcm_deref_id(cm_id_priv);
+ if (iwcm_deref_id(cm_id_priv) &&
+ test_bit(IWCM_F_CALLBACK_DESTROY, &cm_id_priv->flags)) {
+ BUG_ON(!list_empty(&cm_id_priv->work_list));
+ free_cm_id(cm_id_priv);
+ }
}
static int cm_event_handler(struct iw_cm_id *cm_id, struct iw_cm_event *event);
@@ -355,7 +358,9 @@ static void destroy_cm_id(struct iw_cm_id *cm_id)
case IW_CM_STATE_CONN_RECV:
/*
* App called destroy before/without calling accept after
- * receiving connection request event notification.
+ * receiving connection request event notification or
+ * returned non zero from the event callback function.
+ * In either case, must tell the provider to reject.
*/
cm_id_priv->state = IW_CM_STATE_DESTROYING;
break;
@@ -391,9 +396,7 @@ void iw_destroy_cm_id(struct iw_cm_id *cm_id)
wait_for_completion(&cm_id_priv->destroy_comp);
- dealloc_work_entries(cm_id_priv);
-
- kfree(cm_id_priv);
+ free_cm_id(cm_id_priv);
}
EXPORT_SYMBOL(iw_destroy_cm_id);
@@ -647,10 +650,11 @@ static void cm_conn_req_handler(struct iwcm_id_private *listen_id_priv,
/* Call the client CM handler */
ret = cm_id->cm_handler(cm_id, iw_event);
if (ret) {
+ iw_cm_reject(cm_id, NULL, 0);
set_bit(IWCM_F_CALLBACK_DESTROY, &cm_id_priv->flags);
destroy_cm_id(cm_id);
if (atomic_read(&cm_id_priv->refcount)==0)
- kfree(cm_id);
+ free_cm_id(cm_id_priv);
}
out:
@@ -854,13 +858,12 @@ static void cm_work_handler(struct work_struct *_work)
destroy_cm_id(&cm_id_priv->id);
}
BUG_ON(atomic_read(&cm_id_priv->refcount)==0);
- if (iwcm_deref_id(cm_id_priv))
- return;
-
- if (atomic_read(&cm_id_priv->refcount)==0 &&
- test_bit(IWCM_F_CALLBACK_DESTROY, &cm_id_priv->flags)) {
- dealloc_work_entries(cm_id_priv);
- kfree(cm_id_priv);
+ if (iwcm_deref_id(cm_id_priv)) {
+ if (test_bit(IWCM_F_CALLBACK_DESTROY,
+ &cm_id_priv->flags)) {
+ BUG_ON(!list_empty(&cm_id_priv->work_list));
+ free_cm_id(cm_id_priv);
+ }
return;
}
spin_lock_irqsave(&cm_id_priv->lock, flags);
diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c
index 5ed141ebd1c..13efd417034 100644
--- a/drivers/infiniband/core/mad.c
+++ b/drivers/infiniband/core/mad.c
@@ -642,7 +642,8 @@ static void snoop_recv(struct ib_mad_qp_info *qp_info,
spin_unlock_irqrestore(&qp_info->snoop_lock, flags);
}
-static void build_smp_wc(u64 wr_id, u16 slid, u16 pkey_index, u8 port_num,
+static void build_smp_wc(struct ib_qp *qp,
+ u64 wr_id, u16 slid, u16 pkey_index, u8 port_num,
struct ib_wc *wc)
{
memset(wc, 0, sizeof *wc);
@@ -652,7 +653,7 @@ static void build_smp_wc(u64 wr_id, u16 slid, u16 pkey_index, u8 port_num,
wc->pkey_index = pkey_index;
wc->byte_len = sizeof(struct ib_mad) + sizeof(struct ib_grh);
wc->src_qp = IB_QP0;
- wc->qp_num = IB_QP0;
+ wc->qp = qp;
wc->slid = slid;
wc->sl = 0;
wc->dlid_path_bits = 0;
@@ -713,7 +714,8 @@ static int handle_outgoing_dr_smp(struct ib_mad_agent_private *mad_agent_priv,
goto out;
}
- build_smp_wc(send_wr->wr_id, be16_to_cpu(smp->dr_slid),
+ build_smp_wc(mad_agent_priv->agent.qp,
+ send_wr->wr_id, be16_to_cpu(smp->dr_slid),
send_wr->wr.ud.pkey_index,
send_wr->wr.ud.port_num, &mad_wc);
@@ -2355,7 +2357,8 @@ static void local_completions(struct work_struct *work)
* Defined behavior is to complete response
* before request
*/
- build_smp_wc((unsigned long) local->mad_send_wr,
+ build_smp_wc(recv_mad_agent->agent.qp,
+ (unsigned long) local->mad_send_wr,
be16_to_cpu(IB_LID_PERMISSIVE),
0, recv_mad_agent->agent.port_num, &wc);
diff --git a/drivers/infiniband/core/multicast.c b/drivers/infiniband/core/multicast.c
new file mode 100644
index 00000000000..4a579b3a1c9
--- /dev/null
+++ b/drivers/infiniband/core/multicast.c
@@ -0,0 +1,837 @@
+/*
+ * Copyright (c) 2006 Intel Corporation.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/completion.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/bitops.h>
+#include <linux/random.h>
+
+#include <rdma/ib_cache.h>
+#include "sa.h"
+
+static void mcast_add_one(struct ib_device *device);
+static void mcast_remove_one(struct ib_device *device);
+
+static struct ib_client mcast_client = {
+ .name = "ib_multicast",
+ .add = mcast_add_one,
+ .remove = mcast_remove_one
+};
+
+static struct ib_sa_client sa_client;
+static struct workqueue_struct *mcast_wq;
+static union ib_gid mgid0;
+
+struct mcast_device;
+
+struct mcast_port {
+ struct mcast_device *dev;
+ spinlock_t lock;
+ struct rb_root table;
+ atomic_t refcount;
+ struct completion comp;
+ u8 port_num;
+};
+
+struct mcast_device {
+ struct ib_device *device;
+ struct ib_event_handler event_handler;
+ int start_port;
+ int end_port;
+ struct mcast_port port[0];
+};
+
+enum mcast_state {
+ MCAST_IDLE,
+ MCAST_JOINING,
+ MCAST_MEMBER,
+ MCAST_BUSY,
+ MCAST_ERROR
+};
+
+struct mcast_member;
+
+struct mcast_group {
+ struct ib_sa_mcmember_rec rec;
+ struct rb_node node;
+ struct mcast_port *port;
+ spinlock_t lock;
+ struct work_struct work;
+ struct list_head pending_list;
+ struct list_head active_list;
+ struct mcast_member *last_join;
+ int members[3];
+ atomic_t refcount;
+ enum mcast_state state;
+ struct ib_sa_query *query;
+ int query_id;
+};
+
+struct mcast_member {
+ struct ib_sa_multicast multicast;
+ struct ib_sa_client *client;
+ struct mcast_group *group;
+ struct list_head list;
+ enum mcast_state state;
+ atomic_t refcount;
+ struct completion comp;
+};
+
+static void join_handler(int status, struct ib_sa_mcmember_rec *rec,
+ void *context);
+static void leave_handler(int status, struct ib_sa_mcmember_rec *rec,
+ void *context);
+
+static struct mcast_group *mcast_find(struct mcast_port *port,
+ union ib_gid *mgid)
+{
+ struct rb_node *node = port->table.rb_node;
+ struct mcast_group *group;
+ int ret;
+
+ while (node) {
+ group = rb_entry(node, struct mcast_group, node);
+ ret = memcmp(mgid->raw, group->rec.mgid.raw, sizeof *mgid);
+ if (!ret)
+ return group;
+
+ if (ret < 0)
+ node = node->rb_left;
+ else
+ node = node->rb_right;
+ }
+ return NULL;
+}
+
+static struct mcast_group *mcast_insert(struct mcast_port *port,
+ struct mcast_group *group,
+ int allow_duplicates)
+{
+ struct rb_node **link = &port->table.rb_node;
+ struct rb_node *parent = NULL;
+ struct mcast_group *cur_group;
+ int ret;
+
+ while (*link) {
+ parent = *link;
+ cur_group = rb_entry(parent, struct mcast_group, node);
+
+ ret = memcmp(group->rec.mgid.raw, cur_group->rec.mgid.raw,
+ sizeof group->rec.mgid);
+ if (ret < 0)
+ link = &(*link)->rb_left;
+ else if (ret > 0)
+ link = &(*link)->rb_right;
+ else if (allow_duplicates)
+ link = &(*link)->rb_left;
+ else
+ return cur_group;
+ }
+ rb_link_node(&group->node, parent, link);
+ rb_insert_color(&group->node, &port->table);
+ return NULL;
+}
+
+static void deref_port(struct mcast_port *port)
+{
+ if (atomic_dec_and_test(&port->refcount))
+ complete(&port->comp);
+}
+
+static void release_group(struct mcast_group *group)
+{
+ struct mcast_port *port = group->port;
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->lock, flags);
+ if (atomic_dec_and_test(&group->refcount)) {
+ rb_erase(&group->node, &port->table);
+ spin_unlock_irqrestore(&port->lock, flags);
+ kfree(group);
+ deref_port(port);
+ } else
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void deref_member(struct mcast_member *member)
+{
+ if (atomic_dec_and_test(&member->refcount))
+ complete(&member->comp);
+}
+
+static void queue_join(struct mcast_member *member)
+{
+ struct mcast_group *group = member->group;
+ unsigned long flags;
+
+ spin_lock_irqsave(&group->lock, flags);
+ list_add(&member->list, &group->pending_list);
+ if (group->state == MCAST_IDLE) {
+ group->state = MCAST_BUSY;
+ atomic_inc(&group->refcount);
+ queue_work(mcast_wq, &group->work);
+ }
+ spin_unlock_irqrestore(&group->lock, flags);
+}
+
+/*
+ * A multicast group has three types of members: full member, non member, and
+ * send only member. We need to keep track of the number of members of each
+ * type based on their join state. Adjust the number of members the belong to
+ * the specified join states.
+ */
+static void adjust_membership(struct mcast_group *group, u8 join_state, int inc)
+{
+ int i;
+
+ for (i = 0; i < 3; i++, join_state >>= 1)
+ if (join_state & 0x1)
+ group->members[i] += inc;
+}
+
+/*
+ * If a multicast group has zero members left for a particular join state, but
+ * the group is still a member with the SA, we need to leave that join state.
+ * Determine which join states we still belong to, but that do not have any
+ * active members.
+ */
+static u8 get_leave_state(struct mcast_group *group)
+{
+ u8 leave_state = 0;
+ int i;
+
+ for (i = 0; i < 3; i++)
+ if (!group->members[i])
+ leave_state |= (0x1 << i);
+
+ return leave_state & group->rec.join_state;
+}
+
+static int check_selector(ib_sa_comp_mask comp_mask,
+ ib_sa_comp_mask selector_mask,
+ ib_sa_comp_mask value_mask,
+ u8 selector, u8 src_value, u8 dst_value)
+{
+ int err;
+
+ if (!(comp_mask & selector_mask) || !(comp_mask & value_mask))
+ return 0;
+
+ switch (selector) {
+ case IB_SA_GT:
+ err = (src_value <= dst_value);
+ break;
+ case IB_SA_LT:
+ err = (src_value >= dst_value);
+ break;
+ case IB_SA_EQ:
+ err = (src_value != dst_value);
+ break;
+ default:
+ err = 0;
+ break;
+ }
+
+ return err;
+}
+
+static int cmp_rec(struct ib_sa_mcmember_rec *src,
+ struct ib_sa_mcmember_rec *dst, ib_sa_comp_mask comp_mask)
+{
+ /* MGID must already match */
+
+ if (comp_mask & IB_SA_MCMEMBER_REC_PORT_GID &&
+ memcmp(&src->port_gid, &dst->port_gid, sizeof src->port_gid))
+ return -EINVAL;
+ if (comp_mask & IB_SA_MCMEMBER_REC_QKEY && src->qkey != dst->qkey)
+ return -EINVAL;
+ if (comp_mask & IB_SA_MCMEMBER_REC_MLID && src->mlid != dst->mlid)
+ return -EINVAL;
+ if (check_selector(comp_mask, IB_SA_MCMEMBER_REC_MTU_SELECTOR,
+ IB_SA_MCMEMBER_REC_MTU, dst->mtu_selector,
+ src->mtu, dst->mtu))
+ return -EINVAL;
+ if (comp_mask & IB_SA_MCMEMBER_REC_TRAFFIC_CLASS &&
+ src->traffic_class != dst->traffic_class)
+ return -EINVAL;
+ if (comp_mask & IB_SA_MCMEMBER_REC_PKEY && src->pkey != dst->pkey)
+ return -EINVAL;
+ if (check_selector(comp_mask, IB_SA_MCMEMBER_REC_RATE_SELECTOR,
+ IB_SA_MCMEMBER_REC_RATE, dst->rate_selector,
+ src->rate, dst->rate))
+ return -EINVAL;
+ if (check_selector(comp_mask,
+ IB_SA_MCMEMBER_REC_PACKET_LIFE_TIME_SELECTOR,
+ IB_SA_MCMEMBER_REC_PACKET_LIFE_TIME,
+ dst->packet_life_time_selector,
+ src->packet_life_time, dst->packet_life_time))
+ return -EINVAL;
+ if (comp_mask & IB_SA_MCMEMBER_REC_SL && src->sl != dst->sl)
+ return -EINVAL;
+ if (comp_mask & IB_SA_MCMEMBER_REC_FLOW_LABEL &&
+ src->flow_label != dst->flow_label)
+ return -EINVAL;
+ if (comp_mask & IB_SA_MCMEMBER_REC_HOP_LIMIT &&
+ src->hop_limit != dst->hop_limit)
+ return -EINVAL;
+ if (comp_mask & IB_SA_MCMEMBER_REC_SCOPE && src->scope != dst->scope)
+ return -EINVAL;
+
+ /* join_state checked separately, proxy_join ignored */
+
+ return 0;
+}
+
+static int send_join(struct mcast_group *group, struct mcast_member *member)
+{
+ struct mcast_port *port = group->port;
+ int ret;
+
+ group->last_join = member;
+ ret = ib_sa_mcmember_rec_query(&sa_client, port->dev->device,
+ port->port_num, IB_MGMT_METHOD_SET,
+ &member->multicast.rec,
+ member->multicast.comp_mask,
+ 3000, GFP_KERNEL, join_handler, group,
+ &group->query);
+ if (ret >= 0) {
+ group->query_id = ret;
+ ret = 0;
+ }
+ return ret;
+}
+
+static int send_leave(struct mcast_group *group, u8 leave_state)
+{
+ struct mcast_port *port = group->port;
+ struct ib_sa_mcmember_rec rec;
+ int ret;
+
+ rec = group->rec;
+ rec.join_state = leave_state;
+
+ ret = ib_sa_mcmember_rec_query(&sa_client, port->dev->device,
+ port->port_num, IB_SA_METHOD_DELETE, &rec,
+ IB_SA_MCMEMBER_REC_MGID |
+ IB_SA_MCMEMBER_REC_PORT_GID |
+ IB_SA_MCMEMBER_REC_JOIN_STATE,
+ 3000, GFP_KERNEL, leave_handler,
+ group, &group->query);
+ if (ret >= 0) {
+ group->query_id = ret;
+ ret = 0;
+ }
+ return ret;
+}
+
+static void join_group(struct mcast_group *group, struct mcast_member *member,
+ u8 join_state)
+{
+ member->state = MCAST_MEMBER;
+ adjust_membership(group, join_state, 1);
+ group->rec.join_state |= join_state;
+ member->multicast.rec = group->rec;
+ member->multicast.rec.join_state = join_state;
+ list_move(&member->list, &group->active_list);
+}
+
+static int fail_join(struct mcast_group *group, struct mcast_member *member,
+ int status)
+{
+ spin_lock_irq(&group->lock);
+ list_del_init(&member->list);
+ spin_unlock_irq(&group->lock);
+ return member->multicast.callback(status, &member->multicast);
+}
+
+static void process_group_error(struct mcast_group *group)
+{
+ struct mcast_member *member;
+ int ret;
+
+ spin_lock_irq(&group->lock);
+ while (!list_empty(&group->active_list)) {
+ member = list_entry(group->active_list.next,
+ struct mcast_member, list);
+ atomic_inc(&member->refcount);
+ list_del_init(&member->list);
+ adjust_membership(group, member->multicast.rec.join_state, -1);
+ member->state = MCAST_ERROR;
+ spin_unlock_irq(&group->lock);
+
+ ret = member->multicast.callback(-ENETRESET,
+ &member->multicast);
+ deref_member(member);
+ if (ret)
+ ib_sa_free_multicast(&member->multicast);
+ spin_lock_irq(&group->lock);
+ }
+
+ group->rec.join_state = 0;
+ group->state = MCAST_BUSY;
+ spin_unlock_irq(&group->lock);
+}
+
+static void mcast_work_handler(struct work_struct *work)
+{
+ struct mcast_group *group;
+ struct mcast_member *member;
+ struct ib_sa_multicast *multicast;
+ int status, ret;
+ u8 join_state;
+
+ group = container_of(work, typeof(*group), work);
+retest:
+ spin_lock_irq(&group->lock);
+ while (!list_empty(&group->pending_list) ||
+ (group->state == MCAST_ERROR)) {
+
+ if (group->state == MCAST_ERROR) {
+ spin_unlock_irq(&group->lock);
+ process_group_error(group);
+ goto retest;
+ }
+
+ member = list_entry(group->pending_list.next,
+ struct mcast_member, list);
+ multicast = &member->multicast;
+ join_state = multicast->rec.join_state;
+ atomic_inc(&member->refcount);
+
+ if (join_state == (group->rec.join_state & join_state)) {
+ status = cmp_rec(&group->rec, &multicast->rec,
+ multicast->comp_mask);
+ if (!status)
+ join_group(group, member, join_state);
+ else
+ list_del_init(&member->list);
+ spin_unlock_irq(&group->lock);
+ ret = multicast->callback(status, multicast);
+ } else {
+ spin_unlock_irq(&group->lock);
+ status = send_join(group, member);
+ if (!status) {
+ deref_member(member);
+ return;
+ }
+ ret = fail_join(group, member, status);
+ }
+
+ deref_member(member);
+ if (ret)
+ ib_sa_free_multicast(&member->multicast);
+ spin_lock_irq(&group->lock);
+ }
+
+ join_state = get_leave_state(group);
+ if (join_state) {
+ group->rec.join_state &= ~join_state;
+ spin_unlock_irq(&group->lock);
+ if (send_leave(group, join_state))
+ goto retest;
+ } else {
+ group->state = MCAST_IDLE;
+ spin_unlock_irq(&group->lock);
+ release_group(group);
+ }
+}
+
+/*
+ * Fail a join request if it is still active - at the head of the pending queue.
+ */
+static void process_join_error(struct mcast_group *group, int status)
+{
+ struct mcast_member *member;
+ int ret;
+
+ spin_lock_irq(&group->lock);
+ member = list_entry(group->pending_list.next,
+ struct mcast_member, list);
+ if (group->last_join == member) {
+ atomic_inc(&member->refcount);
+ list_del_init(&member->list);
+ spin_unlock_irq(&group->lock);
+ ret = member->multicast.callback(status, &member->multicast);
+ deref_member(member);
+ if (ret)
+ ib_sa_free_multicast(&member->multicast);
+ } else
+ spin_unlock_irq(&group->lock);
+}
+
+static void join_handler(int status, struct ib_sa_mcmember_rec *rec,
+ void *context)
+{
+ struct mcast_group *group = context;
+
+ if (status)
+ process_join_error(group, status);
+ else {
+ spin_lock_irq(&group->port->lock);
+ group->rec = *rec;
+ if (!memcmp(&mgid0, &group->rec.mgid, sizeof mgid0)) {
+ rb_erase(&group->node, &group->port->table);
+ mcast_insert(group->port, group, 1);
+ }
+ spin_unlock_irq(&group->port->lock);
+ }
+ mcast_work_handler(&group->work);
+}
+
+static void leave_handler(int status, struct ib_sa_mcmember_rec *rec,
+ void *context)
+{
+ struct mcast_group *group = context;
+
+ mcast_work_handler(&group->work);
+}
+
+static struct mcast_group *acquire_group(struct mcast_port *port,
+ union ib_gid *mgid, gfp_t gfp_mask)
+{
+ struct mcast_group *group, *cur_group;
+ unsigned long flags;
+ int is_mgid0;
+
+ is_mgid0 = !memcmp(&mgid0, mgid, sizeof mgid0);
+ if (!is_mgid0) {
+ spin_lock_irqsave(&port->lock, flags);
+ group = mcast_find(port, mgid);
+ if (group)
+ goto found;
+ spin_unlock_irqrestore(&port->lock, flags);
+ }
+
+ group = kzalloc(sizeof *group, gfp_mask);
+ if (!group)
+ return NULL;
+
+ group->port = port;
+ group->rec.mgid = *mgid;
+ INIT_LIST_HEAD(&group->pending_list);
+ INIT_LIST_HEAD(&group->active_list);
+ INIT_WORK(&group->work, mcast_work_handler);
+ spin_lock_init(&group->lock);
+
+ spin_lock_irqsave(&port->lock, flags);
+ cur_group = mcast_insert(port, group, is_mgid0);
+ if (cur_group) {
+ kfree(group);
+ group = cur_group;
+ } else
+ atomic_inc(&port->refcount);
+found:
+ atomic_inc(&group->refcount);
+ spin_unlock_irqrestore(&port->lock, flags);
+ return group;
+}
+
+/*
+ * We serialize all join requests to a single group to make our lives much
+ * easier. Otherwise, two users could try to join the same group
+ * simultaneously, with different configurations, one could leave while the
+ * join is in progress, etc., which makes locking around error recovery
+ * difficult.
+ */
+struct ib_sa_multicast *
+ib_sa_join_multicast(struct ib_sa_client *client,
+ struct ib_device *device, u8 port_num,
+ struct ib_sa_mcmember_rec *rec,
+ ib_sa_comp_mask comp_mask, gfp_t gfp_mask,
+ int (*callback)(int status,
+ struct ib_sa_multicast *multicast),
+ void *context)
+{
+ struct mcast_device *dev;
+ struct mcast_member *member;
+ struct ib_sa_multicast *multicast;
+ int ret;
+
+ dev = ib_get_client_data(device, &mcast_client);
+ if (!dev)
+ return ERR_PTR(-ENODEV);
+
+ member = kmalloc(sizeof *member, gfp_mask);
+ if (!member)
+ return ERR_PTR(-ENOMEM);
+
+ ib_sa_client_get(client);
+ member->client = client;
+ member->multicast.rec = *rec;
+ member->multicast.comp_mask = comp_mask;
+ member->multicast.callback = callback;
+ member->multicast.context = context;
+ init_completion(&member->comp);
+ atomic_set(&member->refcount, 1);
+ member->state = MCAST_JOINING;
+
+ member->group = acquire_group(&dev->port[port_num - dev->start_port],
+ &rec->mgid, gfp_mask);
+ if (!member->group) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ /*
+ * The user will get the multicast structure in their callback. They
+ * could then free the multicast structure before we can return from
+ * this routine. So we save the pointer to return before queuing
+ * any callback.
+ */
+ multicast = &member->multicast;
+ queue_join(member);
+ return multicast;
+
+err:
+ ib_sa_client_put(client);
+ kfree(member);
+ return ERR_PTR(ret);
+}
+EXPORT_SYMBOL(ib_sa_join_multicast);
+
+void ib_sa_free_multicast(struct ib_sa_multicast *multicast)
+{
+ struct mcast_member *member;
+ struct mcast_group *group;
+
+ member = container_of(multicast, struct mcast_member, multicast);
+ group = member->group;
+
+ spin_lock_irq(&group->lock);
+ if (member->state == MCAST_MEMBER)
+ adjust_membership(group, multicast->rec.join_state, -1);
+
+ list_del_init(&member->list);
+
+ if (group->state == MCAST_IDLE) {
+ group->state = MCAST_BUSY;
+ spin_unlock_irq(&group->lock);
+ /* Continue to hold reference on group until callback */
+ queue_work(mcast_wq, &group->work);
+ } else {
+ spin_unlock_irq(&group->lock);
+ release_group(group);
+ }
+
+ deref_member(member);
+ wait_for_completion(&member->comp);
+ ib_sa_client_put(member->client);
+ kfree(member);
+}
+EXPORT_SYMBOL(ib_sa_free_multicast);
+
+int ib_sa_get_mcmember_rec(struct ib_device *device, u8 port_num,
+ union ib_gid *mgid, struct ib_sa_mcmember_rec *rec)
+{
+ struct mcast_device *dev;
+ struct mcast_port *port;
+ struct mcast_group *group;
+ unsigned long flags;
+ int ret = 0;
+
+ dev = ib_get_client_data(device, &mcast_client);
+ if (!dev)
+ return -ENODEV;
+
+ port = &dev->port[port_num - dev->start_port];
+ spin_lock_irqsave(&port->lock, flags);
+ group = mcast_find(port, mgid);
+ if (group)
+ *rec = group->rec;
+ else
+ ret = -EADDRNOTAVAIL;
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ return ret;
+}
+EXPORT_SYMBOL(ib_sa_get_mcmember_rec);
+
+int ib_init_ah_from_mcmember(struct ib_device *device, u8 port_num,
+ struct ib_sa_mcmember_rec *rec,
+ struct ib_ah_attr *ah_attr)
+{
+ int ret;
+ u16 gid_index;
+ u8 p;
+
+ ret = ib_find_cached_gid(device, &rec->port_gid, &p, &gid_index);
+ if (ret)
+ return ret;
+
+ memset(ah_attr, 0, sizeof *ah_attr);
+ ah_attr->dlid = be16_to_cpu(rec->mlid);
+ ah_attr->sl = rec->sl;
+ ah_attr->port_num = port_num;
+ ah_attr->static_rate = rec->rate;
+
+ ah_attr->ah_flags = IB_AH_GRH;
+ ah_attr->grh.dgid = rec->mgid;
+
+ ah_attr->grh.sgid_index = (u8) gid_index;
+ ah_attr->grh.flow_label = be32_to_cpu(rec->flow_label);
+ ah_attr->grh.hop_limit = rec->hop_limit;
+ ah_attr->grh.traffic_class = rec->traffic_class;
+
+ return 0;
+}
+EXPORT_SYMBOL(ib_init_ah_from_mcmember);
+
+static void mcast_groups_lost(struct mcast_port *port)
+{
+ struct mcast_group *group;
+ struct rb_node *node;
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->lock, flags);
+ for (node = rb_first(&port->table); node; node = rb_next(node)) {
+ group = rb_entry(node, struct mcast_group, node);
+ spin_lock(&group->lock);
+ if (group->state == MCAST_IDLE) {
+ atomic_inc(&group->refcount);
+ queue_work(mcast_wq, &group->work);
+ }
+ group->state = MCAST_ERROR;
+ spin_unlock(&group->lock);
+ }
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void mcast_event_handler(struct ib_event_handler *handler,
+ struct ib_event *event)
+{
+ struct mcast_device *dev;
+
+ dev = container_of(handler, struct mcast_device, event_handler);
+
+ switch (event->event) {
+ case IB_EVENT_PORT_ERR:
+ case IB_EVENT_LID_CHANGE:
+ case IB_EVENT_SM_CHANGE:
+ case IB_EVENT_CLIENT_REREGISTER:
+ mcast_groups_lost(&dev->port[event->element.port_num -
+ dev->start_port]);
+ break;
+ default:
+ break;
+ }
+}
+
+static void mcast_add_one(struct ib_device *device)
+{
+ struct mcast_device *dev;
+ struct mcast_port *port;
+ int i;
+
+ if (rdma_node_get_transport(device->node_type) != RDMA_TRANSPORT_IB)
+ return;
+
+ dev = kmalloc(sizeof *dev + device->phys_port_cnt * sizeof *port,
+ GFP_KERNEL);
+ if (!dev)
+ return;
+
+ if (device->node_type == RDMA_NODE_IB_SWITCH)
+ dev->start_port = dev->end_port = 0;
+ else {
+ dev->start_port = 1;
+ dev->end_port = device->phys_port_cnt;
+ }
+
+ for (i = 0; i <= dev->end_port - dev->start_port; i++) {
+ port = &dev->port[i];
+ port->dev = dev;
+ port->port_num = dev->start_port + i;
+ spin_lock_init(&port->lock);
+ port->table = RB_ROOT;
+ init_completion(&port->comp);
+ atomic_set(&port->refcount, 1);
+ }
+
+ dev->device = device;
+ ib_set_client_data(device, &mcast_client, dev);
+
+ INIT_IB_EVENT_HANDLER(&dev->event_handler, device, mcast_event_handler);
+ ib_register_event_handler(&dev->event_handler);
+}
+
+static void mcast_remove_one(struct ib_device *device)
+{
+ struct mcast_device *dev;
+ struct mcast_port *port;
+ int i;
+
+ dev = ib_get_client_data(device, &mcast_client);
+ if (!dev)
+ return;
+
+ ib_unregister_event_handler(&dev->event_handler);
+ flush_workqueue(mcast_wq);
+
+ for (i = 0; i <= dev->end_port - dev->start_port; i++) {
+ port = &dev->port[i];
+ deref_port(port);
+ wait_for_completion(&port->comp);
+ }
+
+ kfree(dev);
+}
+
+int mcast_init(void)
+{
+ int ret;
+
+ mcast_wq = create_singlethread_workqueue("ib_mcast");
+ if (!mcast_wq)
+ return -ENOMEM;
+
+ ib_sa_register_client(&sa_client);
+
+ ret = ib_register_client(&mcast_client);
+ if (ret)
+ goto err;
+ return 0;
+
+err:
+ ib_sa_unregister_client(&sa_client);
+ destroy_workqueue(mcast_wq);
+ return ret;
+}
+
+void mcast_cleanup(void)
+{
+ ib_unregister_client(&mcast_client);
+ ib_sa_unregister_client(&sa_client);
+ destroy_workqueue(mcast_wq);
+}
diff --git a/drivers/infiniband/core/sa.h b/drivers/infiniband/core/sa.h
new file mode 100644
index 00000000000..24c93fd320f
--- /dev/null
+++ b/drivers/infiniband/core/sa.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2004 Topspin Communications. All rights reserved.
+ * Copyright (c) 2005 Voltaire, Inc.  All rights reserved.
+ * Copyright (c) 2006 Intel Corporation. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef SA_H
+#define SA_H
+
+#include <rdma/ib_sa.h>
+
+static inline void ib_sa_client_get(struct ib_sa_client *client)
+{
+ atomic_inc(&client->users);
+}
+
+static inline void ib_sa_client_put(struct ib_sa_client *client)
+{
+ if (atomic_dec_and_test(&client->users))
+ complete(&client->comp);
+}
+
+int ib_sa_mcmember_rec_query(struct ib_sa_client *client,
+ struct ib_device *device, u8 port_num,
+ u8 method,
+ struct ib_sa_mcmember_rec *rec,
+ ib_sa_comp_mask comp_mask,
+ int timeout_ms, gfp_t gfp_mask,
+ void (*callback)(int status,
+ struct ib_sa_mcmember_rec *resp,
+ void *context),
+ void *context,
+ struct ib_sa_query **sa_query);
+
+int mcast_init(void);
+void mcast_cleanup(void);
+
+#endif /* SA_H */
diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c
index e45afba7534..68db633711c 100644
--- a/drivers/infiniband/core/sa_query.c
+++ b/drivers/infiniband/core/sa_query.c
@@ -47,8 +47,8 @@
#include <linux/workqueue.h>
#include <rdma/ib_pack.h>
-#include <rdma/ib_sa.h>
#include <rdma/ib_cache.h>
+#include "sa.h"
MODULE_AUTHOR("Roland Dreier");
MODULE_DESCRIPTION("InfiniBand subnet administration query support");
@@ -425,17 +425,6 @@ void ib_sa_register_client(struct ib_sa_client *client)
}
EXPORT_SYMBOL(ib_sa_register_client);
-static inline void ib_sa_client_get(struct ib_sa_client *client)
-{
- atomic_inc(&client->users);
-}
-
-static inline void ib_sa_client_put(struct ib_sa_client *client)
-{
- if (atomic_dec_and_test(&client->users))
- complete(&client->comp);
-}
-
void ib_sa_unregister_client(struct ib_sa_client *client)
{
ib_sa_client_put(client);
@@ -482,6 +471,7 @@ int ib_init_ah_from_path(struct ib_device *device, u8 port_num,
ah_attr->sl = rec->sl;
ah_attr->src_path_bits = be16_to_cpu(rec->slid) & 0x7f;
ah_attr->port_num = port_num;
+ ah_attr->static_rate = rec->rate;
if (rec->hop_limit > 1) {
ah_attr->ah_flags = IB_AH_GRH;
@@ -901,7 +891,6 @@ err1:
kfree(query);
return ret;
}
-EXPORT_SYMBOL(ib_sa_mcmember_rec_query);
static void send_handler(struct ib_mad_agent *agent,
struct ib_mad_send_wc *mad_send_wc)
@@ -1053,14 +1042,27 @@ static int __init ib_sa_init(void)
get_random_bytes(&tid, sizeof tid);
ret = ib_register_client(&sa_client);
- if (ret)
+ if (ret) {
printk(KERN_ERR "Couldn't register ib_sa client\n");
+ goto err1;
+ }
+
+ ret = mcast_init();
+ if (ret) {
+ printk(KERN_ERR "Couldn't initialize multicast handling\n");
+ goto err2;
+ }
+ return 0;
+err2:
+ ib_unregister_client(&sa_client);
+err1:
return ret;
}
static void __exit ib_sa_cleanup(void)
{
+ mcast_cleanup();
ib_unregister_client(&sa_client);
idr_destroy(&query_idr);
}
diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c
index 709323c14c5..000c086bf2e 100644
--- a/drivers/infiniband/core/sysfs.c
+++ b/drivers/infiniband/core/sysfs.c
@@ -714,8 +714,6 @@ int ib_device_register_sysfs(struct ib_device *device)
if (ret)
goto err_put;
} else {
- int i;
-
for (i = 1; i <= device->phys_port_cnt; ++i) {
ret = add_port(device, i);
if (ret)
diff --git a/drivers/infiniband/core/ucm.c b/drivers/infiniband/core/ucm.c
index f15220a0ee7..ee51d79a7ad 100644
--- a/drivers/infiniband/core/ucm.c
+++ b/drivers/infiniband/core/ucm.c
@@ -1221,7 +1221,7 @@ static void ib_ucm_release_class_dev(struct class_device *class_dev)
kfree(dev);
}
-static struct file_operations ucm_fops = {
+static const struct file_operations ucm_fops = {
.owner = THIS_MODULE,
.open = ib_ucm_open,
.release = ib_ucm_close,
diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c
index e2e8d329b44..b516b93b855 100644
--- a/drivers/infiniband/core/ucma.c
+++ b/drivers/infiniband/core/ucma.c
@@ -70,10 +70,24 @@ struct ucma_context {
u64 uid;
struct list_head list;
+ struct list_head mc_list;
+};
+
+struct ucma_multicast {
+ struct ucma_context *ctx;
+ int id;
+ int events_reported;
+
+ u64 uid;
+ struct list_head list;
+ struct sockaddr addr;
+ u8 pad[sizeof(struct sockaddr_in6) -
+ sizeof(struct sockaddr)];
};
struct ucma_event {
struct ucma_context *ctx;
+ struct ucma_multicast *mc;
struct list_head list;
struct rdma_cm_id *cm_id;
struct rdma_ucm_event_resp resp;
@@ -81,6 +95,7 @@ struct ucma_event {
static DEFINE_MUTEX(mut);
static DEFINE_IDR(ctx_idr);
+static DEFINE_IDR(multicast_idr);
static inline struct ucma_context *_ucma_find_context(int id,
struct ucma_file *file)
@@ -124,6 +139,7 @@ static struct ucma_context *ucma_alloc_ctx(struct ucma_file *file)
atomic_set(&ctx->ref, 1);
init_completion(&ctx->comp);
+ INIT_LIST_HEAD(&ctx->mc_list);
ctx->file = file;
do {
@@ -147,6 +163,37 @@ error:
return NULL;
}
+static struct ucma_multicast* ucma_alloc_multicast(struct ucma_context *ctx)
+{
+ struct ucma_multicast *mc;
+ int ret;
+
+ mc = kzalloc(sizeof(*mc), GFP_KERNEL);
+ if (!mc)
+ return NULL;
+
+ do {
+ ret = idr_pre_get(&multicast_idr, GFP_KERNEL);
+ if (!ret)
+ goto error;
+
+ mutex_lock(&mut);
+ ret = idr_get_new(&multicast_idr, mc, &mc->id);
+ mutex_unlock(&mut);
+ } while (ret == -EAGAIN);
+
+ if (ret)
+ goto error;
+
+ mc->ctx = ctx;
+ list_add_tail(&mc->list, &ctx->mc_list);
+ return mc;
+
+error:
+ kfree(mc);
+ return NULL;
+}
+
static void ucma_copy_conn_event(struct rdma_ucm_conn_param *dst,
struct rdma_conn_param *src)
{
@@ -180,8 +227,19 @@ static void ucma_set_event_context(struct ucma_context *ctx,
struct ucma_event *uevent)
{
uevent->ctx = ctx;
- uevent->resp.uid = ctx->uid;
- uevent->resp.id = ctx->id;
+ switch (event->event) {
+ case RDMA_CM_EVENT_MULTICAST_JOIN:
+ case RDMA_CM_EVENT_MULTICAST_ERROR:
+ uevent->mc = (struct ucma_multicast *)
+ event->param.ud.private_data;
+ uevent->resp.uid = uevent->mc->uid;
+ uevent->resp.id = uevent->mc->id;
+ break;
+ default:
+ uevent->resp.uid = ctx->uid;
+ uevent->resp.id = ctx->id;
+ break;
+ }
}
static int ucma_event_handler(struct rdma_cm_id *cm_id,
@@ -199,7 +257,7 @@ static int ucma_event_handler(struct rdma_cm_id *cm_id,
ucma_set_event_context(ctx, event, uevent);
uevent->resp.event = event->event;
uevent->resp.status = event->status;
- if (cm_id->ps == RDMA_PS_UDP)
+ if (cm_id->ps == RDMA_PS_UDP || cm_id->ps == RDMA_PS_IPOIB)
ucma_copy_ud_event(&uevent->resp.param.ud, &event->param.ud);
else
ucma_copy_conn_event(&uevent->resp.param.conn,
@@ -290,6 +348,8 @@ static ssize_t ucma_get_event(struct ucma_file *file, const char __user *inbuf,
list_del(&uevent->list);
uevent->ctx->events_reported++;
+ if (uevent->mc)
+ uevent->mc->events_reported++;
kfree(uevent);
done:
mutex_unlock(&file->mut);
@@ -342,6 +402,19 @@ err1:
return ret;
}
+static void ucma_cleanup_multicast(struct ucma_context *ctx)
+{
+ struct ucma_multicast *mc, *tmp;
+
+ mutex_lock(&mut);
+ list_for_each_entry_safe(mc, tmp, &ctx->mc_list, list) {
+ list_del(&mc->list);
+ idr_remove(&multicast_idr, mc->id);
+ kfree(mc);
+ }
+ mutex_unlock(&mut);
+}
+
static void ucma_cleanup_events(struct ucma_context *ctx)
{
struct ucma_event *uevent, *tmp;
@@ -360,6 +433,19 @@ static void ucma_cleanup_events(struct ucma_context *ctx)
}
}
+static void ucma_cleanup_mc_events(struct ucma_multicast *mc)
+{
+ struct ucma_event *uevent, *tmp;
+
+ list_for_each_entry_safe(uevent, tmp, &mc->ctx->file->event_list, list) {
+ if (uevent->mc != mc)
+ continue;
+
+ list_del(&uevent->list);
+ kfree(uevent);
+ }
+}
+
static int ucma_free_ctx(struct ucma_context *ctx)
{
int events_reported;
@@ -367,6 +453,8 @@ static int ucma_free_ctx(struct ucma_context *ctx)
/* No new events will be generated after destroying the id. */
rdma_destroy_id(ctx->cm_id);
+ ucma_cleanup_multicast(ctx);
+
/* Cleanup events not yet reported to the user. */
mutex_lock(&ctx->file->mut);
ucma_cleanup_events(ctx);
@@ -731,6 +819,114 @@ static ssize_t ucma_notify(struct ucma_file *file, const char __user *inbuf,
return ret;
}
+static ssize_t ucma_join_multicast(struct ucma_file *file,
+ const char __user *inbuf,
+ int in_len, int out_len)
+{
+ struct rdma_ucm_join_mcast cmd;
+ struct rdma_ucm_create_id_resp resp;
+ struct ucma_context *ctx;
+ struct ucma_multicast *mc;
+ int ret;
+
+ if (out_len < sizeof(resp))
+ return -ENOSPC;
+
+ if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
+ return -EFAULT;
+
+ ctx = ucma_get_ctx(file, cmd.id);
+ if (IS_ERR(ctx))
+ return PTR_ERR(ctx);
+
+ mutex_lock(&file->mut);
+ mc = ucma_alloc_multicast(ctx);
+ if (IS_ERR(mc)) {
+ ret = PTR_ERR(mc);
+ goto err1;
+ }
+
+ mc->uid = cmd.uid;
+ memcpy(&mc->addr, &cmd.addr, sizeof cmd.addr);
+ ret = rdma_join_multicast(ctx->cm_id, &mc->addr, mc);
+ if (ret)
+ goto err2;
+
+ resp.id = mc->id;
+ if (copy_to_user((void __user *)(unsigned long)cmd.response,
+ &resp, sizeof(resp))) {
+ ret = -EFAULT;
+ goto err3;
+ }
+
+ mutex_unlock(&file->mut);
+ ucma_put_ctx(ctx);
+ return 0;
+
+err3:
+ rdma_leave_multicast(ctx->cm_id, &mc->addr);
+ ucma_cleanup_mc_events(mc);
+err2:
+ mutex_lock(&mut);
+ idr_remove(&multicast_idr, mc->id);
+ mutex_unlock(&mut);
+ list_del(&mc->list);
+ kfree(mc);
+err1:
+ mutex_unlock(&file->mut);
+ ucma_put_ctx(ctx);
+ return ret;
+}
+
+static ssize_t ucma_leave_multicast(struct ucma_file *file,
+ const char __user *inbuf,
+ int in_len, int out_len)
+{
+ struct rdma_ucm_destroy_id cmd;
+ struct rdma_ucm_destroy_id_resp resp;
+ struct ucma_multicast *mc;
+ int ret = 0;
+
+ if (out_len < sizeof(resp))
+ return -ENOSPC;
+
+ if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
+ return -EFAULT;
+
+ mutex_lock(&mut);
+ mc = idr_find(&multicast_idr, cmd.id);
+ if (!mc)
+ mc = ERR_PTR(-ENOENT);
+ else if (mc->ctx->file != file)
+ mc = ERR_PTR(-EINVAL);
+ else {
+ idr_remove(&multicast_idr, mc->id);
+ atomic_inc(&mc->ctx->ref);
+ }
+ mutex_unlock(&mut);
+
+ if (IS_ERR(mc)) {
+ ret = PTR_ERR(mc);
+ goto out;
+ }
+
+ rdma_leave_multicast(mc->ctx->cm_id, &mc->addr);
+ mutex_lock(&mc->ctx->file->mut);
+ ucma_cleanup_mc_events(mc);
+ list_del(&mc->list);
+ mutex_unlock(&mc->ctx->file->mut);
+
+ ucma_put_ctx(mc->ctx);
+ resp.events_reported = mc->events_reported;
+ kfree(mc);
+
+ if (copy_to_user((void __user *)(unsigned long)cmd.response,
+ &resp, sizeof(resp)))
+ ret = -EFAULT;
+out:
+ return ret;
+}
+
static ssize_t (*ucma_cmd_table[])(struct ucma_file *file,
const char __user *inbuf,
int in_len, int out_len) = {
@@ -750,6 +946,8 @@ static ssize_t (*ucma_cmd_table[])(struct ucma_file *file,
[RDMA_USER_CM_CMD_GET_OPTION] = NULL,
[RDMA_USER_CM_CMD_SET_OPTION] = NULL,
[RDMA_USER_CM_CMD_NOTIFY] = ucma_notify,
+ [RDMA_USER_CM_CMD_JOIN_MCAST] = ucma_join_multicast,
+ [RDMA_USER_CM_CMD_LEAVE_MCAST] = ucma_leave_multicast,
};
static ssize_t ucma_write(struct file *filp, const char __user *buf,
@@ -833,7 +1031,7 @@ static int ucma_close(struct inode *inode, struct file *filp)
return 0;
}
-static struct file_operations ucma_fops = {
+static const struct file_operations ucma_fops = {
.owner = THIS_MODULE,
.open = ucma_open,
.release = ucma_close,
diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c
index 807fbd6b841..c069ebeba8e 100644
--- a/drivers/infiniband/core/user_mad.c
+++ b/drivers/infiniband/core/user_mad.c
@@ -771,7 +771,7 @@ static int ib_umad_close(struct inode *inode, struct file *filp)
return 0;
}
-static struct file_operations umad_fops = {
+static const struct file_operations umad_fops = {
.owner = THIS_MODULE,
.read = ib_umad_read,
.write = ib_umad_write,
@@ -846,7 +846,7 @@ static int ib_umad_sm_close(struct inode *inode, struct file *filp)
return ret;
}
-static struct file_operations umad_sm_fops = {
+static const struct file_operations umad_sm_fops = {
.owner = THIS_MODULE,
.open = ib_umad_sm_open,
.release = ib_umad_sm_close
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
index 743247ec065..df1efbc1088 100644
--- a/drivers/infiniband/core/uverbs_cmd.c
+++ b/drivers/infiniband/core/uverbs_cmd.c
@@ -933,7 +933,7 @@ ssize_t ib_uverbs_poll_cq(struct ib_uverbs_file *file,
resp->wc[i].vendor_err = wc[i].vendor_err;
resp->wc[i].byte_len = wc[i].byte_len;
resp->wc[i].imm_data = (__u32 __force) wc[i].imm_data;
- resp->wc[i].qp_num = wc[i].qp_num;
+ resp->wc[i].qp_num = wc[i].qp->qp_num;
resp->wc[i].src_qp = wc[i].src_qp;
resp->wc[i].wc_flags = wc[i].wc_flags;
resp->wc[i].pkey_index = wc[i].pkey_index;
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c
index a617ca7b692..f8bc822a3cc 100644
--- a/drivers/infiniband/core/uverbs_main.c
+++ b/drivers/infiniband/core/uverbs_main.c
@@ -375,7 +375,7 @@ static int ib_uverbs_event_close(struct inode *inode, struct file *filp)
return 0;
}
-static struct file_operations uverbs_event_fops = {
+static const struct file_operations uverbs_event_fops = {
.owner = THIS_MODULE,
.read = ib_uverbs_event_read,
.poll = ib_uverbs_event_poll,
@@ -679,14 +679,14 @@ static int ib_uverbs_close(struct inode *inode, struct file *filp)
return 0;
}
-static struct file_operations uverbs_fops = {
+static const struct file_operations uverbs_fops = {
.owner = THIS_MODULE,
.write = ib_uverbs_write,
.open = ib_uverbs_open,
.release = ib_uverbs_close
};
-static struct file_operations uverbs_mmap_fops = {
+static const struct file_operations uverbs_mmap_fops = {
.owner = THIS_MODULE,
.write = ib_uverbs_write,
.mmap = ib_uverbs_mmap,
diff --git a/drivers/infiniband/hw/amso1100/c2.c b/drivers/infiniband/hw/amso1100/c2.c
index 27fe242ed43..59243d9aedd 100644
--- a/drivers/infiniband/hw/amso1100/c2.c
+++ b/drivers/infiniband/hw/amso1100/c2.c
@@ -1073,7 +1073,7 @@ static int __devinit c2_probe(struct pci_dev *pcidev,
0xffffc000) / sizeof(struct c2_rxp_desc);
/* Request an interrupt line for the driver */
- ret = request_irq(pcidev->irq, c2_interrupt, SA_SHIRQ, DRV_NAME, c2dev);
+ ret = request_irq(pcidev->irq, c2_interrupt, IRQF_SHARED, DRV_NAME, c2dev);
if (ret) {
printk(KERN_ERR PFX "%s: requested IRQ %u is busy\n",
pci_name(pcidev), pcidev->irq);
diff --git a/drivers/infiniband/hw/amso1100/c2_cq.c b/drivers/infiniband/hw/amso1100/c2_cq.c
index 05c9154d46f..5175c99ee58 100644
--- a/drivers/infiniband/hw/amso1100/c2_cq.c
+++ b/drivers/infiniband/hw/amso1100/c2_cq.c
@@ -153,7 +153,7 @@ static inline int c2_poll_one(struct c2_dev *c2dev,
entry->status = c2_cqe_status_to_openib(c2_wr_get_result(ce));
entry->wr_id = ce->hdr.context;
- entry->qp_num = ce->handle;
+ entry->qp = &qp->ibqp;
entry->wc_flags = 0;
entry->slid = 0;
entry->sl = 0;
diff --git a/drivers/infiniband/hw/cxgb3/Kconfig b/drivers/infiniband/hw/cxgb3/Kconfig
new file mode 100644
index 00000000000..77977f55dca
--- /dev/null
+++ b/drivers/infiniband/hw/cxgb3/Kconfig
@@ -0,0 +1,27 @@
+config INFINIBAND_CXGB3
+ tristate "Chelsio RDMA Driver"
+ depends on CHELSIO_T3 && INFINIBAND && INET
+ select GENERIC_ALLOCATOR
+ ---help---
+ This is an iWARP/RDMA driver for the Chelsio T3 1GbE and
+ 10GbE adapters.
+
+ For general information about Chelsio and our products, visit
+ our website at <http://www.chelsio.com>.
+
+ For customer support, please visit our customer support page at
+ <http://www.chelsio.com/support.htm>.
+
+ Please send feedback to <linux-bugs@chelsio.com>.
+
+ To compile this driver as a module, choose M here: the module
+ will be called iw_cxgb3.
+
+config INFINIBAND_CXGB3_DEBUG
+ bool "Verbose debugging output"
+ depends on INFINIBAND_CXGB3
+ default n
+ ---help---
+ This option causes the Chelsio RDMA driver to produce copious
+ amounts of debug messages. Select this if you are developing
+ the driver or trying to diagnose a problem.
diff --git a/drivers/infiniband/hw/cxgb3/Makefile b/drivers/infiniband/hw/cxgb3/Makefile
new file mode 100644
index 00000000000..0e110f32f12
--- /dev/null
+++ b/drivers/infiniband/hw/cxgb3/Makefile
@@ -0,0 +1,12 @@
+EXTRA_CFLAGS += -I$(TOPDIR)/drivers/net/cxgb3 \
+ -I$(TOPDIR)/drivers/infiniband/hw/cxgb3/core
+
+obj-$(CONFIG_INFINIBAND_CXGB3) += iw_cxgb3.o
+
+iw_cxgb3-y := iwch_cm.o iwch_ev.o iwch_cq.o iwch_qp.o iwch_mem.o \
+ iwch_provider.o iwch.o cxio_hal.o cxio_resource.o
+
+ifdef CONFIG_INFINIBAND_CXGB3_DEBUG
+EXTRA_CFLAGS += -DDEBUG
+iw_cxgb3-y += cxio_dbg.o
+endif
diff --git a/drivers/infiniband/hw/cxgb3/cxio_dbg.c b/drivers/infiniband/hw/cxgb3/cxio_dbg.c
new file mode 100644
index 00000000000..75f7b16a271
--- /dev/null
+++ b/drivers/infiniband/hw/cxgb3/cxio_dbg.c
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2006 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifdef DEBUG
+#include <linux/types.h>
+#include "common.h"
+#include "cxgb3_ioctl.h"
+#include "cxio_hal.h"
+#include "cxio_wr.h"
+
+void cxio_dump_tpt(struct cxio_rdev *rdev, u32 stag)
+{
+ struct ch_mem_range *m;
+ u64 *data;
+ int rc;
+ int size = 32;
+
+ m = kmalloc(sizeof(*m) + size, GFP_ATOMIC);
+ if (!m) {
+ PDBG("%s couldn't allocate memory.\n", __FUNCTION__);
+ return;
+ }
+ m->mem_id = MEM_PMRX;
+ m->addr = (stag>>8) * 32 + rdev->rnic_info.tpt_base;
+ m->len = size;
+ PDBG("%s TPT addr 0x%x len %d\n", __FUNCTION__, m->addr, m->len);
+ rc = rdev->t3cdev_p->ctl(rdev->t3cdev_p, RDMA_GET_MEM, m);
+ if (rc) {
+ PDBG("%s toectl returned error %d\n", __FUNCTION__, rc);
+ kfree(m);
+ return;
+ }
+
+ data = (u64 *)m->buf;
+ while (size > 0) {
+ PDBG("TPT %08x: %016llx\n", m->addr, (unsigned long long) *data);
+ size -= 8;
+ data++;
+ m->addr += 8;
+ }
+ kfree(m);
+}
+
+void cxio_dump_pbl(struct cxio_rdev *rdev, u32 pbl_addr, uint len, u8 shift)
+{
+ struct ch_mem_range *m;
+ u64 *data;
+ int rc;
+ int size, npages;
+
+ shift += 12;
+ npages = (len + (1ULL << shift) - 1) >> shift;
+ size = npages * sizeof(u64);
+
+ m = kmalloc(sizeof(*m) + size, GFP_ATOMIC);
+ if (!m) {
+ PDBG("%s couldn't allocate memory.\n", __FUNCTION__);
+ return;
+ }
+ m->mem_id = MEM_PMRX;
+ m->addr = pbl_addr;
+ m->len = size;
+ PDBG("%s PBL addr 0x%x len %d depth %d\n",
+ __FUNCTION__, m->addr, m->len, npages);
+ rc = rdev->t3cdev_p->ctl(rdev->t3cdev_p, RDMA_GET_MEM, m);
+ if (rc) {
+ PDBG("%s toectl returned error %d\n", __FUNCTION__, rc);
+ kfree(m);
+ return;
+ }
+
+ data = (u64 *)m->buf;
+ while (size > 0) {
+ PDBG("PBL %08x: %016llx\n", m->addr, (unsigned long long) *data);
+ size -= 8;
+ data++;
+ m->addr += 8;
+ }
+ kfree(m);
+}
+
+void cxio_dump_wqe(union t3_wr *wqe)
+{
+ __be64 *data = (__be64 *)wqe;
+ uint size = (uint)(be64_to_cpu(*data) & 0xff);
+
+ if (size == 0)
+ size = 8;
+ while (size > 0) {
+ PDBG("WQE %p: %016llx\n", data,
+ (unsigned long long) be64_to_cpu(*data));
+ size--;
+ data++;
+ }
+}
+
+void cxio_dump_wce(struct t3_cqe *wce)
+{
+ __be64 *data = (__be64 *)wce;
+ int size = sizeof(*wce);
+
+ while (size > 0) {
+ PDBG("WCE %p: %016llx\n", data,
+ (unsigned long long) be64_to_cpu(*data));
+ size -= 8;
+ data++;
+ }
+}
+
+void cxio_dump_rqt(struct cxio_rdev *rdev, u32 hwtid, int nents)
+{
+ struct ch_mem_range *m;
+ int size = nents * 64;
+ u64 *data;
+ int rc;
+
+ m = kmalloc(sizeof(*m) + size, GFP_ATOMIC);
+ if (!m) {
+ PDBG("%s couldn't allocate memory.\n", __FUNCTION__);
+ return;
+ }
+ m->mem_id = MEM_PMRX;
+ m->addr = ((hwtid)<<10) + rdev->rnic_info.rqt_base;
+ m->len = size;
+ PDBG("%s RQT addr 0x%x len %d\n", __FUNCTION__, m->addr, m->len);
+ rc = rdev->t3cdev_p->ctl(rdev->t3cdev_p, RDMA_GET_MEM, m);
+ if (rc) {
+ PDBG("%s toectl returned error %d\n", __FUNCTION__, rc);
+ kfree(m);
+ return;
+ }
+
+ data = (u64 *)m->buf;
+ while (size > 0) {
+ PDBG("RQT %08x: %016llx\n", m->addr, (unsigned long long) *data);
+ size -= 8;
+ data++;
+ m->addr += 8;
+ }
+ kfree(m);
+}
+
+void cxio_dump_tcb(struct cxio_rdev *rdev, u32 hwtid)
+{
+ struct ch_mem_range *m;
+ int size = TCB_SIZE;
+ u32 *data;
+ int rc;
+
+ m = kmalloc(sizeof(*m) + size, GFP_ATOMIC);
+ if (!m) {
+ PDBG("%s couldn't allocate memory.\n", __FUNCTION__);
+ return;
+ }
+ m->mem_id = MEM_CM;
+ m->addr = hwtid * size;
+ m->len = size;
+ PDBG("%s TCB %d len %d\n", __FUNCTION__, m->addr, m->len);
+ rc = rdev->t3cdev_p->ctl(rdev->t3cdev_p, RDMA_GET_MEM, m);
+ if (rc) {
+ PDBG("%s toectl returned error %d\n", __FUNCTION__, rc);
+ kfree(m);
+ return;
+ }
+
+ data = (u32 *)m->buf;
+ while (size > 0) {
+ printk("%2u: %08x %08x %08x %08x %08x %08x %08x %08x\n",
+ m->addr,
+ *(data+2), *(data+3), *(data),*(data+1),
+ *(data+6), *(data+7), *(data+4), *(data+5));
+ size -= 32;
+ data += 8;
+ m->addr += 32;
+ }
+ kfree(m);
+}
+#endif
diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.c b/drivers/infiniband/hw/cxgb3/cxio_hal.c
new file mode 100644
index 00000000000..114ac3b775d
--- /dev/null
+++ b/drivers/infiniband/hw/cxgb3/cxio_hal.c
@@ -0,0 +1,1279 @@
+/*
+ * Copyright (c) 2006 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include <asm/delay.h>
+
+#include <linux/mutex.h>
+#include <linux/netdevice.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/pci.h>
+
+#include "cxio_resource.h"
+#include "cxio_hal.h"
+#include "cxgb3_offload.h"
+#include "sge_defs.h"
+
+static LIST_HEAD(rdev_list);
+static cxio_hal_ev_callback_func_t cxio_ev_cb = NULL;
+
+static inline struct cxio_rdev *cxio_hal_find_rdev_by_name(char *dev_name)
+{
+ struct cxio_rdev *rdev;
+
+ list_for_each_entry(rdev, &rdev_list, entry)
+ if (!strcmp(rdev->dev_name, dev_name))
+ return rdev;
+ return NULL;
+}
+
+static inline struct cxio_rdev *cxio_hal_find_rdev_by_t3cdev(struct t3cdev
+ *tdev)
+{
+ struct cxio_rdev *rdev;
+
+ list_for_each_entry(rdev, &rdev_list, entry)
+ if (rdev->t3cdev_p == tdev)
+ return rdev;
+ return NULL;
+}
+
+int cxio_hal_cq_op(struct cxio_rdev *rdev_p, struct t3_cq *cq,
+ enum t3_cq_opcode op, u32 credit)
+{
+ int ret;
+ struct t3_cqe *cqe;
+ u32 rptr;
+
+ struct rdma_cq_op setup;
+ setup.id = cq->cqid;
+ setup.credits = (op == CQ_CREDIT_UPDATE) ? credit : 0;
+ setup.op = op;
+ ret = rdev_p->t3cdev_p->ctl(rdev_p->t3cdev_p, RDMA_CQ_OP, &setup);
+
+ if ((ret < 0) || (op == CQ_CREDIT_UPDATE))
+ return ret;
+
+ /*
+ * If the rearm returned an index other than our current index,
+ * then there might be CQE's in flight (being DMA'd). We must wait
+ * here for them to complete or the consumer can miss a notification.
+ */
+ if (Q_PTR2IDX((cq->rptr), cq->size_log2) != ret) {
+ int i=0;
+
+ rptr = cq->rptr;
+
+ /*
+ * Keep the generation correct by bumping rptr until it
+ * matches the index returned by the rearm - 1.
+ */
+ while (Q_PTR2IDX((rptr+1), cq->size_log2) != ret)
+ rptr++;
+
+ /*
+ * Now rptr is the index for the (last) cqe that was
+ * in-flight at the time the HW rearmed the CQ. We
+ * spin until that CQE is valid.
+ */
+ cqe = cq->queue + Q_PTR2IDX(rptr, cq->size_log2);
+ 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;
+ }
+ }
+ }
+ return 0;
+}
+
+static inline int cxio_hal_clear_cq_ctx(struct cxio_rdev *rdev_p, u32 cqid)
+{
+ struct rdma_cq_setup setup;
+ setup.id = cqid;
+ setup.base_addr = 0; /* NULL address */
+ setup.size = 0; /* disaable the CQ */
+ setup.credits = 0;
+ setup.credit_thres = 0;
+ setup.ovfl_mode = 0;
+ return (rdev_p->t3cdev_p->ctl(rdev_p->t3cdev_p, RDMA_CQ_SETUP, &setup));
+}
+
+int cxio_hal_clear_qp_ctx(struct cxio_rdev *rdev_p, u32 qpid)
+{
+ u64 sge_cmd;
+ struct t3_modify_qp_wr *wqe;
+ struct sk_buff *skb = alloc_skb(sizeof(*wqe), GFP_KERNEL);
+ if (!skb) {
+ PDBG("%s alloc_skb failed\n", __FUNCTION__);
+ return -ENOMEM;
+ }
+ wqe = (struct t3_modify_qp_wr *) skb_put(skb, sizeof(*wqe));
+ memset(wqe, 0, sizeof(*wqe));
+ build_fw_riwrh((struct fw_riwrh *) wqe, T3_WR_QP_MOD, 3, 1, qpid, 7);
+ wqe->flags = cpu_to_be32(MODQP_WRITE_EC);
+ sge_cmd = qpid << 8 | 3;
+ wqe->sge_cmd = cpu_to_be64(sge_cmd);
+ skb->priority = CPL_PRIORITY_CONTROL;
+ return (cxgb3_ofld_send(rdev_p->t3cdev_p, skb));
+}
+
+int cxio_create_cq(struct cxio_rdev *rdev_p, struct t3_cq *cq)
+{
+ struct rdma_cq_setup setup;
+ int size = (1UL << (cq->size_log2)) * sizeof(struct t3_cqe);
+
+ 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),
+ &(cq->dma_addr), GFP_KERNEL);
+ if (!cq->queue) {
+ kfree(cq->sw_queue);
+ return -ENOMEM;
+ }
+ pci_unmap_addr_set(cq, mapping, cq->dma_addr);
+ memset(cq->queue, 0, size);
+ setup.id = cq->cqid;
+ setup.base_addr = (u64) (cq->dma_addr);
+ setup.size = 1UL << cq->size_log2;
+ setup.credits = 65535;
+ setup.credit_thres = 1;
+ if (rdev_p->t3cdev_p->type == T3B)
+ setup.ovfl_mode = 0;
+ else
+ setup.ovfl_mode = 1;
+ return (rdev_p->t3cdev_p->ctl(rdev_p->t3cdev_p, RDMA_CQ_SETUP, &setup));
+}
+
+int cxio_resize_cq(struct cxio_rdev *rdev_p, struct t3_cq *cq)
+{
+ struct rdma_cq_setup setup;
+ setup.id = cq->cqid;
+ setup.base_addr = (u64) (cq->dma_addr);
+ setup.size = 1UL << cq->size_log2;
+ setup.credits = setup.size;
+ setup.credit_thres = setup.size; /* TBD: overflow recovery */
+ setup.ovfl_mode = 1;
+ return (rdev_p->t3cdev_p->ctl(rdev_p->t3cdev_p, RDMA_CQ_SETUP, &setup));
+}
+
+static u32 get_qpid(struct cxio_rdev *rdev_p, struct cxio_ucontext *uctx)
+{
+ struct cxio_qpid_list *entry;
+ u32 qpid;
+ int i;
+
+ mutex_lock(&uctx->lock);
+ if (!list_empty(&uctx->qpids)) {
+ entry = list_entry(uctx->qpids.next, struct cxio_qpid_list,
+ entry);
+ list_del(&entry->entry);
+ qpid = entry->qpid;
+ kfree(entry);
+ } else {
+ qpid = cxio_hal_get_qpid(rdev_p->rscp);
+ if (!qpid)
+ goto out;
+ for (i = qpid+1; i & rdev_p->qpmask; i++) {
+ entry = kmalloc(sizeof *entry, GFP_KERNEL);
+ if (!entry)
+ break;
+ entry->qpid = i;
+ list_add_tail(&entry->entry, &uctx->qpids);
+ }
+ }
+out:
+ mutex_unlock(&uctx->lock);
+ PDBG("%s qpid 0x%x\n", __FUNCTION__, qpid);
+ return qpid;
+}
+
+static void put_qpid(struct cxio_rdev *rdev_p, u32 qpid,
+ struct cxio_ucontext *uctx)
+{
+ struct cxio_qpid_list *entry;
+
+ entry = kmalloc(sizeof *entry, GFP_KERNEL);
+ if (!entry)
+ return;
+ PDBG("%s qpid 0x%x\n", __FUNCTION__, qpid);
+ entry->qpid = qpid;
+ mutex_lock(&uctx->lock);
+ list_add_tail(&entry->entry, &uctx->qpids);
+ mutex_unlock(&uctx->lock);
+}
+
+void cxio_release_ucontext(struct cxio_rdev *rdev_p, struct cxio_ucontext *uctx)
+{
+ struct list_head *pos, *nxt;
+ struct cxio_qpid_list *entry;
+
+ mutex_lock(&uctx->lock);
+ list_for_each_safe(pos, nxt, &uctx->qpids) {
+ entry = list_entry(pos, struct cxio_qpid_list, entry);
+ list_del_init(&entry->entry);
+ if (!(entry->qpid & rdev_p->qpmask))
+ cxio_hal_put_qpid(rdev_p->rscp, entry->qpid);
+ kfree(entry);
+ }
+ mutex_unlock(&uctx->lock);
+}
+
+void cxio_init_ucontext(struct cxio_rdev *rdev_p, struct cxio_ucontext *uctx)
+{
+ INIT_LIST_HEAD(&uctx->qpids);
+ mutex_init(&uctx->lock);
+}
+
+int cxio_create_qp(struct cxio_rdev *rdev_p, u32 kernel_domain,
+ struct t3_wq *wq, struct cxio_ucontext *uctx)
+{
+ int depth = 1UL << wq->size_log2;
+ int rqsize = 1UL << wq->rq_size_log2;
+
+ wq->qpid = get_qpid(rdev_p, uctx);
+ if (!wq->qpid)
+ return -ENOMEM;
+
+ wq->rq = kzalloc(depth * sizeof(u64), GFP_KERNEL);
+ if (!wq->rq)
+ goto err1;
+
+ wq->rq_addr = cxio_hal_rqtpool_alloc(rdev_p, rqsize);
+ if (!wq->rq_addr)
+ goto err2;
+
+ wq->sq = kzalloc(depth * sizeof(struct t3_swsq), GFP_KERNEL);
+ if (!wq->sq)
+ goto err3;
+
+ wq->queue = dma_alloc_coherent(&(rdev_p->rnic_info.pdev->dev),
+ depth * sizeof(union t3_wr),
+ &(wq->dma_addr), GFP_KERNEL);
+ if (!wq->queue)
+ goto err4;
+
+ memset(wq->queue, 0, depth * sizeof(union t3_wr));
+ pci_unmap_addr_set(wq, mapping, wq->dma_addr);
+ wq->doorbell = (void __iomem *)rdev_p->rnic_info.kdb_addr;
+ if (!kernel_domain)
+ wq->udb = (u64)rdev_p->rnic_info.udbell_physbase +
+ (wq->qpid << rdev_p->qpshift);
+ PDBG("%s qpid 0x%x doorbell 0x%p udb 0x%llx\n", __FUNCTION__,
+ wq->qpid, wq->doorbell, (unsigned long long) wq->udb);
+ return 0;
+err4:
+ kfree(wq->sq);
+err3:
+ cxio_hal_rqtpool_free(rdev_p, wq->rq_addr, rqsize);
+err2:
+ kfree(wq->rq);
+err1:
+ put_qpid(rdev_p, wq->qpid, uctx);
+ return -ENOMEM;
+}
+
+int cxio_destroy_cq(struct cxio_rdev *rdev_p, struct t3_cq *cq)
+{
+ int err;
+ err = cxio_hal_clear_cq_ctx(rdev_p, cq->cqid);
+ kfree(cq->sw_queue);
+ dma_free_coherent(&(rdev_p->rnic_info.pdev->dev),
+ (1UL << (cq->size_log2))
+ * sizeof(struct t3_cqe), cq->queue,
+ pci_unmap_addr(cq, mapping));
+ cxio_hal_put_cqid(rdev_p->rscp, cq->cqid);
+ return err;
+}
+
+int cxio_destroy_qp(struct cxio_rdev *rdev_p, struct t3_wq *wq,
+ struct cxio_ucontext *uctx)
+{
+ dma_free_coherent(&(rdev_p->rnic_info.pdev->dev),
+ (1UL << (wq->size_log2))
+ * sizeof(union t3_wr), wq->queue,
+ pci_unmap_addr(wq, mapping));
+ kfree(wq->sq);
+ cxio_hal_rqtpool_free(rdev_p, wq->rq_addr, (1UL << wq->rq_size_log2));
+ kfree(wq->rq);
+ put_qpid(rdev_p, wq->qpid, uctx);
+ return 0;
+}
+
+static void insert_recv_cqe(struct t3_wq *wq, struct t3_cq *cq)
+{
+ struct t3_cqe cqe;
+
+ PDBG("%s wq %p cq %p sw_rptr 0x%x sw_wptr 0x%x\n", __FUNCTION__,
+ wq, cq, cq->sw_rptr, cq->sw_wptr);
+ memset(&cqe, 0, sizeof(cqe));
+ cqe.header = cpu_to_be32(V_CQE_STATUS(TPT_ERR_SWFLUSH) |
+ V_CQE_OPCODE(T3_SEND) |
+ V_CQE_TYPE(0) |
+ V_CQE_SWCQE(1) |
+ V_CQE_QPID(wq->qpid) |
+ V_CQE_GENBIT(Q_GENBIT(cq->sw_wptr,
+ cq->size_log2)));
+ *(cq->sw_queue + Q_PTR2IDX(cq->sw_wptr, cq->size_log2)) = cqe;
+ cq->sw_wptr++;
+}
+
+void cxio_flush_rq(struct t3_wq *wq, struct t3_cq *cq, int count)
+{
+ u32 ptr;
+
+ PDBG("%s wq %p cq %p\n", __FUNCTION__, wq, cq);
+
+ /* flush RQ */
+ PDBG("%s rq_rptr %u rq_wptr %u skip count %u\n", __FUNCTION__,
+ wq->rq_rptr, wq->rq_wptr, count);
+ ptr = wq->rq_rptr + count;
+ while (ptr++ != wq->rq_wptr)
+ insert_recv_cqe(wq, cq);
+}
+
+static void insert_sq_cqe(struct t3_wq *wq, struct t3_cq *cq,
+ struct t3_swsq *sqp)
+{
+ struct t3_cqe cqe;
+
+ PDBG("%s wq %p cq %p sw_rptr 0x%x sw_wptr 0x%x\n", __FUNCTION__,
+ wq, cq, cq->sw_rptr, cq->sw_wptr);
+ memset(&cqe, 0, sizeof(cqe));
+ cqe.header = cpu_to_be32(V_CQE_STATUS(TPT_ERR_SWFLUSH) |
+ V_CQE_OPCODE(sqp->opcode) |
+ V_CQE_TYPE(1) |
+ V_CQE_SWCQE(1) |
+ V_CQE_QPID(wq->qpid) |
+ V_CQE_GENBIT(Q_GENBIT(cq->sw_wptr,
+ cq->size_log2)));
+ cqe.u.scqe.wrid_hi = sqp->sq_wptr;
+
+ *(cq->sw_queue + Q_PTR2IDX(cq->sw_wptr, cq->size_log2)) = cqe;
+ cq->sw_wptr++;
+}
+
+void cxio_flush_sq(struct t3_wq *wq, struct t3_cq *cq, int count)
+{
+ __u32 ptr;
+ struct t3_swsq *sqp = wq->sq + Q_PTR2IDX(wq->sq_rptr, wq->sq_size_log2);
+
+ ptr = wq->sq_rptr + count;
+ sqp += count;
+ while (ptr != wq->sq_wptr) {
+ insert_sq_cqe(wq, cq, sqp);
+ sqp++;
+ ptr++;
+ }
+}
+
+/*
+ * Move all CQEs from the HWCQ into the SWCQ.
+ */
+void cxio_flush_hw_cq(struct t3_cq *cq)
+{
+ struct t3_cqe *cqe, *swcqe;
+
+ PDBG("%s cq %p cqid 0x%x\n", __FUNCTION__, cq, cq->cqid);
+ cqe = cxio_next_hw_cqe(cq);
+ while (cqe) {
+ PDBG("%s flushing hwcq rptr 0x%x to swcq wptr 0x%x\n",
+ __FUNCTION__, cq->rptr, cq->sw_wptr);
+ swcqe = cq->sw_queue + Q_PTR2IDX(cq->sw_wptr, cq->size_log2);
+ *swcqe = *cqe;
+ swcqe->header |= cpu_to_be32(V_CQE_SWCQE(1));
+ cq->sw_wptr++;
+ cq->rptr++;
+ cqe = cxio_next_hw_cqe(cq);
+ }
+}
+
+static inline int cqe_completes_wr(struct t3_cqe *cqe, struct t3_wq *wq)
+{
+ if (CQE_OPCODE(*cqe) == T3_TERMINATE)
+ return 0;
+
+ if ((CQE_OPCODE(*cqe) == T3_RDMA_WRITE) && RQ_TYPE(*cqe))
+ return 0;
+
+ if ((CQE_OPCODE(*cqe) == T3_READ_RESP) && SQ_TYPE(*cqe))
+ return 0;
+
+ if ((CQE_OPCODE(*cqe) == T3_SEND) && RQ_TYPE(*cqe) &&
+ Q_EMPTY(wq->rq_rptr, wq->rq_wptr))
+ return 0;
+
+ return 1;
+}
+
+void cxio_count_scqes(struct t3_cq *cq, struct t3_wq *wq, int *count)
+{
+ struct t3_cqe *cqe;
+ u32 ptr;
+
+ *count = 0;
+ ptr = cq->sw_rptr;
+ while (!Q_EMPTY(ptr, cq->sw_wptr)) {
+ cqe = cq->sw_queue + (Q_PTR2IDX(ptr, cq->size_log2));
+ if ((SQ_TYPE(*cqe) || (CQE_OPCODE(*cqe) == T3_READ_RESP)) &&
+ (CQE_QPID(*cqe) == wq->qpid))
+ (*count)++;
+ ptr++;
+ }
+ PDBG("%s cq %p count %d\n", __FUNCTION__, cq, *count);
+}
+
+void cxio_count_rcqes(struct t3_cq *cq, struct t3_wq *wq, int *count)
+{
+ struct t3_cqe *cqe;
+ u32 ptr;
+
+ *count = 0;
+ PDBG("%s count zero %d\n", __FUNCTION__, *count);
+ ptr = cq->sw_rptr;
+ while (!Q_EMPTY(ptr, cq->sw_wptr)) {
+ cqe = cq->sw_queue + (Q_PTR2IDX(ptr, cq->size_log2));
+ if (RQ_TYPE(*cqe) && (CQE_OPCODE(*cqe) != T3_READ_RESP) &&
+ (CQE_QPID(*cqe) == wq->qpid) && cqe_completes_wr(cqe, wq))
+ (*count)++;
+ ptr++;
+ }
+ PDBG("%s cq %p count %d\n", __FUNCTION__, cq, *count);
+}
+
+static int cxio_hal_init_ctrl_cq(struct cxio_rdev *rdev_p)
+{
+ struct rdma_cq_setup setup;
+ setup.id = 0;
+ setup.base_addr = 0; /* NULL address */
+ setup.size = 1; /* enable the CQ */
+ setup.credits = 0;
+
+ /* force SGE to redirect to RspQ and interrupt */
+ setup.credit_thres = 0;
+ setup.ovfl_mode = 1;
+ return (rdev_p->t3cdev_p->ctl(rdev_p->t3cdev_p, RDMA_CQ_SETUP, &setup));
+}
+
+static int cxio_hal_init_ctrl_qp(struct cxio_rdev *rdev_p)
+{
+ int err;
+ u64 sge_cmd, ctx0, ctx1;
+ u64 base_addr;
+ struct t3_modify_qp_wr *wqe;
+ struct sk_buff *skb = alloc_skb(sizeof(*wqe), GFP_KERNEL);
+
+
+ if (!skb) {
+ PDBG("%s alloc_skb failed\n", __FUNCTION__);
+ return -ENOMEM;
+ }
+ err = cxio_hal_init_ctrl_cq(rdev_p);
+ if (err) {
+ PDBG("%s err %d initializing ctrl_cq\n", __FUNCTION__, err);
+ return err;
+ }
+ rdev_p->ctrl_qp.workq = dma_alloc_coherent(
+ &(rdev_p->rnic_info.pdev->dev),
+ (1 << T3_CTRL_QP_SIZE_LOG2) *
+ sizeof(union t3_wr),
+ &(rdev_p->ctrl_qp.dma_addr),
+ GFP_KERNEL);
+ if (!rdev_p->ctrl_qp.workq) {
+ PDBG("%s dma_alloc_coherent failed\n", __FUNCTION__);
+ return -ENOMEM;
+ }
+ pci_unmap_addr_set(&rdev_p->ctrl_qp, mapping,
+ rdev_p->ctrl_qp.dma_addr);
+ rdev_p->ctrl_qp.doorbell = (void __iomem *)rdev_p->rnic_info.kdb_addr;
+ memset(rdev_p->ctrl_qp.workq, 0,
+ (1 << T3_CTRL_QP_SIZE_LOG2) * sizeof(union t3_wr));
+
+ mutex_init(&rdev_p->ctrl_qp.lock);
+ init_waitqueue_head(&rdev_p->ctrl_qp.waitq);
+
+ /* update HW Ctrl QP context */
+ base_addr = rdev_p->ctrl_qp.dma_addr;
+ base_addr >>= 12;
+ ctx0 = (V_EC_SIZE((1 << T3_CTRL_QP_SIZE_LOG2)) |
+ V_EC_BASE_LO((u32) base_addr & 0xffff));
+ ctx0 <<= 32;
+ ctx0 |= V_EC_CREDITS(FW_WR_NUM);
+ base_addr >>= 16;
+ ctx1 = (u32) base_addr;
+ base_addr >>= 32;
+ ctx1 |= ((u64) (V_EC_BASE_HI((u32) base_addr & 0xf) | V_EC_RESPQ(0) |
+ V_EC_TYPE(0) | V_EC_GEN(1) |
+ V_EC_UP_TOKEN(T3_CTL_QP_TID) | F_EC_VALID)) << 32;
+ wqe = (struct t3_modify_qp_wr *) skb_put(skb, sizeof(*wqe));
+ memset(wqe, 0, sizeof(*wqe));
+ build_fw_riwrh((struct fw_riwrh *) wqe, T3_WR_QP_MOD, 0, 1,
+ T3_CTL_QP_TID, 7);
+ wqe->flags = cpu_to_be32(MODQP_WRITE_EC);
+ sge_cmd = (3ULL << 56) | FW_RI_SGEEC_START << 8 | 3;
+ wqe->sge_cmd = cpu_to_be64(sge_cmd);
+ wqe->ctx1 = cpu_to_be64(ctx1);
+ wqe->ctx0 = cpu_to_be64(ctx0);
+ PDBG("CtrlQP dma_addr 0x%llx workq %p size %d\n",
+ (unsigned long long) rdev_p->ctrl_qp.dma_addr,
+ rdev_p->ctrl_qp.workq, 1 << T3_CTRL_QP_SIZE_LOG2);
+ skb->priority = CPL_PRIORITY_CONTROL;
+ return (cxgb3_ofld_send(rdev_p->t3cdev_p, skb));
+}
+
+static int cxio_hal_destroy_ctrl_qp(struct cxio_rdev *rdev_p)
+{
+ dma_free_coherent(&(rdev_p->rnic_info.pdev->dev),
+ (1UL << T3_CTRL_QP_SIZE_LOG2)
+ * sizeof(union t3_wr), rdev_p->ctrl_qp.workq,
+ pci_unmap_addr(&rdev_p->ctrl_qp, mapping));
+ return cxio_hal_clear_qp_ctx(rdev_p, T3_CTRL_QP_ID);
+}
+
+/* write len bytes of data into addr (32B aligned address)
+ * If data is NULL, clear len byte of memory to zero.
+ * caller aquires the ctrl_qp lock before the call
+ */
+static int cxio_hal_ctrl_qp_write_mem(struct cxio_rdev *rdev_p, u32 addr,
+ u32 len, void *data, int completion)
+{
+ u32 i, nr_wqe, copy_len;
+ u8 *copy_data;
+ u8 wr_len, utx_len; /* lenght in 8 byte flit */
+ enum t3_wr_flags flag;
+ __be64 *wqe;
+ u64 utx_cmd;
+ addr &= 0x7FFFFFF;
+ nr_wqe = len % 96 ? len / 96 + 1 : len / 96; /* 96B max per WQE */
+ PDBG("%s wptr 0x%x rptr 0x%x len %d, nr_wqe %d data %p addr 0x%0x\n",
+ __FUNCTION__, rdev_p->ctrl_qp.wptr, rdev_p->ctrl_qp.rptr, len,
+ nr_wqe, data, addr);
+ utx_len = 3; /* in 32B unit */
+ for (i = 0; i < nr_wqe; i++) {
+ if (Q_FULL(rdev_p->ctrl_qp.rptr, rdev_p->ctrl_qp.wptr,
+ T3_CTRL_QP_SIZE_LOG2)) {
+ PDBG("%s ctrl_qp full wtpr 0x%0x rptr 0x%0x, "
+ "wait for more space i %d\n", __FUNCTION__,
+ rdev_p->ctrl_qp.wptr, rdev_p->ctrl_qp.rptr, i);
+ if (wait_event_interruptible(rdev_p->ctrl_qp.waitq,
+ !Q_FULL(rdev_p->ctrl_qp.rptr,
+ rdev_p->ctrl_qp.wptr,
+ T3_CTRL_QP_SIZE_LOG2))) {
+ PDBG("%s ctrl_qp workq interrupted\n",
+ __FUNCTION__);
+ return -ERESTARTSYS;
+ }
+ PDBG("%s ctrl_qp wakeup, continue posting work request "
+ "i %d\n", __FUNCTION__, i);
+ }
+ wqe = (__be64 *)(rdev_p->ctrl_qp.workq + (rdev_p->ctrl_qp.wptr %
+ (1 << T3_CTRL_QP_SIZE_LOG2)));
+ flag = 0;
+ if (i == (nr_wqe - 1)) {
+ /* last WQE */
+ flag = completion ? T3_COMPLETION_FLAG : 0;
+ if (len % 32)
+ utx_len = len / 32 + 1;
+ else
+ utx_len = len / 32;
+ }
+
+ /*
+ * Force a CQE to return the credit to the workq in case
+ * we posted more than half the max QP size of WRs
+ */
+ if ((i != 0) &&
+ (i % (((1 << T3_CTRL_QP_SIZE_LOG2)) >> 1) == 0)) {
+ flag = T3_COMPLETION_FLAG;
+ PDBG("%s force completion at i %d\n", __FUNCTION__, i);
+ }
+
+ /* build the utx mem command */
+ wqe += (sizeof(struct t3_bypass_wr) >> 3);
+ utx_cmd = (T3_UTX_MEM_WRITE << 28) | (addr + i * 3);
+ utx_cmd <<= 32;
+ utx_cmd |= (utx_len << 28) | ((utx_len << 2) + 1);
+ *wqe = cpu_to_be64(utx_cmd);
+ wqe++;
+ copy_data = (u8 *) data + i * 96;
+ copy_len = len > 96 ? 96 : len;
+
+ /* clear memory content if data is NULL */
+ if (data)
+ memcpy(wqe, copy_data, copy_len);
+ else
+ memset(wqe, 0, copy_len);
+ if (copy_len % 32)
+ memset(((u8 *) wqe) + copy_len, 0,
+ 32 - (copy_len % 32));
+ wr_len = ((sizeof(struct t3_bypass_wr)) >> 3) + 1 +
+ (utx_len << 2);
+ wqe = (__be64 *)(rdev_p->ctrl_qp.workq + (rdev_p->ctrl_qp.wptr %
+ (1 << T3_CTRL_QP_SIZE_LOG2)));
+
+ /* wptr in the WRID[31:0] */
+ ((union t3_wrid *)(wqe+1))->id0.low = rdev_p->ctrl_qp.wptr;
+
+ /*
+ * This must be the last write with a memory barrier
+ * for the genbit
+ */
+ build_fw_riwrh((struct fw_riwrh *) wqe, T3_WR_BP, flag,
+ Q_GENBIT(rdev_p->ctrl_qp.wptr,
+ T3_CTRL_QP_SIZE_LOG2), T3_CTRL_QP_ID,
+ wr_len);
+ if (flag == T3_COMPLETION_FLAG)
+ ring_doorbell(rdev_p->ctrl_qp.doorbell, T3_CTRL_QP_ID);
+ len -= 96;
+ rdev_p->ctrl_qp.wptr++;
+ }
+ return 0;
+}
+
+/* IN: stag key, pdid, perm, zbva, to, len, page_size, pbl, and pbl_size
+ * OUT: stag index, actual pbl_size, pbl_addr allocated.
+ * TBD: shared memory region support
+ */
+static int __cxio_tpt_op(struct cxio_rdev *rdev_p, u32 reset_tpt_entry,
+ u32 *stag, u8 stag_state, u32 pdid,
+ enum tpt_mem_type type, enum tpt_mem_perm perm,
+ u32 zbva, u64 to, u32 len, u8 page_size, __be64 *pbl,
+ u32 *pbl_size, u32 *pbl_addr)
+{
+ int err;
+ struct tpt_entry tpt;
+ u32 stag_idx;
+ u32 wptr;
+ int rereg = (*stag != T3_STAG_UNSET);
+
+ stag_state = stag_state > 0;
+ stag_idx = (*stag) >> 8;
+
+ if ((!reset_tpt_entry) && !(*stag != T3_STAG_UNSET)) {
+ stag_idx = cxio_hal_get_stag(rdev_p->rscp);
+ if (!stag_idx)
+ return -ENOMEM;
+ *stag = (stag_idx << 8) | ((*stag) & 0xFF);
+ }
+ PDBG("%s stag_state 0x%0x type 0x%0x pdid 0x%0x, stag_idx 0x%x\n",
+ __FUNCTION__, stag_state, type, pdid, stag_idx);
+
+ if (reset_tpt_entry)
+ cxio_hal_pblpool_free(rdev_p, *pbl_addr, *pbl_size << 3);
+ else if (!rereg) {
+ *pbl_addr = cxio_hal_pblpool_alloc(rdev_p, *pbl_size << 3);
+ if (!*pbl_addr) {
+ return -ENOMEM;
+ }
+ }
+
+ mutex_lock(&rdev_p->ctrl_qp.lock);
+
+ /* write PBL first if any - update pbl only if pbl list exist */
+ if (pbl) {
+
+ PDBG("%s *pdb_addr 0x%x, pbl_base 0x%x, pbl_size %d\n",
+ __FUNCTION__, *pbl_addr, rdev_p->rnic_info.pbl_base,
+ *pbl_size);
+ err = cxio_hal_ctrl_qp_write_mem(rdev_p,
+ (*pbl_addr >> 5),
+ (*pbl_size << 3), pbl, 0);
+ if (err)
+ goto ret;
+ }
+
+ /* write TPT entry */
+ if (reset_tpt_entry)
+ memset(&tpt, 0, sizeof(tpt));
+ else {
+ tpt.valid_stag_pdid = cpu_to_be32(F_TPT_VALID |
+ V_TPT_STAG_KEY((*stag) & M_TPT_STAG_KEY) |
+ V_TPT_STAG_STATE(stag_state) |
+ V_TPT_STAG_TYPE(type) | V_TPT_PDID(pdid));
+ BUG_ON(page_size >= 28);
+ tpt.flags_pagesize_qpid = cpu_to_be32(V_TPT_PERM(perm) |
+ F_TPT_MW_BIND_ENABLE |
+ V_TPT_ADDR_TYPE((zbva ? TPT_ZBTO : TPT_VATO)) |
+ V_TPT_PAGE_SIZE(page_size));
+ tpt.rsvd_pbl_addr = reset_tpt_entry ? 0 :
+ cpu_to_be32(V_TPT_PBL_ADDR(PBL_OFF(rdev_p, *pbl_addr)>>3));
+ tpt.len = cpu_to_be32(len);
+ tpt.va_hi = cpu_to_be32((u32) (to >> 32));
+ tpt.va_low_or_fbo = cpu_to_be32((u32) (to & 0xFFFFFFFFULL));
+ tpt.rsvd_bind_cnt_or_pstag = 0;
+ tpt.rsvd_pbl_size = reset_tpt_entry ? 0 :
+ cpu_to_be32(V_TPT_PBL_SIZE((*pbl_size) >> 2));
+ }
+ err = cxio_hal_ctrl_qp_write_mem(rdev_p,
+ stag_idx +
+ (rdev_p->rnic_info.tpt_base >> 5),
+ sizeof(tpt), &tpt, 1);
+
+ /* release the stag index to free pool */
+ if (reset_tpt_entry)
+ cxio_hal_put_stag(rdev_p->rscp, stag_idx);
+ret:
+ wptr = rdev_p->ctrl_qp.wptr;
+ mutex_unlock(&rdev_p->ctrl_qp.lock);
+ if (!err)
+ if (wait_event_interruptible(rdev_p->ctrl_qp.waitq,
+ SEQ32_GE(rdev_p->ctrl_qp.rptr,
+ wptr)))
+ return -ERESTARTSYS;
+ return err;
+}
+
+/* IN : stag key, pdid, pbl_size
+ * Out: stag index, actaul pbl_size, and pbl_addr allocated.
+ */
+int cxio_allocate_stag(struct cxio_rdev *rdev_p, u32 * stag, u32 pdid,
+ enum tpt_mem_perm perm, u32 * pbl_size, u32 * pbl_addr)
+{
+ *stag = T3_STAG_UNSET;
+ return (__cxio_tpt_op(rdev_p, 0, stag, 0, pdid, TPT_NON_SHARED_MR,
+ perm, 0, 0ULL, 0, 0, NULL, pbl_size, pbl_addr));
+}
+
+int cxio_register_phys_mem(struct cxio_rdev *rdev_p, u32 *stag, u32 pdid,
+ enum tpt_mem_perm perm, u32 zbva, u64 to, u32 len,
+ u8 page_size, __be64 *pbl, u32 *pbl_size,
+ u32 *pbl_addr)
+{
+ *stag = T3_STAG_UNSET;
+ return __cxio_tpt_op(rdev_p, 0, stag, 1, pdid, TPT_NON_SHARED_MR, perm,
+ zbva, to, len, page_size, pbl, pbl_size, pbl_addr);
+}
+
+int cxio_reregister_phys_mem(struct cxio_rdev *rdev_p, u32 *stag, u32 pdid,
+ enum tpt_mem_perm perm, u32 zbva, u64 to, u32 len,
+ u8 page_size, __be64 *pbl, u32 *pbl_size,
+ u32 *pbl_addr)
+{
+ return __cxio_tpt_op(rdev_p, 0, stag, 1, pdid, TPT_NON_SHARED_MR, perm,
+ zbva, to, len, page_size, pbl, pbl_size, pbl_addr);
+}
+
+int cxio_dereg_mem(struct cxio_rdev *rdev_p, u32 stag, u32 pbl_size,
+ u32 pbl_addr)
+{
+ return __cxio_tpt_op(rdev_p, 1, &stag, 0, 0, 0, 0, 0, 0ULL, 0, 0, NULL,
+ &pbl_size, &pbl_addr);
+}
+
+int cxio_allocate_window(struct cxio_rdev *rdev_p, u32 * stag, u32 pdid)
+{
+ u32 pbl_size = 0;
+ *stag = T3_STAG_UNSET;
+ return __cxio_tpt_op(rdev_p, 0, stag, 0, pdid, TPT_MW, 0, 0, 0ULL, 0, 0,
+ NULL, &pbl_size, NULL);
+}
+
+int cxio_deallocate_window(struct cxio_rdev *rdev_p, u32 stag)
+{
+ return __cxio_tpt_op(rdev_p, 1, &stag, 0, 0, 0, 0, 0, 0ULL, 0, 0, NULL,
+ NULL, NULL);
+}
+
+int cxio_rdma_init(struct cxio_rdev *rdev_p, struct t3_rdma_init_attr *attr)
+{
+ struct t3_rdma_init_wr *wqe;
+ struct sk_buff *skb = alloc_skb(sizeof(*wqe), GFP_ATOMIC);
+ if (!skb)
+ return -ENOMEM;
+ PDBG("%s rdev_p %p\n", __FUNCTION__, rdev_p);
+ wqe = (struct t3_rdma_init_wr *) __skb_put(skb, sizeof(*wqe));
+ wqe->wrh.op_seop_flags = cpu_to_be32(V_FW_RIWR_OP(T3_WR_INIT));
+ wqe->wrh.gen_tid_len = cpu_to_be32(V_FW_RIWR_TID(attr->tid) |
+ V_FW_RIWR_LEN(sizeof(*wqe) >> 3));
+ wqe->wrid.id1 = 0;
+ wqe->qpid = cpu_to_be32(attr->qpid);
+ wqe->pdid = cpu_to_be32(attr->pdid);
+ wqe->scqid = cpu_to_be32(attr->scqid);
+ wqe->rcqid = cpu_to_be32(attr->rcqid);
+ wqe->rq_addr = cpu_to_be32(attr->rq_addr - rdev_p->rnic_info.rqt_base);
+ wqe->rq_size = cpu_to_be32(attr->rq_size);
+ wqe->mpaattrs = attr->mpaattrs;
+ wqe->qpcaps = attr->qpcaps;
+ wqe->ulpdu_size = cpu_to_be16(attr->tcp_emss);
+ wqe->flags = cpu_to_be32(attr->flags);
+ wqe->ord = cpu_to_be32(attr->ord);
+ wqe->ird = cpu_to_be32(attr->ird);
+ wqe->qp_dma_addr = cpu_to_be64(attr->qp_dma_addr);
+ wqe->qp_dma_size = cpu_to_be32(attr->qp_dma_size);
+ wqe->rsvd = 0;
+ skb->priority = 0; /* 0=>ToeQ; 1=>CtrlQ */
+ return (cxgb3_ofld_send(rdev_p->t3cdev_p, skb));
+}
+
+void cxio_register_ev_cb(cxio_hal_ev_callback_func_t ev_cb)
+{
+ cxio_ev_cb = ev_cb;
+}
+
+void cxio_unregister_ev_cb(cxio_hal_ev_callback_func_t ev_cb)
+{
+ cxio_ev_cb = NULL;
+}
+
+static int cxio_hal_ev_handler(struct t3cdev *t3cdev_p, struct sk_buff *skb)
+{
+ static int cnt;
+ struct cxio_rdev *rdev_p = NULL;
+ struct respQ_msg_t *rsp_msg = (struct respQ_msg_t *) skb->data;
+ PDBG("%d: %s cq_id 0x%x cq_ptr 0x%x genbit %0x overflow %0x an %0x"
+ " se %0x notify %0x cqbranch %0x creditth %0x\n",
+ cnt, __FUNCTION__, RSPQ_CQID(rsp_msg), RSPQ_CQPTR(rsp_msg),
+ RSPQ_GENBIT(rsp_msg), RSPQ_OVERFLOW(rsp_msg), RSPQ_AN(rsp_msg),
+ RSPQ_SE(rsp_msg), RSPQ_NOTIFY(rsp_msg), RSPQ_CQBRANCH(rsp_msg),
+ RSPQ_CREDIT_THRESH(rsp_msg));
+ PDBG("CQE: QPID 0x%0x genbit %0x type 0x%0x status 0x%0x opcode %d "
+ "len 0x%0x wrid_hi_stag 0x%x wrid_low_msn 0x%x\n",
+ CQE_QPID(rsp_msg->cqe), CQE_GENBIT(rsp_msg->cqe),
+ CQE_TYPE(rsp_msg->cqe), CQE_STATUS(rsp_msg->cqe),
+ CQE_OPCODE(rsp_msg->cqe), CQE_LEN(rsp_msg->cqe),
+ CQE_WRID_HI(rsp_msg->cqe), CQE_WRID_LOW(rsp_msg->cqe));
+ rdev_p = (struct cxio_rdev *)t3cdev_p->ulp;
+ if (!rdev_p) {
+ PDBG("%s called by t3cdev %p with null ulp\n", __FUNCTION__,
+ t3cdev_p);
+ return 0;
+ }
+ if (CQE_QPID(rsp_msg->cqe) == T3_CTRL_QP_ID) {
+ rdev_p->ctrl_qp.rptr = CQE_WRID_LOW(rsp_msg->cqe) + 1;
+ wake_up_interruptible(&rdev_p->ctrl_qp.waitq);
+ dev_kfree_skb_irq(skb);
+ } else if (CQE_QPID(rsp_msg->cqe) == 0xfff8)
+ dev_kfree_skb_irq(skb);
+ else if (cxio_ev_cb)
+ (*cxio_ev_cb) (rdev_p, skb);
+ else
+ dev_kfree_skb_irq(skb);
+ cnt++;
+ return 0;
+}
+
+/* Caller takes care of locking if needed */
+int cxio_rdev_open(struct cxio_rdev *rdev_p)
+{
+ struct net_device *netdev_p = NULL;
+ int err = 0;
+ if (strlen(rdev_p->dev_name)) {
+ if (cxio_hal_find_rdev_by_name(rdev_p->dev_name)) {
+ return -EBUSY;
+ }
+ netdev_p = dev_get_by_name(rdev_p->dev_name);
+ if (!netdev_p) {
+ return -EINVAL;
+ }
+ dev_put(netdev_p);
+ } else if (rdev_p->t3cdev_p) {
+ if (cxio_hal_find_rdev_by_t3cdev(rdev_p->t3cdev_p)) {
+ return -EBUSY;
+ }
+ netdev_p = rdev_p->t3cdev_p->lldev;
+ strncpy(rdev_p->dev_name, rdev_p->t3cdev_p->name,
+ T3_MAX_DEV_NAME_LEN);
+ } else {
+ PDBG("%s t3cdev_p or dev_name must be set\n", __FUNCTION__);
+ return -EINVAL;
+ }
+
+ list_add_tail(&rdev_p->entry, &rdev_list);
+
+ PDBG("%s opening rnic dev %s\n", __FUNCTION__, rdev_p->dev_name);
+ memset(&rdev_p->ctrl_qp, 0, sizeof(rdev_p->ctrl_qp));
+ if (!rdev_p->t3cdev_p)
+ rdev_p->t3cdev_p = T3CDEV(netdev_p);
+ rdev_p->t3cdev_p->ulp = (void *) rdev_p;
+ err = rdev_p->t3cdev_p->ctl(rdev_p->t3cdev_p, RDMA_GET_PARAMS,
+ &(rdev_p->rnic_info));
+ if (err) {
+ printk(KERN_ERR "%s t3cdev_p(%p)->ctl returned error %d.\n",
+ __FUNCTION__, rdev_p->t3cdev_p, err);
+ goto err1;
+ }
+ err = rdev_p->t3cdev_p->ctl(rdev_p->t3cdev_p, GET_PORTS,
+ &(rdev_p->port_info));
+ if (err) {
+ printk(KERN_ERR "%s t3cdev_p(%p)->ctl returned error %d.\n",
+ __FUNCTION__, rdev_p->t3cdev_p, err);
+ goto err1;
+ }
+
+ /*
+ * qpshift is the number of bits to shift the qpid left in order
+ * to get the correct address of the doorbell for that qp.
+ */
+ cxio_init_ucontext(rdev_p, &rdev_p->uctx);
+ rdev_p->qpshift = PAGE_SHIFT -
+ ilog2(65536 >>
+ ilog2(rdev_p->rnic_info.udbell_len >>
+ PAGE_SHIFT));
+ rdev_p->qpnr = rdev_p->rnic_info.udbell_len >> PAGE_SHIFT;
+ rdev_p->qpmask = (65536 >> ilog2(rdev_p->qpnr)) - 1;
+ PDBG("%s rnic %s info: tpt_base 0x%0x tpt_top 0x%0x num stags %d "
+ "pbl_base 0x%0x pbl_top 0x%0x rqt_base 0x%0x, rqt_top 0x%0x\n",
+ __FUNCTION__, rdev_p->dev_name, rdev_p->rnic_info.tpt_base,
+ rdev_p->rnic_info.tpt_top, cxio_num_stags(rdev_p),
+ rdev_p->rnic_info.pbl_base,
+ rdev_p->rnic_info.pbl_top, rdev_p->rnic_info.rqt_base,
+ rdev_p->rnic_info.rqt_top);
+ PDBG("udbell_len 0x%0x udbell_physbase 0x%lx kdb_addr %p qpshift %lu "
+ "qpnr %d qpmask 0x%x\n",
+ rdev_p->rnic_info.udbell_len,
+ rdev_p->rnic_info.udbell_physbase, rdev_p->rnic_info.kdb_addr,
+ rdev_p->qpshift, rdev_p->qpnr, rdev_p->qpmask);
+
+ err = cxio_hal_init_ctrl_qp(rdev_p);
+ if (err) {
+ printk(KERN_ERR "%s error %d initializing ctrl_qp.\n",
+ __FUNCTION__, err);
+ goto err1;
+ }
+ err = cxio_hal_init_resource(rdev_p, cxio_num_stags(rdev_p), 0,
+ 0, T3_MAX_NUM_QP, T3_MAX_NUM_CQ,
+ T3_MAX_NUM_PD);
+ if (err) {
+ printk(KERN_ERR "%s error %d initializing hal resources.\n",
+ __FUNCTION__, err);
+ goto err2;
+ }
+ err = cxio_hal_pblpool_create(rdev_p);
+ if (err) {
+ printk(KERN_ERR "%s error %d initializing pbl mem pool.\n",
+ __FUNCTION__, err);
+ goto err3;
+ }
+ err = cxio_hal_rqtpool_create(rdev_p);
+ if (err) {
+ printk(KERN_ERR "%s error %d initializing rqt mem pool.\n",
+ __FUNCTION__, err);
+ goto err4;
+ }
+ return 0;
+err4:
+ cxio_hal_pblpool_destroy(rdev_p);
+err3:
+ cxio_hal_destroy_resource(rdev_p->rscp);
+err2:
+ cxio_hal_destroy_ctrl_qp(rdev_p);
+err1:
+ list_del(&rdev_p->entry);
+ return err;
+}
+
+void cxio_rdev_close(struct cxio_rdev *rdev_p)
+{
+ if (rdev_p) {
+ cxio_hal_pblpool_destroy(rdev_p);
+ cxio_hal_rqtpool_destroy(rdev_p);
+ list_del(&rdev_p->entry);
+ rdev_p->t3cdev_p->ulp = NULL;
+ cxio_hal_destroy_ctrl_qp(rdev_p);
+ cxio_hal_destroy_resource(rdev_p->rscp);
+ }
+}
+
+int __init cxio_hal_init(void)
+{
+ if (cxio_hal_init_rhdl_resource(T3_MAX_NUM_RI))
+ return -ENOMEM;
+ t3_register_cpl_handler(CPL_ASYNC_NOTIF, cxio_hal_ev_handler);
+ return 0;
+}
+
+void __exit cxio_hal_exit(void)
+{
+ struct cxio_rdev *rdev, *tmp;
+
+ t3_register_cpl_handler(CPL_ASYNC_NOTIF, NULL);
+ list_for_each_entry_safe(rdev, tmp, &rdev_list, entry)
+ cxio_rdev_close(rdev);
+ cxio_hal_destroy_rhdl_resource();
+}
+
+static inline void flush_completed_wrs(struct t3_wq *wq, struct t3_cq *cq)
+{
+ struct t3_swsq *sqp;
+ __u32 ptr = wq->sq_rptr;
+ int count = Q_COUNT(wq->sq_rptr, wq->sq_wptr);
+
+ sqp = wq->sq + Q_PTR2IDX(ptr, wq->sq_size_log2);
+ while (count--)
+ if (!sqp->signaled) {
+ ptr++;
+ sqp = wq->sq + Q_PTR2IDX(ptr, wq->sq_size_log2);
+ } else if (sqp->complete) {
+
+ /*
+ * Insert this completed cqe into the swcq.
+ */
+ PDBG("%s moving cqe into swcq sq idx %ld cq idx %ld\n",
+ __FUNCTION__, Q_PTR2IDX(ptr, wq->sq_size_log2),
+ Q_PTR2IDX(cq->sw_wptr, cq->size_log2));
+ sqp->cqe.header |= htonl(V_CQE_SWCQE(1));
+ *(cq->sw_queue + Q_PTR2IDX(cq->sw_wptr, cq->size_log2))
+ = sqp->cqe;
+ cq->sw_wptr++;
+ sqp->signaled = 0;
+ break;
+ } else
+ break;
+}
+
+static inline void create_read_req_cqe(struct t3_wq *wq,
+ struct t3_cqe *hw_cqe,
+ struct t3_cqe *read_cqe)
+{
+ read_cqe->u.scqe.wrid_hi = wq->oldest_read->sq_wptr;
+ read_cqe->len = wq->oldest_read->read_len;
+ read_cqe->header = htonl(V_CQE_QPID(CQE_QPID(*hw_cqe)) |
+ V_CQE_SWCQE(SW_CQE(*hw_cqe)) |
+ V_CQE_OPCODE(T3_READ_REQ) |
+ V_CQE_TYPE(1));
+}
+
+/*
+ * Return a ptr to the next read wr in the SWSQ or NULL.
+ */
+static inline void advance_oldest_read(struct t3_wq *wq)
+{
+
+ u32 rptr = wq->oldest_read - wq->sq + 1;
+ u32 wptr = Q_PTR2IDX(wq->sq_wptr, wq->sq_size_log2);
+
+ while (Q_PTR2IDX(rptr, wq->sq_size_log2) != wptr) {
+ wq->oldest_read = wq->sq + Q_PTR2IDX(rptr, wq->sq_size_log2);
+
+ if (wq->oldest_read->opcode == T3_READ_REQ)
+ return;
+ rptr++;
+ }
+ wq->oldest_read = NULL;
+}
+
+/*
+ * cxio_poll_cq
+ *
+ * Caller must:
+ * check the validity of the first CQE,
+ * supply the wq assicated with the qpid.
+ *
+ * credit: cq credit to return to sge.
+ * cqe_flushed: 1 iff the CQE is flushed.
+ * cqe: copy of the polled CQE.
+ *
+ * return value:
+ * 0 CQE returned,
+ * -1 CQE skipped, try again.
+ */
+int cxio_poll_cq(struct t3_wq *wq, struct t3_cq *cq, struct t3_cqe *cqe,
+ u8 *cqe_flushed, u64 *cookie, u32 *credit)
+{
+ int ret = 0;
+ struct t3_cqe *hw_cqe, read_cqe;
+
+ *cqe_flushed = 0;
+ *credit = 0;
+ hw_cqe = cxio_next_cqe(cq);
+
+ PDBG("%s CQE OOO %d qpid 0x%0x genbit %d type %d status 0x%0x"
+ " opcode 0x%0x len 0x%0x wrid_hi_stag 0x%x wrid_low_msn 0x%x\n",
+ __FUNCTION__, CQE_OOO(*hw_cqe), CQE_QPID(*hw_cqe),
+ CQE_GENBIT(*hw_cqe), CQE_TYPE(*hw_cqe), CQE_STATUS(*hw_cqe),
+ CQE_OPCODE(*hw_cqe), CQE_LEN(*hw_cqe), CQE_WRID_HI(*hw_cqe),
+ CQE_WRID_LOW(*hw_cqe));
+
+ /*
+ * skip cqe's not affiliated with a QP.
+ */
+ if (wq == NULL) {
+ ret = -1;
+ goto skip_cqe;
+ }
+
+ /*
+ * Gotta tweak READ completions:
+ * 1) the cqe doesn't contain the sq_wptr from the wr.
+ * 2) opcode not reflected from the wr.
+ * 3) read_len not reflected from the wr.
+ * 4) cq_type is RQ_TYPE not SQ_TYPE.
+ */
+ if (RQ_TYPE(*hw_cqe) && (CQE_OPCODE(*hw_cqe) == T3_READ_RESP)) {
+
+ /*
+ * Don't write to the HWCQ, so create a new read req CQE
+ * in local memory.
+ */
+ create_read_req_cqe(wq, hw_cqe, &read_cqe);
+ hw_cqe = &read_cqe;
+ advance_oldest_read(wq);
+ }
+
+ /*
+ * T3A: Discard TERMINATE CQEs.
+ */
+ if (CQE_OPCODE(*hw_cqe) == T3_TERMINATE) {
+ ret = -1;
+ wq->error = 1;
+ goto skip_cqe;
+ }
+
+ if (CQE_STATUS(*hw_cqe) || wq->error) {
+ *cqe_flushed = wq->error;
+ wq->error = 1;
+
+ /*
+ * T3A inserts errors into the CQE. We cannot return
+ * these as work completions.
+ */
+ /* incoming write failures */
+ if ((CQE_OPCODE(*hw_cqe) == T3_RDMA_WRITE)
+ && RQ_TYPE(*hw_cqe)) {
+ ret = -1;
+ goto skip_cqe;
+ }
+ /* incoming read request failures */
+ if ((CQE_OPCODE(*hw_cqe) == T3_READ_RESP) && SQ_TYPE(*hw_cqe)) {
+ ret = -1;
+ goto skip_cqe;
+ }
+
+ /* incoming SEND with no receive posted failures */
+ if ((CQE_OPCODE(*hw_cqe) == T3_SEND) && RQ_TYPE(*hw_cqe) &&
+ Q_EMPTY(wq->rq_rptr, wq->rq_wptr)) {
+ ret = -1;
+ goto skip_cqe;
+ }
+ goto proc_cqe;
+ }
+
+ /*
+ * RECV completion.
+ */
+ if (RQ_TYPE(*hw_cqe)) {
+
+ /*
+ * HW only validates 4 bits of MSN. So we must validate that
+ * the MSN in the SEND is the next expected MSN. If its not,
+ * then we complete this with TPT_ERR_MSN and mark the wq in
+ * error.
+ */
+ if (unlikely((CQE_WRID_MSN(*hw_cqe) != (wq->rq_rptr + 1)))) {
+ wq->error = 1;
+ hw_cqe->header |= htonl(V_CQE_STATUS(TPT_ERR_MSN));
+ goto proc_cqe;
+ }
+ goto proc_cqe;
+ }
+
+ /*
+ * If we get here its a send completion.
+ *
+ * Handle out of order completion. These get stuffed
+ * in the SW SQ. Then the SW SQ is walked to move any
+ * now in-order completions into the SW CQ. This handles
+ * 2 cases:
+ * 1) reaping unsignaled WRs when the first subsequent
+ * signaled WR is completed.
+ * 2) out of order read completions.
+ */
+ if (!SW_CQE(*hw_cqe) && (CQE_WRID_SQ_WPTR(*hw_cqe) != wq->sq_rptr)) {
+ struct t3_swsq *sqp;
+
+ PDBG("%s out of order completion going in swsq at idx %ld\n",
+ __FUNCTION__,
+ Q_PTR2IDX(CQE_WRID_SQ_WPTR(*hw_cqe), wq->sq_size_log2));
+ sqp = wq->sq +
+ Q_PTR2IDX(CQE_WRID_SQ_WPTR(*hw_cqe), wq->sq_size_log2);
+ sqp->cqe = *hw_cqe;
+ sqp->complete = 1;
+ ret = -1;
+ goto flush_wq;
+ }
+
+proc_cqe:
+ *cqe = *hw_cqe;
+
+ /*
+ * Reap the associated WR(s) that are freed up with this
+ * completion.
+ */
+ if (SQ_TYPE(*hw_cqe)) {
+ wq->sq_rptr = CQE_WRID_SQ_WPTR(*hw_cqe);
+ PDBG("%s completing sq idx %ld\n", __FUNCTION__,
+ Q_PTR2IDX(wq->sq_rptr, wq->sq_size_log2));
+ *cookie = (wq->sq +
+ Q_PTR2IDX(wq->sq_rptr, wq->sq_size_log2))->wr_id;
+ wq->sq_rptr++;
+ } else {
+ PDBG("%s completing rq idx %ld\n", __FUNCTION__,
+ Q_PTR2IDX(wq->rq_rptr, wq->rq_size_log2));
+ *cookie = *(wq->rq + Q_PTR2IDX(wq->rq_rptr, wq->rq_size_log2));
+ wq->rq_rptr++;
+ }
+
+flush_wq:
+ /*
+ * Flush any completed cqes that are now in-order.
+ */
+ flush_completed_wrs(wq, cq);
+
+skip_cqe:
+ if (SW_CQE(*hw_cqe)) {
+ PDBG("%s cq %p cqid 0x%x skip sw cqe sw_rptr 0x%x\n",
+ __FUNCTION__, cq, cq->cqid, cq->sw_rptr);
+ ++cq->sw_rptr;
+ } else {
+ PDBG("%s cq %p cqid 0x%x skip hw cqe rptr 0x%x\n",
+ __FUNCTION__, cq, cq->cqid, cq->rptr);
+ ++cq->rptr;
+
+ /*
+ * T3A: compute credits.
+ */
+ if (((cq->rptr - cq->wptr) > (1 << (cq->size_log2 - 1)))
+ || ((cq->rptr - cq->wptr) >= 128)) {
+ *credit = cq->rptr - cq->wptr;
+ cq->wptr = cq->rptr;
+ }
+ }
+ return ret;
+}
diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.h b/drivers/infiniband/hw/cxgb3/cxio_hal.h
new file mode 100644
index 00000000000..8ab04a7c6f6
--- /dev/null
+++ b/drivers/infiniband/hw/cxgb3/cxio_hal.h
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2006 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef __CXIO_HAL_H__
+#define __CXIO_HAL_H__
+
+#include <linux/list.h>
+#include <linux/mutex.h>
+
+#include "t3_cpl.h"
+#include "t3cdev.h"
+#include "cxgb3_ctl_defs.h"
+#include "cxio_wr.h"
+
+#define T3_CTRL_QP_ID FW_RI_SGEEC_START
+#define T3_CTL_QP_TID FW_RI_TID_START
+#define T3_CTRL_QP_SIZE_LOG2 8
+#define T3_CTRL_CQ_ID 0
+
+/* TBD */
+#define T3_MAX_NUM_RI (1<<15)
+#define T3_MAX_NUM_QP (1<<15)
+#define T3_MAX_NUM_CQ (1<<15)
+#define T3_MAX_NUM_PD (1<<15)
+#define T3_MAX_PBL_SIZE 256
+#define T3_MAX_RQ_SIZE 1024
+#define T3_MAX_NUM_STAG (1<<15)
+
+#define T3_STAG_UNSET 0xffffffff
+
+#define T3_MAX_DEV_NAME_LEN 32
+
+struct cxio_hal_ctrl_qp {
+ u32 wptr;
+ u32 rptr;
+ struct mutex lock; /* for the wtpr, can sleep */
+ wait_queue_head_t waitq;/* wait for RspQ/CQE msg */
+ union t3_wr *workq; /* the work request queue */
+ dma_addr_t dma_addr; /* pci bus address of the workq */
+ DECLARE_PCI_UNMAP_ADDR(mapping)
+ void __iomem *doorbell;
+};
+
+struct cxio_hal_resource {
+ struct kfifo *tpt_fifo;
+ spinlock_t tpt_fifo_lock;
+ struct kfifo *qpid_fifo;
+ spinlock_t qpid_fifo_lock;
+ struct kfifo *cqid_fifo;
+ spinlock_t cqid_fifo_lock;
+ struct kfifo *pdid_fifo;
+ spinlock_t pdid_fifo_lock;
+};
+
+struct cxio_qpid_list {
+ struct list_head entry;
+ u32 qpid;
+};
+
+struct cxio_ucontext {
+ struct list_head qpids;
+ struct mutex lock;
+};
+
+struct cxio_rdev {
+ char dev_name[T3_MAX_DEV_NAME_LEN];
+ struct t3cdev *t3cdev_p;
+ struct rdma_info rnic_info;
+ struct adap_ports port_info;
+ struct cxio_hal_resource *rscp;
+ struct cxio_hal_ctrl_qp ctrl_qp;
+ void *ulp;
+ unsigned long qpshift;
+ u32 qpnr;
+ u32 qpmask;
+ struct cxio_ucontext uctx;
+ struct gen_pool *pbl_pool;
+ struct gen_pool *rqt_pool;
+ struct list_head entry;
+};
+
+static inline int cxio_num_stags(struct cxio_rdev *rdev_p)
+{
+ return min((int)T3_MAX_NUM_STAG, (int)((rdev_p->rnic_info.tpt_top - rdev_p->rnic_info.tpt_base) >> 5));
+}
+
+typedef void (*cxio_hal_ev_callback_func_t) (struct cxio_rdev * rdev_p,
+ struct sk_buff * skb);
+
+#define RSPQ_CQID(rsp) (be32_to_cpu(rsp->cq_ptrid) & 0xffff)
+#define RSPQ_CQPTR(rsp) ((be32_to_cpu(rsp->cq_ptrid) >> 16) & 0xffff)
+#define RSPQ_GENBIT(rsp) ((be32_to_cpu(rsp->flags) >> 16) & 1)
+#define RSPQ_OVERFLOW(rsp) ((be32_to_cpu(rsp->flags) >> 17) & 1)
+#define RSPQ_AN(rsp) ((be32_to_cpu(rsp->flags) >> 18) & 1)
+#define RSPQ_SE(rsp) ((be32_to_cpu(rsp->flags) >> 19) & 1)
+#define RSPQ_NOTIFY(rsp) ((be32_to_cpu(rsp->flags) >> 20) & 1)
+#define RSPQ_CQBRANCH(rsp) ((be32_to_cpu(rsp->flags) >> 21) & 1)
+#define RSPQ_CREDIT_THRESH(rsp) ((be32_to_cpu(rsp->flags) >> 22) & 1)
+
+struct respQ_msg_t {
+ __be32 flags; /* flit 0 */
+ __be32 cq_ptrid;
+ __be64 rsvd; /* flit 1 */
+ struct t3_cqe cqe; /* flits 2-3 */
+};
+
+enum t3_cq_opcode {
+ CQ_ARM_AN = 0x2,
+ CQ_ARM_SE = 0x6,
+ CQ_FORCE_AN = 0x3,
+ CQ_CREDIT_UPDATE = 0x7
+};
+
+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_hal_clear_qp_ctx(struct cxio_rdev *rdev, u32 qpid);
+int cxio_create_cq(struct cxio_rdev *rdev, struct t3_cq *cq);
+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);
+void cxio_init_ucontext(struct cxio_rdev *rdev, struct cxio_ucontext *uctx);
+int cxio_create_qp(struct cxio_rdev *rdev, u32 kernel_domain, struct t3_wq *wq,
+ struct cxio_ucontext *uctx);
+int cxio_destroy_qp(struct cxio_rdev *rdev, struct t3_wq *wq,
+ struct cxio_ucontext *uctx);
+int cxio_peek_cq(struct t3_wq *wr, struct t3_cq *cq, int opcode);
+int cxio_allocate_stag(struct cxio_rdev *rdev, u32 * stag, u32 pdid,
+ enum tpt_mem_perm perm, u32 * pbl_size, u32 * pbl_addr);
+int cxio_register_phys_mem(struct cxio_rdev *rdev, u32 * stag, u32 pdid,
+ enum tpt_mem_perm perm, u32 zbva, u64 to, u32 len,
+ u8 page_size, __be64 *pbl, u32 *pbl_size,
+ u32 *pbl_addr);
+int cxio_reregister_phys_mem(struct cxio_rdev *rdev, u32 * stag, u32 pdid,
+ enum tpt_mem_perm perm, u32 zbva, u64 to, u32 len,
+ u8 page_size, __be64 *pbl, u32 *pbl_size,
+ u32 *pbl_addr);
+int cxio_dereg_mem(struct cxio_rdev *rdev, u32 stag, u32 pbl_size,
+ u32 pbl_addr);
+int cxio_allocate_window(struct cxio_rdev *rdev, u32 * stag, u32 pdid);
+int cxio_deallocate_window(struct cxio_rdev *rdev, u32 stag);
+int cxio_rdma_init(struct cxio_rdev *rdev, struct t3_rdma_init_attr *attr);
+void cxio_register_ev_cb(cxio_hal_ev_callback_func_t ev_cb);
+void cxio_unregister_ev_cb(cxio_hal_ev_callback_func_t ev_cb);
+u32 cxio_hal_get_rhdl(void);
+void cxio_hal_put_rhdl(u32 rhdl);
+u32 cxio_hal_get_pdid(struct cxio_hal_resource *rscp);
+void cxio_hal_put_pdid(struct cxio_hal_resource *rscp, u32 pdid);
+int __init cxio_hal_init(void);
+void __exit cxio_hal_exit(void);
+void cxio_flush_rq(struct t3_wq *wq, struct t3_cq *cq, int count);
+void cxio_flush_sq(struct t3_wq *wq, struct t3_cq *cq, int count);
+void cxio_count_rcqes(struct t3_cq *cq, struct t3_wq *wq, int *count);
+void cxio_count_scqes(struct t3_cq *cq, struct t3_wq *wq, int *count);
+void cxio_flush_hw_cq(struct t3_cq *cq);
+int cxio_poll_cq(struct t3_wq *wq, struct t3_cq *cq, struct t3_cqe *cqe,
+ u8 *cqe_flushed, u64 *cookie, u32 *credit);
+
+#define MOD "iw_cxgb3: "
+#define PDBG(fmt, args...) pr_debug(MOD fmt, ## args)
+
+#ifdef DEBUG
+void cxio_dump_tpt(struct cxio_rdev *rev, u32 stag);
+void cxio_dump_pbl(struct cxio_rdev *rev, u32 pbl_addr, uint len, u8 shift);
+void cxio_dump_wqe(union t3_wr *wqe);
+void cxio_dump_wce(struct t3_cqe *wce);
+void cxio_dump_rqt(struct cxio_rdev *rdev, u32 hwtid, int nents);
+void cxio_dump_tcb(struct cxio_rdev *rdev, u32 hwtid);
+#endif
+
+#endif
diff --git a/drivers/infiniband/hw/cxgb3/cxio_resource.c b/drivers/infiniband/hw/cxgb3/cxio_resource.c
new file mode 100644
index 00000000000..65bf577311a
--- /dev/null
+++ b/drivers/infiniband/hw/cxgb3/cxio_resource.c
@@ -0,0 +1,330 @@
+/*
+ * Copyright (c) 2006 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/* Crude resource management */
+#include <linux/kernel.h>
+#include <linux/random.h>
+#include <linux/slab.h>
+#include <linux/kfifo.h>
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+#include "cxio_resource.h"
+#include "cxio_hal.h"
+
+static struct kfifo *rhdl_fifo;
+static spinlock_t rhdl_fifo_lock;
+
+#define RANDOM_SIZE 16
+
+static int __cxio_init_resource_fifo(struct kfifo **fifo,
+ spinlock_t *fifo_lock,
+ u32 nr, u32 skip_low,
+ u32 skip_high,
+ int random)
+{
+ u32 i, j, entry = 0, idx;
+ u32 random_bytes;
+ u32 rarray[16];
+ spin_lock_init(fifo_lock);
+
+ *fifo = kfifo_alloc(nr * sizeof(u32), GFP_KERNEL, fifo_lock);
+ if (IS_ERR(*fifo))
+ return -ENOMEM;
+
+ for (i = 0; i < skip_low + skip_high; i++)
+ __kfifo_put(*fifo, (unsigned char *) &entry, sizeof(u32));
+ if (random) {
+ j = 0;
+ random_bytes = random32();
+ for (i = 0; i < RANDOM_SIZE; i++)
+ rarray[i] = i + skip_low;
+ for (i = skip_low + RANDOM_SIZE; i < nr - skip_high; i++) {
+ if (j >= RANDOM_SIZE) {
+ j = 0;
+ random_bytes = random32();
+ }
+ idx = (random_bytes >> (j * 2)) & 0xF;
+ __kfifo_put(*fifo,
+ (unsigned char *) &rarray[idx],
+ sizeof(u32));
+ rarray[idx] = i;
+ j++;
+ }
+ for (i = 0; i < RANDOM_SIZE; i++)
+ __kfifo_put(*fifo,
+ (unsigned char *) &rarray[i],
+ sizeof(u32));
+ } else
+ for (i = skip_low; i < nr - skip_high; i++)
+ __kfifo_put(*fifo, (unsigned char *) &i, sizeof(u32));
+
+ for (i = 0; i < skip_low + skip_high; i++)
+ kfifo_get(*fifo, (unsigned char *) &entry, sizeof(u32));
+ return 0;
+}
+
+static int cxio_init_resource_fifo(struct kfifo **fifo, spinlock_t * fifo_lock,
+ u32 nr, u32 skip_low, u32 skip_high)
+{
+ return (__cxio_init_resource_fifo(fifo, fifo_lock, nr, skip_low,
+ skip_high, 0));
+}
+
+static int cxio_init_resource_fifo_random(struct kfifo **fifo,
+ spinlock_t * fifo_lock,
+ u32 nr, u32 skip_low, u32 skip_high)
+{
+
+ return (__cxio_init_resource_fifo(fifo, fifo_lock, nr, skip_low,
+ skip_high, 1));
+}
+
+static int cxio_init_qpid_fifo(struct cxio_rdev *rdev_p)
+{
+ u32 i;
+
+ spin_lock_init(&rdev_p->rscp->qpid_fifo_lock);
+
+ rdev_p->rscp->qpid_fifo = kfifo_alloc(T3_MAX_NUM_QP * sizeof(u32),
+ GFP_KERNEL,
+ &rdev_p->rscp->qpid_fifo_lock);
+ if (IS_ERR(rdev_p->rscp->qpid_fifo))
+ return -ENOMEM;
+
+ for (i = 16; i < T3_MAX_NUM_QP; i++)
+ if (!(i & rdev_p->qpmask))
+ __kfifo_put(rdev_p->rscp->qpid_fifo,
+ (unsigned char *) &i, sizeof(u32));
+ return 0;
+}
+
+int cxio_hal_init_rhdl_resource(u32 nr_rhdl)
+{
+ return cxio_init_resource_fifo(&rhdl_fifo, &rhdl_fifo_lock, nr_rhdl, 1,
+ 0);
+}
+
+void cxio_hal_destroy_rhdl_resource(void)
+{
+ kfifo_free(rhdl_fifo);
+}
+
+/* nr_* must be power of 2 */
+int cxio_hal_init_resource(struct cxio_rdev *rdev_p,
+ u32 nr_tpt, u32 nr_pbl,
+ u32 nr_rqt, u32 nr_qpid, u32 nr_cqid, u32 nr_pdid)
+{
+ int err = 0;
+ struct cxio_hal_resource *rscp;
+
+ rscp = kmalloc(sizeof(*rscp), GFP_KERNEL);
+ if (!rscp)
+ return -ENOMEM;
+ rdev_p->rscp = rscp;
+ err = cxio_init_resource_fifo_random(&rscp->tpt_fifo,
+ &rscp->tpt_fifo_lock,
+ nr_tpt, 1, 0);
+ if (err)
+ goto tpt_err;
+ err = cxio_init_qpid_fifo(rdev_p);
+ if (err)
+ goto qpid_err;
+ err = cxio_init_resource_fifo(&rscp->cqid_fifo, &rscp->cqid_fifo_lock,
+ nr_cqid, 1, 0);
+ if (err)
+ goto cqid_err;
+ err = cxio_init_resource_fifo(&rscp->pdid_fifo, &rscp->pdid_fifo_lock,
+ nr_pdid, 1, 0);
+ if (err)
+ goto pdid_err;
+ return 0;
+pdid_err:
+ kfifo_free(rscp->cqid_fifo);
+cqid_err:
+ kfifo_free(rscp->qpid_fifo);
+qpid_err:
+ kfifo_free(rscp->tpt_fifo);
+tpt_err:
+ return -ENOMEM;
+}
+
+/*
+ * returns 0 if no resource available
+ */
+static inline u32 cxio_hal_get_resource(struct kfifo *fifo)
+{
+ u32 entry;
+ if (kfifo_get(fifo, (unsigned char *) &entry, sizeof(u32)))
+ return entry;
+ else
+ return 0; /* fifo emptry */
+}
+
+static inline void cxio_hal_put_resource(struct kfifo *fifo, u32 entry)
+{
+ BUG_ON(kfifo_put(fifo, (unsigned char *) &entry, sizeof(u32)) == 0);
+}
+
+u32 cxio_hal_get_rhdl(void)
+{
+ return cxio_hal_get_resource(rhdl_fifo);
+}
+
+void cxio_hal_put_rhdl(u32 rhdl)
+{
+ cxio_hal_put_resource(rhdl_fifo, rhdl);
+}
+
+u32 cxio_hal_get_stag(struct cxio_hal_resource *rscp)
+{
+ return cxio_hal_get_resource(rscp->tpt_fifo);
+}
+
+void cxio_hal_put_stag(struct cxio_hal_resource *rscp, u32 stag)
+{
+ cxio_hal_put_resource(rscp->tpt_fifo, stag);
+}
+
+u32 cxio_hal_get_qpid(struct cxio_hal_resource *rscp)
+{
+ u32 qpid = cxio_hal_get_resource(rscp->qpid_fifo);
+ PDBG("%s qpid 0x%x\n", __FUNCTION__, qpid);
+ return qpid;
+}
+
+void cxio_hal_put_qpid(struct cxio_hal_resource *rscp, u32 qpid)
+{
+ PDBG("%s qpid 0x%x\n", __FUNCTION__, qpid);
+ cxio_hal_put_resource(rscp->qpid_fifo, qpid);
+}
+
+u32 cxio_hal_get_cqid(struct cxio_hal_resource *rscp)
+{
+ return cxio_hal_get_resource(rscp->cqid_fifo);
+}
+
+void cxio_hal_put_cqid(struct cxio_hal_resource *rscp, u32 cqid)
+{
+ cxio_hal_put_resource(rscp->cqid_fifo, cqid);
+}
+
+u32 cxio_hal_get_pdid(struct cxio_hal_resource *rscp)
+{
+ return cxio_hal_get_resource(rscp->pdid_fifo);
+}
+
+void cxio_hal_put_pdid(struct cxio_hal_resource *rscp, u32 pdid)
+{
+ cxio_hal_put_resource(rscp->pdid_fifo, pdid);
+}
+
+void cxio_hal_destroy_resource(struct cxio_hal_resource *rscp)
+{
+ kfifo_free(rscp->tpt_fifo);
+ kfifo_free(rscp->cqid_fifo);
+ kfifo_free(rscp->qpid_fifo);
+ kfifo_free(rscp->pdid_fifo);
+ kfree(rscp);
+}
+
+/*
+ * PBL Memory Manager. Uses Linux generic allocator.
+ */
+
+#define MIN_PBL_SHIFT 8 /* 256B == min PBL size (32 entries) */
+#define PBL_CHUNK 2*1024*1024
+
+u32 cxio_hal_pblpool_alloc(struct cxio_rdev *rdev_p, int size)
+{
+ unsigned long addr = gen_pool_alloc(rdev_p->pbl_pool, size);
+ PDBG("%s addr 0x%x size %d\n", __FUNCTION__, (u32)addr, size);
+ return (u32)addr;
+}
+
+void cxio_hal_pblpool_free(struct cxio_rdev *rdev_p, u32 addr, int size)
+{
+ PDBG("%s addr 0x%x size %d\n", __FUNCTION__, addr, size);
+ gen_pool_free(rdev_p->pbl_pool, (unsigned long)addr, size);
+}
+
+int cxio_hal_pblpool_create(struct cxio_rdev *rdev_p)
+{
+ unsigned long i;
+ rdev_p->pbl_pool = gen_pool_create(MIN_PBL_SHIFT, -1);
+ if (rdev_p->pbl_pool)
+ for (i = rdev_p->rnic_info.pbl_base;
+ i <= rdev_p->rnic_info.pbl_top - PBL_CHUNK + 1;
+ i += PBL_CHUNK)
+ gen_pool_add(rdev_p->pbl_pool, i, PBL_CHUNK, -1);
+ return rdev_p->pbl_pool ? 0 : -ENOMEM;
+}
+
+void cxio_hal_pblpool_destroy(struct cxio_rdev *rdev_p)
+{
+ gen_pool_destroy(rdev_p->pbl_pool);
+}
+
+/*
+ * RQT Memory Manager. Uses Linux generic allocator.
+ */
+
+#define MIN_RQT_SHIFT 10 /* 1KB == mini RQT size (16 entries) */
+#define RQT_CHUNK 2*1024*1024
+
+u32 cxio_hal_rqtpool_alloc(struct cxio_rdev *rdev_p, int size)
+{
+ unsigned long addr = gen_pool_alloc(rdev_p->rqt_pool, size << 6);
+ PDBG("%s addr 0x%x size %d\n", __FUNCTION__, (u32)addr, size << 6);
+ return (u32)addr;
+}
+
+void cxio_hal_rqtpool_free(struct cxio_rdev *rdev_p, u32 addr, int size)
+{
+ PDBG("%s addr 0x%x size %d\n", __FUNCTION__, addr, size << 6);
+ gen_pool_free(rdev_p->rqt_pool, (unsigned long)addr, size << 6);
+}
+
+int cxio_hal_rqtpool_create(struct cxio_rdev *rdev_p)
+{
+ unsigned long i;
+ rdev_p->rqt_pool = gen_pool_create(MIN_RQT_SHIFT, -1);
+ if (rdev_p->rqt_pool)
+ for (i = rdev_p->rnic_info.rqt_base;
+ i <= rdev_p->rnic_info.rqt_top - RQT_CHUNK + 1;
+ i += RQT_CHUNK)
+ gen_pool_add(rdev_p->rqt_pool, i, RQT_CHUNK, -1);
+ return rdev_p->rqt_pool ? 0 : -ENOMEM;
+}
+
+void cxio_hal_rqtpool_destroy(struct cxio_rdev *rdev_p)
+{
+ gen_pool_destroy(rdev_p->rqt_pool);
+}
diff --git a/drivers/infiniband/hw/cxgb3/cxio_resource.h b/drivers/infiniband/hw/cxgb3/cxio_resource.h
new file mode 100644
index 00000000000..a2703a3d882
--- /dev/null
+++ b/drivers/infiniband/hw/cxgb3/cxio_resource.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2006 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef __CXIO_RESOURCE_H__
+#define __CXIO_RESOURCE_H__
+
+#include <linux/kernel.h>
+#include <linux/random.h>
+#include <linux/slab.h>
+#include <linux/kfifo.h>
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+#include <linux/genalloc.h>
+#include "cxio_hal.h"
+
+extern int cxio_hal_init_rhdl_resource(u32 nr_rhdl);
+extern void cxio_hal_destroy_rhdl_resource(void);
+extern int cxio_hal_init_resource(struct cxio_rdev *rdev_p,
+ u32 nr_tpt, u32 nr_pbl,
+ u32 nr_rqt, u32 nr_qpid, u32 nr_cqid,
+ u32 nr_pdid);
+extern u32 cxio_hal_get_stag(struct cxio_hal_resource *rscp);
+extern void cxio_hal_put_stag(struct cxio_hal_resource *rscp, u32 stag);
+extern u32 cxio_hal_get_qpid(struct cxio_hal_resource *rscp);
+extern void cxio_hal_put_qpid(struct cxio_hal_resource *rscp, u32 qpid);
+extern u32 cxio_hal_get_cqid(struct cxio_hal_resource *rscp);
+extern void cxio_hal_put_cqid(struct cxio_hal_resource *rscp, u32 cqid);
+extern void cxio_hal_destroy_resource(struct cxio_hal_resource *rscp);
+
+#define PBL_OFF(rdev_p, a) ( (a) - (rdev_p)->rnic_info.pbl_base )
+extern int cxio_hal_pblpool_create(struct cxio_rdev *rdev_p);
+extern void cxio_hal_pblpool_destroy(struct cxio_rdev *rdev_p);
+extern u32 cxio_hal_pblpool_alloc(struct cxio_rdev *rdev_p, int size);
+extern void cxio_hal_pblpool_free(struct cxio_rdev *rdev_p, u32 addr, int size);
+
+#define RQT_OFF(rdev_p, a) ( (a) - (rdev_p)->rnic_info.rqt_base )
+extern int cxio_hal_rqtpool_create(struct cxio_rdev *rdev_p);
+extern void cxio_hal_rqtpool_destroy(struct cxio_rdev *rdev_p);
+extern u32 cxio_hal_rqtpool_alloc(struct cxio_rdev *rdev_p, int size);
+extern void cxio_hal_rqtpool_free(struct cxio_rdev *rdev_p, u32 addr, int size);
+#endif
diff --git a/drivers/infiniband/hw/cxgb3/cxio_wr.h b/drivers/infiniband/hw/cxgb3/cxio_wr.h
new file mode 100644
index 00000000000..90d7b8972cb
--- /dev/null
+++ b/drivers/infiniband/hw/cxgb3/cxio_wr.h
@@ -0,0 +1,684 @@
+/*
+ * Copyright (c) 2006 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef __CXIO_WR_H__
+#define __CXIO_WR_H__
+
+#include <asm/io.h>
+#include <linux/pci.h>
+#include <linux/timer.h>
+#include "firmware_exports.h"
+
+#define T3_MAX_SGE 4
+
+#define Q_EMPTY(rptr,wptr) ((rptr)==(wptr))
+#define Q_FULL(rptr,wptr,size_log2) ( (((wptr)-(rptr))>>(size_log2)) && \
+ ((rptr)!=(wptr)) )
+#define Q_GENBIT(ptr,size_log2) (!(((ptr)>>size_log2)&0x1))
+#define Q_FREECNT(rptr,wptr,size_log2) ((1UL<<size_log2)-((wptr)-(rptr)))
+#define Q_COUNT(rptr,wptr) ((wptr)-(rptr))
+#define Q_PTR2IDX(ptr,size_log2) (ptr & ((1UL<<size_log2)-1))
+
+static inline void ring_doorbell(void __iomem *doorbell, u32 qpid)
+{
+ writel(((1<<31) | qpid), doorbell);
+}
+
+#define SEQ32_GE(x,y) (!( (((u32) (x)) - ((u32) (y))) & 0x80000000 ))
+
+enum t3_wr_flags {
+ T3_COMPLETION_FLAG = 0x01,
+ T3_NOTIFY_FLAG = 0x02,
+ T3_SOLICITED_EVENT_FLAG = 0x04,
+ T3_READ_FENCE_FLAG = 0x08,
+ T3_LOCAL_FENCE_FLAG = 0x10
+} __attribute__ ((packed));
+
+enum t3_wr_opcode {
+ T3_WR_BP = FW_WROPCODE_RI_BYPASS,
+ T3_WR_SEND = FW_WROPCODE_RI_SEND,
+ T3_WR_WRITE = FW_WROPCODE_RI_RDMA_WRITE,
+ T3_WR_READ = FW_WROPCODE_RI_RDMA_READ,
+ T3_WR_INV_STAG = FW_WROPCODE_RI_LOCAL_INV,
+ T3_WR_BIND = FW_WROPCODE_RI_BIND_MW,
+ T3_WR_RCV = FW_WROPCODE_RI_RECEIVE,
+ T3_WR_INIT = FW_WROPCODE_RI_RDMA_INIT,
+ T3_WR_QP_MOD = FW_WROPCODE_RI_MODIFY_QP
+} __attribute__ ((packed));
+
+enum t3_rdma_opcode {
+ T3_RDMA_WRITE, /* IETF RDMAP v1.0 ... */
+ T3_READ_REQ,
+ T3_READ_RESP,
+ T3_SEND,
+ T3_SEND_WITH_INV,
+ T3_SEND_WITH_SE,
+ T3_SEND_WITH_SE_INV,
+ T3_TERMINATE,
+ T3_RDMA_INIT, /* CHELSIO RI specific ... */
+ T3_BIND_MW,
+ T3_FAST_REGISTER,
+ T3_LOCAL_INV,
+ T3_QP_MOD,
+ T3_BYPASS
+} __attribute__ ((packed));
+
+static inline enum t3_rdma_opcode wr2opcode(enum t3_wr_opcode wrop)
+{
+ switch (wrop) {
+ case T3_WR_BP: return T3_BYPASS;
+ case T3_WR_SEND: return T3_SEND;
+ case T3_WR_WRITE: return T3_RDMA_WRITE;
+ case T3_WR_READ: return T3_READ_REQ;
+ case T3_WR_INV_STAG: return T3_LOCAL_INV;
+ case T3_WR_BIND: return T3_BIND_MW;
+ case T3_WR_INIT: return T3_RDMA_INIT;
+ case T3_WR_QP_MOD: return T3_QP_MOD;
+ default: break;
+ }
+ return -1;
+}
+
+
+/* Work request id */
+union t3_wrid {
+ struct {
+ u32 hi;
+ u32 low;
+ } id0;
+ u64 id1;
+};
+
+#define WRID(wrid) (wrid.id1)
+#define WRID_GEN(wrid) (wrid.id0.wr_gen)
+#define WRID_IDX(wrid) (wrid.id0.wr_idx)
+#define WRID_LO(wrid) (wrid.id0.wr_lo)
+
+struct fw_riwrh {
+ __be32 op_seop_flags;
+ __be32 gen_tid_len;
+};
+
+#define S_FW_RIWR_OP 24
+#define M_FW_RIWR_OP 0xff
+#define V_FW_RIWR_OP(x) ((x) << S_FW_RIWR_OP)
+#define G_FW_RIWR_OP(x) ((((x) >> S_FW_RIWR_OP)) & M_FW_RIWR_OP)
+
+#define S_FW_RIWR_SOPEOP 22
+#define M_FW_RIWR_SOPEOP 0x3
+#define V_FW_RIWR_SOPEOP(x) ((x) << S_FW_RIWR_SOPEOP)
+
+#define S_FW_RIWR_FLAGS 8
+#define M_FW_RIWR_FLAGS 0x3fffff
+#define V_FW_RIWR_FLAGS(x) ((x) << S_FW_RIWR_FLAGS)
+#define G_FW_RIWR_FLAGS(x) ((((x) >> S_FW_RIWR_FLAGS)) & M_FW_RIWR_FLAGS)
+
+#define S_FW_RIWR_TID 8
+#define V_FW_RIWR_TID(x) ((x) << S_FW_RIWR_TID)
+
+#define S_FW_RIWR_LEN 0
+#define V_FW_RIWR_LEN(x) ((x) << S_FW_RIWR_LEN)
+
+#define S_FW_RIWR_GEN 31
+#define V_FW_RIWR_GEN(x) ((x) << S_FW_RIWR_GEN)
+
+struct t3_sge {
+ __be32 stag;
+ __be32 len;
+ __be64 to;
+};
+
+/* If num_sgle is zero, flit 5+ contains immediate data.*/
+struct t3_send_wr {
+ struct fw_riwrh wrh; /* 0 */
+ union t3_wrid wrid; /* 1 */
+
+ u8 rdmaop; /* 2 */
+ u8 reserved[3];
+ __be32 rem_stag;
+ __be32 plen; /* 3 */
+ __be32 num_sgle;
+ struct t3_sge sgl[T3_MAX_SGE]; /* 4+ */
+};
+
+struct t3_local_inv_wr {
+ struct fw_riwrh wrh; /* 0 */
+ union t3_wrid wrid; /* 1 */
+ __be32 stag; /* 2 */
+ __be32 reserved3;
+};
+
+struct t3_rdma_write_wr {
+ struct fw_riwrh wrh; /* 0 */
+ union t3_wrid wrid; /* 1 */
+ u8 rdmaop; /* 2 */
+ u8 reserved[3];
+ __be32 stag_sink;
+ __be64 to_sink; /* 3 */
+ __be32 plen; /* 4 */
+ __be32 num_sgle;
+ struct t3_sge sgl[T3_MAX_SGE]; /* 5+ */
+};
+
+struct t3_rdma_read_wr {
+ struct fw_riwrh wrh; /* 0 */
+ union t3_wrid wrid; /* 1 */
+ u8 rdmaop; /* 2 */
+ u8 reserved[3];
+ __be32 rem_stag;
+ __be64 rem_to; /* 3 */
+ __be32 local_stag; /* 4 */
+ __be32 local_len;
+ __be64 local_to; /* 5 */
+};
+
+enum t3_addr_type {
+ T3_VA_BASED_TO = 0x0,
+ T3_ZERO_BASED_TO = 0x1
+} __attribute__ ((packed));
+
+enum t3_mem_perms {
+ T3_MEM_ACCESS_LOCAL_READ = 0x1,
+ T3_MEM_ACCESS_LOCAL_WRITE = 0x2,
+ T3_MEM_ACCESS_REM_READ = 0x4,
+ T3_MEM_ACCESS_REM_WRITE = 0x8
+} __attribute__ ((packed));
+
+struct t3_bind_mw_wr {
+ struct fw_riwrh wrh; /* 0 */
+ union t3_wrid wrid; /* 1 */
+ u16 reserved; /* 2 */
+ u8 type;
+ u8 perms;
+ __be32 mr_stag;
+ __be32 mw_stag; /* 3 */
+ __be32 mw_len;
+ __be64 mw_va; /* 4 */
+ __be32 mr_pbl_addr; /* 5 */
+ u8 reserved2[3];
+ u8 mr_pagesz;
+};
+
+struct t3_receive_wr {
+ struct fw_riwrh wrh; /* 0 */
+ union t3_wrid wrid; /* 1 */
+ u8 pagesz[T3_MAX_SGE];
+ __be32 num_sgle; /* 2 */
+ struct t3_sge sgl[T3_MAX_SGE]; /* 3+ */
+ __be32 pbl_addr[T3_MAX_SGE];
+};
+
+struct t3_bypass_wr {
+ struct fw_riwrh wrh;
+ union t3_wrid wrid; /* 1 */
+};
+
+struct t3_modify_qp_wr {
+ struct fw_riwrh wrh; /* 0 */
+ union t3_wrid wrid; /* 1 */
+ __be32 flags; /* 2 */
+ __be32 quiesce; /* 2 */
+ __be32 max_ird; /* 3 */
+ __be32 max_ord; /* 3 */
+ __be64 sge_cmd; /* 4 */
+ __be64 ctx1; /* 5 */
+ __be64 ctx0; /* 6 */
+};
+
+enum t3_modify_qp_flags {
+ MODQP_QUIESCE = 0x01,
+ MODQP_MAX_IRD = 0x02,
+ MODQP_MAX_ORD = 0x04,
+ MODQP_WRITE_EC = 0x08,
+ MODQP_READ_EC = 0x10,
+};
+
+
+enum t3_mpa_attrs {
+ uP_RI_MPA_RX_MARKER_ENABLE = 0x1,
+ uP_RI_MPA_TX_MARKER_ENABLE = 0x2,
+ uP_RI_MPA_CRC_ENABLE = 0x4,
+ uP_RI_MPA_IETF_ENABLE = 0x8
+} __attribute__ ((packed));
+
+enum t3_qp_caps {
+ uP_RI_QP_RDMA_READ_ENABLE = 0x01,
+ uP_RI_QP_RDMA_WRITE_ENABLE = 0x02,
+ uP_RI_QP_BIND_ENABLE = 0x04,
+ uP_RI_QP_FAST_REGISTER_ENABLE = 0x08,
+ uP_RI_QP_STAG0_ENABLE = 0x10
+} __attribute__ ((packed));
+
+struct t3_rdma_init_attr {
+ u32 tid;
+ u32 qpid;
+ u32 pdid;
+ u32 scqid;
+ u32 rcqid;
+ u32 rq_addr;
+ u32 rq_size;
+ enum t3_mpa_attrs mpaattrs;
+ enum t3_qp_caps qpcaps;
+ u16 tcp_emss;
+ u32 ord;
+ u32 ird;
+ u64 qp_dma_addr;
+ u32 qp_dma_size;
+ u32 flags;
+};
+
+struct t3_rdma_init_wr {
+ struct fw_riwrh wrh; /* 0 */
+ union t3_wrid wrid; /* 1 */
+ __be32 qpid; /* 2 */
+ __be32 pdid;
+ __be32 scqid; /* 3 */
+ __be32 rcqid;
+ __be32 rq_addr; /* 4 */
+ __be32 rq_size;
+ u8 mpaattrs; /* 5 */
+ u8 qpcaps;
+ __be16 ulpdu_size;
+ __be32 flags; /* bits 31-1 - reservered */
+ /* bit 0 - set if RECV posted */
+ __be32 ord; /* 6 */
+ __be32 ird;
+ __be64 qp_dma_addr; /* 7 */
+ __be32 qp_dma_size; /* 8 */
+ u32 rsvd;
+};
+
+struct t3_genbit {
+ u64 flit[15];
+ __be64 genbit;
+};
+
+enum rdma_init_wr_flags {
+ RECVS_POSTED = 1,
+};
+
+union t3_wr {
+ struct t3_send_wr send;
+ struct t3_rdma_write_wr write;
+ struct t3_rdma_read_wr read;
+ struct t3_receive_wr recv;
+ struct t3_local_inv_wr local_inv;
+ struct t3_bind_mw_wr bind;
+ struct t3_bypass_wr bypass;
+ struct t3_rdma_init_wr init;
+ struct t3_modify_qp_wr qp_mod;
+ struct t3_genbit genbit;
+ u64 flit[16];
+};
+
+#define T3_SQ_CQE_FLIT 13
+#define T3_SQ_COOKIE_FLIT 14
+
+#define T3_RQ_COOKIE_FLIT 13
+#define T3_RQ_CQE_FLIT 14
+
+static inline enum t3_wr_opcode fw_riwrh_opcode(struct fw_riwrh *wqe)
+{
+ return G_FW_RIWR_OP(be32_to_cpu(wqe->op_seop_flags));
+}
+
+static inline void build_fw_riwrh(struct fw_riwrh *wqe, enum t3_wr_opcode op,
+ enum t3_wr_flags flags, u8 genbit, u32 tid,
+ u8 len)
+{
+ wqe->op_seop_flags = cpu_to_be32(V_FW_RIWR_OP(op) |
+ V_FW_RIWR_SOPEOP(M_FW_RIWR_SOPEOP) |
+ V_FW_RIWR_FLAGS(flags));
+ wmb();
+ wqe->gen_tid_len = cpu_to_be32(V_FW_RIWR_GEN(genbit) |
+ V_FW_RIWR_TID(tid) |
+ V_FW_RIWR_LEN(len));
+ /* 2nd gen bit... */
+ ((union t3_wr *)wqe)->genbit.genbit = cpu_to_be64(genbit);
+}
+
+/*
+ * T3 ULP2_TX commands
+ */
+enum t3_utx_mem_op {
+ T3_UTX_MEM_READ = 2,
+ T3_UTX_MEM_WRITE = 3
+};
+
+/* T3 MC7 RDMA TPT entry format */
+
+enum tpt_mem_type {
+ TPT_NON_SHARED_MR = 0x0,
+ TPT_SHARED_MR = 0x1,
+ TPT_MW = 0x2,
+ TPT_MW_RELAXED_PROTECTION = 0x3
+};
+
+enum tpt_addr_type {
+ TPT_ZBTO = 0,
+ TPT_VATO = 1
+};
+
+enum tpt_mem_perm {
+ TPT_LOCAL_READ = 0x8,
+ TPT_LOCAL_WRITE = 0x4,
+ TPT_REMOTE_READ = 0x2,
+ TPT_REMOTE_WRITE = 0x1
+};
+
+struct tpt_entry {
+ __be32 valid_stag_pdid;
+ __be32 flags_pagesize_qpid;
+
+ __be32 rsvd_pbl_addr;
+ __be32 len;
+ __be32 va_hi;
+ __be32 va_low_or_fbo;
+
+ __be32 rsvd_bind_cnt_or_pstag;
+ __be32 rsvd_pbl_size;
+};
+
+#define S_TPT_VALID 31
+#define V_TPT_VALID(x) ((x) << S_TPT_VALID)
+#define F_TPT_VALID V_TPT_VALID(1U)
+
+#define S_TPT_STAG_KEY 23
+#define M_TPT_STAG_KEY 0xFF
+#define V_TPT_STAG_KEY(x) ((x) << S_TPT_STAG_KEY)
+#define G_TPT_STAG_KEY(x) (((x) >> S_TPT_STAG_KEY) & M_TPT_STAG_KEY)
+
+#define S_TPT_STAG_STATE 22
+#define V_TPT_STAG_STATE(x) ((x) << S_TPT_STAG_STATE)
+#define F_TPT_STAG_STATE V_TPT_STAG_STATE(1U)
+
+#define S_TPT_STAG_TYPE 20
+#define M_TPT_STAG_TYPE 0x3
+#define V_TPT_STAG_TYPE(x) ((x) << S_TPT_STAG_TYPE)
+#define G_TPT_STAG_TYPE(x) (((x) >> S_TPT_STAG_TYPE) & M_TPT_STAG_TYPE)
+
+#define S_TPT_PDID 0
+#define M_TPT_PDID 0xFFFFF
+#define V_TPT_PDID(x) ((x) << S_TPT_PDID)
+#define G_TPT_PDID(x) (((x) >> S_TPT_PDID) & M_TPT_PDID)
+
+#define S_TPT_PERM 28
+#define M_TPT_PERM 0xF
+#define V_TPT_PERM(x) ((x) << S_TPT_PERM)
+#define G_TPT_PERM(x) (((x) >> S_TPT_PERM) & M_TPT_PERM)
+
+#define S_TPT_REM_INV_DIS 27
+#define V_TPT_REM_INV_DIS(x) ((x) << S_TPT_REM_INV_DIS)
+#define F_TPT_REM_INV_DIS V_TPT_REM_INV_DIS(1U)
+
+#define S_TPT_ADDR_TYPE 26
+#define V_TPT_ADDR_TYPE(x) ((x) << S_TPT_ADDR_TYPE)
+#define F_TPT_ADDR_TYPE V_TPT_ADDR_TYPE(1U)
+
+#define S_TPT_MW_BIND_ENABLE 25
+#define V_TPT_MW_BIND_ENABLE(x) ((x) << S_TPT_MW_BIND_ENABLE)
+#define F_TPT_MW_BIND_ENABLE V_TPT_MW_BIND_ENABLE(1U)
+
+#define S_TPT_PAGE_SIZE 20
+#define M_TPT_PAGE_SIZE 0x1F
+#define V_TPT_PAGE_SIZE(x) ((x) << S_TPT_PAGE_SIZE)
+#define G_TPT_PAGE_SIZE(x) (((x) >> S_TPT_PAGE_SIZE) & M_TPT_PAGE_SIZE)
+
+#define S_TPT_PBL_ADDR 0
+#define M_TPT_PBL_ADDR 0x1FFFFFFF
+#define V_TPT_PBL_ADDR(x) ((x) << S_TPT_PBL_ADDR)
+#define G_TPT_PBL_ADDR(x) (((x) >> S_TPT_PBL_ADDR) & M_TPT_PBL_ADDR)
+
+#define S_TPT_QPID 0
+#define M_TPT_QPID 0xFFFFF
+#define V_TPT_QPID(x) ((x) << S_TPT_QPID)
+#define G_TPT_QPID(x) (((x) >> S_TPT_QPID) & M_TPT_QPID)
+
+#define S_TPT_PSTAG 0
+#define M_TPT_PSTAG 0xFFFFFF
+#define V_TPT_PSTAG(x) ((x) << S_TPT_PSTAG)
+#define G_TPT_PSTAG(x) (((x) >> S_TPT_PSTAG) & M_TPT_PSTAG)
+
+#define S_TPT_PBL_SIZE 0
+#define M_TPT_PBL_SIZE 0xFFFFF
+#define V_TPT_PBL_SIZE(x) ((x) << S_TPT_PBL_SIZE)
+#define G_TPT_PBL_SIZE(x) (((x) >> S_TPT_PBL_SIZE) & M_TPT_PBL_SIZE)
+
+/*
+ * CQE defs
+ */
+struct t3_cqe {
+ __be32 header;
+ __be32 len;
+ union {
+ struct {
+ __be32 stag;
+ __be32 msn;
+ } rcqe;
+ struct {
+ u32 wrid_hi;
+ u32 wrid_low;
+ } scqe;
+ } u;
+};
+
+#define S_CQE_OOO 31
+#define M_CQE_OOO 0x1
+#define G_CQE_OOO(x) ((((x) >> S_CQE_OOO)) & M_CQE_OOO)
+#define V_CEQ_OOO(x) ((x)<<S_CQE_OOO)
+
+#define S_CQE_QPID 12
+#define M_CQE_QPID 0x7FFFF
+#define G_CQE_QPID(x) ((((x) >> S_CQE_QPID)) & M_CQE_QPID)
+#define V_CQE_QPID(x) ((x)<<S_CQE_QPID)
+
+#define S_CQE_SWCQE 11
+#define M_CQE_SWCQE 0x1
+#define G_CQE_SWCQE(x) ((((x) >> S_CQE_SWCQE)) & M_CQE_SWCQE)
+#define V_CQE_SWCQE(x) ((x)<<S_CQE_SWCQE)
+
+#define S_CQE_GENBIT 10
+#define M_CQE_GENBIT 0x1
+#define G_CQE_GENBIT(x) (((x) >> S_CQE_GENBIT) & M_CQE_GENBIT)
+#define V_CQE_GENBIT(x) ((x)<<S_CQE_GENBIT)
+
+#define S_CQE_STATUS 5
+#define M_CQE_STATUS 0x1F
+#define G_CQE_STATUS(x) ((((x) >> S_CQE_STATUS)) & M_CQE_STATUS)
+#define V_CQE_STATUS(x) ((x)<<S_CQE_STATUS)
+
+#define S_CQE_TYPE 4
+#define M_CQE_TYPE 0x1
+#define G_CQE_TYPE(x) ((((x) >> S_CQE_TYPE)) & M_CQE_TYPE)
+#define V_CQE_TYPE(x) ((x)<<S_CQE_TYPE)
+
+#define S_CQE_OPCODE 0
+#define M_CQE_OPCODE 0xF
+#define G_CQE_OPCODE(x) ((((x) >> S_CQE_OPCODE)) & M_CQE_OPCODE)
+#define V_CQE_OPCODE(x) ((x)<<S_CQE_OPCODE)
+
+#define SW_CQE(x) (G_CQE_SWCQE(be32_to_cpu((x).header)))
+#define CQE_OOO(x) (G_CQE_OOO(be32_to_cpu((x).header)))
+#define CQE_QPID(x) (G_CQE_QPID(be32_to_cpu((x).header)))
+#define CQE_GENBIT(x) (G_CQE_GENBIT(be32_to_cpu((x).header)))
+#define CQE_TYPE(x) (G_CQE_TYPE(be32_to_cpu((x).header)))
+#define SQ_TYPE(x) (CQE_TYPE((x)))
+#define RQ_TYPE(x) (!CQE_TYPE((x)))
+#define CQE_STATUS(x) (G_CQE_STATUS(be32_to_cpu((x).header)))
+#define CQE_OPCODE(x) (G_CQE_OPCODE(be32_to_cpu((x).header)))
+
+#define CQE_LEN(x) (be32_to_cpu((x).len))
+
+/* used for RQ completion processing */
+#define CQE_WRID_STAG(x) (be32_to_cpu((x).u.rcqe.stag))
+#define CQE_WRID_MSN(x) (be32_to_cpu((x).u.rcqe.msn))
+
+/* used for SQ completion processing */
+#define CQE_WRID_SQ_WPTR(x) ((x).u.scqe.wrid_hi)
+#define CQE_WRID_WPTR(x) ((x).u.scqe.wrid_low)
+
+/* generic accessor macros */
+#define CQE_WRID_HI(x) ((x).u.scqe.wrid_hi)
+#define CQE_WRID_LOW(x) ((x).u.scqe.wrid_low)
+
+#define TPT_ERR_SUCCESS 0x0
+#define TPT_ERR_STAG 0x1 /* STAG invalid: either the */
+ /* STAG is offlimt, being 0, */
+ /* or STAG_key mismatch */
+#define TPT_ERR_PDID 0x2 /* PDID mismatch */
+#define TPT_ERR_QPID 0x3 /* QPID mismatch */
+#define TPT_ERR_ACCESS 0x4 /* Invalid access right */
+#define TPT_ERR_WRAP 0x5 /* Wrap error */
+#define TPT_ERR_BOUND 0x6 /* base and bounds voilation */
+#define TPT_ERR_INVALIDATE_SHARED_MR 0x7 /* attempt to invalidate a */
+ /* shared memory region */
+#define TPT_ERR_INVALIDATE_MR_WITH_MW_BOUND 0x8 /* attempt to invalidate a */
+ /* shared memory region */
+#define TPT_ERR_ECC 0x9 /* ECC error detected */
+#define TPT_ERR_ECC_PSTAG 0xA /* ECC error detected when */
+ /* reading PSTAG for a MW */
+ /* Invalidate */
+#define TPT_ERR_PBL_ADDR_BOUND 0xB /* pbl addr out of bounds: */
+ /* software error */
+#define TPT_ERR_SWFLUSH 0xC /* SW FLUSHED */
+#define TPT_ERR_CRC 0x10 /* CRC error */
+#define TPT_ERR_MARKER 0x11 /* Marker error */
+#define TPT_ERR_PDU_LEN_ERR 0x12 /* invalid PDU length */
+#define TPT_ERR_OUT_OF_RQE 0x13 /* out of RQE */
+#define TPT_ERR_DDP_VERSION 0x14 /* wrong DDP version */
+#define TPT_ERR_RDMA_VERSION 0x15 /* wrong RDMA version */
+#define TPT_ERR_OPCODE 0x16 /* invalid rdma opcode */
+#define TPT_ERR_DDP_QUEUE_NUM 0x17 /* invalid ddp queue number */
+#define TPT_ERR_MSN 0x18 /* MSN error */
+#define TPT_ERR_TBIT 0x19 /* tag bit not set correctly */
+#define TPT_ERR_MO 0x1A /* MO not 0 for TERMINATE */
+ /* or READ_REQ */
+#define TPT_ERR_MSN_GAP 0x1B
+#define TPT_ERR_MSN_RANGE 0x1C
+#define TPT_ERR_IRD_OVERFLOW 0x1D
+#define TPT_ERR_RQE_ADDR_BOUND 0x1E /* RQE addr out of bounds: */
+ /* software error */
+#define TPT_ERR_INTERNAL_ERR 0x1F /* internal error (opcode */
+ /* mismatch) */
+
+struct t3_swsq {
+ __u64 wr_id;
+ struct t3_cqe cqe;
+ __u32 sq_wptr;
+ __be32 read_len;
+ int opcode;
+ int complete;
+ int signaled;
+};
+
+/*
+ * A T3 WQ implements both the SQ and RQ.
+ */
+struct t3_wq {
+ union t3_wr *queue; /* DMA accessable memory */
+ dma_addr_t dma_addr; /* DMA address for HW */
+ DECLARE_PCI_UNMAP_ADDR(mapping) /* unmap kruft */
+ u32 error; /* 1 once we go to ERROR */
+ u32 qpid;
+ u32 wptr; /* idx to next available WR slot */
+ u32 size_log2; /* total wq size */
+ struct t3_swsq *sq; /* SW SQ */
+ struct t3_swsq *oldest_read; /* tracks oldest pending read */
+ u32 sq_wptr; /* sq_wptr - sq_rptr == count of */
+ u32 sq_rptr; /* pending wrs */
+ u32 sq_size_log2; /* sq size */
+ u64 *rq; /* SW RQ (holds consumer wr_ids */
+ u32 rq_wptr; /* rq_wptr - rq_rptr == count of */
+ u32 rq_rptr; /* pending wrs */
+ u64 *rq_oldest_wr; /* oldest wr on the SW RQ */
+ u32 rq_size_log2; /* rq size */
+ u32 rq_addr; /* rq adapter address */
+ void __iomem *doorbell; /* kernel db */
+ u64 udb; /* user db if any */
+};
+
+struct t3_cq {
+ u32 cqid;
+ u32 rptr;
+ u32 wptr;
+ u32 size_log2;
+ dma_addr_t dma_addr;
+ DECLARE_PCI_UNMAP_ADDR(mapping)
+ struct t3_cqe *queue;
+ struct t3_cqe *sw_queue;
+ u32 sw_rptr;
+ u32 sw_wptr;
+};
+
+#define CQ_VLD_ENTRY(ptr,size_log2,cqe) (Q_GENBIT(ptr,size_log2) == \
+ CQE_GENBIT(*cqe))
+
+static inline void cxio_set_wq_in_error(struct t3_wq *wq)
+{
+ wq->queue->flit[13] = 1;
+}
+
+static inline struct t3_cqe *cxio_next_hw_cqe(struct t3_cq *cq)
+{
+ struct t3_cqe *cqe;
+
+ cqe = cq->queue + (Q_PTR2IDX(cq->rptr, cq->size_log2));
+ if (CQ_VLD_ENTRY(cq->rptr, cq->size_log2, cqe))
+ return cqe;
+ return NULL;
+}
+
+static inline struct t3_cqe *cxio_next_sw_cqe(struct t3_cq *cq)
+{
+ struct t3_cqe *cqe;
+
+ if (!Q_EMPTY(cq->sw_rptr, cq->sw_wptr)) {
+ cqe = cq->sw_queue + (Q_PTR2IDX(cq->sw_rptr, cq->size_log2));
+ return cqe;
+ }
+ return NULL;
+}
+
+static inline struct t3_cqe *cxio_next_cqe(struct t3_cq *cq)
+{
+ struct t3_cqe *cqe;
+
+ if (!Q_EMPTY(cq->sw_rptr, cq->sw_wptr)) {
+ cqe = cq->sw_queue + (Q_PTR2IDX(cq->sw_rptr, cq->size_log2));
+ return cqe;
+ }
+ cqe = cq->queue + (Q_PTR2IDX(cq->rptr, cq->size_log2));
+ if (CQ_VLD_ENTRY(cq->rptr, cq->size_log2, cqe))
+ return cqe;
+ return NULL;
+}
+
+#endif
diff --git a/drivers/infiniband/hw/cxgb3/iwch.c b/drivers/infiniband/hw/cxgb3/iwch.c
new file mode 100644
index 00000000000..0315c9d9fce
--- /dev/null
+++ b/drivers/infiniband/hw/cxgb3/iwch.c
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2006 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+
+#include <rdma/ib_verbs.h>
+
+#include "cxgb3_offload.h"
+#include "iwch_provider.h"
+#include "iwch_user.h"
+#include "iwch.h"
+#include "iwch_cm.h"
+
+#define DRV_VERSION "1.1"
+
+MODULE_AUTHOR("Boyd Faulkner, Steve Wise");
+MODULE_DESCRIPTION("Chelsio T3 RDMA Driver");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_VERSION(DRV_VERSION);
+
+cxgb3_cpl_handler_func t3c_handlers[NUM_CPL_CMDS];
+
+static void open_rnic_dev(struct t3cdev *);
+static void close_rnic_dev(struct t3cdev *);
+
+struct cxgb3_client t3c_client = {
+ .name = "iw_cxgb3",
+ .add = open_rnic_dev,
+ .remove = close_rnic_dev,
+ .handlers = t3c_handlers,
+ .redirect = iwch_ep_redirect
+};
+
+static LIST_HEAD(dev_list);
+static DEFINE_MUTEX(dev_mutex);
+
+static void rnic_init(struct iwch_dev *rnicp)
+{
+ PDBG("%s iwch_dev %p\n", __FUNCTION__, rnicp);
+ idr_init(&rnicp->cqidr);
+ idr_init(&rnicp->qpidr);
+ idr_init(&rnicp->mmidr);
+ spin_lock_init(&rnicp->lock);
+
+ rnicp->attr.vendor_id = 0x168;
+ rnicp->attr.vendor_part_id = 7;
+ rnicp->attr.max_qps = T3_MAX_NUM_QP - 32;
+ rnicp->attr.max_wrs = (1UL << 24) - 1;
+ rnicp->attr.max_sge_per_wr = T3_MAX_SGE;
+ rnicp->attr.max_sge_per_rdma_write_wr = T3_MAX_SGE;
+ rnicp->attr.max_cqs = T3_MAX_NUM_CQ - 1;
+ rnicp->attr.max_cqes_per_cq = (1UL << 24) - 1;
+ rnicp->attr.max_mem_regs = cxio_num_stags(&rnicp->rdev);
+ rnicp->attr.max_phys_buf_entries = T3_MAX_PBL_SIZE;
+ rnicp->attr.max_pds = T3_MAX_NUM_PD - 1;
+ rnicp->attr.mem_pgsizes_bitmask = 0x7FFF; /* 4KB-128MB */
+ rnicp->attr.can_resize_wq = 0;
+ rnicp->attr.max_rdma_reads_per_qp = 8;
+ rnicp->attr.max_rdma_read_resources =
+ rnicp->attr.max_rdma_reads_per_qp * rnicp->attr.max_qps;
+ rnicp->attr.max_rdma_read_qp_depth = 8; /* IRD */
+ rnicp->attr.max_rdma_read_depth =
+ rnicp->attr.max_rdma_read_qp_depth * rnicp->attr.max_qps;
+ rnicp->attr.rq_overflow_handled = 0;
+ rnicp->attr.can_modify_ird = 0;
+ rnicp->attr.can_modify_ord = 0;
+ rnicp->attr.max_mem_windows = rnicp->attr.max_mem_regs - 1;
+ rnicp->attr.stag0_value = 1;
+ rnicp->attr.zbva_support = 1;
+ rnicp->attr.local_invalidate_fence = 1;
+ rnicp->attr.cq_overflow_detection = 1;
+ return;
+}
+
+static void open_rnic_dev(struct t3cdev *tdev)
+{
+ struct iwch_dev *rnicp;
+ static int vers_printed;
+
+ PDBG("%s t3cdev %p\n", __FUNCTION__, tdev);
+ if (!vers_printed++)
+ printk(KERN_INFO MOD "Chelsio T3 RDMA Driver - version %s\n",
+ DRV_VERSION);
+ rnicp = (struct iwch_dev *)ib_alloc_device(sizeof(*rnicp));
+ if (!rnicp) {
+ printk(KERN_ERR MOD "Cannot allocate ib device\n");
+ return;
+ }
+ rnicp->rdev.ulp = rnicp;
+ rnicp->rdev.t3cdev_p = tdev;
+
+ mutex_lock(&dev_mutex);
+
+ if (cxio_rdev_open(&rnicp->rdev)) {
+ mutex_unlock(&dev_mutex);
+ printk(KERN_ERR MOD "Unable to open CXIO rdev\n");
+ ib_dealloc_device(&rnicp->ibdev);
+ return;
+ }
+
+ rnic_init(rnicp);
+
+ list_add_tail(&rnicp->entry, &dev_list);
+ mutex_unlock(&dev_mutex);
+
+ if (iwch_register_device(rnicp)) {
+ printk(KERN_ERR MOD "Unable to register device\n");
+ close_rnic_dev(tdev);
+ }
+ printk(KERN_INFO MOD "Initialized device %s\n",
+ pci_name(rnicp->rdev.rnic_info.pdev));
+ return;
+}
+
+static void close_rnic_dev(struct t3cdev *tdev)
+{
+ struct iwch_dev *dev, *tmp;
+ PDBG("%s t3cdev %p\n", __FUNCTION__, tdev);
+ mutex_lock(&dev_mutex);
+ list_for_each_entry_safe(dev, tmp, &dev_list, entry) {
+ if (dev->rdev.t3cdev_p == tdev) {
+ list_del(&dev->entry);
+ iwch_unregister_device(dev);
+ cxio_rdev_close(&dev->rdev);
+ idr_destroy(&dev->cqidr);
+ idr_destroy(&dev->qpidr);
+ idr_destroy(&dev->mmidr);
+ ib_dealloc_device(&dev->ibdev);
+ break;
+ }
+ }
+ mutex_unlock(&dev_mutex);
+}
+
+static int __init iwch_init_module(void)
+{
+ int err;
+
+ err = cxio_hal_init();
+ if (err)
+ return err;
+ err = iwch_cm_init();
+ if (err)
+ return err;
+ cxio_register_ev_cb(iwch_ev_dispatch);
+ cxgb3_register_client(&t3c_client);
+ return 0;
+}
+
+static void __exit iwch_exit_module(void)
+{
+ cxgb3_unregister_client(&t3c_client);
+ cxio_unregister_ev_cb(iwch_ev_dispatch);
+ iwch_cm_term();
+ cxio_hal_exit();
+}
+
+module_init(iwch_init_module);
+module_exit(iwch_exit_module);
diff --git a/drivers/infiniband/hw/cxgb3/iwch.h b/drivers/infiniband/hw/cxgb3/iwch.h
new file mode 100644
index 00000000000..caf4e6007a4
--- /dev/null
+++ b/drivers/infiniband/hw/cxgb3/iwch.h
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2006 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef __IWCH_H__
+#define __IWCH_H__
+
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/idr.h>
+
+#include <rdma/ib_verbs.h>
+
+#include "cxio_hal.h"
+#include "cxgb3_offload.h"
+
+struct iwch_pd;
+struct iwch_cq;
+struct iwch_qp;
+struct iwch_mr;
+
+struct iwch_rnic_attributes {
+ u32 vendor_id;
+ u32 vendor_part_id;
+ u32 max_qps;
+ u32 max_wrs; /* Max for any SQ/RQ */
+ u32 max_sge_per_wr;
+ u32 max_sge_per_rdma_write_wr; /* for RDMA Write WR */
+ u32 max_cqs;
+ u32 max_cqes_per_cq;
+ u32 max_mem_regs;
+ u32 max_phys_buf_entries; /* for phys buf list */
+ u32 max_pds;
+
+ /*
+ * The memory page sizes supported by this RNIC.
+ * Bit position i in bitmap indicates page of
+ * size (4k)^i. Phys block list mode unsupported.
+ */
+ u32 mem_pgsizes_bitmask;
+ u8 can_resize_wq;
+
+ /*
+ * The maximum number of RDMA Reads that can be outstanding
+ * per QP with this RNIC as the target.
+ */
+ u32 max_rdma_reads_per_qp;
+
+ /*
+ * The maximum number of resources used for RDMA Reads
+ * by this RNIC with this RNIC as the target.
+ */
+ u32 max_rdma_read_resources;
+
+ /*
+ * The max depth per QP for initiation of RDMA Read
+ * by this RNIC.
+ */
+ u32 max_rdma_read_qp_depth;
+
+ /*
+ * The maximum depth for initiation of RDMA Read
+ * operations by this RNIC on all QPs
+ */
+ u32 max_rdma_read_depth;
+ u8 rq_overflow_handled;
+ u32 can_modify_ird;
+ u32 can_modify_ord;
+ u32 max_mem_windows;
+ u32 stag0_value;
+ u8 zbva_support;
+ u8 local_invalidate_fence;
+ u32 cq_overflow_detection;
+};
+
+struct iwch_dev {
+ struct ib_device ibdev;
+ struct cxio_rdev rdev;
+ u32 device_cap_flags;
+ struct iwch_rnic_attributes attr;
+ struct idr cqidr;
+ struct idr qpidr;
+ struct idr mmidr;
+ spinlock_t lock;
+ struct list_head entry;
+};
+
+static inline struct iwch_dev *to_iwch_dev(struct ib_device *ibdev)
+{
+ return container_of(ibdev, struct iwch_dev, ibdev);
+}
+
+static inline int t3b_device(const struct iwch_dev *rhp)
+{
+ return rhp->rdev.t3cdev_p->type == T3B;
+}
+
+static inline int t3a_device(const struct iwch_dev *rhp)
+{
+ return rhp->rdev.t3cdev_p->type == T3A;
+}
+
+static inline struct iwch_cq *get_chp(struct iwch_dev *rhp, u32 cqid)
+{
+ return idr_find(&rhp->cqidr, cqid);
+}
+
+static inline struct iwch_qp *get_qhp(struct iwch_dev *rhp, u32 qpid)
+{
+ return idr_find(&rhp->qpidr, qpid);
+}
+
+static inline struct iwch_mr *get_mhp(struct iwch_dev *rhp, u32 mmid)
+{
+ return idr_find(&rhp->mmidr, mmid);
+}
+
+static inline int insert_handle(struct iwch_dev *rhp, struct idr *idr,
+ void *handle, u32 id)
+{
+ int ret;
+ u32 newid;
+
+ do {
+ if (!idr_pre_get(idr, GFP_KERNEL)) {
+ return -ENOMEM;
+ }
+ spin_lock_irq(&rhp->lock);
+ ret = idr_get_new_above(idr, handle, id, &newid);
+ BUG_ON(newid != id);
+ spin_unlock_irq(&rhp->lock);
+ } while (ret == -EAGAIN);
+
+ return ret;
+}
+
+static inline void remove_handle(struct iwch_dev *rhp, struct idr *idr, u32 id)
+{
+ spin_lock_irq(&rhp->lock);
+ idr_remove(idr, id);
+ spin_unlock_irq(&rhp->lock);
+}
+
+extern struct cxgb3_client t3c_client;
+extern cxgb3_cpl_handler_func t3c_handlers[NUM_CPL_CMDS];
+extern void iwch_ev_dispatch(struct cxio_rdev *rdev_p, struct sk_buff *skb);
+
+#endif
diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c
new file mode 100644
index 00000000000..e5442e34b78
--- /dev/null
+++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c
@@ -0,0 +1,2080 @@
+/*
+ * Copyright (c) 2006 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/workqueue.h>
+#include <linux/skbuff.h>
+#include <linux/timer.h>
+#include <linux/notifier.h>
+
+#include <net/neighbour.h>
+#include <net/netevent.h>
+#include <net/route.h>
+
+#include "tcb.h"
+#include "cxgb3_offload.h"
+#include "iwch.h"
+#include "iwch_provider.h"
+#include "iwch_cm.h"
+
+static char *states[] = {
+ "idle",
+ "listen",
+ "connecting",
+ "mpa_wait_req",
+ "mpa_req_sent",
+ "mpa_req_rcvd",
+ "mpa_rep_sent",
+ "fpdu_mode",
+ "aborting",
+ "closing",
+ "moribund",
+ "dead",
+ NULL,
+};
+
+static int ep_timeout_secs = 10;
+module_param(ep_timeout_secs, int, 0444);
+MODULE_PARM_DESC(ep_timeout_secs, "CM Endpoint operation timeout "
+ "in seconds (default=10)");
+
+static int mpa_rev = 1;
+module_param(mpa_rev, int, 0444);
+MODULE_PARM_DESC(mpa_rev, "MPA Revision, 0 supports amso1100, "
+ "1 is spec compliant. (default=1)");
+
+static int markers_enabled = 0;
+module_param(markers_enabled, int, 0444);
+MODULE_PARM_DESC(markers_enabled, "Enable MPA MARKERS (default(0)=disabled)");
+
+static int crc_enabled = 1;
+module_param(crc_enabled, int, 0444);
+MODULE_PARM_DESC(crc_enabled, "Enable MPA CRC (default(1)=enabled)");
+
+static int rcv_win = 256 * 1024;
+module_param(rcv_win, int, 0444);
+MODULE_PARM_DESC(rcv_win, "TCP receive window in bytes (default=256)");
+
+static int snd_win = 32 * 1024;
+module_param(snd_win, int, 0444);
+MODULE_PARM_DESC(snd_win, "TCP send window in bytes (default=32KB)");
+
+static unsigned int nocong = 0;
+module_param(nocong, uint, 0444);
+MODULE_PARM_DESC(nocong, "Turn off congestion control (default=0)");
+
+static unsigned int cong_flavor = 1;
+module_param(cong_flavor, uint, 0444);
+MODULE_PARM_DESC(cong_flavor, "TCP Congestion control flavor (default=1)");
+
+static void process_work(struct work_struct *work);
+static struct workqueue_struct *workq;
+static DECLARE_WORK(skb_work, process_work);
+
+static struct sk_buff_head rxq;
+static cxgb3_cpl_handler_func work_handlers[NUM_CPL_CMDS];
+
+static struct sk_buff *get_skb(struct sk_buff *skb, int len, gfp_t gfp);
+static void ep_timeout(unsigned long arg);
+static void connect_reply_upcall(struct iwch_ep *ep, int status);
+
+static void start_ep_timer(struct iwch_ep *ep)
+{
+ PDBG("%s ep %p\n", __FUNCTION__, ep);
+ if (timer_pending(&ep->timer)) {
+ PDBG("%s stopped / restarted timer ep %p\n", __FUNCTION__, ep);
+ del_timer_sync(&ep->timer);
+ } else
+ get_ep(&ep->com);
+ ep->timer.expires = jiffies + ep_timeout_secs * HZ;
+ ep->timer.data = (unsigned long)ep;
+ ep->timer.function = ep_timeout;
+ add_timer(&ep->timer);
+}
+
+static void stop_ep_timer(struct iwch_ep *ep)
+{
+ PDBG("%s ep %p\n", __FUNCTION__, ep);
+ del_timer_sync(&ep->timer);
+ put_ep(&ep->com);
+}
+
+static void release_tid(struct t3cdev *tdev, u32 hwtid, struct sk_buff *skb)
+{
+ struct cpl_tid_release *req;
+
+ skb = get_skb(skb, sizeof *req, GFP_KERNEL);
+ if (!skb)
+ return;
+ req = (struct cpl_tid_release *) skb_put(skb, sizeof(*req));
+ req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
+ OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_TID_RELEASE, hwtid));
+ skb->priority = CPL_PRIORITY_SETUP;
+ tdev->send(tdev, skb);
+ return;
+}
+
+int iwch_quiesce_tid(struct iwch_ep *ep)
+{
+ struct cpl_set_tcb_field *req;
+ struct sk_buff *skb = get_skb(NULL, sizeof(*req), GFP_KERNEL);
+
+ if (!skb)
+ return -ENOMEM;
+ req = (struct cpl_set_tcb_field *) skb_put(skb, sizeof(*req));
+ req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
+ req->wr.wr_lo = htonl(V_WR_TID(ep->hwtid));
+ OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, ep->hwtid));
+ req->reply = 0;
+ req->cpu_idx = 0;
+ req->word = htons(W_TCB_RX_QUIESCE);
+ req->mask = cpu_to_be64(1ULL << S_TCB_RX_QUIESCE);
+ req->val = cpu_to_be64(1 << S_TCB_RX_QUIESCE);
+
+ skb->priority = CPL_PRIORITY_DATA;
+ ep->com.tdev->send(ep->com.tdev, skb);
+ return 0;
+}
+
+int iwch_resume_tid(struct iwch_ep *ep)
+{
+ struct cpl_set_tcb_field *req;
+ struct sk_buff *skb = get_skb(NULL, sizeof(*req), GFP_KERNEL);
+
+ if (!skb)
+ return -ENOMEM;
+ req = (struct cpl_set_tcb_field *) skb_put(skb, sizeof(*req));
+ req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
+ req->wr.wr_lo = htonl(V_WR_TID(ep->hwtid));
+ OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, ep->hwtid));
+ req->reply = 0;
+ req->cpu_idx = 0;
+ req->word = htons(W_TCB_RX_QUIESCE);
+ req->mask = cpu_to_be64(1ULL << S_TCB_RX_QUIESCE);
+ req->val = 0;
+
+ skb->priority = CPL_PRIORITY_DATA;
+ ep->com.tdev->send(ep->com.tdev, skb);
+ return 0;
+}
+
+static void set_emss(struct iwch_ep *ep, u16 opt)
+{
+ PDBG("%s ep %p opt %u\n", __FUNCTION__, ep, opt);
+ ep->emss = T3C_DATA(ep->com.tdev)->mtus[G_TCPOPT_MSS(opt)] - 40;
+ if (G_TCPOPT_TSTAMP(opt))
+ ep->emss -= 12;
+ if (ep->emss < 128)
+ ep->emss = 128;
+ PDBG("emss=%d\n", ep->emss);
+}
+
+static enum iwch_ep_state state_read(struct iwch_ep_common *epc)
+{
+ unsigned long flags;
+ enum iwch_ep_state state;
+
+ spin_lock_irqsave(&epc->lock, flags);
+ state = epc->state;
+ spin_unlock_irqrestore(&epc->lock, flags);
+ return state;
+}
+
+static inline void __state_set(struct iwch_ep_common *epc,
+ enum iwch_ep_state new)
+{
+ epc->state = new;
+}
+
+static void state_set(struct iwch_ep_common *epc, enum iwch_ep_state new)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&epc->lock, flags);
+ PDBG("%s - %s -> %s\n", __FUNCTION__, states[epc->state], states[new]);
+ __state_set(epc, new);
+ spin_unlock_irqrestore(&epc->lock, flags);
+ return;
+}
+
+static void *alloc_ep(int size, gfp_t gfp)
+{
+ struct iwch_ep_common *epc;
+
+ epc = kmalloc(size, gfp);
+ if (epc) {
+ memset(epc, 0, size);
+ kref_init(&epc->kref);
+ spin_lock_init(&epc->lock);
+ init_waitqueue_head(&epc->waitq);
+ }
+ PDBG("%s alloc ep %p\n", __FUNCTION__, epc);
+ return epc;
+}
+
+void __free_ep(struct kref *kref)
+{
+ struct iwch_ep_common *epc;
+ epc = container_of(kref, struct iwch_ep_common, kref);
+ PDBG("%s ep %p state %s\n", __FUNCTION__, epc, states[state_read(epc)]);
+ kfree(epc);
+}
+
+static void release_ep_resources(struct iwch_ep *ep)
+{
+ PDBG("%s ep %p tid %d\n", __FUNCTION__, ep, ep->hwtid);
+ cxgb3_remove_tid(ep->com.tdev, (void *)ep, ep->hwtid);
+ dst_release(ep->dst);
+ l2t_release(L2DATA(ep->com.tdev), ep->l2t);
+ if (ep->com.tdev->type == T3B)
+ release_tid(ep->com.tdev, ep->hwtid, NULL);
+ put_ep(&ep->com);
+}
+
+static void process_work(struct work_struct *work)
+{
+ struct sk_buff *skb = NULL;
+ void *ep;
+ struct t3cdev *tdev;
+ int ret;
+
+ while ((skb = skb_dequeue(&rxq))) {
+ ep = *((void **) (skb->cb));
+ tdev = *((struct t3cdev **) (skb->cb + sizeof(void *)));
+ ret = work_handlers[G_OPCODE(ntohl((__force __be32)skb->csum))](tdev, skb, ep);
+ if (ret & CPL_RET_BUF_DONE)
+ kfree_skb(skb);
+
+ /*
+ * ep was referenced in sched(), and is freed here.
+ */
+ put_ep((struct iwch_ep_common *)ep);
+ }
+}
+
+static int status2errno(int status)
+{
+ switch (status) {
+ case CPL_ERR_NONE:
+ return 0;
+ case CPL_ERR_CONN_RESET:
+ return -ECONNRESET;
+ case CPL_ERR_ARP_MISS:
+ return -EHOSTUNREACH;
+ case CPL_ERR_CONN_TIMEDOUT:
+ return -ETIMEDOUT;
+ case CPL_ERR_TCAM_FULL:
+ return -ENOMEM;
+ case CPL_ERR_CONN_EXIST:
+ return -EADDRINUSE;
+ default:
+ return -EIO;
+ }
+}
+
+/*
+ * Try and reuse skbs already allocated...
+ */
+static struct sk_buff *get_skb(struct sk_buff *skb, int len, gfp_t gfp)
+{
+ if (skb) {
+ BUG_ON(skb_cloned(skb));
+ skb_trim(skb, 0);
+ skb_get(skb);
+ } else {
+ skb = alloc_skb(len, gfp);
+ }
+ return skb;
+}
+
+static struct rtable *find_route(struct t3cdev *dev, __be32 local_ip,
+ __be32 peer_ip, __be16 local_port,
+ __be16 peer_port, u8 tos)
+{
+ struct rtable *rt;
+ struct flowi fl = {
+ .oif = 0,
+ .nl_u = {
+ .ip4_u = {
+ .daddr = peer_ip,
+ .saddr = local_ip,
+ .tos = tos}
+ },
+ .proto = IPPROTO_TCP,
+ .uli_u = {
+ .ports = {
+ .sport = local_port,
+ .dport = peer_port}
+ }
+ };
+
+ if (ip_route_output_flow(&rt, &fl, NULL, 0))
+ return NULL;
+ return rt;
+}
+
+static unsigned int find_best_mtu(const struct t3c_data *d, unsigned short mtu)
+{
+ int i = 0;
+
+ while (i < d->nmtus - 1 && d->mtus[i + 1] <= mtu)
+ ++i;
+ return i;
+}
+
+static void arp_failure_discard(struct t3cdev *dev, struct sk_buff *skb)
+{
+ PDBG("%s t3cdev %p\n", __FUNCTION__, dev);
+ kfree_skb(skb);
+}
+
+/*
+ * Handle an ARP failure for an active open.
+ */
+static void act_open_req_arp_failure(struct t3cdev *dev, struct sk_buff *skb)
+{
+ printk(KERN_ERR MOD "ARP failure duing connect\n");
+ kfree_skb(skb);
+}
+
+/*
+ * Handle an ARP failure for a CPL_ABORT_REQ. Change it into a no RST variant
+ * and send it along.
+ */
+static void abort_arp_failure(struct t3cdev *dev, struct sk_buff *skb)
+{
+ struct cpl_abort_req *req = cplhdr(skb);
+
+ PDBG("%s t3cdev %p\n", __FUNCTION__, dev);
+ req->cmd = CPL_ABORT_NO_RST;
+ cxgb3_ofld_send(dev, skb);
+}
+
+static int send_halfclose(struct iwch_ep *ep, gfp_t gfp)
+{
+ struct cpl_close_con_req *req;
+ struct sk_buff *skb;
+
+ PDBG("%s ep %p\n", __FUNCTION__, ep);
+ skb = get_skb(NULL, sizeof(*req), gfp);
+ if (!skb) {
+ printk(KERN_ERR MOD "%s - failed to alloc skb\n", __FUNCTION__);
+ return -ENOMEM;
+ }
+ skb->priority = CPL_PRIORITY_DATA;
+ set_arp_failure_handler(skb, arp_failure_discard);
+ req = (struct cpl_close_con_req *) skb_put(skb, sizeof(*req));
+ req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_CLOSE_CON));
+ req->wr.wr_lo = htonl(V_WR_TID(ep->hwtid));
+ OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_CLOSE_CON_REQ, ep->hwtid));
+ l2t_send(ep->com.tdev, skb, ep->l2t);
+ return 0;
+}
+
+static int send_abort(struct iwch_ep *ep, struct sk_buff *skb, gfp_t gfp)
+{
+ struct cpl_abort_req *req;
+
+ PDBG("%s ep %p\n", __FUNCTION__, ep);
+ skb = get_skb(skb, sizeof(*req), gfp);
+ if (!skb) {
+ printk(KERN_ERR MOD "%s - failed to alloc skb.\n",
+ __FUNCTION__);
+ return -ENOMEM;
+ }
+ skb->priority = CPL_PRIORITY_DATA;
+ set_arp_failure_handler(skb, abort_arp_failure);
+ req = (struct cpl_abort_req *) skb_put(skb, sizeof(*req));
+ req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_HOST_ABORT_CON_REQ));
+ req->wr.wr_lo = htonl(V_WR_TID(ep->hwtid));
+ OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_ABORT_REQ, ep->hwtid));
+ req->cmd = CPL_ABORT_SEND_RST;
+ l2t_send(ep->com.tdev, skb, ep->l2t);
+ return 0;
+}
+
+static int send_connect(struct iwch_ep *ep)
+{
+ struct cpl_act_open_req *req;
+ struct sk_buff *skb;
+ u32 opt0h, opt0l, opt2;
+ unsigned int mtu_idx;
+ int wscale;
+
+ PDBG("%s ep %p\n", __FUNCTION__, ep);
+
+ skb = get_skb(NULL, sizeof(*req), GFP_KERNEL);
+ if (!skb) {
+ printk(KERN_ERR MOD "%s - failed to alloc skb.\n",
+ __FUNCTION__);
+ return -ENOMEM;
+ }
+ mtu_idx = find_best_mtu(T3C_DATA(ep->com.tdev), dst_mtu(ep->dst));
+ wscale = compute_wscale(rcv_win);
+ opt0h = V_NAGLE(0) |
+ V_NO_CONG(nocong) |
+ V_KEEP_ALIVE(1) |
+ F_TCAM_BYPASS |
+ V_WND_SCALE(wscale) |
+ V_MSS_IDX(mtu_idx) |
+ V_L2T_IDX(ep->l2t->idx) | V_TX_CHANNEL(ep->l2t->smt_idx);
+ opt0l = V_TOS((ep->tos >> 2) & M_TOS) | V_RCV_BUFSIZ(rcv_win>>10);
+ opt2 = V_FLAVORS_VALID(1) | V_CONG_CONTROL_FLAVOR(cong_flavor);
+ skb->priority = CPL_PRIORITY_SETUP;
+ set_arp_failure_handler(skb, act_open_req_arp_failure);
+
+ req = (struct cpl_act_open_req *) skb_put(skb, sizeof(*req));
+ req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
+ OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_ACT_OPEN_REQ, ep->atid));
+ req->local_port = ep->com.local_addr.sin_port;
+ req->peer_port = ep->com.remote_addr.sin_port;
+ req->local_ip = ep->com.local_addr.sin_addr.s_addr;
+ req->peer_ip = ep->com.remote_addr.sin_addr.s_addr;
+ req->opt0h = htonl(opt0h);
+ req->opt0l = htonl(opt0l);
+ req->params = 0;
+ req->opt2 = htonl(opt2);
+ l2t_send(ep->com.tdev, skb, ep->l2t);
+ return 0;
+}
+
+static void send_mpa_req(struct iwch_ep *ep, struct sk_buff *skb)
+{
+ int mpalen;
+ struct tx_data_wr *req;
+ struct mpa_message *mpa;
+ int len;
+
+ PDBG("%s ep %p pd_len %d\n", __FUNCTION__, ep, ep->plen);
+
+ BUG_ON(skb_cloned(skb));
+
+ mpalen = sizeof(*mpa) + ep->plen;
+ if (skb->data + mpalen + sizeof(*req) > skb->end) {
+ kfree_skb(skb);
+ skb=alloc_skb(mpalen + sizeof(*req), GFP_KERNEL);
+ if (!skb) {
+ connect_reply_upcall(ep, -ENOMEM);
+ return;
+ }
+ }
+ skb_trim(skb, 0);
+ skb_reserve(skb, sizeof(*req));
+ skb_put(skb, mpalen);
+ skb->priority = CPL_PRIORITY_DATA;
+ mpa = (struct mpa_message *) skb->data;
+ memset(mpa, 0, sizeof(*mpa));
+ memcpy(mpa->key, MPA_KEY_REQ, sizeof(mpa->key));
+ mpa->flags = (crc_enabled ? MPA_CRC : 0) |
+ (markers_enabled ? MPA_MARKERS : 0);
+ mpa->private_data_size = htons(ep->plen);
+ mpa->revision = mpa_rev;
+
+ if (ep->plen)
+ memcpy(mpa->private_data, ep->mpa_pkt + sizeof(*mpa), ep->plen);
+
+ /*
+ * Reference the mpa skb. This ensures the data area
+ * will remain in memory until the hw acks the tx.
+ * Function tx_ack() will deref it.
+ */
+ skb_get(skb);
+ set_arp_failure_handler(skb, arp_failure_discard);
+ skb->h.raw = skb->data;
+ len = skb->len;
+ req = (struct tx_data_wr *) skb_push(skb, sizeof(*req));
+ req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_TX_DATA));
+ req->wr_lo = htonl(V_WR_TID(ep->hwtid));
+ req->len = htonl(len);
+ req->param = htonl(V_TX_PORT(ep->l2t->smt_idx) |
+ V_TX_SNDBUF(snd_win>>15));
+ req->flags = htonl(F_TX_IMM_ACK|F_TX_INIT);
+ req->sndseq = htonl(ep->snd_seq);
+ BUG_ON(ep->mpa_skb);
+ ep->mpa_skb = skb;
+ l2t_send(ep->com.tdev, skb, ep->l2t);
+ start_ep_timer(ep);
+ state_set(&ep->com, MPA_REQ_SENT);
+ return;
+}
+
+static int send_mpa_reject(struct iwch_ep *ep, const void *pdata, u8 plen)
+{
+ int mpalen;
+ struct tx_data_wr *req;
+ struct mpa_message *mpa;
+ struct sk_buff *skb;
+
+ PDBG("%s ep %p plen %d\n", __FUNCTION__, ep, plen);
+
+ mpalen = sizeof(*mpa) + plen;
+
+ skb = get_skb(NULL, mpalen + sizeof(*req), GFP_KERNEL);
+ if (!skb) {
+ printk(KERN_ERR MOD "%s - cannot alloc skb!\n", __FUNCTION__);
+ return -ENOMEM;
+ }
+ skb_reserve(skb, sizeof(*req));
+ mpa = (struct mpa_message *) skb_put(skb, mpalen);
+ memset(mpa, 0, sizeof(*mpa));
+ memcpy(mpa->key, MPA_KEY_REP, sizeof(mpa->key));
+ mpa->flags = MPA_REJECT;
+ mpa->revision = mpa_rev;
+ mpa->private_data_size = htons(plen);
+ if (plen)
+ memcpy(mpa->private_data, pdata, plen);
+
+ /*
+ * Reference the mpa skb again. This ensures the data area
+ * will remain in memory until the hw acks the tx.
+ * Function tx_ack() will deref it.
+ */
+ skb_get(skb);
+ skb->priority = CPL_PRIORITY_DATA;
+ set_arp_failure_handler(skb, arp_failure_discard);
+ skb->h.raw = skb->data;
+ req = (struct tx_data_wr *) skb_push(skb, sizeof(*req));
+ req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_TX_DATA));
+ req->wr_lo = htonl(V_WR_TID(ep->hwtid));
+ req->len = htonl(mpalen);
+ req->param = htonl(V_TX_PORT(ep->l2t->smt_idx) |
+ V_TX_SNDBUF(snd_win>>15));
+ req->flags = htonl(F_TX_IMM_ACK|F_TX_INIT);
+ req->sndseq = htonl(ep->snd_seq);
+ BUG_ON(ep->mpa_skb);
+ ep->mpa_skb = skb;
+ l2t_send(ep->com.tdev, skb, ep->l2t);
+ return 0;
+}
+
+static int send_mpa_reply(struct iwch_ep *ep, const void *pdata, u8 plen)
+{
+ int mpalen;
+ struct tx_data_wr *req;
+ struct mpa_message *mpa;
+ int len;
+ struct sk_buff *skb;
+
+ PDBG("%s ep %p plen %d\n", __FUNCTION__, ep, plen);
+
+ mpalen = sizeof(*mpa) + plen;
+
+ skb = get_skb(NULL, mpalen + sizeof(*req), GFP_KERNEL);
+ if (!skb) {
+ printk(KERN_ERR MOD "%s - cannot alloc skb!\n", __FUNCTION__);
+ return -ENOMEM;
+ }
+ skb->priority = CPL_PRIORITY_DATA;
+ skb_reserve(skb, sizeof(*req));
+ mpa = (struct mpa_message *) skb_put(skb, mpalen);
+ memset(mpa, 0, sizeof(*mpa));
+ memcpy(mpa->key, MPA_KEY_REP, sizeof(mpa->key));
+ mpa->flags = (ep->mpa_attr.crc_enabled ? MPA_CRC : 0) |
+ (markers_enabled ? MPA_MARKERS : 0);
+ mpa->revision = mpa_rev;
+ mpa->private_data_size = htons(plen);
+ if (plen)
+ memcpy(mpa->private_data, pdata, plen);
+
+ /*
+ * Reference the mpa skb. This ensures the data area
+ * will remain in memory until the hw acks the tx.
+ * Function tx_ack() will deref it.
+ */
+ skb_get(skb);
+ set_arp_failure_handler(skb, arp_failure_discard);
+ skb->h.raw = skb->data;
+ len = skb->len;
+ req = (struct tx_data_wr *) skb_push(skb, sizeof(*req));
+ req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_TX_DATA));
+ req->wr_lo = htonl(V_WR_TID(ep->hwtid));
+ req->len = htonl(len);
+ req->param = htonl(V_TX_PORT(ep->l2t->smt_idx) |
+ V_TX_SNDBUF(snd_win>>15));
+ req->flags = htonl(F_TX_MORE | F_TX_IMM_ACK | F_TX_INIT);
+ req->sndseq = htonl(ep->snd_seq);
+ ep->mpa_skb = skb;
+ state_set(&ep->com, MPA_REP_SENT);
+ l2t_send(ep->com.tdev, skb, ep->l2t);
+ return 0;
+}
+
+static int act_establish(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
+{
+ struct iwch_ep *ep = ctx;
+ struct cpl_act_establish *req = cplhdr(skb);
+ unsigned int tid = GET_TID(req);
+
+ PDBG("%s ep %p tid %d\n", __FUNCTION__, ep, tid);
+
+ dst_confirm(ep->dst);
+
+ /* setup the hwtid for this connection */
+ ep->hwtid = tid;
+ cxgb3_insert_tid(ep->com.tdev, &t3c_client, ep, tid);
+
+ ep->snd_seq = ntohl(req->snd_isn);
+
+ set_emss(ep, ntohs(req->tcp_opt));
+
+ /* dealloc the atid */
+ cxgb3_free_atid(ep->com.tdev, ep->atid);
+
+ /* start MPA negotiation */
+ send_mpa_req(ep, skb);
+
+ return 0;
+}
+
+static void abort_connection(struct iwch_ep *ep, struct sk_buff *skb, gfp_t gfp)
+{
+ PDBG("%s ep %p\n", __FILE__, ep);
+ state_set(&ep->com, ABORTING);
+ send_abort(ep, skb, gfp);
+}
+
+static void close_complete_upcall(struct iwch_ep *ep)
+{
+ struct iw_cm_event event;
+
+ PDBG("%s ep %p\n", __FUNCTION__, ep);
+ memset(&event, 0, sizeof(event));
+ event.event = IW_CM_EVENT_CLOSE;
+ if (ep->com.cm_id) {
+ PDBG("close complete delivered ep %p cm_id %p tid %d\n",
+ ep, ep->com.cm_id, ep->hwtid);
+ ep->com.cm_id->event_handler(ep->com.cm_id, &event);
+ ep->com.cm_id->rem_ref(ep->com.cm_id);
+ ep->com.cm_id = NULL;
+ ep->com.qp = NULL;
+ }
+}
+
+static void peer_close_upcall(struct iwch_ep *ep)
+{
+ struct iw_cm_event event;
+
+ PDBG("%s ep %p\n", __FUNCTION__, ep);
+ memset(&event, 0, sizeof(event));
+ event.event = IW_CM_EVENT_DISCONNECT;
+ if (ep->com.cm_id) {
+ PDBG("peer close delivered ep %p cm_id %p tid %d\n",
+ ep, ep->com.cm_id, ep->hwtid);
+ ep->com.cm_id->event_handler(ep->com.cm_id, &event);
+ }
+}
+
+static void peer_abort_upcall(struct iwch_ep *ep)
+{
+ struct iw_cm_event event;
+
+ PDBG("%s ep %p\n", __FUNCTION__, ep);
+ memset(&event, 0, sizeof(event));
+ event.event = IW_CM_EVENT_CLOSE;
+ event.status = -ECONNRESET;
+ if (ep->com.cm_id) {
+ PDBG("abort delivered ep %p cm_id %p tid %d\n", ep,
+ ep->com.cm_id, ep->hwtid);
+ ep->com.cm_id->event_handler(ep->com.cm_id, &event);
+ ep->com.cm_id->rem_ref(ep->com.cm_id);
+ ep->com.cm_id = NULL;
+ ep->com.qp = NULL;
+ }
+}
+
+static void connect_reply_upcall(struct iwch_ep *ep, int status)
+{
+ struct iw_cm_event event;
+
+ PDBG("%s ep %p status %d\n", __FUNCTION__, ep, status);
+ memset(&event, 0, sizeof(event));
+ event.event = IW_CM_EVENT_CONNECT_REPLY;
+ event.status = status;
+ event.local_addr = ep->com.local_addr;
+ event.remote_addr = ep->com.remote_addr;
+
+ if ((status == 0) || (status == -ECONNREFUSED)) {
+ event.private_data_len = ep->plen;
+ event.private_data = ep->mpa_pkt + sizeof(struct mpa_message);
+ }
+ if (ep->com.cm_id) {
+ PDBG("%s ep %p tid %d status %d\n", __FUNCTION__, ep,
+ ep->hwtid, status);
+ ep->com.cm_id->event_handler(ep->com.cm_id, &event);
+ }
+ if (status < 0) {
+ ep->com.cm_id->rem_ref(ep->com.cm_id);
+ ep->com.cm_id = NULL;
+ ep->com.qp = NULL;
+ }
+}
+
+static void connect_request_upcall(struct iwch_ep *ep)
+{
+ struct iw_cm_event event;
+
+ PDBG("%s ep %p tid %d\n", __FUNCTION__, ep, ep->hwtid);
+ memset(&event, 0, sizeof(event));
+ event.event = IW_CM_EVENT_CONNECT_REQUEST;
+ event.local_addr = ep->com.local_addr;
+ event.remote_addr = ep->com.remote_addr;
+ event.private_data_len = ep->plen;
+ event.private_data = ep->mpa_pkt + sizeof(struct mpa_message);
+ event.provider_data = ep;
+ if (state_read(&ep->parent_ep->com) != DEAD)
+ ep->parent_ep->com.cm_id->event_handler(
+ ep->parent_ep->com.cm_id,
+ &event);
+ put_ep(&ep->parent_ep->com);
+ ep->parent_ep = NULL;
+}
+
+static void established_upcall(struct iwch_ep *ep)
+{
+ struct iw_cm_event event;
+
+ PDBG("%s ep %p\n", __FUNCTION__, ep);
+ memset(&event, 0, sizeof(event));
+ event.event = IW_CM_EVENT_ESTABLISHED;
+ if (ep->com.cm_id) {
+ PDBG("%s ep %p tid %d\n", __FUNCTION__, ep, ep->hwtid);
+ ep->com.cm_id->event_handler(ep->com.cm_id, &event);
+ }
+}
+
+static int update_rx_credits(struct iwch_ep *ep, u32 credits)
+{
+ struct cpl_rx_data_ack *req;
+ struct sk_buff *skb;
+
+ PDBG("%s ep %p credits %u\n", __FUNCTION__, ep, credits);
+ skb = get_skb(NULL, sizeof(*req), GFP_KERNEL);
+ if (!skb) {
+ printk(KERN_ERR MOD "update_rx_credits - cannot alloc skb!\n");
+ return 0;
+ }
+
+ req = (struct cpl_rx_data_ack *) skb_put(skb, sizeof(*req));
+ req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
+ OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_RX_DATA_ACK, ep->hwtid));
+ req->credit_dack = htonl(V_RX_CREDITS(credits) | V_RX_FORCE_ACK(1));
+ skb->priority = CPL_PRIORITY_ACK;
+ ep->com.tdev->send(ep->com.tdev, skb);
+ return credits;
+}
+
+static void process_mpa_reply(struct iwch_ep *ep, struct sk_buff *skb)
+{
+ struct mpa_message *mpa;
+ u16 plen;
+ struct iwch_qp_attributes attrs;
+ enum iwch_qp_attr_mask mask;
+ int err;
+
+ PDBG("%s ep %p\n", __FUNCTION__, ep);
+
+ /*
+ * Stop mpa timer. If it expired, then the state has
+ * changed and we bail since ep_timeout already aborted
+ * the connection.
+ */
+ stop_ep_timer(ep);
+ if (state_read(&ep->com) != MPA_REQ_SENT)
+ return;
+
+ /*
+ * If we get more than the supported amount of private data
+ * then we must fail this connection.
+ */
+ if (ep->mpa_pkt_len + skb->len > sizeof(ep->mpa_pkt)) {
+ err = -EINVAL;
+ goto err;
+ }
+
+ /*
+ * copy the new data into our accumulation buffer.
+ */
+ memcpy(&(ep->mpa_pkt[ep->mpa_pkt_len]), skb->data, skb->len);
+ ep->mpa_pkt_len += skb->len;
+
+ /*
+ * if we don't even have the mpa message, then bail.
+ */
+ if (ep->mpa_pkt_len < sizeof(*mpa))
+ return;
+ mpa = (struct mpa_message *) ep->mpa_pkt;
+
+ /* Validate MPA header. */
+ if (mpa->revision != mpa_rev) {
+ err = -EPROTO;
+ goto err;
+ }
+ if (memcmp(mpa->key, MPA_KEY_REP, sizeof(mpa->key))) {
+ err = -EPROTO;
+ goto err;
+ }
+
+ plen = ntohs(mpa->private_data_size);
+
+ /*
+ * Fail if there's too much private data.
+ */
+ if (plen > MPA_MAX_PRIVATE_DATA) {
+ err = -EPROTO;
+ goto err;
+ }
+
+ /*
+ * If plen does not account for pkt size
+ */
+ if (ep->mpa_pkt_len > (sizeof(*mpa) + plen)) {
+ err = -EPROTO;
+ goto err;
+ }
+
+ ep->plen = (u8) plen;
+
+ /*
+ * If we don't have all the pdata yet, then bail.
+ * We'll continue process when more data arrives.
+ */
+ if (ep->mpa_pkt_len < (sizeof(*mpa) + plen))
+ return;
+
+ if (mpa->flags & MPA_REJECT) {
+ err = -ECONNREFUSED;
+ goto err;
+ }
+
+ /*
+ * If we get here we have accumulated the entire mpa
+ * start reply message including private data. And
+ * the MPA header is valid.
+ */
+ state_set(&ep->com, FPDU_MODE);
+ ep->mpa_attr.crc_enabled = (mpa->flags & MPA_CRC) | crc_enabled ? 1 : 0;
+ ep->mpa_attr.recv_marker_enabled = markers_enabled;
+ ep->mpa_attr.xmit_marker_enabled = mpa->flags & MPA_MARKERS ? 1 : 0;
+ ep->mpa_attr.version = mpa_rev;
+ PDBG("%s - crc_enabled=%d, recv_marker_enabled=%d, "
+ "xmit_marker_enabled=%d, version=%d\n", __FUNCTION__,
+ ep->mpa_attr.crc_enabled, ep->mpa_attr.recv_marker_enabled,
+ ep->mpa_attr.xmit_marker_enabled, ep->mpa_attr.version);
+
+ attrs.mpa_attr = ep->mpa_attr;
+ attrs.max_ird = ep->ird;
+ attrs.max_ord = ep->ord;
+ attrs.llp_stream_handle = ep;
+ attrs.next_state = IWCH_QP_STATE_RTS;
+
+ mask = IWCH_QP_ATTR_NEXT_STATE |
+ IWCH_QP_ATTR_LLP_STREAM_HANDLE | IWCH_QP_ATTR_MPA_ATTR |
+ IWCH_QP_ATTR_MAX_IRD | IWCH_QP_ATTR_MAX_ORD;
+
+ /* bind QP and TID with INIT_WR */
+ err = iwch_modify_qp(ep->com.qp->rhp,
+ ep->com.qp, mask, &attrs, 1);
+ if (!err)
+ goto out;
+err:
+ abort_connection(ep, skb, GFP_KERNEL);
+out:
+ connect_reply_upcall(ep, err);
+ return;
+}
+
+static void process_mpa_request(struct iwch_ep *ep, struct sk_buff *skb)
+{
+ struct mpa_message *mpa;
+ u16 plen;
+
+ PDBG("%s ep %p\n", __FUNCTION__, ep);
+
+ /*
+ * Stop mpa timer. If it expired, then the state has
+ * changed and we bail since ep_timeout already aborted
+ * the connection.
+ */
+ stop_ep_timer(ep);
+ if (state_read(&ep->com) != MPA_REQ_WAIT)
+ return;
+
+ /*
+ * If we get more than the supported amount of private data
+ * then we must fail this connection.
+ */
+ if (ep->mpa_pkt_len + skb->len > sizeof(ep->mpa_pkt)) {
+ abort_connection(ep, skb, GFP_KERNEL);
+ return;
+ }
+
+ PDBG("%s enter (%s line %u)\n", __FUNCTION__, __FILE__, __LINE__);
+
+ /*
+ * Copy the new data into our accumulation buffer.
+ */
+ memcpy(&(ep->mpa_pkt[ep->mpa_pkt_len]), skb->data, skb->len);
+ ep->mpa_pkt_len += skb->len;
+
+ /*
+ * If we don't even have the mpa message, then bail.
+ * We'll continue process when more data arrives.
+ */
+ if (ep->mpa_pkt_len < sizeof(*mpa))
+ return;
+ PDBG("%s enter (%s line %u)\n", __FUNCTION__, __FILE__, __LINE__);
+ mpa = (struct mpa_message *) ep->mpa_pkt;
+
+ /*
+ * Validate MPA Header.
+ */
+ if (mpa->revision != mpa_rev) {
+ abort_connection(ep, skb, GFP_KERNEL);
+ return;
+ }
+
+ if (memcmp(mpa->key, MPA_KEY_REQ, sizeof(mpa->key))) {
+ abort_connection(ep, skb, GFP_KERNEL);
+ return;
+ }
+
+ plen = ntohs(mpa->private_data_size);
+
+ /*
+ * Fail if there's too much private data.
+ */
+ if (plen > MPA_MAX_PRIVATE_DATA) {
+ abort_connection(ep, skb, GFP_KERNEL);
+ return;
+ }
+
+ /*
+ * If plen does not account for pkt size
+ */
+ if (ep->mpa_pkt_len > (sizeof(*mpa) + plen)) {
+ abort_connection(ep, skb, GFP_KERNEL);
+ return;
+ }
+ ep->plen = (u8) plen;
+
+ /*
+ * If we don't have all the pdata yet, then bail.
+ */
+ if (ep->mpa_pkt_len < (sizeof(*mpa) + plen))
+ return;
+
+ /*
+ * If we get here we have accumulated the entire mpa
+ * start reply message including private data.
+ */
+ ep->mpa_attr.crc_enabled = (mpa->flags & MPA_CRC) | crc_enabled ? 1 : 0;
+ ep->mpa_attr.recv_marker_enabled = markers_enabled;
+ ep->mpa_attr.xmit_marker_enabled = mpa->flags & MPA_MARKERS ? 1 : 0;
+ ep->mpa_attr.version = mpa_rev;
+ PDBG("%s - crc_enabled=%d, recv_marker_enabled=%d, "
+ "xmit_marker_enabled=%d, version=%d\n", __FUNCTION__,
+ ep->mpa_attr.crc_enabled, ep->mpa_attr.recv_marker_enabled,
+ ep->mpa_attr.xmit_marker_enabled, ep->mpa_attr.version);
+
+ state_set(&ep->com, MPA_REQ_RCVD);
+
+ /* drive upcall */
+ connect_request_upcall(ep);
+ return;
+}
+
+static int rx_data(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
+{
+ struct iwch_ep *ep = ctx;
+ struct cpl_rx_data *hdr = cplhdr(skb);
+ unsigned int dlen = ntohs(hdr->len);
+
+ PDBG("%s ep %p dlen %u\n", __FUNCTION__, ep, dlen);
+
+ skb_pull(skb, sizeof(*hdr));
+ skb_trim(skb, dlen);
+
+ switch (state_read(&ep->com)) {
+ case MPA_REQ_SENT:
+ process_mpa_reply(ep, skb);
+ break;
+ case MPA_REQ_WAIT:
+ process_mpa_request(ep, skb);
+ break;
+ case MPA_REP_SENT:
+ break;
+ default:
+ printk(KERN_ERR MOD "%s Unexpected streaming data."
+ " ep %p state %d tid %d\n",
+ __FUNCTION__, ep, state_read(&ep->com), ep->hwtid);
+
+ /*
+ * The ep will timeout and inform the ULP of the failure.
+ * See ep_timeout().
+ */
+ break;
+ }
+
+ /* update RX credits */
+ update_rx_credits(ep, dlen);
+
+ return CPL_RET_BUF_DONE;
+}
+
+/*
+ * Upcall from the adapter indicating data has been transmitted.
+ * For us its just the single MPA request or reply. We can now free
+ * the skb holding the mpa message.
+ */
+static int tx_ack(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
+{
+ struct iwch_ep *ep = ctx;
+ struct cpl_wr_ack *hdr = cplhdr(skb);
+ unsigned int credits = ntohs(hdr->credits);
+ enum iwch_qp_attr_mask mask;
+
+ PDBG("%s ep %p credits %u\n", __FUNCTION__, ep, credits);
+
+ if (credits == 0)
+ return CPL_RET_BUF_DONE;
+ BUG_ON(credits != 1);
+ BUG_ON(ep->mpa_skb == NULL);
+ kfree_skb(ep->mpa_skb);
+ ep->mpa_skb = NULL;
+ dst_confirm(ep->dst);
+ if (state_read(&ep->com) == MPA_REP_SENT) {
+ struct iwch_qp_attributes attrs;
+
+ /* bind QP to EP and move to RTS */
+ attrs.mpa_attr = ep->mpa_attr;
+ attrs.max_ird = ep->ord;
+ attrs.max_ord = ep->ord;
+ attrs.llp_stream_handle = ep;
+ attrs.next_state = IWCH_QP_STATE_RTS;
+
+ /* bind QP and TID with INIT_WR */
+ mask = IWCH_QP_ATTR_NEXT_STATE |
+ IWCH_QP_ATTR_LLP_STREAM_HANDLE |
+ IWCH_QP_ATTR_MPA_ATTR |
+ IWCH_QP_ATTR_MAX_IRD |
+ IWCH_QP_ATTR_MAX_ORD;
+
+ ep->com.rpl_err = iwch_modify_qp(ep->com.qp->rhp,
+ ep->com.qp, mask, &attrs, 1);
+
+ if (!ep->com.rpl_err) {
+ state_set(&ep->com, FPDU_MODE);
+ established_upcall(ep);
+ }
+
+ ep->com.rpl_done = 1;
+ PDBG("waking up ep %p\n", ep);
+ wake_up(&ep->com.waitq);
+ }
+ return CPL_RET_BUF_DONE;
+}
+
+static int abort_rpl(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
+{
+ struct iwch_ep *ep = ctx;
+
+ PDBG("%s ep %p\n", __FUNCTION__, ep);
+
+ close_complete_upcall(ep);
+ state_set(&ep->com, DEAD);
+ release_ep_resources(ep);
+ return CPL_RET_BUF_DONE;
+}
+
+static int act_open_rpl(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
+{
+ struct iwch_ep *ep = ctx;
+ struct cpl_act_open_rpl *rpl = cplhdr(skb);
+
+ PDBG("%s ep %p status %u errno %d\n", __FUNCTION__, ep, rpl->status,
+ status2errno(rpl->status));
+ connect_reply_upcall(ep, status2errno(rpl->status));
+ state_set(&ep->com, DEAD);
+ if (ep->com.tdev->type == T3B)
+ release_tid(ep->com.tdev, GET_TID(rpl), NULL);
+ cxgb3_free_atid(ep->com.tdev, ep->atid);
+ dst_release(ep->dst);
+ l2t_release(L2DATA(ep->com.tdev), ep->l2t);
+ put_ep(&ep->com);
+ return CPL_RET_BUF_DONE;
+}
+
+static int listen_start(struct iwch_listen_ep *ep)
+{
+ struct sk_buff *skb;
+ struct cpl_pass_open_req *req;
+
+ PDBG("%s ep %p\n", __FUNCTION__, ep);
+ skb = get_skb(NULL, sizeof(*req), GFP_KERNEL);
+ if (!skb) {
+ printk(KERN_ERR MOD "t3c_listen_start failed to alloc skb!\n");
+ return -ENOMEM;
+ }
+
+ req = (struct cpl_pass_open_req *) skb_put(skb, sizeof(*req));
+ req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
+ OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_PASS_OPEN_REQ, ep->stid));
+ req->local_port = ep->com.local_addr.sin_port;
+ req->local_ip = ep->com.local_addr.sin_addr.s_addr;
+ req->peer_port = 0;
+ req->peer_ip = 0;
+ req->peer_netmask = 0;
+ req->opt0h = htonl(F_DELACK | F_TCAM_BYPASS);
+ req->opt0l = htonl(V_RCV_BUFSIZ(rcv_win>>10));
+ req->opt1 = htonl(V_CONN_POLICY(CPL_CONN_POLICY_ASK));
+
+ skb->priority = 1;
+ ep->com.tdev->send(ep->com.tdev, skb);
+ return 0;
+}
+
+static int pass_open_rpl(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
+{
+ struct iwch_listen_ep *ep = ctx;
+ struct cpl_pass_open_rpl *rpl = cplhdr(skb);
+
+ PDBG("%s ep %p status %d error %d\n", __FUNCTION__, ep,
+ rpl->status, status2errno(rpl->status));
+ ep->com.rpl_err = status2errno(rpl->status);
+ ep->com.rpl_done = 1;
+ wake_up(&ep->com.waitq);
+
+ return CPL_RET_BUF_DONE;
+}
+
+static int listen_stop(struct iwch_listen_ep *ep)
+{
+ struct sk_buff *skb;
+ struct cpl_close_listserv_req *req;
+
+ PDBG("%s ep %p\n", __FUNCTION__, ep);
+ skb = get_skb(NULL, sizeof(*req), GFP_KERNEL);
+ if (!skb) {
+ printk(KERN_ERR MOD "%s - failed to alloc skb\n", __FUNCTION__);
+ return -ENOMEM;
+ }
+ req = (struct cpl_close_listserv_req *) skb_put(skb, sizeof(*req));
+ req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
+ OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_CLOSE_LISTSRV_REQ, ep->stid));
+ skb->priority = 1;
+ ep->com.tdev->send(ep->com.tdev, skb);
+ return 0;
+}
+
+static int close_listsrv_rpl(struct t3cdev *tdev, struct sk_buff *skb,
+ void *ctx)
+{
+ struct iwch_listen_ep *ep = ctx;
+ struct cpl_close_listserv_rpl *rpl = cplhdr(skb);
+
+ PDBG("%s ep %p\n", __FUNCTION__, ep);
+ ep->com.rpl_err = status2errno(rpl->status);
+ ep->com.rpl_done = 1;
+ wake_up(&ep->com.waitq);
+ return CPL_RET_BUF_DONE;
+}
+
+static void accept_cr(struct iwch_ep *ep, __be32 peer_ip, struct sk_buff *skb)
+{
+ struct cpl_pass_accept_rpl *rpl;
+ unsigned int mtu_idx;
+ u32 opt0h, opt0l, opt2;
+ int wscale;
+
+ PDBG("%s ep %p\n", __FUNCTION__, ep);
+ BUG_ON(skb_cloned(skb));
+ skb_trim(skb, sizeof(*rpl));
+ skb_get(skb);
+ mtu_idx = find_best_mtu(T3C_DATA(ep->com.tdev), dst_mtu(ep->dst));
+ wscale = compute_wscale(rcv_win);
+ opt0h = V_NAGLE(0) |
+ V_NO_CONG(nocong) |
+ V_KEEP_ALIVE(1) |
+ F_TCAM_BYPASS |
+ V_WND_SCALE(wscale) |
+ V_MSS_IDX(mtu_idx) |
+ V_L2T_IDX(ep->l2t->idx) | V_TX_CHANNEL(ep->l2t->smt_idx);
+ opt0l = V_TOS((ep->tos >> 2) & M_TOS) | V_RCV_BUFSIZ(rcv_win>>10);
+ opt2 = V_FLAVORS_VALID(1) | V_CONG_CONTROL_FLAVOR(cong_flavor);
+
+ rpl = cplhdr(skb);
+ rpl->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
+ OPCODE_TID(rpl) = htonl(MK_OPCODE_TID(CPL_PASS_ACCEPT_RPL, ep->hwtid));
+ rpl->peer_ip = peer_ip;
+ rpl->opt0h = htonl(opt0h);
+ rpl->opt0l_status = htonl(opt0l | CPL_PASS_OPEN_ACCEPT);
+ rpl->opt2 = htonl(opt2);
+ rpl->rsvd = rpl->opt2; /* workaround for HW bug */
+ skb->priority = CPL_PRIORITY_SETUP;
+ l2t_send(ep->com.tdev, skb, ep->l2t);
+
+ return;
+}
+
+static void reject_cr(struct t3cdev *tdev, u32 hwtid, __be32 peer_ip,
+ struct sk_buff *skb)
+{
+ PDBG("%s t3cdev %p tid %u peer_ip %x\n", __FUNCTION__, tdev, hwtid,
+ peer_ip);
+ BUG_ON(skb_cloned(skb));
+ skb_trim(skb, sizeof(struct cpl_tid_release));
+ skb_get(skb);
+
+ if (tdev->type == T3B)
+ release_tid(tdev, hwtid, skb);
+ else {
+ struct cpl_pass_accept_rpl *rpl;
+
+ rpl = cplhdr(skb);
+ skb->priority = CPL_PRIORITY_SETUP;
+ rpl->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
+ OPCODE_TID(rpl) = htonl(MK_OPCODE_TID(CPL_PASS_ACCEPT_RPL,
+ hwtid));
+ rpl->peer_ip = peer_ip;
+ rpl->opt0h = htonl(F_TCAM_BYPASS);
+ rpl->opt0l_status = htonl(CPL_PASS_OPEN_REJECT);
+ rpl->opt2 = 0;
+ rpl->rsvd = rpl->opt2;
+ tdev->send(tdev, skb);
+ }
+}
+
+static int pass_accept_req(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
+{
+ struct iwch_ep *child_ep, *parent_ep = ctx;
+ struct cpl_pass_accept_req *req = cplhdr(skb);
+ unsigned int hwtid = GET_TID(req);
+ struct dst_entry *dst;
+ struct l2t_entry *l2t;
+ struct rtable *rt;
+ struct iff_mac tim;
+
+ PDBG("%s parent ep %p tid %u\n", __FUNCTION__, parent_ep, hwtid);
+
+ if (state_read(&parent_ep->com) != LISTEN) {
+ printk(KERN_ERR "%s - listening ep not in LISTEN\n",
+ __FUNCTION__);
+ goto reject;
+ }
+
+ /*
+ * Find the netdev for this connection request.
+ */
+ 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",
+ __FUNCTION__,
+ req->dst_mac[0],
+ req->dst_mac[1],
+ req->dst_mac[2],
+ req->dst_mac[3],
+ req->dst_mac[4],
+ req->dst_mac[5]);
+ goto reject;
+ }
+
+ /* Find output route */
+ rt = find_route(tdev,
+ req->local_ip,
+ req->peer_ip,
+ req->local_port,
+ req->peer_port, G_PASS_OPEN_TOS(ntohl(req->tos_tid)));
+ if (!rt) {
+ printk(KERN_ERR MOD "%s - failed to find dst entry!\n",
+ __FUNCTION__);
+ goto reject;
+ }
+ dst = &rt->u.dst;
+ l2t = t3_l2t_get(tdev, dst->neighbour, dst->neighbour->dev);
+ if (!l2t) {
+ printk(KERN_ERR MOD "%s - failed to allocate l2t entry!\n",
+ __FUNCTION__);
+ dst_release(dst);
+ goto reject;
+ }
+ child_ep = alloc_ep(sizeof(*child_ep), GFP_KERNEL);
+ if (!child_ep) {
+ printk(KERN_ERR MOD "%s - failed to allocate ep entry!\n",
+ __FUNCTION__);
+ l2t_release(L2DATA(tdev), l2t);
+ dst_release(dst);
+ goto reject;
+ }
+ state_set(&child_ep->com, CONNECTING);
+ child_ep->com.tdev = tdev;
+ child_ep->com.cm_id = NULL;
+ child_ep->com.local_addr.sin_family = PF_INET;
+ child_ep->com.local_addr.sin_port = req->local_port;
+ child_ep->com.local_addr.sin_addr.s_addr = req->local_ip;
+ child_ep->com.remote_addr.sin_family = PF_INET;
+ child_ep->com.remote_addr.sin_port = req->peer_port;
+ child_ep->com.remote_addr.sin_addr.s_addr = req->peer_ip;
+ get_ep(&parent_ep->com);
+ child_ep->parent_ep = parent_ep;
+ child_ep->tos = G_PASS_OPEN_TOS(ntohl(req->tos_tid));
+ child_ep->l2t = l2t;
+ child_ep->dst = dst;
+ child_ep->hwtid = hwtid;
+ init_timer(&child_ep->timer);
+ cxgb3_insert_tid(tdev, &t3c_client, child_ep, hwtid);
+ accept_cr(child_ep, req->peer_ip, skb);
+ goto out;
+reject:
+ reject_cr(tdev, hwtid, req->peer_ip, skb);
+out:
+ return CPL_RET_BUF_DONE;
+}
+
+static int pass_establish(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
+{
+ struct iwch_ep *ep = ctx;
+ struct cpl_pass_establish *req = cplhdr(skb);
+
+ PDBG("%s ep %p\n", __FUNCTION__, ep);
+ ep->snd_seq = ntohl(req->snd_isn);
+
+ set_emss(ep, ntohs(req->tcp_opt));
+
+ dst_confirm(ep->dst);
+ state_set(&ep->com, MPA_REQ_WAIT);
+ start_ep_timer(ep);
+
+ return CPL_RET_BUF_DONE;
+}
+
+static int peer_close(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
+{
+ struct iwch_ep *ep = ctx;
+ struct iwch_qp_attributes attrs;
+ unsigned long flags;
+ int disconnect = 1;
+ int release = 0;
+
+ PDBG("%s ep %p\n", __FUNCTION__, ep);
+ dst_confirm(ep->dst);
+
+ spin_lock_irqsave(&ep->com.lock, flags);
+ switch (ep->com.state) {
+ case MPA_REQ_WAIT:
+ __state_set(&ep->com, CLOSING);
+ break;
+ case MPA_REQ_SENT:
+ __state_set(&ep->com, CLOSING);
+ connect_reply_upcall(ep, -ECONNRESET);
+ break;
+ case MPA_REQ_RCVD:
+
+ /*
+ * We're gonna mark this puppy DEAD, but keep
+ * the reference on it until the ULP accepts or
+ * rejects the CR.
+ */
+ __state_set(&ep->com, CLOSING);
+ get_ep(&ep->com);
+ break;
+ case MPA_REP_SENT:
+ __state_set(&ep->com, CLOSING);
+ ep->com.rpl_done = 1;
+ ep->com.rpl_err = -ECONNRESET;
+ PDBG("waking up ep %p\n", ep);
+ wake_up(&ep->com.waitq);
+ break;
+ case FPDU_MODE:
+ __state_set(&ep->com, CLOSING);
+ attrs.next_state = IWCH_QP_STATE_CLOSING;
+ iwch_modify_qp(ep->com.qp->rhp, ep->com.qp,
+ IWCH_QP_ATTR_NEXT_STATE, &attrs, 1);
+ peer_close_upcall(ep);
+ break;
+ case ABORTING:
+ disconnect = 0;
+ break;
+ case CLOSING:
+ start_ep_timer(ep);
+ __state_set(&ep->com, MORIBUND);
+ disconnect = 0;
+ break;
+ case MORIBUND:
+ stop_ep_timer(ep);
+ if (ep->com.cm_id && ep->com.qp) {
+ attrs.next_state = IWCH_QP_STATE_IDLE;
+ iwch_modify_qp(ep->com.qp->rhp, ep->com.qp,
+ IWCH_QP_ATTR_NEXT_STATE, &attrs, 1);
+ }
+ close_complete_upcall(ep);
+ __state_set(&ep->com, DEAD);
+ release = 1;
+ disconnect = 0;
+ break;
+ case DEAD:
+ disconnect = 0;
+ break;
+ default:
+ BUG_ON(1);
+ }
+ spin_unlock_irqrestore(&ep->com.lock, flags);
+ if (disconnect)
+ iwch_ep_disconnect(ep, 0, GFP_KERNEL);
+ if (release)
+ release_ep_resources(ep);
+ return CPL_RET_BUF_DONE;
+}
+
+/*
+ * Returns whether an ABORT_REQ_RSS message is a negative advice.
+ */
+static inline int is_neg_adv_abort(unsigned int status)
+{
+ return status == CPL_ERR_RTX_NEG_ADVICE ||
+ status == CPL_ERR_PERSIST_NEG_ADVICE;
+}
+
+static int peer_abort(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
+{
+ struct cpl_abort_req_rss *req = cplhdr(skb);
+ struct iwch_ep *ep = ctx;
+ struct cpl_abort_rpl *rpl;
+ struct sk_buff *rpl_skb;
+ struct iwch_qp_attributes attrs;
+ int ret;
+ int state;
+
+ if (is_neg_adv_abort(req->status)) {
+ PDBG("%s neg_adv_abort ep %p tid %d\n", __FUNCTION__, ep,
+ ep->hwtid);
+ t3_l2t_send_event(ep->com.tdev, ep->l2t);
+ return CPL_RET_BUF_DONE;
+ }
+
+ state = state_read(&ep->com);
+ PDBG("%s ep %p state %u\n", __FUNCTION__, ep, state);
+ switch (state) {
+ case CONNECTING:
+ break;
+ case MPA_REQ_WAIT:
+ break;
+ case MPA_REQ_SENT:
+ connect_reply_upcall(ep, -ECONNRESET);
+ break;
+ case MPA_REP_SENT:
+ ep->com.rpl_done = 1;
+ ep->com.rpl_err = -ECONNRESET;
+ PDBG("waking up ep %p\n", ep);
+ wake_up(&ep->com.waitq);
+ break;
+ case MPA_REQ_RCVD:
+
+ /*
+ * We're gonna mark this puppy DEAD, but keep
+ * the reference on it until the ULP accepts or
+ * rejects the CR.
+ */
+ get_ep(&ep->com);
+ break;
+ case MORIBUND:
+ stop_ep_timer(ep);
+ case FPDU_MODE:
+ case CLOSING:
+ if (ep->com.cm_id && ep->com.qp) {
+ attrs.next_state = IWCH_QP_STATE_ERROR;
+ ret = iwch_modify_qp(ep->com.qp->rhp,
+ ep->com.qp, IWCH_QP_ATTR_NEXT_STATE,
+ &attrs, 1);
+ if (ret)
+ printk(KERN_ERR MOD
+ "%s - qp <- error failed!\n",
+ __FUNCTION__);
+ }
+ peer_abort_upcall(ep);
+ break;
+ case ABORTING:
+ break;
+ case DEAD:
+ PDBG("%s PEER_ABORT IN DEAD STATE!!!!\n", __FUNCTION__);
+ return CPL_RET_BUF_DONE;
+ default:
+ BUG_ON(1);
+ break;
+ }
+ dst_confirm(ep->dst);
+
+ rpl_skb = get_skb(skb, sizeof(*rpl), GFP_KERNEL);
+ if (!rpl_skb) {
+ printk(KERN_ERR MOD "%s - cannot allocate skb!\n",
+ __FUNCTION__);
+ dst_release(ep->dst);
+ l2t_release(L2DATA(ep->com.tdev), ep->l2t);
+ put_ep(&ep->com);
+ return CPL_RET_BUF_DONE;
+ }
+ rpl_skb->priority = CPL_PRIORITY_DATA;
+ rpl = (struct cpl_abort_rpl *) skb_put(rpl_skb, sizeof(*rpl));
+ rpl->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_HOST_ABORT_CON_RPL));
+ rpl->wr.wr_lo = htonl(V_WR_TID(ep->hwtid));
+ OPCODE_TID(rpl) = htonl(MK_OPCODE_TID(CPL_ABORT_RPL, ep->hwtid));
+ rpl->cmd = CPL_ABORT_NO_RST;
+ ep->com.tdev->send(ep->com.tdev, rpl_skb);
+ if (state != ABORTING) {
+ state_set(&ep->com, DEAD);
+ release_ep_resources(ep);
+ }
+ return CPL_RET_BUF_DONE;
+}
+
+static int close_con_rpl(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
+{
+ struct iwch_ep *ep = ctx;
+ struct iwch_qp_attributes attrs;
+ unsigned long flags;
+ int release = 0;
+
+ PDBG("%s ep %p\n", __FUNCTION__, ep);
+ BUG_ON(!ep);
+
+ /* The cm_id may be null if we failed to connect */
+ spin_lock_irqsave(&ep->com.lock, flags);
+ switch (ep->com.state) {
+ case CLOSING:
+ start_ep_timer(ep);
+ __state_set(&ep->com, MORIBUND);
+ break;
+ case MORIBUND:
+ stop_ep_timer(ep);
+ if ((ep->com.cm_id) && (ep->com.qp)) {
+ attrs.next_state = IWCH_QP_STATE_IDLE;
+ iwch_modify_qp(ep->com.qp->rhp,
+ ep->com.qp,
+ IWCH_QP_ATTR_NEXT_STATE,
+ &attrs, 1);
+ }
+ close_complete_upcall(ep);
+ __state_set(&ep->com, DEAD);
+ release = 1;
+ break;
+ case DEAD:
+ default:
+ BUG_ON(1);
+ break;
+ }
+ spin_unlock_irqrestore(&ep->com.lock, flags);
+ if (release)
+ release_ep_resources(ep);
+ return CPL_RET_BUF_DONE;
+}
+
+/*
+ * T3A does 3 things when a TERM is received:
+ * 1) send up a CPL_RDMA_TERMINATE message with the TERM packet
+ * 2) generate an async event on the QP with the TERMINATE opcode
+ * 3) post a TERMINATE opcde cqe into the associated CQ.
+ *
+ * For (1), we save the message in the qp for later consumer consumption.
+ * For (2), we move the QP into TERMINATE, post a QP event and disconnect.
+ * For (3), we toss the CQE in cxio_poll_cq().
+ *
+ * terminate() handles case (1)...
+ */
+static int terminate(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
+{
+ struct iwch_ep *ep = ctx;
+
+ PDBG("%s ep %p\n", __FUNCTION__, ep);
+ skb_pull(skb, sizeof(struct cpl_rdma_terminate));
+ PDBG("%s saving %d bytes of term msg\n", __FUNCTION__, skb->len);
+ memcpy(ep->com.qp->attr.terminate_buffer, skb->data, skb->len);
+ ep->com.qp->attr.terminate_msg_len = skb->len;
+ ep->com.qp->attr.is_terminate_local = 0;
+ return CPL_RET_BUF_DONE;
+}
+
+static int ec_status(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
+{
+ struct cpl_rdma_ec_status *rep = cplhdr(skb);
+ struct iwch_ep *ep = ctx;
+
+ PDBG("%s ep %p tid %u status %d\n", __FUNCTION__, ep, ep->hwtid,
+ rep->status);
+ if (rep->status) {
+ struct iwch_qp_attributes attrs;
+
+ printk(KERN_ERR MOD "%s BAD CLOSE - Aborting tid %u\n",
+ __FUNCTION__, ep->hwtid);
+ attrs.next_state = IWCH_QP_STATE_ERROR;
+ iwch_modify_qp(ep->com.qp->rhp,
+ ep->com.qp, IWCH_QP_ATTR_NEXT_STATE,
+ &attrs, 1);
+ abort_connection(ep, NULL, GFP_KERNEL);
+ }
+ return CPL_RET_BUF_DONE;
+}
+
+static void ep_timeout(unsigned long arg)
+{
+ struct iwch_ep *ep = (struct iwch_ep *)arg;
+ struct iwch_qp_attributes attrs;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ep->com.lock, flags);
+ PDBG("%s ep %p tid %u state %d\n", __FUNCTION__, ep, ep->hwtid,
+ ep->com.state);
+ switch (ep->com.state) {
+ case MPA_REQ_SENT:
+ connect_reply_upcall(ep, -ETIMEDOUT);
+ break;
+ case MPA_REQ_WAIT:
+ break;
+ case MORIBUND:
+ if (ep->com.cm_id && ep->com.qp) {
+ attrs.next_state = IWCH_QP_STATE_ERROR;
+ iwch_modify_qp(ep->com.qp->rhp,
+ ep->com.qp, IWCH_QP_ATTR_NEXT_STATE,
+ &attrs, 1);
+ }
+ break;
+ default:
+ BUG();
+ }
+ __state_set(&ep->com, CLOSING);
+ spin_unlock_irqrestore(&ep->com.lock, flags);
+ abort_connection(ep, NULL, GFP_ATOMIC);
+ put_ep(&ep->com);
+}
+
+int iwch_reject_cr(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len)
+{
+ int err;
+ struct iwch_ep *ep = to_ep(cm_id);
+ PDBG("%s ep %p tid %u\n", __FUNCTION__, ep, ep->hwtid);
+
+ if (state_read(&ep->com) == DEAD) {
+ put_ep(&ep->com);
+ return -ECONNRESET;
+ }
+ BUG_ON(state_read(&ep->com) != MPA_REQ_RCVD);
+ state_set(&ep->com, CLOSING);
+ if (mpa_rev == 0)
+ abort_connection(ep, NULL, GFP_KERNEL);
+ else {
+ err = send_mpa_reject(ep, pdata, pdata_len);
+ err = send_halfclose(ep, GFP_KERNEL);
+ }
+ return 0;
+}
+
+int iwch_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
+{
+ int err;
+ struct iwch_qp_attributes attrs;
+ enum iwch_qp_attr_mask mask;
+ struct iwch_ep *ep = to_ep(cm_id);
+ struct iwch_dev *h = to_iwch_dev(cm_id->device);
+ struct iwch_qp *qp = get_qhp(h, conn_param->qpn);
+
+ PDBG("%s ep %p tid %u\n", __FUNCTION__, ep, ep->hwtid);
+ if (state_read(&ep->com) == DEAD) {
+ put_ep(&ep->com);
+ return -ECONNRESET;
+ }
+
+ BUG_ON(state_read(&ep->com) != MPA_REQ_RCVD);
+ BUG_ON(!qp);
+
+ if ((conn_param->ord > qp->rhp->attr.max_rdma_read_qp_depth) ||
+ (conn_param->ird > qp->rhp->attr.max_rdma_reads_per_qp)) {
+ abort_connection(ep, NULL, GFP_KERNEL);
+ return -EINVAL;
+ }
+
+ cm_id->add_ref(cm_id);
+ ep->com.cm_id = cm_id;
+ ep->com.qp = qp;
+
+ ep->com.rpl_done = 0;
+ ep->com.rpl_err = 0;
+ ep->ird = conn_param->ird;
+ ep->ord = conn_param->ord;
+ PDBG("%s %d ird %d ord %d\n", __FUNCTION__, __LINE__, ep->ird, ep->ord);
+ get_ep(&ep->com);
+ err = send_mpa_reply(ep, conn_param->private_data,
+ conn_param->private_data_len);
+ if (err) {
+ ep->com.cm_id = NULL;
+ ep->com.qp = NULL;
+ cm_id->rem_ref(cm_id);
+ abort_connection(ep, NULL, GFP_KERNEL);
+ put_ep(&ep->com);
+ return err;
+ }
+
+ /* bind QP to EP and move to RTS */
+ attrs.mpa_attr = ep->mpa_attr;
+ attrs.max_ird = ep->ord;
+ attrs.max_ord = ep->ord;
+ attrs.llp_stream_handle = ep;
+ attrs.next_state = IWCH_QP_STATE_RTS;
+
+ /* bind QP and TID with INIT_WR */
+ mask = IWCH_QP_ATTR_NEXT_STATE |
+ IWCH_QP_ATTR_LLP_STREAM_HANDLE |
+ IWCH_QP_ATTR_MPA_ATTR |
+ IWCH_QP_ATTR_MAX_IRD |
+ IWCH_QP_ATTR_MAX_ORD;
+
+ err = iwch_modify_qp(ep->com.qp->rhp,
+ ep->com.qp, mask, &attrs, 1);
+
+ if (err) {
+ ep->com.cm_id = NULL;
+ ep->com.qp = NULL;
+ cm_id->rem_ref(cm_id);
+ abort_connection(ep, NULL, GFP_KERNEL);
+ } else {
+ state_set(&ep->com, FPDU_MODE);
+ established_upcall(ep);
+ }
+ put_ep(&ep->com);
+ return err;
+}
+
+int iwch_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
+{
+ int err = 0;
+ struct iwch_dev *h = to_iwch_dev(cm_id->device);
+ struct iwch_ep *ep;
+ struct rtable *rt;
+
+ ep = alloc_ep(sizeof(*ep), GFP_KERNEL);
+ if (!ep) {
+ printk(KERN_ERR MOD "%s - cannot alloc ep.\n", __FUNCTION__);
+ err = -ENOMEM;
+ goto out;
+ }
+ init_timer(&ep->timer);
+ ep->plen = conn_param->private_data_len;
+ if (ep->plen)
+ memcpy(ep->mpa_pkt + sizeof(struct mpa_message),
+ conn_param->private_data, ep->plen);
+ ep->ird = conn_param->ird;
+ ep->ord = conn_param->ord;
+ ep->com.tdev = h->rdev.t3cdev_p;
+
+ cm_id->add_ref(cm_id);
+ ep->com.cm_id = cm_id;
+ ep->com.qp = get_qhp(h, conn_param->qpn);
+ BUG_ON(!ep->com.qp);
+ PDBG("%s qpn 0x%x qp %p cm_id %p\n", __FUNCTION__, conn_param->qpn,
+ ep->com.qp, cm_id);
+
+ /*
+ * Allocate an active TID to initiate a TCP connection.
+ */
+ ep->atid = cxgb3_alloc_atid(h->rdev.t3cdev_p, &t3c_client, ep);
+ if (ep->atid == -1) {
+ printk(KERN_ERR MOD "%s - cannot alloc atid.\n", __FUNCTION__);
+ err = -ENOMEM;
+ goto fail2;
+ }
+
+ /* find a route */
+ rt = find_route(h->rdev.t3cdev_p,
+ cm_id->local_addr.sin_addr.s_addr,
+ cm_id->remote_addr.sin_addr.s_addr,
+ cm_id->local_addr.sin_port,
+ cm_id->remote_addr.sin_port, IPTOS_LOWDELAY);
+ if (!rt) {
+ printk(KERN_ERR MOD "%s - cannot find route.\n", __FUNCTION__);
+ err = -EHOSTUNREACH;
+ goto fail3;
+ }
+ ep->dst = &rt->u.dst;
+
+ /* get a l2t entry */
+ ep->l2t = t3_l2t_get(ep->com.tdev, ep->dst->neighbour,
+ ep->dst->neighbour->dev);
+ if (!ep->l2t) {
+ printk(KERN_ERR MOD "%s - cannot alloc l2e.\n", __FUNCTION__);
+ err = -ENOMEM;
+ goto fail4;
+ }
+
+ state_set(&ep->com, CONNECTING);
+ ep->tos = IPTOS_LOWDELAY;
+ ep->com.local_addr = cm_id->local_addr;
+ ep->com.remote_addr = cm_id->remote_addr;
+
+ /* send connect request to rnic */
+ err = send_connect(ep);
+ if (!err)
+ goto out;
+
+ l2t_release(L2DATA(h->rdev.t3cdev_p), ep->l2t);
+fail4:
+ dst_release(ep->dst);
+fail3:
+ cxgb3_free_atid(ep->com.tdev, ep->atid);
+fail2:
+ put_ep(&ep->com);
+out:
+ return err;
+}
+
+int iwch_create_listen(struct iw_cm_id *cm_id, int backlog)
+{
+ int err = 0;
+ struct iwch_dev *h = to_iwch_dev(cm_id->device);
+ struct iwch_listen_ep *ep;
+
+
+ might_sleep();
+
+ ep = alloc_ep(sizeof(*ep), GFP_KERNEL);
+ if (!ep) {
+ printk(KERN_ERR MOD "%s - cannot alloc ep.\n", __FUNCTION__);
+ err = -ENOMEM;
+ goto fail1;
+ }
+ PDBG("%s ep %p\n", __FUNCTION__, ep);
+ ep->com.tdev = h->rdev.t3cdev_p;
+ cm_id->add_ref(cm_id);
+ ep->com.cm_id = cm_id;
+ ep->backlog = backlog;
+ ep->com.local_addr = cm_id->local_addr;
+
+ /*
+ * Allocate a server TID.
+ */
+ ep->stid = cxgb3_alloc_stid(h->rdev.t3cdev_p, &t3c_client, ep);
+ if (ep->stid == -1) {
+ printk(KERN_ERR MOD "%s - cannot alloc atid.\n", __FUNCTION__);
+ err = -ENOMEM;
+ goto fail2;
+ }
+
+ state_set(&ep->com, LISTEN);
+ err = listen_start(ep);
+ if (err)
+ goto fail3;
+
+ /* wait for pass_open_rpl */
+ wait_event(ep->com.waitq, ep->com.rpl_done);
+ err = ep->com.rpl_err;
+ if (!err) {
+ cm_id->provider_data = ep;
+ goto out;
+ }
+fail3:
+ cxgb3_free_stid(ep->com.tdev, ep->stid);
+fail2:
+ put_ep(&ep->com);
+fail1:
+out:
+ return err;
+}
+
+int iwch_destroy_listen(struct iw_cm_id *cm_id)
+{
+ int err;
+ struct iwch_listen_ep *ep = to_listen_ep(cm_id);
+
+ PDBG("%s ep %p\n", __FUNCTION__, ep);
+
+ might_sleep();
+ state_set(&ep->com, DEAD);
+ ep->com.rpl_done = 0;
+ ep->com.rpl_err = 0;
+ err = listen_stop(ep);
+ wait_event(ep->com.waitq, ep->com.rpl_done);
+ cxgb3_free_stid(ep->com.tdev, ep->stid);
+ err = ep->com.rpl_err;
+ cm_id->rem_ref(cm_id);
+ put_ep(&ep->com);
+ return err;
+}
+
+int iwch_ep_disconnect(struct iwch_ep *ep, int abrupt, gfp_t gfp)
+{
+ int ret=0;
+ unsigned long flags;
+ int close = 0;
+
+ spin_lock_irqsave(&ep->com.lock, flags);
+
+ PDBG("%s ep %p state %s, abrupt %d\n", __FUNCTION__, ep,
+ states[ep->com.state], abrupt);
+
+ if (ep->com.state == DEAD) {
+ PDBG("%s already dead ep %p\n", __FUNCTION__, ep);
+ goto out;
+ }
+
+ if (abrupt) {
+ if (ep->com.state != ABORTING) {
+ ep->com.state = ABORTING;
+ close = 1;
+ }
+ goto out;
+ }
+
+ switch (ep->com.state) {
+ case MPA_REQ_WAIT:
+ case MPA_REQ_SENT:
+ case MPA_REQ_RCVD:
+ case MPA_REP_SENT:
+ case FPDU_MODE:
+ ep->com.state = CLOSING;
+ close = 1;
+ break;
+ case CLOSING:
+ start_ep_timer(ep);
+ ep->com.state = MORIBUND;
+ close = 1;
+ break;
+ case MORIBUND:
+ break;
+ default:
+ BUG();
+ break;
+ }
+out:
+ spin_unlock_irqrestore(&ep->com.lock, flags);
+ if (close) {
+ if (abrupt)
+ ret = send_abort(ep, NULL, gfp);
+ else
+ ret = send_halfclose(ep, gfp);
+ }
+ return ret;
+}
+
+int iwch_ep_redirect(void *ctx, struct dst_entry *old, struct dst_entry *new,
+ struct l2t_entry *l2t)
+{
+ struct iwch_ep *ep = ctx;
+
+ if (ep->dst != old)
+ return 0;
+
+ PDBG("%s ep %p redirect to dst %p l2t %p\n", __FUNCTION__, ep, new,
+ l2t);
+ dst_hold(new);
+ l2t_release(L2DATA(ep->com.tdev), ep->l2t);
+ ep->l2t = l2t;
+ dst_release(old);
+ ep->dst = new;
+ return 1;
+}
+
+/*
+ * All the CM events are handled on a work queue to have a safe context.
+ */
+static int sched(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
+{
+ struct iwch_ep_common *epc = ctx;
+
+ get_ep(epc);
+
+ /*
+ * Save ctx and tdev in the skb->cb area.
+ */
+ *((void **) skb->cb) = ctx;
+ *((struct t3cdev **) (skb->cb + sizeof(void *))) = tdev;
+
+ /*
+ * Queue the skb and schedule the worker thread.
+ */
+ skb_queue_tail(&rxq, skb);
+ queue_work(workq, &skb_work);
+ return 0;
+}
+
+int __init iwch_cm_init(void)
+{
+ skb_queue_head_init(&rxq);
+
+ workq = create_singlethread_workqueue("iw_cxgb3");
+ if (!workq)
+ return -ENOMEM;
+
+ /*
+ * All upcalls from the T3 Core go to sched() to
+ * schedule the processing on a work queue.
+ */
+ t3c_handlers[CPL_ACT_ESTABLISH] = sched;
+ t3c_handlers[CPL_ACT_OPEN_RPL] = sched;
+ t3c_handlers[CPL_RX_DATA] = sched;
+ t3c_handlers[CPL_TX_DMA_ACK] = sched;
+ t3c_handlers[CPL_ABORT_RPL_RSS] = sched;
+ t3c_handlers[CPL_ABORT_RPL] = sched;
+ t3c_handlers[CPL_PASS_OPEN_RPL] = sched;
+ t3c_handlers[CPL_CLOSE_LISTSRV_RPL] = sched;
+ t3c_handlers[CPL_PASS_ACCEPT_REQ] = sched;
+ t3c_handlers[CPL_PASS_ESTABLISH] = sched;
+ t3c_handlers[CPL_PEER_CLOSE] = sched;
+ t3c_handlers[CPL_CLOSE_CON_RPL] = sched;
+ t3c_handlers[CPL_ABORT_REQ_RSS] = sched;
+ t3c_handlers[CPL_RDMA_TERMINATE] = sched;
+ t3c_handlers[CPL_RDMA_EC_STATUS] = sched;
+
+ /*
+ * These are the real handlers that are called from a
+ * work queue.
+ */
+ work_handlers[CPL_ACT_ESTABLISH] = act_establish;
+ work_handlers[CPL_ACT_OPEN_RPL] = act_open_rpl;
+ work_handlers[CPL_RX_DATA] = rx_data;
+ work_handlers[CPL_TX_DMA_ACK] = tx_ack;
+ work_handlers[CPL_ABORT_RPL_RSS] = abort_rpl;
+ work_handlers[CPL_ABORT_RPL] = abort_rpl;
+ work_handlers[CPL_PASS_OPEN_RPL] = pass_open_rpl;
+ work_handlers[CPL_CLOSE_LISTSRV_RPL] = close_listsrv_rpl;
+ work_handlers[CPL_PASS_ACCEPT_REQ] = pass_accept_req;
+ work_handlers[CPL_PASS_ESTABLISH] = pass_establish;
+ work_handlers[CPL_PEER_CLOSE] = peer_close;
+ work_handlers[CPL_ABORT_REQ_RSS] = peer_abort;
+ work_handlers[CPL_CLOSE_CON_RPL] = close_con_rpl;
+ work_handlers[CPL_RDMA_TERMINATE] = terminate;
+ work_handlers[CPL_RDMA_EC_STATUS] = ec_status;
+ return 0;
+}
+
+void __exit iwch_cm_term(void)
+{
+ flush_workqueue(workq);
+ destroy_workqueue(workq);
+}
diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.h b/drivers/infiniband/hw/cxgb3/iwch_cm.h
new file mode 100644
index 00000000000..0c6f281bd4a
--- /dev/null
+++ b/drivers/infiniband/hw/cxgb3/iwch_cm.h
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2006 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef _IWCH_CM_H_
+#define _IWCH_CM_H_
+
+#include <linux/inet.h>
+#include <linux/wait.h>
+#include <linux/spinlock.h>
+#include <linux/kref.h>
+
+#include <rdma/ib_verbs.h>
+#include <rdma/iw_cm.h>
+
+#include "cxgb3_offload.h"
+#include "iwch_provider.h"
+
+#define MPA_KEY_REQ "MPA ID Req Frame"
+#define MPA_KEY_REP "MPA ID Rep Frame"
+
+#define MPA_MAX_PRIVATE_DATA 256
+#define MPA_REV 0 /* XXX - amso1100 uses rev 0 ! */
+#define MPA_REJECT 0x20
+#define MPA_CRC 0x40
+#define MPA_MARKERS 0x80
+#define MPA_FLAGS_MASK 0xE0
+
+#define put_ep(ep) { \
+ PDBG("put_ep (via %s:%u) ep %p refcnt %d\n", __FUNCTION__, __LINE__, \
+ ep, atomic_read(&((ep)->kref.refcount))); \
+ kref_put(&((ep)->kref), __free_ep); \
+}
+
+#define get_ep(ep) { \
+ PDBG("get_ep (via %s:%u) ep %p, refcnt %d\n", __FUNCTION__, __LINE__, \
+ ep, atomic_read(&((ep)->kref.refcount))); \
+ kref_get(&((ep)->kref)); \
+}
+
+struct mpa_message {
+ u8 key[16];
+ u8 flags;
+ u8 revision;
+ __be16 private_data_size;
+ u8 private_data[0];
+};
+
+struct terminate_message {
+ u8 layer_etype;
+ u8 ecode;
+ __be16 hdrct_rsvd;
+ u8 len_hdrs[0];
+};
+
+#define TERM_MAX_LENGTH (sizeof(struct terminate_message) + 2 + 18 + 28)
+
+enum iwch_layers_types {
+ LAYER_RDMAP = 0x00,
+ LAYER_DDP = 0x10,
+ LAYER_MPA = 0x20,
+ RDMAP_LOCAL_CATA = 0x00,
+ RDMAP_REMOTE_PROT = 0x01,
+ RDMAP_REMOTE_OP = 0x02,
+ DDP_LOCAL_CATA = 0x00,
+ DDP_TAGGED_ERR = 0x01,
+ DDP_UNTAGGED_ERR = 0x02,
+ DDP_LLP = 0x03
+};
+
+enum iwch_rdma_ecodes {
+ RDMAP_INV_STAG = 0x00,
+ RDMAP_BASE_BOUNDS = 0x01,
+ RDMAP_ACC_VIOL = 0x02,
+ RDMAP_STAG_NOT_ASSOC = 0x03,
+ RDMAP_TO_WRAP = 0x04,
+ RDMAP_INV_VERS = 0x05,
+ RDMAP_INV_OPCODE = 0x06,
+ RDMAP_STREAM_CATA = 0x07,
+ RDMAP_GLOBAL_CATA = 0x08,
+ RDMAP_CANT_INV_STAG = 0x09,
+ RDMAP_UNSPECIFIED = 0xff
+};
+
+enum iwch_ddp_ecodes {
+ DDPT_INV_STAG = 0x00,
+ DDPT_BASE_BOUNDS = 0x01,
+ DDPT_STAG_NOT_ASSOC = 0x02,
+ DDPT_TO_WRAP = 0x03,
+ DDPT_INV_VERS = 0x04,
+ DDPU_INV_QN = 0x01,
+ DDPU_INV_MSN_NOBUF = 0x02,
+ DDPU_INV_MSN_RANGE = 0x03,
+ DDPU_INV_MO = 0x04,
+ DDPU_MSG_TOOBIG = 0x05,
+ DDPU_INV_VERS = 0x06
+};
+
+enum iwch_mpa_ecodes {
+ MPA_CRC_ERR = 0x02,
+ MPA_MARKER_ERR = 0x03
+};
+
+enum iwch_ep_state {
+ IDLE = 0,
+ LISTEN,
+ CONNECTING,
+ MPA_REQ_WAIT,
+ MPA_REQ_SENT,
+ MPA_REQ_RCVD,
+ MPA_REP_SENT,
+ FPDU_MODE,
+ ABORTING,
+ CLOSING,
+ MORIBUND,
+ DEAD,
+};
+
+struct iwch_ep_common {
+ struct iw_cm_id *cm_id;
+ struct iwch_qp *qp;
+ struct t3cdev *tdev;
+ enum iwch_ep_state state;
+ struct kref kref;
+ spinlock_t lock;
+ struct sockaddr_in local_addr;
+ struct sockaddr_in remote_addr;
+ wait_queue_head_t waitq;
+ int rpl_done;
+ int rpl_err;
+};
+
+struct iwch_listen_ep {
+ struct iwch_ep_common com;
+ unsigned int stid;
+ int backlog;
+};
+
+struct iwch_ep {
+ struct iwch_ep_common com;
+ struct iwch_ep *parent_ep;
+ struct timer_list timer;
+ unsigned int atid;
+ u32 hwtid;
+ u32 snd_seq;
+ struct l2t_entry *l2t;
+ struct dst_entry *dst;
+ struct sk_buff *mpa_skb;
+ struct iwch_mpa_attributes mpa_attr;
+ unsigned int mpa_pkt_len;
+ u8 mpa_pkt[sizeof(struct mpa_message) + MPA_MAX_PRIVATE_DATA];
+ u8 tos;
+ u16 emss;
+ u16 plen;
+ u32 ird;
+ u32 ord;
+};
+
+static inline struct iwch_ep *to_ep(struct iw_cm_id *cm_id)
+{
+ return cm_id->provider_data;
+}
+
+static inline struct iwch_listen_ep *to_listen_ep(struct iw_cm_id *cm_id)
+{
+ return cm_id->provider_data;
+}
+
+static inline int compute_wscale(int win)
+{
+ int wscale = 0;
+
+ while (wscale < 14 && (65535<<wscale) < win)
+ wscale++;
+ return wscale;
+}
+
+/* CM prototypes */
+
+int iwch_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param);
+int iwch_create_listen(struct iw_cm_id *cm_id, int backlog);
+int iwch_destroy_listen(struct iw_cm_id *cm_id);
+int iwch_reject_cr(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len);
+int iwch_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param);
+int iwch_ep_disconnect(struct iwch_ep *ep, int abrupt, gfp_t gfp);
+int iwch_quiesce_tid(struct iwch_ep *ep);
+int iwch_resume_tid(struct iwch_ep *ep);
+void __free_ep(struct kref *kref);
+void iwch_rearp(struct iwch_ep *ep);
+int iwch_ep_redirect(void *ctx, struct dst_entry *old, struct dst_entry *new, struct l2t_entry *l2t);
+
+int __init iwch_cm_init(void);
+void __exit iwch_cm_term(void);
+
+#endif /* _IWCH_CM_H_ */
diff --git a/drivers/infiniband/hw/cxgb3/iwch_cq.c b/drivers/infiniband/hw/cxgb3/iwch_cq.c
new file mode 100644
index 00000000000..d7624c170ee
--- /dev/null
+++ b/drivers/infiniband/hw/cxgb3/iwch_cq.c
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2006 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include "iwch_provider.h"
+#include "iwch.h"
+
+/*
+ * Get one cq entry from cxio and map it to openib.
+ *
+ * Returns:
+ * 0 EMPTY;
+ * 1 cqe returned
+ * -EAGAIN caller must try again
+ * any other -errno fatal error
+ */
+static int iwch_poll_cq_one(struct iwch_dev *rhp, struct iwch_cq *chp,
+ struct ib_wc *wc)
+{
+ struct iwch_qp *qhp = NULL;
+ struct t3_cqe cqe, *rd_cqe;
+ struct t3_wq *wq;
+ u32 credit = 0;
+ u8 cqe_flushed;
+ u64 cookie;
+ int ret = 1;
+
+ rd_cqe = cxio_next_cqe(&chp->cq);
+
+ if (!rd_cqe)
+ return 0;
+
+ qhp = get_qhp(rhp, CQE_QPID(*rd_cqe));
+ if (!qhp)
+ wq = NULL;
+ else {
+ spin_lock(&qhp->lock);
+ wq = &(qhp->wq);
+ }
+ ret = cxio_poll_cq(wq, &(chp->cq), &cqe, &cqe_flushed, &cookie,
+ &credit);
+ if (t3a_device(chp->rhp) && credit) {
+ PDBG("%s updating %d cq credits on id %d\n", __FUNCTION__,
+ credit, chp->cq.cqid);
+ cxio_hal_cq_op(&rhp->rdev, &chp->cq, CQ_CREDIT_UPDATE, credit);
+ }
+
+ if (ret) {
+ ret = -EAGAIN;
+ goto out;
+ }
+ ret = 1;
+
+ wc->wr_id = cookie;
+ wc->qp = &qhp->ibqp;
+ wc->vendor_err = CQE_STATUS(cqe);
+
+ PDBG("%s qpid 0x%x type %d opcode %d status 0x%x wrid hi 0x%x "
+ "lo 0x%x cookie 0x%llx\n", __FUNCTION__,
+ CQE_QPID(cqe), CQE_TYPE(cqe),
+ CQE_OPCODE(cqe), CQE_STATUS(cqe), CQE_WRID_HI(cqe),
+ CQE_WRID_LOW(cqe), (unsigned long long) cookie);
+
+ if (CQE_TYPE(cqe) == 0) {
+ if (!CQE_STATUS(cqe))
+ wc->byte_len = CQE_LEN(cqe);
+ else
+ wc->byte_len = 0;
+ wc->opcode = IB_WC_RECV;
+ } else {
+ switch (CQE_OPCODE(cqe)) {
+ case T3_RDMA_WRITE:
+ wc->opcode = IB_WC_RDMA_WRITE;
+ break;
+ case T3_READ_REQ:
+ wc->opcode = IB_WC_RDMA_READ;
+ wc->byte_len = CQE_LEN(cqe);
+ break;
+ case T3_SEND:
+ case T3_SEND_WITH_SE:
+ wc->opcode = IB_WC_SEND;
+ break;
+ case T3_BIND_MW:
+ wc->opcode = IB_WC_BIND_MW;
+ break;
+
+ /* these aren't supported yet */
+ case T3_SEND_WITH_INV:
+ case T3_SEND_WITH_SE_INV:
+ case T3_LOCAL_INV:
+ case T3_FAST_REGISTER:
+ default:
+ printk(KERN_ERR MOD "Unexpected opcode %d "
+ "in the CQE received for QPID=0x%0x\n",
+ CQE_OPCODE(cqe), CQE_QPID(cqe));
+ ret = -EINVAL;
+ goto out;
+ }
+ }
+
+ if (cqe_flushed)
+ wc->status = IB_WC_WR_FLUSH_ERR;
+ else {
+
+ switch (CQE_STATUS(cqe)) {
+ case TPT_ERR_SUCCESS:
+ wc->status = IB_WC_SUCCESS;
+ break;
+ case TPT_ERR_STAG:
+ wc->status = IB_WC_LOC_ACCESS_ERR;
+ break;
+ case TPT_ERR_PDID:
+ wc->status = IB_WC_LOC_PROT_ERR;
+ break;
+ case TPT_ERR_QPID:
+ case TPT_ERR_ACCESS:
+ wc->status = IB_WC_LOC_ACCESS_ERR;
+ break;
+ case TPT_ERR_WRAP:
+ wc->status = IB_WC_GENERAL_ERR;
+ break;
+ case TPT_ERR_BOUND:
+ wc->status = IB_WC_LOC_LEN_ERR;
+ break;
+ case TPT_ERR_INVALIDATE_SHARED_MR:
+ case TPT_ERR_INVALIDATE_MR_WITH_MW_BOUND:
+ wc->status = IB_WC_MW_BIND_ERR;
+ break;
+ case TPT_ERR_CRC:
+ case TPT_ERR_MARKER:
+ case TPT_ERR_PDU_LEN_ERR:
+ case TPT_ERR_OUT_OF_RQE:
+ case TPT_ERR_DDP_VERSION:
+ case TPT_ERR_RDMA_VERSION:
+ case TPT_ERR_DDP_QUEUE_NUM:
+ case TPT_ERR_MSN:
+ case TPT_ERR_TBIT:
+ case TPT_ERR_MO:
+ case TPT_ERR_MSN_RANGE:
+ case TPT_ERR_IRD_OVERFLOW:
+ case TPT_ERR_OPCODE:
+ wc->status = IB_WC_FATAL_ERR;
+ break;
+ case TPT_ERR_SWFLUSH:
+ wc->status = IB_WC_WR_FLUSH_ERR;
+ break;
+ default:
+ printk(KERN_ERR MOD "Unexpected cqe_status 0x%x for "
+ "QPID=0x%0x\n", CQE_STATUS(cqe), CQE_QPID(cqe));
+ ret = -EINVAL;
+ }
+ }
+out:
+ if (wq)
+ spin_unlock(&qhp->lock);
+ return ret;
+}
+
+int iwch_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc)
+{
+ struct iwch_dev *rhp;
+ struct iwch_cq *chp;
+ unsigned long flags;
+ int npolled;
+ int err = 0;
+
+ chp = to_iwch_cq(ibcq);
+ rhp = chp->rhp;
+
+ spin_lock_irqsave(&chp->lock, flags);
+ for (npolled = 0; npolled < num_entries; ++npolled) {
+#ifdef DEBUG
+ int i=0;
+#endif
+
+ /*
+ * Because T3 can post CQEs that are _not_ associated
+ * with a WR, we might have to poll again after removing
+ * one of these.
+ */
+ do {
+ err = iwch_poll_cq_one(rhp, chp, wc + npolled);
+#ifdef DEBUG
+ BUG_ON(++i > 1000);
+#endif
+ } while (err == -EAGAIN);
+ if (err <= 0)
+ break;
+ }
+ spin_unlock_irqrestore(&chp->lock, flags);
+
+ if (err < 0)
+ return err;
+ else {
+ return npolled;
+ }
+}
diff --git a/drivers/infiniband/hw/cxgb3/iwch_ev.c b/drivers/infiniband/hw/cxgb3/iwch_ev.c
new file mode 100644
index 00000000000..54362afbf72
--- /dev/null
+++ b/drivers/infiniband/hw/cxgb3/iwch_ev.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2006 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include <linux/slab.h>
+#include <linux/mman.h>
+#include <net/sock.h>
+#include "iwch_provider.h"
+#include "iwch.h"
+#include "iwch_cm.h"
+#include "cxio_hal.h"
+#include "cxio_wr.h"
+
+static void post_qp_event(struct iwch_dev *rnicp, struct iwch_cq *chp,
+ struct respQ_msg_t *rsp_msg,
+ enum ib_event_type ib_event,
+ int send_term)
+{
+ struct ib_event event;
+ struct iwch_qp_attributes attrs;
+ struct iwch_qp *qhp;
+
+ printk(KERN_ERR "%s - AE qpid 0x%x opcode %d status 0x%x "
+ "type %d wrid.hi 0x%x wrid.lo 0x%x \n", __FUNCTION__,
+ CQE_QPID(rsp_msg->cqe), CQE_OPCODE(rsp_msg->cqe),
+ CQE_STATUS(rsp_msg->cqe), CQE_TYPE(rsp_msg->cqe),
+ CQE_WRID_HI(rsp_msg->cqe), CQE_WRID_LOW(rsp_msg->cqe));
+
+ spin_lock(&rnicp->lock);
+ qhp = get_qhp(rnicp, CQE_QPID(rsp_msg->cqe));
+
+ if (!qhp) {
+ printk(KERN_ERR "%s unaffiliated error 0x%x qpid 0x%x\n",
+ __FUNCTION__, CQE_STATUS(rsp_msg->cqe),
+ CQE_QPID(rsp_msg->cqe));
+ spin_unlock(&rnicp->lock);
+ return;
+ }
+
+ if ((qhp->attr.state == IWCH_QP_STATE_ERROR) ||
+ (qhp->attr.state == IWCH_QP_STATE_TERMINATE)) {
+ PDBG("%s AE received after RTS - "
+ "qp state %d qpid 0x%x status 0x%x\n", __FUNCTION__,
+ qhp->attr.state, qhp->wq.qpid, CQE_STATUS(rsp_msg->cqe));
+ spin_unlock(&rnicp->lock);
+ return;
+ }
+
+ atomic_inc(&qhp->refcnt);
+ spin_unlock(&rnicp->lock);
+
+ event.event = ib_event;
+ event.device = chp->ibcq.device;
+ if (ib_event == IB_EVENT_CQ_ERR)
+ event.element.cq = &chp->ibcq;
+ else
+ event.element.qp = &qhp->ibqp;
+
+ if (qhp->ibqp.event_handler)
+ (*qhp->ibqp.event_handler)(&event, qhp->ibqp.qp_context);
+
+ if (qhp->attr.state == IWCH_QP_STATE_RTS) {
+ attrs.next_state = IWCH_QP_STATE_TERMINATE;
+ iwch_modify_qp(qhp->rhp, qhp, IWCH_QP_ATTR_NEXT_STATE,
+ &attrs, 1);
+ if (send_term)
+ iwch_post_terminate(qhp, rsp_msg);
+ }
+
+ if (atomic_dec_and_test(&qhp->refcnt))
+ wake_up(&qhp->wait);
+}
+
+void iwch_ev_dispatch(struct cxio_rdev *rdev_p, struct sk_buff *skb)
+{
+ struct iwch_dev *rnicp;
+ struct respQ_msg_t *rsp_msg = (struct respQ_msg_t *) skb->data;
+ struct iwch_cq *chp;
+ struct iwch_qp *qhp;
+ u32 cqid = RSPQ_CQID(rsp_msg);
+
+ rnicp = (struct iwch_dev *) rdev_p->ulp;
+ spin_lock(&rnicp->lock);
+ chp = get_chp(rnicp, cqid);
+ qhp = get_qhp(rnicp, CQE_QPID(rsp_msg->cqe));
+ if (!chp || !qhp) {
+ printk(KERN_ERR MOD "BAD AE cqid 0x%x qpid 0x%x opcode %d "
+ "status 0x%x type %d wrid.hi 0x%x wrid.lo 0x%x \n",
+ cqid, CQE_QPID(rsp_msg->cqe),
+ CQE_OPCODE(rsp_msg->cqe), CQE_STATUS(rsp_msg->cqe),
+ CQE_TYPE(rsp_msg->cqe), CQE_WRID_HI(rsp_msg->cqe),
+ CQE_WRID_LOW(rsp_msg->cqe));
+ spin_unlock(&rnicp->lock);
+ goto out;
+ }
+ iwch_qp_add_ref(&qhp->ibqp);
+ atomic_inc(&chp->refcnt);
+ spin_unlock(&rnicp->lock);
+
+ /*
+ * 1) completion of our sending a TERMINATE.
+ * 2) incoming TERMINATE message.
+ */
+ if ((CQE_OPCODE(rsp_msg->cqe) == T3_TERMINATE) &&
+ (CQE_STATUS(rsp_msg->cqe) == 0)) {
+ if (SQ_TYPE(rsp_msg->cqe)) {
+ PDBG("%s QPID 0x%x ep %p disconnecting\n",
+ __FUNCTION__, qhp->wq.qpid, qhp->ep);
+ iwch_ep_disconnect(qhp->ep, 0, GFP_ATOMIC);
+ } else {
+ PDBG("%s post REQ_ERR AE QPID 0x%x\n", __FUNCTION__,
+ qhp->wq.qpid);
+ post_qp_event(rnicp, chp, rsp_msg,
+ IB_EVENT_QP_REQ_ERR, 0);
+ iwch_ep_disconnect(qhp->ep, 0, GFP_ATOMIC);
+ }
+ goto done;
+ }
+
+ /* Bad incoming Read request */
+ if (SQ_TYPE(rsp_msg->cqe) &&
+ (CQE_OPCODE(rsp_msg->cqe) == T3_READ_RESP)) {
+ post_qp_event(rnicp, chp, rsp_msg, IB_EVENT_QP_REQ_ERR, 1);
+ goto done;
+ }
+
+ /* Bad incoming write */
+ if (RQ_TYPE(rsp_msg->cqe) &&
+ (CQE_OPCODE(rsp_msg->cqe) == T3_RDMA_WRITE)) {
+ post_qp_event(rnicp, chp, rsp_msg, IB_EVENT_QP_REQ_ERR, 1);
+ goto done;
+ }
+
+ switch (CQE_STATUS(rsp_msg->cqe)) {
+
+ /* Completion Events */
+ case TPT_ERR_SUCCESS:
+
+ /*
+ * Confirm the destination entry if this is a RECV completion.
+ */
+ if (qhp->ep && SQ_TYPE(rsp_msg->cqe))
+ dst_confirm(qhp->ep->dst);
+ (*chp->ibcq.comp_handler)(&chp->ibcq, chp->ibcq.cq_context);
+ break;
+
+ case TPT_ERR_STAG:
+ case TPT_ERR_PDID:
+ case TPT_ERR_QPID:
+ case TPT_ERR_ACCESS:
+ case TPT_ERR_WRAP:
+ case TPT_ERR_BOUND:
+ case TPT_ERR_INVALIDATE_SHARED_MR:
+ case TPT_ERR_INVALIDATE_MR_WITH_MW_BOUND:
+ printk(KERN_ERR "%s - CQE Err qpid 0x%x opcode %d status 0x%x "
+ "type %d wrid.hi 0x%x wrid.lo 0x%x \n", __FUNCTION__,
+ CQE_QPID(rsp_msg->cqe), CQE_OPCODE(rsp_msg->cqe),
+ CQE_STATUS(rsp_msg->cqe), CQE_TYPE(rsp_msg->cqe),
+ CQE_WRID_HI(rsp_msg->cqe), CQE_WRID_LOW(rsp_msg->cqe));
+ (*chp->ibcq.comp_handler)(&chp->ibcq, chp->ibcq.cq_context);
+ post_qp_event(rnicp, chp, rsp_msg, IB_EVENT_QP_ACCESS_ERR, 1);
+ break;
+
+ /* Device Fatal Errors */
+ case TPT_ERR_ECC:
+ case TPT_ERR_ECC_PSTAG:
+ case TPT_ERR_INTERNAL_ERR:
+ post_qp_event(rnicp, chp, rsp_msg, IB_EVENT_DEVICE_FATAL, 1);
+ break;
+
+ /* QP Fatal Errors */
+ case TPT_ERR_OUT_OF_RQE:
+ case TPT_ERR_PBL_ADDR_BOUND:
+ case TPT_ERR_CRC:
+ case TPT_ERR_MARKER:
+ case TPT_ERR_PDU_LEN_ERR:
+ case TPT_ERR_DDP_VERSION:
+ case TPT_ERR_RDMA_VERSION:
+ case TPT_ERR_OPCODE:
+ case TPT_ERR_DDP_QUEUE_NUM:
+ case TPT_ERR_MSN:
+ case TPT_ERR_TBIT:
+ case TPT_ERR_MO:
+ case TPT_ERR_MSN_GAP:
+ case TPT_ERR_MSN_RANGE:
+ case TPT_ERR_RQE_ADDR_BOUND:
+ case TPT_ERR_IRD_OVERFLOW:
+ post_qp_event(rnicp, chp, rsp_msg, IB_EVENT_QP_FATAL, 1);
+ break;
+
+ default:
+ printk(KERN_ERR MOD "Unknown T3 status 0x%x QPID 0x%x\n",
+ CQE_STATUS(rsp_msg->cqe), qhp->wq.qpid);
+ post_qp_event(rnicp, chp, rsp_msg, IB_EVENT_QP_FATAL, 1);
+ break;
+ }
+done:
+ if (atomic_dec_and_test(&chp->refcnt))
+ wake_up(&chp->wait);
+ iwch_qp_rem_ref(&qhp->ibqp);
+out:
+ dev_kfree_skb_irq(skb);
+}
diff --git a/drivers/infiniband/hw/cxgb3/iwch_mem.c b/drivers/infiniband/hw/cxgb3/iwch_mem.c
new file mode 100644
index 00000000000..a6c2c4ba29e
--- /dev/null
+++ b/drivers/infiniband/hw/cxgb3/iwch_mem.c
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2006 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include <asm/byteorder.h>
+
+#include <rdma/iw_cm.h>
+#include <rdma/ib_verbs.h>
+
+#include "cxio_hal.h"
+#include "iwch.h"
+#include "iwch_provider.h"
+
+int iwch_register_mem(struct iwch_dev *rhp, struct iwch_pd *php,
+ struct iwch_mr *mhp,
+ int shift,
+ __be64 *page_list)
+{
+ u32 stag;
+ u32 mmid;
+
+
+ if (cxio_register_phys_mem(&rhp->rdev,
+ &stag, mhp->attr.pdid,
+ mhp->attr.perms,
+ mhp->attr.zbva,
+ mhp->attr.va_fbo,
+ mhp->attr.len,
+ shift-12,
+ page_list,
+ &mhp->attr.pbl_size, &mhp->attr.pbl_addr))
+ return -ENOMEM;
+ mhp->attr.state = 1;
+ mhp->attr.stag = stag;
+ mmid = stag >> 8;
+ mhp->ibmr.rkey = mhp->ibmr.lkey = stag;
+ insert_handle(rhp, &rhp->mmidr, mhp, mmid);
+ PDBG("%s mmid 0x%x mhp %p\n", __FUNCTION__, mmid, mhp);
+ return 0;
+}
+
+int iwch_reregister_mem(struct iwch_dev *rhp, struct iwch_pd *php,
+ struct iwch_mr *mhp,
+ int shift,
+ __be64 *page_list,
+ int npages)
+{
+ u32 stag;
+ u32 mmid;
+
+
+ /* We could support this... */
+ if (npages > mhp->attr.pbl_size)
+ return -ENOMEM;
+
+ stag = mhp->attr.stag;
+ if (cxio_reregister_phys_mem(&rhp->rdev,
+ &stag, mhp->attr.pdid,
+ mhp->attr.perms,
+ mhp->attr.zbva,
+ mhp->attr.va_fbo,
+ mhp->attr.len,
+ shift-12,
+ page_list,
+ &mhp->attr.pbl_size, &mhp->attr.pbl_addr))
+ return -ENOMEM;
+ mhp->attr.state = 1;
+ mhp->attr.stag = stag;
+ mmid = stag >> 8;
+ mhp->ibmr.rkey = mhp->ibmr.lkey = stag;
+ insert_handle(rhp, &rhp->mmidr, mhp, mmid);
+ PDBG("%s mmid 0x%x mhp %p\n", __FUNCTION__, mmid, mhp);
+ return 0;
+}
+
+int build_phys_page_list(struct ib_phys_buf *buffer_list,
+ int num_phys_buf,
+ u64 *iova_start,
+ u64 *total_size,
+ int *npages,
+ int *shift,
+ __be64 **page_list)
+{
+ u64 mask;
+ int i, j, n;
+
+ mask = 0;
+ *total_size = 0;
+ for (i = 0; i < num_phys_buf; ++i) {
+ if (i != 0 && buffer_list[i].addr & ~PAGE_MASK)
+ return -EINVAL;
+ if (i != 0 && i != num_phys_buf - 1 &&
+ (buffer_list[i].size & ~PAGE_MASK))
+ return -EINVAL;
+ *total_size += buffer_list[i].size;
+ if (i > 0)
+ mask |= buffer_list[i].addr;
+ }
+
+ if (*total_size > 0xFFFFFFFFULL)
+ return -ENOMEM;
+
+ /* Find largest page shift we can use to cover buffers */
+ for (*shift = PAGE_SHIFT; *shift < 27; ++(*shift))
+ if (num_phys_buf > 1) {
+ if ((1ULL << *shift) & mask)
+ break;
+ } else
+ if (1ULL << *shift >=
+ buffer_list[0].size +
+ (buffer_list[0].addr & ((1ULL << *shift) - 1)))
+ break;
+
+ buffer_list[0].size += buffer_list[0].addr & ((1ULL << *shift) - 1);
+ buffer_list[0].addr &= ~0ull << *shift;
+
+ *npages = 0;
+ for (i = 0; i < num_phys_buf; ++i)
+ *npages += (buffer_list[i].size +
+ (1ULL << *shift) - 1) >> *shift;
+
+ if (!*npages)
+ return -EINVAL;
+
+ *page_list = kmalloc(sizeof(u64) * *npages, GFP_KERNEL);
+ if (!*page_list)
+ return -ENOMEM;
+
+ n = 0;
+ for (i = 0; i < num_phys_buf; ++i)
+ for (j = 0;
+ j < (buffer_list[i].size + (1ULL << *shift) - 1) >> *shift;
+ ++j)
+ (*page_list)[n++] = cpu_to_be64(buffer_list[i].addr +
+ ((u64) j << *shift));
+
+ PDBG("%s va 0x%llx mask 0x%llx shift %d len %lld pbl_size %d\n",
+ __FUNCTION__, (unsigned long long) *iova_start,
+ (unsigned long long) mask, *shift, (unsigned long long) *total_size,
+ *npages);
+
+ return 0;
+
+}
diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.c b/drivers/infiniband/hw/cxgb3/iwch_provider.c
new file mode 100644
index 00000000000..2aef122f995
--- /dev/null
+++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c
@@ -0,0 +1,1202 @@
+/*
+ * Copyright (c) 2006 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/ethtool.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/byteorder.h>
+
+#include <rdma/iw_cm.h>
+#include <rdma/ib_verbs.h>
+#include <rdma/ib_smi.h>
+#include <rdma/ib_user_verbs.h>
+
+#include "cxio_hal.h"
+#include "iwch.h"
+#include "iwch_provider.h"
+#include "iwch_cm.h"
+#include "iwch_user.h"
+
+static int iwch_modify_port(struct ib_device *ibdev,
+ u8 port, int port_modify_mask,
+ struct ib_port_modify *props)
+{
+ return -ENOSYS;
+}
+
+static struct ib_ah *iwch_ah_create(struct ib_pd *pd,
+ struct ib_ah_attr *ah_attr)
+{
+ return ERR_PTR(-ENOSYS);
+}
+
+static int iwch_ah_destroy(struct ib_ah *ah)
+{
+ return -ENOSYS;
+}
+
+static int iwch_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
+{
+ return -ENOSYS;
+}
+
+static int iwch_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
+{
+ return -ENOSYS;
+}
+
+static int iwch_process_mad(struct ib_device *ibdev,
+ int mad_flags,
+ u8 port_num,
+ struct ib_wc *in_wc,
+ struct ib_grh *in_grh,
+ struct ib_mad *in_mad, struct ib_mad *out_mad)
+{
+ return -ENOSYS;
+}
+
+static int iwch_dealloc_ucontext(struct ib_ucontext *context)
+{
+ struct iwch_dev *rhp = to_iwch_dev(context->device);
+ struct iwch_ucontext *ucontext = to_iwch_ucontext(context);
+ struct iwch_mm_entry *mm, *tmp;
+
+ PDBG("%s context %p\n", __FUNCTION__, context);
+ list_for_each_entry_safe(mm, tmp, &ucontext->mmaps, entry)
+ kfree(mm);
+ cxio_release_ucontext(&rhp->rdev, &ucontext->uctx);
+ kfree(ucontext);
+ return 0;
+}
+
+static struct ib_ucontext *iwch_alloc_ucontext(struct ib_device *ibdev,
+ struct ib_udata *udata)
+{
+ struct iwch_ucontext *context;
+ struct iwch_dev *rhp = to_iwch_dev(ibdev);
+
+ PDBG("%s ibdev %p\n", __FUNCTION__, ibdev);
+ context = kzalloc(sizeof(*context), GFP_KERNEL);
+ if (!context)
+ return ERR_PTR(-ENOMEM);
+ cxio_init_ucontext(&rhp->rdev, &context->uctx);
+ INIT_LIST_HEAD(&context->mmaps);
+ spin_lock_init(&context->mmap_lock);
+ return &context->ibucontext;
+}
+
+static int iwch_destroy_cq(struct ib_cq *ib_cq)
+{
+ struct iwch_cq *chp;
+
+ PDBG("%s ib_cq %p\n", __FUNCTION__, ib_cq);
+ chp = to_iwch_cq(ib_cq);
+
+ remove_handle(chp->rhp, &chp->rhp->cqidr, chp->cq.cqid);
+ atomic_dec(&chp->refcnt);
+ wait_event(chp->wait, !atomic_read(&chp->refcnt));
+
+ cxio_destroy_cq(&chp->rhp->rdev, &chp->cq);
+ kfree(chp);
+ return 0;
+}
+
+static struct ib_cq *iwch_create_cq(struct ib_device *ibdev, int entries,
+ struct ib_ucontext *ib_context,
+ struct ib_udata *udata)
+{
+ struct iwch_dev *rhp;
+ struct iwch_cq *chp;
+ struct iwch_create_cq_resp uresp;
+ struct iwch_create_cq_req ureq;
+ struct iwch_ucontext *ucontext = NULL;
+
+ PDBG("%s ib_dev %p entries %d\n", __FUNCTION__, ibdev, entries);
+ rhp = to_iwch_dev(ibdev);
+ chp = kzalloc(sizeof(*chp), GFP_KERNEL);
+ if (!chp)
+ return ERR_PTR(-ENOMEM);
+
+ if (ib_context) {
+ ucontext = to_iwch_ucontext(ib_context);
+ if (!t3a_device(rhp)) {
+ if (ib_copy_from_udata(&ureq, udata, sizeof (ureq))) {
+ kfree(chp);
+ return ERR_PTR(-EFAULT);
+ }
+ chp->user_rptr_addr = (u32 __user *)(unsigned long)ureq.user_rptr_addr;
+ }
+ }
+
+ if (t3a_device(rhp)) {
+
+ /*
+ * T3A: Add some fluff to handle extra CQEs inserted
+ * for various errors.
+ * Additional CQE possibilities:
+ * TERMINATE,
+ * incoming RDMA WRITE Failures
+ * incoming RDMA READ REQUEST FAILUREs
+ * NOTE: We cannot ensure the CQ won't overflow.
+ */
+ entries += 16;
+ }
+ entries = roundup_pow_of_two(entries);
+ chp->cq.size_log2 = ilog2(entries);
+
+ if (cxio_create_cq(&rhp->rdev, &chp->cq)) {
+ kfree(chp);
+ return ERR_PTR(-ENOMEM);
+ }
+ chp->rhp = rhp;
+ chp->ibcq.cqe = (1 << chp->cq.size_log2) - 1;
+ spin_lock_init(&chp->lock);
+ atomic_set(&chp->refcnt, 1);
+ init_waitqueue_head(&chp->wait);
+ insert_handle(rhp, &rhp->cqidr, chp, chp->cq.cqid);
+
+ if (ucontext) {
+ struct iwch_mm_entry *mm;
+
+ mm = kmalloc(sizeof *mm, GFP_KERNEL);
+ if (!mm) {
+ iwch_destroy_cq(&chp->ibcq);
+ return ERR_PTR(-ENOMEM);
+ }
+ uresp.cqid = chp->cq.cqid;
+ uresp.size_log2 = chp->cq.size_log2;
+ spin_lock(&ucontext->mmap_lock);
+ uresp.key = ucontext->key;
+ ucontext->key += PAGE_SIZE;
+ spin_unlock(&ucontext->mmap_lock);
+ if (ib_copy_to_udata(udata, &uresp, sizeof (uresp))) {
+ kfree(mm);
+ iwch_destroy_cq(&chp->ibcq);
+ return ERR_PTR(-EFAULT);
+ }
+ mm->key = uresp.key;
+ mm->addr = virt_to_phys(chp->cq.queue);
+ mm->len = PAGE_ALIGN((1UL << uresp.size_log2) *
+ sizeof (struct t3_cqe));
+ insert_mmap(ucontext, mm);
+ }
+ PDBG("created cqid 0x%0x chp %p size 0x%0x, dma_addr 0x%0llx\n",
+ chp->cq.cqid, chp, (1 << chp->cq.size_log2),
+ (unsigned long long) chp->cq.dma_addr);
+ return &chp->ibcq;
+}
+
+static int iwch_resize_cq(struct ib_cq *cq, int cqe, struct ib_udata *udata)
+{
+#ifdef notyet
+ struct iwch_cq *chp = to_iwch_cq(cq);
+ struct t3_cq oldcq, newcq;
+ int ret;
+
+ PDBG("%s ib_cq %p cqe %d\n", __FUNCTION__, cq, cqe);
+
+ /* We don't downsize... */
+ if (cqe <= cq->cqe)
+ return 0;
+
+ /* create new t3_cq with new size */
+ cqe = roundup_pow_of_two(cqe+1);
+ newcq.size_log2 = ilog2(cqe);
+
+ /* Dont allow resize to less than the current wce count */
+ if (cqe < Q_COUNT(chp->cq.rptr, chp->cq.wptr)) {
+ return -ENOMEM;
+ }
+
+ /* Quiesce all QPs using this CQ */
+ ret = iwch_quiesce_qps(chp);
+ if (ret) {
+ return ret;
+ }
+
+ ret = cxio_create_cq(&chp->rhp->rdev, &newcq);
+ if (ret) {
+ return ret;
+ }
+
+ /* copy CQEs */
+ memcpy(newcq.queue, chp->cq.queue, (1 << chp->cq.size_log2) *
+ sizeof(struct t3_cqe));
+
+ /* old iwch_qp gets new t3_cq but keeps old cqid */
+ oldcq = chp->cq;
+ chp->cq = newcq;
+ chp->cq.cqid = oldcq.cqid;
+
+ /* resize new t3_cq to update the HW context */
+ ret = cxio_resize_cq(&chp->rhp->rdev, &chp->cq);
+ if (ret) {
+ chp->cq = oldcq;
+ return ret;
+ }
+ chp->ibcq.cqe = (1<<chp->cq.size_log2) - 1;
+
+ /* destroy old t3_cq */
+ oldcq.cqid = newcq.cqid;
+ ret = cxio_destroy_cq(&chp->rhp->rdev, &oldcq);
+ if (ret) {
+ printk(KERN_ERR MOD "%s - cxio_destroy_cq failed %d\n",
+ __FUNCTION__, ret);
+ }
+
+ /* add user hooks here */
+
+ /* resume qps */
+ ret = iwch_resume_qps(chp);
+ return ret;
+#else
+ return -ENOSYS;
+#endif
+}
+
+static int iwch_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify notify)
+{
+ struct iwch_dev *rhp;
+ struct iwch_cq *chp;
+ enum t3_cq_opcode cq_op;
+ int err;
+ unsigned long flag;
+ u32 rptr;
+
+ chp = to_iwch_cq(ibcq);
+ rhp = chp->rhp;
+ if (notify == IB_CQ_SOLICITED)
+ cq_op = CQ_ARM_SE;
+ else
+ cq_op = CQ_ARM_AN;
+ if (chp->user_rptr_addr) {
+ if (get_user(rptr, chp->user_rptr_addr))
+ return -EFAULT;
+ spin_lock_irqsave(&chp->lock, flag);
+ chp->cq.rptr = rptr;
+ } else
+ spin_lock_irqsave(&chp->lock, flag);
+ PDBG("%s rptr 0x%x\n", __FUNCTION__, chp->cq.rptr);
+ err = cxio_hal_cq_op(&rhp->rdev, &chp->cq, cq_op, 0);
+ spin_unlock_irqrestore(&chp->lock, flag);
+ if (err)
+ printk(KERN_ERR MOD "Error %d rearming CQID 0x%x\n", err,
+ chp->cq.cqid);
+ return err;
+}
+
+static int iwch_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
+{
+ int len = vma->vm_end - vma->vm_start;
+ u32 key = vma->vm_pgoff << PAGE_SHIFT;
+ struct cxio_rdev *rdev_p;
+ int ret = 0;
+ struct iwch_mm_entry *mm;
+ struct iwch_ucontext *ucontext;
+
+ PDBG("%s pgoff 0x%lx key 0x%x len %d\n", __FUNCTION__, vma->vm_pgoff,
+ key, len);
+
+ if (vma->vm_start & (PAGE_SIZE-1)) {
+ return -EINVAL;
+ }
+
+ rdev_p = &(to_iwch_dev(context->device)->rdev);
+ ucontext = to_iwch_ucontext(context);
+
+ mm = remove_mmap(ucontext, key, len);
+ if (!mm)
+ return -EINVAL;
+ kfree(mm);
+
+ if ((mm->addr >= rdev_p->rnic_info.udbell_physbase) &&
+ (mm->addr < (rdev_p->rnic_info.udbell_physbase +
+ rdev_p->rnic_info.udbell_len))) {
+
+ /*
+ * Map T3 DB register.
+ */
+ if (vma->vm_flags & VM_READ) {
+ return -EPERM;
+ }
+
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ vma->vm_flags |= VM_DONTCOPY | VM_DONTEXPAND;
+ vma->vm_flags &= ~VM_MAYREAD;
+ ret = io_remap_pfn_range(vma, vma->vm_start,
+ mm->addr >> PAGE_SHIFT,
+ len, vma->vm_page_prot);
+ } else {
+
+ /*
+ * Map WQ or CQ contig dma memory...
+ */
+ ret = remap_pfn_range(vma, vma->vm_start,
+ mm->addr >> PAGE_SHIFT,
+ len, vma->vm_page_prot);
+ }
+
+ return ret;
+}
+
+static int iwch_deallocate_pd(struct ib_pd *pd)
+{
+ struct iwch_dev *rhp;
+ struct iwch_pd *php;
+
+ php = to_iwch_pd(pd);
+ rhp = php->rhp;
+ PDBG("%s ibpd %p pdid 0x%x\n", __FUNCTION__, pd, php->pdid);
+ cxio_hal_put_pdid(rhp->rdev.rscp, php->pdid);
+ kfree(php);
+ return 0;
+}
+
+static struct ib_pd *iwch_allocate_pd(struct ib_device *ibdev,
+ struct ib_ucontext *context,
+ struct ib_udata *udata)
+{
+ struct iwch_pd *php;
+ u32 pdid;
+ struct iwch_dev *rhp;
+
+ PDBG("%s ibdev %p\n", __FUNCTION__, ibdev);
+ rhp = (struct iwch_dev *) ibdev;
+ pdid = cxio_hal_get_pdid(rhp->rdev.rscp);
+ if (!pdid)
+ return ERR_PTR(-EINVAL);
+ php = kzalloc(sizeof(*php), GFP_KERNEL);
+ if (!php) {
+ cxio_hal_put_pdid(rhp->rdev.rscp, pdid);
+ return ERR_PTR(-ENOMEM);
+ }
+ php->pdid = pdid;
+ php->rhp = rhp;
+ if (context) {
+ if (ib_copy_to_udata(udata, &php->pdid, sizeof (__u32))) {
+ iwch_deallocate_pd(&php->ibpd);
+ return ERR_PTR(-EFAULT);
+ }
+ }
+ PDBG("%s pdid 0x%0x ptr 0x%p\n", __FUNCTION__, pdid, php);
+ return &php->ibpd;
+}
+
+static int iwch_dereg_mr(struct ib_mr *ib_mr)
+{
+ struct iwch_dev *rhp;
+ struct iwch_mr *mhp;
+ u32 mmid;
+
+ PDBG("%s ib_mr %p\n", __FUNCTION__, ib_mr);
+ /* There can be no memory windows */
+ if (atomic_read(&ib_mr->usecnt))
+ return -EINVAL;
+
+ mhp = to_iwch_mr(ib_mr);
+ rhp = mhp->rhp;
+ mmid = mhp->attr.stag >> 8;
+ cxio_dereg_mem(&rhp->rdev, mhp->attr.stag, mhp->attr.pbl_size,
+ mhp->attr.pbl_addr);
+ remove_handle(rhp, &rhp->mmidr, mmid);
+ if (mhp->kva)
+ kfree((void *) (unsigned long) mhp->kva);
+ PDBG("%s mmid 0x%x ptr %p\n", __FUNCTION__, mmid, mhp);
+ kfree(mhp);
+ return 0;
+}
+
+static struct ib_mr *iwch_register_phys_mem(struct ib_pd *pd,
+ struct ib_phys_buf *buffer_list,
+ int num_phys_buf,
+ int acc,
+ u64 *iova_start)
+{
+ __be64 *page_list;
+ int shift;
+ u64 total_size;
+ int npages;
+ struct iwch_dev *rhp;
+ struct iwch_pd *php;
+ struct iwch_mr *mhp;
+ int ret;
+
+ PDBG("%s ib_pd %p\n", __FUNCTION__, pd);
+ php = to_iwch_pd(pd);
+ rhp = php->rhp;
+
+ acc = iwch_convert_access(acc);
+
+
+ mhp = kzalloc(sizeof(*mhp), GFP_KERNEL);
+ if (!mhp)
+ return ERR_PTR(-ENOMEM);
+
+ /* First check that we have enough alignment */
+ if ((*iova_start & ~PAGE_MASK) != (buffer_list[0].addr & ~PAGE_MASK)) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ if (num_phys_buf > 1 &&
+ ((buffer_list[0].addr + buffer_list[0].size) & ~PAGE_MASK)) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ ret = build_phys_page_list(buffer_list, num_phys_buf, iova_start,
+ &total_size, &npages, &shift, &page_list);
+ if (ret)
+ goto err;
+
+ mhp->rhp = rhp;
+ mhp->attr.pdid = php->pdid;
+ mhp->attr.zbva = 0;
+
+ /* NOTE: TPT perms are backwards from BIND WR perms! */
+ mhp->attr.perms = (acc & 0x1) << 3;
+ mhp->attr.perms |= (acc & 0x2) << 1;
+ mhp->attr.perms |= (acc & 0x4) >> 1;
+ mhp->attr.perms |= (acc & 0x8) >> 3;
+
+ mhp->attr.va_fbo = *iova_start;
+ mhp->attr.page_size = shift - 12;
+
+ mhp->attr.len = (u32) total_size;
+ mhp->attr.pbl_size = npages;
+ ret = iwch_register_mem(rhp, php, mhp, shift, page_list);
+ kfree(page_list);
+ if (ret) {
+ goto err;
+ }
+ return &mhp->ibmr;
+err:
+ kfree(mhp);
+ return ERR_PTR(ret);
+
+}
+
+static int iwch_reregister_phys_mem(struct ib_mr *mr,
+ int mr_rereg_mask,
+ struct ib_pd *pd,
+ struct ib_phys_buf *buffer_list,
+ int num_phys_buf,
+ int acc, u64 * iova_start)
+{
+
+ struct iwch_mr mh, *mhp;
+ struct iwch_pd *php;
+ struct iwch_dev *rhp;
+ int new_acc;
+ __be64 *page_list = NULL;
+ int shift = 0;
+ u64 total_size;
+ int npages;
+ int ret;
+
+ PDBG("%s ib_mr %p ib_pd %p\n", __FUNCTION__, mr, pd);
+
+ /* There can be no memory windows */
+ if (atomic_read(&mr->usecnt))
+ return -EINVAL;
+
+ mhp = to_iwch_mr(mr);
+ rhp = mhp->rhp;
+ php = to_iwch_pd(mr->pd);
+
+ /* make sure we are on the same adapter */
+ if (rhp != php->rhp)
+ return -EINVAL;
+
+ new_acc = mhp->attr.perms;
+
+ memcpy(&mh, mhp, sizeof *mhp);
+
+ if (mr_rereg_mask & IB_MR_REREG_PD)
+ php = to_iwch_pd(pd);
+ if (mr_rereg_mask & IB_MR_REREG_ACCESS)
+ mh.attr.perms = iwch_convert_access(acc);
+ if (mr_rereg_mask & IB_MR_REREG_TRANS)
+ ret = build_phys_page_list(buffer_list, num_phys_buf,
+ iova_start,
+ &total_size, &npages,
+ &shift, &page_list);
+
+ ret = iwch_reregister_mem(rhp, php, &mh, shift, page_list, npages);
+ kfree(page_list);
+ if (ret) {
+ return ret;
+ }
+ if (mr_rereg_mask & IB_MR_REREG_PD)
+ mhp->attr.pdid = php->pdid;
+ if (mr_rereg_mask & IB_MR_REREG_ACCESS)
+ mhp->attr.perms = acc;
+ if (mr_rereg_mask & IB_MR_REREG_TRANS) {
+ mhp->attr.zbva = 0;
+ mhp->attr.va_fbo = *iova_start;
+ mhp->attr.page_size = shift - 12;
+ mhp->attr.len = (u32) total_size;
+ mhp->attr.pbl_size = npages;
+ }
+
+ return 0;
+}
+
+
+static struct ib_mr *iwch_reg_user_mr(struct ib_pd *pd, struct ib_umem *region,
+ int acc, struct ib_udata *udata)
+{
+ __be64 *pages;
+ int shift, n, len;
+ int i, j, k;
+ int err = 0;
+ struct ib_umem_chunk *chunk;
+ struct iwch_dev *rhp;
+ struct iwch_pd *php;
+ struct iwch_mr *mhp;
+ struct iwch_reg_user_mr_resp uresp;
+
+ PDBG("%s ib_pd %p\n", __FUNCTION__, pd);
+ shift = ffs(region->page_size) - 1;
+
+ php = to_iwch_pd(pd);
+ rhp = php->rhp;
+ mhp = kzalloc(sizeof(*mhp), GFP_KERNEL);
+ if (!mhp)
+ return ERR_PTR(-ENOMEM);
+
+ n = 0;
+ list_for_each_entry(chunk, &region->chunk_list, list)
+ n += chunk->nents;
+
+ pages = kmalloc(n * sizeof(u64), GFP_KERNEL);
+ if (!pages) {
+ err = -ENOMEM;
+ goto err;
+ }
+
+ acc = iwch_convert_access(acc);
+
+ i = n = 0;
+
+ list_for_each_entry(chunk, &region->chunk_list, list)
+ for (j = 0; j < chunk->nmap; ++j) {
+ len = sg_dma_len(&chunk->page_list[j]) >> shift;
+ for (k = 0; k < len; ++k) {
+ pages[i++] = cpu_to_be64(sg_dma_address(
+ &chunk->page_list[j]) +
+ region->page_size * k);
+ }
+ }
+
+ mhp->rhp = rhp;
+ mhp->attr.pdid = php->pdid;
+ mhp->attr.zbva = 0;
+ mhp->attr.perms = (acc & 0x1) << 3;
+ mhp->attr.perms |= (acc & 0x2) << 1;
+ mhp->attr.perms |= (acc & 0x4) >> 1;
+ mhp->attr.perms |= (acc & 0x8) >> 3;
+ mhp->attr.va_fbo = region->virt_base;
+ mhp->attr.page_size = shift - 12;
+ mhp->attr.len = (u32) region->length;
+ mhp->attr.pbl_size = i;
+ err = iwch_register_mem(rhp, php, mhp, shift, pages);
+ kfree(pages);
+ if (err)
+ goto err;
+
+ if (udata && t3b_device(rhp)) {
+ uresp.pbl_addr = (mhp->attr.pbl_addr -
+ rhp->rdev.rnic_info.pbl_base) >> 3;
+ PDBG("%s user resp pbl_addr 0x%x\n", __FUNCTION__,
+ uresp.pbl_addr);
+
+ if (ib_copy_to_udata(udata, &uresp, sizeof (uresp))) {
+ iwch_dereg_mr(&mhp->ibmr);
+ err = -EFAULT;
+ goto err;
+ }
+ }
+
+ return &mhp->ibmr;
+
+err:
+ kfree(mhp);
+ return ERR_PTR(err);
+}
+
+static struct ib_mr *iwch_get_dma_mr(struct ib_pd *pd, int acc)
+{
+ struct ib_phys_buf bl;
+ u64 kva;
+ struct ib_mr *ibmr;
+
+ PDBG("%s ib_pd %p\n", __FUNCTION__, pd);
+
+ /*
+ * T3 only supports 32 bits of size.
+ */
+ bl.size = 0xffffffff;
+ bl.addr = 0;
+ kva = 0;
+ ibmr = iwch_register_phys_mem(pd, &bl, 1, acc, &kva);
+ return ibmr;
+}
+
+static struct ib_mw *iwch_alloc_mw(struct ib_pd *pd)
+{
+ struct iwch_dev *rhp;
+ struct iwch_pd *php;
+ struct iwch_mw *mhp;
+ u32 mmid;
+ u32 stag = 0;
+ int ret;
+
+ php = to_iwch_pd(pd);
+ rhp = php->rhp;
+ mhp = kzalloc(sizeof(*mhp), GFP_KERNEL);
+ if (!mhp)
+ return ERR_PTR(-ENOMEM);
+ ret = cxio_allocate_window(&rhp->rdev, &stag, php->pdid);
+ if (ret) {
+ kfree(mhp);
+ return ERR_PTR(ret);
+ }
+ mhp->rhp = rhp;
+ mhp->attr.pdid = php->pdid;
+ mhp->attr.type = TPT_MW;
+ mhp->attr.stag = stag;
+ mmid = (stag) >> 8;
+ insert_handle(rhp, &rhp->mmidr, mhp, mmid);
+ PDBG("%s mmid 0x%x mhp %p stag 0x%x\n", __FUNCTION__, mmid, mhp, stag);
+ return &(mhp->ibmw);
+}
+
+static int iwch_dealloc_mw(struct ib_mw *mw)
+{
+ struct iwch_dev *rhp;
+ struct iwch_mw *mhp;
+ u32 mmid;
+
+ mhp = to_iwch_mw(mw);
+ rhp = mhp->rhp;
+ mmid = (mw->rkey) >> 8;
+ cxio_deallocate_window(&rhp->rdev, mhp->attr.stag);
+ remove_handle(rhp, &rhp->mmidr, mmid);
+ kfree(mhp);
+ PDBG("%s ib_mw %p mmid 0x%x ptr %p\n", __FUNCTION__, mw, mmid, mhp);
+ return 0;
+}
+
+static int iwch_destroy_qp(struct ib_qp *ib_qp)
+{
+ struct iwch_dev *rhp;
+ struct iwch_qp *qhp;
+ struct iwch_qp_attributes attrs;
+ struct iwch_ucontext *ucontext;
+
+ qhp = to_iwch_qp(ib_qp);
+ rhp = qhp->rhp;
+
+ if (qhp->attr.state == IWCH_QP_STATE_RTS) {
+ attrs.next_state = IWCH_QP_STATE_ERROR;
+ iwch_modify_qp(rhp, qhp, IWCH_QP_ATTR_NEXT_STATE, &attrs, 0);
+ }
+ wait_event(qhp->wait, !qhp->ep);
+
+ remove_handle(rhp, &rhp->qpidr, qhp->wq.qpid);
+
+ atomic_dec(&qhp->refcnt);
+ wait_event(qhp->wait, !atomic_read(&qhp->refcnt));
+
+ ucontext = ib_qp->uobject ? to_iwch_ucontext(ib_qp->uobject->context)
+ : NULL;
+ cxio_destroy_qp(&rhp->rdev, &qhp->wq,
+ ucontext ? &ucontext->uctx : &rhp->rdev.uctx);
+
+ PDBG("%s ib_qp %p qpid 0x%0x qhp %p\n", __FUNCTION__,
+ ib_qp, qhp->wq.qpid, qhp);
+ kfree(qhp);
+ return 0;
+}
+
+static struct ib_qp *iwch_create_qp(struct ib_pd *pd,
+ struct ib_qp_init_attr *attrs,
+ struct ib_udata *udata)
+{
+ struct iwch_dev *rhp;
+ struct iwch_qp *qhp;
+ struct iwch_pd *php;
+ struct iwch_cq *schp;
+ struct iwch_cq *rchp;
+ struct iwch_create_qp_resp uresp;
+ int wqsize, sqsize, rqsize;
+ struct iwch_ucontext *ucontext;
+
+ PDBG("%s ib_pd %p\n", __FUNCTION__, pd);
+ if (attrs->qp_type != IB_QPT_RC)
+ return ERR_PTR(-EINVAL);
+ php = to_iwch_pd(pd);
+ rhp = php->rhp;
+ schp = get_chp(rhp, ((struct iwch_cq *) attrs->send_cq)->cq.cqid);
+ rchp = get_chp(rhp, ((struct iwch_cq *) attrs->recv_cq)->cq.cqid);
+ if (!schp || !rchp)
+ return ERR_PTR(-EINVAL);
+
+ /* The RQT size must be # of entries + 1 rounded up to a power of two */
+ rqsize = roundup_pow_of_two(attrs->cap.max_recv_wr);
+ if (rqsize == attrs->cap.max_recv_wr)
+ rqsize = roundup_pow_of_two(attrs->cap.max_recv_wr+1);
+
+ /* T3 doesn't support RQT depth < 16 */
+ if (rqsize < 16)
+ rqsize = 16;
+
+ if (rqsize > T3_MAX_RQ_SIZE)
+ return ERR_PTR(-EINVAL);
+
+ /*
+ * NOTE: The SQ and total WQ sizes don't need to be
+ * a power of two. However, all the code assumes
+ * they are. EG: Q_FREECNT() and friends.
+ */
+ sqsize = roundup_pow_of_two(attrs->cap.max_send_wr);
+ wqsize = roundup_pow_of_two(rqsize + sqsize);
+ PDBG("%s wqsize %d sqsize %d rqsize %d\n", __FUNCTION__,
+ wqsize, sqsize, rqsize);
+ qhp = kzalloc(sizeof(*qhp), GFP_KERNEL);
+ if (!qhp)
+ return ERR_PTR(-ENOMEM);
+ qhp->wq.size_log2 = ilog2(wqsize);
+ qhp->wq.rq_size_log2 = ilog2(rqsize);
+ qhp->wq.sq_size_log2 = ilog2(sqsize);
+ ucontext = pd->uobject ? to_iwch_ucontext(pd->uobject->context) : NULL;
+ if (cxio_create_qp(&rhp->rdev, !udata, &qhp->wq,
+ ucontext ? &ucontext->uctx : &rhp->rdev.uctx)) {
+ kfree(qhp);
+ return ERR_PTR(-ENOMEM);
+ }
+ attrs->cap.max_recv_wr = rqsize - 1;
+ attrs->cap.max_send_wr = sqsize;
+ qhp->rhp = rhp;
+ qhp->attr.pd = php->pdid;
+ qhp->attr.scq = ((struct iwch_cq *) attrs->send_cq)->cq.cqid;
+ qhp->attr.rcq = ((struct iwch_cq *) attrs->recv_cq)->cq.cqid;
+ qhp->attr.sq_num_entries = attrs->cap.max_send_wr;
+ qhp->attr.rq_num_entries = attrs->cap.max_recv_wr;
+ qhp->attr.sq_max_sges = attrs->cap.max_send_sge;
+ qhp->attr.sq_max_sges_rdma_write = attrs->cap.max_send_sge;
+ qhp->attr.rq_max_sges = attrs->cap.max_recv_sge;
+ qhp->attr.state = IWCH_QP_STATE_IDLE;
+ qhp->attr.next_state = IWCH_QP_STATE_IDLE;
+
+ /*
+ * XXX - These don't get passed in from the openib user
+ * at create time. The CM sets them via a QP modify.
+ * Need to fix... I think the CM should
+ */
+ qhp->attr.enable_rdma_read = 1;
+ qhp->attr.enable_rdma_write = 1;
+ qhp->attr.enable_bind = 1;
+ qhp->attr.max_ord = 1;
+ qhp->attr.max_ird = 1;
+
+ spin_lock_init(&qhp->lock);
+ init_waitqueue_head(&qhp->wait);
+ atomic_set(&qhp->refcnt, 1);
+ insert_handle(rhp, &rhp->qpidr, qhp, qhp->wq.qpid);
+
+ if (udata) {
+
+ struct iwch_mm_entry *mm1, *mm2;
+
+ mm1 = kmalloc(sizeof *mm1, GFP_KERNEL);
+ if (!mm1) {
+ iwch_destroy_qp(&qhp->ibqp);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ mm2 = kmalloc(sizeof *mm2, GFP_KERNEL);
+ if (!mm2) {
+ kfree(mm1);
+ iwch_destroy_qp(&qhp->ibqp);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ uresp.qpid = qhp->wq.qpid;
+ uresp.size_log2 = qhp->wq.size_log2;
+ uresp.sq_size_log2 = qhp->wq.sq_size_log2;
+ uresp.rq_size_log2 = qhp->wq.rq_size_log2;
+ spin_lock(&ucontext->mmap_lock);
+ uresp.key = ucontext->key;
+ ucontext->key += PAGE_SIZE;
+ uresp.db_key = ucontext->key;
+ ucontext->key += PAGE_SIZE;
+ spin_unlock(&ucontext->mmap_lock);
+ if (ib_copy_to_udata(udata, &uresp, sizeof (uresp))) {
+ kfree(mm1);
+ kfree(mm2);
+ iwch_destroy_qp(&qhp->ibqp);
+ return ERR_PTR(-EFAULT);
+ }
+ mm1->key = uresp.key;
+ mm1->addr = virt_to_phys(qhp->wq.queue);
+ mm1->len = PAGE_ALIGN(wqsize * sizeof (union t3_wr));
+ insert_mmap(ucontext, mm1);
+ mm2->key = uresp.db_key;
+ mm2->addr = qhp->wq.udb & PAGE_MASK;
+ mm2->len = PAGE_SIZE;
+ insert_mmap(ucontext, mm2);
+ }
+ qhp->ibqp.qp_num = qhp->wq.qpid;
+ init_timer(&(qhp->timer));
+ PDBG("%s sq_num_entries %d, rq_num_entries %d "
+ "qpid 0x%0x qhp %p dma_addr 0x%llx size %d\n",
+ __FUNCTION__, qhp->attr.sq_num_entries, qhp->attr.rq_num_entries,
+ qhp->wq.qpid, qhp, (unsigned long long) qhp->wq.dma_addr,
+ 1 << qhp->wq.size_log2);
+ return &qhp->ibqp;
+}
+
+static int iwch_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
+ int attr_mask, struct ib_udata *udata)
+{
+ struct iwch_dev *rhp;
+ struct iwch_qp *qhp;
+ enum iwch_qp_attr_mask mask = 0;
+ struct iwch_qp_attributes attrs;
+
+ PDBG("%s ib_qp %p\n", __FUNCTION__, ibqp);
+
+ /* iwarp does not support the RTR state */
+ if ((attr_mask & IB_QP_STATE) && (attr->qp_state == IB_QPS_RTR))
+ attr_mask &= ~IB_QP_STATE;
+
+ /* Make sure we still have something left to do */
+ if (!attr_mask)
+ return 0;
+
+ memset(&attrs, 0, sizeof attrs);
+ qhp = to_iwch_qp(ibqp);
+ rhp = qhp->rhp;
+
+ attrs.next_state = iwch_convert_state(attr->qp_state);
+ attrs.enable_rdma_read = (attr->qp_access_flags &
+ IB_ACCESS_REMOTE_READ) ? 1 : 0;
+ attrs.enable_rdma_write = (attr->qp_access_flags &
+ IB_ACCESS_REMOTE_WRITE) ? 1 : 0;
+ attrs.enable_bind = (attr->qp_access_flags & IB_ACCESS_MW_BIND) ? 1 : 0;
+
+
+ mask |= (attr_mask & IB_QP_STATE) ? IWCH_QP_ATTR_NEXT_STATE : 0;
+ mask |= (attr_mask & IB_QP_ACCESS_FLAGS) ?
+ (IWCH_QP_ATTR_ENABLE_RDMA_READ |
+ IWCH_QP_ATTR_ENABLE_RDMA_WRITE |
+ IWCH_QP_ATTR_ENABLE_RDMA_BIND) : 0;
+
+ return iwch_modify_qp(rhp, qhp, mask, &attrs, 0);
+}
+
+void iwch_qp_add_ref(struct ib_qp *qp)
+{
+ PDBG("%s ib_qp %p\n", __FUNCTION__, qp);
+ atomic_inc(&(to_iwch_qp(qp)->refcnt));
+}
+
+void iwch_qp_rem_ref(struct ib_qp *qp)
+{
+ PDBG("%s ib_qp %p\n", __FUNCTION__, qp);
+ if (atomic_dec_and_test(&(to_iwch_qp(qp)->refcnt)))
+ wake_up(&(to_iwch_qp(qp)->wait));
+}
+
+struct ib_qp *iwch_get_qp(struct ib_device *dev, int qpn)
+{
+ PDBG("%s ib_dev %p qpn 0x%x\n", __FUNCTION__, dev, qpn);
+ return (struct ib_qp *)get_qhp(to_iwch_dev(dev), qpn);
+}
+
+
+static int iwch_query_pkey(struct ib_device *ibdev,
+ u8 port, u16 index, u16 * pkey)
+{
+ PDBG("%s ibdev %p\n", __FUNCTION__, ibdev);
+ *pkey = 0;
+ return 0;
+}
+
+static int iwch_query_gid(struct ib_device *ibdev, u8 port,
+ int index, union ib_gid *gid)
+{
+ struct iwch_dev *dev;
+
+ PDBG("%s ibdev %p, port %d, index %d, gid %p\n",
+ __FUNCTION__, ibdev, port, index, gid);
+ dev = to_iwch_dev(ibdev);
+ BUG_ON(port == 0 || port > 2);
+ memset(&(gid->raw[0]), 0, sizeof(gid->raw));
+ memcpy(&(gid->raw[0]), dev->rdev.port_info.lldevs[port-1]->dev_addr, 6);
+ return 0;
+}
+
+static int iwch_query_device(struct ib_device *ibdev,
+ struct ib_device_attr *props)
+{
+
+ struct iwch_dev *dev;
+ PDBG("%s ibdev %p\n", __FUNCTION__, ibdev);
+
+ dev = to_iwch_dev(ibdev);
+ memset(props, 0, sizeof *props);
+ memcpy(&props->sys_image_guid, dev->rdev.t3cdev_p->lldev->dev_addr, 6);
+ props->device_cap_flags = dev->device_cap_flags;
+ props->vendor_id = (u32)dev->rdev.rnic_info.pdev->vendor;
+ props->vendor_part_id = (u32)dev->rdev.rnic_info.pdev->device;
+ props->max_mr_size = ~0ull;
+ props->max_qp = dev->attr.max_qps;
+ props->max_qp_wr = dev->attr.max_wrs;
+ props->max_sge = dev->attr.max_sge_per_wr;
+ props->max_sge_rd = 1;
+ props->max_qp_rd_atom = dev->attr.max_rdma_reads_per_qp;
+ props->max_cq = dev->attr.max_cqs;
+ props->max_cqe = dev->attr.max_cqes_per_cq;
+ props->max_mr = dev->attr.max_mem_regs;
+ props->max_pd = dev->attr.max_pds;
+ props->local_ca_ack_delay = 0;
+
+ return 0;
+}
+
+static int iwch_query_port(struct ib_device *ibdev,
+ u8 port, struct ib_port_attr *props)
+{
+ PDBG("%s ibdev %p\n", __FUNCTION__, ibdev);
+ props->max_mtu = IB_MTU_4096;
+ props->lid = 0;
+ props->lmc = 0;
+ props->sm_lid = 0;
+ props->sm_sl = 0;
+ props->state = IB_PORT_ACTIVE;
+ props->phys_state = 0;
+ props->port_cap_flags =
+ IB_PORT_CM_SUP |
+ IB_PORT_SNMP_TUNNEL_SUP |
+ IB_PORT_REINIT_SUP |
+ IB_PORT_DEVICE_MGMT_SUP |
+ IB_PORT_VENDOR_CLASS_SUP | IB_PORT_BOOT_MGMT_SUP;
+ props->gid_tbl_len = 1;
+ props->pkey_tbl_len = 1;
+ props->qkey_viol_cntr = 0;
+ props->active_width = 2;
+ props->active_speed = 2;
+ props->max_msg_sz = -1;
+
+ return 0;
+}
+
+static ssize_t show_rev(struct class_device *cdev, char *buf)
+{
+ struct iwch_dev *dev = container_of(cdev, struct iwch_dev,
+ ibdev.class_dev);
+ PDBG("%s class dev 0x%p\n", __FUNCTION__, cdev);
+ return sprintf(buf, "%d\n", dev->rdev.t3cdev_p->type);
+}
+
+static ssize_t show_fw_ver(struct class_device *cdev, char *buf)
+{
+ struct iwch_dev *dev = container_of(cdev, struct iwch_dev,
+ ibdev.class_dev);
+ struct ethtool_drvinfo info;
+ struct net_device *lldev = dev->rdev.t3cdev_p->lldev;
+
+ PDBG("%s class dev 0x%p\n", __FUNCTION__, cdev);
+ lldev->ethtool_ops->get_drvinfo(lldev, &info);
+ return sprintf(buf, "%s\n", info.fw_version);
+}
+
+static ssize_t show_hca(struct class_device *cdev, char *buf)
+{
+ struct iwch_dev *dev = container_of(cdev, struct iwch_dev,
+ ibdev.class_dev);
+ struct ethtool_drvinfo info;
+ struct net_device *lldev = dev->rdev.t3cdev_p->lldev;
+
+ PDBG("%s class dev 0x%p\n", __FUNCTION__, cdev);
+ lldev->ethtool_ops->get_drvinfo(lldev, &info);
+ return sprintf(buf, "%s\n", info.driver);
+}
+
+static ssize_t show_board(struct class_device *cdev, char *buf)
+{
+ struct iwch_dev *dev = container_of(cdev, struct iwch_dev,
+ ibdev.class_dev);
+ PDBG("%s class dev 0x%p\n", __FUNCTION__, dev);
+ return sprintf(buf, "%x.%x\n", dev->rdev.rnic_info.pdev->vendor,
+ dev->rdev.rnic_info.pdev->device);
+}
+
+static CLASS_DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL);
+static CLASS_DEVICE_ATTR(fw_ver, S_IRUGO, show_fw_ver, NULL);
+static CLASS_DEVICE_ATTR(hca_type, S_IRUGO, show_hca, NULL);
+static CLASS_DEVICE_ATTR(board_id, S_IRUGO, show_board, NULL);
+
+static struct class_device_attribute *iwch_class_attributes[] = {
+ &class_device_attr_hw_rev,
+ &class_device_attr_fw_ver,
+ &class_device_attr_hca_type,
+ &class_device_attr_board_id
+};
+
+int iwch_register_device(struct iwch_dev *dev)
+{
+ int ret;
+ int i;
+
+ PDBG("%s iwch_dev %p\n", __FUNCTION__, dev);
+ strlcpy(dev->ibdev.name, "cxgb3_%d", IB_DEVICE_NAME_MAX);
+ memset(&dev->ibdev.node_guid, 0, sizeof(dev->ibdev.node_guid));
+ memcpy(&dev->ibdev.node_guid, dev->rdev.t3cdev_p->lldev->dev_addr, 6);
+ dev->ibdev.owner = THIS_MODULE;
+ dev->device_cap_flags =
+ (IB_DEVICE_ZERO_STAG |
+ IB_DEVICE_SEND_W_INV | IB_DEVICE_MEM_WINDOW);
+
+ dev->ibdev.uverbs_cmd_mask =
+ (1ull << IB_USER_VERBS_CMD_GET_CONTEXT) |
+ (1ull << IB_USER_VERBS_CMD_QUERY_DEVICE) |
+ (1ull << IB_USER_VERBS_CMD_QUERY_PORT) |
+ (1ull << IB_USER_VERBS_CMD_ALLOC_PD) |
+ (1ull << IB_USER_VERBS_CMD_DEALLOC_PD) |
+ (1ull << IB_USER_VERBS_CMD_REG_MR) |
+ (1ull << IB_USER_VERBS_CMD_DEREG_MR) |
+ (1ull << IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL) |
+ (1ull << IB_USER_VERBS_CMD_CREATE_CQ) |
+ (1ull << IB_USER_VERBS_CMD_DESTROY_CQ) |
+ (1ull << IB_USER_VERBS_CMD_REQ_NOTIFY_CQ) |
+ (1ull << IB_USER_VERBS_CMD_CREATE_QP) |
+ (1ull << IB_USER_VERBS_CMD_MODIFY_QP) |
+ (1ull << IB_USER_VERBS_CMD_POLL_CQ) |
+ (1ull << IB_USER_VERBS_CMD_DESTROY_QP) |
+ (1ull << IB_USER_VERBS_CMD_POST_SEND) |
+ (1ull << IB_USER_VERBS_CMD_POST_RECV);
+ dev->ibdev.node_type = RDMA_NODE_RNIC;
+ memcpy(dev->ibdev.node_desc, IWCH_NODE_DESC, sizeof(IWCH_NODE_DESC));
+ dev->ibdev.phys_port_cnt = dev->rdev.port_info.nports;
+ dev->ibdev.dma_device = &(dev->rdev.rnic_info.pdev->dev);
+ dev->ibdev.class_dev.dev = &(dev->rdev.rnic_info.pdev->dev);
+ dev->ibdev.query_device = iwch_query_device;
+ dev->ibdev.query_port = iwch_query_port;
+ dev->ibdev.modify_port = iwch_modify_port;
+ dev->ibdev.query_pkey = iwch_query_pkey;
+ dev->ibdev.query_gid = iwch_query_gid;
+ dev->ibdev.alloc_ucontext = iwch_alloc_ucontext;
+ dev->ibdev.dealloc_ucontext = iwch_dealloc_ucontext;
+ dev->ibdev.mmap = iwch_mmap;
+ dev->ibdev.alloc_pd = iwch_allocate_pd;
+ dev->ibdev.dealloc_pd = iwch_deallocate_pd;
+ dev->ibdev.create_ah = iwch_ah_create;
+ dev->ibdev.destroy_ah = iwch_ah_destroy;
+ dev->ibdev.create_qp = iwch_create_qp;
+ dev->ibdev.modify_qp = iwch_ib_modify_qp;
+ dev->ibdev.destroy_qp = iwch_destroy_qp;
+ dev->ibdev.create_cq = iwch_create_cq;
+ dev->ibdev.destroy_cq = iwch_destroy_cq;
+ dev->ibdev.resize_cq = iwch_resize_cq;
+ dev->ibdev.poll_cq = iwch_poll_cq;
+ dev->ibdev.get_dma_mr = iwch_get_dma_mr;
+ dev->ibdev.reg_phys_mr = iwch_register_phys_mem;
+ dev->ibdev.rereg_phys_mr = iwch_reregister_phys_mem;
+ dev->ibdev.reg_user_mr = iwch_reg_user_mr;
+ dev->ibdev.dereg_mr = iwch_dereg_mr;
+ dev->ibdev.alloc_mw = iwch_alloc_mw;
+ dev->ibdev.bind_mw = iwch_bind_mw;
+ dev->ibdev.dealloc_mw = iwch_dealloc_mw;
+
+ dev->ibdev.attach_mcast = iwch_multicast_attach;
+ dev->ibdev.detach_mcast = iwch_multicast_detach;
+ dev->ibdev.process_mad = iwch_process_mad;
+
+ dev->ibdev.req_notify_cq = iwch_arm_cq;
+ dev->ibdev.post_send = iwch_post_send;
+ dev->ibdev.post_recv = iwch_post_receive;
+
+
+ dev->ibdev.iwcm =
+ (struct iw_cm_verbs *) kmalloc(sizeof(struct iw_cm_verbs),
+ GFP_KERNEL);
+ dev->ibdev.iwcm->connect = iwch_connect;
+ dev->ibdev.iwcm->accept = iwch_accept_cr;
+ dev->ibdev.iwcm->reject = iwch_reject_cr;
+ dev->ibdev.iwcm->create_listen = iwch_create_listen;
+ dev->ibdev.iwcm->destroy_listen = iwch_destroy_listen;
+ dev->ibdev.iwcm->add_ref = iwch_qp_add_ref;
+ dev->ibdev.iwcm->rem_ref = iwch_qp_rem_ref;
+ dev->ibdev.iwcm->get_qp = iwch_get_qp;
+
+ ret = ib_register_device(&dev->ibdev);
+ if (ret)
+ goto bail1;
+
+ for (i = 0; i < ARRAY_SIZE(iwch_class_attributes); ++i) {
+ ret = class_device_create_file(&dev->ibdev.class_dev,
+ iwch_class_attributes[i]);
+ if (ret) {
+ goto bail2;
+ }
+ }
+ return 0;
+bail2:
+ ib_unregister_device(&dev->ibdev);
+bail1:
+ return ret;
+}
+
+void iwch_unregister_device(struct iwch_dev *dev)
+{
+ int i;
+
+ PDBG("%s iwch_dev %p\n", __FUNCTION__, dev);
+ for (i = 0; i < ARRAY_SIZE(iwch_class_attributes); ++i)
+ class_device_remove_file(&dev->ibdev.class_dev,
+ iwch_class_attributes[i]);
+ ib_unregister_device(&dev->ibdev);
+ return;
+}
diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.h b/drivers/infiniband/hw/cxgb3/iwch_provider.h
new file mode 100644
index 00000000000..2af3e93b607
--- /dev/null
+++ b/drivers/infiniband/hw/cxgb3/iwch_provider.h
@@ -0,0 +1,366 @@
+/*
+ * Copyright (c) 2006 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef __IWCH_PROVIDER_H__
+#define __IWCH_PROVIDER_H__
+
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <rdma/ib_verbs.h>
+#include <asm/types.h>
+#include "t3cdev.h"
+#include "iwch.h"
+#include "cxio_wr.h"
+#include "cxio_hal.h"
+
+struct iwch_pd {
+ struct ib_pd ibpd;
+ u32 pdid;
+ struct iwch_dev *rhp;
+};
+
+static inline struct iwch_pd *to_iwch_pd(struct ib_pd *ibpd)
+{
+ return container_of(ibpd, struct iwch_pd, ibpd);
+}
+
+struct tpt_attributes {
+ u32 stag;
+ u32 state:1;
+ u32 type:2;
+ u32 rsvd:1;
+ enum tpt_mem_perm perms;
+ u32 remote_invaliate_disable:1;
+ u32 zbva:1;
+ u32 mw_bind_enable:1;
+ u32 page_size:5;
+
+ u32 pdid;
+ u32 qpid;
+ u32 pbl_addr;
+ u32 len;
+ u64 va_fbo;
+ u32 pbl_size;
+};
+
+struct iwch_mr {
+ struct ib_mr ibmr;
+ struct iwch_dev *rhp;
+ u64 kva;
+ struct tpt_attributes attr;
+};
+
+typedef struct iwch_mw iwch_mw_handle;
+
+static inline struct iwch_mr *to_iwch_mr(struct ib_mr *ibmr)
+{
+ return container_of(ibmr, struct iwch_mr, ibmr);
+}
+
+struct iwch_mw {
+ struct ib_mw ibmw;
+ struct iwch_dev *rhp;
+ u64 kva;
+ struct tpt_attributes attr;
+};
+
+static inline struct iwch_mw *to_iwch_mw(struct ib_mw *ibmw)
+{
+ return container_of(ibmw, struct iwch_mw, ibmw);
+}
+
+struct iwch_cq {
+ struct ib_cq ibcq;
+ struct iwch_dev *rhp;
+ struct t3_cq cq;
+ spinlock_t lock;
+ atomic_t refcnt;
+ wait_queue_head_t wait;
+ u32 __user *user_rptr_addr;
+};
+
+static inline struct iwch_cq *to_iwch_cq(struct ib_cq *ibcq)
+{
+ return container_of(ibcq, struct iwch_cq, ibcq);
+}
+
+enum IWCH_QP_FLAGS {
+ QP_QUIESCED = 0x01
+};
+
+struct iwch_mpa_attributes {
+ u8 recv_marker_enabled;
+ u8 xmit_marker_enabled; /* iWARP: enable inbound Read Resp. */
+ u8 crc_enabled;
+ u8 version; /* 0 or 1 */
+};
+
+struct iwch_qp_attributes {
+ u32 scq;
+ u32 rcq;
+ u32 sq_num_entries;
+ u32 rq_num_entries;
+ u32 sq_max_sges;
+ u32 sq_max_sges_rdma_write;
+ u32 rq_max_sges;
+ u32 state;
+ u8 enable_rdma_read;
+ u8 enable_rdma_write; /* enable inbound Read Resp. */
+ u8 enable_bind;
+ u8 enable_mmid0_fastreg; /* Enable STAG0 + Fast-register */
+ /*
+ * Next QP state. If specify the current state, only the
+ * QP attributes will be modified.
+ */
+ u32 max_ord;
+ u32 max_ird;
+ u32 pd; /* IN */
+ u32 next_state;
+ char terminate_buffer[52];
+ u32 terminate_msg_len;
+ u8 is_terminate_local;
+ struct iwch_mpa_attributes mpa_attr; /* IN-OUT */
+ struct iwch_ep *llp_stream_handle;
+ char *stream_msg_buf; /* Last stream msg. before Idle -> RTS */
+ u32 stream_msg_buf_len; /* Only on Idle -> RTS */
+};
+
+struct iwch_qp {
+ struct ib_qp ibqp;
+ struct iwch_dev *rhp;
+ struct iwch_ep *ep;
+ struct iwch_qp_attributes attr;
+ struct t3_wq wq;
+ spinlock_t lock;
+ atomic_t refcnt;
+ wait_queue_head_t wait;
+ enum IWCH_QP_FLAGS flags;
+ struct timer_list timer;
+};
+
+static inline int qp_quiesced(struct iwch_qp *qhp)
+{
+ return qhp->flags & QP_QUIESCED;
+}
+
+static inline struct iwch_qp *to_iwch_qp(struct ib_qp *ibqp)
+{
+ return container_of(ibqp, struct iwch_qp, ibqp);
+}
+
+void iwch_qp_add_ref(struct ib_qp *qp);
+void iwch_qp_rem_ref(struct ib_qp *qp);
+struct ib_qp *iwch_get_qp(struct ib_device *dev, int qpn);
+
+struct iwch_ucontext {
+ struct ib_ucontext ibucontext;
+ struct cxio_ucontext uctx;
+ u32 key;
+ spinlock_t mmap_lock;
+ struct list_head mmaps;
+};
+
+static inline struct iwch_ucontext *to_iwch_ucontext(struct ib_ucontext *c)
+{
+ return container_of(c, struct iwch_ucontext, ibucontext);
+}
+
+struct iwch_mm_entry {
+ struct list_head entry;
+ u64 addr;
+ u32 key;
+ unsigned len;
+};
+
+static inline struct iwch_mm_entry *remove_mmap(struct iwch_ucontext *ucontext,
+ u32 key, unsigned len)
+{
+ struct list_head *pos, *nxt;
+ struct iwch_mm_entry *mm;
+
+ spin_lock(&ucontext->mmap_lock);
+ list_for_each_safe(pos, nxt, &ucontext->mmaps) {
+
+ mm = list_entry(pos, struct iwch_mm_entry, entry);
+ if (mm->key == key && mm->len == len) {
+ list_del_init(&mm->entry);
+ spin_unlock(&ucontext->mmap_lock);
+ PDBG("%s key 0x%x addr 0x%llx len %d\n", __FUNCTION__,
+ key, (unsigned long long) mm->addr, mm->len);
+ return mm;
+ }
+ }
+ spin_unlock(&ucontext->mmap_lock);
+ return NULL;
+}
+
+static inline void insert_mmap(struct iwch_ucontext *ucontext,
+ struct iwch_mm_entry *mm)
+{
+ spin_lock(&ucontext->mmap_lock);
+ PDBG("%s key 0x%x addr 0x%llx len %d\n", __FUNCTION__,
+ mm->key, (unsigned long long) mm->addr, mm->len);
+ list_add_tail(&mm->entry, &ucontext->mmaps);
+ spin_unlock(&ucontext->mmap_lock);
+}
+
+enum iwch_qp_attr_mask {
+ IWCH_QP_ATTR_NEXT_STATE = 1 << 0,
+ IWCH_QP_ATTR_ENABLE_RDMA_READ = 1 << 7,
+ IWCH_QP_ATTR_ENABLE_RDMA_WRITE = 1 << 8,
+ IWCH_QP_ATTR_ENABLE_RDMA_BIND = 1 << 9,
+ IWCH_QP_ATTR_MAX_ORD = 1 << 11,
+ IWCH_QP_ATTR_MAX_IRD = 1 << 12,
+ IWCH_QP_ATTR_LLP_STREAM_HANDLE = 1 << 22,
+ IWCH_QP_ATTR_STREAM_MSG_BUFFER = 1 << 23,
+ IWCH_QP_ATTR_MPA_ATTR = 1 << 24,
+ IWCH_QP_ATTR_QP_CONTEXT_ACTIVATE = 1 << 25,
+ IWCH_QP_ATTR_VALID_MODIFY = (IWCH_QP_ATTR_ENABLE_RDMA_READ |
+ IWCH_QP_ATTR_ENABLE_RDMA_WRITE |
+ IWCH_QP_ATTR_MAX_ORD |
+ IWCH_QP_ATTR_MAX_IRD |
+ IWCH_QP_ATTR_LLP_STREAM_HANDLE |
+ IWCH_QP_ATTR_STREAM_MSG_BUFFER |
+ IWCH_QP_ATTR_MPA_ATTR |
+ IWCH_QP_ATTR_QP_CONTEXT_ACTIVATE)
+};
+
+int iwch_modify_qp(struct iwch_dev *rhp,
+ struct iwch_qp *qhp,
+ enum iwch_qp_attr_mask mask,
+ struct iwch_qp_attributes *attrs,
+ int internal);
+
+enum iwch_qp_state {
+ IWCH_QP_STATE_IDLE,
+ IWCH_QP_STATE_RTS,
+ IWCH_QP_STATE_ERROR,
+ IWCH_QP_STATE_TERMINATE,
+ IWCH_QP_STATE_CLOSING,
+ IWCH_QP_STATE_TOT
+};
+
+static inline int iwch_convert_state(enum ib_qp_state ib_state)
+{
+ switch (ib_state) {
+ case IB_QPS_RESET:
+ case IB_QPS_INIT:
+ return IWCH_QP_STATE_IDLE;
+ case IB_QPS_RTS:
+ return IWCH_QP_STATE_RTS;
+ case IB_QPS_SQD:
+ return IWCH_QP_STATE_CLOSING;
+ case IB_QPS_SQE:
+ return IWCH_QP_STATE_TERMINATE;
+ case IB_QPS_ERR:
+ return IWCH_QP_STATE_ERROR;
+ default:
+ return -1;
+ }
+}
+
+enum iwch_mem_perms {
+ IWCH_MEM_ACCESS_LOCAL_READ = 1 << 0,
+ IWCH_MEM_ACCESS_LOCAL_WRITE = 1 << 1,
+ IWCH_MEM_ACCESS_REMOTE_READ = 1 << 2,
+ IWCH_MEM_ACCESS_REMOTE_WRITE = 1 << 3,
+ IWCH_MEM_ACCESS_ATOMICS = 1 << 4,
+ IWCH_MEM_ACCESS_BINDING = 1 << 5,
+ IWCH_MEM_ACCESS_LOCAL =
+ (IWCH_MEM_ACCESS_LOCAL_READ | IWCH_MEM_ACCESS_LOCAL_WRITE),
+ IWCH_MEM_ACCESS_REMOTE =
+ (IWCH_MEM_ACCESS_REMOTE_WRITE | IWCH_MEM_ACCESS_REMOTE_READ)
+ /* cannot go beyond 1 << 31 */
+} __attribute__ ((packed));
+
+static inline u32 iwch_convert_access(int acc)
+{
+ return (acc & IB_ACCESS_REMOTE_WRITE ? IWCH_MEM_ACCESS_REMOTE_WRITE : 0)
+ | (acc & IB_ACCESS_REMOTE_READ ? IWCH_MEM_ACCESS_REMOTE_READ : 0) |
+ (acc & IB_ACCESS_LOCAL_WRITE ? IWCH_MEM_ACCESS_LOCAL_WRITE : 0) |
+ (acc & IB_ACCESS_MW_BIND ? IWCH_MEM_ACCESS_BINDING : 0) |
+ IWCH_MEM_ACCESS_LOCAL_READ;
+}
+
+enum iwch_mmid_state {
+ IWCH_STAG_STATE_VALID,
+ IWCH_STAG_STATE_INVALID
+};
+
+enum iwch_qp_query_flags {
+ IWCH_QP_QUERY_CONTEXT_NONE = 0x0, /* No ctx; Only attrs */
+ IWCH_QP_QUERY_CONTEXT_GET = 0x1, /* Get ctx + attrs */
+ IWCH_QP_QUERY_CONTEXT_SUSPEND = 0x2, /* Not Supported */
+
+ /*
+ * Quiesce QP context; Consumer
+ * will NOT replay outstanding WR
+ */
+ IWCH_QP_QUERY_CONTEXT_QUIESCE = 0x4,
+ IWCH_QP_QUERY_CONTEXT_REMOVE = 0x8,
+ IWCH_QP_QUERY_TEST_USERWRITE = 0x32 /* Test special */
+};
+
+int iwch_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
+ struct ib_send_wr **bad_wr);
+int iwch_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
+ struct ib_recv_wr **bad_wr);
+int iwch_bind_mw(struct ib_qp *qp,
+ struct ib_mw *mw,
+ struct ib_mw_bind *mw_bind);
+int iwch_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc);
+int iwch_post_terminate(struct iwch_qp *qhp, struct respQ_msg_t *rsp_msg);
+int iwch_register_device(struct iwch_dev *dev);
+void iwch_unregister_device(struct iwch_dev *dev);
+int iwch_quiesce_qps(struct iwch_cq *chp);
+int iwch_resume_qps(struct iwch_cq *chp);
+void stop_read_rep_timer(struct iwch_qp *qhp);
+int iwch_register_mem(struct iwch_dev *rhp, struct iwch_pd *php,
+ struct iwch_mr *mhp,
+ int shift,
+ __be64 *page_list);
+int iwch_reregister_mem(struct iwch_dev *rhp, struct iwch_pd *php,
+ struct iwch_mr *mhp,
+ int shift,
+ __be64 *page_list,
+ int npages);
+int build_phys_page_list(struct ib_phys_buf *buffer_list,
+ int num_phys_buf,
+ u64 *iova_start,
+ u64 *total_size,
+ int *npages,
+ int *shift,
+ __be64 **page_list);
+
+
+#define IWCH_NODE_DESC "cxgb3 Chelsio Communications"
+
+#endif
diff --git a/drivers/infiniband/hw/cxgb3/iwch_qp.c b/drivers/infiniband/hw/cxgb3/iwch_qp.c
new file mode 100644
index 00000000000..4dda2f6da2d
--- /dev/null
+++ b/drivers/infiniband/hw/cxgb3/iwch_qp.c
@@ -0,0 +1,1008 @@
+/*
+ * Copyright (c) 2006 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include "iwch_provider.h"
+#include "iwch.h"
+#include "iwch_cm.h"
+#include "cxio_hal.h"
+
+#define NO_SUPPORT -1
+
+static inline int iwch_build_rdma_send(union t3_wr *wqe, struct ib_send_wr *wr,
+ u8 * flit_cnt)
+{
+ int i;
+ u32 plen;
+
+ switch (wr->opcode) {
+ case IB_WR_SEND:
+ case IB_WR_SEND_WITH_IMM:
+ if (wr->send_flags & IB_SEND_SOLICITED)
+ wqe->send.rdmaop = T3_SEND_WITH_SE;
+ else
+ wqe->send.rdmaop = T3_SEND;
+ wqe->send.rem_stag = 0;
+ break;
+#if 0 /* Not currently supported */
+ case TYPE_SEND_INVALIDATE:
+ case TYPE_SEND_INVALIDATE_IMMEDIATE:
+ wqe->send.rdmaop = T3_SEND_WITH_INV;
+ wqe->send.rem_stag = cpu_to_be32(wr->wr.rdma.rkey);
+ break;
+ case TYPE_SEND_SE_INVALIDATE:
+ wqe->send.rdmaop = T3_SEND_WITH_SE_INV;
+ wqe->send.rem_stag = cpu_to_be32(wr->wr.rdma.rkey);
+ break;
+#endif
+ default:
+ break;
+ }
+ if (wr->num_sge > T3_MAX_SGE)
+ return -EINVAL;
+ wqe->send.reserved[0] = 0;
+ wqe->send.reserved[1] = 0;
+ wqe->send.reserved[2] = 0;
+ if (wr->opcode == IB_WR_SEND_WITH_IMM) {
+ plen = 4;
+ wqe->send.sgl[0].stag = wr->imm_data;
+ wqe->send.sgl[0].len = __constant_cpu_to_be32(0);
+ wqe->send.num_sgle = __constant_cpu_to_be32(0);
+ *flit_cnt = 5;
+ } else {
+ plen = 0;
+ for (i = 0; i < wr->num_sge; i++) {
+ if ((plen + wr->sg_list[i].length) < plen) {
+ return -EMSGSIZE;
+ }
+ plen += wr->sg_list[i].length;
+ wqe->send.sgl[i].stag =
+ cpu_to_be32(wr->sg_list[i].lkey);
+ wqe->send.sgl[i].len =
+ cpu_to_be32(wr->sg_list[i].length);
+ wqe->send.sgl[i].to = cpu_to_be64(wr->sg_list[i].addr);
+ }
+ wqe->send.num_sgle = cpu_to_be32(wr->num_sge);
+ *flit_cnt = 4 + ((wr->num_sge) << 1);
+ }
+ wqe->send.plen = cpu_to_be32(plen);
+ return 0;
+}
+
+static inline int iwch_build_rdma_write(union t3_wr *wqe, struct ib_send_wr *wr,
+ u8 *flit_cnt)
+{
+ int i;
+ u32 plen;
+ if (wr->num_sge > T3_MAX_SGE)
+ return -EINVAL;
+ wqe->write.rdmaop = T3_RDMA_WRITE;
+ wqe->write.reserved[0] = 0;
+ wqe->write.reserved[1] = 0;
+ wqe->write.reserved[2] = 0;
+ wqe->write.stag_sink = cpu_to_be32(wr->wr.rdma.rkey);
+ wqe->write.to_sink = cpu_to_be64(wr->wr.rdma.remote_addr);
+
+ if (wr->opcode == IB_WR_RDMA_WRITE_WITH_IMM) {
+ plen = 4;
+ wqe->write.sgl[0].stag = wr->imm_data;
+ wqe->write.sgl[0].len = __constant_cpu_to_be32(0);
+ wqe->write.num_sgle = __constant_cpu_to_be32(0);
+ *flit_cnt = 6;
+ } else {
+ plen = 0;
+ for (i = 0; i < wr->num_sge; i++) {
+ if ((plen + wr->sg_list[i].length) < plen) {
+ return -EMSGSIZE;
+ }
+ plen += wr->sg_list[i].length;
+ wqe->write.sgl[i].stag =
+ cpu_to_be32(wr->sg_list[i].lkey);
+ wqe->write.sgl[i].len =
+ cpu_to_be32(wr->sg_list[i].length);
+ wqe->write.sgl[i].to =
+ cpu_to_be64(wr->sg_list[i].addr);
+ }
+ wqe->write.num_sgle = cpu_to_be32(wr->num_sge);
+ *flit_cnt = 5 + ((wr->num_sge) << 1);
+ }
+ wqe->write.plen = cpu_to_be32(plen);
+ return 0;
+}
+
+static inline int iwch_build_rdma_read(union t3_wr *wqe, struct ib_send_wr *wr,
+ u8 *flit_cnt)
+{
+ if (wr->num_sge > 1)
+ return -EINVAL;
+ wqe->read.rdmaop = T3_READ_REQ;
+ wqe->read.reserved[0] = 0;
+ wqe->read.reserved[1] = 0;
+ wqe->read.reserved[2] = 0;
+ wqe->read.rem_stag = cpu_to_be32(wr->wr.rdma.rkey);
+ wqe->read.rem_to = cpu_to_be64(wr->wr.rdma.remote_addr);
+ wqe->read.local_stag = cpu_to_be32(wr->sg_list[0].lkey);
+ wqe->read.local_len = cpu_to_be32(wr->sg_list[0].length);
+ wqe->read.local_to = cpu_to_be64(wr->sg_list[0].addr);
+ *flit_cnt = sizeof(struct t3_rdma_read_wr) >> 3;
+ return 0;
+}
+
+/*
+ * TBD: this is going to be moved to firmware. Missing pdid/qpid check for now.
+ */
+static inline int iwch_sgl2pbl_map(struct iwch_dev *rhp,
+ struct ib_sge *sg_list, u32 num_sgle,
+ u32 * pbl_addr, u8 * page_size)
+{
+ int i;
+ struct iwch_mr *mhp;
+ u32 offset;
+ for (i = 0; i < num_sgle; i++) {
+
+ mhp = get_mhp(rhp, (sg_list[i].lkey) >> 8);
+ if (!mhp) {
+ PDBG("%s %d\n", __FUNCTION__, __LINE__);
+ return -EIO;
+ }
+ if (!mhp->attr.state) {
+ PDBG("%s %d\n", __FUNCTION__, __LINE__);
+ return -EIO;
+ }
+ if (mhp->attr.zbva) {
+ PDBG("%s %d\n", __FUNCTION__, __LINE__);
+ return -EIO;
+ }
+
+ if (sg_list[i].addr < mhp->attr.va_fbo) {
+ PDBG("%s %d\n", __FUNCTION__, __LINE__);
+ return -EINVAL;
+ }
+ if (sg_list[i].addr + ((u64) sg_list[i].length) <
+ sg_list[i].addr) {
+ PDBG("%s %d\n", __FUNCTION__, __LINE__);
+ return -EINVAL;
+ }
+ if (sg_list[i].addr + ((u64) sg_list[i].length) >
+ mhp->attr.va_fbo + ((u64) mhp->attr.len)) {
+ PDBG("%s %d\n", __FUNCTION__, __LINE__);
+ return -EINVAL;
+ }
+ offset = sg_list[i].addr - mhp->attr.va_fbo;
+ offset += ((u32) mhp->attr.va_fbo) %
+ (1UL << (12 + mhp->attr.page_size));
+ pbl_addr[i] = ((mhp->attr.pbl_addr -
+ rhp->rdev.rnic_info.pbl_base) >> 3) +
+ (offset >> (12 + mhp->attr.page_size));
+ page_size[i] = mhp->attr.page_size;
+ }
+ return 0;
+}
+
+static inline int iwch_build_rdma_recv(struct iwch_dev *rhp,
+ union t3_wr *wqe,
+ struct ib_recv_wr *wr)
+{
+ int i, err = 0;
+ u32 pbl_addr[4];
+ u8 page_size[4];
+ if (wr->num_sge > T3_MAX_SGE)
+ return -EINVAL;
+ err = iwch_sgl2pbl_map(rhp, wr->sg_list, wr->num_sge, pbl_addr,
+ page_size);
+ if (err)
+ return err;
+ wqe->recv.pagesz[0] = page_size[0];
+ wqe->recv.pagesz[1] = page_size[1];
+ wqe->recv.pagesz[2] = page_size[2];
+ wqe->recv.pagesz[3] = page_size[3];
+ wqe->recv.num_sgle = cpu_to_be32(wr->num_sge);
+ for (i = 0; i < wr->num_sge; i++) {
+ wqe->recv.sgl[i].stag = cpu_to_be32(wr->sg_list[i].lkey);
+ wqe->recv.sgl[i].len = cpu_to_be32(wr->sg_list[i].length);
+
+ /* to in the WQE == the offset into the page */
+ wqe->recv.sgl[i].to = cpu_to_be64(((u32) wr->sg_list[i].addr) %
+ (1UL << (12 + page_size[i])));
+
+ /* pbl_addr is the adapters address in the PBL */
+ wqe->recv.pbl_addr[i] = cpu_to_be32(pbl_addr[i]);
+ }
+ for (; i < T3_MAX_SGE; i++) {
+ wqe->recv.sgl[i].stag = 0;
+ wqe->recv.sgl[i].len = 0;
+ wqe->recv.sgl[i].to = 0;
+ wqe->recv.pbl_addr[i] = 0;
+ }
+ return 0;
+}
+
+int iwch_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
+ struct ib_send_wr **bad_wr)
+{
+ int err = 0;
+ u8 t3_wr_flit_cnt;
+ enum t3_wr_opcode t3_wr_opcode = 0;
+ enum t3_wr_flags t3_wr_flags;
+ struct iwch_qp *qhp;
+ u32 idx;
+ union t3_wr *wqe;
+ u32 num_wrs;
+ unsigned long flag;
+ struct t3_swsq *sqp;
+
+ qhp = to_iwch_qp(ibqp);
+ spin_lock_irqsave(&qhp->lock, flag);
+ if (qhp->attr.state > IWCH_QP_STATE_RTS) {
+ spin_unlock_irqrestore(&qhp->lock, flag);
+ return -EINVAL;
+ }
+ num_wrs = Q_FREECNT(qhp->wq.sq_rptr, qhp->wq.sq_wptr,
+ qhp->wq.sq_size_log2);
+ if (num_wrs <= 0) {
+ spin_unlock_irqrestore(&qhp->lock, flag);
+ return -ENOMEM;
+ }
+ while (wr) {
+ if (num_wrs == 0) {
+ err = -ENOMEM;
+ *bad_wr = wr;
+ break;
+ }
+ idx = Q_PTR2IDX(qhp->wq.wptr, qhp->wq.size_log2);
+ wqe = (union t3_wr *) (qhp->wq.queue + idx);
+ t3_wr_flags = 0;
+ if (wr->send_flags & IB_SEND_SOLICITED)
+ t3_wr_flags |= T3_SOLICITED_EVENT_FLAG;
+ if (wr->send_flags & IB_SEND_FENCE)
+ t3_wr_flags |= T3_READ_FENCE_FLAG;
+ if (wr->send_flags & IB_SEND_SIGNALED)
+ t3_wr_flags |= T3_COMPLETION_FLAG;
+ sqp = qhp->wq.sq +
+ Q_PTR2IDX(qhp->wq.sq_wptr, qhp->wq.sq_size_log2);
+ switch (wr->opcode) {
+ case IB_WR_SEND:
+ case IB_WR_SEND_WITH_IMM:
+ t3_wr_opcode = T3_WR_SEND;
+ err = iwch_build_rdma_send(wqe, wr, &t3_wr_flit_cnt);
+ break;
+ case IB_WR_RDMA_WRITE:
+ case IB_WR_RDMA_WRITE_WITH_IMM:
+ t3_wr_opcode = T3_WR_WRITE;
+ err = iwch_build_rdma_write(wqe, wr, &t3_wr_flit_cnt);
+ break;
+ case IB_WR_RDMA_READ:
+ t3_wr_opcode = T3_WR_READ;
+ t3_wr_flags = 0; /* T3 reads are always signaled */
+ err = iwch_build_rdma_read(wqe, wr, &t3_wr_flit_cnt);
+ if (err)
+ break;
+ sqp->read_len = wqe->read.local_len;
+ if (!qhp->wq.oldest_read)
+ qhp->wq.oldest_read = sqp;
+ break;
+ default:
+ PDBG("%s post of type=%d TBD!\n", __FUNCTION__,
+ wr->opcode);
+ err = -EINVAL;
+ }
+ if (err) {
+ *bad_wr = wr;
+ break;
+ }
+ wqe->send.wrid.id0.hi = qhp->wq.sq_wptr;
+ sqp->wr_id = wr->wr_id;
+ sqp->opcode = wr2opcode(t3_wr_opcode);
+ sqp->sq_wptr = qhp->wq.sq_wptr;
+ sqp->complete = 0;
+ sqp->signaled = (wr->send_flags & IB_SEND_SIGNALED);
+
+ build_fw_riwrh((void *) wqe, t3_wr_opcode, t3_wr_flags,
+ Q_GENBIT(qhp->wq.wptr, qhp->wq.size_log2),
+ 0, t3_wr_flit_cnt);
+ PDBG("%s cookie 0x%llx wq idx 0x%x swsq idx %ld opcode %d\n",
+ __FUNCTION__, (unsigned long long) wr->wr_id, idx,
+ Q_PTR2IDX(qhp->wq.sq_wptr, qhp->wq.sq_size_log2),
+ sqp->opcode);
+ wr = wr->next;
+ num_wrs--;
+ ++(qhp->wq.wptr);
+ ++(qhp->wq.sq_wptr);
+ }
+ spin_unlock_irqrestore(&qhp->lock, flag);
+ ring_doorbell(qhp->wq.doorbell, qhp->wq.qpid);
+ return err;
+}
+
+int iwch_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
+ struct ib_recv_wr **bad_wr)
+{
+ int err = 0;
+ struct iwch_qp *qhp;
+ u32 idx;
+ union t3_wr *wqe;
+ u32 num_wrs;
+ unsigned long flag;
+
+ qhp = to_iwch_qp(ibqp);
+ spin_lock_irqsave(&qhp->lock, flag);
+ if (qhp->attr.state > IWCH_QP_STATE_RTS) {
+ spin_unlock_irqrestore(&qhp->lock, flag);
+ return -EINVAL;
+ }
+ num_wrs = Q_FREECNT(qhp->wq.rq_rptr, qhp->wq.rq_wptr,
+ qhp->wq.rq_size_log2) - 1;
+ if (!wr) {
+ spin_unlock_irqrestore(&qhp->lock, flag);
+ return -EINVAL;
+ }
+ while (wr) {
+ idx = Q_PTR2IDX(qhp->wq.wptr, qhp->wq.size_log2);
+ wqe = (union t3_wr *) (qhp->wq.queue + idx);
+ if (num_wrs)
+ err = iwch_build_rdma_recv(qhp->rhp, wqe, wr);
+ else
+ err = -ENOMEM;
+ if (err) {
+ *bad_wr = wr;
+ break;
+ }
+ qhp->wq.rq[Q_PTR2IDX(qhp->wq.rq_wptr, qhp->wq.rq_size_log2)] =
+ wr->wr_id;
+ build_fw_riwrh((void *) wqe, T3_WR_RCV, T3_COMPLETION_FLAG,
+ Q_GENBIT(qhp->wq.wptr, qhp->wq.size_log2),
+ 0, sizeof(struct t3_receive_wr) >> 3);
+ PDBG("%s cookie 0x%llx idx 0x%x rq_wptr 0x%x rw_rptr 0x%x "
+ "wqe %p \n", __FUNCTION__, (unsigned long long) wr->wr_id,
+ idx, qhp->wq.rq_wptr, qhp->wq.rq_rptr, wqe);
+ ++(qhp->wq.rq_wptr);
+ ++(qhp->wq.wptr);
+ wr = wr->next;
+ num_wrs--;
+ }
+ spin_unlock_irqrestore(&qhp->lock, flag);
+ ring_doorbell(qhp->wq.doorbell, qhp->wq.qpid);
+ return err;
+}
+
+int iwch_bind_mw(struct ib_qp *qp,
+ struct ib_mw *mw,
+ struct ib_mw_bind *mw_bind)
+{
+ struct iwch_dev *rhp;
+ struct iwch_mw *mhp;
+ struct iwch_qp *qhp;
+ union t3_wr *wqe;
+ u32 pbl_addr;
+ u8 page_size;
+ u32 num_wrs;
+ unsigned long flag;
+ struct ib_sge sgl;
+ int err=0;
+ enum t3_wr_flags t3_wr_flags;
+ u32 idx;
+ struct t3_swsq *sqp;
+
+ qhp = to_iwch_qp(qp);
+ mhp = to_iwch_mw(mw);
+ rhp = qhp->rhp;
+
+ spin_lock_irqsave(&qhp->lock, flag);
+ if (qhp->attr.state > IWCH_QP_STATE_RTS) {
+ spin_unlock_irqrestore(&qhp->lock, flag);
+ return -EINVAL;
+ }
+ num_wrs = Q_FREECNT(qhp->wq.sq_rptr, qhp->wq.sq_wptr,
+ qhp->wq.sq_size_log2);
+ if ((num_wrs) <= 0) {
+ spin_unlock_irqrestore(&qhp->lock, flag);
+ return -ENOMEM;
+ }
+ idx = Q_PTR2IDX(qhp->wq.wptr, qhp->wq.size_log2);
+ PDBG("%s: idx 0x%0x, mw 0x%p, mw_bind 0x%p\n", __FUNCTION__, idx,
+ mw, mw_bind);
+ wqe = (union t3_wr *) (qhp->wq.queue + idx);
+
+ t3_wr_flags = 0;
+ if (mw_bind->send_flags & IB_SEND_SIGNALED)
+ t3_wr_flags = T3_COMPLETION_FLAG;
+
+ sgl.addr = mw_bind->addr;
+ sgl.lkey = mw_bind->mr->lkey;
+ sgl.length = mw_bind->length;
+ wqe->bind.reserved = 0;
+ wqe->bind.type = T3_VA_BASED_TO;
+
+ /* TBD: check perms */
+ wqe->bind.perms = iwch_convert_access(mw_bind->mw_access_flags);
+ wqe->bind.mr_stag = cpu_to_be32(mw_bind->mr->lkey);
+ wqe->bind.mw_stag = cpu_to_be32(mw->rkey);
+ wqe->bind.mw_len = cpu_to_be32(mw_bind->length);
+ wqe->bind.mw_va = cpu_to_be64(mw_bind->addr);
+ err = iwch_sgl2pbl_map(rhp, &sgl, 1, &pbl_addr, &page_size);
+ if (err) {
+ spin_unlock_irqrestore(&qhp->lock, flag);
+ return err;
+ }
+ wqe->send.wrid.id0.hi = qhp->wq.sq_wptr;
+ sqp = qhp->wq.sq + Q_PTR2IDX(qhp->wq.sq_wptr, qhp->wq.sq_size_log2);
+ sqp->wr_id = mw_bind->wr_id;
+ sqp->opcode = T3_BIND_MW;
+ sqp->sq_wptr = qhp->wq.sq_wptr;
+ sqp->complete = 0;
+ sqp->signaled = (mw_bind->send_flags & IB_SEND_SIGNALED);
+ wqe->bind.mr_pbl_addr = cpu_to_be32(pbl_addr);
+ wqe->bind.mr_pagesz = page_size;
+ wqe->flit[T3_SQ_COOKIE_FLIT] = mw_bind->wr_id;
+ build_fw_riwrh((void *)wqe, T3_WR_BIND, t3_wr_flags,
+ Q_GENBIT(qhp->wq.wptr, qhp->wq.size_log2), 0,
+ sizeof(struct t3_bind_mw_wr) >> 3);
+ ++(qhp->wq.wptr);
+ ++(qhp->wq.sq_wptr);
+ spin_unlock_irqrestore(&qhp->lock, flag);
+
+ ring_doorbell(qhp->wq.doorbell, qhp->wq.qpid);
+
+ return err;
+}
+
+static inline void build_term_codes(int t3err, u8 *layer_type, u8 *ecode,
+ int tagged)
+{
+ switch (t3err) {
+ case TPT_ERR_STAG:
+ if (tagged == 1) {
+ *layer_type = LAYER_DDP|DDP_TAGGED_ERR;
+ *ecode = DDPT_INV_STAG;
+ } else if (tagged == 2) {
+ *layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT;
+ *ecode = RDMAP_INV_STAG;
+ }
+ break;
+ case TPT_ERR_PDID:
+ case TPT_ERR_QPID:
+ case TPT_ERR_ACCESS:
+ if (tagged == 1) {
+ *layer_type = LAYER_DDP|DDP_TAGGED_ERR;
+ *ecode = DDPT_STAG_NOT_ASSOC;
+ } else if (tagged == 2) {
+ *layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT;
+ *ecode = RDMAP_STAG_NOT_ASSOC;
+ }
+ break;
+ case TPT_ERR_WRAP:
+ *layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT;
+ *ecode = RDMAP_TO_WRAP;
+ break;
+ case TPT_ERR_BOUND:
+ if (tagged == 1) {
+ *layer_type = LAYER_DDP|DDP_TAGGED_ERR;
+ *ecode = DDPT_BASE_BOUNDS;
+ } else if (tagged == 2) {
+ *layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT;
+ *ecode = RDMAP_BASE_BOUNDS;
+ } else {
+ *layer_type = LAYER_DDP|DDP_UNTAGGED_ERR;
+ *ecode = DDPU_MSG_TOOBIG;
+ }
+ break;
+ case TPT_ERR_INVALIDATE_SHARED_MR:
+ case TPT_ERR_INVALIDATE_MR_WITH_MW_BOUND:
+ *layer_type = LAYER_RDMAP|RDMAP_REMOTE_OP;
+ *ecode = RDMAP_CANT_INV_STAG;
+ break;
+ case TPT_ERR_ECC:
+ case TPT_ERR_ECC_PSTAG:
+ case TPT_ERR_INTERNAL_ERR:
+ *layer_type = LAYER_RDMAP|RDMAP_LOCAL_CATA;
+ *ecode = 0;
+ break;
+ case TPT_ERR_OUT_OF_RQE:
+ *layer_type = LAYER_DDP|DDP_UNTAGGED_ERR;
+ *ecode = DDPU_INV_MSN_NOBUF;
+ break;
+ case TPT_ERR_PBL_ADDR_BOUND:
+ *layer_type = LAYER_DDP|DDP_TAGGED_ERR;
+ *ecode = DDPT_BASE_BOUNDS;
+ break;
+ case TPT_ERR_CRC:
+ *layer_type = LAYER_MPA|DDP_LLP;
+ *ecode = MPA_CRC_ERR;
+ break;
+ case TPT_ERR_MARKER:
+ *layer_type = LAYER_MPA|DDP_LLP;
+ *ecode = MPA_MARKER_ERR;
+ break;
+ case TPT_ERR_PDU_LEN_ERR:
+ *layer_type = LAYER_DDP|DDP_UNTAGGED_ERR;
+ *ecode = DDPU_MSG_TOOBIG;
+ break;
+ case TPT_ERR_DDP_VERSION:
+ if (tagged) {
+ *layer_type = LAYER_DDP|DDP_TAGGED_ERR;
+ *ecode = DDPT_INV_VERS;
+ } else {
+ *layer_type = LAYER_DDP|DDP_UNTAGGED_ERR;
+ *ecode = DDPU_INV_VERS;
+ }
+ break;
+ case TPT_ERR_RDMA_VERSION:
+ *layer_type = LAYER_RDMAP|RDMAP_REMOTE_OP;
+ *ecode = RDMAP_INV_VERS;
+ break;
+ case TPT_ERR_OPCODE:
+ *layer_type = LAYER_RDMAP|RDMAP_REMOTE_OP;
+ *ecode = RDMAP_INV_OPCODE;
+ break;
+ case TPT_ERR_DDP_QUEUE_NUM:
+ *layer_type = LAYER_DDP|DDP_UNTAGGED_ERR;
+ *ecode = DDPU_INV_QN;
+ break;
+ case TPT_ERR_MSN:
+ case TPT_ERR_MSN_GAP:
+ case TPT_ERR_MSN_RANGE:
+ case TPT_ERR_IRD_OVERFLOW:
+ *layer_type = LAYER_DDP|DDP_UNTAGGED_ERR;
+ *ecode = DDPU_INV_MSN_RANGE;
+ break;
+ case TPT_ERR_TBIT:
+ *layer_type = LAYER_DDP|DDP_LOCAL_CATA;
+ *ecode = 0;
+ break;
+ case TPT_ERR_MO:
+ *layer_type = LAYER_DDP|DDP_UNTAGGED_ERR;
+ *ecode = DDPU_INV_MO;
+ break;
+ default:
+ *layer_type = LAYER_RDMAP|DDP_LOCAL_CATA;
+ *ecode = 0;
+ break;
+ }
+}
+
+/*
+ * This posts a TERMINATE with layer=RDMA, type=catastrophic.
+ */
+int iwch_post_terminate(struct iwch_qp *qhp, struct respQ_msg_t *rsp_msg)
+{
+ union t3_wr *wqe;
+ struct terminate_message *term;
+ int status;
+ int tagged = 0;
+ struct sk_buff *skb;
+
+ PDBG("%s %d\n", __FUNCTION__, __LINE__);
+ skb = alloc_skb(40, GFP_ATOMIC);
+ if (!skb) {
+ printk(KERN_ERR "%s cannot send TERMINATE!\n", __FUNCTION__);
+ return -ENOMEM;
+ }
+ wqe = (union t3_wr *)skb_put(skb, 40);
+ memset(wqe, 0, 40);
+ wqe->send.rdmaop = T3_TERMINATE;
+
+ /* immediate data length */
+ wqe->send.plen = htonl(4);
+
+ /* immediate data starts here. */
+ term = (struct terminate_message *)wqe->send.sgl;
+ if (rsp_msg) {
+ status = CQE_STATUS(rsp_msg->cqe);
+ if (CQE_OPCODE(rsp_msg->cqe) == T3_RDMA_WRITE)
+ tagged = 1;
+ if ((CQE_OPCODE(rsp_msg->cqe) == T3_READ_REQ) ||
+ (CQE_OPCODE(rsp_msg->cqe) == T3_READ_RESP))
+ tagged = 2;
+ } else {
+ status = TPT_ERR_INTERNAL_ERR;
+ }
+ build_term_codes(status, &term->layer_etype, &term->ecode, tagged);
+ build_fw_riwrh((void *)wqe, T3_WR_SEND,
+ T3_COMPLETION_FLAG | T3_NOTIFY_FLAG, 1,
+ qhp->ep->hwtid, 5);
+ skb->priority = CPL_PRIORITY_DATA;
+ return cxgb3_ofld_send(qhp->rhp->rdev.t3cdev_p, skb);
+}
+
+/*
+ * Assumes qhp lock is held.
+ */
+static void __flush_qp(struct iwch_qp *qhp, unsigned long *flag)
+{
+ struct iwch_cq *rchp, *schp;
+ int count;
+
+ rchp = get_chp(qhp->rhp, qhp->attr.rcq);
+ schp = get_chp(qhp->rhp, qhp->attr.scq);
+
+ PDBG("%s qhp %p rchp %p schp %p\n", __FUNCTION__, qhp, rchp, schp);
+ /* take a ref on the qhp since we must release the lock */
+ atomic_inc(&qhp->refcnt);
+ spin_unlock_irqrestore(&qhp->lock, *flag);
+
+ /* locking heirarchy: cq lock first, then qp lock. */
+ spin_lock_irqsave(&rchp->lock, *flag);
+ spin_lock(&qhp->lock);
+ cxio_flush_hw_cq(&rchp->cq);
+ cxio_count_rcqes(&rchp->cq, &qhp->wq, &count);
+ cxio_flush_rq(&qhp->wq, &rchp->cq, count);
+ spin_unlock(&qhp->lock);
+ spin_unlock_irqrestore(&rchp->lock, *flag);
+
+ /* locking heirarchy: cq lock first, then qp lock. */
+ spin_lock_irqsave(&schp->lock, *flag);
+ spin_lock(&qhp->lock);
+ cxio_flush_hw_cq(&schp->cq);
+ cxio_count_scqes(&schp->cq, &qhp->wq, &count);
+ cxio_flush_sq(&qhp->wq, &schp->cq, count);
+ spin_unlock(&qhp->lock);
+ spin_unlock_irqrestore(&schp->lock, *flag);
+
+ /* deref */
+ if (atomic_dec_and_test(&qhp->refcnt))
+ wake_up(&qhp->wait);
+
+ spin_lock_irqsave(&qhp->lock, *flag);
+}
+
+static inline void flush_qp(struct iwch_qp *qhp, unsigned long *flag)
+{
+ if (t3b_device(qhp->rhp))
+ cxio_set_wq_in_error(&qhp->wq);
+ else
+ __flush_qp(qhp, flag);
+}
+
+
+/*
+ * Return non zero if at least one RECV was pre-posted.
+ */
+static inline int rqes_posted(struct iwch_qp *qhp)
+{
+ return fw_riwrh_opcode((struct fw_riwrh *)qhp->wq.queue) == T3_WR_RCV;
+}
+
+static int rdma_init(struct iwch_dev *rhp, struct iwch_qp *qhp,
+ enum iwch_qp_attr_mask mask,
+ struct iwch_qp_attributes *attrs)
+{
+ struct t3_rdma_init_attr init_attr;
+ int ret;
+
+ init_attr.tid = qhp->ep->hwtid;
+ init_attr.qpid = qhp->wq.qpid;
+ init_attr.pdid = qhp->attr.pd;
+ init_attr.scqid = qhp->attr.scq;
+ init_attr.rcqid = qhp->attr.rcq;
+ init_attr.rq_addr = qhp->wq.rq_addr;
+ init_attr.rq_size = 1 << qhp->wq.rq_size_log2;
+ init_attr.mpaattrs = uP_RI_MPA_IETF_ENABLE |
+ qhp->attr.mpa_attr.recv_marker_enabled |
+ (qhp->attr.mpa_attr.xmit_marker_enabled << 1) |
+ (qhp->attr.mpa_attr.crc_enabled << 2);
+
+ /*
+ * XXX - The IWCM doesn't quite handle getting these
+ * attrs set before going into RTS. For now, just turn
+ * them on always...
+ */
+#if 0
+ init_attr.qpcaps = qhp->attr.enableRdmaRead |
+ (qhp->attr.enableRdmaWrite << 1) |
+ (qhp->attr.enableBind << 2) |
+ (qhp->attr.enable_stag0_fastreg << 3) |
+ (qhp->attr.enable_stag0_fastreg << 4);
+#else
+ init_attr.qpcaps = 0x1f;
+#endif
+ init_attr.tcp_emss = qhp->ep->emss;
+ init_attr.ord = qhp->attr.max_ord;
+ init_attr.ird = qhp->attr.max_ird;
+ init_attr.qp_dma_addr = qhp->wq.dma_addr;
+ init_attr.qp_dma_size = (1UL << qhp->wq.size_log2);
+ init_attr.flags = rqes_posted(qhp) ? RECVS_POSTED : 0;
+ PDBG("%s init_attr.rq_addr 0x%x init_attr.rq_size = %d "
+ "flags 0x%x qpcaps 0x%x\n", __FUNCTION__,
+ init_attr.rq_addr, init_attr.rq_size,
+ init_attr.flags, init_attr.qpcaps);
+ ret = cxio_rdma_init(&rhp->rdev, &init_attr);
+ PDBG("%s ret %d\n", __FUNCTION__, ret);
+ return ret;
+}
+
+int iwch_modify_qp(struct iwch_dev *rhp, struct iwch_qp *qhp,
+ enum iwch_qp_attr_mask mask,
+ struct iwch_qp_attributes *attrs,
+ int internal)
+{
+ int ret = 0;
+ struct iwch_qp_attributes newattr = qhp->attr;
+ unsigned long flag;
+ int disconnect = 0;
+ int terminate = 0;
+ int abort = 0;
+ int free = 0;
+ struct iwch_ep *ep = NULL;
+
+ PDBG("%s qhp %p qpid 0x%x ep %p state %d -> %d\n", __FUNCTION__,
+ qhp, qhp->wq.qpid, qhp->ep, qhp->attr.state,
+ (mask & IWCH_QP_ATTR_NEXT_STATE) ? attrs->next_state : -1);
+
+ spin_lock_irqsave(&qhp->lock, flag);
+
+ /* Process attr changes if in IDLE */
+ if (mask & IWCH_QP_ATTR_VALID_MODIFY) {
+ if (qhp->attr.state != IWCH_QP_STATE_IDLE) {
+ ret = -EIO;
+ goto out;
+ }
+ if (mask & IWCH_QP_ATTR_ENABLE_RDMA_READ)
+ newattr.enable_rdma_read = attrs->enable_rdma_read;
+ if (mask & IWCH_QP_ATTR_ENABLE_RDMA_WRITE)
+ newattr.enable_rdma_write = attrs->enable_rdma_write;
+ if (mask & IWCH_QP_ATTR_ENABLE_RDMA_BIND)
+ newattr.enable_bind = attrs->enable_bind;
+ if (mask & IWCH_QP_ATTR_MAX_ORD) {
+ if (attrs->max_ord >
+ rhp->attr.max_rdma_read_qp_depth) {
+ ret = -EINVAL;
+ goto out;
+ }
+ newattr.max_ord = attrs->max_ord;
+ }
+ if (mask & IWCH_QP_ATTR_MAX_IRD) {
+ if (attrs->max_ird >
+ rhp->attr.max_rdma_reads_per_qp) {
+ ret = -EINVAL;
+ goto out;
+ }
+ newattr.max_ird = attrs->max_ird;
+ }
+ qhp->attr = newattr;
+ }
+
+ if (!(mask & IWCH_QP_ATTR_NEXT_STATE))
+ goto out;
+ if (qhp->attr.state == attrs->next_state)
+ goto out;
+
+ switch (qhp->attr.state) {
+ case IWCH_QP_STATE_IDLE:
+ switch (attrs->next_state) {
+ case IWCH_QP_STATE_RTS:
+ if (!(mask & IWCH_QP_ATTR_LLP_STREAM_HANDLE)) {
+ ret = -EINVAL;
+ goto out;
+ }
+ if (!(mask & IWCH_QP_ATTR_MPA_ATTR)) {
+ ret = -EINVAL;
+ goto out;
+ }
+ qhp->attr.mpa_attr = attrs->mpa_attr;
+ qhp->attr.llp_stream_handle = attrs->llp_stream_handle;
+ qhp->ep = qhp->attr.llp_stream_handle;
+ qhp->attr.state = IWCH_QP_STATE_RTS;
+
+ /*
+ * Ref the endpoint here and deref when we
+ * disassociate the endpoint from the QP. This
+ * happens in CLOSING->IDLE transition or *->ERROR
+ * transition.
+ */
+ get_ep(&qhp->ep->com);
+ spin_unlock_irqrestore(&qhp->lock, flag);
+ ret = rdma_init(rhp, qhp, mask, attrs);
+ spin_lock_irqsave(&qhp->lock, flag);
+ if (ret)
+ goto err;
+ break;
+ case IWCH_QP_STATE_ERROR:
+ qhp->attr.state = IWCH_QP_STATE_ERROR;
+ flush_qp(qhp, &flag);
+ break;
+ default:
+ ret = -EINVAL;
+ goto out;
+ }
+ break;
+ case IWCH_QP_STATE_RTS:
+ switch (attrs->next_state) {
+ case IWCH_QP_STATE_CLOSING:
+ BUG_ON(atomic_read(&qhp->ep->com.kref.refcount) < 2);
+ qhp->attr.state = IWCH_QP_STATE_CLOSING;
+ if (!internal) {
+ abort=0;
+ disconnect = 1;
+ ep = qhp->ep;
+ }
+ break;
+ case IWCH_QP_STATE_TERMINATE:
+ qhp->attr.state = IWCH_QP_STATE_TERMINATE;
+ if (t3b_device(qhp->rhp))
+ cxio_set_wq_in_error(&qhp->wq);
+ if (!internal)
+ terminate = 1;
+ break;
+ case IWCH_QP_STATE_ERROR:
+ qhp->attr.state = IWCH_QP_STATE_ERROR;
+ if (!internal) {
+ abort=1;
+ disconnect = 1;
+ ep = qhp->ep;
+ }
+ goto err;
+ break;
+ default:
+ ret = -EINVAL;
+ goto out;
+ }
+ break;
+ case IWCH_QP_STATE_CLOSING:
+ if (!internal) {
+ ret = -EINVAL;
+ goto out;
+ }
+ switch (attrs->next_state) {
+ case IWCH_QP_STATE_IDLE:
+ qhp->attr.state = IWCH_QP_STATE_IDLE;
+ qhp->attr.llp_stream_handle = NULL;
+ put_ep(&qhp->ep->com);
+ qhp->ep = NULL;
+ wake_up(&qhp->wait);
+ break;
+ case IWCH_QP_STATE_ERROR:
+ goto err;
+ default:
+ ret = -EINVAL;
+ goto err;
+ }
+ break;
+ case IWCH_QP_STATE_ERROR:
+ if (attrs->next_state != IWCH_QP_STATE_IDLE) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (!Q_EMPTY(qhp->wq.sq_rptr, qhp->wq.sq_wptr) ||
+ !Q_EMPTY(qhp->wq.rq_rptr, qhp->wq.rq_wptr)) {
+ ret = -EINVAL;
+ goto out;
+ }
+ qhp->attr.state = IWCH_QP_STATE_IDLE;
+ memset(&qhp->attr, 0, sizeof(qhp->attr));
+ break;
+ case IWCH_QP_STATE_TERMINATE:
+ if (!internal) {
+ ret = -EINVAL;
+ goto out;
+ }
+ goto err;
+ break;
+ default:
+ printk(KERN_ERR "%s in a bad state %d\n",
+ __FUNCTION__, qhp->attr.state);
+ ret = -EINVAL;
+ goto err;
+ break;
+ }
+ goto out;
+err:
+ PDBG("%s disassociating ep %p qpid 0x%x\n", __FUNCTION__, qhp->ep,
+ qhp->wq.qpid);
+
+ /* disassociate the LLP connection */
+ qhp->attr.llp_stream_handle = NULL;
+ ep = qhp->ep;
+ qhp->ep = NULL;
+ qhp->attr.state = IWCH_QP_STATE_ERROR;
+ free=1;
+ wake_up(&qhp->wait);
+ BUG_ON(!ep);
+ flush_qp(qhp, &flag);
+out:
+ spin_unlock_irqrestore(&qhp->lock, flag);
+
+ if (terminate)
+ iwch_post_terminate(qhp, NULL);
+
+ /*
+ * If disconnect is 1, then we need to initiate a disconnect
+ * on the EP. This can be a normal close (RTS->CLOSING) or
+ * an abnormal close (RTS/CLOSING->ERROR).
+ */
+ if (disconnect)
+ iwch_ep_disconnect(ep, abort, GFP_KERNEL);
+
+ /*
+ * If free is 1, then we've disassociated the EP from the QP
+ * and we need to dereference the EP.
+ */
+ if (free)
+ put_ep(&ep->com);
+
+ PDBG("%s exit state %d\n", __FUNCTION__, qhp->attr.state);
+ return ret;
+}
+
+static int quiesce_qp(struct iwch_qp *qhp)
+{
+ spin_lock_irq(&qhp->lock);
+ iwch_quiesce_tid(qhp->ep);
+ qhp->flags |= QP_QUIESCED;
+ spin_unlock_irq(&qhp->lock);
+ return 0;
+}
+
+static int resume_qp(struct iwch_qp *qhp)
+{
+ spin_lock_irq(&qhp->lock);
+ iwch_resume_tid(qhp->ep);
+ qhp->flags &= ~QP_QUIESCED;
+ spin_unlock_irq(&qhp->lock);
+ return 0;
+}
+
+int iwch_quiesce_qps(struct iwch_cq *chp)
+{
+ int i;
+ struct iwch_qp *qhp;
+
+ for (i=0; i < T3_MAX_NUM_QP; i++) {
+ qhp = get_qhp(chp->rhp, i);
+ if (!qhp)
+ continue;
+ if ((qhp->attr.rcq == chp->cq.cqid) && !qp_quiesced(qhp)) {
+ quiesce_qp(qhp);
+ continue;
+ }
+ if ((qhp->attr.scq == chp->cq.cqid) && !qp_quiesced(qhp))
+ quiesce_qp(qhp);
+ }
+ return 0;
+}
+
+int iwch_resume_qps(struct iwch_cq *chp)
+{
+ int i;
+ struct iwch_qp *qhp;
+
+ for (i=0; i < T3_MAX_NUM_QP; i++) {
+ qhp = get_qhp(chp->rhp, i);
+ if (!qhp)
+ continue;
+ if ((qhp->attr.rcq == chp->cq.cqid) && qp_quiesced(qhp)) {
+ resume_qp(qhp);
+ continue;
+ }
+ if ((qhp->attr.scq == chp->cq.cqid) && qp_quiesced(qhp))
+ resume_qp(qhp);
+ }
+ return 0;
+}
diff --git a/drivers/infiniband/hw/cxgb3/iwch_user.h b/drivers/infiniband/hw/cxgb3/iwch_user.h
new file mode 100644
index 00000000000..cb7086f558c
--- /dev/null
+++ b/drivers/infiniband/hw/cxgb3/iwch_user.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2006 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef __IWCH_USER_H__
+#define __IWCH_USER_H__
+
+#define IWCH_UVERBS_ABI_VERSION 1
+
+/*
+ * Make sure that all structs defined in this file remain laid out so
+ * that they pack the same way on 32-bit and 64-bit architectures (to
+ * avoid incompatibility between 32-bit userspace and 64-bit kernels).
+ * In particular do not use pointer types -- pass pointers in __u64
+ * instead.
+ */
+struct iwch_create_cq_req {
+ __u64 user_rptr_addr;
+};
+
+struct iwch_create_cq_resp {
+ __u64 key;
+ __u32 cqid;
+ __u32 size_log2;
+};
+
+struct iwch_create_qp_resp {
+ __u64 key;
+ __u64 db_key;
+ __u32 qpid;
+ __u32 size_log2;
+ __u32 sq_size_log2;
+ __u32 rq_size_log2;
+};
+
+struct iwch_reg_user_mr_resp {
+ __u32 pbl_addr;
+};
+#endif
diff --git a/drivers/infiniband/hw/cxgb3/tcb.h b/drivers/infiniband/hw/cxgb3/tcb.h
new file mode 100644
index 00000000000..c702dc199e1
--- /dev/null
+++ b/drivers/infiniband/hw/cxgb3/tcb.h
@@ -0,0 +1,632 @@
+/*
+ * Copyright (c) 2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef _TCB_DEFS_H
+#define _TCB_DEFS_H
+
+#define W_TCB_T_STATE 0
+#define S_TCB_T_STATE 0
+#define M_TCB_T_STATE 0xfULL
+#define V_TCB_T_STATE(x) ((x) << S_TCB_T_STATE)
+
+#define W_TCB_TIMER 0
+#define S_TCB_TIMER 4
+#define M_TCB_TIMER 0x1ULL
+#define V_TCB_TIMER(x) ((x) << S_TCB_TIMER)
+
+#define W_TCB_DACK_TIMER 0
+#define S_TCB_DACK_TIMER 5
+#define M_TCB_DACK_TIMER 0x1ULL
+#define V_TCB_DACK_TIMER(x) ((x) << S_TCB_DACK_TIMER)
+
+#define W_TCB_DEL_FLAG 0
+#define S_TCB_DEL_FLAG 6
+#define M_TCB_DEL_FLAG 0x1ULL
+#define V_TCB_DEL_FLAG(x) ((x) << S_TCB_DEL_FLAG)
+
+#define W_TCB_L2T_IX 0
+#define S_TCB_L2T_IX 7
+#define M_TCB_L2T_IX 0x7ffULL
+#define V_TCB_L2T_IX(x) ((x) << S_TCB_L2T_IX)
+
+#define W_TCB_SMAC_SEL 0
+#define S_TCB_SMAC_SEL 18
+#define M_TCB_SMAC_SEL 0x3ULL
+#define V_TCB_SMAC_SEL(x) ((x) << S_TCB_SMAC_SEL)
+
+#define W_TCB_TOS 0
+#define S_TCB_TOS 20
+#define M_TCB_TOS 0x3fULL
+#define V_TCB_TOS(x) ((x) << S_TCB_TOS)
+
+#define W_TCB_MAX_RT 0
+#define S_TCB_MAX_RT 26
+#define M_TCB_MAX_RT 0xfULL
+#define V_TCB_MAX_RT(x) ((x) << S_TCB_MAX_RT)
+
+#define W_TCB_T_RXTSHIFT 0
+#define S_TCB_T_RXTSHIFT 30
+#define M_TCB_T_RXTSHIFT 0xfULL
+#define V_TCB_T_RXTSHIFT(x) ((x) << S_TCB_T_RXTSHIFT)
+
+#define W_TCB_T_DUPACKS 1
+#define S_TCB_T_DUPACKS 2
+#define M_TCB_T_DUPACKS 0xfULL
+#define V_TCB_T_DUPACKS(x) ((x) << S_TCB_T_DUPACKS)
+
+#define W_TCB_T_MAXSEG 1
+#define S_TCB_T_MAXSEG 6
+#define M_TCB_T_MAXSEG 0xfULL
+#define V_TCB_T_MAXSEG(x) ((x) << S_TCB_T_MAXSEG)
+
+#define W_TCB_T_FLAGS1 1
+#define S_TCB_T_FLAGS1 10
+#define M_TCB_T_FLAGS1 0xffffffffULL
+#define V_TCB_T_FLAGS1(x) ((x) << S_TCB_T_FLAGS1)
+
+#define W_TCB_T_MIGRATION 1
+#define S_TCB_T_MIGRATION 20
+#define M_TCB_T_MIGRATION 0x1ULL
+#define V_TCB_T_MIGRATION(x) ((x) << S_TCB_T_MIGRATION)
+
+#define W_TCB_T_FLAGS2 2
+#define S_TCB_T_FLAGS2 10
+#define M_TCB_T_FLAGS2 0x7fULL
+#define V_TCB_T_FLAGS2(x) ((x) << S_TCB_T_FLAGS2)
+
+#define W_TCB_SND_SCALE 2
+#define S_TCB_SND_SCALE 17
+#define M_TCB_SND_SCALE 0xfULL
+#define V_TCB_SND_SCALE(x) ((x) << S_TCB_SND_SCALE)
+
+#define W_TCB_RCV_SCALE 2
+#define S_TCB_RCV_SCALE 21
+#define M_TCB_RCV_SCALE 0xfULL
+#define V_TCB_RCV_SCALE(x) ((x) << S_TCB_RCV_SCALE)
+
+#define W_TCB_SND_UNA_RAW 2
+#define S_TCB_SND_UNA_RAW 25
+#define M_TCB_SND_UNA_RAW 0x7ffffffULL
+#define V_TCB_SND_UNA_RAW(x) ((x) << S_TCB_SND_UNA_RAW)
+
+#define W_TCB_SND_NXT_RAW 3
+#define S_TCB_SND_NXT_RAW 20
+#define M_TCB_SND_NXT_RAW 0x7ffffffULL
+#define V_TCB_SND_NXT_RAW(x) ((x) << S_TCB_SND_NXT_RAW)
+
+#define W_TCB_RCV_NXT 4
+#define S_TCB_RCV_NXT 15
+#define M_TCB_RCV_NXT 0xffffffffULL
+#define V_TCB_RCV_NXT(x) ((x) << S_TCB_RCV_NXT)
+
+#define W_TCB_RCV_ADV 5
+#define S_TCB_RCV_ADV 15
+#define M_TCB_RCV_ADV 0xffffULL
+#define V_TCB_RCV_ADV(x) ((x) << S_TCB_RCV_ADV)
+
+#define W_TCB_SND_MAX_RAW 5
+#define S_TCB_SND_MAX_RAW 31
+#define M_TCB_SND_MAX_RAW 0x7ffffffULL
+#define V_TCB_SND_MAX_RAW(x) ((x) << S_TCB_SND_MAX_RAW)
+
+#define W_TCB_SND_CWND 6
+#define S_TCB_SND_CWND 26
+#define M_TCB_SND_CWND 0x7ffffffULL
+#define V_TCB_SND_CWND(x) ((x) << S_TCB_SND_CWND)
+
+#define W_TCB_SND_SSTHRESH 7
+#define S_TCB_SND_SSTHRESH 21
+#define M_TCB_SND_SSTHRESH 0x7ffffffULL
+#define V_TCB_SND_SSTHRESH(x) ((x) << S_TCB_SND_SSTHRESH)
+
+#define W_TCB_T_RTT_TS_RECENT_AGE 8
+#define S_TCB_T_RTT_TS_RECENT_AGE 16
+#define M_TCB_T_RTT_TS_RECENT_AGE 0xffffffffULL
+#define V_TCB_T_RTT_TS_RECENT_AGE(x) ((x) << S_TCB_T_RTT_TS_RECENT_AGE)
+
+#define W_TCB_T_RTSEQ_RECENT 9
+#define S_TCB_T_RTSEQ_RECENT 16
+#define M_TCB_T_RTSEQ_RECENT 0xffffffffULL
+#define V_TCB_T_RTSEQ_RECENT(x) ((x) << S_TCB_T_RTSEQ_RECENT)
+
+#define W_TCB_T_SRTT 10
+#define S_TCB_T_SRTT 16
+#define M_TCB_T_SRTT 0xffffULL
+#define V_TCB_T_SRTT(x) ((x) << S_TCB_T_SRTT)
+
+#define W_TCB_T_RTTVAR 11
+#define S_TCB_T_RTTVAR 0
+#define M_TCB_T_RTTVAR 0xffffULL
+#define V_TCB_T_RTTVAR(x) ((x) << S_TCB_T_RTTVAR)
+
+#define W_TCB_TS_LAST_ACK_SENT_RAW 11
+#define S_TCB_TS_LAST_ACK_SENT_RAW 16
+#define M_TCB_TS_LAST_ACK_SENT_RAW 0x7ffffffULL
+#define V_TCB_TS_LAST_ACK_SENT_RAW(x) ((x) << S_TCB_TS_LAST_ACK_SENT_RAW)
+
+#define W_TCB_DIP 12
+#define S_TCB_DIP 11
+#define M_TCB_DIP 0xffffffffULL
+#define V_TCB_DIP(x) ((x) << S_TCB_DIP)
+
+#define W_TCB_SIP 13
+#define S_TCB_SIP 11
+#define M_TCB_SIP 0xffffffffULL
+#define V_TCB_SIP(x) ((x) << S_TCB_SIP)
+
+#define W_TCB_DP 14
+#define S_TCB_DP 11
+#define M_TCB_DP 0xffffULL
+#define V_TCB_DP(x) ((x) << S_TCB_DP)
+
+#define W_TCB_SP 14
+#define S_TCB_SP 27
+#define M_TCB_SP 0xffffULL
+#define V_TCB_SP(x) ((x) << S_TCB_SP)
+
+#define W_TCB_TIMESTAMP 15
+#define S_TCB_TIMESTAMP 11
+#define M_TCB_TIMESTAMP 0xffffffffULL
+#define V_TCB_TIMESTAMP(x) ((x) << S_TCB_TIMESTAMP)
+
+#define W_TCB_TIMESTAMP_OFFSET 16
+#define S_TCB_TIMESTAMP_OFFSET 11
+#define M_TCB_TIMESTAMP_OFFSET 0xfULL
+#define V_TCB_TIMESTAMP_OFFSET(x) ((x) << S_TCB_TIMESTAMP_OFFSET)
+
+#define W_TCB_TX_MAX 16
+#define S_TCB_TX_MAX 15
+#define M_TCB_TX_MAX 0xffffffffULL
+#define V_TCB_TX_MAX(x) ((x) << S_TCB_TX_MAX)
+
+#define W_TCB_TX_HDR_PTR_RAW 17
+#define S_TCB_TX_HDR_PTR_RAW 15
+#define M_TCB_TX_HDR_PTR_RAW 0x1ffffULL
+#define V_TCB_TX_HDR_PTR_RAW(x) ((x) << S_TCB_TX_HDR_PTR_RAW)
+
+#define W_TCB_TX_LAST_PTR_RAW 18
+#define S_TCB_TX_LAST_PTR_RAW 0
+#define M_TCB_TX_LAST_PTR_RAW 0x1ffffULL
+#define V_TCB_TX_LAST_PTR_RAW(x) ((x) << S_TCB_TX_LAST_PTR_RAW)
+
+#define W_TCB_TX_COMPACT 18
+#define S_TCB_TX_COMPACT 17
+#define M_TCB_TX_COMPACT 0x1ULL
+#define V_TCB_TX_COMPACT(x) ((x) << S_TCB_TX_COMPACT)
+
+#define W_TCB_RX_COMPACT 18
+#define S_TCB_RX_COMPACT 18
+#define M_TCB_RX_COMPACT 0x1ULL
+#define V_TCB_RX_COMPACT(x) ((x) << S_TCB_RX_COMPACT)
+
+#define W_TCB_RCV_WND 18
+#define S_TCB_RCV_WND 19
+#define M_TCB_RCV_WND 0x7ffffffULL
+#define V_TCB_RCV_WND(x) ((x) << S_TCB_RCV_WND)
+
+#define W_TCB_RX_HDR_OFFSET 19
+#define S_TCB_RX_HDR_OFFSET 14
+#define M_TCB_RX_HDR_OFFSET 0x7ffffffULL
+#define V_TCB_RX_HDR_OFFSET(x) ((x) << S_TCB_RX_HDR_OFFSET)
+
+#define W_TCB_RX_FRAG0_START_IDX_RAW 20
+#define S_TCB_RX_FRAG0_START_IDX_RAW 9
+#define M_TCB_RX_FRAG0_START_IDX_RAW 0x7ffffffULL
+#define V_TCB_RX_FRAG0_START_IDX_RAW(x) ((x) << S_TCB_RX_FRAG0_START_IDX_RAW)
+
+#define W_TCB_RX_FRAG1_START_IDX_OFFSET 21
+#define S_TCB_RX_FRAG1_START_IDX_OFFSET 4
+#define M_TCB_RX_FRAG1_START_IDX_OFFSET 0x7ffffffULL
+#define V_TCB_RX_FRAG1_START_IDX_OFFSET(x) ((x) << S_TCB_RX_FRAG1_START_IDX_OFFSET)
+
+#define W_TCB_RX_FRAG0_LEN 21
+#define S_TCB_RX_FRAG0_LEN 31
+#define M_TCB_RX_FRAG0_LEN 0x7ffffffULL
+#define V_TCB_RX_FRAG0_LEN(x) ((x) << S_TCB_RX_FRAG0_LEN)
+
+#define W_TCB_RX_FRAG1_LEN 22
+#define S_TCB_RX_FRAG1_LEN 26
+#define M_TCB_RX_FRAG1_LEN 0x7ffffffULL
+#define V_TCB_RX_FRAG1_LEN(x) ((x) << S_TCB_RX_FRAG1_LEN)
+
+#define W_TCB_NEWRENO_RECOVER 23
+#define S_TCB_NEWRENO_RECOVER 21
+#define M_TCB_NEWRENO_RECOVER 0x7ffffffULL
+#define V_TCB_NEWRENO_RECOVER(x) ((x) << S_TCB_NEWRENO_RECOVER)
+
+#define W_TCB_PDU_HAVE_LEN 24
+#define S_TCB_PDU_HAVE_LEN 16
+#define M_TCB_PDU_HAVE_LEN 0x1ULL
+#define V_TCB_PDU_HAVE_LEN(x) ((x) << S_TCB_PDU_HAVE_LEN)
+
+#define W_TCB_PDU_LEN 24
+#define S_TCB_PDU_LEN 17
+#define M_TCB_PDU_LEN 0xffffULL
+#define V_TCB_PDU_LEN(x) ((x) << S_TCB_PDU_LEN)
+
+#define W_TCB_RX_QUIESCE 25
+#define S_TCB_RX_QUIESCE 1
+#define M_TCB_RX_QUIESCE 0x1ULL
+#define V_TCB_RX_QUIESCE(x) ((x) << S_TCB_RX_QUIESCE)
+
+#define W_TCB_RX_PTR_RAW 25
+#define S_TCB_RX_PTR_RAW 2
+#define M_TCB_RX_PTR_RAW 0x1ffffULL
+#define V_TCB_RX_PTR_RAW(x) ((x) << S_TCB_RX_PTR_RAW)
+
+#define W_TCB_CPU_NO 25
+#define S_TCB_CPU_NO 19
+#define M_TCB_CPU_NO 0x7fULL
+#define V_TCB_CPU_NO(x) ((x) << S_TCB_CPU_NO)
+
+#define W_TCB_ULP_TYPE 25
+#define S_TCB_ULP_TYPE 26
+#define M_TCB_ULP_TYPE 0xfULL
+#define V_TCB_ULP_TYPE(x) ((x) << S_TCB_ULP_TYPE)
+
+#define W_TCB_RX_FRAG1_PTR_RAW 25
+#define S_TCB_RX_FRAG1_PTR_RAW 30
+#define M_TCB_RX_FRAG1_PTR_RAW 0x1ffffULL
+#define V_TCB_RX_FRAG1_PTR_RAW(x) ((x) << S_TCB_RX_FRAG1_PTR_RAW)
+
+#define W_TCB_RX_FRAG2_START_IDX_OFFSET_RAW 26
+#define S_TCB_RX_FRAG2_START_IDX_OFFSET_RAW 15
+#define M_TCB_RX_FRAG2_START_IDX_OFFSET_RAW 0x7ffffffULL
+#define V_TCB_RX_FRAG2_START_IDX_OFFSET_RAW(x) ((x) << S_TCB_RX_FRAG2_START_IDX_OFFSET_RAW)
+
+#define W_TCB_RX_FRAG2_PTR_RAW 27
+#define S_TCB_RX_FRAG2_PTR_RAW 10
+#define M_TCB_RX_FRAG2_PTR_RAW 0x1ffffULL
+#define V_TCB_RX_FRAG2_PTR_RAW(x) ((x) << S_TCB_RX_FRAG2_PTR_RAW)
+
+#define W_TCB_RX_FRAG2_LEN_RAW 27
+#define S_TCB_RX_FRAG2_LEN_RAW 27
+#define M_TCB_RX_FRAG2_LEN_RAW 0x7ffffffULL
+#define V_TCB_RX_FRAG2_LEN_RAW(x) ((x) << S_TCB_RX_FRAG2_LEN_RAW)
+
+#define W_TCB_RX_FRAG3_PTR_RAW 28
+#define S_TCB_RX_FRAG3_PTR_RAW 22
+#define M_TCB_RX_FRAG3_PTR_RAW 0x1ffffULL
+#define V_TCB_RX_FRAG3_PTR_RAW(x) ((x) << S_TCB_RX_FRAG3_PTR_RAW)
+
+#define W_TCB_RX_FRAG3_LEN_RAW 29
+#define S_TCB_RX_FRAG3_LEN_RAW 7
+#define M_TCB_RX_FRAG3_LEN_RAW 0x7ffffffULL
+#define V_TCB_RX_FRAG3_LEN_RAW(x) ((x) << S_TCB_RX_FRAG3_LEN_RAW)
+
+#define W_TCB_RX_FRAG3_START_IDX_OFFSET_RAW 30
+#define S_TCB_RX_FRAG3_START_IDX_OFFSET_RAW 2
+#define M_TCB_RX_FRAG3_START_IDX_OFFSET_RAW 0x7ffffffULL
+#define V_TCB_RX_FRAG3_START_IDX_OFFSET_RAW(x) ((x) << S_TCB_RX_FRAG3_START_IDX_OFFSET_RAW)
+
+#define W_TCB_PDU_HDR_LEN 30
+#define S_TCB_PDU_HDR_LEN 29
+#define M_TCB_PDU_HDR_LEN 0xffULL
+#define V_TCB_PDU_HDR_LEN(x) ((x) << S_TCB_PDU_HDR_LEN)
+
+#define W_TCB_SLUSH1 31
+#define S_TCB_SLUSH1 5
+#define M_TCB_SLUSH1 0x7ffffULL
+#define V_TCB_SLUSH1(x) ((x) << S_TCB_SLUSH1)
+
+#define W_TCB_ULP_RAW 31
+#define S_TCB_ULP_RAW 24
+#define M_TCB_ULP_RAW 0xffULL
+#define V_TCB_ULP_RAW(x) ((x) << S_TCB_ULP_RAW)
+
+#define W_TCB_DDP_RDMAP_VERSION 25
+#define S_TCB_DDP_RDMAP_VERSION 30
+#define M_TCB_DDP_RDMAP_VERSION 0x1ULL
+#define V_TCB_DDP_RDMAP_VERSION(x) ((x) << S_TCB_DDP_RDMAP_VERSION)
+
+#define W_TCB_MARKER_ENABLE_RX 25
+#define S_TCB_MARKER_ENABLE_RX 31
+#define M_TCB_MARKER_ENABLE_RX 0x1ULL
+#define V_TCB_MARKER_ENABLE_RX(x) ((x) << S_TCB_MARKER_ENABLE_RX)
+
+#define W_TCB_MARKER_ENABLE_TX 26
+#define S_TCB_MARKER_ENABLE_TX 0
+#define M_TCB_MARKER_ENABLE_TX 0x1ULL
+#define V_TCB_MARKER_ENABLE_TX(x) ((x) << S_TCB_MARKER_ENABLE_TX)
+
+#define W_TCB_CRC_ENABLE 26
+#define S_TCB_CRC_ENABLE 1
+#define M_TCB_CRC_ENABLE 0x1ULL
+#define V_TCB_CRC_ENABLE(x) ((x) << S_TCB_CRC_ENABLE)
+
+#define W_TCB_IRS_ULP 26
+#define S_TCB_IRS_ULP 2
+#define M_TCB_IRS_ULP 0x1ffULL
+#define V_TCB_IRS_ULP(x) ((x) << S_TCB_IRS_ULP)
+
+#define W_TCB_ISS_ULP 26
+#define S_TCB_ISS_ULP 11
+#define M_TCB_ISS_ULP 0x1ffULL
+#define V_TCB_ISS_ULP(x) ((x) << S_TCB_ISS_ULP)
+
+#define W_TCB_TX_PDU_LEN 26
+#define S_TCB_TX_PDU_LEN 20
+#define M_TCB_TX_PDU_LEN 0x3fffULL
+#define V_TCB_TX_PDU_LEN(x) ((x) << S_TCB_TX_PDU_LEN)
+
+#define W_TCB_TX_PDU_OUT 27
+#define S_TCB_TX_PDU_OUT 2
+#define M_TCB_TX_PDU_OUT 0x1ULL
+#define V_TCB_TX_PDU_OUT(x) ((x) << S_TCB_TX_PDU_OUT)
+
+#define W_TCB_CQ_IDX_SQ 27
+#define S_TCB_CQ_IDX_SQ 3
+#define M_TCB_CQ_IDX_SQ 0xffffULL
+#define V_TCB_CQ_IDX_SQ(x) ((x) << S_TCB_CQ_IDX_SQ)
+
+#define W_TCB_CQ_IDX_RQ 27
+#define S_TCB_CQ_IDX_RQ 19
+#define M_TCB_CQ_IDX_RQ 0xffffULL
+#define V_TCB_CQ_IDX_RQ(x) ((x) << S_TCB_CQ_IDX_RQ)
+
+#define W_TCB_QP_ID 28
+#define S_TCB_QP_ID 3
+#define M_TCB_QP_ID 0xffffULL
+#define V_TCB_QP_ID(x) ((x) << S_TCB_QP_ID)
+
+#define W_TCB_PD_ID 28
+#define S_TCB_PD_ID 19
+#define M_TCB_PD_ID 0xffffULL
+#define V_TCB_PD_ID(x) ((x) << S_TCB_PD_ID)
+
+#define W_TCB_STAG 29
+#define S_TCB_STAG 3
+#define M_TCB_STAG 0xffffffffULL
+#define V_TCB_STAG(x) ((x) << S_TCB_STAG)
+
+#define W_TCB_RQ_START 30
+#define S_TCB_RQ_START 3
+#define M_TCB_RQ_START 0x3ffffffULL
+#define V_TCB_RQ_START(x) ((x) << S_TCB_RQ_START)
+
+#define W_TCB_RQ_MSN 30
+#define S_TCB_RQ_MSN 29
+#define M_TCB_RQ_MSN 0x3ffULL
+#define V_TCB_RQ_MSN(x) ((x) << S_TCB_RQ_MSN)
+
+#define W_TCB_RQ_MAX_OFFSET 31
+#define S_TCB_RQ_MAX_OFFSET 7
+#define M_TCB_RQ_MAX_OFFSET 0xfULL
+#define V_TCB_RQ_MAX_OFFSET(x) ((x) << S_TCB_RQ_MAX_OFFSET)
+
+#define W_TCB_RQ_WRITE_PTR 31
+#define S_TCB_RQ_WRITE_PTR 11
+#define M_TCB_RQ_WRITE_PTR 0x3ffULL
+#define V_TCB_RQ_WRITE_PTR(x) ((x) << S_TCB_RQ_WRITE_PTR)
+
+#define W_TCB_INB_WRITE_PERM 31
+#define S_TCB_INB_WRITE_PERM 21
+#define M_TCB_INB_WRITE_PERM 0x1ULL
+#define V_TCB_INB_WRITE_PERM(x) ((x) << S_TCB_INB_WRITE_PERM)
+
+#define W_TCB_INB_READ_PERM 31
+#define S_TCB_INB_READ_PERM 22
+#define M_TCB_INB_READ_PERM 0x1ULL
+#define V_TCB_INB_READ_PERM(x) ((x) << S_TCB_INB_READ_PERM)
+
+#define W_TCB_ORD_L_BIT_VLD 31
+#define S_TCB_ORD_L_BIT_VLD 23
+#define M_TCB_ORD_L_BIT_VLD 0x1ULL
+#define V_TCB_ORD_L_BIT_VLD(x) ((x) << S_TCB_ORD_L_BIT_VLD)
+
+#define W_TCB_RDMAP_OPCODE 31
+#define S_TCB_RDMAP_OPCODE 24
+#define M_TCB_RDMAP_OPCODE 0xfULL
+#define V_TCB_RDMAP_OPCODE(x) ((x) << S_TCB_RDMAP_OPCODE)
+
+#define W_TCB_TX_FLUSH 31
+#define S_TCB_TX_FLUSH 28
+#define M_TCB_TX_FLUSH 0x1ULL
+#define V_TCB_TX_FLUSH(x) ((x) << S_TCB_TX_FLUSH)
+
+#define W_TCB_TX_OOS_RXMT 31
+#define S_TCB_TX_OOS_RXMT 29
+#define M_TCB_TX_OOS_RXMT 0x1ULL
+#define V_TCB_TX_OOS_RXMT(x) ((x) << S_TCB_TX_OOS_RXMT)
+
+#define W_TCB_TX_OOS_TXMT 31
+#define S_TCB_TX_OOS_TXMT 30
+#define M_TCB_TX_OOS_TXMT 0x1ULL
+#define V_TCB_TX_OOS_TXMT(x) ((x) << S_TCB_TX_OOS_TXMT)
+
+#define W_TCB_SLUSH_AUX2 31
+#define S_TCB_SLUSH_AUX2 31
+#define M_TCB_SLUSH_AUX2 0x1ULL
+#define V_TCB_SLUSH_AUX2(x) ((x) << S_TCB_SLUSH_AUX2)
+
+#define W_TCB_RX_FRAG1_PTR_RAW2 25
+#define S_TCB_RX_FRAG1_PTR_RAW2 30
+#define M_TCB_RX_FRAG1_PTR_RAW2 0x1ffffULL
+#define V_TCB_RX_FRAG1_PTR_RAW2(x) ((x) << S_TCB_RX_FRAG1_PTR_RAW2)
+
+#define W_TCB_RX_DDP_FLAGS 26
+#define S_TCB_RX_DDP_FLAGS 15
+#define M_TCB_RX_DDP_FLAGS 0x3ffULL
+#define V_TCB_RX_DDP_FLAGS(x) ((x) << S_TCB_RX_DDP_FLAGS)
+
+#define W_TCB_SLUSH_AUX3 26
+#define S_TCB_SLUSH_AUX3 31
+#define M_TCB_SLUSH_AUX3 0x1ffULL
+#define V_TCB_SLUSH_AUX3(x) ((x) << S_TCB_SLUSH_AUX3)
+
+#define W_TCB_RX_DDP_BUF0_OFFSET 27
+#define S_TCB_RX_DDP_BUF0_OFFSET 8
+#define M_TCB_RX_DDP_BUF0_OFFSET 0x3fffffULL
+#define V_TCB_RX_DDP_BUF0_OFFSET(x) ((x) << S_TCB_RX_DDP_BUF0_OFFSET)
+
+#define W_TCB_RX_DDP_BUF0_LEN 27
+#define S_TCB_RX_DDP_BUF0_LEN 30
+#define M_TCB_RX_DDP_BUF0_LEN 0x3fffffULL
+#define V_TCB_RX_DDP_BUF0_LEN(x) ((x) << S_TCB_RX_DDP_BUF0_LEN)
+
+#define W_TCB_RX_DDP_BUF1_OFFSET 28
+#define S_TCB_RX_DDP_BUF1_OFFSET 20
+#define M_TCB_RX_DDP_BUF1_OFFSET 0x3fffffULL
+#define V_TCB_RX_DDP_BUF1_OFFSET(x) ((x) << S_TCB_RX_DDP_BUF1_OFFSET)
+
+#define W_TCB_RX_DDP_BUF1_LEN 29
+#define S_TCB_RX_DDP_BUF1_LEN 10
+#define M_TCB_RX_DDP_BUF1_LEN 0x3fffffULL
+#define V_TCB_RX_DDP_BUF1_LEN(x) ((x) << S_TCB_RX_DDP_BUF1_LEN)
+
+#define W_TCB_RX_DDP_BUF0_TAG 30
+#define S_TCB_RX_DDP_BUF0_TAG 0
+#define M_TCB_RX_DDP_BUF0_TAG 0xffffffffULL
+#define V_TCB_RX_DDP_BUF0_TAG(x) ((x) << S_TCB_RX_DDP_BUF0_TAG)
+
+#define W_TCB_RX_DDP_BUF1_TAG 31
+#define S_TCB_RX_DDP_BUF1_TAG 0
+#define M_TCB_RX_DDP_BUF1_TAG 0xffffffffULL
+#define V_TCB_RX_DDP_BUF1_TAG(x) ((x) << S_TCB_RX_DDP_BUF1_TAG)
+
+#define S_TF_DACK 10
+#define V_TF_DACK(x) ((x) << S_TF_DACK)
+
+#define S_TF_NAGLE 11
+#define V_TF_NAGLE(x) ((x) << S_TF_NAGLE)
+
+#define S_TF_RECV_SCALE 12
+#define V_TF_RECV_SCALE(x) ((x) << S_TF_RECV_SCALE)
+
+#define S_TF_RECV_TSTMP 13
+#define V_TF_RECV_TSTMP(x) ((x) << S_TF_RECV_TSTMP)
+
+#define S_TF_RECV_SACK 14
+#define V_TF_RECV_SACK(x) ((x) << S_TF_RECV_SACK)
+
+#define S_TF_TURBO 15
+#define V_TF_TURBO(x) ((x) << S_TF_TURBO)
+
+#define S_TF_KEEPALIVE 16
+#define V_TF_KEEPALIVE(x) ((x) << S_TF_KEEPALIVE)
+
+#define S_TF_TCAM_BYPASS 17
+#define V_TF_TCAM_BYPASS(x) ((x) << S_TF_TCAM_BYPASS)
+
+#define S_TF_CORE_FIN 18
+#define V_TF_CORE_FIN(x) ((x) << S_TF_CORE_FIN)
+
+#define S_TF_CORE_MORE 19
+#define V_TF_CORE_MORE(x) ((x) << S_TF_CORE_MORE)
+
+#define S_TF_MIGRATING 20
+#define V_TF_MIGRATING(x) ((x) << S_TF_MIGRATING)
+
+#define S_TF_ACTIVE_OPEN 21
+#define V_TF_ACTIVE_OPEN(x) ((x) << S_TF_ACTIVE_OPEN)
+
+#define S_TF_ASK_MODE 22
+#define V_TF_ASK_MODE(x) ((x) << S_TF_ASK_MODE)
+
+#define S_TF_NON_OFFLOAD 23
+#define V_TF_NON_OFFLOAD(x) ((x) << S_TF_NON_OFFLOAD)
+
+#define S_TF_MOD_SCHD 24
+#define V_TF_MOD_SCHD(x) ((x) << S_TF_MOD_SCHD)
+
+#define S_TF_MOD_SCHD_REASON0 25
+#define V_TF_MOD_SCHD_REASON0(x) ((x) << S_TF_MOD_SCHD_REASON0)
+
+#define S_TF_MOD_SCHD_REASON1 26
+#define V_TF_MOD_SCHD_REASON1(x) ((x) << S_TF_MOD_SCHD_REASON1)
+
+#define S_TF_MOD_SCHD_RX 27
+#define V_TF_MOD_SCHD_RX(x) ((x) << S_TF_MOD_SCHD_RX)
+
+#define S_TF_CORE_PUSH 28
+#define V_TF_CORE_PUSH(x) ((x) << S_TF_CORE_PUSH)
+
+#define S_TF_RCV_COALESCE_ENABLE 29
+#define V_TF_RCV_COALESCE_ENABLE(x) ((x) << S_TF_RCV_COALESCE_ENABLE)
+
+#define S_TF_RCV_COALESCE_PUSH 30
+#define V_TF_RCV_COALESCE_PUSH(x) ((x) << S_TF_RCV_COALESCE_PUSH)
+
+#define S_TF_RCV_COALESCE_LAST_PSH 31
+#define V_TF_RCV_COALESCE_LAST_PSH(x) ((x) << S_TF_RCV_COALESCE_LAST_PSH)
+
+#define S_TF_RCV_COALESCE_HEARTBEAT 32
+#define V_TF_RCV_COALESCE_HEARTBEAT(x) ((x) << S_TF_RCV_COALESCE_HEARTBEAT)
+
+#define S_TF_HALF_CLOSE 33
+#define V_TF_HALF_CLOSE(x) ((x) << S_TF_HALF_CLOSE)
+
+#define S_TF_DACK_MSS 34
+#define V_TF_DACK_MSS(x) ((x) << S_TF_DACK_MSS)
+
+#define S_TF_CCTRL_SEL0 35
+#define V_TF_CCTRL_SEL0(x) ((x) << S_TF_CCTRL_SEL0)
+
+#define S_TF_CCTRL_SEL1 36
+#define V_TF_CCTRL_SEL1(x) ((x) << S_TF_CCTRL_SEL1)
+
+#define S_TF_TCP_NEWRENO_FAST_RECOVERY 37
+#define V_TF_TCP_NEWRENO_FAST_RECOVERY(x) ((x) << S_TF_TCP_NEWRENO_FAST_RECOVERY)
+
+#define S_TF_TX_PACE_AUTO 38
+#define V_TF_TX_PACE_AUTO(x) ((x) << S_TF_TX_PACE_AUTO)
+
+#define S_TF_PEER_FIN_HELD 39
+#define V_TF_PEER_FIN_HELD(x) ((x) << S_TF_PEER_FIN_HELD)
+
+#define S_TF_CORE_URG 40
+#define V_TF_CORE_URG(x) ((x) << S_TF_CORE_URG)
+
+#define S_TF_RDMA_ERROR 41
+#define V_TF_RDMA_ERROR(x) ((x) << S_TF_RDMA_ERROR)
+
+#define S_TF_SSWS_DISABLED 42
+#define V_TF_SSWS_DISABLED(x) ((x) << S_TF_SSWS_DISABLED)
+
+#define S_TF_DUPACK_COUNT_ODD 43
+#define V_TF_DUPACK_COUNT_ODD(x) ((x) << S_TF_DUPACK_COUNT_ODD)
+
+#define S_TF_TX_CHANNEL 44
+#define V_TF_TX_CHANNEL(x) ((x) << S_TF_TX_CHANNEL)
+
+#define S_TF_RX_CHANNEL 45
+#define V_TF_RX_CHANNEL(x) ((x) << S_TF_RX_CHANNEL)
+
+#define S_TF_TX_PACE_FIXED 46
+#define V_TF_TX_PACE_FIXED(x) ((x) << S_TF_TX_PACE_FIXED)
+
+#define S_TF_RDMA_FLM_ERROR 47
+#define V_TF_RDMA_FLM_ERROR(x) ((x) << S_TF_RDMA_FLM_ERROR)
+
+#define S_TF_RX_FLOW_CONTROL_DISABLE 48
+#define V_TF_RX_FLOW_CONTROL_DISABLE(x) ((x) << S_TF_RX_FLOW_CONTROL_DISABLE)
+
+#endif /* _TCB_DEFS_H */
diff --git a/drivers/infiniband/hw/ehca/Kconfig b/drivers/infiniband/hw/ehca/Kconfig
index 727b10d8968..1a854598e0e 100644
--- a/drivers/infiniband/hw/ehca/Kconfig
+++ b/drivers/infiniband/hw/ehca/Kconfig
@@ -7,11 +7,3 @@ config INFINIBAND_EHCA
To compile the driver as a module, choose M here. The module
will be called ib_ehca.
-config INFINIBAND_EHCA_SCALING
- bool "Scaling support (EXPERIMENTAL)"
- depends on IBMEBUS && INFINIBAND_EHCA && HOTPLUG_CPU && EXPERIMENTAL
- default y
- ---help---
- eHCA scaling support schedules the CQ callbacks to different CPUs.
-
- To enable this feature choose Y here.
diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h
index 1c722032319..40404c9e281 100644
--- a/drivers/infiniband/hw/ehca/ehca_classes.h
+++ b/drivers/infiniband/hw/ehca/ehca_classes.h
@@ -42,8 +42,6 @@
#ifndef __EHCA_CLASSES_H__
#define __EHCA_CLASSES_H__
-#include "ehca_classes.h"
-#include "ipz_pt_fn.h"
struct ehca_module;
struct ehca_qp;
@@ -54,14 +52,22 @@ struct ehca_mw;
struct ehca_pd;
struct ehca_av;
+#include <rdma/ib_verbs.h>
+#include <rdma/ib_user_verbs.h>
+
#ifdef CONFIG_PPC64
#include "ehca_classes_pSeries.h"
#endif
+#include "ipz_pt_fn.h"
+#include "ehca_qes.h"
+#include "ehca_irq.h"
-#include <rdma/ib_verbs.h>
-#include <rdma/ib_user_verbs.h>
+#define EHCA_EQE_CACHE_SIZE 20
-#include "ehca_irq.h"
+struct ehca_eqe_cache_entry {
+ struct ehca_eqe *eqe;
+ struct ehca_cq *cq;
+};
struct ehca_eq {
u32 length;
@@ -74,6 +80,8 @@ struct ehca_eq {
spinlock_t spinlock;
struct tasklet_struct interrupt_task;
u32 ist;
+ spinlock_t irq_spinlock;
+ struct ehca_eqe_cache_entry eqe_cache[EHCA_EQE_CACHE_SIZE];
};
struct ehca_sport {
@@ -119,13 +127,14 @@ struct ehca_qp {
struct ipz_qp_handle ipz_qp_handle;
struct ehca_pfqp pf;
struct ib_qp_init_attr init_attr;
- u64 uspace_squeue;
- u64 uspace_rqueue;
- u64 uspace_fwh;
struct ehca_cq *send_cq;
struct ehca_cq *recv_cq;
unsigned int sqerr_purgeflag;
struct hlist_node list_entries;
+ /* mmap counter for resources mapped into user space */
+ u32 mm_count_squeue;
+ u32 mm_count_rqueue;
+ u32 mm_count_galpa;
};
/* must be power of 2 */
@@ -142,13 +151,14 @@ struct ehca_cq {
struct ipz_cq_handle ipz_cq_handle;
struct ehca_pfcq pf;
spinlock_t cb_lock;
- u64 uspace_queue;
- u64 uspace_fwh;
struct hlist_head qp_hashtab[QP_HASHTAB_LEN];
struct list_head entry;
u32 nr_callbacks;
spinlock_t task_lock;
u32 ownpid;
+ /* mmap counter for resources mapped into user space */
+ u32 mm_count_queue;
+ u32 mm_count_galpa;
};
enum ehca_mr_flag {
@@ -248,20 +258,6 @@ struct ehca_ucontext {
struct ib_ucontext ib_ucontext;
};
-struct ehca_module *ehca_module_new(void);
-
-int ehca_module_delete(struct ehca_module *me);
-
-int ehca_eq_ctor(struct ehca_eq *eq);
-
-int ehca_eq_dtor(struct ehca_eq *eq);
-
-struct ehca_shca *ehca_shca_new(void);
-
-int ehca_shca_delete(struct ehca_shca *me);
-
-struct ehca_sport *ehca_sport_new(struct ehca_shca *anchor);
-
int ehca_init_pd_cache(void);
void ehca_cleanup_pd_cache(void);
int ehca_init_cq_cache(void);
@@ -281,9 +277,9 @@ extern struct idr ehca_cq_idr;
extern int ehca_static_rate;
extern int ehca_port_act_time;
extern int ehca_use_hp_mr;
+extern int ehca_scaling_code;
struct ipzu_queue_resp {
- u64 queue; /* points to first queue entry */
u32 qe_size; /* queue entry size */
u32 act_nr_of_sg;
u32 queue_length; /* queue length allocated in bytes */
@@ -296,7 +292,6 @@ struct ehca_create_cq_resp {
u32 cq_number;
u32 token;
struct ipzu_queue_resp ipz_queue;
- struct h_galpas galpas;
};
struct ehca_create_qp_resp {
@@ -309,7 +304,6 @@ struct ehca_create_qp_resp {
u32 dummy; /* padding for 8 byte alignment */
struct ipzu_queue_resp ipz_squeue;
struct ipzu_queue_resp ipz_rqueue;
- struct h_galpas galpas;
};
struct ehca_alloc_cq_parms {
diff --git a/drivers/infiniband/hw/ehca/ehca_cq.c b/drivers/infiniband/hw/ehca/ehca_cq.c
index 6074c897f51..6ebfa27e4e1 100644
--- a/drivers/infiniband/hw/ehca/ehca_cq.c
+++ b/drivers/infiniband/hw/ehca/ehca_cq.c
@@ -134,14 +134,13 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe,
if (cqe >= 0xFFFFFFFF - 64 - additional_cqe)
return ERR_PTR(-EINVAL);
- my_cq = kmem_cache_alloc(cq_cache, GFP_KERNEL);
+ my_cq = kmem_cache_zalloc(cq_cache, GFP_KERNEL);
if (!my_cq) {
ehca_err(device, "Out of memory for ehca_cq struct device=%p",
device);
return ERR_PTR(-ENOMEM);
}
- memset(my_cq, 0, sizeof(struct ehca_cq));
memset(&param, 0, sizeof(struct ehca_alloc_cq_parms));
spin_lock_init(&my_cq->spinlock);
@@ -267,7 +266,6 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe,
if (context) {
struct ipz_queue *ipz_queue = &my_cq->ipz_queue;
struct ehca_create_cq_resp resp;
- struct vm_area_struct *vma;
memset(&resp, 0, sizeof(resp));
resp.cq_number = my_cq->cq_number;
resp.token = my_cq->token;
@@ -276,40 +274,14 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe,
resp.ipz_queue.queue_length = ipz_queue->queue_length;
resp.ipz_queue.pagesize = ipz_queue->pagesize;
resp.ipz_queue.toggle_state = ipz_queue->toggle_state;
- ret = ehca_mmap_nopage(((u64)(my_cq->token) << 32) | 0x12000000,
- ipz_queue->queue_length,
- (void**)&resp.ipz_queue.queue,
- &vma);
- if (ret) {
- ehca_err(device, "Could not mmap queue pages");
- cq = ERR_PTR(ret);
- goto create_cq_exit4;
- }
- my_cq->uspace_queue = resp.ipz_queue.queue;
- resp.galpas = my_cq->galpas;
- ret = ehca_mmap_register(my_cq->galpas.user.fw_handle,
- (void**)&resp.galpas.kernel.fw_handle,
- &vma);
- if (ret) {
- ehca_err(device, "Could not mmap fw_handle");
- cq = ERR_PTR(ret);
- goto create_cq_exit5;
- }
- my_cq->uspace_fwh = (u64)resp.galpas.kernel.fw_handle;
if (ib_copy_to_udata(udata, &resp, sizeof(resp))) {
ehca_err(device, "Copy to udata failed.");
- goto create_cq_exit6;
+ goto create_cq_exit4;
}
}
return cq;
-create_cq_exit6:
- ehca_munmap(my_cq->uspace_fwh, EHCA_PAGESIZE);
-
-create_cq_exit5:
- ehca_munmap(my_cq->uspace_queue, my_cq->ipz_queue.queue_length);
-
create_cq_exit4:
ipz_queue_dtor(&my_cq->ipz_queue);
@@ -333,7 +305,6 @@ create_cq_exit1:
int ehca_destroy_cq(struct ib_cq *cq)
{
u64 h_ret;
- int ret;
struct ehca_cq *my_cq = container_of(cq, struct ehca_cq, ib_cq);
int cq_num = my_cq->cq_number;
struct ib_device *device = cq->device;
@@ -343,6 +314,20 @@ int ehca_destroy_cq(struct ib_cq *cq)
u32 cur_pid = current->tgid;
unsigned long flags;
+ if (cq->uobject) {
+ if (my_cq->mm_count_galpa || my_cq->mm_count_queue) {
+ ehca_err(device, "Resources still referenced in "
+ "user space cq_num=%x", my_cq->cq_number);
+ return -EINVAL;
+ }
+ if (my_cq->ownpid != cur_pid) {
+ ehca_err(device, "Invalid caller pid=%x ownpid=%x "
+ "cq_num=%x",
+ cur_pid, my_cq->ownpid, my_cq->cq_number);
+ return -EINVAL;
+ }
+ }
+
spin_lock_irqsave(&ehca_cq_idr_lock, flags);
while (my_cq->nr_callbacks) {
spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
@@ -353,25 +338,6 @@ int ehca_destroy_cq(struct ib_cq *cq)
idr_remove(&ehca_cq_idr, my_cq->token);
spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
- if (my_cq->uspace_queue && my_cq->ownpid != cur_pid) {
- ehca_err(device, "Invalid caller pid=%x ownpid=%x",
- cur_pid, my_cq->ownpid);
- return -EINVAL;
- }
-
- /* un-mmap if vma alloc */
- if (my_cq->uspace_queue ) {
- ret = ehca_munmap(my_cq->uspace_queue,
- my_cq->ipz_queue.queue_length);
- if (ret)
- ehca_err(device, "Could not munmap queue ehca_cq=%p "
- "cq_num=%x", my_cq, cq_num);
- ret = ehca_munmap(my_cq->uspace_fwh, EHCA_PAGESIZE);
- if (ret)
- ehca_err(device, "Could not munmap fwh ehca_cq=%p "
- "cq_num=%x", my_cq, cq_num);
- }
-
h_ret = hipz_h_destroy_cq(adapter_handle, my_cq, 0);
if (h_ret == H_R_STATE) {
/* cq in err: read err data and destroy it forcibly */
@@ -400,7 +366,7 @@ int ehca_resize_cq(struct ib_cq *cq, int cqe, struct ib_udata *udata)
struct ehca_cq *my_cq = container_of(cq, struct ehca_cq, ib_cq);
u32 cur_pid = current->tgid;
- if (my_cq->uspace_queue && my_cq->ownpid != cur_pid) {
+ if (cq->uobject && my_cq->ownpid != cur_pid) {
ehca_err(cq->device, "Invalid caller pid=%x ownpid=%x",
cur_pid, my_cq->ownpid);
return -EINVAL;
diff --git a/drivers/infiniband/hw/ehca/ehca_eq.c b/drivers/infiniband/hw/ehca/ehca_eq.c
index 5281dec66f1..4961eb88827 100644
--- a/drivers/infiniband/hw/ehca/ehca_eq.c
+++ b/drivers/infiniband/hw/ehca/ehca_eq.c
@@ -61,6 +61,7 @@ int ehca_create_eq(struct ehca_shca *shca,
struct ib_device *ib_dev = &shca->ib_device;
spin_lock_init(&eq->spinlock);
+ spin_lock_init(&eq->irq_spinlock);
eq->is_initialized = 0;
if (type != EHCA_EQ && type != EHCA_NEQ) {
@@ -122,7 +123,7 @@ int ehca_create_eq(struct ehca_shca *shca,
/* register interrupt handlers and initialize work queues */
if (type == EHCA_EQ) {
ret = ibmebus_request_irq(NULL, eq->ist, ehca_interrupt_eq,
- SA_INTERRUPT, "ehca_eq",
+ IRQF_DISABLED, "ehca_eq",
(void *)shca);
if (ret < 0)
ehca_err(ib_dev, "Can't map interrupt handler.");
@@ -130,7 +131,7 @@ int ehca_create_eq(struct ehca_shca *shca,
tasklet_init(&eq->interrupt_task, ehca_tasklet_eq, (long)shca);
} else if (type == EHCA_NEQ) {
ret = ibmebus_request_irq(NULL, eq->ist, ehca_interrupt_neq,
- SA_INTERRUPT, "ehca_neq",
+ IRQF_DISABLED, "ehca_neq",
(void *)shca);
if (ret < 0)
ehca_err(ib_dev, "Can't map interrupt handler.");
diff --git a/drivers/infiniband/hw/ehca/ehca_hca.c b/drivers/infiniband/hw/ehca/ehca_hca.c
index b7be950ab47..30eb45df9f0 100644
--- a/drivers/infiniband/hw/ehca/ehca_hca.c
+++ b/drivers/infiniband/hw/ehca/ehca_hca.c
@@ -162,6 +162,9 @@ int ehca_query_port(struct ib_device *ibdev,
props->active_width = IB_WIDTH_12X;
props->active_speed = 0x1;
+ /* at the moment (logical) link state is always LINK_UP */
+ props->phys_state = 0x5;
+
query_port1:
ehca_free_fw_ctrlblock(rblock);
diff --git a/drivers/infiniband/hw/ehca/ehca_irq.c b/drivers/infiniband/hw/ehca/ehca_irq.c
index c069be8cbcb..3ec53c687d0 100644
--- a/drivers/infiniband/hw/ehca/ehca_irq.c
+++ b/drivers/infiniband/hw/ehca/ehca_irq.c
@@ -63,15 +63,11 @@
#define ERROR_DATA_LENGTH EHCA_BMASK_IBM(52,63)
#define ERROR_DATA_TYPE EHCA_BMASK_IBM(0,7)
-#ifdef CONFIG_INFINIBAND_EHCA_SCALING
-
static void queue_comp_task(struct ehca_cq *__cq);
static struct ehca_comp_pool* pool;
static struct notifier_block comp_pool_callback_nb;
-#endif
-
static inline void comp_event_callback(struct ehca_cq *cq)
{
if (!cq->ib_cq.comp_handler)
@@ -206,7 +202,7 @@ static void qp_event_callback(struct ehca_shca *shca,
}
static void cq_event_callback(struct ehca_shca *shca,
- u64 eqe)
+ u64 eqe)
{
struct ehca_cq *cq;
unsigned long flags;
@@ -318,7 +314,7 @@ static void parse_ec(struct ehca_shca *shca, u64 eqe)
"disruptive port %x configuration change", port);
ehca_info(&shca->ib_device,
- "port %x is inactive.", port);
+ "port %x is inactive.", port);
event.device = &shca->ib_device;
event.event = IB_EVENT_PORT_ERR;
event.element.port_num = port;
@@ -326,7 +322,7 @@ static void parse_ec(struct ehca_shca *shca, u64 eqe)
ib_dispatch_event(&event);
ehca_info(&shca->ib_device,
- "port %x is active.", port);
+ "port %x is active.", port);
event.device = &shca->ib_device;
event.event = IB_EVENT_PORT_ACTIVE;
event.element.port_num = port;
@@ -401,115 +397,170 @@ irqreturn_t ehca_interrupt_eq(int irq, void *dev_id)
return IRQ_HANDLED;
}
-void ehca_tasklet_eq(unsigned long data)
-{
- struct ehca_shca *shca = (struct ehca_shca*)data;
- struct ehca_eqe *eqe;
- int int_state;
- int query_cnt = 0;
- do {
- eqe = (struct ehca_eqe *)ehca_poll_eq(shca, &shca->eq);
+static inline void process_eqe(struct ehca_shca *shca, struct ehca_eqe *eqe)
+{
+ u64 eqe_value;
+ u32 token;
+ unsigned long flags;
+ struct ehca_cq *cq;
+ eqe_value = eqe->entry;
+ ehca_dbg(&shca->ib_device, "eqe_value=%lx", eqe_value);
+ if (EHCA_BMASK_GET(EQE_COMPLETION_EVENT, eqe_value)) {
+ ehca_dbg(&shca->ib_device, "... completion event");
+ token = EHCA_BMASK_GET(EQE_CQ_TOKEN, eqe_value);
+ spin_lock_irqsave(&ehca_cq_idr_lock, flags);
+ cq = idr_find(&ehca_cq_idr, token);
+ if (cq == NULL) {
+ spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
+ ehca_err(&shca->ib_device,
+ "Invalid eqe for non-existing cq token=%x",
+ token);
+ return;
+ }
+ reset_eq_pending(cq);
+ if (ehca_scaling_code) {
+ queue_comp_task(cq);
+ spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
+ } else {
+ spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
+ comp_event_callback(cq);
+ }
+ } else {
+ ehca_dbg(&shca->ib_device,
+ "Got non completion event");
+ parse_identifier(shca, eqe_value);
+ }
+}
- if ((shca->hw_level >= 2) && eqe)
- int_state = 1;
- else
- int_state = 0;
-
- while ((int_state == 1) || eqe) {
- while (eqe) {
- u64 eqe_value = eqe->entry;
-
- ehca_dbg(&shca->ib_device,
- "eqe_value=%lx", eqe_value);
-
- /* TODO: better structure */
- if (EHCA_BMASK_GET(EQE_COMPLETION_EVENT,
- eqe_value)) {
- unsigned long flags;
- u32 token;
- struct ehca_cq *cq;
-
- ehca_dbg(&shca->ib_device,
- "... completion event");
- token =
- EHCA_BMASK_GET(EQE_CQ_TOKEN,
- eqe_value);
- spin_lock_irqsave(&ehca_cq_idr_lock,
- flags);
- cq = idr_find(&ehca_cq_idr, token);
-
- if (cq == NULL) {
- spin_unlock_irqrestore(&ehca_cq_idr_lock,
- flags);
- break;
- }
-
- reset_eq_pending(cq);
-#ifdef CONFIG_INFINIBAND_EHCA_SCALING
- queue_comp_task(cq);
- spin_unlock_irqrestore(&ehca_cq_idr_lock,
- flags);
-#else
- spin_unlock_irqrestore(&ehca_cq_idr_lock,
- flags);
- comp_event_callback(cq);
-#endif
- } else {
- ehca_dbg(&shca->ib_device,
- "... non completion event");
- parse_identifier(shca, eqe_value);
- }
- eqe =
- (struct ehca_eqe *)ehca_poll_eq(shca,
- &shca->eq);
- }
+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;
+ unsigned long flags;
+ int eqe_cnt, i;
+ int eq_empty = 0;
+
+ spin_lock_irqsave(&eq->irq_spinlock, flags);
+ if (is_irq) {
+ const int max_query_cnt = 100;
+ int query_cnt = 0;
+ int int_state = 1;
+ do {
+ int_state = hipz_h_query_int_state(
+ shca->ipz_hca_handle, eq->ist);
+ query_cnt++;
+ iosync();
+ } while (int_state && query_cnt < max_query_cnt);
+ if (unlikely((query_cnt == max_query_cnt)))
+ ehca_dbg(&shca->ib_device, "int_state=%x query_cnt=%x",
+ int_state, query_cnt);
+ }
- if (shca->hw_level >= 2) {
- int_state =
- hipz_h_query_int_state(shca->ipz_hca_handle,
- shca->eq.ist);
- query_cnt++;
- iosync();
- if (query_cnt >= 100) {
- query_cnt = 0;
- int_state = 0;
- }
+ /* read out all eqes */
+ eqe_cnt = 0;
+ do {
+ u32 token;
+ eqe_cache[eqe_cnt].eqe =
+ (struct ehca_eqe *)ehca_poll_eq(shca, eq);
+ if (!eqe_cache[eqe_cnt].eqe)
+ break;
+ eqe_value = eqe_cache[eqe_cnt].eqe->entry;
+ if (EHCA_BMASK_GET(EQE_COMPLETION_EVENT, eqe_value)) {
+ token = EHCA_BMASK_GET(EQE_CQ_TOKEN, eqe_value);
+ spin_lock(&ehca_cq_idr_lock);
+ eqe_cache[eqe_cnt].cq = idr_find(&ehca_cq_idr, token);
+ if (!eqe_cache[eqe_cnt].cq) {
+ spin_unlock(&ehca_cq_idr_lock);
+ ehca_err(&shca->ib_device,
+ "Invalid eqe for non-existing cq "
+ "token=%x", token);
+ continue;
}
- eqe = (struct ehca_eqe *)ehca_poll_eq(shca, &shca->eq);
-
+ spin_unlock(&ehca_cq_idr_lock);
+ } else
+ eqe_cache[eqe_cnt].cq = NULL;
+ eqe_cnt++;
+ } while (eqe_cnt < EHCA_EQE_CACHE_SIZE);
+ if (!eqe_cnt) {
+ if (is_irq)
+ ehca_dbg(&shca->ib_device,
+ "No eqe found for irq event");
+ goto unlock_irq_spinlock;
+ } else if (!is_irq)
+ ehca_dbg(&shca->ib_device, "deadman found %x eqe", eqe_cnt);
+ if (unlikely(eqe_cnt == EHCA_EQE_CACHE_SIZE))
+ ehca_dbg(&shca->ib_device, "too many eqes for one irq event");
+ /* enable irq for new packets */
+ for (i = 0; i < eqe_cnt; i++) {
+ if (eq->eqe_cache[i].cq)
+ reset_eq_pending(eq->eqe_cache[i].cq);
+ }
+ /* check eq */
+ spin_lock(&eq->spinlock);
+ eq_empty = (!ipz_eqit_eq_peek_valid(&shca->eq.ipz_queue));
+ spin_unlock(&eq->spinlock);
+ /* call completion handler for cached eqes */
+ for (i = 0; i < eqe_cnt; i++)
+ if (eq->eqe_cache[i].cq) {
+ if (ehca_scaling_code) {
+ spin_lock(&ehca_cq_idr_lock);
+ queue_comp_task(eq->eqe_cache[i].cq);
+ spin_unlock(&ehca_cq_idr_lock);
+ } else
+ comp_event_callback(eq->eqe_cache[i].cq);
+ } else {
+ ehca_dbg(&shca->ib_device, "Got non completion event");
+ parse_identifier(shca, eq->eqe_cache[i].eqe->entry);
}
- } while (int_state != 0);
-
- return;
+ /* poll eq if not empty */
+ if (eq_empty)
+ goto unlock_irq_spinlock;
+ do {
+ struct ehca_eqe *eqe;
+ eqe = (struct ehca_eqe *)ehca_poll_eq(shca, &shca->eq);
+ if (!eqe)
+ break;
+ process_eqe(shca, eqe);
+ eqe_cnt++;
+ } while (1);
+
+unlock_irq_spinlock:
+ spin_unlock_irqrestore(&eq->irq_spinlock, flags);
}
-#ifdef CONFIG_INFINIBAND_EHCA_SCALING
+void ehca_tasklet_eq(unsigned long data)
+{
+ ehca_process_eq((struct ehca_shca*)data, 1);
+}
static inline int find_next_online_cpu(struct ehca_comp_pool* pool)
{
- unsigned long flags_last_cpu;
+ int cpu;
+ unsigned long flags;
+ WARN_ON_ONCE(!in_interrupt());
if (ehca_debug_level)
ehca_dmp(&cpu_online_map, sizeof(cpumask_t), "");
- spin_lock_irqsave(&pool->last_cpu_lock, flags_last_cpu);
- pool->last_cpu = next_cpu(pool->last_cpu, cpu_online_map);
- if (pool->last_cpu == NR_CPUS)
- pool->last_cpu = first_cpu(cpu_online_map);
- spin_unlock_irqrestore(&pool->last_cpu_lock, flags_last_cpu);
+ spin_lock_irqsave(&pool->last_cpu_lock, flags);
+ cpu = next_cpu(pool->last_cpu, cpu_online_map);
+ if (cpu == NR_CPUS)
+ cpu = first_cpu(cpu_online_map);
+ pool->last_cpu = cpu;
+ spin_unlock_irqrestore(&pool->last_cpu_lock, flags);
- return pool->last_cpu;
+ return cpu;
}
static void __queue_comp_task(struct ehca_cq *__cq,
struct ehca_cpu_comp_task *cct)
{
- unsigned long flags_cct;
- unsigned long flags_cq;
+ unsigned long flags;
- spin_lock_irqsave(&cct->task_lock, flags_cct);
- spin_lock_irqsave(&__cq->task_lock, flags_cq);
+ spin_lock_irqsave(&cct->task_lock, flags);
+ spin_lock(&__cq->task_lock);
if (__cq->nr_callbacks == 0) {
__cq->nr_callbacks++;
@@ -520,8 +571,8 @@ static void __queue_comp_task(struct ehca_cq *__cq,
else
__cq->nr_callbacks++;
- spin_unlock_irqrestore(&__cq->task_lock, flags_cq);
- spin_unlock_irqrestore(&cct->task_lock, flags_cct);
+ spin_unlock(&__cq->task_lock);
+ spin_unlock_irqrestore(&cct->task_lock, flags);
}
static void queue_comp_task(struct ehca_cq *__cq)
@@ -532,69 +583,69 @@ static void queue_comp_task(struct ehca_cq *__cq)
cpu = get_cpu();
cpu_id = find_next_online_cpu(pool);
-
BUG_ON(!cpu_online(cpu_id));
cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu_id);
+ BUG_ON(!cct);
if (cct->cq_jobs > 0) {
cpu_id = find_next_online_cpu(pool);
cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu_id);
+ BUG_ON(!cct);
}
__queue_comp_task(__cq, cct);
-
- put_cpu();
-
- return;
}
static void run_comp_task(struct ehca_cpu_comp_task* cct)
{
struct ehca_cq *cq;
- unsigned long flags_cct;
- unsigned long flags_cq;
+ unsigned long flags;
- spin_lock_irqsave(&cct->task_lock, flags_cct);
+ spin_lock_irqsave(&cct->task_lock, flags);
while (!list_empty(&cct->cq_list)) {
cq = list_entry(cct->cq_list.next, struct ehca_cq, entry);
- spin_unlock_irqrestore(&cct->task_lock, flags_cct);
+ spin_unlock_irqrestore(&cct->task_lock, flags);
comp_event_callback(cq);
- spin_lock_irqsave(&cct->task_lock, flags_cct);
+ spin_lock_irqsave(&cct->task_lock, flags);
- spin_lock_irqsave(&cq->task_lock, flags_cq);
+ spin_lock(&cq->task_lock);
cq->nr_callbacks--;
if (cq->nr_callbacks == 0) {
list_del_init(cct->cq_list.next);
cct->cq_jobs--;
}
- spin_unlock_irqrestore(&cq->task_lock, flags_cq);
-
+ spin_unlock(&cq->task_lock);
}
- spin_unlock_irqrestore(&cct->task_lock, flags_cct);
-
- return;
+ spin_unlock_irqrestore(&cct->task_lock, flags);
}
static int comp_task(void *__cct)
{
struct ehca_cpu_comp_task* cct = __cct;
+ int cql_empty;
DECLARE_WAITQUEUE(wait, current);
set_current_state(TASK_INTERRUPTIBLE);
while(!kthread_should_stop()) {
add_wait_queue(&cct->wait_queue, &wait);
- if (list_empty(&cct->cq_list))
+ spin_lock_irq(&cct->task_lock);
+ cql_empty = list_empty(&cct->cq_list);
+ spin_unlock_irq(&cct->task_lock);
+ if (cql_empty)
schedule();
else
__set_current_state(TASK_RUNNING);
remove_wait_queue(&cct->wait_queue, &wait);
- if (!list_empty(&cct->cq_list))
+ spin_lock_irq(&cct->task_lock);
+ cql_empty = list_empty(&cct->cq_list);
+ spin_unlock_irq(&cct->task_lock);
+ if (!cql_empty)
run_comp_task(__cct);
set_current_state(TASK_INTERRUPTIBLE);
@@ -637,8 +688,6 @@ static void destroy_comp_task(struct ehca_comp_pool *pool,
if (task)
kthread_stop(task);
-
- return;
}
static void take_over_work(struct ehca_comp_pool *pool,
@@ -654,11 +703,11 @@ static void take_over_work(struct ehca_comp_pool *pool,
list_splice_init(&cct->cq_list, &list);
while(!list_empty(&list)) {
- cq = list_entry(cct->cq_list.next, struct ehca_cq, entry);
+ cq = list_entry(cct->cq_list.next, struct ehca_cq, entry);
- list_del(&cq->entry);
- __queue_comp_task(cq, per_cpu_ptr(pool->cpu_comp_tasks,
- smp_processor_id()));
+ list_del(&cq->entry);
+ __queue_comp_task(cq, per_cpu_ptr(pool->cpu_comp_tasks,
+ smp_processor_id()));
}
spin_unlock_irqrestore(&cct->task_lock, flags_cct);
@@ -708,14 +757,14 @@ static int comp_pool_callback(struct notifier_block *nfb,
return NOTIFY_OK;
}
-#endif
-
int ehca_create_comp_pool(void)
{
-#ifdef CONFIG_INFINIBAND_EHCA_SCALING
int cpu;
struct task_struct *task;
+ if (!ehca_scaling_code)
+ return 0;
+
pool = kzalloc(sizeof(struct ehca_comp_pool), GFP_KERNEL);
if (pool == NULL)
return -ENOMEM;
@@ -740,23 +789,25 @@ int ehca_create_comp_pool(void)
comp_pool_callback_nb.notifier_call = comp_pool_callback;
comp_pool_callback_nb.priority =0;
register_cpu_notifier(&comp_pool_callback_nb);
-#endif
+
+ printk(KERN_INFO "eHCA scaling code enabled\n");
return 0;
}
void ehca_destroy_comp_pool(void)
{
-#ifdef CONFIG_INFINIBAND_EHCA_SCALING
int i;
+ if (!ehca_scaling_code)
+ return;
+
unregister_cpu_notifier(&comp_pool_callback_nb);
for (i = 0; i < NR_CPUS; i++) {
if (cpu_online(i))
destroy_comp_task(pool, i);
}
-#endif
-
- return;
+ free_percpu(pool->cpu_comp_tasks);
+ kfree(pool);
}
diff --git a/drivers/infiniband/hw/ehca/ehca_irq.h b/drivers/infiniband/hw/ehca/ehca_irq.h
index be579cc0adf..6ed06ee033e 100644
--- a/drivers/infiniband/hw/ehca/ehca_irq.h
+++ b/drivers/infiniband/hw/ehca/ehca_irq.h
@@ -56,6 +56,7 @@ void ehca_tasklet_neq(unsigned long data);
irqreturn_t ehca_interrupt_eq(int irq, void *dev_id);
void ehca_tasklet_eq(unsigned long data);
+void ehca_process_eq(struct ehca_shca *shca, int is_irq);
struct ehca_cpu_comp_task {
wait_queue_head_t wait_queue;
diff --git a/drivers/infiniband/hw/ehca/ehca_iverbs.h b/drivers/infiniband/hw/ehca/ehca_iverbs.h
index cd7789f0d08..95fd59fb452 100644
--- a/drivers/infiniband/hw/ehca/ehca_iverbs.h
+++ b/drivers/infiniband/hw/ehca/ehca_iverbs.h
@@ -171,14 +171,6 @@ int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma);
void ehca_poll_eqs(unsigned long data);
-int ehca_mmap_nopage(u64 foffset,u64 length,void **mapped,
- struct vm_area_struct **vma);
-
-int ehca_mmap_register(u64 physical,void **mapped,
- struct vm_area_struct **vma);
-
-int ehca_munmap(unsigned long addr, size_t len);
-
#ifdef CONFIG_PPC_64K_PAGES
void *ehca_alloc_fw_ctrlblock(gfp_t flags);
void ehca_free_fw_ctrlblock(void *ptr);
diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c
index 6574fbbaead..c1835121a82 100644
--- a/drivers/infiniband/hw/ehca/ehca_main.c
+++ b/drivers/infiniband/hw/ehca/ehca_main.c
@@ -52,7 +52,7 @@
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Christoph Raisch <raisch@de.ibm.com>");
MODULE_DESCRIPTION("IBM eServer HCA InfiniBand Device Driver");
-MODULE_VERSION("SVNEHCA_0019");
+MODULE_VERSION("SVNEHCA_0021");
int ehca_open_aqp1 = 0;
int ehca_debug_level = 0;
@@ -62,6 +62,7 @@ int ehca_use_hp_mr = 0;
int ehca_port_act_time = 30;
int ehca_poll_all_eqs = 1;
int ehca_static_rate = -1;
+int ehca_scaling_code = 1;
module_param_named(open_aqp1, ehca_open_aqp1, int, 0);
module_param_named(debug_level, ehca_debug_level, int, 0);
@@ -71,6 +72,7 @@ module_param_named(use_hp_mr, ehca_use_hp_mr, int, 0);
module_param_named(port_act_time, ehca_port_act_time, int, 0);
module_param_named(poll_all_eqs, ehca_poll_all_eqs, int, 0);
module_param_named(static_rate, ehca_static_rate, int, 0);
+module_param_named(scaling_code, ehca_scaling_code, int, 0);
MODULE_PARM_DESC(open_aqp1,
"AQP1 on startup (0: no (default), 1: yes)");
@@ -91,6 +93,8 @@ MODULE_PARM_DESC(poll_all_eqs,
" (0: no, 1: yes (default))");
MODULE_PARM_DESC(static_rate,
"set permanent static rate (default: disabled)");
+MODULE_PARM_DESC(scaling_code,
+ "set scaling code (0: disabled, 1: enabled/default)");
spinlock_t ehca_qp_idr_lock;
spinlock_t ehca_cq_idr_lock;
@@ -288,7 +292,7 @@ int ehca_init_device(struct ehca_shca *shca)
strlcpy(shca->ib_device.name, "ehca%d", IB_DEVICE_NAME_MAX);
shca->ib_device.owner = THIS_MODULE;
- shca->ib_device.uverbs_abi_ver = 5;
+ shca->ib_device.uverbs_abi_ver = 6;
shca->ib_device.uverbs_cmd_mask =
(1ull << IB_USER_VERBS_CMD_GET_CONTEXT) |
(1ull << IB_USER_VERBS_CMD_QUERY_DEVICE) |
@@ -432,8 +436,8 @@ static int ehca_destroy_aqp1(struct ehca_sport *sport)
static ssize_t ehca_show_debug_level(struct device_driver *ddp, char *buf)
{
- return snprintf(buf, PAGE_SIZE, "%d\n",
- ehca_debug_level);
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ ehca_debug_level);
}
static ssize_t ehca_store_debug_level(struct device_driver *ddp,
@@ -778,8 +782,24 @@ void ehca_poll_eqs(unsigned long data)
spin_lock(&shca_list_lock);
list_for_each_entry(shca, &shca_list, shca_list) {
- if (shca->eq.is_initialized)
- ehca_tasklet_eq((unsigned long)(void*)shca);
+ if (shca->eq.is_initialized) {
+ /* call deadman proc only if eq ptr does not change */
+ struct ehca_eq *eq = &shca->eq;
+ int max = 3;
+ volatile u64 q_ofs, q_ofs2;
+ u64 flags;
+ spin_lock_irqsave(&eq->spinlock, flags);
+ q_ofs = eq->ipz_queue.current_q_offset;
+ spin_unlock_irqrestore(&eq->spinlock, flags);
+ do {
+ spin_lock_irqsave(&eq->spinlock, flags);
+ q_ofs2 = eq->ipz_queue.current_q_offset;
+ spin_unlock_irqrestore(&eq->spinlock, flags);
+ max--;
+ } while (q_ofs == q_ofs2 && max > 0);
+ if (q_ofs == q_ofs2)
+ ehca_process_eq(shca, 0);
+ }
}
mod_timer(&poll_eqs_timer, jiffies + HZ);
spin_unlock(&shca_list_lock);
@@ -790,7 +810,7 @@ int __init ehca_module_init(void)
int ret;
printk(KERN_INFO "eHCA Infiniband Device Driver "
- "(Rel.: SVNEHCA_0019)\n");
+ "(Rel.: SVNEHCA_0021)\n");
idr_init(&ehca_qp_idr);
idr_init(&ehca_cq_idr);
spin_lock_init(&ehca_qp_idr_lock);
diff --git a/drivers/infiniband/hw/ehca/ehca_mrmw.c b/drivers/infiniband/hw/ehca/ehca_mrmw.c
index cfb362a1029..d22ab563633 100644
--- a/drivers/infiniband/hw/ehca/ehca_mrmw.c
+++ b/drivers/infiniband/hw/ehca/ehca_mrmw.c
@@ -53,9 +53,8 @@ static struct ehca_mr *ehca_mr_new(void)
{
struct ehca_mr *me;
- me = kmem_cache_alloc(mr_cache, GFP_KERNEL);
+ me = kmem_cache_zalloc(mr_cache, GFP_KERNEL);
if (me) {
- memset(me, 0, sizeof(struct ehca_mr));
spin_lock_init(&me->mrlock);
} else
ehca_gen_err("alloc failed");
@@ -72,9 +71,8 @@ static struct ehca_mw *ehca_mw_new(void)
{
struct ehca_mw *me;
- me = kmem_cache_alloc(mw_cache, GFP_KERNEL);
+ me = kmem_cache_zalloc(mw_cache, GFP_KERNEL);
if (me) {
- memset(me, 0, sizeof(struct ehca_mw));
spin_lock_init(&me->mwlock);
} else
ehca_gen_err("alloc failed");
diff --git a/drivers/infiniband/hw/ehca/ehca_pd.c b/drivers/infiniband/hw/ehca/ehca_pd.c
index d5345e5b3cd..79d0591a804 100644
--- a/drivers/infiniband/hw/ehca/ehca_pd.c
+++ b/drivers/infiniband/hw/ehca/ehca_pd.c
@@ -50,14 +50,13 @@ struct ib_pd *ehca_alloc_pd(struct ib_device *device,
{
struct ehca_pd *pd;
- pd = kmem_cache_alloc(pd_cache, GFP_KERNEL);
+ pd = kmem_cache_zalloc(pd_cache, GFP_KERNEL);
if (!pd) {
ehca_err(device, "device=%p context=%p out of memory",
device, context);
return ERR_PTR(-ENOMEM);
}
- memset(pd, 0, sizeof(struct ehca_pd));
pd->ownpid = current->tgid;
/*
diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c
index 34b85556d01..df0516f2437 100644
--- a/drivers/infiniband/hw/ehca/ehca_qp.c
+++ b/drivers/infiniband/hw/ehca/ehca_qp.c
@@ -450,13 +450,12 @@ struct ib_qp *ehca_create_qp(struct ib_pd *pd,
if (pd->uobject && udata)
context = pd->uobject->context;
- my_qp = kmem_cache_alloc(qp_cache, GFP_KERNEL);
+ my_qp = kmem_cache_zalloc(qp_cache, GFP_KERNEL);
if (!my_qp) {
ehca_err(pd->device, "pd=%p not enough memory to alloc qp", pd);
return ERR_PTR(-ENOMEM);
}
- memset(my_qp, 0, sizeof(struct ehca_qp));
memset (&parms, 0, sizeof(struct ehca_alloc_qp_parms));
spin_lock_init(&my_qp->spinlock_s);
spin_lock_init(&my_qp->spinlock_r);
@@ -637,7 +636,6 @@ struct ib_qp *ehca_create_qp(struct ib_pd *pd,
struct ipz_queue *ipz_rqueue = &my_qp->ipz_rqueue;
struct ipz_queue *ipz_squeue = &my_qp->ipz_squeue;
struct ehca_create_qp_resp resp;
- struct vm_area_struct * vma;
memset(&resp, 0, sizeof(resp));
resp.qp_num = my_qp->real_qp_num;
@@ -651,59 +649,21 @@ struct ib_qp *ehca_create_qp(struct ib_pd *pd,
resp.ipz_rqueue.queue_length = ipz_rqueue->queue_length;
resp.ipz_rqueue.pagesize = ipz_rqueue->pagesize;
resp.ipz_rqueue.toggle_state = ipz_rqueue->toggle_state;
- ret = ehca_mmap_nopage(((u64)(my_qp->token) << 32) | 0x22000000,
- ipz_rqueue->queue_length,
- (void**)&resp.ipz_rqueue.queue,
- &vma);
- if (ret) {
- ehca_err(pd->device, "Could not mmap rqueue pages");
- goto create_qp_exit3;
- }
- my_qp->uspace_rqueue = resp.ipz_rqueue.queue;
/* squeue properties */
resp.ipz_squeue.qe_size = ipz_squeue->qe_size;
resp.ipz_squeue.act_nr_of_sg = ipz_squeue->act_nr_of_sg;
resp.ipz_squeue.queue_length = ipz_squeue->queue_length;
resp.ipz_squeue.pagesize = ipz_squeue->pagesize;
resp.ipz_squeue.toggle_state = ipz_squeue->toggle_state;
- ret = ehca_mmap_nopage(((u64)(my_qp->token) << 32) | 0x23000000,
- ipz_squeue->queue_length,
- (void**)&resp.ipz_squeue.queue,
- &vma);
- if (ret) {
- ehca_err(pd->device, "Could not mmap squeue pages");
- goto create_qp_exit4;
- }
- my_qp->uspace_squeue = resp.ipz_squeue.queue;
- /* fw_handle */
- resp.galpas = my_qp->galpas;
- ret = ehca_mmap_register(my_qp->galpas.user.fw_handle,
- (void**)&resp.galpas.kernel.fw_handle,
- &vma);
- if (ret) {
- ehca_err(pd->device, "Could not mmap fw_handle");
- goto create_qp_exit5;
- }
- my_qp->uspace_fwh = (u64)resp.galpas.kernel.fw_handle;
-
if (ib_copy_to_udata(udata, &resp, sizeof resp)) {
ehca_err(pd->device, "Copy to udata failed");
ret = -EINVAL;
- goto create_qp_exit6;
+ goto create_qp_exit3;
}
}
return &my_qp->ib_qp;
-create_qp_exit6:
- ehca_munmap(my_qp->uspace_fwh, EHCA_PAGESIZE);
-
-create_qp_exit5:
- ehca_munmap(my_qp->uspace_squeue, my_qp->ipz_squeue.queue_length);
-
-create_qp_exit4:
- ehca_munmap(my_qp->uspace_rqueue, my_qp->ipz_rqueue.queue_length);
-
create_qp_exit3:
ipz_queue_dtor(&my_qp->ipz_rqueue);
ipz_queue_dtor(&my_qp->ipz_squeue);
@@ -931,7 +891,7 @@ static int internal_modify_qp(struct ib_qp *ibqp,
my_qp->qp_type == IB_QPT_SMI) &&
statetrans == IB_QPST_SQE2RTS) {
/* mark next free wqe if kernel */
- if (my_qp->uspace_squeue == 0) {
+ if (!ibqp->uobject) {
struct ehca_wqe *wqe;
/* lock send queue */
spin_lock_irqsave(&my_qp->spinlock_s, spl_flags);
@@ -1417,11 +1377,18 @@ int ehca_destroy_qp(struct ib_qp *ibqp)
enum ib_qp_type qp_type;
unsigned long flags;
- if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context &&
- my_pd->ownpid != cur_pid) {
- ehca_err(ibqp->device, "Invalid caller pid=%x ownpid=%x",
- cur_pid, my_pd->ownpid);
- return -EINVAL;
+ if (ibqp->uobject) {
+ if (my_qp->mm_count_galpa ||
+ my_qp->mm_count_rqueue || my_qp->mm_count_squeue) {
+ ehca_err(ibqp->device, "Resources still referenced in "
+ "user space qp_num=%x", ibqp->qp_num);
+ return -EINVAL;
+ }
+ if (my_pd->ownpid != cur_pid) {
+ ehca_err(ibqp->device, "Invalid caller pid=%x ownpid=%x",
+ cur_pid, my_pd->ownpid);
+ return -EINVAL;
+ }
}
if (my_qp->send_cq) {
@@ -1439,24 +1406,6 @@ int ehca_destroy_qp(struct ib_qp *ibqp)
idr_remove(&ehca_qp_idr, my_qp->token);
spin_unlock_irqrestore(&ehca_qp_idr_lock, flags);
- /* un-mmap if vma alloc */
- if (my_qp->uspace_rqueue) {
- ret = ehca_munmap(my_qp->uspace_rqueue,
- my_qp->ipz_rqueue.queue_length);
- if (ret)
- ehca_err(ibqp->device, "Could not munmap rqueue "
- "qp_num=%x", qp_num);
- ret = ehca_munmap(my_qp->uspace_squeue,
- my_qp->ipz_squeue.queue_length);
- if (ret)
- ehca_err(ibqp->device, "Could not munmap squeue "
- "qp_num=%x", qp_num);
- ret = ehca_munmap(my_qp->uspace_fwh, EHCA_PAGESIZE);
- if (ret)
- ehca_err(ibqp->device, "Could not munmap fwh qp_num=%x",
- qp_num);
- }
-
h_ret = hipz_h_destroy_qp(shca->ipz_hca_handle, my_qp);
if (h_ret != H_SUCCESS) {
ehca_err(ibqp->device, "hipz_h_destroy_qp() failed rc=%lx "
diff --git a/drivers/infiniband/hw/ehca/ehca_reqs.c b/drivers/infiniband/hw/ehca/ehca_reqs.c
index b46bda1bf85..08d3f892d9f 100644
--- a/drivers/infiniband/hw/ehca/ehca_reqs.c
+++ b/drivers/infiniband/hw/ehca/ehca_reqs.c
@@ -579,7 +579,7 @@ poll_cq_one_read_cqe:
} else
wc->status = IB_WC_SUCCESS;
- wc->qp_num = cqe->local_qp_number;
+ wc->qp = NULL;
wc->byte_len = cqe->nr_bytes_transferred;
wc->pkey_index = cqe->pkey_index;
wc->slid = cqe->rlid;
diff --git a/drivers/infiniband/hw/ehca/ehca_uverbs.c b/drivers/infiniband/hw/ehca/ehca_uverbs.c
index e08764e4aef..73db920b694 100644
--- a/drivers/infiniband/hw/ehca/ehca_uverbs.c
+++ b/drivers/infiniband/hw/ehca/ehca_uverbs.c
@@ -68,105 +68,183 @@ int ehca_dealloc_ucontext(struct ib_ucontext *context)
return 0;
}
-struct page *ehca_nopage(struct vm_area_struct *vma,
- unsigned long address, int *type)
+static void ehca_mm_open(struct vm_area_struct *vma)
{
- struct page *mypage = NULL;
- u64 fileoffset = vma->vm_pgoff << PAGE_SHIFT;
- u32 idr_handle = fileoffset >> 32;
- u32 q_type = (fileoffset >> 28) & 0xF; /* CQ, QP,... */
- u32 rsrc_type = (fileoffset >> 24) & 0xF; /* sq,rq,cmnd_window */
- u32 cur_pid = current->tgid;
- unsigned long flags;
- struct ehca_cq *cq;
- struct ehca_qp *qp;
- struct ehca_pd *pd;
- u64 offset;
- void *vaddr;
+ u32 *count = (u32*)vma->vm_private_data;
+ if (!count) {
+ ehca_gen_err("Invalid vma struct vm_start=%lx vm_end=%lx",
+ vma->vm_start, vma->vm_end);
+ return;
+ }
+ (*count)++;
+ if (!(*count))
+ ehca_gen_err("Use count overflow vm_start=%lx vm_end=%lx",
+ vma->vm_start, vma->vm_end);
+ ehca_gen_dbg("vm_start=%lx vm_end=%lx count=%x",
+ vma->vm_start, vma->vm_end, *count);
+}
- switch (q_type) {
- case 1: /* CQ */
- spin_lock_irqsave(&ehca_cq_idr_lock, flags);
- cq = idr_find(&ehca_cq_idr, idr_handle);
- spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
+static void ehca_mm_close(struct vm_area_struct *vma)
+{
+ u32 *count = (u32*)vma->vm_private_data;
+ if (!count) {
+ ehca_gen_err("Invalid vma struct vm_start=%lx vm_end=%lx",
+ vma->vm_start, vma->vm_end);
+ return;
+ }
+ (*count)--;
+ ehca_gen_dbg("vm_start=%lx vm_end=%lx count=%x",
+ vma->vm_start, vma->vm_end, *count);
+}
- /* make sure this mmap really belongs to the authorized user */
- if (!cq) {
- ehca_gen_err("cq is NULL ret=NOPAGE_SIGBUS");
- return NOPAGE_SIGBUS;
+static struct vm_operations_struct vm_ops = {
+ .open = ehca_mm_open,
+ .close = ehca_mm_close,
+};
+
+static int ehca_mmap_fw(struct vm_area_struct *vma, struct h_galpas *galpas,
+ u32 *mm_count)
+{
+ int ret;
+ u64 vsize, physical;
+
+ vsize = vma->vm_end - vma->vm_start;
+ if (vsize != EHCA_PAGESIZE) {
+ ehca_gen_err("invalid vsize=%lx", vma->vm_end - vma->vm_start);
+ return -EINVAL;
+ }
+
+ physical = galpas->user.fw_handle;
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ ehca_gen_dbg("vsize=%lx physical=%lx", vsize, physical);
+ /* VM_IO | VM_RESERVED are set by remap_pfn_range() */
+ ret = remap_pfn_range(vma, vma->vm_start, physical >> PAGE_SHIFT,
+ vsize, vma->vm_page_prot);
+ if (unlikely(ret)) {
+ ehca_gen_err("remap_pfn_range() failed ret=%x", ret);
+ return -ENOMEM;
+ }
+
+ vma->vm_private_data = mm_count;
+ (*mm_count)++;
+ vma->vm_ops = &vm_ops;
+
+ return 0;
+}
+
+static int ehca_mmap_queue(struct vm_area_struct *vma, struct ipz_queue *queue,
+ u32 *mm_count)
+{
+ int ret;
+ u64 start, ofs;
+ struct page *page;
+
+ vma->vm_flags |= VM_RESERVED;
+ start = vma->vm_start;
+ for (ofs = 0; ofs < queue->queue_length; ofs += PAGE_SIZE) {
+ u64 virt_addr = (u64)ipz_qeit_calc(queue, ofs);
+ page = virt_to_page(virt_addr);
+ ret = vm_insert_page(vma, start, page);
+ if (unlikely(ret)) {
+ ehca_gen_err("vm_insert_page() failed rc=%x", ret);
+ return ret;
}
+ start += PAGE_SIZE;
+ }
+ vma->vm_private_data = mm_count;
+ (*mm_count)++;
+ vma->vm_ops = &vm_ops;
- if (cq->ownpid != cur_pid) {
+ return 0;
+}
+
+static int ehca_mmap_cq(struct vm_area_struct *vma, struct ehca_cq *cq,
+ u32 rsrc_type)
+{
+ int ret;
+
+ switch (rsrc_type) {
+ case 1: /* galpa fw handle */
+ ehca_dbg(cq->ib_cq.device, "cq_num=%x fw", cq->cq_number);
+ ret = ehca_mmap_fw(vma, &cq->galpas, &cq->mm_count_galpa);
+ if (unlikely(ret)) {
ehca_err(cq->ib_cq.device,
- "Invalid caller pid=%x ownpid=%x",
- cur_pid, cq->ownpid);
- return NOPAGE_SIGBUS;
+ "ehca_mmap_fw() failed rc=%x cq_num=%x",
+ ret, cq->cq_number);
+ return ret;
}
+ break;
- if (rsrc_type == 2) {
- ehca_dbg(cq->ib_cq.device, "cq=%p cq queuearea", cq);
- offset = address - vma->vm_start;
- vaddr = ipz_qeit_calc(&cq->ipz_queue, offset);
- ehca_dbg(cq->ib_cq.device, "offset=%lx vaddr=%p",
- offset, vaddr);
- mypage = virt_to_page(vaddr);
+ case 2: /* cq queue_addr */
+ ehca_dbg(cq->ib_cq.device, "cq_num=%x queue", cq->cq_number);
+ ret = ehca_mmap_queue(vma, &cq->ipz_queue, &cq->mm_count_queue);
+ if (unlikely(ret)) {
+ ehca_err(cq->ib_cq.device,
+ "ehca_mmap_queue() failed rc=%x cq_num=%x",
+ ret, cq->cq_number);
+ return ret;
}
break;
- case 2: /* QP */
- spin_lock_irqsave(&ehca_qp_idr_lock, flags);
- qp = idr_find(&ehca_qp_idr, idr_handle);
- spin_unlock_irqrestore(&ehca_qp_idr_lock, flags);
+ default:
+ ehca_err(cq->ib_cq.device, "bad resource type=%x cq_num=%x",
+ rsrc_type, cq->cq_number);
+ return -EINVAL;
+ }
- /* make sure this mmap really belongs to the authorized user */
- if (!qp) {
- ehca_gen_err("qp is NULL ret=NOPAGE_SIGBUS");
- return NOPAGE_SIGBUS;
+ return 0;
+}
+
+static int ehca_mmap_qp(struct vm_area_struct *vma, struct ehca_qp *qp,
+ u32 rsrc_type)
+{
+ int ret;
+
+ switch (rsrc_type) {
+ case 1: /* galpa fw handle */
+ ehca_dbg(qp->ib_qp.device, "qp_num=%x fw", qp->ib_qp.qp_num);
+ ret = ehca_mmap_fw(vma, &qp->galpas, &qp->mm_count_galpa);
+ if (unlikely(ret)) {
+ ehca_err(qp->ib_qp.device,
+ "remap_pfn_range() failed ret=%x qp_num=%x",
+ ret, qp->ib_qp.qp_num);
+ return -ENOMEM;
}
+ break;
- pd = container_of(qp->ib_qp.pd, struct ehca_pd, ib_pd);
- if (pd->ownpid != cur_pid) {
+ case 2: /* qp rqueue_addr */
+ ehca_dbg(qp->ib_qp.device, "qp_num=%x rqueue",
+ qp->ib_qp.qp_num);
+ ret = ehca_mmap_queue(vma, &qp->ipz_rqueue, &qp->mm_count_rqueue);
+ if (unlikely(ret)) {
ehca_err(qp->ib_qp.device,
- "Invalid caller pid=%x ownpid=%x",
- cur_pid, pd->ownpid);
- return NOPAGE_SIGBUS;
+ "ehca_mmap_queue(rq) failed rc=%x qp_num=%x",
+ ret, qp->ib_qp.qp_num);
+ return ret;
}
+ break;
- if (rsrc_type == 2) { /* rqueue */
- ehca_dbg(qp->ib_qp.device, "qp=%p qp rqueuearea", qp);
- offset = address - vma->vm_start;
- vaddr = ipz_qeit_calc(&qp->ipz_rqueue, offset);
- ehca_dbg(qp->ib_qp.device, "offset=%lx vaddr=%p",
- offset, vaddr);
- mypage = virt_to_page(vaddr);
- } else if (rsrc_type == 3) { /* squeue */
- ehca_dbg(qp->ib_qp.device, "qp=%p qp squeuearea", qp);
- offset = address - vma->vm_start;
- vaddr = ipz_qeit_calc(&qp->ipz_squeue, offset);
- ehca_dbg(qp->ib_qp.device, "offset=%lx vaddr=%p",
- offset, vaddr);
- mypage = virt_to_page(vaddr);
+ case 3: /* qp squeue_addr */
+ ehca_dbg(qp->ib_qp.device, "qp_num=%x squeue",
+ qp->ib_qp.qp_num);
+ ret = ehca_mmap_queue(vma, &qp->ipz_squeue, &qp->mm_count_squeue);
+ if (unlikely(ret)) {
+ ehca_err(qp->ib_qp.device,
+ "ehca_mmap_queue(sq) failed rc=%x qp_num=%x",
+ ret, qp->ib_qp.qp_num);
+ return ret;
}
break;
default:
- ehca_gen_err("bad queue type %x", q_type);
- return NOPAGE_SIGBUS;
- }
-
- if (!mypage) {
- ehca_gen_err("Invalid page adr==NULL ret=NOPAGE_SIGBUS");
- return NOPAGE_SIGBUS;
+ ehca_err(qp->ib_qp.device, "bad resource type=%x qp=num=%x",
+ rsrc_type, qp->ib_qp.qp_num);
+ return -EINVAL;
}
- get_page(mypage);
- return mypage;
+ return 0;
}
-static struct vm_operations_struct ehcau_vm_ops = {
- .nopage = ehca_nopage,
-};
-
int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
{
u64 fileoffset = vma->vm_pgoff << PAGE_SHIFT;
@@ -175,7 +253,6 @@ int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
u32 rsrc_type = (fileoffset >> 24) & 0xF; /* sq,rq,cmnd_window */
u32 cur_pid = current->tgid;
u32 ret;
- u64 vsize, physical;
unsigned long flags;
struct ehca_cq *cq;
struct ehca_qp *qp;
@@ -201,44 +278,12 @@ int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
if (!cq->ib_cq.uobject || cq->ib_cq.uobject->context != context)
return -EINVAL;
- switch (rsrc_type) {
- case 1: /* galpa fw handle */
- ehca_dbg(cq->ib_cq.device, "cq=%p cq triggerarea", cq);
- vma->vm_flags |= VM_RESERVED;
- vsize = vma->vm_end - vma->vm_start;
- if (vsize != EHCA_PAGESIZE) {
- ehca_err(cq->ib_cq.device, "invalid vsize=%lx",
- vma->vm_end - vma->vm_start);
- return -EINVAL;
- }
-
- physical = cq->galpas.user.fw_handle;
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
- vma->vm_flags |= VM_IO | VM_RESERVED;
-
- ehca_dbg(cq->ib_cq.device,
- "vsize=%lx physical=%lx", vsize, physical);
- ret = remap_pfn_range(vma, vma->vm_start,
- physical >> PAGE_SHIFT, vsize,
- vma->vm_page_prot);
- if (ret) {
- ehca_err(cq->ib_cq.device,
- "remap_pfn_range() failed ret=%x",
- ret);
- return -ENOMEM;
- }
- break;
-
- case 2: /* cq queue_addr */
- ehca_dbg(cq->ib_cq.device, "cq=%p cq q_addr", cq);
- vma->vm_flags |= VM_RESERVED;
- vma->vm_ops = &ehcau_vm_ops;
- break;
-
- default:
- ehca_err(cq->ib_cq.device, "bad resource type %x",
- rsrc_type);
- return -EINVAL;
+ ret = ehca_mmap_cq(vma, cq, rsrc_type);
+ if (unlikely(ret)) {
+ ehca_err(cq->ib_cq.device,
+ "ehca_mmap_cq() failed rc=%x cq_num=%x",
+ ret, cq->cq_number);
+ return ret;
}
break;
@@ -262,50 +307,12 @@ int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
if (!qp->ib_qp.uobject || qp->ib_qp.uobject->context != context)
return -EINVAL;
- switch (rsrc_type) {
- case 1: /* galpa fw handle */
- ehca_dbg(qp->ib_qp.device, "qp=%p qp triggerarea", qp);
- vma->vm_flags |= VM_RESERVED;
- vsize = vma->vm_end - vma->vm_start;
- if (vsize != EHCA_PAGESIZE) {
- ehca_err(qp->ib_qp.device, "invalid vsize=%lx",
- vma->vm_end - vma->vm_start);
- return -EINVAL;
- }
-
- physical = qp->galpas.user.fw_handle;
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
- vma->vm_flags |= VM_IO | VM_RESERVED;
-
- ehca_dbg(qp->ib_qp.device, "vsize=%lx physical=%lx",
- vsize, physical);
- ret = remap_pfn_range(vma, vma->vm_start,
- physical >> PAGE_SHIFT, vsize,
- vma->vm_page_prot);
- if (ret) {
- ehca_err(qp->ib_qp.device,
- "remap_pfn_range() failed ret=%x",
- ret);
- return -ENOMEM;
- }
- break;
-
- case 2: /* qp rqueue_addr */
- ehca_dbg(qp->ib_qp.device, "qp=%p qp rqueue_addr", qp);
- vma->vm_flags |= VM_RESERVED;
- vma->vm_ops = &ehcau_vm_ops;
- break;
-
- case 3: /* qp squeue_addr */
- ehca_dbg(qp->ib_qp.device, "qp=%p qp squeue_addr", qp);
- vma->vm_flags |= VM_RESERVED;
- vma->vm_ops = &ehcau_vm_ops;
- break;
-
- default:
- ehca_err(qp->ib_qp.device, "bad resource type %x",
- rsrc_type);
- return -EINVAL;
+ ret = ehca_mmap_qp(vma, qp, rsrc_type);
+ if (unlikely(ret)) {
+ ehca_err(qp->ib_qp.device,
+ "ehca_mmap_qp() failed rc=%x qp_num=%x",
+ ret, qp->ib_qp.qp_num);
+ return ret;
}
break;
@@ -316,77 +323,3 @@ int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
return 0;
}
-
-int ehca_mmap_nopage(u64 foffset, u64 length, void **mapped,
- struct vm_area_struct **vma)
-{
- down_write(&current->mm->mmap_sem);
- *mapped = (void*)do_mmap(NULL,0, length, PROT_WRITE,
- MAP_SHARED | MAP_ANONYMOUS,
- foffset);
- up_write(&current->mm->mmap_sem);
- if (!(*mapped)) {
- ehca_gen_err("couldn't mmap foffset=%lx length=%lx",
- foffset, length);
- return -EINVAL;
- }
-
- *vma = find_vma(current->mm, (u64)*mapped);
- if (!(*vma)) {
- down_write(&current->mm->mmap_sem);
- do_munmap(current->mm, 0, length);
- up_write(&current->mm->mmap_sem);
- ehca_gen_err("couldn't find vma queue=%p", *mapped);
- return -EINVAL;
- }
- (*vma)->vm_flags |= VM_RESERVED;
- (*vma)->vm_ops = &ehcau_vm_ops;
-
- return 0;
-}
-
-int ehca_mmap_register(u64 physical, void **mapped,
- struct vm_area_struct **vma)
-{
- int ret;
- unsigned long vsize;
- /* ehca hw supports only 4k page */
- ret = ehca_mmap_nopage(0, EHCA_PAGESIZE, mapped, vma);
- if (ret) {
- ehca_gen_err("could'nt mmap physical=%lx", physical);
- return ret;
- }
-
- (*vma)->vm_flags |= VM_RESERVED;
- vsize = (*vma)->vm_end - (*vma)->vm_start;
- if (vsize != EHCA_PAGESIZE) {
- ehca_gen_err("invalid vsize=%lx",
- (*vma)->vm_end - (*vma)->vm_start);
- return -EINVAL;
- }
-
- (*vma)->vm_page_prot = pgprot_noncached((*vma)->vm_page_prot);
- (*vma)->vm_flags |= VM_IO | VM_RESERVED;
-
- ret = remap_pfn_range((*vma), (*vma)->vm_start,
- physical >> PAGE_SHIFT, vsize,
- (*vma)->vm_page_prot);
- if (ret) {
- ehca_gen_err("remap_pfn_range() failed ret=%x", ret);
- return -ENOMEM;
- }
-
- return 0;
-
-}
-
-int ehca_munmap(unsigned long addr, size_t len) {
- int ret = 0;
- struct mm_struct *mm = current->mm;
- if (mm) {
- down_write(&mm->mmap_sem);
- ret = do_munmap(mm, addr, len);
- up_write(&mm->mmap_sem);
- }
- return ret;
-}
diff --git a/drivers/infiniband/hw/ehca/ipz_pt_fn.h b/drivers/infiniband/hw/ehca/ipz_pt_fn.h
index dc3bda2634b..8199c45768a 100644
--- a/drivers/infiniband/hw/ehca/ipz_pt_fn.h
+++ b/drivers/infiniband/hw/ehca/ipz_pt_fn.h
@@ -79,7 +79,7 @@ static inline void *ipz_qeit_calc(struct ipz_queue *queue, u64 q_offset)
if (q_offset >= queue->queue_length)
return NULL;
current_page = (queue->queue_pages)[q_offset >> EHCA_PAGESHIFT];
- return &current_page->entries[q_offset & (EHCA_PAGESIZE - 1)];
+ return &current_page->entries[q_offset & (EHCA_PAGESIZE - 1)];
}
/*
@@ -247,6 +247,15 @@ static inline void *ipz_eqit_eq_get_inc_valid(struct ipz_queue *queue)
return ret;
}
+static inline void *ipz_eqit_eq_peek_valid(struct ipz_queue *queue)
+{
+ void *ret = ipz_qeit_get(queue);
+ u32 qe = *(u8 *) ret;
+ if ((qe >> 7) != (queue->toggle_state & 1))
+ return NULL;
+ return ret;
+}
+
/* returns address (GX) of first queue entry */
static inline u64 ipz_qpt_get_firstpage(struct ipz_qpt *qpt)
{
diff --git a/drivers/infiniband/hw/ipath/ipath_diag.c b/drivers/infiniband/hw/ipath/ipath_diag.c
index 28c087b824c..0f13a2182cc 100644
--- a/drivers/infiniband/hw/ipath/ipath_diag.c
+++ b/drivers/infiniband/hw/ipath/ipath_diag.c
@@ -59,7 +59,7 @@ static ssize_t ipath_diag_read(struct file *fp, char __user *data,
static ssize_t ipath_diag_write(struct file *fp, const char __user *data,
size_t count, loff_t *off);
-static struct file_operations diag_file_ops = {
+static const struct file_operations diag_file_ops = {
.owner = THIS_MODULE,
.write = ipath_diag_write,
.read = ipath_diag_read,
@@ -71,7 +71,7 @@ static ssize_t ipath_diagpkt_write(struct file *fp,
const char __user *data,
size_t count, loff_t *off);
-static struct file_operations diagpkt_file_ops = {
+static const struct file_operations diagpkt_file_ops = {
.owner = THIS_MODULE,
.write = ipath_diagpkt_write,
};
diff --git a/drivers/infiniband/hw/ipath/ipath_dma.c b/drivers/infiniband/hw/ipath/ipath_dma.c
index 6e0f2b8918c..f6f94904082 100644
--- a/drivers/infiniband/hw/ipath/ipath_dma.c
+++ b/drivers/infiniband/hw/ipath/ipath_dma.c
@@ -96,8 +96,8 @@ static void ipath_dma_unmap_page(struct ib_device *dev,
BUG_ON(!valid_dma_direction(direction));
}
-int ipath_map_sg(struct ib_device *dev, struct scatterlist *sg, int nents,
- enum dma_data_direction direction)
+static int ipath_map_sg(struct ib_device *dev, struct scatterlist *sg, int nents,
+ enum dma_data_direction direction)
{
u64 addr;
int i;
diff --git a/drivers/infiniband/hw/ipath/ipath_file_ops.c b/drivers/infiniband/hw/ipath/ipath_file_ops.c
index b932bcb67a5..5d64ff87529 100644
--- a/drivers/infiniband/hw/ipath/ipath_file_ops.c
+++ b/drivers/infiniband/hw/ipath/ipath_file_ops.c
@@ -54,7 +54,7 @@ static ssize_t ipath_write(struct file *, const char __user *, size_t,
static unsigned int ipath_poll(struct file *, struct poll_table_struct *);
static int ipath_mmap(struct file *, struct vm_area_struct *);
-static struct file_operations ipath_file_ops = {
+static const struct file_operations ipath_file_ops = {
.owner = THIS_MODULE,
.write = ipath_write,
.open = ipath_open,
@@ -2153,7 +2153,7 @@ bail:
static struct class *ipath_class;
-static int init_cdev(int minor, char *name, struct file_operations *fops,
+static int init_cdev(int minor, char *name, const struct file_operations *fops,
struct cdev **cdevp, struct class_device **class_devp)
{
const dev_t dev = MKDEV(IPATH_MAJOR, minor);
@@ -2210,7 +2210,7 @@ done:
return ret;
}
-int ipath_cdev_init(int minor, char *name, struct file_operations *fops,
+int ipath_cdev_init(int minor, char *name, const struct file_operations *fops,
struct cdev **cdevp, struct class_device **class_devp)
{
return init_cdev(minor, name, fops, cdevp, class_devp);
diff --git a/drivers/infiniband/hw/ipath/ipath_fs.c b/drivers/infiniband/hw/ipath/ipath_fs.c
index 79a60f020a2..5b40a846ff9 100644
--- a/drivers/infiniband/hw/ipath/ipath_fs.c
+++ b/drivers/infiniband/hw/ipath/ipath_fs.c
@@ -47,7 +47,7 @@
static struct super_block *ipath_super;
static int ipathfs_mknod(struct inode *dir, struct dentry *dentry,
- int mode, struct file_operations *fops,
+ int mode, const struct file_operations *fops,
void *data)
{
int error;
@@ -81,7 +81,7 @@ bail:
static int create_file(const char *name, mode_t mode,
struct dentry *parent, struct dentry **dentry,
- struct file_operations *fops, void *data)
+ const struct file_operations *fops, void *data)
{
int error;
@@ -105,7 +105,7 @@ static ssize_t atomic_stats_read(struct file *file, char __user *buf,
sizeof ipath_stats);
}
-static struct file_operations atomic_stats_ops = {
+static const struct file_operations atomic_stats_ops = {
.read = atomic_stats_read,
};
@@ -127,7 +127,7 @@ static ssize_t atomic_counters_read(struct file *file, char __user *buf,
sizeof counters);
}
-static struct file_operations atomic_counters_ops = {
+static const struct file_operations atomic_counters_ops = {
.read = atomic_counters_read,
};
@@ -166,7 +166,7 @@ static ssize_t atomic_node_info_read(struct file *file, char __user *buf,
sizeof nodeinfo);
}
-static struct file_operations atomic_node_info_ops = {
+static const struct file_operations atomic_node_info_ops = {
.read = atomic_node_info_read,
};
@@ -291,7 +291,7 @@ static ssize_t atomic_port_info_read(struct file *file, char __user *buf,
sizeof portinfo);
}
-static struct file_operations atomic_port_info_ops = {
+static const struct file_operations atomic_port_info_ops = {
.read = atomic_port_info_read,
};
@@ -394,7 +394,7 @@ bail:
return ret;
}
-static struct file_operations flash_ops = {
+static const struct file_operations flash_ops = {
.read = flash_read,
.write = flash_write,
};
diff --git a/drivers/infiniband/hw/ipath/ipath_iba6110.c b/drivers/infiniband/hw/ipath/ipath_iba6110.c
index 7468477ba83..99348254502 100644
--- a/drivers/infiniband/hw/ipath/ipath_iba6110.c
+++ b/drivers/infiniband/hw/ipath/ipath_iba6110.c
@@ -1534,7 +1534,7 @@ static int ipath_ht_early_init(struct ipath_devdata *dd)
* @kbase: ipath_base_info pointer
*
* We set the PCIE flag because the lower bandwidth on PCIe vs
- * HyperTransport can affect some user packet algorithims.
+ * HyperTransport can affect some user packet algorithms.
*/
static int ipath_ht_get_base_info(struct ipath_portdata *pd, void *kbase)
{
diff --git a/drivers/infiniband/hw/ipath/ipath_iba6120.c b/drivers/infiniband/hw/ipath/ipath_iba6120.c
index ae8bf9950c6..05918e1e7c3 100644
--- a/drivers/infiniband/hw/ipath/ipath_iba6120.c
+++ b/drivers/infiniband/hw/ipath/ipath_iba6120.c
@@ -1293,7 +1293,7 @@ int __attribute__((weak)) ipath_unordered_wc(void)
* @kbase: ipath_base_info pointer
*
* We set the PCIE flag because the lower bandwidth on PCIe vs
- * HyperTransport can affect some user packet algorithims.
+ * HyperTransport can affect some user packet algorithms.
*/
static int ipath_pe_get_base_info(struct ipath_portdata *pd, void *kbase)
{
diff --git a/drivers/infiniband/hw/ipath/ipath_kernel.h b/drivers/infiniband/hw/ipath/ipath_kernel.h
index 986b2125b8f..6d8d05fb599 100644
--- a/drivers/infiniband/hw/ipath/ipath_kernel.h
+++ b/drivers/infiniband/hw/ipath/ipath_kernel.h
@@ -593,7 +593,7 @@ void ipath_shutdown_device(struct ipath_devdata *);
void ipath_disarm_senderrbufs(struct ipath_devdata *);
struct file_operations;
-int ipath_cdev_init(int minor, char *name, struct file_operations *fops,
+int ipath_cdev_init(int minor, char *name, const struct file_operations *fops,
struct cdev **cdevp, struct class_device **class_devp);
void ipath_cdev_cleanup(struct cdev **cdevp,
struct class_device **class_devp);
diff --git a/drivers/infiniband/hw/ipath/ipath_qp.c b/drivers/infiniband/hw/ipath/ipath_qp.c
index 46c1c89bf6a..64f07b19349 100644
--- a/drivers/infiniband/hw/ipath/ipath_qp.c
+++ b/drivers/infiniband/hw/ipath/ipath_qp.c
@@ -379,7 +379,7 @@ void ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err)
wc.vendor_err = 0;
wc.byte_len = 0;
wc.imm_data = 0;
- wc.qp_num = qp->ibqp.qp_num;
+ wc.qp = &qp->ibqp;
wc.src_qp = 0;
wc.wc_flags = 0;
wc.pkey_index = 0;
diff --git a/drivers/infiniband/hw/ipath/ipath_rc.c b/drivers/infiniband/hw/ipath/ipath_rc.c
index ce6038743c5..5ff20cb0449 100644
--- a/drivers/infiniband/hw/ipath/ipath_rc.c
+++ b/drivers/infiniband/hw/ipath/ipath_rc.c
@@ -702,7 +702,7 @@ void ipath_restart_rc(struct ipath_qp *qp, u32 psn, struct ib_wc *wc)
wc->opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
wc->vendor_err = 0;
wc->byte_len = 0;
- wc->qp_num = qp->ibqp.qp_num;
+ wc->qp = &qp->ibqp;
wc->src_qp = qp->remote_qpn;
wc->pkey_index = 0;
wc->slid = qp->remote_ah_attr.dlid;
@@ -836,7 +836,7 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode)
wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
wc.vendor_err = 0;
wc.byte_len = wqe->length;
- wc.qp_num = qp->ibqp.qp_num;
+ wc.qp = &qp->ibqp;
wc.src_qp = qp->remote_qpn;
wc.pkey_index = 0;
wc.slid = qp->remote_ah_attr.dlid;
@@ -951,7 +951,7 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode)
wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
wc.vendor_err = 0;
wc.byte_len = 0;
- wc.qp_num = qp->ibqp.qp_num;
+ wc.qp = &qp->ibqp;
wc.src_qp = qp->remote_qpn;
wc.pkey_index = 0;
wc.slid = qp->remote_ah_attr.dlid;
@@ -1511,7 +1511,7 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
wc.status = IB_WC_SUCCESS;
wc.opcode = IB_WC_RECV;
wc.vendor_err = 0;
- wc.qp_num = qp->ibqp.qp_num;
+ wc.qp = &qp->ibqp;
wc.src_qp = qp->remote_qpn;
wc.pkey_index = 0;
wc.slid = qp->remote_ah_attr.dlid;
diff --git a/drivers/infiniband/hw/ipath/ipath_ruc.c b/drivers/infiniband/hw/ipath/ipath_ruc.c
index f7530512045..e86cb171872 100644
--- a/drivers/infiniband/hw/ipath/ipath_ruc.c
+++ b/drivers/infiniband/hw/ipath/ipath_ruc.c
@@ -137,7 +137,7 @@ bad_lkey:
wc.vendor_err = 0;
wc.byte_len = 0;
wc.imm_data = 0;
- wc.qp_num = qp->ibqp.qp_num;
+ wc.qp = &qp->ibqp;
wc.src_qp = 0;
wc.wc_flags = 0;
wc.pkey_index = 0;
@@ -336,7 +336,7 @@ again:
wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
wc.vendor_err = 0;
wc.byte_len = 0;
- wc.qp_num = sqp->ibqp.qp_num;
+ wc.qp = &sqp->ibqp;
wc.src_qp = sqp->remote_qpn;
wc.pkey_index = 0;
wc.slid = sqp->remote_ah_attr.dlid;
@@ -426,7 +426,7 @@ again:
wc.status = IB_WC_SUCCESS;
wc.vendor_err = 0;
wc.byte_len = wqe->length;
- wc.qp_num = qp->ibqp.qp_num;
+ wc.qp = &qp->ibqp;
wc.src_qp = qp->remote_qpn;
/* XXX do we know which pkey matched? Only needed for GSI. */
wc.pkey_index = 0;
@@ -447,7 +447,7 @@ send_comp:
wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
wc.vendor_err = 0;
wc.byte_len = wqe->length;
- wc.qp_num = sqp->ibqp.qp_num;
+ wc.qp = &sqp->ibqp;
wc.src_qp = 0;
wc.pkey_index = 0;
wc.slid = 0;
diff --git a/drivers/infiniband/hw/ipath/ipath_uc.c b/drivers/infiniband/hw/ipath/ipath_uc.c
index e636cfd67a8..325d6634ff5 100644
--- a/drivers/infiniband/hw/ipath/ipath_uc.c
+++ b/drivers/infiniband/hw/ipath/ipath_uc.c
@@ -49,7 +49,7 @@ static void complete_last_send(struct ipath_qp *qp, struct ipath_swqe *wqe,
wc->opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
wc->vendor_err = 0;
wc->byte_len = wqe->length;
- wc->qp_num = qp->ibqp.qp_num;
+ wc->qp = &qp->ibqp;
wc->src_qp = qp->remote_qpn;
wc->pkey_index = 0;
wc->slid = qp->remote_ah_attr.dlid;
@@ -411,7 +411,7 @@ void ipath_uc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
wc.status = IB_WC_SUCCESS;
wc.opcode = IB_WC_RECV;
wc.vendor_err = 0;
- wc.qp_num = qp->ibqp.qp_num;
+ wc.qp = &qp->ibqp;
wc.src_qp = qp->remote_qpn;
wc.pkey_index = 0;
wc.slid = qp->remote_ah_attr.dlid;
diff --git a/drivers/infiniband/hw/ipath/ipath_ud.c b/drivers/infiniband/hw/ipath/ipath_ud.c
index 49f1102af8b..9a3e54664ee 100644
--- a/drivers/infiniband/hw/ipath/ipath_ud.c
+++ b/drivers/infiniband/hw/ipath/ipath_ud.c
@@ -66,7 +66,7 @@ bad_lkey:
wc.vendor_err = 0;
wc.byte_len = 0;
wc.imm_data = 0;
- wc.qp_num = qp->ibqp.qp_num;
+ wc.qp = &qp->ibqp;
wc.src_qp = 0;
wc.wc_flags = 0;
wc.pkey_index = 0;
@@ -255,7 +255,7 @@ static void ipath_ud_loopback(struct ipath_qp *sqp,
wc->status = IB_WC_SUCCESS;
wc->opcode = IB_WC_RECV;
wc->vendor_err = 0;
- wc->qp_num = qp->ibqp.qp_num;
+ wc->qp = &qp->ibqp;
wc->src_qp = sqp->ibqp.qp_num;
/* XXX do we know which pkey matched? Only needed for GSI. */
wc->pkey_index = 0;
@@ -474,7 +474,7 @@ done:
wc.vendor_err = 0;
wc.opcode = IB_WC_SEND;
wc.byte_len = len;
- wc.qp_num = qp->ibqp.qp_num;
+ wc.qp = &qp->ibqp;
wc.src_qp = 0;
wc.wc_flags = 0;
/* XXX initialize other fields? */
@@ -651,7 +651,7 @@ void ipath_ud_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
wc.status = IB_WC_SUCCESS;
wc.opcode = IB_WC_RECV;
wc.vendor_err = 0;
- wc.qp_num = qp->ibqp.qp_num;
+ wc.qp = &qp->ibqp;
wc.src_qp = src_qp;
/* XXX do we know which pkey matched? Only needed for GSI. */
wc.pkey_index = 0;
diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.c b/drivers/infiniband/hw/mthca/mthca_cmd.c
index 768df7265b8..71314460b11 100644
--- a/drivers/infiniband/hw/mthca/mthca_cmd.c
+++ b/drivers/infiniband/hw/mthca/mthca_cmd.c
@@ -1051,7 +1051,11 @@ int mthca_QUERY_DEV_LIM(struct mthca_dev *dev,
MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_EQ_OFFSET);
dev_lim->max_eqs = 1 << (field & 0x7);
MTHCA_GET(field, outbox, QUERY_DEV_LIM_RSVD_MTT_OFFSET);
- dev_lim->reserved_mtts = 1 << (field >> 4);
+ if (mthca_is_memfree(dev))
+ dev_lim->reserved_mtts = ALIGN((1 << (field >> 4)) * sizeof(u64),
+ MTHCA_MTT_SEG_SIZE) / MTHCA_MTT_SEG_SIZE;
+ else
+ dev_lim->reserved_mtts = 1 << (field >> 4);
MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_MRW_SZ_OFFSET);
dev_lim->max_mrw_sz = 1 << field;
MTHCA_GET(field, outbox, QUERY_DEV_LIM_RSVD_MRW_OFFSET);
@@ -1854,7 +1858,7 @@ int mthca_MAD_IFC(struct mthca_dev *dev, int ignore_mkey, int ignore_bkey,
memset(inbox + 256, 0, 256);
- MTHCA_PUT(inbox, in_wc->qp_num, MAD_IFC_MY_QPN_OFFSET);
+ MTHCA_PUT(inbox, in_wc->qp->qp_num, MAD_IFC_MY_QPN_OFFSET);
MTHCA_PUT(inbox, in_wc->src_qp, MAD_IFC_RQPN_OFFSET);
val = in_wc->sl << 4;
diff --git a/drivers/infiniband/hw/mthca/mthca_cq.c b/drivers/infiniband/hw/mthca/mthca_cq.c
index 1159c8a0f2c..efd79ef109a 100644
--- a/drivers/infiniband/hw/mthca/mthca_cq.c
+++ b/drivers/infiniband/hw/mthca/mthca_cq.c
@@ -534,7 +534,7 @@ static inline int mthca_poll_one(struct mthca_dev *dev,
}
}
- entry->qp_num = (*cur_qp)->qpn;
+ entry->qp = &(*cur_qp)->ibqp;
if (is_send) {
wq = &(*cur_qp)->sq;
diff --git a/drivers/infiniband/hw/mthca/mthca_dev.h b/drivers/infiniband/hw/mthca/mthca_dev.h
index fe5cecf70fe..b7e42efaf43 100644
--- a/drivers/infiniband/hw/mthca/mthca_dev.h
+++ b/drivers/infiniband/hw/mthca/mthca_dev.h
@@ -464,6 +464,8 @@ void mthca_uar_free(struct mthca_dev *dev, struct mthca_uar *uar);
int mthca_pd_alloc(struct mthca_dev *dev, int privileged, struct mthca_pd *pd);
void mthca_pd_free(struct mthca_dev *dev, struct mthca_pd *pd);
+int mthca_write_mtt_size(struct mthca_dev *dev);
+
struct mthca_mtt *mthca_alloc_mtt(struct mthca_dev *dev, int size);
void mthca_free_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt);
int mthca_write_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt,
diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c
index 44bc6cc734a..0d9b7d06bbc 100644
--- a/drivers/infiniband/hw/mthca/mthca_main.c
+++ b/drivers/infiniband/hw/mthca/mthca_main.c
@@ -379,7 +379,7 @@ static int mthca_load_fw(struct mthca_dev *mdev)
mdev->fw.arbel.fw_icm =
mthca_alloc_icm(mdev, mdev->fw.arbel.fw_pages,
- GFP_HIGHUSER | __GFP_NOWARN);
+ GFP_HIGHUSER | __GFP_NOWARN, 0);
if (!mdev->fw.arbel.fw_icm) {
mthca_err(mdev, "Couldn't allocate FW area, aborting.\n");
return -ENOMEM;
@@ -412,7 +412,7 @@ err_unmap_fa:
mthca_UNMAP_FA(mdev, &status);
err_free:
- mthca_free_icm(mdev, mdev->fw.arbel.fw_icm);
+ mthca_free_icm(mdev, mdev->fw.arbel.fw_icm, 0);
return err;
}
@@ -441,7 +441,7 @@ static int mthca_init_icm(struct mthca_dev *mdev,
(unsigned long long) aux_pages << 2);
mdev->fw.arbel.aux_icm = mthca_alloc_icm(mdev, aux_pages,
- GFP_HIGHUSER | __GFP_NOWARN);
+ GFP_HIGHUSER | __GFP_NOWARN, 0);
if (!mdev->fw.arbel.aux_icm) {
mthca_err(mdev, "Couldn't allocate aux memory, aborting.\n");
return -ENOMEM;
@@ -464,10 +464,15 @@ static int mthca_init_icm(struct mthca_dev *mdev,
goto err_unmap_aux;
}
+ /* CPU writes to non-reserved MTTs, while HCA might DMA to reserved mtts */
+ mdev->limits.reserved_mtts = ALIGN(mdev->limits.reserved_mtts * MTHCA_MTT_SEG_SIZE,
+ dma_get_cache_alignment()) / MTHCA_MTT_SEG_SIZE;
+
mdev->mr_table.mtt_table = mthca_alloc_icm_table(mdev, init_hca->mtt_base,
MTHCA_MTT_SEG_SIZE,
mdev->limits.num_mtt_segs,
- mdev->limits.reserved_mtts, 1);
+ mdev->limits.reserved_mtts,
+ 1, 0);
if (!mdev->mr_table.mtt_table) {
mthca_err(mdev, "Failed to map MTT context memory, aborting.\n");
err = -ENOMEM;
@@ -477,7 +482,8 @@ static int mthca_init_icm(struct mthca_dev *mdev,
mdev->mr_table.mpt_table = mthca_alloc_icm_table(mdev, init_hca->mpt_base,
dev_lim->mpt_entry_sz,
mdev->limits.num_mpts,
- mdev->limits.reserved_mrws, 1);
+ mdev->limits.reserved_mrws,
+ 1, 1);
if (!mdev->mr_table.mpt_table) {
mthca_err(mdev, "Failed to map MPT context memory, aborting.\n");
err = -ENOMEM;
@@ -487,7 +493,8 @@ static int mthca_init_icm(struct mthca_dev *mdev,
mdev->qp_table.qp_table = mthca_alloc_icm_table(mdev, init_hca->qpc_base,
dev_lim->qpc_entry_sz,
mdev->limits.num_qps,
- mdev->limits.reserved_qps, 0);
+ mdev->limits.reserved_qps,
+ 0, 0);
if (!mdev->qp_table.qp_table) {
mthca_err(mdev, "Failed to map QP context memory, aborting.\n");
err = -ENOMEM;
@@ -497,7 +504,8 @@ static int mthca_init_icm(struct mthca_dev *mdev,
mdev->qp_table.eqp_table = mthca_alloc_icm_table(mdev, init_hca->eqpc_base,
dev_lim->eqpc_entry_sz,
mdev->limits.num_qps,
- mdev->limits.reserved_qps, 0);
+ mdev->limits.reserved_qps,
+ 0, 0);
if (!mdev->qp_table.eqp_table) {
mthca_err(mdev, "Failed to map EQP context memory, aborting.\n");
err = -ENOMEM;
@@ -507,7 +515,7 @@ static int mthca_init_icm(struct mthca_dev *mdev,
mdev->qp_table.rdb_table = mthca_alloc_icm_table(mdev, init_hca->rdb_base,
MTHCA_RDB_ENTRY_SIZE,
mdev->limits.num_qps <<
- mdev->qp_table.rdb_shift,
+ mdev->qp_table.rdb_shift, 0,
0, 0);
if (!mdev->qp_table.rdb_table) {
mthca_err(mdev, "Failed to map RDB context memory, aborting\n");
@@ -518,7 +526,8 @@ static int mthca_init_icm(struct mthca_dev *mdev,
mdev->cq_table.table = mthca_alloc_icm_table(mdev, init_hca->cqc_base,
dev_lim->cqc_entry_sz,
mdev->limits.num_cqs,
- mdev->limits.reserved_cqs, 0);
+ mdev->limits.reserved_cqs,
+ 0, 0);
if (!mdev->cq_table.table) {
mthca_err(mdev, "Failed to map CQ context memory, aborting.\n");
err = -ENOMEM;
@@ -530,7 +539,8 @@ static int mthca_init_icm(struct mthca_dev *mdev,
mthca_alloc_icm_table(mdev, init_hca->srqc_base,
dev_lim->srq_entry_sz,
mdev->limits.num_srqs,
- mdev->limits.reserved_srqs, 0);
+ mdev->limits.reserved_srqs,
+ 0, 0);
if (!mdev->srq_table.table) {
mthca_err(mdev, "Failed to map SRQ context memory, "
"aborting.\n");
@@ -550,7 +560,7 @@ static int mthca_init_icm(struct mthca_dev *mdev,
mdev->limits.num_amgms,
mdev->limits.num_mgms +
mdev->limits.num_amgms,
- 0);
+ 0, 0);
if (!mdev->mcg_table.table) {
mthca_err(mdev, "Failed to map MCG context memory, aborting.\n");
err = -ENOMEM;
@@ -588,7 +598,7 @@ err_unmap_aux:
mthca_UNMAP_ICM_AUX(mdev, &status);
err_free_aux:
- mthca_free_icm(mdev, mdev->fw.arbel.aux_icm);
+ mthca_free_icm(mdev, mdev->fw.arbel.aux_icm, 0);
return err;
}
@@ -609,7 +619,7 @@ static void mthca_free_icms(struct mthca_dev *mdev)
mthca_unmap_eq_icm(mdev);
mthca_UNMAP_ICM_AUX(mdev, &status);
- mthca_free_icm(mdev, mdev->fw.arbel.aux_icm);
+ mthca_free_icm(mdev, mdev->fw.arbel.aux_icm, 0);
}
static int mthca_init_arbel(struct mthca_dev *mdev)
@@ -693,7 +703,7 @@ err_free_icm:
err_stop_fw:
mthca_UNMAP_FA(mdev, &status);
- mthca_free_icm(mdev, mdev->fw.arbel.fw_icm);
+ mthca_free_icm(mdev, mdev->fw.arbel.fw_icm, 0);
err_disable:
if (!(mdev->mthca_flags & MTHCA_FLAG_NO_LAM))
@@ -712,7 +722,7 @@ static void mthca_close_hca(struct mthca_dev *mdev)
mthca_free_icms(mdev);
mthca_UNMAP_FA(mdev, &status);
- mthca_free_icm(mdev, mdev->fw.arbel.fw_icm);
+ mthca_free_icm(mdev, mdev->fw.arbel.fw_icm, 0);
if (!(mdev->mthca_flags & MTHCA_FLAG_NO_LAM))
mthca_DISABLE_LAM(mdev, &status);
diff --git a/drivers/infiniband/hw/mthca/mthca_memfree.c b/drivers/infiniband/hw/mthca/mthca_memfree.c
index 6b19645d946..48f7c65e9ae 100644
--- a/drivers/infiniband/hw/mthca/mthca_memfree.c
+++ b/drivers/infiniband/hw/mthca/mthca_memfree.c
@@ -35,6 +35,9 @@
*/
#include <linux/mm.h>
+#include <linux/scatterlist.h>
+
+#include <asm/page.h>
#include "mthca_memfree.h"
#include "mthca_dev.h"
@@ -58,22 +61,42 @@ struct mthca_user_db_table {
} page[0];
};
-void mthca_free_icm(struct mthca_dev *dev, struct mthca_icm *icm)
+static void mthca_free_icm_pages(struct mthca_dev *dev, struct mthca_icm_chunk *chunk)
+{
+ int i;
+
+ if (chunk->nsg > 0)
+ pci_unmap_sg(dev->pdev, chunk->mem, chunk->npages,
+ PCI_DMA_BIDIRECTIONAL);
+
+ for (i = 0; i < chunk->npages; ++i)
+ __free_pages(chunk->mem[i].page,
+ get_order(chunk->mem[i].length));
+}
+
+static void mthca_free_icm_coherent(struct mthca_dev *dev, struct mthca_icm_chunk *chunk)
{
- struct mthca_icm_chunk *chunk, *tmp;
int i;
+ for (i = 0; i < chunk->npages; ++i) {
+ dma_free_coherent(&dev->pdev->dev, chunk->mem[i].length,
+ lowmem_page_address(chunk->mem[i].page),
+ sg_dma_address(&chunk->mem[i]));
+ }
+}
+
+void mthca_free_icm(struct mthca_dev *dev, struct mthca_icm *icm, int coherent)
+{
+ struct mthca_icm_chunk *chunk, *tmp;
+
if (!icm)
return;
list_for_each_entry_safe(chunk, tmp, &icm->chunk_list, list) {
- if (chunk->nsg > 0)
- pci_unmap_sg(dev->pdev, chunk->mem, chunk->npages,
- PCI_DMA_BIDIRECTIONAL);
-
- for (i = 0; i < chunk->npages; ++i)
- __free_pages(chunk->mem[i].page,
- get_order(chunk->mem[i].length));
+ if (coherent)
+ mthca_free_icm_coherent(dev, chunk);
+ else
+ mthca_free_icm_pages(dev, chunk);
kfree(chunk);
}
@@ -81,12 +104,41 @@ void mthca_free_icm(struct mthca_dev *dev, struct mthca_icm *icm)
kfree(icm);
}
+static int mthca_alloc_icm_pages(struct scatterlist *mem, int order, gfp_t gfp_mask)
+{
+ mem->page = alloc_pages(gfp_mask, order);
+ if (!mem->page)
+ return -ENOMEM;
+
+ mem->length = PAGE_SIZE << order;
+ mem->offset = 0;
+ return 0;
+}
+
+static int mthca_alloc_icm_coherent(struct device *dev, struct scatterlist *mem,
+ int order, gfp_t gfp_mask)
+{
+ void *buf = dma_alloc_coherent(dev, PAGE_SIZE << order, &sg_dma_address(mem),
+ gfp_mask);
+ if (!buf)
+ return -ENOMEM;
+
+ sg_set_buf(mem, buf, PAGE_SIZE << order);
+ BUG_ON(mem->offset);
+ sg_dma_len(mem) = PAGE_SIZE << order;
+ return 0;
+}
+
struct mthca_icm *mthca_alloc_icm(struct mthca_dev *dev, int npages,
- gfp_t gfp_mask)
+ gfp_t gfp_mask, int coherent)
{
struct mthca_icm *icm;
struct mthca_icm_chunk *chunk = NULL;
int cur_order;
+ int ret;
+
+ /* We use sg_set_buf for coherent allocs, which assumes low memory */
+ BUG_ON(coherent && (gfp_mask & __GFP_HIGHMEM));
icm = kmalloc(sizeof *icm, gfp_mask & ~(__GFP_HIGHMEM | __GFP_NOWARN));
if (!icm)
@@ -112,21 +164,30 @@ struct mthca_icm *mthca_alloc_icm(struct mthca_dev *dev, int npages,
while (1 << cur_order > npages)
--cur_order;
- chunk->mem[chunk->npages].page = alloc_pages(gfp_mask, cur_order);
- if (chunk->mem[chunk->npages].page) {
- chunk->mem[chunk->npages].length = PAGE_SIZE << cur_order;
- chunk->mem[chunk->npages].offset = 0;
+ if (coherent)
+ ret = mthca_alloc_icm_coherent(&dev->pdev->dev,
+ &chunk->mem[chunk->npages],
+ cur_order, gfp_mask);
+ else
+ ret = mthca_alloc_icm_pages(&chunk->mem[chunk->npages],
+ cur_order, gfp_mask);
- if (++chunk->npages == MTHCA_ICM_CHUNK_LEN) {
+ if (!ret) {
+ ++chunk->npages;
+
+ if (coherent)
+ ++chunk->nsg;
+ else if (chunk->npages == MTHCA_ICM_CHUNK_LEN) {
chunk->nsg = pci_map_sg(dev->pdev, chunk->mem,
chunk->npages,
PCI_DMA_BIDIRECTIONAL);
if (chunk->nsg <= 0)
goto fail;
+ }
+ if (chunk->npages == MTHCA_ICM_CHUNK_LEN)
chunk = NULL;
- }
npages -= 1 << cur_order;
} else {
@@ -136,7 +197,7 @@ struct mthca_icm *mthca_alloc_icm(struct mthca_dev *dev, int npages,
}
}
- if (chunk) {
+ if (!coherent && chunk) {
chunk->nsg = pci_map_sg(dev->pdev, chunk->mem,
chunk->npages,
PCI_DMA_BIDIRECTIONAL);
@@ -148,7 +209,7 @@ struct mthca_icm *mthca_alloc_icm(struct mthca_dev *dev, int npages,
return icm;
fail:
- mthca_free_icm(dev, icm);
+ mthca_free_icm(dev, icm, coherent);
return NULL;
}
@@ -167,7 +228,7 @@ int mthca_table_get(struct mthca_dev *dev, struct mthca_icm_table *table, int ob
table->icm[i] = mthca_alloc_icm(dev, MTHCA_TABLE_CHUNK_SIZE >> PAGE_SHIFT,
(table->lowmem ? GFP_KERNEL : GFP_HIGHUSER) |
- __GFP_NOWARN);
+ __GFP_NOWARN, table->coherent);
if (!table->icm[i]) {
ret = -ENOMEM;
goto out;
@@ -175,7 +236,7 @@ int mthca_table_get(struct mthca_dev *dev, struct mthca_icm_table *table, int ob
if (mthca_MAP_ICM(dev, table->icm[i], table->virt + i * MTHCA_TABLE_CHUNK_SIZE,
&status) || status) {
- mthca_free_icm(dev, table->icm[i]);
+ mthca_free_icm(dev, table->icm[i], table->coherent);
table->icm[i] = NULL;
ret = -ENOMEM;
goto out;
@@ -204,16 +265,16 @@ void mthca_table_put(struct mthca_dev *dev, struct mthca_icm_table *table, int o
mthca_UNMAP_ICM(dev, table->virt + i * MTHCA_TABLE_CHUNK_SIZE,
MTHCA_TABLE_CHUNK_SIZE / MTHCA_ICM_PAGE_SIZE,
&status);
- mthca_free_icm(dev, table->icm[i]);
+ mthca_free_icm(dev, table->icm[i], table->coherent);
table->icm[i] = NULL;
}
mutex_unlock(&table->mutex);
}
-void *mthca_table_find(struct mthca_icm_table *table, int obj)
+void *mthca_table_find(struct mthca_icm_table *table, int obj, dma_addr_t *dma_handle)
{
- int idx, offset, i;
+ int idx, offset, dma_offset, i;
struct mthca_icm_chunk *chunk;
struct mthca_icm *icm;
struct page *page = NULL;
@@ -225,13 +286,22 @@ void *mthca_table_find(struct mthca_icm_table *table, int obj)
idx = (obj & (table->num_obj - 1)) * table->obj_size;
icm = table->icm[idx / MTHCA_TABLE_CHUNK_SIZE];
- offset = idx % MTHCA_TABLE_CHUNK_SIZE;
+ dma_offset = offset = idx % MTHCA_TABLE_CHUNK_SIZE;
if (!icm)
goto out;
list_for_each_entry(chunk, &icm->chunk_list, list) {
for (i = 0; i < chunk->npages; ++i) {
+ if (dma_handle && dma_offset >= 0) {
+ if (sg_dma_len(&chunk->mem[i]) > dma_offset)
+ *dma_handle = sg_dma_address(&chunk->mem[i]) +
+ dma_offset;
+ dma_offset -= sg_dma_len(&chunk->mem[i]);
+ }
+ /* DMA mapping can merge pages but not split them,
+ * so if we found the page, dma_handle has already
+ * been assigned to. */
if (chunk->mem[i].length > offset) {
page = chunk->mem[i].page;
goto out;
@@ -283,7 +353,7 @@ void mthca_table_put_range(struct mthca_dev *dev, struct mthca_icm_table *table,
struct mthca_icm_table *mthca_alloc_icm_table(struct mthca_dev *dev,
u64 virt, int obj_size,
int nobj, int reserved,
- int use_lowmem)
+ int use_lowmem, int use_coherent)
{
struct mthca_icm_table *table;
int num_icm;
@@ -302,6 +372,7 @@ struct mthca_icm_table *mthca_alloc_icm_table(struct mthca_dev *dev,
table->num_obj = nobj;
table->obj_size = obj_size;
table->lowmem = use_lowmem;
+ table->coherent = use_coherent;
mutex_init(&table->mutex);
for (i = 0; i < num_icm; ++i)
@@ -314,12 +385,12 @@ struct mthca_icm_table *mthca_alloc_icm_table(struct mthca_dev *dev,
table->icm[i] = mthca_alloc_icm(dev, chunk_size >> PAGE_SHIFT,
(use_lowmem ? GFP_KERNEL : GFP_HIGHUSER) |
- __GFP_NOWARN);
+ __GFP_NOWARN, use_coherent);
if (!table->icm[i])
goto err;
if (mthca_MAP_ICM(dev, table->icm[i], virt + i * MTHCA_TABLE_CHUNK_SIZE,
&status) || status) {
- mthca_free_icm(dev, table->icm[i]);
+ mthca_free_icm(dev, table->icm[i], table->coherent);
table->icm[i] = NULL;
goto err;
}
@@ -339,7 +410,7 @@ err:
mthca_UNMAP_ICM(dev, virt + i * MTHCA_TABLE_CHUNK_SIZE,
MTHCA_TABLE_CHUNK_SIZE / MTHCA_ICM_PAGE_SIZE,
&status);
- mthca_free_icm(dev, table->icm[i]);
+ mthca_free_icm(dev, table->icm[i], table->coherent);
}
kfree(table);
@@ -357,7 +428,7 @@ void mthca_free_icm_table(struct mthca_dev *dev, struct mthca_icm_table *table)
mthca_UNMAP_ICM(dev, table->virt + i * MTHCA_TABLE_CHUNK_SIZE,
MTHCA_TABLE_CHUNK_SIZE / MTHCA_ICM_PAGE_SIZE,
&status);
- mthca_free_icm(dev, table->icm[i]);
+ mthca_free_icm(dev, table->icm[i], table->coherent);
}
kfree(table);
diff --git a/drivers/infiniband/hw/mthca/mthca_memfree.h b/drivers/infiniband/hw/mthca/mthca_memfree.h
index 6d42947e1dc..594144145f4 100644
--- a/drivers/infiniband/hw/mthca/mthca_memfree.h
+++ b/drivers/infiniband/hw/mthca/mthca_memfree.h
@@ -69,6 +69,7 @@ struct mthca_icm_table {
int num_obj;
int obj_size;
int lowmem;
+ int coherent;
struct mutex mutex;
struct mthca_icm *icm[0];
};
@@ -82,17 +83,17 @@ struct mthca_icm_iter {
struct mthca_dev;
struct mthca_icm *mthca_alloc_icm(struct mthca_dev *dev, int npages,
- gfp_t gfp_mask);
-void mthca_free_icm(struct mthca_dev *dev, struct mthca_icm *icm);
+ gfp_t gfp_mask, int coherent);
+void mthca_free_icm(struct mthca_dev *dev, struct mthca_icm *icm, int coherent);
struct mthca_icm_table *mthca_alloc_icm_table(struct mthca_dev *dev,
u64 virt, int obj_size,
int nobj, int reserved,
- int use_lowmem);
+ int use_lowmem, int use_coherent);
void mthca_free_icm_table(struct mthca_dev *dev, struct mthca_icm_table *table);
int mthca_table_get(struct mthca_dev *dev, struct mthca_icm_table *table, int obj);
void mthca_table_put(struct mthca_dev *dev, struct mthca_icm_table *table, int obj);
-void *mthca_table_find(struct mthca_icm_table *table, int obj);
+void *mthca_table_find(struct mthca_icm_table *table, int obj, dma_addr_t *dma_handle);
int mthca_table_get_range(struct mthca_dev *dev, struct mthca_icm_table *table,
int start, int end);
void mthca_table_put_range(struct mthca_dev *dev, struct mthca_icm_table *table,
diff --git a/drivers/infiniband/hw/mthca/mthca_mr.c b/drivers/infiniband/hw/mthca/mthca_mr.c
index f71ffa88db3..6037dd3f87d 100644
--- a/drivers/infiniband/hw/mthca/mthca_mr.c
+++ b/drivers/infiniband/hw/mthca/mthca_mr.c
@@ -243,8 +243,8 @@ void mthca_free_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt)
kfree(mtt);
}
-int mthca_write_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt,
- int start_index, u64 *buffer_list, int list_len)
+static int __mthca_write_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt,
+ int start_index, u64 *buffer_list, int list_len)
{
struct mthca_mailbox *mailbox;
__be64 *mtt_entry;
@@ -295,6 +295,84 @@ out:
return err;
}
+int mthca_write_mtt_size(struct mthca_dev *dev)
+{
+ if (dev->mr_table.fmr_mtt_buddy != &dev->mr_table.mtt_buddy)
+ /*
+ * Be friendly to WRITE_MTT command
+ * and leave two empty slots for the
+ * index and reserved fields of the
+ * mailbox.
+ */
+ return PAGE_SIZE / sizeof (u64) - 2;
+
+ /* For Arbel, all MTTs must fit in the same page. */
+ return mthca_is_memfree(dev) ? (PAGE_SIZE / sizeof (u64)) : 0x7ffffff;
+}
+
+void mthca_tavor_write_mtt_seg(struct mthca_dev *dev, struct mthca_mtt *mtt,
+ int start_index, u64 *buffer_list, int list_len)
+{
+ u64 __iomem *mtts;
+ int i;
+
+ mtts = dev->mr_table.tavor_fmr.mtt_base + mtt->first_seg * MTHCA_MTT_SEG_SIZE +
+ start_index * sizeof (u64);
+ for (i = 0; i < list_len; ++i)
+ mthca_write64_raw(cpu_to_be64(buffer_list[i] | MTHCA_MTT_FLAG_PRESENT),
+ mtts + i);
+}
+
+void mthca_arbel_write_mtt_seg(struct mthca_dev *dev, struct mthca_mtt *mtt,
+ int start_index, u64 *buffer_list, int list_len)
+{
+ __be64 *mtts;
+ dma_addr_t dma_handle;
+ int i;
+ int s = start_index * sizeof (u64);
+
+ /* For Arbel, all MTTs must fit in the same page. */
+ BUG_ON(s / PAGE_SIZE != (s + list_len * sizeof(u64) - 1) / PAGE_SIZE);
+ /* Require full segments */
+ BUG_ON(s % MTHCA_MTT_SEG_SIZE);
+
+ mtts = mthca_table_find(dev->mr_table.mtt_table, mtt->first_seg +
+ s / MTHCA_MTT_SEG_SIZE, &dma_handle);
+
+ BUG_ON(!mtts);
+
+ for (i = 0; i < list_len; ++i)
+ mtts[i] = cpu_to_be64(buffer_list[i] | MTHCA_MTT_FLAG_PRESENT);
+
+ dma_sync_single(&dev->pdev->dev, dma_handle, list_len * sizeof (u64), DMA_TO_DEVICE);
+}
+
+int mthca_write_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt,
+ int start_index, u64 *buffer_list, int list_len)
+{
+ int size = mthca_write_mtt_size(dev);
+ int chunk;
+
+ if (dev->mr_table.fmr_mtt_buddy != &dev->mr_table.mtt_buddy)
+ return __mthca_write_mtt(dev, mtt, start_index, buffer_list, list_len);
+
+ while (list_len > 0) {
+ chunk = min(size, list_len);
+ if (mthca_is_memfree(dev))
+ mthca_arbel_write_mtt_seg(dev, mtt, start_index,
+ buffer_list, chunk);
+ else
+ mthca_tavor_write_mtt_seg(dev, mtt, start_index,
+ buffer_list, chunk);
+
+ list_len -= chunk;
+ start_index += chunk;
+ buffer_list += chunk;
+ }
+
+ return 0;
+}
+
static inline u32 tavor_hw_index_to_key(u32 ind)
{
return ind;
@@ -524,7 +602,7 @@ int mthca_fmr_alloc(struct mthca_dev *dev, u32 pd,
if (err)
goto err_out_mpt_free;
- mr->mem.arbel.mpt = mthca_table_find(dev->mr_table.mpt_table, key);
+ mr->mem.arbel.mpt = mthca_table_find(dev->mr_table.mpt_table, key, NULL);
BUG_ON(!mr->mem.arbel.mpt);
} else
mr->mem.tavor.mpt = dev->mr_table.tavor_fmr.mpt_base +
@@ -538,7 +616,8 @@ int mthca_fmr_alloc(struct mthca_dev *dev, u32 pd,
if (mthca_is_memfree(dev)) {
mr->mem.arbel.mtts = mthca_table_find(dev->mr_table.mtt_table,
- mr->mtt->first_seg);
+ mr->mtt->first_seg,
+ &mr->mem.arbel.dma_handle);
BUG_ON(!mr->mem.arbel.mtts);
} else
mr->mem.tavor.mtts = dev->mr_table.tavor_fmr.mtt_base + mtt_seg;
@@ -712,6 +791,9 @@ int mthca_arbel_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list,
fmr->mem.arbel.mtts[i] = cpu_to_be64(page_list[i] |
MTHCA_MTT_FLAG_PRESENT);
+ dma_sync_single(&dev->pdev->dev, fmr->mem.arbel.dma_handle,
+ list_len * sizeof(u64), DMA_TO_DEVICE);
+
fmr->mem.arbel.mpt->key = cpu_to_be32(key);
fmr->mem.arbel.mpt->lkey = cpu_to_be32(key);
fmr->mem.arbel.mpt->length = cpu_to_be64(list_len * (1ull << fmr->attr.page_shift));
@@ -761,7 +843,7 @@ void mthca_arbel_fmr_unmap(struct mthca_dev *dev, struct mthca_fmr *fmr)
int mthca_init_mr_table(struct mthca_dev *dev)
{
unsigned long addr;
- int err, i;
+ int mpts, mtts, err, i;
err = mthca_alloc_init(&dev->mr_table.mpt_alloc,
dev->limits.num_mpts,
@@ -795,13 +877,21 @@ int mthca_init_mr_table(struct mthca_dev *dev)
err = -EINVAL;
goto err_fmr_mpt;
}
+ mpts = mtts = 1 << i;
+ } else {
+ mpts = dev->limits.num_mtt_segs;
+ mtts = dev->limits.num_mpts;
+ }
+
+ if (!mthca_is_memfree(dev) &&
+ (dev->mthca_flags & MTHCA_FLAG_FMR)) {
addr = pci_resource_start(dev->pdev, 4) +
((pci_resource_len(dev->pdev, 4) - 1) &
dev->mr_table.mpt_base);
dev->mr_table.tavor_fmr.mpt_base =
- ioremap(addr, (1 << i) * sizeof(struct mthca_mpt_entry));
+ ioremap(addr, mpts * sizeof(struct mthca_mpt_entry));
if (!dev->mr_table.tavor_fmr.mpt_base) {
mthca_warn(dev, "MPT ioremap for FMR failed.\n");
@@ -814,19 +904,21 @@ int mthca_init_mr_table(struct mthca_dev *dev)
dev->mr_table.mtt_base);
dev->mr_table.tavor_fmr.mtt_base =
- ioremap(addr, (1 << i) * MTHCA_MTT_SEG_SIZE);
+ ioremap(addr, mtts * MTHCA_MTT_SEG_SIZE);
if (!dev->mr_table.tavor_fmr.mtt_base) {
mthca_warn(dev, "MTT ioremap for FMR failed.\n");
err = -ENOMEM;
goto err_fmr_mtt;
}
+ }
- err = mthca_buddy_init(&dev->mr_table.tavor_fmr.mtt_buddy, i);
+ if (dev->limits.fmr_reserved_mtts) {
+ err = mthca_buddy_init(&dev->mr_table.tavor_fmr.mtt_buddy, fls(mtts - 1));
if (err)
goto err_fmr_mtt_buddy;
/* Prevent regular MRs from using FMR keys */
- err = mthca_buddy_alloc(&dev->mr_table.mtt_buddy, i);
+ err = mthca_buddy_alloc(&dev->mr_table.mtt_buddy, fls(mtts - 1));
if (err)
goto err_reserve_fmr;
diff --git a/drivers/infiniband/hw/mthca/mthca_profile.c b/drivers/infiniband/hw/mthca/mthca_profile.c
index 58d44aa3c30..26bf86d1cfc 100644
--- a/drivers/infiniband/hw/mthca/mthca_profile.c
+++ b/drivers/infiniband/hw/mthca/mthca_profile.c
@@ -277,7 +277,7 @@ u64 mthca_make_profile(struct mthca_dev *dev,
* out of the MR pool. They don't use additional memory, but
* we assign them as part of the HCA profile anyway.
*/
- if (mthca_is_memfree(dev))
+ if (mthca_is_memfree(dev) || BITS_PER_LONG == 64)
dev->limits.fmr_reserved_mtts = 0;
else
dev->limits.fmr_reserved_mtts = request->fmr_reserved_mtts;
diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c
index 7b96751695e..0725ad7ad9b 100644
--- a/drivers/infiniband/hw/mthca/mthca_provider.c
+++ b/drivers/infiniband/hw/mthca/mthca_provider.c
@@ -1015,6 +1015,7 @@ static struct ib_mr *mthca_reg_user_mr(struct ib_pd *pd, struct ib_umem *region,
int shift, n, len;
int i, j, k;
int err = 0;
+ int write_mtt_size;
shift = ffs(region->page_size) - 1;
@@ -1040,6 +1041,8 @@ static struct ib_mr *mthca_reg_user_mr(struct ib_pd *pd, struct ib_umem *region,
i = n = 0;
+ write_mtt_size = min(mthca_write_mtt_size(dev), (int) (PAGE_SIZE / sizeof *pages));
+
list_for_each_entry(chunk, &region->chunk_list, list)
for (j = 0; j < chunk->nmap; ++j) {
len = sg_dma_len(&chunk->page_list[j]) >> shift;
@@ -1047,14 +1050,11 @@ static struct ib_mr *mthca_reg_user_mr(struct ib_pd *pd, struct ib_umem *region,
pages[i++] = sg_dma_address(&chunk->page_list[j]) +
region->page_size * k;
/*
- * Be friendly to WRITE_MTT command
- * and leave two empty slots for the
- * index and reserved fields of the
- * mailbox.
+ * Be friendly to write_mtt and pass it chunks
+ * of appropriate size.
*/
- if (i == PAGE_SIZE / sizeof (u64) - 2) {
- err = mthca_write_mtt(dev, mr->mtt,
- n, pages, i);
+ if (i == write_mtt_size) {
+ err = mthca_write_mtt(dev, mr->mtt, n, pages, i);
if (err)
goto mtt_done;
n += i;
diff --git a/drivers/infiniband/hw/mthca/mthca_provider.h b/drivers/infiniband/hw/mthca/mthca_provider.h
index 9a5bece3fa5..1d266ac2e09 100644
--- a/drivers/infiniband/hw/mthca/mthca_provider.h
+++ b/drivers/infiniband/hw/mthca/mthca_provider.h
@@ -89,6 +89,7 @@ struct mthca_fmr {
struct {
struct mthca_mpt_entry *mpt;
__be64 *mtts;
+ dma_addr_t dma_handle;
} arbel;
} mem;
};
diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c
index 5f5214c0337..71dc84bd425 100644
--- a/drivers/infiniband/hw/mthca/mthca_qp.c
+++ b/drivers/infiniband/hw/mthca/mthca_qp.c
@@ -399,7 +399,7 @@ static int to_ib_qp_access_flags(int mthca_flags)
static void to_ib_ah_attr(struct mthca_dev *dev, struct ib_ah_attr *ib_ah_attr,
struct mthca_qp_path *path)
{
- memset(ib_ah_attr, 0, sizeof *path);
+ memset(ib_ah_attr, 0, sizeof *ib_ah_attr);
ib_ah_attr->port_num = (be32_to_cpu(path->port_pkey) >> 24) & 0x3;
if (ib_ah_attr->port_num == 0 || ib_ah_attr->port_num > dev->limits.num_ports)
@@ -573,6 +573,11 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask,
goto out;
}
+ if (cur_state == new_state && cur_state == IB_QPS_RESET) {
+ err = 0;
+ goto out;
+ }
+
if ((attr_mask & IB_QP_PKEY_INDEX) &&
attr->pkey_index >= dev->limits.pkey_table_len) {
mthca_dbg(dev, "P_Key index (%u) too large. max is %d\n",
diff --git a/drivers/infiniband/hw/mthca/mthca_srq.c b/drivers/infiniband/hw/mthca/mthca_srq.c
index 10684da33d5..61974b0296c 100644
--- a/drivers/infiniband/hw/mthca/mthca_srq.c
+++ b/drivers/infiniband/hw/mthca/mthca_srq.c
@@ -116,11 +116,16 @@ static void mthca_arbel_init_srq_context(struct mthca_dev *dev,
struct mthca_srq *srq,
struct mthca_arbel_srq_context *context)
{
- int logsize;
+ int logsize, max;
memset(context, 0, sizeof *context);
- logsize = ilog2(srq->max);
+ /*
+ * Put max in a temporary variable to work around gcc bug
+ * triggered by ilog2() on sparc64.
+ */
+ max = srq->max;
+ logsize = ilog2(max);
context->state_logsize_srqn = cpu_to_be32(logsize << 24 | srq->srqn);
context->lkey = cpu_to_be32(srq->mr.ibmr.lkey);
context->db_index = cpu_to_be32(srq->db_index);
diff --git a/drivers/infiniband/ulp/ipoib/Kconfig b/drivers/infiniband/ulp/ipoib/Kconfig
index c75322d820d..af78ccc4ce7 100644
--- a/drivers/infiniband/ulp/ipoib/Kconfig
+++ b/drivers/infiniband/ulp/ipoib/Kconfig
@@ -1,6 +1,6 @@
config INFINIBAND_IPOIB
tristate "IP-over-InfiniBand"
- depends on INFINIBAND && NETDEVICES && INET
+ depends on INFINIBAND && NETDEVICES && INET && (IPV6 || IPV6=n)
---help---
Support for the IP-over-InfiniBand protocol (IPoIB). This
transports IP packets over InfiniBand so you can use your IB
@@ -8,6 +8,20 @@ config INFINIBAND_IPOIB
See Documentation/infiniband/ipoib.txt for more information
+config INFINIBAND_IPOIB_CM
+ bool "IP-over-InfiniBand Connected Mode support"
+ depends on INFINIBAND_IPOIB && EXPERIMENTAL
+ default n
+ ---help---
+ This option enables experimental support for IPoIB connected mode.
+ After enabling this option, you need to switch to connected mode through
+ /sys/class/net/ibXXX/mode to actually create connections, and then increase
+ the interface MTU with e.g. ifconfig ib0 mtu 65520.
+
+ WARNING: Enabling connected mode will trigger some
+ packet drops for multicast and UD mode traffic from this interface,
+ unless you limit mtu for these destinations to 2044.
+
config INFINIBAND_IPOIB_DEBUG
bool "IP-over-InfiniBand debugging" if EMBEDDED
depends on INFINIBAND_IPOIB
diff --git a/drivers/infiniband/ulp/ipoib/Makefile b/drivers/infiniband/ulp/ipoib/Makefile
index 8935e74ae3f..98ee38e8c2c 100644
--- a/drivers/infiniband/ulp/ipoib/Makefile
+++ b/drivers/infiniband/ulp/ipoib/Makefile
@@ -5,5 +5,6 @@ ib_ipoib-y := ipoib_main.o \
ipoib_multicast.o \
ipoib_verbs.o \
ipoib_vlan.o
+ib_ipoib-$(CONFIG_INFINIBAND_IPOIB_CM) += ipoib_cm.o
ib_ipoib-$(CONFIG_INFINIBAND_IPOIB_DEBUG) += ipoib_fs.o
diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h
index 07deee8f81c..2594db2030b 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib.h
+++ b/drivers/infiniband/ulp/ipoib/ipoib.h
@@ -62,6 +62,10 @@ enum {
IPOIB_ENCAP_LEN = 4,
+ IPOIB_CM_MTU = 0x10000 - 0x10, /* padding to align header to 16 */
+ IPOIB_CM_BUF_SIZE = IPOIB_CM_MTU + IPOIB_ENCAP_LEN,
+ IPOIB_CM_HEAD_SIZE = IPOIB_CM_BUF_SIZE % PAGE_SIZE,
+ IPOIB_CM_RX_SG = ALIGN(IPOIB_CM_BUF_SIZE, PAGE_SIZE) / PAGE_SIZE,
IPOIB_RX_RING_SIZE = 128,
IPOIB_TX_RING_SIZE = 64,
IPOIB_MAX_QUEUE_SIZE = 8192,
@@ -81,6 +85,8 @@ enum {
IPOIB_MCAST_RUN = 6,
IPOIB_STOP_REAPER = 7,
IPOIB_MCAST_STARTED = 8,
+ IPOIB_FLAG_NETIF_STOPPED = 9,
+ IPOIB_FLAG_ADMIN_CM = 10,
IPOIB_MAX_BACKOFF_SECONDS = 16,
@@ -90,6 +96,13 @@ enum {
IPOIB_MCAST_FLAG_ATTACHED = 3,
};
+#define IPOIB_OP_RECV (1ul << 31)
+#ifdef CONFIG_INFINIBAND_IPOIB_CM
+#define IPOIB_CM_OP_SRQ (1ul << 30)
+#else
+#define IPOIB_CM_OP_SRQ (0)
+#endif
+
/* structs */
struct ipoib_header {
@@ -113,6 +126,59 @@ struct ipoib_tx_buf {
u64 mapping;
};
+struct ib_cm_id;
+
+struct ipoib_cm_data {
+ __be32 qpn; /* High byte MUST be ignored on receive */
+ __be32 mtu;
+};
+
+struct ipoib_cm_rx {
+ struct ib_cm_id *id;
+ struct ib_qp *qp;
+ struct list_head list;
+ struct net_device *dev;
+ unsigned long jiffies;
+};
+
+struct ipoib_cm_tx {
+ struct ib_cm_id *id;
+ struct ib_cq *cq;
+ struct ib_qp *qp;
+ struct list_head list;
+ struct net_device *dev;
+ struct ipoib_neigh *neigh;
+ struct ipoib_path *path;
+ struct ipoib_tx_buf *tx_ring;
+ unsigned tx_head;
+ unsigned tx_tail;
+ unsigned long flags;
+ u32 mtu;
+ struct ib_wc ibwc[IPOIB_NUM_WC];
+};
+
+struct ipoib_cm_rx_buf {
+ struct sk_buff *skb;
+ u64 mapping[IPOIB_CM_RX_SG];
+};
+
+struct ipoib_cm_dev_priv {
+ struct ib_srq *srq;
+ struct ipoib_cm_rx_buf *srq_ring;
+ struct ib_cm_id *id;
+ struct list_head passive_ids;
+ struct work_struct start_task;
+ struct work_struct reap_task;
+ struct work_struct skb_task;
+ struct delayed_work stale_task;
+ struct sk_buff_head skb_queue;
+ struct list_head start_list;
+ struct list_head reap_list;
+ struct ib_wc ibwc[IPOIB_NUM_WC];
+ struct ib_sge rx_sge[IPOIB_CM_RX_SG];
+ struct ib_recv_wr rx_wr;
+};
+
/*
* Device private locking: tx_lock protects members used in TX fast
* path (and we use LLTX so upper layers don't do extra locking).
@@ -179,6 +245,10 @@ struct ipoib_dev_priv {
struct list_head child_intfs;
struct list_head list;
+#ifdef CONFIG_INFINIBAND_IPOIB_CM
+ struct ipoib_cm_dev_priv cm;
+#endif
+
#ifdef CONFIG_INFINIBAND_IPOIB_DEBUG
struct list_head fs_list;
struct dentry *mcg_dentry;
@@ -212,6 +282,9 @@ struct ipoib_path {
struct ipoib_neigh {
struct ipoib_ah *ah;
+#ifdef CONFIG_INFINIBAND_IPOIB_CM
+ struct ipoib_cm_tx *cm;
+#endif
union ib_gid dgid;
struct sk_buff_head queue;
@@ -315,6 +388,146 @@ int ipoib_vlan_delete(struct net_device *pdev, unsigned short pkey);
void ipoib_pkey_poll(struct work_struct *work);
int ipoib_pkey_dev_delay_open(struct net_device *dev);
+#ifdef CONFIG_INFINIBAND_IPOIB_CM
+
+#define IPOIB_FLAGS_RC 0x80
+#define IPOIB_FLAGS_UC 0x40
+
+/* We don't support UC connections at the moment */
+#define IPOIB_CM_SUPPORTED(ha) (ha[0] & (IPOIB_FLAGS_RC))
+
+static inline int ipoib_cm_admin_enabled(struct net_device *dev)
+{
+ struct ipoib_dev_priv *priv = netdev_priv(dev);
+ return IPOIB_CM_SUPPORTED(dev->dev_addr) &&
+ test_bit(IPOIB_FLAG_ADMIN_CM, &priv->flags);
+}
+
+static inline int ipoib_cm_enabled(struct net_device *dev, struct neighbour *n)
+{
+ struct ipoib_dev_priv *priv = netdev_priv(dev);
+ return IPOIB_CM_SUPPORTED(n->ha) &&
+ test_bit(IPOIB_FLAG_ADMIN_CM, &priv->flags);
+}
+
+static inline int ipoib_cm_up(struct ipoib_neigh *neigh)
+
+{
+ return test_bit(IPOIB_FLAG_OPER_UP, &neigh->cm->flags);
+}
+
+static inline struct ipoib_cm_tx *ipoib_cm_get(struct ipoib_neigh *neigh)
+{
+ return neigh->cm;
+}
+
+static inline void ipoib_cm_set(struct ipoib_neigh *neigh, struct ipoib_cm_tx *tx)
+{
+ neigh->cm = tx;
+}
+
+void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_tx *tx);
+int ipoib_cm_dev_open(struct net_device *dev);
+void ipoib_cm_dev_stop(struct net_device *dev);
+int ipoib_cm_dev_init(struct net_device *dev);
+int ipoib_cm_add_mode_attr(struct net_device *dev);
+void ipoib_cm_dev_cleanup(struct net_device *dev);
+struct ipoib_cm_tx *ipoib_cm_create_tx(struct net_device *dev, struct ipoib_path *path,
+ struct ipoib_neigh *neigh);
+void ipoib_cm_destroy_tx(struct ipoib_cm_tx *tx);
+void ipoib_cm_skb_too_long(struct net_device* dev, struct sk_buff *skb,
+ unsigned int mtu);
+void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc);
+#else
+
+struct ipoib_cm_tx;
+
+static inline int ipoib_cm_admin_enabled(struct net_device *dev)
+{
+ return 0;
+}
+static inline int ipoib_cm_enabled(struct net_device *dev, struct neighbour *n)
+
+{
+ return 0;
+}
+
+static inline int ipoib_cm_up(struct ipoib_neigh *neigh)
+
+{
+ return 0;
+}
+
+static inline struct ipoib_cm_tx *ipoib_cm_get(struct ipoib_neigh *neigh)
+{
+ return NULL;
+}
+
+static inline void ipoib_cm_set(struct ipoib_neigh *neigh, struct ipoib_cm_tx *tx)
+{
+}
+
+static inline
+void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_tx *tx)
+{
+ return;
+}
+
+static inline
+int ipoib_cm_dev_open(struct net_device *dev)
+{
+ return 0;
+}
+
+static inline
+void ipoib_cm_dev_stop(struct net_device *dev)
+{
+ return;
+}
+
+static inline
+int ipoib_cm_dev_init(struct net_device *dev)
+{
+ return -ENOSYS;
+}
+
+static inline
+void ipoib_cm_dev_cleanup(struct net_device *dev)
+{
+ return;
+}
+
+static inline
+struct ipoib_cm_tx *ipoib_cm_create_tx(struct net_device *dev, struct ipoib_path *path,
+ struct ipoib_neigh *neigh)
+{
+ return NULL;
+}
+
+static inline
+void ipoib_cm_destroy_tx(struct ipoib_cm_tx *tx)
+{
+ return;
+}
+
+static inline
+int ipoib_cm_add_mode_attr(struct net_device *dev)
+{
+ return 0;
+}
+
+static inline void ipoib_cm_skb_too_long(struct net_device* dev, struct sk_buff *skb,
+ unsigned int mtu)
+{
+ dev_kfree_skb_any(skb);
+}
+
+static inline void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
+{
+}
+
+#endif
+
#ifdef CONFIG_INFINIBAND_IPOIB_DEBUG
void ipoib_create_debug_files(struct net_device *dev);
void ipoib_delete_debug_files(struct net_device *dev);
@@ -392,4 +605,6 @@ extern int ipoib_debug_level;
#define IPOIB_GID_ARG(gid) IPOIB_GID_RAW_ARG((gid).raw)
+#define IPOIB_QPN(ha) (be32_to_cpup((__be32 *) ha) & 0xffffff)
+
#endif /* _IPOIB_H */
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
new file mode 100644
index 00000000000..4d59682f7d4
--- /dev/null
+++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
@@ -0,0 +1,1237 @@
+/*
+ * Copyright (c) 2006 Mellanox Technologies. All rights reserved
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * $Id$
+ */
+
+#include <rdma/ib_cm.h>
+#include <rdma/ib_cache.h>
+#include <net/dst.h>
+#include <net/icmp.h>
+#include <linux/icmpv6.h>
+
+#ifdef CONFIG_INFINIBAND_IPOIB_DEBUG_DATA
+static int data_debug_level;
+
+module_param_named(cm_data_debug_level, data_debug_level, int, 0644);
+MODULE_PARM_DESC(cm_data_debug_level,
+ "Enable data path debug tracing for connected mode if > 0");
+#endif
+
+#include "ipoib.h"
+
+#define IPOIB_CM_IETF_ID 0x1000000000000000ULL
+
+#define IPOIB_CM_RX_UPDATE_TIME (256 * HZ)
+#define IPOIB_CM_RX_TIMEOUT (2 * 256 * HZ)
+#define IPOIB_CM_RX_DELAY (3 * 256 * HZ)
+#define IPOIB_CM_RX_UPDATE_MASK (0x3)
+
+struct ipoib_cm_id {
+ struct ib_cm_id *id;
+ int flags;
+ u32 remote_qpn;
+ u32 remote_mtu;
+};
+
+static int ipoib_cm_tx_handler(struct ib_cm_id *cm_id,
+ struct ib_cm_event *event);
+
+static void ipoib_cm_dma_unmap_rx(struct ipoib_dev_priv *priv,
+ u64 mapping[IPOIB_CM_RX_SG])
+{
+ int i;
+
+ ib_dma_unmap_single(priv->ca, mapping[0], IPOIB_CM_HEAD_SIZE, DMA_FROM_DEVICE);
+
+ for (i = 0; i < IPOIB_CM_RX_SG - 1; ++i)
+ ib_dma_unmap_single(priv->ca, mapping[i + 1], PAGE_SIZE, DMA_FROM_DEVICE);
+}
+
+static int ipoib_cm_post_receive(struct net_device *dev, int id)
+{
+ struct ipoib_dev_priv *priv = netdev_priv(dev);
+ struct ib_recv_wr *bad_wr;
+ int i, ret;
+
+ priv->cm.rx_wr.wr_id = id | IPOIB_CM_OP_SRQ;
+
+ for (i = 0; i < IPOIB_CM_RX_SG; ++i)
+ priv->cm.rx_sge[i].addr = priv->cm.srq_ring[id].mapping[i];
+
+ ret = ib_post_srq_recv(priv->cm.srq, &priv->cm.rx_wr, &bad_wr);
+ if (unlikely(ret)) {
+ ipoib_warn(priv, "post srq failed for buf %d (%d)\n", id, ret);
+ ipoib_cm_dma_unmap_rx(priv, priv->cm.srq_ring[id].mapping);
+ dev_kfree_skb_any(priv->cm.srq_ring[id].skb);
+ priv->cm.srq_ring[id].skb = NULL;
+ }
+
+ return ret;
+}
+
+static int ipoib_cm_alloc_rx_skb(struct net_device *dev, int id,
+ u64 mapping[IPOIB_CM_RX_SG])
+{
+ struct ipoib_dev_priv *priv = netdev_priv(dev);
+ struct sk_buff *skb;
+ int i;
+
+ skb = dev_alloc_skb(IPOIB_CM_HEAD_SIZE + 12);
+ if (unlikely(!skb))
+ return -ENOMEM;
+
+ /*
+ * IPoIB adds a 4 byte header. So we need 12 more bytes to align the
+ * IP header to a multiple of 16.
+ */
+ skb_reserve(skb, 12);
+
+ mapping[0] = ib_dma_map_single(priv->ca, skb->data, IPOIB_CM_HEAD_SIZE,
+ DMA_FROM_DEVICE);
+ if (unlikely(ib_dma_mapping_error(priv->ca, mapping[0]))) {
+ dev_kfree_skb_any(skb);
+ return -EIO;
+ }
+
+ for (i = 0; i < IPOIB_CM_RX_SG - 1; i++) {
+ struct page *page = alloc_page(GFP_ATOMIC);
+
+ if (!page)
+ goto partial_error;
+ skb_fill_page_desc(skb, i, page, 0, PAGE_SIZE);
+
+ mapping[i + 1] = ib_dma_map_page(priv->ca, skb_shinfo(skb)->frags[i].page,
+ 0, PAGE_SIZE, DMA_TO_DEVICE);
+ if (unlikely(ib_dma_mapping_error(priv->ca, mapping[i + 1])))
+ goto partial_error;
+ }
+
+ priv->cm.srq_ring[id].skb = skb;
+ return 0;
+
+partial_error:
+
+ ib_dma_unmap_single(priv->ca, mapping[0], IPOIB_CM_HEAD_SIZE, DMA_FROM_DEVICE);
+
+ for (; i >= 0; --i)
+ ib_dma_unmap_single(priv->ca, mapping[i + 1], PAGE_SIZE, DMA_FROM_DEVICE);
+
+ dev_kfree_skb_any(skb);
+ return -ENOMEM;
+}
+
+static struct ib_qp *ipoib_cm_create_rx_qp(struct net_device *dev,
+ struct ipoib_cm_rx *p)
+{
+ struct ipoib_dev_priv *priv = netdev_priv(dev);
+ struct ib_qp_init_attr attr = {
+ .send_cq = priv->cq, /* does not matter, we never send anything */
+ .recv_cq = priv->cq,
+ .srq = priv->cm.srq,
+ .cap.max_send_wr = 1, /* FIXME: 0 Seems not to work */
+ .cap.max_send_sge = 1, /* FIXME: 0 Seems not to work */
+ .sq_sig_type = IB_SIGNAL_ALL_WR,
+ .qp_type = IB_QPT_RC,
+ .qp_context = p,
+ };
+ return ib_create_qp(priv->pd, &attr);
+}
+
+static int ipoib_cm_modify_rx_qp(struct net_device *dev,
+ struct ib_cm_id *cm_id, struct ib_qp *qp,
+ unsigned psn)
+{
+ struct ipoib_dev_priv *priv = netdev_priv(dev);
+ struct ib_qp_attr qp_attr;
+ int qp_attr_mask, ret;
+
+ qp_attr.qp_state = IB_QPS_INIT;
+ ret = ib_cm_init_qp_attr(cm_id, &qp_attr, &qp_attr_mask);
+ if (ret) {
+ ipoib_warn(priv, "failed to init QP attr for INIT: %d\n", ret);
+ return ret;
+ }
+ ret = ib_modify_qp(qp, &qp_attr, qp_attr_mask);
+ if (ret) {
+ ipoib_warn(priv, "failed to modify QP to INIT: %d\n", ret);
+ return ret;
+ }
+ qp_attr.qp_state = IB_QPS_RTR;
+ ret = ib_cm_init_qp_attr(cm_id, &qp_attr, &qp_attr_mask);
+ if (ret) {
+ ipoib_warn(priv, "failed to init QP attr for RTR: %d\n", ret);
+ return ret;
+ }
+ qp_attr.rq_psn = psn;
+ ret = ib_modify_qp(qp, &qp_attr, qp_attr_mask);
+ if (ret) {
+ ipoib_warn(priv, "failed to modify QP to RTR: %d\n", ret);
+ return ret;
+ }
+ return 0;
+}
+
+static int ipoib_cm_send_rep(struct net_device *dev, struct ib_cm_id *cm_id,
+ struct ib_qp *qp, struct ib_cm_req_event_param *req,
+ unsigned psn)
+{
+ struct ipoib_dev_priv *priv = netdev_priv(dev);
+ struct ipoib_cm_data data = {};
+ struct ib_cm_rep_param rep = {};
+
+ data.qpn = cpu_to_be32(priv->qp->qp_num);
+ data.mtu = cpu_to_be32(IPOIB_CM_BUF_SIZE);
+
+ rep.private_data = &data;
+ rep.private_data_len = sizeof data;
+ rep.flow_control = 0;
+ rep.rnr_retry_count = req->rnr_retry_count;
+ rep.target_ack_delay = 20; /* FIXME */
+ rep.srq = 1;
+ rep.qp_num = qp->qp_num;
+ rep.starting_psn = psn;
+ return ib_send_cm_rep(cm_id, &rep);
+}
+
+static int ipoib_cm_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
+{
+ struct net_device *dev = cm_id->context;
+ struct ipoib_dev_priv *priv = netdev_priv(dev);
+ struct ipoib_cm_rx *p;
+ unsigned long flags;
+ unsigned psn;
+ int ret;
+
+ ipoib_dbg(priv, "REQ arrived\n");
+ p = kzalloc(sizeof *p, GFP_KERNEL);
+ if (!p)
+ return -ENOMEM;
+ p->dev = dev;
+ p->id = cm_id;
+ p->qp = ipoib_cm_create_rx_qp(dev, p);
+ if (IS_ERR(p->qp)) {
+ ret = PTR_ERR(p->qp);
+ goto err_qp;
+ }
+
+ psn = random32() & 0xffffff;
+ ret = ipoib_cm_modify_rx_qp(dev, cm_id, p->qp, psn);
+ if (ret)
+ goto err_modify;
+
+ ret = ipoib_cm_send_rep(dev, cm_id, p->qp, &event->param.req_rcvd, psn);
+ if (ret) {
+ ipoib_warn(priv, "failed to send REP: %d\n", ret);
+ goto err_rep;
+ }
+
+ cm_id->context = p;
+ p->jiffies = jiffies;
+ spin_lock_irqsave(&priv->lock, flags);
+ list_add(&p->list, &priv->cm.passive_ids);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ queue_delayed_work(ipoib_workqueue,
+ &priv->cm.stale_task, IPOIB_CM_RX_DELAY);
+ return 0;
+
+err_rep:
+err_modify:
+ ib_destroy_qp(p->qp);
+err_qp:
+ kfree(p);
+ return ret;
+}
+
+static int ipoib_cm_rx_handler(struct ib_cm_id *cm_id,
+ struct ib_cm_event *event)
+{
+ struct ipoib_cm_rx *p;
+ struct ipoib_dev_priv *priv;
+ unsigned long flags;
+ int ret;
+
+ switch (event->event) {
+ case IB_CM_REQ_RECEIVED:
+ return ipoib_cm_req_handler(cm_id, event);
+ case IB_CM_DREQ_RECEIVED:
+ p = cm_id->context;
+ ib_send_cm_drep(cm_id, NULL, 0);
+ /* Fall through */
+ case IB_CM_REJ_RECEIVED:
+ p = cm_id->context;
+ priv = netdev_priv(p->dev);
+ spin_lock_irqsave(&priv->lock, flags);
+ if (list_empty(&p->list))
+ ret = 0; /* Connection is going away already. */
+ else {
+ list_del_init(&p->list);
+ ret = -ECONNRESET;
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+ if (ret) {
+ ib_destroy_qp(p->qp);
+ kfree(p);
+ return ret;
+ }
+ return 0;
+ default:
+ return 0;
+ }
+}
+/* Adjust length of skb with fragments to match received data */
+static void skb_put_frags(struct sk_buff *skb, unsigned int hdr_space,
+ unsigned int length)
+{
+ int i, num_frags;
+ unsigned int size;
+
+ /* put header into skb */
+ size = min(length, hdr_space);
+ skb->tail += size;
+ skb->len += size;
+ length -= size;
+
+ num_frags = skb_shinfo(skb)->nr_frags;
+ for (i = 0; i < num_frags; i++) {
+ skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+
+ if (length == 0) {
+ /* don't need this page */
+ __free_page(frag->page);
+ --skb_shinfo(skb)->nr_frags;
+ } else {
+ size = min(length, (unsigned) PAGE_SIZE);
+
+ frag->size = size;
+ skb->data_len += size;
+ skb->truesize += size;
+ skb->len += size;
+ length -= size;
+ }
+ }
+}
+
+void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
+{
+ struct ipoib_dev_priv *priv = netdev_priv(dev);
+ unsigned int wr_id = wc->wr_id & ~IPOIB_CM_OP_SRQ;
+ struct sk_buff *skb;
+ struct ipoib_cm_rx *p;
+ unsigned long flags;
+ u64 mapping[IPOIB_CM_RX_SG];
+
+ ipoib_dbg_data(priv, "cm recv completion: id %d, op %d, status: %d\n",
+ wr_id, wc->opcode, wc->status);
+
+ if (unlikely(wr_id >= ipoib_recvq_size)) {
+ ipoib_warn(priv, "cm recv completion event with wrid %d (> %d)\n",
+ wr_id, ipoib_recvq_size);
+ return;
+ }
+
+ skb = priv->cm.srq_ring[wr_id].skb;
+
+ if (unlikely(wc->status != IB_WC_SUCCESS)) {
+ ipoib_dbg(priv, "cm recv error "
+ "(status=%d, wrid=%d vend_err %x)\n",
+ wc->status, wr_id, wc->vendor_err);
+ ++priv->stats.rx_dropped;
+ goto repost;
+ }
+
+ if (!likely(wr_id & IPOIB_CM_RX_UPDATE_MASK)) {
+ p = wc->qp->qp_context;
+ if (time_after_eq(jiffies, p->jiffies + IPOIB_CM_RX_UPDATE_TIME)) {
+ spin_lock_irqsave(&priv->lock, flags);
+ p->jiffies = jiffies;
+ /* Move this entry to list head, but do
+ * not re-add it if it has been removed. */
+ if (!list_empty(&p->list))
+ list_move(&p->list, &priv->cm.passive_ids);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ queue_delayed_work(ipoib_workqueue,
+ &priv->cm.stale_task, IPOIB_CM_RX_DELAY);
+ }
+ }
+
+ if (unlikely(ipoib_cm_alloc_rx_skb(dev, wr_id, mapping))) {
+ /*
+ * If we can't allocate a new RX buffer, dump
+ * this packet and reuse the old buffer.
+ */
+ ipoib_dbg(priv, "failed to allocate receive buffer %d\n", wr_id);
+ ++priv->stats.rx_dropped;
+ goto repost;
+ }
+
+ ipoib_cm_dma_unmap_rx(priv, priv->cm.srq_ring[wr_id].mapping);
+ memcpy(priv->cm.srq_ring[wr_id].mapping, mapping, sizeof mapping);
+
+ ipoib_dbg_data(priv, "received %d bytes, SLID 0x%04x\n",
+ wc->byte_len, wc->slid);
+
+ skb_put_frags(skb, IPOIB_CM_HEAD_SIZE, wc->byte_len);
+
+ skb->protocol = ((struct ipoib_header *) skb->data)->proto;
+ skb->mac.raw = skb->data;
+ skb_pull(skb, IPOIB_ENCAP_LEN);
+
+ dev->last_rx = jiffies;
+ ++priv->stats.rx_packets;
+ priv->stats.rx_bytes += skb->len;
+
+ skb->dev = dev;
+ /* XXX get correct PACKET_ type here */
+ skb->pkt_type = PACKET_HOST;
+ netif_rx_ni(skb);
+
+repost:
+ if (unlikely(ipoib_cm_post_receive(dev, wr_id)))
+ ipoib_warn(priv, "ipoib_cm_post_receive failed "
+ "for buf %d\n", wr_id);
+}
+
+static inline int post_send(struct ipoib_dev_priv *priv,
+ struct ipoib_cm_tx *tx,
+ unsigned int wr_id,
+ u64 addr, int len)
+{
+ struct ib_send_wr *bad_wr;
+
+ priv->tx_sge.addr = addr;
+ priv->tx_sge.length = len;
+
+ priv->tx_wr.wr_id = wr_id;
+
+ return ib_post_send(tx->qp, &priv->tx_wr, &bad_wr);
+}
+
+void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_tx *tx)
+{
+ struct ipoib_dev_priv *priv = netdev_priv(dev);
+ struct ipoib_tx_buf *tx_req;
+ u64 addr;
+
+ if (unlikely(skb->len > tx->mtu)) {
+ ipoib_warn(priv, "packet len %d (> %d) too long to send, dropping\n",
+ skb->len, tx->mtu);
+ ++priv->stats.tx_dropped;
+ ++priv->stats.tx_errors;
+ ipoib_cm_skb_too_long(dev, skb, tx->mtu - INFINIBAND_ALEN);
+ return;
+ }
+
+ ipoib_dbg_data(priv, "sending packet: head 0x%x length %d connection 0x%x\n",
+ tx->tx_head, skb->len, tx->qp->qp_num);
+
+ /*
+ * We put the skb into the tx_ring _before_ we call post_send()
+ * because it's entirely possible that the completion handler will
+ * run before we execute anything after the post_send(). That
+ * means we have to make sure everything is properly recorded and
+ * our state is consistent before we call post_send().
+ */
+ tx_req = &tx->tx_ring[tx->tx_head & (ipoib_sendq_size - 1)];
+ tx_req->skb = skb;
+ addr = ib_dma_map_single(priv->ca, skb->data, skb->len, DMA_TO_DEVICE);
+ if (unlikely(ib_dma_mapping_error(priv->ca, addr))) {
+ ++priv->stats.tx_errors;
+ dev_kfree_skb_any(skb);
+ return;
+ }
+
+ 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");
+ ++priv->stats.tx_errors;
+ ib_dma_unmap_single(priv->ca, addr, skb->len, DMA_TO_DEVICE);
+ dev_kfree_skb_any(skb);
+ } else {
+ dev->trans_start = jiffies;
+ ++tx->tx_head;
+
+ if (tx->tx_head - tx->tx_tail == ipoib_sendq_size) {
+ ipoib_dbg(priv, "TX ring 0x%x full, stopping kernel net queue\n",
+ tx->qp->qp_num);
+ netif_stop_queue(dev);
+ set_bit(IPOIB_FLAG_NETIF_STOPPED, &tx->flags);
+ }
+ }
+}
+
+static void ipoib_cm_handle_tx_wc(struct net_device *dev, struct ipoib_cm_tx *tx,
+ struct ib_wc *wc)
+{
+ struct ipoib_dev_priv *priv = netdev_priv(dev);
+ unsigned int wr_id = wc->wr_id;
+ struct ipoib_tx_buf *tx_req;
+ unsigned long flags;
+
+ ipoib_dbg_data(priv, "cm send completion: id %d, op %d, status: %d\n",
+ wr_id, wc->opcode, wc->status);
+
+ if (unlikely(wr_id >= ipoib_sendq_size)) {
+ ipoib_warn(priv, "cm send completion event with wrid %d (> %d)\n",
+ wr_id, ipoib_sendq_size);
+ return;
+ }
+
+ tx_req = &tx->tx_ring[wr_id];
+
+ ib_dma_unmap_single(priv->ca, tx_req->mapping, tx_req->skb->len, DMA_TO_DEVICE);
+
+ /* FIXME: is this right? Shouldn't we only increment on success? */
+ ++priv->stats.tx_packets;
+ priv->stats.tx_bytes += tx_req->skb->len;
+
+ dev_kfree_skb_any(tx_req->skb);
+
+ spin_lock_irqsave(&priv->tx_lock, flags);
+ ++tx->tx_tail;
+ if (unlikely(test_bit(IPOIB_FLAG_NETIF_STOPPED, &tx->flags)) &&
+ tx->tx_head - tx->tx_tail <= ipoib_sendq_size >> 1) {
+ clear_bit(IPOIB_FLAG_NETIF_STOPPED, &tx->flags);
+ netif_wake_queue(dev);
+ }
+
+ if (wc->status != IB_WC_SUCCESS &&
+ wc->status != IB_WC_WR_FLUSH_ERR) {
+ struct ipoib_neigh *neigh;
+
+ ipoib_dbg(priv, "failed cm send event "
+ "(status=%d, wrid=%d vend_err %x)\n",
+ wc->status, wr_id, wc->vendor_err);
+
+ spin_lock(&priv->lock);
+ neigh = tx->neigh;
+
+ if (neigh) {
+ neigh->cm = NULL;
+ list_del(&neigh->list);
+ if (neigh->ah)
+ ipoib_put_ah(neigh->ah);
+ ipoib_neigh_free(dev, neigh);
+
+ tx->neigh = NULL;
+ }
+
+ /* queue would be re-started anyway when TX is destroyed,
+ * but it makes sense to do it ASAP here. */
+ if (test_and_clear_bit(IPOIB_FLAG_NETIF_STOPPED, &tx->flags))
+ netif_wake_queue(dev);
+
+ if (test_and_clear_bit(IPOIB_FLAG_INITIALIZED, &tx->flags)) {
+ list_move(&tx->list, &priv->cm.reap_list);
+ queue_work(ipoib_workqueue, &priv->cm.reap_task);
+ }
+
+ clear_bit(IPOIB_FLAG_OPER_UP, &tx->flags);
+
+ spin_unlock(&priv->lock);
+ }
+
+ spin_unlock_irqrestore(&priv->tx_lock, flags);
+}
+
+static void ipoib_cm_tx_completion(struct ib_cq *cq, void *tx_ptr)
+{
+ struct ipoib_cm_tx *tx = tx_ptr;
+ int n, i;
+
+ ib_req_notify_cq(cq, IB_CQ_NEXT_COMP);
+ do {
+ n = ib_poll_cq(cq, IPOIB_NUM_WC, tx->ibwc);
+ for (i = 0; i < n; ++i)
+ ipoib_cm_handle_tx_wc(tx->dev, tx, tx->ibwc + i);
+ } while (n == IPOIB_NUM_WC);
+}
+
+int ipoib_cm_dev_open(struct net_device *dev)
+{
+ struct ipoib_dev_priv *priv = netdev_priv(dev);
+ int ret;
+
+ if (!IPOIB_CM_SUPPORTED(dev->dev_addr))
+ return 0;
+
+ priv->cm.id = ib_create_cm_id(priv->ca, ipoib_cm_rx_handler, dev);
+ if (IS_ERR(priv->cm.id)) {
+ printk(KERN_WARNING "%s: failed to create CM ID\n", priv->ca->name);
+ return IS_ERR(priv->cm.id);
+ }
+
+ ret = ib_cm_listen(priv->cm.id, cpu_to_be64(IPOIB_CM_IETF_ID | priv->qp->qp_num),
+ 0, NULL);
+ if (ret) {
+ printk(KERN_WARNING "%s: failed to listen on ID 0x%llx\n", priv->ca->name,
+ IPOIB_CM_IETF_ID | priv->qp->qp_num);
+ ib_destroy_cm_id(priv->cm.id);
+ return ret;
+ }
+ return 0;
+}
+
+void ipoib_cm_dev_stop(struct net_device *dev)
+{
+ struct ipoib_dev_priv *priv = netdev_priv(dev);
+ struct ipoib_cm_rx *p;
+ unsigned long flags;
+
+ if (!IPOIB_CM_SUPPORTED(dev->dev_addr))
+ return;
+
+ ib_destroy_cm_id(priv->cm.id);
+ spin_lock_irqsave(&priv->lock, flags);
+ while (!list_empty(&priv->cm.passive_ids)) {
+ p = list_entry(priv->cm.passive_ids.next, typeof(*p), list);
+ list_del_init(&p->list);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ ib_destroy_cm_id(p->id);
+ ib_destroy_qp(p->qp);
+ kfree(p);
+ spin_lock_irqsave(&priv->lock, flags);
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ cancel_delayed_work(&priv->cm.stale_task);
+}
+
+static int ipoib_cm_rep_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
+{
+ struct ipoib_cm_tx *p = cm_id->context;
+ struct ipoib_dev_priv *priv = netdev_priv(p->dev);
+ struct ipoib_cm_data *data = event->private_data;
+ struct sk_buff_head skqueue;
+ struct ib_qp_attr qp_attr;
+ int qp_attr_mask, ret;
+ struct sk_buff *skb;
+ unsigned long flags;
+
+ p->mtu = be32_to_cpu(data->mtu);
+
+ if (p->mtu < priv->dev->mtu + IPOIB_ENCAP_LEN) {
+ ipoib_warn(priv, "Rejecting connection: mtu %d < device mtu %d + 4\n",
+ p->mtu, priv->dev->mtu);
+ return -EINVAL;
+ }
+
+ qp_attr.qp_state = IB_QPS_RTR;
+ ret = ib_cm_init_qp_attr(cm_id, &qp_attr, &qp_attr_mask);
+ if (ret) {
+ ipoib_warn(priv, "failed to init QP attr for RTR: %d\n", ret);
+ return ret;
+ }
+
+ qp_attr.rq_psn = 0 /* FIXME */;
+ ret = ib_modify_qp(p->qp, &qp_attr, qp_attr_mask);
+ if (ret) {
+ ipoib_warn(priv, "failed to modify QP to RTR: %d\n", ret);
+ return ret;
+ }
+
+ qp_attr.qp_state = IB_QPS_RTS;
+ ret = ib_cm_init_qp_attr(cm_id, &qp_attr, &qp_attr_mask);
+ if (ret) {
+ ipoib_warn(priv, "failed to init QP attr for RTS: %d\n", ret);
+ return ret;
+ }
+ ret = ib_modify_qp(p->qp, &qp_attr, qp_attr_mask);
+ if (ret) {
+ ipoib_warn(priv, "failed to modify QP to RTS: %d\n", ret);
+ return ret;
+ }
+
+ skb_queue_head_init(&skqueue);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ set_bit(IPOIB_FLAG_OPER_UP, &p->flags);
+ if (p->neigh)
+ while ((skb = __skb_dequeue(&p->neigh->queue)))
+ __skb_queue_tail(&skqueue, skb);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ while ((skb = __skb_dequeue(&skqueue))) {
+ skb->dev = p->dev;
+ if (dev_queue_xmit(skb))
+ ipoib_warn(priv, "dev_queue_xmit failed "
+ "to requeue packet\n");
+ }
+
+ ret = ib_send_cm_rtu(cm_id, NULL, 0);
+ if (ret) {
+ ipoib_warn(priv, "failed to send RTU: %d\n", ret);
+ return ret;
+ }
+ return 0;
+}
+
+static struct ib_qp *ipoib_cm_create_tx_qp(struct net_device *dev, struct ib_cq *cq)
+{
+ struct ipoib_dev_priv *priv = netdev_priv(dev);
+ struct ib_qp_init_attr attr = {};
+ attr.recv_cq = priv->cq;
+ attr.srq = priv->cm.srq;
+ attr.cap.max_send_wr = ipoib_sendq_size;
+ attr.cap.max_send_sge = 1;
+ attr.sq_sig_type = IB_SIGNAL_ALL_WR;
+ attr.qp_type = IB_QPT_RC;
+ attr.send_cq = cq;
+ return ib_create_qp(priv->pd, &attr);
+}
+
+static int ipoib_cm_send_req(struct net_device *dev,
+ struct ib_cm_id *id, struct ib_qp *qp,
+ u32 qpn,
+ struct ib_sa_path_rec *pathrec)
+{
+ struct ipoib_dev_priv *priv = netdev_priv(dev);
+ struct ipoib_cm_data data = {};
+ struct ib_cm_req_param req = {};
+
+ data.qpn = cpu_to_be32(priv->qp->qp_num);
+ data.mtu = cpu_to_be32(IPOIB_CM_BUF_SIZE);
+
+ req.primary_path = pathrec;
+ req.alternate_path = NULL;
+ req.service_id = cpu_to_be64(IPOIB_CM_IETF_ID | qpn);
+ req.qp_num = qp->qp_num;
+ req.qp_type = qp->qp_type;
+ req.private_data = &data;
+ req.private_data_len = sizeof data;
+ req.flow_control = 0;
+
+ req.starting_psn = 0; /* FIXME */
+
+ /*
+ * Pick some arbitrary defaults here; we could make these
+ * module parameters if anyone cared about setting them.
+ */
+ req.responder_resources = 4;
+ req.remote_cm_response_timeout = 20;
+ req.local_cm_response_timeout = 20;
+ req.retry_count = 0; /* RFC draft warns against retries */
+ req.rnr_retry_count = 0; /* RFC draft warns against retries */
+ req.max_cm_retries = 15;
+ req.srq = 1;
+ return ib_send_cm_req(id, &req);
+}
+
+static int ipoib_cm_modify_tx_init(struct net_device *dev,
+ struct ib_cm_id *cm_id, struct ib_qp *qp)
+{
+ struct ipoib_dev_priv *priv = netdev_priv(dev);
+ struct ib_qp_attr qp_attr;
+ int qp_attr_mask, ret;
+ ret = ib_find_cached_pkey(priv->ca, priv->port, priv->pkey, &qp_attr.pkey_index);
+ if (ret) {
+ ipoib_warn(priv, "pkey 0x%x not in cache: %d\n", priv->pkey, ret);
+ return ret;
+ }
+
+ qp_attr.qp_state = IB_QPS_INIT;
+ qp_attr.qp_access_flags = IB_ACCESS_LOCAL_WRITE;
+ qp_attr.port_num = priv->port;
+ qp_attr_mask = IB_QP_STATE | IB_QP_ACCESS_FLAGS | IB_QP_PKEY_INDEX | IB_QP_PORT;
+
+ ret = ib_modify_qp(qp, &qp_attr, qp_attr_mask);
+ if (ret) {
+ ipoib_warn(priv, "failed to modify tx QP to INIT: %d\n", ret);
+ return ret;
+ }
+ return 0;
+}
+
+static int ipoib_cm_tx_init(struct ipoib_cm_tx *p, u32 qpn,
+ struct ib_sa_path_rec *pathrec)
+{
+ struct ipoib_dev_priv *priv = netdev_priv(p->dev);
+ int ret;
+
+ p->tx_ring = kzalloc(ipoib_sendq_size * sizeof *p->tx_ring,
+ GFP_KERNEL);
+ if (!p->tx_ring) {
+ ipoib_warn(priv, "failed to allocate tx ring\n");
+ ret = -ENOMEM;
+ goto err_tx;
+ }
+
+ p->cq = ib_create_cq(priv->ca, ipoib_cm_tx_completion, NULL, p,
+ ipoib_sendq_size + 1);
+ if (IS_ERR(p->cq)) {
+ ret = PTR_ERR(p->cq);
+ ipoib_warn(priv, "failed to allocate tx cq: %d\n", ret);
+ goto err_cq;
+ }
+
+ ret = ib_req_notify_cq(p->cq, IB_CQ_NEXT_COMP);
+ if (ret) {
+ ipoib_warn(priv, "failed to request completion notification: %d\n", ret);
+ goto err_req_notify;
+ }
+
+ p->qp = ipoib_cm_create_tx_qp(p->dev, p->cq);
+ if (IS_ERR(p->qp)) {
+ ret = PTR_ERR(p->qp);
+ ipoib_warn(priv, "failed to allocate tx qp: %d\n", ret);
+ goto err_qp;
+ }
+
+ p->id = ib_create_cm_id(priv->ca, ipoib_cm_tx_handler, p);
+ if (IS_ERR(p->id)) {
+ ret = PTR_ERR(p->id);
+ ipoib_warn(priv, "failed to create tx cm id: %d\n", ret);
+ goto err_id;
+ }
+
+ ret = ipoib_cm_modify_tx_init(p->dev, p->id, p->qp);
+ if (ret) {
+ ipoib_warn(priv, "failed to modify tx qp to rtr: %d\n", ret);
+ goto err_modify;
+ }
+
+ ret = ipoib_cm_send_req(p->dev, p->id, p->qp, qpn, pathrec);
+ if (ret) {
+ ipoib_warn(priv, "failed to send cm req: %d\n", ret);
+ goto err_send_cm;
+ }
+
+ ipoib_dbg(priv, "Request connection 0x%x for gid " IPOIB_GID_FMT " qpn 0x%x\n",
+ p->qp->qp_num, IPOIB_GID_ARG(pathrec->dgid), qpn);
+
+ return 0;
+
+err_send_cm:
+err_modify:
+ ib_destroy_cm_id(p->id);
+err_id:
+ p->id = NULL;
+ ib_destroy_qp(p->qp);
+err_req_notify:
+err_qp:
+ p->qp = NULL;
+ ib_destroy_cq(p->cq);
+err_cq:
+ p->cq = NULL;
+err_tx:
+ return ret;
+}
+
+static void ipoib_cm_tx_destroy(struct ipoib_cm_tx *p)
+{
+ struct ipoib_dev_priv *priv = netdev_priv(p->dev);
+ struct ipoib_tx_buf *tx_req;
+
+ ipoib_dbg(priv, "Destroy active connection 0x%x head 0x%x tail 0x%x\n",
+ p->qp ? p->qp->qp_num : 0, p->tx_head, p->tx_tail);
+
+ if (p->id)
+ ib_destroy_cm_id(p->id);
+
+ if (p->qp)
+ ib_destroy_qp(p->qp);
+
+ if (p->cq)
+ ib_destroy_cq(p->cq);
+
+ if (test_bit(IPOIB_FLAG_NETIF_STOPPED, &p->flags))
+ netif_wake_queue(p->dev);
+
+ if (p->tx_ring) {
+ while ((int) p->tx_tail - (int) p->tx_head < 0) {
+ tx_req = &p->tx_ring[p->tx_tail & (ipoib_sendq_size - 1)];
+ ib_dma_unmap_single(priv->ca, tx_req->mapping, tx_req->skb->len,
+ DMA_TO_DEVICE);
+ dev_kfree_skb_any(tx_req->skb);
+ ++p->tx_tail;
+ }
+
+ kfree(p->tx_ring);
+ }
+
+ kfree(p);
+}
+
+static int ipoib_cm_tx_handler(struct ib_cm_id *cm_id,
+ struct ib_cm_event *event)
+{
+ struct ipoib_cm_tx *tx = cm_id->context;
+ struct ipoib_dev_priv *priv = netdev_priv(tx->dev);
+ struct net_device *dev = priv->dev;
+ struct ipoib_neigh *neigh;
+ unsigned long flags;
+ int ret;
+
+ switch (event->event) {
+ case IB_CM_DREQ_RECEIVED:
+ ipoib_dbg(priv, "DREQ received.\n");
+ ib_send_cm_drep(cm_id, NULL, 0);
+ break;
+ case IB_CM_REP_RECEIVED:
+ ipoib_dbg(priv, "REP received.\n");
+ ret = ipoib_cm_rep_handler(cm_id, event);
+ if (ret)
+ ib_send_cm_rej(cm_id, IB_CM_REJ_CONSUMER_DEFINED,
+ NULL, 0, NULL, 0);
+ break;
+ case IB_CM_REQ_ERROR:
+ case IB_CM_REJ_RECEIVED:
+ case IB_CM_TIMEWAIT_EXIT:
+ ipoib_dbg(priv, "CM error %d.\n", event->event);
+ spin_lock_irqsave(&priv->tx_lock, flags);
+ spin_lock(&priv->lock);
+ neigh = tx->neigh;
+
+ if (neigh) {
+ neigh->cm = NULL;
+ list_del(&neigh->list);
+ if (neigh->ah)
+ ipoib_put_ah(neigh->ah);
+ ipoib_neigh_free(dev, neigh);
+
+ tx->neigh = NULL;
+ }
+
+ if (test_and_clear_bit(IPOIB_FLAG_INITIALIZED, &tx->flags)) {
+ list_move(&tx->list, &priv->cm.reap_list);
+ queue_work(ipoib_workqueue, &priv->cm.reap_task);
+ }
+
+ spin_unlock(&priv->lock);
+ spin_unlock_irqrestore(&priv->tx_lock, flags);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+struct ipoib_cm_tx *ipoib_cm_create_tx(struct net_device *dev, struct ipoib_path *path,
+ struct ipoib_neigh *neigh)
+{
+ struct ipoib_dev_priv *priv = netdev_priv(dev);
+ struct ipoib_cm_tx *tx;
+
+ tx = kzalloc(sizeof *tx, GFP_ATOMIC);
+ if (!tx)
+ return NULL;
+
+ neigh->cm = tx;
+ tx->neigh = neigh;
+ tx->path = path;
+ tx->dev = dev;
+ list_add(&tx->list, &priv->cm.start_list);
+ set_bit(IPOIB_FLAG_INITIALIZED, &tx->flags);
+ queue_work(ipoib_workqueue, &priv->cm.start_task);
+ return tx;
+}
+
+void ipoib_cm_destroy_tx(struct ipoib_cm_tx *tx)
+{
+ struct ipoib_dev_priv *priv = netdev_priv(tx->dev);
+ if (test_and_clear_bit(IPOIB_FLAG_INITIALIZED, &tx->flags)) {
+ list_move(&tx->list, &priv->cm.reap_list);
+ queue_work(ipoib_workqueue, &priv->cm.reap_task);
+ ipoib_dbg(priv, "Reap connection for gid " IPOIB_GID_FMT "\n",
+ IPOIB_GID_ARG(tx->neigh->dgid));
+ tx->neigh = NULL;
+ }
+}
+
+static void ipoib_cm_tx_start(struct work_struct *work)
+{
+ struct ipoib_dev_priv *priv = container_of(work, struct ipoib_dev_priv,
+ cm.start_task);
+ struct net_device *dev = priv->dev;
+ struct ipoib_neigh *neigh;
+ struct ipoib_cm_tx *p;
+ unsigned long flags;
+ int ret;
+
+ struct ib_sa_path_rec pathrec;
+ u32 qpn;
+
+ spin_lock_irqsave(&priv->tx_lock, flags);
+ spin_lock(&priv->lock);
+ while (!list_empty(&priv->cm.start_list)) {
+ p = list_entry(priv->cm.start_list.next, typeof(*p), list);
+ list_del_init(&p->list);
+ neigh = p->neigh;
+ qpn = IPOIB_QPN(neigh->neighbour->ha);
+ memcpy(&pathrec, &p->path->pathrec, sizeof pathrec);
+ spin_unlock(&priv->lock);
+ spin_unlock_irqrestore(&priv->tx_lock, flags);
+ ret = ipoib_cm_tx_init(p, qpn, &pathrec);
+ spin_lock_irqsave(&priv->tx_lock, flags);
+ spin_lock(&priv->lock);
+ if (ret) {
+ neigh = p->neigh;
+ if (neigh) {
+ neigh->cm = NULL;
+ list_del(&neigh->list);
+ if (neigh->ah)
+ ipoib_put_ah(neigh->ah);
+ ipoib_neigh_free(dev, neigh);
+ }
+ list_del(&p->list);
+ kfree(p);
+ }
+ }
+ spin_unlock(&priv->lock);
+ spin_unlock_irqrestore(&priv->tx_lock, flags);
+}
+
+static void ipoib_cm_tx_reap(struct work_struct *work)
+{
+ struct ipoib_dev_priv *priv = container_of(work, struct ipoib_dev_priv,
+ cm.reap_task);
+ struct ipoib_cm_tx *p;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->tx_lock, flags);
+ spin_lock(&priv->lock);
+ while (!list_empty(&priv->cm.reap_list)) {
+ p = list_entry(priv->cm.reap_list.next, typeof(*p), list);
+ list_del(&p->list);
+ spin_unlock(&priv->lock);
+ spin_unlock_irqrestore(&priv->tx_lock, flags);
+ ipoib_cm_tx_destroy(p);
+ spin_lock_irqsave(&priv->tx_lock, flags);
+ spin_lock(&priv->lock);
+ }
+ spin_unlock(&priv->lock);
+ spin_unlock_irqrestore(&priv->tx_lock, flags);
+}
+
+static void ipoib_cm_skb_reap(struct work_struct *work)
+{
+ struct ipoib_dev_priv *priv = container_of(work, struct ipoib_dev_priv,
+ cm.skb_task);
+ struct net_device *dev = priv->dev;
+ struct sk_buff *skb;
+ unsigned long flags;
+
+ unsigned mtu = priv->mcast_mtu;
+
+ spin_lock_irqsave(&priv->tx_lock, flags);
+ spin_lock(&priv->lock);
+ while ((skb = skb_dequeue(&priv->cm.skb_queue))) {
+ spin_unlock(&priv->lock);
+ spin_unlock_irqrestore(&priv->tx_lock, flags);
+ if (skb->protocol == htons(ETH_P_IP))
+ 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, dev);
+#endif
+ dev_kfree_skb_any(skb);
+ spin_lock_irqsave(&priv->tx_lock, flags);
+ spin_lock(&priv->lock);
+ }
+ spin_unlock(&priv->lock);
+ spin_unlock_irqrestore(&priv->tx_lock, flags);
+}
+
+void ipoib_cm_skb_too_long(struct net_device* dev, struct sk_buff *skb,
+ unsigned int mtu)
+{
+ struct ipoib_dev_priv *priv = netdev_priv(dev);
+ int e = skb_queue_empty(&priv->cm.skb_queue);
+
+ if (skb->dst)
+ skb->dst->ops->update_pmtu(skb->dst, mtu);
+
+ skb_queue_tail(&priv->cm.skb_queue, skb);
+ if (e)
+ queue_work(ipoib_workqueue, &priv->cm.skb_task);
+}
+
+static void ipoib_cm_stale_task(struct work_struct *work)
+{
+ struct ipoib_dev_priv *priv = container_of(work, struct ipoib_dev_priv,
+ cm.stale_task.work);
+ struct ipoib_cm_rx *p;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ while (!list_empty(&priv->cm.passive_ids)) {
+ /* List if sorted by LRU, start from tail,
+ * stop when we see a recently used entry */
+ p = list_entry(priv->cm.passive_ids.prev, typeof(*p), list);
+ if (time_after_eq(jiffies, p->jiffies + IPOIB_CM_RX_TIMEOUT))
+ break;
+ list_del_init(&p->list);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ ib_destroy_cm_id(p->id);
+ ib_destroy_qp(p->qp);
+ kfree(p);
+ spin_lock_irqsave(&priv->lock, flags);
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+
+static ssize_t show_mode(struct device *d, struct device_attribute *attr,
+ char *buf)
+{
+ struct ipoib_dev_priv *priv = netdev_priv(to_net_dev(d));
+
+ if (test_bit(IPOIB_FLAG_ADMIN_CM, &priv->flags))
+ return sprintf(buf, "connected\n");
+ else
+ return sprintf(buf, "datagram\n");
+}
+
+static ssize_t set_mode(struct device *d, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct net_device *dev = to_net_dev(d);
+ struct ipoib_dev_priv *priv = netdev_priv(dev);
+
+ /* flush paths if we switch modes so that connections are restarted */
+ if (IPOIB_CM_SUPPORTED(dev->dev_addr) && !strcmp(buf, "connected\n")) {
+ set_bit(IPOIB_FLAG_ADMIN_CM, &priv->flags);
+ ipoib_warn(priv, "enabling connected mode "
+ "will cause multicast packet drops\n");
+ ipoib_flush_paths(dev);
+ return count;
+ }
+
+ if (!strcmp(buf, "datagram\n")) {
+ clear_bit(IPOIB_FLAG_ADMIN_CM, &priv->flags);
+ dev->mtu = min(priv->mcast_mtu, dev->mtu);
+ ipoib_flush_paths(dev);
+ return count;
+ }
+
+ return -EINVAL;
+}
+
+static DEVICE_ATTR(mode, S_IWUSR | S_IRUGO, show_mode, set_mode);
+
+int ipoib_cm_add_mode_attr(struct net_device *dev)
+{
+ return device_create_file(&dev->dev, &dev_attr_mode);
+}
+
+int ipoib_cm_dev_init(struct net_device *dev)
+{
+ struct ipoib_dev_priv *priv = netdev_priv(dev);
+ struct ib_srq_init_attr srq_init_attr = {
+ .attr = {
+ .max_wr = ipoib_recvq_size,
+ .max_sge = IPOIB_CM_RX_SG
+ }
+ };
+ int ret, i;
+
+ INIT_LIST_HEAD(&priv->cm.passive_ids);
+ INIT_LIST_HEAD(&priv->cm.reap_list);
+ INIT_LIST_HEAD(&priv->cm.start_list);
+ INIT_WORK(&priv->cm.start_task, ipoib_cm_tx_start);
+ INIT_WORK(&priv->cm.reap_task, ipoib_cm_tx_reap);
+ INIT_WORK(&priv->cm.skb_task, ipoib_cm_skb_reap);
+ INIT_DELAYED_WORK(&priv->cm.stale_task, ipoib_cm_stale_task);
+
+ skb_queue_head_init(&priv->cm.skb_queue);
+
+ priv->cm.srq = ib_create_srq(priv->pd, &srq_init_attr);
+ if (IS_ERR(priv->cm.srq)) {
+ ret = PTR_ERR(priv->cm.srq);
+ priv->cm.srq = NULL;
+ return ret;
+ }
+
+ priv->cm.srq_ring = kzalloc(ipoib_recvq_size * sizeof *priv->cm.srq_ring,
+ GFP_KERNEL);
+ if (!priv->cm.srq_ring) {
+ printk(KERN_WARNING "%s: failed to allocate CM ring (%d entries)\n",
+ priv->ca->name, ipoib_recvq_size);
+ ipoib_cm_dev_cleanup(dev);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < IPOIB_CM_RX_SG; ++i)
+ priv->cm.rx_sge[i].lkey = priv->mr->lkey;
+
+ priv->cm.rx_sge[0].length = IPOIB_CM_HEAD_SIZE;
+ for (i = 1; i < IPOIB_CM_RX_SG; ++i)
+ priv->cm.rx_sge[i].length = PAGE_SIZE;
+ priv->cm.rx_wr.next = NULL;
+ priv->cm.rx_wr.sg_list = priv->cm.rx_sge;
+ priv->cm.rx_wr.num_sge = IPOIB_CM_RX_SG;
+
+ for (i = 0; i < ipoib_recvq_size; ++i) {
+ if (ipoib_cm_alloc_rx_skb(dev, i, priv->cm.srq_ring[i].mapping)) {
+ ipoib_warn(priv, "failed to allocate receive buffer %d\n", i);
+ ipoib_cm_dev_cleanup(dev);
+ return -ENOMEM;
+ }
+ if (ipoib_cm_post_receive(dev, i)) {
+ ipoib_warn(priv, "ipoib_ib_post_receive failed for buf %d\n", i);
+ ipoib_cm_dev_cleanup(dev);
+ return -EIO;
+ }
+ }
+
+ priv->dev->dev_addr[0] = IPOIB_FLAGS_RC;
+ return 0;
+}
+
+void ipoib_cm_dev_cleanup(struct net_device *dev)
+{
+ struct ipoib_dev_priv *priv = netdev_priv(dev);
+ int i, ret;
+
+ if (!priv->cm.srq)
+ return;
+
+ ipoib_dbg(priv, "Cleanup ipoib connected mode.\n");
+
+ ret = ib_destroy_srq(priv->cm.srq);
+ if (ret)
+ ipoib_warn(priv, "ib_destroy_srq failed: %d\n", ret);
+
+ priv->cm.srq = NULL;
+ if (!priv->cm.srq_ring)
+ return;
+ for (i = 0; i < ipoib_recvq_size; ++i)
+ if (priv->cm.srq_ring[i].skb) {
+ ipoib_cm_dma_unmap_rx(priv, priv->cm.srq_ring[i].mapping);
+ dev_kfree_skb_any(priv->cm.srq_ring[i].skb);
+ priv->cm.srq_ring[i].skb = NULL;
+ }
+ kfree(priv->cm.srq_ring);
+ priv->cm.srq_ring = NULL;
+}
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_fs.c b/drivers/infiniband/ulp/ipoib/ipoib_fs.c
index f1cb83688b3..44c174182a8 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_fs.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_fs.c
@@ -146,7 +146,7 @@ static int ipoib_mcg_open(struct inode *inode, struct file *file)
return 0;
}
-static struct file_operations ipoib_mcg_fops = {
+static const struct file_operations ipoib_mcg_fops = {
.owner = THIS_MODULE,
.open = ipoib_mcg_open,
.read = seq_read,
@@ -252,7 +252,7 @@ static int ipoib_path_open(struct inode *inode, struct file *file)
return 0;
}
-static struct file_operations ipoib_path_fops = {
+static const struct file_operations ipoib_path_fops = {
.owner = THIS_MODULE,
.open = ipoib_path_open,
.read = seq_read,
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
index 59d9594ed6d..f2aa923ddbe 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
@@ -50,8 +50,6 @@ MODULE_PARM_DESC(data_debug_level,
"Enable data path debug tracing if > 0");
#endif
-#define IPOIB_OP_RECV (1ul << 31)
-
static DEFINE_MUTEX(pkey_mutex);
struct ipoib_ah *ipoib_create_ah(struct net_device *dev,
@@ -268,10 +266,11 @@ static void ipoib_ib_handle_tx_wc(struct net_device *dev, struct ib_wc *wc)
spin_lock_irqsave(&priv->tx_lock, flags);
++priv->tx_tail;
- if (netif_queue_stopped(dev) &&
- test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags) &&
- priv->tx_head - priv->tx_tail <= ipoib_sendq_size >> 1)
+ if (unlikely(test_bit(IPOIB_FLAG_NETIF_STOPPED, &priv->flags)) &&
+ priv->tx_head - priv->tx_tail <= ipoib_sendq_size >> 1) {
+ clear_bit(IPOIB_FLAG_NETIF_STOPPED, &priv->flags);
netif_wake_queue(dev);
+ }
spin_unlock_irqrestore(&priv->tx_lock, flags);
if (wc->status != IB_WC_SUCCESS &&
@@ -283,7 +282,9 @@ static void ipoib_ib_handle_tx_wc(struct net_device *dev, struct ib_wc *wc)
static void ipoib_ib_handle_wc(struct net_device *dev, struct ib_wc *wc)
{
- if (wc->wr_id & IPOIB_OP_RECV)
+ if (wc->wr_id & IPOIB_CM_OP_SRQ)
+ ipoib_cm_handle_rx_wc(dev, wc);
+ else if (wc->wr_id & IPOIB_OP_RECV)
ipoib_ib_handle_rx_wc(dev, wc);
else
ipoib_ib_handle_tx_wc(dev, wc);
@@ -327,12 +328,12 @@ void ipoib_send(struct net_device *dev, struct sk_buff *skb,
struct ipoib_tx_buf *tx_req;
u64 addr;
- if (unlikely(skb->len > dev->mtu + INFINIBAND_ALEN)) {
+ if (unlikely(skb->len > priv->mcast_mtu + INFINIBAND_ALEN)) {
ipoib_warn(priv, "packet len %d (> %d) too long to send, dropping\n",
- skb->len, dev->mtu + INFINIBAND_ALEN);
+ skb->len, priv->mcast_mtu + INFINIBAND_ALEN);
++priv->stats.tx_dropped;
++priv->stats.tx_errors;
- dev_kfree_skb_any(skb);
+ ipoib_cm_skb_too_long(dev, skb, priv->mcast_mtu);
return;
}
@@ -372,6 +373,7 @@ void ipoib_send(struct net_device *dev, struct sk_buff *skb,
if (priv->tx_head - priv->tx_tail == ipoib_sendq_size) {
ipoib_dbg(priv, "TX ring full, stopping kernel net queue\n");
netif_stop_queue(dev);
+ set_bit(IPOIB_FLAG_NETIF_STOPPED, &priv->flags);
}
}
}
@@ -424,6 +426,13 @@ int ipoib_ib_dev_open(struct net_device *dev)
return -1;
}
+ ret = ipoib_cm_dev_open(dev);
+ if (ret) {
+ ipoib_warn(priv, "ipoib_ib_post_receives returned %d\n", ret);
+ ipoib_ib_dev_stop(dev);
+ return -1;
+ }
+
clear_bit(IPOIB_STOP_REAPER, &priv->flags);
queue_delayed_work(ipoib_workqueue, &priv->ah_reap_task, HZ);
@@ -509,6 +518,8 @@ int ipoib_ib_dev_stop(struct net_device *dev)
clear_bit(IPOIB_FLAG_INITIALIZED, &priv->flags);
+ ipoib_cm_dev_stop(dev);
+
/*
* Move our QP to the error state and then reinitialize in
* when all work requests have completed or have been flushed.
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index 705eb1d0e55..18d27fd352a 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -49,8 +49,6 @@
#include <net/dst.h>
-#define IPOIB_QPN(ha) (be32_to_cpup((__be32 *) ha) & 0xffffff)
-
MODULE_AUTHOR("Roland Dreier");
MODULE_DESCRIPTION("IP-over-InfiniBand net driver");
MODULE_LICENSE("Dual BSD/GPL");
@@ -145,6 +143,8 @@ static int ipoib_stop(struct net_device *dev)
netif_stop_queue(dev);
+ clear_bit(IPOIB_FLAG_NETIF_STOPPED, &priv->flags);
+
/*
* Now flush workqueue to make sure a scheduled task doesn't
* bring our internal state back up.
@@ -178,8 +178,18 @@ static int ipoib_change_mtu(struct net_device *dev, int new_mtu)
{
struct ipoib_dev_priv *priv = netdev_priv(dev);
- if (new_mtu > IPOIB_PACKET_SIZE - IPOIB_ENCAP_LEN)
+ /* dev->mtu > 2K ==> connected mode */
+ if (ipoib_cm_admin_enabled(dev) && new_mtu <= IPOIB_CM_MTU) {
+ if (new_mtu > priv->mcast_mtu)
+ ipoib_warn(priv, "mtu > %d will cause multicast packet drops.\n",
+ priv->mcast_mtu);
+ dev->mtu = new_mtu;
+ return 0;
+ }
+
+ if (new_mtu > IPOIB_PACKET_SIZE - IPOIB_ENCAP_LEN) {
return -EINVAL;
+ }
priv->admin_mtu = new_mtu;
@@ -414,6 +424,20 @@ static void path_rec_completion(int status,
memcpy(&neigh->dgid.raw, &path->pathrec.dgid.raw,
sizeof(union ib_gid));
+ if (ipoib_cm_enabled(dev, neigh->neighbour)) {
+ if (!ipoib_cm_get(neigh))
+ ipoib_cm_set(neigh, ipoib_cm_create_tx(dev,
+ path,
+ neigh));
+ if (!ipoib_cm_get(neigh)) {
+ list_del(&neigh->list);
+ if (neigh->ah)
+ ipoib_put_ah(neigh->ah);
+ ipoib_neigh_free(dev, neigh);
+ continue;
+ }
+ }
+
while ((skb = __skb_dequeue(&neigh->queue)))
__skb_queue_tail(&skqueue, skb);
}
@@ -520,7 +544,25 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev)
memcpy(&neigh->dgid.raw, &path->pathrec.dgid.raw,
sizeof(union ib_gid));
- ipoib_send(dev, skb, path->ah, IPOIB_QPN(skb->dst->neighbour->ha));
+ if (ipoib_cm_enabled(dev, neigh->neighbour)) {
+ if (!ipoib_cm_get(neigh))
+ ipoib_cm_set(neigh, ipoib_cm_create_tx(dev, path, neigh));
+ if (!ipoib_cm_get(neigh)) {
+ list_del(&neigh->list);
+ if (neigh->ah)
+ ipoib_put_ah(neigh->ah);
+ ipoib_neigh_free(dev, neigh);
+ goto err_drop;
+ }
+ if (skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE)
+ __skb_queue_tail(&neigh->queue, skb);
+ else {
+ ipoib_warn(priv, "queue length limit %d. Packet drop.\n",
+ skb_queue_len(&neigh->queue));
+ goto err_drop;
+ }
+ } else
+ ipoib_send(dev, skb, path->ah, IPOIB_QPN(skb->dst->neighbour->ha));
} else {
neigh->ah = NULL;
@@ -538,6 +580,7 @@ err_list:
err_path:
ipoib_neigh_free(dev, neigh);
+err_drop:
++priv->stats.tx_dropped;
dev_kfree_skb_any(skb);
@@ -640,7 +683,12 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
neigh = *to_ipoib_neigh(skb->dst->neighbour);
- if (likely(neigh->ah)) {
+ if (ipoib_cm_get(neigh)) {
+ if (ipoib_cm_up(neigh)) {
+ ipoib_cm_send(dev, skb, ipoib_cm_get(neigh));
+ goto out;
+ }
+ } else if (neigh->ah) {
if (unlikely(memcmp(&neigh->dgid.raw,
skb->dst->neighbour->ha + 4,
sizeof(union ib_gid)))) {
@@ -805,6 +853,7 @@ struct ipoib_neigh *ipoib_neigh_alloc(struct neighbour *neighbour)
neigh->neighbour = neighbour;
*to_ipoib_neigh(neighbour) = neigh;
skb_queue_head_init(&neigh->queue);
+ ipoib_cm_set(neigh, NULL);
return neigh;
}
@@ -818,6 +867,8 @@ void ipoib_neigh_free(struct net_device *dev, struct ipoib_neigh *neigh)
++priv->stats.tx_dropped;
dev_kfree_skb_any(skb);
}
+ if (ipoib_cm_get(neigh))
+ ipoib_cm_destroy_tx(ipoib_cm_get(neigh));
kfree(neigh);
}
@@ -958,16 +1009,17 @@ struct ipoib_dev_priv *ipoib_intf_alloc(const char *name)
return netdev_priv(dev);
}
-static ssize_t show_pkey(struct class_device *cdev, char *buf)
+static ssize_t show_pkey(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- struct ipoib_dev_priv *priv =
- netdev_priv(container_of(cdev, struct net_device, class_dev));
+ struct ipoib_dev_priv *priv = netdev_priv(to_net_dev(dev));
return sprintf(buf, "0x%04x\n", priv->pkey);
}
-static CLASS_DEVICE_ATTR(pkey, S_IRUGO, show_pkey, NULL);
+static DEVICE_ATTR(pkey, S_IRUGO, show_pkey, NULL);
-static ssize_t create_child(struct class_device *cdev,
+static ssize_t create_child(struct device *dev,
+ struct device_attribute *attr,
const char *buf, size_t count)
{
int pkey;
@@ -985,14 +1037,14 @@ static ssize_t create_child(struct class_device *cdev,
*/
pkey |= 0x8000;
- ret = ipoib_vlan_add(container_of(cdev, struct net_device, class_dev),
- pkey);
+ ret = ipoib_vlan_add(to_net_dev(dev), pkey);
return ret ? ret : count;
}
-static CLASS_DEVICE_ATTR(create_child, S_IWUGO, NULL, create_child);
+static DEVICE_ATTR(create_child, S_IWUGO, NULL, create_child);
-static ssize_t delete_child(struct class_device *cdev,
+static ssize_t delete_child(struct device *dev,
+ struct device_attribute *attr,
const char *buf, size_t count)
{
int pkey;
@@ -1004,18 +1056,16 @@ static ssize_t delete_child(struct class_device *cdev,
if (pkey < 0 || pkey > 0xffff)
return -EINVAL;
- ret = ipoib_vlan_delete(container_of(cdev, struct net_device, class_dev),
- pkey);
+ ret = ipoib_vlan_delete(to_net_dev(dev), pkey);
return ret ? ret : count;
}
-static CLASS_DEVICE_ATTR(delete_child, S_IWUGO, NULL, delete_child);
+static DEVICE_ATTR(delete_child, S_IWUGO, NULL, delete_child);
int ipoib_add_pkey_attr(struct net_device *dev)
{
- return class_device_create_file(&dev->class_dev,
- &class_device_attr_pkey);
+ return device_create_file(&dev->dev, &dev_attr_pkey);
}
static struct net_device *ipoib_add_port(const char *format,
@@ -1081,13 +1131,13 @@ static struct net_device *ipoib_add_port(const char *format,
ipoib_create_debug_files(priv->dev);
+ if (ipoib_cm_add_mode_attr(priv->dev))
+ goto sysfs_failed;
if (ipoib_add_pkey_attr(priv->dev))
goto sysfs_failed;
- if (class_device_create_file(&priv->dev->class_dev,
- &class_device_attr_create_child))
+ if (device_create_file(&priv->dev->dev, &dev_attr_create_child))
goto sysfs_failed;
- if (class_device_create_file(&priv->dev->class_dev,
- &class_device_attr_delete_child))
+ if (device_create_file(&priv->dev->dev, &dev_attr_delete_child))
goto sysfs_failed;
return priv->dev;
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
index b04b72ca32e..b303ce6bc21 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
@@ -60,14 +60,11 @@ static DEFINE_MUTEX(mcast_mutex);
/* Used for all multicast joins (broadcast, IPv4 mcast and IPv6 mcast) */
struct ipoib_mcast {
struct ib_sa_mcmember_rec mcmember;
+ struct ib_sa_multicast *mc;
struct ipoib_ah *ah;
struct rb_node rb_node;
struct list_head list;
- struct completion done;
-
- int query_id;
- struct ib_sa_query *query;
unsigned long created;
unsigned long backoff;
@@ -299,18 +296,22 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast,
return 0;
}
-static void
+static int
ipoib_mcast_sendonly_join_complete(int status,
- struct ib_sa_mcmember_rec *mcmember,
- void *mcast_ptr)
+ struct ib_sa_multicast *multicast)
{
- struct ipoib_mcast *mcast = mcast_ptr;
+ struct ipoib_mcast *mcast = multicast->context;
struct net_device *dev = mcast->dev;
struct ipoib_dev_priv *priv = netdev_priv(dev);
+ /* We trap for port events ourselves. */
+ if (status == -ENETRESET)
+ return 0;
+
if (!status)
- ipoib_mcast_join_finish(mcast, mcmember);
- else {
+ status = ipoib_mcast_join_finish(mcast, &multicast->rec);
+
+ if (status) {
if (mcast->logcount++ < 20)
ipoib_dbg_mcast(netdev_priv(dev), "multicast join failed for "
IPOIB_GID_FMT ", status %d\n",
@@ -325,11 +326,10 @@ ipoib_mcast_sendonly_join_complete(int status,
spin_unlock_irq(&priv->tx_lock);
/* Clear the busy flag so we try again */
- clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags);
- mcast->query = NULL;
+ status = test_and_clear_bit(IPOIB_MCAST_FLAG_BUSY,
+ &mcast->flags);
}
-
- complete(&mcast->done);
+ return status;
}
static int ipoib_mcast_sendonly_join(struct ipoib_mcast *mcast)
@@ -359,35 +359,33 @@ static int ipoib_mcast_sendonly_join(struct ipoib_mcast *mcast)
rec.port_gid = priv->local_gid;
rec.pkey = cpu_to_be16(priv->pkey);
- init_completion(&mcast->done);
-
- ret = ib_sa_mcmember_rec_set(&ipoib_sa_client, priv->ca, priv->port, &rec,
- IB_SA_MCMEMBER_REC_MGID |
- IB_SA_MCMEMBER_REC_PORT_GID |
- IB_SA_MCMEMBER_REC_PKEY |
- IB_SA_MCMEMBER_REC_JOIN_STATE,
- 1000, GFP_ATOMIC,
- ipoib_mcast_sendonly_join_complete,
- mcast, &mcast->query);
- if (ret < 0) {
- ipoib_warn(priv, "ib_sa_mcmember_rec_set failed (ret = %d)\n",
+ mcast->mc = ib_sa_join_multicast(&ipoib_sa_client, priv->ca,
+ priv->port, &rec,
+ IB_SA_MCMEMBER_REC_MGID |
+ IB_SA_MCMEMBER_REC_PORT_GID |
+ IB_SA_MCMEMBER_REC_PKEY |
+ IB_SA_MCMEMBER_REC_JOIN_STATE,
+ GFP_ATOMIC,
+ ipoib_mcast_sendonly_join_complete,
+ mcast);
+ if (IS_ERR(mcast->mc)) {
+ ret = PTR_ERR(mcast->mc);
+ clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags);
+ ipoib_warn(priv, "ib_sa_join_multicast failed (ret = %d)\n",
ret);
} else {
ipoib_dbg_mcast(priv, "no multicast record for " IPOIB_GID_FMT
", starting join\n",
IPOIB_GID_ARG(mcast->mcmember.mgid));
-
- mcast->query_id = ret;
}
return ret;
}
-static void ipoib_mcast_join_complete(int status,
- struct ib_sa_mcmember_rec *mcmember,
- void *mcast_ptr)
+static int ipoib_mcast_join_complete(int status,
+ struct ib_sa_multicast *multicast)
{
- struct ipoib_mcast *mcast = mcast_ptr;
+ struct ipoib_mcast *mcast = multicast->context;
struct net_device *dev = mcast->dev;
struct ipoib_dev_priv *priv = netdev_priv(dev);
@@ -395,24 +393,25 @@ static void ipoib_mcast_join_complete(int status,
" (status %d)\n",
IPOIB_GID_ARG(mcast->mcmember.mgid), status);
- if (!status && !ipoib_mcast_join_finish(mcast, mcmember)) {
+ /* We trap for port events ourselves. */
+ if (status == -ENETRESET)
+ return 0;
+
+ if (!status)
+ status = ipoib_mcast_join_finish(mcast, &multicast->rec);
+
+ if (!status) {
mcast->backoff = 1;
mutex_lock(&mcast_mutex);
if (test_bit(IPOIB_MCAST_RUN, &priv->flags))
queue_delayed_work(ipoib_workqueue,
&priv->mcast_task, 0);
mutex_unlock(&mcast_mutex);
- complete(&mcast->done);
- return;
- }
-
- if (status == -EINTR) {
- complete(&mcast->done);
- return;
+ return 0;
}
- if (status && mcast->logcount++ < 20) {
- if (status == -ETIMEDOUT || status == -EINTR) {
+ if (mcast->logcount++ < 20) {
+ if (status == -ETIMEDOUT) {
ipoib_dbg_mcast(priv, "multicast join failed for " IPOIB_GID_FMT
", status %d\n",
IPOIB_GID_ARG(mcast->mcmember.mgid),
@@ -429,24 +428,18 @@ static void ipoib_mcast_join_complete(int status,
if (mcast->backoff > IPOIB_MAX_BACKOFF_SECONDS)
mcast->backoff = IPOIB_MAX_BACKOFF_SECONDS;
- mutex_lock(&mcast_mutex);
+ /* Clear the busy flag so we try again */
+ status = test_and_clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags);
+ mutex_lock(&mcast_mutex);
spin_lock_irq(&priv->lock);
- mcast->query = NULL;
-
- if (test_bit(IPOIB_MCAST_RUN, &priv->flags)) {
- if (status == -ETIMEDOUT)
- queue_delayed_work(ipoib_workqueue, &priv->mcast_task,
- 0);
- else
- queue_delayed_work(ipoib_workqueue, &priv->mcast_task,
- mcast->backoff * HZ);
- } else
- complete(&mcast->done);
+ if (test_bit(IPOIB_MCAST_RUN, &priv->flags))
+ queue_delayed_work(ipoib_workqueue, &priv->mcast_task,
+ mcast->backoff * HZ);
spin_unlock_irq(&priv->lock);
mutex_unlock(&mcast_mutex);
- return;
+ return status;
}
static void ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast,
@@ -495,15 +488,14 @@ static void ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast,
rec.hop_limit = priv->broadcast->mcmember.hop_limit;
}
- init_completion(&mcast->done);
-
- ret = ib_sa_mcmember_rec_set(&ipoib_sa_client, priv->ca, priv->port,
- &rec, comp_mask, mcast->backoff * 1000,
- GFP_ATOMIC, ipoib_mcast_join_complete,
- mcast, &mcast->query);
-
- if (ret < 0) {
- ipoib_warn(priv, "ib_sa_mcmember_rec_set failed, status %d\n", ret);
+ set_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags);
+ mcast->mc = ib_sa_join_multicast(&ipoib_sa_client, priv->ca, priv->port,
+ &rec, comp_mask, GFP_KERNEL,
+ ipoib_mcast_join_complete, mcast);
+ if (IS_ERR(mcast->mc)) {
+ clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags);
+ ret = PTR_ERR(mcast->mc);
+ ipoib_warn(priv, "ib_sa_join_multicast failed, status %d\n", ret);
mcast->backoff *= 2;
if (mcast->backoff > IPOIB_MAX_BACKOFF_SECONDS)
@@ -515,8 +507,7 @@ static void ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast,
&priv->mcast_task,
mcast->backoff * HZ);
mutex_unlock(&mcast_mutex);
- } else
- mcast->query_id = ret;
+ }
}
void ipoib_mcast_join_task(struct work_struct *work)
@@ -541,7 +532,7 @@ void ipoib_mcast_join_task(struct work_struct *work)
priv->local_rate = attr.active_speed *
ib_width_enum_to_int(attr.active_width);
} else
- ipoib_warn(priv, "ib_query_port failed\n");
+ ipoib_warn(priv, "ib_query_port failed\n");
}
if (!priv->broadcast) {
@@ -568,7 +559,8 @@ void ipoib_mcast_join_task(struct work_struct *work)
}
if (!test_bit(IPOIB_MCAST_FLAG_ATTACHED, &priv->broadcast->flags)) {
- ipoib_mcast_join(dev, priv->broadcast, 0);
+ if (!test_bit(IPOIB_MCAST_FLAG_BUSY, &priv->broadcast->flags))
+ ipoib_mcast_join(dev, priv->broadcast, 0);
return;
}
@@ -597,7 +589,9 @@ void ipoib_mcast_join_task(struct work_struct *work)
priv->mcast_mtu = ib_mtu_enum_to_int(priv->broadcast->mcmember.mtu) -
IPOIB_ENCAP_LEN;
- dev->mtu = min(priv->mcast_mtu, priv->admin_mtu);
+
+ if (!ipoib_cm_admin_enabled(dev))
+ dev->mtu = min(priv->mcast_mtu, priv->admin_mtu);
ipoib_dbg_mcast(priv, "successfully joined all multicast groups\n");
@@ -623,26 +617,9 @@ int ipoib_mcast_start_thread(struct net_device *dev)
return 0;
}
-static void wait_for_mcast_join(struct ipoib_dev_priv *priv,
- struct ipoib_mcast *mcast)
-{
- spin_lock_irq(&priv->lock);
- if (mcast && mcast->query) {
- ib_sa_cancel_query(mcast->query_id, mcast->query);
- mcast->query = NULL;
- spin_unlock_irq(&priv->lock);
- ipoib_dbg_mcast(priv, "waiting for MGID " IPOIB_GID_FMT "\n",
- IPOIB_GID_ARG(mcast->mcmember.mgid));
- wait_for_completion(&mcast->done);
- }
- else
- spin_unlock_irq(&priv->lock);
-}
-
int ipoib_mcast_stop_thread(struct net_device *dev, int flush)
{
struct ipoib_dev_priv *priv = netdev_priv(dev);
- struct ipoib_mcast *mcast;
ipoib_dbg_mcast(priv, "stopping multicast thread\n");
@@ -658,52 +635,27 @@ int ipoib_mcast_stop_thread(struct net_device *dev, int flush)
if (flush)
flush_workqueue(ipoib_workqueue);
- wait_for_mcast_join(priv, priv->broadcast);
-
- list_for_each_entry(mcast, &priv->multicast_list, list)
- wait_for_mcast_join(priv, mcast);
-
return 0;
}
static int ipoib_mcast_leave(struct net_device *dev, struct ipoib_mcast *mcast)
{
struct ipoib_dev_priv *priv = netdev_priv(dev);
- struct ib_sa_mcmember_rec rec = {
- .join_state = 1
- };
int ret = 0;
- if (!test_and_clear_bit(IPOIB_MCAST_FLAG_ATTACHED, &mcast->flags))
- return 0;
-
- ipoib_dbg_mcast(priv, "leaving MGID " IPOIB_GID_FMT "\n",
- IPOIB_GID_ARG(mcast->mcmember.mgid));
-
- rec.mgid = mcast->mcmember.mgid;
- rec.port_gid = priv->local_gid;
- rec.pkey = cpu_to_be16(priv->pkey);
+ if (test_and_clear_bit(IPOIB_MCAST_FLAG_ATTACHED, &mcast->flags)) {
+ ipoib_dbg_mcast(priv, "leaving MGID " IPOIB_GID_FMT "\n",
+ IPOIB_GID_ARG(mcast->mcmember.mgid));
- /* Remove ourselves from the multicast group */
- ret = ipoib_mcast_detach(dev, be16_to_cpu(mcast->mcmember.mlid),
- &mcast->mcmember.mgid);
- if (ret)
- ipoib_warn(priv, "ipoib_mcast_detach failed (result = %d)\n", ret);
+ /* Remove ourselves from the multicast group */
+ ret = ipoib_mcast_detach(dev, be16_to_cpu(mcast->mcmember.mlid),
+ &mcast->mcmember.mgid);
+ if (ret)
+ ipoib_warn(priv, "ipoib_mcast_detach failed (result = %d)\n", ret);
+ }
- /*
- * Just make one shot at leaving and don't wait for a reply;
- * if we fail, too bad.
- */
- ret = ib_sa_mcmember_rec_delete(&ipoib_sa_client, priv->ca, priv->port, &rec,
- IB_SA_MCMEMBER_REC_MGID |
- IB_SA_MCMEMBER_REC_PORT_GID |
- IB_SA_MCMEMBER_REC_PKEY |
- IB_SA_MCMEMBER_REC_JOIN_STATE,
- 0, GFP_ATOMIC, NULL,
- mcast, &mcast->query);
- if (ret < 0)
- ipoib_warn(priv, "ib_sa_mcmember_rec_delete failed "
- "for leave (result = %d)\n", ret);
+ if (test_and_clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags))
+ ib_sa_free_multicast(mcast->mc);
return 0;
}
@@ -756,7 +708,7 @@ void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb)
dev_kfree_skb_any(skb);
}
- if (mcast->query)
+ if (test_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags))
ipoib_dbg_mcast(priv, "no address vector, "
"but multicast join already started\n");
else if (test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags))
@@ -914,7 +866,6 @@ void ipoib_mcast_restart_task(struct work_struct *work)
/* We have to cancel outside of the spinlock */
list_for_each_entry_safe(mcast, tmcast, &remove_list, list) {
- wait_for_mcast_join(priv, mcast);
ipoib_mcast_leave(mcast->dev, mcast);
ipoib_mcast_free(mcast);
}
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
index 7b717c648f7..3cb551b8875 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
@@ -168,35 +168,41 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca)
.qp_type = IB_QPT_UD
};
+ int ret, size;
+
priv->pd = ib_alloc_pd(priv->ca);
if (IS_ERR(priv->pd)) {
printk(KERN_WARNING "%s: failed to allocate PD\n", ca->name);
return -ENODEV;
}
- priv->cq = ib_create_cq(priv->ca, ipoib_ib_completion, NULL, dev,
- ipoib_sendq_size + ipoib_recvq_size + 1);
+ priv->mr = ib_get_dma_mr(priv->pd, IB_ACCESS_LOCAL_WRITE);
+ if (IS_ERR(priv->mr)) {
+ printk(KERN_WARNING "%s: ib_get_dma_mr failed\n", ca->name);
+ goto out_free_pd;
+ }
+
+ size = ipoib_sendq_size + ipoib_recvq_size + 1;
+ ret = ipoib_cm_dev_init(dev);
+ if (!ret)
+ size += ipoib_recvq_size;
+
+ priv->cq = ib_create_cq(priv->ca, ipoib_ib_completion, NULL, dev, size);
if (IS_ERR(priv->cq)) {
printk(KERN_WARNING "%s: failed to create CQ\n", ca->name);
- goto out_free_pd;
+ goto out_free_mr;
}
if (ib_req_notify_cq(priv->cq, IB_CQ_NEXT_COMP))
goto out_free_cq;
- priv->mr = ib_get_dma_mr(priv->pd, IB_ACCESS_LOCAL_WRITE);
- if (IS_ERR(priv->mr)) {
- printk(KERN_WARNING "%s: ib_get_dma_mr failed\n", ca->name);
- goto out_free_cq;
- }
-
init_attr.send_cq = priv->cq;
init_attr.recv_cq = priv->cq,
priv->qp = ib_create_qp(priv->pd, &init_attr);
if (IS_ERR(priv->qp)) {
printk(KERN_WARNING "%s: failed to create QP\n", ca->name);
- goto out_free_mr;
+ goto out_free_cq;
}
priv->dev->dev_addr[1] = (priv->qp->qp_num >> 16) & 0xff;
@@ -212,12 +218,12 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca)
return 0;
-out_free_mr:
- ib_dereg_mr(priv->mr);
-
out_free_cq:
ib_destroy_cq(priv->cq);
+out_free_mr:
+ ib_dereg_mr(priv->mr);
+
out_free_pd:
ib_dealloc_pd(priv->pd);
return -ENODEV;
@@ -235,12 +241,14 @@ void ipoib_transport_dev_cleanup(struct net_device *dev)
clear_bit(IPOIB_PKEY_ASSIGNED, &priv->flags);
}
- if (ib_dereg_mr(priv->mr))
- ipoib_warn(priv, "ib_dereg_mr failed\n");
-
if (ib_destroy_cq(priv->cq))
ipoib_warn(priv, "ib_cq_destroy failed\n");
+ ipoib_cm_dev_cleanup(dev);
+
+ if (ib_dereg_mr(priv->mr))
+ ipoib_warn(priv, "ib_dereg_mr failed\n");
+
if (ib_dealloc_pd(priv->pd))
ipoib_warn(priv, "ib_dealloc_pd failed\n");
}
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
index f887780e809..6762988439d 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
@@ -42,15 +42,15 @@
#include "ipoib.h"
-static ssize_t show_parent(struct class_device *class_dev, char *buf)
+static ssize_t show_parent(struct device *d, struct device_attribute *attr,
+ char *buf)
{
- struct net_device *dev =
- container_of(class_dev, struct net_device, class_dev);
+ struct net_device *dev = to_net_dev(d);
struct ipoib_dev_priv *priv = netdev_priv(dev);
return sprintf(buf, "%s\n", priv->parent->name);
}
-static CLASS_DEVICE_ATTR(parent, S_IRUGO, show_parent, NULL);
+static DEVICE_ATTR(parent, S_IRUGO, show_parent, NULL);
int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey)
{
@@ -115,11 +115,12 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey)
ipoib_create_debug_files(priv->dev);
+ if (ipoib_cm_add_mode_attr(priv->dev))
+ goto sysfs_failed;
if (ipoib_add_pkey_attr(priv->dev))
goto sysfs_failed;
- if (class_device_create_file(&priv->dev->class_dev,
- &class_device_attr_parent))
+ if (device_create_file(&priv->dev->dev, &dev_attr_parent))
goto sysfs_failed;
list_add_tail(&priv->list, &ppriv->child_intfs);
diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c
index 0a7d1ab60e6..89e37283c83 100644
--- a/drivers/infiniband/ulp/iser/iser_initiator.c
+++ b/drivers/infiniband/ulp/iser/iser_initiator.c
@@ -567,7 +567,7 @@ void iser_rcv_completion(struct iser_desc *rx_desc,
opcode = hdr->opcode & ISCSI_OPCODE_MASK;
if (opcode == ISCSI_OP_SCSI_CMD_RSP) {
- itt = hdr->itt & ISCSI_ITT_MASK; /* mask out cid and age bits */
+ itt = get_itt(hdr->itt); /* mask out cid and age bits */
if (!(itt < session->cmds_max))
iser_err("itt can't be matched to task!!!"
"conn %p opcode %d cmds_max %d itt %d\n",
@@ -625,7 +625,7 @@ void iser_snd_completion(struct iser_desc *tx_desc)
/* this arithmetic is legal by libiscsi dd_data allocation */
mtask = (void *) ((long)(void *)tx_desc -
sizeof(struct iscsi_mgmt_task));
- if (mtask->hdr->itt == cpu_to_be32(ISCSI_RESERVED_TAG)) {
+ if (mtask->hdr->itt == RESERVED_ITT) {
struct iscsi_session *session = conn->session;
spin_lock(&conn->session->lock);
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index 72611fd1510..5e8ac577f0a 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -548,6 +548,7 @@ static int srp_reconnect_target(struct srp_target_port *target)
target->tx_head = 0;
target->tx_tail = 0;
+ target->qp_in_error = 0;
ret = srp_connect_target(target);
if (ret)
goto err;
@@ -878,6 +879,7 @@ static void srp_completion(struct ib_cq *cq, void *target_ptr)
printk(KERN_ERR PFX "failed %s status %d\n",
wc.wr_id & SRP_OP_RECV ? "receive" : "send",
wc.status);
+ target->qp_in_error = 1;
break;
}
@@ -1337,6 +1339,8 @@ static int srp_abort(struct scsi_cmnd *scmnd)
printk(KERN_ERR "SRP abort called\n");
+ if (target->qp_in_error)
+ return FAILED;
if (srp_find_req(target, scmnd, &req))
return FAILED;
if (srp_send_tsk_mgmt(target, req, SRP_TSK_ABORT_TASK))
@@ -1365,6 +1369,8 @@ static int srp_reset_device(struct scsi_cmnd *scmnd)
printk(KERN_ERR "SRP reset_device called\n");
+ if (target->qp_in_error)
+ return FAILED;
if (srp_find_req(target, scmnd, &req))
return FAILED;
if (srp_send_tsk_mgmt(target, req, SRP_TSK_LUN_RESET))
@@ -1801,6 +1807,7 @@ static ssize_t srp_create_target(struct class_device *class_dev,
goto err_free;
}
+ target->qp_in_error = 0;
ret = srp_connect_target(target);
if (ret) {
printk(KERN_ERR PFX "Connection failed\n");
diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h
index c21772317b8..2f3319c719a 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.h
+++ b/drivers/infiniband/ulp/srp/ib_srp.h
@@ -158,6 +158,7 @@ struct srp_target_port {
struct completion done;
int status;
enum srp_target_state state;
+ int qp_in_error;
};
struct srp_iu {
diff --git a/drivers/input/ff-memless.c b/drivers/input/ff-memless.c
index eba18b6ac5e..d226d935b0d 100644
--- a/drivers/input/ff-memless.c
+++ b/drivers/input/ff-memless.c
@@ -29,7 +29,7 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/spinlock.h>
-#include <linux/sched.h>
+#include <linux/jiffies.h>
#include "fixp-arith.h"
diff --git a/drivers/input/gameport/ns558.c b/drivers/input/gameport/ns558.c
index f68dbe6f7f0..7b7a546323c 100644
--- a/drivers/input/gameport/ns558.c
+++ b/drivers/input/gameport/ns558.c
@@ -151,7 +151,6 @@ static int ns558_isa_probe(int io)
return -ENOMEM;
}
- memset(ns558, 0, sizeof(struct ns558));
ns558->io = io;
ns558->size = 1 << i;
ns558->gameport = port;
diff --git a/drivers/input/input.c b/drivers/input/input.c
index 7cf2b4f603a..a9a706f8fff 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -11,7 +11,6 @@
*/
#include <linux/init.h>
-#include <linux/sched.h>
#include <linux/smp_lock.h>
#include <linux/input.h>
#include <linux/module.h>
@@ -482,7 +481,7 @@ static int input_proc_devices_open(struct inode *inode, struct file *file)
return seq_open(file, &input_devices_seq_ops);
}
-static struct file_operations input_devices_fileops = {
+static const struct file_operations input_devices_fileops = {
.owner = THIS_MODULE,
.open = input_proc_devices_open,
.poll = input_proc_devices_poll,
@@ -533,7 +532,7 @@ static int input_proc_handlers_open(struct inode *inode, struct file *file)
return seq_open(file, &input_handlers_seq_ops);
}
-static struct file_operations input_handlers_fileops = {
+static const struct file_operations input_handlers_fileops = {
.owner = THIS_MODULE,
.open = input_proc_handlers_open,
.read = seq_read,
@@ -589,18 +588,9 @@ static inline void input_proc_exit(void) { }
static ssize_t input_dev_show_##name(struct class_device *dev, char *buf) \
{ \
struct input_dev *input_dev = to_input_dev(dev); \
- int retval; \
\
- retval = mutex_lock_interruptible(&input_dev->mutex); \
- if (retval) \
- return retval; \
- \
- retval = scnprintf(buf, PAGE_SIZE, \
- "%s\n", input_dev->name ? input_dev->name : ""); \
- \
- mutex_unlock(&input_dev->mutex); \
- \
- return retval; \
+ return scnprintf(buf, PAGE_SIZE, "%s\n", \
+ input_dev->name ? input_dev->name : ""); \
} \
static CLASS_DEVICE_ATTR(name, S_IRUGO, input_dev_show_##name, NULL);
@@ -1050,10 +1040,6 @@ void input_unregister_device(struct input_dev *dev)
sysfs_remove_group(&dev->cdev.kobj, &input_dev_id_attr_group);
sysfs_remove_group(&dev->cdev.kobj, &input_dev_attr_group);
- mutex_lock(&dev->mutex);
- dev->name = dev->phys = dev->uniq = NULL;
- mutex_unlock(&dev->mutex);
-
class_device_unregister(&dev->cdev);
input_wakeup_procfs_readers();
@@ -1142,7 +1128,7 @@ static int input_open_file(struct inode *inode, struct file *file)
return err;
}
-static struct file_operations input_fops = {
+static const struct file_operations input_fops = {
.owner = THIS_MODULE,
.open = input_open_file,
};
diff --git a/drivers/input/joystick/amijoy.c b/drivers/input/joystick/amijoy.c
index e608691b5a6..b0f5541ec3e 100644
--- a/drivers/input/joystick/amijoy.c
+++ b/drivers/input/joystick/amijoy.c
@@ -50,8 +50,6 @@ static int amijoy[2] = { 0, 1 };
module_param_array_named(map, amijoy, uint, NULL, 0);
MODULE_PARM_DESC(map, "Map of attached joysticks in form of <a>,<b> (default is 0,1)");
-__obsolete_setup("amijoy=");
-
static int amijoy_used;
static DEFINE_MUTEX(amijoy_mutex);
static struct input_dev *amijoy_dev[2];
diff --git a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c
index 7ef68456d7d..51f1e4bfff3 100644
--- a/drivers/input/joystick/analog.c
+++ b/drivers/input/joystick/analog.c
@@ -58,8 +58,6 @@ static int analog_options[ANALOG_PORTS];
module_param_array_named(map, js, charp, &js_nargs, 0);
MODULE_PARM_DESC(map, "Describes analog joysticks type/capabilities");
-__obsolete_setup("js=");
-
/*
* Times, feature definitions.
*/
diff --git a/drivers/input/joystick/db9.c b/drivers/input/joystick/db9.c
index 5080e15c6d3..b41bd2eb37d 100644
--- a/drivers/input/joystick/db9.c
+++ b/drivers/input/joystick/db9.c
@@ -59,10 +59,6 @@ MODULE_PARM_DESC(dev2, "Describes second attached device (<parport#>,<type>)");
module_param_array_named(dev3, db9[2].args, int, &db9[2].nargs, 0);
MODULE_PARM_DESC(dev3, "Describes third attached device (<parport#>,<type>)");
-__obsolete_setup("db9=");
-__obsolete_setup("db9_2=");
-__obsolete_setup("db9_3=");
-
#define DB9_ARG_PARPORT 0
#define DB9_ARG_MODE 1
diff --git a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c
index fe12aa37393..711e4b3e9e6 100644
--- a/drivers/input/joystick/gamecon.c
+++ b/drivers/input/joystick/gamecon.c
@@ -60,10 +60,6 @@ MODULE_PARM_DESC(map2, "Describes second set of devices");
module_param_array_named(map3, gc[2].args, int, &gc[2].nargs, 0);
MODULE_PARM_DESC(map3, "Describes third set of devices");
-__obsolete_setup("gc=");
-__obsolete_setup("gc_2=");
-__obsolete_setup("gc_3=");
-
/* see also gs_psx_delay parameter in PSX support section */
#define GC_SNES 1
@@ -403,8 +399,6 @@ 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)");
-__obsolete_setup("gc_psx_delay=");
-
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 };
diff --git a/drivers/input/joystick/turbografx.c b/drivers/input/joystick/turbografx.c
index 5570fd5487c..037d3487fcc 100644
--- a/drivers/input/joystick/turbografx.c
+++ b/drivers/input/joystick/turbografx.c
@@ -60,10 +60,6 @@ MODULE_PARM_DESC(map2, "Describes second set of devices");
module_param_array_named(map3, tgfx[2].args, int, &tgfx[2].nargs, 0);
MODULE_PARM_DESC(map3, "Describes third set of devices");
-__obsolete_setup("tgfx=");
-__obsolete_setup("tgfx_2=");
-__obsolete_setup("tgfx_3=");
-
#define TGFX_REFRESH_TIME HZ/100 /* 10 ms */
#define TGFX_TRIGGER 0x08
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index 049f2f544e7..64509689fa6 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -135,12 +135,12 @@ config KEYBOARD_STOWAWAY
config KEYBOARD_CORGI
tristate "Corgi keyboard"
depends on PXA_SHARPSL
- default y
+ default y
help
- Say Y here to enable the keyboard on the Sharp Zaurus SL-C7xx
+ Say Y here to enable the keyboard on the Sharp Zaurus SL-C7xx
series of PDAs.
- To compile this driver as a module, choose M here: the
+ To compile this driver as a module, choose M here: the
module will be called corgikbd.
config KEYBOARD_SPITZ
@@ -214,4 +214,17 @@ config KEYBOARD_AAED2000
To compile this driver as a module, choose M here: the
module will be called aaed2000_kbd.
+config KEYBOARD_GPIO
+ tristate "Buttons on CPU GPIOs (PXA)"
+ depends on (ARCH_SA1100 || ARCH_PXA || ARCH_S3C2410)
+ help
+ This driver implements support for buttons connected
+ directly to GPIO pins of SA1100, PXA or S3C24xx CPUs.
+
+ Say Y here if your device has buttons connected
+ directly to GPIO pins of the CPU.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gpio-keys.
+
endif
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index 56879790734..586a0fe53be 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_KEYBOARD_CORGI) += corgikbd.o
obj-$(CONFIG_KEYBOARD_SPITZ) += spitzkbd.o
obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o
obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o
-obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o
-obj-$(CONFIG_KEYBOARD_AAED2000) += aaed2000_kbd.o
+obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o
+obj-$(CONFIG_KEYBOARD_AAED2000) += aaed2000_kbd.o
+obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
index c621a9177a5..663877076bc 100644
--- a/drivers/input/keyboard/atkbd.c
+++ b/drivers/input/keyboard/atkbd.c
@@ -63,10 +63,6 @@ static int 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");
-__obsolete_setup("atkbd_set=");
-__obsolete_setup("atkbd_reset");
-__obsolete_setup("atkbd_softrepeat=");
-
/*
* Scancode to keycode tables. These are just the default setting, and
* are loadable via an userland utility.
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
new file mode 100644
index 00000000000..fa03a00b4c6
--- /dev/null
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -0,0 +1,148 @@
+/*
+ * Driver for keys on GPIO lines capable of generating interrupts.
+ *
+ * Copyright 2005 Phil Blundell
+ *
+ * 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/version.h>
+
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/sched.h>
+#include <linux/pm.h>
+#include <linux/sysctl.h>
+#include <linux/proc_fs.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/irq.h>
+
+#include <asm/gpio.h>
+#include <asm/arch/hardware.h>
+
+#include <asm/hardware/gpio_keys.h>
+
+static irqreturn_t gpio_keys_isr(int irq, void *dev_id)
+{
+ int i;
+ struct platform_device *pdev = dev_id;
+ struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
+ struct input_dev *input = platform_get_drvdata(pdev);
+
+ for (i = 0; i < pdata->nbuttons; i++) {
+ int gpio = pdata->buttons[i].gpio;
+ if (irq == gpio_to_irq(gpio)) {
+ int state = (gpio_get_value(gpio) ? 1 : 0) ^ (pdata->buttons[i].active_low);
+
+ input_report_key(input, pdata->buttons[i].keycode, state);
+ input_sync(input);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int __devinit gpio_keys_probe(struct platform_device *pdev)
+{
+ struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
+ struct input_dev *input;
+ int i, error;
+
+ input = input_allocate_device();
+ if (!input)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, input);
+
+ input->evbit[0] = BIT(EV_KEY);
+
+ input->name = pdev->name;
+ input->phys = "gpio-keys/input0";
+ input->cdev.dev = &pdev->dev;
+ input->private = pdata;
+
+ input->id.bustype = BUS_HOST;
+ input->id.vendor = 0x0001;
+ input->id.product = 0x0001;
+ input->id.version = 0x0100;
+
+ for (i = 0; i < pdata->nbuttons; i++) {
+ int code = pdata->buttons[i].keycode;
+ int irq = gpio_to_irq(pdata->buttons[i].gpio);
+
+ set_irq_type(irq, IRQ_TYPE_EDGE_BOTH);
+ error = request_irq(irq, gpio_keys_isr, IRQF_SAMPLE_RANDOM,
+ pdata->buttons[i].desc ? pdata->buttons[i].desc : "gpio_keys",
+ pdev);
+ if (error) {
+ printk(KERN_ERR "gpio-keys: unable to claim irq %d; error %d\n",
+ irq, error);
+ goto fail;
+ }
+ set_bit(code, input->keybit);
+ }
+
+ error = input_register_device(input);
+ if (error) {
+ printk(KERN_ERR "Unable to register gpio-keys input device\n");
+ goto fail;
+ }
+
+ return 0;
+
+ fail:
+ for (i = i - 1; i >= 0; i--)
+ free_irq(gpio_to_irq(pdata->buttons[i].gpio), pdev);
+
+ input_free_device(input);
+
+ return error;
+}
+
+static int __devexit gpio_keys_remove(struct platform_device *pdev)
+{
+ struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
+ struct input_dev *input = platform_get_drvdata(pdev);
+ int i;
+
+ for (i = 0; i < pdata->nbuttons; i++) {
+ int irq = gpio_to_irq(pdata->buttons[i].gpio);
+ free_irq(irq, pdev);
+ }
+
+ input_unregister_device(input);
+
+ return 0;
+}
+
+struct platform_driver gpio_keys_device_driver = {
+ .probe = gpio_keys_probe,
+ .remove = __devexit_p(gpio_keys_remove),
+ .driver = {
+ .name = "gpio-keys",
+ }
+};
+
+static int __init gpio_keys_init(void)
+{
+ return platform_driver_register(&gpio_keys_device_driver);
+}
+
+static void __exit gpio_keys_exit(void)
+{
+ platform_driver_unregister(&gpio_keys_device_driver);
+}
+
+module_init(gpio_keys_init);
+module_exit(gpio_keys_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Phil Blundell <pb@handhelds.org>");
+MODULE_DESCRIPTION("Keyboard driver for CPU GPIOs");
diff --git a/drivers/input/keyboard/hilkbd.c b/drivers/input/keyboard/hilkbd.c
index 35461eab2fa..4de4dc297d5 100644
--- a/drivers/input/keyboard/hilkbd.c
+++ b/drivers/input/keyboard/hilkbd.c
@@ -6,10 +6,10 @@
* Copyright (C) 1999-2006 Helge Deller <deller@gmx.de>
*
* Very basic HP Human Interface Loop (HIL) driver.
- * This driver handles the keyboard on HP300 (m68k) and on some
+ * This driver handles the keyboard on HP300 (m68k) and on some
* HP700 (parisc) series machines.
*
- *
+ *
* This file is subject to the terms and conditions of the GNU General Public
* License version 2. See the file COPYING in the main directory of this
* archive for more details.
@@ -64,9 +64,9 @@ MODULE_LICENSE("GPL v2");
#endif
-
+
/* HIL helper functions */
-
+
#define hil_busy() (hil_readb(HILBASE + HIL_CMD) & HIL_BUSY)
#define hil_data_available() (hil_readb(HILBASE + HIL_CMD) & HIL_DATA_RDY)
#define hil_status() (hil_readb(HILBASE + HIL_CMD))
@@ -75,7 +75,7 @@ MODULE_LICENSE("GPL v2");
#define hil_write_data(x) do { hil_writeb((x), HILBASE + HIL_DATA); } while (0)
/* HIL constants */
-
+
#define HIL_BUSY 0x02
#define HIL_DATA_RDY 0x01
@@ -86,10 +86,10 @@ MODULE_LICENSE("GPL v2");
#define HIL_INTON 0x5C /* Turn on interrupts. */
#define HIL_INTOFF 0x5D /* Turn off interrupts. */
-#define HIL_READKBDSADR 0xF9
-#define HIL_WRITEKBDSADR 0xE9
+#define HIL_READKBDSADR 0xF9
+#define HIL_WRITEKBDSADR 0xE9
-static unsigned int hphilkeyb_keycode[HIL_KEYCODES_SET1_TBLSIZE] =
+static unsigned int hphilkeyb_keycode[HIL_KEYCODES_SET1_TBLSIZE] =
{ HIL_KEYCODES_SET1 };
/* HIL structure */
@@ -97,11 +97,11 @@ static struct {
struct input_dev *dev;
unsigned int curdev;
-
+
unsigned char s;
unsigned char c;
int valid;
-
+
unsigned char data[16];
unsigned int ptr;
spinlock_t lock;
@@ -115,7 +115,7 @@ static void poll_finished(void)
int down;
int key;
unsigned char scode;
-
+
switch (hil_dev.data[0]) {
case 0x40:
down = (hil_dev.data[1] & 1) == 0;
@@ -127,6 +127,7 @@ static void poll_finished(void)
hil_dev.curdev = 0;
}
+
static inline void handle_status(unsigned char s, unsigned char c)
{
if (c & 0x8) {
@@ -143,6 +144,7 @@ static inline void handle_status(unsigned char s, unsigned char c)
}
}
+
static inline void handle_data(unsigned char s, unsigned char c)
{
if (hil_dev.curdev) {
@@ -152,13 +154,11 @@ static inline void handle_data(unsigned char s, unsigned char c)
}
-/*
- * Handle HIL interrupts.
- */
+/* handle HIL interrupts */
static irqreturn_t hil_interrupt(int irq, void *handle)
{
unsigned char s, c;
-
+
s = hil_status();
c = hil_read_data();
@@ -179,10 +179,8 @@ static irqreturn_t hil_interrupt(int irq, void *handle)
return IRQ_HANDLED;
}
-/*
- * Send a command to the HIL
- */
+/* send a command to the HIL */
static void hil_do(unsigned char cmd, unsigned char *data, unsigned int len)
{
unsigned long flags;
@@ -200,16 +198,14 @@ static void hil_do(unsigned char cmd, unsigned char *data, unsigned int len)
}
-/*
- * Initialise HIL.
- */
-
+/* initialise HIL */
static int __init
hil_keyb_init(void)
{
unsigned char c;
unsigned int i, kbid;
wait_queue_head_t hil_wait;
+ int err;
if (hil_dev.dev) {
return -ENODEV; /* already initialized */
@@ -219,15 +215,25 @@ hil_keyb_init(void)
if (!hil_dev.dev)
return -ENOMEM;
hil_dev.dev->private = &hil_dev;
-
+
#if defined(CONFIG_HP300)
- if (!hwreg_present((void *)(HILBASE + HIL_DATA)))
- return -ENODEV;
-
- request_region(HILBASE+HIL_DATA, 2, "hil");
+ if (!hwreg_present((void *)(HILBASE + HIL_DATA))) {
+ printk(KERN_ERR "HIL: hardware register was not found\n");
+ err = -ENODEV;
+ goto err1;
+ }
+ if (!request_region(HILBASE + HIL_DATA, 2, "hil")) {
+ printk(KERN_ERR "HIL: IOPORT region already used\n");
+ err = -EIO;
+ goto err1;
+ }
#endif
-
- request_irq(HIL_IRQ, hil_interrupt, 0, "hil", hil_dev.dev_id);
+
+ err = request_irq(HIL_IRQ, hil_interrupt, 0, "hil", hil_dev.dev_id);
+ if (err) {
+ printk(KERN_ERR "HIL: Can't get IRQ\n");
+ goto err2;
+ }
/* Turn on interrupts */
hil_do(HIL_INTON, NULL, 0);
@@ -239,47 +245,65 @@ hil_keyb_init(void)
init_waitqueue_head(&hil_wait);
wait_event_interruptible_timeout(hil_wait, hil_dev.valid, 3*HZ);
if (!hil_dev.valid) {
- printk(KERN_WARNING "HIL: timed out, assuming no keyboard present.\n");
+ printk(KERN_WARNING "HIL: timed out, assuming no keyboard present\n");
}
- c = hil_dev.c;
+ c = hil_dev.c;
hil_dev.valid = 0;
if (c == 0) {
kbid = -1;
- printk(KERN_WARNING "HIL: no keyboard present.\n");
+ printk(KERN_WARNING "HIL: no keyboard present\n");
} else {
kbid = ffz(~c);
- /* printk(KERN_INFO "HIL: keyboard found at id %d\n", kbid); */
+ printk(KERN_INFO "HIL: keyboard found at id %d\n", kbid);
}
/* set it to raw mode */
c = 0;
hil_do(HIL_WRITEKBDSADR, &c, 1);
-
+
for (i = 0; i < HIL_KEYCODES_SET1_TBLSIZE; i++)
if (hphilkeyb_keycode[i] != KEY_RESERVED)
set_bit(hphilkeyb_keycode[i], hil_dev.dev->keybit);
- hil_dev.dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
- hil_dev.dev->ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL);
- hil_dev.dev->keycodemax = HIL_KEYCODES_SET1_TBLSIZE;
- hil_dev.dev->keycodesize = sizeof(hphilkeyb_keycode[0]);
- hil_dev.dev->keycode = hphilkeyb_keycode;
- hil_dev.dev->name = "HIL keyboard";
- hil_dev.dev->phys = "hpkbd/input0";
+ hil_dev.dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
+ hil_dev.dev->ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL);
+ hil_dev.dev->keycodemax = HIL_KEYCODES_SET1_TBLSIZE;
+ hil_dev.dev->keycodesize= sizeof(hphilkeyb_keycode[0]);
+ hil_dev.dev->keycode = hphilkeyb_keycode;
+ hil_dev.dev->name = "HIL keyboard";
+ hil_dev.dev->phys = "hpkbd/input0";
hil_dev.dev->id.bustype = BUS_HIL;
hil_dev.dev->id.vendor = PCI_VENDOR_ID_HP;
hil_dev.dev->id.product = 0x0001;
hil_dev.dev->id.version = 0x0010;
- input_register_device(hil_dev.dev);
+ err = input_register_device(hil_dev.dev);
+ if (err) {
+ printk(KERN_ERR "HIL: Can't register device\n");
+ goto err3;
+ }
printk(KERN_INFO "input: %s, ID %d at 0x%08lx (irq %d) found and attached\n",
- hil_dev.dev->name, kbid, HILBASE, HIL_IRQ);
+ hil_dev.dev->name, kbid, HILBASE, HIL_IRQ);
return 0;
+
+err3:
+ hil_do(HIL_INTOFF, NULL, 0);
+ disable_irq(HIL_IRQ);
+ free_irq(HIL_IRQ, hil_dev.dev_id);
+err2:
+#if defined(CONFIG_HP300)
+ release_region(HILBASE + HIL_DATA, 2);
+err1:
+#endif
+ input_free_device(hil_dev.dev);
+ hil_dev.dev = NULL;
+ return err;
}
+
#if defined(CONFIG_PARISC)
static int __init
hil_init_chip(struct parisc_device *dev)
@@ -292,7 +316,7 @@ hil_init_chip(struct parisc_device *dev)
hil_base = dev->hpa.start;
hil_irq = dev->irq;
hil_dev.dev_id = dev;
-
+
printk(KERN_INFO "Found HIL bus at 0x%08lx, IRQ %d\n", hil_base, hil_irq);
return hil_keyb_init();
@@ -313,9 +337,6 @@ static struct parisc_driver hil_driver = {
#endif /* CONFIG_PARISC */
-
-
-
static int __init hil_init(void)
{
#if defined(CONFIG_PARISC)
@@ -349,4 +370,3 @@ static void __exit hil_exit(void)
module_init(hil_init);
module_exit(hil_exit);
-
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index ba0e88c64e1..41b42587f5e 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -50,6 +50,16 @@ config INPUT_WISTRON_BTNS
To compile this driver as a module, choose M here: the module will
be called wistron_btns.
+config INPUT_ATLAS_BTNS
+ tristate "x86 Atlas button interface"
+ depends on X86 && ACPI
+ help
+ Say Y here for support of Atlas wallmount touchscreen buttons.
+ The events will show up as scancodes F1 through F9 via evdev.
+
+ To compile this driver as a module, choose M here: the module will
+ be called atlas_btns.
+
config INPUT_IXP4XX_BEEPER
tristate "IXP4XX Beeper support"
depends on ARCH_IXP4XX
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index 415c4917898..e0a8d58c9e9 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -9,5 +9,6 @@ obj-$(CONFIG_INPUT_PCSPKR) += pcspkr.o
obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o
obj-$(CONFIG_INPUT_UINPUT) += uinput.o
obj-$(CONFIG_INPUT_WISTRON_BTNS) += wistron_btns.o
+obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o
obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o
obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o
diff --git a/drivers/input/misc/atlas_btns.c b/drivers/input/misc/atlas_btns.c
new file mode 100644
index 00000000000..0acc3a12360
--- /dev/null
+++ b/drivers/input/misc/atlas_btns.c
@@ -0,0 +1,170 @@
+/*
+ * atlas_btns.c - Atlas Wallmount Touchscreen ACPI Extras
+ *
+ * Copyright (C) 2006 Jaya Kumar
+ * Based on Toshiba ACPI by John Belmonte and ASUS ACPI
+ * This work was sponsored by CIS(M) Sdn Bhd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under 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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/types.h>
+#include <asm/uaccess.h>
+#include <acpi/acpi_drivers.h>
+
+#define ACPI_ATLAS_NAME "Atlas ACPI"
+#define ACPI_ATLAS_CLASS "Atlas"
+#define ACPI_ATLAS_BUTTON_HID "ASIM0000"
+
+static struct input_dev *input_dev;
+
+/* button handling code */
+static acpi_status acpi_atlas_button_setup(acpi_handle region_handle,
+ u32 function, void *handler_context, void **return_context)
+{
+ *return_context =
+ (function != ACPI_REGION_DEACTIVATE) ? handler_context : NULL;
+
+ return AE_OK;
+}
+
+static acpi_status acpi_atlas_button_handler(u32 function,
+ acpi_physical_address address,
+ u32 bit_width, acpi_integer *value,
+ void *handler_context, void *region_context)
+{
+ acpi_status status;
+ int keycode;
+
+ if (function == ACPI_WRITE) {
+ keycode = KEY_F1 + (address & 0x0F);
+ input_report_key(input_dev, keycode, !(address & 0x10));
+ input_sync(input_dev);
+ status = 0;
+ } else {
+ printk(KERN_WARNING "atlas: shrugged on unexpected function"
+ ":function=%x,address=%lx,value=%x\n",
+ function, (unsigned long)address, (u32)*value);
+ status = -EINVAL;
+ }
+
+ return status;
+}
+
+static int atlas_acpi_button_add(struct acpi_device *device)
+{
+ acpi_status status;
+ int err;
+
+ input_dev = input_allocate_device();
+ if (!input_dev) {
+ printk(KERN_ERR "atlas: unable to allocate input device\n");
+ return -ENOMEM;
+ }
+
+ input_dev->name = "Atlas ACPI button driver";
+ input_dev->phys = "ASIM0000/atlas/input0";
+ input_dev->id.bustype = BUS_HOST;
+ input_dev->evbit[LONG(EV_KEY)] = BIT(EV_KEY);
+
+ set_bit(KEY_F1, input_dev->keybit);
+ set_bit(KEY_F2, input_dev->keybit);
+ set_bit(KEY_F3, input_dev->keybit);
+ set_bit(KEY_F4, input_dev->keybit);
+ set_bit(KEY_F5, input_dev->keybit);
+ set_bit(KEY_F6, input_dev->keybit);
+ set_bit(KEY_F7, input_dev->keybit);
+ set_bit(KEY_F8, input_dev->keybit);
+ set_bit(KEY_F9, input_dev->keybit);
+
+ err = input_register_device(input_dev);
+ if (err) {
+ printk(KERN_ERR "atlas: couldn't register input device\n");
+ input_free_device(input_dev);
+ return err;
+ }
+
+ /* hookup button handler */
+ status = acpi_install_address_space_handler(device->handle,
+ 0x81, &acpi_atlas_button_handler,
+ &acpi_atlas_button_setup, device);
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_ERR "Atlas: Error installing addr spc handler\n");
+ input_unregister_device(input_dev);
+ status = -EINVAL;
+ }
+
+ return status;
+}
+
+static int atlas_acpi_button_remove(struct acpi_device *device, int type)
+{
+ acpi_status status;
+
+ status = acpi_remove_address_space_handler(device->handle,
+ 0x81, &acpi_atlas_button_handler);
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_ERR "Atlas: Error removing addr spc handler\n");
+ status = -EINVAL;
+ }
+
+ input_unregister_device(input_dev);
+
+ return status;
+}
+
+static struct acpi_driver atlas_acpi_driver = {
+ .name = ACPI_ATLAS_NAME,
+ .class = ACPI_ATLAS_CLASS,
+ .ids = ACPI_ATLAS_BUTTON_HID,
+ .ops = {
+ .add = atlas_acpi_button_add,
+ .remove = atlas_acpi_button_remove,
+ },
+};
+
+static int __init atlas_acpi_init(void)
+{
+ int result;
+
+ if (acpi_disabled)
+ return -ENODEV;
+
+ result = acpi_bus_register_driver(&atlas_acpi_driver);
+ if (result < 0) {
+ printk(KERN_ERR "Atlas ACPI: Unable to register driver\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static void __exit atlas_acpi_exit(void)
+{
+ acpi_bus_unregister_driver(&atlas_acpi_driver);
+}
+
+module_init(atlas_acpi_init);
+module_exit(atlas_acpi_exit);
+
+MODULE_AUTHOR("Jaya Kumar");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Atlas button driver");
+
diff --git a/drivers/input/misc/hp_sdc_rtc.c b/drivers/input/misc/hp_sdc_rtc.c
index 31d5a13bfd6..ab76ea442fa 100644
--- a/drivers/input/misc/hp_sdc_rtc.c
+++ b/drivers/input/misc/hp_sdc_rtc.c
@@ -670,7 +670,7 @@ static int hp_sdc_rtc_ioctl(struct inode *inode, struct file *file,
#endif
}
-static struct file_operations hp_sdc_rtc_fops = {
+static const struct file_operations hp_sdc_rtc_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = hp_sdc_rtc_read,
diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
index 9516439b7c7..42556232c52 100644
--- a/drivers/input/misc/uinput.c
+++ b/drivers/input/misc/uinput.c
@@ -627,7 +627,7 @@ static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
return retval;
}
-static struct file_operations uinput_fops = {
+static const struct file_operations uinput_fops = {
.owner = THIS_MODULE,
.open = uinput_open,
.release = uinput_release,
diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c
index 7b9d1c1da41..e1183aeb8ed 100644
--- a/drivers/input/misc/wistron_btns.c
+++ b/drivers/input/misc/wistron_btns.c
@@ -335,6 +335,17 @@ static struct key_entry keymap_aopen_1559as[] = {
{ KE_END, 0 },
};
+static struct key_entry keymap_fs_amilo_d88x0[] = {
+ { KE_KEY, 0x01, KEY_HELP },
+ { KE_KEY, 0x08, KEY_MUTE },
+ { KE_KEY, 0x31, KEY_MAIL },
+ { KE_KEY, 0x36, KEY_WWW },
+ { KE_KEY, 0x11, KEY_PROG1 },
+ { KE_KEY, 0x12, KEY_PROG2 },
+ { KE_KEY, 0x13, KEY_PROG3 },
+ { KE_END, 0 }
+};
+
/*
* If your machine is not here (which is currently rather likely), please send
* a list of buttons and their key codes (reported when loading this module
@@ -413,6 +424,15 @@ static struct dmi_system_id dmi_ids[] __initdata = {
},
.driver_data = keymap_wistron_ms2111
},
+ {
+ .callback = dmi_matched,
+ .ident = "Fujitsu Siemens Amilo D88x0",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "AMILO D"),
+ },
+ .driver_data = keymap_fs_amilo_d88x0
+ },
{ NULL, }
};
diff --git a/drivers/input/mouse/inport.c b/drivers/input/mouse/inport.c
index 13dd96785e3..79b624fe899 100644
--- a/drivers/input/mouse/inport.c
+++ b/drivers/input/mouse/inport.c
@@ -61,7 +61,7 @@ MODULE_LICENSE("GPL");
#define INPORT_REG_MODE 0x07
#define INPORT_RESET 0x80
-#ifdef CONFIG_INPUT_ATIXL
+#ifdef CONFIG_MOUSE_ATIXL
#define INPORT_NAME "ATI XL Mouse"
#define INPORT_VENDOR 0x0002
#define INPORT_SPEED_30HZ 0x01
@@ -84,8 +84,6 @@ static int inport_irq = INPORT_IRQ;
module_param_named(irq, inport_irq, uint, 0);
MODULE_PARM_DESC(irq, "IRQ number (5=default)");
-__obsolete_setup("inport_irq=");
-
static struct input_dev *inport_dev;
static irqreturn_t inport_interrupt(int irq, void *dev_id)
diff --git a/drivers/input/mouse/logibm.c b/drivers/input/mouse/logibm.c
index db205995bff..26c3b2e2ca9 100644
--- a/drivers/input/mouse/logibm.c
+++ b/drivers/input/mouse/logibm.c
@@ -75,8 +75,6 @@ static int logibm_irq = LOGIBM_IRQ;
module_param_named(irq, logibm_irq, uint, 0);
MODULE_PARM_DESC(irq, "IRQ number (5=default)");
-__obsolete_setup("logibm_irq=");
-
static struct input_dev *logibm_dev;
static irqreturn_t logibm_interrupt(int irq, void *dev_id)
diff --git a/drivers/input/mouse/pc110pad.c b/drivers/input/mouse/pc110pad.c
index f155c1fea04..05d992e514f 100644
--- a/drivers/input/mouse/pc110pad.c
+++ b/drivers/input/mouse/pc110pad.c
@@ -113,7 +113,7 @@ static int __init pc110pad_init(void)
dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL);
if (dev) {
pci_dev_put(dev);
- return -ENOENT;
+ return -ENODEV;
}
if (!request_region(pc110pad_io, 4, "pc110pad")) {
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index a0e4a033e2d..0fe5869d7d4 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -93,12 +93,6 @@ static struct attribute_group psmouse_attribute_group = {
.attrs = psmouse_attributes,
};
-__obsolete_setup("psmouse_noext");
-__obsolete_setup("psmouse_resolution=");
-__obsolete_setup("psmouse_smartscroll=");
-__obsolete_setup("psmouse_resetafter=");
-__obsolete_setup("psmouse_rate=");
-
/*
* psmouse_mutex protects all operations changing state of mouse
* (connecting, disconnecting, changing rate or resolution via
@@ -987,8 +981,36 @@ static void psmouse_resync(struct work_struct *work)
static void psmouse_cleanup(struct serio *serio)
{
struct psmouse *psmouse = serio_get_drvdata(serio);
+ struct psmouse *parent = NULL;
+
+ mutex_lock(&psmouse_mutex);
+
+ if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
+ parent = serio_get_drvdata(serio->parent);
+ psmouse_deactivate(parent);
+ }
+
+ psmouse_deactivate(psmouse);
+
+ if (psmouse->cleanup)
+ psmouse->cleanup(psmouse);
psmouse_reset(psmouse);
+
+/*
+ * Some boxes, such as HP nx7400, get terribly confused if mouse
+ * is not fully enabled before suspending/shutting down.
+ */
+ ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE);
+
+ if (parent) {
+ if (parent->pt_deactivate)
+ parent->pt_deactivate(parent);
+
+ psmouse_activate(parent);
+ }
+
+ mutex_unlock(&psmouse_mutex);
}
/*
diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h
index 1b74cae8a55..cf1de95b6f2 100644
--- a/drivers/input/mouse/psmouse.h
+++ b/drivers/input/mouse/psmouse.h
@@ -68,6 +68,7 @@ struct psmouse {
int (*reconnect)(struct psmouse *psmouse);
void (*disconnect)(struct psmouse *psmouse);
+ void (*cleanup)(struct psmouse *psmouse);
int (*poll)(struct psmouse *psmouse);
void (*pt_activate)(struct psmouse *psmouse);
diff --git a/drivers/input/mouse/rpcmouse.c b/drivers/input/mouse/rpcmouse.c
index fbdcfd8eb4e..355efd0423e 100644
--- a/drivers/input/mouse/rpcmouse.c
+++ b/drivers/input/mouse/rpcmouse.c
@@ -18,7 +18,6 @@
*/
#include <linux/module.h>
-#include <linux/sched.h>
#include <linux/ptrace.h>
#include <linux/interrupt.h>
#include <linux/init.h>
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index 49ac696d6cf..f0f9413d762 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -652,6 +652,7 @@ int synaptics_init(struct psmouse *psmouse)
psmouse->set_rate = synaptics_set_rate;
psmouse->disconnect = synaptics_disconnect;
psmouse->reconnect = synaptics_reconnect;
+ psmouse->cleanup = synaptics_reset;
psmouse->pktsize = 6;
/* Synaptics can usually stay in sync without extra help */
psmouse->resync_time = 0;
diff --git a/drivers/input/serio/hil_mlc.c b/drivers/input/serio/hil_mlc.c
index 49e11e2c1d5..4fa93ff3091 100644
--- a/drivers/input/serio/hil_mlc.c
+++ b/drivers/input/serio/hil_mlc.c
@@ -59,7 +59,6 @@
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/timer.h>
-#include <linux/sched.h>
#include <linux/list.h>
MODULE_AUTHOR("Brian S. Julin <bri@calyx.com>");
diff --git a/drivers/input/serio/hp_sdc.c b/drivers/input/serio/hp_sdc.c
index 9907ad3bea2..b57370dc4e3 100644
--- a/drivers/input/serio/hp_sdc.c
+++ b/drivers/input/serio/hp_sdc.c
@@ -62,7 +62,6 @@
*/
#include <linux/hp_sdc.h>
-#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/module.h>
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
index debe9445488..ec195a36e8f 100644
--- a/drivers/input/serio/i8042.c
+++ b/drivers/input/serio/i8042.c
@@ -76,13 +76,6 @@ module_param_named(debug, i8042_debug, bool, 0600);
MODULE_PARM_DESC(debug, "Turn i8042 debugging mode on and off");
#endif
-__obsolete_setup("i8042_noaux");
-__obsolete_setup("i8042_nomux");
-__obsolete_setup("i8042_unlock");
-__obsolete_setup("i8042_reset");
-__obsolete_setup("i8042_direct");
-__obsolete_setup("i8042_dumbkbd");
-
#include "i8042.h"
static DEFINE_SPINLOCK(i8042_lock);
@@ -371,7 +364,7 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id)
if (unlikely(i8042_suppress_kbd_ack))
if (port_no == I8042_KBD_PORT_NO &&
(data == 0xfa || data == 0xfe)) {
- i8042_suppress_kbd_ack = 0;
+ i8042_suppress_kbd_ack--;
goto out;
}
@@ -543,6 +536,7 @@ static int __devinit i8042_check_aux(void)
{
int retval = -1;
int irq_registered = 0;
+ int aux_loop_broken = 0;
unsigned long flags;
unsigned char param;
@@ -572,6 +566,8 @@ static int __devinit i8042_check_aux(void)
if (i8042_command(&param, I8042_CMD_AUX_TEST) ||
(param && param != 0xfa && param != 0xff))
return -1;
+
+ aux_loop_broken = 1;
}
/*
@@ -595,7 +591,7 @@ static int __devinit i8042_check_aux(void)
* used it for a PCI card or somethig else.
*/
- if (i8042_noloop) {
+ if (i8042_noloop || aux_loop_broken) {
/*
* Without LOOP command we can't test AUX IRQ delivery. Assume the port
* is working and hope we are right.
@@ -721,7 +717,7 @@ static int i8042_controller_init(void)
if (~i8042_read_status() & I8042_STR_KEYLOCK) {
if (i8042_unlock)
i8042_ctr |= I8042_CTR_IGNKEYLOCK;
- else
+ else
printk(KERN_WARNING "i8042.c: Warning: Keylock active.\n");
}
spin_unlock_irqrestore(&i8042_lock, flags);
@@ -788,27 +784,6 @@ static void i8042_controller_reset(void)
/*
- * Here we try to reset everything back to a state in which the BIOS will be
- * able to talk to the hardware when rebooting.
- */
-
-static void i8042_controller_cleanup(void)
-{
- int i;
-
-/*
- * Reset anything that is connected to the ports.
- */
-
- for (i = 0; i < I8042_NUM_PORTS; i++)
- if (i8042_ports[i].serio)
- serio_cleanup(i8042_ports[i].serio);
-
- i8042_controller_reset();
-}
-
-
-/*
* i8042_panic_blink() will flash the keyboard LEDs and is called when
* kernel panics. Flashing LEDs is useful for users running X who may
* not see the console and will help distingushing panics from "real"
@@ -838,13 +813,14 @@ static long i8042_panic_blink(long count)
led ^= 0x01 | 0x04;
while (i8042_read_status() & I8042_STR_IBF)
DELAY;
- i8042_suppress_kbd_ack = 1;
+ dbg("%02x -> i8042 (panic blink)", 0xed);
+ i8042_suppress_kbd_ack = 2;
i8042_write_data(0xed); /* set leds */
DELAY;
while (i8042_read_status() & I8042_STR_IBF)
DELAY;
DELAY;
- i8042_suppress_kbd_ack = 1;
+ dbg("%02x -> i8042 (panic blink)", led);
i8042_write_data(led);
DELAY;
last_blink = count;
@@ -853,13 +829,22 @@ static long i8042_panic_blink(long count)
#undef DELAY
+#ifdef CONFIG_PM
/*
- * Here we try to restore the original BIOS settings
+ * Here we try to restore the original BIOS settings. We only want to
+ * do that once, when we really suspend, not when we taking memory
+ * snapshot for swsusp (in this case we'll perform required cleanup
+ * as part of shutdown process).
*/
static int i8042_suspend(struct platform_device *dev, pm_message_t state)
{
- i8042_controller_cleanup();
+ if (dev->dev.power.power_state.event != state.event) {
+ if (state.event == PM_EVENT_SUSPEND)
+ i8042_controller_reset();
+
+ dev->dev.power.power_state = state;
+ }
return 0;
}
@@ -873,6 +858,12 @@ static int i8042_resume(struct platform_device *dev)
{
int error;
+/*
+ * Do not bother with restoring state if we haven't suspened yet
+ */
+ if (dev->dev.power.power_state.event == PM_EVENT_ON)
+ return 0;
+
error = i8042_controller_check();
if (error)
return error;
@@ -882,9 +873,12 @@ static int i8042_resume(struct platform_device *dev)
return error;
/*
- * Restore pre-resume CTR value and disable all ports
+ * Restore original CTR value and disable all ports
*/
+ i8042_ctr = i8042_initial_ctr;
+ if (i8042_direct)
+ i8042_ctr &= ~I8042_CTR_XLATE;
i8042_ctr |= I8042_CTR_AUXDIS | I8042_CTR_KBDDIS;
i8042_ctr &= ~(I8042_CTR_AUXINT | I8042_CTR_KBDINT);
if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
@@ -905,8 +899,11 @@ static int i8042_resume(struct platform_device *dev)
i8042_interrupt(0, NULL);
+ dev->dev.power.power_state = PMSG_ON;
+
return 0;
}
+#endif /* CONFIG_PM */
/*
* We need to reset the 8042 back to original mode on system shutdown,
@@ -915,7 +912,7 @@ static int i8042_resume(struct platform_device *dev)
static void i8042_shutdown(struct platform_device *dev)
{
- i8042_controller_cleanup();
+ i8042_controller_reset();
}
static int __devinit i8042_create_kbd_port(void)
@@ -1150,9 +1147,11 @@ static struct platform_driver i8042_driver = {
},
.probe = i8042_probe,
.remove = __devexit_p(i8042_remove),
+ .shutdown = i8042_shutdown,
+#ifdef CONFIG_PM
.suspend = i8042_suspend,
.resume = i8042_resume,
- .shutdown = i8042_shutdown,
+#endif
};
static int __init i8042_init(void)
diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c
index b3e84d3bb7f..10d9d74ae43 100644
--- a/drivers/input/serio/libps2.c
+++ b/drivers/input/serio/libps2.c
@@ -97,7 +97,7 @@ EXPORT_SYMBOL(ps2_drain);
int ps2_is_keyboard_id(char id_byte)
{
- const static char keyboard_ids[] = {
+ static const char keyboard_ids[] = {
0xab, /* Regular keyboards */
0xac, /* NCD Sun keyboard */
0x2b, /* Trust keyboard, translated */
diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
index f0ce822c102..a15e531ec75 100644
--- a/drivers/input/serio/serio.c
+++ b/drivers/input/serio/serio.c
@@ -45,7 +45,7 @@ EXPORT_SYMBOL(serio_interrupt);
EXPORT_SYMBOL(__serio_register_port);
EXPORT_SYMBOL(serio_unregister_port);
EXPORT_SYMBOL(serio_unregister_child_port);
-EXPORT_SYMBOL(serio_register_driver);
+EXPORT_SYMBOL(__serio_register_driver);
EXPORT_SYMBOL(serio_unregister_driver);
EXPORT_SYMBOL(serio_open);
EXPORT_SYMBOL(serio_close);
@@ -778,6 +778,19 @@ static int serio_driver_remove(struct device *dev)
return 0;
}
+static void serio_cleanup(struct serio *serio)
+{
+ if (serio->drv && serio->drv->cleanup)
+ serio->drv->cleanup(serio);
+}
+
+static void serio_shutdown(struct device *dev)
+{
+ struct serio *serio = to_serio_port(dev);
+
+ serio_cleanup(serio);
+}
+
static void serio_attach_driver(struct serio_driver *drv)
{
int error;
@@ -789,12 +802,14 @@ static void serio_attach_driver(struct serio_driver *drv)
drv->driver.name, error);
}
-int serio_register_driver(struct serio_driver *drv)
+int __serio_register_driver(struct serio_driver *drv, struct module *owner, const char *mod_name)
{
int manual_bind = drv->manual_bind;
int error;
drv->driver.bus = &serio_bus;
+ drv->driver.owner = owner;
+ drv->driver.mod_name = mod_name;
/*
* Temporarily disable automatic binding because probing
@@ -908,11 +923,25 @@ static int serio_uevent(struct device *dev, char **envp, int num_envp, char *buf
#endif /* CONFIG_HOTPLUG */
+#ifdef CONFIG_PM
+static int serio_suspend(struct device *dev, pm_message_t state)
+{
+ if (dev->power.power_state.event != state.event) {
+ if (state.event == PM_EVENT_SUSPEND)
+ serio_cleanup(to_serio_port(dev));
+
+ dev->power.power_state = state;
+ }
+
+ return 0;
+}
+
static int serio_resume(struct device *dev)
{
struct serio *serio = to_serio_port(dev);
- if (serio_reconnect_driver(serio)) {
+ if (dev->power.power_state.event != PM_EVENT_ON &&
+ serio_reconnect_driver(serio)) {
/*
* Driver re-probing can take a while, so better let kseriod
* deal with it.
@@ -920,8 +949,11 @@ static int serio_resume(struct device *dev)
serio_rescan(serio);
}
+ dev->power.power_state = PMSG_ON;
+
return 0;
}
+#endif /* CONFIG_PM */
/* called from serio_driver->connect/disconnect methods under serio_mutex */
int serio_open(struct serio *serio, struct serio_driver *drv)
@@ -972,7 +1004,11 @@ static struct bus_type serio_bus = {
.uevent = serio_uevent,
.probe = serio_driver_probe,
.remove = serio_driver_remove,
+ .shutdown = serio_shutdown,
+#ifdef CONFIG_PM
+ .suspend = serio_suspend,
.resume = serio_resume,
+#endif
};
static int __init serio_init(void)
diff --git a/drivers/input/serio/serio_raw.c b/drivers/input/serio/serio_raw.c
index 088ebc348ba..887357666c6 100644
--- a/drivers/input/serio/serio_raw.c
+++ b/drivers/input/serio/serio_raw.c
@@ -234,7 +234,7 @@ static unsigned int serio_raw_poll(struct file *file, poll_table *wait)
return 0;
}
-static struct file_operations serio_raw_fops = {
+static const struct file_operations serio_raw_fops = {
.owner = THIS_MODULE,
.open = serio_raw_open,
.release = serio_raw_release,
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 6b46c9bf1d2..971618059a6 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -12,13 +12,18 @@ menuconfig INPUT_TOUCHSCREEN
if INPUT_TOUCHSCREEN
config TOUCHSCREEN_ADS7846
- tristate "ADS 7846 based touchscreens"
+ tristate "ADS 7846/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 controller, and your board-specific initialization
+ ADS7846 or ADS7843 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, temperature) sensors of this chip.
+
If unsure, say N (but it's safe to say "Y").
To compile this driver as a module, choose M here: the
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
index c6164b6f476..0a26e066354 100644
--- a/drivers/input/touchscreen/ads7846.c
+++ b/drivers/input/touchscreen/ads7846.c
@@ -17,8 +17,9 @@
* 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/hwmon.h>
#include <linux/init.h>
+#include <linux/err.h>
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/interrupt.h>
@@ -54,7 +55,8 @@
* files.
*/
-#define TS_POLL_PERIOD msecs_to_jiffies(10)
+#define TS_POLL_DELAY (1 * 1000000) /* ns delay before the first sample */
+#define TS_POLL_PERIOD (5 * 1000000) /* ns delay between samples */
/* this driver doesn't aim at the peak continuous sample rate */
#define SAMPLE_BITS (8 /*cmd*/ + 16 /*sample*/ + 2 /* before, after */)
@@ -63,12 +65,12 @@ struct ts_event {
/* For portability, we can't read 12 bit values using SPI (which
* would make the controller deliver them as native byteorder u16
* with msbs zeroed). Instead, we read them as two 8-bit values,
- * which need byteswapping then range adjustment.
+ * *** WHICH NEED BYTESWAPPING *** and range adjustment.
*/
- __be16 x;
- __be16 y;
- __be16 z1, z2;
- int ignore;
+ u16 x;
+ u16 y;
+ u16 z1, z2;
+ int ignore;
};
struct ads7846 {
@@ -76,7 +78,12 @@ struct ads7846 {
char phys[32];
struct spi_device *spi;
+
+#if defined(CONFIG_HWMON) || defined(CONFIG_HWMON_MODULE)
struct attribute_group *attr_group;
+ struct class_device *hwmon;
+#endif
+
u16 model;
u16 vref_delay_usecs;
u16 x_plate_ohms;
@@ -99,13 +106,16 @@ struct ads7846 {
u16 debounce_rep;
spinlock_t lock;
- struct timer_list timer; /* P: lock */
+ struct hrtimer timer;
unsigned pendown:1; /* P: lock */
unsigned pending:1; /* P: lock */
// FIXME remove "irq_disabled"
unsigned irq_disabled:1; /* P: lock */
unsigned disabled:1;
+ int (*filter)(void *data, int data_idx, int *val);
+ void *filter_data;
+ void (*filter_cleanup)(void *data);
int (*get_pendown_state)(void);
};
@@ -142,15 +152,16 @@ struct ads7846 {
#define MAX_12BIT ((1<<12)-1)
/* leave ADC powered up (disables penirq) between differential samples */
-#define READ_12BIT_DFR(x) (ADS_START | ADS_A2A1A0_d_ ## x \
- | ADS_12_BIT | ADS_DFR)
+#define READ_12BIT_DFR(x, adc, vref) (ADS_START | ADS_A2A1A0_d_ ## x \
+ | ADS_12_BIT | ADS_DFR | \
+ (adc ? ADS_PD10_ADC_ON : 0) | (vref ? ADS_PD10_REF_ON : 0))
-#define READ_Y (READ_12BIT_DFR(y) | ADS_PD10_ADC_ON)
-#define READ_Z1 (READ_12BIT_DFR(z1) | ADS_PD10_ADC_ON)
-#define READ_Z2 (READ_12BIT_DFR(z2) | ADS_PD10_ADC_ON)
+#define READ_Y(vref) (READ_12BIT_DFR(y, 1, vref))
+#define READ_Z1(vref) (READ_12BIT_DFR(z1, 1, vref))
+#define READ_Z2(vref) (READ_12BIT_DFR(z2, 1, vref))
-#define READ_X (READ_12BIT_DFR(x) | ADS_PD10_ADC_ON)
-#define PWRDOWN (READ_12BIT_DFR(y) | ADS_PD10_PDOWN) /* LAST */
+#define READ_X(vref) (READ_12BIT_DFR(x, 1, vref))
+#define PWRDOWN (READ_12BIT_DFR(y, 0, 0)) /* LAST */
/* single-ended samples need to first power up reference voltage;
* we leave both ADC and VREF powered
@@ -158,14 +169,19 @@ struct ads7846 {
#define READ_12BIT_SER(x) (ADS_START | ADS_A2A1A0_ ## x \
| ADS_12_BIT | ADS_SER)
-#define REF_ON (READ_12BIT_DFR(x) | ADS_PD10_ALL_ON)
-#define REF_OFF (READ_12BIT_DFR(y) | ADS_PD10_PDOWN)
+#define REF_ON (READ_12BIT_DFR(x, 1, 1))
+#define REF_OFF (READ_12BIT_DFR(y, 0, 0))
/*--------------------------------------------------------------------------*/
/*
* Non-touchscreen sensors only use single-ended conversions.
+ * The range is GND..vREF. The ads7843 and ads7835 must use external vREF;
+ * ads7846 lets that pin be unconnected, to use internal vREF.
*/
+static unsigned vREF_mV;
+module_param(vREF_mV, uint, 0);
+MODULE_PARM_DESC(vREF_mV, "external vREF voltage, in milliVolts");
struct ser_req {
u8 ref_on;
@@ -193,50 +209,55 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)
struct ser_req *req = kzalloc(sizeof *req, GFP_KERNEL);
int status;
int sample;
- int i;
+ int use_internal;
if (!req)
return -ENOMEM;
spi_message_init(&req->msg);
- /* activate reference, so it has time to settle; */
- req->ref_on = REF_ON;
- req->xfer[0].tx_buf = &req->ref_on;
- req->xfer[0].len = 1;
- req->xfer[1].rx_buf = &req->scratch;
- req->xfer[1].len = 2;
-
- /*
- * for external VREF, 0 usec (and assume it's always on);
- * for 1uF, use 800 usec;
- * no cap, 100 usec.
- */
- req->xfer[1].delay_usecs = ts->vref_delay_usecs;
+ /* FIXME boards with ads7846 might use external vref instead ... */
+ use_internal = (ts->model == 7846);
+
+ /* maybe turn on internal vREF, and let it settle */
+ if (use_internal) {
+ req->ref_on = REF_ON;
+ req->xfer[0].tx_buf = &req->ref_on;
+ req->xfer[0].len = 1;
+ spi_message_add_tail(&req->xfer[0], &req->msg);
+
+ req->xfer[1].rx_buf = &req->scratch;
+ req->xfer[1].len = 2;
+
+ /* for 1uF, settle for 800 usec; no cap, 100 usec. */
+ req->xfer[1].delay_usecs = ts->vref_delay_usecs;
+ spi_message_add_tail(&req->xfer[1], &req->msg);
+ }
/* take sample */
req->command = (u8) command;
req->xfer[2].tx_buf = &req->command;
req->xfer[2].len = 1;
+ spi_message_add_tail(&req->xfer[2], &req->msg);
+
req->xfer[3].rx_buf = &req->sample;
req->xfer[3].len = 2;
+ spi_message_add_tail(&req->xfer[3], &req->msg);
/* REVISIT: take a few more samples, and compare ... */
- /* turn off reference */
- req->ref_off = REF_OFF;
- req->xfer[4].tx_buf = &req->ref_off;
- req->xfer[4].len = 1;
- req->xfer[5].rx_buf = &req->scratch;
- req->xfer[5].len = 2;
-
- CS_CHANGE(req->xfer[5]);
-
- /* group all the transfers together, so we can't interfere with
- * reading touchscreen state; disable penirq while sampling
- */
- for (i = 0; i < 6; i++)
- spi_message_add_tail(&req->xfer[i], &req->msg);
+ /* maybe off internal vREF */
+ if (use_internal) {
+ req->ref_off = REF_OFF;
+ req->xfer[4].tx_buf = &req->ref_off;
+ req->xfer[4].len = 1;
+ spi_message_add_tail(&req->xfer[4], &req->msg);
+
+ req->xfer[5].rx_buf = &req->scratch;
+ req->xfer[5].len = 2;
+ CS_CHANGE(req->xfer[5]);
+ spi_message_add_tail(&req->xfer[5], &req->msg);
+ }
ts->irq_disabled = 1;
disable_irq(spi->irq);
@@ -256,25 +277,173 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)
return status ? status : sample;
}
-#define SHOW(name) static ssize_t \
+#if defined(CONFIG_HWMON) || defined(CONFIG_HWMON_MODULE)
+
+#define SHOW(name, var, adjust) static ssize_t \
name ## _show(struct device *dev, struct device_attribute *attr, char *buf) \
{ \
+ struct ads7846 *ts = dev_get_drvdata(dev); \
ssize_t v = ads7846_read12_ser(dev, \
- READ_12BIT_SER(name) | ADS_PD10_ALL_ON); \
+ READ_12BIT_SER(var) | ADS_PD10_ALL_ON); \
if (v < 0) \
return v; \
- return sprintf(buf, "%u\n", (unsigned) v); \
+ return sprintf(buf, "%u\n", adjust(ts, v)); \
} \
static DEVICE_ATTR(name, S_IRUGO, name ## _show, NULL);
-SHOW(temp0)
-SHOW(temp1)
-SHOW(vaux)
-SHOW(vbatt)
+
+/* Sysfs conventions report temperatures in millidegrees Celcius.
+ * ADS7846 could use the low-accuracy two-sample scheme, but can't do the high
+ * accuracy scheme without calibration data. For now we won't try either;
+ * userspace sees raw sensor values, and must scale/calibrate appropriately.
+ */
+static inline unsigned null_adjust(struct ads7846 *ts, ssize_t v)
+{
+ return v;
+}
+
+SHOW(temp0, temp0, null_adjust) /* temp1_input */
+SHOW(temp1, temp1, null_adjust) /* temp2_input */
+
+
+/* sysfs conventions report voltages in millivolts. We can convert voltages
+ * if we know vREF. userspace may need to scale vAUX to match the board's
+ * external resistors; we assume that vBATT only uses the internal ones.
+ */
+static inline unsigned vaux_adjust(struct ads7846 *ts, ssize_t v)
+{
+ unsigned retval = v;
+
+ /* external resistors may scale vAUX into 0..vREF */
+ retval *= vREF_mV;
+ retval = retval >> 12;
+ return retval;
+}
+
+static inline unsigned vbatt_adjust(struct ads7846 *ts, ssize_t v)
+{
+ unsigned retval = vaux_adjust(ts, v);
+
+ /* ads7846 has a resistor ladder to scale this signal down */
+ if (ts->model == 7846)
+ retval *= 4;
+ return retval;
+}
+
+SHOW(in0_input, vaux, vaux_adjust)
+SHOW(in1_input, vbatt, vbatt_adjust)
+
+
+static struct attribute *ads7846_attributes[] = {
+ &dev_attr_temp0.attr,
+ &dev_attr_temp1.attr,
+ &dev_attr_in0_input.attr,
+ &dev_attr_in1_input.attr,
+ NULL,
+};
+
+static struct attribute_group ads7846_attr_group = {
+ .attrs = ads7846_attributes,
+};
+
+static struct attribute *ads7843_attributes[] = {
+ &dev_attr_in0_input.attr,
+ &dev_attr_in1_input.attr,
+ NULL,
+};
+
+static struct attribute_group ads7843_attr_group = {
+ .attrs = ads7843_attributes,
+};
+
+static struct attribute *ads7845_attributes[] = {
+ &dev_attr_in0_input.attr,
+ NULL,
+};
+
+static struct attribute_group ads7845_attr_group = {
+ .attrs = ads7845_attributes,
+};
+
+static int ads784x_hwmon_register(struct spi_device *spi, struct ads7846 *ts)
+{
+ struct class_device *hwmon;
+ int err;
+
+ /* hwmon sensors need a reference voltage */
+ switch (ts->model) {
+ case 7846:
+ if (!vREF_mV) {
+ dev_dbg(&spi->dev, "assuming 2.5V internal vREF\n");
+ vREF_mV = 2500;
+ }
+ break;
+ case 7845:
+ case 7843:
+ if (!vREF_mV) {
+ dev_warn(&spi->dev,
+ "external vREF for ADS%d not specified\n",
+ ts->model);
+ return 0;
+ }
+ break;
+ }
+
+ /* different chips have different sensor groups */
+ switch (ts->model) {
+ case 7846:
+ ts->attr_group = &ads7846_attr_group;
+ break;
+ case 7845:
+ ts->attr_group = &ads7845_attr_group;
+ break;
+ case 7843:
+ ts->attr_group = &ads7843_attr_group;
+ break;
+ default:
+ dev_dbg(&spi->dev, "ADS%d not recognized\n", ts->model);
+ return 0;
+ }
+
+ err = sysfs_create_group(&spi->dev.kobj, ts->attr_group);
+ if (err)
+ return err;
+
+ hwmon = hwmon_device_register(&spi->dev);
+ if (IS_ERR(hwmon)) {
+ sysfs_remove_group(&spi->dev.kobj, ts->attr_group);
+ return PTR_ERR(hwmon);
+ }
+
+ ts->hwmon = hwmon;
+ return 0;
+}
+
+static void ads784x_hwmon_unregister(struct spi_device *spi,
+ struct ads7846 *ts)
+{
+ if (ts->hwmon) {
+ sysfs_remove_group(&spi->dev.kobj, ts->attr_group);
+ hwmon_device_unregister(ts->hwmon);
+ }
+}
+
+#else
+static inline int ads784x_hwmon_register(struct spi_device *spi,
+ struct ads7846 *ts)
+{
+ return 0;
+}
+
+static inline void ads784x_hwmon_unregister(struct spi_device *spi,
+ struct ads7846 *ts)
+{
+}
+#endif
static int is_pen_down(struct device *dev)
{
- struct ads7846 *ts = dev_get_drvdata(dev);
+ struct ads7846 *ts = dev_get_drvdata(dev);
return ts->pendown;
}
@@ -318,46 +487,14 @@ static ssize_t ads7846_disable_store(struct device *dev,
static DEVICE_ATTR(disable, 0664, ads7846_disable_show, ads7846_disable_store);
-static struct attribute *ads7846_attributes[] = {
- &dev_attr_temp0.attr,
- &dev_attr_temp1.attr,
- &dev_attr_vbatt.attr,
- &dev_attr_vaux.attr,
- &dev_attr_pen_down.attr,
- &dev_attr_disable.attr,
- NULL,
-};
-
-static struct attribute_group ads7846_attr_group = {
- .attrs = ads7846_attributes,
-};
-
-/*
- * ads7843/7845 don't have temperature sensors, and
- * use the other sensors a bit differently too
- */
-
-static struct attribute *ads7843_attributes[] = {
- &dev_attr_vbatt.attr,
- &dev_attr_vaux.attr,
+static struct attribute *ads784x_attributes[] = {
&dev_attr_pen_down.attr,
&dev_attr_disable.attr,
NULL,
};
-static struct attribute_group ads7843_attr_group = {
- .attrs = ads7843_attributes,
-};
-
-static struct attribute *ads7845_attributes[] = {
- &dev_attr_vaux.attr,
- &dev_attr_pen_down.attr,
- &dev_attr_disable.attr,
- NULL,
-};
-
-static struct attribute_group ads7845_attr_group = {
- .attrs = ads7845_attributes,
+static struct attribute_group ads784x_attr_group = {
+ .attrs = ads784x_attributes,
};
/*--------------------------------------------------------------------------*/
@@ -373,25 +510,22 @@ static struct attribute_group ads7845_attr_group = {
static void ads7846_rx(void *ads)
{
struct ads7846 *ts = ads;
- struct input_dev *input_dev = ts->input;
unsigned Rt;
- unsigned sync = 0;
u16 x, y, z1, z2;
- unsigned long flags;
- /* adjust: on-wire is a must-ignore bit, a BE12 value, then padding;
- * built from two 8 bit values written msb-first.
+ /* ads7846_rx_val() did in-place conversion (including byteswap) from
+ * on-the-wire format as part of debouncing to get stable readings.
*/
- x = (be16_to_cpu(ts->tc.x) >> 3) & 0x0fff;
- y = (be16_to_cpu(ts->tc.y) >> 3) & 0x0fff;
- z1 = (be16_to_cpu(ts->tc.z1) >> 3) & 0x0fff;
- z2 = (be16_to_cpu(ts->tc.z2) >> 3) & 0x0fff;
+ x = ts->tc.x;
+ y = ts->tc.y;
+ z1 = ts->tc.z1;
+ z2 = ts->tc.z2;
/* range filtering */
if (x == MAX_12BIT)
x = 0;
- if (likely(x && z1 && !device_suspended(&ts->spi->dev))) {
+ if (likely(x && z1)) {
/* compute touch pressure resistance using equation #2 */
Rt = z2;
Rt -= z1;
@@ -403,100 +537,130 @@ static void ads7846_rx(void *ads)
Rt = 0;
/* Sample found inconsistent by debouncing or pressure is beyond
- * the maximum. Don't report it to user space, repeat at least
- * once more the measurement */
+ * the maximum. Don't report it to user space, repeat at least
+ * once more the measurement
+ */
if (ts->tc.ignore || Rt > ts->pressure_max) {
- mod_timer(&ts->timer, jiffies + TS_POLL_PERIOD);
+#ifdef VERBOSE
+ pr_debug("%s: ignored %d pressure %d\n",
+ ts->spi->dev.bus_id, ts->tc.ignore, Rt);
+#endif
+ hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD),
+ HRTIMER_MODE_REL);
return;
}
- /* NOTE: "pendown" is inferred from pressure; we don't rely on
- * being able to check nPENIRQ status, or "friendly" trigger modes
- * (both-edges is much better than just-falling or low-level).
+ /* NOTE: We can't rely on the pressure to determine the pen down
+ * state, even this controller has a pressure sensor. The pressure
+ * value can fluctuate for quite a while after lifting the pen and
+ * in some cases may not even settle at the expected value.
*
- * REVISIT: some boards may require reading nPENIRQ; it's
- * needed on 7843. and 7845 reads pressure differently...
- *
- * REVISIT: the touchscreen might not be connected; this code
- * won't notice that, even if nPENIRQ never fires ...
+ * The only safe way to check for the pen up condition is in the
+ * timer by reading the pen signal state (it's a GPIO _and_ IRQ).
*/
- if (!ts->pendown && Rt != 0) {
- input_report_key(input_dev, BTN_TOUCH, 1);
- sync = 1;
- } else if (ts->pendown && Rt == 0) {
- input_report_key(input_dev, BTN_TOUCH, 0);
- sync = 1;
- }
-
if (Rt) {
- input_report_abs(input_dev, ABS_X, x);
- input_report_abs(input_dev, ABS_Y, y);
- sync = 1;
- }
-
- if (sync) {
- input_report_abs(input_dev, ABS_PRESSURE, Rt);
- input_sync(input_dev);
- }
+ struct input_dev *input = ts->input;
-#ifdef VERBOSE
- if (Rt || ts->pendown)
- pr_debug("%s: %d/%d/%d%s\n", ts->spi->dev.bus_id,
- x, y, Rt, Rt ? "" : " UP");
+ if (!ts->pendown) {
+ input_report_key(input, BTN_TOUCH, 1);
+ ts->pendown = 1;
+#ifdef VERBOSE
+ dev_dbg(&ts->spi->dev, "DOWN\n");
#endif
+ }
+ input_report_abs(input, ABS_X, x);
+ input_report_abs(input, ABS_Y, y);
+ input_report_abs(input, ABS_PRESSURE, Rt);
- spin_lock_irqsave(&ts->lock, flags);
-
- ts->pendown = (Rt != 0);
- mod_timer(&ts->timer, jiffies + TS_POLL_PERIOD);
+ input_sync(input);
+#ifdef VERBOSE
+ dev_dbg(&ts->spi->dev, "%4d/%4d/%4d\n", x, y, Rt);
+#endif
+ }
- spin_unlock_irqrestore(&ts->lock, flags);
+ hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD),
+ HRTIMER_MODE_REL);
}
-static void ads7846_debounce(void *ads)
+static int ads7846_debounce(void *ads, int data_idx, int *val)
{
struct ads7846 *ts = ads;
- struct spi_message *m;
- struct spi_transfer *t;
- int val;
- int status;
- m = &ts->msg[ts->msg_idx];
- t = list_entry(m->transfers.prev, struct spi_transfer, transfer_list);
- val = (be16_to_cpu(*(__be16 *)t->rx_buf) >> 3) & 0x0fff;
- if (!ts->read_cnt || (abs(ts->last_read - val) > ts->debounce_tol)) {
+ if (!ts->read_cnt || (abs(ts->last_read - *val) > ts->debounce_tol)) {
+ /* Start over collecting consistent readings. */
+ ts->read_rep = 0;
/* Repeat it, if this was the first read or the read
* wasn't consistent enough. */
if (ts->read_cnt < ts->debounce_max) {
- ts->last_read = val;
+ ts->last_read = *val;
ts->read_cnt++;
+ return ADS7846_FILTER_REPEAT;
} else {
/* Maximum number of debouncing reached and still
* not enough number of consistent readings. Abort
* the whole sample, repeat it in the next sampling
* period.
*/
- ts->tc.ignore = 1;
ts->read_cnt = 0;
- /* Last message will contain ads7846_rx() as the
- * completion function.
- */
- m = ts->last_msg;
+ return ADS7846_FILTER_IGNORE;
}
- /* Start over collecting consistent readings. */
- ts->read_rep = 0;
} else {
if (++ts->read_rep > ts->debounce_rep) {
/* Got a good reading for this coordinate,
* go for the next one. */
- ts->tc.ignore = 0;
- ts->msg_idx++;
ts->read_cnt = 0;
ts->read_rep = 0;
- m++;
- } else
+ return ADS7846_FILTER_OK;
+ } else {
/* Read more values that are consistent. */
ts->read_cnt++;
+ return ADS7846_FILTER_REPEAT;
+ }
+ }
+}
+
+static int ads7846_no_filter(void *ads, int data_idx, int *val)
+{
+ return ADS7846_FILTER_OK;
+}
+
+static void ads7846_rx_val(void *ads)
+{
+ struct ads7846 *ts = ads;
+ struct spi_message *m;
+ struct spi_transfer *t;
+ u16 *rx_val;
+ int val;
+ int action;
+ int status;
+
+ m = &ts->msg[ts->msg_idx];
+ t = list_entry(m->transfers.prev, struct spi_transfer, transfer_list);
+ rx_val = t->rx_buf;
+
+ /* adjust: on-wire is a must-ignore bit, a BE12 value, then padding;
+ * built from two 8 bit values written msb-first.
+ */
+ val = be16_to_cpu(*rx_val) >> 3;
+
+ action = ts->filter(ts->filter_data, ts->msg_idx, &val);
+ switch (action) {
+ case ADS7846_FILTER_REPEAT:
+ break;
+ case ADS7846_FILTER_IGNORE:
+ ts->tc.ignore = 1;
+ /* Last message will contain ads7846_rx() as the
+ * completion function.
+ */
+ m = ts->last_msg;
+ break;
+ case ADS7846_FILTER_OK:
+ *rx_val = val;
+ ts->tc.ignore = 0;
+ m = &ts->msg[++ts->msg_idx];
+ break;
+ default:
+ BUG();
}
status = spi_async(ts->spi, m);
if (status)
@@ -504,21 +668,34 @@ static void ads7846_debounce(void *ads)
status);
}
-static void ads7846_timer(unsigned long handle)
+static enum hrtimer_restart ads7846_timer(struct hrtimer *handle)
{
- struct ads7846 *ts = (void *)handle;
+ struct ads7846 *ts = container_of(handle, struct ads7846, timer);
int status = 0;
spin_lock_irq(&ts->lock);
- if (unlikely(ts->msg_idx && !ts->pendown)) {
+ if (unlikely(!ts->get_pendown_state() ||
+ device_suspended(&ts->spi->dev))) {
+ if (ts->pendown) {
+ struct input_dev *input = ts->input;
+
+ input_report_key(input, BTN_TOUCH, 0);
+ input_report_abs(input, ABS_PRESSURE, 0);
+ input_sync(input);
+
+ ts->pendown = 0;
+#ifdef VERBOSE
+ dev_dbg(&ts->spi->dev, "UP\n");
+#endif
+ }
+
/* measurement cycle ended */
if (!device_suspended(&ts->spi->dev)) {
ts->irq_disabled = 0;
enable_irq(ts->spi->irq);
}
ts->pending = 0;
- ts->msg_idx = 0;
} else {
/* pen is still down, continue with the measurement */
ts->msg_idx = 0;
@@ -528,6 +705,7 @@ static void ads7846_timer(unsigned long handle)
}
spin_unlock_irq(&ts->lock);
+ return HRTIMER_NORESTART;
}
static irqreturn_t ads7846_irq(int irq, void *handle)
@@ -546,7 +724,8 @@ static irqreturn_t ads7846_irq(int irq, void *handle)
ts->irq_disabled = 1;
disable_irq(ts->spi->irq);
ts->pending = 1;
- mod_timer(&ts->timer, jiffies);
+ hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_DELAY),
+ HRTIMER_MODE_REL);
}
}
spin_unlock_irqrestore(&ts->lock, flags);
@@ -632,6 +811,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
struct ads7846_platform_data *pdata = spi->dev.platform_data;
struct spi_message *m;
struct spi_transfer *x;
+ int vref;
int err;
if (!spi->irq) {
@@ -665,6 +845,10 @@ static int __devinit ads7846_probe(struct spi_device *spi)
* may not. So we stick to very-portable 8 bit words, both RX and TX.
*/
spi->bits_per_word = 8;
+ spi->mode = SPI_MODE_1;
+ err = spi_setup(spi);
+ if (err < 0)
+ return err;
ts = kzalloc(sizeof(struct ads7846), GFP_KERNEL);
input_dev = input_allocate_device();
@@ -679,8 +863,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
ts->spi = spi;
ts->input = input_dev;
- init_timer(&ts->timer);
- ts->timer.data = (unsigned long) ts;
+ hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
ts->timer.function = ads7846_timer;
spin_lock_init(&ts->lock);
@@ -689,14 +872,25 @@ static int __devinit ads7846_probe(struct spi_device *spi)
ts->vref_delay_usecs = pdata->vref_delay_usecs ? : 100;
ts->x_plate_ohms = pdata->x_plate_ohms ? : 400;
ts->pressure_max = pdata->pressure_max ? : ~0;
- if (pdata->debounce_max) {
+
+ if (pdata->filter != NULL) {
+ if (pdata->filter_init != NULL) {
+ err = pdata->filter_init(pdata, &ts->filter_data);
+ if (err < 0)
+ goto err_free_mem;
+ }
+ ts->filter = pdata->filter;
+ ts->filter_cleanup = pdata->filter_cleanup;
+ } else if (pdata->debounce_max) {
ts->debounce_max = pdata->debounce_max;
+ if (ts->debounce_max < 2)
+ ts->debounce_max = 2;
ts->debounce_tol = pdata->debounce_tol;
ts->debounce_rep = pdata->debounce_rep;
- if (ts->debounce_rep > ts->debounce_max + 1)
- ts->debounce_rep = ts->debounce_max - 1;
+ ts->filter = ads7846_debounce;
+ ts->filter_data = ts;
} else
- ts->debounce_tol = ~0;
+ ts->filter = ads7846_no_filter;
ts->get_pendown_state = pdata->get_pendown_state;
snprintf(ts->phys, sizeof(ts->phys), "%s/input0", spi->dev.bus_id);
@@ -718,6 +912,8 @@ static int __devinit ads7846_probe(struct spi_device *spi)
input_set_abs_params(input_dev, ABS_PRESSURE,
pdata->pressure_min, pdata->pressure_max, 0, 0);
+ vref = pdata->keep_vref_on;
+
/* set up the transfers to read touchscreen state; this assumes we
* use formula #2 for pressure, not #3.
*/
@@ -727,7 +923,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
spi_message_init(m);
/* y- still on; turn on only y+ (and ADC) */
- ts->read_y = READ_Y;
+ ts->read_y = READ_Y(vref);
x->tx_buf = &ts->read_y;
x->len = 1;
spi_message_add_tail(x, m);
@@ -737,7 +933,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
x->len = 2;
spi_message_add_tail(x, m);
- m->complete = ads7846_debounce;
+ m->complete = ads7846_rx_val;
m->context = ts;
m++;
@@ -745,7 +941,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
/* turn y- off, x+ on, then leave in lowpower */
x++;
- ts->read_x = READ_X;
+ ts->read_x = READ_X(vref);
x->tx_buf = &ts->read_x;
x->len = 1;
spi_message_add_tail(x, m);
@@ -755,7 +951,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
x->len = 2;
spi_message_add_tail(x, m);
- m->complete = ads7846_debounce;
+ m->complete = ads7846_rx_val;
m->context = ts;
/* turn y+ off, x- on; we'll use formula #2 */
@@ -764,7 +960,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
spi_message_init(m);
x++;
- ts->read_z1 = READ_Z1;
+ ts->read_z1 = READ_Z1(vref);
x->tx_buf = &ts->read_z1;
x->len = 1;
spi_message_add_tail(x, m);
@@ -774,14 +970,14 @@ static int __devinit ads7846_probe(struct spi_device *spi)
x->len = 2;
spi_message_add_tail(x, m);
- m->complete = ads7846_debounce;
+ m->complete = ads7846_rx_val;
m->context = ts;
m++;
spi_message_init(m);
x++;
- ts->read_z2 = READ_Z2;
+ ts->read_z2 = READ_Z2(vref);
x->tx_buf = &ts->read_z2;
x->len = 1;
spi_message_add_tail(x, m);
@@ -791,7 +987,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
x->len = 2;
spi_message_add_tail(x, m);
- m->complete = ads7846_debounce;
+ m->complete = ads7846_rx_val;
m->context = ts;
}
@@ -820,31 +1016,24 @@ static int __devinit ads7846_probe(struct spi_device *spi)
spi->dev.driver->name, ts)) {
dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq);
err = -EBUSY;
- goto err_free_mem;
+ goto err_cleanup_filter;
}
+ err = ads784x_hwmon_register(spi, ts);
+ if (err)
+ goto err_free_irq;
+
dev_info(&spi->dev, "touchscreen, irq %d\n", spi->irq);
- /* take a first sample, leaving nPENIRQ active; avoid
+ /* take a first sample, leaving nPENIRQ active and vREF off; avoid
* the touchscreen, in case it's not connected.
*/
(void) ads7846_read12_ser(&spi->dev,
READ_12BIT_SER(vaux) | ADS_PD10_ALL_ON);
- switch (ts->model) {
- case 7846:
- ts->attr_group = &ads7846_attr_group;
- break;
- case 7845:
- ts->attr_group = &ads7845_attr_group;
- break;
- default:
- ts->attr_group = &ads7843_attr_group;
- break;
- }
- err = sysfs_create_group(&spi->dev.kobj, ts->attr_group);
+ err = sysfs_create_group(&spi->dev.kobj, &ads784x_attr_group);
if (err)
- goto err_free_irq;
+ goto err_remove_hwmon;
err = input_register_device(input_dev);
if (err)
@@ -853,9 +1042,14 @@ static int __devinit ads7846_probe(struct spi_device *spi)
return 0;
err_remove_attr_group:
- sysfs_remove_group(&spi->dev.kobj, ts->attr_group);
+ sysfs_remove_group(&spi->dev.kobj, &ads784x_attr_group);
+ err_remove_hwmon:
+ ads784x_hwmon_unregister(spi, ts);
err_free_irq:
free_irq(spi->irq, ts);
+ err_cleanup_filter:
+ if (ts->filter_cleanup)
+ ts->filter_cleanup(ts->filter_data);
err_free_mem:
input_free_device(input_dev);
kfree(ts);
@@ -866,16 +1060,20 @@ static int __devexit ads7846_remove(struct spi_device *spi)
{
struct ads7846 *ts = dev_get_drvdata(&spi->dev);
+ ads784x_hwmon_unregister(spi, ts);
input_unregister_device(ts->input);
ads7846_suspend(spi, PMSG_SUSPEND);
- sysfs_remove_group(&spi->dev.kobj, ts->attr_group);
+ sysfs_remove_group(&spi->dev.kobj, &ads784x_attr_group);
free_irq(ts->spi->irq, ts);
/* suspend left the IRQ disabled */
enable_irq(ts->spi->irq);
+ if (ts->filter_cleanup)
+ ts->filter_cleanup(ts->filter_data);
+
kfree(ts);
dev_dbg(&spi->dev, "unregistered touchscreen\n");
diff --git a/drivers/input/touchscreen/ucb1400_ts.c b/drivers/input/touchscreen/ucb1400_ts.c
index 4358a0a78ea..c7db4032ef0 100644
--- a/drivers/input/touchscreen/ucb1400_ts.c
+++ b/drivers/input/touchscreen/ucb1400_ts.c
@@ -83,7 +83,7 @@
struct ucb1400 {
- ac97_t *ac97;
+ struct snd_ac97 *ac97;
struct input_dev *ts_idev;
int irq;
diff --git a/drivers/input/tsdev.c b/drivers/input/tsdev.c
index a730c461227..0300dca8591 100644
--- a/drivers/input/tsdev.c
+++ b/drivers/input/tsdev.c
@@ -151,6 +151,10 @@ static int tsdev_open(struct inode *inode, struct file *file)
int i = iminor(inode) - TSDEV_MINOR_BASE;
struct tsdev_list *list;
+ printk(KERN_WARNING "tsdev (compaq touchscreen emulation) is scheduled "
+ "for removal.\nSee Documentation/feature-removal-schedule.txt "
+ "for details.\n");
+
if (i >= TSDEV_MINORS || !tsdev_table[i & TSDEV_MINOR_MASK])
return -ENODEV;
diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c
index d22c0224fde..db1260f73f1 100644
--- a/drivers/isdn/capi/capi.c
+++ b/drivers/isdn/capi/capi.c
@@ -118,6 +118,15 @@ struct capiminor {
};
#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;
u32 ncci;
@@ -589,6 +598,7 @@ static void capi_recv_message(struct capi20_appl *ap, struct sk_buff *skb)
#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
struct capincci *np;
u32 ncci;
+ unsigned long flags;
if (CAPIMSG_CMD(skb->data) == CAPI_CONNECT_B3_CONF) {
u16 info = CAPIMSG_U16(skb->data, 12); // Info field
@@ -603,9 +613,11 @@ static void capi_recv_message(struct capi20_appl *ap, struct sk_buff *skb)
capincci_alloc(cdev, CAPIMSG_NCCI(skb->data));
up(&cdev->ncci_list_sem);
}
+ 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;
}
ncci = CAPIMSG_CONTROL(skb->data);
@@ -615,6 +627,7 @@ static void capi_recv_message(struct capi20_appl *ap, struct sk_buff *skb)
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;
}
#ifndef CONFIG_ISDN_CAPI_MIDDLEWARE
@@ -625,6 +638,7 @@ static void capi_recv_message(struct capi20_appl *ap, struct sk_buff *skb)
if (!mp) {
skb_queue_tail(&cdev->recvqueue, skb);
wake_up_interruptible(&cdev->recvwait);
+ spin_unlock_irqrestore(&workaround_lock, flags);
return;
}
@@ -660,6 +674,7 @@ 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);
}
/* -------- file_operations for capidev ----------------------------- */
@@ -988,7 +1003,7 @@ capi_release(struct inode *inode, struct file *file)
return 0;
}
-static struct file_operations capi_fops =
+static const struct file_operations capi_fops =
{
.owner = THIS_MODULE,
.llseek = no_llseek,
@@ -1006,6 +1021,7 @@ static struct file_operations capi_fops =
static int capinc_tty_open(struct tty_struct * tty, struct file * file)
{
struct capiminor *mp;
+ unsigned long flags;
if ((mp = capiminor_find(iminor(file->f_path.dentry->d_inode))) == 0)
return -ENXIO;
@@ -1014,6 +1030,7 @@ static int capinc_tty_open(struct tty_struct * tty, struct file * file)
tty->driver_data = (void *)mp;
+ spin_lock_irqsave(&workaround_lock, flags);
if (atomic_read(&mp->ttyopencount) == 0)
mp->tty = tty;
atomic_inc(&mp->ttyopencount);
@@ -1021,6 +1038,7 @@ static int capinc_tty_open(struct tty_struct * tty, struct file * file)
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;
}
@@ -1054,6 +1072,7 @@ static int capinc_tty_write(struct tty_struct * tty,
{
struct capiminor *mp = (struct capiminor *)tty->driver_data;
struct sk_buff *skb;
+ unsigned long flags;
#ifdef _DEBUG_TTYFUNCS
printk(KERN_DEBUG "capinc_tty_write(count=%d)\n", count);
@@ -1066,6 +1085,7 @@ static int capinc_tty_write(struct tty_struct * tty,
return 0;
}
+ spin_lock_irqsave(&workaround_lock, flags);
skb = mp->ttyskb;
if (skb) {
mp->ttyskb = NULL;
@@ -1076,6 +1096,7 @@ static int capinc_tty_write(struct tty_struct * tty,
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);
return -ENOMEM;
}
@@ -1086,6 +1107,7 @@ static int capinc_tty_write(struct tty_struct * tty,
mp->outbytes += skb->len;
(void)handle_minor_send(mp);
(void)handle_minor_recv(mp);
+ spin_unlock_irqrestore(&workaround_lock, flags);
return count;
}
@@ -1093,6 +1115,7 @@ static void capinc_tty_put_char(struct tty_struct *tty, unsigned char ch)
{
struct capiminor *mp = (struct capiminor *)tty->driver_data;
struct sk_buff *skb;
+ unsigned long flags;
#ifdef _DEBUG_TTYFUNCS
printk(KERN_DEBUG "capinc_put_char(%u)\n", ch);
@@ -1105,10 +1128,12 @@ static void capinc_tty_put_char(struct tty_struct *tty, unsigned char ch)
return;
}
+ spin_lock_irqsave(&workaround_lock, flags);
skb = mp->ttyskb;
if (skb) {
if (skb_tailroom(skb) > 0) {
*(skb_put(skb, 1)) = ch;
+ spin_unlock_irqrestore(&workaround_lock, flags);
return;
}
mp->ttyskb = NULL;
@@ -1124,12 +1149,14 @@ static void capinc_tty_put_char(struct tty_struct *tty, unsigned char ch)
} else {
printk(KERN_ERR "capinc_put_char: char %u lost\n", ch);
}
+ spin_unlock_irqrestore(&workaround_lock, flags);
}
static void capinc_tty_flush_chars(struct tty_struct *tty)
{
struct capiminor *mp = (struct capiminor *)tty->driver_data;
struct sk_buff *skb;
+ unsigned long flags;
#ifdef _DEBUG_TTYFUNCS
printk(KERN_DEBUG "capinc_tty_flush_chars\n");
@@ -1142,6 +1169,7 @@ static void capinc_tty_flush_chars(struct tty_struct *tty)
return;
}
+ spin_lock_irqsave(&workaround_lock, flags);
skb = mp->ttyskb;
if (skb) {
mp->ttyskb = NULL;
@@ -1150,6 +1178,7 @@ static void capinc_tty_flush_chars(struct tty_struct *tty)
(void)handle_minor_send(mp);
}
(void)handle_minor_recv(mp);
+ spin_unlock_irqrestore(&workaround_lock, flags);
}
static int capinc_tty_write_room(struct tty_struct *tty)
@@ -1220,12 +1249,15 @@ static void capinc_tty_throttle(struct tty_struct * tty)
static void capinc_tty_unthrottle(struct tty_struct * tty)
{
struct capiminor *mp = (struct capiminor *)tty->driver_data;
+ unsigned long flags;
#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);
}
}
@@ -1243,12 +1275,15 @@ static void capinc_tty_stop(struct tty_struct *tty)
static void capinc_tty_start(struct tty_struct *tty)
{
struct capiminor *mp = (struct capiminor *)tty->driver_data;
+ unsigned long flags;
#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);
}
}
@@ -1456,7 +1491,7 @@ static struct procfsentries {
static void __init proc_init(void)
{
- int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]);
+ int nelem = ARRAY_SIZE(procfsentries);
int i;
for (i=0; i < nelem; i++) {
@@ -1468,7 +1503,7 @@ static void __init proc_init(void)
static void __exit proc_exit(void)
{
- int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]);
+ int nelem = ARRAY_SIZE(procfsentries);
int i;
for (i=nelem-1; i >= 0; i--) {
diff --git a/drivers/isdn/capi/capidrv.c b/drivers/isdn/capi/capidrv.c
index c4d438c17da..2a49cea0a22 100644
--- a/drivers/isdn/capi/capidrv.c
+++ b/drivers/isdn/capi/capidrv.c
@@ -13,7 +13,6 @@
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/major.h>
-#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/fcntl.h>
#include <linux/fs.h>
@@ -2218,7 +2217,7 @@ static struct procfsentries {
static void __init proc_init(void)
{
- int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]);
+ int nelem = ARRAY_SIZE(procfsentries);
int i;
for (i=0; i < nelem; i++) {
@@ -2230,7 +2229,7 @@ static void __init proc_init(void)
static void __exit proc_exit(void)
{
- int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]);
+ int nelem = ARRAY_SIZE(procfsentries);
int i;
for (i=nelem-1; i >= 0; i--) {
diff --git a/drivers/isdn/capi/kcapi_proc.c b/drivers/isdn/capi/kcapi_proc.c
index ca9dc00a45c..31f4fd8b8b0 100644
--- a/drivers/isdn/capi/kcapi_proc.c
+++ b/drivers/isdn/capi/kcapi_proc.c
@@ -113,14 +113,14 @@ static int seq_contrstats_open(struct inode *inode, struct file *file)
return seq_open(file, &seq_contrstats_ops);
}
-static struct file_operations proc_controller_ops = {
+static const struct file_operations proc_controller_ops = {
.open = seq_controller_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
-static struct file_operations proc_contrstats_ops = {
+static const struct file_operations proc_contrstats_ops = {
.open = seq_contrstats_open,
.read = seq_read,
.llseek = seq_lseek,
@@ -218,14 +218,14 @@ seq_applstats_open(struct inode *inode, struct file *file)
return seq_open(file, &seq_applstats_ops);
}
-static struct file_operations proc_applications_ops = {
+static const struct file_operations proc_applications_ops = {
.open = seq_applications_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
-static struct file_operations proc_applstats_ops = {
+static const struct file_operations proc_applstats_ops = {
.open = seq_applstats_open,
.read = seq_read,
.llseek = seq_lseek,
@@ -302,7 +302,7 @@ seq_capi_driver_open(struct inode *inode, struct file *file)
return err;
}
-static struct file_operations proc_driver_ops = {
+static const struct file_operations proc_driver_ops = {
.open = seq_capi_driver_open,
.read = seq_read,
.llseek = seq_lseek,
diff --git a/drivers/isdn/divert/divert_procfs.c b/drivers/isdn/divert/divert_procfs.c
index 06967da7c4a..53a18900335 100644
--- a/drivers/isdn/divert/divert_procfs.c
+++ b/drivers/isdn/divert/divert_procfs.c
@@ -256,7 +256,7 @@ isdn_divert_ioctl(struct inode *inode, struct file *file,
#ifdef CONFIG_PROC_FS
-static struct file_operations isdn_fops =
+static const struct file_operations isdn_fops =
{
.owner = THIS_MODULE,
.llseek = no_llseek,
diff --git a/drivers/isdn/gigaset/Kconfig b/drivers/isdn/gigaset/Kconfig
index 708d47a6484..bcbb6502a77 100644
--- a/drivers/isdn/gigaset/Kconfig
+++ b/drivers/isdn/gigaset/Kconfig
@@ -7,7 +7,13 @@ config ISDN_DRV_GIGASET
select CRC_CCITT
select BITREVERSE
help
- Say m here if you have a Gigaset or Sinus isdn device.
+ This driver supports the Siemens Gigaset SX205/255 family of
+ ISDN DECT bases, including the predecessors Gigaset 3070/3075
+ and 4170/4175 and their T-Com versions Sinus 45isdn and Sinus
+ 721X.
+ If you have one of these devices, say M here and for at least
+ one of the connection specific parts that follow.
+ This will build a module called "gigaset".
if ISDN_DRV_GIGASET!=n
@@ -15,14 +21,25 @@ config GIGASET_BASE
tristate "Gigaset base station support"
depends on ISDN_DRV_GIGASET && USB
help
- Say m here if you need to communicate with the base
- directly via USB.
+ Say M here if you want to use the USB interface of the Gigaset
+ base for connection to your system.
+ This will build a module called "bas_gigaset".
config GIGASET_M105
tristate "Gigaset M105 support"
depends on ISDN_DRV_GIGASET && USB
help
- Say m here if you need the driver for the Gigaset M105 device.
+ Say M here if you want to connect to the Gigaset base via DECT
+ using a Gigaset M105 (Sinus 45 Data 2) USB DECT device.
+ This will build a module called "usb_gigaset".
+
+config GIGASET_M101
+ tristate "Gigaset M101 support"
+ depends on ISDN_DRV_GIGASET
+ help
+ Say M here if you want to connect to the Gigaset base via DECT
+ using a Gigaset M101 (Sinus 45 Data 1) RS232 DECT device.
+ This will build a module called "ser_gigaset".
config GIGASET_DEBUG
bool "Gigaset debugging"
diff --git a/drivers/isdn/gigaset/Makefile b/drivers/isdn/gigaset/Makefile
index 9b9acf1a21a..5158be0b7ab 100644
--- a/drivers/isdn/gigaset/Makefile
+++ b/drivers/isdn/gigaset/Makefile
@@ -1,6 +1,8 @@
-gigaset-y := common.o interface.o proc.o ev-layer.o i4l.o
-usb_gigaset-y := usb-gigaset.o asyncdata.o
+gigaset-y := common.o interface.o proc.o ev-layer.o i4l.o asyncdata.o
+usb_gigaset-y := usb-gigaset.o
bas_gigaset-y := bas-gigaset.o isocdata.o
+ser_gigaset-y := ser-gigaset.o
obj-$(CONFIG_GIGASET_M105) += usb_gigaset.o gigaset.o
obj-$(CONFIG_GIGASET_BASE) += bas_gigaset.o gigaset.o
+obj-$(CONFIG_GIGASET_M101) += ser_gigaset.o gigaset.o
diff --git a/drivers/isdn/gigaset/asyncdata.c b/drivers/isdn/gigaset/asyncdata.c
index 88e958f176d..f2f108fcec4 100644
--- a/drivers/isdn/gigaset/asyncdata.c
+++ b/drivers/isdn/gigaset/asyncdata.c
@@ -13,6 +13,11 @@
* =====================================================================
*/
+/* not set by Kbuild when building both ser_gigaset and usb_gigaset */
+#ifndef KBUILD_MODNAME
+#define KBUILD_MODNAME "asy_gigaset"
+#endif
+
#include "gigaset.h"
#include <linux/crc-ccitt.h>
#include <linux/bitrev.h>
@@ -439,6 +444,7 @@ nextbyte:
atomic_set(&inbuf->head, head);
}
}
+EXPORT_SYMBOL_GPL(gigaset_m10x_input);
/* == data output ========================================================== */
@@ -586,3 +592,4 @@ int gigaset_m10x_send_skb(struct bc_state *bcs, struct sk_buff *skb)
return len; /* ok so far */
}
+EXPORT_SYMBOL_GPL(gigaset_m10x_send_skb);
diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c
index b5e7f9c7d74..63e51dd6deb 100644
--- a/drivers/isdn/gigaset/bas-gigaset.c
+++ b/drivers/isdn/gigaset/bas-gigaset.c
@@ -257,10 +257,10 @@ static inline void dump_urb(enum debuglevel level, const char *tag,
urb->transfer_flags);
gig_dbg(level,
" transfer_buffer=0x%08lx[%d], actual_length=%d, "
- "bandwidth=%d, setup_packet=0x%08lx,",
+ "setup_packet=0x%08lx,",
(unsigned long) urb->transfer_buffer,
urb->transfer_buffer_length, urb->actual_length,
- urb->bandwidth, (unsigned long) urb->setup_packet);
+ (unsigned long) urb->setup_packet);
gig_dbg(level,
" start_frame=%d, number_of_packets=%d, interval=%d, "
"error_count=%d,",
diff --git a/drivers/isdn/gigaset/common.c b/drivers/isdn/gigaset/common.c
index 4f75cce6fdf..b460a73a7c8 100644
--- a/drivers/isdn/gigaset/common.c
+++ b/drivers/isdn/gigaset/common.c
@@ -640,7 +640,6 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels,
return NULL;
}
mutex_init(&cs->mutex);
- mutex_lock(&cs->mutex);
gig_dbg(DEBUG_INIT, "allocating bcs[0..%d]", channels - 1);
cs->bcs = kmalloc(channels * sizeof(struct bc_state), GFP_KERNEL);
@@ -738,6 +737,7 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels,
++cs->cs_init;
+ /* set up character device */
gigaset_if_init(cs);
/* set up device sysfs */
@@ -753,11 +753,9 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels,
add_timer(&cs->timer);
gig_dbg(DEBUG_INIT, "cs initialized");
- mutex_unlock(&cs->mutex);
return cs;
error:
- mutex_unlock(&cs->mutex);
gig_dbg(DEBUG_INIT, "failed");
gigaset_freecs(cs);
return NULL;
@@ -908,20 +906,7 @@ void gigaset_shutdown(struct cardstate *cs)
gig_dbg(DEBUG_CMD, "scheduling SHUTDOWN");
gigaset_schedule_event(cs);
- if (wait_event_interruptible(cs->waitqueue, !cs->waiting)) {
- warn("%s: aborted", __func__);
- //FIXME
- }
-
- if (atomic_read(&cs->mstate) != MS_LOCKED) {
- //FIXME?
- //gigaset_baud_rate(cs, B115200);
- //gigaset_set_line_ctrl(cs, CS8);
- //gigaset_set_modem_ctrl(cs, TIOCM_DTR|TIOCM_RTS, 0);
- //cs->control_state = 0;
- } else {
- //FIXME use some saved values?
- }
+ wait_event(cs->waitqueue, !cs->waiting);
cleanup_cs(cs);
@@ -944,10 +929,7 @@ void gigaset_stop(struct cardstate *cs)
gig_dbg(DEBUG_CMD, "scheduling STOP");
gigaset_schedule_event(cs);
- if (wait_event_interruptible(cs->waitqueue, !cs->waiting)) {
- warn("%s: aborted", __func__);
- //FIXME
- }
+ wait_event(cs->waitqueue, !cs->waiting);
cleanup_cs(cs);
diff --git a/drivers/isdn/gigaset/ev-layer.c b/drivers/isdn/gigaset/ev-layer.c
index 44f02dbd111..4661e2c722b 100644
--- a/drivers/isdn/gigaset/ev-layer.c
+++ b/drivers/isdn/gigaset/ev-layer.c
@@ -1015,7 +1015,7 @@ static void finish_shutdown(struct cardstate *cs)
cs->cmd_result = -ENODEV;
cs->waiting = 0;
- wake_up_interruptible(&cs->waitqueue);
+ wake_up(&cs->waitqueue);
}
static void do_shutdown(struct cardstate *cs)
diff --git a/drivers/isdn/gigaset/interface.c b/drivers/isdn/gigaset/interface.c
index 458b6462f93..eb50f3dab5f 100644
--- a/drivers/isdn/gigaset/interface.c
+++ b/drivers/isdn/gigaset/interface.c
@@ -599,19 +599,9 @@ out:
static void if_wake(unsigned long data)
{
struct cardstate *cs = (struct cardstate *) data;
- struct tty_struct *tty;
-
- tty = cs->tty;
- if (!tty)
- return;
-
- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
- tty->ldisc.write_wakeup) {
- gig_dbg(DEBUG_IF, "write wakeup call");
- tty->ldisc.write_wakeup(tty);
- }
- wake_up_interruptible(&tty->write_wait);
+ if (cs->tty)
+ tty_wakeup(cs->tty);
}
/*** interface to common ***/
@@ -625,6 +615,8 @@ void gigaset_if_init(struct cardstate *cs)
return;
tasklet_init(&cs->if_wake_tasklet, &if_wake, (unsigned long) cs);
+
+ mutex_lock(&cs->mutex);
cs->tty_dev = tty_register_device(drv->tty, cs->minor_index, NULL);
if (!IS_ERR(cs->tty_dev))
@@ -633,6 +625,7 @@ void gigaset_if_init(struct cardstate *cs)
warn("could not register device to the tty subsystem");
cs->tty_dev = NULL;
}
+ mutex_unlock(&cs->mutex);
}
void gigaset_if_free(struct cardstate *cs)
diff --git a/drivers/isdn/gigaset/isocdata.c b/drivers/isdn/gigaset/isocdata.c
index df988eb0e36..8c0eb522dab 100644
--- a/drivers/isdn/gigaset/isocdata.c
+++ b/drivers/isdn/gigaset/isocdata.c
@@ -921,6 +921,8 @@ static void cmd_loop(unsigned char *src, int numbytes, struct inbuf_t *inbuf)
/* 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");
cs->cbytes = cbytes;
gigaset_handle_modem_response(cs);
cbytes = 0;
@@ -929,8 +931,6 @@ static void cmd_loop(unsigned char *src, int numbytes, struct inbuf_t *inbuf)
/* advance in line buffer, checking for overflow */
if (cbytes < MAX_RESP_SIZE - 1)
cbytes++;
- else
- dev_warn(cs->dev, "response too large\n");
}
}
diff --git a/drivers/isdn/gigaset/ser-gigaset.c b/drivers/isdn/gigaset/ser-gigaset.c
new file mode 100644
index 00000000000..c8b7db65e48
--- /dev/null
+++ b/drivers/isdn/gigaset/ser-gigaset.c
@@ -0,0 +1,837 @@
+/* This is the serial hardware link layer (HLL) for the Gigaset 307x isdn
+ * DECT base (aka Sinus 45 isdn) using the RS232 DECT data module M101,
+ * written as a line discipline.
+ *
+ * =====================================================================
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ * =====================================================================
+ */
+
+#include "gigaset.h"
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/tty.h>
+#include <linux/poll.h>
+
+/* Version Information */
+#define DRIVER_AUTHOR "Tilman Schmidt"
+#define DRIVER_DESC "Serial Driver for Gigaset 307x using Siemens M101"
+
+#define GIGASET_MINORS 1
+#define GIGASET_MINOR 0
+#define GIGASET_MODULENAME "ser_gigaset"
+#define GIGASET_DEVNAME "ttyGS"
+
+/* length limit according to Siemens 3070usb-protokoll.doc ch. 2.1 */
+#define IF_WRITEBUF 264
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_LDISC(N_GIGASET_M101);
+
+static int startmode = SM_ISDN;
+module_param(startmode, int, S_IRUGO);
+MODULE_PARM_DESC(startmode, "initial operation mode");
+static int cidmode = 1;
+module_param(cidmode, int, S_IRUGO);
+MODULE_PARM_DESC(cidmode, "stay in CID mode when idle");
+
+static struct gigaset_driver *driver;
+
+struct ser_cardstate {
+ struct platform_device dev;
+ struct tty_struct *tty;
+ atomic_t refcnt;
+ struct mutex dead_mutex;
+};
+
+static struct platform_driver device_driver = {
+ .driver = {
+ .name = GIGASET_MODULENAME,
+ },
+};
+
+static void flush_send_queue(struct cardstate *);
+
+/* transmit data from current open skb
+ * result: number of bytes sent or error code < 0
+ */
+static int write_modem(struct cardstate *cs)
+{
+ struct tty_struct *tty = cs->hw.ser->tty;
+ struct bc_state *bcs = &cs->bcs[0]; /* only one channel */
+ struct sk_buff *skb = bcs->tx_skb;
+ int sent;
+
+ if (!tty || !tty->driver || !skb)
+ return -EFAULT;
+
+ if (!skb->len) {
+ dev_kfree_skb_any(skb);
+ bcs->tx_skb = NULL;
+ return -EINVAL;
+ }
+
+ set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
+ sent = tty->driver->write(tty, skb->data, skb->len);
+ gig_dbg(DEBUG_OUTPUT, "write_modem: sent %d", sent);
+ if (sent < 0) {
+ /* error */
+ flush_send_queue(cs);
+ return sent;
+ }
+ skb_pull(skb, sent);
+ if (!skb->len) {
+ /* skb sent completely */
+ gigaset_skb_sent(bcs, skb);
+
+ gig_dbg(DEBUG_INTR, "kfree skb (Adr: %lx)!",
+ (unsigned long) skb);
+ dev_kfree_skb_any(skb);
+ bcs->tx_skb = NULL;
+ }
+ return sent;
+}
+
+/*
+ * transmit first queued command buffer
+ * result: number of bytes sent or error code < 0
+ */
+static int send_cb(struct cardstate *cs)
+{
+ struct tty_struct *tty = cs->hw.ser->tty;
+ struct cmdbuf_t *cb, *tcb;
+ unsigned long flags;
+ int sent = 0;
+
+ if (!tty || !tty->driver)
+ return -EFAULT;
+
+ cb = cs->cmdbuf;
+ if (!cb)
+ return 0; /* nothing to do */
+
+ if (cb->len) {
+ set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
+ sent = tty->driver->write(tty, cb->buf + cb->offset, cb->len);
+ if (sent < 0) {
+ /* error */
+ gig_dbg(DEBUG_OUTPUT, "send_cb: write error %d", sent);
+ flush_send_queue(cs);
+ return sent;
+ }
+ cb->offset += sent;
+ cb->len -= sent;
+ gig_dbg(DEBUG_OUTPUT, "send_cb: sent %d, left %u, queued %u",
+ sent, cb->len, cs->cmdbytes);
+ }
+
+ while (cb && !cb->len) {
+ spin_lock_irqsave(&cs->cmdlock, flags);
+ cs->cmdbytes -= cs->curlen;
+ tcb = cb;
+ cs->cmdbuf = cb = cb->next;
+ if (cb) {
+ cb->prev = NULL;
+ cs->curlen = cb->len;
+ } else {
+ cs->lastcmdbuf = NULL;
+ cs->curlen = 0;
+ }
+ spin_unlock_irqrestore(&cs->cmdlock, flags);
+
+ if (tcb->wake_tasklet)
+ tasklet_schedule(tcb->wake_tasklet);
+ kfree(tcb);
+ }
+ return sent;
+}
+
+/*
+ * send queue tasklet
+ * If there is already a skb opened, put data to the transfer buffer
+ * by calling "write_modem".
+ * Otherwise take a new skb out of the queue.
+ */
+static void gigaset_modem_fill(unsigned long data)
+{
+ struct cardstate *cs = (struct cardstate *) data;
+ struct bc_state *bcs;
+ int sent = 0;
+
+ if (!cs || !(bcs = cs->bcs)) {
+ gig_dbg(DEBUG_OUTPUT, "%s: no cardstate", __func__);
+ return;
+ }
+ if (!bcs->tx_skb) {
+ /* no skb is being sent; send command if any */
+ sent = send_cb(cs);
+ gig_dbg(DEBUG_OUTPUT, "%s: send_cb -> %d", __func__, sent);
+ if (sent)
+ /* something sent or error */
+ return;
+
+ /* no command to send; get skb */
+ if (!(bcs->tx_skb = skb_dequeue(&bcs->squeue)))
+ /* no skb either, nothing to do */
+ return;
+
+ gig_dbg(DEBUG_INTR, "Dequeued skb (Adr: %lx)",
+ (unsigned long) bcs->tx_skb);
+ }
+
+ /* send skb */
+ gig_dbg(DEBUG_OUTPUT, "%s: tx_skb", __func__);
+ if (write_modem(cs) < 0)
+ gig_dbg(DEBUG_OUTPUT, "%s: write_modem failed", __func__);
+}
+
+/*
+ * throw away all data queued for sending
+ */
+static void flush_send_queue(struct cardstate *cs)
+{
+ struct sk_buff *skb;
+ struct cmdbuf_t *cb;
+ unsigned long flags;
+
+ /* command queue */
+ spin_lock_irqsave(&cs->cmdlock, flags);
+ while ((cb = cs->cmdbuf) != NULL) {
+ cs->cmdbuf = cb->next;
+ if (cb->wake_tasklet)
+ tasklet_schedule(cb->wake_tasklet);
+ kfree(cb);
+ }
+ cs->cmdbuf = cs->lastcmdbuf = NULL;
+ cs->cmdbytes = cs->curlen = 0;
+ spin_unlock_irqrestore(&cs->cmdlock, flags);
+
+ /* data queue */
+ if (cs->bcs->tx_skb)
+ dev_kfree_skb_any(cs->bcs->tx_skb);
+ while ((skb = skb_dequeue(&cs->bcs->squeue)) != NULL)
+ dev_kfree_skb_any(skb);
+}
+
+
+/* Gigaset Driver Interface */
+/* ======================== */
+
+/*
+ * queue an AT command string for transmission to the Gigaset device
+ * parameters:
+ * cs controller state structure
+ * buf buffer containing the string to send
+ * len number of characters to send
+ * wake_tasklet tasklet to run when transmission is complete, or NULL
+ * return value:
+ * number of bytes queued, or error code < 0
+ */
+static int gigaset_write_cmd(struct cardstate *cs, const unsigned char *buf,
+ int len, struct tasklet_struct *wake_tasklet)
+{
+ struct cmdbuf_t *cb;
+ unsigned long flags;
+
+ gigaset_dbg_buffer(atomic_read(&cs->mstate) != MS_LOCKED ?
+ DEBUG_TRANSCMD : DEBUG_LOCKCMD,
+ "CMD Transmit", len, buf);
+
+ if (len <= 0)
+ return 0;
+
+ if (!(cb = kmalloc(sizeof(struct cmdbuf_t) + len, GFP_ATOMIC))) {
+ dev_err(cs->dev, "%s: out of memory!\n", __func__);
+ return -ENOMEM;
+ }
+
+ memcpy(cb->buf, buf, len);
+ cb->len = len;
+ cb->offset = 0;
+ cb->next = NULL;
+ cb->wake_tasklet = wake_tasklet;
+
+ spin_lock_irqsave(&cs->cmdlock, flags);
+ cb->prev = cs->lastcmdbuf;
+ if (cs->lastcmdbuf)
+ cs->lastcmdbuf->next = cb;
+ else {
+ cs->cmdbuf = cb;
+ cs->curlen = len;
+ }
+ cs->cmdbytes += len;
+ cs->lastcmdbuf = cb;
+ spin_unlock_irqrestore(&cs->cmdlock, flags);
+
+ spin_lock_irqsave(&cs->lock, flags);
+ if (cs->connected)
+ tasklet_schedule(&cs->write_tasklet);
+ spin_unlock_irqrestore(&cs->lock, flags);
+ return len;
+}
+
+/*
+ * tty_driver.write_room interface routine
+ * return number of characters the driver will accept to be written
+ * parameter:
+ * controller state structure
+ * return value:
+ * number of characters
+ */
+static int gigaset_write_room(struct cardstate *cs)
+{
+ unsigned bytes;
+
+ bytes = cs->cmdbytes;
+ return bytes < IF_WRITEBUF ? IF_WRITEBUF - bytes : 0;
+}
+
+/*
+ * tty_driver.chars_in_buffer interface routine
+ * return number of characters waiting to be sent
+ * parameter:
+ * controller state structure
+ * return value:
+ * number of characters
+ */
+static int gigaset_chars_in_buffer(struct cardstate *cs)
+{
+ return cs->cmdbytes;
+}
+
+/*
+ * implementation of ioctl(GIGASET_BRKCHARS)
+ * parameter:
+ * controller state structure
+ * return value:
+ * -EINVAL (unimplemented function)
+ */
+static int gigaset_brkchars(struct cardstate *cs, const unsigned char buf[6])
+{
+ /* not implemented */
+ return -EINVAL;
+}
+
+/*
+ * Open B channel
+ * Called by "do_action" in ev-layer.c
+ */
+static int gigaset_init_bchannel(struct bc_state *bcs)
+{
+ /* nothing to do for M10x */
+ gigaset_bchannel_up(bcs);
+ return 0;
+}
+
+/*
+ * Close B channel
+ * Called by "do_action" in ev-layer.c
+ */
+static int gigaset_close_bchannel(struct bc_state *bcs)
+{
+ /* nothing to do for M10x */
+ gigaset_bchannel_down(bcs);
+ return 0;
+}
+
+/*
+ * Set up B channel structure
+ * This is called by "gigaset_initcs" in common.c
+ */
+static int gigaset_initbcshw(struct bc_state *bcs)
+{
+ /* unused */
+ bcs->hw.ser = NULL;
+ return 1;
+}
+
+/*
+ * Free B channel structure
+ * Called by "gigaset_freebcs" in common.c
+ */
+static int gigaset_freebcshw(struct bc_state *bcs)
+{
+ /* unused */
+ return 1;
+}
+
+/*
+ * Reinitialize B channel structure
+ * This is called by "bcs_reinit" in common.c
+ */
+static void gigaset_reinitbcshw(struct bc_state *bcs)
+{
+ /* nothing to do for M10x */
+}
+
+/*
+ * Free hardware specific device data
+ * This will be called by "gigaset_freecs" in common.c
+ */
+static void gigaset_freecshw(struct cardstate *cs)
+{
+ tasklet_kill(&cs->write_tasklet);
+ if (!cs->hw.ser)
+ return;
+ dev_set_drvdata(&cs->hw.ser->dev.dev, NULL);
+ platform_device_unregister(&cs->hw.ser->dev);
+ kfree(cs->hw.ser);
+ cs->hw.ser = NULL;
+}
+
+static void gigaset_device_release(struct device *dev)
+{
+ struct platform_device *pdev =
+ container_of(dev, struct platform_device, dev);
+
+ /* adapted from platform_device_release() in drivers/base/platform.c */
+ //FIXME is this actually necessary?
+ kfree(dev->platform_data);
+ kfree(pdev->resource);
+}
+
+/*
+ * Set up hardware specific device data
+ * This is called by "gigaset_initcs" in common.c
+ */
+static int gigaset_initcshw(struct cardstate *cs)
+{
+ int rc;
+
+ if (!(cs->hw.ser = kzalloc(sizeof(struct ser_cardstate), GFP_KERNEL))) {
+ err("%s: out of memory!", __func__);
+ return 0;
+ }
+
+ cs->hw.ser->dev.name = GIGASET_MODULENAME;
+ cs->hw.ser->dev.id = cs->minor_index;
+ cs->hw.ser->dev.dev.release = gigaset_device_release;
+ if ((rc = platform_device_register(&cs->hw.ser->dev)) != 0) {
+ err("error %d registering platform device", rc);
+ kfree(cs->hw.ser);
+ cs->hw.ser = NULL;
+ return 0;
+ }
+ dev_set_drvdata(&cs->hw.ser->dev.dev, cs);
+
+ tasklet_init(&cs->write_tasklet,
+ &gigaset_modem_fill, (unsigned long) cs);
+ return 1;
+}
+
+/*
+ * set modem control lines
+ * Parameters:
+ * card state structure
+ * modem control line state ([TIOCM_DTR]|[TIOCM_RTS])
+ * Called by "gigaset_start" and "gigaset_enterconfigmode" in common.c
+ * and by "if_lock" and "if_termios" in interface.c
+ */
+static int gigaset_set_modem_ctrl(struct cardstate *cs, unsigned old_state, unsigned new_state)
+{
+ struct tty_struct *tty = cs->hw.ser->tty;
+ unsigned int set, clear;
+
+ if (!tty || !tty->driver || !tty->driver->tiocmset)
+ return -EFAULT;
+ set = new_state & ~old_state;
+ clear = old_state & ~new_state;
+ if (!set && !clear)
+ return 0;
+ gig_dbg(DEBUG_IF, "tiocmset set %x clear %x", set, clear);
+ return tty->driver->tiocmset(tty, NULL, set, clear);
+}
+
+static int gigaset_baud_rate(struct cardstate *cs, unsigned cflag)
+{
+ return -EINVAL;
+}
+
+static int gigaset_set_line_ctrl(struct cardstate *cs, unsigned cflag)
+{
+ return -EINVAL;
+}
+
+static struct gigaset_ops ops = {
+ gigaset_write_cmd,
+ gigaset_write_room,
+ gigaset_chars_in_buffer,
+ gigaset_brkchars,
+ gigaset_init_bchannel,
+ gigaset_close_bchannel,
+ gigaset_initbcshw,
+ gigaset_freebcshw,
+ gigaset_reinitbcshw,
+ gigaset_initcshw,
+ gigaset_freecshw,
+ gigaset_set_modem_ctrl,
+ gigaset_baud_rate,
+ gigaset_set_line_ctrl,
+ gigaset_m10x_send_skb, /* asyncdata.c */
+ gigaset_m10x_input, /* asyncdata.c */
+};
+
+
+/* Line Discipline Interface */
+/* ========================= */
+
+/* helper functions for cardstate refcounting */
+static struct cardstate *cs_get(struct tty_struct *tty)
+{
+ struct cardstate *cs = tty->disc_data;
+
+ if (!cs || !cs->hw.ser) {
+ gig_dbg(DEBUG_ANY, "%s: no cardstate", __func__);
+ return NULL;
+ }
+ atomic_inc(&cs->hw.ser->refcnt);
+ return cs;
+}
+
+static void cs_put(struct cardstate *cs)
+{
+ if (atomic_dec_and_test(&cs->hw.ser->refcnt))
+ mutex_unlock(&cs->hw.ser->dead_mutex);
+}
+
+/*
+ * Called by the tty driver when the line discipline is pushed onto the tty.
+ * Called in process context.
+ */
+static int
+gigaset_tty_open(struct tty_struct *tty)
+{
+ struct cardstate *cs;
+
+ gig_dbg(DEBUG_INIT, "Starting HLL for Gigaset M101");
+
+ info(DRIVER_AUTHOR);
+ info(DRIVER_DESC);
+
+ if (!driver) {
+ err("%s: no driver structure", __func__);
+ return -ENODEV;
+ }
+
+ /* allocate memory for our device state and intialize it */
+ if (!(cs = gigaset_initcs(driver, 1, 1, 0, cidmode,
+ GIGASET_MODULENAME)))
+ goto error;
+
+ cs->dev = &cs->hw.ser->dev.dev;
+ cs->hw.ser->tty = tty;
+ mutex_init(&cs->hw.ser->dead_mutex);
+ atomic_set(&cs->hw.ser->refcnt, 1);
+
+ tty->disc_data = cs;
+
+ /* OK.. Initialization of the datastructures and the HW is done.. Now
+ * startup system and notify the LL that we are ready to run
+ */
+ if (startmode == SM_LOCKED)
+ atomic_set(&cs->mstate, MS_LOCKED);
+ if (!gigaset_start(cs)) {
+ tasklet_kill(&cs->write_tasklet);
+ goto error;
+ }
+
+ gig_dbg(DEBUG_INIT, "Startup of HLL done");
+ mutex_lock(&cs->hw.ser->dead_mutex);
+ return 0;
+
+error:
+ gig_dbg(DEBUG_INIT, "Startup of HLL failed");
+ tty->disc_data = NULL;
+ gigaset_freecs(cs);
+ return -ENODEV;
+}
+
+/*
+ * Called by the tty driver when the line discipline is removed.
+ * Called from process context.
+ */
+static void
+gigaset_tty_close(struct tty_struct *tty)
+{
+ struct cardstate *cs = tty->disc_data;
+
+ gig_dbg(DEBUG_INIT, "Stopping HLL for Gigaset M101");
+
+ if (!cs) {
+ gig_dbg(DEBUG_INIT, "%s: no cardstate", __func__);
+ return;
+ }
+
+ /* prevent other callers from entering ldisc methods */
+ tty->disc_data = NULL;
+
+ if (!cs->hw.ser)
+ err("%s: no hw cardstate", __func__);
+ else {
+ /* wait for running methods to finish */
+ if (!atomic_dec_and_test(&cs->hw.ser->refcnt))
+ mutex_lock(&cs->hw.ser->dead_mutex);
+ }
+
+ /* stop operations */
+ gigaset_stop(cs);
+ tasklet_kill(&cs->write_tasklet);
+ flush_send_queue(cs);
+ cs->dev = NULL;
+ gigaset_freecs(cs);
+
+ gig_dbg(DEBUG_INIT, "Shutdown of HLL done");
+}
+
+/*
+ * Called by the tty driver when the tty line is hung up.
+ * Wait for I/O to driver to complete and unregister ISDN device.
+ * This is already done by the close routine, so just call that.
+ * Called from process context.
+ */
+static int gigaset_tty_hangup(struct tty_struct *tty)
+{
+ gigaset_tty_close(tty);
+ return 0;
+}
+
+/*
+ * Read on the tty.
+ * Unused, received data goes only to the Gigaset driver.
+ */
+static ssize_t
+gigaset_tty_read(struct tty_struct *tty, struct file *file,
+ unsigned char __user *buf, size_t count)
+{
+ return -EAGAIN;
+}
+
+/*
+ * Write on the tty.
+ * Unused, transmit data comes only from the Gigaset driver.
+ */
+static ssize_t
+gigaset_tty_write(struct tty_struct *tty, struct file *file,
+ const unsigned char *buf, size_t count)
+{
+ return -EAGAIN;
+}
+
+/*
+ * Ioctl on the tty.
+ * Called in process context only.
+ * May be re-entered by multiple ioctl calling threads.
+ */
+static int
+gigaset_tty_ioctl(struct tty_struct *tty, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct cardstate *cs = cs_get(tty);
+ int rc, val;
+ int __user *p = (int __user *)arg;
+
+ if (!cs)
+ return -ENXIO;
+
+ switch (cmd) {
+ case TCGETS:
+ case TCGETA:
+ /* pass through to underlying serial device */
+ rc = n_tty_ioctl(tty, file, cmd, arg);
+ break;
+
+ case TCFLSH:
+ /* flush our buffers and the serial port's buffer */
+ switch (arg) {
+ case TCIFLUSH:
+ /* no own input buffer to flush */
+ break;
+ case TCIOFLUSH:
+ case TCOFLUSH:
+ flush_send_queue(cs);
+ break;
+ }
+ /* flush the serial port's buffer */
+ rc = n_tty_ioctl(tty, file, cmd, arg);
+ break;
+
+ case FIONREAD:
+ /* unused, always return zero */
+ val = 0;
+ rc = put_user(val, p);
+ break;
+
+ default:
+ rc = -ENOIOCTLCMD;
+ }
+
+ cs_put(cs);
+ return rc;
+}
+
+/*
+ * Poll on the tty.
+ * Unused, always return zero.
+ */
+static unsigned int
+gigaset_tty_poll(struct tty_struct *tty, struct file *file, poll_table *wait)
+{
+ return 0;
+}
+
+/*
+ * Called by the tty driver when a block of data has been received.
+ * Will not be re-entered while running but other ldisc functions
+ * may be called in parallel.
+ * Can be called from hard interrupt level as well as soft interrupt
+ * level or mainline.
+ * Parameters:
+ * tty tty structure
+ * buf buffer containing received characters
+ * cflags buffer containing error flags for received characters (ignored)
+ * count number of received characters
+ */
+static void
+gigaset_tty_receive(struct tty_struct *tty, const unsigned char *buf,
+ char *cflags, int count)
+{
+ struct cardstate *cs = cs_get(tty);
+ unsigned tail, head, n;
+ struct inbuf_t *inbuf;
+
+ if (!cs)
+ return;
+ if (!(inbuf = cs->inbuf)) {
+ dev_err(cs->dev, "%s: no inbuf\n", __func__);
+ cs_put(cs);
+ return;
+ }
+
+ tail = atomic_read(&inbuf->tail);
+ head = atomic_read(&inbuf->head);
+ gig_dbg(DEBUG_INTR, "buffer state: %u -> %u, receive %u bytes",
+ head, tail, count);
+
+ if (head <= tail) {
+ /* possible buffer wraparound */
+ n = min_t(unsigned, count, RBUFSIZE - tail);
+ memcpy(inbuf->data + tail, buf, n);
+ tail = (tail + n) % RBUFSIZE;
+ buf += n;
+ count -= n;
+ }
+
+ if (count > 0) {
+ /* tail < head and some data left */
+ n = head - tail - 1;
+ if (count > n) {
+ dev_err(cs->dev,
+ "inbuf overflow, discarding %d bytes\n",
+ count - n);
+ count = n;
+ }
+ memcpy(inbuf->data + tail, buf, count);
+ tail += count;
+ }
+
+ gig_dbg(DEBUG_INTR, "setting tail to %u", tail);
+ atomic_set(&inbuf->tail, tail);
+
+ /* Everything was received .. Push data into handler */
+ gig_dbg(DEBUG_INTR, "%s-->BH", __func__);
+ gigaset_schedule_event(cs);
+ cs_put(cs);
+}
+
+/*
+ * Called by the tty driver when there's room for more data to send.
+ */
+static void
+gigaset_tty_wakeup(struct tty_struct *tty)
+{
+ struct cardstate *cs = cs_get(tty);
+
+ clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
+ if (!cs)
+ return;
+ tasklet_schedule(&cs->write_tasklet);
+ cs_put(cs);
+}
+
+static struct tty_ldisc gigaset_ldisc = {
+ .owner = THIS_MODULE,
+ .magic = TTY_LDISC_MAGIC,
+ .name = "ser_gigaset",
+ .open = gigaset_tty_open,
+ .close = gigaset_tty_close,
+ .hangup = gigaset_tty_hangup,
+ .read = gigaset_tty_read,
+ .write = gigaset_tty_write,
+ .ioctl = gigaset_tty_ioctl,
+ .poll = gigaset_tty_poll,
+ .receive_buf = gigaset_tty_receive,
+ .write_wakeup = gigaset_tty_wakeup,
+};
+
+
+/* Initialization / Shutdown */
+/* ========================= */
+
+static int __init ser_gigaset_init(void)
+{
+ int rc;
+
+ gig_dbg(DEBUG_INIT, "%s", __func__);
+ if ((rc = platform_driver_register(&device_driver)) != 0) {
+ err("error %d registering platform driver", rc);
+ return rc;
+ }
+
+ /* allocate memory for our driver state and intialize it */
+ if (!(driver = gigaset_initdriver(GIGASET_MINOR, GIGASET_MINORS,
+ GIGASET_MODULENAME, GIGASET_DEVNAME,
+ &ops, THIS_MODULE)))
+ goto error;
+
+ if ((rc = tty_register_ldisc(N_GIGASET_M101, &gigaset_ldisc)) != 0) {
+ err("error %d registering line discipline", rc);
+ goto error;
+ }
+
+ return 0;
+
+error:
+ if (driver) {
+ gigaset_freedriver(driver);
+ driver = NULL;
+ }
+ platform_driver_unregister(&device_driver);
+ return rc;
+}
+
+static void __exit ser_gigaset_exit(void)
+{
+ int rc;
+
+ gig_dbg(DEBUG_INIT, "%s", __func__);
+
+ if (driver) {
+ gigaset_freedriver(driver);
+ driver = NULL;
+ }
+
+ if ((rc = tty_unregister_ldisc(N_GIGASET_M101)) != 0)
+ err("error %d unregistering line discipline", rc);
+
+ platform_driver_unregister(&device_driver);
+}
+
+module_init(ser_gigaset_init);
+module_exit(ser_gigaset_exit);
diff --git a/drivers/isdn/hardware/avm/avm_cs.c b/drivers/isdn/hardware/avm/avm_cs.c
index eba10466ccc..a5b941c327f 100644
--- a/drivers/isdn/hardware/avm/avm_cs.c
+++ b/drivers/isdn/hardware/avm/avm_cs.c
@@ -12,7 +12,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/sched.h>
#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/string.h>
diff --git a/drivers/isdn/hardware/avm/b1dma.c b/drivers/isdn/hardware/avm/b1dma.c
index ddd47cdfdb1..1e2d38e3d68 100644
--- a/drivers/isdn/hardware/avm/b1dma.c
+++ b/drivers/isdn/hardware/avm/b1dma.c
@@ -29,7 +29,7 @@
static char *revision = "$Revision: 1.1.2.3 $";
-#undef CONFIG_B1DMA_DEBUG
+#undef AVM_B1DMA_DEBUG
/* ------------------------------------------------------------- */
@@ -391,16 +391,16 @@ static void b1dma_dispatch_tx(avmcard *card)
_put_slice(&p, skb->data, len);
}
txlen = (u8 *)p - (u8 *)dma->sendbuf.dmabuf;
-#ifdef CONFIG_B1DMA_DEBUG
+#ifdef AVM_B1DMA_DEBUG
printk(KERN_DEBUG "tx: put msg len=%d\n", txlen);
#endif
} else {
txlen = skb->len-2;
-#ifdef CONFIG_B1DMA_POLLDEBUG
+#ifdef AVM_B1DMA_POLLDEBUG
if (skb->data[2] == SEND_POLLACK)
printk(KERN_INFO "%s: send ack\n", card->name);
#endif
-#ifdef CONFIG_B1DMA_DEBUG
+#ifdef AVM_B1DMA_DEBUG
printk(KERN_DEBUG "tx: put 0x%x len=%d\n",
skb->data[2], txlen);
#endif
@@ -450,7 +450,7 @@ static void b1dma_handle_rx(avmcard *card)
u32 ApplId, MsgLen, DataB3Len, NCCI, WindowSize;
u8 b1cmd = _get_byte(&p);
-#ifdef CONFIG_B1DMA_DEBUG
+#ifdef AVM_B1DMA_DEBUG
printk(KERN_DEBUG "rx: 0x%x %lu\n", b1cmd, (unsigned long)dma->recvlen);
#endif
@@ -515,7 +515,7 @@ static void b1dma_handle_rx(avmcard *card)
break;
case RECEIVE_START:
-#ifdef CONFIG_B1DMA_POLLDEBUG
+#ifdef AVM_B1DMA_POLLDEBUG
printk(KERN_INFO "%s: receive poll\n", card->name);
#endif
if (!suppress_pollack)
@@ -601,7 +601,7 @@ static void b1dma_handle_interrupt(avmcard *card)
rxlen = (dma->recvlen + 3) & ~3;
b1dma_writel(card, dma->recvbuf.dmaaddr+4, AMCC_RXPTR);
b1dma_writel(card, rxlen, AMCC_RXLEN);
-#ifdef CONFIG_B1DMA_DEBUG
+#ifdef AVM_B1DMA_DEBUG
} else {
printk(KERN_ERR "%s: rx not complete (%d).\n",
card->name, rxlen);
diff --git a/drivers/isdn/hardware/avm/c4.c b/drivers/isdn/hardware/avm/c4.c
index 2a3eb38f0eb..6f5efa8d78c 100644
--- a/drivers/isdn/hardware/avm/c4.c
+++ b/drivers/isdn/hardware/avm/c4.c
@@ -28,8 +28,8 @@
#include <linux/isdn/capilli.h>
#include "avmcard.h"
-#undef CONFIG_C4_DEBUG
-#undef CONFIG_C4_POLLDEBUG
+#undef AVM_C4_DEBUG
+#undef AVM_C4_POLLDEBUG
/* ------------------------------------------------------------- */
@@ -420,7 +420,7 @@ static void c4_dispatch_tx(avmcard *card)
skb = skb_dequeue(&dma->send_queue);
if (!skb) {
-#ifdef CONFIG_C4_DEBUG
+#ifdef AVM_C4_DEBUG
printk(KERN_DEBUG "%s: tx underrun\n", card->name);
#endif
return;
@@ -444,16 +444,16 @@ static void c4_dispatch_tx(avmcard *card)
_put_slice(&p, skb->data, len);
}
txlen = (u8 *)p - (u8 *)dma->sendbuf.dmabuf;
-#ifdef CONFIG_C4_DEBUG
+#ifdef AVM_C4_DEBUG
printk(KERN_DEBUG "%s: tx put msg len=%d\n", card->name, txlen);
#endif
} else {
txlen = skb->len-2;
-#ifdef CONFIG_C4_POLLDEBUG
+#ifdef AVM_C4_POLLDEBUG
if (skb->data[2] == SEND_POLLACK)
printk(KERN_INFO "%s: ack to c4\n", card->name);
#endif
-#ifdef CONFIG_C4_DEBUG
+#ifdef AVM_C4_DEBUG
printk(KERN_DEBUG "%s: tx put 0x%x len=%d\n",
card->name, skb->data[2], txlen);
#endif
@@ -508,7 +508,7 @@ static void c4_handle_rx(avmcard *card)
u32 cidx;
-#ifdef CONFIG_C4_DEBUG
+#ifdef AVM_C4_DEBUG
printk(KERN_DEBUG "%s: rx 0x%x len=%lu\n", card->name,
b1cmd, (unsigned long)dma->recvlen);
#endif
@@ -586,7 +586,7 @@ static void c4_handle_rx(avmcard *card)
break;
case RECEIVE_START:
-#ifdef CONFIG_C4_POLLDEBUG
+#ifdef AVM_C4_POLLDEBUG
printk(KERN_INFO "%s: poll from c4\n", card->name);
#endif
if (!suppress_pollack)
diff --git a/drivers/isdn/hardware/eicon/capifunc.c b/drivers/isdn/hardware/eicon/capifunc.c
index 0afd7633556..ff284aeb8fb 100644
--- a/drivers/isdn/hardware/eicon/capifunc.c
+++ b/drivers/isdn/hardware/eicon/capifunc.c
@@ -187,7 +187,7 @@ static diva_card *find_card_by_ctrl(word controller)
*/
void *TransmitBufferSet(APPL * appl, dword ref)
{
- appl->xbuffer_used[ref] = TRUE;
+ appl->xbuffer_used[ref] = true;
DBG_PRV1(("%d:xbuf_used(%d)", appl->Id, ref + 1))
return (void *) ref;
}
@@ -202,7 +202,7 @@ void *TransmitBufferGet(APPL * appl, void *p)
void TransmitBufferFree(APPL * appl, void *p)
{
- appl->xbuffer_used[(dword) p] = FALSE;
+ appl->xbuffer_used[(dword) p] = false;
DBG_PRV1(("%d:xbuf_free(%d)", appl->Id, ((dword) p) + 1))
}
diff --git a/drivers/isdn/hardware/eicon/debug.c b/drivers/isdn/hardware/eicon/debug.c
index d835e74ecf1..0db9cc661e2 100644
--- a/drivers/isdn/hardware/eicon/debug.c
+++ b/drivers/isdn/hardware/eicon/debug.c
@@ -287,7 +287,7 @@ void* diva_maint_finit (void) {
}
external_dbg_queue = 0;
- for (i = 1; i < (sizeof(clients)/sizeof(clients[0])); i++) {
+ for (i = 1; i < ARRAY_SIZE(clients); i++) {
if (clients[i].pmem) {
diva_os_free (0, clients[i].pmem);
}
@@ -391,7 +391,7 @@ static void DI_register (void *arg) {
diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "register");
- for (id = 1; id < (sizeof(clients)/sizeof(clients[0])); id++) {
+ for (id = 1; id < ARRAY_SIZE(clients); id++) {
if (clients[id].hDbg == hDbg) {
/*
driver already registered
@@ -494,7 +494,7 @@ static void DI_deregister (pDbgHandle hDbg) {
diva_os_enter_spin_lock (&dbg_adapter_lock, &old_irql1, "read");
diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "read");
- for (i = 1; i < (sizeof(clients)/sizeof(clients[0])); i++) {
+ for (i = 1; i < ARRAY_SIZE(clients); i++) {
if (clients[i].hDbg == hDbg) {
diva_dbg_entry_head_t* pmsg;
char tmp[256];
@@ -736,7 +736,7 @@ int diva_get_driver_info (dword id, byte* data, int data_length) {
int to_copy;
if (!data || !id || (data_length < 17) ||
- (id >= (sizeof(clients)/sizeof(clients[0])))) {
+ (id >= ARRAY_SIZE(clients))) {
return (-1);
}
@@ -786,7 +786,7 @@ int diva_get_driver_dbg_mask (dword id, byte* data) {
diva_os_spin_lock_magic_t old_irql;
int ret = -1;
- if (!data || !id || (id >= (sizeof(clients)/sizeof(clients[0])))) {
+ if (!data || !id || (id >= ARRAY_SIZE(clients))) {
return (-1);
}
diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "driver info");
@@ -809,7 +809,7 @@ int diva_set_driver_dbg_mask (dword id, dword mask) {
int ret = -1;
- if (!id || (id >= (sizeof(clients)/sizeof(clients[0])))) {
+ if (!id || (id >= ARRAY_SIZE(clients))) {
return (-1);
}
@@ -887,7 +887,7 @@ void diva_mnt_add_xdi_adapter (const DESCRIPTOR* d) {
diva_os_enter_spin_lock (&dbg_adapter_lock, &old_irql1, "register");
diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "register");
- for (id = 1; id < (sizeof(clients)/sizeof(clients[0])); id++) {
+ for (id = 1; id < ARRAY_SIZE(clients); id++) {
if (clients[id].hDbg && (clients[id].request == d->request)) {
diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "register");
diva_os_leave_spin_lock (&dbg_adapter_lock, &old_irql1, "register");
@@ -1037,7 +1037,7 @@ void diva_mnt_remove_xdi_adapter (const DESCRIPTOR* d) {
diva_os_enter_spin_lock (&dbg_adapter_lock, &old_irql1, "read");
diva_os_enter_spin_lock (&dbg_q_lock, &old_irql, "read");
- for (i = 1; i < (sizeof(clients)/sizeof(clients[0])); i++) {
+ for (i = 1; i < ARRAY_SIZE(clients); i++) {
if (clients[i].hDbg && (clients[i].request == d->request)) {
diva_dbg_entry_head_t* pmsg;
char tmp[256];
@@ -1115,7 +1115,7 @@ void diva_mnt_remove_xdi_adapter (const DESCRIPTOR* d) {
void* SuperTraceOpenAdapter (int AdapterNumber) {
int i;
- for (i = 1; i < (sizeof(clients)/sizeof(clients[0])); i++) {
+ for (i = 1; i < ARRAY_SIZE(clients); i++) {
if (clients[i].hDbg && clients[i].request && (clients[i].logical == AdapterNumber)) {
return (&clients[i]);
}
@@ -1508,7 +1508,7 @@ static void diva_maint_state_change_notify (void* user_context,
int ch = TraceFilterChannel;
int id = TraceFilterIdent;
- if ((id >= 0) && (ch >= 0) && (id < sizeof(clients)/sizeof(clients[0])) &&
+ if ((id >= 0) && (ch >= 0) && (id < ARRAY_SIZE(clients)) &&
(clients[id].Dbg.id == (byte)id) && (clients[id].pIdiLib == hLib)) {
if (ch != (int)modem->ChannelNumber) {
break;
@@ -1555,7 +1555,7 @@ static void diva_maint_state_change_notify (void* user_context,
int ch = TraceFilterChannel;
int id = TraceFilterIdent;
- if ((id >= 0) && (ch >= 0) && (id < sizeof(clients)/sizeof(clients[0])) &&
+ if ((id >= 0) && (ch >= 0) && (id < ARRAY_SIZE(clients)) &&
(clients[id].Dbg.id == (byte)id) && (clients[id].pIdiLib == hLib)) {
if (ch != (int)fax->ChannelNumber) {
break;
@@ -1803,7 +1803,7 @@ static void diva_maint_trace_notify (void* user_context,
/*
Selective trace
*/
- if ((id >= 0) && (ch >= 0) && (id < sizeof(clients)/sizeof(clients[0])) &&
+ if ((id >= 0) && (ch >= 0) && (id < ARRAY_SIZE(clients)) &&
(clients[id].Dbg.id == (byte)id) && (clients[id].pIdiLib == hLib)) {
const char* p = NULL;
int ch_value = -1;
@@ -1925,7 +1925,7 @@ int diva_mnt_shutdown_xdi_adapters (void) {
byte * pmem;
- for (i = 1; i < (sizeof(clients)/sizeof(clients[0])); i++) {
+ for (i = 1; i < ARRAY_SIZE(clients); i++) {
pmem = NULL;
diva_os_enter_spin_lock (&dbg_adapter_lock, &old_irql1, "unload");
@@ -2006,7 +2006,7 @@ int diva_set_trace_filter (int filter_length, const char* filter) {
on = (TraceFilter[0] == 0);
- for (i = 1; i < (sizeof(clients)/sizeof(clients[0])); i++) {
+ for (i = 1; i < ARRAY_SIZE(clients); i++) {
if (clients[i].hDbg && clients[i].pIdiLib && clients[i].request) {
client_b_on = on && ((clients[i].hDbg->dbgMask & DIVA_MGT_DBG_IFC_BCHANNEL) != 0);
client_atap_on = on && ((clients[i].hDbg->dbgMask & DIVA_MGT_DBG_IFC_AUDIO) != 0);
@@ -2017,7 +2017,7 @@ int diva_set_trace_filter (int filter_length, const char* filter) {
}
}
- for (i = 1; i < (sizeof(clients)/sizeof(clients[0])); i++) {
+ for (i = 1; i < ARRAY_SIZE(clients); i++) {
if (clients[i].hDbg && clients[i].pIdiLib && clients[i].request && clients[i].request_pending) {
diva_os_leave_spin_lock (&dbg_q_lock, &old_irql, "write_filter");
clients[i].request_pending = 0;
diff --git a/drivers/isdn/hardware/eicon/di.c b/drivers/isdn/hardware/eicon/di.c
index e1df8d98c31..ce8df387890 100644
--- a/drivers/isdn/hardware/eicon/di.c
+++ b/drivers/isdn/hardware/eicon/di.c
@@ -173,16 +173,16 @@ void pr_out(ADAPTER * a)
xdi_xlog_request (XDI_A_NR(a), this->Id, this->ReqCh, this->MInd,
a->IdTypeTable[this->No]);
a->ram_out(a, &ReqOut->Req, this->MInd);
- more = TRUE;
+ more = true;
}
else {
xdi_xlog_request (XDI_A_NR(a), this->Id, this->ReqCh, this->Req,
a->IdTypeTable[this->No]);
this->More |=XMOREF;
a->ram_out(a, &ReqOut->Req, this->Req);
- more = FALSE;
+ more = false;
if (a->FlowControlIdTable[this->ReqCh] == this->Id)
- a->FlowControlSkipTable[this->ReqCh] = TRUE;
+ a->FlowControlSkipTable[this->ReqCh] = true;
/*
Note that remove request was sent to the card
*/
@@ -311,7 +311,7 @@ byte pr_dpc(ADAPTER * a)
/* are marked RNR */
if(RNRId && RNRId==a->ram_in(a, &IndIn->IndId)) {
a->ram_out(a, &IndIn->Ind, 0);
- a->ram_out(a, &IndIn->RNR, TRUE);
+ a->ram_out(a, &IndIn->RNR, true);
}
else {
Ind = a->ram_in(a, &IndIn->Ind);
@@ -331,7 +331,7 @@ byte pr_dpc(ADAPTER * a)
dtrc(dprintf("RNR"));
a->ram_out(a, &IndIn->Ind, 0);
RNRId = a->ram_in(a, &IndIn->IndId);
- a->ram_out(a, &IndIn->RNR, TRUE);
+ a->ram_out(a, &IndIn->RNR, true);
}
}
}
@@ -340,7 +340,7 @@ byte pr_dpc(ADAPTER * a)
}
a->ram_out(a, &PR_RAM->IndOutput, 0);
}
- return FALSE;
+ return false;
}
byte scom_test_int(ADAPTER * a)
{
@@ -399,7 +399,7 @@ byte isdn_rc(ADAPTER * a,
return (0);
}
if (extended_info_type == DIVA_RC_TYPE_REMOVE_COMPLETE)
- a->RcExtensionSupported = TRUE;
+ a->RcExtensionSupported = true;
}
a->misc_flags_table[e_no] &= ~DIVA_MISC_FLAGS_REMOVE_PENDING;
a->misc_flags_table[e_no] &= ~DIVA_MISC_FLAGS_NO_RC_CANCELLING;
@@ -428,7 +428,7 @@ byte isdn_rc(ADAPTER * a,
}
if (Rc==OK_FC) {
a->FlowControlIdTable[Ch] = Id;
- a->FlowControlSkipTable[Ch] = FALSE;
+ a->FlowControlSkipTable[Ch] = false;
this->Rc = Rc;
this->More &= ~(XBUSY | XMOREC);
this->complete=0xff;
diff --git a/drivers/isdn/hardware/eicon/divamnt.c b/drivers/isdn/hardware/eicon/divamnt.c
index 77155d9f399..4aba5c502d8 100644
--- a/drivers/isdn/hardware/eicon/divamnt.c
+++ b/drivers/isdn/hardware/eicon/divamnt.c
@@ -13,7 +13,6 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/smp_lock.h>
#include <linux/poll.h>
#include <asm/uaccess.h>
@@ -164,7 +163,7 @@ static ssize_t divas_maint_read(struct file *file, char __user *buf,
return (maint_read_write(buf, (int) count));
}
-static struct file_operations divas_maint_fops = {
+static const struct file_operations divas_maint_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = divas_maint_read,
diff --git a/drivers/isdn/hardware/eicon/divasi.c b/drivers/isdn/hardware/eicon/divasi.c
index fff0d89c806..556b19615bc 100644
--- a/drivers/isdn/hardware/eicon/divasi.c
+++ b/drivers/isdn/hardware/eicon/divasi.c
@@ -131,7 +131,7 @@ static void remove_um_idi_proc(void)
}
}
-static struct file_operations divas_idi_fops = {
+static const struct file_operations divas_idi_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = um_idi_read,
diff --git a/drivers/isdn/hardware/eicon/divasmain.c b/drivers/isdn/hardware/eicon/divasmain.c
index 91fc92c01af..5e862e24411 100644
--- a/drivers/isdn/hardware/eicon/divasmain.c
+++ b/drivers/isdn/hardware/eicon/divasmain.c
@@ -12,7 +12,6 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/ioport.h>
@@ -663,7 +662,7 @@ static unsigned int divas_poll(struct file *file, poll_table * wait)
return (POLLIN | POLLRDNORM);
}
-static struct file_operations divas_fops = {
+static const struct file_operations divas_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = divas_read,
diff --git a/drivers/isdn/hardware/eicon/divasproc.c b/drivers/isdn/hardware/eicon/divasproc.c
index 6a4373a4f1e..0632a260699 100644
--- a/drivers/isdn/hardware/eicon/divasproc.c
+++ b/drivers/isdn/hardware/eicon/divasproc.c
@@ -113,7 +113,7 @@ static int divas_close(struct inode *inode, struct file *file)
return (0);
}
-static struct file_operations divas_fops = {
+static const struct file_operations divas_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = divas_read,
diff --git a/drivers/isdn/hardware/eicon/message.c b/drivers/isdn/hardware/eicon/message.c
index f9b00f19afd..784232a144c 100644
--- a/drivers/isdn/hardware/eicon/message.c
+++ b/drivers/isdn/hardware/eicon/message.c
@@ -253,7 +253,7 @@ extern APPL * application;
-static byte remove_started = FALSE;
+static byte remove_started = false;
static PLCI dummy_plci;
@@ -456,12 +456,12 @@ word api_put(APPL * appl, CAPI_MSG * msg)
return _QUEUE_FULL;
}
- c = FALSE;
+ c = false;
if ((((byte *) msg) < ((byte *)(plci->msg_in_queue)))
|| (((byte *) msg) >= ((byte *)(plci->msg_in_queue)) + sizeof(plci->msg_in_queue)))
{
if (plci->msg_in_write_pos != plci->msg_in_read_pos)
- c = TRUE;
+ c = true;
}
if (msg->header.command == _DATA_B3_R)
{
@@ -506,13 +506,13 @@ word api_put(APPL * appl, CAPI_MSG * msg)
return _QUEUE_FULL;
}
- c = TRUE;
+ c = true;
}
}
else
{
if (plci->req_in || plci->internal_command)
- c = TRUE;
+ c = true;
else
{
plci->command = msg->header.command;
@@ -626,10 +626,10 @@ word api_parse(byte * msg, word length, byte * format, API_PARSE * parms)
break;
}
- if(p>length) return TRUE;
+ if(p>length) return true;
}
if(parms) parms[i].info = NULL;
- return FALSE;
+ return false;
}
void api_save_msg(API_PARSE *in, byte *format, API_SAVE *out)
@@ -687,7 +687,7 @@ word api_remove_start(void)
word j;
if(!remove_started) {
- remove_started = TRUE;
+ remove_started = true;
for(i=0;i<max_adapter;i++) {
if(adapter[i].request) {
for(j=0;j<adapter[i].max_plci;j++) {
@@ -1080,7 +1080,7 @@ static void plci_remove(PLCI * plci)
send_req(plci);
}
}
- ncci_remove (plci, 0, FALSE);
+ ncci_remove (plci, 0, false);
plci_free_msg_in_queue (plci);
plci->channels = 0;
@@ -1226,7 +1226,7 @@ byte connect_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci,
Id = ((word)1<<8)|a->Id;
sendf(appl,_CONNECT_R|CONFIRM,Id,Number,"w",0);
sendf(appl, _DISCONNECT_I, Id, 0, "w", _L1_ERROR);
- return FALSE;
+ return false;
}
Info = _OUT_OF_PLCI;
if((i=get_plci(a)))
@@ -1330,7 +1330,7 @@ byte connect_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci,
plci->command = _CONNECT_R;
plci->number = Number;
/* x.31 or D-ch free SAPI in LinkLayer? */
- if(ch==1 && LinkLayer!=3 && LinkLayer!=12) noCh = TRUE;
+ if(ch==1 && LinkLayer!=3 && LinkLayer!=12) noCh = true;
if((ch==0 || ch==2 || noCh || ch==3 || ch==4) && !Info)
{
/* B-channel used for B3 connections (ch==0), or no B channel */
@@ -1381,7 +1381,7 @@ byte connect_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci,
plci->command = 0;
dbug(1,dprintf("Spoof"));
send_req(plci);
- return FALSE;
+ return false;
}
if(ch==4)add_p(plci,CHI,p_chi);
add_s(plci,CPN,&parms[1]);
@@ -1395,11 +1395,11 @@ byte connect_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci,
plci->appl = appl;
sig_req(plci,LISTEN_REQ,0);
send_req(plci);
- return FALSE;
+ return false;
}
}
send_req(plci);
- return FALSE;
+ return false;
}
plci->Id = 0;
}
@@ -1571,7 +1571,7 @@ byte connect_res(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci,
byte connect_a_res(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * msg)
{
dbug(1,dprintf("connect_a_res"));
- return FALSE;
+ return false;
}
byte disconnect_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * msg)
@@ -1624,9 +1624,9 @@ byte disconnect_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plc
}
}
- if(!appl) return FALSE;
+ if(!appl) return false;
sendf(appl, _DISCONNECT_R|CONFIRM, Id, Number, "w",Info);
- return FALSE;
+ return false;
}
byte disconnect_res(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * msg)
@@ -1702,7 +1702,7 @@ byte listen_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, A
"w",Info);
if (a) listen_check(a);
- return FALSE;
+ return false;
}
byte info_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * msg)
@@ -1739,7 +1739,7 @@ byte info_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APP
add_s(plci,KEY,&ai_parms[1]);
sig_req(plci,INFO_REQ,0);
send_req(plci);
- return FALSE;
+ return false;
}
if(plci->State && ai_parms[2].length)
@@ -1769,7 +1769,7 @@ byte info_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APP
if((i=get_plci(a)))
{
rc_plci = &a->plci[i-1];
- appl->NullCREnable = TRUE;
+ appl->NullCREnable = true;
rc_plci->internal_command = C_NCR_FAC_REQ;
rc_plci->appl = appl;
add_p(rc_plci,CAI,"\x01\x80");
@@ -1788,7 +1788,7 @@ byte info_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APP
add_ai(rc_plci, &msg[1]);
sig_req(rc_plci,NCR_FACILITY,0);
send_req(rc_plci);
- return FALSE;
+ return false;
/* for application controlled supplementary services */
}
}
@@ -1811,13 +1811,13 @@ byte info_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APP
Number,
"w",Info);
}
- return FALSE;
+ return false;
}
byte info_res(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * msg)
{
dbug(1,dprintf("info_res"));
- return FALSE;
+ return false;
}
byte alert_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * msg)
@@ -1828,7 +1828,7 @@ byte alert_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, AP
dbug(1,dprintf("alert_req"));
Info = _WRONG_IDENTIFIER;
- ret = FALSE;
+ ret = false;
if(plci) {
Info = _ALERT_IGNORED;
if(plci->State!=INC_CON_ALERT) {
@@ -1922,7 +1922,7 @@ byte facility_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci,
rplci->appl = appl;
sig_req(rplci,S_SUPPORTED,0);
send_req(rplci);
- return FALSE;
+ return false;
break;
case S_LISTEN:
@@ -1972,7 +1972,7 @@ byte facility_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci,
add_s(plci,CAI,&ss_parms[1]);
sig_req(plci,CALL_HOLD,0);
send_req(plci);
- return FALSE;
+ return false;
}
else Info = 0x3010; /* wrong state */
break;
@@ -1997,13 +1997,13 @@ byte facility_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci,
plci->internal_command = BLOCK_PLCI;
plci->command = 0;
dbug(1,dprintf("Spoof"));
- return FALSE;
+ return false;
}
else
{
sig_req(plci,CALL_RETRIEVE,0);
send_req(plci);
- return FALSE;
+ return false;
}
}
else Info = 0x3010; /* wrong state */
@@ -2123,7 +2123,7 @@ byte facility_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci,
add_p(plci,CAI,cai);
sig_req(plci,S_SERVICE,0);
send_req(plci);
- return FALSE;
+ return false;
}
else Info = 0x3010; /* wrong state */
break;
@@ -2265,7 +2265,7 @@ byte facility_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci,
add_p(rplci,CAI,cai);
sig_req(rplci,S_SERVICE,0);
send_req(rplci);
- return FALSE;
+ return false;
}
else
{
@@ -2291,14 +2291,14 @@ byte facility_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci,
ss_parms[3].info[3] = (byte)GET_WORD(&(ss_parms[2].info[0]));
plci->command = 0;
plci->internal_command = CD_REQ_PEND;
- appl->CDEnable = TRUE;
+ appl->CDEnable = true;
cai[0] = 1;
cai[1] = CALL_DEFLECTION;
add_p(plci,CAI,cai);
add_p(plci,CPN,ss_parms[3].info);
sig_req(plci,S_SERVICE,0);
send_req(plci);
- return FALSE;
+ return false;
break;
case S_CALL_FORWARDING_START:
@@ -2337,7 +2337,7 @@ byte facility_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci,
add_p(rplci,CPN,ss_parms[6].info);
sig_req(rplci,S_SERVICE,0);
send_req(rplci);
- return FALSE;
+ return false;
break;
case S_INTERROGATE_DIVERSION:
@@ -2456,7 +2456,7 @@ byte facility_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci,
sig_req(rplci,S_SERVICE,0);
send_req(rplci);
- return FALSE;
+ return false;
break;
case S_MWI_ACTIVATE:
@@ -2472,7 +2472,7 @@ byte facility_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci,
{
rplci = &a->plci[i-1];
rplci->appl = appl;
- rplci->cr_enquiry=TRUE;
+ rplci->cr_enquiry=true;
add_p(rplci,CAI,"\x01\x80");
add_p(rplci,UID,"\x06\x43\x61\x70\x69\x32\x30");
sig_req(rplci,ASSIGN,DSIG_ID);
@@ -2487,7 +2487,7 @@ byte facility_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci,
else
{
rplci = plci;
- rplci->cr_enquiry=FALSE;
+ rplci->cr_enquiry=false;
}
rplci->command = 0;
@@ -2509,7 +2509,7 @@ byte facility_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci,
add_p(rplci,UID,ss_parms[10].info); /* Time */
sig_req(rplci,S_SERVICE,0);
send_req(rplci);
- return FALSE;
+ return false;
case S_MWI_DEACTIVATE:
if(api_parse(&parms->info[1],(word)parms->length,"wbwwss",ss_parms))
@@ -2524,7 +2524,7 @@ byte facility_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci,
{
rplci = &a->plci[i-1];
rplci->appl = appl;
- rplci->cr_enquiry=TRUE;
+ rplci->cr_enquiry=true;
add_p(rplci,CAI,"\x01\x80");
add_p(rplci,UID,"\x06\x43\x61\x70\x69\x32\x30");
sig_req(rplci,ASSIGN,DSIG_ID);
@@ -2539,7 +2539,7 @@ byte facility_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci,
else
{
rplci = plci;
- rplci->cr_enquiry=FALSE;
+ rplci->cr_enquiry=false;
}
rplci->command = 0;
@@ -2556,7 +2556,7 @@ byte facility_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci,
add_p(rplci,OAD,ss_parms[5].info); /* Controlling User Number */
sig_req(rplci,S_SERVICE,0);
send_req(rplci);
- return FALSE;
+ return false;
default:
Info = 0x300E; /* not supported */
@@ -2597,13 +2597,13 @@ byte facility_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci,
Id,
Number,
"wws",Info,selector,SSparms);
- return FALSE;
+ return false;
}
byte facility_res(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * msg)
{
dbug(1,dprintf("facility_res"));
- return FALSE;
+ return false;
}
byte connect_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * parms)
@@ -2649,7 +2649,7 @@ byte connect_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plc
Id,
Number,
"w",Info);
- return FALSE;
+ return false;
}
plci->requested_options_conn = 0;
@@ -2684,7 +2684,7 @@ byte connect_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plc
|| (fax_feature_bits & T30_FEATURE_BIT_MORE_DOCUMENTS))
{
len = (byte)(&(((T30_INFO *) 0)->universal_6));
- fax_info_change = FALSE;
+ fax_info_change = false;
if (ncpi->length >= 4)
{
w = GET_WORD(&ncpi->info[3]);
@@ -2693,7 +2693,7 @@ byte connect_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plc
((T30_INFO *)(plci->fax_connect_info_buffer))->resolution =
(byte)((((T30_INFO *)(plci->fax_connect_info_buffer))->resolution & ~T30_RESOLUTION_R8_0770_OR_200) |
((w & 0x0001) ? T30_RESOLUTION_R8_0770_OR_200 : 0));
- fax_info_change = TRUE;
+ fax_info_change = true;
}
fax_control_bits &= ~(T30_CONTROL_BIT_REQUEST_POLLING | T30_CONTROL_BIT_MORE_DOCUMENTS);
if (w & 0x0002) /* Fax-polling request */
@@ -2709,7 +2709,7 @@ byte connect_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plc
if (((byte) w) != ((T30_INFO *)(plci->fax_connect_info_buffer))->data_format)
{
((T30_INFO *)(plci->fax_connect_info_buffer))->data_format = (byte) w;
- fax_info_change = TRUE;
+ fax_info_change = true;
}
if ((a->man_profile.private_options & (1L << PRIVATE_FAX_SUB_SEP_PWD))
@@ -2781,13 +2781,13 @@ byte connect_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plc
{
len = (byte)(&(((T30_INFO *) 0)->universal_6));
}
- fax_info_change = TRUE;
+ fax_info_change = true;
}
if (fax_control_bits != GET_WORD(&((T30_INFO *)plci->fax_connect_info_buffer)->control_bits_low))
{
PUT_WORD (&((T30_INFO *)plci->fax_connect_info_buffer)->control_bits_low, fax_control_bits);
- fax_info_change = TRUE;
+ fax_info_change = true;
}
}
if (Info == GOOD)
@@ -2798,12 +2798,12 @@ byte connect_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plc
if (fax_feature_bits & T30_FEATURE_BIT_MORE_DOCUMENTS)
{
start_internal_command (Id, plci, fax_connect_info_command);
- return FALSE;
+ return false;
}
else
{
start_internal_command (Id, plci, fax_adjust_b23_command);
- return FALSE;
+ return false;
}
}
}
@@ -2820,7 +2820,7 @@ byte connect_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plc
for (w = 0; w < ncpi->length; w++)
plci->internal_req_buffer[2+w] = ncpi->info[1+w];
start_internal_command (Id, plci, rtp_connect_b3_req_command);
- return FALSE;
+ return false;
}
if(!Info)
@@ -2837,7 +2837,7 @@ byte connect_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plc
Id,
Number,
"w",Info);
- return FALSE;
+ return false;
}
byte connect_b3_res(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * parms)
@@ -2909,7 +2909,7 @@ byte connect_b3_res(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plc
plci->fax_connect_info_length = len;
((T30_INFO *)(plci->fax_connect_info_buffer))->code = 0;
start_internal_command (Id, plci, fax_connect_ack_command);
- return FALSE;
+ return false;
}
}
@@ -2932,7 +2932,7 @@ byte connect_b3_res(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plc
for (w = 0; w < ncpi->length; w++)
plci->internal_req_buffer[2+w] = ncpi->info[1+w];
start_internal_command (Id, plci, rtp_connect_b3_res_command);
- return FALSE;
+ return false;
}
else
@@ -2945,14 +2945,14 @@ byte connect_b3_res(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plc
sendf(appl,_CONNECT_B3_ACTIVE_I,Id,0,"s","");
if (plci->adjust_b_restore)
{
- plci->adjust_b_restore = FALSE;
+ plci->adjust_b_restore = false;
start_internal_command (Id, plci, adjust_b_restore);
}
}
return 1;
}
}
- return FALSE;
+ return false;
}
byte connect_b3_a_res(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * parms)
@@ -2972,7 +2972,7 @@ byte connect_b3_a_res(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * p
channel_xmit_xon (plci);
}
}
- return FALSE;
+ return false;
}
byte disconnect_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * parms)
@@ -3004,7 +3004,7 @@ byte disconnect_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI *
{
plci->send_disc = (byte)ncci;
plci->command = 0;
- return FALSE;
+ return false;
}
else
{
@@ -3028,7 +3028,7 @@ byte disconnect_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI *
Id,
Number,
"w",Info);
- return FALSE;
+ return false;
}
byte disconnect_b3_res(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * parms)
@@ -3084,7 +3084,7 @@ byte disconnect_b3_res(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI *
}
}
}
- return FALSE;
+ return false;
}
byte data_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * parms)
@@ -3140,7 +3140,7 @@ byte data_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci,
}
send_data(plci);
- return FALSE;
+ return false;
}
}
if (appl)
@@ -3161,7 +3161,7 @@ byte data_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci,
Number,
"ww",GET_WORD(parms[2].info),Info);
}
- return FALSE;
+ return false;
}
byte data_b3_res(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * parms)
@@ -3194,7 +3194,7 @@ byte data_b3_res(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci,
}
}
}
- return FALSE;
+ return false;
}
byte reset_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * parms)
@@ -3235,7 +3235,7 @@ byte reset_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci,
Id,
Number,
"w",Info);
- return FALSE;
+ return false;
}
byte reset_b3_res(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * parms)
@@ -3254,12 +3254,12 @@ byte reset_b3_res(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci,
{
a->ncci_state[ncci] = CONNECTED;
nl_req_ncci(plci,N_RESET_ACK,(byte)ncci);
- return TRUE;
+ return true;
}
break;
}
}
- return FALSE;
+ return false;
}
byte connect_b3_t90_a_res(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * parms)
@@ -3292,7 +3292,7 @@ byte connect_b3_t90_a_res(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI
return 1;
}
}
- return FALSE;
+ return false;
}
@@ -3378,7 +3378,7 @@ byte select_b_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci,
plci->internal_command = BLOCK_PLCI; /* lock other commands */
plci->command = 0;
dbug(1,dprintf("continue if codec loaded"));
- return FALSE;
+ return false;
}
}
}
@@ -3407,12 +3407,12 @@ byte select_b_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci,
else if (plci->call_dir & CALL_DIR_IN)
plci->call_dir = CALL_DIR_IN | CALL_DIR_ANSWER;
start_internal_command (Id, plci, select_b_command);
- return FALSE;
+ return false;
}
}
}
sendf(appl, _SELECT_B_REQ|CONFIRM, Id, Number, "w", Info);
- return FALSE;
+ return false;
}
byte manufacturer_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * parms)
@@ -3489,7 +3489,7 @@ byte manufacturer_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * p
}
plci->State = LOCAL_CONNECT;
- plci->manufacturer = TRUE;
+ plci->manufacturer = true;
plci->command = _MANUFACTURER_R;
plci->m_command = command;
plci->number = Number;
@@ -3520,7 +3520,7 @@ byte manufacturer_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * p
plci->internal_command = BLOCK_PLCI; /* reject other req meanwhile */
plci->command = 0;
send_req(plci);
- return FALSE;
+ return false;
}
if(dir==1) {
sig_req(plci,CALL_REQ,0);
@@ -3573,7 +3573,7 @@ byte manufacturer_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * p
}
else if(req==LAW_REQ)
{
- plci->cr_enquiry = TRUE;
+ plci->cr_enquiry = true;
}
add_ss(plci,FTY,&m_parms[1]);
sig_req(plci,req,0);
@@ -3739,7 +3739,7 @@ byte manufacturer_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * p
Id,
Number,
"dww",_DI_MANU_ID,command,Info);
- return FALSE;
+ return false;
}
@@ -3760,7 +3760,7 @@ byte manufacturer_res(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * p
|| (msg[1].length == 0)
|| (GET_DWORD(msg[0].info)!=_DI_MANU_ID))
{
- return FALSE;
+ return false;
}
indication = GET_WORD(msg[1].info);
switch (indication)
@@ -3811,7 +3811,7 @@ byte manufacturer_res(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * p
break;
}
- return FALSE;
+ return false;
}
/*------------------------------------------------------------------*/
@@ -3908,14 +3908,14 @@ void callback(ENTITY * e)
plci->nl_req = 0;
}
if (plci->nl_req)
- control_rc (plci, 0, rc, ch, 0, TRUE);
+ control_rc (plci, 0, rc, ch, 0, true);
else
{
if (req == N_XON)
{
channel_x_on (plci, ch);
if (plci->internal_command)
- control_rc (plci, req, rc, ch, 0, TRUE);
+ control_rc (plci, req, rc, ch, 0, true);
}
else
{
@@ -3931,21 +3931,21 @@ void callback(ENTITY * e)
}
}
channel_xmit_xon (plci);
- control_rc (plci, 0, rc, ch, global_req, TRUE);
+ control_rc (plci, 0, rc, ch, global_req, true);
}
else if (plci->data_sent)
{
channel_xmit_xon (plci);
- plci->data_sent = FALSE;
+ plci->data_sent = false;
plci->NL.XNum = 1;
data_rc (plci, ch);
if (plci->internal_command)
- control_rc (plci, req, rc, ch, 0, TRUE);
+ control_rc (plci, req, rc, ch, 0, true);
}
else
{
channel_xmit_xon (plci);
- control_rc (plci, req, rc, ch, 0, TRUE);
+ control_rc (plci, req, rc, ch, 0, true);
}
}
}
@@ -3974,12 +3974,12 @@ void callback(ENTITY * e)
if (rc != ASSIGN_OK)
e->Id = 0;
channel_xmit_xon (plci);
- control_rc (plci, 0, rc, ch, global_req, FALSE);
+ control_rc (plci, 0, rc, ch, global_req, false);
}
else
{
channel_xmit_xon (plci);
- control_rc (plci, req, rc, ch, 0, FALSE);
+ control_rc (plci, req, rc, ch, 0, false);
}
}
/*
@@ -4065,8 +4065,8 @@ capi_callback_suffix:
if (plci->li_notify_update)
{
- plci->li_notify_update = FALSE;
- mixer_notify_update (plci, FALSE);
+ plci->li_notify_update = false;
+ mixer_notify_update (plci, false);
}
}
@@ -4428,7 +4428,7 @@ void control_rc(PLCI * plci, byte req, byte rc, byte ch, byte global_req, byte
else
{
sendf(appl,_INFO_R|CONFIRM,Id&0xf,Number,"w",_WRONG_STATE);
- appl->NullCREnable = FALSE;
+ appl->NullCREnable = false;
plci_remove(plci);
}
}
@@ -4441,7 +4441,7 @@ void control_rc(PLCI * plci, byte req, byte rc, byte ch, byte global_req, byte
else
{
sendf(appl,_INFO_R|CONFIRM,Id&0xf,Number,"w",_WRONG_STATE);
- appl->NullCREnable = FALSE;
+ appl->NullCREnable = false;
}
plci_remove(plci);
}
@@ -4862,7 +4862,7 @@ void sig_ind(PLCI * plci)
byte CF_Ind[] = "\x09\x02\x00\x06\x00\x00\x00\x00\x00\x00";
byte Interr_Err_Ind[] = "\x0a\x02\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
byte CONF_Ind[] = "\x09\x16\x00\x06\x00\x00\0x00\0x00\0x00\0x00";
- byte force_mt_info = FALSE;
+ byte force_mt_info = false;
byte dir;
dword d;
word w;
@@ -4933,7 +4933,7 @@ void sig_ind(PLCI * plci)
{
if(plci->cr_enquiry && plci->appl)
{
- plci->cr_enquiry = FALSE;
+ plci->cr_enquiry = false;
/* d = MANU_ID */
/* w = m_command */
/* b = total length */
@@ -5158,7 +5158,7 @@ void sig_ind(PLCI * plci)
if(application[i].CDEnable)
{
if(application[i].Id) sendf(&application[i],_FACILITY_I,Id,0,"ws",3, SS_Ind);
- application[i].CDEnable = FALSE;
+ application[i].CDEnable = false;
}
}
break;
@@ -5375,7 +5375,7 @@ void sig_ind(PLCI * plci)
if(application[i].CDEnable)
{
if(application[i].Id) sendf(&application[i],_FACILITY_I,Id,0,"ws",3, SS_Ind);
- application[i].CDEnable = FALSE;
+ application[i].CDEnable = false;
}
}
break;
@@ -5730,7 +5730,7 @@ void sig_ind(PLCI * plci)
plci,
Id,
parms,
- SendMultiIE(plci,Id,multi_pi_parms, PI, 0x210, TRUE));
+ SendMultiIE(plci,Id,multi_pi_parms, PI, 0x210, true));
}
}
clear_c_ind_mask_bit (plci, MAX_APPL);
@@ -6117,38 +6117,38 @@ static void SendSetupInfo(APPL * appl, PLCI * plci, dword Id, byte * * par
dbug(1,dprintf("CPN "));
Info_Number = 0x0070;
Info_Mask = 0x80;
- Info_Sent_Flag = TRUE;
+ Info_Sent_Flag = true;
break;
case 8: /* display */
dbug(1,dprintf("display(%d)",i));
Info_Number = 0x0028;
Info_Mask = 0x04;
- Info_Sent_Flag = TRUE;
+ Info_Sent_Flag = true;
break;
case 16: /* Channel Id */
dbug(1,dprintf("CHI"));
Info_Number = 0x0018;
Info_Mask = 0x100;
- Info_Sent_Flag = TRUE;
+ Info_Sent_Flag = true;
mixer_set_bchannel_id (plci, Info_Element);
break;
case 19: /* Redirected Number */
dbug(1,dprintf("RDN"));
Info_Number = 0x0074;
Info_Mask = 0x400;
- Info_Sent_Flag = TRUE;
+ Info_Sent_Flag = true;
break;
case 20: /* Redirected Number extended */
dbug(1,dprintf("RDX"));
Info_Number = 0x0073;
Info_Mask = 0x400;
- Info_Sent_Flag = TRUE;
+ Info_Sent_Flag = true;
break;
case 22: /* Redirecing Number */
dbug(1,dprintf("RIN"));
Info_Number = 0x0076;
Info_Mask = 0x400;
- Info_Sent_Flag = TRUE;
+ Info_Sent_Flag = true;
break;
default:
Info_Number = 0;
@@ -6312,7 +6312,7 @@ void SendInfo(PLCI * plci, dword Id, byte * * parms, byte iesent)
&& plci->adapter->Info_Mask[appl->Id-1] &Info_Mask)
{
dbug(1,dprintf("NCR_Ind"));
- iesent=TRUE;
+ iesent=true;
sendf(&application[j],_INFO_I,Id&0x0f,0,"wS",Info_Number,Info_Element);
}
}
@@ -6330,7 +6330,7 @@ void SendInfo(PLCI * plci, dword Id, byte * * parms, byte iesent)
if(test_c_ind_mask_bit (plci, j))
{
dbug(1,dprintf("Ovl_Ind"));
- iesent=TRUE;
+ iesent=true;
sendf(&application[j],_INFO_I,Id,0,"wS",Info_Number,Info_Element);
}
}
@@ -6340,7 +6340,7 @@ void SendInfo(PLCI * plci, dword Id, byte * * parms, byte iesent)
&& plci->adapter->Info_Mask[plci->appl->Id-1] &Info_Mask)
{
dbug(1,dprintf("Std_Ind"));
- iesent=TRUE;
+ iesent=true;
sendf(plci->appl,_INFO_I,Id,0,"wS",Info_Number,Info_Element);
}
}
@@ -6391,7 +6391,7 @@ byte SendMultiIE(PLCI * plci, dword Id, byte * * parms, byte ie_type, dword
&& appl->Id
&& plci->adapter->Info_Mask[appl->Id-1] &Info_Mask)
{
- iesent = TRUE;
+ iesent = true;
dbug(1,dprintf("Mlt_NCR_Ind"));
sendf(&application[j],_INFO_I,Id&0x0f,0,"wS",Info_Number,Info_Element);
}
@@ -6403,7 +6403,7 @@ byte SendMultiIE(PLCI * plci, dword Id, byte * * parms, byte ie_type, dword
{
if(test_c_ind_mask_bit (plci, j))
{
- iesent = TRUE;
+ iesent = true;
dbug(1,dprintf("Mlt_Ovl_Ind"));
sendf(&application[j],_INFO_I,Id,0,"wS",Info_Number,Info_Element);
}
@@ -6412,7 +6412,7 @@ byte SendMultiIE(PLCI * plci, dword Id, byte * * parms, byte ie_type, dword
else if(Info_Number
&& plci->adapter->Info_Mask[plci->appl->Id-1] &Info_Mask)
{
- iesent = TRUE;
+ iesent = true;
dbug(1,dprintf("Mlt_Std_Ind"));
sendf(plci->appl,_INFO_I,Id,0,"wS",Info_Number,Info_Element);
}
@@ -6812,7 +6812,7 @@ void nl_ind(PLCI * plci)
}
if (((plci->NL.Ind & 0x0f) == N_DISC) || ((plci->NL.Ind & 0x0f) == N_DISC_ACK))
{
- if (((T30_INFO *)plci->NL.RBuffer->P)->code < sizeof(fax_info) / sizeof(fax_info[0]))
+ if (((T30_INFO *)plci->NL.RBuffer->P)->code < ARRAY_SIZE(fax_info))
info = fax_info[((T30_INFO *)plci->NL.RBuffer->P)->code];
else
info = _FAX_PROTOCOL_ERROR;
@@ -6887,7 +6887,7 @@ void nl_ind(PLCI * plci)
(byte)(plci->ncpi_buffer[0] + 1), plci->ncpi_buffer);
plci->ncpi_state |= NCPI_NEGOTIATE_B3_SENT;
if (plci->nsf_control_bits & T30_NSF_CONTROL_BIT_NEGOTIATE_RESP)
- fax_send_edata_ack = FALSE;
+ fax_send_edata_ack = false;
}
if (a->manufacturer_features & MANUFACTURER_FEATURE_FAX_PAPER_FORMATS)
@@ -6928,7 +6928,7 @@ void nl_ind(PLCI * plci)
sendf(plci->appl,_DISCONNECT_B3_I,Id,0,"wS",GOOD,plci->ncpi_buffer);
a->ncci_state[ncci] = INC_DIS_PENDING;
plci->ncpi_state = 0;
- fax_send_edata_ack = FALSE;
+ fax_send_edata_ack = false;
}
break;
}
@@ -7025,7 +7025,7 @@ void nl_ind(PLCI * plci)
}
if (plci->adjust_b_restore)
{
- plci->adjust_b_restore = FALSE;
+ plci->adjust_b_restore = false;
start_internal_command (Id, plci, adjust_b_restore);
}
break;
@@ -7041,7 +7041,7 @@ void nl_ind(PLCI * plci)
next_internal_command (Id, plci);
}
ncci_state = a->ncci_state[ncci];
- ncci_remove (plci, ncci, FALSE);
+ ncci_remove (plci, ncci, false);
/* with N_DISC or N_DISC_ACK the IDI frees the respective */
/* channel, so we cannot store the state in ncci_state! The */
@@ -7288,18 +7288,18 @@ word get_plci(DIVA_CAPI_ADAPTER * a)
plci->msg_in_read_pos = MSG_IN_QUEUE_SIZE;
plci->msg_in_wrap_pos = MSG_IN_QUEUE_SIZE;
- plci->data_sent = FALSE;
+ plci->data_sent = false;
plci->send_disc = 0;
plci->sig_global_req = 0;
plci->sig_remove_id = 0;
plci->nl_global_req = 0;
plci->nl_remove_id = 0;
plci->adv_nl = 0;
- plci->manufacturer = FALSE;
+ plci->manufacturer = false;
plci->call_dir = CALL_DIR_OUT | CALL_DIR_ORIGINATE;
plci->spoofed_msg = 0;
plci->ptyState = 0;
- plci->cr_enquiry = FALSE;
+ plci->cr_enquiry = false;
plci->hangup_flow_ctrl_timer = 0;
plci->ncci_ring_list = 0;
@@ -7972,7 +7972,7 @@ word add_b23(PLCI * plci, API_PARSE * bp)
if(!bp->length && plci->tel)
{
- plci->adv_nl = TRUE;
+ plci->adv_nl = true;
dbug(1,dprintf("Default adv.Nl"));
add_p(plci,LLI,lli);
plci->B2_prot = 1 /*XPARENT*/;
@@ -8022,7 +8022,7 @@ word add_b23(PLCI * plci, API_PARSE * bp)
{
if(GET_WORD(bp_parms[1].info)!=1
|| GET_WORD(bp_parms[2].info)!=0) return _B2_NOT_SUPPORTED;
- plci->adv_nl = TRUE;
+ plci->adv_nl = true;
}
else if(plci->tel) return _B2_NOT_SUPPORTED;
@@ -8840,7 +8840,7 @@ void send_data(PLCI * plci)
plci->NL.X = plci->NData;
plci->NL.ReqCh = a->ncci_ch[ncci];
dbug(1,dprintf("%x:DREQ(%x:%x)",a->Id,plci->NL.Id,plci->NL.Req));
- plci->data_sent = TRUE;
+ plci->data_sent = true;
plci->data_sent_ptr = data->P;
a->request(&plci->NL);
}
@@ -8995,10 +8995,10 @@ void IndParse(PLCI * plci, word * parms_id, byte ** parms, byte multiIEsize)
byte ie_compare(byte * ie1, byte * ie2)
{
word i;
- if(!ie1 || ! ie2) return FALSE;
- if(!ie1[0]) return FALSE;
- for(i=0;i<(word)(ie1[0]+1);i++) if(ie1[i]!=ie2[i]) return FALSE;
- return TRUE;
+ if(!ie1 || ! ie2) return false;
+ if(!ie1[0]) return false;
+ for(i=0;i<(word)(ie1[0]+1);i++) if(ie1[i]!=ie2[i]) return false;
+ return true;
}
word find_cip(DIVA_CAPI_ADAPTER * a, byte * bc, byte * hlc)
@@ -9151,7 +9151,7 @@ word AdvCodecSupport(DIVA_CAPI_ADAPTER *a, PLCI *plci, APPL *appl, byte ho
plci->tel=ADV_VOICE;
}
a->AdvSignalAppl = appl;
- a->AdvCodecFLAG = TRUE;
+ a->AdvCodecFLAG = true;
a->AdvCodecPLCI = splci;
add_p(splci,CAI,"\x01\x15");
add_p(splci,LLI,"\x01\x00");
@@ -9183,7 +9183,7 @@ word AdvCodecSupport(DIVA_CAPI_ADAPTER *a, PLCI *plci, APPL *appl, byte ho
add_p(splci,UID,"\x06\x43\x61\x70\x69\x32\x30");
sig_req(splci,ASSIGN,0xC0); /* 0xc0 is the TEL_ID */
send_req(splci);
- a->scom_appl_disable = TRUE;
+ a->scom_appl_disable = true;
}
else{
return 0x2001; /* wrong state, no more plcis */
@@ -9411,7 +9411,7 @@ word CapiRelease(word Id)
}
if(a->AdvSignalAppl==this)
{
- this->NullCREnable = FALSE;
+ this->NullCREnable = false;
if (a->AdvCodecPLCI)
{
plci_remove(a->AdvCodecPLCI);
@@ -9433,7 +9433,7 @@ word CapiRelease(word Id)
static word plci_remove_check(PLCI *plci)
{
- if(!plci) return TRUE;
+ if(!plci) return true;
if(!plci->NL.Id && c_ind_mask_empty (plci))
{
if(plci->Sig.Id == 0xff)
@@ -9446,7 +9446,7 @@ static word plci_remove_check(PLCI *plci)
{
CodecIdCheck(plci->adapter, plci);
clear_b1_config (plci);
- ncci_remove (plci, 0, FALSE);
+ ncci_remove (plci, 0, false);
plci_free_msg_in_queue (plci);
channel_flow_control_remove (plci);
plci->Id = 0;
@@ -9456,10 +9456,10 @@ static word plci_remove_check(PLCI *plci)
plci->notifiedcall = 0;
}
listen_check(plci->adapter);
- return TRUE;
+ return true;
}
}
- return FALSE;
+ return false;
}
@@ -9564,7 +9564,7 @@ static struct
};
-#define DTMF_DIGIT_MAP_ENTRIES (sizeof(dtmf_digit_map) / sizeof(dtmf_digit_map[0]))
+#define DTMF_DIGIT_MAP_ENTRIES ARRAY_SIZE(dtmf_digit_map)
static void dtmf_enable_receiver (PLCI *plci, byte enable_mask)
@@ -9815,7 +9815,7 @@ static void dtmf_command (dword Id, PLCI *plci, byte Rc)
}
plci->dtmf_rec_active &= ~mask;
plci->internal_command = DTMF_COMMAND_2;
- dtmf_enable_receiver (plci, FALSE);
+ dtmf_enable_receiver (plci, false);
return;
}
Rc = OK;
@@ -10020,7 +10020,7 @@ static byte dtmf_request (dword Id, word Number, DIVA_CAPI_ADAPTER *a, PLCI
}
}
start_internal_command (Id, plci, dtmf_command);
- return (FALSE);
+ return (false);
case DTMF_SEND_TONE:
@@ -10069,8 +10069,7 @@ static byte dtmf_request (dword Id, word Number, DIVA_CAPI_ADAPTER *a, PLCI
PUT_WORD (&result[1], DTMF_INCORRECT_DIGIT);
break;
}
- if (plci->dtmf_send_requests >=
- sizeof(plci->dtmf_msg_number_queue) / sizeof(plci->dtmf_msg_number_queue[0]))
+ if (plci->dtmf_send_requests >= ARRAY_SIZE(plci->dtmf_msg_number_queue))
{
dbug (1, dprintf ("[%06lx] %s,%d: DTMF request overrun",
UnMapId (Id), (char *)(FILE_), __LINE__));
@@ -10079,7 +10078,7 @@ static byte dtmf_request (dword Id, word Number, DIVA_CAPI_ADAPTER *a, PLCI
}
api_save_msg (dtmf_parms, "wwws", &plci->saved_msg);
start_internal_command (Id, plci, dtmf_command);
- return (FALSE);
+ return (false);
default:
dbug (1, dprintf ("[%06lx] %s,%d: DTMF unknown request %04x",
@@ -10090,7 +10089,7 @@ static byte dtmf_request (dword Id, word Number, DIVA_CAPI_ADAPTER *a, PLCI
}
sendf (appl, _FACILITY_R | CONFIRM, Id & 0xffffL, Number,
"wws", Info, SELECTOR_DTMF, result);
- return (FALSE);
+ return (false);
}
@@ -10842,10 +10841,10 @@ static struct
byte to_pc;
} xconnect_write_prog[] =
{
- { LI_COEF_CH_CH, FALSE, FALSE },
- { LI_COEF_CH_PC, FALSE, TRUE },
- { LI_COEF_PC_CH, TRUE, FALSE },
- { LI_COEF_PC_PC, TRUE, TRUE }
+ { LI_COEF_CH_CH, false, false },
+ { LI_COEF_CH_PC, false, true },
+ { LI_COEF_PC_CH, true, false },
+ { LI_COEF_PC_PC, true, true }
};
@@ -10916,7 +10915,7 @@ static byte xconnect_write_coefs_process (dword Id, PLCI *plci, byte Rc)
{
dbug (1, dprintf ("[%06x] %s,%d: Channel id wiped out",
UnMapId (Id), (char *)(FILE_), __LINE__));
- return (TRUE);
+ return (true);
}
i = a->li_base + (plci->li_bchannel_id - 1);
j = plci->li_write_channel;
@@ -10927,7 +10926,7 @@ static byte xconnect_write_coefs_process (dword Id, PLCI *plci, byte Rc)
{
dbug (1, dprintf ("[%06lx] %s,%d: LI write coefs failed %02x",
UnMapId (Id), (char *)(FILE_), __LINE__, Rc));
- return (FALSE);
+ return (false);
}
}
if (li_config_table[i].adapter->manufacturer_features & MANUFACTURER_FEATURE_XCONNECT)
@@ -10969,7 +10968,7 @@ static byte xconnect_write_coefs_process (dword Id, PLCI *plci, byte Rc)
{
plci->internal_command = plci->li_write_command;
if (plci_nl_busy (plci))
- return (TRUE);
+ return (true);
to_ch = (a->li_pri) ? plci->li_bchannel_id - 1 : 0;
*(p++) = UDATA_REQUEST_XCONNECT_TO;
do
@@ -11018,9 +11017,9 @@ static byte xconnect_write_coefs_process (dword Id, PLCI *plci, byte Rc)
li_config_table[i].coef_table[j] ^= xconnect_write_prog[n].mask << 4;
}
n++;
- } while ((n < sizeof(xconnect_write_prog) / sizeof(xconnect_write_prog[0]))
+ } while ((n < ARRAY_SIZE(xconnect_write_prog))
&& ((p - plci->internal_req_buffer) + 16 < INTERNAL_REQ_BUFFER_SIZE));
- if (n == sizeof(xconnect_write_prog) / sizeof(xconnect_write_prog[0]))
+ if (n == ARRAY_SIZE(xconnect_write_prog))
{
do
{
@@ -11050,7 +11049,7 @@ static byte xconnect_write_coefs_process (dword Id, PLCI *plci, byte Rc)
{
plci->internal_command = plci->li_write_command;
if (plci_nl_busy (plci))
- return (TRUE);
+ return (true);
if (a->li_pri)
{
*(p++) = UDATA_REQUEST_SET_MIXER_COEFS_PRI_SYNC;
@@ -11090,7 +11089,7 @@ static byte xconnect_write_coefs_process (dword Id, PLCI *plci, byte Rc)
ch_map[j+1] = (byte)(j+1);
}
}
- for (n = 0; n < sizeof(mixer_write_prog_bri) / sizeof(mixer_write_prog_bri[0]); n++)
+ for (n = 0; n < ARRAY_SIZE(mixer_write_prog_bri); n++)
{
i = a->li_base + ch_map[mixer_write_prog_bri[n].to_ch];
j = a->li_base + ch_map[mixer_write_prog_bri[n].from_ch];
@@ -11127,7 +11126,7 @@ static byte xconnect_write_coefs_process (dword Id, PLCI *plci, byte Rc)
{
plci->internal_command = plci->li_write_command;
if (plci_nl_busy (plci))
- return (TRUE);
+ return (true);
if (j < a->li_base)
j = a->li_base;
if (a->li_pri)
@@ -11140,7 +11139,7 @@ static byte xconnect_write_coefs_process (dword Id, PLCI *plci, byte Rc)
w |= MIXER_FEATURE_ENABLE_RX_DATA;
*(p++) = (byte) w;
*(p++) = (byte)(w >> 8);
- for (n = 0; n < sizeof(mixer_write_prog_pri) / sizeof(mixer_write_prog_pri[0]); n++)
+ for (n = 0; n < ARRAY_SIZE(mixer_write_prog_pri); n++)
{
*(p++) = (byte)((plci->li_bchannel_id - 1) | mixer_write_prog_pri[n].line_flags);
for (j = a->li_base; j < a->li_base + MIXER_CHANNELS_PRI; j++)
@@ -11196,7 +11195,7 @@ static byte xconnect_write_coefs_process (dword Id, PLCI *plci, byte Rc)
ch_map[j+1] = (byte)(j+1);
}
}
- for (n = 0; n < sizeof(mixer_write_prog_bri) / sizeof(mixer_write_prog_bri[0]); n++)
+ for (n = 0; n < ARRAY_SIZE(mixer_write_prog_bri); n++)
{
i = a->li_base + ch_map[mixer_write_prog_bri[n].to_ch];
j = a->li_base + ch_map[mixer_write_prog_bri[n].from_ch];
@@ -11232,7 +11231,7 @@ static byte xconnect_write_coefs_process (dword Id, PLCI *plci, byte Rc)
plci->NL.Req = plci->nl_req = (byte) N_UDATA;
plci->adapter->request (&plci->NL);
}
- return (TRUE);
+ return (true);
}
@@ -11251,7 +11250,7 @@ static void mixer_notify_update (PLCI *plci, byte others)
if (a->profile.Global_Options & GL_LINE_INTERCONNECT_SUPPORTED)
{
if (others)
- plci->li_notify_update = TRUE;
+ plci->li_notify_update = true;
i = 0;
do
{
@@ -11277,7 +11276,7 @@ static void mixer_notify_update (PLCI *plci, byte others)
&& (notify_plci->State)
&& notify_plci->NL.Id && !notify_plci->nl_remove_id)
{
- notify_plci->li_notify_update = TRUE;
+ notify_plci->li_notify_update = true;
((CAPI_MSG *) msg)->header.length = 18;
((CAPI_MSG *) msg)->header.appl_id = notify_plci->appl->Id;
((CAPI_MSG *) msg)->header.command = _FACILITY_R;
@@ -11299,12 +11298,12 @@ static void mixer_notify_update (PLCI *plci, byte others)
(char *)(FILE_), __LINE__,
(dword)((notify_plci->Id << 8) | UnMapController (notify_plci->adapter->Id)), w));
}
- notify_plci->li_notify_update = FALSE;
+ notify_plci->li_notify_update = false;
}
}
} while (others && (notify_plci != NULL));
if (others)
- plci->li_notify_update = FALSE;
+ plci->li_notify_update = false;
}
}
@@ -11318,7 +11317,7 @@ static void mixer_clear_config (PLCI *plci)
(dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
(char *)(FILE_), __LINE__));
- plci->li_notify_update = FALSE;
+ plci->li_notify_update = false;
plci->li_plci_b_write_pos = 0;
plci->li_plci_b_read_pos = 0;
plci->li_plci_b_req_pos = 0;
@@ -12159,7 +12158,7 @@ static byte mixer_request (dword Id, word Number, DIVA_CAPI_ADAPTER *a, PLCI
plci_b = li_check_plci_b (Id, plci, plci_b_id, plci_b_write_pos, &result[8]);
if (plci_b == NULL)
break;
- li_update_connect (Id, a, plci, plci_b_id, TRUE, li_flags);
+ li_update_connect (Id, a, plci, plci_b_id, true, li_flags);
plci->li_plci_b_queue[plci_b_write_pos] = plci_b_id | LI_PLCI_B_LAST_FLAG;
plci_b_write_pos = (plci_b_write_pos == LI_PLCI_B_QUEUE_ENTRIES-1) ? 0 : plci_b_write_pos + 1;
plci->li_plci_b_write_pos = plci_b_write_pos;
@@ -12188,7 +12187,7 @@ static byte mixer_request (dword Id, word Number, DIVA_CAPI_ADAPTER *a, PLCI
plci_b_write_pos = plci->li_plci_b_write_pos;
participant_parms_pos = 0;
result_pos = 7;
- li2_update_connect (Id, a, plci, UnMapId (Id), TRUE, li_flags);
+ li2_update_connect (Id, a, plci, UnMapId (Id), true, li_flags);
while (participant_parms_pos < li_req_parms[1].length)
{
result[result_pos] = 6;
@@ -12224,7 +12223,7 @@ static byte mixer_request (dword Id, word Number, DIVA_CAPI_ADAPTER *a, PLCI
plci_b = li2_check_plci_b (Id, plci, plci_b_id, plci_b_write_pos, &result[result_pos - 2]);
if (plci_b != NULL)
{
- li2_update_connect (Id, a, plci, plci_b_id, TRUE, li_flags);
+ li2_update_connect (Id, a, plci, plci_b_id, true, li_flags);
plci->li_plci_b_queue[plci_b_write_pos] = plci_b_id |
((li_flags & (LI2_FLAG_INTERCONNECT_A_B | LI2_FLAG_INTERCONNECT_B_A |
LI2_FLAG_PCCONNECT_A_B | LI2_FLAG_PCCONNECT_B_A)) ? 0 : LI_PLCI_B_DISC_FLAG);
@@ -12249,13 +12248,13 @@ static byte mixer_request (dword Id, word Number, DIVA_CAPI_ADAPTER *a, PLCI
}
mixer_calculate_coefs (a);
plci->li_channel_bits = li_config_table[a->li_base + (plci->li_bchannel_id - 1)].channel;
- mixer_notify_update (plci, TRUE);
+ mixer_notify_update (plci, true);
sendf (appl, _FACILITY_R | CONFIRM, Id & 0xffffL, Number,
"wwS", Info, SELECTOR_LINE_INTERCONNECT, result);
plci->command = 0;
plci->li_cmd = GET_WORD (li_parms[0].info);
start_internal_command (Id, plci, mixer_command);
- return (FALSE);
+ return (false);
case LI_REQ_DISCONNECT:
if (li_parms[1].length == 4)
@@ -12283,7 +12282,7 @@ static byte mixer_request (dword Id, word Number, DIVA_CAPI_ADAPTER *a, PLCI
plci_b = li_check_plci_b (Id, plci, plci_b_id, plci_b_write_pos, &result[8]);
if (plci_b == NULL)
break;
- li_update_connect (Id, a, plci, plci_b_id, FALSE, 0);
+ li_update_connect (Id, a, plci, plci_b_id, false, 0);
plci->li_plci_b_queue[plci_b_write_pos] = plci_b_id | LI_PLCI_B_DISC_FLAG | LI_PLCI_B_LAST_FLAG;
plci_b_write_pos = (plci_b_write_pos == LI_PLCI_B_QUEUE_ENTRIES-1) ? 0 : plci_b_write_pos + 1;
plci->li_plci_b_write_pos = plci_b_write_pos;
@@ -12345,7 +12344,7 @@ static byte mixer_request (dword Id, word Number, DIVA_CAPI_ADAPTER *a, PLCI
plci_b = li2_check_plci_b (Id, plci, plci_b_id, plci_b_write_pos, &result[result_pos - 2]);
if (plci_b != NULL)
{
- li2_update_connect (Id, a, plci, plci_b_id, FALSE, 0);
+ li2_update_connect (Id, a, plci, plci_b_id, false, 0);
plci->li_plci_b_queue[plci_b_write_pos] = plci_b_id | LI_PLCI_B_DISC_FLAG;
plci_b_write_pos = (plci_b_write_pos == LI_PLCI_B_QUEUE_ENTRIES-1) ? 0 : plci_b_write_pos + 1;
}
@@ -12368,13 +12367,13 @@ static byte mixer_request (dword Id, word Number, DIVA_CAPI_ADAPTER *a, PLCI
}
mixer_calculate_coefs (a);
plci->li_channel_bits = li_config_table[a->li_base + (plci->li_bchannel_id - 1)].channel;
- mixer_notify_update (plci, TRUE);
+ mixer_notify_update (plci, true);
sendf (appl, _FACILITY_R | CONFIRM, Id & 0xffffL, Number,
"wwS", Info, SELECTOR_LINE_INTERCONNECT, result);
plci->command = 0;
plci->li_cmd = GET_WORD (li_parms[0].info);
start_internal_command (Id, plci, mixer_command);
- return (FALSE);
+ return (false);
case LI_REQ_SILENT_UPDATE:
if (!plci || !plci->State
@@ -12384,7 +12383,7 @@ static byte mixer_request (dword Id, word Number, DIVA_CAPI_ADAPTER *a, PLCI
{
dbug (1, dprintf ("[%06lx] %s,%d: Wrong state",
UnMapId (Id), (char *)(FILE_), __LINE__));
- return (FALSE);
+ return (false);
}
plci_b_write_pos = plci->li_plci_b_write_pos;
if (((plci->li_plci_b_read_pos > plci_b_write_pos) ? plci->li_plci_b_read_pos :
@@ -12392,7 +12391,7 @@ static byte mixer_request (dword Id, word Number, DIVA_CAPI_ADAPTER *a, PLCI
{
dbug (1, dprintf ("[%06lx] %s,%d: LI request overrun",
UnMapId (Id), (char *)(FILE_), __LINE__));
- return (FALSE);
+ return (false);
}
i = (plci_b_write_pos == 0) ? LI_PLCI_B_QUEUE_ENTRIES-1 : plci_b_write_pos - 1;
if ((plci_b_write_pos == plci->li_plci_b_read_pos)
@@ -12408,7 +12407,7 @@ static byte mixer_request (dword Id, word Number, DIVA_CAPI_ADAPTER *a, PLCI
plci->command = 0;
plci->li_cmd = GET_WORD (li_parms[0].info);
start_internal_command (Id, plci, mixer_command);
- return (FALSE);
+ return (false);
default:
dbug (1, dprintf ("[%06lx] %s,%d: LI unknown request %04x",
@@ -12418,7 +12417,7 @@ static byte mixer_request (dword Id, word Number, DIVA_CAPI_ADAPTER *a, PLCI
}
sendf (appl, _FACILITY_R | CONFIRM, Id & 0xffffL, Number,
"wwS", Info, SELECTOR_LINE_INTERCONNECT, result);
- return (FALSE);
+ return (false);
}
@@ -12523,7 +12522,7 @@ static void mixer_indication_xconnect_from (dword Id, PLCI *plci, byte *msg,
if (!plci->internal_command)
next_internal_command (Id, plci);
}
- mixer_notify_update (plci, TRUE);
+ mixer_notify_update (plci, true);
}
@@ -12547,12 +12546,12 @@ static byte mixer_notify_source_removed (PLCI *plci, dword plci_b_id)
dbug (1, dprintf ("[%06lx] %s,%d: LI request overrun",
(dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
(char *)(FILE_), __LINE__));
- return (FALSE);
+ return (false);
}
plci->li_plci_b_queue[plci_b_write_pos] = plci_b_id | LI_PLCI_B_DISC_FLAG;
plci_b_write_pos = (plci_b_write_pos == LI_PLCI_B_QUEUE_ENTRIES-1) ? 0 : plci_b_write_pos + 1;
plci->li_plci_b_write_pos = plci_b_write_pos;
- return (TRUE);
+ return (true);
}
@@ -12596,7 +12595,7 @@ static void mixer_remove (PLCI *plci)
}
mixer_clear_config (plci);
mixer_calculate_coefs (a);
- mixer_notify_update (plci, TRUE);
+ mixer_notify_update (plci, true);
}
li_config_table[i].plci = NULL;
plci->li_bchannel_id = 0;
@@ -12883,29 +12882,29 @@ static byte ec_request (dword Id, word Number, DIVA_CAPI_ADAPTER *a, PLCI *p
case EC_ENABLE_OPERATION:
plci->ec_idi_options &= ~LEC_FREEZE_COEFFICIENTS;
start_internal_command (Id, plci, ec_command);
- return (FALSE);
+ return (false);
case EC_DISABLE_OPERATION:
plci->ec_idi_options = LEC_ENABLE_ECHO_CANCELLER |
LEC_MANUAL_DISABLE | LEC_ENABLE_NONLINEAR_PROCESSING |
LEC_RESET_COEFFICIENTS;
start_internal_command (Id, plci, ec_command);
- return (FALSE);
+ return (false);
case EC_FREEZE_COEFFICIENTS:
plci->ec_idi_options |= LEC_FREEZE_COEFFICIENTS;
start_internal_command (Id, plci, ec_command);
- return (FALSE);
+ return (false);
case EC_RESUME_COEFFICIENT_UPDATE:
plci->ec_idi_options &= ~LEC_FREEZE_COEFFICIENTS;
start_internal_command (Id, plci, ec_command);
- return (FALSE);
+ return (false);
case EC_RESET_COEFFICIENTS:
plci->ec_idi_options |= LEC_RESET_COEFFICIENTS;
start_internal_command (Id, plci, ec_command);
- return (FALSE);
+ return (false);
default:
dbug (1, dprintf ("[%06lx] %s,%d: EC unknown request %04x",
@@ -12978,14 +12977,14 @@ static byte ec_request (dword Id, word Number, DIVA_CAPI_ADAPTER *a, PLCI *p
case EC_ENABLE_OPERATION:
plci->ec_idi_options &= ~LEC_FREEZE_COEFFICIENTS;
start_internal_command (Id, plci, ec_command);
- return (FALSE);
+ return (false);
case EC_DISABLE_OPERATION:
plci->ec_idi_options = LEC_ENABLE_ECHO_CANCELLER |
LEC_MANUAL_DISABLE | LEC_ENABLE_NONLINEAR_PROCESSING |
LEC_RESET_COEFFICIENTS;
start_internal_command (Id, plci, ec_command);
- return (FALSE);
+ return (false);
default:
dbug (1, dprintf ("[%06lx] %s,%d: EC unknown request %04x",
@@ -12999,7 +12998,7 @@ static byte ec_request (dword Id, word Number, DIVA_CAPI_ADAPTER *a, PLCI *p
sendf (appl, _FACILITY_R | CONFIRM, Id & 0xffffL, Number,
"wws", Info, (appl->appl_flags & APPL_FLAG_PRIV_EC_SPEC) ?
PRIV_SELECTOR_ECHO_CANCELLER : SELECTOR_ECHO_CANCELLER, result);
- return (FALSE);
+ return (false);
}
@@ -13178,7 +13177,7 @@ static void adv_voice_write_coefs (PLCI *plci, word write_command)
ch_map[j] = (byte)(j + (plci->li_bchannel_id - 1));
ch_map[j+1] = (byte)(j + (2 - plci->li_bchannel_id));
}
- for (n = 0; n < sizeof(mixer_write_prog_bri) / sizeof(mixer_write_prog_bri[0]); n++)
+ for (n = 0; n < ARRAY_SIZE(mixer_write_prog_bri); n++)
{
i = a->li_base + ch_map[mixer_write_prog_bri[n].to_ch];
j = a->li_base + ch_map[mixer_write_prog_bri[n].from_ch];
@@ -13563,7 +13562,7 @@ static void adjust_b_clear (PLCI *plci)
(dword)((plci->Id << 8) | UnMapController (plci->adapter->Id)),
(char *)(FILE_), __LINE__));
- plci->adjust_b_restore = FALSE;
+ plci->adjust_b_restore = false;
}
@@ -13832,7 +13831,7 @@ static word adjust_b_process (dword Id, PLCI *plci, byte Rc)
}
if (plci->adjust_b_mode & ADJUST_B_MODE_USER_CONNECT)
{
- plci->adjust_b_restore = TRUE;
+ plci->adjust_b_restore = true;
break;
}
plci->adjust_b_state = ADJUST_B_CONNECT_1;
@@ -14603,7 +14602,7 @@ static void channel_request_xon (PLCI * plci, byte ch) {
static void channel_xmit_extended_xon (PLCI * plci) {
DIVA_CAPI_ADAPTER * a;
- int max_ch = sizeof(a->ch_flow_control)/sizeof(a->ch_flow_control[0]);
+ int max_ch = ARRAY_SIZE(a->ch_flow_control);
int i, one_requested = 0;
if ((!plci) || (!plci->Id) || ((a = plci->adapter) == 0)) {
@@ -14628,7 +14627,7 @@ static void channel_xmit_extended_xon (PLCI * plci) {
Try to xmit next X_ON
*/
static int find_channel_with_pending_x_on (DIVA_CAPI_ADAPTER * a, PLCI * plci) {
- int max_ch = sizeof(a->ch_flow_control)/sizeof(a->ch_flow_control[0]);
+ int max_ch = ARRAY_SIZE(a->ch_flow_control);
int i;
if (!(plci->adapter->manufacturer_features & MANUFACTURER_FEATURE_XONOFF_FLOW_CONTROL)) {
@@ -14768,19 +14767,19 @@ static void group_optimization(DIVA_CAPI_ADAPTER * a, PLCI * plci)
{
if(application[i].Id && a->CIP_Mask[i] )
{
- for(k=0,busy=FALSE; k<a->max_plci; k++)
+ for(k=0,busy=false; k<a->max_plci; k++)
{
if(a->plci[k].Id)
{
auxplci = &a->plci[k];
if(auxplci->appl == &application[i]) /* application has a busy PLCI */
{
- busy = TRUE;
+ busy = true;
dbug(1,dprintf("Appl 0x%x is busy",i+1));
}
else if(test_c_ind_mask_bit (auxplci, i)) /* application has an incoming call pending */
{
- busy = TRUE;
+ busy = true;
dbug(1,dprintf("Appl 0x%x has inc. call pending",i+1));
}
}
@@ -14791,13 +14790,13 @@ static void group_optimization(DIVA_CAPI_ADAPTER * a, PLCI * plci)
if(j==MAX_CIP_TYPES) /* all groups are in use but group still not found */
{ /* the MAX_CIP_TYPES group enables all calls because of field overflow */
appl_number_group_type[i] = MAX_CIP_TYPES;
- group_found=TRUE;
+ group_found=true;
dbug(1,dprintf("Field overflow appl 0x%x",i+1));
}
else if( (info_mask_group[j]==a->CIP_Mask[i]) && (cip_mask_group[j]==a->Info_Mask[i]) )
{ /* is group already present ? */
appl_number_group_type[i] = j|0x80; /* store the group number for each application */
- group_found=TRUE;
+ group_found=true;
dbug(1,dprintf("Group 0x%x found with appl 0x%x, CIP=0x%lx",appl_number_group_type[i],i+1,info_mask_group[j]));
}
else if(!info_mask_group[j])
@@ -14805,7 +14804,7 @@ static void group_optimization(DIVA_CAPI_ADAPTER * a, PLCI * plci)
appl_number_group_type[i] = j|0x80; /* store the group number for each application */
info_mask_group[j] = a->CIP_Mask[i]; /* store the new CIP mask for the new group */
cip_mask_group[j] = a->Info_Mask[i]; /* store the new Info_Mask for this new group */
- group_found=TRUE;
+ group_found=true;
dbug(1,dprintf("New Group 0x%x established with appl 0x%x, CIP=0x%lx",appl_number_group_type[i],i+1,info_mask_group[j]));
}
}
@@ -14860,7 +14859,7 @@ word CapiRegister(word id)
}
}
- if(appls_found) return TRUE;
+ if(appls_found) return true;
for(i=0; i<max_adapter; i++) /* scan all adapters... */
{
a = &adapter[i];
@@ -14889,7 +14888,7 @@ word CapiRegister(word id)
}
}
}
- return FALSE;
+ return false;
}
/*------------------------------------------------------------------*/
diff --git a/drivers/isdn/hardware/eicon/os_pri.c b/drivers/isdn/hardware/eicon/os_pri.c
index a296a846f29..903356547b7 100644
--- a/drivers/isdn/hardware/eicon/os_pri.c
+++ b/drivers/isdn/hardware/eicon/os_pri.c
@@ -487,7 +487,7 @@ diva_pri_start_adapter(PISDN_ADAPTER IoAdapter,
}
DIVA_OS_MEM_DETACH_ADDRESS(IoAdapter, boot);
- IoAdapter->Initialized = TRUE;
+ IoAdapter->Initialized = true;
/*
Check Interrupt
@@ -504,7 +504,7 @@ diva_pri_start_adapter(PISDN_ADAPTER IoAdapter,
if (!IoAdapter->IrqCount) {
DBG_ERR(("A: A(%d) interrupt test failed",
IoAdapter->ANum))
- IoAdapter->Initialized = FALSE;
+ IoAdapter->Initialized = false;
IoAdapter->stop(IoAdapter);
return (-1);
}
diff --git a/drivers/isdn/hardware/eicon/platform.h b/drivers/isdn/hardware/eicon/platform.h
index 2444811e0b3..ff09f07f440 100644
--- a/drivers/isdn/hardware/eicon/platform.h
+++ b/drivers/isdn/hardware/eicon/platform.h
@@ -71,14 +71,6 @@
#define qword u64
#endif
-#ifndef TRUE
-#define TRUE 1
-#endif
-
-#ifndef FALSE
-#define FALSE 0
-#endif
-
#ifndef NULL
#define NULL ((void *) 0)
#endif
@@ -131,10 +123,6 @@
#define DIVA_OS_MEM_DETACH_CONFIG(a, x) do { } while(0)
#define DIVA_OS_MEM_DETACH_CONTROL(a, x) do { } while(0)
-#if !defined(DIM)
-#define DIM(array) (sizeof (array)/sizeof ((array)[0]))
-#endif
-
#define DIVA_INVALID_FILE_HANDLE ((dword)(-1))
#define DIVAS_CONTAINING_RECORD(address, type, field) \
diff --git a/drivers/isdn/hisax/Kconfig b/drivers/isdn/hisax/Kconfig
index 34ab5f7dcab..12d91fb9f8c 100644
--- a/drivers/isdn/hisax/Kconfig
+++ b/drivers/isdn/hisax/Kconfig
@@ -340,8 +340,6 @@ config HISAX_HFC_SX
This enables HiSax support for the HFC-S+, HFC-SP and HFC-PCMCIA
cards. This code is not finished yet.
-# bool ' TESTEMULATOR (EXPERIMENTAL)' CONFIG_HISAX_TESTEMU
-
config HISAX_ENTERNOW_PCI
bool "Formula-n enter:now PCI card"
depends on HISAX_NETJET && PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || FRV))
diff --git a/drivers/isdn/hisax/Makefile b/drivers/isdn/hisax/Makefile
index 293e27789d5..c7a3794bdae 100644
--- a/drivers/isdn/hisax/Makefile
+++ b/drivers/isdn/hisax/Makefile
@@ -60,5 +60,4 @@ hisax-$(CONFIG_HISAX_SCT_QUADRO) += bkm_a8.o isac.o arcofi.o hscx.o
hisax-$(CONFIG_HISAX_GAZEL) += gazel.o isac.o arcofi.o hscx.o
hisax-$(CONFIG_HISAX_W6692) += w6692.o
hisax-$(CONFIG_HISAX_ENTERNOW_PCI) += enternow_pci.o amd7930_fn.o
-#hisax-$(CONFIG_HISAX_TESTEMU) += testemu.o
diff --git a/drivers/isdn/hisax/avma1_cs.c b/drivers/isdn/hisax/avma1_cs.c
index 9e70c206779..fc6cc2c065b 100644
--- a/drivers/isdn/hisax/avma1_cs.c
+++ b/drivers/isdn/hisax/avma1_cs.c
@@ -14,7 +14,6 @@
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/sched.h>
#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/string.h>
diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c
index 17ec0b70ba1..da4196f21e0 100644
--- a/drivers/isdn/hisax/config.c
+++ b/drivers/isdn/hisax/config.c
@@ -549,10 +549,6 @@ extern int setup_isurf(struct IsdnCard *card);
extern int setup_saphir(struct IsdnCard *card);
#endif
-#if CARD_TESTEMU
-extern int setup_testemu(struct IsdnCard *card);
-#endif
-
#if CARD_BKM_A4T
extern int setup_bkm_a4t(struct IsdnCard *card);
#endif
@@ -1061,11 +1057,6 @@ static int checkcard(int cardnr, char *id, int *busy_flag, struct module *lockow
ret = setup_saphir(card);
break;
#endif
-#if CARD_TESTEMU
- case ISDN_CTYPE_TESTEMU:
- ret = setup_testemu(card);
- break;
-#endif
#if CARD_BKM_A4T
case ISDN_CTYPE_BKM_A4T:
ret = setup_bkm_a4t(card);
@@ -1881,7 +1872,7 @@ static struct pci_device_id hisax_pci_tbl[] __devinitdata = {
{PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_DJINN_ITOO, PCI_ANY_ID, PCI_ANY_ID},
{PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_OLITEC, PCI_ANY_ID, PCI_ANY_ID},
#endif
-#ifdef CONFIG_HISAX_QUADRO
+#ifdef CONFIG_HISAX_SCT_QUADRO
{PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_ANY_ID, PCI_ANY_ID},
#endif
#ifdef CONFIG_HISAX_NICCY
diff --git a/drivers/isdn/hisax/elsa_cs.c b/drivers/isdn/hisax/elsa_cs.c
index 79ab9dda7d0..db7e64424af 100644
--- a/drivers/isdn/hisax/elsa_cs.c
+++ b/drivers/isdn/hisax/elsa_cs.c
@@ -38,7 +38,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/sched.h>
#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/string.h>
diff --git a/drivers/isdn/hisax/elsa_ser.c b/drivers/isdn/hisax/elsa_ser.c
index 0279fb323cb..ae377e81277 100644
--- a/drivers/isdn/hisax/elsa_ser.c
+++ b/drivers/isdn/hisax/elsa_ser.c
@@ -58,7 +58,7 @@ static inline unsigned int serial_in(struct IsdnCardState *cs, int offset)
static inline unsigned int serial_inp(struct IsdnCardState *cs, int offset)
{
#ifdef SERIAL_DEBUG_REG
-#ifdef CONFIG_SERIAL_NOPAUSE_IO
+#ifdef ELSA_SERIAL_NOPAUSE_IO
u_int val = inb(cs->hw.elsa.base + 8 + offset);
debugl1(cs,"inp %s %02x",ModemIn[offset], val);
#else
@@ -67,7 +67,7 @@ static inline unsigned int serial_inp(struct IsdnCardState *cs, int offset)
#endif
return(val);
#else
-#ifdef CONFIG_SERIAL_NOPAUSE_IO
+#ifdef ELSA_SERIAL_NOPAUSE_IO
return inb(cs->hw.elsa.base + 8 + offset);
#else
return inb_p(cs->hw.elsa.base + 8 + offset);
@@ -87,13 +87,13 @@ static inline void serial_outp(struct IsdnCardState *cs, int offset,
int value)
{
#ifdef SERIAL_DEBUG_REG
-#ifdef CONFIG_SERIAL_NOPAUSE_IO
+#ifdef ELSA_SERIAL_NOPAUSE_IO
debugl1(cs,"outp %s %02x",ModemOut[offset], value);
#else
debugl1(cs,"outP %s %02x",ModemOut[offset], value);
#endif
#endif
-#ifdef CONFIG_SERIAL_NOPAUSE_IO
+#ifdef ELSA_SERIAL_NOPAUSE_IO
outb(value, cs->hw.elsa.base + 8 + offset);
#else
outb_p(value, cs->hw.elsa.base + 8 + offset);
diff --git a/drivers/isdn/hisax/hfc4s8s_l1.c b/drivers/isdn/hisax/hfc4s8s_l1.c
index a2fa4ecb8c8..ab98e135bcb 100644
--- a/drivers/isdn/hisax/hfc4s8s_l1.c
+++ b/drivers/isdn/hisax/hfc4s8s_l1.c
@@ -199,7 +199,7 @@ typedef struct _hfc4s8s_hw {
/***************************/
/* inline function defines */
/***************************/
-#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM /* inline functions mempry mapped */
+#ifdef HISAX_HFC4S8S_PCIMEM /* inline functions memory mapped */
/* memory write and dummy IO read to avoid PCI byte merge problems */
#define Write_hfc8(a,b,c) {(*((volatile u_char *)(a->membase+b)) = c); inb(a->iobase+4);}
@@ -305,7 +305,7 @@ wait_busy(hfc4s8s_hw * a)
#define PCI_ENA_REGIO 0x01
-#endif /* CONFIG_HISAX_HFC4S8S_PCIMEM */
+#endif /* HISAX_HFC4S8S_PCIMEM */
/******************************************************/
/* function to read critical counter registers that */
@@ -724,12 +724,12 @@ rx_d_frame(struct hfc4s8s_l1 *l1p, int ech)
} else {
/* read errornous D frame */
-#ifndef CONFIG_HISAX_HFC4S8S_PCIMEM
+#ifndef HISAX_HFC4S8S_PCIMEM
SetRegAddr(l1p->hw, A_FIFO_DATA0);
#endif
while (z1 >= 4) {
-#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM
+#ifdef HISAX_HFC4S8S_PCIMEM
Read_hfc32(l1p->hw, A_FIFO_DATA0);
#else
fRead_hfc32(l1p->hw);
@@ -738,7 +738,7 @@ rx_d_frame(struct hfc4s8s_l1 *l1p, int ech)
}
while (z1--)
-#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM
+#ifdef HISAX_HFC4S8S_PCIMEM
Read_hfc8(l1p->hw, A_FIFO_DATA0);
#else
fRead_hfc8(l1p->hw);
@@ -752,12 +752,12 @@ rx_d_frame(struct hfc4s8s_l1 *l1p, int ech)
cp = skb->data;
-#ifndef CONFIG_HISAX_HFC4S8S_PCIMEM
+#ifndef HISAX_HFC4S8S_PCIMEM
SetRegAddr(l1p->hw, A_FIFO_DATA0);
#endif
while (z1 >= 4) {
-#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM
+#ifdef HISAX_HFC4S8S_PCIMEM
*((unsigned long *) cp) =
Read_hfc32(l1p->hw, A_FIFO_DATA0);
#else
@@ -768,7 +768,7 @@ rx_d_frame(struct hfc4s8s_l1 *l1p, int ech)
}
while (z1--)
-#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM
+#ifdef HISAX_HFC4S8S_PCIMEM
*cp++ = Read_hfc8(l1p->hw, A_FIFO_DATA0);
#else
*cp++ = fRead_hfc8(l1p->hw);
@@ -858,12 +858,12 @@ rx_b_frame(struct hfc4s8s_btype *bch)
wait_busy(l1->hw);
return;
}
-#ifndef CONFIG_HISAX_HFC4S8S_PCIMEM
+#ifndef HISAX_HFC4S8S_PCIMEM
SetRegAddr(l1->hw, A_FIFO_DATA0);
#endif
while (z1 >= 4) {
-#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM
+#ifdef HISAX_HFC4S8S_PCIMEM
*((unsigned long *) bch->rx_ptr) =
Read_hfc32(l1->hw, A_FIFO_DATA0);
#else
@@ -875,7 +875,7 @@ rx_b_frame(struct hfc4s8s_btype *bch)
}
while (z1--)
-#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM
+#ifdef HISAX_HFC4S8S_PCIMEM
*(bch->rx_ptr++) = Read_hfc8(l1->hw, A_FIFO_DATA0);
#else
*(bch->rx_ptr++) = fRead_hfc8(l1->hw);
@@ -939,12 +939,12 @@ tx_d_frame(struct hfc4s8s_l1 *l1p)
if ((skb = skb_dequeue(&l1p->d_tx_queue))) {
cp = skb->data;
cnt = skb->len;
-#ifndef CONFIG_HISAX_HFC4S8S_PCIMEM
+#ifndef HISAX_HFC4S8S_PCIMEM
SetRegAddr(l1p->hw, A_FIFO_DATA0);
#endif
while (cnt >= 4) {
-#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM
+#ifdef HISAX_HFC4S8S_PCIMEM
fWrite_hfc32(l1p->hw, A_FIFO_DATA0,
*(unsigned long *) cp);
#else
@@ -955,7 +955,7 @@ tx_d_frame(struct hfc4s8s_l1 *l1p)
cnt -= 4;
}
-#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM
+#ifdef HISAX_HFC4S8S_PCIMEM
while (cnt--)
fWrite_hfc8(l1p->hw, A_FIFO_DATA0, *cp++);
#else
@@ -1036,11 +1036,11 @@ tx_b_frame(struct hfc4s8s_btype *bch)
cp = skb->data + bch->tx_cnt;
bch->tx_cnt += cnt;
-#ifndef CONFIG_HISAX_HFC4S8S_PCIMEM
+#ifndef HISAX_HFC4S8S_PCIMEM
SetRegAddr(l1->hw, A_FIFO_DATA0);
#endif
while (cnt >= 4) {
-#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM
+#ifdef HISAX_HFC4S8S_PCIMEM
fWrite_hfc32(l1->hw, A_FIFO_DATA0,
*(unsigned long *) cp);
#else
@@ -1051,7 +1051,7 @@ tx_b_frame(struct hfc4s8s_btype *bch)
}
while (cnt--)
-#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM
+#ifdef HISAX_HFC4S8S_PCIMEM
fWrite_hfc8(l1->hw, A_FIFO_DATA0, *cp++);
#else
fWrite_hfc8(l1->hw, *cp++);
@@ -1280,7 +1280,7 @@ hfc4s8s_interrupt(int intno, void *dev_id)
if (!hw || !(hw->mr.r_irq_ctrl & M_GLOB_IRQ_EN))
return IRQ_NONE;
-#ifndef CONFIG_HISAX_HFC4S8S_PCIMEM
+#ifndef HISAX_HFC4S8S_PCIMEM
/* read current selected regsister */
old_ioreg = GetRegAddr(hw);
#endif
@@ -1291,7 +1291,7 @@ hfc4s8s_interrupt(int intno, void *dev_id)
if (!
(b = (Read_hfc8(hw, R_STATUS) & (M_MISC_IRQSTA | M_FR_IRQSTA)))
&& !hw->mr.r_irq_statech) {
-#ifndef CONFIG_HISAX_HFC4S8S_PCIMEM
+#ifndef HISAX_HFC4S8S_PCIMEM
SetRegAddr(hw, old_ioreg);
#endif
return IRQ_NONE;
@@ -1321,7 +1321,7 @@ hfc4s8s_interrupt(int intno, void *dev_id)
/* queue the request to allow other cards to interrupt */
schedule_work(&hw->tqueue);
-#ifndef CONFIG_HISAX_HFC4S8S_PCIMEM
+#ifndef HISAX_HFC4S8S_PCIMEM
SetRegAddr(hw, old_ioreg);
#endif
return IRQ_HANDLED;
@@ -1470,7 +1470,7 @@ static void
release_pci_ports(hfc4s8s_hw * hw)
{
pci_write_config_word(hw->pdev, PCI_COMMAND, 0);
-#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM
+#ifdef HISAX_HFC4S8S_PCIMEM
if (hw->membase)
iounmap((void *) hw->membase);
#else
@@ -1485,7 +1485,7 @@ release_pci_ports(hfc4s8s_hw * hw)
static void
enable_pci_ports(hfc4s8s_hw * hw)
{
-#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM
+#ifdef HISAX_HFC4S8S_PCIMEM
pci_write_config_word(hw->pdev, PCI_COMMAND, PCI_ENA_MEMIO);
#else
pci_write_config_word(hw->pdev, PCI_COMMAND, PCI_ENA_REGIO);
@@ -1560,7 +1560,7 @@ setup_instance(hfc4s8s_hw * hw)
hw->irq);
goto out;
}
-#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM
+#ifdef HISAX_HFC4S8S_PCIMEM
printk(KERN_INFO
"HFC-4S/8S: found PCI card at membase 0x%p, irq %d\n",
hw->hw_membase, hw->irq);
@@ -1613,7 +1613,7 @@ hfc4s8s_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
hw->irq = pdev->irq;
hw->iobase = pci_resource_start(pdev, 0);
-#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM
+#ifdef HISAX_HFC4S8S_PCIMEM
hw->hw_membase = (u_char *) pci_resource_start(pdev, 1);
hw->membase = ioremap((ulong) hw->hw_membase, 256);
#else
diff --git a/drivers/isdn/hisax/hfc_usb.c b/drivers/isdn/hisax/hfc_usb.c
index 5a6989f23fc..9f44d3e69fb 100644
--- a/drivers/isdn/hisax/hfc_usb.c
+++ b/drivers/isdn/hisax/hfc_usb.c
@@ -38,7 +38,6 @@
#include <linux/usb.h>
#include <linux/kernel.h>
#include <linux/smp_lock.h>
-#include <linux/sched.h>
#include "hisax.h"
#include "hisax_if.h"
#include "hfc_usb.h"
@@ -183,7 +182,7 @@ typedef struct hfcusb_data {
int vend_idx; /* vendor found */
int b_mode[2]; /* B-channel mode */
int l1_activated; /* layer 1 activated */
- int disc_flag; /* TRUE if device was disonnected to avoid some USB actions */
+ int disc_flag; /* 'true' if device was disonnected to avoid some USB actions */
int packet_size, iso_packet_size;
/* control pipe background handling */
@@ -392,7 +391,7 @@ l1_timer_expire_t3(hfcusb_data * hfc)
DBG(ISDN_DBG,
"HFC-S USB: PH_DEACTIVATE | INDICATION sent (T3 expire)");
#endif
- hfc->l1_activated = FALSE;
+ hfc->l1_activated = false;
handle_led(hfc, LED_S0_OFF);
/* deactivate : */
queue_control_request(hfc, HFCUSB_STATES, 0x10, 1);
@@ -411,7 +410,7 @@ l1_timer_expire_t4(hfcusb_data * hfc)
DBG(ISDN_DBG,
"HFC-S USB: PH_DEACTIVATE | INDICATION sent (T4 expire)");
#endif
- hfc->l1_activated = FALSE;
+ hfc->l1_activated = false;
handle_led(hfc, LED_S0_OFF);
}
@@ -452,7 +451,7 @@ state_handler(hfcusb_data * hfc, __u8 state)
#ifdef CONFIG_HISAX_DEBUG
DBG(ISDN_DBG, "HFC-S USB: PH_ACTIVATE | INDICATION sent");
#endif
- hfc->l1_activated = TRUE;
+ hfc->l1_activated = true;
handle_led(hfc, LED_S0_ON);
} else if (state <= 3 /* && activated */ ) {
if (old_state == 7 || old_state == 8) {
@@ -472,7 +471,7 @@ state_handler(hfcusb_data * hfc, __u8 state)
DBG(ISDN_DBG,
"HFC-S USB: PH_DEACTIVATE | INDICATION sent");
#endif
- hfc->l1_activated = FALSE;
+ hfc->l1_activated = false;
handle_led(hfc, LED_S0_OFF);
}
}
@@ -622,7 +621,7 @@ tx_iso_complete(struct urb *urb)
if (fifo->active && !status) {
transp_mode = 0;
if (fifon < 4 && hfc->b_mode[fifon / 2] == L1_MODE_TRANS)
- transp_mode = TRUE;
+ transp_mode = true;
/* is FifoFull-threshold set for our channel? */
threshbit = threshtable[fifon] & hfc->threshold_mask;
@@ -640,7 +639,7 @@ tx_iso_complete(struct urb *urb)
tx_iso_complete, urb->context);
memset(context_iso_urb->buffer, 0,
sizeof(context_iso_urb->buffer));
- frame_complete = FALSE;
+ frame_complete = false;
/* Generate next Iso Packets */
for (k = 0; k < num_isoc_packets; ++k) {
if (fifo->skbuff) {
@@ -666,7 +665,7 @@ tx_iso_complete(struct urb *urb)
/* add 2 byte flags and 16bit CRC at end of ISDN frame */
fifo->bit_line += 32;
}
- frame_complete = TRUE;
+ frame_complete = true;
}
memcpy(context_iso_urb->buffer +
@@ -693,7 +692,7 @@ tx_iso_complete(struct urb *urb)
}
if (frame_complete) {
- fifo->delete_flg = TRUE;
+ fifo->delete_flg = true;
fifo->hif->l1l2(fifo->hif,
PH_DATA | CONFIRM,
(void *) (unsigned long) fifo->skbuff->
@@ -701,9 +700,9 @@ tx_iso_complete(struct urb *urb)
if (fifo->skbuff && fifo->delete_flg) {
dev_kfree_skb_any(fifo->skbuff);
fifo->skbuff = NULL;
- fifo->delete_flg = FALSE;
+ fifo->delete_flg = false;
}
- frame_complete = FALSE;
+ frame_complete = false;
}
}
errcode = usb_submit_urb(urb, GFP_ATOMIC);
@@ -837,7 +836,7 @@ collect_rx_frame(usb_fifo * fifo, __u8 * data, int len, int finish)
fifon = fifo->fifonum;
transp_mode = 0;
if (fifon < 4 && hfc->b_mode[fifon / 2] == L1_MODE_TRANS)
- transp_mode = TRUE;
+ transp_mode = true;
if (!fifo->skbuff) {
fifo->skbuff = dev_alloc_skb(fifo->max_size + 3);
@@ -1176,7 +1175,7 @@ hfc_usb_l2l1(struct hisax_if *my_hisax_if, int pr, void *arg)
if (fifo->skbuff && fifo->delete_flg) {
dev_kfree_skb_any(fifo->skbuff);
fifo->skbuff = NULL;
- fifo->delete_flg = FALSE;
+ fifo->delete_flg = false;
}
fifo->skbuff = arg; /* we have a new buffer */
break;
@@ -1262,8 +1261,8 @@ usb_init(hfcusb_data * hfc)
hfc->b_mode[0] = L1_MODE_NULL;
hfc->b_mode[1] = L1_MODE_NULL;
- hfc->l1_activated = FALSE;
- hfc->disc_flag = FALSE;
+ hfc->l1_activated = false;
+ hfc->disc_flag = false;
hfc->led_state = 0;
hfc->led_new_data = 0;
hfc->old_led_state = 0;
@@ -1404,7 +1403,7 @@ hfc_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
/* check for config EOL element */
while (validconf[cfg_used][0]) {
- cfg_found = TRUE;
+ cfg_found = true;
vcf = validconf[cfg_used];
/* first endpoint descriptor */
ep = iface->endpoint;
@@ -1426,7 +1425,7 @@ hfc_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
idx++;
attr = ep->desc.bmAttributes;
if (cmptbl[idx] == EP_NUL) {
- cfg_found = FALSE;
+ cfg_found = false;
}
if (attr == USB_ENDPOINT_XFER_INT
&& cmptbl[idx] == EP_INT)
@@ -1448,7 +1447,7 @@ hfc_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
"HFC-S USB: Interrupt Endpoint interval < %d found - skipping config",
vcf[17]);
#endif
- cfg_found = FALSE;
+ cfg_found = false;
}
ep++;
}
@@ -1456,7 +1455,7 @@ hfc_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
/* all entries must be EP_NOP or EP_NUL for a valid config */
if (cmptbl[i] != EP_NOP
&& cmptbl[i] != EP_NUL)
- cfg_found = FALSE;
+ cfg_found = false;
}
if (cfg_found) {
if (cfg_used < small_match) {
@@ -1656,7 +1655,7 @@ hfc_usb_disconnect(struct usb_interface
hfcusb_data *context = usb_get_intfdata(intf);
int i;
printk(KERN_INFO "HFC-S USB: device disconnect\n");
- context->disc_flag = TRUE;
+ context->disc_flag = true;
usb_set_intfdata(intf, NULL);
if (!context)
return;
diff --git a/drivers/isdn/hisax/hfc_usb.h b/drivers/isdn/hisax/hfc_usb.h
index 6349367ed48..471f2354dfd 100644
--- a/drivers/isdn/hisax/hfc_usb.h
+++ b/drivers/isdn/hisax/hfc_usb.h
@@ -12,9 +12,6 @@
#define VERBOSE_USB_DEBUG
-#define TRUE 1
-#define FALSE 0
-
/***********/
/* defines */
diff --git a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h
index 3f1137e3467..3cd8d5ba239 100644
--- a/drivers/isdn/hisax/hisax.h
+++ b/drivers/isdn/hisax/hisax.h
@@ -795,19 +795,6 @@ struct w6692_hw {
struct timer_list timer;
};
-#ifdef CONFIG_HISAX_TESTEMU
-struct te_hw {
- unsigned char *sfifo;
- unsigned char *sfifo_w;
- unsigned char *sfifo_r;
- unsigned char *sfifo_e;
- int sfifo_cnt;
- unsigned int stat;
- wait_queue_head_t rwaitq;
- wait_queue_head_t swaitq;
-};
-#endif
-
struct arcofi_msg {
struct arcofi_msg *next;
u_char receive;
@@ -916,9 +903,6 @@ struct IsdnCardState {
struct ix1_hw niccy;
struct isurf_hw isurf;
struct saphir_hw saphir;
-#ifdef CONFIG_HISAX_TESTEMU
- struct te_hw te;
-#endif
struct bkm_hw ax;
struct gazel_hw gazel;
struct w6692_hw w6692;
@@ -1175,15 +1159,6 @@ struct IsdnCardState {
#define CARD_HSTSAPHIR 0
#endif
-#ifdef CONFIG_HISAX_TESTEMU
-#define CARD_TESTEMU 1
-#define ISDN_CTYPE_TESTEMU 99
-#undef ISDN_CTYPE_COUNT
-#define ISDN_CTYPE_COUNT ISDN_CTYPE_TESTEMU
-#else
-#define CARD_TESTEMU 0
-#endif
-
#ifdef CONFIG_HISAX_BKM_A4T
#define CARD_BKM_A4T 1
#ifndef ISDN_CHIP_ISAC
diff --git a/drivers/isdn/hisax/isar.c b/drivers/isdn/hisax/isar.c
index 6f1a6583b17..9df9e3548cf 100644
--- a/drivers/isdn/hisax/isar.c
+++ b/drivers/isdn/hisax/isar.c
@@ -431,7 +431,6 @@ reterror:
return(ret);
}
-extern void BChannel_bh(struct BCState *);
#define B_LL_NOCARRIER 8
#define B_LL_CONNECT 9
#define B_LL_OK 10
diff --git a/drivers/isdn/hisax/isdnl1.h b/drivers/isdn/hisax/isdnl1.h
index 0e88cfabdf1..172ad4c8c96 100644
--- a/drivers/isdn/hisax/isdnl1.h
+++ b/drivers/isdn/hisax/isdnl1.h
@@ -21,12 +21,11 @@
#define B_XMTBUFREADY 1
#define B_ACKPENDING 2
-extern void debugl1(struct IsdnCardState *cs, char *fmt, ...);
-extern void DChannel_proc_xmt(struct IsdnCardState *cs);
-extern void DChannel_proc_rcv(struct IsdnCardState *cs);
-extern void l1_msg(struct IsdnCardState *cs, int pr, void *arg);
-extern void l1_msg_b(struct PStack *st, int pr, void *arg);
-
-#ifdef L2FRAME_DEBUG
-extern void Logl2Frame(struct IsdnCardState *cs, struct sk_buff *skb, char *buf, int dir);
-#endif
+void debugl1(struct IsdnCardState *cs, char *fmt, ...);
+void DChannel_proc_xmt(struct IsdnCardState *cs);
+void DChannel_proc_rcv(struct IsdnCardState *cs);
+void l1_msg(struct IsdnCardState *cs, int pr, void *arg);
+void l1_msg_b(struct PStack *st, int pr, void *arg);
+void Logl2Frame(struct IsdnCardState *cs, struct sk_buff *skb, char *buf,
+ int dir);
+void BChannel_bh(struct work_struct *work);
diff --git a/drivers/isdn/hisax/isdnl3.c b/drivers/isdn/hisax/isdnl3.c
index 281fa27d9f0..935f23356fa 100644
--- a/drivers/isdn/hisax/isdnl3.c
+++ b/drivers/isdn/hisax/isdnl3.c
@@ -231,18 +231,6 @@ no_l3_proto_spec(struct PStack *st, isdn_ctrl *ic)
return(-1);
}
-#ifdef CONFIG_HISAX_EURO
-extern void setstack_dss1(struct PStack *st);
-#endif
-
-#ifdef CONFIG_HISAX_NI1
-extern void setstack_ni1(struct PStack *st);
-#endif
-
-#ifdef CONFIG_HISAX_1TR6
-extern void setstack_1tr6(struct PStack *st);
-#endif
-
struct l3_process
*getl3proc(struct PStack *st, int cr)
{
diff --git a/drivers/isdn/hisax/isdnl3.h b/drivers/isdn/hisax/isdnl3.h
index 1dbe0297a50..749498fe6c4 100644
--- a/drivers/isdn/hisax/isdnl3.h
+++ b/drivers/isdn/hisax/isdnl3.h
@@ -25,13 +25,19 @@ struct stateentry {
#define l3_debug(st, fmt, args...) HiSax_putstatus(st->l1.hardware, "l3 ", fmt, ## args)
-extern void newl3state(struct l3_process *pc, int state);
-extern void L3InitTimer(struct l3_process *pc, struct L3Timer *t);
-extern void L3DelTimer(struct L3Timer *t);
-extern int L3AddTimer(struct L3Timer *t, int millisec, int event);
-extern void StopAllL3Timer(struct l3_process *pc);
-extern struct sk_buff *l3_alloc_skb(int len);
-extern struct l3_process *new_l3_process(struct PStack *st, int cr);
-extern void release_l3_process(struct l3_process *p);
-extern struct l3_process *getl3proc(struct PStack *st, int cr);
-extern void l3_msg(struct PStack *st, int pr, void *arg);
+struct PStack;
+
+void newl3state(struct l3_process *pc, int state);
+void L3InitTimer(struct l3_process *pc, struct L3Timer *t);
+void L3DelTimer(struct L3Timer *t);
+int L3AddTimer(struct L3Timer *t, int millisec, int event);
+void StopAllL3Timer(struct l3_process *pc);
+struct sk_buff *l3_alloc_skb(int len);
+struct l3_process *new_l3_process(struct PStack *st, int cr);
+void release_l3_process(struct l3_process *p);
+struct l3_process *getl3proc(struct PStack *st, int cr);
+void l3_msg(struct PStack *st, int pr, void *arg);
+void setstack_dss1(struct PStack *st);
+void setstack_ni1(struct PStack *st);
+void setstack_1tr6(struct PStack *st);
+
diff --git a/drivers/isdn/hisax/sedlbauer_cs.c b/drivers/isdn/hisax/sedlbauer_cs.c
index 45debde05fb..439cb530def 100644
--- a/drivers/isdn/hisax/sedlbauer_cs.c
+++ b/drivers/isdn/hisax/sedlbauer_cs.c
@@ -38,7 +38,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/sched.h>
#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/string.h>
diff --git a/drivers/isdn/hisax/teles_cs.c b/drivers/isdn/hisax/teles_cs.c
index 3e3e18239ec..ab4bd455450 100644
--- a/drivers/isdn/hisax/teles_cs.c
+++ b/drivers/isdn/hisax/teles_cs.c
@@ -19,7 +19,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/sched.h>
#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/string.h>
diff --git a/drivers/isdn/hysdn/boardergo.c b/drivers/isdn/hysdn/boardergo.c
index a1206498a1c..84dccd526ac 100644
--- a/drivers/isdn/hysdn/boardergo.c
+++ b/drivers/isdn/hysdn/boardergo.c
@@ -14,7 +14,6 @@
*
*/
-#include <linux/sched.h>
#include <linux/signal.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
diff --git a/drivers/isdn/hysdn/hysdn_procconf.c b/drivers/isdn/hysdn/hysdn_procconf.c
index 94a93508911..dc477e0aab0 100644
--- a/drivers/isdn/hysdn/hysdn_procconf.c
+++ b/drivers/isdn/hysdn/hysdn_procconf.c
@@ -367,7 +367,7 @@ hysdn_conf_close(struct inode *ino, struct file *filep)
/******************************************************/
/* table for conf filesystem functions defined above. */
/******************************************************/
-static struct file_operations conf_fops =
+static const struct file_operations conf_fops =
{
.llseek = no_llseek,
.read = hysdn_conf_read,
diff --git a/drivers/isdn/hysdn/hysdn_proclog.c b/drivers/isdn/hysdn/hysdn_proclog.c
index 375d956884d..f7e83a86f44 100644
--- a/drivers/isdn/hysdn/hysdn_proclog.c
+++ b/drivers/isdn/hysdn/hysdn_proclog.c
@@ -383,7 +383,7 @@ hysdn_log_poll(struct file *file, poll_table * wait)
/**************************************************/
/* table for log filesystem functions defined above. */
/**************************************************/
-static struct file_operations log_fops =
+static const struct file_operations log_fops =
{
.llseek = no_llseek,
.read = hysdn_log_read,
diff --git a/drivers/isdn/hysdn/hysdn_sched.c b/drivers/isdn/hysdn/hysdn_sched.c
index 18758772b74..b7b5aa4748a 100644
--- a/drivers/isdn/hysdn/hysdn_sched.c
+++ b/drivers/isdn/hysdn/hysdn_sched.c
@@ -11,7 +11,6 @@
*
*/
-#include <linux/sched.h>
#include <linux/signal.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
diff --git a/drivers/isdn/i4l/isdn_bsdcomp.c b/drivers/isdn/i4l/isdn_bsdcomp.c
index a20f33b4a22..90a23795db7 100644
--- a/drivers/isdn/i4l/isdn_bsdcomp.c
+++ b/drivers/isdn/i4l/isdn_bsdcomp.c
@@ -56,7 +56,6 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/interrupt.h>
diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c
index 6a2ef0a87ed..9c926e41b11 100644
--- a/drivers/isdn/i4l/isdn_common.c
+++ b/drivers/isdn/i4l/isdn_common.c
@@ -1822,7 +1822,7 @@ isdn_close(struct inode *ino, struct file *filep)
return 0;
}
-static struct file_operations isdn_fops =
+static const struct file_operations isdn_fops =
{
.owner = THIS_MODULE,
.llseek = no_llseek,
diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c
index 4e3f127e400..1b2df80c3bc 100644
--- a/drivers/isdn/i4l/isdn_ppp.c
+++ b/drivers/isdn/i4l/isdn_ppp.c
@@ -1680,7 +1680,7 @@ static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp,
* - we hit a gap in the sequence, so no reassembly/processing is
* possible ('start' would be set to NULL)
*
- * algorightm for this code is derived from code in the book
+ * algorithm for this code is derived from code in the book
* 'PPP Design And Debugging' by James Carlson (Addison-Wesley)
*/
while (start != NULL || newfrag != NULL) {
diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c
index fc80afe555b..ea5f30d4a5a 100644
--- a/drivers/isdn/i4l/isdn_tty.c
+++ b/drivers/isdn/i4l/isdn_tty.c
@@ -1261,7 +1261,6 @@ isdn_tty_flush_buffer(struct tty_struct *tty)
}
isdn_tty_cleanup_xmit(info);
info->xmit_count = 0;
- wake_up_interruptible(&tty->write_wait);
tty_wakeup(tty);
}
diff --git a/drivers/isdn/pcbit/callbacks.c b/drivers/isdn/pcbit/callbacks.c
index f151f36c825..43ecd0f5423 100644
--- a/drivers/isdn/pcbit/callbacks.c
+++ b/drivers/isdn/pcbit/callbacks.c
@@ -15,7 +15,6 @@
* NULL pointer dereference in cb_in_1 (originally fixed in 2.0)
*/
-#include <linux/sched.h>
#include <linux/string.h>
#include <linux/kernel.h>
diff --git a/drivers/isdn/pcbit/capi.c b/drivers/isdn/pcbit/capi.c
index bef321d0e51..47c59e95898 100644
--- a/drivers/isdn/pcbit/capi.c
+++ b/drivers/isdn/pcbit/capi.c
@@ -27,7 +27,6 @@
* encode our number in CallerPN and ConnectedPN
*/
-#include <linux/sched.h>
#include <linux/string.h>
#include <linux/kernel.h>
diff --git a/drivers/isdn/pcbit/drv.c b/drivers/isdn/pcbit/drv.c
index 11c1b0b6e39..8c66bcb953a 100644
--- a/drivers/isdn/pcbit/drv.c
+++ b/drivers/isdn/pcbit/drv.c
@@ -19,7 +19,6 @@
#include <linux/module.h>
-#include <linux/sched.h>
#include <linux/kernel.h>
@@ -774,10 +773,6 @@ static void pcbit_logstat(struct pcbit_dev *dev, char *str)
dev->dev_if->statcallb(&ictl);
}
-extern char * isdn_state_table[];
-extern char * strisdnevent(unsigned short);
-
-
void pcbit_state_change(struct pcbit_dev * dev, struct pcbit_chan * chan,
unsigned short i, unsigned short ev, unsigned short f)
{
diff --git a/drivers/isdn/pcbit/edss1.c b/drivers/isdn/pcbit/edss1.c
index 93ca7de5670..37e9626cebf 100644
--- a/drivers/isdn/pcbit/edss1.c
+++ b/drivers/isdn/pcbit/edss1.c
@@ -15,7 +15,6 @@
* move state/event descriptions to a user space logger
*/
-#include <linux/sched.h>
#include <linux/string.h>
#include <linux/kernel.h>
@@ -35,12 +34,6 @@
#include "callbacks.h"
-extern void pcbit_state_change(struct pcbit_dev *, struct pcbit_chan *,
- unsigned short i, unsigned short ev,
- unsigned short f);
-
-extern struct pcbit_dev * dev_pcbit[MAX_PCBIT_CARDS];
-
char * isdn_state_table[] = {
"Closed",
"Call initiated",
diff --git a/drivers/isdn/pcbit/edss1.h b/drivers/isdn/pcbit/edss1.h
index 6bb587005b8..0b64f97015d 100644
--- a/drivers/isdn/pcbit/edss1.h
+++ b/drivers/isdn/pcbit/edss1.h
@@ -90,9 +90,12 @@ struct fsm_timer_entry {
unsigned long timeout; /* in seconds */
};
+extern char * isdn_state_table[];
+
+void pcbit_fsm_event(struct pcbit_dev *, struct pcbit_chan *,
+ unsigned short event, struct callb_data *);
+char * strisdnevent(ushort ev);
-extern void pcbit_fsm_event(struct pcbit_dev *, struct pcbit_chan *,
- unsigned short event, struct callb_data *);
#endif
diff --git a/drivers/isdn/pcbit/layer2.c b/drivers/isdn/pcbit/layer2.c
index eafcce5e656..5ba2a879df1 100644
--- a/drivers/isdn/pcbit/layer2.c
+++ b/drivers/isdn/pcbit/layer2.c
@@ -24,7 +24,6 @@
* re-write/remove debug printks
*/
-#include <linux/sched.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/types.h>
@@ -47,22 +46,6 @@
#undef DEBUG_FRAG
-
-/*
- * task queue struct
- */
-
-
-
-/*
- * Layer 3 packet demultiplexer
- * drv.c
- */
-
-extern void pcbit_l3_receive(struct pcbit_dev *dev, ulong msg,
- struct sk_buff *skb,
- ushort hdr_len, ushort refnum);
-
/*
* Prototypes
*/
diff --git a/drivers/isdn/pcbit/module.c b/drivers/isdn/pcbit/module.c
index 282073a35d6..04ea241ff17 100644
--- a/drivers/isdn/pcbit/module.c
+++ b/drivers/isdn/pcbit/module.c
@@ -11,7 +11,6 @@
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/sched.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
@@ -32,9 +31,6 @@ module_param_array(irq, int, NULL, 0);
static int num_boards;
struct pcbit_dev * dev_pcbit[MAX_PCBIT_CARDS];
-extern void pcbit_terminate(int board);
-extern int pcbit_init_dev(int board, int mem_base, int irq);
-
static int __init pcbit_init(void)
{
int board;
diff --git a/drivers/isdn/pcbit/pcbit.h b/drivers/isdn/pcbit/pcbit.h
index 19c18e88ff1..d76fffc88b8 100644
--- a/drivers/isdn/pcbit/pcbit.h
+++ b/drivers/isdn/pcbit/pcbit.h
@@ -166,6 +166,12 @@ struct pcbit_ioctl {
#define L2_RUNNING 5
#define L2_ERROR 6
-extern void pcbit_deliver(struct work_struct *work);
+void pcbit_deliver(struct work_struct *work);
+int pcbit_init_dev(int board, int mem_base, int irq);
+void pcbit_terminate(int board);
+void pcbit_l3_receive(struct pcbit_dev * dev, ulong msg, struct sk_buff * skb,
+ ushort hdr_len, ushort refnum);
+void pcbit_state_change(struct pcbit_dev * dev, struct pcbit_chan * chan,
+ unsigned short i, unsigned short ev, unsigned short f);
#endif
diff --git a/drivers/isdn/sc/card.h b/drivers/isdn/sc/card.h
index 8e44928cdf1..4fbfa825c3a 100644
--- a/drivers/isdn/sc/card.h
+++ b/drivers/isdn/sc/card.h
@@ -26,7 +26,9 @@
#include <linux/timer.h>
#include <linux/time.h>
#include <linux/isdnif.h>
+#include <linux/irqreturn.h>
#include "message.h"
+#include "scioc.h"
/*
* Amount of time to wait for a reset to complete
@@ -98,4 +100,32 @@ typedef struct {
spinlock_t lock; /* local lock */
} board;
+
+extern board *sc_adapter[];
+extern int cinst;
+
+void memcpy_toshmem(int card, void *dest, const void *src, size_t n);
+void memcpy_fromshmem(int card, void *dest, const void *src, size_t n);
+int get_card_from_id(int driver);
+int indicate_status(int card, int event, ulong Channel, char *Data);
+irqreturn_t interrupt_handler(int interrupt, void *cardptr);
+int sndpkt(int devId, int channel, struct sk_buff *data);
+void rcvpkt(int card, RspMessage *rcvmsg);
+int command(isdn_ctrl *cmd);
+int reset(int card);
+int startproc(int card);
+int send_and_receive(int card, unsigned int procid, unsigned char type,
+ unsigned char class, unsigned char code,
+ unsigned char link, unsigned char data_len,
+ unsigned char *data, RspMessage *mesgdata, int timeout);
+void flushreadfifo (int card);
+int sendmessage(int card, unsigned int procid, unsigned int type,
+ unsigned int class, unsigned int code, unsigned int link,
+ unsigned int data_len, unsigned int *data);
+int receivemessage(int card, RspMessage *rspmsg);
+int sc_ioctl(int card, scs_ioctl *data);
+int setup_buffers(int card, int c);
+void check_reset(unsigned long data);
+void check_phystat(unsigned long data);
+
#endif /* CARD_H */
diff --git a/drivers/isdn/sc/command.c b/drivers/isdn/sc/command.c
index 04b8a58f03b..b7bb7cbcf50 100644
--- a/drivers/isdn/sc/command.c
+++ b/drivers/isdn/sc/command.c
@@ -31,19 +31,6 @@ static int setl2(int card, unsigned long arg);
static int setl3(int card, unsigned long arg);
static int acceptb(int card, unsigned long channel);
-extern int cinst;
-extern board *sc_adapter[];
-
-extern int sc_ioctl(int, scs_ioctl *);
-extern int setup_buffers(int, int, unsigned int);
-extern int indicate_status(int, int,ulong,char*);
-extern void check_reset(unsigned long);
-extern int send_and_receive(int, unsigned int, unsigned char, unsigned char,
- unsigned char, unsigned char, unsigned char, unsigned char *,
- RspMessage *, int);
-extern int sendmessage(int, unsigned int, unsigned int, unsigned int,
- unsigned int, unsigned int, unsigned int, unsigned int *);
-
#ifdef DEBUG
/*
* Translate command codes to strings
@@ -208,7 +195,7 @@ static int answer(int card, unsigned long channel)
return -ENODEV;
}
- if(setup_buffers(card, channel+1, BUFFER_SIZE)) {
+ if(setup_buffers(card, channel+1)) {
hangup(card, channel+1);
return -ENOBUFS;
}
@@ -297,7 +284,7 @@ static int acceptb(int card, unsigned long channel)
return -ENODEV;
}
- if(setup_buffers(card, channel+1, BUFFER_SIZE))
+ if(setup_buffers(card, channel+1))
{
hangup(card, channel+1);
return -ENOBUFS;
diff --git a/drivers/isdn/sc/event.c b/drivers/isdn/sc/event.c
index 57367325ef0..498f4039ece 100644
--- a/drivers/isdn/sc/event.c
+++ b/drivers/isdn/sc/event.c
@@ -20,9 +20,6 @@
#include "message.h"
#include "card.h"
-extern int cinst;
-extern board *sc_adapter[];
-
#ifdef DEBUG
static char *events[] = { "ISDN_STAT_STAVAIL",
"ISDN_STAT_ICALL",
diff --git a/drivers/isdn/sc/init.c b/drivers/isdn/sc/init.c
index 150759a5cdd..0bf76344a0d 100644
--- a/drivers/isdn/sc/init.c
+++ b/drivers/isdn/sc/init.c
@@ -35,12 +35,6 @@ module_param_array(irq, int, NULL, 0);
module_param_array(ram, int, NULL, 0);
module_param(do_reset, bool, 0);
-extern irqreturn_t interrupt_handler(int, void *);
-extern int sndpkt(int, int, int, struct sk_buff *);
-extern int command(isdn_ctrl *);
-extern int indicate_status(int, int, ulong, char*);
-extern int reset(int);
-
static int identify_board(unsigned long, unsigned int);
static int __init sc_init(void)
diff --git a/drivers/isdn/sc/interrupt.c b/drivers/isdn/sc/interrupt.c
index cd17de18cb7..bef7963cdd0 100644
--- a/drivers/isdn/sc/interrupt.c
+++ b/drivers/isdn/sc/interrupt.c
@@ -21,16 +21,6 @@
#include "card.h"
#include <linux/interrupt.h>
-extern int indicate_status(int, int, ulong, char *);
-extern void check_phystat(unsigned long);
-extern int receivemessage(int, RspMessage *);
-extern int sendmessage(int, unsigned int, unsigned int, unsigned int,
- unsigned int, unsigned int, unsigned int, unsigned int *);
-extern void rcvpkt(int, RspMessage *);
-
-extern int cinst;
-extern board *sc_adapter[];
-
static int get_card_from_irq(int irq)
{
int i;
diff --git a/drivers/isdn/sc/ioctl.c b/drivers/isdn/sc/ioctl.c
index 57c4ab96d13..7817d224492 100644
--- a/drivers/isdn/sc/ioctl.c
+++ b/drivers/isdn/sc/ioctl.c
@@ -12,16 +12,6 @@
#include "card.h"
#include "scioc.h"
-extern int indicate_status(int, int, unsigned long, char *);
-extern int startproc(int);
-extern int reset(int);
-extern int send_and_receive(int, unsigned int, unsigned char,unsigned char,
- unsigned char,unsigned char,
- unsigned char, unsigned char *, RspMessage *, int);
-
-extern board *sc_adapter[];
-
-
static int GetStatus(int card, boardInfo *);
/*
diff --git a/drivers/isdn/sc/message.c b/drivers/isdn/sc/message.c
index 0a0fe6b8039..c5a307e3c49 100644
--- a/drivers/isdn/sc/message.c
+++ b/drivers/isdn/sc/message.c
@@ -22,16 +22,6 @@
#include "message.h"
#include "card.h"
-extern board *sc_adapter[];
-extern unsigned int cinst;
-
-/*
- * Obligatory function prototypes
- */
-extern int indicate_status(int,ulong,char*);
-extern int scm_command(isdn_ctrl *);
-
-
/*
* receive a message from the board
*/
diff --git a/drivers/isdn/sc/packet.c b/drivers/isdn/sc/packet.c
index 1e04676b016..92016a2608e 100644
--- a/drivers/isdn/sc/packet.c
+++ b/drivers/isdn/sc/packet.c
@@ -20,16 +20,6 @@
#include "message.h"
#include "card.h"
-extern board *sc_adapter[];
-extern unsigned int cinst;
-
-extern int get_card_from_id(int);
-extern int indicate_status(int, int,ulong, char*);
-extern void memcpy_toshmem(int, void *, const void *, size_t);
-extern void memcpy_fromshmem(int, void *, const void *, size_t);
-extern int sendmessage(int, unsigned int, unsigned int, unsigned int,
- unsigned int, unsigned int, unsigned int, unsigned int *);
-
int sndpkt(int devId, int channel, struct sk_buff *data)
{
LLData ReqLnkWrite;
diff --git a/drivers/isdn/sc/scioc.h b/drivers/isdn/sc/scioc.h
index d08e650c7b6..dfb107a6de4 100644
--- a/drivers/isdn/sc/scioc.h
+++ b/drivers/isdn/sc/scioc.h
@@ -1,3 +1,6 @@
+#ifndef __ISDN_SC_SCIOC_H__
+#define __ISDN_SC_SCIOC_H__
+
/*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
@@ -103,3 +106,6 @@ typedef struct {
POTInfo potsinfo;
} info;
} boardInfo;
+
+#endif /* __ISDN_SC_SCIOC_H__ */
+
diff --git a/drivers/isdn/sc/shmem.c b/drivers/isdn/sc/shmem.c
index 6f58862992d..034d41a61ae 100644
--- a/drivers/isdn/sc/shmem.c
+++ b/drivers/isdn/sc/shmem.c
@@ -22,12 +22,6 @@
#include "card.h"
/*
- * Main adapter array
- */
-extern board *sc_adapter[];
-extern int cinst;
-
-/*
*
*/
void memcpy_toshmem(int card, void *dest, const void *src, size_t n)
diff --git a/drivers/isdn/sc/timer.c b/drivers/isdn/sc/timer.c
index f43282be0ad..cc1b8861be2 100644
--- a/drivers/isdn/sc/timer.c
+++ b/drivers/isdn/sc/timer.c
@@ -20,14 +20,6 @@
#include "message.h"
#include "card.h"
-extern board *sc_adapter[];
-
-extern void flushreadfifo(int);
-extern int startproc(int);
-extern int indicate_status(int, int, unsigned long, char *);
-extern int sendmessage(int, unsigned int, unsigned int, unsigned int,
- unsigned int, unsigned int, unsigned int, unsigned int *);
-
/*
* Write the proper values into the I/O ports following a reset
diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h
index 2db1ca4c680..04574a9d443 100644
--- a/drivers/kvm/kvm.h
+++ b/drivers/kvm/kvm.h
@@ -304,6 +304,7 @@ struct kvm {
int memory_config_version;
int busy;
unsigned long rmap_overflow;
+ struct list_head vm_list;
};
struct kvm_stat {
@@ -340,6 +341,7 @@ struct kvm_arch_ops {
struct kvm_vcpu *(*vcpu_load)(struct kvm_vcpu *vcpu);
void (*vcpu_put)(struct kvm_vcpu *vcpu);
+ void (*vcpu_decache)(struct kvm_vcpu *vcpu);
int (*set_guest_debug)(struct kvm_vcpu *vcpu,
struct kvm_debug_guest *dbg);
@@ -558,7 +560,7 @@ static inline void load_gs(u16 sel)
#ifndef load_ldt
static inline void load_ldt(u16 sel)
{
- asm ("lldt %0" : : "g"(sel));
+ asm ("lldt %0" : : "rm"(sel));
}
#endif
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c
index b10972ed0c9..af866147ff2 100644
--- a/drivers/kvm/kvm_main.c
+++ b/drivers/kvm/kvm_main.c
@@ -34,6 +34,8 @@
#include <linux/highmem.h>
#include <linux/file.h>
#include <asm/desc.h>
+#include <linux/sysdev.h>
+#include <linux/cpu.h>
#include "x86_emulate.h"
#include "segment_descriptor.h"
@@ -41,6 +43,9 @@
MODULE_AUTHOR("Qumranet");
MODULE_LICENSE("GPL");
+static DEFINE_SPINLOCK(kvm_lock);
+static LIST_HEAD(vm_list);
+
struct kvm_arch_ops *kvm_arch_ops;
struct kvm_stat kvm_stat;
EXPORT_SYMBOL_GPL(kvm_stat);
@@ -62,7 +67,7 @@ static struct kvm_stats_debugfs_item {
{ "halt_exits", &kvm_stat.halt_exits },
{ "request_irq", &kvm_stat.request_irq_exits },
{ "irq_exits", &kvm_stat.irq_exits },
- { 0, 0 }
+ { NULL, NULL }
};
static struct dentry *debugfs_dir;
@@ -205,7 +210,7 @@ static struct kvm_vcpu *vcpu_load(struct kvm *kvm, int vcpu_slot)
mutex_lock(&vcpu->mutex);
if (unlikely(!vcpu->vmcs)) {
mutex_unlock(&vcpu->mutex);
- return 0;
+ return NULL;
}
return kvm_arch_ops->vcpu_load(vcpu);
}
@@ -230,9 +235,13 @@ static int kvm_dev_open(struct inode *inode, struct file *filp)
struct kvm_vcpu *vcpu = &kvm->vcpus[i];
mutex_init(&vcpu->mutex);
+ vcpu->cpu = -1;
vcpu->kvm = kvm;
vcpu->mmu.root_hpa = INVALID_PAGE;
INIT_LIST_HEAD(&vcpu->free_pages);
+ spin_lock(&kvm_lock);
+ list_add(&kvm->vm_list, &vm_list);
+ spin_unlock(&kvm_lock);
}
filp->private_data = kvm;
return 0;
@@ -257,9 +266,9 @@ static void kvm_free_physmem_slot(struct kvm_memory_slot *free,
if (!dont || free->dirty_bitmap != dont->dirty_bitmap)
vfree(free->dirty_bitmap);
- free->phys_mem = 0;
+ free->phys_mem = NULL;
free->npages = 0;
- free->dirty_bitmap = 0;
+ free->dirty_bitmap = NULL;
}
static void kvm_free_physmem(struct kvm *kvm)
@@ -267,12 +276,14 @@ static void kvm_free_physmem(struct kvm *kvm)
int i;
for (i = 0; i < kvm->nmemslots; ++i)
- kvm_free_physmem_slot(&kvm->memslots[i], 0);
+ kvm_free_physmem_slot(&kvm->memslots[i], NULL);
}
static void kvm_free_vcpu(struct kvm_vcpu *vcpu)
{
- vcpu_load(vcpu->kvm, vcpu_slot(vcpu));
+ if (!vcpu_load(vcpu->kvm, vcpu_slot(vcpu)))
+ return;
+
kvm_mmu_destroy(vcpu);
vcpu_put(vcpu);
kvm_arch_ops->vcpu_free(vcpu);
@@ -290,6 +301,9 @@ static int kvm_dev_release(struct inode *inode, struct file *filp)
{
struct kvm *kvm = filp->private_data;
+ spin_lock(&kvm_lock);
+ list_del(&kvm->vm_list);
+ spin_unlock(&kvm_lock);
kvm_free_vcpus(kvm);
kvm_free_physmem(kvm);
kfree(kvm);
@@ -544,7 +558,6 @@ static int kvm_dev_ioctl_create_vcpu(struct kvm *kvm, int n)
FX_IMAGE_ALIGN);
vcpu->guest_fx_image = vcpu->host_fx_image + FX_IMAGE_SIZE;
- vcpu->cpu = -1; /* First load will set up TR */
r = kvm_arch_ops->vcpu_create(vcpu);
if (r < 0)
goto out_free_vcpus;
@@ -640,11 +653,11 @@ raced:
/* Deallocate if slot is being removed */
if (!npages)
- new.phys_mem = 0;
+ new.phys_mem = NULL;
/* Free page dirty bitmap if unneeded */
if (!(new.flags & KVM_MEM_LOG_DIRTY_PAGES))
- new.dirty_bitmap = 0;
+ new.dirty_bitmap = NULL;
r = -ENOMEM;
@@ -799,14 +812,14 @@ struct kvm_memory_slot *gfn_to_memslot(struct kvm *kvm, gfn_t gfn)
&& gfn < memslot->base_gfn + memslot->npages)
return memslot;
}
- return 0;
+ return NULL;
}
EXPORT_SYMBOL_GPL(gfn_to_memslot);
void mark_page_dirty(struct kvm *kvm, gfn_t gfn)
{
int i;
- struct kvm_memory_slot *memslot = 0;
+ struct kvm_memory_slot *memslot = NULL;
unsigned long rel_gfn;
for (i = 0; i < kvm->nmemslots; ++i) {
@@ -1360,6 +1373,9 @@ static int kvm_dev_ioctl_run(struct kvm *kvm, struct kvm_run *kvm_run)
if (!vcpu)
return -ENOENT;
+ /* re-sync apic's tpr */
+ vcpu->cr8 = kvm_run->cr8;
+
if (kvm_run->emulated) {
kvm_arch_ops->skip_emulated_instruction(vcpu);
kvm_run->emulated = 0;
@@ -1778,6 +1794,7 @@ static long kvm_dev_ioctl(struct file *filp,
unsigned int ioctl, unsigned long arg)
{
struct kvm *kvm = filp->private_data;
+ void __user *argp = (void __user *)arg;
int r = -EINVAL;
switch (ioctl) {
@@ -1794,12 +1811,12 @@ static long kvm_dev_ioctl(struct file *filp,
struct kvm_run kvm_run;
r = -EFAULT;
- if (copy_from_user(&kvm_run, (void *)arg, sizeof kvm_run))
+ if (copy_from_user(&kvm_run, argp, sizeof kvm_run))
goto out;
r = kvm_dev_ioctl_run(kvm, &kvm_run);
if (r < 0 && r != -EINTR)
goto out;
- if (copy_to_user((void *)arg, &kvm_run, sizeof kvm_run)) {
+ if (copy_to_user(argp, &kvm_run, sizeof kvm_run)) {
r = -EFAULT;
goto out;
}
@@ -1809,13 +1826,13 @@ static long kvm_dev_ioctl(struct file *filp,
struct kvm_regs kvm_regs;
r = -EFAULT;
- if (copy_from_user(&kvm_regs, (void *)arg, sizeof kvm_regs))
+ if (copy_from_user(&kvm_regs, argp, sizeof kvm_regs))
goto out;
r = kvm_dev_ioctl_get_regs(kvm, &kvm_regs);
if (r)
goto out;
r = -EFAULT;
- if (copy_to_user((void *)arg, &kvm_regs, sizeof kvm_regs))
+ if (copy_to_user(argp, &kvm_regs, sizeof kvm_regs))
goto out;
r = 0;
break;
@@ -1824,7 +1841,7 @@ static long kvm_dev_ioctl(struct file *filp,
struct kvm_regs kvm_regs;
r = -EFAULT;
- if (copy_from_user(&kvm_regs, (void *)arg, sizeof kvm_regs))
+ if (copy_from_user(&kvm_regs, argp, sizeof kvm_regs))
goto out;
r = kvm_dev_ioctl_set_regs(kvm, &kvm_regs);
if (r)
@@ -1836,13 +1853,13 @@ static long kvm_dev_ioctl(struct file *filp,
struct kvm_sregs kvm_sregs;
r = -EFAULT;
- if (copy_from_user(&kvm_sregs, (void *)arg, sizeof kvm_sregs))
+ if (copy_from_user(&kvm_sregs, argp, sizeof kvm_sregs))
goto out;
r = kvm_dev_ioctl_get_sregs(kvm, &kvm_sregs);
if (r)
goto out;
r = -EFAULT;
- if (copy_to_user((void *)arg, &kvm_sregs, sizeof kvm_sregs))
+ if (copy_to_user(argp, &kvm_sregs, sizeof kvm_sregs))
goto out;
r = 0;
break;
@@ -1851,7 +1868,7 @@ static long kvm_dev_ioctl(struct file *filp,
struct kvm_sregs kvm_sregs;
r = -EFAULT;
- if (copy_from_user(&kvm_sregs, (void *)arg, sizeof kvm_sregs))
+ if (copy_from_user(&kvm_sregs, argp, sizeof kvm_sregs))
goto out;
r = kvm_dev_ioctl_set_sregs(kvm, &kvm_sregs);
if (r)
@@ -1863,13 +1880,13 @@ static long kvm_dev_ioctl(struct file *filp,
struct kvm_translation tr;
r = -EFAULT;
- if (copy_from_user(&tr, (void *)arg, sizeof tr))
+ if (copy_from_user(&tr, argp, sizeof tr))
goto out;
r = kvm_dev_ioctl_translate(kvm, &tr);
if (r)
goto out;
r = -EFAULT;
- if (copy_to_user((void *)arg, &tr, sizeof tr))
+ if (copy_to_user(argp, &tr, sizeof tr))
goto out;
r = 0;
break;
@@ -1878,7 +1895,7 @@ static long kvm_dev_ioctl(struct file *filp,
struct kvm_interrupt irq;
r = -EFAULT;
- if (copy_from_user(&irq, (void *)arg, sizeof irq))
+ if (copy_from_user(&irq, argp, sizeof irq))
goto out;
r = kvm_dev_ioctl_interrupt(kvm, &irq);
if (r)
@@ -1890,7 +1907,7 @@ static long kvm_dev_ioctl(struct file *filp,
struct kvm_debug_guest dbg;
r = -EFAULT;
- if (copy_from_user(&dbg, (void *)arg, sizeof dbg))
+ if (copy_from_user(&dbg, argp, sizeof dbg))
goto out;
r = kvm_dev_ioctl_debug_guest(kvm, &dbg);
if (r)
@@ -1902,7 +1919,7 @@ static long kvm_dev_ioctl(struct file *filp,
struct kvm_memory_region kvm_mem;
r = -EFAULT;
- if (copy_from_user(&kvm_mem, (void *)arg, sizeof kvm_mem))
+ if (copy_from_user(&kvm_mem, argp, sizeof kvm_mem))
goto out;
r = kvm_dev_ioctl_set_memory_region(kvm, &kvm_mem);
if (r)
@@ -1913,7 +1930,7 @@ static long kvm_dev_ioctl(struct file *filp,
struct kvm_dirty_log log;
r = -EFAULT;
- if (copy_from_user(&log, (void *)arg, sizeof log))
+ if (copy_from_user(&log, argp, sizeof log))
goto out;
r = kvm_dev_ioctl_get_dirty_log(kvm, &log);
if (r)
@@ -1921,13 +1938,13 @@ static long kvm_dev_ioctl(struct file *filp,
break;
}
case KVM_GET_MSRS:
- r = msr_io(kvm, (void __user *)arg, get_msr, 1);
+ r = msr_io(kvm, argp, get_msr, 1);
break;
case KVM_SET_MSRS:
- r = msr_io(kvm, (void __user *)arg, do_set_msr, 0);
+ r = msr_io(kvm, argp, do_set_msr, 0);
break;
case KVM_GET_MSR_INDEX_LIST: {
- struct kvm_msr_list __user *user_msr_list = (void __user *)arg;
+ struct kvm_msr_list __user *user_msr_list = argp;
struct kvm_msr_list msr_list;
unsigned n;
@@ -2014,7 +2031,7 @@ static int kvm_reboot(struct notifier_block *notifier, unsigned long val,
* in vmx root mode.
*/
printk(KERN_INFO "kvm: exiting hardware virtualization\n");
- on_each_cpu(kvm_arch_ops->hardware_disable, 0, 0, 1);
+ on_each_cpu(kvm_arch_ops->hardware_disable, NULL, 0, 1);
}
return NOTIFY_OK;
}
@@ -2024,11 +2041,69 @@ static struct notifier_block kvm_reboot_notifier = {
.priority = 0,
};
+/*
+ * Make sure that a cpu that is being hot-unplugged does not have any vcpus
+ * cached on it.
+ */
+static void decache_vcpus_on_cpu(int cpu)
+{
+ struct kvm *vm;
+ struct kvm_vcpu *vcpu;
+ int i;
+
+ spin_lock(&kvm_lock);
+ list_for_each_entry(vm, &vm_list, vm_list)
+ for (i = 0; i < KVM_MAX_VCPUS; ++i) {
+ vcpu = &vm->vcpus[i];
+ /*
+ * If the vcpu is locked, then it is running on some
+ * other cpu and therefore it is not cached on the
+ * cpu in question.
+ *
+ * If it's not locked, check the last cpu it executed
+ * on.
+ */
+ if (mutex_trylock(&vcpu->mutex)) {
+ if (vcpu->cpu == cpu) {
+ kvm_arch_ops->vcpu_decache(vcpu);
+ vcpu->cpu = -1;
+ }
+ mutex_unlock(&vcpu->mutex);
+ }
+ }
+ spin_unlock(&kvm_lock);
+}
+
+static int kvm_cpu_hotplug(struct notifier_block *notifier, unsigned long val,
+ void *v)
+{
+ int cpu = (long)v;
+
+ switch (val) {
+ case CPU_DEAD:
+ case CPU_UP_CANCELED:
+ decache_vcpus_on_cpu(cpu);
+ smp_call_function_single(cpu, kvm_arch_ops->hardware_disable,
+ NULL, 0, 1);
+ break;
+ case CPU_UP_PREPARE:
+ smp_call_function_single(cpu, kvm_arch_ops->hardware_enable,
+ NULL, 0, 1);
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block kvm_cpu_notifier = {
+ .notifier_call = kvm_cpu_hotplug,
+ .priority = 20, /* must be > scheduler priority */
+};
+
static __init void kvm_init_debug(void)
{
struct kvm_stats_debugfs_item *p;
- debugfs_dir = debugfs_create_dir("kvm", 0);
+ debugfs_dir = debugfs_create_dir("kvm", NULL);
for (p = debugfs_entries; p->name; ++p)
p->dentry = debugfs_create_u32(p->name, 0444, debugfs_dir,
p->data);
@@ -2043,6 +2118,30 @@ static void kvm_exit_debug(void)
debugfs_remove(debugfs_dir);
}
+static int kvm_suspend(struct sys_device *dev, pm_message_t state)
+{
+ decache_vcpus_on_cpu(raw_smp_processor_id());
+ on_each_cpu(kvm_arch_ops->hardware_disable, 0, 0, 1);
+ return 0;
+}
+
+static int kvm_resume(struct sys_device *dev)
+{
+ on_each_cpu(kvm_arch_ops->hardware_enable, 0, 0, 1);
+ return 0;
+}
+
+static struct sysdev_class kvm_sysdev_class = {
+ set_kset_name("kvm"),
+ .suspend = kvm_suspend,
+ .resume = kvm_resume,
+};
+
+static struct sys_device kvm_sysdev = {
+ .id = 0,
+ .cls = &kvm_sysdev_class,
+};
+
hpa_t bad_page_address;
int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module)
@@ -2069,9 +2168,20 @@ int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module)
if (r < 0)
return r;
- on_each_cpu(kvm_arch_ops->hardware_enable, 0, 0, 1);
+ on_each_cpu(kvm_arch_ops->hardware_enable, NULL, 0, 1);
+ r = register_cpu_notifier(&kvm_cpu_notifier);
+ if (r)
+ goto out_free_1;
register_reboot_notifier(&kvm_reboot_notifier);
+ r = sysdev_class_register(&kvm_sysdev_class);
+ if (r)
+ goto out_free_2;
+
+ r = sysdev_register(&kvm_sysdev);
+ if (r)
+ goto out_free_3;
+
kvm_chardev_ops.owner = module;
r = misc_register(&kvm_dev);
@@ -2083,8 +2193,14 @@ int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module)
return r;
out_free:
+ sysdev_unregister(&kvm_sysdev);
+out_free_3:
+ sysdev_class_unregister(&kvm_sysdev_class);
+out_free_2:
unregister_reboot_notifier(&kvm_reboot_notifier);
- on_each_cpu(kvm_arch_ops->hardware_disable, 0, 0, 1);
+ unregister_cpu_notifier(&kvm_cpu_notifier);
+out_free_1:
+ on_each_cpu(kvm_arch_ops->hardware_disable, NULL, 0, 1);
kvm_arch_ops->hardware_unsetup();
return r;
}
@@ -2092,9 +2208,11 @@ out_free:
void kvm_exit_arch(void)
{
misc_deregister(&kvm_dev);
-
+ sysdev_unregister(&kvm_sysdev);
+ sysdev_class_unregister(&kvm_sysdev_class);
unregister_reboot_notifier(&kvm_reboot_notifier);
- on_each_cpu(kvm_arch_ops->hardware_disable, 0, 0, 1);
+ unregister_cpu_notifier(&kvm_cpu_notifier);
+ on_each_cpu(kvm_arch_ops->hardware_disable, NULL, 0, 1);
kvm_arch_ops->hardware_unsetup();
kvm_arch_ops = NULL;
}
diff --git a/drivers/kvm/mmu.c b/drivers/kvm/mmu.c
index 22c426cd8cb..be793770f31 100644
--- a/drivers/kvm/mmu.c
+++ b/drivers/kvm/mmu.c
@@ -333,7 +333,7 @@ static void rmap_desc_remove_entry(struct kvm_vcpu *vcpu,
for (j = RMAP_EXT - 1; !desc->shadow_ptes[j] && j > i; --j)
;
desc->shadow_ptes[i] = desc->shadow_ptes[j];
- desc->shadow_ptes[j] = 0;
+ desc->shadow_ptes[j] = NULL;
if (j != 0)
return;
if (!prev_desc && !desc->more)
diff --git a/drivers/kvm/paging_tmpl.h b/drivers/kvm/paging_tmpl.h
index 149fa45fd9a..b6b90e9e130 100644
--- a/drivers/kvm/paging_tmpl.h
+++ b/drivers/kvm/paging_tmpl.h
@@ -443,31 +443,17 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr,
static gpa_t FNAME(gva_to_gpa)(struct kvm_vcpu *vcpu, gva_t vaddr)
{
struct guest_walker walker;
- pt_element_t guest_pte;
- gpa_t gpa;
-
- FNAME(walk_addr)(&walker, vcpu, vaddr, 0, 0, 0);
- guest_pte = *walker.ptep;
- FNAME(release_walker)(&walker);
-
- if (!is_present_pte(guest_pte))
- return UNMAPPED_GVA;
-
- if (walker.level == PT_DIRECTORY_LEVEL) {
- ASSERT((guest_pte & PT_PAGE_SIZE_MASK));
- ASSERT(PTTYPE == 64 || is_pse(vcpu));
+ gpa_t gpa = UNMAPPED_GVA;
+ int r;
- gpa = (guest_pte & PT_DIR_BASE_ADDR_MASK) | (vaddr &
- (PT_LEVEL_MASK(PT_PAGE_TABLE_LEVEL) | ~PAGE_MASK));
+ r = FNAME(walk_addr)(&walker, vcpu, vaddr, 0, 0, 0);
- if (PTTYPE == 32 && is_cpuid_PSE36())
- gpa |= (guest_pte & PT32_DIR_PSE36_MASK) <<
- (32 - PT32_DIR_PSE36_SHIFT);
- } else {
- gpa = (guest_pte & PT_BASE_ADDR_MASK);
- gpa |= (vaddr & ~PAGE_MASK);
+ if (r) {
+ gpa = (gpa_t)walker.gfn << PAGE_SHIFT;
+ gpa |= vaddr & ~PAGE_MASK;
}
+ FNAME(release_walker)(&walker);
return gpa;
}
diff --git a/drivers/kvm/svm.c b/drivers/kvm/svm.c
index c79df79307e..83da4ea150a 100644
--- a/drivers/kvm/svm.c
+++ b/drivers/kvm/svm.c
@@ -274,7 +274,7 @@ static void svm_hardware_disable(void *garbage)
wrmsrl(MSR_VM_HSAVE_PA, 0);
rdmsrl(MSR_EFER, efer);
wrmsrl(MSR_EFER, efer & ~MSR_EFER_SVME_MASK);
- per_cpu(svm_data, raw_smp_processor_id()) = 0;
+ per_cpu(svm_data, raw_smp_processor_id()) = NULL;
__free_page(svm_data->save_area);
kfree(svm_data);
}
@@ -528,7 +528,13 @@ static void init_vmcb(struct vmcb *vmcb)
save->cs.attrib = SVM_SELECTOR_READ_MASK | SVM_SELECTOR_P_MASK |
SVM_SELECTOR_S_MASK | SVM_SELECTOR_CODE_MASK;
save->cs.limit = 0xffff;
- save->cs.base = 0xffff0000;
+ /*
+ * cs.base should really be 0xffff0000, but vmx can't handle that, so
+ * be consistent with it.
+ *
+ * Replace when we have real mode working for vmx.
+ */
+ save->cs.base = 0xf0000;
save->gdtr.limit = 0xffff;
save->idtr.limit = 0xffff;
@@ -603,6 +609,10 @@ static void svm_vcpu_put(struct kvm_vcpu *vcpu)
put_cpu();
}
+static void svm_vcpu_decache(struct kvm_vcpu *vcpu)
+{
+}
+
static void svm_cache_regs(struct kvm_vcpu *vcpu)
{
vcpu->regs[VCPU_REGS_RAX] = vcpu->svm->vmcb->save.rax;
@@ -642,7 +652,7 @@ static struct vmcb_seg *svm_seg(struct kvm_vcpu *vcpu, int seg)
case VCPU_SREG_LDTR: return &save->ldtr;
}
BUG();
- return 0;
+ return NULL;
}
static u64 svm_get_segment_base(struct kvm_vcpu *vcpu, int seg)
@@ -723,7 +733,7 @@ static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
}
#endif
vcpu->svm->cr0 = cr0;
- vcpu->svm->vmcb->save.cr0 = cr0 | CR0_PG_MASK;
+ vcpu->svm->vmcb->save.cr0 = cr0 | CR0_PG_MASK | CR0_WP_MASK;
vcpu->cr0 = cr0;
}
@@ -934,7 +944,7 @@ static int io_get_override(struct kvm_vcpu *vcpu,
return 0;
*addr_override = 0;
- *seg = 0;
+ *seg = NULL;
for (i = 0; i < ins_length; i++)
switch (inst[i]) {
case 0xf0:
@@ -1087,7 +1097,7 @@ static int cpuid_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
static int emulate_on_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
{
- if (emulate_instruction(vcpu, 0, 0, 0) != EMULATE_DONE)
+ if (emulate_instruction(vcpu, NULL, 0, 0) != EMULATE_DONE)
printk(KERN_ERR "%s: failed\n", __FUNCTION__);
return 1;
}
@@ -1671,6 +1681,7 @@ static struct kvm_arch_ops svm_arch_ops = {
.vcpu_load = svm_vcpu_load,
.vcpu_put = svm_vcpu_put,
+ .vcpu_decache = svm_vcpu_decache,
.set_guest_debug = svm_guest_debug,
.get_msr = svm_get_msr,
diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c
index 54c35c0b318..fd4e9173438 100644
--- a/drivers/kvm/vmx.c
+++ b/drivers/kvm/vmx.c
@@ -98,7 +98,7 @@ static struct vmx_msr_entry *find_msr_entry(struct kvm_vcpu *vcpu, u32 msr)
for (i = 0; i < vcpu->nmsrs; ++i)
if (vcpu->guest_msrs[i].index == msr)
return &vcpu->guest_msrs[i];
- return 0;
+ return NULL;
}
static void vmcs_clear(struct vmcs *vmcs)
@@ -125,6 +125,15 @@ static void __vcpu_clear(void *arg)
per_cpu(current_vmcs, cpu) = NULL;
}
+static void vcpu_clear(struct kvm_vcpu *vcpu)
+{
+ if (vcpu->cpu != raw_smp_processor_id() && vcpu->cpu != -1)
+ smp_call_function_single(vcpu->cpu, __vcpu_clear, vcpu, 0, 1);
+ else
+ __vcpu_clear(vcpu);
+ vcpu->launched = 0;
+}
+
static unsigned long vmcs_readl(unsigned long field)
{
unsigned long value;
@@ -202,10 +211,8 @@ static struct kvm_vcpu *vmx_vcpu_load(struct kvm_vcpu *vcpu)
cpu = get_cpu();
- if (vcpu->cpu != cpu) {
- smp_call_function(__vcpu_clear, vcpu, 0, 1);
- vcpu->launched = 0;
- }
+ if (vcpu->cpu != cpu)
+ vcpu_clear(vcpu);
if (per_cpu(current_vmcs, cpu) != vcpu->vmcs) {
u8 error;
@@ -243,6 +250,11 @@ static void vmx_vcpu_put(struct kvm_vcpu *vcpu)
put_cpu();
}
+static void vmx_vcpu_decache(struct kvm_vcpu *vcpu)
+{
+ vcpu_clear(vcpu);
+}
+
static unsigned long vmx_get_rflags(struct kvm_vcpu *vcpu)
{
return vmcs_readl(GUEST_RFLAGS);
@@ -502,7 +514,7 @@ static __init int vmx_disabled_by_bios(void)
return (msr & 5) == 1; /* locked but not enabled */
}
-static __init void hardware_enable(void *garbage)
+static void hardware_enable(void *garbage)
{
int cpu = raw_smp_processor_id();
u64 phys_addr = __pa(per_cpu(vmxarea, cpu));
@@ -1375,6 +1387,11 @@ static int handle_external_interrupt(struct kvm_vcpu *vcpu,
return 1;
}
+static int handle_triple_fault(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+ kvm_run->exit_reason = KVM_EXIT_SHUTDOWN;
+ return 0;
+}
static int get_io_count(struct kvm_vcpu *vcpu, u64 *count)
{
@@ -1635,6 +1652,7 @@ static int (*kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu,
struct kvm_run *kvm_run) = {
[EXIT_REASON_EXCEPTION_NMI] = handle_exception,
[EXIT_REASON_EXTERNAL_INTERRUPT] = handle_external_interrupt,
+ [EXIT_REASON_TRIPLE_FAULT] = handle_triple_fault,
[EXIT_REASON_IO_INSTRUCTION] = handle_io,
[EXIT_REASON_CR_ACCESS] = handle_cr,
[EXIT_REASON_DR_ACCESS] = handle_dr,
@@ -1786,10 +1804,10 @@ again:
"kvm_vmx_return: "
/* Save guest registers, load host registers, keep flags */
#ifdef CONFIG_X86_64
- "xchg %3, 0(%%rsp) \n\t"
+ "xchg %3, (%%rsp) \n\t"
"mov %%rax, %c[rax](%3) \n\t"
"mov %%rbx, %c[rbx](%3) \n\t"
- "pushq 0(%%rsp); popq %c[rcx](%3) \n\t"
+ "pushq (%%rsp); popq %c[rcx](%3) \n\t"
"mov %%rdx, %c[rdx](%3) \n\t"
"mov %%rsi, %c[rsi](%3) \n\t"
"mov %%rdi, %c[rdi](%3) \n\t"
@@ -1804,24 +1822,24 @@ again:
"mov %%r15, %c[r15](%3) \n\t"
"mov %%cr2, %%rax \n\t"
"mov %%rax, %c[cr2](%3) \n\t"
- "mov 0(%%rsp), %3 \n\t"
+ "mov (%%rsp), %3 \n\t"
"pop %%rcx; pop %%r15; pop %%r14; pop %%r13; pop %%r12;"
"pop %%r11; pop %%r10; pop %%r9; pop %%r8;"
"pop %%rbp; pop %%rdi; pop %%rsi;"
"pop %%rdx; pop %%rbx; pop %%rax \n\t"
#else
- "xchg %3, 0(%%esp) \n\t"
+ "xchg %3, (%%esp) \n\t"
"mov %%eax, %c[rax](%3) \n\t"
"mov %%ebx, %c[rbx](%3) \n\t"
- "pushl 0(%%esp); popl %c[rcx](%3) \n\t"
+ "pushl (%%esp); popl %c[rcx](%3) \n\t"
"mov %%edx, %c[rdx](%3) \n\t"
"mov %%esi, %c[rsi](%3) \n\t"
"mov %%edi, %c[rdi](%3) \n\t"
"mov %%ebp, %c[rbp](%3) \n\t"
"mov %%cr2, %%eax \n\t"
"mov %%eax, %c[cr2](%3) \n\t"
- "mov 0(%%esp), %3 \n\t"
+ "mov (%%esp), %3 \n\t"
"pop %%ecx; popa \n\t"
#endif
@@ -1859,15 +1877,7 @@ again:
fx_restore(vcpu->host_fx_image);
vcpu->interrupt_window_open = (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0;
-#ifndef CONFIG_X86_64
asm ("mov %0, %%ds; mov %0, %%es" : : "r"(__USER_DS));
-#endif
-
- /*
- * Profile KVM exit RIPs:
- */
- if (unlikely(prof_on == KVM_PROFILING))
- profile_hit(KVM_PROFILING, (void *)vmcs_readl(GUEST_RIP));
kvm_run->exit_type = 0;
if (fail) {
@@ -1891,6 +1901,12 @@ again:
reload_tss();
}
+ /*
+ * Profile KVM exit RIPs:
+ */
+ if (unlikely(prof_on == KVM_PROFILING))
+ profile_hit(KVM_PROFILING, (void *)vmcs_readl(GUEST_RIP));
+
vcpu->launched = 1;
kvm_run->exit_type = KVM_EXIT_TYPE_VM_EXIT;
r = kvm_handle_exit(kvm_run, vcpu);
@@ -2012,6 +2028,7 @@ static struct kvm_arch_ops vmx_arch_ops = {
.vcpu_load = vmx_vcpu_load,
.vcpu_put = vmx_vcpu_put,
+ .vcpu_decache = vmx_vcpu_decache,
.set_guest_debug = set_guest_debug,
.get_msr = vmx_get_msr,
diff --git a/drivers/kvm/vmx.h b/drivers/kvm/vmx.h
index 4c0ab151836..d0dc93df411 100644
--- a/drivers/kvm/vmx.h
+++ b/drivers/kvm/vmx.h
@@ -180,6 +180,7 @@ enum vmcs_field {
#define EXIT_REASON_EXCEPTION_NMI 0
#define EXIT_REASON_EXTERNAL_INTERRUPT 1
+#define EXIT_REASON_TRIPLE_FAULT 2
#define EXIT_REASON_PENDING_INTERRUPT 7
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 7399ba79111..80acd08f0e9 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -82,6 +82,18 @@ config LEDS_WRAP
help
This option enables support for the PCEngines WRAP programmable LEDs.
+config LEDS_H1940
+ tristate "LED Support for iPAQ H1940 device"
+ depends LEDS_CLASS && ARCH_H1940
+ help
+ This option enables support for the LEDs on the h1940.
+
+config LEDS_COBALT
+ tristate "LED Support for Cobalt Server front LED"
+ depends on LEDS_CLASS && MIPS_COBALT
+ help
+ This option enables support for the front LED on Cobalt Server
+
comment "LED Triggers"
config LEDS_TRIGGERS
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 500de3dc962..aa2c18efa5b 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -14,6 +14,8 @@ obj-$(CONFIG_LEDS_S3C24XX) += leds-s3c24xx.o
obj-$(CONFIG_LEDS_AMS_DELTA) += leds-ams-delta.o
obj-$(CONFIG_LEDS_NET48XX) += leds-net48xx.o
obj-$(CONFIG_LEDS_WRAP) += leds-wrap.o
+obj-$(CONFIG_LEDS_H1940) += leds-h1940.o
+obj-$(CONFIG_LEDS_COBALT) += leds-cobalt.o
# LED Triggers
obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o
diff --git a/drivers/leds/leds-cobalt.c b/drivers/leds/leds-cobalt.c
new file mode 100644
index 00000000000..d16439ce5da
--- /dev/null
+++ b/drivers/leds/leds-cobalt.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2006 - Florian Fainelli <florian@openwrt.org>
+ *
+ * Control the Cobalt Qube/RaQ front LED
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/leds.h>
+#include <asm/mach-cobalt/cobalt.h>
+
+static void cobalt_led_set(struct led_classdev *led_cdev, enum led_brightness brightness)
+{
+ if (brightness)
+ COBALT_LED_PORT = COBALT_LED_BAR_LEFT | COBALT_LED_BAR_RIGHT;
+ else
+ COBALT_LED_PORT = 0;
+}
+
+static struct led_classdev cobalt_led = {
+ .name = "cobalt-front-led",
+ .brightness_set = cobalt_led_set,
+ .default_trigger = "ide-disk",
+};
+
+static int __init cobalt_led_init(void)
+{
+ return led_classdev_register(NULL, &cobalt_led);
+}
+
+static void __exit cobalt_led_exit(void)
+{
+ led_classdev_unregister(&cobalt_led);
+}
+
+module_init(cobalt_led_init);
+module_exit(cobalt_led_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Front LED support for Cobalt Server");
+MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>");
diff --git a/drivers/leds/leds-h1940.c b/drivers/leds/leds-h1940.c
new file mode 100644
index 00000000000..1d49d2ade55
--- /dev/null
+++ b/drivers/leds/leds-h1940.c
@@ -0,0 +1,163 @@
+/*
+ * drivers/leds/h1940-leds.c
+ * Copyright (c) Arnaud Patard <arnaud.patard@rtp-net.org>
+ *
+ * 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.
+ *
+ * H1940 leds driver
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/leds.h>
+#include <asm/arch/regs-gpio.h>
+#include <asm/hardware.h>
+#include <asm/arch/h1940-latch.h>
+
+/*
+ * Green led.
+ */
+void h1940_greenled_set(struct led_classdev *led_dev, enum led_brightness value)
+{
+ switch (value) {
+ case LED_HALF:
+ h1940_latch_control(0,H1940_LATCH_LED_FLASH);
+ s3c2410_gpio_setpin(S3C2410_GPA7,1);
+ break;
+ case LED_FULL:
+ h1940_latch_control(0,H1940_LATCH_LED_GREEN);
+ s3c2410_gpio_setpin(S3C2410_GPA7,1);
+ break;
+ default:
+ case LED_OFF:
+ h1940_latch_control(H1940_LATCH_LED_FLASH,0);
+ h1940_latch_control(H1940_LATCH_LED_GREEN,0);
+ s3c2410_gpio_setpin(S3C2410_GPA7,0);
+ break;
+ }
+}
+
+static struct led_classdev h1940_greenled = {
+ .name = "h1940:green",
+ .brightness_set = h1940_greenled_set,
+ .default_trigger = "h1940-charger",
+};
+
+/*
+ * Red led.
+ */
+void h1940_redled_set(struct led_classdev *led_dev, enum led_brightness value)
+{
+ switch (value) {
+ case LED_HALF:
+ h1940_latch_control(0,H1940_LATCH_LED_FLASH);
+ s3c2410_gpio_setpin(S3C2410_GPA1,1);
+ break;
+ case LED_FULL:
+ h1940_latch_control(0,H1940_LATCH_LED_RED);
+ s3c2410_gpio_setpin(S3C2410_GPA1,1);
+ break;
+ default:
+ case LED_OFF:
+ h1940_latch_control(H1940_LATCH_LED_FLASH,0);
+ h1940_latch_control(H1940_LATCH_LED_RED,0);
+ s3c2410_gpio_setpin(S3C2410_GPA1,0);
+ break;
+ }
+}
+
+static struct led_classdev h1940_redled = {
+ .name = "h1940:red",
+ .brightness_set = h1940_redled_set,
+ .default_trigger = "h1940-charger",
+};
+
+/*
+ * Blue led.
+ * (it can only be blue flashing led)
+ */
+void h1940_blueled_set(struct led_classdev *led_dev, enum led_brightness value)
+{
+ if (value) {
+ /* flashing Blue */
+ h1940_latch_control(0,H1940_LATCH_LED_FLASH);
+ s3c2410_gpio_setpin(S3C2410_GPA3,1);
+ } else {
+ h1940_latch_control(H1940_LATCH_LED_FLASH,0);
+ s3c2410_gpio_setpin(S3C2410_GPA3,0);
+ }
+
+}
+
+static struct led_classdev h1940_blueled = {
+ .name = "h1940:blue",
+ .brightness_set = h1940_blueled_set,
+ .default_trigger = "h1940-bluetooth",
+};
+
+static int __init h1940leds_probe(struct platform_device *pdev)
+{
+ int ret;
+
+ ret = led_classdev_register(&pdev->dev, &h1940_greenled);
+ if (ret)
+ goto err_green;
+
+ ret = led_classdev_register(&pdev->dev, &h1940_redled);
+ if (ret)
+ goto err_red;
+
+ ret = led_classdev_register(&pdev->dev, &h1940_blueled);
+ if (ret)
+ goto err_blue;
+
+ return 0;
+
+err_blue:
+ led_classdev_unregister(&h1940_redled);
+err_red:
+ led_classdev_unregister(&h1940_greenled);
+err_green:
+ return ret;
+}
+
+static int h1940leds_remove(struct platform_device *pdev)
+{
+ led_classdev_unregister(&h1940_greenled);
+ led_classdev_unregister(&h1940_redled);
+ led_classdev_unregister(&h1940_blueled);
+ return 0;
+}
+
+
+static struct platform_driver h1940leds_driver = {
+ .driver = {
+ .name = "h1940-leds",
+ },
+ .probe = h1940leds_probe,
+ .remove = h1940leds_remove,
+};
+
+
+static int __init h1940leds_init(void)
+{
+ return platform_driver_register(&h1940leds_driver);
+}
+
+static void __exit h1940leds_exit(void)
+{
+ platform_driver_unregister(&h1940leds_driver);
+}
+
+module_init(h1940leds_init);
+module_exit(h1940leds_exit);
+
+MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
+MODULE_DESCRIPTION("LED driver for the iPAQ H1940");
+MODULE_LICENSE("GPL");
diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig
index a9e747c3979..1a86387e23b 100644
--- a/drivers/macintosh/Kconfig
+++ b/drivers/macintosh/Kconfig
@@ -1,6 +1,6 @@
menu "Macintosh device drivers"
- depends on PPC || MAC
+ depends on PPC || MAC || X86
config ADB
bool "Apple Desktop Bus (ADB) support"
diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c
index 7cec6de5e2b..f729eebf771 100644
--- a/drivers/macintosh/adb.c
+++ b/drivers/macintosh/adb.c
@@ -885,7 +885,7 @@ out:
return ret;
}
-static struct file_operations adb_fops = {
+static const struct file_operations adb_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = adb_read,
diff --git a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c
index 1c7d6f221b5..b77ef5187d6 100644
--- a/drivers/macintosh/adbhid.c
+++ b/drivers/macintosh/adbhid.c
@@ -574,8 +574,8 @@ static struct adb_request led_request;
static int leds_pending[16];
static int leds_req_pending;
static int pending_devs[16];
-static int pending_led_start=0;
-static int pending_led_end=0;
+static int pending_led_start;
+static int pending_led_end;
static DEFINE_SPINLOCK(leds_lock);
static void leds_done(struct adb_request *req)
diff --git a/drivers/macintosh/ans-lcd.c b/drivers/macintosh/ans-lcd.c
index 2b8a6e821d4..cdd5a0f72e3 100644
--- a/drivers/macintosh/ans-lcd.c
+++ b/drivers/macintosh/ans-lcd.c
@@ -121,7 +121,7 @@ anslcd_open( struct inode * inode, struct file * file )
return 0;
}
-struct file_operations anslcd_fops = {
+const struct file_operations anslcd_fops = {
.write = anslcd_write,
.ioctl = anslcd_ioctl,
.open = anslcd_open,
diff --git a/drivers/macintosh/apm_emu.c b/drivers/macintosh/apm_emu.c
index 4300c628f8a..c5e4d43f97f 100644
--- a/drivers/macintosh/apm_emu.c
+++ b/drivers/macintosh/apm_emu.c
@@ -102,7 +102,7 @@ static struct pmu_sleep_notifier apm_sleep_notifier = {
SLEEP_LEVEL_USERLAND,
};
-static char driver_version[] = "0.5"; /* no spaces */
+static const char driver_version[] = "0.5"; /* no spaces */
#ifdef DEBUG
static char * apm_event_name[] = {
@@ -501,7 +501,7 @@ static int apm_emu_get_info(char *buf, char **start, off_t fpos, int length)
return p - buf;
}
-static struct file_operations apm_bios_fops = {
+static const struct file_operations apm_bios_fops = {
.owner = THIS_MODULE,
.read = do_read,
.poll = do_poll,
diff --git a/drivers/macintosh/mac_hid.c b/drivers/macintosh/mac_hid.c
index ee6b4ca6913..c1fd816e9f0 100644
--- a/drivers/macintosh/mac_hid.c
+++ b/drivers/macintosh/mac_hid.c
@@ -17,10 +17,10 @@
static struct input_dev *emumousebtn;
static int emumousebtn_input_register(void);
-static int mouse_emulate_buttons = 0;
+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 = 0;
+static int mouse_last_keycode;
#if defined(CONFIG_SYSCTL)
/* file(s) in /proc/sys/dev/mac_hid */
@@ -138,7 +138,7 @@ int __init mac_hid_init(void)
return err;
#if defined(CONFIG_SYSCTL)
- mac_hid_sysctl_header = register_sysctl_table(mac_hid_root_dir, 1);
+ mac_hid_sysctl_header = register_sysctl_table(mac_hid_root_dir);
#endif /* CONFIG_SYSCTL */
return 0;
diff --git a/drivers/macintosh/macio-adb.c b/drivers/macintosh/macio-adb.c
index 797cef72258..026b67f4f65 100644
--- a/drivers/macintosh/macio-adb.c
+++ b/drivers/macintosh/macio-adb.c
@@ -6,7 +6,6 @@
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/delay.h>
-#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <asm/prom.h>
diff --git a/drivers/macintosh/nvram.c b/drivers/macintosh/nvram.c
index 30791875fc9..b195d753d2e 100644
--- a/drivers/macintosh/nvram.c
+++ b/drivers/macintosh/nvram.c
@@ -100,7 +100,7 @@ static int nvram_ioctl(struct inode *inode, struct file *file,
return 0;
}
-struct file_operations nvram_fops = {
+const struct file_operations nvram_fops = {
.owner = THIS_MODULE,
.llseek = nvram_llseek,
.read = read_nvram,
diff --git a/drivers/macintosh/rack-meter.c b/drivers/macintosh/rack-meter.c
index 5ed41fe84e5..f83fad2a3ff 100644
--- a/drivers/macintosh/rack-meter.c
+++ b/drivers/macintosh/rack-meter.c
@@ -171,11 +171,11 @@ static void rackmeter_setup_dbdma(struct rackmeter *rm)
/* Make sure dbdma is reset */
DBDMA_DO_RESET(rm->dma_regs);
- pr_debug("rackmeter: mark offset=0x%lx\n",
+ pr_debug("rackmeter: mark offset=0x%zx\n",
offsetof(struct rackmeter_dma, mark));
- pr_debug("rackmeter: buf1 offset=0x%lx\n",
+ pr_debug("rackmeter: buf1 offset=0x%zx\n",
offsetof(struct rackmeter_dma, buf1));
- pr_debug("rackmeter: buf2 offset=0x%lx\n",
+ pr_debug("rackmeter: buf2 offset=0x%zx\n",
offsetof(struct rackmeter_dma, buf2));
/* Prepare 4 dbdma commands for the 2 buffers */
diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c
index 6f30459b938..3096836d8bd 100644
--- a/drivers/macintosh/smu.c
+++ b/drivers/macintosh/smu.c
@@ -1277,7 +1277,7 @@ static int smu_release(struct inode *inode, struct file *file)
}
-static struct file_operations smu_device_fops = {
+static const struct file_operations smu_device_fops = {
.llseek = no_llseek,
.read = smu_read,
.write = smu_write,
diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c
index 3d3bf1643e7..a7ce5592663 100644
--- a/drivers/macintosh/therm_adt746x.c
+++ b/drivers/macintosh/therm_adt746x.c
@@ -48,11 +48,11 @@ static u8 FAN_SPD_SET[2] = {0x30, 0x31};
static u8 default_limits_local[3] = {70, 50, 70}; /* local, sensor1, sensor2 */
static u8 default_limits_chip[3] = {80, 65, 80}; /* local, sensor1, sensor2 */
-static const char *sensor_location[3] = {NULL, NULL, NULL};
+static const char *sensor_location[3];
-static int limit_adjust = 0;
+static int limit_adjust;
static int fan_speed = -1;
-static int verbose = 0;
+static int verbose;
MODULE_AUTHOR("Colin Leroy <colin@colino.net>");
MODULE_DESCRIPTION("Driver for ADT746x thermostat in iBook G4 and "
diff --git a/drivers/macintosh/via-cuda.c b/drivers/macintosh/via-cuda.c
index df66291b132..d58fcf6cca0 100644
--- a/drivers/macintosh/via-cuda.c
+++ b/drivers/macintosh/via-cuda.c
@@ -13,7 +13,6 @@
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/delay.h>
-#include <linux/sched.h>
#include <linux/adb.h>
#include <linux/cuda.h>
#include <linux/spinlock.h>
@@ -86,7 +85,7 @@ static int data_index;
#ifdef CONFIG_PPC
static struct device_node *vias;
#endif
-static int cuda_fully_inited = 0;
+static int cuda_fully_inited;
#ifdef CONFIG_ADB
static int cuda_probe(void);
diff --git a/drivers/macintosh/via-macii.c b/drivers/macintosh/via-macii.c
index 5d88d5b0ad9..1b3bad62a1b 100644
--- a/drivers/macintosh/via-macii.c
+++ b/drivers/macintosh/via-macii.c
@@ -19,7 +19,6 @@
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/delay.h>
-#include <linux/sched.h>
#include <linux/adb.h>
#include <linux/interrupt.h>
#include <linux/init.h>
@@ -107,10 +106,10 @@ static enum macii_state {
awaiting_reply
} macii_state;
-static int need_poll = 0;
-static int command_byte = 0;
-static int last_reply = 0;
-static int last_active = 0;
+static int need_poll;
+static int command_byte;
+static int last_reply;
+static int last_active;
static struct adb_request *current_req;
static struct adb_request *last_req;
@@ -124,7 +123,7 @@ static int first_byte;
static int prefix_len;
static int status = ST_IDLE|TREQ;
static int last_status;
-static int driver_running = 0;
+static int driver_running;
/* debug level 10 required for ADB logging (should be && debug_adb, ideally) */
diff --git a/drivers/macintosh/via-maciisi.c b/drivers/macintosh/via-maciisi.c
index 1f0aa5dc9aa..2dc78804270 100644
--- a/drivers/macintosh/via-maciisi.c
+++ b/drivers/macintosh/via-maciisi.c
@@ -18,7 +18,6 @@
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/adb.h>
#include <linux/cuda.h>
#include <linux/delay.h>
@@ -63,10 +62,10 @@ static volatile unsigned char *via;
#undef DEBUG_MACIISI_ADB
-static struct adb_request* current_req = NULL;
-static struct adb_request* last_req = NULL;
+static struct adb_request* current_req;
+static struct adb_request* last_req;
static unsigned char maciisi_rbuf[16];
-static unsigned char *reply_ptr = NULL;
+static unsigned char *reply_ptr;
static int data_index;
static int reading_reply;
static int reply_len;
diff --git a/drivers/macintosh/via-pmu-backlight.c b/drivers/macintosh/via-pmu-backlight.c
index 801a974342f..7e27071746e 100644
--- a/drivers/macintosh/via-pmu-backlight.c
+++ b/drivers/macintosh/via-pmu-backlight.c
@@ -15,7 +15,7 @@
#define MAX_PMU_LEVEL 0xFF
-static struct backlight_properties pmu_backlight_data;
+static struct backlight_ops pmu_backlight_data;
static DEFINE_SPINLOCK(pmu_backlight_lock);
static int sleeping;
static u8 bl_curve[FB_BACKLIGHT_LEVELS];
@@ -72,7 +72,7 @@ static int pmu_backlight_update_status(struct backlight_device *bd)
{
struct adb_request req;
unsigned long flags;
- int level = bd->props->brightness;
+ int level = bd->props.brightness;
spin_lock_irqsave(&pmu_backlight_lock, flags);
@@ -80,8 +80,8 @@ static int pmu_backlight_update_status(struct backlight_device *bd)
if (sleeping)
goto out;
- if (bd->props->power != FB_BLANK_UNBLANK ||
- bd->props->fb_blank != FB_BLANK_UNBLANK)
+ if (bd->props.power != FB_BLANK_UNBLANK ||
+ bd->props.fb_blank != FB_BLANK_UNBLANK)
level = 0;
if (level > 0) {
@@ -107,14 +107,13 @@ out:
static int pmu_backlight_get_brightness(struct backlight_device *bd)
{
- return bd->props->brightness;
+ return bd->props.brightness;
}
-static struct backlight_properties pmu_backlight_data = {
- .owner = THIS_MODULE,
+static struct backlight_ops pmu_backlight_data = {
.get_brightness = pmu_backlight_get_brightness,
.update_status = pmu_backlight_update_status,
- .max_brightness = (FB_BACKLIGHT_LEVELS - 1),
+
};
#ifdef CONFIG_PM
@@ -152,9 +151,10 @@ void __init pmu_backlight_init()
printk("pmubl: Backlight registration failed\n");
goto error;
}
+ bd->props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
pmu_backlight_init_curve(0x7F, 0x46, 0x0E);
- level = pmu_backlight_data.max_brightness;
+ level = bd->props.max_brightness;
if (autosave) {
/* read autosaved value if available */
@@ -164,19 +164,12 @@ void __init pmu_backlight_init()
level = pmu_backlight_curve_lookup(
(req.reply[0] >> 4) *
- pmu_backlight_data.max_brightness / 15);
+ bd->props.max_brightness / 15);
}
- down(&bd->sem);
- bd->props->brightness = level;
- bd->props->power = FB_BLANK_UNBLANK;
- bd->props->update_status(bd);
- up(&bd->sem);
-
- mutex_lock(&pmac_backlight_mutex);
- if (!pmac_backlight)
- pmac_backlight = bd;
- mutex_unlock(&pmac_backlight_mutex);
+ bd->props.brightness = level;
+ bd->props.power = FB_BLANK_UNBLANK;
+ backlight_update_status(bd);
printk("pmubl: Backlight initialized (%s)\n", name);
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
index 8ca75e52f63..b6073bdb50c 100644
--- a/drivers/macintosh/via-pmu.c
+++ b/drivers/macintosh/via-pmu.c
@@ -141,13 +141,13 @@ static volatile int adb_int_pending;
static volatile int disable_poll;
static struct device_node *vias;
static int pmu_kind = PMU_UNKNOWN;
-static int pmu_fully_inited = 0;
+static int pmu_fully_inited;
static int pmu_has_adb;
static struct device_node *gpio_node;
-static unsigned char __iomem *gpio_reg = NULL;
+static unsigned char __iomem *gpio_reg;
static int gpio_irq = NO_IRQ;
static int gpio_irq_enabled = -1;
-static volatile int pmu_suspended = 0;
+static volatile int pmu_suspended;
static spinlock_t pmu_lock;
static u8 pmu_intr_mask;
static int pmu_version;
@@ -169,7 +169,7 @@ static int option_server_mode;
int pmu_battery_count;
int pmu_cur_battery;
-unsigned int pmu_power_flags;
+unsigned int pmu_power_flags = PMU_PWR_AC_PRESENT;
struct pmu_battery_info pmu_batteries[PMU_MAX_BATTERIES];
static int query_batt_timer = BATTERY_POLLING_COUNT;
static struct adb_request batt_req;
@@ -180,7 +180,7 @@ int asleep;
BLOCKING_NOTIFIER_HEAD(sleep_notifier_list);
#ifdef CONFIG_ADB
-static int adb_dev_map = 0;
+static int adb_dev_map;
static int pmu_adb_flags;
static int pmu_probe(void);
@@ -516,7 +516,6 @@ static int __init via_pmu_dev_init(void)
proc_get_irqstats, NULL);
proc_pmu_options = create_proc_entry("options", 0600, proc_pmu_root);
if (proc_pmu_options) {
- proc_pmu_options->nlink = 1;
proc_pmu_options->read_proc = proc_read_options;
proc_pmu_options->write_proc = proc_write_options;
}
@@ -2673,7 +2672,7 @@ pmu_ioctl(struct inode * inode, struct file *filp,
return error;
}
-static struct file_operations pmu_device_fops = {
+static const struct file_operations pmu_device_fops = {
.read = pmu_read,
.write = pmu_write,
.poll = pmu_fpoll,
@@ -2777,7 +2776,7 @@ pmu_polled_request(struct adb_request *req)
#if defined(CONFIG_PM) && defined(CONFIG_PPC32)
-static int pmu_sys_suspended = 0;
+static int pmu_sys_suspended;
static int pmu_sys_suspend(struct sys_device *sysdev, pm_message_t state)
{
@@ -2817,7 +2816,6 @@ static struct sysdev_class pmu_sysclass = {
};
static struct sys_device device_pmu = {
- .id = 0,
.cls = &pmu_sysclass,
};
diff --git a/drivers/macintosh/via-pmu68k.c b/drivers/macintosh/via-pmu68k.c
index 93e6ef9233f..356c7216a17 100644
--- a/drivers/macintosh/via-pmu68k.c
+++ b/drivers/macintosh/via-pmu68k.c
@@ -22,7 +22,6 @@
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/delay.h>
-#include <linux/sched.h>
#include <linux/miscdevice.h>
#include <linux/blkdev.h>
#include <linux/pci.h>
@@ -96,10 +95,10 @@ static int data_index;
static int data_len;
static int adb_int_pending;
static int pmu_adb_flags;
-static int adb_dev_map = 0;
+static int adb_dev_map;
static struct adb_request bright_req_1, bright_req_2, bright_req_3;
static int pmu_kind = PMU_UNKNOWN;
-static int pmu_fully_inited = 0;
+static int pmu_fully_inited;
int asleep;
BLOCKING_NOTIFIER_HEAD(sleep_notifier_list);
@@ -1040,7 +1039,7 @@ static int pmu_ioctl(struct inode * inode, struct file *filp,
return -EINVAL;
}
-static struct file_operations pmu_device_fops = {
+static const struct file_operations pmu_device_fops = {
.read = pmu_read,
.write = pmu_write,
.ioctl = pmu_ioctl,
diff --git a/drivers/macintosh/windfarm_core.c b/drivers/macintosh/windfarm_core.c
index e947af982f9..94c117ef20c 100644
--- a/drivers/macintosh/windfarm_core.c
+++ b/drivers/macintosh/windfarm_core.c
@@ -94,8 +94,6 @@ static int wf_thread_func(void *data)
DBG("wf: thread started\n");
while(!kthread_should_stop()) {
- try_to_freeze();
-
if (time_after_eq(jiffies, next)) {
wf_notify(WF_EVENT_TICK, NULL);
if (wf_overtemp) {
@@ -118,8 +116,8 @@ static int wf_thread_func(void *data)
if (delay <= HZ)
schedule_timeout_interruptible(delay);
- /* there should be no signal, but oh well */
- if (signal_pending(current)) {
+ /* there should be no non-suspend signal, but oh well */
+ if (signal_pending(current) && !try_to_freeze()) {
printk(KERN_WARNING "windfarm: thread got sigl !\n");
break;
}
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index 11108165e26..5554adaa58f 100644
--- a/drivers/md/bitmap.c
+++ b/drivers/md/bitmap.c
@@ -666,7 +666,7 @@ static void bitmap_file_put(struct bitmap *bitmap)
if (file) {
struct inode *inode = file->f_path.dentry->d_inode;
- invalidate_inode_pages(inode->i_mapping);
+ invalidate_mapping_pages(inode->i_mapping, 0, -1);
fput(file);
}
}
@@ -1160,6 +1160,22 @@ int bitmap_startwrite(struct bitmap *bitmap, sector_t offset, unsigned long sect
return 0;
}
+ if (unlikely((*bmc & COUNTER_MAX) == COUNTER_MAX)) {
+ DEFINE_WAIT(__wait);
+ /* note that it is safe to do the prepare_to_wait
+ * after the test as long as we do it before dropping
+ * the spinlock.
+ */
+ prepare_to_wait(&bitmap->overflow_wait, &__wait,
+ TASK_UNINTERRUPTIBLE);
+ spin_unlock_irq(&bitmap->lock);
+ bitmap->mddev->queue
+ ->unplug_fn(bitmap->mddev->queue);
+ schedule();
+ finish_wait(&bitmap->overflow_wait, &__wait);
+ continue;
+ }
+
switch(*bmc) {
case 0:
bitmap_file_set_bit(bitmap, offset);
@@ -1169,7 +1185,7 @@ int bitmap_startwrite(struct bitmap *bitmap, sector_t offset, unsigned long sect
case 1:
*bmc = 2;
}
- BUG_ON((*bmc & COUNTER_MAX) == COUNTER_MAX);
+
(*bmc)++;
spin_unlock_irq(&bitmap->lock);
@@ -1207,6 +1223,9 @@ void bitmap_endwrite(struct bitmap *bitmap, sector_t offset, unsigned long secto
if (!success && ! (*bmc & NEEDED_MASK))
*bmc |= NEEDED_MASK;
+ if ((*bmc & COUNTER_MAX) == COUNTER_MAX)
+ wake_up(&bitmap->overflow_wait);
+
(*bmc)--;
if (*bmc <= 2) {
set_page_attr(bitmap,
@@ -1431,6 +1450,7 @@ int bitmap_create(mddev_t *mddev)
spin_lock_init(&bitmap->lock);
atomic_set(&bitmap->pending_writes, 0);
init_waitqueue_head(&bitmap->write_wait);
+ init_waitqueue_head(&bitmap->overflow_wait);
bitmap->mddev = mddev;
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
index cd6a184536a..b441d82c338 100644
--- a/drivers/md/dm-ioctl.c
+++ b/drivers/md/dm-ioctl.c
@@ -1473,7 +1473,7 @@ static int ctl_ioctl(struct inode *inode, struct file *file,
return r;
}
-static struct file_operations _ctl_fops = {
+static const struct file_operations _ctl_fops = {
.ioctl = ctl_ioctl,
.owner = THIS_MODULE,
};
diff --git a/drivers/md/md.c b/drivers/md/md.c
index e8807ea5377..05febfd9f07 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -4920,7 +4920,7 @@ static unsigned int mdstat_poll(struct file *filp, poll_table *wait)
return mask;
}
-static struct file_operations md_seq_fops = {
+static const struct file_operations md_seq_fops = {
.owner = THIS_MODULE,
.open = md_seq_open,
.read = seq_read,
@@ -5581,7 +5581,7 @@ static int __init md_init(void)
md_probe, NULL, NULL);
register_reboot_notifier(&md_notifier);
- raid_table_header = register_sysctl_table(raid_root_table, 1);
+ raid_table_header = register_sysctl_table(raid_root_table);
md_geninit();
return (0);
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 467c16982d0..11c3d7bfa79 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -2620,7 +2620,7 @@ static struct bio *remove_bio_from_retry(raid5_conf_t *conf)
}
bi = conf->retry_read_aligned_list;
if(bi) {
- conf->retry_read_aligned = bi->bi_next;
+ conf->retry_read_aligned_list = bi->bi_next;
bi->bi_next = NULL;
bi->bi_phys_segments = 1; /* biased count of active stripes */
bi->bi_hw_segments = 0; /* count of processed stripes */
@@ -2669,6 +2669,27 @@ static int raid5_align_endio(struct bio *bi, unsigned int bytes, int error)
return 0;
}
+static int bio_fits_rdev(struct bio *bi)
+{
+ request_queue_t *q = bdev_get_queue(bi->bi_bdev);
+
+ if ((bi->bi_size>>9) > q->max_sectors)
+ return 0;
+ blk_recount_segments(q, bi);
+ if (bi->bi_phys_segments > q->max_phys_segments ||
+ bi->bi_hw_segments > q->max_hw_segments)
+ return 0;
+
+ if (q->merge_bvec_fn)
+ /* it's too hard to apply the merge_bvec_fn at this stage,
+ * just just give up
+ */
+ return 0;
+
+ return 1;
+}
+
+
static int chunk_aligned_read(request_queue_t *q, struct bio * raid_bio)
{
mddev_t *mddev = q->queuedata;
@@ -2715,6 +2736,13 @@ static int chunk_aligned_read(request_queue_t *q, struct bio * raid_bio)
align_bi->bi_flags &= ~(1 << BIO_SEG_VALID);
align_bi->bi_sector += rdev->data_offset;
+ if (!bio_fits_rdev(align_bi)) {
+ /* too big in some way */
+ bio_put(align_bi);
+ rdev_dec_pending(rdev, mddev);
+ return 0;
+ }
+
spin_lock_irq(&conf->device_lock);
wait_event_lock_irq(conf->wait_for_stripe,
conf->quiesce == 0,
@@ -3107,7 +3135,9 @@ static int retry_aligned_read(raid5_conf_t *conf, struct bio *raid_bio)
last_sector = raid_bio->bi_sector + (raid_bio->bi_size>>9);
for (; logical_sector < last_sector;
- logical_sector += STRIPE_SECTORS, scnt++) {
+ logical_sector += STRIPE_SECTORS,
+ sector += STRIPE_SECTORS,
+ scnt++) {
if (scnt < raid_bio->bi_hw_segments)
/* already done this stripe */
@@ -3123,7 +3153,13 @@ static int retry_aligned_read(raid5_conf_t *conf, struct bio *raid_bio)
}
set_bit(R5_ReadError, &sh->dev[dd_idx].flags);
- add_stripe_bio(sh, raid_bio, dd_idx, 0);
+ if (!add_stripe_bio(sh, raid_bio, dd_idx, 0)) {
+ release_stripe(sh);
+ raid_bio->bi_hw_segments = scnt;
+ conf->retry_read_aligned = raid_bio;
+ return handled;
+ }
+
handle_stripe(sh, NULL);
release_stripe(sh);
handled++;
diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig
index 87410dbd3df..91d25798ae4 100644
--- a/drivers/media/Kconfig
+++ b/drivers/media/Kconfig
@@ -70,6 +70,7 @@ config VIDEO_TUNER
depends on I2C
config VIDEO_BUF
+ depends on PCI
tristate
config VIDEO_BUF_DVB
diff --git a/drivers/media/common/Kconfig b/drivers/media/common/Kconfig
index f33e5d97341..c120114c241 100644
--- a/drivers/media/common/Kconfig
+++ b/drivers/media/common/Kconfig
@@ -5,8 +5,4 @@ config VIDEO_SAA7146
config VIDEO_SAA7146_VV
tristate
select VIDEO_BUF
- select VIDEO_VIDEOBUF
select VIDEO_SAA7146
-
-config VIDEO_VIDEOBUF
- tristate
diff --git a/drivers/media/common/ir-functions.c b/drivers/media/common/ir-functions.c
index 9a8dd8764c9..cbf7c056488 100644
--- a/drivers/media/common/ir-functions.c
+++ b/drivers/media/common/ir-functions.c
@@ -256,6 +256,112 @@ int ir_decode_biphase(u32 *samples, int count, int low, int high)
return value;
}
+/* RC5 decoding stuff, moved from bttv-input.c to share it with
+ * saa7134 */
+
+/* decode raw bit pattern to RC5 code */
+u32 ir_rc5_decode(unsigned int code)
+{
+ unsigned int org_code = code;
+ unsigned int pair;
+ unsigned int rc5 = 0;
+ int i;
+
+ for (i = 0; i < 14; ++i) {
+ pair = code & 0x3;
+ code >>= 2;
+
+ rc5 <<= 1;
+ switch (pair) {
+ case 0:
+ case 2:
+ break;
+ case 1:
+ rc5 |= 1;
+ break;
+ case 3:
+ dprintk(1, "ir-common: ir_rc5_decode(%x) bad code\n", org_code);
+ return 0;
+ }
+ }
+ dprintk(1, "ir-common: code=%x, rc5=%x, start=%x, toggle=%x, address=%x, "
+ "instr=%x\n", rc5, org_code, RC5_START(rc5),
+ RC5_TOGGLE(rc5), RC5_ADDR(rc5), RC5_INSTR(rc5));
+ return rc5;
+}
+
+void ir_rc5_timer_end(unsigned long data)
+{
+ struct card_ir *ir = (struct card_ir *)data;
+ struct timeval tv;
+ unsigned long current_jiffies, timeout;
+ u32 gap;
+ u32 rc5 = 0;
+
+ /* get time */
+ current_jiffies = jiffies;
+ do_gettimeofday(&tv);
+
+ /* avoid overflow with gap >1s */
+ if (tv.tv_sec - ir->base_time.tv_sec > 1) {
+ gap = 200000;
+ } else {
+ gap = 1000000 * (tv.tv_sec - ir->base_time.tv_sec) +
+ tv.tv_usec - ir->base_time.tv_usec;
+ }
+
+ /* Allow some timmer jitter (RC5 is ~24ms anyway so this is ok) */
+ if (gap < 28000) {
+ dprintk(1, "ir-common: spurious timer_end\n");
+ return;
+ }
+
+ ir->active = 0;
+ if (ir->last_bit < 20) {
+ /* ignore spurious codes (caused by light/other remotes) */
+ dprintk(1, "ir-common: short code: %x\n", ir->code);
+ } else {
+ ir->code = (ir->code << ir->shift_by) | 1;
+ rc5 = ir_rc5_decode(ir->code);
+
+ /* two start bits? */
+ if (RC5_START(rc5) != ir->start) {
+ dprintk(1, "ir-common: rc5 start bits invalid: %u\n", RC5_START(rc5));
+
+ /* right address? */
+ } else if (RC5_ADDR(rc5) == ir->addr) {
+ u32 toggle = RC5_TOGGLE(rc5);
+ u32 instr = RC5_INSTR(rc5);
+
+ /* Good code, decide if repeat/repress */
+ if (toggle != RC5_TOGGLE(ir->last_rc5) ||
+ instr != RC5_INSTR(ir->last_rc5)) {
+ dprintk(1, "ir-common: instruction %x, toggle %x\n", instr,
+ toggle);
+ ir_input_nokey(ir->dev, &ir->ir);
+ ir_input_keydown(ir->dev, &ir->ir, instr,
+ instr);
+ }
+
+ /* Set/reset key-up timer */
+ timeout = current_jiffies + (500 + ir->rc5_key_timeout
+ * HZ) / 1000;
+ mod_timer(&ir->timer_keyup, timeout);
+
+ /* Save code for repeat test */
+ ir->last_rc5 = rc5;
+ }
+ }
+}
+
+void ir_rc5_timer_keyup(unsigned long data)
+{
+ struct card_ir *ir = (struct card_ir *)data;
+
+ dprintk(1, "ir-common: key released\n");
+ ir_input_nokey(ir->dev, &ir->ir);
+}
+
EXPORT_SYMBOL_GPL(ir_input_init);
EXPORT_SYMBOL_GPL(ir_input_nokey);
EXPORT_SYMBOL_GPL(ir_input_keydown);
@@ -265,6 +371,10 @@ EXPORT_SYMBOL_GPL(ir_dump_samples);
EXPORT_SYMBOL_GPL(ir_decode_biphase);
EXPORT_SYMBOL_GPL(ir_decode_pulsedistance);
+EXPORT_SYMBOL_GPL(ir_rc5_decode);
+EXPORT_SYMBOL_GPL(ir_rc5_timer_end);
+EXPORT_SYMBOL_GPL(ir_rc5_timer_keyup);
+
/*
* Local variables:
* c-basic-offset: 8
diff --git a/drivers/media/common/ir-keymaps.c b/drivers/media/common/ir-keymaps.c
index f51e02fe365..03b47a262f2 100644
--- a/drivers/media/common/ir-keymaps.c
+++ b/drivers/media/common/ir-keymaps.c
@@ -698,7 +698,6 @@ IR_KEYTAB_TYPE ir_codes_pinnacle_grey[IR_KEYTAB_SIZE] = {
[ 0x29 ] = KEY_TEXT,
[ 0x2a ] = KEY_MEDIA,
[ 0x18 ] = KEY_EPG,
- [ 0x27 ] = KEY_RECORD,
};
EXPORT_SYMBOL_GPL(ir_codes_pinnacle_grey);
@@ -1607,3 +1606,174 @@ IR_KEYTAB_TYPE ir_codes_budget_ci_old[IR_KEYTAB_SIZE] = {
};
EXPORT_SYMBOL_GPL(ir_codes_budget_ci_old);
+
+/*
+ * Marc Fargas <telenieko@telenieko.com>
+ * this is the remote control that comes with the asus p7131
+ * which has a label saying is "Model PC-39"
+ */
+IR_KEYTAB_TYPE ir_codes_asus_pc39[IR_KEYTAB_SIZE] = {
+ /* Keys 0 to 9 */
+ [ 0x15 ] = KEY_0,
+ [ 0x29 ] = KEY_1,
+ [ 0x2d ] = KEY_2,
+ [ 0x2b ] = KEY_3,
+ [ 0x09 ] = KEY_4,
+ [ 0x0d ] = KEY_5,
+ [ 0x0b ] = KEY_6,
+ [ 0x31 ] = KEY_7,
+ [ 0x35 ] = KEY_8,
+ [ 0x33 ] = KEY_9,
+
+ [ 0x3e ] = KEY_RADIO, /* radio */
+ [ 0x03 ] = KEY_MENU, /* dvd/menu */
+ [ 0x2a ] = KEY_VOLUMEUP,
+ [ 0x19 ] = KEY_VOLUMEDOWN,
+ [ 0x37 ] = KEY_UP,
+ [ 0x3b ] = KEY_DOWN,
+ [ 0x27 ] = KEY_LEFT,
+ [ 0x2f ] = KEY_RIGHT,
+ [ 0x25 ] = KEY_VIDEO, /* video */
+ [ 0x39 ] = KEY_AUDIO, /* music */
+
+ [ 0x21 ] = KEY_TV, /* tv */
+ [ 0x1d ] = KEY_EXIT, /* back */
+ [ 0x0a ] = KEY_CHANNELUP, /* channel / program + */
+ [ 0x1b ] = KEY_CHANNELDOWN, /* channel / program - */
+ [ 0x1a ] = KEY_ENTER, /* enter */
+
+ [ 0x06 ] = KEY_PAUSE, /* play/pause */
+ [ 0x1e ] = KEY_PREVIOUS, /* rew */
+ [ 0x26 ] = KEY_NEXT, /* forward */
+ [ 0x0e ] = KEY_REWIND, /* backward << */
+ [ 0x3a ] = KEY_FASTFORWARD, /* forward >> */
+ [ 0x36 ] = KEY_STOP,
+ [ 0x2e ] = KEY_RECORD, /* recording */
+ [ 0x16 ] = KEY_POWER, /* the button that reads "close" */
+
+ [ 0x11 ] = KEY_ZOOM, /* full screen */
+ [ 0x13 ] = KEY_MACRO, /* recall */
+ [ 0x23 ] = KEY_HOME, /* home */
+ [ 0x05 ] = KEY_PVR, /* picture */
+ [ 0x3d ] = KEY_MUTE, /* mute */
+ [ 0x01 ] = KEY_DVD, /* dvd */
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_asus_pc39);
+
+
+/* Encore ENLTV-FM - black plastic, white front cover with white glowing buttons
+ Juan Pablo Sormani <sorman@gmail.com> */
+IR_KEYTAB_TYPE ir_codes_encore_enltv[IR_KEYTAB_SIZE] = {
+
+ /* Power button does nothing, neither in Windows app,
+ although it sends data (used for BIOS wakeup?) */
+ [ 0x0d ] = KEY_MUTE,
+
+ [ 0x1e ] = KEY_TV,
+ [ 0x00 ] = KEY_VIDEO,
+ [ 0x01 ] = KEY_AUDIO, /* music */
+ [ 0x02 ] = KEY_MHP, /* picture */
+
+ [ 0x1f ] = KEY_1,
+ [ 0x03 ] = KEY_2,
+ [ 0x04 ] = KEY_3,
+ [ 0x05 ] = KEY_4,
+ [ 0x1c ] = KEY_5,
+ [ 0x06 ] = KEY_6,
+ [ 0x07 ] = KEY_7,
+ [ 0x08 ] = KEY_8,
+ [ 0x1d ] = KEY_9,
+ [ 0x0a ] = KEY_0,
+
+ [ 0x09 ] = KEY_LIST, /* -/-- */
+ [ 0x0b ] = KEY_LAST, /* recall */
+
+ [ 0x14 ] = KEY_HOME, /* win start menu */
+ [ 0x15 ] = KEY_EXIT, /* exit */
+ [ 0x16 ] = KEY_UP,
+ [ 0x12 ] = KEY_DOWN,
+ [ 0x0c ] = KEY_RIGHT,
+ [ 0x17 ] = KEY_LEFT,
+
+ [ 0x18 ] = KEY_ENTER, /* OK */
+
+ [ 0x0e ] = KEY_ESC,
+ [ 0x13 ] = KEY_D, /* desktop */
+ [ 0x11 ] = KEY_TAB,
+ [ 0x19 ] = KEY_SWITCHVIDEOMODE, /* switch */
+
+ [ 0x1a ] = KEY_MENU,
+ [ 0x1b ] = KEY_ZOOM, /* fullscreen */
+ [ 0x44 ] = KEY_TIME, /* time shift */
+ [ 0x40 ] = KEY_MODE, /* source */
+
+ [ 0x5a ] = KEY_RECORD,
+ [ 0x42 ] = KEY_PLAY, /* play/pause */
+ [ 0x45 ] = KEY_STOP,
+ [ 0x43 ] = KEY_CAMERA, /* camera icon */
+
+ [ 0x48 ] = KEY_REWIND,
+ [ 0x4a ] = KEY_FASTFORWARD,
+ [ 0x49 ] = KEY_PREVIOUS,
+ [ 0x4b ] = KEY_NEXT,
+
+ [ 0x4c ] = KEY_FAVORITES, /* tv wall */
+ [ 0x4d ] = KEY_SOUND, /* DVD sound */
+ [ 0x4e ] = KEY_LANGUAGE, /* DVD lang */
+ [ 0x4f ] = KEY_TEXT, /* DVD text */
+
+ [ 0x50 ] = KEY_SLEEP, /* shutdown */
+ [ 0x51 ] = KEY_MODE, /* stereo > main */
+ [ 0x52 ] = KEY_SELECT, /* stereo > sap */
+ [ 0x53 ] = KEY_PROG1, /* teletext */
+
+
+ [ 0x59 ] = KEY_RED, /* AP1 */
+ [ 0x41 ] = KEY_GREEN, /* AP2 */
+ [ 0x47 ] = KEY_YELLOW, /* AP3 */
+ [ 0x57 ] = KEY_BLUE, /* AP4 */
+
+
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_encore_enltv);
+
+/* for the Technotrend 1500 bundled remote: */
+IR_KEYTAB_TYPE ir_codes_tt_1500[IR_KEYTAB_SIZE] = {
+ [ 0x01 ] = KEY_POWER,
+ [ 0x02 ] = KEY_SHUFFLE, /* ? double-arrow key */
+ [ 0x03 ] = KEY_1,
+ [ 0x04 ] = KEY_2,
+ [ 0x05 ] = KEY_3,
+ [ 0x06 ] = KEY_4,
+ [ 0x07 ] = KEY_5,
+ [ 0x08 ] = KEY_6,
+ [ 0x09 ] = KEY_7,
+ [ 0x0a ] = KEY_8,
+ [ 0x0b ] = KEY_9,
+ [ 0x0c ] = KEY_0,
+ [ 0x0d ] = KEY_UP,
+ [ 0x0e ] = KEY_LEFT,
+ [ 0x0f ] = KEY_OK,
+ [ 0x10 ] = KEY_RIGHT,
+ [ 0x11 ] = KEY_DOWN,
+ [ 0x12 ] = KEY_INFO,
+ [ 0x13 ] = KEY_EXIT,
+ [ 0x14 ] = KEY_RED,
+ [ 0x15 ] = KEY_GREEN,
+ [ 0x16 ] = KEY_YELLOW,
+ [ 0x17 ] = KEY_BLUE,
+ [ 0x18 ] = KEY_MUTE,
+ [ 0x19 ] = KEY_TEXT,
+ [ 0x1a ] = KEY_MODE, /* ? TV/Radio */
+ [ 0x21 ] = KEY_OPTION,
+ [ 0x22 ] = KEY_EPG,
+ [ 0x23 ] = KEY_CHANNELUP,
+ [ 0x24 ] = KEY_CHANNELDOWN,
+ [ 0x25 ] = KEY_VOLUMEUP,
+ [ 0x26 ] = KEY_VOLUMEDOWN,
+ [ 0x27 ] = KEY_SETUP,
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_tt_1500);
diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c
index d867a6a9e43..c18a5da6493 100644
--- a/drivers/media/common/saa7146_fops.c
+++ b/drivers/media/common/saa7146_fops.c
@@ -416,7 +416,7 @@ static ssize_t fops_write(struct file *file, const char __user *data, size_t cou
}
}
-static struct file_operations video_fops =
+static const struct file_operations video_fops =
{
.owner = THIS_MODULE,
.open = fops_open,
@@ -508,7 +508,7 @@ int saa7146_vv_release(struct saa7146_dev* dev)
DEB_EE(("dev:%p\n",dev));
- pci_free_consistent(dev->pci, SAA7146_RPS_MEM, vv->d_clipping.cpu_addr, vv->d_clipping.dma_handle);
+ pci_free_consistent(dev->pci, SAA7146_CLIPPING_MEM, vv->d_clipping.cpu_addr, vv->d_clipping.dma_handle);
kfree(vv);
dev->vv_data = NULL;
dev->vv_callback = NULL;
diff --git a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
index c2b35e36624..752cf79c532 100644
--- a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
+++ b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
@@ -385,9 +385,9 @@ static int alps_tdee4_stv0297_tuner_set_params(struct dvb_frontend* fe,
else buf[3] = 0x88;
if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
+ fe->ops.i2c_gate_ctrl(fe, 0);
deb_tuner("tuner buffer for %d Hz: %x %x %x %x\n",fep->frequency, buf[0],buf[1],buf[2],buf[3]);
- ret = fc->i2c_request(fc,FC_WRITE,FC_I2C_PORT_TUNER,0x61,buf[0],&buf[1],3);
+ ret = fc->i2c_request(fc, FC_WRITE, FC_I2C_PORT_TUNER, 0x61, buf[0], &buf[1], 3);
deb_tuner("tuner write returned: %d\n",ret);
return 0;
@@ -398,91 +398,71 @@ static u8 alps_tdee4_stv0297_inittab[] = {
0x80, 0x00,
0x81, 0x01,
0x81, 0x00,
- 0x00, 0x09,
- 0x01, 0x69,
+ 0x00, 0x48,
+ 0x01, 0x58,
0x03, 0x00,
0x04, 0x00,
0x07, 0x00,
0x08, 0x00,
- 0x20, 0x00,
- 0x21, 0x40,
- 0x22, 0x00,
- 0x23, 0x00,
- 0x24, 0x40,
- 0x25, 0x88,
0x30, 0xff,
- 0x31, 0x00,
+ 0x31, 0x9d,
0x32, 0xff,
0x33, 0x00,
- 0x34, 0x50,
- 0x35, 0x7f,
- 0x36, 0x00,
- 0x37, 0x20,
- 0x38, 0x00,
- 0x40, 0x1c,
- 0x41, 0xff,
- 0x42, 0x29,
+ 0x34, 0x29,
+ 0x35, 0x55,
+ 0x36, 0x80,
+ 0x37, 0x6e,
+ 0x38, 0x9c,
+ 0x40, 0x1a,
+ 0x41, 0xfe,
+ 0x42, 0x33,
0x43, 0x00,
0x44, 0xff,
0x45, 0x00,
0x46, 0x00,
0x49, 0x04,
- 0x4a, 0x00,
+ 0x4a, 0x51,
0x4b, 0xf8,
0x52, 0x30,
- 0x55, 0xae,
- 0x56, 0x47,
- 0x57, 0xe1,
- 0x58, 0x3a,
- 0x5a, 0x1e,
- 0x5b, 0x34,
- 0x60, 0x00,
- 0x63, 0x00,
- 0x64, 0x00,
- 0x65, 0x00,
- 0x66, 0x00,
- 0x67, 0x00,
- 0x68, 0x00,
- 0x69, 0x00,
- 0x6a, 0x02,
- 0x6b, 0x00,
+ 0x53, 0x06,
+ 0x59, 0x06,
+ 0x5a, 0x5e,
+ 0x5b, 0x04,
+ 0x61, 0x49,
+ 0x62, 0x0a,
0x70, 0xff,
- 0x71, 0x00,
+ 0x71, 0x04,
0x72, 0x00,
0x73, 0x00,
0x74, 0x0c,
- 0x80, 0x00,
+ 0x80, 0x20,
0x81, 0x00,
- 0x82, 0x00,
+ 0x82, 0x30,
0x83, 0x00,
0x84, 0x04,
- 0x85, 0x80,
- 0x86, 0x24,
- 0x87, 0x78,
- 0x88, 0x10,
+ 0x85, 0x22,
+ 0x86, 0x08,
+ 0x87, 0x1b,
+ 0x88, 0x00,
0x89, 0x00,
- 0x90, 0x01,
- 0x91, 0x01,
- 0xa0, 0x04,
+ 0x90, 0x00,
+ 0x91, 0x04,
+ 0xa0, 0x86,
0xa1, 0x00,
0xa2, 0x00,
0xb0, 0x91,
0xb1, 0x0b,
- 0xc0, 0x53,
- 0xc1, 0x70,
+ 0xc0, 0x5b,
+ 0xc1, 0x10,
0xc2, 0x12,
- 0xd0, 0x00,
+ 0xd0, 0x02,
0xd1, 0x00,
0xd2, 0x00,
0xd3, 0x00,
- 0xd4, 0x00,
+ 0xd4, 0x02,
0xd5, 0x00,
0xde, 0x00,
- 0xdf, 0x00,
- 0x61, 0x49,
- 0x62, 0x0b,
- 0x53, 0x08,
- 0x59, 0x08,
+ 0xdf, 0x01,
0xff, 0xff,
};
diff --git a/drivers/media/dvb/b2c2/flexcop-i2c.c b/drivers/media/dvb/b2c2/flexcop-i2c.c
index e0bd2d8f0f0..5347a406fff 100644
--- a/drivers/media/dvb/b2c2/flexcop-i2c.c
+++ b/drivers/media/dvb/b2c2/flexcop-i2c.c
@@ -190,6 +190,7 @@ int flexcop_i2c_init(struct flexcop_device *fc)
fc->i2c_adap.class = I2C_CLASS_TV_DIGITAL;
fc->i2c_adap.algo = &flexcop_algo;
fc->i2c_adap.algo_data = NULL;
+ fc->i2c_adap.dev.parent = fc->dev;
if ((ret = i2c_add_adapter(&fc->i2c_adap)) < 0)
return ret;
diff --git a/drivers/media/dvb/bt8xx/bt878.c b/drivers/media/dvb/bt8xx/bt878.c
index 329a51c1856..83b090ef244 100644
--- a/drivers/media/dvb/bt8xx/bt878.c
+++ b/drivers/media/dvb/bt8xx/bt878.c
@@ -390,6 +390,7 @@ static struct cards card_list[] __devinitdata = {
{ 0xfc00270f, BTTV_BOARD_TWINHAN_DST, "ChainTech digitop DST-1000 DVB-S" },
{ 0x07711461, BTTV_BOARD_AVDVBT_771, "AVermedia AverTV DVB-T 771" },
{ 0xdb1018ac, BTTV_BOARD_DVICO_DVBT_LITE, "DViCO FusionHDTV DVB-T Lite" },
+ { 0xdb1118ac, BTTV_BOARD_DVICO_DVBT_LITE, "Ultraview DVB-T Lite" },
{ 0xd50018ac, BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE, "DViCO FusionHDTV 5 Lite" },
{ 0x20007063, BTTV_BOARD_PC_HDTV, "pcHDTV HD-2000 TV" },
{ 0x00261822, BTTV_BOARD_TWINHAN_DST, "DNTV Live! Mini" },
diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c
index 9f72b7000c0..0393a3d1992 100644
--- a/drivers/media/dvb/bt8xx/dst.c
+++ b/drivers/media/dvb/bt8xx/dst.c
@@ -1161,7 +1161,7 @@ static int dst_get_device_id(struct dst_state *state)
}
}
- if (i >= sizeof (dst_tlist) / sizeof (dst_tlist [0])) {
+ if (i >= ARRAY_SIZE(dst_tlist)) {
dprintk(verbose, DST_ERROR, 1, "Unable to recognize %s or %s", &state->rxbuffer[0], &state->rxbuffer[1]);
dprintk(verbose, DST_ERROR, 1, "please email linux-dvb@linuxtv.org with this type in");
use_dst_type = DST_TYPE_IS_SAT;
diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
index 3e35931af35..58f69f6ae39 100644
--- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c
+++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
@@ -23,6 +23,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
+#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/slab.h>
@@ -213,7 +214,7 @@ static int cx24108_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend
freq = 2150000; /* satellite IF is 950..2150MHz */
/* decide which VCO to use for the input frequency */
- for(i=1;(i<sizeof(osci)/sizeof(osci[0]))&&(osci[i]<freq);i++);
+ for(i = 1; (i < ARRAY_SIZE(osci)) && (osci[i] < freq); i++);
printk("cx24108 debug: select vco #%d (f=%d)\n",i,freq);
band=bandsel[i];
/* the gain values must be set by SetSymbolrate */
diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c
index d64b96cb0c4..a6cbbdd262d 100644
--- a/drivers/media/dvb/cinergyT2/cinergyT2.c
+++ b/drivers/media/dvb/cinergyT2/cinergyT2.c
@@ -819,6 +819,11 @@ static int cinergyt2_register_rc(struct cinergyt2 *cinergyt2)
set_bit(rc_keys[i + 2], input_dev->keybit);
input_dev->keycodesize = 0;
input_dev->keycodemax = 0;
+ input_dev->id.bustype = BUS_USB;
+ input_dev->id.vendor = cinergyt2->udev->descriptor.idVendor;
+ input_dev->id.product = cinergyt2->udev->descriptor.idProduct;
+ input_dev->id.version = 1;
+ input_dev->cdev.dev = &cinergyt2->udev->dev;
err = input_register_device(input_dev);
if (err) {
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index 988499dfddf..fc77de45ca4 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -25,7 +25,6 @@
#include <linux/vmalloc.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <linux/sched.h>
#include <linux/poll.h>
#include <linux/ioctl.h>
#include <linux/wait.h>
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
index e85972222ab..a21a894d3f9 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -36,6 +36,7 @@
#include <linux/list.h>
#include <linux/freezer.h>
#include <linux/jiffies.h>
+#include <linux/kthread.h>
#include <asm/processor.h>
#include "dvb_frontend.h"
@@ -100,7 +101,7 @@ struct dvb_frontend_private {
struct semaphore sem;
struct list_head list_head;
wait_queue_head_t wait_queue;
- pid_t thread_pid;
+ struct task_struct *thread;
unsigned long release_jiffies;
unsigned int exit;
unsigned int wakeup;
@@ -508,19 +509,11 @@ static int dvb_frontend_thread(void *data)
struct dvb_frontend *fe = data;
struct dvb_frontend_private *fepriv = fe->frontend_priv;
unsigned long timeout;
- char name [15];
fe_status_t s;
struct dvb_frontend_parameters *params;
dprintk("%s\n", __FUNCTION__);
- snprintf (name, sizeof(name), "kdvb-fe-%i", fe->dvb->num);
-
- lock_kernel();
- daemonize(name);
- sigfillset(&current->blocked);
- unlock_kernel();
-
fepriv->check_wrapped = 0;
fepriv->quality = 0;
fepriv->delay = 3*HZ;
@@ -532,16 +525,18 @@ static int dvb_frontend_thread(void *data)
while (1) {
up(&fepriv->sem); /* is locked when we enter the thread... */
-
+restart:
timeout = wait_event_interruptible_timeout(fepriv->wait_queue,
- dvb_frontend_should_wakeup(fe),
- fepriv->delay);
- if (0 != dvb_frontend_is_exiting(fe)) {
+ dvb_frontend_should_wakeup(fe) || kthread_should_stop(),
+ fepriv->delay);
+
+ if (kthread_should_stop() || dvb_frontend_is_exiting(fe)) {
/* got signal or quitting */
break;
}
- try_to_freeze();
+ if (try_to_freeze())
+ goto restart;
if (down_interruptible(&fepriv->sem))
break;
@@ -591,7 +586,7 @@ static int dvb_frontend_thread(void *data)
fe->ops.sleep(fe);
}
- fepriv->thread_pid = 0;
+ fepriv->thread = NULL;
mb();
dvb_frontend_wakeup(fe);
@@ -600,7 +595,6 @@ static int dvb_frontend_thread(void *data)
static void dvb_frontend_stop(struct dvb_frontend *fe)
{
- unsigned long ret;
struct dvb_frontend_private *fepriv = fe->frontend_priv;
dprintk ("%s\n", __FUNCTION__);
@@ -608,33 +602,17 @@ static void dvb_frontend_stop(struct dvb_frontend *fe)
fepriv->exit = 1;
mb();
- if (!fepriv->thread_pid)
+ if (!fepriv->thread)
return;
- /* check if the thread is really alive */
- if (kill_proc(fepriv->thread_pid, 0, 1) == -ESRCH) {
- printk("dvb_frontend_stop: thread PID %d already died\n",
- fepriv->thread_pid);
- /* make sure the mutex was not held by the thread */
- init_MUTEX (&fepriv->sem);
- return;
- }
-
- /* wake up the frontend thread, so it notices that fe->exit == 1 */
- dvb_frontend_wakeup(fe);
-
- /* wait until the frontend thread has exited */
- ret = wait_event_interruptible(fepriv->wait_queue,0 == fepriv->thread_pid);
- if (-ERESTARTSYS != ret) {
- fepriv->state = FESTATE_IDLE;
- return;
- }
+ kthread_stop(fepriv->thread);
+ init_MUTEX (&fepriv->sem);
fepriv->state = FESTATE_IDLE;
/* paranoia check in case a signal arrived */
- if (fepriv->thread_pid)
- printk("dvb_frontend_stop: warning: thread PID %d won't exit\n",
- fepriv->thread_pid);
+ if (fepriv->thread)
+ printk("dvb_frontend_stop: warning: thread %p won't exit\n",
+ fepriv->thread);
}
s32 timeval_usec_diff(struct timeval lasttime, struct timeval curtime)
@@ -684,10 +662,11 @@ static int dvb_frontend_start(struct dvb_frontend *fe)
{
int ret;
struct dvb_frontend_private *fepriv = fe->frontend_priv;
+ struct task_struct *fe_thread;
dprintk ("%s\n", __FUNCTION__);
- if (fepriv->thread_pid) {
+ if (fepriv->thread) {
if (!fepriv->exit)
return 0;
else
@@ -701,18 +680,18 @@ static int dvb_frontend_start(struct dvb_frontend *fe)
fepriv->state = FESTATE_IDLE;
fepriv->exit = 0;
- fepriv->thread_pid = 0;
+ fepriv->thread = NULL;
mb();
- ret = kernel_thread (dvb_frontend_thread, fe, 0);
-
- if (ret < 0) {
- printk("dvb_frontend_start: failed to start kernel_thread (%d)\n", ret);
+ fe_thread = kthread_run(dvb_frontend_thread, fe,
+ "kdvb-fe-%i", fe->dvb->num);
+ if (IS_ERR(fe_thread)) {
+ ret = PTR_ERR(fe_thread);
+ printk("dvb_frontend_start: failed to start kthread (%d)\n", ret);
up(&fepriv->sem);
return ret;
}
- fepriv->thread_pid = ret;
-
+ fepriv->thread = fe_thread;
return 0;
}
@@ -915,7 +894,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
fetunesettings.parameters.inversion = INVERSION_AUTO;
}
if (fe->ops.info.type == FE_OFDM) {
- /* without hierachical coding code_rate_LP is irrelevant,
+ /* without hierarchical coding code_rate_LP is irrelevant,
* so we tolerate the otherwise invalid FEC_NONE setting */
if (fepriv->parameters.u.ofdm.hierarchy_information == HIERARCHY_NONE &&
fepriv->parameters.u.ofdm.code_rate_LP == FEC_NONE)
diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c
index 40774feb895..490337b5ee3 100644
--- a/drivers/media/dvb/dvb-core/dvbdev.c
+++ b/drivers/media/dvb/dvb-core/dvbdev.c
@@ -27,7 +27,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/device.h>
@@ -200,12 +199,14 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
const struct dvb_device *template, void *priv, int type)
{
struct dvb_device *dvbdev;
+ struct file_operations *dvbdevfops;
+
int id;
if (mutex_lock_interruptible(&dvbdev_register_lock))
return -ERESTARTSYS;
- if ((id = dvbdev_get_free_id (adap, type)) < 0) {
+ if ((id = dvbdev_get_free_id (adap, type)) < 0){
mutex_unlock(&dvbdev_register_lock);
*pdvbdev = NULL;
printk ("%s: could get find free device id...\n", __FUNCTION__);
@@ -214,7 +215,15 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
*pdvbdev = dvbdev = kmalloc(sizeof(struct dvb_device), GFP_KERNEL);
- if (!dvbdev) {
+ if (!dvbdev){
+ mutex_unlock(&dvbdev_register_lock);
+ return -ENOMEM;
+ }
+
+ dvbdevfops = kzalloc(sizeof(struct file_operations), GFP_KERNEL);
+
+ if (!dvbdevfops){
+ kfree (dvbdev);
mutex_unlock(&dvbdev_register_lock);
return -ENOMEM;
}
@@ -224,7 +233,9 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
dvbdev->id = id;
dvbdev->adapter = adap;
dvbdev->priv = priv;
+ dvbdev->fops = dvbdevfops;
+ memcpy(dvbdev->fops, template->fops, sizeof(struct file_operations));
dvbdev->fops->owner = adap->module;
list_add_tail (&dvbdev->list_head, &adap->device_list);
@@ -252,6 +263,7 @@ void dvb_unregister_device(struct dvb_device *dvbdev)
dvbdev->type, dvbdev->id)));
list_del (&dvbdev->list_head);
+ kfree (dvbdev->fops);
kfree (dvbdev);
}
EXPORT_SYMBOL(dvb_unregister_device);
diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
index ad52143602c..80f67a51b90 100644
--- a/drivers/media/dvb/dvb-usb/Kconfig
+++ b/drivers/media/dvb/dvb-usb/Kconfig
@@ -109,6 +109,34 @@ config DVB_USB_CXUSB
Medion MD95700 hybrid USB2.0 device.
DViCO FusionHDTV (Bluebird) USB2.0 devices
+config DVB_USB_M920X
+ tristate "Uli m920x DVB-T USB2.0 support"
+ depends on DVB_USB
+ select DVB_MT352 if !DVB_FE_CUSTOMISE
+ select DVB_TUNER_QT1010 if !DVB_FE_CUSTOMISE
+ help
+ Say Y here to support the MSI Mega Sky 580 USB2.0 DVB-T receiver.
+ Currently, only devices with a product id of
+ "DTV USB MINI" (in cold state) are supported.
+ Firmware required.
+
+config DVB_USB_GL861
+ tristate "Genesys Logic GL861 USB2.0 support"
+ depends on DVB_USB
+ select DVB_ZL10353 if !DVB_FE_CUSTOMISE
+ select DVB_TUNER_QT1010 if !DVB_FE_CUSTOMISE
+ help
+ Say Y here to support the MSI Megasky 580 (55801) DVB-T USB2.0
+ receiver with USB ID 0db0:5581.
+
+config DVB_USB_AU6610
+ tristate "Alcor Micro AU6610 USB2.0 support"
+ depends on DVB_USB
+ select DVB_ZL10353 if !DVB_FE_CUSTOMISE
+ select DVB_TUNER_QT1010 if !DVB_FE_CUSTOMISE
+ help
+ Say Y here to support the Sigmatek DVB-110 DVB-T USB2.0 receiver.
+
config DVB_USB_DIGITV
tristate "Nebula Electronics uDigiTV DVB-T USB2.0 support"
depends on DVB_USB
diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile
index 154d593bbb0..40f28f559b5 100644
--- a/drivers/media/dvb/dvb-usb/Makefile
+++ b/drivers/media/dvb/dvb-usb/Makefile
@@ -30,6 +30,15 @@ obj-$(CONFIG_DVB_USB_NOVA_T_USB2) += dvb-usb-dibusb-common.o dvb-usb-nova-t-usb2
dvb-usb-umt-010-objs = umt-010.o
obj-$(CONFIG_DVB_USB_UMT_010) += dvb-usb-dibusb-common.o dvb-usb-umt-010.o
+dvb-usb-m920x-objs = m920x.o
+obj-$(CONFIG_DVB_USB_M920X) += dvb-usb-m920x.o
+
+dvb-usb-gl861-objs = gl861.o
+obj-$(CONFIG_DVB_USB_GL861) += dvb-usb-gl861.o
+
+dvb-usb-au6610-objs = au6610.o
+obj-$(CONFIG_DVB_USB_AU6610) += dvb-usb-au6610.o
+
dvb-usb-digitv-objs = digitv.o
obj-$(CONFIG_DVB_USB_DIGITV) += dvb-usb-digitv.o
diff --git a/drivers/media/dvb/dvb-usb/au6610.c b/drivers/media/dvb/dvb-usb/au6610.c
new file mode 100644
index 00000000000..0dc66a8d2ba
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/au6610.c
@@ -0,0 +1,255 @@
+/* DVB USB compliant linux driver for Sigmatek DVB-110 DVB-T USB2.0 receiver
+ *
+ * Copyright (C) 2006 Antti Palosaari <crope@iki.fi>
+ *
+ * This program is free software; 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 "au6610.h"
+
+#include "zl10353.h"
+#include "qt1010.h"
+
+/* debug */
+static int dvb_usb_au6610_debug;
+module_param_named(debug, dvb_usb_au6610_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
+
+static int au6610_usb_msg(struct dvb_usb_device *d, u8 operation, u8 addr,
+ u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
+{
+ int ret;
+ u16 index;
+ u8 usb_buf[6]; /* enough for all known requests,
+ read returns 5 and write 6 bytes */
+ switch (wlen) {
+ case 1:
+ index = wbuf[0] << 8;
+ break;
+ case 2:
+ index = wbuf[0] << 8;
+ index += wbuf[1];
+ break;
+ default:
+ warn("wlen = %x, aborting.", wlen);
+ return -EINVAL;
+ }
+
+ ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), operation,
+ USB_TYPE_VENDOR|USB_DIR_IN, addr, index, usb_buf,
+ sizeof(usb_buf), AU6610_USB_TIMEOUT);
+
+ if (ret < 0)
+ return ret;
+
+ switch (operation) {
+ case AU6610_REQ_I2C_READ:
+ case AU6610_REQ_USB_READ:
+ /* requested value is always 5th byte in buffer */
+ rbuf[0] = usb_buf[4];
+ }
+
+ return ret;
+}
+
+static int au6610_i2c_msg(struct dvb_usb_device *d, u8 addr,
+ u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
+{
+ u8 request;
+ u8 wo = (rbuf == NULL || rlen == 0); /* write-only */
+
+ if (wo) {
+ request = AU6610_REQ_I2C_WRITE;
+ } else { /* rw */
+ request = AU6610_REQ_I2C_READ;
+ }
+
+ return au6610_usb_msg(d, request, addr, wbuf, wlen, rbuf, rlen);
+}
+
+
+/* I2C */
+static int au6610_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+ int num)
+{
+ struct dvb_usb_device *d = i2c_get_adapdata(adap);
+ int i;
+
+ if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+ return -EAGAIN;
+
+ if (num > 2)
+ return -EINVAL;
+
+ for (i = 0; i < num; i++) {
+ /* write/read request */
+ if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
+ if (au6610_i2c_msg(d, msg[i].addr, msg[i].buf,
+ msg[i].len, msg[i+1].buf,
+ msg[i+1].len) < 0)
+ break;
+ i++;
+ } else if (au6610_i2c_msg(d, msg[i].addr, msg[i].buf,
+ msg[i].len, NULL, 0) < 0)
+ break;
+ }
+
+ mutex_unlock(&d->i2c_mutex);
+ return i;
+}
+
+
+static u32 au6610_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm au6610_i2c_algo = {
+ .master_xfer = au6610_i2c_xfer,
+ .functionality = au6610_i2c_func,
+};
+
+/* Callbacks for DVB USB */
+static int au6610_identify_state(struct usb_device *udev,
+ struct dvb_usb_device_properties *props,
+ struct dvb_usb_device_description **desc,
+ int *cold)
+{
+ *cold = 0;
+ return 0;
+}
+
+static struct zl10353_config au6610_zl10353_config = {
+ .demod_address = 0x1e,
+ .no_tuner = 1,
+ .parallel_ts = 1,
+};
+
+static int au6610_zl10353_frontend_attach(struct dvb_usb_adapter *adap)
+{
+ if ((adap->fe = dvb_attach(zl10353_attach, &au6610_zl10353_config,
+ &adap->dev->i2c_adap)) != NULL) {
+ return 0;
+ }
+
+ return -EIO;
+}
+
+static struct qt1010_config au6610_qt1010_config = {
+ .i2c_address = 0xc4
+};
+
+static int au6610_qt1010_tuner_attach(struct dvb_usb_adapter *adap)
+{
+ return dvb_attach(qt1010_attach,
+ adap->fe, &adap->dev->i2c_adap,
+ &au6610_qt1010_config) == NULL ? -ENODEV : 0;
+}
+
+/* DVB USB Driver stuff */
+static struct dvb_usb_device_properties au6610_properties;
+
+static int au6610_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct dvb_usb_device *d;
+ struct usb_host_interface *alt;
+ int ret;
+
+ if (intf->num_altsetting < AU6610_ALTSETTING_COUNT)
+ return -ENODEV;
+
+ if ((ret = dvb_usb_device_init(intf, &au6610_properties, THIS_MODULE, &d)) == 0) {
+ alt = usb_altnum_to_altsetting(intf, AU6610_ALTSETTING);
+
+ if (alt == NULL) {
+ deb_rc("no alt found!\n");
+ return -ENODEV;
+ }
+ ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber,
+ alt->desc.bAlternateSetting);
+ }
+
+ return ret;
+}
+
+
+static struct usb_device_id au6610_table [] = {
+ { USB_DEVICE(USB_VID_ALCOR_MICRO, USB_PID_SIGMATEK_DVB_110) },
+ { } /* Terminating entry */
+};
+MODULE_DEVICE_TABLE (usb, au6610_table);
+
+static struct dvb_usb_device_properties au6610_properties = {
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+ .usb_ctrl = DEVICE_SPECIFIC,
+ .size_of_priv = 0,
+ .identify_state = au6610_identify_state,
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .frontend_attach = au6610_zl10353_frontend_attach,
+ .tuner_attach = au6610_qt1010_tuner_attach,
+
+ .stream = {
+ .type = USB_ISOC,
+ .count = 5,
+ .endpoint = 0x82,
+ .u = {
+ .isoc = {
+ .framesperurb = 40,
+ .framesize = 942, /* maximum packet size */
+ .interval = 1.25, /* 125 us */
+ }
+ }
+ },
+ }
+ },
+ .i2c_algo = &au6610_i2c_algo,
+ .num_device_descs = 1,
+ .devices = {
+ {
+ "Sigmatek DVB-110 DVB-T USB2.0",
+ { &au6610_table[0], NULL },
+ { NULL },
+ },
+ }
+};
+
+static struct usb_driver au6610_driver = {
+ .name = "dvb_usb_au6610",
+ .probe = au6610_probe,
+ .disconnect = dvb_usb_device_exit,
+ .id_table = au6610_table,
+};
+
+/* module stuff */
+static int __init au6610_module_init(void)
+{
+ int ret;
+
+ if ((ret = usb_register(&au6610_driver))) {
+ err("usb_register failed. Error number %d", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void __exit au6610_module_exit(void)
+{
+ /* deregister this driver from the USB subsystem */
+ usb_deregister(&au6610_driver);
+}
+
+module_init (au6610_module_init);
+module_exit (au6610_module_exit);
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("Driver Sigmatek DVB-110 DVB-T USB2.0 / AU6610");
+MODULE_VERSION("0.1");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/au6610.h b/drivers/media/dvb/dvb-usb/au6610.h
new file mode 100644
index 00000000000..4161b054c71
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/au6610.h
@@ -0,0 +1,19 @@
+#ifndef _DVB_USB_AU6610_H_
+#define _DVB_USB_AU6610_H_
+
+#define DVB_USB_LOG_PREFIX "au6610"
+#include "dvb-usb.h"
+
+#define deb_rc(args...) dprintk(dvb_usb_au6610_debug,0x01,args)
+
+#define AU6610_REQ_I2C_WRITE 0x14
+#define AU6610_REQ_I2C_READ 0x13
+#define AU6610_REQ_USB_WRITE 0x16
+#define AU6610_REQ_USB_READ 0x15
+
+#define AU6610_USB_TIMEOUT 1000
+
+#define AU6610_ALTSETTING_COUNT 6
+#define AU6610_ALTSETTING 5
+
+#endif
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
index 55ba020386c..70df31b0a8a 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
@@ -27,6 +27,7 @@ int dvb_usb_i2c_init(struct dvb_usb_device *d)
#endif
d->i2c_adap.algo = d->props.i2c_algo;
d->i2c_adap.algo_data = NULL;
+ d->i2c_adap.dev.parent = &d->udev->dev;
i2c_set_adapdata(&d->i2c_adap, d);
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
index 299382dcb81..148386aba27 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
@@ -11,6 +11,7 @@
/* Vendor IDs */
#define USB_VID_ADSTECH 0x06e1
+#define USB_VID_ALCOR_MICRO 0x058f
#define USB_VID_ANCHOR 0x0547
#define USB_VID_AVERMEDIA 0x07ca
#define USB_VID_COMPRO 0x185b
@@ -29,6 +30,7 @@
#define USB_VID_LEADTEK 0x0413
#define USB_VID_LITEON 0x04ca
#define USB_VID_MEDION 0x1660
+#define USB_VID_MSI 0x0db0
#define USB_VID_PINNACLE 0x2304
#define USB_VID_VISIONPLUS 0x13d3
#define USB_VID_TWINHAN 0x1822
@@ -119,6 +121,8 @@
#define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_COLD 0xdb54
#define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM 0xdb55
#define USB_PID_MEDION_MD95700 0x0932
+#define USB_PID_MSI_MEGASKY580 0x5580
+#define USB_PID_MSI_MEGASKY580_55801 0x5581
#define USB_PID_KYE_DVB_T_COLD 0x701e
#define USB_PID_KYE_DVB_T_WARM 0x701f
#define USB_PID_PCTV_200E 0x020e
@@ -134,6 +138,7 @@
#define USB_PID_WINFAST_DTV_DONGLE_STK7700P 0x6f00
#define USB_PID_GENPIX_8PSK_COLD 0x0200
#define USB_PID_GENPIX_8PSK_WARM 0x0201
+#define USB_PID_SIGMATEK_DVB_110 0x6610
#endif
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
index 19ff5978bc9..9511a31c8f5 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
@@ -151,7 +151,7 @@ int dvb_usb_remote_init(struct dvb_usb_device *d)
int dvb_usb_remote_exit(struct dvb_usb_device *d)
{
if (d->state & DVB_USB_STATE_REMOTE) {
- cancel_delayed_work(&d->rc_query_work);
+ cancel_rearming_delayed_work(&d->rc_query_work);
flush_scheduled_work();
input_unregister_device(d->rc_input_dev);
}
diff --git a/drivers/media/dvb/dvb-usb/gl861.c b/drivers/media/dvb/dvb-usb/gl861.c
new file mode 100644
index 00000000000..c9f38a5e70d
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/gl861.c
@@ -0,0 +1,231 @@
+/* DVB USB compliant linux driver for GL861 USB2.0 devices.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "gl861.h"
+
+#include "zl10353.h"
+#include "qt1010.h"
+
+/* debug */
+int dvb_usb_gl861_debug;
+module_param_named(debug,dvb_usb_gl861_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
+
+static int gl861_i2c_msg(struct dvb_usb_device *d, u8 addr,
+ u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
+{
+ u16 index;
+ u16 value = addr << 8;
+ int wo = (rbuf == NULL || rlen == 0); /* write-only */
+ u8 req, type;
+
+ if (wo) {
+ req = GL861_REQ_I2C_WRITE;
+ type = GL861_WRITE;
+ } else { /* rw */
+ req = GL861_REQ_I2C_READ;
+ type = GL861_READ;
+ }
+
+ switch (wlen) {
+ case 1:
+ index = wbuf[0];
+ break;
+ case 2:
+ index = wbuf[0];
+ value = value + wbuf[1];
+ break;
+ default:
+ warn("wlen = %x, aborting.", wlen);
+ return -EINVAL;
+ }
+
+ return usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), req, type,
+ value, index, rbuf, rlen, 2000);
+}
+
+/* I2C */
+static int gl861_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+ int num)
+{
+ struct dvb_usb_device *d = i2c_get_adapdata(adap);
+ int i;
+
+ if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+ return -EAGAIN;
+
+ if (num > 2)
+ return -EINVAL;
+
+ for (i = 0; i < num; i++) {
+ /* write/read request */
+ if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
+ if (gl861_i2c_msg(d, msg[i].addr, msg[i].buf,
+ msg[i].len, msg[i+1].buf, msg[i+1].len) < 0)
+ break;
+ i++;
+ } else
+ if (gl861_i2c_msg(d, msg[i].addr, msg[i].buf,
+ msg[i].len, NULL, 0) < 0)
+ break;
+ }
+
+ mutex_unlock(&d->i2c_mutex);
+ return i;
+}
+
+static u32 gl861_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm gl861_i2c_algo = {
+ .master_xfer = gl861_i2c_xfer,
+ .functionality = gl861_i2c_func,
+};
+
+/* Callbacks for DVB USB */
+static int gl861_identify_state(struct usb_device *udev,
+ struct dvb_usb_device_properties *props,
+ struct dvb_usb_device_description **desc,
+ int *cold)
+{
+ *cold = 0;
+
+ return 0;
+}
+
+static struct zl10353_config gl861_zl10353_config = {
+ .demod_address = 0x1e,
+ .no_tuner = 1,
+ .parallel_ts = 1,
+};
+
+static int gl861_frontend_attach(struct dvb_usb_adapter *adap)
+{
+ if ((adap->fe = dvb_attach(zl10353_attach, &gl861_zl10353_config,
+ &adap->dev->i2c_adap)) != NULL) {
+ return 0;
+ }
+
+ return -EIO;
+}
+
+static struct qt1010_config gl861_qt1010_config = {
+ .i2c_address = 0xc4
+};
+
+static int gl861_tuner_attach(struct dvb_usb_adapter *adap)
+{
+ return dvb_attach(qt1010_attach,
+ adap->fe, &adap->dev->i2c_adap,
+ &gl861_qt1010_config) == NULL ? -ENODEV : 0;
+}
+
+/* DVB USB Driver stuff */
+static struct dvb_usb_device_properties gl861_properties;
+
+static int gl861_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct dvb_usb_device *d;
+ struct usb_host_interface *alt;
+ int ret;
+
+ if (intf->num_altsetting < 2)
+ return -ENODEV;
+
+ if ((ret = dvb_usb_device_init(intf, &gl861_properties, THIS_MODULE, &d)) == 0) {
+ alt = usb_altnum_to_altsetting(intf, 0);
+
+ if (alt == NULL) {
+ deb_rc("not alt found!\n");
+ return -ENODEV;
+ }
+
+ ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber,
+ alt->desc.bAlternateSetting);
+ }
+
+ return ret;
+}
+
+static struct usb_device_id gl861_table [] = {
+ { USB_DEVICE(USB_VID_MSI, USB_PID_MSI_MEGASKY580_55801) },
+ { } /* Terminating entry */
+};
+MODULE_DEVICE_TABLE (usb, gl861_table);
+
+static struct dvb_usb_device_properties gl861_properties = {
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+ .usb_ctrl = DEVICE_SPECIFIC,
+
+ .size_of_priv = 0,
+
+ .identify_state = gl861_identify_state,
+ .num_adapters = 1,
+ .adapter = {{
+
+ .frontend_attach = gl861_frontend_attach,
+ .tuner_attach = gl861_tuner_attach,
+
+ .stream = {
+ .type = USB_BULK,
+ .count = 7,
+ .endpoint = 0x81,
+ .u = {
+ .bulk = {
+ .buffersize = 512,
+ }
+ }
+ },
+ }},
+ .i2c_algo = &gl861_i2c_algo,
+
+ .num_device_descs = 1,
+ .devices = {
+ { "MSI Mega Sky 55801 DVB-T USB2.0",
+ { &gl861_table[0], NULL },
+ { NULL },
+ },
+ }
+};
+
+static struct usb_driver gl861_driver = {
+ .name = "dvb_usb_gl861",
+ .probe = gl861_probe,
+ .disconnect = dvb_usb_device_exit,
+ .id_table = gl861_table,
+};
+
+/* module stuff */
+static int __init gl861_module_init(void)
+{
+ int ret;
+
+ if ((ret = usb_register(&gl861_driver))) {
+ err("usb_register failed. Error number %d", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void __exit gl861_module_exit(void)
+{
+ /* deregister this driver from the USB subsystem */
+ usb_deregister(&gl861_driver);
+}
+
+module_init (gl861_module_init);
+module_exit (gl861_module_exit);
+
+MODULE_AUTHOR("Carl Lundqvist <comabug@gmail.com>");
+MODULE_DESCRIPTION("Driver MSI Mega Sky 580 DVB-T USB2.0 / GL861");
+MODULE_VERSION("0.1");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/gl861.h b/drivers/media/dvb/dvb-usb/gl861.h
new file mode 100644
index 00000000000..72a51afd5ee
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/gl861.h
@@ -0,0 +1,15 @@
+#ifndef _DVB_USB_GL861_H_
+#define _DVB_USB_GL861_H_
+
+#define DVB_USB_LOG_PREFIX "gl861"
+#include "dvb-usb.h"
+
+#define deb_rc(args...) dprintk(dvb_usb_gl861_debug,0x01,args)
+
+#define GL861_WRITE 0x40
+#define GL861_READ 0xc0
+
+#define GL861_REQ_I2C_WRITE 0x01
+#define GL861_REQ_I2C_READ 0x02
+
+#endif
diff --git a/drivers/media/dvb/dvb-usb/m920x.c b/drivers/media/dvb/dvb-usb/m920x.c
new file mode 100644
index 00000000000..d48b24d9abf
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/m920x.c
@@ -0,0 +1,541 @@
+/* DVB USB compliant linux driver for MSI Mega Sky 580 DVB-T USB2.0 receiver
+ *
+ * Copyright (C) 2006 Aapo Tahkola (aet@rasterburn.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, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+
+#include "m920x.h"
+
+#include "mt352.h"
+#include "mt352_priv.h"
+#include "qt1010.h"
+
+/* debug */
+static int dvb_usb_m920x_debug;
+module_param_named(debug,dvb_usb_m920x_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
+
+static struct dvb_usb_rc_key megasky_rc_keys [] = {
+ { 0x0, 0x12, KEY_POWER },
+ { 0x0, 0x1e, KEY_CYCLEWINDOWS }, /* min/max */
+ { 0x0, 0x02, KEY_CHANNELUP },
+ { 0x0, 0x05, KEY_CHANNELDOWN },
+ { 0x0, 0x03, KEY_VOLUMEUP },
+ { 0x0, 0x06, KEY_VOLUMEDOWN },
+ { 0x0, 0x04, KEY_MUTE },
+ { 0x0, 0x07, KEY_OK }, /* TS */
+ { 0x0, 0x08, KEY_STOP },
+ { 0x0, 0x09, KEY_MENU }, /* swap */
+ { 0x0, 0x0a, KEY_REWIND },
+ { 0x0, 0x1b, KEY_PAUSE },
+ { 0x0, 0x1f, KEY_FASTFORWARD },
+ { 0x0, 0x0c, KEY_RECORD },
+ { 0x0, 0x0d, KEY_CAMERA }, /* screenshot */
+ { 0x0, 0x0e, KEY_COFFEE }, /* "MTS" */
+};
+
+static inline int m9206_read(struct usb_device *udev, u8 request, u16 value,\
+ u16 index, void *data, int size)
+{
+ int ret;
+
+ ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+ request, USB_TYPE_VENDOR | USB_DIR_IN,
+ value, index, data, size, 2000);
+ if (ret < 0)
+ return ret;
+
+ if (ret != size)
+ return -EIO;
+
+ return 0;
+}
+
+static inline int m9206_write(struct usb_device *udev, u8 request,
+ u16 value, u16 index)
+{
+ int ret;
+
+ ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ request, USB_TYPE_VENDOR | USB_DIR_OUT,
+ value, index, NULL, 0, 2000);
+ return ret;
+}
+
+static int m9206_rc_init(struct usb_device *udev)
+{
+ int ret = 0;
+
+ /* Remote controller init. */
+ if ((ret = m9206_write(udev, M9206_CORE, 0xa8, M9206_RC_INIT2)) != 0)
+ return ret;
+
+ if ((ret = m9206_write(udev, M9206_CORE, 0x51, M9206_RC_INIT1)) != 0)
+ return ret;
+
+ return ret;
+}
+
+static int m9206_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+{
+ struct m9206_state *m = d->priv;
+ int i, ret = 0;
+ u8 rc_state[2];
+
+
+ if ((ret = m9206_read(d->udev, M9206_CORE, 0x0, M9206_RC_STATE, rc_state, 1)) != 0)
+ goto unlock;
+
+ if ((ret = m9206_read(d->udev, M9206_CORE, 0x0, M9206_RC_KEY, rc_state + 1, 1)) != 0)
+ goto unlock;
+
+ for (i = 0; i < ARRAY_SIZE(megasky_rc_keys); i++)
+ if (megasky_rc_keys[i].data == rc_state[1]) {
+ *event = megasky_rc_keys[i].event;
+
+ switch(rc_state[0]) {
+ case 0x80:
+ *state = REMOTE_NO_KEY_PRESSED;
+ goto unlock;
+
+ case 0x93:
+ case 0x92:
+ m->rep_count = 0;
+ *state = REMOTE_KEY_PRESSED;
+ goto unlock;
+
+ case 0x91:
+ /* For comfort. */
+ if (++m->rep_count > 2)
+ *state = REMOTE_KEY_REPEAT;
+ goto unlock;
+
+ default:
+ deb_rc("Unexpected rc response %x\n", rc_state[0]);
+ *state = REMOTE_NO_KEY_PRESSED;
+ goto unlock;
+ }
+ }
+
+ if (rc_state[1] != 0)
+ deb_rc("Unknown rc key %x\n", rc_state[1]);
+
+ *state = REMOTE_NO_KEY_PRESSED;
+
+ unlock:
+
+ return ret;
+}
+
+/* I2C */
+static int m9206_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+ int num)
+{
+ struct dvb_usb_device *d = i2c_get_adapdata(adap);
+ struct m9206_state *m = d->priv;
+ int i;
+ int ret = 0;
+
+ if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+ return -EAGAIN;
+
+ if (num > 2)
+ return -EINVAL;
+
+ for (i = 0; i < num; i++) {
+ if ((ret = m9206_write(d->udev, M9206_I2C, msg[i].addr, 0x80)) != 0)
+ goto unlock;
+
+ if ((ret = m9206_write(d->udev, M9206_I2C, msg[i].buf[0], 0x0)) != 0)
+ goto unlock;
+
+ if (i + 1 < num && msg[i + 1].flags & I2C_M_RD) {
+ int i2c_i;
+
+ for (i2c_i = 0; i2c_i < M9206_I2C_MAX; i2c_i++)
+ if (msg[i].addr == m->i2c_r[i2c_i].addr)
+ break;
+
+ if (i2c_i >= M9206_I2C_MAX) {
+ deb_rc("No magic for i2c addr!\n");
+ ret = -EINVAL;
+ goto unlock;
+ }
+
+ if ((ret = m9206_write(d->udev, M9206_I2C, m->i2c_r[i2c_i].magic, 0x80)) != 0)
+ goto unlock;
+
+ if ((ret = m9206_read(d->udev, M9206_I2C, 0x0, 0x60, msg[i + 1].buf, msg[i + 1].len)) != 0)
+ goto unlock;
+
+ i++;
+ } else {
+ if (msg[i].len != 2)
+ return -EINVAL;
+
+ if ((ret = m9206_write(d->udev, M9206_I2C, msg[i].buf[1], 0x40)) != 0)
+ goto unlock;
+ }
+ }
+ ret = i;
+ unlock:
+ mutex_unlock(&d->i2c_mutex);
+
+ return ret;
+}
+
+static u32 m9206_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm m9206_i2c_algo = {
+ .master_xfer = m9206_i2c_xfer,
+ .functionality = m9206_i2c_func,
+};
+
+
+static int m9206_set_filter(struct dvb_usb_adapter *adap, int type, int idx,
+ int pid)
+{
+ int ret = 0;
+
+ if (pid >= 0x8000)
+ return -EINVAL;
+
+ pid |= 0x8000;
+
+ if ((ret = m9206_write(adap->dev->udev, M9206_FILTER, pid, (type << 8) | (idx * 4) )) != 0)
+ return ret;
+
+ if ((ret = m9206_write(adap->dev->udev, M9206_FILTER, 0, (type << 8) | (idx * 4) )) != 0)
+ return ret;
+
+ return ret;
+}
+
+static int m9206_update_filters(struct dvb_usb_adapter *adap)
+{
+ struct m9206_state *m = adap->dev->priv;
+ int enabled = m->filtering_enabled;
+ int i, ret = 0, filter = 0;
+
+ for (i = 0; i < M9206_MAX_FILTERS; i++)
+ if (m->filters[i] == 8192)
+ enabled = 0;
+
+ /* Disable all filters */
+ if ((ret = m9206_set_filter(adap, 0x81, 1, enabled)) != 0)
+ return ret;
+
+ for (i = 0; i < M9206_MAX_FILTERS; i++)
+ if ((ret = m9206_set_filter(adap, 0x81, i + 2, 0)) != 0)
+ return ret;
+
+ if ((ret = m9206_set_filter(adap, 0x82, 0, 0x0)) != 0)
+ return ret;
+
+ /* Set */
+ if (enabled) {
+ for (i = 0; i < M9206_MAX_FILTERS; i++) {
+ if (m->filters[i] == 0)
+ continue;
+
+ if ((ret = m9206_set_filter(adap, 0x81, filter + 2, m->filters[i])) != 0)
+ return ret;
+
+ filter++;
+ }
+ }
+
+ if ((ret = m9206_set_filter(adap, 0x82, 0, 0x02f5)) != 0)
+ return ret;
+
+ return ret;
+}
+
+static int m9206_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+ struct m9206_state *m = adap->dev->priv;
+
+ m->filtering_enabled = onoff ? 1 : 0;
+
+ return m9206_update_filters(adap);
+}
+
+static int m9206_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid,
+ int onoff)
+{
+ struct m9206_state *m = adap->dev->priv;
+
+ m->filters[index] = onoff ? pid : 0;
+
+ return m9206_update_filters(adap);
+}
+
+static int m9206_firmware_download(struct usb_device *udev,
+ const struct firmware *fw)
+{
+ u16 value, index, size;
+ u8 read[4], *buff;
+ int i, pass, ret = 0;
+
+ buff = kmalloc(65536, GFP_KERNEL);
+
+ if ((ret = m9206_read(udev, M9206_FILTER, 0x0, 0x8000, read, 4)) != 0)
+ goto done;
+ deb_rc("%x %x %x %x\n", read[0], read[1], read[2], read[3]);
+
+ if ((ret = m9206_read(udev, M9206_FW, 0x0, 0x0, read, 1)) != 0)
+ goto done;
+ deb_rc("%x\n", read[0]);
+
+ for (pass = 0; pass < 2; pass++) {
+ for (i = 0; i + (sizeof(u16) * 3) < fw->size;) {
+ value = le16_to_cpu(*(u16 *)(fw->data + i));
+ i += sizeof(u16);
+
+ index = le16_to_cpu(*(u16 *)(fw->data + i));
+ i += sizeof(u16);
+
+ size = le16_to_cpu(*(u16 *)(fw->data + i));
+ i += sizeof(u16);
+
+ if (pass == 1) {
+ /* Will stall if using fw->data ... */
+ memcpy(buff, fw->data + i, size);
+
+ ret = usb_control_msg(udev, usb_sndctrlpipe(udev,0),
+ M9206_FW,
+ USB_TYPE_VENDOR | USB_DIR_OUT,
+ value, index, buff, size, 20);
+ if (ret != size) {
+ deb_rc("error while uploading fw!\n");
+ ret = -EIO;
+ goto done;
+ }
+ msleep(3);
+ }
+ i += size;
+ }
+ if (i != fw->size) {
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+
+ msleep(36);
+
+ /* m9206 will disconnect itself from the bus after this. */
+ (void) m9206_write(udev, M9206_CORE, 0x01, M9206_FW_GO);
+ deb_rc("firmware uploaded!\n");
+
+ done:
+ kfree(buff);
+
+ return ret;
+}
+
+/* Callbacks for DVB USB */
+static int megasky_identify_state(struct usb_device *udev,
+ struct dvb_usb_device_properties *props,
+ struct dvb_usb_device_description **desc,
+ int *cold)
+{
+ struct usb_host_interface *alt;
+
+ alt = usb_altnum_to_altsetting(usb_ifnum_to_if(udev, 0), 1);
+ *cold = (alt == NULL) ? 1 : 0;
+
+ return 0;
+}
+
+static int megasky_mt352_demod_init(struct dvb_frontend *fe)
+{
+ u8 config[] = { CONFIG, 0x3d };
+ u8 clock[] = { CLOCK_CTL, 0x30 };
+ u8 reset[] = { RESET, 0x80 };
+ u8 adc_ctl[] = { ADC_CTL_1, 0x40 };
+ u8 agc[] = { AGC_TARGET, 0x1c, 0x20 };
+ u8 sec_agc[] = { 0x69, 0x00, 0xff, 0xff, 0x40, 0xff, 0x00, 0x40, 0x40 };
+ u8 unk1[] = { 0x93, 0x1a };
+ u8 unk2[] = { 0xb5, 0x7a };
+
+ mt352_write(fe, config, ARRAY_SIZE(config));
+ mt352_write(fe, clock, ARRAY_SIZE(clock));
+ mt352_write(fe, reset, ARRAY_SIZE(reset));
+ mt352_write(fe, adc_ctl, ARRAY_SIZE(adc_ctl));
+ mt352_write(fe, agc, ARRAY_SIZE(agc));
+ mt352_write(fe, sec_agc, ARRAY_SIZE(sec_agc));
+ mt352_write(fe, unk1, ARRAY_SIZE(unk1));
+ mt352_write(fe, unk2, ARRAY_SIZE(unk2));
+
+ deb_rc("Demod init!\n");
+
+ return 0;
+}
+
+static struct mt352_config megasky_mt352_config = {
+ .demod_address = 0x1e,
+ .no_tuner = 1,
+ .demod_init = megasky_mt352_demod_init,
+};
+
+static int megasky_mt352_frontend_attach(struct dvb_usb_adapter *adap)
+{
+ struct m9206_state *m = adap->dev->priv;
+
+ deb_rc("megasky_frontend_attach!\n");
+
+ m->i2c_r[M9206_I2C_DEMOD].addr = megasky_mt352_config.demod_address;
+ m->i2c_r[M9206_I2C_DEMOD].magic = 0x1f;
+
+ if ((adap->fe = dvb_attach(mt352_attach, &megasky_mt352_config, &adap->dev->i2c_adap)) == NULL)
+ return -EIO;
+
+ return 0;
+}
+
+static struct qt1010_config megasky_qt1010_config = {
+ .i2c_address = 0xc4
+};
+
+static int megasky_qt1010_tuner_attach(struct dvb_usb_adapter *adap)
+{
+ struct m9206_state *m = adap->dev->priv;
+
+ m->i2c_r[M9206_I2C_TUNER].addr = megasky_qt1010_config.i2c_address;
+ m->i2c_r[M9206_I2C_TUNER].magic = 0xc5;
+
+ if (dvb_attach(qt1010_attach, adap->fe, &adap->dev->i2c_adap,
+ &megasky_qt1010_config) == NULL)
+ return -ENODEV;
+
+ return 0;
+}
+
+/* DVB USB Driver stuff */
+static struct dvb_usb_device_properties megasky_properties;
+
+static int m920x_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct dvb_usb_device *d;
+ struct usb_host_interface *alt;
+ int ret;
+
+ if ((ret = dvb_usb_device_init(intf, &megasky_properties, THIS_MODULE, &d)) == 0) {
+ deb_rc("probed!\n");
+
+ alt = usb_altnum_to_altsetting(intf, 1);
+ if (alt == NULL) {
+ deb_rc("not alt found!\n");
+ return -ENODEV;
+ }
+
+ ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber,
+ alt->desc.bAlternateSetting);
+ if (ret < 0)
+ return ret;
+
+ deb_rc("Changed to alternate setting!\n");
+
+ if ((ret = m9206_rc_init(d->udev)) != 0)
+ return ret;
+ }
+ return ret;
+}
+
+static struct usb_device_id m920x_table [] = {
+ { USB_DEVICE(USB_VID_MSI, USB_PID_MSI_MEGASKY580) },
+ { } /* Terminating entry */
+};
+MODULE_DEVICE_TABLE (usb, m920x_table);
+
+static struct dvb_usb_device_properties megasky_properties = {
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+ .usb_ctrl = DEVICE_SPECIFIC,
+ .firmware = "dvb-usb-megasky-02.fw",
+ .download_firmware = m9206_firmware_download,
+
+ .rc_interval = 100,
+ .rc_key_map = megasky_rc_keys,
+ .rc_key_map_size = ARRAY_SIZE(megasky_rc_keys),
+ .rc_query = m9206_rc_query,
+
+ .size_of_priv = sizeof(struct m9206_state),
+
+ .identify_state = megasky_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 = m9206_pid_filter,
+ .pid_filter_ctrl = m9206_pid_filter_ctrl,
+
+ .frontend_attach = megasky_mt352_frontend_attach,
+ .tuner_attach = megasky_qt1010_tuner_attach,
+
+ .stream = {
+ .type = USB_BULK,
+ .count = 8,
+ .endpoint = 0x81,
+ .u = {
+ .bulk = {
+ .buffersize = 512,
+ }
+ }
+ },
+ }},
+ .i2c_algo = &m9206_i2c_algo,
+
+ .num_device_descs = 1,
+ .devices = {
+ { "MSI Mega Sky 580 DVB-T USB2.0",
+ { &m920x_table[0], NULL },
+ { NULL },
+ },
+ }
+};
+
+static struct usb_driver m920x_driver = {
+ .name = "dvb_usb_m920x",
+ .probe = m920x_probe,
+ .disconnect = dvb_usb_device_exit,
+ .id_table = m920x_table,
+};
+
+/* module stuff */
+static int __init m920x_module_init(void)
+{
+ int ret;
+
+ if ((ret = usb_register(&m920x_driver))) {
+ err("usb_register failed. Error number %d", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void __exit m920x_module_exit(void)
+{
+ /* deregister this driver from the USB subsystem */
+ usb_deregister(&m920x_driver);
+}
+
+module_init (m920x_module_init);
+module_exit (m920x_module_exit);
+
+MODULE_AUTHOR("Aapo Tahkola <aet@rasterburn.org>");
+MODULE_DESCRIPTION("Driver MSI Mega Sky 580 DVB-T USB2.0 / Uli m920x");
+MODULE_VERSION("0.1");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/m920x.h b/drivers/media/dvb/dvb-usb/m920x.h
new file mode 100644
index 00000000000..c354196ffe5
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/m920x.h
@@ -0,0 +1,35 @@
+#ifndef _DVB_USB_M920X_H_
+#define _DVB_USB_M920X_H_
+
+#define DVB_USB_LOG_PREFIX "m920x"
+#include "dvb-usb.h"
+
+#define deb_rc(args...) dprintk(dvb_usb_m920x_debug,0x01,args)
+
+#define M9206_CORE 0x22
+#define M9206_RC_STATE 0xff51
+#define M9206_RC_KEY 0xff52
+#define M9206_RC_INIT1 0xff54
+#define M9206_RC_INIT2 0xff55
+#define M9206_FW_GO 0xff69
+
+#define M9206_I2C 0x23
+#define M9206_FILTER 0x25
+#define M9206_FW 0x30
+
+#define M9206_MAX_FILTERS 8
+
+#define M9206_I2C_TUNER 0
+#define M9206_I2C_DEMOD 1
+#define M9206_I2C_MAX 2
+
+struct m9206_state {
+ u16 filters[M9206_MAX_FILTERS];
+ int filtering_enabled;
+ int rep_count;
+ struct {
+ unsigned char addr;
+ unsigned char magic;
+ }i2c_r[M9206_I2C_MAX];
+};
+#endif
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index af314bb1dca..22c2cf2cea9 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -290,6 +290,13 @@ config DVB_TDA826X
help
A DVB-S silicon tuner module. Say Y when you want to support this tuner.
+config DVB_TUNER_QT1010
+ tristate "Quantek QT1010 silicon tuner"
+ depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ A driver for the silicon tuner QT1010 from Quantek.
+
config DVB_TUNER_MT2060
tristate "Microtune MT2060 silicon IF tuner"
depends on I2C
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index 3fa6e5d32a9..a646d9969b7 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -38,5 +38,6 @@ obj-$(CONFIG_DVB_ISL6421) += isl6421.o
obj-$(CONFIG_DVB_TDA10086) += tda10086.o
obj-$(CONFIG_DVB_TDA826X) += tda826x.o
obj-$(CONFIG_DVB_TUNER_MT2060) += mt2060.o
+obj-$(CONFIG_DVB_TUNER_QT1010) += qt1010.o
obj-$(CONFIG_DVB_TUA6100) += tua6100.o
obj-$(CONFIG_DVB_TUNER_LGH06XF) += lgh06xf.o
diff --git a/drivers/media/dvb/frontends/cx24110.c b/drivers/media/dvb/frontends/cx24110.c
index ae96395217a..10fc0c8316d 100644
--- a/drivers/media/dvb/frontends/cx24110.c
+++ b/drivers/media/dvb/frontends/cx24110.c
@@ -254,7 +254,7 @@ static int cx24110_set_symbolrate (struct cx24110_state* state, u32 srate)
if (srate<500000)
srate=500000;
- for(i=0;(i<sizeof(bands)/sizeof(bands[0]))&&(srate>bands[i]);i++)
+ for(i = 0; (i < ARRAY_SIZE(bands)) && (srate>bands[i]); i++)
;
/* first, check which sample rate is appropriate: 45, 60 80 or 90 MHz,
and set the PLL accordingly (R07[1:0] Fclk, R06[7:4] PLLmult,
@@ -361,7 +361,7 @@ static int cx24110_initfe(struct dvb_frontend* fe)
dprintk("%s: init chip\n", __FUNCTION__);
- for(i=0;i<sizeof(cx24110_regdata)/sizeof(cx24110_regdata[0]);i++) {
+ for(i = 0; i < ARRAY_SIZE(cx24110_regdata); i++) {
cx24110_writereg(state, cx24110_regdata[i].reg, cx24110_regdata[i].data);
};
diff --git a/drivers/media/dvb/frontends/cx24123.c b/drivers/media/dvb/frontends/cx24123.c
index a356d28fc3b..732e94aaa36 100644
--- a/drivers/media/dvb/frontends/cx24123.c
+++ b/drivers/media/dvb/frontends/cx24123.c
@@ -507,7 +507,7 @@ static int cx24123_pll_calculate(struct dvb_frontend* fe, struct dvb_frontend_pa
int i = 0;
int pump = 2;
int band = 0;
- int num_bands = sizeof(cx24123_bandselect_vals) / sizeof(cx24123_bandselect_vals[0]);
+ int num_bands = ARRAY_SIZE(cx24123_bandselect_vals);
/* Defaults for low freq, low rate */
state->VCAarg = cx24123_AGC_vals[0].VCAprogdata;
@@ -516,7 +516,7 @@ static int cx24123_pll_calculate(struct dvb_frontend* fe, struct dvb_frontend_pa
vco_div = cx24123_bandselect_vals[0].VCOdivider;
/* For the given symbol rate, determine the VCA, VGA and FILTUNE programming bits */
- for (i = 0; i < sizeof(cx24123_AGC_vals) / sizeof(cx24123_AGC_vals[0]); i++)
+ for (i = 0; i < ARRAY_SIZE(cx24123_AGC_vals); i++)
{
if ((cx24123_AGC_vals[i].symbolrate_low <= p->u.qpsk.symbol_rate) &&
(cx24123_AGC_vals[i].symbolrate_high >= p->u.qpsk.symbol_rate) ) {
@@ -658,7 +658,7 @@ static int cx24123_initfe(struct dvb_frontend* fe)
dprintk("%s: init frontend\n",__FUNCTION__);
/* Configure the demod to a good set of defaults */
- for (i = 0; i < sizeof(cx24123_regdata) / sizeof(cx24123_regdata[0]); i++)
+ for (i = 0; i < ARRAY_SIZE(cx24123_regdata); i++)
cx24123_writereg(state, cx24123_regdata[i].reg, cx24123_regdata[i].data);
/* Set the LNB polarity */
diff --git a/drivers/media/dvb/frontends/dib3000mb.c b/drivers/media/dvb/frontends/dib3000mb.c
index adbabfdb04a..b6adea5ffeb 100644
--- a/drivers/media/dvb/frontends/dib3000mb.c
+++ b/drivers/media/dvb/frontends/dib3000mb.c
@@ -239,7 +239,7 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe,
default:
return -EINVAL;
}
- deb_setf("hierachy: ");
+ deb_setf("hierarchy: ");
switch (ofdm->hierarchy_information) {
case HIERARCHY_NONE:
deb_setf("none ");
diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c
index 23aa75a27c1..054d7e6d966 100644
--- a/drivers/media/dvb/frontends/dib3000mc.c
+++ b/drivers/media/dvb/frontends/dib3000mc.c
@@ -475,7 +475,7 @@ static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dibx
tmp = ((chan->nfft & 0x1) << 7) | (chan->guard << 5) | (chan->nqam << 3) | chan->vit_alpha;
dib3000mc_write_word(state, 0, tmp);
- dib3000mc_write_word(state, 5, seq);
+ dib3000mc_write_word(state, 5, (1 << 8) | ((seq & 0xf) << 4));
tmp = (chan->vit_hrch << 4) | (chan->vit_select_hp);
if (!chan->vit_hrch || (chan->vit_hrch && chan->vit_select_hp))
diff --git a/drivers/media/dvb/frontends/qt1010.c b/drivers/media/dvb/frontends/qt1010.c
new file mode 100644
index 00000000000..825aa1412e6
--- /dev/null
+++ b/drivers/media/dvb/frontends/qt1010.c
@@ -0,0 +1,485 @@
+/*
+ * Driver for Quantek QT1010 silicon tuner
+ *
+ * Copyright (C) 2006 Antti Palosaari <crope@iki.fi>
+ * Aapo Tahkola <aet@rasterburn.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 "qt1010.h"
+#include "qt1010_priv.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+
+#define dprintk(args...) \
+ do { \
+ if (debug) printk(KERN_DEBUG "QT1010: " args); \
+ } while (0)
+
+/* read single register */
+static int qt1010_readreg(struct qt1010_priv *priv, u8 reg, u8 *val)
+{
+ struct i2c_msg msg[2] = {
+ { .addr = priv->cfg->i2c_address,
+ .flags = 0, .buf = &reg, .len = 1 },
+ { .addr = priv->cfg->i2c_address,
+ .flags = I2C_M_RD, .buf = val, .len = 1 },
+ };
+
+ if (i2c_transfer(priv->i2c, msg, 2) != 2) {
+ printk(KERN_WARNING "qt1010 I2C read failed\n");
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+/* write single register */
+static int qt1010_writereg(struct qt1010_priv *priv, u8 reg, u8 val)
+{
+ u8 buf[2] = { reg, val };
+ struct i2c_msg msg = { .addr = priv->cfg->i2c_address,
+ .flags = 0, .buf = buf, .len = 2 };
+
+ if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+ printk(KERN_WARNING "qt1010 I2C write failed\n");
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+/* dump all registers */
+static void qt1010_dump_regs(struct qt1010_priv *priv)
+{
+ char buf[52], buf2[4];
+ u8 reg, val;
+
+ for (reg = 0; ; reg++) {
+ if (reg % 16 == 0) {
+ if (reg)
+ printk("%s\n", buf);
+ sprintf(buf, "%02x: ", reg);
+ }
+ if (qt1010_readreg(priv, reg, &val) == 0)
+ sprintf(buf2, "%02x ", val);
+ else
+ strcpy(buf2, "-- ");
+ strcat(buf, buf2);
+ if (reg == 0x2f)
+ break;
+ }
+ printk("%s\n", buf);
+}
+
+static int qt1010_set_params(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params)
+{
+ struct qt1010_priv *priv;
+ int err;
+ u32 freq, div, mod1, mod2;
+ u8 i, tmpval, reg05;
+ qt1010_i2c_oper_t rd[48] = {
+ { QT1010_WR, 0x01, 0x80 },
+ { QT1010_WR, 0x02, 0x3f },
+ { QT1010_WR, 0x05, 0xff }, /* 02 c write */
+ { QT1010_WR, 0x06, 0x44 },
+ { QT1010_WR, 0x07, 0xff }, /* 04 c write */
+ { QT1010_WR, 0x08, 0x08 },
+ { QT1010_WR, 0x09, 0xff }, /* 06 c write */
+ { QT1010_WR, 0x0a, 0xff }, /* 07 c write */
+ { QT1010_WR, 0x0b, 0xff }, /* 08 c write */
+ { QT1010_WR, 0x0c, 0xe1 },
+ { QT1010_WR, 0x1a, 0xff }, /* 10 c write */
+ { QT1010_WR, 0x1b, 0x00 },
+ { QT1010_WR, 0x1c, 0x89 },
+ { QT1010_WR, 0x11, 0xff }, /* 13 c write */
+ { QT1010_WR, 0x12, 0xff }, /* 14 c write */
+ { QT1010_WR, 0x22, 0xff }, /* 15 c write */
+ { QT1010_WR, 0x1e, 0x00 },
+ { QT1010_WR, 0x1e, 0xd0 },
+ { QT1010_RD, 0x22, 0xff }, /* 16 c read */
+ { QT1010_WR, 0x1e, 0x00 },
+ { QT1010_RD, 0x05, 0xff }, /* 20 c read */
+ { QT1010_RD, 0x22, 0xff }, /* 21 c read */
+ { QT1010_WR, 0x23, 0xd0 },
+ { QT1010_WR, 0x1e, 0x00 },
+ { QT1010_WR, 0x1e, 0xe0 },
+ { QT1010_RD, 0x23, 0xff }, /* 25 c read */
+ { QT1010_RD, 0x23, 0xff }, /* 26 c read */
+ { QT1010_WR, 0x1e, 0x00 },
+ { QT1010_WR, 0x24, 0xd0 },
+ { QT1010_WR, 0x1e, 0x00 },
+ { QT1010_WR, 0x1e, 0xf0 },
+ { QT1010_RD, 0x24, 0xff }, /* 31 c read */
+ { QT1010_WR, 0x1e, 0x00 },
+ { QT1010_WR, 0x14, 0x7f },
+ { QT1010_WR, 0x15, 0x7f },
+ { QT1010_WR, 0x05, 0xff }, /* 35 c write */
+ { QT1010_WR, 0x06, 0x00 },
+ { QT1010_WR, 0x15, 0x1f },
+ { QT1010_WR, 0x16, 0xff },
+ { QT1010_WR, 0x18, 0xff },
+ { QT1010_WR, 0x1f, 0xff }, /* 40 c write */
+ { QT1010_WR, 0x20, 0xff }, /* 41 c write */
+ { QT1010_WR, 0x21, 0x53 },
+ { QT1010_WR, 0x25, 0xff }, /* 43 c write */
+ { QT1010_WR, 0x26, 0x15 },
+ { QT1010_WR, 0x00, 0xff }, /* 45 c write */
+ { QT1010_WR, 0x02, 0x00 },
+ { QT1010_WR, 0x01, 0x00 }
+ };
+
+#define FREQ1 32000000 /* 32 MHz */
+#define FREQ2 4000000 /* 4 MHz Quartz oscillator in the stick? */
+
+ priv = fe->tuner_priv;
+ freq = params->frequency;
+ div = (freq + QT1010_OFFSET) / QT1010_STEP;
+ freq = (div * QT1010_STEP) - QT1010_OFFSET;
+ mod1 = (freq + QT1010_OFFSET) % FREQ1;
+ mod2 = (freq + QT1010_OFFSET) % FREQ2;
+ priv->bandwidth =
+ (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
+ priv->frequency = freq;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
+
+ /* reg 05 base value */
+ if (freq < 290000000) reg05 = 0x14; /* 290 MHz */
+ else if (freq < 610000000) reg05 = 0x34; /* 610 MHz */
+ else if (freq < 802000000) reg05 = 0x54; /* 802 MHz */
+ else reg05 = 0x74;
+
+ /* 0x5 */
+ rd[2].val = reg05;
+
+ /* 07 - set frequency: 32 MHz scale */
+ rd[4].val = (freq + QT1010_OFFSET) / FREQ1;
+
+ /* 09 - changes every 8/24 MHz */
+ if (mod1 < 8000000) rd[6].val = 0x1d;
+ else rd[6].val = 0x1c;
+
+ /* 0a - set frequency: 4 MHz scale (max 28 MHz) */
+ if (mod1 < 1*FREQ2) rd[7].val = 0x09; /* +0 MHz */
+ else if (mod1 < 2*FREQ2) rd[7].val = 0x08; /* +4 MHz */
+ else if (mod1 < 3*FREQ2) rd[7].val = 0x0f; /* +8 MHz */
+ else if (mod1 < 4*FREQ2) rd[7].val = 0x0e; /* +12 MHz */
+ else if (mod1 < 5*FREQ2) rd[7].val = 0x0d; /* +16 MHz */
+ else if (mod1 < 6*FREQ2) rd[7].val = 0x0c; /* +20 MHz */
+ else if (mod1 < 7*FREQ2) rd[7].val = 0x0b; /* +24 MHz */
+ else rd[7].val = 0x0a; /* +28 MHz */
+
+ /* 0b - changes every 2/2 MHz */
+ if (mod2 < 2000000) rd[8].val = 0x45;
+ else rd[8].val = 0x44;
+
+ /* 1a - set frequency: 125 kHz scale (max 3875 kHz)*/
+ tmpval = 0x78; /* byte, overflows intentionally */
+ rd[10].val = tmpval-((mod2/QT1010_STEP)*0x08);
+
+ /* 11 */
+ rd[13].val = 0xfd; /* TODO: correct value calculation */
+
+ /* 12 */
+ rd[14].val = 0x91; /* TODO: correct value calculation */
+
+ /* 22 */
+ if (freq < 450000000) rd[15].val = 0xd0; /* 450 MHz */
+ else if (freq < 482000000) rd[15].val = 0xd1; /* 482 MHz */
+ else if (freq < 514000000) rd[15].val = 0xd4; /* 514 MHz */
+ else if (freq < 546000000) rd[15].val = 0xd7; /* 546 MHz */
+ else if (freq < 610000000) rd[15].val = 0xda; /* 610 MHz */
+ else rd[15].val = 0xd0;
+
+ /* 05 */
+ rd[35].val = (reg05 & 0xf0);
+
+ /* 1f */
+ if (mod1 < 8000000) tmpval = 0x00;
+ else if (mod1 < 12000000) tmpval = 0x01;
+ else if (mod1 < 16000000) tmpval = 0x02;
+ else if (mod1 < 24000000) tmpval = 0x03;
+ else if (mod1 < 28000000) tmpval = 0x04;
+ else tmpval = 0x05;
+ rd[40].val = (priv->reg1f_init_val + 0x0e + tmpval);
+
+ /* 20 */
+ if (mod1 < 8000000) tmpval = 0x00;
+ else if (mod1 < 12000000) tmpval = 0x01;
+ else if (mod1 < 20000000) tmpval = 0x02;
+ else if (mod1 < 24000000) tmpval = 0x03;
+ else if (mod1 < 28000000) tmpval = 0x04;
+ else tmpval = 0x05;
+ rd[41].val = (priv->reg20_init_val + 0x0d + tmpval);
+
+ /* 25 */
+ rd[43].val = priv->reg25_init_val;
+
+ /* 00 */
+ rd[45].val = 0x92; /* TODO: correct value calculation */
+
+ dprintk("freq:%u 05:%02x 07:%02x 09:%02x 0a:%02x 0b:%02x " \
+ "1a:%02x 11:%02x 12:%02x 22:%02x 05:%02x 1f:%02x " \
+ "20:%02x 25:%02x 00:%02x", \
+ freq, rd[2].val, rd[4].val, rd[6].val, rd[7].val, rd[8].val, \
+ rd[10].val, rd[13].val, rd[14].val, rd[15].val, rd[35].val, \
+ rd[40].val, rd[41].val, rd[43].val, rd[45].val);
+
+ for (i = 0; i < ARRAY_SIZE(rd); i++) {
+ if (rd[i].oper == QT1010_WR) {
+ err = qt1010_writereg(priv, rd[i].reg, rd[i].val);
+ } else { /* read is required to proper locking */
+ err = qt1010_readreg(priv, rd[i].reg, &tmpval);
+ }
+ if (err) return err;
+ }
+
+ if (debug)
+ qt1010_dump_regs(priv);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
+
+ return 0;
+}
+
+static int qt1010_init_meas1(struct qt1010_priv *priv,
+ u8 oper, u8 reg, u8 reg_init_val, u8 *retval)
+{
+ u8 i, val1, val2;
+ int err;
+
+ qt1010_i2c_oper_t i2c_data[] = {
+ { QT1010_WR, reg, reg_init_val },
+ { QT1010_WR, 0x1e, 0x00 },
+ { QT1010_WR, 0x1e, oper },
+ { QT1010_RD, reg, 0xff }
+ };
+
+ for (i = 0; i < ARRAY_SIZE(i2c_data); i++) {
+ if (i2c_data[i].oper == QT1010_WR) {
+ err = qt1010_writereg(priv, i2c_data[i].reg,
+ i2c_data[i].val);
+ } else {
+ err = qt1010_readreg(priv, i2c_data[i].reg, &val2);
+ }
+ if (err) return err;
+ }
+
+ do {
+ val1 = val2;
+ err = qt1010_readreg(priv, reg, &val2);
+ if (err) return err;
+ dprintk("compare reg:%02x %02x %02x", reg, val1, val2);
+ } while (val1 != val2);
+ *retval = val1;
+
+ return qt1010_writereg(priv, 0x1e, 0x00);
+}
+
+static u8 qt1010_init_meas2(struct qt1010_priv *priv,
+ u8 reg_init_val, u8 *retval)
+{
+ u8 i, val;
+ int err;
+ qt1010_i2c_oper_t i2c_data[] = {
+ { QT1010_WR, 0x07, reg_init_val },
+ { QT1010_WR, 0x22, 0xd0 },
+ { QT1010_WR, 0x1e, 0x00 },
+ { QT1010_WR, 0x1e, 0xd0 },
+ { QT1010_RD, 0x22, 0xff },
+ { QT1010_WR, 0x1e, 0x00 },
+ { QT1010_WR, 0x22, 0xff }
+ };
+ for (i = 0; i < ARRAY_SIZE(i2c_data); i++) {
+ if (i2c_data[i].oper == QT1010_WR) {
+ err = qt1010_writereg(priv, i2c_data[i].reg,
+ i2c_data[i].val);
+ } else {
+ err = qt1010_readreg(priv, i2c_data[i].reg, &val);
+ }
+ if (err) return err;
+ }
+ *retval = val;
+ return 0;
+}
+
+static int qt1010_init(struct dvb_frontend *fe)
+{
+ struct qt1010_priv *priv = fe->tuner_priv;
+ struct dvb_frontend_parameters params;
+ int err = 0;
+ u8 i, tmpval, *valptr = NULL;
+
+ qt1010_i2c_oper_t i2c_data[] = {
+ { QT1010_WR, 0x01, 0x80 },
+ { QT1010_WR, 0x0d, 0x84 },
+ { QT1010_WR, 0x0e, 0xb7 },
+ { QT1010_WR, 0x2a, 0x23 },
+ { QT1010_WR, 0x2c, 0xdc },
+ { QT1010_M1, 0x25, 0x40 }, /* get reg 25 init value */
+ { QT1010_M1, 0x81, 0xff }, /* get reg 25 init value */
+ { QT1010_WR, 0x2b, 0x70 },
+ { QT1010_WR, 0x2a, 0x23 },
+ { QT1010_M1, 0x26, 0x08 },
+ { QT1010_M1, 0x82, 0xff },
+ { QT1010_WR, 0x05, 0x14 },
+ { QT1010_WR, 0x06, 0x44 },
+ { QT1010_WR, 0x07, 0x28 },
+ { QT1010_WR, 0x08, 0x0b },
+ { QT1010_WR, 0x11, 0xfd },
+ { QT1010_M1, 0x22, 0x0d },
+ { QT1010_M1, 0xd0, 0xff },
+ { QT1010_WR, 0x06, 0x40 },
+ { QT1010_WR, 0x16, 0xf0 },
+ { QT1010_WR, 0x02, 0x38 },
+ { QT1010_WR, 0x03, 0x18 },
+ { QT1010_WR, 0x20, 0xe0 },
+ { QT1010_M1, 0x1f, 0x20 }, /* get reg 1f init value */
+ { QT1010_M1, 0x84, 0xff }, /* get reg 1f init value */
+ { QT1010_RD, 0x20, 0x20 }, /* get reg 20 init value */
+ { QT1010_WR, 0x03, 0x19 },
+ { QT1010_WR, 0x02, 0x3f },
+ { QT1010_WR, 0x21, 0x53 },
+ { QT1010_RD, 0x21, 0xff },
+ { QT1010_WR, 0x11, 0xfd },
+ { QT1010_WR, 0x05, 0x34 },
+ { QT1010_WR, 0x06, 0x44 },
+ { QT1010_WR, 0x08, 0x08 }
+ };
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
+
+ for (i = 0; i < ARRAY_SIZE(i2c_data); i++) {
+ switch (i2c_data[i].oper) {
+ case QT1010_WR:
+ err = qt1010_writereg(priv, i2c_data[i].reg,
+ i2c_data[i].val);
+ break;
+ case QT1010_RD:
+ if (i2c_data[i].val == 0x20)
+ valptr = &priv->reg20_init_val;
+ else
+ valptr = &tmpval;
+ err = qt1010_readreg(priv, i2c_data[i].reg, valptr);
+ break;
+ case QT1010_M1:
+ if (i2c_data[i].val == 0x25)
+ valptr = &priv->reg25_init_val;
+ else if (i2c_data[i].val == 0x1f)
+ valptr = &priv->reg1f_init_val;
+ else
+ valptr = &tmpval;
+ err = qt1010_init_meas1(priv, i2c_data[i+1].reg,
+ i2c_data[i].reg,
+ i2c_data[i].val, valptr);
+ i++;
+ break;
+ }
+ if (err) return err;
+ }
+
+ for (i = 0x31; i < 0x3a; i++) /* 0x31 - 0x39 */
+ if ((err = qt1010_init_meas2(priv, i, &tmpval)))
+ return err;
+
+ params.frequency = 545000000; /* Sigmatek DVB-110 545000000 */
+ /* MSI Megasky 580 GL861 533000000 */
+ return qt1010_set_params(fe, &params);
+}
+
+static int qt1010_release(struct dvb_frontend *fe)
+{
+ kfree(fe->tuner_priv);
+ fe->tuner_priv = NULL;
+ return 0;
+}
+
+static int qt1010_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+ struct qt1010_priv *priv = fe->tuner_priv;
+ *frequency = priv->frequency;
+ return 0;
+}
+
+static int qt1010_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+ struct qt1010_priv *priv = fe->tuner_priv;
+ *bandwidth = priv->bandwidth;
+ return 0;
+}
+
+static const struct dvb_tuner_ops qt1010_tuner_ops = {
+ .info = {
+ .name = "Quantek QT1010",
+ .frequency_min = QT1010_MIN_FREQ,
+ .frequency_max = QT1010_MAX_FREQ,
+ .frequency_step = QT1010_STEP,
+ },
+
+ .release = qt1010_release,
+ .init = qt1010_init,
+ /* TODO: implement sleep */
+
+ .set_params = qt1010_set_params,
+ .get_frequency = qt1010_get_frequency,
+ .get_bandwidth = qt1010_get_bandwidth
+};
+
+struct dvb_frontend * qt1010_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c,
+ struct qt1010_config *cfg)
+{
+ struct qt1010_priv *priv = NULL;
+ u8 id;
+
+ priv = kzalloc(sizeof(struct qt1010_priv), GFP_KERNEL);
+ if (priv == NULL)
+ return NULL;
+
+ priv->cfg = cfg;
+ priv->i2c = i2c;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
+
+
+ /* Try to detect tuner chip. Probably this is not correct register. */
+ if (qt1010_readreg(priv, 0x29, &id) != 0 || (id != 0x39)) {
+ kfree(priv);
+ return NULL;
+ }
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
+
+ printk(KERN_INFO "Quantek QT1010 successfully identified.\n");
+ memcpy(&fe->ops.tuner_ops, &qt1010_tuner_ops,
+ sizeof(struct dvb_tuner_ops));
+
+ fe->tuner_priv = priv;
+ return fe;
+}
+EXPORT_SYMBOL(qt1010_attach);
+
+MODULE_DESCRIPTION("Quantek QT1010 silicon tuner driver");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_AUTHOR("Aapo Tahkola <aet@rasterburn.org>");
+MODULE_VERSION("0.1");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/qt1010.h b/drivers/media/dvb/frontends/qt1010.h
new file mode 100644
index 00000000000..3ab4aa045c3
--- /dev/null
+++ b/drivers/media/dvb/frontends/qt1010.h
@@ -0,0 +1,53 @@
+/*
+ * Driver for Quantek QT1010 silicon tuner
+ *
+ * Copyright (C) 2006 Antti Palosaari <crope@iki.fi>
+ * Aapo Tahkola <aet@rasterburn.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.
+ */
+
+#ifndef QT1010_H
+#define QT1010_H
+
+#include "dvb_frontend.h"
+
+struct qt1010_config {
+ u8 i2c_address;
+};
+
+/**
+ * Attach a qt1010 tuner to the supplied frontend structure.
+ *
+ * @param fe frontend to attach to
+ * @param i2c i2c adapter to use
+ * @param cfg tuner hw based configuration
+ * @return fe pointer on success, NULL on failure
+ */
+#if defined(CONFIG_DVB_TUNER_QT1010) || (defined(CONFIG_DVB_TUNER_QT1010_MODULE) && defined(MODULE))
+extern struct dvb_frontend *qt1010_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c,
+ struct qt1010_config *cfg);
+#else
+static inline struct dvb_frontend *qt1010_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c,
+ struct qt1010_config *cfg)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ return NULL;
+}
+#endif // CONFIG_DVB_TUNER_QT1010
+
+#endif
diff --git a/drivers/media/dvb/frontends/qt1010_priv.h b/drivers/media/dvb/frontends/qt1010_priv.h
new file mode 100644
index 00000000000..090cf475f09
--- /dev/null
+++ b/drivers/media/dvb/frontends/qt1010_priv.h
@@ -0,0 +1,105 @@
+/*
+ * Driver for Quantek QT1010 silicon tuner
+ *
+ * Copyright (C) 2006 Antti Palosaari <crope@iki.fi>
+ * Aapo Tahkola <aet@rasterburn.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.
+ */
+
+#ifndef QT1010_PRIV_H
+#define QT1010_PRIV_H
+
+/*
+reg def meaning
+=== === =======
+00 00 ?
+01 a0 ? operation start/stop; start=80, stop=00
+02 00 ?
+03 19 ?
+04 00 ?
+05 00 ? maybe band selection
+06 00 ?
+07 2b set frequency: 32 MHz scale, n*32 MHz
+08 0b ?
+09 10 ? changes every 8/24 MHz; values 1d/1c
+0a 08 set frequency: 4 MHz scale, n*4 MHz
+0b 41 ? changes every 2/2 MHz; values 45/45
+0c e1 ?
+0d 94 ?
+0e b6 ?
+0f 2c ?
+10 10 ?
+11 f1 ? maybe device specified adjustment
+12 11 ? maybe device specified adjustment
+13 3f ?
+14 1f ?
+15 3f ?
+16 ff ?
+17 ff ?
+18 f7 ?
+19 80 ?
+1a d0 set frequency: 125 kHz scale, n*125 kHz
+1b 00 ?
+1c 89 ?
+1d 00 ?
+1e 00 ? looks like operation register; write cmd here, read result from 1f-26
+1f 20 ? chip initialization
+20 e0 ? chip initialization
+21 20 ?
+22 d0 ?
+23 d0 ?
+24 d0 ?
+25 40 ? chip initialization
+26 08 ?
+27 29 ?
+28 55 ?
+29 39 ?
+2a 13 ?
+2b 01 ?
+2c ea ?
+2d 00 ?
+2e 00 ? not used?
+2f 00 ? not used?
+*/
+
+#define QT1010_STEP 125000 /* 125 kHz used by Windows drivers,
+ hw could be more precise but we don't
+ know how to use */
+#define QT1010_MIN_FREQ 48000000 /* 48 MHz */
+#define QT1010_MAX_FREQ 860000000 /* 860 MHz */
+#define QT1010_OFFSET 1246000000 /* 1246 MHz */
+
+#define QT1010_WR 0
+#define QT1010_RD 1
+#define QT1010_M1 3
+
+typedef struct {
+ u8 oper, reg, val;
+} qt1010_i2c_oper_t;
+
+struct qt1010_priv {
+ struct qt1010_config *cfg;
+ struct i2c_adapter *i2c;
+
+ u8 reg1f_init_val;
+ u8 reg20_init_val;
+ u8 reg25_init_val;
+
+ u32 frequency;
+ u32 bandwidth;
+};
+
+#endif
diff --git a/drivers/media/dvb/frontends/stv0297.c b/drivers/media/dvb/frontends/stv0297.c
index 1ca64249010..9a343972ff5 100644
--- a/drivers/media/dvb/frontends/stv0297.c
+++ b/drivers/media/dvb/frontends/stv0297.c
@@ -35,6 +35,7 @@ struct stv0297_state {
const struct stv0297_config *config;
struct dvb_frontend frontend;
+ unsigned long last_ber;
unsigned long base_freq;
};
@@ -310,6 +311,8 @@ static int stv0297_init(struct dvb_frontend *fe)
stv0297_writereg(state, state->config->inittab[i], state->config->inittab[i+1]);
msleep(200);
+ state->last_ber = 0;
+
return 0;
}
@@ -340,11 +343,13 @@ static int stv0297_read_ber(struct dvb_frontend *fe, u32 * ber)
struct stv0297_state *state = fe->demodulator_priv;
u8 BER[3];
- stv0297_writereg(state, 0xA0, 0x80); // Start Counting bit errors for 4096 Bytes
- mdelay(25); // Hopefully got 4096 Bytes
stv0297_readregs(state, 0xA0, BER, 3);
- mdelay(25);
- *ber = (BER[2] << 8 | BER[1]) / (8 * 4096);
+ if (!(BER[0] & 0x80)) {
+ state->last_ber = BER[2] << 8 | BER[1];
+ stv0297_writereg_mask(state, 0xA0, 0x80, 0x80);
+ }
+
+ *ber = state->last_ber;
return 0;
}
@@ -376,9 +381,14 @@ static int stv0297_read_ucblocks(struct dvb_frontend *fe, u32 * ucblocks)
{
struct stv0297_state *state = fe->demodulator_priv;
+ stv0297_writereg_mask(state, 0xDF, 0x03, 0x03); /* freeze the counters */
+
*ucblocks = (stv0297_readreg(state, 0xD5) << 8)
| stv0297_readreg(state, 0xD4);
+ stv0297_writereg_mask(state, 0xDF, 0x03, 0x02); /* clear the counters */
+ stv0297_writereg_mask(state, 0xDF, 0x03, 0x01); /* re-enable the counters */
+
return 0;
}
@@ -648,6 +658,7 @@ struct dvb_frontend *stv0297_attach(const struct stv0297_config *config,
/* setup the state */
state->config = config;
state->i2c = i2c;
+ state->last_ber = 0;
state->base_freq = 0;
/* check if the demod is there */
diff --git a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c
index 93483769eca..18768d2f6d4 100644
--- a/drivers/media/dvb/frontends/stv0299.c
+++ b/drivers/media/dvb/frontends/stv0299.c
@@ -92,7 +92,7 @@ static int stv0299_writeregI (struct stv0299_state* state, u8 reg, u8 data)
return (ret != 1) ? -EREMOTEIO : 0;
}
-int stv0299_write(struct dvb_frontend* fe, u8 *buf, int len)
+static int stv0299_write(struct dvb_frontend* fe, u8 *buf, int len)
{
struct stv0299_state* state = fe->demodulator_priv;
diff --git a/drivers/media/dvb/frontends/tda10021.c b/drivers/media/dvb/frontends/tda10021.c
index dca89171be1..5b9c5bb29b2 100644
--- a/drivers/media/dvb/frontends/tda10021.c
+++ b/drivers/media/dvb/frontends/tda10021.c
@@ -201,7 +201,7 @@ static int tda10021_set_symbolrate (struct tda10021_state* state, u32 symbolrate
return 0;
}
-int tda10021_write(struct dvb_frontend* fe, u8 *buf, int len)
+static int tda10021_write(struct dvb_frontend* fe, u8 *buf, int len)
{
struct tda10021_state* state = fe->demodulator_priv;
diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c
index 00e4bcd9f1a..f4a9cf9d26d 100644
--- a/drivers/media/dvb/frontends/tda1004x.c
+++ b/drivers/media/dvb/frontends/tda1004x.c
@@ -579,7 +579,7 @@ static int tda1004x_decode_fec(int tdafec)
return -1;
}
-int tda1004x_write(struct dvb_frontend* fe, u8 *buf, int len)
+static int tda1004x_write(struct dvb_frontend* fe, u8 *buf, int len)
{
struct tda1004x_state* state = fe->demodulator_priv;
diff --git a/drivers/media/dvb/frontends/zl10353.c b/drivers/media/dvb/frontends/zl10353.c
index 0e9b59af271..245f9b7dddf 100644
--- a/drivers/media/dvb/frontends/zl10353.c
+++ b/drivers/media/dvb/frontends/zl10353.c
@@ -38,6 +38,12 @@ struct zl10353_state {
struct zl10353_config config;
};
+static int debug;
+#define dprintk(args...) \
+ do { \
+ if (debug) printk(KERN_DEBUG "zl10353: " args); \
+ } while (0)
+
static int debug_regs = 0;
static int zl10353_single_write(struct dvb_frontend *fe, u8 reg, u8 val)
@@ -54,7 +60,7 @@ static int zl10353_single_write(struct dvb_frontend *fe, u8 reg, u8 val)
return 0;
}
-int zl10353_write(struct dvb_frontend *fe, u8 *ibuf, int ilen)
+static int zl10353_write(struct dvb_frontend *fe, u8 *ibuf, int ilen)
{
int err, i;
for (i = 0; i < ilen - 1; i++)
@@ -113,6 +119,36 @@ static void zl10353_dump_regs(struct dvb_frontend *fe)
printk(KERN_DEBUG "%s\n", buf);
}
+static void zl10353_calc_nominal_rate(struct dvb_frontend *fe,
+ enum fe_bandwidth bandwidth,
+ u16 *nominal_rate)
+{
+ u32 adc_clock = 22528; /* 20.480 MHz on the board(!?) */
+ u8 bw;
+ struct zl10353_state *state = fe->demodulator_priv;
+
+ if (state->config.adc_clock)
+ adc_clock = state->config.adc_clock;
+
+ switch (bandwidth) {
+ case BANDWIDTH_6_MHZ:
+ bw = 6;
+ break;
+ case BANDWIDTH_7_MHZ:
+ bw = 7;
+ break;
+ case BANDWIDTH_8_MHZ:
+ default:
+ bw = 8;
+ break;
+ }
+
+ *nominal_rate = (64 * bw * (1<<16) / (7 * 8) * 4000 / adc_clock + 2) / 4;
+
+ dprintk("%s: bw %d, adc_clock %d => 0x%x\n",
+ __FUNCTION__, bw, adc_clock, *nominal_rate);
+}
+
static int zl10353_sleep(struct dvb_frontend *fe)
{
static u8 zl10353_softdown[] = { 0x50, 0x0C, 0x44 };
@@ -125,7 +161,7 @@ static int zl10353_set_parameters(struct dvb_frontend *fe,
struct dvb_frontend_parameters *param)
{
struct zl10353_state *state = fe->demodulator_priv;
-
+ u16 nominal_rate;
u8 pllbuf[6] = { 0x67 };
/* These settings set "auto-everything" and start the FSM. */
@@ -138,18 +174,23 @@ static int zl10353_set_parameters(struct dvb_frontend *fe,
zl10353_single_write(fe, 0x56, 0x28);
zl10353_single_write(fe, 0x89, 0x20);
zl10353_single_write(fe, 0x5E, 0x00);
- zl10353_single_write(fe, 0x65, 0x5A);
- zl10353_single_write(fe, 0x66, 0xE9);
+
+ zl10353_calc_nominal_rate(fe, param->u.ofdm.bandwidth, &nominal_rate);
+ zl10353_single_write(fe, TRL_NOMINAL_RATE_1, msb(nominal_rate));
+ zl10353_single_write(fe, TRL_NOMINAL_RATE_0, lsb(nominal_rate));
+
zl10353_single_write(fe, 0x6C, 0xCD);
zl10353_single_write(fe, 0x6D, 0x7E);
- zl10353_single_write(fe, 0x62, 0x0A);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
// if there is no attached secondary tuner, we call set_params to program
// a potential tuner attached somewhere else
if (state->config.no_tuner) {
if (fe->ops.tuner_ops.set_params) {
fe->ops.tuner_ops.set_params(fe, param);
- if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
}
}
@@ -213,6 +254,29 @@ static int zl10353_read_status(struct dvb_frontend *fe, fe_status_t *status)
return 0;
}
+static int zl10353_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+ struct zl10353_state *state = fe->demodulator_priv;
+
+ *ber = zl10353_read_register(state, RS_ERR_CNT_2) << 16 |
+ zl10353_read_register(state, RS_ERR_CNT_1) << 8 |
+ zl10353_read_register(state, RS_ERR_CNT_0);
+
+ return 0;
+}
+
+static int zl10353_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+ struct zl10353_state *state = fe->demodulator_priv;
+
+ u16 signal = zl10353_read_register(state, AGC_GAIN_1) << 10 |
+ zl10353_read_register(state, AGC_GAIN_0) << 2 | 3;
+
+ *strength = ~signal;
+
+ return 0;
+}
+
static int zl10353_read_snr(struct dvb_frontend *fe, u16 *snr)
{
struct zl10353_state *state = fe->demodulator_priv;
@@ -227,6 +291,16 @@ static int zl10353_read_snr(struct dvb_frontend *fe, u16 *snr)
return 0;
}
+static int zl10353_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+ struct zl10353_state *state = fe->demodulator_priv;
+
+ *ucblocks = zl10353_read_register(state, RS_UBC_1) << 8 |
+ zl10353_read_register(state, RS_UBC_0);
+
+ return 0;
+}
+
static int zl10353_get_tune_settings(struct dvb_frontend *fe,
struct dvb_frontend_tune_settings
*fe_tune_settings)
@@ -261,6 +335,16 @@ static int zl10353_init(struct dvb_frontend *fe)
return 0;
}
+static int zl10353_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+ u8 val = 0x0a;
+
+ if (enable)
+ val |= 0x10;
+
+ return zl10353_single_write(fe, 0x62, val);
+}
+
static void zl10353_release(struct dvb_frontend *fe)
{
struct zl10353_state *state = fe->demodulator_priv;
@@ -319,15 +403,22 @@ static struct dvb_frontend_ops zl10353_ops = {
.init = zl10353_init,
.sleep = zl10353_sleep,
+ .i2c_gate_ctrl = zl10353_i2c_gate_ctrl,
.write = zl10353_write,
.set_frontend = zl10353_set_parameters,
.get_tune_settings = zl10353_get_tune_settings,
.read_status = zl10353_read_status,
+ .read_ber = zl10353_read_ber,
+ .read_signal_strength = zl10353_read_signal_strength,
.read_snr = zl10353_read_snr,
+ .read_ucblocks = zl10353_read_ucblocks,
};
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
module_param(debug_regs, int, 0644);
MODULE_PARM_DESC(debug_regs, "Turn on/off frontend register dumps (default:off).");
diff --git a/drivers/media/dvb/frontends/zl10353.h b/drivers/media/dvb/frontends/zl10353.h
index 0bc0109737f..cb274dc12b8 100644
--- a/drivers/media/dvb/frontends/zl10353.h
+++ b/drivers/media/dvb/frontends/zl10353.h
@@ -29,6 +29,9 @@ struct zl10353_config
/* demodulator's I2C address */
u8 demod_address;
+ /* frequencies in kHz */
+ int adc_clock; // default: 22528
+
/* set if no pll is connected to the secondary i2c bus */
int no_tuner;
diff --git a/drivers/media/dvb/frontends/zl10353_priv.h b/drivers/media/dvb/frontends/zl10353_priv.h
index b72224bd7dd..4962434b35e 100644
--- a/drivers/media/dvb/frontends/zl10353_priv.h
+++ b/drivers/media/dvb/frontends/zl10353_priv.h
@@ -24,19 +24,31 @@
#define ID_ZL10353 0x14
+#define msb(x) (((x) >> 8) & 0xff)
+#define lsb(x) ((x) & 0xff)
+
enum zl10353_reg_addr {
- INTERRUPT_0 = 0x00,
- INTERRUPT_1 = 0x01,
- INTERRUPT_2 = 0x02,
- INTERRUPT_3 = 0x03,
- INTERRUPT_4 = 0x04,
- INTERRUPT_5 = 0x05,
- STATUS_6 = 0x06,
- STATUS_7 = 0x07,
- STATUS_8 = 0x08,
- STATUS_9 = 0x09,
- SNR = 0x10,
- CHIP_ID = 0x7F,
+ INTERRUPT_0 = 0x00,
+ INTERRUPT_1 = 0x01,
+ INTERRUPT_2 = 0x02,
+ INTERRUPT_3 = 0x03,
+ INTERRUPT_4 = 0x04,
+ INTERRUPT_5 = 0x05,
+ STATUS_6 = 0x06,
+ STATUS_7 = 0x07,
+ STATUS_8 = 0x08,
+ STATUS_9 = 0x09,
+ AGC_GAIN_1 = 0x0A,
+ AGC_GAIN_0 = 0x0B,
+ SNR = 0x10,
+ RS_ERR_CNT_2 = 0x11,
+ RS_ERR_CNT_1 = 0x12,
+ RS_ERR_CNT_0 = 0x13,
+ RS_UBC_1 = 0x14,
+ RS_UBC_0 = 0x15,
+ TRL_NOMINAL_RATE_1 = 0x65,
+ TRL_NOMINAL_RATE_0 = 0x66,
+ CHIP_ID = 0x7F,
};
#endif /* _ZL10353_PRIV_ */
diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c
index 366c1371ee9..29ed532ba96 100644
--- a/drivers/media/dvb/ttpci/av7110.c
+++ b/drivers/media/dvb/ttpci/av7110.c
@@ -51,6 +51,7 @@
#include <linux/firmware.h>
#include <linux/crc32.h>
#include <linux/i2c.h>
+#include <linux/kthread.h>
#include <asm/system.h>
@@ -223,11 +224,10 @@ static void recover_arm(struct av7110 *av7110)
static void av7110_arm_sync(struct av7110 *av7110)
{
- av7110->arm_rmmod = 1;
- wake_up_interruptible(&av7110->arm_wait);
+ if (av7110->arm_thread)
+ kthread_stop(av7110->arm_thread);
- while (av7110->arm_thread)
- msleep(1);
+ av7110->arm_thread = NULL;
}
static int arm_thread(void *data)
@@ -238,17 +238,11 @@ static int arm_thread(void *data)
dprintk(4, "%p\n",av7110);
- lock_kernel();
- daemonize("arm_mon");
- sigfillset(&current->blocked);
- unlock_kernel();
-
- av7110->arm_thread = current;
-
for (;;) {
timeout = wait_event_interruptible_timeout(av7110->arm_wait,
- av7110->arm_rmmod, 5 * HZ);
- if (-ERESTARTSYS == timeout || av7110->arm_rmmod) {
+ kthread_should_stop(), 5 * HZ);
+
+ if (-ERESTARTSYS == timeout || kthread_should_stop()) {
/* got signal or told to quit*/
break;
}
@@ -276,7 +270,6 @@ static int arm_thread(void *data)
av7110->arm_errors = 0;
}
- av7110->arm_thread = NULL;
return 0;
}
@@ -695,8 +688,8 @@ static void gpioirq(unsigned long data)
static int dvb_osd_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, void *parg)
{
- struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
- struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
+ struct dvb_device *dvbdev = file->private_data;
+ struct av7110 *av7110 = dvbdev->priv;
dprintk(4, "%p\n", av7110);
@@ -786,7 +779,7 @@ int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
static int StartHWFilter(struct dvb_demux_filter *dvbdmxfilter)
{
struct dvb_demux_feed *dvbdmxfeed = dvbdmxfilter->feed;
- struct av7110 *av7110 = (struct av7110 *) dvbdmxfeed->demux->priv;
+ struct av7110 *av7110 = dvbdmxfeed->demux->priv;
u16 buf[20];
int ret, i;
u16 handle;
@@ -835,7 +828,7 @@ static int StartHWFilter(struct dvb_demux_filter *dvbdmxfilter)
static int StopHWFilter(struct dvb_demux_filter *dvbdmxfilter)
{
- struct av7110 *av7110 = (struct av7110 *) dvbdmxfilter->feed->demux->priv;
+ struct av7110 *av7110 = dvbdmxfilter->feed->demux->priv;
u16 buf[3];
u16 answ[2];
int ret;
@@ -871,7 +864,7 @@ static int StopHWFilter(struct dvb_demux_filter *dvbdmxfilter)
static int dvb_feed_start_pid(struct dvb_demux_feed *dvbdmxfeed)
{
struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
- struct av7110 *av7110 = (struct av7110 *) dvbdmx->priv;
+ struct av7110 *av7110 = dvbdmx->priv;
u16 *pid = dvbdmx->pids, npids[5];
int i;
int ret = 0;
@@ -914,7 +907,7 @@ static int dvb_feed_start_pid(struct dvb_demux_feed *dvbdmxfeed)
static int dvb_feed_stop_pid(struct dvb_demux_feed *dvbdmxfeed)
{
struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
- struct av7110 *av7110 = (struct av7110 *) dvbdmx->priv;
+ struct av7110 *av7110 = dvbdmx->priv;
u16 *pid = dvbdmx->pids, npids[5];
int i;
@@ -1103,9 +1096,9 @@ static int dvb_get_stc(struct dmx_demux *demux, unsigned int num,
/* pointer casting paranoia... */
BUG_ON(!demux);
- dvbdemux = (struct dvb_demux *) demux->priv;
+ dvbdemux = demux->priv;
BUG_ON(!dvbdemux);
- av7110 = (struct av7110 *) dvbdemux->priv;
+ av7110 = dvbdemux->priv;
dprintk(4, "%p\n", av7110);
@@ -1137,7 +1130,7 @@ static int dvb_get_stc(struct dmx_demux *demux, unsigned int num,
static int av7110_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
{
- struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+ struct av7110* av7110 = fe->dvb->priv;
switch (tone) {
case SEC_TONE_ON:
@@ -1197,7 +1190,7 @@ static int start_ts_capture(struct av7110 *budget)
static int budget_start_feed(struct dvb_demux_feed *feed)
{
struct dvb_demux *demux = feed->demux;
- struct av7110 *budget = (struct av7110 *) demux->priv;
+ struct av7110 *budget = demux->priv;
int status;
dprintk(2, "av7110: %p\n", budget);
@@ -1212,7 +1205,7 @@ static int budget_start_feed(struct dvb_demux_feed *feed)
static int budget_stop_feed(struct dvb_demux_feed *feed)
{
struct dvb_demux *demux = feed->demux;
- struct av7110 *budget = (struct av7110 *) demux->priv;
+ struct av7110 *budget = demux->priv;
int status;
dprintk(2, "budget: %p\n", budget);
@@ -1551,7 +1544,7 @@ static int get_firmware(struct av7110* av7110)
static int alps_bsrv2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
{
- struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+ struct av7110* av7110 = fe->dvb->priv;
u8 pwr = 0;
u8 buf[4];
struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
@@ -1702,7 +1695,7 @@ static int alps_tdlb7_tuner_set_params(struct dvb_frontend* fe, struct dvb_front
static int alps_tdlb7_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
{
#if defined(CONFIG_DVB_SP8870) || defined(CONFIG_DVB_SP8870_MODULE)
- struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+ struct av7110* av7110 = fe->dvb->priv;
return request_firmware(fw, name, &av7110->dev->pci->dev);
#else
@@ -1867,7 +1860,7 @@ static struct stv0297_config nexusca_stv0297_config = {
static int grundig_29504_401_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
{
- struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+ struct av7110* av7110 = fe->dvb->priv;
u32 div;
u8 cfg, cpump, band_select;
u8 data[4];
@@ -2338,6 +2331,7 @@ static int __devinit av7110_attach(struct saa7146_dev* dev,
const int length = TS_WIDTH * TS_HEIGHT;
struct pci_dev *pdev = dev->pci;
struct av7110 *av7110;
+ struct task_struct *thread;
int ret, count = 0;
dprintk(4, "dev: %p\n", dev);
@@ -2622,9 +2616,12 @@ static int __devinit av7110_attach(struct saa7146_dev* dev,
printk ("dvb-ttpci: Warning, firmware version 0x%04x is too old. "
"System might be unstable!\n", FW_VERSION(av7110->arm_app));
- ret = kernel_thread(arm_thread, (void *) av7110, 0);
- if (ret < 0)
+ thread = kthread_run(arm_thread, (void *) av7110, "arm_mon");
+ if (IS_ERR(thread)) {
+ ret = PTR_ERR(thread);
goto err_stop_arm_9;
+ }
+ av7110->arm_thread = thread;
/* set initial volume in mixer struct */
av7110->mixer.volume_left = volume;
diff --git a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h
index 9c79696da08..b98bd453cad 100644
--- a/drivers/media/dvb/ttpci/av7110.h
+++ b/drivers/media/dvb/ttpci/av7110.h
@@ -35,7 +35,6 @@
#define ANALOG_TUNER_VES1820 1
#define ANALOG_TUNER_STV0297 2
-#define ANALOG_TUNER_VBI 0x100
extern int av7110_debug;
@@ -205,7 +204,6 @@ struct av7110 {
struct task_struct *arm_thread;
wait_queue_head_t arm_wait;
u16 arm_loops;
- int arm_rmmod;
void *debi_virt;
dma_addr_t debi_bus;
diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c
index 8c577cf30fb..e719af80768 100644
--- a/drivers/media/dvb/ttpci/av7110_av.c
+++ b/drivers/media/dvb/ttpci/av7110_av.c
@@ -31,7 +31,6 @@
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/string.h>
-#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/smp_lock.h>
#include <linux/fs.h>
@@ -881,8 +880,8 @@ static int dvb_video_get_event (struct av7110 *av7110, struct video_event *event
static unsigned int dvb_video_poll(struct file *file, poll_table *wait)
{
- struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
- struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
+ struct dvb_device *dvbdev = file->private_data;
+ struct av7110 *av7110 = dvbdev->priv;
unsigned int mask = 0;
dprintk(2, "av7110:%p, \n", av7110);
@@ -909,8 +908,8 @@ static unsigned int dvb_video_poll(struct file *file, poll_table *wait)
static ssize_t dvb_video_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
- struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
- struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
+ struct dvb_device *dvbdev = file->private_data;
+ struct av7110 *av7110 = dvbdev->priv;
dprintk(2, "av7110:%p, \n", av7110);
@@ -925,8 +924,8 @@ static ssize_t dvb_video_write(struct file *file, const char __user *buf,
static unsigned int dvb_audio_poll(struct file *file, poll_table *wait)
{
- struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
- struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
+ struct dvb_device *dvbdev = file->private_data;
+ struct av7110 *av7110 = dvbdev->priv;
unsigned int mask = 0;
dprintk(2, "av7110:%p, \n", av7110);
@@ -945,8 +944,8 @@ static unsigned int dvb_audio_poll(struct file *file, poll_table *wait)
static ssize_t dvb_audio_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
- struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
- struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
+ struct dvb_device *dvbdev = file->private_data;
+ struct av7110 *av7110 = dvbdev->priv;
dprintk(2, "av7110:%p, \n", av7110);
@@ -990,8 +989,8 @@ static int play_iframe(struct av7110 *av7110, u8 __user *buf, unsigned int len,
static int dvb_video_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, void *parg)
{
- struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
- struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
+ struct dvb_device *dvbdev = file->private_data;
+ struct av7110 *av7110 = dvbdev->priv;
unsigned long arg = (unsigned long) parg;
int ret = 0;
@@ -1204,8 +1203,8 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file,
static int dvb_audio_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, void *parg)
{
- struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
- struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
+ struct dvb_device *dvbdev = file->private_data;
+ struct av7110 *av7110 = dvbdev->priv;
unsigned long arg = (unsigned long) parg;
int ret = 0;
@@ -1350,8 +1349,8 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file,
static int dvb_video_open(struct inode *inode, struct file *file)
{
- struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
- struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
+ struct dvb_device *dvbdev = file->private_data;
+ struct av7110 *av7110 = dvbdev->priv;
int err;
dprintk(2, "av7110:%p, \n", av7110);
@@ -1375,8 +1374,8 @@ static int dvb_video_open(struct inode *inode, struct file *file)
static int dvb_video_release(struct inode *inode, struct file *file)
{
- struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
- struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
+ struct dvb_device *dvbdev = file->private_data;
+ struct av7110 *av7110 = dvbdev->priv;
dprintk(2, "av7110:%p, \n", av7110);
@@ -1389,9 +1388,9 @@ static int dvb_video_release(struct inode *inode, struct file *file)
static int dvb_audio_open(struct inode *inode, struct file *file)
{
- struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
- struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
- int err=dvb_generic_open(inode, file);
+ struct dvb_device *dvbdev = file->private_data;
+ struct av7110 *av7110 = dvbdev->priv;
+ int err = dvb_generic_open(inode, file);
dprintk(2, "av7110:%p, \n", av7110);
@@ -1404,8 +1403,8 @@ static int dvb_audio_open(struct inode *inode, struct file *file)
static int dvb_audio_release(struct inode *inode, struct file *file)
{
- struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
- struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
+ struct dvb_device *dvbdev = file->private_data;
+ struct av7110 *av7110 = dvbdev->priv;
dprintk(2, "av7110:%p, \n", av7110);
diff --git a/drivers/media/dvb/ttpci/av7110_ca.c b/drivers/media/dvb/ttpci/av7110_ca.c
index dd9aee314e0..e9b4e88e793 100644
--- a/drivers/media/dvb/ttpci/av7110_ca.c
+++ b/drivers/media/dvb/ttpci/av7110_ca.c
@@ -29,7 +29,6 @@
*/
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/fs.h>
@@ -215,8 +214,8 @@ static ssize_t ci_ll_read(struct dvb_ringbuffer *cibuf, struct file *file,
static int dvb_ca_open(struct inode *inode, struct file *file)
{
- struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
- struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
+ struct dvb_device *dvbdev = file->private_data;
+ struct av7110 *av7110 = dvbdev->priv;
int err = dvb_generic_open(inode, file);
dprintk(8, "av7110:%p\n",av7110);
@@ -229,8 +228,8 @@ static int dvb_ca_open(struct inode *inode, struct file *file)
static unsigned int dvb_ca_poll (struct file *file, poll_table *wait)
{
- struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
- struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
+ struct dvb_device *dvbdev = file->private_data;
+ struct av7110 *av7110 = dvbdev->priv;
struct dvb_ringbuffer *rbuf = &av7110->ci_rbuffer;
struct dvb_ringbuffer *wbuf = &av7110->ci_wbuffer;
unsigned int mask = 0;
@@ -252,8 +251,8 @@ static unsigned int dvb_ca_poll (struct file *file, poll_table *wait)
static int dvb_ca_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, void *parg)
{
- struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
- struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
+ struct dvb_device *dvbdev = file->private_data;
+ struct av7110 *av7110 = dvbdev->priv;
unsigned long arg = (unsigned long) parg;
dprintk(8, "av7110:%p\n",av7110);
@@ -330,8 +329,8 @@ static int dvb_ca_ioctl(struct inode *inode, struct file *file,
static ssize_t dvb_ca_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
- struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
- struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
+ struct dvb_device *dvbdev = file->private_data;
+ struct av7110 *av7110 = dvbdev->priv;
dprintk(8, "av7110:%p\n",av7110);
return ci_ll_write(&av7110->ci_wbuffer, file, buf, count, ppos);
@@ -340,15 +339,13 @@ static ssize_t dvb_ca_write(struct file *file, const char __user *buf,
static ssize_t dvb_ca_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
- struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
- struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
+ struct dvb_device *dvbdev = file->private_data;
+ struct av7110 *av7110 = dvbdev->priv;
dprintk(8, "av7110:%p\n",av7110);
return ci_ll_read(&av7110->ci_rbuffer, file, buf, count, ppos);
}
-
-
static struct file_operations dvb_ca_fops = {
.owner = THIS_MODULE,
.read = dvb_ca_read,
diff --git a/drivers/media/dvb/ttpci/av7110_hw.c b/drivers/media/dvb/ttpci/av7110_hw.c
index 37de2e88a27..4d7150e15d1 100644
--- a/drivers/media/dvb/ttpci/av7110_hw.c
+++ b/drivers/media/dvb/ttpci/av7110_hw.c
@@ -32,7 +32,6 @@
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/string.h>
-#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/smp_lock.h>
#include <linux/fs.h>
diff --git a/drivers/media/dvb/ttpci/av7110_ir.c b/drivers/media/dvb/ttpci/av7110_ir.c
index e4544ea2b89..f59465bb0af 100644
--- a/drivers/media/dvb/ttpci/av7110_ir.c
+++ b/drivers/media/dvb/ttpci/av7110_ir.c
@@ -4,6 +4,7 @@
#include <linux/moduleparam.h>
#include <linux/input.h>
#include <linux/proc_fs.h>
+#include <linux/kernel.h>
#include <asm/bitops.h>
#include "av7110.h"
@@ -16,6 +17,7 @@
static int av_cnt;
static struct av7110 *av_list[4];
static struct input_dev *input_dev;
+static char input_phys[32];
static u8 delay_timer_finished;
@@ -217,7 +219,7 @@ int __devinit av7110_ir_init(struct av7110 *av7110)
static struct proc_dir_entry *e;
int err;
- if (av_cnt >= sizeof av_list/sizeof av_list[0])
+ if (av_cnt >= ARRAY_SIZE(av_list))
return -ENOSPC;
av7110_setup_irc_config(av7110, 0x0001);
@@ -231,8 +233,22 @@ int __devinit av7110_ir_init(struct av7110 *av7110)
if (!input_dev)
return -ENOMEM;
+ snprintf(input_phys, sizeof(input_phys),
+ "pci-%s/ir0", pci_name(av7110->dev->pci));
+
input_dev->name = "DVB on-card IR receiver";
+ input_dev->phys = input_phys;
+ input_dev->id.bustype = BUS_PCI;
+ input_dev->id.version = 1;
+ if (av7110->dev->pci->subsystem_vendor) {
+ input_dev->id.vendor = av7110->dev->pci->subsystem_vendor;
+ input_dev->id.product = av7110->dev->pci->subsystem_device;
+ } else {
+ input_dev->id.vendor = av7110->dev->pci->vendor;
+ input_dev->id.product = av7110->dev->pci->device;
+ }
+ input_dev->cdev.dev = &av7110->dev->pci->dev;
set_bit(EV_KEY, input_dev->evbit);
set_bit(EV_REP, input_dev->evbit);
input_register_keys();
diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c
index 10cfe3131e7..cde5d3ae7ec 100644
--- a/drivers/media/dvb/ttpci/av7110_v4l.c
+++ b/drivers/media/dvb/ttpci/av7110_v4l.c
@@ -26,7 +26,6 @@
*/
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/fs.h>
@@ -141,17 +140,6 @@ static int ves1820_writereg(struct saa7146_dev *dev, u8 addr, u8 reg, u8 data)
return 0;
}
-static int stv0297_writereg(struct saa7146_dev *dev, u8 addr, u8 reg, u8 data)
-{
- u8 buf [] = { reg, data };
- struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = 2 };
-
- if (1 != saa7146_i2c_transfer(dev, &msg, 1, 1))
- return -1;
- return 0;
-}
-
-
static int tuner_write(struct saa7146_dev *dev, u8 addr, u8 data [4])
{
struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = data, .len = 4 };
@@ -194,6 +182,7 @@ static int ves1820_set_tv_freq(struct saa7146_dev *dev, u32 freq)
static int stv0297_set_tv_freq(struct saa7146_dev *dev, u32 freq)
{
+ struct av7110 *av7110 = (struct av7110*)dev->ext_priv;
u32 div;
u8 data[4];
@@ -214,8 +203,8 @@ static int stv0297_set_tv_freq(struct saa7146_dev *dev, u32 freq)
else
return -EINVAL;
- stv0297_writereg(dev, 0x1C, 0x87, 0x78);
- stv0297_writereg(dev, 0x1C, 0x86, 0xc8);
+ if (av7110->fe->ops.i2c_gate_ctrl)
+ av7110->fe->ops.i2c_gate_ctrl(av7110->fe, 1);
return tuner_write(dev, 0x63, data);
}
@@ -818,20 +807,20 @@ int av7110_init_v4l(struct av7110 *av7110)
saa7146_vv_release(dev);
return -ENODEV;
}
- if (saa7146_register_device(&av7110->vbi_dev, dev, "av7110", VFL_TYPE_VBI)) {
+ if (saa7146_register_device(&av7110->vbi_dev, dev, "av7110", VFL_TYPE_VBI))
ERR(("cannot register vbi v4l2 device. skipping.\n"));
- } else {
- if (av7110->analog_tuner_flags)
- av7110->analog_tuner_flags |= ANALOG_TUNER_VBI;
- }
return 0;
}
int av7110_exit_v4l(struct av7110 *av7110)
{
+ struct saa7146_dev* dev = av7110->dev;
+
saa7146_unregister_device(&av7110->v4l_dev, av7110->dev);
- if (av7110->analog_tuner_flags & ANALOG_TUNER_VBI)
- saa7146_unregister_device(&av7110->vbi_dev, av7110->dev);
+ saa7146_unregister_device(&av7110->vbi_dev, av7110->dev);
+
+ saa7146_vv_release(dev);
+
return 0;
}
diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c
index 89ab4b59155..3035b224c7a 100644
--- a/drivers/media/dvb/ttpci/budget-av.c
+++ b/drivers/media/dvb/ttpci/budget-av.c
@@ -1089,6 +1089,8 @@ static int budget_av_detach(struct saa7146_dev *dev)
msleep(200);
saa7146_unregister_device(&budget_av->vd, dev);
+
+ saa7146_vv_release(dev);
}
if (budget_av->budget.ci_present)
@@ -1145,6 +1147,7 @@ static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio
if ((err = saa7146_register_device(&budget_av->vd, dev, "knc1", VFL_TYPE_GRABBER))) {
/* fixme: proper cleanup here */
ERR(("cannot register capture v4l2 device.\n"));
+ saa7146_vv_release(dev);
return err;
}
diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c
index f2066b47bae..464feaf1a9a 100644
--- a/drivers/media/dvb/ttpci/budget-ci.c
+++ b/drivers/media/dvb/ttpci/budget-ci.c
@@ -29,8 +29,6 @@
* the project's page is at http://www.linuxtv.org/dvb/
*/
-#include "budget.h"
-
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/slab.h>
@@ -39,6 +37,8 @@
#include <linux/spinlock.h>
#include <media/ir-common.h>
+#include "budget.h"
+
#include "dvb_ca_en50221.h"
#include "stv0299.h"
#include "stv0297.h"
@@ -130,6 +130,7 @@ static void msp430_ir_interrupt(unsigned long data)
int toggle;
static int prev_toggle = -1;
static u32 ir_key;
+ static int state = 0;
u32 command = ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8;
/*
@@ -138,21 +139,34 @@ static void msp430_ir_interrupt(unsigned long data)
* type1: X1CCCCCC, C = command bits (0 - 63)
* type2: X0TDDDDD, D = device bits (0 - 31), T = RC5 toggle bit
*
- * More than one command byte may be generated before the device byte
- * Only when we have both, a correct keypress is generated
+ * Each signal from the remote control can generate one or more command
+ * bytes and one or more device bytes. For the repeated bytes, the
+ * highest bit (X) is set. The first command byte is always generated
+ * before the first device byte. Other than that, no specific order
+ * seems to apply.
+ *
+ * Only when we have a command and device byte, a keypress is
+ * generated.
*/
+ if (ir_debug)
+ printk("budget_ci: received byte 0x%02x\n", command);
+
+ /* Is this a repeated byte? */
+ if (command & 0x80)
+ return;
+
/* Is this a RC5 command byte? */
if (command & 0x40) {
- if (ir_debug)
- printk("budget_ci: received command byte 0x%02x\n", command);
+ state = 1;
ir_key = command & 0x3f;
return;
}
/* It's a RC5 device byte */
- if (ir_debug)
- printk("budget_ci: received device byte 0x%02x\n", command);
+ if (!state)
+ return;
+ state = 0;
device = command & 0x1f;
toggle = command & 0x20;
@@ -223,7 +237,6 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
switch (budget_ci->budget.dev->pci->subsystem_device) {
case 0x100c:
case 0x100f:
- case 0x1010:
case 0x1011:
case 0x1012:
case 0x1017:
@@ -236,6 +249,16 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
else
budget_ci->ir.rc5_device = rc5_device;
break;
+ case 0x1010:
+ /* for the Technotrend 1500 bundled remote */
+ ir_input_init(input_dev, &budget_ci->ir.state,
+ IR_TYPE_RC5, ir_codes_tt_1500);
+
+ if (rc5_device < 0)
+ budget_ci->ir.rc5_device = IR_DEVICE_ANY;
+ else
+ budget_ci->ir.rc5_device = rc5_device;
+ break;
default:
/* unknown remote */
ir_input_init(input_dev, &budget_ci->ir.state,
@@ -869,6 +892,17 @@ static struct tda1004x_config philips_tdm1316l_config = {
.request_firmware = philips_tdm1316l_request_firmware,
};
+static struct tda1004x_config philips_tdm1316l_config_invert = {
+
+ .demod_address = 0x8,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_4M,
+ .agc_config = TDA10046_AGC_DEFAULT,
+ .if_freq = TDA10046_FREQ_3617,
+ .request_firmware = philips_tdm1316l_request_firmware,
+};
+
static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
{
struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
@@ -1092,9 +1126,8 @@ static void frontend_init(struct budget_ci *budget_ci)
case 0x1012: // TT DVB-T CI budget (tda10046/Philips tdm1316l(tda6651tt))
budget_ci->tuner_pll_address = 0x60;
- philips_tdm1316l_config.invert = 1;
budget_ci->budget.dvb_frontend =
- dvb_attach(tda10046_attach, &philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
+ dvb_attach(tda10046_attach, &philips_tdm1316l_config_invert, &budget_ci->budget.i2c_adap);
if (budget_ci->budget.dvb_frontend) {
budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
index 60820deb900..b60cdc93d6d 100644
--- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
+++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
@@ -1690,6 +1690,7 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i
#endif
ttusb->i2c_adap.algo = &ttusb_dec_algo;
ttusb->i2c_adap.algo_data = NULL;
+ ttusb->i2c_adap.dev.parent = &udev->dev;
result = i2c_add_adapter(&ttusb->i2c_adap);
if (result) {
diff --git a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c
index bd6e7baae2e..78c98b08997 100644
--- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c
+++ b/drivers/media/dvb/ttusb-dec/ttusb_dec.c
@@ -20,8 +20,6 @@
*
*/
-#include <linux/mutex.h>
-
#include <linux/list.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
@@ -35,6 +33,8 @@
#include <linux/init.h>
#include <linux/input.h>
+#include <linux/mutex.h>
+
#include "dmxdev.h"
#include "dvb_demux.h"
#include "dvb_filter.h"
diff --git a/drivers/media/radio/dsbr100.c b/drivers/media/radio/dsbr100.c
index db865a0667e..df8d0520d1d 100644
--- a/drivers/media/radio/dsbr100.c
+++ b/drivers/media/radio/dsbr100.c
@@ -144,7 +144,7 @@ struct dsbr100_device {
/* File system interface */
-static struct file_operations usb_dsbr100_fops = {
+static const struct file_operations usb_dsbr100_fops = {
.owner = THIS_MODULE,
.open = usb_dsbr100_open,
.release = usb_dsbr100_close,
diff --git a/drivers/media/radio/miropcm20-radio.c b/drivers/media/radio/miropcm20-radio.c
index c4312fa0e2f..c7c9d1dc069 100644
--- a/drivers/media/radio/miropcm20-radio.c
+++ b/drivers/media/radio/miropcm20-radio.c
@@ -216,7 +216,7 @@ static struct pcm20_device pcm20_unit = {
.muted = 1,
};
-static struct file_operations pcm20_fops = {
+static const struct file_operations pcm20_fops = {
.owner = THIS_MODULE,
.open = video_exclusive_open,
.release = video_exclusive_release,
diff --git a/drivers/media/radio/miropcm20-rds.c b/drivers/media/radio/miropcm20-rds.c
index c1b1db65e66..aed11477378 100644
--- a/drivers/media/radio/miropcm20-rds.c
+++ b/drivers/media/radio/miropcm20-rds.c
@@ -14,7 +14,6 @@
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
-#include <linux/sched.h> /* current, TASK_*, schedule_timeout() */
#include <linux/delay.h>
#include <asm/uaccess.h>
#include "miropcm20-rds-core.h"
@@ -105,7 +104,7 @@ static ssize_t rds_f_read(struct file *file, char __user *buffer, size_t length,
}
}
-static struct file_operations rds_fops = {
+static const struct file_operations rds_fops = {
.owner = THIS_MODULE,
.read = rds_f_read,
.open = rds_f_open,
diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c
index 3368a89bfad..b2e88ad2897 100644
--- a/drivers/media/radio/radio-aimslab.c
+++ b/drivers/media/radio/radio-aimslab.c
@@ -358,7 +358,7 @@ static int rt_ioctl(struct inode *inode, struct file *file,
static struct rt_device rtrack_unit;
-static struct file_operations rtrack_fops = {
+static const struct file_operations rtrack_fops = {
.owner = THIS_MODULE,
.open = video_exclusive_open,
.release = video_exclusive_release,
diff --git a/drivers/media/radio/radio-aztech.c b/drivers/media/radio/radio-aztech.c
index 3ba5fa8cf7e..9f1addae692 100644
--- a/drivers/media/radio/radio-aztech.c
+++ b/drivers/media/radio/radio-aztech.c
@@ -180,158 +180,200 @@ static int az_setfreq(struct az_device *dev, unsigned long frequency)
return 0;
}
-static int az_do_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, void *arg)
+static int vidioc_querycap (struct file *file, void *priv,
+ struct v4l2_capability *v)
+{
+ strlcpy(v->driver, "radio-aztech", sizeof (v->driver));
+ strlcpy(v->card, "Aztech Radio", sizeof (v->card));
+ sprintf(v->bus_info,"ISA");
+ v->version = RADIO_VERSION;
+ v->capabilities = V4L2_CAP_TUNER;
+ return 0;
+}
+
+static int vidioc_g_tuner (struct file *file, void *priv,
+ struct v4l2_tuner *v)
{
struct video_device *dev = video_devdata(file);
struct az_device *az = dev->priv;
- switch(cmd)
- {
- case VIDIOC_QUERYCAP:
- {
- struct v4l2_capability *v = arg;
- memset(v,0,sizeof(*v));
- strlcpy(v->driver, "radio-aztech", sizeof (v->driver));
- strlcpy(v->card, "Aztech Radio", sizeof (v->card));
- sprintf(v->bus_info,"ISA");
- v->version = RADIO_VERSION;
- v->capabilities = V4L2_CAP_TUNER;
+ if (v->index > 0)
+ return -EINVAL;
- return 0;
- }
- case VIDIOC_G_TUNER:
- {
- struct v4l2_tuner *v = arg;
-
- if (v->index > 0)
- return -EINVAL;
-
- memset(v,0,sizeof(*v));
- strcpy(v->name, "FM");
- v->type = V4L2_TUNER_RADIO;
-
- v->rangelow=(87*16000);
- v->rangehigh=(108*16000);
- v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
- v->capability=V4L2_TUNER_CAP_LOW;
- if(az_getstereo(az))
- v->audmode = V4L2_TUNER_MODE_STEREO;
- else
- v->audmode = V4L2_TUNER_MODE_MONO;
- v->signal=0xFFFF*az_getsigstr(az);
+ strcpy(v->name, "FM");
+ v->type = V4L2_TUNER_RADIO;
- return 0;
- }
- case VIDIOC_S_TUNER:
- {
- struct v4l2_tuner *v = arg;
+ v->rangelow=(87*16000);
+ v->rangehigh=(108*16000);
+ v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
+ v->capability=V4L2_TUNER_CAP_LOW;
+ if(az_getstereo(az))
+ v->audmode = V4L2_TUNER_MODE_STEREO;
+ else
+ v->audmode = V4L2_TUNER_MODE_MONO;
+ v->signal=0xFFFF*az_getsigstr(az);
- if (v->index > 0)
- return -EINVAL;
+ return 0;
+}
- return 0;
- }
- case VIDIOC_S_FREQUENCY:
- {
- struct v4l2_frequency *f = arg;
- az->curfreq = f->frequency;
- az_setfreq(az, az->curfreq);
- return 0;
- }
- case VIDIOC_G_FREQUENCY:
- {
- struct v4l2_frequency *f = arg;
+static int vidioc_s_tuner (struct file *file, void *priv,
+ struct v4l2_tuner *v)
+{
+ if (v->index > 0)
+ return -EINVAL;
- f->type = V4L2_TUNER_RADIO;
- f->frequency = az->curfreq;
+ return 0;
+}
- return 0;
- }
+static int vidioc_g_audio (struct file *file, void *priv,
+ struct v4l2_audio *a)
+{
+ if (a->index > 1)
+ return -EINVAL;
- case VIDIOC_QUERYCTRL:
- {
- struct v4l2_queryctrl *qc = arg;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
- if (qc->id && qc->id == radio_qctrl[i].id) {
- memcpy(qc, &(radio_qctrl[i]),
- sizeof(*qc));
- return (0);
- }
- }
- return -EINVAL;
- }
- case VIDIOC_G_CTRL:
- {
- struct v4l2_control *ctrl= arg;
-
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_MUTE:
- if (az->curvol==0)
- ctrl->value=1;
- else
- ctrl->value=0;
- return (0);
- case V4L2_CID_AUDIO_VOLUME:
- ctrl->value=az->curvol * 6554;
- return (0);
- }
- return -EINVAL;
- }
- case VIDIOC_S_CTRL:
- {
- struct v4l2_control *ctrl= arg;
-
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_MUTE:
- if (ctrl->value) {
- az_setvol(az,0);
- } else {
- az_setvol(az,az->curvol);
- }
- return (0);
- case V4L2_CID_AUDIO_VOLUME:
- az_setvol(az,ctrl->value);
- return (0);
- }
- return -EINVAL;
+ strcpy(a->name, "Radio");
+ a->capability = V4L2_AUDCAP_STEREO;
+ return 0;
+}
+
+static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
+{
+ *i = 0;
+ return 0;
+}
+
+static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
+{
+ if (i != 0)
+ return -EINVAL;
+ return 0;
+}
+
+
+static int vidioc_s_audio (struct file *file, void *priv,
+ struct v4l2_audio *a)
+{
+ if (a->index != 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int vidioc_s_frequency (struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+ struct video_device *dev = video_devdata(file);
+ struct az_device *az = dev->priv;
+
+ az->curfreq = f->frequency;
+ az_setfreq(az, az->curfreq);
+ return 0;
+}
+
+static int vidioc_g_frequency (struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+ struct video_device *dev = video_devdata(file);
+ struct az_device *az = dev->priv;
+
+ f->type = V4L2_TUNER_RADIO;
+ f->frequency = az->curfreq;
+
+ return 0;
+}
+
+static int vidioc_queryctrl (struct file *file, void *priv,
+ struct v4l2_queryctrl *qc)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
+ if (qc->id && qc->id == radio_qctrl[i].id) {
+ memcpy(qc, &(radio_qctrl[i]),
+ sizeof(*qc));
+ return (0);
}
+ }
+ return -EINVAL;
+}
+
+static int vidioc_g_ctrl (struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct video_device *dev = video_devdata(file);
+ struct az_device *az = dev->priv;
- default:
- return v4l_compat_translate_ioctl(inode,file,cmd,arg,
- az_do_ioctl);
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ if (az->curvol==0)
+ ctrl->value=1;
+ else
+ ctrl->value=0;
+ return (0);
+ case V4L2_CID_AUDIO_VOLUME:
+ ctrl->value=az->curvol * 6554;
+ return (0);
}
+ return -EINVAL;
}
-static int az_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+static int vidioc_s_ctrl (struct file *file, void *priv,
+ struct v4l2_control *ctrl)
{
- return video_usercopy(inode, file, cmd, arg, az_do_ioctl);
+ struct video_device *dev = video_devdata(file);
+ struct az_device *az = dev->priv;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ if (ctrl->value) {
+ az_setvol(az,0);
+ } else {
+ az_setvol(az,az->curvol);
+ }
+ return (0);
+ case V4L2_CID_AUDIO_VOLUME:
+ az_setvol(az,ctrl->value);
+ return (0);
+ }
+ return -EINVAL;
}
static struct az_device aztech_unit;
-static struct file_operations aztech_fops = {
+static const struct file_operations aztech_fops = {
.owner = THIS_MODULE,
.open = video_exclusive_open,
.release = video_exclusive_release,
- .ioctl = az_ioctl,
+ .ioctl = video_ioctl2,
.compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek,
};
static struct video_device aztech_radio=
{
- .owner = THIS_MODULE,
- .name = "Aztech radio",
- .type = VID_TYPE_TUNER,
- .hardware = 0,
- .fops = &aztech_fops,
+ .owner = THIS_MODULE,
+ .name = "Aztech radio",
+ .type = VID_TYPE_TUNER,
+ .hardware = 0,
+ .fops = &aztech_fops,
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_g_tuner = vidioc_g_tuner,
+ .vidioc_s_tuner = vidioc_s_tuner,
+ .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_g_frequency = vidioc_g_frequency,
+ .vidioc_s_frequency = vidioc_s_frequency,
+ .vidioc_queryctrl = vidioc_queryctrl,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
};
+module_param_named(debug,aztech_radio.debug, int, 0644);
+MODULE_PARM_DESC(debug,"activates debug info");
+
static int __init aztech_init(void)
{
if(io==-1)
diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c
index 69d4b7919c5..8fbf0d8bd27 100644
--- a/drivers/media/radio/radio-cadet.c
+++ b/drivers/media/radio/radio-cadet.c
@@ -507,7 +507,7 @@ cadet_poll(struct file *file, struct poll_table_struct *wait)
}
-static struct file_operations cadet_fops = {
+static const struct file_operations cadet_fops = {
.owner = THIS_MODULE,
.open = cadet_open,
.release = cadet_release,
diff --git a/drivers/media/radio/radio-gemtek-pci.c b/drivers/media/radio/radio-gemtek-pci.c
index eb14106f66f..74976cba869 100644
--- a/drivers/media/radio/radio-gemtek-pci.c
+++ b/drivers/media/radio/radio-gemtek-pci.c
@@ -89,14 +89,6 @@ static struct v4l2_queryctrl radio_qctrl[] = {
#define GEMTEK_PCI_RANGE_HIGH (108*16000)
#endif
-#ifndef TRUE
-#define TRUE (1)
-#endif
-
-#ifndef FALSE
-#define FALSE (0)
-#endif
-
struct gemtek_pci_card {
struct video_device *videodev;
@@ -146,12 +138,12 @@ static void __gemtek_pci_cmd( u16 value, u32 port, u8 *last_byte, int keep )
static inline void gemtek_pci_nil( u32 port, u8 *last_byte )
{
- __gemtek_pci_cmd( 0x00, port, last_byte, FALSE );
+ __gemtek_pci_cmd( 0x00, port, last_byte, false );
}
static inline void gemtek_pci_cmd( u16 cmd, u32 port, u8 *last_byte )
{
- __gemtek_pci_cmd( cmd, port, last_byte, TRUE );
+ __gemtek_pci_cmd( cmd, port, last_byte, true );
}
static void gemtek_pci_setfrequency( struct gemtek_pci_card *card, unsigned long frequency )
@@ -184,14 +176,14 @@ static void gemtek_pci_setfrequency( struct gemtek_pci_card *card, unsigned long
static inline void gemtek_pci_mute( struct gemtek_pci_card *card )
{
outb( 0x1f, card->iobase );
- card->mute = TRUE;
+ card->mute = true;
}
static inline void gemtek_pci_unmute( struct gemtek_pci_card *card )
{
if ( card->mute ) {
gemtek_pci_setfrequency( card, card->current_frequency );
- card->mute = FALSE;
+ card->mute = false;
}
}
@@ -259,7 +251,7 @@ static int gemtek_pci_do_ioctl(struct inode *inode, struct file *file,
gemtek_pci_setfrequency( card, f->frequency );
card->current_frequency = f->frequency;
- card->mute = FALSE;
+ card->mute = false;
return 0;
}
case VIDIOC_QUERYCTRL:
@@ -346,7 +338,7 @@ MODULE_DEVICE_TABLE( pci, gemtek_pci_id );
static int mx = 1;
-static struct file_operations gemtek_pci_fops = {
+static const struct file_operations gemtek_pci_fops = {
.owner = THIS_MODULE,
.open = video_exclusive_open,
.release = video_exclusive_release,
diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c
index 730fe16126c..36c4be6622c 100644
--- a/drivers/media/radio/radio-gemtek.c
+++ b/drivers/media/radio/radio-gemtek.c
@@ -296,7 +296,7 @@ static int gemtek_ioctl(struct inode *inode, struct file *file,
static struct gemtek_device gemtek_unit;
-static struct file_operations gemtek_fops = {
+static const struct file_operations gemtek_fops = {
.owner = THIS_MODULE,
.open = video_exclusive_open,
.release = video_exclusive_release,
diff --git a/drivers/media/radio/radio-maestro.c b/drivers/media/radio/radio-maestro.c
index e8ce5f75cf1..e67b7f25802 100644
--- a/drivers/media/radio/radio-maestro.c
+++ b/drivers/media/radio/radio-maestro.c
@@ -22,7 +22,6 @@
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/delay.h>
-#include <linux/sched.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/mutex.h>
@@ -99,7 +98,7 @@ static struct pci_driver maestro_r_driver = {
.remove = __devexit_p(maestro_remove),
};
-static struct file_operations maestro_fops = {
+static const struct file_operations maestro_fops = {
.owner = THIS_MODULE,
.open = video_exclusive_open,
.release = video_exclusive_release,
diff --git a/drivers/media/radio/radio-maxiradio.c b/drivers/media/radio/radio-maxiradio.c
index c2eeae7a10d..8e184cfc1c9 100644
--- a/drivers/media/radio/radio-maxiradio.c
+++ b/drivers/media/radio/radio-maxiradio.c
@@ -27,7 +27,9 @@
* BUGS:
* - card unmutes if you change frequency
*
- * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
+ * (c) 2006, 2007 by Mauro Carvalho Chehab <mchehab@infradead.org>:
+ * - Conversion to V4L2 API
+ * - Uses video_ioctl2 for parsing and to add debug support
*/
@@ -35,7 +37,6 @@
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/delay.h>
-#include <linux/sched.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/mutex.h>
@@ -44,10 +45,18 @@
#include <linux/videodev2.h>
#include <media/v4l2-common.h>
-#define DRIVER_VERSION "0.76"
+#define DRIVER_VERSION "0.77"
#include <linux/version.h> /* for KERNEL_VERSION MACRO */
-#define RADIO_VERSION KERNEL_VERSION(0,7,6)
+#define RADIO_VERSION KERNEL_VERSION(0,7,7)
+
+static struct video_device maxiradio_radio;
+
+#define dprintk(num, fmt, arg...) \
+ do { \
+ if (maxiradio_radio.debug >= num) \
+ printk(KERN_DEBUG "%s: " fmt, \
+ maxiradio_radio.name, ## arg); } while (0)
static struct v4l2_queryctrl radio_qctrl[] = {
{
@@ -82,30 +91,21 @@ module_param(radio_nr, int, 0);
#define FREQ_IF 171200 /* 10.7*16000 */
#define FREQ_STEP 200 /* 12.5*16 */
-#define FREQ2BITS(x) ((( (unsigned int)(x)+FREQ_IF+(FREQ_STEP<<1))\
- /(FREQ_STEP<<2))<<2) /* (x==fmhz*16*1000) -> bits */
+/* (x==fmhz*16*1000) -> bits */
+#define FREQ2BITS(x) ((( (unsigned int)(x)+FREQ_IF+(FREQ_STEP<<1)) \
+ /(FREQ_STEP<<2))<<2)
#define BITS2FREQ(x) ((x) * FREQ_STEP - FREQ_IF)
-static int radio_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg);
-
-static struct file_operations maxiradio_fops = {
+static const struct file_operations maxiradio_fops = {
.owner = THIS_MODULE,
.open = video_exclusive_open,
.release = video_exclusive_release,
- .ioctl = radio_ioctl,
+ .ioctl = video_ioctl2,
.compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek,
};
-static struct video_device maxiradio_radio =
-{
- .owner = THIS_MODULE,
- .name = "Maxi Radio FM2000 radio",
- .type = VID_TYPE_TUNER,
- .fops = &maxiradio_fops,
-};
static struct radio_device
{
@@ -117,12 +117,14 @@ static struct radio_device
unsigned long freq;
struct mutex lock;
-} radio_unit = {0, 0, 0, 0, };
-
+} radio_unit = {
+ .muted =1,
+ .freq = FREQ_LO,
+};
static void outbit(unsigned long bit, __u16 io)
{
- if(bit != 0)
+ if (bit != 0)
{
outb( power|wren|data ,io); udelay(4);
outb( power|wren|data|clk ,io); udelay(4);
@@ -138,14 +140,20 @@ static void outbit(unsigned long bit, __u16 io)
static void turn_power(__u16 io, int p)
{
- if(p != 0) outb(power, io); else outb(0,io);
+ if (p != 0) {
+ dprintk(1, "Radio powered on\n");
+ outb(power, io);
+ } else {
+ dprintk(1, "Radio powered off\n");
+ outb(0,io);
+ }
}
-
-static void set_freq(__u16 io, __u32 data)
+static void set_freq(__u16 io, __u32 freq)
{
unsigned long int si;
int bl;
+ int data = FREQ2BITS(freq);
/* TEA5757 shift register bits (see pdf) */
@@ -164,161 +172,225 @@ static void set_freq(__u16 io, __u32 data)
outbit(0,io); // 16 search level
si = 0x8000;
- for(bl = 1; bl <= 16 ; bl++) { outbit(data & si,io); si >>=1; }
+ for (bl = 1; bl <= 16 ; bl++) {
+ outbit(data & si,io);
+ si >>=1;
+ }
- outb(power,io);
+ dprintk(1, "Radio freq set to %d.%02d MHz\n",
+ freq / 16000,
+ freq % 16000 * 100 / 16000);
+
+ turn_power(io, 1);
}
static int get_stereo(__u16 io)
{
- outb(power,io); udelay(4);
+ outb(power,io);
+ udelay(4);
+
return !(inb(io) & mo_st);
}
static int get_tune(__u16 io)
{
- outb(power+clk,io); udelay(4);
+ outb(power+clk,io);
+ udelay(4);
+
return !(inb(io) & mo_st);
}
-static inline int radio_function(struct inode *inode, struct file *file,
- unsigned int cmd, void *arg)
+static int vidioc_querycap (struct file *file, void *priv,
+ struct v4l2_capability *v)
+{
+ strlcpy(v->driver, "radio-maxiradio", sizeof (v->driver));
+ strlcpy(v->card, "Maxi Radio FM2000 radio", sizeof (v->card));
+ sprintf(v->bus_info,"ISA");
+ v->version = RADIO_VERSION;
+ v->capabilities = V4L2_CAP_TUNER;
+
+ return 0;
+}
+
+static int vidioc_g_tuner (struct file *file, void *priv,
+ struct v4l2_tuner *v)
{
struct video_device *dev = video_devdata(file);
struct radio_device *card=dev->priv;
- switch(cmd) {
- case VIDIOC_QUERYCAP:
- {
- struct v4l2_capability *v = arg;
- memset(v,0,sizeof(*v));
- strlcpy(v->driver, "radio-maxiradio", sizeof (v->driver));
- strlcpy(v->card, "Maxi Radio FM2000 radio", sizeof (v->card));
- sprintf(v->bus_info,"ISA");
- v->version = RADIO_VERSION;
- v->capabilities = V4L2_CAP_TUNER;
+ if (v->index > 0)
+ return -EINVAL;
- return 0;
- }
- case VIDIOC_G_TUNER:
- {
- struct v4l2_tuner *v = arg;
+ memset(v,0,sizeof(*v));
+ strcpy(v->name, "FM");
+ v->type = V4L2_TUNER_RADIO;
- if (v->index > 0)
- return -EINVAL;
+ v->rangelow=FREQ_LO;
+ v->rangehigh=FREQ_HI;
+ v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
+ v->capability=V4L2_TUNER_CAP_LOW;
+ if(get_stereo(card->io))
+ v->audmode = V4L2_TUNER_MODE_STEREO;
+ else
+ v->audmode = V4L2_TUNER_MODE_MONO;
+ v->signal=0xffff*get_tune(card->io);
- memset(v,0,sizeof(*v));
- strcpy(v->name, "FM");
- v->type = V4L2_TUNER_RADIO;
+ return 0;
+}
- v->rangelow=FREQ_LO;
- v->rangehigh=FREQ_HI;
- v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
- v->capability=V4L2_TUNER_CAP_LOW;
- if(get_stereo(card->io))
- v->audmode = V4L2_TUNER_MODE_STEREO;
- else
- v->audmode = V4L2_TUNER_MODE_MONO;
- v->signal=0xffff*get_tune(card->io);
+static int vidioc_s_tuner (struct file *file, void *priv,
+ struct v4l2_tuner *v)
+{
+ if (v->index > 0)
+ return -EINVAL;
- return 0;
- }
- case VIDIOC_S_TUNER:
- {
- struct v4l2_tuner *v = arg;
+ return 0;
+}
- if (v->index > 0)
- return -EINVAL;
+static int vidioc_g_audio (struct file *file, void *priv,
+ struct v4l2_audio *a)
+{
+ if (a->index > 1)
+ return -EINVAL;
- return 0;
- }
- case VIDIOC_S_FREQUENCY:
- {
- struct v4l2_frequency *f = arg;
+ strcpy(a->name, "FM");
+ a->capability = V4L2_AUDCAP_STEREO;
+ return 0;
+}
- if (f->frequency < FREQ_LO || f->frequency > FREQ_HI)
- return -EINVAL;
+static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
+{
+ *i = 0;
- card->freq = f->frequency;
- set_freq(card->io, FREQ2BITS(card->freq));
- msleep(125);
- return 0;
- }
- case VIDIOC_G_FREQUENCY:
- {
- struct v4l2_frequency *f = arg;
+ return 0;
+}
- f->type = V4L2_TUNER_RADIO;
- f->frequency = card->freq;
+static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
+{
+ if (i != 0)
+ return -EINVAL;
- return 0;
- }
- case VIDIOC_QUERYCTRL:
- {
- struct v4l2_queryctrl *qc = arg;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
- if (qc->id && qc->id == radio_qctrl[i].id) {
- memcpy(qc, &(radio_qctrl[i]),
- sizeof(*qc));
- return (0);
- }
- }
- return -EINVAL;
- }
- case VIDIOC_G_CTRL:
- {
- struct v4l2_control *ctrl= arg;
-
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_MUTE:
- ctrl->value=card->muted;
- return (0);
- }
- return -EINVAL;
- }
- case VIDIOC_S_CTRL:
- {
- struct v4l2_control *ctrl= arg;
-
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_MUTE:
- card->muted = ctrl->value;
- if(card->muted)
- turn_power(card->io, 0);
- else
- set_freq(card->io, FREQ2BITS(card->freq));
- return 0;
- }
- return -EINVAL;
- }
+ return 0;
+}
+
+
+static int vidioc_s_audio (struct file *file, void *priv,
+ struct v4l2_audio *a)
+{
+ if (a->index != 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int vidioc_s_frequency (struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+ struct video_device *dev = video_devdata(file);
+ struct radio_device *card=dev->priv;
- default:
- return v4l_compat_translate_ioctl(inode,file,cmd,arg,
- radio_function);
+ if (f->frequency < FREQ_LO || f->frequency > FREQ_HI) {
+ dprintk(1, "radio freq (%d.%02d MHz) out of range (%d-%d)\n",
+ f->frequency / 16000,
+ f->frequency % 16000 * 100 / 16000,
+ FREQ_LO / 16000, FREQ_HI / 16000);
+ return -EINVAL;
}
+
+ card->freq = f->frequency;
+ set_freq(card->io, card->freq);
+ msleep(125);
+
+ return 0;
}
-static int radio_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+static int vidioc_g_frequency (struct file *file, void *priv,
+ struct v4l2_frequency *f)
{
struct video_device *dev = video_devdata(file);
struct radio_device *card=dev->priv;
- int ret;
- mutex_lock(&card->lock);
- ret = video_usercopy(inode, file, cmd, arg, radio_function);
- mutex_unlock(&card->lock);
- return ret;
+ f->type = V4L2_TUNER_RADIO;
+ f->frequency = card->freq;
+
+ dprintk(4, "radio freq is %d.%02d MHz",
+ f->frequency / 16000,
+ f->frequency % 16000 * 100 / 16000);
+
+ return 0;
}
-MODULE_AUTHOR("Dimitromanolakis Apostolos, apdim@grecian.net");
-MODULE_DESCRIPTION("Radio driver for the Guillemot Maxi Radio FM2000 radio.");
-MODULE_LICENSE("GPL");
+static int vidioc_queryctrl (struct file *file, void *priv,
+ struct v4l2_queryctrl *qc)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
+ if (qc->id && qc->id == radio_qctrl[i].id) {
+ memcpy(qc, &(radio_qctrl[i]), sizeof(*qc));
+ return (0);
+ }
+ }
+
+ return -EINVAL;
+}
+
+static int vidioc_g_ctrl (struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct video_device *dev = video_devdata(file);
+ struct radio_device *card=dev->priv;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ ctrl->value=card->muted;
+ return (0);
+ }
+
+ return -EINVAL;
+}
+
+static int vidioc_s_ctrl (struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct video_device *dev = video_devdata(file);
+ struct radio_device *card=dev->priv;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ card->muted = ctrl->value;
+ if(card->muted)
+ turn_power(card->io, 0);
+ else
+ set_freq(card->io, card->freq);
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static struct video_device maxiradio_radio =
+{
+ .owner = THIS_MODULE,
+ .name = "Maxi Radio FM2000 radio",
+ .type = VID_TYPE_TUNER,
+ .fops = &maxiradio_fops,
+
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_g_tuner = vidioc_g_tuner,
+ .vidioc_s_tuner = vidioc_s_tuner,
+ .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_g_frequency = vidioc_g_frequency,
+ .vidioc_s_frequency = vidioc_s_frequency,
+ .vidioc_queryctrl = vidioc_queryctrl,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+};
static int __devinit maxiradio_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
@@ -335,7 +407,7 @@ static int __devinit maxiradio_init_one(struct pci_dev *pdev, const struct pci_d
mutex_init(&radio_unit.lock);
maxiradio_radio.priv = &radio_unit;
- if(video_register_device(&maxiradio_radio, VFL_TYPE_RADIO, radio_nr)==-1) {
+ if (video_register_device(&maxiradio_radio, VFL_TYPE_RADIO, radio_nr)==-1) {
printk("radio-maxiradio: can't register device!");
goto err_out_free_region;
}
@@ -390,3 +462,10 @@ static void __exit maxiradio_radio_exit(void)
module_init(maxiradio_radio_init);
module_exit(maxiradio_radio_exit);
+
+MODULE_AUTHOR("Dimitromanolakis Apostolos, apdim@grecian.net");
+MODULE_DESCRIPTION("Radio driver for the Guillemot Maxi Radio FM2000 radio.");
+MODULE_LICENSE("GPL");
+
+module_param_named(debug,maxiradio_radio.debug, int, 0644);
+MODULE_PARM_DESC(debug,"activates debug info");
diff --git a/drivers/media/radio/radio-rtrack2.c b/drivers/media/radio/radio-rtrack2.c
index b9e98483e58..f6683872251 100644
--- a/drivers/media/radio/radio-rtrack2.c
+++ b/drivers/media/radio/radio-rtrack2.c
@@ -262,7 +262,7 @@ static int rt_ioctl(struct inode *inode, struct file *file,
static struct rt_device rtrack2_unit;
-static struct file_operations rtrack2_fops = {
+static const struct file_operations rtrack2_fops = {
.owner = THIS_MODULE,
.open = video_exclusive_open,
.release = video_exclusive_release,
diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c
index ecc854b4ba3..f4619e4dda4 100644
--- a/drivers/media/radio/radio-sf16fmi.c
+++ b/drivers/media/radio/radio-sf16fmi.c
@@ -265,7 +265,7 @@ static int fmi_ioctl(struct inode *inode, struct file *file,
static struct fmi_device fmi_unit;
-static struct file_operations fmi_fops = {
+static const struct file_operations fmi_fops = {
.owner = THIS_MODULE,
.open = video_exclusive_open,
.release = video_exclusive_release,
diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c
index 4444dce864a..b96fafe1f9d 100644
--- a/drivers/media/radio/radio-sf16fmr2.c
+++ b/drivers/media/radio/radio-sf16fmr2.c
@@ -410,7 +410,7 @@ static int fmr2_ioctl(struct inode *inode, struct file *file,
static struct fmr2_device fmr2_unit;
-static struct file_operations fmr2_fops = {
+static const struct file_operations fmr2_fops = {
.owner = THIS_MODULE,
.open = video_exclusive_open,
.release = video_exclusive_release,
diff --git a/drivers/media/radio/radio-terratec.c b/drivers/media/radio/radio-terratec.c
index f539491a0d7..d59a27accb8 100644
--- a/drivers/media/radio/radio-terratec.c
+++ b/drivers/media/radio/radio-terratec.c
@@ -338,7 +338,7 @@ static int tt_ioctl(struct inode *inode, struct file *file,
static struct tt_device terratec_unit;
-static struct file_operations terratec_fops = {
+static const struct file_operations terratec_fops = {
.owner = THIS_MODULE,
.open = video_exclusive_open,
.release = video_exclusive_release,
diff --git a/drivers/media/radio/radio-trust.c b/drivers/media/radio/radio-trust.c
index bb03ad5a203..6d7f1e7116e 100644
--- a/drivers/media/radio/radio-trust.c
+++ b/drivers/media/radio/radio-trust.c
@@ -325,7 +325,7 @@ static int tr_ioctl(struct inode *inode, struct file *file,
return video_usercopy(inode, file, cmd, arg, tr_do_ioctl);
}
-static struct file_operations trust_fops = {
+static const struct file_operations trust_fops = {
.owner = THIS_MODULE,
.open = video_exclusive_open,
.release = video_exclusive_release,
diff --git a/drivers/media/radio/radio-typhoon.c b/drivers/media/radio/radio-typhoon.c
index 4a72b4d4e62..3031fef178c 100644
--- a/drivers/media/radio/radio-typhoon.c
+++ b/drivers/media/radio/radio-typhoon.c
@@ -318,7 +318,7 @@ static struct typhoon_device typhoon_unit =
.mutefreq = CONFIG_RADIO_TYPHOON_MUTEFREQ,
};
-static struct file_operations typhoon_fops = {
+static const struct file_operations typhoon_fops = {
.owner = THIS_MODULE,
.open = video_exclusive_open,
.release = video_exclusive_release,
diff --git a/drivers/media/radio/radio-zoltrix.c b/drivers/media/radio/radio-zoltrix.c
index 671fe1b1e5b..ec08491fb7c 100644
--- a/drivers/media/radio/radio-zoltrix.c
+++ b/drivers/media/radio/radio-zoltrix.c
@@ -373,7 +373,7 @@ static int zol_ioctl(struct inode *inode, struct file *file,
static struct zol_device zoltrix_unit;
-static struct file_operations zoltrix_fops =
+static const struct file_operations zoltrix_fops =
{
.owner = THIS_MODULE,
.open = video_exclusive_open,
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 57357db31b8..7a6105153f2 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -342,7 +342,7 @@ endmenu # encoder / decoder chips
config VIDEO_VIVI
tristate "Virtual Video Driver"
- depends on VIDEO_V4L2 && !SPARC32 && !SPARC64
+ depends on VIDEO_V4L2 && !SPARC32 && !SPARC64 && PCI
select VIDEO_BUF
default n
---help---
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 9b1f3f06bb7..44ccaed40b4 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -113,4 +113,3 @@ obj-$(CONFIG_USB_QUICKCAM_MESSENGER) += usbvideo/
obj-$(CONFIG_VIDEO_VIVI) += vivi.o
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
-extra-cflags-$(CONFIG_VIDEO_V4L1_COMPAT) += -DCONFIG_VIDEO_V4L1_COMPAT
diff --git a/drivers/media/video/adv7170.c b/drivers/media/video/adv7170.c
index 48709582a18..2aa9ce92060 100644
--- a/drivers/media/video/adv7170.c
+++ b/drivers/media/video/adv7170.c
@@ -42,7 +42,6 @@
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/page.h>
-#include <linux/sched.h>
#include <linux/types.h>
#include <linux/videodev.h>
diff --git a/drivers/media/video/adv7175.c b/drivers/media/video/adv7175.c
index 68e7d7aff5e..a3246a283aa 100644
--- a/drivers/media/video/adv7175.c
+++ b/drivers/media/video/adv7175.c
@@ -38,7 +38,6 @@
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/page.h>
-#include <linux/sched.h>
#include <linux/types.h>
#include <linux/videodev.h>
diff --git a/drivers/media/video/arv.c b/drivers/media/video/arv.c
index 4861799eb43..649f52f9ad2 100644
--- a/drivers/media/video/arv.c
+++ b/drivers/media/video/arv.c
@@ -742,7 +742,7 @@ void ar_release(struct video_device *vfd)
* Video4Linux Module functions
*
****************************************************************************/
-static struct file_operations ar_fops = {
+static const struct file_operations ar_fops = {
.owner = THIS_MODULE,
.open = video_exclusive_open,
.release = video_exclusive_release,
diff --git a/drivers/media/video/bt819.c b/drivers/media/video/bt819.c
index e7b38fdd5e3..68673863d5c 100644
--- a/drivers/media/video/bt819.c
+++ b/drivers/media/video/bt819.c
@@ -42,7 +42,6 @@
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/page.h>
-#include <linux/sched.h>
#include <linux/types.h>
#include <linux/videodev.h>
diff --git a/drivers/media/video/bt856.c b/drivers/media/video/bt856.c
index af3b61d4fa7..42e2299dcb2 100644
--- a/drivers/media/video/bt856.c
+++ b/drivers/media/video/bt856.c
@@ -42,7 +42,6 @@
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/page.h>
-#include <linux/sched.h>
#include <linux/types.h>
#include <linux/videodev.h>
diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c
index 21ebe8f1381..6addc42df04 100644
--- a/drivers/media/video/bt8xx/bttv-cards.c
+++ b/drivers/media/video/bt8xx/bttv-cards.c
@@ -307,6 +307,7 @@ static struct CARD {
{ 0x07711461, BTTV_BOARD_AVDVBT_771, "AVermedia AverTV DVB-T 771" },
{ 0x07611461, BTTV_BOARD_AVDVBT_761, "AverMedia AverTV DVB-T 761" },
{ 0xdb1018ac, BTTV_BOARD_DVICO_DVBT_LITE, "DViCO FusionHDTV DVB-T Lite" },
+ { 0xdb1118ac, BTTV_BOARD_DVICO_DVBT_LITE, "Ultraview DVB-T Lite" },
{ 0xd50018ac, BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE, "DViCO FusionHDTV 5 Lite" },
{ 0x00261822, BTTV_BOARD_TWINHAN_DST, "DNTV Live! Mini "},
@@ -578,14 +579,9 @@ struct tvcard bttv_tvcards[] = {
.svhs = 2,
.gpiomask = 0x01fe00,
.muxsel = { 2, 3, 1, 1 },
- #if 0
- /* old */
- .gpiomux = { 0x01c000, 0, 0x018000, 0x014000, 0x002000 },
- #else
/* 2003-10-20 by "Anton A. Arapov" <arapov@mail.ru> */
.gpiomux = { 0x001e00, 0, 0x018000, 0x014000 },
.gpiomute = 0x002000,
- #endif
.needs_tvaudio = 1,
.pll = PLL_28,
.tuner_type = -1,
@@ -894,15 +890,10 @@ struct tvcard bttv_tvcards[] = {
.tuner = 0,
.svhs = 2,
.muxsel = { 2, 3, 1, 1, 0 }, /* TV, CVid, SVid, CVid over SVid connector */
- #if 0
- .gpiomask = 0xc33000,
- .gpiomux = { 0x422000,0x1000,0x0000,0x620000,0x800000 },
- #else
/* Alexander Varakin <avarakin@hotmail.com> [stereo version] */
.gpiomask = 0xb33000,
.gpiomux = { 0x122000,0x1000,0x0000,0x620000 },
.gpiomute = 0x800000,
- #endif
/* Audio Routing for "WinFast 2000 XP" (no tv stereo !)
gpio23 -- hef4052:nEnable (0x800000)
gpio12 -- hef4052:A1
@@ -1937,11 +1928,6 @@ struct tvcard bttv_tvcards[] = {
.video_inputs = 4,
.audio_inputs = 1,
.tuner = -1,
- #if 0 /* TODO ... */
- .svhs = OSPREY540_SVID_ANALOG,
- .muxsel = { [OSPREY540_COMP_ANALOG] = 2,
- [OSPREY540_SVID_ANALOG] = 3, },
- #endif
.pll = PLL_28,
.tuner_type = -1,
.tuner_addr = ADDR_UNSET,
@@ -1949,10 +1935,6 @@ struct tvcard bttv_tvcards[] = {
.no_msp34xx = 1,
.no_tda9875 = 1,
.no_tda7432 = 1,
- #if 0 /* TODO ... */
- .muxsel_hook = osprey_540_muxsel,
- .picture_hook = osprey_540_set_picture,
- #endif
},
/* ---- card 0x5C ---------------------------------- */
@@ -2627,9 +2609,6 @@ struct tvcard bttv_tvcards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.has_radio = 0,
- #if 0
- .has_remote = 1,
- #endif
},
[BTTV_BOARD_SUPER_TV] = {
/* Rick C <cryptdragoon@gmail.com> */
diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c
index ab8f970760f..5720b77ac9a 100644
--- a/drivers/media/video/bt8xx/bttv-driver.c
+++ b/drivers/media/video/bt8xx/bttv-driver.c
@@ -9,6 +9,10 @@
some v4l2 code lines are taken from Justin's bttv2 driver which is
(c) 2000 Justin Schoeman <justin@suntiger.ee.up.ac.za>
+ Cropping and overscan support
+ Copyright (C) 2005, 2006 Michael H. Schimek <mschimek@gmx.at>
+ Sponsored by OPQ Systems 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 2 of the License, or
@@ -64,6 +68,7 @@ static unsigned int radio[BTTV_MAX];
static unsigned int irq_debug;
static unsigned int gbuffers = 8;
static unsigned int gbufsize = 0x208000;
+static unsigned int reset_crop = 1;
static int video_nr = -1;
static int radio_nr = -1;
@@ -103,6 +108,7 @@ module_param(radio_nr, int, 0444);
module_param(vbi_nr, int, 0444);
module_param(gbuffers, int, 0444);
module_param(gbufsize, int, 0444);
+module_param(reset_crop, int, 0444);
module_param(v4l2, int, 0644);
module_param(bigendian, int, 0644);
@@ -129,6 +135,8 @@ 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(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 "
+ "is 1 (yes) for compatibility with older applications");
MODULE_PARM_DESC(automute,"mute audio on bad/missing video signal, default is 1 (yes)");
MODULE_PARM_DESC(chroma_agc,"enables the AGC of chroma signal, default is 0 (no)");
MODULE_PARM_DESC(adc_crush,"enables the luminance ADC crush, default is 1 (yes)");
@@ -192,6 +200,33 @@ static u8 SRAM_Table[][60] =
}
};
+/* minhdelayx1 first video pixel we can capture on a line and
+ hdelayx1 start of active video, both relative to rising edge of
+ /HRESET pulse (0H) in 1 / fCLKx1.
+ swidth width of active video and
+ totalwidth total line width, both in 1 / fCLKx1.
+ sqwidth total line width in square pixels.
+ vdelay start of active video in 2 * field lines relative to
+ trailing edge of /VRESET pulse (VDELAY register).
+ sheight height of active video in 2 * field lines.
+ videostart0 ITU-R frame line number of the line corresponding
+ to vdelay in the first field. */
+#define CROPCAP(minhdelayx1, hdelayx1, swidth, totalwidth, sqwidth, \
+ vdelay, sheight, videostart0) \
+ .cropcap.bounds.left = minhdelayx1, \
+ /* * 2 because vertically we count field lines times two, */ \
+ /* e.g. 23 * 2 to 23 * 2 + 576 in PAL-BGHI defrect. */ \
+ .cropcap.bounds.top = (videostart0) * 2 - (vdelay) + MIN_VDELAY, \
+ /* 4 is a safety margin at the end of the line. */ \
+ .cropcap.bounds.width = (totalwidth) - (minhdelayx1) - 4, \
+ .cropcap.bounds.height = (sheight) + (vdelay) - MIN_VDELAY, \
+ .cropcap.defrect.left = hdelayx1, \
+ .cropcap.defrect.top = (videostart0) * 2, \
+ .cropcap.defrect.width = swidth, \
+ .cropcap.defrect.height = sheight, \
+ .cropcap.pixelaspect.numerator = totalwidth, \
+ .cropcap.pixelaspect.denominator = sqwidth,
+
const struct bttv_tvnorm bttv_tvnorms[] = {
/* PAL-BDGHI */
/* max. active video is actually 922, but 924 is divisible by 4 and 3! */
@@ -210,11 +245,26 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
.hdelayx1 = 186,
.hactivex1 = 924,
.vdelay = 0x20,
- .vbipack = 255,
+ .vbipack = 255, /* min (2048 / 4, 0x1ff) & 0xff */
.sram = 0,
/* ITU-R frame line number of the first VBI line
- we can capture, of the first and second field. */
- .vbistart = { 7,320 },
+ we can capture, of the first and second field.
+ The last line is determined by cropcap.bounds. */
+ .vbistart = { 7, 320 },
+ CROPCAP(/* minhdelayx1 */ 68,
+ /* hdelayx1 */ 186,
+ /* Should be (768 * 1135 + 944 / 2) / 944.
+ cropcap.defrect is used for image width
+ checks, so we keep the old value 924. */
+ /* swidth */ 924,
+ /* totalwidth */ 1135,
+ /* sqwidth */ 944,
+ /* vdelay */ 0x20,
+ /* sheight */ 576,
+ /* videostart0 */ 23)
+ /* bt878 (and bt848?) can capture another
+ line below active video. */
+ .cropcap.bounds.height = (576 + 2) + 0x20 - 2,
},{
.v4l2_id = V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_KR,
.name = "NTSC",
@@ -229,9 +279,18 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
.hdelayx1 = 128,
.hactivex1 = 910,
.vdelay = 0x1a,
- .vbipack = 144,
+ .vbipack = 144, /* min (1600 / 4, 0x1ff) & 0xff */
.sram = 1,
.vbistart = { 10, 273 },
+ CROPCAP(/* minhdelayx1 */ 68,
+ /* hdelayx1 */ 128,
+ /* Should be (640 * 910 + 780 / 2) / 780? */
+ /* swidth */ 768,
+ /* totalwidth */ 910,
+ /* sqwidth */ 780,
+ /* vdelay */ 0x1a,
+ /* sheight */ 480,
+ /* videostart0 */ 23)
},{
.v4l2_id = V4L2_STD_SECAM,
.name = "SECAM",
@@ -249,6 +308,14 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
.vbipack = 255,
.sram = 0, /* like PAL, correct? */
.vbistart = { 7, 320 },
+ CROPCAP(/* minhdelayx1 */ 68,
+ /* hdelayx1 */ 186,
+ /* swidth */ 924,
+ /* totalwidth */ 1135,
+ /* sqwidth */ 944,
+ /* vdelay */ 0x20,
+ /* sheight */ 576,
+ /* videostart0 */ 23)
},{
.v4l2_id = V4L2_STD_PAL_Nc,
.name = "PAL-Nc",
@@ -266,6 +333,14 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
.vbipack = 144,
.sram = -1,
.vbistart = { 7, 320 },
+ CROPCAP(/* minhdelayx1 */ 68,
+ /* hdelayx1 */ 130,
+ /* swidth */ (640 * 910 + 780 / 2) / 780,
+ /* totalwidth */ 910,
+ /* sqwidth */ 780,
+ /* vdelay */ 0x1a,
+ /* sheight */ 576,
+ /* videostart0 */ 23)
},{
.v4l2_id = V4L2_STD_PAL_M,
.name = "PAL-M",
@@ -283,6 +358,14 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
.vbipack = 144,
.sram = -1,
.vbistart = { 10, 273 },
+ CROPCAP(/* minhdelayx1 */ 68,
+ /* hdelayx1 */ 135,
+ /* swidth */ (640 * 910 + 780 / 2) / 780,
+ /* totalwidth */ 910,
+ /* sqwidth */ 780,
+ /* vdelay */ 0x1a,
+ /* sheight */ 480,
+ /* videostart0 */ 23)
},{
.v4l2_id = V4L2_STD_PAL_N,
.name = "PAL-N",
@@ -299,7 +382,15 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
.vdelay = 0x20,
.vbipack = 144,
.sram = -1,
- .vbistart = { 7, 320},
+ .vbistart = { 7, 320 },
+ CROPCAP(/* minhdelayx1 */ 68,
+ /* hdelayx1 */ 186,
+ /* swidth */ (768 * 1135 + 944 / 2) / 944,
+ /* totalwidth */ 1135,
+ /* sqwidth */ 944,
+ /* vdelay */ 0x20,
+ /* sheight */ 576,
+ /* videostart0 */ 23)
},{
.v4l2_id = V4L2_STD_NTSC_M_JP,
.name = "NTSC-JP",
@@ -316,7 +407,15 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
.vdelay = 0x16,
.vbipack = 144,
.sram = -1,
- .vbistart = {10, 273},
+ .vbistart = { 10, 273 },
+ CROPCAP(/* minhdelayx1 */ 68,
+ /* hdelayx1 */ 135,
+ /* swidth */ (640 * 910 + 780 / 2) / 780,
+ /* totalwidth */ 910,
+ /* sqwidth */ 780,
+ /* vdelay */ 0x16,
+ /* sheight */ 480,
+ /* videostart0 */ 23)
},{
/* that one hopefully works with the strange timing
* which video recorders produce when playing a NTSC
@@ -338,6 +437,14 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
.vtotal = 524,
.sram = -1,
.vbistart = { 10, 273 },
+ CROPCAP(/* minhdelayx1 */ 68,
+ /* hdelayx1 */ 186,
+ /* swidth */ 924,
+ /* totalwidth */ 1135,
+ /* sqwidth */ 944,
+ /* vdelay */ 0x1a,
+ /* sheight */ 480,
+ /* videostart0 */ 23)
}
};
static const unsigned int BTTV_TVNORMS = ARRAY_SIZE(bttv_tvnorms);
@@ -678,25 +785,89 @@ static const int BTTV_CTLS = ARRAY_SIZE(bttv_ctls);
/* ----------------------------------------------------------------------- */
/* resource management */
+/*
+ RESOURCE_ allocated by freed by
+
+ VIDEO_READ bttv_read 1) bttv_read 2)
+
+ VIDEO_STREAM VIDIOC_STREAMON VIDIOC_STREAMOFF
+ VIDIOC_QBUF 1) bttv_release
+ VIDIOCMCAPTURE 1)
+
+ OVERLAY VIDIOCCAPTURE on VIDIOCCAPTURE off
+ VIDIOC_OVERLAY on VIDIOC_OVERLAY off
+ 3) bttv_release
+
+ VBI VIDIOC_STREAMON VIDIOC_STREAMOFF
+ VIDIOC_QBUF 1) bttv_release
+ bttv_read, bttv_poll 1) 4)
+
+ 1) The resource must be allocated when we enter buffer prepare functions
+ and remain allocated while buffers are in the DMA queue.
+ 2) This is a single frame read.
+ 3) VIDIOC_S_FBUF and VIDIOC_S_FMT (OVERLAY) still work when
+ RESOURCE_OVERLAY is allocated.
+ 4) This is a continuous read, implies VIDIOC_STREAMON.
+
+ Note this driver permits video input and standard changes regardless if
+ resources are allocated.
+*/
+
+#define VBI_RESOURCES (RESOURCE_VBI)
+#define VIDEO_RESOURCES (RESOURCE_VIDEO_READ | \
+ RESOURCE_VIDEO_STREAM | \
+ RESOURCE_OVERLAY)
+
static
int check_alloc_btres(struct bttv *btv, struct bttv_fh *fh, int bit)
{
+ int xbits; /* mutual exclusive resources */
+
if (fh->resources & bit)
/* have it already allocated */
return 1;
+ xbits = bit;
+ if (bit & (RESOURCE_VIDEO_READ | RESOURCE_VIDEO_STREAM))
+ xbits |= RESOURCE_VIDEO_READ | RESOURCE_VIDEO_STREAM;
+
/* is it free? */
- mutex_lock(&btv->reslock);
- if (btv->resources & bit) {
+ mutex_lock(&btv->lock);
+ if (btv->resources & xbits) {
/* no, someone else uses it */
- mutex_unlock(&btv->reslock);
- return 0;
+ goto fail;
+ }
+
+ if ((bit & VIDEO_RESOURCES)
+ && 0 == (btv->resources & VIDEO_RESOURCES)) {
+ /* Do crop - use current, don't - use default parameters. */
+ __s32 top = btv->crop[!!fh->do_crop].rect.top;
+
+ if (btv->vbi_end > top)
+ goto fail;
+
+ /* We cannot capture the same line as video and VBI data.
+ Claim scan lines crop[].rect.top to bottom. */
+ btv->crop_start = top;
+ } else if (bit & VBI_RESOURCES) {
+ __s32 end = fh->vbi_fmt.end;
+
+ if (end > btv->crop_start)
+ goto fail;
+
+ /* Claim scan lines above fh->vbi_fmt.end. */
+ btv->vbi_end = end;
}
+
/* it's free, grab it */
fh->resources |= bit;
btv->resources |= bit;
- mutex_unlock(&btv->reslock);
+ mutex_unlock(&btv->lock);
return 1;
+
+ fail:
+ mutex_unlock(&btv->lock);
+ return 0;
}
static
@@ -711,6 +882,35 @@ int locked_btres(struct bttv *btv, int bit)
return (btv->resources & bit);
}
+/* Call with btv->lock down. */
+static void
+disclaim_vbi_lines(struct bttv *btv)
+{
+ btv->vbi_end = 0;
+}
+
+/* Call with btv->lock down. */
+static void
+disclaim_video_lines(struct bttv *btv)
+{
+ const struct bttv_tvnorm *tvnorm;
+ u8 crop;
+
+ tvnorm = &bttv_tvnorms[btv->tvnorm];
+ btv->crop_start = tvnorm->cropcap.bounds.top
+ + tvnorm->cropcap.bounds.height;
+
+ /* VBI capturing ends at VDELAY, start of video capturing, no
+ matter how many lines the VBI RISC program expects. When video
+ capturing is off, it shall no longer "preempt" VBI capturing,
+ so we set VDELAY to maximum. */
+ crop = btread(BT848_E_CROP) | 0xc0;
+ btwrite(crop, BT848_E_CROP);
+ btwrite(0xfe, BT848_E_VDELAY_LO);
+ btwrite(crop, BT848_O_CROP);
+ btwrite(0xfe, BT848_O_VDELAY_LO);
+}
+
static
void free_btres(struct bttv *btv, struct bttv_fh *fh, int bits)
{
@@ -718,10 +918,19 @@ void free_btres(struct bttv *btv, struct bttv_fh *fh, int bits)
/* trying to free ressources not allocated by us ... */
printk("bttv: BUG! (btres)\n");
}
- mutex_lock(&btv->reslock);
+ mutex_lock(&btv->lock);
fh->resources &= ~bits;
btv->resources &= ~bits;
- mutex_unlock(&btv->reslock);
+
+ bits = btv->resources;
+
+ if (0 == (bits & VIDEO_RESOURCES))
+ disclaim_video_lines(btv);
+
+ if (0 == (bits & VBI_RESOURCES))
+ disclaim_vbi_lines(btv);
+
+ mutex_unlock(&btv->lock);
}
/* ----------------------------------------------------------------------- */
@@ -1030,6 +1239,36 @@ i2c_vidiocschan(struct bttv *btv)
bttv_tda9880_setnorm(btv,btv->tvnorm);
}
+static void
+bttv_crop_calc_limits(struct bttv_crop *c)
+{
+ /* Scale factor min. 1:1, max. 16:1. Min. image size
+ 48 x 32. Scaled width must be a multiple of 4. */
+
+ if (1) {
+ /* For bug compatibility with VIDIOCGCAP and image
+ size checks in earlier driver versions. */
+ c->min_scaled_width = 48;
+ c->min_scaled_height = 32;
+ } else {
+ c->min_scaled_width =
+ (max(48, c->rect.width >> 4) + 3) & ~3;
+ c->min_scaled_height =
+ max(32, c->rect.height >> 4);
+ }
+
+ c->max_scaled_width = c->rect.width & ~3;
+ c->max_scaled_height = c->rect.height;
+}
+
+static void
+bttv_crop_reset(struct bttv_crop *c, int norm)
+{
+ c->rect = bttv_tvnorms[norm].cropcap.defrect;
+ bttv_crop_calc_limits(c);
+}
+
+/* Call with btv->lock down. */
static int
set_tvnorm(struct bttv *btv, unsigned int norm)
{
@@ -1038,9 +1277,24 @@ set_tvnorm(struct bttv *btv, unsigned int norm)
if (norm < 0 || norm >= BTTV_TVNORMS)
return -EINVAL;
- btv->tvnorm = norm;
tvnorm = &bttv_tvnorms[norm];
+ if (btv->tvnorm < 0 ||
+ btv->tvnorm >= BTTV_TVNORMS ||
+ 0 != memcmp(&bttv_tvnorms[btv->tvnorm].cropcap,
+ &tvnorm->cropcap,
+ sizeof (tvnorm->cropcap))) {
+ bttv_crop_reset(&btv->crop[0], norm);
+ btv->crop[1] = btv->crop[0]; /* current = default */
+
+ if (0 == (btv->resources & VIDEO_RESOURCES)) {
+ btv->crop_start = tvnorm->cropcap.bounds.top
+ + tvnorm->cropcap.bounds.height;
+ }
+ }
+
+ btv->tvnorm = norm;
+
btwrite(tvnorm->adelay, BT848_ADELAY);
btwrite(tvnorm->bdelay, BT848_BDELAY);
btaor(tvnorm->iform,~(BT848_IFORM_NORM|BT848_IFORM_XTBOTH),
@@ -1057,6 +1311,7 @@ set_tvnorm(struct bttv *btv, unsigned int norm)
return 0;
}
+/* Call with btv->lock down. */
static void
set_input(struct bttv *btv, unsigned int input)
{
@@ -1459,13 +1714,13 @@ bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh,
btv->loop_irq |= 1;
bttv_set_dma(btv, 0x03);
spin_unlock_irqrestore(&btv->s_lock,flags);
- if (NULL == new)
- free_btres(btv,fh,RESOURCE_OVERLAY);
if (NULL != old) {
dprintk("switch_overlay: old=%p state is %d\n",old,old->vb.state);
bttv_dma_free(&fh->cap,btv, old);
kfree(old);
}
+ if (NULL == new)
+ free_btres(btv,fh,RESOURCE_OVERLAY);
dprintk("switch_overlay: done\n");
return retval;
}
@@ -1479,7 +1734,10 @@ static int bttv_prepare_buffer(struct videobuf_queue *q,struct bttv *btv,
unsigned int width, unsigned int height,
enum v4l2_field field)
{
+ struct bttv_fh *fh = q->priv_data;
int redo_dma_risc = 0;
+ struct bttv_crop c;
+ int norm;
int rc;
/* check settings */
@@ -1491,12 +1749,52 @@ static int bttv_prepare_buffer(struct videobuf_queue *q,struct bttv *btv,
if (width*height > buf->vb.bsize)
return -EINVAL;
buf->vb.size = buf->vb.bsize;
+
+ /* Make sure tvnorm and vbi_end remain consistent
+ until we're done. */
+ mutex_lock(&btv->lock);
+
+ norm = btv->tvnorm;
+
+ /* In this mode capturing always starts at defrect.top
+ (default VDELAY), ignoring cropping parameters. */
+ if (btv->vbi_end > bttv_tvnorms[norm].cropcap.defrect.top) {
+ mutex_unlock(&btv->lock);
+ return -EINVAL;
+ }
+
+ mutex_unlock(&btv->lock);
+
+ c.rect = bttv_tvnorms[norm].cropcap.defrect;
} else {
- if (width < 48 ||
- height < 32 ||
- width > bttv_tvnorms[btv->tvnorm].swidth ||
- height > bttv_tvnorms[btv->tvnorm].sheight)
+ mutex_lock(&btv->lock);
+
+ norm = btv->tvnorm;
+ c = btv->crop[!!fh->do_crop];
+
+ mutex_unlock(&btv->lock);
+
+ if (width < c.min_scaled_width ||
+ width > c.max_scaled_width ||
+ height < c.min_scaled_height)
return -EINVAL;
+
+ switch (field) {
+ case V4L2_FIELD_TOP:
+ case V4L2_FIELD_BOTTOM:
+ case V4L2_FIELD_ALTERNATE:
+ /* btv->crop counts frame lines. Max. scale
+ factor is 16:1 for frames, 8:1 for fields. */
+ if (height * 2 > c.max_scaled_height)
+ return -EINVAL;
+ break;
+
+ default:
+ if (height > c.max_scaled_height)
+ return -EINVAL;
+ break;
+ }
+
buf->vb.size = (width * height * fmt->depth) >> 3;
if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
return -EINVAL;
@@ -1505,12 +1803,17 @@ static int bttv_prepare_buffer(struct videobuf_queue *q,struct bttv *btv,
/* alloc + fill struct bttv_buffer (if changed) */
if (buf->vb.width != width || buf->vb.height != height ||
buf->vb.field != field ||
- buf->tvnorm != btv->tvnorm || buf->fmt != fmt) {
+ buf->tvnorm != norm || buf->fmt != fmt ||
+ buf->crop.top != c.rect.top ||
+ buf->crop.left != c.rect.left ||
+ buf->crop.width != c.rect.width ||
+ buf->crop.height != c.rect.height) {
buf->vb.width = width;
buf->vb.height = height;
buf->vb.field = field;
- buf->tvnorm = btv->tvnorm;
+ buf->tvnorm = norm;
buf->fmt = fmt;
+ buf->crop = c.rect;
redo_dma_risc = 1;
}
@@ -1577,7 +1880,7 @@ static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
struct bttv_fh *fh = q->priv_data;
- bttv_dma_free(&fh->cap,fh->btv,buf);
+ bttv_dma_free(q,fh->btv,buf);
}
static struct videobuf_queue_ops bttv_video_qops = {
@@ -1939,11 +2242,179 @@ static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
return 0;
}
-static int verify_window(const struct bttv_tvnorm *tvn,
- struct v4l2_window *win, int fixup)
+/* Given cropping boundaries b and the scaled width and height of a
+ single field or frame, which must not exceed hardware limits, this
+ function adjusts the cropping parameters c. */
+static void
+bttv_crop_adjust (struct bttv_crop * c,
+ const struct v4l2_rect * b,
+ __s32 width,
+ __s32 height,
+ enum v4l2_field field)
+{
+ __s32 frame_height = height << !V4L2_FIELD_HAS_BOTH(field);
+ __s32 max_left;
+ __s32 max_top;
+
+ if (width < c->min_scaled_width) {
+ /* Max. hor. scale factor 16:1. */
+ c->rect.width = width * 16;
+ } else if (width > c->max_scaled_width) {
+ /* Min. hor. scale factor 1:1. */
+ c->rect.width = width;
+
+ max_left = b->left + b->width - width;
+ max_left = min(max_left, (__s32) MAX_HDELAY);
+ if (c->rect.left > max_left)
+ c->rect.left = max_left;
+ }
+
+ if (height < c->min_scaled_height) {
+ /* Max. vert. scale factor 16:1, single fields 8:1. */
+ c->rect.height = height * 16;
+ } else if (frame_height > c->max_scaled_height) {
+ /* Min. vert. scale factor 1:1.
+ Top and height count field lines times two. */
+ c->rect.height = (frame_height + 1) & ~1;
+
+ max_top = b->top + b->height - c->rect.height;
+ if (c->rect.top > max_top)
+ c->rect.top = max_top;
+ }
+
+ bttv_crop_calc_limits(c);
+}
+
+/* Returns an error if scaling to a frame or single field with the given
+ width and height is not possible with the current cropping parameters
+ and width aligned according to width_mask. If adjust_size is TRUE the
+ function may adjust the width and/or height instead, rounding width
+ to (width + width_bias) & width_mask. If adjust_crop is TRUE it may
+ also adjust the current cropping parameters to get closer to the
+ desired image size. */
+static int
+limit_scaled_size (struct bttv_fh * fh,
+ __s32 * width,
+ __s32 * height,
+ enum v4l2_field field,
+ unsigned int width_mask,
+ unsigned int width_bias,
+ int adjust_size,
+ int adjust_crop)
+{
+ struct bttv *btv = fh->btv;
+ const struct v4l2_rect *b;
+ struct bttv_crop *c;
+ __s32 min_width;
+ __s32 min_height;
+ __s32 max_width;
+ __s32 max_height;
+ int rc;
+
+ BUG_ON((int) width_mask >= 0 ||
+ width_bias >= (unsigned int) -width_mask);
+
+ /* Make sure tvnorm, vbi_end and the current cropping parameters
+ remain consistent until we're done. */
+ mutex_lock(&btv->lock);
+
+ b = &bttv_tvnorms[btv->tvnorm].cropcap.bounds;
+
+ /* Do crop - use current, don't - use default parameters. */
+ c = &btv->crop[!!fh->do_crop];
+
+ if (fh->do_crop
+ && adjust_size
+ && adjust_crop
+ && !locked_btres(btv, VIDEO_RESOURCES)) {
+ min_width = 48;
+ min_height = 32;
+
+ /* We cannot scale up. When the scaled image is larger
+ than crop.rect we adjust the crop.rect as required
+ by the V4L2 spec, hence cropcap.bounds are our limit. */
+ max_width = min(b->width, (__s32) MAX_HACTIVE);
+ max_height = b->height;
+
+ /* We cannot capture the same line as video and VBI data.
+ Note btv->vbi_end is really a minimum, see
+ bttv_vbi_try_fmt(). */
+ if (btv->vbi_end > b->top) {
+ max_height -= btv->vbi_end - b->top;
+ rc = -EBUSY;
+ if (min_height > max_height)
+ goto fail;
+ }
+ } else {
+ rc = -EBUSY;
+ if (btv->vbi_end > c->rect.top)
+ goto fail;
+
+ min_width = c->min_scaled_width;
+ min_height = c->min_scaled_height;
+ max_width = c->max_scaled_width;
+ max_height = c->max_scaled_height;
+
+ adjust_crop = 0;
+ }
+
+ min_width = (min_width - width_mask - 1) & width_mask;
+ max_width = max_width & width_mask;
+
+ /* Max. scale factor is 16:1 for frames, 8:1 for fields. */
+ min_height = min_height;
+ /* Min. scale factor is 1:1. */
+ max_height >>= !V4L2_FIELD_HAS_BOTH(field);
+
+ if (adjust_size) {
+ *width = clamp(*width, min_width, max_width);
+ *height = clamp(*height, min_height, max_height);
+
+ /* Round after clamping to avoid overflow. */
+ *width = (*width + width_bias) & width_mask;
+
+ if (adjust_crop) {
+ bttv_crop_adjust(c, b, *width, *height, field);
+
+ if (btv->vbi_end > c->rect.top) {
+ /* Move the crop window out of the way. */
+ c->rect.top = btv->vbi_end;
+ }
+ }
+ } else {
+ rc = -EINVAL;
+ if (*width < min_width ||
+ *height < min_height ||
+ *width > max_width ||
+ *height > max_height ||
+ 0 != (*width & ~width_mask))
+ goto fail;
+ }
+
+ rc = 0; /* success */
+
+ fail:
+ mutex_unlock(&btv->lock);
+
+ return rc;
+}
+
+/* Returns an error if the given overlay window dimensions are not
+ possible with the current cropping parameters. If adjust_size is
+ TRUE the function may adjust the window width and/or height
+ instead, however it always rounds the horizontal position and
+ width as btcx_align() does. If adjust_crop is TRUE the function
+ may also adjust the current cropping parameters to get closer
+ to the desired window size. */
+static int
+verify_window (struct bttv_fh * fh,
+ struct v4l2_window * win,
+ int adjust_size,
+ int adjust_crop)
{
enum v4l2_field field;
- int maxw, maxh;
+ unsigned int width_mask;
+ int rc;
if (win->w.width < 48 || win->w.height < 32)
return -EINVAL;
@@ -1951,32 +2422,52 @@ static int verify_window(const struct bttv_tvnorm *tvn,
return -EINVAL;
field = win->field;
- maxw = tvn->swidth;
- maxh = tvn->sheight;
if (V4L2_FIELD_ANY == field) {
- field = (win->w.height > maxh/2)
+ __s32 height2;
+
+ height2 = fh->btv->crop[!!fh->do_crop].rect.height >> 1;
+ field = (win->w.height > height2)
? V4L2_FIELD_INTERLACED
: V4L2_FIELD_TOP;
}
switch (field) {
case V4L2_FIELD_TOP:
case V4L2_FIELD_BOTTOM:
- maxh = maxh / 2;
- break;
case V4L2_FIELD_INTERLACED:
break;
default:
return -EINVAL;
}
- if (!fixup && (win->w.width > maxw || win->w.height > maxh))
+ /* 4-byte alignment. */
+ if (NULL == fh->ovfmt)
return -EINVAL;
+ width_mask = ~0;
+ switch (fh->ovfmt->depth) {
+ case 8:
+ case 24:
+ width_mask = ~3;
+ break;
+ case 16:
+ width_mask = ~1;
+ break;
+ case 32:
+ break;
+ default:
+ BUG();
+ }
+
+ win->w.width -= win->w.left & ~width_mask;
+ win->w.left = (win->w.left - width_mask - 1) & width_mask;
+
+ rc = limit_scaled_size(fh, &win->w.width, &win->w.height,
+ field, width_mask,
+ /* width_bias: round down */ 0,
+ adjust_size, adjust_crop);
+ if (0 != rc)
+ return rc;
- if (win->w.width > maxw)
- win->w.width = maxw;
- if (win->w.height > maxh)
- win->w.height = maxh;
win->field = field;
return 0;
}
@@ -1991,7 +2482,9 @@ static int setup_window(struct bttv_fh *fh, struct bttv *btv,
return -EINVAL;
if (!(fh->ovfmt->flags & FORMAT_FLAGS_PACKED))
return -EINVAL;
- retval = verify_window(&bttv_tvnorms[btv->tvnorm],win,fixup);
+ retval = verify_window(fh, win,
+ /* adjust_size */ fixup,
+ /* adjust_crop */ fixup);
if (0 != retval)
return retval;
@@ -2048,6 +2541,7 @@ static int setup_window(struct bttv_fh *fh, struct bttv *btv,
struct bttv_buffer *new;
new = videobuf_alloc(sizeof(*new));
+ new->crop = btv->crop[!!fh->do_crop].rect;
bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
retval = bttv_switch_overlay(btv,fh,new);
}
@@ -2080,7 +2574,7 @@ static int bttv_resource(struct bttv_fh *fh)
switch (fh->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- res = RESOURCE_VIDEO;
+ res = RESOURCE_VIDEO_STREAM;
break;
case V4L2_BUF_TYPE_VBI_CAPTURE:
res = RESOURCE_VBI;
@@ -2138,7 +2632,7 @@ static int bttv_g_fmt(struct bttv_fh *fh, struct v4l2_format *f)
f->fmt.win.field = fh->ov.field;
return 0;
case V4L2_BUF_TYPE_VBI_CAPTURE:
- bttv_vbi_get_fmt(fh,f);
+ bttv_vbi_get_fmt(fh, &f->fmt.vbi);
return 0;
default:
return -EINVAL;
@@ -2146,35 +2640,35 @@ static int bttv_g_fmt(struct bttv_fh *fh, struct v4l2_format *f)
}
static int bttv_try_fmt(struct bttv_fh *fh, struct bttv *btv,
- struct v4l2_format *f)
+ struct v4l2_format *f, int adjust_crop)
{
switch (f->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
{
const struct bttv_format *fmt;
enum v4l2_field field;
- unsigned int maxw,maxh;
+ __s32 width, height;
+ int rc;
fmt = format_by_fourcc(f->fmt.pix.pixelformat);
if (NULL == fmt)
return -EINVAL;
- /* fixup format */
- maxw = bttv_tvnorms[btv->tvnorm].swidth;
- maxh = bttv_tvnorms[btv->tvnorm].sheight;
field = f->fmt.pix.field;
- if (V4L2_FIELD_ANY == field)
- field = (f->fmt.pix.height > maxh/2)
+ if (V4L2_FIELD_ANY == field) {
+ __s32 height2;
+
+ height2 = btv->crop[!!fh->do_crop].rect.height >> 1;
+ field = (f->fmt.pix.height > height2)
? V4L2_FIELD_INTERLACED
: V4L2_FIELD_BOTTOM;
+ }
if (V4L2_FIELD_SEQ_BT == field)
field = V4L2_FIELD_SEQ_TB;
switch (field) {
case V4L2_FIELD_TOP:
case V4L2_FIELD_BOTTOM:
case V4L2_FIELD_ALTERNATE:
- maxh = maxh/2;
- break;
case V4L2_FIELD_INTERLACED:
break;
case V4L2_FIELD_SEQ_TB:
@@ -2185,28 +2679,29 @@ static int bttv_try_fmt(struct bttv_fh *fh, struct bttv *btv,
return -EINVAL;
}
+ width = f->fmt.pix.width;
+ height = f->fmt.pix.height;
+
+ rc = limit_scaled_size(fh, &width, &height, field,
+ /* width_mask: 4 pixels */ ~3,
+ /* width_bias: nearest */ 2,
+ /* adjust_size */ 1,
+ adjust_crop);
+ if (0 != rc)
+ return rc;
+
/* update data for the application */
f->fmt.pix.field = field;
- if (f->fmt.pix.width < 48)
- f->fmt.pix.width = 48;
- if (f->fmt.pix.height < 32)
- f->fmt.pix.height = 32;
- if (f->fmt.pix.width > maxw)
- f->fmt.pix.width = maxw;
- if (f->fmt.pix.height > maxh)
- f->fmt.pix.height = maxh;
- pix_format_set_size (&f->fmt.pix, fmt,
- f->fmt.pix.width & ~3,
- f->fmt.pix.height);
+ pix_format_set_size(&f->fmt.pix, fmt, width, height);
return 0;
}
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
- return verify_window(&bttv_tvnorms[btv->tvnorm],
- &f->fmt.win, 1);
+ return verify_window(fh, &f->fmt.win,
+ /* adjust_size */ 1,
+ /* adjust_crop */ 0);
case V4L2_BUF_TYPE_VBI_CAPTURE:
- bttv_vbi_try_fmt(fh,f);
- return 0;
+ return bttv_vbi_try_fmt(fh, &f->fmt.vbi);
default:
return -EINVAL;
}
@@ -2225,7 +2720,7 @@ static int bttv_s_fmt(struct bttv_fh *fh, struct bttv *btv,
retval = bttv_switch_type(fh,f->type);
if (0 != retval)
return retval;
- retval = bttv_try_fmt(fh,btv,f);
+ retval = bttv_try_fmt(fh,btv,f, /* adjust_crop */ 1);
if (0 != retval)
return retval;
fmt = format_by_fourcc(f->fmt.pix.pixelformat);
@@ -2254,12 +2749,7 @@ static int bttv_s_fmt(struct bttv_fh *fh, struct bttv *btv,
retval = bttv_switch_type(fh,f->type);
if (0 != retval)
return retval;
- if (locked_btres(fh->btv, RESOURCE_VBI))
- return -EBUSY;
- bttv_vbi_try_fmt(fh,f);
- bttv_vbi_setlines(fh,btv,f->fmt.vbi.count[0]);
- bttv_vbi_get_fmt(fh,f);
- return 0;
+ return bttv_vbi_set_fmt(fh, &f->fmt.vbi);
default:
return -EINVAL;
}
@@ -2517,6 +3007,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
if (*on) {
fh->ov.tvnorm = btv->tvnorm;
new = videobuf_alloc(sizeof(*new));
+ new->crop = btv->crop[!!fh->do_crop].rect;
bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
} else {
new = NULL;
@@ -2551,10 +3042,16 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
struct video_mmap *vm = arg;
struct bttv_buffer *buf;
enum v4l2_field field;
+ __s32 height2;
+ int res;
if (vm->frame >= VIDEO_MAX_FRAME)
return -EINVAL;
+ res = bttv_resource(fh);
+ if (!check_alloc_btres(btv, fh, res))
+ return -EBUSY;
+
mutex_lock(&fh->cap.lock);
retval = -EINVAL;
buf = (struct bttv_buffer *)fh->cap.bufs[vm->frame];
@@ -2566,7 +3063,8 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
buf->vb.state == STATE_ACTIVE)
goto fh_unlock_and_return;
- field = (vm->height > bttv_tvnorms[btv->tvnorm].sheight/2)
+ height2 = btv->crop[!!fh->do_crop].rect.height >> 1;
+ field = (vm->height > height2)
? V4L2_FIELD_INTERLACED
: V4L2_FIELD_BOTTOM;
retval = bttv_prepare_buffer(&fh->cap,btv,buf,
@@ -2613,54 +3111,17 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
}
case VIDIOCGVBIFMT:
- {
- struct vbi_format *fmt = (void *) arg;
- struct v4l2_format fmt2;
-
if (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE) {
retval = bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE);
if (0 != retval)
return retval;
}
- bttv_vbi_get_fmt(fh, &fmt2);
-
- memset(fmt,0,sizeof(*fmt));
- fmt->sampling_rate = fmt2.fmt.vbi.sampling_rate;
- fmt->samples_per_line = fmt2.fmt.vbi.samples_per_line;
- fmt->sample_format = VIDEO_PALETTE_RAW;
- fmt->start[0] = fmt2.fmt.vbi.start[0];
- fmt->count[0] = fmt2.fmt.vbi.count[0];
- fmt->start[1] = fmt2.fmt.vbi.start[1];
- fmt->count[1] = fmt2.fmt.vbi.count[1];
- if (fmt2.fmt.vbi.flags & V4L2_VBI_UNSYNC)
- fmt->flags |= VBI_UNSYNC;
- if (fmt2.fmt.vbi.flags & V4L2_VBI_INTERLACED)
- fmt->flags |= VBI_INTERLACED;
- return 0;
- }
- case VIDIOCSVBIFMT:
- {
- struct vbi_format *fmt = (void *) arg;
- struct v4l2_format fmt2;
- retval = bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE);
- if (0 != retval)
- return retval;
- bttv_vbi_get_fmt(fh, &fmt2);
-
- if (fmt->sampling_rate != fmt2.fmt.vbi.sampling_rate ||
- fmt->samples_per_line != fmt2.fmt.vbi.samples_per_line ||
- fmt->sample_format != VIDEO_PALETTE_RAW ||
- fmt->start[0] != fmt2.fmt.vbi.start[0] ||
- fmt->start[1] != fmt2.fmt.vbi.start[1] ||
- fmt->count[0] != fmt->count[1] ||
- fmt->count[0] < 1 ||
- fmt->count[0] > 32 /* VBI_MAXLINES */)
- return -EINVAL;
+ /* fall through */
- bttv_vbi_setlines(fh,btv,fmt->count[0]);
- return 0;
- }
+ case VIDIOCSVBIFMT:
+ return v4l_compat_translate_ioctl(inode, file, cmd,
+ arg, bttv_do_ioctl);
case BTTV_VERSION:
case VIDIOCGFREQ:
@@ -2753,7 +3214,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
case VIDIOC_TRY_FMT:
{
struct v4l2_format *f = arg;
- return bttv_try_fmt(fh,btv,f);
+ return bttv_try_fmt(fh,btv,f, /* adjust_crop */ 0);
}
case VIDIOC_G_FMT:
{
@@ -2792,16 +3253,23 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
if (0 == (fmt->flags & FORMAT_FLAGS_PACKED))
return -EINVAL;
- mutex_lock(&fh->cap.lock);
retval = -EINVAL;
if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
- if (fb->fmt.width > bttv_tvnorms[btv->tvnorm].swidth)
- goto fh_unlock_and_return;
- if (fb->fmt.height > bttv_tvnorms[btv->tvnorm].sheight)
- goto fh_unlock_and_return;
+ __s32 width = fb->fmt.width;
+ __s32 height = fb->fmt.height;
+
+ retval = limit_scaled_size(fh, &width, &height,
+ V4L2_FIELD_INTERLACED,
+ /* width_mask */ ~3,
+ /* width_bias */ 2,
+ /* adjust_size */ 0,
+ /* adjust_crop */ 0);
+ if (0 != retval)
+ return retval;
}
/* ok, accept it */
+ mutex_lock(&fh->cap.lock);
btv->fbuf.base = fb->base;
btv->fbuf.fmt.width = fb->fmt.width;
btv->fbuf.fmt.height = fb->fmt.height;
@@ -2828,6 +3296,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
struct bttv_buffer *new;
new = videobuf_alloc(sizeof(*new));
+ new->crop = btv->crop[!!fh->do_crop].rect;
bttv_overlay_risc(btv,&fh->ov,fh->ovfmt,new);
retval = bttv_switch_overlay(btv,fh,new);
}
@@ -2843,7 +3312,13 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
return videobuf_querybuf(bttv_queue(fh),arg);
case VIDIOC_QBUF:
+ {
+ int res = bttv_resource(fh);
+
+ if (!check_alloc_btres(btv, fh, res))
+ return -EBUSY;
return videobuf_qbuf(bttv_queue(fh),arg);
+ }
case VIDIOC_DQBUF:
return videobuf_dqbuf(bttv_queue(fh),arg,
@@ -2942,6 +3417,122 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
return v4l2_prio_change(&btv->prio, &fh->prio, *prio);
}
+ case VIDIOC_CROPCAP:
+ {
+ struct v4l2_cropcap *cap = arg;
+ enum v4l2_buf_type type;
+
+ type = cap->type;
+
+ if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+ type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
+ return -EINVAL;
+
+ *cap = bttv_tvnorms[btv->tvnorm].cropcap;
+ cap->type = type;
+
+ return 0;
+ }
+ case VIDIOC_G_CROP:
+ {
+ struct v4l2_crop * crop = arg;
+
+ if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+ crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
+ return -EINVAL;
+
+ /* No fh->do_crop = 1; because btv->crop[1] may be
+ inconsistent with fh->width or fh->height and apps
+ do not expect a change here. */
+
+ crop->c = btv->crop[!!fh->do_crop].rect;
+
+ return 0;
+ }
+ case VIDIOC_S_CROP:
+ {
+ struct v4l2_crop *crop = arg;
+ const struct v4l2_rect *b;
+ struct bttv_crop c;
+ __s32 b_left;
+ __s32 b_top;
+ __s32 b_right;
+ __s32 b_bottom;
+
+ if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+ crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
+ return -EINVAL;
+
+ retval = v4l2_prio_check(&btv->prio,&fh->prio);
+ if (0 != retval)
+ return retval;
+
+ /* Make sure tvnorm, vbi_end and the current cropping
+ parameters remain consistent until we're done. Note
+ read() may change vbi_end in check_alloc_btres(). */
+ mutex_lock(&btv->lock);
+
+ retval = -EBUSY;
+
+ if (locked_btres(fh->btv, VIDEO_RESOURCES))
+ goto btv_unlock_and_return;
+
+ b = &bttv_tvnorms[btv->tvnorm].cropcap.bounds;
+
+ b_left = b->left;
+ b_right = b_left + b->width;
+ b_bottom = b->top + b->height;
+
+ b_top = max(b->top, btv->vbi_end);
+ if (b_top + 32 >= b_bottom)
+ goto btv_unlock_and_return;
+
+ /* Min. scaled size 48 x 32. */
+ c.rect.left = clamp(crop->c.left, b_left, b_right - 48);
+ c.rect.left = min(c.rect.left, (__s32) MAX_HDELAY);
+
+ c.rect.width = clamp(crop->c.width,
+ 48, b_right - c.rect.left);
+
+ c.rect.top = clamp(crop->c.top, b_top, b_bottom - 32);
+ /* Top and height must be a multiple of two. */
+ c.rect.top = (c.rect.top + 1) & ~1;
+
+ c.rect.height = clamp(crop->c.height,
+ 32, b_bottom - c.rect.top);
+ c.rect.height = (c.rect.height + 1) & ~1;
+
+ bttv_crop_calc_limits(&c);
+
+ btv->crop[1] = c;
+
+ mutex_unlock(&btv->lock);
+
+ fh->do_crop = 1;
+
+ mutex_lock(&fh->cap.lock);
+
+ if (fh->width < c.min_scaled_width) {
+ fh->width = c.min_scaled_width;
+ btv->init.width = c.min_scaled_width;
+ } else if (fh->width > c.max_scaled_width) {
+ fh->width = c.max_scaled_width;
+ btv->init.width = c.max_scaled_width;
+ }
+
+ if (fh->height < c.min_scaled_height) {
+ fh->height = c.min_scaled_height;
+ btv->init.height = c.min_scaled_height;
+ } else if (fh->height > c.max_scaled_height) {
+ fh->height = c.max_scaled_height;
+ btv->init.height = c.max_scaled_height;
+ }
+
+ mutex_unlock(&fh->cap.lock);
+
+ return 0;
+ }
+
case VIDIOC_ENUMSTD:
case VIDIOC_G_STD:
case VIDIOC_S_STD:
@@ -2963,6 +3554,10 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
fh_unlock_and_return:
mutex_unlock(&fh->cap.lock);
return retval;
+
+ btv_unlock_and_return:
+ mutex_unlock(&btv->lock);
+ return retval;
}
static int bttv_ioctl(struct inode *inode, struct file *file,
@@ -2972,8 +3567,26 @@ static int bttv_ioctl(struct inode *inode, struct file *file,
switch (cmd) {
case BTTV_VBISIZE:
+ {
+ const struct bttv_tvnorm *tvnorm;
+
+ tvnorm = fh->vbi_fmt.tvnorm;
+
+ if (fh->vbi_fmt.fmt.start[0] != tvnorm->vbistart[0] ||
+ fh->vbi_fmt.fmt.start[1] != tvnorm->vbistart[1] ||
+ fh->vbi_fmt.fmt.count[0] != fh->vbi_fmt.fmt.count[1]) {
+ /* BTTV_VBISIZE cannot express these parameters,
+ however open() resets the paramters to defaults
+ and apps shouldn't call BTTV_VBISIZE after
+ VIDIOC_S_FMT. */
+ return -EINVAL;
+ }
+
bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE);
- return fh->lines * 2 * 2048;
+ return (fh->vbi_fmt.fmt.count[0] * 2
+ * fh->vbi_fmt.fmt.samples_per_line);
+ }
+
default:
return video_usercopy(inode, file, cmd, arg, bttv_do_ioctl);
}
@@ -2992,10 +3605,14 @@ static ssize_t bttv_read(struct file *file, char __user *data,
switch (fh->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- if (locked_btres(fh->btv,RESOURCE_VIDEO))
+ if (!check_alloc_btres(fh->btv, fh, RESOURCE_VIDEO_READ)) {
+ /* VIDEO_READ in use by another fh,
+ or VIDEO_STREAM by any fh. */
return -EBUSY;
+ }
retval = videobuf_read_one(&fh->cap, data, count, ppos,
file->f_flags & O_NONBLOCK);
+ free_btres(fh->btv, fh, RESOURCE_VIDEO_READ);
break;
case V4L2_BUF_TYPE_VBI_CAPTURE:
if (!check_alloc_btres(fh->btv,fh,RESOURCE_VBI))
@@ -3021,7 +3638,7 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait)
return videobuf_poll_stream(file, &fh->vbi, wait);
}
- if (check_btres(fh,RESOURCE_VIDEO)) {
+ if (check_btres(fh,RESOURCE_VIDEO_STREAM)) {
/* streaming capture */
if (list_empty(&fh->cap.stream))
return POLLERR;
@@ -3031,7 +3648,7 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait)
mutex_lock(&fh->cap.lock);
if (NULL == fh->cap.read_buf) {
/* need to capture a new frame */
- if (locked_btres(fh->btv,RESOURCE_VIDEO)) {
+ if (locked_btres(fh->btv,RESOURCE_VIDEO_STREAM)) {
mutex_unlock(&fh->cap.lock);
return POLLERR;
}
@@ -3117,8 +3734,23 @@ static int bttv_open(struct inode *inode, struct file *file)
i2c_vidiocschan(btv);
btv->users++;
- if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type)
- bttv_vbi_setlines(fh,btv,16);
+
+ /* The V4L2 spec requires one global set of cropping parameters
+ which only change on request. These are stored in btv->crop[1].
+ However for compatibility with V4L apps and cropping unaware
+ V4L2 apps we now reset the cropping parameters as seen through
+ this fh, which is to say VIDIOC_G_CROP and scaling limit checks
+ will use btv->crop[0], the default cropping parameters for the
+ current video standard, and VIDIOC_S_FMT will not implicitely
+ change the cropping parameters until VIDIOC_S_CROP has been
+ called. */
+ fh->do_crop = !reset_crop; /* module parameter */
+
+ /* Likewise there should be one global set of VBI capture
+ parameters, but for compatibility with V4L apps and earlier
+ driver versions each fh has its own parameters. */
+ bttv_vbi_fmt_reset(&fh->vbi_fmt, btv->tvnorm);
+
bttv_field_count(btv);
return 0;
}
@@ -3133,14 +3765,17 @@ static int bttv_release(struct inode *inode, struct file *file)
bttv_switch_overlay(btv,fh,NULL);
/* stop video capture */
- if (check_btres(fh, RESOURCE_VIDEO)) {
+ if (check_btres(fh, RESOURCE_VIDEO_STREAM)) {
videobuf_streamoff(&fh->cap);
- free_btres(btv,fh,RESOURCE_VIDEO);
+ free_btres(btv,fh,RESOURCE_VIDEO_STREAM);
}
if (fh->cap.read_buf) {
buffer_release(&fh->cap,fh->cap.read_buf);
kfree(fh->cap.read_buf);
}
+ if (check_btres(fh, RESOURCE_VIDEO_READ)) {
+ free_btres(btv, fh, RESOURCE_VIDEO_READ);
+ }
/* stop vbi capture */
if (check_btres(fh, RESOURCE_VBI)) {
@@ -3174,7 +3809,7 @@ bttv_mmap(struct file *file, struct vm_area_struct *vma)
return videobuf_mmap_mapper(bttv_queue(fh),vma);
}
-static struct file_operations bttv_fops =
+static const struct file_operations bttv_fops =
{
.owner = THIS_MODULE,
.open = bttv_open,
@@ -3332,7 +3967,7 @@ static unsigned int radio_poll(struct file *file, poll_table *wait)
return cmd.result;
}
-static struct file_operations radio_fops =
+static const struct file_operations radio_fops =
{
.owner = THIS_MODULE,
.open = radio_open,
@@ -3997,7 +4632,6 @@ static int __devinit bttv_probe(struct pci_dev *dev,
/* initialize structs / fill in defaults */
mutex_init(&btv->lock);
- mutex_init(&btv->reslock);
spin_lock_init(&btv->s_lock);
spin_lock_init(&btv->gpio_lock);
init_waitqueue_head(&btv->gpioq);
@@ -4095,7 +4729,6 @@ static int __devinit bttv_probe(struct pci_dev *dev,
btv->init.fmt = format_by_palette(VIDEO_PALETTE_RGB24);
btv->init.width = 320;
btv->init.height = 240;
- btv->init.lines = 16;
btv->input = 0;
/* initialize hardware */
@@ -4130,6 +4763,10 @@ static int __devinit bttv_probe(struct pci_dev *dev,
bt848_sat(btv,32768);
audio_mute(btv, 1);
set_input(btv,0);
+ bttv_crop_reset(&btv->crop[0], btv->tvnorm);
+ btv->crop[1] = btv->crop[0]; /* current = default */
+ disclaim_vbi_lines(btv);
+ disclaim_video_lines(btv);
}
/* add subdevices */
diff --git a/drivers/media/video/bt8xx/bttv-input.c b/drivers/media/video/bt8xx/bttv-input.c
index cbc012f71f5..6f74c8042bc 100644
--- a/drivers/media/video/bt8xx/bttv-input.c
+++ b/drivers/media/video/bt8xx/bttv-input.c
@@ -36,13 +36,18 @@ module_param(repeat_delay, int, 0644);
static int repeat_period = 33;
module_param(repeat_period, int, 0644);
+static int ir_rc5_remote_gap = 885;
+module_param(ir_rc5_remote_gap, int, 0644);
+static int ir_rc5_key_timeout = 200;
+module_param(ir_rc5_key_timeout, int, 0644);
+
#define DEVNAME "bttv-input"
/* ---------------------------------------------------------------------- */
static void ir_handle_key(struct bttv *btv)
{
- struct bttv_ir *ir = btv->remote;
+ struct card_ir *ir = btv->remote;
u32 gpio,data;
/* read gpio value */
@@ -72,7 +77,7 @@ static void ir_handle_key(struct bttv *btv)
void bttv_input_irq(struct bttv *btv)
{
- struct bttv_ir *ir = btv->remote;
+ struct card_ir *ir = btv->remote;
if (!ir->polling)
ir_handle_key(btv);
@@ -81,65 +86,21 @@ void bttv_input_irq(struct bttv *btv)
static void bttv_input_timer(unsigned long data)
{
struct bttv *btv = (struct bttv*)data;
- struct bttv_ir *ir = btv->remote;
- unsigned long timeout;
+ struct card_ir *ir = btv->remote;
ir_handle_key(btv);
- timeout = jiffies + (ir->polling * HZ / 1000);
- mod_timer(&ir->timer, timeout);
+ mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling));
}
/* ---------------------------------------------------------------*/
-static int rc5_remote_gap = 885;
-module_param(rc5_remote_gap, int, 0644);
-static int rc5_key_timeout = 200;
-module_param(rc5_key_timeout, int, 0644);
-
-#define RC5_START(x) (((x)>>12)&3)
-#define RC5_TOGGLE(x) (((x)>>11)&1)
-#define RC5_ADDR(x) (((x)>>6)&31)
-#define RC5_INSTR(x) ((x)&63)
-
-/* decode raw bit pattern to RC5 code */
-static u32 rc5_decode(unsigned int code)
-{
- unsigned int org_code = code;
- unsigned int pair;
- unsigned int rc5 = 0;
- int i;
-
- code = (code << 1) | 1;
- for (i = 0; i < 14; ++i) {
- pair = code & 0x3;
- code >>= 2;
-
- rc5 <<= 1;
- switch (pair) {
- case 0:
- case 2:
- break;
- case 1:
- rc5 |= 1;
- break;
- case 3:
- dprintk(KERN_WARNING "bad code: %x\n", org_code);
- return 0;
- }
- }
- dprintk(KERN_WARNING "code=%x, rc5=%x, start=%x, toggle=%x, address=%x, "
- "instr=%x\n", rc5, org_code, RC5_START(rc5),
- RC5_TOGGLE(rc5), RC5_ADDR(rc5), RC5_INSTR(rc5));
- return rc5;
-}
-
static int bttv_rc5_irq(struct bttv *btv)
{
- struct bttv_ir *ir = btv->remote;
+ struct card_ir *ir = btv->remote;
struct timeval tv;
u32 gpio;
u32 gap;
- unsigned long current_jiffies, timeout;
+ unsigned long current_jiffies;
/* read gpio port */
gpio = bttv_gpio_read(&btv->c);
@@ -165,8 +126,8 @@ static int bttv_rc5_irq(struct bttv *btv)
/* only if in the code (otherwise spurious IRQ or timer
late) */
if (ir->last_bit < 28) {
- ir->last_bit = (gap - rc5_remote_gap / 2) /
- rc5_remote_gap;
+ ir->last_bit = (gap - ir_rc5_remote_gap / 2) /
+ ir_rc5_remote_gap;
ir->code |= 1 << ir->last_bit;
}
/* starting new code */
@@ -176,8 +137,8 @@ static int bttv_rc5_irq(struct bttv *btv)
ir->base_time = tv;
ir->last_bit = 0;
- timeout = current_jiffies + (500 + 30 * HZ) / 1000;
- mod_timer(&ir->timer_end, timeout);
+ mod_timer(&ir->timer_end,
+ current_jiffies + msecs_to_jiffies(30));
}
/* toggle GPIO pin 4 to reset the irq */
@@ -186,96 +147,28 @@ static int bttv_rc5_irq(struct bttv *btv)
return 1;
}
-
-static void bttv_rc5_timer_end(unsigned long data)
-{
- struct bttv_ir *ir = (struct bttv_ir *)data;
- struct timeval tv;
- unsigned long current_jiffies, timeout;
- u32 gap;
-
- /* get time */
- current_jiffies = jiffies;
- do_gettimeofday(&tv);
-
- /* avoid overflow with gap >1s */
- if (tv.tv_sec - ir->base_time.tv_sec > 1) {
- gap = 200000;
- } else {
- gap = 1000000 * (tv.tv_sec - ir->base_time.tv_sec) +
- tv.tv_usec - ir->base_time.tv_usec;
- }
-
- /* Allow some timmer jitter (RC5 is ~24ms anyway so this is ok) */
- if (gap < 28000) {
- dprintk(KERN_WARNING "spurious timer_end\n");
- return;
- }
-
- ir->active = 0;
- if (ir->last_bit < 20) {
- /* ignore spurious codes (caused by light/other remotes) */
- dprintk(KERN_WARNING "short code: %x\n", ir->code);
- } else {
- u32 rc5 = rc5_decode(ir->code);
-
- /* two start bits? */
- if (RC5_START(rc5) != 3) {
- dprintk(KERN_WARNING "rc5 start bits invalid: %u\n", RC5_START(rc5));
-
- /* right address? */
- } else if (RC5_ADDR(rc5) == 0x0) {
- u32 toggle = RC5_TOGGLE(rc5);
- u32 instr = RC5_INSTR(rc5);
-
- /* Good code, decide if repeat/repress */
- if (toggle != RC5_TOGGLE(ir->last_rc5) ||
- instr != RC5_INSTR(ir->last_rc5)) {
- dprintk(KERN_WARNING "instruction %x, toggle %x\n", instr,
- toggle);
- ir_input_nokey(ir->dev, &ir->ir);
- ir_input_keydown(ir->dev, &ir->ir, instr,
- instr);
- }
-
- /* Set/reset key-up timer */
- timeout = current_jiffies + (500 + rc5_key_timeout
- * HZ) / 1000;
- mod_timer(&ir->timer_keyup, timeout);
-
- /* Save code for repeat test */
- ir->last_rc5 = rc5;
- }
- }
-}
-
-static void bttv_rc5_timer_keyup(unsigned long data)
-{
- struct bttv_ir *ir = (struct bttv_ir *)data;
-
- dprintk(KERN_DEBUG "key released\n");
- ir_input_nokey(ir->dev, &ir->ir);
-}
-
/* ---------------------------------------------------------------------- */
-static void bttv_ir_start(struct bttv *btv, struct bttv_ir *ir)
+static void bttv_ir_start(struct bttv *btv, struct card_ir *ir)
{
if (ir->polling) {
- init_timer(&ir->timer);
- ir->timer.function = bttv_input_timer;
- ir->timer.data = (unsigned long)btv;
+ setup_timer(&ir->timer, bttv_input_timer, (unsigned long)btv);
ir->timer.expires = jiffies + HZ;
add_timer(&ir->timer);
} else if (ir->rc5_gpio) {
/* set timer_end for code completion */
init_timer(&ir->timer_end);
- ir->timer_end.function = bttv_rc5_timer_end;
+ ir->timer_end.function = ir_rc5_timer_end;
ir->timer_end.data = (unsigned long)ir;
init_timer(&ir->timer_keyup);
- ir->timer_keyup.function = bttv_rc5_timer_keyup;
+ ir->timer_keyup.function = ir_rc5_timer_keyup;
ir->timer_keyup.data = (unsigned long)ir;
+ ir->shift_by = 1;
+ ir->start = 3;
+ ir->addr = 0x0;
+ ir->rc5_key_timeout = ir_rc5_key_timeout;
+ ir->rc5_remote_gap = ir_rc5_remote_gap;
}
}
@@ -299,7 +192,7 @@ static void bttv_ir_stop(struct bttv *btv)
int bttv_input_init(struct bttv *btv)
{
- struct bttv_ir *ir;
+ struct card_ir *ir;
IR_KEYTAB_TYPE *ir_codes = NULL;
struct input_dev *input_dev;
int ir_type = IR_TYPE_OTHER;
diff --git a/drivers/media/video/bt8xx/bttv-risc.c b/drivers/media/video/bt8xx/bttv-risc.c
index afcfe71e379..e7104d9cb4b 100644
--- a/drivers/media/video/bt8xx/bttv-risc.c
+++ b/drivers/media/video/bt8xx/bttv-risc.c
@@ -43,7 +43,8 @@ int
bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
struct scatterlist *sglist,
unsigned int offset, unsigned int bpl,
- unsigned int padding, unsigned int lines)
+ unsigned int padding, unsigned int skip_lines,
+ unsigned int store_lines)
{
u32 instructions,line,todo;
struct scatterlist *sg;
@@ -54,9 +55,11 @@ bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
one write per scan line + sync + jump (all 2 dwords). padding
can cause next bpl to start close to a page border. First DMA
region may be smaller than PAGE_SIZE */
- instructions = 1 + ((bpl + padding) * lines) / PAGE_SIZE + lines;
- instructions += 2;
- if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions*8)) < 0)
+ instructions = skip_lines * 4;
+ instructions += (1 + ((bpl + padding) * store_lines)
+ / PAGE_SIZE + store_lines) * 8;
+ instructions += 2 * 8;
+ if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions)) < 0)
return rc;
/* sync instruction */
@@ -64,11 +67,16 @@ bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
*(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1);
*(rp++) = cpu_to_le32(0);
+ while (skip_lines-- > 0) {
+ *(rp++) = cpu_to_le32(BT848_RISC_SKIP | BT848_RISC_SOL |
+ BT848_RISC_EOL | bpl);
+ }
+
/* scan lines */
sg = sglist;
- for (line = 0; line < lines; line++) {
+ for (line = 0; line < store_lines; line++) {
if ((btv->opt_vcr_hack) &&
- (line >= (lines - VCR_HACK_LINES)))
+ (line >= (store_lines - VCR_HACK_LINES)))
continue;
while (offset && offset >= sg_dma_len(sg)) {
offset -= sg_dma_len(sg);
@@ -130,7 +138,8 @@ bttv_risc_planar(struct bttv *btv, struct btcx_riscmem *risc,
/* estimate risc mem: worst case is one write per page border +
one write per scan line (5 dwords)
plus sync + jump (2 dwords) */
- instructions = (ybpl * ylines * 2) / PAGE_SIZE + ylines;
+ instructions = ((3 + (ybpl + ypadding) * ylines * 2)
+ / PAGE_SIZE) + ylines;
instructions += 2;
if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions*4*5)) < 0)
return rc;
@@ -317,10 +326,10 @@ bttv_risc_overlay(struct bttv *btv, struct btcx_riscmem *risc,
/* ---------------------------------------------------------- */
static void
-bttv_calc_geo(struct bttv *btv, struct bttv_geometry *geo,
- int width, int height, int interleaved, int norm)
+bttv_calc_geo_old(struct bttv *btv, struct bttv_geometry *geo,
+ int width, int height, int interleaved,
+ const struct bttv_tvnorm *tvnorm)
{
- const struct bttv_tvnorm *tvnorm = &bttv_tvnorms[norm];
u32 xsf, sr;
int vdelay;
@@ -361,6 +370,62 @@ bttv_calc_geo(struct bttv *btv, struct bttv_geometry *geo,
}
static void
+bttv_calc_geo (struct bttv * btv,
+ struct bttv_geometry * geo,
+ unsigned int width,
+ unsigned int height,
+ int both_fields,
+ const struct bttv_tvnorm * tvnorm,
+ const struct v4l2_rect * crop)
+{
+ unsigned int c_width;
+ unsigned int c_height;
+ u32 sr;
+
+ if ((crop->left == tvnorm->cropcap.defrect.left
+ && crop->top == tvnorm->cropcap.defrect.top
+ && crop->width == tvnorm->cropcap.defrect.width
+ && crop->height == tvnorm->cropcap.defrect.height
+ && width <= tvnorm->swidth /* see PAL-Nc et al */)
+ || bttv_tvcards[btv->c.type].muxsel[btv->input] < 0) {
+ bttv_calc_geo_old(btv, geo, width, height,
+ both_fields, tvnorm);
+ return;
+ }
+
+ /* For bug compatibility the image size checks permit scale
+ factors > 16. See bttv_crop_calc_limits(). */
+ c_width = min((unsigned int) crop->width, width * 16);
+ c_height = min((unsigned int) crop->height, height * 16);
+
+ geo->width = width;
+ geo->hscale = (c_width * 4096U + (width >> 1)) / width - 4096;
+ /* Even to store Cb first, odd for Cr. */
+ geo->hdelay = ((crop->left * width + c_width) / c_width) & ~1;
+
+ geo->sheight = c_height;
+ geo->vdelay = crop->top - tvnorm->cropcap.bounds.top + MIN_VDELAY;
+ sr = c_height >> !both_fields;
+ sr = (sr * 512U + (height >> 1)) / height - 512;
+ geo->vscale = (0x10000UL - sr) & 0x1fff;
+ geo->vscale |= both_fields ? (BT848_VSCALE_INT << 8) : 0;
+ geo->vtotal = tvnorm->vtotal;
+
+ geo->crop = (((geo->width >> 8) & 0x03) |
+ ((geo->hdelay >> 6) & 0x0c) |
+ ((geo->sheight >> 4) & 0x30) |
+ ((geo->vdelay >> 2) & 0xc0));
+
+ if (btv->opt_combfilter) {
+ geo->vtc = (width < 193) ? 2 : ((width < 385) ? 1 : 0);
+ geo->comb = (width < 769) ? 1 : 0;
+ } else {
+ geo->vtc = 0;
+ geo->comb = 0;
+ }
+}
+
+static void
bttv_apply_geo(struct bttv *btv, struct bttv_geometry *geo, int odd)
{
int off = odd ? 0x80 : 0x00;
@@ -522,16 +587,51 @@ int
bttv_buffer_activate_vbi(struct bttv *btv,
struct bttv_buffer *vbi)
{
- /* vbi capture */
+ struct btcx_riscmem *top;
+ struct btcx_riscmem *bottom;
+ int top_irq_flags;
+ int bottom_irq_flags;
+
+ top = NULL;
+ bottom = NULL;
+ top_irq_flags = 0;
+ bottom_irq_flags = 0;
+
if (vbi) {
+ unsigned int crop, vdelay;
+
vbi->vb.state = STATE_ACTIVE;
list_del(&vbi->vb.queue);
- bttv_risc_hook(btv, RISC_SLOT_O_VBI, &vbi->top, 0);
- bttv_risc_hook(btv, RISC_SLOT_E_VBI, &vbi->bottom, 4);
- } else {
- bttv_risc_hook(btv, RISC_SLOT_O_VBI, NULL, 0);
- bttv_risc_hook(btv, RISC_SLOT_E_VBI, NULL, 0);
+
+ /* VDELAY is start of video, end of VBI capturing. */
+ crop = btread(BT848_E_CROP);
+ vdelay = btread(BT848_E_VDELAY_LO) + ((crop & 0xc0) << 2);
+
+ if (vbi->geo.vdelay > vdelay) {
+ vdelay = vbi->geo.vdelay & 0xfe;
+ crop = (crop & 0x3f) | ((vbi->geo.vdelay >> 2) & 0xc0);
+
+ btwrite(vdelay, BT848_E_VDELAY_LO);
+ btwrite(crop, BT848_E_CROP);
+ btwrite(vdelay, BT848_O_VDELAY_LO);
+ btwrite(crop, BT848_O_CROP);
+ }
+
+ if (vbi->vbi_count[0] > 0) {
+ top = &vbi->top;
+ top_irq_flags = 4;
+ }
+
+ if (vbi->vbi_count[1] > 0) {
+ top_irq_flags = 0;
+ bottom = &vbi->bottom;
+ bottom_irq_flags = 4;
+ }
}
+
+ bttv_risc_hook(btv, RISC_SLOT_O_VBI, top, top_irq_flags);
+ bttv_risc_hook(btv, RISC_SLOT_E_VBI, bottom, bottom_irq_flags);
+
return 0;
}
@@ -611,28 +711,31 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
int bpf = bpl * (buf->vb.height >> 1);
bttv_calc_geo(btv,&buf->geo,buf->vb.width,buf->vb.height,
- V4L2_FIELD_HAS_BOTH(buf->vb.field),buf->tvnorm);
+ V4L2_FIELD_HAS_BOTH(buf->vb.field),
+ tvnorm,&buf->crop);
switch (buf->vb.field) {
case V4L2_FIELD_TOP:
bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist,
- 0,bpl,0,buf->vb.height);
+ /* offset */ 0,bpl,
+ /* padding */ 0,/* skip_lines */ 0,
+ buf->vb.height);
break;
case V4L2_FIELD_BOTTOM:
bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist,
- 0,bpl,0,buf->vb.height);
+ 0,bpl,0,0,buf->vb.height);
break;
case V4L2_FIELD_INTERLACED:
bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist,
- 0,bpl,bpl,buf->vb.height >> 1);
+ 0,bpl,bpl,0,buf->vb.height >> 1);
bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist,
- bpl,bpl,bpl,buf->vb.height >> 1);
+ bpl,bpl,bpl,0,buf->vb.height >> 1);
break;
case V4L2_FIELD_SEQ_TB:
bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist,
- 0,bpl,0,buf->vb.height >> 1);
+ 0,bpl,0,0,buf->vb.height >> 1);
bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist,
- bpf,bpl,0,buf->vb.height >> 1);
+ bpf,bpl,0,0,buf->vb.height >> 1);
break;
default:
BUG();
@@ -662,7 +765,8 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
switch (buf->vb.field) {
case V4L2_FIELD_TOP:
bttv_calc_geo(btv,&buf->geo,buf->vb.width,
- buf->vb.height,0,buf->tvnorm);
+ buf->vb.height,/* both_fields */ 0,
+ tvnorm,&buf->crop);
bttv_risc_planar(btv, &buf->top, buf->vb.dma.sglist,
0,buf->vb.width,0,buf->vb.height,
uoffset,voffset,buf->fmt->hshift,
@@ -670,7 +774,8 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
break;
case V4L2_FIELD_BOTTOM:
bttv_calc_geo(btv,&buf->geo,buf->vb.width,
- buf->vb.height,0,buf->tvnorm);
+ buf->vb.height,0,
+ tvnorm,&buf->crop);
bttv_risc_planar(btv, &buf->bottom, buf->vb.dma.sglist,
0,buf->vb.width,0,buf->vb.height,
uoffset,voffset,buf->fmt->hshift,
@@ -678,7 +783,8 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
break;
case V4L2_FIELD_INTERLACED:
bttv_calc_geo(btv,&buf->geo,buf->vb.width,
- buf->vb.height,1,buf->tvnorm);
+ buf->vb.height,1,
+ tvnorm,&buf->crop);
lines = buf->vb.height >> 1;
ypadding = buf->vb.width;
cpadding = buf->vb.width >> buf->fmt->hshift;
@@ -700,7 +806,8 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
break;
case V4L2_FIELD_SEQ_TB:
bttv_calc_geo(btv,&buf->geo,buf->vb.width,
- buf->vb.height,1,buf->tvnorm);
+ buf->vb.height,1,
+ tvnorm,&buf->crop);
lines = buf->vb.height >> 1;
ypadding = buf->vb.width;
cpadding = buf->vb.width >> buf->fmt->hshift;
@@ -731,11 +838,12 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
/* build risc code */
buf->vb.field = V4L2_FIELD_SEQ_TB;
bttv_calc_geo(btv,&buf->geo,tvnorm->swidth,tvnorm->sheight,
- 1,buf->tvnorm);
+ 1,tvnorm,&buf->crop);
bttv_risc_packed(btv, &buf->top, buf->vb.dma.sglist,
- 0, RAW_BPL, 0, RAW_LINES);
+ /* offset */ 0, RAW_BPL, /* padding */ 0,
+ /* skip_lines */ 0, RAW_LINES);
bttv_risc_packed(btv, &buf->bottom, buf->vb.dma.sglist,
- buf->vb.size/2 , RAW_BPL, 0, RAW_LINES);
+ buf->vb.size/2 , RAW_BPL, 0, 0, RAW_LINES);
}
/* copy format info */
@@ -761,7 +869,8 @@ bttv_overlay_risc(struct bttv *btv,
/* calculate geometry */
bttv_calc_geo(btv,&buf->geo,ov->w.width,ov->w.height,
- V4L2_FIELD_HAS_BOTH(ov->field), ov->tvnorm);
+ V4L2_FIELD_HAS_BOTH(ov->field),
+ &bttv_tvnorms[ov->tvnorm],&buf->crop);
/* build risc code */
switch (ov->field) {
diff --git a/drivers/media/video/bt8xx/bttv-vbi.c b/drivers/media/video/bt8xx/bttv-vbi.c
index 63676e7bd63..93e35de5a18 100644
--- a/drivers/media/video/bt8xx/bttv-vbi.c
+++ b/drivers/media/video/bt8xx/bttv-vbi.c
@@ -5,6 +5,9 @@
(c) 2002 Gerd Knorr <kraxel@bytesex.org>
+ Copyright (C) 2005, 2006 Michael H. Schimek <mschimek@gmx.at>
+ Sponsored by OPQ Systems 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 2 of the License, or
@@ -25,7 +28,6 @@
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/kdev_t.h>
#include <asm/io.h>
@@ -42,8 +44,15 @@
to be about 244. */
#define VBI_OFFSET 244
+/* 2048 for compatibility with earlier driver versions. The driver
+ really stores 1024 + tvnorm->vbipack * 4 samples per line in the
+ buffer. Note tvnorm->vbipack is <= 0xFF (limit of VBIPACK_LO + HI
+ is 0x1FF DWORDs) and VBI read()s store a frame counter in the last
+ four bytes of the VBI image. */
+#define VBI_BPL 2048
+
+/* Compatibility. */
#define VBI_DEFLINES 16
-#define VBI_MAXLINES 32
static unsigned int vbibufs = 4;
static unsigned int vbi_debug = 0;
@@ -59,21 +68,12 @@ MODULE_PARM_DESC(vbi_debug,"vbi code debug messages, default is 0 (no)");
#define dprintk(fmt, arg...) if (vbi_debug) \
printk(KERN_DEBUG "bttv%d/vbi: " fmt, btv->c.nr , ## arg)
+#define IMAGE_SIZE(fmt) \
+ (((fmt)->count[0] + (fmt)->count[1]) * (fmt)->samples_per_line)
+
/* ----------------------------------------------------------------------- */
/* vbi risc code + mm */
-static int
-vbi_buffer_risc(struct bttv *btv, struct bttv_buffer *buf, int lines)
-{
- int bpl = 2048;
-
- bttv_risc_packed(btv, &buf->top, buf->vb.dma.sglist,
- 0, bpl-4, 4, lines);
- bttv_risc_packed(btv, &buf->bottom, buf->vb.dma.sglist,
- lines * bpl, bpl-4, 4, lines);
- return 0;
-}
-
static int vbi_buffer_setup(struct videobuf_queue *q,
unsigned int *count, unsigned int *size)
{
@@ -82,8 +82,16 @@ static int vbi_buffer_setup(struct videobuf_queue *q,
if (0 == *count)
*count = vbibufs;
- *size = fh->lines * 2 * 2048;
- dprintk("setup: lines=%d\n",fh->lines);
+
+ *size = IMAGE_SIZE(&fh->vbi_fmt.fmt);
+
+ dprintk("setup: samples=%u start=%d,%d count=%u,%u\n",
+ fh->vbi_fmt.fmt.samples_per_line,
+ fh->vbi_fmt.fmt.start[0],
+ fh->vbi_fmt.fmt.start[1],
+ fh->vbi_fmt.fmt.count[0],
+ fh->vbi_fmt.fmt.count[1]);
+
return 0;
}
@@ -94,18 +102,93 @@ static int vbi_buffer_prepare(struct videobuf_queue *q,
struct bttv_fh *fh = q->priv_data;
struct bttv *btv = fh->btv;
struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
+ const struct bttv_tvnorm *tvnorm;
+ unsigned int skip_lines0, skip_lines1, min_vdelay;
+ int redo_dma_risc;
int rc;
- buf->vb.size = fh->lines * 2 * 2048;
+ buf->vb.size = IMAGE_SIZE(&fh->vbi_fmt.fmt);
if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
return -EINVAL;
+ tvnorm = fh->vbi_fmt.tvnorm;
+
+ /* There's no VBI_VDELAY register, RISC must skip the lines
+ we don't want. With default parameters we skip zero lines
+ as earlier driver versions did. The driver permits video
+ standard changes while capturing, so we use vbi_fmt.tvnorm
+ instead of btv->tvnorm to skip zero lines after video
+ standard changes as well. */
+
+ skip_lines0 = 0;
+ skip_lines1 = 0;
+
+ if (fh->vbi_fmt.fmt.count[0] > 0)
+ skip_lines0 = max(0, (fh->vbi_fmt.fmt.start[0]
+ - tvnorm->vbistart[0]));
+ if (fh->vbi_fmt.fmt.count[1] > 0)
+ skip_lines1 = max(0, (fh->vbi_fmt.fmt.start[1]
+ - tvnorm->vbistart[1]));
+
+ redo_dma_risc = 0;
+
+ if (buf->vbi_skip[0] != skip_lines0 ||
+ buf->vbi_skip[1] != skip_lines1 ||
+ buf->vbi_count[0] != fh->vbi_fmt.fmt.count[0] ||
+ buf->vbi_count[1] != fh->vbi_fmt.fmt.count[1]) {
+ buf->vbi_skip[0] = skip_lines0;
+ buf->vbi_skip[1] = skip_lines1;
+ buf->vbi_count[0] = fh->vbi_fmt.fmt.count[0];
+ buf->vbi_count[1] = fh->vbi_fmt.fmt.count[1];
+ redo_dma_risc = 1;
+ }
+
if (STATE_NEEDS_INIT == buf->vb.state) {
+ redo_dma_risc = 1;
if (0 != (rc = videobuf_iolock(q, &buf->vb, NULL)))
goto fail;
- if (0 != (rc = vbi_buffer_risc(btv,buf,fh->lines)))
- goto fail;
}
+
+ if (redo_dma_risc) {
+ unsigned int bpl, padding, offset;
+
+ bpl = 2044; /* max. vbipack */
+ padding = VBI_BPL - bpl;
+
+ if (fh->vbi_fmt.fmt.count[0] > 0) {
+ rc = bttv_risc_packed(btv, &buf->top,
+ buf->vb.dma.sglist,
+ /* offset */ 0, bpl,
+ padding, skip_lines0,
+ fh->vbi_fmt.fmt.count[0]);
+ if (0 != rc)
+ goto fail;
+ }
+
+ if (fh->vbi_fmt.fmt.count[1] > 0) {
+ offset = fh->vbi_fmt.fmt.count[0] * VBI_BPL;
+
+ rc = bttv_risc_packed(btv, &buf->bottom,
+ buf->vb.dma.sglist,
+ offset, bpl,
+ padding, skip_lines1,
+ fh->vbi_fmt.fmt.count[1]);
+ if (0 != rc)
+ goto fail;
+ }
+ }
+
+ /* VBI capturing ends at VDELAY, start of video capturing,
+ no matter where the RISC program ends. VDELAY minimum is 2,
+ bounds.top is the corresponding first field line number
+ times two. VDELAY counts half field lines. */
+ min_vdelay = MIN_VDELAY;
+ if (fh->vbi_fmt.end >= tvnorm->cropcap.bounds.top)
+ min_vdelay += fh->vbi_fmt.end - tvnorm->cropcap.bounds.top;
+
+ /* For bttv_buffer_activate_vbi(). */
+ buf->geo.vdelay = min_vdelay;
+
buf->vb.state = STATE_PREPARED;
buf->vb.field = field;
dprintk("buf prepare %p: top=%p bottom=%p field=%s\n",
@@ -141,7 +224,7 @@ static void vbi_buffer_release(struct videobuf_queue *q, struct videobuf_buffer
struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
dprintk("free %p\n",vb);
- bttv_dma_free(&fh->cap,fh->btv,buf);
+ bttv_dma_free(q,fh->btv,buf);
}
struct videobuf_queue_ops bttv_vbi_qops = {
@@ -153,69 +236,215 @@ struct videobuf_queue_ops bttv_vbi_qops = {
/* ----------------------------------------------------------------------- */
-void bttv_vbi_setlines(struct bttv_fh *fh, struct bttv *btv, int lines)
+static int
+try_fmt (struct v4l2_vbi_format * f,
+ const struct bttv_tvnorm * tvnorm,
+ __s32 crop_start)
{
- int vdelay;
-
- if (lines < 1)
- lines = 1;
- if (lines > VBI_MAXLINES)
- lines = VBI_MAXLINES;
- fh->lines = lines;
-
- vdelay = btread(BT848_E_VDELAY_LO);
- if (vdelay < lines*2) {
- vdelay = lines*2;
- btwrite(vdelay,BT848_E_VDELAY_LO);
- btwrite(vdelay,BT848_O_VDELAY_LO);
+ __s32 min_start, max_start, max_end, f2_offset;
+ unsigned int i;
+
+ /* For compatibility with earlier driver versions we must pretend
+ the VBI and video capture window may overlap. In reality RISC
+ magic aborts VBI capturing at the first line of video capturing,
+ leaving the rest of the buffer unchanged, usually all zero.
+ VBI capturing must always start before video capturing. >> 1
+ because cropping counts field lines times two. */
+ min_start = tvnorm->vbistart[0];
+ max_start = (crop_start >> 1) - 1;
+ max_end = (tvnorm->cropcap.bounds.top
+ + tvnorm->cropcap.bounds.height) >> 1;
+
+ if (min_start > max_start)
+ return -EBUSY;
+
+ BUG_ON(max_start >= max_end);
+
+ f->sampling_rate = tvnorm->Fsc;
+ f->samples_per_line = VBI_BPL;
+ f->sample_format = V4L2_PIX_FMT_GREY;
+ f->offset = VBI_OFFSET;
+
+ f2_offset = tvnorm->vbistart[1] - tvnorm->vbistart[0];
+
+ for (i = 0; i < 2; ++i) {
+ if (0 == f->count[i]) {
+ /* No data from this field. We leave f->start[i]
+ alone because VIDIOCSVBIFMT is w/o and EINVALs
+ when a driver does not support exactly the
+ requested parameters. */
+ } else {
+ s64 start, count;
+
+ start = clamp(f->start[i], min_start, max_start);
+ /* s64 to prevent overflow. */
+ count = (s64) f->start[i] + f->count[i] - start;
+ f->start[i] = start;
+ f->count[i] = clamp(count, (s64) 1,
+ max_end - start);
+ }
+
+ min_start += f2_offset;
+ max_start += f2_offset;
+ max_end += f2_offset;
}
+
+ if (0 == (f->count[0] | f->count[1])) {
+ /* As in earlier driver versions. */
+ f->start[0] = tvnorm->vbistart[0];
+ f->start[1] = tvnorm->vbistart[1];
+ f->count[0] = 1;
+ f->count[1] = 1;
+ }
+
+ f->flags = 0;
+
+ f->reserved[0] = 0;
+ f->reserved[1] = 0;
+
+ return 0;
}
-void bttv_vbi_try_fmt(struct bttv_fh *fh, struct v4l2_format *f)
+int
+bttv_vbi_try_fmt (struct bttv_fh * fh,
+ struct v4l2_vbi_format * f)
{
+ struct bttv *btv = fh->btv;
const struct bttv_tvnorm *tvnorm;
- s64 count0,count1,count;
+ __s32 crop_start;
- tvnorm = &bttv_tvnorms[fh->btv->tvnorm];
- f->type = V4L2_BUF_TYPE_VBI_CAPTURE;
- f->fmt.vbi.sampling_rate = tvnorm->Fsc;
- f->fmt.vbi.samples_per_line = 2048;
- f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
- f->fmt.vbi.offset = VBI_OFFSET;
- f->fmt.vbi.flags = 0;
-
- /* s64 to prevent overflow. */
- count0 = (s64) f->fmt.vbi.start[0] + f->fmt.vbi.count[0]
- - tvnorm->vbistart[0];
- count1 = (s64) f->fmt.vbi.start[1] + f->fmt.vbi.count[1]
- - tvnorm->vbistart[1];
- count = clamp (max (count0, count1), (s64) 1, (s64) VBI_MAXLINES);
-
- f->fmt.vbi.start[0] = tvnorm->vbistart[0];
- f->fmt.vbi.start[1] = tvnorm->vbistart[1];
- f->fmt.vbi.count[0] = count;
- f->fmt.vbi.count[1] = count;
-
- f->fmt.vbi.reserved[0] = 0;
- f->fmt.vbi.reserved[1] = 0;
+ mutex_lock(&btv->lock);
+
+ tvnorm = &bttv_tvnorms[btv->tvnorm];
+ crop_start = btv->crop_start;
+
+ mutex_unlock(&btv->lock);
+
+ return try_fmt(f, tvnorm, crop_start);
}
-void bttv_vbi_get_fmt(struct bttv_fh *fh, struct v4l2_format *f)
+int
+bttv_vbi_set_fmt (struct bttv_fh * fh,
+ struct v4l2_vbi_format * f)
{
+ struct bttv *btv = fh->btv;
const struct bttv_tvnorm *tvnorm;
+ __s32 start1, end;
+ int rc;
+
+ mutex_lock(&btv->lock);
+
+ rc = -EBUSY;
+ if (fh->resources & RESOURCE_VBI)
+ goto fail;
+
+ tvnorm = &bttv_tvnorms[btv->tvnorm];
+
+ rc = try_fmt(f, tvnorm, btv->crop_start);
+ if (0 != rc)
+ goto fail;
+
+ start1 = f->start[1] - tvnorm->vbistart[1] + tvnorm->vbistart[0];
+
+ /* First possible line of video capturing. Should be
+ max(f->start[0] + f->count[0], start1 + f->count[1]) * 2
+ when capturing both fields. But for compatibility we must
+ pretend the VBI and video capture window may overlap,
+ so end = start + 1, the lowest possible value, times two
+ because vbi_fmt.end counts field lines times two. */
+ end = max(f->start[0], start1) * 2 + 2;
+
+ mutex_lock(&fh->vbi.lock);
+
+ fh->vbi_fmt.fmt = *f;
+ fh->vbi_fmt.tvnorm = tvnorm;
+ fh->vbi_fmt.end = end;
+
+ mutex_unlock(&fh->vbi.lock);
+
+ rc = 0;
+
+ fail:
+ mutex_unlock(&btv->lock);
+
+ return rc;
+}
+
+void
+bttv_vbi_get_fmt (struct bttv_fh * fh,
+ struct v4l2_vbi_format * f)
+{
+ const struct bttv_tvnorm *tvnorm;
+
+ *f = fh->vbi_fmt.fmt;
tvnorm = &bttv_tvnorms[fh->btv->tvnorm];
- memset(f,0,sizeof(*f));
- f->type = V4L2_BUF_TYPE_VBI_CAPTURE;
- f->fmt.vbi.sampling_rate = tvnorm->Fsc;
- f->fmt.vbi.samples_per_line = 2048;
- f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
- f->fmt.vbi.offset = VBI_OFFSET;
- f->fmt.vbi.start[0] = tvnorm->vbistart[0];
- f->fmt.vbi.start[1] = tvnorm->vbistart[1];
- f->fmt.vbi.count[0] = fh->lines;
- f->fmt.vbi.count[1] = fh->lines;
- f->fmt.vbi.flags = 0;
+
+ if (tvnorm != fh->vbi_fmt.tvnorm) {
+ __s32 max_end;
+ unsigned int i;
+
+ /* As in vbi_buffer_prepare() this imitates the
+ behaviour of earlier driver versions after video
+ standard changes, with default parameters anyway. */
+
+ max_end = (tvnorm->cropcap.bounds.top
+ + tvnorm->cropcap.bounds.height) >> 1;
+
+ f->sampling_rate = tvnorm->Fsc;
+
+ for (i = 0; i < 2; ++i) {
+ __s32 new_start;
+
+ new_start = f->start[i]
+ + tvnorm->vbistart[i]
+ - fh->vbi_fmt.tvnorm->vbistart[i];
+
+ f->start[i] = min(new_start, max_end - 1);
+ f->count[i] = min((__s32) f->count[i],
+ max_end - f->start[i]);
+
+ max_end += tvnorm->vbistart[1]
+ - tvnorm->vbistart[0];
+ }
+ }
+}
+
+void
+bttv_vbi_fmt_reset (struct bttv_vbi_fmt * f,
+ int norm)
+{
+ const struct bttv_tvnorm *tvnorm;
+ unsigned int real_samples_per_line;
+ unsigned int real_count;
+
+ tvnorm = &bttv_tvnorms[norm];
+
+ f->fmt.sampling_rate = tvnorm->Fsc;
+ f->fmt.samples_per_line = VBI_BPL;
+ f->fmt.sample_format = V4L2_PIX_FMT_GREY;
+ f->fmt.offset = VBI_OFFSET;
+ f->fmt.start[0] = tvnorm->vbistart[0];
+ f->fmt.start[1] = tvnorm->vbistart[1];
+ f->fmt.count[0] = VBI_DEFLINES;
+ f->fmt.count[1] = VBI_DEFLINES;
+ f->fmt.flags = 0;
+ f->fmt.reserved[0] = 0;
+ f->fmt.reserved[1] = 0;
+
+ /* For compatibility the buffer size must be 2 * VBI_DEFLINES *
+ VBI_BPL regardless of the current video standard. */
+ real_samples_per_line = 1024 + tvnorm->vbipack * 4;
+ real_count = ((tvnorm->cropcap.defrect.top >> 1)
+ - tvnorm->vbistart[0]);
+
+ BUG_ON(real_samples_per_line > VBI_BPL);
+ BUG_ON(real_count > VBI_DEFLINES);
+
+ f->tvnorm = tvnorm;
+
+ /* See bttv_vbi_fmt_set(). */
+ f->end = tvnorm->vbistart[0] * 2 + 2;
}
/* ----------------------------------------------------------------------- */
diff --git a/drivers/media/video/bt8xx/bttv.h b/drivers/media/video/bt8xx/bttv.h
index f9c9e3c4d11..5491acbdaf6 100644
--- a/drivers/media/video/bt8xx/bttv.h
+++ b/drivers/media/video/bt8xx/bttv.h
@@ -197,33 +197,6 @@ struct bttv_core {
struct bttv;
-struct bttv_ir {
- struct input_dev *dev;
- struct ir_input_state ir;
- char name[32];
- char phys[32];
-
- /* Usual gpio signalling */
-
- u32 mask_keycode;
- u32 mask_keydown;
- u32 mask_keyup;
- u32 polling;
- u32 last_gpio;
- struct work_struct work;
- struct timer_list timer;
-
- /* RC5 gpio */
- u32 rc5_gpio;
- struct timer_list timer_end; /* timer_end for code completion */
- struct timer_list timer_keyup; /* timer_end for key release */
- u32 last_rc5; /* last good rc5 code */
- u32 last_bit; /* last raw bit seen */
- u32 code; /* raw code under construction */
- struct timeval base_time; /* time of last seen code */
- int active; /* building raw code */
-};
-
struct tvcard
{
char *name;
diff --git a/drivers/media/video/bt8xx/bttvp.h b/drivers/media/video/bt8xx/bttvp.h
index 311c4c541e0..ad79b8d5343 100644
--- a/drivers/media/video/bt8xx/bttvp.h
+++ b/drivers/media/video/bt8xx/bttvp.h
@@ -26,7 +26,7 @@
#define _BTTVP_H_
#include <linux/version.h>
-#define BTTV_VERSION_CODE KERNEL_VERSION(0,9,16)
+#define BTTV_VERSION_CODE KERNEL_VERSION(0,9,17)
#include <linux/types.h>
#include <linux/wait.h>
@@ -66,14 +66,22 @@
#define RISC_SLOT_LOOP 14
#define RESOURCE_OVERLAY 1
-#define RESOURCE_VIDEO 2
+#define RESOURCE_VIDEO_STREAM 2
#define RESOURCE_VBI 4
+#define RESOURCE_VIDEO_READ 8
#define RAW_LINES 640
#define RAW_BPL 1024
#define UNSET (-1U)
+/* Min. value in VDELAY register. */
+#define MIN_VDELAY 2
+/* Even to get Cb first, odd for Cr. */
+#define MAX_HDELAY (0x3FF & -2)
+/* Limits scaled width, which must be a multiple of 4. */
+#define MAX_HACTIVE (0x3FF & -4)
+
#define clamp(x, low, high) min (max (low, x), high)
/* ---------------------------------------------------------- */
@@ -92,8 +100,13 @@ struct bttv_tvnorm {
u16 vtotal;
int sram;
/* ITU-R frame line number of the first VBI line we can
- capture, of the first and second field. */
+ capture, of the first and second field. The last possible line
+ is determined by cropcap.bounds. */
u16 vbistart[2];
+ /* Horizontally this counts fCLKx1 samples following the leading
+ edge of the horizontal sync pulse, vertically ITU-R frame line
+ numbers of the first field times two (2, 4, 6, ... 524 or 624). */
+ struct v4l2_cropcap cropcap;
};
extern const struct bttv_tvnorm bttv_tvnorms[];
@@ -128,6 +141,9 @@ struct bttv_buffer {
struct bttv_geometry geo;
struct btcx_riscmem top;
struct btcx_riscmem bottom;
+ struct v4l2_rect crop;
+ unsigned int vbi_skip[2];
+ unsigned int vbi_count[2];
};
struct bttv_buffer_set {
@@ -146,6 +162,34 @@ struct bttv_overlay {
int setup_ok;
};
+struct bttv_vbi_fmt {
+ struct v4l2_vbi_format fmt;
+
+ /* fmt.start[] and count[] refer to this video standard. */
+ const struct bttv_tvnorm *tvnorm;
+
+ /* Earliest possible start of video capturing with this
+ v4l2_vbi_format, in struct bttv_crop.rect units. */
+ __s32 end;
+};
+
+/* bttv-vbi.c */
+void bttv_vbi_fmt_reset(struct bttv_vbi_fmt *f, int norm);
+
+struct bttv_crop {
+ /* A cropping rectangle in struct bttv_tvnorm.cropcap units. */
+ struct v4l2_rect rect;
+
+ /* Scaled image size limits with this crop rect. Divide
+ max_height, but not min_height, by two when capturing
+ single fields. See also bttv_crop_reset() and
+ bttv_crop_adjust() in bttv-driver.c. */
+ __s32 min_scaled_width;
+ __s32 min_scaled_height;
+ __s32 max_scaled_width;
+ __s32 max_scaled_height;
+};
+
struct bttv_fh {
struct bttv *btv;
int resources;
@@ -160,13 +204,19 @@ struct bttv_fh {
int width;
int height;
- /* current settings */
+ /* video overlay */
const struct bttv_format *ovfmt;
struct bttv_overlay ov;
- /* video overlay */
+ /* Application called VIDIOC_S_CROP. */
+ int do_crop;
+
+ /* vbi capture */
struct videobuf_queue vbi;
- int lines;
+ /* Current VBI capture window as seen through this fh (cannot
+ be global for compatibility with earlier drivers). Protected
+ by struct bttv.lock and struct bttv_fh.vbi.lock. */
+ struct bttv_vbi_fmt vbi_fmt;
};
/* ---------------------------------------------------------- */
@@ -176,7 +226,8 @@ struct bttv_fh {
int bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
struct scatterlist *sglist,
unsigned int offset, unsigned int bpl,
- unsigned int pitch, unsigned int lines);
+ unsigned int pitch, unsigned int skip_lines,
+ unsigned int store_lines);
/* control dma register + risc main loop */
void bttv_set_dma(struct bttv *btv, int override);
@@ -202,9 +253,9 @@ int bttv_overlay_risc(struct bttv *btv, struct bttv_overlay *ov,
/* ---------------------------------------------------------- */
/* bttv-vbi.c */
-void bttv_vbi_try_fmt(struct bttv_fh *fh, struct v4l2_format *f);
-void bttv_vbi_get_fmt(struct bttv_fh *fh, struct v4l2_format *f);
-void bttv_vbi_setlines(struct bttv_fh *fh, struct bttv *btv, int lines);
+int bttv_vbi_try_fmt(struct bttv_fh *fh, struct v4l2_vbi_format *f);
+void bttv_vbi_get_fmt(struct bttv_fh *fh, struct v4l2_vbi_format *f);
+int bttv_vbi_set_fmt(struct bttv_fh *fh, struct v4l2_vbi_format *f);
extern struct videobuf_queue_ops bttv_vbi_qops;
@@ -233,7 +284,6 @@ extern int fini_bttv_i2c(struct bttv *btv);
#define d2printk if (bttv_debug >= 2) printk
#define BTTV_MAX_FBUF 0x208000
-#define VBIBUF_SIZE (2048*VBI_MAXLINES*2)
#define BTTV_TIMEOUT (HZ/2) /* 0.5 seconds */
#define BTTV_FREE_IDLE (HZ) /* one second */
@@ -308,13 +358,12 @@ struct bttv {
/* infrared remote */
int has_remote;
- struct bttv_ir *remote;
+ struct card_ir *remote;
/* locking */
spinlock_t s_lock;
struct mutex lock;
int resources;
- struct mutex reslock;
#ifdef VIDIOC_G_PRIORITY
struct v4l2_prio_state prio;
#endif
@@ -384,6 +433,21 @@ struct bttv {
unsigned int users;
struct bttv_fh init;
+
+ /* Default (0) and current (1) video capturing and overlay
+ cropping parameters in bttv_tvnorm.cropcap units. Protected
+ by bttv.lock. */
+ struct bttv_crop crop[2];
+
+ /* Earliest possible start of video capturing in
+ bttv_tvnorm.cropcap line units. Set by check_alloc_btres()
+ and free_btres(). Protected by bttv.lock. */
+ __s32 vbi_end;
+
+ /* Latest possible end of VBI capturing (= crop[x].rect.top when
+ VIDEO_RESOURCES are locked). Set by check_alloc_btres()
+ and free_btres(). Protected by bttv.lock. */
+ __s32 crop_start;
};
/* our devices */
diff --git a/drivers/media/video/bw-qcam.c b/drivers/media/video/bw-qcam.c
index 7d0b6e59c6e..7d47cbe6ad2 100644
--- a/drivers/media/video/bw-qcam.c
+++ b/drivers/media/video/bw-qcam.c
@@ -871,7 +871,7 @@ static ssize_t qcam_read(struct file *file, char __user *buf,
return len;
}
-static struct file_operations qcam_fops = {
+static const struct file_operations qcam_fops = {
.owner = THIS_MODULE,
.open = video_exclusive_open,
.release = video_exclusive_release,
diff --git a/drivers/media/video/c-qcam.c b/drivers/media/video/c-qcam.c
index a3989bd2f81..925ff17efbb 100644
--- a/drivers/media/video/c-qcam.c
+++ b/drivers/media/video/c-qcam.c
@@ -684,7 +684,7 @@ static ssize_t qcam_read(struct file *file, char __user *buf,
}
/* video device template */
-static struct file_operations qcam_fops = {
+static const struct file_operations qcam_fops = {
.owner = THIS_MODULE,
.open = video_exclusive_open,
.release = video_exclusive_release,
diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c
index 3083c8075d1..682dc7ce48d 100644
--- a/drivers/media/video/cafe_ccic.c
+++ b/drivers/media/video/cafe_ccic.c
@@ -549,6 +549,7 @@ static int cafe_smbus_setup(struct cafe_camera *cam)
adap->client_unregister = cafe_smbus_detach;
adap->algo = &cafe_smbus_algo;
strcpy(adap->name, "cafe_ccic");
+ adap->dev.parent = &cam->pdev->dev;
i2c_set_adapdata(adap, cam);
ret = i2c_add_adapter(adap);
if (ret)
@@ -1194,7 +1195,7 @@ static int cafe_vidioc_reqbufs(struct file *filp, void *priv,
struct v4l2_requestbuffers *req)
{
struct cafe_camera *cam = filp->private_data;
- int ret;
+ int ret = 0; /* Silence warning */
/*
* Make sure it's something we can do. User pointers could be
@@ -1715,7 +1716,7 @@ static void cafe_v4l_dev_release(struct video_device *vd)
* clone it for specific real devices.
*/
-static struct file_operations cafe_v4l_fops = {
+static const struct file_operations cafe_v4l_fops = {
.owner = THIS_MODULE,
.open = cafe_v4l_open,
.release = cafe_v4l_release,
@@ -1969,7 +1970,7 @@ static ssize_t cafe_dfs_read_regs(struct file *file,
s - cafe_debug_buf);
}
-static struct file_operations cafe_dfs_reg_ops = {
+static const struct file_operations cafe_dfs_reg_ops = {
.owner = THIS_MODULE,
.read = cafe_dfs_read_regs,
.open = cafe_dfs_open
@@ -1995,7 +1996,7 @@ static ssize_t cafe_dfs_read_cam(struct file *file,
s - cafe_debug_buf);
}
-static struct file_operations cafe_dfs_cam_ops = {
+static const struct file_operations cafe_dfs_cam_ops = {
.owner = THIS_MODULE,
.read = cafe_dfs_read_cam,
.open = cafe_dfs_open
diff --git a/drivers/media/video/cpia.c b/drivers/media/video/cpia.c
index 3b31a0dd2f0..78c9699eafb 100644
--- a/drivers/media/video/cpia.c
+++ b/drivers/media/video/cpia.c
@@ -1350,13 +1350,13 @@ out:
static void create_proc_cpia_cam(struct cam_data *cam)
{
- char name[7];
+ char name[5 + 1 + 10 + 1];
struct proc_dir_entry *ent;
if (!cpia_proc_root || !cam)
return;
- sprintf(name, "video%d", cam->vdev.minor);
+ snprintf(name, sizeof(name), "video%d", cam->vdev.minor);
ent = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, cpia_proc_root);
if (!ent)
@@ -1376,12 +1376,12 @@ static void create_proc_cpia_cam(struct cam_data *cam)
static void destroy_proc_cpia_cam(struct cam_data *cam)
{
- char name[7];
+ char name[5 + 1 + 10 + 1];
if (!cam || !cam->proc_entry)
return;
- sprintf(name, "video%d", cam->vdev.minor);
+ snprintf(name, sizeof(name), "video%d", cam->vdev.minor);
remove_proc_entry(name, cpia_proc_root);
cam->proc_entry = NULL;
}
@@ -3153,8 +3153,7 @@ static int reset_camera(struct cam_data *cam)
static void put_cam(struct cpia_camera_ops* ops)
{
- if (ops->owner)
- module_put(ops->owner);
+ module_put(ops->owner);
}
/* ------------------------- V4L interface --------------------- */
@@ -3791,7 +3790,7 @@ static int cpia_mmap(struct file *file, struct vm_area_struct *vma)
return 0;
}
-static struct file_operations cpia_fops = {
+static const struct file_operations cpia_fops = {
.owner = THIS_MODULE,
.open = cpia_open,
.release = cpia_close,
diff --git a/drivers/media/video/cpia2/cpia2_v4l.c b/drivers/media/video/cpia2/cpia2_v4l.c
index d09f49950f2..1bda7ad9de1 100644
--- a/drivers/media/video/cpia2/cpia2_v4l.c
+++ b/drivers/media/video/cpia2/cpia2_v4l.c
@@ -1924,7 +1924,7 @@ static void reset_camera_struct_v4l(struct camera_data *cam)
/***
* The v4l video device structure initialized for this device
***/
-static struct file_operations fops_template = {
+static const struct file_operations fops_template = {
.owner = THIS_MODULE,
.open = cpia2_open,
.release = cpia2_close,
diff --git a/drivers/media/video/cx2341x.c b/drivers/media/video/cx2341x.c
index 2f5ca71e026..d60cd5ecf82 100644
--- a/drivers/media/video/cx2341x.c
+++ b/drivers/media/video/cx2341x.c
@@ -56,7 +56,6 @@ const u32 cx2341x_mpeg_ctrls[] = {
V4L2_CID_MPEG_VIDEO_B_FRAMES,
V4L2_CID_MPEG_VIDEO_GOP_SIZE,
V4L2_CID_MPEG_VIDEO_GOP_CLOSURE,
- V4L2_CID_MPEG_VIDEO_PULLDOWN,
V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
V4L2_CID_MPEG_VIDEO_BITRATE,
V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
@@ -118,9 +117,6 @@ static int cx2341x_get_ctrl(struct cx2341x_mpeg_params *params,
case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
ctrl->value = params->video_gop_closure;
break;
- case V4L2_CID_MPEG_VIDEO_PULLDOWN:
- ctrl->value = params->video_pulldown;
- break;
case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
ctrl->value = params->video_bitrate_mode;
break;
@@ -231,9 +227,6 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params,
case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
params->video_gop_closure = ctrl->value;
break;
- case V4L2_CID_MPEG_VIDEO_PULLDOWN:
- params->video_pulldown = ctrl->value;
- break;
case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
/* MPEG-1 only allows CBR */
if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1 &&
@@ -679,7 +672,6 @@ void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p)
.video_b_frames = 2,
.video_gop_size = 12,
.video_gop_closure = 1,
- .video_pulldown = 0,
.video_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
.video_bitrate = 6000000,
.video_bitrate_peak = 8000000,
@@ -783,10 +775,6 @@ int cx2341x_update(void *priv, cx2341x_mbox_func func,
err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_CLOSURE, 1, new->video_gop_closure);
if (err) return err;
}
- if (old == NULL || old->video_pulldown != new->video_pulldown) {
- err = cx2341x_api(priv, func, CX2341X_ENC_SET_3_2_PULLDOWN, 1, new->video_pulldown);
- if (err) return err;
- }
if (old == NULL || old->audio_properties != new->audio_properties) {
err = cx2341x_api(priv, func, CX2341X_ENC_SET_AUDIO_PROPERTIES, 1, new->audio_properties);
if (err) return err;
@@ -888,11 +876,10 @@ void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix)
printk(", Peak %d", p->video_bitrate_peak);
}
printk("\n");
- printk(KERN_INFO "%s: Video: GOP Size %d, %d B-Frames, %sGOP Closure, %s3:2 Pulldown\n",
+ printk(KERN_INFO "%s: Video: GOP Size %d, %d B-Frames, %sGOP Closure\n",
prefix,
p->video_gop_size, p->video_b_frames,
- p->video_gop_closure ? "" : "No ",
- p->video_pulldown ? "" : "No ");
+ p->video_gop_closure ? "" : "No ");
if (p->video_temporal_decimation) {
printk(KERN_INFO "%s: Video: Temporal Decimation %d\n",
prefix, p->video_temporal_decimation);
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c
index 7bb7589a07c..cc535ca713d 100644
--- a/drivers/media/video/cx25840/cx25840-core.c
+++ b/drivers/media/video/cx25840/cx25840-core.c
@@ -628,17 +628,8 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
#ifdef CONFIG_VIDEO_ADV_DEBUG
/* ioctls to allow direct access to the
* cx25840 registers for testing */
- case VIDIOC_INT_G_REGISTER:
- {
- struct v4l2_register *reg = arg;
-
- if (reg->i2c_id != I2C_DRIVERID_CX25840)
- return -EINVAL;
- reg->val = cx25840_read(client, reg->reg & 0x0fff);
- break;
- }
-
- case VIDIOC_INT_S_REGISTER:
+ case VIDIOC_DBG_G_REGISTER:
+ case VIDIOC_DBG_S_REGISTER:
{
struct v4l2_register *reg = arg;
@@ -646,7 +637,10 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
return -EINVAL;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- cx25840_write(client, reg->reg & 0x0fff, reg->val & 0xff);
+ if (cmd == VIDIOC_DBG_G_REGISTER)
+ reg->val = cx25840_read(client, reg->reg & 0x0fff);
+ else
+ cx25840_write(client, reg->reg & 0x0fff, reg->val & 0xff);
break;
}
#endif
@@ -893,9 +887,11 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
return 0;
}
+ /* Note: revision '(device_id & 0x0f) == 2' was never built. The
+ marking skips from 0x1 == 22 to 0x3 == 23. */
v4l_info(client, "cx25%3x-2%x found @ 0x%x (%s)\n",
(device_id & 0xfff0) >> 4,
- (device_id & 0x0f) < 3 ? (device_id & 0x0f) + 1 : 3,
+ (device_id & 0x0f) < 3 ? (device_id & 0x0f) + 1 : (device_id & 0x0f),
address << 1, adapter->name);
i2c_set_clientdata(client, state);
diff --git a/drivers/media/video/cx88/Makefile b/drivers/media/video/cx88/Makefile
index 639c3b659d0..532cee35eb3 100644
--- a/drivers/media/video/cx88/Makefile
+++ b/drivers/media/video/cx88/Makefile
@@ -12,8 +12,3 @@ obj-$(CONFIG_VIDEO_CX88_VP3054) += cx88-vp3054-i2c.o
EXTRA_CFLAGS += -Idrivers/media/video
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
-
-extra-cflags-$(CONFIG_VIDEO_BUF_DVB) += -DHAVE_VIDEO_BUF_DVB=1
-extra-cflags-$(CONFIG_VIDEO_CX88_VP3054)+= -DHAVE_VP3054_I2C=1
-
-EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m)
diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c
index 0cf0360588e..a1be1e279df 100644
--- a/drivers/media/video/cx88/cx88-blackbird.c
+++ b/drivers/media/video/cx88/cx88-blackbird.c
@@ -6,6 +6,9 @@
* (c) 2004 Jelle Foks <jelle@foks.8m.com>
* (c) 2004 Gerd Knorr <kraxel@bytesex.org>
*
+ * (c) 2005-2006 Mauro Carvalho Chehab <mchehab@infradead.org>
+ * - video_ioctl2 conversion
+ *
* Includes parts from the ivtv driver( http://ivtv.sourceforge.net/),
*
* This program is free software; you can redistribute it and/or modify
@@ -520,7 +523,7 @@ static void blackbird_codec_settings(struct cx8802_dev *dev)
dev->params.width = dev->width;
dev->params.height = dev->height;
- dev->params.is_50hz = (dev->core->tvnorm->id & V4L2_STD_625_50) != 0;
+ dev->params.is_50hz = (dev->core->tvnorm & V4L2_STD_625_50) != 0;
cx2341x_update(dev, blackbird_mbox_func, NULL, &dev->params);
}
@@ -710,8 +713,13 @@ static int blackbird_queryctrl(struct cx8802_dev *dev, struct v4l2_queryctrl *qc
return 0;
}
-static int blackbird_querymenu(struct cx8802_dev *dev, struct v4l2_querymenu *qmenu)
+/* ------------------------------------------------------------------ */
+/* IOCTL Handlers */
+
+static int vidioc_querymenu (struct file *file, void *priv,
+ struct v4l2_querymenu *qmenu)
{
+ struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev;
struct v4l2_queryctrl qctrl;
qctrl.id = qmenu->id;
@@ -719,221 +727,347 @@ static int blackbird_querymenu(struct cx8802_dev *dev, struct v4l2_querymenu *qm
return v4l2_ctrl_query_menu(qmenu, &qctrl, cx2341x_ctrl_get_menu(qmenu->id));
}
-/* ------------------------------------------------------------------ */
+static int vidioc_querycap (struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev;
+ struct cx88_core *core = dev->core;
-static int mpeg_do_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, void *arg)
+ strcpy(cap->driver, "cx88_blackbird");
+ strlcpy(cap->card, cx88_boards[core->board].name,sizeof(cap->card));
+ sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
+ cap->version = CX88_VERSION_CODE;
+ cap->capabilities =
+ V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING;
+ if (UNSET != core->tuner_type)
+ cap->capabilities |= V4L2_CAP_TUNER;
+ return 0;
+}
+
+static int vidioc_enum_fmt_cap (struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
{
- struct cx8802_fh *fh = file->private_data;
- struct cx8802_dev *dev = fh->dev;
+ if (f->index != 0)
+ return -EINVAL;
+
+ strlcpy(f->description, "MPEG", sizeof(f->description));
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ f->pixelformat = V4L2_PIX_FMT_MPEG;
+ return 0;
+}
+
+static int vidioc_g_fmt_cap (struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct cx8802_fh *fh = priv;
+ struct cx8802_dev *dev = fh->dev;
+
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
+ f->fmt.pix.bytesperline = 0;
+ f->fmt.pix.sizeimage = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */
+ f->fmt.pix.colorspace = 0;
+ f->fmt.pix.width = dev->width;
+ f->fmt.pix.height = dev->height;
+ f->fmt.pix.field = fh->mpegq.field;
+ dprintk(0,"VIDIOC_G_FMT: w: %d, h: %d, f: %d\n",
+ dev->width, dev->height, fh->mpegq.field );
+ return 0;
+}
+
+static int vidioc_try_fmt_cap (struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct cx8802_fh *fh = priv;
+ struct cx8802_dev *dev = fh->dev;
+
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
+ f->fmt.pix.bytesperline = 0;
+ f->fmt.pix.sizeimage = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */;
+ f->fmt.pix.colorspace = 0;
+ dprintk(0,"VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n",
+ dev->width, dev->height, fh->mpegq.field );
+ return 0;
+}
+
+static int vidioc_s_fmt_cap (struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct cx8802_fh *fh = priv;
+ struct cx8802_dev *dev = fh->dev;
struct cx88_core *core = dev->core;
- if (debug > 1)
- v4l_print_ioctl(core->name,cmd);
-
- switch (cmd) {
-
- /* --- capabilities ------------------------------------------ */
- case VIDIOC_QUERYCAP:
- {
- struct v4l2_capability *cap = arg;
-
- memset(cap,0,sizeof(*cap));
- strcpy(cap->driver, "cx88_blackbird");
- strlcpy(cap->card, cx88_boards[core->board].name,sizeof(cap->card));
- sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
- cap->version = CX88_VERSION_CODE;
- cap->capabilities =
- V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_READWRITE |
- V4L2_CAP_STREAMING |
- 0;
- if (UNSET != core->tuner_type)
- cap->capabilities |= V4L2_CAP_TUNER;
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
+ f->fmt.pix.bytesperline = 0;
+ f->fmt.pix.sizeimage = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */;
+ f->fmt.pix.colorspace = 0;
+ dev->width = f->fmt.pix.width;
+ dev->height = f->fmt.pix.height;
+ fh->mpegq.field = f->fmt.pix.field;
+ cx88_set_scale(core, f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field);
+ blackbird_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0,
+ f->fmt.pix.height, f->fmt.pix.width);
+ dprintk(0,"VIDIOC_S_FMT: w: %d, h: %d, f: %d\n",
+ f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field );
+ return 0;
+}
- return 0;
- }
+static int vidioc_reqbufs (struct file *file, void *priv, struct v4l2_requestbuffers *p)
+{
+ struct cx8802_fh *fh = priv;
+ return (videobuf_reqbufs(&fh->mpegq, p));
+}
- /* --- capture ioctls ---------------------------------------- */
- case VIDIOC_ENUM_FMT:
- {
- struct v4l2_fmtdesc *f = arg;
- int index;
-
- index = f->index;
- if (index != 0)
- return -EINVAL;
-
- memset(f,0,sizeof(*f));
- f->index = index;
- strlcpy(f->description, "MPEG", sizeof(f->description));
- f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- f->pixelformat = V4L2_PIX_FMT_MPEG;
- return 0;
- }
- case VIDIOC_G_FMT:
- {
- struct v4l2_format *f = arg;
-
- memset(f,0,sizeof(*f));
- f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
- f->fmt.pix.bytesperline = 0;
- f->fmt.pix.sizeimage = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */
- f->fmt.pix.colorspace = 0;
- f->fmt.pix.width = dev->width;
- f->fmt.pix.height = dev->height;
- f->fmt.pix.field = fh->mpegq.field;
- dprintk(0,"VIDIOC_G_FMT: w: %d, h: %d, f: %d\n",
- dev->width, dev->height, fh->mpegq.field );
- return 0;
- }
- case VIDIOC_TRY_FMT:
- {
- struct v4l2_format *f = arg;
-
- f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
- f->fmt.pix.bytesperline = 0;
- f->fmt.pix.sizeimage = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */;
- f->fmt.pix.colorspace = 0;
- dprintk(0,"VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n",
- dev->width, dev->height, fh->mpegq.field );
- return 0;
- }
- case VIDIOC_S_FMT:
- {
- struct v4l2_format *f = arg;
-
- f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
- f->fmt.pix.bytesperline = 0;
- f->fmt.pix.sizeimage = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */;
- f->fmt.pix.colorspace = 0;
- dprintk(0,"VIDIOC_S_FMT: w: %d, h: %d, f: %d\n",
- f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field );
- return 0;
- }
+static int vidioc_querybuf (struct file *file, void *priv, struct v4l2_buffer *p)
+{
+ struct cx8802_fh *fh = priv;
+ return (videobuf_querybuf(&fh->mpegq, p));
+}
- /* --- streaming capture ------------------------------------- */
- case VIDIOC_REQBUFS:
- return videobuf_reqbufs(&fh->mpegq, arg);
+static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *p)
+{
+ struct cx8802_fh *fh = priv;
+ return (videobuf_qbuf(&fh->mpegq, p));
+}
- case VIDIOC_QUERYBUF:
- return videobuf_querybuf(&fh->mpegq, arg);
+static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p)
+{
+ struct cx8802_fh *fh = priv;
+ return (videobuf_dqbuf(&fh->mpegq, p,
+ file->f_flags & O_NONBLOCK));
+}
- case VIDIOC_QBUF:
- return videobuf_qbuf(&fh->mpegq, arg);
+static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+ struct cx8802_fh *fh = priv;
+ return videobuf_streamon(&fh->mpegq);
+}
- case VIDIOC_DQBUF:
- return videobuf_dqbuf(&fh->mpegq, arg,
- file->f_flags & O_NONBLOCK);
+static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+ struct cx8802_fh *fh = priv;
+ return videobuf_streamoff(&fh->mpegq);
+}
- case VIDIOC_STREAMON:
- return videobuf_streamon(&fh->mpegq);
+static int vidioc_g_mpegcomp (struct file *file, void *fh,
+ struct v4l2_mpeg_compression *f)
+{
+ printk(KERN_WARNING "VIDIOC_G_MPEGCOMP is obsolete. "
+ "Replace with VIDIOC_G_EXT_CTRLS!");
+ memcpy(f,&default_mpeg_params,sizeof(*f));
+ return 0;
+}
- case VIDIOC_STREAMOFF:
- return videobuf_streamoff(&fh->mpegq);
+static int vidioc_s_mpegcomp (struct file *file, void *fh,
+ struct v4l2_mpeg_compression *f)
+{
+ printk(KERN_WARNING "VIDIOC_S_MPEGCOMP is obsolete. "
+ "Replace with VIDIOC_S_EXT_CTRLS!");
+ return 0;
+}
- /* --- mpeg compression -------------------------------------- */
- case VIDIOC_G_MPEGCOMP:
- {
- struct v4l2_mpeg_compression *f = arg;
+static int vidioc_g_ext_ctrls (struct file *file, void *priv,
+ struct v4l2_ext_controls *f)
+{
+ struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev;
- printk(KERN_WARNING "VIDIOC_G_MPEGCOMP is obsolete. "
- "Replace with VIDIOC_G_EXT_CTRLS!");
- memcpy(f,&default_mpeg_params,sizeof(*f));
- return 0;
- }
- case VIDIOC_S_MPEGCOMP:
- printk(KERN_WARNING "VIDIOC_S_MPEGCOMP is obsolete. "
- "Replace with VIDIOC_S_EXT_CTRLS!");
- return 0;
- case VIDIOC_G_EXT_CTRLS:
- {
- struct v4l2_ext_controls *f = arg;
+ if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+ return -EINVAL;
+ return cx2341x_ext_ctrls(&dev->params, f, VIDIOC_G_EXT_CTRLS);
+}
- if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
- return -EINVAL;
- return cx2341x_ext_ctrls(&dev->params, f, cmd);
- }
- case VIDIOC_S_EXT_CTRLS:
- case VIDIOC_TRY_EXT_CTRLS:
- {
- struct v4l2_ext_controls *f = arg;
- struct cx2341x_mpeg_params p;
- int err;
-
- if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
- return -EINVAL;
- p = dev->params;
- err = cx2341x_ext_ctrls(&p, f, cmd);
- if (err == 0 && cmd == VIDIOC_S_EXT_CTRLS) {
- err = cx2341x_update(dev, blackbird_mbox_func, &dev->params, &p);
- dev->params = p;
- }
- return err;
- }
- case VIDIOC_S_FREQUENCY:
- {
- blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
- BLACKBIRD_END_NOW,
- BLACKBIRD_MPEG_CAPTURE,
- BLACKBIRD_RAW_BITS_NONE);
-
- cx88_do_ioctl(inode, file, 0, dev->core, cmd, arg, cx88_ioctl_hook);
-
- blackbird_initialize_codec(dev);
- cx88_set_scale(dev->core, dev->width, dev->height,
- fh->mpegq.field);
- return 0;
+static int vidioc_s_ext_ctrls (struct file *file, void *priv,
+ struct v4l2_ext_controls *f)
+{
+ struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev;
+ struct cx2341x_mpeg_params p;
+ int err;
+
+ if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+ return -EINVAL;
+ p = dev->params;
+ err = cx2341x_ext_ctrls(&p, f, VIDIOC_S_EXT_CTRLS);
+ if (!err) {
+ err = cx2341x_update(dev, blackbird_mbox_func, &dev->params, &p);
+ dev->params = p;
}
- case VIDIOC_LOG_STATUS:
- {
- char name[32 + 2];
-
- snprintf(name, sizeof(name), "%s/2", core->name);
- printk("%s/2: ============ START LOG STATUS ============\n",
- core->name);
- cx88_call_i2c_clients(core, VIDIOC_LOG_STATUS, NULL);
- cx2341x_log_status(&dev->params, name);
- printk("%s/2: ============= END LOG STATUS =============\n",
- core->name);
+ return err;
+}
+
+static int vidioc_try_ext_ctrls (struct file *file, void *priv,
+ struct v4l2_ext_controls *f)
+{
+ struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev;
+ struct cx2341x_mpeg_params p;
+ int err;
+
+ if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+ return -EINVAL;
+ p = dev->params;
+ err = cx2341x_ext_ctrls(&p, f, VIDIOC_TRY_EXT_CTRLS);
+
+ return err;
+}
+
+static int vidioc_s_frequency (struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+ struct cx8802_fh *fh = priv;
+ struct cx8802_dev *dev = fh->dev;
+ struct cx88_core *core = dev->core;
+
+ blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
+ BLACKBIRD_END_NOW,
+ BLACKBIRD_MPEG_CAPTURE,
+ BLACKBIRD_RAW_BITS_NONE);
+ cx88_set_freq (core,f);
+ blackbird_initialize_codec(dev);
+ cx88_set_scale(dev->core, dev->width, dev->height,
+ fh->mpegq.field);
+ return 0;
+}
+
+static int vidioc_log_status (struct file *file, void *priv)
+{
+ struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev;
+ struct cx88_core *core = dev->core;
+ char name[32 + 2];
+
+ snprintf(name, sizeof(name), "%s/2", core->name);
+ printk("%s/2: ============ START LOG STATUS ============\n",
+ core->name);
+ cx88_call_i2c_clients(core, VIDIOC_LOG_STATUS, NULL);
+ cx2341x_log_status(&dev->params, name);
+ printk("%s/2: ============= END LOG STATUS =============\n",
+ core->name);
+ return 0;
+}
+
+static int vidioc_queryctrl (struct file *file, void *priv,
+ struct v4l2_queryctrl *qctrl)
+{
+ struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev;
+
+ if (blackbird_queryctrl(dev, qctrl) == 0)
return 0;
- }
- case VIDIOC_QUERYMENU:
- return blackbird_querymenu(dev, arg);
- case VIDIOC_QUERYCTRL:
- {
- struct v4l2_queryctrl *c = arg;
- if (blackbird_queryctrl(dev, c) == 0)
- return 0;
- return cx88_do_ioctl(inode, file, 0, dev->core, cmd, arg, mpeg_do_ioctl);
- }
+ qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
+ if (unlikely(qctrl->id == 0))
+ return -EINVAL;
+ return cx8800_ctrl_query(qctrl);
+}
- default:
- return cx88_do_ioctl(inode, file, 0, dev->core, cmd, arg, cx88_ioctl_hook);
- }
+static int vidioc_enum_input (struct file *file, void *priv,
+ struct v4l2_input *i)
+{
+ struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core;
+ return cx88_enum_input (core,i);
+}
+
+static int vidioc_g_ctrl (struct file *file, void *priv,
+ struct v4l2_control *ctl)
+{
+ struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core;
+ return
+ cx88_get_control(core,ctl);
+}
+
+static int vidioc_s_ctrl (struct file *file, void *priv,
+ struct v4l2_control *ctl)
+{
+ struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core;
+ return
+ cx88_set_control(core,ctl);
+}
+
+static int vidioc_g_frequency (struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+ struct cx8802_fh *fh = priv;
+ struct cx88_core *core = fh->dev->core;
+
+ if (unlikely(UNSET == core->tuner_type))
+ return -EINVAL;
+
+ f->type = V4L2_TUNER_ANALOG_TV;
+ f->frequency = core->freq;
+ cx88_call_i2c_clients(core,VIDIOC_G_FREQUENCY,f);
+
+ return 0;
+}
+
+static int vidioc_g_input (struct file *file, void *priv, unsigned int *i)
+{
+ struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core;
+
+ *i = core->input;
+ return 0;
+}
+
+static int vidioc_s_input (struct file *file, void *priv, unsigned int i)
+{
+ struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core;
+
+ if (i >= 4)
+ return -EINVAL;
+
+ mutex_lock(&core->lock);
+ cx88_newstation(core);
+ cx88_video_mux(core,i);
+ mutex_unlock(&core->lock);
return 0;
}
-int (*cx88_ioctl_hook)(struct inode *inode, struct file *file,
- unsigned int cmd, void *arg);
-unsigned int (*cx88_ioctl_translator)(unsigned int cmd);
+static int vidioc_g_tuner (struct file *file, void *priv,
+ struct v4l2_tuner *t)
+{
+ struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core;
+ u32 reg;
+
+ if (unlikely(UNSET == core->tuner_type))
+ return -EINVAL;
+
+ strcpy(t->name, "Television");
+ t->type = V4L2_TUNER_ANALOG_TV;
+ t->capability = V4L2_TUNER_CAP_NORM;
+ t->rangehigh = 0xffffffffUL;
+
+ cx88_get_stereo(core ,t);
+ reg = cx_read(MO_DEVICE_STATUS);
+ t->signal = (reg & (1<<5)) ? 0xffff : 0x0000;
+ return 0;
+}
-static unsigned int mpeg_translate_ioctl(unsigned int cmd)
+static int vidioc_s_tuner (struct file *file, void *priv,
+ struct v4l2_tuner *t)
{
- return cmd;
+ struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core;
+
+ if (UNSET == core->tuner_type)
+ return -EINVAL;
+ if (0 != t->index)
+ return -EINVAL;
+
+ cx88_set_stereo(core, t->audmode, 1);
+ return 0;
}
-static int mpeg_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *id)
{
- cmd = cx88_ioctl_translator( cmd );
- return video_usercopy(inode, file, cmd, arg, cx88_ioctl_hook);
+ struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core;
+
+ mutex_lock(&core->lock);
+ cx88_set_tvnorm(core,*id);
+ mutex_unlock(&core->lock);
+ return 0;
}
+/* FIXME: cx88_ioctl_hook not implemented */
+
static int mpeg_open(struct inode *inode, struct file *file)
{
int minor = iminor(inode);
@@ -1051,7 +1185,7 @@ mpeg_mmap(struct file *file, struct vm_area_struct * vma)
return videobuf_mmap_mapper(&fh->mpegq, vma);
}
-static struct file_operations mpeg_fops =
+static const struct file_operations mpeg_fops =
{
.owner = THIS_MODULE,
.open = mpeg_open,
@@ -1059,17 +1193,47 @@ static struct file_operations mpeg_fops =
.read = mpeg_read,
.poll = mpeg_poll,
.mmap = mpeg_mmap,
- .ioctl = mpeg_ioctl,
+ .ioctl = video_ioctl2,
.llseek = no_llseek,
};
static struct video_device cx8802_mpeg_template =
{
- .name = "cx8802",
- .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_SCALES|VID_TYPE_MPEG_ENCODER,
- .hardware = 0,
- .fops = &mpeg_fops,
- .minor = -1,
+ .name = "cx8802",
+ .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_SCALES|VID_TYPE_MPEG_ENCODER,
+ .fops = &mpeg_fops,
+ .minor = -1,
+ .vidioc_querymenu = vidioc_querymenu,
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_enum_fmt_cap = vidioc_enum_fmt_cap,
+ .vidioc_g_fmt_cap = vidioc_g_fmt_cap,
+ .vidioc_try_fmt_cap = vidioc_try_fmt_cap,
+ .vidioc_s_fmt_cap = vidioc_s_fmt_cap,
+ .vidioc_reqbufs = vidioc_reqbufs,
+ .vidioc_querybuf = vidioc_querybuf,
+ .vidioc_qbuf = vidioc_qbuf,
+ .vidioc_dqbuf = vidioc_dqbuf,
+ .vidioc_streamon = vidioc_streamon,
+ .vidioc_streamoff = vidioc_streamoff,
+ .vidioc_g_mpegcomp = vidioc_g_mpegcomp,
+ .vidioc_s_mpegcomp = vidioc_s_mpegcomp,
+ .vidioc_g_ext_ctrls = vidioc_g_ext_ctrls,
+ .vidioc_s_ext_ctrls = vidioc_s_ext_ctrls,
+ .vidioc_try_ext_ctrls = vidioc_try_ext_ctrls,
+ .vidioc_s_frequency = vidioc_s_frequency,
+ .vidioc_log_status = vidioc_log_status,
+ .vidioc_queryctrl = vidioc_queryctrl,
+ .vidioc_enum_input = vidioc_enum_input,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ .vidioc_g_frequency = vidioc_g_frequency,
+ .vidioc_g_input = vidioc_g_input,
+ .vidioc_s_input = vidioc_s_input,
+ .vidioc_g_tuner = vidioc_g_tuner,
+ .vidioc_s_tuner = vidioc_s_tuner,
+ .vidioc_s_std = vidioc_s_std,
+ .tvnorms = CX88_NORMS,
+ .current_norm = V4L2_STD_NTSC_M,
};
/* ------------------------------------------------------------------ */
@@ -1164,7 +1328,9 @@ static int cx8802_blackbird_probe(struct cx8802_driver *drv)
cx2341x_fill_defaults(&dev->params);
dev->params.port = CX2341X_PORT_STREAMING;
- if (core->tvnorm->id & V4L2_STD_525_60) {
+ cx8802_mpeg_template.current_norm = core->tvnorm;
+
+ if (core->tvnorm & V4L2_STD_525_60) {
dev->height = 480;
} else {
dev->height = 576;
@@ -1178,6 +1344,11 @@ static int cx8802_blackbird_probe(struct cx8802_driver *drv)
blackbird_register_video(dev);
/* initial device configuration: needed ? */
+ mutex_lock(&dev->core->lock);
+// init_controls(core);
+ cx88_set_tvnorm(core,core->tvnorm);
+ cx88_video_mux(core,0);
+ mutex_unlock(&dev->core->lock);
return 0;
@@ -1212,8 +1383,6 @@ static int blackbird_init(void)
printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n",
SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
#endif
- cx88_ioctl_hook = mpeg_do_ioctl;
- cx88_ioctl_translator = mpeg_translate_ioctl;
return cx8802_register_driver(&cx8802_blackbird_driver);
}
@@ -1225,8 +1394,8 @@ static void blackbird_fini(void)
module_init(blackbird_init);
module_exit(blackbird_fini);
-EXPORT_SYMBOL(cx88_ioctl_hook);
-EXPORT_SYMBOL(cx88_ioctl_translator);
+module_param_named(video_debug,cx8802_mpeg_template.debug, int, 0644);
+MODULE_PARM_DESC(debug,"enable debug messages [video]");
/* ----------------------------------------------------------- */
/*
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
index 434b78ab37d..65e9d8096b7 100644
--- a/drivers/media/video/cx88/cx88-cards.c
+++ b/drivers/media/video/cx88/cx88-cards.c
@@ -764,6 +764,12 @@ struct cx88_board cx88_boards[] = {
.input = {{
.type = CX88_VMUX_DVB,
.vmux = 0,
+ },{
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 2,
+ },{
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
}},
.mpeg = CX88_MPEG_DVB,
},
diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c
index 18997361c75..d86813be56d 100644
--- a/drivers/media/video/cx88/cx88-core.c
+++ b/drivers/media/video/cx88/cx88-core.c
@@ -5,6 +5,11 @@
*
* (c) 2003 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
*
+ * (c) 2005-2006 Mauro Carvalho Chehab <mchehab@infradead.org>
+ * - Multituner support
+ * - video_ioctl2 conversion
+ * - PAL/M fixes
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -631,30 +636,30 @@ int cx88_reset(struct cx88_core *core)
/* ------------------------------------------------------------------ */
-static unsigned int inline norm_swidth(struct cx88_tvnorm *norm)
+static unsigned int inline norm_swidth(v4l2_std_id norm)
{
- return (norm->id & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 754 : 922;
+ return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 754 : 922;
}
-static unsigned int inline norm_hdelay(struct cx88_tvnorm *norm)
+static unsigned int inline norm_hdelay(v4l2_std_id norm)
{
- return (norm->id & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 135 : 186;
+ return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 135 : 186;
}
-static unsigned int inline norm_vdelay(struct cx88_tvnorm *norm)
+static unsigned int inline norm_vdelay(v4l2_std_id norm)
{
- return (norm->id & V4L2_STD_625_50) ? 0x24 : 0x18;
+ return (norm & V4L2_STD_625_50) ? 0x24 : 0x18;
}
-static unsigned int inline norm_fsc8(struct cx88_tvnorm *norm)
+static unsigned int inline norm_fsc8(v4l2_std_id norm)
{
- if (norm->id & V4L2_STD_PAL_M)
+ if (norm & V4L2_STD_PAL_M)
return 28604892; // 3.575611 MHz
- if (norm->id & (V4L2_STD_PAL_Nc))
+ if (norm & (V4L2_STD_PAL_Nc))
return 28656448; // 3.582056 MHz
- if (norm->id & V4L2_STD_NTSC) // All NTSC/M and variants
+ if (norm & V4L2_STD_NTSC) // All NTSC/M and variants
return 28636360; // 3.57954545 MHz +/- 10 Hz
/* SECAM have also different sub carrier for chroma,
@@ -666,20 +671,20 @@ static unsigned int inline norm_fsc8(struct cx88_tvnorm *norm)
return 35468950; // 4.43361875 MHz +/- 5 Hz
}
-static unsigned int inline norm_htotal(struct cx88_tvnorm *norm)
+static unsigned int inline norm_htotal(v4l2_std_id norm)
{
unsigned int fsc4=norm_fsc8(norm)/2;
/* returns 4*FSC / vtotal / frames per seconds */
- return (norm->id & V4L2_STD_625_50) ?
+ return (norm & V4L2_STD_625_50) ?
((fsc4+312)/625+12)/25 :
((fsc4+262)/525*1001+15000)/30000;
}
-static unsigned int inline norm_vbipack(struct cx88_tvnorm *norm)
+static unsigned int inline norm_vbipack(v4l2_std_id norm)
{
- return (norm->id & V4L2_STD_625_50) ? 511 : 400;
+ return (norm & V4L2_STD_625_50) ? 511 : 400;
}
int cx88_set_scale(struct cx88_core *core, unsigned int width, unsigned int height,
@@ -692,7 +697,7 @@ int cx88_set_scale(struct cx88_core *core, unsigned int width, unsigned int heig
dprintk(1,"set_scale: %dx%d [%s%s,%s]\n", width, height,
V4L2_FIELD_HAS_TOP(field) ? "T" : "",
V4L2_FIELD_HAS_BOTTOM(field) ? "B" : "",
- core->tvnorm->name);
+ v4l2_norm_to_name(core->tvnorm));
if (!V4L2_FIELD_HAS_BOTH(field))
height *= 2;
@@ -729,7 +734,7 @@ int cx88_set_scale(struct cx88_core *core, unsigned int width, unsigned int heig
// setup filters
value = 0;
value |= (1 << 19); // CFILT (default)
- if (core->tvnorm->id & V4L2_STD_SECAM) {
+ if (core->tvnorm & V4L2_STD_SECAM) {
value |= (1 << 15);
value |= (1 << 16);
}
@@ -826,36 +831,36 @@ int cx88_stop_audio_dma(struct cx88_core *core)
static int set_tvaudio(struct cx88_core *core)
{
- struct cx88_tvnorm *norm = core->tvnorm;
+ v4l2_std_id norm = core->tvnorm;
if (CX88_VMUX_TELEVISION != INPUT(core->input)->type)
return 0;
- if (V4L2_STD_PAL_BG & norm->id) {
+ if (V4L2_STD_PAL_BG & norm) {
core->tvaudio = WW_BG;
- } else if (V4L2_STD_PAL_DK & norm->id) {
+ } else if (V4L2_STD_PAL_DK & norm) {
core->tvaudio = WW_DK;
- } else if (V4L2_STD_PAL_I & norm->id) {
+ } else if (V4L2_STD_PAL_I & norm) {
core->tvaudio = WW_I;
- } else if (V4L2_STD_SECAM_L & norm->id) {
+ } else if (V4L2_STD_SECAM_L & norm) {
core->tvaudio = WW_L;
- } else if (V4L2_STD_SECAM_DK & norm->id) {
+ } else if (V4L2_STD_SECAM_DK & norm) {
core->tvaudio = WW_DK;
- } else if ((V4L2_STD_NTSC_M & norm->id) ||
- (V4L2_STD_PAL_M & norm->id)) {
+ } else if ((V4L2_STD_NTSC_M & norm) ||
+ (V4L2_STD_PAL_M & norm)) {
core->tvaudio = WW_BTSC;
- } else if (V4L2_STD_NTSC_M_JP & norm->id) {
+ } else if (V4L2_STD_NTSC_M_JP & norm) {
core->tvaudio = WW_EIAJ;
} else {
printk("%s/0: tvaudio support needs work for this tv norm [%s], sorry\n",
- core->name, norm->name);
+ core->name, v4l2_norm_to_name(core->tvnorm));
core->tvaudio = 0;
return 0;
}
@@ -874,7 +879,7 @@ static int set_tvaudio(struct cx88_core *core)
-int cx88_set_tvnorm(struct cx88_core *core, struct cx88_tvnorm *norm)
+int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm)
{
u32 fsc8;
u32 adc_clock;
@@ -882,6 +887,7 @@ int cx88_set_tvnorm(struct cx88_core *core, struct cx88_tvnorm *norm)
u32 step_db,step_dr;
u64 tmp64;
u32 bdelay,agcdelay,htotal;
+ u32 cxiformat, cxoformat;
core->tvnorm = norm;
fsc8 = norm_fsc8(norm);
@@ -890,23 +896,51 @@ int cx88_set_tvnorm(struct cx88_core *core, struct cx88_tvnorm *norm)
step_db = fsc8;
step_dr = fsc8;
- if (norm->id & V4L2_STD_SECAM) {
+ if (norm & V4L2_STD_NTSC_M_JP) {
+ cxiformat = VideoFormatNTSCJapan;
+ cxoformat = 0x181f0008;
+ } else if (norm & V4L2_STD_NTSC_443) {
+ cxiformat = VideoFormatNTSC443;
+ cxoformat = 0x181f0008;
+ } else if (norm & V4L2_STD_PAL_M) {
+ cxiformat = VideoFormatPALM;
+ cxoformat = 0x1c1f0008;
+ } else if (norm & V4L2_STD_PAL_N) {
+ cxiformat = VideoFormatPALN;
+ cxoformat = 0x1c1f0008;
+ } else if (norm & V4L2_STD_PAL_Nc) {
+ cxiformat = VideoFormatPALNC;
+ cxoformat = 0x1c1f0008;
+ } else if (norm & V4L2_STD_PAL_60) {
+ cxiformat = VideoFormatPAL60;
+ cxoformat = 0x181f0008;
+ } else if (norm & V4L2_STD_NTSC) {
+ cxiformat = VideoFormatNTSC;
+ cxoformat = 0x181f0008;
+ } else if (norm & V4L2_STD_SECAM) {
step_db = 4250000 * 8;
step_dr = 4406250 * 8;
+
+ cxiformat = VideoFormatSECAM;
+ cxoformat = 0x181f0008;
+ } else { /* PAL */
+ cxiformat = VideoFormatPAL;
+ cxoformat = 0x181f0008;
}
dprintk(1,"set_tvnorm: \"%s\" fsc8=%d adc=%d vdec=%d db/dr=%d/%d\n",
- norm->name, fsc8, adc_clock, vdec_clock, step_db, step_dr);
+ v4l2_norm_to_name(core->tvnorm), fsc8, adc_clock, vdec_clock,
+ step_db, step_dr);
set_pll(core,2,vdec_clock);
dprintk(1,"set_tvnorm: MO_INPUT_FORMAT 0x%08x [old=0x%08x]\n",
- norm->cxiformat, cx_read(MO_INPUT_FORMAT) & 0x0f);
- cx_andor(MO_INPUT_FORMAT, 0xf, norm->cxiformat);
+ cxiformat, cx_read(MO_INPUT_FORMAT) & 0x0f);
+ cx_andor(MO_INPUT_FORMAT, 0xf, cxiformat);
// FIXME: as-is from DScaler
dprintk(1,"set_tvnorm: MO_OUTPUT_FORMAT 0x%08x [old=0x%08x]\n",
- norm->cxoformat, cx_read(MO_OUTPUT_FORMAT));
- cx_write(MO_OUTPUT_FORMAT, norm->cxoformat);
+ cxoformat, cx_read(MO_OUTPUT_FORMAT));
+ cx_write(MO_OUTPUT_FORMAT, cxoformat);
// MO_SCONV_REG = adc clock / video dec clock * 2^17
tmp64 = adc_clock * (u64)(1 << 17);
@@ -955,7 +989,7 @@ int cx88_set_tvnorm(struct cx88_core *core, struct cx88_tvnorm *norm)
set_tvaudio(core);
// tell i2c chips
- cx88_call_i2c_clients(core,VIDIOC_S_STD,&norm->id);
+ cx88_call_i2c_clients(core,VIDIOC_S_STD,&norm);
// done
return 0;
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
index 8b203354fcc..4f556028577 100644
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ b/drivers/media/video/cx88/cx88-dvb.c
@@ -35,7 +35,7 @@
#include "mt352.h"
#include "mt352_priv.h"
-#ifdef HAVE_VP3054_I2C
+#if defined(CONFIG_VIDEO_CX88_VP3054) || defined(CONFIG_VIDEO_CX88_VP3054_MODULE)
# include "cx88-vp3054-i2c.h"
#endif
#include "zl10353.h"
@@ -200,7 +200,7 @@ static struct mt352_config dvico_fusionhdtv_dual = {
.demod_init = dvico_dual_demod_init,
};
-#ifdef HAVE_VP3054_I2C
+#if defined(CONFIG_VIDEO_CX88_VP3054) || defined(CONFIG_VIDEO_CX88_VP3054_MODULE)
static int dntv_live_dvbt_pro_demod_init(struct dvb_frontend* fe)
{
static u8 clock_config [] = { 0x89, 0x38, 0x38 };
@@ -543,7 +543,7 @@ static int dvb_register(struct cx8802_dev *dev)
}
break;
case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
-#ifdef HAVE_VP3054_I2C
+#if defined(CONFIG_VIDEO_CX88_VP3054) || defined(CONFIG_VIDEO_CX88_VP3054_MODULE)
dev->core->pll_addr = 0x61;
dev->core->pll_desc = &dvb_pll_fmd1216me;
dev->dvb.frontend = dvb_attach(mt352_attach, &dntv_live_dvbt_pro_config,
@@ -793,7 +793,7 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv)
if (!(cx88_boards[core->board].mpeg & CX88_MPEG_DVB))
goto fail_core;
-#ifdef HAVE_VP3054_I2C
+#if defined(CONFIG_VIDEO_CX88_VP3054) || defined(CONFIG_VIDEO_CX88_VP3054_MODULE)
err = vp3054_i2c_probe(dev);
if (0 != err)
goto fail_core;
@@ -822,7 +822,7 @@ static int cx8802_dvb_remove(struct cx8802_driver *drv)
/* dvb */
videobuf_dvb_unregister(&dev->dvb);
-#ifdef HAVE_VP3054_I2C
+#if defined(CONFIG_VIDEO_CX88_VP3054) || defined(CONFIG_VIDEO_CX88_VP3054_MODULE)
vp3054_i2c_remove(dev);
#endif
diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c
index 88af23a9387..9830d5c4392 100644
--- a/drivers/media/video/cx88/cx88-i2c.c
+++ b/drivers/media/video/cx88/cx88-i2c.c
@@ -145,6 +145,7 @@ void cx88_call_i2c_clients(struct cx88_core *core, unsigned int cmd, void *arg)
if (0 != core->i2c_rc)
return;
+#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE)
if ( (core->dvbdev) && (core->dvbdev->dvb.frontend) ) {
if (core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl)
core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl(core->dvbdev->dvb.frontend, 1);
@@ -154,6 +155,7 @@ void cx88_call_i2c_clients(struct cx88_core *core, unsigned int cmd, void *arg)
if (core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl)
core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl(core->dvbdev->dvb.frontend, 0);
} else
+#endif
i2c_clients_command(&core->i2c_adap, cmd, arg);
}
diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c
index 2bd84d351a1..97ef421dd09 100644
--- a/drivers/media/video/cx88/cx88-tvaudio.c
+++ b/drivers/media/video/cx88/cx88-tvaudio.c
@@ -46,7 +46,6 @@
#include <linux/pci.h>
#include <linux/signal.h>
#include <linux/ioport.h>
-#include <linux/sched.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/vmalloc.h>
@@ -798,55 +797,6 @@ void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t)
Add some code here later.
*/
-# if 0
- t->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_SAP |
- V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
- t->rxsubchans = V4L2_TUNER_SUB_MONO;
- t->audmode = V4L2_TUNER_MODE_MONO;
-
- switch (core->tvaudio) {
- case WW_BTSC:
- t->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_SAP;
- t->rxsubchans = V4L2_TUNER_SUB_STEREO;
- if (1 == pilot) {
- /* SAP */
- t->rxsubchans |= V4L2_TUNER_SUB_SAP;
- }
- break;
- case WW_A2_BG:
- case WW_A2_DK:
- case WW_A2_M:
- if (1 == pilot) {
- /* stereo */
- t->rxsubchans =
- V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
- if (0 == mode)
- t->audmode = V4L2_TUNER_MODE_STEREO;
- }
- if (2 == pilot) {
- /* dual language -- FIXME */
- t->rxsubchans =
- V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
- t->audmode = V4L2_TUNER_MODE_LANG1;
- }
- break;
- case WW_NICAM_BGDKL:
- if (0 == mode) {
- t->audmode = V4L2_TUNER_MODE_STEREO;
- t->rxsubchans |= V4L2_TUNER_SUB_STEREO;
- }
- break;
- case WW_SYSTEM_L_AM:
- if (0x0 == mode && !(cx_read(AUD_INIT) & 0x04)) {
- t->audmode = V4L2_TUNER_MODE_STEREO;
- t->rxsubchans |= V4L2_TUNER_SUB_STEREO;
- }
- break;
- default:
- /* nothing */
- break;
- }
-# endif
return;
}
diff --git a/drivers/media/video/cx88/cx88-vbi.c b/drivers/media/video/cx88/cx88-vbi.c
index aa2a6977009..86c1cf8334b 100644
--- a/drivers/media/video/cx88/cx88-vbi.c
+++ b/drivers/media/video/cx88/cx88-vbi.c
@@ -21,9 +21,11 @@ MODULE_PARM_DESC(vbi_debug,"enable debug messages [vbi]");
/* ------------------------------------------------------------------ */
-void cx8800_vbi_fmt(struct cx8800_dev *dev, struct v4l2_format *f)
+int cx8800_vbi_fmt (struct file *file, void *priv,
+ struct v4l2_format *f)
{
- memset(&f->fmt.vbi,0,sizeof(f->fmt.vbi));
+ struct cx8800_fh *fh = priv;
+ struct cx8800_dev *dev = fh->dev;
f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH;
f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
@@ -31,18 +33,19 @@ void cx8800_vbi_fmt(struct cx8800_dev *dev, struct v4l2_format *f)
f->fmt.vbi.count[0] = VBI_LINE_COUNT;
f->fmt.vbi.count[1] = VBI_LINE_COUNT;
- if (dev->core->tvnorm->id & V4L2_STD_525_60) {
+ if (dev->core->tvnorm & V4L2_STD_525_60) {
/* ntsc */
f->fmt.vbi.sampling_rate = 28636363;
f->fmt.vbi.start[0] = 10;
f->fmt.vbi.start[1] = 273;
- } else if (dev->core->tvnorm->id & V4L2_STD_625_50) {
+ } else if (dev->core->tvnorm & V4L2_STD_625_50) {
/* pal */
f->fmt.vbi.sampling_rate = 35468950;
f->fmt.vbi.start[0] = 7 -1;
f->fmt.vbi.start[1] = 319 -1;
}
+ return 0;
}
static int cx8800_start_vbi_dma(struct cx8800_dev *dev,
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c
index 8613378428f..a97be1bdc31 100644
--- a/drivers/media/video/cx88/cx88-video.c
+++ b/drivers/media/video/cx88/cx88-video.c
@@ -1,3 +1,4 @@
+
/*
*
* device driver for Conexant 2388x based TV cards
@@ -5,6 +6,11 @@
*
* (c) 2003-04 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
*
+ * (c) 2005-2006 Mauro Carvalho Chehab <mchehab@infradead.org>
+ * - Multituner support
+ * - video_ioctl2 conversion
+ * - PAL/M fixes
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -80,65 +86,6 @@ static LIST_HEAD(cx8800_devlist);
/* ------------------------------------------------------------------- */
/* static data */
-static struct cx88_tvnorm tvnorms[] = {
- {
- .name = "NTSC-M",
- .id = V4L2_STD_NTSC_M,
- .cxiformat = VideoFormatNTSC,
- .cxoformat = 0x181f0008,
- },{
- .name = "NTSC-JP",
- .id = V4L2_STD_NTSC_M_JP,
- .cxiformat = VideoFormatNTSCJapan,
- .cxoformat = 0x181f0008,
- },{
- .name = "PAL-BG",
- .id = V4L2_STD_PAL_BG,
- .cxiformat = VideoFormatPAL,
- .cxoformat = 0x181f0008,
- },{
- .name = "PAL-DK",
- .id = V4L2_STD_PAL_DK,
- .cxiformat = VideoFormatPAL,
- .cxoformat = 0x181f0008,
- },{
- .name = "PAL-I",
- .id = V4L2_STD_PAL_I,
- .cxiformat = VideoFormatPAL,
- .cxoformat = 0x181f0008,
- },{
- .name = "PAL-M",
- .id = V4L2_STD_PAL_M,
- .cxiformat = VideoFormatPALM,
- .cxoformat = 0x1c1f0008,
- },{
- .name = "PAL-N",
- .id = V4L2_STD_PAL_N,
- .cxiformat = VideoFormatPALN,
- .cxoformat = 0x1c1f0008,
- },{
- .name = "PAL-Nc",
- .id = V4L2_STD_PAL_Nc,
- .cxiformat = VideoFormatPALNC,
- .cxoformat = 0x1c1f0008,
- },{
- .name = "PAL-60",
- .id = V4L2_STD_PAL_60,
- .cxiformat = VideoFormatPAL60,
- .cxoformat = 0x181f0008,
- },{
- .name = "SECAM-L",
- .id = V4L2_STD_SECAM_L,
- .cxiformat = VideoFormatSECAM,
- .cxoformat = 0x181f0008,
- },{
- .name = "SECAM-DK",
- .id = V4L2_STD_SECAM_DK,
- .cxiformat = VideoFormatSECAM,
- .cxoformat = 0x181f0008,
- }
-};
-
static struct cx8800_fmt formats[] = {
{
.name = "8 bpp, gray",
@@ -364,14 +311,6 @@ int cx8800_ctrl_query(struct v4l2_queryctrl *qctrl)
}
EXPORT_SYMBOL(cx8800_ctrl_query);
-static int cx88_queryctrl(struct v4l2_queryctrl *qctrl)
-{
- qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
- if (qctrl->id == 0)
- return -EINVAL;
- return cx8800_ctrl_query(qctrl);
-}
-
/* ------------------------------------------------------------------- */
/* resource management */
@@ -424,8 +363,7 @@ void res_free(struct cx8800_dev *dev, struct cx8800_fh *fh, unsigned int bits)
/* ------------------------------------------------------------------ */
-/* static int video_mux(struct cx8800_dev *dev, unsigned int input) */
-static int video_mux(struct cx88_core *core, unsigned int input)
+int cx88_video_mux(struct cx88_core *core, unsigned int input)
{
/* struct cx88_core *core = dev->core; */
@@ -464,6 +402,7 @@ static int video_mux(struct cx88_core *core, unsigned int input)
}
return 0;
}
+EXPORT_SYMBOL(cx88_video_mux);
/* ------------------------------------------------------------------ */
@@ -944,19 +883,18 @@ video_mmap(struct file *file, struct vm_area_struct * vma)
}
/* ------------------------------------------------------------------ */
+/* VIDEO CTRL IOCTLS */
-/* static int get_control(struct cx8800_dev *dev, struct v4l2_control *ctl) */
-static int get_control(struct cx88_core *core, struct v4l2_control *ctl)
+int cx88_get_control (struct cx88_core *core, struct v4l2_control *ctl)
{
- /* struct cx88_core *core = dev->core; */
- struct cx88_ctrl *c = NULL;
+ struct cx88_ctrl *c = NULL;
u32 value;
int i;
for (i = 0; i < CX8800_CTLS; i++)
if (cx8800_ctls[i].v.id == ctl->id)
c = &cx8800_ctls[i];
- if (NULL == c)
+ if (unlikely(NULL == c))
return -EINVAL;
value = c->sreg ? cx_sread(c->sreg) : cx_read(c->reg);
@@ -977,20 +915,20 @@ static int get_control(struct cx88_core *core, struct v4l2_control *ctl)
value,c->mask, c->sreg ? " [shadowed]" : "");
return 0;
}
+EXPORT_SYMBOL(cx88_get_control);
-/* static int set_control(struct cx8800_dev *dev, struct v4l2_control *ctl) */
-static int set_control(struct cx88_core *core, struct v4l2_control *ctl)
+int cx88_set_control(struct cx88_core *core, struct v4l2_control *ctl)
{
- /* struct cx88_core *core = dev->core; */
struct cx88_ctrl *c = NULL;
u32 value,mask;
int i;
+
for (i = 0; i < CX8800_CTLS; i++) {
if (cx8800_ctls[i].v.id == ctl->id) {
c = &cx8800_ctls[i];
}
}
- if (NULL == c)
+ if (unlikely(NULL == c))
return -EINVAL;
if (ctl->value < c->v.minimum)
@@ -1010,7 +948,7 @@ static int set_control(struct cx88_core *core, struct v4l2_control *ctl)
value = ((ctl->value - c->off) << c->shift) & c->mask;
- if (core->tvnorm->id & V4L2_STD_SECAM) {
+ if (core->tvnorm & V4L2_STD_SECAM) {
/* For SECAM, both U and V sat should be equal */
value=value<<8|value;
} else {
@@ -1033,6 +971,7 @@ static int set_control(struct cx88_core *core, struct v4l2_control *ctl)
}
return 0;
}
+EXPORT_SYMBOL(cx88_set_control);
static void init_controls(struct cx88_core *core)
{
@@ -1042,648 +981,531 @@ static void init_controls(struct cx88_core *core)
for (i = 0; i < CX8800_CTLS; i++) {
ctrl.id=cx8800_ctls[i].v.id;
ctrl.value=cx8800_ctls[i].v.default_value;
- set_control(core, &ctrl);
+
+ cx88_set_control(core, &ctrl);
}
}
/* ------------------------------------------------------------------ */
+/* VIDEO IOCTLS */
-static int cx8800_g_fmt(struct cx8800_dev *dev, struct cx8800_fh *fh,
+static int vidioc_g_fmt_cap (struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct cx8800_fh *fh = priv;
+
+ f->fmt.pix.width = fh->width;
+ f->fmt.pix.height = fh->height;
+ f->fmt.pix.field = fh->vidq.field;
+ f->fmt.pix.pixelformat = fh->fmt->fourcc;
+ f->fmt.pix.bytesperline =
+ (f->fmt.pix.width * fh->fmt->depth) >> 3;
+ f->fmt.pix.sizeimage =
+ f->fmt.pix.height * f->fmt.pix.bytesperline;
+ return 0;
+}
+
+static int vidioc_try_fmt_cap (struct file *file, void *priv,
struct v4l2_format *f)
{
- switch (f->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- memset(&f->fmt.pix,0,sizeof(f->fmt.pix));
- f->fmt.pix.width = fh->width;
- f->fmt.pix.height = fh->height;
- f->fmt.pix.field = fh->vidq.field;
- f->fmt.pix.pixelformat = fh->fmt->fourcc;
- f->fmt.pix.bytesperline =
- (f->fmt.pix.width * fh->fmt->depth) >> 3;
- f->fmt.pix.sizeimage =
- f->fmt.pix.height * f->fmt.pix.bytesperline;
- return 0;
- case V4L2_BUF_TYPE_VBI_CAPTURE:
- cx8800_vbi_fmt(dev, f);
- return 0;
+ struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core;
+ struct cx8800_fmt *fmt;
+ enum v4l2_field field;
+ unsigned int maxw, maxh;
+
+ fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+ if (NULL == fmt)
+ return -EINVAL;
+
+ field = f->fmt.pix.field;
+ maxw = norm_maxw(core->tvnorm);
+ maxh = norm_maxh(core->tvnorm);
+
+ if (V4L2_FIELD_ANY == field) {
+ field = (f->fmt.pix.height > maxh/2)
+ ? V4L2_FIELD_INTERLACED
+ : V4L2_FIELD_BOTTOM;
+ }
+
+ switch (field) {
+ case V4L2_FIELD_TOP:
+ case V4L2_FIELD_BOTTOM:
+ maxh = maxh / 2;
+ break;
+ case V4L2_FIELD_INTERLACED:
+ break;
default:
return -EINVAL;
}
+
+ f->fmt.pix.field = field;
+ if (f->fmt.pix.height < 32)
+ f->fmt.pix.height = 32;
+ if (f->fmt.pix.height > maxh)
+ f->fmt.pix.height = maxh;
+ if (f->fmt.pix.width < 48)
+ f->fmt.pix.width = 48;
+ if (f->fmt.pix.width > maxw)
+ f->fmt.pix.width = maxw;
+ f->fmt.pix.width &= ~0x03;
+ f->fmt.pix.bytesperline =
+ (f->fmt.pix.width * fmt->depth) >> 3;
+ f->fmt.pix.sizeimage =
+ f->fmt.pix.height * f->fmt.pix.bytesperline;
+
+ return 0;
}
-static int cx8800_try_fmt(struct cx8800_dev *dev, struct cx8800_fh *fh,
- struct v4l2_format *f)
+static int vidioc_s_fmt_cap (struct file *file, void *priv,
+ struct v4l2_format *f)
{
- struct cx88_core *core = dev->core;
+ struct cx8800_fh *fh = priv;
+ int err = vidioc_try_fmt_cap (file,priv,f);
- switch (f->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- {
- struct cx8800_fmt *fmt;
- enum v4l2_field field;
- unsigned int maxw, maxh;
-
- fmt = format_by_fourcc(f->fmt.pix.pixelformat);
- if (NULL == fmt)
- return -EINVAL;
-
- field = f->fmt.pix.field;
- maxw = norm_maxw(core->tvnorm);
- maxh = norm_maxh(core->tvnorm);
-
- if (V4L2_FIELD_ANY == field) {
- field = (f->fmt.pix.height > maxh/2)
- ? V4L2_FIELD_INTERLACED
- : V4L2_FIELD_BOTTOM;
- }
+ if (0 != err)
+ return err;
+ fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+ fh->width = f->fmt.pix.width;
+ fh->height = f->fmt.pix.height;
+ fh->vidq.field = f->fmt.pix.field;
+ return 0;
+}
- switch (field) {
- case V4L2_FIELD_TOP:
- case V4L2_FIELD_BOTTOM:
- maxh = maxh / 2;
- break;
- case V4L2_FIELD_INTERLACED:
- break;
- default:
- return -EINVAL;
- }
+static int vidioc_querycap (struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct cx8800_dev *dev = ((struct cx8800_fh *)priv)->dev;
+ struct cx88_core *core = dev->core;
- f->fmt.pix.field = field;
- if (f->fmt.pix.height < 32)
- f->fmt.pix.height = 32;
- if (f->fmt.pix.height > maxh)
- f->fmt.pix.height = maxh;
- if (f->fmt.pix.width < 48)
- f->fmt.pix.width = 48;
- if (f->fmt.pix.width > maxw)
- f->fmt.pix.width = maxw;
- f->fmt.pix.width &= ~0x03;
- f->fmt.pix.bytesperline =
- (f->fmt.pix.width * fmt->depth) >> 3;
- f->fmt.pix.sizeimage =
- f->fmt.pix.height * f->fmt.pix.bytesperline;
+ strcpy(cap->driver, "cx8800");
+ strlcpy(cap->card, cx88_boards[core->board].name,
+ sizeof(cap->card));
+ sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
+ cap->version = CX88_VERSION_CODE;
+ cap->capabilities =
+ V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING |
+ V4L2_CAP_VBI_CAPTURE;
+ if (UNSET != core->tuner_type)
+ cap->capabilities |= V4L2_CAP_TUNER;
+ return 0;
+}
- return 0;
- }
- case V4L2_BUF_TYPE_VBI_CAPTURE:
- cx8800_vbi_fmt(dev, f);
- return 0;
- default:
+static int vidioc_enum_fmt_cap (struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ if (unlikely(f->index >= ARRAY_SIZE(formats)))
return -EINVAL;
- }
+
+ strlcpy(f->description,formats[f->index].name,sizeof(f->description));
+ f->pixelformat = formats[f->index].fourcc;
+
+ return 0;
}
-static int cx8800_s_fmt(struct cx8800_dev *dev, struct cx8800_fh *fh,
- struct v4l2_format *f)
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+static int vidiocgmbuf (struct file *file, void *priv, struct video_mbuf *mbuf)
{
+ struct cx8800_fh *fh = priv;
+ struct videobuf_queue *q;
+ struct v4l2_requestbuffers req;
+ unsigned int i;
int err;
- switch (f->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- err = cx8800_try_fmt(dev,fh,f);
- if (0 != err)
- return err;
+ q = get_queue(fh);
+ memset(&req,0,sizeof(req));
+ req.type = q->type;
+ req.count = 8;
+ req.memory = V4L2_MEMORY_MMAP;
+ err = videobuf_reqbufs(q,&req);
+ if (err < 0)
+ return err;
- fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
- fh->width = f->fmt.pix.width;
- fh->height = f->fmt.pix.height;
- fh->vidq.field = f->fmt.pix.field;
- return 0;
- case V4L2_BUF_TYPE_VBI_CAPTURE:
- cx8800_vbi_fmt(dev, f);
- return 0;
- default:
- return -EINVAL;
+ mbuf->frames = req.count;
+ mbuf->size = 0;
+ for (i = 0; i < mbuf->frames; i++) {
+ mbuf->offsets[i] = q->bufs[i]->boff;
+ mbuf->size += q->bufs[i]->bsize;
}
+ return 0;
}
+#endif
-/*
- * This function is _not_ called directly, but from
- * video_generic_ioctl (and maybe others). userspace
- * copying is done already, arg is a kernel pointer.
- */
-static int video_do_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, void *arg)
+static int vidioc_reqbufs (struct file *file, void *priv, struct v4l2_requestbuffers *p)
+{
+ struct cx8800_fh *fh = priv;
+ return (videobuf_reqbufs(get_queue(fh), p));
+}
+
+static int vidioc_querybuf (struct file *file, void *priv, struct v4l2_buffer *p)
+{
+ struct cx8800_fh *fh = priv;
+ return (videobuf_querybuf(get_queue(fh), p));
+}
+
+static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *p)
+{
+ struct cx8800_fh *fh = priv;
+ return (videobuf_qbuf(get_queue(fh), p));
+}
+
+static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p)
+{
+ struct cx8800_fh *fh = priv;
+ return (videobuf_dqbuf(get_queue(fh), p,
+ file->f_flags & O_NONBLOCK));
+}
+
+static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
{
- struct cx8800_fh *fh = file->private_data;
+ struct cx8800_fh *fh = priv;
struct cx8800_dev *dev = fh->dev;
- struct cx88_core *core = dev->core;
- int err;
- if (video_debug > 1)
- v4l_print_ioctl(core->name,cmd);
- switch (cmd) {
+ if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE))
+ return -EINVAL;
+ if (unlikely(i != fh->type))
+ return -EINVAL;
- /* --- capabilities ------------------------------------------ */
- case VIDIOC_QUERYCAP:
- {
- struct v4l2_capability *cap = arg;
-
- memset(cap,0,sizeof(*cap));
- strcpy(cap->driver, "cx8800");
- strlcpy(cap->card, cx88_boards[core->board].name,
- sizeof(cap->card));
- sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
- cap->version = CX88_VERSION_CODE;
- cap->capabilities =
- V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_READWRITE |
- V4L2_CAP_STREAMING |
- V4L2_CAP_VBI_CAPTURE |
- 0;
- if (UNSET != core->tuner_type)
- cap->capabilities |= V4L2_CAP_TUNER;
- return 0;
- }
+ if (unlikely(!res_get(dev,fh,get_ressource(fh))))
+ return -EBUSY;
+ return videobuf_streamon(get_queue(fh));
+}
- /* --- capture ioctls ---------------------------------------- */
- case VIDIOC_ENUM_FMT:
- {
- struct v4l2_fmtdesc *f = arg;
- enum v4l2_buf_type type;
- unsigned int index;
-
- index = f->index;
- type = f->type;
- switch (type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- if (index >= ARRAY_SIZE(formats))
- return -EINVAL;
- memset(f,0,sizeof(*f));
- f->index = index;
- f->type = type;
- strlcpy(f->description,formats[index].name,sizeof(f->description));
- f->pixelformat = formats[index].fourcc;
- break;
- default:
- return -EINVAL;
- }
- return 0;
- }
- case VIDIOC_G_FMT:
- {
- struct v4l2_format *f = arg;
- return cx8800_g_fmt(dev,fh,f);
- }
- case VIDIOC_S_FMT:
- {
- struct v4l2_format *f = arg;
- return cx8800_s_fmt(dev,fh,f);
- }
- case VIDIOC_TRY_FMT:
- {
- struct v4l2_format *f = arg;
- return cx8800_try_fmt(dev,fh,f);
- }
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- /* --- streaming capture ------------------------------------- */
- case VIDIOCGMBUF:
- {
- struct video_mbuf *mbuf = arg;
- struct videobuf_queue *q;
- struct v4l2_requestbuffers req;
- unsigned int i;
-
- q = get_queue(fh);
- memset(&req,0,sizeof(req));
- req.type = q->type;
- req.count = 8;
- req.memory = V4L2_MEMORY_MMAP;
- err = videobuf_reqbufs(q,&req);
- if (err < 0)
- return err;
- memset(mbuf,0,sizeof(*mbuf));
- mbuf->frames = req.count;
- mbuf->size = 0;
- for (i = 0; i < mbuf->frames; i++) {
- mbuf->offsets[i] = q->bufs[i]->boff;
- mbuf->size += q->bufs[i]->bsize;
- }
- return 0;
- }
-#endif
- case VIDIOC_REQBUFS:
- return videobuf_reqbufs(get_queue(fh), arg);
+static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+ struct cx8800_fh *fh = priv;
+ struct cx8800_dev *dev = fh->dev;
+ int err, res;
- case VIDIOC_QUERYBUF:
- return videobuf_querybuf(get_queue(fh), arg);
+ if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ if (i != fh->type)
+ return -EINVAL;
- case VIDIOC_QBUF:
- return videobuf_qbuf(get_queue(fh), arg);
+ res = get_ressource(fh);
+ err = videobuf_streamoff(get_queue(fh));
+ if (err < 0)
+ return err;
+ res_free(dev,fh,res);
+ return 0;
+}
- case VIDIOC_DQBUF:
- return videobuf_dqbuf(get_queue(fh), arg,
- file->f_flags & O_NONBLOCK);
+static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *tvnorms)
+{
+ struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core;
- case VIDIOC_STREAMON:
- {
- int res = get_ressource(fh);
+ mutex_lock(&core->lock);
+ cx88_set_tvnorm(core,*tvnorms);
+ mutex_unlock(&core->lock);
- if (!res_get(dev,fh,res))
- return -EBUSY;
- return videobuf_streamon(get_queue(fh));
- }
- case VIDIOC_STREAMOFF:
- {
- int res = get_ressource(fh);
+ return 0;
+}
- err = videobuf_streamoff(get_queue(fh));
- if (err < 0)
- return err;
- res_free(dev,fh,res);
- return 0;
- }
- default:
- return cx88_do_ioctl( inode, file, fh->radio, core, cmd, arg, video_do_ioctl );
- }
+/* only one input in this sample driver */
+int cx88_enum_input (struct cx88_core *core,struct v4l2_input *i)
+{
+ static const char *iname[] = {
+ [ CX88_VMUX_COMPOSITE1 ] = "Composite1",
+ [ CX88_VMUX_COMPOSITE2 ] = "Composite2",
+ [ CX88_VMUX_COMPOSITE3 ] = "Composite3",
+ [ CX88_VMUX_COMPOSITE4 ] = "Composite4",
+ [ CX88_VMUX_SVIDEO ] = "S-Video",
+ [ CX88_VMUX_TELEVISION ] = "Television",
+ [ CX88_VMUX_CABLE ] = "Cable TV",
+ [ CX88_VMUX_DVB ] = "DVB",
+ [ CX88_VMUX_DEBUG ] = "for debug only",
+ };
+ unsigned int n;
+
+ n = i->index;
+ if (n >= 4)
+ return -EINVAL;
+ if (0 == INPUT(n)->type)
+ return -EINVAL;
+ memset(i,0,sizeof(*i));
+ i->index = n;
+ i->type = V4L2_INPUT_TYPE_CAMERA;
+ strcpy(i->name,iname[INPUT(n)->type]);
+ if ((CX88_VMUX_TELEVISION == INPUT(n)->type) ||
+ (CX88_VMUX_CABLE == INPUT(n)->type))
+ i->type = V4L2_INPUT_TYPE_TUNER;
+ i->std = CX88_NORMS;
return 0;
}
+EXPORT_SYMBOL(cx88_enum_input);
-int cx88_do_ioctl(struct inode *inode, struct file *file, int radio,
- struct cx88_core *core, unsigned int cmd, void *arg, v4l2_kioctl driver_ioctl)
+static int vidioc_enum_input (struct file *file, void *priv,
+ struct v4l2_input *i)
{
- int err;
+ struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core;
+ return cx88_enum_input (core,i);
+}
- if (video_debug) {
- if (video_debug > 1) {
- if (_IOC_DIR(cmd) & _IOC_WRITE)
- v4l_printk_ioctl_arg("cx88(w)",cmd, arg);
- else if (!_IOC_DIR(cmd) & _IOC_READ) {
- v4l_print_ioctl("cx88", cmd);
- }
- } else
- v4l_print_ioctl(core->name,cmd);
-
- }
-
- switch (cmd) {
- /* ---------- tv norms ---------- */
- case VIDIOC_ENUMSTD:
- {
- struct v4l2_standard *e = arg;
- unsigned int i;
-
- i = e->index;
- if (i >= ARRAY_SIZE(tvnorms))
- return -EINVAL;
- err = v4l2_video_std_construct(e, tvnorms[e->index].id,
- tvnorms[e->index].name);
- e->index = i;
- if (err < 0)
- return err;
- return 0;
- }
- case VIDIOC_G_STD:
- {
- v4l2_std_id *id = arg;
+static int vidioc_g_input (struct file *file, void *priv, unsigned int *i)
+{
+ struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core;
- *id = core->tvnorm->id;
- return 0;
- }
- case VIDIOC_S_STD:
- {
- v4l2_std_id *id = arg;
- unsigned int i;
+ *i = core->input;
+ return 0;
+}
- for(i = 0; i < ARRAY_SIZE(tvnorms); i++)
- if (*id & tvnorms[i].id)
- break;
- if (i == ARRAY_SIZE(tvnorms))
- return -EINVAL;
+static int vidioc_s_input (struct file *file, void *priv, unsigned int i)
+{
+ struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core;
- mutex_lock(&core->lock);
- cx88_set_tvnorm(core,&tvnorms[i]);
- mutex_unlock(&core->lock);
- return 0;
- }
+ if (i >= 4)
+ return -EINVAL;
- /* ------ input switching ---------- */
- case VIDIOC_ENUMINPUT:
- {
- static const char *iname[] = {
- [ CX88_VMUX_COMPOSITE1 ] = "Composite1",
- [ CX88_VMUX_COMPOSITE2 ] = "Composite2",
- [ CX88_VMUX_COMPOSITE3 ] = "Composite3",
- [ CX88_VMUX_COMPOSITE4 ] = "Composite4",
- [ CX88_VMUX_SVIDEO ] = "S-Video",
- [ CX88_VMUX_TELEVISION ] = "Television",
- [ CX88_VMUX_CABLE ] = "Cable TV",
- [ CX88_VMUX_DVB ] = "DVB",
- [ CX88_VMUX_DEBUG ] = "for debug only",
- };
- struct v4l2_input *i = arg;
- unsigned int n;
-
- n = i->index;
- if (n >= 4)
- return -EINVAL;
- if (0 == INPUT(n)->type)
- return -EINVAL;
- memset(i,0,sizeof(*i));
- i->index = n;
- i->type = V4L2_INPUT_TYPE_CAMERA;
- strcpy(i->name,iname[INPUT(n)->type]);
- if ((CX88_VMUX_TELEVISION == INPUT(n)->type) ||
- (CX88_VMUX_CABLE == INPUT(n)->type))
- i->type = V4L2_INPUT_TYPE_TUNER;
- for (n = 0; n < ARRAY_SIZE(tvnorms); n++)
- i->std |= tvnorms[n].id;
- return 0;
- }
- case VIDIOC_G_INPUT:
- {
- unsigned int *i = arg;
+ mutex_lock(&core->lock);
+ cx88_newstation(core);
+ cx88_video_mux(core,i);
+ mutex_unlock(&core->lock);
+ return 0;
+}
- *i = core->input;
- return 0;
- }
- case VIDIOC_S_INPUT:
- {
- unsigned int *i = arg;
- if (*i >= 4)
- return -EINVAL;
- mutex_lock(&core->lock);
- cx88_newstation(core);
- video_mux(core,*i);
- mutex_unlock(&core->lock);
- return 0;
- }
+static int vidioc_queryctrl (struct file *file, void *priv,
+ struct v4l2_queryctrl *qctrl)
+{
+ qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
+ if (unlikely(qctrl->id == 0))
+ return -EINVAL;
+ return cx8800_ctrl_query(qctrl);
+}
+static int vidioc_g_ctrl (struct file *file, void *priv,
+ struct v4l2_control *ctl)
+{
+ struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core;
+ return
+ cx88_get_control(core,ctl);
+}
- /* --- controls ---------------------------------------------- */
- case VIDIOC_QUERYCTRL:
- {
- struct v4l2_queryctrl *c = arg;
+static int vidioc_s_ctrl (struct file *file, void *priv,
+ struct v4l2_control *ctl)
+{
+ struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core;
+ return
+ cx88_set_control(core,ctl);
+}
- return cx88_queryctrl(c);
- }
- case VIDIOC_G_CTRL:
- return get_control(core,arg);
- case VIDIOC_S_CTRL:
- return set_control(core,arg);
+static int vidioc_g_tuner (struct file *file, void *priv,
+ struct v4l2_tuner *t)
+{
+ struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core;
+ u32 reg;
- /* --- tuner ioctls ------------------------------------------ */
- case VIDIOC_G_TUNER:
- {
- struct v4l2_tuner *t = arg;
- u32 reg;
-
- if (UNSET == core->tuner_type)
- return -EINVAL;
- if (0 != t->index)
- return -EINVAL;
-
- memset(t,0,sizeof(*t));
- strcpy(t->name, "Television");
- t->type = V4L2_TUNER_ANALOG_TV;
- t->capability = V4L2_TUNER_CAP_NORM;
- t->rangehigh = 0xffffffffUL;
-
- cx88_get_stereo(core ,t);
- reg = cx_read(MO_DEVICE_STATUS);
- t->signal = (reg & (1<<5)) ? 0xffff : 0x0000;
- return 0;
- }
- case VIDIOC_S_TUNER:
- {
- struct v4l2_tuner *t = arg;
+ if (unlikely(UNSET == core->tuner_type))
+ return -EINVAL;
+ if (0 != t->index)
+ return -EINVAL;
- if (UNSET == core->tuner_type)
- return -EINVAL;
- if (0 != t->index)
- return -EINVAL;
- cx88_set_stereo(core, t->audmode, 1);
- return 0;
- }
- case VIDIOC_G_FREQUENCY:
- {
- struct v4l2_frequency *f = arg;
+ strcpy(t->name, "Television");
+ t->type = V4L2_TUNER_ANALOG_TV;
+ t->capability = V4L2_TUNER_CAP_NORM;
+ t->rangehigh = 0xffffffffUL;
- memset(f,0,sizeof(*f));
+ cx88_get_stereo(core ,t);
+ reg = cx_read(MO_DEVICE_STATUS);
+ t->signal = (reg & (1<<5)) ? 0xffff : 0x0000;
+ return 0;
+}
- if (UNSET == core->tuner_type)
- return -EINVAL;
+static int vidioc_s_tuner (struct file *file, void *priv,
+ struct v4l2_tuner *t)
+{
+ struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core;
- /* f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; */
- f->type = radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
- f->frequency = core->freq;
+ if (UNSET == core->tuner_type)
+ return -EINVAL;
+ if (0 != t->index)
+ return -EINVAL;
- cx88_call_i2c_clients(core,VIDIOC_G_FREQUENCY,f);
+ cx88_set_stereo(core, t->audmode, 1);
+ return 0;
+}
- return 0;
- }
- case VIDIOC_S_FREQUENCY:
- {
- struct v4l2_frequency *f = arg;
-
- if (UNSET == core->tuner_type)
- return -EINVAL;
- if (f->tuner != 0)
- return -EINVAL;
- if (0 == radio && f->type != V4L2_TUNER_ANALOG_TV)
- return -EINVAL;
- if (1 == radio && f->type != V4L2_TUNER_RADIO)
- return -EINVAL;
- mutex_lock(&core->lock);
- core->freq = f->frequency;
- cx88_newstation(core);
- cx88_call_i2c_clients(core,VIDIOC_S_FREQUENCY,f);
-
- /* When changing channels it is required to reset TVAUDIO */
- msleep (10);
- cx88_set_tvaudio(core);
+static int vidioc_g_frequency (struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+ struct cx8800_fh *fh = priv;
+ struct cx88_core *core = fh->dev->core;
- mutex_unlock(&core->lock);
- return 0;
- }
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- /* ioctls to allow direct acces to the cx2388x registers */
- case VIDIOC_INT_G_REGISTER:
- {
- struct v4l2_register *reg = arg;
+ if (unlikely(UNSET == core->tuner_type))
+ return -EINVAL;
- if (reg->i2c_id != 0)
- return -EINVAL;
- /* cx2388x has a 24-bit register space */
- reg->val = cx_read(reg->reg&0xffffff);
- return 0;
- }
- case VIDIOC_INT_S_REGISTER:
- {
- struct v4l2_register *reg = arg;
+ /* f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; */
+ f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
+ f->frequency = core->freq;
- if (reg->i2c_id != 0)
- return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- cx_write(reg->reg&0xffffff, reg->val);
- return 0;
- }
-#endif
+ cx88_call_i2c_clients(core,VIDIOC_G_FREQUENCY,f);
- default:
- return v4l_compat_translate_ioctl(inode,file,cmd,arg,
- driver_ioctl);
- }
return 0;
}
-static int video_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+int cx88_set_freq (struct cx88_core *core,
+ struct v4l2_frequency *f)
{
- int retval;
+ if (unlikely(UNSET == core->tuner_type))
+ return -EINVAL;
+ if (unlikely(f->tuner != 0))
+ return -EINVAL;
- retval=video_usercopy(inode, file, cmd, arg, video_do_ioctl);
+ mutex_lock(&core->lock);
+ core->freq = f->frequency;
+ cx88_newstation(core);
+ cx88_call_i2c_clients(core,VIDIOC_S_FREQUENCY,f);
+
+ /* When changing channels it is required to reset TVAUDIO */
+ msleep (10);
+ cx88_set_tvaudio(core);
- if (video_debug > 1) {
- if (retval < 0) {
- v4l_print_ioctl("cx88(err)", cmd);
- printk(KERN_DEBUG "cx88(err): errcode=%d\n",retval);
- } else if (_IOC_DIR(cmd) & _IOC_READ)
- v4l_printk_ioctl_arg("cx88(r)",cmd, (void *)arg);
- }
+ mutex_unlock(&core->lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(cx88_set_freq);
+
+static int vidioc_s_frequency (struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+ struct cx8800_fh *fh = priv;
+ struct cx88_core *core = fh->dev->core;
- return retval;
+ if (unlikely(0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV))
+ return -EINVAL;
+ if (unlikely(1 == fh->radio && f->type != V4L2_TUNER_RADIO))
+ return -EINVAL;
+
+ return
+ cx88_set_freq (core,f);
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int vidioc_g_register (struct file *file, void *fh,
+ struct v4l2_register *reg)
+{
+ struct cx88_core *core = ((struct cx8800_fh*)fh)->dev->core;
+
+ if (reg->i2c_id != 0)
+ return -EINVAL;
+ /* cx2388x has a 24-bit register space */
+ reg->val = cx_read(reg->reg&0xffffff);
+ return 0;
}
+static int vidioc_s_register (struct file *file, void *fh,
+ struct v4l2_register *reg)
+{
+ struct cx88_core *core = ((struct cx8800_fh*)fh)->dev->core;
+
+ if (reg->i2c_id != 0)
+ return -EINVAL;
+ cx_write(reg->reg&0xffffff, reg->val);
+ return 0;
+}
+#endif
+
+/* ----------------------------------------------------------- */
+/* RADIO ESPECIFIC IOCTLS */
/* ----------------------------------------------------------- */
-static int radio_do_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, void *arg)
+static int radio_querycap (struct file *file, void *priv,
+ struct v4l2_capability *cap)
{
- struct cx8800_fh *fh = file->private_data;
- struct cx8800_dev *dev = fh->dev;
+ struct cx8800_dev *dev = ((struct cx8800_fh *)priv)->dev;
struct cx88_core *core = dev->core;
- if (video_debug > 1)
- v4l_print_ioctl(core->name,cmd);
-
- switch (cmd) {
- case VIDIOC_QUERYCAP:
- {
- struct v4l2_capability *cap = arg;
-
- memset(cap,0,sizeof(*cap));
- strcpy(cap->driver, "cx8800");
- strlcpy(cap->card, cx88_boards[core->board].name,
- sizeof(cap->card));
- sprintf(cap->bus_info,"PCI:%s", pci_name(dev->pci));
- cap->version = CX88_VERSION_CODE;
- cap->capabilities = V4L2_CAP_TUNER;
- return 0;
- }
- case VIDIOC_G_TUNER:
- {
- struct v4l2_tuner *t = arg;
+ strcpy(cap->driver, "cx8800");
+ strlcpy(cap->card, cx88_boards[core->board].name,
+ sizeof(cap->card));
+ sprintf(cap->bus_info,"PCI:%s", pci_name(dev->pci));
+ cap->version = CX88_VERSION_CODE;
+ cap->capabilities = V4L2_CAP_TUNER;
+ return 0;
+}
- if (t->index > 0)
- return -EINVAL;
+static int radio_g_tuner (struct file *file, void *priv,
+ struct v4l2_tuner *t)
+{
+ struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core;
- memset(t,0,sizeof(*t));
- strcpy(t->name, "Radio");
- t->type = V4L2_TUNER_RADIO;
+ if (unlikely(t->index > 0))
+ return -EINVAL;
- cx88_call_i2c_clients(core,VIDIOC_G_TUNER,t);
- return 0;
- }
- case VIDIOC_ENUMINPUT:
- {
- struct v4l2_input *i = arg;
+ strcpy(t->name, "Radio");
+ t->type = V4L2_TUNER_RADIO;
- if (i->index != 0)
- return -EINVAL;
- strcpy(i->name,"Radio");
- i->type = V4L2_INPUT_TYPE_TUNER;
- return 0;
- }
- case VIDIOC_G_INPUT:
- {
- int *i = arg;
- *i = 0;
- return 0;
- }
- case VIDIOC_G_AUDIO:
- {
- struct v4l2_audio *a = arg;
+ cx88_call_i2c_clients(core,VIDIOC_G_TUNER,t);
+ return 0;
+}
- memset(a,0,sizeof(*a));
- strcpy(a->name,"Radio");
- return 0;
- }
- case VIDIOC_G_STD:
- {
- v4l2_std_id *id = arg;
- *id = 0;
- return 0;
- }
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- case VIDIOCSTUNER:
- {
- struct video_tuner *v = arg;
+static int radio_enum_input (struct file *file, void *priv,
+ struct v4l2_input *i)
+{
+ if (i->index != 0)
+ return -EINVAL;
+ strcpy(i->name,"Radio");
+ i->type = V4L2_INPUT_TYPE_TUNER;
- if (v->tuner) /* Only tuner 0 */
- return -EINVAL;
+ return 0;
+}
- cx88_call_i2c_clients(core,VIDIOCSTUNER,v);
- return 0;
- }
-#endif
- case VIDIOC_S_TUNER:
- {
- struct v4l2_tuner *t = arg;
+static int radio_g_audio (struct file *file, void *priv, struct v4l2_audio *a)
+{
+ if (unlikely(a->index))
+ return -EINVAL;
- if (0 != t->index)
- return -EINVAL;
+ memset(a,0,sizeof(*a));
+ strcpy(a->name,"Radio");
+ return 0;
+}
- cx88_call_i2c_clients(core,VIDIOC_S_TUNER,t);
+/* FIXME: Should add a standard for radio */
- return 0;
- }
+static int radio_s_tuner (struct file *file, void *priv,
+ struct v4l2_tuner *t)
+{
+ struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core;
- case VIDIOC_S_AUDIO:
- case VIDIOC_S_INPUT:
- case VIDIOC_S_STD:
- return 0;
+ if (0 != t->index)
+ return -EINVAL;
- case VIDIOC_QUERYCTRL:
- {
- struct v4l2_queryctrl *c = arg;
- int i;
-
- if (c->id < V4L2_CID_BASE ||
- c->id >= V4L2_CID_LASTP1)
- return -EINVAL;
- if (c->id == V4L2_CID_AUDIO_MUTE) {
- for (i = 0; i < CX8800_CTLS; i++)
- if (cx8800_ctls[i].v.id == c->id)
- break;
- *c = cx8800_ctls[i].v;
- } else
- *c = no_ctl;
- return 0;
- }
+ cx88_call_i2c_clients(core,VIDIOC_S_TUNER,t);
+ return 0;
+}
- case VIDIOC_G_CTRL:
- case VIDIOC_S_CTRL:
- case VIDIOC_G_FREQUENCY:
- case VIDIOC_S_FREQUENCY:
- return video_do_ioctl(inode,file,cmd,arg);
+static int radio_s_audio (struct file *file, void *fh,
+ struct v4l2_audio *a)
+{
+ return 0;
+}
- default:
- return v4l_compat_translate_ioctl(inode,file,cmd,arg,
- radio_do_ioctl);
- }
+static int radio_s_input (struct file *file, void *fh, unsigned int i)
+{
return 0;
-};
+}
-static int radio_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+static int radio_queryctrl (struct file *file, void *priv,
+ struct v4l2_queryctrl *c)
{
- return video_usercopy(inode, file, cmd, arg, radio_do_ioctl);
-};
+ int i;
+
+ if (c->id < V4L2_CID_BASE ||
+ c->id >= V4L2_CID_LASTP1)
+ return -EINVAL;
+ if (c->id == V4L2_CID_AUDIO_MUTE) {
+ for (i = 0; i < CX8800_CTLS; i++)
+ if (cx8800_ctls[i].v.id == c->id)
+ break;
+ *c = cx8800_ctls[i].v;
+ } else
+ *c = no_ctl;
+ return 0;
+}
/* ----------------------------------------------------------- */
@@ -1808,7 +1630,7 @@ static irqreturn_t cx8800_irq(int irq, void *dev_id)
/* ----------------------------------------------------------- */
/* exported stuff */
-static struct file_operations video_fops =
+static const struct file_operations video_fops =
{
.owner = THIS_MODULE,
.open = video_open,
@@ -1816,46 +1638,83 @@ static struct file_operations video_fops =
.read = video_read,
.poll = video_poll,
.mmap = video_mmap,
- .ioctl = video_ioctl,
+ .ioctl = video_ioctl2,
.compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek,
};
+static struct video_device cx8800_vbi_template;
static struct video_device cx8800_video_template =
{
- .name = "cx8800-video",
- .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_SCALES,
- .hardware = 0,
- .fops = &video_fops,
- .minor = -1,
-};
-
-static struct video_device cx8800_vbi_template =
-{
- .name = "cx8800-vbi",
- .type = VID_TYPE_TELETEXT|VID_TYPE_TUNER,
- .hardware = 0,
- .fops = &video_fops,
- .minor = -1,
+ .name = "cx8800-video",
+ .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_SCALES,
+ .fops = &video_fops,
+ .minor = -1,
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_enum_fmt_cap = vidioc_enum_fmt_cap,
+ .vidioc_g_fmt_cap = vidioc_g_fmt_cap,
+ .vidioc_try_fmt_cap = vidioc_try_fmt_cap,
+ .vidioc_s_fmt_cap = vidioc_s_fmt_cap,
+ .vidioc_g_fmt_vbi = cx8800_vbi_fmt,
+ .vidioc_try_fmt_vbi = cx8800_vbi_fmt,
+ .vidioc_s_fmt_vbi = cx8800_vbi_fmt,
+ .vidioc_reqbufs = vidioc_reqbufs,
+ .vidioc_querybuf = vidioc_querybuf,
+ .vidioc_qbuf = vidioc_qbuf,
+ .vidioc_dqbuf = vidioc_dqbuf,
+ .vidioc_s_std = vidioc_s_std,
+ .vidioc_enum_input = vidioc_enum_input,
+ .vidioc_g_input = vidioc_g_input,
+ .vidioc_s_input = vidioc_s_input,
+ .vidioc_queryctrl = vidioc_queryctrl,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ .vidioc_streamon = vidioc_streamon,
+ .vidioc_streamoff = vidioc_streamoff,
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+ .vidiocgmbuf = vidiocgmbuf,
+#endif
+ .vidioc_g_tuner = vidioc_g_tuner,
+ .vidioc_s_tuner = vidioc_s_tuner,
+ .vidioc_g_frequency = vidioc_g_frequency,
+ .vidioc_s_frequency = vidioc_s_frequency,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .vidioc_g_register = vidioc_g_register,
+ .vidioc_s_register = vidioc_s_register,
+#endif
+ .tvnorms = CX88_NORMS,
+ .current_norm = V4L2_STD_NTSC_M,
};
-static struct file_operations radio_fops =
+static const struct file_operations radio_fops =
{
.owner = THIS_MODULE,
.open = video_open,
.release = video_release,
- .ioctl = radio_ioctl,
+ .ioctl = video_ioctl2,
.compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek,
};
static struct video_device cx8800_radio_template =
{
- .name = "cx8800-radio",
- .type = VID_TYPE_TUNER,
- .hardware = 0,
- .fops = &radio_fops,
- .minor = -1,
+ .name = "cx8800-radio",
+ .type = VID_TYPE_TUNER,
+ .hardware = 0,
+ .fops = &radio_fops,
+ .minor = -1,
+ .vidioc_querycap = radio_querycap,
+ .vidioc_g_tuner = radio_g_tuner,
+ .vidioc_enum_input = radio_enum_input,
+ .vidioc_g_audio = radio_g_audio,
+ .vidioc_s_tuner = radio_s_tuner,
+ .vidioc_s_audio = radio_s_audio,
+ .vidioc_s_input = radio_s_input,
+ .vidioc_queryctrl = radio_queryctrl,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ .vidioc_g_frequency = vidioc_g_frequency,
+ .vidioc_s_frequency = vidioc_s_frequency,
};
/* ----------------------------------------------------------- */
@@ -1890,6 +1749,7 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
{
struct cx8800_dev *dev;
struct cx88_core *core;
+
int err;
dev = kzalloc(sizeof(*dev),GFP_KERNEL);
@@ -1924,9 +1784,15 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
goto fail_core;
}
+ /* Initialize VBI template */
+ memcpy( &cx8800_vbi_template, &cx8800_video_template,
+ sizeof(cx8800_vbi_template) );
+ strcpy(cx8800_vbi_template.name,"cx8800-vbi");
+ cx8800_vbi_template.type = VID_TYPE_TELETEXT|VID_TYPE_TUNER;
+
/* initialize driver struct */
spin_lock_init(&dev->slock);
- core->tvnorm = tvnorms;
+ core->tvnorm = cx8800_video_template.current_norm;
/* init video dma queues */
INIT_LIST_HEAD(&dev->vidq.active);
@@ -2007,9 +1873,9 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
/* initial device configuration */
mutex_lock(&core->lock);
- cx88_set_tvnorm(core,tvnorms);
+ cx88_set_tvnorm(core,core->tvnorm);
init_controls(core);
- video_mux(core,0);
+ cx88_video_mux(core,0);
mutex_unlock(&core->lock);
/* start tvaudio thread */
@@ -2178,8 +2044,6 @@ static void cx8800_fini(void)
module_init(cx8800_init);
module_exit(cx8800_fini);
-EXPORT_SYMBOL(cx88_do_ioctl);
-
/* ----------------------------------------------------------- */
/*
* Local variables:
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
index a9575ad8ca2..d2ecfba9bb4 100644
--- a/drivers/media/video/cx88/cx88.h
+++ b/drivers/media/video/cx88/cx88.h
@@ -31,7 +31,9 @@
#include <media/video-buf.h>
#include <media/cx2341x.h>
#include <media/audiochip.h>
+#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE)
#include <media/video-buf-dvb.h>
+#endif
#include "btcx-risc.h"
#include "cx88-reg.h"
@@ -50,6 +52,13 @@
/* ----------------------------------------------------------- */
/* defines and enums */
+/* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM B/G/H/LC */
+#define CX88_NORMS (\
+ V4L2_STD_NTSC_M| V4L2_STD_NTSC_M_JP| V4L2_STD_NTSC_443 | \
+ V4L2_STD_PAL_BG| V4L2_STD_PAL_DK | V4L2_STD_PAL_I | \
+ V4L2_STD_PAL_M | V4L2_STD_PAL_N | V4L2_STD_PAL_Nc | \
+ V4L2_STD_PAL_60| V4L2_STD_SECAM_L | V4L2_STD_SECAM_DK )
+
#define FORMAT_FLAGS_PACKED 0x01
#define FORMAT_FLAGS_PLANAR 0x02
@@ -82,22 +91,15 @@ enum cx8802_board_access {
/* ----------------------------------------------------------- */
/* tv norms */
-struct cx88_tvnorm {
- char *name;
- v4l2_std_id id;
- u32 cxiformat;
- u32 cxoformat;
-};
-
-static unsigned int inline norm_maxw(struct cx88_tvnorm *norm)
+static unsigned int inline norm_maxw(v4l2_std_id norm)
{
- return (norm->id & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 720 : 768;
+ return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 720 : 768;
}
-static unsigned int inline norm_maxh(struct cx88_tvnorm *norm)
+static unsigned int inline norm_maxh(v4l2_std_id norm)
{
- return (norm->id & V4L2_STD_625_50) ? 576 : 480;
+ return (norm & V4L2_STD_625_50) ? 576 : 480;
}
/* ----------------------------------------------------------- */
@@ -313,13 +315,15 @@ struct cx88_core {
unsigned int tuner_formats;
/* config info -- dvb */
+#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE)
struct dvb_pll_desc *pll_desc;
unsigned int pll_addr;
int (*prev_set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
+#endif
/* state info */
struct task_struct *kthread;
- struct cx88_tvnorm *tvnorm;
+ v4l2_std_id tvnorm;
u32 tvaudio;
u32 audiomode_manual;
u32 audiomode_current;
@@ -460,12 +464,14 @@ struct cx8802_dev {
int width;
int height;
+#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE)
/* for dvb only */
struct videobuf_dvb dvb;
void* fe_handle;
int (*fe_release)(void *handle);
void *card_priv;
+#endif
/* for switching modulation types */
unsigned char ts_gen_cntrl;
@@ -536,7 +542,7 @@ extern void cx88_sram_channel_dump(struct cx88_core *core,
extern int cx88_set_scale(struct cx88_core *core, unsigned int width,
unsigned int height, enum v4l2_field field);
-extern int cx88_set_tvnorm(struct cx88_core *core, struct cx88_tvnorm *norm);
+extern int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm);
extern struct video_device *cx88_vdev_init(struct cx88_core *core,
struct pci_dev *pci,
@@ -553,7 +559,10 @@ extern int cx88_stop_audio_dma(struct cx88_core *core);
/* ----------------------------------------------------------- */
/* cx88-vbi.c */
-void cx8800_vbi_fmt(struct cx8800_dev *dev, struct v4l2_format *f);
+/* Can be used as g_vbi_fmt, try_vbi_fmt and s_vbi_fmt */
+int cx8800_vbi_fmt (struct file *file, void *priv,
+ struct v4l2_format *f);
+
/*
int cx8800_start_vbi_dma(struct cx8800_dev *dev,
struct cx88_dmaqueue *q,
@@ -633,19 +642,14 @@ int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state);
int cx8802_resume_common(struct pci_dev *pci_dev);
/* ----------------------------------------------------------- */
-/* cx88-video.c */
-extern int cx88_do_ioctl(struct inode *inode, struct file *file, int radio,
- struct cx88_core *core, unsigned int cmd,
- void *arg, v4l2_kioctl driver_ioctl);
+/* cx88-video.c*/
extern const u32 cx88_user_ctrls[];
extern int cx8800_ctrl_query(struct v4l2_queryctrl *qctrl);
-
-/* ----------------------------------------------------------- */
-/* cx88-blackbird.c */
-/* used by cx88-ivtv ioctl emulation layer */
-extern int (*cx88_ioctl_hook)(struct inode *inode, struct file *file,
- unsigned int cmd, void *arg);
-extern unsigned int (*cx88_ioctl_translator)(unsigned int cmd);
+int cx88_enum_input (struct cx88_core *core,struct v4l2_input *i);
+int cx88_set_freq (struct cx88_core *core,struct v4l2_frequency *f);
+int cx88_get_control(struct cx88_core *core, struct v4l2_control *ctl);
+int cx88_set_control(struct cx88_core *core, struct v4l2_control *ctl);
+int cx88_video_mux(struct cx88_core *core, unsigned int input);
/*
* Local variables:
diff --git a/drivers/media/video/dabusb.c b/drivers/media/video/dabusb.c
index 917021fc299..ff4b238090a 100644
--- a/drivers/media/video/dabusb.c
+++ b/drivers/media/video/dabusb.c
@@ -696,7 +696,7 @@ static int dabusb_ioctl (struct inode *inode, struct file *file, unsigned int cm
return ret;
}
-static struct file_operations dabusb_fops =
+static const struct file_operations dabusb_fops =
{
.owner = THIS_MODULE,
.llseek = no_llseek,
diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c
index 3ffb5684f12..55d45b0032c 100644
--- a/drivers/media/video/em28xx/em28xx-input.c
+++ b/drivers/media/video/em28xx/em28xx-input.c
@@ -25,7 +25,6 @@
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
-#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/input.h>
#include <linux/usb.h>
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c
index 36e72c207a8..bec67609500 100644
--- a/drivers/media/video/em28xx/em28xx-video.c
+++ b/drivers/media/video/em28xx/em28xx-video.c
@@ -1480,7 +1480,7 @@ static int em28xx_v4l2_ioctl(struct inode *inode, struct file *filp,
return ret;
}
-static struct file_operations em28xx_v4l_fops = {
+static const struct file_operations em28xx_v4l_fops = {
.owner = THIS_MODULE,
.open = em28xx_v4l2_open,
.release = em28xx_v4l2_close,
diff --git a/drivers/media/video/et61x251/et61x251.h b/drivers/media/video/et61x251/et61x251.h
index 2e5ca403248..262f98e1240 100644
--- a/drivers/media/video/et61x251/et61x251.h
+++ b/drivers/media/video/et61x251/et61x251.h
@@ -171,10 +171,7 @@ struct et61x251_device {
struct et61x251_device*
et61x251_match_id(struct et61x251_device* cam, const struct usb_device_id *id)
{
- if (usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id))
- return cam;
-
- return NULL;
+ return usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id) ? cam : NULL;
}
diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c
index 86e353b26b5..a6525513cd1 100644
--- a/drivers/media/video/et61x251/et61x251_core.c
+++ b/drivers/media/video/et61x251/et61x251_core.c
@@ -1,7 +1,7 @@
/***************************************************************************
* V4L2 driver for ET61X[12]51 PC Camera Controllers *
* *
- * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
+ * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.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 *
@@ -48,8 +48,8 @@
#define ET61X251_MODULE_AUTHOR "(C) 2006 Luca Risolia"
#define ET61X251_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>"
#define ET61X251_MODULE_LICENSE "GPL"
-#define ET61X251_MODULE_VERSION "1:1.02"
-#define ET61X251_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 2)
+#define ET61X251_MODULE_VERSION "1:1.04"
+#define ET61X251_MODULE_VERSION_CODE KERNEL_VERSION(1, 1, 4)
/*****************************************************************************/
@@ -85,7 +85,7 @@ MODULE_PARM_DESC(force_munmap,
"\ndetected camera."
"\n 0 = do not force memory unmapping"
"\n 1 = force memory unmapping (save memory)"
- "\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"."
+ "\nDefault value is "__MODULE_STRING(ET61X251_FORCE_MUNMAP)"."
"\n");
static unsigned int frame_timeout[] = {[0 ... ET61X251_MAX_DEVICES-1] =
@@ -133,7 +133,8 @@ et61x251_request_buffers(struct et61x251_device* cam, u32 count,
cam->nbuffers = count;
while (cam->nbuffers > 0) {
- if ((buff = vmalloc_32(cam->nbuffers * PAGE_ALIGN(imagesize))))
+ if ((buff = vmalloc_32_user(cam->nbuffers *
+ PAGE_ALIGN(imagesize))))
break;
cam->nbuffers--;
}
@@ -543,10 +544,11 @@ static int et61x251_start_transfer(struct et61x251_device* cam)
{
struct usb_device *udev = cam->usbdev;
struct urb* urb;
- const unsigned int wMaxPacketSize[] = {0, 256, 384, 512, 640, 768, 832,
- 864, 896, 920, 956, 980, 1000,
- 1022};
- const unsigned int psz = wMaxPacketSize[ET61X251_ALTERNATE_SETTING];
+ struct usb_host_interface* altsetting = usb_altnum_to_altsetting(
+ usb_ifnum_to_if(udev, 0),
+ ET61X251_ALTERNATE_SETTING);
+ const unsigned int psz = le16_to_cpu(altsetting->
+ endpoint[0].desc.wMaxPacketSize);
s8 i, j;
int err = 0;
@@ -976,29 +978,31 @@ static CLASS_DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR,
static int et61x251_create_sysfs(struct et61x251_device* cam)
{
struct video_device *v4ldev = cam->v4ldev;
- int rc;
+ int err = 0;
+
+ if ((err = video_device_create_file(v4ldev, &class_device_attr_reg)))
+ goto err_out;
+ if ((err = video_device_create_file(v4ldev, &class_device_attr_val)))
+ goto err_reg;
- rc = video_device_create_file(v4ldev, &class_device_attr_reg);
- if (rc) goto err;
- rc = video_device_create_file(v4ldev, &class_device_attr_val);
- if (rc) goto err_reg;
if (cam->sensor.sysfs_ops) {
- rc = video_device_create_file(v4ldev, &class_device_attr_i2c_reg);
- if (rc) goto err_val;
- rc = video_device_create_file(v4ldev, &class_device_attr_i2c_val);
- if (rc) goto err_i2c_reg;
+ if ((err = video_device_create_file(v4ldev,
+ &class_device_attr_i2c_reg)))
+ goto err_val;
+ if ((err = video_device_create_file(v4ldev,
+ &class_device_attr_i2c_val)))
+ goto err_i2c_reg;
}
- return 0;
-
err_i2c_reg:
+ if (cam->sensor.sysfs_ops)
video_device_remove_file(v4ldev, &class_device_attr_i2c_reg);
err_val:
video_device_remove_file(v4ldev, &class_device_attr_val);
err_reg:
video_device_remove_file(v4ldev, &class_device_attr_reg);
-err:
- return rc;
+err_out:
+ return err;
}
#endif /* CONFIG_VIDEO_ADV_DEBUG */
@@ -1767,10 +1771,10 @@ et61x251_vidioc_s_crop(struct et61x251_device* cam, void __user * arg)
rect->left = (s->_rect.left & 1L) ? rect->left | 1L : rect->left & ~1L;
rect->top = (s->_rect.top & 1L) ? rect->top | 1L : rect->top & ~1L;
- if (rect->width < 4)
- rect->width = 4;
- if (rect->height < 4)
- rect->height = 4;
+ if (rect->width < 16)
+ rect->width = 16;
+ if (rect->height < 16)
+ rect->height = 16;
if (rect->width > bounds->width)
rect->width = bounds->width;
if (rect->height > bounds->height)
@@ -1784,8 +1788,8 @@ et61x251_vidioc_s_crop(struct et61x251_device* cam, void __user * arg)
if (rect->top + rect->height > bounds->top + bounds->height)
rect->top = bounds->top+bounds->height - rect->height;
- rect->width &= ~3L;
- rect->height &= ~3L;
+ rect->width &= ~15L;
+ rect->height &= ~15L;
if (ET61X251_PRESERVE_IMGSCALE) {
/* Calculate the actual scaling factor */
@@ -1846,6 +1850,35 @@ et61x251_vidioc_s_crop(struct et61x251_device* cam, void __user * arg)
static int
+et61x251_vidioc_enum_framesizes(struct et61x251_device* cam, void __user * arg)
+{
+ struct v4l2_frmsizeenum frmsize;
+
+ if (copy_from_user(&frmsize, arg, sizeof(frmsize)))
+ return -EFAULT;
+
+ if (frmsize.index != 0)
+ return -EINVAL;
+
+ if (frmsize.pixel_format != V4L2_PIX_FMT_ET61X251 &&
+ frmsize.pixel_format != V4L2_PIX_FMT_SBGGR8)
+ return -EINVAL;
+
+ frmsize.type = V4L2_FRMSIZE_TYPE_STEPWISE;
+ frmsize.stepwise.min_width = frmsize.stepwise.step_width = 16;
+ frmsize.stepwise.min_height = frmsize.stepwise.step_height = 16;
+ frmsize.stepwise.max_width = cam->sensor.cropcap.bounds.width;
+ frmsize.stepwise.max_height = cam->sensor.cropcap.bounds.height;
+ memset(&frmsize.reserved, 0, sizeof(frmsize.reserved));
+
+ if (copy_to_user(arg, &frmsize, sizeof(frmsize)))
+ return -EFAULT;
+
+ return 0;
+}
+
+
+static int
et61x251_vidioc_enum_fmt(struct et61x251_device* cam, void __user * arg)
{
struct v4l2_fmtdesc fmtd;
@@ -1853,6 +1886,9 @@ et61x251_vidioc_enum_fmt(struct et61x251_device* cam, void __user * arg)
if (copy_from_user(&fmtd, arg, sizeof(fmtd)))
return -EFAULT;
+ if (fmtd.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
if (fmtd.index == 0) {
strcpy(fmtd.description, "bayer rgb");
fmtd.pixelformat = V4L2_PIX_FMT_SBGGR8;
@@ -1934,17 +1970,17 @@ et61x251_vidioc_try_s_fmt(struct et61x251_device* cam, unsigned int cmd,
rect.width = scale * pix->width;
rect.height = scale * pix->height;
- if (rect.width < 4)
- rect.width = 4;
- if (rect.height < 4)
- rect.height = 4;
+ if (rect.width < 16)
+ rect.width = 16;
+ if (rect.height < 16)
+ rect.height = 16;
if (rect.width > bounds->left + bounds->width - rect.left)
rect.width = bounds->left + bounds->width - rect.left;
if (rect.height > bounds->top + bounds->height - rect.top)
rect.height = bounds->top + bounds->height - rect.top;
- rect.width &= ~3L;
- rect.height &= ~3L;
+ rect.width &= ~15L;
+ rect.height &= ~15L;
{ /* adjust the scaling factor */
u32 a, b;
@@ -2378,6 +2414,9 @@ static int et61x251_ioctl_v4l2(struct inode* inode, struct file* filp,
case VIDIOC_S_FMT:
return et61x251_vidioc_try_s_fmt(cam, cmd, arg);
+ case VIDIOC_ENUM_FRAMESIZES:
+ return et61x251_vidioc_enum_framesizes(cam, arg);
+
case VIDIOC_G_JPEGCOMP:
return et61x251_vidioc_g_jpegcomp(cam, arg);
@@ -2413,6 +2452,7 @@ static int et61x251_ioctl_v4l2(struct inode* inode, struct file* filp,
case VIDIOC_QUERYSTD:
case VIDIOC_ENUMSTD:
case VIDIOC_QUERYMENU:
+ case VIDIOC_ENUM_FRAMEINTERVALS:
return -EINVAL;
default:
@@ -2454,11 +2494,12 @@ static int et61x251_ioctl(struct inode* inode, struct file* filp,
}
-static struct file_operations et61x251_fops = {
+static const struct file_operations et61x251_fops = {
.owner = THIS_MODULE,
.open = et61x251_open,
.release = et61x251_release,
.ioctl = et61x251_ioctl,
+ .compat_ioctl = v4l_compat_ioctl32,
.read = et61x251_read,
.poll = et61x251_poll,
.mmap = et61x251_mmap,
@@ -2497,7 +2538,7 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
mutex_init(&cam->dev_mutex);
DBG(2, "ET61X[12]51 PC Camera Controller detected "
- "(vid/pid 0x%04X/0x%04X)",id->idVendor, id->idProduct);
+ "(vid/pid 0x%04X:0x%04X)",id->idVendor, id->idProduct);
for (i = 0; et61x251_sensor_table[i]; i++) {
err = et61x251_sensor_table[i](cam);
@@ -2550,9 +2591,14 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
#ifdef CONFIG_VIDEO_ADV_DEBUG
err = et61x251_create_sysfs(cam);
- if (err)
- goto fail2;
- DBG(2, "Optional device control through 'sysfs' interface ready");
+ if (!err)
+ DBG(2, "Optional device control through 'sysfs' "
+ "interface ready");
+ else
+ DBG(2, "Failed to create 'sysfs' interface for optional "
+ "device controlling. Error #%d", err);
+#else
+ DBG(2, "Optional device control through 'sysfs' interface disabled");
#endif
usb_set_intfdata(intf, cam);
@@ -2561,13 +2607,6 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
return 0;
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-fail2:
- video_nr[dev_nr] = -1;
- dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0;
- mutex_unlock(&cam->dev_mutex);
- video_unregister_device(cam->v4ldev);
-#endif
fail:
if (cam) {
kfree(cam->control_buffer);
diff --git a/drivers/media/video/et61x251/et61x251_sensor.h b/drivers/media/video/et61x251/et61x251_sensor.h
index 65edd08dc38..5fadb5de68b 100644
--- a/drivers/media/video/et61x251/et61x251_sensor.h
+++ b/drivers/media/video/et61x251/et61x251_sensor.h
@@ -1,7 +1,7 @@
/***************************************************************************
* API for image sensors connected to ET61X[12]51 PC Camera Controllers *
* *
- * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
+ * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.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 *
@@ -82,7 +82,7 @@ enum et61x251_i2c_rsta {
ET61X251_I2C_RSTA_REPEAT = 0x01, /* repeat start */
};
-#define ET61X251_MAX_CTRLS V4L2_CID_LASTP1-V4L2_CID_BASE+10
+#define ET61X251_MAX_CTRLS (V4L2_CID_LASTP1-V4L2_CID_BASE+10)
struct et61x251_sensor {
char name[32];
diff --git a/drivers/media/video/et61x251/et61x251_tas5130d1b.c b/drivers/media/video/et61x251/et61x251_tas5130d1b.c
index a7d65b82b2f..b0664340984 100644
--- a/drivers/media/video/et61x251/et61x251_tas5130d1b.c
+++ b/drivers/media/video/et61x251/et61x251_tas5130d1b.c
@@ -2,7 +2,7 @@
* Plug-in for TAS5130D1B image sensor connected to the ET61X[12]51 *
* PC Camera Controllers *
* *
- * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
+ * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.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 *
diff --git a/drivers/media/video/indycam.c b/drivers/media/video/indycam.c
index 7420b79e987..5c2c4029ff8 100644
--- a/drivers/media/video/indycam.c
+++ b/drivers/media/video/indycam.c
@@ -17,7 +17,6 @@
#include <linux/major.h>
#include <linux/module.h>
#include <linux/mm.h>
-#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/videodev.h>
diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c
index 59edf58204d..210582d420f 100644
--- a/drivers/media/video/ir-kbd-i2c.c
+++ b/drivers/media/video/ir-kbd-i2c.c
@@ -31,7 +31,6 @@
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/delay.h>
diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c
index 616a35da191..98681da5e3b 100644
--- a/drivers/media/video/meye.c
+++ b/drivers/media/video/meye.c
@@ -28,7 +28,6 @@
*/
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/sched.h>
#include <linux/init.h>
#include <linux/videodev.h>
#include <media/v4l2-common.h>
@@ -1748,7 +1747,7 @@ static int meye_mmap(struct file *file, struct vm_area_struct *vma)
return 0;
}
-static struct file_operations meye_fops = {
+static const struct file_operations meye_fops = {
.owner = THIS_MODULE,
.open = meye_open,
.release = meye_release,
diff --git a/drivers/media/video/ov511.c b/drivers/media/video/ov511.c
index b4db2cbb5a8..e5edff1059a 100644
--- a/drivers/media/video/ov511.c
+++ b/drivers/media/video/ov511.c
@@ -4653,7 +4653,7 @@ ov51x_v4l1_mmap(struct file *file, struct vm_area_struct *vma)
return 0;
}
-static struct file_operations ov511_fops = {
+static const struct file_operations ov511_fops = {
.owner = THIS_MODULE,
.open = ov51x_v4l1_open,
.release = ov51x_v4l1_close,
diff --git a/drivers/media/video/pms.c b/drivers/media/video/pms.c
index 5d681fa8bcb..b5a67f0dd19 100644
--- a/drivers/media/video/pms.c
+++ b/drivers/media/video/pms.c
@@ -28,7 +28,6 @@
#include <linux/ioport.h>
#include <linux/init.h>
#include <asm/io.h>
-#include <linux/sched.h>
#include <linux/videodev.h>
#include <media/v4l2-common.h>
#include <linux/mutex.h>
@@ -881,7 +880,7 @@ static ssize_t pms_read(struct file *file, char __user *buf,
return len;
}
-static struct file_operations pms_fops = {
+static const struct file_operations pms_fops = {
.owner = THIS_MODULE,
.open = video_exclusive_open,
.release = video_exclusive_release,
diff --git a/drivers/media/video/pvrusb2/pvrusb2-audio.c b/drivers/media/video/pvrusb2/pvrusb2-audio.c
index 9846c464ec8..379645e481c 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-audio.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-audio.c
@@ -31,7 +31,6 @@ struct pvr2_msp3400_handler {
struct pvr2_hdw *hdw;
struct pvr2_i2c_client *client;
struct pvr2_i2c_handler i2c_handler;
- struct pvr2_audio_stat astat;
unsigned long stale_mask;
};
@@ -44,13 +43,6 @@ static void set_stereo(struct pvr2_msp3400_handler *ctxt)
pvr2_trace(PVR2_TRACE_CHIPS,"i2c msp3400 v4l2 set_stereo");
- if (hdw->input_val == PVR2_CVAL_INPUT_TV) {
- struct v4l2_tuner vt;
- memset(&vt,0,sizeof(vt));
- vt.audmode = hdw->audiomode_val;
- pvr2_i2c_client_cmd(ctxt->client,VIDIOC_S_TUNER,&vt);
- }
-
route.input = MSP_INPUT_DEFAULT;
route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1);
switch (hdw->input_val) {
@@ -78,8 +70,7 @@ static void set_stereo(struct pvr2_msp3400_handler *ctxt)
static int check_stereo(struct pvr2_msp3400_handler *ctxt)
{
struct pvr2_hdw *hdw = ctxt->hdw;
- return (hdw->input_dirty ||
- hdw->audiomode_dirty);
+ return hdw->input_dirty;
}
@@ -99,8 +90,7 @@ static int msp3400_check(struct pvr2_msp3400_handler *ctxt)
unsigned long msk;
unsigned int idx;
- for (idx = 0; idx < sizeof(msp3400_ops)/sizeof(msp3400_ops[0]);
- idx++) {
+ for (idx = 0; idx < ARRAY_SIZE(msp3400_ops); idx++) {
msk = 1 << idx;
if (ctxt->stale_mask & msk) continue;
if (msp3400_ops[idx].check(ctxt)) {
@@ -116,8 +106,7 @@ static void msp3400_update(struct pvr2_msp3400_handler *ctxt)
unsigned long msk;
unsigned int idx;
- for (idx = 0; idx < sizeof(msp3400_ops)/sizeof(msp3400_ops[0]);
- idx++) {
+ for (idx = 0; idx < ARRAY_SIZE(msp3400_ops); idx++) {
msk = 1 << idx;
if (!(ctxt->stale_mask & msk)) continue;
ctxt->stale_mask &= ~msk;
@@ -126,27 +115,9 @@ static void msp3400_update(struct pvr2_msp3400_handler *ctxt)
}
-/* This reads back the current signal type */
-static int get_audio_status(struct pvr2_msp3400_handler *ctxt)
-{
- struct v4l2_tuner vt;
- int stat;
-
- memset(&vt,0,sizeof(vt));
- stat = pvr2_i2c_client_cmd(ctxt->client,VIDIOC_G_TUNER,&vt);
- if (stat < 0) return stat;
-
- ctxt->hdw->flag_stereo = (vt.audmode & V4L2_TUNER_MODE_STEREO) != 0;
- ctxt->hdw->flag_bilingual =
- (vt.audmode & V4L2_TUNER_MODE_LANG2) != 0;
- return 0;
-}
-
-
static void pvr2_msp3400_detach(struct pvr2_msp3400_handler *ctxt)
{
ctxt->client->handler = NULL;
- ctxt->hdw->audio_stat = NULL;
kfree(ctxt);
}
@@ -158,7 +129,7 @@ static unsigned int pvr2_msp3400_describe(struct pvr2_msp3400_handler *ctxt,
}
-const static struct pvr2_i2c_handler_functions msp3400_funcs = {
+static const struct pvr2_i2c_handler_functions msp3400_funcs = {
.detach = (void (*)(void *))pvr2_msp3400_detach,
.check = (int (*)(void *))msp3400_check,
.update = (void (*)(void *))msp3400_update,
@@ -169,24 +140,17 @@ const static struct pvr2_i2c_handler_functions msp3400_funcs = {
int pvr2_i2c_msp3400_setup(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp)
{
struct pvr2_msp3400_handler *ctxt;
- if (hdw->audio_stat) return 0;
if (cp->handler) return 0;
- ctxt = kmalloc(sizeof(*ctxt),GFP_KERNEL);
+ ctxt = kzalloc(sizeof(*ctxt),GFP_KERNEL);
if (!ctxt) return 0;
- memset(ctxt,0,sizeof(*ctxt));
ctxt->i2c_handler.func_data = ctxt;
ctxt->i2c_handler.func_table = &msp3400_funcs;
ctxt->client = cp;
ctxt->hdw = hdw;
- ctxt->astat.ctxt = ctxt;
- ctxt->astat.status = (int (*)(void *))get_audio_status;
- ctxt->astat.detach = (void (*)(void *))pvr2_msp3400_detach;
- ctxt->stale_mask = (1 << (sizeof(msp3400_ops)/
- sizeof(msp3400_ops[0]))) - 1;
+ ctxt->stale_mask = (1 << ARRAY_SIZE(msp3400_ops)) - 1;
cp->handler = &ctxt->i2c_handler;
- hdw->audio_stat = &ctxt->astat;
pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x msp3400 V4L2 handler set up",
cp->client->addr);
return !0;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-context.c b/drivers/media/video/pvrusb2/pvrusb2-context.c
index cf129746205..6bbed88d786 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-context.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-context.c
@@ -83,9 +83,8 @@ struct pvr2_context *pvr2_context_create(
void (*setup_func)(struct pvr2_context *))
{
struct pvr2_context *mp = NULL;
- mp = kmalloc(sizeof(*mp),GFP_KERNEL);
+ mp = kzalloc(sizeof(*mp),GFP_KERNEL);
if (!mp) goto done;
- memset(mp,0,sizeof(*mp));
pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr_main id=%p",mp);
mp->setup_func = setup_func;
mutex_init(&mp->mutex);
diff --git a/drivers/media/video/pvrusb2/pvrusb2-ctrl.c b/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
index c77de859cc8..f569b00201d 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
@@ -26,6 +26,27 @@
#include <linux/mutex.h>
+static int pvr2_ctrl_range_check(struct pvr2_ctrl *cptr,int val)
+{
+ if (cptr->info->check_value) {
+ if (!cptr->info->check_value(cptr,val)) return -ERANGE;
+ } else {
+ int lim;
+ lim = cptr->info->def.type_int.min_value;
+ if (cptr->info->get_min_value) {
+ cptr->info->get_min_value(cptr,&lim);
+ }
+ if (val < lim) return -ERANGE;
+ lim = cptr->info->def.type_int.max_value;
+ if (cptr->info->get_max_value) {
+ cptr->info->get_max_value(cptr,&lim);
+ }
+ if (val > lim) return -ERANGE;
+ }
+ return 0;
+}
+
+
/* Set the given control. */
int pvr2_ctrl_set_value(struct pvr2_ctrl *cptr,int val)
{
@@ -43,17 +64,8 @@ int pvr2_ctrl_set_mask_value(struct pvr2_ctrl *cptr,int mask,int val)
if (cptr->info->type == pvr2_ctl_bitmask) {
mask &= cptr->info->def.type_bitmask.valid_bits;
} else if (cptr->info->type == pvr2_ctl_int) {
- int lim;
- lim = cptr->info->def.type_int.min_value;
- if (cptr->info->get_min_value) {
- cptr->info->get_min_value(cptr,&lim);
- }
- if (val < lim) break;
- lim = cptr->info->def.type_int.max_value;
- if (cptr->info->get_max_value) {
- cptr->info->get_max_value(cptr,&lim);
- }
- if (val > lim) break;
+ ret = pvr2_ctrl_range_check(cptr,val);
+ if (ret < 0) break;
} else if (cptr->info->type == pvr2_ctl_enum) {
if (val >= cptr->info->def.type_enum.count) {
break;
@@ -498,16 +510,13 @@ int pvr2_ctrl_sym_to_value(struct pvr2_ctrl *cptr,
LOCK_TAKE(cptr->hdw->big_lock); do {
if (cptr->info->type == pvr2_ctl_int) {
ret = parse_token(ptr,len,valptr,NULL,0);
- if ((ret >= 0) &&
- ((*valptr < cptr->info->def.type_int.min_value) ||
- (*valptr > cptr->info->def.type_int.max_value))) {
- ret = -ERANGE;
+ if (ret >= 0) {
+ ret = pvr2_ctrl_range_check(cptr,*valptr);
}
if (maskptr) *maskptr = ~0;
} else if (cptr->info->type == pvr2_ctl_bool) {
- ret = parse_token(
- ptr,len,valptr,boolNames,
- sizeof(boolNames)/sizeof(boolNames[0]));
+ ret = parse_token(ptr,len,valptr,boolNames,
+ ARRAY_SIZE(boolNames));
if (ret == 1) {
*valptr = *valptr ? !0 : 0;
} else if (ret == 0) {
diff --git a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
index 848fb233d80..e8a9252c7df 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
@@ -63,6 +63,7 @@ static void set_input(struct pvr2_v4l_cx2584x *ctxt)
vid_input = CX25840_COMPOSITE7;
aud_input = CX25840_AUDIO8;
break;
+ case PVR2_CVAL_INPUT_RADIO: // Treat same as composite
case PVR2_CVAL_INPUT_COMPOSITE:
vid_input = CX25840_COMPOSITE3;
aud_input = CX25840_AUDIO_SERIAL;
@@ -71,7 +72,6 @@ static void set_input(struct pvr2_v4l_cx2584x *ctxt)
vid_input = CX25840_SVIDEO1;
aud_input = CX25840_AUDIO_SERIAL;
break;
- case PVR2_CVAL_INPUT_RADIO:
default:
// Just set it to be composite input for now...
vid_input = CX25840_COMPOSITE3;
@@ -150,8 +150,7 @@ static int decoder_check(struct pvr2_v4l_cx2584x *ctxt)
unsigned long msk;
unsigned int idx;
- for (idx = 0; idx < sizeof(decoder_ops)/sizeof(decoder_ops[0]);
- idx++) {
+ for (idx = 0; idx < ARRAY_SIZE(decoder_ops); idx++) {
msk = 1 << idx;
if (ctxt->stale_mask & msk) continue;
if (decoder_ops[idx].check(ctxt)) {
@@ -167,8 +166,7 @@ static void decoder_update(struct pvr2_v4l_cx2584x *ctxt)
unsigned long msk;
unsigned int idx;
- for (idx = 0; idx < sizeof(decoder_ops)/sizeof(decoder_ops[0]);
- idx++) {
+ for (idx = 0; idx < ARRAY_SIZE(decoder_ops); idx++) {
msk = 1 << idx;
if (!(ctxt->stale_mask & msk)) continue;
ctxt->stale_mask &= ~msk;
@@ -199,18 +197,6 @@ static int decoder_detect(struct pvr2_i2c_client *cp)
}
-static int decoder_is_tuned(struct pvr2_v4l_cx2584x *ctxt)
-{
- struct v4l2_tuner vt;
- int ret;
-
- memset(&vt,0,sizeof(vt));
- ret = pvr2_i2c_client_cmd(ctxt->client,VIDIOC_G_TUNER,&vt);
- if (ret < 0) return -EINVAL;
- return vt.signal ? 1 : 0;
-}
-
-
static unsigned int decoder_describe(struct pvr2_v4l_cx2584x *ctxt,
char *buf,unsigned int cnt)
{
@@ -226,7 +212,7 @@ static void decoder_reset(struct pvr2_v4l_cx2584x *ctxt)
}
-const static struct pvr2_i2c_handler_functions hfuncs = {
+static const struct pvr2_i2c_handler_functions hfuncs = {
.detach = (void (*)(void *))decoder_detach,
.check = (int (*)(void *))decoder_check,
.update = (void (*)(void *))decoder_update,
@@ -243,21 +229,18 @@ int pvr2_i2c_cx2584x_v4l_setup(struct pvr2_hdw *hdw,
if (cp->handler) return 0;
if (!decoder_detect(cp)) return 0;
- ctxt = kmalloc(sizeof(*ctxt),GFP_KERNEL);
+ ctxt = kzalloc(sizeof(*ctxt),GFP_KERNEL);
if (!ctxt) return 0;
- memset(ctxt,0,sizeof(*ctxt));
ctxt->handler.func_data = ctxt;
ctxt->handler.func_table = &hfuncs;
ctxt->ctrl.ctxt = ctxt;
ctxt->ctrl.detach = (void (*)(void *))decoder_detach;
ctxt->ctrl.enable = (void (*)(void *,int))decoder_enable;
- ctxt->ctrl.tuned = (int (*)(void *))decoder_is_tuned;
ctxt->ctrl.force_reset = (void (*)(void*))decoder_reset;
ctxt->client = cp;
ctxt->hdw = hdw;
- ctxt->stale_mask = (1 << (sizeof(decoder_ops)/
- sizeof(decoder_ops[0]))) - 1;
+ ctxt->stale_mask = (1 << ARRAY_SIZE(decoder_ops)) - 1;
hdw->decoder_ctrl = &ctxt->ctrl;
cp->handler = &ctxt->handler;
{
diff --git a/drivers/media/video/pvrusb2/pvrusb2-debugifc.c b/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
index f985f00d885..e9da9bb8f8d 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
@@ -152,7 +152,7 @@ static unsigned long debugifc_find_mask(const char *buf,unsigned int count)
{
struct debugifc_mask_item *mip;
unsigned int idx;
- for (idx = 0; idx < sizeof(mask_items)/sizeof(mask_items[0]); idx++) {
+ for (idx = 0; idx < ARRAY_SIZE(mask_items); idx++) {
mip = mask_items + idx;
if (debugifc_match_keyword(buf,count,mip->name)) {
return mip->msk;
@@ -169,7 +169,7 @@ static int debugifc_print_mask(char *buf,unsigned int sz,
unsigned int idx;
int bcnt = 0;
int ccnt;
- for (idx = 0; idx < sizeof(mask_items)/sizeof(mask_items[0]); idx++) {
+ for (idx = 0; idx < ARRAY_SIZE(mask_items); idx++) {
mip = mask_items + idx;
if (!(mip->msk & msk)) continue;
ccnt = scnprintf(buf,sz,"%s%c%s",
diff --git a/drivers/media/video/pvrusb2/pvrusb2-eeprom.c b/drivers/media/video/pvrusb2/pvrusb2-eeprom.c
index 6cff8e75f42..45cbca0143c 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-eeprom.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-eeprom.c
@@ -102,9 +102,8 @@ static u8 *pvr2_eeprom_fetch(struct pvr2_hdw *hdw)
}
msg[1].len = pcnt;
msg[1].buf = eeprom+tcnt;
- if ((ret = i2c_transfer(
- &hdw->i2c_adap,
- msg,sizeof(msg)/sizeof(msg[0]))) != 2) {
+ if ((ret = i2c_transfer(&hdw->i2c_adap,
+ msg,ARRAY_SIZE(msg))) != 2) {
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
"eeprom fetch set offs err=%d",ret);
kfree(eeprom);
diff --git a/drivers/media/video/pvrusb2/pvrusb2-encoder.c b/drivers/media/video/pvrusb2/pvrusb2-encoder.c
index c94f97b7939..5786faf9b3b 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-encoder.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-encoder.c
@@ -26,6 +26,7 @@
#include "pvrusb2-encoder.h"
#include "pvrusb2-hdw-internal.h"
#include "pvrusb2-debug.h"
+#include "pvrusb2-fx2-cmd.h"
@@ -34,34 +35,41 @@
#define IVTV_MBOX_DRIVER_DONE 0x00000002
#define IVTV_MBOX_DRIVER_BUSY 0x00000001
+#define MBOX_BASE 0x44
+
static int pvr2_encoder_write_words(struct pvr2_hdw *hdw,
+ unsigned int offs,
const u32 *data, unsigned int dlen)
{
- unsigned int idx;
+ unsigned int idx,addr;
+ unsigned int bAddr;
int ret;
- unsigned int offs = 0;
unsigned int chunkCnt;
/*
Format: First byte must be 0x01. Remaining 32 bit words are
- spread out into chunks of 7 bytes each, little-endian ordered,
- offset at zero within each 2 blank bytes following and a
- single byte that is 0x44 plus the offset of the word. Repeat
- request for additional words, with offset adjusted
- accordingly.
+ spread out into chunks of 7 bytes each, with the first 4 bytes
+ being the data word (little endian), and the next 3 bytes
+ being the address where that data word is to be written (big
+ endian). Repeat request for additional words, with offset
+ adjusted accordingly.
*/
while (dlen) {
chunkCnt = 8;
if (chunkCnt > dlen) chunkCnt = dlen;
memset(hdw->cmd_buffer,0,sizeof(hdw->cmd_buffer));
- hdw->cmd_buffer[0] = 0x01;
+ bAddr = 0;
+ hdw->cmd_buffer[bAddr++] = FX2CMD_MEM_WRITE_DWORD;
for (idx = 0; idx < chunkCnt; idx++) {
- hdw->cmd_buffer[1+(idx*7)+6] = 0x44 + idx + offs;
- PVR2_DECOMPOSE_LE(hdw->cmd_buffer, 1+(idx*7),
- data[idx]);
+ addr = idx + offs;
+ hdw->cmd_buffer[bAddr+6] = (addr & 0xffu);
+ hdw->cmd_buffer[bAddr+5] = ((addr>>8) & 0xffu);
+ hdw->cmd_buffer[bAddr+4] = ((addr>>16) & 0xffu);
+ PVR2_DECOMPOSE_LE(hdw->cmd_buffer, bAddr,data[idx]);
+ bAddr += 7;
}
ret = pvr2_send_request(hdw,
hdw->cmd_buffer,1+(chunkCnt*7),
@@ -76,33 +84,42 @@ static int pvr2_encoder_write_words(struct pvr2_hdw *hdw,
}
-static int pvr2_encoder_read_words(struct pvr2_hdw *hdw,int statusFl,
+static int pvr2_encoder_read_words(struct pvr2_hdw *hdw,
+ unsigned int offs,
u32 *data, unsigned int dlen)
{
unsigned int idx;
int ret;
- unsigned int offs = 0;
unsigned int chunkCnt;
/*
Format: First byte must be 0x02 (status check) or 0x28 (read
back block of 32 bit words). Next 6 bytes must be zero,
- followed by a single byte of 0x44+offset for portion to be
- read. Returned data is packed set of 32 bits words that were
- read.
+ followed by a single byte of MBOX_BASE+offset for portion to
+ be read. Returned data is packed set of 32 bits words that
+ were read.
*/
while (dlen) {
chunkCnt = 16;
if (chunkCnt > dlen) chunkCnt = dlen;
- memset(hdw->cmd_buffer,0,sizeof(hdw->cmd_buffer));
- hdw->cmd_buffer[0] = statusFl ? 0x02 : 0x28;
- hdw->cmd_buffer[7] = 0x44 + offs;
+ if (chunkCnt < 16) chunkCnt = 1;
+ hdw->cmd_buffer[0] =
+ ((chunkCnt == 1) ?
+ FX2CMD_MEM_READ_DWORD : FX2CMD_MEM_READ_64BYTES);
+ hdw->cmd_buffer[1] = 0;
+ hdw->cmd_buffer[2] = 0;
+ hdw->cmd_buffer[3] = 0;
+ hdw->cmd_buffer[4] = 0;
+ hdw->cmd_buffer[5] = ((offs>>16) & 0xffu);
+ hdw->cmd_buffer[6] = ((offs>>8) & 0xffu);
+ hdw->cmd_buffer[7] = (offs & 0xffu);
ret = pvr2_send_request(hdw,
hdw->cmd_buffer,8,
- hdw->cmd_buffer,chunkCnt * 4);
+ hdw->cmd_buffer,
+ (chunkCnt == 1 ? 4 : 16 * 4));
if (ret) return ret;
for (idx = 0; idx < chunkCnt; idx++) {
@@ -129,6 +146,8 @@ static int pvr2_encoder_cmd(void *ctxt,
u32 *argp)
{
unsigned int poll_count;
+ unsigned int try_count = 0;
+ int retry_flag;
int ret = 0;
unsigned int idx;
/* These sizes look to be limited by the FX2 firmware implementation */
@@ -140,14 +159,15 @@ static int pvr2_encoder_cmd(void *ctxt,
/*
The encoder seems to speak entirely using blocks 32 bit words.
- In ivtv driver terms, this is a mailbox which we populate with
- data and watch what the hardware does with it. The first word
- is a set of flags used to control the transaction, the second
- word is the command to execute, the third byte is zero (ivtv
- driver suggests that this is some kind of return value), and
- the fourth byte is a specified timeout (windows driver always
- uses 0x00060000 except for one case when it is zero). All
- successive words are the argument words for the command.
+ In ivtv driver terms, this is a mailbox at MBOX_BASE which we
+ populate with data and watch what the hardware does with it.
+ The first word is a set of flags used to control the
+ transaction, the second word is the command to execute, the
+ third byte is zero (ivtv driver suggests that this is some
+ kind of return value), and the fourth byte is a specified
+ timeout (windows driver always uses 0x00060000 except for one
+ case when it is zero). All successive words are the argument
+ words for the command.
First, write out the entire set of words, with the first word
being zero.
@@ -156,44 +176,42 @@ static int pvr2_encoder_cmd(void *ctxt,
IVTV_MBOX_DRIVER_DONE | IVTV_DRIVER_BUSY this time (which
probably means "go").
- Next, read back 16 words as status. Check the first word,
+ Next, read back the return count words. Check the first word,
which should have IVTV_MBOX_FIRMWARE_DONE set. If however
that bit is not set, then the command isn't done so repeat the
- read.
-
- Next, read back 32 words and compare with the original
- arugments. Hopefully they will match.
+ read until it is set.
Finally, write out just the first word again, but set it to
0x0 this time (which probably means "idle").
*/
- if (arg_cnt_send > (sizeof(wrData)/sizeof(wrData[0]))-4) {
+ if (arg_cnt_send > (ARRAY_SIZE(wrData) - 4)) {
pvr2_trace(
PVR2_TRACE_ERROR_LEGS,
"Failed to write cx23416 command"
" - too many input arguments"
- " (was given %u limit %u)",
- arg_cnt_send,
- (unsigned int)(sizeof(wrData)/sizeof(wrData[0])) - 4);
+ " (was given %u limit %lu)",
+ arg_cnt_send, (long unsigned) ARRAY_SIZE(wrData) - 4);
return -EINVAL;
}
- if (arg_cnt_recv > (sizeof(rdData)/sizeof(rdData[0]))-4) {
+ if (arg_cnt_recv > (ARRAY_SIZE(rdData) - 4)) {
pvr2_trace(
PVR2_TRACE_ERROR_LEGS,
"Failed to write cx23416 command"
" - too many return arguments"
- " (was given %u limit %u)",
- arg_cnt_recv,
- (unsigned int)(sizeof(rdData)/sizeof(rdData[0])) - 4);
+ " (was given %u limit %lu)",
+ arg_cnt_recv, (long unsigned) ARRAY_SIZE(rdData) - 4);
return -EINVAL;
}
LOCK_TAKE(hdw->ctl_lock); do {
+ retry_flag = 0;
+ try_count++;
+ ret = 0;
wrData[0] = 0;
wrData[1] = cmd;
wrData[2] = 0;
@@ -201,59 +219,74 @@ static int pvr2_encoder_cmd(void *ctxt,
for (idx = 0; idx < arg_cnt_send; idx++) {
wrData[idx+4] = argp[idx];
}
- for (; idx < (sizeof(wrData)/sizeof(wrData[0]))-4; idx++) {
+ for (; idx < ARRAY_SIZE(wrData) - 4; idx++) {
wrData[idx+4] = 0;
}
- ret = pvr2_encoder_write_words(hdw,wrData,idx);
+ ret = pvr2_encoder_write_words(hdw,MBOX_BASE,wrData,idx);
if (ret) break;
wrData[0] = IVTV_MBOX_DRIVER_DONE|IVTV_MBOX_DRIVER_BUSY;
- ret = pvr2_encoder_write_words(hdw,wrData,1);
+ ret = pvr2_encoder_write_words(hdw,MBOX_BASE,wrData,1);
if (ret) break;
poll_count = 0;
while (1) {
- if (poll_count < 10000000) poll_count++;
- ret = pvr2_encoder_read_words(hdw,!0,rdData,1);
- if (ret) break;
+ poll_count++;
+ ret = pvr2_encoder_read_words(hdw,MBOX_BASE,rdData,
+ arg_cnt_recv+4);
+ if (ret) {
+ break;
+ }
if (rdData[0] & IVTV_MBOX_FIRMWARE_DONE) {
break;
}
- if (poll_count == 100) {
+ if (rdData[0] && (poll_count < 1000)) continue;
+ if (!rdData[0]) {
+ retry_flag = !0;
pvr2_trace(
PVR2_TRACE_ERROR_LEGS,
- "***WARNING*** device's encoder"
- " appears to be stuck"
- " (status=0%08x)",rdData[0]);
+ "Encoder timed out waiting for us"
+ "; arranging to retry");
+ } else {
pvr2_trace(
PVR2_TRACE_ERROR_LEGS,
- "Encoder command: 0x%02x",cmd);
- for (idx = 4; idx < arg_cnt_send; idx++) {
- pvr2_trace(
- PVR2_TRACE_ERROR_LEGS,
- "Encoder arg%d: 0x%08x",
- idx-3,wrData[idx]);
- }
+ "***WARNING*** device's encoder"
+ " appears to be stuck"
+ " (status=0x%08x)",rdData[0]);
+ }
+ pvr2_trace(
+ PVR2_TRACE_ERROR_LEGS,
+ "Encoder command: 0x%02x",cmd);
+ for (idx = 4; idx < arg_cnt_send; idx++) {
pvr2_trace(
PVR2_TRACE_ERROR_LEGS,
- "Giving up waiting."
- " It is likely that"
- " this is a bad idea...");
- ret = -EBUSY;
- break;
+ "Encoder arg%d: 0x%08x",
+ idx-3,wrData[idx]);
}
+ ret = -EBUSY;
+ break;
+ }
+ if (retry_flag) {
+ if (try_count < 20) continue;
+ pvr2_trace(
+ PVR2_TRACE_ERROR_LEGS,
+ "Too many retries...");
+ ret = -EBUSY;
+ }
+ if (ret) {
+ pvr2_trace(
+ PVR2_TRACE_ERROR_LEGS,
+ "Giving up on command."
+ " It is likely that"
+ " this is a bad idea...");
+ break;
}
- if (ret) break;
wrData[0] = 0x7;
- ret = pvr2_encoder_read_words(
- hdw,0,rdData,
- sizeof(rdData)/sizeof(rdData[0]));
- if (ret) break;
for (idx = 0; idx < arg_cnt_recv; idx++) {
argp[idx] = rdData[idx+4];
}
wrData[0] = 0x0;
- ret = pvr2_encoder_write_words(hdw,wrData,1);
+ ret = pvr2_encoder_write_words(hdw,MBOX_BASE,wrData,1);
if (ret) break;
} while(0); LOCK_GIVE(hdw->ctl_lock);
@@ -269,13 +302,13 @@ static int pvr2_encoder_vcmd(struct pvr2_hdw *hdw, int cmd,
unsigned int idx;
u32 data[12];
- if (args > sizeof(data)/sizeof(data[0])) {
+ if (args > ARRAY_SIZE(data)) {
pvr2_trace(
PVR2_TRACE_ERROR_LEGS,
"Failed to write cx23416 command"
" - too many arguments"
- " (was given %u limit %u)",
- args,(unsigned int)(sizeof(data)/sizeof(data[0])));
+ " (was given %u limit %lu)",
+ args, (long unsigned) ARRAY_SIZE(data));
return -EINVAL;
}
@@ -288,6 +321,73 @@ static int pvr2_encoder_vcmd(struct pvr2_hdw *hdw, int cmd,
return pvr2_encoder_cmd(hdw,cmd,args,0,data);
}
+
+/* This implements some extra setup for the encoder that seems to be
+ specific to the PVR USB2 hardware. */
+int pvr2_encoder_prep_config(struct pvr2_hdw *hdw)
+{
+ int ret = 0;
+ int encMisc3Arg = 0;
+
+#if 0
+ /* This inexplicable bit happens in the Hauppage windows
+ driver (for both 24xxx and 29xxx devices). However I
+ currently see no difference in behavior with or without
+ this stuff. Leave this here as a note of its existence,
+ but don't use it. */
+ LOCK_TAKE(hdw->ctl_lock); do {
+ u32 dat[1];
+ dat[0] = 0x80000640;
+ pvr2_encoder_write_words(hdw,0x01fe,dat,1);
+ pvr2_encoder_write_words(hdw,0x023e,dat,1);
+ } while(0); LOCK_GIVE(hdw->ctl_lock);
+#endif
+
+ /* Mike Isely <isely@pobox.com> 26-Jan-2006 The windows driver
+ sends the following list of ENC_MISC commands (for both
+ 24xxx and 29xxx devices). Meanings are not entirely clear,
+ however without the ENC_MISC(3,1) command then we risk
+ random perpetual video corruption whenever the video input
+ breaks up for a moment (like when switching channels). */
+
+
+#if 0
+ /* This ENC_MISC(5,0) command seems to hurt 29xxx sync
+ performance on channel changes, but is not a problem on
+ 24xxx devices. */
+ ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 5,0,0,0);
+#endif
+
+ /* This ENC_MISC(3,encMisc3Arg) command is critical - without
+ it there will eventually be video corruption. Also, the
+ 29xxx case is strange - the Windows driver is passing 1
+ regardless of device type but if we have 1 for 29xxx device
+ the video turns sluggish. */
+ switch (hdw->hdw_type) {
+ case PVR2_HDW_TYPE_24XXX: encMisc3Arg = 1; break;
+ case PVR2_HDW_TYPE_29XXX: encMisc3Arg = 0; break;
+ default: break;
+ }
+ ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 3,
+ encMisc3Arg,0,0);
+
+ ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 8,0,0,0);
+
+#if 0
+ /* This ENC_MISC(4,1) command is poisonous, so it is commented
+ out. But I'm leaving it here anyway to document its
+ existence in the Windows driver. The effect of this
+ command is that apps displaying the stream become sluggish
+ with stuttering video. */
+ ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 4,1,0,0);
+#endif
+
+ ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 0,3,0,0);
+ ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4,15,0,0,0);
+
+ return ret;
+}
+
int pvr2_encoder_configure(struct pvr2_hdw *hdw)
{
int ret;
@@ -302,6 +402,8 @@ int pvr2_encoder_configure(struct pvr2_hdw *hdw)
ret = 0;
+ ret |= pvr2_encoder_prep_config(hdw);
+
if (!ret) ret = pvr2_encoder_vcmd(
hdw,CX2341X_ENC_SET_NUM_VSYNC_LINES, 2,
0xf0, 0xf0);
@@ -360,15 +462,22 @@ int pvr2_encoder_start(struct pvr2_hdw *hdw)
pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000481);
pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000000);
- if (hdw->config == pvr2_config_vbi) {
+ pvr2_encoder_vcmd(hdw,CX2341X_ENC_MUTE_VIDEO,1,
+ hdw->input_val == PVR2_CVAL_INPUT_RADIO ? 1 : 0);
+
+ switch (hdw->config) {
+ case pvr2_config_vbi:
status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,
0x01,0x14);
- } else if (hdw->config == pvr2_config_mpeg) {
+ break;
+ case pvr2_config_mpeg:
status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,
0,0x13);
- } else {
+ break;
+ default: /* Unhandled cases for now */
status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,
0,0x13);
+ break;
}
if (!status) {
hdw->subsys_enabled_mask |= (1<<PVR2_SUBSYS_B_ENC_RUN);
@@ -383,15 +492,19 @@ int pvr2_encoder_stop(struct pvr2_hdw *hdw)
/* mask all interrupts */
pvr2_write_register(hdw, 0x0048, 0xffffffff);
- if (hdw->config == pvr2_config_vbi) {
+ switch (hdw->config) {
+ case pvr2_config_vbi:
status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,
0x01,0x01,0x14);
- } else if (hdw->config == pvr2_config_mpeg) {
+ break;
+ case pvr2_config_mpeg:
status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,
0x01,0,0x13);
- } else {
+ break;
+ default: /* Unhandled cases for now */
status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,
0x01,0,0x13);
+ break;
}
/* change some GPIO data */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h b/drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h
new file mode 100644
index 00000000000..ffbc6d09610
--- /dev/null
+++ b/drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h
@@ -0,0 +1,62 @@
+/*
+ *
+ * $Id$
+ *
+ * Copyright (C) 2007 Michael Krufky <mkrufky@linuxtv.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
+ *
+ * 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 _PVRUSB2_FX2_CMD_H_
+#define _PVRUSB2_FX2_CMD_H_
+
+#define FX2CMD_MEM_WRITE_DWORD 0x01
+#define FX2CMD_MEM_READ_DWORD 0x02
+
+#define FX2CMD_MEM_READ_64BYTES 0x28
+
+#define FX2CMD_REG_WRITE 0x04
+#define FX2CMD_REG_READ 0x05
+#define FX2CMD_MEMSEL 0x06
+
+#define FX2CMD_I2C_WRITE 0x08
+#define FX2CMD_I2C_READ 0x09
+
+#define FX2CMD_GET_USB_SPEED 0x0b
+
+#define FX2CMD_STREAMING_ON 0x36
+#define FX2CMD_STREAMING_OFF 0x37
+
+#define FX2CMD_FWPOST1 0x52
+
+#define FX2CMD_POWER_OFF 0xdc
+#define FX2CMD_POWER_ON 0xde
+
+#define FX2CMD_DEEP_RESET 0xdd
+
+#define FX2CMD_GET_EEPROM_ADDR 0xeb
+#define FX2CMD_GET_IR_CODE 0xec
+
+#endif /* _PVRUSB2_FX2_CMD_H_ */
+
+/*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+ *** Local Variables: ***
+ *** mode: c ***
+ *** fill-column: 75 ***
+ *** tab-width: 8 ***
+ *** c-basic-offset: 8 ***
+ *** End: ***
+ */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
index 34b08fbcc6e..16bd7419960 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
@@ -60,6 +60,7 @@ struct pvr2_decoder;
typedef int (*pvr2_ctlf_is_dirty)(struct pvr2_ctrl *);
typedef void (*pvr2_ctlf_clear_dirty)(struct pvr2_ctrl *);
+typedef int (*pvr2_ctlf_check_value)(struct pvr2_ctrl *,int);
typedef int (*pvr2_ctlf_get_value)(struct pvr2_ctrl *,int *);
typedef int (*pvr2_ctlf_set_value)(struct pvr2_ctrl *,int msk,int val);
typedef int (*pvr2_ctlf_val_to_sym)(struct pvr2_ctrl *,int msk,int val,
@@ -83,6 +84,7 @@ struct pvr2_ctl_info {
pvr2_ctlf_get_value get_min_value; /* Get minimum allowed value */
pvr2_ctlf_get_value get_max_value; /* Get maximum allowed value */
pvr2_ctlf_set_value set_value; /* Set its value */
+ pvr2_ctlf_check_value check_value; /* Check that value is valid */
pvr2_ctlf_val_to_sym val_to_sym; /* Custom convert value->symbol */
pvr2_ctlf_sym_to_val sym_to_val; /* Custom convert symbol->value */
pvr2_ctlf_is_dirty is_dirty; /* Return true if dirty */
@@ -135,17 +137,10 @@ struct pvr2_ctrl {
};
-struct pvr2_audio_stat {
- void *ctxt;
- void (*detach)(void *);
- int (*status)(void *);
-};
-
struct pvr2_decoder_ctrl {
void *ctxt;
void (*detach)(void *);
void (*enable)(void *,int);
- int (*tuned)(void *);
void (*force_reset)(void *);
};
@@ -212,7 +207,6 @@ struct pvr2_hdw {
/* Frequency table */
unsigned int freqTable[FREQTABLE_SIZE];
unsigned int freqProgSlot;
- unsigned int freqSlot;
/* Stuff for handling low level control interaction with device */
struct mutex ctl_lock_mutex;
@@ -258,9 +252,17 @@ struct pvr2_hdw {
/* Tuner / frequency control stuff */
unsigned int tuner_type;
int tuner_updated;
- unsigned int freqVal;
+ unsigned int freqValTelevision; /* Current freq for tv mode */
+ unsigned int freqValRadio; /* Current freq for radio mode */
+ unsigned int freqSlotTelevision; /* Current slot for tv mode */
+ unsigned int freqSlotRadio; /* Current slot for radio mode */
+ unsigned int freqSelector; /* 0=radio 1=television */
int freqDirty;
+ /* Current tuner info - this information is polled from the I2C bus */
+ struct v4l2_tuner tuner_signal_info;
+ int tuner_signal_stale;
+
/* Video standard handling */
v4l2_std_id std_mask_eeprom; // Hardware supported selections
v4l2_std_id std_mask_avail; // Which standards we may select from
@@ -281,20 +283,17 @@ struct pvr2_hdw {
int unit_number; /* ID for driver instance */
unsigned long serial_number; /* ID for hardware itself */
- /* Minor number used by v4l logic (yes, this is a hack, as there should
- be no v4l junk here). Probably a better way to do this. */
- int v4l_minor_number;
+ /* Minor numbers used by v4l logic (yes, this is a hack, as there
+ should be no v4l junk here). Probably a better way to do this. */
+ int v4l_minor_number_video;
+ int v4l_minor_number_vbi;
+ int v4l_minor_number_radio;
/* Location of eeprom or a negative number if none */
int eeprom_addr;
enum pvr2_config config;
- /* Information about what audio signal we're hearing */
- int flag_stereo;
- int flag_bilingual;
- struct pvr2_audio_stat *audio_stat;
-
/* Control state needed for cx2341x module */
struct cx2341x_mpeg_params enc_cur_state;
struct cx2341x_mpeg_params enc_ctl_state;
@@ -327,6 +326,9 @@ struct pvr2_hdw {
unsigned int control_cnt;
};
+/* This function gets the current frequency */
+unsigned long pvr2_hdw_get_cur_freq(struct pvr2_hdw *);
+
#endif /* __PVRUSB2_HDW_INTERNAL_H */
/*
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
index d2004965187..a1ca0f5007e 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
@@ -36,6 +36,10 @@
#include "pvrusb2-hdw-internal.h"
#include "pvrusb2-encoder.h"
#include "pvrusb2-debug.h"
+#include "pvrusb2-fx2-cmd.h"
+
+#define TV_MIN_FREQ 55250000L
+#define TV_MAX_FREQ 850000000L
struct usb_device_id pvr2_device_table[] = {
[PVR2_HDW_TYPE_29XXX] = { USB_DEVICE(0x2040, 0x2900) },
@@ -71,12 +75,10 @@ static const char *pvr2_client_29xxx[] = {
static struct pvr2_string_table pvr2_client_lists[] = {
[PVR2_HDW_TYPE_29XXX] = {
- pvr2_client_29xxx,
- sizeof(pvr2_client_29xxx)/sizeof(pvr2_client_29xxx[0]),
+ pvr2_client_29xxx, ARRAY_SIZE(pvr2_client_29xxx)
},
[PVR2_HDW_TYPE_24XXX] = {
- pvr2_client_24xxx,
- sizeof(pvr2_client_24xxx)/sizeof(pvr2_client_24xxx[0]),
+ pvr2_client_24xxx, ARRAY_SIZE(pvr2_client_24xxx)
},
};
@@ -160,9 +162,6 @@ static const struct pvr2_mpeg_ids mpeg_ids[] = {
.strid = "video_gop_closure",
.id = V4L2_CID_MPEG_VIDEO_GOP_CLOSURE,
},{
- .strid = "video_pulldown",
- .id = V4L2_CID_MPEG_VIDEO_PULLDOWN,
- },{
.strid = "video_bitrate_mode",
.id = V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
},{
@@ -212,7 +211,7 @@ static const struct pvr2_mpeg_ids mpeg_ids[] = {
.id = V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM,
}
};
-#define MPEGDEF_COUNT (sizeof(mpeg_ids)/sizeof(mpeg_ids[0]))
+#define MPEGDEF_COUNT ARRAY_SIZE(mpeg_ids)
static const char *control_values_srate[] = {
@@ -255,10 +254,10 @@ static const char *control_values_subsystem[] = {
[PVR2_SUBSYS_B_ENC_RUN] = "enc_run",
};
+static void pvr2_hdw_set_cur_freq(struct pvr2_hdw *,unsigned long);
static int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl);
static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw);
static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw);
-static unsigned int pvr2_hdw_get_signal_status_internal(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_render_useless_unlocked(struct pvr2_hdw *hdw);
@@ -272,8 +271,6 @@ static int pvr2_send_request_ex(struct pvr2_hdw *hdw,
unsigned int timeout,int probe_fl,
void *write_data,unsigned int write_len,
void *read_data,unsigned int read_len);
-static int pvr2_write_u16(struct pvr2_hdw *hdw, u16 data, int res);
-static int pvr2_write_u8(struct pvr2_hdw *hdw, u8 data, int res);
static int ctrl_channelfreq_get(struct pvr2_ctrl *cptr,int *vp)
{
@@ -289,8 +286,21 @@ static int ctrl_channelfreq_get(struct pvr2_ctrl *cptr,int *vp)
static int ctrl_channelfreq_set(struct pvr2_ctrl *cptr,int m,int v)
{
struct pvr2_hdw *hdw = cptr->hdw;
- if ((hdw->freqProgSlot > 0) && (hdw->freqProgSlot <= FREQTABLE_SIZE)) {
- hdw->freqTable[hdw->freqProgSlot-1] = v;
+ unsigned int slotId = hdw->freqProgSlot;
+ if ((slotId > 0) && (slotId <= FREQTABLE_SIZE)) {
+ hdw->freqTable[slotId-1] = v;
+ /* Handle side effects correctly - if we're tuned to this
+ slot, then forgot the slot id relation since the stored
+ frequency has been changed. */
+ if (hdw->freqSelector) {
+ if (hdw->freqSlotRadio == slotId) {
+ hdw->freqSlotRadio = 0;
+ }
+ } else {
+ if (hdw->freqSlotTelevision == slotId) {
+ hdw->freqSlotTelevision = 0;
+ }
+ }
}
return 0;
}
@@ -312,28 +322,32 @@ static int ctrl_channelprog_set(struct pvr2_ctrl *cptr,int m,int v)
static int ctrl_channel_get(struct pvr2_ctrl *cptr,int *vp)
{
- *vp = cptr->hdw->freqSlot;
+ struct pvr2_hdw *hdw = cptr->hdw;
+ *vp = hdw->freqSelector ? hdw->freqSlotRadio : hdw->freqSlotTelevision;
return 0;
}
-static int ctrl_channel_set(struct pvr2_ctrl *cptr,int m,int v)
+static int ctrl_channel_set(struct pvr2_ctrl *cptr,int m,int slotId)
{
unsigned freq = 0;
struct pvr2_hdw *hdw = cptr->hdw;
- hdw->freqSlot = v;
- if ((hdw->freqSlot > 0) && (hdw->freqSlot <= FREQTABLE_SIZE)) {
- freq = hdw->freqTable[hdw->freqSlot-1];
- }
- if (freq && (freq != hdw->freqVal)) {
- hdw->freqVal = freq;
- hdw->freqDirty = !0;
+ if ((slotId < 0) || (slotId > FREQTABLE_SIZE)) return 0;
+ if (slotId > 0) {
+ freq = hdw->freqTable[slotId-1];
+ if (!freq) return 0;
+ pvr2_hdw_set_cur_freq(hdw,freq);
+ }
+ if (hdw->freqSelector) {
+ hdw->freqSlotRadio = slotId;
+ } else {
+ hdw->freqSlotTelevision = slotId;
}
return 0;
}
static int ctrl_freq_get(struct pvr2_ctrl *cptr,int *vp)
{
- *vp = cptr->hdw->freqVal;
+ *vp = pvr2_hdw_get_cur_freq(cptr->hdw);
return 0;
}
@@ -349,10 +363,7 @@ static void ctrl_freq_clear_dirty(struct pvr2_ctrl *cptr)
static int ctrl_freq_set(struct pvr2_ctrl *cptr,int m,int v)
{
- struct pvr2_hdw *hdw = cptr->hdw;
- hdw->freqVal = v;
- hdw->freqDirty = !0;
- hdw->freqSlot = 0;
+ pvr2_hdw_set_cur_freq(cptr->hdw,v);
return 0;
}
@@ -378,6 +389,89 @@ static int ctrl_vres_min_get(struct pvr2_ctrl *cptr,int *vp)
return 0;
}
+static int ctrl_get_input(struct pvr2_ctrl *cptr,int *vp)
+{
+ *vp = cptr->hdw->input_val;
+ return 0;
+}
+
+static int ctrl_set_input(struct pvr2_ctrl *cptr,int m,int v)
+{
+ struct pvr2_hdw *hdw = cptr->hdw;
+
+ if (hdw->input_val != v) {
+ hdw->input_val = v;
+ hdw->input_dirty = !0;
+ }
+
+ /* Handle side effects - if we switch to a mode that needs the RF
+ tuner, then select the right frequency choice as well and mark
+ it dirty. */
+ if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
+ hdw->freqSelector = 0;
+ hdw->freqDirty = !0;
+ } else if (hdw->input_val == PVR2_CVAL_INPUT_TV) {
+ hdw->freqSelector = 1;
+ hdw->freqDirty = !0;
+ }
+ return 0;
+}
+
+static int ctrl_isdirty_input(struct pvr2_ctrl *cptr)
+{
+ return cptr->hdw->input_dirty != 0;
+}
+
+static void ctrl_cleardirty_input(struct pvr2_ctrl *cptr)
+{
+ cptr->hdw->input_dirty = 0;
+}
+
+
+static int ctrl_freq_max_get(struct pvr2_ctrl *cptr, int *vp)
+{
+ unsigned long fv;
+ struct pvr2_hdw *hdw = cptr->hdw;
+ if (hdw->tuner_signal_stale) {
+ pvr2_i2c_core_status_poll(hdw);
+ }
+ fv = hdw->tuner_signal_info.rangehigh;
+ if (!fv) {
+ /* Safety fallback */
+ *vp = TV_MAX_FREQ;
+ return 0;
+ }
+ if (hdw->tuner_signal_info.capability & V4L2_TUNER_CAP_LOW) {
+ fv = (fv * 125) / 2;
+ } else {
+ fv = fv * 62500;
+ }
+ *vp = fv;
+ return 0;
+}
+
+static int ctrl_freq_min_get(struct pvr2_ctrl *cptr, int *vp)
+{
+ unsigned long fv;
+ struct pvr2_hdw *hdw = cptr->hdw;
+ if (hdw->tuner_signal_stale) {
+ pvr2_i2c_core_status_poll(hdw);
+ }
+ fv = hdw->tuner_signal_info.rangelow;
+ if (!fv) {
+ /* Safety fallback */
+ *vp = TV_MIN_FREQ;
+ return 0;
+ }
+ if (hdw->tuner_signal_info.capability & V4L2_TUNER_CAP_LOW) {
+ fv = (fv * 125) / 2;
+ } else {
+ fv = fv * 62500;
+ }
+ *vp = fv;
+ return 0;
+}
+
static int ctrl_cx2341x_is_dirty(struct pvr2_ctrl *cptr)
{
return cptr->hdw->enc_stale != 0;
@@ -534,8 +628,32 @@ static void ctrl_stdcur_clear_dirty(struct pvr2_ctrl *cptr)
static int ctrl_signal_get(struct pvr2_ctrl *cptr,int *vp)
{
- *vp = ((pvr2_hdw_get_signal_status_internal(cptr->hdw) &
- PVR2_SIGNAL_OK) ? 1 : 0);
+ struct pvr2_hdw *hdw = cptr->hdw;
+ pvr2_i2c_core_status_poll(hdw);
+ *vp = hdw->tuner_signal_info.signal;
+ return 0;
+}
+
+static int ctrl_audio_modes_present_get(struct pvr2_ctrl *cptr,int *vp)
+{
+ int val = 0;
+ unsigned int subchan;
+ struct pvr2_hdw *hdw = cptr->hdw;
+ pvr2_i2c_core_status_poll(hdw);
+ subchan = hdw->tuner_signal_info.rxsubchans;
+ if (subchan & V4L2_TUNER_SUB_MONO) {
+ val |= (1 << V4L2_TUNER_MODE_MONO);
+ }
+ if (subchan & V4L2_TUNER_SUB_STEREO) {
+ val |= (1 << V4L2_TUNER_MODE_STEREO);
+ }
+ if (subchan & V4L2_TUNER_SUB_LANG1) {
+ val |= (1 << V4L2_TUNER_MODE_LANG1);
+ }
+ if (subchan & V4L2_TUNER_SUB_LANG2) {
+ val |= (1 << V4L2_TUNER_MODE_LANG2);
+ }
+ *vp = val;
return 0;
}
@@ -604,7 +722,7 @@ static void ctrl_stdenumcur_clear_dirty(struct pvr2_ctrl *cptr)
#define DEFENUM(tab) \
.type = pvr2_ctl_enum, \
- .def.type_enum.count = (sizeof(tab)/sizeof((tab)[0])), \
+ .def.type_enum.count = ARRAY_SIZE(tab), \
.def.type_enum.value_names = tab
#define DEFBOOL \
@@ -641,15 +759,11 @@ VCREATE_FUNCS(balance)
VCREATE_FUNCS(bass)
VCREATE_FUNCS(treble)
VCREATE_FUNCS(mute)
-VCREATE_FUNCS(input)
VCREATE_FUNCS(audiomode)
VCREATE_FUNCS(res_hor)
VCREATE_FUNCS(res_ver)
VCREATE_FUNCS(srate)
-#define MIN_FREQ 55250000L
-#define MAX_FREQ 850000000L
-
/* Table definition of all controls which can be manipulated */
static const struct pvr2_ctl_info control_defs[] = {
{
@@ -684,7 +798,7 @@ static const struct pvr2_ctl_info control_defs[] = {
.v4l_id = V4L2_CID_AUDIO_VOLUME,
.desc = "Volume",
.name = "volume",
- .default_value = 65535,
+ .default_value = 62000,
DEFREF(volume),
DEFINT(0,65535),
},{
@@ -758,12 +872,16 @@ static const struct pvr2_ctl_info control_defs[] = {
.desc = "Tuner Frequency (Hz)",
.name = "frequency",
.internal_id = PVR2_CID_FREQUENCY,
- .default_value = 175250000L,
+ .default_value = 0,
.set_value = ctrl_freq_set,
.get_value = ctrl_freq_get,
.is_dirty = ctrl_freq_is_dirty,
.clear_dirty = ctrl_freq_clear_dirty,
- DEFINT(MIN_FREQ,MAX_FREQ),
+ DEFINT(0,0),
+ /* Hook in check for input value (tv/radio) and adjust
+ max/min values accordingly */
+ .get_max_value = ctrl_freq_max_get,
+ .get_min_value = ctrl_freq_min_get,
},{
.desc = "Channel",
.name = "channel",
@@ -775,7 +893,11 @@ static const struct pvr2_ctl_info control_defs[] = {
.name = "freq_table_value",
.set_value = ctrl_channelfreq_set,
.get_value = ctrl_channelfreq_get,
- DEFINT(MIN_FREQ,MAX_FREQ),
+ DEFINT(0,0),
+ /* Hook in check for input value (tv/radio) and adjust
+ max/min values accordingly */
+ .get_max_value = ctrl_freq_max_get,
+ .get_min_value = ctrl_freq_min_get,
},{
.desc = "Channel Program ID",
.name = "freq_table_channel",
@@ -796,7 +918,20 @@ static const struct pvr2_ctl_info control_defs[] = {
.desc = "Signal Present",
.name = "signal_present",
.get_value = ctrl_signal_get,
- DEFBOOL,
+ DEFINT(0,65535),
+ },{
+ .desc = "Audio Modes Present",
+ .name = "audio_modes_present",
+ .get_value = ctrl_audio_modes_present_get,
+ /* For this type we "borrow" the V4L2_TUNER_MODE enum from
+ v4l. Nothing outside of this module cares about this,
+ but I reuse it in order to also reuse the
+ control_values_audiomode string table. */
+ DEFMASK(((1 << V4L2_TUNER_MODE_MONO)|
+ (1 << V4L2_TUNER_MODE_STEREO)|
+ (1 << V4L2_TUNER_MODE_LANG1)|
+ (1 << V4L2_TUNER_MODE_LANG2)),
+ control_values_audiomode),
},{
.desc = "Video Standards Available Mask",
.name = "video_standard_mask_available",
@@ -846,7 +981,7 @@ static const struct pvr2_ctl_info control_defs[] = {
}
};
-#define CTRLDEF_COUNT (sizeof(control_defs)/sizeof(control_defs[0]))
+#define CTRLDEF_COUNT ARRAY_SIZE(control_defs)
const char *pvr2_config_get_name(enum pvr2_config cfg)
@@ -855,7 +990,8 @@ const char *pvr2_config_get_name(enum pvr2_config cfg)
case pvr2_config_empty: return "empty";
case pvr2_config_mpeg: return "mpeg";
case pvr2_config_vbi: return "vbi";
- case pvr2_config_radio: return "radio";
+ case pvr2_config_pcm: return "pcm";
+ case pvr2_config_rawvideo: return "raw video";
}
return "<unknown>";
}
@@ -872,6 +1008,40 @@ unsigned long pvr2_hdw_get_sn(struct pvr2_hdw *hdw)
return hdw->serial_number;
}
+unsigned long pvr2_hdw_get_cur_freq(struct pvr2_hdw *hdw)
+{
+ return hdw->freqSelector ? hdw->freqValTelevision : hdw->freqValRadio;
+}
+
+/* Set the currently tuned frequency and account for all possible
+ driver-core side effects of this action. */
+void pvr2_hdw_set_cur_freq(struct pvr2_hdw *hdw,unsigned long val)
+{
+ if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
+ if (hdw->freqSelector) {
+ /* Swing over to radio frequency selection */
+ hdw->freqSelector = 0;
+ hdw->freqDirty = !0;
+ }
+ if (hdw->freqValRadio != val) {
+ hdw->freqValRadio = val;
+ hdw->freqSlotRadio = 0;
+ hdw->freqDirty = !0;
+ }
+ } else {
+ if (!(hdw->freqSelector)) {
+ /* Swing over to television frequency selection */
+ hdw->freqSelector = 1;
+ hdw->freqDirty = !0;
+ }
+ if (hdw->freqValTelevision != val) {
+ hdw->freqValTelevision = val;
+ hdw->freqSlotTelevision = 0;
+ hdw->freqDirty = !0;
+ }
+ }
+}
+
int pvr2_hdw_get_unit_number(struct pvr2_hdw *hdw)
{
return hdw->unit_number;
@@ -960,12 +1130,10 @@ static int pvr2_upload_firmware1(struct pvr2_hdw *hdw)
};
static const struct pvr2_string_table fw_file_defs[] = {
[PVR2_HDW_TYPE_29XXX] = {
- fw_files_29xxx,
- sizeof(fw_files_29xxx)/sizeof(fw_files_29xxx[0]),
+ fw_files_29xxx, ARRAY_SIZE(fw_files_29xxx)
},
[PVR2_HDW_TYPE_24XXX] = {
- fw_files_24xxx,
- sizeof(fw_files_24xxx)/sizeof(fw_files_24xxx[0]),
+ fw_files_24xxx, ARRAY_SIZE(fw_files_24xxx)
},
};
hdw->fw1_state = FW1_STATE_FAILED; // default result
@@ -1041,7 +1209,7 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
{
const struct firmware *fw_entry = NULL;
void *fw_ptr;
- unsigned int pipe, fw_len, fw_done;
+ unsigned int pipe, fw_len, fw_done, bcnt, icnt;
int actual_length;
int ret = 0;
int fwidx;
@@ -1052,8 +1220,7 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
trace_firmware("pvr2_upload_firmware2");
ret = pvr2_locate_firmware(hdw,&fw_entry,"encoder",
- sizeof(fw_files)/sizeof(fw_files[0]),
- fw_files);
+ ARRAY_SIZE(fw_files), fw_files);
if (ret < 0) return ret;
fwidx = ret;
ret = 0;
@@ -1079,8 +1246,13 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
ret |= pvr2_write_register(hdw, 0xaa04, 0x00057810); /*unknown*/
ret |= pvr2_write_register(hdw, 0xaa10, 0x00148500); /*unknown*/
ret |= pvr2_write_register(hdw, 0xaa18, 0x00840000); /*unknown*/
- ret |= pvr2_write_u8(hdw, 0x52, 0);
- ret |= pvr2_write_u16(hdw, 0x0600, 0);
+ LOCK_TAKE(hdw->ctl_lock); do {
+ hdw->cmd_buffer[0] = FX2CMD_FWPOST1;
+ ret |= pvr2_send_request(hdw,hdw->cmd_buffer,1,0,0);
+ hdw->cmd_buffer[0] = FX2CMD_MEMSEL;
+ hdw->cmd_buffer[1] = 0;
+ ret |= pvr2_send_request(hdw,hdw->cmd_buffer,2,0,0);
+ } while (0); LOCK_GIVE(hdw->ctl_lock);
if (ret) {
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
@@ -1093,11 +1265,11 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
fw_len = fw_entry->size;
- if (fw_len % FIRMWARE_CHUNK_SIZE) {
+ if (fw_len % sizeof(u32)) {
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
"size of %s firmware"
- " must be a multiple of 8192B",
- fw_files[fwidx]);
+ " must be a multiple of %u bytes",
+ fw_files[fwidx],sizeof(u32));
release_firmware(fw_entry);
return -1;
}
@@ -1112,18 +1284,21 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
pipe = usb_sndbulkpipe(hdw->usb_dev, PVR2_FIRMWARE_ENDPOINT);
- for (fw_done = 0 ; (fw_done < fw_len) && !ret ;
- fw_done += FIRMWARE_CHUNK_SIZE ) {
- int i;
- memcpy(fw_ptr, fw_entry->data + fw_done, FIRMWARE_CHUNK_SIZE);
- /* Usbsnoop log shows that we must swap bytes... */
- for (i = 0; i < FIRMWARE_CHUNK_SIZE/4 ; i++)
- ((u32 *)fw_ptr)[i] = ___swab32(((u32 *)fw_ptr)[i]);
-
- ret |= usb_bulk_msg(hdw->usb_dev, pipe, fw_ptr,
- FIRMWARE_CHUNK_SIZE,
+ fw_done = 0;
+ for (fw_done = 0; fw_done < fw_len;) {
+ bcnt = fw_len - fw_done;
+ if (bcnt > FIRMWARE_CHUNK_SIZE) bcnt = FIRMWARE_CHUNK_SIZE;
+ memcpy(fw_ptr, fw_entry->data + fw_done, bcnt);
+ /* Usbsnoop log shows that we must swap bytes... */
+ for (icnt = 0; icnt < bcnt/4 ; icnt++)
+ ((u32 *)fw_ptr)[icnt] =
+ ___swab32(((u32 *)fw_ptr)[icnt]);
+
+ ret |= usb_bulk_msg(hdw->usb_dev, pipe, fw_ptr,bcnt,
&actual_length, HZ);
- ret |= (actual_length != FIRMWARE_CHUNK_SIZE);
+ ret |= (actual_length != bcnt);
+ if (ret) break;
+ fw_done += bcnt;
}
trace_firmware("upload of %s : %i / %i ",
@@ -1142,7 +1317,11 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
ret |= pvr2_write_register(hdw, 0x9054, 0xffffffff); /*reset hw blocks*/
ret |= pvr2_write_register(hdw, 0x9058, 0xffffffe8); /*VPU ctrl*/
- ret |= pvr2_write_u16(hdw, 0x0600, 0);
+ LOCK_TAKE(hdw->ctl_lock); do {
+ hdw->cmd_buffer[0] = FX2CMD_MEMSEL;
+ hdw->cmd_buffer[1] = 0;
+ ret |= pvr2_send_request(hdw,hdw->cmd_buffer,2,0,0);
+ } while (0); LOCK_GIVE(hdw->ctl_lock);
if (ret) {
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
@@ -1479,7 +1658,7 @@ static int pvr2_hdw_check_firmware(struct pvr2_hdw *hdw)
firmware needs be loaded. */
int result;
LOCK_TAKE(hdw->ctl_lock); do {
- hdw->cmd_buffer[0] = 0xeb;
+ hdw->cmd_buffer[0] = FX2CMD_GET_EEPROM_ADDR;
result = pvr2_send_request_ex(hdw,HZ*1,!0,
hdw->cmd_buffer,1,
hdw->cmd_buffer,1);
@@ -1611,6 +1790,16 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
cptr->info->set_value(cptr,~0,cptr->info->default_value);
}
+ /* Set up special default values for the television and radio
+ frequencies here. It's not really important what these defaults
+ are, but I set them to something usable in the Chicago area just
+ to make driver testing a little easier. */
+
+ /* US Broadcast channel 7 (175.25 MHz) */
+ hdw->freqValTelevision = 175250000L;
+ /* 104.3 MHz, a usable FM station for my area */
+ hdw->freqValRadio = 104300000L;
+
// Do not use pvr2_reset_ctl_endpoints() here. It is not
// thread-safe against the normal pvr2_send_request() mechanism.
// (We should make it thread safe).
@@ -1750,26 +1939,24 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
struct pvr2_ctl_info *ciptr;
hdw_type = devid - pvr2_device_table;
- if (hdw_type >=
- sizeof(pvr2_device_names)/sizeof(pvr2_device_names[0])) {
+ if (hdw_type >= ARRAY_SIZE(pvr2_device_names)) {
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
"Bogus device type of %u reported",hdw_type);
return NULL;
}
- hdw = kmalloc(sizeof(*hdw),GFP_KERNEL);
+ hdw = kzalloc(sizeof(*hdw),GFP_KERNEL);
pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_create: hdw=%p, type \"%s\"",
hdw,pvr2_device_names[hdw_type]);
if (!hdw) goto fail;
- memset(hdw,0,sizeof(*hdw));
+ hdw->tuner_signal_stale = !0;
cx2341x_fill_defaults(&hdw->enc_ctl_state);
hdw->control_cnt = CTRLDEF_COUNT;
hdw->control_cnt += MPEGDEF_COUNT;
- hdw->controls = kmalloc(sizeof(struct pvr2_ctrl) * hdw->control_cnt,
+ hdw->controls = kzalloc(sizeof(struct pvr2_ctrl) * hdw->control_cnt,
GFP_KERNEL);
if (!hdw->controls) goto fail;
- memset(hdw->controls,0,sizeof(struct pvr2_ctrl) * hdw->control_cnt);
hdw->hdw_type = hdw_type;
for (idx = 0; idx < hdw->control_cnt; idx++) {
cptr = hdw->controls + idx;
@@ -1783,11 +1970,9 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
cptr->info = control_defs+idx;
}
/* Define and configure additional controls from cx2341x module. */
- hdw->mpeg_ctrl_info = kmalloc(
+ hdw->mpeg_ctrl_info = kzalloc(
sizeof(*(hdw->mpeg_ctrl_info)) * MPEGDEF_COUNT, GFP_KERNEL);
if (!hdw->mpeg_ctrl_info) goto fail;
- memset(hdw->mpeg_ctrl_info,0,
- sizeof(*(hdw->mpeg_ctrl_info)) * MPEGDEF_COUNT);
for (idx = 0; idx < MPEGDEF_COUNT; idx++) {
cptr = hdw->controls + idx + CTRLDEF_COUNT;
ciptr = &(hdw->mpeg_ctrl_info[idx].info);
@@ -1872,7 +2057,9 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
hdw->eeprom_addr = -1;
hdw->unit_number = -1;
- hdw->v4l_minor_number = -1;
+ hdw->v4l_minor_number_video = -1;
+ hdw->v4l_minor_number_vbi = -1;
+ hdw->v4l_minor_number_radio = -1;
hdw->ctl_write_buffer = kmalloc(PVR2_CTL_BUFFSIZE,GFP_KERNEL);
if (!hdw->ctl_write_buffer) goto fail;
hdw->ctl_read_buffer = kmalloc(PVR2_CTL_BUFFSIZE,GFP_KERNEL);
@@ -1929,10 +2116,10 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
if (hdw) {
usb_free_urb(hdw->ctl_read_urb);
usb_free_urb(hdw->ctl_write_urb);
- if (hdw->ctl_read_buffer) kfree(hdw->ctl_read_buffer);
- if (hdw->ctl_write_buffer) kfree(hdw->ctl_write_buffer);
- if (hdw->controls) kfree(hdw->controls);
- if (hdw->mpeg_ctrl_info) kfree(hdw->mpeg_ctrl_info);
+ kfree(hdw->ctl_read_buffer);
+ kfree(hdw->ctl_write_buffer);
+ kfree(hdw->controls);
+ kfree(hdw->mpeg_ctrl_info);
kfree(hdw);
}
return NULL;
@@ -1982,9 +2169,6 @@ void pvr2_hdw_destroy(struct pvr2_hdw *hdw)
pvr2_stream_destroy(hdw->vid_stream);
hdw->vid_stream = NULL;
}
- if (hdw->audio_stat) {
- hdw->audio_stat->detach(hdw->audio_stat->ctxt);
- }
if (hdw->decoder_ctrl) {
hdw->decoder_ctrl->detach(hdw->decoder_ctrl->ctxt);
}
@@ -1997,10 +2181,10 @@ void pvr2_hdw_destroy(struct pvr2_hdw *hdw)
unit_pointers[hdw->unit_number] = NULL;
}
} while (0); up(&pvr2_unit_sem);
- if (hdw->controls) kfree(hdw->controls);
- if (hdw->mpeg_ctrl_info) kfree(hdw->mpeg_ctrl_info);
- if (hdw->std_defs) kfree(hdw->std_defs);
- if (hdw->std_enum_names) kfree(hdw->std_enum_names);
+ kfree(hdw->controls);
+ kfree(hdw->mpeg_ctrl_info);
+ kfree(hdw->std_defs);
+ kfree(hdw->std_enum_names);
kfree(hdw);
}
@@ -2210,10 +2394,9 @@ static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw)
cptr = hdw->controls + idx;
if (cptr->info->is_dirty == 0) continue;
if (!cptr->info->is_dirty(cptr)) continue;
- if (!commit_flag) {
- commit_flag = !0;
- }
+ commit_flag = !0;
+ if (!(pvrusb2_debug & PVR2_TRACE_CTL)) continue;
bcnt = scnprintf(buf,sizeof(buf),"\"%s\" <-- ",
cptr->info->name);
value = 0;
@@ -2263,6 +2446,13 @@ static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw)
stale_subsys_mask |= (1<<PVR2_SUBSYS_B_ENC_CFG);
}
+ if (hdw->input_dirty) {
+ /* pk: If input changes to or from radio, then the encoder
+ needs to be restarted (for ENC_MUTE_VIDEO to work) */
+ stale_subsys_mask |= (1<<PVR2_SUBSYS_B_ENC_RUN);
+ }
+
+
if (hdw->srate_dirty) {
/* Write new sample rate into control structure since
* the master copy is stale. We must track srate
@@ -2343,39 +2533,11 @@ const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *hdw)
}
-/* Return bit mask indicating signal status */
-static unsigned int pvr2_hdw_get_signal_status_internal(struct pvr2_hdw *hdw)
-{
- unsigned int msk = 0;
- switch (hdw->input_val) {
- case PVR2_CVAL_INPUT_TV:
- case PVR2_CVAL_INPUT_RADIO:
- if (hdw->decoder_ctrl &&
- hdw->decoder_ctrl->tuned(hdw->decoder_ctrl->ctxt)) {
- msk |= PVR2_SIGNAL_OK;
- if (hdw->audio_stat &&
- hdw->audio_stat->status(hdw->audio_stat->ctxt)) {
- if (hdw->flag_stereo) {
- msk |= PVR2_SIGNAL_STEREO;
- }
- if (hdw->flag_bilingual) {
- msk |= PVR2_SIGNAL_SAP;
- }
- }
- }
- break;
- default:
- msk |= PVR2_SIGNAL_OK | PVR2_SIGNAL_STEREO;
- }
- return msk;
-}
-
-
int pvr2_hdw_is_hsm(struct pvr2_hdw *hdw)
{
int result;
LOCK_TAKE(hdw->ctl_lock); do {
- hdw->cmd_buffer[0] = 0x0b;
+ hdw->cmd_buffer[0] = FX2CMD_GET_USB_SPEED;
result = pvr2_send_request(hdw,
hdw->cmd_buffer,1,
hdw->cmd_buffer,1);
@@ -2386,14 +2548,25 @@ int pvr2_hdw_is_hsm(struct pvr2_hdw *hdw)
}
-/* Return bit mask indicating signal status */
-unsigned int pvr2_hdw_get_signal_status(struct pvr2_hdw *hdw)
+/* Execute poll of tuner status */
+void pvr2_hdw_execute_tuner_poll(struct pvr2_hdw *hdw)
{
- unsigned int msk = 0;
LOCK_TAKE(hdw->big_lock); do {
- msk = pvr2_hdw_get_signal_status_internal(hdw);
+ pvr2_i2c_core_status_poll(hdw);
} while (0); LOCK_GIVE(hdw->big_lock);
- return msk;
+}
+
+
+/* Return information about the tuner */
+int pvr2_hdw_get_tuner_status(struct pvr2_hdw *hdw,struct v4l2_tuner *vtp)
+{
+ LOCK_TAKE(hdw->big_lock); do {
+ if (hdw->tuner_signal_stale) {
+ pvr2_i2c_core_status_poll(hdw);
+ }
+ memcpy(vtp,&hdw->tuner_signal_info,sizeof(struct v4l2_tuner));
+ } while (0); LOCK_GIVE(hdw->big_lock);
+ return 0;
}
@@ -2442,14 +2615,12 @@ void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *hdw, int enable_flag)
pvr2_trace(PVR2_TRACE_FIRMWARE,
"Preparing to suck out CPU firmware");
hdw->fw_size = 0x2000;
- hdw->fw_buffer = kmalloc(hdw->fw_size,GFP_KERNEL);
+ hdw->fw_buffer = kzalloc(hdw->fw_size,GFP_KERNEL);
if (!hdw->fw_buffer) {
hdw->fw_size = 0;
break;
}
- memset(hdw->fw_buffer,0,hdw->fw_size);
-
/* We have to hold the CPU during firmware upload. */
pvr2_hdw_cpureset_assert(hdw,1);
@@ -2513,16 +2684,28 @@ int pvr2_hdw_cpufw_get(struct pvr2_hdw *hdw,unsigned int offs,
}
-int pvr2_hdw_v4l_get_minor_number(struct pvr2_hdw *hdw)
+int pvr2_hdw_v4l_get_minor_number(struct pvr2_hdw *hdw,
+ enum pvr2_v4l_type index)
{
- return hdw->v4l_minor_number;
+ switch (index) {
+ case pvr2_v4l_type_video: return hdw->v4l_minor_number_video;
+ case pvr2_v4l_type_vbi: return hdw->v4l_minor_number_vbi;
+ case pvr2_v4l_type_radio: return hdw->v4l_minor_number_radio;
+ default: return -1;
+ }
}
-/* Store the v4l minor device number */
-void pvr2_hdw_v4l_store_minor_number(struct pvr2_hdw *hdw,int v)
+/* Store a v4l minor device number */
+void pvr2_hdw_v4l_store_minor_number(struct pvr2_hdw *hdw,
+ enum pvr2_v4l_type index,int v)
{
- hdw->v4l_minor_number = v;
+ switch (index) {
+ case pvr2_v4l_type_video: hdw->v4l_minor_number_video = v;
+ case pvr2_v4l_type_vbi: hdw->v4l_minor_number_vbi = v;
+ case pvr2_v4l_type_radio: hdw->v4l_minor_number_radio = v;
+ default: break;
+ }
}
@@ -2804,7 +2987,7 @@ int pvr2_write_register(struct pvr2_hdw *hdw, u16 reg, u32 data)
LOCK_TAKE(hdw->ctl_lock);
- hdw->cmd_buffer[0] = 0x04; /* write register prefix */
+ hdw->cmd_buffer[0] = FX2CMD_REG_WRITE; /* write register prefix */
PVR2_DECOMPOSE_LE(hdw->cmd_buffer,1,data);
hdw->cmd_buffer[5] = 0;
hdw->cmd_buffer[6] = (reg >> 8) & 0xff;
@@ -2825,7 +3008,7 @@ static int pvr2_read_register(struct pvr2_hdw *hdw, u16 reg, u32 *data)
LOCK_TAKE(hdw->ctl_lock);
- hdw->cmd_buffer[0] = 0x05; /* read register prefix */
+ hdw->cmd_buffer[0] = FX2CMD_REG_READ; /* read register prefix */
hdw->cmd_buffer[1] = 0;
hdw->cmd_buffer[2] = 0;
hdw->cmd_buffer[3] = 0;
@@ -2843,39 +3026,6 @@ static int pvr2_read_register(struct pvr2_hdw *hdw, u16 reg, u32 *data)
}
-static int pvr2_write_u16(struct pvr2_hdw *hdw, u16 data, int res)
-{
- int ret;
-
- LOCK_TAKE(hdw->ctl_lock);
-
- hdw->cmd_buffer[0] = (data >> 8) & 0xff;
- hdw->cmd_buffer[1] = data & 0xff;
-
- ret = pvr2_send_request(hdw, hdw->cmd_buffer, 2, hdw->cmd_buffer, res);
-
- LOCK_GIVE(hdw->ctl_lock);
-
- return ret;
-}
-
-
-static int pvr2_write_u8(struct pvr2_hdw *hdw, u8 data, int res)
-{
- int ret;
-
- LOCK_TAKE(hdw->ctl_lock);
-
- hdw->cmd_buffer[0] = data;
-
- ret = pvr2_send_request(hdw, hdw->cmd_buffer, 1, hdw->cmd_buffer, res);
-
- LOCK_GIVE(hdw->ctl_lock);
-
- return ret;
-}
-
-
static void pvr2_hdw_render_useless_unlocked(struct pvr2_hdw *hdw)
{
if (!hdw->flag_ok) return;
@@ -2949,7 +3099,7 @@ int pvr2_hdw_cmd_deep_reset(struct pvr2_hdw *hdw)
LOCK_TAKE(hdw->ctl_lock); do {
pvr2_trace(PVR2_TRACE_INIT,"Requesting uproc hard reset");
hdw->flag_ok = !0;
- hdw->cmd_buffer[0] = 0xdd;
+ hdw->cmd_buffer[0] = FX2CMD_DEEP_RESET;
status = pvr2_send_request(hdw,hdw->cmd_buffer,1,NULL,0);
} while (0); LOCK_GIVE(hdw->ctl_lock);
return status;
@@ -2961,7 +3111,7 @@ int pvr2_hdw_cmd_powerup(struct pvr2_hdw *hdw)
int status;
LOCK_TAKE(hdw->ctl_lock); do {
pvr2_trace(PVR2_TRACE_INIT,"Requesting powerup");
- hdw->cmd_buffer[0] = 0xde;
+ hdw->cmd_buffer[0] = FX2CMD_POWER_ON;
status = pvr2_send_request(hdw,hdw->cmd_buffer,1,NULL,0);
} while (0); LOCK_GIVE(hdw->ctl_lock);
return status;
@@ -2994,7 +3144,8 @@ static int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl)
{
int status;
LOCK_TAKE(hdw->ctl_lock); do {
- hdw->cmd_buffer[0] = (runFl ? 0x36 : 0x37);
+ hdw->cmd_buffer[0] =
+ (runFl ? FX2CMD_STREAMING_ON : FX2CMD_STREAMING_OFF);
status = pvr2_send_request(hdw,hdw->cmd_buffer,1,NULL,0);
} while (0); LOCK_GIVE(hdw->ctl_lock);
if (!status) {
@@ -3093,7 +3244,7 @@ static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw)
{
int result;
LOCK_TAKE(hdw->ctl_lock); do {
- hdw->cmd_buffer[0] = 0xeb;
+ hdw->cmd_buffer[0] = FX2CMD_GET_EEPROM_ADDR;
result = pvr2_send_request(hdw,
hdw->cmd_buffer,1,
hdw->cmd_buffer,1);
@@ -3105,7 +3256,7 @@ static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw)
int pvr2_hdw_register_access(struct pvr2_hdw *hdw,
- u32 chip_id,unsigned long reg_id,
+ u32 chip_id, u64 reg_id,
int setFl,u32 *val_ptr)
{
#ifdef CONFIG_VIDEO_ADV_DEBUG
@@ -3115,6 +3266,8 @@ int pvr2_hdw_register_access(struct pvr2_hdw *hdw,
int stat = 0;
int okFl = 0;
+ if (!capable(CAP_SYS_ADMIN)) return -EPERM;
+
req.i2c_id = chip_id;
req.reg = reg_id;
if (setFl) req.val = *val_ptr;
@@ -3123,8 +3276,8 @@ int pvr2_hdw_register_access(struct pvr2_hdw *hdw,
cp = list_entry(item,struct pvr2_i2c_client,list);
if (cp->client->driver->id != chip_id) continue;
stat = pvr2_i2c_client_cmd(
- cp,(setFl ? VIDIOC_INT_S_REGISTER :
- VIDIOC_INT_G_REGISTER),&req);
+ cp,(setFl ? VIDIOC_DBG_S_REGISTER :
+ VIDIOC_DBG_G_REGISTER),&req);
if (!setFl) *val_ptr = req.val;
okFl = !0;
break;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/drivers/media/video/pvrusb2/pvrusb2-hdw.h
index 29979bb2a76..566a8ef7e12 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.h
@@ -44,12 +44,6 @@
#define PVR2_CVAL_INPUT_COMPOSITE 2
#define PVR2_CVAL_INPUT_RADIO 3
-/* Values that pvr2_hdw_get_signal_status() returns */
-#define PVR2_SIGNAL_OK 0x0001
-#define PVR2_SIGNAL_STEREO 0x0002
-#define PVR2_SIGNAL_SAP 0x0004
-
-
/* Subsystem definitions - these are various pieces that can be
independently stopped / started. Usually you don't want to mess with
this directly (let the driver handle things itself), but it is useful
@@ -72,10 +66,17 @@
PVR2_SUBSYS_RUN_ALL )
enum pvr2_config {
- pvr2_config_empty,
- pvr2_config_mpeg,
- pvr2_config_vbi,
- pvr2_config_radio,
+ pvr2_config_empty, /* No configuration */
+ pvr2_config_mpeg, /* Encoded / compressed video */
+ pvr2_config_vbi, /* Standard vbi info */
+ pvr2_config_pcm, /* Audio raw pcm stream */
+ pvr2_config_rawvideo, /* Video raw frames */
+};
+
+enum pvr2_v4l_type {
+ pvr2_v4l_type_video,
+ pvr2_v4l_type_vbi,
+ pvr2_v4l_type_radio,
};
const char *pvr2_config_get_name(enum pvr2_config);
@@ -148,8 +149,11 @@ int pvr2_hdw_commit_ctl(struct pvr2_hdw *);
/* Return name for this driver instance */
const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *);
-/* Return PVR2_SIGNAL_XXXX bit mask indicating signal status */
-unsigned int pvr2_hdw_get_signal_status(struct pvr2_hdw *);
+/* Mark tuner status stale so that it will be re-fetched */
+void pvr2_hdw_execute_tuner_poll(struct pvr2_hdw *);
+
+/* Return information about the tuner */
+int pvr2_hdw_get_tuner_status(struct pvr2_hdw *,struct v4l2_tuner *);
/* Query device and see if it thinks it is on a high-speed USB link */
int pvr2_hdw_is_hsm(struct pvr2_hdw *);
@@ -205,11 +209,12 @@ int pvr2_hdw_cpufw_get_enabled(struct pvr2_hdw *);
int pvr2_hdw_cpufw_get(struct pvr2_hdw *,unsigned int offs,
char *buf,unsigned int cnt);
-/* Retrieve previously stored v4l minor device number */
-int pvr2_hdw_v4l_get_minor_number(struct pvr2_hdw *);
+/* Retrieve a previously stored v4l minor device number */
+int pvr2_hdw_v4l_get_minor_number(struct pvr2_hdw *,enum pvr2_v4l_type index);
-/* Store the v4l minor device number */
-void pvr2_hdw_v4l_store_minor_number(struct pvr2_hdw *,int);
+/* Store a v4l minor device number */
+void pvr2_hdw_v4l_store_minor_number(struct pvr2_hdw *,
+ enum pvr2_v4l_type index,int);
/* Direct read/write access to chip's registers:
chip_id - unique id of chip (e.g. I2C_DRIVERD_xxxx)
@@ -217,7 +222,7 @@ void pvr2_hdw_v4l_store_minor_number(struct pvr2_hdw *,int);
setFl - true to set the register, false to read it
val_ptr - storage location for source / result. */
int pvr2_hdw_register_access(struct pvr2_hdw *,
- u32 chip_id,unsigned long reg_id,
+ u32 chip_id,u64 reg_id,
int setFl,u32 *val_ptr);
/* The following entry points are all lower level things you normally don't
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c
index 05121666b9b..49773764383 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c
@@ -33,15 +33,17 @@
#define trace_i2c(...) pvr2_trace(PVR2_TRACE_I2C,__VA_ARGS__)
#define OP_STANDARD 0
-#define OP_BCSH 1
-#define OP_VOLUME 2
-#define OP_FREQ 3
-#define OP_AUDIORATE 4
-#define OP_SIZE 5
-#define OP_LOG 6
+#define OP_AUDIOMODE 1
+#define OP_BCSH 2
+#define OP_VOLUME 3
+#define OP_FREQ 4
+#define OP_AUDIORATE 5
+#define OP_SIZE 6
+#define OP_LOG 7
static const struct pvr2_i2c_op * const ops[] = {
[OP_STANDARD] = &pvr2_i2c_op_v4l2_standard,
+ [OP_AUDIOMODE] = &pvr2_i2c_op_v4l2_audiomode,
[OP_BCSH] = &pvr2_i2c_op_v4l2_bcsh,
[OP_VOLUME] = &pvr2_i2c_op_v4l2_volume,
[OP_FREQ] = &pvr2_i2c_op_v4l2_frequency,
@@ -54,11 +56,13 @@ void pvr2_i2c_probe(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp)
int id;
id = cp->client->driver->id;
cp->ctl_mask = ((1 << OP_STANDARD) |
+ (1 << OP_AUDIOMODE) |
(1 << OP_BCSH) |
(1 << OP_VOLUME) |
(1 << OP_FREQ) |
(1 << OP_SIZE) |
(1 << OP_LOG));
+ cp->status_poll = pvr2_v4l2_cmd_status_poll;
if (id == I2C_DRIVERID_MSP3400) {
if (pvr2_i2c_msp3400_setup(hdw,cp)) {
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c
index 05ea17afe90..c650e02ccd0 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c
@@ -24,22 +24,26 @@
#include "pvrusb2-hdw-internal.h"
#include "pvrusb2-debug.h"
#include <linux/videodev2.h>
-
+#include <media/v4l2-common.h>
static void set_standard(struct pvr2_hdw *hdw)
{
- v4l2_std_id vs;
- vs = hdw->std_mask_cur;
- pvr2_trace(PVR2_TRACE_CHIPS,
- "i2c v4l2 set_standard(0x%llx)",(long long unsigned)vs);
-
- pvr2_i2c_core_cmd(hdw,VIDIOC_S_STD,&vs);
+ pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_standard");
+
+ if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
+ pvr2_i2c_core_cmd(hdw,AUDC_SET_RADIO,NULL);
+ } else {
+ v4l2_std_id vs;
+ vs = hdw->std_mask_cur;
+ pvr2_i2c_core_cmd(hdw,VIDIOC_S_STD,&vs);
+ }
+ hdw->tuner_signal_stale = !0;
}
static int check_standard(struct pvr2_hdw *hdw)
{
- return hdw->std_dirty != 0;
+ return (hdw->input_dirty != 0) || (hdw->std_dirty != 0);
}
@@ -136,16 +140,53 @@ const struct pvr2_i2c_op pvr2_i2c_op_v4l2_volume = {
};
+static void set_audiomode(struct pvr2_hdw *hdw)
+{
+ struct v4l2_tuner vt;
+ memset(&vt,0,sizeof(vt));
+ vt.audmode = hdw->audiomode_val;
+ pvr2_i2c_core_cmd(hdw,VIDIOC_S_TUNER,&vt);
+}
+
+
+static int check_audiomode(struct pvr2_hdw *hdw)
+{
+ return (hdw->input_dirty ||
+ hdw->audiomode_dirty);
+}
+
+
+const struct pvr2_i2c_op pvr2_i2c_op_v4l2_audiomode = {
+ .check = check_audiomode,
+ .update = set_audiomode,
+ .name = "v4l2_audiomode",
+};
+
+
static void set_frequency(struct pvr2_hdw *hdw)
{
unsigned long fv;
struct v4l2_frequency freq;
- fv = hdw->freqVal;
+ fv = pvr2_hdw_get_cur_freq(hdw);
pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_freq(%lu)",fv);
+ if (hdw->tuner_signal_stale) {
+ pvr2_i2c_core_status_poll(hdw);
+ }
memset(&freq,0,sizeof(freq));
- freq.frequency = fv / 62500;
+ if (hdw->tuner_signal_info.capability & V4L2_TUNER_CAP_LOW) {
+ // ((fv * 1000) / 62500)
+ freq.frequency = (fv * 2) / 125;
+ } else {
+ freq.frequency = fv / 62500;
+ }
+ /* tuner-core currently doesn't seem to care about this, but
+ let's set it anyway for completeness. */
+ if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
+ freq.type = V4L2_TUNER_RADIO;
+ } else {
+ freq.type = V4L2_TUNER_ANALOG_TV;
+ }
freq.tuner = 0;
- freq.type = V4L2_TUNER_ANALOG_TV;
pvr2_i2c_core_cmd(hdw,VIDIOC_S_FREQUENCY,&freq);
}
@@ -221,6 +262,12 @@ void pvr2_v4l2_cmd_stream(struct pvr2_i2c_client *cp,int fl)
}
+void pvr2_v4l2_cmd_status_poll(struct pvr2_i2c_client *cp)
+{
+ pvr2_i2c_client_cmd(cp,VIDIOC_G_TUNER,&cp->hdw->tuner_signal_info);
+}
+
+
/*
Stuff for Emacs to see, in order to encourage consistent editing style:
*** Local Variables: ***
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h b/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h
index ecabddba1ec..c838df6167f 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h
@@ -26,13 +26,16 @@
#include "pvrusb2-i2c-core.h"
extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_standard;
+extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_radio;
extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_bcsh;
extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_volume;
extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_frequency;
extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_size;
+extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_audiomode;
extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_log;
void pvr2_v4l2_cmd_stream(struct pvr2_i2c_client *,int);
+void pvr2_v4l2_cmd_status_poll(struct pvr2_i2c_client *);
#endif /* __PVRUSB2_CMD_V4L2_H */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
index f9bb41d8f4f..58fc3c730fe 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
@@ -22,6 +22,7 @@
#include "pvrusb2-i2c-core.h"
#include "pvrusb2-hdw-internal.h"
#include "pvrusb2-debug.h"
+#include "pvrusb2-fx2-cmd.h"
#define trace_i2c(...) pvr2_trace(PVR2_TRACE_I2C,__VA_ARGS__)
@@ -66,7 +67,7 @@ static int pvr2_i2c_write(struct pvr2_hdw *hdw, /* Context */
memset(hdw->cmd_buffer, 0, sizeof(hdw->cmd_buffer));
/* Set up command buffer for an I2C write */
- hdw->cmd_buffer[0] = 0x08; /* write prefix */
+ hdw->cmd_buffer[0] = FX2CMD_I2C_WRITE; /* write prefix */
hdw->cmd_buffer[1] = i2c_addr; /* i2c addr of chip */
hdw->cmd_buffer[2] = length; /* length of what follows */
if (length) memcpy(hdw->cmd_buffer + 3, data, length);
@@ -128,7 +129,7 @@ static int pvr2_i2c_read(struct pvr2_hdw *hdw, /* Context */
memset(hdw->cmd_buffer, 0, sizeof(hdw->cmd_buffer));
/* Set up command buffer for an I2C write followed by a read */
- hdw->cmd_buffer[0] = 0x09; /* read prefix */
+ hdw->cmd_buffer[0] = FX2CMD_I2C_READ; /* read prefix */
hdw->cmd_buffer[1] = dlen; /* arg length */
hdw->cmd_buffer[2] = rlen; /* answer length. Device will send one
more byte (status). */
@@ -221,7 +222,7 @@ static int i2c_24xxx_ir(struct pvr2_hdw *hdw,
/* Issue a command to the FX2 to read the IR receiver. */
LOCK_TAKE(hdw->ctl_lock); do {
- hdw->cmd_buffer[0] = 0xec;
+ hdw->cmd_buffer[0] = FX2CMD_GET_IR_CODE;
stat = pvr2_send_request(hdw,
hdw->cmd_buffer,1,
hdw->cmd_buffer,4);
@@ -590,6 +591,33 @@ static int handler_check(struct pvr2_i2c_client *cp)
#define BUFSIZE 500
+
+void pvr2_i2c_core_status_poll(struct pvr2_hdw *hdw)
+{
+ struct list_head *item;
+ struct pvr2_i2c_client *cp;
+ mutex_lock(&hdw->i2c_list_lock); do {
+ struct v4l2_tuner *vtp = &hdw->tuner_signal_info;
+ memset(vtp,0,sizeof(*vtp));
+ list_for_each(item,&hdw->i2c_clients) {
+ cp = list_entry(item,struct pvr2_i2c_client,list);
+ if (!cp->detected_flag) continue;
+ if (!cp->status_poll) continue;
+ cp->status_poll(cp);
+ }
+ hdw->tuner_signal_stale = 0;
+ pvr2_trace(PVR2_TRACE_CHIPS,"i2c status poll"
+ " type=%u strength=%u audio=0x%x cap=0x%x"
+ " low=%u hi=%u",
+ vtp->type,
+ vtp->signal,vtp->rxsubchans,vtp->capability,
+ vtp->rangelow,vtp->rangehigh);
+ } while (0); mutex_unlock(&hdw->i2c_list_lock);
+}
+
+
+/* Issue various I2C operations to bring chip-level drivers into sync with
+ state stored in this driver. */
void pvr2_i2c_core_sync(struct pvr2_hdw *hdw)
{
unsigned long msk;
@@ -870,12 +898,12 @@ static int pvr2_i2c_attach_inform(struct i2c_client *client)
struct pvr2_hdw *hdw = (struct pvr2_hdw *)(client->adapter->algo_data);
struct pvr2_i2c_client *cp;
int fl = !(hdw->i2c_pend_types & PVR2_I2C_PEND_ALL);
- cp = kmalloc(sizeof(*cp),GFP_KERNEL);
+ cp = kzalloc(sizeof(*cp),GFP_KERNEL);
trace_i2c("i2c_attach [client=%s @ 0x%x ctxt=%p]",
client->name,
client->addr,cp);
if (!cp) return -ENOMEM;
- memset(cp,0,sizeof(*cp));
+ cp->hdw = hdw;
INIT_LIST_HEAD(&cp->list);
cp->client = client;
mutex_lock(&hdw->i2c_list_lock); do {
@@ -948,8 +976,7 @@ static void do_i2c_scan(struct pvr2_hdw *hdw)
printk("%s: i2c scan beginning\n",hdw->name);
for (i = 0; i < 128; i++) {
msg[0].addr = i;
- rc = i2c_transfer(&hdw->i2c_adap,msg,
- sizeof(msg)/sizeof(msg[0]));
+ rc = i2c_transfer(&hdw->i2c_adap,msg, ARRAY_SIZE(msg));
if (rc != 1) continue;
printk("%s: i2c scan: found device @ 0x%x\n",hdw->name,i);
}
@@ -977,6 +1004,7 @@ void pvr2_i2c_core_init(struct pvr2_hdw *hdw)
memcpy(&hdw->i2c_adap,&pvr2_i2c_adap_template,sizeof(hdw->i2c_adap));
memcpy(&hdw->i2c_algo,&pvr2_i2c_algo_template,sizeof(hdw->i2c_algo));
strlcpy(hdw->i2c_adap.name,hdw->name,sizeof(hdw->i2c_adap.name));
+ hdw->i2c_adap.dev.parent = &hdw->usb_dev->dev;
hdw->i2c_adap.algo = &hdw->i2c_algo;
hdw->i2c_adap.algo_data = hdw;
hdw->i2c_pend_mask = 0;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h
index 6d7e2524757..bd0807b905b 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h
@@ -35,10 +35,12 @@ struct pvr2_i2c_client {
struct i2c_client *client;
struct pvr2_i2c_handler *handler;
struct list_head list;
+ struct pvr2_hdw *hdw;
int detected_flag;
int recv_enable;
unsigned long pend_mask;
unsigned long ctl_mask;
+ void (*status_poll)(struct pvr2_i2c_client *);
};
struct pvr2_i2c_handler {
@@ -67,6 +69,7 @@ int pvr2_i2c_core_cmd(struct pvr2_hdw *,unsigned int cmd,void *arg);
int pvr2_i2c_core_check_stale(struct pvr2_hdw *);
void pvr2_i2c_core_sync(struct pvr2_hdw *);
+void pvr2_i2c_core_status_poll(struct pvr2_hdw *);
unsigned int pvr2_i2c_report(struct pvr2_hdw *,char *buf,unsigned int maxlen);
#define PVR2_I2C_DETAIL_DEBUG 0x0001
#define PVR2_I2C_DETAIL_HANDLER 0x0002
diff --git a/drivers/media/video/pvrusb2/pvrusb2-io.c b/drivers/media/video/pvrusb2/pvrusb2-io.c
index 57fb3203354..ce3c8982ffe 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-io.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-io.c
@@ -474,9 +474,8 @@ static void buffer_complete(struct urb *urb)
struct pvr2_stream *pvr2_stream_create(void)
{
struct pvr2_stream *sp;
- sp = kmalloc(sizeof(*sp),GFP_KERNEL);
+ sp = kzalloc(sizeof(*sp),GFP_KERNEL);
if (!sp) return sp;
- memset(sp,0,sizeof(*sp));
pvr2_trace(PVR2_TRACE_INIT,"pvr2_stream_create: sp=%p",sp);
pvr2_stream_init(sp);
return sp;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-ioread.c b/drivers/media/video/pvrusb2/pvrusb2-ioread.c
index b71f9a961f8..f782418afa4 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-ioread.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-ioread.c
@@ -87,10 +87,9 @@ static void pvr2_ioread_done(struct pvr2_ioread *cp)
struct pvr2_ioread *pvr2_ioread_create(void)
{
struct pvr2_ioread *cp;
- cp = kmalloc(sizeof(*cp),GFP_KERNEL);
+ cp = kzalloc(sizeof(*cp),GFP_KERNEL);
if (!cp) return NULL;
pvr2_trace(PVR2_TRACE_STRUCT,"pvr2_ioread_create id=%p",cp);
- memset(cp,0,sizeof(*cp));
if (pvr2_ioread_init(cp) < 0) {
kfree(cp);
return NULL;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-std.c b/drivers/media/video/pvrusb2/pvrusb2-std.c
index f95c598ff62..81de26ba41d 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-std.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-std.c
@@ -78,14 +78,14 @@ struct std_name {
#define CSTD_ALL (CSTD_PAL|CSTD_NTSC|CSTD_SECAM)
/* Mapping of standard bits to color system */
-const static struct std_name std_groups[] = {
+static const struct std_name std_groups[] = {
{"PAL",CSTD_PAL},
{"NTSC",CSTD_NTSC},
{"SECAM",CSTD_SECAM},
};
/* Mapping of standard bits to modulation system */
-const static struct std_name std_items[] = {
+static const struct std_name std_items[] = {
{"B",TSTD_B},
{"B1",TSTD_B1},
{"D",TSTD_D},
@@ -141,10 +141,8 @@ int pvr2_std_str_to_id(v4l2_std_id *idPtr,const char *bufPtr,
cnt = 0;
while ((cnt < bufSize) && (bufPtr[cnt] != '-')) cnt++;
if (cnt >= bufSize) return 0; // No more characters
- sp = find_std_name(
- std_groups,
- sizeof(std_groups)/sizeof(std_groups[0]),
- bufPtr,cnt);
+ sp = find_std_name(std_groups, ARRAY_SIZE(std_groups),
+ bufPtr,cnt);
if (!sp) return 0; // Illegal color system name
cnt++;
bufPtr += cnt;
@@ -163,8 +161,7 @@ int pvr2_std_str_to_id(v4l2_std_id *idPtr,const char *bufPtr,
if (ch == '/') break;
cnt++;
}
- sp = find_std_name(std_items,
- sizeof(std_items)/sizeof(std_items[0]),
+ sp = find_std_name(std_items, ARRAY_SIZE(std_items),
bufPtr,cnt);
if (!sp) return 0; // Illegal modulation system ID
t = sp->id & cmsk;
@@ -189,14 +186,10 @@ unsigned int pvr2_std_id_to_str(char *bufPtr, unsigned int bufSize,
unsigned int c1,c2;
cfl = 0;
c1 = 0;
- for (idx1 = 0;
- idx1 < sizeof(std_groups)/sizeof(std_groups[0]);
- idx1++) {
+ for (idx1 = 0; idx1 < ARRAY_SIZE(std_groups); idx1++) {
gp = std_groups + idx1;
gfl = 0;
- for (idx2 = 0;
- idx2 < sizeof(std_items)/sizeof(std_items[0]);
- idx2++) {
+ for (idx2 = 0; idx2 < ARRAY_SIZE(std_items); idx2++) {
ip = std_items + idx2;
if (!(gp->id & ip->id & id)) continue;
if (!gfl) {
@@ -279,7 +272,7 @@ static struct v4l2_standard generic_standards[] = {
}
};
-#define generic_standards_cnt (sizeof(generic_standards)/sizeof(generic_standards[0]))
+#define generic_standards_cnt ARRAY_SIZE(generic_standards)
static struct v4l2_standard *match_std(v4l2_std_id id)
{
@@ -348,7 +341,7 @@ struct v4l2_standard *pvr2_std_create_enum(unsigned int *countptr,
fmsk |= idmsk;
}
- for (idx2 = 0; idx2 < sizeof(std_mixes)/sizeof(std_mixes[0]); idx2++) {
+ for (idx2 = 0; idx2 < ARRAY_SIZE(std_mixes); idx2++) {
if ((id & std_mixes[idx2]) == std_mixes[idx2]) std_cnt++;
}
@@ -366,16 +359,15 @@ struct v4l2_standard *pvr2_std_create_enum(unsigned int *countptr,
std_cnt);
if (!std_cnt) return NULL; // paranoia
- stddefs = kmalloc(sizeof(struct v4l2_standard) * std_cnt,
+ stddefs = kzalloc(sizeof(struct v4l2_standard) * std_cnt,
GFP_KERNEL);
- memset(stddefs,0,sizeof(struct v4l2_standard) * std_cnt);
for (idx = 0; idx < std_cnt; idx++) stddefs[idx].index = idx;
idx = 0;
/* Enumerate potential special cases */
- for (idx2 = 0; ((idx2 < sizeof(std_mixes)/sizeof(std_mixes[0])) &&
- (idx < std_cnt)); idx2++) {
+ for (idx2 = 0; (idx2 < ARRAY_SIZE(std_mixes)) && (idx < std_cnt);
+ idx2++) {
if (!(id & std_mixes[idx2])) continue;
if (pvr2_std_fill(stddefs+idx,std_mixes[idx2])) idx++;
}
diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
index c294f46db9b..91396fd573e 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
@@ -40,8 +40,10 @@ struct pvr2_sysfs {
struct pvr2_sysfs_ctl_item *item_first;
struct pvr2_sysfs_ctl_item *item_last;
struct class_device_attribute attr_v4l_minor_number;
+ struct class_device_attribute attr_v4l_radio_minor_number;
struct class_device_attribute attr_unit_number;
int v4l_minor_number_created_ok;
+ int v4l_radio_minor_number_created_ok;
int unit_number_created_ok;
};
@@ -491,7 +493,7 @@ static void pvr2_sysfs_add_control(struct pvr2_sysfs *sfp,int ctl_id)
unsigned int cnt,acnt;
int ret;
- if ((ctl_id < 0) || (ctl_id >= (sizeof(funcs)/sizeof(funcs[0])))) {
+ if ((ctl_id < 0) || (ctl_id >= ARRAY_SIZE(funcs))) {
return;
}
@@ -499,9 +501,8 @@ static void pvr2_sysfs_add_control(struct pvr2_sysfs *sfp,int ctl_id)
cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,ctl_id);
if (!cptr) return;
- cip = kmalloc(sizeof(*cip),GFP_KERNEL);
+ cip = kzalloc(sizeof(*cip),GFP_KERNEL);
if (!cip) return;
- memset(cip,0,sizeof(*cip));
pvr2_sysfs_trace("Creating pvr2_sysfs_ctl_item id=%p",cip);
cip->cptr = cptr;
@@ -611,9 +612,8 @@ static void pvr2_sysfs_add_debugifc(struct pvr2_sysfs *sfp)
struct pvr2_sysfs_debugifc *dip;
int ret;
- dip = kmalloc(sizeof(*dip),GFP_KERNEL);
+ dip = kzalloc(sizeof(*dip),GFP_KERNEL);
if (!dip) return;
- memset(dip,0,sizeof(*dip));
dip->attr_debugcmd.attr.owner = THIS_MODULE;
dip->attr_debugcmd.attr.name = "debugcmd";
dip->attr_debugcmd.attr.mode = S_IRUGO|S_IWUSR|S_IWGRP;
@@ -709,6 +709,10 @@ static void class_dev_destroy(struct pvr2_sysfs *sfp)
class_device_remove_file(sfp->class_dev,
&sfp->attr_v4l_minor_number);
}
+ if (sfp->v4l_radio_minor_number_created_ok) {
+ class_device_remove_file(sfp->class_dev,
+ &sfp->attr_v4l_radio_minor_number);
+ }
if (sfp->unit_number_created_ok) {
class_device_remove_file(sfp->class_dev,
&sfp->attr_unit_number);
@@ -726,7 +730,20 @@ static ssize_t v4l_minor_number_show(struct class_device *class_dev,char *buf)
sfp = (struct pvr2_sysfs *)class_dev->class_data;
if (!sfp) return -EINVAL;
return scnprintf(buf,PAGE_SIZE,"%d\n",
- pvr2_hdw_v4l_get_minor_number(sfp->channel.hdw));
+ pvr2_hdw_v4l_get_minor_number(sfp->channel.hdw,
+ pvr2_v4l_type_video));
+}
+
+
+static ssize_t v4l_radio_minor_number_show(struct class_device *class_dev,
+ char *buf)
+{
+ struct pvr2_sysfs *sfp;
+ sfp = (struct pvr2_sysfs *)class_dev->class_data;
+ if (!sfp) return -EINVAL;
+ return scnprintf(buf,PAGE_SIZE,"%d\n",
+ pvr2_hdw_v4l_get_minor_number(sfp->channel.hdw,
+ pvr2_v4l_type_radio));
}
@@ -749,9 +766,8 @@ static void class_dev_create(struct pvr2_sysfs *sfp,
usb_dev = pvr2_hdw_get_dev(sfp->channel.hdw);
if (!usb_dev) return;
- class_dev = kmalloc(sizeof(*class_dev),GFP_KERNEL);
+ class_dev = kzalloc(sizeof(*class_dev),GFP_KERNEL);
if (!class_dev) return;
- memset(class_dev,0,sizeof(*class_dev));
pvr2_sysfs_trace("Creating class_dev id=%p",class_dev);
@@ -793,6 +809,20 @@ static void class_dev_create(struct pvr2_sysfs *sfp,
sfp->v4l_minor_number_created_ok = !0;
}
+ sfp->attr_v4l_radio_minor_number.attr.owner = THIS_MODULE;
+ sfp->attr_v4l_radio_minor_number.attr.name = "v4l_radio_minor_number";
+ sfp->attr_v4l_radio_minor_number.attr.mode = S_IRUGO;
+ sfp->attr_v4l_radio_minor_number.show = v4l_radio_minor_number_show;
+ sfp->attr_v4l_radio_minor_number.store = NULL;
+ ret = class_device_create_file(sfp->class_dev,
+ &sfp->attr_v4l_radio_minor_number);
+ if (ret < 0) {
+ printk(KERN_WARNING "%s: class_device_create_file error: %d\n",
+ __FUNCTION__, ret);
+ } else {
+ sfp->v4l_radio_minor_number_created_ok = !0;
+ }
+
sfp->attr_unit_number.attr.owner = THIS_MODULE;
sfp->attr_unit_number.attr.name = "unit_number";
sfp->attr_unit_number.attr.mode = S_IRUGO;
@@ -829,9 +859,8 @@ struct pvr2_sysfs *pvr2_sysfs_create(struct pvr2_context *mp,
struct pvr2_sysfs_class *class_ptr)
{
struct pvr2_sysfs *sfp;
- sfp = kmalloc(sizeof(*sfp),GFP_KERNEL);
+ sfp = kzalloc(sizeof(*sfp),GFP_KERNEL);
if (!sfp) return sfp;
- memset(sfp,0,sizeof(*sfp));
pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr2_sysfs id=%p",sfp);
pvr2_channel_init(&sfp->channel,mp);
sfp->channel.check_func = pvr2_sysfs_internal_check;
@@ -852,9 +881,8 @@ static int pvr2_sysfs_hotplug(struct class_device *cd,char **envp,
struct pvr2_sysfs_class *pvr2_sysfs_class_create(void)
{
struct pvr2_sysfs_class *clp;
- clp = kmalloc(sizeof(*clp),GFP_KERNEL);
+ clp = kzalloc(sizeof(*clp),GFP_KERNEL);
if (!clp) return clp;
- memset(clp,0,sizeof(*clp));
pvr2_sysfs_trace("Creating pvr2_sysfs_class id=%p",clp);
clp->class.name = "pvrusb2";
clp->class.class_release = pvr2_sysfs_class_release;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-tuner.c b/drivers/media/video/pvrusb2/pvrusb2-tuner.c
index af9f246f8d3..05e65ce2e3a 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-tuner.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-tuner.c
@@ -80,7 +80,7 @@ static unsigned int pvr2_tuner_describe(struct pvr2_tuner_handler *ctxt,char *bu
}
-const static struct pvr2_i2c_handler_functions tuner_funcs = {
+static const struct pvr2_i2c_handler_functions tuner_funcs = {
.detach = (void (*)(void *))pvr2_tuner_detach,
.check = (int (*)(void *))tuner_check,
.update = (void (*)(void *))tuner_update,
@@ -93,9 +93,8 @@ int pvr2_i2c_tuner_setup(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp)
struct pvr2_tuner_handler *ctxt;
if (cp->handler) return 0;
- ctxt = kmalloc(sizeof(*ctxt),GFP_KERNEL);
+ ctxt = kzalloc(sizeof(*ctxt),GFP_KERNEL);
if (!ctxt) return 0;
- memset(ctxt,0,sizeof(*ctxt));
ctxt->i2c_handler.func_data = ctxt;
ctxt->i2c_handler.func_table = &tuner_funcs;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
index bb40e908597..4fe4136204c 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
@@ -40,7 +40,10 @@ struct pvr2_v4l2_dev {
struct video_device devbase; /* MUST be first! */
struct pvr2_v4l2 *v4lp;
struct pvr2_context_stream *stream;
- enum pvr2_config config;
+ /* Information about this device: */
+ enum pvr2_config config; /* Expected stream format */
+ int v4l_type; /* V4L defined type for this device node */
+ enum pvr2_v4l_type minor_type; /* pvr2-understood minor device type */
};
struct pvr2_v4l2_fh {
@@ -54,6 +57,7 @@ struct pvr2_v4l2_fh {
struct pvr2_v4l2_fh *vprev;
wait_queue_head_t wait_data;
int fw_mode_flag;
+ int prev_input_val;
};
struct pvr2_v4l2 {
@@ -63,13 +67,22 @@ struct pvr2_v4l2 {
struct v4l2_prio_state prio;
- /* streams */
- struct pvr2_v4l2_dev *vdev;
+ /* streams - Note that these must be separately, individually,
+ * allocated pointers. This is because the v4l core is going to
+ * manage their deletion - separately, individually... */
+ struct pvr2_v4l2_dev *dev_video;
+ struct pvr2_v4l2_dev *dev_radio;
};
static int video_nr[PVR_NUM] = {[0 ... PVR_NUM-1] = -1};
module_param_array(video_nr, int, NULL, 0444);
-MODULE_PARM_DESC(video_nr, "Offset for device's minor");
+MODULE_PARM_DESC(video_nr, "Offset for device's video dev minor");
+static int radio_nr[PVR_NUM] = {[0 ... PVR_NUM-1] = -1};
+module_param_array(radio_nr, int, NULL, 0444);
+MODULE_PARM_DESC(radio_nr, "Offset for device's radio dev minor");
+static int vbi_nr[PVR_NUM] = {[0 ... PVR_NUM-1] = -1};
+module_param_array(vbi_nr, int, NULL, 0444);
+MODULE_PARM_DESC(vbi_nr, "Offset for device's vbi dev minor");
static struct v4l2_capability pvr_capability ={
.driver = "pvrusb2",
@@ -77,30 +90,11 @@ static struct v4l2_capability pvr_capability ={
.bus_info = "usb",
.version = KERNEL_VERSION(0,8,0),
.capabilities = (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VBI_CAPTURE |
- V4L2_CAP_TUNER | V4L2_CAP_AUDIO |
+ V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_RADIO |
V4L2_CAP_READWRITE),
.reserved = {0,0,0,0}
};
-static struct v4l2_tuner pvr_v4l2_tuners[]= {
- {
- .index = 0,
- .name = "TV Tuner",
- .type = V4L2_TUNER_ANALOG_TV,
- .capability = (V4L2_TUNER_CAP_NORM |
- V4L2_TUNER_CAP_STEREO |
- V4L2_TUNER_CAP_LANG1 |
- V4L2_TUNER_CAP_LANG2),
- .rangelow = 0,
- .rangehigh = 0,
- .rxsubchans = V4L2_TUNER_SUB_STEREO,
- .audmode = V4L2_TUNER_MODE_STEREO,
- .signal = 0,
- .afc = 0,
- .reserved = {0,0,0,0}
- }
-};
-
static struct v4l2_fmtdesc pvr_fmtdesc [] = {
{
.index = 0,
@@ -154,6 +148,18 @@ static struct v4l2_format pvr_format [] = {
}
};
+
+static const char *get_v4l_name(int v4l_type)
+{
+ switch (v4l_type) {
+ case VFL_TYPE_GRABBER: return "video";
+ case VFL_TYPE_RADIO: return "radio";
+ case VFL_TYPE_VBI: return "vbi";
+ default: return "?";
+ }
+}
+
+
/*
* pvr_ioctl()
*
@@ -315,13 +321,39 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
case VIDIOC_ENUMAUDIO:
{
+ /* pkt: FIXME: We are returning one "fake" input here
+ which could very well be called "whatever_we_like".
+ This is for apps that want to see an audio input
+ just to feel comfortable, as well as to test if
+ it can do stereo or sth. There is actually no guarantee
+ that the actual audio input cannot change behind the app's
+ back, but most applications should not mind that either.
+
+ Hopefully, mplayer people will work with us on this (this
+ whole mess is to support mplayer pvr://), or Hans will come
+ up with a more standard way to say "we have inputs but we
+ don 't want you to change them independent of video" which
+ will sort this mess.
+ */
+ struct v4l2_audio *vin = arg;
ret = -EINVAL;
+ if (vin->index > 0) break;
+ strncpy(vin->name, "PVRUSB2 Audio",14);
+ vin->capability = V4L2_AUDCAP_STEREO;
+ ret = 0;
+ break;
break;
}
case VIDIOC_G_AUDIO:
{
- ret = -EINVAL;
+ /* pkt: FIXME: see above comment (VIDIOC_ENUMAUDIO) */
+ struct v4l2_audio *vin = arg;
+ memset(vin,0,sizeof(*vin));
+ vin->index = 0;
+ strncpy(vin->name, "PVRUSB2 Audio",14);
+ vin->capability = V4L2_AUDCAP_STEREO;
+ ret = 0;
break;
}
@@ -333,34 +365,11 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
case VIDIOC_G_TUNER:
{
struct v4l2_tuner *vt = (struct v4l2_tuner *)arg;
- unsigned int status_mask;
- int val;
- if (vt->index !=0) break;
- status_mask = pvr2_hdw_get_signal_status(hdw);
+ if (vt->index != 0) break; /* Only answer for the 1st tuner */
- memcpy(vt, &pvr_v4l2_tuners[vt->index],
- sizeof(struct v4l2_tuner));
-
- vt->signal = 0;
- if (status_mask & PVR2_SIGNAL_OK) {
- if (status_mask & PVR2_SIGNAL_STEREO) {
- vt->rxsubchans = V4L2_TUNER_SUB_STEREO;
- } else {
- vt->rxsubchans = V4L2_TUNER_SUB_MONO;
- }
- if (status_mask & PVR2_SIGNAL_SAP) {
- vt->rxsubchans |= (V4L2_TUNER_SUB_LANG1 |
- V4L2_TUNER_SUB_LANG2);
- }
- vt->signal = 65535;
- }
-
- val = 0;
- ret = pvr2_ctrl_get_value(
- pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_AUDIOMODE),
- &val);
- vt->audmode = val;
+ pvr2_hdw_execute_tuner_poll(hdw);
+ ret = pvr2_hdw_get_tuner_status(hdw,vt);
break;
}
@@ -374,14 +383,40 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
ret = pvr2_ctrl_set_value(
pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_AUDIOMODE),
vt->audmode);
+ break;
}
case VIDIOC_S_FREQUENCY:
{
const struct v4l2_frequency *vf = (struct v4l2_frequency *)arg;
+ unsigned long fv;
+ struct v4l2_tuner vt;
+ int cur_input;
+ struct pvr2_ctrl *ctrlp;
+ ret = pvr2_hdw_get_tuner_status(hdw,&vt);
+ if (ret != 0) break;
+ ctrlp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
+ ret = pvr2_ctrl_get_value(ctrlp,&cur_input);
+ if (ret != 0) break;
+ if (vf->type == V4L2_TUNER_RADIO) {
+ if (cur_input != PVR2_CVAL_INPUT_RADIO) {
+ pvr2_ctrl_set_value(ctrlp,
+ PVR2_CVAL_INPUT_RADIO);
+ }
+ } else {
+ if (cur_input == PVR2_CVAL_INPUT_RADIO) {
+ pvr2_ctrl_set_value(ctrlp,
+ PVR2_CVAL_INPUT_TV);
+ }
+ }
+ fv = vf->frequency;
+ if (vt.capability & V4L2_TUNER_CAP_LOW) {
+ fv = (fv * 125) / 2;
+ } else {
+ fv = fv * 62500;
+ }
ret = pvr2_ctrl_set_value(
- pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_FREQUENCY),
- vf->frequency * 62500);
+ pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_FREQUENCY),fv);
break;
}
@@ -389,10 +424,27 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
{
struct v4l2_frequency *vf = (struct v4l2_frequency *)arg;
int val = 0;
+ int cur_input;
+ struct v4l2_tuner vt;
+ ret = pvr2_hdw_get_tuner_status(hdw,&vt);
+ if (ret != 0) break;
ret = pvr2_ctrl_get_value(
pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_FREQUENCY),
&val);
- val /= 62500;
+ if (ret != 0) break;
+ pvr2_ctrl_get_value(
+ pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT),
+ &cur_input);
+ if (cur_input == PVR2_CVAL_INPUT_RADIO) {
+ vf->type = V4L2_TUNER_RADIO;
+ } else {
+ vf->type = V4L2_TUNER_ANALOG_TV;
+ }
+ if (vt.capability & V4L2_TUNER_CAP_LOW) {
+ val = (val * 2) / 125;
+ } else {
+ val /= 62500;
+ }
vf->frequency = val;
break;
}
@@ -449,7 +501,7 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
ret = 0;
switch(vf->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
- int lmin,lmax;
+ int lmin,lmax,ldef;
struct pvr2_ctrl *hcp,*vcp;
int h = vf->fmt.pix.height;
int w = vf->fmt.pix.width;
@@ -458,14 +510,20 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
lmin = pvr2_ctrl_get_min(hcp);
lmax = pvr2_ctrl_get_max(hcp);
- if (w < lmin) {
+ ldef = pvr2_ctrl_get_def(hcp);
+ if (w == -1) {
+ w = ldef;
+ } else if (w < lmin) {
w = lmin;
} else if (w > lmax) {
w = lmax;
}
lmin = pvr2_ctrl_get_min(vcp);
lmax = pvr2_ctrl_get_max(vcp);
- if (h < lmin) {
+ ldef = pvr2_ctrl_get_def(vcp);
+ if (h == -1) {
+ h = ldef;
+ } else if (h < lmin) {
h = lmin;
} else if (h > lmax) {
h = lmax;
@@ -494,6 +552,13 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
case VIDIOC_STREAMON:
{
+ if (!fh->dev_info->stream) {
+ /* No stream defined for this node. This means
+ that we're not currently allowed to stream from
+ this node. */
+ ret = -EPERM;
+ break;
+ }
ret = pvr2_hdw_set_stream_type(hdw,dev_info->config);
if (ret < 0) return ret;
ret = pvr2_hdw_set_streaming(hdw,!0);
@@ -502,6 +567,13 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
case VIDIOC_STREAMOFF:
{
+ if (!fh->dev_info->stream) {
+ /* No stream defined for this node. This means
+ that we're not currently allowed to stream from
+ this node. */
+ ret = -EPERM;
+ break;
+ }
ret = pvr2_hdw_set_streaming(hdw,0);
break;
}
@@ -599,6 +671,7 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
struct v4l2_ext_control *ctrl;
unsigned int idx;
int val;
+ ret = 0;
for (idx = 0; idx < ctls->count; idx++) {
ctrl = ctls->controls + idx;
ret = pvr2_ctrl_get_value(
@@ -621,6 +694,7 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
(struct v4l2_ext_controls *)arg;
struct v4l2_ext_control *ctrl;
unsigned int idx;
+ ret = 0;
for (idx = 0; idx < ctls->count; idx++) {
ctrl = ctls->controls + idx;
ret = pvr2_ctrl_set_value(
@@ -643,6 +717,7 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
unsigned int idx;
/* For the moment just validate that the requested control
actually exists. */
+ ret = 0;
for (idx = 0; idx < ctls->count; idx++) {
ctrl = ctls->controls + idx;
pctl = pvr2_hdw_get_ctrl_v4l(hdw,ctrl->id);
@@ -662,16 +737,16 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
break;
}
#ifdef CONFIG_VIDEO_ADV_DEBUG
- case VIDIOC_INT_G_REGISTER:
- case VIDIOC_INT_S_REGISTER:
+ case VIDIOC_DBG_S_REGISTER:
+ case VIDIOC_DBG_G_REGISTER:
{
u32 val;
struct v4l2_register *req = (struct v4l2_register *)arg;
- if (cmd == VIDIOC_INT_S_REGISTER) val = req->val;
+ if (cmd == VIDIOC_DBG_S_REGISTER) val = req->val;
ret = pvr2_hdw_register_access(
hdw,req->i2c_id,req->reg,
- cmd == VIDIOC_INT_S_REGISTER,&val);
- if (cmd == VIDIOC_INT_G_REGISTER) req->val = val;
+ cmd == VIDIOC_DBG_S_REGISTER,&val);
+ if (cmd == VIDIOC_DBG_G_REGISTER) req->val = val;
break;
}
#endif
@@ -707,8 +782,12 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip)
{
- printk(KERN_INFO "pvrusb2: unregistering device video%d [%s]\n",
- dip->devbase.minor,pvr2_config_get_name(dip->config));
+ int minor_id = dip->devbase.minor;
+ struct pvr2_hdw *hdw = dip->v4lp->channel.mc_head->hdw;
+ enum pvr2_config cfg = dip->config;
+ int v4l_type = dip->v4l_type;
+
+ pvr2_hdw_v4l_store_minor_number(hdw,dip->minor_type,-1);
/* Paranoia */
dip->v4lp = NULL;
@@ -717,13 +796,24 @@ static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip)
/* Actual deallocation happens later when all internal references
are gone. */
video_unregister_device(&dip->devbase);
+
+ printk(KERN_INFO "pvrusb2: unregistered device %s%u [%s]\n",
+ get_v4l_name(v4l_type),minor_id & 0x1f,
+ pvr2_config_get_name(cfg));
+
}
static void pvr2_v4l2_destroy_no_lock(struct pvr2_v4l2 *vp)
{
- pvr2_hdw_v4l_store_minor_number(vp->channel.mc_head->hdw,-1);
- pvr2_v4l2_dev_destroy(vp->vdev);
+ if (vp->dev_video) {
+ pvr2_v4l2_dev_destroy(vp->dev_video);
+ vp->dev_video = 0;
+ }
+ if (vp->dev_radio) {
+ pvr2_v4l2_dev_destroy(vp->dev_radio);
+ vp->dev_radio = 0;
+ }
pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr2_v4l2 id=%p",vp);
pvr2_channel_done(&vp->channel);
@@ -766,23 +856,37 @@ static int pvr2_v4l2_release(struct inode *inode, struct file *file)
struct pvr2_v4l2_fh *fhp = file->private_data;
struct pvr2_v4l2 *vp = fhp->vhead;
struct pvr2_context *mp = fhp->vhead->channel.mc_head;
+ struct pvr2_hdw *hdw = fhp->channel.mc_head->hdw;
pvr2_trace(PVR2_TRACE_OPEN_CLOSE,"pvr2_v4l2_release");
if (fhp->rhp) {
struct pvr2_stream *sp;
- struct pvr2_hdw *hdw;
- hdw = fhp->channel.mc_head->hdw;
pvr2_hdw_set_streaming(hdw,0);
sp = pvr2_ioread_get_stream(fhp->rhp);
if (sp) pvr2_stream_set_callback(sp,NULL,NULL);
pvr2_ioread_destroy(fhp->rhp);
fhp->rhp = NULL;
}
+
v4l2_prio_close(&vp->prio, &fhp->prio);
file->private_data = NULL;
pvr2_context_enter(mp); do {
+ /* Restore the previous input selection, if it makes sense
+ to do so. */
+ if (fhp->dev_info->v4l_type == VFL_TYPE_RADIO) {
+ struct pvr2_ctrl *cp;
+ int pval;
+ cp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
+ pvr2_ctrl_get_value(cp,&pval);
+ /* Only restore if we're still selecting the radio */
+ if (pval == PVR2_CVAL_INPUT_RADIO) {
+ pvr2_ctrl_set_value(cp,fhp->prev_input_val);
+ pvr2_hdw_commit_ctl(hdw);
+ }
+ }
+
if (fhp->vnext) {
fhp->vnext->vprev = fhp->vprev;
} else {
@@ -828,11 +932,10 @@ static int pvr2_v4l2_open(struct inode *inode, struct file *file)
return -EIO;
}
- fhp = kmalloc(sizeof(*fhp),GFP_KERNEL);
+ fhp = kzalloc(sizeof(*fhp),GFP_KERNEL);
if (!fhp) {
return -ENOMEM;
}
- memset(fhp,0,sizeof(*fhp));
init_waitqueue_head(&fhp->wait_data);
fhp->dev_info = dip;
@@ -840,6 +943,7 @@ static int pvr2_v4l2_open(struct inode *inode, struct file *file)
pvr2_context_enter(vp->channel.mc_head); do {
pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr_v4l2_fh id=%p",fhp);
pvr2_channel_init(&fhp->channel,vp->channel.mc_head);
+
fhp->vnext = NULL;
fhp->vprev = vp->vlast;
if (vp->vlast) {
@@ -849,6 +953,18 @@ static int pvr2_v4l2_open(struct inode *inode, struct file *file)
}
vp->vlast = fhp;
fhp->vhead = vp;
+
+ /* Opening the /dev/radioX device implies a mode switch.
+ So execute that here. Note that you can get the
+ IDENTICAL effect merely by opening the normal video
+ device and setting the input appropriately. */
+ if (dip->v4l_type == VFL_TYPE_RADIO) {
+ struct pvr2_ctrl *cp;
+ cp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
+ pvr2_ctrl_get_value(cp,&fhp->prev_input_val);
+ pvr2_ctrl_set_value(cp,PVR2_CVAL_INPUT_RADIO);
+ pvr2_hdw_commit_ctl(hdw);
+ }
} while (0); pvr2_context_exit(vp->channel.mc_head);
fhp->file = file;
@@ -873,6 +989,12 @@ static int pvr2_v4l2_iosetup(struct pvr2_v4l2_fh *fh)
struct pvr2_hdw *hdw;
if (fh->rhp) return 0;
+ if (!fh->dev_info->stream) {
+ /* No stream defined for this node. This means that we're
+ not currently allowed to stream from this node. */
+ return -EPERM;
+ }
+
/* First read() attempt. Try to claim the stream and start
it... */
if ((ret = pvr2_channel_claim_stream(&fh->channel,
@@ -986,7 +1108,7 @@ static unsigned int pvr2_v4l2_poll(struct file *file, poll_table *wait)
}
-static struct file_operations vdev_fops = {
+static const struct file_operations vdev_fops = {
.owner = THIS_MODULE,
.open = pvr2_v4l2_open,
.release = pvr2_v4l2_release,
@@ -1012,25 +1134,37 @@ static struct video_device vdev_template = {
static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
struct pvr2_v4l2 *vp,
- enum pvr2_config cfg)
+ int v4l_type)
{
int mindevnum;
int unit_number;
- int v4l_type;
+ int *nr_ptr = 0;
dip->v4lp = vp;
- dip->config = cfg;
- switch (cfg) {
- case pvr2_config_mpeg:
- v4l_type = VFL_TYPE_GRABBER;
+ dip->v4l_type = v4l_type;
+ switch (v4l_type) {
+ case VFL_TYPE_GRABBER:
dip->stream = &vp->channel.mc_head->video_stream;
+ dip->config = pvr2_config_mpeg;
+ dip->minor_type = pvr2_v4l_type_video;
+ nr_ptr = video_nr;
+ if (!dip->stream) {
+ err("Failed to set up pvrusb2 v4l video dev"
+ " due to missing stream instance");
+ return;
+ }
break;
- case pvr2_config_vbi:
- v4l_type = VFL_TYPE_VBI;
+ case VFL_TYPE_VBI:
+ dip->config = pvr2_config_vbi;
+ dip->minor_type = pvr2_v4l_type_vbi;
+ nr_ptr = vbi_nr;
break;
- case pvr2_config_radio:
- v4l_type = VFL_TYPE_RADIO;
+ case VFL_TYPE_RADIO:
+ dip->stream = &vp->channel.mc_head->video_stream;
+ dip->config = pvr2_config_mpeg;
+ dip->minor_type = pvr2_v4l_type_radio;
+ nr_ptr = radio_nr;
break;
default:
/* Bail out (this should be impossible) */
@@ -1039,30 +1173,27 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
return;
}
- if (!dip->stream) {
- err("Failed to set up pvrusb2 v4l dev"
- " due to missing stream instance");
- return;
- }
-
memcpy(&dip->devbase,&vdev_template,sizeof(vdev_template));
dip->devbase.release = pvr2_video_device_release;
mindevnum = -1;
unit_number = pvr2_hdw_get_unit_number(vp->channel.mc_head->hdw);
- if ((unit_number >= 0) && (unit_number < PVR_NUM)) {
- mindevnum = video_nr[unit_number];
+ if (nr_ptr && (unit_number >= 0) && (unit_number < PVR_NUM)) {
+ mindevnum = nr_ptr[unit_number];
}
- if ((video_register_device(&dip->devbase, v4l_type, mindevnum) < 0) &&
- (video_register_device(&dip->devbase, v4l_type, -1) < 0)) {
- err("Failed to register pvrusb2 v4l video device");
- } else {
- printk(KERN_INFO "pvrusb2: registered device video%d [%s]\n",
- dip->devbase.minor,pvr2_config_get_name(dip->config));
+ if ((video_register_device(&dip->devbase,
+ dip->v4l_type, mindevnum) < 0) &&
+ (video_register_device(&dip->devbase,
+ dip->v4l_type, -1) < 0)) {
+ err("Failed to register pvrusb2 v4l device");
}
+ printk(KERN_INFO "pvrusb2: registered device %s%u [%s]\n",
+ get_v4l_name(dip->v4l_type),dip->devbase.minor & 0x1f,
+ pvr2_config_get_name(dip->config));
+
pvr2_hdw_v4l_store_minor_number(vp->channel.mc_head->hdw,
- dip->devbase.minor);
+ dip->minor_type,dip->devbase.minor);
}
@@ -1070,22 +1201,24 @@ struct pvr2_v4l2 *pvr2_v4l2_create(struct pvr2_context *mnp)
{
struct pvr2_v4l2 *vp;
- vp = kmalloc(sizeof(*vp),GFP_KERNEL);
+ vp = kzalloc(sizeof(*vp),GFP_KERNEL);
if (!vp) return vp;
- memset(vp,0,sizeof(*vp));
- vp->vdev = kmalloc(sizeof(*vp->vdev),GFP_KERNEL);
- if (!vp->vdev) {
+ vp->dev_video = kzalloc(sizeof(*vp->dev_video),GFP_KERNEL);
+ vp->dev_radio = kzalloc(sizeof(*vp->dev_radio),GFP_KERNEL);
+ if (!(vp->dev_video && vp->dev_radio)) {
+ kfree(vp->dev_video);
+ kfree(vp->dev_radio);
kfree(vp);
return NULL;
}
- memset(vp->vdev,0,sizeof(*vp->vdev));
pvr2_channel_init(&vp->channel,mnp);
pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr2_v4l2 id=%p",vp);
vp->channel.check_func = pvr2_v4l2_internal_check;
/* register streams */
- pvr2_v4l2_dev_init(vp->vdev,vp,pvr2_config_mpeg);
+ pvr2_v4l2_dev_init(vp->dev_video,vp,VFL_TYPE_GRABBER);
+ pvr2_v4l2_dev_init(vp->dev_radio,vp,VFL_TYPE_RADIO);
return vp;
}
diff --git a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c
index 05f2cddeb47..61efa6f0220 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c
@@ -66,7 +66,9 @@ static void set_input(struct pvr2_v4l_decoder *ctxt)
route.input = SAA7115_SVIDEO2;
break;
case PVR2_CVAL_INPUT_RADIO:
- // ????? No idea yet what to do here
+ // In radio mode, we mute the video, but point at one
+ // spot just to stay consistent
+ route.input = SAA7115_COMPOSITE5;
default:
return;
}
@@ -137,8 +139,7 @@ static int decoder_check(struct pvr2_v4l_decoder *ctxt)
unsigned long msk;
unsigned int idx;
- for (idx = 0; idx < sizeof(decoder_ops)/sizeof(decoder_ops[0]);
- idx++) {
+ for (idx = 0; idx < ARRAY_SIZE(decoder_ops); idx++) {
msk = 1 << idx;
if (ctxt->stale_mask & msk) continue;
if (decoder_ops[idx].check(ctxt)) {
@@ -154,8 +155,7 @@ static void decoder_update(struct pvr2_v4l_decoder *ctxt)
unsigned long msk;
unsigned int idx;
- for (idx = 0; idx < sizeof(decoder_ops)/sizeof(decoder_ops[0]);
- idx++) {
+ for (idx = 0; idx < ARRAY_SIZE(decoder_ops); idx++) {
msk = 1 << idx;
if (!(ctxt->stale_mask & msk)) continue;
ctxt->stale_mask &= ~msk;
@@ -183,25 +183,13 @@ static void decoder_enable(struct pvr2_v4l_decoder *ctxt,int fl)
}
-static int decoder_is_tuned(struct pvr2_v4l_decoder *ctxt)
-{
- struct v4l2_tuner vt;
- int ret;
-
- memset(&vt,0,sizeof(vt));
- ret = pvr2_i2c_client_cmd(ctxt->client,VIDIOC_G_TUNER,&vt);
- if (ret < 0) return -EINVAL;
- return vt.signal ? 1 : 0;
-}
-
-
static unsigned int decoder_describe(struct pvr2_v4l_decoder *ctxt,char *buf,unsigned int cnt)
{
return scnprintf(buf,cnt,"handler: pvrusb2-video-v4l");
}
-const static struct pvr2_i2c_handler_functions hfuncs = {
+static const struct pvr2_i2c_handler_functions hfuncs = {
.detach = (void (*)(void *))decoder_detach,
.check = (int (*)(void *))decoder_check,
.update = (void (*)(void *))decoder_update,
@@ -218,20 +206,17 @@ int pvr2_i2c_decoder_v4l_setup(struct pvr2_hdw *hdw,
if (cp->handler) return 0;
if (!decoder_detect(cp)) return 0;
- ctxt = kmalloc(sizeof(*ctxt),GFP_KERNEL);
+ ctxt = kzalloc(sizeof(*ctxt),GFP_KERNEL);
if (!ctxt) return 0;
- memset(ctxt,0,sizeof(*ctxt));
ctxt->handler.func_data = ctxt;
ctxt->handler.func_table = &hfuncs;
ctxt->ctrl.ctxt = ctxt;
ctxt->ctrl.detach = (void (*)(void *))decoder_detach;
ctxt->ctrl.enable = (void (*)(void *,int))decoder_enable;
- ctxt->ctrl.tuned = (int (*)(void *))decoder_is_tuned;
ctxt->client = cp;
ctxt->hdw = hdw;
- ctxt->stale_mask = (1 << (sizeof(decoder_ops)/
- sizeof(decoder_ops[0]))) - 1;
+ ctxt->stale_mask = (1 << ARRAY_SIZE(decoder_ops)) - 1;
hdw->decoder_ctrl = &ctxt->ctrl;
cp->handler = &ctxt->handler;
pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x saa711x V4L2 handler set up",
diff --git a/drivers/media/video/pvrusb2/pvrusb2-wm8775.c b/drivers/media/video/pvrusb2/pvrusb2-wm8775.c
index 2413e5198e1..66b4d36ef76 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-wm8775.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-wm8775.c
@@ -50,15 +50,21 @@ static void set_input(struct pvr2_v4l_wm8775 *ctxt)
{
struct v4l2_routing route;
struct pvr2_hdw *hdw = ctxt->hdw;
- int msk = 0;
memset(&route,0,sizeof(route));
- pvr2_trace(PVR2_TRACE_CHIPS,"i2c wm8775 set_input(val=%d msk=0x%x)",
- hdw->input_val,msk);
+ switch(hdw->input_val) {
+ case PVR2_CVAL_INPUT_RADIO:
+ route.input = 1;
+ break;
+ default:
+ /* All other cases just use the second input */
+ route.input = 2;
+ break;
+ }
+ pvr2_trace(PVR2_TRACE_CHIPS,"i2c wm8775 set_input(val=%d route=0x%x)",
+ hdw->input_val,route.input);
- // Always point to input #1 no matter what
- route.input = 2;
pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_S_AUDIO_ROUTING,&route);
}
@@ -99,8 +105,7 @@ static int wm8775_check(struct pvr2_v4l_wm8775 *ctxt)
unsigned long msk;
unsigned int idx;
- for (idx = 0; idx < sizeof(wm8775_ops)/sizeof(wm8775_ops[0]);
- idx++) {
+ for (idx = 0; idx < ARRAY_SIZE(wm8775_ops); idx++) {
msk = 1 << idx;
if (ctxt->stale_mask & msk) continue;
if (wm8775_ops[idx].check(ctxt)) {
@@ -116,8 +121,7 @@ static void wm8775_update(struct pvr2_v4l_wm8775 *ctxt)
unsigned long msk;
unsigned int idx;
- for (idx = 0; idx < sizeof(wm8775_ops)/sizeof(wm8775_ops[0]);
- idx++) {
+ for (idx = 0; idx < ARRAY_SIZE(wm8775_ops); idx++) {
msk = 1 << idx;
if (!(ctxt->stale_mask & msk)) continue;
ctxt->stale_mask &= ~msk;
@@ -126,7 +130,7 @@ static void wm8775_update(struct pvr2_v4l_wm8775 *ctxt)
}
-const static struct pvr2_i2c_handler_functions hfuncs = {
+static const struct pvr2_i2c_handler_functions hfuncs = {
.detach = (void (*)(void *))wm8775_detach,
.check = (int (*)(void *))wm8775_check,
.update = (void (*)(void *))wm8775_update,
@@ -140,16 +144,14 @@ int pvr2_i2c_wm8775_setup(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp)
if (cp->handler) return 0;
- ctxt = kmalloc(sizeof(*ctxt),GFP_KERNEL);
+ ctxt = kzalloc(sizeof(*ctxt),GFP_KERNEL);
if (!ctxt) return 0;
- memset(ctxt,0,sizeof(*ctxt));
ctxt->handler.func_data = ctxt;
ctxt->handler.func_table = &hfuncs;
ctxt->client = cp;
ctxt->hdw = hdw;
- ctxt->stale_mask = (1 << (sizeof(wm8775_ops)/
- sizeof(wm8775_ops[0]))) - 1;
+ ctxt->stale_mask = (1 << ARRAY_SIZE(wm8775_ops)) - 1;
cp->handler = &ctxt->handler;
pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x wm8775 V4L2 handler set up",
cp->client->addr);
diff --git a/drivers/media/video/pwc/Makefile b/drivers/media/video/pwc/Makefile
index 9db2260d10c..f5c8ec261e8 100644
--- a/drivers/media/video/pwc/Makefile
+++ b/drivers/media/video/pwc/Makefile
@@ -2,11 +2,3 @@ pwc-objs := pwc-if.o pwc-misc.o pwc-ctrl.o pwc-v4l.o pwc-uncompress.o
pwc-objs += pwc-dec1.o pwc-dec23.o pwc-kiara.o pwc-timon.o
obj-$(CONFIG_USB_PWC) += pwc.o
-
-ifeq ($(CONFIG_USB_PWC_DEBUG),y)
-EXTRA_CFLAGS += -DCONFIG_PWC_DEBUG=1
-else
-EXTRA_CFLAGS += -DCONFIG_PWC_DEBUG=0
-endif
-
-
diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c
index a996aad7927..27ed76986ca 100644
--- a/drivers/media/video/pwc/pwc-if.c
+++ b/drivers/media/video/pwc/pwc-if.c
@@ -128,7 +128,7 @@ static int default_size = PSZ_QCIF;
static int default_fps = 10;
static int default_fbufs = 3; /* Default number of frame buffers */
int pwc_mbufs = 2; /* Default number of mmap() buffers */
-#if CONFIG_PWC_DEBUG
+#ifdef CONFIG_USB_PWC_DEBUG
int pwc_trace = PWC_DEBUG_LEVEL;
#endif
static int power_save = 0;
@@ -152,7 +152,7 @@ static int pwc_video_ioctl(struct inode *inode, struct file *file,
unsigned int ioctlnr, unsigned long arg);
static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma);
-static struct file_operations pwc_fops = {
+static const struct file_operations pwc_fops = {
.owner = THIS_MODULE,
.open = pwc_video_open,
.release = pwc_video_close,
@@ -1051,7 +1051,7 @@ static void pwc_remove_sysfs_files(struct video_device *vdev)
video_device_remove_file(vdev, &class_device_attr_button);
}
-#if CONFIG_PWC_DEBUG
+#ifdef CONFIG_USB_PWC_DEBUG
static const char *pwc_sensor_type_to_string(unsigned int sensor_type)
{
switch(sensor_type) {
@@ -1835,7 +1835,7 @@ module_param(size, charp, 0444);
module_param(fps, int, 0444);
module_param(fbufs, int, 0444);
module_param(mbufs, int, 0444);
-#if CONFIG_PWC_DEBUG
+#ifdef CONFIG_USB_PWC_DEBUG
module_param_named(trace, pwc_trace, int, 0644);
#endif
module_param(power_save, int, 0444);
@@ -1908,7 +1908,7 @@ static int __init usb_pwc_init(void)
default_fbufs = fbufs;
PWC_DEBUG_MODULE("Number of frame buffers set to %d.\n", default_fbufs);
}
-#if CONFIG_PWC_DEBUG
+#ifdef CONFIG_USB_PWC_DEBUG
if (pwc_trace >= 0) {
PWC_DEBUG_MODULE("Trace options: 0x%04x\n", pwc_trace);
}
diff --git a/drivers/media/video/pwc/pwc-v4l.c b/drivers/media/video/pwc/pwc-v4l.c
index b7eb3ce3b96..d5e6bc85064 100644
--- a/drivers/media/video/pwc/pwc-v4l.c
+++ b/drivers/media/video/pwc/pwc-v4l.c
@@ -350,7 +350,7 @@ int pwc_video_do_ioctl(struct inode *inode, struct file *file,
if (pdev == NULL)
return -EFAULT;
-#if CONFIG_PWC_DEBUG
+#ifdef CONFIG_USB_PWC_DEBUG
if (PWC_DEBUG_LEVEL_IOCTL & pwc_trace)
v4l_printk_ioctl(cmd);
#endif
diff --git a/drivers/media/video/pwc/pwc.h b/drivers/media/video/pwc/pwc.h
index 7e9c4237d1e..e778a2b8c28 100644
--- a/drivers/media/video/pwc/pwc.h
+++ b/drivers/media/video/pwc/pwc.h
@@ -39,11 +39,6 @@
#include "pwc-uncompress.h"
#include <media/pwc-ioctl.h>
-/* Turn some debugging options on/off */
-#ifndef CONFIG_PWC_DEBUG
-#define CONFIG_PWC_DEBUG 1
-#endif
-
/* Version block */
#define PWC_MAJOR 10
#define PWC_MINOR 0
@@ -76,7 +71,7 @@
#define PWC_DEBUG_TRACE(fmt, args...) PWC_DEBUG(TRACE, fmt, ##args)
-#if CONFIG_PWC_DEBUG
+#ifdef CONFIG_USB_PWC_DEBUG
#define PWC_DEBUG_LEVEL (PWC_DEBUG_LEVEL_MODULE)
@@ -270,7 +265,7 @@ extern "C" {
#endif
/* Global variables */
-#if CONFIG_PWC_DEBUG
+#ifdef CONFIG_USB_PWC_DEBUG
extern int pwc_trace;
#endif
extern int pwc_mbufs;
diff --git a/drivers/media/video/saa5246a.c b/drivers/media/video/saa5246a.c
index 77bb940a1a4..e20aa3612a7 100644
--- a/drivers/media/video/saa5246a.c
+++ b/drivers/media/video/saa5246a.c
@@ -40,7 +40,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/init.h>
#include <linux/i2c.h>
@@ -112,7 +111,7 @@ static int saa5246a_attach(struct i2c_adapter *adap, int addr, int kind)
for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++)
{
memset(t->pgbuf[pgbuf], ' ', sizeof(t->pgbuf[0]));
- t->is_searching[pgbuf] = FALSE;
+ t->is_searching[pgbuf] = false;
}
vd->priv=t;
@@ -199,7 +198,7 @@ static int i2c_senddata(struct saa5246a_device *t, ...)
/* Get count number of bytes from I²C-device at address adr, store them in buf.
* Start & stop handshaking is done by this routine, ack will be sent after the
- * last byte to inhibit further sending of data. If uaccess is TRUE, data is
+ * last byte to inhibit further sending of data. If uaccess is 'true', data is
* written to user-space with put_user. Returns -1 if I²C-device didn't send
* acknowledge, 0 otherwise
*/
@@ -339,7 +338,7 @@ static int saa5246a_request_page(struct saa5246a_device *t,
return -EIO;
}
- t->is_searching[req->pgbuf] = TRUE;
+ t->is_searching[req->pgbuf] = true;
return 0;
}
@@ -453,7 +452,7 @@ static inline int saa5246a_get_status(struct saa5246a_device *t,
}
}
if (!info->hamming && !info->notfound)
- t->is_searching[dau_no] = FALSE;
+ t->is_searching[dau_no] = false;
return 0;
}
@@ -565,7 +564,7 @@ static inline int saa5246a_stop_dau(struct saa5246a_device *t,
{
return -EIO;
}
- t->is_searching[dau_no] = FALSE;
+ t->is_searching[dau_no] = false;
return 0;
}
@@ -817,7 +816,7 @@ static void __exit cleanup_saa_5246a (void)
module_init(init_saa_5246a);
module_exit(cleanup_saa_5246a);
-static struct file_operations saa_fops = {
+static const struct file_operations saa_fops = {
.owner = THIS_MODULE,
.open = saa5246a_open,
.release = saa5246a_release,
diff --git a/drivers/media/video/saa5246a.h b/drivers/media/video/saa5246a.h
index 7b91112304e..64394c036c6 100644
--- a/drivers/media/video/saa5246a.h
+++ b/drivers/media/video/saa5246a.h
@@ -41,23 +41,18 @@
#define POS_HEADER_START 7
#define POS_HEADER_END 31
-/* Returns TRUE if the part of the videotext page described with req contains
+/* Returns 'true' if the part of the videotext page described with req contains
(at least parts of) the time field */
#define REQ_CONTAINS_TIME(p_req) \
((p_req)->start <= POS_TIME_END && \
(p_req)->end >= POS_TIME_START)
-/* Returns TRUE if the part of the videotext page described with req contains
+/* Returns 'true' if the part of the videotext page described with req contains
(at least parts of) the page header */
#define REQ_CONTAINS_HEADER(p_req) \
((p_req)->start <= POS_HEADER_END && \
(p_req)->end >= POS_HEADER_START)
-#ifndef FALSE
-#define FALSE 0
-#define TRUE 1
-#endif
-
/*****************************************************************************/
/* Mode register numbers of the SAA5246A */
/*****************************************************************************/
diff --git a/drivers/media/video/saa5249.c b/drivers/media/video/saa5249.c
index bb3fb4387f6..f2a2f34cd62 100644
--- a/drivers/media/video/saa5249.c
+++ b/drivers/media/video/saa5249.c
@@ -124,11 +124,6 @@ struct saa5249_device
/* General defines and debugging support */
-#ifndef FALSE
-#define FALSE 0
-#define TRUE 1
-#endif
-
#define RESCHED do { cond_resched(); } while(0)
static struct video_device saa_template; /* Declared near bottom */
@@ -183,9 +178,9 @@ static int saa5249_attach(struct i2c_adapter *adap, int addr, int kind)
memset(t->vdau[pgbuf].sregs, 0, sizeof(t->vdau[0].sregs));
memset(t->vdau[pgbuf].laststat, 0, sizeof(t->vdau[0].laststat));
t->vdau[pgbuf].expire = 0;
- t->vdau[pgbuf].clrfound = TRUE;
- t->vdau[pgbuf].stopped = TRUE;
- t->is_searching[pgbuf] = FALSE;
+ t->vdau[pgbuf].clrfound = true;
+ t->vdau[pgbuf].stopped = true;
+ t->is_searching[pgbuf] = false;
}
vd->priv=t;
@@ -298,7 +293,7 @@ static int i2c_senddata(struct saa5249_device *t, ...)
/* Get count number of bytes from I²C-device at address adr, store them in buf. Start & stop
* handshaking is done by this routine, ack will be sent after the last byte to inhibit further
- * sending of data. If uaccess is TRUE, data is written to user-space with put_user.
+ * sending of data. If uaccess is 'true', data is written to user-space with put_user.
* Returns -1 if I²C-device didn't send acknowledge, 0 otherwise
*/
@@ -317,7 +312,7 @@ static int i2c_getdata(struct saa5249_device *t, int count, u8 *buf)
static int do_saa5249_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, void *arg)
{
- static int virtual_mode = FALSE;
+ static int virtual_mode = false;
struct video_device *vd = video_devdata(file);
struct saa5249_device *t=vd->priv;
@@ -340,7 +335,7 @@ static int do_saa5249_ioctl(struct inode *inode, struct file *file,
if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
return -EINVAL;
memset(t->vdau[req->pgbuf].pgbuf, ' ', sizeof(t->vdau[0].pgbuf));
- t->vdau[req->pgbuf].clrfound = TRUE;
+ t->vdau[req->pgbuf].clrfound = true;
return 0;
}
@@ -350,7 +345,7 @@ static int do_saa5249_ioctl(struct inode *inode, struct file *file,
if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
return -EINVAL;
- t->vdau[req->pgbuf].clrfound = TRUE;
+ t->vdau[req->pgbuf].clrfound = true;
return 0;
}
@@ -376,9 +371,9 @@ static int do_saa5249_ioctl(struct inode *inode, struct file *file,
t->vdau[req->pgbuf].sregs[4] = (req->pagemask & HR_UNIT ? 0x10 : 0) | (req->hour & 0xf);
t->vdau[req->pgbuf].sregs[5] = (req->pagemask & MIN_TEN ? 0x10 : 0) | (req->minute / 0x10);
t->vdau[req->pgbuf].sregs[6] = (req->pagemask & MIN_UNIT ? 0x10 : 0) | (req->minute & 0xf);
- t->vdau[req->pgbuf].stopped = FALSE;
- t->vdau[req->pgbuf].clrfound = TRUE;
- t->is_searching[req->pgbuf] = TRUE;
+ t->vdau[req->pgbuf].stopped = false;
+ t->vdau[req->pgbuf].clrfound = true;
+ t->is_searching[req->pgbuf] = true;
return 0;
}
@@ -430,7 +425,7 @@ static int do_saa5249_ioctl(struct inode *inode, struct file *file,
i2c_getdata(t, 40, t->vdau[req->pgbuf].pgbuf + VTX_PAGESIZE + 23 * 40))
return -EIO;
}
- t->vdau[req->pgbuf].clrfound = FALSE;
+ t->vdau[req->pgbuf].clrfound = false;
memcpy(t->vdau[req->pgbuf].laststat, infobits, sizeof(infobits));
}
else
@@ -474,7 +469,7 @@ static int do_saa5249_ioctl(struct inode *inode, struct file *file,
return -EFAULT;
if (!info.hamming && !info.notfound)
{
- t->is_searching[req->pgbuf] = FALSE;
+ t->is_searching[req->pgbuf] = false;
}
return 0;
}
@@ -530,8 +525,8 @@ static int do_saa5249_ioctl(struct inode *inode, struct file *file,
if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
return -EINVAL;
- t->vdau[req->pgbuf].stopped = TRUE;
- t->is_searching[req->pgbuf] = FALSE;
+ t->vdau[req->pgbuf].stopped = true;
+ t->is_searching[req->pgbuf] = false;
return 0;
}
@@ -660,11 +655,11 @@ static int saa5249_open(struct inode *inode, struct file *file)
memset(t->vdau[pgbuf].sregs, 0, sizeof(t->vdau[0].sregs));
memset(t->vdau[pgbuf].laststat, 0, sizeof(t->vdau[0].laststat));
t->vdau[pgbuf].expire = 0;
- t->vdau[pgbuf].clrfound = TRUE;
- t->vdau[pgbuf].stopped = TRUE;
- t->is_searching[pgbuf] = FALSE;
+ t->vdau[pgbuf].clrfound = true;
+ t->vdau[pgbuf].stopped = true;
+ t->is_searching[pgbuf] = false;
}
- t->virtual_mode=FALSE;
+ t->virtual_mode = false;
return 0;
fail:
@@ -699,7 +694,7 @@ static void __exit cleanup_saa_5249 (void)
module_init(init_saa_5249);
module_exit(cleanup_saa_5249);
-static struct file_operations saa_fops = {
+static const struct file_operations saa_fops = {
.owner = THIS_MODULE,
.open = saa5249_open,
.release = saa5249_release,
diff --git a/drivers/media/video/saa7111.c b/drivers/media/video/saa7111.c
index 686fd474620..44dc7479119 100644
--- a/drivers/media/video/saa7111.c
+++ b/drivers/media/video/saa7111.c
@@ -41,7 +41,6 @@
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/page.h>
-#include <linux/sched.h>
#include <linux/types.h>
#include <linux/videodev.h>
diff --git a/drivers/media/video/saa7114.c b/drivers/media/video/saa7114.c
index 90398ab8252..2ce3321ab99 100644
--- a/drivers/media/video/saa7114.c
+++ b/drivers/media/video/saa7114.c
@@ -44,7 +44,6 @@
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/page.h>
-#include <linux/sched.h>
#include <linux/types.h>
#include <linux/videodev.h>
diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c
index c2374ed7ba9..c4f066d6668 100644
--- a/drivers/media/video/saa7115.c
+++ b/drivers/media/video/saa7115.c
@@ -71,6 +71,7 @@ I2C_CLIENT_INSMOD;
struct saa711x_state {
v4l2_std_id std;
int input;
+ int output;
int enable;
int radio;
int bright;
@@ -1301,7 +1302,7 @@ static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *ar
struct v4l2_routing *route = arg;
route->input = state->input;
- route->output = 0;
+ route->output = state->output;
break;
}
@@ -1309,7 +1310,7 @@ static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *ar
{
struct v4l2_routing *route = arg;
- v4l_dbg(1, debug, client, "decoder set input %d\n", route->input);
+ v4l_dbg(1, debug, client, "decoder set input %d output %d\n", route->input, route->output);
/* saa7113 does not have these inputs */
if (state->ident == V4L2_IDENT_SAA7113 &&
(route->input == SAA7115_COMPOSITE4 ||
@@ -1318,10 +1319,12 @@ static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *ar
}
if (route->input > SAA7115_SVIDEO3)
return -EINVAL;
- if (state->input == route->input)
+ if (route->output > SAA7115_IPORT_ON)
+ return -EINVAL;
+ if (state->input == route->input && state->output == route->output)
break;
- v4l_dbg(1, debug, client, "now setting %s input\n",
- (route->input >= SAA7115_SVIDEO0) ? "S-Video" : "Composite");
+ v4l_dbg(1, debug, client, "now setting %s input %s output\n",
+ (route->input >= SAA7115_SVIDEO0) ? "S-Video" : "Composite", (route->output == SAA7115_IPORT_ON) ? "iport on" : "iport off");
state->input = route->input;
/* select mode */
@@ -1333,6 +1336,14 @@ static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *ar
saa711x_write(client, R_09_LUMA_CNTL,
(saa711x_read(client, R_09_LUMA_CNTL) & 0x7f) |
(state->input >= SAA7115_SVIDEO0 ? 0x80 : 0x0));
+
+ state->output = route->output;
+ if (state->ident == V4L2_IDENT_SAA7114 ||
+ state->ident == V4L2_IDENT_SAA7115) {
+ saa711x_write(client, R_83_X_PORT_I_O_ENA_AND_OUT_CLK,
+ (saa711x_read(client, R_83_X_PORT_I_O_ENA_AND_OUT_CLK) & 0xfe) |
+ (state->output & 0x01));
+ }
break;
}
@@ -1377,6 +1388,9 @@ static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *ar
{
struct v4l2_sliced_vbi_data *data = arg;
+ /* Note: the internal field ID is inverted for NTSC,
+ so data->field 0 maps to the saa7115 even field,
+ whereas for PAL it maps to the saa7115 odd field. */
switch (data->id) {
case V4L2_SLICED_WSS_625:
if (saa711x_read(client, 0x6b) & 0xc0)
@@ -1387,17 +1401,17 @@ static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *ar
case V4L2_SLICED_CAPTION_525:
if (data->field == 0) {
/* CC */
- if (saa711x_read(client, 0x66) & 0xc0)
+ if (saa711x_read(client, 0x66) & 0x30)
return -EIO;
- data->data[0] = saa711x_read(client, 0x67);
- data->data[1] = saa711x_read(client, 0x68);
+ data->data[0] = saa711x_read(client, 0x69);
+ data->data[1] = saa711x_read(client, 0x6a);
return 0;
}
/* XDS */
- if (saa711x_read(client, 0x66) & 0x30)
+ if (saa711x_read(client, 0x66) & 0xc0)
return -EIO;
- data->data[0] = saa711x_read(client, 0x69);
- data->data[1] = saa711x_read(client, 0x6a);
+ data->data[0] = saa711x_read(client, 0x67);
+ data->data[1] = saa711x_read(client, 0x68);
return 0;
default:
return -EINVAL;
@@ -1406,17 +1420,8 @@ static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *ar
}
#ifdef CONFIG_VIDEO_ADV_DEBUG
- case VIDIOC_INT_G_REGISTER:
- {
- struct v4l2_register *reg = arg;
-
- if (reg->i2c_id != I2C_DRIVERID_SAA711X)
- return -EINVAL;
- reg->val = saa711x_read(client, reg->reg & 0xff);
- break;
- }
-
- case VIDIOC_INT_S_REGISTER:
+ case VIDIOC_DBG_G_REGISTER:
+ case VIDIOC_DBG_S_REGISTER:
{
struct v4l2_register *reg = arg;
@@ -1424,7 +1429,10 @@ static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *ar
return -EINVAL;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- saa711x_write(client, reg->reg & 0xff, reg->val & 0xff);
+ if (cmd == VIDIOC_DBG_G_REGISTER)
+ reg->val = saa711x_read(client, reg->reg & 0xff);
+ else
+ saa711x_write(client, reg->reg & 0xff, reg->val & 0xff);
break;
}
#endif
@@ -1492,6 +1500,7 @@ static int saa711x_attach(struct i2c_adapter *adapter, int address, int kind)
return -ENOMEM;
}
state->input = -1;
+ state->output = SAA7115_IPORT_ON;
state->enable = 1;
state->radio = 0;
state->bright = 128;
@@ -1550,7 +1559,7 @@ static int saa711x_attach(struct i2c_adapter *adapter, int address, int kind)
static int saa711x_probe(struct i2c_adapter *adapter)
{
- if (adapter->class & I2C_CLASS_TV_ANALOG)
+ if (adapter->class & I2C_CLASS_TV_ANALOG || adapter->class & I2C_CLASS_TV_DIGITAL)
return i2c_probe(adapter, &addr_data, &saa711x_attach);
return 0;
}
diff --git a/drivers/media/video/saa711x.c b/drivers/media/video/saa711x.c
index 708fae51e8e..269d7114a93 100644
--- a/drivers/media/video/saa711x.c
+++ b/drivers/media/video/saa711x.c
@@ -35,7 +35,6 @@
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/page.h>
-#include <linux/sched.h>
#include <linux/types.h>
#include <asm/uaccess.h>
#include <linux/videodev.h>
diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c
index ad401bdefea..bd9c4f3ad02 100644
--- a/drivers/media/video/saa7127.c
+++ b/drivers/media/video/saa7127.c
@@ -614,17 +614,8 @@ static int saa7127_command(struct i2c_client *client,
break;
#ifdef CONFIG_VIDEO_ADV_DEBUG
- case VIDIOC_INT_G_REGISTER:
- {
- struct v4l2_register *reg = arg;
-
- if (reg->i2c_id != I2C_DRIVERID_SAA7127)
- return -EINVAL;
- reg->val = saa7127_read(client, reg->reg & 0xff);
- break;
- }
-
- case VIDIOC_INT_S_REGISTER:
+ case VIDIOC_DBG_G_REGISTER:
+ case VIDIOC_DBG_S_REGISTER:
{
struct v4l2_register *reg = arg;
@@ -632,7 +623,10 @@ static int saa7127_command(struct i2c_client *client,
return -EINVAL;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- saa7127_write(client, reg->reg & 0xff, reg->val & 0xff);
+ if (cmd == VIDIOC_DBG_G_REGISTER)
+ reg->val = saa7127_read(client, reg->reg & 0xff);
+ else
+ saa7127_write(client, reg->reg & 0xff, reg->val & 0xff);
break;
}
#endif
diff --git a/drivers/media/video/saa7134/Makefile b/drivers/media/video/saa7134/Makefile
index 89a1565b425..c85c8a8ec36 100644
--- a/drivers/media/video/saa7134/Makefile
+++ b/drivers/media/video/saa7134/Makefile
@@ -14,7 +14,3 @@ obj-$(CONFIG_VIDEO_SAA7134_DVB) += saa7134-dvb.o
EXTRA_CFLAGS += -Idrivers/media/video
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
-
-extra-cflags-$(CONFIG_VIDEO_BUF_DVB) += -DHAVE_VIDEO_BUF_DVB=1
-
-EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m)
diff --git a/drivers/media/video/saa7134/saa6752hs.c b/drivers/media/video/saa7134/saa6752hs.c
index afc8f352b8e..57f1f5d409e 100644
--- a/drivers/media/video/saa7134/saa6752hs.c
+++ b/drivers/media/video/saa7134/saa6752hs.c
@@ -1,6 +1,5 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/delay.h>
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
index ae984bbe36b..89f32107f46 100644
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -2469,6 +2469,11 @@ struct saa7134_board saa7134_boards[] = {
.amux = LINE2,
.gpio = 0x0200000,
},{
+ .name = name_comp2,
+ .vmux = 0,
+ .amux = LINE2,
+ .gpio = 0x0200000,
+ },{
.name = name_svideo,
.vmux = 8,
.amux = LINE2,
@@ -3183,6 +3188,107 @@ struct saa7134_board saa7134_boards[] = {
.amux = LINE1,
}},
},
+ [SAA7134_BOARD_ENCORE_ENLTV] = {
+ /* Steven Walter <stevenrwalter@gmail.com>
+ Juan Pablo Sormani <sorman@gmail.com> */
+ .name = "Encore ENLTV",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_TNF_5335MF,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = 3,
+ .tv = 1,
+ },{
+ .name = name_tv_mono,
+ .vmux = 7,
+ .amux = 4,
+ .tv = 1,
+ },{
+ .name = name_comp1,
+ .vmux = 3,
+ .amux = 2,
+ },{
+ .name = name_svideo,
+ .vmux = 0,
+ .amux = 2,
+ }},
+ .radio = {
+ .name = name_radio,
+ .amux = LINE2,
+/* .gpio = 0x00300001,*/
+ .gpio = 0x20000,
+
+ },
+ .mute = {
+ .name = name_mute,
+ .amux = 0,
+ },
+ },
+ [SAA7134_BOARD_ENCORE_ENLTV_FM] = {
+ /* Juan Pablo Sormani <sorman@gmail.com> */
+ .name = "Encore ENLTV-FM",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_PHILIPS_ATSC,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = 3,
+ .tv = 1,
+ },{
+ .name = name_tv_mono,
+ .vmux = 7,
+ .amux = 4,
+ .tv = 1,
+ },{
+ .name = name_comp1,
+ .vmux = 3,
+ .amux = 2,
+ },{
+ .name = name_svideo,
+ .vmux = 0,
+ .amux = 2,
+ }},
+ .radio = {
+ .name = name_radio,
+ .amux = LINE2,
+ .gpio = 0x20000,
+
+ },
+ .mute = {
+ .name = name_mute,
+ .amux = 0,
+ },
+ },
+ [SAA7134_BOARD_CINERGY_HT_PCI] = {
+ .name = "Terratec Cinergy HT PCI",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ },{
+ .name = name_comp1,
+ .vmux = 0,
+ .amux = LINE1,
+ },{
+ .name = name_svideo,
+ .vmux = 6,
+ .amux = LINE1,
+ }},
+ },
};
const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
@@ -3822,6 +3928,36 @@ struct pci_device_id saa7134_pci_tbl[] = {
.subdevice = 0x1172,
.driver_data = SAA7134_BOARD_CINERGY_HT_PCMCIA,
},{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = PCI_VENDOR_ID_PHILIPS,
+ .subdevice = 0x2342,
+ .driver_data = SAA7134_BOARD_ENCORE_ENLTV,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = 0x1131,
+ .subdevice = 0x2341,
+ .driver_data = SAA7134_BOARD_ENCORE_ENLTV,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = 0x3016,
+ .subdevice = 0x2344,
+ .driver_data = SAA7134_BOARD_ENCORE_ENLTV,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = 0x1131,
+ .subdevice = 0x230f,
+ .driver_data = SAA7134_BOARD_ENCORE_ENLTV_FM,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x153b,
+ .subdevice = 0x1175,
+ .driver_data = SAA7134_BOARD_CINERGY_HT_PCI,
+ },{
/* --- boards without eeprom + subsystem ID --- */
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
@@ -3926,9 +4062,12 @@ int saa7134_board_init1(struct saa7134_dev *dev)
case SAA7134_BOARD_KWORLD_TERMINATOR:
case SAA7134_BOARD_SEDNA_PC_TV_CARDBUS:
case SAA7134_BOARD_FLYDVBT_LR301:
+ case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
case SAA7134_BOARD_FLYDVBTDUO:
case SAA7134_BOARD_PROTEUS_2309:
case SAA7134_BOARD_AVERMEDIA_A16AR:
+ case SAA7134_BOARD_ENCORE_ENLTV:
+ case SAA7134_BOARD_ENCORE_ENLTV_FM:
dev->has_remote = SAA7134_REMOTE_GPIO;
break;
case SAA7134_BOARD_FLYDVBS_LR300:
@@ -4150,6 +4289,7 @@ int saa7134_board_init2(struct saa7134_dev *dev)
}
break;
case SAA7134_BOARD_CINERGY_HT_PCMCIA:
+ case SAA7134_BOARD_CINERGY_HT_PCI:
/* make the tda10046 find its eeprom */
{
u8 data[] = { 0x3c, 0x33, 0x60};
diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c
index c33f6a69a24..e3059fd3395 100644
--- a/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/drivers/media/video/saa7134/saa7134-dvb.c
@@ -1426,6 +1426,18 @@ static int dvb_init(struct saa7134_dev *dev)
}
break;
+ case SAA7134_BOARD_CINERGY_HT_PCI:
+ dev->dvb.frontend = dvb_attach(tda10046_attach,
+ &cinergy_ht_config,
+ &dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl;
+ dev->dvb.frontend->ops.tuner_ops.init = cinergy_ht_tuner_init;
+ dev->dvb.frontend->ops.tuner_ops.sleep = cinergy_ht_tuner_sleep;
+ dev->dvb.frontend->ops.tuner_ops.set_params = md8800_dvbt_pll_set;
+
+ }
+ break;
default:
printk("%s: Huh? unknown DVB card?\n",dev->name);
break;
diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c
index daaae870a2c..f521603482c 100644
--- a/drivers/media/video/saa7134/saa7134-empress.c
+++ b/drivers/media/video/saa7134/saa7134-empress.c
@@ -319,7 +319,7 @@ static int ts_ioctl(struct inode *inode, struct file *file,
return video_usercopy(inode, file, cmd, arg, ts_do_ioctl);
}
-static struct file_operations ts_fops =
+static const struct file_operations ts_fops =
{
.owner = THIS_MODULE,
.open = ts_open,
diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c
index 6f9fe86fed9..cce8da6a4f9 100644
--- a/drivers/media/video/saa7134/saa7134-i2c.c
+++ b/drivers/media/video/saa7134/saa7134-i2c.c
@@ -120,9 +120,9 @@ static inline int i2c_is_error(enum i2c_status status)
case ARB_LOST:
case SEQ_ERR:
case ST_ERR:
- return TRUE;
+ return true;
default:
- return FALSE;
+ return false;
}
}
@@ -131,9 +131,9 @@ static inline int i2c_is_idle(enum i2c_status status)
switch (status) {
case IDLE:
case DONE_STOP:
- return TRUE;
+ return true;
default:
- return FALSE;
+ return false;
}
}
@@ -141,9 +141,9 @@ static inline int i2c_is_busy(enum i2c_status status)
{
switch (status) {
case BUSY:
- return TRUE;
+ return true;
default:
- return FALSE;
+ return false;
}
}
@@ -159,8 +159,8 @@ static int i2c_is_busy_wait(struct saa7134_dev *dev)
saa_wait(I2C_WAIT_DELAY);
}
if (I2C_WAIT_RETRY == count)
- return FALSE;
- return TRUE;
+ return false;
+ return true;
}
static int i2c_reset(struct saa7134_dev *dev)
@@ -171,7 +171,7 @@ static int i2c_reset(struct saa7134_dev *dev)
d2printk(KERN_DEBUG "%s: i2c reset\n",dev->name);
status = i2c_get_status(dev);
if (!i2c_is_error(status))
- return TRUE;
+ return true;
i2c_set_status(dev,status);
for (count = 0; count < I2C_WAIT_RETRY; count++) {
@@ -181,13 +181,13 @@ static int i2c_reset(struct saa7134_dev *dev)
udelay(I2C_WAIT_DELAY);
}
if (I2C_WAIT_RETRY == count)
- return FALSE;
+ return false;
if (!i2c_is_idle(status))
- return FALSE;
+ return false;
i2c_set_attr(dev,NOP);
- return TRUE;
+ return true;
}
static inline int i2c_send_byte(struct saa7134_dev *dev,
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
index 60b38defd9b..46c583f1e78 100644
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -22,7 +22,6 @@
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
-#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/input.h>
@@ -41,16 +40,24 @@ static int pinnacle_remote = 0;
module_param(pinnacle_remote, int, 0644); /* Choose Pinnacle PCTV remote */
MODULE_PARM_DESC(pinnacle_remote, "Specify Pinnacle PCTV remote: 0=coloured, 1=grey (defaults to 0)");
+static int ir_rc5_remote_gap = 885;
+module_param(ir_rc5_remote_gap, int, 0644);
+static int ir_rc5_key_timeout = 115;
+module_param(ir_rc5_key_timeout, int, 0644);
+
#define dprintk(fmt, arg...) if (ir_debug) \
printk(KERN_DEBUG "%s/ir: " fmt, dev->name , ## arg)
#define i2cdprintk(fmt, arg...) if (ir_debug) \
printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg)
+/** rc5 functions */
+static int saa7134_rc5_irq(struct saa7134_dev *dev);
+
/* -------------------- GPIO generic keycode builder -------------------- */
static int build_key(struct saa7134_dev *dev)
{
- struct saa7134_ir *ir = dev->remote;
+ struct card_ir *ir = dev->remote;
u32 gpio, data;
/* rising SAA7134_GPIO_GPRESCAN reads the status */
@@ -135,16 +142,19 @@ static int get_key_hvr1110(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
void saa7134_input_irq(struct saa7134_dev *dev)
{
- struct saa7134_ir *ir = dev->remote;
+ struct card_ir *ir = dev->remote;
- if (!ir->polling)
+ if (!ir->polling && !ir->rc5_gpio) {
build_key(dev);
+ } else if (ir->rc5_gpio) {
+ saa7134_rc5_irq(dev);
+ }
}
static void saa7134_input_timer(unsigned long data)
{
struct saa7134_dev *dev = (struct saa7134_dev*)data;
- struct saa7134_ir *ir = dev->remote;
+ struct card_ir *ir = dev->remote;
unsigned long timeout;
build_key(dev);
@@ -152,7 +162,7 @@ static void saa7134_input_timer(unsigned long data)
mod_timer(&ir->timer, timeout);
}
-static void saa7134_ir_start(struct saa7134_dev *dev, struct saa7134_ir *ir)
+static void saa7134_ir_start(struct saa7134_dev *dev, struct card_ir *ir)
{
if (ir->polling) {
init_timer(&ir->timer);
@@ -160,6 +170,19 @@ static void saa7134_ir_start(struct saa7134_dev *dev, struct saa7134_ir *ir)
ir->timer.data = (unsigned long)dev;
ir->timer.expires = jiffies + HZ;
add_timer(&ir->timer);
+ } else if (ir->rc5_gpio) {
+ /* set timer_end for code completion */
+ init_timer(&ir->timer_end);
+ ir->timer_end.function = ir_rc5_timer_end;
+ ir->timer_end.data = (unsigned long)ir;
+ init_timer(&ir->timer_keyup);
+ ir->timer_keyup.function = ir_rc5_timer_keyup;
+ ir->timer_keyup.data = (unsigned long)ir;
+ ir->shift_by = 2;
+ ir->start = 0x2;
+ ir->addr = 0x17;
+ ir->rc5_key_timeout = ir_rc5_key_timeout;
+ ir->rc5_remote_gap = ir_rc5_remote_gap;
}
}
@@ -171,13 +194,14 @@ static void saa7134_ir_stop(struct saa7134_dev *dev)
int saa7134_input_init1(struct saa7134_dev *dev)
{
- struct saa7134_ir *ir;
+ struct card_ir *ir;
struct input_dev *input_dev;
IR_KEYTAB_TYPE *ir_codes = NULL;
u32 mask_keycode = 0;
u32 mask_keydown = 0;
u32 mask_keyup = 0;
int polling = 0;
+ int rc5_gpio = 0;
int ir_type = IR_TYPE_OTHER;
int err;
@@ -296,6 +320,18 @@ int saa7134_input_init1(struct saa7134_dev *dev)
mask_keycode = 0x0001F00;
mask_keydown = 0x0040000;
break;
+ case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
+ ir_codes = ir_codes_asus_pc39;
+ mask_keydown = 0x0040000;
+ rc5_gpio = 1;
+ break;
+ case SAA7134_BOARD_ENCORE_ENLTV:
+ case SAA7134_BOARD_ENCORE_ENLTV_FM:
+ ir_codes = ir_codes_encore_enltv;
+ mask_keycode = 0x00007f;
+ mask_keyup = 0x040000;
+ polling = 50; // ms
+ break;
}
if (NULL == ir_codes) {
printk("%s: Oops: IR config error [card=%d]\n",
@@ -317,6 +353,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
ir->mask_keydown = mask_keydown;
ir->mask_keyup = mask_keyup;
ir->polling = polling;
+ ir->rc5_gpio = rc5_gpio;
/* init input device */
snprintf(ir->name, sizeof(ir->name), "saa7134 IR (%s)",
@@ -403,6 +440,49 @@ void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir)
}
}
+
+static int saa7134_rc5_irq(struct saa7134_dev *dev)
+{
+ struct card_ir *ir = dev->remote;
+ struct timeval tv;
+ u32 gap;
+ unsigned long current_jiffies, timeout;
+
+ /* get time of bit */
+ current_jiffies = jiffies;
+ do_gettimeofday(&tv);
+
+ /* avoid overflow with gap >1s */
+ if (tv.tv_sec - ir->base_time.tv_sec > 1) {
+ gap = 200000;
+ } else {
+ gap = 1000000 * (tv.tv_sec - ir->base_time.tv_sec) +
+ tv.tv_usec - ir->base_time.tv_usec;
+ }
+
+ /* active code => add bit */
+ if (ir->active) {
+ /* only if in the code (otherwise spurious IRQ or timer
+ late) */
+ if (ir->last_bit < 28) {
+ ir->last_bit = (gap - ir_rc5_remote_gap / 2) /
+ ir_rc5_remote_gap;
+ ir->code |= 1 << ir->last_bit;
+ }
+ /* starting new code */
+ } else {
+ ir->active = 1;
+ ir->code = 0;
+ ir->base_time = tv;
+ ir->last_bit = 0;
+
+ timeout = current_jiffies + (500 + 30 * HZ) / 1000;
+ mod_timer(&ir->timer_end, timeout);
+ }
+
+ return 1;
+}
+
/* ----------------------------------------------------------------------
* Local variables:
* c-basic-offset: 8
diff --git a/drivers/media/video/saa7134/saa7134-oss.c b/drivers/media/video/saa7134/saa7134-oss.c
index bfcb860d14c..72444f039e3 100644
--- a/drivers/media/video/saa7134/saa7134-oss.c
+++ b/drivers/media/video/saa7134/saa7134-oss.c
@@ -563,7 +563,7 @@ static unsigned int dsp_poll(struct file *file, struct poll_table_struct *wait)
return mask;
}
-struct file_operations saa7134_dsp_fops = {
+const struct file_operations saa7134_dsp_fops = {
.owner = THIS_MODULE,
.open = dsp_open,
.release = dsp_release,
@@ -804,7 +804,7 @@ static int mixer_ioctl(struct inode *inode, struct file *file,
}
}
-struct file_operations saa7134_mixer_fops = {
+const struct file_operations saa7134_mixer_fops = {
.owner = THIS_MODULE,
.open = mixer_open,
.release = mixer_release,
diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c
index 830617ea81c..f2cb6305304 100644
--- a/drivers/media/video/saa7134/saa7134-video.c
+++ b/drivers/media/video/saa7134/saa7134-video.c
@@ -2336,7 +2336,7 @@ static int radio_ioctl(struct inode *inode, struct file *file,
return video_usercopy(inode, file, cmd, arg, radio_do_ioctl);
}
-static struct file_operations video_fops =
+static const struct file_operations video_fops =
{
.owner = THIS_MODULE,
.open = video_open,
@@ -2349,7 +2349,7 @@ static struct file_operations video_fops =
.llseek = no_llseek,
};
-static struct file_operations radio_fops =
+static const struct file_operations radio_fops =
{
.owner = THIS_MODULE,
.open = video_open,
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
index e88ad7b40c4..b3e3957c89b 100644
--- a/drivers/media/video/saa7134/saa7134.h
+++ b/drivers/media/video/saa7134/saa7134.h
@@ -41,14 +41,10 @@
#include <sound/driver.h>
#include <sound/core.h>
#include <sound/pcm.h>
+#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE)
#include <media/video-buf-dvb.h>
-
-#ifndef TRUE
-# define TRUE (1==1)
-#endif
-#ifndef FALSE
-# define FALSE (1==0)
#endif
+
#define UNSET (-1U)
/* ----------------------------------------------------------- */
@@ -232,6 +228,9 @@ struct saa7134_format {
#define SAA7134_BOARD_VIDEOMATE_DVBT_200A 103
#define SAA7134_BOARD_HAUPPAUGE_HVR1110 104
#define SAA7134_BOARD_CINERGY_HT_PCMCIA 105
+#define SAA7134_BOARD_ENCORE_ENLTV 106
+#define SAA7134_BOARD_ENCORE_ENLTV_FM 107
+#define SAA7134_BOARD_CINERGY_HT_PCI 108
#define SAA7134_MAXBOARDS 8
#define SAA7134_INPUT_MAX 8
@@ -411,20 +410,6 @@ struct saa7134_dmasound {
struct snd_pcm_substream *substream;
};
-/* IR input */
-struct saa7134_ir {
- struct input_dev *dev;
- struct ir_input_state ir;
- char name[32];
- char phys[32];
- u32 mask_keycode;
- u32 mask_keydown;
- u32 mask_keyup;
- int polling;
- u32 last_gpio;
- struct timer_list timer;
-};
-
/* ts/mpeg status */
struct saa7134_ts {
/* TS capture */
@@ -463,7 +448,7 @@ struct saa7134_dev {
/* infrared remote */
int has_remote;
- struct saa7134_ir *remote;
+ struct card_ir *remote;
/* pci i/o */
char name[32];
@@ -543,9 +528,11 @@ struct saa7134_dev {
struct work_struct empress_workqueue;
int empress_started;
+#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE)
/* SAA7134_MPEG_DVB only */
struct videobuf_dvb dvb;
int (*original_demod_sleep)(struct dvb_frontend* fe);
+#endif
};
/* ----------------------------------------------------------- */
@@ -683,8 +670,8 @@ int saa_dsp_writel(struct saa7134_dev *dev, int reg, u32 value);
/* ----------------------------------------------------------- */
/* saa7134-oss.c */
-extern struct file_operations saa7134_dsp_fops;
-extern struct file_operations saa7134_mixer_fops;
+extern const struct file_operations saa7134_dsp_fops;
+extern const struct file_operations saa7134_mixer_fops;
int saa7134_oss_init1(struct saa7134_dev *dev);
int saa7134_oss_fini(struct saa7134_dev *dev);
@@ -698,6 +685,7 @@ void saa7134_input_fini(struct saa7134_dev *dev);
void saa7134_input_irq(struct saa7134_dev *dev);
void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir);
+
/*
* Local variables:
* c-basic-offset: 8
diff --git a/drivers/media/video/saa7185.c b/drivers/media/video/saa7185.c
index 9c308410856..e0fdb1ab758 100644
--- a/drivers/media/video/saa7185.c
+++ b/drivers/media/video/saa7185.c
@@ -38,7 +38,6 @@
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/page.h>
-#include <linux/sched.h>
#include <linux/types.h>
#include <linux/videodev.h>
diff --git a/drivers/media/video/saa7191.c b/drivers/media/video/saa7191.c
index 746cadb8f1c..8615a6081a5 100644
--- a/drivers/media/video/saa7191.c
+++ b/drivers/media/video/saa7191.c
@@ -17,7 +17,6 @@
#include <linux/major.h>
#include <linux/module.h>
#include <linux/mm.h>
-#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/videodev.h>
diff --git a/drivers/media/video/se401.c b/drivers/media/video/se401.c
index 7aeec574d7c..038448f5a97 100644
--- a/drivers/media/video/se401.c
+++ b/drivers/media/video/se401.c
@@ -1185,7 +1185,7 @@ static int se401_mmap(struct file *file, struct vm_area_struct *vma)
return 0;
}
-static struct file_operations se401_fops = {
+static const struct file_operations se401_fops = {
.owner = THIS_MODULE,
.open = se401_open,
.release = se401_close,
diff --git a/drivers/media/video/sn9c102/Kconfig b/drivers/media/video/sn9c102/Kconfig
index cf552e6b8ec..1a7ccb666ab 100644
--- a/drivers/media/video/sn9c102/Kconfig
+++ b/drivers/media/video/sn9c102/Kconfig
@@ -1,9 +1,9 @@
config USB_SN9C102
- tristate "USB SN9C10x PC Camera Controller support"
+ tristate "USB SN9C1xx PC Camera Controller support"
depends on USB && VIDEO_V4L1
---help---
Say Y here if you want support for cameras based on SONiX SN9C101,
- SN9C102 or SN9C103 PC Camera Controllers.
+ SN9C102, SN9C103, SN9C105 and SN9C120 PC Camera Controllers.
See <file:Documentation/video4linux/sn9c102.txt> for more info.
diff --git a/drivers/media/video/sn9c102/Makefile b/drivers/media/video/sn9c102/Makefile
index 536ad3098da..30e3dfe537f 100644
--- a/drivers/media/video/sn9c102/Makefile
+++ b/drivers/media/video/sn9c102/Makefile
@@ -1,5 +1,5 @@
sn9c102-objs := sn9c102_core.o sn9c102_hv7131d.o sn9c102_mi0343.o \
- sn9c102_ov7630.o sn9c102_pas106b.o sn9c102_pas202bca.o \
+ sn9c102_ov7630.o sn9c102_ov7660.o sn9c102_pas106b.o \
sn9c102_pas202bcb.o sn9c102_tas5110c1b.o \
sn9c102_tas5130d1b.o
diff --git a/drivers/media/video/sn9c102/sn9c102.h b/drivers/media/video/sn9c102/sn9c102.h
index 2c6ff396daf..5428f34e7c5 100644
--- a/drivers/media/video/sn9c102/sn9c102.h
+++ b/drivers/media/video/sn9c102/sn9c102.h
@@ -1,5 +1,5 @@
/***************************************************************************
- * V4L2 driver for SN9C10x PC Camera Controllers *
+ * V4L2 driver for SN9C1xx PC Camera Controllers *
* *
* Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
* *
@@ -37,33 +37,10 @@
#include <linux/string.h>
#include <linux/stddef.h>
+#include "sn9c102_config.h"
#include "sn9c102_sensor.h"
+#include "sn9c102_devtable.h"
-/*****************************************************************************/
-
-#define SN9C102_DEBUG
-#define SN9C102_DEBUG_LEVEL 2
-#define SN9C102_MAX_DEVICES 64
-#define SN9C102_PRESERVE_IMGSCALE 0
-#define SN9C102_FORCE_MUNMAP 0
-#define SN9C102_MAX_FRAMES 32
-#define SN9C102_URBS 2
-#define SN9C102_ISO_PACKETS 7
-#define SN9C102_ALTERNATE_SETTING 8
-#define SN9C102_URB_TIMEOUT msecs_to_jiffies(2 * SN9C102_ISO_PACKETS)
-#define SN9C102_CTRL_TIMEOUT 300
-#define SN9C102_FRAME_TIMEOUT 2
-
-/*****************************************************************************/
-
-enum sn9c102_bridge {
- BRIDGE_SN9C101 = 0x01,
- BRIDGE_SN9C102 = 0x02,
- BRIDGE_SN9C103 = 0x04,
-};
-
-SN9C102_ID_TABLE
-SN9C102_SENSOR_TABLE
enum sn9c102_frame_state {
F_UNUSED,
@@ -99,13 +76,11 @@ enum sn9c102_stream_state {
STREAM_ON,
};
-typedef char sn9c103_sof_header_t[18];
-typedef char sn9c102_sof_header_t[12];
-typedef char sn9c102_eof_header_t[4];
+typedef char sn9c102_sof_header_t[62];
struct sn9c102_sysfs_attr {
u8 reg, i2c_reg;
- sn9c103_sof_header_t frame_header;
+ sn9c102_sof_header_t frame_header;
};
struct sn9c102_module_param {
@@ -137,8 +112,8 @@ struct sn9c102_device {
struct v4l2_jpegcompression compression;
struct sn9c102_sysfs_attr sysfs;
- sn9c103_sof_header_t sof_header;
- u16 reg[63];
+ sn9c102_sof_header_t sof_header;
+ u16 reg[384];
struct sn9c102_module_param module_param;
@@ -155,10 +130,7 @@ struct sn9c102_device {
struct sn9c102_device*
sn9c102_match_id(struct sn9c102_device* cam, const struct usb_device_id *id)
{
- if (usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id))
- return cam;
-
- return NULL;
+ return usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id) ? cam : NULL;
}
@@ -169,6 +141,19 @@ sn9c102_attach_sensor(struct sn9c102_device* cam,
memcpy(&cam->sensor, sensor, sizeof(struct sn9c102_sensor));
}
+
+enum sn9c102_bridge
+sn9c102_get_bridge(struct sn9c102_device* cam)
+{
+ return cam->bridge;
+}
+
+
+struct sn9c102_sensor* sn9c102_get_sensor(struct sn9c102_device* cam)
+{
+ return &cam->sensor;
+}
+
/*****************************************************************************/
#undef DBG
diff --git a/drivers/media/video/sn9c102/sn9c102_config.h b/drivers/media/video/sn9c102/sn9c102_config.h
new file mode 100644
index 00000000000..0f4e0378b07
--- /dev/null
+++ b/drivers/media/video/sn9c102/sn9c102_config.h
@@ -0,0 +1,86 @@
+/***************************************************************************
+ * Global parameters for the V4L2 driver for SN9C1xx PC Camera Controllers *
+ * *
+ * Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.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. *
+ ***************************************************************************/
+
+#ifndef _SN9C102_CONFIG_H_
+#define _SN9C102_CONFIG_H_
+
+#include <linux/types.h>
+#include <linux/jiffies.h>
+
+#define SN9C102_DEBUG
+#define SN9C102_DEBUG_LEVEL 2
+#define SN9C102_MAX_DEVICES 64
+#define SN9C102_PRESERVE_IMGSCALE 0
+#define SN9C102_FORCE_MUNMAP 0
+#define SN9C102_MAX_FRAMES 32
+#define SN9C102_URBS 2
+#define SN9C102_ISO_PACKETS 7
+#define SN9C102_ALTERNATE_SETTING 8
+#define SN9C102_URB_TIMEOUT msecs_to_jiffies(2 * SN9C102_ISO_PACKETS)
+#define SN9C102_CTRL_TIMEOUT 300
+#define SN9C102_FRAME_TIMEOUT 0
+
+/*****************************************************************************/
+
+static const u8 SN9C102_Y_QTABLE0[64] = {
+ 8, 5, 5, 8, 12, 20, 25, 30,
+ 6, 6, 7, 9, 13, 29, 30, 27,
+ 7, 6, 8, 12, 20, 28, 34, 28,
+ 7, 8, 11, 14, 25, 43, 40, 31,
+ 9, 11, 18, 28, 34, 54, 51, 38,
+ 12, 17, 27, 32, 40, 52, 56, 46,
+ 24, 32, 39, 43, 51, 60, 60, 50,
+ 36, 46, 47, 49, 56, 50, 51, 49
+};
+
+static const u8 SN9C102_UV_QTABLE0[64] = {
+ 8, 9, 12, 23, 49, 49, 49, 49,
+ 9, 10, 13, 33, 49, 49, 49, 49,
+ 12, 13, 28, 49, 49, 49, 49, 49,
+ 23, 33, 49, 49, 49, 49, 49, 49,
+ 49, 49, 49, 49, 49, 49, 49, 49,
+ 49, 49, 49, 49, 49, 49, 49, 49,
+ 49, 49, 49, 49, 49, 49, 49, 49,
+ 49, 49, 49, 49, 49, 49, 49, 49
+};
+
+static const u8 SN9C102_Y_QTABLE1[64] = {
+ 16, 11, 10, 16, 24, 40, 51, 61,
+ 12, 12, 14, 19, 26, 58, 60, 55,
+ 14, 13, 16, 24, 40, 57, 69, 56,
+ 14, 17, 22, 29, 51, 87, 80, 62,
+ 18, 22, 37, 56, 68, 109, 103, 77,
+ 24, 35, 55, 64, 81, 104, 113, 92,
+ 49, 64, 78, 87, 103, 121, 120, 101,
+ 72, 92, 95, 98, 112, 100, 103, 99
+};
+
+static const u8 SN9C102_UV_QTABLE1[64] = {
+ 17, 18, 24, 47, 99, 99, 99, 99,
+ 18, 21, 26, 66, 99, 99, 99, 99,
+ 24, 26, 56, 99, 99, 99, 99, 99,
+ 47, 66, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99
+};
+
+#endif /* _SN9C102_CONFIG_H_ */
diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c
index 18458d46c0f..d0e2b40a772 100644
--- a/drivers/media/video/sn9c102/sn9c102_core.c
+++ b/drivers/media/video/sn9c102/sn9c102_core.c
@@ -1,7 +1,7 @@
/***************************************************************************
- * V4L2 driver for SN9C10x PC Camera Controllers *
+ * V4L2 driver for SN9C1xx PC Camera Controllers *
* *
- * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
+ * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.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 *
@@ -43,12 +43,12 @@
/*****************************************************************************/
-#define SN9C102_MODULE_NAME "V4L2 driver for SN9C10x PC Camera Controllers"
+#define SN9C102_MODULE_NAME "V4L2 driver for SN9C1xx PC Camera Controllers"
#define SN9C102_MODULE_AUTHOR "(C) 2004-2006 Luca Risolia"
#define SN9C102_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>"
#define SN9C102_MODULE_LICENSE "GPL"
-#define SN9C102_MODULE_VERSION "1:1.27"
-#define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 27)
+#define SN9C102_MODULE_VERSION "1:1.34"
+#define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 1, 34)
/*****************************************************************************/
@@ -91,7 +91,8 @@ static unsigned int frame_timeout[] = {[0 ... SN9C102_MAX_DEVICES-1] =
SN9C102_FRAME_TIMEOUT};
module_param_array(frame_timeout, uint, NULL, 0644);
MODULE_PARM_DESC(frame_timeout,
- "\n<n[,...]> Timeout for a video frame in seconds."
+ "\n<0|n[,...]> Timeout for a video frame in seconds before"
+ "\nreturning an I/O error; 0 for infinity."
"\nThis parameter is specific for each detected camera."
"\nDefault value is "__MODULE_STRING(SN9C102_FRAME_TIMEOUT)"."
"\n");
@@ -113,32 +114,13 @@ MODULE_PARM_DESC(debug,
/*****************************************************************************/
-static sn9c102_sof_header_t sn9c102_sof_header[] = {
- {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x00},
- {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x01},
-};
-
-static sn9c103_sof_header_t sn9c103_sof_header[] = {
- {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x20},
-};
-
-static sn9c102_eof_header_t sn9c102_eof_header[] = {
- {0x00, 0x00, 0x00, 0x00},
- {0x40, 0x00, 0x00, 0x00},
- {0x80, 0x00, 0x00, 0x00},
- {0xc0, 0x00, 0x00, 0x00},
-};
-
-/*****************************************************************************/
-
static u32
sn9c102_request_buffers(struct sn9c102_device* cam, u32 count,
enum sn9c102_io_method io)
{
struct v4l2_pix_format* p = &(cam->sensor.pix_format);
struct v4l2_rect* r = &(cam->sensor.cropcap.bounds);
- const size_t imagesize = cam->module_param.force_munmap ||
- io == IO_READ ?
+ size_t imagesize = cam->module_param.force_munmap || io == IO_READ ?
(p->width * p->height * p->priv) / 8 :
(r->width * r->height * p->priv) / 8;
void* buff = NULL;
@@ -147,9 +129,13 @@ sn9c102_request_buffers(struct sn9c102_device* cam, u32 count,
if (count > SN9C102_MAX_FRAMES)
count = SN9C102_MAX_FRAMES;
+ if (cam->bridge == BRIDGE_SN9C105 || cam->bridge == BRIDGE_SN9C120)
+ imagesize += 589 + 2; /* length of JPEG header + EOI marker */
+
cam->nbuffers = count;
while (cam->nbuffers > 0) {
- if ((buff = vmalloc_32(cam->nbuffers * PAGE_ALIGN(imagesize))))
+ if ((buff = vmalloc_32_user(cam->nbuffers *
+ PAGE_ALIGN(imagesize))))
break;
cam->nbuffers--;
}
@@ -322,9 +308,21 @@ static int
sn9c102_i2c_detect_read_error(struct sn9c102_device* cam,
struct sn9c102_sensor* sensor)
{
- int r;
+ int r , err = 0;
+
r = sn9c102_read_reg(cam, 0x08);
- return (r < 0 || (r >= 0 && !(r & 0x08))) ? -EIO : 0;
+ if (r < 0)
+ err += r;
+
+ if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) {
+ if (!(r & 0x08))
+ err += -1;
+ } else {
+ if (r & 0x08)
+ err += -1;
+ }
+
+ return err ? -EIO : 0;
}
@@ -415,7 +413,7 @@ sn9c102_i2c_try_raw_write(struct sn9c102_device* cam,
data[4] = data3;
data[5] = data4;
data[6] = data5;
- data[7] = 0x14;
+ data[7] = 0x17;
res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41,
0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT);
if (res < 0)
@@ -467,31 +465,35 @@ int sn9c102_i2c_write(struct sn9c102_device* cam, u8 address, u8 value)
/*****************************************************************************/
-static void*
-sn9c102_find_sof_header(struct sn9c102_device* cam, void* mem, size_t len)
+static size_t sn9c102_sof_length(struct sn9c102_device* cam)
{
- size_t soflen = 0, i;
- u8 j, n = 0;
-
switch (cam->bridge) {
case BRIDGE_SN9C101:
case BRIDGE_SN9C102:
- soflen = sizeof(sn9c102_sof_header_t);
- n = sizeof(sn9c102_sof_header) / soflen;
- break;
+ return 12;
case BRIDGE_SN9C103:
- soflen = sizeof(sn9c103_sof_header_t);
- n = sizeof(sn9c103_sof_header) / soflen;
+ return 18;
+ case BRIDGE_SN9C105:
+ case BRIDGE_SN9C120:
+ return 62;
}
+ return 0;
+}
+
+
+static void*
+sn9c102_find_sof_header(struct sn9c102_device* cam, void* mem, size_t len)
+{
+ char sof_header[6] = {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96};
+ size_t soflen = 0, i;
+
+ soflen = sn9c102_sof_length(cam);
+
for (i = 0; (len >= soflen) && (i <= len - soflen); i++)
- for (j = 0; j < n; j++)
- /* The invariable part of the header is 6 bytes long */
- if ((cam->bridge != BRIDGE_SN9C103 &&
- !memcmp(mem + i, sn9c102_sof_header[j], 6)) ||
- (cam->bridge == BRIDGE_SN9C103 &&
- !memcmp(mem + i, sn9c103_sof_header[j], 6))) {
- memcpy(cam->sof_header, mem + i, soflen);
+ if (!memcmp(mem + i, sof_header, sizeof(sof_header))) {
+ memcpy(cam->sof_header, mem + i,
+ sizeof(sn9c102_sof_header_t));
/* Skip the header */
return mem + i + soflen;
}
@@ -503,21 +505,123 @@ sn9c102_find_sof_header(struct sn9c102_device* cam, void* mem, size_t len)
static void*
sn9c102_find_eof_header(struct sn9c102_device* cam, void* mem, size_t len)
{
- size_t eoflen = sizeof(sn9c102_eof_header_t), i;
- unsigned j, n = sizeof(sn9c102_eof_header) / eoflen;
+ char eof_header[4][4] = {
+ {0x00, 0x00, 0x00, 0x00},
+ {0x40, 0x00, 0x00, 0x00},
+ {0x80, 0x00, 0x00, 0x00},
+ {0xc0, 0x00, 0x00, 0x00},
+ };
+ size_t i, j;
- if (cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X)
+ if (cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X ||
+ cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_JPEG)
return NULL; /* EOF header does not exist in compressed data */
- for (i = 0; (len >= eoflen) && (i <= len - eoflen); i++)
- for (j = 0; j < n; j++)
- if (!memcmp(mem + i, sn9c102_eof_header[j], eoflen))
+ for (i = 0; (len >= 4) && (i <= len - 4); i++)
+ for (j = 0; j < ARRAY_SIZE(eof_header); j++)
+ if (!memcmp(mem + i, eof_header[j], 4))
return mem + i;
return NULL;
}
+static void
+sn9c102_write_jpegheader(struct sn9c102_device* cam, struct sn9c102_frame_t* f)
+{
+ static u8 jpeg_header[589] = {
+ 0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x06, 0x04, 0x05,
+ 0x06, 0x05, 0x04, 0x06, 0x06, 0x05, 0x06, 0x07, 0x07, 0x06,
+ 0x08, 0x0a, 0x10, 0x0a, 0x0a, 0x09, 0x09, 0x0a, 0x14, 0x0e,
+ 0x0f, 0x0c, 0x10, 0x17, 0x14, 0x18, 0x18, 0x17, 0x14, 0x16,
+ 0x16, 0x1a, 0x1d, 0x25, 0x1f, 0x1a, 0x1b, 0x23, 0x1c, 0x16,
+ 0x16, 0x20, 0x2c, 0x20, 0x23, 0x26, 0x27, 0x29, 0x2a, 0x29,
+ 0x19, 0x1f, 0x2d, 0x30, 0x2d, 0x28, 0x30, 0x25, 0x28, 0x29,
+ 0x28, 0x01, 0x07, 0x07, 0x07, 0x0a, 0x08, 0x0a, 0x13, 0x0a,
+ 0x0a, 0x13, 0x28, 0x1a, 0x16, 0x1a, 0x28, 0x28, 0x28, 0x28,
+ 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
+ 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
+ 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
+ 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
+ 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0xff, 0xc4, 0x01, 0xa2,
+ 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02,
+ 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x01,
+ 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03,
+ 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x10, 0x00,
+ 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04,
+ 0x04, 0x00, 0x00, 0x01, 0x7d, 0x01, 0x02, 0x03, 0x00, 0x04,
+ 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61,
+ 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23,
+ 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62,
+ 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25,
+ 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38,
+ 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a,
+ 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64,
+ 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76,
+ 0x77, 0x78, 0x79, 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88,
+ 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
+ 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa,
+ 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2,
+ 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3,
+ 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, 0xe3,
+ 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3,
+ 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0x11, 0x00, 0x02,
+ 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04,
+ 0x00, 0x01, 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, 0x04,
+ 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
+ 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1,
+ 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1,
+ 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19,
+ 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
+ 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a,
+ 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64,
+ 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76,
+ 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
+ 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9,
+ 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba,
+ 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
+ 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe2, 0xe3,
+ 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4,
+ 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xff, 0xc0, 0x00, 0x11,
+ 0x08, 0x01, 0xe0, 0x02, 0x80, 0x03, 0x01, 0x21, 0x00, 0x02,
+ 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xda, 0x00, 0x0c, 0x03,
+ 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00
+ };
+ u8 *pos = f->bufmem;
+
+ memcpy(pos, jpeg_header, sizeof(jpeg_header));
+ *(pos + 6) = 0x00;
+ *(pos + 7 + 64) = 0x01;
+ if (cam->compression.quality == 0) {
+ memcpy(pos + 7, SN9C102_Y_QTABLE0, 64);
+ memcpy(pos + 8 + 64, SN9C102_UV_QTABLE0, 64);
+ } else if (cam->compression.quality == 1) {
+ memcpy(pos + 7, SN9C102_Y_QTABLE1, 64);
+ memcpy(pos + 8 + 64, SN9C102_UV_QTABLE1, 64);
+ }
+ *(pos + 564) = cam->sensor.pix_format.width & 0xFF;
+ *(pos + 563) = (cam->sensor.pix_format.width >> 8) & 0xFF;
+ *(pos + 562) = cam->sensor.pix_format.height & 0xFF;
+ *(pos + 561) = (cam->sensor.pix_format.height >> 8) & 0xFF;
+ *(pos + 567) = 0x21;
+
+ f->buf.bytesused += sizeof(jpeg_header);
+}
+
+
+static void
+sn9c102_write_eoimarker(struct sn9c102_device* cam, struct sn9c102_frame_t* f)
+{
+ static const u8 eoi_marker[2] = {0xff, 0xd9};
+
+ memcpy(f->bufmem + f->buf.bytesused, eoi_marker, sizeof(eoi_marker));
+ f->buf.bytesused += sizeof(eoi_marker);
+}
+
+
static void sn9c102_urb_complete(struct urb *urb)
{
struct sn9c102_device* cam = urb->context;
@@ -535,7 +639,7 @@ static void sn9c102_urb_complete(struct urb *urb)
cam->stream = STREAM_OFF;
if ((*f))
(*f)->state = F_QUEUED;
- DBG(3, "Stream interrupted");
+ DBG(3, "Stream interrupted by application");
wake_up(&cam->wait_stream);
}
@@ -557,10 +661,9 @@ static void sn9c102_urb_complete(struct urb *urb)
imagesize = (cam->sensor.pix_format.width *
cam->sensor.pix_format.height *
cam->sensor.pix_format.priv) / 8;
-
- soflen = (cam->bridge) == BRIDGE_SN9C103 ?
- sizeof(sn9c103_sof_header_t) :
- sizeof(sn9c102_sof_header_t);
+ if (cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_JPEG)
+ imagesize += 589; /* length of jpeg header */
+ soflen = sn9c102_sof_length(cam);
for (i = 0; i < urb->number_of_packets; i++) {
unsigned int img, len, status;
@@ -610,12 +713,21 @@ end_of_frame:
(*f)->buf.bytesused += img;
if ((*f)->buf.bytesused == imagesize ||
- (cam->sensor.pix_format.pixelformat ==
- V4L2_PIX_FMT_SN9C10X && eof)) {
+ ((cam->sensor.pix_format.pixelformat ==
+ V4L2_PIX_FMT_SN9C10X ||
+ cam->sensor.pix_format.pixelformat ==
+ V4L2_PIX_FMT_JPEG) && eof)) {
u32 b;
+
+ if (cam->sensor.pix_format.pixelformat
+ == V4L2_PIX_FMT_JPEG)
+ sn9c102_write_eoimarker(cam,
+ (*f));
+
b = (*f)->buf.bytesused;
(*f)->state = F_DONE;
(*f)->buf.sequence= ++cam->frame_count;
+
spin_lock(&cam->queue_lock);
list_move_tail(&(*f)->frame,
&cam->outqueue);
@@ -627,8 +739,10 @@ end_of_frame:
else
(*f) = NULL;
spin_unlock(&cam->queue_lock);
+
memcpy(cam->sysfs.frame_header,
cam->sof_header, soflen);
+
DBG(3, "Video frame captured: %lu "
"bytes", (unsigned long)(b));
@@ -661,6 +775,9 @@ start_of_frame:
(*f)->buf.bytesused = 0;
len -= (sof - pos);
pos = sof;
+ if (cam->sensor.pix_format.pixelformat ==
+ V4L2_PIX_FMT_JPEG)
+ sn9c102_write_jpegheader(cam, (*f));
DBG(3, "SOF detected: new video frame");
if (len)
goto redo;
@@ -671,7 +788,9 @@ start_of_frame:
goto end_of_frame; /* (1) */
else {
if (cam->sensor.pix_format.pixelformat ==
- V4L2_PIX_FMT_SN9C10X) {
+ V4L2_PIX_FMT_SN9C10X ||
+ cam->sensor.pix_format.pixelformat ==
+ V4L2_PIX_FMT_JPEG) {
eof = sof - soflen;
goto end_of_frame;
} else {
@@ -701,13 +820,11 @@ static int sn9c102_start_transfer(struct sn9c102_device* cam)
{
struct usb_device *udev = cam->usbdev;
struct urb* urb;
- const unsigned int sn9c102_wMaxPacketSize[] = {0, 128, 256, 384, 512,
- 680, 800, 900, 1023};
- const unsigned int sn9c103_wMaxPacketSize[] = {0, 128, 256, 384, 512,
- 680, 800, 900, 1003};
- const unsigned int psz = (cam->bridge == BRIDGE_SN9C103) ?
- sn9c103_wMaxPacketSize[SN9C102_ALTERNATE_SETTING] :
- sn9c102_wMaxPacketSize[SN9C102_ALTERNATE_SETTING];
+ struct usb_host_interface* altsetting = usb_altnum_to_altsetting(
+ usb_ifnum_to_if(udev, 0),
+ SN9C102_ALTERNATE_SETTING);
+ const unsigned int psz = le16_to_cpu(altsetting->
+ endpoint[0].desc.wMaxPacketSize);
s8 i, j;
int err = 0;
@@ -775,7 +892,7 @@ static int sn9c102_start_transfer(struct sn9c102_device* cam)
return 0;
free_urbs:
- for (i = 0; i < SN9C102_URBS; i++)
+ for (i = 0; (i < SN9C102_URBS) && cam->urb[i]; i++)
usb_free_urb(cam->urb[i]);
free_buffers:
@@ -834,29 +951,29 @@ static int sn9c102_stream_interrupt(struct sn9c102_device* cam)
/*****************************************************************************/
#ifdef CONFIG_VIDEO_ADV_DEBUG
-static u8 sn9c102_strtou8(const char* buff, size_t len, ssize_t* count)
+static u16 sn9c102_strtou16(const char* buff, size_t len, ssize_t* count)
{
- char str[5];
+ char str[7];
char* endp;
unsigned long val;
- if (len < 4) {
+ if (len < 6) {
strncpy(str, buff, len);
str[len+1] = '\0';
} else {
strncpy(str, buff, 4);
- str[4] = '\0';
+ str[6] = '\0';
}
val = simple_strtoul(str, &endp, 0);
*count = 0;
- if (val <= 0xff)
+ if (val <= 0xffff)
*count = (ssize_t)(endp - str);
if ((*count) && (len == *count+1) && (buff[*count] == '\n'))
*count += 1;
- return (u8)val;
+ return (u16)val;
}
/*
@@ -873,7 +990,8 @@ static ssize_t sn9c102_show_reg(struct class_device* cd, char* buf)
if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
return -ERESTARTSYS;
- cam = video_get_drvdata(to_video_device(cd));
+ cam = video_get_drvdata(container_of(cd, struct video_device,
+ class_dev));
if (!cam) {
mutex_unlock(&sn9c102_sysfs_lock);
return -ENODEV;
@@ -891,27 +1009,28 @@ static ssize_t
sn9c102_store_reg(struct class_device* cd, const char* buf, size_t len)
{
struct sn9c102_device* cam;
- u8 index;
+ u16 index;
ssize_t count;
if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
return -ERESTARTSYS;
- cam = video_get_drvdata(to_video_device(cd));
+ cam = video_get_drvdata(container_of(cd, struct video_device,
+ class_dev));
if (!cam) {
mutex_unlock(&sn9c102_sysfs_lock);
return -ENODEV;
}
- index = sn9c102_strtou8(buf, len, &count);
- if (index > 0x1f || !count) {
+ index = sn9c102_strtou16(buf, len, &count);
+ if (index >= ARRAY_SIZE(cam->reg) || !count) {
mutex_unlock(&sn9c102_sysfs_lock);
return -EINVAL;
}
cam->sysfs.reg = index;
- DBG(2, "Moved SN9C10X register index to 0x%02X", cam->sysfs.reg);
+ DBG(2, "Moved SN9C1XX register index to 0x%02X", cam->sysfs.reg);
DBG(3, "Written bytes: %zd", count);
mutex_unlock(&sn9c102_sysfs_lock);
@@ -929,7 +1048,8 @@ static ssize_t sn9c102_show_val(struct class_device* cd, char* buf)
if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
return -ERESTARTSYS;
- cam = video_get_drvdata(to_video_device(cd));
+ cam = video_get_drvdata(container_of(cd, struct video_device,
+ class_dev));
if (!cam) {
mutex_unlock(&sn9c102_sysfs_lock);
return -ENODEV;
@@ -954,20 +1074,21 @@ static ssize_t
sn9c102_store_val(struct class_device* cd, const char* buf, size_t len)
{
struct sn9c102_device* cam;
- u8 value;
+ u16 value;
ssize_t count;
int err;
if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
return -ERESTARTSYS;
- cam = video_get_drvdata(to_video_device(cd));
+ cam = video_get_drvdata(container_of(cd, struct video_device,
+ class_dev));
if (!cam) {
mutex_unlock(&sn9c102_sysfs_lock);
return -ENODEV;
}
- value = sn9c102_strtou8(buf, len, &count);
+ value = sn9c102_strtou16(buf, len, &count);
if (!count) {
mutex_unlock(&sn9c102_sysfs_lock);
return -EINVAL;
@@ -979,7 +1100,7 @@ sn9c102_store_val(struct class_device* cd, const char* buf, size_t len)
return -EIO;
}
- DBG(2, "Written SN9C10X reg. 0x%02X, val. 0x%02X",
+ DBG(2, "Written SN9C1XX reg. 0x%02X, val. 0x%02X",
cam->sysfs.reg, value);
DBG(3, "Written bytes: %zd", count);
@@ -997,7 +1118,8 @@ static ssize_t sn9c102_show_i2c_reg(struct class_device* cd, char* buf)
if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
return -ERESTARTSYS;
- cam = video_get_drvdata(to_video_device(cd));
+ cam = video_get_drvdata(container_of(cd, struct video_device,
+ class_dev));
if (!cam) {
mutex_unlock(&sn9c102_sysfs_lock);
return -ENODEV;
@@ -1017,19 +1139,20 @@ static ssize_t
sn9c102_store_i2c_reg(struct class_device* cd, const char* buf, size_t len)
{
struct sn9c102_device* cam;
- u8 index;
+ u16 index;
ssize_t count;
if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
return -ERESTARTSYS;
- cam = video_get_drvdata(to_video_device(cd));
+ cam = video_get_drvdata(container_of(cd, struct video_device,
+ class_dev));
if (!cam) {
mutex_unlock(&sn9c102_sysfs_lock);
return -ENODEV;
}
- index = sn9c102_strtou8(buf, len, &count);
+ index = sn9c102_strtou16(buf, len, &count);
if (!count) {
mutex_unlock(&sn9c102_sysfs_lock);
return -EINVAL;
@@ -1055,7 +1178,8 @@ static ssize_t sn9c102_show_i2c_val(struct class_device* cd, char* buf)
if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
return -ERESTARTSYS;
- cam = video_get_drvdata(to_video_device(cd));
+ cam = video_get_drvdata(container_of(cd, struct video_device,
+ class_dev));
if (!cam) {
mutex_unlock(&sn9c102_sysfs_lock);
return -ENODEV;
@@ -1085,14 +1209,15 @@ static ssize_t
sn9c102_store_i2c_val(struct class_device* cd, const char* buf, size_t len)
{
struct sn9c102_device* cam;
- u8 value;
+ u16 value;
ssize_t count;
int err;
if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
return -ERESTARTSYS;
- cam = video_get_drvdata(to_video_device(cd));
+ cam = video_get_drvdata(container_of(cd, struct video_device,
+ class_dev));
if (!cam) {
mutex_unlock(&sn9c102_sysfs_lock);
return -ENODEV;
@@ -1103,7 +1228,7 @@ sn9c102_store_i2c_val(struct class_device* cd, const char* buf, size_t len)
return -ENOSYS;
}
- value = sn9c102_strtou8(buf, len, &count);
+ value = sn9c102_strtou16(buf, len, &count);
if (!count) {
mutex_unlock(&sn9c102_sysfs_lock);
return -EINVAL;
@@ -1131,13 +1256,14 @@ sn9c102_store_green(struct class_device* cd, const char* buf, size_t len)
struct sn9c102_device* cam;
enum sn9c102_bridge bridge;
ssize_t res = 0;
- u8 value;
+ u16 value;
ssize_t count;
if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
return -ERESTARTSYS;
- cam = video_get_drvdata(to_video_device(cd));
+ cam = video_get_drvdata(container_of(cd, struct video_device,
+ class_dev));
if (!cam) {
mutex_unlock(&sn9c102_sysfs_lock);
return -ENODEV;
@@ -1147,7 +1273,7 @@ sn9c102_store_green(struct class_device* cd, const char* buf, size_t len)
mutex_unlock(&sn9c102_sysfs_lock);
- value = sn9c102_strtou8(buf, len, &count);
+ value = sn9c102_strtou16(buf, len, &count);
if (!count)
return -EINVAL;
@@ -1160,9 +1286,11 @@ sn9c102_store_green(struct class_device* cd, const char* buf, size_t len)
res = sn9c102_store_val(cd, buf, len);
break;
case BRIDGE_SN9C103:
+ case BRIDGE_SN9C105:
+ case BRIDGE_SN9C120:
if (value > 0x7f)
return -EINVAL;
- if ((res = sn9c102_store_reg(cd, "0x04", 4)) >= 0)
+ if ((res = sn9c102_store_reg(cd, "0x07", 4)) >= 0)
res = sn9c102_store_val(cd, buf, len);
break;
}
@@ -1175,10 +1303,10 @@ static ssize_t
sn9c102_store_blue(struct class_device* cd, const char* buf, size_t len)
{
ssize_t res = 0;
- u8 value;
+ u16 value;
ssize_t count;
- value = sn9c102_strtou8(buf, len, &count);
+ value = sn9c102_strtou16(buf, len, &count);
if (!count || value > 0x7f)
return -EINVAL;
@@ -1193,10 +1321,10 @@ static ssize_t
sn9c102_store_red(struct class_device* cd, const char* buf, size_t len)
{
ssize_t res = 0;
- u8 value;
+ u16 value;
ssize_t count;
- value = sn9c102_strtou8(buf, len, &count);
+ value = sn9c102_strtou16(buf, len, &count);
if (!count || value > 0x7f)
return -EINVAL;
@@ -1212,7 +1340,8 @@ static ssize_t sn9c102_show_frame_header(struct class_device* cd, char* buf)
struct sn9c102_device* cam;
ssize_t count;
- cam = video_get_drvdata(to_video_device(cd));
+ cam = video_get_drvdata(container_of(cd, struct video_device,
+ class_dev));
if (!cam)
return -ENODEV;
@@ -1243,30 +1372,36 @@ static CLASS_DEVICE_ATTR(frame_header, S_IRUGO,
static int sn9c102_create_sysfs(struct sn9c102_device* cam)
{
struct video_device *v4ldev = cam->v4ldev;
- int rc;
+ int err = 0;
- rc = video_device_create_file(v4ldev, &class_device_attr_reg);
- if (rc) goto err;
- rc = video_device_create_file(v4ldev, &class_device_attr_val);
- if (rc) goto err_reg;
- rc = video_device_create_file(v4ldev, &class_device_attr_frame_header);
- if (rc) goto err_val;
+ if ((err = video_device_create_file(v4ldev, &class_device_attr_reg)))
+ goto err_out;
+ if ((err = video_device_create_file(v4ldev, &class_device_attr_val)))
+ goto err_reg;
+ if ((err = video_device_create_file(v4ldev,
+ &class_device_attr_frame_header)))
+ goto err_val;
if (cam->sensor.sysfs_ops) {
- rc = video_device_create_file(v4ldev, &class_device_attr_i2c_reg);
- if (rc) goto err_frhead;
- rc = video_device_create_file(v4ldev, &class_device_attr_i2c_val);
- if (rc) goto err_i2c_reg;
+ if ((err = video_device_create_file(v4ldev,
+ &class_device_attr_i2c_reg)))
+ goto err_frame_header;
+ if ((err = video_device_create_file(v4ldev,
+ &class_device_attr_i2c_val)))
+ goto err_i2c_reg;
}
if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) {
- rc = video_device_create_file(v4ldev, &class_device_attr_green);
- if (rc) goto err_i2c_val;
- } else if (cam->bridge == BRIDGE_SN9C103) {
- rc = video_device_create_file(v4ldev, &class_device_attr_blue);
- if (rc) goto err_i2c_val;
- rc = video_device_create_file(v4ldev, &class_device_attr_red);
- if (rc) goto err_blue;
+ if ((err = video_device_create_file(v4ldev,
+ &class_device_attr_green)))
+ goto err_i2c_val;
+ } else {
+ if ((err = video_device_create_file(v4ldev,
+ &class_device_attr_blue)))
+ goto err_i2c_val;
+ if ((err = video_device_create_file(v4ldev,
+ &class_device_attr_red)))
+ goto err_blue;
}
return 0;
@@ -1279,14 +1414,14 @@ err_i2c_val:
err_i2c_reg:
if (cam->sensor.sysfs_ops)
video_device_remove_file(v4ldev, &class_device_attr_i2c_reg);
-err_frhead:
+err_frame_header:
video_device_remove_file(v4ldev, &class_device_attr_frame_header);
err_val:
video_device_remove_file(v4ldev, &class_device_attr_val);
err_reg:
video_device_remove_file(v4ldev, &class_device_attr_reg);
-err:
- return rc;
+err_out:
+ return err;
}
#endif /* CONFIG_VIDEO_ADV_DEBUG */
@@ -1297,10 +1432,36 @@ sn9c102_set_pix_format(struct sn9c102_device* cam, struct v4l2_pix_format* pix)
{
int err = 0;
- if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
- err += sn9c102_write_reg(cam, cam->reg[0x18] | 0x80, 0x18);
- else
- err += sn9c102_write_reg(cam, cam->reg[0x18] & 0x7f, 0x18);
+ if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X ||
+ pix->pixelformat == V4L2_PIX_FMT_JPEG) {
+ switch (cam->bridge) {
+ case BRIDGE_SN9C101:
+ case BRIDGE_SN9C102:
+ case BRIDGE_SN9C103:
+ err += sn9c102_write_reg(cam, cam->reg[0x18] | 0x80,
+ 0x18);
+ break;
+ case BRIDGE_SN9C105:
+ case BRIDGE_SN9C120:
+ err += sn9c102_write_reg(cam, cam->reg[0x18] & 0x7f,
+ 0x18);
+ break;
+ }
+ } else {
+ switch (cam->bridge) {
+ case BRIDGE_SN9C101:
+ case BRIDGE_SN9C102:
+ case BRIDGE_SN9C103:
+ err += sn9c102_write_reg(cam, cam->reg[0x18] & 0x7f,
+ 0x18);
+ break;
+ case BRIDGE_SN9C105:
+ case BRIDGE_SN9C120:
+ err += sn9c102_write_reg(cam, cam->reg[0x18] | 0x80,
+ 0x18);
+ break;
+ }
+ }
return err ? -EIO : 0;
}
@@ -1310,12 +1471,46 @@ static int
sn9c102_set_compression(struct sn9c102_device* cam,
struct v4l2_jpegcompression* compression)
{
- int err = 0;
+ int i, err = 0;
+ switch (cam->bridge) {
+ case BRIDGE_SN9C101:
+ case BRIDGE_SN9C102:
+ case BRIDGE_SN9C103:
if (compression->quality == 0)
- err += sn9c102_write_reg(cam, cam->reg[0x17] | 0x01, 0x17);
+ err += sn9c102_write_reg(cam, cam->reg[0x17] | 0x01,
+ 0x17);
else if (compression->quality == 1)
- err += sn9c102_write_reg(cam, cam->reg[0x17] & 0xfe, 0x17);
+ err += sn9c102_write_reg(cam, cam->reg[0x17] & 0xfe,
+ 0x17);
+ break;
+ case BRIDGE_SN9C105:
+ case BRIDGE_SN9C120:
+ if (compression->quality == 0) {
+ for (i = 0; i <= 63; i++) {
+ err += sn9c102_write_reg(cam,
+ SN9C102_Y_QTABLE0[i],
+ 0x100 + i);
+ err += sn9c102_write_reg(cam,
+ SN9C102_UV_QTABLE0[i],
+ 0x140 + i);
+ }
+ err += sn9c102_write_reg(cam, cam->reg[0x18] & 0xbf,
+ 0x18);
+ } else if (compression->quality == 1) {
+ for (i = 0; i <= 63; i++) {
+ err += sn9c102_write_reg(cam,
+ SN9C102_Y_QTABLE1[i],
+ 0x100 + i);
+ err += sn9c102_write_reg(cam,
+ SN9C102_UV_QTABLE1[i],
+ 0x140 + i);
+ }
+ err += sn9c102_write_reg(cam, cam->reg[0x18] | 0x40,
+ 0x18);
+ }
+ break;
+ }
return err ? -EIO : 0;
}
@@ -1399,7 +1594,16 @@ static int sn9c102_init(struct sn9c102_device* cam)
}
if (!(cam->state & DEV_INITIALIZED))
- cam->compression.quality = cam->reg[0x17] & 0x01 ? 0 : 1;
+ if (cam->bridge == BRIDGE_SN9C101 ||
+ cam->bridge == BRIDGE_SN9C102 ||
+ cam->bridge == BRIDGE_SN9C103) {
+ cam->compression.quality = cam->reg[0x17] & 0x01 ?
+ 0 : 1;
+ } else {
+ cam->compression.quality = cam->reg[0x18] & 0x40 ?
+ 0 : 1;
+ err += sn9c102_set_compression(cam, &cam->compression);
+ }
else
err += sn9c102_set_compression(cam, &cam->compression);
err += sn9c102_set_pix_format(cam, &s->pix_format);
@@ -1408,7 +1612,8 @@ static int sn9c102_init(struct sn9c102_device* cam)
if (err)
return err;
- if (s->pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X)
+ if (s->pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X ||
+ s->pix_format.pixelformat == V4L2_PIX_FMT_JPEG)
DBG(3, "Compressed video format is active, quality %d",
cam->compression.quality);
else
@@ -1490,6 +1695,7 @@ static int sn9c102_open(struct inode* inode, struct file* filp)
if (cam->users) {
DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor);
+ DBG(3, "Simultaneous opens are not supported");
if ((filp->f_flags & O_NONBLOCK) ||
(filp->f_flags & O_NDELAY)) {
err = -EWOULDBLOCK;
@@ -1628,6 +1834,17 @@ sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
mutex_unlock(&cam->fileop_mutex);
return -EAGAIN;
}
+ if (!cam->module_param.frame_timeout) {
+ err = wait_event_interruptible
+ ( cam->wait_frame,
+ (!list_empty(&cam->outqueue)) ||
+ (cam->state & DEV_DISCONNECTED) ||
+ (cam->state & DEV_MISCONFIGURED) );
+ if (err) {
+ mutex_unlock(&cam->fileop_mutex);
+ return err;
+ }
+ } else {
timeout = wait_event_interruptible_timeout
( cam->wait_frame,
(!list_empty(&cam->outqueue)) ||
@@ -1638,12 +1855,18 @@ sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
if (timeout < 0) {
mutex_unlock(&cam->fileop_mutex);
return timeout;
+ } else if (timeout == 0 &&
+ !(cam->state & DEV_DISCONNECTED)) {
+ DBG(1, "Video frame timeout elapsed");
+ mutex_unlock(&cam->fileop_mutex);
+ return -EIO;
+ }
}
if (cam->state & DEV_DISCONNECTED) {
mutex_unlock(&cam->fileop_mutex);
return -ENODEV;
}
- if (!timeout || (cam->state & DEV_MISCONFIGURED)) {
+ if (cam->state & DEV_MISCONFIGURED) {
mutex_unlock(&cam->fileop_mutex);
return -EIO;
}
@@ -1940,6 +2163,9 @@ exit:
if (copy_to_user(arg, &ctrl, sizeof(ctrl)))
return -EFAULT;
+ PDBGG("VIDIOC_G_CTRL: id %lu, value %lu",
+ (unsigned long)ctrl.id, (unsigned long)ctrl.value);
+
return err;
}
@@ -2127,6 +2353,45 @@ sn9c102_vidioc_s_crop(struct sn9c102_device* cam, void __user * arg)
static int
+sn9c102_vidioc_enum_framesizes(struct sn9c102_device* cam, void __user * arg)
+{
+ struct v4l2_frmsizeenum frmsize;
+
+ if (copy_from_user(&frmsize, arg, sizeof(frmsize)))
+ return -EFAULT;
+
+ if (frmsize.index != 0)
+ return -EINVAL;
+
+ switch (cam->bridge) {
+ case BRIDGE_SN9C101:
+ case BRIDGE_SN9C102:
+ case BRIDGE_SN9C103:
+ if (frmsize.pixel_format != V4L2_PIX_FMT_SN9C10X &&
+ frmsize.pixel_format != V4L2_PIX_FMT_SBGGR8)
+ return -EINVAL;
+ case BRIDGE_SN9C105:
+ case BRIDGE_SN9C120:
+ if (frmsize.pixel_format != V4L2_PIX_FMT_JPEG &&
+ frmsize.pixel_format != V4L2_PIX_FMT_SBGGR8)
+ return -EINVAL;
+ }
+
+ frmsize.type = V4L2_FRMSIZE_TYPE_STEPWISE;
+ frmsize.stepwise.min_width = frmsize.stepwise.step_width = 16;
+ frmsize.stepwise.min_height = frmsize.stepwise.step_height = 16;
+ frmsize.stepwise.max_width = cam->sensor.cropcap.bounds.width;
+ frmsize.stepwise.max_height = cam->sensor.cropcap.bounds.height;
+ memset(&frmsize.reserved, 0, sizeof(frmsize.reserved));
+
+ if (copy_to_user(arg, &frmsize, sizeof(frmsize)))
+ return -EFAULT;
+
+ return 0;
+}
+
+
+static int
sn9c102_vidioc_enum_fmt(struct sn9c102_device* cam, void __user * arg)
{
struct v4l2_fmtdesc fmtd;
@@ -2134,12 +2399,26 @@ sn9c102_vidioc_enum_fmt(struct sn9c102_device* cam, void __user * arg)
if (copy_from_user(&fmtd, arg, sizeof(fmtd)))
return -EFAULT;
+ if (fmtd.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
if (fmtd.index == 0) {
strcpy(fmtd.description, "bayer rgb");
fmtd.pixelformat = V4L2_PIX_FMT_SBGGR8;
} else if (fmtd.index == 1) {
+ switch (cam->bridge) {
+ case BRIDGE_SN9C101:
+ case BRIDGE_SN9C102:
+ case BRIDGE_SN9C103:
strcpy(fmtd.description, "compressed");
fmtd.pixelformat = V4L2_PIX_FMT_SN9C10X;
+ break;
+ case BRIDGE_SN9C105:
+ case BRIDGE_SN9C120:
+ strcpy(fmtd.description, "JPEG");
+ fmtd.pixelformat = V4L2_PIX_FMT_JPEG;
+ break;
+ }
fmtd.flags = V4L2_FMT_FLAG_COMPRESSED;
} else
return -EINVAL;
@@ -2166,7 +2445,8 @@ sn9c102_vidioc_g_fmt(struct sn9c102_device* cam, void __user * arg)
if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
- pfmt->bytesperline = (pfmt->pixelformat==V4L2_PIX_FMT_SN9C10X)
+ pfmt->bytesperline = (pfmt->pixelformat==V4L2_PIX_FMT_SN9C10X ||
+ pfmt->pixelformat==V4L2_PIX_FMT_JPEG)
? 0 : (pfmt->width * pfmt->priv) / 8;
pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8);
pfmt->field = V4L2_FIELD_NONE;
@@ -2237,12 +2517,25 @@ sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd,
pix->width = rect.width / scale;
pix->height = rect.height / scale;
+ switch (cam->bridge) {
+ case BRIDGE_SN9C101:
+ case BRIDGE_SN9C102:
+ case BRIDGE_SN9C103:
if (pix->pixelformat != V4L2_PIX_FMT_SN9C10X &&
pix->pixelformat != V4L2_PIX_FMT_SBGGR8)
pix->pixelformat = pfmt->pixelformat;
+ break;
+ case BRIDGE_SN9C105:
+ case BRIDGE_SN9C120:
+ if (pix->pixelformat != V4L2_PIX_FMT_JPEG &&
+ pix->pixelformat != V4L2_PIX_FMT_SBGGR8)
+ pix->pixelformat = pfmt->pixelformat;
+ break;
+ }
pix->priv = pfmt->priv; /* bpp */
pix->colorspace = pfmt->colorspace;
- pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
+ pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_SN9C10X ||
+ pix->pixelformat == V4L2_PIX_FMT_JPEG)
? 0 : (pix->width * pix->priv) / 8;
pix->sizeimage = pix->height * ((pix->width * pix->priv) / 8);
pix->field = V4L2_FIELD_NONE;
@@ -2315,8 +2608,7 @@ sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd,
static int
sn9c102_vidioc_g_jpegcomp(struct sn9c102_device* cam, void __user * arg)
{
- if (copy_to_user(arg, &cam->compression,
- sizeof(cam->compression)))
+ if (copy_to_user(arg, &cam->compression, sizeof(cam->compression)))
return -EFAULT;
return 0;
@@ -2471,6 +2763,7 @@ sn9c102_vidioc_dqbuf(struct sn9c102_device* cam, struct file* filp,
struct sn9c102_frame_t *f;
unsigned long lock_flags;
long timeout;
+ int err = 0;
if (copy_from_user(&b, arg, sizeof(b)))
return -EFAULT;
@@ -2483,6 +2776,15 @@ sn9c102_vidioc_dqbuf(struct sn9c102_device* cam, struct file* filp,
return -EINVAL;
if (filp->f_flags & O_NONBLOCK)
return -EAGAIN;
+ if (!cam->module_param.frame_timeout) {
+ err = wait_event_interruptible
+ ( cam->wait_frame,
+ (!list_empty(&cam->outqueue)) ||
+ (cam->state & DEV_DISCONNECTED) ||
+ (cam->state & DEV_MISCONFIGURED) );
+ if (err)
+ return err;
+ } else {
timeout = wait_event_interruptible_timeout
( cam->wait_frame,
(!list_empty(&cam->outqueue)) ||
@@ -2492,9 +2794,15 @@ sn9c102_vidioc_dqbuf(struct sn9c102_device* cam, struct file* filp,
1000 * msecs_to_jiffies(1) );
if (timeout < 0)
return timeout;
+ else if (timeout == 0 &&
+ !(cam->state & DEV_DISCONNECTED)) {
+ DBG(1, "Video frame timeout elapsed");
+ return -EIO;
+ }
+ }
if (cam->state & DEV_DISCONNECTED)
return -ENODEV;
- if (!timeout || (cam->state & DEV_MISCONFIGURED))
+ if (cam->state & DEV_MISCONFIGURED)
return -EIO;
}
@@ -2612,6 +2920,70 @@ sn9c102_vidioc_s_parm(struct sn9c102_device* cam, void __user * arg)
}
+static int
+sn9c102_vidioc_enumaudio(struct sn9c102_device* cam, void __user * arg)
+{
+ struct v4l2_audio audio;
+
+ if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102)
+ return -EINVAL;
+
+ if (copy_from_user(&audio, arg, sizeof(audio)))
+ return -EFAULT;
+
+ if (audio.index != 0)
+ return -EINVAL;
+
+ strcpy(audio.name, "Microphone");
+ audio.capability = 0;
+ audio.mode = 0;
+
+ if (copy_to_user(arg, &audio, sizeof(audio)))
+ return -EFAULT;
+
+ return 0;
+}
+
+
+static int
+sn9c102_vidioc_g_audio(struct sn9c102_device* cam, void __user * arg)
+{
+ struct v4l2_audio audio;
+
+ if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102)
+ return -EINVAL;
+
+ if (copy_from_user(&audio, arg, sizeof(audio)))
+ return -EFAULT;
+
+ memset(&audio, 0, sizeof(audio));
+ strcpy(audio.name, "Microphone");
+
+ if (copy_to_user(arg, &audio, sizeof(audio)))
+ return -EFAULT;
+
+ return 0;
+}
+
+
+static int
+sn9c102_vidioc_s_audio(struct sn9c102_device* cam, void __user * arg)
+{
+ struct v4l2_audio audio;
+
+ if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102)
+ return -EINVAL;
+
+ if (copy_from_user(&audio, arg, sizeof(audio)))
+ return -EFAULT;
+
+ if (audio.index != 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+
static int sn9c102_ioctl_v4l2(struct inode* inode, struct file* filp,
unsigned int cmd, void __user * arg)
{
@@ -2649,6 +3021,9 @@ static int sn9c102_ioctl_v4l2(struct inode* inode, struct file* filp,
case VIDIOC_S_CROP:
return sn9c102_vidioc_s_crop(cam, arg);
+ case VIDIOC_ENUM_FRAMESIZES:
+ return sn9c102_vidioc_enum_framesizes(cam, arg);
+
case VIDIOC_ENUM_FMT:
return sn9c102_vidioc_enum_fmt(cam, arg);
@@ -2689,11 +3064,21 @@ static int sn9c102_ioctl_v4l2(struct inode* inode, struct file* filp,
case VIDIOC_S_PARM:
return sn9c102_vidioc_s_parm(cam, arg);
+ case VIDIOC_ENUMAUDIO:
+ return sn9c102_vidioc_enumaudio(cam, arg);
+
+ case VIDIOC_G_AUDIO:
+ return sn9c102_vidioc_g_audio(cam, arg);
+
+ case VIDIOC_S_AUDIO:
+ return sn9c102_vidioc_s_audio(cam, arg);
+
case VIDIOC_G_STD:
case VIDIOC_S_STD:
case VIDIOC_QUERYSTD:
case VIDIOC_ENUMSTD:
case VIDIOC_QUERYMENU:
+ case VIDIOC_ENUM_FRAMEINTERVALS:
return -EINVAL;
default:
@@ -2736,11 +3121,12 @@ static int sn9c102_ioctl(struct inode* inode, struct file* filp,
/*****************************************************************************/
-static struct file_operations sn9c102_fops = {
+static const struct file_operations sn9c102_fops = {
.owner = THIS_MODULE,
.open = sn9c102_open,
.release = sn9c102_release,
.ioctl = sn9c102_ioctl,
+ .compat_ioctl = v4l_compat_ioctl32,
.read = sn9c102_read,
.poll = sn9c102_poll,
.mmap = sn9c102_mmap,
@@ -2765,7 +3151,7 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
cam->usbdev = udev;
if (!(cam->control_buffer = kzalloc(8, GFP_KERNEL))) {
- DBG(1, "kmalloc() failed");
+ DBG(1, "kzalloc() failed");
err = -ENOMEM;
goto fail;
}
@@ -2779,24 +3165,31 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
mutex_init(&cam->dev_mutex);
r = sn9c102_read_reg(cam, 0x00);
- if (r < 0 || r != 0x10) {
- DBG(1, "Sorry, this is not a SN9C10x based camera "
- "(vid/pid 0x%04X/0x%04X)", id->idVendor, id->idProduct);
+ if (r < 0 || (r != 0x10 && r != 0x11 && r != 0x12)) {
+ DBG(1, "Sorry, this is not a SN9C1xx based camera "
+ "(vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
err = -ENODEV;
goto fail;
}
- cam->bridge = (id->idProduct & 0xffc0) == 0x6080 ?
- BRIDGE_SN9C103 : BRIDGE_SN9C102;
+ cam->bridge = id->driver_info;
switch (cam->bridge) {
case BRIDGE_SN9C101:
case BRIDGE_SN9C102:
DBG(2, "SN9C10[12] PC Camera Controller detected "
- "(vid/pid 0x%04X/0x%04X)", id->idVendor, id->idProduct);
+ "(vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
break;
case BRIDGE_SN9C103:
DBG(2, "SN9C103 PC Camera Controller detected "
- "(vid/pid 0x%04X/0x%04X)", id->idVendor, id->idProduct);
+ "(vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
+ break;
+ case BRIDGE_SN9C105:
+ DBG(2, "SN9C105 PC Camera Controller detected "
+ "(vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
+ break;
+ case BRIDGE_SN9C120:
+ DBG(2, "SN9C120 PC Camera Controller detected "
+ "(vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
break;
}
@@ -2816,12 +3209,18 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
goto fail;
}
+ if (!(cam->bridge & cam->sensor.supported_bridge)) {
+ DBG(1, "Bridge not supported");
+ err = -ENODEV;
+ goto fail;
+ }
+
if (sn9c102_init(cam)) {
DBG(1, "Initialization failed. I will retry on open().");
cam->state |= DEV_MISCONFIGURED;
}
- strcpy(cam->v4ldev->name, "SN9C10x PC Camera");
+ strcpy(cam->v4ldev->name, "SN9C1xx PC Camera");
cam->v4ldev->owner = THIS_MODULE;
cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES;
cam->v4ldev->hardware = 0;
@@ -2838,7 +3237,10 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
DBG(1, "V4L2 device registration failed");
if (err == -ENFILE && video_nr[dev_nr] == -1)
DBG(1, "Free /dev/videoX node not found");
- goto fail2;
+ video_nr[dev_nr] = -1;
+ dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0;
+ mutex_unlock(&cam->dev_mutex);
+ goto fail;
}
DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor);
@@ -2850,9 +3252,14 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
#ifdef CONFIG_VIDEO_ADV_DEBUG
err = sn9c102_create_sysfs(cam);
- if (err)
- goto fail3;
- DBG(2, "Optional device control through 'sysfs' interface ready");
+ if (!err)
+ DBG(2, "Optional device control through 'sysfs' "
+ "interface ready");
+ else
+ DBG(2, "Failed to create optional 'sysfs' interface for "
+ "device controlling. Error #%d", err);
+#else
+ DBG(2, "Optional device control through 'sysfs' interface disabled");
#endif
usb_set_intfdata(intf, cam);
@@ -2861,14 +3268,6 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
return 0;
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-fail3:
- video_unregister_device(cam->v4ldev);
-#endif
-fail2:
- video_nr[dev_nr] = -1;
- dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0;
- mutex_unlock(&cam->dev_mutex);
fail:
if (cam) {
kfree(cam->control_buffer);
diff --git a/drivers/media/video/sn9c102/sn9c102_devtable.h b/drivers/media/video/sn9c102/sn9c102_devtable.h
new file mode 100644
index 00000000000..3a682eca6c6
--- /dev/null
+++ b/drivers/media/video/sn9c102/sn9c102_devtable.h
@@ -0,0 +1,142 @@
+/***************************************************************************
+ * Table of device identifiers of the SN9C1xx PC Camera Controllers *
+ * *
+ * Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.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. *
+ ***************************************************************************/
+
+#ifndef _SN9C102_DEVTABLE_H_
+#define _SN9C102_DEVTABLE_H_
+
+#include <linux/usb.h>
+
+struct sn9c102_device;
+
+/*
+ Each SN9C1xx camera has proper PID/VID identifiers.
+ SN9C103, SN9C105, SN9C120 support multiple interfaces, but we only have to
+ handle the video class interface.
+*/
+#define SN9C102_USB_DEVICE(vend, prod, bridge) \
+ .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \
+ USB_DEVICE_ID_MATCH_INT_CLASS, \
+ .idVendor = (vend), \
+ .idProduct = (prod), \
+ .bInterfaceClass = 0xff, \
+ .driver_info = (bridge)
+
+static const struct usb_device_id sn9c102_id_table[] = {
+ /* SN9C101 and SN9C102 */
+ { SN9C102_USB_DEVICE(0x0c45, 0x6001, BRIDGE_SN9C102), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x6005, BRIDGE_SN9C102), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x6007, BRIDGE_SN9C102), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x6009, BRIDGE_SN9C102), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x6011, BRIDGE_SN9C102), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x600d, BRIDGE_SN9C102), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x6019, BRIDGE_SN9C102), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x6024, BRIDGE_SN9C102), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x6025, BRIDGE_SN9C102), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x6028, BRIDGE_SN9C102), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x6029, BRIDGE_SN9C102), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x602a, BRIDGE_SN9C102), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x602b, BRIDGE_SN9C102), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x602c, BRIDGE_SN9C102), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x602d, BRIDGE_SN9C102), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x602e, BRIDGE_SN9C102), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x6030, BRIDGE_SN9C102), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x603f, BRIDGE_SN9C102), },
+ /* SN9C103 */
+ { SN9C102_USB_DEVICE(0x0c45, 0x6080, BRIDGE_SN9C103), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x6082, BRIDGE_SN9C103), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x6083, BRIDGE_SN9C103), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x6088, BRIDGE_SN9C103), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x608a, BRIDGE_SN9C103), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x608b, BRIDGE_SN9C103), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x608c, BRIDGE_SN9C103), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x608e, BRIDGE_SN9C103), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x608f, BRIDGE_SN9C103), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x60a0, BRIDGE_SN9C103), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x60a2, BRIDGE_SN9C103), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x60a3, BRIDGE_SN9C103), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x60a8, BRIDGE_SN9C103), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x60aa, BRIDGE_SN9C103), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x60ab, BRIDGE_SN9C103), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x60ac, BRIDGE_SN9C103), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x60ae, BRIDGE_SN9C103), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x60af, BRIDGE_SN9C103), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x60b0, BRIDGE_SN9C103), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x60b2, BRIDGE_SN9C103), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x60b3, BRIDGE_SN9C103), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x60b8, BRIDGE_SN9C103), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x60ba, BRIDGE_SN9C103), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x60bb, BRIDGE_SN9C103), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x60bc, BRIDGE_SN9C103), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x60be, BRIDGE_SN9C103), },
+ /* SN9C105 */
+ { SN9C102_USB_DEVICE(0x0471, 0x0327, BRIDGE_SN9C105), },
+ { SN9C102_USB_DEVICE(0x0471, 0x0328, BRIDGE_SN9C105), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x60c0, BRIDGE_SN9C105), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x60c8, BRIDGE_SN9C105), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x60cc, BRIDGE_SN9C105), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x60ea, BRIDGE_SN9C105), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x60ec, BRIDGE_SN9C105), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x60fa, BRIDGE_SN9C105), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x60fb, BRIDGE_SN9C105), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x60fc, BRIDGE_SN9C105), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x60fe, BRIDGE_SN9C105), },
+ /* SN9C120 */
+ { SN9C102_USB_DEVICE(0x0c45, 0x6130, BRIDGE_SN9C120), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x613a, BRIDGE_SN9C120), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x613b, BRIDGE_SN9C120), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x613c, BRIDGE_SN9C120), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x613e, BRIDGE_SN9C120), },
+ { }
+};
+
+/*
+ Probing functions: on success, you must attach the sensor to the camera
+ by calling sn9c102_attach_sensor().
+ To enable the I2C communication, you might need to perform a really basic
+ initialization of the SN9C1XX chip.
+ Functions must return 0 on success, the appropriate error otherwise.
+*/
+extern int sn9c102_probe_hv7131d(struct sn9c102_device* cam);
+extern int sn9c102_probe_mi0343(struct sn9c102_device* cam);
+extern int sn9c102_probe_ov7630(struct sn9c102_device* cam);
+extern int sn9c102_probe_ov7660(struct sn9c102_device* cam);
+extern int sn9c102_probe_pas106b(struct sn9c102_device* cam);
+extern int sn9c102_probe_pas202bcb(struct sn9c102_device* cam);
+extern int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam);
+extern int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam);
+
+/*
+ Add the above entries to this table. Be sure to add the entry in the right
+ place, since, on failure, the next probing routine is called according to
+ the order of the list below, from top to bottom.
+*/
+static int (*sn9c102_sensor_table[])(struct sn9c102_device*) = {
+ &sn9c102_probe_mi0343, /* strong detection based on SENSOR ids */
+ &sn9c102_probe_pas106b, /* strong detection based on SENSOR ids */
+ &sn9c102_probe_pas202bcb, /* strong detection based on SENSOR ids */
+ &sn9c102_probe_hv7131d, /* strong detection based on SENSOR ids */
+ &sn9c102_probe_ov7630, /* strong detection based on SENSOR ids */
+ &sn9c102_probe_ov7660, /* strong detection based on SENSOR ids */
+ &sn9c102_probe_tas5110c1b, /* detection based on USB pid/vid */
+ &sn9c102_probe_tas5130d1b, /* detection based on USB pid/vid */
+ NULL,
+};
+
+#endif /* _SN9C102_DEVTABLE_H_ */
diff --git a/drivers/media/video/sn9c102/sn9c102_hv7131d.c b/drivers/media/video/sn9c102/sn9c102_hv7131d.c
index c4117bf64b6..7ae368f60d8 100644
--- a/drivers/media/video/sn9c102/sn9c102_hv7131d.c
+++ b/drivers/media/video/sn9c102/sn9c102_hv7131d.c
@@ -1,8 +1,8 @@
/***************************************************************************
- * Plug-in for HV7131D image sensor connected to the SN9C10x PC Camera *
+ * Plug-in for HV7131D image sensor connected to the SN9C1xx PC Camera *
* Controllers *
* *
- * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
+ * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.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 *
@@ -124,7 +124,7 @@ static int hv7131d_set_ctrl(struct sn9c102_device* cam,
static int hv7131d_set_crop(struct sn9c102_device* cam,
const struct v4l2_rect* rect)
{
- struct sn9c102_sensor* s = &hv7131d;
+ struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
int err = 0;
u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 2,
v_start = (u8)(rect->top - s->cropcap.bounds.top) + 2;
@@ -153,6 +153,7 @@ static int hv7131d_set_pix_format(struct sn9c102_device* cam,
static struct sn9c102_sensor hv7131d = {
.name = "HV7131D",
.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
+ .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103,
.sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
.frequency = SN9C102_I2C_100KHZ,
.interface = SN9C102_I2C_2WIRES,
diff --git a/drivers/media/video/sn9c102/sn9c102_mi0343.c b/drivers/media/video/sn9c102/sn9c102_mi0343.c
index 4169ea4a2e2..a33d1bc10f9 100644
--- a/drivers/media/video/sn9c102/sn9c102_mi0343.c
+++ b/drivers/media/video/sn9c102/sn9c102_mi0343.c
@@ -1,8 +1,8 @@
/***************************************************************************
- * Plug-in for MI-0343 image sensor connected to the SN9C10x PC Camera *
+ * Plug-in for MI-0343 image sensor connected to the SN9C1xx PC Camera *
* Controllers *
* *
- * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
+ * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.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 *
@@ -201,7 +201,7 @@ static int mi0343_set_ctrl(struct sn9c102_device* cam,
static int mi0343_set_crop(struct sn9c102_device* cam,
const struct v4l2_rect* rect)
{
- struct sn9c102_sensor* s = &mi0343;
+ struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
int err = 0;
u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 0,
v_start = (u8)(rect->top - s->cropcap.bounds.top) + 2;
@@ -237,6 +237,7 @@ static int mi0343_set_pix_format(struct sn9c102_device* cam,
static struct sn9c102_sensor mi0343 = {
.name = "MI-0343",
.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
+ .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103,
.frequency = SN9C102_I2C_100KHZ,
.interface = SN9C102_I2C_2WIRES,
.i2c_slave_id = 0x5d,
diff --git a/drivers/media/video/sn9c102/sn9c102_ov7630.c b/drivers/media/video/sn9c102/sn9c102_ov7630.c
index 3da04202178..7df09ff38e6 100644
--- a/drivers/media/video/sn9c102/sn9c102_ov7630.c
+++ b/drivers/media/video/sn9c102/sn9c102_ov7630.c
@@ -1,8 +1,8 @@
/***************************************************************************
- * Plug-in for OV7630 image sensor connected to the SN9C10x PC Camera *
+ * Plug-in for OV7630 image sensor connected to the SN9C1xx PC Camera *
* Controllers *
* *
- * Copyright (C) 2005-2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
+ * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.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 *
@@ -29,13 +29,17 @@ static int ov7630_init(struct sn9c102_device* cam)
{
int err = 0;
+ switch (sn9c102_get_bridge(cam)) {
+ case BRIDGE_SN9C101:
+ case BRIDGE_SN9C102:
err += sn9c102_write_reg(cam, 0x00, 0x14);
err += sn9c102_write_reg(cam, 0x60, 0x17);
err += sn9c102_write_reg(cam, 0x0f, 0x18);
err += sn9c102_write_reg(cam, 0x50, 0x19);
- err += sn9c102_i2c_write(cam, 0x12, 0x80);
- err += sn9c102_i2c_write(cam, 0x11, 0x01);
+ err += sn9c102_i2c_write(cam, 0x12, 0x8d);
+ err += sn9c102_i2c_write(cam, 0x12, 0x0d);
+ err += sn9c102_i2c_write(cam, 0x11, 0x00);
err += sn9c102_i2c_write(cam, 0x15, 0x34);
err += sn9c102_i2c_write(cam, 0x16, 0x03);
err += sn9c102_i2c_write(cam, 0x17, 0x1c);
@@ -43,14 +47,72 @@ static int ov7630_init(struct sn9c102_device* cam)
err += sn9c102_i2c_write(cam, 0x19, 0x06);
err += sn9c102_i2c_write(cam, 0x1a, 0xf6);
err += sn9c102_i2c_write(cam, 0x1b, 0x04);
- err += sn9c102_i2c_write(cam, 0x20, 0xf6);
+ err += sn9c102_i2c_write(cam, 0x20, 0x44);
+ err += sn9c102_i2c_write(cam, 0x23, 0xee);
+ err += sn9c102_i2c_write(cam, 0x26, 0xa0);
+ err += sn9c102_i2c_write(cam, 0x27, 0x9a);
+ err += sn9c102_i2c_write(cam, 0x28, 0x20);
+ err += sn9c102_i2c_write(cam, 0x29, 0x30);
+ err += sn9c102_i2c_write(cam, 0x2f, 0x3d);
+ err += sn9c102_i2c_write(cam, 0x30, 0x24);
+ err += sn9c102_i2c_write(cam, 0x32, 0x86);
+ err += sn9c102_i2c_write(cam, 0x60, 0xa9);
+ err += sn9c102_i2c_write(cam, 0x61, 0x42);
+ err += sn9c102_i2c_write(cam, 0x65, 0x00);
+ err += sn9c102_i2c_write(cam, 0x69, 0x38);
+ err += sn9c102_i2c_write(cam, 0x6f, 0x88);
+ err += sn9c102_i2c_write(cam, 0x70, 0x0b);
+ err += sn9c102_i2c_write(cam, 0x71, 0x00);
+ err += sn9c102_i2c_write(cam, 0x74, 0x21);
+ err += sn9c102_i2c_write(cam, 0x7d, 0xf7);
+ break;
+ case BRIDGE_SN9C103:
+ err += sn9c102_write_reg(cam, 0x00, 0x02);
+ err += sn9c102_write_reg(cam, 0x00, 0x03);
+ err += sn9c102_write_reg(cam, 0x1a, 0x04);
+ err += sn9c102_write_reg(cam, 0x20, 0x05);
+ err += sn9c102_write_reg(cam, 0x20, 0x06);
+ err += sn9c102_write_reg(cam, 0x20, 0x07);
+ err += sn9c102_write_reg(cam, 0x03, 0x10);
+ err += sn9c102_write_reg(cam, 0x0a, 0x14);
+ err += sn9c102_write_reg(cam, 0x60, 0x17);
+ err += sn9c102_write_reg(cam, 0x0f, 0x18);
+ err += sn9c102_write_reg(cam, 0x50, 0x19);
+ err += sn9c102_write_reg(cam, 0x1d, 0x1a);
+ err += sn9c102_write_reg(cam, 0x10, 0x1b);
+ err += sn9c102_write_reg(cam, 0x02, 0x1c);
+ err += sn9c102_write_reg(cam, 0x03, 0x1d);
+ err += sn9c102_write_reg(cam, 0x0f, 0x1e);
+ err += sn9c102_write_reg(cam, 0x0c, 0x1f);
+ err += sn9c102_write_reg(cam, 0x00, 0x20);
+ err += sn9c102_write_reg(cam, 0x10, 0x21);
+ err += sn9c102_write_reg(cam, 0x20, 0x22);
+ err += sn9c102_write_reg(cam, 0x30, 0x23);
+ err += sn9c102_write_reg(cam, 0x40, 0x24);
+ err += sn9c102_write_reg(cam, 0x50, 0x25);
+ err += sn9c102_write_reg(cam, 0x60, 0x26);
+ err += sn9c102_write_reg(cam, 0x70, 0x27);
+ err += sn9c102_write_reg(cam, 0x80, 0x28);
+ err += sn9c102_write_reg(cam, 0x90, 0x29);
+ err += sn9c102_write_reg(cam, 0xa0, 0x2a);
+ err += sn9c102_write_reg(cam, 0xb0, 0x2b);
+ err += sn9c102_write_reg(cam, 0xc0, 0x2c);
+ err += sn9c102_write_reg(cam, 0xd0, 0x2d);
+ err += sn9c102_write_reg(cam, 0xe0, 0x2e);
+ err += sn9c102_write_reg(cam, 0xf0, 0x2f);
+ err += sn9c102_write_reg(cam, 0xff, 0x30);
+
+ err += sn9c102_i2c_write(cam, 0x12, 0x8d);
+ err += sn9c102_i2c_write(cam, 0x12, 0x0d);
+ err += sn9c102_i2c_write(cam, 0x15, 0x34);
+ err += sn9c102_i2c_write(cam, 0x11, 0x01);
+ err += sn9c102_i2c_write(cam, 0x1b, 0x04);
+ err += sn9c102_i2c_write(cam, 0x20, 0x44);
err += sn9c102_i2c_write(cam, 0x23, 0xee);
err += sn9c102_i2c_write(cam, 0x26, 0xa0);
err += sn9c102_i2c_write(cam, 0x27, 0x9a);
- err += sn9c102_i2c_write(cam, 0x28, 0xa0);
+ err += sn9c102_i2c_write(cam, 0x28, 0x20);
err += sn9c102_i2c_write(cam, 0x29, 0x30);
- err += sn9c102_i2c_write(cam, 0x2a, 0xa0);
- err += sn9c102_i2c_write(cam, 0x2b, 0x1f);
err += sn9c102_i2c_write(cam, 0x2f, 0x3d);
err += sn9c102_i2c_write(cam, 0x30, 0x24);
err += sn9c102_i2c_write(cam, 0x32, 0x86);
@@ -63,45 +125,97 @@ static int ov7630_init(struct sn9c102_device* cam)
err += sn9c102_i2c_write(cam, 0x71, 0x00);
err += sn9c102_i2c_write(cam, 0x74, 0x21);
err += sn9c102_i2c_write(cam, 0x7d, 0xf7);
+ break;
+ default:
+ break;
+ }
return err;
}
-static int ov7630_set_ctrl(struct sn9c102_device* cam,
- const struct v4l2_control* ctrl)
+static int ov7630_get_ctrl(struct sn9c102_device* cam,
+ struct v4l2_control* ctrl)
{
int err = 0;
switch (ctrl->id) {
case V4L2_CID_EXPOSURE:
- err += sn9c102_i2c_write(cam, 0x10, ctrl->value >> 2);
- err += sn9c102_i2c_write(cam, 0x76, ctrl->value & 0x03);
+ if ((ctrl->value = sn9c102_i2c_read(cam, 0x10)) < 0)
+ return -EIO;
break;
case V4L2_CID_RED_BALANCE:
- err += sn9c102_i2c_write(cam, 0x02, ctrl->value);
+ ctrl->value = sn9c102_pread_reg(cam, 0x07);
break;
case V4L2_CID_BLUE_BALANCE:
- err += sn9c102_i2c_write(cam, 0x01, ctrl->value);
+ ctrl->value = sn9c102_pread_reg(cam, 0x06);
+ break;
+ case SN9C102_V4L2_CID_GREEN_BALANCE:
+ ctrl->value = sn9c102_pread_reg(cam, 0x05);
break;
case V4L2_CID_GAIN:
- err += sn9c102_i2c_write(cam, 0x00, ctrl->value);
+ if ((ctrl->value = sn9c102_i2c_read(cam, 0x00)) < 0)
+ return -EIO;
+ ctrl->value &= 0x3f;
+ break;
+ case V4L2_CID_DO_WHITE_BALANCE:
+ if ((ctrl->value = sn9c102_i2c_read(cam, 0x0c)) < 0)
+ return -EIO;
+ ctrl->value &= 0x3f;
+ break;
+ case V4L2_CID_WHITENESS:
+ if ((ctrl->value = sn9c102_i2c_read(cam, 0x0d)) < 0)
+ return -EIO;
+ ctrl->value &= 0x3f;
+ break;
+ case V4L2_CID_AUTOGAIN:
+ if ((ctrl->value = sn9c102_i2c_read(cam, 0x13)) < 0)
+ return -EIO;
+ ctrl->value &= 0x01;
+ break;
+ case V4L2_CID_VFLIP:
+ if ((ctrl->value = sn9c102_i2c_read(cam, 0x75)) < 0)
+ return -EIO;
+ ctrl->value = (ctrl->value & 0x80) ? 1 : 0;
+ break;
+ case SN9C102_V4L2_CID_GAMMA:
+ if ((ctrl->value = sn9c102_i2c_read(cam, 0x14)) < 0)
+ return -EIO;
+ ctrl->value = (ctrl->value & 0x02) ? 1 : 0;
+ break;
+ case SN9C102_V4L2_CID_BAND_FILTER:
+ if ((ctrl->value = sn9c102_i2c_read(cam, 0x2d)) < 0)
+ return -EIO;
+ ctrl->value = (ctrl->value & 0x02) ? 1 : 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return err ? -EIO : 0;
+}
+
+
+static int ov7630_set_ctrl(struct sn9c102_device* cam,
+ const struct v4l2_control* ctrl)
+{
+ int err = 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_EXPOSURE:
+ err += sn9c102_i2c_write(cam, 0x10, ctrl->value);
break;
- case V4L2_CID_CONTRAST:
- err += ctrl->value ? sn9c102_i2c_write(cam, 0x05,
- (ctrl->value-1) | 0x20)
- : sn9c102_i2c_write(cam, 0x05, 0x00);
+ case V4L2_CID_RED_BALANCE:
+ err += sn9c102_write_reg(cam, ctrl->value, 0x07);
break;
- case V4L2_CID_BRIGHTNESS:
- err += sn9c102_i2c_write(cam, 0x06, ctrl->value);
+ case V4L2_CID_BLUE_BALANCE:
+ err += sn9c102_write_reg(cam, ctrl->value, 0x06);
break;
- case V4L2_CID_SATURATION:
- err += sn9c102_i2c_write(cam, 0x03, ctrl->value << 4);
+ case SN9C102_V4L2_CID_GREEN_BALANCE:
+ err += sn9c102_write_reg(cam, ctrl->value, 0x05);
break;
- case V4L2_CID_HUE:
- err += ctrl->value ? sn9c102_i2c_write(cam, 0x04,
- (ctrl->value-1) | 0x20)
- : sn9c102_i2c_write(cam, 0x04, 0x00);
+ case V4L2_CID_GAIN:
+ err += sn9c102_i2c_write(cam, 0x00, ctrl->value);
break;
case V4L2_CID_DO_WHITE_BALANCE:
err += sn9c102_i2c_write(cam, 0x0c, ctrl->value);
@@ -109,23 +223,15 @@ static int ov7630_set_ctrl(struct sn9c102_device* cam,
case V4L2_CID_WHITENESS:
err += sn9c102_i2c_write(cam, 0x0d, ctrl->value);
break;
- case V4L2_CID_AUTO_WHITE_BALANCE:
- err += sn9c102_i2c_write(cam, 0x12, (ctrl->value << 2) | 0x78);
- break;
case V4L2_CID_AUTOGAIN:
- err += sn9c102_i2c_write(cam, 0x13, ctrl->value);
+ err += sn9c102_i2c_write(cam, 0x13, ctrl->value |
+ (ctrl->value << 1));
break;
case V4L2_CID_VFLIP:
err += sn9c102_i2c_write(cam, 0x75, 0x0e | (ctrl->value << 7));
break;
- case V4L2_CID_BLACK_LEVEL:
- err += sn9c102_i2c_write(cam, 0x25, ctrl->value);
- break;
- case SN9C102_V4L2_CID_BRIGHT_LEVEL:
- err += sn9c102_i2c_write(cam, 0x24, ctrl->value);
- break;
case SN9C102_V4L2_CID_GAMMA:
- err += sn9c102_i2c_write(cam, 0x14, (ctrl->value << 2) | 0x80);
+ err += sn9c102_i2c_write(cam, 0x14, ctrl->value << 2);
break;
case SN9C102_V4L2_CID_BAND_FILTER:
err += sn9c102_i2c_write(cam, 0x2d, ctrl->value << 2);
@@ -141,10 +247,12 @@ static int ov7630_set_ctrl(struct sn9c102_device* cam,
static int ov7630_set_crop(struct sn9c102_device* cam,
const struct v4l2_rect* rect)
{
- struct sn9c102_sensor* s = &ov7630;
+ struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
int err = 0;
- u8 v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1;
+ u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 1,
+ v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1;
+ err += sn9c102_write_reg(cam, h_start, 0x12);
err += sn9c102_write_reg(cam, v_start, 0x13);
return err;
@@ -168,7 +276,8 @@ static int ov7630_set_pix_format(struct sn9c102_device* cam,
static struct sn9c102_sensor ov7630 = {
.name = "OV7630",
.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
- .sysfs_ops = SN9C102_I2C_WRITE,
+ .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103,
+ .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
.frequency = SN9C102_I2C_100KHZ,
.interface = SN9C102_I2C_2WIRES,
.i2c_slave_id = 0x21,
@@ -185,73 +294,23 @@ static struct sn9c102_sensor ov7630 = {
.flags = 0,
},
{
- .id = V4L2_CID_HUE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "hue",
- .minimum = 0x00,
- .maximum = 0x1f+1,
- .step = 0x01,
- .default_value = 0x00,
- .flags = 0,
- },
- {
- .id = V4L2_CID_SATURATION,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "saturation",
- .minimum = 0x00,
- .maximum = 0x0f,
- .step = 0x01,
- .default_value = 0x08,
- .flags = 0,
- },
- {
- .id = V4L2_CID_CONTRAST,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "contrast",
- .minimum = 0x00,
- .maximum = 0x1f+1,
- .step = 0x01,
- .default_value = 0x00,
- .flags = 0,
- },
- {
.id = V4L2_CID_EXPOSURE,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "exposure",
- .minimum = 0x000,
- .maximum = 0x3ff,
- .step = 0x001,
- .default_value = 0x83<<2,
- .flags = 0,
- },
- {
- .id = V4L2_CID_RED_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "red balance",
- .minimum = 0x00,
- .maximum = 0xff,
- .step = 0x01,
- .default_value = 0x3a,
- .flags = 0,
- },
- {
- .id = V4L2_CID_BLUE_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "blue balance",
.minimum = 0x00,
.maximum = 0xff,
.step = 0x01,
- .default_value = 0x77,
+ .default_value = 0x60,
.flags = 0,
},
{
- .id = V4L2_CID_BRIGHTNESS,
+ .id = V4L2_CID_WHITENESS,
.type = V4L2_CTRL_TYPE_INTEGER,
- .name = "brightness",
+ .name = "white balance background: red",
.minimum = 0x00,
- .maximum = 0xff,
+ .maximum = 0x3f,
.step = 0x01,
- .default_value = 0xa0,
+ .default_value = 0x20,
.flags = 0,
},
{
@@ -265,31 +324,31 @@ static struct sn9c102_sensor ov7630 = {
.flags = 0,
},
{
- .id = V4L2_CID_WHITENESS,
+ .id = V4L2_CID_RED_BALANCE,
.type = V4L2_CTRL_TYPE_INTEGER,
- .name = "white balance background: red",
+ .name = "red balance",
.minimum = 0x00,
- .maximum = 0x3f,
+ .maximum = 0x7f,
.step = 0x01,
.default_value = 0x20,
.flags = 0,
},
{
- .id = V4L2_CID_AUTO_WHITE_BALANCE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "auto white balance",
+ .id = V4L2_CID_BLUE_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "blue balance",
.minimum = 0x00,
- .maximum = 0x01,
+ .maximum = 0x7f,
.step = 0x01,
- .default_value = 0x01,
+ .default_value = 0x20,
.flags = 0,
},
{
.id = V4L2_CID_AUTOGAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "gain & exposure mode",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "auto adjust",
.minimum = 0x00,
- .maximum = 0x03,
+ .maximum = 0x01,
.step = 0x01,
.default_value = 0x00,
.flags = 0,
@@ -305,23 +364,13 @@ static struct sn9c102_sensor ov7630 = {
.flags = 0,
},
{
- .id = V4L2_CID_BLACK_LEVEL,
+ .id = SN9C102_V4L2_CID_GREEN_BALANCE,
.type = V4L2_CTRL_TYPE_INTEGER,
- .name = "black pixel ratio",
- .minimum = 0x01,
- .maximum = 0x9a,
- .step = 0x01,
- .default_value = 0x8a,
- .flags = 0,
- },
- {
- .id = SN9C102_V4L2_CID_BRIGHT_LEVEL,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "bright pixel ratio",
- .minimum = 0x01,
- .maximum = 0x9a,
+ .name = "green balance",
+ .minimum = 0x00,
+ .maximum = 0x7f,
.step = 0x01,
- .default_value = 0x10,
+ .default_value = 0x20,
.flags = 0,
},
{
@@ -345,6 +394,7 @@ static struct sn9c102_sensor ov7630 = {
.flags = 0,
},
},
+ .get_ctrl = &ov7630_get_ctrl,
.set_ctrl = &ov7630_set_ctrl,
.cropcap = {
.bounds = {
@@ -364,7 +414,7 @@ static struct sn9c102_sensor ov7630 = {
.pix_format = {
.width = 640,
.height = 480,
- .pixelformat = V4L2_PIX_FMT_SBGGR8,
+ .pixelformat = V4L2_PIX_FMT_SN9C10X,
.priv = 8,
},
.set_pix_format = &ov7630_set_pix_format
@@ -373,28 +423,36 @@ static struct sn9c102_sensor ov7630 = {
int sn9c102_probe_ov7630(struct sn9c102_device* cam)
{
- const struct usb_device_id ov7630_id_table[] = {
- { USB_DEVICE(0x0c45, 0x602c), },
- { USB_DEVICE(0x0c45, 0x602d), },
- { USB_DEVICE(0x0c45, 0x608f), },
- { USB_DEVICE(0x0c45, 0x60b0), },
- { }
- };
- int err = 0;
-
- if (!sn9c102_match_id(cam, ov7630_id_table))
- return -ENODEV;
+ int pid, ver, err = 0;
+ switch (sn9c102_get_bridge(cam)) {
+ case BRIDGE_SN9C101:
+ case BRIDGE_SN9C102:
err += sn9c102_write_reg(cam, 0x01, 0x01);
err += sn9c102_write_reg(cam, 0x00, 0x01);
err += sn9c102_write_reg(cam, 0x28, 0x17);
- if (err)
- return -EIO;
+ break;
+ case BRIDGE_SN9C103: /* do _not_ change anything! */
+ err += sn9c102_write_reg(cam, 0x09, 0x01);
+ err += sn9c102_write_reg(cam, 0x42, 0x01);
+ err += sn9c102_write_reg(cam, 0x28, 0x17);
+ err += sn9c102_write_reg(cam, 0x44, 0x02);
+ pid = sn9c102_i2c_try_read(cam, &ov7630, 0x0a);
+ if (err || pid < 0) { /* try a different initialization */
+ err = sn9c102_write_reg(cam, 0x01, 0x01);
+ err += sn9c102_write_reg(cam, 0x00, 0x01);
+ }
+ break;
+ default:
+ break;
+ }
- err += sn9c102_i2c_try_write(cam, &ov7630, 0x0b, 0);
- if (err)
+ pid = sn9c102_i2c_try_read(cam, &ov7630, 0x0a);
+ ver = sn9c102_i2c_try_read(cam, &ov7630, 0x0b);
+ if (err || pid < 0 || ver < 0)
+ return -EIO;
+ if (pid != 0x76 || ver != 0x31)
return -ENODEV;
-
sn9c102_attach_sensor(cam, &ov7630);
return 0;
diff --git a/drivers/media/video/sn9c102/sn9c102_ov7660.c b/drivers/media/video/sn9c102/sn9c102_ov7660.c
new file mode 100644
index 00000000000..d670c24d443
--- /dev/null
+++ b/drivers/media/video/sn9c102/sn9c102_ov7660.c
@@ -0,0 +1,592 @@
+/***************************************************************************
+ * Plug-in for OV7660 image sensor connected to the SN9C1xx PC Camera *
+ * Controllers *
+ * *
+ * Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.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 "sn9c102_sensor.h"
+
+
+static struct sn9c102_sensor ov7660;
+
+
+static int ov7660_init(struct sn9c102_device* cam)
+{
+ int err = 0;
+
+ err += sn9c102_write_reg(cam, 0x40, 0x02);
+ err += sn9c102_write_reg(cam, 0x00, 0x03);
+ err += sn9c102_write_reg(cam, 0x1a, 0x04);
+ err += sn9c102_write_reg(cam, 0x03, 0x10);
+ err += sn9c102_write_reg(cam, 0x08, 0x14);
+ err += sn9c102_write_reg(cam, 0x20, 0x17);
+ err += sn9c102_write_reg(cam, 0x8b, 0x18);
+ err += sn9c102_write_reg(cam, 0x00, 0x19);
+ err += sn9c102_write_reg(cam, 0x1d, 0x1a);
+ err += sn9c102_write_reg(cam, 0x10, 0x1b);
+ err += sn9c102_write_reg(cam, 0x02, 0x1c);
+ err += sn9c102_write_reg(cam, 0x03, 0x1d);
+ err += sn9c102_write_reg(cam, 0x0f, 0x1e);
+ err += sn9c102_write_reg(cam, 0x0c, 0x1f);
+ err += sn9c102_write_reg(cam, 0x00, 0x20);
+ err += sn9c102_write_reg(cam, 0x29, 0x21);
+ err += sn9c102_write_reg(cam, 0x40, 0x22);
+ err += sn9c102_write_reg(cam, 0x54, 0x23);
+ err += sn9c102_write_reg(cam, 0x66, 0x24);
+ err += sn9c102_write_reg(cam, 0x76, 0x25);
+ err += sn9c102_write_reg(cam, 0x85, 0x26);
+ err += sn9c102_write_reg(cam, 0x94, 0x27);
+ err += sn9c102_write_reg(cam, 0xa1, 0x28);
+ err += sn9c102_write_reg(cam, 0xae, 0x29);
+ err += sn9c102_write_reg(cam, 0xbb, 0x2a);
+ err += sn9c102_write_reg(cam, 0xc7, 0x2b);
+ err += sn9c102_write_reg(cam, 0xd3, 0x2c);
+ err += sn9c102_write_reg(cam, 0xde, 0x2d);
+ err += sn9c102_write_reg(cam, 0xea, 0x2e);
+ err += sn9c102_write_reg(cam, 0xf4, 0x2f);
+ err += sn9c102_write_reg(cam, 0xff, 0x30);
+ err += sn9c102_write_reg(cam, 0x00, 0x3F);
+ err += sn9c102_write_reg(cam, 0xC7, 0x40);
+ err += sn9c102_write_reg(cam, 0x01, 0x41);
+ err += sn9c102_write_reg(cam, 0x44, 0x42);
+ err += sn9c102_write_reg(cam, 0x00, 0x43);
+ err += sn9c102_write_reg(cam, 0x44, 0x44);
+ err += sn9c102_write_reg(cam, 0x00, 0x45);
+ err += sn9c102_write_reg(cam, 0x44, 0x46);
+ err += sn9c102_write_reg(cam, 0x00, 0x47);
+ err += sn9c102_write_reg(cam, 0xC7, 0x48);
+ err += sn9c102_write_reg(cam, 0x01, 0x49);
+ err += sn9c102_write_reg(cam, 0xC7, 0x4A);
+ err += sn9c102_write_reg(cam, 0x01, 0x4B);
+ err += sn9c102_write_reg(cam, 0xC7, 0x4C);
+ err += sn9c102_write_reg(cam, 0x01, 0x4D);
+ err += sn9c102_write_reg(cam, 0x44, 0x4E);
+ err += sn9c102_write_reg(cam, 0x00, 0x4F);
+ err += sn9c102_write_reg(cam, 0x44, 0x50);
+ err += sn9c102_write_reg(cam, 0x00, 0x51);
+ err += sn9c102_write_reg(cam, 0x44, 0x52);
+ err += sn9c102_write_reg(cam, 0x00, 0x53);
+ err += sn9c102_write_reg(cam, 0xC7, 0x54);
+ err += sn9c102_write_reg(cam, 0x01, 0x55);
+ err += sn9c102_write_reg(cam, 0xC7, 0x56);
+ err += sn9c102_write_reg(cam, 0x01, 0x57);
+ err += sn9c102_write_reg(cam, 0xC7, 0x58);
+ err += sn9c102_write_reg(cam, 0x01, 0x59);
+ err += sn9c102_write_reg(cam, 0x44, 0x5A);
+ err += sn9c102_write_reg(cam, 0x00, 0x5B);
+ err += sn9c102_write_reg(cam, 0x44, 0x5C);
+ err += sn9c102_write_reg(cam, 0x00, 0x5D);
+ err += sn9c102_write_reg(cam, 0x44, 0x5E);
+ err += sn9c102_write_reg(cam, 0x00, 0x5F);
+ err += sn9c102_write_reg(cam, 0xC7, 0x60);
+ err += sn9c102_write_reg(cam, 0x01, 0x61);
+ err += sn9c102_write_reg(cam, 0xC7, 0x62);
+ err += sn9c102_write_reg(cam, 0x01, 0x63);
+ err += sn9c102_write_reg(cam, 0xC7, 0x64);
+ err += sn9c102_write_reg(cam, 0x01, 0x65);
+ err += sn9c102_write_reg(cam, 0x44, 0x66);
+ err += sn9c102_write_reg(cam, 0x00, 0x67);
+ err += sn9c102_write_reg(cam, 0x44, 0x68);
+ err += sn9c102_write_reg(cam, 0x00, 0x69);
+ err += sn9c102_write_reg(cam, 0x44, 0x6A);
+ err += sn9c102_write_reg(cam, 0x00, 0x6B);
+ err += sn9c102_write_reg(cam, 0xC7, 0x6C);
+ err += sn9c102_write_reg(cam, 0x01, 0x6D);
+ err += sn9c102_write_reg(cam, 0xC7, 0x6E);
+ err += sn9c102_write_reg(cam, 0x01, 0x6F);
+ err += sn9c102_write_reg(cam, 0xC7, 0x70);
+ err += sn9c102_write_reg(cam, 0x01, 0x71);
+ err += sn9c102_write_reg(cam, 0x44, 0x72);
+ err += sn9c102_write_reg(cam, 0x00, 0x73);
+ err += sn9c102_write_reg(cam, 0x44, 0x74);
+ err += sn9c102_write_reg(cam, 0x00, 0x75);
+ err += sn9c102_write_reg(cam, 0x44, 0x76);
+ err += sn9c102_write_reg(cam, 0x00, 0x77);
+ err += sn9c102_write_reg(cam, 0xC7, 0x78);
+ err += sn9c102_write_reg(cam, 0x01, 0x79);
+ err += sn9c102_write_reg(cam, 0xC7, 0x7A);
+ err += sn9c102_write_reg(cam, 0x01, 0x7B);
+ err += sn9c102_write_reg(cam, 0xC7, 0x7C);
+ err += sn9c102_write_reg(cam, 0x01, 0x7D);
+ err += sn9c102_write_reg(cam, 0x44, 0x7E);
+ err += sn9c102_write_reg(cam, 0x00, 0x7F);
+ err += sn9c102_write_reg(cam, 0x14, 0x84);
+ err += sn9c102_write_reg(cam, 0x00, 0x85);
+ err += sn9c102_write_reg(cam, 0x27, 0x86);
+ err += sn9c102_write_reg(cam, 0x00, 0x87);
+ err += sn9c102_write_reg(cam, 0x07, 0x88);
+ err += sn9c102_write_reg(cam, 0x00, 0x89);
+ err += sn9c102_write_reg(cam, 0xEC, 0x8A);
+ err += sn9c102_write_reg(cam, 0x0f, 0x8B);
+ err += sn9c102_write_reg(cam, 0xD8, 0x8C);
+ err += sn9c102_write_reg(cam, 0x0f, 0x8D);
+ err += sn9c102_write_reg(cam, 0x3D, 0x8E);
+ err += sn9c102_write_reg(cam, 0x00, 0x8F);
+ err += sn9c102_write_reg(cam, 0x3D, 0x90);
+ err += sn9c102_write_reg(cam, 0x00, 0x91);
+ err += sn9c102_write_reg(cam, 0xCD, 0x92);
+ err += sn9c102_write_reg(cam, 0x0f, 0x93);
+ err += sn9c102_write_reg(cam, 0xf7, 0x94);
+ err += sn9c102_write_reg(cam, 0x0f, 0x95);
+ err += sn9c102_write_reg(cam, 0x0C, 0x96);
+ err += sn9c102_write_reg(cam, 0x00, 0x97);
+ err += sn9c102_write_reg(cam, 0x00, 0x98);
+ err += sn9c102_write_reg(cam, 0x66, 0x99);
+ err += sn9c102_write_reg(cam, 0x05, 0x9A);
+ err += sn9c102_write_reg(cam, 0x00, 0x9B);
+ err += sn9c102_write_reg(cam, 0x04, 0x9C);
+ err += sn9c102_write_reg(cam, 0x00, 0x9D);
+ err += sn9c102_write_reg(cam, 0x08, 0x9E);
+ err += sn9c102_write_reg(cam, 0x00, 0x9F);
+ err += sn9c102_write_reg(cam, 0x2D, 0xC0);
+ err += sn9c102_write_reg(cam, 0x2D, 0xC1);
+ err += sn9c102_write_reg(cam, 0x3A, 0xC2);
+ err += sn9c102_write_reg(cam, 0x05, 0xC3);
+ err += sn9c102_write_reg(cam, 0x04, 0xC4);
+ err += sn9c102_write_reg(cam, 0x3F, 0xC5);
+ err += sn9c102_write_reg(cam, 0x00, 0xC6);
+ err += sn9c102_write_reg(cam, 0x00, 0xC7);
+ err += sn9c102_write_reg(cam, 0x50, 0xC8);
+ err += sn9c102_write_reg(cam, 0x3C, 0xC9);
+ err += sn9c102_write_reg(cam, 0x28, 0xCA);
+ err += sn9c102_write_reg(cam, 0xD8, 0xCB);
+ err += sn9c102_write_reg(cam, 0x14, 0xCC);
+ err += sn9c102_write_reg(cam, 0xEC, 0xCD);
+ err += sn9c102_write_reg(cam, 0x32, 0xCE);
+ err += sn9c102_write_reg(cam, 0xDD, 0xCF);
+ err += sn9c102_write_reg(cam, 0x32, 0xD0);
+ err += sn9c102_write_reg(cam, 0xDD, 0xD1);
+ err += sn9c102_write_reg(cam, 0x6A, 0xD2);
+ err += sn9c102_write_reg(cam, 0x50, 0xD3);
+ err += sn9c102_write_reg(cam, 0x00, 0xD4);
+ err += sn9c102_write_reg(cam, 0x00, 0xD5);
+ err += sn9c102_write_reg(cam, 0x00, 0xD6);
+
+ err += sn9c102_i2c_write(cam, 0x12, 0x80);
+ err += sn9c102_i2c_write(cam, 0x11, 0x09);
+ err += sn9c102_i2c_write(cam, 0x00, 0x0A);
+ err += sn9c102_i2c_write(cam, 0x01, 0x78);
+ err += sn9c102_i2c_write(cam, 0x02, 0x90);
+ err += sn9c102_i2c_write(cam, 0x03, 0x00);
+ err += sn9c102_i2c_write(cam, 0x04, 0x00);
+ err += sn9c102_i2c_write(cam, 0x05, 0x08);
+ err += sn9c102_i2c_write(cam, 0x06, 0x0B);
+ err += sn9c102_i2c_write(cam, 0x07, 0x00);
+ err += sn9c102_i2c_write(cam, 0x08, 0x1C);
+ err += sn9c102_i2c_write(cam, 0x09, 0x01);
+ err += sn9c102_i2c_write(cam, 0x0A, 0x76);
+ err += sn9c102_i2c_write(cam, 0x0B, 0x60);
+ err += sn9c102_i2c_write(cam, 0x0C, 0x00);
+ err += sn9c102_i2c_write(cam, 0x0D, 0x08);
+ err += sn9c102_i2c_write(cam, 0x0E, 0x04);
+ err += sn9c102_i2c_write(cam, 0x0F, 0x6F);
+ err += sn9c102_i2c_write(cam, 0x10, 0x20);
+ err += sn9c102_i2c_write(cam, 0x11, 0x03);
+ err += sn9c102_i2c_write(cam, 0x12, 0x05);
+ err += sn9c102_i2c_write(cam, 0x13, 0xF8);
+ err += sn9c102_i2c_write(cam, 0x14, 0x2C);
+ err += sn9c102_i2c_write(cam, 0x15, 0x00);
+ err += sn9c102_i2c_write(cam, 0x16, 0x02);
+ err += sn9c102_i2c_write(cam, 0x17, 0x10);
+ err += sn9c102_i2c_write(cam, 0x18, 0x60);
+ err += sn9c102_i2c_write(cam, 0x19, 0x02);
+ err += sn9c102_i2c_write(cam, 0x1A, 0x7B);
+ err += sn9c102_i2c_write(cam, 0x1B, 0x02);
+ err += sn9c102_i2c_write(cam, 0x1C, 0x7F);
+ err += sn9c102_i2c_write(cam, 0x1D, 0xA2);
+ err += sn9c102_i2c_write(cam, 0x1E, 0x01);
+ err += sn9c102_i2c_write(cam, 0x1F, 0x0E);
+ err += sn9c102_i2c_write(cam, 0x20, 0x05);
+ err += sn9c102_i2c_write(cam, 0x21, 0x05);
+ err += sn9c102_i2c_write(cam, 0x22, 0x05);
+ err += sn9c102_i2c_write(cam, 0x23, 0x05);
+ err += sn9c102_i2c_write(cam, 0x24, 0x68);
+ err += sn9c102_i2c_write(cam, 0x25, 0x58);
+ err += sn9c102_i2c_write(cam, 0x26, 0xD4);
+ err += sn9c102_i2c_write(cam, 0x27, 0x80);
+ err += sn9c102_i2c_write(cam, 0x28, 0x80);
+ err += sn9c102_i2c_write(cam, 0x29, 0x30);
+ err += sn9c102_i2c_write(cam, 0x2A, 0x00);
+ err += sn9c102_i2c_write(cam, 0x2B, 0x00);
+ err += sn9c102_i2c_write(cam, 0x2C, 0x80);
+ err += sn9c102_i2c_write(cam, 0x2D, 0x00);
+ err += sn9c102_i2c_write(cam, 0x2E, 0x00);
+ err += sn9c102_i2c_write(cam, 0x2F, 0x0E);
+ err += sn9c102_i2c_write(cam, 0x30, 0x08);
+ err += sn9c102_i2c_write(cam, 0x31, 0x30);
+ err += sn9c102_i2c_write(cam, 0x32, 0xB4);
+ err += sn9c102_i2c_write(cam, 0x33, 0x00);
+ err += sn9c102_i2c_write(cam, 0x34, 0x07);
+ err += sn9c102_i2c_write(cam, 0x35, 0x84);
+ err += sn9c102_i2c_write(cam, 0x36, 0x00);
+ err += sn9c102_i2c_write(cam, 0x37, 0x0C);
+ err += sn9c102_i2c_write(cam, 0x38, 0x02);
+ err += sn9c102_i2c_write(cam, 0x39, 0x43);
+ err += sn9c102_i2c_write(cam, 0x3A, 0x00);
+ err += sn9c102_i2c_write(cam, 0x3B, 0x02);
+ err += sn9c102_i2c_write(cam, 0x3C, 0x6C);
+ err += sn9c102_i2c_write(cam, 0x3D, 0x99);
+ err += sn9c102_i2c_write(cam, 0x3E, 0x0E);
+ err += sn9c102_i2c_write(cam, 0x3F, 0x41);
+ err += sn9c102_i2c_write(cam, 0x40, 0xC1);
+ err += sn9c102_i2c_write(cam, 0x41, 0x22);
+ err += sn9c102_i2c_write(cam, 0x42, 0x08);
+ err += sn9c102_i2c_write(cam, 0x43, 0xF0);
+ err += sn9c102_i2c_write(cam, 0x44, 0x10);
+ err += sn9c102_i2c_write(cam, 0x45, 0x78);
+ err += sn9c102_i2c_write(cam, 0x46, 0xA8);
+ err += sn9c102_i2c_write(cam, 0x47, 0x60);
+ err += sn9c102_i2c_write(cam, 0x48, 0x80);
+ err += sn9c102_i2c_write(cam, 0x49, 0x00);
+ err += sn9c102_i2c_write(cam, 0x4A, 0x00);
+ err += sn9c102_i2c_write(cam, 0x4B, 0x00);
+ err += sn9c102_i2c_write(cam, 0x4C, 0x00);
+ err += sn9c102_i2c_write(cam, 0x4D, 0x00);
+ err += sn9c102_i2c_write(cam, 0x4E, 0x00);
+ err += sn9c102_i2c_write(cam, 0x4F, 0x46);
+ err += sn9c102_i2c_write(cam, 0x50, 0x36);
+ err += sn9c102_i2c_write(cam, 0x51, 0x0F);
+ err += sn9c102_i2c_write(cam, 0x52, 0x17);
+ err += sn9c102_i2c_write(cam, 0x53, 0x7F);
+ err += sn9c102_i2c_write(cam, 0x54, 0x96);
+ err += sn9c102_i2c_write(cam, 0x55, 0x40);
+ err += sn9c102_i2c_write(cam, 0x56, 0x40);
+ err += sn9c102_i2c_write(cam, 0x57, 0x40);
+ err += sn9c102_i2c_write(cam, 0x58, 0x0F);
+ err += sn9c102_i2c_write(cam, 0x59, 0xBA);
+ err += sn9c102_i2c_write(cam, 0x5A, 0x9A);
+ err += sn9c102_i2c_write(cam, 0x5B, 0x22);
+ err += sn9c102_i2c_write(cam, 0x5C, 0xB9);
+ err += sn9c102_i2c_write(cam, 0x5D, 0x9B);
+ err += sn9c102_i2c_write(cam, 0x5E, 0x10);
+ err += sn9c102_i2c_write(cam, 0x5F, 0xF0);
+ err += sn9c102_i2c_write(cam, 0x60, 0x05);
+ err += sn9c102_i2c_write(cam, 0x61, 0x60);
+ err += sn9c102_i2c_write(cam, 0x62, 0x00);
+ err += sn9c102_i2c_write(cam, 0x63, 0x00);
+ err += sn9c102_i2c_write(cam, 0x64, 0x50);
+ err += sn9c102_i2c_write(cam, 0x65, 0x30);
+ err += sn9c102_i2c_write(cam, 0x66, 0x00);
+ err += sn9c102_i2c_write(cam, 0x67, 0x80);
+ err += sn9c102_i2c_write(cam, 0x68, 0x7A);
+ err += sn9c102_i2c_write(cam, 0x69, 0x90);
+ err += sn9c102_i2c_write(cam, 0x6A, 0x80);
+ err += sn9c102_i2c_write(cam, 0x6B, 0x0A);
+ err += sn9c102_i2c_write(cam, 0x6C, 0x30);
+ err += sn9c102_i2c_write(cam, 0x6D, 0x48);
+ err += sn9c102_i2c_write(cam, 0x6E, 0x80);
+ err += sn9c102_i2c_write(cam, 0x6F, 0x74);
+ err += sn9c102_i2c_write(cam, 0x70, 0x64);
+ err += sn9c102_i2c_write(cam, 0x71, 0x60);
+ err += sn9c102_i2c_write(cam, 0x72, 0x5C);
+ err += sn9c102_i2c_write(cam, 0x73, 0x58);
+ err += sn9c102_i2c_write(cam, 0x74, 0x54);
+ err += sn9c102_i2c_write(cam, 0x75, 0x4C);
+ err += sn9c102_i2c_write(cam, 0x76, 0x40);
+ err += sn9c102_i2c_write(cam, 0x77, 0x38);
+ err += sn9c102_i2c_write(cam, 0x78, 0x34);
+ err += sn9c102_i2c_write(cam, 0x79, 0x30);
+ err += sn9c102_i2c_write(cam, 0x7A, 0x2F);
+ err += sn9c102_i2c_write(cam, 0x7B, 0x2B);
+ err += sn9c102_i2c_write(cam, 0x7C, 0x03);
+ err += sn9c102_i2c_write(cam, 0x7D, 0x07);
+ err += sn9c102_i2c_write(cam, 0x7E, 0x17);
+ err += sn9c102_i2c_write(cam, 0x7F, 0x34);
+ err += sn9c102_i2c_write(cam, 0x80, 0x41);
+ err += sn9c102_i2c_write(cam, 0x81, 0x4D);
+ err += sn9c102_i2c_write(cam, 0x82, 0x58);
+ err += sn9c102_i2c_write(cam, 0x83, 0x63);
+ err += sn9c102_i2c_write(cam, 0x84, 0x6E);
+ err += sn9c102_i2c_write(cam, 0x85, 0x77);
+ err += sn9c102_i2c_write(cam, 0x86, 0x87);
+ err += sn9c102_i2c_write(cam, 0x87, 0x95);
+ err += sn9c102_i2c_write(cam, 0x88, 0xAF);
+ err += sn9c102_i2c_write(cam, 0x89, 0xC7);
+ err += sn9c102_i2c_write(cam, 0x8A, 0xDF);
+ err += sn9c102_i2c_write(cam, 0x8B, 0x99);
+ err += sn9c102_i2c_write(cam, 0x8C, 0x99);
+ err += sn9c102_i2c_write(cam, 0x8D, 0xCF);
+ err += sn9c102_i2c_write(cam, 0x8E, 0x20);
+ err += sn9c102_i2c_write(cam, 0x8F, 0x26);
+ err += sn9c102_i2c_write(cam, 0x90, 0x10);
+ err += sn9c102_i2c_write(cam, 0x91, 0x0C);
+ err += sn9c102_i2c_write(cam, 0x92, 0x25);
+ err += sn9c102_i2c_write(cam, 0x93, 0x00);
+ err += sn9c102_i2c_write(cam, 0x94, 0x50);
+ err += sn9c102_i2c_write(cam, 0x95, 0x50);
+ err += sn9c102_i2c_write(cam, 0x96, 0x00);
+ err += sn9c102_i2c_write(cam, 0x97, 0x01);
+ err += sn9c102_i2c_write(cam, 0x98, 0x10);
+ err += sn9c102_i2c_write(cam, 0x99, 0x40);
+ err += sn9c102_i2c_write(cam, 0x9A, 0x40);
+ err += sn9c102_i2c_write(cam, 0x9B, 0x20);
+ err += sn9c102_i2c_write(cam, 0x9C, 0x00);
+ err += sn9c102_i2c_write(cam, 0x9D, 0x99);
+ err += sn9c102_i2c_write(cam, 0x9E, 0x7F);
+ err += sn9c102_i2c_write(cam, 0x9F, 0x00);
+ err += sn9c102_i2c_write(cam, 0xA0, 0x00);
+ err += sn9c102_i2c_write(cam, 0xA1, 0x00);
+
+ return err;
+}
+
+
+static int ov7660_get_ctrl(struct sn9c102_device* cam,
+ struct v4l2_control* ctrl)
+{
+ int err = 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_EXPOSURE:
+ if ((ctrl->value = sn9c102_i2c_read(cam, 0x10)) < 0)
+ return -EIO;
+ break;
+ case V4L2_CID_DO_WHITE_BALANCE:
+ ctrl->value = sn9c102_pread_reg(cam, 0x02);
+ ctrl->value = (ctrl->value & 0x04) ? 1 : 0;
+ break;
+ case V4L2_CID_RED_BALANCE:
+ ctrl->value = sn9c102_pread_reg(cam, 0x05);
+ ctrl->value &= 0x7f;
+ break;
+ case V4L2_CID_BLUE_BALANCE:
+ ctrl->value = sn9c102_pread_reg(cam, 0x06);
+ ctrl->value &= 0x7f;
+ break;
+ case SN9C102_V4L2_CID_GREEN_BALANCE:
+ ctrl->value = sn9c102_pread_reg(cam, 0x07);
+ ctrl->value &= 0x7f;
+ break;
+ case V4L2_CID_GAIN:
+ if ((ctrl->value = sn9c102_i2c_read(cam, 0x00)) < 0)
+ return -EIO;
+ ctrl->value &= 0x7f;
+ break;
+ case V4L2_CID_AUTOGAIN:
+ if ((ctrl->value = sn9c102_i2c_read(cam, 0x13)) < 0)
+ return -EIO;
+ ctrl->value &= 0x01;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return err ? -EIO : 0;
+}
+
+
+static int ov7660_set_ctrl(struct sn9c102_device* cam,
+ const struct v4l2_control* ctrl)
+{
+ int err = 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_EXPOSURE:
+ err += sn9c102_i2c_write(cam, 0x10, ctrl->value);
+ break;
+ case V4L2_CID_DO_WHITE_BALANCE:
+ err += sn9c102_write_reg(cam, 0x43 | (ctrl->value << 2), 0x02);
+ break;
+ case V4L2_CID_RED_BALANCE:
+ err += sn9c102_write_reg(cam, ctrl->value, 0x05);
+ break;
+ case V4L2_CID_BLUE_BALANCE:
+ err += sn9c102_write_reg(cam, ctrl->value, 0x06);
+ break;
+ case SN9C102_V4L2_CID_GREEN_BALANCE:
+ err += sn9c102_write_reg(cam, ctrl->value, 0x07);
+ break;
+ case V4L2_CID_GAIN:
+ err += sn9c102_i2c_write(cam, 0x00, ctrl->value);
+ break;
+ case V4L2_CID_AUTOGAIN:
+ err += sn9c102_i2c_write(cam, 0x13, 0xf0 | ctrl->value |
+ (ctrl->value << 1));
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return err ? -EIO : 0;
+}
+
+
+static int ov7660_set_crop(struct sn9c102_device* cam,
+ const struct v4l2_rect* rect)
+{
+ struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
+ int err = 0;
+ u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 1,
+ v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1;
+
+ err += sn9c102_write_reg(cam, h_start, 0x12);
+ err += sn9c102_write_reg(cam, v_start, 0x13);
+
+ return err;
+}
+
+
+static int ov7660_set_pix_format(struct sn9c102_device* cam,
+ const struct v4l2_pix_format* pix)
+{
+ int r0, err = 0;
+
+ r0 = sn9c102_pread_reg(cam, 0x01);
+
+ if (pix->pixelformat == V4L2_PIX_FMT_JPEG) {
+ err += sn9c102_write_reg(cam, r0 | 0x40, 0x01);
+ err += sn9c102_write_reg(cam, 0xa2, 0x17);
+ err += sn9c102_i2c_write(cam, 0x11, 0x00);
+ } else {
+ err += sn9c102_write_reg(cam, r0 | 0x40, 0x01);
+ err += sn9c102_write_reg(cam, 0xa2, 0x17);
+ err += sn9c102_i2c_write(cam, 0x11, 0x0d);
+ }
+
+ return err;
+}
+
+
+static struct sn9c102_sensor ov7660 = {
+ .name = "OV7660",
+ .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
+ .supported_bridge = BRIDGE_SN9C105 | BRIDGE_SN9C120,
+ .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
+ .frequency = SN9C102_I2C_100KHZ,
+ .interface = SN9C102_I2C_2WIRES,
+ .i2c_slave_id = 0x21,
+ .init = &ov7660_init,
+ .qctrl = {
+ {
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "global gain",
+ .minimum = 0x00,
+ .maximum = 0x7f,
+ .step = 0x01,
+ .default_value = 0x0a,
+ .flags = 0,
+ },
+ {
+ .id = V4L2_CID_EXPOSURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "exposure",
+ .minimum = 0x00,
+ .maximum = 0xff,
+ .step = 0x01,
+ .default_value = 0x50,
+ .flags = 0,
+ },
+ {
+ .id = V4L2_CID_DO_WHITE_BALANCE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "night mode",
+ .minimum = 0x00,
+ .maximum = 0x01,
+ .step = 0x01,
+ .default_value = 0x00,
+ .flags = 0,
+ },
+ {
+ .id = V4L2_CID_RED_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "red balance",
+ .minimum = 0x00,
+ .maximum = 0x7f,
+ .step = 0x01,
+ .default_value = 0x1f,
+ .flags = 0,
+ },
+ {
+ .id = V4L2_CID_BLUE_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "blue balance",
+ .minimum = 0x00,
+ .maximum = 0x7f,
+ .step = 0x01,
+ .default_value = 0x1e,
+ .flags = 0,
+ },
+ {
+ .id = V4L2_CID_AUTOGAIN,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "auto adjust",
+ .minimum = 0x00,
+ .maximum = 0x01,
+ .step = 0x01,
+ .default_value = 0x00,
+ .flags = 0,
+ },
+ {
+ .id = SN9C102_V4L2_CID_GREEN_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "green balance",
+ .minimum = 0x00,
+ .maximum = 0x7f,
+ .step = 0x01,
+ .default_value = 0x20,
+ .flags = 0,
+ },
+ },
+ .get_ctrl = &ov7660_get_ctrl,
+ .set_ctrl = &ov7660_set_ctrl,
+ .cropcap = {
+ .bounds = {
+ .left = 0,
+ .top = 0,
+ .width = 640,
+ .height = 480,
+ },
+ .defrect = {
+ .left = 0,
+ .top = 0,
+ .width = 640,
+ .height = 480,
+ },
+ },
+ .set_crop = &ov7660_set_crop,
+ .pix_format = {
+ .width = 640,
+ .height = 480,
+ .pixelformat = V4L2_PIX_FMT_JPEG,
+ .priv = 8,
+ },
+ .set_pix_format = &ov7660_set_pix_format
+};
+
+
+int sn9c102_probe_ov7660(struct sn9c102_device* cam)
+{
+ int pid, ver, err = 0;
+
+ err += sn9c102_write_reg(cam, 0x01, 0xf1);
+ err += sn9c102_write_reg(cam, 0x00, 0xf1);
+ err += sn9c102_write_reg(cam, 0x01, 0x01);
+ err += sn9c102_write_reg(cam, 0x00, 0x01);
+ err += sn9c102_write_reg(cam, 0x28, 0x17);
+
+ pid = sn9c102_i2c_try_read(cam, &ov7660, 0x0a);
+ ver = sn9c102_i2c_try_read(cam, &ov7660, 0x0b);
+ if (err || pid < 0 || ver < 0)
+ return -EIO;
+ if (pid != 0x76 || ver != 0x60)
+ return -ENODEV;
+ sn9c102_attach_sensor(cam, &ov7660);
+
+ return 0;
+}
diff --git a/drivers/media/video/sn9c102/sn9c102_pas106b.c b/drivers/media/video/sn9c102/sn9c102_pas106b.c
index 9915944235e..8d79a5fae5d 100644
--- a/drivers/media/video/sn9c102/sn9c102_pas106b.c
+++ b/drivers/media/video/sn9c102/sn9c102_pas106b.c
@@ -1,8 +1,8 @@
/***************************************************************************
- * Plug-in for PAS106B image sensor connected to the SN9C10x PC Camera *
+ * Plug-in for PAS106B image sensor connected to the SN9C1xx PC Camera *
* Controllers *
* *
- * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
+ * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.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 *
@@ -143,7 +143,7 @@ static int pas106b_set_ctrl(struct sn9c102_device* cam,
static int pas106b_set_crop(struct sn9c102_device* cam,
const struct v4l2_rect* rect)
{
- struct sn9c102_sensor* s = &pas106b;
+ struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
int err = 0;
u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4,
v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3;
@@ -172,6 +172,7 @@ static int pas106b_set_pix_format(struct sn9c102_device* cam,
static struct sn9c102_sensor pas106b = {
.name = "PAS106B",
.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
+ .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103,
.sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
.frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ,
.interface = SN9C102_I2C_2WIRES,
diff --git a/drivers/media/video/sn9c102/sn9c102_pas202bca.c b/drivers/media/video/sn9c102/sn9c102_pas202bca.c
deleted file mode 100644
index c8f1ae2152b..00000000000
--- a/drivers/media/video/sn9c102/sn9c102_pas202bca.c
+++ /dev/null
@@ -1,238 +0,0 @@
-/***************************************************************************
- * Plug-in for PAS202BCA image sensor connected to the SN9C10x PC Camera *
- * Controllers *
- * *
- * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.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/delay.h>
-#include "sn9c102_sensor.h"
-
-
-static struct sn9c102_sensor pas202bca;
-
-
-static int pas202bca_init(struct sn9c102_device* cam)
-{
- int err = 0;
-
- err += sn9c102_write_reg(cam, 0x00, 0x10);
- err += sn9c102_write_reg(cam, 0x00, 0x11);
- err += sn9c102_write_reg(cam, 0x00, 0x14);
- err += sn9c102_write_reg(cam, 0x20, 0x17);
- err += sn9c102_write_reg(cam, 0x30, 0x19);
- err += sn9c102_write_reg(cam, 0x09, 0x18);
-
- err += sn9c102_i2c_write(cam, 0x02, 0x14);
- err += sn9c102_i2c_write(cam, 0x03, 0x40);
- err += sn9c102_i2c_write(cam, 0x0d, 0x2c);
- err += sn9c102_i2c_write(cam, 0x0e, 0x01);
- err += sn9c102_i2c_write(cam, 0x0f, 0xa9);
- err += sn9c102_i2c_write(cam, 0x10, 0x08);
- err += sn9c102_i2c_write(cam, 0x13, 0x63);
- err += sn9c102_i2c_write(cam, 0x15, 0x70);
- err += sn9c102_i2c_write(cam, 0x11, 0x01);
-
- msleep(400);
-
- return err;
-}
-
-
-static int pas202bca_set_pix_format(struct sn9c102_device* cam,
- const struct v4l2_pix_format* pix)
-{
- int err = 0;
-
- if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
- err += sn9c102_write_reg(cam, 0x24, 0x17);
- else
- err += sn9c102_write_reg(cam, 0x20, 0x17);
-
- return err;
-}
-
-
-static int pas202bca_set_ctrl(struct sn9c102_device* cam,
- const struct v4l2_control* ctrl)
-{
- int err = 0;
-
- switch (ctrl->id) {
- case V4L2_CID_EXPOSURE:
- err += sn9c102_i2c_write(cam, 0x04, ctrl->value >> 6);
- err += sn9c102_i2c_write(cam, 0x05, ctrl->value & 0x3f);
- break;
- case V4L2_CID_RED_BALANCE:
- err += sn9c102_i2c_write(cam, 0x09, ctrl->value);
- break;
- case V4L2_CID_BLUE_BALANCE:
- err += sn9c102_i2c_write(cam, 0x07, ctrl->value);
- break;
- case V4L2_CID_GAIN:
- err += sn9c102_i2c_write(cam, 0x10, ctrl->value);
- break;
- case SN9C102_V4L2_CID_GREEN_BALANCE:
- err += sn9c102_i2c_write(cam, 0x08, ctrl->value);
- break;
- case SN9C102_V4L2_CID_DAC_MAGNITUDE:
- err += sn9c102_i2c_write(cam, 0x0c, ctrl->value);
- break;
- default:
- return -EINVAL;
- }
- err += sn9c102_i2c_write(cam, 0x11, 0x01);
-
- return err ? -EIO : 0;
-}
-
-
-static int pas202bca_set_crop(struct sn9c102_device* cam,
- const struct v4l2_rect* rect)
-{
- struct sn9c102_sensor* s = &pas202bca;
- int err = 0;
- u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 3,
- v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3;
-
- err += sn9c102_write_reg(cam, h_start, 0x12);
- err += sn9c102_write_reg(cam, v_start, 0x13);
-
- return err;
-}
-
-
-static struct sn9c102_sensor pas202bca = {
- .name = "PAS202BCA",
- .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
- .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
- .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ,
- .interface = SN9C102_I2C_2WIRES,
- .i2c_slave_id = 0x40,
- .init = &pas202bca_init,
- .qctrl = {
- {
- .id = V4L2_CID_EXPOSURE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "exposure",
- .minimum = 0x01e5,
- .maximum = 0x3fff,
- .step = 0x0001,
- .default_value = 0x01e5,
- .flags = 0,
- },
- {
- .id = V4L2_CID_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "global gain",
- .minimum = 0x00,
- .maximum = 0x1f,
- .step = 0x01,
- .default_value = 0x0c,
- .flags = 0,
- },
- {
- .id = V4L2_CID_RED_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "red balance",
- .minimum = 0x00,
- .maximum = 0x0f,
- .step = 0x01,
- .default_value = 0x01,
- .flags = 0,
- },
- {
- .id = V4L2_CID_BLUE_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "blue balance",
- .minimum = 0x00,
- .maximum = 0x0f,
- .step = 0x01,
- .default_value = 0x05,
- .flags = 0,
- },
- {
- .id = SN9C102_V4L2_CID_GREEN_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "green balance",
- .minimum = 0x00,
- .maximum = 0x0f,
- .step = 0x01,
- .default_value = 0x00,
- .flags = 0,
- },
- {
- .id = SN9C102_V4L2_CID_DAC_MAGNITUDE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "DAC magnitude",
- .minimum = 0x00,
- .maximum = 0xff,
- .step = 0x01,
- .default_value = 0x04,
- .flags = 0,
- },
- },
- .set_ctrl = &pas202bca_set_ctrl,
- .cropcap = {
- .bounds = {
- .left = 0,
- .top = 0,
- .width = 640,
- .height = 480,
- },
- .defrect = {
- .left = 0,
- .top = 0,
- .width = 640,
- .height = 480,
- },
- },
- .set_crop = &pas202bca_set_crop,
- .pix_format = {
- .width = 640,
- .height = 480,
- .pixelformat = V4L2_PIX_FMT_SBGGR8,
- .priv = 8,
- },
- .set_pix_format = &pas202bca_set_pix_format
-};
-
-
-int sn9c102_probe_pas202bca(struct sn9c102_device* cam)
-{
- const struct usb_device_id pas202bca_id_table[] = {
- { USB_DEVICE(0x0c45, 0x60af), },
- { }
- };
- int err = 0;
-
- if (!sn9c102_match_id(cam,pas202bca_id_table))
- return -ENODEV;
-
- err += sn9c102_write_reg(cam, 0x01, 0x01);
- err += sn9c102_write_reg(cam, 0x40, 0x01);
- err += sn9c102_write_reg(cam, 0x28, 0x17);
- if (err)
- return -EIO;
-
- if (sn9c102_i2c_try_write(cam, &pas202bca, 0x10, 0)) /* try to write */
- return -ENODEV;
-
- sn9c102_attach_sensor(cam, &pas202bca);
-
- return 0;
-}
diff --git a/drivers/media/video/sn9c102/sn9c102_pas202bcb.c b/drivers/media/video/sn9c102/sn9c102_pas202bcb.c
index e3c1178e339..7894f01b56e 100644
--- a/drivers/media/video/sn9c102/sn9c102_pas202bcb.c
+++ b/drivers/media/video/sn9c102/sn9c102_pas202bcb.c
@@ -1,13 +1,13 @@
/***************************************************************************
- * Plug-in for PAS202BCB image sensor connected to the SN9C10x PC Camera *
+ * Plug-in for PAS202BCB image sensor connected to the SN9C1xx PC Camera *
* Controllers *
* *
* Copyright (C) 2004 by Carlos Eduardo Medaglia Dyonisio *
* <medaglia@undl.org.br> *
* http://cadu.homelinux.com:8080/ *
* *
- * DAC Magnitude, exposure and green gain controls added by *
- * Luca Risolia <luca.risolia@studio.unibo.it> *
+ * Support for SN9C103, DAC Magnitude, exposure and green gain controls *
+ * added by Luca Risolia <luca.risolia@studio.unibo.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 *
@@ -35,12 +35,54 @@ static int pas202bcb_init(struct sn9c102_device* cam)
{
int err = 0;
+ switch (sn9c102_get_bridge(cam)) {
+ case BRIDGE_SN9C101:
+ case BRIDGE_SN9C102:
err += sn9c102_write_reg(cam, 0x00, 0x10);
err += sn9c102_write_reg(cam, 0x00, 0x11);
err += sn9c102_write_reg(cam, 0x00, 0x14);
err += sn9c102_write_reg(cam, 0x20, 0x17);
err += sn9c102_write_reg(cam, 0x30, 0x19);
err += sn9c102_write_reg(cam, 0x09, 0x18);
+ break;
+ case BRIDGE_SN9C103:
+ err += sn9c102_write_reg(cam, 0x00, 0x02);
+ err += sn9c102_write_reg(cam, 0x00, 0x03);
+ err += sn9c102_write_reg(cam, 0x1a, 0x04);
+ err += sn9c102_write_reg(cam, 0x20, 0x05);
+ err += sn9c102_write_reg(cam, 0x20, 0x06);
+ err += sn9c102_write_reg(cam, 0x20, 0x07);
+ err += sn9c102_write_reg(cam, 0x00, 0x10);
+ err += sn9c102_write_reg(cam, 0x00, 0x11);
+ err += sn9c102_write_reg(cam, 0x00, 0x14);
+ err += sn9c102_write_reg(cam, 0x20, 0x17);
+ err += sn9c102_write_reg(cam, 0x30, 0x19);
+ err += sn9c102_write_reg(cam, 0x09, 0x18);
+ err += sn9c102_write_reg(cam, 0x02, 0x1c);
+ err += sn9c102_write_reg(cam, 0x03, 0x1d);
+ err += sn9c102_write_reg(cam, 0x0f, 0x1e);
+ err += sn9c102_write_reg(cam, 0x0c, 0x1f);
+ err += sn9c102_write_reg(cam, 0x00, 0x20);
+ err += sn9c102_write_reg(cam, 0x10, 0x21);
+ err += sn9c102_write_reg(cam, 0x20, 0x22);
+ err += sn9c102_write_reg(cam, 0x30, 0x23);
+ err += sn9c102_write_reg(cam, 0x40, 0x24);
+ err += sn9c102_write_reg(cam, 0x50, 0x25);
+ err += sn9c102_write_reg(cam, 0x60, 0x26);
+ err += sn9c102_write_reg(cam, 0x70, 0x27);
+ err += sn9c102_write_reg(cam, 0x80, 0x28);
+ err += sn9c102_write_reg(cam, 0x90, 0x29);
+ err += sn9c102_write_reg(cam, 0xa0, 0x2a);
+ err += sn9c102_write_reg(cam, 0xb0, 0x2b);
+ err += sn9c102_write_reg(cam, 0xc0, 0x2c);
+ err += sn9c102_write_reg(cam, 0xd0, 0x2d);
+ err += sn9c102_write_reg(cam, 0xe0, 0x2e);
+ err += sn9c102_write_reg(cam, 0xf0, 0x2f);
+ err += sn9c102_write_reg(cam, 0xff, 0x30);
+ break;
+ default:
+ break;
+ }
err += sn9c102_i2c_write(cam, 0x02, 0x14);
err += sn9c102_i2c_write(cam, 0x03, 0x40);
@@ -107,7 +149,7 @@ static int pas202bcb_set_pix_format(struct sn9c102_device* cam,
int err = 0;
if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
- err += sn9c102_write_reg(cam, 0x24, 0x17);
+ err += sn9c102_write_reg(cam, 0x28, 0x17);
else
err += sn9c102_write_reg(cam, 0x20, 0x17);
@@ -152,11 +194,23 @@ static int pas202bcb_set_ctrl(struct sn9c102_device* cam,
static int pas202bcb_set_crop(struct sn9c102_device* cam,
const struct v4l2_rect* rect)
{
- struct sn9c102_sensor* s = &pas202bcb;
+ struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
int err = 0;
- u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4,
+ u8 h_start = 0,
v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3;
+ switch (sn9c102_get_bridge(cam)) {
+ case BRIDGE_SN9C101:
+ case BRIDGE_SN9C102:
+ h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4;
+ break;
+ case BRIDGE_SN9C103:
+ h_start = (u8)(rect->left - s->cropcap.bounds.left) + 3;
+ break;
+ default:
+ break;
+ }
+
err += sn9c102_write_reg(cam, h_start, 0x12);
err += sn9c102_write_reg(cam, v_start, 0x13);
@@ -166,8 +220,8 @@ static int pas202bcb_set_crop(struct sn9c102_device* cam,
static struct sn9c102_sensor pas202bcb = {
.name = "PAS202BCB",
- .maintainer = "Carlos Eduardo Medaglia Dyonisio "
- "<medaglia@undl.org.br>",
+ .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
+ .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103,
.sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
.frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ,
.interface = SN9C102_I2C_2WIRES,
@@ -191,7 +245,7 @@ static struct sn9c102_sensor pas202bcb = {
.minimum = 0x00,
.maximum = 0x1f,
.step = 0x01,
- .default_value = 0x0c,
+ .default_value = 0x0b,
.flags = 0,
},
{
@@ -201,7 +255,7 @@ static struct sn9c102_sensor pas202bcb = {
.minimum = 0x00,
.maximum = 0x0f,
.step = 0x01,
- .default_value = 0x01,
+ .default_value = 0x00,
.flags = 0,
},
{
@@ -271,16 +325,27 @@ int sn9c102_probe_pas202bcb(struct sn9c102_device* cam)
* Minimal initialization to enable the I2C communication
* NOTE: do NOT change the values!
*/
- err += sn9c102_write_reg(cam, 0x01, 0x01); /* sensor power down */
- err += sn9c102_write_reg(cam, 0x40, 0x01); /* sensor power on */
- err += sn9c102_write_reg(cam, 0x28, 0x17); /* sensor clock at 24 MHz */
- if (err)
- return -EIO;
+ switch (sn9c102_get_bridge(cam)) {
+ case BRIDGE_SN9C101:
+ case BRIDGE_SN9C102:
+ err += sn9c102_write_reg(cam, 0x01, 0x01); /* power down */
+ err += sn9c102_write_reg(cam, 0x40, 0x01); /* power on */
+ err += sn9c102_write_reg(cam, 0x28, 0x17); /* clock 24 MHz */
+ break;
+ case BRIDGE_SN9C103: /* do _not_ change anything! */
+ err += sn9c102_write_reg(cam, 0x09, 0x01);
+ err += sn9c102_write_reg(cam, 0x44, 0x01);
+ err += sn9c102_write_reg(cam, 0x44, 0x02);
+ err += sn9c102_write_reg(cam, 0x29, 0x17);
+ break;
+ default:
+ break;
+ }
r0 = sn9c102_i2c_try_read(cam, &pas202bcb, 0x00);
r1 = sn9c102_i2c_try_read(cam, &pas202bcb, 0x01);
- if (r0 < 0 || r1 < 0)
+ if (err || r0 < 0 || r1 < 0)
return -EIO;
pid = (r0 << 4) | ((r1 & 0xf0) >> 4);
diff --git a/drivers/media/video/sn9c102/sn9c102_sensor.h b/drivers/media/video/sn9c102/sn9c102_sensor.h
index 2a874ee6f9f..05f2942639c 100644
--- a/drivers/media/video/sn9c102/sn9c102_sensor.h
+++ b/drivers/media/video/sn9c102/sn9c102_sensor.h
@@ -1,7 +1,7 @@
/***************************************************************************
- * API for image sensors connected to the SN9C10x PC Camera Controllers *
+ * API for image sensors connected to the SN9C1xx PC Camera Controllers *
* *
- * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
+ * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.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 *
@@ -36,14 +36,13 @@ struct sn9c102_sensor;
/*
OVERVIEW.
This is a small interface that allows you to add support for any CCD/CMOS
- image sensors connected to the SN9C10X bridges. The entire API is documented
+ image sensors connected to the SN9C1XX bridges. The entire API is documented
below. In the most general case, to support a sensor there are three steps
you have to follow:
1) define the main "sn9c102_sensor" structure by setting the basic fields;
2) write a probing function to be called by the core module when the USB
camera is recognized, then add both the USB ids and the name of that
- function to the two corresponding tables SENSOR_TABLE and ID_TABLE (see
- below);
+ function to the two corresponding tables in sn9c102_devtable.h;
3) implement the methods that you want/need (and fill the rest of the main
structure accordingly).
"sn9c102_pas106b.c" is an example of all this stuff. Remember that you do
@@ -54,42 +53,21 @@ struct sn9c102_sensor;
/*****************************************************************************/
-/*
- Probing functions: on success, you must attach the sensor to the camera
- by calling sn9c102_attach_sensor() provided below.
- To enable the I2C communication, you might need to perform a really basic
- initialization of the SN9C10X chip by using the write function declared
- ahead.
- Functions must return 0 on success, the appropriate error otherwise.
-*/
-extern int sn9c102_probe_hv7131d(struct sn9c102_device* cam);
-extern int sn9c102_probe_mi0343(struct sn9c102_device* cam);
-extern int sn9c102_probe_ov7630(struct sn9c102_device* cam);
-extern int sn9c102_probe_pas106b(struct sn9c102_device* cam);
-extern int sn9c102_probe_pas202bca(struct sn9c102_device* cam);
-extern int sn9c102_probe_pas202bcb(struct sn9c102_device* cam);
-extern int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam);
-extern int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam);
-
-/*
- Add the above entries to this table. Be sure to add the entry in the right
- place, since, on failure, the next probing routine is called according to
- the order of the list below, from top to bottom.
-*/
-#define SN9C102_SENSOR_TABLE \
-static int (*sn9c102_sensor_table[])(struct sn9c102_device*) = { \
- &sn9c102_probe_mi0343, /* strong detection based on SENSOR ids */ \
- &sn9c102_probe_pas106b, /* strong detection based on SENSOR ids */ \
- &sn9c102_probe_pas202bcb, /* strong detection based on SENSOR ids */ \
- &sn9c102_probe_hv7131d, /* strong detection based on SENSOR ids */ \
- &sn9c102_probe_pas202bca, /* detection mostly based on USB pid/vid */ \
- &sn9c102_probe_ov7630, /* detection mostly based on USB pid/vid */ \
- &sn9c102_probe_tas5110c1b, /* detection based on USB pid/vid */ \
- &sn9c102_probe_tas5130d1b, /* detection based on USB pid/vid */ \
- NULL, \
+enum sn9c102_bridge {
+ BRIDGE_SN9C101 = 0x01,
+ BRIDGE_SN9C102 = 0x02,
+ BRIDGE_SN9C103 = 0x04,
+ BRIDGE_SN9C105 = 0x08,
+ BRIDGE_SN9C120 = 0x10,
};
-/* Device identification */
+/* Return the bridge name */
+enum sn9c102_bridge sn9c102_get_bridge(struct sn9c102_device* cam);
+
+/* Return a pointer the sensor struct attached to the camera */
+struct sn9c102_sensor* sn9c102_get_sensor(struct sn9c102_device* cam);
+
+/* Identify a device */
extern struct sn9c102_device*
sn9c102_match_id(struct sn9c102_device* cam, const struct usb_device_id *id);
@@ -99,68 +77,8 @@ sn9c102_attach_sensor(struct sn9c102_device* cam,
struct sn9c102_sensor* sensor);
/*
- Each SN9C10x camera has proper PID/VID identifiers.
- SN9C103 supports multiple interfaces, but we only handle the video class
- interface.
-*/
-#define SN9C102_USB_DEVICE(vend, prod, intclass) \
- .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \
- USB_DEVICE_ID_MATCH_INT_CLASS, \
- .idVendor = (vend), \
- .idProduct = (prod), \
- .bInterfaceClass = (intclass)
-
-#define SN9C102_ID_TABLE \
-static const struct usb_device_id sn9c102_id_table[] = { \
- { USB_DEVICE(0x0c45, 0x6001), }, /* TAS5110C1B */ \
- { USB_DEVICE(0x0c45, 0x6005), }, /* TAS5110C1B */ \
- { USB_DEVICE(0x0c45, 0x6007), }, \
- { USB_DEVICE(0x0c45, 0x6009), }, /* PAS106B */ \
- { USB_DEVICE(0x0c45, 0x600d), }, /* PAS106B */ \
- { USB_DEVICE(0x0c45, 0x6024), }, \
- { USB_DEVICE(0x0c45, 0x6025), }, /* TAS5130D1B and TAS5110C1B */ \
- { USB_DEVICE(0x0c45, 0x6028), }, /* PAS202BCB */ \
- { USB_DEVICE(0x0c45, 0x6029), }, /* PAS106B */ \
- { USB_DEVICE(0x0c45, 0x602a), }, /* HV7131D */ \
- { USB_DEVICE(0x0c45, 0x602b), }, /* MI-0343 */ \
- { USB_DEVICE(0x0c45, 0x602c), }, /* OV7630 */ \
- { USB_DEVICE(0x0c45, 0x602d), }, \
- { USB_DEVICE(0x0c45, 0x602e), }, /* OV7630 */ \
- { USB_DEVICE(0x0c45, 0x6030), }, /* MI03x */ \
- { SN9C102_USB_DEVICE(0x0c45, 0x6080, 0xff), }, \
- { SN9C102_USB_DEVICE(0x0c45, 0x6082, 0xff), }, /* MI0343 & MI0360 */ \
- { SN9C102_USB_DEVICE(0x0c45, 0x6083, 0xff), }, /* HV7131[D|E1] */ \
- { SN9C102_USB_DEVICE(0x0c45, 0x6088, 0xff), }, \
- { SN9C102_USB_DEVICE(0x0c45, 0x608a, 0xff), }, \
- { SN9C102_USB_DEVICE(0x0c45, 0x608b, 0xff), }, \
- { SN9C102_USB_DEVICE(0x0c45, 0x608c, 0xff), }, /* HV7131/R */ \
- { SN9C102_USB_DEVICE(0x0c45, 0x608e, 0xff), }, /* CIS-VF10 */ \
- { SN9C102_USB_DEVICE(0x0c45, 0x608f, 0xff), }, /* OV7630 */ \
- { SN9C102_USB_DEVICE(0x0c45, 0x60a0, 0xff), }, \
- { SN9C102_USB_DEVICE(0x0c45, 0x60a2, 0xff), }, \
- { SN9C102_USB_DEVICE(0x0c45, 0x60a3, 0xff), }, \
- { SN9C102_USB_DEVICE(0x0c45, 0x60a8, 0xff), }, /* PAS106B */ \
- { SN9C102_USB_DEVICE(0x0c45, 0x60aa, 0xff), }, /* TAS5130D1B */ \
- { SN9C102_USB_DEVICE(0x0c45, 0x60ab, 0xff), }, /* TAS5110C1B */ \
- { SN9C102_USB_DEVICE(0x0c45, 0x60ac, 0xff), }, \
- { SN9C102_USB_DEVICE(0x0c45, 0x60ae, 0xff), }, \
- { SN9C102_USB_DEVICE(0x0c45, 0x60af, 0xff), }, /* PAS202BCB */ \
- { SN9C102_USB_DEVICE(0x0c45, 0x60b0, 0xff), }, /* OV7630 (?) */ \
- { SN9C102_USB_DEVICE(0x0c45, 0x60b2, 0xff), }, \
- { SN9C102_USB_DEVICE(0x0c45, 0x60b3, 0xff), }, \
- { SN9C102_USB_DEVICE(0x0c45, 0x60b8, 0xff), }, \
- { SN9C102_USB_DEVICE(0x0c45, 0x60ba, 0xff), }, \
- { SN9C102_USB_DEVICE(0x0c45, 0x60bb, 0xff), }, \
- { SN9C102_USB_DEVICE(0x0c45, 0x60bc, 0xff), }, \
- { SN9C102_USB_DEVICE(0x0c45, 0x60be, 0xff), }, \
- { } \
-};
-
-/*****************************************************************************/
-
-/*
Read/write routines: they always return -1 on error, 0 or the read value
- otherwise. NOTE that a real read operation is not supported by the SN9C10X
+ otherwise. NOTE that a real read operation is not supported by the SN9C1XX
chip for some of its registers. To work around this problem, a pseudo-read
call is provided instead: it returns the last successfully written value
on the register (0 if it has never been written), the usual -1 on error.
@@ -176,7 +94,7 @@ extern int sn9c102_i2c_try_read(struct sn9c102_device*,struct sn9c102_sensor*,
These must be used if and only if the sensor doesn't implement the standard
I2C protocol. There are a number of good reasons why you must use the
single-byte versions of these functions: do not abuse. The first function
- writes n bytes, from data0 to datan, to registers 0x09 - 0x09+n of SN9C10X
+ writes n bytes, from data0 to datan, to registers 0x09 - 0x09+n of SN9C1XX
chip. The second one programs the registers 0x09 and 0x10 with data0 and
data1, and places the n bytes read from the sensor register table in the
buffer pointed by 'buffer'. Both the functions return -1 on error; the write
@@ -200,16 +118,6 @@ extern int sn9c102_write_regs(struct sn9c102_device*, u8* buff, u16 index);
extern int sn9c102_write_reg(struct sn9c102_device*, u8 value, u16 index);
extern int sn9c102_pread_reg(struct sn9c102_device*, u16 index);
-/*
- NOTE: there are no exported debugging functions. To uniform the output you
- must use the dev_info()/dev_warn()/dev_err() macros defined in device.h,
- already included here, the argument being the struct device '&usbdev->dev'
- of the sensor structure. Do NOT use these macros before the sensor is
- attached or the kernel will crash! However, you should not need to notify
- the user about common errors or other messages, since this is done by the
- master module.
-*/
-
/*****************************************************************************/
enum sn9c102_i2c_sysfs_ops {
@@ -227,17 +135,19 @@ enum sn9c102_i2c_interface {
SN9C102_I2C_3WIRES,
};
-#define SN9C102_MAX_CTRLS V4L2_CID_LASTP1-V4L2_CID_BASE+10
+#define SN9C102_MAX_CTRLS (V4L2_CID_LASTP1-V4L2_CID_BASE+10)
struct sn9c102_sensor {
char name[32], /* sensor name */
maintainer[64]; /* name of the mantainer <email> */
+ enum sn9c102_bridge supported_bridge; /* supported SN9C1xx bridges */
+
/* Supported operations through the 'sysfs' interface */
enum sn9c102_i2c_sysfs_ops sysfs_ops;
/*
- These sensor capabilities must be provided if the SN9C10X controller
+ These sensor capabilities must be provided if the SN9C1XX controller
needs to communicate through the sensor serial interface by using
at least one of the i2c functions available.
*/
@@ -260,7 +170,7 @@ struct sn9c102_sensor {
/*
This function will be called after the sensor has been attached.
It should be used to initialize the sensor only, but may also
- configure part of the SN9C10X chip if necessary. You don't need to
+ configure part of the SN9C1XX chip if necessary. You don't need to
setup picture settings like brightness, contrast, etc.. here, if
the corrisponding controls are implemented (see below), since
they are adjusted in the core driver by calling the set_ctrl()
@@ -300,7 +210,7 @@ struct sn9c102_sensor {
It is not always true that the largest achievable active window can
cover the whole array of pixels. The V4L2 API defines another
area called "source rectangle", which, in turn, is a subrectangle of
- the active window. The SN9C10X chip is always programmed to read the
+ the active window. The SN9C1XX chip is always programmed to read the
source rectangle.
The bounds of both the active window and the source rectangle are
specified in the cropcap substructures 'bounds' and 'defrect'.
@@ -326,13 +236,13 @@ struct sn9c102_sensor {
const struct v4l2_rect* rect);
/*
To be called on VIDIOC_C_SETCROP. The core module always calls a
- default routine which configures the appropriate SN9C10X regs (also
+ default routine which configures the appropriate SN9C1XX regs (also
scaling), but you may need to override/adjust specific stuff.
'rect' contains width and height values that are multiple of 16: in
case you override the default function, you always have to program
the chip to match those values; on error return the corresponding
error code without rolling back.
- NOTE: in case, you must program the SN9C10X chip to get rid of
+ NOTE: in case, you must program the SN9C1XX chip to get rid of
blank pixels or blank lines at the _start_ of each line or
frame after each HSYNC or VSYNC, so that the image starts with
real RGB data (see regs 0x12, 0x13) (having set H_SIZE and,
@@ -344,16 +254,16 @@ struct sn9c102_sensor {
/*
What you have to define here are: 1) initial 'width' and 'height' of
the target rectangle 2) the initial 'pixelformat', which can be
- either V4L2_PIX_FMT_SN9C10X (for compressed video) or
- V4L2_PIX_FMT_SBGGR8 3) 'priv', which we'll be used to indicate the
- number of bits per pixel for uncompressed video, 8 or 9 (despite the
- current value of 'pixelformat').
+ either V4L2_PIX_FMT_SN9C10X, V4L2_PIX_FMT_JPEG (for ompressed video)
+ or V4L2_PIX_FMT_SBGGR8 3) 'priv', which we'll be used to indicate
+ the number of bits per pixel for uncompressed video, 8 or 9 (despite
+ the current value of 'pixelformat').
NOTE 1: both 'width' and 'height' _must_ be either 1/1 or 1/2 or 1/4
of cropcap.defrect.width and cropcap.defrect.height. I
suggest 1/1.
NOTE 2: The initial compression quality is defined by the first bit
of reg 0x17 during the initialization of the image sensor.
- NOTE 3: as said above, you have to program the SN9C10X chip to get
+ NOTE 3: as said above, you have to program the SN9C1XX chip to get
rid of any blank pixels, so that the output of the sensor
matches the RGB bayer sequence (i.e. BGBGBG...GRGRGR).
*/
@@ -378,12 +288,12 @@ struct sn9c102_sensor {
/*****************************************************************************/
/* Private ioctl's for control settings supported by some image sensors */
-#define SN9C102_V4L2_CID_DAC_MAGNITUDE V4L2_CID_PRIVATE_BASE
-#define SN9C102_V4L2_CID_GREEN_BALANCE V4L2_CID_PRIVATE_BASE + 1
-#define SN9C102_V4L2_CID_RESET_LEVEL V4L2_CID_PRIVATE_BASE + 2
-#define SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE V4L2_CID_PRIVATE_BASE + 3
-#define SN9C102_V4L2_CID_GAMMA V4L2_CID_PRIVATE_BASE + 4
-#define SN9C102_V4L2_CID_BAND_FILTER V4L2_CID_PRIVATE_BASE + 5
-#define SN9C102_V4L2_CID_BRIGHT_LEVEL V4L2_CID_PRIVATE_BASE + 6
+#define SN9C102_V4L2_CID_DAC_MAGNITUDE (V4L2_CID_PRIVATE_BASE + 0)
+#define SN9C102_V4L2_CID_GREEN_BALANCE (V4L2_CID_PRIVATE_BASE + 1)
+#define SN9C102_V4L2_CID_RESET_LEVEL (V4L2_CID_PRIVATE_BASE + 2)
+#define SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE (V4L2_CID_PRIVATE_BASE + 3)
+#define SN9C102_V4L2_CID_GAMMA (V4L2_CID_PRIVATE_BASE + 4)
+#define SN9C102_V4L2_CID_BAND_FILTER (V4L2_CID_PRIVATE_BASE + 5)
+#define SN9C102_V4L2_CID_BRIGHT_LEVEL (V4L2_CID_PRIVATE_BASE + 6)
#endif /* _SN9C102_SENSOR_H_ */
diff --git a/drivers/media/video/sn9c102/sn9c102_tas5110c1b.c b/drivers/media/video/sn9c102/sn9c102_tas5110c1b.c
index 294eb02fbd8..90023ad63ad 100644
--- a/drivers/media/video/sn9c102/sn9c102_tas5110c1b.c
+++ b/drivers/media/video/sn9c102/sn9c102_tas5110c1b.c
@@ -1,8 +1,8 @@
/***************************************************************************
- * Plug-in for TAS5110C1B image sensor connected to the SN9C10x PC Camera *
+ * Plug-in for TAS5110C1B image sensor connected to the SN9C1xx PC Camera *
* Controllers *
* *
- * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
+ * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.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 *
@@ -64,7 +64,7 @@ static int tas5110c1b_set_ctrl(struct sn9c102_device* cam,
static int tas5110c1b_set_crop(struct sn9c102_device* cam,
const struct v4l2_rect* rect)
{
- struct sn9c102_sensor* s = &tas5110c1b;
+ struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
int err = 0;
u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 69,
v_start = (u8)(rect->top - s->cropcap.bounds.top) + 9;
@@ -98,6 +98,7 @@ static int tas5110c1b_set_pix_format(struct sn9c102_device* cam,
static struct sn9c102_sensor tas5110c1b = {
.name = "TAS5110C1B",
.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
+ .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103,
.sysfs_ops = SN9C102_I2C_WRITE,
.frequency = SN9C102_I2C_100KHZ,
.interface = SN9C102_I2C_3WIRES,
@@ -145,6 +146,7 @@ int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam)
const struct usb_device_id tas5110c1b_id_table[] = {
{ USB_DEVICE(0x0c45, 0x6001), },
{ USB_DEVICE(0x0c45, 0x6005), },
+ { USB_DEVICE(0x0c45, 0x6007), },
{ USB_DEVICE(0x0c45, 0x60ab), },
{ }
};
diff --git a/drivers/media/video/sn9c102/sn9c102_tas5130d1b.c b/drivers/media/video/sn9c102/sn9c102_tas5130d1b.c
index 9ecb09032b6..cb1b318bc1f 100644
--- a/drivers/media/video/sn9c102/sn9c102_tas5130d1b.c
+++ b/drivers/media/video/sn9c102/sn9c102_tas5130d1b.c
@@ -1,8 +1,8 @@
/***************************************************************************
- * Plug-in for TAS5130D1B image sensor connected to the SN9C10x PC Camera *
+ * Plug-in for TAS5130D1B image sensor connected to the SN9C1xx PC Camera *
* Controllers *
* *
- * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
+ * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.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 *
@@ -65,7 +65,7 @@ static int tas5130d1b_set_ctrl(struct sn9c102_device* cam,
static int tas5130d1b_set_crop(struct sn9c102_device* cam,
const struct v4l2_rect* rect)
{
- struct sn9c102_sensor* s = &tas5130d1b;
+ struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 104,
v_start = (u8)(rect->top - s->cropcap.bounds.top) + 12;
int err = 0;
@@ -99,6 +99,7 @@ static int tas5130d1b_set_pix_format(struct sn9c102_device* cam,
static struct sn9c102_sensor tas5130d1b = {
.name = "TAS5130D1B",
.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
+ .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103,
.sysfs_ops = SN9C102_I2C_WRITE,
.frequency = SN9C102_I2C_100KHZ,
.interface = SN9C102_I2C_3WIRES,
@@ -154,6 +155,7 @@ static struct sn9c102_sensor tas5130d1b = {
int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam)
{
const struct usb_device_id tas5130d1b_id_table[] = {
+ { USB_DEVICE(0x0c45, 0x6024), },
{ USB_DEVICE(0x0c45, 0x6025), },
{ USB_DEVICE(0x0c45, 0x60aa), },
{ }
diff --git a/drivers/media/video/stradis.c b/drivers/media/video/stradis.c
index 525d81288d5..3e736be5de8 100644
--- a/drivers/media/video/stradis.c
+++ b/drivers/media/video/stradis.c
@@ -1901,7 +1901,7 @@ static int saa_release(struct inode *inode, struct file *file)
return 0;
}
-static struct file_operations saa_fops = {
+static const struct file_operations saa_fops = {
.owner = THIS_MODULE,
.open = saa_open,
.release = saa_release,
diff --git a/drivers/media/video/stv680.c b/drivers/media/video/stv680.c
index a1ec3aca3f9..bf3aa8d2d57 100644
--- a/drivers/media/video/stv680.c
+++ b/drivers/media/video/stv680.c
@@ -1380,7 +1380,7 @@ static ssize_t stv680_read (struct file *file, char __user *buf,
return realcount;
} /* stv680_read */
-static struct file_operations stv680_fops = {
+static const struct file_operations stv680_fops = {
.owner = THIS_MODULE,
.open = stv_open,
.release = stv_close,
diff --git a/drivers/media/video/tda7432.c b/drivers/media/video/tda7432.c
index 78e043ac9ea..d1ccc064206 100644
--- a/drivers/media/video/tda7432.c
+++ b/drivers/media/video/tda7432.c
@@ -38,7 +38,6 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/delay.h>
diff --git a/drivers/media/video/tda9875.c b/drivers/media/video/tda9875.c
index 827633b3bb4..00f0e8b6e03 100644
--- a/drivers/media/video/tda9875.c
+++ b/drivers/media/video/tda9875.c
@@ -19,7 +19,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/delay.h>
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c
index ee4a493032d..7be73e3763d 100644
--- a/drivers/media/video/tuner-core.c
+++ b/drivers/media/video/tuner-core.c
@@ -7,7 +7,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/delay.h>
diff --git a/drivers/media/video/tvmixer.c b/drivers/media/video/tvmixer.c
index 1654576de10..3ae5a9cd2e2 100644
--- a/drivers/media/video/tvmixer.c
+++ b/drivers/media/video/tvmixer.c
@@ -4,7 +4,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/delay.h>
@@ -213,8 +212,7 @@ static int tvmixer_release(struct inode *inode, struct file *file)
return -ENODEV;
}
- if (client->adapter->owner)
- module_put(client->adapter->owner);
+ module_put(client->adapter->owner);
return 0;
}
@@ -228,7 +226,7 @@ static struct i2c_driver driver = {
.detach_client = tvmixer_clients,
};
-static struct file_operations tvmixer_fops = {
+static const struct file_operations tvmixer_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.ioctl = tvmixer_ioctl,
diff --git a/drivers/media/video/tvp5150.c b/drivers/media/video/tvp5150.c
index bc0a4fc27b2..886b5df7c9d 100644
--- a/drivers/media/video/tvp5150.c
+++ b/drivers/media/video/tvp5150.c
@@ -950,17 +950,8 @@ static int tvp5150_command(struct i2c_client *c,
}
#ifdef CONFIG_VIDEO_ADV_DEBUG
- case VIDIOC_INT_G_REGISTER:
- {
- struct v4l2_register *reg = arg;
-
- if (reg->i2c_id != I2C_DRIVERID_TVP5150)
- return -EINVAL;
- reg->val = tvp5150_read(c, reg->reg & 0xff);
- break;
- }
-
- case VIDIOC_INT_S_REGISTER:
+ case VIDIOC_DBG_G_REGISTER:
+ case VIDIOC_DBG_S_REGISTER:
{
struct v4l2_register *reg = arg;
@@ -968,7 +959,10 @@ static int tvp5150_command(struct i2c_client *c,
return -EINVAL;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- tvp5150_write(c, reg->reg & 0xff, reg->val & 0xff);
+ if (cmd == VIDIOC_DBG_G_REGISTER)
+ reg->val = tvp5150_read(c, reg->reg & 0xff);
+ else
+ tvp5150_write(c, reg->reg & 0xff, reg->val & 0xff);
break;
}
#endif
diff --git a/drivers/media/video/upd64031a.c b/drivers/media/video/upd64031a.c
index fc52201d607..b3b5fd536dc 100644
--- a/drivers/media/video/upd64031a.c
+++ b/drivers/media/video/upd64031a.c
@@ -162,27 +162,19 @@ static int upd64031a_command(struct i2c_client *client, unsigned int cmd, void *
break;
#ifdef CONFIG_VIDEO_ADV_DEBUG
- case VIDIOC_INT_G_REGISTER:
+ case VIDIOC_DBG_G_REGISTER:
+ case VIDIOC_DBG_S_REGISTER:
{
struct v4l2_register *reg = arg;
if (reg->i2c_id != I2C_DRIVERID_UPD64031A)
return -EINVAL;
- reg->val = upd64031a_read(client, reg->reg & 0xff);
- break;
- }
-
- case VIDIOC_INT_S_REGISTER:
- {
- struct v4l2_register *reg = arg;
- u8 addr = reg->reg & 0xff;
- u8 val = reg->val & 0xff;
-
- if (reg->i2c_id != I2C_DRIVERID_UPD64031A)
- return -EINVAL;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- upd64031a_write(client, addr, val);
+ if (cmd == VIDIOC_DBG_G_REGISTER)
+ reg->val = upd64031a_read(client, reg->reg & 0xff);
+ else
+ upd64031a_write(client, reg->reg & 0xff, reg->val & 0xff);
break;
}
#endif
diff --git a/drivers/media/video/upd64083.c b/drivers/media/video/upd64083.c
index c3a7ffe5c26..8852903e7a9 100644
--- a/drivers/media/video/upd64083.c
+++ b/drivers/media/video/upd64083.c
@@ -139,27 +139,19 @@ static int upd64083_command(struct i2c_client *client, unsigned int cmd, void *a
break;
#ifdef CONFIG_VIDEO_ADV_DEBUG
- case VIDIOC_INT_G_REGISTER:
+ case VIDIOC_DBG_G_REGISTER:
+ case VIDIOC_DBG_S_REGISTER:
{
struct v4l2_register *reg = arg;
if (reg->i2c_id != I2C_DRIVERID_UPD64083)
return -EINVAL;
- reg->val = upd64083_read(client, reg->reg & 0xff);
- break;
- }
-
- case VIDIOC_INT_S_REGISTER:
- {
- struct v4l2_register *reg = arg;
- u8 addr = reg->reg & 0xff;
- u8 val = reg->val & 0xff;
-
- if (reg->i2c_id != I2C_DRIVERID_UPD64083)
- return -EINVAL;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- upd64083_write(client, addr, val);
+ if (cmd == VIDIOC_DBG_G_REGISTER)
+ reg->val = upd64083_read(client, reg->reg & 0xff);
+ else
+ upd64083_write(client, reg->reg & 0xff, reg->val & 0xff);
break;
}
#endif
diff --git a/drivers/media/video/usbvideo/ibmcam.c b/drivers/media/video/usbvideo/ibmcam.c
index 76f771b6a32..14db95e10cf 100644
--- a/drivers/media/video/usbvideo/ibmcam.c
+++ b/drivers/media/video/usbvideo/ibmcam.c
@@ -15,7 +15,6 @@
*/
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/module.h>
#include <linux/init.h>
diff --git a/drivers/media/video/usbvideo/ultracam.c b/drivers/media/video/usbvideo/ultracam.c
index 10c58b4a2e5..95453c108d4 100644
--- a/drivers/media/video/usbvideo/ultracam.c
+++ b/drivers/media/video/usbvideo/ultracam.c
@@ -6,7 +6,6 @@
*/
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/module.h>
#include <linux/init.h>
diff --git a/drivers/media/video/usbvideo/usbvideo.c b/drivers/media/video/usbvideo/usbvideo.c
index b560c9d7c51..d34d8c8b737 100644
--- a/drivers/media/video/usbvideo/usbvideo.c
+++ b/drivers/media/video/usbvideo/usbvideo.c
@@ -945,7 +945,7 @@ static int usbvideo_find_struct(struct usbvideo *cams)
return rv;
}
-static struct file_operations usbvideo_fops = {
+static const struct file_operations usbvideo_fops = {
.owner = THIS_MODULE,
.open = usbvideo_v4l_open,
.release =usbvideo_v4l_close,
diff --git a/drivers/media/video/usbvideo/vicam.c b/drivers/media/video/usbvideo/vicam.c
index 08f9559a6bf..876fd276824 100644
--- a/drivers/media/video/usbvideo/vicam.c
+++ b/drivers/media/video/usbvideo/vicam.c
@@ -1234,7 +1234,7 @@ static inline void vicam_create_proc_entry(struct vicam_camera *cam) { }
static inline void vicam_destroy_proc_entry(void *ptr) { }
#endif
-static struct file_operations vicam_fops = {
+static const struct file_operations vicam_fops = {
.owner = THIS_MODULE,
.open = vicam_open,
.release = vicam_close,
diff --git a/drivers/media/video/usbvision/Kconfig b/drivers/media/video/usbvision/Kconfig
index fc24ef05b3f..c43a5d89909 100644
--- a/drivers/media/video/usbvision/Kconfig
+++ b/drivers/media/video/usbvision/Kconfig
@@ -1,6 +1,6 @@
config VIDEO_USBVISION
tristate "USB video devices based on Nogatech NT1003/1004/1005"
- depends on I2C && VIDEO_V4L2
+ depends on I2C && VIDEO_V4L2 && USB
select VIDEO_TUNER
select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO
---help---
diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c
index a807d971e27..f2154dc072e 100644
--- a/drivers/media/video/usbvision/usbvision-core.c
+++ b/drivers/media/video/usbvision/usbvision-core.c
@@ -24,7 +24,6 @@
*/
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/list.h>
#include <linux/timer.h>
#include <linux/slab.h>
@@ -139,7 +138,7 @@ static void *usbvision_rvmalloc(unsigned long size)
return mem;
}
-void usbvision_rvfree(void *mem, unsigned long size)
+static void usbvision_rvfree(void *mem, unsigned long size)
{
unsigned long adr;
@@ -1853,28 +1852,33 @@ int usbvision_set_output(struct usb_usbvision *usbvision, int width,
/*
* usbvision_frames_alloc
- * allocate the maximum frames this driver can manage
+ * allocate the required frames
*/
-int usbvision_frames_alloc(struct usb_usbvision *usbvision)
+int usbvision_frames_alloc(struct usb_usbvision *usbvision, int number_of_frames)
{
int i;
- /* Allocate memory for the frame buffers */
- usbvision->max_frame_size = MAX_FRAME_SIZE;
- usbvision->fbuf_size = USBVISION_NUMFRAMES * usbvision->max_frame_size;
- usbvision->fbuf = usbvision_rvmalloc(usbvision->fbuf_size);
+ /*needs to be page aligned cause the buffers can be mapped individually! */
+ usbvision->max_frame_size = PAGE_ALIGN(usbvision->curwidth *
+ usbvision->curheight *
+ usbvision->palette.bytes_per_pixel);
- if(usbvision->fbuf == NULL) {
- err("%s: unable to allocate %d bytes for fbuf ",
- __FUNCTION__, usbvision->fbuf_size);
- return -ENOMEM;
+ /* Try to do my best to allocate the frames the user want in the remaining memory */
+ usbvision->num_frames = number_of_frames;
+ while (usbvision->num_frames > 0) {
+ usbvision->fbuf_size = usbvision->num_frames * usbvision->max_frame_size;
+ if((usbvision->fbuf = usbvision_rvmalloc(usbvision->fbuf_size))) {
+ break;
+ }
+ usbvision->num_frames--;
}
+
spin_lock_init(&usbvision->queue_lock);
init_waitqueue_head(&usbvision->wait_frame);
init_waitqueue_head(&usbvision->wait_stream);
/* Allocate all buffers */
- for (i = 0; i < USBVISION_NUMFRAMES; i++) {
+ for (i = 0; i < usbvision->num_frames; i++) {
usbvision->frame[i].index = i;
usbvision->frame[i].grabstate = FrameState_Unused;
usbvision->frame[i].data = usbvision->fbuf +
@@ -1888,7 +1892,8 @@ int usbvision_frames_alloc(struct usb_usbvision *usbvision)
usbvision->frame[i].height = usbvision->curheight;
usbvision->frame[i].bytes_read = 0;
}
- return 0;
+ PDEBUG(DBG_FUNC, "allocated %d frames (%d bytes per frame)",usbvision->num_frames,usbvision->max_frame_size);
+ return usbvision->num_frames;
}
/*
@@ -1898,9 +1903,13 @@ int usbvision_frames_alloc(struct usb_usbvision *usbvision)
void usbvision_frames_free(struct usb_usbvision *usbvision)
{
/* Have to free all that memory */
+ PDEBUG(DBG_FUNC, "free %d frames",usbvision->num_frames);
+
if (usbvision->fbuf != NULL) {
usbvision_rvfree(usbvision->fbuf, usbvision->fbuf_size);
usbvision->fbuf = NULL;
+
+ usbvision->num_frames = 0;
}
}
/*
@@ -2352,6 +2361,32 @@ int usbvision_setup(struct usb_usbvision *usbvision,int format)
return USBVISION_IS_OPERATIONAL(usbvision);
}
+int usbvision_set_alternate(struct usb_usbvision *dev)
+{
+ int errCode, prev_alt = dev->ifaceAlt;
+ int i;
+
+ dev->ifaceAlt=0;
+ for(i=0;i< dev->num_alt; i++)
+ if(dev->alt_max_pkt_size[i]>dev->alt_max_pkt_size[dev->ifaceAlt])
+ dev->ifaceAlt=i;
+
+ if (dev->ifaceAlt != prev_alt) {
+ dev->isocPacketSize = dev->alt_max_pkt_size[dev->ifaceAlt];
+ PDEBUG(DBG_FUNC,"setting alternate %d with wMaxPacketSize=%u", dev->ifaceAlt,dev->isocPacketSize);
+ errCode = usb_set_interface(dev->dev, dev->iface, dev->ifaceAlt);
+ if (errCode < 0) {
+ err ("cannot change alternate number to %d (error=%i)",
+ dev->ifaceAlt, errCode);
+ return errCode;
+ }
+ }
+
+ PDEBUG(DBG_ISOC, "ISO Packet Length:%d", dev->isocPacketSize);
+
+ return 0;
+}
+
/*
* usbvision_init_isoc()
*
@@ -2369,15 +2404,13 @@ int usbvision_init_isoc(struct usb_usbvision *usbvision)
scratch_reset(usbvision);
/* Alternate interface 1 is is the biggest frame size */
- errCode = usb_set_interface(dev, usbvision->iface, usbvision->ifaceAltActive);
+ errCode = usbvision_set_alternate(usbvision);
if (errCode < 0) {
usbvision->last_error = errCode;
return -EBUSY;
}
regValue = (16 - usbvision_read_reg(usbvision, USBVISION_ALTER_REG)) & 0x0F;
- usbvision->isocPacketSize = (regValue == 0) ? 0 : (regValue * 64) - 1;
- PDEBUG(DBG_ISOC, "ISO Packet Length:%d", usbvision->isocPacketSize);
usbvision->usb_bandwidth = regValue >> 1;
PDEBUG(DBG_ISOC, "USB Bandwidth Usage: %dMbit/Sec", usbvision->usb_bandwidth);
@@ -2463,8 +2496,9 @@ void usbvision_stop_isoc(struct usb_usbvision *usbvision)
if (!usbvision->remove_pending) {
/* Set packet size to 0 */
+ usbvision->ifaceAlt=0;
errCode = usb_set_interface(usbvision->dev, usbvision->iface,
- usbvision->ifaceAltInactive);
+ usbvision->ifaceAlt);
if (errCode < 0) {
err("%s: usb_set_interface() failed: error %d", __FUNCTION__, errCode);
usbvision->last_error = errCode;
@@ -2491,6 +2525,7 @@ int usbvision_muxsel(struct usb_usbvision *usbvision, int channel)
RESTRICT_TO_RANGE(channel, 0, usbvision->video_inputs);
usbvision->ctl_input = channel;
route.input = SAA7115_COMPOSITE1;
+ route.output = 0;
call_i2c_clients(usbvision, VIDIOC_INT_S_VIDEO_ROUTING,&route);
call_i2c_clients(usbvision, VIDIOC_S_INPUT, &usbvision->ctl_input);
diff --git a/drivers/media/video/usbvision/usbvision-i2c.c b/drivers/media/video/usbvision/usbvision-i2c.c
index 858252c1508..609e1fd9c78 100644
--- a/drivers/media/video/usbvision/usbvision-i2c.c
+++ b/drivers/media/video/usbvision/usbvision-i2c.c
@@ -34,7 +34,6 @@
#include <asm/uaccess.h>
#include <linux/ioport.h>
#include <linux/errno.h>
-#include <linux/sched.h>
#include <linux/usb.h>
#include <linux/i2c.h>
#include "usbvision.h"
@@ -258,6 +257,7 @@ int usbvision_init_i2c(struct usb_usbvision *usbvision)
sprintf(usbvision->i2c_adap.name + strlen(usbvision->i2c_adap.name),
" #%d", usbvision->vdev->minor & 0x1f);
PDEBUG(DBG_I2C,"Adaptername: %s", usbvision->i2c_adap.name);
+ usbvision->i2c_adap.dev.parent = &usbvision->dev->dev;
i2c_set_adapdata(&usbvision->i2c_adap, usbvision);
i2c_set_clientdata(&usbvision->i2c_client, usbvision);
diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c
index 7243337b771..ae5f42562c0 100644
--- a/drivers/media/video/usbvision/usbvision-video.c
+++ b/drivers/media/video/usbvision/usbvision-video.c
@@ -46,7 +46,6 @@
#include <linux/version.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/list.h>
#include <linux/timer.h>
#include <linux/slab.h>
@@ -231,7 +230,7 @@ static ssize_t show_hue(struct class_device *cd, char *buf)
ctrl.value = 0;
if(usbvision->user)
call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl);
- return sprintf(buf, "%d\n", ctrl.value >> 8);
+ return sprintf(buf, "%d\n", ctrl.value);
}
static CLASS_DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL);
@@ -244,7 +243,7 @@ static ssize_t show_contrast(struct class_device *cd, char *buf)
ctrl.value = 0;
if(usbvision->user)
call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl);
- return sprintf(buf, "%d\n", ctrl.value >> 8);
+ return sprintf(buf, "%d\n", ctrl.value);
}
static CLASS_DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL);
@@ -257,7 +256,7 @@ static ssize_t show_brightness(struct class_device *cd, char *buf)
ctrl.value = 0;
if(usbvision->user)
call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl);
- return sprintf(buf, "%d\n", ctrl.value >> 8);
+ return sprintf(buf, "%d\n", ctrl.value);
}
static CLASS_DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL);
@@ -270,7 +269,7 @@ static ssize_t show_saturation(struct class_device *cd, char *buf)
ctrl.value = 0;
if(usbvision->user)
call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl);
- return sprintf(buf, "%d\n", ctrl.value >> 8);
+ return sprintf(buf, "%d\n", ctrl.value);
}
static CLASS_DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL);
@@ -392,19 +391,14 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file)
if (usbvision->user)
errCode = -EBUSY;
else {
- /* Allocate memory for the frame buffers */
- errCode = usbvision_frames_alloc(usbvision);
- if(!errCode) {
- /* Allocate memory for the scratch ring buffer */
- errCode = usbvision_scratch_alloc(usbvision);
- if ((!errCode) && (isocMode==ISOC_MODE_COMPRESS)) {
- /* Allocate intermediate decompression buffers only if needed */
- errCode = usbvision_decompress_alloc(usbvision);
- }
+ /* Allocate memory for the scratch ring buffer */
+ errCode = usbvision_scratch_alloc(usbvision);
+ if (isocMode==ISOC_MODE_COMPRESS) {
+ /* Allocate intermediate decompression buffers only if needed */
+ errCode = usbvision_decompress_alloc(usbvision);
}
if (errCode) {
/* Deallocate all buffers if trouble */
- usbvision_frames_free(usbvision);
usbvision_scratch_free(usbvision);
usbvision_decompress_free(usbvision);
}
@@ -477,6 +471,7 @@ static int usbvision_v4l2_close(struct inode *inode, struct file *file)
usbvision_decompress_free(usbvision);
usbvision_frames_free(usbvision);
+ usbvision_empty_framequeues(usbvision);
usbvision_scratch_free(usbvision);
usbvision->user--;
@@ -490,7 +485,7 @@ static int usbvision_v4l2_close(struct inode *inode, struct file *file)
up(&usbvision->lock);
if (usbvision->remove_pending) {
- info("%s: Final disconnect", __FUNCTION__);
+ printk(KERN_INFO "%s: Final disconnect\n", __FUNCTION__);
usbvision_release(usbvision);
}
@@ -520,27 +515,8 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file,
#ifdef CONFIG_VIDEO_ADV_DEBUG
/* ioctls to allow direct acces to the NT100x registers */
- case VIDIOC_INT_G_REGISTER:
- {
- struct v4l2_register *reg = arg;
- int errCode;
-
- if (reg->i2c_id != 0)
- return -EINVAL;
- /* NT100x has a 8-bit register space */
- errCode = usbvision_read_reg(usbvision, reg->reg&0xff);
- if (errCode < 0) {
- err("%s: VIDIOC_INT_G_REGISTER failed: error %d", __FUNCTION__, errCode);
- }
- else {
- reg->val=(unsigned char)errCode;
- PDEBUG(DBG_IOCTL, "VIDIOC_INT_G_REGISTER reg=0x%02X, value=0x%02X",
- (unsigned int)reg->reg, reg->val);
- errCode = 0; // No error
- }
- return errCode;
- }
- case VIDIOC_INT_S_REGISTER:
+ case VIDIOC_DBG_G_REGISTER:
+ case VIDIOC_DBG_S_REGISTER:
{
struct v4l2_register *reg = arg;
int errCode;
@@ -549,15 +525,22 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file,
return -EINVAL;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- errCode = usbvision_write_reg(usbvision, reg->reg&0xff, reg->val);
+ /* NT100x has a 8-bit register space */
+ if (cmd == VIDIOC_DBG_G_REGISTER)
+ errCode = usbvision_read_reg(usbvision, reg->reg&0xff);
+ else
+ errCode = usbvision_write_reg(usbvision, reg->reg&0xff, reg->val);
if (errCode < 0) {
- err("%s: VIDIOC_INT_S_REGISTER failed: error %d", __FUNCTION__, errCode);
- }
- else {
- PDEBUG(DBG_IOCTL, "VIDIOC_INT_S_REGISTER reg=0x%02X, value=0x%02X",
- (unsigned int)reg->reg, reg->val);
- errCode = 0;
+ err("%s: VIDIOC_DBG_%c_REGISTER failed: error %d", __FUNCTION__,
+ cmd == VIDIOC_DBG_G_REGISTER ? 'G' : 'S', errCode);
+ return errCode;
}
+ if (cmd == VIDIOC_DBG_S_REGISTER)
+ reg->val = (u8)errCode;
+
+ PDEBUG(DBG_IOCTL, "VIDIOC_DBG_%c_REGISTER reg=0x%02X, value=0x%02X",
+ cmd == VIDIOC_DBG_G_REGISTER ? 'G' : 'S',
+ (unsigned int)reg->reg, reg->val);
return 0;
}
#endif
@@ -793,8 +776,8 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file,
case VIDIOC_G_CTRL:
{
struct v4l2_control *ctrl = arg;
- PDEBUG(DBG_IOCTL,"VIDIOC_G_CTRL id=%x value=%x",ctrl->id,ctrl->value);
call_i2c_clients(usbvision, VIDIOC_G_CTRL, ctrl);
+ PDEBUG(DBG_IOCTL,"VIDIOC_G_CTRL id=%x value=%x",ctrl->id,ctrl->value);
return 0;
}
case VIDIOC_S_CTRL:
@@ -822,7 +805,9 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file,
return ret;
}
+ usbvision_frames_free(usbvision);
usbvision_empty_framequeues(usbvision);
+ vr->count = usbvision_frames_alloc(usbvision,vr->count);
usbvision->curFrame = NULL;
@@ -839,7 +824,7 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file,
if(vb->type != V4L2_CAP_VIDEO_CAPTURE) {
return -EINVAL;
}
- if(vb->index>=USBVISION_NUMFRAMES) {
+ if(vb->index>=usbvision->num_frames) {
return -EINVAL;
}
// Updating the corresponding frame state
@@ -853,7 +838,7 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file,
vb->flags |= V4L2_BUF_FLAG_MAPPED;
vb->memory = V4L2_MEMORY_MMAP;
- vb->m.offset = vb->index*usbvision->max_frame_size;
+ vb->m.offset = vb->index*PAGE_ALIGN(usbvision->max_frame_size);
vb->memory = V4L2_MEMORY_MMAP;
vb->field = V4L2_FIELD_NONE;
@@ -872,7 +857,7 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file,
if(vb->type != V4L2_CAP_VIDEO_CAPTURE) {
return -EINVAL;
}
- if(vb->index>=USBVISION_NUMFRAMES) {
+ if(vb->index>=usbvision->num_frames) {
return -EINVAL;
}
@@ -1042,6 +1027,7 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file,
if ((ret = usbvision_stream_interrupt(usbvision)))
return ret;
}
+ usbvision_frames_free(usbvision);
usbvision_empty_framequeues(usbvision);
usbvision->curFrame = NULL;
@@ -1072,7 +1058,7 @@ static int usbvision_v4l2_ioctl(struct inode *inode, struct file *file,
}
-static ssize_t usbvision_v4l2_read(struct file *file, char *buf,
+static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
struct video_device *dev = video_devdata(file);
@@ -1088,12 +1074,24 @@ static ssize_t usbvision_v4l2_read(struct file *file, char *buf,
if (!USBVISION_IS_OPERATIONAL(usbvision) || (buf == NULL))
return -EFAULT;
- /* no stream is running, make it running ! */
- usbvision->streaming = Stream_On;
- call_i2c_clients(usbvision,VIDIOC_STREAMON , NULL);
+ /* This entry point is compatible with the mmap routines so that a user can do either
+ VIDIOC_QBUF/VIDIOC_DQBUF to get frames or call read on the device. */
+ if(!usbvision->num_frames) {
+ /* First, allocate some frames to work with if this has not been done with
+ VIDIOC_REQBUF */
+ usbvision_frames_free(usbvision);
+ usbvision_empty_framequeues(usbvision);
+ usbvision_frames_alloc(usbvision,USBVISION_NUMFRAMES);
+ }
+
+ if(usbvision->streaming != Stream_On) {
+ /* no stream is running, make it running ! */
+ usbvision->streaming = Stream_On;
+ call_i2c_clients(usbvision,VIDIOC_STREAMON , NULL);
+ }
- /* First, enqueue as many frames as possible (like a user of VIDIOC_QBUF would do) */
- for(i=0;i<USBVISION_NUMFRAMES;i++) {
+ /* Then, enqueue as many frames as possible (like a user of VIDIOC_QBUF would do) */
+ for(i=0;i<usbvision->num_frames;i++) {
frame = &usbvision->frame[i];
if(frame->grabstate == FrameState_Unused) {
/* Mark it as ready and enqueue frame */
@@ -1170,6 +1168,8 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
struct video_device *dev = video_devdata(file);
struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
+ PDEBUG(DBG_MMAP, "mmap");
+
down(&usbvision->lock);
if (!USBVISION_IS_OPERATIONAL(usbvision)) {
@@ -1178,16 +1178,16 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
}
if (!(vma->vm_flags & VM_WRITE) ||
- size != PAGE_ALIGN(usbvision->curwidth*usbvision->curheight*usbvision->palette.bytes_per_pixel)) {
+ size != PAGE_ALIGN(usbvision->max_frame_size)) {
up(&usbvision->lock);
return -EINVAL;
}
- for (i = 0; i < USBVISION_NUMFRAMES; i++) {
- if (((usbvision->max_frame_size*i) >> PAGE_SHIFT) == vma->vm_pgoff)
+ for (i = 0; i < usbvision->num_frames; i++) {
+ if (((PAGE_ALIGN(usbvision->max_frame_size)*i) >> PAGE_SHIFT) == vma->vm_pgoff)
break;
}
- if (i == USBVISION_NUMFRAMES) {
+ if (i == usbvision->num_frames) {
PDEBUG(DBG_MMAP, "mmap: user supplied mapping address is out of range");
up(&usbvision->lock);
return -EINVAL;
@@ -1243,6 +1243,13 @@ static int usbvision_radio_open(struct inode *inode, struct file *file)
}
}
+ /* Alternate interface 1 is is the biggest frame size */
+ errCode = usbvision_set_alternate(usbvision);
+ if (errCode < 0) {
+ usbvision->last_error = errCode;
+ return -EBUSY;
+ }
+
// If so far no errors then we shall start the radio
usbvision->radio = 1;
call_i2c_clients(usbvision,AUDC_SET_RADIO,&usbvision->tuner_type);
@@ -1274,6 +1281,11 @@ static int usbvision_radio_close(struct inode *inode, struct file *file)
down(&usbvision->lock);
+ /* Set packet size to 0 */
+ usbvision->ifaceAlt=0;
+ errCode = usb_set_interface(usbvision->dev, usbvision->iface,
+ usbvision->ifaceAlt);
+
usbvision_audio_off(usbvision);
usbvision->radio=0;
usbvision->user--;
@@ -1286,7 +1298,7 @@ static int usbvision_radio_close(struct inode *inode, struct file *file)
up(&usbvision->lock);
if (usbvision->remove_pending) {
- info("%s: Final disconnect", __FUNCTION__);
+ printk(KERN_INFO "%s: Final disconnect\n", __FUNCTION__);
usbvision_release(usbvision);
}
@@ -1475,7 +1487,7 @@ static int usbvision_vbi_ioctl(struct inode *inode, struct file *file,
//
// Video template
-static struct file_operations usbvision_fops = {
+static const struct file_operations usbvision_fops = {
.owner = THIS_MODULE,
.open = usbvision_v4l2_open,
.release = usbvision_v4l2_close,
@@ -1496,7 +1508,7 @@ static struct video_device usbvision_video_template = {
// Radio template
-static struct file_operations usbvision_radio_fops = {
+static const struct file_operations usbvision_radio_fops = {
.owner = THIS_MODULE,
.open = usbvision_radio_open,
.release = usbvision_radio_close,
@@ -1517,7 +1529,7 @@ static struct video_device usbvision_radio_template=
// vbi template
-static struct file_operations usbvision_vbi_fops = {
+static const struct file_operations usbvision_vbi_fops = {
.owner = THIS_MODULE,
.open = usbvision_vbi_open,
.release = usbvision_vbi_close,
@@ -1612,7 +1624,7 @@ static int __devinit usbvision_register_video(struct usb_usbvision *usbvision)
if (video_register_device(usbvision->vdev, VFL_TYPE_GRABBER, video_nr)<0) {
goto err_exit;
}
- info("USBVision[%d]: registered USBVision Video device /dev/video%d [v4l2]", usbvision->nr,usbvision->vdev->minor & 0x1f);
+ printk(KERN_INFO "USBVision[%d]: registered USBVision Video device /dev/video%d [v4l2]\n", usbvision->nr,usbvision->vdev->minor & 0x1f);
// Radio Device:
if (usbvision_device_data[usbvision->DevModel].Radio) {
@@ -1624,7 +1636,7 @@ static int __devinit usbvision_register_video(struct usb_usbvision *usbvision)
if (video_register_device(usbvision->rdev, VFL_TYPE_RADIO, radio_nr)<0) {
goto err_exit;
}
- info("USBVision[%d]: registered USBVision Radio device /dev/radio%d [v4l2]", usbvision->nr, usbvision->rdev->minor & 0x1f);
+ printk(KERN_INFO "USBVision[%d]: registered USBVision Radio device /dev/radio%d [v4l2]\n", usbvision->nr, usbvision->rdev->minor & 0x1f);
}
// vbi Device:
if (usbvision_device_data[usbvision->DevModel].vbi) {
@@ -1635,7 +1647,7 @@ static int __devinit usbvision_register_video(struct usb_usbvision *usbvision)
if (video_register_device(usbvision->vbi, VFL_TYPE_VBI, vbi_nr)<0) {
goto err_exit;
}
- info("USBVision[%d]: registered USBVision VBI device /dev/vbi%d [v4l2] (Not Working Yet!)", usbvision->nr,usbvision->vbi->minor & 0x1f);
+ printk(KERN_INFO "USBVision[%d]: registered USBVision VBI device /dev/vbi%d [v4l2] (Not Working Yet!)\n", usbvision->nr,usbvision->vbi->minor & 0x1f);
}
// all done
return 0;
@@ -1765,15 +1777,17 @@ static void usbvision_configure_video(struct usb_usbvision *usbvision)
*/
static int __devinit usbvision_probe(struct usb_interface *intf, const struct usb_device_id *devid)
{
- struct usb_device *dev = interface_to_usbdev(intf);
+ struct usb_device *dev = usb_get_dev(interface_to_usbdev(intf));
+ struct usb_interface *uif;
__u8 ifnum = intf->altsetting->desc.bInterfaceNumber;
const struct usb_host_interface *interface;
struct usb_usbvision *usbvision = NULL;
const struct usb_endpoint_descriptor *endpoint;
- int model;
+ int model,i;
PDEBUG(DBG_PROBE, "VID=%#04x, PID=%#04x, ifnum=%u",
dev->descriptor.idVendor, dev->descriptor.idProduct, ifnum);
+
/* Is it an USBVISION video dev? */
model = 0;
for(model = 0; usbvision_device_data[model].idVendor; model++) {
@@ -1784,7 +1798,7 @@ static int __devinit usbvision_probe(struct usb_interface *intf, const struct us
continue;
}
- info("%s: %s found", __FUNCTION__, usbvision_device_data[model].ModelString);
+ printk(KERN_INFO "%s: %s found\n", __FUNCTION__, usbvision_device_data[model].ModelString);
break;
}
@@ -1800,7 +1814,7 @@ static int __devinit usbvision_probe(struct usb_interface *intf, const struct us
endpoint = &interface->endpoint[1].desc;
if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_ISOC) {
err("%s: interface %d. has non-ISO endpoint!", __FUNCTION__, ifnum);
- err("%s: Endpoint attribures %d", __FUNCTION__, endpoint->bmAttributes);
+ err("%s: Endpoint attributes %d", __FUNCTION__, endpoint->bmAttributes);
return -ENODEV;
}
if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) {
@@ -1827,6 +1841,28 @@ static int __devinit usbvision_probe(struct usb_interface *intf, const struct us
down(&usbvision->lock);
+ /* compute alternate max packet sizes */
+ uif = dev->actconfig->interface[0];
+
+ usbvision->num_alt=uif->num_altsetting;
+ PDEBUG(DBG_PROBE, "Alternate settings: %i",usbvision->num_alt);
+ usbvision->alt_max_pkt_size = kmalloc(32*
+ usbvision->num_alt,GFP_KERNEL);
+ if (usbvision->alt_max_pkt_size == NULL) {
+ err("usbvision: out of memory!\n");
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < usbvision->num_alt ; i++) {
+ u16 tmp = le16_to_cpu(uif->altsetting[i].endpoint[1].desc.
+ wMaxPacketSize);
+ usbvision->alt_max_pkt_size[i] =
+ (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
+ PDEBUG(DBG_PROBE, "Alternate setting %i, max size= %i",i,
+ usbvision->alt_max_pkt_size[i]);
+ }
+
+
usbvision->nr = usbvision_nr++;
usbvision->have_tuner = usbvision_device_data[model].Tuner;
@@ -1839,8 +1875,7 @@ static int __devinit usbvision_probe(struct usb_interface *intf, const struct us
usbvision->DevModel = model;
usbvision->remove_pending = 0;
usbvision->iface = ifnum;
- usbvision->ifaceAltInactive = 0;
- usbvision->ifaceAltActive = 1;
+ usbvision->ifaceAlt = 0;
usbvision->video_endp = endpoint->bEndpointAddress;
usbvision->isocPacketSize = 0;
usbvision->usb_bandwidth = 0;
@@ -1896,7 +1931,7 @@ static void __devexit usbvision_disconnect(struct usb_interface *intf)
up(&usbvision->lock);
if (usbvision->user) {
- info("%s: In use, disconnect pending", __FUNCTION__);
+ printk(KERN_INFO "%s: In use, disconnect pending\n", __FUNCTION__);
wake_up_interruptible(&usbvision->wait_frame);
wake_up_interruptible(&usbvision->wait_stream);
}
@@ -2062,7 +2097,7 @@ static int __init usbvision_init(void)
errCode = usb_register(&usbvision_driver);
if (errCode == 0) {
- info(DRIVER_DESC " : " USBVISION_VERSION_STRING);
+ printk(KERN_INFO DRIVER_DESC " : " USBVISION_VERSION_STRING "\n");
PDEBUG(DBG_PROBE, "success");
}
return errCode;
diff --git a/drivers/media/video/usbvision/usbvision.h b/drivers/media/video/usbvision/usbvision.h
index e2bcaba9387..ad6afd3e42a 100644
--- a/drivers/media/video/usbvision/usbvision.h
+++ b/drivers/media/video/usbvision/usbvision.h
@@ -33,6 +33,7 @@
#include <linux/list.h>
#include <linux/usb.h>
+#include <linux/i2c.h>
#include <media/v4l2-common.h>
#include <media/tuner.h>
#include <linux/videodev2.h>
@@ -396,8 +397,11 @@ struct usb_usbvision {
/* Device structure */
struct usb_device *dev;
+ /* usb transfer */
+ int num_alt; /* Number of alternative settings */
+ unsigned int *alt_max_pkt_size; /* array of wMaxPacketSize */
unsigned char iface; /* Video interface number */
- unsigned char ifaceAltActive, ifaceAltInactive; /* Alt settings */
+ unsigned char ifaceAlt; /* Alt settings */
unsigned char Vin_Reg2_Preset;
struct semaphore lock;
struct timer_list powerOffTimer;
@@ -421,6 +425,7 @@ struct usb_usbvision {
wait_queue_head_t wait_stream; /* Processes waiting */
struct usbvision_frame *curFrame; // pointer to current frame, set by usbvision_find_header
struct usbvision_frame frame[USBVISION_NUMFRAMES]; // frame buffer
+ int num_frames; // number of frames allocated
struct usbvision_sbuf sbuf[USBVISION_NUMSBUF]; // S buffering
volatile int remove_pending; /* If set then about to exit */
@@ -486,12 +491,11 @@ int usbvision_init_i2c(struct usb_usbvision *usbvision);
void call_i2c_clients(struct usb_usbvision *usbvision, unsigned int cmd,void *arg);
/* defined in usbvision-core.c */
-void usbvision_rvfree(void *mem, unsigned long size);
int usbvision_read_reg(struct usb_usbvision *usbvision, unsigned char reg);
int usbvision_write_reg(struct usb_usbvision *usbvision, unsigned char reg,
unsigned char value);
-int usbvision_frames_alloc(struct usb_usbvision *usbvision);
+int usbvision_frames_alloc(struct usb_usbvision *usbvision, int number_of_frames);
void usbvision_frames_free(struct usb_usbvision *usbvision);
int usbvision_scratch_alloc(struct usb_usbvision *usbvision);
void usbvision_scratch_free(struct usb_usbvision *usbvision);
@@ -502,6 +506,7 @@ int usbvision_setup(struct usb_usbvision *usbvision,int format);
int usbvision_init_isoc(struct usb_usbvision *usbvision);
int usbvision_restart_isoc(struct usb_usbvision *usbvision);
void usbvision_stop_isoc(struct usb_usbvision *usbvision);
+int usbvision_set_alternate(struct usb_usbvision *dev);
int usbvision_set_audio(struct usb_usbvision *usbvision, int AudioChannel);
int usbvision_audio_off(struct usb_usbvision *usbvision);
diff --git a/drivers/media/video/v4l1-compat.c b/drivers/media/video/v4l1-compat.c
index 8a13e595304..d2c1ae0dbfb 100644
--- a/drivers/media/video/v4l1-compat.c
+++ b/drivers/media/video/v4l1-compat.c
@@ -11,7 +11,7 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
- * Author: Bill Dirks <bdirks@pacbell.net>
+ * Author: Bill Dirks <bill@thedirks.org>
* et al.
*
*/
diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
index b87d571e046..ddfd80c5618 100644
--- a/drivers/media/video/v4l2-common.c
+++ b/drivers/media/video/v4l2-common.c
@@ -12,7 +12,7 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
- * Author: Bill Dirks <bdirks@pacbell.net>
+ * Author: Bill Dirks <bill@thedirks.org>
* based on code by Alan Cox, <alan@cymru.net>
*
*/
@@ -47,7 +47,6 @@
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/smp_lock.h>
#include <linux/mm.h>
#include <linux/string.h>
@@ -272,11 +271,6 @@ char *v4l2_type_names[] = {
[V4L2_BUF_TYPE_SLICED_VBI_OUTPUT] = "slicec-vbi-out",
};
-static char *v4l2_memory_names[] = {
- [V4L2_MEMORY_MMAP] = "mmap",
- [V4L2_MEMORY_USERPTR] = "userptr",
- [V4L2_MEMORY_OVERLAY] = "overlay",
-};
#define prt_names(a,arr) (((a)>=0)&&((a)<ARRAY_SIZE(arr)))?arr[a]:"unknown"
@@ -401,9 +395,10 @@ static const char *v4l2_int_ioctls[] = {
[_IOC_NR(TUNER_SET_STANDBY)] = "TUNER_SET_STANDBY",
[_IOC_NR(TDA9887_SET_CONFIG)] = "TDA9887_SET_CONFIG",
+ [_IOC_NR(VIDIOC_DBG_S_REGISTER)] = "VIDIOC_DBG_S_REGISTER",
+ [_IOC_NR(VIDIOC_DBG_G_REGISTER)] = "VIDIOC_DBG_G_REGISTER",
+
[_IOC_NR(VIDIOC_INT_S_TUNER_MODE)] = "VIDIOC_INT_S_TUNER_MODE",
- [_IOC_NR(VIDIOC_INT_S_REGISTER)] = "VIDIOC_INT_S_REGISTER",
- [_IOC_NR(VIDIOC_INT_G_REGISTER)] = "VIDIOC_INT_G_REGISTER",
[_IOC_NR(VIDIOC_INT_RESET)] = "VIDIOC_INT_RESET",
[_IOC_NR(VIDIOC_INT_AUDIO_CLOCK_FREQ)] = "VIDIOC_INT_AUDIO_CLOCK_FREQ",
[_IOC_NR(VIDIOC_INT_DECODE_VBI_LINE)] = "VIDIOC_INT_DECODE_VBI_LINE",
@@ -420,14 +415,6 @@ static const char *v4l2_int_ioctls[] = {
};
#define V4L2_INT_IOCTLS ARRAY_SIZE(v4l2_int_ioctls)
-static void v4l_print_pix_fmt (char *s, struct v4l2_pix_format *fmt)
-{
- printk ("%s: width=%d, height=%d, format=%d, field=%s, "
- "bytesperline=%d sizeimage=%d, colorspace=%d\n", s,
- fmt->width,fmt->height,fmt->pixelformat,
- prt_names(fmt->field,v4l2_field_names),
- fmt->bytesperline,fmt->sizeimage,fmt->colorspace);
-};
/* Common ioctl debug function. This function can be used by
external ioctl messages as well as internal V4L ioctl */
@@ -467,576 +454,6 @@ void v4l_printk_ioctl(unsigned int cmd)
}
}
-/* Common ioctl debug function. This function can be used by
- external ioctl messages as well as internal V4L ioctl and its
- arguments */
-void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg)
-{
- printk(s);
- printk(": ");
- v4l_printk_ioctl(cmd);
- switch (cmd) {
- case VIDIOC_INT_G_CHIP_IDENT:
- {
- enum v4l2_chip_ident *p=arg;
- printk ("%s: chip ident=%d\n", s, *p);
- break;
- }
- case VIDIOC_G_PRIORITY:
- case VIDIOC_S_PRIORITY:
- {
- enum v4l2_priority *p=arg;
- printk ("%s: priority=%d\n", s, *p);
- break;
- }
- case VIDIOC_INT_S_TUNER_MODE:
- {
- enum v4l2_tuner_type *p=arg;
- printk ("%s: tuner type=%d\n", s, *p);
- break;
- }
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- case DECODER_SET_VBI_BYPASS:
- case DECODER_ENABLE_OUTPUT:
- case DECODER_GET_STATUS:
- case DECODER_SET_OUTPUT:
- case DECODER_SET_INPUT:
- case DECODER_SET_GPIO:
- case DECODER_SET_NORM:
- case VIDIOCCAPTURE:
- case VIDIOCSYNC:
- case VIDIOCSWRITEMODE:
-#endif
- case TUNER_SET_TYPE_ADDR:
- case TUNER_SET_STANDBY:
- case TDA9887_SET_CONFIG:
-#ifdef __OLD_VIDIOC_
- case VIDIOC_OVERLAY_OLD:
-#endif
- case VIDIOC_STREAMOFF:
- case VIDIOC_G_OUTPUT:
- case VIDIOC_S_OUTPUT:
- case VIDIOC_STREAMON:
- case VIDIOC_G_INPUT:
- case VIDIOC_OVERLAY:
- case VIDIOC_S_INPUT:
- {
- int *p=arg;
- printk ("%s: value=%d\n", s, *p);
- break;
- }
- case VIDIOC_G_AUDIO:
- case VIDIOC_S_AUDIO:
- case VIDIOC_ENUMAUDIO:
-#ifdef __OLD_VIDIOC_
- case VIDIOC_G_AUDIO_OLD:
-#endif
- {
- struct v4l2_audio *p=arg;
-
- printk ("%s: index=%d, name=%s, capability=%d, mode=%d\n",
- s,p->index, p->name,p->capability, p->mode);
- break;
- }
- case VIDIOC_G_AUDOUT:
- case VIDIOC_S_AUDOUT:
- case VIDIOC_ENUMAUDOUT:
-#ifdef __OLD_VIDIOC_
- case VIDIOC_G_AUDOUT_OLD:
-#endif
- {
- struct v4l2_audioout *p=arg;
- printk ("%s: index=%d, name=%s, capability=%d, mode=%d\n", s,
- p->index, p->name, p->capability,p->mode);
- break;
- }
- case VIDIOC_QBUF:
- case VIDIOC_DQBUF:
- case VIDIOC_QUERYBUF:
- {
- struct v4l2_buffer *p=arg;
- struct v4l2_timecode *tc=&p->timecode;
- printk ("%s: %02ld:%02d:%02d.%08ld index=%d, type=%s, "
- "bytesused=%d, flags=0x%08x, "
- "field=%0d, sequence=%d, memory=%s, offset/userptr=0x%08lx\n",
- s,
- (p->timestamp.tv_sec/3600),
- (int)(p->timestamp.tv_sec/60)%60,
- (int)(p->timestamp.tv_sec%60),
- p->timestamp.tv_usec,
- p->index,
- prt_names(p->type,v4l2_type_names),
- p->bytesused,p->flags,
- p->field,p->sequence,
- prt_names(p->memory,v4l2_memory_names),
- p->m.userptr);
- printk ("%s: timecode= %02d:%02d:%02d type=%d, "
- "flags=0x%08x, frames=%d, userbits=0x%08x\n",
- s,tc->hours,tc->minutes,tc->seconds,
- tc->type, tc->flags, tc->frames, *(__u32 *) tc->userbits);
- break;
- }
- case VIDIOC_QUERYCAP:
- {
- struct v4l2_capability *p=arg;
- printk ("%s: driver=%s, card=%s, bus=%s, version=0x%08x, "
- "capabilities=0x%08x\n", s,
- p->driver,p->card,p->bus_info,
- p->version,
- p->capabilities);
- break;
- }
- case VIDIOC_G_CTRL:
- case VIDIOC_S_CTRL:
-#ifdef __OLD_VIDIOC_
- case VIDIOC_S_CTRL_OLD:
-#endif
- {
- struct v4l2_control *p=arg;
- printk ("%s: id=%d, value=%d\n", s, p->id, p->value);
- break;
- }
- case VIDIOC_G_EXT_CTRLS:
- case VIDIOC_S_EXT_CTRLS:
- case VIDIOC_TRY_EXT_CTRLS:
- {
- struct v4l2_ext_controls *p = arg;
- int i;
-
- printk("%s: ctrl_class=%d, count=%d\n", s, p->ctrl_class, p->count);
- for (i = 0; i < p->count; i++) {
- struct v4l2_ext_control *c = &p->controls[i];
- if (cmd == VIDIOC_G_EXT_CTRLS)
- printk("%s: id=%d\n", s, c->id);
- else
- printk("%s: id=%d, value=%d\n", s, c->id, c->value);
- }
- break;
- }
- case VIDIOC_G_CROP:
- case VIDIOC_S_CROP:
- {
- struct v4l2_crop *p=arg;
- /*FIXME: Should also show rect structs */
- printk ("%s: type=%d\n", s, p->type);
- break;
- }
- case VIDIOC_CROPCAP:
-#ifdef __OLD_VIDIOC_
- case VIDIOC_CROPCAP_OLD:
-#endif
- {
- struct v4l2_cropcap *p=arg;
- /*FIXME: Should also show rect structs */
- printk ("%s: type=%d\n", s, p->type);
- break;
- }
- case VIDIOC_INT_DECODE_VBI_LINE:
- {
- struct v4l2_decode_vbi_line *p=arg;
- printk ("%s: is_second_field=%d, ptr=0x%08lx, line=%d, "
- "type=%d\n", s,
- p->is_second_field,(unsigned long)p->p,p->line,p->type);
- break;
- }
- case VIDIOC_ENUM_FMT:
- {
- struct v4l2_fmtdesc *p=arg;
- printk ("%s: index=%d, type=%d, flags=%d, description=%s,"
- " pixelformat=%d\n", s,
- p->index, p->type, p->flags,p->description,
- p->pixelformat);
-
- break;
- }
- case VIDIOC_G_FMT:
- case VIDIOC_S_FMT:
- case VIDIOC_TRY_FMT:
- {
- struct v4l2_format *p=arg;
- printk ("%s: type=%s\n", s,
- prt_names(p->type,v4l2_type_names));
- switch (p->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- v4l_print_pix_fmt (s, &p->fmt.pix);
- break;
- default:
- break;
- }
- }
- case VIDIOC_G_FBUF:
- case VIDIOC_S_FBUF:
- {
- struct v4l2_framebuffer *p=arg;
- printk ("%s: capability=%d, flags=%d, base=0x%08lx\n", s,
- p->capability,p->flags, (unsigned long)p->base);
- v4l_print_pix_fmt (s, &p->fmt);
- break;
- }
- case VIDIOC_G_FREQUENCY:
- case VIDIOC_S_FREQUENCY:
- {
- struct v4l2_frequency *p=arg;
- printk ("%s: tuner=%d, type=%d, frequency=%d\n", s,
- p->tuner,p->type,p->frequency);
- break;
- }
- case VIDIOC_ENUMINPUT:
- {
- struct v4l2_input *p=arg;
- printk ("%s: index=%d, name=%s, type=%d, audioset=%d, "
- "tuner=%d, std=%Ld, status=%d\n", s,
- p->index,p->name,p->type,p->audioset,
- p->tuner,
- (unsigned long long)p->std,
- p->status);
- break;
- }
- case VIDIOC_G_JPEGCOMP:
- case VIDIOC_S_JPEGCOMP:
- {
- struct v4l2_jpegcompression *p=arg;
- printk ("%s: quality=%d, APPn=%d, APP_len=%d, COM_len=%d,"
- " jpeg_markers=%d\n", s,
- p->quality,p->APPn,p->APP_len,
- p->COM_len,p->jpeg_markers);
- break;
- }
- case VIDIOC_G_MODULATOR:
- case VIDIOC_S_MODULATOR:
- {
- struct v4l2_modulator *p=arg;
- printk ("%s: index=%d, name=%s, capability=%d, rangelow=%d,"
- " rangehigh=%d, txsubchans=%d\n", s,
- p->index, p->name,p->capability,p->rangelow,
- p->rangehigh,p->txsubchans);
- break;
- }
- case VIDIOC_G_MPEGCOMP:
- case VIDIOC_S_MPEGCOMP:
- {
- struct v4l2_mpeg_compression *p=arg;
- /*FIXME: Several fields not shown */
- printk ("%s: ts_pid_pmt=%d, ts_pid_audio=%d, ts_pid_video=%d, "
- "ts_pid_pcr=%d, ps_size=%d, au_sample_rate=%d, "
- "au_pesid=%c, vi_frame_rate=%d, vi_frames_per_gop=%d, "
- "vi_bframes_count=%d, vi_pesid=%c\n", s,
- p->ts_pid_pmt,p->ts_pid_audio, p->ts_pid_video,
- p->ts_pid_pcr, p->ps_size, p->au_sample_rate,
- p->au_pesid, p->vi_frame_rate,
- p->vi_frames_per_gop, p->vi_bframes_count,
- p->vi_pesid);
- break;
- }
- case VIDIOC_ENUMOUTPUT:
- {
- struct v4l2_output *p=arg;
- printk ("%s: index=%d, name=%s,type=%d, audioset=%d, "
- "modulator=%d, std=%Ld\n",
- s,p->index,p->name,p->type,p->audioset,
- p->modulator,
- (unsigned long long)p->std);
- break;
- }
- case VIDIOC_QUERYCTRL:
- {
- struct v4l2_queryctrl *p=arg;
- printk ("%s: id=%d, type=%d, name=%s, min/max=%d/%d,"
- " step=%d, default=%d, flags=0x%08x\n", s,
- p->id,p->type,p->name,p->minimum,p->maximum,
- p->step,p->default_value,p->flags);
- break;
- }
- case VIDIOC_QUERYMENU:
- {
- struct v4l2_querymenu *p=arg;
- printk ("%s: id=%d, index=%d, name=%s\n", s,
- p->id,p->index,p->name);
- break;
- }
- case VIDIOC_INT_G_REGISTER:
- case VIDIOC_INT_S_REGISTER:
- {
- struct v4l2_register *p=arg;
- printk ("%s: i2c_id=%d, reg=%lu, val=%d\n", s,
- p->i2c_id,p->reg,p->val);
-
- break;
- }
- case VIDIOC_REQBUFS:
- {
- struct v4l2_requestbuffers *p=arg;
- printk ("%s: count=%d, type=%s, memory=%s\n", s,
- p->count,
- prt_names(p->type,v4l2_type_names),
- prt_names(p->memory,v4l2_memory_names));
- break;
- }
- case VIDIOC_INT_S_AUDIO_ROUTING:
- case VIDIOC_INT_S_VIDEO_ROUTING:
- case VIDIOC_INT_G_AUDIO_ROUTING:
- case VIDIOC_INT_G_VIDEO_ROUTING:
- {
- struct v4l2_routing *p=arg;
- printk ("%s: input=0x%x, output=0x%x\n", s, p->input, p->output);
- break;
- }
- case VIDIOC_INT_S_CRYSTAL_FREQ:
- {
- struct v4l2_crystal_freq *p=arg;
- printk ("%s: freq=%u, flags=0x%x\n", s, p->freq, p->flags);
- break;
- }
- case VIDIOC_G_SLICED_VBI_CAP:
- {
- struct v4l2_sliced_vbi_cap *p=arg;
- printk ("%s: service_set=%d\n", s,
- p->service_set);
- break;
- }
- case VIDIOC_INT_S_VBI_DATA:
- case VIDIOC_INT_G_VBI_DATA:
- {
- struct v4l2_sliced_vbi_data *p=arg;
- printk ("%s: id=%d, field=%d, line=%d\n", s,
- p->id, p->field, p->line);
- break;
- }
- case VIDIOC_ENUMSTD:
- {
- struct v4l2_standard *p=arg;
- printk ("%s: index=%d, id=%Ld, name=%s, fps=%d/%d, "
- "framelines=%d\n", s, p->index,
- (unsigned long long)p->id, p->name,
- p->frameperiod.numerator,
- p->frameperiod.denominator,
- p->framelines);
-
- break;
- }
- case VIDIOC_G_PARM:
- case VIDIOC_S_PARM:
-#ifdef __OLD_VIDIOC_
- case VIDIOC_S_PARM_OLD:
-#endif
- {
- struct v4l2_streamparm *p=arg;
- printk ("%s: type=%d\n", s, p->type);
-
- break;
- }
- case VIDIOC_G_TUNER:
- case VIDIOC_S_TUNER:
- {
- struct v4l2_tuner *p=arg;
- printk ("%s: index=%d, name=%s, type=%d, capability=%d, "
- "rangelow=%d, rangehigh=%d, signal=%d, afc=%d, "
- "rxsubchans=%d, audmode=%d\n", s,
- p->index, p->name, p->type,
- p->capability, p->rangelow,p->rangehigh,
- p->rxsubchans, p->audmode, p->signal,
- p->afc);
- break;
- }
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- case VIDIOCGVBIFMT:
- case VIDIOCSVBIFMT:
- {
- struct vbi_format *p=arg;
- printk ("%s: sampling_rate=%d, samples_per_line=%d, "
- "sample_format=%d, start=%d/%d, count=%d/%d, flags=%d\n", s,
- p->sampling_rate,p->samples_per_line,
- p->sample_format,p->start[0],p->start[1],
- p->count[0],p->count[1],p->flags);
- break;
- }
- case VIDIOCGAUDIO:
- case VIDIOCSAUDIO:
- {
- struct video_audio *p=arg;
- printk ("%s: audio=%d, volume=%d, bass=%d, treble=%d, "
- "flags=%d, name=%s, mode=%d, balance=%d, step=%d\n",
- s,p->audio,p->volume,p->bass, p->treble,
- p->flags,p->name,p->mode,p->balance,p->step);
- break;
- }
- case VIDIOCGFBUF:
- case VIDIOCSFBUF:
- {
- struct video_buffer *p=arg;
- printk ("%s: base=%08lx, height=%d, width=%d, depth=%d, "
- "bytesperline=%d\n", s,
- (unsigned long) p->base, p->height, p->width,
- p->depth,p->bytesperline);
- break;
- }
- case VIDIOCGCAP:
- {
- struct video_capability *p=arg;
- printk ("%s: name=%s, type=%d, channels=%d, audios=%d, "
- "maxwidth=%d, maxheight=%d, minwidth=%d, minheight=%d\n",
- s,p->name,p->type,p->channels,p->audios,
- p->maxwidth,p->maxheight,p->minwidth,
- p->minheight);
-
- break;
- }
- case VIDIOCGCAPTURE:
- case VIDIOCSCAPTURE:
- {
- struct video_capture *p=arg;
- printk ("%s: x=%d, y=%d, width=%d, height=%d, decimation=%d,"
- " flags=%d\n", s,
- p->x, p->y,p->width, p->height,
- p->decimation,p->flags);
- break;
- }
- case VIDIOCGCHAN:
- case VIDIOCSCHAN:
- {
- struct video_channel *p=arg;
- printk ("%s: channel=%d, name=%s, tuners=%d, flags=%d, "
- "type=%d, norm=%d\n", s,
- p->channel,p->name,p->tuners,
- p->flags,p->type,p->norm);
-
- break;
- }
- case VIDIOCSMICROCODE:
- {
- struct video_code *p=arg;
- printk ("%s: loadwhat=%s, datasize=%d\n", s,
- p->loadwhat,p->datasize);
- break;
- }
- case DECODER_GET_CAPABILITIES:
- {
- struct video_decoder_capability *p=arg;
- printk ("%s: flags=%d, inputs=%d, outputs=%d\n", s,
- p->flags,p->inputs,p->outputs);
- break;
- }
- case DECODER_INIT:
- {
- struct video_decoder_init *p=arg;
- printk ("%s: len=%c\n", s, p->len);
- break;
- }
- case VIDIOCGPLAYINFO:
- {
- struct video_info *p=arg;
- printk ("%s: frame_count=%d, h_size=%d, v_size=%d, "
- "smpte_timecode=%d, picture_type=%d, "
- "temporal_reference=%d, user_data=%s\n", s,
- p->frame_count, p->h_size,
- p->v_size, p->smpte_timecode,
- p->picture_type, p->temporal_reference,
- p->user_data);
- break;
- }
- case VIDIOCKEY:
- {
- struct video_key *p=arg;
- printk ("%s: key=%s, flags=%d\n", s,
- p->key, p->flags);
- break;
- }
- case VIDIOCGMBUF:
- {
- struct video_mbuf *p=arg;
- printk ("%s: size=%d, frames=%d, offsets=0x%08lx\n", s,
- p->size,
- p->frames,
- (unsigned long)p->offsets);
- break;
- }
- case VIDIOCMCAPTURE:
- {
- struct video_mmap *p=arg;
- printk ("%s: frame=%d, height=%d, width=%d, format=%d\n", s,
- p->frame,
- p->height, p->width,
- p->format);
- break;
- }
- case VIDIOCGPICT:
- case VIDIOCSPICT:
- case DECODER_SET_PICTURE:
- {
- struct video_picture *p=arg;
-
- printk ("%s: brightness=%d, hue=%d, colour=%d, contrast=%d,"
- " whiteness=%d, depth=%d, palette=%d\n", s,
- p->brightness, p->hue, p->colour,
- p->contrast, p->whiteness, p->depth,
- p->palette);
- break;
- }
- case VIDIOCSPLAYMODE:
- {
- struct video_play_mode *p=arg;
- printk ("%s: mode=%d, p1=%d, p2=%d\n", s,
- p->mode,p->p1,p->p2);
- break;
- }
- case VIDIOCGTUNER:
- case VIDIOCSTUNER:
- {
- struct video_tuner *p=arg;
- printk ("%s: tuner=%d, name=%s, rangelow=%ld, rangehigh=%ld, "
- "flags=%d, mode=%d, signal=%d\n", s,
- p->tuner, p->name,p->rangelow, p->rangehigh,
- p->flags,p->mode, p->signal);
- break;
- }
- case VIDIOCGUNIT:
- {
- struct video_unit *p=arg;
- printk ("%s: video=%d, vbi=%d, radio=%d, audio=%d, "
- "teletext=%d\n", s,
- p->video,p->vbi,p->radio,p->audio,p->teletext);
- break;
- }
- case VIDIOCGWIN:
- case VIDIOCSWIN:
- {
- struct video_window *p=arg;
- printk ("%s: x=%d, y=%d, width=%d, height=%d, chromakey=%d,"
- " flags=%d, clipcount=%d\n", s,
- p->x, p->y,p->width, p->height,
- p->chromakey,p->flags,
- p->clipcount);
- break;
- }
- case VIDIOCGFREQ:
- case VIDIOCSFREQ:
- {
- unsigned long *p=arg;
- printk ("%s: value=%lu\n", s, *p);
- break;
- }
-#endif
- case VIDIOC_INT_AUDIO_CLOCK_FREQ:
- case VIDIOC_INT_I2S_CLOCK_FREQ:
- case VIDIOC_INT_S_STANDBY:
- case VIDIOC_INT_RESET:
- {
- u32 *p=arg;
-
- printk ("%s: value=%d\n", s, *p);
- break;
- }
- case VIDIOC_G_STD:
- case VIDIOC_S_STD:
- case VIDIOC_QUERYSTD:
- {
- v4l2_std_id *p=arg;
-
- printk ("%s: value=%Lu\n", s, (unsigned long long)*p);
- break;
- }
- }
-}
/* ----------------------------------------------------------------- */
@@ -1545,7 +962,6 @@ EXPORT_SYMBOL(v4l2_prio_check);
EXPORT_SYMBOL(v4l2_field_names);
EXPORT_SYMBOL(v4l2_type_names);
EXPORT_SYMBOL(v4l_printk_ioctl);
-EXPORT_SYMBOL(v4l_printk_ioctl_arg);
EXPORT_SYMBOL(v4l2_ctrl_next);
EXPORT_SYMBOL(v4l2_ctrl_check);
diff --git a/drivers/media/video/video-buf.c b/drivers/media/video/video-buf.c
index 6504a586684..459786ff459 100644
--- a/drivers/media/video/video-buf.c
+++ b/drivers/media/video/video-buf.c
@@ -148,6 +148,8 @@ int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction,
dprintk(1,"init user [0x%lx+0x%lx => %d pages]\n",
data,size,dma->nr_pages);
+ dma->varea = (void *) data;
+
down_read(&current->mm->mmap_sem);
err = get_user_pages(current,current->mm,
data & PAGE_MASK, dma->nr_pages,
@@ -285,6 +287,7 @@ int videobuf_dma_free(struct videobuf_dmabuf *dma)
vfree(dma->vmalloc);
dma->vmalloc = NULL;
+ dma->varea = NULL;
if (dma->bus_addr) {
dma->bus_addr = 0;
diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c
index 6a0e8ca7294..dc9b1ef678a 100644
--- a/drivers/media/video/videodev.c
+++ b/drivers/media/video/videodev.c
@@ -30,7 +30,6 @@
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/smp_lock.h>
#include <linux/mm.h>
#include <linux/string.h>
@@ -1454,6 +1453,26 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
ret=vfd->vidioc_log_status(file, fh);
break;
}
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ case VIDIOC_DBG_G_REGISTER:
+ {
+ struct v4l2_register *p=arg;
+ if (!capable(CAP_SYS_ADMIN))
+ ret=-EPERM;
+ else if (vfd->vidioc_g_register)
+ ret=vfd->vidioc_g_register(file, fh, p);
+ break;
+ }
+ case VIDIOC_DBG_S_REGISTER:
+ {
+ struct v4l2_register *p=arg;
+ if (!capable(CAP_SYS_ADMIN))
+ ret=-EPERM;
+ else if (vfd->vidioc_s_register)
+ ret=vfd->vidioc_s_register(file, fh, p);
+ break;
+ }
+#endif
} /* switch */
if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) {
@@ -1561,7 +1580,7 @@ out:
}
-static struct file_operations video_fops;
+static const struct file_operations video_fops;
/**
* video_register_device - register video4linux devices
@@ -1709,7 +1728,7 @@ void video_unregister_device(struct video_device *vfd)
/*
* Video fs operations
*/
-static struct file_operations video_fops=
+static const struct file_operations video_fops=
{
.owner = THIS_MODULE,
.llseek = no_llseek,
diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c
index a373c142e74..0c658b74f2c 100644
--- a/drivers/media/video/vino.c
+++ b/drivers/media/video/vino.c
@@ -4390,7 +4390,7 @@ static int vino_ioctl(struct inode *inode, struct file *file,
// __initdata
static int vino_init_stage = 0;
-static struct file_operations vino_fops = {
+static const struct file_operations vino_fops = {
.owner = THIS_MODULE,
.open = vino_open,
.release = vino_close,
diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c
index d4cf5566673..f7e1d191037 100644
--- a/drivers/media/video/vivi.c
+++ b/drivers/media/video/vivi.c
@@ -145,7 +145,9 @@ struct vivi_buffer {
struct vivi_fmt *fmt;
+#ifdef CONFIG_VIVI_SCATTER
struct sg_to_addr *to_addr;
+#endif
};
struct vivi_dmaqueue {
@@ -230,6 +232,7 @@ static u8 bars[8][3] = {
#define TSTAMP_MAX_Y TSTAMP_MIN_Y+15
#define TSTAMP_MIN_X 64
+#ifdef CONFIG_VIVI_SCATTER
static void prep_to_addr(struct sg_to_addr to_addr[],
struct videobuf_buffer *vb)
{
@@ -262,14 +265,24 @@ static int get_addr_pos(int pos, int pages, struct sg_to_addr to_addr[])
return (p1);
}
+#endif
+#ifdef CONFIG_VIVI_SCATTER
static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax,
int hmax, int line, char *timestr)
+#else
+static void gen_line(char *basep,int inipos,int wmax,
+ int hmax, int line, char *timestr)
+#endif
{
- int w,i,j,pos=inipos,pgpos,oldpg,y;
- char *p,*s,*basep;
- struct page *pg;
+ int w,i,j,pos=inipos,y;
+ char *p,*s;
u8 chr,r,g,b,color;
+#ifdef CONFIG_VIVI_SCATTER
+ int pgpos,oldpg;
+ char *basep;
+ struct page *pg;
+
unsigned long flags;
spinlock_t spinlock;
@@ -280,6 +293,7 @@ static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax,
pg=pfn_to_page(sg_dma_address(to_addr[oldpg].sg) >> PAGE_SHIFT);
spin_lock_irqsave(&spinlock,flags);
basep = kmap_atomic(pg, KM_BOUNCE_READ)+to_addr[oldpg].sg->offset;
+#endif
/* We will just duplicate the second pixel at the packet */
wmax/=2;
@@ -291,6 +305,7 @@ static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax,
b=bars[w*7/wmax][2];
for (color=0;color<4;color++) {
+#ifdef CONFIG_VIVI_SCATTER
pgpos=get_addr_pos(pos,pages,to_addr);
if (pgpos!=oldpg) {
pg=pfn_to_page(sg_dma_address(to_addr[pgpos].sg) >> PAGE_SHIFT);
@@ -299,6 +314,9 @@ static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax,
oldpg=pgpos;
}
p=basep+pos-to_addr[pgpos].pos;
+#else
+ p=basep+pos;
+#endif
switch (color) {
case 0:
@@ -343,6 +361,7 @@ static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax,
pos=inipos+j*2;
for (color=0;color<4;color++) {
+#ifdef CONFIG_VIVI_SCATTER
pgpos=get_addr_pos(pos,pages,to_addr);
if (pgpos!=oldpg) {
pg=pfn_to_page(sg_dma_address(
@@ -356,6 +375,9 @@ static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax,
oldpg=pgpos;
}
p=basep+pos-to_addr[pgpos].pos;
+#else
+ p=basep+pos;
+#endif
y=TO_Y(r,g,b);
@@ -380,19 +402,27 @@ static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax,
end:
+#ifdef CONFIG_VIVI_SCATTER
kunmap_atomic(basep, KM_BOUNCE_READ);
spin_unlock_irqrestore(&spinlock,flags);
-
+#else
+ return;
+#endif
}
static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf)
{
int h,pos=0;
int hmax = buf->vb.height;
int wmax = buf->vb.width;
- struct videobuf_buffer *vb=&buf->vb;
- struct sg_to_addr *to_addr=buf->to_addr;
struct timeval ts;
+#ifdef CONFIG_VIVI_SCATTER
+ struct sg_to_addr *to_addr=buf->to_addr;
+ struct videobuf_buffer *vb=&buf->vb;
+#else
+ char *tmpbuf;
+#endif
+#ifdef CONFIG_VIVI_SCATTER
/* Test if DMA mapping is ready */
if (!sg_dma_address(&vb->dma.sglist[0]))
return;
@@ -401,9 +431,28 @@ static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf)
/* Check if there is enough memory */
BUG_ON(buf->vb.dma.nr_pages << PAGE_SHIFT < (buf->vb.width*buf->vb.height)*2);
+#else
+ if (buf->vb.dma.varea) {
+ tmpbuf=kmalloc (wmax*2, GFP_KERNEL);
+ } else {
+ tmpbuf=buf->vb.dma.vmalloc;
+ }
+
+#endif
for (h=0;h<hmax;h++) {
+#ifdef CONFIG_VIVI_SCATTER
gen_line(to_addr,pos,vb->dma.nr_pages,wmax,hmax,h,dev->timestr);
+#else
+ if (buf->vb.dma.varea) {
+ gen_line(tmpbuf,0,wmax,hmax,h,dev->timestr);
+ /* FIXME: replacing to __copy_to_user */
+ if (copy_to_user(buf->vb.dma.varea+pos,tmpbuf,wmax*2)!=0)
+ dprintk(2,"vivifill copy_to_user failed.\n");
+ } else {
+ gen_line(tmpbuf,pos,wmax,hmax,h,dev->timestr);
+ }
+#endif
pos += wmax*2;
}
@@ -429,7 +478,7 @@ static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf)
dev->h,dev->m,dev->s,(dev->us+500)/1000);
dprintk(2,"vivifill at %s: Buffer 0x%08lx size= %d\n",dev->timestr,
- (unsigned long)buf->vb.dma.vmalloc,pos);
+ (unsigned long)buf->vb.dma.varea,pos);
/* Advice that buffer was filled */
buf->vb.state = STATE_DONE;
@@ -471,11 +520,12 @@ static void vivi_thread_tick(struct vivi_dmaqueue *dma_q)
/* Fill buffer */
vivi_fillbuff(dev,buf);
- }
- if (list_empty(&dma_q->active)) {
- del_timer(&dma_q->timeout);
- } else {
- mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);
+
+ if (list_empty(&dma_q->active)) {
+ del_timer(&dma_q->timeout);
+ } else {
+ mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);
+ }
}
if (bc != 1)
dprintk(1,"%s: %d buffers handled (should be 1)\n",__FUNCTION__,bc);
@@ -522,6 +572,8 @@ static int vivi_thread(void *data)
dprintk(1,"thread started\n");
+ mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);
+
for (;;) {
vivi_sleep(dma_q);
@@ -538,7 +590,6 @@ static int vivi_start_thread(struct vivi_dmaqueue *dma_q)
dma_q->ini_jiffies=jiffies;
dprintk(1,"%s\n",__FUNCTION__);
- init_waitqueue_head(&dma_q->wq);
dma_q->kthread = kthread_run(vivi_thread, dma_q, "vivi");
@@ -546,6 +597,9 @@ static int vivi_start_thread(struct vivi_dmaqueue *dma_q)
printk(KERN_ERR "vivi: kernel_thread() failed\n");
return PTR_ERR(dma_q->kthread);
}
+ /* Wakes thread */
+ wake_up_interruptible(&dma_q->wq);
+
dprintk(1,"returning from %s\n",__FUNCTION__);
return 0;
}
@@ -663,9 +717,11 @@ static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf)
if (in_interrupt())
BUG();
+#ifdef CONFIG_VIVI_SCATTER
/*FIXME: Maybe a spinlock is required here */
kfree(buf->to_addr);
buf->to_addr=NULL;
+#endif
videobuf_waiton(&buf->vb,0,0);
videobuf_dma_unmap(vq, &buf->vb.dma);
@@ -711,11 +767,12 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
buf->vb.state = STATE_PREPARED;
+#ifdef CONFIG_VIVI_SCATTER
if (NULL == (buf->to_addr = kmalloc(sizeof(*buf->to_addr) * vb->dma.nr_pages,GFP_KERNEL))) {
rc=-ENOMEM;
goto fail;
}
-
+#endif
return 0;
fail:
@@ -780,6 +837,7 @@ static void buffer_release(struct videobuf_queue *vq, struct videobuf_buffer *vb
free_buffer(vq,buf);
}
+#ifdef CONFIG_VIVI_SCATTER
static int vivi_map_sg(void *dev, struct scatterlist *sg, int nents,
int direction)
{
@@ -812,6 +870,7 @@ static int vivi_dma_sync_sg(void *dev,struct scatterlist *sglist, int nr_pages,
// flush_write_buffers();
return 0;
}
+#endif
static struct videobuf_queue_ops vivi_video_qops = {
.buf_setup = buffer_setup,
@@ -820,9 +879,9 @@ static struct videobuf_queue_ops vivi_video_qops = {
.buf_release = buffer_release,
/* Non-pci handling routines */
- .vb_map_sg = vivi_map_sg,
- .vb_dma_sync_sg = vivi_dma_sync_sg,
- .vb_unmap_sg = vivi_unmap_sg,
+// .vb_map_sg = vivi_map_sg,
+// .vb_dma_sync_sg = vivi_dma_sync_sg,
+// .vb_unmap_sg = vivi_unmap_sg,
};
/* ------------------------------------------------------------------
@@ -1200,11 +1259,19 @@ static int vivi_open(struct inode *inode, struct file *file)
sprintf(dev->timestr,"%02d:%02d:%02d:%03d",
dev->h,dev->m,dev->s,(dev->us+500)/1000);
+#ifdef CONFIG_VIVI_SCATTER
+ videobuf_queue_init(&fh->vb_vidq,VIDEOBUF_DMA_SCATTER, &vivi_video_qops,
+ NULL, NULL,
+ fh->type,
+ V4L2_FIELD_INTERLACED,
+ sizeof(struct vivi_buffer),fh);
+#else
videobuf_queue_init(&fh->vb_vidq, &vivi_video_qops,
NULL, NULL,
fh->type,
V4L2_FIELD_INTERLACED,
sizeof(struct vivi_buffer),fh);
+#endif
return 0;
}
@@ -1292,7 +1359,7 @@ vivi_mmap(struct file *file, struct vm_area_struct * vma)
return ret;
}
-static struct file_operations vivi_fops = {
+static const struct file_operations vivi_fops = {
.owner = THIS_MODULE,
.open = vivi_open,
.release = vivi_release,
@@ -1352,6 +1419,7 @@ static int __init vivi_init(void)
/* init video dma queues */
INIT_LIST_HEAD(&dev->vidq.active);
INIT_LIST_HEAD(&dev->vidq.queued);
+ init_waitqueue_head(&dev->vidq.wq);
/* initialize locks */
init_MUTEX(&dev->lock);
diff --git a/drivers/media/video/w9966.c b/drivers/media/video/w9966.c
index 8d14f308f17..47366408637 100644
--- a/drivers/media/video/w9966.c
+++ b/drivers/media/video/w9966.c
@@ -183,7 +183,7 @@ static int w9966_v4l_ioctl(struct inode *inode, struct file *file,
static ssize_t w9966_v4l_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos);
-static struct file_operations w9966_fops = {
+static const struct file_operations w9966_fops = {
.owner = THIS_MODULE,
.open = video_exclusive_open,
.release = video_exclusive_release,
diff --git a/drivers/media/video/w9968cf.c b/drivers/media/video/w9968cf.c
index 9f403af7b04..8f31613b990 100644
--- a/drivers/media/video/w9968cf.c
+++ b/drivers/media/video/w9968cf.c
@@ -399,7 +399,7 @@ MODULE_PARM_DESC(specific_debug,
****************************************************************************/
/* Video4linux interface */
-static struct file_operations w9968cf_fops;
+static const struct file_operations w9968cf_fops;
static int w9968cf_open(struct inode*, struct file*);
static int w9968cf_release(struct inode*, struct file*);
static int w9968cf_mmap(struct file*, struct vm_area_struct*);
@@ -1573,6 +1573,7 @@ static int w9968cf_i2c_init(struct w9968cf_device* cam)
memcpy(&cam->i2c_adapter, &adap, sizeof(struct i2c_adapter));
strcpy(cam->i2c_adapter.name, "w9968cf");
+ cam->i2c_adapter.dev.parent = &cam->usbdev->dev;
i2c_set_adapdata(&cam->i2c_adapter, cam);
DBG(6, "Registering I2C adapter with kernel...")
@@ -3466,7 +3467,7 @@ ioctl_fail:
}
-static struct file_operations w9968cf_fops = {
+static const struct file_operations w9968cf_fops = {
.owner = THIS_MODULE,
.open = w9968cf_open,
.release = w9968cf_release,
diff --git a/drivers/media/video/zc0301/zc0301.h b/drivers/media/video/zc0301/zc0301.h
index b9c93b8c16f..710f12eb912 100644
--- a/drivers/media/video/zc0301/zc0301.h
+++ b/drivers/media/video/zc0301/zc0301.h
@@ -1,7 +1,7 @@
/***************************************************************************
- * V4L2 driver for ZC0301 Image Processor and Control Chip *
+ * V4L2 driver for ZC0301[P] Image Processor and Control Chip *
* *
- * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
+ * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.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 *
diff --git a/drivers/media/video/zc0301/zc0301_core.c b/drivers/media/video/zc0301/zc0301_core.c
index 52d0f759ee0..f1120551c70 100644
--- a/drivers/media/video/zc0301/zc0301_core.c
+++ b/drivers/media/video/zc0301/zc0301_core.c
@@ -1,7 +1,7 @@
/***************************************************************************
* Video4Linux2 driver for ZC0301[P] Image Processor and Control Chip *
* *
- * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
+ * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
* *
* Informations about the chip internals needed to enable the I2C protocol *
* have been taken from the documentation of the ZC030x Video4Linux1 *
@@ -52,8 +52,8 @@
#define ZC0301_MODULE_AUTHOR "(C) 2006 Luca Risolia"
#define ZC0301_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>"
#define ZC0301_MODULE_LICENSE "GPL"
-#define ZC0301_MODULE_VERSION "1:1.05"
-#define ZC0301_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 5)
+#define ZC0301_MODULE_VERSION "1:1.07"
+#define ZC0301_MODULE_VERSION_CODE KERNEL_VERSION(1, 1, 7)
/*****************************************************************************/
@@ -89,7 +89,7 @@ MODULE_PARM_DESC(force_munmap,
"\ndetected camera."
"\n 0 = do not force memory unmapping"
"\n 1 = force memory unmapping (save memory)"
- "\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"."
+ "\nDefault value is "__MODULE_STRING(ZC0301_FORCE_MUNMAP)"."
"\n");
static unsigned int frame_timeout[] = {[0 ... ZC0301_MAX_DEVICES-1] =
@@ -136,7 +136,8 @@ zc0301_request_buffers(struct zc0301_device* cam, u32 count,
cam->nbuffers = count;
while (cam->nbuffers > 0) {
- if ((buff = vmalloc_32(cam->nbuffers * PAGE_ALIGN(imagesize))))
+ if ((buff = vmalloc_32_user(cam->nbuffers *
+ PAGE_ALIGN(imagesize))))
break;
cam->nbuffers--;
}
@@ -430,7 +431,8 @@ static int zc0301_start_transfer(struct zc0301_device* cam)
struct usb_host_interface* altsetting = usb_altnum_to_altsetting(
usb_ifnum_to_if(udev, 0),
ZC0301_ALTERNATE_SETTING);
- const unsigned int psz = altsetting->endpoint[0].desc.wMaxPacketSize;
+ const unsigned int psz = le16_to_cpu(altsetting->
+ endpoint[0].desc.wMaxPacketSize);
struct urb* urb;
s8 i, j;
int err = 0;
@@ -489,7 +491,7 @@ static int zc0301_start_transfer(struct zc0301_device* cam)
return 0;
free_urbs:
- for (i = 0; i < ZC0301_URBS; i++)
+ for (i = 0; (i < ZC0301_URBS) && cam->urb[i]; i++)
usb_free_urb(cam->urb[i]);
free_buffers:
@@ -1288,6 +1290,35 @@ zc0301_vidioc_s_crop(struct zc0301_device* cam, void __user * arg)
static int
+zc0301_vidioc_enum_framesizes(struct zc0301_device* cam, void __user * arg)
+{
+ struct v4l2_frmsizeenum frmsize;
+
+ if (copy_from_user(&frmsize, arg, sizeof(frmsize)))
+ return -EFAULT;
+
+ if (frmsize.index != 0 && frmsize.index != 1)
+ return -EINVAL;
+
+ if (frmsize.pixel_format != V4L2_PIX_FMT_JPEG)
+ return -EINVAL;
+
+ frmsize.type = V4L2_FRMSIZE_TYPE_DISCRETE;
+
+ if (frmsize.index == 1) {
+ frmsize.discrete.width = cam->sensor.cropcap.defrect.width;
+ frmsize.discrete.height = cam->sensor.cropcap.defrect.height;
+ }
+ memset(&frmsize.reserved, 0, sizeof(frmsize.reserved));
+
+ if (copy_to_user(arg, &frmsize, sizeof(frmsize)))
+ return -EFAULT;
+
+ return 0;
+}
+
+
+static int
zc0301_vidioc_enum_fmt(struct zc0301_device* cam, void __user * arg)
{
struct v4l2_fmtdesc fmtd;
@@ -1295,6 +1326,9 @@ zc0301_vidioc_enum_fmt(struct zc0301_device* cam, void __user * arg)
if (copy_from_user(&fmtd, arg, sizeof(fmtd)))
return -EFAULT;
+ if (fmtd.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
if (fmtd.index == 0) {
strcpy(fmtd.description, "JPEG");
fmtd.pixelformat = V4L2_PIX_FMT_JPEG;
@@ -1795,6 +1829,9 @@ static int zc0301_ioctl_v4l2(struct inode* inode, struct file* filp,
case VIDIOC_S_FMT:
return zc0301_vidioc_try_s_fmt(cam, cmd, arg);
+ case VIDIOC_ENUM_FRAMESIZES:
+ return zc0301_vidioc_enum_framesizes(cam, arg);
+
case VIDIOC_G_JPEGCOMP:
return zc0301_vidioc_g_jpegcomp(cam, arg);
@@ -1830,6 +1867,7 @@ static int zc0301_ioctl_v4l2(struct inode* inode, struct file* filp,
case VIDIOC_QUERYSTD:
case VIDIOC_ENUMSTD:
case VIDIOC_QUERYMENU:
+ case VIDIOC_ENUM_FRAMEINTERVALS:
return -EINVAL;
default:
@@ -1871,11 +1909,12 @@ static int zc0301_ioctl(struct inode* inode, struct file* filp,
}
-static struct file_operations zc0301_fops = {
+static const struct file_operations zc0301_fops = {
.owner = THIS_MODULE,
.open = zc0301_open,
.release = zc0301_release,
.ioctl = zc0301_ioctl,
+ .compat_ioctl = v4l_compat_ioctl32,
.read = zc0301_read,
.poll = zc0301_poll,
.mmap = zc0301_mmap,
@@ -1913,7 +1952,7 @@ zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
mutex_init(&cam->dev_mutex);
DBG(2, "ZC0301[P] Image Processor and Control Chip detected "
- "(vid/pid 0x%04X/0x%04X)",id->idVendor, id->idProduct);
+ "(vid/pid 0x%04X:0x%04X)",id->idVendor, id->idProduct);
for (i = 0; zc0301_sensor_table[i]; i++) {
err = zc0301_sensor_table[i](cam);
diff --git a/drivers/media/video/zc0301/zc0301_pas202bcb.c b/drivers/media/video/zc0301/zc0301_pas202bcb.c
index ecfd39a56df..3efb92a0d0d 100644
--- a/drivers/media/video/zc0301/zc0301_pas202bcb.c
+++ b/drivers/media/video/zc0301/zc0301_pas202bcb.c
@@ -1,8 +1,8 @@
/***************************************************************************
- * Plug-in for PAS202BCB image sensor connected to the ZC0301[P] Image *
+ * Plug-in for PAS202BCB image sensor connected to the ZC0301 Image *
* Processor and Control Chip *
* *
- * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
+ * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
* *
* Initialization values of the ZC0301[P] have been taken from the SPCA5XX *
* driver maintained by Michel Xhaard <mxhaard@magic.fr> *
diff --git a/drivers/media/video/zc0301/zc0301_pb0330.c b/drivers/media/video/zc0301/zc0301_pb0330.c
index ed8542e6c50..5784b1d1491 100644
--- a/drivers/media/video/zc0301/zc0301_pb0330.c
+++ b/drivers/media/video/zc0301/zc0301_pb0330.c
@@ -1,8 +1,8 @@
/***************************************************************************
- * Plug-in for PB-0330 image sensor connected to the ZC0301[P] Image *
+ * Plug-in for PB-0330 image sensor connected to the ZC0301P Image *
* Processor and Control Chip *
* *
- * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
+ * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
* *
* Initialization values of the ZC0301[P] have been taken from the SPCA5XX *
* driver maintained by Michel Xhaard <mxhaard@magic.fr> *
diff --git a/drivers/media/video/zc0301/zc0301_sensor.h b/drivers/media/video/zc0301/zc0301_sensor.h
index 4363a915b1f..44e82cff931 100644
--- a/drivers/media/video/zc0301/zc0301_sensor.h
+++ b/drivers/media/video/zc0301/zc0301_sensor.h
@@ -1,8 +1,8 @@
/***************************************************************************
- * API for image sensors connected to the ZC0301 Image Processor and *
+ * API for image sensors connected to the ZC0301[P] Image Processor and *
* Control Chip *
* *
- * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
+ * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.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 *
@@ -70,12 +70,11 @@ static const struct usb_device_id zc0301_id_table[] = { \
{ ZC0301_USB_DEVICE(0x041e, 0x4036, 0xff), }, /* HV7131 */ \
{ ZC0301_USB_DEVICE(0x041e, 0x403a, 0xff), }, /* HV7131 */ \
{ ZC0301_USB_DEVICE(0x0458, 0x7007, 0xff), }, /* TAS5130 */ \
- { ZC0301_USB_DEVICE(0x0458, 0x700C, 0xff), }, /* TAS5130 */ \
+ { ZC0301_USB_DEVICE(0x0458, 0x700c, 0xff), }, /* TAS5130 */ \
{ ZC0301_USB_DEVICE(0x0458, 0x700f, 0xff), }, /* TAS5130 */ \
{ ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202 */ \
{ ZC0301_USB_DEVICE(0x055f, 0xd003, 0xff), }, /* TAS5130 */ \
{ ZC0301_USB_DEVICE(0x055f, 0xd004, 0xff), }, /* TAS5130 */ \
- { ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202 */ \
{ ZC0301_USB_DEVICE(0x0ac8, 0x0301, 0xff), }, \
{ ZC0301_USB_DEVICE(0x0ac8, 0x301b, 0xff), }, /* PB-0330/HV7131 */ \
{ ZC0301_USB_DEVICE(0x0ac8, 0x303b, 0xff), }, /* PB-0330 */ \
@@ -94,9 +93,9 @@ extern int zc0301_i2c_read(struct zc0301_device*, u16 address, u8 length);
/*****************************************************************************/
-#define ZC0301_MAX_CTRLS V4L2_CID_LASTP1-V4L2_CID_BASE+10
-#define ZC0301_V4L2_CID_DAC_MAGNITUDE V4L2_CID_PRIVATE_BASE
-#define ZC0301_V4L2_CID_GREEN_BALANCE V4L2_CID_PRIVATE_BASE + 1
+#define ZC0301_MAX_CTRLS (V4L2_CID_LASTP1 - V4L2_CID_BASE + 10)
+#define ZC0301_V4L2_CID_DAC_MAGNITUDE (V4L2_CID_PRIVATE_BASE + 0)
+#define ZC0301_V4L2_CID_GREEN_BALANCE (V4L2_CID_PRIVATE_BASE + 1)
struct zc0301_sensor {
char name[32];
diff --git a/drivers/media/video/zoran_card.c b/drivers/media/video/zoran_card.c
index 4d1eb2fba34..73162a3a61d 100644
--- a/drivers/media/video/zoran_card.c
+++ b/drivers/media/video/zoran_card.c
@@ -843,6 +843,7 @@ zoran_register_i2c (struct zoran *zr)
sizeof(I2C_NAME(&zr->i2c_adapter)) - 1);
i2c_set_adapdata(&zr->i2c_adapter, zr);
zr->i2c_adapter.algo_data = &zr->i2c_algo;
+ zr->i2c_adapter.dev.parent = &zr->pci_dev->dev;
return i2c_bit_add_bus(&zr->i2c_adapter);
}
diff --git a/drivers/media/video/zoran_driver.c b/drivers/media/video/zoran_driver.c
index 862a984c215..07432373335 100644
--- a/drivers/media/video/zoran_driver.c
+++ b/drivers/media/video/zoran_driver.c
@@ -562,7 +562,6 @@ jpg_fbuffer_alloc (struct file *file)
jpg_fbuffer_free(file);
return -ENOBUFS;
}
- memset((void *) mem, 0, PAGE_SIZE);
fh->jpg_buffers.buffer[i].frag_tab = (u32 *) mem;
fh->jpg_buffers.buffer[i].frag_tab_bus =
virt_to_bus((void *) mem);
@@ -4680,7 +4679,7 @@ zoran_mmap (struct file *file,
return 0;
}
-static struct file_operations zoran_fops = {
+static const struct file_operations zoran_fops = {
.owner = THIS_MODULE,
.open = zoran_open,
.release = zoran_close,
diff --git a/drivers/media/video/zoran_procfs.c b/drivers/media/video/zoran_procfs.c
index c374c76b375..446ae8d5c3d 100644
--- a/drivers/media/video/zoran_procfs.c
+++ b/drivers/media/video/zoran_procfs.c
@@ -186,7 +186,7 @@ static ssize_t zoran_write(struct file *file, const char __user *buffer,
return count;
}
-static struct file_operations zoran_operations = {
+static const struct file_operations zoran_operations = {
.open = zoran_open,
.read = seq_read,
.write = zoran_write,
diff --git a/drivers/message/fusion/Kconfig b/drivers/message/fusion/Kconfig
index ea31d847051..71037f91c22 100644
--- a/drivers/message/fusion/Kconfig
+++ b/drivers/message/fusion/Kconfig
@@ -66,7 +66,7 @@ config FUSION_MAX_SGE
config FUSION_CTL
tristate "Fusion MPT misc device (ioctl) driver"
- depends on FUSION_SPI || FUSION_FC
+ depends on FUSION_SPI || FUSION_FC || FUSION_SAS
---help---
The Fusion MPT misc device driver provides specialized control
of MPT adapters via system ioctl calls. Use of ioctl calls to
diff --git a/drivers/message/fusion/Makefile b/drivers/message/fusion/Makefile
index 341691390e8..6003b46c843 100644
--- a/drivers/message/fusion/Makefile
+++ b/drivers/message/fusion/Makefile
@@ -8,6 +8,9 @@
#EXTRA_CFLAGS += -DMPT_DEBUG_INIT
#EXTRA_CFLAGS += -DMPT_DEBUG_EXIT
#EXTRA_CFLAGS += -DMPT_DEBUG_FAIL
+#EXTRA_CFLAGS += -DMPT_DEBUG_DV
+#EXTRA_CFLAGS += -DMPT_DEBUG_TM
+#EXTRA_CFLAGS += -DMPT_DEBUG_REPLY
#
# driver/module specifics...
@@ -20,11 +23,7 @@
#CFLAGS_mptbase.o += -DMPT_DEBUG_RESET
#
# For mptscsih:
-#CFLAGS_mptscsih.o += -DMPT_DEBUG_DV
-#CFLAGS_mptscsih.o += -DMPT_DEBUG_NEGO
-#CFLAGS_mptscsih.o += -DMPT_DEBUG_TM
#CFLAGS_mptscsih.o += -DMPT_DEBUG_SCSI
-#CFLAGS_mptscsih.o += -DMPT_DEBUG_REPLY
#
# For mptctl:
#CFLAGS_mptctl.o += -DMPT_DEBUG_IOCTL
diff --git a/drivers/message/fusion/lsi/mpi.h b/drivers/message/fusion/lsi/mpi.h
index 81ad77622da..75223bf24ae 100644
--- a/drivers/message/fusion/lsi/mpi.h
+++ b/drivers/message/fusion/lsi/mpi.h
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2000-2005 LSI Logic Corporation.
+ * Copyright (c) 2000-2006 LSI Logic Corporation.
*
*
* Name: mpi.h
* Title: MPI Message independent structures and definitions
* Creation Date: July 27, 2000
*
- * mpi.h Version: 01.05.11
+ * mpi.h Version: 01.05.12
*
* Version History
* ---------------
@@ -77,6 +77,7 @@
* 08-03-05 01.05.09 Bumped MPI_HEADER_VERSION_UNIT.
* 08-30-05 01.05.10 Added 2 new IOCStatus codes for Target.
* 03-27-06 01.05.11 Bumped MPI_HEADER_VERSION_UNIT.
+ * 10-11-06 01.05.12 Bumped MPI_HEADER_VERSION_UNIT.
* --------------------------------------------------------------------------
*/
@@ -107,7 +108,7 @@
/* Note: The major versions of 0xe0 through 0xff are reserved */
/* versioning for this MPI header set */
-#define MPI_HEADER_VERSION_UNIT (0x0D)
+#define MPI_HEADER_VERSION_UNIT (0x0E)
#define MPI_HEADER_VERSION_DEV (0x00)
#define MPI_HEADER_VERSION_UNIT_MASK (0xFF00)
#define MPI_HEADER_VERSION_UNIT_SHIFT (8)
diff --git a/drivers/message/fusion/lsi/mpi_cnfg.h b/drivers/message/fusion/lsi/mpi_cnfg.h
index 47e13e360c1..0e4c8e77a81 100644
--- a/drivers/message/fusion/lsi/mpi_cnfg.h
+++ b/drivers/message/fusion/lsi/mpi_cnfg.h
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2000-2005 LSI Logic Corporation.
+ * Copyright (c) 2000-2006 LSI Logic Corporation.
*
*
* Name: mpi_cnfg.h
* Title: MPI Config message, structures, and Pages
* Creation Date: July 27, 2000
*
- * mpi_cnfg.h Version: 01.05.12
+ * mpi_cnfg.h Version: 01.05.13
*
* Version History
* ---------------
@@ -276,6 +276,23 @@
* Added AdditionalControlFlags, MaxTargetPortConnectTime,
* ReportDeviceMissingDelay, and IODeviceMissingDelay
* fields to SAS IO Unit Page 1.
+ * 10-11-06 01.05.13 Added NumForceWWID field and ForceWWID array to
+ * Manufacturing Page 5.
+ * Added Manufacturing pages 8 through 10.
+ * Added defines for supported metadata size bits in
+ * CapabilitiesFlags field of IOC Page 6.
+ * Added defines for metadata size bits in VolumeSettings
+ * field of RAID Volume Page 0.
+ * Added SATA Link Reset settings, Enable SATA Asynchronous
+ * Notification bit, and HideNonZeroAttachedPhyIdentifiers
+ * bit to AdditionalControlFlags field of SAS IO Unit
+ * Page 1.
+ * Added defines for Enclosure Devices Unmapped and
+ * Device Limit Exceeded bits in Status field of SAS IO
+ * Unit Page 2.
+ * Added more AccessStatus values for SAS Device Page 0.
+ * Added bit for SATA Asynchronous Notification Support in
+ * Flags field of SAS Device Page 0.
* --------------------------------------------------------------------------
*/
@@ -654,17 +671,24 @@ typedef struct _CONFIG_PAGE_MANUFACTURING_4
#define MPI_MANPAGE4_IR_NO_MIX_SAS_SATA (0x01)
+#ifndef MPI_MANPAGE5_NUM_FORCEWWID
+#define MPI_MANPAGE5_NUM_FORCEWWID (1)
+#endif
+
typedef struct _CONFIG_PAGE_MANUFACTURING_5
{
CONFIG_PAGE_HEADER Header; /* 00h */
U64 BaseWWID; /* 04h */
U8 Flags; /* 0Ch */
- U8 Reserved1; /* 0Dh */
+ U8 NumForceWWID; /* 0Dh */
U16 Reserved2; /* 0Eh */
+ U32 Reserved3; /* 10h */
+ U32 Reserved4; /* 14h */
+ U64 ForceWWID[MPI_MANPAGE5_NUM_FORCEWWID]; /* 18h */
} CONFIG_PAGE_MANUFACTURING_5, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_5,
ManufacturingPage5_t, MPI_POINTER pManufacturingPage5_t;
-#define MPI_MANUFACTURING5_PAGEVERSION (0x01)
+#define MPI_MANUFACTURING5_PAGEVERSION (0x02)
/* defines for the Flags field */
#define MPI_MANPAGE5_TWO_WWID_PER_PHY (0x01)
@@ -740,6 +764,36 @@ typedef struct _CONFIG_PAGE_MANUFACTURING_7
#define MPI_MANPAGE7_FLAG_USE_SLOT_INFO (0x00000001)
+typedef struct _CONFIG_PAGE_MANUFACTURING_8
+{
+ CONFIG_PAGE_HEADER Header; /* 00h */
+ U32 ProductSpecificInfo;/* 04h */
+} CONFIG_PAGE_MANUFACTURING_8, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_8,
+ ManufacturingPage8_t, MPI_POINTER pManufacturingPage8_t;
+
+#define MPI_MANUFACTURING8_PAGEVERSION (0x00)
+
+
+typedef struct _CONFIG_PAGE_MANUFACTURING_9
+{
+ CONFIG_PAGE_HEADER Header; /* 00h */
+ U32 ProductSpecificInfo;/* 04h */
+} CONFIG_PAGE_MANUFACTURING_9, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_9,
+ ManufacturingPage9_t, MPI_POINTER pManufacturingPage9_t;
+
+#define MPI_MANUFACTURING6_PAGEVERSION (0x00)
+
+
+typedef struct _CONFIG_PAGE_MANUFACTURING_10
+{
+ CONFIG_PAGE_HEADER Header; /* 00h */
+ U32 ProductSpecificInfo;/* 04h */
+} CONFIG_PAGE_MANUFACTURING_10, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_10,
+ ManufacturingPage10_t, MPI_POINTER pManufacturingPage10_t;
+
+#define MPI_MANUFACTURING10_PAGEVERSION (0x00)
+
+
/****************************************************************************
* IO Unit Config Pages
****************************************************************************/
@@ -1080,10 +1134,14 @@ typedef struct _CONFIG_PAGE_IOC_6
} CONFIG_PAGE_IOC_6, MPI_POINTER PTR_CONFIG_PAGE_IOC_6,
IOCPage6_t, MPI_POINTER pIOCPage6_t;
-#define MPI_IOCPAGE6_PAGEVERSION (0x00)
+#define MPI_IOCPAGE6_PAGEVERSION (0x01)
/* IOC Page 6 Capabilities Flags */
+#define MPI_IOCPAGE6_CAP_FLAGS_MASK_METADATA_SIZE (0x00000006)
+#define MPI_IOCPAGE6_CAP_FLAGS_64MB_METADATA_SIZE (0x00000000)
+#define MPI_IOCPAGE6_CAP_FLAGS_512MB_METADATA_SIZE (0x00000002)
+
#define MPI_IOCPAGE6_CAP_FLAGS_GLOBAL_HOT_SPARE (0x00000001)
@@ -2160,6 +2218,11 @@ typedef struct _RAID_VOL0_SETTINGS
#define MPI_RAIDVOL0_SETTING_AUTO_CONFIGURE (0x0004)
#define MPI_RAIDVOL0_SETTING_PRIORITY_RESYNC (0x0008)
#define MPI_RAIDVOL0_SETTING_FAST_DATA_SCRUBBING_0102 (0x0020) /* obsolete */
+
+#define MPI_RAIDVOL0_SETTING_MASK_METADATA_SIZE (0x00C0)
+#define MPI_RAIDVOL0_SETTING_64MB_METADATA_SIZE (0x0000)
+#define MPI_RAIDVOL0_SETTING_512MB_METADATA_SIZE (0x0040)
+
#define MPI_RAIDVOL0_SETTING_USE_PRODUCT_ID_SUFFIX (0x0010)
#define MPI_RAIDVOL0_SETTING_USE_DEFAULTS (0x8000)
@@ -2203,7 +2266,7 @@ typedef struct _CONFIG_PAGE_RAID_VOL_0
} CONFIG_PAGE_RAID_VOL_0, MPI_POINTER PTR_CONFIG_PAGE_RAID_VOL_0,
RaidVolumePage0_t, MPI_POINTER pRaidVolumePage0_t;
-#define MPI_RAIDVOLPAGE0_PAGEVERSION (0x06)
+#define MPI_RAIDVOLPAGE0_PAGEVERSION (0x07)
/* values for RAID Volume Page 0 InactiveStatus field */
#define MPI_RAIDVOLPAGE0_UNKNOWN_INACTIVE (0x00)
@@ -2518,7 +2581,7 @@ typedef struct _CONFIG_PAGE_SAS_IO_UNIT_1
} CONFIG_PAGE_SAS_IO_UNIT_1, MPI_POINTER PTR_CONFIG_PAGE_SAS_IO_UNIT_1,
SasIOUnitPage1_t, MPI_POINTER pSasIOUnitPage1_t;
-#define MPI_SASIOUNITPAGE1_PAGEVERSION (0x06)
+#define MPI_SASIOUNITPAGE1_PAGEVERSION (0x07)
/* values for SAS IO Unit Page 1 ControlFlags */
#define MPI_SAS_IOUNIT1_CONTROL_DEVICE_SELF_TEST (0x8000)
@@ -2544,7 +2607,13 @@ typedef struct _CONFIG_PAGE_SAS_IO_UNIT_1
#define MPI_SAS_IOUNIT1_CONTROL_CLEAR_AFFILIATION (0x0001)
/* values for SAS IO Unit Page 1 AdditionalControlFlags */
-#define MPI_SAS_IOUNIT1_ACONTROL_ALLOW_TABLE_TO_TABLE (0x0001)
+#define MPI_SAS_IOUNIT1_ACONTROL_SATA_ASYNCHROUNOUS_NOTIFICATION (0x0040)
+#define MPI_SAS_IOUNIT1_ACONTROL_HIDE_NONZERO_ATTACHED_PHY_IDENT (0x0020)
+#define MPI_SAS_IOUNIT1_ACONTROL_PORT_ENABLE_ONLY_SATA_LINK_RESET (0x0010)
+#define MPI_SAS_IOUNIT1_ACONTROL_OTHER_AFFILIATION_SATA_LINK_RESET (0x0008)
+#define MPI_SAS_IOUNIT1_ACONTROL_SELF_AFFILIATION_SATA_LINK_RESET (0x0004)
+#define MPI_SAS_IOUNIT1_ACONTROL_NO_AFFILIATION_SATA_LINK_RESET (0x0002)
+#define MPI_SAS_IOUNIT1_ACONTROL_ALLOW_TABLE_TO_TABLE (0x0001)
/* defines for SAS IO Unit Page 1 ReportDeviceMissingDelay */
#define MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK (0x7F)
@@ -2585,9 +2654,11 @@ typedef struct _CONFIG_PAGE_SAS_IO_UNIT_2
} CONFIG_PAGE_SAS_IO_UNIT_2, MPI_POINTER PTR_CONFIG_PAGE_SAS_IO_UNIT_2,
SasIOUnitPage2_t, MPI_POINTER pSasIOUnitPage2_t;
-#define MPI_SASIOUNITPAGE2_PAGEVERSION (0x05)
+#define MPI_SASIOUNITPAGE2_PAGEVERSION (0x06)
/* values for SAS IO Unit Page 2 Status field */
+#define MPI_SAS_IOUNIT2_STATUS_DEVICE_LIMIT_EXCEEDED (0x08)
+#define MPI_SAS_IOUNIT2_STATUS_ENCLOSURE_DEVICES_UNMAPPED (0x04)
#define MPI_SAS_IOUNIT2_STATUS_DISABLED_PERSISTENT_MAPPINGS (0x02)
#define MPI_SAS_IOUNIT2_STATUS_FULL_PERSISTENT_MAPPINGS (0x01)
@@ -2739,24 +2810,38 @@ typedef struct _CONFIG_PAGE_SAS_DEVICE_0
} CONFIG_PAGE_SAS_DEVICE_0, MPI_POINTER PTR_CONFIG_PAGE_SAS_DEVICE_0,
SasDevicePage0_t, MPI_POINTER pSasDevicePage0_t;
-#define MPI_SASDEVICE0_PAGEVERSION (0x04)
+#define MPI_SASDEVICE0_PAGEVERSION (0x05)
/* values for SAS Device Page 0 AccessStatus field */
-#define MPI_SAS_DEVICE0_ASTATUS_NO_ERRORS (0x00)
-#define MPI_SAS_DEVICE0_ASTATUS_SATA_INIT_FAILED (0x01)
-#define MPI_SAS_DEVICE0_ASTATUS_SATA_CAPABILITY_FAILED (0x02)
+#define MPI_SAS_DEVICE0_ASTATUS_NO_ERRORS (0x00)
+#define MPI_SAS_DEVICE0_ASTATUS_SATA_INIT_FAILED (0x01)
+#define MPI_SAS_DEVICE0_ASTATUS_SATA_CAPABILITY_FAILED (0x02)
+#define MPI_SAS_DEVICE0_ASTATUS_SATA_AFFILIATION_CONFLICT (0x03)
+/* specific values for SATA Init failures */
+#define MPI_SAS_DEVICE0_ASTATUS_SIF_UNKNOWN (0x10)
+#define MPI_SAS_DEVICE0_ASTATUS_SIF_AFFILIATION_CONFLICT (0x11)
+#define MPI_SAS_DEVICE0_ASTATUS_SIF_DIAG (0x12)
+#define MPI_SAS_DEVICE0_ASTATUS_SIF_IDENTIFICATION (0x13)
+#define MPI_SAS_DEVICE0_ASTATUS_SIF_CHECK_POWER (0x14)
+#define MPI_SAS_DEVICE0_ASTATUS_SIF_PIO_SN (0x15)
+#define MPI_SAS_DEVICE0_ASTATUS_SIF_MDMA_SN (0x16)
+#define MPI_SAS_DEVICE0_ASTATUS_SIF_UDMA_SN (0x17)
+#define MPI_SAS_DEVICE0_ASTATUS_SIF_ZONING_VIOLATION (0x18)
+#define MPI_SAS_DEVICE0_ASTATUS_SIF_NOT_ADDRESSABLE (0x19)
+#define MPI_SAS_DEVICE0_ASTATUS_SIF_MAX (0x1F)
/* values for SAS Device Page 0 Flags field */
-#define MPI_SAS_DEVICE0_FLAGS_SATA_SW_PRESERVE (0x0200)
-#define MPI_SAS_DEVICE0_FLAGS_UNSUPPORTED_DEVICE (0x0100)
-#define MPI_SAS_DEVICE0_FLAGS_SATA_48BIT_LBA_SUPPORTED (0x0080)
-#define MPI_SAS_DEVICE0_FLAGS_SATA_SMART_SUPPORTED (0x0040)
-#define MPI_SAS_DEVICE0_FLAGS_SATA_NCQ_SUPPORTED (0x0020)
-#define MPI_SAS_DEVICE0_FLAGS_SATA_FUA_SUPPORTED (0x0010)
-#define MPI_SAS_DEVICE0_FLAGS_PORT_SELECTOR_ATTACH (0x0008)
-#define MPI_SAS_DEVICE0_FLAGS_MAPPING_PERSISTENT (0x0004)
-#define MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED (0x0002)
-#define MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT (0x0001)
+#define MPI_SAS_DEVICE0_FLAGS_SATA_ASYNCHRONOUS_NOTIFY (0x0400)
+#define MPI_SAS_DEVICE0_FLAGS_SATA_SW_PRESERVE (0x0200)
+#define MPI_SAS_DEVICE0_FLAGS_UNSUPPORTED_DEVICE (0x0100)
+#define MPI_SAS_DEVICE0_FLAGS_SATA_48BIT_LBA_SUPPORTED (0x0080)
+#define MPI_SAS_DEVICE0_FLAGS_SATA_SMART_SUPPORTED (0x0040)
+#define MPI_SAS_DEVICE0_FLAGS_SATA_NCQ_SUPPORTED (0x0020)
+#define MPI_SAS_DEVICE0_FLAGS_SATA_FUA_SUPPORTED (0x0010)
+#define MPI_SAS_DEVICE0_FLAGS_PORT_SELECTOR_ATTACH (0x0008)
+#define MPI_SAS_DEVICE0_FLAGS_MAPPING_PERSISTENT (0x0004)
+#define MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED (0x0002)
+#define MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT (0x0001)
/* see mpi_sas.h for values for SAS Device Page 0 DeviceInfo values */
diff --git a/drivers/message/fusion/lsi/mpi_history.txt b/drivers/message/fusion/lsi/mpi_history.txt
index 582cfe7c2aa..d6b4c607453 100644
--- a/drivers/message/fusion/lsi/mpi_history.txt
+++ b/drivers/message/fusion/lsi/mpi_history.txt
@@ -3,28 +3,28 @@
MPI Header File Change History
==============================
- Copyright (c) 2000-2005 LSI Logic Corporation.
+ Copyright (c) 2000-2006 LSI Logic Corporation.
---------------------------------------
- Header Set Release Version: 01.05.13
- Header Set Release Date: 03-27-06
+ Header Set Release Version: 01.05.14
+ Header Set Release Date: 10-11-06
---------------------------------------
Filename Current version Prior version
---------- --------------- -------------
- mpi.h 01.05.11 01.05.10
- mpi_ioc.h 01.05.11 01.05.10
- mpi_cnfg.h 01.05.12 01.05.11
- mpi_init.h 01.05.07 01.05.06
- mpi_targ.h 01.05.06 01.05.05
+ mpi.h 01.05.12 01.05.11
+ mpi_ioc.h 01.05.12 01.05.11
+ mpi_cnfg.h 01.05.13 01.05.12
+ mpi_init.h 01.05.08 01.05.07
+ mpi_targ.h 01.05.06 01.05.06
mpi_fc.h 01.05.01 01.05.01
mpi_lan.h 01.05.01 01.05.01
mpi_raid.h 01.05.02 01.05.02
mpi_tool.h 01.05.03 01.05.03
mpi_inb.h 01.05.01 01.05.01
- mpi_sas.h 01.05.03 01.05.02
+ mpi_sas.h 01.05.04 01.05.03
mpi_type.h 01.05.02 01.05.02
- mpi_history.txt 01.05.13 01.05.12
+ mpi_history.txt 01.05.14 01.05.13
* Date Version Description
@@ -94,6 +94,7 @@ mpi.h
* 08-03-05 01.05.09 Bumped MPI_HEADER_VERSION_UNIT.
* 08-30-05 01.05.10 Added 2 new IOCStatus codes for Target.
* 03-27-06 01.05.11 Bumped MPI_HEADER_VERSION_UNIT.
+ * 10-11-06 01.05.12 Bumped MPI_HEADER_VERSION_UNIT.
* --------------------------------------------------------------------------
mpi_ioc.h
@@ -182,6 +183,14 @@ mpi_ioc.h
* Added MPI_EVENT_SAS_INIT_TABLE_OVERFLOW and event
* data structure.
* Added MPI_EXT_IMAGE_TYPE_INITIALIZATION.
+ * 10-11-06 01.05.12 Added MPI_IOCFACTS_EXCEPT_METADATA_UNSUPPORTED.
+ * Added MaxInitiators field to PortFacts reply.
+ * Added SAS Device Status Change ReasonCode for
+ * asynchronous notificaiton.
+ * Added MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE and event
+ * data structure.
+ * Added new ImageType values for FWDownload and FWUpload
+ * requests.
* --------------------------------------------------------------------------
mpi_cnfg.h
@@ -447,6 +456,23 @@ mpi_cnfg.h
* Added AdditionalControlFlags, MaxTargetPortConnectTime,
* ReportDeviceMissingDelay, and IODeviceMissingDelay
* fields to SAS IO Unit Page 1.
+ * 10-11-06 01.05.13 Added NumForceWWID field and ForceWWID array to
+ * Manufacturing Page 5.
+ * Added Manufacturing pages 8 through 10.
+ * Added defines for supported metadata size bits in
+ * CapabilitiesFlags field of IOC Page 6.
+ * Added defines for metadata size bits in VolumeSettings
+ * field of RAID Volume Page 0.
+ * Added SATA Link Reset settings, Enable SATA Asynchronous
+ * Notification bit, and HideNonZeroAttachedPhyIdentifiers
+ * bit to AdditionalControlFlags field of SAS IO Unit
+ * Page 1.
+ * Added defines for Enclosure Devices Unmapped and
+ * Device Limit Exceeded bits in Status field of SAS IO
+ * Unit Page 2.
+ * Added more AccessStatus values for SAS Device Page 0.
+ * Added bit for SATA Asynchronous Notification Support in
+ * Flags field of SAS Device Page 0.
* --------------------------------------------------------------------------
mpi_init.h
@@ -490,6 +516,7 @@ mpi_init.h
* 08-03-05 01.05.06 Fixed some MPI_SCSIIO32_MSGFLGS_ defines to make them
* unique in the first 32 characters.
* 03-27-06 01.05.07 Added Task Management type of Clear ACA.
+ * 10-11-06 01.05.08 Shortened define for Task Management type of Clear ACA.
* --------------------------------------------------------------------------
mpi_targ.h
@@ -638,6 +665,8 @@ mpi_sas.h
* and Remove Device operations to SAS IO Unit Control.
* Added DevHandle field to SAS IO Unit Control request and
* reply.
+ * 10-11-06 01.05.04 Fixed the name of a define for Operation field of SAS IO
+ * Unit Control request.
* --------------------------------------------------------------------------
mpi_type.h
@@ -653,20 +682,20 @@ mpi_type.h
mpi_history.txt Parts list history
-Filename 01.05.13 01.05.12 01.05.11 01.05.10 01.05.09
----------- -------- -------- -------- -------- --------
-mpi.h 01.05.11 01.05.10 01.05.09 01.05.08 01.05.07
-mpi_ioc.h 01.05.11 01.05.10 01.05.09 01.05.09 01.05.08
-mpi_cnfg.h 01.05.12 01.05.11 01.05.10 01.05.09 01.05.08
-mpi_init.h 01.05.07 01.05.06 01.05.06 01.05.05 01.05.04
-mpi_targ.h 01.05.06 01.05.05 01.05.05 01.05.05 01.05.04
-mpi_fc.h 01.05.01 01.05.01 01.05.01 01.05.01 01.05.01
-mpi_lan.h 01.05.01 01.05.01 01.05.01 01.05.01 01.05.01
-mpi_raid.h 01.05.02 01.05.02 01.05.02 01.05.02 01.05.02
-mpi_tool.h 01.05.03 01.05.03 01.05.03 01.05.03 01.05.03
-mpi_inb.h 01.05.01 01.05.01 01.05.01 01.05.01 01.05.01
-mpi_sas.h 01.05.03 01.05.02 01.05.01 01.05.01 01.05.01
-mpi_type.h 01.05.02 01.05.02 01.05.01 01.05.01 01.05.01
+Filename 01.05.13 01.05.13 01.05.12 01.05.11 01.05.10 01.05.09
+---------- -------- -------- -------- -------- -------- --------
+mpi.h 01.05.12 01.05.11 01.05.10 01.05.09 01.05.08 01.05.07
+mpi_ioc.h 01.05.12 01.05.11 01.05.10 01.05.09 01.05.09 01.05.08
+mpi_cnfg.h 01.05.13 01.05.12 01.05.11 01.05.10 01.05.09 01.05.08
+mpi_init.h 01.05.08 01.05.07 01.05.06 01.05.06 01.05.05 01.05.04
+mpi_targ.h 01.05.06 01.05.06 01.05.05 01.05.05 01.05.05 01.05.04
+mpi_fc.h 01.05.01 01.05.01 01.05.01 01.05.01 01.05.01 01.05.01
+mpi_lan.h 01.05.01 01.05.01 01.05.01 01.05.01 01.05.01 01.05.01
+mpi_raid.h 01.05.02 01.05.02 01.05.02 01.05.02 01.05.02 01.05.02
+mpi_tool.h 01.05.03 01.05.03 01.05.03 01.05.03 01.05.03 01.05.03
+mpi_inb.h 01.05.01 01.05.01 01.05.01 01.05.01 01.05.01 01.05.01
+mpi_sas.h 01.05.04 01.05.03 01.05.02 01.05.01 01.05.01 01.05.01
+mpi_type.h 01.05.02 01.05.02 01.05.02 01.05.01 01.05.01 01.05.01
Filename 01.05.08 01.05.07 01.05.06 01.05.05 01.05.04 01.05.03
---------- -------- -------- -------- -------- -------- --------
diff --git a/drivers/message/fusion/lsi/mpi_init.h b/drivers/message/fusion/lsi/mpi_init.h
index c1c678989a2..ec9dff2249a 100644
--- a/drivers/message/fusion/lsi/mpi_init.h
+++ b/drivers/message/fusion/lsi/mpi_init.h
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2000-2005 LSI Logic Corporation.
+ * Copyright (c) 2000-2006 LSI Logic Corporation.
*
*
* Name: mpi_init.h
* Title: MPI initiator mode messages and structures
* Creation Date: June 8, 2000
*
- * mpi_init.h Version: 01.05.07
+ * mpi_init.h Version: 01.05.08
*
* Version History
* ---------------
@@ -53,6 +53,7 @@
* 08-03-05 01.05.06 Fixed some MPI_SCSIIO32_MSGFLGS_ defines to make them
* unique in the first 32 characters.
* 03-27-06 01.05.07 Added Task Management type of Clear ACA.
+ * 10-11-06 01.05.08 Shortened define for Task Management type of Clear ACA.
* --------------------------------------------------------------------------
*/
@@ -428,7 +429,7 @@ typedef struct _MSG_SCSI_TASK_MGMT
#define MPI_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET (0x05)
#define MPI_SCSITASKMGMT_TASKTYPE_CLEAR_TASK_SET (0x06)
#define MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK (0x07)
-#define MPI_SCSITASKMGMT_TASKTYPE_CLEAR_ACA (0x08)
+#define MPI_SCSITASKMGMT_TASKTYPE_CLR_ACA (0x08)
/* MsgFlags bits */
#define MPI_SCSITASKMGMT_MSGFLAGS_TARGET_RESET_OPTION (0x00)
diff --git a/drivers/message/fusion/lsi/mpi_ioc.h b/drivers/message/fusion/lsi/mpi_ioc.h
index 18ba407fd39..6c33e335337 100644
--- a/drivers/message/fusion/lsi/mpi_ioc.h
+++ b/drivers/message/fusion/lsi/mpi_ioc.h
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2000-2005 LSI Logic Corporation.
+ * Copyright (c) 2000-2006 LSI Logic Corporation.
*
*
* Name: mpi_ioc.h
* Title: MPI IOC, Port, Event, FW Download, and FW Upload messages
* Creation Date: August 11, 2000
*
- * mpi_ioc.h Version: 01.05.11
+ * mpi_ioc.h Version: 01.05.12
*
* Version History
* ---------------
@@ -98,6 +98,14 @@
* Added MPI_EVENT_SAS_INIT_TABLE_OVERFLOW and event
* data structure.
* Added MPI_EXT_IMAGE_TYPE_INITIALIZATION.
+ * 10-11-06 01.05.12 Added MPI_IOCFACTS_EXCEPT_METADATA_UNSUPPORTED.
+ * Added MaxInitiators field to PortFacts reply.
+ * Added SAS Device Status Change ReasonCode for
+ * asynchronous notificaiton.
+ * Added MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE and event
+ * data structure.
+ * Added new ImageType values for FWDownload and FWUpload
+ * requests.
* --------------------------------------------------------------------------
*/
@@ -264,6 +272,7 @@ typedef struct _MSG_IOC_FACTS_REPLY
#define MPI_IOCFACTS_EXCEPT_RAID_CONFIG_INVALID (0x0002)
#define MPI_IOCFACTS_EXCEPT_FW_CHECKSUM_FAIL (0x0004)
#define MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL (0x0008)
+#define MPI_IOCFACTS_EXCEPT_METADATA_UNSUPPORTED (0x0010)
#define MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT (0x01)
#define MPI_IOCFACTS_FLAGS_REPLY_FIFO_HOST_SIGNAL (0x02)
@@ -328,7 +337,8 @@ typedef struct _MSG_PORT_FACTS_REPLY
U16 MaxPostedCmdBuffers; /* 1Ch */
U16 MaxPersistentIDs; /* 1Eh */
U16 MaxLanBuckets; /* 20h */
- U16 Reserved4; /* 22h */
+ U8 MaxInitiators; /* 22h */
+ U8 Reserved4; /* 23h */
U32 Reserved5; /* 24h */
} MSG_PORT_FACTS_REPLY, MPI_POINTER PTR_MSG_PORT_FACTS_REPLY,
PortFactsReply_t, MPI_POINTER pPortFactsReply_t;
@@ -487,6 +497,7 @@ typedef struct _MSG_EVENT_ACK_REPLY
#define MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE (0x00000018)
#define MPI_EVENT_SAS_INIT_TABLE_OVERFLOW (0x00000019)
#define MPI_EVENT_SAS_SMP_ERROR (0x0000001A)
+#define MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE (0x0000001B)
#define MPI_EVENT_LOG_ENTRY_ADDED (0x00000021)
/* AckRequired field values */
@@ -593,6 +604,7 @@ typedef struct _EVENT_DATA_SAS_DEVICE_STATUS_CHANGE
#define MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL (0x0A)
#define MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL (0x0B)
#define MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL (0x0C)
+#define MPI_EVENT_SAS_DEV_STAT_RC_ASYNC_NOTIFICATION (0x0D)
/* SCSI Event data for Queue Full event */
@@ -895,6 +907,54 @@ typedef struct _EVENT_DATA_SAS_INIT_TABLE_OVERFLOW
MpiEventDataSasInitTableOverflow_t,
MPI_POINTER pMpiEventDataSasInitTableOverflow_t;
+/* SAS Expander Status Change Event data */
+
+typedef struct _EVENT_DATA_SAS_EXPANDER_STATUS_CHANGE
+{
+ U8 ReasonCode; /* 00h */
+ U8 Reserved1; /* 01h */
+ U16 Reserved2; /* 02h */
+ U8 PhysicalPort; /* 04h */
+ U8 Reserved3; /* 05h */
+ U16 EnclosureHandle; /* 06h */
+ U64 SASAddress; /* 08h */
+ U32 DiscoveryStatus; /* 10h */
+ U16 DevHandle; /* 14h */
+ U16 ParentDevHandle; /* 16h */
+ U16 ExpanderChangeCount; /* 18h */
+ U16 ExpanderRouteIndexes; /* 1Ah */
+ U8 NumPhys; /* 1Ch */
+ U8 SASLevel; /* 1Dh */
+ U8 Flags; /* 1Eh */
+ U8 Reserved4; /* 1Fh */
+} EVENT_DATA_SAS_EXPANDER_STATUS_CHANGE,
+ MPI_POINTER PTR_EVENT_DATA_SAS_EXPANDER_STATUS_CHANGE,
+ MpiEventDataSasExpanderStatusChange_t,
+ MPI_POINTER pMpiEventDataSasExpanderStatusChange_t;
+
+/* values for ReasonCode field of SAS Expander Status Change Event data */
+#define MPI_EVENT_SAS_EXP_RC_ADDED (0x00)
+#define MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING (0x01)
+
+/* values for DiscoveryStatus field of SAS Expander Status Change Event data */
+#define MPI_EVENT_SAS_EXP_DS_LOOP_DETECTED (0x00000001)
+#define MPI_EVENT_SAS_EXP_DS_UNADDRESSABLE_DEVICE (0x00000002)
+#define MPI_EVENT_SAS_EXP_DS_MULTIPLE_PORTS (0x00000004)
+#define MPI_EVENT_SAS_EXP_DS_EXPANDER_ERR (0x00000008)
+#define MPI_EVENT_SAS_EXP_DS_SMP_TIMEOUT (0x00000010)
+#define MPI_EVENT_SAS_EXP_DS_OUT_ROUTE_ENTRIES (0x00000020)
+#define MPI_EVENT_SAS_EXP_DS_INDEX_NOT_EXIST (0x00000040)
+#define MPI_EVENT_SAS_EXP_DS_SMP_FUNCTION_FAILED (0x00000080)
+#define MPI_EVENT_SAS_EXP_DS_SMP_CRC_ERROR (0x00000100)
+#define MPI_EVENT_SAS_EXP_DS_SUBTRACTIVE_LINK (0x00000200)
+#define MPI_EVENT_SAS_EXP_DS_TABLE_LINK (0x00000400)
+#define MPI_EVENT_SAS_EXP_DS_UNSUPPORTED_DEVICE (0x00000800)
+
+/* values for Flags field of SAS Expander Status Change Event data */
+#define MPI_EVENT_SAS_EXP_FLAGS_ROUTE_TABLE_CONFIG (0x02)
+#define MPI_EVENT_SAS_EXP_FLAGS_CONFIG_IN_PROGRESS (0x01)
+
+
/*****************************************************************************
*
@@ -926,6 +986,10 @@ typedef struct _MSG_FW_DOWNLOAD
#define MPI_FW_DOWNLOAD_ITYPE_BIOS (0x02)
#define MPI_FW_DOWNLOAD_ITYPE_NVDATA (0x03)
#define MPI_FW_DOWNLOAD_ITYPE_BOOTLOADER (0x04)
+#define MPI_FW_DOWNLOAD_ITYPE_MANUFACTURING (0x06)
+#define MPI_FW_DOWNLOAD_ITYPE_CONFIG_1 (0x07)
+#define MPI_FW_DOWNLOAD_ITYPE_CONFIG_2 (0x08)
+#define MPI_FW_DOWNLOAD_ITYPE_MEGARAID (0x09)
typedef struct _FWDownloadTCSGE
@@ -980,6 +1044,11 @@ typedef struct _MSG_FW_UPLOAD
#define MPI_FW_UPLOAD_ITYPE_NVDATA (0x03)
#define MPI_FW_UPLOAD_ITYPE_BOOTLOADER (0x04)
#define MPI_FW_UPLOAD_ITYPE_FW_BACKUP (0x05)
+#define MPI_FW_UPLOAD_ITYPE_MANUFACTURING (0x06)
+#define MPI_FW_UPLOAD_ITYPE_CONFIG_1 (0x07)
+#define MPI_FW_UPLOAD_ITYPE_CONFIG_2 (0x08)
+#define MPI_FW_UPLOAD_ITYPE_MEGARAID (0x09)
+#define MPI_FW_UPLOAD_ITYPE_COMPLETE (0x0A)
typedef struct _FWUploadTCSGE
{
diff --git a/drivers/message/fusion/lsi/mpi_log_sas.h b/drivers/message/fusion/lsi/mpi_log_sas.h
index 871ebc08b70..635bbe04513 100644
--- a/drivers/message/fusion/lsi/mpi_log_sas.h
+++ b/drivers/message/fusion/lsi/mpi_log_sas.h
@@ -1,4 +1,3 @@
-
/***************************************************************************
* *
* Copyright 2003 LSI Logic Corporation. All rights reserved. *
@@ -14,7 +13,7 @@
#define IOPI_IOCLOGINFO_H_INCLUDED
#define SAS_LOGINFO_NEXUS_LOSS 0x31170000
-#define SAS_LOGINFO_MASK 0xFFFF0000
+#define SAS_LOGINFO_MASK 0xFFFF0000
/****************************************************************************/
/* IOC LOGINFO defines, 0x00000000 - 0x0FFFFFFF */
@@ -43,129 +42,172 @@
/****************************************************************************/
/* IOP LOGINFO_CODE defines, valid if IOC_LOGINFO_ORIGINATOR = IOP */
/****************************************************************************/
-#define IOP_LOGINFO_CODE_INVALID_SAS_ADDRESS (0x00010000)
-#define IOP_LOGINFO_CODE_UNUSED2 (0x00020000)
-#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE (0x00030000)
-#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_RT (0x00030100) /* Route Table Entry not found */
-#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_PN (0x00030200) /* Invalid Page Number */
-#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_FORM (0x00030300) /* Invalid FORM */
-#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_PT (0x00030400) /* Invalid Page Type */
-#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_DNM (0x00030500) /* Device Not Mapped */
-#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_PERSIST (0x00030600) /* Persistent Page not found */
-#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_DEFAULT (0x00030700) /* Default Page not found */
-
-#define IOP_LOGINFO_CODE_DIAG_MSG_ERROR (0x00040000) /* Error handling diag msg - or'd with diag status */
-
-#define IOP_LOGINFO_CODE_TASK_TERMINATED (0x00050000)
-
-#define IOP_LOGINFO_CODE_ENCL_MGMT_READ_ACTION_ERR0R (0x00060001) /* Read Action not supported for SEP msg */
-#define IOP_LOGINFO_CODE_ENCL_MGMT_INVALID_BUS_ID_ERR0R (0x00060002) /* Invalid Bus/ID in SEP msg */
-
-#define IOP_LOGINFO_CODE_TARGET_ASSIST_TERMINATED (0x00070001)
-#define IOP_LOGINFO_CODE_TARGET_STATUS_SEND_TERMINATED (0x00070002)
-#define IOP_LOGINFO_CODE_TARGET_MODE_ABORT_ALL_IO (0x00070003)
-#define IOP_LOGINFO_CODE_TARGET_MODE_ABORT_EXACT_IO (0x00070004)
-#define IOP_LOGINFO_CODE_TARGET_MODE_ABORT_EXACT_IO_REQ (0x00070005)
+#define IOP_LOGINFO_CODE_INVALID_SAS_ADDRESS (0x00010000)
+#define IOP_LOGINFO_CODE_UNUSED2 (0x00020000)
+#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE (0x00030000)
+#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_RT (0x00030100) /* Route Table Entry not found */
+#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_PN (0x00030200) /* Invalid Page Number */
+#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_FORM (0x00030300) /* Invalid FORM */
+#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_PT (0x00030400) /* Invalid Page Type */
+#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_DNM (0x00030500) /* Device Not Mapped */
+#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_PERSIST (0x00030600) /* Persistent Page not found */
+#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_DEFAULT (0x00030700) /* Default Page not found */
+
+#define IOP_LOGINFO_CODE_FWUPLOAD_NO_FLASH_AVAILABLE (0x0003E000) /* Tried to upload from flash, but there is none */
+#define IOP_LOGINFO_CODE_FWUPLOAD_UNKNOWN_IMAGE_TYPE (0x0003E001) /* ImageType field contents were invalid */
+#define IOP_LOGINFO_CODE_FWUPLOAD_WRONG_IMAGE_SIZE (0x0003E002) /* ImageSize field in TCSGE was bad/offset in MfgPg 4 was wrong */
+#define IOP_LOGINFO_CODE_FWUPLOAD_ENTIRE_FLASH_UPLOAD_FAILED (0x0003E003) /* Error occured while attempting to upload the entire flash */
+#define IOP_LOGINFO_CODE_FWUPLOAD_REGION_UPLOAD_FAILED (0x0003E004) /* Error occured while attempting to upload single flash region */
+#define IOP_LOGINFO_CODE_FWUPLOAD_DMA_FAILURE (0x0003E005) /* Problem occured while DMAing FW to host memory */
+
+#define IOP_LOGINFO_CODE_DIAG_MSG_ERROR (0x00040000) /* Error handling diag msg - or'd with diag status */
+
+#define IOP_LOGINFO_CODE_TASK_TERMINATED (0x00050000)
+
+#define IOP_LOGINFO_CODE_ENCL_MGMT_READ_ACTION_ERR0R (0x00060001) /* Read Action not supported for SEP msg */
+#define IOP_LOGINFO_CODE_ENCL_MGMT_INVALID_BUS_ID_ERR0R (0x00060002) /* Invalid Bus/ID in SEP msg */
+
+#define IOP_LOGINFO_CODE_TARGET_ASSIST_TERMINATED (0x00070001)
+#define IOP_LOGINFO_CODE_TARGET_STATUS_SEND_TERMINATED (0x00070002)
+#define IOP_LOGINFO_CODE_TARGET_MODE_ABORT_ALL_IO (0x00070003)
+#define IOP_LOGINFO_CODE_TARGET_MODE_ABORT_EXACT_IO (0x00070004)
+#define IOP_LOGINFO_CODE_TARGET_MODE_ABORT_EXACT_IO_REQ (0x00070005)
/****************************************************************************/
/* PL LOGINFO_CODE defines, valid if IOC_LOGINFO_ORIGINATOR = PL */
/****************************************************************************/
-#define PL_LOGINFO_CODE_OPEN_FAILURE (0x00010000)
-#define PL_LOG_INFO_CODE_OPEN_FAILURE_NO_DEST_TIME_OUT (0x00010001)
-#define PL_LOGINFO_CODE_OPEN_FAILURE_BAD_DESTINATION (0x00010011)
-#define PL_LOGINFO_CODE_OPEN_FAILURE_PROTOCOL_NOT_SUPPORTED (0x00010013)
-#define PL_LOGINFO_CODE_OPEN_FAILURE_STP_RESOURCES_BSY (0x00010018)
-#define PL_LOGINFO_CODE_OPEN_FAILURE_WRONG_DESTINATION (0x00010019)
-#define PL_LOGINFO_CODE_OPEN_FAILURE_ORR_TIMEOUT (0X0001001A)
-#define PL_LOGINFO_CODE_OPEN_FAILURE_PATHWAY_BLOCKED (0x0001001B)
-#define PL_LOGINFO_CODE_OPEN_FAILURE_AWT_MAXED (0x0001001C)
-#define PL_LOGINFO_CODE_INVALID_SGL (0x00020000)
-#define PL_LOGINFO_CODE_WRONG_REL_OFF_OR_FRAME_LENGTH (0x00030000)
-#define PL_LOGINFO_CODE_FRAME_XFER_ERROR (0x00040000)
-#define PL_LOGINFO_CODE_TX_FM_CONNECTED_LOW (0x00050000)
-#define PL_LOGINFO_CODE_SATA_NON_NCQ_RW_ERR_BIT_SET (0x00060000)
-#define PL_LOGINFO_CODE_SATA_READ_LOG_RECEIVE_DATA_ERR (0x00070000)
-#define PL_LOGINFO_CODE_SATA_NCQ_FAIL_ALL_CMDS_AFTR_ERR (0x00080000)
-#define PL_LOGINFO_CODE_SATA_ERR_IN_RCV_SET_DEV_BIT_FIS (0x00090000)
-#define PL_LOGINFO_CODE_RX_FM_INVALID_MESSAGE (0x000A0000)
-#define PL_LOGINFO_CODE_RX_CTX_MESSAGE_VALID_ERROR (0x000B0000)
-#define PL_LOGINFO_CODE_RX_FM_CURRENT_FRAME_ERROR (0x000C0000)
-#define PL_LOGINFO_CODE_SATA_LINK_DOWN (0x000D0000)
-#define PL_LOGINFO_CODE_DISCOVERY_SATA_INIT_W_IOS (0x000E0000)
-#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE (0x000F0000)
-#define PL_LOGINFO_CODE_CONFIG_PL_NOT_INITIALIZED (0x000F0001) /* PL not yet initialized, can't do config page req. */
-#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_PT (0x000F0100) /* Invalid Page Type */
-#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_NUM_PHYS (0x000F0200) /* Invalid Number of Phys */
-#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_NOT_IMP (0x000F0300) /* Case Not Handled */
-#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_NO_DEV (0x000F0400) /* No Device Found */
-#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_FORM (0x000F0500) /* Invalid FORM */
-#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_PHY (0x000F0600) /* Invalid Phy */
-#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_NO_OWNER (0x000F0700) /* No Owner Found */
-#define PL_LOGINFO_CODE_DSCVRY_SATA_INIT_TIMEOUT (0x00100000)
-#define PL_LOGINFO_CODE_RESET (0x00110000) /* See Sub-Codes below */
-#define PL_LOGINFO_CODE_ABORT (0x00120000) /* See Sub-Codes below */
-#define PL_LOGINFO_CODE_IO_NOT_YET_EXECUTED (0x00130000)
-#define PL_LOGINFO_CODE_IO_EXECUTED (0x00140000)
-#define PL_LOGINFO_CODE_PERS_RESV_OUT_NOT_AFFIL_OWNER (0x00150000)
-#define PL_LOGINFO_CODE_OPEN_TXDMA_ABORT (0x00160000)
-#define PL_LOGINFO_CODE_IO_DEVICE_MISSING_DELAY_RETRY (0x00170000)
-#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE (0x00000100)
-#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_NO_DEST_TIMEOUT (0x00000101)
-#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_ORR_TIMEOUT (0x0000011A) /* Open Reject (Retry) Timeout */
-#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_PATHWAY_BLOCKED (0x0000011B)
-#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_AWT_MAXED (0x0000011C) /* Arbitration Wait Timer Maxed */
-
-#define PL_LOGINFO_SUB_CODE_TARGET_BUS_RESET (0x00000120)
-#define PL_LOGINFO_SUB_CODE_TRANSPORT_LAYER (0x00000130) /* Leave lower nibble (1-f) reserved. */
-#define PL_LOGINFO_SUB_CODE_PORT_LAYER (0x00000140) /* Leave lower nibble (1-f) reserved. */
-
-
-#define PL_LOGINFO_SUB_CODE_INVALID_SGL (0x00000200)
-#define PL_LOGINFO_SUB_CODE_WRONG_REL_OFF_OR_FRAME_LENGTH (0x00000300)
-#define PL_LOGINFO_SUB_CODE_FRAME_XFER_ERROR (0x00000400)
-#define PL_LOGINFO_SUB_CODE_TX_FM_CONNECTED_LOW (0x00000500)
-#define PL_LOGINFO_SUB_CODE_SATA_NON_NCQ_RW_ERR_BIT_SET (0x00000600)
-#define PL_LOGINFO_SUB_CODE_SATA_READ_LOG_RECEIVE_DATA_ERR (0x00000700)
-#define PL_LOGINFO_SUB_CODE_SATA_NCQ_FAIL_ALL_CMDS_AFTR_ERR (0x00000800)
-#define PL_LOGINFO_SUB_CODE_SATA_ERR_IN_RCV_SET_DEV_BIT_FIS (0x00000900)
-#define PL_LOGINFO_SUB_CODE_RX_FM_INVALID_MESSAGE (0x00000A00)
-#define PL_LOGINFO_SUB_CODE_RX_CTX_MESSAGE_VALID_ERROR (0x00000B00)
-#define PL_LOGINFO_SUB_CODE_RX_FM_CURRENT_FRAME_ERROR (0x00000C00)
-#define PL_LOGINFO_SUB_CODE_SATA_LINK_DOWN (0x00000D00)
-#define PL_LOGINFO_SUB_CODE_DISCOVERY_SATA_INIT_W_IOS (0x00000E00)
-#define PL_LOGINFO_SUB_CODE_DISCOVERY_REMOTE_SEP_RESET (0x00000E01)
-#define PL_LOGINFO_SUB_CODE_SECOND_OPEN (0x00000F00)
-#define PL_LOGINFO_SUB_CODE_DSCVRY_SATA_INIT_TIMEOUT (0x00001000)
-
-
-#define PL_LOGINFO_CODE_ENCL_MGMT_SMP_FRAME_FAILURE (0x00200000) /* Can't get SMP Frame */
-#define PL_LOGINFO_CODE_ENCL_MGMT_SMP_READ_ERROR (0x00200010) /* Error occured on SMP Read */
-#define PL_LOGINFO_CODE_ENCL_MGMT_SMP_WRITE_ERROR (0x00200020) /* Error occured on SMP Write */
-#define PL_LOGINFO_CODE_ENCL_MGMT_NOT_SUPPORTED_ON_ENCL (0x00200040) /* Encl Mgmt services not available for this WWID */
-#define PL_LOGINFO_CODE_ENCL_MGMT_ADDR_MODE_NOT_SUPPORTED (0x00200050) /* Address Mode not suppored */
-#define PL_LOGINFO_CODE_ENCL_MGMT_BAD_SLOT_NUM (0x00200060) /* Invalid Slot Number in SEP Msg */
-#define PL_LOGINFO_CODE_ENCL_MGMT_SGPIO_NOT_PRESENT (0x00200070) /* SGPIO not present/enabled */
-#define PL_LOGINFO_CODE_ENCL_MGMT_GPIO_NOT_CONFIGURED (0x00200080) /* GPIO not configured */
-#define PL_LOGINFO_CODE_ENCL_MGMT_GPIO_FRAME_ERROR (0x00200090) /* GPIO can't allocate a frame */
-#define PL_LOGINFO_CODE_ENCL_MGMT_GPIO_CONFIG_PAGE_ERROR (0x002000A0) /* GPIO failed config page request */
-#define PL_LOGINFO_CODE_ENCL_MGMT_SES_FRAME_ALLOC_ERROR (0x002000B0) /* Can't get frame for SES command */
-#define PL_LOGINFO_CODE_ENCL_MGMT_SES_IO_ERROR (0x002000C0) /* I/O execution error */
-#define PL_LOGINFO_CODE_ENCL_MGMT_SES_RETRIES_EXHAUSTED (0x002000D0) /* SEP I/O retries exhausted */
-#define PL_LOGINFO_CODE_ENCL_MGMT_SMP_FRAME_ALLOC_ERROR (0x002000E0) /* Can't get frame for SMP command */
-
-#define PL_LOGINFO_DA_SEP_NOT_PRESENT (0x00200100) /* SEP not present when msg received */
-#define PL_LOGINFO_DA_SEP_SINGLE_THREAD_ERROR (0x00200101) /* Can only accept 1 msg at a time */
-#define PL_LOGINFO_DA_SEP_ISTWI_INTR_IN_IDLE_STATE (0x00200102) /* ISTWI interrupt recvd. while IDLE */
-#define PL_LOGINFO_DA_SEP_RECEIVED_NACK_FROM_SLAVE (0x00200103) /* SEP NACK'd, it is busy */
-#define PL_LOGINFO_DA_SEP_DID_NOT_RECEIVE_ACK (0x00200104) /* SEP didn't rcv. ACK (Last Rcvd Bit = 1) */
-#define PL_LOGINFO_DA_SEP_BAD_STATUS_HDR_CHKSUM (0x00200105) /* SEP stopped or sent bad chksum in Hdr */
-#define PL_LOGINFO_DA_SEP_STOP_ON_DATA (0x00200106) /* SEP stopped while transfering data */
-#define PL_LOGINFO_DA_SEP_STOP_ON_SENSE_DATA (0x00200107) /* SEP stopped while transfering sense data */
-#define PL_LOGINFO_DA_SEP_UNSUPPORTED_SCSI_STATUS_1 (0x00200108) /* SEP returned unknown scsi status */
-#define PL_LOGINFO_DA_SEP_UNSUPPORTED_SCSI_STATUS_2 (0x00200109) /* SEP returned unknown scsi status */
-#define PL_LOGINFO_DA_SEP_CHKSUM_ERROR_AFTER_STOP (0x0020010A) /* SEP returned bad chksum after STOP */
-#define PL_LOGINFO_DA_SEP_CHKSUM_ERROR_AFTER_STOP_GETDATA (0x0020010B) /* SEP returned bad chksum after STOP while gettin data*/
-#define PL_LOGINFO_DA_SEP_UNSUPPORTED_COMMAND (0x0020010C) /* SEP doesn't support CDB opcode */
+#define PL_LOGINFO_CODE_OPEN_FAILURE (0x00010000) /* see SUB_CODE_OPEN_FAIL_ below */
+
+#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_NO_DEST_TIME_OUT (0x00000001)
+#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_PATHWAY_BLOCKED (0x00000002)
+#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_RES_CONTINUE0 (0x00000003)
+#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_RES_CONTINUE1 (0x00000004)
+#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_RES_INITIALIZE0 (0x00000005)
+#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_RES_INITIALIZE1 (0x00000006)
+#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_RES_STOP0 (0x00000007)
+#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_RES_STOP1 (0x00000008)
+#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_RETRY (0x00000009)
+#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_BREAK (0x0000000A)
+#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_UNUSED_0B (0x0000000B)
+#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_OPEN_TIMEOUT_EXP (0x0000000C)
+#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_UNUSED_0D (0x0000000D)
+#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_DVTBLE_ACCSS_FAIL (0x0000000E)
+#define PL_LOGINFO_SUB CODE_OPEN_FAIL_BAD_DEST (0x00000011)
+#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_RATE_NOT_SUPP (0x00000012)
+#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_PROT_NOT_SUPP (0x00000013)
+#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_RESERVED_ABANDON0 (0x00000014)
+#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_RESERVED_ABANDON1 (0x00000015)
+#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_RESERVED_ABANDON2 (0x00000016)
+#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_RESERVED_ABANDON3 (0x00000017)
+#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_STP_RESOURCES_BSY (0x00000018)
+#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_WRONG_DESTINATION (0x00000019)
+
+#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_PATH_BLOCKED (0x0000001B) /* Retry Timeout */
+#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_AWT_MAXED (0x0000001C) /* Retry Timeout */
+
+
+
+#define PL_LOGINFO_CODE_INVALID_SGL (0x00020000)
+#define PL_LOGINFO_CODE_WRONG_REL_OFF_OR_FRAME_LENGTH (0x00030000)
+#define PL_LOGINFO_CODE_FRAME_XFER_ERROR (0x00040000)
+#define PL_LOGINFO_CODE_TX_FM_CONNECTED_LOW (0x00050000)
+#define PL_LOGINFO_CODE_SATA_NON_NCQ_RW_ERR_BIT_SET (0x00060000)
+#define PL_LOGINFO_CODE_SATA_READ_LOG_RECEIVE_DATA_ERR (0x00070000)
+#define PL_LOGINFO_CODE_SATA_NCQ_FAIL_ALL_CMDS_AFTR_ERR (0x00080000)
+#define PL_LOGINFO_CODE_SATA_ERR_IN_RCV_SET_DEV_BIT_FIS (0x00090000)
+#define PL_LOGINFO_CODE_RX_FM_INVALID_MESSAGE (0x000A0000)
+#define PL_LOGINFO_CODE_RX_CTX_MESSAGE_VALID_ERROR (0x000B0000)
+#define PL_LOGINFO_CODE_RX_FM_CURRENT_FRAME_ERROR (0x000C0000)
+#define PL_LOGINFO_CODE_SATA_LINK_DOWN (0x000D0000)
+#define PL_LOGINFO_CODE_DISCOVERY_SATA_INIT_W_IOS (0x000E0000)
+#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE (0x000F0000)
+#define PL_LOGINFO_CODE_CONFIG_PL_NOT_INITIALIZED (0x000F0001) /* PL not yet initialized, can't do config page req. */
+#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_PT (0x000F0100) /* Invalid Page Type */
+#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_NUM_PHYS (0x000F0200) /* Invalid Number of Phys */
+#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_NOT_IMP (0x000F0300) /* Case Not Handled */
+#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_NO_DEV (0x000F0400) /* No Device Found */
+#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_FORM (0x000F0500) /* Invalid FORM */
+#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_PHY (0x000F0600) /* Invalid Phy */
+#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_NO_OWNER (0x000F0700) /* No Owner Found */
+#define PL_LOGINFO_CODE_DSCVRY_SATA_INIT_TIMEOUT (0x00100000)
+#define PL_LOGINFO_CODE_RESET (0x00110000) /* See Sub-Codes below (PL_LOGINFO_SUB_CODE) */
+#define PL_LOGINFO_CODE_ABORT (0x00120000) /* See Sub-Codes below (PL_LOGINFO_SUB_CODE)*/
+#define PL_LOGINFO_CODE_IO_NOT_YET_EXECUTED (0x00130000)
+#define PL_LOGINFO_CODE_IO_EXECUTED (0x00140000)
+#define PL_LOGINFO_CODE_PERS_RESV_OUT_NOT_AFFIL_OWNER (0x00150000)
+#define PL_LOGINFO_CODE_OPEN_TXDMA_ABORT (0x00160000)
+#define PL_LOGINFO_CODE_IO_DEVICE_MISSING_DELAY_RETRY (0x00170000)
+#define PL_LOGINFO_CODE_IO_CANCELLED_DUE_TO_R_ERR (0x00180000)
+#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE (0x00000100)
+#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_NO_DEST_TIMEOUT (0x00000101)
+#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_SATA_NEG_RATE_2HI (0x00000102)
+#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_RATE_NOT_SUPPORTED (0x00000103)
+#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_BREAK (0x00000104)
+#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_ZONE_VIOLATION (0x00000114)
+#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_ABANDON0 (0x00000114) /* Open Reject (Zone Violation) - available on SAS-2 devices */
+#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_ABANDON1 (0x00000115)
+#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_ABANDON2 (0x00000116)
+#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_ABANDON3 (0x00000117)
+#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_ORR_TIMEOUT (0x0000011A) /* Open Reject (Retry) Timeout */
+#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_PATH_BLOCKED (0x0000011B)
+#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_AWT_MAXED (0x0000011C) /* Arbitration Wait Timer Maxed */
+
+#define PL_LOGINFO_SUB_CODE_TARGET_BUS_RESET (0x00000120)
+#define PL_LOGINFO_SUB_CODE_TRANSPORT_LAYER (0x00000130) /* Leave lower nibble (1-f) reserved. */
+#define PL_LOGINFO_SUB_CODE_PORT_LAYER (0x00000140) /* Leave lower nibble (1-f) reserved. */
+
+
+#define PL_LOGINFO_SUB_CODE_INVALID_SGL (0x00000200)
+#define PL_LOGINFO_SUB_CODE_WRONG_REL_OFF_OR_FRAME_LENGTH (0x00000300)
+#define PL_LOGINFO_SUB_CODE_FRAME_XFER_ERROR (0x00000400) /* Bits 0-3 encode Transport Status Register (offset 0x08) */
+ /* Bit 0 is Status Bit 0: FrameXferErr */
+ /* Bit 1 & 2 are Status Bits 16 and 17: FrameXmitErrStatus */
+ /* Bit 3 is Status Bit 18 WriteDataLenghtGTDataLengthErr */
+
+#define PL_LOGINFO_SUB_CODE_TX_FM_CONNECTED_LOW (0x00000500)
+#define PL_LOGINFO_SUB_CODE_SATA_NON_NCQ_RW_ERR_BIT_SET (0x00000600)
+#define PL_LOGINFO_SUB_CODE_SATA_READ_LOG_RECEIVE_DATA_ERR (0x00000700)
+#define PL_LOGINFO_SUB_CODE_SATA_NCQ_FAIL_ALL_CMDS_AFTR_ERR (0x00000800)
+#define PL_LOGINFO_SUB_CODE_SATA_ERR_IN_RCV_SET_DEV_BIT_FIS (0x00000900)
+#define PL_LOGINFO_SUB_CODE_RX_FM_INVALID_MESSAGE (0x00000A00)
+#define PL_LOGINFO_SUB_CODE_RX_CTX_MESSAGE_VALID_ERROR (0x00000B00)
+#define PL_LOGINFO_SUB_CODE_RX_FM_CURRENT_FRAME_ERROR (0x00000C00)
+#define PL_LOGINFO_SUB_CODE_SATA_LINK_DOWN (0x00000D00)
+#define PL_LOGINFO_SUB_CODE_DISCOVERY_SATA_INIT_W_IOS (0x00000E00)
+#define PL_LOGINFO_SUB_CODE_DISCOVERY_REMOTE_SEP_RESET (0x00000E01)
+#define PL_LOGINFO_SUB_CODE_SECOND_OPEN (0x00000F00)
+#define PL_LOGINFO_SUB_CODE_DSCVRY_SATA_INIT_TIMEOUT (0x00001000)
+
+#define PL_LOGINFO_CODE_ENCL_MGMT_SMP_FRAME_FAILURE (0x00200000) /* Can't get SMP Frame */
+#define PL_LOGINFO_CODE_ENCL_MGMT_SMP_READ_ERROR (0x00200010) /* Error occured on SMP Read */
+#define PL_LOGINFO_CODE_ENCL_MGMT_SMP_WRITE_ERROR (0x00200020) /* Error occured on SMP Write */
+#define PL_LOGINFO_CODE_ENCL_MGMT_NOT_SUPPORTED_ON_ENCL (0x00200040) /* Encl Mgmt services not available for this WWID */
+#define PL_LOGINFO_CODE_ENCL_MGMT_ADDR_MODE_NOT_SUPPORTED (0x00200050) /* Address Mode not suppored */
+#define PL_LOGINFO_CODE_ENCL_MGMT_BAD_SLOT_NUM (0x00200060) /* Invalid Slot Number in SEP Msg */
+#define PL_LOGINFO_CODE_ENCL_MGMT_SGPIO_NOT_PRESENT (0x00200070) /* SGPIO not present/enabled */
+#define PL_LOGINFO_CODE_ENCL_MGMT_GPIO_NOT_CONFIGURED (0x00200080) /* GPIO not configured */
+#define PL_LOGINFO_CODE_ENCL_MGMT_GPIO_FRAME_ERROR (0x00200090) /* GPIO can't allocate a frame */
+#define PL_LOGINFO_CODE_ENCL_MGMT_GPIO_CONFIG_PAGE_ERROR (0x002000A0) /* GPIO failed config page request */
+#define PL_LOGINFO_CODE_ENCL_MGMT_SES_FRAME_ALLOC_ERROR (0x002000B0) /* Can't get frame for SES command */
+#define PL_LOGINFO_CODE_ENCL_MGMT_SES_IO_ERROR (0x002000C0) /* I/O execution error */
+#define PL_LOGINFO_CODE_ENCL_MGMT_SES_RETRIES_EXHAUSTED (0x002000D0) /* SEP I/O retries exhausted */
+#define PL_LOGINFO_CODE_ENCL_MGMT_SMP_FRAME_ALLOC_ERROR (0x002000E0) /* Can't get frame for SMP command */
+
+#define PL_LOGINFO_DA_SEP_NOT_PRESENT (0x00200100) /* SEP not present when msg received */
+#define PL_LOGINFO_DA_SEP_SINGLE_THREAD_ERROR (0x00200101) /* Can only accept 1 msg at a time */
+#define PL_LOGINFO_DA_SEP_ISTWI_INTR_IN_IDLE_STATE (0x00200102) /* ISTWI interrupt recvd. while IDLE */
+#define PL_LOGINFO_DA_SEP_RECEIVED_NACK_FROM_SLAVE (0x00200103) /* SEP NACK'd, it is busy */
+#define PL_LOGINFO_DA_SEP_DID_NOT_RECEIVE_ACK (0x00200104) /* SEP didn't rcv. ACK (Last Rcvd Bit = 1) */
+#define PL_LOGINFO_DA_SEP_BAD_STATUS_HDR_CHKSUM (0x00200105) /* SEP stopped or sent bad chksum in Hdr */
+#define PL_LOGINFO_DA_SEP_STOP_ON_DATA (0x00200106) /* SEP stopped while transfering data */
+#define PL_LOGINFO_DA_SEP_STOP_ON_SENSE_DATA (0x00200107) /* SEP stopped while transfering sense data */
+#define PL_LOGINFO_DA_SEP_UNSUPPORTED_SCSI_STATUS_1 (0x00200108) /* SEP returned unknown scsi status */
+#define PL_LOGINFO_DA_SEP_UNSUPPORTED_SCSI_STATUS_2 (0x00200109) /* SEP returned unknown scsi status */
+#define PL_LOGINFO_DA_SEP_CHKSUM_ERROR_AFTER_STOP (0x0020010A) /* SEP returned bad chksum after STOP */
+#define PL_LOGINFO_DA_SEP_CHKSUM_ERROR_AFTER_STOP_GETDATA (0x0020010B) /* SEP returned bad chksum after STOP while gettin data*/
+#define PL_LOGINFO_DA_SEP_UNSUPPORTED_COMMAND (0x0020010C) /* SEP doesn't support CDB opcode f/w location 1 */
+#define PL_LOGINFO_DA_SEP_UNSUPPORTED_COMMAND_2 (0x0020010D) /* SEP doesn't support CDB opcode f/w location 2 */
+#define PL_LOGINFO_DA_SEP_UNSUPPORTED_COMMAND_3 (0x0020010E) /* SEP doesn't support CDB opcode f/w location 3 */
/****************************************************************************/
diff --git a/drivers/message/fusion/lsi/mpi_sas.h b/drivers/message/fusion/lsi/mpi_sas.h
index 50b8f0a8f45..8e990a0fa7a 100644
--- a/drivers/message/fusion/lsi/mpi_sas.h
+++ b/drivers/message/fusion/lsi/mpi_sas.h
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2004 LSI Logic Corporation.
+ * Copyright (c) 2004-2006 LSI Logic Corporation.
*
*
* Name: mpi_sas.h
* Title: MPI Serial Attached SCSI structures and definitions
* Creation Date: August 19, 2004
*
- * mpi_sas.h Version: 01.05.03
+ * mpi_sas.h Version: 01.05.04
*
* Version History
* ---------------
@@ -21,6 +21,8 @@
* and Remove Device operations to SAS IO Unit Control.
* Added DevHandle field to SAS IO Unit Control request and
* reply.
+ * 10-11-06 01.05.04 Fixed the name of a define for Operation field of SAS IO
+ * Unit Control request.
* --------------------------------------------------------------------------
*/
@@ -237,7 +239,8 @@ typedef struct _MSG_SAS_IOUNIT_CONTROL_REQUEST
#define MPI_SAS_OP_SEND_PRIMITIVE (0x0A)
#define MPI_SAS_OP_FORCE_FULL_DISCOVERY (0x0B)
#define MPI_SAS_OP_TRANSMIT_PORT_SELECT_SIGNAL (0x0C)
-#define MPI_SAS_OP_TRANSMIT_REMOVE_DEVICE (0x0D)
+#define MPI_SAS_OP_TRANSMIT_REMOVE_DEVICE (0x0D) /* obsolete name */
+#define MPI_SAS_OP_REMOVE_DEVICE (0x0D)
/* values for the PrimFlags field */
#define MPI_SAS_PRIMFLAGS_SINGLE (0x08)
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
index b3f28a03b6a..083acfd91d8 100644
--- a/drivers/message/fusion/mptbase.c
+++ b/drivers/message/fusion/mptbase.c
@@ -6,7 +6,7 @@
* running LSI Logic Fusion MPT (Message Passing Technology) firmware.
*
* Copyright (c) 1999-2007 LSI Logic Corporation
- * (mailto:mpt_linux_developer@lsil.com)
+ * (mailto:mpt_linux_developer@lsi.com)
*
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -82,6 +82,10 @@ static int mpt_msi_enable;
module_param(mpt_msi_enable, int, 0);
MODULE_PARM_DESC(mpt_msi_enable, " MSI Support Enable (default=0)");
+static int mpt_channel_mapping;
+module_param(mpt_channel_mapping, int, 0);
+MODULE_PARM_DESC(mpt_channel_mapping, " Mapping id's to channels (default=0)");
+
#ifdef MFCNT
static int mfcounter = 0;
#define PRINT_MF_COUNT 20000
@@ -173,11 +177,14 @@ static void mpt_get_fw_exp_ver(char *buf, MPT_ADAPTER *ioc);
//int mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
static int ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply, int *evHandlers);
-static void mpt_sp_ioc_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf);
+#ifdef MPT_DEBUG_REPLY
+static void mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf);
+#endif
static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
static void mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info);
static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info);
static int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc);
+static void mpt_inactive_raid_list_free(MPT_ADAPTER *ioc);
/* module entry point */
static int __init fusion_init (void);
@@ -319,13 +326,11 @@ mpt_reply(MPT_ADAPTER *ioc, u32 pa)
else if (ioc->bus_type == SAS)
mpt_sas_log_info(ioc, log_info);
}
- if (ioc_stat & MPI_IOCSTATUS_MASK) {
- if (ioc->bus_type == SPI &&
- cb_idx != mpt_stm_index &&
- cb_idx != mpt_lan_index)
- mpt_sp_ioc_info(ioc, (u32)ioc_stat, mf);
- }
+#ifdef MPT_DEBUG_REPLY
+ if (ioc_stat & MPI_IOCSTATUS_MASK)
+ mpt_iocstatus_info(ioc, (u32)ioc_stat, mf);
+#endif
/* Check for (valid) IO callback! */
if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
@@ -911,7 +916,7 @@ mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
int
mpt_send_handshake_request(int handle, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag)
{
- int r = 0;
+ int r = 0;
u8 *req_as_bytes;
int ii;
@@ -1811,6 +1816,13 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
* and we try GetLanConfigPages again...
*/
if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) {
+
+ /*
+ * Initalize link list for inactive raid volumes.
+ */
+ init_MUTEX(&ioc->raid_data.inactive_list_mutex);
+ INIT_LIST_HEAD(&ioc->raid_data.inactive_list);
+
if (ioc->bus_type == SAS) {
/* clear persistency table */
@@ -2017,6 +2029,8 @@ mpt_adapter_disable(MPT_ADAPTER *ioc)
}
kfree(ioc->spi_data.nvram);
+ mpt_inactive_raid_list_free(ioc);
+ kfree(ioc->raid_data.pIocPg2);
kfree(ioc->raid_data.pIocPg3);
ioc->spi_data.nvram = NULL;
ioc->raid_data.pIocPg3 = NULL;
@@ -2413,6 +2427,9 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
facts->FWVersion.Word = le32_to_cpu(facts->FWVersion.Word);
facts->ProductID = le16_to_cpu(facts->ProductID);
+ if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
+ > MPI_FW_HEADER_PID_PROD_TARGET_SCSI)
+ ioc->ir_firmware = 1;
facts->CurrentHostMfaHighAddr =
le32_to_cpu(facts->CurrentHostMfaHighAddr);
facts->GlobalCredits = le16_to_cpu(facts->GlobalCredits);
@@ -2505,6 +2522,7 @@ GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
int ii;
int req_sz;
int reply_sz;
+ int max_id;
/* IOC *must* NOT be in RESET state! */
if (ioc->last_state == MPI_IOC_STATE_RESET) {
@@ -2552,6 +2570,21 @@ GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
pfacts->MaxPersistentIDs = le16_to_cpu(pfacts->MaxPersistentIDs);
pfacts->MaxLanBuckets = le16_to_cpu(pfacts->MaxLanBuckets);
+ max_id = (ioc->bus_type == SAS) ? pfacts->PortSCSIID :
+ pfacts->MaxDevices;
+ ioc->devices_per_bus = (max_id > 255) ? 256 : max_id;
+ ioc->number_of_buses = (ioc->devices_per_bus < 256) ? 1 : max_id/256;
+
+ /*
+ * Place all the devices on channels
+ *
+ * (for debuging)
+ */
+ if (mpt_channel_mapping) {
+ ioc->devices_per_bus = 1;
+ ioc->number_of_buses = (max_id > 255) ? 255 : max_id;
+ }
+
return 0;
}
@@ -2592,13 +2625,8 @@ SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
ddlprintk((MYIOC_s_INFO_FMT "upload_fw %d facts.Flags=%x\n",
ioc->name, ioc->upload_fw, ioc->facts.Flags));
- if(ioc->bus_type == SAS)
- ioc_init.MaxDevices = ioc->facts.MaxDevices;
- else if(ioc->bus_type == FC)
- ioc_init.MaxDevices = MPT_MAX_FC_DEVICES;
- else
- ioc_init.MaxDevices = MPT_MAX_SCSI_DEVICES;
- ioc_init.MaxBuses = MPT_MAX_BUS;
+ ioc_init.MaxDevices = (U8)ioc->devices_per_bus;
+ ioc_init.MaxBuses = (U8)ioc->number_of_buses;
dinitprintk((MYIOC_s_INFO_FMT "facts.MsgVersion=%x\n",
ioc->name, ioc->facts.MsgVersion));
if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
@@ -2720,9 +2748,7 @@ SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
/* RAID FW may take a long time to enable
*/
- if (((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
- > MPI_FW_HEADER_PID_PROD_TARGET_SCSI) ||
- (ioc->bus_type == SAS)) {
+ if (ioc->ir_firmware || ioc->bus_type == SAS) {
rc = mpt_handshake_req_reply_wait(ioc, req_sz,
(u32*)&port_enable, reply_sz, (u16*)&reply_buf,
300 /*seconds*/, sleepFlag);
@@ -3193,6 +3219,9 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
u32 diag1val = 0;
#endif
+ /* Clear any existing interrupts */
+ CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
+
if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
drsprintk((MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
"address=%p\n", ioc->name, __FUNCTION__,
@@ -3212,7 +3241,7 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
" count=%d\n",
ioc->name, doorbell, count));
if (doorbell == MPI_IOC_STATE_READY) {
- return 0;
+ return 1;
}
/* wait 1 sec */
@@ -3224,9 +3253,6 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
return -1;
}
- /* Clear any existing interrupts */
- CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
-
/* Use "Diagnostic reset" method! (only thing available!) */
diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
@@ -3942,7 +3968,7 @@ WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
}
} else {
while (--cntdn) {
- mdelay (1);
+ udelay (1000);
intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
break;
@@ -3994,7 +4020,7 @@ WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
if (intstat & MPI_HIS_DOORBELL_INTERRUPT)
break;
- mdelay(1);
+ udelay (1000);
count++;
}
}
@@ -4310,8 +4336,8 @@ mptbase_raid_process_event_data(MPT_ADAPTER *ioc,
if ((reason >= MPI_EVENT_RAID_RC_PHYSDISK_CREATED &&
reason <= MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED) ||
(reason == MPI_EVENT_RAID_RC_SMART_DATA)) {
- printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d\n",
- ioc->name, disk);
+ printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for PhysDisk %d id=%d\n",
+ ioc->name, disk, volume);
} else {
printk(MYIOC_s_INFO_FMT "RAID STATUS CHANGE for VolumeID %d\n",
ioc->name, volume);
@@ -4712,7 +4738,187 @@ mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
return 0;
}
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ * mpt_inactive_raid_list_free
+ *
+ * This clears this link list.
+ *
+ * @ioc - pointer to per adapter structure
+ *
+ **/
+static void
+mpt_inactive_raid_list_free(MPT_ADAPTER *ioc)
+{
+ struct inactive_raid_component_info *component_info, *pNext;
+
+ if (list_empty(&ioc->raid_data.inactive_list))
+ return;
+
+ down(&ioc->raid_data.inactive_list_mutex);
+ list_for_each_entry_safe(component_info, pNext,
+ &ioc->raid_data.inactive_list, list) {
+ list_del(&component_info->list);
+ kfree(component_info);
+ }
+ up(&ioc->raid_data.inactive_list_mutex);
+}
+
+/**
+ * mpt_inactive_raid_volumes
+ *
+ * This sets up link list of phy_disk_nums for devices belonging in an inactive volume
+ *
+ * @ioc - pointer to per adapter structure
+ * @channel - volume channel
+ * @id - volume target id
+ *
+ *
+ **/
+static void
+mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id)
+{
+ CONFIGPARMS cfg;
+ ConfigPageHeader_t hdr;
+ dma_addr_t dma_handle;
+ pRaidVolumePage0_t buffer = NULL;
+ int i;
+ RaidPhysDiskPage0_t phys_disk;
+ struct inactive_raid_component_info *component_info;
+ int handle_inactive_volumes;
+
+ memset(&cfg, 0 , sizeof(CONFIGPARMS));
+ memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
+ hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
+ cfg.pageAddr = (channel << 8) + id;
+ cfg.cfghdr.hdr = &hdr;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+
+ if (mpt_config(ioc, &cfg) != 0)
+ goto out;
+
+ if (!hdr.PageLength)
+ goto out;
+
+ buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
+ &dma_handle);
+
+ if (!buffer)
+ goto out;
+
+ cfg.physAddr = dma_handle;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+ if (mpt_config(ioc, &cfg) != 0)
+ goto out;
+
+ if (!buffer->NumPhysDisks)
+ goto out;
+
+ handle_inactive_volumes =
+ (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE ||
+ (buffer->VolumeStatus.Flags & MPI_RAIDVOL0_STATUS_FLAG_ENABLED) == 0 ||
+ buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_FAILED ||
+ buffer->VolumeStatus.State == MPI_RAIDVOL0_STATUS_STATE_MISSING) ? 1 : 0;
+
+ if (!handle_inactive_volumes)
+ goto out;
+
+ down(&ioc->raid_data.inactive_list_mutex);
+ for (i = 0; i < buffer->NumPhysDisks; i++) {
+ if(mpt_raid_phys_disk_pg0(ioc,
+ buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
+ continue;
+
+ if ((component_info = kmalloc(sizeof (*component_info),
+ GFP_KERNEL)) == NULL)
+ continue;
+
+ component_info->volumeID = id;
+ component_info->volumeBus = channel;
+ component_info->d.PhysDiskNum = phys_disk.PhysDiskNum;
+ component_info->d.PhysDiskBus = phys_disk.PhysDiskBus;
+ component_info->d.PhysDiskID = phys_disk.PhysDiskID;
+ component_info->d.PhysDiskIOC = phys_disk.PhysDiskIOC;
+
+ list_add_tail(&component_info->list,
+ &ioc->raid_data.inactive_list);
+ }
+ up(&ioc->raid_data.inactive_list_mutex);
+
+ out:
+ if (buffer)
+ pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
+ dma_handle);
+}
+
+/**
+ * mpt_raid_phys_disk_pg0 - returns phys disk page zero
+ * @ioc: Pointer to a Adapter Structure
+ * @phys_disk_num: io unit unique phys disk num generated by the ioc
+ * @phys_disk: requested payload data returned
+ *
+ * Return:
+ * 0 on success
+ * -EFAULT if read of config page header fails or data pointer not NULL
+ * -ENOMEM if pci_alloc failed
+ **/
+int
+mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage0_t phys_disk)
+{
+ CONFIGPARMS cfg;
+ ConfigPageHeader_t hdr;
+ dma_addr_t dma_handle;
+ pRaidPhysDiskPage0_t buffer = NULL;
+ int rc;
+
+ memset(&cfg, 0 , sizeof(CONFIGPARMS));
+ memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
+
+ hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
+ cfg.cfghdr.hdr = &hdr;
+ cfg.physAddr = -1;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+
+ if (mpt_config(ioc, &cfg) != 0) {
+ rc = -EFAULT;
+ goto out;
+ }
+
+ if (!hdr.PageLength) {
+ rc = -EFAULT;
+ goto out;
+ }
+
+ buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
+ &dma_handle);
+
+ if (!buffer) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ cfg.physAddr = dma_handle;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+ cfg.pageAddr = phys_disk_num;
+
+ if (mpt_config(ioc, &cfg) != 0) {
+ rc = -EFAULT;
+ goto out;
+ }
+
+ rc = 0;
+ memcpy(phys_disk, buffer, sizeof(*buffer));
+ phys_disk->MaxLBA = le32_to_cpu(buffer->MaxLBA);
+
+ out:
+
+ if (buffer)
+ pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
+ dma_handle);
+
+ return rc;
+}
+
/**
* mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
* @ioc: Pointer to a Adapter Strucutre
@@ -4722,21 +4928,27 @@ mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
* 0 on success
* -EFAULT if read of config page header fails or data pointer not NULL
* -ENOMEM if pci_alloc failed
- */
+ **/
int
mpt_findImVolumes(MPT_ADAPTER *ioc)
{
IOCPage2_t *pIoc2;
u8 *mem;
- ConfigPageIoc2RaidVol_t *pIocRv;
dma_addr_t ioc2_dma;
CONFIGPARMS cfg;
ConfigPageHeader_t header;
- int jj;
int rc = 0;
int iocpage2sz;
- u8 nVols, nPhys;
- u8 vid, vbus, vioc;
+ int i;
+
+ if (!ioc->ir_firmware)
+ return 0;
+
+ /* Free the old page
+ */
+ kfree(ioc->raid_data.pIocPg2);
+ ioc->raid_data.pIocPg2 = NULL;
+ mpt_inactive_raid_list_free(ioc);
/* Read IOCP2 header then the page.
*/
@@ -4764,55 +4976,23 @@ mpt_findImVolumes(MPT_ADAPTER *ioc)
cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
cfg.physAddr = ioc2_dma;
if (mpt_config(ioc, &cfg) != 0)
- goto done_and_free;
+ goto out;
+
+ mem = kmalloc(iocpage2sz, GFP_KERNEL);
+ if (!mem)
+ goto out;
- if ( (mem = (u8 *)ioc->raid_data.pIocPg2) == NULL ) {
- mem = kmalloc(iocpage2sz, GFP_ATOMIC);
- if (mem) {
- ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
- } else {
- goto done_and_free;
- }
- }
memcpy(mem, (u8 *)pIoc2, iocpage2sz);
+ ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem;
- /* Identify RAID Volume Id's */
- nVols = pIoc2->NumActiveVolumes;
- if ( nVols == 0) {
- /* No RAID Volume.
- */
- goto done_and_free;
- } else {
- /* At least 1 RAID Volume
- */
- pIocRv = pIoc2->RaidVolume;
- ioc->raid_data.isRaid = 0;
- for (jj = 0; jj < nVols; jj++, pIocRv++) {
- vid = pIocRv->VolumeID;
- vbus = pIocRv->VolumeBus;
- vioc = pIocRv->VolumeIOC;
-
- /* find the match
- */
- if (vbus == 0) {
- ioc->raid_data.isRaid |= (1 << vid);
- } else {
- /* Error! Always bus 0
- */
- }
- }
- }
+ mpt_read_ioc_pg_3(ioc);
- /* Identify Hidden Physical Disk Id's */
- nPhys = pIoc2->NumActivePhysDisks;
- if (nPhys == 0) {
- /* No physical disks.
- */
- } else {
- mpt_read_ioc_pg_3(ioc);
- }
+ for (i = 0; i < pIoc2->NumActiveVolumes ; i++)
+ mpt_inactive_raid_volumes(ioc,
+ pIoc2->RaidVolume[i].VolumeBus,
+ pIoc2->RaidVolume[i].VolumeID);
-done_and_free:
+ out:
pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma);
return rc;
@@ -4865,7 +5045,7 @@ mpt_read_ioc_pg_3(MPT_ADAPTER *ioc)
cfg.physAddr = ioc3_dma;
cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
if (mpt_config(ioc, &cfg) == 0) {
- mem = kmalloc(iocpage3sz, GFP_ATOMIC);
+ mem = kmalloc(iocpage3sz, GFP_KERNEL);
if (mem) {
memcpy(mem, (u8 *)pIoc3, iocpage3sz);
ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem;
@@ -5679,8 +5859,6 @@ mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
return rc;
}
-# define EVENT_DESCR_STR_SZ 100
-
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
static void
EventDescriptionStr(u8 event, u32 evData0, char *evStr)
@@ -5708,9 +5886,6 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr)
break;
case MPI_EVENT_RESCAN:
ds = "Bus Rescan Event";
- /* Ok, do we need to do anything here? As far as
- I can tell, this is when a new device gets added
- to the loop. */
break;
case MPI_EVENT_LINK_STATUS_CHANGE:
if (evData0 == MPI_EVENT_LINK_STATUS_FAILURE)
@@ -5787,48 +5962,63 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr)
case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
{
u8 id = (u8)(evData0);
+ u8 channel = (u8)(evData0 >> 8);
u8 ReasonCode = (u8)(evData0 >> 16);
switch (ReasonCode) {
case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
snprintf(evStr, EVENT_DESCR_STR_SZ,
- "SAS Device Status Change: Added: id=%d", id);
+ "SAS Device Status Change: Added: "
+ "id=%d channel=%d", id, channel);
break;
case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
snprintf(evStr, EVENT_DESCR_STR_SZ,
- "SAS Device Status Change: Deleted: id=%d", id);
+ "SAS Device Status Change: Deleted: "
+ "id=%d channel=%d", id, channel);
break;
case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
snprintf(evStr, EVENT_DESCR_STR_SZ,
- "SAS Device Status Change: SMART Data: id=%d",
- id);
+ "SAS Device Status Change: SMART Data: "
+ "id=%d channel=%d", id, channel);
break;
case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
snprintf(evStr, EVENT_DESCR_STR_SZ,
- "SAS Device Status Change: No Persistancy: id=%d", id);
+ "SAS Device Status Change: No Persistancy: "
+ "id=%d channel=%d", id, channel);
+ break;
+ case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
+ snprintf(evStr, EVENT_DESCR_STR_SZ,
+ "SAS Device Status Change: Unsupported Device "
+ "Discovered : id=%d channel=%d", id, channel);
break;
case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
snprintf(evStr, EVENT_DESCR_STR_SZ,
- "SAS Device Status Change: Internal Device Reset : id=%d", id);
+ "SAS Device Status Change: Internal Device "
+ "Reset : id=%d channel=%d", id, channel);
break;
case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
snprintf(evStr, EVENT_DESCR_STR_SZ,
- "SAS Device Status Change: Internal Task Abort : id=%d", id);
+ "SAS Device Status Change: Internal Task "
+ "Abort : id=%d channel=%d", id, channel);
break;
case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
snprintf(evStr, EVENT_DESCR_STR_SZ,
- "SAS Device Status Change: Internal Abort Task Set : id=%d", id);
+ "SAS Device Status Change: Internal Abort "
+ "Task Set : id=%d channel=%d", id, channel);
break;
case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
snprintf(evStr, EVENT_DESCR_STR_SZ,
- "SAS Device Status Change: Internal Clear Task Set : id=%d", id);
+ "SAS Device Status Change: Internal Clear "
+ "Task Set : id=%d channel=%d", id, channel);
break;
case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
snprintf(evStr, EVENT_DESCR_STR_SZ,
- "SAS Device Status Change: Internal Query Task : id=%d", id);
+ "SAS Device Status Change: Internal Query "
+ "Task : id=%d channel=%d", id, channel);
break;
default:
snprintf(evStr, EVENT_DESCR_STR_SZ,
- "SAS Device Status Change: Unknown: id=%d", id);
+ "SAS Device Status Change: Unknown: "
+ "id=%d channel=%d", id, channel);
break;
}
break;
@@ -5837,8 +6027,16 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr)
ds = "Bus Timer Expired";
break;
case MPI_EVENT_QUEUE_FULL:
- ds = "Queue Full";
+ {
+ u16 curr_depth = (u16)(evData0 >> 16);
+ u8 channel = (u8)(evData0 >> 8);
+ u8 id = (u8)(evData0);
+
+ snprintf(evStr, EVENT_DESCR_STR_SZ,
+ "Queue Full: channel=%d id=%d depth=%d",
+ channel, id, curr_depth);
break;
+ }
case MPI_EVENT_SAS_SES:
ds = "SAS SES Event";
break;
@@ -5942,6 +6140,76 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr)
ds = "SAS Log Entry Added";
break;
+ case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
+ {
+ u8 phy_num = (u8)(evData0);
+ u8 port_num = (u8)(evData0 >> 8);
+ u8 port_width = (u8)(evData0 >> 16);
+ u8 primative = (u8)(evData0 >> 24);
+ snprintf(evStr, EVENT_DESCR_STR_SZ,
+ "SAS Broadcase Primative: phy=%d port=%d "
+ "width=%d primative=0x%02x",
+ phy_num, port_num, port_width, primative);
+ break;
+ }
+
+ case MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
+ {
+ u8 reason = (u8)(evData0);
+ u8 port_num = (u8)(evData0 >> 8);
+ u16 handle = le16_to_cpu(evData0 >> 16);
+
+ snprintf(evStr, EVENT_DESCR_STR_SZ,
+ "SAS Initiator Device Status Change: reason=0x%02x "
+ "port=%d handle=0x%04x",
+ reason, port_num, handle);
+ break;
+ }
+
+ case MPI_EVENT_SAS_INIT_TABLE_OVERFLOW:
+ {
+ u8 max_init = (u8)(evData0);
+ u8 current_init = (u8)(evData0 >> 8);
+
+ snprintf(evStr, EVENT_DESCR_STR_SZ,
+ "SAS Initiator Device Table Overflow: max initiators=%02d "
+ "current initators=%02d",
+ max_init, current_init);
+ break;
+ }
+ case MPI_EVENT_SAS_SMP_ERROR:
+ {
+ u8 status = (u8)(evData0);
+ u8 port_num = (u8)(evData0 >> 8);
+ u8 result = (u8)(evData0 >> 16);
+
+ if (status == MPI_EVENT_SAS_SMP_FUNCTION_RESULT_VALID)
+ snprintf(evStr, EVENT_DESCR_STR_SZ,
+ "SAS SMP Error: port=%d result=0x%02x",
+ port_num, result);
+ else if (status == MPI_EVENT_SAS_SMP_CRC_ERROR)
+ snprintf(evStr, EVENT_DESCR_STR_SZ,
+ "SAS SMP Error: port=%d : CRC Error",
+ port_num);
+ else if (status == MPI_EVENT_SAS_SMP_TIMEOUT)
+ snprintf(evStr, EVENT_DESCR_STR_SZ,
+ "SAS SMP Error: port=%d : Timeout",
+ port_num);
+ else if (status == MPI_EVENT_SAS_SMP_NO_DESTINATION)
+ snprintf(evStr, EVENT_DESCR_STR_SZ,
+ "SAS SMP Error: port=%d : No Destination",
+ port_num);
+ else if (status == MPI_EVENT_SAS_SMP_BAD_DESTINATION)
+ snprintf(evStr, EVENT_DESCR_STR_SZ,
+ "SAS SMP Error: port=%d : Bad Destination",
+ port_num);
+ else
+ snprintf(evStr, EVENT_DESCR_STR_SZ,
+ "SAS SMP Error: port=%d : status=0x%02x",
+ port_num, status);
+ break;
+ }
+
/*
* MPT base "custom" events may be added here...
*/
@@ -6205,10 +6473,11 @@ mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
"Abort", /* 12h */
"IO Not Yet Executed", /* 13h */
"IO Executed", /* 14h */
- "Persistent Reservation Out Not Affiliation Owner", /* 15h */
+ "Persistent Reservation Out Not Affiliation "
+ "Owner", /* 15h */
"Open Transmit DMA Abort", /* 16h */
"IO Device Missing Delay Retry", /* 17h */
- NULL, /* 18h */
+ "IO Cancelled Due to Recieve Error", /* 18h */
NULL, /* 19h */
NULL, /* 1Ah */
NULL, /* 1Bh */
@@ -6218,6 +6487,96 @@ mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
NULL, /* 1Fh */
"Enclosure Management" /* 20h */
};
+ static char *ir_code_str[] = {
+ "Raid Action Error", /* 00h */
+ NULL, /* 00h */
+ NULL, /* 01h */
+ NULL, /* 02h */
+ NULL, /* 03h */
+ NULL, /* 04h */
+ NULL, /* 05h */
+ NULL, /* 06h */
+ NULL /* 07h */
+ };
+ static char *raid_sub_code_str[] = {
+ NULL, /* 00h */
+ "Volume Creation Failed: Data Passed too "
+ "Large", /* 01h */
+ "Volume Creation Failed: Duplicate Volumes "
+ "Attempted", /* 02h */
+ "Volume Creation Failed: Max Number "
+ "Supported Volumes Exceeded", /* 03h */
+ "Volume Creation Failed: DMA Error", /* 04h */
+ "Volume Creation Failed: Invalid Volume Type", /* 05h */
+ "Volume Creation Failed: Error Reading "
+ "MFG Page 4", /* 06h */
+ "Volume Creation Failed: Creating Internal "
+ "Structures", /* 07h */
+ NULL, /* 08h */
+ NULL, /* 09h */
+ NULL, /* 0Ah */
+ NULL, /* 0Bh */
+ NULL, /* 0Ch */
+ NULL, /* 0Dh */
+ NULL, /* 0Eh */
+ NULL, /* 0Fh */
+ "Activation failed: Already Active Volume", /* 10h */
+ "Activation failed: Unsupported Volume Type", /* 11h */
+ "Activation failed: Too Many Active Volumes", /* 12h */
+ "Activation failed: Volume ID in Use", /* 13h */
+ "Activation failed: Reported Failure", /* 14h */
+ "Activation failed: Importing a Volume", /* 15h */
+ NULL, /* 16h */
+ NULL, /* 17h */
+ NULL, /* 18h */
+ NULL, /* 19h */
+ NULL, /* 1Ah */
+ NULL, /* 1Bh */
+ NULL, /* 1Ch */
+ NULL, /* 1Dh */
+ NULL, /* 1Eh */
+ NULL, /* 1Fh */
+ "Phys Disk failed: Too Many Phys Disks", /* 20h */
+ "Phys Disk failed: Data Passed too Large", /* 21h */
+ "Phys Disk failed: DMA Error", /* 22h */
+ "Phys Disk failed: Invalid <channel:id>", /* 23h */
+ "Phys Disk failed: Creating Phys Disk Config "
+ "Page", /* 24h */
+ NULL, /* 25h */
+ NULL, /* 26h */
+ NULL, /* 27h */
+ NULL, /* 28h */
+ NULL, /* 29h */
+ NULL, /* 2Ah */
+ NULL, /* 2Bh */
+ NULL, /* 2Ch */
+ NULL, /* 2Dh */
+ NULL, /* 2Eh */
+ NULL, /* 2Fh */
+ "Compatibility Error: IR Disabled", /* 30h */
+ "Compatibility Error: Inquiry Comand Failed", /* 31h */
+ "Compatibility Error: Device not Direct Access "
+ "Device ", /* 32h */
+ "Compatibility Error: Removable Device Found", /* 33h */
+ "Compatibility Error: Device SCSI Version not "
+ "2 or Higher", /* 34h */
+ "Compatibility Error: SATA Device, 48 BIT LBA "
+ "not Supported", /* 35h */
+ "Compatibility Error: Device doesn't have "
+ "512 Byte Block Sizes", /* 36h */
+ "Compatibility Error: Volume Type Check Failed", /* 37h */
+ "Compatibility Error: Volume Type is "
+ "Unsupported by FW", /* 38h */
+ "Compatibility Error: Disk Drive too Small for "
+ "use in Volume", /* 39h */
+ "Compatibility Error: Phys Disk for Create "
+ "Volume not Found", /* 3Ah */
+ "Compatibility Error: Too Many or too Few "
+ "Disks for Volume Type", /* 3Bh */
+ "Compatibility Error: Disk stripe Sizes "
+ "Must be 64KB", /* 3Ch */
+ "Compatibility Error: IME Size Limited to < 2TB", /* 3Dh */
+ };
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
@@ -6226,7 +6585,7 @@ mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
* @log_info: U32 LogInfo reply word from the IOC
*
* Refer to lsi/mpi_log_sas.h.
- */
+ **/
static void
mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info)
{
@@ -6240,56 +6599,165 @@ union loginfo_type {
}dw;
};
union loginfo_type sas_loginfo;
+ char *originator_desc = NULL;
char *code_desc = NULL;
+ char *sub_code_desc = NULL;
sas_loginfo.loginfo = log_info;
if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) &&
(sas_loginfo.dw.originator < sizeof(originator_str)/sizeof(char*)))
return;
- if ((sas_loginfo.dw.originator == 0 /*IOP*/) &&
- (sas_loginfo.dw.code < sizeof(iop_code_str)/sizeof(char*))) {
- code_desc = iop_code_str[sas_loginfo.dw.code];
- }else if ((sas_loginfo.dw.originator == 1 /*PL*/) &&
- (sas_loginfo.dw.code < sizeof(pl_code_str)/sizeof(char*) )) {
- code_desc = pl_code_str[sas_loginfo.dw.code];
+
+ originator_desc = originator_str[sas_loginfo.dw.originator];
+
+ switch (sas_loginfo.dw.originator) {
+
+ case 0: /* IOP */
+ if (sas_loginfo.dw.code <
+ sizeof(iop_code_str)/sizeof(char*))
+ code_desc = iop_code_str[sas_loginfo.dw.code];
+ break;
+ case 1: /* PL */
+ if (sas_loginfo.dw.code <
+ sizeof(pl_code_str)/sizeof(char*))
+ code_desc = pl_code_str[sas_loginfo.dw.code];
+ break;
+ case 2: /* IR */
+ if (sas_loginfo.dw.code >=
+ sizeof(ir_code_str)/sizeof(char*))
+ break;
+ code_desc = ir_code_str[sas_loginfo.dw.code];
+ if (sas_loginfo.dw.subcode >=
+ sizeof(raid_sub_code_str)/sizeof(char*))
+ break;
+ if (sas_loginfo.dw.code == 0)
+ sub_code_desc =
+ raid_sub_code_str[sas_loginfo.dw.subcode];
+ break;
+ default:
+ return;
}
- if (code_desc != NULL)
+ if (sub_code_desc != NULL)
+ printk(MYIOC_s_INFO_FMT
+ "LogInfo(0x%08x): Originator={%s}, Code={%s},"
+ " SubCode={%s}\n",
+ ioc->name, log_info, originator_desc, code_desc,
+ sub_code_desc);
+ else if (code_desc != NULL)
printk(MYIOC_s_INFO_FMT
"LogInfo(0x%08x): Originator={%s}, Code={%s},"
" SubCode(0x%04x)\n",
- ioc->name,
- log_info,
- originator_str[sas_loginfo.dw.originator],
- code_desc,
+ ioc->name, log_info, originator_desc, code_desc,
sas_loginfo.dw.subcode);
else
printk(MYIOC_s_INFO_FMT
"LogInfo(0x%08x): Originator={%s}, Code=(0x%02x),"
" SubCode(0x%04x)\n",
- ioc->name,
- log_info,
- originator_str[sas_loginfo.dw.originator],
- sas_loginfo.dw.code,
- sas_loginfo.dw.subcode);
+ ioc->name, log_info, originator_desc,
+ sas_loginfo.dw.code, sas_loginfo.dw.subcode);
}
+#ifdef MPT_DEBUG_REPLY
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
- * mpt_sp_ioc_info - IOC information returned from SCSI Parallel IOC.
+ * mpt_iocstatus_info_config - IOCSTATUS information for config pages
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * ioc_status: U32 IOCStatus word from IOC
+ * @mf: Pointer to MPT request frame
+ *
+ * Refer to lsi/mpi.h.
+ **/
+static void
+mpt_iocstatus_info_config(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
+{
+ Config_t *pReq = (Config_t *)mf;
+ char extend_desc[EVENT_DESCR_STR_SZ];
+ char *desc = NULL;
+ u32 form;
+ u8 page_type;
+
+ if (pReq->Header.PageType == MPI_CONFIG_PAGETYPE_EXTENDED)
+ page_type = pReq->ExtPageType;
+ else
+ page_type = pReq->Header.PageType;
+
+ /*
+ * ignore invalid page messages for GET_NEXT_HANDLE
+ */
+ form = le32_to_cpu(pReq->PageAddress);
+ if (ioc_status == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
+ if (page_type == MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE ||
+ page_type == MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER ||
+ page_type == MPI_CONFIG_EXTPAGETYPE_ENCLOSURE) {
+ if ((form >> MPI_SAS_DEVICE_PGAD_FORM_SHIFT) ==
+ MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE)
+ return;
+ }
+ if (page_type == MPI_CONFIG_PAGETYPE_FC_DEVICE)
+ if ((form & MPI_FC_DEVICE_PGAD_FORM_MASK) ==
+ MPI_FC_DEVICE_PGAD_FORM_NEXT_DID)
+ return;
+ }
+
+ snprintf(extend_desc, EVENT_DESCR_STR_SZ,
+ "type=%02Xh, page=%02Xh, action=%02Xh, form=%08Xh",
+ page_type, pReq->Header.PageNumber, pReq->Action, form);
+
+ switch (ioc_status) {
+
+ case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
+ desc = "Config Page Invalid Action";
+ break;
+
+ case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
+ desc = "Config Page Invalid Type";
+ break;
+
+ case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
+ desc = "Config Page Invalid Page";
+ break;
+
+ case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
+ desc = "Config Page Invalid Data";
+ break;
+
+ case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
+ desc = "Config Page No Defaults";
+ break;
+
+ case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
+ desc = "Config Page Can't Commit";
+ break;
+ }
+
+ if (!desc)
+ return;
+
+ printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04X): %s: %s\n",
+ ioc->name, ioc_status, desc, extend_desc);
+}
+
+/**
+ * mpt_iocstatus_info - IOCSTATUS information returned from IOC.
* @ioc: Pointer to MPT_ADAPTER structure
* @ioc_status: U32 IOCStatus word from IOC
* @mf: Pointer to MPT request frame
*
* Refer to lsi/mpi.h.
- */
+ **/
static void
-mpt_sp_ioc_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
+mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
{
u32 status = ioc_status & MPI_IOCSTATUS_MASK;
char *desc = NULL;
switch (status) {
+
+/****************************************************************************/
+/* Common IOCStatus values for all replies */
+/****************************************************************************/
+
case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
desc = "Invalid Function";
break;
@@ -6322,84 +6790,180 @@ mpt_sp_ioc_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
desc = "Invalid State";
break;
+/****************************************************************************/
+/* Config IOCStatus values */
+/****************************************************************************/
+
case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */
case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */
case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */
case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */
case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */
case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */
- /* No message for Config IOCStatus values */
+ mpt_iocstatus_info_config(ioc, status, mf);
break;
+/****************************************************************************/
+/* SCSIIO Reply (SPI, FCP, SAS) initiator values */
+/* */
+/* Look at mptscsih_iocstatus_info_scsiio in mptscsih.c */
+/* */
+/****************************************************************************/
+
case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
- /* No message for recovered error
- desc = "SCSI Recovered Error";
- */
+ case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
+ case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
+ case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
+ case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
+ case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
+ case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
+ case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
+ case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
+ case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
+ case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
+ case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
+ case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
break;
- case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
- desc = "SCSI Invalid Bus";
+/****************************************************************************/
+/* SCSI Target values */
+/****************************************************************************/
+
+ case MPI_IOCSTATUS_TARGET_PRIORITY_IO: /* 0x0060 */
+ desc = "Target: Priority IO";
break;
- case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
- desc = "SCSI Invalid TargetID";
+ case MPI_IOCSTATUS_TARGET_INVALID_PORT: /* 0x0061 */
+ desc = "Target: Invalid Port";
break;
- case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
- {
- SCSIIORequest_t *pScsiReq = (SCSIIORequest_t *) mf;
- U8 cdb = pScsiReq->CDB[0];
- if (cdb != 0x12) { /* Inquiry is issued for device scanning */
- desc = "SCSI Device Not There";
- }
+ case MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX: /* 0x0062 */
+ desc = "Target Invalid IO Index:";
break;
- }
- case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
- desc = "SCSI Data Overrun";
+ case MPI_IOCSTATUS_TARGET_ABORTED: /* 0x0063 */
+ desc = "Target: Aborted";
break;
- case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
- /* This error is checked in scsi_io_done(). Skip.
- desc = "SCSI Data Underrun";
- */
+ case MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: /* 0x0064 */
+ desc = "Target: No Conn Retryable";
break;
- case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
- desc = "SCSI I/O Data Error";
+ case MPI_IOCSTATUS_TARGET_NO_CONNECTION: /* 0x0065 */
+ desc = "Target: No Connection";
break;
- case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
- desc = "SCSI Protocol Error";
+ case MPI_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: /* 0x006A */
+ desc = "Target: Transfer Count Mismatch";
break;
- case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
- desc = "SCSI Task Terminated";
+ case MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT: /* 0x006B */
+ desc = "Target: STS Data not Sent";
break;
- case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
- desc = "SCSI Residual Mismatch";
+ case MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: /* 0x006D */
+ desc = "Target: Data Offset Error";
break;
- case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
- desc = "SCSI Task Management Failed";
+ case MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: /* 0x006E */
+ desc = "Target: Too Much Write Data";
break;
- case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
- desc = "SCSI IOC Terminated";
+ case MPI_IOCSTATUS_TARGET_IU_TOO_SHORT: /* 0x006F */
+ desc = "Target: IU Too Short";
break;
- case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
- desc = "SCSI Ext Terminated";
+ case MPI_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT: /* 0x0070 */
+ desc = "Target: ACK NAK Timeout";
+ break;
+
+ case MPI_IOCSTATUS_TARGET_NAK_RECEIVED: /* 0x0071 */
+ desc = "Target: Nak Received";
+ break;
+
+/****************************************************************************/
+/* Fibre Channel Direct Access values */
+/****************************************************************************/
+
+ case MPI_IOCSTATUS_FC_ABORTED: /* 0x0066 */
+ desc = "FC: Aborted";
+ break;
+
+ case MPI_IOCSTATUS_FC_RX_ID_INVALID: /* 0x0067 */
+ desc = "FC: RX ID Invalid";
+ break;
+
+ case MPI_IOCSTATUS_FC_DID_INVALID: /* 0x0068 */
+ desc = "FC: DID Invalid";
+ break;
+
+ case MPI_IOCSTATUS_FC_NODE_LOGGED_OUT: /* 0x0069 */
+ desc = "FC: Node Logged Out";
+ break;
+
+ case MPI_IOCSTATUS_FC_EXCHANGE_CANCELED: /* 0x006C */
+ desc = "FC: Exchange Canceled";
+ break;
+
+/****************************************************************************/
+/* LAN values */
+/****************************************************************************/
+
+ case MPI_IOCSTATUS_LAN_DEVICE_NOT_FOUND: /* 0x0080 */
+ desc = "LAN: Device not Found";
+ break;
+
+ case MPI_IOCSTATUS_LAN_DEVICE_FAILURE: /* 0x0081 */
+ desc = "LAN: Device Failure";
+ break;
+
+ case MPI_IOCSTATUS_LAN_TRANSMIT_ERROR: /* 0x0082 */
+ desc = "LAN: Transmit Error";
+ break;
+
+ case MPI_IOCSTATUS_LAN_TRANSMIT_ABORTED: /* 0x0083 */
+ desc = "LAN: Transmit Aborted";
+ break;
+
+ case MPI_IOCSTATUS_LAN_RECEIVE_ERROR: /* 0x0084 */
+ desc = "LAN: Receive Error";
+ break;
+
+ case MPI_IOCSTATUS_LAN_RECEIVE_ABORTED: /* 0x0085 */
+ desc = "LAN: Receive Aborted";
+ break;
+
+ case MPI_IOCSTATUS_LAN_PARTIAL_PACKET: /* 0x0086 */
+ desc = "LAN: Partial Packet";
+ break;
+
+ case MPI_IOCSTATUS_LAN_CANCELED: /* 0x0087 */
+ desc = "LAN: Canceled";
+ break;
+
+/****************************************************************************/
+/* Serial Attached SCSI values */
+/****************************************************************************/
+
+ case MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED: /* 0x0090 */
+ desc = "SAS: SMP Request Failed";
+ break;
+
+ case MPI_IOCSTATUS_SAS_SMP_DATA_OVERRUN: /* 0x0090 */
+ desc = "SAS: SMP Data Overrun";
break;
default:
desc = "Others";
break;
}
- if (desc != NULL)
- printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04x): %s\n", ioc->name, status, desc);
+
+ if (!desc)
+ return;
+
+ printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04X): %s\n", ioc->name, status, desc);
}
+#endif
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
EXPORT_SYMBOL(mpt_attach);
@@ -6434,6 +6998,7 @@ EXPORT_SYMBOL(mpt_findImVolumes);
EXPORT_SYMBOL(mpt_alloc_fw_memory);
EXPORT_SYMBOL(mpt_free_fw_memory);
EXPORT_SYMBOL(mptbase_sas_persist_operation);
+EXPORT_SYMBOL(mpt_raid_phys_disk_pg0);
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h
index e316708f76b..e3a39272aad 100644
--- a/drivers/message/fusion/mptbase.h
+++ b/drivers/message/fusion/mptbase.h
@@ -6,7 +6,7 @@
* running LSI Logic Fusion MPT (Message Passing Technology) firmware.
*
* Copyright (c) 1999-2007 LSI Logic Corporation
- * (mailto:mpt_linux_developer@lsil.com)
+ * (mailto:mpt_linux_developer@lsi.com)
*
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -75,8 +75,8 @@
#define COPYRIGHT "Copyright (c) 1999-2007 " MODULEAUTHOR
#endif
-#define MPT_LINUX_VERSION_COMMON "3.04.03"
-#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.03"
+#define MPT_LINUX_VERSION_COMMON "3.04.04"
+#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.04"
#define WHAT_MAGIC_STRING "@" "(" "#" ")"
#define show_mptmod_ver(s,ver) \
@@ -172,6 +172,9 @@
#define MPT_SCSI_SG_DEPTH 40
#endif
+/* debug print string length used for events and iocstatus */
+# define EVENT_DESCR_STR_SZ 100
+
#ifdef __KERNEL__ /* { */
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -334,8 +337,8 @@ typedef struct _VirtTarget {
struct scsi_target *starget;
u8 tflags;
u8 ioc_id;
- u8 target_id;
- u8 bus_id;
+ u8 id;
+ u8 channel;
u8 minSyncFactor; /* 0xFF is async */
u8 maxOffset; /* 0 if async */
u8 maxWidth; /* 0 if narrow, 1 if wide */
@@ -344,13 +347,12 @@ typedef struct _VirtTarget {
u8 type; /* byte 0 of Inquiry data */
u8 deleted; /* target in process of being removed */
u32 num_luns;
- u32 luns[8]; /* Max LUNs is 256 */
} VirtTarget;
typedef struct _VirtDevice {
VirtTarget *vtarget;
u8 configured_lun;
- u32 lun;
+ int lun;
} VirtDevice;
/*
@@ -412,7 +414,7 @@ typedef struct _MPT_IOCTL {
u8 rsvd;
u8 status; /* current command status */
u8 reset; /* 1 if bus reset allowed */
- u8 target; /* target for reset */
+ u8 id; /* target for reset */
struct mutex ioctl_mutex;
} MPT_IOCTL;
@@ -483,10 +485,24 @@ typedef struct _SasCfgData {
*/
}SasCfgData;
+/*
+ * Inactive volume link list of raid component data
+ * @inactive_list
+ */
+struct inactive_raid_component_info {
+ struct list_head list;
+ u8 volumeID; /* volume target id */
+ u8 volumeBus; /* volume channel */
+ IOC_3_PHYS_DISK d; /* phys disk info */
+};
+
typedef struct _RaidCfgData {
IOCPage2_t *pIocPg2; /* table of Raid Volumes */
IOCPage3_t *pIocPg3; /* table of physical disks */
- int isRaid; /* bit field, 1 if RAID */
+ struct semaphore inactive_list_mutex;
+ struct list_head inactive_list; /* link list for physical
+ disk that belong in
+ inactive volumes */
}RaidCfgData;
typedef struct _FcCfgData {
@@ -528,6 +544,8 @@ typedef struct _MPT_ADAPTER
u32 mem_phys; /* == f4020000 (mmap) */
u32 pio_mem_phys; /* Programmed IO (downloadboot) */
int mem_size; /* mmap memory size */
+ int number_of_buses;
+ int devices_per_bus;
int alloc_total;
u32 last_state;
int active;
@@ -607,6 +625,8 @@ typedef struct _MPT_ADAPTER
u8 persist_reply_frame[MPT_DEFAULT_FRAME_SIZE]; /* persist reply */
LANPage0_t lan_cnfg_page0;
LANPage1_t lan_cnfg_page1;
+
+ u8 ir_firmware; /* =1 if IR firmware detected */
/*
* Description: errata_flag_1064
* If a PCIX read occurs within 1 or 2 cycles after the chip receives
@@ -790,12 +810,6 @@ typedef struct _mpt_sge {
#define ddvprintk(x)
#endif
-#ifdef MPT_DEBUG_NEGO
-#define dnegoprintk(x) printk x
-#else
-#define dnegoprintk(x)
-#endif
-
#if defined(MPT_DEBUG_DV) || defined(MPT_DEBUG_DV_TINY)
#define ddvtprintk(x) printk x
#else
@@ -957,7 +971,6 @@ typedef struct _MPT_SCSI_HOST {
int port;
u32 pad0;
struct scsi_cmnd **ScsiLookup;
- VirtTarget **Targets;
MPT_LOCAL_REPLY *pLocal; /* used for internal commands */
struct timer_list timer;
/* Pool of memory for holding SCpnts before doing
@@ -981,6 +994,7 @@ typedef struct _MPT_SCSI_HOST {
int scandv_wait_done;
long last_queue_full;
u16 tm_iocstatus;
+ struct list_head target_reset_list;
} MPT_SCSI_HOST;
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -1046,6 +1060,7 @@ extern void mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size);
extern void mpt_free_fw_memory(MPT_ADAPTER *ioc);
extern int mpt_findImVolumes(MPT_ADAPTER *ioc);
extern int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
+extern int mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage0_t phys_disk);
/*
* Public data decl's...
diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c
index 504632da434..9d0f30478e4 100644
--- a/drivers/message/fusion/mptctl.c
+++ b/drivers/message/fusion/mptctl.c
@@ -5,7 +5,7 @@
* running LSI Logic Fusion MPT (Message Passing Technology) firmware.
*
* Copyright (c) 1999-2007 LSI Logic Corporation
- * (mailto:mpt_linux_developer@lsil.com)
+ * (mailto:mpt_linux_developer@lsi.com)
*
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -313,7 +313,7 @@ static void mptctl_timeout_expired (MPT_IOCTL *ioctl)
*/
dctlprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n",
ioctl->ioc->name));
- mpt_HardResetHandler(ioctl->ioc, NO_SLEEP);
+ mpt_HardResetHandler(ioctl->ioc, CAN_SLEEP);
}
return;
@@ -361,7 +361,7 @@ static int mptctl_bus_reset(MPT_IOCTL *ioctl)
ioctl->ioc->name, mf));
pScsiTm = (SCSITaskMgmt_t *) mf;
- pScsiTm->TargetID = ioctl->target;
+ pScsiTm->TargetID = ioctl->id;
pScsiTm->Bus = hd->port; /* 0 */
pScsiTm->ChainOffset = 0;
pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
@@ -1159,15 +1159,12 @@ mptctl_getiocinfo (unsigned long arg, unsigned int data_size)
struct mpt_ioctl_iocinfo *karg;
MPT_ADAPTER *ioc;
struct pci_dev *pdev;
- struct Scsi_Host *sh;
- MPT_SCSI_HOST *hd;
int iocnum;
- int numDevices = 0;
- unsigned int max_id;
- int ii;
unsigned int port;
int cim_rev;
u8 revision;
+ struct scsi_device *sdev;
+ VirtDevice *vdev;
dctlprintk((": mptctl_getiocinfo called.\n"));
/* Add of PCI INFO results in unaligned access for
@@ -1257,23 +1254,16 @@ mptctl_getiocinfo (unsigned long arg, unsigned int data_size)
/* Get number of devices
*/
- if ((sh = ioc->sh) != NULL) {
- /* sh->max_id = maximum target ID + 1
- */
- max_id = sh->max_id - 1;
- hd = (MPT_SCSI_HOST *) sh->hostdata;
-
- /* Check all of the target structures and
- * keep a counter.
- */
- if (hd && hd->Targets) {
- for (ii = 0; ii <= max_id; ii++) {
- if (hd->Targets[ii])
- numDevices++;
- }
+ karg->numDevices = 0;
+ if (ioc->sh) {
+ shost_for_each_device(sdev, ioc->sh) {
+ vdev = sdev->hostdata;
+ if (vdev->vtarget->tflags &
+ MPT_TARGET_FLAGS_RAID_COMPONENT)
+ continue;
+ karg->numDevices++;
}
}
- karg->numDevices = numDevices;
/* Set the BIOS and FW Version
*/
@@ -1319,21 +1309,16 @@ mptctl_gettargetinfo (unsigned long arg)
struct mpt_ioctl_targetinfo __user *uarg = (void __user *) arg;
struct mpt_ioctl_targetinfo karg;
MPT_ADAPTER *ioc;
- struct Scsi_Host *sh;
- MPT_SCSI_HOST *hd;
- VirtTarget *vdev;
+ VirtDevice *vdev;
char *pmem;
int *pdata;
- IOCPage2_t *pIoc2;
- IOCPage3_t *pIoc3;
int iocnum;
int numDevices = 0;
- unsigned int max_id;
- int id, jj, indexed_lun, lun_index;
- u32 lun;
+ int lun;
int maxWordsLeft;
int numBytes;
- u8 port, devType, bus_id;
+ u8 port;
+ struct scsi_device *sdev;
dctlprintk(("mptctl_gettargetinfo called.\n"));
if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_targetinfo))) {
@@ -1389,74 +1374,22 @@ mptctl_gettargetinfo (unsigned long arg)
/* Get number of devices
*/
- if ((sh = ioc->sh) != NULL) {
-
- max_id = sh->max_id - 1;
- hd = (MPT_SCSI_HOST *) sh->hostdata;
-
- /* Check all of the target structures.
- * Save the Id and increment the counter,
- * if ptr non-null.
- * sh->max_id = maximum target ID + 1
- */
- if (hd && hd->Targets) {
- mpt_findImVolumes(ioc);
- pIoc2 = ioc->raid_data.pIocPg2;
- for ( id = 0; id <= max_id; ) {
- if ( pIoc2 && pIoc2->NumActiveVolumes ) {
- if ( id == pIoc2->RaidVolume[0].VolumeID ) {
- if (maxWordsLeft <= 0) {
- printk(KERN_ERR "mptctl_gettargetinfo - "
- "buffer is full but volume is available on ioc %d\n, numDevices=%d", iocnum, numDevices);
- goto data_space_full;
- }
- if ( ( pIoc2->RaidVolume[0].Flags & MPI_IOCPAGE2_FLAG_VOLUME_INACTIVE ) == 0 )
- devType = 0x80;
- else
- devType = 0xC0;
- bus_id = pIoc2->RaidVolume[0].VolumeBus;
- numDevices++;
- *pdata = ( (devType << 24) | (bus_id << 8) | id );
- dctlprintk((KERN_ERR "mptctl_gettargetinfo - "
- "volume ioc=%d target=%x numDevices=%d pdata=%p\n", iocnum, *pdata, numDevices, pdata));
- pdata++;
- --maxWordsLeft;
- goto next_id;
- } else {
- pIoc3 = ioc->raid_data.pIocPg3;
- for ( jj = 0; jj < pIoc3->NumPhysDisks; jj++ ) {
- if ( pIoc3->PhysDisk[jj].PhysDiskID == id )
- goto next_id;
- }
- }
- }
- if ( (vdev = hd->Targets[id]) ) {
- for (jj = 0; jj <= MPT_LAST_LUN; jj++) {
- lun_index = (jj >> 5);
- indexed_lun = (jj % 32);
- lun = (1 << indexed_lun);
- if (vdev->luns[lun_index] & lun) {
- if (maxWordsLeft <= 0) {
- printk(KERN_ERR "mptctl_gettargetinfo - "
- "buffer is full but more targets are available on ioc %d numDevices=%d\n", iocnum, numDevices);
- goto data_space_full;
- }
- bus_id = vdev->bus_id;
- numDevices++;
- *pdata = ( (jj << 16) | (bus_id << 8) | id );
- dctlprintk((KERN_ERR "mptctl_gettargetinfo - "
- "target ioc=%d target=%x numDevices=%d pdata=%p\n", iocnum, *pdata, numDevices, pdata));
- pdata++;
- --maxWordsLeft;
- }
- }
- }
-next_id:
- id++;
- }
+ if (ioc->sh){
+ shost_for_each_device(sdev, ioc->sh) {
+ if (!maxWordsLeft)
+ continue;
+ vdev = sdev->hostdata;
+ if (vdev->vtarget->tflags &
+ MPT_TARGET_FLAGS_RAID_COMPONENT)
+ continue;
+ lun = (vdev->vtarget->raidVolume) ? 0x80 : vdev->lun;
+ *pdata = (((u8)lun << 16) + (vdev->vtarget->channel << 8) +
+ (vdev->vtarget->id ));
+ pdata++;
+ numDevices++;
+ --maxWordsLeft;
}
}
-data_space_full:
karg.numDevices = numDevices;
/* Copy part of the data from kernel memory to user memory
@@ -1821,6 +1754,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
int msgContext;
u16 req_idx;
ulong timeout;
+ struct scsi_device *sdev;
dctlprintk(("mptctl_do_mpt_command called.\n"));
bufIn.kptr = bufOut.kptr = NULL;
@@ -1902,14 +1836,13 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
case MPI_FUNCTION_SCSI_IO_REQUEST:
if (ioc->sh) {
SCSIIORequest_t *pScsiReq = (SCSIIORequest_t *) mf;
- VirtTarget *pTarget = NULL;
- MPT_SCSI_HOST *hd = NULL;
int qtag = MPI_SCSIIO_CONTROL_UNTAGGED;
int scsidir = 0;
- int target = (int) pScsiReq->TargetID;
int dataSize;
+ u32 id;
- if ((target < 0) || (target >= ioc->sh->max_id)) {
+ id = (ioc->devices_per_bus == 0) ? 256 : ioc->devices_per_bus;
+ if (pScsiReq->TargetID > id) {
printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
"Target ID out of bounds. \n",
__FILE__, __LINE__);
@@ -1917,6 +1850,14 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
goto done_free_mem;
}
+ if (pScsiReq->Bus >= ioc->number_of_buses) {
+ printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+ "Target Bus out of bounds. \n",
+ __FILE__, __LINE__);
+ rc = -ENODEV;
+ goto done_free_mem;
+ }
+
pScsiReq->MsgFlags &= ~MPI_SCSIIO_MSGFLGS_SENSE_WIDTH;
pScsiReq->MsgFlags |= mpt_msg_flags();
@@ -1936,13 +1877,15 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
cpu_to_le32(ioc->sense_buf_low_dma
+ (req_idx * MPT_SENSE_BUFFER_ALLOC));
- if ((hd = (MPT_SCSI_HOST *) ioc->sh->hostdata)) {
- if (hd->Targets)
- pTarget = hd->Targets[target];
- }
+ shost_for_each_device(sdev, ioc->sh) {
+ struct scsi_target *starget = scsi_target(sdev);
+ VirtTarget *vtarget = starget->hostdata;
- if (pTarget &&(pTarget->tflags & MPT_TARGET_FLAGS_Q_YES))
- qtag = MPI_SCSIIO_CONTROL_SIMPLEQ;
+ if ((pScsiReq->TargetID == vtarget->id) &&
+ (pScsiReq->Bus == vtarget->channel) &&
+ (vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
+ qtag = MPI_SCSIIO_CONTROL_SIMPLEQ;
+ }
/* Have the IOCTL driver set the direction based
* on the dataOutSize (ordering issue with Sparc).
@@ -1959,7 +1902,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
pScsiReq->DataLength = cpu_to_le32(dataSize);
ioc->ioctl->reset = MPTCTL_RESET_OK;
- ioc->ioctl->target = target;
+ ioc->ioctl->id = pScsiReq->TargetID;
} else {
printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
@@ -2038,7 +1981,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
pScsiReq->DataLength = cpu_to_le32(dataSize);
ioc->ioctl->reset = MPTCTL_RESET_OK;
- ioc->ioctl->target = pScsiReq->TargetID;
+ ioc->ioctl->id = pScsiReq->TargetID;
} else {
printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
"SCSI driver is not loaded. \n",
@@ -2719,7 +2662,7 @@ mptctl_hp_targetinfo(unsigned long arg)
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-static struct file_operations mptctl_fops = {
+static const struct file_operations mptctl_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.release = mptctl_release,
diff --git a/drivers/message/fusion/mptctl.h b/drivers/message/fusion/mptctl.h
index e65a1cf5eb0..f7e72c5e47d 100644
--- a/drivers/message/fusion/mptctl.h
+++ b/drivers/message/fusion/mptctl.h
@@ -6,7 +6,7 @@
* running LSI Logic Fusion MPT (Message Passing Technology) firmware.
*
* Copyright (c) 1999-2007 LSI Logic Corporation
- * (mailto:mpt_linux_developer@lsil.com)
+ * (mailto:mpt_linux_developer@lsi.com)
*
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c
index c819c23b55b..0caaf640399 100644
--- a/drivers/message/fusion/mptfc.c
+++ b/drivers/message/fusion/mptfc.c
@@ -4,7 +4,7 @@
* running LSI Logic Fusion MPT (Message Passing Technology) firmware.
*
* Copyright (c) 1999-2007 LSI Logic Corporation
- * (mailto:mpt_linux_developer@lsil.com)
+ * (mailto:mpt_linux_developer@lsi.com)
*
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -53,7 +53,6 @@
#include <linux/delay.h> /* for mdelay */
#include <linux/interrupt.h> /* needed for in_interrupt() proto */
#include <linux/reboot.h> /* notifier code */
-#include <linux/sched.h>
#include <linux/workqueue.h>
#include <linux/sort.h>
@@ -86,6 +85,12 @@ MODULE_PARM_DESC(mptfc_dev_loss_tmo, " Initial time the driver programs the "
" return following a device loss event."
" Default=60.");
+/* scsi-mid layer global parmeter is max_report_luns, which is 511 */
+#define MPTFC_MAX_LUN (16895)
+static int max_lun = MPTFC_MAX_LUN;
+module_param(max_lun, int, 0);
+MODULE_PARM_DESC(max_lun, " max lun, default=16895 ");
+
static int mptfcDoneCtx = -1;
static int mptfcTaskCtx = -1;
static int mptfcInternalCtx = -1; /* Used only for internal commands */
@@ -292,10 +297,9 @@ mptfc_GetFcDevPage0(MPT_ADAPTER *ioc, int ioc_port,
U32 port_id = 0xffffff;
int num_targ = 0;
int max_bus = ioc->facts.MaxBuses;
- int max_targ = ioc->facts.MaxDevices;
+ int max_targ;
- if (max_bus == 0 || max_targ == 0)
- goto out;
+ max_targ = (ioc->facts.MaxDevices == 0) ? 256 : ioc->facts.MaxDevices;
data_sz = sizeof(FCDevicePage0_t) * max_bus * max_targ;
p_p0 = p0_array = kzalloc(data_sz, GFP_KERNEL);
@@ -467,8 +471,8 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0)
if (ri->starget) {
vtarget = ri->starget->hostdata;
if (vtarget) {
- vtarget->target_id = pg0->CurrentTargetID;
- vtarget->bus_id = pg0->CurrentBus;
+ vtarget->id = pg0->CurrentTargetID;
+ vtarget->channel = pg0->CurrentBus;
}
}
*((struct mptfc_rport_info **)rport->dd_data) = ri;
@@ -540,8 +544,8 @@ mptfc_target_alloc(struct scsi_target *starget)
if (rport) {
ri = *((struct mptfc_rport_info **)rport->dd_data);
if (ri) { /* better be! */
- vtarget->target_id = ri->pg0.CurrentTargetID;
- vtarget->bus_id = ri->pg0.CurrentBus;
+ vtarget->id = ri->pg0.CurrentTargetID;
+ vtarget->channel = ri->pg0.CurrentBus;
ri->starget = starget;
rc = 0;
}
@@ -592,7 +596,6 @@ mptfc_slave_alloc(struct scsi_device *sdev)
if (vtarget->num_luns == 0) {
vtarget->ioc_id = hd->ioc->id;
vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
- hd->Targets[sdev->id] = vtarget;
}
vdev->vtarget = vtarget;
@@ -630,16 +633,17 @@ mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
struct mptfc_rport_info *ri;
struct fc_rport *rport = starget_to_rport(scsi_target(SCpnt->device));
int err;
+ VirtDevice *vdev = SCpnt->device->hostdata;
- err = fc_remote_port_chkready(rport);
- if (unlikely(err)) {
- SCpnt->result = err;
+ if (!vdev || !vdev->vtarget) {
+ SCpnt->result = DID_NO_CONNECT << 16;
done(SCpnt);
return 0;
}
- if (!SCpnt->device->hostdata) { /* vdev */
- SCpnt->result = DID_NO_CONNECT << 16;
+ err = fc_remote_port_chkready(rport);
+ if (unlikely(err)) {
+ SCpnt->result = err;
done(SCpnt);
return 0;
}
@@ -1143,7 +1147,7 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
printk(MYIOC_s_WARN_FMT
"Skipping ioc=%p because SCSI Initiator mode is NOT enabled!\n",
ioc->name, ioc);
- return -ENODEV;
+ return 0;
}
sh = scsi_host_alloc(&mptfc_driver_template, sizeof(MPT_SCSI_HOST));
@@ -1173,10 +1177,9 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
/* set 16 byte cdb's */
sh->max_cmd_len = 16;
- sh->max_id = MPT_MAX_FC_DEVICES<256 ? MPT_MAX_FC_DEVICES : 255;
+ sh->max_id = ioc->pfacts->MaxDevices;
+ sh->max_lun = max_lun;
- sh->max_lun = MPT_LAST_LUN + 1;
- sh->max_channel = 0;
sh->this_id = ioc->pfacts[0].PortSCSIID;
/* Required entry.
@@ -1230,19 +1233,6 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p\n",
ioc->name, hd->ScsiLookup));
- /* Allocate memory for the device structures.
- * A non-Null pointer at an offset
- * indicates a device exists.
- * max_id = 1 + maximum id (hosts.h)
- */
- hd->Targets = kcalloc(sh->max_id, sizeof(void *), GFP_ATOMIC);
- if (!hd->Targets) {
- error = -ENOMEM;
- goto out_mptfc_probe;
- }
-
- dprintk((KERN_INFO " vdev @ %p\n", hd->Targets));
-
/* Clear the TM flags
*/
hd->tmPending = 0;
diff --git a/drivers/message/fusion/mptlan.c b/drivers/message/fusion/mptlan.c
index 2936204d8ad..b691292ff59 100644
--- a/drivers/message/fusion/mptlan.c
+++ b/drivers/message/fusion/mptlan.c
@@ -5,6 +5,7 @@
* running LSI Logic Fusion MPT (Message Passing Technology) firmware.
*
* Copyright (c) 2000-2007 LSI Logic Corporation
+ * (mailto:mpt_linux_developer@lsi.com)
*
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
diff --git a/drivers/message/fusion/mptlan.h b/drivers/message/fusion/mptlan.h
index 70ab75e7c26..fe438bf119f 100644
--- a/drivers/message/fusion/mptlan.h
+++ b/drivers/message/fusion/mptlan.h
@@ -5,6 +5,7 @@
* running LSI Logic Fusion MPT (Message Passing Technology) firmware.
*
* Copyright (c) 2000-2007 LSI Logic Corporation
+ * (mailto:mpt_linux_developer@lsi.com)
*
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c
index 09e9a9d9641..404c014db1b 100644
--- a/drivers/message/fusion/mptsas.c
+++ b/drivers/message/fusion/mptsas.c
@@ -4,7 +4,7 @@
* running LSI Logic Fusion MPT (Message Passing Technology) firmware.
*
* Copyright (c) 1999-2007 LSI Logic Corporation
- * (mailto:mpt_linux_developer@lsil.com)
+ * (mailto:mpt_linux_developer@lsi.com)
* Copyright (c) 2005-2007 Dell
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -48,7 +48,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/errno.h>
-#include <linux/sched.h>
+#include <linux/jiffies.h>
#include <linux/workqueue.h>
#include <linux/delay.h> /* for mdelay */
@@ -83,17 +83,31 @@ MODULE_PARM_DESC(mpt_pt_clear,
" Clear persistency table: enable=1 "
"(default=MPTSCSIH_PT_CLEAR=0)");
+/* scsi-mid layer global parmeter is max_report_luns, which is 511 */
+#define MPTSAS_MAX_LUN (16895)
+static int max_lun = MPTSAS_MAX_LUN;
+module_param(max_lun, int, 0);
+MODULE_PARM_DESC(max_lun, " max lun, default=16895 ");
+
static int mptsasDoneCtx = -1;
static int mptsasTaskCtx = -1;
static int mptsasInternalCtx = -1; /* Used only for internal commands */
static int mptsasMgmtCtx = -1;
+static void mptsas_hotplug_work(struct work_struct *work);
+
+struct mptsas_target_reset_event {
+ struct list_head list;
+ EVENT_DATA_SAS_DEVICE_STATUS_CHANGE sas_event_data;
+ u8 target_reset_issued;
+};
enum mptsas_hotplug_action {
MPTSAS_ADD_DEVICE,
MPTSAS_DEL_DEVICE,
MPTSAS_ADD_RAID,
MPTSAS_DEL_RAID,
+ MPTSAS_ADD_INACTIVE_VOLUME,
MPTSAS_IGNORE_EVENT,
};
@@ -102,14 +116,15 @@ struct mptsas_hotplug_event {
MPT_ADAPTER *ioc;
enum mptsas_hotplug_action event_type;
u64 sas_address;
- u32 channel;
- u32 id;
+ u8 channel;
+ u8 id;
u32 device_info;
u16 handle;
u16 parent_handle;
u8 phy_id;
- u8 phys_disk_num;
- u8 phys_disk_num_valid;
+ u8 phys_disk_num_valid; /* hrc (hidden raid component) */
+ u8 phys_disk_num; /* hrc - unique index*/
+ u8 hidden_raid_component; /* hrc - don't expose*/
};
struct mptsas_discovery_event {
@@ -134,6 +149,7 @@ struct mptsas_devinfo {
u8 port_id; /* sas physical port this device
is assoc'd with */
u8 id; /* logical target id of this device */
+ u32 phys_disk_num; /* phys disk id, for csmi-ioctls */
u8 channel; /* logical bus number of this device */
u64 sas_address; /* WWN of this device,
SATA is assigned by HBA,expander */
@@ -153,6 +169,7 @@ struct mptsas_portinfo_details{
};
struct mptsas_phyinfo {
+ u16 handle; /* unique id to address this */
u8 phy_id; /* phy index */
u8 port_id; /* firmware port identifier */
u8 negotiated_link_rate; /* nego'd link rate for this phy */
@@ -168,7 +185,6 @@ struct mptsas_phyinfo {
struct mptsas_portinfo {
struct list_head list;
- u16 handle; /* unique id to address this */
u16 num_phys; /* number of phys */
struct mptsas_phyinfo *phy_info;
};
@@ -561,22 +577,273 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
mutex_unlock(&ioc->sas_topology_mutex);
}
+/**
+ * csmisas_find_vtarget
+ *
+ * @ioc
+ * @volume_id
+ * @volume_bus
+ *
+ **/
+static VirtTarget *
+mptsas_find_vtarget(MPT_ADAPTER *ioc, u8 channel, u8 id)
+{
+ struct scsi_device *sdev;
+ VirtDevice *vdev;
+ VirtTarget *vtarget = NULL;
+
+ shost_for_each_device(sdev, ioc->sh) {
+ if ((vdev = sdev->hostdata) == NULL)
+ continue;
+ if (vdev->vtarget->id == id &&
+ vdev->vtarget->channel == channel)
+ vtarget = vdev->vtarget;
+ }
+ return vtarget;
+}
+
+/**
+ * mptsas_target_reset
+ *
+ * Issues TARGET_RESET to end device using handshaking method
+ *
+ * @ioc
+ * @channel
+ * @id
+ *
+ * Returns (1) success
+ * (0) failure
+ *
+ **/
+static int
+mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id)
+{
+ MPT_FRAME_HDR *mf;
+ SCSITaskMgmt_t *pScsiTm;
+
+ if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) {
+ dfailprintk((MYIOC_s_WARN_FMT "%s, no msg frames @%d!!\n",
+ ioc->name,__FUNCTION__, __LINE__));
+ return 0;
+ }
+
+ /* Format the Request
+ */
+ pScsiTm = (SCSITaskMgmt_t *) mf;
+ memset (pScsiTm, 0, sizeof(SCSITaskMgmt_t));
+ pScsiTm->TargetID = id;
+ pScsiTm->Bus = channel;
+ pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
+ pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
+ pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION;
+
+ DBG_DUMP_TM_REQUEST_FRAME(mf);
+
+ if (mpt_send_handshake_request(ioc->TaskCtx, ioc,
+ sizeof(SCSITaskMgmt_t), (u32 *)mf, NO_SLEEP)) {
+ mpt_free_msg_frame(ioc, mf);
+ dfailprintk((MYIOC_s_WARN_FMT "%s, tm handshake failed @%d!!\n",
+ ioc->name,__FUNCTION__, __LINE__));
+ return 0;
+ }
+
+ return 1;
+}
+
+/**
+ * mptsas_target_reset_queue
+ *
+ * Receive request for TARGET_RESET after recieving an firmware
+ * event NOT_RESPONDING_EVENT, then put command in link list
+ * and queue if task_queue already in use.
+ *
+ * @ioc
+ * @sas_event_data
+ *
+ **/
static void
-mptsas_target_reset(MPT_ADAPTER *ioc, VirtTarget * vtarget)
+mptsas_target_reset_queue(MPT_ADAPTER *ioc,
+ EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
{
- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
+ MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
+ VirtTarget *vtarget = NULL;
+ struct mptsas_target_reset_event *target_reset_list;
+ u8 id, channel;
- if (mptscsih_TMHandler(hd,
- MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
- vtarget->bus_id, vtarget->target_id, 0, 0, 5) < 0) {
- hd->tmPending = 0;
- hd->tmState = TM_STATE_NONE;
- printk(MYIOC_s_WARN_FMT
- "Error processing TaskMgmt id=%d TARGET_RESET\n",
- ioc->name, vtarget->target_id);
+ id = sas_event_data->TargetID;
+ channel = sas_event_data->Bus;
+
+ if (!(vtarget = mptsas_find_vtarget(ioc, channel, id)))
+ return;
+
+ vtarget->deleted = 1; /* block IO */
+
+ target_reset_list = kzalloc(sizeof(*target_reset_list),
+ GFP_ATOMIC);
+ if (!target_reset_list) {
+ dfailprintk((MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n",
+ ioc->name,__FUNCTION__, __LINE__));
+ return;
+ }
+
+ memcpy(&target_reset_list->sas_event_data, sas_event_data,
+ sizeof(*sas_event_data));
+ list_add_tail(&target_reset_list->list, &hd->target_reset_list);
+
+ if (hd->resetPending)
+ return;
+
+ if (mptsas_target_reset(ioc, channel, id)) {
+ target_reset_list->target_reset_issued = 1;
+ hd->resetPending = 1;
}
}
+/**
+ * mptsas_dev_reset_complete
+ *
+ * Completion for TARGET_RESET after NOT_RESPONDING_EVENT,
+ * enable work queue to finish off removing device from upper layers.
+ * then send next TARGET_RESET in the queue.
+ *
+ * @ioc
+ *
+ **/
+static void
+mptsas_dev_reset_complete(MPT_ADAPTER *ioc)
+{
+ MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
+ struct list_head *head = &hd->target_reset_list;
+ struct mptsas_target_reset_event *target_reset_list;
+ struct mptsas_hotplug_event *ev;
+ EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data;
+ u8 id, channel;
+ __le64 sas_address;
+
+ if (list_empty(head))
+ return;
+
+ target_reset_list = list_entry(head->next, struct mptsas_target_reset_event, list);
+
+ sas_event_data = &target_reset_list->sas_event_data;
+ id = sas_event_data->TargetID;
+ channel = sas_event_data->Bus;
+ hd->resetPending = 0;
+
+ /*
+ * retry target reset
+ */
+ if (!target_reset_list->target_reset_issued) {
+ if (mptsas_target_reset(ioc, channel, id)) {
+ target_reset_list->target_reset_issued = 1;
+ hd->resetPending = 1;
+ }
+ return;
+ }
+
+ /*
+ * enable work queue to remove device from upper layers
+ */
+ list_del(&target_reset_list->list);
+
+ ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
+ if (!ev) {
+ dfailprintk((MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n",
+ ioc->name,__FUNCTION__, __LINE__));
+ return;
+ }
+
+ INIT_WORK(&ev->work, mptsas_hotplug_work);
+ ev->ioc = ioc;
+ ev->handle = le16_to_cpu(sas_event_data->DevHandle);
+ ev->parent_handle =
+ le16_to_cpu(sas_event_data->ParentDevHandle);
+ ev->channel = channel;
+ ev->id =id;
+ ev->phy_id = sas_event_data->PhyNum;
+ memcpy(&sas_address, &sas_event_data->SASAddress,
+ sizeof(__le64));
+ ev->sas_address = le64_to_cpu(sas_address);
+ ev->device_info = le32_to_cpu(sas_event_data->DeviceInfo);
+ ev->event_type = MPTSAS_DEL_DEVICE;
+ schedule_work(&ev->work);
+ kfree(target_reset_list);
+
+ /*
+ * issue target reset to next device in the queue
+ */
+
+ head = &hd->target_reset_list;
+ if (list_empty(head))
+ return;
+
+ target_reset_list = list_entry(head->next, struct mptsas_target_reset_event,
+ list);
+
+ sas_event_data = &target_reset_list->sas_event_data;
+ id = sas_event_data->TargetID;
+ channel = sas_event_data->Bus;
+
+ if (mptsas_target_reset(ioc, channel, id)) {
+ target_reset_list->target_reset_issued = 1;
+ hd->resetPending = 1;
+ }
+}
+
+/**
+ * mptsas_taskmgmt_complete
+ *
+ * @ioc
+ * @mf
+ * @mr
+ *
+ **/
+static int
+mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
+{
+ mptsas_dev_reset_complete(ioc);
+ return mptscsih_taskmgmt_complete(ioc, mf, mr);
+}
+
+/**
+ * mptscsih_ioc_reset
+ *
+ * @ioc
+ * @reset_phase
+ *
+ **/
+static int
+mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
+{
+ MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
+ struct mptsas_target_reset_event *target_reset_list, *n;
+ int rc;
+
+ rc = mptscsih_ioc_reset(ioc, reset_phase);
+
+ if (ioc->bus_type != SAS)
+ goto out;
+
+ if (reset_phase != MPT_IOC_POST_RESET)
+ goto out;
+
+ if (!hd || !hd->ioc)
+ goto out;
+
+ if (list_empty(&hd->target_reset_list))
+ goto out;
+
+ /* flush the target_reset_list */
+ list_for_each_entry_safe(target_reset_list, n,
+ &hd->target_reset_list, list) {
+ list_del(&target_reset_list->list);
+ kfree(target_reset_list);
+ }
+
+ out:
+ return rc;
+}
+
static int
mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,
u32 form, u32 form_specific)
@@ -661,8 +928,7 @@ mptsas_target_alloc(struct scsi_target *starget)
struct Scsi_Host *host = dev_to_shost(&starget->dev);
MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
VirtTarget *vtarget;
- u32 target_id;
- u32 channel;
+ u8 id, channel;
struct sas_rphy *rphy;
struct mptsas_portinfo *p;
int i;
@@ -673,15 +939,19 @@ mptsas_target_alloc(struct scsi_target *starget)
vtarget->starget = starget;
vtarget->ioc_id = hd->ioc->id;
- vtarget->tflags = MPT_TARGET_FLAGS_Q_YES|MPT_TARGET_FLAGS_VALID_INQUIRY;
-
- target_id = starget->id;
+ vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
+ id = starget->id;
channel = 0;
- hd->Targets[target_id] = vtarget;
-
- if (starget->channel == MPTSAS_RAID_CHANNEL)
+ /*
+ * RAID volumes placed beyond the last expected port.
+ */
+ if (starget->channel == MPTSAS_RAID_CHANNEL) {
+ for (i=0; i < hd->ioc->raid_data.pIocPg2->NumActiveVolumes; i++)
+ if (id == hd->ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID)
+ channel = hd->ioc->raid_data.pIocPg2->RaidVolume[i].VolumeBus;
goto out;
+ }
rphy = dev_to_rphy(starget->dev.parent);
mutex_lock(&hd->ioc->sas_topology_mutex);
@@ -690,18 +960,19 @@ mptsas_target_alloc(struct scsi_target *starget)
if (p->phy_info[i].attached.sas_address !=
rphy->identify.sas_address)
continue;
- target_id = p->phy_info[i].attached.id;
+ id = p->phy_info[i].attached.id;
channel = p->phy_info[i].attached.channel;
mptsas_set_starget(&p->phy_info[i], starget);
/*
* Exposing hidden raid components
*/
- if (mptscsih_is_phys_disk(hd->ioc, target_id)) {
- target_id = mptscsih_raid_id_to_num(hd,
- target_id);
+ if (mptscsih_is_phys_disk(hd->ioc, channel, id)) {
+ id = mptscsih_raid_id_to_num(hd->ioc,
+ channel, id);
vtarget->tflags |=
MPT_TARGET_FLAGS_RAID_COMPONENT;
+ p->phy_info[i].attached.phys_disk_num = id;
}
mutex_unlock(&hd->ioc->sas_topology_mutex);
goto out;
@@ -713,8 +984,8 @@ mptsas_target_alloc(struct scsi_target *starget)
return -ENXIO;
out:
- vtarget->target_id = target_id;
- vtarget->bus_id = channel;
+ vtarget->id = id;
+ vtarget->channel = channel;
starget->hostdata = vtarget;
return 0;
}
@@ -786,7 +1057,8 @@ mptsas_slave_alloc(struct scsi_device *sdev)
* Exposing hidden raid components
*/
if (mptscsih_is_phys_disk(hd->ioc,
- p->phy_info[i].attached.id))
+ p->phy_info[i].attached.channel,
+ p->phy_info[i].attached.id))
sdev->no_uld_attach = 1;
mutex_unlock(&hd->ioc->sas_topology_mutex);
goto out;
@@ -808,13 +1080,14 @@ mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
{
VirtDevice *vdev = SCpnt->device->hostdata;
-// scsi_print_command(SCpnt);
- if (vdev->vtarget->deleted) {
+ if (!vdev || !vdev->vtarget || vdev->vtarget->deleted) {
SCpnt->result = DID_NO_CONNECT << 16;
done(SCpnt);
return 0;
}
+// scsi_print_command(SCpnt);
+
return mptscsih_qcmd(SCpnt,done);
}
@@ -1114,9 +1387,6 @@ mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
goto out_free_consistent;
}
- if (port_info->num_phys)
- port_info->handle =
- le16_to_cpu(buffer->PhyData[0].ControllerDevHandle);
for (i = 0; i < port_info->num_phys; i++) {
mptsas_print_phy_data(&buffer->PhyData[i]);
port_info->phy_info[i].phy_id = i;
@@ -1125,6 +1395,8 @@ mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
port_info->phy_info[i].negotiated_link_rate =
buffer->PhyData[i].NegotiatedLinkRate;
port_info->phy_info[i].portinfo = port_info;
+ port_info->phy_info[i].handle =
+ le16_to_cpu(buffer->PhyData[i].ControllerDevHandle);
}
out_free_consistent:
@@ -1261,6 +1533,7 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
device_info->phy_id = buffer->PhyNum;
device_info->port_id = buffer->PhysicalPort;
device_info->id = buffer->TargetID;
+ device_info->phys_disk_num = ~0;
device_info->channel = buffer->Bus;
memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
device_info->sas_address = le64_to_cpu(sas_address);
@@ -1325,7 +1598,6 @@ mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
/* save config data */
port_info->num_phys = buffer->NumPhys;
- port_info->handle = le16_to_cpu(buffer->DevHandle);
port_info->phy_info = kcalloc(port_info->num_phys,
sizeof(*port_info->phy_info),GFP_KERNEL);
if (!port_info->phy_info) {
@@ -1333,8 +1605,11 @@ mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
goto out_free_consistent;
}
- for (i = 0; i < port_info->num_phys; i++)
+ for (i = 0; i < port_info->num_phys; i++) {
port_info->phy_info[i].portinfo = port_info;
+ port_info->phy_info[i].handle =
+ le16_to_cpu(buffer->DevHandle);
+ }
out_free_consistent:
pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
@@ -1702,7 +1977,6 @@ static int
mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
{
struct mptsas_portinfo *port_info, *hba;
- u32 handle = 0xFFFF;
int error = -ENOMEM, i;
hba = kzalloc(sizeof(*port_info), GFP_KERNEL);
@@ -1714,34 +1988,36 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
goto out_free_port_info;
mutex_lock(&ioc->sas_topology_mutex);
- ioc->handle = hba->handle;
- port_info = mptsas_find_portinfo_by_handle(ioc, hba->handle);
+ ioc->handle = hba->phy_info[0].handle;
+ port_info = mptsas_find_portinfo_by_handle(ioc, ioc->handle);
if (!port_info) {
port_info = hba;
list_add_tail(&port_info->list, &ioc->sas_topology);
} else {
- port_info->handle = hba->handle;
- for (i = 0; i < hba->num_phys; i++)
+ for (i = 0; i < hba->num_phys; i++) {
port_info->phy_info[i].negotiated_link_rate =
hba->phy_info[i].negotiated_link_rate;
+ port_info->phy_info[i].handle =
+ hba->phy_info[i].handle;
+ port_info->phy_info[i].port_id =
+ hba->phy_info[i].port_id;
+ }
kfree(hba->phy_info);
kfree(hba);
hba = NULL;
}
mutex_unlock(&ioc->sas_topology_mutex);
-
for (i = 0; i < port_info->num_phys; i++) {
mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i],
(MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER <<
MPI_SAS_PHY_PGAD_FORM_SHIFT), i);
mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify,
- (MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE <<
- MPI_SAS_DEVICE_PGAD_FORM_SHIFT), handle);
+ (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
+ MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
+ port_info->phy_info[i].handle);
port_info->phy_info[i].identify.phy_id =
- port_info->phy_info[i].phy_id;
- handle = port_info->phy_info[i].identify.handle;
-
+ port_info->phy_info[i].phy_id = i;
if (port_info->phy_info[i].attached.handle)
mptsas_sas_device_pg0(ioc,
&port_info->phy_info[i].attached,
@@ -1777,12 +2053,12 @@ mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle)
goto out;
error = mptsas_sas_expander_pg0(ioc, ex,
- (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
- MPI_SAS_EXPAND_PGAD_FORM_SHIFT), *handle);
+ (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
+ MPI_SAS_EXPAND_PGAD_FORM_SHIFT), *handle);
if (error)
goto out_free_port_info;
- *handle = ex->handle;
+ *handle = ex->phy_info[0].handle;
mutex_lock(&ioc->sas_topology_mutex);
port_info = mptsas_find_portinfo_by_handle(ioc, *handle);
@@ -1790,7 +2066,12 @@ mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle)
port_info = ex;
list_add_tail(&port_info->list, &ioc->sas_topology);
} else {
- port_info->handle = ex->handle;
+ for (i = 0; i < ex->num_phys; i++) {
+ port_info->phy_info[i].handle =
+ ex->phy_info[i].handle;
+ port_info->phy_info[i].port_id =
+ ex->phy_info[i].port_id;
+ }
kfree(ex->phy_info);
kfree(ex);
ex = NULL;
@@ -1868,8 +2149,6 @@ mptsas_delete_expander_phys(MPT_ADAPTER *ioc)
struct mptsas_portinfo buffer;
struct mptsas_portinfo *port_info, *n, *parent;
struct mptsas_phyinfo *phy_info;
- struct scsi_target * starget;
- VirtTarget * vtarget;
struct sas_port * port;
int i;
u64 expander_sas_address;
@@ -1884,26 +2163,8 @@ mptsas_delete_expander_phys(MPT_ADAPTER *ioc)
if (mptsas_sas_expander_pg0(ioc, &buffer,
(MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
- MPI_SAS_EXPAND_PGAD_FORM_SHIFT), port_info->handle)) {
-
- /*
- * Issue target reset to all child end devices
- * then mark them deleted to prevent further
- * IO going to them.
- */
- phy_info = port_info->phy_info;
- for (i = 0; i < port_info->num_phys; i++, phy_info++) {
- starget = mptsas_get_starget(phy_info);
- if (!starget)
- continue;
- vtarget = starget->hostdata;
- if(vtarget->deleted)
- continue;
- vtarget->deleted = 1;
- mptsas_target_reset(ioc, vtarget);
- sas_port_delete(mptsas_get_port(phy_info));
- mptsas_port_delete(phy_info->port_details);
- }
+ MPI_SAS_EXPAND_PGAD_FORM_SHIFT),
+ port_info->phy_info[0].handle)) {
/*
* Obtain the port_info instance to the parent port
@@ -1972,11 +2233,13 @@ mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
/*
Reporting RAID volumes.
*/
+ if (!ioc->ir_firmware)
+ goto out;
if (!ioc->raid_data.pIocPg2)
goto out;
if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
goto out;
- for (i=0; i<ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
+ for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
}
@@ -2030,12 +2293,37 @@ mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
mutex_lock(&ioc->sas_topology_mutex);
list_for_each_entry(port_info, &ioc->sas_topology, list) {
for (i = 0; i < port_info->num_phys; i++) {
+ if (!mptsas_is_end_device(
+ &port_info->phy_info[i].attached))
+ continue;
if (port_info->phy_info[i].attached.sas_address
!= sas_address)
continue;
+ phy_info = &port_info->phy_info[i];
+ break;
+ }
+ }
+ mutex_unlock(&ioc->sas_topology_mutex);
+ return phy_info;
+}
+
+static struct mptsas_phyinfo *
+mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u8 channel, u8 id)
+{
+ struct mptsas_portinfo *port_info;
+ struct mptsas_phyinfo *phy_info = NULL;
+ int i;
+
+ mutex_lock(&ioc->sas_topology_mutex);
+ list_for_each_entry(port_info, &ioc->sas_topology, list) {
+ for (i = 0; i < port_info->num_phys; i++) {
if (!mptsas_is_end_device(
&port_info->phy_info[i].attached))
continue;
+ if (port_info->phy_info[i].attached.id != id)
+ continue;
+ if (port_info->phy_info[i].attached.channel != channel)
+ continue;
phy_info = &port_info->phy_info[i];
break;
}
@@ -2045,7 +2333,7 @@ mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
}
static struct mptsas_phyinfo *
-mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u32 id)
+mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
{
struct mptsas_portinfo *port_info;
struct mptsas_phyinfo *phy_info = NULL;
@@ -2054,11 +2342,15 @@ mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u32 id)
mutex_lock(&ioc->sas_topology_mutex);
list_for_each_entry(port_info, &ioc->sas_topology, list) {
for (i = 0; i < port_info->num_phys; i++) {
- if (port_info->phy_info[i].attached.id != id)
- continue;
if (!mptsas_is_end_device(
&port_info->phy_info[i].attached))
continue;
+ if (port_info->phy_info[i].attached.phys_disk_num == ~0)
+ continue;
+ if (port_info->phy_info[i].attached.phys_disk_num != id)
+ continue;
+ if (port_info->phy_info[i].attached.channel != channel)
+ continue;
phy_info = &port_info->phy_info[i];
break;
}
@@ -2094,6 +2386,76 @@ mptsas_reprobe_target(struct scsi_target *starget, int uld_attach)
mptsas_reprobe_lun);
}
+static void
+mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
+{
+ CONFIGPARMS cfg;
+ ConfigPageHeader_t hdr;
+ dma_addr_t dma_handle;
+ pRaidVolumePage0_t buffer = NULL;
+ RaidPhysDiskPage0_t phys_disk;
+ int i;
+ struct mptsas_hotplug_event *ev;
+
+ memset(&cfg, 0 , sizeof(CONFIGPARMS));
+ memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
+ hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
+ cfg.pageAddr = (channel << 8) + id;
+ cfg.cfghdr.hdr = &hdr;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+
+ if (mpt_config(ioc, &cfg) != 0)
+ goto out;
+
+ if (!hdr.PageLength)
+ goto out;
+
+ buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
+ &dma_handle);
+
+ if (!buffer)
+ goto out;
+
+ cfg.physAddr = dma_handle;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+ if (mpt_config(ioc, &cfg) != 0)
+ goto out;
+
+ if (!(buffer->VolumeStatus.Flags &
+ MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE))
+ goto out;
+
+ if (!buffer->NumPhysDisks)
+ goto out;
+
+ for (i = 0; i < buffer->NumPhysDisks; i++) {
+
+ if (mpt_raid_phys_disk_pg0(ioc,
+ buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
+ continue;
+
+ ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
+ if (!ev) {
+ printk(KERN_WARNING "mptsas: lost hotplug event\n");
+ goto out;
+ }
+
+ INIT_WORK(&ev->work, mptsas_hotplug_work);
+ ev->ioc = ioc;
+ ev->id = phys_disk.PhysDiskID;
+ ev->channel = phys_disk.PhysDiskBus;
+ ev->phys_disk_num_valid = 1;
+ ev->phys_disk_num = phys_disk.PhysDiskNum;
+ ev->event_type = MPTSAS_ADD_DEVICE;
+ schedule_work(&ev->work);
+ }
+
+ out:
+ if (buffer)
+ pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
+ dma_handle);
+}
/*
* Work queue thread to handle SAS hotplug events
*/
@@ -2102,6 +2464,7 @@ mptsas_hotplug_work(struct work_struct *work)
{
struct mptsas_hotplug_event *ev =
container_of(work, struct mptsas_hotplug_event, work);
+
MPT_ADAPTER *ioc = ev->ioc;
struct mptsas_phyinfo *phy_info;
struct sas_rphy *rphy;
@@ -2114,17 +2477,43 @@ mptsas_hotplug_work(struct work_struct *work)
VirtTarget *vtarget;
VirtDevice *vdevice;
-
mutex_lock(&ioc->sas_discovery_mutex);
switch (ev->event_type) {
case MPTSAS_DEL_DEVICE:
- phy_info = mptsas_find_phyinfo_by_target(ioc, ev->id);
+ phy_info = NULL;
+ if (ev->phys_disk_num_valid) {
+ if (ev->hidden_raid_component){
+ if (mptsas_sas_device_pg0(ioc, &sas_device,
+ (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
+ MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
+ (ev->channel << 8) + ev->id)) {
+ dfailprintk((MYIOC_s_ERR_FMT
+ "%s: exit at line=%d\n", ioc->name,
+ __FUNCTION__, __LINE__));
+ break;
+ }
+ phy_info = mptsas_find_phyinfo_by_sas_address(
+ ioc, sas_device.sas_address);
+ }else
+ phy_info = mptsas_find_phyinfo_by_phys_disk_num(
+ ioc, ev->channel, ev->phys_disk_num);
+ }
+
+ if (!phy_info)
+ phy_info = mptsas_find_phyinfo_by_target(ioc,
+ ev->channel, ev->id);
/*
* Sanity checks, for non-existing phys and remote rphys.
*/
- if (!phy_info || !phy_info->port_details) {
+ if (!phy_info){
+ dfailprintk((MYIOC_s_ERR_FMT
+ "%s: exit at line=%d\n", ioc->name,
+ __FUNCTION__, __LINE__));
+ break;
+ }
+ if (!phy_info->port_details) {
dfailprintk((MYIOC_s_ERR_FMT
"%s: exit at line=%d\n", ioc->name,
__FUNCTION__, __LINE__));
@@ -2137,6 +2526,7 @@ mptsas_hotplug_work(struct work_struct *work)
__FUNCTION__, __LINE__));
break;
}
+
port = mptsas_get_port(phy_info);
if (!port) {
dfailprintk((MYIOC_s_ERR_FMT
@@ -2159,28 +2549,35 @@ mptsas_hotplug_work(struct work_struct *work)
/*
* Handling RAID components
*/
- if (ev->phys_disk_num_valid) {
- vtarget->target_id = ev->phys_disk_num;
- vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
+ if (ev->phys_disk_num_valid &&
+ ev->hidden_raid_component) {
+ printk(MYIOC_s_INFO_FMT
+ "RAID Hidding: channel=%d, id=%d, "
+ "physdsk %d \n", ioc->name, ev->channel,
+ ev->id, ev->phys_disk_num);
+ vtarget->id = ev->phys_disk_num;
+ vtarget->tflags |=
+ MPT_TARGET_FLAGS_RAID_COMPONENT;
mptsas_reprobe_target(starget, 1);
- break;
+ phy_info->attached.phys_disk_num =
+ ev->phys_disk_num;
+ break;
}
-
- vtarget->deleted = 1;
- mptsas_target_reset(ioc, vtarget);
}
- if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_TARGET)
+ if (phy_info->attached.device_info &
+ MPI_SAS_DEVICE_INFO_SSP_TARGET)
ds = "ssp";
- if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_STP_TARGET)
+ if (phy_info->attached.device_info &
+ MPI_SAS_DEVICE_INFO_STP_TARGET)
ds = "stp";
- if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
+ if (phy_info->attached.device_info &
+ MPI_SAS_DEVICE_INFO_SATA_DEVICE)
ds = "sata";
printk(MYIOC_s_INFO_FMT
"removing %s device, channel %d, id %d, phy %d\n",
ioc->name, ds, ev->channel, ev->id, phy_info->phy_id);
-
#ifdef MPT_DEBUG_SAS_WIDE
dev_printk(KERN_DEBUG, &port->dev,
"delete port (%d)\n", port->port_identifier);
@@ -2198,14 +2595,14 @@ mptsas_hotplug_work(struct work_struct *work)
*/
if (mptsas_sas_device_pg0(ioc, &sas_device,
(MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
- MPI_SAS_DEVICE_PGAD_FORM_SHIFT), ev->id)) {
+ MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
+ (ev->channel << 8) + ev->id)) {
dfailprintk((MYIOC_s_ERR_FMT
"%s: exit at line=%d\n", ioc->name,
__FUNCTION__, __LINE__));
break;
}
- ssleep(2);
__mptsas_discovery_work(ioc);
phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
@@ -2219,7 +2616,8 @@ mptsas_hotplug_work(struct work_struct *work)
}
starget = mptsas_get_starget(phy_info);
- if (starget) {
+ if (starget && (!ev->hidden_raid_component)){
+
vtarget = starget->hostdata;
if (!vtarget) {
@@ -2232,9 +2630,15 @@ mptsas_hotplug_work(struct work_struct *work)
* Handling RAID components
*/
if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
- vtarget->tflags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT;
- vtarget->target_id = ev->id;
+ printk(MYIOC_s_INFO_FMT
+ "RAID Exposing: channel=%d, id=%d, "
+ "physdsk %d \n", ioc->name, ev->channel,
+ ev->id, ev->phys_disk_num);
+ vtarget->tflags &=
+ ~MPT_TARGET_FLAGS_RAID_COMPONENT;
+ vtarget->id = ev->id;
mptsas_reprobe_target(starget, 0);
+ phy_info->attached.phys_disk_num = ~0;
}
break;
}
@@ -2243,8 +2647,10 @@ mptsas_hotplug_work(struct work_struct *work)
dfailprintk((MYIOC_s_ERR_FMT
"%s: exit at line=%d\n", ioc->name,
__FUNCTION__, __LINE__));
+ if (ev->channel) printk("%d\n", __LINE__);
break;
}
+
port = mptsas_get_port(phy_info);
if (!port) {
dfailprintk((MYIOC_s_ERR_FMT
@@ -2252,15 +2658,17 @@ mptsas_hotplug_work(struct work_struct *work)
__FUNCTION__, __LINE__));
break;
}
-
memcpy(&phy_info->attached, &sas_device,
sizeof(struct mptsas_devinfo));
- if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_TARGET)
+ if (phy_info->attached.device_info &
+ MPI_SAS_DEVICE_INFO_SSP_TARGET)
ds = "ssp";
- if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_STP_TARGET)
+ if (phy_info->attached.device_info &
+ MPI_SAS_DEVICE_INFO_STP_TARGET)
ds = "stp";
- if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
+ if (phy_info->attached.device_info &
+ MPI_SAS_DEVICE_INFO_SATA_DEVICE)
ds = "sata";
printk(MYIOC_s_INFO_FMT
@@ -2301,19 +2709,21 @@ mptsas_hotplug_work(struct work_struct *work)
break;
case MPTSAS_DEL_RAID:
sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
- ev->id, 0);
+ ev->id, 0);
if (!sdev)
break;
printk(MYIOC_s_INFO_FMT
"removing raid volume, channel %d, id %d\n",
ioc->name, MPTSAS_RAID_CHANNEL, ev->id);
vdevice = sdev->hostdata;
- vdevice->vtarget->deleted = 1;
- mptsas_target_reset(ioc, vdevice->vtarget);
scsi_remove_device(sdev);
scsi_device_put(sdev);
mpt_findImVolumes(ioc);
break;
+ case MPTSAS_ADD_INACTIVE_VOLUME:
+ mptsas_adding_inactive_raid_components(ioc,
+ ev->channel, ev->id);
+ break;
case MPTSAS_IGNORE_EVENT:
default:
break;
@@ -2321,7 +2731,6 @@ mptsas_hotplug_work(struct work_struct *work)
mutex_unlock(&ioc->sas_discovery_mutex);
kfree(ev);
-
}
static void
@@ -2339,8 +2748,12 @@ mptsas_send_sas_event(MPT_ADAPTER *ioc,
return;
switch (sas_event_data->ReasonCode) {
- case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
+
+ mptsas_target_reset_queue(ioc, sas_event_data);
+ break;
+
+ case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
if (!ev) {
printk(KERN_WARNING "mptsas: lost hotplug event\n");
@@ -2375,15 +2788,20 @@ mptsas_send_sas_event(MPT_ADAPTER *ioc,
mptsas_persist_clear_table);
schedule_work(&ioc->sas_persist_task);
break;
+ /*
+ * TODO, handle other events
+ */
case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
- /* TODO */
+ case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
- /* TODO */
+ case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
+ case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
+ case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
+ case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
default:
break;
}
}
-
static void
mptsas_send_raid_event(MPT_ADAPTER *ioc,
EVENT_DATA_RAID *raid_event_data)
@@ -2404,31 +2822,36 @@ mptsas_send_raid_event(MPT_ADAPTER *ioc,
INIT_WORK(&ev->work, mptsas_hotplug_work);
ev->ioc = ioc;
ev->id = raid_event_data->VolumeID;
+ ev->channel = raid_event_data->VolumeBus;
ev->event_type = MPTSAS_IGNORE_EVENT;
switch (raid_event_data->ReasonCode) {
case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
+ ev->phys_disk_num_valid = 1;
+ ev->phys_disk_num = raid_event_data->PhysDiskNum;
ev->event_type = MPTSAS_ADD_DEVICE;
break;
case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
- ioc->raid_data.isRaid = 1;
ev->phys_disk_num_valid = 1;
ev->phys_disk_num = raid_event_data->PhysDiskNum;
+ ev->hidden_raid_component = 1;
ev->event_type = MPTSAS_DEL_DEVICE;
break;
case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
switch (state) {
case MPI_PD_STATE_ONLINE:
- ioc->raid_data.isRaid = 1;
+ case MPI_PD_STATE_NOT_COMPATIBLE:
ev->phys_disk_num_valid = 1;
ev->phys_disk_num = raid_event_data->PhysDiskNum;
+ ev->hidden_raid_component = 1;
ev->event_type = MPTSAS_ADD_DEVICE;
break;
case MPI_PD_STATE_MISSING:
- case MPI_PD_STATE_NOT_COMPATIBLE:
case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST:
case MPI_PD_STATE_FAILED_AT_HOST_REQUEST:
case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON:
+ ev->phys_disk_num_valid = 1;
+ ev->phys_disk_num = raid_event_data->PhysDiskNum;
ev->event_type = MPTSAS_DEL_DEVICE;
break;
default:
@@ -2485,6 +2908,35 @@ mptsas_send_discovery_event(MPT_ADAPTER *ioc,
schedule_work(&ev->work);
};
+/*
+ * mptsas_send_ir2_event - handle exposing hidden disk when
+ * an inactive raid volume is added
+ *
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @ir2_data
+ *
+ */
+static void
+mptsas_send_ir2_event(MPT_ADAPTER *ioc, PTR_MPI_EVENT_DATA_IR2 ir2_data)
+{
+ struct mptsas_hotplug_event *ev;
+
+ if (ir2_data->ReasonCode !=
+ MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED)
+ return;
+
+ ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
+ if (!ev)
+ return;
+
+ INIT_WORK(&ev->work, mptsas_hotplug_work);
+ ev->ioc = ioc;
+ ev->id = ir2_data->TargetID;
+ ev->channel = ir2_data->Bus;
+ ev->event_type = MPTSAS_ADD_INACTIVE_VOLUME;
+
+ schedule_work(&ev->work);
+};
static int
mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
@@ -2524,6 +2976,10 @@ mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
mptsas_send_discovery_event(ioc,
(EVENT_DATA_SAS_DISCOVERY *)reply->Data);
break;
+ case MPI_EVENT_IR2:
+ mptsas_send_ir2_event(ioc,
+ (PTR_MPI_EVENT_DATA_IR2)reply->Data);
+ break;
default:
rc = mptscsih_event_process(ioc, reply);
break;
@@ -2611,12 +3067,11 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
/* set 16 byte cdb's */
sh->max_cmd_len = 16;
- sh->max_id = ioc->pfacts->MaxDevices + 1;
+ sh->max_id = ioc->pfacts[0].PortSCSIID;
+ sh->max_lun = max_lun;
sh->transportt = mptsas_transport_template;
- sh->max_lun = MPT_LAST_LUN + 1;
- sh->max_channel = 0;
sh->this_id = ioc->pfacts[0].PortSCSIID;
/* Required entry.
@@ -2659,8 +3114,6 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
sh->sg_tablesize = numSGE;
}
- spin_unlock_irqrestore(&ioc->FreeQlock, flags);
-
hd = (MPT_SCSI_HOST *) sh->hostdata;
hd->ioc = ioc;
@@ -2676,19 +3129,6 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p\n",
ioc->name, hd->ScsiLookup));
- /* Allocate memory for the device structures.
- * A non-Null pointer at an offset
- * indicates a device exists.
- * max_id = 1 + maximum id (hosts.h)
- */
- hd->Targets = kcalloc(sh->max_id, sizeof(void *), GFP_ATOMIC);
- if (!hd->Targets) {
- error = -ENOMEM;
- goto out_mptsas_probe;
- }
-
- dprintk((KERN_INFO " vtarget @ %p\n", hd->Targets));
-
/* Clear the TM flags
*/
hd->tmPending = 0;
@@ -2713,15 +3153,17 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
ioc->sas_data.ptClear = mpt_pt_clear;
+ init_waitqueue_head(&hd->scandv_waitq);
+ hd->scandv_wait_done = 0;
+ hd->last_queue_full = 0;
+ INIT_LIST_HEAD(&hd->target_reset_list);
+ spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+
if (ioc->sas_data.ptClear==1) {
mptbase_sas_persist_operation(
ioc, MPI_SAS_OP_CLEAR_ALL_PERSISTENT);
}
- init_waitqueue_head(&hd->scandv_waitq);
- hd->scandv_wait_done = 0;
- hd->last_queue_full = 0;
-
error = scsi_add_host(sh, &ioc->pcidev->dev);
if (error) {
dprintk((KERN_ERR MYNAM
@@ -2745,7 +3187,7 @@ static void __devexit mptsas_remove(struct pci_dev *pdev)
struct mptsas_portinfo *p, *n;
int i;
- ioc->sas_discovery_ignore_events=1;
+ ioc->sas_discovery_ignore_events = 1;
sas_remove_host(ioc->sh);
mutex_lock(&ioc->sas_topology_mutex);
@@ -2800,7 +3242,7 @@ mptsas_init(void)
return -ENODEV;
mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER);
- mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER);
+ mptsasTaskCtx = mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER);
mptsasInternalCtx =
mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);
mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER);
@@ -2810,7 +3252,7 @@ mptsas_init(void)
": Registered for IOC event notifications\n"));
}
- if (mpt_reset_register(mptsasDoneCtx, mptscsih_ioc_reset) == 0) {
+ if (mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset) == 0) {
dprintk((KERN_INFO MYNAM
": Registered for IOC reset notifications\n"));
}
diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c
index f0cca3ea93b..2a3e9e66d4e 100644
--- a/drivers/message/fusion/mptscsih.c
+++ b/drivers/message/fusion/mptscsih.c
@@ -4,7 +4,7 @@
* running LSI Logic Fusion MPT (Message Passing Technology) firmware.
*
* Copyright (c) 1999-2007 LSI Logic Corporation
- * (mailto:mpt_linux_developer@lsil.com)
+ * (mailto:mpt_linux_developer@lsi.com)
*
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -54,7 +54,6 @@
#include <linux/delay.h> /* for mdelay */
#include <linux/interrupt.h> /* needed for in_interrupt() proto */
#include <linux/reboot.h> /* notifier code */
-#include <linux/sched.h>
#include <linux/workqueue.h>
#include <scsi/scsi.h>
@@ -79,43 +78,6 @@ MODULE_LICENSE("GPL");
MODULE_VERSION(my_VERSION);
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-
-typedef struct _BIG_SENSE_BUF {
- u8 data[MPT_SENSE_BUFFER_ALLOC];
-} BIG_SENSE_BUF;
-
-#define MPT_SCANDV_GOOD (0x00000000) /* must be 0 */
-#define MPT_SCANDV_DID_RESET (0x00000001)
-#define MPT_SCANDV_SENSE (0x00000002)
-#define MPT_SCANDV_SOME_ERROR (0x00000004)
-#define MPT_SCANDV_SELECTION_TIMEOUT (0x00000008)
-#define MPT_SCANDV_ISSUE_SENSE (0x00000010)
-#define MPT_SCANDV_FALLBACK (0x00000020)
-
-#define MPT_SCANDV_MAX_RETRIES (10)
-
-#define MPT_ICFLAG_BUF_CAP 0x01 /* ReadBuffer Read Capacity format */
-#define MPT_ICFLAG_ECHO 0x02 /* ReadBuffer Echo buffer format */
-#define MPT_ICFLAG_EBOS 0x04 /* ReadBuffer Echo buffer has EBOS */
-#define MPT_ICFLAG_PHYS_DISK 0x08 /* Any SCSI IO but do Phys Disk Format */
-#define MPT_ICFLAG_TAGGED_CMD 0x10 /* Do tagged IO */
-#define MPT_ICFLAG_DID_RESET 0x20 /* Bus Reset occurred with this command */
-#define MPT_ICFLAG_RESERVED 0x40 /* Reserved has been issued */
-
-typedef struct _internal_cmd {
- char *data; /* data pointer */
- dma_addr_t data_dma; /* data dma address */
- int size; /* transfer size */
- u8 cmd; /* SCSI Op Code */
- u8 bus; /* bus number */
- u8 id; /* SCSI ID (virtual) */
- u8 lun;
- u8 flags; /* Bit Field - See above */
- u8 physDiskNum; /* Phys disk number, -1 else */
- u8 rsvd2;
- u8 rsvd;
-} INTERNAL_CMD;
-
/*
* Other private/forward protos...
*/
@@ -131,14 +93,11 @@ static int mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd);
static int mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout );
static int SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc);
-static int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout);
+static int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout);
int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset);
int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
-static void mptscsih_initTarget(MPT_SCSI_HOST *hd, VirtTarget *vtarget, struct scsi_device *sdev);
-static void mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *vtarget, struct scsi_device *sdev);
-static int mptscsih_writeIOCPage4(MPT_SCSI_HOST *hd, int target_id, int bus);
int mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
static int mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd);
static void mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice);
@@ -517,16 +476,100 @@ mptscsih_issue_sep_command(MPT_ADAPTER *ioc, VirtTarget *vtarget,
SEPMsg = (SEPRequest_t *)mf;
SEPMsg->Function = MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
- SEPMsg->Bus = vtarget->bus_id;
- SEPMsg->TargetID = vtarget->target_id;
+ SEPMsg->Bus = vtarget->channel;
+ SEPMsg->TargetID = vtarget->id;
SEPMsg->Action = MPI_SEP_REQ_ACTION_WRITE_STATUS;
SEPMsg->SlotStatus = SlotStatus;
devtverboseprintk((MYIOC_s_WARN_FMT
- "Sending SEP cmd=%x id=%d bus=%d\n",
- ioc->name, SlotStatus, SEPMsg->TargetID, SEPMsg->Bus));
+ "Sending SEP cmd=%x channel=%d id=%d\n",
+ ioc->name, SlotStatus, SEPMsg->Bus, SEPMsg->TargetID));
mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
}
+#ifdef MPT_DEBUG_REPLY
+/**
+ * mptscsih_iocstatus_info_scsiio - IOCSTATUS information for SCSIIO
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @ioc_status: U32 IOCStatus word from IOC
+ * @scsi_status: U8 sam status from target
+ * @scsi_state: U8 scsi state
+ * @sc: original scsi cmnd pointer
+ * @mf: Pointer to MPT request frame
+ *
+ * Refer to lsi/mpi.h.
+ **/
+static void
+mptscsih_iocstatus_info_scsiio(MPT_ADAPTER *ioc, u32 ioc_status,
+ u8 scsi_status, u8 scsi_state, struct scsi_cmnd *sc)
+{
+ char extend_desc[EVENT_DESCR_STR_SZ];
+ char *desc = NULL;
+
+ switch (ioc_status) {
+
+ case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
+ desc = "SCSI Invalid Bus";
+ break;
+
+ case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
+ desc = "SCSI Invalid TargetID";
+ break;
+
+ case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
+ /*
+ * Inquiry is issued for device scanning
+ */
+ if (sc->cmnd[0] != 0x12)
+ desc = "SCSI Device Not There";
+ break;
+
+ case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
+ desc = "SCSI Data Overrun";
+ break;
+
+ case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
+ desc = "SCSI I/O Data Error";
+ break;
+
+ case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
+ desc = "SCSI Protocol Error";
+ break;
+
+ case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
+ desc = "SCSI Task Terminated";
+ break;
+
+ case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
+ desc = "SCSI Residual Mismatch";
+ break;
+
+ case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
+ desc = "SCSI Task Management Failed";
+ break;
+
+ case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
+ desc = "SCSI IOC Terminated";
+ break;
+
+ case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
+ desc = "SCSI Ext Terminated";
+ break;
+ }
+
+ if (!desc)
+ return;
+
+ snprintf(extend_desc, EVENT_DESCR_STR_SZ,
+ "[%d:%d:%d:%d] cmd=%02Xh, sam_status=%02Xh state=%02Xh",
+ sc->device->host->host_no,
+ sc->device->channel, sc->device->id, sc->device->lun,
+ sc->cmnd[0], scsi_status, scsi_state);
+
+ printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04X): %s: %s\n",
+ ioc->name, ioc_status, desc, extend_desc);
+}
+#endif
+
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
* mptscsih_io_done - Main SCSI IO callback routine registered to
@@ -613,12 +656,14 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
u32 xfer_cnt;
u16 status;
u8 scsi_state, scsi_status;
+ u32 log_info;
status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
scsi_state = pScsiReply->SCSIState;
scsi_status = pScsiReply->SCSIStatus;
xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);
sc->resid = sc->request_bufflen - xfer_cnt;
+ log_info = le32_to_cpu(pScsiReply->IOCLogInfo);
/*
* if we get a data underrun indication, yet no data was
@@ -633,13 +678,6 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
status = MPI_IOCSTATUS_SUCCESS;
}
- dreplyprintk((KERN_NOTICE "Reply ha=%d id=%d lun=%d:\n"
- "IOCStatus=%04xh SCSIState=%02xh SCSIStatus=%02xh\n"
- "resid=%d bufflen=%d xfer_cnt=%d\n",
- ioc->id, sc->device->id, sc->device->lun,
- status, scsi_state, scsi_status, sc->resid,
- sc->request_bufflen, xfer_cnt));
-
if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID)
mptscsih_copy_sense_data(sc, hd, mf, pScsiReply);
@@ -648,9 +686,10 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
*/
if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
pScsiReply->ResponseInfo) {
- printk(KERN_NOTICE "ha=%d id=%d lun=%d: "
+ printk(KERN_NOTICE "[%d:%d:%d:%d] "
"FCP_ResponseInfo=%08xh\n",
- ioc->id, sc->device->id, sc->device->lun,
+ sc->device->host->host_no, sc->device->channel,
+ sc->device->id, sc->device->lun,
le32_to_cpu(pScsiReply->ResponseInfo));
}
@@ -695,9 +734,8 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
if ( ioc->bus_type == SAS ) {
u16 ioc_status = le16_to_cpu(pScsiReply->IOCStatus);
if (ioc_status & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
- u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo);
- log_info &=SAS_LOGINFO_MASK;
- if (log_info == SAS_LOGINFO_NEXUS_LOSS) {
+ if ((log_info & SAS_LOGINFO_MASK)
+ == SAS_LOGINFO_NEXUS_LOSS) {
sc->result = (DID_BUS_BUSY << 16);
break;
}
@@ -735,7 +773,8 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
else /* Sufficient data transfer occurred */
sc->result = (DID_OK << 16) | scsi_status;
dreplyprintk((KERN_NOTICE
- "RESIDUAL_MISMATCH: result=%x on id=%d\n", sc->result, sc->device->id));
+ "RESIDUAL_MISMATCH: result=%x on channel=%d id=%d\n",
+ sc->result, sc->device->channel, sc->device->id));
break;
case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
@@ -848,7 +887,28 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
} /* switch(status) */
- dreplyprintk((KERN_NOTICE " sc->result is %08xh\n", sc->result));
+#ifdef MPT_DEBUG_REPLY
+ if (sc->result) {
+
+ mptscsih_iocstatus_info_scsiio(ioc, status,
+ scsi_status, scsi_state, sc);
+
+ dreplyprintk(("%s: [%d:%d:%d:%d] cmd=0x%02x "
+ "result=0x%08x\n\tiocstatus=0x%04X "
+ "scsi_state=0x%02X scsi_status=0x%02X "
+ "loginfo=0x%08X\n", __FUNCTION__,
+ sc->device->host->host_no, sc->device->channel, sc->device->id,
+ sc->device->lun, sc->cmnd[0], sc->result, status,
+ scsi_state, scsi_status, log_info));
+
+ dreplyprintk(("%s: [%d:%d:%d:%d] resid=%d "
+ "bufflen=%d xfer_cnt=%d\n", __FUNCTION__,
+ sc->device->host->host_no, sc->device->channel, sc->device->id,
+ sc->device->lun, sc->resid, sc->request_bufflen,
+ xfer_cnt));
+ }
+#endif
+
} /* end of address reply case */
/* Unmap the DMA buffers, if any. */
@@ -955,9 +1015,10 @@ mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
int ii;
int max = hd->ioc->req_depth;
struct scsi_cmnd *sc;
+ struct scsi_lun lun;
- dsprintk((KERN_INFO MYNAM ": search_running target %d lun %d max %d\n",
- vdevice->vtarget->target_id, vdevice->lun, max));
+ dsprintk((KERN_INFO MYNAM ": search_running channel %d id %d lun %d max %d\n",
+ vdevice->vtarget->channel, vdevice->vtarget->id, vdevice->lun, max));
for (ii=0; ii < max; ii++) {
if ((sc = hd->ScsiLookup[ii]) != NULL) {
@@ -965,10 +1026,14 @@ mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(hd->ioc, ii);
if (mf == NULL)
continue;
- dsprintk(( "search_running: found (sc=%p, mf = %p) target %d, lun %d \n",
- hd->ScsiLookup[ii], mf, mf->TargetID, mf->LUN[1]));
- if ((mf->TargetID != ((u8)vdevice->vtarget->target_id)) || (mf->LUN[1] != ((u8) vdevice->lun)))
+ int_to_scsilun(vdevice->lun, &lun);
+ if ((mf->Bus != vdevice->vtarget->channel) ||
+ (mf->TargetID != vdevice->vtarget->id) ||
+ memcmp(lun.scsi_lun, mf->LUN, 8))
continue;
+ dsprintk(( "search_running: found (sc=%p, mf = %p) "
+ "channel %d id %d, lun %d \n", hd->ScsiLookup[ii],
+ mf, mf->Bus, mf->TargetID, vdevice->lun));
/* Cleanup
*/
@@ -1065,12 +1130,6 @@ mptscsih_remove(struct pci_dev *pdev)
hd->ScsiLookup = NULL;
}
- /*
- * Free pointer array.
- */
- kfree(hd->Targets);
- hd->Targets = NULL;
-
dprintk((MYIOC_s_INFO_FMT
"Free'd ScsiLookup (%d) memory\n",
hd->ioc->name, sz1));
@@ -1317,14 +1376,6 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
return SCSI_MLQUEUE_HOST_BUSY;
}
- if ((hd->ioc->bus_type == SPI) &&
- vdev->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT &&
- mptscsih_raid_id_to_num(hd, SCpnt->device->id) < 0) {
- SCpnt->result = DID_NO_CONNECT << 16;
- done(SCpnt);
- return 0;
- }
-
/*
* Put together a MPT SCSI request...
*/
@@ -1368,8 +1419,8 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
/* Use the above information to set up the message frame
*/
- pScsiReq->TargetID = (u8) vdev->vtarget->target_id;
- pScsiReq->Bus = vdev->vtarget->bus_id;
+ pScsiReq->TargetID = (u8) vdev->vtarget->id;
+ pScsiReq->Bus = vdev->vtarget->channel;
pScsiReq->ChainOffset = 0;
if (vdev->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
@@ -1379,14 +1430,7 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE;
pScsiReq->Reserved = 0;
pScsiReq->MsgFlags = mpt_msg_flags();
- pScsiReq->LUN[0] = 0;
- pScsiReq->LUN[1] = lun;
- pScsiReq->LUN[2] = 0;
- pScsiReq->LUN[3] = 0;
- pScsiReq->LUN[4] = 0;
- pScsiReq->LUN[5] = 0;
- pScsiReq->LUN[6] = 0;
- pScsiReq->LUN[7] = 0;
+ int_to_scsilun(SCpnt->device->lun, (struct scsi_lun *)pScsiReq->LUN);
pScsiReq->Control = cpu_to_le32(scsictl);
/*
@@ -1491,14 +1535,14 @@ mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx)
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
+/**
* mptscsih_TMHandler - Generic handler for SCSI Task Management.
* Fall through to mpt_HardResetHandler if: not operational, too many
* failed TM requests or handshake failure.
*
* @ioc: Pointer to MPT_ADAPTER structure
* @type: Task Management type
- * @target: Logical Target ID for reset (if appropriate)
+ * @id: Logical Target ID for reset (if appropriate)
* @lun: Logical Unit for reset (if appropriate)
* @ctx2abort: Context for the task to be aborted (if appropriate)
*
@@ -1507,28 +1551,17 @@ mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx)
* Remark: With old EH code, at most 1 SCSI TaskMgmt function per IOC
* will be active.
*
- * Returns 0 for SUCCESS or -1 if FAILED.
- */
+ * Returns 0 for SUCCESS, or FAILED.
+ **/
int
-mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout)
+mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout)
{
MPT_ADAPTER *ioc;
int rc = -1;
- int doTask = 1;
u32 ioc_raw_state;
unsigned long flags;
- /* If FW is being reloaded currently, return success to
- * the calling function.
- */
- if (hd == NULL)
- return 0;
-
ioc = hd->ioc;
- if (ioc == NULL) {
- printk(KERN_ERR MYNAM " TMHandler" " NULL ioc!\n");
- return FAILED;
- }
dtmprintk((MYIOC_s_INFO_FMT "TMHandler Entered!\n", ioc->name));
// SJR - CHECKME - Can we avoid this here?
@@ -1541,8 +1574,10 @@ mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, in
spin_unlock_irqrestore(&ioc->diagLock, flags);
/* Wait a fixed amount of time for the TM pending flag to be cleared.
- * If we time out and not bus reset, then we return a FAILED status to the caller.
- * The call to mptscsih_tm_pending_wait() will set the pending flag if we are
+ * If we time out and not bus reset, then we return a FAILED status
+ * to the caller.
+ * The call to mptscsih_tm_pending_wait() will set the pending flag
+ * if we are
* successful. Otherwise, reload the FW.
*/
if (mptscsih_tm_pending_wait(hd) == FAILED) {
@@ -1552,18 +1587,16 @@ mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, in
hd->ioc->name, hd->tmPending));
return FAILED;
} else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {
- dtmprintk((KERN_INFO MYNAM ": %s: TMHandler target reset: "
- "Timed out waiting for last TM (%d) to complete! \n",
- hd->ioc->name, hd->tmPending));
+ dtmprintk((KERN_INFO MYNAM ": %s: TMHandler target "
+ "reset: Timed out waiting for last TM (%d) "
+ "to complete! \n", hd->ioc->name,
+ hd->tmPending));
return FAILED;
} else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
dtmprintk((KERN_INFO MYNAM ": %s: TMHandler bus reset: "
"Timed out waiting for last TM (%d) to complete! \n",
hd->ioc->name, hd->tmPending));
- if (hd->tmPending & (1 << MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS))
- return FAILED;
-
- doTask = 0;
+ return FAILED;
}
} else {
spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
@@ -1571,47 +1604,40 @@ mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, in
spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
}
- /* Is operational?
- */
ioc_raw_state = mpt_GetIocState(hd->ioc, 0);
-#ifdef MPT_DEBUG_RESET
if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
printk(MYIOC_s_WARN_FMT
- "TM Handler: IOC Not operational(0x%x)!\n",
- hd->ioc->name, ioc_raw_state);
- }
-#endif
-
- if (doTask && ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL)
- && !(ioc_raw_state & MPI_DOORBELL_ACTIVE)) {
-
- /* Isse the Task Mgmt request.
- */
- if (hd->hard_resets < -1)
- hd->hard_resets++;
- rc = mptscsih_IssueTaskMgmt(hd, type, channel, target, lun, ctx2abort, timeout);
- if (rc) {
- printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n", hd->ioc->name);
- } else {
- dtmprintk((MYIOC_s_INFO_FMT "Issue of TaskMgmt Successful!\n", hd->ioc->name));
- }
+ "TM Handler for type=%x: IOC Not operational (0x%x)!\n",
+ ioc->name, type, ioc_raw_state);
+ printk(KERN_WARNING " Issuing HardReset!!\n");
+ if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0)
+ printk((KERN_WARNING "TMHandler: HardReset "
+ "FAILED!!\n"));
+ return FAILED;
}
- /* Only fall through to the HRH if this is a bus reset
- */
- if ((type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) && (rc ||
- ioc->reload_fw || (ioc->alt_ioc && ioc->alt_ioc->reload_fw))) {
- dtmprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n",
- hd->ioc->name));
- rc = mpt_HardResetHandler(hd->ioc, CAN_SLEEP);
+ if (ioc_raw_state & MPI_DOORBELL_ACTIVE) {
+ printk(MYIOC_s_WARN_FMT
+ "TM Handler for type=%x: ioc_state: "
+ "DOORBELL_ACTIVE (0x%x)!\n",
+ ioc->name, type, ioc_raw_state);
+ return FAILED;
}
- /*
- * Check IOCStatus from TM reply message
+ /* Isse the Task Mgmt request.
*/
- if (hd->tm_iocstatus != MPI_IOCSTATUS_SUCCESS)
- rc = FAILED;
+ if (hd->hard_resets < -1)
+ hd->hard_resets++;
+
+ rc = mptscsih_IssueTaskMgmt(hd, type, channel, id, lun,
+ ctx2abort, timeout);
+ if (rc)
+ printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n",
+ hd->ioc->name);
+ else
+ dtmprintk((MYIOC_s_INFO_FMT "Issue of TaskMgmt Successful!\n",
+ hd->ioc->name));
dtmprintk((MYIOC_s_INFO_FMT "TMHandler rc = %d!\n", hd->ioc->name, rc));
@@ -1620,11 +1646,11 @@ mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, in
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
+/**
* mptscsih_IssueTaskMgmt - Generic send Task Management function.
* @hd: Pointer to MPT_SCSI_HOST structure
* @type: Task Management type
- * @target: Logical Target ID for reset (if appropriate)
+ * @id: Logical Target ID for reset (if appropriate)
* @lun: Logical Unit for reset (if appropriate)
* @ctx2abort: Context for the task to be aborted (if appropriate)
*
@@ -1633,11 +1659,11 @@ mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, in
*
* Not all fields are meaningfull for all task types.
*
- * Returns 0 for SUCCESS, -999 for "no msg frames",
- * else other non-zero value returned.
- */
+ * Returns 0 for SUCCESS, or FAILED.
+ *
+ **/
static int
-mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout)
+mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout)
{
MPT_FRAME_HDR *mf;
SCSITaskMgmt_t *pScsiTm;
@@ -1657,7 +1683,7 @@ mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun
/* Format the Request
*/
pScsiTm = (SCSITaskMgmt_t *) mf;
- pScsiTm->TargetID = target;
+ pScsiTm->TargetID = id;
pScsiTm->Bus = channel;
pScsiTm->ChainOffset = 0;
pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
@@ -1668,42 +1694,59 @@ mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun
pScsiTm->MsgFlags = (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)
? MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION : 0;
- for (ii= 0; ii < 8; ii++) {
- pScsiTm->LUN[ii] = 0;
- }
- pScsiTm->LUN[1] = lun;
+ int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN);
for (ii=0; ii < 7; ii++)
pScsiTm->Reserved2[ii] = 0;
pScsiTm->TaskMsgContext = ctx2abort;
- dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt: ctx2abort (0x%08x) type=%d\n",
- hd->ioc->name, ctx2abort, type));
+ dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt: ctx2abort (0x%08x) "
+ "type=%d\n", hd->ioc->name, ctx2abort, type));
DBG_DUMP_TM_REQUEST_FRAME((u32 *)pScsiTm);
if ((retval = mpt_send_handshake_request(hd->ioc->TaskCtx, hd->ioc,
- sizeof(SCSITaskMgmt_t), (u32*)pScsiTm,
- CAN_SLEEP)) != 0) {
- dfailprintk((MYIOC_s_ERR_FMT "_send_handshake FAILED!"
- " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
- hd->ioc, mf));
- mpt_free_msg_frame(hd->ioc, mf);
- return retval;
+ sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP)) != 0) {
+ dfailprintk((MYIOC_s_ERR_FMT "send_handshake FAILED!"
+ " (hd %p, ioc %p, mf %p, rc=%d) \n", hd->ioc->name, hd,
+ hd->ioc, mf, retval));
+ goto fail_out;
}
if(mptscsih_tm_wait_for_completion(hd, timeout) == FAILED) {
- dfailprintk((MYIOC_s_ERR_FMT "_wait_for_completion FAILED!"
+ dfailprintk((MYIOC_s_ERR_FMT "task management request TIMED OUT!"
" (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
hd->ioc, mf));
- mpt_free_msg_frame(hd->ioc, mf);
dtmprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n",
hd->ioc->name));
retval = mpt_HardResetHandler(hd->ioc, CAN_SLEEP);
+ dtmprintk((MYIOC_s_INFO_FMT "rc=%d \n",
+ hd->ioc->name, retval));
+ goto fail_out;
}
+ /*
+ * Handle success case, see if theres a non-zero ioc_status.
+ */
+ if (hd->tm_iocstatus == MPI_IOCSTATUS_SUCCESS ||
+ hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_TASK_TERMINATED ||
+ hd->tm_iocstatus == MPI_IOCSTATUS_SCSI_IOC_TERMINATED)
+ retval = 0;
+ else
+ retval = FAILED;
+
return retval;
+
+ fail_out:
+
+ /*
+ * Free task managment mf, and corresponding tm flags
+ */
+ mpt_free_msg_frame(hd->ioc, mf);
+ hd->tmPending = 0;
+ hd->tmState = TM_STATE_NONE;
+ return FAILED;
}
static int
@@ -1728,7 +1771,7 @@ mptscsih_get_tm_timeout(MPT_ADAPTER *ioc)
* (linux scsi_host_template.eh_abort_handler routine)
*
* Returns SUCCESS or FAILED.
- */
+ **/
int
mptscsih_abort(struct scsi_cmnd * SCpnt)
{
@@ -1764,9 +1807,8 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
return SUCCESS;
}
- if (hd->resetPending) {
+ if (hd->resetPending)
return FAILED;
- }
if (hd->timeouts < -1)
hd->timeouts++;
@@ -1789,13 +1831,12 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
vdev = SCpnt->device->hostdata;
retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
- vdev->vtarget->bus_id, vdev->vtarget->target_id, vdev->lun,
+ vdev->vtarget->channel, vdev->vtarget->id, vdev->lun,
ctx2abort, mptscsih_get_tm_timeout(hd->ioc));
if (SCPNT_TO_LOOKUP_IDX(SCpnt) == scpnt_idx &&
- SCpnt->serial_number == sn) {
+ SCpnt->serial_number == sn)
retval = FAILED;
- }
printk (KERN_WARNING MYNAM ": %s: task abort: %s (sc=%p)\n",
hd->ioc->name,
@@ -1803,12 +1844,8 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
if (retval == 0)
return SUCCESS;
-
- if(retval != FAILED ) {
- hd->tmPending = 0;
- hd->tmState = TM_STATE_NONE;
- }
- return FAILED;
+ else
+ return FAILED;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -1819,7 +1856,7 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
* (linux scsi_host_template.eh_dev_reset_handler routine)
*
* Returns SUCCESS or FAILED.
- */
+ **/
int
mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
{
@@ -1845,7 +1882,7 @@ mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
vdev = SCpnt->device->hostdata;
retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
- vdev->vtarget->bus_id, vdev->vtarget->target_id,
+ vdev->vtarget->channel, vdev->vtarget->id,
0, 0, mptscsih_get_tm_timeout(hd->ioc));
printk (KERN_WARNING MYNAM ": %s: target reset: %s (sc=%p)\n",
@@ -1854,14 +1891,11 @@ mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
if (retval == 0)
return SUCCESS;
-
- if(retval != FAILED ) {
- hd->tmPending = 0;
- hd->tmState = TM_STATE_NONE;
- }
- return FAILED;
+ else
+ return FAILED;
}
+
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* mptscsih_bus_reset - Perform a SCSI BUS_RESET! new_eh variant
@@ -1870,7 +1904,7 @@ mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
* (linux scsi_host_template.eh_bus_reset_handler routine)
*
* Returns SUCCESS or FAILED.
- */
+ **/
int
mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
{
@@ -1896,7 +1930,7 @@ mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
vdev = SCpnt->device->hostdata;
retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
- vdev->vtarget->bus_id, 0, 0, 0, mptscsih_get_tm_timeout(hd->ioc));
+ vdev->vtarget->channel, 0, 0, 0, mptscsih_get_tm_timeout(hd->ioc));
printk (KERN_WARNING MYNAM ": %s: bus reset: %s (sc=%p)\n",
hd->ioc->name,
@@ -1904,12 +1938,8 @@ mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
if (retval == 0)
return SUCCESS;
-
- if(retval != FAILED ) {
- hd->tmPending = 0;
- hd->tmState = TM_STATE_NONE;
- }
- return FAILED;
+ else
+ return FAILED;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -1992,7 +2022,6 @@ mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd)
/**
* mptscsih_tm_wait_for_completion - wait for completion of TM task
* @hd: Pointer to MPT host structure.
- * @timeout: timeout in seconds
*
* Returns {SUCCESS,FAILED}.
*/
@@ -2066,7 +2095,7 @@ mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code)
* load/init time via the mpt_register() API call.
*
* Returns 1 indicating alloc'd request frame ptr should be freed.
- */
+ **/
int
mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
{
@@ -2076,78 +2105,85 @@ mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *m
unsigned long flags;
u16 iocstatus;
u8 tmType;
+ u32 termination_count;
dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt completed (mf=%p,mr=%p)\n",
- ioc->name, mf, mr));
- if (ioc->sh) {
- /* Depending on the thread, a timer is activated for
- * the TM request. Delete this timer on completion of TM.
- * Decrement count of outstanding TM requests.
- */
- hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
- } else {
- dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt Complete: NULL Scsi Host Ptr\n",
- ioc->name));
+ ioc->name, mf, mr));
+ if (!ioc->sh) {
+ dtmprintk((MYIOC_s_WARN_FMT
+ "TaskMgmt Complete: NULL Scsi Host Ptr\n", ioc->name));
return 1;
}
if (mr == NULL) {
- dtmprintk((MYIOC_s_WARN_FMT "ERROR! TaskMgmt Reply: NULL Request %p\n",
- ioc->name, mf));
+ dtmprintk((MYIOC_s_WARN_FMT
+ "ERROR! TaskMgmt Reply: NULL Request %p\n", ioc->name, mf));
return 1;
- } else {
- pScsiTmReply = (SCSITaskMgmtReply_t*)mr;
- pScsiTmReq = (SCSITaskMgmt_t*)mf;
-
- /* Figure out if this was ABORT_TASK, TARGET_RESET, or BUS_RESET! */
- tmType = pScsiTmReq->TaskType;
+ }
- if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 &&
- pScsiTmReply->ResponseCode)
- mptscsih_taskmgmt_response_code(ioc,
- pScsiTmReply->ResponseCode);
+ hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
+ pScsiTmReply = (SCSITaskMgmtReply_t*)mr;
+ pScsiTmReq = (SCSITaskMgmt_t*)mf;
+ tmType = pScsiTmReq->TaskType;
+ iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
+ termination_count = le32_to_cpu(pScsiTmReply->TerminationCount);
+
+ if (ioc->facts.MsgVersion >= MPI_VERSION_01_05 &&
+ pScsiTmReply->ResponseCode)
+ mptscsih_taskmgmt_response_code(ioc,
+ pScsiTmReply->ResponseCode);
+ DBG_DUMP_TM_REPLY_FRAME((u32 *)pScsiTmReply);
+
+#if defined(MPT_DEBUG_REPLY) || defined(MPT_DEBUG_TM)
+ printk("%s: ha=%d [%d:%d:0] task_type=0x%02X "
+ "iocstatus=0x%04X\n\tloginfo=0x%08X response_code=0x%02X "
+ "term_cmnds=%d\n", __FUNCTION__, ioc->id, pScsiTmReply->Bus,
+ pScsiTmReply->TargetID, pScsiTmReq->TaskType,
+ le16_to_cpu(pScsiTmReply->IOCStatus),
+ le32_to_cpu(pScsiTmReply->IOCLogInfo),pScsiTmReply->ResponseCode,
+ le32_to_cpu(pScsiTmReply->TerminationCount));
+#endif
+ if (!iocstatus) {
+ dtmprintk((MYIOC_s_WARN_FMT " TaskMgmt SUCCESS\n", ioc->name));
+ hd->abortSCpnt = NULL;
+ goto out;
+ }
- dtmprintk((MYIOC_s_WARN_FMT " TaskType = %d, TerminationCount=%d\n",
- ioc->name, tmType, le32_to_cpu(pScsiTmReply->TerminationCount)));
- DBG_DUMP_TM_REPLY_FRAME((u32 *)pScsiTmReply);
+ /* Error? (anything non-zero?) */
- iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
- hd->tm_iocstatus = iocstatus;
- dtmprintk((MYIOC_s_WARN_FMT " SCSI TaskMgmt (%d) IOCStatus=%04x IOCLogInfo=%08x\n",
- ioc->name, tmType, iocstatus, le32_to_cpu(pScsiTmReply->IOCLogInfo)));
- /* Error? (anything non-zero?) */
- if (iocstatus) {
+ /* clear flags and continue.
+ */
+ switch (tmType) {
- /* clear flags and continue.
- */
- if (tmType == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK)
- hd->abortSCpnt = NULL;
+ case MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK:
+ if (termination_count == 1)
+ iocstatus = MPI_IOCSTATUS_SCSI_TASK_TERMINATED;
+ hd->abortSCpnt = NULL;
+ break;
- /* If an internal command is present
- * or the TM failed - reload the FW.
- * FC FW may respond FAILED to an ABORT
- */
- if (tmType == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
- if ((hd->cmdPtr) ||
- (iocstatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED)) {
- if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) {
- printk((KERN_WARNING
- " Firmware Reload FAILED!!\n"));
- }
- }
- }
- } else {
- dtmprintk((MYIOC_s_WARN_FMT " TaskMgmt SUCCESS\n", ioc->name));
+ case MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS:
- hd->abortSCpnt = NULL;
+ /* If an internal command is present
+ * or the TM failed - reload the FW.
+ * FC FW may respond FAILED to an ABORT
+ */
+ if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED ||
+ hd->cmdPtr)
+ if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
+ printk((KERN_WARNING " Firmware Reload FAILED!!\n"));
+ break;
- }
+ case MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET:
+ default:
+ break;
}
+ out:
spin_lock_irqsave(&ioc->FreeQlock, flags);
hd->tmPending = 0;
- spin_unlock_irqrestore(&ioc->FreeQlock, flags);
hd->tmState = TM_STATE_NONE;
+ hd->tm_iocstatus = iocstatus;
+ spin_unlock_irqrestore(&ioc->FreeQlock, flags);
return 1;
}
@@ -2191,7 +2227,7 @@ mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev,
dprintk((KERN_NOTICE
": bios_param: Id=%i Lun=%i Channel=%i CHS=%i/%i/%i\n",
- sdev->id, sdev->lun,sdev->channel,(int)cylinders,heads,sectors));
+ sdev->id, sdev->lun, sdev->channel, (int)cylinders, heads, sectors));
return 0;
}
@@ -2200,115 +2236,78 @@ mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev,
*
*/
int
-mptscsih_is_phys_disk(MPT_ADAPTER *ioc, int id)
+mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id)
{
+ struct inactive_raid_component_info *component_info;
int i;
+ int rc = 0;
- if (!ioc->raid_data.isRaid || !ioc->raid_data.pIocPg3)
- return 0;
+ if (!ioc->raid_data.pIocPg3)
+ goto out;
for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
- if (id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID)
- return 1;
- }
- return 0;
-}
-EXPORT_SYMBOL(mptscsih_is_phys_disk);
-
-int
-mptscsih_raid_id_to_num(MPT_SCSI_HOST *hd, uint physdiskid)
-{
- int i;
-
- if (!hd->ioc->raid_data.isRaid || !hd->ioc->raid_data.pIocPg3)
- return -ENXIO;
-
- for (i = 0; i < hd->ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
- if (physdiskid ==
- hd->ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID)
- return hd->ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum;
+ if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
+ (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
+ rc = 1;
+ goto out;
+ }
}
- return -ENXIO;
-}
-EXPORT_SYMBOL(mptscsih_raid_id_to_num);
+ /*
+ * Check inactive list for matching phys disks
+ */
+ if (list_empty(&ioc->raid_data.inactive_list))
+ goto out;
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
- * OS entry point to allow host driver to alloc memory
- * for each scsi target. Called once per device the bus scan.
- * Return non-zero if allocation fails.
- */
-int
-mptscsih_target_alloc(struct scsi_target *starget)
-{
- VirtTarget *vtarget;
+ down(&ioc->raid_data.inactive_list_mutex);
+ list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
+ list) {
+ if ((component_info->d.PhysDiskID == id) &&
+ (component_info->d.PhysDiskBus == channel))
+ rc = 1;
+ }
+ up(&ioc->raid_data.inactive_list_mutex);
- vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
- if (!vtarget)
- return -ENOMEM;
- starget->hostdata = vtarget;
- vtarget->starget = starget;
- return 0;
+ out:
+ return rc;
}
+EXPORT_SYMBOL(mptscsih_is_phys_disk);
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
- * OS entry point to allow host driver to alloc memory
- * for each scsi device. Called once per device the bus scan.
- * Return non-zero if allocation fails.
- */
-int
-mptscsih_slave_alloc(struct scsi_device *sdev)
+u8
+mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
{
- struct Scsi_Host *host = sdev->host;
- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
- VirtTarget *vtarget;
- VirtDevice *vdev;
- struct scsi_target *starget;
+ struct inactive_raid_component_info *component_info;
+ int i;
+ int rc = -ENXIO;
- vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
- if (!vdev) {
- printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
- hd->ioc->name, sizeof(VirtDevice));
- return -ENOMEM;
+ if (!ioc->raid_data.pIocPg3)
+ goto out;
+ for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
+ if ((id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) &&
+ (channel == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskBus)) {
+ rc = ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum;
+ goto out;
+ }
}
- vdev->lun = sdev->lun;
- sdev->hostdata = vdev;
-
- starget = scsi_target(sdev);
- vtarget = starget->hostdata;
+ /*
+ * Check inactive list for matching phys disks
+ */
+ if (list_empty(&ioc->raid_data.inactive_list))
+ goto out;
- vdev->vtarget = vtarget;
-
- if (vtarget->num_luns == 0) {
- hd->Targets[sdev->id] = vtarget;
- vtarget->ioc_id = hd->ioc->id;
- vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
- vtarget->target_id = sdev->id;
- vtarget->bus_id = sdev->channel;
- if (hd->ioc->bus_type == SPI && sdev->channel == 0 &&
- hd->ioc->raid_data.isRaid & (1 << sdev->id)) {
- vtarget->raidVolume = 1;
- ddvtprintk((KERN_INFO
- "RAID Volume @ id %d\n", sdev->id));
- }
+ down(&ioc->raid_data.inactive_list_mutex);
+ list_for_each_entry(component_info, &ioc->raid_data.inactive_list,
+ list) {
+ if ((component_info->d.PhysDiskID == id) &&
+ (component_info->d.PhysDiskBus == channel))
+ rc = component_info->d.PhysDiskNum;
}
- vtarget->num_luns++;
- return 0;
-}
+ up(&ioc->raid_data.inactive_list_mutex);
-/*
- * OS entry point to allow for host driver to free allocated memory
- * Called if no device present or device being unloaded
- */
-void
-mptscsih_target_destroy(struct scsi_target *starget)
-{
- if (starget->hostdata)
- kfree(starget->hostdata);
- starget->hostdata = NULL;
+ out:
+ return rc;
}
+EXPORT_SYMBOL(mptscsih_raid_id_to_num);
/*
* OS entry point to allow for host driver to free allocated memory
@@ -2328,11 +2327,7 @@ mptscsih_slave_destroy(struct scsi_device *sdev)
vdevice = sdev->hostdata;
mptscsih_search_running_cmds(hd, vdevice);
- vtarget->luns[0] &= ~(1 << vdevice->lun);
vtarget->num_luns--;
- if (vtarget->num_luns == 0) {
- hd->Targets[sdev->id] = NULL;
- }
mptscsih_synchronize_cache(hd, vdevice);
kfree(vdevice);
sdev->hostdata = NULL;
@@ -2394,15 +2389,14 @@ mptscsih_slave_configure(struct scsi_device *sdev)
VirtDevice *vdevice;
struct scsi_target *starget;
MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sh->hostdata;
- int indexed_lun, lun_index;
starget = scsi_target(sdev);
vtarget = starget->hostdata;
vdevice = sdev->hostdata;
dsprintk((MYIOC_s_INFO_FMT
- "device @ %p, id=%d, LUN=%d, channel=%d\n",
- hd->ioc->name, sdev, sdev->id, sdev->lun, sdev->channel));
+ "device @ %p, channel=%d, id=%d, lun=%d\n",
+ hd->ioc->name, sdev, sdev->channel, sdev->id, sdev->lun));
if (hd->ioc->bus_type == SPI)
dsprintk((MYIOC_s_INFO_FMT
"sdtr %d wdtr %d ppr %d inq length=%d\n",
@@ -2415,11 +2409,7 @@ mptscsih_slave_configure(struct scsi_device *sdev)
goto slave_configure_exit;
}
- vdevice->configured_lun=1;
- lun_index = (vdevice->lun >> 5); /* 32 luns per lun_index */
- indexed_lun = (vdevice->lun % 32);
- vtarget->luns[lun_index] |= (1 << indexed_lun);
- mptscsih_initTarget(hd, vtarget, sdev);
+ vdevice->configured_lun = 1;
mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH);
dsprintk((MYIOC_s_INFO_FMT
@@ -2683,285 +2673,6 @@ mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
- * mptscsih_initTarget - Target, LUN alloc/free functionality.
- * @hd: Pointer to MPT_SCSI_HOST structure
- * @vtarget: per target private data
- * @sdev: SCSI device
- *
- * NOTE: It's only SAFE to call this routine if data points to
- * sane & valid STANDARD INQUIRY data!
- *
- * Allocate and initialize memory for this target.
- * Save inquiry data.
- *
- */
-static void
-mptscsih_initTarget(MPT_SCSI_HOST *hd, VirtTarget *vtarget,
- struct scsi_device *sdev)
-{
- dinitprintk((MYIOC_s_INFO_FMT "initTarget bus=%d id=%d lun=%d hd=%p\n",
- hd->ioc->name, vtarget->bus_id, vtarget->target_id,
- sdev->lun, hd));
-
- /* Is LUN supported? If so, upper 2 bits will be 0
- * in first byte of inquiry data.
- */
- if (sdev->inq_periph_qual != 0)
- return;
-
- if (vtarget == NULL)
- return;
-
- vtarget->type = sdev->type;
-
- if (hd->ioc->bus_type != SPI)
- return;
-
- if ((sdev->type == TYPE_PROCESSOR) && (hd->ioc->spi_data.Saf_Te)) {
- /* Treat all Processors as SAF-TE if
- * command line option is set */
- vtarget->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED;
- mptscsih_writeIOCPage4(hd, vtarget->target_id, vtarget->bus_id);
- }else if ((sdev->type == TYPE_PROCESSOR) &&
- !(vtarget->tflags & MPT_TARGET_FLAGS_SAF_TE_ISSUED )) {
- if (sdev->inquiry_len > 49 ) {
- if (sdev->inquiry[44] == 'S' &&
- sdev->inquiry[45] == 'A' &&
- sdev->inquiry[46] == 'F' &&
- sdev->inquiry[47] == '-' &&
- sdev->inquiry[48] == 'T' &&
- sdev->inquiry[49] == 'E' ) {
- vtarget->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED;
- mptscsih_writeIOCPage4(hd, vtarget->target_id, vtarget->bus_id);
- }
- }
- }
- mptscsih_setTargetNegoParms(hd, vtarget, sdev);
-}
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
- * Update the target negotiation parameters based on the
- * the Inquiry data, adapter capabilities, and NVRAM settings.
- *
- */
-static void
-mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target,
- struct scsi_device *sdev)
-{
- SpiCfgData *pspi_data = &hd->ioc->spi_data;
- int id = (int) target->target_id;
- int nvram;
- u8 width = MPT_NARROW;
- u8 factor = MPT_ASYNC;
- u8 offset = 0;
- u8 nfactor;
- u8 noQas = 1;
-
- target->negoFlags = pspi_data->noQas;
-
- /* noQas == 0 => device supports QAS. */
-
- if (sdev->scsi_level < SCSI_2) {
- width = 0;
- factor = MPT_ULTRA2;
- offset = pspi_data->maxSyncOffset;
- target->tflags &= ~MPT_TARGET_FLAGS_Q_YES;
- } else {
- if (scsi_device_wide(sdev)) {
- width = 1;
- }
-
- if (scsi_device_sync(sdev)) {
- factor = pspi_data->minSyncFactor;
- if (!scsi_device_dt(sdev))
- factor = MPT_ULTRA2;
- else {
- if (!scsi_device_ius(sdev) &&
- !scsi_device_qas(sdev))
- factor = MPT_ULTRA160;
- else {
- factor = MPT_ULTRA320;
- if (scsi_device_qas(sdev)) {
- ddvtprintk((KERN_INFO "Enabling QAS due to byte56=%02x on id=%d!\n", scsi_device_qas(sdev), id));
- noQas = 0;
- }
- if (sdev->type == TYPE_TAPE &&
- scsi_device_ius(sdev))
- target->negoFlags |= MPT_TAPE_NEGO_IDP;
- }
- }
- offset = pspi_data->maxSyncOffset;
-
- /* If RAID, never disable QAS
- * else if non RAID, do not disable
- * QAS if bit 1 is set
- * bit 1 QAS support, non-raid only
- * bit 0 IU support
- */
- if (target->raidVolume == 1) {
- noQas = 0;
- }
- } else {
- factor = MPT_ASYNC;
- offset = 0;
- }
- }
-
- if (!sdev->tagged_supported) {
- target->tflags &= ~MPT_TARGET_FLAGS_Q_YES;
- }
-
- /* Update tflags based on NVRAM settings. (SCSI only)
- */
- if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) {
- nvram = pspi_data->nvram[id];
- nfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8;
-
- if (width)
- width = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
-
- if (offset > 0) {
- /* Ensure factor is set to the
- * maximum of: adapter, nvram, inquiry
- */
- if (nfactor) {
- if (nfactor < pspi_data->minSyncFactor )
- nfactor = pspi_data->minSyncFactor;
-
- factor = max(factor, nfactor);
- if (factor == MPT_ASYNC)
- offset = 0;
- } else {
- offset = 0;
- factor = MPT_ASYNC;
- }
- } else {
- factor = MPT_ASYNC;
- }
- }
-
- /* Make sure data is consistent
- */
- if ((!width) && (factor < MPT_ULTRA2)) {
- factor = MPT_ULTRA2;
- }
-
- /* Save the data to the target structure.
- */
- target->minSyncFactor = factor;
- target->maxOffset = offset;
- target->maxWidth = width;
-
- target->tflags |= MPT_TARGET_FLAGS_VALID_NEGO;
-
- /* Disable unused features.
- */
- if (!width)
- target->negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
-
- if (!offset)
- target->negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
-
- if ( factor > MPT_ULTRA320 )
- noQas = 0;
-
- if (noQas && (pspi_data->noQas == 0)) {
- pspi_data->noQas |= MPT_TARGET_NO_NEGO_QAS;
- target->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
-
- /* Disable QAS in a mixed configuration case
- */
-
- ddvtprintk((KERN_INFO "Disabling QAS due to noQas=%02x on id=%d!\n", noQas, id));
- }
-}
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
- * SCSI Config Page functionality ...
- */
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/* mptscsih_writeIOCPage4 - write IOC Page 4
- * @hd: Pointer to a SCSI Host Structure
- * @target_id: write IOC Page4 for this ID & Bus
- *
- * Return: -EAGAIN if unable to obtain a Message Frame
- * or 0 if success.
- *
- * Remark: We do not wait for a return, write pages sequentially.
- */
-static int
-mptscsih_writeIOCPage4(MPT_SCSI_HOST *hd, int target_id, int bus)
-{
- MPT_ADAPTER *ioc = hd->ioc;
- Config_t *pReq;
- IOCPage4_t *IOCPage4Ptr;
- MPT_FRAME_HDR *mf;
- dma_addr_t dataDma;
- u16 req_idx;
- u32 frameOffset;
- u32 flagsLength;
- int ii;
-
- /* Get a MF for this command.
- */
- if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
- dfailprintk((MYIOC_s_WARN_FMT "writeIOCPage4 : no msg frames!\n",
- ioc->name));
- return -EAGAIN;
- }
-
- /* Set the request and the data pointers.
- * Place data at end of MF.
- */
- pReq = (Config_t *)mf;
-
- req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
- frameOffset = ioc->req_sz - sizeof(IOCPage4_t);
-
- /* Complete the request frame (same for all requests).
- */
- pReq->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
- pReq->Reserved = 0;
- pReq->ChainOffset = 0;
- pReq->Function = MPI_FUNCTION_CONFIG;
- pReq->ExtPageLength = 0;
- pReq->ExtPageType = 0;
- pReq->MsgFlags = 0;
- for (ii=0; ii < 8; ii++) {
- pReq->Reserved2[ii] = 0;
- }
-
- IOCPage4Ptr = ioc->spi_data.pIocPg4;
- dataDma = ioc->spi_data.IocPg4_dma;
- ii = IOCPage4Ptr->ActiveSEP++;
- IOCPage4Ptr->SEP[ii].SEPTargetID = target_id;
- IOCPage4Ptr->SEP[ii].SEPBus = bus;
- pReq->Header = IOCPage4Ptr->Header;
- pReq->PageAddress = cpu_to_le32(target_id | (bus << 8 ));
-
- /* Add a SGE to the config request.
- */
- flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE |
- (IOCPage4Ptr->Header.PageLength + ii) * 4;
-
- mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma);
-
- dinitprintk((MYIOC_s_INFO_FMT
- "writeIOCPage4: MaxSEP=%d ActiveSEP=%d id=%d bus=%d\n",
- ioc->name, IOCPage4Ptr->MaxSEP, IOCPage4Ptr->ActiveSEP, target_id, bus));
-
- mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
-
- return 0;
-}
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
* Bus Scan and Domain Validation functionality ...
*/
@@ -3343,7 +3054,7 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
} else {
pScsiReq->TargetID = io->id;
- pScsiReq->Bus = io->bus;
+ pScsiReq->Bus = io->channel;
pScsiReq->ChainOffset = 0;
pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
}
@@ -3356,9 +3067,7 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
pScsiReq->MsgFlags = mpt_msg_flags();
/* MsgContext set in mpt_get_msg_fram call */
- for (ii=0; ii < 8; ii++)
- pScsiReq->LUN[ii] = 0;
- pScsiReq->LUN[1] = io->lun;
+ int_to_scsilun(io->lun, (struct scsi_lun *)pScsiReq->LUN);
if (io->flags & MPT_ICFLAG_TAGGED_CMD)
pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_SIMPLEQ);
@@ -3379,7 +3088,7 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
+ (my_idx * MPT_SENSE_BUFFER_ALLOC));
ddvprintk((MYIOC_s_INFO_FMT "Sending Command 0x%x for (%d:%d:%d)\n",
- hd->ioc->name, cmd, io->bus, io->id, io->lun));
+ hd->ioc->name, cmd, io->channel, io->id, io->lun));
if (dir == MPI_SCSIIO_CONTROL_READ) {
mpt_add_sge((char *) &pScsiReq->SGL,
@@ -3462,9 +3171,9 @@ mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
iocmd.data_dma = -1;
iocmd.size = 0;
iocmd.rsvd = iocmd.rsvd2 = 0;
- iocmd.bus = vdevice->vtarget->bus_id;
- iocmd.id = vdevice->vtarget->target_id;
- iocmd.lun = (u8)vdevice->lun;
+ iocmd.channel = vdevice->vtarget->channel;
+ iocmd.id = vdevice->vtarget->id;
+ iocmd.lun = vdevice->lun;
if ((vdevice->vtarget->type == TYPE_DISK) &&
(vdevice->configured_lun))
@@ -3480,9 +3189,6 @@ EXPORT_SYMBOL(mptscsih_resume);
EXPORT_SYMBOL(mptscsih_proc_info);
EXPORT_SYMBOL(mptscsih_info);
EXPORT_SYMBOL(mptscsih_qcmd);
-EXPORT_SYMBOL(mptscsih_target_alloc);
-EXPORT_SYMBOL(mptscsih_slave_alloc);
-EXPORT_SYMBOL(mptscsih_target_destroy);
EXPORT_SYMBOL(mptscsih_slave_destroy);
EXPORT_SYMBOL(mptscsih_slave_configure);
EXPORT_SYMBOL(mptscsih_abort);
diff --git a/drivers/message/fusion/mptscsih.h b/drivers/message/fusion/mptscsih.h
index 187c8af0890..843c01a6aa0 100644
--- a/drivers/message/fusion/mptscsih.h
+++ b/drivers/message/fusion/mptscsih.h
@@ -6,7 +6,7 @@
* running LSI Logic Fusion MPT (Message Passing Technology) firmware.
*
* Copyright (c) 1999-2007 LSI Logic Corporation
- * (mailto:mpt_linux_developer@lsil.com)
+ * (mailto:mpt_linux_developer@lsi.com)
*
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -53,6 +53,24 @@
* SCSI Public stuff...
*/
+#define MPT_SCANDV_GOOD (0x00000000) /* must be 0 */
+#define MPT_SCANDV_DID_RESET (0x00000001)
+#define MPT_SCANDV_SENSE (0x00000002)
+#define MPT_SCANDV_SOME_ERROR (0x00000004)
+#define MPT_SCANDV_SELECTION_TIMEOUT (0x00000008)
+#define MPT_SCANDV_ISSUE_SENSE (0x00000010)
+#define MPT_SCANDV_FALLBACK (0x00000020)
+
+#define MPT_SCANDV_MAX_RETRIES (10)
+
+#define MPT_ICFLAG_BUF_CAP 0x01 /* ReadBuffer Read Capacity format */
+#define MPT_ICFLAG_ECHO 0x02 /* ReadBuffer Echo buffer format */
+#define MPT_ICFLAG_EBOS 0x04 /* ReadBuffer Echo buffer has EBOS */
+#define MPT_ICFLAG_PHYS_DISK 0x08 /* Any SCSI IO but do Phys Disk Format */
+#define MPT_ICFLAG_TAGGED_CMD 0x10 /* Do tagged IO */
+#define MPT_ICFLAG_DID_RESET 0x20 /* Bus Reset occurred with this command */
+#define MPT_ICFLAG_RESERVED 0x40 /* Reserved has been issued */
+
#define MPT_SCSI_CMD_PER_DEV_HIGH 64
#define MPT_SCSI_CMD_PER_DEV_LOW 32
@@ -69,9 +87,22 @@
#define MPTSCSIH_SAF_TE 0
#define MPTSCSIH_PT_CLEAR 0
-
#endif
+typedef struct _internal_cmd {
+ char *data; /* data pointer */
+ dma_addr_t data_dma; /* data dma address */
+ int size; /* transfer size */
+ u8 cmd; /* SCSI Op Code */
+ u8 channel; /* bus number */
+ u8 id; /* SCSI ID (virtual) */
+ int lun;
+ u8 flags; /* Bit Field - See above */
+ u8 physDiskNum; /* Phys disk number, -1 else */
+ u8 rsvd2;
+ u8 rsvd;
+} INTERNAL_CMD;
+
extern void mptscsih_remove(struct pci_dev *);
extern void mptscsih_shutdown(struct pci_dev *);
#ifdef CONFIG_PM
@@ -81,9 +112,6 @@ extern int mptscsih_resume(struct pci_dev *pdev);
extern int mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, int func);
extern const char * mptscsih_info(struct Scsi_Host *SChost);
extern int mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *));
-extern int mptscsih_target_alloc(struct scsi_target *starget);
-extern int mptscsih_slave_alloc(struct scsi_device *device);
-extern void mptscsih_target_destroy(struct scsi_target *starget);
extern void mptscsih_slave_destroy(struct scsi_device *device);
extern int mptscsih_slave_configure(struct scsi_device *device);
extern int mptscsih_abort(struct scsi_cmnd * SCpnt);
@@ -98,6 +126,6 @@ extern int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pE
extern int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset);
extern int mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth);
extern void mptscsih_timer_expired(unsigned long data);
-extern int mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout);
-extern int mptscsih_raid_id_to_num(MPT_SCSI_HOST *hd, uint physdiskid);
-extern int mptscsih_is_phys_disk(MPT_ADAPTER *ioc, int id);
+extern int mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout);
+extern u8 mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id);
+extern int mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id);
diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c
index 203c661d2c7..85f21b54cb7 100644
--- a/drivers/message/fusion/mptspi.c
+++ b/drivers/message/fusion/mptspi.c
@@ -4,7 +4,7 @@
* running LSI Logic Fusion MPT (Message Passing Technology) firmware.
*
* Copyright (c) 1999-2007 LSI Logic Corporation
- * (mailto:mpt_linux_developer@lsil.com)
+ * (mailto:mpt_linux_developer@lsi.com)
*
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -54,7 +54,6 @@
#include <linux/delay.h> /* for mdelay */
#include <linux/interrupt.h> /* needed for in_interrupt() proto */
#include <linux/reboot.h> /* notifier code */
-#include <linux/sched.h>
#include <linux/workqueue.h>
#include <linux/raid_class.h>
@@ -65,6 +64,7 @@
#include <scsi/scsi_tcq.h>
#include <scsi/scsi_transport.h>
#include <scsi/scsi_transport_spi.h>
+#include <scsi/scsi_dbg.h>
#include "mptbase.h"
#include "mptscsih.h"
@@ -95,25 +95,339 @@ static int mptspiDoneCtx = -1;
static int mptspiTaskCtx = -1;
static int mptspiInternalCtx = -1; /* Used only for internal commands */
+/**
+ * mptspi_setTargetNegoParms - Update the target negotiation
+ * parameters based on the the Inquiry data, adapter capabilities,
+ * and NVRAM settings
+ *
+ * @hd: Pointer to a SCSI Host Structure
+ * @vtarget: per target private data
+ * @sdev: SCSI device
+ *
+ **/
+static void
+mptspi_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target,
+ struct scsi_device *sdev)
+{
+ SpiCfgData *pspi_data = &hd->ioc->spi_data;
+ int id = (int) target->id;
+ int nvram;
+ u8 width = MPT_NARROW;
+ u8 factor = MPT_ASYNC;
+ u8 offset = 0;
+ u8 nfactor;
+ u8 noQas = 1;
+
+ target->negoFlags = pspi_data->noQas;
+
+ if (sdev->scsi_level < SCSI_2) {
+ width = 0;
+ factor = MPT_ULTRA2;
+ offset = pspi_data->maxSyncOffset;
+ target->tflags &= ~MPT_TARGET_FLAGS_Q_YES;
+ } else {
+ if (scsi_device_wide(sdev))
+ width = 1;
+
+ if (scsi_device_sync(sdev)) {
+ factor = pspi_data->minSyncFactor;
+ if (!scsi_device_dt(sdev))
+ factor = MPT_ULTRA2;
+ else {
+ if (!scsi_device_ius(sdev) &&
+ !scsi_device_qas(sdev))
+ factor = MPT_ULTRA160;
+ else {
+ factor = MPT_ULTRA320;
+ if (scsi_device_qas(sdev)) {
+ ddvprintk((KERN_INFO "Enabling QAS due to byte56=%02x on id=%d!\n", scsi_device_qas(sdev), id));
+ noQas = 0;
+ }
+ if (sdev->type == TYPE_TAPE &&
+ scsi_device_ius(sdev))
+ target->negoFlags |= MPT_TAPE_NEGO_IDP;
+ }
+ }
+ offset = pspi_data->maxSyncOffset;
+
+ /* If RAID, never disable QAS
+ * else if non RAID, do not disable
+ * QAS if bit 1 is set
+ * bit 1 QAS support, non-raid only
+ * bit 0 IU support
+ */
+ if (target->raidVolume == 1)
+ noQas = 0;
+ } else {
+ factor = MPT_ASYNC;
+ offset = 0;
+ }
+ }
+
+ if (!sdev->tagged_supported)
+ target->tflags &= ~MPT_TARGET_FLAGS_Q_YES;
+
+ /* Update tflags based on NVRAM settings. (SCSI only)
+ */
+ if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) {
+ nvram = pspi_data->nvram[id];
+ nfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8;
+
+ if (width)
+ width = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
+
+ if (offset > 0) {
+ /* Ensure factor is set to the
+ * maximum of: adapter, nvram, inquiry
+ */
+ if (nfactor) {
+ if (nfactor < pspi_data->minSyncFactor )
+ nfactor = pspi_data->minSyncFactor;
+
+ factor = max(factor, nfactor);
+ if (factor == MPT_ASYNC)
+ offset = 0;
+ } else {
+ offset = 0;
+ factor = MPT_ASYNC;
+ }
+ } else {
+ factor = MPT_ASYNC;
+ }
+ }
+
+ /* Make sure data is consistent
+ */
+ if ((!width) && (factor < MPT_ULTRA2))
+ factor = MPT_ULTRA2;
+
+ /* Save the data to the target structure.
+ */
+ target->minSyncFactor = factor;
+ target->maxOffset = offset;
+ target->maxWidth = width;
+
+ target->tflags |= MPT_TARGET_FLAGS_VALID_NEGO;
+
+ /* Disable unused features.
+ */
+ if (!width)
+ target->negoFlags |= MPT_TARGET_NO_NEGO_WIDE;
+
+ if (!offset)
+ target->negoFlags |= MPT_TARGET_NO_NEGO_SYNC;
+
+ if ( factor > MPT_ULTRA320 )
+ noQas = 0;
+
+ if (noQas && (pspi_data->noQas == 0)) {
+ pspi_data->noQas |= MPT_TARGET_NO_NEGO_QAS;
+ target->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
+
+ /* Disable QAS in a mixed configuration case
+ */
+
+ ddvprintk((KERN_INFO "Disabling QAS due to noQas=%02x on id=%d!\n", noQas, id));
+ }
+}
+
+/**
+ * mptspi_writeIOCPage4 - write IOC Page 4
+ * @hd: Pointer to a SCSI Host Structure
+ * @channel:
+ * @id: write IOC Page4 for this ID & Bus
+ *
+ * Return: -EAGAIN if unable to obtain a Message Frame
+ * or 0 if success.
+ *
+ * Remark: We do not wait for a return, write pages sequentially.
+ **/
+static int
+mptspi_writeIOCPage4(MPT_SCSI_HOST *hd, u8 channel , u8 id)
+{
+ MPT_ADAPTER *ioc = hd->ioc;
+ Config_t *pReq;
+ IOCPage4_t *IOCPage4Ptr;
+ MPT_FRAME_HDR *mf;
+ dma_addr_t dataDma;
+ u16 req_idx;
+ u32 frameOffset;
+ u32 flagsLength;
+ int ii;
+
+ /* Get a MF for this command.
+ */
+ if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
+ dfailprintk((MYIOC_s_WARN_FMT "writeIOCPage4 : no msg frames!\n",
+ ioc->name));
+ return -EAGAIN;
+ }
+
+ /* Set the request and the data pointers.
+ * Place data at end of MF.
+ */
+ pReq = (Config_t *)mf;
+
+ req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
+ frameOffset = ioc->req_sz - sizeof(IOCPage4_t);
+
+ /* Complete the request frame (same for all requests).
+ */
+ pReq->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
+ pReq->Reserved = 0;
+ pReq->ChainOffset = 0;
+ pReq->Function = MPI_FUNCTION_CONFIG;
+ pReq->ExtPageLength = 0;
+ pReq->ExtPageType = 0;
+ pReq->MsgFlags = 0;
+ for (ii=0; ii < 8; ii++) {
+ pReq->Reserved2[ii] = 0;
+ }
+
+ IOCPage4Ptr = ioc->spi_data.pIocPg4;
+ dataDma = ioc->spi_data.IocPg4_dma;
+ ii = IOCPage4Ptr->ActiveSEP++;
+ IOCPage4Ptr->SEP[ii].SEPTargetID = id;
+ IOCPage4Ptr->SEP[ii].SEPBus = channel;
+ pReq->Header = IOCPage4Ptr->Header;
+ pReq->PageAddress = cpu_to_le32(id | (channel << 8 ));
+
+ /* Add a SGE to the config request.
+ */
+ flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE |
+ (IOCPage4Ptr->Header.PageLength + ii) * 4;
+
+ mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma);
+
+ ddvprintk((MYIOC_s_INFO_FMT
+ "writeIOCPage4: MaxSEP=%d ActiveSEP=%d id=%d bus=%d\n",
+ ioc->name, IOCPage4Ptr->MaxSEP, IOCPage4Ptr->ActiveSEP, id, channel));
+
+ mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
+
+ return 0;
+}
+
+/**
+ * mptspi_initTarget - Target, LUN alloc/free functionality.
+ * @hd: Pointer to MPT_SCSI_HOST structure
+ * @vtarget: per target private data
+ * @sdev: SCSI device
+ *
+ * NOTE: It's only SAFE to call this routine if data points to
+ * sane & valid STANDARD INQUIRY data!
+ *
+ * Allocate and initialize memory for this target.
+ * Save inquiry data.
+ *
+ **/
+static void
+mptspi_initTarget(MPT_SCSI_HOST *hd, VirtTarget *vtarget,
+ struct scsi_device *sdev)
+{
+
+ /* Is LUN supported? If so, upper 2 bits will be 0
+ * in first byte of inquiry data.
+ */
+ if (sdev->inq_periph_qual != 0)
+ return;
+
+ if (vtarget == NULL)
+ return;
+
+ vtarget->type = sdev->type;
+
+ if ((sdev->type == TYPE_PROCESSOR) && (hd->ioc->spi_data.Saf_Te)) {
+ /* Treat all Processors as SAF-TE if
+ * command line option is set */
+ vtarget->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED;
+ mptspi_writeIOCPage4(hd, vtarget->channel, vtarget->id);
+ }else if ((sdev->type == TYPE_PROCESSOR) &&
+ !(vtarget->tflags & MPT_TARGET_FLAGS_SAF_TE_ISSUED )) {
+ if (sdev->inquiry_len > 49 ) {
+ if (sdev->inquiry[44] == 'S' &&
+ sdev->inquiry[45] == 'A' &&
+ sdev->inquiry[46] == 'F' &&
+ sdev->inquiry[47] == '-' &&
+ sdev->inquiry[48] == 'T' &&
+ sdev->inquiry[49] == 'E' ) {
+ vtarget->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED;
+ mptspi_writeIOCPage4(hd, vtarget->channel, vtarget->id);
+ }
+ }
+ }
+ mptspi_setTargetNegoParms(hd, vtarget, sdev);
+}
+
+/**
+ * mptspi_is_raid - Determines whether target is belonging to volume
+ * @hd: Pointer to a SCSI HOST structure
+ * @id: target device id
+ *
+ * Return:
+ * non-zero = true
+ * zero = false
+ *
+ */
+static int
+mptspi_is_raid(struct _MPT_SCSI_HOST *hd, u32 id)
+{
+ int i, rc = 0;
+
+ if (!hd->ioc->raid_data.pIocPg2)
+ goto out;
+
+ if (!hd->ioc->raid_data.pIocPg2->NumActiveVolumes)
+ goto out;
+ for (i=0; i < hd->ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
+ if (hd->ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == id) {
+ rc = 1;
+ goto out;
+ }
+ }
+
+ out:
+ return rc;
+}
+
static int mptspi_target_alloc(struct scsi_target *starget)
{
struct Scsi_Host *shost = dev_to_shost(&starget->dev);
struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)shost->hostdata;
- int ret;
+ VirtTarget *vtarget;
if (hd == NULL)
return -ENODEV;
- ret = mptscsih_target_alloc(starget);
- if (ret)
- return ret;
+ vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
+ if (!vtarget)
+ return -ENOMEM;
+
+ vtarget->ioc_id = hd->ioc->id;
+ vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
+ vtarget->id = (u8)starget->id;
+ vtarget->channel = (u8)starget->channel;
+ vtarget->starget = starget;
+ starget->hostdata = vtarget;
+
+ if (starget->channel == 1) {
+ if (mptscsih_is_phys_disk(hd->ioc, 0, starget->id) == 0)
+ return 0;
+ vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
+ /* The real channel for this device is zero */
+ vtarget->channel = 0;
+ /* The actual physdisknum (for RAID passthrough) */
+ vtarget->id = mptscsih_raid_id_to_num(hd->ioc, 0,
+ starget->id);
+ }
- /* if we're a device on virtual channel 1 and we're not part
- * of an array, just return here (otherwise the setup below
- * may actually affect a real physical device on channel 0 */
- if (starget->channel == 1 &&
- mptscsih_raid_id_to_num(hd, starget->id) < 0)
- return 0;
+ if (starget->channel == 0 &&
+ mptspi_is_raid(hd, starget->id)) {
+ vtarget->raidVolume = 1;
+ ddvprintk((KERN_INFO
+ "RAID Volume @ channel=%d id=%d\n", starget->channel,
+ starget->id));
+ }
if (hd->ioc->spi_data.nvram &&
hd->ioc->spi_data.nvram[starget->id] != MPT_HOST_NVRAM_INVALID) {
@@ -132,6 +446,64 @@ static int mptspi_target_alloc(struct scsi_target *starget)
return 0;
}
+void
+mptspi_target_destroy(struct scsi_target *starget)
+{
+ if (starget->hostdata)
+ kfree(starget->hostdata);
+ starget->hostdata = NULL;
+}
+
+/**
+ * mptspi_print_write_nego - negotiation parameters debug info that is being sent
+ * @hd: Pointer to a SCSI HOST structure
+ * @starget: SCSI target
+ * @ii: negotiation parameters
+ *
+ */
+static void
+mptspi_print_write_nego(struct _MPT_SCSI_HOST *hd, struct scsi_target *starget, u32 ii)
+{
+ ddvprintk((MYIOC_s_INFO_FMT "id=%d Requested = 0x%08x"
+ " ( %s factor = 0x%02x @ offset = 0x%02x %s%s%s%s%s%s%s%s)\n",
+ hd->ioc->name, starget->id, ii,
+ ii & MPI_SCSIDEVPAGE0_NP_WIDE ? "Wide ": "",
+ ((ii >> 8) & 0xFF), ((ii >> 16) & 0xFF),
+ ii & MPI_SCSIDEVPAGE0_NP_IU ? "IU ": "",
+ ii & MPI_SCSIDEVPAGE0_NP_DT ? "DT ": "",
+ ii & MPI_SCSIDEVPAGE0_NP_QAS ? "QAS ": "",
+ ii & MPI_SCSIDEVPAGE0_NP_HOLD_MCS ? "HOLDMCS ": "",
+ ii & MPI_SCSIDEVPAGE0_NP_WR_FLOW ? "WRFLOW ": "",
+ ii & MPI_SCSIDEVPAGE0_NP_RD_STRM ? "RDSTRM ": "",
+ ii & MPI_SCSIDEVPAGE0_NP_RTI ? "RTI ": "",
+ ii & MPI_SCSIDEVPAGE0_NP_PCOMP_EN ? "PCOMP ": ""));
+}
+
+/**
+ * mptspi_print_read_nego - negotiation parameters debug info that is being read
+ * @hd: Pointer to a SCSI HOST structure
+ * @starget: SCSI target
+ * @ii: negotiation parameters
+ *
+ */
+static void
+mptspi_print_read_nego(struct _MPT_SCSI_HOST *hd, struct scsi_target *starget, u32 ii)
+{
+ ddvprintk((MYIOC_s_INFO_FMT "id=%d Read = 0x%08x"
+ " ( %s factor = 0x%02x @ offset = 0x%02x %s%s%s%s%s%s%s%s)\n",
+ hd->ioc->name, starget->id, ii,
+ ii & MPI_SCSIDEVPAGE0_NP_WIDE ? "Wide ": "",
+ ((ii >> 8) & 0xFF), ((ii >> 16) & 0xFF),
+ ii & MPI_SCSIDEVPAGE0_NP_IU ? "IU ": "",
+ ii & MPI_SCSIDEVPAGE0_NP_DT ? "DT ": "",
+ ii & MPI_SCSIDEVPAGE0_NP_QAS ? "QAS ": "",
+ ii & MPI_SCSIDEVPAGE0_NP_HOLD_MCS ? "HOLDMCS ": "",
+ ii & MPI_SCSIDEVPAGE0_NP_WR_FLOW ? "WRFLOW ": "",
+ ii & MPI_SCSIDEVPAGE0_NP_RD_STRM ? "RDSTRM ": "",
+ ii & MPI_SCSIDEVPAGE0_NP_RTI ? "RTI ": "",
+ ii & MPI_SCSIDEVPAGE0_NP_PCOMP_EN ? "PCOMP ": ""));
+}
+
static int mptspi_read_spi_device_pg0(struct scsi_target *starget,
struct _CONFIG_PAGE_SCSI_DEVICE_0 *pass_pg0)
{
@@ -147,7 +519,7 @@ static int mptspi_read_spi_device_pg0(struct scsi_target *starget,
/* No SPI parameters for RAID devices */
if (starget->channel == 0 &&
- (hd->ioc->raid_data.isRaid & (1 << starget->id)))
+ mptspi_is_raid(hd, starget->id))
return -1;
size = ioc->spi_data.sdp0length * 4;
@@ -185,6 +557,8 @@ static int mptspi_read_spi_device_pg0(struct scsi_target *starget,
err = 0;
memcpy(pass_pg0, pg0, size);
+ mptspi_print_read_nego(hd, starget, le32_to_cpu(pg0->NegotiatedParameters));
+
out_free:
dma_free_coherent(&ioc->pcidev->dev, size, pg0, pg0_dma);
return err;
@@ -233,7 +607,7 @@ static void mptspi_read_parameters(struct scsi_target *starget)
}
static int
-mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, int disk)
+mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, u8 channel, u8 id)
{
MpiRaidActionRequest_t *pReq;
MPT_FRAME_HDR *mf;
@@ -253,8 +627,8 @@ mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, int disk)
pReq->Reserved1 = 0;
pReq->ChainOffset = 0;
pReq->Function = MPI_FUNCTION_RAID_ACTION;
- pReq->VolumeID = disk;
- pReq->VolumeBus = 0;
+ pReq->VolumeID = id;
+ pReq->VolumeBus = channel;
pReq->PhysDiskNum = 0;
pReq->MsgFlags = 0;
pReq->Reserved2 = 0;
@@ -263,8 +637,8 @@ mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, int disk)
mpt_add_sge((char *)&pReq->ActionDataSGE,
MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1);
- ddvprintk((MYIOC_s_INFO_FMT "RAID Volume action %x id %d\n",
- hd->ioc->name, action, io->id));
+ ddvprintk((MYIOC_s_INFO_FMT "RAID Volume action=%x channel=%d id=%d\n",
+ hd->ioc->name, pReq->Action, channel, id));
hd->pLocal = NULL;
hd->timer.expires = jiffies + HZ*10; /* 10 second timeout */
@@ -292,12 +666,12 @@ static void mptspi_dv_device(struct _MPT_SCSI_HOST *hd,
/* no DV on RAID devices */
if (sdev->channel == 0 &&
- (hd->ioc->raid_data.isRaid & (1 << sdev->id)))
+ mptspi_is_raid(hd, sdev->id))
return;
/* If this is a piece of a RAID, then quiesce first */
if (sdev->channel == 1 &&
- mptscsih_quiesce_raid(hd, 1, vtarget->target_id) < 0) {
+ mptscsih_quiesce_raid(hd, 1, vtarget->channel, vtarget->id) < 0) {
starget_printk(KERN_ERR, scsi_target(sdev),
"Integrated RAID quiesce failed\n");
return;
@@ -306,7 +680,7 @@ static void mptspi_dv_device(struct _MPT_SCSI_HOST *hd,
spi_dv_device(sdev);
if (sdev->channel == 1 &&
- mptscsih_quiesce_raid(hd, 0, vtarget->target_id) < 0)
+ mptscsih_quiesce_raid(hd, 0, vtarget->channel, vtarget->id) < 0)
starget_printk(KERN_ERR, scsi_target(sdev),
"Integrated RAID resume failed\n");
@@ -317,54 +691,89 @@ static void mptspi_dv_device(struct _MPT_SCSI_HOST *hd,
static int mptspi_slave_alloc(struct scsi_device *sdev)
{
- int ret;
MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sdev->host->hostdata;
- /* gcc doesn't see that all uses of this variable occur within
- * the if() statements, so stop it from whining */
- int physdisknum = 0;
-
- if (sdev->channel == 1) {
- physdisknum = mptscsih_raid_id_to_num(hd, sdev->id);
+ VirtTarget *vtarget;
+ VirtDevice *vdev;
+ struct scsi_target *starget;
- if (physdisknum < 0)
- return physdisknum;
+ if (sdev->channel == 1 &&
+ mptscsih_is_phys_disk(hd->ioc, 0, sdev->id) == 0)
+ return -ENXIO;
+
+ vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
+ if (!vdev) {
+ printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
+ hd->ioc->name, sizeof(VirtDevice));
+ return -ENOMEM;
}
- ret = mptscsih_slave_alloc(sdev);
+ vdev->lun = sdev->lun;
+ sdev->hostdata = vdev;
- if (ret)
- return ret;
+ starget = scsi_target(sdev);
+ vtarget = starget->hostdata;
+ vdev->vtarget = vtarget;
+ vtarget->num_luns++;
- if (sdev->channel == 1) {
- VirtDevice *vdev = sdev->hostdata;
+ if (sdev->channel == 1)
sdev->no_uld_attach = 1;
- vdev->vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
- /* The real channel for this device is zero */
- vdev->vtarget->bus_id = 0;
- /* The actual physdisknum (for RAID passthrough) */
- vdev->vtarget->target_id = physdisknum;
- }
return 0;
}
static int mptspi_slave_configure(struct scsi_device *sdev)
{
- int ret = mptscsih_slave_configure(sdev);
struct _MPT_SCSI_HOST *hd =
(struct _MPT_SCSI_HOST *)sdev->host->hostdata;
+ VirtTarget *vtarget = scsi_target(sdev)->hostdata;
+ int ret = mptscsih_slave_configure(sdev);
if (ret)
return ret;
+ mptspi_initTarget(hd, vtarget, sdev);
+
+ ddvprintk((MYIOC_s_INFO_FMT "id=%d min_period=0x%02x"
+ " max_offset=0x%02x max_width=%d\n", hd->ioc->name,
+ sdev->id, spi_min_period(scsi_target(sdev)),
+ spi_max_offset(scsi_target(sdev)),
+ spi_max_width(scsi_target(sdev))));
+
if ((sdev->channel == 1 ||
- !(hd->ioc->raid_data.isRaid & (1 << sdev->id))) &&
+ !(mptspi_is_raid(hd, sdev->id))) &&
!spi_initial_dv(sdev->sdev_target))
mptspi_dv_device(hd, sdev);
return 0;
}
+static int
+mptspi_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
+{
+ struct _MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata;
+ VirtDevice *vdev = SCpnt->device->hostdata;
+
+ if (!vdev || !vdev->vtarget) {
+ SCpnt->result = DID_NO_CONNECT << 16;
+ done(SCpnt);
+ return 0;
+ }
+
+ if (SCpnt->device->channel == 1 &&
+ mptscsih_is_phys_disk(hd->ioc, 0, SCpnt->device->id) == 0) {
+ SCpnt->result = DID_NO_CONNECT << 16;
+ done(SCpnt);
+ return 0;
+ }
+
+#ifdef MPT_DEBUG_DV
+ if (spi_dv_pending(scsi_target(SCpnt->device)))
+ scsi_print_command(SCpnt);
+#endif
+
+ return mptscsih_qcmd(SCpnt,done);
+}
+
static void mptspi_slave_destroy(struct scsi_device *sdev)
{
struct scsi_target *starget = scsi_target(sdev);
@@ -392,11 +801,11 @@ static struct scsi_host_template mptspi_driver_template = {
.proc_info = mptscsih_proc_info,
.name = "MPT SPI Host",
.info = mptscsih_info,
- .queuecommand = mptscsih_qcmd,
+ .queuecommand = mptspi_qcmd,
.target_alloc = mptspi_target_alloc,
.slave_alloc = mptspi_slave_alloc,
.slave_configure = mptspi_slave_configure,
- .target_destroy = mptscsih_target_destroy,
+ .target_destroy = mptspi_target_destroy,
.slave_destroy = mptspi_slave_destroy,
.change_queue_depth = mptscsih_change_queue_depth,
.eh_abort_handler = mptscsih_abort,
@@ -427,7 +836,7 @@ static int mptspi_write_spi_device_pg1(struct scsi_target *starget,
/* don't allow updating nego parameters on RAID devices */
if (starget->channel == 0 &&
- (hd->ioc->raid_data.isRaid & (1 << starget->id)))
+ mptspi_is_raid(hd, starget->id))
return -1;
size = ioc->spi_data.sdp1length * 4;
@@ -460,6 +869,8 @@ static int mptspi_write_spi_device_pg1(struct scsi_target *starget,
pg1->Header.PageNumber = hdr.PageNumber;
pg1->Header.PageType = hdr.PageType;
+ mptspi_print_write_nego(hd, starget, le32_to_cpu(pg1->RequestedParameters));
+
if (mpt_config(ioc, &cfg)) {
starget_printk(KERN_ERR, starget, "mpt_config failed\n");
goto out_free;
@@ -672,9 +1083,9 @@ static void mpt_work_wrapper(struct work_struct *work)
if (sdev->channel != 1)
continue;
- /* The target_id is the raid PhysDiskNum, even if
+ /* The id is the raid PhysDiskNum, even if
* starget->id is the actual target address */
- if(vtarget->target_id != disk)
+ if(vtarget->id != disk)
continue;
starget_printk(KERN_INFO, vtarget->starget,
@@ -727,7 +1138,7 @@ mptspi_deny_binding(struct scsi_target *starget)
{
struct _MPT_SCSI_HOST *hd =
(struct _MPT_SCSI_HOST *)dev_to_shost(starget->dev.parent)->hostdata;
- return ((hd->ioc->raid_data.isRaid & (1 << starget->id)) &&
+ return ((mptspi_is_raid(hd, starget->id)) &&
starget->channel == 0) ? 1 : 0;
}
@@ -945,14 +1356,13 @@ mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
* max_lun = 1 + actual last lun,
* see hosts.h :o(
*/
- sh->max_id = MPT_MAX_SCSI_DEVICES;
+ sh->max_id = ioc->devices_per_bus;
sh->max_lun = MPT_LAST_LUN + 1;
/*
* If RAID Firmware Detected, setup virtual channel
*/
- if ((ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK)
- > MPI_FW_HEADER_PID_PROD_TARGET_SCSI)
+ if (ioc->ir_firmware)
sh->max_channel = 1;
else
sh->max_channel = 0;
@@ -1009,20 +1419,6 @@ mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p\n",
ioc->name, hd->ScsiLookup));
- /* Allocate memory for the device structures.
- * A non-Null pointer at an offset
- * indicates a device exists.
- * max_id = 1 + maximum id (hosts.h)
- */
- hd->Targets = kcalloc(sh->max_id * (sh->max_channel + 1),
- sizeof(void *), GFP_ATOMIC);
- if (!hd->Targets) {
- error = -ENOMEM;
- goto out_mptspi_probe;
- }
-
- dprintk((KERN_INFO " vdev @ %p\n", hd->Targets));
-
/* Clear the TM flags
*/
hd->tmPending = 0;
diff --git a/drivers/message/i2o/i2o_config.c b/drivers/message/i2o/i2o_config.c
index e33d446e749..8ba275a1277 100644
--- a/drivers/message/i2o/i2o_config.c
+++ b/drivers/message/i2o/i2o_config.c
@@ -1111,7 +1111,7 @@ static int cfg_release(struct inode *inode, struct file *file)
return 0;
}
-static struct file_operations config_fops = {
+static const struct file_operations config_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.ioctl = i2o_cfg_ioctl,
diff --git a/drivers/message/i2o/i2o_proc.c b/drivers/message/i2o/i2o_proc.c
index a61cb17c5c1..06892ac2286 100644
--- a/drivers/message/i2o/i2o_proc.c
+++ b/drivers/message/i2o/i2o_proc.c
@@ -1703,133 +1703,133 @@ static int i2o_seq_open_dev_name(struct inode *inode, struct file *file)
return single_open(file, i2o_seq_show_dev_name, PDE(inode)->data);
};
-static struct file_operations i2o_seq_fops_lct = {
+static const struct file_operations i2o_seq_fops_lct = {
.open = i2o_seq_open_lct,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
-static struct file_operations i2o_seq_fops_hrt = {
+static const struct file_operations i2o_seq_fops_hrt = {
.open = i2o_seq_open_hrt,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
-static struct file_operations i2o_seq_fops_status = {
+static const struct file_operations i2o_seq_fops_status = {
.open = i2o_seq_open_status,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
-static struct file_operations i2o_seq_fops_hw = {
+static const struct file_operations i2o_seq_fops_hw = {
.open = i2o_seq_open_hw,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
-static struct file_operations i2o_seq_fops_ddm_table = {
+static const struct file_operations i2o_seq_fops_ddm_table = {
.open = i2o_seq_open_ddm_table,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
-static struct file_operations i2o_seq_fops_driver_store = {
+static const struct file_operations i2o_seq_fops_driver_store = {
.open = i2o_seq_open_driver_store,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
-static struct file_operations i2o_seq_fops_drivers_stored = {
+static const struct file_operations i2o_seq_fops_drivers_stored = {
.open = i2o_seq_open_drivers_stored,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
-static struct file_operations i2o_seq_fops_groups = {
+static const struct file_operations i2o_seq_fops_groups = {
.open = i2o_seq_open_groups,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
-static struct file_operations i2o_seq_fops_phys_device = {
+static const struct file_operations i2o_seq_fops_phys_device = {
.open = i2o_seq_open_phys_device,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
-static struct file_operations i2o_seq_fops_claimed = {
+static const struct file_operations i2o_seq_fops_claimed = {
.open = i2o_seq_open_claimed,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
-static struct file_operations i2o_seq_fops_users = {
+static const struct file_operations i2o_seq_fops_users = {
.open = i2o_seq_open_users,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
-static struct file_operations i2o_seq_fops_priv_msgs = {
+static const struct file_operations i2o_seq_fops_priv_msgs = {
.open = i2o_seq_open_priv_msgs,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
-static struct file_operations i2o_seq_fops_authorized_users = {
+static const struct file_operations i2o_seq_fops_authorized_users = {
.open = i2o_seq_open_authorized_users,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
-static struct file_operations i2o_seq_fops_dev_name = {
+static const struct file_operations i2o_seq_fops_dev_name = {
.open = i2o_seq_open_dev_name,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
-static struct file_operations i2o_seq_fops_dev_identity = {
+static const struct file_operations i2o_seq_fops_dev_identity = {
.open = i2o_seq_open_dev_identity,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
-static struct file_operations i2o_seq_fops_ddm_identity = {
+static const struct file_operations i2o_seq_fops_ddm_identity = {
.open = i2o_seq_open_ddm_identity,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
-static struct file_operations i2o_seq_fops_uinfo = {
+static const struct file_operations i2o_seq_fops_uinfo = {
.open = i2o_seq_open_uinfo,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
-static struct file_operations i2o_seq_fops_sgl_limits = {
+static const struct file_operations i2o_seq_fops_sgl_limits = {
.open = i2o_seq_open_sgl_limits,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
-static struct file_operations i2o_seq_fops_sensors = {
+static const struct file_operations i2o_seq_fops_sensors = {
.open = i2o_seq_open_sensors,
.read = seq_read,
.llseek = seq_lseek,
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index fc3c8854f43..ab6e985275b 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -2,6 +2,20 @@
# Multifunction miscellaneous devices
#
+menu "Multifunction device drivers"
+
+config MFD_SM501
+ tristate "Support for Silicon Motion SM501"
+ ---help---
+ This is the core driver for the Silicon Motion SM501 multimedia
+ companion chip. This device is a multifunction device which may
+ provide numerous interfaces including USB host controller USB gadget,
+ Asyncronous Serial ports, Audio functions and a dual display video
+ interface. The device may be connected by PCI or local bus with
+ varying functions enabled.
+
+endmenu
+
menu "Multimedia Capabilities Port drivers"
depends on ARCH_SA1100
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index adb29b5368a..51432091b32 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -2,6 +2,8 @@
# Makefile for multifunction miscellaneous devices
#
+obj-$(CONFIG_MFD_SM501) += sm501.o
+
obj-$(CONFIG_MCP) += mcp-core.o
obj-$(CONFIG_MCP_SA11X0) += mcp-sa11x0.o
obj-$(CONFIG_MCP_UCB1200) += ucb1x00-core.o
diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c
new file mode 100644
index 00000000000..c707c8ebc1a
--- /dev/null
+++ b/drivers/mfd/sm501.c
@@ -0,0 +1,1148 @@
+/* linux/drivers/mfd/sm501.c
+ *
+ * Copyright (C) 2006 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ * Vincent Sanders <vince@simtec.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * SM501 MFD driver
+*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/pci.h>
+
+#include <linux/sm501.h>
+#include <linux/sm501-regs.h>
+
+#include <asm/io.h>
+
+struct sm501_device {
+ struct list_head list;
+ struct platform_device pdev;
+};
+
+struct sm501_devdata {
+ spinlock_t reg_lock;
+ struct mutex clock_lock;
+ struct list_head devices;
+
+ struct device *dev;
+ struct resource *io_res;
+ struct resource *mem_res;
+ struct resource *regs_claim;
+ struct sm501_platdata *platdata;
+
+ int unit_power[20];
+ unsigned int pdev_id;
+ unsigned int irq;
+ void __iomem *regs;
+};
+
+#define MHZ (1000 * 1000)
+
+#ifdef DEBUG
+static const unsigned int misc_div[] = {
+ [0] = 1,
+ [1] = 2,
+ [2] = 4,
+ [3] = 8,
+ [4] = 16,
+ [5] = 32,
+ [6] = 64,
+ [7] = 128,
+ [8] = 3,
+ [9] = 6,
+ [10] = 12,
+ [11] = 24,
+ [12] = 48,
+ [13] = 96,
+ [14] = 192,
+ [15] = 384,
+};
+
+static const unsigned int px_div[] = {
+ [0] = 1,
+ [1] = 2,
+ [2] = 4,
+ [3] = 8,
+ [4] = 16,
+ [5] = 32,
+ [6] = 64,
+ [7] = 128,
+ [8] = 3,
+ [9] = 6,
+ [10] = 12,
+ [11] = 24,
+ [12] = 48,
+ [13] = 96,
+ [14] = 192,
+ [15] = 384,
+ [16] = 5,
+ [17] = 10,
+ [18] = 20,
+ [19] = 40,
+ [20] = 80,
+ [21] = 160,
+ [22] = 320,
+ [23] = 604,
+};
+
+static unsigned long decode_div(unsigned long pll2, unsigned long val,
+ unsigned int lshft, unsigned int selbit,
+ unsigned long mask, const unsigned int *dtab)
+{
+ if (val & selbit)
+ pll2 = 288 * MHZ;
+
+ return pll2 / dtab[(val >> lshft) & mask];
+}
+
+#define fmt_freq(x) ((x) / MHZ), ((x) % MHZ), (x)
+
+/* sm501_dump_clk
+ *
+ * Print out the current clock configuration for the device
+*/
+
+static void sm501_dump_clk(struct sm501_devdata *sm)
+{
+ unsigned long misct = readl(sm->regs + SM501_MISC_TIMING);
+ unsigned long pm0 = readl(sm->regs + SM501_POWER_MODE_0_CLOCK);
+ unsigned long pm1 = readl(sm->regs + SM501_POWER_MODE_1_CLOCK);
+ unsigned long pmc = readl(sm->regs + SM501_POWER_MODE_CONTROL);
+ unsigned long sdclk0, sdclk1;
+ unsigned long pll2 = 0;
+
+ switch (misct & 0x30) {
+ case 0x00:
+ pll2 = 336 * MHZ;
+ break;
+ case 0x10:
+ pll2 = 288 * MHZ;
+ break;
+ case 0x20:
+ pll2 = 240 * MHZ;
+ break;
+ case 0x30:
+ pll2 = 192 * MHZ;
+ break;
+ }
+
+ sdclk0 = (misct & (1<<12)) ? pll2 : 288 * MHZ;
+ sdclk0 /= misc_div[((misct >> 8) & 0xf)];
+
+ sdclk1 = (misct & (1<<20)) ? pll2 : 288 * MHZ;
+ sdclk1 /= misc_div[((misct >> 16) & 0xf)];
+
+ dev_dbg(sm->dev, "MISCT=%08lx, PM0=%08lx, PM1=%08lx\n",
+ misct, pm0, pm1);
+
+ dev_dbg(sm->dev, "PLL2 = %ld.%ld MHz (%ld), SDCLK0=%08lx, SDCLK1=%08lx\n",
+ fmt_freq(pll2), sdclk0, sdclk1);
+
+ dev_dbg(sm->dev, "SDRAM: PM0=%ld, PM1=%ld\n", sdclk0, sdclk1);
+
+ dev_dbg(sm->dev, "PM0[%c]: "
+ "P2 %ld.%ld MHz (%ld), V2 %ld.%ld (%ld), "
+x "M %ld.%ld (%ld), MX1 %ld.%ld (%ld)\n",
+ (pmc & 3 ) == 0 ? '*' : '-',
+ fmt_freq(decode_div(pll2, pm0, 24, 1<<29, 31, px_div)),
+ fmt_freq(decode_div(pll2, pm0, 16, 1<<20, 15, misc_div)),
+ fmt_freq(decode_div(pll2, pm0, 8, 1<<12, 15, misc_div)),
+ fmt_freq(decode_div(pll2, pm0, 0, 1<<4, 15, misc_div)));
+
+ dev_dbg(sm->dev, "PM1[%c]: "
+ "P2 %ld.%ld MHz (%ld), V2 %ld.%ld (%ld), "
+ "M %ld.%ld (%ld), MX1 %ld.%ld (%ld)\n",
+ (pmc & 3 ) == 1 ? '*' : '-',
+ fmt_freq(decode_div(pll2, pm1, 24, 1<<29, 31, px_div)),
+ fmt_freq(decode_div(pll2, pm1, 16, 1<<20, 15, misc_div)),
+ fmt_freq(decode_div(pll2, pm1, 8, 1<<12, 15, misc_div)),
+ fmt_freq(decode_div(pll2, pm1, 0, 1<<4, 15, misc_div)));
+}
+#else
+static void sm501_dump_clk(struct sm501_devdata *sm)
+{
+}
+#endif
+
+/* sm501_sync_regs
+ *
+ * ensure the
+*/
+
+static void sm501_sync_regs(struct sm501_devdata *sm)
+{
+ readl(sm->regs);
+}
+
+/* sm501_misc_control
+ *
+ * alters the misceleneous control parameters
+*/
+
+int sm501_misc_control(struct device *dev,
+ unsigned long set, unsigned long clear)
+{
+ struct sm501_devdata *sm = dev_get_drvdata(dev);
+ unsigned long misc;
+ unsigned long save;
+ unsigned long to;
+
+ spin_lock_irqsave(&sm->reg_lock, save);
+
+ misc = readl(sm->regs + SM501_MISC_CONTROL);
+ to = (misc & ~clear) | set;
+
+ if (to != misc) {
+ writel(to, sm->regs + SM501_MISC_CONTROL);
+ sm501_sync_regs(sm);
+
+ dev_dbg(sm->dev, "MISC_CONTROL %08lx\n", misc);
+ }
+
+ spin_unlock_irqrestore(&sm->reg_lock, save);
+ return to;
+}
+
+EXPORT_SYMBOL_GPL(sm501_misc_control);
+
+/* sm501_modify_reg
+ *
+ * Modify a register in the SM501 which may be shared with other
+ * drivers.
+*/
+
+unsigned long sm501_modify_reg(struct device *dev,
+ unsigned long reg,
+ unsigned long set,
+ unsigned long clear)
+{
+ struct sm501_devdata *sm = dev_get_drvdata(dev);
+ unsigned long data;
+ unsigned long save;
+
+ spin_lock_irqsave(&sm->reg_lock, save);
+
+ data = readl(sm->regs + reg);
+ data |= set;
+ data &= ~clear;
+
+ writel(data, sm->regs + reg);
+ sm501_sync_regs(sm);
+
+ spin_unlock_irqrestore(&sm->reg_lock, save);
+
+ return data;
+}
+
+EXPORT_SYMBOL_GPL(sm501_modify_reg);
+
+unsigned long sm501_gpio_get(struct device *dev,
+ unsigned long gpio)
+{
+ struct sm501_devdata *sm = dev_get_drvdata(dev);
+ unsigned long result;
+ unsigned long reg;
+
+ reg = (gpio > 32) ? SM501_GPIO_DATA_HIGH : SM501_GPIO_DATA_LOW;
+ result = readl(sm->regs + reg);
+
+ result >>= (gpio & 31);
+ return result & 1UL;
+}
+
+EXPORT_SYMBOL_GPL(sm501_gpio_get);
+
+void sm501_gpio_set(struct device *dev,
+ unsigned long gpio,
+ unsigned int to,
+ unsigned int dir)
+{
+ struct sm501_devdata *sm = dev_get_drvdata(dev);
+
+ unsigned long bit = 1 << (gpio & 31);
+ unsigned long base;
+ unsigned long save;
+ unsigned long val;
+
+ base = (gpio > 32) ? SM501_GPIO_DATA_HIGH : SM501_GPIO_DATA_LOW;
+ base += SM501_GPIO;
+
+ spin_lock_irqsave(&sm->reg_lock, save);
+
+ val = readl(sm->regs + base) & ~bit;
+ if (to)
+ val |= bit;
+ writel(val, sm->regs + base);
+
+ val = readl(sm->regs + SM501_GPIO_DDR_LOW) & ~bit;
+ if (dir)
+ val |= bit;
+
+ writel(val, sm->regs + SM501_GPIO_DDR_LOW);
+ sm501_sync_regs(sm);
+
+ spin_unlock_irqrestore(&sm->reg_lock, save);
+
+}
+
+EXPORT_SYMBOL_GPL(sm501_gpio_set);
+
+
+/* sm501_unit_power
+ *
+ * alters the power active gate to set specific units on or off
+ */
+
+int sm501_unit_power(struct device *dev, unsigned int unit, unsigned int to)
+{
+ struct sm501_devdata *sm = dev_get_drvdata(dev);
+ unsigned long mode;
+ unsigned long gate;
+ unsigned long clock;
+
+ mutex_lock(&sm->clock_lock);
+
+ mode = readl(sm->regs + SM501_POWER_MODE_CONTROL);
+ gate = readl(sm->regs + SM501_CURRENT_GATE);
+ clock = readl(sm->regs + SM501_CURRENT_CLOCK);
+
+ mode &= 3; /* get current power mode */
+
+ if (unit > ARRAY_SIZE(sm->unit_power)) {
+ dev_err(dev, "%s: bad unit %d\n", __FUNCTION__, unit);
+ goto already;
+ }
+
+ dev_dbg(sm->dev, "%s: unit %d, cur %d, to %d\n", __FUNCTION__, unit,
+ sm->unit_power[unit], to);
+
+ if (to == 0 && sm->unit_power[unit] == 0) {
+ dev_err(sm->dev, "unit %d is already shutdown\n", unit);
+ goto already;
+ }
+
+ sm->unit_power[unit] += to ? 1 : -1;
+ to = sm->unit_power[unit] ? 1 : 0;
+
+ if (to) {
+ if (gate & (1 << unit))
+ goto already;
+ gate |= (1 << unit);
+ } else {
+ if (!(gate & (1 << unit)))
+ goto already;
+ gate &= ~(1 << unit);
+ }
+
+ switch (mode) {
+ case 1:
+ writel(gate, sm->regs + SM501_POWER_MODE_0_GATE);
+ writel(clock, sm->regs + SM501_POWER_MODE_0_CLOCK);
+ mode = 0;
+ break;
+ case 2:
+ case 0:
+ writel(gate, sm->regs + SM501_POWER_MODE_1_GATE);
+ writel(clock, sm->regs + SM501_POWER_MODE_1_CLOCK);
+ mode = 1;
+ break;
+
+ default:
+ return -1;
+ }
+
+ writel(mode, sm->regs + SM501_POWER_MODE_CONTROL);
+ sm501_sync_regs(sm);
+
+ dev_dbg(sm->dev, "gate %08lx, clock %08lx, mode %08lx\n",
+ gate, clock, mode);
+
+ msleep(16);
+
+ already:
+ mutex_unlock(&sm->clock_lock);
+ return gate;
+}
+
+EXPORT_SYMBOL_GPL(sm501_unit_power);
+
+
+/* Perform a rounded division. */
+static long sm501fb_round_div(long num, long denom)
+{
+ /* n / d + 1 / 2 = (2n + d) / 2d */
+ return (2 * num + denom) / (2 * denom);
+}
+
+/* clock value structure. */
+struct sm501_clock {
+ unsigned long mclk;
+ int divider;
+ int shift;
+};
+
+/* sm501_select_clock
+ *
+ * selects nearest discrete clock frequency the SM501 can achive
+ * the maximum divisor is 3 or 5
+ */
+static unsigned long sm501_select_clock(unsigned long freq,
+ struct sm501_clock *clock,
+ int max_div)
+{
+ unsigned long mclk;
+ int divider;
+ int shift;
+ long diff;
+ long best_diff = 999999999;
+
+ /* Try 288MHz and 336MHz clocks. */
+ for (mclk = 288000000; mclk <= 336000000; mclk += 48000000) {
+ /* try dividers 1 and 3 for CRT and for panel,
+ try divider 5 for panel only.*/
+
+ for (divider = 1; divider <= max_div; divider += 2) {
+ /* try all 8 shift values.*/
+ for (shift = 0; shift < 8; shift++) {
+ /* Calculate difference to requested clock */
+ diff = sm501fb_round_div(mclk, divider << shift) - freq;
+ if (diff < 0)
+ diff = -diff;
+
+ /* If it is less than the current, use it */
+ if (diff < best_diff) {
+ best_diff = diff;
+
+ clock->mclk = mclk;
+ clock->divider = divider;
+ clock->shift = shift;
+ }
+ }
+ }
+ }
+
+ /* Return best clock. */
+ return clock->mclk / (clock->divider << clock->shift);
+}
+
+/* sm501_set_clock
+ *
+ * set one of the four clock sources to the closest available frequency to
+ * the one specified
+*/
+
+unsigned long sm501_set_clock(struct device *dev,
+ int clksrc,
+ unsigned long req_freq)
+{
+ struct sm501_devdata *sm = dev_get_drvdata(dev);
+ unsigned long mode = readl(sm->regs + SM501_POWER_MODE_CONTROL);
+ unsigned long gate = readl(sm->regs + SM501_CURRENT_GATE);
+ unsigned long clock = readl(sm->regs + SM501_CURRENT_CLOCK);
+ unsigned char reg;
+ unsigned long sm501_freq; /* the actual frequency acheived */
+
+ struct sm501_clock to;
+
+ /* find achivable discrete frequency and setup register value
+ * accordingly, V2XCLK, MCLK and M1XCLK are the same P2XCLK
+ * has an extra bit for the divider */
+
+ switch (clksrc) {
+ case SM501_CLOCK_P2XCLK:
+ /* This clock is divided in half so to achive the
+ * requested frequency the value must be multiplied by
+ * 2. This clock also has an additional pre divisor */
+
+ sm501_freq = (sm501_select_clock(2 * req_freq, &to, 5) / 2);
+ reg=to.shift & 0x07;/* bottom 3 bits are shift */
+ if (to.divider == 3)
+ reg |= 0x08; /* /3 divider required */
+ else if (to.divider == 5)
+ reg |= 0x10; /* /5 divider required */
+ if (to.mclk != 288000000)
+ reg |= 0x20; /* which mclk pll is source */
+ break;
+
+ case SM501_CLOCK_V2XCLK:
+ /* This clock is divided in half so to achive the
+ * requested frequency the value must be multiplied by 2. */
+
+ sm501_freq = (sm501_select_clock(2 * req_freq, &to, 3) / 2);
+ reg=to.shift & 0x07; /* bottom 3 bits are shift */
+ if (to.divider == 3)
+ reg |= 0x08; /* /3 divider required */
+ if (to.mclk != 288000000)
+ reg |= 0x10; /* which mclk pll is source */
+ break;
+
+ case SM501_CLOCK_MCLK:
+ case SM501_CLOCK_M1XCLK:
+ /* These clocks are the same and not further divided */
+
+ sm501_freq = sm501_select_clock( req_freq, &to, 3);
+ reg=to.shift & 0x07; /* bottom 3 bits are shift */
+ if (to.divider == 3)
+ reg |= 0x08; /* /3 divider required */
+ if (to.mclk != 288000000)
+ reg |= 0x10; /* which mclk pll is source */
+ break;
+
+ default:
+ return 0; /* this is bad */
+ }
+
+ mutex_lock(&sm->clock_lock);
+
+ mode = readl(sm->regs + SM501_POWER_MODE_CONTROL);
+ gate = readl(sm->regs + SM501_CURRENT_GATE);
+ clock = readl(sm->regs + SM501_CURRENT_CLOCK);
+
+ clock = clock & ~(0xFF << clksrc);
+ clock |= reg<<clksrc;
+
+ mode &= 3; /* find current mode */
+
+ switch (mode) {
+ case 1:
+ writel(gate, sm->regs + SM501_POWER_MODE_0_GATE);
+ writel(clock, sm->regs + SM501_POWER_MODE_0_CLOCK);
+ mode = 0;
+ break;
+ case 2:
+ case 0:
+ writel(gate, sm->regs + SM501_POWER_MODE_1_GATE);
+ writel(clock, sm->regs + SM501_POWER_MODE_1_CLOCK);
+ mode = 1;
+ break;
+
+ default:
+ mutex_unlock(&sm->clock_lock);
+ return -1;
+ }
+
+ writel(mode, sm->regs + SM501_POWER_MODE_CONTROL);
+ sm501_sync_regs(sm);
+
+ dev_info(sm->dev, "gate %08lx, clock %08lx, mode %08lx\n",
+ gate, clock, mode);
+
+ msleep(16);
+ mutex_unlock(&sm->clock_lock);
+
+ sm501_dump_clk(sm);
+
+ return sm501_freq;
+}
+
+EXPORT_SYMBOL_GPL(sm501_set_clock);
+
+/* sm501_find_clock
+ *
+ * finds the closest available frequency for a given clock
+*/
+
+unsigned long sm501_find_clock(int clksrc,
+ unsigned long req_freq)
+{
+ unsigned long sm501_freq; /* the frequency achiveable by the 501 */
+ struct sm501_clock to;
+
+ switch (clksrc) {
+ case SM501_CLOCK_P2XCLK:
+ sm501_freq = (sm501_select_clock(2 * req_freq, &to, 5) / 2);
+ break;
+
+ case SM501_CLOCK_V2XCLK:
+ sm501_freq = (sm501_select_clock(2 * req_freq, &to, 3) / 2);
+ break;
+
+ case SM501_CLOCK_MCLK:
+ case SM501_CLOCK_M1XCLK:
+ sm501_freq = sm501_select_clock(req_freq, &to, 3);
+ break;
+
+ default:
+ sm501_freq = 0; /* error */
+ }
+
+ return sm501_freq;
+}
+
+EXPORT_SYMBOL_GPL(sm501_find_clock);
+
+static struct sm501_device *to_sm_device(struct platform_device *pdev)
+{
+ return container_of(pdev, struct sm501_device, pdev);
+}
+
+/* sm501_device_release
+ *
+ * A release function for the platform devices we create to allow us to
+ * free any items we allocated
+*/
+
+static void sm501_device_release(struct device *dev)
+{
+ kfree(to_sm_device(to_platform_device(dev)));
+}
+
+/* sm501_create_subdev
+ *
+ * Create a skeleton platform device with resources for passing to a
+ * sub-driver
+*/
+
+static struct platform_device *
+sm501_create_subdev(struct sm501_devdata *sm,
+ char *name, unsigned int res_count)
+{
+ struct sm501_device *smdev;
+
+ smdev = kzalloc(sizeof(struct sm501_device) +
+ sizeof(struct resource) * res_count, GFP_KERNEL);
+ if (!smdev)
+ return NULL;
+
+ smdev->pdev.dev.release = sm501_device_release;
+
+ smdev->pdev.name = name;
+ smdev->pdev.id = sm->pdev_id;
+ smdev->pdev.resource = (struct resource *)(smdev+1);
+ smdev->pdev.num_resources = res_count;
+
+ smdev->pdev.dev.parent = sm->dev;
+
+ return &smdev->pdev;
+}
+
+/* sm501_register_device
+ *
+ * Register a platform device created with sm501_create_subdev()
+*/
+
+static int sm501_register_device(struct sm501_devdata *sm,
+ struct platform_device *pdev)
+{
+ struct sm501_device *smdev = to_sm_device(pdev);
+ int ptr;
+ int ret;
+
+ for (ptr = 0; ptr < pdev->num_resources; ptr++) {
+ printk("%s[%d] flags %08lx: %08llx..%08llx\n",
+ pdev->name, ptr,
+ pdev->resource[ptr].flags,
+ (unsigned long long)pdev->resource[ptr].start,
+ (unsigned long long)pdev->resource[ptr].end);
+ }
+
+ ret = platform_device_register(pdev);
+
+ if (ret >= 0) {
+ dev_dbg(sm->dev, "registered %s\n", pdev->name);
+ list_add_tail(&smdev->list, &sm->devices);
+ } else
+ dev_err(sm->dev, "error registering %s (%d)\n",
+ pdev->name, ret);
+
+ return ret;
+}
+
+/* sm501_create_subio
+ *
+ * Fill in an IO resource for a sub device
+*/
+
+static void sm501_create_subio(struct sm501_devdata *sm,
+ struct resource *res,
+ resource_size_t offs,
+ resource_size_t size)
+{
+ res->flags = IORESOURCE_MEM;
+ res->parent = sm->io_res;
+ res->start = sm->io_res->start + offs;
+ res->end = res->start + size - 1;
+}
+
+/* sm501_create_mem
+ *
+ * Fill in an MEM resource for a sub device
+*/
+
+static void sm501_create_mem(struct sm501_devdata *sm,
+ struct resource *res,
+ resource_size_t *offs,
+ resource_size_t size)
+{
+ *offs -= size; /* adjust memory size */
+
+ res->flags = IORESOURCE_MEM;
+ res->parent = sm->mem_res;
+ res->start = sm->mem_res->start + *offs;
+ res->end = res->start + size - 1;
+}
+
+/* sm501_create_irq
+ *
+ * Fill in an IRQ resource for a sub device
+*/
+
+static void sm501_create_irq(struct sm501_devdata *sm,
+ struct resource *res)
+{
+ res->flags = IORESOURCE_IRQ;
+ res->parent = NULL;
+ res->start = res->end = sm->irq;
+}
+
+static int sm501_register_usbhost(struct sm501_devdata *sm,
+ resource_size_t *mem_avail)
+{
+ struct platform_device *pdev;
+
+ pdev = sm501_create_subdev(sm, "sm501-usb", 3);
+ if (!pdev)
+ return -ENOMEM;
+
+ sm501_create_subio(sm, &pdev->resource[0], 0x40000, 0x20000);
+ sm501_create_mem(sm, &pdev->resource[1], mem_avail, 256*1024);
+ sm501_create_irq(sm, &pdev->resource[2]);
+
+ return sm501_register_device(sm, pdev);
+}
+
+static int sm501_register_display(struct sm501_devdata *sm,
+ resource_size_t *mem_avail)
+{
+ struct platform_device *pdev;
+
+ pdev = sm501_create_subdev(sm, "sm501-fb", 4);
+ if (!pdev)
+ return -ENOMEM;
+
+ sm501_create_subio(sm, &pdev->resource[0], 0x80000, 0x10000);
+ sm501_create_subio(sm, &pdev->resource[1], 0x100000, 0x50000);
+ sm501_create_mem(sm, &pdev->resource[2], mem_avail, *mem_avail);
+ sm501_create_irq(sm, &pdev->resource[3]);
+
+ return sm501_register_device(sm, pdev);
+}
+
+/* sm501_dbg_regs
+ *
+ * Debug attribute to attach to parent device to show core registers
+*/
+
+static ssize_t sm501_dbg_regs(struct device *dev,
+ struct device_attribute *attr, char *buff)
+{
+ struct sm501_devdata *sm = dev_get_drvdata(dev) ;
+ unsigned int reg;
+ char *ptr = buff;
+ int ret;
+
+ for (reg = 0x00; reg < 0x70; reg += 4) {
+ ret = sprintf(ptr, "%08x = %08x\n",
+ reg, readl(sm->regs + reg));
+ ptr += ret;
+ }
+
+ return ptr - buff;
+}
+
+
+static DEVICE_ATTR(dbg_regs, 0666, sm501_dbg_regs, NULL);
+
+/* sm501_init_reg
+ *
+ * Helper function for the init code to setup a register
+*/
+
+static inline void sm501_init_reg(struct sm501_devdata *sm,
+ unsigned long reg,
+ struct sm501_reg_init *r)
+{
+ unsigned long tmp;
+
+ tmp = readl(sm->regs + reg);
+ tmp |= r->set;
+ tmp &= ~r->mask;
+ writel(tmp, sm->regs + reg);
+}
+
+/* sm501_init_regs
+ *
+ * Setup core register values
+*/
+
+static void sm501_init_regs(struct sm501_devdata *sm,
+ struct sm501_initdata *init)
+{
+ sm501_misc_control(sm->dev,
+ init->misc_control.set,
+ init->misc_control.mask);
+
+ sm501_init_reg(sm, SM501_MISC_TIMING, &init->misc_timing);
+ sm501_init_reg(sm, SM501_GPIO31_0_CONTROL, &init->gpio_low);
+ sm501_init_reg(sm, SM501_GPIO63_32_CONTROL, &init->gpio_high);
+
+ if (init->mclk) {
+ dev_info(sm->dev, "setting MCLK to %ld\n", init->mclk);
+ sm501_set_clock(sm->dev, SM501_CLOCK_MCLK, init->mclk);
+ }
+
+ if (init->m1xclk) {
+ dev_info(sm->dev, "setting M1XCLK to %ld\n", init->m1xclk);
+ sm501_set_clock(sm->dev, SM501_CLOCK_M1XCLK, init->m1xclk);
+ }
+}
+
+static unsigned int sm501_mem_local[] = {
+ [0] = 4*1024*1024,
+ [1] = 8*1024*1024,
+ [2] = 16*1024*1024,
+ [3] = 32*1024*1024,
+ [4] = 64*1024*1024,
+ [5] = 2*1024*1024,
+};
+
+/* sm501_init_dev
+ *
+ * Common init code for an SM501
+*/
+
+static int sm501_init_dev(struct sm501_devdata *sm)
+{
+ resource_size_t mem_avail;
+ unsigned long dramctrl;
+ int ret;
+
+ mutex_init(&sm->clock_lock);
+ spin_lock_init(&sm->reg_lock);
+
+ INIT_LIST_HEAD(&sm->devices);
+
+ dramctrl = readl(sm->regs + SM501_DRAM_CONTROL);
+
+ mem_avail = sm501_mem_local[(dramctrl >> 13) & 0x7];
+
+ dev_info(sm->dev, "SM501 At %p: Version %08x, %ld Mb, IRQ %d\n",
+ sm->regs, readl(sm->regs + SM501_DEVICEID),
+ (unsigned long)mem_avail >> 20, sm->irq);
+
+ dev_info(sm->dev, "CurrentGate %08x\n", readl(sm->regs+0x38));
+ dev_info(sm->dev, "CurrentClock %08x\n", readl(sm->regs+0x3c));
+ dev_info(sm->dev, "PowerModeControl %08x\n", readl(sm->regs+0x54));
+
+ ret = device_create_file(sm->dev, &dev_attr_dbg_regs);
+ if (ret)
+ dev_err(sm->dev, "failed to create debug regs file\n");
+
+ sm501_dump_clk(sm);
+
+ /* check to see if we have some device initialisation */
+
+ if (sm->platdata) {
+ struct sm501_platdata *pdata = sm->platdata;
+
+ if (pdata->init) {
+ sm501_init_regs(sm, sm->platdata->init);
+
+ if (pdata->init->devices & SM501_USE_USB_HOST)
+ sm501_register_usbhost(sm, &mem_avail);
+ }
+ }
+
+ /* always create a framebuffer */
+ sm501_register_display(sm, &mem_avail);
+
+ return 0;
+}
+
+static int sm501_plat_probe(struct platform_device *dev)
+{
+ struct sm501_devdata *sm;
+ int err;
+
+ sm = kzalloc(sizeof(struct sm501_devdata), GFP_KERNEL);
+ if (sm == NULL) {
+ dev_err(&dev->dev, "no memory for device data\n");
+ err = -ENOMEM;
+ goto err1;
+ }
+
+ sm->dev = &dev->dev;
+ sm->pdev_id = dev->id;
+ sm->irq = platform_get_irq(dev, 0);
+ sm->io_res = platform_get_resource(dev, IORESOURCE_MEM, 1);
+ sm->mem_res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ sm->platdata = dev->dev.platform_data;
+
+ if (sm->irq < 0) {
+ dev_err(&dev->dev, "failed to get irq resource\n");
+ err = sm->irq;
+ goto err_res;
+ }
+
+ if (sm->io_res == NULL || sm->mem_res == NULL) {
+ dev_err(&dev->dev, "failed to get IO resource\n");
+ err = -ENOENT;
+ goto err_res;
+ }
+
+ sm->regs_claim = request_mem_region(sm->io_res->start,
+ 0x100, "sm501");
+
+ if (sm->regs_claim == NULL) {
+ dev_err(&dev->dev, "cannot claim registers\n");
+ err= -EBUSY;
+ goto err_res;
+ }
+
+ platform_set_drvdata(dev, sm);
+
+ sm->regs = ioremap(sm->io_res->start,
+ (sm->io_res->end - sm->io_res->start) - 1);
+
+ if (sm->regs == NULL) {
+ dev_err(&dev->dev, "cannot remap registers\n");
+ err = -EIO;
+ goto err_claim;
+ }
+
+ return sm501_init_dev(sm);
+
+ err_claim:
+ release_resource(sm->regs_claim);
+ kfree(sm->regs_claim);
+ err_res:
+ kfree(sm);
+ err1:
+ return err;
+
+}
+
+/* Initialisation data for PCI devices */
+
+static struct sm501_initdata sm501_pci_initdata = {
+ .gpio_high = {
+ .set = 0x3F000000, /* 24bit panel */
+ .mask = 0x0,
+ },
+ .misc_timing = {
+ .set = 0x010100, /* SDRAM timing */
+ .mask = 0x1F1F00,
+ },
+ .misc_control = {
+ .set = SM501_MISC_PNL_24BIT,
+ .mask = 0,
+ },
+
+ .devices = SM501_USE_ALL,
+ .mclk = 100 * MHZ,
+ .m1xclk = 160 * MHZ,
+};
+
+static struct sm501_platdata_fbsub sm501_pdata_fbsub = {
+ .flags = (SM501FB_FLAG_USE_INIT_MODE |
+ SM501FB_FLAG_USE_HWCURSOR |
+ SM501FB_FLAG_USE_HWACCEL |
+ SM501FB_FLAG_DISABLE_AT_EXIT),
+};
+
+static struct sm501_platdata_fb sm501_fb_pdata = {
+ .fb_route = SM501_FB_OWN,
+ .fb_crt = &sm501_pdata_fbsub,
+ .fb_pnl = &sm501_pdata_fbsub,
+};
+
+static struct sm501_platdata sm501_pci_platdata = {
+ .init = &sm501_pci_initdata,
+ .fb = &sm501_fb_pdata,
+};
+
+static int sm501_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *id)
+{
+ struct sm501_devdata *sm;
+ int err;
+
+ sm = kzalloc(sizeof(struct sm501_devdata), GFP_KERNEL);
+ if (sm == NULL) {
+ dev_err(&dev->dev, "no memory for device data\n");
+ err = -ENOMEM;
+ goto err1;
+ }
+
+ /* set a default set of platform data */
+ dev->dev.platform_data = sm->platdata = &sm501_pci_platdata;
+
+ /* set a hopefully unique id for our child platform devices */
+ sm->pdev_id = 32 + dev->devfn;
+
+ pci_set_drvdata(dev, sm);
+
+ err = pci_enable_device(dev);
+ if (err) {
+ dev_err(&dev->dev, "cannot enable device\n");
+ goto err2;
+ }
+
+ sm->dev = &dev->dev;
+ sm->irq = dev->irq;
+
+#ifdef __BIG_ENDIAN
+ /* if the system is big-endian, we most probably have a
+ * translation in the IO layer making the PCI bus little endian
+ * so make the framebuffer swapped pixels */
+
+ sm501_fb_pdata.flags |= SM501_FBPD_SWAP_FB_ENDIAN;
+#endif
+
+ /* check our resources */
+
+ if (!(pci_resource_flags(dev, 0) & IORESOURCE_MEM)) {
+ dev_err(&dev->dev, "region #0 is not memory?\n");
+ err = -EINVAL;
+ goto err3;
+ }
+
+ if (!(pci_resource_flags(dev, 1) & IORESOURCE_MEM)) {
+ dev_err(&dev->dev, "region #1 is not memory?\n");
+ err = -EINVAL;
+ goto err3;
+ }
+
+ /* make our resources ready for sharing */
+
+ sm->io_res = &dev->resource[1];
+ sm->mem_res = &dev->resource[0];
+
+ sm->regs_claim = request_mem_region(sm->io_res->start,
+ 0x100, "sm501");
+ if (sm->regs_claim == NULL) {
+ dev_err(&dev->dev, "cannot claim registers\n");
+ err= -EBUSY;
+ goto err3;
+ }
+
+ sm->regs = ioremap(pci_resource_start(dev, 1),
+ pci_resource_len(dev, 1));
+
+ if (sm->regs == NULL) {
+ dev_err(&dev->dev, "cannot remap registers\n");
+ err = -EIO;
+ goto err4;
+ }
+
+ sm501_init_dev(sm);
+ return 0;
+
+ err4:
+ release_resource(sm->regs_claim);
+ kfree(sm->regs_claim);
+ err3:
+ pci_disable_device(dev);
+ err2:
+ pci_set_drvdata(dev, NULL);
+ kfree(sm);
+ err1:
+ return err;
+}
+
+static void sm501_remove_sub(struct sm501_devdata *sm,
+ struct sm501_device *smdev)
+{
+ list_del(&smdev->list);
+ platform_device_unregister(&smdev->pdev);
+}
+
+static void sm501_dev_remove(struct sm501_devdata *sm)
+{
+ struct sm501_device *smdev, *tmp;
+
+ list_for_each_entry_safe(smdev, tmp, &sm->devices, list)
+ sm501_remove_sub(sm, smdev);
+
+ device_remove_file(sm->dev, &dev_attr_dbg_regs);
+}
+
+static void sm501_pci_remove(struct pci_dev *dev)
+{
+ struct sm501_devdata *sm = pci_get_drvdata(dev);
+
+ sm501_dev_remove(sm);
+ iounmap(sm->regs);
+
+ release_resource(sm->regs_claim);
+ kfree(sm->regs_claim);
+
+ pci_set_drvdata(dev, NULL);
+ pci_disable_device(dev);
+}
+
+static int sm501_plat_remove(struct platform_device *dev)
+{
+ struct sm501_devdata *sm = platform_get_drvdata(dev);
+
+ sm501_dev_remove(sm);
+ iounmap(sm->regs);
+
+ release_resource(sm->regs_claim);
+ kfree(sm->regs_claim);
+
+ return 0;
+}
+
+static struct pci_device_id sm501_pci_tbl[] = {
+ { 0x126f, 0x0501, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { 0, },
+};
+
+MODULE_DEVICE_TABLE(pci, sm501_pci_tbl);
+
+static struct pci_driver sm501_pci_drv = {
+ .name = "sm501",
+ .id_table = sm501_pci_tbl,
+ .probe = sm501_pci_probe,
+ .remove = sm501_pci_remove,
+};
+
+static struct platform_driver sm501_plat_drv = {
+ .driver = {
+ .name = "sm501",
+ .owner = THIS_MODULE,
+ },
+ .probe = sm501_plat_probe,
+ .remove = sm501_plat_remove,
+};
+
+static int __init sm501_base_init(void)
+{
+ platform_driver_register(&sm501_plat_drv);
+ return pci_register_driver(&sm501_pci_drv);
+}
+
+static void __exit sm501_base_exit(void)
+{
+ platform_driver_unregister(&sm501_plat_drv);
+ pci_unregister_driver(&sm501_pci_drv);
+}
+
+module_init(sm501_base_init);
+module_exit(sm501_base_exit);
+
+MODULE_DESCRIPTION("SM501 Core Driver");
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>, Vincent Sanders");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 00db31c314e..80b199fa0aa 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -42,7 +42,7 @@ config SGI_IOC4
config TIFM_CORE
tristate "TI Flash Media interface support (EXPERIMENTAL)"
- depends on EXPERIMENTAL
+ depends on EXPERIMENTAL && PCI
help
If you want support for Texas Instruments(R) Flash Media adapters
you should select this option and then also choose an appropriate
@@ -69,6 +69,25 @@ config TIFM_7XX1
To compile this driver as a module, choose M here: the module will
be called tifm_7xx1.
+config ASUS_LAPTOP
+ tristate "Asus Laptop Extras (EXPERIMENTAL)"
+ depends on X86
+ depends on ACPI
+ depends on EXPERIMENTAL && !ACPI_ASUS
+ depends on LEDS_CLASS
+ depends on BACKLIGHT_CLASS_DEVICE
+ ---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
+ standard ACPI events that go through /proc/acpi/events. It also adds
+ support for video output switching, LCD backlight control, Bluetooth and
+ Wlan control, and most importantly, allows you to blink those fancy LEDs.
+
+ For more information and a userspace daemon for handling the extra
+ buttons see <http://acpi4asus.sf.net/>.
+
+ If you have an ACPI-compatible ASUS laptop, say Y or M here.
+
config MSI_LAPTOP
tristate "MSI Laptop Extras"
depends on X86
@@ -88,4 +107,19 @@ config MSI_LAPTOP
If you have an MSI S270 laptop, say Y or M here.
+config SONY_LAPTOP
+ tristate "Sony Laptop Extras"
+ depends on X86 && ACPI
+ select BACKLIGHT_CLASS_DEVICE
+ ---help---
+ This mini-driver drives the SNC device present in the ACPI BIOS of
+ the Sony Vaio laptops.
+
+ It gives access to some extra laptop functionalities. In its current
+ form, this driver let the user set or query the screen brightness
+ through the backlight subsystem and remove/apply power to some
+ devices.
+
+ Read <file:Documentation/sony-laptop.txt> for more information.
+
endmenu
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index c9e98ab021c..7793ccd7904 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -6,7 +6,9 @@ obj- := misc.o # Dummy rule to force built-in.o to be made
obj-$(CONFIG_IBM_ASM) += ibmasm/
obj-$(CONFIG_HDPU_FEATURES) += hdpuftrs/
obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o
+obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o
obj-$(CONFIG_LKDTM) += lkdtm.o
obj-$(CONFIG_TIFM_CORE) += tifm_core.o
obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o
obj-$(CONFIG_SGI_IOC4) += ioc4.o
+obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o
diff --git a/drivers/misc/asus-laptop.c b/drivers/misc/asus-laptop.c
new file mode 100644
index 00000000000..295e931c0df
--- /dev/null
+++ b/drivers/misc/asus-laptop.c
@@ -0,0 +1,1149 @@
+/*
+ * asus-laptop.c - Asus Laptop Support
+ *
+ *
+ * Copyright (C) 2002-2005 Julien Lerouge, 2003-2006 Karol Kozimor
+ * Copyright (C) 2006 Corentin Chary
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under 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 development page for this driver is located at
+ * http://sourceforge.net/projects/acpi4asus/
+ *
+ * Credits:
+ * Pontus Fuchs - Helper functions, cleanup
+ * Johann Wiesner - Small compile fixes
+ * John Belmonte - ACPI code for Toshiba laptop was a good starting point.
+ * Eric Burghard - LED display support for W1N
+ * Josh Green - Light Sens support
+ * Thomas Tuttle - His first patch for led support was very helpfull
+ *
+ */
+
+#include <linux/autoconf.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/err.h>
+#include <linux/proc_fs.h>
+#include <linux/backlight.h>
+#include <linux/fb.h>
+#include <linux/leds.h>
+#include <linux/platform_device.h>
+#include <acpi/acpi_drivers.h>
+#include <acpi/acpi_bus.h>
+#include <asm/uaccess.h>
+
+#define ASUS_LAPTOP_VERSION "0.40"
+
+#define ASUS_HOTK_NAME "Asus Laptop Support"
+#define ASUS_HOTK_CLASS "hotkey"
+#define ASUS_HOTK_DEVICE_NAME "Hotkey"
+#define ASUS_HOTK_HID "ATK0100"
+#define ASUS_HOTK_FILE "asus-laptop"
+#define ASUS_HOTK_PREFIX "\\_SB.ATKD."
+
+/*
+ * 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 LCD_ON 0x40 //LCD 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
+
+MODULE_AUTHOR("Julien Lerouge, Karol Kozimor, Corentin Chary");
+MODULE_DESCRIPTION(ASUS_HOTK_NAME);
+MODULE_LICENSE("GPL");
+
+#define ASUS_HANDLE(object, paths...) \
+ static acpi_handle object##_handle = NULL; \
+ static char *object##_paths[] = { paths }
+
+/* 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 */
+
+/* LEDD */
+ASUS_HANDLE(ledd_set, ASUS_HOTK_PREFIX "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 */
+
+/* Brightness */
+ASUS_HANDLE(brightness_set, ASUS_HOTK_PREFIX "SPLV");
+ASUS_HANDLE(brightness_get, ASUS_HOTK_PREFIX "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.PX40.Q10", /* S1x */
+ "\\Q10"); /* A2x, L2D, L3D, M2E */
+
+/* Display */
+ASUS_HANDLE(display_set, ASUS_HOTK_PREFIX "SDSP");
+ASUS_HANDLE(display_get, "\\_SB.PCI0.P0P1.VGA.GETD", /* A6B, A6K A6R A7D F3JM L4R M6R A3G
+ M6A M6V VX-1 V6J V6V W3Z */
+ "\\_SB.PCI0.P0P2.VGA.GETD", /* A3E A4K, A4D A4L A6J A7J A8J Z71V M9V
+ S5A M5A z33A W1Jc W2V */
+ "\\_SB.PCI0.P0P3.VGA.GETD", /* A6V A6Q */
+ "\\_SB.PCI0.P0PA.VGA.GETD", /* A6T, A6M */
+ "\\_SB.PCI0.PCI1.VGAC.NMAP", /* L3C */
+ "\\_SB.PCI0.VGA.GETD", /* Z96F */
+ "\\ACTD", /* A2D */
+ "\\ADVG", /* A4G Z71A W1N W5A W5F M2N M3N M5N M6N S1N S5N */
+ "\\DNXT", /* P30 */
+ "\\INFB", /* A2H D1 L2D L3D L3H L2E L5D L5C M1A M2E L4L W3V */
+ "\\SSTE"); /* A3F A6F A3N A3L M6N W3N W6A */
+
+ASUS_HANDLE(ls_switch, ASUS_HOTK_PREFIX "ALSC"); /* Z71A Z71V */
+ASUS_HANDLE(ls_level, ASUS_HOTK_PREFIX "ALSL"); /* Z71A Z71V */
+
+/*
+ * This is the main structure, we can use it to store anything interesting
+ * about the hotk device
+ */
+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
+};
+
+/*
+ * 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
+ */
+static int asus_hotk_add(struct acpi_device *device);
+static int asus_hotk_remove(struct acpi_device *device, int type);
+static struct acpi_driver asus_hotk_driver = {
+ .name = ASUS_HOTK_NAME,
+ .class = ASUS_HOTK_CLASS,
+ .ids = ASUS_HOTK_HID,
+ .ops = {
+ .add = asus_hotk_add,
+ .remove = asus_hotk_remove,
+ },
+};
+
+/* The backlight device /sys/class/backlight */
+static struct backlight_device *asus_backlight_device;
+
+/*
+ * 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,
+};
+
+/* 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) \
+ static void object##_led_set(struct led_classdev *led_cdev, \
+ enum led_brightness value); \
+ static void object##_led_update(struct work_struct *ignored); \
+ static int object##_led_wk; \
+ DECLARE_WORK(object##_led_work, object##_led_update); \
+ static struct led_classdev object##_led = { \
+ .name = "asus:" ledname, \
+ .brightness_set = object##_led_set, \
+ }
+
+ASUS_LED(mled, "mail");
+ASUS_LED(tled, "touchpad");
+ASUS_LED(rled, "record");
+ASUS_LED(pled, "phone");
+
+/*
+ * 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
+ * of the method is written is output, which can also be NULL
+ *
+ * returns 1 if write is successful, 0 else.
+ */
+static int write_acpi_int(acpi_handle handle, const char *method, int val,
+ struct acpi_buffer *output)
+{
+ struct acpi_object_list params; //list of input parameters (an int here)
+ union acpi_object in_obj; //the only param we use
+ acpi_status status;
+
+ params.count = 1;
+ params.pointer = &in_obj;
+ in_obj.type = ACPI_TYPE_INTEGER;
+ in_obj.integer.value = val;
+
+ status = acpi_evaluate_object(handle, (char *)method, &params, output);
+ return (status == AE_OK);
+}
+
+static int read_acpi_int(acpi_handle handle, const char *method, int *val,
+ struct acpi_object_list *params)
+{
+ struct acpi_buffer output;
+ union acpi_object out_obj;
+ acpi_status status;
+
+ output.length = sizeof(out_obj);
+ output.pointer = &out_obj;
+
+ status = acpi_evaluate_object(handle, (char *)method, params, &output);
+ *val = out_obj.integer.value;
+ return (status == AE_OK) && (out_obj.type == ACPI_TYPE_INTEGER);
+}
+
+static int read_wireless_status(int mask)
+{
+ int status;
+
+ if (!wireless_status_handle)
+ return (hotk->status & mask) ? 1 : 0;
+
+ if (read_acpi_int(wireless_status_handle, NULL, &status, NULL)) {
+ return (status & mask) ? 1 : 0;
+ } else
+ printk(ASUS_WARNING "Error reading Wireless status\n");
+
+ return (hotk->status & mask) ? 1 : 0;
+}
+
+/* Generic LED functions */
+static int read_status(int mask)
+{
+ /* There is a special method for both wireless devices */
+ if (mask == BT_ON || mask == WL_ON)
+ return read_wireless_status(mask);
+
+ return (hotk->status & mask) ? 1 : 0;
+}
+
+static void write_status(acpi_handle handle, int out, int mask, int invert)
+{
+ hotk->status = (out) ? (hotk->status | mask) : (hotk->status & ~mask);
+
+ if (invert) /* invert target value */
+ out = !out & 0x1;
+
+ if (handle && !write_acpi_int(handle, NULL, out, NULL))
+ printk(ASUS_WARNING " write failed\n");
+}
+
+/* /sys/class/led handlers */
+#define ASUS_LED_HANDLER(object, mask, invert) \
+ static void object##_led_set(struct led_classdev *led_cdev, \
+ enum led_brightness value) \
+ { \
+ object##_led_wk = value; \
+ 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), (invert)); \
+ }
+
+ASUS_LED_HANDLER(mled, MLED_ON, 1);
+ASUS_LED_HANDLER(pled, PLED_ON, 0);
+ASUS_LED_HANDLER(rled, RLED_ON, 0);
+ASUS_LED_HANDLER(tled, TLED_ON, 0);
+
+static int get_lcd_state(void)
+{
+ return read_status(LCD_ON);
+}
+
+static int set_lcd_state(int value)
+{
+ int lcd = 0;
+ acpi_status status = 0;
+
+ lcd = value ? 1 : 0;
+
+ if (lcd == get_lcd_state())
+ return 0;
+
+ if (lcd_switch_handle) {
+ status = acpi_evaluate_object(lcd_switch_handle,
+ NULL, NULL, NULL);
+
+ if (ACPI_FAILURE(status))
+ printk(ASUS_WARNING "Error switching LCD\n");
+ }
+
+ write_status(NULL, lcd, LCD_ON, 0);
+ return 0;
+}
+
+static void lcd_blank(int blank)
+{
+ struct backlight_device *bd = asus_backlight_device;
+
+ if (bd) {
+ bd->props.power = blank;
+ backlight_update_status(bd);
+ }
+}
+
+static int read_brightness(struct backlight_device *bd)
+{
+ int value;
+
+ if (!read_acpi_int(brightness_get_handle, NULL, &value, NULL))
+ printk(ASUS_WARNING "Error reading brightness\n");
+
+ return value;
+}
+
+static int set_brightness(struct backlight_device *bd, int value)
+{
+ int ret = 0;
+
+ value = (0 < value) ? ((15 < value) ? 15 : value) : 0;
+ /* 0 <= value <= 15 */
+
+ if (!write_acpi_int(brightness_set_handle, NULL, value, NULL)) {
+ printk(ASUS_WARNING "Error changing brightness\n");
+ ret = -EIO;
+ }
+
+ return ret;
+}
+
+static int update_bl_status(struct backlight_device *bd)
+{
+ int rv;
+ int value = bd->props.brightness;
+
+ rv = set_brightness(bd, value);
+ if (rv)
+ return rv;
+
+ value = (bd->props.power == FB_BLANK_UNBLANK) ? 1 : 0;
+ return set_lcd_state(value);
+}
+
+/*
+ * Platform device handlers
+ */
+
+/*
+ * We write our info in page, we begin at offset off and cannot write more
+ * than count bytes. We set eof to 1 if we handle those 2 values. We return the
+ * number of bytes written in page
+ */
+static ssize_t show_infos(struct device *dev,
+ struct device_attribute *attr, char *page)
+{
+ int len = 0;
+ int temp;
+ char buf[16]; //enough for all info
+ /*
+ * 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);
+ /*
+ * 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.
+ */
+ if (read_acpi_int(hotk->handle, "SFUN", &temp, NULL))
+ len +=
+ sprintf(page + len, "SFUN value : 0x%04x\n", temp);
+ /*
+ * Another value for userspace: the ASYM method returns 0x02 for
+ * battery low and 0x04 for battery critical, its readings tend to be
+ * more accurate than those provided by _BST.
+ * Note: since not all the laptops provide this method, errors are
+ * silently ignored.
+ */
+ if (read_acpi_int(hotk->handle, "ASYM", &temp, NULL))
+ len +=
+ sprintf(page + len, "ASYM value : 0x%04x\n", temp);
+ if (asus_info) {
+ snprintf(buf, 16, "%d", asus_info->length);
+ len += sprintf(page + len, "DSDT length : %s\n", buf);
+ snprintf(buf, 16, "%d", asus_info->checksum);
+ len += sprintf(page + len, "DSDT checksum : %s\n", buf);
+ snprintf(buf, 16, "%d", asus_info->revision);
+ len += sprintf(page + len, "DSDT revision : %s\n", buf);
+ snprintf(buf, 7, "%s", asus_info->oem_id);
+ len += sprintf(page + len, "OEM id : %s\n", buf);
+ snprintf(buf, 9, "%s", asus_info->oem_table_id);
+ len += sprintf(page + len, "OEM table id : %s\n", buf);
+ snprintf(buf, 16, "%x", asus_info->oem_revision);
+ len += sprintf(page + len, "OEM revision : 0x%s\n", buf);
+ snprintf(buf, 5, "%s", asus_info->asl_compiler_id);
+ len += sprintf(page + len, "ASL comp vendor id : %s\n", buf);
+ snprintf(buf, 16, "%x", asus_info->asl_compiler_revision);
+ len += sprintf(page + len, "ASL comp revision : 0x%s\n", buf);
+ }
+
+ return len;
+}
+
+static int parse_arg(const char *buf, unsigned long count, int *val)
+{
+ if (!count)
+ return 0;
+ if (count > 31)
+ return -EINVAL;
+ if (sscanf(buf, "%i", val) != 1)
+ return -EINVAL;
+ return count;
+}
+
+static ssize_t store_status(const char *buf, size_t count,
+ acpi_handle handle, int mask, int invert)
+{
+ int rv, value;
+ int out = 0;
+
+ rv = parse_arg(buf, count, &value);
+ if (rv > 0)
+ out = value ? 1 : 0;
+
+ write_status(handle, out, mask, invert);
+
+ return rv;
+}
+
+/*
+ * LEDD display
+ */
+static ssize_t show_ledd(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "0x%08x\n", hotk->ledd_status);
+}
+
+static ssize_t store_ledd(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int rv, value;
+
+ rv = parse_arg(buf, count, &value);
+ if (rv > 0) {
+ if (!write_acpi_int(ledd_set_handle, NULL, value, NULL))
+ printk(ASUS_WARNING "LED display write failed\n");
+ else
+ hotk->ledd_status = (u32) value;
+ }
+ return rv;
+}
+
+/*
+ * WLAN
+ */
+static ssize_t show_wlan(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", read_status(WL_ON));
+}
+
+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, 0);
+}
+
+/*
+ * Bluetooth
+ */
+static ssize_t show_bluetooth(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", read_status(BT_ON));
+}
+
+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, 0);
+}
+
+/*
+ * Display
+ */
+static void set_display(int value)
+{
+ /* no sanity check needed for now */
+ if (!write_acpi_int(display_set_handle, NULL, value, NULL))
+ printk(ASUS_WARNING "Error setting display\n");
+ return;
+}
+
+static int read_display(void)
+{
+ int value = 0;
+
+ /* In most of the case, we know how to set the display, but sometime
+ we can't read it */
+ if (display_get_handle) {
+ if (!read_acpi_int(display_get_handle, NULL, &value, NULL))
+ printk(ASUS_WARNING "Error reading display status\n");
+ }
+
+ value &= 0x0F; /* needed for some models, shouldn't hurt others */
+
+ return value;
+}
+
+/*
+ * Now, *this* one could be more user-friendly, but so far, no-one has
+ * complained. The significance of bits is the same as in store_disp()
+ */
+static ssize_t show_disp(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", read_display());
+}
+
+/*
+ * Experimental support for display switching. As of now: 1 should activate
+ * the LCD output, 2 should do for CRT, 4 for TV-Out and 8 for DVI.
+ * Any combination (bitwise) of these will suffice. I never actually tested 4
+ * displays hooked up simultaneously, so be warned. See the acpi4asus README
+ * for more info.
+ */
+static ssize_t store_disp(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int rv, value;
+
+ rv = parse_arg(buf, count, &value);
+ if (rv > 0)
+ set_display(value);
+ return rv;
+}
+
+/*
+ * Light Sens
+ */
+static void set_light_sens_switch(int value)
+{
+ if (!write_acpi_int(ls_switch_handle, NULL, value, NULL))
+ printk(ASUS_WARNING "Error setting light sensor switch\n");
+ hotk->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);
+}
+
+static ssize_t store_lssw(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int rv, value;
+
+ rv = parse_arg(buf, count, &value);
+ if (rv > 0)
+ set_light_sens_switch(value ? 1 : 0);
+
+ return rv;
+}
+
+static void set_light_sens_level(int value)
+{
+ if (!write_acpi_int(ls_level_handle, NULL, value, NULL))
+ printk(ASUS_WARNING "Error setting light sensor level\n");
+ hotk->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);
+}
+
+static ssize_t store_lslvl(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ 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);
+ }
+
+ return rv;
+}
+
+static void asus_hotk_notify(acpi_handle handle, u32 event, void *data)
+{
+ /* TODO Find a better way to handle events count. */
+ if (!hotk)
+ return;
+
+ /*
+ * We need to tell the backlight device when the backlight power is
+ * switched
+ */
+ if (event == ATKD_LCD_ON) {
+ write_status(NULL, 1, LCD_ON, 0);
+ lcd_blank(FB_BLANK_UNBLANK);
+ } else if (event == ATKD_LCD_OFF) {
+ write_status(NULL, 0, LCD_ON, 0);
+ lcd_blank(FB_BLANK_POWERDOWN);
+ }
+
+ acpi_bus_generate_event(hotk->device, event,
+ hotk->event_count[event % 128]++);
+
+ return;
+}
+
+#define ASUS_CREATE_DEVICE_ATTR(_name) \
+ struct device_attribute dev_attr_##_name = { \
+ .attr = { \
+ .name = __stringify(_name), \
+ .mode = 0, \
+ .owner = THIS_MODULE }, \
+ .show = NULL, \
+ .store = NULL, \
+ }
+
+#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 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,
+ NULL
+};
+
+static struct attribute_group asuspf_attribute_group = {
+ .attrs = asuspf_attributes
+};
+
+static struct platform_driver asuspf_driver = {
+ .driver = {
+ .name = ASUS_HOTK_FILE,
+ .owner = THIS_MODULE,
+ }
+};
+
+static struct platform_device *asuspf_device;
+
+static void asus_hotk_add_fs(void)
+{
+ ASUS_SET_DEVICE_ATTR(infos, 0444, show_infos, NULL);
+
+ if (wl_switch_handle)
+ ASUS_SET_DEVICE_ATTR(wlan, 0644, show_wlan, store_wlan);
+
+ if (bt_switch_handle)
+ ASUS_SET_DEVICE_ATTR(bluetooth, 0644,
+ show_bluetooth, store_bluetooth);
+
+ 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);
+
+ if (ledd_set_handle)
+ ASUS_SET_DEVICE_ATTR(ledd, 0644, show_ledd, store_ledd);
+
+ 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);
+ }
+}
+
+static int asus_handle_init(char *name, acpi_handle * handle,
+ char **paths, int num_paths)
+{
+ int i;
+ acpi_status status;
+
+ for (i = 0; i < num_paths; i++) {
+ status = acpi_get_handle(NULL, paths[i], handle);
+ if (ACPI_SUCCESS(status))
+ return 0;
+ }
+
+ *handle = NULL;
+ return -ENODEV;
+}
+
+#define ASUS_HANDLE_INIT(object) \
+ asus_handle_init(#object, &object##_handle, object##_paths, \
+ 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
+ */
+static int asus_hotk_get_info(void)
+{
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object *model = NULL;
+ int bsts_result, hwrs_result;
+ char *string = NULL;
+ acpi_status status;
+
+ /*
+ * Get DSDT headers early enough to allow for differentiating between
+ * 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.
+ */
+ status = acpi_get_table(ACPI_SIG_DSDT, 1, &asus_info);
+ if (ACPI_FAILURE(status))
+ printk(ASUS_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)) {
+ printk(ASUS_ERR "Hotkey initialization failed\n");
+ return -ENODEV;
+ }
+
+ /* This needs to be called for some laptops to init properly */
+ if (!read_acpi_int(hotk->handle, "BSTS", &bsts_result, NULL))
+ printk(ASUS_WARNING "Error calling BSTS\n");
+ else if (bsts_result)
+ printk(ASUS_NOTICE "BSTS called, 0x%02x returned\n",
+ bsts_result);
+
+ /*
+ * Try to match the object returned by INIT to the specific model.
+ * Handle every possible object (or the lack of thereof) the DSDT
+ * writers might throw at us. When in trouble, we pass NULL to
+ * asus_model_match() and try something completely different.
+ */
+ if (buffer.pointer) {
+ model = buffer.pointer;
+ switch (model->type) {
+ case ACPI_TYPE_STRING:
+ string = model->string.pointer;
+ break;
+ case ACPI_TYPE_BUFFER:
+ string = model->buffer.pointer;
+ break;
+ default:
+ string = "";
+ break;
+ }
+ }
+ hotk->name = kstrdup(string, GFP_KERNEL);
+ if (!hotk->name)
+ return -ENOMEM;
+
+ if (*string)
+ printk(ASUS_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(ledd_set);
+
+ /*
+ * 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.
+ */
+ if (!read_acpi_int(hotk->handle, "HRWS", &hwrs_result, NULL))
+ 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);
+
+ ASUS_HANDLE_INIT(brightness_set);
+ ASUS_HANDLE_INIT(brightness_get);
+
+ 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);
+
+ kfree(model);
+
+ return AE_OK;
+}
+
+static int asus_hotk_check(void)
+{
+ int result = 0;
+
+ result = acpi_bus_get_status(hotk->device);
+ if (result)
+ return result;
+
+ if (hotk->device->status.present) {
+ result = asus_hotk_get_info();
+ } else {
+ printk(ASUS_ERR "Hotkey device not present, aborting\n");
+ return -EINVAL;
+ }
+
+ return result;
+}
+
+static int asus_hotk_found;
+
+static int asus_hotk_add(struct acpi_device *device)
+{
+ acpi_status status = AE_OK;
+ int result;
+
+ if (!device)
+ return -EINVAL;
+
+ printk(ASUS_NOTICE "Asus Laptop Support version %s\n",
+ ASUS_LAPTOP_VERSION);
+
+ hotk = kmalloc(sizeof(struct asus_hotk), GFP_KERNEL);
+ if (!hotk)
+ return -ENOMEM;
+ memset(hotk, 0, sizeof(struct asus_hotk));
+
+ hotk->handle = device->handle;
+ strcpy(acpi_device_name(device), ASUS_HOTK_DEVICE_NAME);
+ strcpy(acpi_device_class(device), ASUS_HOTK_CLASS);
+ acpi_driver_data(device) = hotk;
+ hotk->device = device;
+
+ result = asus_hotk_check();
+ if (result)
+ goto end;
+
+ asus_hotk_add_fs();
+
+ /*
+ * We install the handler, it will receive the hotk in parameter, so, we
+ * could add other data to the hotk struct
+ */
+ status = acpi_install_notify_handler(hotk->handle, ACPI_SYSTEM_NOTIFY,
+ asus_hotk_notify, hotk);
+ if (ACPI_FAILURE(status))
+ printk(ASUS_ERR "Error installing notify handler\n");
+
+ asus_hotk_found = 1;
+
+ /* WLED and BLED are on by default */
+ write_status(bt_switch_handle, 1, BT_ON, 0);
+ write_status(wl_switch_handle, 1, WL_ON, 0);
+
+ /* LCD Backlight is on by default */
+ write_status(NULL, 1, LCD_ON, 0);
+
+ /* LED display is off by default */
+ hotk->ledd_status = 0xFFF;
+
+ /* Set initial values of light sensor and level */
+ hotk->light_switch = 1; /* Default to light sensor disabled */
+ hotk->light_level = 0; /* 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);
+
+ end:
+ if (result) {
+ kfree(hotk->name);
+ kfree(hotk);
+ }
+
+ return result;
+}
+
+static int asus_hotk_remove(struct acpi_device *device, int type)
+{
+ acpi_status status = 0;
+
+ if (!device || !acpi_driver_data(device))
+ return -EINVAL;
+
+ status = acpi_remove_notify_handler(hotk->handle, ACPI_SYSTEM_NOTIFY,
+ asus_hotk_notify);
+ if (ACPI_FAILURE(status))
+ printk(ASUS_ERR "Error removing notify handler\n");
+
+ kfree(hotk->name);
+ kfree(hotk);
+
+ return 0;
+}
+
+static void asus_backlight_exit(void)
+{
+ if (asus_backlight_device)
+ backlight_device_unregister(asus_backlight_device);
+}
+
+#define ASUS_LED_UNREGISTER(object) \
+ if(object##_led.class_dev \
+ && !IS_ERR(object##_led.class_dev)) \
+ led_classdev_unregister(&object##_led)
+
+static void asus_led_exit(void)
+{
+ ASUS_LED_UNREGISTER(mled);
+ ASUS_LED_UNREGISTER(tled);
+ ASUS_LED_UNREGISTER(pled);
+ ASUS_LED_UNREGISTER(rled);
+
+ destroy_workqueue(led_workqueue);
+}
+
+static void __exit asus_laptop_exit(void)
+{
+ asus_backlight_exit();
+ asus_led_exit();
+
+ 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);
+}
+
+static int asus_backlight_init(struct device *dev)
+{
+ struct backlight_device *bd;
+
+ if (brightness_set_handle && lcd_switch_handle) {
+ bd = backlight_device_register(ASUS_HOTK_FILE, dev,
+ NULL, &asusbl_ops);
+ if (IS_ERR(bd)) {
+ printk(ASUS_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.brightness = read_brightness(NULL);
+ bd->props.power = FB_BLANK_UNBLANK;
+ backlight_update_status(bd);
+ }
+ return 0;
+}
+
+static int asus_led_register(acpi_handle handle,
+ struct led_classdev *ldev, struct device *dev)
+{
+ if (!handle)
+ return 0;
+
+ return led_classdev_register(dev, ldev);
+}
+
+#define ASUS_LED_REGISTER(object, device) \
+ asus_led_register(object##_set_handle, &object##_led, device)
+
+static int asus_led_init(struct device *dev)
+{
+ int rv;
+
+ rv = ASUS_LED_REGISTER(mled, dev);
+ if (rv)
+ return rv;
+
+ rv = ASUS_LED_REGISTER(tled, dev);
+ if (rv)
+ return rv;
+
+ rv = ASUS_LED_REGISTER(rled, dev);
+ if (rv)
+ return rv;
+
+ rv = ASUS_LED_REGISTER(pled, dev);
+ if (rv)
+ return rv;
+
+ led_workqueue = create_singlethread_workqueue("led_workqueue");
+ if (!led_workqueue)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int __init asus_laptop_init(void)
+{
+ struct device *dev;
+ int result;
+
+ if (acpi_disabled)
+ return -ENODEV;
+
+ result = acpi_bus_register_driver(&asus_hotk_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;
+ }
+
+ dev = acpi_get_physical_device(hotk->device->handle);
+
+ result = asus_backlight_init(dev);
+ if (result)
+ goto fail_backlight;
+
+ result = asus_led_init(dev);
+ if (result)
+ goto fail_led;
+
+ /* 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 = 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;
+
+ return 0;
+
+ 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_led_exit();
+
+ fail_led:
+ asus_backlight_exit();
+
+ fail_backlight:
+
+ return result;
+}
+
+module_init(asus_laptop_init);
+module_exit(asus_laptop_exit);
diff --git a/drivers/misc/hdpuftrs/hdpu_cpustate.c b/drivers/misc/hdpuftrs/hdpu_cpustate.c
index 11a801be71c..ca86f113f36 100644
--- a/drivers/misc/hdpuftrs/hdpu_cpustate.c
+++ b/drivers/misc/hdpuftrs/hdpu_cpustate.c
@@ -169,7 +169,7 @@ static struct platform_driver hdpu_cpustate_driver = {
/*
* The various file operations we support.
*/
-static struct file_operations cpustate_fops = {
+static const struct file_operations cpustate_fops = {
owner:THIS_MODULE,
open:cpustate_open,
release:cpustate_release,
diff --git a/drivers/misc/hdpuftrs/hdpu_nexus.c b/drivers/misc/hdpuftrs/hdpu_nexus.c
index ea9d5f233c8..6a51e99a807 100644
--- a/drivers/misc/hdpuftrs/hdpu_nexus.c
+++ b/drivers/misc/hdpuftrs/hdpu_nexus.c
@@ -72,11 +72,9 @@ static int hdpu_nexus_probe(struct platform_device *pdev)
printk("Could not map slot id\n");
hdpu_slot_id = create_proc_entry("sky_slot_id", 0666, &proc_root);
hdpu_slot_id->read_proc = hdpu_slot_id_read;
- hdpu_slot_id->nlink = 1;
hdpu_chassis_id = create_proc_entry("sky_chassis_id", 0666, &proc_root);
hdpu_chassis_id->read_proc = hdpu_chassis_id_read;
- hdpu_chassis_id->nlink = 1;
return 0;
}
diff --git a/drivers/misc/ibmasm/ibmasmfs.c b/drivers/misc/ibmasm/ibmasmfs.c
index b99dc507de2..c436d3de8b8 100644
--- a/drivers/misc/ibmasm/ibmasmfs.c
+++ b/drivers/misc/ibmasm/ibmasmfs.c
@@ -156,7 +156,7 @@ static struct inode *ibmasmfs_make_inode(struct super_block *sb, int mode)
static struct dentry *ibmasmfs_create_file (struct super_block *sb,
struct dentry *parent,
const char *name,
- struct file_operations *fops,
+ const struct file_operations *fops,
void *data,
int mode)
{
@@ -581,28 +581,28 @@ static ssize_t remote_settings_file_write(struct file *file, const char __user *
return count;
}
-static struct file_operations command_fops = {
+static const struct file_operations command_fops = {
.open = command_file_open,
.release = command_file_close,
.read = command_file_read,
.write = command_file_write,
};
-static struct file_operations event_fops = {
+static const struct file_operations event_fops = {
.open = event_file_open,
.release = event_file_close,
.read = event_file_read,
.write = event_file_write,
};
-static struct file_operations r_heartbeat_fops = {
+static const struct file_operations r_heartbeat_fops = {
.open = r_heartbeat_file_open,
.release = r_heartbeat_file_close,
.read = r_heartbeat_file_read,
.write = r_heartbeat_file_write,
};
-static struct file_operations remote_settings_fops = {
+static const struct file_operations remote_settings_fops = {
.open = remote_settings_file_open,
.release = remote_settings_file_close,
.read = remote_settings_file_read,
diff --git a/drivers/misc/ioc4.c b/drivers/misc/ioc4.c
index b995a15b752..6a5a05d1f39 100644
--- a/drivers/misc/ioc4.c
+++ b/drivers/misc/ioc4.c
@@ -309,7 +309,7 @@ ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
ret = -ENODEV;
goto out_pci;
}
- if (!request_region(idd->idd_bar0, sizeof(struct ioc4_misc_regs),
+ if (!request_mem_region(idd->idd_bar0, sizeof(struct ioc4_misc_regs),
"ioc4_misc")) {
printk(KERN_WARNING
"%s: Unable to request IOC4 misc region "
@@ -379,7 +379,7 @@ ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
return 0;
out_misc_region:
- release_region(idd->idd_bar0, sizeof(struct ioc4_misc_regs));
+ release_mem_region(idd->idd_bar0, sizeof(struct ioc4_misc_regs));
out_pci:
kfree(idd);
out_idd:
@@ -418,7 +418,7 @@ ioc4_remove(struct pci_dev *pdev)
"Device removal may be incomplete.\n",
__FUNCTION__, pci_name(idd->idd_pdev));
}
- release_region(idd->idd_bar0, sizeof(struct ioc4_misc_regs));
+ release_mem_region(idd->idd_bar0, sizeof(struct ioc4_misc_regs));
/* Disable IOC4 and relinquish */
pci_disable_device(pdev);
diff --git a/drivers/misc/lkdtm.c b/drivers/misc/lkdtm.c
index db9d7df75ae..552b7957a92 100644
--- a/drivers/misc/lkdtm.c
+++ b/drivers/misc/lkdtm.c
@@ -108,8 +108,8 @@ static struct jprobe lkdtm;
static int lkdtm_parse_commandline(void);
static void lkdtm_handler(void);
-static char* cpoint_name = INVALID;
-static char* cpoint_type = NONE;
+static char* cpoint_name;
+static char* cpoint_type;
static int cpoint_count = DEFAULT_COUNT;
static int recur_count = REC_NUM_DEFAULT;
diff --git a/drivers/misc/msi-laptop.c b/drivers/misc/msi-laptop.c
index 8e5e07e4c1c..68c4b58525b 100644
--- a/drivers/misc/msi-laptop.c
+++ b/drivers/misc/msi-laptop.c
@@ -157,14 +157,12 @@ static int bl_get_brightness(struct backlight_device *b)
static int bl_update_status(struct backlight_device *b)
{
- return set_lcd_level(b->props->brightness);
+ return set_lcd_level(b->props.brightness);
}
-static struct backlight_properties msibl_props = {
- .owner = THIS_MODULE,
+static struct backlight_ops msibl_ops = {
.get_brightness = bl_get_brightness,
.update_status = bl_update_status,
- .max_brightness = MSI_LCD_LEVEL_MAX-1,
};
static struct backlight_device *msibl_device;
@@ -318,10 +316,12 @@ static int __init msi_init(void)
/* Register backlight stuff */
msibl_device = backlight_device_register("msi-laptop-bl", NULL, NULL,
- &msibl_props);
+ &msibl_ops);
if (IS_ERR(msibl_device))
return PTR_ERR(msibl_device);
+ msibl_device->props.max_brightness = MSI_LCD_LEVEL_MAX-1,
+
ret = platform_driver_register(&msipf_driver);
if (ret)
goto fail_backlight;
diff --git a/drivers/misc/sony-laptop.c b/drivers/misc/sony-laptop.c
new file mode 100644
index 00000000000..2ebe240dd53
--- /dev/null
+++ b/drivers/misc/sony-laptop.c
@@ -0,0 +1,564 @@
+/*
+ * ACPI Sony Notebook Control Driver (SNC)
+ *
+ * Copyright (C) 2004-2005 Stelian Pop <stelian@popies.net>
+ * Copyright (C) 2007 Mattia Dongili <malattia@linux.it>
+ *
+ * Parts of this driver inspired from asus_acpi.c and ibm_acpi.c
+ * which are copyrighted by their respective authors.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/backlight.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <acpi/acpi_drivers.h>
+#include <acpi/acpi_bus.h>
+#include <asm/uaccess.h>
+
+#define ACPI_SNC_CLASS "sony"
+#define ACPI_SNC_HID "SNY5001"
+#define ACPI_SNC_DRIVER_NAME "ACPI Sony Notebook Control Driver v0.4"
+
+/* the device uses 1-based values, while the backlight subsystem uses
+ 0-based values */
+#define SONY_MAX_BRIGHTNESS 8
+
+#define LOG_PFX KERN_WARNING "sony-laptop: "
+
+MODULE_AUTHOR("Stelian Pop, Mattia Dongili");
+MODULE_DESCRIPTION(ACPI_SNC_DRIVER_NAME);
+MODULE_LICENSE("GPL");
+
+static int debug;
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "set this to 1 (and RTFM) if you want to help "
+ "the development of this driver");
+
+static ssize_t sony_acpi_show(struct device *, struct device_attribute *,
+ char *);
+static ssize_t sony_acpi_store(struct device *, struct device_attribute *,
+ const char *, size_t);
+static int boolean_validate(const int, const int);
+static int brightness_default_validate(const int, const int);
+
+#define SNC_VALIDATE_IN 0
+#define SNC_VALIDATE_OUT 1
+
+struct sony_acpi_value {
+ char *name; /* name of the entry */
+ char **acpiget; /* names of the ACPI get function */
+ char **acpiset; /* names of the ACPI set function */
+ int (*validate)(const int, const int); /* input/output validation */
+ int value; /* current setting */
+ int valid; /* Has ever been set */
+ int debug; /* active only in debug mode ? */
+ struct device_attribute devattr; /* sysfs atribute */
+};
+
+#define HANDLE_NAMES(_name, _values...) \
+ static char *snc_##_name[] = { _values, NULL }
+
+#define SONY_ACPI_VALUE(_name, _getters, _setters, _validate, _debug) \
+ { \
+ .name = __stringify(_name), \
+ .acpiget = _getters, \
+ .acpiset = _setters, \
+ .validate = _validate, \
+ .debug = _debug, \
+ .devattr = __ATTR(_name, 0, sony_acpi_show, sony_acpi_store), \
+ }
+
+#define SONY_ACPI_VALUE_NULL { .name = NULL }
+
+HANDLE_NAMES(fnkey_get, "GHKE");
+
+HANDLE_NAMES(brightness_def_get, "GPBR");
+HANDLE_NAMES(brightness_def_set, "SPBR");
+
+HANDLE_NAMES(cdpower_get, "GCDP");
+HANDLE_NAMES(cdpower_set, "SCDP", "CDPW");
+
+HANDLE_NAMES(audiopower_get, "GAZP");
+HANDLE_NAMES(audiopower_set, "AZPW");
+
+HANDLE_NAMES(lanpower_get, "GLNP");
+HANDLE_NAMES(lanpower_set, "LNPW");
+
+HANDLE_NAMES(PID_get, "GPID");
+
+HANDLE_NAMES(CTR_get, "GCTR");
+HANDLE_NAMES(CTR_set, "SCTR");
+
+HANDLE_NAMES(PCR_get, "GPCR");
+HANDLE_NAMES(PCR_set, "SPCR");
+
+HANDLE_NAMES(CMI_get, "GCMI");
+HANDLE_NAMES(CMI_set, "SCMI");
+
+static struct sony_acpi_value sony_acpi_values[] = {
+ SONY_ACPI_VALUE(brightness_default, snc_brightness_def_get,
+ snc_brightness_def_set, brightness_default_validate, 0),
+ SONY_ACPI_VALUE(fnkey, snc_fnkey_get, NULL, NULL, 0),
+ SONY_ACPI_VALUE(cdpower, snc_cdpower_get, snc_cdpower_set, boolean_validate, 0),
+ SONY_ACPI_VALUE(audiopower, snc_audiopower_get, snc_audiopower_set,
+ boolean_validate, 0),
+ SONY_ACPI_VALUE(lanpower, snc_lanpower_get, snc_lanpower_set,
+ boolean_validate, 1),
+ /* unknown methods */
+ SONY_ACPI_VALUE(PID, snc_PID_get, NULL, NULL, 1),
+ SONY_ACPI_VALUE(CTR, snc_CTR_get, snc_CTR_set, NULL, 1),
+ SONY_ACPI_VALUE(PCR, snc_PCR_get, snc_PCR_set, NULL, 1),
+ SONY_ACPI_VALUE(CMI, snc_CMI_get, snc_CMI_set, NULL, 1),
+ SONY_ACPI_VALUE_NULL
+};
+
+static acpi_handle sony_acpi_handle;
+static struct acpi_device *sony_acpi_acpi_device = NULL;
+
+/*
+ * acpi_evaluate_object wrappers
+ */
+static int acpi_callgetfunc(acpi_handle handle, char *name, int *result)
+{
+ struct acpi_buffer output;
+ union acpi_object out_obj;
+ acpi_status status;
+
+ output.length = sizeof(out_obj);
+ output.pointer = &out_obj;
+
+ status = acpi_evaluate_object(handle, name, NULL, &output);
+ if ((status == AE_OK) && (out_obj.type == ACPI_TYPE_INTEGER)) {
+ *result = out_obj.integer.value;
+ return 0;
+ }
+
+ printk(LOG_PFX "acpi_callreadfunc failed\n");
+
+ return -1;
+}
+
+static int acpi_callsetfunc(acpi_handle handle, char *name, int value,
+ int *result)
+{
+ struct acpi_object_list params;
+ union acpi_object in_obj;
+ struct acpi_buffer output;
+ union acpi_object out_obj;
+ acpi_status status;
+
+ params.count = 1;
+ params.pointer = &in_obj;
+ in_obj.type = ACPI_TYPE_INTEGER;
+ in_obj.integer.value = value;
+
+ output.length = sizeof(out_obj);
+ output.pointer = &out_obj;
+
+ status = acpi_evaluate_object(handle, name, &params, &output);
+ if (status == AE_OK) {
+ if (result != NULL) {
+ if (out_obj.type != ACPI_TYPE_INTEGER) {
+ printk(LOG_PFX "acpi_evaluate_object bad "
+ "return type\n");
+ return -1;
+ }
+ *result = out_obj.integer.value;
+ }
+ return 0;
+ }
+
+ printk(LOG_PFX "acpi_evaluate_object failed\n");
+
+ return -1;
+}
+
+/*
+ * sony_acpi_values input/output validate functions
+ */
+
+/* brightness_default_validate:
+ *
+ * manipulate input output values to keep consistency with the
+ * backlight framework for which brightness values are 0-based.
+ */
+static int brightness_default_validate(const int direction, const int value)
+{
+ switch (direction) {
+ case SNC_VALIDATE_OUT:
+ return value - 1;
+ case SNC_VALIDATE_IN:
+ if (value >= 0 && value < SONY_MAX_BRIGHTNESS)
+ return value + 1;
+ }
+ return -EINVAL;
+}
+
+/* boolean_validate:
+ *
+ * on input validate boolean values 0/1, on output just pass the
+ * received value.
+ */
+static int boolean_validate(const int direction, const int value)
+{
+ if (direction == SNC_VALIDATE_IN) {
+ if (value != 0 && value != 1)
+ return -EINVAL;
+ }
+ return value;
+}
+
+/*
+ * Sysfs show/store common to all sony_acpi_values
+ */
+static ssize_t sony_acpi_show(struct device *dev, struct device_attribute *attr,
+ char *buffer)
+{
+ int value;
+ struct sony_acpi_value *item =
+ container_of(attr, struct sony_acpi_value, devattr);
+
+ if (!*item->acpiget)
+ return -EIO;
+
+ if (acpi_callgetfunc(sony_acpi_handle, *item->acpiget, &value) < 0)
+ return -EIO;
+
+ if (item->validate)
+ value = item->validate(SNC_VALIDATE_OUT, value);
+
+ return snprintf(buffer, PAGE_SIZE, "%d\n", value);
+}
+
+static ssize_t sony_acpi_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buffer, size_t count)
+{
+ int value;
+ struct sony_acpi_value *item =
+ container_of(attr, struct sony_acpi_value, devattr);
+
+ if (!item->acpiset)
+ return -EIO;
+
+ if (count > 31)
+ return -EINVAL;
+
+ value = simple_strtoul(buffer, NULL, 10);
+
+ if (item->validate)
+ value = item->validate(SNC_VALIDATE_IN, value);
+
+ if (value < 0)
+ return value;
+
+ if (acpi_callsetfunc(sony_acpi_handle, *item->acpiset, value, NULL) < 0)
+ return -EIO;
+ item->value = value;
+ item->valid = 1;
+ return count;
+}
+
+/*
+ * Platform device
+ */
+static struct platform_driver sncpf_driver = {
+ .driver = {
+ .name = "sony-laptop",
+ .owner = THIS_MODULE,
+ }
+};
+static struct platform_device *sncpf_device;
+
+static int sony_snc_pf_add(void)
+{
+ acpi_handle handle;
+ struct sony_acpi_value *item;
+ int ret = 0;
+
+ ret = platform_driver_register(&sncpf_driver);
+ if (ret)
+ goto out;
+
+ sncpf_device = platform_device_alloc("sony-laptop", -1);
+ if (!sncpf_device) {
+ ret = -ENOMEM;
+ goto out_platform_registered;
+ }
+
+ ret = platform_device_add(sncpf_device);
+ if (ret)
+ goto out_platform_alloced;
+
+ for (item = sony_acpi_values; item->name; ++item) {
+
+ if (!debug && item->debug)
+ continue;
+
+ /* find the available acpiget as described in the DSDT */
+ for (; item->acpiget && *item->acpiget; ++item->acpiget) {
+ if (ACPI_SUCCESS(acpi_get_handle(sony_acpi_handle,
+ *item->acpiget,
+ &handle))) {
+ if (debug)
+ printk(LOG_PFX "Found %s getter: %s\n",
+ item->name, *item->acpiget);
+ item->devattr.attr.mode |= S_IRUGO;
+ break;
+ }
+ }
+
+ /* find the available acpiset as described in the DSDT */
+ for (; item->acpiset && *item->acpiset; ++item->acpiset) {
+ if (ACPI_SUCCESS(acpi_get_handle(sony_acpi_handle,
+ *item->acpiset,
+ &handle))) {
+ if (debug)
+ printk(LOG_PFX "Found %s setter: %s\n",
+ item->name, *item->acpiset);
+ item->devattr.attr.mode |= S_IWUSR;
+ break;
+ }
+ }
+
+ if (item->devattr.attr.mode != 0) {
+ ret =
+ device_create_file(&sncpf_device->dev,
+ &item->devattr);
+ if (ret)
+ goto out_sysfs;
+ }
+ }
+
+ return 0;
+
+ out_sysfs:
+ for (item = sony_acpi_values; item->name; ++item) {
+ device_remove_file(&sncpf_device->dev, &item->devattr);
+ }
+ platform_device_del(sncpf_device);
+ out_platform_alloced:
+ platform_device_put(sncpf_device);
+ out_platform_registered:
+ platform_driver_unregister(&sncpf_driver);
+ out:
+ return ret;
+}
+
+static void sony_snc_pf_remove(void)
+{
+ struct sony_acpi_value *item;
+
+ for (item = sony_acpi_values; item->name; ++item) {
+ device_remove_file(&sncpf_device->dev, &item->devattr);
+ }
+
+ platform_device_del(sncpf_device);
+ platform_device_put(sncpf_device);
+ platform_driver_unregister(&sncpf_driver);
+}
+
+/*
+ * Backlight device
+ */
+static int sony_backlight_update_status(struct backlight_device *bd)
+{
+ return acpi_callsetfunc(sony_acpi_handle, "SBRT",
+ bd->props.brightness + 1, NULL);
+}
+
+static int sony_backlight_get_brightness(struct backlight_device *bd)
+{
+ int value;
+
+ if (acpi_callgetfunc(sony_acpi_handle, "GBRT", &value))
+ return 0;
+ /* brightness levels are 1-based, while backlight ones are 0-based */
+ return value - 1;
+}
+
+static struct backlight_device *sony_backlight_device;
+static struct backlight_ops sony_backlight_ops = {
+ .update_status = sony_backlight_update_status,
+ .get_brightness = sony_backlight_get_brightness,
+};
+
+/*
+ * ACPI callbacks
+ */
+static void sony_acpi_notify(acpi_handle handle, u32 event, void *data)
+{
+ if (debug)
+ printk(LOG_PFX "sony_acpi_notify, event: %d\n", event);
+ acpi_bus_generate_event(sony_acpi_acpi_device, 1, event);
+}
+
+static acpi_status sony_walk_callback(acpi_handle handle, u32 level,
+ void *context, void **return_value)
+{
+ struct acpi_namespace_node *node;
+ union acpi_operand_object *operand;
+
+ node = (struct acpi_namespace_node *)handle;
+ operand = (union acpi_operand_object *)node->object;
+
+ printk(LOG_PFX "method: name: %4.4s, args %X\n", node->name.ascii,
+ (u32) operand->method.param_count);
+
+ return AE_OK;
+}
+
+/*
+ * ACPI device
+ */
+static int sony_acpi_resume(struct acpi_device *device)
+{
+ struct sony_acpi_value *item;
+
+ for (item = sony_acpi_values; item->name; item++) {
+ int ret;
+
+ if (!item->valid)
+ continue;
+ ret = acpi_callsetfunc(sony_acpi_handle, *item->acpiset,
+ item->value, NULL);
+ if (ret < 0) {
+ printk("%s: %d\n", __FUNCTION__, ret);
+ break;
+ }
+ }
+ return 0;
+}
+
+static int sony_acpi_add(struct acpi_device *device)
+{
+ acpi_status status;
+ int result;
+ acpi_handle handle;
+
+ sony_acpi_acpi_device = device;
+
+ sony_acpi_handle = device->handle;
+
+ if (debug) {
+ status = acpi_walk_namespace(ACPI_TYPE_METHOD, sony_acpi_handle,
+ 1, sony_walk_callback, NULL, NULL);
+ if (ACPI_FAILURE(status)) {
+ printk(LOG_PFX "unable to walk acpi resources\n");
+ result = -ENODEV;
+ goto outwalk;
+ }
+ }
+
+ status = acpi_install_notify_handler(sony_acpi_handle,
+ ACPI_DEVICE_NOTIFY,
+ sony_acpi_notify, NULL);
+ if (ACPI_FAILURE(status)) {
+ printk(LOG_PFX "unable to install notify handler\n");
+ result = -ENODEV;
+ goto outwalk;
+ }
+
+ if (ACPI_SUCCESS(acpi_get_handle(sony_acpi_handle, "GBRT", &handle))) {
+ sony_backlight_device = backlight_device_register("sony", NULL,
+ NULL,
+ &sony_backlight_ops);
+
+ if (IS_ERR(sony_backlight_device)) {
+ printk(LOG_PFX "unable to register backlight device\n");
+ sony_backlight_device = NULL;
+ } else {
+ sony_backlight_device->props.brightness =
+ sony_backlight_get_brightness
+ (sony_backlight_device);
+ sony_backlight_device->props.max_brightness =
+ SONY_MAX_BRIGHTNESS - 1;
+ }
+
+ }
+
+ if (sony_snc_pf_add())
+ goto outbacklight;
+
+ printk(KERN_INFO ACPI_SNC_DRIVER_NAME " successfully installed\n");
+
+ return 0;
+
+ outbacklight:
+ if (sony_backlight_device)
+ backlight_device_unregister(sony_backlight_device);
+
+ status = acpi_remove_notify_handler(sony_acpi_handle,
+ ACPI_DEVICE_NOTIFY,
+ sony_acpi_notify);
+ if (ACPI_FAILURE(status))
+ printk(LOG_PFX "unable to remove notify handler\n");
+ outwalk:
+ return result;
+}
+
+static int sony_acpi_remove(struct acpi_device *device, int type)
+{
+ acpi_status status;
+
+ if (sony_backlight_device)
+ backlight_device_unregister(sony_backlight_device);
+
+ sony_acpi_acpi_device = NULL;
+
+ status = acpi_remove_notify_handler(sony_acpi_handle,
+ ACPI_DEVICE_NOTIFY,
+ sony_acpi_notify);
+ if (ACPI_FAILURE(status))
+ printk(LOG_PFX "unable to remove notify handler\n");
+
+ sony_snc_pf_remove();
+
+ printk(KERN_INFO ACPI_SNC_DRIVER_NAME " successfully removed\n");
+
+ return 0;
+}
+
+static struct acpi_driver sony_acpi_driver = {
+ .name = ACPI_SNC_DRIVER_NAME,
+ .class = ACPI_SNC_CLASS,
+ .ids = ACPI_SNC_HID,
+ .ops = {
+ .add = sony_acpi_add,
+ .remove = sony_acpi_remove,
+ .resume = sony_acpi_resume,
+ },
+};
+
+static int __init sony_acpi_init(void)
+{
+ return acpi_bus_register_driver(&sony_acpi_driver);
+}
+
+static void __exit sony_acpi_exit(void)
+{
+ acpi_bus_unregister_driver(&sony_acpi_driver);
+}
+
+module_init(sony_acpi_init);
+module_exit(sony_acpi_exit);
diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c
index 2ab7add78f9..bc60e2fc3c2 100644
--- a/drivers/misc/tifm_7xx1.c
+++ b/drivers/misc/tifm_7xx1.c
@@ -11,66 +11,25 @@
#include <linux/tifm.h>
#include <linux/dma-mapping.h>
+#include <linux/freezer.h>
#define DRIVER_NAME "tifm_7xx1"
-#define DRIVER_VERSION "0.6"
+#define DRIVER_VERSION "0.7"
static void tifm_7xx1_eject(struct tifm_adapter *fm, struct tifm_dev *sock)
{
- int cnt;
- unsigned long flags;
-
- spin_lock_irqsave(&fm->lock, flags);
- if (!fm->inhibit_new_cards) {
- for (cnt = 0; cnt < fm->max_sockets; cnt++) {
- if (fm->sockets[cnt] == sock) {
- fm->remove_mask |= (1 << cnt);
- queue_work(fm->wq, &fm->media_remover);
- break;
- }
- }
- }
- spin_unlock_irqrestore(&fm->lock, flags);
-}
-
-static void tifm_7xx1_remove_media(struct work_struct *work)
-{
- struct tifm_adapter *fm =
- container_of(work, struct tifm_adapter, media_remover);
unsigned long flags;
- int cnt;
- struct tifm_dev *sock;
- if (!class_device_get(&fm->cdev))
- return;
spin_lock_irqsave(&fm->lock, flags);
- for (cnt = 0; cnt < fm->max_sockets; cnt++) {
- if (fm->sockets[cnt] && (fm->remove_mask & (1 << cnt))) {
- printk(KERN_INFO DRIVER_NAME
- ": demand removing card from socket %d\n", cnt);
- sock = fm->sockets[cnt];
- fm->sockets[cnt] = NULL;
- fm->remove_mask &= ~(1 << cnt);
-
- writel(0x0e00, sock->addr + SOCK_CONTROL);
-
- writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt,
- fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
- writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt,
- fm->addr + FM_SET_INTERRUPT_ENABLE);
-
- spin_unlock_irqrestore(&fm->lock, flags);
- device_unregister(&sock->dev);
- spin_lock_irqsave(&fm->lock, flags);
- }
- }
+ fm->socket_change_set |= 1 << sock->socket_id;
+ wake_up_all(&fm->change_set_notify);
spin_unlock_irqrestore(&fm->lock, flags);
- class_device_put(&fm->cdev);
}
static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id)
{
struct tifm_adapter *fm = dev_id;
+ struct tifm_dev *sock;
unsigned int irq_status;
unsigned int sock_irq_status, cnt;
@@ -84,42 +43,32 @@ static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id)
if (irq_status & TIFM_IRQ_ENABLE) {
writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
- for (cnt = 0; cnt < fm->max_sockets; cnt++) {
- sock_irq_status = (irq_status >> cnt) &
- (TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK);
-
- if (fm->sockets[cnt]) {
- if (sock_irq_status &&
- fm->sockets[cnt]->signal_irq)
- sock_irq_status = fm->sockets[cnt]->
- signal_irq(fm->sockets[cnt],
- sock_irq_status);
+ for (cnt = 0; cnt < fm->num_sockets; cnt++) {
+ sock = fm->sockets[cnt];
+ sock_irq_status = (irq_status >> cnt)
+ & (TIFM_IRQ_FIFOMASK(1)
+ | TIFM_IRQ_CARDMASK(1));
- if (irq_status & (1 << cnt))
- fm->remove_mask |= 1 << cnt;
- } else {
- if (irq_status & (1 << cnt))
- fm->insert_mask |= 1 << cnt;
- }
+ if (sock && sock_irq_status)
+ sock->signal_irq(sock, sock_irq_status);
}
+
+ fm->socket_change_set |= irq_status
+ & ((1 << fm->num_sockets) - 1);
}
writel(irq_status, fm->addr + FM_INTERRUPT_STATUS);
- if (!fm->inhibit_new_cards) {
- if (!fm->remove_mask && !fm->insert_mask) {
- writel(TIFM_IRQ_ENABLE,
- fm->addr + FM_SET_INTERRUPT_ENABLE);
- } else {
- queue_work(fm->wq, &fm->media_remover);
- queue_work(fm->wq, &fm->media_inserter);
- }
- }
+ if (!fm->socket_change_set)
+ writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE);
+ else
+ wake_up_all(&fm->change_set_notify);
spin_unlock(&fm->lock);
return IRQ_HANDLED;
}
-static tifm_media_id tifm_7xx1_toggle_sock_power(char __iomem *sock_addr, int is_x2)
+static tifm_media_id tifm_7xx1_toggle_sock_power(char __iomem *sock_addr,
+ int is_x2)
{
unsigned int s_state;
int cnt;
@@ -127,8 +76,8 @@ static tifm_media_id tifm_7xx1_toggle_sock_power(char __iomem *sock_addr, int is
writel(0x0e00, sock_addr + SOCK_CONTROL);
for (cnt = 0; cnt < 100; cnt++) {
- if (!(TIFM_SOCK_STATE_POWERED &
- readl(sock_addr + SOCK_PRESENT_STATE)))
+ if (!(TIFM_SOCK_STATE_POWERED
+ & readl(sock_addr + SOCK_PRESENT_STATE)))
break;
msleep(10);
}
@@ -151,8 +100,8 @@ static tifm_media_id tifm_7xx1_toggle_sock_power(char __iomem *sock_addr, int is
}
for (cnt = 0; cnt < 100; cnt++) {
- if ((TIFM_SOCK_STATE_POWERED &
- readl(sock_addr + SOCK_PRESENT_STATE)))
+ if ((TIFM_SOCK_STATE_POWERED
+ & readl(sock_addr + SOCK_PRESENT_STATE)))
break;
msleep(10);
}
@@ -170,130 +119,209 @@ tifm_7xx1_sock_addr(char __iomem *base_addr, unsigned int sock_num)
return base_addr + ((sock_num + 1) << 10);
}
-static void tifm_7xx1_insert_media(struct work_struct *work)
+static int tifm_7xx1_switch_media(void *data)
{
- struct tifm_adapter *fm =
- container_of(work, struct tifm_adapter, media_inserter);
+ struct tifm_adapter *fm = data;
unsigned long flags;
tifm_media_id media_id;
char *card_name = "xx";
- int cnt, ok_to_register;
- unsigned int insert_mask;
- struct tifm_dev *new_sock = NULL;
+ int cnt, rc;
+ struct tifm_dev *sock;
+ unsigned int socket_change_set;
- if (!class_device_get(&fm->cdev))
- return;
- spin_lock_irqsave(&fm->lock, flags);
- insert_mask = fm->insert_mask;
- fm->insert_mask = 0;
- if (fm->inhibit_new_cards) {
+ while (1) {
+ rc = wait_event_interruptible(fm->change_set_notify,
+ fm->socket_change_set);
+ if (rc == -ERESTARTSYS)
+ try_to_freeze();
+
+ spin_lock_irqsave(&fm->lock, flags);
+ socket_change_set = fm->socket_change_set;
+ fm->socket_change_set = 0;
+
+ dev_dbg(fm->dev, "checking media set %x\n",
+ socket_change_set);
+
+ if (kthread_should_stop())
+ socket_change_set = (1 << fm->num_sockets) - 1;
spin_unlock_irqrestore(&fm->lock, flags);
- class_device_put(&fm->cdev);
- return;
- }
- spin_unlock_irqrestore(&fm->lock, flags);
- for (cnt = 0; cnt < fm->max_sockets; cnt++) {
- if (!(insert_mask & (1 << cnt)))
+ if (!socket_change_set)
continue;
- media_id = tifm_7xx1_toggle_sock_power(tifm_7xx1_sock_addr(fm->addr, cnt),
- fm->max_sockets == 2);
- if (media_id) {
- ok_to_register = 0;
- new_sock = tifm_alloc_device(fm, cnt);
- if (new_sock) {
- new_sock->addr = tifm_7xx1_sock_addr(fm->addr,
- cnt);
- new_sock->media_id = media_id;
- switch (media_id) {
- case 1:
- card_name = "xd";
- break;
- case 2:
- card_name = "ms";
- break;
- case 3:
- card_name = "sd";
- break;
- default:
- break;
- }
- snprintf(new_sock->dev.bus_id, BUS_ID_SIZE,
- "tifm_%s%u:%u", card_name, fm->id, cnt);
+ spin_lock_irqsave(&fm->lock, flags);
+ for (cnt = 0; cnt < fm->num_sockets; cnt++) {
+ if (!(socket_change_set & (1 << cnt)))
+ continue;
+ sock = fm->sockets[cnt];
+ if (sock) {
printk(KERN_INFO DRIVER_NAME
- ": %s card detected in socket %d\n",
- card_name, cnt);
+ ": demand removing card from socket %d\n",
+ cnt);
+ fm->sockets[cnt] = NULL;
+ spin_unlock_irqrestore(&fm->lock, flags);
+ device_unregister(&sock->dev);
spin_lock_irqsave(&fm->lock, flags);
- if (!fm->sockets[cnt]) {
- fm->sockets[cnt] = new_sock;
- ok_to_register = 1;
+ writel(0x0e00,
+ tifm_7xx1_sock_addr(fm->addr, cnt)
+ + SOCK_CONTROL);
+ }
+ if (kthread_should_stop())
+ continue;
+
+ spin_unlock_irqrestore(&fm->lock, flags);
+ media_id = tifm_7xx1_toggle_sock_power(
+ tifm_7xx1_sock_addr(fm->addr, cnt),
+ fm->num_sockets == 2);
+ if (media_id) {
+ sock = tifm_alloc_device(fm);
+ if (sock) {
+ sock->addr = tifm_7xx1_sock_addr(fm->addr,
+ cnt);
+ sock->media_id = media_id;
+ sock->socket_id = cnt;
+ switch (media_id) {
+ case 1:
+ card_name = "xd";
+ break;
+ case 2:
+ card_name = "ms";
+ break;
+ case 3:
+ card_name = "sd";
+ break;
+ default:
+ tifm_free_device(&sock->dev);
+ spin_lock_irqsave(&fm->lock, flags);
+ continue;
+ }
+ snprintf(sock->dev.bus_id, BUS_ID_SIZE,
+ "tifm_%s%u:%u", card_name,
+ fm->id, cnt);
+ printk(KERN_INFO DRIVER_NAME
+ ": %s card detected in socket %d\n",
+ card_name, cnt);
+ if (!device_register(&sock->dev)) {
+ spin_lock_irqsave(&fm->lock, flags);
+ if (!fm->sockets[cnt]) {
+ fm->sockets[cnt] = sock;
+ sock = NULL;
+ }
+ spin_unlock_irqrestore(&fm->lock, flags);
+ }
+ if (sock)
+ tifm_free_device(&sock->dev);
}
+ spin_lock_irqsave(&fm->lock, flags);
+ }
+ }
+
+ if (!kthread_should_stop()) {
+ writel(TIFM_IRQ_FIFOMASK(socket_change_set)
+ | TIFM_IRQ_CARDMASK(socket_change_set),
+ fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
+ writel(TIFM_IRQ_FIFOMASK(socket_change_set)
+ | TIFM_IRQ_CARDMASK(socket_change_set),
+ fm->addr + FM_SET_INTERRUPT_ENABLE);
+ writel(TIFM_IRQ_ENABLE,
+ fm->addr + FM_SET_INTERRUPT_ENABLE);
+ spin_unlock_irqrestore(&fm->lock, flags);
+ } else {
+ for (cnt = 0; cnt < fm->num_sockets; cnt++) {
+ if (fm->sockets[cnt])
+ fm->socket_change_set |= 1 << cnt;
+ }
+ if (!fm->socket_change_set) {
+ spin_unlock_irqrestore(&fm->lock, flags);
+ return 0;
+ } else {
spin_unlock_irqrestore(&fm->lock, flags);
- if (!ok_to_register ||
- device_register(&new_sock->dev)) {
- spin_lock_irqsave(&fm->lock, flags);
- fm->sockets[cnt] = NULL;
- spin_unlock_irqrestore(&fm->lock,
- flags);
- tifm_free_device(&new_sock->dev);
- }
}
}
- writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt,
- fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
- writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt,
- fm->addr + FM_SET_INTERRUPT_ENABLE);
}
-
- writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE);
- class_device_put(&fm->cdev);
+ return 0;
}
+#ifdef CONFIG_PM
+
static int tifm_7xx1_suspend(struct pci_dev *dev, pm_message_t state)
{
- struct tifm_adapter *fm = pci_get_drvdata(dev);
- unsigned long flags;
+ dev_dbg(&dev->dev, "suspending host\n");
- spin_lock_irqsave(&fm->lock, flags);
- fm->inhibit_new_cards = 1;
- fm->remove_mask = 0xf;
- fm->insert_mask = 0;
- writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
- spin_unlock_irqrestore(&fm->lock, flags);
- flush_workqueue(fm->wq);
-
- tifm_7xx1_remove_media(&fm->media_remover);
-
- pci_set_power_state(dev, PCI_D3hot);
- pci_disable_device(dev);
- pci_save_state(dev);
+ pci_save_state(dev);
+ pci_enable_wake(dev, pci_choose_state(dev, state), 0);
+ pci_disable_device(dev);
+ pci_set_power_state(dev, pci_choose_state(dev, state));
return 0;
}
static int tifm_7xx1_resume(struct pci_dev *dev)
{
struct tifm_adapter *fm = pci_get_drvdata(dev);
+ int cnt, rc;
unsigned long flags;
+ tifm_media_id new_ids[fm->num_sockets];
+ pci_set_power_state(dev, PCI_D0);
pci_restore_state(dev);
- pci_enable_device(dev);
- pci_set_power_state(dev, PCI_D0);
- pci_set_master(dev);
+ rc = pci_enable_device(dev);
+ if (rc)
+ return rc;
+ pci_set_master(dev);
+ dev_dbg(&dev->dev, "resuming host\n");
+
+ for (cnt = 0; cnt < fm->num_sockets; cnt++)
+ new_ids[cnt] = tifm_7xx1_toggle_sock_power(
+ tifm_7xx1_sock_addr(fm->addr, cnt),
+ fm->num_sockets == 2);
spin_lock_irqsave(&fm->lock, flags);
- fm->inhibit_new_cards = 0;
- writel(TIFM_IRQ_SETALL, fm->addr + FM_INTERRUPT_STATUS);
- writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
- writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SETALLSOCK,
- fm->addr + FM_SET_INTERRUPT_ENABLE);
- fm->insert_mask = 0xf;
+ fm->socket_change_set = 0;
+ for (cnt = 0; cnt < fm->num_sockets; cnt++) {
+ if (fm->sockets[cnt]) {
+ if (fm->sockets[cnt]->media_id == new_ids[cnt])
+ fm->socket_change_set |= 1 << cnt;
+
+ fm->sockets[cnt]->media_id = new_ids[cnt];
+ }
+ }
+
+ writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1),
+ fm->addr + FM_SET_INTERRUPT_ENABLE);
+ if (!fm->socket_change_set) {
+ spin_unlock_irqrestore(&fm->lock, flags);
+ return 0;
+ } else {
+ fm->socket_change_set = 0;
+ spin_unlock_irqrestore(&fm->lock, flags);
+ }
+
+ wait_event_timeout(fm->change_set_notify, fm->socket_change_set, HZ);
+
+ spin_lock_irqsave(&fm->lock, flags);
+ writel(TIFM_IRQ_FIFOMASK(fm->socket_change_set)
+ | TIFM_IRQ_CARDMASK(fm->socket_change_set),
+ fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
+ writel(TIFM_IRQ_FIFOMASK(fm->socket_change_set)
+ | TIFM_IRQ_CARDMASK(fm->socket_change_set),
+ fm->addr + FM_SET_INTERRUPT_ENABLE);
+ writel(TIFM_IRQ_ENABLE,
+ fm->addr + FM_SET_INTERRUPT_ENABLE);
+ fm->socket_change_set = 0;
+
spin_unlock_irqrestore(&fm->lock, flags);
return 0;
}
+#else
+
+#define tifm_7xx1_suspend NULL
+#define tifm_7xx1_resume NULL
+
+#endif /* CONFIG_PM */
+
static int tifm_7xx1_probe(struct pci_dev *dev,
- const struct pci_device_id *dev_id)
+ const struct pci_device_id *dev_id)
{
struct tifm_adapter *fm;
int pci_dev_busy = 0;
@@ -324,36 +352,34 @@ static int tifm_7xx1_probe(struct pci_dev *dev,
}
fm->dev = &dev->dev;
- fm->max_sockets = (dev->device == 0x803B) ? 2 : 4;
- fm->sockets = kzalloc(sizeof(struct tifm_dev*) * fm->max_sockets,
- GFP_KERNEL);
+ fm->num_sockets = (dev->device == PCI_DEVICE_ID_TI_XX21_XX11_FM)
+ ? 4 : 2;
+ fm->sockets = kzalloc(sizeof(struct tifm_dev*) * fm->num_sockets,
+ GFP_KERNEL);
if (!fm->sockets)
goto err_out_free;
- INIT_WORK(&fm->media_inserter, tifm_7xx1_insert_media);
- INIT_WORK(&fm->media_remover, tifm_7xx1_remove_media);
fm->eject = tifm_7xx1_eject;
pci_set_drvdata(dev, fm);
fm->addr = ioremap(pci_resource_start(dev, 0),
- pci_resource_len(dev, 0));
+ pci_resource_len(dev, 0));
if (!fm->addr)
goto err_out_free;
- rc = request_irq(dev->irq, tifm_7xx1_isr, SA_SHIRQ, DRIVER_NAME, fm);
+ rc = request_irq(dev->irq, tifm_7xx1_isr, IRQF_SHARED, DRIVER_NAME, fm);
if (rc)
goto err_out_unmap;
- rc = tifm_add_adapter(fm);
+ init_waitqueue_head(&fm->change_set_notify);
+ rc = tifm_add_adapter(fm, tifm_7xx1_switch_media);
if (rc)
goto err_out_irq;
writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
- writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SETALLSOCK,
- fm->addr + FM_SET_INTERRUPT_ENABLE);
-
- fm->insert_mask = 0xf;
-
+ writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1),
+ fm->addr + FM_SET_INTERRUPT_ENABLE);
+ wake_up_process(fm->media_switcher);
return 0;
err_out_irq:
@@ -377,19 +403,15 @@ static void tifm_7xx1_remove(struct pci_dev *dev)
struct tifm_adapter *fm = pci_get_drvdata(dev);
unsigned long flags;
+ writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
+ mmiowb();
+ free_irq(dev->irq, fm);
+
spin_lock_irqsave(&fm->lock, flags);
- fm->inhibit_new_cards = 1;
- fm->remove_mask = 0xf;
- fm->insert_mask = 0;
- writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
+ fm->socket_change_set = (1 << fm->num_sockets) - 1;
spin_unlock_irqrestore(&fm->lock, flags);
- flush_workqueue(fm->wq);
-
- tifm_7xx1_remove_media(&fm->media_remover);
-
- writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
- free_irq(dev->irq, fm);
+ kthread_stop(fm->media_switcher);
tifm_remove_adapter(fm);
@@ -404,10 +426,12 @@ static void tifm_7xx1_remove(struct pci_dev *dev)
}
static struct pci_device_id tifm_7xx1_pci_tbl [] = {
- { PCI_VENDOR_ID_TI, 0x8033, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- 0 }, /* xx21 - the one I have */
- { PCI_VENDOR_ID_TI, 0x803B, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- 0 }, /* xx12 - should be also supported */
+ { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_XX21_XX11_FM, PCI_ANY_ID,
+ PCI_ANY_ID, 0, 0, 0 }, /* xx21 - the one I have */
+ { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_XX12_FM, PCI_ANY_ID,
+ PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_XX20_FM, PCI_ANY_ID,
+ PCI_ANY_ID, 0, 0, 0 },
{ }
};
diff --git a/drivers/misc/tifm_core.c b/drivers/misc/tifm_core.c
index d61df5c3ac3..6b10ebe9d93 100644
--- a/drivers/misc/tifm_core.c
+++ b/drivers/misc/tifm_core.c
@@ -14,7 +14,7 @@
#include <linux/idr.h>
#define DRIVER_NAME "tifm_core"
-#define DRIVER_VERSION "0.6"
+#define DRIVER_VERSION "0.7"
static DEFINE_IDR(tifm_adapter_idr);
static DEFINE_SPINLOCK(tifm_adapter_lock);
@@ -60,10 +60,41 @@ static int tifm_uevent(struct device *dev, char **envp, int num_envp,
return 0;
}
+#ifdef CONFIG_PM
+
+static int tifm_device_suspend(struct device *dev, pm_message_t state)
+{
+ struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev);
+ struct tifm_driver *drv = fm_dev->drv;
+
+ if (drv && drv->suspend)
+ return drv->suspend(fm_dev, state);
+ return 0;
+}
+
+static int tifm_device_resume(struct device *dev)
+{
+ struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev);
+ struct tifm_driver *drv = fm_dev->drv;
+
+ if (drv && drv->resume)
+ return drv->resume(fm_dev);
+ return 0;
+}
+
+#else
+
+#define tifm_device_suspend NULL
+#define tifm_device_resume NULL
+
+#endif /* CONFIG_PM */
+
static struct bus_type tifm_bus_type = {
.name = "tifm",
.match = tifm_match,
.uevent = tifm_uevent,
+ .suspend = tifm_device_suspend,
+ .resume = tifm_device_resume
};
static void tifm_free(struct class_device *cdev)
@@ -71,8 +102,6 @@ static void tifm_free(struct class_device *cdev)
struct tifm_adapter *fm = container_of(cdev, struct tifm_adapter, cdev);
kfree(fm->sockets);
- if (fm->wq)
- destroy_workqueue(fm->wq);
kfree(fm);
}
@@ -101,7 +130,8 @@ void tifm_free_adapter(struct tifm_adapter *fm)
}
EXPORT_SYMBOL(tifm_free_adapter);
-int tifm_add_adapter(struct tifm_adapter *fm)
+int tifm_add_adapter(struct tifm_adapter *fm,
+ int (*mediathreadfn)(void *data))
{
int rc;
@@ -113,10 +143,10 @@ int tifm_add_adapter(struct tifm_adapter *fm)
spin_unlock(&tifm_adapter_lock);
if (!rc) {
snprintf(fm->cdev.class_id, BUS_ID_SIZE, "tifm%u", fm->id);
- strncpy(fm->wq_name, fm->cdev.class_id, KOBJ_NAME_LEN);
+ fm->media_switcher = kthread_create(mediathreadfn,
+ fm, "tifm/%u", fm->id);
- fm->wq = create_singlethread_workqueue(fm->wq_name);
- if (fm->wq)
+ if (!IS_ERR(fm->media_switcher))
return class_device_add(&fm->cdev);
spin_lock(&tifm_adapter_lock);
@@ -141,27 +171,27 @@ EXPORT_SYMBOL(tifm_remove_adapter);
void tifm_free_device(struct device *dev)
{
struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev);
- if (fm_dev->wq)
- destroy_workqueue(fm_dev->wq);
kfree(fm_dev);
}
EXPORT_SYMBOL(tifm_free_device);
-struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm, unsigned int id)
+static void tifm_dummy_signal_irq(struct tifm_dev *sock,
+ unsigned int sock_irq_status)
+{
+ return;
+}
+
+struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm)
{
struct tifm_dev *dev = kzalloc(sizeof(struct tifm_dev), GFP_KERNEL);
if (dev) {
spin_lock_init(&dev->lock);
- snprintf(dev->wq_name, KOBJ_NAME_LEN, "tifm%u:%u", fm->id, id);
- dev->wq = create_singlethread_workqueue(dev->wq_name);
- if (!dev->wq) {
- kfree(dev);
- return NULL;
- }
+
dev->dev.parent = fm->dev;
dev->dev.bus = &tifm_bus_type;
dev->dev.release = tifm_free_device;
+ dev->signal_irq = tifm_dummy_signal_irq;
}
return dev;
}
@@ -219,6 +249,7 @@ static int tifm_device_remove(struct device *dev)
struct tifm_driver *drv = fm_dev->drv;
if (drv) {
+ fm_dev->signal_irq = tifm_dummy_signal_irq;
if (drv->remove)
drv->remove(fm_dev);
fm_dev->drv = NULL;
@@ -233,6 +264,8 @@ int tifm_register_driver(struct tifm_driver *drv)
drv->driver.bus = &tifm_bus_type;
drv->driver.probe = tifm_device_probe;
drv->driver.remove = tifm_device_remove;
+ drv->driver.suspend = tifm_device_suspend;
+ drv->driver.resume = tifm_device_resume;
return driver_register(&drv->driver);
}
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index 4224686fdf2..12af9c71876 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -111,7 +111,7 @@ config MMC_IMX
config MMC_TIFM_SD
tristate "TI Flash Media MMC/SD Interface support (EXPERIMENTAL)"
- depends on MMC && EXPERIMENTAL
+ depends on MMC && EXPERIMENTAL && PCI
select TIFM_CORE
help
Say Y here if you want to be able to access MMC/SD cards with
diff --git a/drivers/mmc/at91_mci.c b/drivers/mmc/at91_mci.c
index aa152f31851..459f4b4fede 100644
--- a/drivers/mmc/at91_mci.c
+++ b/drivers/mmc/at91_mci.c
@@ -64,6 +64,7 @@
#include <linux/err.h>
#include <linux/dma-mapping.h>
#include <linux/clk.h>
+#include <linux/atmel_pdc.h>
#include <linux/mmc/host.h>
#include <linux/mmc/protocol.h>
@@ -75,7 +76,6 @@
#include <asm/arch/cpu.h>
#include <asm/arch/gpio.h>
#include <asm/arch/at91_mci.h>
-#include <asm/arch/at91_pdc.h>
#define DRIVER_NAME "at91_mci"
@@ -211,13 +211,13 @@ static void at91mci_pre_dma_read(struct at91mci_host *host)
/* Check to see if this needs filling */
if (i == 0) {
- if (at91_mci_read(host, AT91_PDC_RCR) != 0) {
+ if (at91_mci_read(host, ATMEL_PDC_RCR) != 0) {
pr_debug("Transfer active in current\n");
continue;
}
}
else {
- if (at91_mci_read(host, AT91_PDC_RNCR) != 0) {
+ if (at91_mci_read(host, ATMEL_PDC_RNCR) != 0) {
pr_debug("Transfer active in next\n");
continue;
}
@@ -234,12 +234,12 @@ static void at91mci_pre_dma_read(struct at91mci_host *host)
pr_debug("dma address = %08X, length = %d\n", sg->dma_address, sg->length);
if (i == 0) {
- at91_mci_write(host, AT91_PDC_RPR, sg->dma_address);
- at91_mci_write(host, AT91_PDC_RCR, sg->length / 4);
+ at91_mci_write(host, ATMEL_PDC_RPR, sg->dma_address);
+ at91_mci_write(host, ATMEL_PDC_RCR, sg->length / 4);
}
else {
- at91_mci_write(host, AT91_PDC_RNPR, sg->dma_address);
- at91_mci_write(host, AT91_PDC_RNCR, sg->length / 4);
+ at91_mci_write(host, ATMEL_PDC_RNPR, sg->dma_address);
+ at91_mci_write(host, ATMEL_PDC_RNCR, sg->length / 4);
}
}
@@ -303,7 +303,7 @@ static void at91mci_post_dma_read(struct at91mci_host *host)
at91mci_pre_dma_read(host);
else {
at91_mci_write(host, AT91_MCI_IER, AT91_MCI_RXBUFF);
- at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_PDC_TXTDIS);
+ at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS);
}
pr_debug("post dma read done\n");
@@ -320,7 +320,7 @@ static void at91_mci_handle_transmitted(struct at91mci_host *host)
pr_debug("Handling the transmit\n");
/* Disable the transfer */
- at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_PDC_TXTDIS);
+ at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS);
/* Now wait for cmd ready */
at91_mci_write(host, AT91_MCI_IDR, AT91_MCI_TXBUFE);
@@ -431,15 +431,15 @@ static unsigned int at91_mci_send_command(struct at91mci_host *host, struct mmc_
cmd->opcode, cmdr, cmd->arg, blocks, block_length, at91_mci_read(host, AT91_MCI_MR));
if (!data) {
- at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_TXTDIS | AT91_PDC_RXTDIS);
- at91_mci_write(host, AT91_PDC_RPR, 0);
- at91_mci_write(host, AT91_PDC_RCR, 0);
- at91_mci_write(host, AT91_PDC_RNPR, 0);
- at91_mci_write(host, AT91_PDC_RNCR, 0);
- at91_mci_write(host, AT91_PDC_TPR, 0);
- at91_mci_write(host, AT91_PDC_TCR, 0);
- at91_mci_write(host, AT91_PDC_TNPR, 0);
- at91_mci_write(host, AT91_PDC_TNCR, 0);
+ at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_TXTDIS | ATMEL_PDC_RXTDIS);
+ at91_mci_write(host, ATMEL_PDC_RPR, 0);
+ at91_mci_write(host, ATMEL_PDC_RCR, 0);
+ at91_mci_write(host, ATMEL_PDC_RNPR, 0);
+ at91_mci_write(host, ATMEL_PDC_RNCR, 0);
+ at91_mci_write(host, ATMEL_PDC_TPR, 0);
+ at91_mci_write(host, ATMEL_PDC_TCR, 0);
+ at91_mci_write(host, ATMEL_PDC_TNPR, 0);
+ at91_mci_write(host, ATMEL_PDC_TNCR, 0);
at91_mci_write(host, AT91_MCI_ARGR, cmd->arg);
at91_mci_write(host, AT91_MCI_CMDR, cmdr);
@@ -452,7 +452,7 @@ static unsigned int at91_mci_send_command(struct at91mci_host *host, struct mmc_
/*
* Disable the PDC controller
*/
- at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_PDC_TXTDIS);
+ at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS);
if (cmdr & AT91_MCI_TRCMD_START) {
data->bytes_xfered = 0;
@@ -481,8 +481,8 @@ static unsigned int at91_mci_send_command(struct at91mci_host *host, struct mmc_
pr_debug("Transmitting %d bytes\n", host->total_length);
- at91_mci_write(host, AT91_PDC_TPR, host->physical_address);
- at91_mci_write(host, AT91_PDC_TCR, host->total_length / 4);
+ at91_mci_write(host, ATMEL_PDC_TPR, host->physical_address);
+ at91_mci_write(host, ATMEL_PDC_TCR, host->total_length / 4);
ier = AT91_MCI_TXBUFE;
}
}
@@ -497,9 +497,9 @@ static unsigned int at91_mci_send_command(struct at91mci_host *host, struct mmc_
if (cmdr & AT91_MCI_TRCMD_START) {
if (cmdr & AT91_MCI_TRDIR)
- at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_RXTEN);
+ at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTEN);
else
- at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_TXTEN);
+ at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN);
}
return ier;
}
@@ -823,6 +823,9 @@ static int __init at91_mci_probe(struct platform_device *pdev)
mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
mmc->caps = MMC_CAP_BYTEBLOCK;
+ mmc->max_blk_size = 4095;
+ mmc->max_blk_count = mmc->max_req_size;
+
host = mmc_priv(mmc);
host->mmc = mmc;
host->buffer = NULL;
diff --git a/drivers/mmc/au1xmmc.c b/drivers/mmc/au1xmmc.c
index 800527cf40d..b834be261ab 100644
--- a/drivers/mmc/au1xmmc.c
+++ b/drivers/mmc/au1xmmc.c
@@ -152,8 +152,9 @@ static inline int au1xmmc_card_inserted(struct au1xmmc_host *host)
? 1 : 0;
}
-static inline int au1xmmc_card_readonly(struct au1xmmc_host *host)
+static int au1xmmc_card_readonly(struct mmc_host *mmc)
{
+ struct au1xmmc_host *host = mmc_priv(mmc);
return (bcsr->status & au1xmmc_card_table[host->id].wpstatus)
? 1 : 0;
}
@@ -193,6 +194,8 @@ static int au1xmmc_send_command(struct au1xmmc_host *host, int wait,
u32 mmccmd = (cmd->opcode << SD_CMD_CI_SHIFT);
switch (mmc_resp_type(cmd)) {
+ case MMC_RSP_NONE:
+ break;
case MMC_RSP_R1:
mmccmd |= SD_CMD_RT_1;
break;
@@ -205,6 +208,10 @@ static int au1xmmc_send_command(struct au1xmmc_host *host, int wait,
case MMC_RSP_R3:
mmccmd |= SD_CMD_RT_3;
break;
+ default:
+ printk(KERN_INFO "au1xmmc: unhandled response type %02x\n",
+ mmc_resp_type(cmd));
+ return MMC_ERR_INVALID;
}
switch(cmd->opcode) {
@@ -878,6 +885,7 @@ static void au1xmmc_init_dma(struct au1xmmc_host *host)
static const struct mmc_host_ops au1xmmc_ops = {
.request = au1xmmc_request,
.set_ios = au1xmmc_set_ios,
+ .get_ro = au1xmmc_card_readonly,
};
static int __devinit au1xmmc_probe(struct platform_device *pdev)
@@ -914,6 +922,9 @@ static int __devinit au1xmmc_probe(struct platform_device *pdev)
mmc->max_seg_size = AU1XMMC_DESCRIPTOR_SIZE;
mmc->max_phys_segs = AU1XMMC_DESCRIPTOR_COUNT;
+ mmc->max_blk_size = 2048;
+ mmc->max_blk_count = 512;
+
mmc->ocr_avail = AU1XMMC_OCR;
host = mmc_priv(mmc);
diff --git a/drivers/mmc/imxmmc.c b/drivers/mmc/imxmmc.c
index bfb9ff69320..b060d4bfba2 100644
--- a/drivers/mmc/imxmmc.c
+++ b/drivers/mmc/imxmmc.c
@@ -958,8 +958,10 @@ static int imxmci_probe(struct platform_device *pdev)
/* MMC core transfer sizes tunable parameters */
mmc->max_hw_segs = 64;
mmc->max_phys_segs = 64;
- mmc->max_sectors = 64; /* default 1 << (PAGE_CACHE_SHIFT - 9) */
mmc->max_seg_size = 64*512; /* default PAGE_CACHE_SIZE */
+ mmc->max_req_size = 64*512; /* default PAGE_CACHE_SIZE */
+ mmc->max_blk_size = 2048;
+ mmc->max_blk_count = 65535;
host = mmc_priv(mmc);
host->mmc = mmc;
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 6f2a282e2b9..5046a166134 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -103,11 +103,16 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
mmc_hostname(host), mrq->cmd->opcode,
mrq->cmd->arg, mrq->cmd->flags);
- WARN_ON(host->card_busy == NULL);
+ WARN_ON(!host->claimed);
mrq->cmd->error = 0;
mrq->cmd->mrq = mrq;
if (mrq->data) {
+ BUG_ON(mrq->data->blksz > host->max_blk_size);
+ BUG_ON(mrq->data->blocks > host->max_blk_count);
+ BUG_ON(mrq->data->blocks * mrq->data->blksz >
+ host->max_req_size);
+
mrq->cmd->data = mrq->data;
mrq->data->error = 0;
mrq->data->mrq = mrq;
@@ -157,7 +162,7 @@ int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries
{
struct mmc_request mrq;
- BUG_ON(host->card_busy == NULL);
+ BUG_ON(!host->claimed);
memset(&mrq, 0, sizeof(struct mmc_request));
@@ -195,7 +200,7 @@ int mmc_wait_for_app_cmd(struct mmc_host *host, unsigned int rca,
int i, err;
- BUG_ON(host->card_busy == NULL);
+ BUG_ON(!host->claimed);
BUG_ON(retries < 0);
err = MMC_ERR_INVALID;
@@ -289,7 +294,10 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card,
else
limit_us = 100000;
- if (timeout_us > limit_us) {
+ /*
+ * SDHC cards always use these fixed values.
+ */
+ if (timeout_us > limit_us || mmc_card_blockaddr(card)) {
data->timeout_ns = limit_us * 1000;
data->timeout_clks = 0;
}
@@ -320,14 +328,14 @@ int __mmc_claim_host(struct mmc_host *host, struct mmc_card *card)
spin_lock_irqsave(&host->lock, flags);
while (1) {
set_current_state(TASK_UNINTERRUPTIBLE);
- if (host->card_busy == NULL)
+ if (!host->claimed)
break;
spin_unlock_irqrestore(&host->lock, flags);
schedule();
spin_lock_irqsave(&host->lock, flags);
}
set_current_state(TASK_RUNNING);
- host->card_busy = card;
+ host->claimed = 1;
spin_unlock_irqrestore(&host->lock, flags);
remove_wait_queue(&host->wq, &wait);
@@ -353,10 +361,10 @@ void mmc_release_host(struct mmc_host *host)
{
unsigned long flags;
- BUG_ON(host->card_busy == NULL);
+ BUG_ON(!host->claimed);
spin_lock_irqsave(&host->lock, flags);
- host->card_busy = NULL;
+ host->claimed = 0;
spin_unlock_irqrestore(&host->lock, flags);
wake_up(&host->wq);
@@ -372,7 +380,7 @@ static inline void mmc_set_ios(struct mmc_host *host)
mmc_hostname(host), ios->clock, ios->bus_mode,
ios->power_mode, ios->chip_select, ios->vdd,
ios->bus_width);
-
+
host->ops->set_ios(host, ios);
}
@@ -381,7 +389,7 @@ static int mmc_select_card(struct mmc_host *host, struct mmc_card *card)
int err;
struct mmc_command cmd;
- BUG_ON(host->card_busy == NULL);
+ BUG_ON(!host->claimed);
if (host->card_selected == card)
return MMC_ERR_NONE;
@@ -588,34 +596,65 @@ static void mmc_decode_csd(struct mmc_card *card)
if (mmc_card_sd(card)) {
csd_struct = UNSTUFF_BITS(resp, 126, 2);
- if (csd_struct != 0) {
+
+ switch (csd_struct) {
+ case 0:
+ m = UNSTUFF_BITS(resp, 115, 4);
+ e = UNSTUFF_BITS(resp, 112, 3);
+ csd->tacc_ns = (tacc_exp[e] * tacc_mant[m] + 9) / 10;
+ csd->tacc_clks = UNSTUFF_BITS(resp, 104, 8) * 100;
+
+ m = UNSTUFF_BITS(resp, 99, 4);
+ e = UNSTUFF_BITS(resp, 96, 3);
+ csd->max_dtr = tran_exp[e] * tran_mant[m];
+ csd->cmdclass = UNSTUFF_BITS(resp, 84, 12);
+
+ e = UNSTUFF_BITS(resp, 47, 3);
+ m = UNSTUFF_BITS(resp, 62, 12);
+ csd->capacity = (1 + m) << (e + 2);
+
+ csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
+ csd->read_partial = UNSTUFF_BITS(resp, 79, 1);
+ csd->write_misalign = UNSTUFF_BITS(resp, 78, 1);
+ csd->read_misalign = UNSTUFF_BITS(resp, 77, 1);
+ csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3);
+ csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4);
+ csd->write_partial = UNSTUFF_BITS(resp, 21, 1);
+ break;
+ case 1:
+ /*
+ * This is a block-addressed SDHC card. Most
+ * interesting fields are unused and have fixed
+ * values. To avoid getting tripped by buggy cards,
+ * we assume those fixed values ourselves.
+ */
+ mmc_card_set_blockaddr(card);
+
+ csd->tacc_ns = 0; /* Unused */
+ csd->tacc_clks = 0; /* Unused */
+
+ m = UNSTUFF_BITS(resp, 99, 4);
+ e = UNSTUFF_BITS(resp, 96, 3);
+ csd->max_dtr = tran_exp[e] * tran_mant[m];
+ csd->cmdclass = UNSTUFF_BITS(resp, 84, 12);
+
+ m = UNSTUFF_BITS(resp, 48, 22);
+ csd->capacity = (1 + m) << 10;
+
+ csd->read_blkbits = 9;
+ csd->read_partial = 0;
+ csd->write_misalign = 0;
+ csd->read_misalign = 0;
+ csd->r2w_factor = 4; /* Unused */
+ csd->write_blkbits = 9;
+ csd->write_partial = 0;
+ break;
+ default:
printk("%s: unrecognised CSD structure version %d\n",
mmc_hostname(card->host), csd_struct);
mmc_card_set_bad(card);
return;
}
-
- m = UNSTUFF_BITS(resp, 115, 4);
- e = UNSTUFF_BITS(resp, 112, 3);
- csd->tacc_ns = (tacc_exp[e] * tacc_mant[m] + 9) / 10;
- csd->tacc_clks = UNSTUFF_BITS(resp, 104, 8) * 100;
-
- m = UNSTUFF_BITS(resp, 99, 4);
- e = UNSTUFF_BITS(resp, 96, 3);
- csd->max_dtr = tran_exp[e] * tran_mant[m];
- csd->cmdclass = UNSTUFF_BITS(resp, 84, 12);
-
- e = UNSTUFF_BITS(resp, 47, 3);
- m = UNSTUFF_BITS(resp, 62, 12);
- csd->capacity = (1 + m) << (e + 2);
-
- csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
- csd->read_partial = UNSTUFF_BITS(resp, 79, 1);
- csd->write_misalign = UNSTUFF_BITS(resp, 78, 1);
- csd->read_misalign = UNSTUFF_BITS(resp, 77, 1);
- csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3);
- csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4);
- csd->write_partial = UNSTUFF_BITS(resp, 21, 1);
} else {
/*
* We only understand CSD structure v1.1 and v1.2.
@@ -848,6 +887,41 @@ static int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
return err;
}
+static int mmc_send_if_cond(struct mmc_host *host, u32 ocr, int *rsd2)
+{
+ struct mmc_command cmd;
+ int err, sd2;
+ static const u8 test_pattern = 0xAA;
+
+ /*
+ * To support SD 2.0 cards, we must always invoke SD_SEND_IF_COND
+ * before SD_APP_OP_COND. This command will harmlessly fail for
+ * SD 1.0 cards.
+ */
+ cmd.opcode = SD_SEND_IF_COND;
+ cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | test_pattern;
+ cmd.flags = MMC_RSP_R7 | MMC_CMD_BCR;
+
+ err = mmc_wait_for_cmd(host, &cmd, 0);
+ if (err == MMC_ERR_NONE) {
+ if ((cmd.resp[0] & 0xFF) == test_pattern) {
+ sd2 = 1;
+ } else {
+ sd2 = 0;
+ err = MMC_ERR_FAILED;
+ }
+ } else {
+ /*
+ * Treat errors as SD 1.0 card.
+ */
+ sd2 = 0;
+ err = MMC_ERR_NONE;
+ }
+ if (rsd2)
+ *rsd2 = sd2;
+ return err;
+}
+
/*
* Discover cards by requesting their CID. If this command
* times out, it is not an error; there are no further cards
@@ -1018,7 +1092,8 @@ static void mmc_process_ext_csds(struct mmc_host *host)
mmc_wait_for_req(host, &mrq);
if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) {
- mmc_card_set_dead(card);
+ printk("%s: unable to read EXT_CSD, performance "
+ "might suffer.\n", mmc_hostname(card->host));
continue;
}
@@ -1034,7 +1109,6 @@ static void mmc_process_ext_csds(struct mmc_host *host)
printk("%s: card is mmc v4 but doesn't support "
"any high-speed modes.\n",
mmc_hostname(card->host));
- mmc_card_set_bad(card);
continue;
}
@@ -1215,7 +1289,9 @@ static void mmc_read_switch_caps(struct mmc_host *host)
mmc_wait_for_req(host, &mrq);
if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) {
- mmc_card_set_dead(card);
+ printk("%s: unable to read switch capabilities, "
+ "performance might suffer.\n",
+ mmc_hostname(card->host));
continue;
}
@@ -1247,12 +1323,8 @@ static void mmc_read_switch_caps(struct mmc_host *host)
mmc_wait_for_req(host, &mrq);
- if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) {
- mmc_card_set_dead(card);
- continue;
- }
-
- if ((status[16] & 0xF) != 1) {
+ if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE ||
+ (status[16] & 0xF) != 1) {
printk(KERN_WARNING "%s: Problem switching card "
"into high-speed mode!\n",
mmc_hostname(host));
@@ -1334,6 +1406,10 @@ static void mmc_setup(struct mmc_host *host)
mmc_power_up(host);
mmc_idle_cards(host);
+ err = mmc_send_if_cond(host, host->ocr_avail, NULL);
+ if (err != MMC_ERR_NONE) {
+ return;
+ }
err = mmc_send_app_op_cond(host, 0, &ocr);
/*
@@ -1386,10 +1462,21 @@ static void mmc_setup(struct mmc_host *host)
* all get the idea that they should be ready for CMD2.
* (My SanDisk card seems to need this.)
*/
- if (host->mode == MMC_MODE_SD)
- mmc_send_app_op_cond(host, host->ocr, NULL);
- else
+ if (host->mode == MMC_MODE_SD) {
+ int err, sd2;
+ err = mmc_send_if_cond(host, host->ocr, &sd2);
+ if (err == MMC_ERR_NONE) {
+ /*
+ * If SD_SEND_IF_COND indicates an SD 2.0
+ * compliant card and we should set bit 30
+ * of the ocr to indicate that we can handle
+ * block-addressed SDHC cards.
+ */
+ mmc_send_app_op_cond(host, host->ocr | (sd2 << 30), NULL);
+ }
+ } else {
mmc_send_op_cond(host, host->ocr, NULL);
+ }
mmc_discover_cards(host);
@@ -1519,8 +1606,11 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
*/
host->max_hw_segs = 1;
host->max_phys_segs = 1;
- host->max_sectors = 1 << (PAGE_CACHE_SHIFT - 9);
host->max_seg_size = PAGE_CACHE_SIZE;
+
+ host->max_req_size = PAGE_CACHE_SIZE;
+ host->max_blk_size = 512;
+ host->max_blk_count = PAGE_CACHE_SIZE / 512;
}
return host;
diff --git a/drivers/mmc/mmc_block.c b/drivers/mmc/mmc_block.c
index 87713572293..86439a0bb27 100644
--- a/drivers/mmc/mmc_block.c
+++ b/drivers/mmc/mmc_block.c
@@ -20,7 +20,6 @@
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/errno.h>
@@ -237,13 +236,17 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
brq.mrq.cmd = &brq.cmd;
brq.mrq.data = &brq.data;
- brq.cmd.arg = req->sector << 9;
+ brq.cmd.arg = req->sector;
+ if (!mmc_card_blockaddr(card))
+ brq.cmd.arg <<= 9;
brq.cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
brq.data.blksz = 1 << md->block_bits;
- brq.data.blocks = req->nr_sectors >> (md->block_bits - 9);
brq.stop.opcode = MMC_STOP_TRANSMISSION;
brq.stop.arg = 0;
brq.stop.flags = MMC_RSP_R1B | MMC_CMD_AC;
+ brq.data.blocks = req->nr_sectors >> (md->block_bits - 9);
+ if (brq.data.blocks > card->host->max_blk_count)
+ brq.data.blocks = card->host->max_blk_count;
mmc_set_data_timeout(&brq.data, card, rq_data_dir(req) != READ);
@@ -375,9 +378,10 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
spin_unlock_irq(&md->lock);
}
+flush_queue:
+
mmc_card_release_host(card);
-flush_queue:
spin_lock_irq(&md->lock);
while (ret) {
ret = end_that_request_chunk(req, 0,
@@ -494,6 +498,10 @@ mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)
struct mmc_command cmd;
int err;
+ /* Block-addressed cards ignore MMC_SET_BLOCKLEN. */
+ if (mmc_card_blockaddr(card))
+ return 0;
+
mmc_card_claim_host(card);
cmd.opcode = MMC_SET_BLOCKLEN;
cmd.arg = 1 << md->block_bits;
diff --git a/drivers/mmc/mmc_queue.c b/drivers/mmc/mmc_queue.c
index 3e35a43819f..c27e42645cd 100644
--- a/drivers/mmc/mmc_queue.c
+++ b/drivers/mmc/mmc_queue.c
@@ -147,7 +147,7 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
blk_queue_prep_rq(mq->queue, mmc_prep_request);
blk_queue_bounce_limit(mq->queue, limit);
- blk_queue_max_sectors(mq->queue, host->max_sectors);
+ blk_queue_max_sectors(mq->queue, 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_segment_size(mq->queue, host->max_seg_size);
diff --git a/drivers/mmc/mmc_sysfs.c b/drivers/mmc/mmc_sysfs.c
index e334acd045b..d32698b02d7 100644
--- a/drivers/mmc/mmc_sysfs.c
+++ b/drivers/mmc/mmc_sysfs.c
@@ -199,7 +199,7 @@ void mmc_init_card(struct mmc_card *card, struct mmc_host *host)
memset(card, 0, sizeof(struct mmc_card));
card->host = host;
device_initialize(&card->dev);
- card->dev.parent = mmc_dev(host);
+ card->dev.parent = mmc_classdev(host);
card->dev.bus = &mmc_bus_type;
card->dev.release = mmc_release_card;
}
diff --git a/drivers/mmc/mmci.c b/drivers/mmc/mmci.c
index ccfe6561be2..5941dd951e8 100644
--- a/drivers/mmc/mmci.c
+++ b/drivers/mmc/mmci.c
@@ -524,15 +524,24 @@ static int mmci_probe(struct amba_device *dev, void *id)
/*
* Since we only have a 16-bit data length register, we must
* ensure that we don't exceed 2^16-1 bytes in a single request.
- * Choose 64 (512-byte) sectors as the limit.
*/
- mmc->max_sectors = 64;
+ mmc->max_req_size = 65535;
/*
* Set the maximum segment size. Since we aren't doing DMA
* (yet) we are only limited by the data length register.
*/
- mmc->max_seg_size = mmc->max_sectors << 9;
+ mmc->max_seg_size = mmc->max_req_size;
+
+ /*
+ * Block size can be up to 2048 bytes, but must be a power of two.
+ */
+ mmc->max_blk_size = 2048;
+
+ /*
+ * No limit on the number of blocks transferred.
+ */
+ mmc->max_blk_count = mmc->max_req_size;
spin_lock_init(&host->lock);
diff --git a/drivers/mmc/omap.c b/drivers/mmc/omap.c
index d30540b2761..1e96a2f6502 100644
--- a/drivers/mmc/omap.c
+++ b/drivers/mmc/omap.c
@@ -1099,8 +1099,10 @@ static int __init mmc_omap_probe(struct platform_device *pdev)
*/
mmc->max_phys_segs = 32;
mmc->max_hw_segs = 32;
- mmc->max_sectors = 256; /* NBLK max 11-bits, OMAP also limited by DMA */
- mmc->max_seg_size = mmc->max_sectors * 512;
+ mmc->max_blk_size = 2048; /* BLEN is 11 bits (+1) */
+ mmc->max_blk_count = 2048; /* NBLK is 11 bits (+1) */
+ mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
+ mmc->max_seg_size = mmc->max_req_size;
if (host->power_pin >= 0) {
if ((ret = omap_request_gpio(host->power_pin)) != 0) {
diff --git a/drivers/mmc/pxamci.c b/drivers/mmc/pxamci.c
index 6073d998b11..9774fc68b61 100644
--- a/drivers/mmc/pxamci.c
+++ b/drivers/mmc/pxamci.c
@@ -450,6 +450,16 @@ static int pxamci_probe(struct platform_device *pdev)
*/
mmc->max_seg_size = PAGE_SIZE;
+ /*
+ * Block length register is 10 bits.
+ */
+ mmc->max_blk_size = 1023;
+
+ /*
+ * Block count register is 16 bits.
+ */
+ mmc->max_blk_count = 65535;
+
host = mmc_priv(mmc);
host->mmc = mmc;
host->dma = -1;
diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
index c2d13d7e991..7522f76b15e 100644
--- a/drivers/mmc/sdhci.c
+++ b/drivers/mmc/sdhci.c
@@ -22,9 +22,6 @@
#include "sdhci.h"
#define DRIVER_NAME "sdhci"
-#define DRIVER_VERSION "0.12"
-
-#define BUGMAIL "<sdhci-devel@list.drzeus.cx>"
#define DBG(f, x...) \
pr_debug(DRIVER_NAME " [%s()]: " f, __func__,## x)
@@ -37,6 +34,7 @@ static unsigned int debug_quirks = 0;
#define SDHCI_QUIRK_FORCE_DMA (1<<1)
/* Controller doesn't like some resets when there is no card inserted. */
#define SDHCI_QUIRK_NO_CARD_NO_RESET (1<<2)
+#define SDHCI_QUIRK_SINGLE_POWER_WRITE (1<<3)
static const struct pci_device_id pci_ids[] __devinitdata = {
{
@@ -65,6 +63,14 @@ static const struct pci_device_id pci_ids[] __devinitdata = {
.driver_data = SDHCI_QUIRK_FORCE_DMA,
},
+ {
+ .vendor = PCI_VENDOR_ID_ENE,
+ .device = PCI_DEVICE_ID_ENE_CB712_SD,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = SDHCI_QUIRK_SINGLE_POWER_WRITE,
+ },
+
{ /* Generic SD host controller */
PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00)
},
@@ -145,8 +151,7 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask)
/* hw clears the bit when it's done */
while (readb(host->ioaddr + SDHCI_SOFTWARE_RESET) & mask) {
if (timeout == 0) {
- printk(KERN_ERR "%s: Reset 0x%x never completed. "
- "Please report this to " BUGMAIL ".\n",
+ printk(KERN_ERR "%s: Reset 0x%x never completed.\n",
mmc_hostname(host->mmc), (int)mask);
sdhci_dumpregs(host);
return;
@@ -197,15 +202,9 @@ static void sdhci_deactivate_led(struct sdhci_host *host)
* *
\*****************************************************************************/
-static inline char* sdhci_kmap_sg(struct sdhci_host* host)
+static inline char* sdhci_sg_to_buffer(struct sdhci_host* host)
{
- host->mapped_sg = kmap_atomic(host->cur_sg->page, KM_BIO_SRC_IRQ);
- return host->mapped_sg + host->cur_sg->offset;
-}
-
-static inline void sdhci_kunmap_sg(struct sdhci_host* host)
-{
- kunmap_atomic(host->mapped_sg, KM_BIO_SRC_IRQ);
+ return page_address(host->cur_sg->page) + host->cur_sg->offset;
}
static inline int sdhci_next_sg(struct sdhci_host* host)
@@ -240,7 +239,7 @@ static void sdhci_read_block_pio(struct sdhci_host *host)
chunk_remain = 0;
data = 0;
- buffer = sdhci_kmap_sg(host) + host->offset;
+ buffer = sdhci_sg_to_buffer(host) + host->offset;
while (blksize) {
if (chunk_remain == 0) {
@@ -264,16 +263,13 @@ static void sdhci_read_block_pio(struct sdhci_host *host)
}
if (host->remain == 0) {
- sdhci_kunmap_sg(host);
if (sdhci_next_sg(host) == 0) {
BUG_ON(blksize != 0);
return;
}
- buffer = sdhci_kmap_sg(host);
+ buffer = sdhci_sg_to_buffer(host);
}
}
-
- sdhci_kunmap_sg(host);
}
static void sdhci_write_block_pio(struct sdhci_host *host)
@@ -290,7 +286,7 @@ static void sdhci_write_block_pio(struct sdhci_host *host)
data = 0;
bytes = 0;
- buffer = sdhci_kmap_sg(host) + host->offset;
+ buffer = sdhci_sg_to_buffer(host) + host->offset;
while (blksize) {
size = min(host->size, host->remain);
@@ -314,16 +310,13 @@ static void sdhci_write_block_pio(struct sdhci_host *host)
}
if (host->remain == 0) {
- sdhci_kunmap_sg(host);
if (sdhci_next_sg(host) == 0) {
BUG_ON(blksize != 0);
return;
}
- buffer = sdhci_kmap_sg(host);
+ buffer = sdhci_sg_to_buffer(host);
}
}
-
- sdhci_kunmap_sg(host);
}
static void sdhci_transfer_pio(struct sdhci_host *host)
@@ -372,7 +365,7 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
/* Sanity checks */
BUG_ON(data->blksz * data->blocks > 524288);
- BUG_ON(data->blksz > host->max_block);
+ BUG_ON(data->blksz > host->mmc->max_blk_size);
BUG_ON(data->blocks > 65535);
/* timeout in us */
@@ -477,12 +470,11 @@ static void sdhci_finish_data(struct sdhci_host *host)
if ((data->error == MMC_ERR_NONE) && blocks) {
printk(KERN_ERR "%s: Controller signalled completion even "
- "though there were blocks left. Please report this "
- "to " BUGMAIL ".\n", mmc_hostname(host->mmc));
+ "though there were blocks left.\n",
+ mmc_hostname(host->mmc));
data->error = MMC_ERR_FAILED;
} else if (host->size != 0) {
- printk(KERN_ERR "%s: %d bytes were left untransferred. "
- "Please report this to " BUGMAIL ".\n",
+ printk(KERN_ERR "%s: %d bytes were left untransferred.\n",
mmc_hostname(host->mmc), host->size);
data->error = MMC_ERR_FAILED;
}
@@ -529,8 +521,7 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
while (readl(host->ioaddr + SDHCI_PRESENT_STATE) & mask) {
if (timeout == 0) {
printk(KERN_ERR "%s: Controller never released "
- "inhibit bit(s). Please report this to "
- BUGMAIL ".\n", mmc_hostname(host->mmc));
+ "inhibit bit(s).\n", mmc_hostname(host->mmc));
sdhci_dumpregs(host);
cmd->error = MMC_ERR_FAILED;
tasklet_schedule(&host->finish_tasklet);
@@ -551,8 +542,7 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
sdhci_set_transfer_mode(host, cmd->data);
if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) {
- printk(KERN_ERR "%s: Unsupported response type! "
- "Please report this to " BUGMAIL ".\n",
+ printk(KERN_ERR "%s: Unsupported response type!\n",
mmc_hostname(host->mmc));
cmd->error = MMC_ERR_INVALID;
tasklet_schedule(&host->finish_tasklet);
@@ -650,9 +640,8 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
while (!((clk = readw(host->ioaddr + SDHCI_CLOCK_CONTROL))
& SDHCI_CLOCK_INT_STABLE)) {
if (timeout == 0) {
- printk(KERN_ERR "%s: Internal clock never stabilised. "
- "Please report this to " BUGMAIL ".\n",
- mmc_hostname(host->mmc));
+ printk(KERN_ERR "%s: Internal clock never "
+ "stabilised.\n", mmc_hostname(host->mmc));
sdhci_dumpregs(host);
return;
}
@@ -674,10 +663,17 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
if (host->power == power)
return;
- writeb(0, host->ioaddr + SDHCI_POWER_CONTROL);
-
- if (power == (unsigned short)-1)
+ if (power == (unsigned short)-1) {
+ writeb(0, host->ioaddr + SDHCI_POWER_CONTROL);
goto out;
+ }
+
+ /*
+ * Spec says that we should clear the power reg before setting
+ * a new value. Some controllers don't seem to like this though.
+ */
+ if (!(host->chip->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE))
+ writeb(0, host->ioaddr + SDHCI_POWER_CONTROL);
pwr = SDHCI_POWER_ON;
@@ -895,9 +891,8 @@ static void sdhci_timeout_timer(unsigned long data)
spin_lock_irqsave(&host->lock, flags);
if (host->mrq) {
- printk(KERN_ERR "%s: Timeout waiting for hardware interrupt. "
- "Please report this to " BUGMAIL ".\n",
- mmc_hostname(host->mmc));
+ printk(KERN_ERR "%s: Timeout waiting for hardware "
+ "interrupt.\n", mmc_hostname(host->mmc));
sdhci_dumpregs(host);
if (host->data) {
@@ -931,8 +926,6 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask)
printk(KERN_ERR "%s: Got command interrupt even though no "
"command operation was in progress.\n",
mmc_hostname(host->mmc));
- printk(KERN_ERR "%s: Please report this to " BUGMAIL ".\n",
- mmc_hostname(host->mmc));
sdhci_dumpregs(host);
return;
}
@@ -968,8 +961,6 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
printk(KERN_ERR "%s: Got data interrupt even though no "
"data operation was in progress.\n",
mmc_hostname(host->mmc));
- printk(KERN_ERR "%s: Please report this to " BUGMAIL ".\n",
- mmc_hostname(host->mmc));
sdhci_dumpregs(host);
return;
@@ -1041,8 +1032,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
intmask &= SDHCI_INT_BUS_POWER;
if (intmask) {
- printk(KERN_ERR "%s: Unexpected interrupt 0x%08x. Please "
- "report this to " BUGMAIL ".\n",
+ printk(KERN_ERR "%s: Unexpected interrupt 0x%08x.\n",
mmc_hostname(host->mmc), intmask);
sdhci_dumpregs(host);
@@ -1109,7 +1099,9 @@ static int sdhci_resume (struct pci_dev *pdev)
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
- pci_enable_device(pdev);
+ ret = pci_enable_device(pdev);
+ if (ret)
+ return ret;
for (i = 0;i < chip->num_slots;i++) {
if (!chip->hosts[i])
@@ -1274,15 +1266,6 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
if (caps & SDHCI_TIMEOUT_CLK_UNIT)
host->timeout_clk *= 1000;
- host->max_block = (caps & SDHCI_MAX_BLOCK_MASK) >> SDHCI_MAX_BLOCK_SHIFT;
- if (host->max_block >= 3) {
- printk(KERN_ERR "%s: Invalid maximum block size.\n",
- host->slot_descr);
- ret = -ENODEV;
- goto unmap;
- }
- host->max_block = 512 << host->max_block;
-
/*
* Set host parameters.
*/
@@ -1294,9 +1277,9 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
mmc->ocr_avail = 0;
if (caps & SDHCI_CAN_VDD_330)
mmc->ocr_avail |= MMC_VDD_32_33|MMC_VDD_33_34;
- else if (caps & SDHCI_CAN_VDD_300)
+ if (caps & SDHCI_CAN_VDD_300)
mmc->ocr_avail |= MMC_VDD_29_30|MMC_VDD_30_31;
- else if (caps & SDHCI_CAN_VDD_180)
+ if (caps & SDHCI_CAN_VDD_180)
mmc->ocr_avail |= MMC_VDD_17_18|MMC_VDD_18_19;
if ((host->max_clk > 25000000) && !(caps & SDHCI_CAN_DO_HISPD)) {
@@ -1326,15 +1309,33 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
/*
* Maximum number of sectors in one transfer. Limited by DMA boundary
- * size (512KiB), which means (512 KiB/512=) 1024 entries.
+ * size (512KiB).
*/
- mmc->max_sectors = 1024;
+ mmc->max_req_size = 524288;
/*
* Maximum segment size. Could be one segment with the maximum number
- * of sectors.
+ * of bytes.
+ */
+ mmc->max_seg_size = mmc->max_req_size;
+
+ /*
+ * Maximum block size. This varies from controller to controller and
+ * is specified in the capabilities register.
+ */
+ mmc->max_blk_size = (caps & SDHCI_MAX_BLOCK_MASK) >> SDHCI_MAX_BLOCK_SHIFT;
+ if (mmc->max_blk_size >= 3) {
+ printk(KERN_ERR "%s: Invalid maximum block size.\n",
+ host->slot_descr);
+ ret = -ENODEV;
+ goto unmap;
+ }
+ mmc->max_blk_size = 512 << mmc->max_blk_size;
+
+ /*
+ * Maximum block count.
*/
- mmc->max_seg_size = mmc->max_sectors * 512;
+ mmc->max_blk_count = 65535;
/*
* Init tasklets.
@@ -1513,8 +1514,7 @@ static struct pci_driver sdhci_driver = {
static int __init sdhci_drv_init(void)
{
printk(KERN_INFO DRIVER_NAME
- ": Secure Digital Host Controller Interface driver, "
- DRIVER_VERSION "\n");
+ ": Secure Digital Host Controller Interface driver\n");
printk(KERN_INFO DRIVER_NAME ": Copyright(c) Pierre Ossman\n");
return pci_register_driver(&sdhci_driver);
@@ -1536,7 +1536,6 @@ module_param(debug_quirks, uint, 0444);
MODULE_AUTHOR("Pierre Ossman <drzeus@drzeus.cx>");
MODULE_DESCRIPTION("Secure Digital Host Controller Interface driver");
-MODULE_VERSION(DRIVER_VERSION);
MODULE_LICENSE("GPL");
MODULE_PARM_DESC(debug_nodma, "Forcefully disable DMA transfers. (default 0)");
diff --git a/drivers/mmc/sdhci.h b/drivers/mmc/sdhci.h
index f9d1a0a6f03..e324f0a623d 100644
--- a/drivers/mmc/sdhci.h
+++ b/drivers/mmc/sdhci.h
@@ -174,7 +174,6 @@ struct sdhci_host {
unsigned int max_clk; /* Max possible freq (MHz) */
unsigned int timeout_clk; /* Timeout freq (KHz) */
- unsigned int max_block; /* Max block size (bytes) */
unsigned int clock; /* Current clock (MHz) */
unsigned short power; /* Current voltage */
@@ -184,7 +183,6 @@ struct sdhci_host {
struct mmc_data *data; /* Current data request */
struct scatterlist *cur_sg; /* We're working on this */
- char *mapped_sg; /* This is where it's mapped */
int num_sg; /* Entries left */
int offset; /* Offset into current sg */
int remain; /* Bytes left in current */
diff --git a/drivers/mmc/tifm_sd.c b/drivers/mmc/tifm_sd.c
index fa4a52886b9..0581d09c58f 100644
--- a/drivers/mmc/tifm_sd.c
+++ b/drivers/mmc/tifm_sd.c
@@ -17,7 +17,7 @@
#include <asm/io.h>
#define DRIVER_NAME "tifm_sd"
-#define DRIVER_VERSION "0.6"
+#define DRIVER_VERSION "0.7"
static int no_dma = 0;
static int fixed_timeout = 0;
@@ -36,8 +36,8 @@ module_param(fixed_timeout, bool, 0644);
#define TIFM_MMCSD_INAB 0x0080 /* abort / initialize command */
#define TIFM_MMCSD_READ 0x8000
-#define TIFM_MMCSD_DATAMASK 0x001d /* set bits: EOFB, BRS, CB, EOC */
-#define TIFM_MMCSD_ERRMASK 0x41e0 /* set bits: CERR, CCRC, CTO, DCRC, DTO */
+#define TIFM_MMCSD_DATAMASK 0x401d /* set bits: CERR, EOFB, BRS, CB, EOC */
+#define TIFM_MMCSD_ERRMASK 0x01e0 /* set bits: CCRC, CTO, DCRC, DTO */
#define TIFM_MMCSD_EOC 0x0001 /* end of command phase */
#define TIFM_MMCSD_CB 0x0004 /* card enter busy state */
#define TIFM_MMCSD_BRS 0x0008 /* block received/sent */
@@ -79,7 +79,6 @@ typedef enum {
enum {
FIFO_RDY = 0x0001, /* hardware dependent value */
- HOST_REG = 0x0002,
EJECT = 0x0004,
EJECT_DONE = 0x0008,
CARD_BUSY = 0x0010,
@@ -95,46 +94,53 @@ struct tifm_sd {
card_state_t state;
unsigned int clk_freq;
unsigned int clk_div;
- unsigned long timeout_jiffies; // software timeout - 2 sec
+ unsigned long timeout_jiffies;
+ struct tasklet_struct finish_tasklet;
+ struct timer_list timer;
struct mmc_request *req;
- struct work_struct cmd_handler;
- struct delayed_work abort_handler;
- wait_queue_head_t can_eject;
+ wait_queue_head_t notify;
size_t written_blocks;
- char *buffer;
size_t buffer_size;
size_t buffer_pos;
};
+static char* tifm_sd_data_buffer(struct mmc_data *data)
+{
+ return page_address(data->sg->page) + data->sg->offset;
+}
+
static int tifm_sd_transfer_data(struct tifm_dev *sock, struct tifm_sd *host,
- unsigned int host_status)
+ unsigned int host_status)
{
struct mmc_command *cmd = host->req->cmd;
unsigned int t_val = 0, cnt = 0;
+ char *buffer;
if (host_status & TIFM_MMCSD_BRS) {
/* in non-dma rx mode BRS fires when fifo is still not empty */
- if (host->buffer && (cmd->data->flags & MMC_DATA_READ)) {
+ if (no_dma && (cmd->data->flags & MMC_DATA_READ)) {
+ buffer = tifm_sd_data_buffer(host->req->data);
while (host->buffer_size > host->buffer_pos) {
t_val = readl(sock->addr + SOCK_MMCSD_DATA);
- host->buffer[host->buffer_pos++] = t_val & 0xff;
- host->buffer[host->buffer_pos++] =
+ buffer[host->buffer_pos++] = t_val & 0xff;
+ buffer[host->buffer_pos++] =
(t_val >> 8) & 0xff;
}
}
return 1;
- } else if (host->buffer) {
+ } else if (no_dma) {
+ buffer = tifm_sd_data_buffer(host->req->data);
if ((cmd->data->flags & MMC_DATA_READ) &&
(host_status & TIFM_MMCSD_AF)) {
for (cnt = 0; cnt < TIFM_MMCSD_FIFO_SIZE; cnt++) {
t_val = readl(sock->addr + SOCK_MMCSD_DATA);
if (host->buffer_size > host->buffer_pos) {
- host->buffer[host->buffer_pos++] =
+ buffer[host->buffer_pos++] =
t_val & 0xff;
- host->buffer[host->buffer_pos++] =
+ buffer[host->buffer_pos++] =
(t_val >> 8) & 0xff;
}
}
@@ -142,11 +148,12 @@ static int tifm_sd_transfer_data(struct tifm_dev *sock, struct tifm_sd *host,
&& (host_status & TIFM_MMCSD_AE)) {
for (cnt = 0; cnt < TIFM_MMCSD_FIFO_SIZE; cnt++) {
if (host->buffer_size > host->buffer_pos) {
- t_val = host->buffer[host->buffer_pos++] & 0x00ff;
- t_val |= ((host->buffer[host->buffer_pos++]) << 8)
- & 0xff00;
+ t_val = buffer[host->buffer_pos++]
+ & 0x00ff;
+ t_val |= ((buffer[host->buffer_pos++])
+ << 8) & 0xff00;
writel(t_val,
- sock->addr + SOCK_MMCSD_DATA);
+ sock->addr + SOCK_MMCSD_DATA);
}
}
}
@@ -206,7 +213,7 @@ static void tifm_sd_exec(struct tifm_sd *host, struct mmc_command *cmd)
cmd_mask |= TIFM_MMCSD_READ;
dev_dbg(&sock->dev, "executing opcode 0x%x, arg: 0x%x, mask: 0x%x\n",
- cmd->opcode, cmd->arg, cmd_mask);
+ cmd->opcode, cmd->arg, cmd_mask);
writel((cmd->arg >> 16) & 0xffff, sock->addr + SOCK_MMCSD_ARG_HIGH);
writel(cmd->arg & 0xffff, sock->addr + SOCK_MMCSD_ARG_LOW);
@@ -235,69 +242,82 @@ change_state:
case IDLE:
return;
case CMD:
- if (host_status & TIFM_MMCSD_EOC) {
+ if (host_status & (TIFM_MMCSD_EOC | TIFM_MMCSD_CERR)) {
tifm_sd_fetch_resp(cmd, sock);
if (cmd->data) {
host->state = BRS;
- } else
+ } else {
host->state = READY;
+ }
goto change_state;
}
break;
case BRS:
if (tifm_sd_transfer_data(sock, host, host_status)) {
- if (!host->req->stop) {
- if (cmd->data->flags & MMC_DATA_WRITE) {
- host->state = CARD;
+ if (cmd->data->flags & MMC_DATA_WRITE) {
+ host->state = CARD;
+ } else {
+ if (no_dma) {
+ if (host->req->stop) {
+ tifm_sd_exec(host, host->req->stop);
+ host->state = SCMD;
+ } else {
+ host->state = READY;
+ }
} else {
- host->state =
- host->buffer ? READY : FIFO;
+ host->state = FIFO;
}
- goto change_state;
}
- tifm_sd_exec(host, host->req->stop);
- host->state = SCMD;
+ goto change_state;
}
break;
case SCMD:
if (host_status & TIFM_MMCSD_EOC) {
tifm_sd_fetch_resp(host->req->stop, sock);
- if (cmd->error) {
- host->state = READY;
- } else if (cmd->data->flags & MMC_DATA_WRITE) {
- host->state = CARD;
- } else {
- host->state = host->buffer ? READY : FIFO;
- }
+ host->state = READY;
goto change_state;
}
break;
case CARD:
+ dev_dbg(&sock->dev, "waiting for CARD, have %zd blocks\n",
+ host->written_blocks);
if (!(host->flags & CARD_BUSY)
&& (host->written_blocks == cmd->data->blocks)) {
- host->state = host->buffer ? READY : FIFO;
+ if (no_dma) {
+ if (host->req->stop) {
+ tifm_sd_exec(host, host->req->stop);
+ host->state = SCMD;
+ } else {
+ host->state = READY;
+ }
+ } else {
+ host->state = FIFO;
+ }
goto change_state;
}
break;
case FIFO:
if (host->flags & FIFO_RDY) {
- host->state = READY;
host->flags &= ~FIFO_RDY;
+ if (host->req->stop) {
+ tifm_sd_exec(host, host->req->stop);
+ host->state = SCMD;
+ } else {
+ host->state = READY;
+ }
goto change_state;
}
break;
case READY:
- queue_work(sock->wq, &host->cmd_handler);
+ tasklet_schedule(&host->finish_tasklet);
return;
}
- queue_delayed_work(sock->wq, &host->abort_handler,
- host->timeout_jiffies);
}
/* Called from interrupt handler */
-static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock,
- unsigned int sock_irq_status)
+static void tifm_sd_signal_irq(struct tifm_dev *sock,
+ unsigned int sock_irq_status)
{
struct tifm_sd *host;
unsigned int host_status = 0, fifo_status = 0;
@@ -305,7 +325,6 @@ static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock,
spin_lock(&sock->lock);
host = mmc_priv((struct mmc_host*)tifm_get_drvdata(sock));
- cancel_delayed_work(&host->abort_handler);
if (sock_irq_status & FIFO_EVENT) {
fifo_status = readl(sock->addr + SOCK_DMA_FIFO_STATUS);
@@ -318,19 +337,14 @@ static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock,
host_status = readl(sock->addr + SOCK_MMCSD_STATUS);
writel(host_status, sock->addr + SOCK_MMCSD_STATUS);
- if (!(host->flags & HOST_REG))
- queue_work(sock->wq, &host->cmd_handler);
if (!host->req)
goto done;
if (host_status & TIFM_MMCSD_ERRMASK) {
- if (host_status & TIFM_MMCSD_CERR)
- error_code = MMC_ERR_FAILED;
- else if (host_status &
- (TIFM_MMCSD_CTO | TIFM_MMCSD_DTO))
+ if (host_status & (TIFM_MMCSD_CTO | TIFM_MMCSD_DTO))
error_code = MMC_ERR_TIMEOUT;
- else if (host_status &
- (TIFM_MMCSD_CCRC | TIFM_MMCSD_DCRC))
+ else if (host_status
+ & (TIFM_MMCSD_CCRC | TIFM_MMCSD_DCRC))
error_code = MMC_ERR_BADCRC;
writel(TIFM_FIFO_INT_SETALL,
@@ -340,12 +354,11 @@ static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock,
if (host->req->stop) {
if (host->state == SCMD) {
host->req->stop->error = error_code;
- } else if(host->state == BRS) {
+ } else if (host->state == BRS
+ || host->state == CARD
+ || host->state == FIFO) {
host->req->cmd->error = error_code;
tifm_sd_exec(host, host->req->stop);
- queue_delayed_work(sock->wq,
- &host->abort_handler,
- host->timeout_jiffies);
host->state = SCMD;
goto done;
} else {
@@ -359,8 +372,8 @@ static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock,
if (host_status & TIFM_MMCSD_CB)
host->flags |= CARD_BUSY;
- if ((host_status & TIFM_MMCSD_EOFB) &&
- (host->flags & CARD_BUSY)) {
+ if ((host_status & TIFM_MMCSD_EOFB)
+ && (host->flags & CARD_BUSY)) {
host->written_blocks++;
host->flags &= ~CARD_BUSY;
}
@@ -370,22 +383,22 @@ static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock,
tifm_sd_process_cmd(sock, host, host_status);
done:
dev_dbg(&sock->dev, "host_status %x, fifo_status %x\n",
- host_status, fifo_status);
+ host_status, fifo_status);
spin_unlock(&sock->lock);
- return sock_irq_status;
}
-static void tifm_sd_prepare_data(struct tifm_sd *card, struct mmc_command *cmd)
+static void tifm_sd_prepare_data(struct tifm_sd *host, struct mmc_command *cmd)
{
- struct tifm_dev *sock = card->dev;
+ struct tifm_dev *sock = host->dev;
unsigned int dest_cnt;
/* DMA style IO */
-
+ dev_dbg(&sock->dev, "setting dma for %d blocks\n",
+ cmd->data->blocks);
writel(TIFM_FIFO_INT_SETALL,
- sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
+ sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
writel(ilog2(cmd->data->blksz) - 2,
- sock->addr + SOCK_FIFO_PAGE_SIZE);
+ sock->addr + SOCK_FIFO_PAGE_SIZE);
writel(TIFM_FIFO_ENABLE, sock->addr + SOCK_FIFO_CONTROL);
writel(TIFM_FIFO_INTMASK, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET);
@@ -399,7 +412,7 @@ static void tifm_sd_prepare_data(struct tifm_sd *card, struct mmc_command *cmd)
if (cmd->data->flags & MMC_DATA_WRITE) {
writel(TIFM_MMCSD_TXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
writel(dest_cnt | TIFM_DMA_TX | TIFM_DMA_EN,
- sock->addr + SOCK_DMA_CONTROL);
+ sock->addr + SOCK_DMA_CONTROL);
} else {
writel(TIFM_MMCSD_RXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
writel(dest_cnt | TIFM_DMA_EN, sock->addr + SOCK_DMA_CONTROL);
@@ -407,7 +420,7 @@ static void tifm_sd_prepare_data(struct tifm_sd *card, struct mmc_command *cmd)
}
static void tifm_sd_set_data_timeout(struct tifm_sd *host,
- struct mmc_data *data)
+ struct mmc_data *data)
{
struct tifm_dev *sock = host->dev;
unsigned int data_timeout = data->timeout_clks;
@@ -416,22 +429,21 @@ static void tifm_sd_set_data_timeout(struct tifm_sd *host,
return;
data_timeout += data->timeout_ns /
- ((1000000000 / host->clk_freq) * host->clk_div);
- data_timeout *= 10; // call it fudge factor for now
+ ((1000000000UL / host->clk_freq) * host->clk_div);
if (data_timeout < 0xffff) {
- writel((~TIFM_MMCSD_DPE) &
- readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG),
- sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG);
writel(data_timeout, sock->addr + SOCK_MMCSD_DATA_TO);
+ writel((~TIFM_MMCSD_DPE)
+ & readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG),
+ sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG);
} else {
- writel(TIFM_MMCSD_DPE |
- readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG),
- sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG);
data_timeout = (data_timeout >> 10) + 1;
- if(data_timeout > 0xffff)
+ if (data_timeout > 0xffff)
data_timeout = 0; /* set to unlimited */
writel(data_timeout, sock->addr + SOCK_MMCSD_DATA_TO);
+ writel(TIFM_MMCSD_DPE
+ | readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG),
+ sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG);
}
}
@@ -474,11 +486,10 @@ static void tifm_sd_request(struct mmc_host *mmc, struct mmc_request *mrq)
}
host->req = mrq;
+ mod_timer(&host->timer, jiffies + host->timeout_jiffies);
host->state = CMD;
- queue_delayed_work(sock->wq, &host->abort_handler,
- host->timeout_jiffies);
writel(TIFM_CTRL_LED | readl(sock->addr + SOCK_CONTROL),
- sock->addr + SOCK_CONTROL);
+ sock->addr + SOCK_CONTROL);
tifm_sd_exec(host, mrq->cmd);
spin_unlock_irqrestore(&sock->lock, flags);
return;
@@ -493,9 +504,9 @@ err_out:
mmc_request_done(mmc, mrq);
}
-static void tifm_sd_end_cmd(struct work_struct *work)
+static void tifm_sd_end_cmd(unsigned long data)
{
- struct tifm_sd *host = container_of(work, struct tifm_sd, cmd_handler);
+ struct tifm_sd *host = (struct tifm_sd*)data;
struct tifm_dev *sock = host->dev;
struct mmc_host *mmc = tifm_get_drvdata(sock);
struct mmc_request *mrq;
@@ -504,6 +515,7 @@ static void tifm_sd_end_cmd(struct work_struct *work)
spin_lock_irqsave(&sock->lock, flags);
+ del_timer(&host->timer);
mrq = host->req;
host->req = NULL;
host->state = IDLE;
@@ -517,8 +529,8 @@ static void tifm_sd_end_cmd(struct work_struct *work)
r_data = mrq->cmd->data;
if (r_data) {
if (r_data->flags & MMC_DATA_WRITE) {
- r_data->bytes_xfered = host->written_blocks *
- r_data->blksz;
+ r_data->bytes_xfered = host->written_blocks
+ * r_data->blksz;
} else {
r_data->bytes_xfered = r_data->blocks -
readl(sock->addr + SOCK_MMCSD_NUM_BLOCKS) - 1;
@@ -532,7 +544,7 @@ static void tifm_sd_end_cmd(struct work_struct *work)
}
writel((~TIFM_CTRL_LED) & readl(sock->addr + SOCK_CONTROL),
- sock->addr + SOCK_CONTROL);
+ sock->addr + SOCK_CONTROL);
spin_unlock_irqrestore(&sock->lock, flags);
mmc_request_done(mmc, mrq);
@@ -544,15 +556,6 @@ static void tifm_sd_request_nodma(struct mmc_host *mmc, struct mmc_request *mrq)
struct tifm_dev *sock = host->dev;
unsigned long flags;
struct mmc_data *r_data = mrq->cmd->data;
- char *t_buffer = NULL;
-
- if (r_data) {
- t_buffer = kmap(r_data->sg->page);
- if (!t_buffer) {
- printk(KERN_ERR DRIVER_NAME ": kmap failed\n");
- goto err_out;
- }
- }
spin_lock_irqsave(&sock->lock, flags);
if (host->flags & EJECT) {
@@ -569,15 +572,14 @@ static void tifm_sd_request_nodma(struct mmc_host *mmc, struct mmc_request *mrq)
if (r_data) {
tifm_sd_set_data_timeout(host, r_data);
- host->buffer = t_buffer + r_data->sg->offset;
- host->buffer_size = mrq->cmd->data->blocks *
- mrq->cmd->data->blksz;
+ host->buffer_size = mrq->cmd->data->blocks
+ * mrq->cmd->data->blksz;
- writel(TIFM_MMCSD_BUFINT |
- readl(sock->addr + SOCK_MMCSD_INT_ENABLE),
+ writel(TIFM_MMCSD_BUFINT
+ | readl(sock->addr + SOCK_MMCSD_INT_ENABLE),
sock->addr + SOCK_MMCSD_INT_ENABLE);
- writel(((TIFM_MMCSD_FIFO_SIZE - 1) << 8) |
- (TIFM_MMCSD_FIFO_SIZE - 1),
+ writel(((TIFM_MMCSD_FIFO_SIZE - 1) << 8)
+ | (TIFM_MMCSD_FIFO_SIZE - 1),
sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
host->written_blocks = 0;
@@ -588,26 +590,22 @@ static void tifm_sd_request_nodma(struct mmc_host *mmc, struct mmc_request *mrq)
}
host->req = mrq;
+ mod_timer(&host->timer, jiffies + host->timeout_jiffies);
host->state = CMD;
- queue_delayed_work(sock->wq, &host->abort_handler,
- host->timeout_jiffies);
writel(TIFM_CTRL_LED | readl(sock->addr + SOCK_CONTROL),
- sock->addr + SOCK_CONTROL);
+ sock->addr + SOCK_CONTROL);
tifm_sd_exec(host, mrq->cmd);
spin_unlock_irqrestore(&sock->lock, flags);
return;
err_out:
- if (t_buffer)
- kunmap(r_data->sg->page);
-
mrq->cmd->error = MMC_ERR_TIMEOUT;
mmc_request_done(mmc, mrq);
}
-static void tifm_sd_end_cmd_nodma(struct work_struct *work)
+static void tifm_sd_end_cmd_nodma(unsigned long data)
{
- struct tifm_sd *host = container_of(work, struct tifm_sd, cmd_handler);
+ struct tifm_sd *host = (struct tifm_sd*)data;
struct tifm_dev *sock = host->dev;
struct mmc_host *mmc = tifm_get_drvdata(sock);
struct mmc_request *mrq;
@@ -616,6 +614,7 @@ static void tifm_sd_end_cmd_nodma(struct work_struct *work)
spin_lock_irqsave(&sock->lock, flags);
+ del_timer(&host->timer);
mrq = host->req;
host->req = NULL;
host->state = IDLE;
@@ -633,8 +632,8 @@ static void tifm_sd_end_cmd_nodma(struct work_struct *work)
sock->addr + SOCK_MMCSD_INT_ENABLE);
if (r_data->flags & MMC_DATA_WRITE) {
- r_data->bytes_xfered = host->written_blocks *
- r_data->blksz;
+ r_data->bytes_xfered = host->written_blocks
+ * r_data->blksz;
} else {
r_data->bytes_xfered = r_data->blocks -
readl(sock->addr + SOCK_MMCSD_NUM_BLOCKS) - 1;
@@ -642,29 +641,44 @@ static void tifm_sd_end_cmd_nodma(struct work_struct *work)
r_data->bytes_xfered += r_data->blksz -
readl(sock->addr + SOCK_MMCSD_BLOCK_LEN) + 1;
}
- host->buffer = NULL;
host->buffer_pos = 0;
host->buffer_size = 0;
}
writel((~TIFM_CTRL_LED) & readl(sock->addr + SOCK_CONTROL),
- sock->addr + SOCK_CONTROL);
+ sock->addr + SOCK_CONTROL);
spin_unlock_irqrestore(&sock->lock, flags);
- if (r_data)
- kunmap(r_data->sg->page);
-
mmc_request_done(mmc, mrq);
}
-static void tifm_sd_abort(struct work_struct *work)
+static void tifm_sd_terminate(struct tifm_sd *host)
+{
+ struct tifm_dev *sock = host->dev;
+ unsigned long flags;
+
+ writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE);
+ mmiowb();
+ spin_lock_irqsave(&sock->lock, flags);
+ host->flags |= EJECT;
+ if (host->req) {
+ writel(TIFM_FIFO_INT_SETALL,
+ sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
+ writel(0, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET);
+ tasklet_schedule(&host->finish_tasklet);
+ }
+ spin_unlock_irqrestore(&sock->lock, flags);
+}
+
+static void tifm_sd_abort(unsigned long data)
{
- struct tifm_sd *host =
- container_of(work, struct tifm_sd, abort_handler.work);
+ struct tifm_sd *host = (struct tifm_sd*)data;
printk(KERN_ERR DRIVER_NAME
- ": card failed to respond for a long period of time");
+ ": card failed to respond for a long period of time");
+
+ tifm_sd_terminate(host);
tifm_eject(host->dev);
}
@@ -683,9 +697,9 @@ static void tifm_sd_ios(struct mmc_host *mmc, struct mmc_ios *ios)
writel(TIFM_MMCSD_4BBUS | readl(sock->addr + SOCK_MMCSD_CONFIG),
sock->addr + SOCK_MMCSD_CONFIG);
} else {
- writel((~TIFM_MMCSD_4BBUS) &
- readl(sock->addr + SOCK_MMCSD_CONFIG),
- sock->addr + SOCK_MMCSD_CONFIG);
+ writel((~TIFM_MMCSD_4BBUS)
+ & readl(sock->addr + SOCK_MMCSD_CONFIG),
+ sock->addr + SOCK_MMCSD_CONFIG);
}
if (ios->clock) {
@@ -704,23 +718,24 @@ static void tifm_sd_ios(struct mmc_host *mmc, struct mmc_ios *ios)
if ((20000000 / clk_div1) > (24000000 / clk_div2)) {
host->clk_freq = 20000000;
host->clk_div = clk_div1;
- writel((~TIFM_CTRL_FAST_CLK) &
- readl(sock->addr + SOCK_CONTROL),
- sock->addr + SOCK_CONTROL);
+ writel((~TIFM_CTRL_FAST_CLK)
+ & readl(sock->addr + SOCK_CONTROL),
+ sock->addr + SOCK_CONTROL);
} else {
host->clk_freq = 24000000;
host->clk_div = clk_div2;
- writel(TIFM_CTRL_FAST_CLK |
- readl(sock->addr + SOCK_CONTROL),
- sock->addr + SOCK_CONTROL);
+ writel(TIFM_CTRL_FAST_CLK
+ | readl(sock->addr + SOCK_CONTROL),
+ sock->addr + SOCK_CONTROL);
}
} else {
host->clk_div = 0;
}
host->clk_div &= TIFM_MMCSD_CLKMASK;
- writel(host->clk_div | ((~TIFM_MMCSD_CLKMASK) &
- readl(sock->addr + SOCK_MMCSD_CONFIG)),
- sock->addr + SOCK_MMCSD_CONFIG);
+ writel(host->clk_div
+ | ((~TIFM_MMCSD_CLKMASK)
+ & readl(sock->addr + SOCK_MMCSD_CONFIG)),
+ sock->addr + SOCK_MMCSD_CONFIG);
if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN)
host->flags |= OPENDRAIN;
@@ -734,7 +749,7 @@ static void tifm_sd_ios(struct mmc_host *mmc, struct mmc_ios *ios)
// allow removal.
if ((host->flags & EJECT) && ios->power_mode == MMC_POWER_OFF) {
host->flags |= EJECT_DONE;
- wake_up_all(&host->can_eject);
+ wake_up_all(&host->notify);
}
spin_unlock_irqrestore(&sock->lock, flags);
@@ -762,20 +777,67 @@ static struct mmc_host_ops tifm_sd_ops = {
.get_ro = tifm_sd_ro
};
-static void tifm_sd_register_host(struct work_struct *work)
+static int tifm_sd_initialize_host(struct tifm_sd *host)
{
- struct tifm_sd *host = container_of(work, struct tifm_sd, cmd_handler);
+ int rc;
+ unsigned int host_status = 0;
struct tifm_dev *sock = host->dev;
- struct mmc_host *mmc = tifm_get_drvdata(sock);
- unsigned long flags;
- spin_lock_irqsave(&sock->lock, flags);
- host->flags |= HOST_REG;
- PREPARE_WORK(&host->cmd_handler,
- no_dma ? tifm_sd_end_cmd_nodma : tifm_sd_end_cmd);
- spin_unlock_irqrestore(&sock->lock, flags);
- dev_dbg(&sock->dev, "adding host\n");
- mmc_add_host(mmc);
+ writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE);
+ mmiowb();
+ host->clk_div = 61;
+ host->clk_freq = 20000000;
+ writel(TIFM_MMCSD_RESET, sock->addr + SOCK_MMCSD_SYSTEM_CONTROL);
+ writel(host->clk_div | TIFM_MMCSD_POWER,
+ sock->addr + SOCK_MMCSD_CONFIG);
+
+ /* wait up to 0.51 sec for reset */
+ for (rc = 2; rc <= 256; rc <<= 1) {
+ if (1 & readl(sock->addr + SOCK_MMCSD_SYSTEM_STATUS)) {
+ rc = 0;
+ break;
+ }
+ msleep(rc);
+ }
+
+ if (rc) {
+ printk(KERN_ERR DRIVER_NAME
+ ": controller failed to reset\n");
+ return -ENODEV;
+ }
+
+ writel(0, sock->addr + SOCK_MMCSD_NUM_BLOCKS);
+ writel(host->clk_div | TIFM_MMCSD_POWER,
+ sock->addr + SOCK_MMCSD_CONFIG);
+ writel(TIFM_MMCSD_RXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
+
+ // command timeout fixed to 64 clocks for now
+ writel(64, sock->addr + SOCK_MMCSD_COMMAND_TO);
+ writel(TIFM_MMCSD_INAB, sock->addr + SOCK_MMCSD_COMMAND);
+
+ /* INAB should take much less than reset */
+ for (rc = 1; rc <= 16; rc <<= 1) {
+ host_status = readl(sock->addr + SOCK_MMCSD_STATUS);
+ writel(host_status, sock->addr + SOCK_MMCSD_STATUS);
+ if (!(host_status & TIFM_MMCSD_ERRMASK)
+ && (host_status & TIFM_MMCSD_EOC)) {
+ rc = 0;
+ break;
+ }
+ msleep(rc);
+ }
+
+ if (rc) {
+ printk(KERN_ERR DRIVER_NAME
+ ": card not ready - probe failed on initialization\n");
+ return -ENODEV;
+ }
+
+ writel(TIFM_MMCSD_DATAMASK | TIFM_MMCSD_ERRMASK,
+ sock->addr + SOCK_MMCSD_INT_ENABLE);
+ mmiowb();
+
+ return 0;
}
static int tifm_sd_probe(struct tifm_dev *sock)
@@ -784,8 +846,8 @@ static int tifm_sd_probe(struct tifm_dev *sock)
struct tifm_sd *host;
int rc = -EIO;
- if (!(TIFM_SOCK_STATE_OCCUPIED &
- readl(sock->addr + SOCK_PRESENT_STATE))) {
+ if (!(TIFM_SOCK_STATE_OCCUPIED
+ & readl(sock->addr + SOCK_PRESENT_STATE))) {
printk(KERN_WARNING DRIVER_NAME ": card gone, unexpectedly\n");
return rc;
}
@@ -795,109 +857,99 @@ static int tifm_sd_probe(struct tifm_dev *sock)
return -ENOMEM;
host = mmc_priv(mmc);
- host->dev = sock;
- host->clk_div = 61;
- init_waitqueue_head(&host->can_eject);
- INIT_WORK(&host->cmd_handler, tifm_sd_register_host);
- INIT_DELAYED_WORK(&host->abort_handler, tifm_sd_abort);
-
tifm_set_drvdata(sock, mmc);
- sock->signal_irq = tifm_sd_signal_irq;
-
- host->clk_freq = 20000000;
+ host->dev = sock;
host->timeout_jiffies = msecs_to_jiffies(1000);
+ init_waitqueue_head(&host->notify);
+ tasklet_init(&host->finish_tasklet,
+ no_dma ? tifm_sd_end_cmd_nodma : tifm_sd_end_cmd,
+ (unsigned long)host);
+ setup_timer(&host->timer, tifm_sd_abort, (unsigned long)host);
+
tifm_sd_ops.request = no_dma ? tifm_sd_request_nodma : tifm_sd_request;
mmc->ops = &tifm_sd_ops;
mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
- mmc->caps = MMC_CAP_4_BIT_DATA;
+ mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE;
mmc->f_min = 20000000 / 60;
mmc->f_max = 24000000;
mmc->max_hw_segs = 1;
mmc->max_phys_segs = 1;
- mmc->max_sectors = 127;
- mmc->max_seg_size = mmc->max_sectors << 11; //2k maximum hw block length
-
- writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE);
- writel(TIFM_MMCSD_RESET, sock->addr + SOCK_MMCSD_SYSTEM_CONTROL);
- writel(host->clk_div | TIFM_MMCSD_POWER,
- sock->addr + SOCK_MMCSD_CONFIG);
+ // limited by DMA counter - it's safer to stick with
+ // block counter has 11 bits though
+ mmc->max_blk_count = 256;
+ // 2k maximum hw block length
+ mmc->max_blk_size = 2048;
+ mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
+ mmc->max_seg_size = mmc->max_req_size;
+ sock->signal_irq = tifm_sd_signal_irq;
+ rc = tifm_sd_initialize_host(host);
- for (rc = 0; rc < 50; rc++) {
- /* Wait for reset ack */
- if (1 & readl(sock->addr + SOCK_MMCSD_SYSTEM_STATUS)) {
- rc = 0;
- break;
- }
- msleep(10);
- }
+ if (!rc)
+ rc = mmc_add_host(mmc);
+ if (rc)
+ goto out_free_mmc;
- if (rc) {
- printk(KERN_ERR DRIVER_NAME
- ": card not ready - probe failed\n");
- mmc_free_host(mmc);
- return -ENODEV;
- }
+ return 0;
+out_free_mmc:
+ mmc_free_host(mmc);
+ return rc;
+}
- writel(0, sock->addr + SOCK_MMCSD_NUM_BLOCKS);
- writel(host->clk_div | TIFM_MMCSD_POWER,
- sock->addr + SOCK_MMCSD_CONFIG);
- writel(TIFM_MMCSD_RXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
- writel(TIFM_MMCSD_DATAMASK | TIFM_MMCSD_ERRMASK,
- sock->addr + SOCK_MMCSD_INT_ENABLE);
+static void tifm_sd_remove(struct tifm_dev *sock)
+{
+ struct mmc_host *mmc = tifm_get_drvdata(sock);
+ struct tifm_sd *host = mmc_priv(mmc);
- writel(64, sock->addr + SOCK_MMCSD_COMMAND_TO); // command timeout 64 clocks for now
- writel(TIFM_MMCSD_INAB, sock->addr + SOCK_MMCSD_COMMAND);
- writel(host->clk_div | TIFM_MMCSD_POWER,
- sock->addr + SOCK_MMCSD_CONFIG);
+ del_timer_sync(&host->timer);
+ tifm_sd_terminate(host);
+ wait_event_timeout(host->notify, host->flags & EJECT_DONE,
+ host->timeout_jiffies);
+ tasklet_kill(&host->finish_tasklet);
+ mmc_remove_host(mmc);
- queue_delayed_work(sock->wq, &host->abort_handler,
- host->timeout_jiffies);
+ /* The meaning of the bit majority in this constant is unknown. */
+ writel(0xfff8 & readl(sock->addr + SOCK_CONTROL),
+ sock->addr + SOCK_CONTROL);
- return 0;
+ tifm_set_drvdata(sock, NULL);
+ mmc_free_host(mmc);
}
-static int tifm_sd_host_is_down(struct tifm_dev *sock)
+#ifdef CONFIG_PM
+
+static int tifm_sd_suspend(struct tifm_dev *sock, pm_message_t state)
{
struct mmc_host *mmc = tifm_get_drvdata(sock);
- struct tifm_sd *host = mmc_priv(mmc);
- unsigned long flags;
- int rc = 0;
+ int rc;
- spin_lock_irqsave(&sock->lock, flags);
- rc = (host->flags & EJECT_DONE);
- spin_unlock_irqrestore(&sock->lock, flags);
+ rc = mmc_suspend_host(mmc, state);
+ /* The meaning of the bit majority in this constant is unknown. */
+ writel(0xfff8 & readl(sock->addr + SOCK_CONTROL),
+ sock->addr + SOCK_CONTROL);
return rc;
}
-static void tifm_sd_remove(struct tifm_dev *sock)
+static int tifm_sd_resume(struct tifm_dev *sock)
{
struct mmc_host *mmc = tifm_get_drvdata(sock);
struct tifm_sd *host = mmc_priv(mmc);
- unsigned long flags;
- spin_lock_irqsave(&sock->lock, flags);
- host->flags |= EJECT;
- if (host->req)
- queue_work(sock->wq, &host->cmd_handler);
- spin_unlock_irqrestore(&sock->lock, flags);
- wait_event_timeout(host->can_eject, tifm_sd_host_is_down(sock),
- host->timeout_jiffies);
+ if (sock->media_id != FM_SD
+ || tifm_sd_initialize_host(host)) {
+ tifm_eject(sock);
+ return 0;
+ } else {
+ return mmc_resume_host(mmc);
+ }
+}
- if (host->flags & HOST_REG)
- mmc_remove_host(mmc);
+#else
- /* The meaning of the bit majority in this constant is unknown. */
- writel(0xfff8 & readl(sock->addr + SOCK_CONTROL),
- sock->addr + SOCK_CONTROL);
- writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE);
- writel(TIFM_FIFO_INT_SETALL,
- sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
- writel(0, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET);
+#define tifm_sd_suspend NULL
+#define tifm_sd_resume NULL
- tifm_set_drvdata(sock, NULL);
- mmc_free_host(mmc);
-}
+#endif /* CONFIG_PM */
static tifm_media_id tifm_sd_id_tbl[] = {
FM_SD, 0
@@ -910,7 +962,9 @@ static struct tifm_driver tifm_sd_driver = {
},
.id_table = tifm_sd_id_tbl,
.probe = tifm_sd_probe,
- .remove = tifm_sd_remove
+ .remove = tifm_sd_remove,
+ .suspend = tifm_sd_suspend,
+ .resume = tifm_sd_resume
};
static int __init tifm_sd_init(void)
diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c
index 7a282672f8e..05ccfc43168 100644
--- a/drivers/mmc/wbsd.c
+++ b/drivers/mmc/wbsd.c
@@ -1,7 +1,7 @@
/*
* linux/drivers/mmc/wbsd.c - Winbond W83L51xD SD/MMC driver
*
- * Copyright (C) 2004-2005 Pierre Ossman, All Rights Reserved.
+ * Copyright (C) 2004-2006 Pierre Ossman, 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
@@ -42,7 +42,6 @@
#include "wbsd.h"
#define DRIVER_NAME "wbsd"
-#define DRIVER_VERSION "1.6"
#define DBG(x...) \
pr_debug(DRIVER_NAME ": " x)
@@ -272,16 +271,9 @@ static inline int wbsd_next_sg(struct wbsd_host *host)
return host->num_sg;
}
-static inline char *wbsd_kmap_sg(struct wbsd_host *host)
+static inline char *wbsd_sg_to_buffer(struct wbsd_host *host)
{
- host->mapped_sg = kmap_atomic(host->cur_sg->page, KM_BIO_SRC_IRQ) +
- host->cur_sg->offset;
- return host->mapped_sg;
-}
-
-static inline void wbsd_kunmap_sg(struct wbsd_host *host)
-{
- kunmap_atomic(host->mapped_sg, KM_BIO_SRC_IRQ);
+ return page_address(host->cur_sg->page) + host->cur_sg->offset;
}
static inline void wbsd_sg_to_dma(struct wbsd_host *host, struct mmc_data *data)
@@ -302,12 +294,11 @@ static inline void wbsd_sg_to_dma(struct wbsd_host *host, struct mmc_data *data)
* we do not transfer too much.
*/
for (i = 0; i < len; i++) {
- sgbuf = kmap_atomic(sg[i].page, KM_BIO_SRC_IRQ) + sg[i].offset;
+ sgbuf = page_address(sg[i].page) + sg[i].offset;
if (size < sg[i].length)
memcpy(dmabuf, sgbuf, size);
else
memcpy(dmabuf, sgbuf, sg[i].length);
- kunmap_atomic(sgbuf, KM_BIO_SRC_IRQ);
dmabuf += sg[i].length;
if (size < sg[i].length)
@@ -347,12 +338,11 @@ static inline void wbsd_dma_to_sg(struct wbsd_host *host, struct mmc_data *data)
* we do not transfer too much.
*/
for (i = 0; i < len; i++) {
- sgbuf = kmap_atomic(sg[i].page, KM_BIO_SRC_IRQ) + sg[i].offset;
+ sgbuf = page_address(sg[i].page) + sg[i].offset;
if (size < sg[i].length)
memcpy(sgbuf, dmabuf, size);
else
memcpy(sgbuf, dmabuf, sg[i].length);
- kunmap_atomic(sgbuf, KM_BIO_SRC_IRQ);
dmabuf += sg[i].length;
if (size < sg[i].length)
@@ -497,7 +487,7 @@ static void wbsd_empty_fifo(struct wbsd_host *host)
if (data->bytes_xfered == host->size)
return;
- buffer = wbsd_kmap_sg(host) + host->offset;
+ buffer = wbsd_sg_to_buffer(host) + host->offset;
/*
* Drain the fifo. This has a tendency to loop longer
@@ -526,17 +516,13 @@ static void wbsd_empty_fifo(struct wbsd_host *host)
/*
* Transfer done?
*/
- if (data->bytes_xfered == host->size) {
- wbsd_kunmap_sg(host);
+ if (data->bytes_xfered == host->size)
return;
- }
/*
* End of scatter list entry?
*/
if (host->remain == 0) {
- wbsd_kunmap_sg(host);
-
/*
* Get next entry. Check if last.
*/
@@ -554,13 +540,11 @@ static void wbsd_empty_fifo(struct wbsd_host *host)
return;
}
- buffer = wbsd_kmap_sg(host);
+ buffer = wbsd_sg_to_buffer(host);
}
}
}
- wbsd_kunmap_sg(host);
-
/*
* This is a very dirty hack to solve a
* hardware problem. The chip doesn't trigger
@@ -583,7 +567,7 @@ static void wbsd_fill_fifo(struct wbsd_host *host)
if (data->bytes_xfered == host->size)
return;
- buffer = wbsd_kmap_sg(host) + host->offset;
+ buffer = wbsd_sg_to_buffer(host) + host->offset;
/*
* Fill the fifo. This has a tendency to loop longer
@@ -612,17 +596,13 @@ static void wbsd_fill_fifo(struct wbsd_host *host)
/*
* Transfer done?
*/
- if (data->bytes_xfered == host->size) {
- wbsd_kunmap_sg(host);
+ if (data->bytes_xfered == host->size)
return;
- }
/*
* End of scatter list entry?
*/
if (host->remain == 0) {
- wbsd_kunmap_sg(host);
-
/*
* Get next entry. Check if last.
*/
@@ -640,13 +620,11 @@ static void wbsd_fill_fifo(struct wbsd_host *host)
return;
}
- buffer = wbsd_kmap_sg(host);
+ buffer = wbsd_sg_to_buffer(host);
}
}
}
- wbsd_kunmap_sg(host);
-
/*
* The controller stops sending interrupts for
* 'FIFO empty' under certain conditions. So we
@@ -910,6 +888,45 @@ static void wbsd_request(struct mmc_host *mmc, struct mmc_request *mrq)
*/
if (cmd->data && (cmd->error == MMC_ERR_NONE)) {
/*
+ * The hardware is so delightfully stupid that it has a list
+ * of "data" commands. If a command isn't on this list, it'll
+ * just go back to the idle state and won't send any data
+ * interrupts.
+ */
+ switch (cmd->opcode) {
+ case 11:
+ case 17:
+ case 18:
+ case 20:
+ case 24:
+ case 25:
+ case 26:
+ case 27:
+ case 30:
+ case 42:
+ case 56:
+ break;
+
+ /* ACMDs. We don't keep track of state, so we just treat them
+ * like any other command. */
+ case 51:
+ break;
+
+ default:
+#ifdef CONFIG_MMC_DEBUG
+ printk(KERN_WARNING "%s: Data command %d is not "
+ "supported by this controller.\n",
+ mmc_hostname(host->mmc), cmd->opcode);
+#endif
+ cmd->data->error = MMC_ERR_INVALID;
+
+ if (cmd->data->stop)
+ wbsd_send_command(host, cmd->data->stop);
+
+ goto done;
+ };
+
+ /*
* Dirty fix for hardware bug.
*/
if (host->dma == -1)
@@ -1343,16 +1360,27 @@ static int __devinit wbsd_alloc_mmc(struct device *dev)
mmc->max_phys_segs = 128;
/*
- * Maximum number of sectors in one transfer. Also limited by 64kB
- * buffer.
+ * Maximum request size. Also limited by 64KiB buffer.
*/
- mmc->max_sectors = 128;
+ mmc->max_req_size = 65536;
/*
* Maximum segment size. Could be one segment with the maximum number
- * of segments.
+ * of bytes.
+ */
+ mmc->max_seg_size = mmc->max_req_size;
+
+ /*
+ * Maximum block size. We have 12 bits (= 4095) but have to subtract
+ * space for CRC. So the maximum is 4095 - 4*2 = 4087.
+ */
+ mmc->max_blk_size = 4087;
+
+ /*
+ * Maximum block count. There is no real limit so the maximum
+ * request size will be the only restriction.
*/
- mmc->max_seg_size = mmc->max_sectors * 512;
+ mmc->max_blk_count = mmc->max_req_size;
dev_set_drvdata(dev, mmc);
@@ -2071,8 +2099,7 @@ static int __init wbsd_drv_init(void)
int result;
printk(KERN_INFO DRIVER_NAME
- ": Winbond W83L51xD SD/MMC card interface driver, "
- DRIVER_VERSION "\n");
+ ": Winbond W83L51xD SD/MMC card interface driver\n");
printk(KERN_INFO DRIVER_NAME ": Copyright(c) Pierre Ossman\n");
#ifdef CONFIG_PNP
@@ -2136,7 +2163,6 @@ module_param(dma, int, 0444);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Pierre Ossman <drzeus@drzeus.cx>");
MODULE_DESCRIPTION("Winbond W83L51xD SD/MMC card interface driver");
-MODULE_VERSION(DRIVER_VERSION);
#ifdef CONFIG_PNP
MODULE_PARM_DESC(nopnp, "Scan for device instead of relying on PNP. (default 0)");
diff --git a/drivers/mmc/wbsd.h b/drivers/mmc/wbsd.h
index 6072993f01e..d06718b0e2a 100644
--- a/drivers/mmc/wbsd.h
+++ b/drivers/mmc/wbsd.h
@@ -154,7 +154,6 @@ struct wbsd_host
struct scatterlist* cur_sg; /* Current SG entry */
unsigned int num_sg; /* Number of entries left */
- void* mapped_sg; /* vaddr of mapped sg */
unsigned int offset; /* Offset into current entry */
unsigned int remain; /* Data left in curren entry */
diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c
index f69184a92eb..f334959a335 100644
--- a/drivers/mtd/chips/cfi_cmdset_0001.c
+++ b/drivers/mtd/chips/cfi_cmdset_0001.c
@@ -397,9 +397,23 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary)
cfi_fixup(mtd, fixup_table);
for (i=0; i< cfi->numchips; i++) {
- cfi->chips[i].word_write_time = 1<<cfi->cfiq->WordWriteTimeoutTyp;
- cfi->chips[i].buffer_write_time = 1<<cfi->cfiq->BufWriteTimeoutTyp;
- cfi->chips[i].erase_time = 1000<<cfi->cfiq->BlockEraseTimeoutTyp;
+ if (cfi->cfiq->WordWriteTimeoutTyp)
+ cfi->chips[i].word_write_time =
+ 1<<cfi->cfiq->WordWriteTimeoutTyp;
+ else
+ cfi->chips[i].word_write_time = 50000;
+
+ if (cfi->cfiq->BufWriteTimeoutTyp)
+ cfi->chips[i].buffer_write_time =
+ 1<<cfi->cfiq->BufWriteTimeoutTyp;
+ /* No default; if it isn't specified, we won't use it */
+
+ if (cfi->cfiq->BlockEraseTimeoutTyp)
+ cfi->chips[i].erase_time =
+ 1000<<cfi->cfiq->BlockEraseTimeoutTyp;
+ else
+ cfi->chips[i].erase_time = 2000000;
+
cfi->chips[i].ref_point_counter = 0;
init_waitqueue_head(&(cfi->chips[i].wq));
}
@@ -546,13 +560,11 @@ static int cfi_intelext_partition_fixup(struct mtd_info *mtd,
struct cfi_intelext_programming_regioninfo *prinfo;
prinfo = (struct cfi_intelext_programming_regioninfo *)&extp->extra[offs];
mtd->writesize = cfi->interleave << prinfo->ProgRegShift;
- MTD_PROGREGION_CTRLMODE_VALID(mtd) = cfi->interleave * prinfo->ControlValid;
- MTD_PROGREGION_CTRLMODE_INVALID(mtd) = cfi->interleave * prinfo->ControlInvalid;
mtd->flags &= ~MTD_BIT_WRITEABLE;
printk(KERN_DEBUG "%s: program region size/ctrl_valid/ctrl_inval = %d/%d/%d\n",
map->name, mtd->writesize,
- MTD_PROGREGION_CTRLMODE_VALID(mtd),
- MTD_PROGREGION_CTRLMODE_INVALID(mtd));
+ cfi->interleave * prinfo->ControlValid,
+ cfi->interleave * prinfo->ControlInvalid);
}
/*
diff --git a/drivers/mtd/chips/cfi_cmdset_0020.c b/drivers/mtd/chips/cfi_cmdset_0020.c
index d56849f5f10..69d49e0250a 100644
--- a/drivers/mtd/chips/cfi_cmdset_0020.c
+++ b/drivers/mtd/chips/cfi_cmdset_0020.c
@@ -662,7 +662,7 @@ static int cfi_staa_write_buffers (struct mtd_info *mtd, loff_t to,
* a small buffer for this.
* XXX: If the buffer size is not a multiple of 2, this will break
*/
-#define ECCBUF_SIZE (mtd->eccsize)
+#define ECCBUF_SIZE (mtd->writesize)
#define ECCBUF_DIV(x) ((x) & ~(ECCBUF_SIZE - 1))
#define ECCBUF_MOD(x) ((x) & (ECCBUF_SIZE - 1))
static int
diff --git a/drivers/mtd/chips/cfi_util.c b/drivers/mtd/chips/cfi_util.c
index d8e7a026ba5..2e51496c248 100644
--- a/drivers/mtd/chips/cfi_util.c
+++ b/drivers/mtd/chips/cfi_util.c
@@ -14,7 +14,6 @@
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <asm/io.h>
#include <asm/byteorder.h>
diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c
index 6d917a4daa9..f9f2ce7806b 100644
--- a/drivers/mtd/devices/block2mtd.c
+++ b/drivers/mtd/devices/block2mtd.c
@@ -278,7 +278,8 @@ static void block2mtd_free_device(struct block2mtd_dev *dev)
kfree(dev->mtd.name);
if (dev->blkdev) {
- invalidate_inode_pages(dev->blkdev->bd_inode->i_mapping);
+ invalidate_mapping_pages(dev->blkdev->bd_inode->i_mapping,
+ 0, -1);
close_bdev_excl(dev->blkdev);
}
diff --git a/drivers/mtd/devices/doc2000.c b/drivers/mtd/devices/doc2000.c
index 603a7951ac9..8a0c4dec635 100644
--- a/drivers/mtd/devices/doc2000.c
+++ b/drivers/mtd/devices/doc2000.c
@@ -569,7 +569,6 @@ void DoC2k_init(struct mtd_info *mtd)
mtd->type = MTD_NANDFLASH;
mtd->flags = MTD_CAP_NANDFLASH;
- mtd->ecctype = MTD_ECC_RS_DiskOnChip;
mtd->size = 0;
mtd->erasesize = 0;
mtd->writesize = 512;
diff --git a/drivers/mtd/devices/doc2001.c b/drivers/mtd/devices/doc2001.c
index 0e2a9326f71..6f368aec5d5 100644
--- a/drivers/mtd/devices/doc2001.c
+++ b/drivers/mtd/devices/doc2001.c
@@ -16,7 +16,6 @@
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/slab.h>
-#include <linux/sched.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/bitops.h>
@@ -349,7 +348,6 @@ void DoCMil_init(struct mtd_info *mtd)
mtd->type = MTD_NANDFLASH;
mtd->flags = MTD_CAP_NANDFLASH;
- mtd->ecctype = MTD_ECC_RS_DiskOnChip;
mtd->size = 0;
/* FIXME: erase size is not always 8KiB */
diff --git a/drivers/mtd/devices/doc2001plus.c b/drivers/mtd/devices/doc2001plus.c
index 92dbb47f2ac..88ba82df0fb 100644
--- a/drivers/mtd/devices/doc2001plus.c
+++ b/drivers/mtd/devices/doc2001plus.c
@@ -20,7 +20,6 @@
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/slab.h>
-#include <linux/sched.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/bitops.h>
@@ -473,7 +472,6 @@ void DoCMilPlus_init(struct mtd_info *mtd)
mtd->type = MTD_NANDFLASH;
mtd->flags = MTD_CAP_NANDFLASH;
- mtd->ecctype = MTD_ECC_RS_DiskOnChip;
mtd->size = 0;
mtd->erasesize = 0;
diff --git a/drivers/mtd/devices/docecc.c b/drivers/mtd/devices/docecc.c
index cd3db72bef9..52b5d638077 100644
--- a/drivers/mtd/devices/docecc.c
+++ b/drivers/mtd/devices/docecc.c
@@ -32,7 +32,6 @@
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/slab.h>
-#include <linux/sched.h>
#include <linux/init.h>
#include <linux/types.h>
diff --git a/drivers/mtd/devices/pmc551.c b/drivers/mtd/devices/pmc551.c
index 354e1657cc2..a4873ab84e6 100644
--- a/drivers/mtd/devices/pmc551.c
+++ b/drivers/mtd/devices/pmc551.c
@@ -86,7 +86,6 @@
#include <linux/module.h>
#include <asm/uaccess.h>
#include <linux/types.h>
-#include <linux/sched.h>
#include <linux/init.h>
#include <linux/ptrace.h>
#include <linux/slab.h>
diff --git a/drivers/mtd/devices/slram.c b/drivers/mtd/devices/slram.c
index 5f49248a485..d293add1857 100644
--- a/drivers/mtd/devices/slram.c
+++ b/drivers/mtd/devices/slram.c
@@ -35,7 +35,6 @@
#include <asm/uaccess.h>
#include <linux/types.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/string.h>
diff --git a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c
index 24235d4f1d2..c815d0f3857 100644
--- a/drivers/mtd/ftl.c
+++ b/drivers/mtd/ftl.c
@@ -61,7 +61,6 @@
/*#define PSYCHO_DEBUG */
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/string.h>
diff --git a/drivers/mtd/inftlmount.c b/drivers/mtd/inftlmount.c
index 8f6006f1a51..acf3ba22329 100644
--- a/drivers/mtd/inftlmount.c
+++ b/drivers/mtd/inftlmount.c
@@ -34,7 +34,6 @@
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/slab.h>
-#include <linux/sched.h>
#include <linux/init.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nftl.h>
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
index f457315579d..bbf0553bdb2 100644
--- a/drivers/mtd/maps/Kconfig
+++ b/drivers/mtd/maps/Kconfig
@@ -204,7 +204,7 @@ config MTD_ESB2ROM
config MTD_CK804XROM
tristate "BIOS flash chip on Nvidia CK804"
- depends on X86 && MTD_JEDECPROBE
+ depends on X86 && MTD_JEDECPROBE && PCI
help
Support for treating the BIOS flash chip on nvidia motherboards
as an MTD device - with this you can reprogram your BIOS.
diff --git a/drivers/mtd/maps/amd76xrom.c b/drivers/mtd/maps/amd76xrom.c
index 78b671172bb..728aed6ad72 100644
--- a/drivers/mtd/maps/amd76xrom.c
+++ b/drivers/mtd/maps/amd76xrom.c
@@ -205,8 +205,8 @@ static int __devinit amd76xrom_init_one (struct pci_dev *pdev,
(((unsigned long)(window->virt)) + offset);
map->map.size = 0xffffffffUL - map_top + 1UL;
/* Set the name of the map to the address I am trying */
- sprintf(map->map_name, "%s @%08lx",
- MOD_NAME, map->map.phys);
+ sprintf(map->map_name, "%s @%08Lx",
+ MOD_NAME, (unsigned long long)map->map.phys);
/* There is no generic VPP support */
for(map->map.bankwidth = 32; map->map.bankwidth;
diff --git a/drivers/mtd/maps/ck804xrom.c b/drivers/mtd/maps/ck804xrom.c
index 238d42e88ec..3d4a4d8ac78 100644
--- a/drivers/mtd/maps/ck804xrom.c
+++ b/drivers/mtd/maps/ck804xrom.c
@@ -207,8 +207,8 @@ static int __devinit ck804xrom_init_one (struct pci_dev *pdev,
(((unsigned long)(window->virt)) + offset);
map->map.size = 0xffffffffUL - map_top + 1UL;
/* Set the name of the map to the address I am trying */
- sprintf(map->map_name, "%s @%08lx",
- MOD_NAME, map->map.phys);
+ sprintf(map->map_name, "%s @%08Lx",
+ MOD_NAME, (unsigned long long)map->map.phys);
/* There is no generic VPP support */
for(map->map.bankwidth = 32; map->map.bankwidth;
@@ -327,7 +327,7 @@ static int __init init_ck804xrom(void)
pdev = NULL;
for(id = ck804xrom_pci_tbl; id->vendor; id++) {
- pdev = pci_find_device(id->vendor, id->device, NULL);
+ pdev = pci_get_device(id->vendor, id->device, NULL);
if (pdev)
break;
}
diff --git a/drivers/mtd/maps/esb2rom.c b/drivers/mtd/maps/esb2rom.c
index a9d808a617c..0bc013fd66a 100644
--- a/drivers/mtd/maps/esb2rom.c
+++ b/drivers/mtd/maps/esb2rom.c
@@ -289,8 +289,8 @@ static int __devinit esb2rom_init_one(struct pci_dev *pdev,
(((unsigned long)(window->virt)) + offset);
map->map.size = 0xffffffffUL - map_top + 1UL;
/* Set the name of the map to the address I am trying */
- sprintf(map->map_name, "%s @%08lx",
- MOD_NAME, map->map.phys);
+ sprintf(map->map_name, "%s @%08Lx",
+ MOD_NAME, (unsigned long long)map->map.phys);
/* Firmware hubs only use vpp when being programmed
* in a factory setting. So in-place programming
diff --git a/drivers/mtd/maps/ichxrom.c b/drivers/mtd/maps/ichxrom.c
index 2bb3e63606e..2c884c49e84 100644
--- a/drivers/mtd/maps/ichxrom.c
+++ b/drivers/mtd/maps/ichxrom.c
@@ -227,8 +227,8 @@ static int __devinit ichxrom_init_one (struct pci_dev *pdev,
(((unsigned long)(window->virt)) + offset);
map->map.size = 0xffffffffUL - map_top + 1UL;
/* Set the name of the map to the address I am trying */
- sprintf(map->map_name, "%s @%08lx",
- MOD_NAME, map->map.phys);
+ sprintf(map->map_name, "%s @%08Lx",
+ MOD_NAME, (unsigned long long)map->map.phys);
/* Firmware hubs only use vpp when being programmed
* in a factory setting. So in-place programming
diff --git a/drivers/mtd/maps/netsc520.c b/drivers/mtd/maps/netsc520.c
index ed215470158..95dcab2146a 100644
--- a/drivers/mtd/maps/netsc520.c
+++ b/drivers/mtd/maps/netsc520.c
@@ -94,7 +94,9 @@ static struct mtd_info *mymtd;
static int __init init_netsc520(void)
{
- printk(KERN_NOTICE "NetSc520 flash device: 0x%lx at 0x%lx\n", netsc520_map.size, netsc520_map.phys);
+ printk(KERN_NOTICE "NetSc520 flash device: 0x%Lx at 0x%Lx\n",
+ (unsigned long long)netsc520_map.size,
+ (unsigned long long)netsc520_map.phys);
netsc520_map.virt = ioremap_nocache(netsc520_map.phys, netsc520_map.size);
if (!netsc520_map.virt) {
diff --git a/drivers/mtd/maps/sc520cdp.c b/drivers/mtd/maps/sc520cdp.c
index 9b50cfc355b..4045e372b90 100644
--- a/drivers/mtd/maps/sc520cdp.c
+++ b/drivers/mtd/maps/sc520cdp.c
@@ -237,8 +237,9 @@ static int __init init_sc520cdp(void)
#endif
for (i = 0; i < NUM_FLASH_BANKS; i++) {
- printk(KERN_NOTICE "SC520 CDP flash device: 0x%lx at 0x%lx\n",
- sc520cdp_map[i].size, sc520cdp_map[i].phys);
+ printk(KERN_NOTICE "SC520 CDP flash device: 0x%Lx at 0x%Lx\n",
+ (unsigned long long)sc520cdp_map[i].size,
+ (unsigned long long)sc520cdp_map[i].phys);
sc520cdp_map[i].virt = ioremap_nocache(sc520cdp_map[i].phys, sc520cdp_map[i].size);
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index 3013d0883b9..1592eac64e5 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -419,8 +419,9 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
info.erasesize = mtd->erasesize;
info.writesize = mtd->writesize;
info.oobsize = mtd->oobsize;
- info.ecctype = mtd->ecctype;
- info.eccsize = mtd->eccsize;
+ /* The below fields are obsolete */
+ info.ecctype = -1;
+ info.eccsize = 0;
if (copy_to_user(argp, &info, sizeof(struct mtd_info_user)))
return -EFAULT;
break;
@@ -759,7 +760,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
return ret;
} /* memory_ioctl */
-static struct file_operations mtd_fops = {
+static const struct file_operations mtd_fops = {
.owner = THIS_MODULE,
.llseek = mtd_lseek,
.read = mtd_read,
diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c
index 06902683bc2..880580c44e0 100644
--- a/drivers/mtd/mtdconcat.c
+++ b/drivers/mtd/mtdconcat.c
@@ -727,8 +727,6 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
concat->mtd.erasesize = subdev[0]->erasesize;
concat->mtd.writesize = subdev[0]->writesize;
concat->mtd.oobsize = subdev[0]->oobsize;
- concat->mtd.ecctype = subdev[0]->ecctype;
- concat->mtd.eccsize = subdev[0]->eccsize;
if (subdev[0]->writev)
concat->mtd.writev = concat_writev;
if (subdev[0]->read_oob)
@@ -774,8 +772,6 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
if (concat->mtd.writesize != subdev[i]->writesize ||
concat->mtd.subpage_sft != subdev[i]->subpage_sft ||
concat->mtd.oobsize != subdev[i]->oobsize ||
- concat->mtd.ecctype != subdev[i]->ecctype ||
- concat->mtd.eccsize != subdev[i]->eccsize ||
!concat->mtd.read_oob != !subdev[i]->read_oob ||
!concat->mtd.write_oob != !subdev[i]->write_oob) {
kfree(concat);
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index 7070110aba2..c153b64a830 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -8,7 +8,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/string.h>
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index bafd2fba87b..633def3fb08 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -338,8 +338,6 @@ int add_mtd_partitions(struct mtd_info *master,
slave->mtd.size = parts[i].size;
slave->mtd.writesize = master->writesize;
slave->mtd.oobsize = master->oobsize;
- slave->mtd.ecctype = master->ecctype;
- slave->mtd.eccsize = master->eccsize;
slave->mtd.subpage_sft = master->subpage_sft;
slave->mtd.name = parts[i].name;
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 358f55a82db..2d12dcdd740 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -126,10 +126,6 @@ config MTD_NAND_S3C2410_HWECC
incorrect ECC generation, and if using these, the default of
software ECC is preferable.
- If you lay down a device with the hardware ECC, then you will
- currently not be able to switch to software, as there is no
- implementation for ECC method used by the S3C2410
-
config MTD_NAND_NDFC
tristate "NDFC NanD Flash Controller"
depends on MTD_NAND && 44x
@@ -221,9 +217,17 @@ config MTD_NAND_SHARPSL
tristate "Support for NAND Flash on Sharp SL Series (C7xx + others)"
depends on MTD_NAND && ARCH_PXA
+config MTD_NAND_BASLER_EXCITE
+ tristate "Support for NAND Flash on Basler eXcite"
+ depends on MTD_NAND && BASLER_EXCITE
+ help
+ This enables the driver for the NAND flash device found on the
+ Basler eXcite Smart Camera. If built as a module, the driver
+ will be named "excite_nandflash.ko".
+
config MTD_NAND_CAFE
tristate "NAND support for OLPC CAFÉ chip"
- depends on PCI
+ depends on MTD_NAND && PCI
help
Use NAND flash attached to the CAFÉ chip designed for the $100
laptop.
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index f7a53f0b701..80f1dfc7794 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_MTD_NAND_NANDSIM) += nandsim.o
obj-$(CONFIG_MTD_NAND_CS553X) += cs553x_nand.o
obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o
obj-$(CONFIG_MTD_NAND_AT91) += at91_nand.o
+obj-$(CONFIG_MTD_NAND_BASLER_EXCITE) += excite_nandflash.o
nand-objs := nand_base.o nand_bbt.o
cafe_nand-objs := cafe.o cafe_ecc.o
diff --git a/drivers/mtd/nand/cafe.c b/drivers/mtd/nand/cafe.c
index 65f9bd3ceeb..fd6bb3ed40d 100644
--- a/drivers/mtd/nand/cafe.c
+++ b/drivers/mtd/nand/cafe.c
@@ -78,8 +78,9 @@ module_param(regdebug, int, 0644);
static int checkecc = 1;
module_param(checkecc, int, 0644);
-static int slowtiming = 0;
-module_param(slowtiming, int, 0644);
+static int numtimings;
+static int timing[3];
+module_param_array(timing, int, &numtimings, 0644);
/* Hrm. Why isn't this already conditional on something in the struct device? */
#define cafe_dev_dbg(dev, args...) do { if (debug) dev_dbg(dev, ##args); } while(0)
@@ -264,10 +265,10 @@ static void cafe_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
ndelay(100);
if (1) {
- int c = 500000;
+ int c;
uint32_t irqs;
- while (c--) {
+ for (c = 500000; c != 0; c--) {
irqs = cafe_readl(cafe, NAND_IRQ);
if (irqs & doneint)
break;
@@ -529,6 +530,7 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev,
{
struct mtd_info *mtd;
struct cafe_priv *cafe;
+ uint32_t timing1, timing2, timing3;
uint32_t ctrl;
int err = 0;
@@ -580,30 +582,45 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev,
cafe->nand.block_bad = cafe_nand_block_bad;
}
+ if (numtimings && numtimings != 3) {
+ dev_warn(&cafe->pdev->dev, "%d timing register values ignored; precisely three are required\n", numtimings);
+ }
+
+ if (numtimings == 3) {
+ timing1 = timing[0];
+ timing2 = timing[1];
+ timing3 = timing[2];
+ cafe_dev_dbg(&cafe->pdev->dev, "Using provided timings (%08x %08x %08x)\n",
+ timing1, timing2, timing3);
+ } else {
+ timing1 = cafe_readl(cafe, NAND_TIMING1);
+ timing2 = cafe_readl(cafe, NAND_TIMING2);
+ timing3 = cafe_readl(cafe, NAND_TIMING3);
+
+ if (timing1 | timing2 | timing3) {
+ cafe_dev_dbg(&cafe->pdev->dev, "Timing registers already set (%08x %08x %08x)\n", timing1, timing2, timing3);
+ } else {
+ dev_warn(&cafe->pdev->dev, "Timing registers unset; using most conservative defaults\n");
+ timing1 = timing2 = timing3 = 0xffffffff;
+ }
+ }
+
/* Start off by resetting the NAND controller completely */
cafe_writel(cafe, 1, NAND_RESET);
cafe_writel(cafe, 0, NAND_RESET);
- cafe_writel(cafe, 0xffffffff, NAND_IRQ_MASK);
+ cafe_writel(cafe, timing1, NAND_TIMING1);
+ cafe_writel(cafe, timing2, NAND_TIMING2);
+ cafe_writel(cafe, timing3, NAND_TIMING3);
- /* Timings from Marvell's test code (not verified or calculated by us) */
- if (!slowtiming) {
- cafe_writel(cafe, 0x01010a0a, NAND_TIMING1);
- cafe_writel(cafe, 0x24121212, NAND_TIMING2);
- cafe_writel(cafe, 0x11000000, NAND_TIMING3);
- } else {
- cafe_writel(cafe, 0xffffffff, NAND_TIMING1);
- cafe_writel(cafe, 0xffffffff, NAND_TIMING2);
- cafe_writel(cafe, 0xffffffff, NAND_TIMING3);
- }
cafe_writel(cafe, 0xffffffff, NAND_IRQ_MASK);
- err = request_irq(pdev->irq, &cafe_nand_interrupt, SA_SHIRQ, "CAFE NAND", mtd);
+ err = request_irq(pdev->irq, &cafe_nand_interrupt, IRQF_SHARED,
+ "CAFE NAND", mtd);
if (err) {
dev_warn(&pdev->dev, "Could not register IRQ %d\n", pdev->irq);
-
goto out_free_dma;
}
-#if 1
+
/* Disable master reset, enable NAND clock */
ctrl = cafe_readl(cafe, GLOBAL_CTRL);
ctrl &= 0xffffeff0;
@@ -630,32 +647,8 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev,
cafe_writel(cafe, 0x80000007, GLOBAL_IRQ_MASK);
cafe_dev_dbg(&cafe->pdev->dev, "Control %x, IRQ mask %x\n",
cafe_readl(cafe, GLOBAL_CTRL), cafe_readl(cafe, GLOBAL_IRQ_MASK));
-#endif
-#if 1
- mtd->writesize=2048;
- mtd->oobsize = 0x40;
- memset(cafe->dmabuf, 0x5a, 2112);
- cafe->nand.cmdfunc(mtd, NAND_CMD_READID, 0, -1);
- cafe->nand.read_byte(mtd);
- cafe->nand.read_byte(mtd);
- cafe->nand.read_byte(mtd);
- cafe->nand.read_byte(mtd);
- cafe->nand.read_byte(mtd);
-#endif
-#if 0
- cafe->nand.cmdfunc(mtd, NAND_CMD_READ0, 0, 0);
- // nand_wait_ready(mtd);
- cafe->nand.read_byte(mtd);
- cafe->nand.read_byte(mtd);
- cafe->nand.read_byte(mtd);
- cafe->nand.read_byte(mtd);
-#endif
-#if 0
- writel(0x84600070, cafe->mmio);
- udelay(10);
- cafe_dev_dbg(&cafe->pdev->dev, "Status %x\n", cafe_readl(cafe, NAND_NONMEM));
-#endif
- /* Scan to find existance of the device */
+
+ /* Scan to find existence of the device */
if (nand_scan_ident(mtd, 1)) {
err = -ENXIO;
goto out_irq;
@@ -759,13 +752,4 @@ module_exit(cafe_nand_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
-MODULE_DESCRIPTION("NAND flash driver for OLPC CAFE chip");
-
-/* Correct ECC for 2048 bytes of 0xff:
- 41 a0 71 65 54 27 f3 93 ec a9 be ed 0b a1 */
-
-/* dwmw2's B-test board, in case of completely screwing it:
-Bad eraseblock 2394 at 0x12b40000
-Bad eraseblock 2627 at 0x14860000
-Bad eraseblock 3349 at 0x1a2a0000
-*/
+MODULE_DESCRIPTION("NAND flash driver for OLPC CAFÉ chip");
diff --git a/drivers/mtd/nand/cafe_ecc.c b/drivers/mtd/nand/cafe_ecc.c
index 1b9fa05a447..ea5c8491d2c 100644
--- a/drivers/mtd/nand/cafe_ecc.c
+++ b/drivers/mtd/nand/cafe_ecc.c
@@ -1045,7 +1045,7 @@ static unsigned short err_pos_lut[4096] = {
static unsigned short err_pos(unsigned short din)
{
- BUG_ON(din > 4096);
+ BUG_ON(din >= ARRAY_SIZE(err_pos_lut));
return err_pos_lut[din];
}
static int chk_no_err_only(unsigned short *chk_syndrome_list, unsigned short *err_info)
diff --git a/drivers/mtd/nand/excite_nandflash.c b/drivers/mtd/nand/excite_nandflash.c
new file mode 100644
index 00000000000..7e9afc4c775
--- /dev/null
+++ b/drivers/mtd/nand/excite_nandflash.c
@@ -0,0 +1,248 @@
+/*
+* Copyright (C) 2005 - 2007 by Basler Vision Technologies AG
+* Author: Thomas Koeller <thomas.koeller.qbaslerweb.com>
+* Original code by Thies Moeller <thies.moeller@baslerweb.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/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/io.h>
+#include <asm/rm9k-ocd.h>
+
+#include <excite_nandflash.h>
+
+#define EXCITE_NANDFLASH_VERSION "0.1"
+
+/* I/O register offsets */
+#define EXCITE_NANDFLASH_DATA_BYTE 0x00
+#define EXCITE_NANDFLASH_STATUS_BYTE 0x0c
+#define EXCITE_NANDFLASH_ADDR_BYTE 0x10
+#define EXCITE_NANDFLASH_CMD_BYTE 0x14
+
+/* prefix for debug output */
+static const char module_id[] = "excite_nandflash";
+
+/*
+ * partition definition
+ */
+static const struct mtd_partition partition_info[] = {
+ {
+ .name = "eXcite RootFS",
+ .offset = 0,
+ .size = MTDPART_SIZ_FULL
+ }
+};
+
+static inline const struct resource *
+excite_nand_get_resource(struct platform_device *d, unsigned long flags,
+ const char *basename)
+{
+ char buf[80];
+
+ if (snprintf(buf, sizeof buf, "%s_%u", basename, d->id) >= sizeof buf)
+ return NULL;
+ return platform_get_resource_byname(d, flags, buf);
+}
+
+static inline void __iomem *
+excite_nand_map_regs(struct platform_device *d, const char *basename)
+{
+ void *result = NULL;
+ const struct resource *const r =
+ excite_nand_get_resource(d, IORESOURCE_MEM, basename);
+
+ if (r)
+ result = ioremap_nocache(r->start, r->end + 1 - r->start);
+ return result;
+}
+
+/* controller and mtd information */
+struct excite_nand_drvdata {
+ struct mtd_info board_mtd;
+ struct nand_chip board_chip;
+ void __iomem *regs;
+ void __iomem *tgt;
+};
+
+/* Control function */
+static void excite_nand_control(struct mtd_info *mtd, int cmd,
+ unsigned int ctrl)
+{
+ struct excite_nand_drvdata * const d =
+ container_of(mtd, struct excite_nand_drvdata, board_mtd);
+
+ switch (ctrl) {
+ case NAND_CTRL_CHANGE | NAND_CTRL_CLE:
+ d->tgt = d->regs + EXCITE_NANDFLASH_CMD_BYTE;
+ break;
+ case NAND_CTRL_CHANGE | NAND_CTRL_ALE:
+ d->tgt = d->regs + EXCITE_NANDFLASH_ADDR_BYTE;
+ break;
+ case NAND_CTRL_CHANGE | NAND_NCE:
+ d->tgt = d->regs + EXCITE_NANDFLASH_DATA_BYTE;
+ break;
+ }
+
+ if (cmd != NAND_CMD_NONE)
+ __raw_writeb(cmd, d->tgt);
+}
+
+/* Return 0 if flash is busy, 1 if ready */
+static int excite_nand_devready(struct mtd_info *mtd)
+{
+ struct excite_nand_drvdata * const drvdata =
+ container_of(mtd, struct excite_nand_drvdata, board_mtd);
+
+ return __raw_readb(drvdata->regs + EXCITE_NANDFLASH_STATUS_BYTE);
+}
+
+/*
+ * Called by device layer to remove the driver.
+ * The binding to the mtd and all allocated
+ * resources are released.
+ */
+static int __exit excite_nand_remove(struct device *dev)
+{
+ struct excite_nand_drvdata * const this = dev_get_drvdata(dev);
+
+ dev_set_drvdata(dev, NULL);
+
+ if (unlikely(!this)) {
+ printk(KERN_ERR "%s: called %s without private data!!",
+ module_id, __func__);
+ return -EINVAL;
+ }
+
+ /* first thing we need to do is release our mtd
+ * then go through freeing the resource used
+ */
+ nand_release(&this->board_mtd);
+
+ /* free the common resources */
+ iounmap(this->regs);
+ kfree(this);
+
+ DEBUG(MTD_DEBUG_LEVEL1, "%s: removed\n", module_id);
+ return 0;
+}
+
+/*
+ * Called by device layer when it finds a device matching
+ * one our driver can handle. This code checks to see if
+ * it can allocate all necessary resources then calls the
+ * nand layer to look for devices.
+*/
+static int __init excite_nand_probe(struct device *dev)
+{
+ struct platform_device * const pdev = to_platform_device(dev);
+ struct excite_nand_drvdata *drvdata; /* private driver data */
+ struct nand_chip *board_chip; /* private flash chip data */
+ struct mtd_info *board_mtd; /* mtd info for this board */
+ int scan_res;
+
+ drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
+ if (unlikely(!drvdata)) {
+ printk(KERN_ERR "%s: no memory for drvdata\n",
+ module_id);
+ return -ENOMEM;
+ }
+
+ /* bind private data into driver */
+ dev_set_drvdata(dev, drvdata);
+
+ /* allocate and map the resource */
+ drvdata->regs =
+ excite_nand_map_regs(pdev, EXCITE_NANDFLASH_RESOURCE_REGS);
+
+ if (unlikely(!drvdata->regs)) {
+ printk(KERN_ERR "%s: cannot reserve register region\n",
+ module_id);
+ kfree(drvdata);
+ return -ENXIO;
+ }
+
+ drvdata->tgt = drvdata->regs + EXCITE_NANDFLASH_DATA_BYTE;
+
+ /* initialise our chip */
+ board_chip = &drvdata->board_chip;
+ board_chip->IO_ADDR_R = board_chip->IO_ADDR_W =
+ drvdata->regs + EXCITE_NANDFLASH_DATA_BYTE;
+ board_chip->cmd_ctrl = excite_nand_control;
+ board_chip->dev_ready = excite_nand_devready;
+ board_chip->chip_delay = 25;
+ board_chip->ecc.mode = NAND_ECC_SOFT;
+
+ /* link chip to mtd */
+ board_mtd = &drvdata->board_mtd;
+ board_mtd->priv = board_chip;
+
+ DEBUG(MTD_DEBUG_LEVEL2, "%s: device scan\n", module_id);
+ scan_res = nand_scan(&drvdata->board_mtd, 1);
+
+ if (likely(!scan_res)) {
+ DEBUG(MTD_DEBUG_LEVEL2, "%s: register partitions\n", module_id);
+ add_mtd_partitions(&drvdata->board_mtd, partition_info,
+ sizeof partition_info / sizeof partition_info[0]);
+ } else {
+ iounmap(drvdata->regs);
+ kfree(drvdata);
+ printk(KERN_ERR "%s: device scan failed\n", module_id);
+ return -EIO;
+ }
+ return 0;
+}
+
+static struct device_driver excite_nand_driver = {
+ .name = "excite_nand",
+ .bus = &platform_bus_type,
+ .probe = excite_nand_probe,
+ .remove = __exit_p(excite_nand_remove)
+};
+
+static int __init excite_nand_init(void)
+{
+ pr_info("Basler eXcite nand flash driver Version "
+ EXCITE_NANDFLASH_VERSION "\n");
+ return driver_register(&excite_nand_driver);
+}
+
+static void __exit excite_nand_exit(void)
+{
+ driver_unregister(&excite_nand_driver);
+}
+
+module_init(excite_nand_init);
+module_exit(excite_nand_exit);
+
+MODULE_AUTHOR("Thomas Koeller <thomas.koeller@baslerweb.com>");
+MODULE_DESCRIPTION("Basler eXcite NAND-Flash driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(EXCITE_NANDFLASH_VERSION)
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index dfe56e03e48..acaf97bc80d 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -1272,10 +1272,25 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
DEBUG(MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08Lx, len = %i\n",
(unsigned long long)from, readlen);
- if (ops->mode == MTD_OOB_RAW)
- len = mtd->oobsize;
- else
+ if (ops->mode == MTD_OOB_AUTO)
len = chip->ecc.layout->oobavail;
+ else
+ len = mtd->oobsize;
+
+ if (unlikely(ops->ooboffs >= len)) {
+ DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "
+ "Attempt to start read outside oob\n");
+ return -EINVAL;
+ }
+
+ /* Do not allow reads past end of device */
+ if (unlikely(from >= mtd->size ||
+ ops->ooboffs + readlen > ((mtd->size >> chip->page_shift) -
+ (from >> chip->page_shift)) * len)) {
+ DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "
+ "Attempt read beyond end of device\n");
+ return -EINVAL;
+ }
chipnr = (int)(from >> chip->chip_shift);
chip->select_chip(mtd, chipnr);
@@ -1742,19 +1757,40 @@ static int nand_write(struct mtd_info *mtd, loff_t to, size_t len,
static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
struct mtd_oob_ops *ops)
{
- int chipnr, page, status;
+ int chipnr, page, status, len;
struct nand_chip *chip = mtd->priv;
DEBUG(MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n",
(unsigned int)to, (int)ops->ooblen);
+ if (ops->mode == MTD_OOB_AUTO)
+ len = chip->ecc.layout->oobavail;
+ else
+ len = mtd->oobsize;
+
/* Do not allow write past end of page */
- if ((ops->ooboffs + ops->ooblen) > mtd->oobsize) {
+ if ((ops->ooboffs + ops->ooblen) > len) {
DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: "
"Attempt to write past end of page\n");
return -EINVAL;
}
+ if (unlikely(ops->ooboffs >= len)) {
+ DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "
+ "Attempt to start write outside oob\n");
+ return -EINVAL;
+ }
+
+ /* Do not allow reads past end of device */
+ if (unlikely(to >= mtd->size ||
+ ops->ooboffs + ops->ooblen >
+ ((mtd->size >> chip->page_shift) -
+ (to >> chip->page_shift)) * len)) {
+ DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "
+ "Attempt write beyond end of device\n");
+ return -EINVAL;
+ }
+
chipnr = (int)(to >> chip->chip_shift);
chip->select_chip(mtd, chipnr);
@@ -2530,7 +2566,6 @@ int nand_scan_tail(struct mtd_info *mtd)
/* Fill in remaining MTD driver data */
mtd->type = MTD_NANDFLASH;
mtd->flags = MTD_CAP_NANDFLASH;
- mtd->ecctype = MTD_ECC_SW;
mtd->erase = nand_erase;
mtd->point = NULL;
mtd->unpoint = NULL;
diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
index 8b3203571ee..0ddfd6de75c 100644
--- a/drivers/mtd/nand/s3c2410.c
+++ b/drivers/mtd/nand/s3c2410.c
@@ -337,17 +337,69 @@ static int s3c2412_nand_devready(struct mtd_info *mtd)
static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
u_char *read_ecc, u_char *calc_ecc)
{
- pr_debug("s3c2410_nand_correct_data(%p,%p,%p,%p)\n", mtd, dat, read_ecc, calc_ecc);
+ struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+ unsigned int diff0, diff1, diff2;
+ unsigned int bit, byte;
- pr_debug("eccs: read %02x,%02x,%02x vs calc %02x,%02x,%02x\n",
- read_ecc[0], read_ecc[1], read_ecc[2], calc_ecc[0], calc_ecc[1], calc_ecc[2]);
+ pr_debug("%s(%p,%p,%p,%p)\n", __func__, mtd, dat, read_ecc, calc_ecc);
- if (read_ecc[0] == calc_ecc[0] && read_ecc[1] == calc_ecc[1] && read_ecc[2] == calc_ecc[2])
- return 0;
+ diff0 = read_ecc[0] ^ calc_ecc[0];
+ diff1 = read_ecc[1] ^ calc_ecc[1];
+ diff2 = read_ecc[2] ^ calc_ecc[2];
+
+ pr_debug("%s: rd %02x%02x%02x calc %02x%02x%02x diff %02x%02x%02x\n",
+ __func__,
+ read_ecc[0], read_ecc[1], read_ecc[2],
+ calc_ecc[0], calc_ecc[1], calc_ecc[2],
+ diff0, diff1, diff2);
+
+ if (diff0 == 0 && diff1 == 0 && diff2 == 0)
+ return 0; /* ECC is ok */
+
+ /* Can we correct this ECC (ie, one row and column change).
+ * Note, this is similar to the 256 error code on smartmedia */
+
+ if (((diff0 ^ (diff0 >> 1)) & 0x55) == 0x55 &&
+ ((diff1 ^ (diff1 >> 1)) & 0x55) == 0x55 &&
+ ((diff2 ^ (diff2 >> 1)) & 0x55) == 0x55) {
+ /* calculate the bit position of the error */
+
+ bit = (diff2 >> 2) & 1;
+ bit |= (diff2 >> 3) & 2;
+ bit |= (diff2 >> 4) & 4;
+
+ /* calculate the byte position of the error */
+
+ byte = (diff1 << 1) & 0x80;
+ byte |= (diff1 << 2) & 0x40;
+ byte |= (diff1 << 3) & 0x20;
+ byte |= (diff1 << 4) & 0x10;
+
+ byte |= (diff0 >> 3) & 0x08;
+ byte |= (diff0 >> 2) & 0x04;
+ byte |= (diff0 >> 1) & 0x02;
+ byte |= (diff0 >> 0) & 0x01;
- /* we curently have no method for correcting the error */
+ byte |= (diff2 << 8) & 0x100;
- return -1;
+ dev_dbg(info->device, "correcting error bit %d, byte %d\n",
+ bit, byte);
+
+ dat[byte] ^= (1 << bit);
+ return 1;
+ }
+
+ /* if there is only one bit difference in the ECC, then
+ * one of only a row or column parity has changed, which
+ * means the error is most probably in the ECC itself */
+
+ diff0 |= (diff1 << 8);
+ diff0 |= (diff2 << 16);
+
+ if ((diff0 & ~(1<<fls(diff0))) == 0)
+ return 1;
+
+ return 0;
}
/* ECC functions
@@ -366,6 +418,15 @@ static void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode)
writel(ctrl, info->regs + S3C2410_NFCONF);
}
+static void s3c2412_nand_enable_hwecc(struct mtd_info *mtd, int mode)
+{
+ struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+ unsigned long ctrl;
+
+ ctrl = readl(info->regs + S3C2440_NFCONT);
+ writel(ctrl | S3C2412_NFCONT_INIT_MAIN_ECC, info->regs + S3C2440_NFCONT);
+}
+
static void s3c2440_nand_enable_hwecc(struct mtd_info *mtd, int mode)
{
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
@@ -383,6 +444,21 @@ static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u
ecc_code[1] = readb(info->regs + S3C2410_NFECC + 1);
ecc_code[2] = readb(info->regs + S3C2410_NFECC + 2);
+ pr_debug("%s: returning ecc %02x%02x%02x\n", __func__,
+ ecc_code[0], ecc_code[1], ecc_code[2]);
+
+ return 0;
+}
+
+static int s3c2412_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code)
+{
+ struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+ unsigned long ecc = readl(info->regs + S3C2412_NFMECC0);
+
+ ecc_code[0] = ecc;
+ ecc_code[1] = ecc >> 8;
+ ecc_code[2] = ecc >> 16;
+
pr_debug("calculate_ecc: returning ecc %02x,%02x,%02x\n", ecc_code[0], ecc_code[1], ecc_code[2]);
return 0;
@@ -397,7 +473,7 @@ static int s3c2440_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u
ecc_code[1] = ecc >> 8;
ecc_code[2] = ecc >> 16;
- pr_debug("calculate_ecc: returning ecc %02x,%02x,%02x\n", ecc_code[0], ecc_code[1], ecc_code[2]);
+ pr_debug("%s: returning ecc %06x\n", __func__, ecc);
return 0;
}
@@ -565,6 +641,10 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
break;
case TYPE_S3C2412:
+ chip->ecc.hwctl = s3c2412_nand_enable_hwecc;
+ chip->ecc.calculate = s3c2412_nand_calculate_ecc;
+ break;
+
case TYPE_S3C2440:
chip->ecc.hwctl = s3c2440_nand_enable_hwecc;
chip->ecc.calculate = s3c2440_nand_calculate_ecc;
diff --git a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c
index 4b1ba4fcfcd..e6ef7d7f9f1 100644
--- a/drivers/mtd/nftlcore.c
+++ b/drivers/mtd/nftlcore.c
@@ -20,7 +20,6 @@
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/slab.h>
-#include <linux/sched.h>
#include <linux/init.h>
#include <linux/hdreg.h>
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
index 2da6bb26353..7f1cb6e5dcc 100644
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -1,7 +1,7 @@
/*
* linux/drivers/mtd/onenand/onenand_base.c
*
- * Copyright (C) 2005-2006 Samsung Electronics
+ * Copyright (C) 2005-2007 Samsung Electronics
* Kyungmin Park <kyungmin.park@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -94,16 +94,9 @@ static void onenand_writew(unsigned short value, void __iomem *addr)
*/
static int onenand_block_address(struct onenand_chip *this, int block)
{
- if (this->device_id & ONENAND_DEVICE_IS_DDP) {
- /* Device Flash Core select, NAND Flash Block Address */
- int dfs = 0;
-
- if (block & this->density_mask)
- dfs = 1;
-
- return (dfs << ONENAND_DDP_SHIFT) |
- (block & (this->density_mask - 1));
- }
+ /* Device Flash Core select, NAND Flash Block Address */
+ if (block & this->density_mask)
+ return ONENAND_DDP_CHIP1 | (block ^ this->density_mask);
return block;
}
@@ -118,17 +111,11 @@ static int onenand_block_address(struct onenand_chip *this, int block)
*/
static int onenand_bufferram_address(struct onenand_chip *this, int block)
{
- if (this->device_id & ONENAND_DEVICE_IS_DDP) {
- /* Device BufferRAM Select */
- int dbs = 0;
-
- if (block & this->density_mask)
- dbs = 1;
+ /* Device BufferRAM Select */
+ if (block & this->density_mask)
+ return ONENAND_DDP_CHIP1;
- return (dbs << ONENAND_DDP_SHIFT);
- }
-
- return 0;
+ return ONENAND_DDP_CHIP0;
}
/**
@@ -317,22 +304,25 @@ static int onenand_wait(struct mtd_info *mtd, int state)
ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS);
if (ctrl & ONENAND_CTRL_ERROR) {
- DEBUG(MTD_DEBUG_LEVEL0, "onenand_wait: controller error = 0x%04x\n", ctrl);
+ printk(KERN_ERR "onenand_wait: controller error = 0x%04x\n", ctrl);
if (ctrl & ONENAND_CTRL_LOCK)
- DEBUG(MTD_DEBUG_LEVEL0, "onenand_wait: it's locked error.\n");
+ printk(KERN_ERR "onenand_wait: it's locked error.\n");
return ctrl;
}
if (interrupt & ONENAND_INT_READ) {
int ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS);
if (ecc) {
- DEBUG(MTD_DEBUG_LEVEL0, "onenand_wait: ECC error = 0x%04x\n", ecc);
+ printk(KERN_ERR "onenand_wait: ECC error = 0x%04x\n", ecc);
if (ecc & ONENAND_ECC_2BIT_ALL) {
mtd->ecc_stats.failed++;
return ecc;
} else if (ecc & ONENAND_ECC_1BIT_ALL)
mtd->ecc_stats.corrected++;
}
+ } else if (state == FL_READING) {
+ printk(KERN_ERR "onenand_wait: read timeout! ctrl=0x%04x intr=0x%04x\n", ctrl, interrupt);
+ return -EIO;
}
return 0;
@@ -587,22 +577,32 @@ static int onenand_write_bufferram(struct mtd_info *mtd, int area,
static int onenand_check_bufferram(struct mtd_info *mtd, loff_t addr)
{
struct onenand_chip *this = mtd->priv;
- int block, page;
- int i;
+ int blockpage, found = 0;
+ unsigned int i;
- block = (int) (addr >> this->erase_shift);
- page = (int) (addr >> this->page_shift);
- page &= this->page_mask;
+ blockpage = (int) (addr >> this->page_shift);
+ /* Is there valid data? */
i = ONENAND_CURRENT_BUFFERRAM(this);
+ if (this->bufferram[i].blockpage == blockpage)
+ found = 1;
+ else {
+ /* Check another BufferRAM */
+ i = ONENAND_NEXT_BUFFERRAM(this);
+ if (this->bufferram[i].blockpage == blockpage) {
+ ONENAND_SET_NEXT_BUFFERRAM(this);
+ found = 1;
+ }
+ }
- /* Is there valid data? */
- if (this->bufferram[i].block == block &&
- this->bufferram[i].page == page &&
- this->bufferram[i].valid)
- return 1;
+ if (found && ONENAND_IS_DDP(this)) {
+ /* Select DataRAM for DDP */
+ int block = (int) (addr >> this->erase_shift);
+ int value = onenand_bufferram_address(this, block);
+ this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);
+ }
- return 0;
+ return found;
}
/**
@@ -613,31 +613,49 @@ static int onenand_check_bufferram(struct mtd_info *mtd, loff_t addr)
*
* Update BufferRAM information
*/
-static int onenand_update_bufferram(struct mtd_info *mtd, loff_t addr,
+static void onenand_update_bufferram(struct mtd_info *mtd, loff_t addr,
int valid)
{
struct onenand_chip *this = mtd->priv;
- int block, page;
- int i;
+ int blockpage;
+ unsigned int i;
- block = (int) (addr >> this->erase_shift);
- page = (int) (addr >> this->page_shift);
- page &= this->page_mask;
+ blockpage = (int) (addr >> this->page_shift);
- /* Invalidate BufferRAM */
- for (i = 0; i < MAX_BUFFERRAM; i++) {
- if (this->bufferram[i].block == block &&
- this->bufferram[i].page == page)
- this->bufferram[i].valid = 0;
- }
+ /* Invalidate another BufferRAM */
+ i = ONENAND_NEXT_BUFFERRAM(this);
+ if (this->bufferram[i].blockpage == blockpage)
+ this->bufferram[i].blockpage = -1;
/* Update BufferRAM */
i = ONENAND_CURRENT_BUFFERRAM(this);
- this->bufferram[i].block = block;
- this->bufferram[i].page = page;
- this->bufferram[i].valid = valid;
+ if (valid)
+ this->bufferram[i].blockpage = blockpage;
+ else
+ this->bufferram[i].blockpage = -1;
+}
- return 0;
+/**
+ * onenand_invalidate_bufferram - [GENERIC] Invalidate BufferRAM information
+ * @param mtd MTD data structure
+ * @param addr start address to invalidate
+ * @param len length to invalidate
+ *
+ * Invalidate BufferRAM information
+ */
+static void onenand_invalidate_bufferram(struct mtd_info *mtd, loff_t addr,
+ unsigned int len)
+{
+ struct onenand_chip *this = mtd->priv;
+ int i;
+ loff_t end_addr = addr + len;
+
+ /* Invalidate BufferRAM */
+ for (i = 0; i < MAX_BUFFERRAM; i++) {
+ loff_t buf_addr = this->bufferram[i].blockpage << this->page_shift;
+ if (buf_addr >= addr && buf_addr < end_addr)
+ this->bufferram[i].blockpage = -1;
+ }
}
/**
@@ -716,7 +734,7 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
/* Do not allow reads past end of device */
if ((from + len) > mtd->size) {
- DEBUG(MTD_DEBUG_LEVEL0, "onenand_read: Attempt read beyond end of device\n");
+ printk(KERN_ERR "onenand_read: Attempt read beyond end of device\n");
*retlen = 0;
return -EINVAL;
}
@@ -724,8 +742,6 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
/* Grab the lock and see if the device is available */
onenand_get_device(mtd, FL_READING);
- /* TODO handling oob */
-
stats = mtd->ecc_stats;
/* Read-while-load method */
@@ -754,9 +770,9 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
* Now we issued chip 1 read and pointed chip 1
* bufferam so we have to point chip 0 bufferam.
*/
- if (this->device_id & ONENAND_DEVICE_IS_DDP &&
- unlikely(from == (this->chipsize >> 1))) {
- this->write_word(0, this->base + ONENAND_REG_START_ADDRESS2);
+ if (ONENAND_IS_DDP(this) &&
+ unlikely(from == (this->chipsize >> 1))) {
+ this->write_word(ONENAND_DDP_CHIP0, this->base + ONENAND_REG_START_ADDRESS2);
boundary = 1;
} else
boundary = 0;
@@ -770,7 +786,7 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
break;
/* Set up for next read from bufferRAM */
if (unlikely(boundary))
- this->write_word(0x8000, this->base + ONENAND_REG_START_ADDRESS2);
+ this->write_word(ONENAND_DDP_CHIP1, this->base + ONENAND_REG_START_ADDRESS2);
ONENAND_SET_NEXT_BUFFERRAM(this);
buf += thislen;
thislen = min_t(int, mtd->writesize, len - read);
@@ -801,20 +817,59 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
}
/**
+ * onenand_transfer_auto_oob - [Internal] oob auto-placement transfer
+ * @param mtd MTD device structure
+ * @param buf destination address
+ * @param column oob offset to read from
+ * @param thislen oob length to read
+ */
+static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf, int column,
+ int thislen)
+{
+ struct onenand_chip *this = mtd->priv;
+ struct nand_oobfree *free;
+ int readcol = column;
+ int readend = column + thislen;
+ int lastgap = 0;
+ uint8_t *oob_buf = this->page_buf + mtd->writesize;
+
+ for (free = this->ecclayout->oobfree; free->length; ++free) {
+ if (readcol >= lastgap)
+ readcol += free->offset - lastgap;
+ if (readend >= lastgap)
+ readend += free->offset - lastgap;
+ lastgap = free->offset + free->length;
+ }
+ this->read_bufferram(mtd, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize);
+ for (free = this->ecclayout->oobfree; free->length; ++free) {
+ int free_end = free->offset + free->length;
+ if (free->offset < readend && free_end > readcol) {
+ int st = max_t(int,free->offset,readcol);
+ int ed = min_t(int,free_end,readend);
+ int n = ed - st;
+ memcpy(buf, oob_buf + st, n);
+ buf += n;
+ }
+ }
+ return 0;
+}
+
+/**
* onenand_do_read_oob - [MTD Interface] OneNAND read out-of-band
* @param mtd MTD device structure
* @param from offset to read from
* @param len number of bytes to read
* @param retlen pointer to variable to store the number of read bytes
* @param buf the databuffer to put data
+ * @param mode operation mode
*
* OneNAND read out-of-band data from the spare area
*/
-int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char *buf)
+static int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, u_char *buf, mtd_oob_mode_t mode)
{
struct onenand_chip *this = mtd->priv;
- int read = 0, thislen, column;
+ int read = 0, thislen, column, oobsize;
int ret = 0;
DEBUG(MTD_DEBUG_LEVEL3, "onenand_read_oob: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
@@ -822,21 +877,33 @@ int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
/* Initialize return length value */
*retlen = 0;
+ if (mode == MTD_OOB_AUTO)
+ oobsize = this->ecclayout->oobavail;
+ else
+ oobsize = mtd->oobsize;
+
+ column = from & (mtd->oobsize - 1);
+
+ if (unlikely(column >= oobsize)) {
+ printk(KERN_ERR "onenand_read_oob: Attempted to start read outside oob\n");
+ return -EINVAL;
+ }
+
/* Do not allow reads past end of device */
- if (unlikely((from + len) > mtd->size)) {
- DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_oob: Attempt read beyond end of device\n");
+ if (unlikely(from >= mtd->size ||
+ column + len > ((mtd->size >> this->page_shift) -
+ (from >> this->page_shift)) * oobsize)) {
+ printk(KERN_ERR "onenand_read_oob: Attempted to read beyond end of device\n");
return -EINVAL;
}
/* Grab the lock and see if the device is available */
onenand_get_device(mtd, FL_READING);
- column = from & (mtd->oobsize - 1);
-
while (read < len) {
cond_resched();
- thislen = mtd->oobsize - column;
+ thislen = oobsize - column;
thislen = min_t(int, thislen, len);
this->command(mtd, ONENAND_CMD_READOOB, from, mtd->oobsize);
@@ -846,11 +913,14 @@ int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
ret = this->wait(mtd, FL_READING);
/* First copy data and check return value for ECC handling */
- this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen);
+ if (mode == MTD_OOB_AUTO)
+ onenand_transfer_auto_oob(mtd, buf, column, thislen);
+ else
+ this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen);
if (ret) {
- DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_oob: read failed = 0x%x\n", ret);
- goto out;
+ printk(KERN_ERR "onenand_read_oob: read failed = 0x%x\n", ret);
+ break;
}
read += thislen;
@@ -868,7 +938,6 @@ int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
}
}
-out:
/* Deselect and wake up anyone waiting on the device */
onenand_release_device(mtd);
@@ -885,10 +954,132 @@ out:
static int onenand_read_oob(struct mtd_info *mtd, loff_t from,
struct mtd_oob_ops *ops)
{
- BUG_ON(ops->mode != MTD_OOB_PLACE);
-
+ switch (ops->mode) {
+ case MTD_OOB_PLACE:
+ case MTD_OOB_AUTO:
+ break;
+ case MTD_OOB_RAW:
+ /* Not implemented yet */
+ default:
+ return -EINVAL;
+ }
return onenand_do_read_oob(mtd, from + ops->ooboffs, ops->ooblen,
- &ops->oobretlen, ops->oobbuf);
+ &ops->oobretlen, ops->oobbuf, ops->mode);
+}
+
+/**
+ * onenand_bbt_wait - [DEFAULT] wait until the command is done
+ * @param mtd MTD device structure
+ * @param state state to select the max. timeout value
+ *
+ * Wait for command done.
+ */
+static int onenand_bbt_wait(struct mtd_info *mtd, int state)
+{
+ struct onenand_chip *this = mtd->priv;
+ unsigned long timeout;
+ unsigned int interrupt;
+ unsigned int ctrl;
+
+ /* The 20 msec is enough */
+ timeout = jiffies + msecs_to_jiffies(20);
+ while (time_before(jiffies, timeout)) {
+ interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
+ if (interrupt & ONENAND_INT_MASTER)
+ break;
+ }
+ /* To get correct interrupt status in timeout case */
+ interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
+ ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS);
+
+ if (ctrl & ONENAND_CTRL_ERROR) {
+ printk(KERN_DEBUG "onenand_bbt_wait: controller error = 0x%04x\n", ctrl);
+ /* Initial bad block case */
+ if (ctrl & ONENAND_CTRL_LOAD)
+ return ONENAND_BBT_READ_ERROR;
+ return ONENAND_BBT_READ_FATAL_ERROR;
+ }
+
+ if (interrupt & ONENAND_INT_READ) {
+ int ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS);
+ if (ecc & ONENAND_ECC_2BIT_ALL)
+ return ONENAND_BBT_READ_ERROR;
+ } else {
+ printk(KERN_ERR "onenand_bbt_wait: read timeout!"
+ "ctrl=0x%04x intr=0x%04x\n", ctrl, interrupt);
+ return ONENAND_BBT_READ_FATAL_ERROR;
+ }
+
+ return 0;
+}
+
+/**
+ * onenand_bbt_read_oob - [MTD Interface] OneNAND read out-of-band for bbt scan
+ * @param mtd MTD device structure
+ * @param from offset to read from
+ * @param @ops oob operation description structure
+ *
+ * OneNAND read out-of-band data from the spare area for bbt scan
+ */
+int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,
+ struct mtd_oob_ops *ops)
+{
+ struct onenand_chip *this = mtd->priv;
+ int read = 0, thislen, column;
+ int ret = 0;
+ size_t len = ops->ooblen;
+ u_char *buf = ops->oobbuf;
+
+ DEBUG(MTD_DEBUG_LEVEL3, "onenand_bbt_read_oob: from = 0x%08x, len = %zi\n", (unsigned int) from, len);
+
+ /* Initialize return value */
+ ops->oobretlen = 0;
+
+ /* Do not allow reads past end of device */
+ if (unlikely((from + len) > mtd->size)) {
+ printk(KERN_ERR "onenand_bbt_read_oob: Attempt read beyond end of device\n");
+ return ONENAND_BBT_READ_FATAL_ERROR;
+ }
+
+ /* Grab the lock and see if the device is available */
+ onenand_get_device(mtd, FL_READING);
+
+ column = from & (mtd->oobsize - 1);
+
+ while (read < len) {
+ cond_resched();
+
+ thislen = mtd->oobsize - column;
+ thislen = min_t(int, thislen, len);
+
+ this->command(mtd, ONENAND_CMD_READOOB, from, mtd->oobsize);
+
+ onenand_update_bufferram(mtd, from, 0);
+
+ ret = onenand_bbt_wait(mtd, FL_READING);
+ if (ret)
+ break;
+
+ this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen);
+ read += thislen;
+ if (read == len)
+ break;
+
+ buf += thislen;
+
+ /* Read more? */
+ if (read < len) {
+ /* Update Page size */
+ from += mtd->writesize;
+ column = 0;
+ }
+ }
+
+ /* Deselect and wake up anyone waiting on the device */
+ onenand_release_device(mtd);
+
+ ops->oobretlen = read;
+ return ret;
}
#ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE
@@ -897,14 +1088,12 @@ static int onenand_read_oob(struct mtd_info *mtd, loff_t from,
* @param mtd MTD device structure
* @param buf the databuffer to verify
* @param to offset to read from
- * @param len number of bytes to read and compare
*
*/
-static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to, int len)
+static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to)
{
struct onenand_chip *this = mtd->priv;
- char *readp = this->page_buf;
- int column = to & (mtd->oobsize - 1);
+ char *readp = this->page_buf + mtd->writesize;
int status, i;
this->command(mtd, ONENAND_CMD_READOOB, to, mtd->oobsize);
@@ -913,9 +1102,8 @@ static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to
if (status)
return status;
- this->read_bufferram(mtd, ONENAND_SPARERAM, readp, column, len);
-
- for(i = 0; i < len; i++)
+ this->read_bufferram(mtd, ONENAND_SPARERAM, readp, 0, mtd->oobsize);
+ for(i = 0; i < mtd->oobsize; i++)
if (buf[i] != 0xFF && buf[i] != readp[i])
return -EBADMSG;
@@ -923,41 +1111,51 @@ static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to
}
/**
- * onenand_verify_page - [GENERIC] verify the chip contents after a write
- * @param mtd MTD device structure
- * @param buf the databuffer to verify
+ * onenand_verify - [GENERIC] verify the chip contents after a write
+ * @param mtd MTD device structure
+ * @param buf the databuffer to verify
+ * @param addr offset to read from
+ * @param len number of bytes to read and compare
*
- * Check DataRAM area directly
*/
-static int onenand_verify_page(struct mtd_info *mtd, u_char *buf, loff_t addr)
+static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr, size_t len)
{
struct onenand_chip *this = mtd->priv;
- void __iomem *dataram0, *dataram1;
+ void __iomem *dataram;
int ret = 0;
+ int thislen, column;
- /* In partial page write, just skip it */
- if ((addr & (mtd->writesize - 1)) != 0)
- return 0;
+ while (len != 0) {
+ thislen = min_t(int, mtd->writesize, len);
+ column = addr & (mtd->writesize - 1);
+ if (column + thislen > mtd->writesize)
+ thislen = mtd->writesize - column;
- this->command(mtd, ONENAND_CMD_READ, addr, mtd->writesize);
+ this->command(mtd, ONENAND_CMD_READ, addr, mtd->writesize);
- ret = this->wait(mtd, FL_READING);
- if (ret)
- return ret;
+ onenand_update_bufferram(mtd, addr, 0);
+
+ ret = this->wait(mtd, FL_READING);
+ if (ret)
+ return ret;
- onenand_update_bufferram(mtd, addr, 1);
+ onenand_update_bufferram(mtd, addr, 1);
- /* Check, if the two dataram areas are same */
- dataram0 = this->base + ONENAND_DATARAM;
- dataram1 = dataram0 + mtd->writesize;
+ dataram = this->base + ONENAND_DATARAM;
+ dataram += onenand_bufferram_offset(mtd, ONENAND_DATARAM);
- if (memcmp(dataram0, dataram1, mtd->writesize))
- return -EBADMSG;
+ if (memcmp(buf, dataram + column, thislen))
+ return -EBADMSG;
+
+ len -= thislen;
+ buf += thislen;
+ addr += thislen;
+ }
return 0;
}
#else
-#define onenand_verify_page(...) (0)
+#define onenand_verify(...) (0)
#define onenand_verify_oob(...) (0)
#endif
@@ -988,60 +1186,57 @@ static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len,
/* Do not allow writes past end of device */
if (unlikely((to + len) > mtd->size)) {
- DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: Attempt write to past end of device\n");
+ printk(KERN_ERR "onenand_write: Attempt write to past end of device\n");
return -EINVAL;
}
/* Reject writes, which are not page aligned */
if (unlikely(NOTALIGNED(to)) || unlikely(NOTALIGNED(len))) {
- DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: Attempt to write not page aligned data\n");
+ printk(KERN_ERR "onenand_write: Attempt to write not page aligned data\n");
return -EINVAL;
}
column = to & (mtd->writesize - 1);
- subpage = column || (len & (mtd->writesize - 1));
/* Grab the lock and see if the device is available */
onenand_get_device(mtd, FL_WRITING);
/* Loop until all data write */
while (written < len) {
- int bytes = mtd->writesize;
- int thislen = min_t(int, bytes, len - written);
+ int thislen = min_t(int, mtd->writesize - column, len - written);
u_char *wbuf = (u_char *) buf;
cond_resched();
- this->command(mtd, ONENAND_CMD_BUFFERRAM, to, bytes);
+ this->command(mtd, ONENAND_CMD_BUFFERRAM, to, thislen);
/* Partial page write */
+ subpage = thislen < mtd->writesize;
if (subpage) {
- bytes = min_t(int, bytes - column, (int) len);
memset(this->page_buf, 0xff, mtd->writesize);
- memcpy(this->page_buf + column, buf, bytes);
+ memcpy(this->page_buf + column, buf, thislen);
wbuf = this->page_buf;
- /* Even though partial write, we need page size */
- thislen = mtd->writesize;
}
- this->write_bufferram(mtd, ONENAND_DATARAM, wbuf, 0, thislen);
+ this->write_bufferram(mtd, ONENAND_DATARAM, wbuf, 0, mtd->writesize);
this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize);
this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize);
+ ret = this->wait(mtd, FL_WRITING);
+
/* In partial page write we don't update bufferram */
- onenand_update_bufferram(mtd, to, !subpage);
+ onenand_update_bufferram(mtd, to, !ret && !subpage);
- ret = this->wait(mtd, FL_WRITING);
if (ret) {
- DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: write filaed %d\n", ret);
+ printk(KERN_ERR "onenand_write: write filaed %d\n", ret);
break;
}
/* Only check verify write turn on */
- ret = onenand_verify_page(mtd, (u_char *) wbuf, to);
+ ret = onenand_verify(mtd, (u_char *) wbuf, to, thislen);
if (ret) {
- DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: verify failed %d\n", ret);
+ printk(KERN_ERR "onenand_write: verify failed %d\n", ret);
break;
}
@@ -1064,20 +1259,58 @@ static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len,
}
/**
+ * onenand_fill_auto_oob - [Internal] oob auto-placement transfer
+ * @param mtd MTD device structure
+ * @param oob_buf oob buffer
+ * @param buf source address
+ * @param column oob offset to write to
+ * @param thislen oob length to write
+ */
+static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf,
+ const u_char *buf, int column, int thislen)
+{
+ struct onenand_chip *this = mtd->priv;
+ struct nand_oobfree *free;
+ int writecol = column;
+ int writeend = column + thislen;
+ int lastgap = 0;
+
+ for (free = this->ecclayout->oobfree; free->length; ++free) {
+ if (writecol >= lastgap)
+ writecol += free->offset - lastgap;
+ if (writeend >= lastgap)
+ writeend += free->offset - lastgap;
+ lastgap = free->offset + free->length;
+ }
+ for (free = this->ecclayout->oobfree; free->length; ++free) {
+ int free_end = free->offset + free->length;
+ if (free->offset < writeend && free_end > writecol) {
+ int st = max_t(int,free->offset,writecol);
+ int ed = min_t(int,free_end,writeend);
+ int n = ed - st;
+ memcpy(oob_buf + st, buf, n);
+ buf += n;
+ }
+ }
+ return 0;
+}
+
+/**
* onenand_do_write_oob - [Internal] OneNAND write out-of-band
* @param mtd MTD device structure
* @param to offset to write to
* @param len number of bytes to write
* @param retlen pointer to variable to store the number of written bytes
* @param buf the data to write
+ * @param mode operation mode
*
* OneNAND write out-of-band
*/
static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
- size_t *retlen, const u_char *buf)
+ size_t *retlen, const u_char *buf, mtd_oob_mode_t mode)
{
struct onenand_chip *this = mtd->priv;
- int column, ret = 0;
+ int column, ret = 0, oobsize;
int written = 0;
DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_oob: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
@@ -1085,9 +1318,30 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
/* Initialize retlen, in case of early exit */
*retlen = 0;
- /* Do not allow writes past end of device */
- if (unlikely((to + len) > mtd->size)) {
- DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_oob: Attempt write to past end of device\n");
+ if (mode == MTD_OOB_AUTO)
+ oobsize = this->ecclayout->oobavail;
+ else
+ oobsize = mtd->oobsize;
+
+ column = to & (mtd->oobsize - 1);
+
+ if (unlikely(column >= oobsize)) {
+ printk(KERN_ERR "onenand_write_oob: Attempted to start write outside oob\n");
+ return -EINVAL;
+ }
+
+ /* For compatibility with NAND: Do not allow write past end of page */
+ if (column + len > oobsize) {
+ printk(KERN_ERR "onenand_write_oob: "
+ "Attempt to write past end of page\n");
+ return -EINVAL;
+ }
+
+ /* Do not allow reads past end of device */
+ if (unlikely(to >= mtd->size ||
+ column + len > ((mtd->size >> this->page_shift) -
+ (to >> this->page_shift)) * oobsize)) {
+ printk(KERN_ERR "onenand_write_oob: Attempted to write past end of device\n");
return -EINVAL;
}
@@ -1096,18 +1350,19 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
/* Loop until all data write */
while (written < len) {
- int thislen = min_t(int, mtd->oobsize, len - written);
+ int thislen = min_t(int, oobsize, len - written);
cond_resched();
- column = to & (mtd->oobsize - 1);
-
this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->oobsize);
/* We send data to spare ram with oobsize
* to prevent byte access */
memset(this->page_buf, 0xff, mtd->oobsize);
- memcpy(this->page_buf + column, buf, thislen);
+ if (mode == MTD_OOB_AUTO)
+ onenand_fill_auto_oob(mtd, this->page_buf, buf, column, thislen);
+ else
+ memcpy(this->page_buf + column, buf, thislen);
this->write_bufferram(mtd, ONENAND_SPARERAM, this->page_buf, 0, mtd->oobsize);
this->command(mtd, ONENAND_CMD_PROGOOB, to, mtd->oobsize);
@@ -1116,26 +1371,25 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
ret = this->wait(mtd, FL_WRITING);
if (ret) {
- DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_oob: write filaed %d\n", ret);
- goto out;
+ printk(KERN_ERR "onenand_write_oob: write failed %d\n", ret);
+ break;
}
- ret = onenand_verify_oob(mtd, buf, to, thislen);
+ ret = onenand_verify_oob(mtd, this->page_buf, to);
if (ret) {
- DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_oob: verify failed %d\n", ret);
- goto out;
+ printk(KERN_ERR "onenand_write_oob: verify failed %d\n", ret);
+ break;
}
written += thislen;
-
if (written == len)
break;
- to += thislen;
+ to += mtd->writesize;
buf += thislen;
+ column = 0;
}
-out:
/* Deselect and wake up anyone waiting on the device */
onenand_release_device(mtd);
@@ -1153,10 +1407,17 @@ out:
static int onenand_write_oob(struct mtd_info *mtd, loff_t to,
struct mtd_oob_ops *ops)
{
- BUG_ON(ops->mode != MTD_OOB_PLACE);
-
+ switch (ops->mode) {
+ case MTD_OOB_PLACE:
+ case MTD_OOB_AUTO:
+ break;
+ case MTD_OOB_RAW:
+ /* Not implemented yet */
+ default:
+ return -EINVAL;
+ }
return onenand_do_write_oob(mtd, to + ops->ooboffs, ops->ooblen,
- &ops->oobretlen, ops->oobbuf);
+ &ops->oobretlen, ops->oobbuf, ops->mode);
}
/**
@@ -1199,19 +1460,19 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
/* Start address must align on block boundary */
if (unlikely(instr->addr & (block_size - 1))) {
- DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Unaligned address\n");
+ printk(KERN_ERR "onenand_erase: Unaligned address\n");
return -EINVAL;
}
/* Length must align on block boundary */
if (unlikely(instr->len & (block_size - 1))) {
- DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Length not block aligned\n");
+ printk(KERN_ERR "onenand_erase: Length not block aligned\n");
return -EINVAL;
}
/* Do not allow erase past end of device */
if (unlikely((instr->len + instr->addr) > mtd->size)) {
- DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Erase past end of device\n");
+ printk(KERN_ERR "onenand_erase: Erase past end of device\n");
return -EINVAL;
}
@@ -1238,10 +1499,12 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
this->command(mtd, ONENAND_CMD_ERASE, addr, block_size);
+ onenand_invalidate_bufferram(mtd, addr, block_size);
+
ret = this->wait(mtd, FL_ERASING);
/* Check, if it is write protected */
if (ret) {
- DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Failed erase, block %d\n", (unsigned) (addr >> this->erase_shift));
+ printk(KERN_ERR "onenand_erase: Failed erase, block %d\n", (unsigned) (addr >> this->erase_shift));
instr->state = MTD_ERASE_FAILED;
instr->fail_addr = addr;
goto erase_exit;
@@ -1322,7 +1585,7 @@ static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
/* We write two bytes, so we dont have to mess with 16 bit access */
ofs += mtd->oobsize + (bbm->badblockpos & ~0x01);
- return onenand_do_write_oob(mtd, ofs , 2, &retlen, buf);
+ return onenand_do_write_oob(mtd, ofs , 2, &retlen, buf, MTD_OOB_PLACE);
}
/**
@@ -1491,6 +1754,8 @@ static int onenand_unlock_all(struct mtd_info *mtd)
struct onenand_chip *this = mtd->priv;
if (this->options & ONENAND_HAS_UNLOCK_ALL) {
+ /* Set start block address */
+ this->write_word(0, this->base + ONENAND_REG_START_BLOCK_ADDRESS);
/* Write unlock command */
this->command(mtd, ONENAND_CMD_UNLOCK_ALL, 0, 0);
@@ -1503,13 +1768,10 @@ static int onenand_unlock_all(struct mtd_info *mtd)
continue;
/* Workaround for all block unlock in DDP */
- if (this->device_id & ONENAND_DEVICE_IS_DDP) {
- loff_t ofs;
- size_t len;
-
+ if (ONENAND_IS_DDP(this)) {
/* 1st block on another chip */
- ofs = this->chipsize >> 1;
- len = 1 << this->erase_shift;
+ loff_t ofs = this->chipsize >> 1;
+ size_t len = mtd->erasesize;
onenand_unlock(mtd, ofs, len);
}
@@ -1617,7 +1879,7 @@ static int do_otp_lock(struct mtd_info *mtd, loff_t from, size_t len,
this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0);
this->wait(mtd, FL_OTPING);
- ret = onenand_do_write_oob(mtd, from, len, retlen, buf);
+ ret = onenand_do_write_oob(mtd, from, len, retlen, buf, MTD_OOB_PLACE);
/* Exit OTP access mode */
this->command(mtd, ONENAND_CMD_RESET, 0, 0);
@@ -1823,12 +2085,13 @@ static int onenand_lock_user_prot_reg(struct mtd_info *mtd, loff_t from,
#endif /* CONFIG_MTD_ONENAND_OTP */
/**
- * onenand_lock_scheme - Check and set OneNAND lock scheme
+ * onenand_check_features - Check and set OneNAND features
* @param mtd MTD data structure
*
- * Check and set OneNAND lock scheme
+ * Check and set OneNAND features
+ * - lock scheme
*/
-static void onenand_lock_scheme(struct mtd_info *mtd)
+static void onenand_check_features(struct mtd_info *mtd)
{
struct onenand_chip *this = mtd->priv;
unsigned int density, process;
@@ -1961,26 +2224,28 @@ static int onenand_probe(struct mtd_info *mtd)
density = dev_id >> ONENAND_DEVICE_DENSITY_SHIFT;
this->chipsize = (16 << density) << 20;
/* Set density mask. it is used for DDP */
- this->density_mask = (1 << (density + 6));
+ if (ONENAND_IS_DDP(this))
+ this->density_mask = (1 << (density + 6));
+ else
+ this->density_mask = 0;
/* OneNAND page size & block size */
/* The data buffer size is equal to page size */
mtd->writesize = this->read_word(this->base + ONENAND_REG_DATA_BUFFER_SIZE);
mtd->oobsize = mtd->writesize >> 5;
- /* Pagers per block is always 64 in OneNAND */
+ /* Pages per a block are always 64 in OneNAND */
mtd->erasesize = mtd->writesize << 6;
this->erase_shift = ffs(mtd->erasesize) - 1;
this->page_shift = ffs(mtd->writesize) - 1;
- this->ppb_shift = (this->erase_shift - this->page_shift);
- this->page_mask = (mtd->erasesize / mtd->writesize) - 1;
+ this->page_mask = (1 << (this->erase_shift - this->page_shift)) - 1;
/* REVIST: Multichip handling */
mtd->size = this->chipsize;
- /* Check OneNAND lock scheme */
- onenand_lock_scheme(mtd);
+ /* Check OneNAND features */
+ onenand_check_features(mtd);
return 0;
}
@@ -2021,6 +2286,7 @@ static void onenand_resume(struct mtd_info *mtd)
*/
int onenand_scan(struct mtd_info *mtd, int maxchips)
{
+ int i;
struct onenand_chip *this = mtd->priv;
if (!this->read_word)
@@ -2092,12 +2358,21 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
}
this->subpagesize = mtd->writesize >> mtd->subpage_sft;
+
+ /*
+ * The number of bytes available for a client to place data into
+ * the out of band area
+ */
+ this->ecclayout->oobavail = 0;
+ for (i = 0; this->ecclayout->oobfree[i].length; i++)
+ this->ecclayout->oobavail +=
+ this->ecclayout->oobfree[i].length;
+
mtd->ecclayout = this->ecclayout;
/* Fill in remaining MTD driver data */
mtd->type = MTD_NANDFLASH;
mtd->flags = MTD_CAP_NANDFLASH;
- mtd->ecctype = MTD_ECC_SW;
mtd->erase = onenand_erase;
mtd->point = NULL;
mtd->unpoint = NULL;
@@ -2144,8 +2419,11 @@ void onenand_release(struct mtd_info *mtd)
del_mtd_device (mtd);
/* Free bad block table memory, if allocated */
- if (this->bbm)
+ if (this->bbm) {
+ struct bbm_info *bbm = this->bbm;
+ kfree(bbm->bbt);
kfree(this->bbm);
+ }
/* Buffer allocated by onenand_scan */
if (this->options & ONENAND_PAGEBUF_ALLOC)
kfree(this->page_buf);
diff --git a/drivers/mtd/onenand/onenand_bbt.c b/drivers/mtd/onenand/onenand_bbt.c
index 98f8fd1c637..aecdd50a178 100644
--- a/drivers/mtd/onenand/onenand_bbt.c
+++ b/drivers/mtd/onenand/onenand_bbt.c
@@ -17,8 +17,8 @@
#include <linux/mtd/onenand.h>
#include <linux/mtd/compatmac.h>
-extern int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char *buf);
+extern int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,
+ struct mtd_oob_ops *ops);
/**
* check_short_pattern - [GENERIC] check if a pattern is in the buffer
@@ -65,10 +65,11 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
int startblock;
loff_t from;
size_t readlen, ooblen;
+ struct mtd_oob_ops ops;
printk(KERN_INFO "Scanning device for bad blocks\n");
- len = 1;
+ len = 2;
/* We need only read few bytes from the OOB area */
scanlen = ooblen = 0;
@@ -82,22 +83,24 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
startblock = 0;
from = 0;
+ ops.mode = MTD_OOB_PLACE;
+ ops.ooblen = readlen;
+ ops.oobbuf = buf;
+ ops.len = ops.ooboffs = ops.retlen = ops.oobretlen = 0;
+
for (i = startblock; i < numblocks; ) {
int ret;
for (j = 0; j < len; j++) {
- size_t retlen;
-
/* No need to read pages fully,
* just read required OOB bytes */
- ret = onenand_do_read_oob(mtd, from + j * mtd->writesize + bd->offs,
- readlen, &retlen, &buf[0]);
+ ret = onenand_bbt_read_oob(mtd, from + j * mtd->writesize + bd->offs, &ops);
/* If it is a initial bad block, just ignore it */
- if (ret && !(ret & ONENAND_CTRL_LOAD))
- return ret;
+ if (ret == ONENAND_BBT_READ_FATAL_ERROR)
+ return -EIO;
- if (check_short_pattern(&buf[j * scanlen], scanlen, mtd->writesize, bd)) {
+ if (ret || check_short_pattern(&buf[j * scanlen], scanlen, mtd->writesize, bd)) {
bbm->bbt[i >> 3] |= 0x03 << (i & 0x6);
printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n",
i >> 1, (unsigned int) from);
@@ -168,8 +171,8 @@ static int onenand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
* marked good / bad blocks and writes the bad block table(s) to
* the selected place.
*
- * The bad block table memory is allocated here. It must be freed
- * by calling the onenand_free_bbt function.
+ * The bad block table memory is allocated here. It is freed
+ * by the onenand_release function.
*
*/
int onenand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
diff --git a/drivers/mtd/redboot.c b/drivers/mtd/redboot.c
index 035cd9b0cc0..a61351f88ec 100644
--- a/drivers/mtd/redboot.c
+++ b/drivers/mtd/redboot.c
@@ -94,8 +94,19 @@ static int parse_redboot_partitions(struct mtd_info *master,
* (NOTE: this is 'size' not 'data_length'; size is
* the full size of the entry.)
*/
- if (swab32(buf[i].size) == master->erasesize) {
+
+ /* RedBoot can combine the FIS directory and
+ config partitions into a single eraseblock;
+ we assume wrong-endian if either the swapped
+ 'size' matches the eraseblock size precisely,
+ or if the swapped size actually fits in an
+ eraseblock while the unswapped size doesn't. */
+ if (swab32(buf[i].size) == master->erasesize ||
+ (buf[i].size > master->erasesize
+ && swab32(buf[i].size) < master->erasesize)) {
int j;
+ /* Update numslots based on actual FIS directory size */
+ numslots = swab32(buf[i].size) / sizeof (struct fis_image_desc);
for (j = 0; j < numslots; ++j) {
/* A single 0xff denotes a deleted entry.
@@ -120,11 +131,11 @@ static int parse_redboot_partitions(struct mtd_info *master,
swab32s(&buf[j].desc_cksum);
swab32s(&buf[j].file_cksum);
}
+ } else if (buf[i].size < master->erasesize) {
+ /* Update numslots based on actual FIS directory size */
+ numslots = buf[i].size / sizeof(struct fis_image_desc);
}
break;
- } else {
- /* re-calculate of real numslots */
- numslots = buf[i].size / sizeof(struct fis_image_desc);
}
}
if (i == numslots) {
diff --git a/drivers/net/3c503.c b/drivers/net/3c503.c
index 7e34c4f07b7..bc7e906571d 100644
--- a/drivers/net/3c503.c
+++ b/drivers/net/3c503.c
@@ -600,8 +600,7 @@ el2_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring
count -= semi_count;
memcpy_fromio(skb->data + semi_count, base + ei_status.priv, count);
} else {
- /* Packet is in one chunk -- we can copy + cksum. */
- eth_io_copy_and_sum(skb, base + ring_offset, count, 0);
+ memcpy_fromio(skb->data, base + ring_offset, count);
}
return;
}
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
index 80bdcf84623..716a47210aa 100644
--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -792,8 +792,7 @@ static void poll_vortex(struct net_device *dev)
{
struct vortex_private *vp = netdev_priv(dev);
unsigned long flags;
- local_save_flags(flags);
- local_irq_disable();
+ local_irq_save(flags);
(vp->full_bus_master_rx ? boomerang_interrupt:vortex_interrupt)(dev->irq,dev);
local_irq_restore(flags);
}
diff --git a/drivers/net/7990.c b/drivers/net/7990.c
index 2d5ba076471..1b3d11ed6cf 100644
--- a/drivers/net/7990.c
+++ b/drivers/net/7990.c
@@ -500,7 +500,7 @@ int lance_open (struct net_device *dev)
int res;
/* Install the Interrupt handler. Or we could shunt this out to specific drivers? */
- if (request_irq(lp->irq, lance_interrupt, SA_SHIRQ, lp->name, dev))
+ if (request_irq(lp->irq, lance_interrupt, IRQF_SHARED, lp->name, dev))
return -EAGAIN;
res = lance_reset(dev);
diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c
index 35ad5cff18e..99304b2aa86 100644
--- a/drivers/net/8139too.c
+++ b/drivers/net/8139too.c
@@ -1109,6 +1109,8 @@ static void __devexit rtl8139_remove_one (struct pci_dev *pdev)
assert (dev != NULL);
+ flush_scheduled_work();
+
unregister_netdev (dev);
__rtl8139_cleanup_dev (dev);
@@ -1603,18 +1605,21 @@ static void rtl8139_thread (struct work_struct *work)
struct net_device *dev = tp->mii.dev;
unsigned long thr_delay = next_tick;
+ rtnl_lock();
+
+ if (!netif_running(dev))
+ goto out_unlock;
+
if (tp->watchdog_fired) {
tp->watchdog_fired = 0;
rtl8139_tx_timeout_task(work);
- } else if (rtnl_trylock()) {
- rtl8139_thread_iter (dev, tp, tp->mmio_addr);
- rtnl_unlock ();
- } else {
- /* unlikely race. mitigate with fast poll. */
- thr_delay = HZ / 2;
- }
+ } else
+ rtl8139_thread_iter(dev, tp, tp->mmio_addr);
- schedule_delayed_work(&tp->thread, thr_delay);
+ if (tp->have_thread)
+ schedule_delayed_work(&tp->thread, thr_delay);
+out_unlock:
+ rtnl_unlock ();
}
static void rtl8139_start_thread(struct rtl8139_private *tp)
@@ -1626,19 +1631,11 @@ static void rtl8139_start_thread(struct rtl8139_private *tp)
return;
tp->have_thread = 1;
+ tp->watchdog_fired = 0;
schedule_delayed_work(&tp->thread, next_tick);
}
-static void rtl8139_stop_thread(struct rtl8139_private *tp)
-{
- if (tp->have_thread) {
- cancel_rearming_delayed_work(&tp->thread);
- tp->have_thread = 0;
- } else
- flush_scheduled_work();
-}
-
static inline void rtl8139_tx_clear (struct rtl8139_private *tp)
{
tp->cur_tx = 0;
@@ -1696,12 +1693,11 @@ static void rtl8139_tx_timeout (struct net_device *dev)
{
struct rtl8139_private *tp = netdev_priv(dev);
+ tp->watchdog_fired = 1;
if (!tp->have_thread) {
- INIT_DELAYED_WORK(&tp->thread, rtl8139_tx_timeout_task);
+ INIT_DELAYED_WORK(&tp->thread, rtl8139_thread);
schedule_delayed_work(&tp->thread, next_tick);
- } else
- tp->watchdog_fired = 1;
-
+ }
}
static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev)
@@ -2233,8 +2229,6 @@ static int rtl8139_close (struct net_device *dev)
netif_stop_queue (dev);
- rtl8139_stop_thread(tp);
-
if (netif_msg_ifdown(tp))
printk(KERN_DEBUG "%s: Shutting down ethercard, status was 0x%4.4x.\n",
dev->name, RTL_R16 (IntrStatus));
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 79eade7e9d9..38ac6796fc4 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -190,7 +190,7 @@ config MII
config MACB
tristate "Atmel MACB support"
- depends on NET_ETHERNET && AVR32
+ depends on NET_ETHERNET && (AVR32 || ARCH_AT91SAM9260 || ARCH_AT91SAM9263)
select MII
help
The Atmel MACB ethernet interface is found on many AT32 and AT91
@@ -235,16 +235,6 @@ config BMAC
To compile this driver as a module, choose M here: the module
will be called bmac.
-config OAKNET
- tristate "National DP83902AV (Oak ethernet) support"
- depends on NET_ETHERNET && PPC && BROKEN
- select CRC32
- help
- Say Y if your machine has this type of Ethernet network card.
-
- To compile this driver as a module, choose M here: the module
- will be called oaknet.
-
config ARIADNE
tristate "Ariadne support"
depends on NET_ETHERNET && ZORRO
@@ -1155,21 +1145,6 @@ config SEEQ8005
<file:Documentation/networking/net-modules.txt>. The module
will be called seeq8005.
-config SKMC
- tristate "SKnet MCA support"
- depends on NET_ETHERNET && MCA && BROKEN
- ---help---
- These are Micro Channel Ethernet adapters. You need to say Y to "MCA
- support" in order to use this driver. Supported cards are the SKnet
- Junior MC2 and the SKnet MC2(+). The driver automatically
- distinguishes between the two cards. Note that using multiple boards
- of different type hasn't been tested with this driver. Say Y if you
- have one of these Ethernet adapters.
-
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module
- will be called sk_mca.
-
config NE2_MCA
tristate "NE/2 (ne2000 MCA version) support"
depends on NET_ETHERNET && MCA_LEGACY
@@ -1309,8 +1284,8 @@ config PCNET32
will be called pcnet32.
config PCNET32_NAPI
- bool "Use RX polling (NAPI) (EXPERIMENTAL)"
- depends on PCNET32 && EXPERIMENTAL
+ bool "Use RX polling (NAPI)"
+ depends on PCNET32
help
NAPI is a new driver API designed to reduce CPU and interrupt load
when the driver is receiving lots of packets from the card. It is
@@ -1788,6 +1763,18 @@ config LAN_SAA9730
workstations.
See <http://www.semiconductors.philips.com/pip/SAA9730_flyer_1>.
+config SC92031
+ tristate "Silan SC92031 PCI Fast Ethernet Adapter driver (EXPERIMENTAL)"
+ depends on NET_PCI && PCI && EXPERIMENTAL
+ select CRC32
+ ---help---
+ This is a driver for the Fast Ethernet PCI network cards based on
+ the Silan SC92031 chip (sometimes also called Rsltek 8139D). If you
+ have one of these, say Y here.
+
+ To compile this driver as a module, choose M here: the module
+ will be called sc92031. This is recommended.
+
config NET_POCKET
bool "Pocket and portable adapters"
depends on NET_ETHERNET && PARPORT
@@ -2138,14 +2125,16 @@ config SKY2
will be called sky2. This is recommended.
config SK98LIN
- tristate "Marvell Yukon Chipset / SysKonnect SK-98xx Support"
+ tristate "Marvell Yukon Chipset / SysKonnect SK-98xx Support (DEPRECATED)"
depends on PCI
---help---
Say Y here if you have a Marvell Yukon or SysKonnect SK-98xx/SK-95xx
compliant Gigabit Ethernet Adapter.
- This driver supports the original Yukon chipset. A cleaner driver is
- also available (skge) which seems to work better than this one.
+ This driver supports the original Yukon chipset. This driver is
+ deprecated and will be removed from the kernel in the near future,
+ it has been replaced by the skge driver. skge is cleaner and
+ seems to work better.
This driver does not support the newer Yukon2 chipset. A separate
driver, sky2, is provided to support Yukon2-based adapters.
@@ -2318,27 +2307,6 @@ config MV643XX_ETH
chipset which is used in the Momenco Ocelot C and Jaguar ATX and
Pegasos II, amongst other PPC and MIPS boards.
-config MV643XX_ETH_0
- bool "MV-643XX Port 0"
- depends on MV643XX_ETH
- help
- This enables support for Port 0 of the Marvell MV643XX Gigabit
- Ethernet.
-
-config MV643XX_ETH_1
- bool "MV-643XX Port 1"
- depends on MV643XX_ETH
- help
- This enables support for Port 1 of the Marvell MV643XX Gigabit
- Ethernet.
-
-config MV643XX_ETH_2
- bool "MV-643XX Port 2"
- depends on MV643XX_ETH
- help
- This enables support for Port 2 of the Marvell MV643XX Gigabit
- Ethernet.
-
config QLA3XXX
tristate "QLogic QLA3XXX Network Driver Support"
depends on PCI
@@ -2348,6 +2316,17 @@ config QLA3XXX
To compile this driver as a module, choose M here: the module
will be called qla3xxx.
+config ATL1
+ tristate "Attansic L1 Gigabit Ethernet support (EXPERIMENTAL)"
+ depends on PCI && EXPERIMENTAL
+ select CRC32
+ select MII
+ help
+ This driver supports the Attansic L1 gigabit ethernet adapter.
+
+ To compile this driver as a module, choose M here. The module
+ will be called atl1.
+
endmenu
#
@@ -2392,6 +2371,24 @@ config CHELSIO_T1_NAPI
NAPI is a driver API designed to reduce CPU and interrupt load
when the driver is receiving lots of packets from the card.
+config CHELSIO_T3
+ tristate "Chelsio Communications T3 10Gb Ethernet support"
+ depends on PCI
+ help
+ This driver supports Chelsio T3-based gigabit and 10Gb Ethernet
+ adapters.
+
+ For general information about Chelsio and our products, visit
+ our website at <http://www.chelsio.com>.
+
+ For customer support, please visit our customer support page at
+ <http://www.chelsio.com/support.htm>.
+
+ Please send feedback to <linux-bugs@chelsio.com>.
+
+ To compile this driver as a module, choose M here: the module
+ will be called cxgb3.
+
config EHEA
tristate "eHEA Ethernet support"
depends on IBMEBUS
@@ -2488,6 +2485,13 @@ config NETXEN_NIC
help
This enables the support for NetXen's Gigabit Ethernet card.
+config PASEMI_MAC
+ tristate "PA Semi 1/10Gbit MAC"
+ depends on PPC64 && PCI
+ help
+ This driver supports the on-chip 1/10Gbit Ethernet controller on
+ PA Semi's PWRficient line of chips.
+
endmenu
source "drivers/net/tokenring/Kconfig"
@@ -2522,7 +2526,7 @@ config RIONET_RX_SIZE
config FDDI
bool "FDDI driver support"
- depends on (PCI || EISA)
+ depends on (PCI || EISA || TC)
help
Fiber Distributed Data Interface is a high speed local area network
design; essentially a replacement for high speed Ethernet. FDDI can
@@ -2532,15 +2536,36 @@ config FDDI
will say N.
config DEFXX
- tristate "Digital DEFEA and DEFPA adapter support"
- depends on FDDI && (PCI || EISA)
- help
- This is support for the DIGITAL series of EISA (DEFEA) and PCI
- (DEFPA) controllers which can connect you to a local FDDI network.
+ tristate "Digital DEFTA/DEFEA/DEFPA adapter support"
+ depends on FDDI && (PCI || EISA || TC)
+ ---help---
+ This is support for the DIGITAL series of TURBOchannel (DEFTA),
+ EISA (DEFEA) and PCI (DEFPA) controllers which can connect you
+ to a local FDDI network.
+
+ To compile this driver as a module, choose M here: the module
+ will be called defxx. If unsure, say N.
+
+config DEFXX_MMIO
+ bool
+ prompt "Use MMIO instead of PIO" if PCI || EISA
+ depends on DEFXX
+ default n if PCI || EISA
+ default y
+ ---help---
+ This instructs the driver to use EISA or PCI memory-mapped I/O
+ (MMIO) as appropriate instead of programmed I/O ports (PIO).
+ Enabling this gives an improvement in processing time in parts
+ of the driver, but it may cause problems with EISA (DEFEA)
+ adapters. TURBOchannel does not have the concept of I/O ports,
+ so MMIO is always used for these (DEFTA) adapters.
+
+ If unsure, say N.
config SKFP
tristate "SysKonnect FDDI PCI support"
depends on FDDI && PCI
+ select BITREVERSE
---help---
Say Y here if you have a SysKonnect FDDI PCI adapter.
The following adapters are supported by this driver:
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 4c0d4e5ce42..33af833667d 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -6,8 +6,10 @@ obj-$(CONFIG_E1000) += e1000/
obj-$(CONFIG_IBM_EMAC) += ibm_emac/
obj-$(CONFIG_IXGB) += ixgb/
obj-$(CONFIG_CHELSIO_T1) += chelsio/
+obj-$(CONFIG_CHELSIO_T3) += cxgb3/
obj-$(CONFIG_EHEA) += ehea/
obj-$(CONFIG_BONDING) += bonding/
+obj-$(CONFIG_ATL1) += atl1/
obj-$(CONFIG_GIANFAR) += gianfar_driver.o
gianfar_driver-objs := gianfar.o \
@@ -36,8 +38,6 @@ obj-$(CONFIG_CASSINI) += cassini.o
obj-$(CONFIG_MACE) += mace.o
obj-$(CONFIG_BMAC) += bmac.o
-obj-$(CONFIG_OAKNET) += oaknet.o 8390.o
-
obj-$(CONFIG_DGRS) += dgrs.o
obj-$(CONFIG_VORTEX) += 3c59x.o
obj-$(CONFIG_TYPHOON) += typhoon.o
@@ -137,7 +137,6 @@ obj-$(CONFIG_AT1700) += at1700.o
obj-$(CONFIG_EL1) += 3c501.o
obj-$(CONFIG_EL16) += 3c507.o
obj-$(CONFIG_ELMC) += 3c523.o
-obj-$(CONFIG_SKMC) += sk_mca.o
obj-$(CONFIG_IBMLANA) += ibmlana.o
obj-$(CONFIG_ELMC_II) += 3c527.o
obj-$(CONFIG_EL3) += 3c509.o
@@ -160,6 +159,7 @@ obj-$(CONFIG_APRICOT) += 82596.o
obj-$(CONFIG_LASI_82596) += lasi_82596.o
obj-$(CONFIG_MVME16x_NET) += 82596.o
obj-$(CONFIG_BVME6000_NET) += 82596.o
+obj-$(CONFIG_SC92031) += sc92031.o
# This is also a 82596 and should probably be merged
obj-$(CONFIG_LP486E) += lp486e.o
@@ -196,6 +196,7 @@ obj-$(CONFIG_SMC91X) += smc91x.o
obj-$(CONFIG_SMC911X) += smc911x.o
obj-$(CONFIG_DM9000) += dm9000.o
obj-$(CONFIG_FEC_8XX) += fec_8xx/
+obj-$(CONFIG_PASEMI_MAC) += pasemi_mac.o
obj-$(CONFIG_MACB) += macb.o
diff --git a/drivers/net/Space.c b/drivers/net/Space.c
index 9305eb9b1b9..dd8ed456c8b 100644
--- a/drivers/net/Space.c
+++ b/drivers/net/Space.c
@@ -59,7 +59,6 @@ extern struct net_device *wavelan_probe(int unit);
extern struct net_device *arlan_probe(int unit);
extern struct net_device *el16_probe(int unit);
extern struct net_device *elmc_probe(int unit);
-extern struct net_device *skmca_probe(int unit);
extern struct net_device *elplus_probe(int unit);
extern struct net_device *ac3200_probe(int unit);
extern struct net_device *es_probe(int unit);
@@ -153,9 +152,6 @@ static struct devprobe2 mca_probes[] __initdata = {
#ifdef CONFIG_ELMC_II /* 3c527 */
{mc32_probe, 0},
#endif
-#ifdef CONFIG_SKMC /* SKnet Microchannel */
- {skmca_probe, 0},
-#endif
{NULL, 0},
};
diff --git a/drivers/net/ac3200.c b/drivers/net/ac3200.c
index c01f87f5bed..644c408515d 100644
--- a/drivers/net/ac3200.c
+++ b/drivers/net/ac3200.c
@@ -327,8 +327,7 @@ static void ac_block_input(struct net_device *dev, int count, struct sk_buff *sk
memcpy_fromio(skb->data + semi_count,
ei_status.mem + TX_PAGES*256, count);
} else {
- /* Packet is in one chunk -- we can copy + cksum. */
- eth_io_copy_and_sum(skb, start, count, 0);
+ memcpy_fromio(skb->data, start, count);
}
}
diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c
index 18896f24d40..9c399aaefbd 100644
--- a/drivers/net/amd8111e.c
+++ b/drivers/net/amd8111e.c
@@ -1334,8 +1334,7 @@ err_no_interrupt:
static void amd8111e_poll(struct net_device *dev)
{
unsigned long flags;
- local_save_flags(flags);
- local_irq_disable();
+ local_irq_save(flags);
amd8111e_interrupt(0, dev);
local_irq_restore(flags);
}
diff --git a/drivers/net/arcnet/arc-rawmode.c b/drivers/net/arcnet/arc-rawmode.c
index e7555d4e6ff..6318814a11a 100644
--- a/drivers/net/arcnet/arc-rawmode.c
+++ b/drivers/net/arcnet/arc-rawmode.c
@@ -94,7 +94,7 @@ static void rx(struct net_device *dev, int bufnum,
BUGMSG(D_DURING, "it's a raw packet (length=%d)\n", length);
- if (length >= MinTU)
+ if (length > MTU)
ofs = 512 - length;
else
ofs = 256 - length;
@@ -183,7 +183,7 @@ static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length,
length, XMTU);
length = XMTU;
}
- if (length > MinTU) {
+ if (length >= MinTU) {
hard->offset[0] = 0;
hard->offset[1] = ofs = 512 - length;
} else if (length > MTU) {
diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c
index 4e91dab1f17..83004fdab0a 100644
--- a/drivers/net/arcnet/arcnet.c
+++ b/drivers/net/arcnet/arcnet.c
@@ -41,7 +41,7 @@
* <jojo@repas.de>
*/
-#define VERSION "arcnet: v3.93 BETA 2000/04/29 - by Avery Pennarun et al.\n"
+#define VERSION "arcnet: v3.94 BETA 2007/02/08 - by Avery Pennarun et al.\n"
#include <linux/module.h>
#include <linux/types.h>
diff --git a/drivers/net/arcnet/com20020-pci.c b/drivers/net/arcnet/com20020-pci.c
index 98d326b23c9..b8c0fa6d401 100644
--- a/drivers/net/arcnet/com20020-pci.c
+++ b/drivers/net/arcnet/com20020-pci.c
@@ -155,6 +155,7 @@ static struct pci_device_id com20020pci_id_table[] = {
{ 0x1571, 0xa00b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_IS_5MBIT },
{ 0x1571, 0xa00c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_IS_5MBIT },
{ 0x1571, 0xa00d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_IS_5MBIT },
+ { 0x1571, 0xa00e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_IS_5MBIT },
{ 0x1571, 0xa201, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT },
{ 0x1571, 0xa202, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT },
{ 0x1571, 0xa203, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT },
@@ -163,6 +164,8 @@ static struct pci_device_id com20020pci_id_table[] = {
{ 0x1571, 0xa206, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT },
{ 0x10B5, 0x9030, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT },
{ 0x10B5, 0x9050, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT },
+ { 0x14BA, 0x6000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT },
+ { 0x10B5, 0x2200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT },
{0,}
};
diff --git a/drivers/net/arcnet/com20020.c b/drivers/net/arcnet/com20020.c
index aa9dd8f1126..7cf0a251169 100644
--- a/drivers/net/arcnet/com20020.c
+++ b/drivers/net/arcnet/com20020.c
@@ -104,7 +104,7 @@ int com20020_check(struct net_device *dev)
SET_SUBADR(SUB_SETUP1);
outb(lp->setup, _XREG);
- if (lp->card_flags & ARC_CAN_10MBIT)
+ if (lp->clockm != 0)
{
SET_SUBADR(SUB_SETUP2);
outb(lp->setup2, _XREG);
@@ -338,7 +338,8 @@ static void com20020_set_mc_list(struct net_device *dev)
}
#if defined(CONFIG_ARCNET_COM20020_PCI_MODULE) || \
- defined(CONFIG_ARCNET_COM20020_ISA_MODULE)
+ defined(CONFIG_ARCNET_COM20020_ISA_MODULE) || \
+ defined(CONFIG_ARCNET_COM20020_CS_MODULE)
EXPORT_SYMBOL(com20020_check);
EXPORT_SYMBOL(com20020_found);
#endif
diff --git a/drivers/net/arm/at91_ether.c b/drivers/net/arm/at91_ether.c
index fada15d959d..1621b8fe35c 100644
--- a/drivers/net/arm/at91_ether.c
+++ b/drivers/net/arm/at91_ether.c
@@ -641,7 +641,7 @@ static void at91ether_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo
{
strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
strlcpy(info->version, DRV_VERSION, sizeof(info->version));
- strlcpy(info->bus_info, dev->class_dev.dev->bus_id, sizeof(info->bus_info));
+ strlcpy(info->bus_info, dev->dev.parent->bus_id, sizeof(info->bus_info));
}
static const struct ethtool_ops at91ether_ethtool_ops = {
diff --git a/drivers/net/arm/ether1.c b/drivers/net/arm/ether1.c
index d6da3ce9ad7..a2921882eba 100644
--- a/drivers/net/arm/ether1.c
+++ b/drivers/net/arm/ether1.c
@@ -33,7 +33,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/interrupt.h>
diff --git a/drivers/net/arm/ether3.c b/drivers/net/arm/ether3.c
index 4fc234785d5..841178343a0 100644
--- a/drivers/net/arm/ether3.c
+++ b/drivers/net/arm/ether3.c
@@ -48,7 +48,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/interrupt.h>
diff --git a/drivers/net/arm/etherh.c b/drivers/net/arm/etherh.c
index f3faa4fe58e..61f574aa3a9 100644
--- a/drivers/net/arm/etherh.c
+++ b/drivers/net/arm/etherh.c
@@ -28,7 +28,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/interrupt.h>
@@ -587,7 +586,7 @@ static void etherh_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *i
{
strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
strlcpy(info->version, DRV_VERSION, sizeof(info->version));
- strlcpy(info->bus_info, dev->class_dev.dev->bus_id,
+ strlcpy(info->bus_info, dev->dev.parent->bus_id,
sizeof(info->bus_info));
}
diff --git a/drivers/net/atl1/Makefile b/drivers/net/atl1/Makefile
new file mode 100644
index 00000000000..a6b707e4e69
--- /dev/null
+++ b/drivers/net/atl1/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_ATL1) += atl1.o
+atl1-y += atl1_main.o atl1_hw.o atl1_ethtool.o atl1_param.o
diff --git a/drivers/net/atl1/atl1.h b/drivers/net/atl1/atl1.h
new file mode 100644
index 00000000000..b1c6034e68f
--- /dev/null
+++ b/drivers/net/atl1/atl1.h
@@ -0,0 +1,283 @@
+/*
+ * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved.
+ * Copyright(c) 2006 Chris Snook <csnook@redhat.com>
+ * Copyright(c) 2006 Jay Cliburn <jcliburn@gmail.com>
+ *
+ * Derived from Intel e1000 driver
+ * Copyright(c) 1999 - 2005 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.
+ */
+
+#ifndef _ATL1_H_
+#define _ATL1_H_
+
+#include <linux/types.h>
+#include <linux/if_vlan.h>
+
+#include "atl1_hw.h"
+
+/* function prototypes needed by multiple files */
+s32 atl1_up(struct atl1_adapter *adapter);
+void atl1_down(struct atl1_adapter *adapter);
+int atl1_reset(struct atl1_adapter *adapter);
+s32 atl1_setup_ring_resources(struct atl1_adapter *adapter);
+void atl1_free_ring_resources(struct atl1_adapter *adapter);
+
+extern char atl1_driver_name[];
+extern char atl1_driver_version[];
+extern const struct ethtool_ops atl1_ethtool_ops;
+
+struct atl1_adapter;
+
+#define ATL1_MAX_INTR 3
+
+#define ATL1_DEFAULT_TPD 256
+#define ATL1_MAX_TPD 1024
+#define ATL1_MIN_TPD 64
+#define ATL1_DEFAULT_RFD 512
+#define ATL1_MIN_RFD 128
+#define ATL1_MAX_RFD 2048
+
+#define ATL1_GET_DESC(R, i, type) (&(((type *)((R)->desc))[i]))
+#define ATL1_RFD_DESC(R, i) ATL1_GET_DESC(R, i, struct rx_free_desc)
+#define ATL1_TPD_DESC(R, i) ATL1_GET_DESC(R, i, struct tx_packet_desc)
+#define ATL1_RRD_DESC(R, i) ATL1_GET_DESC(R, i, struct rx_return_desc)
+
+/*
+ * Some workarounds require millisecond delays and are run during interrupt
+ * context. Most notably, when establishing link, the phy may need tweaking
+ * but cannot process phy register reads/writes faster than millisecond
+ * intervals...and we establish link due to a "link status change" interrupt.
+ */
+
+/*
+ * wrapper around a pointer to a socket buffer,
+ * so a DMA handle can be stored along with the buffer
+ */
+struct atl1_buffer {
+ struct sk_buff *skb;
+ u16 length;
+ u16 alloced;
+ dma_addr_t dma;
+};
+
+#define MAX_TX_BUF_LEN 0x3000 /* 12KB */
+
+struct atl1_tpd_ring {
+ void *desc; /* pointer to the descriptor ring memory */
+ dma_addr_t dma; /* physical adress of the descriptor ring */
+ u16 size; /* length of descriptor ring in bytes */
+ u16 count; /* number of descriptors in the ring */
+ u16 hw_idx; /* hardware index */
+ atomic_t next_to_clean;
+ atomic_t next_to_use;
+ struct atl1_buffer *buffer_info;
+};
+
+struct atl1_rfd_ring {
+ void *desc;
+ dma_addr_t dma;
+ u16 size;
+ u16 count;
+ atomic_t next_to_use;
+ u16 next_to_clean;
+ struct atl1_buffer *buffer_info;
+};
+
+struct atl1_rrd_ring {
+ void *desc;
+ dma_addr_t dma;
+ unsigned int size;
+ u16 count;
+ u16 next_to_use;
+ atomic_t next_to_clean;
+};
+
+struct atl1_ring_header {
+ void *desc; /* pointer to the descriptor ring memory */
+ dma_addr_t dma; /* physical adress of the descriptor ring */
+ unsigned int size; /* length of descriptor ring in bytes */
+};
+
+struct atl1_cmb {
+ struct coals_msg_block *cmb;
+ dma_addr_t dma;
+};
+
+struct atl1_smb {
+ struct stats_msg_block *smb;
+ dma_addr_t dma;
+};
+
+/* Statistics counters */
+struct atl1_sft_stats {
+ u64 rx_packets;
+ u64 tx_packets;
+ u64 rx_bytes;
+ u64 tx_bytes;
+ u64 multicast;
+ u64 collisions;
+ u64 rx_errors;
+ u64 rx_length_errors;
+ u64 rx_crc_errors;
+ u64 rx_frame_errors;
+ u64 rx_fifo_errors;
+ u64 rx_missed_errors;
+ u64 tx_errors;
+ u64 tx_fifo_errors;
+ u64 tx_aborted_errors;
+ u64 tx_window_errors;
+ u64 tx_carrier_errors;
+
+ u64 tx_pause; /* num Pause packet transmitted. */
+ u64 excecol; /* num tx packets aborted due to excessive collisions. */
+ u64 deffer; /* num deferred tx packets */
+ u64 scc; /* num packets subsequently transmitted successfully w/ single prior collision. */
+ u64 mcc; /* num packets subsequently transmitted successfully w/ multiple prior collisions. */
+ u64 latecol; /* num tx packets w/ late collisions. */
+ u64 tx_underun; /* num tx packets aborted due to transmit FIFO underrun, or TRD FIFO underrun */
+ u64 tx_trunc; /* num tx packets truncated due to size exceeding MTU, regardless whether truncated by Selene or not. (The name doesn't really reflect the meaning in this case.) */
+ u64 rx_pause; /* num Pause packets received. */
+ u64 rx_rrd_ov;
+ u64 rx_trunc;
+};
+
+/* board specific private data structure */
+#define ATL1_REGS_LEN 8
+
+/* Structure containing variables used by the shared code */
+struct atl1_hw {
+ u8 __iomem *hw_addr;
+ struct atl1_adapter *back;
+ enum atl1_dma_order dma_ord;
+ enum atl1_dma_rcb rcb_value;
+ enum atl1_dma_req_block dmar_block;
+ enum atl1_dma_req_block dmaw_block;
+ u8 preamble_len;
+ u8 max_retry; /* Retransmission maximum, after which the packet will be discarded */
+ u8 jam_ipg; /* IPG to start JAM for collision based flow control in half-duplex mode. In units of 8-bit time */
+ u8 ipgt; /* Desired back to back inter-packet gap. The default is 96-bit time */
+ u8 min_ifg; /* Minimum number of IFG to enforce in between RX frames. Frame gap below such IFP is dropped */
+ u8 ipgr1; /* 64bit Carrier-Sense window */
+ u8 ipgr2; /* 96-bit IPG window */
+ u8 tpd_burst; /* Number of TPD to prefetch in cache-aligned burst. Each TPD is 16 bytes long */
+ u8 rfd_burst; /* Number of RFD to prefetch in cache-aligned burst. Each RFD is 12 bytes long */
+ u8 rfd_fetch_gap;
+ u8 rrd_burst; /* Threshold number of RRDs that can be retired in a burst. Each RRD is 16 bytes long */
+ u8 tpd_fetch_th;
+ u8 tpd_fetch_gap;
+ u16 tx_jumbo_task_th;
+ u16 txf_burst; /* Number of data bytes to read in a cache-aligned burst. Each SRAM entry is
+ 8 bytes long */
+ u16 rx_jumbo_th; /* Jumbo packet size for non-VLAN packet. VLAN packets should add 4 bytes */
+ u16 rx_jumbo_lkah;
+ u16 rrd_ret_timer; /* RRD retirement timer. Decrement by 1 after every 512ns passes. */
+ u16 lcol; /* Collision Window */
+
+ u16 cmb_tpd;
+ u16 cmb_rrd;
+ u16 cmb_rx_timer;
+ u16 cmb_tx_timer;
+ u32 smb_timer;
+ u16 media_type;
+ u16 autoneg_advertised;
+ u16 pci_cmd_word;
+
+ u16 mii_autoneg_adv_reg;
+ u16 mii_1000t_ctrl_reg;
+
+ u32 mem_rang;
+ u32 txcw;
+ u32 max_frame_size;
+ u32 min_frame_size;
+ u32 mc_filter_type;
+ u32 num_mc_addrs;
+ u32 collision_delta;
+ u32 tx_packet_delta;
+ u16 phy_spd_default;
+
+ u16 dev_rev;
+ u8 revision_id;
+
+ /* spi flash */
+ u8 flash_vendor;
+
+ u8 dma_fairness;
+ u8 mac_addr[ETH_ALEN];
+ u8 perm_mac_addr[ETH_ALEN];
+
+ /* bool phy_preamble_sup; */
+ bool phy_configured;
+};
+
+struct atl1_adapter {
+ /* OS defined structs */
+ struct net_device *netdev;
+ struct pci_dev *pdev;
+ struct net_device_stats net_stats;
+ struct atl1_sft_stats soft_stats;
+
+ struct vlan_group *vlgrp;
+ u32 rx_buffer_len;
+ u32 wol;
+ u16 link_speed;
+ u16 link_duplex;
+ spinlock_t lock;
+ atomic_t irq_sem;
+ struct work_struct tx_timeout_task;
+ struct work_struct link_chg_task;
+ struct work_struct pcie_dma_to_rst_task;
+ struct timer_list watchdog_timer;
+ struct timer_list phy_config_timer;
+ bool phy_timer_pending;
+
+ bool mac_disabled;
+
+ /* All descriptor rings' memory */
+ struct atl1_ring_header ring_header;
+
+ /* TX */
+ struct atl1_tpd_ring tpd_ring;
+ spinlock_t mb_lock;
+
+ /* RX */
+ struct atl1_rfd_ring rfd_ring;
+ struct atl1_rrd_ring rrd_ring;
+ u64 hw_csum_err;
+ u64 hw_csum_good;
+
+ u32 gorcl;
+ u64 gorcl_old;
+
+ /* Interrupt Moderator timer ( 2us resolution) */
+ u16 imt;
+ /* Interrupt Clear timer (2us resolution) */
+ u16 ict;
+
+ /* MII interface info */
+ struct mii_if_info mii;
+
+ /* structs defined in atl1_hw.h */
+ u32 bd_number; /* board number */
+ bool pci_using_64;
+ struct atl1_hw hw;
+ struct atl1_smb smb;
+ struct atl1_cmb cmb;
+
+ u32 pci_state[16];
+};
+
+#endif /* _ATL1_H_ */
diff --git a/drivers/net/atl1/atl1_ethtool.c b/drivers/net/atl1/atl1_ethtool.c
new file mode 100644
index 00000000000..c11c27798e5
--- /dev/null
+++ b/drivers/net/atl1/atl1_ethtool.c
@@ -0,0 +1,508 @@
+/*
+ * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved.
+ * Copyright(c) 2006 Chris Snook <csnook@redhat.com>
+ * Copyright(c) 2006 Jay Cliburn <jcliburn@gmail.com>
+ *
+ * Derived from Intel e1000 driver
+ * Copyright(c) 1999 - 2005 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.
+ */
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/ethtool.h>
+#include <linux/netdevice.h>
+#include <linux/mii.h>
+#include <asm/uaccess.h>
+
+#include "atl1.h"
+
+struct atl1_stats {
+ char stat_string[ETH_GSTRING_LEN];
+ int sizeof_stat;
+ int stat_offset;
+};
+
+#define ATL1_STAT(m) sizeof(((struct atl1_adapter *)0)->m), \
+ offsetof(struct atl1_adapter, m)
+
+static struct atl1_stats atl1_gstrings_stats[] = {
+ {"rx_packets", ATL1_STAT(soft_stats.rx_packets)},
+ {"tx_packets", ATL1_STAT(soft_stats.tx_packets)},
+ {"rx_bytes", ATL1_STAT(soft_stats.rx_bytes)},
+ {"tx_bytes", ATL1_STAT(soft_stats.tx_bytes)},
+ {"rx_errors", ATL1_STAT(soft_stats.rx_errors)},
+ {"tx_errors", ATL1_STAT(soft_stats.tx_errors)},
+ {"rx_dropped", ATL1_STAT(net_stats.rx_dropped)},
+ {"tx_dropped", ATL1_STAT(net_stats.tx_dropped)},
+ {"multicast", ATL1_STAT(soft_stats.multicast)},
+ {"collisions", ATL1_STAT(soft_stats.collisions)},
+ {"rx_length_errors", ATL1_STAT(soft_stats.rx_length_errors)},
+ {"rx_over_errors", ATL1_STAT(soft_stats.rx_missed_errors)},
+ {"rx_crc_errors", ATL1_STAT(soft_stats.rx_crc_errors)},
+ {"rx_frame_errors", ATL1_STAT(soft_stats.rx_frame_errors)},
+ {"rx_fifo_errors", ATL1_STAT(soft_stats.rx_fifo_errors)},
+ {"rx_missed_errors", ATL1_STAT(soft_stats.rx_missed_errors)},
+ {"tx_aborted_errors", ATL1_STAT(soft_stats.tx_aborted_errors)},
+ {"tx_carrier_errors", ATL1_STAT(soft_stats.tx_carrier_errors)},
+ {"tx_fifo_errors", ATL1_STAT(soft_stats.tx_fifo_errors)},
+ {"tx_window_errors", ATL1_STAT(soft_stats.tx_window_errors)},
+ {"tx_abort_exce_coll", ATL1_STAT(soft_stats.excecol)},
+ {"tx_abort_late_coll", ATL1_STAT(soft_stats.latecol)},
+ {"tx_deferred_ok", ATL1_STAT(soft_stats.deffer)},
+ {"tx_single_coll_ok", ATL1_STAT(soft_stats.scc)},
+ {"tx_multi_coll_ok", ATL1_STAT(soft_stats.mcc)},
+ {"tx_underun", ATL1_STAT(soft_stats.tx_underun)},
+ {"tx_trunc", ATL1_STAT(soft_stats.tx_trunc)},
+ {"tx_pause", ATL1_STAT(soft_stats.tx_pause)},
+ {"rx_pause", ATL1_STAT(soft_stats.rx_pause)},
+ {"rx_rrd_ov", ATL1_STAT(soft_stats.rx_rrd_ov)},
+ {"rx_trunc", ATL1_STAT(soft_stats.rx_trunc)}
+};
+
+static void atl1_get_ethtool_stats(struct net_device *netdev,
+ struct ethtool_stats *stats, u64 *data)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ int i;
+ char *p;
+
+ for (i = 0; i < ARRAY_SIZE(atl1_gstrings_stats); i++) {
+ p = (char *)adapter+atl1_gstrings_stats[i].stat_offset;
+ data[i] = (atl1_gstrings_stats[i].sizeof_stat ==
+ sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
+ }
+
+}
+
+static int atl1_get_stats_count(struct net_device *netdev)
+{
+ return ARRAY_SIZE(atl1_gstrings_stats);
+}
+
+static int atl1_get_settings(struct net_device *netdev,
+ struct ethtool_cmd *ecmd)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ struct atl1_hw *hw = &adapter->hw;
+
+ ecmd->supported = (SUPPORTED_10baseT_Half |
+ SUPPORTED_10baseT_Full |
+ SUPPORTED_100baseT_Half |
+ SUPPORTED_100baseT_Full |
+ SUPPORTED_1000baseT_Full |
+ SUPPORTED_Autoneg | SUPPORTED_TP);
+ ecmd->advertising = ADVERTISED_TP;
+ if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR ||
+ hw->media_type == MEDIA_TYPE_1000M_FULL) {
+ ecmd->advertising |= ADVERTISED_Autoneg;
+ if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR) {
+ ecmd->advertising |= ADVERTISED_Autoneg;
+ ecmd->advertising |=
+ (ADVERTISED_10baseT_Half |
+ ADVERTISED_10baseT_Full |
+ ADVERTISED_100baseT_Half |
+ ADVERTISED_100baseT_Full |
+ ADVERTISED_1000baseT_Full);
+ }
+ else
+ ecmd->advertising |= (ADVERTISED_1000baseT_Full);
+ }
+ ecmd->port = PORT_TP;
+ ecmd->phy_address = 0;
+ ecmd->transceiver = XCVR_INTERNAL;
+
+ if (netif_carrier_ok(adapter->netdev)) {
+ u16 link_speed, link_duplex;
+ atl1_get_speed_and_duplex(hw, &link_speed, &link_duplex);
+ ecmd->speed = link_speed;
+ if (link_duplex == FULL_DUPLEX)
+ ecmd->duplex = DUPLEX_FULL;
+ else
+ ecmd->duplex = DUPLEX_HALF;
+ } else {
+ ecmd->speed = -1;
+ ecmd->duplex = -1;
+ }
+ if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR ||
+ hw->media_type == MEDIA_TYPE_1000M_FULL)
+ ecmd->autoneg = AUTONEG_ENABLE;
+ else
+ ecmd->autoneg = AUTONEG_DISABLE;
+
+ return 0;
+}
+
+static int atl1_set_settings(struct net_device *netdev,
+ struct ethtool_cmd *ecmd)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ struct atl1_hw *hw = &adapter->hw;
+ u16 phy_data;
+ int ret_val = 0;
+ u16 old_media_type = hw->media_type;
+
+ if (netif_running(adapter->netdev)) {
+ printk(KERN_DEBUG "%s: ethtool shutting down adapter\n",
+ atl1_driver_name);
+ atl1_down(adapter);
+ }
+
+ if (ecmd->autoneg == AUTONEG_ENABLE)
+ hw->media_type = MEDIA_TYPE_AUTO_SENSOR;
+ else {
+ if (ecmd->speed == SPEED_1000) {
+ if (ecmd->duplex != DUPLEX_FULL) {
+ printk(KERN_WARNING
+ "%s: can't force to 1000M half duplex\n",
+ atl1_driver_name);
+ ret_val = -EINVAL;
+ goto exit_sset;
+ }
+ hw->media_type = MEDIA_TYPE_1000M_FULL;
+ } else if (ecmd->speed == SPEED_100) {
+ if (ecmd->duplex == DUPLEX_FULL) {
+ hw->media_type = MEDIA_TYPE_100M_FULL;
+ } else
+ hw->media_type = MEDIA_TYPE_100M_HALF;
+ } else {
+ if (ecmd->duplex == DUPLEX_FULL)
+ hw->media_type = MEDIA_TYPE_10M_FULL;
+ else
+ hw->media_type = MEDIA_TYPE_10M_HALF;
+ }
+ }
+ switch (hw->media_type) {
+ case MEDIA_TYPE_AUTO_SENSOR:
+ ecmd->advertising =
+ ADVERTISED_10baseT_Half |
+ ADVERTISED_10baseT_Full |
+ ADVERTISED_100baseT_Half |
+ ADVERTISED_100baseT_Full |
+ ADVERTISED_1000baseT_Full |
+ ADVERTISED_Autoneg | ADVERTISED_TP;
+ break;
+ case MEDIA_TYPE_1000M_FULL:
+ ecmd->advertising =
+ ADVERTISED_1000baseT_Full |
+ ADVERTISED_Autoneg | ADVERTISED_TP;
+ break;
+ default:
+ ecmd->advertising = 0;
+ break;
+ }
+ if (atl1_phy_setup_autoneg_adv(hw)) {
+ ret_val = -EINVAL;
+ printk(KERN_WARNING
+ "%s: invalid ethtool speed/duplex setting\n",
+ atl1_driver_name);
+ goto exit_sset;
+ }
+ if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR ||
+ hw->media_type == MEDIA_TYPE_1000M_FULL)
+ phy_data = MII_CR_RESET | MII_CR_AUTO_NEG_EN;
+ else {
+ switch (hw->media_type) {
+ case MEDIA_TYPE_100M_FULL:
+ phy_data =
+ MII_CR_FULL_DUPLEX | MII_CR_SPEED_100 |
+ MII_CR_RESET;
+ break;
+ case MEDIA_TYPE_100M_HALF:
+ phy_data = MII_CR_SPEED_100 | MII_CR_RESET;
+ break;
+ case MEDIA_TYPE_10M_FULL:
+ phy_data =
+ MII_CR_FULL_DUPLEX | MII_CR_SPEED_10 | MII_CR_RESET;
+ break;
+ default: /* MEDIA_TYPE_10M_HALF: */
+ phy_data = MII_CR_SPEED_10 | MII_CR_RESET;
+ break;
+ }
+ }
+ atl1_write_phy_reg(hw, MII_BMCR, phy_data);
+exit_sset:
+ if (ret_val)
+ hw->media_type = old_media_type;
+
+ if (netif_running(adapter->netdev)) {
+ printk(KERN_DEBUG "%s: ethtool starting adapter\n",
+ atl1_driver_name);
+ atl1_up(adapter);
+ } else if (!ret_val) {
+ printk(KERN_DEBUG "%s: ethtool resetting adapter\n",
+ atl1_driver_name);
+ atl1_reset(adapter);
+ }
+ return ret_val;
+}
+
+static void atl1_get_drvinfo(struct net_device *netdev,
+ struct ethtool_drvinfo *drvinfo)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+
+ strncpy(drvinfo->driver, atl1_driver_name, sizeof(drvinfo->driver));
+ strncpy(drvinfo->version, atl1_driver_version,
+ sizeof(drvinfo->version));
+ strncpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version));
+ strncpy(drvinfo->bus_info, pci_name(adapter->pdev),
+ sizeof(drvinfo->bus_info));
+ drvinfo->eedump_len = ATL1_EEDUMP_LEN;
+}
+
+static void atl1_get_wol(struct net_device *netdev,
+ struct ethtool_wolinfo *wol)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+
+ wol->supported = WAKE_UCAST | WAKE_MCAST | WAKE_BCAST | WAKE_MAGIC;
+ wol->wolopts = 0;
+ if (adapter->wol & ATL1_WUFC_EX)
+ wol->wolopts |= WAKE_UCAST;
+ if (adapter->wol & ATL1_WUFC_MC)
+ wol->wolopts |= WAKE_MCAST;
+ if (adapter->wol & ATL1_WUFC_BC)
+ wol->wolopts |= WAKE_BCAST;
+ if (adapter->wol & ATL1_WUFC_MAG)
+ wol->wolopts |= WAKE_MAGIC;
+ return;
+}
+
+static int atl1_set_wol(struct net_device *netdev,
+ struct ethtool_wolinfo *wol)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+
+ if (wol->wolopts & (WAKE_PHY | WAKE_ARP | WAKE_MAGICSECURE))
+ return -EOPNOTSUPP;
+ adapter->wol = 0;
+ if (wol->wolopts & WAKE_UCAST)
+ adapter->wol |= ATL1_WUFC_EX;
+ if (wol->wolopts & WAKE_MCAST)
+ adapter->wol |= ATL1_WUFC_MC;
+ if (wol->wolopts & WAKE_BCAST)
+ adapter->wol |= ATL1_WUFC_BC;
+ if (wol->wolopts & WAKE_MAGIC)
+ adapter->wol |= ATL1_WUFC_MAG;
+ return 0;
+}
+
+static void atl1_get_ringparam(struct net_device *netdev,
+ struct ethtool_ringparam *ring)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ struct atl1_tpd_ring *txdr = &adapter->tpd_ring;
+ struct atl1_rfd_ring *rxdr = &adapter->rfd_ring;
+
+ ring->rx_max_pending = ATL1_MAX_RFD;
+ ring->tx_max_pending = ATL1_MAX_TPD;
+ ring->rx_mini_max_pending = 0;
+ ring->rx_jumbo_max_pending = 0;
+ ring->rx_pending = rxdr->count;
+ ring->tx_pending = txdr->count;
+ ring->rx_mini_pending = 0;
+ ring->rx_jumbo_pending = 0;
+}
+
+static int atl1_set_ringparam(struct net_device *netdev,
+ struct ethtool_ringparam *ring)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ struct atl1_tpd_ring *tpdr = &adapter->tpd_ring;
+ struct atl1_rrd_ring *rrdr = &adapter->rrd_ring;
+ struct atl1_rfd_ring *rfdr = &adapter->rfd_ring;
+
+ struct atl1_tpd_ring tpd_old, tpd_new;
+ struct atl1_rfd_ring rfd_old, rfd_new;
+ struct atl1_rrd_ring rrd_old, rrd_new;
+ struct atl1_ring_header rhdr_old, rhdr_new;
+ int err;
+
+ tpd_old = adapter->tpd_ring;
+ rfd_old = adapter->rfd_ring;
+ rrd_old = adapter->rrd_ring;
+ rhdr_old = adapter->ring_header;
+
+ if (netif_running(adapter->netdev))
+ atl1_down(adapter);
+
+ rfdr->count = (u16) max(ring->rx_pending, (u32) ATL1_MIN_RFD);
+ rfdr->count = rfdr->count > ATL1_MAX_RFD ? ATL1_MAX_RFD :
+ rfdr->count;
+ rfdr->count = (rfdr->count + 3) & ~3;
+ rrdr->count = rfdr->count;
+
+ tpdr->count = (u16) max(ring->tx_pending, (u32) ATL1_MIN_TPD);
+ tpdr->count = tpdr->count > ATL1_MAX_TPD ? ATL1_MAX_TPD :
+ tpdr->count;
+ tpdr->count = (tpdr->count + 3) & ~3;
+
+ if (netif_running(adapter->netdev)) {
+ /* try to get new resources before deleting old */
+ err = atl1_setup_ring_resources(adapter);
+ if (err)
+ goto err_setup_ring;
+
+ /*
+ * save the new, restore the old in order to free it,
+ * then restore the new back again
+ */
+
+ rfd_new = adapter->rfd_ring;
+ rrd_new = adapter->rrd_ring;
+ tpd_new = adapter->tpd_ring;
+ rhdr_new = adapter->ring_header;
+ adapter->rfd_ring = rfd_old;
+ adapter->rrd_ring = rrd_old;
+ adapter->tpd_ring = tpd_old;
+ adapter->ring_header = rhdr_old;
+ atl1_free_ring_resources(adapter);
+ adapter->rfd_ring = rfd_new;
+ adapter->rrd_ring = rrd_new;
+ adapter->tpd_ring = tpd_new;
+ adapter->ring_header = rhdr_new;
+
+ err = atl1_up(adapter);
+ if (err)
+ return err;
+ }
+ return 0;
+
+err_setup_ring:
+ adapter->rfd_ring = rfd_old;
+ adapter->rrd_ring = rrd_old;
+ adapter->tpd_ring = tpd_old;
+ adapter->ring_header = rhdr_old;
+ atl1_up(adapter);
+ return err;
+}
+
+static void atl1_get_pauseparam(struct net_device *netdev,
+ struct ethtool_pauseparam *epause)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ struct atl1_hw *hw = &adapter->hw;
+
+ if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR ||
+ hw->media_type == MEDIA_TYPE_1000M_FULL) {
+ epause->autoneg = AUTONEG_ENABLE;
+ } else {
+ epause->autoneg = AUTONEG_DISABLE;
+ }
+ epause->rx_pause = 1;
+ epause->tx_pause = 1;
+}
+
+static int atl1_set_pauseparam(struct net_device *netdev,
+ struct ethtool_pauseparam *epause)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ struct atl1_hw *hw = &adapter->hw;
+
+ if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR ||
+ hw->media_type == MEDIA_TYPE_1000M_FULL) {
+ epause->autoneg = AUTONEG_ENABLE;
+ } else {
+ epause->autoneg = AUTONEG_DISABLE;
+ }
+
+ epause->rx_pause = 1;
+ epause->tx_pause = 1;
+
+ return 0;
+}
+
+static u32 atl1_get_rx_csum(struct net_device *netdev)
+{
+ return 1;
+}
+
+static void atl1_get_strings(struct net_device *netdev, u32 stringset,
+ u8 *data)
+{
+ u8 *p = data;
+ int i;
+
+ switch (stringset) {
+ case ETH_SS_STATS:
+ for (i = 0; i < ARRAY_SIZE(atl1_gstrings_stats); i++) {
+ memcpy(p, atl1_gstrings_stats[i].stat_string,
+ ETH_GSTRING_LEN);
+ p += ETH_GSTRING_LEN;
+ }
+ break;
+ }
+}
+
+static int atl1_nway_reset(struct net_device *netdev)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ struct atl1_hw *hw = &adapter->hw;
+
+ if (netif_running(netdev)) {
+ u16 phy_data;
+ atl1_down(adapter);
+
+ if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR ||
+ hw->media_type == MEDIA_TYPE_1000M_FULL) {
+ phy_data = MII_CR_RESET | MII_CR_AUTO_NEG_EN;
+ } else {
+ switch (hw->media_type) {
+ case MEDIA_TYPE_100M_FULL:
+ phy_data = MII_CR_FULL_DUPLEX |
+ MII_CR_SPEED_100 | MII_CR_RESET;
+ break;
+ case MEDIA_TYPE_100M_HALF:
+ phy_data = MII_CR_SPEED_100 | MII_CR_RESET;
+ break;
+ case MEDIA_TYPE_10M_FULL:
+ phy_data = MII_CR_FULL_DUPLEX |
+ MII_CR_SPEED_10 | MII_CR_RESET;
+ break;
+ default: /* MEDIA_TYPE_10M_HALF */
+ phy_data = MII_CR_SPEED_10 | MII_CR_RESET;
+ }
+ }
+ atl1_write_phy_reg(hw, MII_BMCR, phy_data);
+ atl1_up(adapter);
+ }
+ return 0;
+}
+
+const struct ethtool_ops atl1_ethtool_ops = {
+ .get_settings = atl1_get_settings,
+ .set_settings = atl1_set_settings,
+ .get_drvinfo = atl1_get_drvinfo,
+ .get_wol = atl1_get_wol,
+ .set_wol = atl1_set_wol,
+ .get_ringparam = atl1_get_ringparam,
+ .set_ringparam = atl1_set_ringparam,
+ .get_pauseparam = atl1_get_pauseparam,
+ .set_pauseparam = atl1_set_pauseparam,
+ .get_rx_csum = atl1_get_rx_csum,
+ .get_tx_csum = ethtool_op_get_tx_csum,
+ .set_tx_csum = ethtool_op_set_tx_hw_csum,
+ .get_link = ethtool_op_get_link,
+ .get_sg = ethtool_op_get_sg,
+ .set_sg = ethtool_op_set_sg,
+ .get_strings = atl1_get_strings,
+ .nway_reset = atl1_nway_reset,
+ .get_ethtool_stats = atl1_get_ethtool_stats,
+ .get_stats_count = atl1_get_stats_count,
+ .get_tso = ethtool_op_get_tso,
+ .set_tso = ethtool_op_set_tso,
+};
diff --git a/drivers/net/atl1/atl1_hw.c b/drivers/net/atl1/atl1_hw.c
new file mode 100644
index 00000000000..314dbaabb64
--- /dev/null
+++ b/drivers/net/atl1/atl1_hw.c
@@ -0,0 +1,723 @@
+/*
+ * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved.
+ * Copyright(c) 2006 Chris Snook <csnook@redhat.com>
+ * Copyright(c) 2006 Jay Cliburn <jcliburn@gmail.com>
+ *
+ * Derived from Intel e1000 driver
+ * Copyright(c) 1999 - 2005 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.
+ */
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/if_vlan.h>
+#include <linux/etherdevice.h>
+#include <linux/crc32.h>
+#include <asm/byteorder.h>
+
+#include "atl1.h"
+
+/*
+ * Reset the transmit and receive units; mask and clear all interrupts.
+ * hw - Struct containing variables accessed by shared code
+ * return : ATL1_SUCCESS or idle status (if error)
+ */
+s32 atl1_reset_hw(struct atl1_hw *hw)
+{
+ u32 icr;
+ int i;
+
+ /*
+ * Clear Interrupt mask to stop board from generating
+ * interrupts & Clear any pending interrupt events
+ */
+ /*
+ * iowrite32(0, hw->hw_addr + REG_IMR);
+ * iowrite32(0xffffffff, hw->hw_addr + REG_ISR);
+ */
+
+ /*
+ * Issue Soft Reset to the MAC. This will reset the chip's
+ * transmit, receive, DMA. It will not effect
+ * the current PCI configuration. The global reset bit is self-
+ * clearing, and should clear within a microsecond.
+ */
+ iowrite32(MASTER_CTRL_SOFT_RST, hw->hw_addr + REG_MASTER_CTRL);
+ ioread32(hw->hw_addr + REG_MASTER_CTRL);
+
+ iowrite16(1, hw->hw_addr + REG_GPHY_ENABLE);
+ ioread16(hw->hw_addr + REG_GPHY_ENABLE);
+
+ msleep(1); /* delay about 1ms */
+
+ /* Wait at least 10ms for All module to be Idle */
+ for (i = 0; i < 10; i++) {
+ icr = ioread32(hw->hw_addr + REG_IDLE_STATUS);
+ if (!icr)
+ break;
+ msleep(1); /* delay 1 ms */
+ cpu_relax(); /* FIXME: is this still the right way to do this? */
+ }
+
+ if (icr) {
+ printk (KERN_DEBUG "icr = %x\n", icr);
+ return icr;
+ }
+
+ return ATL1_SUCCESS;
+}
+
+/* function about EEPROM
+ *
+ * check_eeprom_exist
+ * return 0 if eeprom exist
+ */
+static int atl1_check_eeprom_exist(struct atl1_hw *hw)
+{
+ u32 value;
+ value = ioread32(hw->hw_addr + REG_SPI_FLASH_CTRL);
+ if (value & SPI_FLASH_CTRL_EN_VPD) {
+ value &= ~SPI_FLASH_CTRL_EN_VPD;
+ iowrite32(value, hw->hw_addr + REG_SPI_FLASH_CTRL);
+ }
+
+ value = ioread16(hw->hw_addr + REG_PCIE_CAP_LIST);
+ return ((value & 0xFF00) == 0x6C00) ? 0 : 1;
+}
+
+static bool atl1_read_eeprom(struct atl1_hw *hw, u32 offset, u32 *p_value)
+{
+ int i;
+ u32 control;
+
+ if (offset & 3)
+ return false; /* address do not align */
+
+ iowrite32(0, hw->hw_addr + REG_VPD_DATA);
+ control = (offset & VPD_CAP_VPD_ADDR_MASK) << VPD_CAP_VPD_ADDR_SHIFT;
+ iowrite32(control, hw->hw_addr + REG_VPD_CAP);
+ ioread32(hw->hw_addr + REG_VPD_CAP);
+
+ for (i = 0; i < 10; i++) {
+ msleep(2);
+ control = ioread32(hw->hw_addr + REG_VPD_CAP);
+ if (control & VPD_CAP_VPD_FLAG)
+ break;
+ }
+ if (control & VPD_CAP_VPD_FLAG) {
+ *p_value = ioread32(hw->hw_addr + REG_VPD_DATA);
+ return true;
+ }
+ return false; /* timeout */
+}
+
+/*
+ * Reads the value from a PHY register
+ * hw - Struct containing variables accessed by shared code
+ * reg_addr - address of the PHY register to read
+ */
+s32 atl1_read_phy_reg(struct atl1_hw *hw, u16 reg_addr, u16 *phy_data)
+{
+ u32 val;
+ int i;
+
+ val = ((u32) (reg_addr & MDIO_REG_ADDR_MASK)) << MDIO_REG_ADDR_SHIFT |
+ MDIO_START | MDIO_SUP_PREAMBLE | MDIO_RW | MDIO_CLK_25_4 <<
+ MDIO_CLK_SEL_SHIFT;
+ iowrite32(val, hw->hw_addr + REG_MDIO_CTRL);
+ ioread32(hw->hw_addr + REG_MDIO_CTRL);
+
+ for (i = 0; i < MDIO_WAIT_TIMES; i++) {
+ udelay(2);
+ val = ioread32(hw->hw_addr + REG_MDIO_CTRL);
+ if (!(val & (MDIO_START | MDIO_BUSY)))
+ break;
+ }
+ if (!(val & (MDIO_START | MDIO_BUSY))) {
+ *phy_data = (u16) val;
+ return ATL1_SUCCESS;
+ }
+ return ATL1_ERR_PHY;
+}
+
+#define CUSTOM_SPI_CS_SETUP 2
+#define CUSTOM_SPI_CLK_HI 2
+#define CUSTOM_SPI_CLK_LO 2
+#define CUSTOM_SPI_CS_HOLD 2
+#define CUSTOM_SPI_CS_HI 3
+
+static bool atl1_spi_read(struct atl1_hw *hw, u32 addr, u32 *buf)
+{
+ int i;
+ u32 value;
+
+ iowrite32(0, hw->hw_addr + REG_SPI_DATA);
+ iowrite32(addr, hw->hw_addr + REG_SPI_ADDR);
+
+ value = SPI_FLASH_CTRL_WAIT_READY |
+ (CUSTOM_SPI_CS_SETUP & SPI_FLASH_CTRL_CS_SETUP_MASK) <<
+ SPI_FLASH_CTRL_CS_SETUP_SHIFT | (CUSTOM_SPI_CLK_HI &
+ SPI_FLASH_CTRL_CLK_HI_MASK) <<
+ SPI_FLASH_CTRL_CLK_HI_SHIFT | (CUSTOM_SPI_CLK_LO &
+ SPI_FLASH_CTRL_CLK_LO_MASK) <<
+ SPI_FLASH_CTRL_CLK_LO_SHIFT | (CUSTOM_SPI_CS_HOLD &
+ SPI_FLASH_CTRL_CS_HOLD_MASK) <<
+ SPI_FLASH_CTRL_CS_HOLD_SHIFT | (CUSTOM_SPI_CS_HI &
+ SPI_FLASH_CTRL_CS_HI_MASK) <<
+ SPI_FLASH_CTRL_CS_HI_SHIFT | (1 & SPI_FLASH_CTRL_INS_MASK) <<
+ SPI_FLASH_CTRL_INS_SHIFT;
+
+ iowrite32(value, hw->hw_addr + REG_SPI_FLASH_CTRL);
+
+ value |= SPI_FLASH_CTRL_START;
+ iowrite32(value, hw->hw_addr + REG_SPI_FLASH_CTRL);
+ ioread32(hw->hw_addr + REG_SPI_FLASH_CTRL);
+
+ for (i = 0; i < 10; i++) {
+ msleep(1); /* 1ms */
+ value = ioread32(hw->hw_addr + REG_SPI_FLASH_CTRL);
+ if (!(value & SPI_FLASH_CTRL_START))
+ break;
+ }
+
+ if (value & SPI_FLASH_CTRL_START)
+ return false;
+
+ *buf = ioread32(hw->hw_addr + REG_SPI_DATA);
+
+ return true;
+}
+
+/*
+ * get_permanent_address
+ * return 0 if get valid mac address,
+ */
+static int atl1_get_permanent_address(struct atl1_hw *hw)
+{
+ u32 addr[2];
+ u32 i, control;
+ u16 reg;
+ u8 eth_addr[ETH_ALEN];
+ bool key_valid;
+
+ if (is_valid_ether_addr(hw->perm_mac_addr))
+ return 0;
+
+ /* init */
+ addr[0] = addr[1] = 0;
+
+ if (!atl1_check_eeprom_exist(hw)) { /* eeprom exist */
+ reg = 0;
+ key_valid = false;
+ /* Read out all EEPROM content */
+ i = 0;
+ while (1) {
+ if (atl1_read_eeprom(hw, i + 0x100, &control)) {
+ if (key_valid) {
+ if (reg == REG_MAC_STA_ADDR)
+ addr[0] = control;
+ else if (reg == (REG_MAC_STA_ADDR + 4))
+ addr[1] = control;
+ key_valid = false;
+ } else if ((control & 0xff) == 0x5A) {
+ key_valid = true;
+ reg = (u16) (control >> 16);
+ } else
+ break; /* assume data end while encount an invalid KEYWORD */
+ } else
+ break; /* read error */
+ i += 4;
+ }
+
+ *(u32 *) &eth_addr[2] = swab32(addr[0]);
+ *(u16 *) &eth_addr[0] = swab16(*(u16 *) &addr[1]);
+ if (is_valid_ether_addr(eth_addr)) {
+ memcpy(hw->perm_mac_addr, eth_addr, ETH_ALEN);
+ return 0;
+ }
+ return 1;
+ }
+
+ /* see if SPI FLAGS exist ? */
+ addr[0] = addr[1] = 0;
+ reg = 0;
+ key_valid = false;
+ i = 0;
+ while (1) {
+ if (atl1_spi_read(hw, i + 0x1f000, &control)) {
+ if (key_valid) {
+ if (reg == REG_MAC_STA_ADDR)
+ addr[0] = control;
+ else if (reg == (REG_MAC_STA_ADDR + 4))
+ addr[1] = control;
+ key_valid = false;
+ } else if ((control & 0xff) == 0x5A) {
+ key_valid = true;
+ reg = (u16) (control >> 16);
+ } else
+ break; /* data end */
+ } else
+ break; /* read error */
+ i += 4;
+ }
+
+ *(u32 *) &eth_addr[2] = swab32(addr[0]);
+ *(u16 *) &eth_addr[0] = swab16(*(u16 *) &addr[1]);
+ if (is_valid_ether_addr(eth_addr)) {
+ memcpy(hw->perm_mac_addr, eth_addr, ETH_ALEN);
+ return 0;
+ }
+
+ /*
+ * On some motherboards, the MAC address is written by the
+ * BIOS directly to the MAC register during POST, and is
+ * not stored in eeprom. If all else thus far has failed
+ * to fetch the permanent MAC address, try reading it directly.
+ */
+ addr[0] = ioread32(hw->hw_addr + REG_MAC_STA_ADDR);
+ addr[1] = ioread16(hw->hw_addr + (REG_MAC_STA_ADDR + 4));
+ *(u32 *) &eth_addr[2] = swab32(addr[0]);
+ *(u16 *) &eth_addr[0] = swab16(*(u16 *) &addr[1]);
+ if (is_valid_ether_addr(eth_addr)) {
+ memcpy(hw->perm_mac_addr, eth_addr, ETH_ALEN);
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * Reads the adapter's MAC address from the EEPROM
+ * hw - Struct containing variables accessed by shared code
+ */
+s32 atl1_read_mac_addr(struct atl1_hw *hw)
+{
+ u16 i;
+
+ if (atl1_get_permanent_address(hw))
+ random_ether_addr(hw->perm_mac_addr);
+
+ for (i = 0; i < ETH_ALEN; i++)
+ hw->mac_addr[i] = hw->perm_mac_addr[i];
+ return ATL1_SUCCESS;
+}
+
+/*
+ * Hashes an address to determine its location in the multicast table
+ * hw - Struct containing variables accessed by shared code
+ * mc_addr - the multicast address to hash
+ *
+ * atl1_hash_mc_addr
+ * purpose
+ * set hash value for a multicast address
+ * hash calcu processing :
+ * 1. calcu 32bit CRC for multicast address
+ * 2. reverse crc with MSB to LSB
+ */
+u32 atl1_hash_mc_addr(struct atl1_hw *hw, u8 *mc_addr)
+{
+ u32 crc32, value = 0;
+ int i;
+
+ crc32 = ether_crc_le(6, mc_addr);
+ crc32 = ~crc32;
+ for (i = 0; i < 32; i++)
+ value |= (((crc32 >> i) & 1) << (31 - i));
+
+ return value;
+}
+
+/*
+ * Sets the bit in the multicast table corresponding to the hash value.
+ * hw - Struct containing variables accessed by shared code
+ * hash_value - Multicast address hash value
+ */
+void atl1_hash_set(struct atl1_hw *hw, u32 hash_value)
+{
+ u32 hash_bit, hash_reg;
+ u32 mta;
+
+ /*
+ * The HASH Table is a register array of 2 32-bit registers.
+ * It is treated like an array of 64 bits. We want to set
+ * bit BitArray[hash_value]. So we figure out what register
+ * the bit is in, read it, OR in the new bit, then write
+ * back the new value. The register is determined by the
+ * upper 7 bits of the hash value and the bit within that
+ * register are determined by the lower 5 bits of the value.
+ */
+ hash_reg = (hash_value >> 31) & 0x1;
+ hash_bit = (hash_value >> 26) & 0x1F;
+ mta = ioread32((hw->hw_addr + REG_RX_HASH_TABLE) + (hash_reg << 2));
+ mta |= (1 << hash_bit);
+ iowrite32(mta, (hw->hw_addr + REG_RX_HASH_TABLE) + (hash_reg << 2));
+}
+
+/*
+ * Writes a value to a PHY register
+ * hw - Struct containing variables accessed by shared code
+ * reg_addr - address of the PHY register to write
+ * data - data to write to the PHY
+ */
+s32 atl1_write_phy_reg(struct atl1_hw *hw, u32 reg_addr, u16 phy_data)
+{
+ int i;
+ u32 val;
+
+ val = ((u32) (phy_data & MDIO_DATA_MASK)) << MDIO_DATA_SHIFT |
+ (reg_addr & MDIO_REG_ADDR_MASK) << MDIO_REG_ADDR_SHIFT |
+ MDIO_SUP_PREAMBLE |
+ MDIO_START | MDIO_CLK_25_4 << MDIO_CLK_SEL_SHIFT;
+ iowrite32(val, hw->hw_addr + REG_MDIO_CTRL);
+ ioread32(hw->hw_addr + REG_MDIO_CTRL);
+
+ for (i = 0; i < MDIO_WAIT_TIMES; i++) {
+ udelay(2);
+ val = ioread32(hw->hw_addr + REG_MDIO_CTRL);
+ if (!(val & (MDIO_START | MDIO_BUSY)))
+ break;
+ }
+
+ if (!(val & (MDIO_START | MDIO_BUSY)))
+ return ATL1_SUCCESS;
+
+ return ATL1_ERR_PHY;
+}
+
+/*
+ * Make L001's PHY out of Power Saving State (bug)
+ * hw - Struct containing variables accessed by shared code
+ * when power on, L001's PHY always on Power saving State
+ * (Gigabit Link forbidden)
+ */
+static s32 atl1_phy_leave_power_saving(struct atl1_hw *hw)
+{
+ s32 ret;
+ ret = atl1_write_phy_reg(hw, 29, 0x0029);
+ if (ret)
+ return ret;
+ return atl1_write_phy_reg(hw, 30, 0);
+}
+
+/*
+ *TODO: do something or get rid of this
+ */
+s32 atl1_phy_enter_power_saving(struct atl1_hw *hw)
+{
+/* s32 ret_val;
+ * u16 phy_data;
+ */
+
+/*
+ ret_val = atl1_write_phy_reg(hw, ...);
+ ret_val = atl1_write_phy_reg(hw, ...);
+ ....
+*/
+ return ATL1_SUCCESS;
+}
+
+/*
+ * Resets the PHY and make all config validate
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Sets bit 15 and 12 of the MII Control regiser (for F001 bug)
+ */
+static s32 atl1_phy_reset(struct atl1_hw *hw)
+{
+ s32 ret_val;
+ u16 phy_data;
+
+ if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR ||
+ hw->media_type == MEDIA_TYPE_1000M_FULL)
+ phy_data = MII_CR_RESET | MII_CR_AUTO_NEG_EN;
+ else {
+ switch (hw->media_type) {
+ case MEDIA_TYPE_100M_FULL:
+ phy_data =
+ MII_CR_FULL_DUPLEX | MII_CR_SPEED_100 |
+ MII_CR_RESET;
+ break;
+ case MEDIA_TYPE_100M_HALF:
+ phy_data = MII_CR_SPEED_100 | MII_CR_RESET;
+ break;
+ case MEDIA_TYPE_10M_FULL:
+ phy_data =
+ MII_CR_FULL_DUPLEX | MII_CR_SPEED_10 | MII_CR_RESET;
+ break;
+ default: /* MEDIA_TYPE_10M_HALF: */
+ phy_data = MII_CR_SPEED_10 | MII_CR_RESET;
+ break;
+ }
+ }
+
+ ret_val = atl1_write_phy_reg(hw, MII_BMCR, phy_data);
+ if (ret_val) {
+ u32 val;
+ int i;
+ /* pcie serdes link may be down! */
+ printk(KERN_DEBUG "%s: autoneg caused pcie phy link down\n",
+ atl1_driver_name);
+
+ for (i = 0; i < 25; i++) {
+ msleep(1);
+ val = ioread32(hw->hw_addr + REG_MDIO_CTRL);
+ if (!(val & (MDIO_START | MDIO_BUSY)))
+ break;
+ }
+
+ if ((val & (MDIO_START | MDIO_BUSY)) != 0) {
+ printk(KERN_WARNING
+ "%s: pcie link down at least for 25ms\n",
+ atl1_driver_name);
+ return ret_val;
+ }
+ }
+ return ATL1_SUCCESS;
+}
+
+/*
+ * Configures PHY autoneg and flow control advertisement settings
+ * hw - Struct containing variables accessed by shared code
+ */
+s32 atl1_phy_setup_autoneg_adv(struct atl1_hw *hw)
+{
+ s32 ret_val;
+ s16 mii_autoneg_adv_reg;
+ s16 mii_1000t_ctrl_reg;
+
+ /* Read the MII Auto-Neg Advertisement Register (Address 4). */
+ mii_autoneg_adv_reg = MII_AR_DEFAULT_CAP_MASK;
+
+ /* Read the MII 1000Base-T Control Register (Address 9). */
+ mii_1000t_ctrl_reg = MII_AT001_CR_1000T_DEFAULT_CAP_MASK;
+
+ /*
+ * First we clear all the 10/100 mb speed bits in the Auto-Neg
+ * Advertisement Register (Address 4) and the 1000 mb speed bits in
+ * the 1000Base-T Control Register (Address 9).
+ */
+ mii_autoneg_adv_reg &= ~MII_AR_SPEED_MASK;
+ mii_1000t_ctrl_reg &= ~MII_AT001_CR_1000T_SPEED_MASK;
+
+ /*
+ * Need to parse media_type and set up
+ * the appropriate PHY registers.
+ */
+ switch (hw->media_type) {
+ case MEDIA_TYPE_AUTO_SENSOR:
+ mii_autoneg_adv_reg |= (MII_AR_10T_HD_CAPS |
+ MII_AR_10T_FD_CAPS |
+ MII_AR_100TX_HD_CAPS |
+ MII_AR_100TX_FD_CAPS);
+ mii_1000t_ctrl_reg |= MII_AT001_CR_1000T_FD_CAPS;
+ break;
+
+ case MEDIA_TYPE_1000M_FULL:
+ mii_1000t_ctrl_reg |= MII_AT001_CR_1000T_FD_CAPS;
+ break;
+
+ case MEDIA_TYPE_100M_FULL:
+ mii_autoneg_adv_reg |= MII_AR_100TX_FD_CAPS;
+ break;
+
+ case MEDIA_TYPE_100M_HALF:
+ mii_autoneg_adv_reg |= MII_AR_100TX_HD_CAPS;
+ break;
+
+ case MEDIA_TYPE_10M_FULL:
+ mii_autoneg_adv_reg |= MII_AR_10T_FD_CAPS;
+ break;
+
+ default:
+ mii_autoneg_adv_reg |= MII_AR_10T_HD_CAPS;
+ break;
+ }
+
+ /* flow control fixed to enable all */
+ mii_autoneg_adv_reg |= (MII_AR_ASM_DIR | MII_AR_PAUSE);
+
+ hw->mii_autoneg_adv_reg = mii_autoneg_adv_reg;
+ hw->mii_1000t_ctrl_reg = mii_1000t_ctrl_reg;
+
+ ret_val = atl1_write_phy_reg(hw, MII_ADVERTISE, mii_autoneg_adv_reg);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = atl1_write_phy_reg(hw, MII_AT001_CR, mii_1000t_ctrl_reg);
+ if (ret_val)
+ return ret_val;
+
+ return ATL1_SUCCESS;
+}
+
+/*
+ * Configures link settings.
+ * hw - Struct containing variables accessed by shared code
+ * Assumes the hardware has previously been reset and the
+ * transmitter and receiver are not enabled.
+ */
+static s32 atl1_setup_link(struct atl1_hw *hw)
+{
+ s32 ret_val;
+
+ /*
+ * Options:
+ * PHY will advertise value(s) parsed from
+ * autoneg_advertised and fc
+ * no matter what autoneg is , We will not wait link result.
+ */
+ ret_val = atl1_phy_setup_autoneg_adv(hw);
+ if (ret_val) {
+ printk(KERN_DEBUG "%s: error setting up autonegotiation\n",
+ atl1_driver_name);
+ return ret_val;
+ }
+ /* SW.Reset , En-Auto-Neg if needed */
+ ret_val = atl1_phy_reset(hw);
+ if (ret_val) {
+ printk(KERN_DEBUG "%s: error resetting the phy\n",
+ atl1_driver_name);
+ return ret_val;
+ }
+ hw->phy_configured = true;
+ return ret_val;
+}
+
+static struct atl1_spi_flash_dev flash_table[] = {
+/* MFR_NAME WRSR READ PRGM WREN WRDI RDSR RDID SECTOR_ERASE CHIP_ERASE */
+ {"Atmel", 0x00, 0x03, 0x02, 0x06, 0x04, 0x05, 0x15, 0x52, 0x62},
+ {"SST", 0x01, 0x03, 0x02, 0x06, 0x04, 0x05, 0x90, 0x20, 0x60},
+ {"ST", 0x01, 0x03, 0x02, 0x06, 0x04, 0x05, 0xAB, 0xD8, 0xC7},
+};
+
+static void atl1_init_flash_opcode(struct atl1_hw *hw)
+{
+ if (hw->flash_vendor >= sizeof(flash_table) / sizeof(flash_table[0]))
+ hw->flash_vendor = 0; /* ATMEL */
+
+ /* Init OP table */
+ iowrite8(flash_table[hw->flash_vendor].cmd_program,
+ hw->hw_addr + REG_SPI_FLASH_OP_PROGRAM);
+ iowrite8(flash_table[hw->flash_vendor].cmd_sector_erase,
+ hw->hw_addr + REG_SPI_FLASH_OP_SC_ERASE);
+ iowrite8(flash_table[hw->flash_vendor].cmd_chip_erase,
+ hw->hw_addr + REG_SPI_FLASH_OP_CHIP_ERASE);
+ iowrite8(flash_table[hw->flash_vendor].cmd_rdid,
+ hw->hw_addr + REG_SPI_FLASH_OP_RDID);
+ iowrite8(flash_table[hw->flash_vendor].cmd_wren,
+ hw->hw_addr + REG_SPI_FLASH_OP_WREN);
+ iowrite8(flash_table[hw->flash_vendor].cmd_rdsr,
+ hw->hw_addr + REG_SPI_FLASH_OP_RDSR);
+ iowrite8(flash_table[hw->flash_vendor].cmd_wrsr,
+ hw->hw_addr + REG_SPI_FLASH_OP_WRSR);
+ iowrite8(flash_table[hw->flash_vendor].cmd_read,
+ hw->hw_addr + REG_SPI_FLASH_OP_READ);
+}
+
+/*
+ * Performs basic configuration of the adapter.
+ * hw - Struct containing variables accessed by shared code
+ * Assumes that the controller has previously been reset and is in a
+ * post-reset uninitialized state. Initializes multicast table,
+ * and Calls routines to setup link
+ * Leaves the transmit and receive units disabled and uninitialized.
+ */
+s32 atl1_init_hw(struct atl1_hw *hw)
+{
+ u32 ret_val = 0;
+
+ /* Zero out the Multicast HASH table */
+ iowrite32(0, hw->hw_addr + REG_RX_HASH_TABLE);
+ /* clear the old settings from the multicast hash table */
+ iowrite32(0, (hw->hw_addr + REG_RX_HASH_TABLE) + (1 << 2));
+
+ atl1_init_flash_opcode(hw);
+
+ if (!hw->phy_configured) {
+ /* enable GPHY LinkChange Interrrupt */
+ ret_val = atl1_write_phy_reg(hw, 18, 0xC00);
+ if (ret_val)
+ return ret_val;
+ /* make PHY out of power-saving state */
+ ret_val = atl1_phy_leave_power_saving(hw);
+ if (ret_val)
+ return ret_val;
+ /* Call a subroutine to configure the link */
+ ret_val = atl1_setup_link(hw);
+ }
+ return ret_val;
+}
+
+/*
+ * Detects the current speed and duplex settings of the hardware.
+ * hw - Struct containing variables accessed by shared code
+ * speed - Speed of the connection
+ * duplex - Duplex setting of the connection
+ */
+s32 atl1_get_speed_and_duplex(struct atl1_hw *hw, u16 *speed, u16 *duplex)
+{
+ s32 ret_val;
+ u16 phy_data;
+
+ /* ; --- Read PHY Specific Status Register (17) */
+ ret_val = atl1_read_phy_reg(hw, MII_AT001_PSSR, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ if (!(phy_data & MII_AT001_PSSR_SPD_DPLX_RESOLVED))
+ return ATL1_ERR_PHY_RES;
+
+ switch (phy_data & MII_AT001_PSSR_SPEED) {
+ case MII_AT001_PSSR_1000MBS:
+ *speed = SPEED_1000;
+ break;
+ case MII_AT001_PSSR_100MBS:
+ *speed = SPEED_100;
+ break;
+ case MII_AT001_PSSR_10MBS:
+ *speed = SPEED_10;
+ break;
+ default:
+ printk(KERN_DEBUG "%s: error getting speed\n",
+ atl1_driver_name);
+ return ATL1_ERR_PHY_SPEED;
+ break;
+ }
+ if (phy_data & MII_AT001_PSSR_DPLX)
+ *duplex = FULL_DUPLEX;
+ else
+ *duplex = HALF_DUPLEX;
+
+ return ATL1_SUCCESS;
+}
+
+void atl1_set_mac_addr(struct atl1_hw *hw)
+{
+ u32 value;
+ /*
+ * 00-0B-6A-F6-00-DC
+ * 0: 6AF600DC 1: 000B
+ * low dword
+ */
+ value = (((u32) hw->mac_addr[2]) << 24) |
+ (((u32) hw->mac_addr[3]) << 16) |
+ (((u32) hw->mac_addr[4]) << 8) | (((u32) hw->mac_addr[5]));
+ iowrite32(value, hw->hw_addr + REG_MAC_STA_ADDR);
+ /* high dword */
+ value = (((u32) hw->mac_addr[0]) << 8) | (((u32) hw->mac_addr[1]));
+ iowrite32(value, (hw->hw_addr + REG_MAC_STA_ADDR) + (1 << 2));
+}
diff --git a/drivers/net/atl1/atl1_hw.h b/drivers/net/atl1/atl1_hw.h
new file mode 100644
index 00000000000..100c09c66e6
--- /dev/null
+++ b/drivers/net/atl1/atl1_hw.h
@@ -0,0 +1,951 @@
+/*
+ * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved.
+ * Copyright(c) 2006 Chris Snook <csnook@redhat.com>
+ * Copyright(c) 2006 Jay Cliburn <jcliburn@gmail.com>
+ *
+ * Derived from Intel e1000 driver
+ * Copyright(c) 1999 - 2005 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.
+ *
+ * There are a lot of defines in here that are unused and/or have cryptic
+ * names. Please leave them alone, as they're the closest thing we have
+ * to a spec from Attansic at present. *ahem* -- CHS
+ */
+
+#ifndef _ATL1_HW_H_
+#define _ATL1_HW_H_
+
+#include <linux/types.h>
+#include <linux/mii.h>
+
+struct atl1_adapter;
+struct atl1_hw;
+
+/* function prototypes needed by multiple files */
+s32 atl1_phy_setup_autoneg_adv(struct atl1_hw *hw);
+s32 atl1_write_phy_reg(struct atl1_hw *hw, u32 reg_addr, u16 phy_data);
+s32 atl1_get_speed_and_duplex(struct atl1_hw *hw, u16 *speed, u16 *duplex);
+s32 atl1_read_mac_addr(struct atl1_hw *hw);
+s32 atl1_init_hw(struct atl1_hw *hw);
+s32 atl1_get_speed_and_duplex(struct atl1_hw *hw, u16 *speed, u16 *duplex);
+s32 atl1_set_speed_and_duplex(struct atl1_hw *hw, u16 speed, u16 duplex);
+u32 atl1_hash_mc_addr(struct atl1_hw *hw, u8 *mc_addr);
+void atl1_hash_set(struct atl1_hw *hw, u32 hash_value);
+s32 atl1_read_phy_reg(struct atl1_hw *hw, u16 reg_addr, u16 *phy_data);
+void atl1_set_mac_addr(struct atl1_hw *hw);
+s32 atl1_phy_enter_power_saving(struct atl1_hw *hw);
+s32 atl1_reset_hw(struct atl1_hw *hw);
+void atl1_check_options(struct atl1_adapter *adapter);
+
+/* register definitions */
+#define REG_PCIE_CAP_LIST 0x58
+
+#define REG_VPD_CAP 0x6C
+#define VPD_CAP_ID_MASK 0xff
+#define VPD_CAP_ID_SHIFT 0
+#define VPD_CAP_NEXT_PTR_MASK 0xFF
+#define VPD_CAP_NEXT_PTR_SHIFT 8
+#define VPD_CAP_VPD_ADDR_MASK 0x7FFF
+#define VPD_CAP_VPD_ADDR_SHIFT 16
+#define VPD_CAP_VPD_FLAG 0x80000000
+
+#define REG_VPD_DATA 0x70
+
+#define REG_SPI_FLASH_CTRL 0x200
+#define SPI_FLASH_CTRL_STS_NON_RDY 0x1
+#define SPI_FLASH_CTRL_STS_WEN 0x2
+#define SPI_FLASH_CTRL_STS_WPEN 0x80
+#define SPI_FLASH_CTRL_DEV_STS_MASK 0xFF
+#define SPI_FLASH_CTRL_DEV_STS_SHIFT 0
+#define SPI_FLASH_CTRL_INS_MASK 0x7
+#define SPI_FLASH_CTRL_INS_SHIFT 8
+#define SPI_FLASH_CTRL_START 0x800
+#define SPI_FLASH_CTRL_EN_VPD 0x2000
+#define SPI_FLASH_CTRL_LDSTART 0x8000
+#define SPI_FLASH_CTRL_CS_HI_MASK 0x3
+#define SPI_FLASH_CTRL_CS_HI_SHIFT 16
+#define SPI_FLASH_CTRL_CS_HOLD_MASK 0x3
+#define SPI_FLASH_CTRL_CS_HOLD_SHIFT 18
+#define SPI_FLASH_CTRL_CLK_LO_MASK 0x3
+#define SPI_FLASH_CTRL_CLK_LO_SHIFT 20
+#define SPI_FLASH_CTRL_CLK_HI_MASK 0x3
+#define SPI_FLASH_CTRL_CLK_HI_SHIFT 22
+#define SPI_FLASH_CTRL_CS_SETUP_MASK 0x3
+#define SPI_FLASH_CTRL_CS_SETUP_SHIFT 24
+#define SPI_FLASH_CTRL_EROM_PGSZ_MASK 0x3
+#define SPI_FLASH_CTRL_EROM_PGSZ_SHIFT 26
+#define SPI_FLASH_CTRL_WAIT_READY 0x10000000
+
+#define REG_SPI_ADDR 0x204
+
+#define REG_SPI_DATA 0x208
+
+#define REG_SPI_FLASH_CONFIG 0x20C
+#define SPI_FLASH_CONFIG_LD_ADDR_MASK 0xFFFFFF
+#define SPI_FLASH_CONFIG_LD_ADDR_SHIFT 0
+#define SPI_FLASH_CONFIG_VPD_ADDR_MASK 0x3
+#define SPI_FLASH_CONFIG_VPD_ADDR_SHIFT 24
+#define SPI_FLASH_CONFIG_LD_EXIST 0x4000000
+
+#define REG_SPI_FLASH_OP_PROGRAM 0x210
+#define REG_SPI_FLASH_OP_SC_ERASE 0x211
+#define REG_SPI_FLASH_OP_CHIP_ERASE 0x212
+#define REG_SPI_FLASH_OP_RDID 0x213
+#define REG_SPI_FLASH_OP_WREN 0x214
+#define REG_SPI_FLASH_OP_RDSR 0x215
+#define REG_SPI_FLASH_OP_WRSR 0x216
+#define REG_SPI_FLASH_OP_READ 0x217
+
+#define REG_TWSI_CTRL 0x218
+#define TWSI_CTRL_LD_OFFSET_MASK 0xFF
+#define TWSI_CTRL_LD_OFFSET_SHIFT 0
+#define TWSI_CTRL_LD_SLV_ADDR_MASK 0x7
+#define TWSI_CTRL_LD_SLV_ADDR_SHIFT 8
+#define TWSI_CTRL_SW_LDSTART 0x800
+#define TWSI_CTRL_HW_LDSTART 0x1000
+#define TWSI_CTRL_SMB_SLV_ADDR_MASK 0x7F
+#define TWSI_CTRL_SMB_SLV_ADDR_SHIFT 15
+#define TWSI_CTRL_LD_EXIST 0x400000
+#define TWSI_CTRL_READ_FREQ_SEL_MASK 0x3
+#define TWSI_CTRL_READ_FREQ_SEL_SHIFT 23
+#define TWSI_CTRL_FREQ_SEL_100K 0
+#define TWSI_CTRL_FREQ_SEL_200K 1
+#define TWSI_CTRL_FREQ_SEL_300K 2
+#define TWSI_CTRL_FREQ_SEL_400K 3
+#define TWSI_CTRL_SMB_SLV_ADDR
+#define TWSI_CTRL_WRITE_FREQ_SEL_MASK 0x3
+#define TWSI_CTRL_WRITE_FREQ_SEL_SHIFT 24
+
+#define REG_PCIE_DEV_MISC_CTRL 0x21C
+#define PCIE_DEV_MISC_CTRL_EXT_PIPE 0x2
+#define PCIE_DEV_MISC_CTRL_RETRY_BUFDIS 0x1
+#define PCIE_DEV_MISC_CTRL_SPIROM_EXIST 0x4
+#define PCIE_DEV_MISC_CTRL_SERDES_ENDIAN 0x8
+#define PCIE_DEV_MISC_CTRL_SERDES_SEL_DIN 0x10
+
+/* Selene Master Control Register */
+#define REG_MASTER_CTRL 0x1400
+#define MASTER_CTRL_SOFT_RST 0x1
+#define MASTER_CTRL_MTIMER_EN 0x2
+#define MASTER_CTRL_ITIMER_EN 0x4
+#define MASTER_CTRL_MANUAL_INT 0x8
+#define MASTER_CTRL_REV_NUM_SHIFT 16
+#define MASTER_CTRL_REV_NUM_MASK 0xff
+#define MASTER_CTRL_DEV_ID_SHIFT 24
+#define MASTER_CTRL_DEV_ID_MASK 0xff
+
+/* Timer Initial Value Register */
+#define REG_MANUAL_TIMER_INIT 0x1404
+
+/* IRQ ModeratorTimer Initial Value Register */
+#define REG_IRQ_MODU_TIMER_INIT 0x1408
+
+#define REG_GPHY_ENABLE 0x140C
+
+/* IRQ Anti-Lost Timer Initial Value Register */
+#define REG_CMBDISDMA_TIMER 0x140E
+
+/* Block IDLE Status Register */
+#define REG_IDLE_STATUS 0x1410
+#define IDLE_STATUS_RXMAC 1
+#define IDLE_STATUS_TXMAC 2
+#define IDLE_STATUS_RXQ 4
+#define IDLE_STATUS_TXQ 8
+#define IDLE_STATUS_DMAR 0x10
+#define IDLE_STATUS_DMAW 0x20
+#define IDLE_STATUS_SMB 0x40
+#define IDLE_STATUS_CMB 0x80
+
+/* MDIO Control Register */
+#define REG_MDIO_CTRL 0x1414
+#define MDIO_DATA_MASK 0xffff
+#define MDIO_DATA_SHIFT 0
+#define MDIO_REG_ADDR_MASK 0x1f
+#define MDIO_REG_ADDR_SHIFT 16
+#define MDIO_RW 0x200000
+#define MDIO_SUP_PREAMBLE 0x400000
+#define MDIO_START 0x800000
+#define MDIO_CLK_SEL_SHIFT 24
+#define MDIO_CLK_25_4 0
+#define MDIO_CLK_25_6 2
+#define MDIO_CLK_25_8 3
+#define MDIO_CLK_25_10 4
+#define MDIO_CLK_25_14 5
+#define MDIO_CLK_25_20 6
+#define MDIO_CLK_25_28 7
+#define MDIO_BUSY 0x8000000
+#define MDIO_WAIT_TIMES 30
+
+/* MII PHY Status Register */
+#define REG_PHY_STATUS 0x1418
+
+/* BIST Control and Status Register0 (for the Packet Memory) */
+#define REG_BIST0_CTRL 0x141c
+#define BIST0_NOW 0x1
+#define BIST0_SRAM_FAIL 0x2
+#define BIST0_FUSE_FLAG 0x4
+#define REG_BIST1_CTRL 0x1420
+#define BIST1_NOW 0x1
+#define BIST1_SRAM_FAIL 0x2
+#define BIST1_FUSE_FLAG 0x4
+
+/* MAC Control Register */
+#define REG_MAC_CTRL 0x1480
+#define MAC_CTRL_TX_EN 1
+#define MAC_CTRL_RX_EN 2
+#define MAC_CTRL_TX_FLOW 4
+#define MAC_CTRL_RX_FLOW 8
+#define MAC_CTRL_LOOPBACK 0x10
+#define MAC_CTRL_DUPLX 0x20
+#define MAC_CTRL_ADD_CRC 0x40
+#define MAC_CTRL_PAD 0x80
+#define MAC_CTRL_LENCHK 0x100
+#define MAC_CTRL_HUGE_EN 0x200
+#define MAC_CTRL_PRMLEN_SHIFT 10
+#define MAC_CTRL_PRMLEN_MASK 0xf
+#define MAC_CTRL_RMV_VLAN 0x4000
+#define MAC_CTRL_PROMIS_EN 0x8000
+#define MAC_CTRL_TX_PAUSE 0x10000
+#define MAC_CTRL_SCNT 0x20000
+#define MAC_CTRL_SRST_TX 0x40000
+#define MAC_CTRL_TX_SIMURST 0x80000
+#define MAC_CTRL_SPEED_SHIFT 20
+#define MAC_CTRL_SPEED_MASK 0x300000
+#define MAC_CTRL_SPEED_1000 2
+#define MAC_CTRL_SPEED_10_100 1
+#define MAC_CTRL_DBG_TX_BKPRESURE 0x400000
+#define MAC_CTRL_TX_HUGE 0x800000
+#define MAC_CTRL_RX_CHKSUM_EN 0x1000000
+#define MAC_CTRL_MC_ALL_EN 0x2000000
+#define MAC_CTRL_BC_EN 0x4000000
+#define MAC_CTRL_DBG 0x8000000
+
+/* MAC IPG/IFG Control Register */
+#define REG_MAC_IPG_IFG 0x1484
+#define MAC_IPG_IFG_IPGT_SHIFT 0
+#define MAC_IPG_IFG_IPGT_MASK 0x7f
+#define MAC_IPG_IFG_MIFG_SHIFT 8
+#define MAC_IPG_IFG_MIFG_MASK 0xff
+#define MAC_IPG_IFG_IPGR1_SHIFT 16
+#define MAC_IPG_IFG_IPGR1_MASK 0x7f
+#define MAC_IPG_IFG_IPGR2_SHIFT 24
+#define MAC_IPG_IFG_IPGR2_MASK 0x7f
+
+/* MAC STATION ADDRESS */
+#define REG_MAC_STA_ADDR 0x1488
+
+/* Hash table for multicast address */
+#define REG_RX_HASH_TABLE 0x1490
+
+/* MAC Half-Duplex Control Register */
+#define REG_MAC_HALF_DUPLX_CTRL 0x1498
+#define MAC_HALF_DUPLX_CTRL_LCOL_SHIFT 0
+#define MAC_HALF_DUPLX_CTRL_LCOL_MASK 0x3ff
+#define MAC_HALF_DUPLX_CTRL_RETRY_SHIFT 12
+#define MAC_HALF_DUPLX_CTRL_RETRY_MASK 0xf
+#define MAC_HALF_DUPLX_CTRL_EXC_DEF_EN 0x10000
+#define MAC_HALF_DUPLX_CTRL_NO_BACK_C 0x20000
+#define MAC_HALF_DUPLX_CTRL_NO_BACK_P 0x40000
+#define MAC_HALF_DUPLX_CTRL_ABEBE 0x80000
+#define MAC_HALF_DUPLX_CTRL_ABEBT_SHIFT 20
+#define MAC_HALF_DUPLX_CTRL_ABEBT_MASK 0xf
+#define MAC_HALF_DUPLX_CTRL_JAMIPG_SHIFT 24
+#define MAC_HALF_DUPLX_CTRL_JAMIPG_MASK 0xf
+
+/* Maximum Frame Length Control Register */
+#define REG_MTU 0x149c
+
+/* Wake-On-Lan control register */
+#define REG_WOL_CTRL 0x14a0
+#define WOL_PATTERN_EN 0x00000001
+#define WOL_PATTERN_PME_EN 0x00000002
+#define WOL_MAGIC_EN 0x00000004
+#define WOL_MAGIC_PME_EN 0x00000008
+#define WOL_LINK_CHG_EN 0x00000010
+#define WOL_LINK_CHG_PME_EN 0x00000020
+#define WOL_PATTERN_ST 0x00000100
+#define WOL_MAGIC_ST 0x00000200
+#define WOL_LINKCHG_ST 0x00000400
+#define WOL_CLK_SWITCH_EN 0x00008000
+#define WOL_PT0_EN 0x00010000
+#define WOL_PT1_EN 0x00020000
+#define WOL_PT2_EN 0x00040000
+#define WOL_PT3_EN 0x00080000
+#define WOL_PT4_EN 0x00100000
+#define WOL_PT5_EN 0x00200000
+#define WOL_PT6_EN 0x00400000
+
+/* WOL Length ( 2 DWORD ) */
+#define REG_WOL_PATTERN_LEN 0x14a4
+#define WOL_PT_LEN_MASK 0x7f
+#define WOL_PT0_LEN_SHIFT 0
+#define WOL_PT1_LEN_SHIFT 8
+#define WOL_PT2_LEN_SHIFT 16
+#define WOL_PT3_LEN_SHIFT 24
+#define WOL_PT4_LEN_SHIFT 0
+#define WOL_PT5_LEN_SHIFT 8
+#define WOL_PT6_LEN_SHIFT 16
+
+/* Internal SRAM Partition Register */
+#define REG_SRAM_RFD_ADDR 0x1500
+#define REG_SRAM_RFD_LEN (REG_SRAM_RFD_ADDR+ 4)
+#define REG_SRAM_RRD_ADDR (REG_SRAM_RFD_ADDR+ 8)
+#define REG_SRAM_RRD_LEN (REG_SRAM_RFD_ADDR+12)
+#define REG_SRAM_TPD_ADDR (REG_SRAM_RFD_ADDR+16)
+#define REG_SRAM_TPD_LEN (REG_SRAM_RFD_ADDR+20)
+#define REG_SRAM_TRD_ADDR (REG_SRAM_RFD_ADDR+24)
+#define REG_SRAM_TRD_LEN (REG_SRAM_RFD_ADDR+28)
+#define REG_SRAM_RXF_ADDR (REG_SRAM_RFD_ADDR+32)
+#define REG_SRAM_RXF_LEN (REG_SRAM_RFD_ADDR+36)
+#define REG_SRAM_TXF_ADDR (REG_SRAM_RFD_ADDR+40)
+#define REG_SRAM_TXF_LEN (REG_SRAM_RFD_ADDR+44)
+#define REG_SRAM_TCPH_PATH_ADDR (REG_SRAM_RFD_ADDR+48)
+#define SRAM_TCPH_ADDR_MASK 0x0fff
+#define SRAM_TCPH_ADDR_SHIFT 0
+#define SRAM_PATH_ADDR_MASK 0x0fff
+#define SRAM_PATH_ADDR_SHIFT 16
+
+/* Load Ptr Register */
+#define REG_LOAD_PTR (REG_SRAM_RFD_ADDR+52)
+
+/* Descriptor Control register */
+#define REG_DESC_BASE_ADDR_HI 0x1540
+#define REG_DESC_RFD_ADDR_LO (REG_DESC_BASE_ADDR_HI+4)
+#define REG_DESC_RRD_ADDR_LO (REG_DESC_BASE_ADDR_HI+8)
+#define REG_DESC_TPD_ADDR_LO (REG_DESC_BASE_ADDR_HI+12)
+#define REG_DESC_CMB_ADDR_LO (REG_DESC_BASE_ADDR_HI+16)
+#define REG_DESC_SMB_ADDR_LO (REG_DESC_BASE_ADDR_HI+20)
+#define REG_DESC_RFD_RRD_RING_SIZE (REG_DESC_BASE_ADDR_HI+24)
+#define DESC_RFD_RING_SIZE_MASK 0x7ff
+#define DESC_RFD_RING_SIZE_SHIFT 0
+#define DESC_RRD_RING_SIZE_MASK 0x7ff
+#define DESC_RRD_RING_SIZE_SHIFT 16
+#define REG_DESC_TPD_RING_SIZE (REG_DESC_BASE_ADDR_HI+28)
+#define DESC_TPD_RING_SIZE_MASK 0x3ff
+#define DESC_TPD_RING_SIZE_SHIFT 0
+
+/* TXQ Control Register */
+#define REG_TXQ_CTRL 0x1580
+#define TXQ_CTRL_TPD_BURST_NUM_SHIFT 0
+#define TXQ_CTRL_TPD_BURST_NUM_MASK 0x1f
+#define TXQ_CTRL_EN 0x20
+#define TXQ_CTRL_ENH_MODE 0x40
+#define TXQ_CTRL_TPD_FETCH_TH_SHIFT 8
+#define TXQ_CTRL_TPD_FETCH_TH_MASK 0x3f
+#define TXQ_CTRL_TXF_BURST_NUM_SHIFT 16
+#define TXQ_CTRL_TXF_BURST_NUM_MASK 0xffff
+
+/* Jumbo packet Threshold for task offload */
+#define REG_TX_JUMBO_TASK_TH_TPD_IPG 0x1584
+#define TX_JUMBO_TASK_TH_MASK 0x7ff
+#define TX_JUMBO_TASK_TH_SHIFT 0
+#define TX_TPD_MIN_IPG_MASK 0x1f
+#define TX_TPD_MIN_IPG_SHIFT 16
+
+/* RXQ Control Register */
+#define REG_RXQ_CTRL 0x15a0
+#define RXQ_CTRL_RFD_BURST_NUM_SHIFT 0
+#define RXQ_CTRL_RFD_BURST_NUM_MASK 0xff
+#define RXQ_CTRL_RRD_BURST_THRESH_SHIFT 8
+#define RXQ_CTRL_RRD_BURST_THRESH_MASK 0xff
+#define RXQ_CTRL_RFD_PREF_MIN_IPG_SHIFT 16
+#define RXQ_CTRL_RFD_PREF_MIN_IPG_MASK 0x1f
+#define RXQ_CTRL_CUT_THRU_EN 0x40000000
+#define RXQ_CTRL_EN 0x80000000
+
+/* Rx jumbo packet threshold and rrd retirement timer */
+#define REG_RXQ_JMBOSZ_RRDTIM (REG_RXQ_CTRL+ 4)
+#define RXQ_JMBOSZ_TH_MASK 0x7ff
+#define RXQ_JMBOSZ_TH_SHIFT 0
+#define RXQ_JMBO_LKAH_MASK 0xf
+#define RXQ_JMBO_LKAH_SHIFT 11
+#define RXQ_RRD_TIMER_MASK 0xffff
+#define RXQ_RRD_TIMER_SHIFT 16
+
+/* RFD flow control register */
+#define REG_RXQ_RXF_PAUSE_THRESH (REG_RXQ_CTRL+ 8)
+#define RXQ_RXF_PAUSE_TH_HI_SHIFT 16
+#define RXQ_RXF_PAUSE_TH_HI_MASK 0xfff
+#define RXQ_RXF_PAUSE_TH_LO_SHIFT 0
+#define RXQ_RXF_PAUSE_TH_LO_MASK 0xfff
+
+/* RRD flow control register */
+#define REG_RXQ_RRD_PAUSE_THRESH (REG_RXQ_CTRL+12)
+#define RXQ_RRD_PAUSE_TH_HI_SHIFT 0
+#define RXQ_RRD_PAUSE_TH_HI_MASK 0xfff
+#define RXQ_RRD_PAUSE_TH_LO_SHIFT 16
+#define RXQ_RRD_PAUSE_TH_LO_MASK 0xfff
+
+/* DMA Engine Control Register */
+#define REG_DMA_CTRL 0x15c0
+#define DMA_CTRL_DMAR_IN_ORDER 0x1
+#define DMA_CTRL_DMAR_ENH_ORDER 0x2
+#define DMA_CTRL_DMAR_OUT_ORDER 0x4
+#define DMA_CTRL_RCB_VALUE 0x8
+#define DMA_CTRL_DMAR_BURST_LEN_SHIFT 4
+#define DMA_CTRL_DMAR_BURST_LEN_MASK 7
+#define DMA_CTRL_DMAW_BURST_LEN_SHIFT 7
+#define DMA_CTRL_DMAW_BURST_LEN_MASK 7
+#define DMA_CTRL_DMAR_EN 0x400
+#define DMA_CTRL_DMAW_EN 0x800
+
+/* CMB/SMB Control Register */
+#define REG_CSMB_CTRL 0x15d0
+#define CSMB_CTRL_CMB_NOW 1
+#define CSMB_CTRL_SMB_NOW 2
+#define CSMB_CTRL_CMB_EN 4
+#define CSMB_CTRL_SMB_EN 8
+
+/* CMB DMA Write Threshold Register */
+#define REG_CMB_WRITE_TH (REG_CSMB_CTRL+ 4)
+#define CMB_RRD_TH_SHIFT 0
+#define CMB_RRD_TH_MASK 0x7ff
+#define CMB_TPD_TH_SHIFT 16
+#define CMB_TPD_TH_MASK 0x7ff
+
+/* RX/TX count-down timer to trigger CMB-write. 2us resolution. */
+#define REG_CMB_WRITE_TIMER (REG_CSMB_CTRL+ 8)
+#define CMB_RX_TM_SHIFT 0
+#define CMB_RX_TM_MASK 0xffff
+#define CMB_TX_TM_SHIFT 16
+#define CMB_TX_TM_MASK 0xffff
+
+/* Number of packet received since last CMB write */
+#define REG_CMB_RX_PKT_CNT (REG_CSMB_CTRL+12)
+
+/* Number of packet transmitted since last CMB write */
+#define REG_CMB_TX_PKT_CNT (REG_CSMB_CTRL+16)
+
+/* SMB auto DMA timer register */
+#define REG_SMB_TIMER (REG_CSMB_CTRL+20)
+
+/* Mailbox Register */
+#define REG_MAILBOX 0x15f0
+#define MB_RFD_PROD_INDX_SHIFT 0
+#define MB_RFD_PROD_INDX_MASK 0x7ff
+#define MB_RRD_CONS_INDX_SHIFT 11
+#define MB_RRD_CONS_INDX_MASK 0x7ff
+#define MB_TPD_PROD_INDX_SHIFT 22
+#define MB_TPD_PROD_INDX_MASK 0x3ff
+
+/* Interrupt Status Register */
+#define REG_ISR 0x1600
+#define ISR_SMB 1
+#define ISR_TIMER 2
+#define ISR_MANUAL 4
+#define ISR_RXF_OV 8
+#define ISR_RFD_UNRUN 0x10
+#define ISR_RRD_OV 0x20
+#define ISR_TXF_UNRUN 0x40
+#define ISR_LINK 0x80
+#define ISR_HOST_RFD_UNRUN 0x100
+#define ISR_HOST_RRD_OV 0x200
+#define ISR_DMAR_TO_RST 0x400
+#define ISR_DMAW_TO_RST 0x800
+#define ISR_GPHY 0x1000
+#define ISR_RX_PKT 0x10000
+#define ISR_TX_PKT 0x20000
+#define ISR_TX_DMA 0x40000
+#define ISR_RX_DMA 0x80000
+#define ISR_CMB_RX 0x100000
+#define ISR_CMB_TX 0x200000
+#define ISR_MAC_RX 0x400000
+#define ISR_MAC_TX 0x800000
+#define ISR_UR_DETECTED 0x1000000
+#define ISR_FERR_DETECTED 0x2000000
+#define ISR_NFERR_DETECTED 0x4000000
+#define ISR_CERR_DETECTED 0x8000000
+#define ISR_PHY_LINKDOWN 0x10000000
+#define ISR_DIS_SMB 0x20000000
+#define ISR_DIS_DMA 0x40000000
+#define ISR_DIS_INT 0x80000000
+
+/* Interrupt Mask Register */
+#define REG_IMR 0x1604
+
+/* Normal Interrupt mask */
+#define IMR_NORMAL_MASK (\
+ ISR_SMB |\
+ ISR_GPHY |\
+ ISR_PHY_LINKDOWN|\
+ ISR_DMAR_TO_RST |\
+ ISR_DMAW_TO_RST |\
+ ISR_CMB_TX |\
+ ISR_CMB_RX )
+
+/* Debug Interrupt Mask (enable all interrupt) */
+#define IMR_DEBUG_MASK (\
+ ISR_SMB |\
+ ISR_TIMER |\
+ ISR_MANUAL |\
+ ISR_RXF_OV |\
+ ISR_RFD_UNRUN |\
+ ISR_RRD_OV |\
+ ISR_TXF_UNRUN |\
+ ISR_LINK |\
+ ISR_CMB_TX |\
+ ISR_CMB_RX |\
+ ISR_RX_PKT |\
+ ISR_TX_PKT |\
+ ISR_MAC_RX |\
+ ISR_MAC_TX )
+
+/* Interrupt Status Register */
+#define REG_RFD_RRD_IDX 0x1800
+#define REG_TPD_IDX 0x1804
+
+/* MII definition */
+/* PHY Common Register */
+#define MII_AT001_CR 0x09
+#define MII_AT001_SR 0x0A
+#define MII_AT001_ESR 0x0F
+#define MII_AT001_PSCR 0x10
+#define MII_AT001_PSSR 0x11
+
+/* PHY Control Register */
+#define MII_CR_SPEED_SELECT_MSB 0x0040 /* bits 6,13: 10=1000, 01=100, 00=10 */
+#define MII_CR_COLL_TEST_ENABLE 0x0080 /* Collision test enable */
+#define MII_CR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */
+#define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */
+#define MII_CR_ISOLATE 0x0400 /* Isolate PHY from MII */
+#define MII_CR_POWER_DOWN 0x0800 /* Power down */
+#define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */
+#define MII_CR_SPEED_SELECT_LSB 0x2000 /* bits 6,13: 10=1000, 01=100, 00=10 */
+#define MII_CR_LOOPBACK 0x4000 /* 0 = normal, 1 = loopback */
+#define MII_CR_RESET 0x8000 /* 0 = normal, 1 = PHY reset */
+#define MII_CR_SPEED_MASK 0x2040
+#define MII_CR_SPEED_1000 0x0040
+#define MII_CR_SPEED_100 0x2000
+#define MII_CR_SPEED_10 0x0000
+
+/* PHY Status Register */
+#define MII_SR_EXTENDED_CAPS 0x0001 /* Extended register capabilities */
+#define MII_SR_JABBER_DETECT 0x0002 /* Jabber Detected */
+#define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */
+#define MII_SR_AUTONEG_CAPS 0x0008 /* Auto Neg Capable */
+#define MII_SR_REMOTE_FAULT 0x0010 /* Remote Fault Detect */
+#define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */
+#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */
+#define MII_SR_EXTENDED_STATUS 0x0100 /* Ext. status info in Reg 0x0F */
+#define MII_SR_100T2_HD_CAPS 0x0200 /* 100T2 Half Duplex Capable */
+#define MII_SR_100T2_FD_CAPS 0x0400 /* 100T2 Full Duplex Capable */
+#define MII_SR_10T_HD_CAPS 0x0800 /* 10T Half Duplex Capable */
+#define MII_SR_10T_FD_CAPS 0x1000 /* 10T Full Duplex Capable */
+#define MII_SR_100X_HD_CAPS 0x2000 /* 100X Half Duplex Capable */
+#define MII_SR_100X_FD_CAPS 0x4000 /* 100X Full Duplex Capable */
+#define MII_SR_100T4_CAPS 0x8000 /* 100T4 Capable */
+
+/* Link partner ability register. */
+#define MII_LPA_SLCT 0x001f /* Same as advertise selector */
+#define MII_LPA_10HALF 0x0020 /* Can do 10mbps half-duplex */
+#define MII_LPA_10FULL 0x0040 /* Can do 10mbps full-duplex */
+#define MII_LPA_100HALF 0x0080 /* Can do 100mbps half-duplex */
+#define MII_LPA_100FULL 0x0100 /* Can do 100mbps full-duplex */
+#define MII_LPA_100BASE4 0x0200 /* 100BASE-T4 */
+#define MII_LPA_PAUSE 0x0400 /* PAUSE */
+#define MII_LPA_ASYPAUSE 0x0800 /* Asymmetrical PAUSE */
+#define MII_LPA_RFAULT 0x2000 /* Link partner faulted */
+#define MII_LPA_LPACK 0x4000 /* Link partner acked us */
+#define MII_LPA_NPAGE 0x8000 /* Next page bit */
+
+/* Autoneg Advertisement Register */
+#define MII_AR_SELECTOR_FIELD 0x0001 /* indicates IEEE 802.3 CSMA/CD */
+#define MII_AR_10T_HD_CAPS 0x0020 /* 10T Half Duplex Capable */
+#define MII_AR_10T_FD_CAPS 0x0040 /* 10T Full Duplex Capable */
+#define MII_AR_100TX_HD_CAPS 0x0080 /* 100TX Half Duplex Capable */
+#define MII_AR_100TX_FD_CAPS 0x0100 /* 100TX Full Duplex Capable */
+#define MII_AR_100T4_CAPS 0x0200 /* 100T4 Capable */
+#define MII_AR_PAUSE 0x0400 /* Pause operation desired */
+#define MII_AR_ASM_DIR 0x0800 /* Asymmetric Pause Direction bit */
+#define MII_AR_REMOTE_FAULT 0x2000 /* Remote Fault detected */
+#define MII_AR_NEXT_PAGE 0x8000 /* Next Page ability supported */
+#define MII_AR_SPEED_MASK 0x01E0
+#define MII_AR_DEFAULT_CAP_MASK 0x0DE0
+
+/* 1000BASE-T Control Register */
+#define MII_AT001_CR_1000T_HD_CAPS 0x0100 /* Advertise 1000T HD capability */
+#define MII_AT001_CR_1000T_FD_CAPS 0x0200 /* Advertise 1000T FD capability */
+#define MII_AT001_CR_1000T_REPEATER_DTE 0x0400 /* 1=Repeater/switch device port, 0=DTE device */
+#define MII_AT001_CR_1000T_MS_VALUE 0x0800 /* 1=Configure PHY as Master, 0=Configure PHY as Slave */
+#define MII_AT001_CR_1000T_MS_ENABLE 0x1000 /* 1=Master/Slave manual config value, 0=Automatic Master/Slave config */
+#define MII_AT001_CR_1000T_TEST_MODE_NORMAL 0x0000 /* Normal Operation */
+#define MII_AT001_CR_1000T_TEST_MODE_1 0x2000 /* Transmit Waveform test */
+#define MII_AT001_CR_1000T_TEST_MODE_2 0x4000 /* Master Transmit Jitter test */
+#define MII_AT001_CR_1000T_TEST_MODE_3 0x6000 /* Slave Transmit Jitter test */
+#define MII_AT001_CR_1000T_TEST_MODE_4 0x8000 /* Transmitter Distortion test */
+#define MII_AT001_CR_1000T_SPEED_MASK 0x0300
+#define MII_AT001_CR_1000T_DEFAULT_CAP_MASK 0x0300
+
+/* 1000BASE-T Status Register */
+#define MII_AT001_SR_1000T_LP_HD_CAPS 0x0400 /* LP is 1000T HD capable */
+#define MII_AT001_SR_1000T_LP_FD_CAPS 0x0800 /* LP is 1000T FD capable */
+#define MII_AT001_SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */
+#define MII_AT001_SR_1000T_LOCAL_RX_STATUS 0x2000 /* Local receiver OK */
+#define MII_AT001_SR_1000T_MS_CONFIG_RES 0x4000 /* 1=Local TX is Master, 0=Slave */
+#define MII_AT001_SR_1000T_MS_CONFIG_FAULT 0x8000 /* Master/Slave config fault */
+#define MII_AT001_SR_1000T_REMOTE_RX_STATUS_SHIFT 12
+#define MII_AT001_SR_1000T_LOCAL_RX_STATUS_SHIFT 13
+
+/* Extended Status Register */
+#define MII_AT001_ESR_1000T_HD_CAPS 0x1000 /* 1000T HD capable */
+#define MII_AT001_ESR_1000T_FD_CAPS 0x2000 /* 1000T FD capable */
+#define MII_AT001_ESR_1000X_HD_CAPS 0x4000 /* 1000X HD capable */
+#define MII_AT001_ESR_1000X_FD_CAPS 0x8000 /* 1000X FD capable */
+
+/* AT001 PHY Specific Control Register */
+#define MII_AT001_PSCR_JABBER_DISABLE 0x0001 /* 1=Jabber Function disabled */
+#define MII_AT001_PSCR_POLARITY_REVERSAL 0x0002 /* 1=Polarity Reversal enabled */
+#define MII_AT001_PSCR_SQE_TEST 0x0004 /* 1=SQE Test enabled */
+#define MII_AT001_PSCR_MAC_POWERDOWN 0x0008
+#define MII_AT001_PSCR_CLK125_DISABLE 0x0010 /* 1=CLK125 low, 0=CLK125 toggling */
+#define MII_AT001_PSCR_MDI_MANUAL_MODE 0x0000 /* MDI Crossover Mode bits 6:5, Manual MDI configuration */
+#define MII_AT001_PSCR_MDIX_MANUAL_MODE 0x0020 /* Manual MDIX configuration */
+#define MII_AT001_PSCR_AUTO_X_1000T 0x0040 /* 1000BASE-T: Auto crossover, 100BASE-TX/10BASE-T: MDI Mode */
+#define MII_AT001_PSCR_AUTO_X_MODE 0x0060 /* Auto crossover enabled all speeds. */
+#define MII_AT001_PSCR_10BT_EXT_DIST_ENABLE 0x0080 /* 1=Enable Extended 10BASE-T distance (Lower 10BASE-T RX Threshold), 0=Normal 10BASE-T RX Threshold */
+#define MII_AT001_PSCR_MII_5BIT_ENABLE 0x0100 /* 1=5-Bit interface in 100BASE-TX, 0=MII interface in 100BASE-TX */
+#define MII_AT001_PSCR_SCRAMBLER_DISABLE 0x0200 /* 1=Scrambler disable */
+#define MII_AT001_PSCR_FORCE_LINK_GOOD 0x0400 /* 1=Force link good */
+#define MII_AT001_PSCR_ASSERT_CRS_ON_TX 0x0800 /* 1=Assert CRS on Transmit */
+#define MII_AT001_PSCR_POLARITY_REVERSAL_SHIFT 1
+#define MII_AT001_PSCR_AUTO_X_MODE_SHIFT 5
+#define MII_AT001_PSCR_10BT_EXT_DIST_ENABLE_SHIFT 7
+
+/* AT001 PHY Specific Status Register */
+#define MII_AT001_PSSR_SPD_DPLX_RESOLVED 0x0800 /* 1=Speed & Duplex resolved */
+#define MII_AT001_PSSR_DPLX 0x2000 /* 1=Duplex 0=Half Duplex */
+#define MII_AT001_PSSR_SPEED 0xC000 /* Speed, bits 14:15 */
+#define MII_AT001_PSSR_10MBS 0x0000 /* 00=10Mbs */
+#define MII_AT001_PSSR_100MBS 0x4000 /* 01=100Mbs */
+#define MII_AT001_PSSR_1000MBS 0x8000 /* 10=1000Mbs */
+
+/* PCI Command Register Bit Definitions */
+#define PCI_REG_COMMAND 0x04 /* PCI Command Register */
+#define CMD_IO_SPACE 0x0001
+#define CMD_MEMORY_SPACE 0x0002
+#define CMD_BUS_MASTER 0x0004
+
+/* Wake Up Filter Control */
+#define ATL1_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */
+#define ATL1_WUFC_MAG 0x00000002 /* Magic Packet Wakeup Enable */
+#define ATL1_WUFC_EX 0x00000004 /* Directed Exact Wakeup Enable */
+#define ATL1_WUFC_MC 0x00000008 /* Multicast Wakeup Enable */
+#define ATL1_WUFC_BC 0x00000010 /* Broadcast Wakeup Enable */
+
+/* Error Codes */
+#define ATL1_SUCCESS 0
+#define ATL1_ERR_EEPROM 1
+#define ATL1_ERR_PHY 2
+#define ATL1_ERR_CONFIG 3
+#define ATL1_ERR_PARAM 4
+#define ATL1_ERR_MAC_TYPE 5
+#define ATL1_ERR_PHY_TYPE 6
+#define ATL1_ERR_PHY_SPEED 7
+#define ATL1_ERR_PHY_RES 8
+
+#define SPEED_0 0xffff
+#define SPEED_10 10
+#define SPEED_100 100
+#define SPEED_1000 1000
+#define HALF_DUPLEX 1
+#define FULL_DUPLEX 2
+
+#define MEDIA_TYPE_AUTO_SENSOR 0
+#define MEDIA_TYPE_1000M_FULL 1
+#define MEDIA_TYPE_100M_FULL 2
+#define MEDIA_TYPE_100M_HALF 3
+#define MEDIA_TYPE_10M_FULL 4
+#define MEDIA_TYPE_10M_HALF 5
+
+#define ADVERTISE_10_HALF 0x0001
+#define ADVERTISE_10_FULL 0x0002
+#define ADVERTISE_100_HALF 0x0004
+#define ADVERTISE_100_FULL 0x0008
+#define ADVERTISE_1000_HALF 0x0010
+#define ADVERTISE_1000_FULL 0x0020
+#define AUTONEG_ADVERTISE_SPEED_DEFAULT 0x002F /* Everything but 1000-Half */
+#define AUTONEG_ADVERTISE_10_100_ALL 0x000F /* All 10/100 speeds */
+#define AUTONEG_ADVERTISE_10_ALL 0x0003 /* 10Mbps Full & Half speeds */
+
+/* The size (in bytes) of a ethernet packet */
+#define ENET_HEADER_SIZE 14
+#define MAXIMUM_ETHERNET_FRAME_SIZE 1518 /* with FCS */
+#define MINIMUM_ETHERNET_FRAME_SIZE 64 /* with FCS */
+#define ETHERNET_FCS_SIZE 4
+#define MAX_JUMBO_FRAME_SIZE 0x2800
+
+#define PHY_AUTO_NEG_TIME 45 /* 4.5 Seconds */
+#define PHY_FORCE_TIME 20 /* 2.0 Seconds */
+
+/* For checksumming , the sum of all words in the EEPROM should equal 0xBABA */
+#define EEPROM_SUM 0xBABA
+
+#define ATL1_EEDUMP_LEN 48
+
+/* Statistics counters collected by the MAC */
+struct stats_msg_block {
+ /* rx */
+ u32 rx_ok; /* The number of good packet received. */
+ u32 rx_bcast; /* The number of good broadcast packet received. */
+ u32 rx_mcast; /* The number of good multicast packet received. */
+ u32 rx_pause; /* The number of Pause packet received. */
+ u32 rx_ctrl; /* The number of Control packet received other than Pause frame. */
+ u32 rx_fcs_err; /* The number of packets with bad FCS. */
+ u32 rx_len_err; /* The number of packets with mismatch of length field and actual size. */
+ u32 rx_byte_cnt; /* The number of bytes of good packet received. FCS is NOT included. */
+ u32 rx_runt; /* The number of packets received that are less than 64 byte long and with good FCS. */
+ u32 rx_frag; /* The number of packets received that are less than 64 byte long and with bad FCS. */
+ u32 rx_sz_64; /* The number of good and bad packets received that are 64 byte long. */
+ u32 rx_sz_65_127; /* The number of good and bad packets received that are between 65 and 127-byte long. */
+ u32 rx_sz_128_255; /* The number of good and bad packets received that are between 128 and 255-byte long. */
+ u32 rx_sz_256_511; /* The number of good and bad packets received that are between 256 and 511-byte long. */
+ u32 rx_sz_512_1023; /* The number of good and bad packets received that are between 512 and 1023-byte long. */
+ u32 rx_sz_1024_1518; /* The number of good and bad packets received that are between 1024 and 1518-byte long. */
+ u32 rx_sz_1519_max; /* The number of good and bad packets received that are between 1519-byte and MTU. */
+ u32 rx_sz_ov; /* The number of good and bad packets received that are more than MTU size Å¡C truncated by Selene. */
+ u32 rx_rxf_ov; /* The number of frame dropped due to occurrence of RX FIFO overflow. */
+ u32 rx_rrd_ov; /* The number of frame dropped due to occurrence of RRD overflow. */
+ u32 rx_align_err; /* Alignment Error */
+ u32 rx_bcast_byte_cnt; /* The byte count of broadcast packet received, excluding FCS. */
+ u32 rx_mcast_byte_cnt; /* The byte count of multicast packet received, excluding FCS. */
+ u32 rx_err_addr; /* The number of packets dropped due to address filtering. */
+
+ /* tx */
+ u32 tx_ok; /* The number of good packet transmitted. */
+ u32 tx_bcast; /* The number of good broadcast packet transmitted. */
+ u32 tx_mcast; /* The number of good multicast packet transmitted. */
+ u32 tx_pause; /* The number of Pause packet transmitted. */
+ u32 tx_exc_defer; /* The number of packets transmitted with excessive deferral. */
+ u32 tx_ctrl; /* The number of packets transmitted is a control frame, excluding Pause frame. */
+ u32 tx_defer; /* The number of packets transmitted that is deferred. */
+ u32 tx_byte_cnt; /* The number of bytes of data transmitted. FCS is NOT included. */
+ u32 tx_sz_64; /* The number of good and bad packets transmitted that are 64 byte long. */
+ u32 tx_sz_65_127; /* The number of good and bad packets transmitted that are between 65 and 127-byte long. */
+ u32 tx_sz_128_255; /* The number of good and bad packets transmitted that are between 128 and 255-byte long. */
+ u32 tx_sz_256_511; /* The number of good and bad packets transmitted that are between 256 and 511-byte long. */
+ u32 tx_sz_512_1023; /* The number of good and bad packets transmitted that are between 512 and 1023-byte long. */
+ u32 tx_sz_1024_1518; /* The number of good and bad packets transmitted that are between 1024 and 1518-byte long. */
+ u32 tx_sz_1519_max; /* The number of good and bad packets transmitted that are between 1519-byte and MTU. */
+ u32 tx_1_col; /* The number of packets subsequently transmitted successfully with a single prior collision. */
+ u32 tx_2_col; /* The number of packets subsequently transmitted successfully with multiple prior collisions. */
+ u32 tx_late_col; /* The number of packets transmitted with late collisions. */
+ u32 tx_abort_col; /* The number of transmit packets aborted due to excessive collisions. */
+ u32 tx_underrun; /* The number of transmit packets aborted due to transmit FIFO underrun, or TRD FIFO underrun */
+ u32 tx_rd_eop; /* The number of times that read beyond the EOP into the next frame area when TRD was not written timely */
+ u32 tx_len_err; /* The number of transmit packets with length field does NOT match the actual frame size. */
+ u32 tx_trunc; /* The number of transmit packets truncated due to size exceeding MTU. */
+ u32 tx_bcast_byte; /* The byte count of broadcast packet transmitted, excluding FCS. */
+ u32 tx_mcast_byte; /* The byte count of multicast packet transmitted, excluding FCS. */
+ u32 smb_updated; /* 1: SMB Updated. This is used by software as the indication of the statistics update.
+ * Software should clear this bit as soon as retrieving the statistics information. */
+};
+
+/* Coalescing Message Block */
+struct coals_msg_block {
+ u32 int_stats; /* interrupt status */
+ u16 rrd_prod_idx; /* TRD Producer Index. */
+ u16 rfd_cons_idx; /* RFD Consumer Index. */
+ u16 update; /* Selene sets this bit every time it DMA the CMB to host memory.
+ * Software supposes to clear this bit when CMB information is processed. */
+ u16 tpd_cons_idx; /* TPD Consumer Index. */
+};
+
+/* RRD descriptor */
+struct rx_return_desc {
+ u8 num_buf; /* Number of RFD buffers used by the received packet */
+ u8 resved;
+ u16 buf_indx; /* RFD Index of the first buffer */
+ union {
+ u32 valid;
+ struct {
+ u16 rx_chksum;
+ u16 pkt_size;
+ } xsum_sz;
+ } xsz;
+
+ u16 pkt_flg; /* Packet flags */
+ u16 err_flg; /* Error flags */
+ u16 resved2;
+ u16 vlan_tag; /* VLAN TAG */
+};
+
+#define PACKET_FLAG_ETH_TYPE 0x0080
+#define PACKET_FLAG_VLAN_INS 0x0100
+#define PACKET_FLAG_ERR 0x0200
+#define PACKET_FLAG_IPV4 0x0400
+#define PACKET_FLAG_UDP 0x0800
+#define PACKET_FLAG_TCP 0x1000
+#define PACKET_FLAG_BCAST 0x2000
+#define PACKET_FLAG_MCAST 0x4000
+#define PACKET_FLAG_PAUSE 0x8000
+
+#define ERR_FLAG_CRC 0x0001
+#define ERR_FLAG_CODE 0x0002
+#define ERR_FLAG_DRIBBLE 0x0004
+#define ERR_FLAG_RUNT 0x0008
+#define ERR_FLAG_OV 0x0010
+#define ERR_FLAG_TRUNC 0x0020
+#define ERR_FLAG_IP_CHKSUM 0x0040
+#define ERR_FLAG_L4_CHKSUM 0x0080
+#define ERR_FLAG_LEN 0x0100
+#define ERR_FLAG_DES_ADDR 0x0200
+
+/* RFD descriptor */
+struct rx_free_desc {
+ __le64 buffer_addr; /* Address of the descriptor's data buffer */
+ __le16 buf_len; /* Size of the receive buffer in host memory, in byte */
+ u16 coalese; /* Update consumer index to host after the reception of this frame */
+ /* __attribute__ ((packed)) is required */
+} __attribute__ ((packed));
+
+/* tsopu defines */
+#define TSO_PARAM_BUFLEN_MASK 0x3FFF
+#define TSO_PARAM_BUFLEN_SHIFT 0
+#define TSO_PARAM_DMAINT_MASK 0x0001
+#define TSO_PARAM_DMAINT_SHIFT 14
+#define TSO_PARAM_PKTNT_MASK 0x0001
+#define TSO_PARAM_PKTINT_SHIFT 15
+#define TSO_PARAM_VLANTAG_MASK 0xFFFF
+#define TSO_PARAM_VLAN_SHIFT 16
+
+/* tsopl defines */
+#define TSO_PARAM_EOP_MASK 0x0001
+#define TSO_PARAM_EOP_SHIFT 0
+#define TSO_PARAM_COALESCE_MASK 0x0001
+#define TSO_PARAM_COALESCE_SHIFT 1
+#define TSO_PARAM_INSVLAG_MASK 0x0001
+#define TSO_PARAM_INSVLAG_SHIFT 2
+#define TSO_PARAM_CUSTOMCKSUM_MASK 0x0001
+#define TSO_PARAM_CUSTOMCKSUM_SHIFT 3
+#define TSO_PARAM_SEGMENT_MASK 0x0001
+#define TSO_PARAM_SEGMENT_SHIFT 4
+#define TSO_PARAM_IPCKSUM_MASK 0x0001
+#define TSO_PARAM_IPCKSUM_SHIFT 5
+#define TSO_PARAM_TCPCKSUM_MASK 0x0001
+#define TSO_PARAM_TCPCKSUM_SHIFT 6
+#define TSO_PARAM_UDPCKSUM_MASK 0x0001
+#define TSO_PARAM_UDPCKSUM_SHIFT 7
+#define TSO_PARAM_VLANTAGGED_MASK 0x0001
+#define TSO_PARAM_VLANTAGGED_SHIFT 8
+#define TSO_PARAM_ETHTYPE_MASK 0x0001
+#define TSO_PARAM_ETHTYPE_SHIFT 9
+#define TSO_PARAM_IPHL_MASK 0x000F
+#define TSO_PARAM_IPHL_SHIFT 10
+#define TSO_PARAM_TCPHDRLEN_MASK 0x000F
+#define TSO_PARAM_TCPHDRLEN_SHIFT 14
+#define TSO_PARAM_HDRFLAG_MASK 0x0001
+#define TSO_PARAM_HDRFLAG_SHIFT 18
+#define TSO_PARAM_MSS_MASK 0x1FFF
+#define TSO_PARAM_MSS_SHIFT 19
+
+/* csumpu defines */
+#define CSUM_PARAM_BUFLEN_MASK 0x3FFF
+#define CSUM_PARAM_BUFLEN_SHIFT 0
+#define CSUM_PARAM_DMAINT_MASK 0x0001
+#define CSUM_PARAM_DMAINT_SHIFT 14
+#define CSUM_PARAM_PKTINT_MASK 0x0001
+#define CSUM_PARAM_PKTINT_SHIFT 15
+#define CSUM_PARAM_VALANTAG_MASK 0xFFFF
+#define CSUM_PARAM_VALAN_SHIFT 16
+
+/* csumpl defines*/
+#define CSUM_PARAM_EOP_MASK 0x0001
+#define CSUM_PARAM_EOP_SHIFT 0
+#define CSUM_PARAM_COALESCE_MASK 0x0001
+#define CSUM_PARAM_COALESCE_SHIFT 1
+#define CSUM_PARAM_INSVLAG_MASK 0x0001
+#define CSUM_PARAM_INSVLAG_SHIFT 2
+#define CSUM_PARAM_CUSTOMCKSUM_MASK 0x0001
+#define CSUM_PARAM_CUSTOMCKSUM_SHIFT 3
+#define CSUM_PARAM_SEGMENT_MASK 0x0001
+#define CSUM_PARAM_SEGMENT_SHIFT 4
+#define CSUM_PARAM_IPCKSUM_MASK 0x0001
+#define CSUM_PARAM_IPCKSUM_SHIFT 5
+#define CSUM_PARAM_TCPCKSUM_MASK 0x0001
+#define CSUM_PARAM_TCPCKSUM_SHIFT 6
+#define CSUM_PARAM_UDPCKSUM_MASK 0x0001
+#define CSUM_PARAM_UDPCKSUM_SHIFT 7
+#define CSUM_PARAM_VLANTAGGED_MASK 0x0001
+#define CSUM_PARAM_VLANTAGGED_SHIFT 8
+#define CSUM_PARAM_ETHTYPE_MASK 0x0001
+#define CSUM_PARAM_ETHTYPE_SHIFT 9
+#define CSUM_PARAM_IPHL_MASK 0x000F
+#define CSUM_PARAM_IPHL_SHIFT 10
+#define CSUM_PARAM_PLOADOFFSET_MASK 0x00FF
+#define CSUM_PARAM_PLOADOFFSET_SHIFT 16
+#define CSUM_PARAM_XSUMOFFSET_MASK 0x00FF
+#define CSUM_PARAM_XSUMOFFSET_SHIFT 24
+
+/* TPD descriptor */
+struct tso_param {
+ /* The order of these declarations is important -- don't change it */
+ u32 tsopu; /* tso_param upper word */
+ u32 tsopl; /* tso_param lower word */
+};
+
+struct csum_param {
+ /* The order of these declarations is important -- don't change it */
+ u32 csumpu; /* csum_param upper word */
+ u32 csumpl; /* csum_param lower word */
+};
+
+union tpd_descr {
+ u64 data;
+ struct csum_param csum;
+ struct tso_param tso;
+};
+
+struct tx_packet_desc {
+ __le64 buffer_addr;
+ union tpd_descr desc;
+};
+
+/* DMA Order Settings */
+enum atl1_dma_order {
+ atl1_dma_ord_in = 1,
+ atl1_dma_ord_enh = 2,
+ atl1_dma_ord_out = 4
+};
+
+enum atl1_dma_rcb {
+ atl1_rcb_64 = 0,
+ atl1_rcb_128 = 1
+};
+
+enum atl1_dma_req_block {
+ atl1_dma_req_128 = 0,
+ atl1_dma_req_256 = 1,
+ atl1_dma_req_512 = 2,
+ atl1_dam_req_1024 = 3,
+ atl1_dam_req_2048 = 4,
+ atl1_dma_req_4096 = 5
+};
+
+struct atl1_spi_flash_dev {
+ const char *manu_name; /* manufacturer id */
+ /* op-code */
+ u8 cmd_wrsr;
+ u8 cmd_read;
+ u8 cmd_program;
+ u8 cmd_wren;
+ u8 cmd_wrdi;
+ u8 cmd_rdsr;
+ u8 cmd_rdid;
+ u8 cmd_sector_erase;
+ u8 cmd_chip_erase;
+};
+
+#endif /* _ATL1_HW_H_ */
diff --git a/drivers/net/atl1/atl1_main.c b/drivers/net/atl1/atl1_main.c
new file mode 100644
index 00000000000..65673485bb6
--- /dev/null
+++ b/drivers/net/atl1/atl1_main.c
@@ -0,0 +1,2467 @@
+/*
+ * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved.
+ * Copyright(c) 2006 Chris Snook <csnook@redhat.com>
+ * Copyright(c) 2006 Jay Cliburn <jcliburn@gmail.com>
+ *
+ * Derived from Intel e1000 driver
+ * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called COPYING.
+ *
+ * Contact Information:
+ * Xiong Huang <xiong_huang@attansic.com>
+ * Attansic Technology Corp. 3F 147, Xianzheng 9th Road, Zhubei,
+ * Xinzhu 302, TAIWAN, REPUBLIC OF CHINA
+ *
+ * Chris Snook <csnook@redhat.com>
+ * Jay Cliburn <jcliburn@gmail.com>
+ *
+ * This version is adapted from the Attansic reference driver for
+ * inclusion in the Linux kernel. It is currently under heavy development.
+ * A very incomplete list of things that need to be dealt with:
+ *
+ * TODO:
+ * Fix TSO; tx performance is horrible with TSO enabled.
+ * Wake on LAN.
+ * Add more ethtool functions, including set ring parameters.
+ * Fix abstruse irq enable/disable condition described here:
+ * http://marc.theaimsgroup.com/?l=linux-netdev&m=116398508500553&w=2
+ *
+ * NEEDS TESTING:
+ * VLAN
+ * multicast
+ * promiscuous mode
+ * interrupt coalescing
+ * SMP torture testing
+ */
+
+#include <linux/types.h>
+#include <linux/netdevice.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/skbuff.h>
+#include <linux/etherdevice.h>
+#include <linux/if_vlan.h>
+#include <linux/irqreturn.h>
+#include <linux/workqueue.h>
+#include <linux/timer.h>
+#include <linux/jiffies.h>
+#include <linux/hardirq.h>
+#include <linux/interrupt.h>
+#include <linux/irqflags.h>
+#include <linux/dma-mapping.h>
+#include <linux/net.h>
+#include <linux/pm.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/compiler.h>
+#include <linux/delay.h>
+#include <linux/mii.h>
+#include <net/checksum.h>
+
+#include <asm/atomic.h>
+#include <asm/byteorder.h>
+
+#include "atl1.h"
+
+#define DRIVER_VERSION "2.0.7"
+
+char atl1_driver_name[] = "atl1";
+static const char atl1_driver_string[] = "Attansic L1 Ethernet Network Driver";
+static const char atl1_copyright[] = "Copyright(c) 2005-2006 Attansic Corporation.";
+char atl1_driver_version[] = DRIVER_VERSION;
+
+MODULE_AUTHOR
+ ("Attansic Corporation <xiong_huang@attansic.com>, Chris Snook <csnook@redhat.com>, Jay Cliburn <jcliburn@gmail.com>");
+MODULE_DESCRIPTION("Attansic 1000M Ethernet Network Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRIVER_VERSION);
+
+/*
+ * atl1_pci_tbl - PCI Device ID Table
+ */
+static const struct pci_device_id atl1_pci_tbl[] = {
+ {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATTANSIC_L1)},
+ /* required last entry */
+ {0,}
+};
+
+MODULE_DEVICE_TABLE(pci, atl1_pci_tbl);
+
+/*
+ * atl1_sw_init - Initialize general software structures (struct atl1_adapter)
+ * @adapter: board private structure to initialize
+ *
+ * atl1_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 atl1_sw_init(struct atl1_adapter *adapter)
+{
+ struct atl1_hw *hw = &adapter->hw;
+ struct net_device *netdev = adapter->netdev;
+ struct pci_dev *pdev = adapter->pdev;
+
+ /* PCI config space info */
+ pci_read_config_byte(pdev, PCI_REVISION_ID, &hw->revision_id);
+
+ hw->max_frame_size = netdev->mtu + ENET_HEADER_SIZE + ETHERNET_FCS_SIZE;
+ hw->min_frame_size = MINIMUM_ETHERNET_FRAME_SIZE;
+
+ adapter->wol = 0;
+ adapter->rx_buffer_len = (hw->max_frame_size + 7) & ~7;
+ adapter->ict = 50000; /* 100ms */
+ adapter->link_speed = SPEED_0; /* hardware init */
+ adapter->link_duplex = FULL_DUPLEX;
+
+ hw->phy_configured = false;
+ hw->preamble_len = 7;
+ hw->ipgt = 0x60;
+ hw->min_ifg = 0x50;
+ hw->ipgr1 = 0x40;
+ hw->ipgr2 = 0x60;
+ hw->max_retry = 0xf;
+ hw->lcol = 0x37;
+ hw->jam_ipg = 7;
+ hw->rfd_burst = 8;
+ hw->rrd_burst = 8;
+ hw->rfd_fetch_gap = 1;
+ hw->rx_jumbo_th = adapter->rx_buffer_len / 8;
+ hw->rx_jumbo_lkah = 1;
+ hw->rrd_ret_timer = 16;
+ hw->tpd_burst = 4;
+ hw->tpd_fetch_th = 16;
+ hw->txf_burst = 0x100;
+ hw->tx_jumbo_task_th = (hw->max_frame_size + 7) >> 3;
+ hw->tpd_fetch_gap = 1;
+ hw->rcb_value = atl1_rcb_64;
+ hw->dma_ord = atl1_dma_ord_enh;
+ hw->dmar_block = atl1_dma_req_256;
+ hw->dmaw_block = atl1_dma_req_256;
+ hw->cmb_rrd = 4;
+ hw->cmb_tpd = 4;
+ hw->cmb_rx_timer = 1; /* about 2us */
+ hw->cmb_tx_timer = 1; /* about 2us */
+ hw->smb_timer = 100000; /* about 200ms */
+
+ atomic_set(&adapter->irq_sem, 0);
+ spin_lock_init(&adapter->lock);
+ spin_lock_init(&adapter->mb_lock);
+
+ return 0;
+}
+
+/*
+ * atl1_setup_mem_resources - allocate Tx / RX descriptor resources
+ * @adapter: board private structure
+ *
+ * Return 0 on success, negative on failure
+ */
+s32 atl1_setup_ring_resources(struct atl1_adapter *adapter)
+{
+ struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring;
+ struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring;
+ struct atl1_rrd_ring *rrd_ring = &adapter->rrd_ring;
+ struct atl1_ring_header *ring_header = &adapter->ring_header;
+ struct pci_dev *pdev = adapter->pdev;
+ int size;
+ u8 offset = 0;
+
+ size = sizeof(struct atl1_buffer) * (tpd_ring->count + rfd_ring->count);
+ tpd_ring->buffer_info = kzalloc(size, GFP_KERNEL);
+ if (unlikely(!tpd_ring->buffer_info)) {
+ printk(KERN_WARNING "%s: kzalloc failed , size = D%d\n",
+ atl1_driver_name, size);
+ goto err_nomem;
+ }
+ rfd_ring->buffer_info =
+ (struct atl1_buffer *)(tpd_ring->buffer_info + tpd_ring->count);
+
+ /* real ring DMA buffer */
+ ring_header->size = size = sizeof(struct tx_packet_desc) *
+ tpd_ring->count
+ + sizeof(struct rx_free_desc) * rfd_ring->count
+ + sizeof(struct rx_return_desc) * rrd_ring->count
+ + sizeof(struct coals_msg_block)
+ + sizeof(struct stats_msg_block)
+ + 40; /* "40: for 8 bytes align" huh? -- CHS */
+
+ ring_header->desc = pci_alloc_consistent(pdev, ring_header->size,
+ &ring_header->dma);
+ if (unlikely(!ring_header->desc)) {
+ printk(KERN_WARNING
+ "%s: pci_alloc_consistent failed, size = D%d\n",
+ atl1_driver_name, size);
+ goto err_nomem;
+ }
+
+ memset(ring_header->desc, 0, ring_header->size);
+
+ /* init TPD ring */
+ tpd_ring->dma = ring_header->dma;
+ offset = (tpd_ring->dma & 0x7) ? (8 - (ring_header->dma & 0x7)) : 0;
+ tpd_ring->dma += offset;
+ tpd_ring->desc = (u8 *) ring_header->desc + offset;
+ tpd_ring->size = sizeof(struct tx_packet_desc) * tpd_ring->count;
+ atomic_set(&tpd_ring->next_to_use, 0);
+ atomic_set(&tpd_ring->next_to_clean, 0);
+
+ /* init RFD ring */
+ rfd_ring->dma = tpd_ring->dma + tpd_ring->size;
+ offset = (rfd_ring->dma & 0x7) ? (8 - (rfd_ring->dma & 0x7)) : 0;
+ rfd_ring->dma += offset;
+ rfd_ring->desc = (u8 *) tpd_ring->desc + (tpd_ring->size + offset);
+ rfd_ring->size = sizeof(struct rx_free_desc) * rfd_ring->count;
+ rfd_ring->next_to_clean = 0;
+ /* rfd_ring->next_to_use = rfd_ring->count - 1; */
+ atomic_set(&rfd_ring->next_to_use, 0);
+
+ /* init RRD ring */
+ rrd_ring->dma = rfd_ring->dma + rfd_ring->size;
+ offset = (rrd_ring->dma & 0x7) ? (8 - (rrd_ring->dma & 0x7)) : 0;
+ rrd_ring->dma += offset;
+ rrd_ring->desc = (u8 *) rfd_ring->desc + (rfd_ring->size + offset);
+ rrd_ring->size = sizeof(struct rx_return_desc) * rrd_ring->count;
+ rrd_ring->next_to_use = 0;
+ atomic_set(&rrd_ring->next_to_clean, 0);
+
+ /* init CMB */
+ adapter->cmb.dma = rrd_ring->dma + rrd_ring->size;
+ offset = (adapter->cmb.dma & 0x7) ? (8 - (adapter->cmb.dma & 0x7)) : 0;
+ adapter->cmb.dma += offset;
+ adapter->cmb.cmb =
+ (struct coals_msg_block *) ((u8 *) rrd_ring->desc +
+ (rrd_ring->size + offset));
+
+ /* init SMB */
+ adapter->smb.dma = adapter->cmb.dma + sizeof(struct coals_msg_block);
+ offset = (adapter->smb.dma & 0x7) ? (8 - (adapter->smb.dma & 0x7)) : 0;
+ adapter->smb.dma += offset;
+ adapter->smb.smb = (struct stats_msg_block *)
+ ((u8 *) adapter->cmb.cmb + (sizeof(struct coals_msg_block) + offset));
+
+ return ATL1_SUCCESS;
+
+err_nomem:
+ kfree(tpd_ring->buffer_info);
+ return -ENOMEM;
+}
+
+/*
+ * atl1_irq_enable - Enable default interrupt generation settings
+ * @adapter: board private structure
+ */
+static void atl1_irq_enable(struct atl1_adapter *adapter)
+{
+ if (likely(!atomic_dec_and_test(&adapter->irq_sem)))
+ iowrite32(IMR_NORMAL_MASK, adapter->hw.hw_addr + REG_IMR);
+}
+
+static void atl1_clear_phy_int(struct atl1_adapter *adapter)
+{
+ u16 phy_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&adapter->lock, flags);
+ atl1_read_phy_reg(&adapter->hw, 19, &phy_data);
+ spin_unlock_irqrestore(&adapter->lock, flags);
+}
+
+static void atl1_inc_smb(struct atl1_adapter *adapter)
+{
+ struct stats_msg_block *smb = adapter->smb.smb;
+
+ /* Fill out the OS statistics structure */
+ adapter->soft_stats.rx_packets += smb->rx_ok;
+ adapter->soft_stats.tx_packets += smb->tx_ok;
+ adapter->soft_stats.rx_bytes += smb->rx_byte_cnt;
+ adapter->soft_stats.tx_bytes += smb->tx_byte_cnt;
+ adapter->soft_stats.multicast += smb->rx_mcast;
+ adapter->soft_stats.collisions += (smb->tx_1_col +
+ smb->tx_2_col * 2 +
+ smb->tx_late_col +
+ smb->tx_abort_col *
+ adapter->hw.max_retry);
+
+ /* Rx Errors */
+ adapter->soft_stats.rx_errors += (smb->rx_frag +
+ smb->rx_fcs_err +
+ smb->rx_len_err +
+ smb->rx_sz_ov +
+ smb->rx_rxf_ov +
+ smb->rx_rrd_ov + smb->rx_align_err);
+ adapter->soft_stats.rx_fifo_errors += smb->rx_rxf_ov;
+ adapter->soft_stats.rx_length_errors += smb->rx_len_err;
+ adapter->soft_stats.rx_crc_errors += smb->rx_fcs_err;
+ adapter->soft_stats.rx_frame_errors += smb->rx_align_err;
+ adapter->soft_stats.rx_missed_errors += (smb->rx_rrd_ov +
+ smb->rx_rxf_ov);
+
+ adapter->soft_stats.rx_pause += smb->rx_pause;
+ adapter->soft_stats.rx_rrd_ov += smb->rx_rrd_ov;
+ adapter->soft_stats.rx_trunc += smb->rx_sz_ov;
+
+ /* Tx Errors */
+ adapter->soft_stats.tx_errors += (smb->tx_late_col +
+ smb->tx_abort_col +
+ smb->tx_underrun + smb->tx_trunc);
+ adapter->soft_stats.tx_fifo_errors += smb->tx_underrun;
+ adapter->soft_stats.tx_aborted_errors += smb->tx_abort_col;
+ adapter->soft_stats.tx_window_errors += smb->tx_late_col;
+
+ adapter->soft_stats.excecol += smb->tx_abort_col;
+ adapter->soft_stats.deffer += smb->tx_defer;
+ adapter->soft_stats.scc += smb->tx_1_col;
+ adapter->soft_stats.mcc += smb->tx_2_col;
+ adapter->soft_stats.latecol += smb->tx_late_col;
+ adapter->soft_stats.tx_underun += smb->tx_underrun;
+ adapter->soft_stats.tx_trunc += smb->tx_trunc;
+ adapter->soft_stats.tx_pause += smb->tx_pause;
+
+ adapter->net_stats.rx_packets = adapter->soft_stats.rx_packets;
+ adapter->net_stats.tx_packets = adapter->soft_stats.tx_packets;
+ adapter->net_stats.rx_bytes = adapter->soft_stats.rx_bytes;
+ adapter->net_stats.tx_bytes = adapter->soft_stats.tx_bytes;
+ adapter->net_stats.multicast = adapter->soft_stats.multicast;
+ adapter->net_stats.collisions = adapter->soft_stats.collisions;
+ adapter->net_stats.rx_errors = adapter->soft_stats.rx_errors;
+ adapter->net_stats.rx_over_errors =
+ adapter->soft_stats.rx_missed_errors;
+ adapter->net_stats.rx_length_errors =
+ adapter->soft_stats.rx_length_errors;
+ adapter->net_stats.rx_crc_errors = adapter->soft_stats.rx_crc_errors;
+ adapter->net_stats.rx_frame_errors =
+ adapter->soft_stats.rx_frame_errors;
+ adapter->net_stats.rx_fifo_errors = adapter->soft_stats.rx_fifo_errors;
+ adapter->net_stats.rx_missed_errors =
+ adapter->soft_stats.rx_missed_errors;
+ adapter->net_stats.tx_errors = adapter->soft_stats.tx_errors;
+ adapter->net_stats.tx_fifo_errors = adapter->soft_stats.tx_fifo_errors;
+ adapter->net_stats.tx_aborted_errors =
+ adapter->soft_stats.tx_aborted_errors;
+ adapter->net_stats.tx_window_errors =
+ adapter->soft_stats.tx_window_errors;
+ adapter->net_stats.tx_carrier_errors =
+ adapter->soft_stats.tx_carrier_errors;
+}
+
+static void atl1_rx_checksum(struct atl1_adapter *adapter,
+ struct rx_return_desc *rrd,
+ struct sk_buff *skb)
+{
+ skb->ip_summed = CHECKSUM_NONE;
+
+ if (unlikely(rrd->pkt_flg & PACKET_FLAG_ERR)) {
+ if (rrd->err_flg & (ERR_FLAG_CRC | ERR_FLAG_TRUNC |
+ ERR_FLAG_CODE | ERR_FLAG_OV)) {
+ adapter->hw_csum_err++;
+ printk(KERN_DEBUG "%s: rx checksum error\n",
+ atl1_driver_name);
+ return;
+ }
+ }
+
+ /* not IPv4 */
+ if (!(rrd->pkt_flg & PACKET_FLAG_IPV4))
+ /* checksum is invalid, but it's not an IPv4 pkt, so ok */
+ return;
+
+ /* IPv4 packet */
+ if (likely(!(rrd->err_flg &
+ (ERR_FLAG_IP_CHKSUM | ERR_FLAG_L4_CHKSUM)))) {
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ adapter->hw_csum_good++;
+ return;
+ }
+
+ /* IPv4, but hardware thinks its checksum is wrong */
+ printk(KERN_DEBUG "%s: hw csum wrong pkt_flag:%x, err_flag:%x\n",
+ atl1_driver_name, rrd->pkt_flg, rrd->err_flg);
+ skb->ip_summed = CHECKSUM_COMPLETE;
+ skb->csum = htons(rrd->xsz.xsum_sz.rx_chksum);
+ adapter->hw_csum_err++;
+ return;
+}
+
+/*
+ * atl1_alloc_rx_buffers - Replace used receive buffers
+ * @adapter: address of board private structure
+ */
+static u16 atl1_alloc_rx_buffers(struct atl1_adapter *adapter)
+{
+ struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring;
+ struct net_device *netdev = adapter->netdev;
+ struct pci_dev *pdev = adapter->pdev;
+ struct page *page;
+ unsigned long offset;
+ struct atl1_buffer *buffer_info, *next_info;
+ struct sk_buff *skb;
+ u16 num_alloc = 0;
+ u16 rfd_next_to_use, next_next;
+ struct rx_free_desc *rfd_desc;
+
+ next_next = rfd_next_to_use = atomic_read(&rfd_ring->next_to_use);
+ if (++next_next == rfd_ring->count)
+ next_next = 0;
+ buffer_info = &rfd_ring->buffer_info[rfd_next_to_use];
+ next_info = &rfd_ring->buffer_info[next_next];
+
+ while (!buffer_info->alloced && !next_info->alloced) {
+ if (buffer_info->skb) {
+ buffer_info->alloced = 1;
+ goto next;
+ }
+
+ rfd_desc = ATL1_RFD_DESC(rfd_ring, rfd_next_to_use);
+
+ skb = dev_alloc_skb(adapter->rx_buffer_len + NET_IP_ALIGN);
+ if (unlikely(!skb)) { /* Better luck next round */
+ adapter->net_stats.rx_dropped++;
+ break;
+ }
+
+ /*
+ * 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);
+ skb->dev = netdev;
+
+ buffer_info->alloced = 1;
+ buffer_info->skb = skb;
+ buffer_info->length = (u16) adapter->rx_buffer_len;
+ page = virt_to_page(skb->data);
+ offset = (unsigned long)skb->data & ~PAGE_MASK;
+ buffer_info->dma = pci_map_page(pdev, page, offset,
+ adapter->rx_buffer_len,
+ PCI_DMA_FROMDEVICE);
+ rfd_desc->buffer_addr = cpu_to_le64(buffer_info->dma);
+ rfd_desc->buf_len = cpu_to_le16(adapter->rx_buffer_len);
+ rfd_desc->coalese = 0;
+
+next:
+ rfd_next_to_use = next_next;
+ if (unlikely(++next_next == rfd_ring->count))
+ next_next = 0;
+
+ buffer_info = &rfd_ring->buffer_info[rfd_next_to_use];
+ next_info = &rfd_ring->buffer_info[next_next];
+ num_alloc++;
+ }
+
+ if (num_alloc) {
+ /*
+ * 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();
+ atomic_set(&rfd_ring->next_to_use, (int)rfd_next_to_use);
+ }
+ return num_alloc;
+}
+
+static void atl1_intr_rx(struct atl1_adapter *adapter)
+{
+ int i, count;
+ u16 length;
+ u16 rrd_next_to_clean;
+ u32 value;
+ struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring;
+ struct atl1_rrd_ring *rrd_ring = &adapter->rrd_ring;
+ struct atl1_buffer *buffer_info;
+ struct rx_return_desc *rrd;
+ struct sk_buff *skb;
+
+ count = 0;
+
+ rrd_next_to_clean = atomic_read(&rrd_ring->next_to_clean);
+
+ while (1) {
+ rrd = ATL1_RRD_DESC(rrd_ring, rrd_next_to_clean);
+ i = 1;
+ if (likely(rrd->xsz.valid)) { /* packet valid */
+chk_rrd:
+ /* check rrd status */
+ if (likely(rrd->num_buf == 1))
+ goto rrd_ok;
+
+ /* rrd seems to be bad */
+ if (unlikely(i-- > 0)) {
+ /* rrd may not be DMAed completely */
+ printk(KERN_DEBUG
+ "%s: RRD may not be DMAed completely\n",
+ atl1_driver_name);
+ udelay(1);
+ goto chk_rrd;
+ }
+ /* bad rrd */
+ printk(KERN_DEBUG "%s: bad RRD\n", atl1_driver_name);
+ /* see if update RFD index */
+ if (rrd->num_buf > 1) {
+ u16 num_buf;
+ num_buf =
+ (rrd->xsz.xsum_sz.pkt_size +
+ adapter->rx_buffer_len -
+ 1) / adapter->rx_buffer_len;
+ if (rrd->num_buf == num_buf) {
+ /* clean alloc flag for bad rrd */
+ while (rfd_ring->next_to_clean !=
+ (rrd->buf_indx + num_buf)) {
+ rfd_ring->buffer_info[rfd_ring->
+ next_to_clean].alloced = 0;
+ if (++rfd_ring->next_to_clean ==
+ rfd_ring->count) {
+ rfd_ring->
+ next_to_clean = 0;
+ }
+ }
+ }
+ }
+
+ /* update rrd */
+ rrd->xsz.valid = 0;
+ if (++rrd_next_to_clean == rrd_ring->count)
+ rrd_next_to_clean = 0;
+ count++;
+ continue;
+ } else { /* current rrd still not be updated */
+
+ break;
+ }
+rrd_ok:
+ /* clean alloc flag for bad rrd */
+ while (rfd_ring->next_to_clean != rrd->buf_indx) {
+ rfd_ring->buffer_info[rfd_ring->next_to_clean].alloced =
+ 0;
+ if (++rfd_ring->next_to_clean == rfd_ring->count)
+ rfd_ring->next_to_clean = 0;
+ }
+
+ buffer_info = &rfd_ring->buffer_info[rrd->buf_indx];
+ if (++rfd_ring->next_to_clean == rfd_ring->count)
+ rfd_ring->next_to_clean = 0;
+
+ /* update rrd next to clean */
+ if (++rrd_next_to_clean == rrd_ring->count)
+ rrd_next_to_clean = 0;
+ count++;
+
+ if (unlikely(rrd->pkt_flg & PACKET_FLAG_ERR)) {
+ if (!(rrd->err_flg &
+ (ERR_FLAG_IP_CHKSUM | ERR_FLAG_L4_CHKSUM
+ | ERR_FLAG_LEN))) {
+ /* packet error, don't need upstream */
+ buffer_info->alloced = 0;
+ rrd->xsz.valid = 0;
+ continue;
+ }
+ }
+
+ /* Good Receive */
+ pci_unmap_page(adapter->pdev, buffer_info->dma,
+ buffer_info->length, PCI_DMA_FROMDEVICE);
+ skb = buffer_info->skb;
+ length = le16_to_cpu(rrd->xsz.xsum_sz.pkt_size);
+
+ skb_put(skb, length - ETHERNET_FCS_SIZE);
+
+ /* Receive Checksum Offload */
+ atl1_rx_checksum(adapter, rrd, skb);
+ skb->protocol = eth_type_trans(skb, adapter->netdev);
+
+ if (adapter->vlgrp && (rrd->pkt_flg & PACKET_FLAG_VLAN_INS)) {
+ u16 vlan_tag = (rrd->vlan_tag >> 4) |
+ ((rrd->vlan_tag & 7) << 13) |
+ ((rrd->vlan_tag & 8) << 9);
+ vlan_hwaccel_rx(skb, adapter->vlgrp, vlan_tag);
+ } else
+ netif_rx(skb);
+
+ /* let protocol layer free skb */
+ buffer_info->skb = NULL;
+ buffer_info->alloced = 0;
+ rrd->xsz.valid = 0;
+
+ adapter->netdev->last_rx = jiffies;
+ }
+
+ atomic_set(&rrd_ring->next_to_clean, rrd_next_to_clean);
+
+ atl1_alloc_rx_buffers(adapter);
+
+ /* update mailbox ? */
+ if (count) {
+ u32 tpd_next_to_use;
+ u32 rfd_next_to_use;
+ u32 rrd_next_to_clean;
+
+ spin_lock(&adapter->mb_lock);
+
+ tpd_next_to_use = atomic_read(&adapter->tpd_ring.next_to_use);
+ rfd_next_to_use =
+ atomic_read(&adapter->rfd_ring.next_to_use);
+ rrd_next_to_clean =
+ atomic_read(&adapter->rrd_ring.next_to_clean);
+ value = ((rfd_next_to_use & MB_RFD_PROD_INDX_MASK) <<
+ MB_RFD_PROD_INDX_SHIFT) |
+ ((rrd_next_to_clean & MB_RRD_CONS_INDX_MASK) <<
+ MB_RRD_CONS_INDX_SHIFT) |
+ ((tpd_next_to_use & MB_TPD_PROD_INDX_MASK) <<
+ MB_TPD_PROD_INDX_SHIFT);
+ iowrite32(value, adapter->hw.hw_addr + REG_MAILBOX);
+ spin_unlock(&adapter->mb_lock);
+ }
+}
+
+static void atl1_intr_tx(struct atl1_adapter *adapter)
+{
+ struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring;
+ struct atl1_buffer *buffer_info;
+ u16 sw_tpd_next_to_clean;
+ u16 cmb_tpd_next_to_clean;
+ u8 update = 0;
+
+ sw_tpd_next_to_clean = atomic_read(&tpd_ring->next_to_clean);
+ cmb_tpd_next_to_clean = le16_to_cpu(adapter->cmb.cmb->tpd_cons_idx);
+
+ while (cmb_tpd_next_to_clean != sw_tpd_next_to_clean) {
+ struct tx_packet_desc *tpd;
+ update = 1;
+ tpd = ATL1_TPD_DESC(tpd_ring, sw_tpd_next_to_clean);
+ buffer_info = &tpd_ring->buffer_info[sw_tpd_next_to_clean];
+ if (buffer_info->dma) {
+ pci_unmap_page(adapter->pdev, buffer_info->dma,
+ buffer_info->length, PCI_DMA_TODEVICE);
+ buffer_info->dma = 0;
+ }
+
+ if (buffer_info->skb) {
+ dev_kfree_skb_irq(buffer_info->skb);
+ buffer_info->skb = NULL;
+ }
+ tpd->buffer_addr = 0;
+ tpd->desc.data = 0;
+
+ if (++sw_tpd_next_to_clean == tpd_ring->count)
+ sw_tpd_next_to_clean = 0;
+ }
+ atomic_set(&tpd_ring->next_to_clean, sw_tpd_next_to_clean);
+
+ if (netif_queue_stopped(adapter->netdev)
+ && netif_carrier_ok(adapter->netdev))
+ netif_wake_queue(adapter->netdev);
+}
+
+static void atl1_check_for_link(struct atl1_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+ u16 phy_data = 0;
+
+ spin_lock(&adapter->lock);
+ adapter->phy_timer_pending = false;
+ atl1_read_phy_reg(&adapter->hw, MII_BMSR, &phy_data);
+ atl1_read_phy_reg(&adapter->hw, MII_BMSR, &phy_data);
+ spin_unlock(&adapter->lock);
+
+ /* notify upper layer link down ASAP */
+ if (!(phy_data & BMSR_LSTATUS)) { /* Link Down */
+ if (netif_carrier_ok(netdev)) { /* old link state: Up */
+ printk(KERN_INFO "%s: %s link is down\n",
+ atl1_driver_name, netdev->name);
+ adapter->link_speed = SPEED_0;
+ netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
+ }
+ }
+ schedule_work(&adapter->link_chg_task);
+}
+
+/*
+ * atl1_intr - Interrupt Handler
+ * @irq: interrupt number
+ * @data: pointer to a network interface device structure
+ * @pt_regs: CPU registers structure
+ */
+static irqreturn_t atl1_intr(int irq, void *data)
+{
+ /*struct atl1_adapter *adapter = ((struct net_device *)data)->priv;*/
+ struct atl1_adapter *adapter = netdev_priv(data);
+ u32 status;
+ u8 update_rx;
+ int max_ints = 10;
+
+ status = adapter->cmb.cmb->int_stats;
+ if (!status)
+ return IRQ_NONE;
+
+ update_rx = 0;
+
+ do {
+ /* clear CMB interrupt status at once */
+ adapter->cmb.cmb->int_stats = 0;
+
+ if (status & ISR_GPHY) /* clear phy status */
+ atl1_clear_phy_int(adapter);
+
+ /* clear ISR status, and Enable CMB DMA/Disable Interrupt */
+ iowrite32(status | ISR_DIS_INT, adapter->hw.hw_addr + REG_ISR);
+
+ /* check if SMB intr */
+ if (status & ISR_SMB)
+ atl1_inc_smb(adapter);
+
+ /* check if PCIE PHY Link down */
+ if (status & ISR_PHY_LINKDOWN) {
+ printk(KERN_DEBUG "%s: pcie phy link down %x\n",
+ atl1_driver_name, status);
+ if (netif_running(adapter->netdev)) { /* reset MAC */
+ iowrite32(0, adapter->hw.hw_addr + REG_IMR);
+ schedule_work(&adapter->pcie_dma_to_rst_task);
+ return IRQ_HANDLED;
+ }
+ }
+
+ /* check if DMA read/write error ? */
+ if (status & (ISR_DMAR_TO_RST | ISR_DMAW_TO_RST)) {
+ printk(KERN_DEBUG
+ "%s: pcie DMA r/w error (status = 0x%x)\n",
+ atl1_driver_name, status);
+ iowrite32(0, adapter->hw.hw_addr + REG_IMR);
+ schedule_work(&adapter->pcie_dma_to_rst_task);
+ return IRQ_HANDLED;
+ }
+
+ /* link event */
+ if (status & ISR_GPHY) {
+ adapter->soft_stats.tx_carrier_errors++;
+ atl1_check_for_link(adapter);
+ }
+
+ /* transmit event */
+ if (status & ISR_CMB_TX)
+ atl1_intr_tx(adapter);
+
+ /* rx exception */
+ if (unlikely(status & (ISR_RXF_OV | ISR_RFD_UNRUN |
+ ISR_RRD_OV | ISR_HOST_RFD_UNRUN |
+ ISR_HOST_RRD_OV | ISR_CMB_RX))) {
+ if (status &
+ (ISR_RXF_OV | ISR_RFD_UNRUN | ISR_RRD_OV |
+ ISR_HOST_RFD_UNRUN | ISR_HOST_RRD_OV))
+ printk(KERN_INFO
+ "%s: rx exception: status = 0x%x\n",
+ atl1_driver_name, status);
+ atl1_intr_rx(adapter);
+ }
+
+ if (--max_ints < 0)
+ break;
+
+ } while ((status = adapter->cmb.cmb->int_stats));
+
+ /* re-enable Interrupt */
+ iowrite32(ISR_DIS_SMB | ISR_DIS_DMA, adapter->hw.hw_addr + REG_ISR);
+ return IRQ_HANDLED;
+}
+
+/*
+ * atl1_set_multi - Multicast and Promiscuous mode set
+ * @netdev: network interface device structure
+ *
+ * The set_multi 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,
+ * promiscuous mode, and all-multi behavior.
+ */
+static void atl1_set_multi(struct net_device *netdev)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ struct atl1_hw *hw = &adapter->hw;
+ struct dev_mc_list *mc_ptr;
+ u32 rctl;
+ u32 hash_value;
+
+ /* Check for Promiscuous and All Multicast modes */
+ rctl = ioread32(hw->hw_addr + REG_MAC_CTRL);
+ if (netdev->flags & IFF_PROMISC)
+ rctl |= MAC_CTRL_PROMIS_EN;
+ else if (netdev->flags & IFF_ALLMULTI) {
+ rctl |= MAC_CTRL_MC_ALL_EN;
+ rctl &= ~MAC_CTRL_PROMIS_EN;
+ } else
+ rctl &= ~(MAC_CTRL_PROMIS_EN | MAC_CTRL_MC_ALL_EN);
+
+ iowrite32(rctl, hw->hw_addr + REG_MAC_CTRL);
+
+ /* clear the old settings from the multicast hash table */
+ iowrite32(0, hw->hw_addr + REG_RX_HASH_TABLE);
+ 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) {
+ hash_value = atl1_hash_mc_addr(hw, mc_ptr->dmi_addr);
+ atl1_hash_set(hw, hash_value);
+ }
+}
+
+static void atl1_setup_mac_ctrl(struct atl1_adapter *adapter)
+{
+ u32 value;
+ struct atl1_hw *hw = &adapter->hw;
+ struct net_device *netdev = adapter->netdev;
+ /* Config MAC CTRL Register */
+ value = MAC_CTRL_TX_EN | MAC_CTRL_RX_EN;
+ /* duplex */
+ if (FULL_DUPLEX == adapter->link_duplex)
+ value |= MAC_CTRL_DUPLX;
+ /* speed */
+ value |= ((u32) ((SPEED_1000 == adapter->link_speed) ?
+ MAC_CTRL_SPEED_1000 : MAC_CTRL_SPEED_10_100) <<
+ MAC_CTRL_SPEED_SHIFT);
+ /* flow control */
+ value |= (MAC_CTRL_TX_FLOW | MAC_CTRL_RX_FLOW);
+ /* PAD & CRC */
+ value |= (MAC_CTRL_ADD_CRC | MAC_CTRL_PAD);
+ /* preamble length */
+ value |= (((u32) adapter->hw.preamble_len
+ & MAC_CTRL_PRMLEN_MASK) << MAC_CTRL_PRMLEN_SHIFT);
+ /* vlan */
+ if (adapter->vlgrp)
+ value |= MAC_CTRL_RMV_VLAN;
+ /* rx checksum
+ if (adapter->rx_csum)
+ value |= MAC_CTRL_RX_CHKSUM_EN;
+ */
+ /* filter mode */
+ value |= MAC_CTRL_BC_EN;
+ if (netdev->flags & IFF_PROMISC)
+ value |= MAC_CTRL_PROMIS_EN;
+ else if (netdev->flags & IFF_ALLMULTI)
+ value |= MAC_CTRL_MC_ALL_EN;
+ /* value |= MAC_CTRL_LOOPBACK; */
+ iowrite32(value, hw->hw_addr + REG_MAC_CTRL);
+}
+
+static u32 atl1_check_link(struct atl1_adapter *adapter)
+{
+ struct atl1_hw *hw = &adapter->hw;
+ struct net_device *netdev = adapter->netdev;
+ u32 ret_val;
+ u16 speed, duplex, phy_data;
+ int reconfig = 0;
+
+ /* MII_BMSR must read twice */
+ atl1_read_phy_reg(hw, MII_BMSR, &phy_data);
+ atl1_read_phy_reg(hw, MII_BMSR, &phy_data);
+ if (!(phy_data & BMSR_LSTATUS)) { /* link down */
+ if (netif_carrier_ok(netdev)) { /* old link state: Up */
+ printk(KERN_INFO "%s: link is down\n",
+ atl1_driver_name);
+ adapter->link_speed = SPEED_0;
+ netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
+ }
+ return ATL1_SUCCESS;
+ }
+
+ /* Link Up */
+ ret_val = atl1_get_speed_and_duplex(hw, &speed, &duplex);
+ if (ret_val)
+ return ret_val;
+
+ switch (hw->media_type) {
+ case MEDIA_TYPE_1000M_FULL:
+ if (speed != SPEED_1000 || duplex != FULL_DUPLEX)
+ reconfig = 1;
+ break;
+ case MEDIA_TYPE_100M_FULL:
+ if (speed != SPEED_100 || duplex != FULL_DUPLEX)
+ reconfig = 1;
+ break;
+ case MEDIA_TYPE_100M_HALF:
+ if (speed != SPEED_100 || duplex != HALF_DUPLEX)
+ reconfig = 1;
+ break;
+ case MEDIA_TYPE_10M_FULL:
+ if (speed != SPEED_10 || duplex != FULL_DUPLEX)
+ reconfig = 1;
+ break;
+ case MEDIA_TYPE_10M_HALF:
+ if (speed != SPEED_10 || duplex != HALF_DUPLEX)
+ reconfig = 1;
+ break;
+ }
+
+ /* link result is our setting */
+ if (!reconfig) {
+ if (adapter->link_speed != speed
+ || adapter->link_duplex != duplex) {
+ adapter->link_speed = speed;
+ adapter->link_duplex = duplex;
+ atl1_setup_mac_ctrl(adapter);
+ printk(KERN_INFO "%s: %s link is up %d Mbps %s\n",
+ atl1_driver_name, netdev->name,
+ adapter->link_speed,
+ adapter->link_duplex ==
+ FULL_DUPLEX ? "full duplex" : "half duplex");
+ }
+ if (!netif_carrier_ok(netdev)) { /* Link down -> Up */
+ netif_carrier_on(netdev);
+ netif_wake_queue(netdev);
+ }
+ return ATL1_SUCCESS;
+ }
+
+ /* change orignal link status */
+ if (netif_carrier_ok(netdev)) {
+ adapter->link_speed = SPEED_0;
+ netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
+ }
+
+ if (hw->media_type != MEDIA_TYPE_AUTO_SENSOR &&
+ hw->media_type != MEDIA_TYPE_1000M_FULL) {
+ switch (hw->media_type) {
+ case MEDIA_TYPE_100M_FULL:
+ phy_data = MII_CR_FULL_DUPLEX | MII_CR_SPEED_100 |
+ MII_CR_RESET;
+ break;
+ case MEDIA_TYPE_100M_HALF:
+ phy_data = MII_CR_SPEED_100 | MII_CR_RESET;
+ break;
+ case MEDIA_TYPE_10M_FULL:
+ phy_data =
+ MII_CR_FULL_DUPLEX | MII_CR_SPEED_10 | MII_CR_RESET;
+ break;
+ default: /* MEDIA_TYPE_10M_HALF: */
+ phy_data = MII_CR_SPEED_10 | MII_CR_RESET;
+ break;
+ }
+ atl1_write_phy_reg(hw, MII_BMCR, phy_data);
+ return ATL1_SUCCESS;
+ }
+
+ /* auto-neg, insert timer to re-config phy */
+ if (!adapter->phy_timer_pending) {
+ adapter->phy_timer_pending = true;
+ mod_timer(&adapter->phy_config_timer, jiffies + 3 * HZ);
+ }
+
+ return ATL1_SUCCESS;
+}
+
+static void set_flow_ctrl_old(struct atl1_adapter *adapter)
+{
+ u32 hi, lo, value;
+
+ /* RFD Flow Control */
+ value = adapter->rfd_ring.count;
+ hi = value / 16;
+ if (hi < 2)
+ hi = 2;
+ lo = value * 7 / 8;
+
+ value = ((hi & RXQ_RXF_PAUSE_TH_HI_MASK) << RXQ_RXF_PAUSE_TH_HI_SHIFT) |
+ ((lo & RXQ_RXF_PAUSE_TH_LO_MASK) << RXQ_RXF_PAUSE_TH_LO_SHIFT);
+ iowrite32(value, adapter->hw.hw_addr + REG_RXQ_RXF_PAUSE_THRESH);
+
+ /* RRD Flow Control */
+ value = adapter->rrd_ring.count;
+ lo = value / 16;
+ hi = value * 7 / 8;
+ if (lo < 2)
+ lo = 2;
+ value = ((hi & RXQ_RRD_PAUSE_TH_HI_MASK) << RXQ_RRD_PAUSE_TH_HI_SHIFT) |
+ ((lo & RXQ_RRD_PAUSE_TH_LO_MASK) << RXQ_RRD_PAUSE_TH_LO_SHIFT);
+ iowrite32(value, adapter->hw.hw_addr + REG_RXQ_RRD_PAUSE_THRESH);
+}
+
+static void set_flow_ctrl_new(struct atl1_hw *hw)
+{
+ u32 hi, lo, value;
+
+ /* RXF Flow Control */
+ value = ioread32(hw->hw_addr + REG_SRAM_RXF_LEN);
+ lo = value / 16;
+ if (lo < 192)
+ lo = 192;
+ hi = value * 7 / 8;
+ if (hi < lo)
+ hi = lo + 16;
+ value = ((hi & RXQ_RXF_PAUSE_TH_HI_MASK) << RXQ_RXF_PAUSE_TH_HI_SHIFT) |
+ ((lo & RXQ_RXF_PAUSE_TH_LO_MASK) << RXQ_RXF_PAUSE_TH_LO_SHIFT);
+ iowrite32(value, hw->hw_addr + REG_RXQ_RXF_PAUSE_THRESH);
+
+ /* RRD Flow Control */
+ value = ioread32(hw->hw_addr + REG_SRAM_RRD_LEN);
+ lo = value / 8;
+ hi = value * 7 / 8;
+ if (lo < 2)
+ lo = 2;
+ if (hi < lo)
+ hi = lo + 3;
+ value = ((hi & RXQ_RRD_PAUSE_TH_HI_MASK) << RXQ_RRD_PAUSE_TH_HI_SHIFT) |
+ ((lo & RXQ_RRD_PAUSE_TH_LO_MASK) << RXQ_RRD_PAUSE_TH_LO_SHIFT);
+ iowrite32(value, hw->hw_addr + REG_RXQ_RRD_PAUSE_THRESH);
+}
+
+/*
+ * atl1_configure - Configure Transmit&Receive Unit after Reset
+ * @adapter: board private structure
+ *
+ * Configure the Tx /Rx unit of the MAC after a reset.
+ */
+static u32 atl1_configure(struct atl1_adapter *adapter)
+{
+ struct atl1_hw *hw = &adapter->hw;
+ u32 value;
+
+ /* clear interrupt status */
+ iowrite32(0xffffffff, adapter->hw.hw_addr + REG_ISR);
+
+ /* set MAC Address */
+ value = (((u32) hw->mac_addr[2]) << 24) |
+ (((u32) hw->mac_addr[3]) << 16) |
+ (((u32) hw->mac_addr[4]) << 8) |
+ (((u32) hw->mac_addr[5]));
+ iowrite32(value, hw->hw_addr + REG_MAC_STA_ADDR);
+ value = (((u32) hw->mac_addr[0]) << 8) | (((u32) hw->mac_addr[1]));
+ iowrite32(value, hw->hw_addr + (REG_MAC_STA_ADDR + 4));
+
+ /* tx / rx ring */
+
+ /* HI base address */
+ iowrite32((u32) ((adapter->tpd_ring.dma & 0xffffffff00000000ULL) >> 32),
+ hw->hw_addr + REG_DESC_BASE_ADDR_HI);
+ /* LO base address */
+ iowrite32((u32) (adapter->rfd_ring.dma & 0x00000000ffffffffULL),
+ hw->hw_addr + REG_DESC_RFD_ADDR_LO);
+ iowrite32((u32) (adapter->rrd_ring.dma & 0x00000000ffffffffULL),
+ hw->hw_addr + REG_DESC_RRD_ADDR_LO);
+ iowrite32((u32) (adapter->tpd_ring.dma & 0x00000000ffffffffULL),
+ hw->hw_addr + REG_DESC_TPD_ADDR_LO);
+ iowrite32((u32) (adapter->cmb.dma & 0x00000000ffffffffULL),
+ hw->hw_addr + REG_DESC_CMB_ADDR_LO);
+ iowrite32((u32) (adapter->smb.dma & 0x00000000ffffffffULL),
+ hw->hw_addr + REG_DESC_SMB_ADDR_LO);
+
+ /* element count */
+ value = adapter->rrd_ring.count;
+ value <<= 16;
+ value += adapter->rfd_ring.count;
+ iowrite32(value, hw->hw_addr + REG_DESC_RFD_RRD_RING_SIZE);
+ iowrite32(adapter->tpd_ring.count, hw->hw_addr + REG_DESC_TPD_RING_SIZE);
+
+ /* Load Ptr */
+ iowrite32(1, hw->hw_addr + REG_LOAD_PTR);
+
+ /* config Mailbox */
+ value = ((atomic_read(&adapter->tpd_ring.next_to_use)
+ & MB_TPD_PROD_INDX_MASK) << MB_TPD_PROD_INDX_SHIFT) |
+ ((atomic_read(&adapter->rrd_ring.next_to_clean)
+ & MB_RRD_CONS_INDX_MASK) << MB_RRD_CONS_INDX_SHIFT) |
+ ((atomic_read(&adapter->rfd_ring.next_to_use)
+ & MB_RFD_PROD_INDX_MASK) << MB_RFD_PROD_INDX_SHIFT);
+ iowrite32(value, hw->hw_addr + REG_MAILBOX);
+
+ /* config IPG/IFG */
+ value = (((u32) hw->ipgt & MAC_IPG_IFG_IPGT_MASK)
+ << MAC_IPG_IFG_IPGT_SHIFT) |
+ (((u32) hw->min_ifg & MAC_IPG_IFG_MIFG_MASK)
+ << MAC_IPG_IFG_MIFG_SHIFT) |
+ (((u32) hw->ipgr1 & MAC_IPG_IFG_IPGR1_MASK)
+ << MAC_IPG_IFG_IPGR1_SHIFT) |
+ (((u32) hw->ipgr2 & MAC_IPG_IFG_IPGR2_MASK)
+ << MAC_IPG_IFG_IPGR2_SHIFT);
+ iowrite32(value, hw->hw_addr + REG_MAC_IPG_IFG);
+
+ /* config Half-Duplex Control */
+ value = ((u32) hw->lcol & MAC_HALF_DUPLX_CTRL_LCOL_MASK) |
+ (((u32) hw->max_retry & MAC_HALF_DUPLX_CTRL_RETRY_MASK)
+ << MAC_HALF_DUPLX_CTRL_RETRY_SHIFT) |
+ MAC_HALF_DUPLX_CTRL_EXC_DEF_EN |
+ (0xa << MAC_HALF_DUPLX_CTRL_ABEBT_SHIFT) |
+ (((u32) hw->jam_ipg & MAC_HALF_DUPLX_CTRL_JAMIPG_MASK)
+ << MAC_HALF_DUPLX_CTRL_JAMIPG_SHIFT);
+ iowrite32(value, hw->hw_addr + REG_MAC_HALF_DUPLX_CTRL);
+
+ /* set Interrupt Moderator Timer */
+ iowrite16(adapter->imt, hw->hw_addr + REG_IRQ_MODU_TIMER_INIT);
+ iowrite32(MASTER_CTRL_ITIMER_EN, hw->hw_addr + REG_MASTER_CTRL);
+
+ /* set Interrupt Clear Timer */
+ iowrite16(adapter->ict, hw->hw_addr + REG_CMBDISDMA_TIMER);
+
+ /* set MTU, 4 : VLAN */
+ iowrite32(hw->max_frame_size + 4, hw->hw_addr + REG_MTU);
+
+ /* jumbo size & rrd retirement timer */
+ value = (((u32) hw->rx_jumbo_th & RXQ_JMBOSZ_TH_MASK)
+ << RXQ_JMBOSZ_TH_SHIFT) |
+ (((u32) hw->rx_jumbo_lkah & RXQ_JMBO_LKAH_MASK)
+ << RXQ_JMBO_LKAH_SHIFT) |
+ (((u32) hw->rrd_ret_timer & RXQ_RRD_TIMER_MASK)
+ << RXQ_RRD_TIMER_SHIFT);
+ iowrite32(value, hw->hw_addr + REG_RXQ_JMBOSZ_RRDTIM);
+
+ /* Flow Control */
+ switch (hw->dev_rev) {
+ case 0x8001:
+ case 0x9001:
+ case 0x9002:
+ case 0x9003:
+ set_flow_ctrl_old(adapter);
+ break;
+ default:
+ set_flow_ctrl_new(hw);
+ break;
+ }
+
+ /* config TXQ */
+ value = (((u32) hw->tpd_burst & TXQ_CTRL_TPD_BURST_NUM_MASK)
+ << TXQ_CTRL_TPD_BURST_NUM_SHIFT) |
+ (((u32) hw->txf_burst & TXQ_CTRL_TXF_BURST_NUM_MASK)
+ << TXQ_CTRL_TXF_BURST_NUM_SHIFT) |
+ (((u32) hw->tpd_fetch_th & TXQ_CTRL_TPD_FETCH_TH_MASK)
+ << TXQ_CTRL_TPD_FETCH_TH_SHIFT) | TXQ_CTRL_ENH_MODE | TXQ_CTRL_EN;
+ iowrite32(value, hw->hw_addr + REG_TXQ_CTRL);
+
+ /* min tpd fetch gap & tx jumbo packet size threshold for taskoffload */
+ value = (((u32) hw->tx_jumbo_task_th & TX_JUMBO_TASK_TH_MASK)
+ << TX_JUMBO_TASK_TH_SHIFT) |
+ (((u32) hw->tpd_fetch_gap & TX_TPD_MIN_IPG_MASK)
+ << TX_TPD_MIN_IPG_SHIFT);
+ iowrite32(value, hw->hw_addr + REG_TX_JUMBO_TASK_TH_TPD_IPG);
+
+ /* config RXQ */
+ value = (((u32) hw->rfd_burst & RXQ_CTRL_RFD_BURST_NUM_MASK)
+ << RXQ_CTRL_RFD_BURST_NUM_SHIFT) |
+ (((u32) hw->rrd_burst & RXQ_CTRL_RRD_BURST_THRESH_MASK)
+ << RXQ_CTRL_RRD_BURST_THRESH_SHIFT) |
+ (((u32) hw->rfd_fetch_gap & RXQ_CTRL_RFD_PREF_MIN_IPG_MASK)
+ << RXQ_CTRL_RFD_PREF_MIN_IPG_SHIFT) |
+ RXQ_CTRL_CUT_THRU_EN | RXQ_CTRL_EN;
+ iowrite32(value, hw->hw_addr + REG_RXQ_CTRL);
+
+ /* config DMA Engine */
+ value = ((((u32) hw->dmar_block) & DMA_CTRL_DMAR_BURST_LEN_MASK)
+ << DMA_CTRL_DMAR_BURST_LEN_SHIFT) |
+ ((((u32) hw->dmaw_block) & DMA_CTRL_DMAR_BURST_LEN_MASK)
+ << DMA_CTRL_DMAR_BURST_LEN_SHIFT) |
+ DMA_CTRL_DMAR_EN | DMA_CTRL_DMAW_EN;
+ value |= (u32) hw->dma_ord;
+ if (atl1_rcb_128 == hw->rcb_value)
+ value |= DMA_CTRL_RCB_VALUE;
+ iowrite32(value, hw->hw_addr + REG_DMA_CTRL);
+
+ /* config CMB / SMB */
+ value = hw->cmb_rrd | ((u32) hw->cmb_tpd << 16);
+ iowrite32(value, hw->hw_addr + REG_CMB_WRITE_TH);
+ value = hw->cmb_rx_timer | ((u32) hw->cmb_tx_timer << 16);
+ iowrite32(value, hw->hw_addr + REG_CMB_WRITE_TIMER);
+ iowrite32(hw->smb_timer, hw->hw_addr + REG_SMB_TIMER);
+
+ /* --- enable CMB / SMB */
+ value = CSMB_CTRL_CMB_EN | CSMB_CTRL_SMB_EN;
+ iowrite32(value, hw->hw_addr + REG_CSMB_CTRL);
+
+ value = ioread32(adapter->hw.hw_addr + REG_ISR);
+ if (unlikely((value & ISR_PHY_LINKDOWN) != 0))
+ value = 1; /* config failed */
+ else
+ value = 0;
+
+ /* clear all interrupt status */
+ iowrite32(0x3fffffff, adapter->hw.hw_addr + REG_ISR);
+ iowrite32(0, adapter->hw.hw_addr + REG_ISR);
+ return value;
+}
+
+/*
+ * atl1_irq_disable - Mask off interrupt generation on the NIC
+ * @adapter: board private structure
+ */
+static void atl1_irq_disable(struct atl1_adapter *adapter)
+{
+ atomic_inc(&adapter->irq_sem);
+ iowrite32(0, adapter->hw.hw_addr + REG_IMR);
+ ioread32(adapter->hw.hw_addr + REG_IMR);
+ synchronize_irq(adapter->pdev->irq);
+}
+
+static void atl1_vlan_rx_register(struct net_device *netdev,
+ struct vlan_group *grp)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ unsigned long flags;
+ u32 ctrl;
+
+ spin_lock_irqsave(&adapter->lock, flags);
+ /* atl1_irq_disable(adapter); */
+ adapter->vlgrp = grp;
+
+ if (grp) {
+ /* enable VLAN tag insert/strip */
+ ctrl = ioread32(adapter->hw.hw_addr + REG_MAC_CTRL);
+ ctrl |= MAC_CTRL_RMV_VLAN;
+ iowrite32(ctrl, adapter->hw.hw_addr + REG_MAC_CTRL);
+ } else {
+ /* disable VLAN tag insert/strip */
+ ctrl = ioread32(adapter->hw.hw_addr + REG_MAC_CTRL);
+ ctrl &= ~MAC_CTRL_RMV_VLAN;
+ iowrite32(ctrl, adapter->hw.hw_addr + REG_MAC_CTRL);
+ }
+
+ /* atl1_irq_enable(adapter); */
+ spin_unlock_irqrestore(&adapter->lock, flags);
+}
+
+/* FIXME: justify or remove -- CHS */
+static void atl1_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
+{
+ /* We don't do Vlan filtering */
+ return;
+}
+
+/* FIXME: this looks wrong too -- CHS */
+static void atl1_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&adapter->lock, flags);
+ /* atl1_irq_disable(adapter); */
+ if (adapter->vlgrp)
+ adapter->vlgrp->vlan_devices[vid] = NULL;
+ /* atl1_irq_enable(adapter); */
+ spin_unlock_irqrestore(&adapter->lock, flags);
+ /* We don't do Vlan filtering */
+ return;
+}
+
+static void atl1_restore_vlan(struct atl1_adapter *adapter)
+{
+ atl1_vlan_rx_register(adapter->netdev, adapter->vlgrp);
+ if (adapter->vlgrp) {
+ u16 vid;
+ for (vid = 0; vid < VLAN_GROUP_ARRAY_LEN; vid++) {
+ if (!adapter->vlgrp->vlan_devices[vid])
+ continue;
+ atl1_vlan_rx_add_vid(adapter->netdev, vid);
+ }
+ }
+}
+
+static u16 tpd_avail(struct atl1_tpd_ring *tpd_ring)
+{
+ u16 next_to_clean = atomic_read(&tpd_ring->next_to_clean);
+ u16 next_to_use = atomic_read(&tpd_ring->next_to_use);
+ return ((next_to_clean >
+ next_to_use) ? next_to_clean - next_to_use -
+ 1 : tpd_ring->count + next_to_clean - next_to_use - 1);
+}
+
+static int atl1_tso(struct atl1_adapter *adapter, struct sk_buff *skb,
+ struct tso_param *tso)
+{
+ /* We enter this function holding a spinlock. */
+ u8 ipofst;
+ int err;
+
+ if (skb_shinfo(skb)->gso_size) {
+ if (skb_header_cloned(skb)) {
+ err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
+ if (unlikely(err))
+ return err;
+ }
+
+ if (skb->protocol == ntohs(ETH_P_IP)) {
+ skb->nh.iph->tot_len = 0;
+ skb->nh.iph->check = 0;
+ skb->h.th->check =
+ ~csum_tcpudp_magic(skb->nh.iph->saddr,
+ skb->nh.iph->daddr, 0,
+ IPPROTO_TCP, 0);
+ ipofst = skb->nh.raw - skb->data;
+ if (ipofst != ENET_HEADER_SIZE) /* 802.3 frame */
+ tso->tsopl |= 1 << TSO_PARAM_ETHTYPE_SHIFT;
+
+ tso->tsopl |= (skb->nh.iph->ihl &
+ CSUM_PARAM_IPHL_MASK) << CSUM_PARAM_IPHL_SHIFT;
+ tso->tsopl |= ((skb->h.th->doff << 2) &
+ TSO_PARAM_TCPHDRLEN_MASK) << TSO_PARAM_TCPHDRLEN_SHIFT;
+ tso->tsopl |= (skb_shinfo(skb)->gso_size &
+ TSO_PARAM_MSS_MASK) << TSO_PARAM_MSS_SHIFT;
+ tso->tsopl |= 1 << TSO_PARAM_IPCKSUM_SHIFT;
+ tso->tsopl |= 1 << TSO_PARAM_TCPCKSUM_SHIFT;
+ tso->tsopl |= 1 << TSO_PARAM_SEGMENT_SHIFT;
+ return true;
+ }
+ }
+ return false;
+}
+
+static int atl1_tx_csum(struct atl1_adapter *adapter, struct sk_buff *skb,
+ struct csum_param *csum)
+{
+ u8 css, cso;
+
+ if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) {
+ cso = skb->h.raw - skb->data;
+ css = (skb->h.raw + skb->csum) - skb->data;
+ if (unlikely(cso & 0x1)) {
+ printk(KERN_DEBUG "%s: payload offset != even number\n",
+ atl1_driver_name);
+ return -1;
+ }
+ csum->csumpl |= (cso & CSUM_PARAM_PLOADOFFSET_MASK) <<
+ CSUM_PARAM_PLOADOFFSET_SHIFT;
+ csum->csumpl |= (css & CSUM_PARAM_XSUMOFFSET_MASK) <<
+ CSUM_PARAM_XSUMOFFSET_SHIFT;
+ csum->csumpl |= 1 << CSUM_PARAM_CUSTOMCKSUM_SHIFT;
+ return true;
+ }
+
+ return true;
+}
+
+static void atl1_tx_map(struct atl1_adapter *adapter,
+ struct sk_buff *skb, bool tcp_seg)
+{
+ /* We enter this function holding a spinlock. */
+ struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring;
+ struct atl1_buffer *buffer_info;
+ struct page *page;
+ int first_buf_len = skb->len;
+ unsigned long offset;
+ unsigned int nr_frags;
+ unsigned int f;
+ u16 tpd_next_to_use;
+ u16 proto_hdr_len;
+ u16 i, m, len12;
+
+ first_buf_len -= skb->data_len;
+ nr_frags = skb_shinfo(skb)->nr_frags;
+ tpd_next_to_use = atomic_read(&tpd_ring->next_to_use);
+ buffer_info = &tpd_ring->buffer_info[tpd_next_to_use];
+ if (unlikely(buffer_info->skb))
+ BUG();
+ buffer_info->skb = NULL; /* put skb in last TPD */
+
+ if (tcp_seg) {
+ /* TSO/GSO */
+ proto_hdr_len =
+ ((skb->h.raw - skb->data) + (skb->h.th->doff << 2));
+ buffer_info->length = proto_hdr_len;
+ page = virt_to_page(skb->data);
+ offset = (unsigned long)skb->data & ~PAGE_MASK;
+ buffer_info->dma = pci_map_page(adapter->pdev, page,
+ offset, proto_hdr_len,
+ PCI_DMA_TODEVICE);
+
+ if (++tpd_next_to_use == tpd_ring->count)
+ tpd_next_to_use = 0;
+
+ if (first_buf_len > proto_hdr_len) {
+ len12 = first_buf_len - proto_hdr_len;
+ m = (len12 + MAX_TX_BUF_LEN - 1) / MAX_TX_BUF_LEN;
+ for (i = 0; i < m; i++) {
+ buffer_info =
+ &tpd_ring->buffer_info[tpd_next_to_use];
+ buffer_info->skb = NULL;
+ buffer_info->length =
+ (MAX_TX_BUF_LEN >=
+ len12) ? MAX_TX_BUF_LEN : len12;
+ len12 -= buffer_info->length;
+ page = virt_to_page(skb->data +
+ (proto_hdr_len +
+ i * MAX_TX_BUF_LEN));
+ offset = (unsigned long)(skb->data +
+ (proto_hdr_len +
+ i * MAX_TX_BUF_LEN)) &
+ ~PAGE_MASK;
+ buffer_info->dma =
+ pci_map_page(adapter->pdev, page, offset,
+ buffer_info->length,
+ PCI_DMA_TODEVICE);
+ if (++tpd_next_to_use == tpd_ring->count)
+ tpd_next_to_use = 0;
+ }
+ }
+ } else {
+ /* not TSO/GSO */
+ buffer_info->length = first_buf_len;
+ page = virt_to_page(skb->data);
+ offset = (unsigned long)skb->data & ~PAGE_MASK;
+ buffer_info->dma = pci_map_page(adapter->pdev, page,
+ offset, first_buf_len,
+ PCI_DMA_TODEVICE);
+ if (++tpd_next_to_use == tpd_ring->count)
+ tpd_next_to_use = 0;
+ }
+
+ for (f = 0; f < nr_frags; f++) {
+ struct skb_frag_struct *frag;
+ u16 lenf, i, m;
+
+ frag = &skb_shinfo(skb)->frags[f];
+ lenf = frag->size;
+
+ m = (lenf + MAX_TX_BUF_LEN - 1) / MAX_TX_BUF_LEN;
+ for (i = 0; i < m; i++) {
+ buffer_info = &tpd_ring->buffer_info[tpd_next_to_use];
+ if (unlikely(buffer_info->skb))
+ BUG();
+ buffer_info->skb = NULL;
+ buffer_info->length =
+ (lenf > MAX_TX_BUF_LEN) ? MAX_TX_BUF_LEN : lenf;
+ lenf -= buffer_info->length;
+ buffer_info->dma =
+ pci_map_page(adapter->pdev, frag->page,
+ frag->page_offset + i * MAX_TX_BUF_LEN,
+ buffer_info->length, PCI_DMA_TODEVICE);
+
+ if (++tpd_next_to_use == tpd_ring->count)
+ tpd_next_to_use = 0;
+ }
+ }
+
+ /* last tpd's buffer-info */
+ buffer_info->skb = skb;
+}
+
+static void atl1_tx_queue(struct atl1_adapter *adapter, int count,
+ union tpd_descr *descr)
+{
+ /* We enter this function holding a spinlock. */
+ struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring;
+ int j;
+ u32 val;
+ struct atl1_buffer *buffer_info;
+ struct tx_packet_desc *tpd;
+ u16 tpd_next_to_use = atomic_read(&tpd_ring->next_to_use);
+
+ for (j = 0; j < count; j++) {
+ buffer_info = &tpd_ring->buffer_info[tpd_next_to_use];
+ tpd = ATL1_TPD_DESC(&adapter->tpd_ring, tpd_next_to_use);
+ tpd->desc.csum.csumpu = descr->csum.csumpu;
+ tpd->desc.csum.csumpl = descr->csum.csumpl;
+ tpd->desc.tso.tsopu = descr->tso.tsopu;
+ tpd->desc.tso.tsopl = descr->tso.tsopl;
+ tpd->buffer_addr = cpu_to_le64(buffer_info->dma);
+ tpd->desc.data = descr->data;
+ tpd->desc.csum.csumpu |= (cpu_to_le16(buffer_info->length) &
+ CSUM_PARAM_BUFLEN_MASK) << CSUM_PARAM_BUFLEN_SHIFT;
+
+ val = (descr->tso.tsopl >> TSO_PARAM_SEGMENT_SHIFT) &
+ TSO_PARAM_SEGMENT_MASK;
+ if (val && !j)
+ tpd->desc.tso.tsopl |= 1 << TSO_PARAM_HDRFLAG_SHIFT;
+
+ if (j == (count - 1))
+ tpd->desc.csum.csumpl |= 1 << CSUM_PARAM_EOP_SHIFT;
+
+ if (++tpd_next_to_use == tpd_ring->count)
+ tpd_next_to_use = 0;
+ }
+ /*
+ * 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();
+
+ atomic_set(&tpd_ring->next_to_use, (int)tpd_next_to_use);
+}
+
+static void atl1_update_mailbox(struct atl1_adapter *adapter)
+{
+ unsigned long flags;
+ u32 tpd_next_to_use;
+ u32 rfd_next_to_use;
+ u32 rrd_next_to_clean;
+ u32 value;
+
+ spin_lock_irqsave(&adapter->mb_lock, flags);
+
+ tpd_next_to_use = atomic_read(&adapter->tpd_ring.next_to_use);
+ rfd_next_to_use = atomic_read(&adapter->rfd_ring.next_to_use);
+ rrd_next_to_clean = atomic_read(&adapter->rrd_ring.next_to_clean);
+
+ value = ((rfd_next_to_use & MB_RFD_PROD_INDX_MASK) <<
+ MB_RFD_PROD_INDX_SHIFT) |
+ ((rrd_next_to_clean & MB_RRD_CONS_INDX_MASK) <<
+ MB_RRD_CONS_INDX_SHIFT) |
+ ((tpd_next_to_use & MB_TPD_PROD_INDX_MASK) <<
+ MB_TPD_PROD_INDX_SHIFT);
+ iowrite32(value, adapter->hw.hw_addr + REG_MAILBOX);
+
+ spin_unlock_irqrestore(&adapter->mb_lock, flags);
+}
+
+static int atl1_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ int len = skb->len;
+ int tso;
+ int count = 1;
+ int ret_val;
+ u32 val;
+ union tpd_descr param;
+ u16 frag_size;
+ u16 vlan_tag;
+ unsigned long flags;
+ unsigned int nr_frags = 0;
+ unsigned int mss = 0;
+ unsigned int f;
+ unsigned int proto_hdr_len;
+
+ len -= skb->data_len;
+
+ if (unlikely(skb->len == 0)) {
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
+ }
+
+ param.data = 0;
+ param.tso.tsopu = 0;
+ param.tso.tsopl = 0;
+ param.csum.csumpu = 0;
+ param.csum.csumpl = 0;
+
+ /* nr_frags will be nonzero if we're doing scatter/gather (SG) */
+ nr_frags = skb_shinfo(skb)->nr_frags;
+ for (f = 0; f < nr_frags; f++) {
+ frag_size = skb_shinfo(skb)->frags[f].size;
+ if (frag_size)
+ count +=
+ (frag_size + MAX_TX_BUF_LEN - 1) / MAX_TX_BUF_LEN;
+ }
+
+ /* mss will be nonzero if we're doing segment offload (TSO/GSO) */
+ mss = skb_shinfo(skb)->gso_size;
+ if (mss) {
+ if (skb->protocol == ntohs(ETH_P_IP)) {
+ proto_hdr_len = ((skb->h.raw - skb->data) +
+ (skb->h.th->doff << 2));
+ if (unlikely(proto_hdr_len > len)) {
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
+ }
+ /* need additional TPD ? */
+ if (proto_hdr_len != len)
+ count += (len - proto_hdr_len +
+ MAX_TX_BUF_LEN - 1) / MAX_TX_BUF_LEN;
+ }
+ }
+
+ local_irq_save(flags);
+ if (!spin_trylock(&adapter->lock)) {
+ /* Can't get lock - tell upper layer to requeue */
+ local_irq_restore(flags);
+ printk(KERN_DEBUG "%s: TX locked\n", atl1_driver_name);
+ return NETDEV_TX_LOCKED;
+ }
+
+ if (tpd_avail(&adapter->tpd_ring) < count) {
+ /* not enough descriptors */
+ netif_stop_queue(netdev);
+ spin_unlock_irqrestore(&adapter->lock, flags);
+ printk(KERN_DEBUG "%s: TX busy\n", atl1_driver_name);
+ return NETDEV_TX_BUSY;
+ }
+
+ param.data = 0;
+
+ if (adapter->vlgrp && vlan_tx_tag_present(skb)) {
+ vlan_tag = vlan_tx_tag_get(skb);
+ vlan_tag = (vlan_tag << 4) | (vlan_tag >> 13) |
+ ((vlan_tag >> 9) & 0x8);
+ param.csum.csumpl |= 1 << CSUM_PARAM_INSVLAG_SHIFT;
+ param.csum.csumpu |= (vlan_tag & CSUM_PARAM_VALANTAG_MASK) <<
+ CSUM_PARAM_VALAN_SHIFT;
+ }
+
+ tso = atl1_tso(adapter, skb, &param.tso);
+ if (tso < 0) {
+ spin_unlock_irqrestore(&adapter->lock, flags);
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
+ }
+
+ if (!tso) {
+ ret_val = atl1_tx_csum(adapter, skb, &param.csum);
+ if (ret_val < 0) {
+ spin_unlock_irqrestore(&adapter->lock, flags);
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
+ }
+ }
+
+ val = (param.csum.csumpl >> CSUM_PARAM_SEGMENT_SHIFT) &
+ CSUM_PARAM_SEGMENT_MASK;
+ atl1_tx_map(adapter, skb, 1 == val);
+ atl1_tx_queue(adapter, count, &param);
+ netdev->trans_start = jiffies;
+ spin_unlock_irqrestore(&adapter->lock, flags);
+ atl1_update_mailbox(adapter);
+ return NETDEV_TX_OK;
+}
+
+/*
+ * atl1_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 *atl1_get_stats(struct net_device *netdev)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ return &adapter->net_stats;
+}
+
+/*
+ * atl1_clean_rx_ring - Free RFD Buffers
+ * @adapter: board private structure
+ */
+static void atl1_clean_rx_ring(struct atl1_adapter *adapter)
+{
+ struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring;
+ struct atl1_rrd_ring *rrd_ring = &adapter->rrd_ring;
+ struct atl1_buffer *buffer_info;
+ struct pci_dev *pdev = adapter->pdev;
+ unsigned long size;
+ unsigned int i;
+
+ /* Free all the Rx ring sk_buffs */
+ for (i = 0; i < rfd_ring->count; i++) {
+ buffer_info = &rfd_ring->buffer_info[i];
+ if (buffer_info->dma) {
+ pci_unmap_page(pdev,
+ buffer_info->dma,
+ buffer_info->length,
+ PCI_DMA_FROMDEVICE);
+ buffer_info->dma = 0;
+ }
+ if (buffer_info->skb) {
+ dev_kfree_skb(buffer_info->skb);
+ buffer_info->skb = NULL;
+ }
+ }
+
+ size = sizeof(struct atl1_buffer) * rfd_ring->count;
+ memset(rfd_ring->buffer_info, 0, size);
+
+ /* Zero out the descriptor ring */
+ memset(rfd_ring->desc, 0, rfd_ring->size);
+
+ rfd_ring->next_to_clean = 0;
+ atomic_set(&rfd_ring->next_to_use, 0);
+
+ rrd_ring->next_to_use = 0;
+ atomic_set(&rrd_ring->next_to_clean, 0);
+}
+
+/*
+ * atl1_clean_tx_ring - Free Tx Buffers
+ * @adapter: board private structure
+ */
+static void atl1_clean_tx_ring(struct atl1_adapter *adapter)
+{
+ struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring;
+ struct atl1_buffer *buffer_info;
+ struct pci_dev *pdev = adapter->pdev;
+ unsigned long size;
+ unsigned int i;
+
+ /* Free all the Tx ring sk_buffs */
+ for (i = 0; i < tpd_ring->count; i++) {
+ buffer_info = &tpd_ring->buffer_info[i];
+ if (buffer_info->dma) {
+ pci_unmap_page(pdev, buffer_info->dma,
+ buffer_info->length, PCI_DMA_TODEVICE);
+ buffer_info->dma = 0;
+ }
+ }
+
+ for (i = 0; i < tpd_ring->count; i++) {
+ buffer_info = &tpd_ring->buffer_info[i];
+ if (buffer_info->skb) {
+ dev_kfree_skb_any(buffer_info->skb);
+ buffer_info->skb = NULL;
+ }
+ }
+
+ size = sizeof(struct atl1_buffer) * tpd_ring->count;
+ memset(tpd_ring->buffer_info, 0, size);
+
+ /* Zero out the descriptor ring */
+ memset(tpd_ring->desc, 0, tpd_ring->size);
+
+ atomic_set(&tpd_ring->next_to_use, 0);
+ atomic_set(&tpd_ring->next_to_clean, 0);
+}
+
+/*
+ * atl1_free_ring_resources - Free Tx / RX descriptor Resources
+ * @adapter: board private structure
+ *
+ * Free all transmit software resources
+ */
+void atl1_free_ring_resources(struct atl1_adapter *adapter)
+{
+ struct pci_dev *pdev = adapter->pdev;
+ struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring;
+ struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring;
+ struct atl1_rrd_ring *rrd_ring = &adapter->rrd_ring;
+ struct atl1_ring_header *ring_header = &adapter->ring_header;
+
+ atl1_clean_tx_ring(adapter);
+ atl1_clean_rx_ring(adapter);
+
+ kfree(tpd_ring->buffer_info);
+ pci_free_consistent(pdev, ring_header->size, ring_header->desc,
+ ring_header->dma);
+
+ tpd_ring->buffer_info = NULL;
+ tpd_ring->desc = NULL;
+ tpd_ring->dma = 0;
+
+ rfd_ring->buffer_info = NULL;
+ rfd_ring->desc = NULL;
+ rfd_ring->dma = 0;
+
+ rrd_ring->desc = NULL;
+ rrd_ring->dma = 0;
+}
+
+s32 atl1_up(struct atl1_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+ int err;
+ int irq_flags = IRQF_SAMPLE_RANDOM;
+
+ /* hardware has been reset, we need to reload some things */
+ atl1_set_multi(netdev);
+ atl1_restore_vlan(adapter);
+ err = atl1_alloc_rx_buffers(adapter);
+ if (unlikely(!err)) /* no RX BUFFER allocated */
+ return -ENOMEM;
+
+ if (unlikely(atl1_configure(adapter))) {
+ err = -EIO;
+ goto err_up;
+ }
+
+ err = pci_enable_msi(adapter->pdev);
+ if (err) {
+ dev_info(&adapter->pdev->dev,
+ "Unable to enable MSI: %d\n", err);
+ irq_flags |= IRQF_SHARED;
+ }
+
+ err = request_irq(adapter->pdev->irq, &atl1_intr, irq_flags,
+ netdev->name, netdev);
+ if (unlikely(err))
+ goto err_up;
+
+ mod_timer(&adapter->watchdog_timer, jiffies);
+ atl1_irq_enable(adapter);
+ atl1_check_link(adapter);
+ return 0;
+
+ /* FIXME: unreachable code! -- CHS */
+ /* free irq disable any interrupt */
+ iowrite32(0, adapter->hw.hw_addr + REG_IMR);
+ free_irq(adapter->pdev->irq, netdev);
+
+err_up:
+ pci_disable_msi(adapter->pdev);
+ /* free rx_buffers */
+ atl1_clean_rx_ring(adapter);
+ return err;
+}
+
+void atl1_down(struct atl1_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+
+ del_timer_sync(&adapter->watchdog_timer);
+ del_timer_sync(&adapter->phy_config_timer);
+ adapter->phy_timer_pending = false;
+
+ atl1_irq_disable(adapter);
+ free_irq(adapter->pdev->irq, netdev);
+ pci_disable_msi(adapter->pdev);
+ atl1_reset_hw(&adapter->hw);
+ adapter->cmb.cmb->int_stats = 0;
+
+ adapter->link_speed = SPEED_0;
+ adapter->link_duplex = -1;
+ netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
+
+ atl1_clean_tx_ring(adapter);
+ atl1_clean_rx_ring(adapter);
+}
+
+/*
+ * atl1_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 atl1_change_mtu(struct net_device *netdev, int new_mtu)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ int old_mtu = netdev->mtu;
+ int max_frame = new_mtu + ENET_HEADER_SIZE + ETHERNET_FCS_SIZE;
+
+ if ((max_frame < MINIMUM_ETHERNET_FRAME_SIZE) ||
+ (max_frame > MAX_JUMBO_FRAME_SIZE)) {
+ printk(KERN_WARNING "%s: invalid MTU setting\n",
+ atl1_driver_name);
+ return -EINVAL;
+ }
+
+ adapter->hw.max_frame_size = max_frame;
+ adapter->hw.tx_jumbo_task_th = (max_frame + 7) >> 3;
+ adapter->rx_buffer_len = (max_frame + 7) & ~7;
+ adapter->hw.rx_jumbo_th = adapter->rx_buffer_len / 8;
+
+ netdev->mtu = new_mtu;
+ if ((old_mtu != new_mtu) && netif_running(netdev)) {
+ atl1_down(adapter);
+ atl1_up(adapter);
+ }
+
+ return 0;
+}
+
+/*
+ * atl1_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 atl1_set_mac(struct net_device *netdev, void *p)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ struct sockaddr *addr = p;
+
+ if (netif_running(netdev))
+ return -EBUSY;
+
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EADDRNOTAVAIL;
+
+ memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
+ memcpy(adapter->hw.mac_addr, addr->sa_data, netdev->addr_len);
+
+ atl1_set_mac_addr(&adapter->hw);
+ return 0;
+}
+
+/*
+ * atl1_watchdog - Timer Call-back
+ * @data: pointer to netdev cast into an unsigned long
+ */
+static void atl1_watchdog(unsigned long data)
+{
+ struct atl1_adapter *adapter = (struct atl1_adapter *)data;
+
+ /* Reset the timer */
+ mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ);
+}
+
+static int mdio_read(struct net_device *netdev, int phy_id, int reg_num)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ u16 result;
+
+ atl1_read_phy_reg(&adapter->hw, reg_num & 0x1f, &result);
+
+ return result;
+}
+
+static void mdio_write(struct net_device *netdev, int phy_id, int reg_num, int val)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+
+ atl1_write_phy_reg(&adapter->hw, reg_num, val);
+}
+
+/*
+ * atl1_mii_ioctl -
+ * @netdev:
+ * @ifreq:
+ * @cmd:
+ */
+static int atl1_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ unsigned long flags;
+ int retval;
+
+ if (!netif_running(netdev))
+ return -EINVAL;
+
+ spin_lock_irqsave(&adapter->lock, flags);
+ retval = generic_mii_ioctl(&adapter->mii, if_mii(ifr), cmd, NULL);
+ spin_unlock_irqrestore(&adapter->lock, flags);
+
+ return retval;
+}
+
+/*
+ * atl1_ioctl -
+ * @netdev:
+ * @ifreq:
+ * @cmd:
+ */
+static int atl1_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+ switch (cmd) {
+ case SIOCGMIIPHY:
+ case SIOCGMIIREG:
+ case SIOCSMIIREG:
+ return atl1_mii_ioctl(netdev, ifr, cmd);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+/*
+ * atl1_tx_timeout - Respond to a Tx Hang
+ * @netdev: network interface device structure
+ */
+static void atl1_tx_timeout(struct net_device *netdev)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ /* Do the reset outside of interrupt context */
+ schedule_work(&adapter->tx_timeout_task);
+}
+
+/*
+ * atl1_phy_config - Timer Call-back
+ * @data: pointer to netdev cast into an unsigned long
+ */
+static void atl1_phy_config(unsigned long data)
+{
+ struct atl1_adapter *adapter = (struct atl1_adapter *)data;
+ struct atl1_hw *hw = &adapter->hw;
+ unsigned long flags;
+
+ spin_lock_irqsave(&adapter->lock, flags);
+ adapter->phy_timer_pending = false;
+ atl1_write_phy_reg(hw, MII_ADVERTISE, hw->mii_autoneg_adv_reg);
+ atl1_write_phy_reg(hw, MII_AT001_CR, hw->mii_1000t_ctrl_reg);
+ atl1_write_phy_reg(hw, MII_BMCR, MII_CR_RESET | MII_CR_AUTO_NEG_EN);
+ spin_unlock_irqrestore(&adapter->lock, flags);
+}
+
+int atl1_reset(struct atl1_adapter *adapter)
+{
+ int ret;
+
+ ret = atl1_reset_hw(&adapter->hw);
+ if (ret != ATL1_SUCCESS)
+ return ret;
+ return atl1_init_hw(&adapter->hw);
+}
+
+/*
+ * atl1_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 atl1_open(struct net_device *netdev)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ int err;
+
+ /* allocate transmit descriptors */
+ err = atl1_setup_ring_resources(adapter);
+ if (err)
+ return err;
+
+ err = atl1_up(adapter);
+ if (err)
+ goto err_up;
+
+ return 0;
+
+err_up:
+ atl1_reset(adapter);
+ return err;
+}
+
+/*
+ * atl1_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 atl1_close(struct net_device *netdev)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ atl1_down(adapter);
+ atl1_free_ring_resources(adapter);
+ return 0;
+}
+
+/*
+ * If TPD Buffer size equal to 0, PCIE DMAR_TO_INT
+ * will assert. We do soft reset <0x1400=1> according
+ * with the SPEC. BUT, it seemes that PCIE or DMA
+ * state-machine will not be reset. DMAR_TO_INT will
+ * assert again and again.
+ */
+static void atl1_tx_timeout_task(struct work_struct *work)
+{
+ struct atl1_adapter *adapter =
+ container_of(work, struct atl1_adapter, tx_timeout_task);
+ struct net_device *netdev = adapter->netdev;
+
+ netif_device_detach(netdev);
+ atl1_down(adapter);
+ atl1_up(adapter);
+ netif_device_attach(netdev);
+}
+
+/*
+ * atl1_link_chg_task - deal with link change event Out of interrupt context
+ */
+static void atl1_link_chg_task(struct work_struct *work)
+{
+ struct atl1_adapter *adapter =
+ container_of(work, struct atl1_adapter, link_chg_task);
+ unsigned long flags;
+
+ spin_lock_irqsave(&adapter->lock, flags);
+ atl1_check_link(adapter);
+ spin_unlock_irqrestore(&adapter->lock, flags);
+}
+
+/*
+ * atl1_pcie_patch - Patch for PCIE module
+ */
+static void atl1_pcie_patch(struct atl1_adapter *adapter)
+{
+ u32 value;
+ value = 0x6500;
+ iowrite32(value, adapter->hw.hw_addr + 0x12FC);
+ /* pcie flow control mode change */
+ value = ioread32(adapter->hw.hw_addr + 0x1008);
+ value |= 0x8000;
+ iowrite32(value, adapter->hw.hw_addr + 0x1008);
+}
+
+/*
+ * When ACPI resume on some VIA MotherBoard, the Interrupt Disable bit/0x400
+ * on PCI Command register is disable.
+ * The function enable this bit.
+ * Brackett, 2006/03/15
+ */
+static void atl1_via_workaround(struct atl1_adapter *adapter)
+{
+ unsigned long value;
+
+ value = ioread16(adapter->hw.hw_addr + PCI_COMMAND);
+ if (value & PCI_COMMAND_INTX_DISABLE)
+ value &= ~PCI_COMMAND_INTX_DISABLE;
+ iowrite32(value, adapter->hw.hw_addr + PCI_COMMAND);
+}
+
+/*
+ * atl1_probe - Device Initialization Routine
+ * @pdev: PCI device information struct
+ * @ent: entry in atl1_pci_tbl
+ *
+ * Returns 0 on success, negative on failure
+ *
+ * atl1_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 atl1_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ struct net_device *netdev;
+ struct atl1_adapter *adapter;
+ static int cards_found = 0;
+ bool pci_using_64 = true;
+ int err;
+
+ err = pci_enable_device(pdev);
+ if (err)
+ return err;
+
+ err = pci_set_dma_mask(pdev, DMA_64BIT_MASK);
+ if (err) {
+ err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ if (err) {
+ printk(KERN_DEBUG
+ "%s: no usable DMA configuration, aborting\n",
+ atl1_driver_name);
+ goto err_dma;
+ }
+ pci_using_64 = false;
+ }
+ /* Mark all PCI regions associated with PCI device
+ * pdev as being reserved by owner atl1_driver_name
+ */
+ err = pci_request_regions(pdev, atl1_driver_name);
+ if (err)
+ goto err_request_regions;
+
+ /* Enables bus-mastering on the device and calls
+ * pcibios_set_master to do the needed arch specific settings
+ */
+ pci_set_master(pdev);
+
+ netdev = alloc_etherdev(sizeof(struct atl1_adapter));
+ if (!netdev) {
+ err = -ENOMEM;
+ goto err_alloc_etherdev;
+ }
+ SET_MODULE_OWNER(netdev);
+ SET_NETDEV_DEV(netdev, &pdev->dev);
+
+ pci_set_drvdata(pdev, netdev);
+ adapter = netdev_priv(netdev);
+ adapter->netdev = netdev;
+ adapter->pdev = pdev;
+ adapter->hw.back = adapter;
+
+ adapter->hw.hw_addr = pci_iomap(pdev, 0, 0);
+ if (!adapter->hw.hw_addr) {
+ err = -EIO;
+ goto err_pci_iomap;
+ }
+ /* get device revision number */
+ adapter->hw.dev_rev = ioread16(adapter->hw.hw_addr + (REG_MASTER_CTRL + 2));
+
+ /* set default ring resource counts */
+ adapter->rfd_ring.count = adapter->rrd_ring.count = ATL1_DEFAULT_RFD;
+ adapter->tpd_ring.count = ATL1_DEFAULT_TPD;
+
+ adapter->mii.dev = netdev;
+ adapter->mii.mdio_read = mdio_read;
+ adapter->mii.mdio_write = mdio_write;
+ adapter->mii.phy_id_mask = 0x1f;
+ adapter->mii.reg_num_mask = 0x1f;
+
+ netdev->open = &atl1_open;
+ netdev->stop = &atl1_close;
+ netdev->hard_start_xmit = &atl1_xmit_frame;
+ netdev->get_stats = &atl1_get_stats;
+ netdev->set_multicast_list = &atl1_set_multi;
+ netdev->set_mac_address = &atl1_set_mac;
+ netdev->change_mtu = &atl1_change_mtu;
+ netdev->do_ioctl = &atl1_ioctl;
+ netdev->tx_timeout = &atl1_tx_timeout;
+ netdev->watchdog_timeo = 5 * HZ;
+ netdev->vlan_rx_register = atl1_vlan_rx_register;
+ netdev->vlan_rx_add_vid = atl1_vlan_rx_add_vid;
+ netdev->vlan_rx_kill_vid = atl1_vlan_rx_kill_vid;
+ netdev->ethtool_ops = &atl1_ethtool_ops;
+ adapter->bd_number = cards_found;
+ adapter->pci_using_64 = pci_using_64;
+
+ /* setup the private structure */
+ err = atl1_sw_init(adapter);
+ if (err)
+ goto err_common;
+
+ netdev->features = NETIF_F_HW_CSUM;
+ netdev->features |= NETIF_F_SG;
+ netdev->features |= (NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX);
+
+ /*
+ * FIXME - Until tso performance gets fixed, disable the feature.
+ * Enable it with ethtool -K if desired.
+ */
+ /* netdev->features |= NETIF_F_TSO; */
+
+ if (pci_using_64)
+ netdev->features |= NETIF_F_HIGHDMA;
+
+ netdev->features |= NETIF_F_LLTX;
+
+ /*
+ * patch for some L1 of old version,
+ * the final version of L1 may not need these
+ * patches
+ */
+ /* atl1_pcie_patch(adapter); */
+
+ /* really reset GPHY core */
+ iowrite16(0, adapter->hw.hw_addr + REG_GPHY_ENABLE);
+
+ /*
+ * reset the controller to
+ * put the device in a known good starting state
+ */
+ if (atl1_reset_hw(&adapter->hw)) {
+ err = -EIO;
+ goto err_common;
+ }
+
+ /* copy the MAC address out of the EEPROM */
+ atl1_read_mac_addr(&adapter->hw);
+ memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len);
+
+ if (!is_valid_ether_addr(netdev->dev_addr)) {
+ err = -EIO;
+ goto err_common;
+ }
+
+ atl1_check_options(adapter);
+
+ /* pre-init the MAC, and setup link */
+ err = atl1_init_hw(&adapter->hw);
+ if (err) {
+ err = -EIO;
+ goto err_common;
+ }
+
+ atl1_pcie_patch(adapter);
+ /* assume we have no link for now */
+ netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
+
+ init_timer(&adapter->watchdog_timer);
+ adapter->watchdog_timer.function = &atl1_watchdog;
+ adapter->watchdog_timer.data = (unsigned long)adapter;
+
+ init_timer(&adapter->phy_config_timer);
+ adapter->phy_config_timer.function = &atl1_phy_config;
+ adapter->phy_config_timer.data = (unsigned long)adapter;
+ adapter->phy_timer_pending = false;
+
+ INIT_WORK(&adapter->tx_timeout_task, atl1_tx_timeout_task);
+
+ INIT_WORK(&adapter->link_chg_task, atl1_link_chg_task);
+
+ INIT_WORK(&adapter->pcie_dma_to_rst_task, atl1_tx_timeout_task);
+
+ err = register_netdev(netdev);
+ if (err)
+ goto err_common;
+
+ cards_found++;
+ atl1_via_workaround(adapter);
+ return 0;
+
+err_common:
+ pci_iounmap(pdev, adapter->hw.hw_addr);
+err_pci_iomap:
+ free_netdev(netdev);
+err_alloc_etherdev:
+ pci_release_regions(pdev);
+err_dma:
+err_request_regions:
+ pci_disable_device(pdev);
+ return err;
+}
+
+/*
+ * atl1_remove - Device Removal Routine
+ * @pdev: PCI device information struct
+ *
+ * atl1_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 atl1_remove(struct pci_dev *pdev)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct atl1_adapter *adapter;
+ /* Device not available. Return. */
+ if (!netdev)
+ return;
+
+ adapter = netdev_priv(netdev);
+ iowrite16(0, adapter->hw.hw_addr + REG_GPHY_ENABLE);
+ unregister_netdev(netdev);
+ pci_iounmap(pdev, adapter->hw.hw_addr);
+ pci_release_regions(pdev);
+ free_netdev(netdev);
+ pci_disable_device(pdev);
+}
+
+#ifdef CONFIG_PM
+static int atl1_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ struct atl1_hw *hw = &adapter->hw;
+ u32 ctrl = 0;
+ u32 wufc = adapter->wol;
+
+ netif_device_detach(netdev);
+ if (netif_running(netdev))
+ atl1_down(adapter);
+
+ atl1_read_phy_reg(hw, MII_BMSR, (u16 *) & ctrl);
+ atl1_read_phy_reg(hw, MII_BMSR, (u16 *) & ctrl);
+ if (ctrl & BMSR_LSTATUS)
+ wufc &= ~ATL1_WUFC_LNKC;
+
+ /* reduce speed to 10/100M */
+ if (wufc) {
+ atl1_phy_enter_power_saving(hw);
+ /* if resume, let driver to re- setup link */
+ hw->phy_configured = false;
+ atl1_set_mac_addr(hw);
+ atl1_set_multi(netdev);
+
+ ctrl = 0;
+ /* turn on magic packet wol */
+ if (wufc & ATL1_WUFC_MAG)
+ ctrl = WOL_MAGIC_EN | WOL_MAGIC_PME_EN;
+
+ /* turn on Link change WOL */
+ if (wufc & ATL1_WUFC_LNKC)
+ ctrl |= (WOL_LINK_CHG_EN | WOL_LINK_CHG_PME_EN);
+ iowrite32(ctrl, hw->hw_addr + REG_WOL_CTRL);
+
+ /* turn on all-multi mode if wake on multicast is enabled */
+ ctrl = ioread32(hw->hw_addr + REG_MAC_CTRL);
+ ctrl &= ~MAC_CTRL_DBG;
+ ctrl &= ~MAC_CTRL_PROMIS_EN;
+ if (wufc & ATL1_WUFC_MC)
+ ctrl |= MAC_CTRL_MC_ALL_EN;
+ else
+ ctrl &= ~MAC_CTRL_MC_ALL_EN;
+
+ /* turn on broadcast mode if wake on-BC is enabled */
+ if (wufc & ATL1_WUFC_BC)
+ ctrl |= MAC_CTRL_BC_EN;
+ else
+ ctrl &= ~MAC_CTRL_BC_EN;
+
+ /* enable RX */
+ ctrl |= MAC_CTRL_RX_EN;
+ iowrite32(ctrl, hw->hw_addr + REG_MAC_CTRL);
+ pci_enable_wake(pdev, PCI_D3hot, 1);
+ pci_enable_wake(pdev, PCI_D3cold, 1); /* 4 == D3 cold */
+ } else {
+ iowrite32(0, hw->hw_addr + REG_WOL_CTRL);
+ pci_enable_wake(pdev, PCI_D3hot, 0);
+ pci_enable_wake(pdev, PCI_D3cold, 0); /* 4 == D3 cold */
+ }
+
+ pci_save_state(pdev);
+ pci_disable_device(pdev);
+
+ pci_set_power_state(pdev, PCI_D3hot);
+
+ return 0;
+}
+
+static int atl1_resume(struct pci_dev *pdev)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ u32 ret_val;
+
+ pci_set_power_state(pdev, 0);
+ pci_restore_state(pdev);
+
+ ret_val = pci_enable_device(pdev);
+ pci_enable_wake(pdev, PCI_D3hot, 0);
+ pci_enable_wake(pdev, PCI_D3cold, 0);
+
+ iowrite32(0, adapter->hw.hw_addr + REG_WOL_CTRL);
+ atl1_reset(adapter);
+
+ if (netif_running(netdev))
+ atl1_up(adapter);
+ netif_device_attach(netdev);
+
+ atl1_via_workaround(adapter);
+
+ return 0;
+}
+#else
+#define atl1_suspend NULL
+#define atl1_resume NULL
+#endif
+
+static struct pci_driver atl1_driver = {
+ .name = atl1_driver_name,
+ .id_table = atl1_pci_tbl,
+ .probe = atl1_probe,
+ .remove = __devexit_p(atl1_remove),
+ /* Power Managment Hooks */
+ /* probably broken right now -- CHS */
+ .suspend = atl1_suspend,
+ .resume = atl1_resume
+};
+
+/*
+ * atl1_exit_module - Driver Exit Cleanup Routine
+ *
+ * atl1_exit_module is called just before the driver is removed
+ * from memory.
+ */
+static void __exit atl1_exit_module(void)
+{
+ pci_unregister_driver(&atl1_driver);
+}
+
+/*
+ * atl1_init_module - Driver Registration Routine
+ *
+ * atl1_init_module is the first routine called when the driver is
+ * loaded. All it does is register with the PCI subsystem.
+ */
+static int __init atl1_init_module(void)
+{
+ printk(KERN_INFO "%s - version %s\n", atl1_driver_string, DRIVER_VERSION);
+ printk(KERN_INFO "%s\n", atl1_copyright);
+ return pci_register_driver(&atl1_driver);
+}
+
+module_init(atl1_init_module);
+module_exit(atl1_exit_module);
diff --git a/drivers/net/atl1/atl1_param.c b/drivers/net/atl1/atl1_param.c
new file mode 100644
index 00000000000..c407214339f
--- /dev/null
+++ b/drivers/net/atl1/atl1_param.c
@@ -0,0 +1,206 @@
+/*
+ * Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved.
+ * Copyright(c) 2006 Chris Snook <csnook@redhat.com>
+ * Copyright(c) 2006 Jay Cliburn <jcliburn@gmail.com>
+ *
+ * Derived from Intel e1000 driver
+ * Copyright(c) 1999 - 2005 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.
+ */
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/moduleparam.h>
+#include "atl1.h"
+
+/*
+ * This is the only thing that needs to be changed to adjust the
+ * maximum number of ports that the driver can manage.
+ */
+#define ATL1_MAX_NIC 4
+
+#define OPTION_UNSET -1
+#define OPTION_DISABLED 0
+#define OPTION_ENABLED 1
+
+#define ATL1_PARAM_INIT { [0 ... ATL1_MAX_NIC] = OPTION_UNSET }
+
+/*
+ * Interrupt Moderate Timer in units of 2 us
+ *
+ * Valid Range: 10-65535
+ *
+ * Default Value: 100 (200us)
+ */
+static int __devinitdata int_mod_timer[ATL1_MAX_NIC+1] = ATL1_PARAM_INIT;
+static int num_int_mod_timer = 0;
+module_param_array_named(int_mod_timer, int_mod_timer, int, &num_int_mod_timer, 0);
+MODULE_PARM_DESC(int_mod_timer, "Interrupt moderator timer");
+
+/*
+ * flash_vendor
+ *
+ * Valid Range: 0-2
+ *
+ * 0 - Atmel
+ * 1 - SST
+ * 2 - ST
+ *
+ * Default Value: 0
+ */
+static int __devinitdata flash_vendor[ATL1_MAX_NIC+1] = ATL1_PARAM_INIT;
+static int num_flash_vendor = 0;
+module_param_array_named(flash_vendor, flash_vendor, int, &num_flash_vendor, 0);
+MODULE_PARM_DESC(flash_vendor, "SPI flash vendor");
+
+#define DEFAULT_INT_MOD_CNT 100 /* 200us */
+#define MAX_INT_MOD_CNT 65000
+#define MIN_INT_MOD_CNT 50
+
+#define FLASH_VENDOR_DEFAULT 0
+#define FLASH_VENDOR_MIN 0
+#define FLASH_VENDOR_MAX 2
+
+struct atl1_option {
+ enum { enable_option, range_option, list_option } type;
+ char *name;
+ char *err;
+ int def;
+ union {
+ struct { /* range_option info */
+ int min;
+ int max;
+ } r;
+ struct { /* list_option info */
+ int nr;
+ struct atl1_opt_list {
+ int i;
+ char *str;
+ } *p;
+ } l;
+ } arg;
+};
+
+static int __devinit atl1_validate_option(int *value, struct atl1_option *opt)
+{
+ if (*value == OPTION_UNSET) {
+ *value = opt->def;
+ return 0;
+ }
+
+ switch (opt->type) {
+ case enable_option:
+ switch (*value) {
+ case OPTION_ENABLED:
+ printk(KERN_INFO "%s: %s Enabled\n", atl1_driver_name,
+ opt->name);
+ return 0;
+ case OPTION_DISABLED:
+ printk(KERN_INFO "%s: %s Disabled\n", atl1_driver_name,
+ opt->name);
+ return 0;
+ }
+ break;
+ case range_option:
+ if (*value >= opt->arg.r.min && *value <= opt->arg.r.max) {
+ printk(KERN_INFO "%s: %s set to %i\n",
+ atl1_driver_name, opt->name, *value);
+ return 0;
+ }
+ break;
+ case list_option:{
+ int i;
+ struct atl1_opt_list *ent;
+
+ for (i = 0; i < opt->arg.l.nr; i++) {
+ ent = &opt->arg.l.p[i];
+ if (*value == ent->i) {
+ if (ent->str[0] != '\0')
+ printk(KERN_INFO "%s: %s\n",
+ atl1_driver_name, ent->str);
+ return 0;
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ printk(KERN_INFO "%s: invalid %s specified (%i) %s\n",
+ atl1_driver_name, opt->name, *value, opt->err);
+ *value = opt->def;
+ return -1;
+}
+
+/*
+ * atl1_check_options - Range Checking for Command Line Parameters
+ * @adapter: board private structure
+ *
+ * This routine checks all command line parameters for valid user
+ * input. If an invalid value is given, or if no user specified
+ * value exists, a default value is used. The final value is stored
+ * in a variable in the adapter structure.
+ */
+void __devinit atl1_check_options(struct atl1_adapter *adapter)
+{
+ int bd = adapter->bd_number;
+ if (bd >= ATL1_MAX_NIC) {
+ printk(KERN_NOTICE "%s: warning: no configuration for board #%i\n",
+ atl1_driver_name, bd);
+ printk(KERN_NOTICE "%s: using defaults for all values\n",
+ atl1_driver_name);
+ }
+ { /* Interrupt Moderate Timer */
+ struct atl1_option opt = {
+ .type = range_option,
+ .name = "Interrupt Moderator Timer",
+ .err = "using default of "
+ __MODULE_STRING(DEFAULT_INT_MOD_CNT),
+ .def = DEFAULT_INT_MOD_CNT,
+ .arg = {.r =
+ {.min = MIN_INT_MOD_CNT,.max = MAX_INT_MOD_CNT}}
+ };
+ int val;
+ if (num_int_mod_timer > bd) {
+ val = int_mod_timer[bd];
+ atl1_validate_option(&val, &opt);
+ adapter->imt = (u16) val;
+ } else
+ adapter->imt = (u16) (opt.def);
+ }
+
+ { /* Flash Vendor */
+ struct atl1_option opt = {
+ .type = range_option,
+ .name = "SPI Flash Vendor",
+ .err = "using default of "
+ __MODULE_STRING(FLASH_VENDOR_DEFAULT),
+ .def = DEFAULT_INT_MOD_CNT,
+ .arg = {.r =
+ {.min = FLASH_VENDOR_MIN,.max =
+ FLASH_VENDOR_MAX}}
+ };
+ int val;
+ if (num_flash_vendor > bd) {
+ val = flash_vendor[bd];
+ atl1_validate_option(&val, &opt);
+ adapter->hw.flash_vendor = (u8) val;
+ } else
+ adapter->hw.flash_vendor = (u8) (opt.def);
+ }
+}
diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c
index f0b6879a1c7..69ae229b680 100644
--- a/drivers/net/au1000_eth.c
+++ b/drivers/net/au1000_eth.c
@@ -37,7 +37,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/errno.h>
diff --git a/drivers/net/b44.c b/drivers/net/b44.c
index 303a8d94ad4..aaada572732 100644
--- a/drivers/net/b44.c
+++ b/drivers/net/b44.c
@@ -59,7 +59,6 @@
#define B44_DEF_TX_RING_PENDING (B44_TX_RING_SIZE - 1)
#define B44_TX_RING_BYTES (sizeof(struct dma_desc) * \
B44_TX_RING_SIZE)
-#define B44_DMA_MASK 0x3fffffff
#define TX_RING_GAP(BP) \
(B44_TX_RING_SIZE - (BP)->tx_pending)
@@ -665,7 +664,7 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
/* Hardware bug work-around, the chip is unable to do PCI DMA
to/from anything above 1GB :-( */
if (dma_mapping_error(mapping) ||
- mapping + RX_PKT_BUF_SZ > B44_DMA_MASK) {
+ mapping + RX_PKT_BUF_SZ > DMA_30BIT_MASK) {
/* Sigh... */
if (!dma_mapping_error(mapping))
pci_unmap_single(bp->pdev, mapping, RX_PKT_BUF_SZ,PCI_DMA_FROMDEVICE);
@@ -677,7 +676,7 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
RX_PKT_BUF_SZ,
PCI_DMA_FROMDEVICE);
if (dma_mapping_error(mapping) ||
- mapping + RX_PKT_BUF_SZ > B44_DMA_MASK) {
+ mapping + RX_PKT_BUF_SZ > DMA_30BIT_MASK) {
if (!dma_mapping_error(mapping))
pci_unmap_single(bp->pdev, mapping, RX_PKT_BUF_SZ,PCI_DMA_FROMDEVICE);
dev_kfree_skb_any(skb);
@@ -721,7 +720,7 @@ static void b44_recycle_rx(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
struct ring_info *src_map, *dest_map;
struct rx_header *rh;
int dest_idx;
- u32 ctrl;
+ __le32 ctrl;
dest_idx = dest_idx_unmasked & (B44_RX_RING_SIZE - 1);
dest_desc = &bp->rx_ring[dest_idx];
@@ -783,7 +782,7 @@ static int b44_rx(struct b44 *bp, int budget)
RX_PKT_BUF_SZ,
PCI_DMA_FROMDEVICE);
rh = (struct rx_header *) skb->data;
- len = cpu_to_le16(rh->len);
+ len = le16_to_cpu(rh->len);
if ((len > (RX_PKT_BUF_SZ - bp->rx_offset)) ||
(rh->flags & cpu_to_le16(RX_FLAG_ERRORS))) {
drop_it:
@@ -799,7 +798,7 @@ static int b44_rx(struct b44 *bp, int budget)
do {
udelay(2);
barrier();
- len = cpu_to_le16(rh->len);
+ len = le16_to_cpu(rh->len);
} while (len == 0 && i++ < 5);
if (len == 0)
goto drop_it;
@@ -988,7 +987,7 @@ static int b44_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
mapping = pci_map_single(bp->pdev, skb->data, len, PCI_DMA_TODEVICE);
- if (dma_mapping_error(mapping) || mapping + len > B44_DMA_MASK) {
+ if (dma_mapping_error(mapping) || mapping + len > DMA_30BIT_MASK) {
/* Chip can't handle DMA to/from >1GB, use bounce buffer */
if (!dma_mapping_error(mapping))
pci_unmap_single(bp->pdev, mapping, len, PCI_DMA_TODEVICE);
@@ -1000,7 +999,7 @@ static int b44_start_xmit(struct sk_buff *skb, struct net_device *dev)
mapping = pci_map_single(bp->pdev, bounce_skb->data,
len, PCI_DMA_TODEVICE);
- if (dma_mapping_error(mapping) || mapping + len > B44_DMA_MASK) {
+ if (dma_mapping_error(mapping) || mapping + len > DMA_30BIT_MASK) {
if (!dma_mapping_error(mapping))
pci_unmap_single(bp->pdev, mapping,
len, PCI_DMA_TODEVICE);
@@ -1227,7 +1226,7 @@ static int b44_alloc_consistent(struct b44 *bp)
DMA_BIDIRECTIONAL);
if (dma_mapping_error(rx_ring_dma) ||
- rx_ring_dma + size > B44_DMA_MASK) {
+ rx_ring_dma + size > DMA_30BIT_MASK) {
kfree(rx_ring);
goto out_err;
}
@@ -1254,7 +1253,7 @@ static int b44_alloc_consistent(struct b44 *bp)
DMA_TO_DEVICE);
if (dma_mapping_error(tx_ring_dma) ||
- tx_ring_dma + size > B44_DMA_MASK) {
+ tx_ring_dma + size > DMA_30BIT_MASK) {
kfree(tx_ring);
goto out_err;
}
@@ -1289,7 +1288,7 @@ static void b44_chip_reset(struct b44 *bp)
if (ssb_is_core_up(bp)) {
bw32(bp, B44_RCV_LAZY, 0);
bw32(bp, B44_ENET_CTRL, ENET_CTRL_DISABLE);
- b44_wait_bit(bp, B44_ENET_CTRL, ENET_CTRL_DISABLE, 100, 1);
+ b44_wait_bit(bp, B44_ENET_CTRL, ENET_CTRL_DISABLE, 200, 1);
bw32(bp, B44_DMATX_CTRL, 0);
bp->tx_prod = bp->tx_cons = 0;
if (br32(bp, B44_DMARX_STAT) & DMARX_STAT_EMASK) {
@@ -2061,7 +2060,7 @@ out:
static int b44_read_eeprom(struct b44 *bp, u8 *data)
{
long i;
- u16 *ptr = (u16 *) data;
+ __le16 *ptr = (__le16 *) data;
for (i = 0; i < 128; i += 2)
ptr[i / 2] = cpu_to_le16(readw(bp->regs + 4096 + i));
@@ -2151,13 +2150,13 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
pci_set_master(pdev);
- err = pci_set_dma_mask(pdev, (u64) B44_DMA_MASK);
+ err = pci_set_dma_mask(pdev, (u64) DMA_30BIT_MASK);
if (err) {
dev_err(&pdev->dev, "No usable DMA configuration, aborting.\n");
goto err_out_free_res;
}
- err = pci_set_consistent_dma_mask(pdev, (u64) B44_DMA_MASK);
+ err = pci_set_consistent_dma_mask(pdev, (u64) DMA_30BIT_MASK);
if (err) {
dev_err(&pdev->dev, "No usable DMA configuration, aborting.\n");
goto err_out_free_res;
diff --git a/drivers/net/b44.h b/drivers/net/b44.h
index 4944507fad2..18fc1333662 100644
--- a/drivers/net/b44.h
+++ b/drivers/net/b44.h
@@ -308,8 +308,8 @@
#define MII_TLEDCTRL_ENABLE 0x0040
struct dma_desc {
- u32 ctrl;
- u32 addr;
+ __le32 ctrl;
+ __le32 addr;
};
/* There are only 12 bits in the DMA engine for descriptor offsetting
@@ -327,9 +327,9 @@ struct dma_desc {
#define RX_COPY_THRESHOLD 256
struct rx_header {
- u16 len;
- u16 flags;
- u16 pad[12];
+ __le16 len;
+ __le16 flags;
+ __le16 pad[12];
};
#define RX_HEADER_LEN 28
diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c
index 4528ce9c4e4..c143304dcff 100644
--- a/drivers/net/bmac.c
+++ b/drivers/net/bmac.c
@@ -18,6 +18,7 @@
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/crc32.h>
+#include <linux/bitrev.h>
#include <asm/prom.h>
#include <asm/dbdma.h>
#include <asm/io.h>
@@ -140,7 +141,6 @@ static unsigned char *bmac_emergency_rxbuf;
+ (N_RX_RING + N_TX_RING + 4) * sizeof(struct dbdma_cmd) \
+ sizeof(struct sk_buff_head))
-static unsigned char bitrev(unsigned char b);
static int bmac_open(struct net_device *dev);
static int bmac_close(struct net_device *dev);
static int bmac_transmit_packet(struct sk_buff *skb, struct net_device *dev);
@@ -586,18 +586,6 @@ bmac_construct_rxbuff(struct sk_buff *skb, volatile struct dbdma_cmd *cp)
virt_to_bus(addr), 0);
}
-/* Bit-reverse one byte of an ethernet hardware address. */
-static unsigned char
-bitrev(unsigned char b)
-{
- int d = 0, i;
-
- for (i = 0; i < 8; ++i, b >>= 1)
- d = (d << 1) | (b & 1);
- return d;
-}
-
-
static void
bmac_init_tx_ring(struct bmac_data *bp)
{
@@ -1224,8 +1212,8 @@ bmac_get_station_address(struct net_device *dev, unsigned char *ea)
{
reset_and_select_srom(dev);
data = read_srom(dev, i + EnetAddressOffset/2, SROMAddressBits);
- ea[2*i] = bitrev(data & 0x0ff);
- ea[2*i+1] = bitrev((data >> 8) & 0x0ff);
+ ea[2*i] = bitrev8(data & 0x0ff);
+ ea[2*i+1] = bitrev8((data >> 8) & 0x0ff);
}
}
@@ -1315,7 +1303,7 @@ static int __devinit bmac_probe(struct macio_dev *mdev, const struct of_device_i
rev = addr[0] == 0 && addr[1] == 0xA0;
for (j = 0; j < 6; ++j)
- dev->dev_addr[j] = rev? bitrev(addr[j]): addr[j];
+ dev->dev_addr[j] = rev ? bitrev8(addr[j]): addr[j];
/* Enable chip without interrupts for now */
bmac_enable_and_reset_chip(dev);
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index ee7b75b976b..5a96d7611af 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -39,12 +39,9 @@
#include <linux/if_vlan.h>
#define BCM_VLAN 1
#endif
-#ifdef NETIF_F_TSO
#include <net/ip.h>
#include <net/tcp.h>
#include <net/checksum.h>
-#define BCM_TSO 1
-#endif
#include <linux/workqueue.h>
#include <linux/crc32.h>
#include <linux/prefetch.h>
@@ -1728,7 +1725,7 @@ bnx2_tx_int(struct bnx2 *bp)
tx_buf = &bp->tx_buf_ring[sw_ring_cons];
skb = tx_buf->skb;
-#ifdef BCM_TSO
+
/* partial BD completions possible with TSO packets */
if (skb_is_gso(skb)) {
u16 last_idx, last_ring_idx;
@@ -1744,7 +1741,7 @@ bnx2_tx_int(struct bnx2 *bp)
break;
}
}
-#endif
+
pci_unmap_single(bp->pdev, pci_unmap_addr(tx_buf, mapping),
skb_headlen(skb), PCI_DMA_TODEVICE);
@@ -4514,7 +4511,6 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
vlan_tag_flags |=
(TX_BD_FLAGS_VLAN_TAG | (vlan_tx_tag_get(skb) << 16));
}
-#ifdef BCM_TSO
if ((mss = skb_shinfo(skb)->gso_size) &&
(skb->len > (bp->dev->mtu + ETH_HLEN))) {
u32 tcp_opt_len, ip_tcp_len;
@@ -4547,7 +4543,6 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
}
else
-#endif
{
mss = 0;
}
@@ -5544,10 +5539,8 @@ static const struct ethtool_ops bnx2_ethtool_ops = {
.set_tx_csum = ethtool_op_set_tx_csum,
.get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
-#ifdef BCM_TSO
.get_tso = ethtool_op_get_tso,
.set_tso = bnx2_set_tso,
-#endif
.self_test_count = bnx2_self_test_count,
.self_test = bnx2_self_test,
.get_strings = bnx2_get_strings,
@@ -5954,8 +5947,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
* responding after a while.
*
* AMD believes this incompatibility is unique to the 5706, and
- * prefers to locally disable MSI rather than globally disabling it
- * using pci_msi_quirk.
+ * prefers to locally disable MSI rather than globally disabling it.
*/
if (CHIP_NUM(bp) == CHIP_NUM_5706 && disable_msi == 0) {
struct pci_dev *amd_8132 = NULL;
@@ -6104,9 +6096,7 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
#ifdef BCM_VLAN
dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
#endif
-#ifdef BCM_TSO
dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN;
-#endif
netif_carrier_off(bp->dev);
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index 32923162179..217a2eedee0 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -184,7 +184,7 @@ static int tlb_initialize(struct bonding *bond)
spin_lock_init(&(bond_info->tx_hashtbl_lock));
- new_hashtbl = kmalloc(size, GFP_KERNEL);
+ new_hashtbl = kzalloc(size, GFP_KERNEL);
if (!new_hashtbl) {
printk(KERN_ERR DRV_NAME
": %s: Error: Failed to allocate TLB hash table\n",
@@ -195,8 +195,6 @@ static int tlb_initialize(struct bonding *bond)
bond_info->tx_hashtbl = new_hashtbl;
- memset(bond_info->tx_hashtbl, 0, size);
-
for (i = 0; i < TLB_HASH_TABLE_SIZE; i++) {
tlb_init_table_entry(&bond_info->tx_hashtbl[i], 1);
}
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 6482aed4bb7..a7c8f98a890 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -35,7 +35,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/sched.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/interrupt.h>
@@ -1343,14 +1342,12 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
"inaccurate.\n", bond_dev->name, slave_dev->name);
}
- new_slave = kmalloc(sizeof(struct slave), GFP_KERNEL);
+ new_slave = kzalloc(sizeof(struct slave), GFP_KERNEL);
if (!new_slave) {
res = -ENOMEM;
goto err_undo_flags;
}
- memset(new_slave, 0, sizeof(struct slave));
-
/* save slave's original flags before calling
* netdev_set_master and dev_open
*/
@@ -3122,7 +3119,7 @@ static int bond_info_open(struct inode *inode, struct file *file)
return res;
}
-static struct file_operations bond_info_fops = {
+static const struct file_operations bond_info_fops = {
.owner = THIS_MODULE,
.open = bond_info_open,
.read = seq_read,
@@ -4704,6 +4701,7 @@ static int bond_check_params(struct bond_params *params)
static struct lock_class_key bonding_netdev_xmit_lock_key;
/* Create a new bond based on the specified name and bonding parameters.
+ * If name is NULL, obtain a suitable "bond%d" name for us.
* Caller must NOT hold rtnl_lock; we need to release it here before we
* set up our sysfs entries.
*/
@@ -4713,7 +4711,8 @@ int bond_create(char *name, struct bond_params *params, struct bonding **newbond
int res;
rtnl_lock();
- bond_dev = alloc_netdev(sizeof(struct bonding), name, ether_setup);
+ bond_dev = alloc_netdev(sizeof(struct bonding), name ? name : "",
+ ether_setup);
if (!bond_dev) {
printk(KERN_ERR DRV_NAME
": %s: eek! can't alloc netdev!\n",
@@ -4722,6 +4721,12 @@ int bond_create(char *name, struct bond_params *params, struct bonding **newbond
goto out_rtnl;
}
+ if (!name) {
+ res = dev_alloc_name(bond_dev, "bond%d");
+ if (res < 0)
+ goto out_netdev;
+ }
+
/* bond_init() must be called after dev_alloc_name() (for the
* /proc files), but before register_netdevice(), because we
* need to set function pointers.
@@ -4748,14 +4753,19 @@ int bond_create(char *name, struct bond_params *params, struct bonding **newbond
rtnl_unlock(); /* allows sysfs registration of net device */
res = bond_create_sysfs_entry(bond_dev->priv);
- goto done;
+ if (res < 0) {
+ rtnl_lock();
+ goto out_bond;
+ }
+
+ return 0;
+
out_bond:
bond_deinit(bond_dev);
out_netdev:
free_netdev(bond_dev);
out_rtnl:
rtnl_unlock();
-done:
return res;
}
@@ -4763,7 +4773,6 @@ static int __init bonding_init(void)
{
int i;
int res;
- char new_bond_name[8]; /* Enough room for 999 bonds at init. */
printk(KERN_INFO "%s", version);
@@ -4776,8 +4785,7 @@ static int __init bonding_init(void)
bond_create_proc_dir();
#endif
for (i = 0; i < max_bonds; i++) {
- sprintf(new_bond_name, "bond%d",i);
- res = bond_create(new_bond_name,&bonding_defaults, NULL);
+ res = bond_create(NULL, &bonding_defaults, NULL);
if (res)
goto err;
}
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index ced9ed8f995..a122baa5c7b 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -22,7 +22,6 @@
*/
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/sched.h>
#include <linux/device.h>
#include <linux/sysdev.h>
#include <linux/fs.h>
@@ -39,8 +38,7 @@
/* #define BONDING_DEBUG 1 */
#include "bonding.h"
-#define to_class_dev(obj) container_of(obj,struct class_device,kobj)
-#define to_net_dev(class) container_of(class, struct net_device, class_dev)
+#define to_dev(obj) container_of(obj,struct device,kobj)
#define to_bond(cd) ((struct bonding *)(to_net_dev(cd)->priv))
/*---------------------------- Declarations -------------------------------*/
@@ -154,7 +152,7 @@ static ssize_t bonding_store_bonds(struct class *cls, const char *buffer, size_t
* If it's > expected, then there's a file open,
* and we have to fail.
*/
- if (atomic_read(&bond->dev->class_dev.kobj.kref.refcount)
+ if (atomic_read(&bond->dev->dev.kobj.kref.refcount)
> expected_refcount){
rtnl_unlock();
printk(KERN_INFO DRV_NAME
@@ -201,13 +199,13 @@ int bond_create_slave_symlinks(struct net_device *master, struct net_device *sla
int ret = 0;
/* first, create a link from the slave back to the master */
- ret = sysfs_create_link(&(slave->class_dev.kobj), &(master->class_dev.kobj),
+ ret = sysfs_create_link(&(slave->dev.kobj), &(master->dev.kobj),
"master");
if (ret)
return ret;
/* next, create a link from the master to the slave */
sprintf(linkname,"slave_%s",slave->name);
- ret = sysfs_create_link(&(master->class_dev.kobj), &(slave->class_dev.kobj),
+ ret = sysfs_create_link(&(master->dev.kobj), &(slave->dev.kobj),
linkname);
return ret;
@@ -217,20 +215,21 @@ void bond_destroy_slave_symlinks(struct net_device *master, struct net_device *s
{
char linkname[IFNAMSIZ+7];
- sysfs_remove_link(&(slave->class_dev.kobj), "master");
+ sysfs_remove_link(&(slave->dev.kobj), "master");
sprintf(linkname,"slave_%s",slave->name);
- sysfs_remove_link(&(master->class_dev.kobj), linkname);
+ sysfs_remove_link(&(master->dev.kobj), linkname);
}
/*
* Show the slaves in the current bond.
*/
-static ssize_t bonding_show_slaves(struct class_device *cd, char *buf)
+static ssize_t bonding_show_slaves(struct device *d,
+ struct device_attribute *attr, char *buf)
{
struct slave *slave;
int i, res = 0;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
read_lock_bh(&bond->lock);
bond_for_each_slave(bond, slave, i) {
@@ -254,14 +253,16 @@ static ssize_t bonding_show_slaves(struct class_device *cd, char *buf)
* up for this to succeed.
* This function is largely the same flow as bonding_update_bonds().
*/
-static ssize_t bonding_store_slaves(struct class_device *cd, const char *buffer, size_t count)
+static ssize_t bonding_store_slaves(struct device *d,
+ struct device_attribute *attr,
+ const char *buffer, size_t count)
{
char command[IFNAMSIZ + 1] = { 0, };
char *ifname;
int i, res, found, ret = count;
struct slave *slave;
struct net_device *dev = NULL;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
/* Quick sanity check -- is the bond interface up? */
if (!(bond->dev->flags & IFF_UP)) {
@@ -387,25 +388,28 @@ out:
return ret;
}
-static CLASS_DEVICE_ATTR(slaves, S_IRUGO | S_IWUSR, bonding_show_slaves, bonding_store_slaves);
+static DEVICE_ATTR(slaves, S_IRUGO | S_IWUSR, bonding_show_slaves, bonding_store_slaves);
/*
* Show and set the bonding mode. The bond interface must be down to
* change the mode.
*/
-static ssize_t bonding_show_mode(struct class_device *cd, char *buf)
+static ssize_t bonding_show_mode(struct device *d,
+ struct device_attribute *attr, char *buf)
{
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
return sprintf(buf, "%s %d\n",
bond_mode_tbl[bond->params.mode].modename,
bond->params.mode) + 1;
}
-static ssize_t bonding_store_mode(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_mode(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
int new_value, ret = count;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
if (bond->dev->flags & IFF_UP) {
printk(KERN_ERR DRV_NAME
@@ -438,16 +442,18 @@ static ssize_t bonding_store_mode(struct class_device *cd, const char *buf, size
out:
return ret;
}
-static CLASS_DEVICE_ATTR(mode, S_IRUGO | S_IWUSR, bonding_show_mode, bonding_store_mode);
+static DEVICE_ATTR(mode, S_IRUGO | S_IWUSR, bonding_show_mode, bonding_store_mode);
/*
* Show and set the bonding transmit hash method. The bond interface must be down to
* change the xmit hash policy.
*/
-static ssize_t bonding_show_xmit_hash(struct class_device *cd, char *buf)
+static ssize_t bonding_show_xmit_hash(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
{
int count;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
if ((bond->params.mode != BOND_MODE_XOR) &&
(bond->params.mode != BOND_MODE_8023AD)) {
@@ -462,10 +468,12 @@ static ssize_t bonding_show_xmit_hash(struct class_device *cd, char *buf)
return count;
}
-static ssize_t bonding_store_xmit_hash(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_xmit_hash(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
int new_value, ret = count;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
if (bond->dev->flags & IFF_UP) {
printk(KERN_ERR DRV_NAME
@@ -501,24 +509,28 @@ static ssize_t bonding_store_xmit_hash(struct class_device *cd, const char *buf,
out:
return ret;
}
-static CLASS_DEVICE_ATTR(xmit_hash_policy, S_IRUGO | S_IWUSR, bonding_show_xmit_hash, bonding_store_xmit_hash);
+static DEVICE_ATTR(xmit_hash_policy, S_IRUGO | S_IWUSR, bonding_show_xmit_hash, bonding_store_xmit_hash);
/*
* Show and set arp_validate.
*/
-static ssize_t bonding_show_arp_validate(struct class_device *cd, char *buf)
+static ssize_t bonding_show_arp_validate(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
{
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
return sprintf(buf, "%s %d\n",
arp_validate_tbl[bond->params.arp_validate].modename,
bond->params.arp_validate) + 1;
}
-static ssize_t bonding_store_arp_validate(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_arp_validate(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
int new_value;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
new_value = bond_parse_parm((char *)buf, arp_validate_tbl);
if (new_value < 0) {
@@ -548,7 +560,7 @@ static ssize_t bonding_store_arp_validate(struct class_device *cd, const char *b
return count;
}
-static CLASS_DEVICE_ATTR(arp_validate, S_IRUGO | S_IWUSR, bonding_show_arp_validate, bonding_store_arp_validate);
+static DEVICE_ATTR(arp_validate, S_IRUGO | S_IWUSR, bonding_show_arp_validate, bonding_store_arp_validate);
/*
* Show and set the arp timer interval. There are two tricky bits
@@ -556,17 +568,21 @@ static CLASS_DEVICE_ATTR(arp_validate, S_IRUGO | S_IWUSR, bonding_show_arp_valid
* MII monitoring. Second, if the ARP timer isn't running, we must
* start it.
*/
-static ssize_t bonding_show_arp_interval(struct class_device *cd, char *buf)
+static ssize_t bonding_show_arp_interval(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
{
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
return sprintf(buf, "%d\n", bond->params.arp_interval) + 1;
}
-static ssize_t bonding_store_arp_interval(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_arp_interval(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
int new_value, ret = count;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
if (sscanf(buf, "%d", &new_value) != 1) {
printk(KERN_ERR DRV_NAME
@@ -638,15 +654,17 @@ static ssize_t bonding_store_arp_interval(struct class_device *cd, const char *b
out:
return ret;
}
-static CLASS_DEVICE_ATTR(arp_interval, S_IRUGO | S_IWUSR , bonding_show_arp_interval, bonding_store_arp_interval);
+static DEVICE_ATTR(arp_interval, S_IRUGO | S_IWUSR , bonding_show_arp_interval, bonding_store_arp_interval);
/*
* Show and set the arp targets.
*/
-static ssize_t bonding_show_arp_targets(struct class_device *cd, char *buf)
+static ssize_t bonding_show_arp_targets(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
{
int i, res = 0;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
for (i = 0; i < BOND_MAX_ARP_TARGETS; i++) {
if (bond->params.arp_targets[i])
@@ -660,11 +678,13 @@ static ssize_t bonding_show_arp_targets(struct class_device *cd, char *buf)
return res;
}
-static ssize_t bonding_store_arp_targets(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_arp_targets(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
u32 newtarget;
int i = 0, done = 0, ret = count;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
u32 *targets;
targets = bond->params.arp_targets;
@@ -742,24 +762,28 @@ static ssize_t bonding_store_arp_targets(struct class_device *cd, const char *bu
out:
return ret;
}
-static CLASS_DEVICE_ATTR(arp_ip_target, S_IRUGO | S_IWUSR , bonding_show_arp_targets, bonding_store_arp_targets);
+static DEVICE_ATTR(arp_ip_target, S_IRUGO | S_IWUSR , bonding_show_arp_targets, bonding_store_arp_targets);
/*
* Show and set the up and down delays. These must be multiples of the
* MII monitoring value, and are stored internally as the multiplier.
* Thus, we must translate to MS for the real world.
*/
-static ssize_t bonding_show_downdelay(struct class_device *cd, char *buf)
+static ssize_t bonding_show_downdelay(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
{
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
return sprintf(buf, "%d\n", bond->params.downdelay * bond->params.miimon) + 1;
}
-static ssize_t bonding_store_downdelay(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_downdelay(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
int new_value, ret = count;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
if (!(bond->params.miimon)) {
printk(KERN_ERR DRV_NAME
@@ -800,20 +824,24 @@ static ssize_t bonding_store_downdelay(struct class_device *cd, const char *buf,
out:
return ret;
}
-static CLASS_DEVICE_ATTR(downdelay, S_IRUGO | S_IWUSR , bonding_show_downdelay, bonding_store_downdelay);
+static DEVICE_ATTR(downdelay, S_IRUGO | S_IWUSR , bonding_show_downdelay, bonding_store_downdelay);
-static ssize_t bonding_show_updelay(struct class_device *cd, char *buf)
+static ssize_t bonding_show_updelay(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
{
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
return sprintf(buf, "%d\n", bond->params.updelay * bond->params.miimon) + 1;
}
-static ssize_t bonding_store_updelay(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_updelay(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
int new_value, ret = count;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
if (!(bond->params.miimon)) {
printk(KERN_ERR DRV_NAME
@@ -854,25 +882,29 @@ static ssize_t bonding_store_updelay(struct class_device *cd, const char *buf, s
out:
return ret;
}
-static CLASS_DEVICE_ATTR(updelay, S_IRUGO | S_IWUSR , bonding_show_updelay, bonding_store_updelay);
+static DEVICE_ATTR(updelay, S_IRUGO | S_IWUSR , bonding_show_updelay, bonding_store_updelay);
/*
* Show and set the LACP interval. Interface must be down, and the mode
* must be set to 802.3ad mode.
*/
-static ssize_t bonding_show_lacp(struct class_device *cd, char *buf)
+static ssize_t bonding_show_lacp(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
{
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
return sprintf(buf, "%s %d\n",
bond_lacp_tbl[bond->params.lacp_fast].modename,
bond->params.lacp_fast) + 1;
}
-static ssize_t bonding_store_lacp(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_lacp(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
int new_value, ret = count;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
if (bond->dev->flags & IFF_UP) {
printk(KERN_ERR DRV_NAME
@@ -906,7 +938,7 @@ static ssize_t bonding_store_lacp(struct class_device *cd, const char *buf, size
out:
return ret;
}
-static CLASS_DEVICE_ATTR(lacp_rate, S_IRUGO | S_IWUSR, bonding_show_lacp, bonding_store_lacp);
+static DEVICE_ATTR(lacp_rate, S_IRUGO | S_IWUSR, bonding_show_lacp, bonding_store_lacp);
/*
* Show and set the MII monitor interval. There are two tricky bits
@@ -914,17 +946,21 @@ static CLASS_DEVICE_ATTR(lacp_rate, S_IRUGO | S_IWUSR, bonding_show_lacp, bondin
* ARP monitoring. Second, if the timer isn't running, we must
* start it.
*/
-static ssize_t bonding_show_miimon(struct class_device *cd, char *buf)
+static ssize_t bonding_show_miimon(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
{
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
return sprintf(buf, "%d\n", bond->params.miimon) + 1;
}
-static ssize_t bonding_store_miimon(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_miimon(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
int new_value, ret = count;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
if (sscanf(buf, "%d", &new_value) != 1) {
printk(KERN_ERR DRV_NAME
@@ -1000,7 +1036,7 @@ static ssize_t bonding_store_miimon(struct class_device *cd, const char *buf, si
out:
return ret;
}
-static CLASS_DEVICE_ATTR(miimon, S_IRUGO | S_IWUSR, bonding_show_miimon, bonding_store_miimon);
+static DEVICE_ATTR(miimon, S_IRUGO | S_IWUSR, bonding_show_miimon, bonding_store_miimon);
/*
* Show and set the primary slave. The store function is much
@@ -1009,10 +1045,12 @@ static CLASS_DEVICE_ATTR(miimon, S_IRUGO | S_IWUSR, bonding_show_miimon, bonding
* The bond must be a mode that supports a primary for this be
* set.
*/
-static ssize_t bonding_show_primary(struct class_device *cd, char *buf)
+static ssize_t bonding_show_primary(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
{
int count = 0;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
if (bond->primary_slave)
count = sprintf(buf, "%s\n", bond->primary_slave->dev->name) + 1;
@@ -1022,11 +1060,13 @@ static ssize_t bonding_show_primary(struct class_device *cd, char *buf)
return count;
}
-static ssize_t bonding_store_primary(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_primary(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
int i;
struct slave *slave;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
write_lock_bh(&bond->lock);
if (!USES_PRIMARY(bond->params.mode)) {
@@ -1065,22 +1105,26 @@ out:
write_unlock_bh(&bond->lock);
return count;
}
-static CLASS_DEVICE_ATTR(primary, S_IRUGO | S_IWUSR, bonding_show_primary, bonding_store_primary);
+static DEVICE_ATTR(primary, S_IRUGO | S_IWUSR, bonding_show_primary, bonding_store_primary);
/*
* Show and set the use_carrier flag.
*/
-static ssize_t bonding_show_carrier(struct class_device *cd, char *buf)
+static ssize_t bonding_show_carrier(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
{
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
return sprintf(buf, "%d\n", bond->params.use_carrier) + 1;
}
-static ssize_t bonding_store_carrier(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_carrier(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
int new_value, ret = count;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
if (sscanf(buf, "%d", &new_value) != 1) {
@@ -1102,16 +1146,18 @@ static ssize_t bonding_store_carrier(struct class_device *cd, const char *buf, s
out:
return count;
}
-static CLASS_DEVICE_ATTR(use_carrier, S_IRUGO | S_IWUSR, bonding_show_carrier, bonding_store_carrier);
+static DEVICE_ATTR(use_carrier, S_IRUGO | S_IWUSR, bonding_show_carrier, bonding_store_carrier);
/*
* Show and set currently active_slave.
*/
-static ssize_t bonding_show_active_slave(struct class_device *cd, char *buf)
+static ssize_t bonding_show_active_slave(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
{
struct slave *curr;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
int count;
@@ -1126,13 +1172,15 @@ static ssize_t bonding_show_active_slave(struct class_device *cd, char *buf)
return count;
}
-static ssize_t bonding_store_active_slave(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_active_slave(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
int i;
struct slave *slave;
struct slave *old_active = NULL;
struct slave *new_active = NULL;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
write_lock_bh(&bond->lock);
if (!USES_PRIMARY(bond->params.mode)) {
@@ -1194,16 +1242,18 @@ out:
return count;
}
-static CLASS_DEVICE_ATTR(active_slave, S_IRUGO | S_IWUSR, bonding_show_active_slave, bonding_store_active_slave);
+static DEVICE_ATTR(active_slave, S_IRUGO | S_IWUSR, bonding_show_active_slave, bonding_store_active_slave);
/*
* Show link status of the bond interface.
*/
-static ssize_t bonding_show_mii_status(struct class_device *cd, char *buf)
+static ssize_t bonding_show_mii_status(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
{
struct slave *curr;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
read_lock(&bond->curr_slave_lock);
curr = bond->curr_active_slave;
@@ -1211,16 +1261,18 @@ static ssize_t bonding_show_mii_status(struct class_device *cd, char *buf)
return sprintf(buf, "%s\n", (curr) ? "up" : "down") + 1;
}
-static CLASS_DEVICE_ATTR(mii_status, S_IRUGO, bonding_show_mii_status, NULL);
+static DEVICE_ATTR(mii_status, S_IRUGO, bonding_show_mii_status, NULL);
/*
* Show current 802.3ad aggregator ID.
*/
-static ssize_t bonding_show_ad_aggregator(struct class_device *cd, char *buf)
+static ssize_t bonding_show_ad_aggregator(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
{
int count = 0;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
if (bond->params.mode == BOND_MODE_8023AD) {
struct ad_info ad_info;
@@ -1231,16 +1283,18 @@ static ssize_t bonding_show_ad_aggregator(struct class_device *cd, char *buf)
return count;
}
-static CLASS_DEVICE_ATTR(ad_aggregator, S_IRUGO, bonding_show_ad_aggregator, NULL);
+static DEVICE_ATTR(ad_aggregator, S_IRUGO, bonding_show_ad_aggregator, NULL);
/*
* Show number of active 802.3ad ports.
*/
-static ssize_t bonding_show_ad_num_ports(struct class_device *cd, char *buf)
+static ssize_t bonding_show_ad_num_ports(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
{
int count = 0;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
if (bond->params.mode == BOND_MODE_8023AD) {
struct ad_info ad_info;
@@ -1251,16 +1305,18 @@ static ssize_t bonding_show_ad_num_ports(struct class_device *cd, char *buf)
return count;
}
-static CLASS_DEVICE_ATTR(ad_num_ports, S_IRUGO, bonding_show_ad_num_ports, NULL);
+static DEVICE_ATTR(ad_num_ports, S_IRUGO, bonding_show_ad_num_ports, NULL);
/*
* Show current 802.3ad actor key.
*/
-static ssize_t bonding_show_ad_actor_key(struct class_device *cd, char *buf)
+static ssize_t bonding_show_ad_actor_key(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
{
int count = 0;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
if (bond->params.mode == BOND_MODE_8023AD) {
struct ad_info ad_info;
@@ -1271,16 +1327,18 @@ static ssize_t bonding_show_ad_actor_key(struct class_device *cd, char *buf)
return count;
}
-static CLASS_DEVICE_ATTR(ad_actor_key, S_IRUGO, bonding_show_ad_actor_key, NULL);
+static DEVICE_ATTR(ad_actor_key, S_IRUGO, bonding_show_ad_actor_key, NULL);
/*
* Show current 802.3ad partner key.
*/
-static ssize_t bonding_show_ad_partner_key(struct class_device *cd, char *buf)
+static ssize_t bonding_show_ad_partner_key(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
{
int count = 0;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
if (bond->params.mode == BOND_MODE_8023AD) {
struct ad_info ad_info;
@@ -1291,16 +1349,18 @@ static ssize_t bonding_show_ad_partner_key(struct class_device *cd, char *buf)
return count;
}
-static CLASS_DEVICE_ATTR(ad_partner_key, S_IRUGO, bonding_show_ad_partner_key, NULL);
+static DEVICE_ATTR(ad_partner_key, S_IRUGO, bonding_show_ad_partner_key, NULL);
/*
* Show current 802.3ad partner mac.
*/
-static ssize_t bonding_show_ad_partner_mac(struct class_device *cd, char *buf)
+static ssize_t bonding_show_ad_partner_mac(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
{
int count = 0;
- struct bonding *bond = to_bond(cd);
+ struct bonding *bond = to_bond(d);
if (bond->params.mode == BOND_MODE_8023AD) {
struct ad_info ad_info;
@@ -1319,30 +1379,30 @@ static ssize_t bonding_show_ad_partner_mac(struct class_device *cd, char *buf)
return count;
}
-static CLASS_DEVICE_ATTR(ad_partner_mac, S_IRUGO, bonding_show_ad_partner_mac, NULL);
+static DEVICE_ATTR(ad_partner_mac, S_IRUGO, bonding_show_ad_partner_mac, NULL);
static struct attribute *per_bond_attrs[] = {
- &class_device_attr_slaves.attr,
- &class_device_attr_mode.attr,
- &class_device_attr_arp_validate.attr,
- &class_device_attr_arp_interval.attr,
- &class_device_attr_arp_ip_target.attr,
- &class_device_attr_downdelay.attr,
- &class_device_attr_updelay.attr,
- &class_device_attr_lacp_rate.attr,
- &class_device_attr_xmit_hash_policy.attr,
- &class_device_attr_miimon.attr,
- &class_device_attr_primary.attr,
- &class_device_attr_use_carrier.attr,
- &class_device_attr_active_slave.attr,
- &class_device_attr_mii_status.attr,
- &class_device_attr_ad_aggregator.attr,
- &class_device_attr_ad_num_ports.attr,
- &class_device_attr_ad_actor_key.attr,
- &class_device_attr_ad_partner_key.attr,
- &class_device_attr_ad_partner_mac.attr,
+ &dev_attr_slaves.attr,
+ &dev_attr_mode.attr,
+ &dev_attr_arp_validate.attr,
+ &dev_attr_arp_interval.attr,
+ &dev_attr_arp_ip_target.attr,
+ &dev_attr_downdelay.attr,
+ &dev_attr_updelay.attr,
+ &dev_attr_lacp_rate.attr,
+ &dev_attr_xmit_hash_policy.attr,
+ &dev_attr_miimon.attr,
+ &dev_attr_primary.attr,
+ &dev_attr_use_carrier.attr,
+ &dev_attr_active_slave.attr,
+ &dev_attr_mii_status.attr,
+ &dev_attr_ad_aggregator.attr,
+ &dev_attr_ad_num_ports.attr,
+ &dev_attr_ad_actor_key.attr,
+ &dev_attr_ad_partner_key.attr,
+ &dev_attr_ad_partner_mac.attr,
NULL,
};
@@ -1367,11 +1427,26 @@ int bond_create_sysfs(void)
if (!firstbond)
return -ENODEV;
- netdev_class = firstbond->dev->class_dev.class;
+ netdev_class = firstbond->dev->dev.class;
if (!netdev_class)
return -ENODEV;
ret = class_create_file(netdev_class, &class_attr_bonding_masters);
+ /*
+ * Permit multiple loads of the module by ignoring failures to
+ * create the bonding_masters sysfs file. Bonding devices
+ * created by second or subsequent loads of the module will
+ * not be listed in, or controllable by, bonding_masters, but
+ * will have the usual "bonding" sysfs directory.
+ *
+ * This is done to preserve backwards compatibility for
+ * initscripts/sysconfig, which load bonding multiple times to
+ * configure multiple bonding devices.
+ */
+ if (ret == -EEXIST) {
+ netdev_class = NULL;
+ return 0;
+ }
return ret;
@@ -1395,13 +1470,13 @@ int bond_create_sysfs_entry(struct bonding *bond)
struct net_device *dev = bond->dev;
int err;
- err = sysfs_create_group(&(dev->class_dev.kobj), &bonding_group);
+ err = sysfs_create_group(&(dev->dev.kobj), &bonding_group);
if (err) {
printk(KERN_EMERG "eek! didn't create group!\n");
}
if (expected_refcount < 1)
- expected_refcount = atomic_read(&bond->dev->class_dev.kobj.kref.refcount);
+ expected_refcount = atomic_read(&bond->dev->dev.kobj.kref.refcount);
return err;
}
@@ -1412,6 +1487,6 @@ void bond_destroy_sysfs_entry(struct bonding *bond)
{
struct net_device *dev = bond->dev;
- sysfs_remove_group(&(dev->class_dev.kobj), &bonding_group);
+ sysfs_remove_group(&(dev->dev.kobj), &bonding_group);
}
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index 0978c9ac6d2..41aa78bf1f7 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -22,8 +22,8 @@
#include "bond_3ad.h"
#include "bond_alb.h"
-#define DRV_VERSION "3.1.1"
-#define DRV_RELDATE "September 26, 2006"
+#define DRV_VERSION "3.1.2"
+#define DRV_RELDATE "January 20, 2007"
#define DRV_NAME "bonding"
#define DRV_DESCRIPTION "Ethernet Channel Bonding Driver"
@@ -237,12 +237,13 @@ static inline struct bonding *bond_get_bond_by_slave(struct slave *slave)
#define BOND_ARP_VALIDATE_ALL (BOND_ARP_VALIDATE_ACTIVE | \
BOND_ARP_VALIDATE_BACKUP)
-extern inline int slave_do_arp_validate(struct bonding *bond, struct slave *slave)
+static inline int slave_do_arp_validate(struct bonding *bond,
+ struct slave *slave)
{
return bond->params.arp_validate & (1 << slave->state);
}
-extern inline unsigned long slave_last_rx(struct bonding *bond,
+static inline unsigned long slave_last_rx(struct bonding *bond,
struct slave *slave)
{
if (slave_do_arp_validate(bond, slave))
diff --git a/drivers/net/chelsio/common.h b/drivers/net/chelsio/common.h
index 74758d2c7af..787f2f2820f 100644
--- a/drivers/net/chelsio/common.h
+++ b/drivers/net/chelsio/common.h
@@ -324,7 +324,7 @@ struct board_info {
unsigned char mdio_phybaseaddr;
struct gmac *gmac;
struct gphy *gphy;
- struct mdio_ops *mdio_ops;
+ struct mdio_ops *mdio_ops;
const char *desc;
};
diff --git a/drivers/net/chelsio/cpl5_cmd.h b/drivers/net/chelsio/cpl5_cmd.h
index 35f565be4fd..e36d45b78cc 100644
--- a/drivers/net/chelsio/cpl5_cmd.h
+++ b/drivers/net/chelsio/cpl5_cmd.h
@@ -103,7 +103,7 @@ enum CPL_opcode {
CPL_MIGRATE_C2T_RPL = 0xDD,
CPL_ERROR = 0xD7,
- /* internal: driver -> TOM */
+ /* internal: driver -> TOM */
CPL_MSS_CHANGE = 0xE1
};
@@ -159,8 +159,8 @@ enum { // TX_PKT_LSO ethernet types
};
union opcode_tid {
- u32 opcode_tid;
- u8 opcode;
+ u32 opcode_tid;
+ u8 opcode;
};
#define S_OPCODE 24
@@ -234,7 +234,7 @@ struct cpl_pass_accept_req {
u32 local_ip;
u32 peer_ip;
u32 tos_tid;
- struct tcp_options tcp_options;
+ struct tcp_options tcp_options;
u8 dst_mac[6];
u16 vlan_tag;
u8 src_mac[6];
@@ -250,12 +250,12 @@ struct cpl_pass_accept_rpl {
u32 peer_ip;
u32 opt0h;
union {
- u32 opt0l;
- struct {
- u8 rsvd[3];
- u8 status;
+ u32 opt0l;
+ struct {
+ u8 rsvd[3];
+ u8 status;
+ };
};
- };
};
struct cpl_act_open_req {
diff --git a/drivers/net/chelsio/cxgb2.c b/drivers/net/chelsio/cxgb2.c
index fd5d821f3f2..7d0f24f6977 100644
--- a/drivers/net/chelsio/cxgb2.c
+++ b/drivers/net/chelsio/cxgb2.c
@@ -69,14 +69,14 @@ static inline void cancel_mac_stats_update(struct adapter *ap)
cancel_delayed_work(&ap->stats_update_task);
}
-#define MAX_CMDQ_ENTRIES 16384
-#define MAX_CMDQ1_ENTRIES 1024
-#define MAX_RX_BUFFERS 16384
-#define MAX_RX_JUMBO_BUFFERS 16384
+#define MAX_CMDQ_ENTRIES 16384
+#define MAX_CMDQ1_ENTRIES 1024
+#define MAX_RX_BUFFERS 16384
+#define MAX_RX_JUMBO_BUFFERS 16384
#define MAX_TX_BUFFERS_HIGH 16384U
#define MAX_TX_BUFFERS_LOW 1536U
#define MAX_TX_BUFFERS 1460U
-#define MIN_FL_ENTRIES 32
+#define MIN_FL_ENTRIES 32
#define DFLT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK | \
NETIF_MSG_TIMER | NETIF_MSG_IFDOWN | NETIF_MSG_IFUP |\
@@ -143,7 +143,7 @@ static void link_report(struct port_info *p)
case SPEED_100: s = "100Mbps"; break;
}
- printk(KERN_INFO "%s: link up, %s, %s-duplex\n",
+ printk(KERN_INFO "%s: link up, %s, %s-duplex\n",
p->dev->name, s,
p->link_config.duplex == DUPLEX_FULL ? "full" : "half");
}
@@ -233,7 +233,7 @@ static int cxgb_up(struct adapter *adapter)
t1_sge_start(adapter->sge);
t1_interrupts_enable(adapter);
- out_err:
+out_err:
return err;
}
@@ -454,51 +454,21 @@ static void get_stats(struct net_device *dev, struct ethtool_stats *stats,
const struct cmac_statistics *s;
const struct sge_intr_counts *t;
struct sge_port_stats ss;
+ unsigned int len;
s = mac->ops->statistics_update(mac, MAC_STATS_UPDATE_FULL);
- *data++ = s->TxOctetsOK;
- *data++ = s->TxOctetsBad;
- *data++ = s->TxUnicastFramesOK;
- *data++ = s->TxMulticastFramesOK;
- *data++ = s->TxBroadcastFramesOK;
- *data++ = s->TxPauseFrames;
- *data++ = s->TxFramesWithDeferredXmissions;
- *data++ = s->TxLateCollisions;
- *data++ = s->TxTotalCollisions;
- *data++ = s->TxFramesAbortedDueToXSCollisions;
- *data++ = s->TxUnderrun;
- *data++ = s->TxLengthErrors;
- *data++ = s->TxInternalMACXmitError;
- *data++ = s->TxFramesWithExcessiveDeferral;
- *data++ = s->TxFCSErrors;
-
- *data++ = s->RxOctetsOK;
- *data++ = s->RxOctetsBad;
- *data++ = s->RxUnicastFramesOK;
- *data++ = s->RxMulticastFramesOK;
- *data++ = s->RxBroadcastFramesOK;
- *data++ = s->RxPauseFrames;
- *data++ = s->RxFCSErrors;
- *data++ = s->RxAlignErrors;
- *data++ = s->RxSymbolErrors;
- *data++ = s->RxDataErrors;
- *data++ = s->RxSequenceErrors;
- *data++ = s->RxRuntErrors;
- *data++ = s->RxJabberErrors;
- *data++ = s->RxInternalMACRcvError;
- *data++ = s->RxInRangeLengthErrors;
- *data++ = s->RxOutOfRangeLengthField;
- *data++ = s->RxFrameTooLongErrors;
+ len = sizeof(u64)*(&s->TxFCSErrors + 1 - &s->TxOctetsOK);
+ memcpy(data, &s->TxOctetsOK, len);
+ data += len;
+
+ len = sizeof(u64)*(&s->RxFrameTooLongErrors + 1 - &s->RxOctetsOK);
+ memcpy(data, &s->RxOctetsOK, len);
+ data += len;
t1_sge_get_port_stats(adapter->sge, dev->if_port, &ss);
- *data++ = ss.rx_packets;
- *data++ = ss.rx_cso_good;
- *data++ = ss.tx_packets;
- *data++ = ss.tx_cso;
- *data++ = ss.tx_tso;
- *data++ = ss.vlan_xtract;
- *data++ = ss.vlan_insert;
+ memcpy(data, &ss, sizeof(ss));
+ data += sizeof(ss);
t = t1_sge_get_intr_counts(adapter->sge);
*data++ = t->rx_drops;
@@ -749,7 +719,7 @@ static int set_sge_param(struct net_device *dev, struct ethtool_ringparam *e)
return -EINVAL;
if (adapter->flags & FULL_INIT_DONE)
- return -EBUSY;
+ return -EBUSY;
adapter->params.sge.freelQ_size[!jumbo_fl] = e->rx_pending;
adapter->params.sge.freelQ_size[jumbo_fl] = e->rx_jumbo_pending;
@@ -764,7 +734,7 @@ static int set_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
struct adapter *adapter = dev->priv;
adapter->params.sge.rx_coalesce_usecs = c->rx_coalesce_usecs;
- adapter->params.sge.coalesce_enable = c->use_adaptive_rx_coalesce;
+ adapter->params.sge.coalesce_enable = c->use_adaptive_rx_coalesce;
adapter->params.sge.sample_interval_usecs = c->rate_sample_interval;
t1_sge_set_coalesce_params(adapter->sge, &adapter->params.sge);
return 0;
@@ -782,9 +752,9 @@ static int get_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
static int get_eeprom_len(struct net_device *dev)
{
- struct adapter *adapter = dev->priv;
+ struct adapter *adapter = dev->priv;
- return t1_is_asic(adapter) ? EEPROM_SIZE : 0;
+ return t1_is_asic(adapter) ? EEPROM_SIZE : 0;
}
#define EEPROM_MAGIC(ap) \
@@ -848,7 +818,7 @@ static int t1_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
u32 val;
if (!phy->mdio_read)
- return -EOPNOTSUPP;
+ return -EOPNOTSUPP;
phy->mdio_read(adapter, data->phy_id, 0, data->reg_num & 0x1f,
&val);
data->val_out = val;
@@ -860,7 +830,7 @@ static int t1_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
if (!capable(CAP_NET_ADMIN))
return -EPERM;
if (!phy->mdio_write)
- return -EOPNOTSUPP;
+ return -EOPNOTSUPP;
phy->mdio_write(adapter, data->phy_id, 0, data->reg_num & 0x1f,
data->val_in);
break;
@@ -879,9 +849,9 @@ static int t1_change_mtu(struct net_device *dev, int new_mtu)
struct cmac *mac = adapter->port[dev->if_port].mac;
if (!mac->ops->set_mtu)
- return -EOPNOTSUPP;
+ return -EOPNOTSUPP;
if (new_mtu < 68)
- return -EINVAL;
+ return -EINVAL;
if ((ret = mac->ops->set_mtu(mac, new_mtu)))
return ret;
dev->mtu = new_mtu;
@@ -1211,9 +1181,9 @@ static int __devinit init_one(struct pci_dev *pdev,
return 0;
- out_release_adapter_res:
+out_release_adapter_res:
t1_free_sw_modules(adapter);
- out_free_dev:
+out_free_dev:
if (adapter) {
if (adapter->regs)
iounmap(adapter->regs);
@@ -1222,7 +1192,7 @@ static int __devinit init_one(struct pci_dev *pdev,
free_netdev(adapter->port[i].dev);
}
pci_release_regions(pdev);
- out_disable_pdev:
+out_disable_pdev:
pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
return err;
@@ -1273,28 +1243,27 @@ static int t1_clock(struct adapter *adapter, int mode)
int M_MEM_VAL;
enum {
- M_CORE_BITS = 9,
- T_CORE_VAL = 0,
- T_CORE_BITS = 2,
- N_CORE_VAL = 0,
- N_CORE_BITS = 2,
- M_MEM_BITS = 9,
- T_MEM_VAL = 0,
- T_MEM_BITS = 2,
- N_MEM_VAL = 0,
- N_MEM_BITS = 2,
- NP_LOAD = 1 << 17,
- S_LOAD_MEM = 1 << 5,
- S_LOAD_CORE = 1 << 6,
- S_CLOCK = 1 << 3
+ M_CORE_BITS = 9,
+ T_CORE_VAL = 0,
+ T_CORE_BITS = 2,
+ N_CORE_VAL = 0,
+ N_CORE_BITS = 2,
+ M_MEM_BITS = 9,
+ T_MEM_VAL = 0,
+ T_MEM_BITS = 2,
+ N_MEM_VAL = 0,
+ N_MEM_BITS = 2,
+ NP_LOAD = 1 << 17,
+ S_LOAD_MEM = 1 << 5,
+ S_LOAD_CORE = 1 << 6,
+ S_CLOCK = 1 << 3
};
if (!t1_is_T1B(adapter))
return -ENODEV; /* Can't re-clock this chip. */
- if (mode & 2) {
+ if (mode & 2)
return 0; /* show current mode. */
- }
if ((adapter->t1powersave & 1) == (mode & 1))
return -EALREADY; /* ASIC already running in mode. */
@@ -1386,26 +1355,26 @@ static inline void t1_sw_reset(struct pci_dev *pdev)
static void __devexit remove_one(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
+ struct adapter *adapter = dev->priv;
+ int i;
- if (dev) {
- int i;
- struct adapter *adapter = dev->priv;
-
- for_each_port(adapter, i)
- if (test_bit(i, &adapter->registered_device_map))
- unregister_netdev(adapter->port[i].dev);
+ for_each_port(adapter, i) {
+ if (test_bit(i, &adapter->registered_device_map))
+ unregister_netdev(adapter->port[i].dev);
+ }
- t1_free_sw_modules(adapter);
- iounmap(adapter->regs);
- while (--i >= 0)
- if (adapter->port[i].dev)
- free_netdev(adapter->port[i].dev);
+ t1_free_sw_modules(adapter);
+ iounmap(adapter->regs);
- pci_release_regions(pdev);
- pci_disable_device(pdev);
- pci_set_drvdata(pdev, NULL);
- t1_sw_reset(pdev);
+ while (--i >= 0) {
+ if (adapter->port[i].dev)
+ free_netdev(adapter->port[i].dev);
}
+
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+ t1_sw_reset(pdev);
}
static struct pci_driver driver = {
diff --git a/drivers/net/chelsio/elmer0.h b/drivers/net/chelsio/elmer0.h
index 9ebecaa97d3..eef655c827d 100644
--- a/drivers/net/chelsio/elmer0.h
+++ b/drivers/net/chelsio/elmer0.h
@@ -46,14 +46,14 @@ enum {
};
/* ELMER0 registers */
-#define A_ELMER0_VERSION 0x100000
-#define A_ELMER0_PHY_CFG 0x100004
-#define A_ELMER0_INT_ENABLE 0x100008
-#define A_ELMER0_INT_CAUSE 0x10000c
-#define A_ELMER0_GPI_CFG 0x100010
-#define A_ELMER0_GPI_STAT 0x100014
-#define A_ELMER0_GPO 0x100018
-#define A_ELMER0_PORT0_MI1_CFG 0x400000
+#define A_ELMER0_VERSION 0x100000
+#define A_ELMER0_PHY_CFG 0x100004
+#define A_ELMER0_INT_ENABLE 0x100008
+#define A_ELMER0_INT_CAUSE 0x10000c
+#define A_ELMER0_GPI_CFG 0x100010
+#define A_ELMER0_GPI_STAT 0x100014
+#define A_ELMER0_GPO 0x100018
+#define A_ELMER0_PORT0_MI1_CFG 0x400000
#define S_MI1_MDI_ENABLE 0
#define V_MI1_MDI_ENABLE(x) ((x) << S_MI1_MDI_ENABLE)
@@ -111,18 +111,18 @@ enum {
#define V_MI1_OP_BUSY(x) ((x) << S_MI1_OP_BUSY)
#define F_MI1_OP_BUSY V_MI1_OP_BUSY(1U)
-#define A_ELMER0_PORT1_MI1_CFG 0x500000
-#define A_ELMER0_PORT1_MI1_ADDR 0x500004
-#define A_ELMER0_PORT1_MI1_DATA 0x500008
-#define A_ELMER0_PORT1_MI1_OP 0x50000c
-#define A_ELMER0_PORT2_MI1_CFG 0x600000
-#define A_ELMER0_PORT2_MI1_ADDR 0x600004
-#define A_ELMER0_PORT2_MI1_DATA 0x600008
-#define A_ELMER0_PORT2_MI1_OP 0x60000c
-#define A_ELMER0_PORT3_MI1_CFG 0x700000
-#define A_ELMER0_PORT3_MI1_ADDR 0x700004
-#define A_ELMER0_PORT3_MI1_DATA 0x700008
-#define A_ELMER0_PORT3_MI1_OP 0x70000c
+#define A_ELMER0_PORT1_MI1_CFG 0x500000
+#define A_ELMER0_PORT1_MI1_ADDR 0x500004
+#define A_ELMER0_PORT1_MI1_DATA 0x500008
+#define A_ELMER0_PORT1_MI1_OP 0x50000c
+#define A_ELMER0_PORT2_MI1_CFG 0x600000
+#define A_ELMER0_PORT2_MI1_ADDR 0x600004
+#define A_ELMER0_PORT2_MI1_DATA 0x600008
+#define A_ELMER0_PORT2_MI1_OP 0x60000c
+#define A_ELMER0_PORT3_MI1_CFG 0x700000
+#define A_ELMER0_PORT3_MI1_ADDR 0x700004
+#define A_ELMER0_PORT3_MI1_DATA 0x700008
+#define A_ELMER0_PORT3_MI1_OP 0x70000c
/* Simple bit definition for GPI and GP0 registers. */
#define ELMER0_GP_BIT0 0x0001
diff --git a/drivers/net/chelsio/espi.c b/drivers/net/chelsio/espi.c
index 4192f0f5b3e..d7c5406a6c3 100644
--- a/drivers/net/chelsio/espi.c
+++ b/drivers/net/chelsio/espi.c
@@ -202,9 +202,9 @@ static void espi_setup_for_pm3393(adapter_t *adapter)
static void espi_setup_for_vsc7321(adapter_t *adapter)
{
- writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN0);
- writel(0x1f401f4, adapter->regs + A_ESPI_SCH_TOKEN1);
- writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN2);
+ writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN0);
+ writel(0x1f401f4, adapter->regs + A_ESPI_SCH_TOKEN1);
+ writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN2);
writel(0xa00, adapter->regs + A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK);
writel(0x1ff, adapter->regs + A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK);
writel(1, adapter->regs + A_ESPI_CALENDAR_LENGTH);
@@ -247,10 +247,10 @@ int t1_espi_init(struct peespi *espi, int mac_type, int nports)
writel(V_OUT_OF_SYNC_COUNT(4) |
V_DIP2_PARITY_ERR_THRES(3) |
V_DIP4_THRES(1), adapter->regs + A_ESPI_MISC_CONTROL);
- writel(nports == 4 ? 0x200040 : 0x1000080,
+ writel(nports == 4 ? 0x200040 : 0x1000080,
adapter->regs + A_ESPI_MAXBURST1_MAXBURST2);
} else
- writel(0x800100, adapter->regs + A_ESPI_MAXBURST1_MAXBURST2);
+ writel(0x800100, adapter->regs + A_ESPI_MAXBURST1_MAXBURST2);
if (mac_type == CHBT_MAC_PM3393)
espi_setup_for_pm3393(adapter);
@@ -301,7 +301,8 @@ void t1_espi_set_misc_ctrl(adapter_t *adapter, u32 val)
{
struct peespi *espi = adapter->espi;
- if (!is_T2(adapter)) return;
+ if (!is_T2(adapter))
+ return;
spin_lock(&espi->lock);
espi->misc_ctrl = (val & ~MON_MASK) |
(espi->misc_ctrl & MON_MASK);
@@ -340,32 +341,31 @@ u32 t1_espi_get_mon(adapter_t *adapter, u32 addr, u8 wait)
* compare with t1_espi_get_mon(), it reads espiInTxSop[0 ~ 3] in
* one shot, since there is no per port counter on the out side.
*/
-int
-t1_espi_get_mon_t204(adapter_t *adapter, u32 *valp, u8 wait)
+int t1_espi_get_mon_t204(adapter_t *adapter, u32 *valp, u8 wait)
{
- struct peespi *espi = adapter->espi;
+ struct peespi *espi = adapter->espi;
u8 i, nport = (u8)adapter->params.nports;
- if (!wait) {
- if (!spin_trylock(&espi->lock))
- return -1;
- } else
- spin_lock(&espi->lock);
+ if (!wait) {
+ if (!spin_trylock(&espi->lock))
+ return -1;
+ } else
+ spin_lock(&espi->lock);
- if ( (espi->misc_ctrl & MON_MASK) != F_MONITORED_DIRECTION ) {
+ if ((espi->misc_ctrl & MON_MASK) != F_MONITORED_DIRECTION) {
espi->misc_ctrl = (espi->misc_ctrl & ~MON_MASK) |
F_MONITORED_DIRECTION;
- writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL);
- }
+ writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL);
+ }
for (i = 0 ; i < nport; i++, valp++) {
if (i) {
writel(espi->misc_ctrl | V_MONITORED_PORT_NUM(i),
adapter->regs + A_ESPI_MISC_CONTROL);
}
- *valp = readl(adapter->regs + A_ESPI_SCH_TOKEN3);
- }
+ *valp = readl(adapter->regs + A_ESPI_SCH_TOKEN3);
+ }
- writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL);
- spin_unlock(&espi->lock);
- return 0;
+ writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL);
+ spin_unlock(&espi->lock);
+ return 0;
}
diff --git a/drivers/net/chelsio/fpga_defs.h b/drivers/net/chelsio/fpga_defs.h
index 17a3c2ba36a..ccdb2bc9ae9 100644
--- a/drivers/net/chelsio/fpga_defs.h
+++ b/drivers/net/chelsio/fpga_defs.h
@@ -98,9 +98,9 @@
#define A_MI0_DATA_INT 0xb10
/* GMAC registers */
-#define A_GMAC_MACID_LO 0x28
-#define A_GMAC_MACID_HI 0x2c
-#define A_GMAC_CSR 0x30
+#define A_GMAC_MACID_LO 0x28
+#define A_GMAC_MACID_HI 0x2c
+#define A_GMAC_CSR 0x30
#define S_INTERFACE 0
#define M_INTERFACE 0x3
diff --git a/drivers/net/chelsio/gmac.h b/drivers/net/chelsio/gmac.h
index a2b8ad9b553..006a2eb2d36 100644
--- a/drivers/net/chelsio/gmac.h
+++ b/drivers/net/chelsio/gmac.h
@@ -42,8 +42,15 @@
#include "common.h"
-enum { MAC_STATS_UPDATE_FAST, MAC_STATS_UPDATE_FULL };
-enum { MAC_DIRECTION_RX = 1, MAC_DIRECTION_TX = 2 };
+enum {
+ MAC_STATS_UPDATE_FAST,
+ MAC_STATS_UPDATE_FULL
+};
+
+enum {
+ MAC_DIRECTION_RX = 1,
+ MAC_DIRECTION_TX = 2
+};
struct cmac_statistics {
/* Transmit */
diff --git a/drivers/net/chelsio/ixf1010.c b/drivers/net/chelsio/ixf1010.c
index 5b8f144e83d..10b2a9a1900 100644
--- a/drivers/net/chelsio/ixf1010.c
+++ b/drivers/net/chelsio/ixf1010.c
@@ -145,48 +145,61 @@ static void disable_port(struct cmac *mac)
t1_tpi_write(mac->adapter, REG_PORT_ENABLE, val);
}
-#define RMON_UPDATE(mac, name, stat_name) \
- t1_tpi_read((mac)->adapter, MACREG(mac, REG_##name), &val); \
- (mac)->stats.stat_name += val;
-
/*
* Read the current values of the RMON counters and add them to the cumulative
* port statistics. The HW RMON counters are cleared by this operation.
*/
static void port_stats_update(struct cmac *mac)
{
- u32 val;
+ static struct {
+ unsigned int reg;
+ unsigned int offset;
+ } hw_stats[] = {
+
+#define HW_STAT(name, stat_name) \
+ { REG_##name, \
+ (&((struct cmac_statistics *)NULL)->stat_name) - (u64 *)NULL }
+
+ /* Rx stats */
+ HW_STAT(RxOctetsTotalOK, RxOctetsOK),
+ HW_STAT(RxOctetsBad, RxOctetsBad),
+ HW_STAT(RxUCPkts, RxUnicastFramesOK),
+ HW_STAT(RxMCPkts, RxMulticastFramesOK),
+ HW_STAT(RxBCPkts, RxBroadcastFramesOK),
+ HW_STAT(RxJumboPkts, RxJumboFramesOK),
+ HW_STAT(RxFCSErrors, RxFCSErrors),
+ HW_STAT(RxAlignErrors, RxAlignErrors),
+ HW_STAT(RxLongErrors, RxFrameTooLongErrors),
+ HW_STAT(RxVeryLongErrors, RxFrameTooLongErrors),
+ HW_STAT(RxPauseMacControlCounter, RxPauseFrames),
+ HW_STAT(RxDataErrors, RxDataErrors),
+ HW_STAT(RxJabberErrors, RxJabberErrors),
+ HW_STAT(RxRuntErrors, RxRuntErrors),
+ HW_STAT(RxShortErrors, RxRuntErrors),
+ HW_STAT(RxSequenceErrors, RxSequenceErrors),
+ HW_STAT(RxSymbolErrors, RxSymbolErrors),
+
+ /* Tx stats (skip collision stats as we are full-duplex only) */
+ HW_STAT(TxOctetsTotalOK, TxOctetsOK),
+ HW_STAT(TxOctetsBad, TxOctetsBad),
+ HW_STAT(TxUCPkts, TxUnicastFramesOK),
+ HW_STAT(TxMCPkts, TxMulticastFramesOK),
+ HW_STAT(TxBCPkts, TxBroadcastFramesOK),
+ HW_STAT(TxJumboPkts, TxJumboFramesOK),
+ HW_STAT(TxPauseFrames, TxPauseFrames),
+ HW_STAT(TxExcessiveLengthDrop, TxLengthErrors),
+ HW_STAT(TxUnderrun, TxUnderrun),
+ HW_STAT(TxCRCErrors, TxFCSErrors)
+ }, *p = hw_stats;
+ u64 *stats = (u64 *) &mac->stats;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(hw_stats); i++) {
+ u32 val;
- /* Rx stats */
- RMON_UPDATE(mac, RxOctetsTotalOK, RxOctetsOK);
- RMON_UPDATE(mac, RxOctetsBad, RxOctetsBad);
- RMON_UPDATE(mac, RxUCPkts, RxUnicastFramesOK);
- RMON_UPDATE(mac, RxMCPkts, RxMulticastFramesOK);
- RMON_UPDATE(mac, RxBCPkts, RxBroadcastFramesOK);
- RMON_UPDATE(mac, RxJumboPkts, RxJumboFramesOK);
- RMON_UPDATE(mac, RxFCSErrors, RxFCSErrors);
- RMON_UPDATE(mac, RxAlignErrors, RxAlignErrors);
- RMON_UPDATE(mac, RxLongErrors, RxFrameTooLongErrors);
- RMON_UPDATE(mac, RxVeryLongErrors, RxFrameTooLongErrors);
- RMON_UPDATE(mac, RxPauseMacControlCounter, RxPauseFrames);
- RMON_UPDATE(mac, RxDataErrors, RxDataErrors);
- RMON_UPDATE(mac, RxJabberErrors, RxJabberErrors);
- RMON_UPDATE(mac, RxRuntErrors, RxRuntErrors);
- RMON_UPDATE(mac, RxShortErrors, RxRuntErrors);
- RMON_UPDATE(mac, RxSequenceErrors, RxSequenceErrors);
- RMON_UPDATE(mac, RxSymbolErrors, RxSymbolErrors);
-
- /* Tx stats (skip collision stats as we are full-duplex only) */
- RMON_UPDATE(mac, TxOctetsTotalOK, TxOctetsOK);
- RMON_UPDATE(mac, TxOctetsBad, TxOctetsBad);
- RMON_UPDATE(mac, TxUCPkts, TxUnicastFramesOK);
- RMON_UPDATE(mac, TxMCPkts, TxMulticastFramesOK);
- RMON_UPDATE(mac, TxBCPkts, TxBroadcastFramesOK);
- RMON_UPDATE(mac, TxJumboPkts, TxJumboFramesOK);
- RMON_UPDATE(mac, TxPauseFrames, TxPauseFrames);
- RMON_UPDATE(mac, TxExcessiveLengthDrop, TxLengthErrors);
- RMON_UPDATE(mac, TxUnderrun, TxUnderrun);
- RMON_UPDATE(mac, TxCRCErrors, TxFCSErrors);
+ t1_tpi_read(mac->adapter, MACREG(mac, p->reg), &val);
+ stats[p->offset] += val;
+ }
}
/* No-op interrupt operation as this MAC does not support interrupts */
@@ -273,7 +286,8 @@ static int mac_set_rx_mode(struct cmac *mac, struct t1_rx_mode *rm)
static int mac_set_mtu(struct cmac *mac, int mtu)
{
/* MAX_FRAME_SIZE inludes header + FCS, mtu doesn't */
- if (mtu > (MAX_FRAME_SIZE - 14 - 4)) return -EINVAL;
+ if (mtu > (MAX_FRAME_SIZE - 14 - 4))
+ return -EINVAL;
t1_tpi_write(mac->adapter, MACREG(mac, REG_MAX_FRAME_SIZE),
mtu + 14 + 4);
return 0;
@@ -357,8 +371,8 @@ static void enable_port(struct cmac *mac)
val |= (1 << index);
t1_tpi_write(adapter, REG_PORT_ENABLE, val);
- index <<= 2;
- if (is_T2(adapter)) {
+ index <<= 2;
+ if (is_T2(adapter)) {
/* T204: set the Fifo water level & threshold */
t1_tpi_write(adapter, RX_FIFO_HIGH_WATERMARK_BASE + index, 0x740);
t1_tpi_write(adapter, RX_FIFO_LOW_WATERMARK_BASE + index, 0x730);
@@ -389,6 +403,10 @@ static int mac_disable(struct cmac *mac, int which)
return 0;
}
+#define RMON_UPDATE(mac, name, stat_name) \
+ t1_tpi_read((mac)->adapter, MACREG(mac, REG_##name), &val); \
+ (mac)->stats.stat_name += val;
+
/*
* This function is called periodically to accumulate the current values of the
* RMON counters into the port statistics. Since the counters are only 32 bits
@@ -460,10 +478,12 @@ static struct cmac *ixf1010_mac_create(adapter_t *adapter, int index)
struct cmac *mac;
u32 val;
- if (index > 9) return NULL;
+ if (index > 9)
+ return NULL;
mac = kzalloc(sizeof(*mac) + sizeof(cmac_instance), GFP_KERNEL);
- if (!mac) return NULL;
+ if (!mac)
+ return NULL;
mac->ops = &ixf1010_ops;
mac->instance = (cmac_instance *)(mac + 1);
diff --git a/drivers/net/chelsio/mv88e1xxx.c b/drivers/net/chelsio/mv88e1xxx.c
index 28ac93ff7c4..5867e3b0a88 100644
--- a/drivers/net/chelsio/mv88e1xxx.c
+++ b/drivers/net/chelsio/mv88e1xxx.c
@@ -73,9 +73,8 @@ static int mv88e1xxx_interrupt_enable(struct cphy *cphy)
t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer);
elmer |= ELMER0_GP_BIT1;
- if (is_T2(cphy->adapter)) {
- elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4;
- }
+ if (is_T2(cphy->adapter))
+ elmer |= ELMER0_GP_BIT2 | ELMER0_GP_BIT3 | ELMER0_GP_BIT4;
t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer);
}
return 0;
@@ -92,9 +91,8 @@ static int mv88e1xxx_interrupt_disable(struct cphy *cphy)
t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer);
elmer &= ~ELMER0_GP_BIT1;
- if (is_T2(cphy->adapter)) {
+ if (is_T2(cphy->adapter))
elmer &= ~(ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4);
- }
t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer);
}
return 0;
@@ -112,9 +110,8 @@ static int mv88e1xxx_interrupt_clear(struct cphy *cphy)
if (t1_is_asic(cphy->adapter)) {
t1_tpi_read(cphy->adapter, A_ELMER0_INT_CAUSE, &elmer);
elmer |= ELMER0_GP_BIT1;
- if (is_T2(cphy->adapter)) {
+ if (is_T2(cphy->adapter))
elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4;
- }
t1_tpi_write(cphy->adapter, A_ELMER0_INT_CAUSE, elmer);
}
return 0;
@@ -300,7 +297,7 @@ static int mv88e1xxx_interrupt_handler(struct cphy *cphy)
/*
* Loop until cause reads zero. Need to handle bouncing interrupts.
- */
+ */
while (1) {
u32 cause;
@@ -308,15 +305,16 @@ static int mv88e1xxx_interrupt_handler(struct cphy *cphy)
MV88E1XXX_INTERRUPT_STATUS_REGISTER,
&cause);
cause &= INTR_ENABLE_MASK;
- if (!cause) break;
+ if (!cause)
+ break;
if (cause & MV88E1XXX_INTR_LINK_CHNG) {
(void) simple_mdio_read(cphy,
MV88E1XXX_SPECIFIC_STATUS_REGISTER, &status);
- if (status & MV88E1XXX_INTR_LINK_CHNG) {
+ if (status & MV88E1XXX_INTR_LINK_CHNG)
cphy->state |= PHY_LINK_UP;
- } else {
+ else {
cphy->state &= ~PHY_LINK_UP;
if (cphy->state & PHY_AUTONEG_EN)
cphy->state &= ~PHY_AUTONEG_RDY;
@@ -360,7 +358,8 @@ static struct cphy *mv88e1xxx_phy_create(adapter_t *adapter, int phy_addr,
{
struct cphy *cphy = kzalloc(sizeof(*cphy), GFP_KERNEL);
- if (!cphy) return NULL;
+ if (!cphy)
+ return NULL;
cphy_init(cphy, adapter, phy_addr, &mv88e1xxx_ops, mdio_ops);
@@ -377,11 +376,11 @@ static struct cphy *mv88e1xxx_phy_create(adapter_t *adapter, int phy_addr,
}
(void) mv88e1xxx_downshift_set(cphy, 1); /* Enable downshift */
- /* LED */
+ /* LED */
if (is_T2(adapter)) {
(void) simple_mdio_write(cphy,
MV88E1XXX_LED_CONTROL_REGISTER, 0x1);
- }
+ }
return cphy;
}
diff --git a/drivers/net/chelsio/my3126.c b/drivers/net/chelsio/my3126.c
index 82fed1dd500..87dde3e6004 100644
--- a/drivers/net/chelsio/my3126.c
+++ b/drivers/net/chelsio/my3126.c
@@ -10,25 +10,25 @@ static int my3126_reset(struct cphy *cphy, int wait)
* This can be done through registers. It is not required since
* a full chip reset is used.
*/
- return (0);
+ return 0;
}
static int my3126_interrupt_enable(struct cphy *cphy)
{
schedule_delayed_work(&cphy->phy_update, HZ/30);
t1_tpi_read(cphy->adapter, A_ELMER0_GPO, &cphy->elmer_gpo);
- return (0);
+ return 0;
}
static int my3126_interrupt_disable(struct cphy *cphy)
{
cancel_rearming_delayed_work(&cphy->phy_update);
- return (0);
+ return 0;
}
static int my3126_interrupt_clear(struct cphy *cphy)
{
- return (0);
+ return 0;
}
#define OFFSET(REG_ADDR) (REG_ADDR << 2)
@@ -102,7 +102,7 @@ static void my3216_poll(struct work_struct *work)
static int my3126_set_loopback(struct cphy *cphy, int on)
{
- return (0);
+ return 0;
}
/* To check the activity LED */
@@ -146,7 +146,7 @@ static int my3126_get_link_status(struct cphy *cphy,
if (fc)
*fc = PAUSE_RX | PAUSE_TX;
- return (0);
+ return 0;
}
static void my3126_destroy(struct cphy *cphy)
@@ -177,7 +177,7 @@ static struct cphy *my3126_phy_create(adapter_t *adapter,
INIT_DELAYED_WORK(&cphy->phy_update, my3216_poll);
cphy->bmsr = 0;
- return (cphy);
+ return cphy;
}
/* Chip Reset */
@@ -198,7 +198,7 @@ static int my3126_phy_reset(adapter_t * adapter)
val |= 0x8000;
t1_tpi_write(adapter, A_ELMER0_GPO, val);
udelay(100);
- return (0);
+ return 0;
}
struct gphy t1_my3126_ops = {
diff --git a/drivers/net/chelsio/pm3393.c b/drivers/net/chelsio/pm3393.c
index 63cabeb98af..69129edeefd 100644
--- a/drivers/net/chelsio/pm3393.c
+++ b/drivers/net/chelsio/pm3393.c
@@ -446,17 +446,51 @@ static void pm3393_rmon_update(struct adapter *adapter, u32 offs, u64 *val,
*val += 1ull << 40;
}
-#define RMON_UPDATE(mac, name, stat_name) \
- pm3393_rmon_update((mac)->adapter, OFFSET(name), \
- &(mac)->stats.stat_name, \
- (ro &((name - SUNI1x10GEXP_REG_MSTAT_COUNTER_0_LOW) >> 2)))
-
-
static const struct cmac_statistics *pm3393_update_statistics(struct cmac *mac,
int flag)
{
- u64 ro;
- u32 val0, val1, val2, val3;
+ static struct {
+ unsigned int reg;
+ unsigned int offset;
+ } hw_stats [] = {
+
+#define HW_STAT(name, stat_name) \
+ { name, (&((struct cmac_statistics *)NULL)->stat_name) - (u64 *)NULL }
+
+ /* Rx stats */
+ HW_STAT(RxOctetsReceivedOK, RxOctetsOK),
+ HW_STAT(RxUnicastFramesReceivedOK, RxUnicastFramesOK),
+ HW_STAT(RxMulticastFramesReceivedOK, RxMulticastFramesOK),
+ HW_STAT(RxBroadcastFramesReceivedOK, RxBroadcastFramesOK),
+ HW_STAT(RxPAUSEMACCtrlFramesReceived, RxPauseFrames),
+ HW_STAT(RxFrameCheckSequenceErrors, RxFCSErrors),
+ HW_STAT(RxFramesLostDueToInternalMACErrors,
+ RxInternalMACRcvError),
+ HW_STAT(RxSymbolErrors, RxSymbolErrors),
+ HW_STAT(RxInRangeLengthErrors, RxInRangeLengthErrors),
+ HW_STAT(RxFramesTooLongErrors , RxFrameTooLongErrors),
+ HW_STAT(RxJabbers, RxJabberErrors),
+ HW_STAT(RxFragments, RxRuntErrors),
+ HW_STAT(RxUndersizedFrames, RxRuntErrors),
+ HW_STAT(RxJumboFramesReceivedOK, RxJumboFramesOK),
+ HW_STAT(RxJumboOctetsReceivedOK, RxJumboOctetsOK),
+
+ /* Tx stats */
+ HW_STAT(TxOctetsTransmittedOK, TxOctetsOK),
+ HW_STAT(TxFramesLostDueToInternalMACTransmissionError,
+ TxInternalMACXmitError),
+ HW_STAT(TxTransmitSystemError, TxFCSErrors),
+ HW_STAT(TxUnicastFramesTransmittedOK, TxUnicastFramesOK),
+ HW_STAT(TxMulticastFramesTransmittedOK, TxMulticastFramesOK),
+ HW_STAT(TxBroadcastFramesTransmittedOK, TxBroadcastFramesOK),
+ HW_STAT(TxPAUSEMACCtrlFramesTransmitted, TxPauseFrames),
+ HW_STAT(TxJumboFramesReceivedOK, TxJumboFramesOK),
+ HW_STAT(TxJumboOctetsReceivedOK, TxJumboOctetsOK)
+ }, *p = hw_stats;
+ u64 ro;
+ u32 val0, val1, val2, val3;
+ u64 *stats = (u64 *) &mac->stats;
+ unsigned int i;
/* Snap the counters */
pmwrite(mac, SUNI1x10GEXP_REG_MSTAT_CONTROL,
@@ -470,35 +504,14 @@ static const struct cmac_statistics *pm3393_update_statistics(struct cmac *mac,
ro = ((u64)val0 & 0xffff) | (((u64)val1 & 0xffff) << 16) |
(((u64)val2 & 0xffff) << 32) | (((u64)val3 & 0xffff) << 48);
- /* Rx stats */
- RMON_UPDATE(mac, RxOctetsReceivedOK, RxOctetsOK);
- RMON_UPDATE(mac, RxUnicastFramesReceivedOK, RxUnicastFramesOK);
- RMON_UPDATE(mac, RxMulticastFramesReceivedOK, RxMulticastFramesOK);
- RMON_UPDATE(mac, RxBroadcastFramesReceivedOK, RxBroadcastFramesOK);
- RMON_UPDATE(mac, RxPAUSEMACCtrlFramesReceived, RxPauseFrames);
- RMON_UPDATE(mac, RxFrameCheckSequenceErrors, RxFCSErrors);
- RMON_UPDATE(mac, RxFramesLostDueToInternalMACErrors,
- RxInternalMACRcvError);
- RMON_UPDATE(mac, RxSymbolErrors, RxSymbolErrors);
- RMON_UPDATE(mac, RxInRangeLengthErrors, RxInRangeLengthErrors);
- RMON_UPDATE(mac, RxFramesTooLongErrors , RxFrameTooLongErrors);
- RMON_UPDATE(mac, RxJabbers, RxJabberErrors);
- RMON_UPDATE(mac, RxFragments, RxRuntErrors);
- RMON_UPDATE(mac, RxUndersizedFrames, RxRuntErrors);
- RMON_UPDATE(mac, RxJumboFramesReceivedOK, RxJumboFramesOK);
- RMON_UPDATE(mac, RxJumboOctetsReceivedOK, RxJumboOctetsOK);
-
- /* Tx stats */
- RMON_UPDATE(mac, TxOctetsTransmittedOK, TxOctetsOK);
- RMON_UPDATE(mac, TxFramesLostDueToInternalMACTransmissionError,
- TxInternalMACXmitError);
- RMON_UPDATE(mac, TxTransmitSystemError, TxFCSErrors);
- RMON_UPDATE(mac, TxUnicastFramesTransmittedOK, TxUnicastFramesOK);
- RMON_UPDATE(mac, TxMulticastFramesTransmittedOK, TxMulticastFramesOK);
- RMON_UPDATE(mac, TxBroadcastFramesTransmittedOK, TxBroadcastFramesOK);
- RMON_UPDATE(mac, TxPAUSEMACCtrlFramesTransmitted, TxPauseFrames);
- RMON_UPDATE(mac, TxJumboFramesReceivedOK, TxJumboFramesOK);
- RMON_UPDATE(mac, TxJumboOctetsReceivedOK, TxJumboOctetsOK);
+ for (i = 0; i < ARRAY_SIZE(hw_stats); i++) {
+ unsigned reg = p->reg - SUNI1x10GEXP_REG_MSTAT_COUNTER_0_LOW;
+
+ pm3393_rmon_update((mac)->adapter, OFFSET(p->reg),
+ stats + p->offset, ro & (reg >> 2));
+ }
+
+
return &mac->stats;
}
@@ -534,9 +547,9 @@ static int pm3393_macaddress_set(struct cmac *cmac, u8 ma[6])
/* Store local copy */
memcpy(cmac->instance->mac_addr, ma, 6);
- lo = ((u32) ma[1] << 8) | (u32) ma[0];
+ lo = ((u32) ma[1] << 8) | (u32) ma[0];
mid = ((u32) ma[3] << 8) | (u32) ma[2];
- hi = ((u32) ma[5] << 8) | (u32) ma[4];
+ hi = ((u32) ma[5] << 8) | (u32) ma[4];
/* Disable Rx/Tx MAC before configuring it. */
if (enabled)
diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c
index 659cb2252e4..89a682702fa 100644
--- a/drivers/net/chelsio/sge.c
+++ b/drivers/net/chelsio/sge.c
@@ -71,12 +71,9 @@
#define SGE_FREEL_REFILL_THRESH 16
#define SGE_RESPQ_E_N 1024
#define SGE_INTRTIMER_NRES 1000
-#define SGE_RX_COPY_THRES 256
#define SGE_RX_SM_BUF_SIZE 1536
#define SGE_TX_DESC_MAX_PLEN 16384
-# define SGE_RX_DROP_THRES 2
-
#define SGE_RESPQ_REPLENISH_THRES (SGE_RESPQ_E_N / 4)
/*
@@ -85,10 +82,6 @@
*/
#define TX_RECLAIM_PERIOD (HZ / 4)
-#ifndef NET_IP_ALIGN
-# define NET_IP_ALIGN 2
-#endif
-
#define M_CMD_LEN 0x7fffffff
#define V_CMD_LEN(v) (v)
#define G_CMD_LEN(v) ((v) & M_CMD_LEN)
@@ -195,7 +188,7 @@ struct cmdQ {
struct cmdQ_e *entries; /* HW command descriptor Q */
struct cmdQ_ce *centries; /* SW command context descriptor Q */
dma_addr_t dma_addr; /* DMA addr HW command descriptor Q */
- spinlock_t lock; /* Lock to protect cmdQ enqueuing */
+ spinlock_t lock; /* Lock to protect cmdQ enqueuing */
};
struct freelQ {
@@ -241,9 +234,9 @@ struct sched_port {
/* Per T204 device */
struct sched {
ktime_t last_updated; /* last time quotas were computed */
- unsigned int max_avail; /* max bits to be sent to any port */
- unsigned int port; /* port index (round robin ports) */
- unsigned int num; /* num skbs in per port queues */
+ unsigned int max_avail; /* max bits to be sent to any port */
+ unsigned int port; /* port index (round robin ports) */
+ unsigned int num; /* num skbs in per port queues */
struct sched_port p[MAX_NPORTS];
struct tasklet_struct sched_tsk;/* tasklet used to run scheduler */
};
@@ -259,10 +252,10 @@ static void restart_sched(unsigned long);
* contention.
*/
struct sge {
- struct adapter *adapter; /* adapter backpointer */
+ struct adapter *adapter; /* adapter backpointer */
struct net_device *netdev; /* netdevice backpointer */
- struct freelQ freelQ[SGE_FREELQ_N]; /* buffer free lists */
- struct respQ respQ; /* response Q */
+ struct freelQ freelQ[SGE_FREELQ_N]; /* buffer free lists */
+ struct respQ respQ; /* response Q */
unsigned long stopped_tx_queues; /* bitmap of suspended Tx queues */
unsigned int rx_pkt_pad; /* RX padding for L2 packets */
unsigned int jumbo_fl; /* jumbo freelist Q index */
@@ -460,7 +453,7 @@ static struct sk_buff *sched_skb(struct sge *sge, struct sk_buff *skb,
if (credits < MAX_SKB_FRAGS + 1)
goto out;
- again:
+again:
for (i = 0; i < MAX_NPORTS; i++) {
s->port = ++s->port & (MAX_NPORTS - 1);
skbq = &s->p[s->port].skbq;
@@ -483,8 +476,8 @@ static struct sk_buff *sched_skb(struct sge *sge, struct sk_buff *skb,
if (update-- && sched_update_avail(sge))
goto again;
- out:
- /* If there are more pending skbs, we use the hardware to schedule us
+out:
+ /* If there are more pending skbs, we use the hardware to schedule us
* again.
*/
if (s->num && !skb) {
@@ -575,11 +568,10 @@ static int alloc_rx_resources(struct sge *sge, struct sge_params *p)
q->size = p->freelQ_size[i];
q->dma_offset = sge->rx_pkt_pad ? 0 : NET_IP_ALIGN;
size = sizeof(struct freelQ_e) * q->size;
- q->entries = (struct freelQ_e *)
- pci_alloc_consistent(pdev, size, &q->dma_addr);
+ q->entries = pci_alloc_consistent(pdev, size, &q->dma_addr);
if (!q->entries)
goto err_no_mem;
- memset(q->entries, 0, size);
+
size = sizeof(struct freelQ_ce) * q->size;
q->centries = kzalloc(size, GFP_KERNEL);
if (!q->centries)
@@ -613,11 +605,10 @@ static int alloc_rx_resources(struct sge *sge, struct sge_params *p)
sge->respQ.size = SGE_RESPQ_E_N;
sge->respQ.credits = 0;
size = sizeof(struct respQ_e) * sge->respQ.size;
- sge->respQ.entries = (struct respQ_e *)
+ sge->respQ.entries =
pci_alloc_consistent(pdev, size, &sge->respQ.dma_addr);
if (!sge->respQ.entries)
goto err_no_mem;
- memset(sge->respQ.entries, 0, size);
return 0;
err_no_mem:
@@ -637,20 +628,12 @@ static void free_cmdQ_buffers(struct sge *sge, struct cmdQ *q, unsigned int n)
q->in_use -= n;
ce = &q->centries[cidx];
while (n--) {
- if (q->sop) {
- if (likely(pci_unmap_len(ce, dma_len))) {
- pci_unmap_single(pdev,
- pci_unmap_addr(ce, dma_addr),
- pci_unmap_len(ce, dma_len),
- PCI_DMA_TODEVICE);
+ if (likely(pci_unmap_len(ce, dma_len))) {
+ pci_unmap_single(pdev, pci_unmap_addr(ce, dma_addr),
+ pci_unmap_len(ce, dma_len),
+ PCI_DMA_TODEVICE);
+ if (q->sop)
q->sop = 0;
- }
- } else {
- if (likely(pci_unmap_len(ce, dma_len))) {
- pci_unmap_page(pdev, pci_unmap_addr(ce, dma_addr),
- pci_unmap_len(ce, dma_len),
- PCI_DMA_TODEVICE);
- }
}
if (ce->skb) {
dev_kfree_skb_any(ce->skb);
@@ -711,11 +694,10 @@ static int alloc_tx_resources(struct sge *sge, struct sge_params *p)
q->stop_thres = 0;
spin_lock_init(&q->lock);
size = sizeof(struct cmdQ_e) * q->size;
- q->entries = (struct cmdQ_e *)
- pci_alloc_consistent(pdev, size, &q->dma_addr);
+ q->entries = pci_alloc_consistent(pdev, size, &q->dma_addr);
if (!q->entries)
goto err_no_mem;
- memset(q->entries, 0, size);
+
size = sizeof(struct cmdQ_ce) * q->size;
q->centries = kzalloc(size, GFP_KERNEL);
if (!q->centries)
@@ -770,7 +752,7 @@ void t1_set_vlan_accel(struct adapter *adapter, int on_off)
static void configure_sge(struct sge *sge, struct sge_params *p)
{
struct adapter *ap = sge->adapter;
-
+
writel(0, ap->regs + A_SG_CONTROL);
setup_ring_params(ap, sge->cmdQ[0].dma_addr, sge->cmdQ[0].size,
A_SG_CMD0BASELWR, A_SG_CMD0BASEUPR, A_SG_CMD0SIZE);
@@ -850,7 +832,6 @@ static void refill_free_list(struct sge *sge, struct freelQ *q)
struct freelQ_e *e = &q->entries[q->pidx];
unsigned int dma_len = q->rx_buffer_size - q->dma_offset;
-
while (q->credits < q->size) {
struct sk_buff *skb;
dma_addr_t mapping;
@@ -862,6 +843,8 @@ static void refill_free_list(struct sge *sge, struct freelQ *q)
skb_reserve(skb, q->dma_offset);
mapping = pci_map_single(pdev, skb->data, dma_len,
PCI_DMA_FROMDEVICE);
+ skb_reserve(skb, sge->rx_pkt_pad);
+
ce->skb = skb;
pci_unmap_addr_set(ce, dma_addr, mapping);
pci_unmap_len_set(ce, dma_len, dma_len);
@@ -881,7 +864,6 @@ static void refill_free_list(struct sge *sge, struct freelQ *q)
}
q->credits++;
}
-
}
/*
@@ -1041,6 +1023,10 @@ static void recycle_fl_buf(struct freelQ *fl, int idx)
}
}
+static int copybreak __read_mostly = 256;
+module_param(copybreak, int, 0);
+MODULE_PARM_DESC(copybreak, "Receive copy threshold");
+
/**
* get_packet - return the next ingress packet buffer
* @pdev: the PCI device that received the packet
@@ -1060,45 +1046,42 @@ static void recycle_fl_buf(struct freelQ *fl, int idx)
* be copied but there is no memory for the copy.
*/
static inline struct sk_buff *get_packet(struct pci_dev *pdev,
- struct freelQ *fl, unsigned int len,
- int dma_pad, int skb_pad,
- unsigned int copy_thres,
- unsigned int drop_thres)
+ struct freelQ *fl, unsigned int len)
{
struct sk_buff *skb;
- struct freelQ_ce *ce = &fl->centries[fl->cidx];
+ const struct freelQ_ce *ce = &fl->centries[fl->cidx];
- if (len < copy_thres) {
- skb = alloc_skb(len + skb_pad, GFP_ATOMIC);
- if (likely(skb != NULL)) {
- skb_reserve(skb, skb_pad);
- skb_put(skb, len);
- pci_dma_sync_single_for_cpu(pdev,
- pci_unmap_addr(ce, dma_addr),
- pci_unmap_len(ce, dma_len),
- PCI_DMA_FROMDEVICE);
- memcpy(skb->data, ce->skb->data + dma_pad, len);
- pci_dma_sync_single_for_device(pdev,
- pci_unmap_addr(ce, dma_addr),
- pci_unmap_len(ce, dma_len),
- PCI_DMA_FROMDEVICE);
- } else if (!drop_thres)
+ if (len < copybreak) {
+ skb = alloc_skb(len + 2, GFP_ATOMIC);
+ if (!skb)
goto use_orig_buf;
+ skb_reserve(skb, 2); /* align IP header */
+ skb_put(skb, len);
+ pci_dma_sync_single_for_cpu(pdev,
+ pci_unmap_addr(ce, dma_addr),
+ pci_unmap_len(ce, dma_len),
+ PCI_DMA_FROMDEVICE);
+ memcpy(skb->data, ce->skb->data, len);
+ pci_dma_sync_single_for_device(pdev,
+ pci_unmap_addr(ce, dma_addr),
+ pci_unmap_len(ce, dma_len),
+ PCI_DMA_FROMDEVICE);
recycle_fl_buf(fl, fl->cidx);
return skb;
}
- if (fl->credits < drop_thres) {
+use_orig_buf:
+ if (fl->credits < 2) {
recycle_fl_buf(fl, fl->cidx);
return NULL;
}
-use_orig_buf:
pci_unmap_single(pdev, pci_unmap_addr(ce, dma_addr),
pci_unmap_len(ce, dma_len), PCI_DMA_FROMDEVICE);
skb = ce->skb;
- skb_reserve(skb, dma_pad);
+ prefetch(skb->data);
+
skb_put(skb, len);
return skb;
}
@@ -1137,6 +1120,7 @@ static void unexpected_offload(struct adapter *adapter, struct freelQ *fl)
static inline unsigned int compute_large_page_tx_descs(struct sk_buff *skb)
{
unsigned int count = 0;
+
if (PAGE_SIZE > SGE_TX_DESC_MAX_PLEN) {
unsigned int nfrags = skb_shinfo(skb)->nr_frags;
unsigned int i, len = skb->len - skb->data_len;
@@ -1343,7 +1327,7 @@ static void restart_sched(unsigned long arg)
while ((skb = sched_skb(sge, NULL, credits)) != NULL) {
unsigned int genbit, pidx, count;
count = 1 + skb_shinfo(skb)->nr_frags;
- count += compute_large_page_tx_descs(skb);
+ count += compute_large_page_tx_descs(skb);
q->in_use += count;
genbit = q->genbit;
pidx = q->pidx;
@@ -1375,27 +1359,25 @@ static void restart_sched(unsigned long arg)
*
* Process an ingress ethernet pakcet and deliver it to the stack.
*/
-static int sge_rx(struct sge *sge, struct freelQ *fl, unsigned int len)
+static void sge_rx(struct sge *sge, struct freelQ *fl, unsigned int len)
{
struct sk_buff *skb;
- struct cpl_rx_pkt *p;
+ const struct cpl_rx_pkt *p;
struct adapter *adapter = sge->adapter;
struct sge_port_stats *st;
- skb = get_packet(adapter->pdev, fl, len - sge->rx_pkt_pad,
- sge->rx_pkt_pad, 2, SGE_RX_COPY_THRES,
- SGE_RX_DROP_THRES);
+ skb = get_packet(adapter->pdev, fl, len - sge->rx_pkt_pad);
if (unlikely(!skb)) {
sge->stats.rx_drops++;
- return 0;
+ return;
}
- p = (struct cpl_rx_pkt *)skb->data;
- skb_pull(skb, sizeof(*p));
+ p = (const struct cpl_rx_pkt *) skb->data;
if (p->iff >= adapter->params.nports) {
kfree_skb(skb);
- return 0;
+ return;
}
+ __skb_pull(skb, sizeof(*p));
skb->dev = adapter->port[p->iff].dev;
skb->dev->last_rx = jiffies;
@@ -1427,7 +1409,6 @@ static int sge_rx(struct sge *sge, struct freelQ *fl, unsigned int len)
netif_rx(skb);
#endif
}
- return 0;
}
/*
@@ -1448,29 +1429,28 @@ static inline int enough_free_Tx_descs(const struct cmdQ *q)
static void restart_tx_queues(struct sge *sge)
{
struct adapter *adap = sge->adapter;
+ int i;
- if (enough_free_Tx_descs(&sge->cmdQ[0])) {
- int i;
+ if (!enough_free_Tx_descs(&sge->cmdQ[0]))
+ return;
- for_each_port(adap, i) {
- struct net_device *nd = adap->port[i].dev;
+ for_each_port(adap, i) {
+ struct net_device *nd = adap->port[i].dev;
- if (test_and_clear_bit(nd->if_port,
- &sge->stopped_tx_queues) &&
- netif_running(nd)) {
- sge->stats.cmdQ_restarted[2]++;
- netif_wake_queue(nd);
- }
+ if (test_and_clear_bit(nd->if_port, &sge->stopped_tx_queues) &&
+ netif_running(nd)) {
+ sge->stats.cmdQ_restarted[2]++;
+ netif_wake_queue(nd);
}
}
}
/*
- * update_tx_info is called from the interrupt handler/NAPI to return cmdQ0
+ * update_tx_info is called from the interrupt handler/NAPI to return cmdQ0
* information.
*/
-static unsigned int update_tx_info(struct adapter *adapter,
- unsigned int flags,
+static unsigned int update_tx_info(struct adapter *adapter,
+ unsigned int flags,
unsigned int pr0)
{
struct sge *sge = adapter->sge;
@@ -1510,29 +1490,30 @@ static int process_responses(struct adapter *adapter, int budget)
struct sge *sge = adapter->sge;
struct respQ *q = &sge->respQ;
struct respQ_e *e = &q->entries[q->cidx];
- int budget_left = budget;
+ int done = 0;
unsigned int flags = 0;
unsigned int cmdq_processed[SGE_CMDQ_N] = {0, 0};
-
- while (likely(budget_left && e->GenerationBit == q->genbit)) {
+ while (done < budget && e->GenerationBit == q->genbit) {
flags |= e->Qsleeping;
-
+
cmdq_processed[0] += e->Cmdq0CreditReturn;
cmdq_processed[1] += e->Cmdq1CreditReturn;
-
+
/* We batch updates to the TX side to avoid cacheline
* ping-pong of TX state information on MP where the sender
* might run on a different CPU than this function...
*/
- if (unlikely(flags & F_CMDQ0_ENABLE || cmdq_processed[0] > 64)) {
+ if (unlikely((flags & F_CMDQ0_ENABLE) || cmdq_processed[0] > 64)) {
flags = update_tx_info(adapter, flags, cmdq_processed[0]);
cmdq_processed[0] = 0;
}
+
if (unlikely(cmdq_processed[1] > 16)) {
sge->cmdQ[1].processed += cmdq_processed[1];
cmdq_processed[1] = 0;
}
+
if (likely(e->DataValid)) {
struct freelQ *fl = &sge->freelQ[e->FreelistQid];
@@ -1542,12 +1523,16 @@ static int process_responses(struct adapter *adapter, int budget)
else
sge_rx(sge, fl, e->BufferLength);
+ ++done;
+
/*
* Note: this depends on each packet consuming a
* single free-list buffer; cf. the BUG above.
*/
if (++fl->cidx == fl->size)
fl->cidx = 0;
+ prefetch(fl->centries[fl->cidx].skb);
+
if (unlikely(--fl->credits <
fl->size - SGE_FREEL_REFILL_THRESH))
refill_free_list(sge, fl);
@@ -1566,14 +1551,20 @@ static int process_responses(struct adapter *adapter, int budget)
writel(q->credits, adapter->regs + A_SG_RSPQUEUECREDIT);
q->credits = 0;
}
- --budget_left;
}
- flags = update_tx_info(adapter, flags, cmdq_processed[0]);
+ flags = update_tx_info(adapter, flags, cmdq_processed[0]);
sge->cmdQ[1].processed += cmdq_processed[1];
- budget -= budget_left;
- return budget;
+ return done;
+}
+
+static inline int responses_pending(const struct adapter *adapter)
+{
+ const struct respQ *Q = &adapter->sge->respQ;
+ const struct respQ_e *e = &Q->entries[Q->cidx];
+
+ return (e->GenerationBit == Q->genbit);
}
#ifdef CONFIG_CHELSIO_T1_NAPI
@@ -1585,19 +1576,25 @@ static int process_responses(struct adapter *adapter, int budget)
* which the caller must ensure is a valid pure response. Returns 1 if it
* encounters a valid data-carrying response, 0 otherwise.
*/
-static int process_pure_responses(struct adapter *adapter, struct respQ_e *e)
+static int process_pure_responses(struct adapter *adapter)
{
struct sge *sge = adapter->sge;
struct respQ *q = &sge->respQ;
+ struct respQ_e *e = &q->entries[q->cidx];
+ const struct freelQ *fl = &sge->freelQ[e->FreelistQid];
unsigned int flags = 0;
unsigned int cmdq_processed[SGE_CMDQ_N] = {0, 0};
+ prefetch(fl->centries[fl->cidx].skb);
+ if (e->DataValid)
+ return 1;
+
do {
flags |= e->Qsleeping;
cmdq_processed[0] += e->Cmdq0CreditReturn;
cmdq_processed[1] += e->Cmdq1CreditReturn;
-
+
e++;
if (unlikely(++q->cidx == q->size)) {
q->cidx = 0;
@@ -1613,7 +1610,7 @@ static int process_pure_responses(struct adapter *adapter, struct respQ_e *e)
sge->stats.pure_rsps++;
} while (e->GenerationBit == q->genbit && !e->DataValid);
- flags = update_tx_info(adapter, flags, cmdq_processed[0]);
+ flags = update_tx_info(adapter, flags, cmdq_processed[0]);
sge->cmdQ[1].processed += cmdq_processed[1];
return e->GenerationBit == q->genbit;
@@ -1627,23 +1624,20 @@ static int process_pure_responses(struct adapter *adapter, struct respQ_e *e)
int t1_poll(struct net_device *dev, int *budget)
{
struct adapter *adapter = dev->priv;
- int effective_budget = min(*budget, dev->quota);
- int work_done = process_responses(adapter, effective_budget);
+ int work_done;
+ work_done = process_responses(adapter, min(*budget, dev->quota));
*budget -= work_done;
dev->quota -= work_done;
- if (work_done >= effective_budget)
+ if (unlikely(responses_pending(adapter)))
return 1;
- spin_lock_irq(&adapter->async_lock);
- __netif_rx_complete(dev);
+ netif_rx_complete(dev);
writel(adapter->sge->respQ.cidx, adapter->regs + A_SG_SLEEPING);
- writel(adapter->slow_intr_mask | F_PL_INTR_SGE_DATA,
- adapter->regs + A_PL_ENABLE);
- spin_unlock_irq(&adapter->async_lock);
return 0;
+
}
/*
@@ -1652,44 +1646,33 @@ int t1_poll(struct net_device *dev, int *budget)
irqreturn_t t1_interrupt(int irq, void *data)
{
struct adapter *adapter = data;
- struct net_device *dev = adapter->sge->netdev;
struct sge *sge = adapter->sge;
- u32 cause;
- int handled = 0;
+ int handled;
- cause = readl(adapter->regs + A_PL_CAUSE);
- if (cause == 0 || cause == ~0)
- return IRQ_NONE;
+ if (likely(responses_pending(adapter))) {
+ struct net_device *dev = sge->netdev;
- spin_lock(&adapter->async_lock);
- if (cause & F_PL_INTR_SGE_DATA) {
- struct respQ *q = &adapter->sge->respQ;
- struct respQ_e *e = &q->entries[q->cidx];
-
- handled = 1;
- writel(F_PL_INTR_SGE_DATA, adapter->regs + A_PL_CAUSE);
-
- if (e->GenerationBit == q->genbit &&
- __netif_rx_schedule_prep(dev)) {
- if (e->DataValid || process_pure_responses(adapter, e)) {
- /* mask off data IRQ */
- writel(adapter->slow_intr_mask,
- adapter->regs + A_PL_ENABLE);
- __netif_rx_schedule(sge->netdev);
- goto unlock;
- }
- /* no data, no NAPI needed */
- netif_poll_enable(dev);
+ writel(F_PL_INTR_SGE_DATA, adapter->regs + A_PL_CAUSE);
+ if (__netif_rx_schedule_prep(dev)) {
+ if (process_pure_responses(adapter))
+ __netif_rx_schedule(dev);
+ else {
+ /* no data, no NAPI needed */
+ writel(sge->respQ.cidx, adapter->regs + A_SG_SLEEPING);
+ netif_poll_enable(dev); /* undo schedule_prep */
+ }
}
- writel(q->cidx, adapter->regs + A_SG_SLEEPING);
- } else
- handled = t1_slow_intr_handler(adapter);
+ return IRQ_HANDLED;
+ }
+
+ spin_lock(&adapter->async_lock);
+ handled = t1_slow_intr_handler(adapter);
+ spin_unlock(&adapter->async_lock);
if (!handled)
sge->stats.unhandled_irqs++;
-unlock:
- spin_unlock(&adapter->async_lock);
+
return IRQ_RETVAL(handled != 0);
}
@@ -1712,17 +1695,13 @@ unlock:
irqreturn_t t1_interrupt(int irq, void *cookie)
{
int work_done;
- struct respQ_e *e;
struct adapter *adapter = cookie;
- struct respQ *Q = &adapter->sge->respQ;
spin_lock(&adapter->async_lock);
- e = &Q->entries[Q->cidx];
- prefetch(e);
writel(F_PL_INTR_SGE_DATA, adapter->regs + A_PL_CAUSE);
- if (likely(e->GenerationBit == Q->genbit))
+ if (likely(responses_pending(adapter)))
work_done = process_responses(adapter, -1);
else
work_done = t1_slow_intr_handler(adapter);
@@ -1796,7 +1775,7 @@ static int t1_sge_tx(struct sk_buff *skb, struct adapter *adapter,
* through the scheduler.
*/
if (sge->tx_sched && !qid && skb->dev) {
- use_sched:
+use_sched:
use_sched_skb = 1;
/* Note that the scheduler might return a different skb than
* the one passed in.
@@ -1900,7 +1879,7 @@ int t1_start_xmit(struct sk_buff *skb, struct net_device *dev)
cpl = (struct cpl_tx_pkt *)hdr;
} else {
/*
- * Packets shorter than ETH_HLEN can break the MAC, drop them
+ * Packets shorter than ETH_HLEN can break the MAC, drop them
* early. Also, we may get oversized packets because some
* parts of the kernel don't handle our unusual hard_header_len
* right, drop those too.
@@ -1984,9 +1963,9 @@ send:
* then silently discard to avoid leak.
*/
if (unlikely(ret != NETDEV_TX_OK && skb != orig_skb)) {
- dev_kfree_skb_any(skb);
+ dev_kfree_skb_any(skb);
ret = NETDEV_TX_OK;
- }
+ }
return ret;
}
@@ -2099,31 +2078,35 @@ static void espibug_workaround_t204(unsigned long data)
if (adapter->open_device_map & PORT_MASK) {
int i;
- if (t1_espi_get_mon_t204(adapter, &(seop[0]), 0) < 0) {
+
+ if (t1_espi_get_mon_t204(adapter, &(seop[0]), 0) < 0)
return;
- }
+
for (i = 0; i < nports; i++) {
- struct sk_buff *skb = sge->espibug_skb[i];
- if ( (netif_running(adapter->port[i].dev)) &&
- !(netif_queue_stopped(adapter->port[i].dev)) &&
- (seop[i] && ((seop[i] & 0xfff) == 0)) &&
- skb ) {
- if (!skb->cb[0]) {
- u8 ch_mac_addr[ETH_ALEN] =
- {0x0, 0x7, 0x43, 0x0, 0x0, 0x0};
- memcpy(skb->data + sizeof(struct cpl_tx_pkt),
- ch_mac_addr, ETH_ALEN);
- memcpy(skb->data + skb->len - 10,
- ch_mac_addr, ETH_ALEN);
- skb->cb[0] = 0xff;
- }
-
- /* bump the reference count to avoid freeing of
- * the skb once the DMA has completed.
- */
- skb = skb_get(skb);
- t1_sge_tx(skb, adapter, 0, adapter->port[i].dev);
+ struct sk_buff *skb = sge->espibug_skb[i];
+
+ if (!netif_running(adapter->port[i].dev) ||
+ netif_queue_stopped(adapter->port[i].dev) ||
+ !seop[i] || ((seop[i] & 0xfff) != 0) || !skb)
+ continue;
+
+ if (!skb->cb[0]) {
+ u8 ch_mac_addr[ETH_ALEN] = {
+ 0x0, 0x7, 0x43, 0x0, 0x0, 0x0
+ };
+
+ memcpy(skb->data + sizeof(struct cpl_tx_pkt),
+ ch_mac_addr, ETH_ALEN);
+ memcpy(skb->data + skb->len - 10,
+ ch_mac_addr, ETH_ALEN);
+ skb->cb[0] = 0xff;
}
+
+ /* bump the reference count to avoid freeing of
+ * the skb once the DMA has completed.
+ */
+ skb = skb_get(skb);
+ t1_sge_tx(skb, adapter, 0, adapter->port[i].dev);
}
}
mod_timer(&sge->espibug_timer, jiffies + sge->espibug_timeout);
@@ -2192,9 +2175,8 @@ struct sge * __devinit t1_sge_create(struct adapter *adapter,
if (adapter->params.nports > 1) {
tx_sched_init(sge);
sge->espibug_timer.function = espibug_workaround_t204;
- } else {
+ } else
sge->espibug_timer.function = espibug_workaround;
- }
sge->espibug_timer.data = (unsigned long)sge->adapter;
sge->espibug_timeout = 1;
@@ -2202,7 +2184,7 @@ struct sge * __devinit t1_sge_create(struct adapter *adapter,
if (adapter->params.nports > 1)
sge->espibug_timeout = HZ/100;
}
-
+
p->cmdQ_size[0] = SGE_CMDQ0_E_N;
p->cmdQ_size[1] = SGE_CMDQ1_E_N;
diff --git a/drivers/net/chelsio/subr.c b/drivers/net/chelsio/subr.c
index 22ed9a383c0..c2522cdfab3 100644
--- a/drivers/net/chelsio/subr.c
+++ b/drivers/net/chelsio/subr.c
@@ -223,13 +223,13 @@ static int fpga_slow_intr(adapter_t *adapter)
t1_sge_intr_error_handler(adapter->sge);
if (cause & FPGA_PCIX_INTERRUPT_GMAC)
- fpga_phy_intr_handler(adapter);
+ fpga_phy_intr_handler(adapter);
if (cause & FPGA_PCIX_INTERRUPT_TP) {
- /*
+ /*
* FPGA doesn't support MC4 interrupts and it requires
* this odd layer of indirection for MC5.
- */
+ */
u32 tp_cause = readl(adapter->regs + FPGA_TP_ADDR_INTERRUPT_CAUSE);
/* Clear TP interrupt */
@@ -262,8 +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);
+ CH_ALERT("%s: MDIO operation timed out\n", adapter->name);
return busy;
}
@@ -605,22 +604,23 @@ int t1_elmer0_ext_intr_handler(adapter_t *adapter)
switch (board_info(adapter)->board) {
#ifdef CONFIG_CHELSIO_T1_1G
- case CHBT_BOARD_CHT204:
- case CHBT_BOARD_CHT204E:
- case CHBT_BOARD_CHN204:
- case CHBT_BOARD_CHT204V: {
- int i, port_bit;
+ case CHBT_BOARD_CHT204:
+ case CHBT_BOARD_CHT204E:
+ case CHBT_BOARD_CHN204:
+ case CHBT_BOARD_CHT204V: {
+ int i, port_bit;
for_each_port(adapter, i) {
port_bit = i + 1;
- if (!(cause & (1 << port_bit))) continue;
+ if (!(cause & (1 << port_bit)))
+ continue;
- phy = adapter->port[i].phy;
+ phy = adapter->port[i].phy;
phy_cause = phy->ops->interrupt_handler(phy);
if (phy_cause & cphy_cause_link_change)
t1_link_changed(adapter, i);
}
- break;
- }
+ break;
+ }
case CHBT_BOARD_CHT101:
if (cause & ELMER0_GP_BIT1) { /* Marvell 88E1111 interrupt */
phy = adapter->port[0].phy;
@@ -631,13 +631,13 @@ int t1_elmer0_ext_intr_handler(adapter_t *adapter)
break;
case CHBT_BOARD_7500: {
int p;
- /*
+ /*
* Elmer0's interrupt cause isn't useful here because there is
* only one bit that can be set for all 4 ports. This means
* we are forced to check every PHY's interrupt status
* register to see who initiated the interrupt.
- */
- for_each_port(adapter, p) {
+ */
+ for_each_port(adapter, p) {
phy = adapter->port[p].phy;
phy_cause = phy->ops->interrupt_handler(phy);
if (phy_cause & cphy_cause_link_change)
@@ -658,7 +658,7 @@ 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",
+ CH_DBG(adapter, INTR, "External interrupt cause 0x%x\n",
cause);
if (cause & ELMER0_GP_BIT1) { /* PMC3393 INTB */
struct cmac *mac = adapter->port[0].mac;
@@ -670,9 +670,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",
+ CH_MSG(adapter, INFO, LINK, "XPAK %s\n",
mod_detect ? "removed" : "inserted");
- }
+ }
break;
#ifdef CONFIG_CHELSIO_T1_COUGAR
case CHBT_BOARD_COUGAR:
@@ -688,7 +688,8 @@ int t1_elmer0_ext_intr_handler(adapter_t *adapter)
for_each_port(adapter, i) {
port_bit = i ? i + 1 : 0;
- if (!(cause & (1 << port_bit))) continue;
+ if (!(cause & (1 << port_bit)))
+ continue;
phy = adapter->port[i].phy;
phy_cause = phy->ops->interrupt_handler(phy);
@@ -755,7 +756,7 @@ void t1_interrupts_disable(adapter_t* adapter)
/* Disable PCIX & external chip interrupts. */
if (t1_is_asic(adapter))
- writel(0, adapter->regs + A_PL_ENABLE);
+ writel(0, adapter->regs + A_PL_ENABLE);
/* PCI-X interrupts */
pci_write_config_dword(adapter->pdev, A_PCICFG_INTR_ENABLE, 0);
@@ -830,11 +831,11 @@ int t1_slow_intr_handler(adapter_t *adapter)
/* Power sequencing is a work-around for Intel's XPAKs. */
static void power_sequence_xpak(adapter_t* adapter)
{
- u32 mod_detect;
- u32 gpo;
+ u32 mod_detect;
+ u32 gpo;
- /* Check for XPAK */
- t1_tpi_read(adapter, A_ELMER0_GPI_STAT, &mod_detect);
+ /* Check for XPAK */
+ t1_tpi_read(adapter, A_ELMER0_GPI_STAT, &mod_detect);
if (!(ELMER0_GP_BIT5 & mod_detect)) {
/* XPAK is present */
t1_tpi_read(adapter, A_ELMER0_GPO, &gpo);
@@ -877,31 +878,31 @@ static int board_init(adapter_t *adapter, const struct board_info *bi)
case CHBT_BOARD_N210:
case CHBT_BOARD_CHT210:
case CHBT_BOARD_COUGAR:
- t1_tpi_par(adapter, 0xf);
- t1_tpi_write(adapter, A_ELMER0_GPO, 0x800);
+ t1_tpi_par(adapter, 0xf);
+ t1_tpi_write(adapter, A_ELMER0_GPO, 0x800);
break;
case CHBT_BOARD_CHT110:
- t1_tpi_par(adapter, 0xf);
- t1_tpi_write(adapter, A_ELMER0_GPO, 0x1800);
+ t1_tpi_par(adapter, 0xf);
+ t1_tpi_write(adapter, A_ELMER0_GPO, 0x1800);
- /* TBD XXX Might not need. This fixes a problem
- * described in the Intel SR XPAK errata.
- */
- power_sequence_xpak(adapter);
+ /* TBD XXX Might not need. This fixes a problem
+ * described in the Intel SR XPAK errata.
+ */
+ power_sequence_xpak(adapter);
break;
#ifdef CONFIG_CHELSIO_T1_1G
- case CHBT_BOARD_CHT204E:
- /* add config space write here */
+ case CHBT_BOARD_CHT204E:
+ /* add config space write here */
case CHBT_BOARD_CHT204:
case CHBT_BOARD_CHT204V:
case CHBT_BOARD_CHN204:
- t1_tpi_par(adapter, 0xf);
- t1_tpi_write(adapter, A_ELMER0_GPO, 0x804);
- break;
+ t1_tpi_par(adapter, 0xf);
+ t1_tpi_write(adapter, A_ELMER0_GPO, 0x804);
+ break;
case CHBT_BOARD_CHT101:
case CHBT_BOARD_7500:
- t1_tpi_par(adapter, 0xf);
- t1_tpi_write(adapter, A_ELMER0_GPO, 0x1804);
+ t1_tpi_par(adapter, 0xf);
+ t1_tpi_write(adapter, A_ELMER0_GPO, 0x1804);
break;
#endif
}
@@ -941,7 +942,7 @@ int t1_init_hw_modules(adapter_t *adapter)
goto out_err;
err = 0;
- out_err:
+out_err:
return err;
}
@@ -983,7 +984,7 @@ void t1_free_sw_modules(adapter_t *adapter)
if (adapter->espi)
t1_espi_destroy(adapter->espi);
#ifdef CONFIG_CHELSIO_T1_COUGAR
- if (adapter->cspi)
+ if (adapter->cspi)
t1_cspi_destroy(adapter->cspi);
#endif
}
@@ -1010,7 +1011,7 @@ static void __devinit init_link_config(struct link_config *lc,
CH_ERR("%s: CSPI initialization failed\n",
adapter->name);
goto error;
- }
+ }
#endif
/*
diff --git a/drivers/net/chelsio/tp.c b/drivers/net/chelsio/tp.c
index 0ca0b6e19e4..6222d585e44 100644
--- a/drivers/net/chelsio/tp.c
+++ b/drivers/net/chelsio/tp.c
@@ -17,39 +17,36 @@ struct petp {
static void tp_init(adapter_t * ap, const struct tp_params *p,
unsigned int tp_clk)
{
- if (t1_is_asic(ap)) {
- u32 val;
-
- val = F_TP_IN_CSPI_CPL | F_TP_IN_CSPI_CHECK_IP_CSUM |
- F_TP_IN_CSPI_CHECK_TCP_CSUM | F_TP_IN_ESPI_ETHERNET;
- if (!p->pm_size)
- val |= F_OFFLOAD_DISABLE;
- else
- val |= F_TP_IN_ESPI_CHECK_IP_CSUM |
- F_TP_IN_ESPI_CHECK_TCP_CSUM;
- writel(val, ap->regs + A_TP_IN_CONFIG);
- writel(F_TP_OUT_CSPI_CPL |
- F_TP_OUT_ESPI_ETHERNET |
- F_TP_OUT_ESPI_GENERATE_IP_CSUM |
- F_TP_OUT_ESPI_GENERATE_TCP_CSUM,
- ap->regs + A_TP_OUT_CONFIG);
- writel(V_IP_TTL(64) |
- F_PATH_MTU /* IP DF bit */ |
- V_5TUPLE_LOOKUP(p->use_5tuple_mode) |
- V_SYN_COOKIE_PARAMETER(29),
- ap->regs + A_TP_GLOBAL_CONFIG);
- /*
- * Enable pause frame deadlock prevention.
- */
- if (is_T2(ap) && ap->params.nports > 1) {
- u32 drop_ticks = DROP_MSEC * (tp_clk / 1000);
-
- writel(F_ENABLE_TX_DROP | F_ENABLE_TX_ERROR |
- V_DROP_TICKS_CNT(drop_ticks) |
- V_NUM_PKTS_DROPPED(DROP_PKTS_CNT),
- ap->regs + A_TP_TX_DROP_CONFIG);
- }
+ u32 val;
+ if (!t1_is_asic(ap))
+ return;
+
+ val = F_TP_IN_CSPI_CPL | F_TP_IN_CSPI_CHECK_IP_CSUM |
+ F_TP_IN_CSPI_CHECK_TCP_CSUM | F_TP_IN_ESPI_ETHERNET;
+ if (!p->pm_size)
+ val |= F_OFFLOAD_DISABLE;
+ else
+ val |= F_TP_IN_ESPI_CHECK_IP_CSUM | F_TP_IN_ESPI_CHECK_TCP_CSUM;
+ writel(val, ap->regs + A_TP_IN_CONFIG);
+ writel(F_TP_OUT_CSPI_CPL |
+ F_TP_OUT_ESPI_ETHERNET |
+ F_TP_OUT_ESPI_GENERATE_IP_CSUM |
+ F_TP_OUT_ESPI_GENERATE_TCP_CSUM, ap->regs + A_TP_OUT_CONFIG);
+ writel(V_IP_TTL(64) |
+ F_PATH_MTU /* IP DF bit */ |
+ V_5TUPLE_LOOKUP(p->use_5tuple_mode) |
+ V_SYN_COOKIE_PARAMETER(29), ap->regs + A_TP_GLOBAL_CONFIG);
+ /*
+ * Enable pause frame deadlock prevention.
+ */
+ if (is_T2(ap) && ap->params.nports > 1) {
+ u32 drop_ticks = DROP_MSEC * (tp_clk / 1000);
+
+ writel(F_ENABLE_TX_DROP | F_ENABLE_TX_ERROR |
+ V_DROP_TICKS_CNT(drop_ticks) |
+ V_NUM_PKTS_DROPPED(DROP_PKTS_CNT),
+ ap->regs + A_TP_TX_DROP_CONFIG);
}
}
@@ -61,6 +58,7 @@ void t1_tp_destroy(struct petp *tp)
struct petp *__devinit t1_tp_create(adapter_t * adapter, struct tp_params *p)
{
struct petp *tp = kzalloc(sizeof(*tp), GFP_KERNEL);
+
if (!tp)
return NULL;
diff --git a/drivers/net/chelsio/vsc7326.c b/drivers/net/chelsio/vsc7326.c
index 85dc3b1dc30..534ffa0f616 100644
--- a/drivers/net/chelsio/vsc7326.c
+++ b/drivers/net/chelsio/vsc7326.c
@@ -226,22 +226,21 @@ static void run_table(adapter_t *adapter, struct init_table *ib, int len)
if (ib[i].addr == INITBLOCK_SLEEP) {
udelay( ib[i].data );
CH_ERR("sleep %d us\n",ib[i].data);
- } else {
+ } else
vsc_write( adapter, ib[i].addr, ib[i].data );
- }
}
}
static int bist_rd(adapter_t *adapter, int moduleid, int address)
{
- int data=0;
- u32 result=0;
-
- if( (address != 0x0) &&
- (address != 0x1) &&
- (address != 0x2) &&
- (address != 0xd) &&
- (address != 0xe))
+ int data = 0;
+ u32 result = 0;
+
+ if ((address != 0x0) &&
+ (address != 0x1) &&
+ (address != 0x2) &&
+ (address != 0xd) &&
+ (address != 0xe))
CH_ERR("No bist address: 0x%x\n", address);
data = ((0x00 << 24) | ((address & 0xff) << 16) | (0x00 << 8) |
@@ -251,27 +250,27 @@ static int bist_rd(adapter_t *adapter, int moduleid, int address)
udelay(10);
vsc_read(adapter, REG_RAM_BIST_RESULT, &result);
- if((result & (1<<9)) != 0x0)
+ if ((result & (1 << 9)) != 0x0)
CH_ERR("Still in bist read: 0x%x\n", result);
- else if((result & (1<<8)) != 0x0)
+ else if ((result & (1 << 8)) != 0x0)
CH_ERR("bist read error: 0x%x\n", result);
- return(result & 0xff);
+ return (result & 0xff);
}
static int bist_wr(adapter_t *adapter, int moduleid, int address, int value)
{
- int data=0;
- u32 result=0;
-
- if( (address != 0x0) &&
- (address != 0x1) &&
- (address != 0x2) &&
- (address != 0xd) &&
- (address != 0xe))
+ int data = 0;
+ u32 result = 0;
+
+ if ((address != 0x0) &&
+ (address != 0x1) &&
+ (address != 0x2) &&
+ (address != 0xd) &&
+ (address != 0xe))
CH_ERR("No bist address: 0x%x\n", address);
- if( value>255 )
+ if (value > 255)
CH_ERR("Suspicious write out of range value: 0x%x\n", value);
data = ((0x01 << 24) | ((address & 0xff) << 16) | (value << 8) |
@@ -281,12 +280,12 @@ static int bist_wr(adapter_t *adapter, int moduleid, int address, int value)
udelay(5);
vsc_read(adapter, REG_RAM_BIST_CMD, &result);
- if((result & (1<<27)) != 0x0)
+ if ((result & (1 << 27)) != 0x0)
CH_ERR("Still in bist write: 0x%x\n", result);
- else if((result & (1<<26)) != 0x0)
+ else if ((result & (1 << 26)) != 0x0)
CH_ERR("bist write error: 0x%x\n", result);
- return(0);
+ return 0;
}
static int run_bist(adapter_t *adapter, int moduleid)
@@ -295,7 +294,7 @@ static int run_bist(adapter_t *adapter, int moduleid)
(void) bist_wr(adapter,moduleid, 0x00, 0x02);
(void) bist_wr(adapter,moduleid, 0x01, 0x01);
- return(0);
+ return 0;
}
static int check_bist(adapter_t *adapter, int moduleid)
@@ -309,27 +308,26 @@ static int check_bist(adapter_t *adapter, int moduleid)
if ((result & 3) != 0x3)
CH_ERR("Result: 0x%x BIST error in ram %d, column: 0x%04x\n",
result, moduleid, column);
- return(0);
+ return 0;
}
static int enable_mem(adapter_t *adapter, int moduleid)
{
/*enable mem*/
(void) bist_wr(adapter,moduleid, 0x00, 0x00);
- return(0);
+ return 0;
}
static int run_bist_all(adapter_t *adapter)
{
- int port=0;
- u32 val=0;
+ int port = 0;
+ u32 val = 0;
vsc_write(adapter, REG_MEM_BIST, 0x5);
vsc_read(adapter, REG_MEM_BIST, &val);
- for(port=0; port<12; port++){
+ for (port = 0; port < 12; port++)
vsc_write(adapter, REG_DEV_SETUP(port), 0x0);
- }
udelay(300);
vsc_write(adapter, REG_SPI4_MISC, 0x00040409);
@@ -352,13 +350,13 @@ static int run_bist_all(adapter_t *adapter)
udelay(300);
vsc_write(adapter, REG_SPI4_MISC, 0x60040400);
udelay(300);
- for(port=0; port<12; port++){
+ for (port = 0; port < 12; port++)
vsc_write(adapter, REG_DEV_SETUP(port), 0x1);
- }
+
udelay(300);
vsc_write(adapter, REG_MEM_BIST, 0x0);
mdelay(10);
- return(0);
+ return 0;
}
static int mac_intr_handler(struct cmac *mac)
@@ -591,40 +589,46 @@ static void rmon_update(struct cmac *mac, unsigned int addr, u64 *stat)
static void port_stats_update(struct cmac *mac)
{
- int port = mac->instance->index;
+ struct {
+ unsigned int reg;
+ unsigned int offset;
+ } hw_stats[] = {
+
+#define HW_STAT(reg, stat_name) \
+ { reg, (&((struct cmac_statistics *)NULL)->stat_name) - (u64 *)NULL }
+
+ /* Rx stats */
+ HW_STAT(RxUnicast, RxUnicastFramesOK),
+ HW_STAT(RxMulticast, RxMulticastFramesOK),
+ HW_STAT(RxBroadcast, RxBroadcastFramesOK),
+ HW_STAT(Crc, RxFCSErrors),
+ HW_STAT(RxAlignment, RxAlignErrors),
+ HW_STAT(RxOversize, RxFrameTooLongErrors),
+ HW_STAT(RxPause, RxPauseFrames),
+ HW_STAT(RxJabbers, RxJabberErrors),
+ HW_STAT(RxFragments, RxRuntErrors),
+ HW_STAT(RxUndersize, RxRuntErrors),
+ HW_STAT(RxSymbolCarrier, RxSymbolErrors),
+ HW_STAT(RxSize1519ToMax, RxJumboFramesOK),
+
+ /* Tx stats (skip collision stats as we are full-duplex only) */
+ HW_STAT(TxUnicast, TxUnicastFramesOK),
+ HW_STAT(TxMulticast, TxMulticastFramesOK),
+ HW_STAT(TxBroadcast, TxBroadcastFramesOK),
+ HW_STAT(TxPause, TxPauseFrames),
+ HW_STAT(TxUnderrun, TxUnderrun),
+ HW_STAT(TxSize1519ToMax, TxJumboFramesOK),
+ }, *p = hw_stats;
+ unsigned int port = mac->instance->index;
+ u64 *stats = (u64 *)&mac->stats;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(hw_stats); i++)
+ rmon_update(mac, CRA(0x4, port, p->reg), stats + p->offset);
- /* Rx stats */
+ rmon_update(mac, REG_TX_OK_BYTES(port), &mac->stats.TxOctetsOK);
rmon_update(mac, REG_RX_OK_BYTES(port), &mac->stats.RxOctetsOK);
rmon_update(mac, REG_RX_BAD_BYTES(port), &mac->stats.RxOctetsBad);
- rmon_update(mac, REG_RX_UNICAST(port), &mac->stats.RxUnicastFramesOK);
- rmon_update(mac, REG_RX_MULTICAST(port),
- &mac->stats.RxMulticastFramesOK);
- rmon_update(mac, REG_RX_BROADCAST(port),
- &mac->stats.RxBroadcastFramesOK);
- rmon_update(mac, REG_CRC(port), &mac->stats.RxFCSErrors);
- rmon_update(mac, REG_RX_ALIGNMENT(port), &mac->stats.RxAlignErrors);
- rmon_update(mac, REG_RX_OVERSIZE(port),
- &mac->stats.RxFrameTooLongErrors);
- rmon_update(mac, REG_RX_PAUSE(port), &mac->stats.RxPauseFrames);
- rmon_update(mac, REG_RX_JABBERS(port), &mac->stats.RxJabberErrors);
- rmon_update(mac, REG_RX_FRAGMENTS(port), &mac->stats.RxRuntErrors);
- rmon_update(mac, REG_RX_UNDERSIZE(port), &mac->stats.RxRuntErrors);
- rmon_update(mac, REG_RX_SYMBOL_CARRIER(port),
- &mac->stats.RxSymbolErrors);
- rmon_update(mac, REG_RX_SIZE_1519_TO_MAX(port),
- &mac->stats.RxJumboFramesOK);
-
- /* Tx stats (skip collision stats as we are full-duplex only) */
- rmon_update(mac, REG_TX_OK_BYTES(port), &mac->stats.TxOctetsOK);
- rmon_update(mac, REG_TX_UNICAST(port), &mac->stats.TxUnicastFramesOK);
- rmon_update(mac, REG_TX_MULTICAST(port),
- &mac->stats.TxMulticastFramesOK);
- rmon_update(mac, REG_TX_BROADCAST(port),
- &mac->stats.TxBroadcastFramesOK);
- rmon_update(mac, REG_TX_PAUSE(port), &mac->stats.TxPauseFrames);
- rmon_update(mac, REG_TX_UNDERRUN(port), &mac->stats.TxUnderrun);
- rmon_update(mac, REG_TX_SIZE_1519_TO_MAX(port),
- &mac->stats.TxJumboFramesOK);
}
/*
@@ -686,7 +690,8 @@ static struct cmac *vsc7326_mac_create(adapter_t *adapter, int index)
int i;
mac = kzalloc(sizeof(*mac) + sizeof(cmac_instance), GFP_KERNEL);
- if (!mac) return NULL;
+ if (!mac)
+ return NULL;
mac->ops = &vsc7326_ops;
mac->instance = (cmac_instance *)(mac + 1);
diff --git a/drivers/net/chelsio/vsc7326_reg.h b/drivers/net/chelsio/vsc7326_reg.h
index 491bcf75c4f..479edbcabe6 100644
--- a/drivers/net/chelsio/vsc7326_reg.h
+++ b/drivers/net/chelsio/vsc7326_reg.h
@@ -192,73 +192,84 @@
#define REG_HDX(pn) CRA(0x1,pn,0x19) /* Half-duplex config */
/* Statistics */
+/* CRA(0x4,pn,reg) */
+/* reg below */
/* pn = port number, 0-a, a = 10GbE */
-#define REG_RX_IN_BYTES(pn) CRA(0x4,pn,0x00) /* # Rx in octets */
-#define REG_RX_SYMBOL_CARRIER(pn) CRA(0x4,pn,0x01) /* Frames w/ symbol errors */
-#define REG_RX_PAUSE(pn) CRA(0x4,pn,0x02) /* # pause frames received */
-#define REG_RX_UNSUP_OPCODE(pn) CRA(0x4,pn,0x03) /* # control frames with unsupported opcode */
-#define REG_RX_OK_BYTES(pn) CRA(0x4,pn,0x04) /* # octets in good frames */
-#define REG_RX_BAD_BYTES(pn) CRA(0x4,pn,0x05) /* # octets in bad frames */
-#define REG_RX_UNICAST(pn) CRA(0x4,pn,0x06) /* # good unicast frames */
-#define REG_RX_MULTICAST(pn) CRA(0x4,pn,0x07) /* # good multicast frames */
-#define REG_RX_BROADCAST(pn) CRA(0x4,pn,0x08) /* # good broadcast frames */
-#define REG_CRC(pn) CRA(0x4,pn,0x09) /* # frames w/ bad CRC only */
-#define REG_RX_ALIGNMENT(pn) CRA(0x4,pn,0x0a) /* # frames w/ alignment err */
-#define REG_RX_UNDERSIZE(pn) CRA(0x4,pn,0x0b) /* # frames undersize */
-#define REG_RX_FRAGMENTS(pn) CRA(0x4,pn,0x0c) /* # frames undersize w/ crc err */
-#define REG_RX_IN_RANGE_LENGTH_ERROR(pn) CRA(0x4,pn,0x0d) /* # frames with length error */
-#define REG_RX_OUT_OF_RANGE_ERROR(pn) CRA(0x4,pn,0x0e) /* # frames with illegal length field */
-#define REG_RX_OVERSIZE(pn) CRA(0x4,pn,0x0f) /* # frames oversize */
-#define REG_RX_JABBERS(pn) CRA(0x4,pn,0x10) /* # frames oversize w/ crc err */
-#define REG_RX_SIZE_64(pn) CRA(0x4,pn,0x11) /* # frames 64 octets long */
-#define REG_RX_SIZE_65_TO_127(pn) CRA(0x4,pn,0x12) /* # frames 65-127 octets */
-#define REG_RX_SIZE_128_TO_255(pn) CRA(0x4,pn,0x13) /* # frames 128-255 */
-#define REG_RX_SIZE_256_TO_511(pn) CRA(0x4,pn,0x14) /* # frames 256-511 */
-#define REG_RX_SIZE_512_TO_1023(pn) CRA(0x4,pn,0x15) /* # frames 512-1023 */
-#define REG_RX_SIZE_1024_TO_1518(pn) CRA(0x4,pn,0x16) /* # frames 1024-1518 */
-#define REG_RX_SIZE_1519_TO_MAX(pn) CRA(0x4,pn,0x17) /* # frames 1519-max */
-#define REG_TX_OUT_BYTES(pn) CRA(0x4,pn,0x18) /* # octets tx */
-#define REG_TX_PAUSE(pn) CRA(0x4,pn,0x19) /* # pause frames sent */
-#define REG_TX_OK_BYTES(pn) CRA(0x4,pn,0x1a) /* # octets tx OK */
-#define REG_TX_UNICAST(pn) CRA(0x4,pn,0x1b) /* # frames unicast */
-#define REG_TX_MULTICAST(pn) CRA(0x4,pn,0x1c) /* # frames multicast */
-#define REG_TX_BROADCAST(pn) CRA(0x4,pn,0x1d) /* # frames broadcast */
-#define REG_TX_MULTIPLE_COLL(pn) CRA(0x4,pn,0x1e) /* # frames tx after multiple collisions */
-#define REG_TX_LATE_COLL(pn) CRA(0x4,pn,0x1f) /* # late collisions detected */
-#define REG_TX_XCOLL(pn) CRA(0x4,pn,0x20) /* # frames lost, excessive collisions */
-#define REG_TX_DEFER(pn) CRA(0x4,pn,0x21) /* # frames deferred on first tx attempt */
-#define REG_TX_XDEFER(pn) CRA(0x4,pn,0x22) /* # frames excessively deferred */
-#define REG_TX_CSENSE(pn) CRA(0x4,pn,0x23) /* carrier sense errors at frame end */
-#define REG_TX_SIZE_64(pn) CRA(0x4,pn,0x24) /* # frames 64 octets long */
-#define REG_TX_SIZE_65_TO_127(pn) CRA(0x4,pn,0x25) /* # frames 65-127 octets */
-#define REG_TX_SIZE_128_TO_255(pn) CRA(0x4,pn,0x26) /* # frames 128-255 */
-#define REG_TX_SIZE_256_TO_511(pn) CRA(0x4,pn,0x27) /* # frames 256-511 */
-#define REG_TX_SIZE_512_TO_1023(pn) CRA(0x4,pn,0x28) /* # frames 512-1023 */
-#define REG_TX_SIZE_1024_TO_1518(pn) CRA(0x4,pn,0x29) /* # frames 1024-1518 */
-#define REG_TX_SIZE_1519_TO_MAX(pn) CRA(0x4,pn,0x2a) /* # frames 1519-max */
-#define REG_TX_SINGLE_COLL(pn) CRA(0x4,pn,0x2b) /* # frames tx after single collision */
-#define REG_TX_BACKOFF2(pn) CRA(0x4,pn,0x2c) /* # frames tx ok after 2 backoffs/collisions */
-#define REG_TX_BACKOFF3(pn) CRA(0x4,pn,0x2d) /* after 3 backoffs/collisions */
-#define REG_TX_BACKOFF4(pn) CRA(0x4,pn,0x2e) /* after 4 */
-#define REG_TX_BACKOFF5(pn) CRA(0x4,pn,0x2f) /* after 5 */
-#define REG_TX_BACKOFF6(pn) CRA(0x4,pn,0x30) /* after 6 */
-#define REG_TX_BACKOFF7(pn) CRA(0x4,pn,0x31) /* after 7 */
-#define REG_TX_BACKOFF8(pn) CRA(0x4,pn,0x32) /* after 8 */
-#define REG_TX_BACKOFF9(pn) CRA(0x4,pn,0x33) /* after 9 */
-#define REG_TX_BACKOFF10(pn) CRA(0x4,pn,0x34) /* after 10 */
-#define REG_TX_BACKOFF11(pn) CRA(0x4,pn,0x35) /* after 11 */
-#define REG_TX_BACKOFF12(pn) CRA(0x4,pn,0x36) /* after 12 */
-#define REG_TX_BACKOFF13(pn) CRA(0x4,pn,0x37) /* after 13 */
-#define REG_TX_BACKOFF14(pn) CRA(0x4,pn,0x38) /* after 14 */
-#define REG_TX_BACKOFF15(pn) CRA(0x4,pn,0x39) /* after 15 */
-#define REG_TX_UNDERRUN(pn) CRA(0x4,pn,0x3a) /* # frames dropped from underrun */
-#define REG_RX_XGMII_PROT_ERR CRA(0x4,0xa,0x3b) /* # protocol errors detected on XGMII interface */
-#define REG_RX_IPG_SHRINK(pn) CRA(0x4,pn,0x3c) /* # of IPG shrinks detected */
+enum {
+ RxInBytes = 0x00, // # Rx in octets
+ RxSymbolCarrier = 0x01, // Frames w/ symbol errors
+ RxPause = 0x02, // # pause frames received
+ RxUnsupOpcode = 0x03, // # control frames with unsupported opcode
+ RxOkBytes = 0x04, // # octets in good frames
+ RxBadBytes = 0x05, // # octets in bad frames
+ RxUnicast = 0x06, // # good unicast frames
+ RxMulticast = 0x07, // # good multicast frames
+ RxBroadcast = 0x08, // # good broadcast frames
+ Crc = 0x09, // # frames w/ bad CRC only
+ RxAlignment = 0x0a, // # frames w/ alignment err
+ RxUndersize = 0x0b, // # frames undersize
+ RxFragments = 0x0c, // # frames undersize w/ crc err
+ RxInRangeLengthError = 0x0d, // # frames with length error
+ RxOutOfRangeError = 0x0e, // # frames with illegal length field
+ RxOversize = 0x0f, // # frames oversize
+ RxJabbers = 0x10, // # frames oversize w/ crc err
+ RxSize64 = 0x11, // # frames 64 octets long
+ RxSize65To127 = 0x12, // # frames 65-127 octets
+ RxSize128To255 = 0x13, // # frames 128-255
+ RxSize256To511 = 0x14, // # frames 256-511
+ RxSize512To1023 = 0x15, // # frames 512-1023
+ RxSize1024To1518 = 0x16, // # frames 1024-1518
+ RxSize1519ToMax = 0x17, // # frames 1519-max
-#define REG_STAT_STICKY1G(pn) CRA(0x4,pn,0x3e) /* tri-speed sticky bits */
-#define REG_STAT_STICKY10G CRA(0x4,0xa,0x3e) /* 10GbE sticky bits */
-#define REG_STAT_INIT(pn) CRA(0x4,pn,0x3f) /* Clear all statistics */
+ TxOutBytes = 0x18, // # octets tx
+ TxPause = 0x19, // # pause frames sent
+ TxOkBytes = 0x1a, // # octets tx OK
+ TxUnicast = 0x1b, // # frames unicast
+ TxMulticast = 0x1c, // # frames multicast
+ TxBroadcast = 0x1d, // # frames broadcast
+ TxMultipleColl = 0x1e, // # frames tx after multiple collisions
+ TxLateColl = 0x1f, // # late collisions detected
+ TxXcoll = 0x20, // # frames lost, excessive collisions
+ TxDefer = 0x21, // # frames deferred on first tx attempt
+ TxXdefer = 0x22, // # frames excessively deferred
+ TxCsense = 0x23, // carrier sense errors at frame end
+ TxSize64 = 0x24, // # frames 64 octets long
+ TxSize65To127 = 0x25, // # frames 65-127 octets
+ TxSize128To255 = 0x26, // # frames 128-255
+ TxSize256To511 = 0x27, // # frames 256-511
+ TxSize512To1023 = 0x28, // # frames 512-1023
+ TxSize1024To1518 = 0x29, // # frames 1024-1518
+ TxSize1519ToMax = 0x2a, // # frames 1519-max
+ TxSingleColl = 0x2b, // # frames tx after single collision
+ TxBackoff2 = 0x2c, // # frames tx ok after 2 backoffs/collisions
+ TxBackoff3 = 0x2d, // after 3 backoffs/collisions
+ TxBackoff4 = 0x2e, // after 4
+ TxBackoff5 = 0x2f, // after 5
+ TxBackoff6 = 0x30, // after 6
+ TxBackoff7 = 0x31, // after 7
+ TxBackoff8 = 0x32, // after 8
+ TxBackoff9 = 0x33, // after 9
+ TxBackoff10 = 0x34, // after 10
+ TxBackoff11 = 0x35, // after 11
+ TxBackoff12 = 0x36, // after 12
+ TxBackoff13 = 0x37, // after 13
+ TxBackoff14 = 0x38, // after 14
+ TxBackoff15 = 0x39, // after 15
+ TxUnderrun = 0x3a, // # frames dropped from underrun
+ // Hole. See REG_RX_XGMII_PROT_ERR below.
+ RxIpgShrink = 0x3c, // # of IPG shrinks detected
+ // Duplicate. See REG_STAT_STICKY10G below.
+ StatSticky1G = 0x3e, // tri-speed sticky bits
+ StatInit = 0x3f // Clear all statistics
+};
+
+#define REG_RX_XGMII_PROT_ERR CRA(0x4,0xa,0x3b) /* # protocol errors detected on XGMII interface */
+#define REG_STAT_STICKY10G CRA(0x4,0xa,StatSticky1G) /* 10GbE sticky bits */
+
+#define REG_RX_OK_BYTES(pn) CRA(0x4,pn,RxOkBytes)
+#define REG_RX_BAD_BYTES(pn) CRA(0x4,pn,RxBadBytes)
+#define REG_TX_OK_BYTES(pn) CRA(0x4,pn,TxOkBytes)
/* MII-Management Block registers */
/* These are for MII-M interface 0, which is the bidirectional LVTTL one. If
diff --git a/drivers/net/chelsio/vsc8244.c b/drivers/net/chelsio/vsc8244.c
index c493e783d45..251d4859c91 100644
--- a/drivers/net/chelsio/vsc8244.c
+++ b/drivers/net/chelsio/vsc8244.c
@@ -54,7 +54,7 @@ enum {
};
#define CFG_CHG_INTR_MASK (VSC_INTR_LINK_CHG | VSC_INTR_NEG_ERR | \
- VSC_INTR_NEG_DONE)
+ VSC_INTR_NEG_DONE)
#define INTR_MASK (CFG_CHG_INTR_MASK | VSC_INTR_TX_FIFO | VSC_INTR_RX_FIFO | \
VSC_INTR_ENABLE)
@@ -94,19 +94,18 @@ static int vsc8244_intr_enable(struct cphy *cphy)
{
simple_mdio_write(cphy, VSC8244_INTR_ENABLE, INTR_MASK);
- /* Enable interrupts through Elmer */
+ /* Enable interrupts through Elmer */
if (t1_is_asic(cphy->adapter)) {
u32 elmer;
t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer);
elmer |= ELMER0_GP_BIT1;
- if (is_T2(cphy->adapter)) {
+ if (is_T2(cphy->adapter))
elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4;
- }
t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer);
}
- return 0;
+ return 0;
}
static int vsc8244_intr_disable(struct cphy *cphy)
@@ -118,19 +117,18 @@ static int vsc8244_intr_disable(struct cphy *cphy)
t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer);
elmer &= ~ELMER0_GP_BIT1;
- if (is_T2(cphy->adapter)) {
+ if (is_T2(cphy->adapter))
elmer &= ~(ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4);
- }
t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer);
}
- return 0;
+ return 0;
}
static int vsc8244_intr_clear(struct cphy *cphy)
{
u32 val;
- u32 elmer;
+ u32 elmer;
/* Clear PHY interrupts by reading the register. */
simple_mdio_read(cphy, VSC8244_INTR_ENABLE, &val);
@@ -138,13 +136,12 @@ static int vsc8244_intr_clear(struct cphy *cphy)
if (t1_is_asic(cphy->adapter)) {
t1_tpi_read(cphy->adapter, A_ELMER0_INT_CAUSE, &elmer);
elmer |= ELMER0_GP_BIT1;
- if (is_T2(cphy->adapter)) {
+ if (is_T2(cphy->adapter))
elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4;
- }
t1_tpi_write(cphy->adapter, A_ELMER0_INT_CAUSE, elmer);
}
- return 0;
+ return 0;
}
/*
@@ -179,13 +176,13 @@ static int vsc8244_set_speed_duplex(struct cphy *phy, int speed, int duplex)
int t1_mdio_set_bits(struct cphy *phy, int mmd, int reg, unsigned int bits)
{
- int ret;
- unsigned int val;
+ int ret;
+ unsigned int val;
- ret = mdio_read(phy, mmd, reg, &val);
- if (!ret)
- ret = mdio_write(phy, mmd, reg, val | bits);
- return ret;
+ ret = mdio_read(phy, mmd, reg, &val);
+ if (!ret)
+ ret = mdio_write(phy, mmd, reg, val | bits);
+ return ret;
}
static int vsc8244_autoneg_enable(struct cphy *cphy)
@@ -235,7 +232,7 @@ static int vsc8244_advertise(struct cphy *phy, unsigned int advertise_map)
}
static int vsc8244_get_link_status(struct cphy *cphy, int *link_ok,
- int *speed, int *duplex, int *fc)
+ int *speed, int *duplex, int *fc)
{
unsigned int bmcr, status, lpa, adv;
int err, sp = -1, dplx = -1, pause = 0;
@@ -343,11 +340,13 @@ static struct cphy_ops vsc8244_ops = {
.get_link_status = vsc8244_get_link_status
};
-static struct cphy* vsc8244_phy_create(adapter_t *adapter, int phy_addr, struct mdio_ops *mdio_ops)
+static struct cphy* vsc8244_phy_create(adapter_t *adapter, int phy_addr,
+ struct mdio_ops *mdio_ops)
{
struct cphy *cphy = kzalloc(sizeof(*cphy), GFP_KERNEL);
- if (!cphy) return NULL;
+ if (!cphy)
+ return NULL;
cphy_init(cphy, adapter, phy_addr, &vsc8244_ops, mdio_ops);
diff --git a/drivers/net/cris/eth_v10.c b/drivers/net/cris/eth_v10.c
index a03d781f6d0..8eb57127600 100644
--- a/drivers/net/cris/eth_v10.c
+++ b/drivers/net/cris/eth_v10.c
@@ -222,7 +222,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/types.h>
#include <linux/fcntl.h>
diff --git a/drivers/net/cxgb3/Makefile b/drivers/net/cxgb3/Makefile
new file mode 100644
index 00000000000..34346798532
--- /dev/null
+++ b/drivers/net/cxgb3/Makefile
@@ -0,0 +1,8 @@
+#
+# Chelsio T3 driver
+#
+
+obj-$(CONFIG_CHELSIO_T3) += cxgb3.o
+
+cxgb3-objs := cxgb3_main.o ael1002.o vsc8211.o t3_hw.o mc5.o \
+ xgmac.o sge.o l2t.o cxgb3_offload.o
diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h
new file mode 100644
index 00000000000..5c97a64451c
--- /dev/null
+++ b/drivers/net/cxgb3/adapter.h
@@ -0,0 +1,279 @@
+/*
+ * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* This file should not be included directly. Include common.h instead. */
+
+#ifndef __T3_ADAPTER_H__
+#define __T3_ADAPTER_H__
+
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/timer.h>
+#include <linux/cache.h>
+#include <linux/mutex.h>
+#include "t3cdev.h"
+#include <asm/semaphore.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+
+typedef irqreturn_t(*intr_handler_t) (int, void *);
+
+struct vlan_group;
+
+struct port_info {
+ struct vlan_group *vlan_grp;
+ const struct port_type_info *port_type;
+ u8 port_id;
+ u8 rx_csum_offload;
+ u8 nqsets;
+ u8 first_qset;
+ struct cphy phy;
+ struct cmac mac;
+ struct link_config link_config;
+ struct net_device_stats netstats;
+ int activity;
+};
+
+enum { /* adapter flags */
+ FULL_INIT_DONE = (1 << 0),
+ USING_MSI = (1 << 1),
+ USING_MSIX = (1 << 2),
+ QUEUES_BOUND = (1 << 3),
+};
+
+struct rx_desc;
+struct rx_sw_desc;
+
+struct sge_fl { /* SGE per free-buffer list state */
+ unsigned int buf_size; /* size of each Rx buffer */
+ unsigned int credits; /* # of available Rx buffers */
+ unsigned int size; /* capacity of free list */
+ unsigned int cidx; /* consumer index */
+ unsigned int pidx; /* producer index */
+ unsigned int gen; /* free list generation */
+ struct rx_desc *desc; /* address of HW Rx descriptor ring */
+ struct rx_sw_desc *sdesc; /* address of SW Rx descriptor ring */
+ dma_addr_t phys_addr; /* physical address of HW ring start */
+ unsigned int cntxt_id; /* SGE context id for the free list */
+ unsigned long empty; /* # of times queue ran out of buffers */
+};
+
+/*
+ * Bundle size for grouping offload RX packets for delivery to the stack.
+ * Don't make this too big as we do prefetch on each packet in a bundle.
+ */
+# define RX_BUNDLE_SIZE 8
+
+struct rsp_desc;
+
+struct sge_rspq { /* state for an SGE response queue */
+ unsigned int credits; /* # of pending response credits */
+ unsigned int size; /* capacity of response queue */
+ unsigned int cidx; /* consumer index */
+ unsigned int gen; /* current generation bit */
+ unsigned int polling; /* is the queue serviced through NAPI? */
+ unsigned int holdoff_tmr; /* interrupt holdoff timer in 100ns */
+ unsigned int next_holdoff; /* holdoff time for next interrupt */
+ struct rsp_desc *desc; /* address of HW response ring */
+ dma_addr_t phys_addr; /* physical address of the ring */
+ unsigned int cntxt_id; /* SGE context id for the response q */
+ spinlock_t lock; /* guards response processing */
+ struct sk_buff *rx_head; /* offload packet receive queue head */
+ struct sk_buff *rx_tail; /* offload packet receive queue tail */
+
+ unsigned long offload_pkts;
+ unsigned long offload_bundles;
+ unsigned long eth_pkts; /* # of ethernet packets */
+ unsigned long pure_rsps; /* # of pure (non-data) responses */
+ unsigned long imm_data; /* responses with immediate data */
+ unsigned long rx_drops; /* # of packets dropped due to no mem */
+ unsigned long async_notif; /* # of asynchronous notification events */
+ unsigned long empty; /* # of times queue ran out of credits */
+ unsigned long nomem; /* # of responses deferred due to no mem */
+ unsigned long unhandled_irqs; /* # of spurious intrs */
+};
+
+struct tx_desc;
+struct tx_sw_desc;
+
+struct sge_txq { /* state for an SGE Tx queue */
+ unsigned long flags; /* HW DMA fetch status */
+ unsigned int in_use; /* # of in-use Tx descriptors */
+ unsigned int size; /* # of descriptors */
+ unsigned int processed; /* total # of descs HW has processed */
+ unsigned int cleaned; /* total # of descs SW has reclaimed */
+ unsigned int stop_thres; /* SW TX queue suspend threshold */
+ unsigned int cidx; /* consumer index */
+ unsigned int pidx; /* producer index */
+ unsigned int gen; /* current value of generation bit */
+ unsigned int unacked; /* Tx descriptors used since last COMPL */
+ struct tx_desc *desc; /* address of HW Tx descriptor ring */
+ struct tx_sw_desc *sdesc; /* address of SW Tx descriptor ring */
+ spinlock_t lock; /* guards enqueueing of new packets */
+ unsigned int token; /* WR token */
+ dma_addr_t phys_addr; /* physical address of the ring */
+ struct sk_buff_head sendq; /* List of backpressured offload packets */
+ struct tasklet_struct qresume_tsk; /* restarts the queue */
+ unsigned int cntxt_id; /* SGE context id for the Tx q */
+ unsigned long stops; /* # of times q has been stopped */
+ unsigned long restarts; /* # of queue restarts */
+};
+
+enum { /* per port SGE statistics */
+ SGE_PSTAT_TSO, /* # of TSO requests */
+ SGE_PSTAT_RX_CSUM_GOOD, /* # of successful RX csum offloads */
+ SGE_PSTAT_TX_CSUM, /* # of TX checksum offloads */
+ SGE_PSTAT_VLANEX, /* # of VLAN tag extractions */
+ SGE_PSTAT_VLANINS, /* # of VLAN tag insertions */
+
+ SGE_PSTAT_MAX /* must be last */
+};
+
+struct sge_qset { /* an SGE queue set */
+ struct sge_rspq rspq;
+ struct sge_fl fl[SGE_RXQ_PER_SET];
+ struct sge_txq txq[SGE_TXQ_PER_SET];
+ struct net_device *netdev; /* associated net device */
+ unsigned long txq_stopped; /* which Tx queues are stopped */
+ struct timer_list tx_reclaim_timer; /* reclaims TX buffers */
+ unsigned long port_stats[SGE_PSTAT_MAX];
+} ____cacheline_aligned;
+
+struct sge {
+ struct sge_qset qs[SGE_QSETS];
+ spinlock_t reg_lock; /* guards non-atomic SGE registers (eg context) */
+};
+
+struct adapter {
+ struct t3cdev tdev;
+ struct list_head adapter_list;
+ void __iomem *regs;
+ struct pci_dev *pdev;
+ unsigned long registered_device_map;
+ unsigned long open_device_map;
+ unsigned long flags;
+
+ const char *name;
+ int msg_enable;
+ unsigned int mmio_len;
+
+ struct adapter_params params;
+ unsigned int slow_intr_mask;
+ unsigned long irq_stats[IRQ_NUM_STATS];
+
+ struct {
+ unsigned short vec;
+ char desc[22];
+ } msix_info[SGE_QSETS + 1];
+
+ /* T3 modules */
+ struct sge sge;
+ struct mc7 pmrx;
+ struct mc7 pmtx;
+ struct mc7 cm;
+ struct mc5 mc5;
+
+ struct net_device *port[MAX_NPORTS];
+ unsigned int check_task_cnt;
+ struct delayed_work adap_check_task;
+ struct work_struct ext_intr_handler_task;
+
+ /*
+ * Dummy netdevices are needed when using multiple receive queues with
+ * NAPI as each netdevice can service only one queue.
+ */
+ struct net_device *dummy_netdev[SGE_QSETS - 1];
+
+ struct dentry *debugfs_root;
+
+ struct mutex mdio_lock;
+ spinlock_t stats_lock;
+ spinlock_t work_lock;
+};
+
+static inline u32 t3_read_reg(struct adapter *adapter, u32 reg_addr)
+{
+ u32 val = readl(adapter->regs + reg_addr);
+
+ CH_DBG(adapter, MMIO, "read register 0x%x value 0x%x\n", reg_addr, val);
+ return val;
+}
+
+static inline void t3_write_reg(struct adapter *adapter, u32 reg_addr, u32 val)
+{
+ CH_DBG(adapter, MMIO, "setting register 0x%x to 0x%x\n", reg_addr, val);
+ writel(val, adapter->regs + reg_addr);
+}
+
+static inline struct port_info *adap2pinfo(struct adapter *adap, int idx)
+{
+ return netdev_priv(adap->port[idx]);
+}
+
+/*
+ * We use the spare atalk_ptr to map a net device to its SGE queue set.
+ * This is a macro so it can be used as l-value.
+ */
+#define dev2qset(netdev) ((netdev)->atalk_ptr)
+
+#define OFFLOAD_DEVMAP_BIT 15
+
+#define tdev2adap(d) container_of(d, struct adapter, tdev)
+
+static inline int offload_running(struct adapter *adapter)
+{
+ return test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map);
+}
+
+int t3_offload_tx(struct t3cdev *tdev, struct sk_buff *skb);
+
+void t3_os_ext_intr_handler(struct adapter *adapter);
+void t3_os_link_changed(struct adapter *adapter, int port_id, int link_status,
+ int speed, int duplex, int fc);
+
+void t3_sge_start(struct adapter *adap);
+void t3_sge_stop(struct adapter *adap);
+void t3_free_sge_resources(struct adapter *adap);
+void t3_sge_err_intr_handler(struct adapter *adapter);
+intr_handler_t t3_intr_handler(struct adapter *adap, int polling);
+int t3_eth_xmit(struct sk_buff *skb, struct net_device *dev);
+int t3_mgmt_tx(struct adapter *adap, struct sk_buff *skb);
+void t3_update_qset_coalesce(struct sge_qset *qs, const struct qset_params *p);
+int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports,
+ int irq_vec_idx, const struct qset_params *p,
+ int ntxq, struct net_device *netdev);
+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);
+
+#endif /* __T3_ADAPTER_H__ */
diff --git a/drivers/net/cxgb3/ael1002.c b/drivers/net/cxgb3/ael1002.c
new file mode 100644
index 00000000000..73a41e6a5bf
--- /dev/null
+++ b/drivers/net/cxgb3/ael1002.c
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 2005-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include "common.h"
+#include "regs.h"
+
+enum {
+ AEL100X_TX_DISABLE = 9,
+ AEL100X_TX_CONFIG1 = 0xc002,
+ AEL1002_PWR_DOWN_HI = 0xc011,
+ AEL1002_PWR_DOWN_LO = 0xc012,
+ AEL1002_XFI_EQL = 0xc015,
+ AEL1002_LB_EN = 0xc017,
+
+ LASI_CTRL = 0x9002,
+ LASI_STAT = 0x9005
+};
+
+static void ael100x_txon(struct cphy *phy)
+{
+ int tx_on_gpio = phy->addr == 0 ? F_GPIO7_OUT_VAL : F_GPIO2_OUT_VAL;
+
+ msleep(100);
+ t3_set_reg_field(phy->adapter, A_T3DBG_GPIO_EN, 0, tx_on_gpio);
+ msleep(30);
+}
+
+static int ael1002_power_down(struct cphy *phy, int enable)
+{
+ int err;
+
+ err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL100X_TX_DISABLE, !!enable);
+ if (!err)
+ err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR,
+ BMCR_PDOWN, enable ? BMCR_PDOWN : 0);
+ return err;
+}
+
+static int ael1002_reset(struct cphy *phy, int wait)
+{
+ int err;
+
+ if ((err = ael1002_power_down(phy, 0)) ||
+ (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL100X_TX_CONFIG1, 1)) ||
+ (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_PWR_DOWN_HI, 0)) ||
+ (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_PWR_DOWN_LO, 0)) ||
+ (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_XFI_EQL, 0x18)) ||
+ (err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, AEL1002_LB_EN,
+ 0, 1 << 5)))
+ return err;
+ return 0;
+}
+
+static int ael1002_intr_noop(struct cphy *phy)
+{
+ return 0;
+}
+
+static int ael100x_get_link_status(struct cphy *phy, int *link_ok,
+ int *speed, int *duplex, int *fc)
+{
+ if (link_ok) {
+ unsigned int status;
+ int err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR, &status);
+
+ /*
+ * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it
+ * once more to get the current link state.
+ */
+ if (!err && !(status & BMSR_LSTATUS))
+ err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR,
+ &status);
+ if (err)
+ return err;
+ *link_ok = !!(status & BMSR_LSTATUS);
+ }
+ if (speed)
+ *speed = SPEED_10000;
+ if (duplex)
+ *duplex = DUPLEX_FULL;
+ return 0;
+}
+
+static struct cphy_ops ael1002_ops = {
+ .reset = ael1002_reset,
+ .intr_enable = ael1002_intr_noop,
+ .intr_disable = ael1002_intr_noop,
+ .intr_clear = ael1002_intr_noop,
+ .intr_handler = ael1002_intr_noop,
+ .get_link_status = ael100x_get_link_status,
+ .power_down = ael1002_power_down,
+};
+
+void t3_ael1002_phy_prep(struct cphy *phy, struct adapter *adapter,
+ int phy_addr, const struct mdio_ops *mdio_ops)
+{
+ cphy_init(phy, adapter, phy_addr, &ael1002_ops, mdio_ops);
+ ael100x_txon(phy);
+}
+
+static int ael1006_reset(struct cphy *phy, int wait)
+{
+ return t3_phy_reset(phy, MDIO_DEV_PMA_PMD, wait);
+}
+
+static int ael1006_intr_enable(struct cphy *phy)
+{
+ return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 1);
+}
+
+static int ael1006_intr_disable(struct cphy *phy)
+{
+ return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 0);
+}
+
+static int ael1006_intr_clear(struct cphy *phy)
+{
+ u32 val;
+
+ return mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &val);
+}
+
+static int ael1006_intr_handler(struct cphy *phy)
+{
+ unsigned int status;
+ int err = mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &status);
+
+ if (err)
+ return err;
+ return (status & 1) ? cphy_cause_link_change : 0;
+}
+
+static int ael1006_power_down(struct cphy *phy, int enable)
+{
+ return t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR,
+ BMCR_PDOWN, enable ? BMCR_PDOWN : 0);
+}
+
+static struct cphy_ops ael1006_ops = {
+ .reset = ael1006_reset,
+ .intr_enable = ael1006_intr_enable,
+ .intr_disable = ael1006_intr_disable,
+ .intr_clear = ael1006_intr_clear,
+ .intr_handler = ael1006_intr_handler,
+ .get_link_status = ael100x_get_link_status,
+ .power_down = ael1006_power_down,
+};
+
+void t3_ael1006_phy_prep(struct cphy *phy, struct adapter *adapter,
+ int phy_addr, const struct mdio_ops *mdio_ops)
+{
+ cphy_init(phy, adapter, phy_addr, &ael1006_ops, mdio_ops);
+ ael100x_txon(phy);
+}
+
+static struct cphy_ops qt2045_ops = {
+ .reset = ael1006_reset,
+ .intr_enable = ael1006_intr_enable,
+ .intr_disable = ael1006_intr_disable,
+ .intr_clear = ael1006_intr_clear,
+ .intr_handler = ael1006_intr_handler,
+ .get_link_status = ael100x_get_link_status,
+ .power_down = ael1006_power_down,
+};
+
+void t3_qt2045_phy_prep(struct cphy *phy, struct adapter *adapter,
+ int phy_addr, const struct mdio_ops *mdio_ops)
+{
+ unsigned int stat;
+
+ cphy_init(phy, adapter, phy_addr, &qt2045_ops, mdio_ops);
+
+ /*
+ * Some cards where the PHY is supposed to be at address 0 actually
+ * have it at 1.
+ */
+ if (!phy_addr && !mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR, &stat) &&
+ stat == 0xffff)
+ phy->addr = 1;
+}
+
+static int xaui_direct_reset(struct cphy *phy, int wait)
+{
+ return 0;
+}
+
+static int xaui_direct_get_link_status(struct cphy *phy, int *link_ok,
+ int *speed, int *duplex, int *fc)
+{
+ if (link_ok) {
+ unsigned int status;
+
+ status = t3_read_reg(phy->adapter,
+ XGM_REG(A_XGM_SERDES_STAT0, phy->addr));
+ *link_ok = !(status & F_LOWSIG0);
+ }
+ if (speed)
+ *speed = SPEED_10000;
+ if (duplex)
+ *duplex = DUPLEX_FULL;
+ return 0;
+}
+
+static int xaui_direct_power_down(struct cphy *phy, int enable)
+{
+ return 0;
+}
+
+static struct cphy_ops xaui_direct_ops = {
+ .reset = xaui_direct_reset,
+ .intr_enable = ael1002_intr_noop,
+ .intr_disable = ael1002_intr_noop,
+ .intr_clear = ael1002_intr_noop,
+ .intr_handler = ael1002_intr_noop,
+ .get_link_status = xaui_direct_get_link_status,
+ .power_down = xaui_direct_power_down,
+};
+
+void t3_xaui_direct_phy_prep(struct cphy *phy, struct adapter *adapter,
+ int phy_addr, const struct mdio_ops *mdio_ops)
+{
+ cphy_init(phy, adapter, 1, &xaui_direct_ops, mdio_ops);
+}
diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h
new file mode 100644
index 00000000000..e23deeb7d06
--- /dev/null
+++ b/drivers/net/cxgb3/common.h
@@ -0,0 +1,729 @@
+/*
+ * Copyright (c) 2005-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef __CHELSIO_COMMON_H
+#define __CHELSIO_COMMON_H
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/ctype.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include "version.h"
+
+#define CH_ERR(adap, fmt, ...) dev_err(&adap->pdev->dev, fmt, ## __VA_ARGS__)
+#define CH_WARN(adap, fmt, ...) dev_warn(&adap->pdev->dev, fmt, ## __VA_ARGS__)
+#define CH_ALERT(adap, fmt, ...) \
+ dev_printk(KERN_ALERT, &adap->pdev->dev, 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) \
+ dev_printk(KERN_##level, &adapter->pdev->dev, fmt, \
+ ## __VA_ARGS__); \
+} while (0)
+
+#ifdef DEBUG
+# define CH_DBG(adapter, category, fmt, ...) \
+ CH_MSG(adapter, DEBUG, category, fmt, ## __VA_ARGS__)
+#else
+# define CH_DBG(adapter, category, fmt, ...)
+#endif
+
+/* 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 */
+ EEPROMSIZE = 8192, /* Serial EEPROM size */
+ RSS_TABLE_SIZE = 64, /* size of RSS lookup and mapping tables */
+ TCB_SIZE = 128, /* TCB size */
+ NMTUS = 16, /* size of MTU table */
+ NCCTRL_WIN = 32, /* # of congestion control windows */
+};
+
+#define MAX_RX_COALESCING_LEN 16224U
+
+enum {
+ PAUSE_RX = 1 << 0,
+ PAUSE_TX = 1 << 1,
+ PAUSE_AUTONEG = 1 << 2
+};
+
+enum {
+ SUPPORTED_OFFLOAD = 1 << 24,
+ SUPPORTED_IRQ = 1 << 25
+};
+
+enum { /* adapter interrupt-maintained statistics */
+ STAT_ULP_CH0_PBL_OOB,
+ STAT_ULP_CH1_PBL_OOB,
+ STAT_PCI_CORR_ECC,
+
+ IRQ_NUM_STATS /* keep last */
+};
+
+enum {
+ SGE_QSETS = 8, /* # of SGE Tx/Rx/RspQ sets */
+ SGE_RXQ_PER_SET = 2, /* # of Rx queues per set */
+ SGE_TXQ_PER_SET = 3 /* # of Tx queues per set */
+};
+
+enum sge_context_type { /* SGE egress context types */
+ SGE_CNTXT_RDMA = 0,
+ SGE_CNTXT_ETH = 2,
+ SGE_CNTXT_OFLD = 4,
+ SGE_CNTXT_CTRL = 5
+};
+
+enum {
+ AN_PKT_SIZE = 32, /* async notification packet size */
+ IMMED_PKT_SIZE = 48 /* packet size for immediate data */
+};
+
+struct sg_ent { /* SGE scatter/gather entry */
+ u32 len[2];
+ u64 addr[2];
+};
+
+#ifndef SGE_NUM_GENBITS
+/* Must be 1 or 2 */
+# define SGE_NUM_GENBITS 2
+#endif
+
+#define TX_DESC_FLITS 16U
+#define WR_FLITS (TX_DESC_FLITS + 1 - SGE_NUM_GENBITS)
+
+struct cphy;
+struct adapter;
+
+struct mdio_ops {
+ int (*read)(struct adapter *adapter, int phy_addr, int mmd_addr,
+ int reg_addr, unsigned int *val);
+ int (*write)(struct adapter *adapter, int phy_addr, int mmd_addr,
+ int reg_addr, unsigned int val);
+};
+
+struct adapter_info {
+ unsigned char nports; /* # of ports */
+ unsigned char phy_base_addr; /* MDIO PHY base address */
+ unsigned char mdien;
+ unsigned char mdiinv;
+ unsigned int gpio_out; /* GPIO output settings */
+ unsigned int gpio_intr; /* GPIO IRQ enable mask */
+ unsigned long caps; /* adapter capabilities */
+ const struct mdio_ops *mdio_ops; /* MDIO operations */
+ const char *desc; /* product description */
+};
+
+struct port_type_info {
+ void (*phy_prep)(struct cphy *phy, struct adapter *adapter,
+ int phy_addr, const struct mdio_ops *ops);
+ unsigned int caps;
+ const char *desc;
+};
+
+struct mc5_stats {
+ unsigned long parity_err;
+ unsigned long active_rgn_full;
+ unsigned long nfa_srch_err;
+ unsigned long unknown_cmd;
+ unsigned long reqq_parity_err;
+ unsigned long dispq_parity_err;
+ unsigned long del_act_empty;
+};
+
+struct mc7_stats {
+ unsigned long corr_err;
+ unsigned long uncorr_err;
+ unsigned long parity_err;
+ unsigned long addr_err;
+};
+
+struct mac_stats {
+ u64 tx_octets; /* total # of octets in good frames */
+ u64 tx_octets_bad; /* total # of octets in error frames */
+ u64 tx_frames; /* all good frames */
+ u64 tx_mcast_frames; /* good multicast frames */
+ u64 tx_bcast_frames; /* good broadcast frames */
+ u64 tx_pause; /* # of transmitted pause frames */
+ u64 tx_deferred; /* frames with deferred transmissions */
+ u64 tx_late_collisions; /* # of late collisions */
+ u64 tx_total_collisions; /* # of total collisions */
+ u64 tx_excess_collisions; /* frame errors from excessive collissions */
+ u64 tx_underrun; /* # of Tx FIFO underruns */
+ u64 tx_len_errs; /* # of Tx length errors */
+ u64 tx_mac_internal_errs; /* # of internal MAC errors on Tx */
+ u64 tx_excess_deferral; /* # of frames with excessive deferral */
+ u64 tx_fcs_errs; /* # of frames with bad FCS */
+
+ u64 tx_frames_64; /* # of Tx frames in a particular range */
+ u64 tx_frames_65_127;
+ u64 tx_frames_128_255;
+ u64 tx_frames_256_511;
+ u64 tx_frames_512_1023;
+ u64 tx_frames_1024_1518;
+ u64 tx_frames_1519_max;
+
+ u64 rx_octets; /* total # of octets in good frames */
+ u64 rx_octets_bad; /* total # of octets in error frames */
+ u64 rx_frames; /* all good frames */
+ u64 rx_mcast_frames; /* good multicast frames */
+ u64 rx_bcast_frames; /* good broadcast frames */
+ u64 rx_pause; /* # of received pause frames */
+ u64 rx_fcs_errs; /* # of received frames with bad FCS */
+ u64 rx_align_errs; /* alignment errors */
+ u64 rx_symbol_errs; /* symbol errors */
+ u64 rx_data_errs; /* data errors */
+ u64 rx_sequence_errs; /* sequence errors */
+ u64 rx_runt; /* # of runt frames */
+ u64 rx_jabber; /* # of jabber frames */
+ u64 rx_short; /* # of short frames */
+ u64 rx_too_long; /* # of oversized frames */
+ u64 rx_mac_internal_errs; /* # of internal MAC errors on Rx */
+
+ u64 rx_frames_64; /* # of Rx frames in a particular range */
+ u64 rx_frames_65_127;
+ u64 rx_frames_128_255;
+ u64 rx_frames_256_511;
+ u64 rx_frames_512_1023;
+ u64 rx_frames_1024_1518;
+ u64 rx_frames_1519_max;
+
+ u64 rx_cong_drops; /* # of Rx drops due to SGE congestion */
+
+ unsigned long tx_fifo_parity_err;
+ unsigned long rx_fifo_parity_err;
+ unsigned long tx_fifo_urun;
+ unsigned long rx_fifo_ovfl;
+ unsigned long serdes_signal_loss;
+ unsigned long xaui_pcs_ctc_err;
+ unsigned long xaui_pcs_align_change;
+};
+
+struct tp_mib_stats {
+ u32 ipInReceive_hi;
+ u32 ipInReceive_lo;
+ u32 ipInHdrErrors_hi;
+ u32 ipInHdrErrors_lo;
+ u32 ipInAddrErrors_hi;
+ u32 ipInAddrErrors_lo;
+ u32 ipInUnknownProtos_hi;
+ u32 ipInUnknownProtos_lo;
+ u32 ipInDiscards_hi;
+ u32 ipInDiscards_lo;
+ u32 ipInDelivers_hi;
+ u32 ipInDelivers_lo;
+ u32 ipOutRequests_hi;
+ u32 ipOutRequests_lo;
+ u32 ipOutDiscards_hi;
+ u32 ipOutDiscards_lo;
+ u32 ipOutNoRoutes_hi;
+ u32 ipOutNoRoutes_lo;
+ u32 ipReasmTimeout;
+ u32 ipReasmReqds;
+ u32 ipReasmOKs;
+ u32 ipReasmFails;
+
+ u32 reserved[8];
+
+ u32 tcpActiveOpens;
+ u32 tcpPassiveOpens;
+ u32 tcpAttemptFails;
+ u32 tcpEstabResets;
+ u32 tcpOutRsts;
+ u32 tcpCurrEstab;
+ u32 tcpInSegs_hi;
+ u32 tcpInSegs_lo;
+ u32 tcpOutSegs_hi;
+ u32 tcpOutSegs_lo;
+ u32 tcpRetransSeg_hi;
+ u32 tcpRetransSeg_lo;
+ u32 tcpInErrs_hi;
+ u32 tcpInErrs_lo;
+ u32 tcpRtoMin;
+ u32 tcpRtoMax;
+};
+
+struct tp_params {
+ unsigned int nchan; /* # of channels */
+ unsigned int pmrx_size; /* total PMRX capacity */
+ unsigned int pmtx_size; /* total PMTX capacity */
+ unsigned int cm_size; /* total CM capacity */
+ unsigned int chan_rx_size; /* per channel Rx size */
+ unsigned int chan_tx_size; /* per channel Tx size */
+ unsigned int rx_pg_size; /* Rx page size */
+ unsigned int tx_pg_size; /* Tx page size */
+ unsigned int rx_num_pgs; /* # of Rx pages */
+ unsigned int tx_num_pgs; /* # of Tx pages */
+ unsigned int ntimer_qs; /* # of timer queues */
+};
+
+struct qset_params { /* SGE queue set parameters */
+ unsigned int polling; /* polling/interrupt service for rspq */
+ unsigned int coalesce_usecs; /* irq coalescing timer */
+ unsigned int rspq_size; /* # of entries in response queue */
+ unsigned int fl_size; /* # of entries in regular free list */
+ unsigned int jumbo_size; /* # of entries in jumbo free list */
+ unsigned int txq_size[SGE_TXQ_PER_SET]; /* Tx queue sizes */
+ unsigned int cong_thres; /* FL congestion threshold */
+};
+
+struct sge_params {
+ unsigned int max_pkt_size; /* max offload pkt size */
+ struct qset_params qset[SGE_QSETS];
+};
+
+struct mc5_params {
+ unsigned int mode; /* selects MC5 width */
+ unsigned int nservers; /* size of server region */
+ unsigned int nfilters; /* size of filter region */
+ unsigned int nroutes; /* size of routing region */
+};
+
+/* Default MC5 region sizes */
+enum {
+ DEFAULT_NSERVERS = 512,
+ DEFAULT_NFILTERS = 128
+};
+
+/* MC5 modes, these must be non-0 */
+enum {
+ MC5_MODE_144_BIT = 1,
+ MC5_MODE_72_BIT = 2
+};
+
+struct vpd_params {
+ unsigned int cclk;
+ unsigned int mclk;
+ unsigned int uclk;
+ unsigned int mdc;
+ unsigned int mem_timing;
+ u8 eth_base[6];
+ u8 port_type[MAX_NPORTS];
+ unsigned short xauicfg[2];
+};
+
+struct pci_params {
+ unsigned int vpd_cap_addr;
+ unsigned int pcie_cap_addr;
+ unsigned short speed;
+ unsigned char width;
+ unsigned char variant;
+};
+
+enum {
+ PCI_VARIANT_PCI,
+ PCI_VARIANT_PCIX_MODE1_PARITY,
+ PCI_VARIANT_PCIX_MODE1_ECC,
+ PCI_VARIANT_PCIX_266_MODE2,
+ PCI_VARIANT_PCIE
+};
+
+struct adapter_params {
+ struct sge_params sge;
+ struct mc5_params mc5;
+ struct tp_params tp;
+ struct vpd_params vpd;
+ struct pci_params pci;
+
+ const struct adapter_info *info;
+
+ unsigned short mtus[NMTUS];
+ unsigned short a_wnd[NCCTRL_WIN];
+ unsigned short b_wnd[NCCTRL_WIN];
+
+ unsigned int nports; /* # of ethernet ports */
+ unsigned int stats_update_period; /* MAC stats accumulation period */
+ unsigned int linkpoll_period; /* link poll period in 0.1s */
+ unsigned int rev; /* chip revision */
+};
+
+struct trace_params {
+ u32 sip;
+ u32 sip_mask;
+ u32 dip;
+ u32 dip_mask;
+ u16 sport;
+ u16 sport_mask;
+ u16 dport;
+ u16 dport_mask;
+ u32 vlan:12;
+ u32 vlan_mask:12;
+ u32 intf:4;
+ u32 intf_mask:4;
+ u8 proto;
+ u8 proto_mask;
+};
+
+struct link_config {
+ unsigned int supported; /* link capabilities */
+ unsigned int advertising; /* advertised capabilities */
+ unsigned short requested_speed; /* speed user has requested */
+ unsigned short speed; /* actual link speed */
+ unsigned char requested_duplex; /* duplex user has requested */
+ unsigned char duplex; /* actual link duplex */
+ unsigned char requested_fc; /* flow control user has requested */
+ unsigned char fc; /* actual link flow control */
+ unsigned char autoneg; /* autonegotiating? */
+ unsigned int link_ok; /* link up? */
+};
+
+#define SPEED_INVALID 0xffff
+#define DUPLEX_INVALID 0xff
+
+struct mc5 {
+ struct adapter *adapter;
+ unsigned int tcam_size;
+ unsigned char part_type;
+ unsigned char parity_enabled;
+ unsigned char mode;
+ struct mc5_stats stats;
+};
+
+static inline unsigned int t3_mc5_size(const struct mc5 *p)
+{
+ return p->tcam_size;
+}
+
+struct mc7 {
+ struct adapter *adapter; /* backpointer to adapter */
+ unsigned int size; /* memory size in bytes */
+ unsigned int width; /* MC7 interface width */
+ unsigned int offset; /* register address offset for MC7 instance */
+ const char *name; /* name of MC7 instance */
+ struct mc7_stats stats; /* MC7 statistics */
+};
+
+static inline unsigned int t3_mc7_size(const struct mc7 *p)
+{
+ return p->size;
+}
+
+struct cmac {
+ struct adapter *adapter;
+ unsigned int offset;
+ unsigned int nucast; /* # of address filters for unicast MACs */
+ struct mac_stats stats;
+};
+
+enum {
+ MAC_DIRECTION_RX = 1,
+ MAC_DIRECTION_TX = 2,
+ MAC_RXFIFO_SIZE = 32768
+};
+
+/* IEEE 802.3ae specified MDIO devices */
+enum {
+ MDIO_DEV_PMA_PMD = 1,
+ MDIO_DEV_WIS = 2,
+ MDIO_DEV_PCS = 3,
+ MDIO_DEV_XGXS = 4
+};
+
+/* PHY loopback direction */
+enum {
+ PHY_LOOPBACK_TX = 1,
+ PHY_LOOPBACK_RX = 2
+};
+
+/* PHY interrupt types */
+enum {
+ cphy_cause_link_change = 1,
+ cphy_cause_fifo_error = 2
+};
+
+/* PHY operations */
+struct cphy_ops {
+ void (*destroy)(struct cphy *phy);
+ int (*reset)(struct cphy *phy, int wait);
+
+ int (*intr_enable)(struct cphy *phy);
+ int (*intr_disable)(struct cphy *phy);
+ int (*intr_clear)(struct cphy *phy);
+ int (*intr_handler)(struct cphy *phy);
+
+ int (*autoneg_enable)(struct cphy *phy);
+ int (*autoneg_restart)(struct cphy *phy);
+
+ int (*advertise)(struct cphy *phy, unsigned int advertise_map);
+ int (*set_loopback)(struct cphy *phy, int mmd, int dir, int enable);
+ int (*set_speed_duplex)(struct cphy *phy, int speed, int duplex);
+ int (*get_link_status)(struct cphy *phy, int *link_ok, int *speed,
+ int *duplex, int *fc);
+ int (*power_down)(struct cphy *phy, int enable);
+};
+
+/* A PHY instance */
+struct cphy {
+ int addr; /* PHY address */
+ struct adapter *adapter; /* associated adapter */
+ unsigned long fifo_errors; /* FIFO over/under-flows */
+ const struct cphy_ops *ops; /* PHY operations */
+ int (*mdio_read)(struct adapter *adapter, int phy_addr, int mmd_addr,
+ int reg_addr, unsigned int *val);
+ int (*mdio_write)(struct adapter *adapter, int phy_addr, int mmd_addr,
+ int reg_addr, unsigned int val);
+};
+
+/* Convenience MDIO read/write wrappers */
+static inline int mdio_read(struct cphy *phy, int mmd, int reg,
+ unsigned int *valp)
+{
+ return phy->mdio_read(phy->adapter, phy->addr, mmd, reg, valp);
+}
+
+static inline int mdio_write(struct cphy *phy, int mmd, int reg,
+ unsigned int val)
+{
+ return phy->mdio_write(phy->adapter, phy->addr, mmd, reg, val);
+}
+
+/* Convenience initializer */
+static inline void cphy_init(struct cphy *phy, struct adapter *adapter,
+ int phy_addr, struct cphy_ops *phy_ops,
+ const struct mdio_ops *mdio_ops)
+{
+ phy->adapter = adapter;
+ phy->addr = phy_addr;
+ phy->ops = phy_ops;
+ if (mdio_ops) {
+ phy->mdio_read = mdio_ops->read;
+ phy->mdio_write = mdio_ops->write;
+ }
+}
+
+/* Accumulate MAC statistics every 180 seconds. For 1G we multiply by 10. */
+#define MAC_STATS_ACCUM_SECS 180
+
+#define XGM_REG(reg_addr, idx) \
+ ((reg_addr) + (idx) * (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR))
+
+struct addr_val_pair {
+ unsigned int reg_addr;
+ unsigned int val;
+};
+
+#include "adapter.h"
+
+#ifndef PCI_VENDOR_ID_CHELSIO
+# define PCI_VENDOR_ID_CHELSIO 0x1425
+#endif
+
+#define for_each_port(adapter, iter) \
+ for (iter = 0; iter < (adapter)->params.nports; ++iter)
+
+#define adapter_info(adap) ((adap)->params.info)
+
+static inline int uses_xaui(const struct adapter *adap)
+{
+ return adapter_info(adap)->caps & SUPPORTED_AUI;
+}
+
+static inline int is_10G(const struct adapter *adap)
+{
+ return adapter_info(adap)->caps & SUPPORTED_10000baseT_Full;
+}
+
+static inline int is_offload(const struct adapter *adap)
+{
+ return adapter_info(adap)->caps & SUPPORTED_OFFLOAD;
+}
+
+static inline unsigned int core_ticks_per_usec(const struct adapter *adap)
+{
+ return adap->params.vpd.cclk / 1000;
+}
+
+static inline unsigned int is_pcie(const struct adapter *adap)
+{
+ return adap->params.pci.variant == PCI_VARIANT_PCIE;
+}
+
+void t3_set_reg_field(struct adapter *adap, unsigned int addr, u32 mask,
+ u32 val);
+void t3_write_regs(struct adapter *adapter, const struct addr_val_pair *p,
+ int n, unsigned int offset);
+int t3_wait_op_done_val(struct adapter *adapter, int reg, u32 mask,
+ int polarity, int attempts, int delay, u32 *valp);
+static inline int t3_wait_op_done(struct adapter *adapter, int reg, u32 mask,
+ int polarity, int attempts, int delay)
+{
+ return t3_wait_op_done_val(adapter, reg, mask, polarity, attempts,
+ delay, NULL);
+}
+int t3_mdio_change_bits(struct cphy *phy, int mmd, int reg, unsigned int clear,
+ unsigned int set);
+int t3_phy_reset(struct cphy *phy, int mmd, int wait);
+int t3_phy_advertise(struct cphy *phy, unsigned int advert);
+int t3_set_phy_speed_duplex(struct cphy *phy, int speed, int duplex);
+
+void t3_intr_enable(struct adapter *adapter);
+void t3_intr_disable(struct adapter *adapter);
+void t3_intr_clear(struct adapter *adapter);
+void t3_port_intr_enable(struct adapter *adapter, int idx);
+void t3_port_intr_disable(struct adapter *adapter, int idx);
+void t3_port_intr_clear(struct adapter *adapter, int idx);
+int t3_slow_intr_handler(struct adapter *adapter);
+int t3_phy_intr_handler(struct adapter *adapter);
+
+void t3_link_changed(struct adapter *adapter, int port_id);
+int t3_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc);
+const struct adapter_info *t3_get_adapter_info(unsigned int board_id);
+int t3_seeprom_read(struct adapter *adapter, u32 addr, u32 *data);
+int t3_seeprom_write(struct adapter *adapter, u32 addr, u32 data);
+int t3_seeprom_wp(struct adapter *adapter, int enable);
+int t3_read_flash(struct adapter *adapter, unsigned int addr,
+ unsigned int nwords, u32 *data, int byte_oriented);
+int t3_load_fw(struct adapter *adapter, const u8 * fw_data, unsigned int size);
+int t3_get_fw_version(struct adapter *adapter, u32 *vers);
+int t3_check_fw_version(struct adapter *adapter);
+int t3_init_hw(struct adapter *adapter, u32 fw_params);
+void mac_prep(struct cmac *mac, struct adapter *adapter, int index);
+void early_hw_init(struct adapter *adapter, const struct adapter_info *ai);
+int t3_prep_adapter(struct adapter *adapter, const struct adapter_info *ai,
+ int reset);
+void t3_led_ready(struct adapter *adapter);
+void t3_fatal_err(struct adapter *adapter);
+void t3_set_vlan_accel(struct adapter *adapter, unsigned int ports, int on);
+void t3_config_rss(struct adapter *adapter, unsigned int rss_config,
+ const u8 * cpus, const u16 *rspq);
+int t3_read_rss(struct adapter *adapter, u8 * lkup, u16 *map);
+int t3_mps_set_active_ports(struct adapter *adap, unsigned int port_mask);
+int t3_cim_ctl_blk_read(struct adapter *adap, unsigned int addr,
+ unsigned int n, unsigned int *valp);
+int t3_mc7_bd_read(struct mc7 *mc7, unsigned int start, unsigned int n,
+ u64 *buf);
+
+int t3_mac_reset(struct cmac *mac);
+void t3b_pcs_reset(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_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);
+int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc);
+
+void t3_mc5_prep(struct adapter *adapter, struct mc5 *mc5, int mode);
+int t3_mc5_init(struct mc5 *mc5, unsigned int nservers, unsigned int nfilters,
+ unsigned int nroutes);
+void t3_mc5_intr_handler(struct mc5 *mc5);
+int t3_read_mc5_range(const struct mc5 *mc5, unsigned int start, unsigned int n,
+ u32 *buf);
+
+int t3_tp_set_coalescing_size(struct adapter *adap, unsigned int size, int psh);
+void t3_tp_set_max_rxsize(struct adapter *adap, unsigned int size);
+void t3_tp_set_offload_mode(struct adapter *adap, int enable);
+void t3_tp_get_mib_stats(struct adapter *adap, struct tp_mib_stats *tps);
+void t3_load_mtus(struct adapter *adap, unsigned short mtus[NMTUS],
+ unsigned short alpha[NCCTRL_WIN],
+ unsigned short beta[NCCTRL_WIN], unsigned short mtu_cap);
+void t3_read_hw_mtus(struct adapter *adap, unsigned short mtus[NMTUS]);
+void t3_get_cong_cntl_tab(struct adapter *adap,
+ unsigned short incr[NMTUS][NCCTRL_WIN]);
+void t3_config_trace_filter(struct adapter *adapter,
+ const struct trace_params *tp, int filter_index,
+ int invert, int enable);
+int t3_config_sched(struct adapter *adap, unsigned int kbps, int sched);
+
+void t3_sge_prep(struct adapter *adap, struct sge_params *p);
+void t3_sge_init(struct adapter *adap, struct sge_params *p);
+int t3_sge_init_ecntxt(struct adapter *adapter, unsigned int id, int gts_enable,
+ enum sge_context_type type, int respq, u64 base_addr,
+ unsigned int size, unsigned int token, int gen,
+ unsigned int cidx);
+int t3_sge_init_flcntxt(struct adapter *adapter, unsigned int id,
+ int gts_enable, u64 base_addr, unsigned int size,
+ unsigned int esize, unsigned int cong_thres, int gen,
+ unsigned int cidx);
+int t3_sge_init_rspcntxt(struct adapter *adapter, unsigned int id,
+ int irq_vec_idx, u64 base_addr, unsigned int size,
+ unsigned int fl_thres, int gen, unsigned int cidx);
+int t3_sge_init_cqcntxt(struct adapter *adapter, unsigned int id, u64 base_addr,
+ unsigned int size, int rspq, int ovfl_mode,
+ unsigned int credits, unsigned int credit_thres);
+int t3_sge_enable_ecntxt(struct adapter *adapter, unsigned int id, int enable);
+int t3_sge_disable_fl(struct adapter *adapter, unsigned int id);
+int t3_sge_disable_rspcntxt(struct adapter *adapter, unsigned int id);
+int t3_sge_disable_cqcntxt(struct adapter *adapter, unsigned int id);
+int t3_sge_read_ecntxt(struct adapter *adapter, unsigned int id, u32 data[4]);
+int t3_sge_read_fl(struct adapter *adapter, unsigned int id, u32 data[4]);
+int t3_sge_read_cq(struct adapter *adapter, unsigned int id, u32 data[4]);
+int t3_sge_read_rspq(struct adapter *adapter, unsigned int id, u32 data[4]);
+int t3_sge_cqcntxt_op(struct adapter *adapter, unsigned int id, unsigned int op,
+ unsigned int credits);
+
+void t3_vsc8211_phy_prep(struct cphy *phy, struct adapter *adapter,
+ int phy_addr, const struct mdio_ops *mdio_ops);
+void t3_ael1002_phy_prep(struct cphy *phy, struct adapter *adapter,
+ int phy_addr, const struct mdio_ops *mdio_ops);
+void t3_ael1006_phy_prep(struct cphy *phy, struct adapter *adapter,
+ int phy_addr, const struct mdio_ops *mdio_ops);
+void t3_qt2045_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr,
+ const struct mdio_ops *mdio_ops);
+void t3_xaui_direct_phy_prep(struct cphy *phy, struct adapter *adapter,
+ int phy_addr, const struct mdio_ops *mdio_ops);
+#endif /* __CHELSIO_COMMON_H */
diff --git a/drivers/net/cxgb3/cxgb3_ctl_defs.h b/drivers/net/cxgb3/cxgb3_ctl_defs.h
new file mode 100644
index 00000000000..2095ddacff7
--- /dev/null
+++ b/drivers/net/cxgb3/cxgb3_ctl_defs.h
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef _CXGB3_OFFLOAD_CTL_DEFS_H
+#define _CXGB3_OFFLOAD_CTL_DEFS_H
+
+enum {
+ GET_MAX_OUTSTANDING_WR,
+ GET_TX_MAX_CHUNK,
+ GET_TID_RANGE,
+ GET_STID_RANGE,
+ GET_RTBL_RANGE,
+ GET_L2T_CAPACITY,
+ GET_MTUS,
+ GET_WR_LEN,
+ GET_IFF_FROM_MAC,
+ GET_DDP_PARAMS,
+ GET_PORTS,
+
+ ULP_ISCSI_GET_PARAMS,
+ ULP_ISCSI_SET_PARAMS,
+
+ RDMA_GET_PARAMS,
+ RDMA_CQ_OP,
+ RDMA_CQ_SETUP,
+ RDMA_CQ_DISABLE,
+ RDMA_CTRL_QP_SETUP,
+ RDMA_GET_MEM,
+};
+
+/*
+ * Structure used to describe a TID range. Valid TIDs are [base, base+num).
+ */
+struct tid_range {
+ unsigned int base; /* first TID */
+ unsigned int num; /* number of TIDs in range */
+};
+
+/*
+ * Structure used to request the size and contents of the MTU table.
+ */
+struct mtutab {
+ unsigned int size; /* # of entries in the MTU table */
+ const unsigned short *mtus; /* the MTU table values */
+};
+
+struct net_device;
+
+/*
+ * Structure used to request the adapter net_device owning a given MAC address.
+ */
+struct iff_mac {
+ struct net_device *dev; /* the net_device */
+ const unsigned char *mac_addr; /* MAC address to lookup */
+ u16 vlan_tag;
+};
+
+struct pci_dev;
+
+/*
+ * Structure used to request the TCP DDP parameters.
+ */
+struct ddp_params {
+ unsigned int llimit; /* TDDP region start address */
+ unsigned int ulimit; /* TDDP region end address */
+ unsigned int tag_mask; /* TDDP tag mask */
+ struct pci_dev *pdev;
+};
+
+struct adap_ports {
+ unsigned int nports; /* number of ports on this adapter */
+ struct net_device *lldevs[2];
+};
+
+/*
+ * Structure used to return information to the iscsi layer.
+ */
+struct ulp_iscsi_info {
+ unsigned int offset;
+ unsigned int llimit;
+ unsigned int ulimit;
+ unsigned int tagmask;
+ unsigned int pgsz3;
+ unsigned int pgsz2;
+ unsigned int pgsz1;
+ unsigned int pgsz0;
+ unsigned int max_rxsz;
+ unsigned int max_txsz;
+ struct pci_dev *pdev;
+};
+
+/*
+ * Structure used to return information to the RDMA layer.
+ */
+struct rdma_info {
+ unsigned int tpt_base; /* TPT base address */
+ unsigned int tpt_top; /* TPT last entry address */
+ unsigned int pbl_base; /* PBL base address */
+ unsigned int pbl_top; /* PBL last entry address */
+ unsigned int rqt_base; /* RQT base address */
+ unsigned int rqt_top; /* RQT last entry address */
+ unsigned int udbell_len; /* user doorbell region length */
+ unsigned long udbell_physbase; /* user doorbell physical start addr */
+ void __iomem *kdb_addr; /* kernel doorbell register address */
+ struct pci_dev *pdev; /* associated PCI device */
+};
+
+/*
+ * Structure used to request an operation on an RDMA completion queue.
+ */
+struct rdma_cq_op {
+ unsigned int id;
+ unsigned int op;
+ unsigned int credits;
+};
+
+/*
+ * Structure used to setup RDMA completion queues.
+ */
+struct rdma_cq_setup {
+ unsigned int id;
+ unsigned long long base_addr;
+ unsigned int size;
+ unsigned int credits;
+ unsigned int credit_thres;
+ unsigned int ovfl_mode;
+};
+
+/*
+ * Structure used to setup the RDMA control egress context.
+ */
+struct rdma_ctrlqp_setup {
+ unsigned long long base_addr;
+ unsigned int size;
+};
+#endif /* _CXGB3_OFFLOAD_CTL_DEFS_H */
diff --git a/drivers/net/cxgb3/cxgb3_defs.h b/drivers/net/cxgb3/cxgb3_defs.h
new file mode 100644
index 00000000000..e14862b43d1
--- /dev/null
+++ b/drivers/net/cxgb3/cxgb3_defs.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2006-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef _CHELSIO_DEFS_H
+#define _CHELSIO_DEFS_H
+
+#include <linux/skbuff.h>
+#include <net/tcp.h>
+
+#include "t3cdev.h"
+
+#include "cxgb3_offload.h"
+
+#define VALIDATE_TID 1
+
+void *cxgb_alloc_mem(unsigned long size);
+void cxgb_free_mem(void *addr);
+void cxgb_neigh_update(struct neighbour *neigh);
+void cxgb_redirect(struct dst_entry *old, struct dst_entry *new);
+
+/*
+ * Map an ATID or STID to their entries in the corresponding TID tables.
+ */
+static inline union active_open_entry *atid2entry(const struct tid_info *t,
+ unsigned int atid)
+{
+ return &t->atid_tab[atid - t->atid_base];
+}
+
+static inline union listen_entry *stid2entry(const struct tid_info *t,
+ unsigned int stid)
+{
+ return &t->stid_tab[stid - t->stid_base];
+}
+
+/*
+ * Find the connection corresponding to a TID.
+ */
+static inline struct t3c_tid_entry *lookup_tid(const struct tid_info *t,
+ unsigned int tid)
+{
+ return tid < t->ntids ? &(t->tid_tab[tid]) : NULL;
+}
+
+/*
+ * Find the connection corresponding to a server TID.
+ */
+static inline struct t3c_tid_entry *lookup_stid(const struct tid_info *t,
+ unsigned int tid)
+{
+ if (tid < t->stid_base || tid >= t->stid_base + t->nstids)
+ return NULL;
+ return &(stid2entry(t, tid)->t3c_tid);
+}
+
+/*
+ * Find the connection corresponding to an active-open TID.
+ */
+static inline struct t3c_tid_entry *lookup_atid(const struct tid_info *t,
+ unsigned int tid)
+{
+ if (tid < t->atid_base || tid >= t->atid_base + t->natids)
+ return NULL;
+ return &(atid2entry(t, tid)->t3c_tid);
+}
+
+int process_rx(struct t3cdev *dev, struct sk_buff **skbs, int n);
+int attach_t3cdev(struct t3cdev *dev);
+void detach_t3cdev(struct t3cdev *dev);
+#endif
diff --git a/drivers/net/cxgb3/cxgb3_ioctl.h b/drivers/net/cxgb3/cxgb3_ioctl.h
new file mode 100644
index 00000000000..a94281861a6
--- /dev/null
+++ b/drivers/net/cxgb3/cxgb3_ioctl.h
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef __CHIOCTL_H__
+#define __CHIOCTL_H__
+
+/*
+ * Ioctl commands specific to this driver.
+ */
+enum {
+ CHELSIO_SETREG = 1024,
+ CHELSIO_GETREG,
+ CHELSIO_SETTPI,
+ CHELSIO_GETTPI,
+ CHELSIO_GETMTUTAB,
+ CHELSIO_SETMTUTAB,
+ CHELSIO_GETMTU,
+ CHELSIO_SET_PM,
+ CHELSIO_GET_PM,
+ CHELSIO_GET_TCAM,
+ CHELSIO_SET_TCAM,
+ CHELSIO_GET_TCB,
+ CHELSIO_GET_MEM,
+ CHELSIO_LOAD_FW,
+ CHELSIO_GET_PROTO,
+ CHELSIO_SET_PROTO,
+ CHELSIO_SET_TRACE_FILTER,
+ CHELSIO_SET_QSET_PARAMS,
+ CHELSIO_GET_QSET_PARAMS,
+ CHELSIO_SET_QSET_NUM,
+ CHELSIO_GET_QSET_NUM,
+ CHELSIO_SET_PKTSCHED,
+};
+
+struct ch_reg {
+ uint32_t cmd;
+ uint32_t addr;
+ uint32_t val;
+};
+
+struct ch_cntxt {
+ uint32_t cmd;
+ uint32_t cntxt_type;
+ uint32_t cntxt_id;
+ uint32_t data[4];
+};
+
+/* context types */
+enum { CNTXT_TYPE_EGRESS, CNTXT_TYPE_FL, CNTXT_TYPE_RSP, CNTXT_TYPE_CQ };
+
+struct ch_desc {
+ uint32_t cmd;
+ uint32_t queue_num;
+ uint32_t idx;
+ uint32_t size;
+ uint8_t data[128];
+};
+
+struct ch_mem_range {
+ uint32_t cmd;
+ uint32_t mem_id;
+ uint32_t addr;
+ uint32_t len;
+ uint32_t version;
+ uint8_t buf[0];
+};
+
+struct ch_qset_params {
+ uint32_t cmd;
+ uint32_t qset_idx;
+ int32_t txq_size[3];
+ int32_t rspq_size;
+ int32_t fl_size[2];
+ int32_t intr_lat;
+ int32_t polling;
+ int32_t cong_thres;
+};
+
+struct ch_pktsched_params {
+ uint32_t cmd;
+ uint8_t sched;
+ uint8_t idx;
+ uint8_t min;
+ uint8_t max;
+ uint8_t binding;
+};
+
+#ifndef TCB_SIZE
+# define TCB_SIZE 128
+#endif
+
+/* TCB size in 32-bit words */
+#define TCB_WORDS (TCB_SIZE / 4)
+
+enum { MEM_CM, MEM_PMRX, MEM_PMTX }; /* ch_mem_range.mem_id values */
+
+struct ch_mtus {
+ uint32_t cmd;
+ uint32_t nmtus;
+ uint16_t mtus[NMTUS];
+};
+
+struct ch_pm {
+ uint32_t cmd;
+ uint32_t tx_pg_sz;
+ uint32_t tx_num_pg;
+ uint32_t rx_pg_sz;
+ uint32_t rx_num_pg;
+ uint32_t pm_total;
+};
+
+struct ch_tcam {
+ uint32_t cmd;
+ uint32_t tcam_size;
+ uint32_t nservers;
+ uint32_t nroutes;
+ uint32_t nfilters;
+};
+
+struct ch_tcb {
+ uint32_t cmd;
+ uint32_t tcb_index;
+ uint32_t tcb_data[TCB_WORDS];
+};
+
+struct ch_tcam_word {
+ uint32_t cmd;
+ uint32_t addr;
+ uint32_t buf[3];
+};
+
+struct ch_trace {
+ uint32_t cmd;
+ uint32_t sip;
+ uint32_t sip_mask;
+ uint32_t dip;
+ uint32_t dip_mask;
+ uint16_t sport;
+ uint16_t sport_mask;
+ uint16_t dport;
+ uint16_t dport_mask;
+ uint32_t vlan:12;
+ uint32_t vlan_mask:12;
+ uint32_t intf:4;
+ uint32_t intf_mask:4;
+ uint8_t proto;
+ uint8_t proto_mask;
+ uint8_t invert_match:1;
+ uint8_t config_tx:1;
+ uint8_t config_rx:1;
+ uint8_t trace_tx:1;
+ uint8_t trace_rx:1;
+};
+
+#define SIOCCHIOCTL SIOCDEVPRIVATE
+
+#endif
diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c
new file mode 100644
index 00000000000..43583ed655a
--- /dev/null
+++ b/drivers/net/cxgb3/cxgb3_main.c
@@ -0,0 +1,2520 @@
+/*
+ * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/if_vlan.h>
+#include <linux/mii.h>
+#include <linux/sockios.h>
+#include <linux/workqueue.h>
+#include <linux/proc_fs.h>
+#include <linux/rtnetlink.h>
+#include <asm/uaccess.h>
+
+#include "common.h"
+#include "cxgb3_ioctl.h"
+#include "regs.h"
+#include "cxgb3_offload.h"
+#include "version.h"
+
+#include "cxgb3_ctl_defs.h"
+#include "t3_cpl.h"
+#include "firmware_exports.h"
+
+enum {
+ MAX_TXQ_ENTRIES = 16384,
+ MAX_CTRL_TXQ_ENTRIES = 1024,
+ MAX_RSPQ_ENTRIES = 16384,
+ MAX_RX_BUFFERS = 16384,
+ MAX_RX_JUMBO_BUFFERS = 16384,
+ MIN_TXQ_ENTRIES = 4,
+ MIN_CTRL_TXQ_ENTRIES = 4,
+ MIN_RSPQ_ENTRIES = 32,
+ MIN_FL_ENTRIES = 32
+};
+
+#define PORT_MASK ((1 << MAX_NPORTS) - 1)
+
+#define DFLT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK | \
+ NETIF_MSG_TIMER | NETIF_MSG_IFDOWN | NETIF_MSG_IFUP |\
+ NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR)
+
+#define EEPROM_MAGIC 0x38E2F10C
+
+#define CH_DEVICE(devid, ssid, idx) \
+ { PCI_VENDOR_ID_CHELSIO, devid, PCI_ANY_ID, ssid, 0, 0, idx }
+
+static const struct pci_device_id cxgb3_pci_tbl[] = {
+ CH_DEVICE(0x20, 1, 0), /* PE9000 */
+ CH_DEVICE(0x21, 1, 1), /* T302E */
+ CH_DEVICE(0x22, 1, 2), /* T310E */
+ CH_DEVICE(0x23, 1, 3), /* T320X */
+ CH_DEVICE(0x24, 1, 1), /* T302X */
+ CH_DEVICE(0x25, 1, 3), /* T320E */
+ CH_DEVICE(0x26, 1, 2), /* T310X */
+ CH_DEVICE(0x30, 1, 2), /* T3B10 */
+ CH_DEVICE(0x31, 1, 3), /* T3B20 */
+ CH_DEVICE(0x32, 1, 1), /* T3B02 */
+ {0,}
+};
+
+MODULE_DESCRIPTION(DRV_DESC);
+MODULE_AUTHOR("Chelsio Communications");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_VERSION(DRV_VERSION);
+MODULE_DEVICE_TABLE(pci, cxgb3_pci_tbl);
+
+static int dflt_msg_enable = DFLT_MSG_ENABLE;
+
+module_param(dflt_msg_enable, int, 0644);
+MODULE_PARM_DESC(dflt_msg_enable, "Chelsio T3 default message enable bitmap");
+
+/*
+ * The driver uses the best interrupt scheme available on a platform in the
+ * order MSI-X, MSI, legacy pin interrupts. This parameter determines which
+ * of these schemes the driver may consider as follows:
+ *
+ * msi = 2: choose from among all three options
+ * msi = 1: only consider MSI and pin interrupts
+ * msi = 0: force pin interrupts
+ */
+static int msi = 2;
+
+module_param(msi, int, 0644);
+MODULE_PARM_DESC(msi, "whether to use MSI or MSI-X");
+
+/*
+ * The driver enables offload as a default.
+ * To disable it, use ofld_disable = 1.
+ */
+
+static int ofld_disable = 0;
+
+module_param(ofld_disable, int, 0644);
+MODULE_PARM_DESC(ofld_disable, "whether to enable offload at init time or not");
+
+/*
+ * We have work elements that we need to cancel when an interface is taken
+ * down. Normally the work elements would be executed by keventd but that
+ * can deadlock because of linkwatch. If our close method takes the rtnl
+ * lock and linkwatch is ahead of our work elements in keventd, linkwatch
+ * 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;
+
+/**
+ * link_report - show link status and link speed/duplex
+ * @p: the port whose settings are to be reported
+ *
+ * Shows the link status, speed, and duplex of a port.
+ */
+static void link_report(struct net_device *dev)
+{
+ if (!netif_carrier_ok(dev))
+ printk(KERN_INFO "%s: link down\n", dev->name);
+ else {
+ const char *s = "10Mbps";
+ const struct port_info *p = netdev_priv(dev);
+
+ switch (p->link_config.speed) {
+ case SPEED_10000:
+ s = "10Gbps";
+ break;
+ case SPEED_1000:
+ s = "1000Mbps";
+ break;
+ case SPEED_100:
+ s = "100Mbps";
+ break;
+ }
+
+ printk(KERN_INFO "%s: link up, %s, %s-duplex\n", dev->name, s,
+ p->link_config.duplex == DUPLEX_FULL ? "full" : "half");
+ }
+}
+
+/**
+ * t3_os_link_changed - handle link status changes
+ * @adapter: the adapter associated with the link change
+ * @port_id: the port index whose limk status has changed
+ * @link_stat: the new status of the link
+ * @speed: the new speed setting
+ * @duplex: the new duplex setting
+ * @pause: the new flow-control setting
+ *
+ * This is the OS-dependent handler for link status changes. The OS
+ * neutral handler takes care of most of the processing for these events,
+ * then calls this handler for any OS-specific processing.
+ */
+void t3_os_link_changed(struct adapter *adapter, int port_id, int link_stat,
+ int speed, int duplex, int pause)
+{
+ struct net_device *dev = adapter->port[port_id];
+
+ /* Skip changes from disabled ports. */
+ if (!netif_running(dev))
+ return;
+
+ if (link_stat != netif_carrier_ok(dev)) {
+ if (link_stat)
+ netif_carrier_on(dev);
+ else
+ netif_carrier_off(dev);
+ link_report(dev);
+ }
+}
+
+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);
+}
+
+/**
+ * link_start - enable a port
+ * @dev: the device to enable
+ *
+ * Performs the MAC and PHY actions needed to enable a port.
+ */
+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_mtu(mac, dev->mtu);
+ t3_mac_set_address(mac, 0, dev->dev_addr);
+ t3_mac_set_rx_mode(mac, &rm);
+ t3_link_start(&pi->phy, mac, &pi->link_config);
+ t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
+}
+
+static inline void cxgb_disable_msi(struct adapter *adapter)
+{
+ if (adapter->flags & USING_MSIX) {
+ pci_disable_msix(adapter->pdev);
+ adapter->flags &= ~USING_MSIX;
+ } else if (adapter->flags & USING_MSI) {
+ pci_disable_msi(adapter->pdev);
+ adapter->flags &= ~USING_MSI;
+ }
+}
+
+/*
+ * Interrupt handler for asynchronous events used with MSI-X.
+ */
+static irqreturn_t t3_async_intr_handler(int irq, void *cookie)
+{
+ t3_slow_intr_handler(cookie);
+ return IRQ_HANDLED;
+}
+
+/*
+ * Name the MSI-X interrupts.
+ */
+static void name_msix_vecs(struct adapter *adap)
+{
+ int i, j, msi_idx = 1, n = sizeof(adap->msix_info[0].desc) - 1;
+
+ snprintf(adap->msix_info[0].desc, n, "%s", adap->name);
+ adap->msix_info[0].desc[n] = 0;
+
+ for_each_port(adap, j) {
+ struct net_device *d = adap->port[j];
+ const struct port_info *pi = netdev_priv(d);
+
+ for (i = 0; i < pi->nqsets; i++, msi_idx++) {
+ snprintf(adap->msix_info[msi_idx].desc, n,
+ "%s (queue %d)", d->name, i);
+ adap->msix_info[msi_idx].desc[n] = 0;
+ }
+ }
+}
+
+static int request_msix_data_irqs(struct adapter *adap)
+{
+ int i, j, err, qidx = 0;
+
+ for_each_port(adap, i) {
+ int nqsets = adap2pinfo(adap, i)->nqsets;
+
+ for (j = 0; j < nqsets; ++j) {
+ err = request_irq(adap->msix_info[qidx + 1].vec,
+ t3_intr_handler(adap,
+ adap->sge.qs[qidx].
+ rspq.polling), 0,
+ adap->msix_info[qidx + 1].desc,
+ &adap->sge.qs[qidx]);
+ if (err) {
+ while (--qidx >= 0)
+ free_irq(adap->msix_info[qidx + 1].vec,
+ &adap->sge.qs[qidx]);
+ return err;
+ }
+ qidx++;
+ }
+ }
+ return 0;
+}
+
+/**
+ * setup_rss - configure RSS
+ * @adap: the adapter
+ *
+ * Sets up RSS to distribute packets to multiple receive queues. We
+ * configure the RSS CPU lookup table to distribute to the number of HW
+ * receive queues, and the response queue lookup table to narrow that
+ * down to the response queues actually configured for each port.
+ * We always configure the RSS mapping for two ports since the mapping
+ * table has plenty of entries.
+ */
+static void setup_rss(struct adapter *adap)
+{
+ int i;
+ unsigned int nq0 = adap2pinfo(adap, 0)->nqsets;
+ unsigned int nq1 = adap->port[1] ? adap2pinfo(adap, 1)->nqsets : 1;
+ u8 cpus[SGE_QSETS + 1];
+ u16 rspq_map[RSS_TABLE_SIZE];
+
+ for (i = 0; i < SGE_QSETS; ++i)
+ cpus[i] = i;
+ cpus[SGE_QSETS] = 0xff; /* terminator */
+
+ for (i = 0; i < RSS_TABLE_SIZE / 2; ++i) {
+ rspq_map[i] = i % nq0;
+ rspq_map[i + RSS_TABLE_SIZE / 2] = (i % nq1) + nq0;
+ }
+
+ t3_config_rss(adap, F_RQFEEDBACKENABLE | F_TNLLKPEN | F_TNLMAPEN |
+ F_TNLPRTEN | F_TNL2TUPEN | F_TNL4TUPEN |
+ V_RRCPLCPUSIZE(6), cpus, rspq_map);
+}
+
+/*
+ * If we have multiple receive queues per port serviced by NAPI we need one
+ * netdevice per queue as NAPI operates on netdevices. We already have one
+ * netdevice, namely the one associated with the interface, so we use dummy
+ * ones for any additional queues. Note that these netdevices exist purely
+ * so that NAPI has something to work with, they do not represent network
+ * ports and are not registered.
+ */
+static int init_dummy_netdevs(struct adapter *adap)
+{
+ int i, j, dummy_idx = 0;
+ struct net_device *nd;
+
+ for_each_port(adap, i) {
+ struct net_device *dev = adap->port[i];
+ const struct port_info *pi = netdev_priv(dev);
+
+ for (j = 0; j < pi->nqsets - 1; j++) {
+ if (!adap->dummy_netdev[dummy_idx]) {
+ nd = alloc_netdev(0, "", ether_setup);
+ if (!nd)
+ goto free_all;
+
+ nd->priv = adap;
+ nd->weight = 64;
+ set_bit(__LINK_STATE_START, &nd->state);
+ adap->dummy_netdev[dummy_idx] = nd;
+ }
+ strcpy(adap->dummy_netdev[dummy_idx]->name, dev->name);
+ dummy_idx++;
+ }
+ }
+ return 0;
+
+free_all:
+ while (--dummy_idx >= 0) {
+ free_netdev(adap->dummy_netdev[dummy_idx]);
+ adap->dummy_netdev[dummy_idx] = NULL;
+ }
+ return -ENOMEM;
+}
+
+/*
+ * Wait until all NAPI handlers are descheduled. This includes the handlers of
+ * both netdevices representing interfaces and the dummy ones for the extra
+ * queues.
+ */
+static void quiesce_rx(struct adapter *adap)
+{
+ int i;
+ struct net_device *dev;
+
+ for_each_port(adap, i) {
+ dev = adap->port[i];
+ while (test_bit(__LINK_STATE_RX_SCHED, &dev->state))
+ msleep(1);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(adap->dummy_netdev); i++) {
+ dev = adap->dummy_netdev[i];
+ if (dev)
+ while (test_bit(__LINK_STATE_RX_SCHED, &dev->state))
+ msleep(1);
+ }
+}
+
+/**
+ * setup_sge_qsets - configure SGE Tx/Rx/response queues
+ * @adap: the adapter
+ *
+ * Determines how many sets of SGE queues to use and initializes them.
+ * We support multiple queue sets per port if we have MSI-X, otherwise
+ * just one queue set per port.
+ */
+static int setup_sge_qsets(struct adapter *adap)
+{
+ int i, j, err, irq_idx = 0, qset_idx = 0, dummy_dev_idx = 0;
+ unsigned int ntxq = is_offload(adap) ? SGE_TXQ_PER_SET : 1;
+
+ if (adap->params.rev > 0 && !(adap->flags & USING_MSI))
+ irq_idx = -1;
+
+ for_each_port(adap, i) {
+ struct net_device *dev = adap->port[i];
+ const struct port_info *pi = netdev_priv(dev);
+
+ for (j = 0; j < pi->nqsets; ++j, ++qset_idx) {
+ err = t3_sge_alloc_qset(adap, qset_idx, 1,
+ (adap->flags & USING_MSIX) ? qset_idx + 1 :
+ irq_idx,
+ &adap->params.sge.qset[qset_idx], ntxq,
+ j == 0 ? dev :
+ adap-> dummy_netdev[dummy_dev_idx++]);
+ if (err) {
+ t3_free_sge_resources(adap);
+ return err;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static ssize_t attr_show(struct device *d, struct device_attribute *attr,
+ char *buf,
+ ssize_t(*format) (struct adapter *, char *))
+{
+ ssize_t len;
+ struct adapter *adap = to_net_dev(d)->priv;
+
+ /* Synchronize with ioctls that may shut down the device */
+ rtnl_lock();
+ len = (*format) (adap, buf);
+ rtnl_unlock();
+ return len;
+}
+
+static ssize_t attr_store(struct device *d, struct device_attribute *attr,
+ const char *buf, size_t len,
+ ssize_t(*set) (struct adapter *, unsigned int),
+ unsigned int min_val, unsigned int max_val)
+{
+ char *endp;
+ ssize_t ret;
+ unsigned int val;
+ struct adapter *adap = to_net_dev(d)->priv;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ val = simple_strtoul(buf, &endp, 0);
+ if (endp == buf || val < min_val || val > max_val)
+ return -EINVAL;
+
+ rtnl_lock();
+ ret = (*set) (adap, val);
+ if (!ret)
+ ret = len;
+ rtnl_unlock();
+ return ret;
+}
+
+#define CXGB3_SHOW(name, val_expr) \
+static ssize_t format_##name(struct adapter *adap, char *buf) \
+{ \
+ return sprintf(buf, "%u\n", val_expr); \
+} \
+static ssize_t show_##name(struct device *d, struct device_attribute *attr, \
+ char *buf) \
+{ \
+ return attr_show(d, attr, buf, format_##name); \
+}
+
+static ssize_t set_nfilters(struct adapter *adap, unsigned int val)
+{
+ if (adap->flags & FULL_INIT_DONE)
+ return -EBUSY;
+ if (val && adap->params.rev == 0)
+ return -EINVAL;
+ if (val > t3_mc5_size(&adap->mc5) - adap->params.mc5.nservers)
+ return -EINVAL;
+ adap->params.mc5.nfilters = val;
+ return 0;
+}
+
+static ssize_t store_nfilters(struct device *d, struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ return attr_store(d, attr, buf, len, set_nfilters, 0, ~0);
+}
+
+static ssize_t set_nservers(struct adapter *adap, unsigned int val)
+{
+ if (adap->flags & FULL_INIT_DONE)
+ return -EBUSY;
+ if (val > t3_mc5_size(&adap->mc5) - adap->params.mc5.nfilters)
+ return -EINVAL;
+ adap->params.mc5.nservers = val;
+ return 0;
+}
+
+static ssize_t store_nservers(struct device *d, struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ return attr_store(d, attr, buf, len, set_nservers, 0, ~0);
+}
+
+#define CXGB3_ATTR_R(name, val_expr) \
+CXGB3_SHOW(name, val_expr) \
+static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
+
+#define CXGB3_ATTR_RW(name, val_expr, store_method) \
+CXGB3_SHOW(name, val_expr) \
+static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_##name, store_method)
+
+CXGB3_ATTR_R(cam_size, t3_mc5_size(&adap->mc5));
+CXGB3_ATTR_RW(nfilters, adap->params.mc5.nfilters, store_nfilters);
+CXGB3_ATTR_RW(nservers, adap->params.mc5.nservers, store_nservers);
+
+static struct attribute *cxgb3_attrs[] = {
+ &dev_attr_cam_size.attr,
+ &dev_attr_nfilters.attr,
+ &dev_attr_nservers.attr,
+ NULL
+};
+
+static struct attribute_group cxgb3_attr_group = {.attrs = cxgb3_attrs };
+
+static ssize_t tm_attr_show(struct device *d, struct device_attribute *attr,
+ char *buf, int sched)
+{
+ ssize_t len;
+ unsigned int v, addr, bpt, cpt;
+ struct adapter *adap = to_net_dev(d)->priv;
+
+ addr = A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2;
+ rtnl_lock();
+ t3_write_reg(adap, A_TP_TM_PIO_ADDR, addr);
+ v = t3_read_reg(adap, A_TP_TM_PIO_DATA);
+ if (sched & 1)
+ v >>= 16;
+ bpt = (v >> 8) & 0xff;
+ cpt = v & 0xff;
+ if (!cpt)
+ len = sprintf(buf, "disabled\n");
+ else {
+ v = (adap->params.vpd.cclk * 1000) / cpt;
+ len = sprintf(buf, "%u Kbps\n", (v * bpt) / 125);
+ }
+ rtnl_unlock();
+ return len;
+}
+
+static ssize_t tm_attr_store(struct device *d, struct device_attribute *attr,
+ const char *buf, size_t len, int sched)
+{
+ char *endp;
+ ssize_t ret;
+ unsigned int val;
+ struct adapter *adap = to_net_dev(d)->priv;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ val = simple_strtoul(buf, &endp, 0);
+ if (endp == buf || val > 10000000)
+ return -EINVAL;
+
+ rtnl_lock();
+ ret = t3_config_sched(adap, val, sched);
+ if (!ret)
+ ret = len;
+ rtnl_unlock();
+ return ret;
+}
+
+#define TM_ATTR(name, sched) \
+static ssize_t show_##name(struct device *d, struct device_attribute *attr, \
+ char *buf) \
+{ \
+ return tm_attr_show(d, attr, buf, sched); \
+} \
+static ssize_t store_##name(struct device *d, struct device_attribute *attr, \
+ const char *buf, size_t len) \
+{ \
+ return tm_attr_store(d, attr, buf, len, sched); \
+} \
+static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_##name, store_##name)
+
+TM_ATTR(sched0, 0);
+TM_ATTR(sched1, 1);
+TM_ATTR(sched2, 2);
+TM_ATTR(sched3, 3);
+TM_ATTR(sched4, 4);
+TM_ATTR(sched5, 5);
+TM_ATTR(sched6, 6);
+TM_ATTR(sched7, 7);
+
+static struct attribute *offload_attrs[] = {
+ &dev_attr_sched0.attr,
+ &dev_attr_sched1.attr,
+ &dev_attr_sched2.attr,
+ &dev_attr_sched3.attr,
+ &dev_attr_sched4.attr,
+ &dev_attr_sched5.attr,
+ &dev_attr_sched6.attr,
+ &dev_attr_sched7.attr,
+ NULL
+};
+
+static struct attribute_group offload_attr_group = {.attrs = offload_attrs };
+
+/*
+ * Sends an sk_buff to an offload queue driver
+ * after dealing with any active network taps.
+ */
+static inline int offload_tx(struct t3cdev *tdev, struct sk_buff *skb)
+{
+ int ret;
+
+ local_bh_disable();
+ ret = t3_offload_tx(tdev, skb);
+ local_bh_enable();
+ return ret;
+}
+
+static int write_smt_entry(struct adapter *adapter, int idx)
+{
+ struct cpl_smt_write_req *req;
+ struct sk_buff *skb = alloc_skb(sizeof(*req), GFP_KERNEL);
+
+ if (!skb)
+ return -ENOMEM;
+
+ req = (struct cpl_smt_write_req *)__skb_put(skb, sizeof(*req));
+ req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
+ OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, idx));
+ req->mtu_idx = NMTUS - 1; /* should be 0 but there's a T3 bug */
+ req->iff = idx;
+ memset(req->src_mac1, 0, sizeof(req->src_mac1));
+ memcpy(req->src_mac0, adapter->port[idx]->dev_addr, ETH_ALEN);
+ skb->priority = 1;
+ offload_tx(&adapter->tdev, skb);
+ return 0;
+}
+
+static int init_smt(struct adapter *adapter)
+{
+ int i;
+
+ for_each_port(adapter, i)
+ write_smt_entry(adapter, i);
+ return 0;
+}
+
+static void init_port_mtus(struct adapter *adapter)
+{
+ unsigned int mtus = adapter->port[0]->mtu;
+
+ if (adapter->port[1])
+ mtus |= adapter->port[1]->mtu << 16;
+ t3_write_reg(adapter, A_TP_MTU_PORT_TABLE, mtus);
+}
+
+static void send_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo,
+ int hi, int port)
+{
+ struct sk_buff *skb;
+ struct mngt_pktsched_wr *req;
+
+ skb = alloc_skb(sizeof(*req), GFP_KERNEL | __GFP_NOFAIL);
+ req = (struct mngt_pktsched_wr *)skb_put(skb, sizeof(*req));
+ req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_MNGT));
+ req->mngt_opcode = FW_MNGTOPCODE_PKTSCHED_SET;
+ req->sched = sched;
+ req->idx = qidx;
+ req->min = lo;
+ req->max = hi;
+ req->binding = port;
+ t3_mgmt_tx(adap, skb);
+}
+
+static void bind_qsets(struct adapter *adap)
+{
+ int i, j;
+
+ for_each_port(adap, i) {
+ const struct port_info *pi = adap2pinfo(adap, i);
+
+ for (j = 0; j < pi->nqsets; ++j)
+ send_pktsched_cmd(adap, 1, pi->first_qset + j, -1,
+ -1, i);
+ }
+}
+
+/**
+ * cxgb_up - enable the adapter
+ * @adapter: adapter being enabled
+ *
+ * Called when the first port is enabled, this function performs the
+ * actions necessary to make an adapter operational, such as completing
+ * the initialization of HW modules, and enabling interrupts.
+ *
+ * Must be called with the rtnl lock held.
+ */
+static int cxgb_up(struct adapter *adap)
+{
+ int err = 0;
+
+ if (!(adap->flags & FULL_INIT_DONE)) {
+ err = t3_check_fw_version(adap);
+ if (err)
+ goto out;
+
+ err = init_dummy_netdevs(adap);
+ if (err)
+ goto out;
+
+ err = t3_init_hw(adap, 0);
+ if (err)
+ goto out;
+
+ err = setup_sge_qsets(adap);
+ if (err)
+ goto out;
+
+ setup_rss(adap);
+ adap->flags |= FULL_INIT_DONE;
+ }
+
+ t3_intr_clear(adap);
+
+ if (adap->flags & USING_MSIX) {
+ name_msix_vecs(adap);
+ err = request_irq(adap->msix_info[0].vec,
+ t3_async_intr_handler, 0,
+ adap->msix_info[0].desc, adap);
+ if (err)
+ goto irq_err;
+
+ if (request_msix_data_irqs(adap)) {
+ free_irq(adap->msix_info[0].vec, adap);
+ goto irq_err;
+ }
+ } else if ((err = request_irq(adap->pdev->irq,
+ t3_intr_handler(adap,
+ adap->sge.qs[0].rspq.
+ polling),
+ (adap->flags & USING_MSI) ?
+ 0 : IRQF_SHARED,
+ adap->name, adap)))
+ goto irq_err;
+
+ t3_sge_start(adap);
+ t3_intr_enable(adap);
+
+ if ((adap->flags & (USING_MSIX | QUEUES_BOUND)) == USING_MSIX)
+ bind_qsets(adap);
+ adap->flags |= QUEUES_BOUND;
+
+out:
+ return err;
+irq_err:
+ CH_ERR(adap, "request_irq failed, err %d\n", err);
+ goto out;
+}
+
+/*
+ * Release resources when all the ports and offloading have been stopped.
+ */
+static void cxgb_down(struct adapter *adapter)
+{
+ t3_sge_stop(adapter);
+ spin_lock_irq(&adapter->work_lock); /* sync with PHY intr task */
+ t3_intr_disable(adapter);
+ spin_unlock_irq(&adapter->work_lock);
+
+ if (adapter->flags & USING_MSIX) {
+ int i, n = 0;
+
+ free_irq(adapter->msix_info[0].vec, adapter);
+ for_each_port(adapter, i)
+ n += adap2pinfo(adapter, i)->nqsets;
+
+ for (i = 0; i < n; ++i)
+ free_irq(adapter->msix_info[i + 1].vec,
+ &adapter->sge.qs[i]);
+ } else
+ free_irq(adapter->pdev->irq, adapter);
+
+ flush_workqueue(cxgb3_wq); /* wait for external IRQ handler */
+ quiesce_rx(adapter);
+}
+
+static void schedule_chk_task(struct adapter *adap)
+{
+ unsigned int timeo;
+
+ timeo = adap->params.linkpoll_period ?
+ (HZ * adap->params.linkpoll_period) / 10 :
+ adap->params.stats_update_period * HZ;
+ if (timeo)
+ queue_delayed_work(cxgb3_wq, &adap->adap_check_task, timeo);
+}
+
+static int offload_open(struct net_device *dev)
+{
+ struct adapter *adapter = dev->priv;
+ struct t3cdev *tdev = T3CDEV(dev);
+ int adap_up = adapter->open_device_map & PORT_MASK;
+ int err = 0;
+
+ if (test_and_set_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map))
+ return 0;
+
+ if (!adap_up && (err = cxgb_up(adapter)) < 0)
+ return err;
+
+ t3_tp_set_offload_mode(adapter, 1);
+ tdev->lldev = adapter->port[0];
+ err = cxgb3_offload_activate(adapter);
+ if (err)
+ goto out;
+
+ init_port_mtus(adapter);
+ t3_load_mtus(adapter, adapter->params.mtus, adapter->params.a_wnd,
+ adapter->params.b_wnd,
+ adapter->params.rev == 0 ?
+ adapter->port[0]->mtu : 0xffff);
+ init_smt(adapter);
+
+ /* Never mind if the next step fails */
+ sysfs_create_group(&tdev->lldev->dev.kobj, &offload_attr_group);
+
+ /* Call back all registered clients */
+ cxgb3_add_clients(tdev);
+
+out:
+ /* restore them in case the offload module has changed them */
+ if (err) {
+ t3_tp_set_offload_mode(adapter, 0);
+ clear_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map);
+ cxgb3_set_dummy_ops(tdev);
+ }
+ return err;
+}
+
+static int offload_close(struct t3cdev *tdev)
+{
+ struct adapter *adapter = tdev2adap(tdev);
+
+ if (!test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map))
+ return 0;
+
+ /* Call back all registered clients */
+ cxgb3_remove_clients(tdev);
+
+ sysfs_remove_group(&tdev->lldev->dev.kobj, &offload_attr_group);
+
+ tdev->lldev = NULL;
+ cxgb3_set_dummy_ops(tdev);
+ t3_tp_set_offload_mode(adapter, 0);
+ clear_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map);
+
+ if (!adapter->open_device_map)
+ cxgb_down(adapter);
+
+ cxgb3_offload_deactivate(adapter);
+ return 0;
+}
+
+static int cxgb_open(struct net_device *dev)
+{
+ int err;
+ struct adapter *adapter = dev->priv;
+ struct port_info *pi = netdev_priv(dev);
+ int other_ports = adapter->open_device_map & PORT_MASK;
+
+ if (!adapter->open_device_map && (err = cxgb_up(adapter)) < 0)
+ return err;
+
+ set_bit(pi->port_id, &adapter->open_device_map);
+ if (!ofld_disable) {
+ err = offload_open(dev);
+ if (err)
+ printk(KERN_WARNING
+ "Could not initialize offload capabilities\n");
+ }
+
+ link_start(dev);
+ t3_port_intr_enable(adapter, pi->port_id);
+ netif_start_queue(dev);
+ if (!other_ports)
+ schedule_chk_task(adapter);
+
+ return 0;
+}
+
+static int cxgb_close(struct net_device *dev)
+{
+ struct adapter *adapter = dev->priv;
+ struct port_info *p = netdev_priv(dev);
+
+ t3_port_intr_disable(adapter, p->port_id);
+ netif_stop_queue(dev);
+ p->phy.ops->power_down(&p->phy, 1);
+ netif_carrier_off(dev);
+ t3_mac_disable(&p->mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX);
+
+ spin_lock(&adapter->work_lock); /* sync with update task */
+ clear_bit(p->port_id, &adapter->open_device_map);
+ spin_unlock(&adapter->work_lock);
+
+ if (!(adapter->open_device_map & PORT_MASK))
+ cancel_rearming_delayed_workqueue(cxgb3_wq,
+ &adapter->adap_check_task);
+
+ if (!adapter->open_device_map)
+ cxgb_down(adapter);
+
+ return 0;
+}
+
+static struct net_device_stats *cxgb_get_stats(struct net_device *dev)
+{
+ struct adapter *adapter = dev->priv;
+ struct port_info *p = netdev_priv(dev);
+ struct net_device_stats *ns = &p->netstats;
+ const struct mac_stats *pstats;
+
+ spin_lock(&adapter->stats_lock);
+ pstats = t3_mac_update_stats(&p->mac);
+ spin_unlock(&adapter->stats_lock);
+
+ ns->tx_bytes = pstats->tx_octets;
+ ns->tx_packets = pstats->tx_frames;
+ ns->rx_bytes = pstats->rx_octets;
+ ns->rx_packets = pstats->rx_frames;
+ ns->multicast = pstats->rx_mcast_frames;
+
+ ns->tx_errors = pstats->tx_underrun;
+ ns->rx_errors = pstats->rx_symbol_errs + pstats->rx_fcs_errs +
+ pstats->rx_too_long + pstats->rx_jabber + pstats->rx_short +
+ pstats->rx_fifo_ovfl;
+
+ /* detailed rx_errors */
+ ns->rx_length_errors = pstats->rx_jabber + pstats->rx_too_long;
+ ns->rx_over_errors = 0;
+ ns->rx_crc_errors = pstats->rx_fcs_errs;
+ ns->rx_frame_errors = pstats->rx_symbol_errs;
+ ns->rx_fifo_errors = pstats->rx_fifo_ovfl;
+ ns->rx_missed_errors = pstats->rx_cong_drops;
+
+ /* detailed tx_errors */
+ ns->tx_aborted_errors = 0;
+ ns->tx_carrier_errors = 0;
+ ns->tx_fifo_errors = pstats->tx_underrun;
+ ns->tx_heartbeat_errors = 0;
+ ns->tx_window_errors = 0;
+ return ns;
+}
+
+static u32 get_msglevel(struct net_device *dev)
+{
+ struct adapter *adapter = dev->priv;
+
+ return adapter->msg_enable;
+}
+
+static void set_msglevel(struct net_device *dev, u32 val)
+{
+ struct adapter *adapter = dev->priv;
+
+ adapter->msg_enable = val;
+}
+
+static char stats_strings[][ETH_GSTRING_LEN] = {
+ "TxOctetsOK ",
+ "TxFramesOK ",
+ "TxMulticastFramesOK",
+ "TxBroadcastFramesOK",
+ "TxPauseFrames ",
+ "TxUnderrun ",
+ "TxExtUnderrun ",
+
+ "TxFrames64 ",
+ "TxFrames65To127 ",
+ "TxFrames128To255 ",
+ "TxFrames256To511 ",
+ "TxFrames512To1023 ",
+ "TxFrames1024To1518 ",
+ "TxFrames1519ToMax ",
+
+ "RxOctetsOK ",
+ "RxFramesOK ",
+ "RxMulticastFramesOK",
+ "RxBroadcastFramesOK",
+ "RxPauseFrames ",
+ "RxFCSErrors ",
+ "RxSymbolErrors ",
+ "RxShortErrors ",
+ "RxJabberErrors ",
+ "RxLengthErrors ",
+ "RxFIFOoverflow ",
+
+ "RxFrames64 ",
+ "RxFrames65To127 ",
+ "RxFrames128To255 ",
+ "RxFrames256To511 ",
+ "RxFrames512To1023 ",
+ "RxFrames1024To1518 ",
+ "RxFrames1519ToMax ",
+
+ "PhyFIFOErrors ",
+ "TSO ",
+ "VLANextractions ",
+ "VLANinsertions ",
+ "TxCsumOffload ",
+ "RxCsumGood ",
+ "RxDrops "
+};
+
+static int get_stats_count(struct net_device *dev)
+{
+ return ARRAY_SIZE(stats_strings);
+}
+
+#define T3_REGMAP_SIZE (3 * 1024)
+
+static int get_regs_len(struct net_device *dev)
+{
+ return T3_REGMAP_SIZE;
+}
+
+static int get_eeprom_len(struct net_device *dev)
+{
+ return EEPROMSIZE;
+}
+
+static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+ u32 fw_vers = 0;
+ struct adapter *adapter = dev->priv;
+
+ t3_get_fw_version(adapter, &fw_vers);
+
+ strcpy(info->driver, DRV_NAME);
+ strcpy(info->version, DRV_VERSION);
+ strcpy(info->bus_info, pci_name(adapter->pdev));
+ if (!fw_vers)
+ strcpy(info->fw_version, "N/A");
+ else {
+ snprintf(info->fw_version, sizeof(info->fw_version),
+ "%s %u.%u.%u",
+ G_FW_VERSION_TYPE(fw_vers) ? "T" : "N",
+ G_FW_VERSION_MAJOR(fw_vers),
+ G_FW_VERSION_MINOR(fw_vers),
+ G_FW_VERSION_MICRO(fw_vers));
+ }
+}
+
+static void get_strings(struct net_device *dev, u32 stringset, u8 * data)
+{
+ if (stringset == ETH_SS_STATS)
+ memcpy(data, stats_strings, sizeof(stats_strings));
+}
+
+static unsigned long collect_sge_port_stats(struct adapter *adapter,
+ struct port_info *p, int idx)
+{
+ int i;
+ unsigned long tot = 0;
+
+ for (i = 0; i < p->nqsets; ++i)
+ tot += adapter->sge.qs[i + p->first_qset].port_stats[idx];
+ return tot;
+}
+
+static void get_stats(struct net_device *dev, struct ethtool_stats *stats,
+ u64 *data)
+{
+ struct adapter *adapter = dev->priv;
+ struct port_info *pi = netdev_priv(dev);
+ const struct mac_stats *s;
+
+ spin_lock(&adapter->stats_lock);
+ s = t3_mac_update_stats(&pi->mac);
+ spin_unlock(&adapter->stats_lock);
+
+ *data++ = s->tx_octets;
+ *data++ = s->tx_frames;
+ *data++ = s->tx_mcast_frames;
+ *data++ = s->tx_bcast_frames;
+ *data++ = s->tx_pause;
+ *data++ = s->tx_underrun;
+ *data++ = s->tx_fifo_urun;
+
+ *data++ = s->tx_frames_64;
+ *data++ = s->tx_frames_65_127;
+ *data++ = s->tx_frames_128_255;
+ *data++ = s->tx_frames_256_511;
+ *data++ = s->tx_frames_512_1023;
+ *data++ = s->tx_frames_1024_1518;
+ *data++ = s->tx_frames_1519_max;
+
+ *data++ = s->rx_octets;
+ *data++ = s->rx_frames;
+ *data++ = s->rx_mcast_frames;
+ *data++ = s->rx_bcast_frames;
+ *data++ = s->rx_pause;
+ *data++ = s->rx_fcs_errs;
+ *data++ = s->rx_symbol_errs;
+ *data++ = s->rx_short;
+ *data++ = s->rx_jabber;
+ *data++ = s->rx_too_long;
+ *data++ = s->rx_fifo_ovfl;
+
+ *data++ = s->rx_frames_64;
+ *data++ = s->rx_frames_65_127;
+ *data++ = s->rx_frames_128_255;
+ *data++ = s->rx_frames_256_511;
+ *data++ = s->rx_frames_512_1023;
+ *data++ = s->rx_frames_1024_1518;
+ *data++ = s->rx_frames_1519_max;
+
+ *data++ = pi->phy.fifo_errors;
+
+ *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_TSO);
+ *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_VLANEX);
+ *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_VLANINS);
+ *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_TX_CSUM);
+ *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_RX_CSUM_GOOD);
+ *data++ = s->rx_cong_drops;
+}
+
+static inline void reg_block_dump(struct adapter *ap, void *buf,
+ unsigned int start, unsigned int end)
+{
+ u32 *p = buf + start;
+
+ for (; start <= end; start += sizeof(u32))
+ *p++ = t3_read_reg(ap, start);
+}
+
+static void get_regs(struct net_device *dev, struct ethtool_regs *regs,
+ void *buf)
+{
+ struct adapter *ap = dev->priv;
+
+ /*
+ * Version scheme:
+ * bits 0..9: chip version
+ * bits 10..15: chip revision
+ * bit 31: set for PCIe cards
+ */
+ regs->version = 3 | (ap->params.rev << 10) | (is_pcie(ap) << 31);
+
+ /*
+ * We skip the MAC statistics registers because they are clear-on-read.
+ * Also reading multi-register stats would need to synchronize with the
+ * periodic mac stats accumulation. Hard to justify the complexity.
+ */
+ memset(buf, 0, T3_REGMAP_SIZE);
+ reg_block_dump(ap, buf, 0, A_SG_RSPQ_CREDIT_RETURN);
+ reg_block_dump(ap, buf, A_SG_HI_DRB_HI_THRSH, A_ULPRX_PBL_ULIMIT);
+ reg_block_dump(ap, buf, A_ULPTX_CONFIG, A_MPS_INT_CAUSE);
+ reg_block_dump(ap, buf, A_CPL_SWITCH_CNTRL, A_CPL_MAP_TBL_DATA);
+ reg_block_dump(ap, buf, A_SMB_GLOBAL_TIME_CFG, A_XGM_SERDES_STAT3);
+ reg_block_dump(ap, buf, A_XGM_SERDES_STATUS0,
+ XGM_REG(A_XGM_SERDES_STAT3, 1));
+ reg_block_dump(ap, buf, XGM_REG(A_XGM_SERDES_STATUS0, 1),
+ XGM_REG(A_XGM_RX_SPI4_SOP_EOP_CNT, 1));
+}
+
+static int restart_autoneg(struct net_device *dev)
+{
+ struct port_info *p = netdev_priv(dev);
+
+ if (!netif_running(dev))
+ return -EAGAIN;
+ if (p->link_config.autoneg != AUTONEG_ENABLE)
+ return -EINVAL;
+ p->phy.ops->autoneg_restart(&p->phy);
+ return 0;
+}
+
+static int cxgb3_phys_id(struct net_device *dev, u32 data)
+{
+ int i;
+ struct adapter *adapter = dev->priv;
+
+ if (data == 0)
+ data = 2;
+
+ for (i = 0; i < data * 2; i++) {
+ t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL,
+ (i & 1) ? F_GPIO0_OUT_VAL : 0);
+ if (msleep_interruptible(500))
+ break;
+ }
+ t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL,
+ F_GPIO0_OUT_VAL);
+ return 0;
+}
+
+static int get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct port_info *p = netdev_priv(dev);
+
+ cmd->supported = p->link_config.supported;
+ cmd->advertising = p->link_config.advertising;
+
+ if (netif_carrier_ok(dev)) {
+ cmd->speed = p->link_config.speed;
+ cmd->duplex = p->link_config.duplex;
+ } else {
+ cmd->speed = -1;
+ cmd->duplex = -1;
+ }
+
+ cmd->port = (cmd->supported & SUPPORTED_TP) ? PORT_TP : PORT_FIBRE;
+ cmd->phy_address = p->phy.addr;
+ cmd->transceiver = XCVR_EXTERNAL;
+ cmd->autoneg = p->link_config.autoneg;
+ cmd->maxtxpkt = 0;
+ cmd->maxrxpkt = 0;
+ return 0;
+}
+
+static int speed_duplex_to_caps(int speed, int duplex)
+{
+ int cap = 0;
+
+ switch (speed) {
+ case SPEED_10:
+ if (duplex == DUPLEX_FULL)
+ cap = SUPPORTED_10baseT_Full;
+ else
+ cap = SUPPORTED_10baseT_Half;
+ break;
+ case SPEED_100:
+ if (duplex == DUPLEX_FULL)
+ cap = SUPPORTED_100baseT_Full;
+ else
+ cap = SUPPORTED_100baseT_Half;
+ break;
+ case SPEED_1000:
+ if (duplex == DUPLEX_FULL)
+ cap = SUPPORTED_1000baseT_Full;
+ else
+ cap = SUPPORTED_1000baseT_Half;
+ break;
+ case SPEED_10000:
+ if (duplex == DUPLEX_FULL)
+ cap = SUPPORTED_10000baseT_Full;
+ }
+ return cap;
+}
+
+#define ADVERTISED_MASK (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | \
+ ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | \
+ ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full | \
+ ADVERTISED_10000baseT_Full)
+
+static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct port_info *p = netdev_priv(dev);
+ struct link_config *lc = &p->link_config;
+
+ if (!(lc->supported & SUPPORTED_Autoneg))
+ return -EOPNOTSUPP; /* can't change speed/duplex */
+
+ if (cmd->autoneg == AUTONEG_DISABLE) {
+ int cap = speed_duplex_to_caps(cmd->speed, cmd->duplex);
+
+ if (!(lc->supported & cap) || cmd->speed == SPEED_1000)
+ return -EINVAL;
+ lc->requested_speed = cmd->speed;
+ lc->requested_duplex = cmd->duplex;
+ lc->advertising = 0;
+ } else {
+ cmd->advertising &= ADVERTISED_MASK;
+ cmd->advertising &= lc->supported;
+ if (!cmd->advertising)
+ return -EINVAL;
+ lc->requested_speed = SPEED_INVALID;
+ lc->requested_duplex = DUPLEX_INVALID;
+ lc->advertising = cmd->advertising | ADVERTISED_Autoneg;
+ }
+ lc->autoneg = cmd->autoneg;
+ if (netif_running(dev))
+ t3_link_start(&p->phy, &p->mac, lc);
+ return 0;
+}
+
+static void get_pauseparam(struct net_device *dev,
+ struct ethtool_pauseparam *epause)
+{
+ struct port_info *p = netdev_priv(dev);
+
+ epause->autoneg = (p->link_config.requested_fc & PAUSE_AUTONEG) != 0;
+ epause->rx_pause = (p->link_config.fc & PAUSE_RX) != 0;
+ epause->tx_pause = (p->link_config.fc & PAUSE_TX) != 0;
+}
+
+static int set_pauseparam(struct net_device *dev,
+ struct ethtool_pauseparam *epause)
+{
+ struct port_info *p = netdev_priv(dev);
+ struct link_config *lc = &p->link_config;
+
+ if (epause->autoneg == AUTONEG_DISABLE)
+ lc->requested_fc = 0;
+ else if (lc->supported & SUPPORTED_Autoneg)
+ lc->requested_fc = PAUSE_AUTONEG;
+ else
+ return -EINVAL;
+
+ if (epause->rx_pause)
+ lc->requested_fc |= PAUSE_RX;
+ if (epause->tx_pause)
+ lc->requested_fc |= PAUSE_TX;
+ if (lc->autoneg == AUTONEG_ENABLE) {
+ if (netif_running(dev))
+ t3_link_start(&p->phy, &p->mac, lc);
+ } else {
+ lc->fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
+ if (netif_running(dev))
+ t3_mac_set_speed_duplex_fc(&p->mac, -1, -1, lc->fc);
+ }
+ return 0;
+}
+
+static u32 get_rx_csum(struct net_device *dev)
+{
+ struct port_info *p = netdev_priv(dev);
+
+ return p->rx_csum_offload;
+}
+
+static int set_rx_csum(struct net_device *dev, u32 data)
+{
+ struct port_info *p = netdev_priv(dev);
+
+ p->rx_csum_offload = data;
+ return 0;
+}
+
+static void get_sge_param(struct net_device *dev, struct ethtool_ringparam *e)
+{
+ struct adapter *adapter = dev->priv;
+
+ e->rx_max_pending = MAX_RX_BUFFERS;
+ e->rx_mini_max_pending = 0;
+ e->rx_jumbo_max_pending = MAX_RX_JUMBO_BUFFERS;
+ e->tx_max_pending = MAX_TXQ_ENTRIES;
+
+ e->rx_pending = adapter->params.sge.qset[0].fl_size;
+ e->rx_mini_pending = adapter->params.sge.qset[0].rspq_size;
+ e->rx_jumbo_pending = adapter->params.sge.qset[0].jumbo_size;
+ e->tx_pending = adapter->params.sge.qset[0].txq_size[0];
+}
+
+static int set_sge_param(struct net_device *dev, struct ethtool_ringparam *e)
+{
+ int i;
+ struct adapter *adapter = dev->priv;
+
+ if (e->rx_pending > MAX_RX_BUFFERS ||
+ e->rx_jumbo_pending > MAX_RX_JUMBO_BUFFERS ||
+ e->tx_pending > MAX_TXQ_ENTRIES ||
+ e->rx_mini_pending > MAX_RSPQ_ENTRIES ||
+ e->rx_mini_pending < MIN_RSPQ_ENTRIES ||
+ e->rx_pending < MIN_FL_ENTRIES ||
+ e->rx_jumbo_pending < MIN_FL_ENTRIES ||
+ e->tx_pending < adapter->params.nports * MIN_TXQ_ENTRIES)
+ return -EINVAL;
+
+ if (adapter->flags & FULL_INIT_DONE)
+ return -EBUSY;
+
+ for (i = 0; i < SGE_QSETS; ++i) {
+ struct qset_params *q = &adapter->params.sge.qset[i];
+
+ q->rspq_size = e->rx_mini_pending;
+ q->fl_size = e->rx_pending;
+ q->jumbo_size = e->rx_jumbo_pending;
+ q->txq_size[0] = e->tx_pending;
+ q->txq_size[1] = e->tx_pending;
+ q->txq_size[2] = e->tx_pending;
+ }
+ return 0;
+}
+
+static int set_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
+{
+ struct adapter *adapter = dev->priv;
+ struct qset_params *qsp = &adapter->params.sge.qset[0];
+ struct sge_qset *qs = &adapter->sge.qs[0];
+
+ if (c->rx_coalesce_usecs * 10 > M_NEWTIMER)
+ return -EINVAL;
+
+ qsp->coalesce_usecs = c->rx_coalesce_usecs;
+ t3_update_qset_coalesce(qs, qsp);
+ return 0;
+}
+
+static int get_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
+{
+ struct adapter *adapter = dev->priv;
+ struct qset_params *q = adapter->params.sge.qset;
+
+ c->rx_coalesce_usecs = q->coalesce_usecs;
+ return 0;
+}
+
+static int get_eeprom(struct net_device *dev, struct ethtool_eeprom *e,
+ u8 * data)
+{
+ int i, err = 0;
+ struct adapter *adapter = dev->priv;
+
+ u8 *buf = kmalloc(EEPROMSIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ e->magic = EEPROM_MAGIC;
+ for (i = e->offset & ~3; !err && i < e->offset + e->len; i += 4)
+ err = t3_seeprom_read(adapter, i, (u32 *) & buf[i]);
+
+ if (!err)
+ memcpy(data, buf + e->offset, e->len);
+ kfree(buf);
+ return err;
+}
+
+static int set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
+ u8 * data)
+{
+ u8 *buf;
+ int err = 0;
+ u32 aligned_offset, aligned_len, *p;
+ struct adapter *adapter = dev->priv;
+
+ if (eeprom->magic != EEPROM_MAGIC)
+ return -EINVAL;
+
+ aligned_offset = eeprom->offset & ~3;
+ aligned_len = (eeprom->len + (eeprom->offset & 3) + 3) & ~3;
+
+ if (aligned_offset != eeprom->offset || aligned_len != eeprom->len) {
+ buf = kmalloc(aligned_len, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+ err = t3_seeprom_read(adapter, aligned_offset, (u32 *) buf);
+ if (!err && aligned_len > 4)
+ err = t3_seeprom_read(adapter,
+ aligned_offset + aligned_len - 4,
+ (u32 *) & buf[aligned_len - 4]);
+ if (err)
+ goto out;
+ memcpy(buf + (eeprom->offset & 3), data, eeprom->len);
+ } else
+ buf = data;
+
+ err = t3_seeprom_wp(adapter, 0);
+ if (err)
+ goto out;
+
+ for (p = (u32 *) buf; !err && aligned_len; aligned_len -= 4, p++) {
+ err = t3_seeprom_write(adapter, aligned_offset, *p);
+ aligned_offset += 4;
+ }
+
+ if (!err)
+ err = t3_seeprom_wp(adapter, 1);
+out:
+ if (buf != data)
+ kfree(buf);
+ return err;
+}
+
+static void get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+ wol->supported = 0;
+ wol->wolopts = 0;
+ memset(&wol->sopass, 0, sizeof(wol->sopass));
+}
+
+static const struct ethtool_ops cxgb_ethtool_ops = {
+ .get_settings = get_settings,
+ .set_settings = set_settings,
+ .get_drvinfo = get_drvinfo,
+ .get_msglevel = get_msglevel,
+ .set_msglevel = set_msglevel,
+ .get_ringparam = get_sge_param,
+ .set_ringparam = set_sge_param,
+ .get_coalesce = get_coalesce,
+ .set_coalesce = set_coalesce,
+ .get_eeprom_len = get_eeprom_len,
+ .get_eeprom = get_eeprom,
+ .set_eeprom = set_eeprom,
+ .get_pauseparam = get_pauseparam,
+ .set_pauseparam = set_pauseparam,
+ .get_rx_csum = get_rx_csum,
+ .set_rx_csum = 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,
+ .get_link = ethtool_op_get_link,
+ .get_strings = get_strings,
+ .phys_id = cxgb3_phys_id,
+ .nway_reset = restart_autoneg,
+ .get_stats_count = get_stats_count,
+ .get_ethtool_stats = get_stats,
+ .get_regs_len = get_regs_len,
+ .get_regs = get_regs,
+ .get_wol = get_wol,
+ .get_tso = ethtool_op_get_tso,
+ .set_tso = ethtool_op_set_tso,
+ .get_perm_addr = ethtool_op_get_perm_addr
+};
+
+static int in_range(int val, int lo, int hi)
+{
+ return val < 0 || (val <= hi && val >= lo);
+}
+
+static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
+{
+ int ret;
+ u32 cmd;
+ struct adapter *adapter = dev->priv;
+
+ if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
+ return -EFAULT;
+
+ switch (cmd) {
+ case CHELSIO_SETREG:{
+ struct ch_reg edata;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (copy_from_user(&edata, useraddr, sizeof(edata)))
+ return -EFAULT;
+ if ((edata.addr & 3) != 0
+ || edata.addr >= adapter->mmio_len)
+ return -EINVAL;
+ writel(edata.val, adapter->regs + edata.addr);
+ break;
+ }
+ case CHELSIO_GETREG:{
+ struct ch_reg edata;
+
+ if (copy_from_user(&edata, useraddr, sizeof(edata)))
+ return -EFAULT;
+ if ((edata.addr & 3) != 0
+ || edata.addr >= adapter->mmio_len)
+ return -EINVAL;
+ edata.val = readl(adapter->regs + edata.addr);
+ if (copy_to_user(useraddr, &edata, sizeof(edata)))
+ return -EFAULT;
+ break;
+ }
+ case CHELSIO_SET_QSET_PARAMS:{
+ int i;
+ struct qset_params *q;
+ struct ch_qset_params t;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (copy_from_user(&t, useraddr, sizeof(t)))
+ return -EFAULT;
+ if (t.qset_idx >= SGE_QSETS)
+ return -EINVAL;
+ if (!in_range(t.intr_lat, 0, M_NEWTIMER) ||
+ !in_range(t.cong_thres, 0, 255) ||
+ !in_range(t.txq_size[0], MIN_TXQ_ENTRIES,
+ MAX_TXQ_ENTRIES) ||
+ !in_range(t.txq_size[1], MIN_TXQ_ENTRIES,
+ MAX_TXQ_ENTRIES) ||
+ !in_range(t.txq_size[2], MIN_CTRL_TXQ_ENTRIES,
+ MAX_CTRL_TXQ_ENTRIES) ||
+ !in_range(t.fl_size[0], MIN_FL_ENTRIES,
+ MAX_RX_BUFFERS)
+ || !in_range(t.fl_size[1], MIN_FL_ENTRIES,
+ MAX_RX_JUMBO_BUFFERS)
+ || !in_range(t.rspq_size, MIN_RSPQ_ENTRIES,
+ MAX_RSPQ_ENTRIES))
+ return -EINVAL;
+ if ((adapter->flags & FULL_INIT_DONE) &&
+ (t.rspq_size >= 0 || t.fl_size[0] >= 0 ||
+ t.fl_size[1] >= 0 || t.txq_size[0] >= 0 ||
+ t.txq_size[1] >= 0 || t.txq_size[2] >= 0 ||
+ t.polling >= 0 || t.cong_thres >= 0))
+ return -EBUSY;
+
+ q = &adapter->params.sge.qset[t.qset_idx];
+
+ if (t.rspq_size >= 0)
+ q->rspq_size = t.rspq_size;
+ if (t.fl_size[0] >= 0)
+ q->fl_size = t.fl_size[0];
+ if (t.fl_size[1] >= 0)
+ q->jumbo_size = t.fl_size[1];
+ if (t.txq_size[0] >= 0)
+ q->txq_size[0] = t.txq_size[0];
+ if (t.txq_size[1] >= 0)
+ q->txq_size[1] = t.txq_size[1];
+ if (t.txq_size[2] >= 0)
+ q->txq_size[2] = t.txq_size[2];
+ if (t.cong_thres >= 0)
+ q->cong_thres = t.cong_thres;
+ if (t.intr_lat >= 0) {
+ struct sge_qset *qs =
+ &adapter->sge.qs[t.qset_idx];
+
+ q->coalesce_usecs = t.intr_lat;
+ t3_update_qset_coalesce(qs, q);
+ }
+ if (t.polling >= 0) {
+ if (adapter->flags & USING_MSIX)
+ q->polling = t.polling;
+ else {
+ /* No polling with INTx for T3A */
+ if (adapter->params.rev == 0 &&
+ !(adapter->flags & USING_MSI))
+ t.polling = 0;
+
+ for (i = 0; i < SGE_QSETS; i++) {
+ q = &adapter->params.sge.
+ qset[i];
+ q->polling = t.polling;
+ }
+ }
+ }
+ break;
+ }
+ case CHELSIO_GET_QSET_PARAMS:{
+ struct qset_params *q;
+ struct ch_qset_params t;
+
+ if (copy_from_user(&t, useraddr, sizeof(t)))
+ return -EFAULT;
+ if (t.qset_idx >= SGE_QSETS)
+ return -EINVAL;
+
+ q = &adapter->params.sge.qset[t.qset_idx];
+ t.rspq_size = q->rspq_size;
+ t.txq_size[0] = q->txq_size[0];
+ t.txq_size[1] = q->txq_size[1];
+ t.txq_size[2] = q->txq_size[2];
+ t.fl_size[0] = q->fl_size;
+ t.fl_size[1] = q->jumbo_size;
+ t.polling = q->polling;
+ t.intr_lat = q->coalesce_usecs;
+ t.cong_thres = q->cong_thres;
+
+ if (copy_to_user(useraddr, &t, sizeof(t)))
+ return -EFAULT;
+ break;
+ }
+ case CHELSIO_SET_QSET_NUM:{
+ struct ch_reg edata;
+ struct port_info *pi = netdev_priv(dev);
+ unsigned int i, first_qset = 0, other_qsets = 0;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (adapter->flags & FULL_INIT_DONE)
+ return -EBUSY;
+ if (copy_from_user(&edata, useraddr, sizeof(edata)))
+ return -EFAULT;
+ if (edata.val < 1 ||
+ (edata.val > 1 && !(adapter->flags & USING_MSIX)))
+ return -EINVAL;
+
+ for_each_port(adapter, i)
+ if (adapter->port[i] && adapter->port[i] != dev)
+ other_qsets += adap2pinfo(adapter, i)->nqsets;
+
+ if (edata.val + other_qsets > SGE_QSETS)
+ return -EINVAL;
+
+ pi->nqsets = edata.val;
+
+ for_each_port(adapter, i)
+ if (adapter->port[i]) {
+ pi = adap2pinfo(adapter, i);
+ pi->first_qset = first_qset;
+ first_qset += pi->nqsets;
+ }
+ break;
+ }
+ case CHELSIO_GET_QSET_NUM:{
+ struct ch_reg edata;
+ struct port_info *pi = netdev_priv(dev);
+
+ edata.cmd = CHELSIO_GET_QSET_NUM;
+ edata.val = pi->nqsets;
+ if (copy_to_user(useraddr, &edata, sizeof(edata)))
+ return -EFAULT;
+ break;
+ }
+ case CHELSIO_LOAD_FW:{
+ u8 *fw_data;
+ struct ch_mem_range t;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (copy_from_user(&t, useraddr, sizeof(t)))
+ return -EFAULT;
+
+ fw_data = kmalloc(t.len, GFP_KERNEL);
+ if (!fw_data)
+ return -ENOMEM;
+
+ if (copy_from_user
+ (fw_data, useraddr + sizeof(t), t.len)) {
+ kfree(fw_data);
+ return -EFAULT;
+ }
+
+ ret = t3_load_fw(adapter, fw_data, t.len);
+ kfree(fw_data);
+ if (ret)
+ return ret;
+ break;
+ }
+ case CHELSIO_SETMTUTAB:{
+ struct ch_mtus m;
+ int i;
+
+ if (!is_offload(adapter))
+ return -EOPNOTSUPP;
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (offload_running(adapter))
+ return -EBUSY;
+ if (copy_from_user(&m, useraddr, sizeof(m)))
+ return -EFAULT;
+ if (m.nmtus != NMTUS)
+ return -EINVAL;
+ if (m.mtus[0] < 81) /* accommodate SACK */
+ return -EINVAL;
+
+ /* MTUs must be in ascending order */
+ for (i = 1; i < NMTUS; ++i)
+ if (m.mtus[i] < m.mtus[i - 1])
+ return -EINVAL;
+
+ memcpy(adapter->params.mtus, m.mtus,
+ sizeof(adapter->params.mtus));
+ break;
+ }
+ case CHELSIO_GET_PM:{
+ struct tp_params *p = &adapter->params.tp;
+ struct ch_pm m = {.cmd = CHELSIO_GET_PM };
+
+ if (!is_offload(adapter))
+ return -EOPNOTSUPP;
+ m.tx_pg_sz = p->tx_pg_size;
+ m.tx_num_pg = p->tx_num_pgs;
+ m.rx_pg_sz = p->rx_pg_size;
+ m.rx_num_pg = p->rx_num_pgs;
+ m.pm_total = p->pmtx_size + p->chan_rx_size * p->nchan;
+ if (copy_to_user(useraddr, &m, sizeof(m)))
+ return -EFAULT;
+ break;
+ }
+ case CHELSIO_SET_PM:{
+ struct ch_pm m;
+ struct tp_params *p = &adapter->params.tp;
+
+ if (!is_offload(adapter))
+ return -EOPNOTSUPP;
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (adapter->flags & FULL_INIT_DONE)
+ return -EBUSY;
+ if (copy_from_user(&m, useraddr, sizeof(m)))
+ return -EFAULT;
+ if (!m.rx_pg_sz || (m.rx_pg_sz & (m.rx_pg_sz - 1)) ||
+ !m.tx_pg_sz || (m.tx_pg_sz & (m.tx_pg_sz - 1)))
+ return -EINVAL; /* not power of 2 */
+ if (!(m.rx_pg_sz & 0x14000))
+ return -EINVAL; /* not 16KB or 64KB */
+ if (!(m.tx_pg_sz & 0x1554000))
+ return -EINVAL;
+ if (m.tx_num_pg == -1)
+ m.tx_num_pg = p->tx_num_pgs;
+ if (m.rx_num_pg == -1)
+ m.rx_num_pg = p->rx_num_pgs;
+ if (m.tx_num_pg % 24 || m.rx_num_pg % 24)
+ return -EINVAL;
+ if (m.rx_num_pg * m.rx_pg_sz > p->chan_rx_size ||
+ m.tx_num_pg * m.tx_pg_sz > p->chan_tx_size)
+ return -EINVAL;
+ p->rx_pg_size = m.rx_pg_sz;
+ p->tx_pg_size = m.tx_pg_sz;
+ p->rx_num_pgs = m.rx_num_pg;
+ p->tx_num_pgs = m.tx_num_pg;
+ break;
+ }
+ case CHELSIO_GET_MEM:{
+ struct ch_mem_range t;
+ struct mc7 *mem;
+ u64 buf[32];
+
+ if (!is_offload(adapter))
+ return -EOPNOTSUPP;
+ if (!(adapter->flags & FULL_INIT_DONE))
+ return -EIO; /* need the memory controllers */
+ if (copy_from_user(&t, useraddr, sizeof(t)))
+ return -EFAULT;
+ if ((t.addr & 7) || (t.len & 7))
+ return -EINVAL;
+ if (t.mem_id == MEM_CM)
+ mem = &adapter->cm;
+ else if (t.mem_id == MEM_PMRX)
+ mem = &adapter->pmrx;
+ else if (t.mem_id == MEM_PMTX)
+ mem = &adapter->pmtx;
+ else
+ return -EINVAL;
+
+ /*
+ * Version scheme:
+ * bits 0..9: chip version
+ * bits 10..15: chip revision
+ */
+ t.version = 3 | (adapter->params.rev << 10);
+ if (copy_to_user(useraddr, &t, sizeof(t)))
+ return -EFAULT;
+
+ /*
+ * Read 256 bytes at a time as len can be large and we don't
+ * want to use huge intermediate buffers.
+ */
+ useraddr += sizeof(t); /* advance to start of buffer */
+ while (t.len) {
+ unsigned int chunk =
+ min_t(unsigned int, t.len, sizeof(buf));
+
+ ret =
+ t3_mc7_bd_read(mem, t.addr / 8, chunk / 8,
+ buf);
+ if (ret)
+ return ret;
+ if (copy_to_user(useraddr, buf, chunk))
+ return -EFAULT;
+ useraddr += chunk;
+ t.addr += chunk;
+ t.len -= chunk;
+ }
+ break;
+ }
+ case CHELSIO_SET_TRACE_FILTER:{
+ struct ch_trace t;
+ const struct trace_params *tp;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (!offload_running(adapter))
+ return -EAGAIN;
+ if (copy_from_user(&t, useraddr, sizeof(t)))
+ return -EFAULT;
+
+ tp = (const struct trace_params *)&t.sip;
+ if (t.config_tx)
+ t3_config_trace_filter(adapter, tp, 0,
+ t.invert_match,
+ t.trace_tx);
+ if (t.config_rx)
+ t3_config_trace_filter(adapter, tp, 1,
+ t.invert_match,
+ t.trace_rx);
+ break;
+ }
+ case CHELSIO_SET_PKTSCHED:{
+ struct ch_pktsched_params p;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (!adapter->open_device_map)
+ return -EAGAIN; /* uP and SGE must be running */
+ if (copy_from_user(&p, useraddr, sizeof(p)))
+ return -EFAULT;
+ send_pktsched_cmd(adapter, p.sched, p.idx, p.min, p.max,
+ p.binding);
+ break;
+
+ }
+ default:
+ return -EOPNOTSUPP;
+ }
+ return 0;
+}
+
+static int cxgb_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
+{
+ int ret, mmd;
+ struct adapter *adapter = dev->priv;
+ struct port_info *pi = netdev_priv(dev);
+ struct mii_ioctl_data *data = if_mii(req);
+
+ switch (cmd) {
+ case SIOCGMIIPHY:
+ data->phy_id = pi->phy.addr;
+ /* FALLTHRU */
+ case SIOCGMIIREG:{
+ u32 val;
+ struct cphy *phy = &pi->phy;
+
+ if (!phy->mdio_read)
+ return -EOPNOTSUPP;
+ if (is_10G(adapter)) {
+ mmd = data->phy_id >> 8;
+ if (!mmd)
+ mmd = MDIO_DEV_PCS;
+ else if (mmd > MDIO_DEV_XGXS)
+ return -EINVAL;
+
+ ret =
+ phy->mdio_read(adapter, data->phy_id & 0x1f,
+ mmd, data->reg_num, &val);
+ } else
+ ret =
+ phy->mdio_read(adapter, data->phy_id & 0x1f,
+ 0, data->reg_num & 0x1f,
+ &val);
+ if (!ret)
+ data->val_out = val;
+ break;
+ }
+ case SIOCSMIIREG:{
+ struct cphy *phy = &pi->phy;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (!phy->mdio_write)
+ return -EOPNOTSUPP;
+ if (is_10G(adapter)) {
+ mmd = data->phy_id >> 8;
+ if (!mmd)
+ mmd = MDIO_DEV_PCS;
+ else if (mmd > MDIO_DEV_XGXS)
+ return -EINVAL;
+
+ ret =
+ phy->mdio_write(adapter,
+ data->phy_id & 0x1f, mmd,
+ data->reg_num,
+ data->val_in);
+ } else
+ ret =
+ phy->mdio_write(adapter,
+ data->phy_id & 0x1f, 0,
+ data->reg_num & 0x1f,
+ data->val_in);
+ break;
+ }
+ case SIOCCHIOCTL:
+ return cxgb_extension_ioctl(dev, req->ifr_data);
+ default:
+ return -EOPNOTSUPP;
+ }
+ return ret;
+}
+
+static int cxgb_change_mtu(struct net_device *dev, int new_mtu)
+{
+ int ret;
+ struct adapter *adapter = dev->priv;
+ struct port_info *pi = netdev_priv(dev);
+
+ if (new_mtu < 81) /* accommodate SACK */
+ return -EINVAL;
+ if ((ret = t3_mac_set_mtu(&pi->mac, new_mtu)))
+ return ret;
+ dev->mtu = new_mtu;
+ init_port_mtus(adapter);
+ if (adapter->params.rev == 0 && offload_running(adapter))
+ t3_load_mtus(adapter, adapter->params.mtus,
+ adapter->params.a_wnd, adapter->params.b_wnd,
+ adapter->port[0]->mtu);
+ return 0;
+}
+
+static int cxgb_set_mac_addr(struct net_device *dev, void *p)
+{
+ struct adapter *adapter = dev->priv;
+ struct port_info *pi = netdev_priv(dev);
+ struct sockaddr *addr = p;
+
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EINVAL;
+
+ memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+ t3_mac_set_address(&pi->mac, 0, dev->dev_addr);
+ if (offload_running(adapter))
+ write_smt_entry(adapter, pi->port_id);
+ return 0;
+}
+
+/**
+ * t3_synchronize_rx - wait for current Rx processing on a port to complete
+ * @adap: the adapter
+ * @p: the port
+ *
+ * Ensures that current Rx processing on any of the queues associated with
+ * the given port completes before returning. We do this by acquiring and
+ * releasing the locks of the response queues associated with the port.
+ */
+static void t3_synchronize_rx(struct adapter *adap, const struct port_info *p)
+{
+ int i;
+
+ for (i = 0; i < p->nqsets; i++) {
+ struct sge_rspq *q = &adap->sge.qs[i + p->first_qset].rspq;
+
+ spin_lock_irq(&q->lock);
+ spin_unlock_irq(&q->lock);
+ }
+}
+
+static void vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
+{
+ struct adapter *adapter = dev->priv;
+ struct port_info *pi = netdev_priv(dev);
+
+ pi->vlan_grp = grp;
+ if (adapter->params.rev > 0)
+ t3_set_vlan_accel(adapter, 1 << pi->port_id, grp != NULL);
+ else {
+ /* single control for all ports */
+ unsigned int i, have_vlans = 0;
+ for_each_port(adapter, i)
+ have_vlans |= adap2pinfo(adapter, i)->vlan_grp != NULL;
+
+ t3_set_vlan_accel(adapter, 1, have_vlans);
+ }
+ t3_synchronize_rx(adapter, pi);
+}
+
+static void vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
+{
+ /* nothing */
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void cxgb_netpoll(struct net_device *dev)
+{
+ struct adapter *adapter = dev->priv;
+ struct sge_qset *qs = dev2qset(dev);
+
+ t3_intr_handler(adapter, qs->rspq.polling) (adapter->pdev->irq,
+ adapter);
+}
+#endif
+
+/*
+ * Periodic accumulation of MAC statistics.
+ */
+static void mac_stats_update(struct adapter *adapter)
+{
+ int i;
+
+ for_each_port(adapter, i) {
+ struct net_device *dev = adapter->port[i];
+ struct port_info *p = netdev_priv(dev);
+
+ if (netif_running(dev)) {
+ spin_lock(&adapter->stats_lock);
+ t3_mac_update_stats(&p->mac);
+ spin_unlock(&adapter->stats_lock);
+ }
+ }
+}
+
+static void check_link_status(struct adapter *adapter)
+{
+ int i;
+
+ for_each_port(adapter, i) {
+ struct net_device *dev = adapter->port[i];
+ struct port_info *p = netdev_priv(dev);
+
+ if (!(p->port_type->caps & SUPPORTED_IRQ) && netif_running(dev))
+ t3_link_changed(adapter, i);
+ }
+}
+
+static void t3_adap_check_task(struct work_struct *work)
+{
+ struct adapter *adapter = container_of(work, struct adapter,
+ adap_check_task.work);
+ const struct adapter_params *p = &adapter->params;
+
+ adapter->check_task_cnt++;
+
+ /* Check link status for PHYs without interrupts */
+ if (p->linkpoll_period)
+ check_link_status(adapter);
+
+ /* Accumulate MAC stats if needed */
+ if (!p->linkpoll_period ||
+ (adapter->check_task_cnt * p->linkpoll_period) / 10 >=
+ p->stats_update_period) {
+ mac_stats_update(adapter);
+ adapter->check_task_cnt = 0;
+ }
+
+ /* Schedule the next check update if any port is active. */
+ spin_lock(&adapter->work_lock);
+ if (adapter->open_device_map & PORT_MASK)
+ schedule_chk_task(adapter);
+ spin_unlock(&adapter->work_lock);
+}
+
+/*
+ * Processes external (PHY) interrupts in process context.
+ */
+static void ext_intr_task(struct work_struct *work)
+{
+ struct adapter *adapter = container_of(work, struct adapter,
+ ext_intr_handler_task);
+
+ t3_phy_intr_handler(adapter);
+
+ /* Now reenable external interrupts */
+ spin_lock_irq(&adapter->work_lock);
+ if (adapter->slow_intr_mask) {
+ adapter->slow_intr_mask |= F_T3DBG;
+ t3_write_reg(adapter, A_PL_INT_CAUSE0, F_T3DBG);
+ t3_write_reg(adapter, A_PL_INT_ENABLE0,
+ adapter->slow_intr_mask);
+ }
+ spin_unlock_irq(&adapter->work_lock);
+}
+
+/*
+ * Interrupt-context handler for external (PHY) interrupts.
+ */
+void t3_os_ext_intr_handler(struct adapter *adapter)
+{
+ /*
+ * Schedule a task to handle external interrupts as they may be slow
+ * and we use a mutex to protect MDIO registers. We disable PHY
+ * interrupts in the meantime and let the task reenable them when
+ * it's done.
+ */
+ spin_lock(&adapter->work_lock);
+ if (adapter->slow_intr_mask) {
+ adapter->slow_intr_mask &= ~F_T3DBG;
+ t3_write_reg(adapter, A_PL_INT_ENABLE0,
+ adapter->slow_intr_mask);
+ queue_work(cxgb3_wq, &adapter->ext_intr_handler_task);
+ }
+ spin_unlock(&adapter->work_lock);
+}
+
+void t3_fatal_err(struct adapter *adapter)
+{
+ unsigned int fw_status[4];
+
+ if (adapter->flags & FULL_INIT_DONE) {
+ t3_sge_stop(adapter);
+ t3_intr_disable(adapter);
+ }
+ CH_ALERT(adapter, "encountered fatal error, operation suspended\n");
+ if (!t3_cim_ctl_blk_read(adapter, 0xa0, 4, fw_status))
+ CH_ALERT(adapter, "FW status: 0x%x, 0x%x, 0x%x, 0x%x\n",
+ fw_status[0], fw_status[1],
+ fw_status[2], fw_status[3]);
+
+}
+
+static int __devinit cxgb_enable_msix(struct adapter *adap)
+{
+ struct msix_entry entries[SGE_QSETS + 1];
+ int i, err;
+
+ for (i = 0; i < ARRAY_SIZE(entries); ++i)
+ entries[i].entry = i;
+
+ err = pci_enable_msix(adap->pdev, entries, ARRAY_SIZE(entries));
+ if (!err) {
+ for (i = 0; i < ARRAY_SIZE(entries); ++i)
+ adap->msix_info[i].vec = entries[i].vector;
+ } else if (err > 0)
+ dev_info(&adap->pdev->dev,
+ "only %d MSI-X vectors left, not using MSI-X\n", err);
+ return err;
+}
+
+static void __devinit print_port_info(struct adapter *adap,
+ const struct adapter_info *ai)
+{
+ static const char *pci_variant[] = {
+ "PCI", "PCI-X", "PCI-X ECC", "PCI-X 266", "PCI Express"
+ };
+
+ int i;
+ char buf[80];
+
+ if (is_pcie(adap))
+ snprintf(buf, sizeof(buf), "%s x%d",
+ pci_variant[adap->params.pci.variant],
+ adap->params.pci.width);
+ else
+ snprintf(buf, sizeof(buf), "%s %dMHz/%d-bit",
+ pci_variant[adap->params.pci.variant],
+ adap->params.pci.speed, adap->params.pci.width);
+
+ for_each_port(adap, i) {
+ struct net_device *dev = adap->port[i];
+ const struct port_info *pi = netdev_priv(dev);
+
+ if (!test_bit(i, &adap->registered_device_map))
+ continue;
+ printk(KERN_INFO "%s: %s %s RNIC (rev %d) %s%s\n",
+ dev->name, ai->desc, pi->port_type->desc,
+ adap->params.rev, buf,
+ (adap->flags & USING_MSIX) ? " MSI-X" :
+ (adap->flags & USING_MSI) ? " MSI" : "");
+ if (adap->name == dev->name && adap->params.vpd.mclk)
+ printk(KERN_INFO "%s: %uMB CM, %uMB PMTX, %uMB PMRX\n",
+ adap->name, t3_mc7_size(&adap->cm) >> 20,
+ t3_mc7_size(&adap->pmtx) >> 20,
+ t3_mc7_size(&adap->pmrx) >> 20);
+ }
+}
+
+static int __devinit init_one(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ static int version_printed;
+
+ int i, err, pci_using_dac = 0;
+ unsigned long mmio_start, mmio_len;
+ const struct adapter_info *ai;
+ struct adapter *adapter = NULL;
+ struct port_info *pi;
+
+ if (!version_printed) {
+ printk(KERN_INFO "%s - version %s\n", DRV_DESC, DRV_VERSION);
+ ++version_printed;
+ }
+
+ if (!cxgb3_wq) {
+ cxgb3_wq = create_singlethread_workqueue(DRV_NAME);
+ if (!cxgb3_wq) {
+ printk(KERN_ERR DRV_NAME
+ ": cannot initialize work queue\n");
+ return -ENOMEM;
+ }
+ }
+
+ err = pci_request_regions(pdev, DRV_NAME);
+ if (err) {
+ /* Just info, some other driver may have claimed the device. */
+ dev_info(&pdev->dev, "cannot obtain PCI resources\n");
+ return err;
+ }
+
+ err = pci_enable_device(pdev);
+ if (err) {
+ dev_err(&pdev->dev, "cannot enable PCI device\n");
+ goto out_release_regions;
+ }
+
+ if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
+ pci_using_dac = 1;
+ err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
+ if (err) {
+ dev_err(&pdev->dev, "unable to obtain 64-bit DMA for "
+ "coherent allocations\n");
+ goto out_disable_device;
+ }
+ } else if ((err = pci_set_dma_mask(pdev, DMA_32BIT_MASK)) != 0) {
+ dev_err(&pdev->dev, "no usable DMA configuration\n");
+ goto out_disable_device;
+ }
+
+ pci_set_master(pdev);
+
+ mmio_start = pci_resource_start(pdev, 0);
+ mmio_len = pci_resource_len(pdev, 0);
+ ai = t3_get_adapter_info(ent->driver_data);
+
+ adapter = kzalloc(sizeof(*adapter), GFP_KERNEL);
+ if (!adapter) {
+ err = -ENOMEM;
+ goto out_disable_device;
+ }
+
+ adapter->regs = ioremap_nocache(mmio_start, mmio_len);
+ if (!adapter->regs) {
+ dev_err(&pdev->dev, "cannot map device registers\n");
+ err = -ENOMEM;
+ goto out_free_adapter;
+ }
+
+ adapter->pdev = pdev;
+ adapter->name = pci_name(pdev);
+ adapter->msg_enable = dflt_msg_enable;
+ adapter->mmio_len = mmio_len;
+
+ mutex_init(&adapter->mdio_lock);
+ spin_lock_init(&adapter->work_lock);
+ spin_lock_init(&adapter->stats_lock);
+
+ INIT_LIST_HEAD(&adapter->adapter_list);
+ INIT_WORK(&adapter->ext_intr_handler_task, ext_intr_task);
+ INIT_DELAYED_WORK(&adapter->adap_check_task, t3_adap_check_task);
+
+ for (i = 0; i < ai->nports; ++i) {
+ struct net_device *netdev;
+
+ netdev = alloc_etherdev(sizeof(struct port_info));
+ if (!netdev) {
+ err = -ENOMEM;
+ goto out_free_dev;
+ }
+
+ SET_MODULE_OWNER(netdev);
+ SET_NETDEV_DEV(netdev, &pdev->dev);
+
+ adapter->port[i] = netdev;
+ pi = netdev_priv(netdev);
+ pi->rx_csum_offload = 1;
+ pi->nqsets = 1;
+ pi->first_qset = i;
+ pi->activity = 0;
+ pi->port_id = i;
+ netif_carrier_off(netdev);
+ netdev->irq = pdev->irq;
+ netdev->mem_start = mmio_start;
+ netdev->mem_end = mmio_start + mmio_len - 1;
+ netdev->priv = adapter;
+ netdev->features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO;
+ netdev->features |= NETIF_F_LLTX;
+ if (pci_using_dac)
+ netdev->features |= NETIF_F_HIGHDMA;
+
+ netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+ netdev->vlan_rx_register = vlan_rx_register;
+ netdev->vlan_rx_kill_vid = vlan_rx_kill_vid;
+
+ netdev->open = cxgb_open;
+ netdev->stop = cxgb_close;
+ netdev->hard_start_xmit = t3_eth_xmit;
+ netdev->get_stats = cxgb_get_stats;
+ netdev->set_multicast_list = cxgb_set_rxmode;
+ netdev->do_ioctl = cxgb_ioctl;
+ netdev->change_mtu = cxgb_change_mtu;
+ netdev->set_mac_address = cxgb_set_mac_addr;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ netdev->poll_controller = cxgb_netpoll;
+#endif
+ netdev->weight = 64;
+
+ SET_ETHTOOL_OPS(netdev, &cxgb_ethtool_ops);
+ }
+
+ pci_set_drvdata(pdev, adapter->port[0]);
+ if (t3_prep_adapter(adapter, ai, 1) < 0) {
+ err = -ENODEV;
+ goto out_free_dev;
+ }
+
+ /*
+ * The card is now ready to go. If any errors occur during device
+ * registration we do not fail the whole card but rather proceed only
+ * with the ports we manage to register successfully. However we must
+ * register at least one net device.
+ */
+ for_each_port(adapter, i) {
+ err = register_netdev(adapter->port[i]);
+ if (err)
+ dev_warn(&pdev->dev,
+ "cannot register net device %s, skipping\n",
+ adapter->port[i]->name);
+ else {
+ /*
+ * Change the name we use for messages to the name of
+ * the first successfully registered interface.
+ */
+ if (!adapter->registered_device_map)
+ adapter->name = adapter->port[i]->name;
+
+ __set_bit(i, &adapter->registered_device_map);
+ }
+ }
+ if (!adapter->registered_device_map) {
+ dev_err(&pdev->dev, "could not register any net devices\n");
+ goto out_free_dev;
+ }
+
+ /* Driver's ready. Reflect it on LEDs */
+ t3_led_ready(adapter);
+
+ if (is_offload(adapter)) {
+ __set_bit(OFFLOAD_DEVMAP_BIT, &adapter->registered_device_map);
+ cxgb3_adapter_ofld(adapter);
+ }
+
+ /* See what interrupts we'll be using */
+ if (msi > 1 && cxgb_enable_msix(adapter) == 0)
+ adapter->flags |= USING_MSIX;
+ else if (msi > 0 && pci_enable_msi(pdev) == 0)
+ adapter->flags |= USING_MSI;
+
+ err = sysfs_create_group(&adapter->port[0]->dev.kobj,
+ &cxgb3_attr_group);
+
+ print_port_info(adapter, ai);
+ return 0;
+
+out_free_dev:
+ iounmap(adapter->regs);
+ for (i = ai->nports - 1; i >= 0; --i)
+ if (adapter->port[i])
+ free_netdev(adapter->port[i]);
+
+out_free_adapter:
+ kfree(adapter);
+
+out_disable_device:
+ pci_disable_device(pdev);
+out_release_regions:
+ pci_release_regions(pdev);
+ pci_set_drvdata(pdev, NULL);
+ return err;
+}
+
+static void __devexit remove_one(struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+
+ if (dev) {
+ int i;
+ struct adapter *adapter = dev->priv;
+
+ t3_sge_stop(adapter);
+ sysfs_remove_group(&adapter->port[0]->dev.kobj,
+ &cxgb3_attr_group);
+
+ for_each_port(adapter, i)
+ if (test_bit(i, &adapter->registered_device_map))
+ unregister_netdev(adapter->port[i]);
+
+ if (is_offload(adapter)) {
+ cxgb3_adapter_unofld(adapter);
+ if (test_bit(OFFLOAD_DEVMAP_BIT,
+ &adapter->open_device_map))
+ offload_close(&adapter->tdev);
+ }
+
+ t3_free_sge_resources(adapter);
+ cxgb_disable_msi(adapter);
+
+ for (i = 0; i < ARRAY_SIZE(adapter->dummy_netdev); i++)
+ if (adapter->dummy_netdev[i]) {
+ free_netdev(adapter->dummy_netdev[i]);
+ adapter->dummy_netdev[i] = NULL;
+ }
+
+ for_each_port(adapter, i)
+ if (adapter->port[i])
+ free_netdev(adapter->port[i]);
+
+ iounmap(adapter->regs);
+ kfree(adapter);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+ }
+}
+
+static struct pci_driver driver = {
+ .name = DRV_NAME,
+ .id_table = cxgb3_pci_tbl,
+ .probe = init_one,
+ .remove = __devexit_p(remove_one),
+};
+
+static int __init cxgb3_init_module(void)
+{
+ int ret;
+
+ cxgb3_offload_init();
+
+ ret = pci_register_driver(&driver);
+ return ret;
+}
+
+static void __exit cxgb3_cleanup_module(void)
+{
+ pci_unregister_driver(&driver);
+ if (cxgb3_wq)
+ destroy_workqueue(cxgb3_wq);
+}
+
+module_init(cxgb3_init_module);
+module_exit(cxgb3_cleanup_module);
diff --git a/drivers/net/cxgb3/cxgb3_offload.c b/drivers/net/cxgb3/cxgb3_offload.c
new file mode 100644
index 00000000000..b2cf5f6feb4
--- /dev/null
+++ b/drivers/net/cxgb3/cxgb3_offload.c
@@ -0,0 +1,1221 @@
+/*
+ * Copyright (c) 2006-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/list.h>
+#include <net/neighbour.h>
+#include <linux/notifier.h>
+#include <asm/atomic.h>
+#include <linux/proc_fs.h>
+#include <linux/if_vlan.h>
+#include <net/netevent.h>
+#include <linux/highmem.h>
+#include <linux/vmalloc.h>
+
+#include "common.h"
+#include "regs.h"
+#include "cxgb3_ioctl.h"
+#include "cxgb3_ctl_defs.h"
+#include "cxgb3_defs.h"
+#include "l2t.h"
+#include "firmware_exports.h"
+#include "cxgb3_offload.h"
+
+static LIST_HEAD(client_list);
+static LIST_HEAD(ofld_dev_list);
+static DEFINE_MUTEX(cxgb3_db_lock);
+
+static DEFINE_RWLOCK(adapter_list_lock);
+static LIST_HEAD(adapter_list);
+
+static const unsigned int MAX_ATIDS = 64 * 1024;
+static const unsigned int ATID_BASE = 0x100000;
+
+static inline int offload_activated(struct t3cdev *tdev)
+{
+ const struct adapter *adapter = tdev2adap(tdev);
+
+ return (test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map));
+}
+
+/**
+ * cxgb3_register_client - register an offload client
+ * @client: the client
+ *
+ * Add the client to the client list,
+ * and call backs the client for each activated offload device
+ */
+void cxgb3_register_client(struct cxgb3_client *client)
+{
+ struct t3cdev *tdev;
+
+ mutex_lock(&cxgb3_db_lock);
+ list_add_tail(&client->client_list, &client_list);
+
+ if (client->add) {
+ list_for_each_entry(tdev, &ofld_dev_list, ofld_dev_list) {
+ if (offload_activated(tdev))
+ client->add(tdev);
+ }
+ }
+ mutex_unlock(&cxgb3_db_lock);
+}
+
+EXPORT_SYMBOL(cxgb3_register_client);
+
+/**
+ * cxgb3_unregister_client - unregister an offload client
+ * @client: the client
+ *
+ * Remove the client to the client list,
+ * and call backs the client for each activated offload device.
+ */
+void cxgb3_unregister_client(struct cxgb3_client *client)
+{
+ struct t3cdev *tdev;
+
+ mutex_lock(&cxgb3_db_lock);
+ list_del(&client->client_list);
+
+ if (client->remove) {
+ list_for_each_entry(tdev, &ofld_dev_list, ofld_dev_list) {
+ if (offload_activated(tdev))
+ client->remove(tdev);
+ }
+ }
+ mutex_unlock(&cxgb3_db_lock);
+}
+
+EXPORT_SYMBOL(cxgb3_unregister_client);
+
+/**
+ * cxgb3_add_clients - activate registered clients for an offload device
+ * @tdev: the offload device
+ *
+ * Call backs all registered clients once a offload device is activated
+ */
+void cxgb3_add_clients(struct t3cdev *tdev)
+{
+ struct cxgb3_client *client;
+
+ mutex_lock(&cxgb3_db_lock);
+ list_for_each_entry(client, &client_list, client_list) {
+ if (client->add)
+ client->add(tdev);
+ }
+ mutex_unlock(&cxgb3_db_lock);
+}
+
+/**
+ * cxgb3_remove_clients - deactivates registered clients
+ * for an offload device
+ * @tdev: the offload device
+ *
+ * Call backs all registered clients once a offload device is deactivated
+ */
+void cxgb3_remove_clients(struct t3cdev *tdev)
+{
+ struct cxgb3_client *client;
+
+ mutex_lock(&cxgb3_db_lock);
+ list_for_each_entry(client, &client_list, client_list) {
+ if (client->remove)
+ client->remove(tdev);
+ }
+ mutex_unlock(&cxgb3_db_lock);
+}
+
+static struct net_device *get_iff_from_mac(struct adapter *adapter,
+ const unsigned char *mac,
+ unsigned int vlan)
+{
+ int i;
+
+ for_each_port(adapter, i) {
+ const struct vlan_group *grp;
+ struct net_device *dev = adapter->port[i];
+ const struct port_info *p = netdev_priv(dev);
+
+ if (!memcmp(dev->dev_addr, mac, ETH_ALEN)) {
+ if (vlan && vlan != VLAN_VID_MASK) {
+ grp = p->vlan_grp;
+ dev = grp ? grp->vlan_devices[vlan] : NULL;
+ } else
+ while (dev->master)
+ dev = dev->master;
+ return dev;
+ }
+ }
+ return NULL;
+}
+
+static int cxgb_ulp_iscsi_ctl(struct adapter *adapter, unsigned int req,
+ void *data)
+{
+ int ret = 0;
+ struct ulp_iscsi_info *uiip = data;
+
+ switch (req) {
+ case ULP_ISCSI_GET_PARAMS:
+ uiip->pdev = adapter->pdev;
+ uiip->llimit = t3_read_reg(adapter, A_ULPRX_ISCSI_LLIMIT);
+ uiip->ulimit = t3_read_reg(adapter, A_ULPRX_ISCSI_ULIMIT);
+ uiip->tagmask = t3_read_reg(adapter, A_ULPRX_ISCSI_TAGMASK);
+ /*
+ * On tx, the iscsi pdu has to be <= tx page size and has to
+ * fit into the Tx PM FIFO.
+ */
+ uiip->max_txsz = min(adapter->params.tp.tx_pg_size,
+ t3_read_reg(adapter, A_PM1_TX_CFG) >> 17);
+ /* on rx, the iscsi pdu has to be < rx page size and the
+ whole pdu + cpl headers has to fit into one sge buffer */
+ uiip->max_rxsz = min_t(unsigned int,
+ adapter->params.tp.rx_pg_size,
+ (adapter->sge.qs[0].fl[1].buf_size -
+ sizeof(struct cpl_rx_data) * 2 -
+ sizeof(struct cpl_rx_data_ddp)));
+ break;
+ case ULP_ISCSI_SET_PARAMS:
+ t3_write_reg(adapter, A_ULPRX_ISCSI_TAGMASK, uiip->tagmask);
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ }
+ return ret;
+}
+
+/* Response queue used for RDMA events. */
+#define ASYNC_NOTIF_RSPQ 0
+
+static int cxgb_rdma_ctl(struct adapter *adapter, unsigned int req, void *data)
+{
+ int ret = 0;
+
+ switch (req) {
+ case RDMA_GET_PARAMS:{
+ struct rdma_info *req = data;
+ struct pci_dev *pdev = adapter->pdev;
+
+ req->udbell_physbase = pci_resource_start(pdev, 2);
+ req->udbell_len = pci_resource_len(pdev, 2);
+ req->tpt_base =
+ t3_read_reg(adapter, A_ULPTX_TPT_LLIMIT);
+ req->tpt_top = t3_read_reg(adapter, A_ULPTX_TPT_ULIMIT);
+ req->pbl_base =
+ t3_read_reg(adapter, A_ULPTX_PBL_LLIMIT);
+ req->pbl_top = t3_read_reg(adapter, A_ULPTX_PBL_ULIMIT);
+ req->rqt_base = t3_read_reg(adapter, A_ULPRX_RQ_LLIMIT);
+ req->rqt_top = t3_read_reg(adapter, A_ULPRX_RQ_ULIMIT);
+ req->kdb_addr = adapter->regs + A_SG_KDOORBELL;
+ req->pdev = pdev;
+ break;
+ }
+ case RDMA_CQ_OP:{
+ unsigned long flags;
+ struct rdma_cq_op *req = data;
+
+ /* may be called in any context */
+ spin_lock_irqsave(&adapter->sge.reg_lock, flags);
+ ret = t3_sge_cqcntxt_op(adapter, req->id, req->op,
+ req->credits);
+ spin_unlock_irqrestore(&adapter->sge.reg_lock, flags);
+ break;
+ }
+ case RDMA_GET_MEM:{
+ struct ch_mem_range *t = data;
+ struct mc7 *mem;
+
+ if ((t->addr & 7) || (t->len & 7))
+ return -EINVAL;
+ if (t->mem_id == MEM_CM)
+ mem = &adapter->cm;
+ else if (t->mem_id == MEM_PMRX)
+ mem = &adapter->pmrx;
+ else if (t->mem_id == MEM_PMTX)
+ mem = &adapter->pmtx;
+ else
+ return -EINVAL;
+
+ ret =
+ t3_mc7_bd_read(mem, t->addr / 8, t->len / 8,
+ (u64 *) t->buf);
+ if (ret)
+ return ret;
+ break;
+ }
+ case RDMA_CQ_SETUP:{
+ struct rdma_cq_setup *req = data;
+
+ spin_lock_irq(&adapter->sge.reg_lock);
+ ret =
+ t3_sge_init_cqcntxt(adapter, req->id,
+ req->base_addr, req->size,
+ ASYNC_NOTIF_RSPQ,
+ req->ovfl_mode, req->credits,
+ req->credit_thres);
+ spin_unlock_irq(&adapter->sge.reg_lock);
+ break;
+ }
+ case RDMA_CQ_DISABLE:
+ spin_lock_irq(&adapter->sge.reg_lock);
+ ret = t3_sge_disable_cqcntxt(adapter, *(unsigned int *)data);
+ spin_unlock_irq(&adapter->sge.reg_lock);
+ break;
+ case RDMA_CTRL_QP_SETUP:{
+ struct rdma_ctrlqp_setup *req = data;
+
+ spin_lock_irq(&adapter->sge.reg_lock);
+ ret = t3_sge_init_ecntxt(adapter, FW_RI_SGEEC_START, 0,
+ SGE_CNTXT_RDMA,
+ ASYNC_NOTIF_RSPQ,
+ req->base_addr, req->size,
+ FW_RI_TID_START, 1, 0);
+ spin_unlock_irq(&adapter->sge.reg_lock);
+ break;
+ }
+ default:
+ ret = -EOPNOTSUPP;
+ }
+ return ret;
+}
+
+static int cxgb_offload_ctl(struct t3cdev *tdev, unsigned int req, void *data)
+{
+ struct adapter *adapter = tdev2adap(tdev);
+ struct tid_range *tid;
+ struct mtutab *mtup;
+ struct iff_mac *iffmacp;
+ struct ddp_params *ddpp;
+ struct adap_ports *ports;
+ int i;
+
+ switch (req) {
+ case GET_MAX_OUTSTANDING_WR:
+ *(unsigned int *)data = FW_WR_NUM;
+ break;
+ case GET_WR_LEN:
+ *(unsigned int *)data = WR_FLITS;
+ break;
+ case GET_TX_MAX_CHUNK:
+ *(unsigned int *)data = 1 << 20; /* 1MB */
+ break;
+ case GET_TID_RANGE:
+ tid = data;
+ tid->num = t3_mc5_size(&adapter->mc5) -
+ adapter->params.mc5.nroutes -
+ adapter->params.mc5.nfilters - adapter->params.mc5.nservers;
+ tid->base = 0;
+ break;
+ case GET_STID_RANGE:
+ tid = data;
+ tid->num = adapter->params.mc5.nservers;
+ tid->base = t3_mc5_size(&adapter->mc5) - tid->num -
+ adapter->params.mc5.nfilters - adapter->params.mc5.nroutes;
+ break;
+ case GET_L2T_CAPACITY:
+ *(unsigned int *)data = 2048;
+ break;
+ case GET_MTUS:
+ mtup = data;
+ mtup->size = NMTUS;
+ mtup->mtus = adapter->params.mtus;
+ break;
+ case GET_IFF_FROM_MAC:
+ iffmacp = data;
+ iffmacp->dev = get_iff_from_mac(adapter, iffmacp->mac_addr,
+ iffmacp->vlan_tag &
+ VLAN_VID_MASK);
+ break;
+ case GET_DDP_PARAMS:
+ ddpp = data;
+ ddpp->llimit = t3_read_reg(adapter, A_ULPRX_TDDP_LLIMIT);
+ ddpp->ulimit = t3_read_reg(adapter, A_ULPRX_TDDP_ULIMIT);
+ ddpp->tag_mask = t3_read_reg(adapter, A_ULPRX_TDDP_TAGMASK);
+ break;
+ case GET_PORTS:
+ ports = data;
+ ports->nports = adapter->params.nports;
+ for_each_port(adapter, i)
+ ports->lldevs[i] = adapter->port[i];
+ break;
+ case ULP_ISCSI_GET_PARAMS:
+ case ULP_ISCSI_SET_PARAMS:
+ if (!offload_running(adapter))
+ return -EAGAIN;
+ return cxgb_ulp_iscsi_ctl(adapter, req, data);
+ case RDMA_GET_PARAMS:
+ case RDMA_CQ_OP:
+ case RDMA_CQ_SETUP:
+ case RDMA_CQ_DISABLE:
+ case RDMA_CTRL_QP_SETUP:
+ case RDMA_GET_MEM:
+ if (!offload_running(adapter))
+ return -EAGAIN;
+ return cxgb_rdma_ctl(adapter, req, data);
+ default:
+ return -EOPNOTSUPP;
+ }
+ return 0;
+}
+
+/*
+ * Dummy handler for Rx offload packets in case we get an offload packet before
+ * proper processing is setup. This complains and drops the packet as it isn't
+ * normal to get offload packets at this stage.
+ */
+static int rx_offload_blackhole(struct t3cdev *dev, struct sk_buff **skbs,
+ int n)
+{
+ CH_ERR(tdev2adap(dev), "%d unexpected offload packets, first data %u\n",
+ n, ntohl(*(__be32 *)skbs[0]->data));
+ while (n--)
+ dev_kfree_skb_any(skbs[n]);
+ return 0;
+}
+
+static void dummy_neigh_update(struct t3cdev *dev, struct neighbour *neigh)
+{
+}
+
+void cxgb3_set_dummy_ops(struct t3cdev *dev)
+{
+ dev->recv = rx_offload_blackhole;
+ dev->neigh_update = dummy_neigh_update;
+}
+
+/*
+ * Free an active-open TID.
+ */
+void *cxgb3_free_atid(struct t3cdev *tdev, int atid)
+{
+ struct tid_info *t = &(T3C_DATA(tdev))->tid_maps;
+ union active_open_entry *p = atid2entry(t, atid);
+ void *ctx = p->t3c_tid.ctx;
+
+ spin_lock_bh(&t->atid_lock);
+ p->next = t->afree;
+ t->afree = p;
+ t->atids_in_use--;
+ spin_unlock_bh(&t->atid_lock);
+
+ return ctx;
+}
+
+EXPORT_SYMBOL(cxgb3_free_atid);
+
+/*
+ * Free a server TID and return it to the free pool.
+ */
+void cxgb3_free_stid(struct t3cdev *tdev, int stid)
+{
+ struct tid_info *t = &(T3C_DATA(tdev))->tid_maps;
+ union listen_entry *p = stid2entry(t, stid);
+
+ spin_lock_bh(&t->stid_lock);
+ p->next = t->sfree;
+ t->sfree = p;
+ t->stids_in_use--;
+ spin_unlock_bh(&t->stid_lock);
+}
+
+EXPORT_SYMBOL(cxgb3_free_stid);
+
+void cxgb3_insert_tid(struct t3cdev *tdev, struct cxgb3_client *client,
+ void *ctx, unsigned int tid)
+{
+ struct tid_info *t = &(T3C_DATA(tdev))->tid_maps;
+
+ t->tid_tab[tid].client = client;
+ t->tid_tab[tid].ctx = ctx;
+ atomic_inc(&t->tids_in_use);
+}
+
+EXPORT_SYMBOL(cxgb3_insert_tid);
+
+/*
+ * Populate a TID_RELEASE WR. The skb must be already propely sized.
+ */
+static inline void mk_tid_release(struct sk_buff *skb, unsigned int tid)
+{
+ struct cpl_tid_release *req;
+
+ skb->priority = CPL_PRIORITY_SETUP;
+ req = (struct cpl_tid_release *)__skb_put(skb, sizeof(*req));
+ req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
+ OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_TID_RELEASE, tid));
+}
+
+static void t3_process_tid_release_list(struct work_struct *work)
+{
+ struct t3c_data *td = container_of(work, struct t3c_data,
+ tid_release_task);
+ struct sk_buff *skb;
+ struct t3cdev *tdev = td->dev;
+
+
+ spin_lock_bh(&td->tid_release_lock);
+ while (td->tid_release_list) {
+ struct t3c_tid_entry *p = td->tid_release_list;
+
+ td->tid_release_list = (struct t3c_tid_entry *)p->ctx;
+ spin_unlock_bh(&td->tid_release_lock);
+
+ skb = alloc_skb(sizeof(struct cpl_tid_release),
+ GFP_KERNEL | __GFP_NOFAIL);
+ mk_tid_release(skb, p - td->tid_maps.tid_tab);
+ cxgb3_ofld_send(tdev, skb);
+ p->ctx = NULL;
+ spin_lock_bh(&td->tid_release_lock);
+ }
+ spin_unlock_bh(&td->tid_release_lock);
+}
+
+/* use ctx as a next pointer in the tid release list */
+void cxgb3_queue_tid_release(struct t3cdev *tdev, unsigned int tid)
+{
+ struct t3c_data *td = T3C_DATA(tdev);
+ struct t3c_tid_entry *p = &td->tid_maps.tid_tab[tid];
+
+ spin_lock_bh(&td->tid_release_lock);
+ p->ctx = (void *)td->tid_release_list;
+ td->tid_release_list = p;
+ if (!p->ctx)
+ schedule_work(&td->tid_release_task);
+ spin_unlock_bh(&td->tid_release_lock);
+}
+
+EXPORT_SYMBOL(cxgb3_queue_tid_release);
+
+/*
+ * Remove a tid from the TID table. A client may defer processing its last
+ * CPL message if it is locked at the time it arrives, and while the message
+ * sits in the client's backlog the TID may be reused for another connection.
+ * To handle this we atomically switch the TID association if it still points
+ * to the original client context.
+ */
+void cxgb3_remove_tid(struct t3cdev *tdev, void *ctx, unsigned int tid)
+{
+ struct tid_info *t = &(T3C_DATA(tdev))->tid_maps;
+
+ BUG_ON(tid >= t->ntids);
+ if (tdev->type == T3A)
+ (void)cmpxchg(&t->tid_tab[tid].ctx, ctx, NULL);
+ else {
+ struct sk_buff *skb;
+
+ skb = alloc_skb(sizeof(struct cpl_tid_release), GFP_ATOMIC);
+ if (likely(skb)) {
+ mk_tid_release(skb, tid);
+ cxgb3_ofld_send(tdev, skb);
+ t->tid_tab[tid].ctx = NULL;
+ } else
+ cxgb3_queue_tid_release(tdev, tid);
+ }
+ atomic_dec(&t->tids_in_use);
+}
+
+EXPORT_SYMBOL(cxgb3_remove_tid);
+
+int cxgb3_alloc_atid(struct t3cdev *tdev, struct cxgb3_client *client,
+ void *ctx)
+{
+ int atid = -1;
+ struct tid_info *t = &(T3C_DATA(tdev))->tid_maps;
+
+ spin_lock_bh(&t->atid_lock);
+ if (t->afree) {
+ union active_open_entry *p = t->afree;
+
+ atid = (p - t->atid_tab) + t->atid_base;
+ t->afree = p->next;
+ p->t3c_tid.ctx = ctx;
+ p->t3c_tid.client = client;
+ t->atids_in_use++;
+ }
+ spin_unlock_bh(&t->atid_lock);
+ return atid;
+}
+
+EXPORT_SYMBOL(cxgb3_alloc_atid);
+
+int cxgb3_alloc_stid(struct t3cdev *tdev, struct cxgb3_client *client,
+ void *ctx)
+{
+ int stid = -1;
+ struct tid_info *t = &(T3C_DATA(tdev))->tid_maps;
+
+ spin_lock_bh(&t->stid_lock);
+ if (t->sfree) {
+ union listen_entry *p = t->sfree;
+
+ stid = (p - t->stid_tab) + t->stid_base;
+ t->sfree = p->next;
+ p->t3c_tid.ctx = ctx;
+ p->t3c_tid.client = client;
+ t->stids_in_use++;
+ }
+ spin_unlock_bh(&t->stid_lock);
+ return stid;
+}
+
+EXPORT_SYMBOL(cxgb3_alloc_stid);
+
+static int do_smt_write_rpl(struct t3cdev *dev, struct sk_buff *skb)
+{
+ struct cpl_smt_write_rpl *rpl = cplhdr(skb);
+
+ if (rpl->status != CPL_ERR_NONE)
+ printk(KERN_ERR
+ "Unexpected SMT_WRITE_RPL status %u for entry %u\n",
+ rpl->status, GET_TID(rpl));
+
+ return CPL_RET_BUF_DONE;
+}
+
+static int do_l2t_write_rpl(struct t3cdev *dev, struct sk_buff *skb)
+{
+ struct cpl_l2t_write_rpl *rpl = cplhdr(skb);
+
+ if (rpl->status != CPL_ERR_NONE)
+ printk(KERN_ERR
+ "Unexpected L2T_WRITE_RPL status %u for entry %u\n",
+ rpl->status, GET_TID(rpl));
+
+ return CPL_RET_BUF_DONE;
+}
+
+static int do_act_open_rpl(struct t3cdev *dev, struct sk_buff *skb)
+{
+ struct cpl_act_open_rpl *rpl = cplhdr(skb);
+ unsigned int atid = G_TID(ntohl(rpl->atid));
+ struct t3c_tid_entry *t3c_tid;
+
+ t3c_tid = lookup_atid(&(T3C_DATA(dev))->tid_maps, atid);
+ if (t3c_tid->ctx && t3c_tid->client && t3c_tid->client->handlers &&
+ t3c_tid->client->handlers[CPL_ACT_OPEN_RPL]) {
+ return t3c_tid->client->handlers[CPL_ACT_OPEN_RPL] (dev, skb,
+ t3c_tid->
+ ctx);
+ } else {
+ printk(KERN_ERR "%s: received clientless CPL command 0x%x\n",
+ dev->name, CPL_ACT_OPEN_RPL);
+ return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
+ }
+}
+
+static int do_stid_rpl(struct t3cdev *dev, struct sk_buff *skb)
+{
+ union opcode_tid *p = cplhdr(skb);
+ unsigned int stid = G_TID(ntohl(p->opcode_tid));
+ struct t3c_tid_entry *t3c_tid;
+
+ t3c_tid = lookup_stid(&(T3C_DATA(dev))->tid_maps, stid);
+ if (t3c_tid->ctx && t3c_tid->client->handlers &&
+ t3c_tid->client->handlers[p->opcode]) {
+ return t3c_tid->client->handlers[p->opcode] (dev, skb,
+ t3c_tid->ctx);
+ } else {
+ printk(KERN_ERR "%s: received clientless CPL command 0x%x\n",
+ dev->name, p->opcode);
+ return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
+ }
+}
+
+static int do_hwtid_rpl(struct t3cdev *dev, struct sk_buff *skb)
+{
+ union opcode_tid *p = cplhdr(skb);
+ unsigned int hwtid = G_TID(ntohl(p->opcode_tid));
+ struct t3c_tid_entry *t3c_tid;
+
+ t3c_tid = lookup_tid(&(T3C_DATA(dev))->tid_maps, hwtid);
+ if (t3c_tid->ctx && t3c_tid->client->handlers &&
+ t3c_tid->client->handlers[p->opcode]) {
+ return t3c_tid->client->handlers[p->opcode]
+ (dev, skb, t3c_tid->ctx);
+ } else {
+ printk(KERN_ERR "%s: received clientless CPL command 0x%x\n",
+ dev->name, p->opcode);
+ return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
+ }
+}
+
+static int do_cr(struct t3cdev *dev, struct sk_buff *skb)
+{
+ struct cpl_pass_accept_req *req = cplhdr(skb);
+ unsigned int stid = G_PASS_OPEN_TID(ntohl(req->tos_tid));
+ struct t3c_tid_entry *t3c_tid;
+
+ t3c_tid = lookup_stid(&(T3C_DATA(dev))->tid_maps, stid);
+ if (t3c_tid->ctx && t3c_tid->client->handlers &&
+ t3c_tid->client->handlers[CPL_PASS_ACCEPT_REQ]) {
+ return t3c_tid->client->handlers[CPL_PASS_ACCEPT_REQ]
+ (dev, skb, t3c_tid->ctx);
+ } else {
+ printk(KERN_ERR "%s: received clientless CPL command 0x%x\n",
+ dev->name, CPL_PASS_ACCEPT_REQ);
+ return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
+ }
+}
+
+static int do_abort_req_rss(struct t3cdev *dev, struct sk_buff *skb)
+{
+ union opcode_tid *p = cplhdr(skb);
+ unsigned int hwtid = G_TID(ntohl(p->opcode_tid));
+ struct t3c_tid_entry *t3c_tid;
+
+ t3c_tid = lookup_tid(&(T3C_DATA(dev))->tid_maps, hwtid);
+ if (t3c_tid->ctx && t3c_tid->client->handlers &&
+ t3c_tid->client->handlers[p->opcode]) {
+ return t3c_tid->client->handlers[p->opcode]
+ (dev, skb, t3c_tid->ctx);
+ } else {
+ struct cpl_abort_req_rss *req = cplhdr(skb);
+ struct cpl_abort_rpl *rpl;
+
+ struct sk_buff *skb =
+ alloc_skb(sizeof(struct cpl_abort_rpl), GFP_ATOMIC);
+ if (!skb) {
+ printk("do_abort_req_rss: couldn't get skb!\n");
+ goto out;
+ }
+ skb->priority = CPL_PRIORITY_DATA;
+ __skb_put(skb, sizeof(struct cpl_abort_rpl));
+ rpl = cplhdr(skb);
+ rpl->wr.wr_hi =
+ htonl(V_WR_OP(FW_WROPCODE_OFLD_HOST_ABORT_CON_RPL));
+ rpl->wr.wr_lo = htonl(V_WR_TID(GET_TID(req)));
+ OPCODE_TID(rpl) =
+ htonl(MK_OPCODE_TID(CPL_ABORT_RPL, GET_TID(req)));
+ rpl->cmd = req->status;
+ cxgb3_ofld_send(dev, skb);
+out:
+ return CPL_RET_BUF_DONE;
+ }
+}
+
+static int do_act_establish(struct t3cdev *dev, struct sk_buff *skb)
+{
+ struct cpl_act_establish *req = cplhdr(skb);
+ unsigned int atid = G_PASS_OPEN_TID(ntohl(req->tos_tid));
+ struct t3c_tid_entry *t3c_tid;
+
+ t3c_tid = lookup_atid(&(T3C_DATA(dev))->tid_maps, atid);
+ if (t3c_tid->ctx && t3c_tid->client->handlers &&
+ t3c_tid->client->handlers[CPL_ACT_ESTABLISH]) {
+ return t3c_tid->client->handlers[CPL_ACT_ESTABLISH]
+ (dev, skb, t3c_tid->ctx);
+ } else {
+ printk(KERN_ERR "%s: received clientless CPL command 0x%x\n",
+ dev->name, CPL_PASS_ACCEPT_REQ);
+ return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
+ }
+}
+
+static int do_set_tcb_rpl(struct t3cdev *dev, struct sk_buff *skb)
+{
+ struct cpl_set_tcb_rpl *rpl = cplhdr(skb);
+
+ if (rpl->status != CPL_ERR_NONE)
+ printk(KERN_ERR
+ "Unexpected SET_TCB_RPL status %u for tid %u\n",
+ rpl->status, GET_TID(rpl));
+ return CPL_RET_BUF_DONE;
+}
+
+static int do_trace(struct t3cdev *dev, struct sk_buff *skb)
+{
+ struct cpl_trace_pkt *p = cplhdr(skb);
+
+ skb->protocol = htons(0xffff);
+ skb->dev = dev->lldev;
+ skb_pull(skb, sizeof(*p));
+ skb->mac.raw = skb->data;
+ netif_receive_skb(skb);
+ return 0;
+}
+
+static int do_term(struct t3cdev *dev, struct sk_buff *skb)
+{
+ unsigned int hwtid = ntohl(skb->priority) >> 8 & 0xfffff;
+ unsigned int opcode = G_OPCODE(ntohl(skb->csum));
+ struct t3c_tid_entry *t3c_tid;
+
+ t3c_tid = lookup_tid(&(T3C_DATA(dev))->tid_maps, hwtid);
+ if (t3c_tid->ctx && t3c_tid->client->handlers &&
+ t3c_tid->client->handlers[opcode]) {
+ return t3c_tid->client->handlers[opcode] (dev, skb,
+ t3c_tid->ctx);
+ } else {
+ printk(KERN_ERR "%s: received clientless CPL command 0x%x\n",
+ dev->name, opcode);
+ return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
+ }
+}
+
+static int nb_callback(struct notifier_block *self, unsigned long event,
+ void *ctx)
+{
+ switch (event) {
+ case (NETEVENT_NEIGH_UPDATE):{
+ cxgb_neigh_update((struct neighbour *)ctx);
+ break;
+ }
+ case (NETEVENT_PMTU_UPDATE):
+ break;
+ case (NETEVENT_REDIRECT):{
+ struct netevent_redirect *nr = ctx;
+ cxgb_redirect(nr->old, nr->new);
+ cxgb_neigh_update(nr->new->neighbour);
+ break;
+ }
+ default:
+ break;
+ }
+ return 0;
+}
+
+static struct notifier_block nb = {
+ .notifier_call = nb_callback
+};
+
+/*
+ * Process a received packet with an unknown/unexpected CPL opcode.
+ */
+static int do_bad_cpl(struct t3cdev *dev, struct sk_buff *skb)
+{
+ printk(KERN_ERR "%s: received bad CPL command 0x%x\n", dev->name,
+ *skb->data);
+ return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
+}
+
+/*
+ * Handlers for each CPL opcode
+ */
+static cpl_handler_func cpl_handlers[NUM_CPL_CMDS];
+
+/*
+ * Add a new handler to the CPL dispatch table. A NULL handler may be supplied
+ * to unregister an existing handler.
+ */
+void t3_register_cpl_handler(unsigned int opcode, cpl_handler_func h)
+{
+ if (opcode < NUM_CPL_CMDS)
+ cpl_handlers[opcode] = h ? h : do_bad_cpl;
+ else
+ printk(KERN_ERR "T3C: handler registration for "
+ "opcode %x failed\n", opcode);
+}
+
+EXPORT_SYMBOL(t3_register_cpl_handler);
+
+/*
+ * T3CDEV's receive method.
+ */
+int process_rx(struct t3cdev *dev, struct sk_buff **skbs, int n)
+{
+ while (n--) {
+ struct sk_buff *skb = *skbs++;
+ unsigned int opcode = G_OPCODE(ntohl(skb->csum));
+ int ret = cpl_handlers[opcode] (dev, skb);
+
+#if VALIDATE_TID
+ if (ret & CPL_RET_UNKNOWN_TID) {
+ union opcode_tid *p = cplhdr(skb);
+
+ printk(KERN_ERR "%s: CPL message (opcode %u) had "
+ "unknown TID %u\n", dev->name, opcode,
+ G_TID(ntohl(p->opcode_tid)));
+ }
+#endif
+ if (ret & CPL_RET_BUF_DONE)
+ kfree_skb(skb);
+ }
+ return 0;
+}
+
+/*
+ * Sends an sk_buff to a T3C driver after dealing with any active network taps.
+ */
+int cxgb3_ofld_send(struct t3cdev *dev, struct sk_buff *skb)
+{
+ int r;
+
+ local_bh_disable();
+ r = dev->send(dev, skb);
+ local_bh_enable();
+ return r;
+}
+
+EXPORT_SYMBOL(cxgb3_ofld_send);
+
+static int is_offloading(struct net_device *dev)
+{
+ struct adapter *adapter;
+ int i;
+
+ read_lock_bh(&adapter_list_lock);
+ list_for_each_entry(adapter, &adapter_list, adapter_list) {
+ for_each_port(adapter, i) {
+ if (dev == adapter->port[i]) {
+ read_unlock_bh(&adapter_list_lock);
+ return 1;
+ }
+ }
+ }
+ read_unlock_bh(&adapter_list_lock);
+ return 0;
+}
+
+void cxgb_neigh_update(struct neighbour *neigh)
+{
+ struct net_device *dev = neigh->dev;
+
+ if (dev && (is_offloading(dev))) {
+ struct t3cdev *tdev = T3CDEV(dev);
+
+ BUG_ON(!tdev);
+ t3_l2t_update(tdev, neigh);
+ }
+}
+
+static void set_l2t_ix(struct t3cdev *tdev, u32 tid, struct l2t_entry *e)
+{
+ struct sk_buff *skb;
+ struct cpl_set_tcb_field *req;
+
+ skb = alloc_skb(sizeof(*req), GFP_ATOMIC);
+ if (!skb) {
+ printk(KERN_ERR "%s: cannot allocate skb!\n", __FUNCTION__);
+ return;
+ }
+ skb->priority = CPL_PRIORITY_CONTROL;
+ req = (struct cpl_set_tcb_field *)skb_put(skb, sizeof(*req));
+ req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
+ OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, tid));
+ req->reply = 0;
+ req->cpu_idx = 0;
+ req->word = htons(W_TCB_L2T_IX);
+ req->mask = cpu_to_be64(V_TCB_L2T_IX(M_TCB_L2T_IX));
+ req->val = cpu_to_be64(V_TCB_L2T_IX(e->idx));
+ tdev->send(tdev, skb);
+}
+
+void cxgb_redirect(struct dst_entry *old, struct dst_entry *new)
+{
+ struct net_device *olddev, *newdev;
+ struct tid_info *ti;
+ struct t3cdev *tdev;
+ u32 tid;
+ int update_tcb;
+ struct l2t_entry *e;
+ struct t3c_tid_entry *te;
+
+ olddev = old->neighbour->dev;
+ newdev = new->neighbour->dev;
+ if (!is_offloading(olddev))
+ return;
+ if (!is_offloading(newdev)) {
+ printk(KERN_WARNING "%s: Redirect to non-offload"
+ "device ignored.\n", __FUNCTION__);
+ return;
+ }
+ tdev = T3CDEV(olddev);
+ BUG_ON(!tdev);
+ if (tdev != T3CDEV(newdev)) {
+ printk(KERN_WARNING "%s: Redirect to different "
+ "offload device ignored.\n", __FUNCTION__);
+ return;
+ }
+
+ /* Add new L2T entry */
+ e = t3_l2t_get(tdev, new->neighbour, newdev);
+ if (!e) {
+ printk(KERN_ERR "%s: couldn't allocate new l2t entry!\n",
+ __FUNCTION__);
+ return;
+ }
+
+ /* Walk tid table and notify clients of dst change. */
+ ti = &(T3C_DATA(tdev))->tid_maps;
+ for (tid = 0; tid < ti->ntids; tid++) {
+ te = lookup_tid(ti, tid);
+ BUG_ON(!te);
+ if (te->ctx && te->client && te->client->redirect) {
+ update_tcb = te->client->redirect(te->ctx, old, new, e);
+ if (update_tcb) {
+ l2t_hold(L2DATA(tdev), e);
+ set_l2t_ix(tdev, tid, e);
+ }
+ }
+ }
+ l2t_release(L2DATA(tdev), e);
+}
+
+/*
+ * Allocate a chunk of memory using kmalloc or, if that fails, vmalloc.
+ * The allocated memory is cleared.
+ */
+void *cxgb_alloc_mem(unsigned long size)
+{
+ void *p = kmalloc(size, GFP_KERNEL);
+
+ if (!p)
+ p = vmalloc(size);
+ if (p)
+ memset(p, 0, size);
+ return p;
+}
+
+/*
+ * Free memory allocated through t3_alloc_mem().
+ */
+void cxgb_free_mem(void *addr)
+{
+ unsigned long p = (unsigned long)addr;
+
+ if (p >= VMALLOC_START && p < VMALLOC_END)
+ vfree(addr);
+ else
+ kfree(addr);
+}
+
+/*
+ * Allocate and initialize the TID tables. Returns 0 on success.
+ */
+static int init_tid_tabs(struct tid_info *t, unsigned int ntids,
+ unsigned int natids, unsigned int nstids,
+ unsigned int atid_base, unsigned int stid_base)
+{
+ unsigned long size = ntids * sizeof(*t->tid_tab) +
+ natids * sizeof(*t->atid_tab) + nstids * sizeof(*t->stid_tab);
+
+ t->tid_tab = cxgb_alloc_mem(size);
+ if (!t->tid_tab)
+ return -ENOMEM;
+
+ t->stid_tab = (union listen_entry *)&t->tid_tab[ntids];
+ t->atid_tab = (union active_open_entry *)&t->stid_tab[nstids];
+ t->ntids = ntids;
+ t->nstids = nstids;
+ t->stid_base = stid_base;
+ t->sfree = NULL;
+ t->natids = natids;
+ t->atid_base = atid_base;
+ t->afree = NULL;
+ t->stids_in_use = t->atids_in_use = 0;
+ atomic_set(&t->tids_in_use, 0);
+ spin_lock_init(&t->stid_lock);
+ spin_lock_init(&t->atid_lock);
+
+ /*
+ * Setup the free lists for stid_tab and atid_tab.
+ */
+ if (nstids) {
+ while (--nstids)
+ t->stid_tab[nstids - 1].next = &t->stid_tab[nstids];
+ t->sfree = t->stid_tab;
+ }
+ if (natids) {
+ while (--natids)
+ t->atid_tab[natids - 1].next = &t->atid_tab[natids];
+ t->afree = t->atid_tab;
+ }
+ return 0;
+}
+
+static void free_tid_maps(struct tid_info *t)
+{
+ cxgb_free_mem(t->tid_tab);
+}
+
+static inline void add_adapter(struct adapter *adap)
+{
+ write_lock_bh(&adapter_list_lock);
+ list_add_tail(&adap->adapter_list, &adapter_list);
+ write_unlock_bh(&adapter_list_lock);
+}
+
+static inline void remove_adapter(struct adapter *adap)
+{
+ write_lock_bh(&adapter_list_lock);
+ list_del(&adap->adapter_list);
+ write_unlock_bh(&adapter_list_lock);
+}
+
+int cxgb3_offload_activate(struct adapter *adapter)
+{
+ struct t3cdev *dev = &adapter->tdev;
+ int natids, err;
+ struct t3c_data *t;
+ struct tid_range stid_range, tid_range;
+ struct mtutab mtutab;
+ unsigned int l2t_capacity;
+
+ t = kcalloc(1, sizeof(*t), GFP_KERNEL);
+ if (!t)
+ return -ENOMEM;
+
+ err = -EOPNOTSUPP;
+ if (dev->ctl(dev, GET_TX_MAX_CHUNK, &t->tx_max_chunk) < 0 ||
+ dev->ctl(dev, GET_MAX_OUTSTANDING_WR, &t->max_wrs) < 0 ||
+ dev->ctl(dev, GET_L2T_CAPACITY, &l2t_capacity) < 0 ||
+ dev->ctl(dev, GET_MTUS, &mtutab) < 0 ||
+ dev->ctl(dev, GET_TID_RANGE, &tid_range) < 0 ||
+ dev->ctl(dev, GET_STID_RANGE, &stid_range) < 0)
+ goto out_free;
+
+ err = -ENOMEM;
+ L2DATA(dev) = t3_init_l2t(l2t_capacity);
+ if (!L2DATA(dev))
+ goto out_free;
+
+ natids = min(tid_range.num / 2, MAX_ATIDS);
+ err = init_tid_tabs(&t->tid_maps, tid_range.num, natids,
+ stid_range.num, ATID_BASE, stid_range.base);
+ if (err)
+ goto out_free_l2t;
+
+ t->mtus = mtutab.mtus;
+ t->nmtus = mtutab.size;
+
+ INIT_WORK(&t->tid_release_task, t3_process_tid_release_list);
+ spin_lock_init(&t->tid_release_lock);
+ INIT_LIST_HEAD(&t->list_node);
+ t->dev = dev;
+
+ T3C_DATA(dev) = t;
+ dev->recv = process_rx;
+ dev->neigh_update = t3_l2t_update;
+
+ /* Register netevent handler once */
+ if (list_empty(&adapter_list))
+ register_netevent_notifier(&nb);
+
+ add_adapter(adapter);
+ return 0;
+
+out_free_l2t:
+ t3_free_l2t(L2DATA(dev));
+ L2DATA(dev) = NULL;
+out_free:
+ kfree(t);
+ return err;
+}
+
+void cxgb3_offload_deactivate(struct adapter *adapter)
+{
+ struct t3cdev *tdev = &adapter->tdev;
+ struct t3c_data *t = T3C_DATA(tdev);
+
+ remove_adapter(adapter);
+ if (list_empty(&adapter_list))
+ unregister_netevent_notifier(&nb);
+
+ free_tid_maps(&t->tid_maps);
+ T3C_DATA(tdev) = NULL;
+ t3_free_l2t(L2DATA(tdev));
+ L2DATA(tdev) = NULL;
+ kfree(t);
+}
+
+static inline void register_tdev(struct t3cdev *tdev)
+{
+ static int unit;
+
+ mutex_lock(&cxgb3_db_lock);
+ snprintf(tdev->name, sizeof(tdev->name), "ofld_dev%d", unit++);
+ list_add_tail(&tdev->ofld_dev_list, &ofld_dev_list);
+ mutex_unlock(&cxgb3_db_lock);
+}
+
+static inline void unregister_tdev(struct t3cdev *tdev)
+{
+ mutex_lock(&cxgb3_db_lock);
+ list_del(&tdev->ofld_dev_list);
+ mutex_unlock(&cxgb3_db_lock);
+}
+
+void __devinit cxgb3_adapter_ofld(struct adapter *adapter)
+{
+ struct t3cdev *tdev = &adapter->tdev;
+
+ INIT_LIST_HEAD(&tdev->ofld_dev_list);
+
+ cxgb3_set_dummy_ops(tdev);
+ tdev->send = t3_offload_tx;
+ tdev->ctl = cxgb_offload_ctl;
+ tdev->type = adapter->params.rev == 0 ? T3A : T3B;
+
+ register_tdev(tdev);
+}
+
+void __devexit cxgb3_adapter_unofld(struct adapter *adapter)
+{
+ struct t3cdev *tdev = &adapter->tdev;
+
+ tdev->recv = NULL;
+ tdev->neigh_update = NULL;
+
+ unregister_tdev(tdev);
+}
+
+void __init cxgb3_offload_init(void)
+{
+ int i;
+
+ for (i = 0; i < NUM_CPL_CMDS; ++i)
+ cpl_handlers[i] = do_bad_cpl;
+
+ t3_register_cpl_handler(CPL_SMT_WRITE_RPL, do_smt_write_rpl);
+ t3_register_cpl_handler(CPL_L2T_WRITE_RPL, do_l2t_write_rpl);
+ t3_register_cpl_handler(CPL_PASS_OPEN_RPL, do_stid_rpl);
+ t3_register_cpl_handler(CPL_CLOSE_LISTSRV_RPL, do_stid_rpl);
+ t3_register_cpl_handler(CPL_PASS_ACCEPT_REQ, do_cr);
+ t3_register_cpl_handler(CPL_PASS_ESTABLISH, do_hwtid_rpl);
+ t3_register_cpl_handler(CPL_ABORT_RPL_RSS, do_hwtid_rpl);
+ t3_register_cpl_handler(CPL_ABORT_RPL, do_hwtid_rpl);
+ t3_register_cpl_handler(CPL_RX_URG_NOTIFY, do_hwtid_rpl);
+ t3_register_cpl_handler(CPL_RX_DATA, do_hwtid_rpl);
+ t3_register_cpl_handler(CPL_TX_DATA_ACK, do_hwtid_rpl);
+ t3_register_cpl_handler(CPL_TX_DMA_ACK, do_hwtid_rpl);
+ t3_register_cpl_handler(CPL_ACT_OPEN_RPL, do_act_open_rpl);
+ t3_register_cpl_handler(CPL_PEER_CLOSE, do_hwtid_rpl);
+ t3_register_cpl_handler(CPL_CLOSE_CON_RPL, do_hwtid_rpl);
+ t3_register_cpl_handler(CPL_ABORT_REQ_RSS, do_abort_req_rss);
+ t3_register_cpl_handler(CPL_ACT_ESTABLISH, do_act_establish);
+ t3_register_cpl_handler(CPL_SET_TCB_RPL, do_set_tcb_rpl);
+ t3_register_cpl_handler(CPL_RDMA_TERMINATE, do_term);
+ t3_register_cpl_handler(CPL_RDMA_EC_STATUS, do_hwtid_rpl);
+ t3_register_cpl_handler(CPL_TRACE_PKT, do_trace);
+ t3_register_cpl_handler(CPL_RX_DATA_DDP, do_hwtid_rpl);
+ t3_register_cpl_handler(CPL_RX_DDP_COMPLETE, do_hwtid_rpl);
+ t3_register_cpl_handler(CPL_ISCSI_HDR, do_hwtid_rpl);
+}
diff --git a/drivers/net/cxgb3/cxgb3_offload.h b/drivers/net/cxgb3/cxgb3_offload.h
new file mode 100644
index 00000000000..f15446a32ef
--- /dev/null
+++ b/drivers/net/cxgb3/cxgb3_offload.h
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2006-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef _CXGB3_OFFLOAD_H
+#define _CXGB3_OFFLOAD_H
+
+#include <linux/list.h>
+#include <linux/skbuff.h>
+
+#include "l2t.h"
+
+#include "t3cdev.h"
+#include "t3_cpl.h"
+
+struct adapter;
+
+void cxgb3_offload_init(void);
+
+void cxgb3_adapter_ofld(struct adapter *adapter);
+void cxgb3_adapter_unofld(struct adapter *adapter);
+int cxgb3_offload_activate(struct adapter *adapter);
+void cxgb3_offload_deactivate(struct adapter *adapter);
+
+void cxgb3_set_dummy_ops(struct t3cdev *dev);
+
+/*
+ * Client registration. Users of T3 driver must register themselves.
+ * The T3 driver will call the add function of every client for each T3
+ * adapter activated, passing up the t3cdev ptr. Each client fills out an
+ * array of callback functions to process CPL messages.
+ */
+
+void cxgb3_register_client(struct cxgb3_client *client);
+void cxgb3_unregister_client(struct cxgb3_client *client);
+void cxgb3_add_clients(struct t3cdev *tdev);
+void cxgb3_remove_clients(struct t3cdev *tdev);
+
+typedef int (*cxgb3_cpl_handler_func)(struct t3cdev *dev,
+ struct sk_buff *skb, void *ctx);
+
+struct cxgb3_client {
+ char *name;
+ void (*add) (struct t3cdev *);
+ void (*remove) (struct t3cdev *);
+ cxgb3_cpl_handler_func *handlers;
+ int (*redirect)(void *ctx, struct dst_entry *old,
+ struct dst_entry *new, struct l2t_entry *l2t);
+ struct list_head client_list;
+};
+
+/*
+ * TID allocation services.
+ */
+int cxgb3_alloc_atid(struct t3cdev *dev, struct cxgb3_client *client,
+ void *ctx);
+int cxgb3_alloc_stid(struct t3cdev *dev, struct cxgb3_client *client,
+ void *ctx);
+void *cxgb3_free_atid(struct t3cdev *dev, int atid);
+void cxgb3_free_stid(struct t3cdev *dev, int stid);
+void cxgb3_insert_tid(struct t3cdev *dev, struct cxgb3_client *client,
+ void *ctx, unsigned int tid);
+void cxgb3_queue_tid_release(struct t3cdev *dev, unsigned int tid);
+void cxgb3_remove_tid(struct t3cdev *dev, void *ctx, unsigned int tid);
+
+struct t3c_tid_entry {
+ struct cxgb3_client *client;
+ void *ctx;
+};
+
+/* CPL message priority levels */
+enum {
+ CPL_PRIORITY_DATA = 0, /* data messages */
+ CPL_PRIORITY_SETUP = 1, /* connection setup messages */
+ CPL_PRIORITY_TEARDOWN = 0, /* connection teardown messages */
+ CPL_PRIORITY_LISTEN = 1, /* listen start/stop messages */
+ CPL_PRIORITY_ACK = 1, /* RX ACK messages */
+ CPL_PRIORITY_CONTROL = 1 /* offload control messages */
+};
+
+/* Flags for return value of CPL message handlers */
+enum {
+ CPL_RET_BUF_DONE = 1, /* buffer processing done, buffer may be freed */
+ CPL_RET_BAD_MSG = 2, /* bad CPL message (e.g., unknown opcode) */
+ CPL_RET_UNKNOWN_TID = 4 /* unexpected unknown TID */
+};
+
+typedef int (*cpl_handler_func)(struct t3cdev *dev, struct sk_buff *skb);
+
+/*
+ * Returns a pointer to the first byte of the CPL header in an sk_buff that
+ * contains a CPL message.
+ */
+static inline void *cplhdr(struct sk_buff *skb)
+{
+ return skb->data;
+}
+
+void t3_register_cpl_handler(unsigned int opcode, cpl_handler_func h);
+
+union listen_entry {
+ struct t3c_tid_entry t3c_tid;
+ union listen_entry *next;
+};
+
+union active_open_entry {
+ struct t3c_tid_entry t3c_tid;
+ union active_open_entry *next;
+};
+
+/*
+ * Holds the size, base address, free list start, etc of the TID, server TID,
+ * and active-open TID tables for a offload device.
+ * The tables themselves are allocated dynamically.
+ */
+struct tid_info {
+ struct t3c_tid_entry *tid_tab;
+ unsigned int ntids;
+ atomic_t tids_in_use;
+
+ union listen_entry *stid_tab;
+ unsigned int nstids;
+ unsigned int stid_base;
+
+ union active_open_entry *atid_tab;
+ unsigned int natids;
+ unsigned int atid_base;
+
+ /*
+ * The following members are accessed R/W so we put them in their own
+ * cache lines.
+ *
+ * XXX We could combine the atid fields above with the lock here since
+ * atids are use once (unlike other tids). OTOH the above fields are
+ * usually in cache due to tid_tab.
+ */
+ spinlock_t atid_lock ____cacheline_aligned_in_smp;
+ union active_open_entry *afree;
+ unsigned int atids_in_use;
+
+ spinlock_t stid_lock ____cacheline_aligned;
+ union listen_entry *sfree;
+ unsigned int stids_in_use;
+};
+
+struct t3c_data {
+ struct list_head list_node;
+ struct t3cdev *dev;
+ unsigned int tx_max_chunk; /* max payload for TX_DATA */
+ unsigned int max_wrs; /* max in-flight WRs per connection */
+ unsigned int nmtus;
+ const unsigned short *mtus;
+ struct tid_info tid_maps;
+
+ struct t3c_tid_entry *tid_release_list;
+ spinlock_t tid_release_lock;
+ struct work_struct tid_release_task;
+};
+
+/*
+ * t3cdev -> t3c_data accessor
+ */
+#define T3C_DATA(dev) (*(struct t3c_data **)&(dev)->l4opt)
+
+#endif
diff --git a/drivers/net/cxgb3/firmware_exports.h b/drivers/net/cxgb3/firmware_exports.h
new file mode 100644
index 00000000000..6a835f6a262
--- /dev/null
+++ b/drivers/net/cxgb3/firmware_exports.h
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2004-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef _FIRMWARE_EXPORTS_H_
+#define _FIRMWARE_EXPORTS_H_
+
+/* WR OPCODES supported by the firmware.
+ */
+#define FW_WROPCODE_FORWARD 0x01
+#define FW_WROPCODE_BYPASS 0x05
+
+#define FW_WROPCODE_TUNNEL_TX_PKT 0x03
+
+#define FW_WROPOCDE_ULPTX_DATA_SGL 0x00
+#define FW_WROPCODE_ULPTX_MEM_READ 0x02
+#define FW_WROPCODE_ULPTX_PKT 0x04
+#define FW_WROPCODE_ULPTX_INVALIDATE 0x06
+
+#define FW_WROPCODE_TUNNEL_RX_PKT 0x07
+
+#define FW_WROPCODE_OFLD_GETTCB_RPL 0x08
+#define FW_WROPCODE_OFLD_CLOSE_CON 0x09
+#define FW_WROPCODE_OFLD_TP_ABORT_CON_REQ 0x0A
+#define FW_WROPCODE_OFLD_HOST_ABORT_CON_RPL 0x0F
+#define FW_WROPCODE_OFLD_HOST_ABORT_CON_REQ 0x0B
+#define FW_WROPCODE_OFLD_TP_ABORT_CON_RPL 0x0C
+#define FW_WROPCODE_OFLD_TX_DATA 0x0D
+#define FW_WROPCODE_OFLD_TX_DATA_ACK 0x0E
+
+#define FW_WROPCODE_RI_RDMA_INIT 0x10
+#define FW_WROPCODE_RI_RDMA_WRITE 0x11
+#define FW_WROPCODE_RI_RDMA_READ_REQ 0x12
+#define FW_WROPCODE_RI_RDMA_READ_RESP 0x13
+#define FW_WROPCODE_RI_SEND 0x14
+#define FW_WROPCODE_RI_TERMINATE 0x15
+#define FW_WROPCODE_RI_RDMA_READ 0x16
+#define FW_WROPCODE_RI_RECEIVE 0x17
+#define FW_WROPCODE_RI_BIND_MW 0x18
+#define FW_WROPCODE_RI_FASTREGISTER_MR 0x19
+#define FW_WROPCODE_RI_LOCAL_INV 0x1A
+#define FW_WROPCODE_RI_MODIFY_QP 0x1B
+#define FW_WROPCODE_RI_BYPASS 0x1C
+
+#define FW_WROPOCDE_RSVD 0x1E
+
+#define FW_WROPCODE_SGE_EGRESSCONTEXT_RR 0x1F
+
+#define FW_WROPCODE_MNGT 0x1D
+#define FW_MNGTOPCODE_PKTSCHED_SET 0x00
+
+/* Maximum size of a WR sent from the host, limited by the SGE.
+ *
+ * Note: WR coming from ULP or TP are only limited by CIM.
+ */
+#define FW_WR_SIZE 128
+
+/* Maximum number of outstanding WRs sent from the host. Value must be
+ * programmed in the CTRL/TUNNEL/QP SGE Egress Context and used by
+ * offload modules to limit the number of WRs per connection.
+ */
+#define FW_T3_WR_NUM 16
+#define FW_N3_WR_NUM 7
+
+#ifndef N3
+# define FW_WR_NUM FW_T3_WR_NUM
+#else
+# define FW_WR_NUM FW_N3_WR_NUM
+#endif
+
+/* FW_TUNNEL_NUM corresponds to the number of supported TUNNEL Queues. These
+ * queues must start at SGE Egress Context FW_TUNNEL_SGEEC_START and must
+ * start at 'TID' (or 'uP Token') FW_TUNNEL_TID_START.
+ *
+ * Ingress Traffic (e.g. DMA completion credit) for TUNNEL Queue[i] is sent
+ * to RESP Queue[i].
+ */
+#define FW_TUNNEL_NUM 8
+#define FW_TUNNEL_SGEEC_START 8
+#define FW_TUNNEL_TID_START 65544
+
+/* FW_CTRL_NUM corresponds to the number of supported CTRL Queues. These queues
+ * must start at SGE Egress Context FW_CTRL_SGEEC_START and must start at 'TID'
+ * (or 'uP Token') FW_CTRL_TID_START.
+ *
+ * Ingress Traffic for CTRL Queue[i] is sent to RESP Queue[i].
+ */
+#define FW_CTRL_NUM 8
+#define FW_CTRL_SGEEC_START 65528
+#define FW_CTRL_TID_START 65536
+
+/* FW_OFLD_NUM corresponds to the number of supported OFFLOAD Queues. These
+ * queues must start at SGE Egress Context FW_OFLD_SGEEC_START.
+ *
+ * Note: the 'uP Token' in the SGE Egress Context fields is irrelevant for
+ * OFFLOAD Queues, as the host is responsible for providing the correct TID in
+ * every WR.
+ *
+ * Ingress Trafffic for OFFLOAD Queue[i] is sent to RESP Queue[i].
+ */
+#define FW_OFLD_NUM 8
+#define FW_OFLD_SGEEC_START 0
+
+/*
+ *
+ */
+#define FW_RI_NUM 1
+#define FW_RI_SGEEC_START 65527
+#define FW_RI_TID_START 65552
+
+/*
+ * The RX_PKT_TID
+ */
+#define FW_RX_PKT_NUM 1
+#define FW_RX_PKT_TID_START 65553
+
+/* FW_WRC_NUM corresponds to the number of Work Request Context that supported
+ * by the firmware.
+ */
+#define FW_WRC_NUM \
+ (65536 + FW_TUNNEL_NUM + FW_CTRL_NUM + FW_RI_NUM + FW_RX_PKT_NUM)
+
+/*
+ * FW type and version.
+ */
+#define S_FW_VERSION_TYPE 28
+#define M_FW_VERSION_TYPE 0xF
+#define V_FW_VERSION_TYPE(x) ((x) << S_FW_VERSION_TYPE)
+#define G_FW_VERSION_TYPE(x) \
+ (((x) >> S_FW_VERSION_TYPE) & M_FW_VERSION_TYPE)
+
+#define S_FW_VERSION_MAJOR 16
+#define M_FW_VERSION_MAJOR 0xFFF
+#define V_FW_VERSION_MAJOR(x) ((x) << S_FW_VERSION_MAJOR)
+#define G_FW_VERSION_MAJOR(x) \
+ (((x) >> S_FW_VERSION_MAJOR) & M_FW_VERSION_MAJOR)
+
+#define S_FW_VERSION_MINOR 8
+#define M_FW_VERSION_MINOR 0xFF
+#define V_FW_VERSION_MINOR(x) ((x) << S_FW_VERSION_MINOR)
+#define G_FW_VERSION_MINOR(x) \
+ (((x) >> S_FW_VERSION_MINOR) & M_FW_VERSION_MINOR)
+
+#define S_FW_VERSION_MICRO 0
+#define M_FW_VERSION_MICRO 0xFF
+#define V_FW_VERSION_MICRO(x) ((x) << S_FW_VERSION_MICRO)
+#define G_FW_VERSION_MICRO(x) \
+ (((x) >> S_FW_VERSION_MICRO) & M_FW_VERSION_MICRO)
+
+#endif /* _FIRMWARE_EXPORTS_H_ */
diff --git a/drivers/net/cxgb3/l2t.c b/drivers/net/cxgb3/l2t.c
new file mode 100644
index 00000000000..d660af74606
--- /dev/null
+++ b/drivers/net/cxgb3/l2t.c
@@ -0,0 +1,449 @@
+/*
+ * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/if.h>
+#include <linux/if_vlan.h>
+#include <linux/jhash.h>
+#include <net/neighbour.h>
+#include "common.h"
+#include "t3cdev.h"
+#include "cxgb3_defs.h"
+#include "l2t.h"
+#include "t3_cpl.h"
+#include "firmware_exports.h"
+
+#define VLAN_NONE 0xfff
+
+/*
+ * Module locking notes: There is a RW lock protecting the L2 table as a
+ * whole plus a spinlock per L2T entry. Entry lookups and allocations happen
+ * under the protection of the table lock, individual entry changes happen
+ * while holding that entry's spinlock. The table lock nests outside the
+ * entry locks. Allocations of new entries take the table lock as writers so
+ * no other lookups can happen while allocating new entries. Entry updates
+ * take the table lock as readers so multiple entries can be updated in
+ * parallel. An L2T entry can be dropped by decrementing its reference count
+ * and therefore can happen in parallel with entry allocation but no entry
+ * can change state or increment its ref count during allocation as both of
+ * these perform lookups.
+ */
+
+static inline unsigned int vlan_prio(const struct l2t_entry *e)
+{
+ return e->vlan >> 13;
+}
+
+static inline unsigned int arp_hash(u32 key, int ifindex,
+ const struct l2t_data *d)
+{
+ return jhash_2words(key, ifindex, 0) & (d->nentries - 1);
+}
+
+static inline void neigh_replace(struct l2t_entry *e, struct neighbour *n)
+{
+ neigh_hold(n);
+ if (e->neigh)
+ neigh_release(e->neigh);
+ e->neigh = n;
+}
+
+/*
+ * Set up an L2T entry and send any packets waiting in the arp queue. The
+ * supplied skb is used for the CPL_L2T_WRITE_REQ. Must be called with the
+ * entry locked.
+ */
+static int setup_l2e_send_pending(struct t3cdev *dev, struct sk_buff *skb,
+ struct l2t_entry *e)
+{
+ struct cpl_l2t_write_req *req;
+
+ if (!skb) {
+ skb = alloc_skb(sizeof(*req), GFP_ATOMIC);
+ if (!skb)
+ return -ENOMEM;
+ }
+
+ req = (struct cpl_l2t_write_req *)__skb_put(skb, sizeof(*req));
+ req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
+ OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, e->idx));
+ req->params = htonl(V_L2T_W_IDX(e->idx) | V_L2T_W_IFF(e->smt_idx) |
+ V_L2T_W_VLAN(e->vlan & VLAN_VID_MASK) |
+ V_L2T_W_PRIO(vlan_prio(e)));
+ memcpy(e->dmac, e->neigh->ha, sizeof(e->dmac));
+ memcpy(req->dst_mac, e->dmac, sizeof(req->dst_mac));
+ skb->priority = CPL_PRIORITY_CONTROL;
+ cxgb3_ofld_send(dev, skb);
+ while (e->arpq_head) {
+ skb = e->arpq_head;
+ e->arpq_head = skb->next;
+ skb->next = NULL;
+ cxgb3_ofld_send(dev, skb);
+ }
+ e->arpq_tail = NULL;
+ e->state = L2T_STATE_VALID;
+
+ return 0;
+}
+
+/*
+ * Add a packet to the an L2T entry's queue of packets awaiting resolution.
+ * Must be called with the entry's lock held.
+ */
+static inline void arpq_enqueue(struct l2t_entry *e, struct sk_buff *skb)
+{
+ skb->next = NULL;
+ if (e->arpq_head)
+ e->arpq_tail->next = skb;
+ else
+ e->arpq_head = skb;
+ e->arpq_tail = skb;
+}
+
+int t3_l2t_send_slow(struct t3cdev *dev, struct sk_buff *skb,
+ struct l2t_entry *e)
+{
+again:
+ switch (e->state) {
+ case L2T_STATE_STALE: /* entry is stale, kick off revalidation */
+ neigh_event_send(e->neigh, NULL);
+ spin_lock_bh(&e->lock);
+ if (e->state == L2T_STATE_STALE)
+ e->state = L2T_STATE_VALID;
+ spin_unlock_bh(&e->lock);
+ case L2T_STATE_VALID: /* fast-path, send the packet on */
+ return cxgb3_ofld_send(dev, skb);
+ case L2T_STATE_RESOLVING:
+ spin_lock_bh(&e->lock);
+ if (e->state != L2T_STATE_RESOLVING) {
+ /* ARP already completed */
+ spin_unlock_bh(&e->lock);
+ goto again;
+ }
+ arpq_enqueue(e, skb);
+ spin_unlock_bh(&e->lock);
+
+ /*
+ * Only the first packet added to the arpq should kick off
+ * resolution. However, because the alloc_skb below can fail,
+ * we allow each packet added to the arpq to retry resolution
+ * as a way of recovering from transient memory exhaustion.
+ * A better way would be to use a work request to retry L2T
+ * entries when there's no memory.
+ */
+ if (!neigh_event_send(e->neigh, NULL)) {
+ skb = alloc_skb(sizeof(struct cpl_l2t_write_req),
+ GFP_ATOMIC);
+ if (!skb)
+ break;
+
+ spin_lock_bh(&e->lock);
+ if (e->arpq_head)
+ setup_l2e_send_pending(dev, skb, e);
+ else /* we lost the race */
+ __kfree_skb(skb);
+ spin_unlock_bh(&e->lock);
+ }
+ }
+ return 0;
+}
+
+EXPORT_SYMBOL(t3_l2t_send_slow);
+
+void t3_l2t_send_event(struct t3cdev *dev, struct l2t_entry *e)
+{
+again:
+ switch (e->state) {
+ case L2T_STATE_STALE: /* entry is stale, kick off revalidation */
+ neigh_event_send(e->neigh, NULL);
+ spin_lock_bh(&e->lock);
+ if (e->state == L2T_STATE_STALE) {
+ e->state = L2T_STATE_VALID;
+ }
+ spin_unlock_bh(&e->lock);
+ return;
+ case L2T_STATE_VALID: /* fast-path, send the packet on */
+ return;
+ case L2T_STATE_RESOLVING:
+ spin_lock_bh(&e->lock);
+ if (e->state != L2T_STATE_RESOLVING) {
+ /* ARP already completed */
+ spin_unlock_bh(&e->lock);
+ goto again;
+ }
+ spin_unlock_bh(&e->lock);
+
+ /*
+ * Only the first packet added to the arpq should kick off
+ * resolution. However, because the alloc_skb below can fail,
+ * we allow each packet added to the arpq to retry resolution
+ * as a way of recovering from transient memory exhaustion.
+ * A better way would be to use a work request to retry L2T
+ * entries when there's no memory.
+ */
+ neigh_event_send(e->neigh, NULL);
+ }
+ return;
+}
+
+EXPORT_SYMBOL(t3_l2t_send_event);
+
+/*
+ * Allocate a free L2T entry. Must be called with l2t_data.lock held.
+ */
+static struct l2t_entry *alloc_l2e(struct l2t_data *d)
+{
+ struct l2t_entry *end, *e, **p;
+
+ if (!atomic_read(&d->nfree))
+ return NULL;
+
+ /* there's definitely a free entry */
+ for (e = d->rover, end = &d->l2tab[d->nentries]; e != end; ++e)
+ if (atomic_read(&e->refcnt) == 0)
+ goto found;
+
+ for (e = &d->l2tab[1]; atomic_read(&e->refcnt); ++e) ;
+found:
+ d->rover = e + 1;
+ atomic_dec(&d->nfree);
+
+ /*
+ * The entry we found may be an inactive entry that is
+ * presently in the hash table. We need to remove it.
+ */
+ if (e->state != L2T_STATE_UNUSED) {
+ int hash = arp_hash(e->addr, e->ifindex, d);
+
+ for (p = &d->l2tab[hash].first; *p; p = &(*p)->next)
+ if (*p == e) {
+ *p = e->next;
+ break;
+ }
+ e->state = L2T_STATE_UNUSED;
+ }
+ return e;
+}
+
+/*
+ * Called when an L2T entry has no more users. The entry is left in the hash
+ * table since it is likely to be reused but we also bump nfree to indicate
+ * that the entry can be reallocated for a different neighbor. We also drop
+ * the existing neighbor reference in case the neighbor is going away and is
+ * waiting on our reference.
+ *
+ * Because entries can be reallocated to other neighbors once their ref count
+ * drops to 0 we need to take the entry's lock to avoid races with a new
+ * incarnation.
+ */
+void t3_l2e_free(struct l2t_data *d, struct l2t_entry *e)
+{
+ spin_lock_bh(&e->lock);
+ if (atomic_read(&e->refcnt) == 0) { /* hasn't been recycled */
+ if (e->neigh) {
+ neigh_release(e->neigh);
+ e->neigh = NULL;
+ }
+ }
+ spin_unlock_bh(&e->lock);
+ atomic_inc(&d->nfree);
+}
+
+EXPORT_SYMBOL(t3_l2e_free);
+
+/*
+ * Update an L2T entry that was previously used for the same next hop as neigh.
+ * Must be called with softirqs disabled.
+ */
+static inline void reuse_entry(struct l2t_entry *e, struct neighbour *neigh)
+{
+ unsigned int nud_state;
+
+ spin_lock(&e->lock); /* avoid race with t3_l2t_free */
+
+ if (neigh != e->neigh)
+ neigh_replace(e, neigh);
+ nud_state = neigh->nud_state;
+ if (memcmp(e->dmac, neigh->ha, sizeof(e->dmac)) ||
+ !(nud_state & NUD_VALID))
+ e->state = L2T_STATE_RESOLVING;
+ else if (nud_state & NUD_CONNECTED)
+ e->state = L2T_STATE_VALID;
+ else
+ e->state = L2T_STATE_STALE;
+ spin_unlock(&e->lock);
+}
+
+struct l2t_entry *t3_l2t_get(struct t3cdev *cdev, struct neighbour *neigh,
+ struct net_device *dev)
+{
+ struct l2t_entry *e;
+ struct l2t_data *d = L2DATA(cdev);
+ u32 addr = *(u32 *) neigh->primary_key;
+ int ifidx = neigh->dev->ifindex;
+ int hash = arp_hash(addr, ifidx, d);
+ struct port_info *p = netdev_priv(dev);
+ int smt_idx = p->port_id;
+
+ write_lock_bh(&d->lock);
+ for (e = d->l2tab[hash].first; e; e = e->next)
+ if (e->addr == addr && e->ifindex == ifidx &&
+ e->smt_idx == smt_idx) {
+ l2t_hold(d, e);
+ if (atomic_read(&e->refcnt) == 1)
+ reuse_entry(e, neigh);
+ goto done;
+ }
+
+ /* Need to allocate a new entry */
+ e = alloc_l2e(d);
+ if (e) {
+ spin_lock(&e->lock); /* avoid race with t3_l2t_free */
+ e->next = d->l2tab[hash].first;
+ d->l2tab[hash].first = e;
+ e->state = L2T_STATE_RESOLVING;
+ e->addr = addr;
+ e->ifindex = ifidx;
+ e->smt_idx = smt_idx;
+ atomic_set(&e->refcnt, 1);
+ neigh_replace(e, neigh);
+ if (neigh->dev->priv_flags & IFF_802_1Q_VLAN)
+ e->vlan = VLAN_DEV_INFO(neigh->dev)->vlan_id;
+ else
+ e->vlan = VLAN_NONE;
+ spin_unlock(&e->lock);
+ }
+done:
+ write_unlock_bh(&d->lock);
+ return e;
+}
+
+EXPORT_SYMBOL(t3_l2t_get);
+
+/*
+ * Called when address resolution fails for an L2T entry to handle packets
+ * on the arpq head. If a packet specifies a failure handler it is invoked,
+ * otherwise the packets is sent to the offload device.
+ *
+ * XXX: maybe we should abandon the latter behavior and just require a failure
+ * handler.
+ */
+static void handle_failed_resolution(struct t3cdev *dev, struct sk_buff *arpq)
+{
+ while (arpq) {
+ struct sk_buff *skb = arpq;
+ struct l2t_skb_cb *cb = L2T_SKB_CB(skb);
+
+ arpq = skb->next;
+ skb->next = NULL;
+ if (cb->arp_failure_handler)
+ cb->arp_failure_handler(dev, skb);
+ else
+ cxgb3_ofld_send(dev, skb);
+ }
+}
+
+/*
+ * Called when the host's ARP layer makes a change to some entry that is
+ * loaded into the HW L2 table.
+ */
+void t3_l2t_update(struct t3cdev *dev, struct neighbour *neigh)
+{
+ struct l2t_entry *e;
+ struct sk_buff *arpq = NULL;
+ struct l2t_data *d = L2DATA(dev);
+ u32 addr = *(u32 *) neigh->primary_key;
+ int ifidx = neigh->dev->ifindex;
+ int hash = arp_hash(addr, ifidx, d);
+
+ read_lock_bh(&d->lock);
+ for (e = d->l2tab[hash].first; e; e = e->next)
+ if (e->addr == addr && e->ifindex == ifidx) {
+ spin_lock(&e->lock);
+ goto found;
+ }
+ read_unlock_bh(&d->lock);
+ return;
+
+found:
+ read_unlock(&d->lock);
+ if (atomic_read(&e->refcnt)) {
+ if (neigh != e->neigh)
+ neigh_replace(e, neigh);
+
+ if (e->state == L2T_STATE_RESOLVING) {
+ if (neigh->nud_state & NUD_FAILED) {
+ arpq = e->arpq_head;
+ e->arpq_head = e->arpq_tail = NULL;
+ } else if (neigh_is_connected(neigh))
+ setup_l2e_send_pending(dev, NULL, e);
+ } else {
+ e->state = neigh_is_connected(neigh) ?
+ L2T_STATE_VALID : L2T_STATE_STALE;
+ if (memcmp(e->dmac, neigh->ha, 6))
+ setup_l2e_send_pending(dev, NULL, e);
+ }
+ }
+ spin_unlock_bh(&e->lock);
+
+ if (arpq)
+ handle_failed_resolution(dev, arpq);
+}
+
+struct l2t_data *t3_init_l2t(unsigned int l2t_capacity)
+{
+ struct l2t_data *d;
+ int i, size = sizeof(*d) + l2t_capacity * sizeof(struct l2t_entry);
+
+ d = cxgb_alloc_mem(size);
+ if (!d)
+ return NULL;
+
+ d->nentries = l2t_capacity;
+ d->rover = &d->l2tab[1]; /* entry 0 is not used */
+ atomic_set(&d->nfree, l2t_capacity - 1);
+ rwlock_init(&d->lock);
+
+ for (i = 0; i < l2t_capacity; ++i) {
+ d->l2tab[i].idx = i;
+ d->l2tab[i].state = L2T_STATE_UNUSED;
+ spin_lock_init(&d->l2tab[i].lock);
+ atomic_set(&d->l2tab[i].refcnt, 0);
+ }
+ return d;
+}
+
+void t3_free_l2t(struct l2t_data *d)
+{
+ cxgb_free_mem(d);
+}
+
diff --git a/drivers/net/cxgb3/l2t.h b/drivers/net/cxgb3/l2t.h
new file mode 100644
index 00000000000..d79001336cf
--- /dev/null
+++ b/drivers/net/cxgb3/l2t.h
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef _CHELSIO_L2T_H
+#define _CHELSIO_L2T_H
+
+#include <linux/spinlock.h>
+#include "t3cdev.h"
+#include <asm/atomic.h>
+
+enum {
+ L2T_STATE_VALID, /* entry is up to date */
+ L2T_STATE_STALE, /* entry may be used but needs revalidation */
+ L2T_STATE_RESOLVING, /* entry needs address resolution */
+ L2T_STATE_UNUSED /* entry not in use */
+};
+
+struct neighbour;
+struct sk_buff;
+
+/*
+ * Each L2T entry plays multiple roles. First of all, it keeps state for the
+ * corresponding entry of the HW L2 table and maintains a queue of offload
+ * packets awaiting address resolution. Second, it is a node of a hash table
+ * chain, where the nodes of the chain are linked together through their next
+ * pointer. Finally, each node is a bucket of a hash table, pointing to the
+ * first element in its chain through its first pointer.
+ */
+struct l2t_entry {
+ u16 state; /* entry state */
+ u16 idx; /* entry index */
+ u32 addr; /* dest IP address */
+ int ifindex; /* neighbor's net_device's ifindex */
+ u16 smt_idx; /* SMT index */
+ u16 vlan; /* VLAN TCI (id: bits 0-11, prio: 13-15 */
+ struct neighbour *neigh; /* associated neighbour */
+ struct l2t_entry *first; /* start of hash chain */
+ struct l2t_entry *next; /* next l2t_entry on chain */
+ struct sk_buff *arpq_head; /* queue of packets awaiting resolution */
+ struct sk_buff *arpq_tail;
+ spinlock_t lock;
+ atomic_t refcnt; /* entry reference count */
+ u8 dmac[6]; /* neighbour's MAC address */
+};
+
+struct l2t_data {
+ unsigned int nentries; /* number of entries */
+ struct l2t_entry *rover; /* starting point for next allocation */
+ atomic_t nfree; /* number of free entries */
+ rwlock_t lock;
+ struct l2t_entry l2tab[0];
+};
+
+typedef void (*arp_failure_handler_func)(struct t3cdev * dev,
+ struct sk_buff * skb);
+
+/*
+ * Callback stored in an skb to handle address resolution failure.
+ */
+struct l2t_skb_cb {
+ arp_failure_handler_func arp_failure_handler;
+};
+
+#define L2T_SKB_CB(skb) ((struct l2t_skb_cb *)(skb)->cb)
+
+static inline void set_arp_failure_handler(struct sk_buff *skb,
+ arp_failure_handler_func hnd)
+{
+ L2T_SKB_CB(skb)->arp_failure_handler = hnd;
+}
+
+/*
+ * Getting to the L2 data from an offload device.
+ */
+#define L2DATA(dev) ((dev)->l2opt)
+
+#define W_TCB_L2T_IX 0
+#define S_TCB_L2T_IX 7
+#define M_TCB_L2T_IX 0x7ffULL
+#define V_TCB_L2T_IX(x) ((x) << S_TCB_L2T_IX)
+
+void t3_l2e_free(struct l2t_data *d, struct l2t_entry *e);
+void t3_l2t_update(struct t3cdev *dev, struct neighbour *neigh);
+struct l2t_entry *t3_l2t_get(struct t3cdev *cdev, struct neighbour *neigh,
+ struct net_device *dev);
+int t3_l2t_send_slow(struct t3cdev *dev, struct sk_buff *skb,
+ struct l2t_entry *e);
+void t3_l2t_send_event(struct t3cdev *dev, struct l2t_entry *e);
+struct l2t_data *t3_init_l2t(unsigned int l2t_capacity);
+void t3_free_l2t(struct l2t_data *d);
+
+int cxgb3_ofld_send(struct t3cdev *dev, struct sk_buff *skb);
+
+static inline int l2t_send(struct t3cdev *dev, struct sk_buff *skb,
+ struct l2t_entry *e)
+{
+ if (likely(e->state == L2T_STATE_VALID))
+ return cxgb3_ofld_send(dev, skb);
+ return t3_l2t_send_slow(dev, skb, e);
+}
+
+static inline void l2t_release(struct l2t_data *d, struct l2t_entry *e)
+{
+ if (atomic_dec_and_test(&e->refcnt))
+ t3_l2e_free(d, e);
+}
+
+static inline void l2t_hold(struct l2t_data *d, struct l2t_entry *e)
+{
+ if (atomic_add_return(1, &e->refcnt) == 1) /* 0 -> 1 transition */
+ atomic_dec(&d->nfree);
+}
+
+#endif
diff --git a/drivers/net/cxgb3/mc5.c b/drivers/net/cxgb3/mc5.c
new file mode 100644
index 00000000000..644d62ea86a
--- /dev/null
+++ b/drivers/net/cxgb3/mc5.c
@@ -0,0 +1,473 @@
+/*
+ * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include "common.h"
+#include "regs.h"
+
+enum {
+ IDT75P52100 = 4,
+ IDT75N43102 = 5
+};
+
+/* DBGI command mode */
+enum {
+ DBGI_MODE_MBUS = 0,
+ DBGI_MODE_IDT52100 = 5
+};
+
+/* IDT 75P52100 commands */
+#define IDT_CMD_READ 0
+#define IDT_CMD_WRITE 1
+#define IDT_CMD_SEARCH 2
+#define IDT_CMD_LEARN 3
+
+/* IDT LAR register address and value for 144-bit mode (low 32 bits) */
+#define IDT_LAR_ADR0 0x180006
+#define IDT_LAR_MODE144 0xffff0000
+
+/* IDT SCR and SSR addresses (low 32 bits) */
+#define IDT_SCR_ADR0 0x180000
+#define IDT_SSR0_ADR0 0x180002
+#define IDT_SSR1_ADR0 0x180004
+
+/* IDT GMR base address (low 32 bits) */
+#define IDT_GMR_BASE_ADR0 0x180020
+
+/* IDT data and mask array base addresses (low 32 bits) */
+#define IDT_DATARY_BASE_ADR0 0
+#define IDT_MSKARY_BASE_ADR0 0x80000
+
+/* IDT 75N43102 commands */
+#define IDT4_CMD_SEARCH144 3
+#define IDT4_CMD_WRITE 4
+#define IDT4_CMD_READ 5
+
+/* IDT 75N43102 SCR address (low 32 bits) */
+#define IDT4_SCR_ADR0 0x3
+
+/* IDT 75N43102 GMR base addresses (low 32 bits) */
+#define IDT4_GMR_BASE0 0x10
+#define IDT4_GMR_BASE1 0x20
+#define IDT4_GMR_BASE2 0x30
+
+/* IDT 75N43102 data and mask array base addresses (low 32 bits) */
+#define IDT4_DATARY_BASE_ADR0 0x1000000
+#define IDT4_MSKARY_BASE_ADR0 0x2000000
+
+#define MAX_WRITE_ATTEMPTS 5
+
+#define MAX_ROUTES 2048
+
+/*
+ * Issue a command to the TCAM and wait for its completion. The address and
+ * any data required by the command must have been setup by the caller.
+ */
+static int mc5_cmd_write(struct adapter *adapter, u32 cmd)
+{
+ t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_CMD, cmd);
+ return t3_wait_op_done(adapter, A_MC5_DB_DBGI_RSP_STATUS,
+ F_DBGIRSPVALID, 1, MAX_WRITE_ATTEMPTS, 1);
+}
+
+static inline void dbgi_wr_addr3(struct adapter *adapter, u32 v1, u32 v2,
+ u32 v3)
+{
+ t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_ADDR0, v1);
+ t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_ADDR1, v2);
+ t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_ADDR2, v3);
+}
+
+static inline void dbgi_wr_data3(struct adapter *adapter, u32 v1, u32 v2,
+ u32 v3)
+{
+ t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_DATA0, v1);
+ t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_DATA1, v2);
+ t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_DATA2, v3);
+}
+
+static inline void dbgi_rd_rsp3(struct adapter *adapter, u32 *v1, u32 *v2,
+ u32 *v3)
+{
+ *v1 = t3_read_reg(adapter, A_MC5_DB_DBGI_RSP_DATA0);
+ *v2 = t3_read_reg(adapter, A_MC5_DB_DBGI_RSP_DATA1);
+ *v3 = t3_read_reg(adapter, A_MC5_DB_DBGI_RSP_DATA2);
+}
+
+/*
+ * Write data to the TCAM register at address (0, 0, addr_lo) using the TCAM
+ * command cmd. The data to be written must have been set up by the caller.
+ * Returns -1 on failure, 0 on success.
+ */
+static int mc5_write(struct adapter *adapter, u32 addr_lo, u32 cmd)
+{
+ t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_ADDR0, addr_lo);
+ if (mc5_cmd_write(adapter, cmd) == 0)
+ return 0;
+ CH_ERR(adapter, "MC5 timeout writing to TCAM address 0x%x\n",
+ addr_lo);
+ return -1;
+}
+
+static int init_mask_data_array(struct mc5 *mc5, u32 mask_array_base,
+ u32 data_array_base, u32 write_cmd,
+ int addr_shift)
+{
+ unsigned int i;
+ struct adapter *adap = mc5->adapter;
+
+ /*
+ * We need the size of the TCAM data and mask arrays in terms of
+ * 72-bit entries.
+ */
+ unsigned int size72 = mc5->tcam_size;
+ unsigned int server_base = t3_read_reg(adap, A_MC5_DB_SERVER_INDEX);
+
+ if (mc5->mode == MC5_MODE_144_BIT) {
+ size72 *= 2; /* 1 144-bit entry is 2 72-bit entries */
+ server_base *= 2;
+ }
+
+ /* Clear the data array */
+ dbgi_wr_data3(adap, 0, 0, 0);
+ for (i = 0; i < size72; i++)
+ if (mc5_write(adap, data_array_base + (i << addr_shift),
+ write_cmd))
+ return -1;
+
+ /* Initialize the mask array. */
+ dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0xff);
+ for (i = 0; i < size72; i++) {
+ if (i == server_base) /* entering server or routing region */
+ t3_write_reg(adap, A_MC5_DB_DBGI_REQ_DATA0,
+ mc5->mode == MC5_MODE_144_BIT ?
+ 0xfffffff9 : 0xfffffffd);
+ if (mc5_write(adap, mask_array_base + (i << addr_shift),
+ write_cmd))
+ return -1;
+ }
+ return 0;
+}
+
+static int init_idt52100(struct mc5 *mc5)
+{
+ int i;
+ struct adapter *adap = mc5->adapter;
+
+ t3_write_reg(adap, A_MC5_DB_RSP_LATENCY,
+ V_RDLAT(0x15) | V_LRNLAT(0x15) | V_SRCHLAT(0x15));
+ t3_write_reg(adap, A_MC5_DB_PART_ID_INDEX, 2);
+
+ /*
+ * Use GMRs 14-15 for ELOOKUP, GMRs 12-13 for SYN lookups, and
+ * GMRs 8-9 for ACK- and AOPEN searches.
+ */
+ t3_write_reg(adap, A_MC5_DB_POPEN_DATA_WR_CMD, IDT_CMD_WRITE);
+ t3_write_reg(adap, A_MC5_DB_POPEN_MASK_WR_CMD, IDT_CMD_WRITE);
+ t3_write_reg(adap, A_MC5_DB_AOPEN_SRCH_CMD, IDT_CMD_SEARCH);
+ t3_write_reg(adap, A_MC5_DB_AOPEN_LRN_CMD, IDT_CMD_LEARN);
+ t3_write_reg(adap, A_MC5_DB_SYN_SRCH_CMD, IDT_CMD_SEARCH | 0x6000);
+ t3_write_reg(adap, A_MC5_DB_SYN_LRN_CMD, IDT_CMD_LEARN);
+ t3_write_reg(adap, A_MC5_DB_ACK_SRCH_CMD, IDT_CMD_SEARCH);
+ t3_write_reg(adap, A_MC5_DB_ACK_LRN_CMD, IDT_CMD_LEARN);
+ t3_write_reg(adap, A_MC5_DB_ILOOKUP_CMD, IDT_CMD_SEARCH);
+ t3_write_reg(adap, A_MC5_DB_ELOOKUP_CMD, IDT_CMD_SEARCH | 0x7000);
+ t3_write_reg(adap, A_MC5_DB_DATA_WRITE_CMD, IDT_CMD_WRITE);
+ t3_write_reg(adap, A_MC5_DB_DATA_READ_CMD, IDT_CMD_READ);
+
+ /* Set DBGI command mode for IDT TCAM. */
+ t3_write_reg(adap, A_MC5_DB_DBGI_CONFIG, DBGI_MODE_IDT52100);
+
+ /* Set up LAR */
+ dbgi_wr_data3(adap, IDT_LAR_MODE144, 0, 0);
+ if (mc5_write(adap, IDT_LAR_ADR0, IDT_CMD_WRITE))
+ goto err;
+
+ /* Set up SSRs */
+ dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0);
+ if (mc5_write(adap, IDT_SSR0_ADR0, IDT_CMD_WRITE) ||
+ mc5_write(adap, IDT_SSR1_ADR0, IDT_CMD_WRITE))
+ goto err;
+
+ /* Set up GMRs */
+ for (i = 0; i < 32; ++i) {
+ if (i >= 12 && i < 15)
+ dbgi_wr_data3(adap, 0xfffffff9, 0xffffffff, 0xff);
+ else if (i == 15)
+ dbgi_wr_data3(adap, 0xfffffff9, 0xffff8007, 0xff);
+ else
+ dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0xff);
+
+ if (mc5_write(adap, IDT_GMR_BASE_ADR0 + i, IDT_CMD_WRITE))
+ goto err;
+ }
+
+ /* Set up SCR */
+ dbgi_wr_data3(adap, 1, 0, 0);
+ if (mc5_write(adap, IDT_SCR_ADR0, IDT_CMD_WRITE))
+ goto err;
+
+ return init_mask_data_array(mc5, IDT_MSKARY_BASE_ADR0,
+ IDT_DATARY_BASE_ADR0, IDT_CMD_WRITE, 0);
+err:
+ return -EIO;
+}
+
+static int init_idt43102(struct mc5 *mc5)
+{
+ int i;
+ struct adapter *adap = mc5->adapter;
+
+ t3_write_reg(adap, A_MC5_DB_RSP_LATENCY,
+ adap->params.rev == 0 ? V_RDLAT(0xd) | V_SRCHLAT(0x11) :
+ V_RDLAT(0xd) | V_SRCHLAT(0x12));
+
+ /*
+ * Use GMRs 24-25 for ELOOKUP, GMRs 20-21 for SYN lookups, and no mask
+ * for ACK- and AOPEN searches.
+ */
+ t3_write_reg(adap, A_MC5_DB_POPEN_DATA_WR_CMD, IDT4_CMD_WRITE);
+ t3_write_reg(adap, A_MC5_DB_POPEN_MASK_WR_CMD, IDT4_CMD_WRITE);
+ t3_write_reg(adap, A_MC5_DB_AOPEN_SRCH_CMD,
+ IDT4_CMD_SEARCH144 | 0x3800);
+ t3_write_reg(adap, A_MC5_DB_SYN_SRCH_CMD, IDT4_CMD_SEARCH144);
+ t3_write_reg(adap, A_MC5_DB_ACK_SRCH_CMD, IDT4_CMD_SEARCH144 | 0x3800);
+ t3_write_reg(adap, A_MC5_DB_ILOOKUP_CMD, IDT4_CMD_SEARCH144 | 0x3800);
+ t3_write_reg(adap, A_MC5_DB_ELOOKUP_CMD, IDT4_CMD_SEARCH144 | 0x800);
+ t3_write_reg(adap, A_MC5_DB_DATA_WRITE_CMD, IDT4_CMD_WRITE);
+ t3_write_reg(adap, A_MC5_DB_DATA_READ_CMD, IDT4_CMD_READ);
+
+ t3_write_reg(adap, A_MC5_DB_PART_ID_INDEX, 3);
+
+ /* Set DBGI command mode for IDT TCAM. */
+ t3_write_reg(adap, A_MC5_DB_DBGI_CONFIG, DBGI_MODE_IDT52100);
+
+ /* Set up GMRs */
+ dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0xff);
+ for (i = 0; i < 7; ++i)
+ if (mc5_write(adap, IDT4_GMR_BASE0 + i, IDT4_CMD_WRITE))
+ goto err;
+
+ for (i = 0; i < 4; ++i)
+ if (mc5_write(adap, IDT4_GMR_BASE2 + i, IDT4_CMD_WRITE))
+ goto err;
+
+ dbgi_wr_data3(adap, 0xfffffff9, 0xffffffff, 0xff);
+ if (mc5_write(adap, IDT4_GMR_BASE1, IDT4_CMD_WRITE) ||
+ mc5_write(adap, IDT4_GMR_BASE1 + 1, IDT4_CMD_WRITE) ||
+ mc5_write(adap, IDT4_GMR_BASE1 + 4, IDT4_CMD_WRITE))
+ goto err;
+
+ dbgi_wr_data3(adap, 0xfffffff9, 0xffff8007, 0xff);
+ if (mc5_write(adap, IDT4_GMR_BASE1 + 5, IDT4_CMD_WRITE))
+ goto err;
+
+ /* Set up SCR */
+ dbgi_wr_data3(adap, 0xf0000000, 0, 0);
+ if (mc5_write(adap, IDT4_SCR_ADR0, IDT4_CMD_WRITE))
+ goto err;
+
+ return init_mask_data_array(mc5, IDT4_MSKARY_BASE_ADR0,
+ IDT4_DATARY_BASE_ADR0, IDT4_CMD_WRITE, 1);
+err:
+ return -EIO;
+}
+
+/* Put MC5 in DBGI mode. */
+static inline void mc5_dbgi_mode_enable(const struct mc5 *mc5)
+{
+ t3_write_reg(mc5->adapter, A_MC5_DB_CONFIG,
+ V_TMMODE(mc5->mode == MC5_MODE_72_BIT) | F_DBGIEN);
+}
+
+/* Put MC5 in M-Bus mode. */
+static void mc5_dbgi_mode_disable(const struct mc5 *mc5)
+{
+ t3_write_reg(mc5->adapter, A_MC5_DB_CONFIG,
+ V_TMMODE(mc5->mode == MC5_MODE_72_BIT) |
+ V_COMPEN(mc5->mode == MC5_MODE_72_BIT) |
+ V_PRTYEN(mc5->parity_enabled) | F_MBUSEN);
+}
+
+/*
+ * Initialization that requires the OS and protocol layers to already
+ * be intialized goes here.
+ */
+int t3_mc5_init(struct mc5 *mc5, unsigned int nservers, unsigned int nfilters,
+ unsigned int nroutes)
+{
+ u32 cfg;
+ int err;
+ unsigned int tcam_size = mc5->tcam_size;
+ struct adapter *adap = mc5->adapter;
+
+ if (nroutes > MAX_ROUTES || nroutes + nservers + nfilters > tcam_size)
+ return -EINVAL;
+
+ /* Reset the TCAM */
+ cfg = t3_read_reg(adap, A_MC5_DB_CONFIG) & ~F_TMMODE;
+ cfg |= V_TMMODE(mc5->mode == MC5_MODE_72_BIT) | F_TMRST;
+ t3_write_reg(adap, A_MC5_DB_CONFIG, cfg);
+ if (t3_wait_op_done(adap, A_MC5_DB_CONFIG, F_TMRDY, 1, 500, 0)) {
+ CH_ERR(adap, "TCAM reset timed out\n");
+ return -1;
+ }
+
+ t3_write_reg(adap, A_MC5_DB_ROUTING_TABLE_INDEX, tcam_size - nroutes);
+ t3_write_reg(adap, A_MC5_DB_FILTER_TABLE,
+ tcam_size - nroutes - nfilters);
+ t3_write_reg(adap, A_MC5_DB_SERVER_INDEX,
+ tcam_size - nroutes - nfilters - nservers);
+
+ mc5->parity_enabled = 1;
+
+ /* All the TCAM addresses we access have only the low 32 bits non 0 */
+ t3_write_reg(adap, A_MC5_DB_DBGI_REQ_ADDR1, 0);
+ t3_write_reg(adap, A_MC5_DB_DBGI_REQ_ADDR2, 0);
+
+ mc5_dbgi_mode_enable(mc5);
+
+ switch (mc5->part_type) {
+ case IDT75P52100:
+ err = init_idt52100(mc5);
+ break;
+ case IDT75N43102:
+ err = init_idt43102(mc5);
+ break;
+ default:
+ CH_ERR(adap, "Unsupported TCAM type %d\n", mc5->part_type);
+ err = -EINVAL;
+ break;
+ }
+
+ mc5_dbgi_mode_disable(mc5);
+ return err;
+}
+
+/*
+ * read_mc5_range - dump a part of the memory managed by MC5
+ * @mc5: the MC5 handle
+ * @start: the start address for the dump
+ * @n: number of 72-bit words to read
+ * @buf: result buffer
+ *
+ * Read n 72-bit words from MC5 memory from the given start location.
+ */
+int t3_read_mc5_range(const struct mc5 *mc5, unsigned int start,
+ unsigned int n, u32 *buf)
+{
+ u32 read_cmd;
+ int err = 0;
+ struct adapter *adap = mc5->adapter;
+
+ if (mc5->part_type == IDT75P52100)
+ read_cmd = IDT_CMD_READ;
+ else if (mc5->part_type == IDT75N43102)
+ read_cmd = IDT4_CMD_READ;
+ else
+ return -EINVAL;
+
+ mc5_dbgi_mode_enable(mc5);
+
+ while (n--) {
+ t3_write_reg(adap, A_MC5_DB_DBGI_REQ_ADDR0, start++);
+ if (mc5_cmd_write(adap, read_cmd)) {
+ err = -EIO;
+ break;
+ }
+ dbgi_rd_rsp3(adap, buf + 2, buf + 1, buf);
+ buf += 3;
+ }
+
+ mc5_dbgi_mode_disable(mc5);
+ return 0;
+}
+
+#define MC5_INT_FATAL (F_PARITYERR | F_REQQPARERR | F_DISPQPARERR)
+
+/*
+ * MC5 interrupt handler
+ */
+void t3_mc5_intr_handler(struct mc5 *mc5)
+{
+ struct adapter *adap = mc5->adapter;
+ u32 cause = t3_read_reg(adap, A_MC5_DB_INT_CAUSE);
+
+ if ((cause & F_PARITYERR) && mc5->parity_enabled) {
+ CH_ALERT(adap, "MC5 parity error\n");
+ mc5->stats.parity_err++;
+ }
+
+ if (cause & F_REQQPARERR) {
+ CH_ALERT(adap, "MC5 request queue parity error\n");
+ mc5->stats.reqq_parity_err++;
+ }
+
+ if (cause & F_DISPQPARERR) {
+ CH_ALERT(adap, "MC5 dispatch queue parity error\n");
+ mc5->stats.dispq_parity_err++;
+ }
+
+ if (cause & F_ACTRGNFULL)
+ mc5->stats.active_rgn_full++;
+ if (cause & F_NFASRCHFAIL)
+ mc5->stats.nfa_srch_err++;
+ if (cause & F_UNKNOWNCMD)
+ mc5->stats.unknown_cmd++;
+ if (cause & F_DELACTEMPTY)
+ mc5->stats.del_act_empty++;
+ if (cause & MC5_INT_FATAL)
+ t3_fatal_err(adap);
+
+ t3_write_reg(adap, A_MC5_DB_INT_CAUSE, cause);
+}
+
+void __devinit t3_mc5_prep(struct adapter *adapter, struct mc5 *mc5, int mode)
+{
+#define K * 1024
+
+ static unsigned int tcam_part_size[] = { /* in K 72-bit entries */
+ 64 K, 128 K, 256 K, 32 K
+ };
+
+#undef K
+
+ u32 cfg = t3_read_reg(adapter, A_MC5_DB_CONFIG);
+
+ mc5->adapter = adapter;
+ mc5->mode = (unsigned char)mode;
+ mc5->part_type = (unsigned char)G_TMTYPE(cfg);
+ if (cfg & F_TMTYPEHI)
+ mc5->part_type |= 4;
+
+ mc5->tcam_size = tcam_part_size[G_TMPARTSIZE(cfg)];
+ if (mode == MC5_MODE_144_BIT)
+ mc5->tcam_size /= 2;
+}
diff --git a/drivers/net/cxgb3/regs.h b/drivers/net/cxgb3/regs.h
new file mode 100644
index 00000000000..b56c5f52bcd
--- /dev/null
+++ b/drivers/net/cxgb3/regs.h
@@ -0,0 +1,2195 @@
+#define A_SG_CONTROL 0x0
+
+#define S_DROPPKT 20
+#define V_DROPPKT(x) ((x) << S_DROPPKT)
+#define F_DROPPKT V_DROPPKT(1U)
+
+#define S_EGRGENCTRL 19
+#define V_EGRGENCTRL(x) ((x) << S_EGRGENCTRL)
+#define F_EGRGENCTRL V_EGRGENCTRL(1U)
+
+#define S_USERSPACESIZE 14
+#define M_USERSPACESIZE 0x1f
+#define V_USERSPACESIZE(x) ((x) << S_USERSPACESIZE)
+
+#define S_HOSTPAGESIZE 11
+#define M_HOSTPAGESIZE 0x7
+#define V_HOSTPAGESIZE(x) ((x) << S_HOSTPAGESIZE)
+
+#define S_FLMODE 9
+#define V_FLMODE(x) ((x) << S_FLMODE)
+#define F_FLMODE V_FLMODE(1U)
+
+#define S_PKTSHIFT 6
+#define M_PKTSHIFT 0x7
+#define V_PKTSHIFT(x) ((x) << S_PKTSHIFT)
+
+#define S_ONEINTMULTQ 5
+#define V_ONEINTMULTQ(x) ((x) << S_ONEINTMULTQ)
+#define F_ONEINTMULTQ V_ONEINTMULTQ(1U)
+
+#define S_BIGENDIANINGRESS 2
+#define V_BIGENDIANINGRESS(x) ((x) << S_BIGENDIANINGRESS)
+#define F_BIGENDIANINGRESS V_BIGENDIANINGRESS(1U)
+
+#define S_ISCSICOALESCING 1
+#define V_ISCSICOALESCING(x) ((x) << S_ISCSICOALESCING)
+#define F_ISCSICOALESCING V_ISCSICOALESCING(1U)
+
+#define S_GLOBALENABLE 0
+#define V_GLOBALENABLE(x) ((x) << S_GLOBALENABLE)
+#define F_GLOBALENABLE V_GLOBALENABLE(1U)
+
+#define S_AVOIDCQOVFL 24
+#define V_AVOIDCQOVFL(x) ((x) << S_AVOIDCQOVFL)
+#define F_AVOIDCQOVFL V_AVOIDCQOVFL(1U)
+
+#define S_OPTONEINTMULTQ 23
+#define V_OPTONEINTMULTQ(x) ((x) << S_OPTONEINTMULTQ)
+#define F_OPTONEINTMULTQ V_OPTONEINTMULTQ(1U)
+
+#define S_CQCRDTCTRL 22
+#define V_CQCRDTCTRL(x) ((x) << S_CQCRDTCTRL)
+#define F_CQCRDTCTRL V_CQCRDTCTRL(1U)
+
+#define A_SG_KDOORBELL 0x4
+
+#define S_SELEGRCNTX 31
+#define V_SELEGRCNTX(x) ((x) << S_SELEGRCNTX)
+#define F_SELEGRCNTX V_SELEGRCNTX(1U)
+
+#define S_EGRCNTX 0
+#define M_EGRCNTX 0xffff
+#define V_EGRCNTX(x) ((x) << S_EGRCNTX)
+
+#define A_SG_GTS 0x8
+
+#define S_RSPQ 29
+#define M_RSPQ 0x7
+#define V_RSPQ(x) ((x) << S_RSPQ)
+#define G_RSPQ(x) (((x) >> S_RSPQ) & M_RSPQ)
+
+#define S_NEWTIMER 16
+#define M_NEWTIMER 0x1fff
+#define V_NEWTIMER(x) ((x) << S_NEWTIMER)
+
+#define S_NEWINDEX 0
+#define M_NEWINDEX 0xffff
+#define V_NEWINDEX(x) ((x) << S_NEWINDEX)
+
+#define A_SG_CONTEXT_CMD 0xc
+
+#define S_CONTEXT_CMD_OPCODE 28
+#define M_CONTEXT_CMD_OPCODE 0xf
+#define V_CONTEXT_CMD_OPCODE(x) ((x) << S_CONTEXT_CMD_OPCODE)
+
+#define S_CONTEXT_CMD_BUSY 27
+#define V_CONTEXT_CMD_BUSY(x) ((x) << S_CONTEXT_CMD_BUSY)
+#define F_CONTEXT_CMD_BUSY V_CONTEXT_CMD_BUSY(1U)
+
+#define S_CQ_CREDIT 20
+
+#define M_CQ_CREDIT 0x7f
+
+#define V_CQ_CREDIT(x) ((x) << S_CQ_CREDIT)
+
+#define G_CQ_CREDIT(x) (((x) >> S_CQ_CREDIT) & M_CQ_CREDIT)
+
+#define S_CQ 19
+
+#define V_CQ(x) ((x) << S_CQ)
+#define F_CQ V_CQ(1U)
+
+#define S_RESPONSEQ 18
+#define V_RESPONSEQ(x) ((x) << S_RESPONSEQ)
+#define F_RESPONSEQ V_RESPONSEQ(1U)
+
+#define S_EGRESS 17
+#define V_EGRESS(x) ((x) << S_EGRESS)
+#define F_EGRESS V_EGRESS(1U)
+
+#define S_FREELIST 16
+#define V_FREELIST(x) ((x) << S_FREELIST)
+#define F_FREELIST V_FREELIST(1U)
+
+#define S_CONTEXT 0
+#define M_CONTEXT 0xffff
+#define V_CONTEXT(x) ((x) << S_CONTEXT)
+
+#define G_CONTEXT(x) (((x) >> S_CONTEXT) & M_CONTEXT)
+
+#define A_SG_CONTEXT_DATA0 0x10
+
+#define A_SG_CONTEXT_DATA1 0x14
+
+#define A_SG_CONTEXT_DATA2 0x18
+
+#define A_SG_CONTEXT_DATA3 0x1c
+
+#define A_SG_CONTEXT_MASK0 0x20
+
+#define A_SG_CONTEXT_MASK1 0x24
+
+#define A_SG_CONTEXT_MASK2 0x28
+
+#define A_SG_CONTEXT_MASK3 0x2c
+
+#define A_SG_RSPQ_CREDIT_RETURN 0x30
+
+#define S_CREDITS 0
+#define M_CREDITS 0xffff
+#define V_CREDITS(x) ((x) << S_CREDITS)
+
+#define A_SG_DATA_INTR 0x34
+
+#define S_ERRINTR 31
+#define V_ERRINTR(x) ((x) << S_ERRINTR)
+#define F_ERRINTR V_ERRINTR(1U)
+
+#define A_SG_HI_DRB_HI_THRSH 0x38
+
+#define A_SG_HI_DRB_LO_THRSH 0x3c
+
+#define A_SG_LO_DRB_HI_THRSH 0x40
+
+#define A_SG_LO_DRB_LO_THRSH 0x44
+
+#define A_SG_RSPQ_FL_STATUS 0x4c
+
+#define S_RSPQ0DISABLED 8
+
+#define A_SG_EGR_RCQ_DRB_THRSH 0x54
+
+#define S_HIRCQDRBTHRSH 16
+#define M_HIRCQDRBTHRSH 0x7ff
+#define V_HIRCQDRBTHRSH(x) ((x) << S_HIRCQDRBTHRSH)
+
+#define S_LORCQDRBTHRSH 0
+#define M_LORCQDRBTHRSH 0x7ff
+#define V_LORCQDRBTHRSH(x) ((x) << S_LORCQDRBTHRSH)
+
+#define A_SG_EGR_CNTX_BADDR 0x58
+
+#define A_SG_INT_CAUSE 0x5c
+
+#define S_RSPQDISABLED 3
+#define V_RSPQDISABLED(x) ((x) << S_RSPQDISABLED)
+#define F_RSPQDISABLED V_RSPQDISABLED(1U)
+
+#define S_RSPQCREDITOVERFOW 2
+#define V_RSPQCREDITOVERFOW(x) ((x) << S_RSPQCREDITOVERFOW)
+#define F_RSPQCREDITOVERFOW V_RSPQCREDITOVERFOW(1U)
+
+#define A_SG_INT_ENABLE 0x60
+
+#define A_SG_CMDQ_CREDIT_TH 0x64
+
+#define S_TIMEOUT 8
+#define M_TIMEOUT 0xffffff
+#define V_TIMEOUT(x) ((x) << S_TIMEOUT)
+
+#define S_THRESHOLD 0
+#define M_THRESHOLD 0xff
+#define V_THRESHOLD(x) ((x) << S_THRESHOLD)
+
+#define A_SG_TIMER_TICK 0x68
+
+#define A_SG_CQ_CONTEXT_BADDR 0x6c
+
+#define A_SG_OCO_BASE 0x70
+
+#define S_BASE1 16
+#define M_BASE1 0xffff
+#define V_BASE1(x) ((x) << S_BASE1)
+
+#define A_SG_DRB_PRI_THRESH 0x74
+
+#define A_PCIX_INT_ENABLE 0x80
+
+#define S_MSIXPARERR 22
+#define M_MSIXPARERR 0x7
+
+#define V_MSIXPARERR(x) ((x) << S_MSIXPARERR)
+
+#define S_CFPARERR 18
+#define M_CFPARERR 0xf
+
+#define V_CFPARERR(x) ((x) << S_CFPARERR)
+
+#define S_RFPARERR 14
+#define M_RFPARERR 0xf
+
+#define V_RFPARERR(x) ((x) << S_RFPARERR)
+
+#define S_WFPARERR 12
+#define M_WFPARERR 0x3
+
+#define V_WFPARERR(x) ((x) << S_WFPARERR)
+
+#define S_PIOPARERR 11
+#define V_PIOPARERR(x) ((x) << S_PIOPARERR)
+#define F_PIOPARERR V_PIOPARERR(1U)
+
+#define S_DETUNCECCERR 10
+#define V_DETUNCECCERR(x) ((x) << S_DETUNCECCERR)
+#define F_DETUNCECCERR V_DETUNCECCERR(1U)
+
+#define S_DETCORECCERR 9
+#define V_DETCORECCERR(x) ((x) << S_DETCORECCERR)
+#define F_DETCORECCERR V_DETCORECCERR(1U)
+
+#define S_RCVSPLCMPERR 8
+#define V_RCVSPLCMPERR(x) ((x) << S_RCVSPLCMPERR)
+#define F_RCVSPLCMPERR V_RCVSPLCMPERR(1U)
+
+#define S_UNXSPLCMP 7
+#define V_UNXSPLCMP(x) ((x) << S_UNXSPLCMP)
+#define F_UNXSPLCMP V_UNXSPLCMP(1U)
+
+#define S_SPLCMPDIS 6
+#define V_SPLCMPDIS(x) ((x) << S_SPLCMPDIS)
+#define F_SPLCMPDIS V_SPLCMPDIS(1U)
+
+#define S_DETPARERR 5
+#define V_DETPARERR(x) ((x) << S_DETPARERR)
+#define F_DETPARERR V_DETPARERR(1U)
+
+#define S_SIGSYSERR 4
+#define V_SIGSYSERR(x) ((x) << S_SIGSYSERR)
+#define F_SIGSYSERR V_SIGSYSERR(1U)
+
+#define S_RCVMSTABT 3
+#define V_RCVMSTABT(x) ((x) << S_RCVMSTABT)
+#define F_RCVMSTABT V_RCVMSTABT(1U)
+
+#define S_RCVTARABT 2
+#define V_RCVTARABT(x) ((x) << S_RCVTARABT)
+#define F_RCVTARABT V_RCVTARABT(1U)
+
+#define S_SIGTARABT 1
+#define V_SIGTARABT(x) ((x) << S_SIGTARABT)
+#define F_SIGTARABT V_SIGTARABT(1U)
+
+#define S_MSTDETPARERR 0
+#define V_MSTDETPARERR(x) ((x) << S_MSTDETPARERR)
+#define F_MSTDETPARERR V_MSTDETPARERR(1U)
+
+#define A_PCIX_INT_CAUSE 0x84
+
+#define A_PCIX_CFG 0x88
+
+#define S_CLIDECEN 18
+#define V_CLIDECEN(x) ((x) << S_CLIDECEN)
+#define F_CLIDECEN V_CLIDECEN(1U)
+
+#define A_PCIX_MODE 0x8c
+
+#define S_PCLKRANGE 6
+#define M_PCLKRANGE 0x3
+#define V_PCLKRANGE(x) ((x) << S_PCLKRANGE)
+#define G_PCLKRANGE(x) (((x) >> S_PCLKRANGE) & M_PCLKRANGE)
+
+#define S_PCIXINITPAT 2
+#define M_PCIXINITPAT 0xf
+#define V_PCIXINITPAT(x) ((x) << S_PCIXINITPAT)
+#define G_PCIXINITPAT(x) (((x) >> S_PCIXINITPAT) & M_PCIXINITPAT)
+
+#define S_64BIT 0
+#define V_64BIT(x) ((x) << S_64BIT)
+#define F_64BIT V_64BIT(1U)
+
+#define A_PCIE_INT_ENABLE 0x80
+
+#define S_BISTERR 15
+#define M_BISTERR 0xff
+
+#define V_BISTERR(x) ((x) << S_BISTERR)
+
+#define S_PCIE_MSIXPARERR 12
+#define M_PCIE_MSIXPARERR 0x7
+
+#define V_PCIE_MSIXPARERR(x) ((x) << S_PCIE_MSIXPARERR)
+
+#define S_PCIE_CFPARERR 11
+#define V_PCIE_CFPARERR(x) ((x) << S_PCIE_CFPARERR)
+#define F_PCIE_CFPARERR V_PCIE_CFPARERR(1U)
+
+#define S_PCIE_RFPARERR 10
+#define V_PCIE_RFPARERR(x) ((x) << S_PCIE_RFPARERR)
+#define F_PCIE_RFPARERR V_PCIE_RFPARERR(1U)
+
+#define S_PCIE_WFPARERR 9
+#define V_PCIE_WFPARERR(x) ((x) << S_PCIE_WFPARERR)
+#define F_PCIE_WFPARERR V_PCIE_WFPARERR(1U)
+
+#define S_PCIE_PIOPARERR 8
+#define V_PCIE_PIOPARERR(x) ((x) << S_PCIE_PIOPARERR)
+#define F_PCIE_PIOPARERR V_PCIE_PIOPARERR(1U)
+
+#define S_UNXSPLCPLERRC 7
+#define V_UNXSPLCPLERRC(x) ((x) << S_UNXSPLCPLERRC)
+#define F_UNXSPLCPLERRC V_UNXSPLCPLERRC(1U)
+
+#define S_UNXSPLCPLERRR 6
+#define V_UNXSPLCPLERRR(x) ((x) << S_UNXSPLCPLERRR)
+#define F_UNXSPLCPLERRR V_UNXSPLCPLERRR(1U)
+
+#define S_PEXERR 0
+#define V_PEXERR(x) ((x) << S_PEXERR)
+#define F_PEXERR V_PEXERR(1U)
+
+#define A_PCIE_INT_CAUSE 0x84
+
+#define A_PCIE_CFG 0x88
+
+#define S_PCIE_CLIDECEN 16
+#define V_PCIE_CLIDECEN(x) ((x) << S_PCIE_CLIDECEN)
+#define F_PCIE_CLIDECEN V_PCIE_CLIDECEN(1U)
+
+#define S_CRSTWRMMODE 0
+#define V_CRSTWRMMODE(x) ((x) << S_CRSTWRMMODE)
+#define F_CRSTWRMMODE V_CRSTWRMMODE(1U)
+
+#define A_PCIE_MODE 0x8c
+
+#define S_NUMFSTTRNSEQRX 10
+#define M_NUMFSTTRNSEQRX 0xff
+#define V_NUMFSTTRNSEQRX(x) ((x) << S_NUMFSTTRNSEQRX)
+#define G_NUMFSTTRNSEQRX(x) (((x) >> S_NUMFSTTRNSEQRX) & M_NUMFSTTRNSEQRX)
+
+#define A_PCIE_PEX_CTRL0 0x98
+
+#define S_NUMFSTTRNSEQ 22
+#define M_NUMFSTTRNSEQ 0xff
+#define V_NUMFSTTRNSEQ(x) ((x) << S_NUMFSTTRNSEQ)
+#define G_NUMFSTTRNSEQ(x) (((x) >> S_NUMFSTTRNSEQ) & M_NUMFSTTRNSEQ)
+
+#define S_REPLAYLMT 2
+#define M_REPLAYLMT 0xfffff
+
+#define V_REPLAYLMT(x) ((x) << S_REPLAYLMT)
+
+#define A_PCIE_PEX_CTRL1 0x9c
+
+#define S_T3A_ACKLAT 0
+#define M_T3A_ACKLAT 0x7ff
+
+#define V_T3A_ACKLAT(x) ((x) << S_T3A_ACKLAT)
+
+#define S_ACKLAT 0
+#define M_ACKLAT 0x1fff
+
+#define V_ACKLAT(x) ((x) << S_ACKLAT)
+
+#define A_PCIE_PEX_ERR 0xa4
+
+#define A_T3DBG_GPIO_EN 0xd0
+
+#define S_GPIO11_OEN 27
+#define V_GPIO11_OEN(x) ((x) << S_GPIO11_OEN)
+#define F_GPIO11_OEN V_GPIO11_OEN(1U)
+
+#define S_GPIO10_OEN 26
+#define V_GPIO10_OEN(x) ((x) << S_GPIO10_OEN)
+#define F_GPIO10_OEN V_GPIO10_OEN(1U)
+
+#define S_GPIO7_OEN 23
+#define V_GPIO7_OEN(x) ((x) << S_GPIO7_OEN)
+#define F_GPIO7_OEN V_GPIO7_OEN(1U)
+
+#define S_GPIO6_OEN 22
+#define V_GPIO6_OEN(x) ((x) << S_GPIO6_OEN)
+#define F_GPIO6_OEN V_GPIO6_OEN(1U)
+
+#define S_GPIO5_OEN 21
+#define V_GPIO5_OEN(x) ((x) << S_GPIO5_OEN)
+#define F_GPIO5_OEN V_GPIO5_OEN(1U)
+
+#define S_GPIO4_OEN 20
+#define V_GPIO4_OEN(x) ((x) << S_GPIO4_OEN)
+#define F_GPIO4_OEN V_GPIO4_OEN(1U)
+
+#define S_GPIO2_OEN 18
+#define V_GPIO2_OEN(x) ((x) << S_GPIO2_OEN)
+#define F_GPIO2_OEN V_GPIO2_OEN(1U)
+
+#define S_GPIO1_OEN 17
+#define V_GPIO1_OEN(x) ((x) << S_GPIO1_OEN)
+#define F_GPIO1_OEN V_GPIO1_OEN(1U)
+
+#define S_GPIO0_OEN 16
+#define V_GPIO0_OEN(x) ((x) << S_GPIO0_OEN)
+#define F_GPIO0_OEN V_GPIO0_OEN(1U)
+
+#define S_GPIO10_OUT_VAL 10
+#define V_GPIO10_OUT_VAL(x) ((x) << S_GPIO10_OUT_VAL)
+#define F_GPIO10_OUT_VAL V_GPIO10_OUT_VAL(1U)
+
+#define S_GPIO7_OUT_VAL 7
+#define V_GPIO7_OUT_VAL(x) ((x) << S_GPIO7_OUT_VAL)
+#define F_GPIO7_OUT_VAL V_GPIO7_OUT_VAL(1U)
+
+#define S_GPIO6_OUT_VAL 6
+#define V_GPIO6_OUT_VAL(x) ((x) << S_GPIO6_OUT_VAL)
+#define F_GPIO6_OUT_VAL V_GPIO6_OUT_VAL(1U)
+
+#define S_GPIO5_OUT_VAL 5
+#define V_GPIO5_OUT_VAL(x) ((x) << S_GPIO5_OUT_VAL)
+#define F_GPIO5_OUT_VAL V_GPIO5_OUT_VAL(1U)
+
+#define S_GPIO4_OUT_VAL 4
+#define V_GPIO4_OUT_VAL(x) ((x) << S_GPIO4_OUT_VAL)
+#define F_GPIO4_OUT_VAL V_GPIO4_OUT_VAL(1U)
+
+#define S_GPIO2_OUT_VAL 2
+#define V_GPIO2_OUT_VAL(x) ((x) << S_GPIO2_OUT_VAL)
+#define F_GPIO2_OUT_VAL V_GPIO2_OUT_VAL(1U)
+
+#define S_GPIO1_OUT_VAL 1
+#define V_GPIO1_OUT_VAL(x) ((x) << S_GPIO1_OUT_VAL)
+#define F_GPIO1_OUT_VAL V_GPIO1_OUT_VAL(1U)
+
+#define S_GPIO0_OUT_VAL 0
+#define V_GPIO0_OUT_VAL(x) ((x) << S_GPIO0_OUT_VAL)
+#define F_GPIO0_OUT_VAL V_GPIO0_OUT_VAL(1U)
+
+#define A_T3DBG_INT_ENABLE 0xd8
+
+#define S_GPIO11 11
+#define V_GPIO11(x) ((x) << S_GPIO11)
+#define F_GPIO11 V_GPIO11(1U)
+
+#define S_GPIO10 10
+#define V_GPIO10(x) ((x) << S_GPIO10)
+#define F_GPIO10 V_GPIO10(1U)
+
+#define S_GPIO7 7
+#define V_GPIO7(x) ((x) << S_GPIO7)
+#define F_GPIO7 V_GPIO7(1U)
+
+#define S_GPIO6 6
+#define V_GPIO6(x) ((x) << S_GPIO6)
+#define F_GPIO6 V_GPIO6(1U)
+
+#define S_GPIO5 5
+#define V_GPIO5(x) ((x) << S_GPIO5)
+#define F_GPIO5 V_GPIO5(1U)
+
+#define S_GPIO4 4
+#define V_GPIO4(x) ((x) << S_GPIO4)
+#define F_GPIO4 V_GPIO4(1U)
+
+#define S_GPIO3 3
+#define V_GPIO3(x) ((x) << S_GPIO3)
+#define F_GPIO3 V_GPIO3(1U)
+
+#define S_GPIO2 2
+#define V_GPIO2(x) ((x) << S_GPIO2)
+#define F_GPIO2 V_GPIO2(1U)
+
+#define S_GPIO1 1
+#define V_GPIO1(x) ((x) << S_GPIO1)
+#define F_GPIO1 V_GPIO1(1U)
+
+#define S_GPIO0 0
+#define V_GPIO0(x) ((x) << S_GPIO0)
+#define F_GPIO0 V_GPIO0(1U)
+
+#define A_T3DBG_INT_CAUSE 0xdc
+
+#define A_T3DBG_GPIO_ACT_LOW 0xf0
+
+#define MC7_PMRX_BASE_ADDR 0x100
+
+#define A_MC7_CFG 0x100
+
+#define S_IFEN 13
+#define V_IFEN(x) ((x) << S_IFEN)
+#define F_IFEN V_IFEN(1U)
+
+#define S_TERM150 11
+#define V_TERM150(x) ((x) << S_TERM150)
+#define F_TERM150 V_TERM150(1U)
+
+#define S_SLOW 10
+#define V_SLOW(x) ((x) << S_SLOW)
+#define F_SLOW V_SLOW(1U)
+
+#define S_WIDTH 8
+#define M_WIDTH 0x3
+#define V_WIDTH(x) ((x) << S_WIDTH)
+#define G_WIDTH(x) (((x) >> S_WIDTH) & M_WIDTH)
+
+#define S_BKS 6
+#define V_BKS(x) ((x) << S_BKS)
+#define F_BKS V_BKS(1U)
+
+#define S_ORG 5
+#define V_ORG(x) ((x) << S_ORG)
+#define F_ORG V_ORG(1U)
+
+#define S_DEN 2
+#define M_DEN 0x7
+#define V_DEN(x) ((x) << S_DEN)
+#define G_DEN(x) (((x) >> S_DEN) & M_DEN)
+
+#define S_RDY 1
+#define V_RDY(x) ((x) << S_RDY)
+#define F_RDY V_RDY(1U)
+
+#define S_CLKEN 0
+#define V_CLKEN(x) ((x) << S_CLKEN)
+#define F_CLKEN V_CLKEN(1U)
+
+#define A_MC7_MODE 0x104
+
+#define S_BUSY 31
+#define V_BUSY(x) ((x) << S_BUSY)
+#define F_BUSY V_BUSY(1U)
+
+#define S_BUSY 31
+#define V_BUSY(x) ((x) << S_BUSY)
+#define F_BUSY V_BUSY(1U)
+
+#define A_MC7_EXT_MODE1 0x108
+
+#define A_MC7_EXT_MODE2 0x10c
+
+#define A_MC7_EXT_MODE3 0x110
+
+#define A_MC7_PRE 0x114
+
+#define A_MC7_REF 0x118
+
+#define S_PREREFDIV 1
+#define M_PREREFDIV 0x3fff
+#define V_PREREFDIV(x) ((x) << S_PREREFDIV)
+
+#define S_PERREFEN 0
+#define V_PERREFEN(x) ((x) << S_PERREFEN)
+#define F_PERREFEN V_PERREFEN(1U)
+
+#define A_MC7_DLL 0x11c
+
+#define S_DLLENB 1
+#define V_DLLENB(x) ((x) << S_DLLENB)
+#define F_DLLENB V_DLLENB(1U)
+
+#define S_DLLRST 0
+#define V_DLLRST(x) ((x) << S_DLLRST)
+#define F_DLLRST V_DLLRST(1U)
+
+#define A_MC7_PARM 0x120
+
+#define S_ACTTOPREDLY 26
+#define M_ACTTOPREDLY 0xf
+#define V_ACTTOPREDLY(x) ((x) << S_ACTTOPREDLY)
+
+#define S_ACTTORDWRDLY 23
+#define M_ACTTORDWRDLY 0x7
+#define V_ACTTORDWRDLY(x) ((x) << S_ACTTORDWRDLY)
+
+#define S_PRECYC 20
+#define M_PRECYC 0x7
+#define V_PRECYC(x) ((x) << S_PRECYC)
+
+#define S_REFCYC 13
+#define M_REFCYC 0x7f
+#define V_REFCYC(x) ((x) << S_REFCYC)
+
+#define S_BKCYC 8
+#define M_BKCYC 0x1f
+#define V_BKCYC(x) ((x) << S_BKCYC)
+
+#define S_WRTORDDLY 4
+#define M_WRTORDDLY 0xf
+#define V_WRTORDDLY(x) ((x) << S_WRTORDDLY)
+
+#define S_RDTOWRDLY 0
+#define M_RDTOWRDLY 0xf
+#define V_RDTOWRDLY(x) ((x) << S_RDTOWRDLY)
+
+#define A_MC7_CAL 0x128
+
+#define S_BUSY 31
+#define V_BUSY(x) ((x) << S_BUSY)
+#define F_BUSY V_BUSY(1U)
+
+#define S_BUSY 31
+#define V_BUSY(x) ((x) << S_BUSY)
+#define F_BUSY V_BUSY(1U)
+
+#define S_CAL_FAULT 30
+#define V_CAL_FAULT(x) ((x) << S_CAL_FAULT)
+#define F_CAL_FAULT V_CAL_FAULT(1U)
+
+#define S_SGL_CAL_EN 20
+#define V_SGL_CAL_EN(x) ((x) << S_SGL_CAL_EN)
+#define F_SGL_CAL_EN V_SGL_CAL_EN(1U)
+
+#define A_MC7_ERR_ADDR 0x12c
+
+#define A_MC7_ECC 0x130
+
+#define S_ECCCHKEN 1
+#define V_ECCCHKEN(x) ((x) << S_ECCCHKEN)
+#define F_ECCCHKEN V_ECCCHKEN(1U)
+
+#define S_ECCGENEN 0
+#define V_ECCGENEN(x) ((x) << S_ECCGENEN)
+#define F_ECCGENEN V_ECCGENEN(1U)
+
+#define A_MC7_CE_ADDR 0x134
+
+#define A_MC7_CE_DATA0 0x138
+
+#define A_MC7_CE_DATA1 0x13c
+
+#define A_MC7_CE_DATA2 0x140
+
+#define S_DATA 0
+#define M_DATA 0xff
+
+#define G_DATA(x) (((x) >> S_DATA) & M_DATA)
+
+#define A_MC7_UE_ADDR 0x144
+
+#define A_MC7_UE_DATA0 0x148
+
+#define A_MC7_UE_DATA1 0x14c
+
+#define A_MC7_UE_DATA2 0x150
+
+#define A_MC7_BD_ADDR 0x154
+
+#define S_ADDR 3
+
+#define M_ADDR 0x1fffffff
+
+#define A_MC7_BD_DATA0 0x158
+
+#define A_MC7_BD_DATA1 0x15c
+
+#define A_MC7_BD_OP 0x164
+
+#define S_OP 0
+
+#define V_OP(x) ((x) << S_OP)
+#define F_OP V_OP(1U)
+
+#define F_OP V_OP(1U)
+#define A_SF_OP 0x6dc
+
+#define A_MC7_BIST_ADDR_BEG 0x168
+
+#define A_MC7_BIST_ADDR_END 0x16c
+
+#define A_MC7_BIST_DATA 0x170
+
+#define A_MC7_BIST_OP 0x174
+
+#define S_CONT 3
+#define V_CONT(x) ((x) << S_CONT)
+#define F_CONT V_CONT(1U)
+
+#define F_CONT V_CONT(1U)
+
+#define A_MC7_INT_ENABLE 0x178
+
+#define S_AE 17
+#define V_AE(x) ((x) << S_AE)
+#define F_AE V_AE(1U)
+
+#define S_PE 2
+#define M_PE 0x7fff
+
+#define V_PE(x) ((x) << S_PE)
+
+#define G_PE(x) (((x) >> S_PE) & M_PE)
+
+#define S_UE 1
+#define V_UE(x) ((x) << S_UE)
+#define F_UE V_UE(1U)
+
+#define S_CE 0
+#define V_CE(x) ((x) << S_CE)
+#define F_CE V_CE(1U)
+
+#define A_MC7_INT_CAUSE 0x17c
+
+#define MC7_PMTX_BASE_ADDR 0x180
+
+#define MC7_CM_BASE_ADDR 0x200
+
+#define A_CIM_BOOT_CFG 0x280
+
+#define S_BOOTADDR 2
+#define M_BOOTADDR 0x3fffffff
+#define V_BOOTADDR(x) ((x) << S_BOOTADDR)
+
+#define A_CIM_SDRAM_BASE_ADDR 0x28c
+
+#define A_CIM_SDRAM_ADDR_SIZE 0x290
+
+#define A_CIM_HOST_INT_ENABLE 0x298
+
+#define A_CIM_HOST_INT_CAUSE 0x29c
+
+#define S_BLKWRPLINT 12
+#define V_BLKWRPLINT(x) ((x) << S_BLKWRPLINT)
+#define F_BLKWRPLINT V_BLKWRPLINT(1U)
+
+#define S_BLKRDPLINT 11
+#define V_BLKRDPLINT(x) ((x) << S_BLKRDPLINT)
+#define F_BLKRDPLINT V_BLKRDPLINT(1U)
+
+#define S_BLKWRCTLINT 10
+#define V_BLKWRCTLINT(x) ((x) << S_BLKWRCTLINT)
+#define F_BLKWRCTLINT V_BLKWRCTLINT(1U)
+
+#define S_BLKRDCTLINT 9
+#define V_BLKRDCTLINT(x) ((x) << S_BLKRDCTLINT)
+#define F_BLKRDCTLINT V_BLKRDCTLINT(1U)
+
+#define S_BLKWRFLASHINT 8
+#define V_BLKWRFLASHINT(x) ((x) << S_BLKWRFLASHINT)
+#define F_BLKWRFLASHINT V_BLKWRFLASHINT(1U)
+
+#define S_BLKRDFLASHINT 7
+#define V_BLKRDFLASHINT(x) ((x) << S_BLKRDFLASHINT)
+#define F_BLKRDFLASHINT V_BLKRDFLASHINT(1U)
+
+#define S_SGLWRFLASHINT 6
+#define V_SGLWRFLASHINT(x) ((x) << S_SGLWRFLASHINT)
+#define F_SGLWRFLASHINT V_SGLWRFLASHINT(1U)
+
+#define S_WRBLKFLASHINT 5
+#define V_WRBLKFLASHINT(x) ((x) << S_WRBLKFLASHINT)
+#define F_WRBLKFLASHINT V_WRBLKFLASHINT(1U)
+
+#define S_BLKWRBOOTINT 4
+#define V_BLKWRBOOTINT(x) ((x) << S_BLKWRBOOTINT)
+#define F_BLKWRBOOTINT V_BLKWRBOOTINT(1U)
+
+#define S_FLASHRANGEINT 2
+#define V_FLASHRANGEINT(x) ((x) << S_FLASHRANGEINT)
+#define F_FLASHRANGEINT V_FLASHRANGEINT(1U)
+
+#define S_SDRAMRANGEINT 1
+#define V_SDRAMRANGEINT(x) ((x) << S_SDRAMRANGEINT)
+#define F_SDRAMRANGEINT V_SDRAMRANGEINT(1U)
+
+#define S_RSVDSPACEINT 0
+#define V_RSVDSPACEINT(x) ((x) << S_RSVDSPACEINT)
+#define F_RSVDSPACEINT V_RSVDSPACEINT(1U)
+
+#define A_CIM_HOST_ACC_CTRL 0x2b0
+
+#define S_HOSTBUSY 17
+#define V_HOSTBUSY(x) ((x) << S_HOSTBUSY)
+#define F_HOSTBUSY V_HOSTBUSY(1U)
+
+#define A_CIM_HOST_ACC_DATA 0x2b4
+
+#define A_TP_IN_CONFIG 0x300
+
+#define S_NICMODE 14
+#define V_NICMODE(x) ((x) << S_NICMODE)
+#define F_NICMODE V_NICMODE(1U)
+
+#define F_NICMODE V_NICMODE(1U)
+
+#define S_IPV6ENABLE 15
+#define V_IPV6ENABLE(x) ((x) << S_IPV6ENABLE)
+#define F_IPV6ENABLE V_IPV6ENABLE(1U)
+
+#define A_TP_OUT_CONFIG 0x304
+
+#define S_VLANEXTRACTIONENABLE 12
+
+#define A_TP_GLOBAL_CONFIG 0x308
+
+#define S_TXPACINGENABLE 24
+#define V_TXPACINGENABLE(x) ((x) << S_TXPACINGENABLE)
+#define F_TXPACINGENABLE V_TXPACINGENABLE(1U)
+
+#define S_PATHMTU 15
+#define V_PATHMTU(x) ((x) << S_PATHMTU)
+#define F_PATHMTU V_PATHMTU(1U)
+
+#define S_IPCHECKSUMOFFLOAD 13
+#define V_IPCHECKSUMOFFLOAD(x) ((x) << S_IPCHECKSUMOFFLOAD)
+#define F_IPCHECKSUMOFFLOAD V_IPCHECKSUMOFFLOAD(1U)
+
+#define S_UDPCHECKSUMOFFLOAD 12
+#define V_UDPCHECKSUMOFFLOAD(x) ((x) << S_UDPCHECKSUMOFFLOAD)
+#define F_UDPCHECKSUMOFFLOAD V_UDPCHECKSUMOFFLOAD(1U)
+
+#define S_TCPCHECKSUMOFFLOAD 11
+#define V_TCPCHECKSUMOFFLOAD(x) ((x) << S_TCPCHECKSUMOFFLOAD)
+#define F_TCPCHECKSUMOFFLOAD V_TCPCHECKSUMOFFLOAD(1U)
+
+#define S_IPTTL 0
+#define M_IPTTL 0xff
+#define V_IPTTL(x) ((x) << S_IPTTL)
+
+#define A_TP_CMM_MM_BASE 0x314
+
+#define A_TP_CMM_TIMER_BASE 0x318
+
+#define S_CMTIMERMAXNUM 28
+#define M_CMTIMERMAXNUM 0x3
+#define V_CMTIMERMAXNUM(x) ((x) << S_CMTIMERMAXNUM)
+
+#define A_TP_PMM_SIZE 0x31c
+
+#define A_TP_PMM_TX_BASE 0x320
+
+#define A_TP_PMM_RX_BASE 0x328
+
+#define A_TP_PMM_RX_PAGE_SIZE 0x32c
+
+#define A_TP_PMM_RX_MAX_PAGE 0x330
+
+#define A_TP_PMM_TX_PAGE_SIZE 0x334
+
+#define A_TP_PMM_TX_MAX_PAGE 0x338
+
+#define A_TP_TCP_OPTIONS 0x340
+
+#define S_MTUDEFAULT 16
+#define M_MTUDEFAULT 0xffff
+#define V_MTUDEFAULT(x) ((x) << S_MTUDEFAULT)
+
+#define S_MTUENABLE 10
+#define V_MTUENABLE(x) ((x) << S_MTUENABLE)
+#define F_MTUENABLE V_MTUENABLE(1U)
+
+#define S_SACKRX 8
+#define V_SACKRX(x) ((x) << S_SACKRX)
+#define F_SACKRX V_SACKRX(1U)
+
+#define S_SACKMODE 4
+
+#define M_SACKMODE 0x3
+
+#define V_SACKMODE(x) ((x) << S_SACKMODE)
+
+#define S_WINDOWSCALEMODE 2
+#define M_WINDOWSCALEMODE 0x3
+#define V_WINDOWSCALEMODE(x) ((x) << S_WINDOWSCALEMODE)
+
+#define S_TIMESTAMPSMODE 0
+
+#define M_TIMESTAMPSMODE 0x3
+
+#define V_TIMESTAMPSMODE(x) ((x) << S_TIMESTAMPSMODE)
+
+#define A_TP_DACK_CONFIG 0x344
+
+#define S_AUTOSTATE3 30
+#define M_AUTOSTATE3 0x3
+#define V_AUTOSTATE3(x) ((x) << S_AUTOSTATE3)
+
+#define S_AUTOSTATE2 28
+#define M_AUTOSTATE2 0x3
+#define V_AUTOSTATE2(x) ((x) << S_AUTOSTATE2)
+
+#define S_AUTOSTATE1 26
+#define M_AUTOSTATE1 0x3
+#define V_AUTOSTATE1(x) ((x) << S_AUTOSTATE1)
+
+#define S_BYTETHRESHOLD 5
+#define M_BYTETHRESHOLD 0xfffff
+#define V_BYTETHRESHOLD(x) ((x) << S_BYTETHRESHOLD)
+
+#define S_MSSTHRESHOLD 3
+#define M_MSSTHRESHOLD 0x3
+#define V_MSSTHRESHOLD(x) ((x) << S_MSSTHRESHOLD)
+
+#define S_AUTOCAREFUL 2
+#define V_AUTOCAREFUL(x) ((x) << S_AUTOCAREFUL)
+#define F_AUTOCAREFUL V_AUTOCAREFUL(1U)
+
+#define S_AUTOENABLE 1
+#define V_AUTOENABLE(x) ((x) << S_AUTOENABLE)
+#define F_AUTOENABLE V_AUTOENABLE(1U)
+
+#define S_DACK_MODE 0
+#define V_DACK_MODE(x) ((x) << S_DACK_MODE)
+#define F_DACK_MODE V_DACK_MODE(1U)
+
+#define A_TP_PC_CONFIG 0x348
+
+#define S_TXTOSQUEUEMAPMODE 26
+#define V_TXTOSQUEUEMAPMODE(x) ((x) << S_TXTOSQUEUEMAPMODE)
+#define F_TXTOSQUEUEMAPMODE V_TXTOSQUEUEMAPMODE(1U)
+
+#define S_ENABLEEPCMDAFULL 23
+#define V_ENABLEEPCMDAFULL(x) ((x) << S_ENABLEEPCMDAFULL)
+#define F_ENABLEEPCMDAFULL V_ENABLEEPCMDAFULL(1U)
+
+#define S_MODULATEUNIONMODE 22
+#define V_MODULATEUNIONMODE(x) ((x) << S_MODULATEUNIONMODE)
+#define F_MODULATEUNIONMODE V_MODULATEUNIONMODE(1U)
+
+#define S_TXDEFERENABLE 20
+#define V_TXDEFERENABLE(x) ((x) << S_TXDEFERENABLE)
+#define F_TXDEFERENABLE V_TXDEFERENABLE(1U)
+
+#define S_RXCONGESTIONMODE 19
+#define V_RXCONGESTIONMODE(x) ((x) << S_RXCONGESTIONMODE)
+#define F_RXCONGESTIONMODE V_RXCONGESTIONMODE(1U)
+
+#define S_HEARBEATDACK 16
+#define V_HEARBEATDACK(x) ((x) << S_HEARBEATDACK)
+#define F_HEARBEATDACK V_HEARBEATDACK(1U)
+
+#define S_TXCONGESTIONMODE 15
+#define V_TXCONGESTIONMODE(x) ((x) << S_TXCONGESTIONMODE)
+#define F_TXCONGESTIONMODE V_TXCONGESTIONMODE(1U)
+
+#define S_ENABLEOCSPIFULL 30
+#define V_ENABLEOCSPIFULL(x) ((x) << S_ENABLEOCSPIFULL)
+#define F_ENABLEOCSPIFULL V_ENABLEOCSPIFULL(1U)
+
+#define S_LOCKTID 28
+#define V_LOCKTID(x) ((x) << S_LOCKTID)
+#define F_LOCKTID V_LOCKTID(1U)
+
+#define A_TP_PC_CONFIG2 0x34c
+
+#define S_CHDRAFULL 4
+#define V_CHDRAFULL(x) ((x) << S_CHDRAFULL)
+#define F_CHDRAFULL V_CHDRAFULL(1U)
+
+#define A_TP_TCP_BACKOFF_REG0 0x350
+
+#define A_TP_TCP_BACKOFF_REG1 0x354
+
+#define A_TP_TCP_BACKOFF_REG2 0x358
+
+#define A_TP_TCP_BACKOFF_REG3 0x35c
+
+#define A_TP_PARA_REG2 0x368
+
+#define S_MAXRXDATA 16
+#define M_MAXRXDATA 0xffff
+#define V_MAXRXDATA(x) ((x) << S_MAXRXDATA)
+
+#define S_RXCOALESCESIZE 0
+#define M_RXCOALESCESIZE 0xffff
+#define V_RXCOALESCESIZE(x) ((x) << S_RXCOALESCESIZE)
+
+#define A_TP_PARA_REG3 0x36c
+
+#define S_TXDATAACKIDX 16
+#define M_TXDATAACKIDX 0xf
+
+#define V_TXDATAACKIDX(x) ((x) << S_TXDATAACKIDX)
+
+#define S_TXPACEAUTOSTRICT 10
+#define V_TXPACEAUTOSTRICT(x) ((x) << S_TXPACEAUTOSTRICT)
+#define F_TXPACEAUTOSTRICT V_TXPACEAUTOSTRICT(1U)
+
+#define S_TXPACEFIXED 9
+#define V_TXPACEFIXED(x) ((x) << S_TXPACEFIXED)
+#define F_TXPACEFIXED V_TXPACEFIXED(1U)
+
+#define S_TXPACEAUTO 8
+#define V_TXPACEAUTO(x) ((x) << S_TXPACEAUTO)
+#define F_TXPACEAUTO V_TXPACEAUTO(1U)
+
+#define S_RXCOALESCEENABLE 1
+#define V_RXCOALESCEENABLE(x) ((x) << S_RXCOALESCEENABLE)
+#define F_RXCOALESCEENABLE V_RXCOALESCEENABLE(1U)
+
+#define S_RXCOALESCEPSHEN 0
+#define V_RXCOALESCEPSHEN(x) ((x) << S_RXCOALESCEPSHEN)
+#define F_RXCOALESCEPSHEN V_RXCOALESCEPSHEN(1U)
+
+#define A_TP_PARA_REG4 0x370
+
+#define A_TP_PARA_REG6 0x378
+
+#define S_T3A_ENABLEESND 13
+#define V_T3A_ENABLEESND(x) ((x) << S_T3A_ENABLEESND)
+#define F_T3A_ENABLEESND V_T3A_ENABLEESND(1U)
+
+#define S_ENABLEESND 11
+#define V_ENABLEESND(x) ((x) << S_ENABLEESND)
+#define F_ENABLEESND V_ENABLEESND(1U)
+
+#define A_TP_PARA_REG7 0x37c
+
+#define S_PMMAXXFERLEN1 16
+#define M_PMMAXXFERLEN1 0xffff
+#define V_PMMAXXFERLEN1(x) ((x) << S_PMMAXXFERLEN1)
+
+#define S_PMMAXXFERLEN0 0
+#define M_PMMAXXFERLEN0 0xffff
+#define V_PMMAXXFERLEN0(x) ((x) << S_PMMAXXFERLEN0)
+
+#define A_TP_TIMER_RESOLUTION 0x390
+
+#define S_TIMERRESOLUTION 16
+#define M_TIMERRESOLUTION 0xff
+#define V_TIMERRESOLUTION(x) ((x) << S_TIMERRESOLUTION)
+
+#define S_TIMESTAMPRESOLUTION 8
+#define M_TIMESTAMPRESOLUTION 0xff
+#define V_TIMESTAMPRESOLUTION(x) ((x) << S_TIMESTAMPRESOLUTION)
+
+#define S_DELAYEDACKRESOLUTION 0
+#define M_DELAYEDACKRESOLUTION 0xff
+#define V_DELAYEDACKRESOLUTION(x) ((x) << S_DELAYEDACKRESOLUTION)
+
+#define A_TP_MSL 0x394
+
+#define A_TP_RXT_MIN 0x398
+
+#define A_TP_RXT_MAX 0x39c
+
+#define A_TP_PERS_MIN 0x3a0
+
+#define A_TP_PERS_MAX 0x3a4
+
+#define A_TP_KEEP_IDLE 0x3a8
+
+#define A_TP_KEEP_INTVL 0x3ac
+
+#define A_TP_INIT_SRTT 0x3b0
+
+#define A_TP_DACK_TIMER 0x3b4
+
+#define A_TP_FINWAIT2_TIMER 0x3b8
+
+#define A_TP_SHIFT_CNT 0x3c0
+
+#define S_SYNSHIFTMAX 24
+
+#define M_SYNSHIFTMAX 0xff
+
+#define V_SYNSHIFTMAX(x) ((x) << S_SYNSHIFTMAX)
+
+#define S_RXTSHIFTMAXR1 20
+
+#define M_RXTSHIFTMAXR1 0xf
+
+#define V_RXTSHIFTMAXR1(x) ((x) << S_RXTSHIFTMAXR1)
+
+#define S_RXTSHIFTMAXR2 16
+
+#define M_RXTSHIFTMAXR2 0xf
+
+#define V_RXTSHIFTMAXR2(x) ((x) << S_RXTSHIFTMAXR2)
+
+#define S_PERSHIFTBACKOFFMAX 12
+#define M_PERSHIFTBACKOFFMAX 0xf
+#define V_PERSHIFTBACKOFFMAX(x) ((x) << S_PERSHIFTBACKOFFMAX)
+
+#define S_PERSHIFTMAX 8
+#define M_PERSHIFTMAX 0xf
+#define V_PERSHIFTMAX(x) ((x) << S_PERSHIFTMAX)
+
+#define S_KEEPALIVEMAX 0
+
+#define M_KEEPALIVEMAX 0xff
+
+#define V_KEEPALIVEMAX(x) ((x) << S_KEEPALIVEMAX)
+
+#define A_TP_MTU_PORT_TABLE 0x3d0
+
+#define A_TP_CCTRL_TABLE 0x3dc
+
+#define A_TP_MTU_TABLE 0x3e4
+
+#define A_TP_RSS_MAP_TABLE 0x3e8
+
+#define A_TP_RSS_LKP_TABLE 0x3ec
+
+#define A_TP_RSS_CONFIG 0x3f0
+
+#define S_TNL4TUPEN 29
+#define V_TNL4TUPEN(x) ((x) << S_TNL4TUPEN)
+#define F_TNL4TUPEN V_TNL4TUPEN(1U)
+
+#define S_TNL2TUPEN 28
+#define V_TNL2TUPEN(x) ((x) << S_TNL2TUPEN)
+#define F_TNL2TUPEN V_TNL2TUPEN(1U)
+
+#define S_TNLPRTEN 26
+#define V_TNLPRTEN(x) ((x) << S_TNLPRTEN)
+#define F_TNLPRTEN V_TNLPRTEN(1U)
+
+#define S_TNLMAPEN 25
+#define V_TNLMAPEN(x) ((x) << S_TNLMAPEN)
+#define F_TNLMAPEN V_TNLMAPEN(1U)
+
+#define S_TNLLKPEN 24
+#define V_TNLLKPEN(x) ((x) << S_TNLLKPEN)
+#define F_TNLLKPEN V_TNLLKPEN(1U)
+
+#define S_RRCPLCPUSIZE 4
+#define M_RRCPLCPUSIZE 0x7
+#define V_RRCPLCPUSIZE(x) ((x) << S_RRCPLCPUSIZE)
+
+#define S_RQFEEDBACKENABLE 3
+#define V_RQFEEDBACKENABLE(x) ((x) << S_RQFEEDBACKENABLE)
+#define F_RQFEEDBACKENABLE V_RQFEEDBACKENABLE(1U)
+
+#define S_DISABLE 0
+
+#define A_TP_TM_PIO_ADDR 0x418
+
+#define A_TP_TM_PIO_DATA 0x41c
+
+#define A_TP_TX_MOD_QUE_TABLE 0x420
+
+#define A_TP_TX_RESOURCE_LIMIT 0x424
+
+#define A_TP_TX_MOD_QUEUE_REQ_MAP 0x428
+
+#define S_TX_MOD_QUEUE_REQ_MAP 0
+#define M_TX_MOD_QUEUE_REQ_MAP 0xff
+#define V_TX_MOD_QUEUE_REQ_MAP(x) ((x) << S_TX_MOD_QUEUE_REQ_MAP)
+
+#define A_TP_TX_MOD_QUEUE_WEIGHT1 0x42c
+
+#define A_TP_TX_MOD_QUEUE_WEIGHT0 0x430
+
+#define A_TP_MOD_CHANNEL_WEIGHT 0x434
+
+#define A_TP_PIO_ADDR 0x440
+
+#define A_TP_PIO_DATA 0x444
+
+#define A_TP_RESET 0x44c
+
+#define S_FLSTINITENABLE 1
+#define V_FLSTINITENABLE(x) ((x) << S_FLSTINITENABLE)
+#define F_FLSTINITENABLE V_FLSTINITENABLE(1U)
+
+#define S_TPRESET 0
+#define V_TPRESET(x) ((x) << S_TPRESET)
+#define F_TPRESET V_TPRESET(1U)
+
+#define A_TP_CMM_MM_RX_FLST_BASE 0x460
+
+#define A_TP_CMM_MM_TX_FLST_BASE 0x464
+
+#define A_TP_CMM_MM_PS_FLST_BASE 0x468
+
+#define A_TP_MIB_INDEX 0x450
+
+#define A_TP_MIB_RDATA 0x454
+
+#define A_TP_CMM_MM_MAX_PSTRUCT 0x46c
+
+#define A_TP_INT_ENABLE 0x470
+
+#define A_TP_INT_CAUSE 0x474
+
+#define A_TP_TX_MOD_Q1_Q0_RATE_LIMIT 0x8
+
+#define A_TP_TX_DROP_CFG_CH0 0x12b
+
+#define A_TP_TX_DROP_MODE 0x12f
+
+#define A_TP_EGRESS_CONFIG 0x145
+
+#define S_REWRITEFORCETOSIZE 0
+#define V_REWRITEFORCETOSIZE(x) ((x) << S_REWRITEFORCETOSIZE)
+#define F_REWRITEFORCETOSIZE V_REWRITEFORCETOSIZE(1U)
+
+#define A_TP_TX_TRC_KEY0 0x20
+
+#define A_TP_RX_TRC_KEY0 0x120
+
+#define A_ULPRX_CTL 0x500
+
+#define S_ROUND_ROBIN 4
+#define V_ROUND_ROBIN(x) ((x) << S_ROUND_ROBIN)
+#define F_ROUND_ROBIN V_ROUND_ROBIN(1U)
+
+#define A_ULPRX_INT_ENABLE 0x504
+
+#define S_PARERR 0
+#define V_PARERR(x) ((x) << S_PARERR)
+#define F_PARERR V_PARERR(1U)
+
+#define A_ULPRX_INT_CAUSE 0x508
+
+#define A_ULPRX_ISCSI_LLIMIT 0x50c
+
+#define A_ULPRX_ISCSI_ULIMIT 0x510
+
+#define A_ULPRX_ISCSI_TAGMASK 0x514
+
+#define A_ULPRX_TDDP_LLIMIT 0x51c
+
+#define A_ULPRX_TDDP_ULIMIT 0x520
+
+#define A_ULPRX_STAG_LLIMIT 0x52c
+
+#define A_ULPRX_STAG_ULIMIT 0x530
+
+#define A_ULPRX_RQ_LLIMIT 0x534
+#define A_ULPRX_RQ_LLIMIT 0x534
+
+#define A_ULPRX_RQ_ULIMIT 0x538
+#define A_ULPRX_RQ_ULIMIT 0x538
+
+#define A_ULPRX_PBL_LLIMIT 0x53c
+
+#define A_ULPRX_PBL_ULIMIT 0x540
+#define A_ULPRX_PBL_ULIMIT 0x540
+
+#define A_ULPRX_TDDP_TAGMASK 0x524
+
+#define A_ULPRX_RQ_LLIMIT 0x534
+#define A_ULPRX_RQ_LLIMIT 0x534
+
+#define A_ULPRX_RQ_ULIMIT 0x538
+#define A_ULPRX_RQ_ULIMIT 0x538
+
+#define A_ULPRX_PBL_ULIMIT 0x540
+#define A_ULPRX_PBL_ULIMIT 0x540
+
+#define A_ULPTX_CONFIG 0x580
+
+#define S_CFG_RR_ARB 0
+#define V_CFG_RR_ARB(x) ((x) << S_CFG_RR_ARB)
+#define F_CFG_RR_ARB V_CFG_RR_ARB(1U)
+
+#define A_ULPTX_INT_ENABLE 0x584
+
+#define S_PBL_BOUND_ERR_CH1 1
+#define V_PBL_BOUND_ERR_CH1(x) ((x) << S_PBL_BOUND_ERR_CH1)
+#define F_PBL_BOUND_ERR_CH1 V_PBL_BOUND_ERR_CH1(1U)
+
+#define S_PBL_BOUND_ERR_CH0 0
+#define V_PBL_BOUND_ERR_CH0(x) ((x) << S_PBL_BOUND_ERR_CH0)
+#define F_PBL_BOUND_ERR_CH0 V_PBL_BOUND_ERR_CH0(1U)
+
+#define A_ULPTX_INT_CAUSE 0x588
+
+#define A_ULPTX_TPT_LLIMIT 0x58c
+
+#define A_ULPTX_TPT_ULIMIT 0x590
+
+#define A_ULPTX_PBL_LLIMIT 0x594
+
+#define A_ULPTX_PBL_ULIMIT 0x598
+
+#define A_ULPTX_DMA_WEIGHT 0x5ac
+
+#define S_D1_WEIGHT 16
+#define M_D1_WEIGHT 0xffff
+#define V_D1_WEIGHT(x) ((x) << S_D1_WEIGHT)
+
+#define S_D0_WEIGHT 0
+#define M_D0_WEIGHT 0xffff
+#define V_D0_WEIGHT(x) ((x) << S_D0_WEIGHT)
+
+#define A_PM1_RX_CFG 0x5c0
+
+#define A_PM1_RX_INT_ENABLE 0x5d8
+
+#define S_ZERO_E_CMD_ERROR 18
+#define V_ZERO_E_CMD_ERROR(x) ((x) << S_ZERO_E_CMD_ERROR)
+#define F_ZERO_E_CMD_ERROR V_ZERO_E_CMD_ERROR(1U)
+
+#define S_IESPI0_FIFO2X_RX_FRAMING_ERROR 17
+#define V_IESPI0_FIFO2X_RX_FRAMING_ERROR(x) ((x) << S_IESPI0_FIFO2X_RX_FRAMING_ERROR)
+#define F_IESPI0_FIFO2X_RX_FRAMING_ERROR V_IESPI0_FIFO2X_RX_FRAMING_ERROR(1U)
+
+#define S_IESPI1_FIFO2X_RX_FRAMING_ERROR 16
+#define V_IESPI1_FIFO2X_RX_FRAMING_ERROR(x) ((x) << S_IESPI1_FIFO2X_RX_FRAMING_ERROR)
+#define F_IESPI1_FIFO2X_RX_FRAMING_ERROR V_IESPI1_FIFO2X_RX_FRAMING_ERROR(1U)
+
+#define S_IESPI0_RX_FRAMING_ERROR 15
+#define V_IESPI0_RX_FRAMING_ERROR(x) ((x) << S_IESPI0_RX_FRAMING_ERROR)
+#define F_IESPI0_RX_FRAMING_ERROR V_IESPI0_RX_FRAMING_ERROR(1U)
+
+#define S_IESPI1_RX_FRAMING_ERROR 14
+#define V_IESPI1_RX_FRAMING_ERROR(x) ((x) << S_IESPI1_RX_FRAMING_ERROR)
+#define F_IESPI1_RX_FRAMING_ERROR V_IESPI1_RX_FRAMING_ERROR(1U)
+
+#define S_IESPI0_TX_FRAMING_ERROR 13
+#define V_IESPI0_TX_FRAMING_ERROR(x) ((x) << S_IESPI0_TX_FRAMING_ERROR)
+#define F_IESPI0_TX_FRAMING_ERROR V_IESPI0_TX_FRAMING_ERROR(1U)
+
+#define S_IESPI1_TX_FRAMING_ERROR 12
+#define V_IESPI1_TX_FRAMING_ERROR(x) ((x) << S_IESPI1_TX_FRAMING_ERROR)
+#define F_IESPI1_TX_FRAMING_ERROR V_IESPI1_TX_FRAMING_ERROR(1U)
+
+#define S_OCSPI0_RX_FRAMING_ERROR 11
+#define V_OCSPI0_RX_FRAMING_ERROR(x) ((x) << S_OCSPI0_RX_FRAMING_ERROR)
+#define F_OCSPI0_RX_FRAMING_ERROR V_OCSPI0_RX_FRAMING_ERROR(1U)
+
+#define S_OCSPI1_RX_FRAMING_ERROR 10
+#define V_OCSPI1_RX_FRAMING_ERROR(x) ((x) << S_OCSPI1_RX_FRAMING_ERROR)
+#define F_OCSPI1_RX_FRAMING_ERROR V_OCSPI1_RX_FRAMING_ERROR(1U)
+
+#define S_OCSPI0_TX_FRAMING_ERROR 9
+#define V_OCSPI0_TX_FRAMING_ERROR(x) ((x) << S_OCSPI0_TX_FRAMING_ERROR)
+#define F_OCSPI0_TX_FRAMING_ERROR V_OCSPI0_TX_FRAMING_ERROR(1U)
+
+#define S_OCSPI1_TX_FRAMING_ERROR 8
+#define V_OCSPI1_TX_FRAMING_ERROR(x) ((x) << S_OCSPI1_TX_FRAMING_ERROR)
+#define F_OCSPI1_TX_FRAMING_ERROR V_OCSPI1_TX_FRAMING_ERROR(1U)
+
+#define S_OCSPI0_OFIFO2X_TX_FRAMING_ERROR 7
+#define V_OCSPI0_OFIFO2X_TX_FRAMING_ERROR(x) ((x) << S_OCSPI0_OFIFO2X_TX_FRAMING_ERROR)
+#define F_OCSPI0_OFIFO2X_TX_FRAMING_ERROR V_OCSPI0_OFIFO2X_TX_FRAMING_ERROR(1U)
+
+#define S_OCSPI1_OFIFO2X_TX_FRAMING_ERROR 6
+#define V_OCSPI1_OFIFO2X_TX_FRAMING_ERROR(x) ((x) << S_OCSPI1_OFIFO2X_TX_FRAMING_ERROR)
+#define F_OCSPI1_OFIFO2X_TX_FRAMING_ERROR V_OCSPI1_OFIFO2X_TX_FRAMING_ERROR(1U)
+
+#define S_IESPI_PAR_ERROR 3
+#define M_IESPI_PAR_ERROR 0x7
+
+#define V_IESPI_PAR_ERROR(x) ((x) << S_IESPI_PAR_ERROR)
+
+#define S_OCSPI_PAR_ERROR 0
+#define M_OCSPI_PAR_ERROR 0x7
+
+#define V_OCSPI_PAR_ERROR(x) ((x) << S_OCSPI_PAR_ERROR)
+
+#define A_PM1_RX_INT_CAUSE 0x5dc
+
+#define A_PM1_TX_CFG 0x5e0
+
+#define A_PM1_TX_INT_ENABLE 0x5f8
+
+#define S_ZERO_C_CMD_ERROR 18
+#define V_ZERO_C_CMD_ERROR(x) ((x) << S_ZERO_C_CMD_ERROR)
+#define F_ZERO_C_CMD_ERROR V_ZERO_C_CMD_ERROR(1U)
+
+#define S_ICSPI0_FIFO2X_RX_FRAMING_ERROR 17
+#define V_ICSPI0_FIFO2X_RX_FRAMING_ERROR(x) ((x) << S_ICSPI0_FIFO2X_RX_FRAMING_ERROR)
+#define F_ICSPI0_FIFO2X_RX_FRAMING_ERROR V_ICSPI0_FIFO2X_RX_FRAMING_ERROR(1U)
+
+#define S_ICSPI1_FIFO2X_RX_FRAMING_ERROR 16
+#define V_ICSPI1_FIFO2X_RX_FRAMING_ERROR(x) ((x) << S_ICSPI1_FIFO2X_RX_FRAMING_ERROR)
+#define F_ICSPI1_FIFO2X_RX_FRAMING_ERROR V_ICSPI1_FIFO2X_RX_FRAMING_ERROR(1U)
+
+#define S_ICSPI0_RX_FRAMING_ERROR 15
+#define V_ICSPI0_RX_FRAMING_ERROR(x) ((x) << S_ICSPI0_RX_FRAMING_ERROR)
+#define F_ICSPI0_RX_FRAMING_ERROR V_ICSPI0_RX_FRAMING_ERROR(1U)
+
+#define S_ICSPI1_RX_FRAMING_ERROR 14
+#define V_ICSPI1_RX_FRAMING_ERROR(x) ((x) << S_ICSPI1_RX_FRAMING_ERROR)
+#define F_ICSPI1_RX_FRAMING_ERROR V_ICSPI1_RX_FRAMING_ERROR(1U)
+
+#define S_ICSPI0_TX_FRAMING_ERROR 13
+#define V_ICSPI0_TX_FRAMING_ERROR(x) ((x) << S_ICSPI0_TX_FRAMING_ERROR)
+#define F_ICSPI0_TX_FRAMING_ERROR V_ICSPI0_TX_FRAMING_ERROR(1U)
+
+#define S_ICSPI1_TX_FRAMING_ERROR 12
+#define V_ICSPI1_TX_FRAMING_ERROR(x) ((x) << S_ICSPI1_TX_FRAMING_ERROR)
+#define F_ICSPI1_TX_FRAMING_ERROR V_ICSPI1_TX_FRAMING_ERROR(1U)
+
+#define S_OESPI0_RX_FRAMING_ERROR 11
+#define V_OESPI0_RX_FRAMING_ERROR(x) ((x) << S_OESPI0_RX_FRAMING_ERROR)
+#define F_OESPI0_RX_FRAMING_ERROR V_OESPI0_RX_FRAMING_ERROR(1U)
+
+#define S_OESPI1_RX_FRAMING_ERROR 10
+#define V_OESPI1_RX_FRAMING_ERROR(x) ((x) << S_OESPI1_RX_FRAMING_ERROR)
+#define F_OESPI1_RX_FRAMING_ERROR V_OESPI1_RX_FRAMING_ERROR(1U)
+
+#define S_OESPI0_TX_FRAMING_ERROR 9
+#define V_OESPI0_TX_FRAMING_ERROR(x) ((x) << S_OESPI0_TX_FRAMING_ERROR)
+#define F_OESPI0_TX_FRAMING_ERROR V_OESPI0_TX_FRAMING_ERROR(1U)
+
+#define S_OESPI1_TX_FRAMING_ERROR 8
+#define V_OESPI1_TX_FRAMING_ERROR(x) ((x) << S_OESPI1_TX_FRAMING_ERROR)
+#define F_OESPI1_TX_FRAMING_ERROR V_OESPI1_TX_FRAMING_ERROR(1U)
+
+#define S_OESPI0_OFIFO2X_TX_FRAMING_ERROR 7
+#define V_OESPI0_OFIFO2X_TX_FRAMING_ERROR(x) ((x) << S_OESPI0_OFIFO2X_TX_FRAMING_ERROR)
+#define F_OESPI0_OFIFO2X_TX_FRAMING_ERROR V_OESPI0_OFIFO2X_TX_FRAMING_ERROR(1U)
+
+#define S_OESPI1_OFIFO2X_TX_FRAMING_ERROR 6
+#define V_OESPI1_OFIFO2X_TX_FRAMING_ERROR(x) ((x) << S_OESPI1_OFIFO2X_TX_FRAMING_ERROR)
+#define F_OESPI1_OFIFO2X_TX_FRAMING_ERROR V_OESPI1_OFIFO2X_TX_FRAMING_ERROR(1U)
+
+#define S_ICSPI_PAR_ERROR 3
+#define M_ICSPI_PAR_ERROR 0x7
+
+#define V_ICSPI_PAR_ERROR(x) ((x) << S_ICSPI_PAR_ERROR)
+
+#define S_OESPI_PAR_ERROR 0
+#define M_OESPI_PAR_ERROR 0x7
+
+#define V_OESPI_PAR_ERROR(x) ((x) << S_OESPI_PAR_ERROR)
+
+#define A_PM1_TX_INT_CAUSE 0x5fc
+
+#define A_MPS_CFG 0x600
+
+#define S_TPRXPORTEN 4
+#define V_TPRXPORTEN(x) ((x) << S_TPRXPORTEN)
+#define F_TPRXPORTEN V_TPRXPORTEN(1U)
+
+#define S_TPTXPORT1EN 3
+#define V_TPTXPORT1EN(x) ((x) << S_TPTXPORT1EN)
+#define F_TPTXPORT1EN V_TPTXPORT1EN(1U)
+
+#define S_TPTXPORT0EN 2
+#define V_TPTXPORT0EN(x) ((x) << S_TPTXPORT0EN)
+#define F_TPTXPORT0EN V_TPTXPORT0EN(1U)
+
+#define S_PORT1ACTIVE 1
+#define V_PORT1ACTIVE(x) ((x) << S_PORT1ACTIVE)
+#define F_PORT1ACTIVE V_PORT1ACTIVE(1U)
+
+#define S_PORT0ACTIVE 0
+#define V_PORT0ACTIVE(x) ((x) << S_PORT0ACTIVE)
+#define F_PORT0ACTIVE V_PORT0ACTIVE(1U)
+
+#define S_ENFORCEPKT 11
+#define V_ENFORCEPKT(x) ((x) << S_ENFORCEPKT)
+#define F_ENFORCEPKT V_ENFORCEPKT(1U)
+
+#define A_MPS_INT_ENABLE 0x61c
+
+#define S_MCAPARERRENB 6
+#define M_MCAPARERRENB 0x7
+
+#define V_MCAPARERRENB(x) ((x) << S_MCAPARERRENB)
+
+#define S_RXTPPARERRENB 4
+#define M_RXTPPARERRENB 0x3
+
+#define V_RXTPPARERRENB(x) ((x) << S_RXTPPARERRENB)
+
+#define S_TX1TPPARERRENB 2
+#define M_TX1TPPARERRENB 0x3
+
+#define V_TX1TPPARERRENB(x) ((x) << S_TX1TPPARERRENB)
+
+#define S_TX0TPPARERRENB 0
+#define M_TX0TPPARERRENB 0x3
+
+#define V_TX0TPPARERRENB(x) ((x) << S_TX0TPPARERRENB)
+
+#define A_MPS_INT_CAUSE 0x620
+
+#define S_MCAPARERR 6
+#define M_MCAPARERR 0x7
+
+#define V_MCAPARERR(x) ((x) << S_MCAPARERR)
+
+#define S_RXTPPARERR 4
+#define M_RXTPPARERR 0x3
+
+#define V_RXTPPARERR(x) ((x) << S_RXTPPARERR)
+
+#define S_TX1TPPARERR 2
+#define M_TX1TPPARERR 0x3
+
+#define V_TX1TPPARERR(x) ((x) << S_TX1TPPARERR)
+
+#define S_TX0TPPARERR 0
+#define M_TX0TPPARERR 0x3
+
+#define V_TX0TPPARERR(x) ((x) << S_TX0TPPARERR)
+
+#define A_CPL_SWITCH_CNTRL 0x640
+
+#define A_CPL_INTR_ENABLE 0x650
+
+#define S_CIM_OVFL_ERROR 4
+#define V_CIM_OVFL_ERROR(x) ((x) << S_CIM_OVFL_ERROR)
+#define F_CIM_OVFL_ERROR V_CIM_OVFL_ERROR(1U)
+
+#define S_TP_FRAMING_ERROR 3
+#define V_TP_FRAMING_ERROR(x) ((x) << S_TP_FRAMING_ERROR)
+#define F_TP_FRAMING_ERROR V_TP_FRAMING_ERROR(1U)
+
+#define S_SGE_FRAMING_ERROR 2
+#define V_SGE_FRAMING_ERROR(x) ((x) << S_SGE_FRAMING_ERROR)
+#define F_SGE_FRAMING_ERROR V_SGE_FRAMING_ERROR(1U)
+
+#define S_CIM_FRAMING_ERROR 1
+#define V_CIM_FRAMING_ERROR(x) ((x) << S_CIM_FRAMING_ERROR)
+#define F_CIM_FRAMING_ERROR V_CIM_FRAMING_ERROR(1U)
+
+#define S_ZERO_SWITCH_ERROR 0
+#define V_ZERO_SWITCH_ERROR(x) ((x) << S_ZERO_SWITCH_ERROR)
+#define F_ZERO_SWITCH_ERROR V_ZERO_SWITCH_ERROR(1U)
+
+#define A_CPL_INTR_CAUSE 0x654
+
+#define A_CPL_MAP_TBL_DATA 0x65c
+
+#define A_SMB_GLOBAL_TIME_CFG 0x660
+
+#define A_I2C_CFG 0x6a0
+
+#define S_I2C_CLKDIV 0
+#define M_I2C_CLKDIV 0xfff
+#define V_I2C_CLKDIV(x) ((x) << S_I2C_CLKDIV)
+
+#define A_MI1_CFG 0x6b0
+
+#define S_CLKDIV 5
+#define M_CLKDIV 0xff
+#define V_CLKDIV(x) ((x) << S_CLKDIV)
+
+#define S_ST 3
+
+#define M_ST 0x3
+
+#define V_ST(x) ((x) << S_ST)
+
+#define G_ST(x) (((x) >> S_ST) & M_ST)
+
+#define S_PREEN 2
+#define V_PREEN(x) ((x) << S_PREEN)
+#define F_PREEN V_PREEN(1U)
+
+#define S_MDIINV 1
+#define V_MDIINV(x) ((x) << S_MDIINV)
+#define F_MDIINV V_MDIINV(1U)
+
+#define S_MDIEN 0
+#define V_MDIEN(x) ((x) << S_MDIEN)
+#define F_MDIEN V_MDIEN(1U)
+
+#define A_MI1_ADDR 0x6b4
+
+#define S_PHYADDR 5
+#define M_PHYADDR 0x1f
+#define V_PHYADDR(x) ((x) << S_PHYADDR)
+
+#define S_REGADDR 0
+#define M_REGADDR 0x1f
+#define V_REGADDR(x) ((x) << S_REGADDR)
+
+#define A_MI1_DATA 0x6b8
+
+#define A_MI1_OP 0x6bc
+
+#define S_MDI_OP 0
+#define M_MDI_OP 0x3
+#define V_MDI_OP(x) ((x) << S_MDI_OP)
+
+#define A_SF_DATA 0x6d8
+
+#define A_SF_OP 0x6dc
+
+#define S_BYTECNT 1
+#define M_BYTECNT 0x3
+#define V_BYTECNT(x) ((x) << S_BYTECNT)
+
+#define A_PL_INT_ENABLE0 0x6e0
+
+#define S_T3DBG 23
+#define V_T3DBG(x) ((x) << S_T3DBG)
+#define F_T3DBG V_T3DBG(1U)
+
+#define S_XGMAC0_1 20
+#define V_XGMAC0_1(x) ((x) << S_XGMAC0_1)
+#define F_XGMAC0_1 V_XGMAC0_1(1U)
+
+#define S_XGMAC0_0 19
+#define V_XGMAC0_0(x) ((x) << S_XGMAC0_0)
+#define F_XGMAC0_0 V_XGMAC0_0(1U)
+
+#define S_MC5A 18
+#define V_MC5A(x) ((x) << S_MC5A)
+#define F_MC5A V_MC5A(1U)
+
+#define S_CPL_SWITCH 12
+#define V_CPL_SWITCH(x) ((x) << S_CPL_SWITCH)
+#define F_CPL_SWITCH V_CPL_SWITCH(1U)
+
+#define S_MPS0 11
+#define V_MPS0(x) ((x) << S_MPS0)
+#define F_MPS0 V_MPS0(1U)
+
+#define S_PM1_TX 10
+#define V_PM1_TX(x) ((x) << S_PM1_TX)
+#define F_PM1_TX V_PM1_TX(1U)
+
+#define S_PM1_RX 9
+#define V_PM1_RX(x) ((x) << S_PM1_RX)
+#define F_PM1_RX V_PM1_RX(1U)
+
+#define S_ULP2_TX 8
+#define V_ULP2_TX(x) ((x) << S_ULP2_TX)
+#define F_ULP2_TX V_ULP2_TX(1U)
+
+#define S_ULP2_RX 7
+#define V_ULP2_RX(x) ((x) << S_ULP2_RX)
+#define F_ULP2_RX V_ULP2_RX(1U)
+
+#define S_TP1 6
+#define V_TP1(x) ((x) << S_TP1)
+#define F_TP1 V_TP1(1U)
+
+#define S_CIM 5
+#define V_CIM(x) ((x) << S_CIM)
+#define F_CIM V_CIM(1U)
+
+#define S_MC7_CM 4
+#define V_MC7_CM(x) ((x) << S_MC7_CM)
+#define F_MC7_CM V_MC7_CM(1U)
+
+#define S_MC7_PMTX 3
+#define V_MC7_PMTX(x) ((x) << S_MC7_PMTX)
+#define F_MC7_PMTX V_MC7_PMTX(1U)
+
+#define S_MC7_PMRX 2
+#define V_MC7_PMRX(x) ((x) << S_MC7_PMRX)
+#define F_MC7_PMRX V_MC7_PMRX(1U)
+
+#define S_PCIM0 1
+#define V_PCIM0(x) ((x) << S_PCIM0)
+#define F_PCIM0 V_PCIM0(1U)
+
+#define S_SGE3 0
+#define V_SGE3(x) ((x) << S_SGE3)
+#define F_SGE3 V_SGE3(1U)
+
+#define A_PL_INT_CAUSE0 0x6e4
+
+#define A_PL_RST 0x6f0
+
+#define S_CRSTWRM 1
+#define V_CRSTWRM(x) ((x) << S_CRSTWRM)
+#define F_CRSTWRM V_CRSTWRM(1U)
+
+#define A_PL_REV 0x6f4
+
+#define A_PL_CLI 0x6f8
+
+#define A_MC5_DB_CONFIG 0x704
+
+#define S_TMTYPEHI 30
+#define V_TMTYPEHI(x) ((x) << S_TMTYPEHI)
+#define F_TMTYPEHI V_TMTYPEHI(1U)
+
+#define S_TMPARTSIZE 28
+#define M_TMPARTSIZE 0x3
+#define V_TMPARTSIZE(x) ((x) << S_TMPARTSIZE)
+#define G_TMPARTSIZE(x) (((x) >> S_TMPARTSIZE) & M_TMPARTSIZE)
+
+#define S_TMTYPE 26
+#define M_TMTYPE 0x3
+#define V_TMTYPE(x) ((x) << S_TMTYPE)
+#define G_TMTYPE(x) (((x) >> S_TMTYPE) & M_TMTYPE)
+
+#define S_COMPEN 17
+#define V_COMPEN(x) ((x) << S_COMPEN)
+#define F_COMPEN V_COMPEN(1U)
+
+#define S_PRTYEN 6
+#define V_PRTYEN(x) ((x) << S_PRTYEN)
+#define F_PRTYEN V_PRTYEN(1U)
+
+#define S_MBUSEN 5
+#define V_MBUSEN(x) ((x) << S_MBUSEN)
+#define F_MBUSEN V_MBUSEN(1U)
+
+#define S_DBGIEN 4
+#define V_DBGIEN(x) ((x) << S_DBGIEN)
+#define F_DBGIEN V_DBGIEN(1U)
+
+#define S_TMRDY 2
+#define V_TMRDY(x) ((x) << S_TMRDY)
+#define F_TMRDY V_TMRDY(1U)
+
+#define S_TMRST 1
+#define V_TMRST(x) ((x) << S_TMRST)
+#define F_TMRST V_TMRST(1U)
+
+#define S_TMMODE 0
+#define V_TMMODE(x) ((x) << S_TMMODE)
+#define F_TMMODE V_TMMODE(1U)
+
+#define F_TMMODE V_TMMODE(1U)
+
+#define A_MC5_DB_ROUTING_TABLE_INDEX 0x70c
+
+#define A_MC5_DB_FILTER_TABLE 0x710
+
+#define A_MC5_DB_SERVER_INDEX 0x714
+
+#define A_MC5_DB_RSP_LATENCY 0x720
+
+#define S_RDLAT 16
+#define M_RDLAT 0x1f
+#define V_RDLAT(x) ((x) << S_RDLAT)
+
+#define S_LRNLAT 8
+#define M_LRNLAT 0x1f
+#define V_LRNLAT(x) ((x) << S_LRNLAT)
+
+#define S_SRCHLAT 0
+#define M_SRCHLAT 0x1f
+#define V_SRCHLAT(x) ((x) << S_SRCHLAT)
+
+#define A_MC5_DB_PART_ID_INDEX 0x72c
+
+#define A_MC5_DB_INT_ENABLE 0x740
+
+#define S_DELACTEMPTY 18
+#define V_DELACTEMPTY(x) ((x) << S_DELACTEMPTY)
+#define F_DELACTEMPTY V_DELACTEMPTY(1U)
+
+#define S_DISPQPARERR 17
+#define V_DISPQPARERR(x) ((x) << S_DISPQPARERR)
+#define F_DISPQPARERR V_DISPQPARERR(1U)
+
+#define S_REQQPARERR 16
+#define V_REQQPARERR(x) ((x) << S_REQQPARERR)
+#define F_REQQPARERR V_REQQPARERR(1U)
+
+#define S_UNKNOWNCMD 15
+#define V_UNKNOWNCMD(x) ((x) << S_UNKNOWNCMD)
+#define F_UNKNOWNCMD V_UNKNOWNCMD(1U)
+
+#define S_NFASRCHFAIL 8
+#define V_NFASRCHFAIL(x) ((x) << S_NFASRCHFAIL)
+#define F_NFASRCHFAIL V_NFASRCHFAIL(1U)
+
+#define S_ACTRGNFULL 7
+#define V_ACTRGNFULL(x) ((x) << S_ACTRGNFULL)
+#define F_ACTRGNFULL V_ACTRGNFULL(1U)
+
+#define S_PARITYERR 6
+#define V_PARITYERR(x) ((x) << S_PARITYERR)
+#define F_PARITYERR V_PARITYERR(1U)
+
+#define A_MC5_DB_INT_CAUSE 0x744
+
+#define A_MC5_DB_DBGI_CONFIG 0x774
+
+#define A_MC5_DB_DBGI_REQ_CMD 0x778
+
+#define A_MC5_DB_DBGI_REQ_ADDR0 0x77c
+
+#define A_MC5_DB_DBGI_REQ_ADDR1 0x780
+
+#define A_MC5_DB_DBGI_REQ_ADDR2 0x784
+
+#define A_MC5_DB_DBGI_REQ_DATA0 0x788
+
+#define A_MC5_DB_DBGI_REQ_DATA1 0x78c
+
+#define A_MC5_DB_DBGI_REQ_DATA2 0x790
+
+#define A_MC5_DB_DBGI_RSP_STATUS 0x7b0
+
+#define S_DBGIRSPVALID 0
+#define V_DBGIRSPVALID(x) ((x) << S_DBGIRSPVALID)
+#define F_DBGIRSPVALID V_DBGIRSPVALID(1U)
+
+#define A_MC5_DB_DBGI_RSP_DATA0 0x7b4
+
+#define A_MC5_DB_DBGI_RSP_DATA1 0x7b8
+
+#define A_MC5_DB_DBGI_RSP_DATA2 0x7bc
+
+#define A_MC5_DB_POPEN_DATA_WR_CMD 0x7cc
+
+#define A_MC5_DB_POPEN_MASK_WR_CMD 0x7d0
+
+#define A_MC5_DB_AOPEN_SRCH_CMD 0x7d4
+
+#define A_MC5_DB_AOPEN_LRN_CMD 0x7d8
+
+#define A_MC5_DB_SYN_SRCH_CMD 0x7dc
+
+#define A_MC5_DB_SYN_LRN_CMD 0x7e0
+
+#define A_MC5_DB_ACK_SRCH_CMD 0x7e4
+
+#define A_MC5_DB_ACK_LRN_CMD 0x7e8
+
+#define A_MC5_DB_ILOOKUP_CMD 0x7ec
+
+#define A_MC5_DB_ELOOKUP_CMD 0x7f0
+
+#define A_MC5_DB_DATA_WRITE_CMD 0x7f4
+
+#define A_MC5_DB_DATA_READ_CMD 0x7f8
+
+#define XGMAC0_0_BASE_ADDR 0x800
+
+#define A_XGM_TX_CTRL 0x800
+
+#define S_TXEN 0
+#define V_TXEN(x) ((x) << S_TXEN)
+#define F_TXEN V_TXEN(1U)
+
+#define A_XGM_TX_CFG 0x804
+
+#define S_TXPAUSEEN 0
+#define V_TXPAUSEEN(x) ((x) << S_TXPAUSEEN)
+#define F_TXPAUSEEN V_TXPAUSEEN(1U)
+
+#define A_XGM_RX_CTRL 0x80c
+
+#define S_RXEN 0
+#define V_RXEN(x) ((x) << S_RXEN)
+#define F_RXEN V_RXEN(1U)
+
+#define A_XGM_RX_CFG 0x810
+
+#define S_DISPAUSEFRAMES 9
+#define V_DISPAUSEFRAMES(x) ((x) << S_DISPAUSEFRAMES)
+#define F_DISPAUSEFRAMES V_DISPAUSEFRAMES(1U)
+
+#define S_EN1536BFRAMES 8
+#define V_EN1536BFRAMES(x) ((x) << S_EN1536BFRAMES)
+#define F_EN1536BFRAMES V_EN1536BFRAMES(1U)
+
+#define S_ENJUMBO 7
+#define V_ENJUMBO(x) ((x) << S_ENJUMBO)
+#define F_ENJUMBO V_ENJUMBO(1U)
+
+#define S_RMFCS 6
+#define V_RMFCS(x) ((x) << S_RMFCS)
+#define F_RMFCS V_RMFCS(1U)
+
+#define S_ENHASHMCAST 2
+#define V_ENHASHMCAST(x) ((x) << S_ENHASHMCAST)
+#define F_ENHASHMCAST V_ENHASHMCAST(1U)
+
+#define S_COPYALLFRAMES 0
+#define V_COPYALLFRAMES(x) ((x) << S_COPYALLFRAMES)
+#define F_COPYALLFRAMES V_COPYALLFRAMES(1U)
+
+#define A_XGM_RX_HASH_LOW 0x814
+
+#define A_XGM_RX_HASH_HIGH 0x818
+
+#define A_XGM_RX_EXACT_MATCH_LOW_1 0x81c
+
+#define A_XGM_RX_EXACT_MATCH_HIGH_1 0x820
+
+#define A_XGM_RX_EXACT_MATCH_LOW_2 0x824
+
+#define A_XGM_RX_EXACT_MATCH_LOW_3 0x82c
+
+#define A_XGM_RX_EXACT_MATCH_LOW_4 0x834
+
+#define A_XGM_RX_EXACT_MATCH_LOW_5 0x83c
+
+#define A_XGM_RX_EXACT_MATCH_LOW_6 0x844
+
+#define A_XGM_RX_EXACT_MATCH_LOW_7 0x84c
+
+#define A_XGM_RX_EXACT_MATCH_LOW_8 0x854
+
+#define A_XGM_STAT_CTRL 0x880
+
+#define S_CLRSTATS 2
+#define V_CLRSTATS(x) ((x) << S_CLRSTATS)
+#define F_CLRSTATS V_CLRSTATS(1U)
+
+#define A_XGM_RXFIFO_CFG 0x884
+
+#define S_RXFIFOPAUSEHWM 17
+#define M_RXFIFOPAUSEHWM 0xfff
+
+#define V_RXFIFOPAUSEHWM(x) ((x) << S_RXFIFOPAUSEHWM)
+
+#define G_RXFIFOPAUSEHWM(x) (((x) >> S_RXFIFOPAUSEHWM) & M_RXFIFOPAUSEHWM)
+
+#define S_RXFIFOPAUSELWM 5
+#define M_RXFIFOPAUSELWM 0xfff
+
+#define V_RXFIFOPAUSELWM(x) ((x) << S_RXFIFOPAUSELWM)
+
+#define G_RXFIFOPAUSELWM(x) (((x) >> S_RXFIFOPAUSELWM) & M_RXFIFOPAUSELWM)
+
+#define S_RXSTRFRWRD 1
+#define V_RXSTRFRWRD(x) ((x) << S_RXSTRFRWRD)
+#define F_RXSTRFRWRD V_RXSTRFRWRD(1U)
+
+#define S_DISERRFRAMES 0
+#define V_DISERRFRAMES(x) ((x) << S_DISERRFRAMES)
+#define F_DISERRFRAMES V_DISERRFRAMES(1U)
+
+#define A_XGM_TXFIFO_CFG 0x888
+
+#define S_TXFIFOTHRESH 4
+#define M_TXFIFOTHRESH 0x1ff
+
+#define V_TXFIFOTHRESH(x) ((x) << S_TXFIFOTHRESH)
+
+#define A_XGM_SERDES_CTRL 0x890
+#define A_XGM_SERDES_CTRL0 0x8e0
+
+#define S_SERDESRESET_ 24
+#define V_SERDESRESET_(x) ((x) << S_SERDESRESET_)
+#define F_SERDESRESET_ V_SERDESRESET_(1U)
+
+#define S_RXENABLE 4
+#define V_RXENABLE(x) ((x) << S_RXENABLE)
+#define F_RXENABLE V_RXENABLE(1U)
+
+#define S_TXENABLE 3
+#define V_TXENABLE(x) ((x) << S_TXENABLE)
+#define F_TXENABLE V_TXENABLE(1U)
+
+#define A_XGM_PAUSE_TIMER 0x890
+
+#define A_XGM_RGMII_IMP 0x89c
+
+#define S_XGM_IMPSETUPDATE 6
+#define V_XGM_IMPSETUPDATE(x) ((x) << S_XGM_IMPSETUPDATE)
+#define F_XGM_IMPSETUPDATE V_XGM_IMPSETUPDATE(1U)
+
+#define S_RGMIIIMPPD 3
+#define M_RGMIIIMPPD 0x7
+#define V_RGMIIIMPPD(x) ((x) << S_RGMIIIMPPD)
+
+#define S_RGMIIIMPPU 0
+#define M_RGMIIIMPPU 0x7
+#define V_RGMIIIMPPU(x) ((x) << S_RGMIIIMPPU)
+
+#define S_CALRESET 8
+#define V_CALRESET(x) ((x) << S_CALRESET)
+#define F_CALRESET V_CALRESET(1U)
+
+#define S_CALUPDATE 7
+#define V_CALUPDATE(x) ((x) << S_CALUPDATE)
+#define F_CALUPDATE V_CALUPDATE(1U)
+
+#define A_XGM_XAUI_IMP 0x8a0
+
+#define S_CALBUSY 31
+#define V_CALBUSY(x) ((x) << S_CALBUSY)
+#define F_CALBUSY V_CALBUSY(1U)
+
+#define S_XGM_CALFAULT 29
+#define V_XGM_CALFAULT(x) ((x) << S_XGM_CALFAULT)
+#define F_XGM_CALFAULT V_XGM_CALFAULT(1U)
+
+#define S_CALIMP 24
+#define M_CALIMP 0x1f
+#define V_CALIMP(x) ((x) << S_CALIMP)
+#define G_CALIMP(x) (((x) >> S_CALIMP) & M_CALIMP)
+
+#define S_XAUIIMP 0
+#define M_XAUIIMP 0x7
+#define V_XAUIIMP(x) ((x) << S_XAUIIMP)
+
+#define A_XGM_RX_MAX_PKT_SIZE 0x8a8
+#define A_XGM_RX_MAX_PKT_SIZE_ERR_CNT 0x9a4
+
+#define A_XGM_RESET_CTRL 0x8ac
+
+#define S_XG2G_RESET_ 3
+#define V_XG2G_RESET_(x) ((x) << S_XG2G_RESET_)
+#define F_XG2G_RESET_ V_XG2G_RESET_(1U)
+
+#define S_RGMII_RESET_ 2
+#define V_RGMII_RESET_(x) ((x) << S_RGMII_RESET_)
+#define F_RGMII_RESET_ V_RGMII_RESET_(1U)
+
+#define S_PCS_RESET_ 1
+#define V_PCS_RESET_(x) ((x) << S_PCS_RESET_)
+#define F_PCS_RESET_ V_PCS_RESET_(1U)
+
+#define S_MAC_RESET_ 0
+#define V_MAC_RESET_(x) ((x) << S_MAC_RESET_)
+#define F_MAC_RESET_ V_MAC_RESET_(1U)
+
+#define A_XGM_PORT_CFG 0x8b8
+
+#define S_CLKDIVRESET_ 3
+#define V_CLKDIVRESET_(x) ((x) << S_CLKDIVRESET_)
+#define F_CLKDIVRESET_ V_CLKDIVRESET_(1U)
+
+#define S_PORTSPEED 1
+#define M_PORTSPEED 0x3
+
+#define V_PORTSPEED(x) ((x) << S_PORTSPEED)
+
+#define S_ENRGMII 0
+#define V_ENRGMII(x) ((x) << S_ENRGMII)
+#define F_ENRGMII V_ENRGMII(1U)
+
+#define A_XGM_INT_ENABLE 0x8d4
+
+#define S_TXFIFO_PRTY_ERR 17
+#define M_TXFIFO_PRTY_ERR 0x7
+
+#define V_TXFIFO_PRTY_ERR(x) ((x) << S_TXFIFO_PRTY_ERR)
+
+#define S_RXFIFO_PRTY_ERR 14
+#define M_RXFIFO_PRTY_ERR 0x7
+
+#define V_RXFIFO_PRTY_ERR(x) ((x) << S_RXFIFO_PRTY_ERR)
+
+#define S_TXFIFO_UNDERRUN 13
+#define V_TXFIFO_UNDERRUN(x) ((x) << S_TXFIFO_UNDERRUN)
+#define F_TXFIFO_UNDERRUN V_TXFIFO_UNDERRUN(1U)
+
+#define S_RXFIFO_OVERFLOW 12
+#define V_RXFIFO_OVERFLOW(x) ((x) << S_RXFIFO_OVERFLOW)
+#define F_RXFIFO_OVERFLOW V_RXFIFO_OVERFLOW(1U)
+
+#define S_SERDES_LOS 4
+#define M_SERDES_LOS 0xf
+
+#define V_SERDES_LOS(x) ((x) << S_SERDES_LOS)
+
+#define S_XAUIPCSCTCERR 3
+#define V_XAUIPCSCTCERR(x) ((x) << S_XAUIPCSCTCERR)
+#define F_XAUIPCSCTCERR V_XAUIPCSCTCERR(1U)
+
+#define S_XAUIPCSALIGNCHANGE 2
+#define V_XAUIPCSALIGNCHANGE(x) ((x) << S_XAUIPCSALIGNCHANGE)
+#define F_XAUIPCSALIGNCHANGE V_XAUIPCSALIGNCHANGE(1U)
+
+#define A_XGM_INT_CAUSE 0x8d8
+
+#define A_XGM_XAUI_ACT_CTRL 0x8dc
+
+#define S_TXACTENABLE 1
+#define V_TXACTENABLE(x) ((x) << S_TXACTENABLE)
+#define F_TXACTENABLE V_TXACTENABLE(1U)
+
+#define A_XGM_SERDES_CTRL0 0x8e0
+
+#define S_RESET3 23
+#define V_RESET3(x) ((x) << S_RESET3)
+#define F_RESET3 V_RESET3(1U)
+
+#define S_RESET2 22
+#define V_RESET2(x) ((x) << S_RESET2)
+#define F_RESET2 V_RESET2(1U)
+
+#define S_RESET1 21
+#define V_RESET1(x) ((x) << S_RESET1)
+#define F_RESET1 V_RESET1(1U)
+
+#define S_RESET0 20
+#define V_RESET0(x) ((x) << S_RESET0)
+#define F_RESET0 V_RESET0(1U)
+
+#define S_PWRDN3 19
+#define V_PWRDN3(x) ((x) << S_PWRDN3)
+#define F_PWRDN3 V_PWRDN3(1U)
+
+#define S_PWRDN2 18
+#define V_PWRDN2(x) ((x) << S_PWRDN2)
+#define F_PWRDN2 V_PWRDN2(1U)
+
+#define S_PWRDN1 17
+#define V_PWRDN1(x) ((x) << S_PWRDN1)
+#define F_PWRDN1 V_PWRDN1(1U)
+
+#define S_PWRDN0 16
+#define V_PWRDN0(x) ((x) << S_PWRDN0)
+#define F_PWRDN0 V_PWRDN0(1U)
+
+#define S_RESETPLL23 15
+#define V_RESETPLL23(x) ((x) << S_RESETPLL23)
+#define F_RESETPLL23 V_RESETPLL23(1U)
+
+#define S_RESETPLL01 14
+#define V_RESETPLL01(x) ((x) << S_RESETPLL01)
+#define F_RESETPLL01 V_RESETPLL01(1U)
+
+#define A_XGM_SERDES_STAT0 0x8f0
+
+#define S_LOWSIG0 0
+#define V_LOWSIG0(x) ((x) << S_LOWSIG0)
+#define F_LOWSIG0 V_LOWSIG0(1U)
+
+#define A_XGM_SERDES_STAT3 0x8fc
+
+#define A_XGM_STAT_TX_BYTE_LOW 0x900
+
+#define A_XGM_STAT_TX_BYTE_HIGH 0x904
+
+#define A_XGM_STAT_TX_FRAME_LOW 0x908
+
+#define A_XGM_STAT_TX_FRAME_HIGH 0x90c
+
+#define A_XGM_STAT_TX_BCAST 0x910
+
+#define A_XGM_STAT_TX_MCAST 0x914
+
+#define A_XGM_STAT_TX_PAUSE 0x918
+
+#define A_XGM_STAT_TX_64B_FRAMES 0x91c
+
+#define A_XGM_STAT_TX_65_127B_FRAMES 0x920
+
+#define A_XGM_STAT_TX_128_255B_FRAMES 0x924
+
+#define A_XGM_STAT_TX_256_511B_FRAMES 0x928
+
+#define A_XGM_STAT_TX_512_1023B_FRAMES 0x92c
+
+#define A_XGM_STAT_TX_1024_1518B_FRAMES 0x930
+
+#define A_XGM_STAT_TX_1519_MAXB_FRAMES 0x934
+
+#define A_XGM_STAT_TX_ERR_FRAMES 0x938
+
+#define A_XGM_STAT_RX_BYTES_LOW 0x93c
+
+#define A_XGM_STAT_RX_BYTES_HIGH 0x940
+
+#define A_XGM_STAT_RX_FRAMES_LOW 0x944
+
+#define A_XGM_STAT_RX_FRAMES_HIGH 0x948
+
+#define A_XGM_STAT_RX_BCAST_FRAMES 0x94c
+
+#define A_XGM_STAT_RX_MCAST_FRAMES 0x950
+
+#define A_XGM_STAT_RX_PAUSE_FRAMES 0x954
+
+#define A_XGM_STAT_RX_64B_FRAMES 0x958
+
+#define A_XGM_STAT_RX_65_127B_FRAMES 0x95c
+
+#define A_XGM_STAT_RX_128_255B_FRAMES 0x960
+
+#define A_XGM_STAT_RX_256_511B_FRAMES 0x964
+
+#define A_XGM_STAT_RX_512_1023B_FRAMES 0x968
+
+#define A_XGM_STAT_RX_1024_1518B_FRAMES 0x96c
+
+#define A_XGM_STAT_RX_1519_MAXB_FRAMES 0x970
+
+#define A_XGM_STAT_RX_SHORT_FRAMES 0x974
+
+#define A_XGM_STAT_RX_OVERSIZE_FRAMES 0x978
+
+#define A_XGM_STAT_RX_JABBER_FRAMES 0x97c
+
+#define A_XGM_STAT_RX_CRC_ERR_FRAMES 0x980
+
+#define A_XGM_STAT_RX_LENGTH_ERR_FRAMES 0x984
+
+#define A_XGM_STAT_RX_SYM_CODE_ERR_FRAMES 0x988
+
+#define A_XGM_SERDES_STATUS0 0x98c
+
+#define A_XGM_SERDES_STATUS1 0x990
+
+#define S_CMULOCK 31
+#define V_CMULOCK(x) ((x) << S_CMULOCK)
+#define F_CMULOCK V_CMULOCK(1U)
+
+#define A_XGM_RX_MAX_PKT_SIZE_ERR_CNT 0x9a4
+
+#define A_XGM_RX_SPI4_SOP_EOP_CNT 0x9ac
+
+#define XGMAC0_1_BASE_ADDR 0xa00
diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c
new file mode 100644
index 00000000000..3f2cf8a07c6
--- /dev/null
+++ b/drivers/net/cxgb3/sge.c
@@ -0,0 +1,2681 @@
+/*
+ * Copyright (c) 2005-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/if_vlan.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/dma-mapping.h>
+#include "common.h"
+#include "regs.h"
+#include "sge_defs.h"
+#include "t3_cpl.h"
+#include "firmware_exports.h"
+
+#define USE_GTS 0
+
+#define SGE_RX_SM_BUF_SIZE 1536
+#define SGE_RX_COPY_THRES 256
+
+# define SGE_RX_DROP_THRES 16
+
+/*
+ * Period of the Tx buffer reclaim timer. This timer does not need to run
+ * frequently as Tx buffers are usually reclaimed by new Tx packets.
+ */
+#define TX_RECLAIM_PERIOD (HZ / 4)
+
+/* WR size in bytes */
+#define WR_LEN (WR_FLITS * 8)
+
+/*
+ * Types of Tx queues in each queue set. Order here matters, do not change.
+ */
+enum { TXQ_ETH, TXQ_OFLD, TXQ_CTRL };
+
+/* Values for sge_txq.flags */
+enum {
+ TXQ_RUNNING = 1 << 0, /* fetch engine is running */
+ TXQ_LAST_PKT_DB = 1 << 1, /* last packet rang the doorbell */
+};
+
+struct tx_desc {
+ u64 flit[TX_DESC_FLITS];
+};
+
+struct rx_desc {
+ __be32 addr_lo;
+ __be32 len_gen;
+ __be32 gen2;
+ __be32 addr_hi;
+};
+
+struct tx_sw_desc { /* SW state per Tx descriptor */
+ struct sk_buff *skb;
+};
+
+struct rx_sw_desc { /* SW state per Rx descriptor */
+ struct sk_buff *skb;
+ DECLARE_PCI_UNMAP_ADDR(dma_addr);
+};
+
+struct rsp_desc { /* response queue descriptor */
+ struct rss_header rss_hdr;
+ __be32 flags;
+ __be32 len_cq;
+ u8 imm_data[47];
+ u8 intr_gen;
+};
+
+struct unmap_info { /* packet unmapping info, overlays skb->cb */
+ int sflit; /* start flit of first SGL entry in Tx descriptor */
+ u16 fragidx; /* first page fragment in current Tx descriptor */
+ u16 addr_idx; /* buffer index of first SGL entry in descriptor */
+ u32 len; /* mapped length of skb main body */
+};
+
+/*
+ * Maps a number of flits to the number of Tx descriptors that can hold them.
+ * The formula is
+ *
+ * desc = 1 + (flits - 2) / (WR_FLITS - 1).
+ *
+ * HW allows up to 4 descriptors to be combined into a WR.
+ */
+static u8 flit_desc_map[] = {
+ 0,
+#if SGE_NUM_GENBITS == 1
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4
+#elif SGE_NUM_GENBITS == 2
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+#else
+# error "SGE_NUM_GENBITS must be 1 or 2"
+#endif
+};
+
+static inline struct sge_qset *fl_to_qset(const struct sge_fl *q, int qidx)
+{
+ return container_of(q, struct sge_qset, fl[qidx]);
+}
+
+static inline struct sge_qset *rspq_to_qset(const struct sge_rspq *q)
+{
+ return container_of(q, struct sge_qset, rspq);
+}
+
+static inline struct sge_qset *txq_to_qset(const struct sge_txq *q, int qidx)
+{
+ return container_of(q, struct sge_qset, txq[qidx]);
+}
+
+/**
+ * refill_rspq - replenish an SGE response queue
+ * @adapter: the adapter
+ * @q: the response queue to replenish
+ * @credits: how many new responses to make available
+ *
+ * Replenishes a response queue by making the supplied number of responses
+ * available to HW.
+ */
+static inline void refill_rspq(struct adapter *adapter,
+ const struct sge_rspq *q, unsigned int credits)
+{
+ t3_write_reg(adapter, A_SG_RSPQ_CREDIT_RETURN,
+ V_RSPQ(q->cntxt_id) | V_CREDITS(credits));
+}
+
+/**
+ * need_skb_unmap - does the platform need unmapping of sk_buffs?
+ *
+ * Returns true if the platfrom 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
+ * unmapping by checking if DECLARE_PCI_UNMAP_ADDR defines anything.
+ */
+ struct dummy {
+ DECLARE_PCI_UNMAP_ADDR(addr);
+ };
+
+ return sizeof(struct dummy) != 0;
+}
+
+/**
+ * unmap_skb - unmap a packet main body and its page fragments
+ * @skb: the packet
+ * @q: the Tx queue containing Tx descriptors for the packet
+ * @cidx: index of Tx descriptor
+ * @pdev: the PCI device
+ *
+ * Unmap the main body of an sk_buff and its page fragments, if any.
+ * Because of the fairly complicated structure of our SGLs and the desire
+ * to conserve space for metadata, we keep the information necessary to
+ * unmap an sk_buff partly in the sk_buff itself (in its cb), and partly
+ * in the Tx descriptors (the physical addresses of the various data
+ * buffers). The send functions initialize the state in skb->cb so we
+ * can unmap the buffers held in the first Tx descriptor here, and we
+ * have enough information at this point to update the state for the next
+ * Tx descriptor.
+ */
+static inline void unmap_skb(struct sk_buff *skb, struct sge_txq *q,
+ unsigned int cidx, struct pci_dev *pdev)
+{
+ const struct sg_ent *sgp;
+ struct unmap_info *ui = (struct unmap_info *)skb->cb;
+ int nfrags, frag_idx, curflit, j = ui->addr_idx;
+
+ sgp = (struct sg_ent *)&q->desc[cidx].flit[ui->sflit];
+
+ if (ui->len) {
+ pci_unmap_single(pdev, be64_to_cpu(sgp->addr[0]), ui->len,
+ PCI_DMA_TODEVICE);
+ ui->len = 0; /* so we know for next descriptor for this skb */
+ j = 1;
+ }
+
+ frag_idx = ui->fragidx;
+ curflit = ui->sflit + 1 + j;
+ nfrags = skb_shinfo(skb)->nr_frags;
+
+ while (frag_idx < nfrags && curflit < WR_FLITS) {
+ pci_unmap_page(pdev, be64_to_cpu(sgp->addr[j]),
+ skb_shinfo(skb)->frags[frag_idx].size,
+ PCI_DMA_TODEVICE);
+ j ^= 1;
+ if (j == 0) {
+ sgp++;
+ curflit++;
+ }
+ curflit++;
+ frag_idx++;
+ }
+
+ if (frag_idx < nfrags) { /* SGL continues into next Tx descriptor */
+ ui->fragidx = frag_idx;
+ ui->addr_idx = j;
+ ui->sflit = curflit - WR_FLITS - j; /* sflit can be -1 */
+ }
+}
+
+/**
+ * free_tx_desc - reclaims Tx descriptors and their buffers
+ * @adapter: the adapter
+ * @q: the Tx queue to reclaim descriptors from
+ * @n: the number of descriptors to reclaim
+ *
+ * Reclaims Tx descriptors from an SGE Tx queue and frees the associated
+ * Tx buffers. Called with the Tx queue lock held.
+ */
+static void free_tx_desc(struct adapter *adapter, struct sge_txq *q,
+ unsigned int n)
+{
+ struct tx_sw_desc *d;
+ struct pci_dev *pdev = adapter->pdev;
+ unsigned int cidx = q->cidx;
+
+ d = &q->sdesc[cidx];
+ while (n--) {
+ if (d->skb) { /* an SGL is present */
+ if (need_skb_unmap())
+ unmap_skb(d->skb, q, cidx, pdev);
+ if (d->skb->priority == cidx)
+ kfree_skb(d->skb);
+ }
+ ++d;
+ if (++cidx == q->size) {
+ cidx = 0;
+ d = q->sdesc;
+ }
+ }
+ q->cidx = cidx;
+}
+
+/**
+ * reclaim_completed_tx - reclaims completed Tx descriptors
+ * @adapter: the adapter
+ * @q: the Tx queue to reclaim completed descriptors from
+ *
+ * Reclaims Tx descriptors that the SGE has indicated it has processed,
+ * and frees the associated buffers if possible. Called with the Tx
+ * queue's lock held.
+ */
+static inline void reclaim_completed_tx(struct adapter *adapter,
+ struct sge_txq *q)
+{
+ unsigned int reclaim = q->processed - q->cleaned;
+
+ if (reclaim) {
+ free_tx_desc(adapter, q, reclaim);
+ q->cleaned += reclaim;
+ q->in_use -= reclaim;
+ }
+}
+
+/**
+ * should_restart_tx - are there enough resources to restart a Tx queue?
+ * @q: the Tx queue
+ *
+ * Checks if there are enough descriptors to restart a suspended Tx queue.
+ */
+static inline int should_restart_tx(const struct sge_txq *q)
+{
+ unsigned int r = q->processed - q->cleaned;
+
+ return q->in_use - r < (q->size >> 1);
+}
+
+/**
+ * free_rx_bufs - free the Rx buffers on an SGE free list
+ * @pdev: the PCI device associated with the adapter
+ * @rxq: the SGE free list to clean up
+ *
+ * Release the buffers on an SGE free-buffer Rx queue. HW fetching from
+ * this queue should be stopped before calling this function.
+ */
+static void free_rx_bufs(struct pci_dev *pdev, struct sge_fl *q)
+{
+ unsigned int cidx = q->cidx;
+
+ while (q->credits--) {
+ struct rx_sw_desc *d = &q->sdesc[cidx];
+
+ pci_unmap_single(pdev, pci_unmap_addr(d, dma_addr),
+ q->buf_size, PCI_DMA_FROMDEVICE);
+ kfree_skb(d->skb);
+ d->skb = NULL;
+ if (++cidx == q->size)
+ cidx = 0;
+ }
+}
+
+/**
+ * add_one_rx_buf - add a packet buffer to a free-buffer list
+ * @skb: the buffer to add
+ * @len: the buffer length
+ * @d: the HW Rx descriptor to write
+ * @sd: the SW Rx descriptor to write
+ * @gen: the generation bit value
+ * @pdev: the PCI device associated with the adapter
+ *
+ * Add a buffer of the given length to the supplied HW and SW Rx
+ * descriptors.
+ */
+static inline void add_one_rx_buf(struct sk_buff *skb, unsigned int len,
+ struct rx_desc *d, struct rx_sw_desc *sd,
+ unsigned int gen, struct pci_dev *pdev)
+{
+ dma_addr_t mapping;
+
+ sd->skb = skb;
+ mapping = pci_map_single(pdev, skb->data, len, PCI_DMA_FROMDEVICE);
+ pci_unmap_addr_set(sd, dma_addr, mapping);
+
+ d->addr_lo = cpu_to_be32(mapping);
+ d->addr_hi = cpu_to_be32((u64) mapping >> 32);
+ wmb();
+ d->len_gen = cpu_to_be32(V_FLD_GEN1(gen));
+ d->gen2 = cpu_to_be32(V_FLD_GEN2(gen));
+}
+
+/**
+ * refill_fl - refill an SGE free-buffer list
+ * @adapter: the adapter
+ * @q: the free-list to refill
+ * @n: the number of new buffers to allocate
+ * @gfp: the gfp flags for allocating new buffers
+ *
+ * (Re)populate an SGE free-buffer list with up to @n new packet buffers,
+ * allocated with the supplied gfp flags. The caller must assure that
+ * @n does not exceed the queue's capacity.
+ */
+static void refill_fl(struct adapter *adap, struct sge_fl *q, int n, gfp_t gfp)
+{
+ struct rx_sw_desc *sd = &q->sdesc[q->pidx];
+ struct rx_desc *d = &q->desc[q->pidx];
+
+ while (n--) {
+ struct sk_buff *skb = alloc_skb(q->buf_size, gfp);
+
+ if (!skb)
+ break;
+
+ add_one_rx_buf(skb, q->buf_size, d, sd, q->gen, adap->pdev);
+ d++;
+ sd++;
+ if (++q->pidx == q->size) {
+ q->pidx = 0;
+ q->gen ^= 1;
+ sd = q->sdesc;
+ d = q->desc;
+ }
+ q->credits++;
+ }
+
+ t3_write_reg(adap, A_SG_KDOORBELL, V_EGRCNTX(q->cntxt_id));
+}
+
+static inline void __refill_fl(struct adapter *adap, struct sge_fl *fl)
+{
+ refill_fl(adap, fl, min(16U, fl->size - fl->credits), GFP_ATOMIC);
+}
+
+/**
+ * recycle_rx_buf - recycle a receive buffer
+ * @adapter: the adapter
+ * @q: the SGE free list
+ * @idx: index of buffer to recycle
+ *
+ * Recycles the specified buffer on the given free list by adding it at
+ * the next available slot on the list.
+ */
+static void recycle_rx_buf(struct adapter *adap, struct sge_fl *q,
+ unsigned int idx)
+{
+ struct rx_desc *from = &q->desc[idx];
+ struct rx_desc *to = &q->desc[q->pidx];
+
+ q->sdesc[q->pidx] = q->sdesc[idx];
+ to->addr_lo = from->addr_lo; /* already big endian */
+ to->addr_hi = from->addr_hi; /* likewise */
+ wmb();
+ to->len_gen = cpu_to_be32(V_FLD_GEN1(q->gen));
+ to->gen2 = cpu_to_be32(V_FLD_GEN2(q->gen));
+ q->credits++;
+
+ if (++q->pidx == q->size) {
+ q->pidx = 0;
+ q->gen ^= 1;
+ }
+ t3_write_reg(adap, A_SG_KDOORBELL, V_EGRCNTX(q->cntxt_id));
+}
+
+/**
+ * alloc_ring - allocate resources for an SGE descriptor ring
+ * @pdev: the PCI device
+ * @nelem: the number of descriptors
+ * @elem_size: the size of each descriptor
+ * @sw_size: the size of the SW state associated with each ring element
+ * @phys: the physical address of the allocated ring
+ * @metadata: address of the array holding the SW state for the ring
+ *
+ * Allocates resources for an SGE descriptor ring, such as Tx queues,
+ * free buffer lists, or response queues. Each SGE ring requires
+ * space for its HW descriptors plus, optionally, space for the SW state
+ * associated with each HW entry (the metadata). The function returns
+ * three values: the virtual address for the HW ring (the return value
+ * of the function), the physical address of the HW ring, and the address
+ * of the SW ring.
+ */
+static void *alloc_ring(struct pci_dev *pdev, size_t nelem, size_t elem_size,
+ size_t sw_size, dma_addr_t *phys, void *metadata)
+{
+ size_t len = nelem * elem_size;
+ void *s = NULL;
+ void *p = dma_alloc_coherent(&pdev->dev, len, phys, GFP_KERNEL);
+
+ if (!p)
+ return NULL;
+ if (sw_size) {
+ s = kcalloc(nelem, sw_size, GFP_KERNEL);
+
+ if (!s) {
+ dma_free_coherent(&pdev->dev, len, p, *phys);
+ return NULL;
+ }
+ }
+ if (metadata)
+ *(void **)metadata = s;
+ memset(p, 0, len);
+ return p;
+}
+
+/**
+ * free_qset - free the resources of an SGE queue set
+ * @adapter: the adapter owning the queue set
+ * @q: the queue set
+ *
+ * Release the HW and SW resources associated with an SGE queue set, such
+ * as HW contexts, packet buffers, and descriptor rings. Traffic to the
+ * queue set must be quiesced prior to calling this.
+ */
+void t3_free_qset(struct adapter *adapter, struct sge_qset *q)
+{
+ int i;
+ struct pci_dev *pdev = adapter->pdev;
+
+ if (q->tx_reclaim_timer.function)
+ del_timer_sync(&q->tx_reclaim_timer);
+
+ for (i = 0; i < SGE_RXQ_PER_SET; ++i)
+ if (q->fl[i].desc) {
+ spin_lock(&adapter->sge.reg_lock);
+ t3_sge_disable_fl(adapter, q->fl[i].cntxt_id);
+ spin_unlock(&adapter->sge.reg_lock);
+ free_rx_bufs(pdev, &q->fl[i]);
+ kfree(q->fl[i].sdesc);
+ dma_free_coherent(&pdev->dev,
+ q->fl[i].size *
+ sizeof(struct rx_desc), q->fl[i].desc,
+ q->fl[i].phys_addr);
+ }
+
+ for (i = 0; i < SGE_TXQ_PER_SET; ++i)
+ if (q->txq[i].desc) {
+ spin_lock(&adapter->sge.reg_lock);
+ t3_sge_enable_ecntxt(adapter, q->txq[i].cntxt_id, 0);
+ spin_unlock(&adapter->sge.reg_lock);
+ if (q->txq[i].sdesc) {
+ free_tx_desc(adapter, &q->txq[i],
+ q->txq[i].in_use);
+ kfree(q->txq[i].sdesc);
+ }
+ dma_free_coherent(&pdev->dev,
+ q->txq[i].size *
+ sizeof(struct tx_desc),
+ q->txq[i].desc, q->txq[i].phys_addr);
+ __skb_queue_purge(&q->txq[i].sendq);
+ }
+
+ if (q->rspq.desc) {
+ spin_lock(&adapter->sge.reg_lock);
+ t3_sge_disable_rspcntxt(adapter, q->rspq.cntxt_id);
+ spin_unlock(&adapter->sge.reg_lock);
+ dma_free_coherent(&pdev->dev,
+ q->rspq.size * sizeof(struct rsp_desc),
+ q->rspq.desc, q->rspq.phys_addr);
+ }
+
+ if (q->netdev)
+ q->netdev->atalk_ptr = NULL;
+
+ memset(q, 0, sizeof(*q));
+}
+
+/**
+ * init_qset_cntxt - initialize an SGE queue set context info
+ * @qs: the queue set
+ * @id: the queue set id
+ *
+ * Initializes the TIDs and context ids for the queues of a queue set.
+ */
+static void init_qset_cntxt(struct sge_qset *qs, unsigned int id)
+{
+ qs->rspq.cntxt_id = id;
+ qs->fl[0].cntxt_id = 2 * id;
+ qs->fl[1].cntxt_id = 2 * id + 1;
+ qs->txq[TXQ_ETH].cntxt_id = FW_TUNNEL_SGEEC_START + id;
+ qs->txq[TXQ_ETH].token = FW_TUNNEL_TID_START + id;
+ qs->txq[TXQ_OFLD].cntxt_id = FW_OFLD_SGEEC_START + id;
+ qs->txq[TXQ_CTRL].cntxt_id = FW_CTRL_SGEEC_START + id;
+ qs->txq[TXQ_CTRL].token = FW_CTRL_TID_START + id;
+}
+
+/**
+ * sgl_len - calculates the size of an SGL of the given capacity
+ * @n: the number of SGL entries
+ *
+ * Calculates the number of flits needed for a scatter/gather list that
+ * can hold the given number of entries.
+ */
+static inline unsigned int sgl_len(unsigned int n)
+{
+ /* alternatively: 3 * (n / 2) + 2 * (n & 1) */
+ return (3 * n) / 2 + (n & 1);
+}
+
+/**
+ * flits_to_desc - returns the num of Tx descriptors for the given flits
+ * @n: the number of flits
+ *
+ * Calculates the number of Tx descriptors needed for the supplied number
+ * of flits.
+ */
+static inline unsigned int flits_to_desc(unsigned int n)
+{
+ BUG_ON(n >= ARRAY_SIZE(flit_desc_map));
+ return flit_desc_map[n];
+}
+
+/**
+ * get_packet - return the next ingress packet buffer from a free list
+ * @adap: the adapter that received the packet
+ * @fl: the SGE free list holding the packet
+ * @len: the packet length including any SGE padding
+ * @drop_thres: # of remaining buffers before we start dropping packets
+ *
+ * Get the next packet from a free list and complete setup of the
+ * sk_buff. If the packet is small we make a copy and recycle the
+ * original buffer, otherwise we use the original buffer itself. If a
+ * positive drop threshold is supplied packets are dropped and their
+ * buffers recycled if (a) the number of remaining buffers is under the
+ * threshold and the packet is too big to copy, or (b) the packet should
+ * be copied but there is no memory for the copy.
+ */
+static struct sk_buff *get_packet(struct adapter *adap, struct sge_fl *fl,
+ unsigned int len, unsigned int drop_thres)
+{
+ struct sk_buff *skb = NULL;
+ struct rx_sw_desc *sd = &fl->sdesc[fl->cidx];
+
+ prefetch(sd->skb->data);
+
+ if (len <= SGE_RX_COPY_THRES) {
+ skb = alloc_skb(len, GFP_ATOMIC);
+ if (likely(skb != NULL)) {
+ __skb_put(skb, len);
+ pci_dma_sync_single_for_cpu(adap->pdev,
+ pci_unmap_addr(sd,
+ dma_addr),
+ len, PCI_DMA_FROMDEVICE);
+ memcpy(skb->data, sd->skb->data, len);
+ pci_dma_sync_single_for_device(adap->pdev,
+ pci_unmap_addr(sd,
+ dma_addr),
+ len, PCI_DMA_FROMDEVICE);
+ } else if (!drop_thres)
+ goto use_orig_buf;
+ recycle:
+ recycle_rx_buf(adap, fl, fl->cidx);
+ return skb;
+ }
+
+ if (unlikely(fl->credits < drop_thres))
+ goto recycle;
+
+ use_orig_buf:
+ pci_unmap_single(adap->pdev, pci_unmap_addr(sd, dma_addr),
+ fl->buf_size, PCI_DMA_FROMDEVICE);
+ skb = sd->skb;
+ skb_put(skb, len);
+ __refill_fl(adap, fl);
+ return skb;
+}
+
+/**
+ * get_imm_packet - return the next ingress packet buffer from a response
+ * @resp: the response descriptor containing the packet data
+ *
+ * Return a packet containing the immediate data of the given response.
+ */
+static inline struct sk_buff *get_imm_packet(const struct rsp_desc *resp)
+{
+ struct sk_buff *skb = alloc_skb(IMMED_PKT_SIZE, GFP_ATOMIC);
+
+ if (skb) {
+ __skb_put(skb, IMMED_PKT_SIZE);
+ memcpy(skb->data, resp->imm_data, IMMED_PKT_SIZE);
+ }
+ return skb;
+}
+
+/**
+ * calc_tx_descs - calculate the number of Tx descriptors for a packet
+ * @skb: the packet
+ *
+ * Returns the number of Tx descriptors needed for the given Ethernet
+ * packet. Ethernet packets require addition of WR and CPL headers.
+ */
+static inline unsigned int calc_tx_descs(const struct sk_buff *skb)
+{
+ unsigned int flits;
+
+ if (skb->len <= WR_LEN - sizeof(struct cpl_tx_pkt))
+ return 1;
+
+ flits = sgl_len(skb_shinfo(skb)->nr_frags + 1) + 2;
+ if (skb_shinfo(skb)->gso_size)
+ flits++;
+ return flits_to_desc(flits);
+}
+
+/**
+ * make_sgl - populate a scatter/gather list for a packet
+ * @skb: the packet
+ * @sgp: the SGL to populate
+ * @start: start address of skb main body data to include in the SGL
+ * @len: length of skb main body data to include in the SGL
+ * @pdev: the PCI device
+ *
+ * Generates a scatter/gather list for the buffers that make up a packet
+ * and returns the SGL size in 8-byte words. The caller must size the SGL
+ * appropriately.
+ */
+static inline unsigned int make_sgl(const struct sk_buff *skb,
+ struct sg_ent *sgp, unsigned char *start,
+ unsigned int len, struct pci_dev *pdev)
+{
+ dma_addr_t mapping;
+ unsigned int i, j = 0, nfrags;
+
+ if (len) {
+ mapping = pci_map_single(pdev, start, len, PCI_DMA_TODEVICE);
+ sgp->len[0] = cpu_to_be32(len);
+ sgp->addr[0] = cpu_to_be64(mapping);
+ j = 1;
+ }
+
+ nfrags = skb_shinfo(skb)->nr_frags;
+ for (i = 0; i < nfrags; i++) {
+ skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+
+ mapping = pci_map_page(pdev, frag->page, frag->page_offset,
+ frag->size, PCI_DMA_TODEVICE);
+ sgp->len[j] = cpu_to_be32(frag->size);
+ sgp->addr[j] = cpu_to_be64(mapping);
+ j ^= 1;
+ if (j == 0)
+ ++sgp;
+ }
+ if (j)
+ sgp->len[j] = 0;
+ return ((nfrags + (len != 0)) * 3) / 2 + j;
+}
+
+/**
+ * check_ring_tx_db - check and potentially ring a Tx queue's doorbell
+ * @adap: the adapter
+ * @q: the Tx queue
+ *
+ * Ring the doorbel if a Tx queue is asleep. There is a natural race,
+ * where the HW is going to sleep just after we checked, however,
+ * then the interrupt handler will detect the outstanding TX packet
+ * and ring the doorbell for us.
+ *
+ * When GTS is disabled we unconditionally ring the doorbell.
+ */
+static inline void check_ring_tx_db(struct adapter *adap, struct sge_txq *q)
+{
+#if USE_GTS
+ clear_bit(TXQ_LAST_PKT_DB, &q->flags);
+ if (test_and_set_bit(TXQ_RUNNING, &q->flags) == 0) {
+ set_bit(TXQ_LAST_PKT_DB, &q->flags);
+ t3_write_reg(adap, A_SG_KDOORBELL,
+ F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id));
+ }
+#else
+ wmb(); /* write descriptors before telling HW */
+ t3_write_reg(adap, A_SG_KDOORBELL,
+ F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id));
+#endif
+}
+
+static inline void wr_gen2(struct tx_desc *d, unsigned int gen)
+{
+#if SGE_NUM_GENBITS == 2
+ d->flit[TX_DESC_FLITS - 1] = cpu_to_be64(gen);
+#endif
+}
+
+/**
+ * write_wr_hdr_sgl - write a WR header and, optionally, SGL
+ * @ndesc: number of Tx descriptors spanned by the SGL
+ * @skb: the packet corresponding to the WR
+ * @d: first Tx descriptor to be written
+ * @pidx: index of above descriptors
+ * @q: the SGE Tx queue
+ * @sgl: the SGL
+ * @flits: number of flits to the start of the SGL in the first descriptor
+ * @sgl_flits: the SGL size in flits
+ * @gen: the Tx descriptor generation
+ * @wr_hi: top 32 bits of WR header based on WR type (big endian)
+ * @wr_lo: low 32 bits of WR header based on WR type (big endian)
+ *
+ * Write a work request header and an associated SGL. If the SGL is
+ * small enough to fit into one Tx descriptor it has already been written
+ * and we just need to write the WR header. Otherwise we distribute the
+ * SGL across the number of descriptors it spans.
+ */
+static void write_wr_hdr_sgl(unsigned int ndesc, struct sk_buff *skb,
+ struct tx_desc *d, unsigned int pidx,
+ const struct sge_txq *q,
+ const struct sg_ent *sgl,
+ unsigned int flits, unsigned int sgl_flits,
+ unsigned int gen, unsigned int wr_hi,
+ unsigned int wr_lo)
+{
+ struct work_request_hdr *wrp = (struct work_request_hdr *)d;
+ struct tx_sw_desc *sd = &q->sdesc[pidx];
+
+ sd->skb = skb;
+ if (need_skb_unmap()) {
+ struct unmap_info *ui = (struct unmap_info *)skb->cb;
+
+ ui->fragidx = 0;
+ ui->addr_idx = 0;
+ ui->sflit = flits;
+ }
+
+ if (likely(ndesc == 1)) {
+ skb->priority = pidx;
+ wrp->wr_hi = htonl(F_WR_SOP | F_WR_EOP | V_WR_DATATYPE(1) |
+ V_WR_SGLSFLT(flits)) | wr_hi;
+ wmb();
+ wrp->wr_lo = htonl(V_WR_LEN(flits + sgl_flits) |
+ V_WR_GEN(gen)) | wr_lo;
+ wr_gen2(d, gen);
+ } else {
+ unsigned int ogen = gen;
+ const u64 *fp = (const u64 *)sgl;
+ struct work_request_hdr *wp = wrp;
+
+ wrp->wr_hi = htonl(F_WR_SOP | V_WR_DATATYPE(1) |
+ V_WR_SGLSFLT(flits)) | wr_hi;
+
+ while (sgl_flits) {
+ unsigned int avail = WR_FLITS - flits;
+
+ if (avail > sgl_flits)
+ avail = sgl_flits;
+ memcpy(&d->flit[flits], fp, avail * sizeof(*fp));
+ sgl_flits -= avail;
+ ndesc--;
+ if (!sgl_flits)
+ break;
+
+ fp += avail;
+ d++;
+ sd++;
+ if (++pidx == q->size) {
+ pidx = 0;
+ gen ^= 1;
+ d = q->desc;
+ sd = q->sdesc;
+ }
+
+ sd->skb = skb;
+ wrp = (struct work_request_hdr *)d;
+ wrp->wr_hi = htonl(V_WR_DATATYPE(1) |
+ V_WR_SGLSFLT(1)) | wr_hi;
+ wrp->wr_lo = htonl(V_WR_LEN(min(WR_FLITS,
+ sgl_flits + 1)) |
+ V_WR_GEN(gen)) | wr_lo;
+ wr_gen2(d, gen);
+ flits = 1;
+ }
+ skb->priority = pidx;
+ wrp->wr_hi |= htonl(F_WR_EOP);
+ wmb();
+ wp->wr_lo = htonl(V_WR_LEN(WR_FLITS) | V_WR_GEN(ogen)) | wr_lo;
+ wr_gen2((struct tx_desc *)wp, ogen);
+ WARN_ON(ndesc != 0);
+ }
+}
+
+/**
+ * write_tx_pkt_wr - write a TX_PKT work request
+ * @adap: the adapter
+ * @skb: the packet to send
+ * @pi: the egress interface
+ * @pidx: index of the first Tx descriptor to write
+ * @gen: the generation value to use
+ * @q: the Tx queue
+ * @ndesc: number of descriptors the packet will occupy
+ * @compl: the value of the COMPL bit to use
+ *
+ * Generate a TX_PKT work request to send the supplied packet.
+ */
+static void write_tx_pkt_wr(struct adapter *adap, struct sk_buff *skb,
+ const struct port_info *pi,
+ unsigned int pidx, unsigned int gen,
+ struct sge_txq *q, unsigned int ndesc,
+ unsigned int compl)
+{
+ unsigned int flits, sgl_flits, cntrl, tso_info;
+ struct sg_ent *sgp, sgl[MAX_SKB_FRAGS / 2 + 1];
+ struct tx_desc *d = &q->desc[pidx];
+ struct cpl_tx_pkt *cpl = (struct cpl_tx_pkt *)d;
+
+ cpl->len = htonl(skb->len | 0x80000000);
+ cntrl = V_TXPKT_INTF(pi->port_id);
+
+ if (vlan_tx_tag_present(skb) && pi->vlan_grp)
+ cntrl |= F_TXPKT_VLAN_VLD | V_TXPKT_VLAN(vlan_tx_tag_get(skb));
+
+ tso_info = V_LSO_MSS(skb_shinfo(skb)->gso_size);
+ if (tso_info) {
+ int eth_type;
+ struct cpl_tx_pkt_lso *hdr = (struct cpl_tx_pkt_lso *)cpl;
+
+ d->flit[2] = 0;
+ cntrl |= V_TXPKT_OPCODE(CPL_TX_PKT_LSO);
+ hdr->cntrl = htonl(cntrl);
+ eth_type = skb->nh.raw - skb->data == ETH_HLEN ?
+ CPL_ETH_II : CPL_ETH_II_VLAN;
+ tso_info |= V_LSO_ETH_TYPE(eth_type) |
+ V_LSO_IPHDR_WORDS(skb->nh.iph->ihl) |
+ V_LSO_TCPHDR_WORDS(skb->h.th->doff);
+ hdr->lso_info = htonl(tso_info);
+ flits = 3;
+ } else {
+ cntrl |= V_TXPKT_OPCODE(CPL_TX_PKT);
+ cntrl |= F_TXPKT_IPCSUM_DIS; /* SW calculates IP csum */
+ cntrl |= V_TXPKT_L4CSUM_DIS(skb->ip_summed != CHECKSUM_PARTIAL);
+ cpl->cntrl = htonl(cntrl);
+
+ if (skb->len <= WR_LEN - sizeof(*cpl)) {
+ q->sdesc[pidx].skb = NULL;
+ if (!skb->data_len)
+ memcpy(&d->flit[2], skb->data, skb->len);
+ else
+ skb_copy_bits(skb, 0, &d->flit[2], skb->len);
+
+ flits = (skb->len + 7) / 8 + 2;
+ cpl->wr.wr_hi = htonl(V_WR_BCNTLFLT(skb->len & 7) |
+ V_WR_OP(FW_WROPCODE_TUNNEL_TX_PKT)
+ | F_WR_SOP | F_WR_EOP | compl);
+ wmb();
+ cpl->wr.wr_lo = htonl(V_WR_LEN(flits) | V_WR_GEN(gen) |
+ V_WR_TID(q->token));
+ wr_gen2(d, gen);
+ kfree_skb(skb);
+ return;
+ }
+
+ flits = 2;
+ }
+
+ sgp = ndesc == 1 ? (struct sg_ent *)&d->flit[flits] : sgl;
+ sgl_flits = make_sgl(skb, sgp, skb->data, skb_headlen(skb), adap->pdev);
+ if (need_skb_unmap())
+ ((struct unmap_info *)skb->cb)->len = skb_headlen(skb);
+
+ write_wr_hdr_sgl(ndesc, skb, d, pidx, q, sgl, flits, sgl_flits, gen,
+ htonl(V_WR_OP(FW_WROPCODE_TUNNEL_TX_PKT) | compl),
+ htonl(V_WR_TID(q->token)));
+}
+
+/**
+ * eth_xmit - add a packet to the Ethernet Tx queue
+ * @skb: the packet
+ * @dev: the egress net device
+ *
+ * Add a packet to an SGE Tx queue. Runs with softirqs disabled.
+ */
+int t3_eth_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ unsigned int ndesc, pidx, credits, gen, compl;
+ const struct port_info *pi = netdev_priv(dev);
+ struct adapter *adap = dev->priv;
+ struct sge_qset *qs = dev2qset(dev);
+ struct sge_txq *q = &qs->txq[TXQ_ETH];
+
+ /*
+ * The chip min packet length is 9 octets but play safe and reject
+ * anything shorter than an Ethernet header.
+ */
+ if (unlikely(skb->len < ETH_HLEN)) {
+ dev_kfree_skb(skb);
+ return NETDEV_TX_OK;
+ }
+
+ spin_lock(&q->lock);
+ reclaim_completed_tx(adap, q);
+
+ credits = q->size - q->in_use;
+ ndesc = calc_tx_descs(skb);
+
+ if (unlikely(credits < ndesc)) {
+ if (!netif_queue_stopped(dev)) {
+ netif_stop_queue(dev);
+ set_bit(TXQ_ETH, &qs->txq_stopped);
+ q->stops++;
+ dev_err(&adap->pdev->dev,
+ "%s: Tx ring %u full while queue awake!\n",
+ dev->name, q->cntxt_id & 7);
+ }
+ spin_unlock(&q->lock);
+ return NETDEV_TX_BUSY;
+ }
+
+ q->in_use += ndesc;
+ if (unlikely(credits - ndesc < q->stop_thres)) {
+ q->stops++;
+ netif_stop_queue(dev);
+ set_bit(TXQ_ETH, &qs->txq_stopped);
+#if !USE_GTS
+ if (should_restart_tx(q) &&
+ test_and_clear_bit(TXQ_ETH, &qs->txq_stopped)) {
+ q->restarts++;
+ netif_wake_queue(dev);
+ }
+#endif
+ }
+
+ gen = q->gen;
+ q->unacked += ndesc;
+ compl = (q->unacked & 8) << (S_WR_COMPL - 3);
+ q->unacked &= 7;
+ pidx = q->pidx;
+ q->pidx += ndesc;
+ if (q->pidx >= q->size) {
+ q->pidx -= q->size;
+ q->gen ^= 1;
+ }
+
+ /* update port statistics */
+ if (skb->ip_summed == CHECKSUM_COMPLETE)
+ qs->port_stats[SGE_PSTAT_TX_CSUM]++;
+ if (skb_shinfo(skb)->gso_size)
+ qs->port_stats[SGE_PSTAT_TSO]++;
+ if (vlan_tx_tag_present(skb) && pi->vlan_grp)
+ qs->port_stats[SGE_PSTAT_VLANINS]++;
+
+ dev->trans_start = jiffies;
+ spin_unlock(&q->lock);
+
+ /*
+ * We do not use Tx completion interrupts to free DMAd Tx packets.
+ * This is good for performamce but means that we rely on new Tx
+ * packets arriving to run the destructors of completed packets,
+ * which open up space in their sockets' send queues. Sometimes
+ * we do not get such new packets causing Tx to stall. A single
+ * UDP transmitter is a good example of this situation. We have
+ * a clean up timer that periodically reclaims completed packets
+ * but it doesn't run often enough (nor do we want it to) to prevent
+ * lengthy stalls. A solution to this problem is to run the
+ * destructor early, after the packet is queued but before it's DMAd.
+ * A cons is that we lie to socket memory accounting, but the amount
+ * of extra memory is reasonable (limited by the number of Tx
+ * descriptors), the packets do actually get freed quickly by new
+ * packets almost always, and for protocols like TCP that wait for
+ * acks to really free up the data the extra memory is even less.
+ * On the positive side we run the destructors on the sending CPU
+ * rather than on a potentially different completing CPU, usually a
+ * good thing. We also run them without holding our Tx queue lock,
+ * unlike what reclaim_completed_tx() would otherwise do.
+ *
+ * Run the destructor before telling the DMA engine about the packet
+ * to make sure it doesn't complete and get freed prematurely.
+ */
+ if (likely(!skb_shared(skb)))
+ skb_orphan(skb);
+
+ write_tx_pkt_wr(adap, skb, pi, pidx, gen, q, ndesc, compl);
+ check_ring_tx_db(adap, q);
+ return NETDEV_TX_OK;
+}
+
+/**
+ * write_imm - write a packet into a Tx descriptor as immediate data
+ * @d: the Tx descriptor to write
+ * @skb: the packet
+ * @len: the length of packet data to write as immediate data
+ * @gen: the generation bit value to write
+ *
+ * Writes a packet as immediate data into a Tx descriptor. The packet
+ * contains a work request at its beginning. We must write the packet
+ * carefully so the SGE doesn't read accidentally before it's written in
+ * its entirety.
+ */
+static inline void write_imm(struct tx_desc *d, struct sk_buff *skb,
+ unsigned int len, unsigned int gen)
+{
+ struct work_request_hdr *from = (struct work_request_hdr *)skb->data;
+ struct work_request_hdr *to = (struct work_request_hdr *)d;
+
+ memcpy(&to[1], &from[1], len - sizeof(*from));
+ to->wr_hi = from->wr_hi | htonl(F_WR_SOP | F_WR_EOP |
+ V_WR_BCNTLFLT(len & 7));
+ wmb();
+ to->wr_lo = from->wr_lo | htonl(V_WR_GEN(gen) |
+ V_WR_LEN((len + 7) / 8));
+ wr_gen2(d, gen);
+ kfree_skb(skb);
+}
+
+/**
+ * check_desc_avail - check descriptor availability on a send queue
+ * @adap: the adapter
+ * @q: the send queue
+ * @skb: the packet needing the descriptors
+ * @ndesc: the number of Tx descriptors needed
+ * @qid: the Tx queue number in its queue set (TXQ_OFLD or TXQ_CTRL)
+ *
+ * Checks if the requested number of Tx descriptors is available on an
+ * SGE send queue. If the queue is already suspended or not enough
+ * descriptors are available the packet is queued for later transmission.
+ * Must be called with the Tx queue locked.
+ *
+ * Returns 0 if enough descriptors are available, 1 if there aren't
+ * enough descriptors and the packet has been queued, and 2 if the caller
+ * needs to retry because there weren't enough descriptors at the
+ * beginning of the call but some freed up in the mean time.
+ */
+static inline int check_desc_avail(struct adapter *adap, struct sge_txq *q,
+ struct sk_buff *skb, unsigned int ndesc,
+ unsigned int qid)
+{
+ if (unlikely(!skb_queue_empty(&q->sendq))) {
+ addq_exit:__skb_queue_tail(&q->sendq, skb);
+ return 1;
+ }
+ if (unlikely(q->size - q->in_use < ndesc)) {
+ struct sge_qset *qs = txq_to_qset(q, qid);
+
+ set_bit(qid, &qs->txq_stopped);
+ smp_mb__after_clear_bit();
+
+ if (should_restart_tx(q) &&
+ test_and_clear_bit(qid, &qs->txq_stopped))
+ return 2;
+
+ q->stops++;
+ goto addq_exit;
+ }
+ return 0;
+}
+
+/**
+ * reclaim_completed_tx_imm - reclaim completed control-queue Tx descs
+ * @q: the SGE control Tx queue
+ *
+ * This is a variant of reclaim_completed_tx() that is used for Tx queues
+ * that send only immediate data (presently just the control queues) and
+ * thus do not have any sk_buffs to release.
+ */
+static inline void reclaim_completed_tx_imm(struct sge_txq *q)
+{
+ unsigned int reclaim = q->processed - q->cleaned;
+
+ q->in_use -= reclaim;
+ q->cleaned += reclaim;
+}
+
+static inline int immediate(const struct sk_buff *skb)
+{
+ return skb->len <= WR_LEN && !skb->data_len;
+}
+
+/**
+ * ctrl_xmit - send a packet through an SGE control Tx queue
+ * @adap: the adapter
+ * @q: the control queue
+ * @skb: the packet
+ *
+ * Send a packet through an SGE control Tx queue. Packets sent through
+ * a control queue must fit entirely as immediate data in a single Tx
+ * descriptor and have no page fragments.
+ */
+static int ctrl_xmit(struct adapter *adap, struct sge_txq *q,
+ struct sk_buff *skb)
+{
+ int ret;
+ struct work_request_hdr *wrp = (struct work_request_hdr *)skb->data;
+
+ if (unlikely(!immediate(skb))) {
+ WARN_ON(1);
+ dev_kfree_skb(skb);
+ return NET_XMIT_SUCCESS;
+ }
+
+ wrp->wr_hi |= htonl(F_WR_SOP | F_WR_EOP);
+ wrp->wr_lo = htonl(V_WR_TID(q->token));
+
+ spin_lock(&q->lock);
+ again:reclaim_completed_tx_imm(q);
+
+ ret = check_desc_avail(adap, q, skb, 1, TXQ_CTRL);
+ if (unlikely(ret)) {
+ if (ret == 1) {
+ spin_unlock(&q->lock);
+ return NET_XMIT_CN;
+ }
+ goto again;
+ }
+
+ write_imm(&q->desc[q->pidx], skb, skb->len, q->gen);
+
+ q->in_use++;
+ if (++q->pidx >= q->size) {
+ q->pidx = 0;
+ q->gen ^= 1;
+ }
+ spin_unlock(&q->lock);
+ wmb();
+ t3_write_reg(adap, A_SG_KDOORBELL,
+ F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id));
+ return NET_XMIT_SUCCESS;
+}
+
+/**
+ * restart_ctrlq - restart a suspended control queue
+ * @qs: the queue set cotaining the control queue
+ *
+ * Resumes transmission on a suspended Tx control queue.
+ */
+static void restart_ctrlq(unsigned long data)
+{
+ struct sk_buff *skb;
+ struct sge_qset *qs = (struct sge_qset *)data;
+ struct sge_txq *q = &qs->txq[TXQ_CTRL];
+ struct adapter *adap = qs->netdev->priv;
+
+ spin_lock(&q->lock);
+ again:reclaim_completed_tx_imm(q);
+
+ while (q->in_use < q->size && (skb = __skb_dequeue(&q->sendq)) != NULL) {
+
+ write_imm(&q->desc[q->pidx], skb, skb->len, q->gen);
+
+ if (++q->pidx >= q->size) {
+ q->pidx = 0;
+ q->gen ^= 1;
+ }
+ q->in_use++;
+ }
+
+ if (!skb_queue_empty(&q->sendq)) {
+ set_bit(TXQ_CTRL, &qs->txq_stopped);
+ smp_mb__after_clear_bit();
+
+ if (should_restart_tx(q) &&
+ test_and_clear_bit(TXQ_CTRL, &qs->txq_stopped))
+ goto again;
+ q->stops++;
+ }
+
+ spin_unlock(&q->lock);
+ t3_write_reg(adap, A_SG_KDOORBELL,
+ F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id));
+}
+
+/*
+ * Send a management message through control queue 0
+ */
+int t3_mgmt_tx(struct adapter *adap, struct sk_buff *skb)
+{
+ return ctrl_xmit(adap, &adap->sge.qs[0].txq[TXQ_CTRL], skb);
+}
+
+/**
+ * write_ofld_wr - write an offload work request
+ * @adap: the adapter
+ * @skb: the packet to send
+ * @q: the Tx queue
+ * @pidx: index of the first Tx descriptor to write
+ * @gen: the generation value to use
+ * @ndesc: number of descriptors the packet will occupy
+ *
+ * Write an offload work request to send the supplied packet. The packet
+ * data already carry the work request with most fields populated.
+ */
+static void write_ofld_wr(struct adapter *adap, struct sk_buff *skb,
+ struct sge_txq *q, unsigned int pidx,
+ unsigned int gen, unsigned int ndesc)
+{
+ unsigned int sgl_flits, flits;
+ struct work_request_hdr *from;
+ struct sg_ent *sgp, sgl[MAX_SKB_FRAGS / 2 + 1];
+ struct tx_desc *d = &q->desc[pidx];
+
+ if (immediate(skb)) {
+ q->sdesc[pidx].skb = NULL;
+ write_imm(d, skb, skb->len, gen);
+ return;
+ }
+
+ /* Only TX_DATA builds SGLs */
+
+ from = (struct work_request_hdr *)skb->data;
+ memcpy(&d->flit[1], &from[1], skb->h.raw - skb->data - sizeof(*from));
+
+ flits = (skb->h.raw - skb->data) / 8;
+ sgp = ndesc == 1 ? (struct sg_ent *)&d->flit[flits] : sgl;
+ sgl_flits = make_sgl(skb, sgp, skb->h.raw, skb->tail - skb->h.raw,
+ adap->pdev);
+ if (need_skb_unmap())
+ ((struct unmap_info *)skb->cb)->len = skb->tail - skb->h.raw;
+
+ write_wr_hdr_sgl(ndesc, skb, d, pidx, q, sgl, flits, sgl_flits,
+ gen, from->wr_hi, from->wr_lo);
+}
+
+/**
+ * calc_tx_descs_ofld - calculate # of Tx descriptors for an offload packet
+ * @skb: the packet
+ *
+ * Returns the number of Tx descriptors needed for the given offload
+ * packet. These packets are already fully constructed.
+ */
+static inline unsigned int calc_tx_descs_ofld(const struct sk_buff *skb)
+{
+ unsigned int flits, cnt = skb_shinfo(skb)->nr_frags;
+
+ if (skb->len <= WR_LEN && cnt == 0)
+ return 1; /* packet fits as immediate data */
+
+ flits = (skb->h.raw - skb->data) / 8; /* headers */
+ if (skb->tail != skb->h.raw)
+ cnt++;
+ return flits_to_desc(flits + sgl_len(cnt));
+}
+
+/**
+ * ofld_xmit - send a packet through an offload queue
+ * @adap: the adapter
+ * @q: the Tx offload queue
+ * @skb: the packet
+ *
+ * Send an offload packet through an SGE offload queue.
+ */
+static int ofld_xmit(struct adapter *adap, struct sge_txq *q,
+ struct sk_buff *skb)
+{
+ int ret;
+ unsigned int ndesc = calc_tx_descs_ofld(skb), pidx, gen;
+
+ spin_lock(&q->lock);
+ again:reclaim_completed_tx(adap, q);
+
+ ret = check_desc_avail(adap, q, skb, ndesc, TXQ_OFLD);
+ if (unlikely(ret)) {
+ if (ret == 1) {
+ skb->priority = ndesc; /* save for restart */
+ spin_unlock(&q->lock);
+ return NET_XMIT_CN;
+ }
+ goto again;
+ }
+
+ gen = q->gen;
+ q->in_use += ndesc;
+ pidx = q->pidx;
+ q->pidx += ndesc;
+ if (q->pidx >= q->size) {
+ q->pidx -= q->size;
+ q->gen ^= 1;
+ }
+ spin_unlock(&q->lock);
+
+ write_ofld_wr(adap, skb, q, pidx, gen, ndesc);
+ check_ring_tx_db(adap, q);
+ return NET_XMIT_SUCCESS;
+}
+
+/**
+ * restart_offloadq - restart a suspended offload queue
+ * @qs: the queue set cotaining the offload queue
+ *
+ * Resumes transmission on a suspended Tx offload queue.
+ */
+static void restart_offloadq(unsigned long data)
+{
+ struct sk_buff *skb;
+ struct sge_qset *qs = (struct sge_qset *)data;
+ struct sge_txq *q = &qs->txq[TXQ_OFLD];
+ struct adapter *adap = qs->netdev->priv;
+
+ spin_lock(&q->lock);
+ again:reclaim_completed_tx(adap, q);
+
+ while ((skb = skb_peek(&q->sendq)) != NULL) {
+ unsigned int gen, pidx;
+ unsigned int ndesc = skb->priority;
+
+ if (unlikely(q->size - q->in_use < ndesc)) {
+ set_bit(TXQ_OFLD, &qs->txq_stopped);
+ smp_mb__after_clear_bit();
+
+ if (should_restart_tx(q) &&
+ test_and_clear_bit(TXQ_OFLD, &qs->txq_stopped))
+ goto again;
+ q->stops++;
+ break;
+ }
+
+ gen = q->gen;
+ q->in_use += ndesc;
+ pidx = q->pidx;
+ q->pidx += ndesc;
+ if (q->pidx >= q->size) {
+ q->pidx -= q->size;
+ q->gen ^= 1;
+ }
+ __skb_unlink(skb, &q->sendq);
+ spin_unlock(&q->lock);
+
+ write_ofld_wr(adap, skb, q, pidx, gen, ndesc);
+ spin_lock(&q->lock);
+ }
+ spin_unlock(&q->lock);
+
+#if USE_GTS
+ set_bit(TXQ_RUNNING, &q->flags);
+ set_bit(TXQ_LAST_PKT_DB, &q->flags);
+#endif
+ t3_write_reg(adap, A_SG_KDOORBELL,
+ F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id));
+}
+
+/**
+ * queue_set - return the queue set a packet should use
+ * @skb: the packet
+ *
+ * Maps a packet to the SGE queue set it should use. The desired queue
+ * set is carried in bits 1-3 in the packet's priority.
+ */
+static inline int queue_set(const struct sk_buff *skb)
+{
+ return skb->priority >> 1;
+}
+
+/**
+ * is_ctrl_pkt - return whether an offload packet is a control packet
+ * @skb: the packet
+ *
+ * Determines whether an offload packet should use an OFLD or a CTRL
+ * Tx queue. This is indicated by bit 0 in the packet's priority.
+ */
+static inline int is_ctrl_pkt(const struct sk_buff *skb)
+{
+ return skb->priority & 1;
+}
+
+/**
+ * t3_offload_tx - send an offload packet
+ * @tdev: the offload device to send to
+ * @skb: the packet
+ *
+ * Sends an offload packet. We use the packet priority to select the
+ * appropriate Tx queue as follows: bit 0 indicates whether the packet
+ * should be sent as regular or control, bits 1-3 select the queue set.
+ */
+int t3_offload_tx(struct t3cdev *tdev, struct sk_buff *skb)
+{
+ struct adapter *adap = tdev2adap(tdev);
+ struct sge_qset *qs = &adap->sge.qs[queue_set(skb)];
+
+ if (unlikely(is_ctrl_pkt(skb)))
+ return ctrl_xmit(adap, &qs->txq[TXQ_CTRL], skb);
+
+ return ofld_xmit(adap, &qs->txq[TXQ_OFLD], skb);
+}
+
+/**
+ * offload_enqueue - add an offload packet to an SGE offload receive queue
+ * @q: the SGE response queue
+ * @skb: the packet
+ *
+ * Add a new offload packet to an SGE response queue's offload packet
+ * queue. If the packet is the first on the queue it schedules the RX
+ * softirq to process the queue.
+ */
+static inline void offload_enqueue(struct sge_rspq *q, struct sk_buff *skb)
+{
+ skb->next = skb->prev = NULL;
+ if (q->rx_tail)
+ q->rx_tail->next = skb;
+ else {
+ struct sge_qset *qs = rspq_to_qset(q);
+
+ if (__netif_rx_schedule_prep(qs->netdev))
+ __netif_rx_schedule(qs->netdev);
+ q->rx_head = skb;
+ }
+ q->rx_tail = skb;
+}
+
+/**
+ * deliver_partial_bundle - deliver a (partial) bundle of Rx offload pkts
+ * @tdev: the offload device that will be receiving the packets
+ * @q: the SGE response queue that assembled the bundle
+ * @skbs: the partial bundle
+ * @n: the number of packets in the bundle
+ *
+ * Delivers a (partial) bundle of Rx offload packets to an offload device.
+ */
+static inline void deliver_partial_bundle(struct t3cdev *tdev,
+ struct sge_rspq *q,
+ struct sk_buff *skbs[], int n)
+{
+ if (n) {
+ q->offload_bundles++;
+ tdev->recv(tdev, skbs, n);
+ }
+}
+
+/**
+ * ofld_poll - NAPI handler for offload packets in interrupt mode
+ * @dev: the network device doing the polling
+ * @budget: polling budget
+ *
+ * The NAPI handler for offload packets when a response queue is serviced
+ * by the hard interrupt handler, i.e., when it's operating in non-polling
+ * mode. Creates small packet batches and sends them through the offload
+ * receive handler. Batches need to be of modest size as we do prefetches
+ * on the packets in each.
+ */
+static int ofld_poll(struct net_device *dev, int *budget)
+{
+ struct adapter *adapter = dev->priv;
+ struct sge_qset *qs = dev2qset(dev);
+ struct sge_rspq *q = &qs->rspq;
+ int work_done, limit = min(*budget, dev->quota), avail = limit;
+
+ while (avail) {
+ struct sk_buff *head, *tail, *skbs[RX_BUNDLE_SIZE];
+ int ngathered;
+
+ spin_lock_irq(&q->lock);
+ head = q->rx_head;
+ if (!head) {
+ work_done = limit - avail;
+ *budget -= work_done;
+ dev->quota -= work_done;
+ __netif_rx_complete(dev);
+ spin_unlock_irq(&q->lock);
+ return 0;
+ }
+
+ tail = q->rx_tail;
+ q->rx_head = q->rx_tail = NULL;
+ spin_unlock_irq(&q->lock);
+
+ for (ngathered = 0; avail && head; avail--) {
+ prefetch(head->data);
+ skbs[ngathered] = head;
+ head = head->next;
+ skbs[ngathered]->next = NULL;
+ if (++ngathered == RX_BUNDLE_SIZE) {
+ q->offload_bundles++;
+ adapter->tdev.recv(&adapter->tdev, skbs,
+ ngathered);
+ ngathered = 0;
+ }
+ }
+ if (head) { /* splice remaining packets back onto Rx queue */
+ spin_lock_irq(&q->lock);
+ tail->next = q->rx_head;
+ if (!q->rx_head)
+ q->rx_tail = tail;
+ q->rx_head = head;
+ spin_unlock_irq(&q->lock);
+ }
+ deliver_partial_bundle(&adapter->tdev, q, skbs, ngathered);
+ }
+ work_done = limit - avail;
+ *budget -= work_done;
+ dev->quota -= work_done;
+ return 1;
+}
+
+/**
+ * rx_offload - process a received offload packet
+ * @tdev: the offload device receiving the packet
+ * @rq: the response queue that received the packet
+ * @skb: the packet
+ * @rx_gather: a gather list of packets if we are building a bundle
+ * @gather_idx: index of the next available slot in the bundle
+ *
+ * Process an ingress offload pakcet and add it to the offload ingress
+ * queue. Returns the index of the next available slot in the bundle.
+ */
+static inline int rx_offload(struct t3cdev *tdev, struct sge_rspq *rq,
+ struct sk_buff *skb, struct sk_buff *rx_gather[],
+ unsigned int gather_idx)
+{
+ rq->offload_pkts++;
+ skb->mac.raw = skb->nh.raw = skb->h.raw = skb->data;
+
+ if (rq->polling) {
+ rx_gather[gather_idx++] = skb;
+ if (gather_idx == RX_BUNDLE_SIZE) {
+ tdev->recv(tdev, rx_gather, RX_BUNDLE_SIZE);
+ gather_idx = 0;
+ rq->offload_bundles++;
+ }
+ } else
+ offload_enqueue(rq, skb);
+
+ return gather_idx;
+}
+
+/**
+ * restart_tx - check whether to restart suspended Tx queues
+ * @qs: the queue set to resume
+ *
+ * Restarts suspended Tx queues of an SGE queue set if they have enough
+ * free resources to resume operation.
+ */
+static void restart_tx(struct sge_qset *qs)
+{
+ if (test_bit(TXQ_ETH, &qs->txq_stopped) &&
+ should_restart_tx(&qs->txq[TXQ_ETH]) &&
+ test_and_clear_bit(TXQ_ETH, &qs->txq_stopped)) {
+ qs->txq[TXQ_ETH].restarts++;
+ if (netif_running(qs->netdev))
+ netif_wake_queue(qs->netdev);
+ }
+
+ if (test_bit(TXQ_OFLD, &qs->txq_stopped) &&
+ should_restart_tx(&qs->txq[TXQ_OFLD]) &&
+ test_and_clear_bit(TXQ_OFLD, &qs->txq_stopped)) {
+ qs->txq[TXQ_OFLD].restarts++;
+ tasklet_schedule(&qs->txq[TXQ_OFLD].qresume_tsk);
+ }
+ if (test_bit(TXQ_CTRL, &qs->txq_stopped) &&
+ should_restart_tx(&qs->txq[TXQ_CTRL]) &&
+ test_and_clear_bit(TXQ_CTRL, &qs->txq_stopped)) {
+ qs->txq[TXQ_CTRL].restarts++;
+ tasklet_schedule(&qs->txq[TXQ_CTRL].qresume_tsk);
+ }
+}
+
+/**
+ * rx_eth - process an ingress ethernet packet
+ * @adap: the adapter
+ * @rq: the response queue that received the packet
+ * @skb: the packet
+ * @pad: amount of padding at the start of the buffer
+ *
+ * Process an ingress ethernet pakcet and deliver it to the stack.
+ * The padding is 2 if the packet was delivered in an Rx buffer and 0
+ * if it was immediate data in a response.
+ */
+static void rx_eth(struct adapter *adap, struct sge_rspq *rq,
+ struct sk_buff *skb, int pad)
+{
+ struct cpl_rx_pkt *p = (struct cpl_rx_pkt *)(skb->data + pad);
+ struct port_info *pi;
+
+ rq->eth_pkts++;
+ skb_pull(skb, sizeof(*p) + pad);
+ skb->dev = adap->port[p->iff];
+ skb->dev->last_rx = jiffies;
+ skb->protocol = eth_type_trans(skb, skb->dev);
+ pi = netdev_priv(skb->dev);
+ if (pi->rx_csum_offload && p->csum_valid && p->csum == 0xffff &&
+ !p->fragment) {
+ rspq_to_qset(rq)->port_stats[SGE_PSTAT_RX_CSUM_GOOD]++;
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ } else
+ skb->ip_summed = CHECKSUM_NONE;
+
+ if (unlikely(p->vlan_valid)) {
+ struct vlan_group *grp = pi->vlan_grp;
+
+ rspq_to_qset(rq)->port_stats[SGE_PSTAT_VLANEX]++;
+ if (likely(grp))
+ __vlan_hwaccel_rx(skb, grp, ntohs(p->vlan),
+ rq->polling);
+ else
+ dev_kfree_skb_any(skb);
+ } else if (rq->polling)
+ netif_receive_skb(skb);
+ else
+ netif_rx(skb);
+}
+
+/**
+ * handle_rsp_cntrl_info - handles control information in a response
+ * @qs: the queue set corresponding to the response
+ * @flags: the response control flags
+ *
+ * Handles the control information of an SGE response, such as GTS
+ * indications and completion credits for the queue set's Tx queues.
+ * HW coalesces credits, we don't do any extra SW coalescing.
+ */
+static inline void handle_rsp_cntrl_info(struct sge_qset *qs, u32 flags)
+{
+ unsigned int credits;
+
+#if USE_GTS
+ if (flags & F_RSPD_TXQ0_GTS)
+ clear_bit(TXQ_RUNNING, &qs->txq[TXQ_ETH].flags);
+#endif
+
+ credits = G_RSPD_TXQ0_CR(flags);
+ if (credits)
+ qs->txq[TXQ_ETH].processed += credits;
+
+ credits = G_RSPD_TXQ2_CR(flags);
+ if (credits)
+ qs->txq[TXQ_CTRL].processed += credits;
+
+# if USE_GTS
+ if (flags & F_RSPD_TXQ1_GTS)
+ clear_bit(TXQ_RUNNING, &qs->txq[TXQ_OFLD].flags);
+# endif
+ credits = G_RSPD_TXQ1_CR(flags);
+ if (credits)
+ qs->txq[TXQ_OFLD].processed += credits;
+}
+
+/**
+ * check_ring_db - check if we need to ring any doorbells
+ * @adapter: the adapter
+ * @qs: the queue set whose Tx queues are to be examined
+ * @sleeping: indicates which Tx queue sent GTS
+ *
+ * Checks if some of a queue set's Tx queues need to ring their doorbells
+ * to resume transmission after idling while they still have unprocessed
+ * descriptors.
+ */
+static void check_ring_db(struct adapter *adap, struct sge_qset *qs,
+ unsigned int sleeping)
+{
+ if (sleeping & F_RSPD_TXQ0_GTS) {
+ struct sge_txq *txq = &qs->txq[TXQ_ETH];
+
+ if (txq->cleaned + txq->in_use != txq->processed &&
+ !test_and_set_bit(TXQ_LAST_PKT_DB, &txq->flags)) {
+ set_bit(TXQ_RUNNING, &txq->flags);
+ t3_write_reg(adap, A_SG_KDOORBELL, F_SELEGRCNTX |
+ V_EGRCNTX(txq->cntxt_id));
+ }
+ }
+
+ if (sleeping & F_RSPD_TXQ1_GTS) {
+ struct sge_txq *txq = &qs->txq[TXQ_OFLD];
+
+ if (txq->cleaned + txq->in_use != txq->processed &&
+ !test_and_set_bit(TXQ_LAST_PKT_DB, &txq->flags)) {
+ set_bit(TXQ_RUNNING, &txq->flags);
+ t3_write_reg(adap, A_SG_KDOORBELL, F_SELEGRCNTX |
+ V_EGRCNTX(txq->cntxt_id));
+ }
+ }
+}
+
+/**
+ * is_new_response - check if a response is newly written
+ * @r: the response descriptor
+ * @q: the response queue
+ *
+ * Returns true if a response descriptor contains a yet unprocessed
+ * response.
+ */
+static inline int is_new_response(const struct rsp_desc *r,
+ const struct sge_rspq *q)
+{
+ return (r->intr_gen & F_RSPD_GEN2) == q->gen;
+}
+
+#define RSPD_GTS_MASK (F_RSPD_TXQ0_GTS | F_RSPD_TXQ1_GTS)
+#define RSPD_CTRL_MASK (RSPD_GTS_MASK | \
+ V_RSPD_TXQ0_CR(M_RSPD_TXQ0_CR) | \
+ V_RSPD_TXQ1_CR(M_RSPD_TXQ1_CR) | \
+ V_RSPD_TXQ2_CR(M_RSPD_TXQ2_CR))
+
+/* How long to delay the next interrupt in case of memory shortage, in 0.1us. */
+#define NOMEM_INTR_DELAY 2500
+
+/**
+ * process_responses - process responses from an SGE response queue
+ * @adap: the adapter
+ * @qs: the queue set to which the response queue belongs
+ * @budget: how many responses can be processed in this round
+ *
+ * Process responses from an SGE response queue up to the supplied budget.
+ * Responses include received packets as well as credits and other events
+ * for the queues that belong to the response queue's queue set.
+ * A negative budget is effectively unlimited.
+ *
+ * Additionally choose the interrupt holdoff time for the next interrupt
+ * on this queue. If the system is under memory shortage use a fairly
+ * long delay to help recovery.
+ */
+static int process_responses(struct adapter *adap, struct sge_qset *qs,
+ int budget)
+{
+ struct sge_rspq *q = &qs->rspq;
+ struct rsp_desc *r = &q->desc[q->cidx];
+ int budget_left = budget;
+ unsigned int sleeping = 0;
+ struct sk_buff *offload_skbs[RX_BUNDLE_SIZE];
+ int ngathered = 0;
+
+ q->next_holdoff = q->holdoff_tmr;
+
+ while (likely(budget_left && is_new_response(r, q))) {
+ int eth, ethpad = 0;
+ struct sk_buff *skb = NULL;
+ u32 len, flags = ntohl(r->flags);
+ u32 rss_hi = *(const u32 *)r, rss_lo = r->rss_hdr.rss_hash_val;
+
+ eth = r->rss_hdr.opcode == CPL_RX_PKT;
+
+ if (unlikely(flags & F_RSPD_ASYNC_NOTIF)) {
+ skb = alloc_skb(AN_PKT_SIZE, GFP_ATOMIC);
+ if (!skb)
+ goto no_mem;
+
+ memcpy(__skb_put(skb, AN_PKT_SIZE), r, AN_PKT_SIZE);
+ skb->data[0] = CPL_ASYNC_NOTIF;
+ rss_hi = htonl(CPL_ASYNC_NOTIF << 24);
+ q->async_notif++;
+ } else if (flags & F_RSPD_IMM_DATA_VALID) {
+ skb = get_imm_packet(r);
+ if (unlikely(!skb)) {
+ no_mem:
+ q->next_holdoff = NOMEM_INTR_DELAY;
+ q->nomem++;
+ /* consume one credit since we tried */
+ budget_left--;
+ break;
+ }
+ q->imm_data++;
+ } else if ((len = ntohl(r->len_cq)) != 0) {
+ struct sge_fl *fl;
+
+ fl = (len & F_RSPD_FLQ) ? &qs->fl[1] : &qs->fl[0];
+ fl->credits--;
+ skb = get_packet(adap, fl, G_RSPD_LEN(len),
+ eth ? SGE_RX_DROP_THRES : 0);
+ if (!skb)
+ q->rx_drops++;
+ else if (r->rss_hdr.opcode == CPL_TRACE_PKT)
+ __skb_pull(skb, 2);
+ ethpad = 2;
+ if (++fl->cidx == fl->size)
+ fl->cidx = 0;
+ } else
+ q->pure_rsps++;
+
+ if (flags & RSPD_CTRL_MASK) {
+ sleeping |= flags & RSPD_GTS_MASK;
+ handle_rsp_cntrl_info(qs, flags);
+ }
+
+ r++;
+ if (unlikely(++q->cidx == q->size)) {
+ q->cidx = 0;
+ q->gen ^= 1;
+ r = q->desc;
+ }
+ prefetch(r);
+
+ if (++q->credits >= (q->size / 4)) {
+ refill_rspq(adap, q, q->credits);
+ q->credits = 0;
+ }
+
+ if (likely(skb != NULL)) {
+ if (eth)
+ rx_eth(adap, q, skb, ethpad);
+ else {
+ /* Preserve the RSS info in csum & priority */
+ skb->csum = rss_hi;
+ skb->priority = rss_lo;
+ ngathered = rx_offload(&adap->tdev, q, skb,
+ offload_skbs, ngathered);
+ }
+ }
+
+ --budget_left;
+ }
+
+ deliver_partial_bundle(&adap->tdev, q, offload_skbs, ngathered);
+ if (sleeping)
+ check_ring_db(adap, qs, sleeping);
+
+ smp_mb(); /* commit Tx queue .processed updates */
+ if (unlikely(qs->txq_stopped != 0))
+ restart_tx(qs);
+
+ budget -= budget_left;
+ return budget;
+}
+
+static inline int is_pure_response(const struct rsp_desc *r)
+{
+ u32 n = ntohl(r->flags) & (F_RSPD_ASYNC_NOTIF | F_RSPD_IMM_DATA_VALID);
+
+ return (n | r->len_cq) == 0;
+}
+
+/**
+ * napi_rx_handler - the NAPI handler for Rx processing
+ * @dev: the net device
+ * @budget: how many packets we can process in this round
+ *
+ * Handler for new data events when using NAPI.
+ */
+static int napi_rx_handler(struct net_device *dev, int *budget)
+{
+ struct adapter *adap = dev->priv;
+ struct sge_qset *qs = dev2qset(dev);
+ int effective_budget = min(*budget, dev->quota);
+
+ int work_done = process_responses(adap, qs, effective_budget);
+ *budget -= work_done;
+ dev->quota -= work_done;
+
+ if (work_done >= effective_budget)
+ return 1;
+
+ netif_rx_complete(dev);
+
+ /*
+ * Because we don't atomically flush the following write it is
+ * possible that in very rare cases it can reach the device in a way
+ * that races with a new response being written plus an error interrupt
+ * causing the NAPI interrupt handler below to return unhandled status
+ * to the OS. To protect against this would require flushing the write
+ * and doing both the write and the flush with interrupts off. Way too
+ * expensive and unjustifiable given the rarity of the race.
+ *
+ * The race cannot happen at all with MSI-X.
+ */
+ t3_write_reg(adap, A_SG_GTS, V_RSPQ(qs->rspq.cntxt_id) |
+ V_NEWTIMER(qs->rspq.next_holdoff) |
+ V_NEWINDEX(qs->rspq.cidx));
+ return 0;
+}
+
+/*
+ * Returns true if the device is already scheduled for polling.
+ */
+static inline int napi_is_scheduled(struct net_device *dev)
+{
+ return test_bit(__LINK_STATE_RX_SCHED, &dev->state);
+}
+
+/**
+ * process_pure_responses - process pure responses from a response queue
+ * @adap: the adapter
+ * @qs: the queue set owning the response queue
+ * @r: the first pure response to process
+ *
+ * A simpler version of process_responses() that handles only pure (i.e.,
+ * non data-carrying) responses. Such respones are too light-weight to
+ * justify calling a softirq under NAPI, so we handle them specially in
+ * the interrupt handler. The function is called with a pointer to a
+ * response, which the caller must ensure is a valid pure response.
+ *
+ * Returns 1 if it encounters a valid data-carrying response, 0 otherwise.
+ */
+static int process_pure_responses(struct adapter *adap, struct sge_qset *qs,
+ struct rsp_desc *r)
+{
+ struct sge_rspq *q = &qs->rspq;
+ unsigned int sleeping = 0;
+
+ do {
+ u32 flags = ntohl(r->flags);
+
+ r++;
+ if (unlikely(++q->cidx == q->size)) {
+ q->cidx = 0;
+ q->gen ^= 1;
+ r = q->desc;
+ }
+ prefetch(r);
+
+ if (flags & RSPD_CTRL_MASK) {
+ sleeping |= flags & RSPD_GTS_MASK;
+ handle_rsp_cntrl_info(qs, flags);
+ }
+
+ q->pure_rsps++;
+ if (++q->credits >= (q->size / 4)) {
+ refill_rspq(adap, q, q->credits);
+ q->credits = 0;
+ }
+ } while (is_new_response(r, q) && is_pure_response(r));
+
+ if (sleeping)
+ check_ring_db(adap, qs, sleeping);
+
+ smp_mb(); /* commit Tx queue .processed updates */
+ if (unlikely(qs->txq_stopped != 0))
+ restart_tx(qs);
+
+ return is_new_response(r, q);
+}
+
+/**
+ * handle_responses - decide what to do with new responses in NAPI mode
+ * @adap: the adapter
+ * @q: the response queue
+ *
+ * This is used by the NAPI interrupt handlers to decide what to do with
+ * new SGE responses. If there are no new responses it returns -1. If
+ * there are new responses and they are pure (i.e., non-data carrying)
+ * it handles them straight in hard interrupt context as they are very
+ * cheap and don't deliver any packets. Finally, if there are any data
+ * signaling responses it schedules the NAPI handler. Returns 1 if it
+ * schedules NAPI, 0 if all new responses were pure.
+ *
+ * The caller must ascertain NAPI is not already running.
+ */
+static inline int handle_responses(struct adapter *adap, struct sge_rspq *q)
+{
+ struct sge_qset *qs = rspq_to_qset(q);
+ struct rsp_desc *r = &q->desc[q->cidx];
+
+ if (!is_new_response(r, q))
+ return -1;
+ 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));
+ return 0;
+ }
+ if (likely(__netif_rx_schedule_prep(qs->netdev)))
+ __netif_rx_schedule(qs->netdev);
+ return 1;
+}
+
+/*
+ * The MSI-X interrupt handler for an SGE response queue for the non-NAPI case
+ * (i.e., response queue serviced in hard interrupt).
+ */
+irqreturn_t t3_sge_intr_msix(int irq, void *cookie)
+{
+ struct sge_qset *qs = cookie;
+ struct adapter *adap = qs->netdev->priv;
+ struct sge_rspq *q = &qs->rspq;
+
+ spin_lock(&q->lock);
+ if (process_responses(adap, qs, -1) == 0)
+ q->unhandled_irqs++;
+ t3_write_reg(adap, A_SG_GTS, V_RSPQ(q->cntxt_id) |
+ V_NEWTIMER(q->next_holdoff) | V_NEWINDEX(q->cidx));
+ spin_unlock(&q->lock);
+ return IRQ_HANDLED;
+}
+
+/*
+ * The MSI-X interrupt handler for an SGE response queue for the NAPI case
+ * (i.e., response queue serviced by NAPI polling).
+ */
+irqreturn_t t3_sge_intr_msix_napi(int irq, void *cookie)
+{
+ struct sge_qset *qs = cookie;
+ struct adapter *adap = qs->netdev->priv;
+ struct sge_rspq *q = &qs->rspq;
+
+ spin_lock(&q->lock);
+ BUG_ON(napi_is_scheduled(qs->netdev));
+
+ if (handle_responses(adap, q) < 0)
+ q->unhandled_irqs++;
+ spin_unlock(&q->lock);
+ return IRQ_HANDLED;
+}
+
+/*
+ * The non-NAPI MSI interrupt handler. This needs to handle data events from
+ * SGE response queues as well as error and other async events as they all use
+ * the same MSI vector. We use one SGE response queue per port in this mode
+ * and protect all response queues with queue 0's lock.
+ */
+static irqreturn_t t3_intr_msi(int irq, void *cookie)
+{
+ int new_packets = 0;
+ struct adapter *adap = cookie;
+ struct sge_rspq *q = &adap->sge.qs[0].rspq;
+
+ spin_lock(&q->lock);
+
+ if (process_responses(adap, &adap->sge.qs[0], -1)) {
+ t3_write_reg(adap, A_SG_GTS, V_RSPQ(q->cntxt_id) |
+ V_NEWTIMER(q->next_holdoff) | V_NEWINDEX(q->cidx));
+ new_packets = 1;
+ }
+
+ if (adap->params.nports == 2 &&
+ process_responses(adap, &adap->sge.qs[1], -1)) {
+ struct sge_rspq *q1 = &adap->sge.qs[1].rspq;
+
+ t3_write_reg(adap, A_SG_GTS, V_RSPQ(q1->cntxt_id) |
+ V_NEWTIMER(q1->next_holdoff) |
+ V_NEWINDEX(q1->cidx));
+ new_packets = 1;
+ }
+
+ if (!new_packets && t3_slow_intr_handler(adap) == 0)
+ q->unhandled_irqs++;
+
+ spin_unlock(&q->lock);
+ return IRQ_HANDLED;
+}
+
+static int rspq_check_napi(struct net_device *dev, struct sge_rspq *q)
+{
+ if (!napi_is_scheduled(dev) && is_new_response(&q->desc[q->cidx], q)) {
+ if (likely(__netif_rx_schedule_prep(dev)))
+ __netif_rx_schedule(dev);
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * The MSI interrupt handler for the NAPI case (i.e., response queues serviced
+ * by NAPI polling). Handles data events from SGE response queues as well as
+ * error and other async events as they all use the same MSI vector. We use
+ * one SGE response queue per port in this mode and protect all response
+ * queues with queue 0's lock.
+ */
+irqreturn_t t3_intr_msi_napi(int irq, void *cookie)
+{
+ int new_packets;
+ struct adapter *adap = cookie;
+ struct sge_rspq *q = &adap->sge.qs[0].rspq;
+
+ spin_lock(&q->lock);
+
+ new_packets = rspq_check_napi(adap->sge.qs[0].netdev, q);
+ if (adap->params.nports == 2)
+ new_packets += rspq_check_napi(adap->sge.qs[1].netdev,
+ &adap->sge.qs[1].rspq);
+ if (!new_packets && t3_slow_intr_handler(adap) == 0)
+ q->unhandled_irqs++;
+
+ spin_unlock(&q->lock);
+ return IRQ_HANDLED;
+}
+
+/*
+ * A helper function that processes responses and issues GTS.
+ */
+static inline int process_responses_gts(struct adapter *adap,
+ struct sge_rspq *rq)
+{
+ int work;
+
+ work = process_responses(adap, rspq_to_qset(rq), -1);
+ t3_write_reg(adap, A_SG_GTS, V_RSPQ(rq->cntxt_id) |
+ V_NEWTIMER(rq->next_holdoff) | V_NEWINDEX(rq->cidx));
+ return work;
+}
+
+/*
+ * The legacy INTx interrupt handler. This needs to handle data events from
+ * SGE response queues as well as error and other async events as they all use
+ * the same interrupt pin. We use one SGE response queue per port in this mode
+ * and protect all response queues with queue 0's lock.
+ */
+static irqreturn_t t3_intr(int irq, void *cookie)
+{
+ int work_done, w0, w1;
+ struct adapter *adap = cookie;
+ struct sge_rspq *q0 = &adap->sge.qs[0].rspq;
+ struct sge_rspq *q1 = &adap->sge.qs[1].rspq;
+
+ spin_lock(&q0->lock);
+
+ w0 = is_new_response(&q0->desc[q0->cidx], q0);
+ w1 = adap->params.nports == 2 &&
+ is_new_response(&q1->desc[q1->cidx], q1);
+
+ if (likely(w0 | w1)) {
+ t3_write_reg(adap, A_PL_CLI, 0);
+ t3_read_reg(adap, A_PL_CLI); /* flush */
+
+ if (likely(w0))
+ process_responses_gts(adap, q0);
+
+ if (w1)
+ process_responses_gts(adap, q1);
+
+ work_done = w0 | w1;
+ } else
+ work_done = t3_slow_intr_handler(adap);
+
+ spin_unlock(&q0->lock);
+ return IRQ_RETVAL(work_done != 0);
+}
+
+/*
+ * Interrupt handler for legacy INTx interrupts for T3B-based cards.
+ * Handles data events from SGE response queues as well as error and other
+ * async events as they all use the same interrupt pin. We use one SGE
+ * response queue per port in this mode and protect all response queues with
+ * queue 0's lock.
+ */
+static irqreturn_t t3b_intr(int irq, void *cookie)
+{
+ u32 map;
+ struct adapter *adap = cookie;
+ struct sge_rspq *q0 = &adap->sge.qs[0].rspq;
+
+ t3_write_reg(adap, A_PL_CLI, 0);
+ map = t3_read_reg(adap, A_SG_DATA_INTR);
+
+ if (unlikely(!map)) /* shared interrupt, most likely */
+ return IRQ_NONE;
+
+ spin_lock(&q0->lock);
+
+ if (unlikely(map & F_ERRINTR))
+ t3_slow_intr_handler(adap);
+
+ if (likely(map & 1))
+ process_responses_gts(adap, q0);
+
+ if (map & 2)
+ process_responses_gts(adap, &adap->sge.qs[1].rspq);
+
+ spin_unlock(&q0->lock);
+ return IRQ_HANDLED;
+}
+
+/*
+ * NAPI interrupt handler for legacy INTx interrupts for T3B-based cards.
+ * Handles data events from SGE response queues as well as error and other
+ * async events as they all use the same interrupt pin. We use one SGE
+ * response queue per port in this mode and protect all response queues with
+ * queue 0's lock.
+ */
+static irqreturn_t t3b_intr_napi(int irq, void *cookie)
+{
+ u32 map;
+ struct net_device *dev;
+ struct adapter *adap = cookie;
+ struct sge_rspq *q0 = &adap->sge.qs[0].rspq;
+
+ t3_write_reg(adap, A_PL_CLI, 0);
+ map = t3_read_reg(adap, A_SG_DATA_INTR);
+
+ if (unlikely(!map)) /* shared interrupt, most likely */
+ return IRQ_NONE;
+
+ spin_lock(&q0->lock);
+
+ if (unlikely(map & F_ERRINTR))
+ t3_slow_intr_handler(adap);
+
+ if (likely(map & 1)) {
+ dev = adap->sge.qs[0].netdev;
+
+ if (likely(__netif_rx_schedule_prep(dev)))
+ __netif_rx_schedule(dev);
+ }
+ if (map & 2) {
+ dev = adap->sge.qs[1].netdev;
+
+ if (likely(__netif_rx_schedule_prep(dev)))
+ __netif_rx_schedule(dev);
+ }
+
+ spin_unlock(&q0->lock);
+ return IRQ_HANDLED;
+}
+
+/**
+ * t3_intr_handler - select the top-level interrupt handler
+ * @adap: the adapter
+ * @polling: whether using NAPI to service response queues
+ *
+ * Selects the top-level interrupt handler based on the type of interrupts
+ * (MSI-X, MSI, or legacy) and whether NAPI will be used to service the
+ * response queues.
+ */
+intr_handler_t t3_intr_handler(struct adapter *adap, int polling)
+{
+ if (adap->flags & USING_MSIX)
+ return polling ? t3_sge_intr_msix_napi : t3_sge_intr_msix;
+ if (adap->flags & USING_MSI)
+ return polling ? t3_intr_msi_napi : t3_intr_msi;
+ if (adap->params.rev > 0)
+ return polling ? t3b_intr_napi : t3b_intr;
+ return t3_intr;
+}
+
+/**
+ * t3_sge_err_intr_handler - SGE async event interrupt handler
+ * @adapter: the adapter
+ *
+ * Interrupt handler for SGE asynchronous (non-data) events.
+ */
+void t3_sge_err_intr_handler(struct adapter *adapter)
+{
+ unsigned int v, status = t3_read_reg(adapter, A_SG_INT_CAUSE);
+
+ if (status & F_RSPQCREDITOVERFOW)
+ CH_ALERT(adapter, "SGE response queue credit overflow\n");
+
+ if (status & F_RSPQDISABLED) {
+ v = t3_read_reg(adapter, A_SG_RSPQ_FL_STATUS);
+
+ CH_ALERT(adapter,
+ "packet delivered to disabled response queue "
+ "(0x%x)\n", (v >> S_RSPQ0DISABLED) & 0xff);
+ }
+
+ t3_write_reg(adapter, A_SG_INT_CAUSE, status);
+ if (status & (F_RSPQCREDITOVERFOW | F_RSPQDISABLED))
+ t3_fatal_err(adapter);
+}
+
+/**
+ * sge_timer_cb - perform periodic maintenance of an SGE qset
+ * @data: the SGE queue set to maintain
+ *
+ * Runs periodically from a timer to perform maintenance of an SGE queue
+ * set. It performs two tasks:
+ *
+ * a) Cleans up any completed Tx descriptors that may still be pending.
+ * Normal descriptor cleanup happens when new packets are added to a Tx
+ * queue so this timer is relatively infrequent and does any cleanup only
+ * if the Tx queue has not seen any new packets in a while. We make a
+ * best effort attempt to reclaim descriptors, in that we don't wait
+ * around if we cannot get a queue's lock (which most likely is because
+ * someone else is queueing new packets and so will also handle the clean
+ * up). Since control queues use immediate data exclusively we don't
+ * bother cleaning them up here.
+ *
+ * b) Replenishes Rx queues that have run out due to memory shortage.
+ * Normally new Rx buffers are added when existing ones are consumed but
+ * when out of memory a queue can become empty. We try to add only a few
+ * buffers here, the queue will be replenished fully as these new buffers
+ * are used up if memory shortage has subsided.
+ */
+static void sge_timer_cb(unsigned long data)
+{
+ spinlock_t *lock;
+ struct sge_qset *qs = (struct sge_qset *)data;
+ struct adapter *adap = qs->netdev->priv;
+
+ if (spin_trylock(&qs->txq[TXQ_ETH].lock)) {
+ reclaim_completed_tx(adap, &qs->txq[TXQ_ETH]);
+ spin_unlock(&qs->txq[TXQ_ETH].lock);
+ }
+ if (spin_trylock(&qs->txq[TXQ_OFLD].lock)) {
+ reclaim_completed_tx(adap, &qs->txq[TXQ_OFLD]);
+ spin_unlock(&qs->txq[TXQ_OFLD].lock);
+ }
+ lock = (adap->flags & USING_MSIX) ? &qs->rspq.lock :
+ &adap->sge.qs[0].rspq.lock;
+ if (spin_trylock_irq(lock)) {
+ if (!napi_is_scheduled(qs->netdev)) {
+ if (qs->fl[0].credits < qs->fl[0].size)
+ __refill_fl(adap, &qs->fl[0]);
+ if (qs->fl[1].credits < qs->fl[1].size)
+ __refill_fl(adap, &qs->fl[1]);
+ }
+ spin_unlock_irq(lock);
+ }
+ mod_timer(&qs->tx_reclaim_timer, jiffies + TX_RECLAIM_PERIOD);
+}
+
+/**
+ * t3_update_qset_coalesce - update coalescing settings for a queue set
+ * @qs: the SGE queue set
+ * @p: new queue set parameters
+ *
+ * Update the coalescing settings for an SGE queue set. Nothing is done
+ * if the queue set is not initialized yet.
+ */
+void t3_update_qset_coalesce(struct sge_qset *qs, const struct qset_params *p)
+{
+ if (!qs->netdev)
+ return;
+
+ qs->rspq.holdoff_tmr = max(p->coalesce_usecs * 10, 1U);/* can't be 0 */
+ qs->rspq.polling = p->polling;
+ qs->netdev->poll = p->polling ? napi_rx_handler : ofld_poll;
+}
+
+/**
+ * t3_sge_alloc_qset - initialize an SGE queue set
+ * @adapter: the adapter
+ * @id: the queue set id
+ * @nports: how many Ethernet ports will be using this queue set
+ * @irq_vec_idx: the IRQ vector index for response queue interrupts
+ * @p: configuration parameters for this queue set
+ * @ntxq: number of Tx queues for the queue set
+ * @netdev: net device associated with this queue set
+ *
+ * Allocate resources and initialize an SGE queue set. A queue set
+ * comprises a response queue, two Rx free-buffer queues, and up to 3
+ * Tx queues. The Tx queues are assigned roles in the order Ethernet
+ * queue, offload queue, and control queue.
+ */
+int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports,
+ int irq_vec_idx, const struct qset_params *p,
+ int ntxq, struct net_device *netdev)
+{
+ int i, ret = -ENOMEM;
+ struct sge_qset *q = &adapter->sge.qs[id];
+
+ init_qset_cntxt(q, id);
+ init_timer(&q->tx_reclaim_timer);
+ q->tx_reclaim_timer.data = (unsigned long)q;
+ q->tx_reclaim_timer.function = sge_timer_cb;
+
+ q->fl[0].desc = alloc_ring(adapter->pdev, p->fl_size,
+ sizeof(struct rx_desc),
+ sizeof(struct rx_sw_desc),
+ &q->fl[0].phys_addr, &q->fl[0].sdesc);
+ if (!q->fl[0].desc)
+ goto err;
+
+ q->fl[1].desc = alloc_ring(adapter->pdev, p->jumbo_size,
+ sizeof(struct rx_desc),
+ sizeof(struct rx_sw_desc),
+ &q->fl[1].phys_addr, &q->fl[1].sdesc);
+ if (!q->fl[1].desc)
+ goto err;
+
+ q->rspq.desc = alloc_ring(adapter->pdev, p->rspq_size,
+ sizeof(struct rsp_desc), 0,
+ &q->rspq.phys_addr, NULL);
+ if (!q->rspq.desc)
+ goto err;
+
+ for (i = 0; i < ntxq; ++i) {
+ /*
+ * The control queue always uses immediate data so does not
+ * need to keep track of any sk_buffs.
+ */
+ size_t sz = i == TXQ_CTRL ? 0 : sizeof(struct tx_sw_desc);
+
+ q->txq[i].desc = alloc_ring(adapter->pdev, p->txq_size[i],
+ sizeof(struct tx_desc), sz,
+ &q->txq[i].phys_addr,
+ &q->txq[i].sdesc);
+ if (!q->txq[i].desc)
+ goto err;
+
+ q->txq[i].gen = 1;
+ q->txq[i].size = p->txq_size[i];
+ spin_lock_init(&q->txq[i].lock);
+ skb_queue_head_init(&q->txq[i].sendq);
+ }
+
+ tasklet_init(&q->txq[TXQ_OFLD].qresume_tsk, restart_offloadq,
+ (unsigned long)q);
+ tasklet_init(&q->txq[TXQ_CTRL].qresume_tsk, restart_ctrlq,
+ (unsigned long)q);
+
+ q->fl[0].gen = q->fl[1].gen = 1;
+ q->fl[0].size = p->fl_size;
+ q->fl[1].size = p->jumbo_size;
+
+ q->rspq.gen = 1;
+ q->rspq.size = p->rspq_size;
+ spin_lock_init(&q->rspq.lock);
+
+ q->txq[TXQ_ETH].stop_thres = nports *
+ flits_to_desc(sgl_len(MAX_SKB_FRAGS + 1) + 3);
+
+ if (ntxq == 1) {
+ q->fl[0].buf_size = SGE_RX_SM_BUF_SIZE + 2 +
+ sizeof(struct cpl_rx_pkt);
+ q->fl[1].buf_size = MAX_FRAME_SIZE + 2 +
+ sizeof(struct cpl_rx_pkt);
+ } else {
+ q->fl[0].buf_size = SGE_RX_SM_BUF_SIZE +
+ sizeof(struct cpl_rx_data);
+ q->fl[1].buf_size = (16 * 1024) -
+ SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+ }
+
+ spin_lock(&adapter->sge.reg_lock);
+
+ /* FL threshold comparison uses < */
+ ret = t3_sge_init_rspcntxt(adapter, q->rspq.cntxt_id, irq_vec_idx,
+ q->rspq.phys_addr, q->rspq.size,
+ q->fl[0].buf_size, 1, 0);
+ if (ret)
+ goto err_unlock;
+
+ for (i = 0; i < SGE_RXQ_PER_SET; ++i) {
+ ret = t3_sge_init_flcntxt(adapter, q->fl[i].cntxt_id, 0,
+ q->fl[i].phys_addr, q->fl[i].size,
+ q->fl[i].buf_size, p->cong_thres, 1,
+ 0);
+ if (ret)
+ goto err_unlock;
+ }
+
+ ret = t3_sge_init_ecntxt(adapter, q->txq[TXQ_ETH].cntxt_id, USE_GTS,
+ SGE_CNTXT_ETH, id, q->txq[TXQ_ETH].phys_addr,
+ q->txq[TXQ_ETH].size, q->txq[TXQ_ETH].token,
+ 1, 0);
+ if (ret)
+ goto err_unlock;
+
+ if (ntxq > 1) {
+ ret = t3_sge_init_ecntxt(adapter, q->txq[TXQ_OFLD].cntxt_id,
+ USE_GTS, SGE_CNTXT_OFLD, id,
+ q->txq[TXQ_OFLD].phys_addr,
+ q->txq[TXQ_OFLD].size, 0, 1, 0);
+ if (ret)
+ goto err_unlock;
+ }
+
+ if (ntxq > 2) {
+ ret = t3_sge_init_ecntxt(adapter, q->txq[TXQ_CTRL].cntxt_id, 0,
+ SGE_CNTXT_CTRL, id,
+ q->txq[TXQ_CTRL].phys_addr,
+ q->txq[TXQ_CTRL].size,
+ q->txq[TXQ_CTRL].token, 1, 0);
+ if (ret)
+ goto err_unlock;
+ }
+
+ spin_unlock(&adapter->sge.reg_lock);
+ q->netdev = netdev;
+ t3_update_qset_coalesce(q, p);
+
+ /*
+ * We use atalk_ptr as a backpointer to a qset. In case a device is
+ * associated with multiple queue sets only the first one sets
+ * atalk_ptr.
+ */
+ if (netdev->atalk_ptr == NULL)
+ netdev->atalk_ptr = q;
+
+ refill_fl(adapter, &q->fl[0], q->fl[0].size, GFP_KERNEL);
+ refill_fl(adapter, &q->fl[1], q->fl[1].size, GFP_KERNEL);
+ refill_rspq(adapter, &q->rspq, q->rspq.size - 1);
+
+ t3_write_reg(adapter, A_SG_GTS, V_RSPQ(q->rspq.cntxt_id) |
+ V_NEWTIMER(q->rspq.holdoff_tmr));
+
+ mod_timer(&q->tx_reclaim_timer, jiffies + TX_RECLAIM_PERIOD);
+ return 0;
+
+ err_unlock:
+ spin_unlock(&adapter->sge.reg_lock);
+ err:
+ t3_free_qset(adapter, q);
+ return ret;
+}
+
+/**
+ * t3_free_sge_resources - free SGE resources
+ * @adap: the adapter
+ *
+ * Frees resources used by the SGE queue sets.
+ */
+void t3_free_sge_resources(struct adapter *adap)
+{
+ int i;
+
+ for (i = 0; i < SGE_QSETS; ++i)
+ t3_free_qset(adap, &adap->sge.qs[i]);
+}
+
+/**
+ * t3_sge_start - enable SGE
+ * @adap: the adapter
+ *
+ * Enables the SGE for DMAs. This is the last step in starting packet
+ * transfers.
+ */
+void t3_sge_start(struct adapter *adap)
+{
+ t3_set_reg_field(adap, A_SG_CONTROL, F_GLOBALENABLE, F_GLOBALENABLE);
+}
+
+/**
+ * t3_sge_stop - disable SGE operation
+ * @adap: the adapter
+ *
+ * Disables the DMA engine. This can be called in emeregencies (e.g.,
+ * from error interrupts) or from normal process context. In the latter
+ * case it also disables any pending queue restart tasklets. Note that
+ * if it is called in interrupt context it cannot disable the restart
+ * tasklets as it cannot wait, however the tasklets will have no effect
+ * since the doorbells are disabled and the driver will call this again
+ * later from process context, at which time the tasklets will be stopped
+ * if they are still running.
+ */
+void t3_sge_stop(struct adapter *adap)
+{
+ t3_set_reg_field(adap, A_SG_CONTROL, F_GLOBALENABLE, 0);
+ if (!in_interrupt()) {
+ int i;
+
+ for (i = 0; i < SGE_QSETS; ++i) {
+ struct sge_qset *qs = &adap->sge.qs[i];
+
+ tasklet_kill(&qs->txq[TXQ_OFLD].qresume_tsk);
+ tasklet_kill(&qs->txq[TXQ_CTRL].qresume_tsk);
+ }
+ }
+}
+
+/**
+ * t3_sge_init - initialize SGE
+ * @adap: the adapter
+ * @p: the SGE parameters
+ *
+ * Performs SGE initialization needed every time after a chip reset.
+ * We do not initialize any of the queue sets here, instead the driver
+ * top-level must request those individually. We also do not enable DMA
+ * here, that should be done after the queues have been set up.
+ */
+void t3_sge_init(struct adapter *adap, struct sge_params *p)
+{
+ unsigned int ctrl, ups = ffs(pci_resource_len(adap->pdev, 2) >> 12);
+
+ ctrl = F_DROPPKT | V_PKTSHIFT(2) | F_FLMODE | F_AVOIDCQOVFL |
+ F_CQCRDTCTRL |
+ V_HOSTPAGESIZE(PAGE_SHIFT - 11) | F_BIGENDIANINGRESS |
+ V_USERSPACESIZE(ups ? ups - 1 : 0) | F_ISCSICOALESCING;
+#if SGE_NUM_GENBITS == 1
+ ctrl |= F_EGRGENCTRL;
+#endif
+ if (adap->params.rev > 0) {
+ if (!(adap->flags & (USING_MSIX | USING_MSI)))
+ ctrl |= F_ONEINTMULTQ | F_OPTONEINTMULTQ;
+ ctrl |= F_CQCRDTCTRL | F_AVOIDCQOVFL;
+ }
+ t3_write_reg(adap, A_SG_CONTROL, ctrl);
+ t3_write_reg(adap, A_SG_EGR_RCQ_DRB_THRSH, V_HIRCQDRBTHRSH(512) |
+ V_LORCQDRBTHRSH(512));
+ t3_write_reg(adap, A_SG_TIMER_TICK, core_ticks_per_usec(adap) / 10);
+ t3_write_reg(adap, A_SG_CMDQ_CREDIT_TH, V_THRESHOLD(32) |
+ V_TIMEOUT(200 * core_ticks_per_usec(adap)));
+ t3_write_reg(adap, A_SG_HI_DRB_HI_THRSH, 1000);
+ t3_write_reg(adap, A_SG_HI_DRB_LO_THRSH, 256);
+ t3_write_reg(adap, A_SG_LO_DRB_HI_THRSH, 1000);
+ t3_write_reg(adap, A_SG_LO_DRB_LO_THRSH, 256);
+ t3_write_reg(adap, A_SG_OCO_BASE, V_BASE1(0xfff));
+ t3_write_reg(adap, A_SG_DRB_PRI_THRESH, 63 * 1024);
+}
+
+/**
+ * t3_sge_prep - one-time SGE initialization
+ * @adap: the associated adapter
+ * @p: SGE parameters
+ *
+ * Performs one-time initialization of SGE SW state. Includes determining
+ * defaults for the assorted SGE parameters, which admins can change until
+ * they are used to initialize the SGE.
+ */
+void __devinit t3_sge_prep(struct adapter *adap, struct sge_params *p)
+{
+ int i;
+
+ p->max_pkt_size = (16 * 1024) - sizeof(struct cpl_rx_data) -
+ SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+
+ for (i = 0; i < SGE_QSETS; ++i) {
+ struct qset_params *q = p->qset + i;
+
+ q->polling = adap->params.rev > 0;
+ q->coalesce_usecs = 5;
+ q->rspq_size = 1024;
+ q->fl_size = 4096;
+ q->jumbo_size = 512;
+ q->txq_size[TXQ_ETH] = 1024;
+ q->txq_size[TXQ_OFLD] = 1024;
+ q->txq_size[TXQ_CTRL] = 256;
+ q->cong_thres = 0;
+ }
+
+ spin_lock_init(&adap->sge.reg_lock);
+}
+
+/**
+ * t3_get_desc - dump an SGE descriptor for debugging purposes
+ * @qs: the queue set
+ * @qnum: identifies the specific queue (0..2: Tx, 3:response, 4..5: Rx)
+ * @idx: the descriptor index in the queue
+ * @data: where to dump the descriptor contents
+ *
+ * Dumps the contents of a HW descriptor of an SGE queue. Returns the
+ * size of the descriptor.
+ */
+int t3_get_desc(const struct sge_qset *qs, unsigned int qnum, unsigned int idx,
+ unsigned char *data)
+{
+ if (qnum >= 6)
+ return -EINVAL;
+
+ if (qnum < 3) {
+ if (!qs->txq[qnum].desc || idx >= qs->txq[qnum].size)
+ return -EINVAL;
+ memcpy(data, &qs->txq[qnum].desc[idx], sizeof(struct tx_desc));
+ return sizeof(struct tx_desc);
+ }
+
+ if (qnum == 3) {
+ if (!qs->rspq.desc || idx >= qs->rspq.size)
+ return -EINVAL;
+ memcpy(data, &qs->rspq.desc[idx], sizeof(struct rsp_desc));
+ return sizeof(struct rsp_desc);
+ }
+
+ qnum -= 4;
+ if (!qs->fl[qnum].desc || idx >= qs->fl[qnum].size)
+ return -EINVAL;
+ memcpy(data, &qs->fl[qnum].desc[idx], sizeof(struct rx_desc));
+ return sizeof(struct rx_desc);
+}
diff --git a/drivers/net/cxgb3/sge_defs.h b/drivers/net/cxgb3/sge_defs.h
new file mode 100644
index 00000000000..514869e26a7
--- /dev/null
+++ b/drivers/net/cxgb3/sge_defs.h
@@ -0,0 +1,251 @@
+/*
+ * This file is automatically generated --- any changes will be lost.
+ */
+
+#ifndef _SGE_DEFS_H
+#define _SGE_DEFS_H
+
+#define S_EC_CREDITS 0
+#define M_EC_CREDITS 0x7FFF
+#define V_EC_CREDITS(x) ((x) << S_EC_CREDITS)
+#define G_EC_CREDITS(x) (((x) >> S_EC_CREDITS) & M_EC_CREDITS)
+
+#define S_EC_GTS 15
+#define V_EC_GTS(x) ((x) << S_EC_GTS)
+#define F_EC_GTS V_EC_GTS(1U)
+
+#define S_EC_INDEX 16
+#define M_EC_INDEX 0xFFFF
+#define V_EC_INDEX(x) ((x) << S_EC_INDEX)
+#define G_EC_INDEX(x) (((x) >> S_EC_INDEX) & M_EC_INDEX)
+
+#define S_EC_SIZE 0
+#define M_EC_SIZE 0xFFFF
+#define V_EC_SIZE(x) ((x) << S_EC_SIZE)
+#define G_EC_SIZE(x) (((x) >> S_EC_SIZE) & M_EC_SIZE)
+
+#define S_EC_BASE_LO 16
+#define M_EC_BASE_LO 0xFFFF
+#define V_EC_BASE_LO(x) ((x) << S_EC_BASE_LO)
+#define G_EC_BASE_LO(x) (((x) >> S_EC_BASE_LO) & M_EC_BASE_LO)
+
+#define S_EC_BASE_HI 0
+#define M_EC_BASE_HI 0xF
+#define V_EC_BASE_HI(x) ((x) << S_EC_BASE_HI)
+#define G_EC_BASE_HI(x) (((x) >> S_EC_BASE_HI) & M_EC_BASE_HI)
+
+#define S_EC_RESPQ 4
+#define M_EC_RESPQ 0x7
+#define V_EC_RESPQ(x) ((x) << S_EC_RESPQ)
+#define G_EC_RESPQ(x) (((x) >> S_EC_RESPQ) & M_EC_RESPQ)
+
+#define S_EC_TYPE 7
+#define M_EC_TYPE 0x7
+#define V_EC_TYPE(x) ((x) << S_EC_TYPE)
+#define G_EC_TYPE(x) (((x) >> S_EC_TYPE) & M_EC_TYPE)
+
+#define S_EC_GEN 10
+#define V_EC_GEN(x) ((x) << S_EC_GEN)
+#define F_EC_GEN V_EC_GEN(1U)
+
+#define S_EC_UP_TOKEN 11
+#define M_EC_UP_TOKEN 0xFFFFF
+#define V_EC_UP_TOKEN(x) ((x) << S_EC_UP_TOKEN)
+#define G_EC_UP_TOKEN(x) (((x) >> S_EC_UP_TOKEN) & M_EC_UP_TOKEN)
+
+#define S_EC_VALID 31
+#define V_EC_VALID(x) ((x) << S_EC_VALID)
+#define F_EC_VALID V_EC_VALID(1U)
+
+#define S_RQ_MSI_VEC 20
+#define M_RQ_MSI_VEC 0x3F
+#define V_RQ_MSI_VEC(x) ((x) << S_RQ_MSI_VEC)
+#define G_RQ_MSI_VEC(x) (((x) >> S_RQ_MSI_VEC) & M_RQ_MSI_VEC)
+
+#define S_RQ_INTR_EN 26
+#define V_RQ_INTR_EN(x) ((x) << S_RQ_INTR_EN)
+#define F_RQ_INTR_EN V_RQ_INTR_EN(1U)
+
+#define S_RQ_GEN 28
+#define V_RQ_GEN(x) ((x) << S_RQ_GEN)
+#define F_RQ_GEN V_RQ_GEN(1U)
+
+#define S_CQ_INDEX 0
+#define M_CQ_INDEX 0xFFFF
+#define V_CQ_INDEX(x) ((x) << S_CQ_INDEX)
+#define G_CQ_INDEX(x) (((x) >> S_CQ_INDEX) & M_CQ_INDEX)
+
+#define S_CQ_SIZE 16
+#define M_CQ_SIZE 0xFFFF
+#define V_CQ_SIZE(x) ((x) << S_CQ_SIZE)
+#define G_CQ_SIZE(x) (((x) >> S_CQ_SIZE) & M_CQ_SIZE)
+
+#define S_CQ_BASE_HI 0
+#define M_CQ_BASE_HI 0xFFFFF
+#define V_CQ_BASE_HI(x) ((x) << S_CQ_BASE_HI)
+#define G_CQ_BASE_HI(x) (((x) >> S_CQ_BASE_HI) & M_CQ_BASE_HI)
+
+#define S_CQ_RSPQ 20
+#define M_CQ_RSPQ 0x3F
+#define V_CQ_RSPQ(x) ((x) << S_CQ_RSPQ)
+#define G_CQ_RSPQ(x) (((x) >> S_CQ_RSPQ) & M_CQ_RSPQ)
+
+#define S_CQ_ASYNC_NOTIF 26
+#define V_CQ_ASYNC_NOTIF(x) ((x) << S_CQ_ASYNC_NOTIF)
+#define F_CQ_ASYNC_NOTIF V_CQ_ASYNC_NOTIF(1U)
+
+#define S_CQ_ARMED 27
+#define V_CQ_ARMED(x) ((x) << S_CQ_ARMED)
+#define F_CQ_ARMED V_CQ_ARMED(1U)
+
+#define S_CQ_ASYNC_NOTIF_SOL 28
+#define V_CQ_ASYNC_NOTIF_SOL(x) ((x) << S_CQ_ASYNC_NOTIF_SOL)
+#define F_CQ_ASYNC_NOTIF_SOL V_CQ_ASYNC_NOTIF_SOL(1U)
+
+#define S_CQ_GEN 29
+#define V_CQ_GEN(x) ((x) << S_CQ_GEN)
+#define F_CQ_GEN V_CQ_GEN(1U)
+
+#define S_CQ_OVERFLOW_MODE 31
+#define V_CQ_OVERFLOW_MODE(x) ((x) << S_CQ_OVERFLOW_MODE)
+#define F_CQ_OVERFLOW_MODE V_CQ_OVERFLOW_MODE(1U)
+
+#define S_CQ_CREDITS 0
+#define M_CQ_CREDITS 0xFFFF
+#define V_CQ_CREDITS(x) ((x) << S_CQ_CREDITS)
+#define G_CQ_CREDITS(x) (((x) >> S_CQ_CREDITS) & M_CQ_CREDITS)
+
+#define S_CQ_CREDIT_THRES 16
+#define M_CQ_CREDIT_THRES 0x1FFF
+#define V_CQ_CREDIT_THRES(x) ((x) << S_CQ_CREDIT_THRES)
+#define G_CQ_CREDIT_THRES(x) (((x) >> S_CQ_CREDIT_THRES) & M_CQ_CREDIT_THRES)
+
+#define S_FL_BASE_HI 0
+#define M_FL_BASE_HI 0xFFFFF
+#define V_FL_BASE_HI(x) ((x) << S_FL_BASE_HI)
+#define G_FL_BASE_HI(x) (((x) >> S_FL_BASE_HI) & M_FL_BASE_HI)
+
+#define S_FL_INDEX_LO 20
+#define M_FL_INDEX_LO 0xFFF
+#define V_FL_INDEX_LO(x) ((x) << S_FL_INDEX_LO)
+#define G_FL_INDEX_LO(x) (((x) >> S_FL_INDEX_LO) & M_FL_INDEX_LO)
+
+#define S_FL_INDEX_HI 0
+#define M_FL_INDEX_HI 0xF
+#define V_FL_INDEX_HI(x) ((x) << S_FL_INDEX_HI)
+#define G_FL_INDEX_HI(x) (((x) >> S_FL_INDEX_HI) & M_FL_INDEX_HI)
+
+#define S_FL_SIZE 4
+#define M_FL_SIZE 0xFFFF
+#define V_FL_SIZE(x) ((x) << S_FL_SIZE)
+#define G_FL_SIZE(x) (((x) >> S_FL_SIZE) & M_FL_SIZE)
+
+#define S_FL_GEN 20
+#define V_FL_GEN(x) ((x) << S_FL_GEN)
+#define F_FL_GEN V_FL_GEN(1U)
+
+#define S_FL_ENTRY_SIZE_LO 21
+#define M_FL_ENTRY_SIZE_LO 0x7FF
+#define V_FL_ENTRY_SIZE_LO(x) ((x) << S_FL_ENTRY_SIZE_LO)
+#define G_FL_ENTRY_SIZE_LO(x) (((x) >> S_FL_ENTRY_SIZE_LO) & M_FL_ENTRY_SIZE_LO)
+
+#define S_FL_ENTRY_SIZE_HI 0
+#define M_FL_ENTRY_SIZE_HI 0x1FFFFF
+#define V_FL_ENTRY_SIZE_HI(x) ((x) << S_FL_ENTRY_SIZE_HI)
+#define G_FL_ENTRY_SIZE_HI(x) (((x) >> S_FL_ENTRY_SIZE_HI) & M_FL_ENTRY_SIZE_HI)
+
+#define S_FL_CONG_THRES 21
+#define M_FL_CONG_THRES 0x3FF
+#define V_FL_CONG_THRES(x) ((x) << S_FL_CONG_THRES)
+#define G_FL_CONG_THRES(x) (((x) >> S_FL_CONG_THRES) & M_FL_CONG_THRES)
+
+#define S_FL_GTS 31
+#define V_FL_GTS(x) ((x) << S_FL_GTS)
+#define F_FL_GTS V_FL_GTS(1U)
+
+#define S_FLD_GEN1 31
+#define V_FLD_GEN1(x) ((x) << S_FLD_GEN1)
+#define F_FLD_GEN1 V_FLD_GEN1(1U)
+
+#define S_FLD_GEN2 0
+#define V_FLD_GEN2(x) ((x) << S_FLD_GEN2)
+#define F_FLD_GEN2 V_FLD_GEN2(1U)
+
+#define S_RSPD_TXQ1_CR 0
+#define M_RSPD_TXQ1_CR 0x7F
+#define V_RSPD_TXQ1_CR(x) ((x) << S_RSPD_TXQ1_CR)
+#define G_RSPD_TXQ1_CR(x) (((x) >> S_RSPD_TXQ1_CR) & M_RSPD_TXQ1_CR)
+
+#define S_RSPD_TXQ1_GTS 7
+#define V_RSPD_TXQ1_GTS(x) ((x) << S_RSPD_TXQ1_GTS)
+#define F_RSPD_TXQ1_GTS V_RSPD_TXQ1_GTS(1U)
+
+#define S_RSPD_TXQ2_CR 8
+#define M_RSPD_TXQ2_CR 0x7F
+#define V_RSPD_TXQ2_CR(x) ((x) << S_RSPD_TXQ2_CR)
+#define G_RSPD_TXQ2_CR(x) (((x) >> S_RSPD_TXQ2_CR) & M_RSPD_TXQ2_CR)
+
+#define S_RSPD_TXQ2_GTS 15
+#define V_RSPD_TXQ2_GTS(x) ((x) << S_RSPD_TXQ2_GTS)
+#define F_RSPD_TXQ2_GTS V_RSPD_TXQ2_GTS(1U)
+
+#define S_RSPD_TXQ0_CR 16
+#define M_RSPD_TXQ0_CR 0x7F
+#define V_RSPD_TXQ0_CR(x) ((x) << S_RSPD_TXQ0_CR)
+#define G_RSPD_TXQ0_CR(x) (((x) >> S_RSPD_TXQ0_CR) & M_RSPD_TXQ0_CR)
+
+#define S_RSPD_TXQ0_GTS 23
+#define V_RSPD_TXQ0_GTS(x) ((x) << S_RSPD_TXQ0_GTS)
+#define F_RSPD_TXQ0_GTS V_RSPD_TXQ0_GTS(1U)
+
+#define S_RSPD_EOP 24
+#define V_RSPD_EOP(x) ((x) << S_RSPD_EOP)
+#define F_RSPD_EOP V_RSPD_EOP(1U)
+
+#define S_RSPD_SOP 25
+#define V_RSPD_SOP(x) ((x) << S_RSPD_SOP)
+#define F_RSPD_SOP V_RSPD_SOP(1U)
+
+#define S_RSPD_ASYNC_NOTIF 26
+#define V_RSPD_ASYNC_NOTIF(x) ((x) << S_RSPD_ASYNC_NOTIF)
+#define F_RSPD_ASYNC_NOTIF V_RSPD_ASYNC_NOTIF(1U)
+
+#define S_RSPD_FL0_GTS 27
+#define V_RSPD_FL0_GTS(x) ((x) << S_RSPD_FL0_GTS)
+#define F_RSPD_FL0_GTS V_RSPD_FL0_GTS(1U)
+
+#define S_RSPD_FL1_GTS 28
+#define V_RSPD_FL1_GTS(x) ((x) << S_RSPD_FL1_GTS)
+#define F_RSPD_FL1_GTS V_RSPD_FL1_GTS(1U)
+
+#define S_RSPD_IMM_DATA_VALID 29
+#define V_RSPD_IMM_DATA_VALID(x) ((x) << S_RSPD_IMM_DATA_VALID)
+#define F_RSPD_IMM_DATA_VALID V_RSPD_IMM_DATA_VALID(1U)
+
+#define S_RSPD_OFFLOAD 30
+#define V_RSPD_OFFLOAD(x) ((x) << S_RSPD_OFFLOAD)
+#define F_RSPD_OFFLOAD V_RSPD_OFFLOAD(1U)
+
+#define S_RSPD_GEN1 31
+#define V_RSPD_GEN1(x) ((x) << S_RSPD_GEN1)
+#define F_RSPD_GEN1 V_RSPD_GEN1(1U)
+
+#define S_RSPD_LEN 0
+#define M_RSPD_LEN 0x7FFFFFFF
+#define V_RSPD_LEN(x) ((x) << S_RSPD_LEN)
+#define G_RSPD_LEN(x) (((x) >> S_RSPD_LEN) & M_RSPD_LEN)
+
+#define S_RSPD_FLQ 31
+#define V_RSPD_FLQ(x) ((x) << S_RSPD_FLQ)
+#define F_RSPD_FLQ V_RSPD_FLQ(1U)
+
+#define S_RSPD_GEN2 0
+#define V_RSPD_GEN2(x) ((x) << S_RSPD_GEN2)
+#define F_RSPD_GEN2 V_RSPD_GEN2(1U)
+
+#define S_RSPD_INR_VEC 1
+#define M_RSPD_INR_VEC 0x7F
+#define V_RSPD_INR_VEC(x) ((x) << S_RSPD_INR_VEC)
+#define G_RSPD_INR_VEC(x) (((x) >> S_RSPD_INR_VEC) & M_RSPD_INR_VEC)
+
+#endif /* _SGE_DEFS_H */
diff --git a/drivers/net/cxgb3/t3_cpl.h b/drivers/net/cxgb3/t3_cpl.h
new file mode 100644
index 00000000000..b7a1a310dfd
--- /dev/null
+++ b/drivers/net/cxgb3/t3_cpl.h
@@ -0,0 +1,1444 @@
+/*
+ * Copyright (c) 2004-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef T3_CPL_H
+#define T3_CPL_H
+
+#if !defined(__LITTLE_ENDIAN_BITFIELD) && !defined(__BIG_ENDIAN_BITFIELD)
+# include <asm/byteorder.h>
+#endif
+
+enum CPL_opcode {
+ CPL_PASS_OPEN_REQ = 0x1,
+ CPL_PASS_ACCEPT_RPL = 0x2,
+ CPL_ACT_OPEN_REQ = 0x3,
+ CPL_SET_TCB = 0x4,
+ CPL_SET_TCB_FIELD = 0x5,
+ CPL_GET_TCB = 0x6,
+ CPL_PCMD = 0x7,
+ CPL_CLOSE_CON_REQ = 0x8,
+ CPL_CLOSE_LISTSRV_REQ = 0x9,
+ CPL_ABORT_REQ = 0xA,
+ CPL_ABORT_RPL = 0xB,
+ CPL_TX_DATA = 0xC,
+ CPL_RX_DATA_ACK = 0xD,
+ CPL_TX_PKT = 0xE,
+ CPL_RTE_DELETE_REQ = 0xF,
+ CPL_RTE_WRITE_REQ = 0x10,
+ CPL_RTE_READ_REQ = 0x11,
+ CPL_L2T_WRITE_REQ = 0x12,
+ CPL_L2T_READ_REQ = 0x13,
+ CPL_SMT_WRITE_REQ = 0x14,
+ CPL_SMT_READ_REQ = 0x15,
+ CPL_TX_PKT_LSO = 0x16,
+ CPL_PCMD_READ = 0x17,
+ CPL_BARRIER = 0x18,
+ CPL_TID_RELEASE = 0x1A,
+
+ CPL_CLOSE_LISTSRV_RPL = 0x20,
+ CPL_ERROR = 0x21,
+ CPL_GET_TCB_RPL = 0x22,
+ CPL_L2T_WRITE_RPL = 0x23,
+ CPL_PCMD_READ_RPL = 0x24,
+ CPL_PCMD_RPL = 0x25,
+ CPL_PEER_CLOSE = 0x26,
+ CPL_RTE_DELETE_RPL = 0x27,
+ CPL_RTE_WRITE_RPL = 0x28,
+ CPL_RX_DDP_COMPLETE = 0x29,
+ CPL_RX_PHYS_ADDR = 0x2A,
+ CPL_RX_PKT = 0x2B,
+ CPL_RX_URG_NOTIFY = 0x2C,
+ CPL_SET_TCB_RPL = 0x2D,
+ CPL_SMT_WRITE_RPL = 0x2E,
+ CPL_TX_DATA_ACK = 0x2F,
+
+ CPL_ABORT_REQ_RSS = 0x30,
+ CPL_ABORT_RPL_RSS = 0x31,
+ CPL_CLOSE_CON_RPL = 0x32,
+ CPL_ISCSI_HDR = 0x33,
+ CPL_L2T_READ_RPL = 0x34,
+ CPL_RDMA_CQE = 0x35,
+ CPL_RDMA_CQE_READ_RSP = 0x36,
+ CPL_RDMA_CQE_ERR = 0x37,
+ CPL_RTE_READ_RPL = 0x38,
+ CPL_RX_DATA = 0x39,
+
+ CPL_ACT_OPEN_RPL = 0x40,
+ CPL_PASS_OPEN_RPL = 0x41,
+ CPL_RX_DATA_DDP = 0x42,
+ CPL_SMT_READ_RPL = 0x43,
+
+ CPL_ACT_ESTABLISH = 0x50,
+ CPL_PASS_ESTABLISH = 0x51,
+
+ CPL_PASS_ACCEPT_REQ = 0x70,
+
+ CPL_ASYNC_NOTIF = 0x80, /* fake opcode for async notifications */
+
+ CPL_TX_DMA_ACK = 0xA0,
+ CPL_RDMA_READ_REQ = 0xA1,
+ CPL_RDMA_TERMINATE = 0xA2,
+ CPL_TRACE_PKT = 0xA3,
+ CPL_RDMA_EC_STATUS = 0xA5,
+
+ NUM_CPL_CMDS /* must be last and previous entries must be sorted */
+};
+
+enum CPL_error {
+ CPL_ERR_NONE = 0,
+ CPL_ERR_TCAM_PARITY = 1,
+ CPL_ERR_TCAM_FULL = 3,
+ CPL_ERR_CONN_RESET = 20,
+ CPL_ERR_CONN_EXIST = 22,
+ CPL_ERR_ARP_MISS = 23,
+ CPL_ERR_BAD_SYN = 24,
+ CPL_ERR_CONN_TIMEDOUT = 30,
+ CPL_ERR_XMIT_TIMEDOUT = 31,
+ CPL_ERR_PERSIST_TIMEDOUT = 32,
+ CPL_ERR_FINWAIT2_TIMEDOUT = 33,
+ CPL_ERR_KEEPALIVE_TIMEDOUT = 34,
+ CPL_ERR_RTX_NEG_ADVICE = 35,
+ CPL_ERR_PERSIST_NEG_ADVICE = 36,
+ CPL_ERR_ABORT_FAILED = 42,
+ CPL_ERR_GENERAL = 99
+};
+
+enum {
+ CPL_CONN_POLICY_AUTO = 0,
+ CPL_CONN_POLICY_ASK = 1,
+ CPL_CONN_POLICY_DENY = 3
+};
+
+enum {
+ ULP_MODE_NONE = 0,
+ ULP_MODE_ISCSI = 2,
+ ULP_MODE_RDMA = 4,
+ ULP_MODE_TCPDDP = 5
+};
+
+enum {
+ ULP_CRC_HEADER = 1 << 0,
+ ULP_CRC_DATA = 1 << 1
+};
+
+enum {
+ CPL_PASS_OPEN_ACCEPT,
+ CPL_PASS_OPEN_REJECT
+};
+
+enum {
+ CPL_ABORT_SEND_RST = 0,
+ CPL_ABORT_NO_RST,
+ CPL_ABORT_POST_CLOSE_REQ = 2
+};
+
+enum { /* TX_PKT_LSO ethernet types */
+ CPL_ETH_II,
+ CPL_ETH_II_VLAN,
+ CPL_ETH_802_3,
+ CPL_ETH_802_3_VLAN
+};
+
+enum { /* TCP congestion control algorithms */
+ CONG_ALG_RENO,
+ CONG_ALG_TAHOE,
+ CONG_ALG_NEWRENO,
+ CONG_ALG_HIGHSPEED
+};
+
+union opcode_tid {
+ __be32 opcode_tid;
+ __u8 opcode;
+};
+
+#define S_OPCODE 24
+#define V_OPCODE(x) ((x) << S_OPCODE)
+#define G_OPCODE(x) (((x) >> S_OPCODE) & 0xFF)
+#define G_TID(x) ((x) & 0xFFFFFF)
+
+/* tid is assumed to be 24-bits */
+#define MK_OPCODE_TID(opcode, tid) (V_OPCODE(opcode) | (tid))
+
+#define OPCODE_TID(cmd) ((cmd)->ot.opcode_tid)
+
+/* extract the TID from a CPL command */
+#define GET_TID(cmd) (G_TID(ntohl(OPCODE_TID(cmd))))
+
+struct tcp_options {
+ __be16 mss;
+ __u8 wsf;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8:5;
+ __u8 ecn:1;
+ __u8 sack:1;
+ __u8 tstamp:1;
+#else
+ __u8 tstamp:1;
+ __u8 sack:1;
+ __u8 ecn:1;
+ __u8:5;
+#endif
+};
+
+struct rss_header {
+ __u8 opcode;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 cpu_idx:6;
+ __u8 hash_type:2;
+#else
+ __u8 hash_type:2;
+ __u8 cpu_idx:6;
+#endif
+ __be16 cq_idx;
+ __be32 rss_hash_val;
+};
+
+#ifndef CHELSIO_FW
+struct work_request_hdr {
+ __be32 wr_hi;
+ __be32 wr_lo;
+};
+
+/* wr_hi fields */
+#define S_WR_SGE_CREDITS 0
+#define M_WR_SGE_CREDITS 0xFF
+#define V_WR_SGE_CREDITS(x) ((x) << S_WR_SGE_CREDITS)
+#define G_WR_SGE_CREDITS(x) (((x) >> S_WR_SGE_CREDITS) & M_WR_SGE_CREDITS)
+
+#define S_WR_SGLSFLT 8
+#define M_WR_SGLSFLT 0xFF
+#define V_WR_SGLSFLT(x) ((x) << S_WR_SGLSFLT)
+#define G_WR_SGLSFLT(x) (((x) >> S_WR_SGLSFLT) & M_WR_SGLSFLT)
+
+#define S_WR_BCNTLFLT 16
+#define M_WR_BCNTLFLT 0xF
+#define V_WR_BCNTLFLT(x) ((x) << S_WR_BCNTLFLT)
+#define G_WR_BCNTLFLT(x) (((x) >> S_WR_BCNTLFLT) & M_WR_BCNTLFLT)
+
+#define S_WR_DATATYPE 20
+#define V_WR_DATATYPE(x) ((x) << S_WR_DATATYPE)
+#define F_WR_DATATYPE V_WR_DATATYPE(1U)
+
+#define S_WR_COMPL 21
+#define V_WR_COMPL(x) ((x) << S_WR_COMPL)
+#define F_WR_COMPL V_WR_COMPL(1U)
+
+#define S_WR_EOP 22
+#define V_WR_EOP(x) ((x) << S_WR_EOP)
+#define F_WR_EOP V_WR_EOP(1U)
+
+#define S_WR_SOP 23
+#define V_WR_SOP(x) ((x) << S_WR_SOP)
+#define F_WR_SOP V_WR_SOP(1U)
+
+#define S_WR_OP 24
+#define M_WR_OP 0xFF
+#define V_WR_OP(x) ((x) << S_WR_OP)
+#define G_WR_OP(x) (((x) >> S_WR_OP) & M_WR_OP)
+
+/* wr_lo fields */
+#define S_WR_LEN 0
+#define M_WR_LEN 0xFF
+#define V_WR_LEN(x) ((x) << S_WR_LEN)
+#define G_WR_LEN(x) (((x) >> S_WR_LEN) & M_WR_LEN)
+
+#define S_WR_TID 8
+#define M_WR_TID 0xFFFFF
+#define V_WR_TID(x) ((x) << S_WR_TID)
+#define G_WR_TID(x) (((x) >> S_WR_TID) & M_WR_TID)
+
+#define S_WR_CR_FLUSH 30
+#define V_WR_CR_FLUSH(x) ((x) << S_WR_CR_FLUSH)
+#define F_WR_CR_FLUSH V_WR_CR_FLUSH(1U)
+
+#define S_WR_GEN 31
+#define V_WR_GEN(x) ((x) << S_WR_GEN)
+#define F_WR_GEN V_WR_GEN(1U)
+
+# define WR_HDR struct work_request_hdr wr
+# define RSS_HDR
+#else
+# define WR_HDR
+# define RSS_HDR struct rss_header rss_hdr;
+#endif
+
+/* option 0 lower-half fields */
+#define S_CPL_STATUS 0
+#define M_CPL_STATUS 0xFF
+#define V_CPL_STATUS(x) ((x) << S_CPL_STATUS)
+#define G_CPL_STATUS(x) (((x) >> S_CPL_STATUS) & M_CPL_STATUS)
+
+#define S_INJECT_TIMER 6
+#define V_INJECT_TIMER(x) ((x) << S_INJECT_TIMER)
+#define F_INJECT_TIMER V_INJECT_TIMER(1U)
+
+#define S_NO_OFFLOAD 7
+#define V_NO_OFFLOAD(x) ((x) << S_NO_OFFLOAD)
+#define F_NO_OFFLOAD V_NO_OFFLOAD(1U)
+
+#define S_ULP_MODE 8
+#define M_ULP_MODE 0xF
+#define V_ULP_MODE(x) ((x) << S_ULP_MODE)
+#define G_ULP_MODE(x) (((x) >> S_ULP_MODE) & M_ULP_MODE)
+
+#define S_RCV_BUFSIZ 12
+#define M_RCV_BUFSIZ 0x3FFF
+#define V_RCV_BUFSIZ(x) ((x) << S_RCV_BUFSIZ)
+#define G_RCV_BUFSIZ(x) (((x) >> S_RCV_BUFSIZ) & M_RCV_BUFSIZ)
+
+#define S_TOS 26
+#define M_TOS 0x3F
+#define V_TOS(x) ((x) << S_TOS)
+#define G_TOS(x) (((x) >> S_TOS) & M_TOS)
+
+/* option 0 upper-half fields */
+#define S_DELACK 0
+#define V_DELACK(x) ((x) << S_DELACK)
+#define F_DELACK V_DELACK(1U)
+
+#define S_NO_CONG 1
+#define V_NO_CONG(x) ((x) << S_NO_CONG)
+#define F_NO_CONG V_NO_CONG(1U)
+
+#define S_SRC_MAC_SEL 2
+#define M_SRC_MAC_SEL 0x3
+#define V_SRC_MAC_SEL(x) ((x) << S_SRC_MAC_SEL)
+#define G_SRC_MAC_SEL(x) (((x) >> S_SRC_MAC_SEL) & M_SRC_MAC_SEL)
+
+#define S_L2T_IDX 4
+#define M_L2T_IDX 0x7FF
+#define V_L2T_IDX(x) ((x) << S_L2T_IDX)
+#define G_L2T_IDX(x) (((x) >> S_L2T_IDX) & M_L2T_IDX)
+
+#define S_TX_CHANNEL 15
+#define V_TX_CHANNEL(x) ((x) << S_TX_CHANNEL)
+#define F_TX_CHANNEL V_TX_CHANNEL(1U)
+
+#define S_TCAM_BYPASS 16
+#define V_TCAM_BYPASS(x) ((x) << S_TCAM_BYPASS)
+#define F_TCAM_BYPASS V_TCAM_BYPASS(1U)
+
+#define S_NAGLE 17
+#define V_NAGLE(x) ((x) << S_NAGLE)
+#define F_NAGLE V_NAGLE(1U)
+
+#define S_WND_SCALE 18
+#define M_WND_SCALE 0xF
+#define V_WND_SCALE(x) ((x) << S_WND_SCALE)
+#define G_WND_SCALE(x) (((x) >> S_WND_SCALE) & M_WND_SCALE)
+
+#define S_KEEP_ALIVE 22
+#define V_KEEP_ALIVE(x) ((x) << S_KEEP_ALIVE)
+#define F_KEEP_ALIVE V_KEEP_ALIVE(1U)
+
+#define S_MAX_RETRANS 23
+#define M_MAX_RETRANS 0xF
+#define V_MAX_RETRANS(x) ((x) << S_MAX_RETRANS)
+#define G_MAX_RETRANS(x) (((x) >> S_MAX_RETRANS) & M_MAX_RETRANS)
+
+#define S_MAX_RETRANS_OVERRIDE 27
+#define V_MAX_RETRANS_OVERRIDE(x) ((x) << S_MAX_RETRANS_OVERRIDE)
+#define F_MAX_RETRANS_OVERRIDE V_MAX_RETRANS_OVERRIDE(1U)
+
+#define S_MSS_IDX 28
+#define M_MSS_IDX 0xF
+#define V_MSS_IDX(x) ((x) << S_MSS_IDX)
+#define G_MSS_IDX(x) (((x) >> S_MSS_IDX) & M_MSS_IDX)
+
+/* option 1 fields */
+#define S_RSS_ENABLE 0
+#define V_RSS_ENABLE(x) ((x) << S_RSS_ENABLE)
+#define F_RSS_ENABLE V_RSS_ENABLE(1U)
+
+#define S_RSS_MASK_LEN 1
+#define M_RSS_MASK_LEN 0x7
+#define V_RSS_MASK_LEN(x) ((x) << S_RSS_MASK_LEN)
+#define G_RSS_MASK_LEN(x) (((x) >> S_RSS_MASK_LEN) & M_RSS_MASK_LEN)
+
+#define S_CPU_IDX 4
+#define M_CPU_IDX 0x3F
+#define V_CPU_IDX(x) ((x) << S_CPU_IDX)
+#define G_CPU_IDX(x) (((x) >> S_CPU_IDX) & M_CPU_IDX)
+
+#define S_MAC_MATCH_VALID 18
+#define V_MAC_MATCH_VALID(x) ((x) << S_MAC_MATCH_VALID)
+#define F_MAC_MATCH_VALID V_MAC_MATCH_VALID(1U)
+
+#define S_CONN_POLICY 19
+#define M_CONN_POLICY 0x3
+#define V_CONN_POLICY(x) ((x) << S_CONN_POLICY)
+#define G_CONN_POLICY(x) (((x) >> S_CONN_POLICY) & M_CONN_POLICY)
+
+#define S_SYN_DEFENSE 21
+#define V_SYN_DEFENSE(x) ((x) << S_SYN_DEFENSE)
+#define F_SYN_DEFENSE V_SYN_DEFENSE(1U)
+
+#define S_VLAN_PRI 22
+#define M_VLAN_PRI 0x3
+#define V_VLAN_PRI(x) ((x) << S_VLAN_PRI)
+#define G_VLAN_PRI(x) (((x) >> S_VLAN_PRI) & M_VLAN_PRI)
+
+#define S_VLAN_PRI_VALID 24
+#define V_VLAN_PRI_VALID(x) ((x) << S_VLAN_PRI_VALID)
+#define F_VLAN_PRI_VALID V_VLAN_PRI_VALID(1U)
+
+#define S_PKT_TYPE 25
+#define M_PKT_TYPE 0x3
+#define V_PKT_TYPE(x) ((x) << S_PKT_TYPE)
+#define G_PKT_TYPE(x) (((x) >> S_PKT_TYPE) & M_PKT_TYPE)
+
+#define S_MAC_MATCH 27
+#define M_MAC_MATCH 0x1F
+#define V_MAC_MATCH(x) ((x) << S_MAC_MATCH)
+#define G_MAC_MATCH(x) (((x) >> S_MAC_MATCH) & M_MAC_MATCH)
+
+/* option 2 fields */
+#define S_CPU_INDEX 0
+#define M_CPU_INDEX 0x7F
+#define V_CPU_INDEX(x) ((x) << S_CPU_INDEX)
+#define G_CPU_INDEX(x) (((x) >> S_CPU_INDEX) & M_CPU_INDEX)
+
+#define S_CPU_INDEX_VALID 7
+#define V_CPU_INDEX_VALID(x) ((x) << S_CPU_INDEX_VALID)
+#define F_CPU_INDEX_VALID V_CPU_INDEX_VALID(1U)
+
+#define S_RX_COALESCE 8
+#define M_RX_COALESCE 0x3
+#define V_RX_COALESCE(x) ((x) << S_RX_COALESCE)
+#define G_RX_COALESCE(x) (((x) >> S_RX_COALESCE) & M_RX_COALESCE)
+
+#define S_RX_COALESCE_VALID 10
+#define V_RX_COALESCE_VALID(x) ((x) << S_RX_COALESCE_VALID)
+#define F_RX_COALESCE_VALID V_RX_COALESCE_VALID(1U)
+
+#define S_CONG_CONTROL_FLAVOR 11
+#define M_CONG_CONTROL_FLAVOR 0x3
+#define V_CONG_CONTROL_FLAVOR(x) ((x) << S_CONG_CONTROL_FLAVOR)
+#define G_CONG_CONTROL_FLAVOR(x) (((x) >> S_CONG_CONTROL_FLAVOR) & M_CONG_CONTROL_FLAVOR)
+
+#define S_PACING_FLAVOR 13
+#define M_PACING_FLAVOR 0x3
+#define V_PACING_FLAVOR(x) ((x) << S_PACING_FLAVOR)
+#define G_PACING_FLAVOR(x) (((x) >> S_PACING_FLAVOR) & M_PACING_FLAVOR)
+
+#define S_FLAVORS_VALID 15
+#define V_FLAVORS_VALID(x) ((x) << S_FLAVORS_VALID)
+#define F_FLAVORS_VALID V_FLAVORS_VALID(1U)
+
+#define S_RX_FC_DISABLE 16
+#define V_RX_FC_DISABLE(x) ((x) << S_RX_FC_DISABLE)
+#define F_RX_FC_DISABLE V_RX_FC_DISABLE(1U)
+
+#define S_RX_FC_VALID 17
+#define V_RX_FC_VALID(x) ((x) << S_RX_FC_VALID)
+#define F_RX_FC_VALID V_RX_FC_VALID(1U)
+
+struct cpl_pass_open_req {
+ WR_HDR;
+ union opcode_tid ot;
+ __be16 local_port;
+ __be16 peer_port;
+ __be32 local_ip;
+ __be32 peer_ip;
+ __be32 opt0h;
+ __be32 opt0l;
+ __be32 peer_netmask;
+ __be32 opt1;
+};
+
+struct cpl_pass_open_rpl {
+ RSS_HDR union opcode_tid ot;
+ __be16 local_port;
+ __be16 peer_port;
+ __be32 local_ip;
+ __be32 peer_ip;
+ __u8 resvd[7];
+ __u8 status;
+};
+
+struct cpl_pass_establish {
+ RSS_HDR union opcode_tid ot;
+ __be16 local_port;
+ __be16 peer_port;
+ __be32 local_ip;
+ __be32 peer_ip;
+ __be32 tos_tid;
+ __be16 l2t_idx;
+ __be16 tcp_opt;
+ __be32 snd_isn;
+ __be32 rcv_isn;
+};
+
+/* cpl_pass_establish.tos_tid fields */
+#define S_PASS_OPEN_TID 0
+#define M_PASS_OPEN_TID 0xFFFFFF
+#define V_PASS_OPEN_TID(x) ((x) << S_PASS_OPEN_TID)
+#define G_PASS_OPEN_TID(x) (((x) >> S_PASS_OPEN_TID) & M_PASS_OPEN_TID)
+
+#define S_PASS_OPEN_TOS 24
+#define M_PASS_OPEN_TOS 0xFF
+#define V_PASS_OPEN_TOS(x) ((x) << S_PASS_OPEN_TOS)
+#define G_PASS_OPEN_TOS(x) (((x) >> S_PASS_OPEN_TOS) & M_PASS_OPEN_TOS)
+
+/* cpl_pass_establish.l2t_idx fields */
+#define S_L2T_IDX16 5
+#define M_L2T_IDX16 0x7FF
+#define V_L2T_IDX16(x) ((x) << S_L2T_IDX16)
+#define G_L2T_IDX16(x) (((x) >> S_L2T_IDX16) & M_L2T_IDX16)
+
+/* cpl_pass_establish.tcp_opt fields (also applies act_open_establish) */
+#define G_TCPOPT_WSCALE_OK(x) (((x) >> 5) & 1)
+#define G_TCPOPT_SACK(x) (((x) >> 6) & 1)
+#define G_TCPOPT_TSTAMP(x) (((x) >> 7) & 1)
+#define G_TCPOPT_SND_WSCALE(x) (((x) >> 8) & 0xf)
+#define G_TCPOPT_MSS(x) (((x) >> 12) & 0xf)
+
+struct cpl_pass_accept_req {
+ RSS_HDR union opcode_tid ot;
+ __be16 local_port;
+ __be16 peer_port;
+ __be32 local_ip;
+ __be32 peer_ip;
+ __be32 tos_tid;
+ struct tcp_options tcp_options;
+ __u8 dst_mac[6];
+ __be16 vlan_tag;
+ __u8 src_mac[6];
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8:3;
+ __u8 addr_idx:3;
+ __u8 port_idx:1;
+ __u8 exact_match:1;
+#else
+ __u8 exact_match:1;
+ __u8 port_idx:1;
+ __u8 addr_idx:3;
+ __u8:3;
+#endif
+ __u8 rsvd;
+ __be32 rcv_isn;
+ __be32 rsvd2;
+};
+
+struct cpl_pass_accept_rpl {
+ WR_HDR;
+ union opcode_tid ot;
+ __be32 opt2;
+ __be32 rsvd;
+ __be32 peer_ip;
+ __be32 opt0h;
+ __be32 opt0l_status;
+};
+
+struct cpl_act_open_req {
+ WR_HDR;
+ union opcode_tid ot;
+ __be16 local_port;
+ __be16 peer_port;
+ __be32 local_ip;
+ __be32 peer_ip;
+ __be32 opt0h;
+ __be32 opt0l;
+ __be32 params;
+ __be32 opt2;
+};
+
+/* cpl_act_open_req.params fields */
+#define S_AOPEN_VLAN_PRI 9
+#define M_AOPEN_VLAN_PRI 0x3
+#define V_AOPEN_VLAN_PRI(x) ((x) << S_AOPEN_VLAN_PRI)
+#define G_AOPEN_VLAN_PRI(x) (((x) >> S_AOPEN_VLAN_PRI) & M_AOPEN_VLAN_PRI)
+
+#define S_AOPEN_VLAN_PRI_VALID 11
+#define V_AOPEN_VLAN_PRI_VALID(x) ((x) << S_AOPEN_VLAN_PRI_VALID)
+#define F_AOPEN_VLAN_PRI_VALID V_AOPEN_VLAN_PRI_VALID(1U)
+
+#define S_AOPEN_PKT_TYPE 12
+#define M_AOPEN_PKT_TYPE 0x3
+#define V_AOPEN_PKT_TYPE(x) ((x) << S_AOPEN_PKT_TYPE)
+#define G_AOPEN_PKT_TYPE(x) (((x) >> S_AOPEN_PKT_TYPE) & M_AOPEN_PKT_TYPE)
+
+#define S_AOPEN_MAC_MATCH 14
+#define M_AOPEN_MAC_MATCH 0x1F
+#define V_AOPEN_MAC_MATCH(x) ((x) << S_AOPEN_MAC_MATCH)
+#define G_AOPEN_MAC_MATCH(x) (((x) >> S_AOPEN_MAC_MATCH) & M_AOPEN_MAC_MATCH)
+
+#define S_AOPEN_MAC_MATCH_VALID 19
+#define V_AOPEN_MAC_MATCH_VALID(x) ((x) << S_AOPEN_MAC_MATCH_VALID)
+#define F_AOPEN_MAC_MATCH_VALID V_AOPEN_MAC_MATCH_VALID(1U)
+
+#define S_AOPEN_IFF_VLAN 20
+#define M_AOPEN_IFF_VLAN 0xFFF
+#define V_AOPEN_IFF_VLAN(x) ((x) << S_AOPEN_IFF_VLAN)
+#define G_AOPEN_IFF_VLAN(x) (((x) >> S_AOPEN_IFF_VLAN) & M_AOPEN_IFF_VLAN)
+
+struct cpl_act_open_rpl {
+ RSS_HDR union opcode_tid ot;
+ __be16 local_port;
+ __be16 peer_port;
+ __be32 local_ip;
+ __be32 peer_ip;
+ __be32 atid;
+ __u8 rsvd[3];
+ __u8 status;
+};
+
+struct cpl_act_establish {
+ RSS_HDR union opcode_tid ot;
+ __be16 local_port;
+ __be16 peer_port;
+ __be32 local_ip;
+ __be32 peer_ip;
+ __be32 tos_tid;
+ __be16 l2t_idx;
+ __be16 tcp_opt;
+ __be32 snd_isn;
+ __be32 rcv_isn;
+};
+
+struct cpl_get_tcb {
+ WR_HDR;
+ union opcode_tid ot;
+ __be16 cpuno;
+ __be16 rsvd;
+};
+
+struct cpl_get_tcb_rpl {
+ RSS_HDR union opcode_tid ot;
+ __u8 rsvd;
+ __u8 status;
+ __be16 len;
+};
+
+struct cpl_set_tcb {
+ WR_HDR;
+ union opcode_tid ot;
+ __u8 reply;
+ __u8 cpu_idx;
+ __be16 len;
+};
+
+/* cpl_set_tcb.reply fields */
+#define S_NO_REPLY 7
+#define V_NO_REPLY(x) ((x) << S_NO_REPLY)
+#define F_NO_REPLY V_NO_REPLY(1U)
+
+struct cpl_set_tcb_field {
+ WR_HDR;
+ union opcode_tid ot;
+ __u8 reply;
+ __u8 cpu_idx;
+ __be16 word;
+ __be64 mask;
+ __be64 val;
+};
+
+struct cpl_set_tcb_rpl {
+ RSS_HDR union opcode_tid ot;
+ __u8 rsvd[3];
+ __u8 status;
+};
+
+struct cpl_pcmd {
+ WR_HDR;
+ union opcode_tid ot;
+ __u8 rsvd[3];
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 src:1;
+ __u8 bundle:1;
+ __u8 channel:1;
+ __u8:5;
+#else
+ __u8:5;
+ __u8 channel:1;
+ __u8 bundle:1;
+ __u8 src:1;
+#endif
+ __be32 pcmd_parm[2];
+};
+
+struct cpl_pcmd_reply {
+ RSS_HDR union opcode_tid ot;
+ __u8 status;
+ __u8 rsvd;
+ __be16 len;
+};
+
+struct cpl_close_con_req {
+ WR_HDR;
+ union opcode_tid ot;
+ __be32 rsvd;
+};
+
+struct cpl_close_con_rpl {
+ RSS_HDR union opcode_tid ot;
+ __u8 rsvd[3];
+ __u8 status;
+ __be32 snd_nxt;
+ __be32 rcv_nxt;
+};
+
+struct cpl_close_listserv_req {
+ WR_HDR;
+ union opcode_tid ot;
+ __u8 rsvd0;
+ __u8 cpu_idx;
+ __be16 rsvd1;
+};
+
+struct cpl_close_listserv_rpl {
+ RSS_HDR union opcode_tid ot;
+ __u8 rsvd[3];
+ __u8 status;
+};
+
+struct cpl_abort_req_rss {
+ RSS_HDR union opcode_tid ot;
+ __be32 rsvd0;
+ __u8 rsvd1;
+ __u8 status;
+ __u8 rsvd2[6];
+};
+
+struct cpl_abort_req {
+ WR_HDR;
+ union opcode_tid ot;
+ __be32 rsvd0;
+ __u8 rsvd1;
+ __u8 cmd;
+ __u8 rsvd2[6];
+};
+
+struct cpl_abort_rpl_rss {
+ RSS_HDR union opcode_tid ot;
+ __be32 rsvd0;
+ __u8 rsvd1;
+ __u8 status;
+ __u8 rsvd2[6];
+};
+
+struct cpl_abort_rpl {
+ WR_HDR;
+ union opcode_tid ot;
+ __be32 rsvd0;
+ __u8 rsvd1;
+ __u8 cmd;
+ __u8 rsvd2[6];
+};
+
+struct cpl_peer_close {
+ RSS_HDR union opcode_tid ot;
+ __be32 rcv_nxt;
+};
+
+struct tx_data_wr {
+ __be32 wr_hi;
+ __be32 wr_lo;
+ __be32 len;
+ __be32 flags;
+ __be32 sndseq;
+ __be32 param;
+};
+
+/* tx_data_wr.param fields */
+#define S_TX_PORT 0
+#define M_TX_PORT 0x7
+#define V_TX_PORT(x) ((x) << S_TX_PORT)
+#define G_TX_PORT(x) (((x) >> S_TX_PORT) & M_TX_PORT)
+
+#define S_TX_MSS 4
+#define M_TX_MSS 0xF
+#define V_TX_MSS(x) ((x) << S_TX_MSS)
+#define G_TX_MSS(x) (((x) >> S_TX_MSS) & M_TX_MSS)
+
+#define S_TX_QOS 8
+#define M_TX_QOS 0xFF
+#define V_TX_QOS(x) ((x) << S_TX_QOS)
+#define G_TX_QOS(x) (((x) >> S_TX_QOS) & M_TX_QOS)
+
+#define S_TX_SNDBUF 16
+#define M_TX_SNDBUF 0xFFFF
+#define V_TX_SNDBUF(x) ((x) << S_TX_SNDBUF)
+#define G_TX_SNDBUF(x) (((x) >> S_TX_SNDBUF) & M_TX_SNDBUF)
+
+struct cpl_tx_data {
+ union opcode_tid ot;
+ __be32 len;
+ __be32 rsvd;
+ __be16 urg;
+ __be16 flags;
+};
+
+/* cpl_tx_data.flags fields */
+#define S_TX_ULP_SUBMODE 6
+#define M_TX_ULP_SUBMODE 0xF
+#define V_TX_ULP_SUBMODE(x) ((x) << S_TX_ULP_SUBMODE)
+#define G_TX_ULP_SUBMODE(x) (((x) >> S_TX_ULP_SUBMODE) & M_TX_ULP_SUBMODE)
+
+#define S_TX_ULP_MODE 10
+#define M_TX_ULP_MODE 0xF
+#define V_TX_ULP_MODE(x) ((x) << S_TX_ULP_MODE)
+#define G_TX_ULP_MODE(x) (((x) >> S_TX_ULP_MODE) & M_TX_ULP_MODE)
+
+#define S_TX_SHOVE 14
+#define V_TX_SHOVE(x) ((x) << S_TX_SHOVE)
+#define F_TX_SHOVE V_TX_SHOVE(1U)
+
+#define S_TX_MORE 15
+#define V_TX_MORE(x) ((x) << S_TX_MORE)
+#define F_TX_MORE V_TX_MORE(1U)
+
+/* additional tx_data_wr.flags fields */
+#define S_TX_CPU_IDX 0
+#define M_TX_CPU_IDX 0x3F
+#define V_TX_CPU_IDX(x) ((x) << S_TX_CPU_IDX)
+#define G_TX_CPU_IDX(x) (((x) >> S_TX_CPU_IDX) & M_TX_CPU_IDX)
+
+#define S_TX_URG 16
+#define V_TX_URG(x) ((x) << S_TX_URG)
+#define F_TX_URG V_TX_URG(1U)
+
+#define S_TX_CLOSE 17
+#define V_TX_CLOSE(x) ((x) << S_TX_CLOSE)
+#define F_TX_CLOSE V_TX_CLOSE(1U)
+
+#define S_TX_INIT 18
+#define V_TX_INIT(x) ((x) << S_TX_INIT)
+#define F_TX_INIT V_TX_INIT(1U)
+
+#define S_TX_IMM_ACK 19
+#define V_TX_IMM_ACK(x) ((x) << S_TX_IMM_ACK)
+#define F_TX_IMM_ACK V_TX_IMM_ACK(1U)
+
+#define S_TX_IMM_DMA 20
+#define V_TX_IMM_DMA(x) ((x) << S_TX_IMM_DMA)
+#define F_TX_IMM_DMA V_TX_IMM_DMA(1U)
+
+struct cpl_tx_data_ack {
+ RSS_HDR union opcode_tid ot;
+ __be32 ack_seq;
+};
+
+struct cpl_wr_ack {
+ RSS_HDR union opcode_tid ot;
+ __be16 credits;
+ __be16 rsvd;
+ __be32 snd_nxt;
+ __be32 snd_una;
+};
+
+struct cpl_rdma_ec_status {
+ RSS_HDR union opcode_tid ot;
+ __u8 rsvd[3];
+ __u8 status;
+};
+
+struct mngt_pktsched_wr {
+ __be32 wr_hi;
+ __be32 wr_lo;
+ __u8 mngt_opcode;
+ __u8 rsvd[7];
+ __u8 sched;
+ __u8 idx;
+ __u8 min;
+ __u8 max;
+ __u8 binding;
+ __u8 rsvd1[3];
+};
+
+struct cpl_iscsi_hdr {
+ RSS_HDR union opcode_tid ot;
+ __be16 pdu_len_ddp;
+ __be16 len;
+ __be32 seq;
+ __be16 urg;
+ __u8 rsvd;
+ __u8 status;
+};
+
+/* cpl_iscsi_hdr.pdu_len_ddp fields */
+#define S_ISCSI_PDU_LEN 0
+#define M_ISCSI_PDU_LEN 0x7FFF
+#define V_ISCSI_PDU_LEN(x) ((x) << S_ISCSI_PDU_LEN)
+#define G_ISCSI_PDU_LEN(x) (((x) >> S_ISCSI_PDU_LEN) & M_ISCSI_PDU_LEN)
+
+#define S_ISCSI_DDP 15
+#define V_ISCSI_DDP(x) ((x) << S_ISCSI_DDP)
+#define F_ISCSI_DDP V_ISCSI_DDP(1U)
+
+struct cpl_rx_data {
+ RSS_HDR union opcode_tid ot;
+ __be16 rsvd;
+ __be16 len;
+ __be32 seq;
+ __be16 urg;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 dack_mode:2;
+ __u8 psh:1;
+ __u8 heartbeat:1;
+ __u8:4;
+#else
+ __u8:4;
+ __u8 heartbeat:1;
+ __u8 psh:1;
+ __u8 dack_mode:2;
+#endif
+ __u8 status;
+};
+
+struct cpl_rx_data_ack {
+ WR_HDR;
+ union opcode_tid ot;
+ __be32 credit_dack;
+};
+
+/* cpl_rx_data_ack.ack_seq fields */
+#define S_RX_CREDITS 0
+#define M_RX_CREDITS 0x7FFFFFF
+#define V_RX_CREDITS(x) ((x) << S_RX_CREDITS)
+#define G_RX_CREDITS(x) (((x) >> S_RX_CREDITS) & M_RX_CREDITS)
+
+#define S_RX_MODULATE 27
+#define V_RX_MODULATE(x) ((x) << S_RX_MODULATE)
+#define F_RX_MODULATE V_RX_MODULATE(1U)
+
+#define S_RX_FORCE_ACK 28
+#define V_RX_FORCE_ACK(x) ((x) << S_RX_FORCE_ACK)
+#define F_RX_FORCE_ACK V_RX_FORCE_ACK(1U)
+
+#define S_RX_DACK_MODE 29
+#define M_RX_DACK_MODE 0x3
+#define V_RX_DACK_MODE(x) ((x) << S_RX_DACK_MODE)
+#define G_RX_DACK_MODE(x) (((x) >> S_RX_DACK_MODE) & M_RX_DACK_MODE)
+
+#define S_RX_DACK_CHANGE 31
+#define V_RX_DACK_CHANGE(x) ((x) << S_RX_DACK_CHANGE)
+#define F_RX_DACK_CHANGE V_RX_DACK_CHANGE(1U)
+
+struct cpl_rx_urg_notify {
+ RSS_HDR union opcode_tid ot;
+ __be32 seq;
+};
+
+struct cpl_rx_ddp_complete {
+ RSS_HDR union opcode_tid ot;
+ __be32 ddp_report;
+};
+
+struct cpl_rx_data_ddp {
+ RSS_HDR union opcode_tid ot;
+ __be16 urg;
+ __be16 len;
+ __be32 seq;
+ union {
+ __be32 nxt_seq;
+ __be32 ddp_report;
+ };
+ __be32 ulp_crc;
+ __be32 ddpvld_status;
+};
+
+/* cpl_rx_data_ddp.ddpvld_status fields */
+#define S_DDP_STATUS 0
+#define M_DDP_STATUS 0xFF
+#define V_DDP_STATUS(x) ((x) << S_DDP_STATUS)
+#define G_DDP_STATUS(x) (((x) >> S_DDP_STATUS) & M_DDP_STATUS)
+
+#define S_DDP_VALID 15
+#define M_DDP_VALID 0x1FFFF
+#define V_DDP_VALID(x) ((x) << S_DDP_VALID)
+#define G_DDP_VALID(x) (((x) >> S_DDP_VALID) & M_DDP_VALID)
+
+#define S_DDP_PPOD_MISMATCH 15
+#define V_DDP_PPOD_MISMATCH(x) ((x) << S_DDP_PPOD_MISMATCH)
+#define F_DDP_PPOD_MISMATCH V_DDP_PPOD_MISMATCH(1U)
+
+#define S_DDP_PDU 16
+#define V_DDP_PDU(x) ((x) << S_DDP_PDU)
+#define F_DDP_PDU V_DDP_PDU(1U)
+
+#define S_DDP_LLIMIT_ERR 17
+#define V_DDP_LLIMIT_ERR(x) ((x) << S_DDP_LLIMIT_ERR)
+#define F_DDP_LLIMIT_ERR V_DDP_LLIMIT_ERR(1U)
+
+#define S_DDP_PPOD_PARITY_ERR 18
+#define V_DDP_PPOD_PARITY_ERR(x) ((x) << S_DDP_PPOD_PARITY_ERR)
+#define F_DDP_PPOD_PARITY_ERR V_DDP_PPOD_PARITY_ERR(1U)
+
+#define S_DDP_PADDING_ERR 19
+#define V_DDP_PADDING_ERR(x) ((x) << S_DDP_PADDING_ERR)
+#define F_DDP_PADDING_ERR V_DDP_PADDING_ERR(1U)
+
+#define S_DDP_HDRCRC_ERR 20
+#define V_DDP_HDRCRC_ERR(x) ((x) << S_DDP_HDRCRC_ERR)
+#define F_DDP_HDRCRC_ERR V_DDP_HDRCRC_ERR(1U)
+
+#define S_DDP_DATACRC_ERR 21
+#define V_DDP_DATACRC_ERR(x) ((x) << S_DDP_DATACRC_ERR)
+#define F_DDP_DATACRC_ERR V_DDP_DATACRC_ERR(1U)
+
+#define S_DDP_INVALID_TAG 22
+#define V_DDP_INVALID_TAG(x) ((x) << S_DDP_INVALID_TAG)
+#define F_DDP_INVALID_TAG V_DDP_INVALID_TAG(1U)
+
+#define S_DDP_ULIMIT_ERR 23
+#define V_DDP_ULIMIT_ERR(x) ((x) << S_DDP_ULIMIT_ERR)
+#define F_DDP_ULIMIT_ERR V_DDP_ULIMIT_ERR(1U)
+
+#define S_DDP_OFFSET_ERR 24
+#define V_DDP_OFFSET_ERR(x) ((x) << S_DDP_OFFSET_ERR)
+#define F_DDP_OFFSET_ERR V_DDP_OFFSET_ERR(1U)
+
+#define S_DDP_COLOR_ERR 25
+#define V_DDP_COLOR_ERR(x) ((x) << S_DDP_COLOR_ERR)
+#define F_DDP_COLOR_ERR V_DDP_COLOR_ERR(1U)
+
+#define S_DDP_TID_MISMATCH 26
+#define V_DDP_TID_MISMATCH(x) ((x) << S_DDP_TID_MISMATCH)
+#define F_DDP_TID_MISMATCH V_DDP_TID_MISMATCH(1U)
+
+#define S_DDP_INVALID_PPOD 27
+#define V_DDP_INVALID_PPOD(x) ((x) << S_DDP_INVALID_PPOD)
+#define F_DDP_INVALID_PPOD V_DDP_INVALID_PPOD(1U)
+
+#define S_DDP_ULP_MODE 28
+#define M_DDP_ULP_MODE 0xF
+#define V_DDP_ULP_MODE(x) ((x) << S_DDP_ULP_MODE)
+#define G_DDP_ULP_MODE(x) (((x) >> S_DDP_ULP_MODE) & M_DDP_ULP_MODE)
+
+/* cpl_rx_data_ddp.ddp_report fields */
+#define S_DDP_OFFSET 0
+#define M_DDP_OFFSET 0x3FFFFF
+#define V_DDP_OFFSET(x) ((x) << S_DDP_OFFSET)
+#define G_DDP_OFFSET(x) (((x) >> S_DDP_OFFSET) & M_DDP_OFFSET)
+
+#define S_DDP_URG 24
+#define V_DDP_URG(x) ((x) << S_DDP_URG)
+#define F_DDP_URG V_DDP_URG(1U)
+
+#define S_DDP_PSH 25
+#define V_DDP_PSH(x) ((x) << S_DDP_PSH)
+#define F_DDP_PSH V_DDP_PSH(1U)
+
+#define S_DDP_BUF_COMPLETE 26
+#define V_DDP_BUF_COMPLETE(x) ((x) << S_DDP_BUF_COMPLETE)
+#define F_DDP_BUF_COMPLETE V_DDP_BUF_COMPLETE(1U)
+
+#define S_DDP_BUF_TIMED_OUT 27
+#define V_DDP_BUF_TIMED_OUT(x) ((x) << S_DDP_BUF_TIMED_OUT)
+#define F_DDP_BUF_TIMED_OUT V_DDP_BUF_TIMED_OUT(1U)
+
+#define S_DDP_BUF_IDX 28
+#define V_DDP_BUF_IDX(x) ((x) << S_DDP_BUF_IDX)
+#define F_DDP_BUF_IDX V_DDP_BUF_IDX(1U)
+
+struct cpl_tx_pkt {
+ WR_HDR;
+ __be32 cntrl;
+ __be32 len;
+};
+
+struct cpl_tx_pkt_lso {
+ WR_HDR;
+ __be32 cntrl;
+ __be32 len;
+
+ __be32 rsvd;
+ __be32 lso_info;
+};
+
+/* cpl_tx_pkt*.cntrl fields */
+#define S_TXPKT_VLAN 0
+#define M_TXPKT_VLAN 0xFFFF
+#define V_TXPKT_VLAN(x) ((x) << S_TXPKT_VLAN)
+#define G_TXPKT_VLAN(x) (((x) >> S_TXPKT_VLAN) & M_TXPKT_VLAN)
+
+#define S_TXPKT_INTF 16
+#define M_TXPKT_INTF 0xF
+#define V_TXPKT_INTF(x) ((x) << S_TXPKT_INTF)
+#define G_TXPKT_INTF(x) (((x) >> S_TXPKT_INTF) & M_TXPKT_INTF)
+
+#define S_TXPKT_IPCSUM_DIS 20
+#define V_TXPKT_IPCSUM_DIS(x) ((x) << S_TXPKT_IPCSUM_DIS)
+#define F_TXPKT_IPCSUM_DIS V_TXPKT_IPCSUM_DIS(1U)
+
+#define S_TXPKT_L4CSUM_DIS 21
+#define V_TXPKT_L4CSUM_DIS(x) ((x) << S_TXPKT_L4CSUM_DIS)
+#define F_TXPKT_L4CSUM_DIS V_TXPKT_L4CSUM_DIS(1U)
+
+#define S_TXPKT_VLAN_VLD 22
+#define V_TXPKT_VLAN_VLD(x) ((x) << S_TXPKT_VLAN_VLD)
+#define F_TXPKT_VLAN_VLD V_TXPKT_VLAN_VLD(1U)
+
+#define S_TXPKT_LOOPBACK 23
+#define V_TXPKT_LOOPBACK(x) ((x) << S_TXPKT_LOOPBACK)
+#define F_TXPKT_LOOPBACK V_TXPKT_LOOPBACK(1U)
+
+#define S_TXPKT_OPCODE 24
+#define M_TXPKT_OPCODE 0xFF
+#define V_TXPKT_OPCODE(x) ((x) << S_TXPKT_OPCODE)
+#define G_TXPKT_OPCODE(x) (((x) >> S_TXPKT_OPCODE) & M_TXPKT_OPCODE)
+
+/* cpl_tx_pkt_lso.lso_info fields */
+#define S_LSO_MSS 0
+#define M_LSO_MSS 0x3FFF
+#define V_LSO_MSS(x) ((x) << S_LSO_MSS)
+#define G_LSO_MSS(x) (((x) >> S_LSO_MSS) & M_LSO_MSS)
+
+#define S_LSO_ETH_TYPE 14
+#define M_LSO_ETH_TYPE 0x3
+#define V_LSO_ETH_TYPE(x) ((x) << S_LSO_ETH_TYPE)
+#define G_LSO_ETH_TYPE(x) (((x) >> S_LSO_ETH_TYPE) & M_LSO_ETH_TYPE)
+
+#define S_LSO_TCPHDR_WORDS 16
+#define M_LSO_TCPHDR_WORDS 0xF
+#define V_LSO_TCPHDR_WORDS(x) ((x) << S_LSO_TCPHDR_WORDS)
+#define G_LSO_TCPHDR_WORDS(x) (((x) >> S_LSO_TCPHDR_WORDS) & M_LSO_TCPHDR_WORDS)
+
+#define S_LSO_IPHDR_WORDS 20
+#define M_LSO_IPHDR_WORDS 0xF
+#define V_LSO_IPHDR_WORDS(x) ((x) << S_LSO_IPHDR_WORDS)
+#define G_LSO_IPHDR_WORDS(x) (((x) >> S_LSO_IPHDR_WORDS) & M_LSO_IPHDR_WORDS)
+
+#define S_LSO_IPV6 24
+#define V_LSO_IPV6(x) ((x) << S_LSO_IPV6)
+#define F_LSO_IPV6 V_LSO_IPV6(1U)
+
+struct cpl_trace_pkt {
+#ifdef CHELSIO_FW
+ __u8 rss_opcode;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 err:1;
+ __u8:7;
+#else
+ __u8:7;
+ __u8 err:1;
+#endif
+ __u8 rsvd0;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 qid:4;
+ __u8:4;
+#else
+ __u8:4;
+ __u8 qid:4;
+#endif
+ __be32 tstamp;
+#endif /* CHELSIO_FW */
+
+ __u8 opcode;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 iff:4;
+ __u8:4;
+#else
+ __u8:4;
+ __u8 iff:4;
+#endif
+ __u8 rsvd[4];
+ __be16 len;
+};
+
+struct cpl_rx_pkt {
+ RSS_HDR __u8 opcode;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 iff:4;
+ __u8 csum_valid:1;
+ __u8 ipmi_pkt:1;
+ __u8 vlan_valid:1;
+ __u8 fragment:1;
+#else
+ __u8 fragment:1;
+ __u8 vlan_valid:1;
+ __u8 ipmi_pkt:1;
+ __u8 csum_valid:1;
+ __u8 iff:4;
+#endif
+ __be16 csum;
+ __be16 vlan;
+ __be16 len;
+};
+
+struct cpl_l2t_write_req {
+ WR_HDR;
+ union opcode_tid ot;
+ __be32 params;
+ __u8 rsvd[2];
+ __u8 dst_mac[6];
+};
+
+/* cpl_l2t_write_req.params fields */
+#define S_L2T_W_IDX 0
+#define M_L2T_W_IDX 0x7FF
+#define V_L2T_W_IDX(x) ((x) << S_L2T_W_IDX)
+#define G_L2T_W_IDX(x) (((x) >> S_L2T_W_IDX) & M_L2T_W_IDX)
+
+#define S_L2T_W_VLAN 11
+#define M_L2T_W_VLAN 0xFFF
+#define V_L2T_W_VLAN(x) ((x) << S_L2T_W_VLAN)
+#define G_L2T_W_VLAN(x) (((x) >> S_L2T_W_VLAN) & M_L2T_W_VLAN)
+
+#define S_L2T_W_IFF 23
+#define M_L2T_W_IFF 0xF
+#define V_L2T_W_IFF(x) ((x) << S_L2T_W_IFF)
+#define G_L2T_W_IFF(x) (((x) >> S_L2T_W_IFF) & M_L2T_W_IFF)
+
+#define S_L2T_W_PRIO 27
+#define M_L2T_W_PRIO 0x7
+#define V_L2T_W_PRIO(x) ((x) << S_L2T_W_PRIO)
+#define G_L2T_W_PRIO(x) (((x) >> S_L2T_W_PRIO) & M_L2T_W_PRIO)
+
+struct cpl_l2t_write_rpl {
+ RSS_HDR union opcode_tid ot;
+ __u8 status;
+ __u8 rsvd[3];
+};
+
+struct cpl_l2t_read_req {
+ WR_HDR;
+ union opcode_tid ot;
+ __be16 rsvd;
+ __be16 l2t_idx;
+};
+
+struct cpl_l2t_read_rpl {
+ RSS_HDR union opcode_tid ot;
+ __be32 params;
+ __u8 rsvd[2];
+ __u8 dst_mac[6];
+};
+
+/* cpl_l2t_read_rpl.params fields */
+#define S_L2T_R_PRIO 0
+#define M_L2T_R_PRIO 0x7
+#define V_L2T_R_PRIO(x) ((x) << S_L2T_R_PRIO)
+#define G_L2T_R_PRIO(x) (((x) >> S_L2T_R_PRIO) & M_L2T_R_PRIO)
+
+#define S_L2T_R_VLAN 8
+#define M_L2T_R_VLAN 0xFFF
+#define V_L2T_R_VLAN(x) ((x) << S_L2T_R_VLAN)
+#define G_L2T_R_VLAN(x) (((x) >> S_L2T_R_VLAN) & M_L2T_R_VLAN)
+
+#define S_L2T_R_IFF 20
+#define M_L2T_R_IFF 0xF
+#define V_L2T_R_IFF(x) ((x) << S_L2T_R_IFF)
+#define G_L2T_R_IFF(x) (((x) >> S_L2T_R_IFF) & M_L2T_R_IFF)
+
+#define S_L2T_STATUS 24
+#define M_L2T_STATUS 0xFF
+#define V_L2T_STATUS(x) ((x) << S_L2T_STATUS)
+#define G_L2T_STATUS(x) (((x) >> S_L2T_STATUS) & M_L2T_STATUS)
+
+struct cpl_smt_write_req {
+ WR_HDR;
+ union opcode_tid ot;
+ __u8 rsvd0;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 mtu_idx:4;
+ __u8 iff:4;
+#else
+ __u8 iff:4;
+ __u8 mtu_idx:4;
+#endif
+ __be16 rsvd2;
+ __be16 rsvd3;
+ __u8 src_mac1[6];
+ __be16 rsvd4;
+ __u8 src_mac0[6];
+};
+
+struct cpl_smt_write_rpl {
+ RSS_HDR union opcode_tid ot;
+ __u8 status;
+ __u8 rsvd[3];
+};
+
+struct cpl_smt_read_req {
+ WR_HDR;
+ union opcode_tid ot;
+ __u8 rsvd0;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8:4;
+ __u8 iff:4;
+#else
+ __u8 iff:4;
+ __u8:4;
+#endif
+ __be16 rsvd2;
+};
+
+struct cpl_smt_read_rpl {
+ RSS_HDR union opcode_tid ot;
+ __u8 status;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 mtu_idx:4;
+ __u8:4;
+#else
+ __u8:4;
+ __u8 mtu_idx:4;
+#endif
+ __be16 rsvd2;
+ __be16 rsvd3;
+ __u8 src_mac1[6];
+ __be16 rsvd4;
+ __u8 src_mac0[6];
+};
+
+struct cpl_rte_delete_req {
+ WR_HDR;
+ union opcode_tid ot;
+ __be32 params;
+};
+
+/* { cpl_rte_delete_req, cpl_rte_read_req }.params fields */
+#define S_RTE_REQ_LUT_IX 8
+#define M_RTE_REQ_LUT_IX 0x7FF
+#define V_RTE_REQ_LUT_IX(x) ((x) << S_RTE_REQ_LUT_IX)
+#define G_RTE_REQ_LUT_IX(x) (((x) >> S_RTE_REQ_LUT_IX) & M_RTE_REQ_LUT_IX)
+
+#define S_RTE_REQ_LUT_BASE 19
+#define M_RTE_REQ_LUT_BASE 0x7FF
+#define V_RTE_REQ_LUT_BASE(x) ((x) << S_RTE_REQ_LUT_BASE)
+#define G_RTE_REQ_LUT_BASE(x) (((x) >> S_RTE_REQ_LUT_BASE) & M_RTE_REQ_LUT_BASE)
+
+#define S_RTE_READ_REQ_SELECT 31
+#define V_RTE_READ_REQ_SELECT(x) ((x) << S_RTE_READ_REQ_SELECT)
+#define F_RTE_READ_REQ_SELECT V_RTE_READ_REQ_SELECT(1U)
+
+struct cpl_rte_delete_rpl {
+ RSS_HDR union opcode_tid ot;
+ __u8 status;
+ __u8 rsvd[3];
+};
+
+struct cpl_rte_write_req {
+ WR_HDR;
+ union opcode_tid ot;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8:6;
+ __u8 write_tcam:1;
+ __u8 write_l2t_lut:1;
+#else
+ __u8 write_l2t_lut:1;
+ __u8 write_tcam:1;
+ __u8:6;
+#endif
+ __u8 rsvd[3];
+ __be32 lut_params;
+ __be16 rsvd2;
+ __be16 l2t_idx;
+ __be32 netmask;
+ __be32 faddr;
+};
+
+/* cpl_rte_write_req.lut_params fields */
+#define S_RTE_WRITE_REQ_LUT_IX 10
+#define M_RTE_WRITE_REQ_LUT_IX 0x7FF
+#define V_RTE_WRITE_REQ_LUT_IX(x) ((x) << S_RTE_WRITE_REQ_LUT_IX)
+#define G_RTE_WRITE_REQ_LUT_IX(x) (((x) >> S_RTE_WRITE_REQ_LUT_IX) & M_RTE_WRITE_REQ_LUT_IX)
+
+#define S_RTE_WRITE_REQ_LUT_BASE 21
+#define M_RTE_WRITE_REQ_LUT_BASE 0x7FF
+#define V_RTE_WRITE_REQ_LUT_BASE(x) ((x) << S_RTE_WRITE_REQ_LUT_BASE)
+#define G_RTE_WRITE_REQ_LUT_BASE(x) (((x) >> S_RTE_WRITE_REQ_LUT_BASE) & M_RTE_WRITE_REQ_LUT_BASE)
+
+struct cpl_rte_write_rpl {
+ RSS_HDR union opcode_tid ot;
+ __u8 status;
+ __u8 rsvd[3];
+};
+
+struct cpl_rte_read_req {
+ WR_HDR;
+ union opcode_tid ot;
+ __be32 params;
+};
+
+struct cpl_rte_read_rpl {
+ RSS_HDR union opcode_tid ot;
+ __u8 status;
+ __u8 rsvd0;
+ __be16 l2t_idx;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8:7;
+ __u8 select:1;
+#else
+ __u8 select:1;
+ __u8:7;
+#endif
+ __u8 rsvd2[3];
+ __be32 addr;
+};
+
+struct cpl_tid_release {
+ WR_HDR;
+ union opcode_tid ot;
+ __be32 rsvd;
+};
+
+struct cpl_barrier {
+ WR_HDR;
+ __u8 opcode;
+ __u8 rsvd[7];
+};
+
+struct cpl_rdma_read_req {
+ __u8 opcode;
+ __u8 rsvd[15];
+};
+
+struct cpl_rdma_terminate {
+#ifdef CHELSIO_FW
+ __u8 opcode;
+ __u8 rsvd[2];
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 rspq:3;
+ __u8:5;
+#else
+ __u8:5;
+ __u8 rspq:3;
+#endif
+ __be32 tid_len;
+#endif
+ __be32 msn;
+ __be32 mo;
+ __u8 data[0];
+};
+
+/* cpl_rdma_terminate.tid_len fields */
+#define S_FLIT_CNT 0
+#define M_FLIT_CNT 0xFF
+#define V_FLIT_CNT(x) ((x) << S_FLIT_CNT)
+#define G_FLIT_CNT(x) (((x) >> S_FLIT_CNT) & M_FLIT_CNT)
+
+#define S_TERM_TID 8
+#define M_TERM_TID 0xFFFFF
+#define V_TERM_TID(x) ((x) << S_TERM_TID)
+#define G_TERM_TID(x) (((x) >> S_TERM_TID) & M_TERM_TID)
+#endif /* T3_CPL_H */
diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c
new file mode 100644
index 00000000000..365a7f5b1f9
--- /dev/null
+++ b/drivers/net/cxgb3/t3_hw.c
@@ -0,0 +1,3375 @@
+/*
+ * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include "common.h"
+#include "regs.h"
+#include "sge_defs.h"
+#include "firmware_exports.h"
+
+/**
+ * t3_wait_op_done_val - wait until an operation is completed
+ * @adapter: the adapter performing the operation
+ * @reg: the register to check for completion
+ * @mask: a single-bit field within @reg that indicates completion
+ * @polarity: the value of the field when the operation is completed
+ * @attempts: number of check iterations
+ * @delay: delay in usecs between iterations
+ * @valp: where to store the value of the register at completion time
+ *
+ * Wait until an operation is completed by checking a bit in a register
+ * up to @attempts times. If @valp is not NULL the value of the register
+ * at the time it indicated completion is stored there. Returns 0 if the
+ * operation completes and -EAGAIN otherwise.
+ */
+
+int t3_wait_op_done_val(struct adapter *adapter, int reg, u32 mask,
+ int polarity, int attempts, int delay, u32 *valp)
+{
+ while (1) {
+ u32 val = t3_read_reg(adapter, reg);
+
+ if (!!(val & mask) == polarity) {
+ if (valp)
+ *valp = val;
+ return 0;
+ }
+ if (--attempts == 0)
+ return -EAGAIN;
+ if (delay)
+ udelay(delay);
+ }
+}
+
+/**
+ * t3_write_regs - write a bunch of registers
+ * @adapter: the adapter to program
+ * @p: an array of register address/register value pairs
+ * @n: the number of address/value pairs
+ * @offset: register address offset
+ *
+ * Takes an array of register address/register value pairs and writes each
+ * value to the corresponding register. Register addresses are adjusted
+ * by the supplied offset.
+ */
+void t3_write_regs(struct adapter *adapter, const struct addr_val_pair *p,
+ int n, unsigned int offset)
+{
+ while (n--) {
+ t3_write_reg(adapter, p->reg_addr + offset, p->val);
+ p++;
+ }
+}
+
+/**
+ * t3_set_reg_field - set a register field to a value
+ * @adapter: the adapter to program
+ * @addr: the register address
+ * @mask: specifies the portion of the register to modify
+ * @val: the new value for the register field
+ *
+ * Sets a register field specified by the supplied mask to the
+ * given value.
+ */
+void t3_set_reg_field(struct adapter *adapter, unsigned int addr, u32 mask,
+ u32 val)
+{
+ u32 v = t3_read_reg(adapter, addr) & ~mask;
+
+ t3_write_reg(adapter, addr, v | val);
+ t3_read_reg(adapter, addr); /* flush */
+}
+
+/**
+ * t3_read_indirect - read indirectly addressed registers
+ * @adap: the adapter
+ * @addr_reg: register holding the indirect address
+ * @data_reg: register holding the value of the indirect register
+ * @vals: where the read register values are stored
+ * @start_idx: index of first indirect register to read
+ * @nregs: how many indirect registers to read
+ *
+ * Reads registers that are accessed indirectly through an address/data
+ * register pair.
+ */
+void t3_read_indirect(struct adapter *adap, unsigned int addr_reg,
+ unsigned int data_reg, u32 *vals, unsigned int nregs,
+ unsigned int start_idx)
+{
+ while (nregs--) {
+ t3_write_reg(adap, addr_reg, start_idx);
+ *vals++ = t3_read_reg(adap, data_reg);
+ start_idx++;
+ }
+}
+
+/**
+ * t3_mc7_bd_read - read from MC7 through backdoor accesses
+ * @mc7: identifies MC7 to read from
+ * @start: index of first 64-bit word to read
+ * @n: number of 64-bit words to read
+ * @buf: where to store the read result
+ *
+ * Read n 64-bit words from MC7 starting at word start, using backdoor
+ * accesses.
+ */
+int t3_mc7_bd_read(struct mc7 *mc7, unsigned int start, unsigned int n,
+ u64 *buf)
+{
+ static const int shift[] = { 0, 0, 16, 24 };
+ static const int step[] = { 0, 32, 16, 8 };
+
+ unsigned int size64 = mc7->size / 8; /* # of 64-bit words */
+ struct adapter *adap = mc7->adapter;
+
+ if (start >= size64 || start + n > size64)
+ return -EINVAL;
+
+ start *= (8 << mc7->width);
+ while (n--) {
+ int i;
+ u64 val64 = 0;
+
+ for (i = (1 << mc7->width) - 1; i >= 0; --i) {
+ int attempts = 10;
+ u32 val;
+
+ t3_write_reg(adap, mc7->offset + A_MC7_BD_ADDR, start);
+ t3_write_reg(adap, mc7->offset + A_MC7_BD_OP, 0);
+ val = t3_read_reg(adap, mc7->offset + A_MC7_BD_OP);
+ while ((val & F_BUSY) && attempts--)
+ val = t3_read_reg(adap,
+ mc7->offset + A_MC7_BD_OP);
+ if (val & F_BUSY)
+ return -EIO;
+
+ val = t3_read_reg(adap, mc7->offset + A_MC7_BD_DATA1);
+ if (mc7->width == 0) {
+ val64 = t3_read_reg(adap,
+ mc7->offset +
+ A_MC7_BD_DATA0);
+ val64 |= (u64) val << 32;
+ } else {
+ if (mc7->width > 1)
+ val >>= shift[mc7->width];
+ val64 |= (u64) val << (step[mc7->width] * i);
+ }
+ start += 8;
+ }
+ *buf++ = val64;
+ }
+ return 0;
+}
+
+/*
+ * Initialize MI1.
+ */
+static void mi1_init(struct adapter *adap, const struct adapter_info *ai)
+{
+ u32 clkdiv = adap->params.vpd.cclk / (2 * adap->params.vpd.mdc) - 1;
+ u32 val = F_PREEN | V_MDIINV(ai->mdiinv) | V_MDIEN(ai->mdien) |
+ V_CLKDIV(clkdiv);
+
+ if (!(ai->caps & SUPPORTED_10000baseT_Full))
+ val |= V_ST(1);
+ t3_write_reg(adap, A_MI1_CFG, val);
+}
+
+#define MDIO_ATTEMPTS 10
+
+/*
+ * MI1 read/write operations for direct-addressed PHYs.
+ */
+static int mi1_read(struct adapter *adapter, int phy_addr, int mmd_addr,
+ int reg_addr, unsigned int *valp)
+{
+ int ret;
+ u32 addr = V_REGADDR(reg_addr) | V_PHYADDR(phy_addr);
+
+ if (mmd_addr)
+ return -EINVAL;
+
+ mutex_lock(&adapter->mdio_lock);
+ t3_write_reg(adapter, A_MI1_ADDR, addr);
+ t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(2));
+ ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 20);
+ if (!ret)
+ *valp = t3_read_reg(adapter, A_MI1_DATA);
+ mutex_unlock(&adapter->mdio_lock);
+ return ret;
+}
+
+static int mi1_write(struct adapter *adapter, int phy_addr, int mmd_addr,
+ int reg_addr, unsigned int val)
+{
+ int ret;
+ u32 addr = V_REGADDR(reg_addr) | V_PHYADDR(phy_addr);
+
+ if (mmd_addr)
+ return -EINVAL;
+
+ mutex_lock(&adapter->mdio_lock);
+ t3_write_reg(adapter, A_MI1_ADDR, addr);
+ t3_write_reg(adapter, A_MI1_DATA, val);
+ t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(1));
+ ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 20);
+ mutex_unlock(&adapter->mdio_lock);
+ return ret;
+}
+
+static const struct mdio_ops mi1_mdio_ops = {
+ mi1_read,
+ mi1_write
+};
+
+/*
+ * MI1 read/write operations for indirect-addressed PHYs.
+ */
+static int mi1_ext_read(struct adapter *adapter, int phy_addr, int mmd_addr,
+ int reg_addr, unsigned int *valp)
+{
+ int ret;
+ u32 addr = V_REGADDR(mmd_addr) | V_PHYADDR(phy_addr);
+
+ mutex_lock(&adapter->mdio_lock);
+ t3_write_reg(adapter, A_MI1_ADDR, addr);
+ t3_write_reg(adapter, A_MI1_DATA, reg_addr);
+ t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(0));
+ ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 20);
+ if (!ret) {
+ t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(3));
+ ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0,
+ MDIO_ATTEMPTS, 20);
+ if (!ret)
+ *valp = t3_read_reg(adapter, A_MI1_DATA);
+ }
+ mutex_unlock(&adapter->mdio_lock);
+ return ret;
+}
+
+static int mi1_ext_write(struct adapter *adapter, int phy_addr, int mmd_addr,
+ int reg_addr, unsigned int val)
+{
+ int ret;
+ u32 addr = V_REGADDR(mmd_addr) | V_PHYADDR(phy_addr);
+
+ mutex_lock(&adapter->mdio_lock);
+ t3_write_reg(adapter, A_MI1_ADDR, addr);
+ t3_write_reg(adapter, A_MI1_DATA, reg_addr);
+ t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(0));
+ ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 20);
+ if (!ret) {
+ t3_write_reg(adapter, A_MI1_DATA, val);
+ t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(1));
+ ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0,
+ MDIO_ATTEMPTS, 20);
+ }
+ mutex_unlock(&adapter->mdio_lock);
+ return ret;
+}
+
+static const struct mdio_ops mi1_mdio_ext_ops = {
+ mi1_ext_read,
+ mi1_ext_write
+};
+
+/**
+ * t3_mdio_change_bits - modify the value of a PHY register
+ * @phy: the PHY to operate on
+ * @mmd: the device address
+ * @reg: the register address
+ * @clear: what part of the register value to mask off
+ * @set: what part of the register value to set
+ *
+ * Changes the value of a PHY register by applying a mask to its current
+ * value and ORing the result with a new value.
+ */
+int t3_mdio_change_bits(struct cphy *phy, int mmd, int reg, unsigned int clear,
+ unsigned int set)
+{
+ int ret;
+ unsigned int val;
+
+ ret = mdio_read(phy, mmd, reg, &val);
+ if (!ret) {
+ val &= ~clear;
+ ret = mdio_write(phy, mmd, reg, val | set);
+ }
+ return ret;
+}
+
+/**
+ * t3_phy_reset - reset a PHY block
+ * @phy: the PHY to operate on
+ * @mmd: the device address of the PHY block to reset
+ * @wait: how long to wait for the reset to complete in 1ms increments
+ *
+ * Resets a PHY block and optionally waits for the reset to complete.
+ * @mmd should be 0 for 10/100/1000 PHYs and the device address to reset
+ * for 10G PHYs.
+ */
+int t3_phy_reset(struct cphy *phy, int mmd, int wait)
+{
+ int err;
+ unsigned int ctl;
+
+ err = t3_mdio_change_bits(phy, mmd, MII_BMCR, BMCR_PDOWN, BMCR_RESET);
+ if (err || !wait)
+ return err;
+
+ do {
+ err = mdio_read(phy, mmd, MII_BMCR, &ctl);
+ if (err)
+ return err;
+ ctl &= BMCR_RESET;
+ if (ctl)
+ msleep(1);
+ } while (ctl && --wait);
+
+ return ctl ? -1 : 0;
+}
+
+/**
+ * t3_phy_advertise - set the PHY advertisement registers for autoneg
+ * @phy: the PHY to operate on
+ * @advert: bitmap of capabilities the PHY should advertise
+ *
+ * Sets a 10/100/1000 PHY's advertisement registers to advertise the
+ * requested capabilities.
+ */
+int t3_phy_advertise(struct cphy *phy, unsigned int advert)
+{
+ int err;
+ unsigned int val = 0;
+
+ err = mdio_read(phy, 0, MII_CTRL1000, &val);
+ if (err)
+ return err;
+
+ val &= ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL);
+ if (advert & ADVERTISED_1000baseT_Half)
+ val |= ADVERTISE_1000HALF;
+ if (advert & ADVERTISED_1000baseT_Full)
+ val |= ADVERTISE_1000FULL;
+
+ err = mdio_write(phy, 0, MII_CTRL1000, val);
+ if (err)
+ return err;
+
+ val = 1;
+ if (advert & ADVERTISED_10baseT_Half)
+ val |= ADVERTISE_10HALF;
+ if (advert & ADVERTISED_10baseT_Full)
+ val |= ADVERTISE_10FULL;
+ if (advert & ADVERTISED_100baseT_Half)
+ val |= ADVERTISE_100HALF;
+ if (advert & ADVERTISED_100baseT_Full)
+ val |= ADVERTISE_100FULL;
+ if (advert & ADVERTISED_Pause)
+ val |= ADVERTISE_PAUSE_CAP;
+ if (advert & ADVERTISED_Asym_Pause)
+ val |= ADVERTISE_PAUSE_ASYM;
+ return mdio_write(phy, 0, MII_ADVERTISE, val);
+}
+
+/**
+ * t3_set_phy_speed_duplex - force PHY speed and duplex
+ * @phy: the PHY to operate on
+ * @speed: requested PHY speed
+ * @duplex: requested PHY duplex
+ *
+ * Force a 10/100/1000 PHY's speed and duplex. This also disables
+ * auto-negotiation except for GigE, where auto-negotiation is mandatory.
+ */
+int t3_set_phy_speed_duplex(struct cphy *phy, int speed, int duplex)
+{
+ int err;
+ unsigned int ctl;
+
+ err = mdio_read(phy, 0, MII_BMCR, &ctl);
+ if (err)
+ return err;
+
+ if (speed >= 0) {
+ ctl &= ~(BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE);
+ if (speed == SPEED_100)
+ ctl |= BMCR_SPEED100;
+ else if (speed == SPEED_1000)
+ ctl |= BMCR_SPEED1000;
+ }
+ if (duplex >= 0) {
+ ctl &= ~(BMCR_FULLDPLX | BMCR_ANENABLE);
+ if (duplex == DUPLEX_FULL)
+ ctl |= BMCR_FULLDPLX;
+ }
+ if (ctl & BMCR_SPEED1000) /* auto-negotiation required for GigE */
+ ctl |= BMCR_ANENABLE;
+ return mdio_write(phy, 0, MII_BMCR, ctl);
+}
+
+static const struct adapter_info t3_adap_info[] = {
+ {2, 0, 0, 0,
+ F_GPIO2_OEN | F_GPIO4_OEN |
+ F_GPIO2_OUT_VAL | F_GPIO4_OUT_VAL, F_GPIO3 | F_GPIO5,
+ SUPPORTED_OFFLOAD,
+ &mi1_mdio_ops, "Chelsio PE9000"},
+ {2, 0, 0, 0,
+ F_GPIO2_OEN | F_GPIO4_OEN |
+ F_GPIO2_OUT_VAL | F_GPIO4_OUT_VAL, F_GPIO3 | F_GPIO5,
+ SUPPORTED_OFFLOAD,
+ &mi1_mdio_ops, "Chelsio T302"},
+ {1, 0, 0, 0,
+ F_GPIO1_OEN | F_GPIO6_OEN | F_GPIO7_OEN | F_GPIO10_OEN |
+ F_GPIO1_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL, 0,
+ SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_OFFLOAD,
+ &mi1_mdio_ext_ops, "Chelsio T310"},
+ {2, 0, 0, 0,
+ F_GPIO1_OEN | F_GPIO2_OEN | F_GPIO4_OEN | F_GPIO5_OEN | F_GPIO6_OEN |
+ F_GPIO7_OEN | F_GPIO10_OEN | F_GPIO11_OEN | F_GPIO1_OUT_VAL |
+ F_GPIO5_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL, 0,
+ SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_OFFLOAD,
+ &mi1_mdio_ext_ops, "Chelsio T320"},
+};
+
+/*
+ * Return the adapter_info structure with a given index. Out-of-range indices
+ * return NULL.
+ */
+const struct adapter_info *t3_get_adapter_info(unsigned int id)
+{
+ return id < ARRAY_SIZE(t3_adap_info) ? &t3_adap_info[id] : NULL;
+}
+
+#define CAPS_1G (SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Full | \
+ SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | SUPPORTED_MII)
+#define CAPS_10G (SUPPORTED_10000baseT_Full | SUPPORTED_AUI)
+
+static const struct port_type_info port_types[] = {
+ {NULL},
+ {t3_ael1002_phy_prep, CAPS_10G | SUPPORTED_FIBRE,
+ "10GBASE-XR"},
+ {t3_vsc8211_phy_prep, CAPS_1G | SUPPORTED_TP | SUPPORTED_IRQ,
+ "10/100/1000BASE-T"},
+ {NULL, CAPS_1G | SUPPORTED_TP | SUPPORTED_IRQ,
+ "10/100/1000BASE-T"},
+ {t3_xaui_direct_phy_prep, CAPS_10G | SUPPORTED_TP, "10GBASE-CX4"},
+ {NULL, CAPS_10G, "10GBASE-KX4"},
+ {t3_qt2045_phy_prep, CAPS_10G | SUPPORTED_TP, "10GBASE-CX4"},
+ {t3_ael1006_phy_prep, CAPS_10G | SUPPORTED_FIBRE,
+ "10GBASE-SR"},
+ {NULL, CAPS_10G | SUPPORTED_TP, "10GBASE-CX4"},
+};
+
+#undef CAPS_1G
+#undef CAPS_10G
+
+#define VPD_ENTRY(name, len) \
+ u8 name##_kword[2]; u8 name##_len; u8 name##_data[len]
+
+/*
+ * Partial EEPROM Vital Product Data structure. Includes only the ID and
+ * VPD-R sections.
+ */
+struct t3_vpd {
+ u8 id_tag;
+ u8 id_len[2];
+ u8 id_data[16];
+ u8 vpdr_tag;
+ u8 vpdr_len[2];
+ VPD_ENTRY(pn, 16); /* part number */
+ VPD_ENTRY(ec, 16); /* EC level */
+ VPD_ENTRY(sn, 16); /* serial number */
+ VPD_ENTRY(na, 12); /* MAC address base */
+ VPD_ENTRY(cclk, 6); /* core clock */
+ VPD_ENTRY(mclk, 6); /* mem clock */
+ VPD_ENTRY(uclk, 6); /* uP clk */
+ VPD_ENTRY(mdc, 6); /* MDIO clk */
+ VPD_ENTRY(mt, 2); /* mem timing */
+ VPD_ENTRY(xaui0cfg, 6); /* XAUI0 config */
+ VPD_ENTRY(xaui1cfg, 6); /* XAUI1 config */
+ VPD_ENTRY(port0, 2); /* PHY0 complex */
+ VPD_ENTRY(port1, 2); /* PHY1 complex */
+ VPD_ENTRY(port2, 2); /* PHY2 complex */
+ VPD_ENTRY(port3, 2); /* PHY3 complex */
+ VPD_ENTRY(rv, 1); /* csum */
+ u32 pad; /* for multiple-of-4 sizing and alignment */
+};
+
+#define EEPROM_MAX_POLL 4
+#define EEPROM_STAT_ADDR 0x4000
+#define VPD_BASE 0xc00
+
+/**
+ * t3_seeprom_read - read a VPD EEPROM location
+ * @adapter: adapter to read
+ * @addr: EEPROM address
+ * @data: where to store the read data
+ *
+ * Read a 32-bit word from a location in VPD EEPROM using the card's PCI
+ * VPD ROM capability. A zero is written to the flag bit when the
+ * addres is written to the control register. The hardware device will
+ * set the flag to 1 when 4 bytes have been read into the data register.
+ */
+int t3_seeprom_read(struct adapter *adapter, u32 addr, u32 *data)
+{
+ u16 val;
+ int attempts = EEPROM_MAX_POLL;
+ unsigned int base = adapter->params.pci.vpd_cap_addr;
+
+ if ((addr >= EEPROMSIZE && addr != EEPROM_STAT_ADDR) || (addr & 3))
+ return -EINVAL;
+
+ pci_write_config_word(adapter->pdev, base + PCI_VPD_ADDR, addr);
+ do {
+ udelay(10);
+ pci_read_config_word(adapter->pdev, base + PCI_VPD_ADDR, &val);
+ } while (!(val & PCI_VPD_ADDR_F) && --attempts);
+
+ if (!(val & PCI_VPD_ADDR_F)) {
+ CH_ERR(adapter, "reading EEPROM address 0x%x failed\n", addr);
+ return -EIO;
+ }
+ pci_read_config_dword(adapter->pdev, base + PCI_VPD_DATA, data);
+ *data = le32_to_cpu(*data);
+ return 0;
+}
+
+/**
+ * t3_seeprom_write - write a VPD EEPROM location
+ * @adapter: adapter to write
+ * @addr: EEPROM address
+ * @data: value to write
+ *
+ * Write a 32-bit word to a location in VPD EEPROM using the card's PCI
+ * VPD ROM capability.
+ */
+int t3_seeprom_write(struct adapter *adapter, u32 addr, u32 data)
+{
+ u16 val;
+ int attempts = EEPROM_MAX_POLL;
+ unsigned int base = adapter->params.pci.vpd_cap_addr;
+
+ if ((addr >= EEPROMSIZE && addr != EEPROM_STAT_ADDR) || (addr & 3))
+ return -EINVAL;
+
+ pci_write_config_dword(adapter->pdev, base + PCI_VPD_DATA,
+ cpu_to_le32(data));
+ pci_write_config_word(adapter->pdev,base + PCI_VPD_ADDR,
+ addr | PCI_VPD_ADDR_F);
+ do {
+ msleep(1);
+ pci_read_config_word(adapter->pdev, base + PCI_VPD_ADDR, &val);
+ } while ((val & PCI_VPD_ADDR_F) && --attempts);
+
+ if (val & PCI_VPD_ADDR_F) {
+ CH_ERR(adapter, "write to EEPROM address 0x%x failed\n", addr);
+ return -EIO;
+ }
+ return 0;
+}
+
+/**
+ * t3_seeprom_wp - enable/disable EEPROM write protection
+ * @adapter: the adapter
+ * @enable: 1 to enable write protection, 0 to disable it
+ *
+ * Enables or disables write protection on the serial EEPROM.
+ */
+int t3_seeprom_wp(struct adapter *adapter, int enable)
+{
+ return t3_seeprom_write(adapter, EEPROM_STAT_ADDR, enable ? 0xc : 0);
+}
+
+/*
+ * Convert a character holding a hex digit to a number.
+ */
+static unsigned int hex2int(unsigned char c)
+{
+ return isdigit(c) ? c - '0' : toupper(c) - 'A' + 10;
+}
+
+/**
+ * get_vpd_params - read VPD parameters from VPD EEPROM
+ * @adapter: adapter to read
+ * @p: where to store the parameters
+ *
+ * Reads card parameters stored in VPD EEPROM.
+ */
+static int get_vpd_params(struct adapter *adapter, struct vpd_params *p)
+{
+ int i, addr, ret;
+ struct t3_vpd vpd;
+
+ /*
+ * Card information is normally at VPD_BASE but some early cards had
+ * it at 0.
+ */
+ ret = t3_seeprom_read(adapter, VPD_BASE, (u32 *)&vpd);
+ if (ret)
+ return ret;
+ addr = vpd.id_tag == 0x82 ? VPD_BASE : 0;
+
+ for (i = 0; i < sizeof(vpd); i += 4) {
+ ret = t3_seeprom_read(adapter, addr + i,
+ (u32 *)((u8 *)&vpd + i));
+ if (ret)
+ return ret;
+ }
+
+ p->cclk = simple_strtoul(vpd.cclk_data, NULL, 10);
+ p->mclk = simple_strtoul(vpd.mclk_data, NULL, 10);
+ p->uclk = simple_strtoul(vpd.uclk_data, NULL, 10);
+ p->mdc = simple_strtoul(vpd.mdc_data, NULL, 10);
+ p->mem_timing = simple_strtoul(vpd.mt_data, NULL, 10);
+
+ /* Old eeproms didn't have port information */
+ if (adapter->params.rev == 0 && !vpd.port0_data[0]) {
+ p->port_type[0] = uses_xaui(adapter) ? 1 : 2;
+ p->port_type[1] = uses_xaui(adapter) ? 6 : 2;
+ } else {
+ p->port_type[0] = hex2int(vpd.port0_data[0]);
+ p->port_type[1] = hex2int(vpd.port1_data[0]);
+ p->xauicfg[0] = simple_strtoul(vpd.xaui0cfg_data, NULL, 16);
+ p->xauicfg[1] = simple_strtoul(vpd.xaui1cfg_data, NULL, 16);
+ }
+
+ for (i = 0; i < 6; i++)
+ p->eth_base[i] = hex2int(vpd.na_data[2 * i]) * 16 +
+ hex2int(vpd.na_data[2 * i + 1]);
+ return 0;
+}
+
+/* serial flash and firmware constants */
+enum {
+ SF_ATTEMPTS = 5, /* max retries for SF1 operations */
+ SF_SEC_SIZE = 64 * 1024, /* serial flash sector size */
+ SF_SIZE = SF_SEC_SIZE * 8, /* serial flash size */
+
+ /* flash command opcodes */
+ SF_PROG_PAGE = 2, /* program page */
+ SF_WR_DISABLE = 4, /* disable writes */
+ SF_RD_STATUS = 5, /* read status register */
+ SF_WR_ENABLE = 6, /* enable writes */
+ SF_RD_DATA_FAST = 0xb, /* read flash */
+ SF_ERASE_SECTOR = 0xd8, /* erase sector */
+
+ FW_FLASH_BOOT_ADDR = 0x70000, /* start address of FW in flash */
+ FW_VERS_ADDR = 0x77ffc /* flash address holding FW version */
+};
+
+/**
+ * sf1_read - read data from the serial flash
+ * @adapter: the adapter
+ * @byte_cnt: number of bytes to read
+ * @cont: whether another operation will be chained
+ * @valp: where to store the read data
+ *
+ * Reads up to 4 bytes of data from the serial flash. The location of
+ * the read needs to be specified prior to calling this by issuing the
+ * appropriate commands to the serial flash.
+ */
+static int sf1_read(struct adapter *adapter, unsigned int byte_cnt, int cont,
+ u32 *valp)
+{
+ int ret;
+
+ if (!byte_cnt || byte_cnt > 4)
+ return -EINVAL;
+ if (t3_read_reg(adapter, A_SF_OP) & F_BUSY)
+ return -EBUSY;
+ t3_write_reg(adapter, A_SF_OP, V_CONT(cont) | V_BYTECNT(byte_cnt - 1));
+ ret = t3_wait_op_done(adapter, A_SF_OP, F_BUSY, 0, SF_ATTEMPTS, 10);
+ if (!ret)
+ *valp = t3_read_reg(adapter, A_SF_DATA);
+ return ret;
+}
+
+/**
+ * sf1_write - write data to the serial flash
+ * @adapter: the adapter
+ * @byte_cnt: number of bytes to write
+ * @cont: whether another operation will be chained
+ * @val: value to write
+ *
+ * Writes up to 4 bytes of data to the serial flash. The location of
+ * the write needs to be specified prior to calling this by issuing the
+ * appropriate commands to the serial flash.
+ */
+static int sf1_write(struct adapter *adapter, unsigned int byte_cnt, int cont,
+ u32 val)
+{
+ if (!byte_cnt || byte_cnt > 4)
+ return -EINVAL;
+ if (t3_read_reg(adapter, A_SF_OP) & F_BUSY)
+ return -EBUSY;
+ t3_write_reg(adapter, A_SF_DATA, val);
+ t3_write_reg(adapter, A_SF_OP,
+ V_CONT(cont) | V_BYTECNT(byte_cnt - 1) | V_OP(1));
+ return t3_wait_op_done(adapter, A_SF_OP, F_BUSY, 0, SF_ATTEMPTS, 10);
+}
+
+/**
+ * flash_wait_op - wait for a flash operation to complete
+ * @adapter: the adapter
+ * @attempts: max number of polls of the status register
+ * @delay: delay between polls in ms
+ *
+ * Wait for a flash operation to complete by polling the status register.
+ */
+static int flash_wait_op(struct adapter *adapter, int attempts, int delay)
+{
+ int ret;
+ u32 status;
+
+ while (1) {
+ if ((ret = sf1_write(adapter, 1, 1, SF_RD_STATUS)) != 0 ||
+ (ret = sf1_read(adapter, 1, 0, &status)) != 0)
+ return ret;
+ if (!(status & 1))
+ return 0;
+ if (--attempts == 0)
+ return -EAGAIN;
+ if (delay)
+ msleep(delay);
+ }
+}
+
+/**
+ * t3_read_flash - read words from serial flash
+ * @adapter: the adapter
+ * @addr: the start address for the read
+ * @nwords: how many 32-bit words to read
+ * @data: where to store the read data
+ * @byte_oriented: whether to store data as bytes or as words
+ *
+ * Read the specified number of 32-bit words from the serial flash.
+ * If @byte_oriented is set the read data is stored as a byte array
+ * (i.e., big-endian), otherwise as 32-bit words in the platform's
+ * natural endianess.
+ */
+int t3_read_flash(struct adapter *adapter, unsigned int addr,
+ unsigned int nwords, u32 *data, int byte_oriented)
+{
+ int ret;
+
+ if (addr + nwords * sizeof(u32) > SF_SIZE || (addr & 3))
+ return -EINVAL;
+
+ addr = swab32(addr) | SF_RD_DATA_FAST;
+
+ if ((ret = sf1_write(adapter, 4, 1, addr)) != 0 ||
+ (ret = sf1_read(adapter, 1, 1, data)) != 0)
+ return ret;
+
+ for (; nwords; nwords--, data++) {
+ ret = sf1_read(adapter, 4, nwords > 1, data);
+ if (ret)
+ return ret;
+ if (byte_oriented)
+ *data = htonl(*data);
+ }
+ return 0;
+}
+
+/**
+ * t3_write_flash - write up to a page of data to the serial flash
+ * @adapter: the adapter
+ * @addr: the start address to write
+ * @n: length of data to write
+ * @data: the data to write
+ *
+ * Writes up to a page of data (256 bytes) to the serial flash starting
+ * at the given address.
+ */
+static int t3_write_flash(struct adapter *adapter, unsigned int addr,
+ unsigned int n, const u8 *data)
+{
+ int ret;
+ u32 buf[64];
+ unsigned int i, c, left, val, offset = addr & 0xff;
+
+ if (addr + n > SF_SIZE || offset + n > 256)
+ return -EINVAL;
+
+ val = swab32(addr) | SF_PROG_PAGE;
+
+ if ((ret = sf1_write(adapter, 1, 0, SF_WR_ENABLE)) != 0 ||
+ (ret = sf1_write(adapter, 4, 1, val)) != 0)
+ return ret;
+
+ for (left = n; left; left -= c) {
+ c = min(left, 4U);
+ for (val = 0, i = 0; i < c; ++i)
+ val = (val << 8) + *data++;
+
+ ret = sf1_write(adapter, c, c != left, val);
+ if (ret)
+ return ret;
+ }
+ if ((ret = flash_wait_op(adapter, 5, 1)) != 0)
+ return ret;
+
+ /* Read the page to verify the write succeeded */
+ ret = t3_read_flash(adapter, addr & ~0xff, ARRAY_SIZE(buf), buf, 1);
+ if (ret)
+ return ret;
+
+ if (memcmp(data - n, (u8 *) buf + offset, n))
+ return -EIO;
+ return 0;
+}
+
+enum fw_version_type {
+ FW_VERSION_N3,
+ FW_VERSION_T3
+};
+
+/**
+ * t3_get_fw_version - read the firmware version
+ * @adapter: the adapter
+ * @vers: where to place the version
+ *
+ * Reads the FW version from flash.
+ */
+int t3_get_fw_version(struct adapter *adapter, u32 *vers)
+{
+ return t3_read_flash(adapter, FW_VERS_ADDR, 1, vers, 0);
+}
+
+/**
+ * t3_check_fw_version - check if the FW is compatible with this driver
+ * @adapter: the adapter
+ *
+ * Checks if an adapter's FW is compatible with the driver. Returns 0
+ * if the versions are compatible, a negative error otherwise.
+ */
+int t3_check_fw_version(struct adapter *adapter)
+{
+ int ret;
+ u32 vers;
+ unsigned int type, major, minor;
+
+ ret = t3_get_fw_version(adapter, &vers);
+ if (ret)
+ return ret;
+
+ type = G_FW_VERSION_TYPE(vers);
+ major = G_FW_VERSION_MAJOR(vers);
+ minor = G_FW_VERSION_MINOR(vers);
+
+ if (type == FW_VERSION_T3 && major == 3 && minor == 1)
+ return 0;
+
+ CH_ERR(adapter, "found wrong FW version(%u.%u), "
+ "driver needs version 3.1\n", major, minor);
+ return -EINVAL;
+}
+
+/**
+ * t3_flash_erase_sectors - erase a range of flash sectors
+ * @adapter: the adapter
+ * @start: the first sector to erase
+ * @end: the last sector to erase
+ *
+ * Erases the sectors in the given range.
+ */
+static int t3_flash_erase_sectors(struct adapter *adapter, int start, int end)
+{
+ while (start <= end) {
+ int ret;
+
+ if ((ret = sf1_write(adapter, 1, 0, SF_WR_ENABLE)) != 0 ||
+ (ret = sf1_write(adapter, 4, 0,
+ SF_ERASE_SECTOR | (start << 8))) != 0 ||
+ (ret = flash_wait_op(adapter, 5, 500)) != 0)
+ return ret;
+ start++;
+ }
+ return 0;
+}
+
+/*
+ * t3_load_fw - download firmware
+ * @adapter: the adapter
+ * @fw_data: the firrware image to write
+ * @size: image size
+ *
+ * Write the supplied firmware image to the card's serial flash.
+ * The FW image has the following sections: @size - 8 bytes of code and
+ * data, followed by 4 bytes of FW version, followed by the 32-bit
+ * 1's complement checksum of the whole image.
+ */
+int t3_load_fw(struct adapter *adapter, const u8 *fw_data, unsigned int size)
+{
+ u32 csum;
+ unsigned int i;
+ const u32 *p = (const u32 *)fw_data;
+ int ret, addr, fw_sector = FW_FLASH_BOOT_ADDR >> 16;
+
+ if (size & 3)
+ return -EINVAL;
+ if (size > FW_VERS_ADDR + 8 - FW_FLASH_BOOT_ADDR)
+ return -EFBIG;
+
+ for (csum = 0, i = 0; i < size / sizeof(csum); i++)
+ csum += ntohl(p[i]);
+ if (csum != 0xffffffff) {
+ CH_ERR(adapter, "corrupted firmware image, checksum %u\n",
+ csum);
+ return -EINVAL;
+ }
+
+ ret = t3_flash_erase_sectors(adapter, fw_sector, fw_sector);
+ if (ret)
+ goto out;
+
+ size -= 8; /* trim off version and checksum */
+ for (addr = FW_FLASH_BOOT_ADDR; size;) {
+ unsigned int chunk_size = min(size, 256U);
+
+ ret = t3_write_flash(adapter, addr, chunk_size, fw_data);
+ if (ret)
+ goto out;
+
+ addr += chunk_size;
+ fw_data += chunk_size;
+ size -= chunk_size;
+ }
+
+ ret = t3_write_flash(adapter, FW_VERS_ADDR, 4, fw_data);
+out:
+ if (ret)
+ CH_ERR(adapter, "firmware download failed, error %d\n", ret);
+ return ret;
+}
+
+#define CIM_CTL_BASE 0x2000
+
+/**
+ * t3_cim_ctl_blk_read - read a block from CIM control region
+ *
+ * @adap: the adapter
+ * @addr: the start address within the CIM control region
+ * @n: number of words to read
+ * @valp: where to store the result
+ *
+ * Reads a block of 4-byte words from the CIM control region.
+ */
+int t3_cim_ctl_blk_read(struct adapter *adap, unsigned int addr,
+ unsigned int n, unsigned int *valp)
+{
+ int ret = 0;
+
+ if (t3_read_reg(adap, A_CIM_HOST_ACC_CTRL) & F_HOSTBUSY)
+ return -EBUSY;
+
+ for ( ; !ret && n--; addr += 4) {
+ t3_write_reg(adap, A_CIM_HOST_ACC_CTRL, CIM_CTL_BASE + addr);
+ ret = t3_wait_op_done(adap, A_CIM_HOST_ACC_CTRL, F_HOSTBUSY,
+ 0, 5, 2);
+ if (!ret)
+ *valp++ = t3_read_reg(adap, A_CIM_HOST_ACC_DATA);
+ }
+ return ret;
+}
+
+
+/**
+ * t3_link_changed - handle interface link changes
+ * @adapter: the adapter
+ * @port_id: the port index that changed link state
+ *
+ * Called when a port's link settings change to propagate the new values
+ * to the associated PHY and MAC. After performing the common tasks it
+ * invokes an OS-specific handler.
+ */
+void t3_link_changed(struct adapter *adapter, int port_id)
+{
+ int link_ok, speed, duplex, fc;
+ struct port_info *pi = adap2pinfo(adapter, port_id);
+ struct cphy *phy = &pi->phy;
+ struct cmac *mac = &pi->mac;
+ struct link_config *lc = &pi->link_config;
+
+ phy->ops->get_link_status(phy, &link_ok, &speed, &duplex, &fc);
+
+ if (link_ok != lc->link_ok && adapter->params.rev > 0 &&
+ uses_xaui(adapter)) {
+ if (link_ok)
+ t3b_pcs_reset(mac);
+ t3_write_reg(adapter, A_XGM_XAUI_ACT_CTRL + mac->offset,
+ link_ok ? F_TXACTENABLE | F_RXEN : 0);
+ }
+ lc->link_ok = link_ok;
+ lc->speed = speed < 0 ? SPEED_INVALID : speed;
+ lc->duplex = duplex < 0 ? DUPLEX_INVALID : duplex;
+ if (lc->requested_fc & PAUSE_AUTONEG)
+ fc &= lc->requested_fc;
+ else
+ fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
+
+ if (link_ok && speed >= 0 && lc->autoneg == AUTONEG_ENABLE) {
+ /* Set MAC speed, duplex, and flow control to match PHY. */
+ t3_mac_set_speed_duplex_fc(mac, speed, duplex, fc);
+ lc->fc = fc;
+ }
+
+ t3_os_link_changed(adapter, port_id, link_ok, speed, duplex, fc);
+}
+
+/**
+ * t3_link_start - apply link configuration to MAC/PHY
+ * @phy: the PHY to setup
+ * @mac: the MAC to setup
+ * @lc: the requested link configuration
+ *
+ * Set up a port's MAC and PHY according to a desired link configuration.
+ * - If the PHY can auto-negotiate first decide what to advertise, then
+ * enable/disable auto-negotiation as desired, and reset.
+ * - If the PHY does not auto-negotiate just reset it.
+ * - If auto-negotiation is off set the MAC to the proper speed/duplex/FC,
+ * otherwise do it later based on the outcome of auto-negotiation.
+ */
+int t3_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc)
+{
+ unsigned int fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
+
+ lc->link_ok = 0;
+ if (lc->supported & SUPPORTED_Autoneg) {
+ lc->advertising &= ~(ADVERTISED_Asym_Pause | ADVERTISED_Pause);
+ if (fc) {
+ lc->advertising |= ADVERTISED_Asym_Pause;
+ if (fc & PAUSE_RX)
+ lc->advertising |= ADVERTISED_Pause;
+ }
+ phy->ops->advertise(phy, lc->advertising);
+
+ if (lc->autoneg == AUTONEG_DISABLE) {
+ lc->speed = lc->requested_speed;
+ lc->duplex = lc->requested_duplex;
+ lc->fc = (unsigned char)fc;
+ t3_mac_set_speed_duplex_fc(mac, lc->speed, lc->duplex,
+ fc);
+ /* Also disables autoneg */
+ phy->ops->set_speed_duplex(phy, lc->speed, lc->duplex);
+ phy->ops->reset(phy, 0);
+ } else
+ phy->ops->autoneg_enable(phy);
+ } else {
+ t3_mac_set_speed_duplex_fc(mac, -1, -1, fc);
+ lc->fc = (unsigned char)fc;
+ phy->ops->reset(phy, 0);
+ }
+ return 0;
+}
+
+/**
+ * t3_set_vlan_accel - control HW VLAN extraction
+ * @adapter: the adapter
+ * @ports: bitmap of adapter ports to operate on
+ * @on: enable (1) or disable (0) HW VLAN extraction
+ *
+ * Enables or disables HW extraction of VLAN tags for the given port.
+ */
+void t3_set_vlan_accel(struct adapter *adapter, unsigned int ports, int on)
+{
+ t3_set_reg_field(adapter, A_TP_OUT_CONFIG,
+ ports << S_VLANEXTRACTIONENABLE,
+ on ? (ports << S_VLANEXTRACTIONENABLE) : 0);
+}
+
+struct intr_info {
+ unsigned int mask; /* bits to check in interrupt status */
+ const char *msg; /* message to print or NULL */
+ short stat_idx; /* stat counter to increment or -1 */
+ unsigned short fatal:1; /* whether the condition reported is fatal */
+};
+
+/**
+ * t3_handle_intr_status - table driven interrupt handler
+ * @adapter: the adapter that generated the interrupt
+ * @reg: the interrupt status register to process
+ * @mask: a mask to apply to the interrupt status
+ * @acts: table of interrupt actions
+ * @stats: statistics counters tracking interrupt occurences
+ *
+ * A table driven interrupt handler that applies a set of masks to an
+ * interrupt status word and performs the corresponding actions if the
+ * interrupts described by the mask have occured. The actions include
+ * optionally printing a warning or alert message, and optionally
+ * incrementing a stat counter. The table is terminated by an entry
+ * specifying mask 0. Returns the number of fatal interrupt conditions.
+ */
+static int t3_handle_intr_status(struct adapter *adapter, unsigned int reg,
+ unsigned int mask,
+ const struct intr_info *acts,
+ unsigned long *stats)
+{
+ int fatal = 0;
+ unsigned int status = t3_read_reg(adapter, reg) & mask;
+
+ for (; acts->mask; ++acts) {
+ if (!(status & acts->mask))
+ continue;
+ if (acts->fatal) {
+ fatal++;
+ CH_ALERT(adapter, "%s (0x%x)\n",
+ acts->msg, status & acts->mask);
+ } else if (acts->msg)
+ CH_WARN(adapter, "%s (0x%x)\n",
+ acts->msg, status & acts->mask);
+ if (acts->stat_idx >= 0)
+ stats[acts->stat_idx]++;
+ }
+ if (status) /* clear processed interrupts */
+ t3_write_reg(adapter, reg, status);
+ return fatal;
+}
+
+#define SGE_INTR_MASK (F_RSPQDISABLED)
+#define MC5_INTR_MASK (F_PARITYERR | F_ACTRGNFULL | F_UNKNOWNCMD | \
+ F_REQQPARERR | F_DISPQPARERR | F_DELACTEMPTY | \
+ F_NFASRCHFAIL)
+#define MC7_INTR_MASK (F_AE | F_UE | F_CE | V_PE(M_PE))
+#define XGM_INTR_MASK (V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR) | \
+ V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR) | \
+ F_TXFIFO_UNDERRUN | F_RXFIFO_OVERFLOW)
+#define PCIX_INTR_MASK (F_MSTDETPARERR | F_SIGTARABT | F_RCVTARABT | \
+ F_RCVMSTABT | F_SIGSYSERR | F_DETPARERR | \
+ F_SPLCMPDIS | F_UNXSPLCMP | F_RCVSPLCMPERR | \
+ F_DETCORECCERR | F_DETUNCECCERR | F_PIOPARERR | \
+ V_WFPARERR(M_WFPARERR) | V_RFPARERR(M_RFPARERR) | \
+ V_CFPARERR(M_CFPARERR) /* | V_MSIXPARERR(M_MSIXPARERR) */)
+#define PCIE_INTR_MASK (F_UNXSPLCPLERRR | F_UNXSPLCPLERRC | F_PCIE_PIOPARERR |\
+ F_PCIE_WFPARERR | F_PCIE_RFPARERR | F_PCIE_CFPARERR | \
+ /* V_PCIE_MSIXPARERR(M_PCIE_MSIXPARERR) | */ \
+ V_BISTERR(M_BISTERR) | F_PEXERR)
+#define ULPRX_INTR_MASK F_PARERR
+#define ULPTX_INTR_MASK 0
+#define CPLSW_INTR_MASK (F_TP_FRAMING_ERROR | \
+ F_SGE_FRAMING_ERROR | F_CIM_FRAMING_ERROR | \
+ F_ZERO_SWITCH_ERROR)
+#define CIM_INTR_MASK (F_BLKWRPLINT | F_BLKRDPLINT | F_BLKWRCTLINT | \
+ F_BLKRDCTLINT | F_BLKWRFLASHINT | F_BLKRDFLASHINT | \
+ F_SGLWRFLASHINT | F_WRBLKFLASHINT | F_BLKWRBOOTINT | \
+ F_FLASHRANGEINT | F_SDRAMRANGEINT | F_RSVDSPACEINT)
+#define PMTX_INTR_MASK (F_ZERO_C_CMD_ERROR | ICSPI_FRM_ERR | OESPI_FRM_ERR | \
+ V_ICSPI_PAR_ERROR(M_ICSPI_PAR_ERROR) | \
+ V_OESPI_PAR_ERROR(M_OESPI_PAR_ERROR))
+#define PMRX_INTR_MASK (F_ZERO_E_CMD_ERROR | IESPI_FRM_ERR | OCSPI_FRM_ERR | \
+ V_IESPI_PAR_ERROR(M_IESPI_PAR_ERROR) | \
+ V_OCSPI_PAR_ERROR(M_OCSPI_PAR_ERROR))
+#define MPS_INTR_MASK (V_TX0TPPARERRENB(M_TX0TPPARERRENB) | \
+ V_TX1TPPARERRENB(M_TX1TPPARERRENB) | \
+ V_RXTPPARERRENB(M_RXTPPARERRENB) | \
+ V_MCAPARERRENB(M_MCAPARERRENB))
+#define PL_INTR_MASK (F_T3DBG | F_XGMAC0_0 | F_XGMAC0_1 | F_MC5A | F_PM1_TX | \
+ F_PM1_RX | F_ULP2_TX | F_ULP2_RX | F_TP1 | F_CIM | \
+ F_MC7_CM | F_MC7_PMTX | F_MC7_PMRX | F_SGE3 | F_PCIM0 | \
+ F_MPS0 | F_CPL_SWITCH)
+
+/*
+ * Interrupt handler for the PCIX1 module.
+ */
+static void pci_intr_handler(struct adapter *adapter)
+{
+ static const struct intr_info pcix1_intr_info[] = {
+ {F_MSTDETPARERR, "PCI master detected parity error", -1, 1},
+ {F_SIGTARABT, "PCI signaled target abort", -1, 1},
+ {F_RCVTARABT, "PCI received target abort", -1, 1},
+ {F_RCVMSTABT, "PCI received master abort", -1, 1},
+ {F_SIGSYSERR, "PCI signaled system error", -1, 1},
+ {F_DETPARERR, "PCI detected parity error", -1, 1},
+ {F_SPLCMPDIS, "PCI split completion discarded", -1, 1},
+ {F_UNXSPLCMP, "PCI unexpected split completion error", -1, 1},
+ {F_RCVSPLCMPERR, "PCI received split completion error", -1,
+ 1},
+ {F_DETCORECCERR, "PCI correctable ECC error",
+ STAT_PCI_CORR_ECC, 0},
+ {F_DETUNCECCERR, "PCI uncorrectable ECC error", -1, 1},
+ {F_PIOPARERR, "PCI PIO FIFO parity error", -1, 1},
+ {V_WFPARERR(M_WFPARERR), "PCI write FIFO parity error", -1,
+ 1},
+ {V_RFPARERR(M_RFPARERR), "PCI read FIFO parity error", -1,
+ 1},
+ {V_CFPARERR(M_CFPARERR), "PCI command FIFO parity error", -1,
+ 1},
+ {V_MSIXPARERR(M_MSIXPARERR), "PCI MSI-X table/PBA parity "
+ "error", -1, 1},
+ {0}
+ };
+
+ if (t3_handle_intr_status(adapter, A_PCIX_INT_CAUSE, PCIX_INTR_MASK,
+ pcix1_intr_info, adapter->irq_stats))
+ t3_fatal_err(adapter);
+}
+
+/*
+ * Interrupt handler for the PCIE module.
+ */
+static void pcie_intr_handler(struct adapter *adapter)
+{
+ static const struct intr_info pcie_intr_info[] = {
+ {F_PEXERR, "PCI PEX error", -1, 1},
+ {F_UNXSPLCPLERRR,
+ "PCI unexpected split completion DMA read error", -1, 1},
+ {F_UNXSPLCPLERRC,
+ "PCI unexpected split completion DMA command error", -1, 1},
+ {F_PCIE_PIOPARERR, "PCI PIO FIFO parity error", -1, 1},
+ {F_PCIE_WFPARERR, "PCI write FIFO parity error", -1, 1},
+ {F_PCIE_RFPARERR, "PCI read FIFO parity error", -1, 1},
+ {F_PCIE_CFPARERR, "PCI command FIFO parity error", -1, 1},
+ {V_PCIE_MSIXPARERR(M_PCIE_MSIXPARERR),
+ "PCI MSI-X table/PBA parity error", -1, 1},
+ {V_BISTERR(M_BISTERR), "PCI BIST error", -1, 1},
+ {0}
+ };
+
+ if (t3_handle_intr_status(adapter, A_PCIE_INT_CAUSE, PCIE_INTR_MASK,
+ pcie_intr_info, adapter->irq_stats))
+ t3_fatal_err(adapter);
+}
+
+/*
+ * TP interrupt handler.
+ */
+static void tp_intr_handler(struct adapter *adapter)
+{
+ static const struct intr_info tp_intr_info[] = {
+ {0xffffff, "TP parity error", -1, 1},
+ {0x1000000, "TP out of Rx pages", -1, 1},
+ {0x2000000, "TP out of Tx pages", -1, 1},
+ {0}
+ };
+
+ if (t3_handle_intr_status(adapter, A_TP_INT_CAUSE, 0xffffffff,
+ tp_intr_info, NULL))
+ t3_fatal_err(adapter);
+}
+
+/*
+ * CIM interrupt handler.
+ */
+static void cim_intr_handler(struct adapter *adapter)
+{
+ static const struct intr_info cim_intr_info[] = {
+ {F_RSVDSPACEINT, "CIM reserved space write", -1, 1},
+ {F_SDRAMRANGEINT, "CIM SDRAM address out of range", -1, 1},
+ {F_FLASHRANGEINT, "CIM flash address out of range", -1, 1},
+ {F_BLKWRBOOTINT, "CIM block write to boot space", -1, 1},
+ {F_WRBLKFLASHINT, "CIM write to cached flash space", -1, 1},
+ {F_SGLWRFLASHINT, "CIM single write to flash space", -1, 1},
+ {F_BLKRDFLASHINT, "CIM block read from flash space", -1, 1},
+ {F_BLKWRFLASHINT, "CIM block write to flash space", -1, 1},
+ {F_BLKRDCTLINT, "CIM block read from CTL space", -1, 1},
+ {F_BLKWRCTLINT, "CIM block write to CTL space", -1, 1},
+ {F_BLKRDPLINT, "CIM block read from PL space", -1, 1},
+ {F_BLKWRPLINT, "CIM block write to PL space", -1, 1},
+ {0}
+ };
+
+ if (t3_handle_intr_status(adapter, A_CIM_HOST_INT_CAUSE, 0xffffffff,
+ cim_intr_info, NULL))
+ t3_fatal_err(adapter);
+}
+
+/*
+ * ULP RX interrupt handler.
+ */
+static void ulprx_intr_handler(struct adapter *adapter)
+{
+ static const struct intr_info ulprx_intr_info[] = {
+ {F_PARERR, "ULP RX parity error", -1, 1},
+ {0}
+ };
+
+ if (t3_handle_intr_status(adapter, A_ULPRX_INT_CAUSE, 0xffffffff,
+ ulprx_intr_info, NULL))
+ t3_fatal_err(adapter);
+}
+
+/*
+ * ULP TX interrupt handler.
+ */
+static void ulptx_intr_handler(struct adapter *adapter)
+{
+ static const struct intr_info ulptx_intr_info[] = {
+ {F_PBL_BOUND_ERR_CH0, "ULP TX channel 0 PBL out of bounds",
+ STAT_ULP_CH0_PBL_OOB, 0},
+ {F_PBL_BOUND_ERR_CH1, "ULP TX channel 1 PBL out of bounds",
+ STAT_ULP_CH1_PBL_OOB, 0},
+ {0}
+ };
+
+ if (t3_handle_intr_status(adapter, A_ULPTX_INT_CAUSE, 0xffffffff,
+ ulptx_intr_info, adapter->irq_stats))
+ t3_fatal_err(adapter);
+}
+
+#define ICSPI_FRM_ERR (F_ICSPI0_FIFO2X_RX_FRAMING_ERROR | \
+ F_ICSPI1_FIFO2X_RX_FRAMING_ERROR | F_ICSPI0_RX_FRAMING_ERROR | \
+ F_ICSPI1_RX_FRAMING_ERROR | F_ICSPI0_TX_FRAMING_ERROR | \
+ F_ICSPI1_TX_FRAMING_ERROR)
+#define OESPI_FRM_ERR (F_OESPI0_RX_FRAMING_ERROR | \
+ F_OESPI1_RX_FRAMING_ERROR | F_OESPI0_TX_FRAMING_ERROR | \
+ F_OESPI1_TX_FRAMING_ERROR | F_OESPI0_OFIFO2X_TX_FRAMING_ERROR | \
+ F_OESPI1_OFIFO2X_TX_FRAMING_ERROR)
+
+/*
+ * PM TX interrupt handler.
+ */
+static void pmtx_intr_handler(struct adapter *adapter)
+{
+ static const struct intr_info pmtx_intr_info[] = {
+ {F_ZERO_C_CMD_ERROR, "PMTX 0-length pcmd", -1, 1},
+ {ICSPI_FRM_ERR, "PMTX ispi framing error", -1, 1},
+ {OESPI_FRM_ERR, "PMTX ospi framing error", -1, 1},
+ {V_ICSPI_PAR_ERROR(M_ICSPI_PAR_ERROR),
+ "PMTX ispi parity error", -1, 1},
+ {V_OESPI_PAR_ERROR(M_OESPI_PAR_ERROR),
+ "PMTX ospi parity error", -1, 1},
+ {0}
+ };
+
+ if (t3_handle_intr_status(adapter, A_PM1_TX_INT_CAUSE, 0xffffffff,
+ pmtx_intr_info, NULL))
+ t3_fatal_err(adapter);
+}
+
+#define IESPI_FRM_ERR (F_IESPI0_FIFO2X_RX_FRAMING_ERROR | \
+ F_IESPI1_FIFO2X_RX_FRAMING_ERROR | F_IESPI0_RX_FRAMING_ERROR | \
+ F_IESPI1_RX_FRAMING_ERROR | F_IESPI0_TX_FRAMING_ERROR | \
+ F_IESPI1_TX_FRAMING_ERROR)
+#define OCSPI_FRM_ERR (F_OCSPI0_RX_FRAMING_ERROR | \
+ F_OCSPI1_RX_FRAMING_ERROR | F_OCSPI0_TX_FRAMING_ERROR | \
+ F_OCSPI1_TX_FRAMING_ERROR | F_OCSPI0_OFIFO2X_TX_FRAMING_ERROR | \
+ F_OCSPI1_OFIFO2X_TX_FRAMING_ERROR)
+
+/*
+ * PM RX interrupt handler.
+ */
+static void pmrx_intr_handler(struct adapter *adapter)
+{
+ static const struct intr_info pmrx_intr_info[] = {
+ {F_ZERO_E_CMD_ERROR, "PMRX 0-length pcmd", -1, 1},
+ {IESPI_FRM_ERR, "PMRX ispi framing error", -1, 1},
+ {OCSPI_FRM_ERR, "PMRX ospi framing error", -1, 1},
+ {V_IESPI_PAR_ERROR(M_IESPI_PAR_ERROR),
+ "PMRX ispi parity error", -1, 1},
+ {V_OCSPI_PAR_ERROR(M_OCSPI_PAR_ERROR),
+ "PMRX ospi parity error", -1, 1},
+ {0}
+ };
+
+ if (t3_handle_intr_status(adapter, A_PM1_RX_INT_CAUSE, 0xffffffff,
+ pmrx_intr_info, NULL))
+ t3_fatal_err(adapter);
+}
+
+/*
+ * CPL switch interrupt handler.
+ */
+static void cplsw_intr_handler(struct adapter *adapter)
+{
+ static const struct intr_info cplsw_intr_info[] = {
+/* { F_CIM_OVFL_ERROR, "CPL switch CIM overflow", -1, 1 }, */
+ {F_TP_FRAMING_ERROR, "CPL switch TP framing error", -1, 1},
+ {F_SGE_FRAMING_ERROR, "CPL switch SGE framing error", -1, 1},
+ {F_CIM_FRAMING_ERROR, "CPL switch CIM framing error", -1, 1},
+ {F_ZERO_SWITCH_ERROR, "CPL switch no-switch error", -1, 1},
+ {0}
+ };
+
+ if (t3_handle_intr_status(adapter, A_CPL_INTR_CAUSE, 0xffffffff,
+ cplsw_intr_info, NULL))
+ t3_fatal_err(adapter);
+}
+
+/*
+ * MPS interrupt handler.
+ */
+static void mps_intr_handler(struct adapter *adapter)
+{
+ static const struct intr_info mps_intr_info[] = {
+ {0x1ff, "MPS parity error", -1, 1},
+ {0}
+ };
+
+ if (t3_handle_intr_status(adapter, A_MPS_INT_CAUSE, 0xffffffff,
+ mps_intr_info, NULL))
+ t3_fatal_err(adapter);
+}
+
+#define MC7_INTR_FATAL (F_UE | V_PE(M_PE) | F_AE)
+
+/*
+ * MC7 interrupt handler.
+ */
+static void mc7_intr_handler(struct mc7 *mc7)
+{
+ struct adapter *adapter = mc7->adapter;
+ u32 cause = t3_read_reg(adapter, mc7->offset + A_MC7_INT_CAUSE);
+
+ if (cause & F_CE) {
+ mc7->stats.corr_err++;
+ CH_WARN(adapter, "%s MC7 correctable error at addr 0x%x, "
+ "data 0x%x 0x%x 0x%x\n", mc7->name,
+ t3_read_reg(adapter, mc7->offset + A_MC7_CE_ADDR),
+ t3_read_reg(adapter, mc7->offset + A_MC7_CE_DATA0),
+ t3_read_reg(adapter, mc7->offset + A_MC7_CE_DATA1),
+ t3_read_reg(adapter, mc7->offset + A_MC7_CE_DATA2));
+ }
+
+ if (cause & F_UE) {
+ mc7->stats.uncorr_err++;
+ CH_ALERT(adapter, "%s MC7 uncorrectable error at addr 0x%x, "
+ "data 0x%x 0x%x 0x%x\n", mc7->name,
+ t3_read_reg(adapter, mc7->offset + A_MC7_UE_ADDR),
+ t3_read_reg(adapter, mc7->offset + A_MC7_UE_DATA0),
+ t3_read_reg(adapter, mc7->offset + A_MC7_UE_DATA1),
+ t3_read_reg(adapter, mc7->offset + A_MC7_UE_DATA2));
+ }
+
+ if (G_PE(cause)) {
+ mc7->stats.parity_err++;
+ CH_ALERT(adapter, "%s MC7 parity error 0x%x\n",
+ mc7->name, G_PE(cause));
+ }
+
+ if (cause & F_AE) {
+ u32 addr = 0;
+
+ if (adapter->params.rev > 0)
+ addr = t3_read_reg(adapter,
+ mc7->offset + A_MC7_ERR_ADDR);
+ mc7->stats.addr_err++;
+ CH_ALERT(adapter, "%s MC7 address error: 0x%x\n",
+ mc7->name, addr);
+ }
+
+ if (cause & MC7_INTR_FATAL)
+ t3_fatal_err(adapter);
+
+ t3_write_reg(adapter, mc7->offset + A_MC7_INT_CAUSE, cause);
+}
+
+#define XGM_INTR_FATAL (V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR) | \
+ V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR))
+/*
+ * XGMAC interrupt handler.
+ */
+static int mac_intr_handler(struct adapter *adap, unsigned int idx)
+{
+ struct cmac *mac = &adap2pinfo(adap, idx)->mac;
+ u32 cause = t3_read_reg(adap, A_XGM_INT_CAUSE + mac->offset);
+
+ if (cause & V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR)) {
+ mac->stats.tx_fifo_parity_err++;
+ CH_ALERT(adap, "port%d: MAC TX FIFO parity error\n", idx);
+ }
+ if (cause & V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR)) {
+ mac->stats.rx_fifo_parity_err++;
+ CH_ALERT(adap, "port%d: MAC RX FIFO parity error\n", idx);
+ }
+ if (cause & F_TXFIFO_UNDERRUN)
+ mac->stats.tx_fifo_urun++;
+ if (cause & F_RXFIFO_OVERFLOW)
+ mac->stats.rx_fifo_ovfl++;
+ if (cause & V_SERDES_LOS(M_SERDES_LOS))
+ mac->stats.serdes_signal_loss++;
+ if (cause & F_XAUIPCSCTCERR)
+ mac->stats.xaui_pcs_ctc_err++;
+ if (cause & F_XAUIPCSALIGNCHANGE)
+ mac->stats.xaui_pcs_align_change++;
+
+ t3_write_reg(adap, A_XGM_INT_CAUSE + mac->offset, cause);
+ if (cause & XGM_INTR_FATAL)
+ t3_fatal_err(adap);
+ return cause != 0;
+}
+
+/*
+ * Interrupt handler for PHY events.
+ */
+int t3_phy_intr_handler(struct adapter *adapter)
+{
+ static const int intr_gpio_bits[] = { 8, 0x20 };
+
+ u32 i, cause = t3_read_reg(adapter, A_T3DBG_INT_CAUSE);
+
+ for_each_port(adapter, i) {
+ if (cause & intr_gpio_bits[i]) {
+ struct cphy *phy = &adap2pinfo(adapter, i)->phy;
+ int phy_cause = phy->ops->intr_handler(phy);
+
+ if (phy_cause & cphy_cause_link_change)
+ t3_link_changed(adapter, i);
+ if (phy_cause & cphy_cause_fifo_error)
+ phy->fifo_errors++;
+ }
+ }
+
+ t3_write_reg(adapter, A_T3DBG_INT_CAUSE, cause);
+ return 0;
+}
+
+/*
+ * T3 slow path (non-data) interrupt handler.
+ */
+int t3_slow_intr_handler(struct adapter *adapter)
+{
+ u32 cause = t3_read_reg(adapter, A_PL_INT_CAUSE0);
+
+ cause &= adapter->slow_intr_mask;
+ if (!cause)
+ return 0;
+ if (cause & F_PCIM0) {
+ if (is_pcie(adapter))
+ pcie_intr_handler(adapter);
+ else
+ pci_intr_handler(adapter);
+ }
+ if (cause & F_SGE3)
+ t3_sge_err_intr_handler(adapter);
+ if (cause & F_MC7_PMRX)
+ mc7_intr_handler(&adapter->pmrx);
+ if (cause & F_MC7_PMTX)
+ mc7_intr_handler(&adapter->pmtx);
+ if (cause & F_MC7_CM)
+ mc7_intr_handler(&adapter->cm);
+ if (cause & F_CIM)
+ cim_intr_handler(adapter);
+ if (cause & F_TP1)
+ tp_intr_handler(adapter);
+ if (cause & F_ULP2_RX)
+ ulprx_intr_handler(adapter);
+ if (cause & F_ULP2_TX)
+ ulptx_intr_handler(adapter);
+ if (cause & F_PM1_RX)
+ pmrx_intr_handler(adapter);
+ if (cause & F_PM1_TX)
+ pmtx_intr_handler(adapter);
+ if (cause & F_CPL_SWITCH)
+ cplsw_intr_handler(adapter);
+ if (cause & F_MPS0)
+ mps_intr_handler(adapter);
+ if (cause & F_MC5A)
+ t3_mc5_intr_handler(&adapter->mc5);
+ if (cause & F_XGMAC0_0)
+ mac_intr_handler(adapter, 0);
+ if (cause & F_XGMAC0_1)
+ mac_intr_handler(adapter, 1);
+ if (cause & F_T3DBG)
+ t3_os_ext_intr_handler(adapter);
+
+ /* Clear the interrupts just processed. */
+ t3_write_reg(adapter, A_PL_INT_CAUSE0, cause);
+ t3_read_reg(adapter, A_PL_INT_CAUSE0); /* flush */
+ return 1;
+}
+
+/**
+ * t3_intr_enable - enable interrupts
+ * @adapter: the adapter whose interrupts should be enabled
+ *
+ * Enable interrupts by setting the interrupt enable registers of the
+ * various HW modules and then enabling the top-level interrupt
+ * concentrator.
+ */
+void t3_intr_enable(struct adapter *adapter)
+{
+ static const struct addr_val_pair intr_en_avp[] = {
+ {A_SG_INT_ENABLE, SGE_INTR_MASK},
+ {A_MC7_INT_ENABLE, MC7_INTR_MASK},
+ {A_MC7_INT_ENABLE - MC7_PMRX_BASE_ADDR + MC7_PMTX_BASE_ADDR,
+ MC7_INTR_MASK},
+ {A_MC7_INT_ENABLE - MC7_PMRX_BASE_ADDR + MC7_CM_BASE_ADDR,
+ MC7_INTR_MASK},
+ {A_MC5_DB_INT_ENABLE, MC5_INTR_MASK},
+ {A_ULPRX_INT_ENABLE, ULPRX_INTR_MASK},
+ {A_TP_INT_ENABLE, 0x3bfffff},
+ {A_PM1_TX_INT_ENABLE, PMTX_INTR_MASK},
+ {A_PM1_RX_INT_ENABLE, PMRX_INTR_MASK},
+ {A_CIM_HOST_INT_ENABLE, CIM_INTR_MASK},
+ {A_MPS_INT_ENABLE, MPS_INTR_MASK},
+ };
+
+ adapter->slow_intr_mask = PL_INTR_MASK;
+
+ t3_write_regs(adapter, intr_en_avp, ARRAY_SIZE(intr_en_avp), 0);
+
+ if (adapter->params.rev > 0) {
+ t3_write_reg(adapter, A_CPL_INTR_ENABLE,
+ CPLSW_INTR_MASK | F_CIM_OVFL_ERROR);
+ t3_write_reg(adapter, A_ULPTX_INT_ENABLE,
+ ULPTX_INTR_MASK | F_PBL_BOUND_ERR_CH0 |
+ F_PBL_BOUND_ERR_CH1);
+ } else {
+ t3_write_reg(adapter, A_CPL_INTR_ENABLE, CPLSW_INTR_MASK);
+ t3_write_reg(adapter, A_ULPTX_INT_ENABLE, ULPTX_INTR_MASK);
+ }
+
+ t3_write_reg(adapter, A_T3DBG_GPIO_ACT_LOW,
+ adapter_info(adapter)->gpio_intr);
+ t3_write_reg(adapter, A_T3DBG_INT_ENABLE,
+ adapter_info(adapter)->gpio_intr);
+ if (is_pcie(adapter))
+ t3_write_reg(adapter, A_PCIE_INT_ENABLE, PCIE_INTR_MASK);
+ else
+ t3_write_reg(adapter, A_PCIX_INT_ENABLE, PCIX_INTR_MASK);
+ t3_write_reg(adapter, A_PL_INT_ENABLE0, adapter->slow_intr_mask);
+ t3_read_reg(adapter, A_PL_INT_ENABLE0); /* flush */
+}
+
+/**
+ * t3_intr_disable - disable a card's interrupts
+ * @adapter: the adapter whose interrupts should be disabled
+ *
+ * Disable interrupts. We only disable the top-level interrupt
+ * concentrator and the SGE data interrupts.
+ */
+void t3_intr_disable(struct adapter *adapter)
+{
+ t3_write_reg(adapter, A_PL_INT_ENABLE0, 0);
+ t3_read_reg(adapter, A_PL_INT_ENABLE0); /* flush */
+ adapter->slow_intr_mask = 0;
+}
+
+/**
+ * t3_intr_clear - clear all interrupts
+ * @adapter: the adapter whose interrupts should be cleared
+ *
+ * Clears all interrupts.
+ */
+void t3_intr_clear(struct adapter *adapter)
+{
+ static const unsigned int cause_reg_addr[] = {
+ A_SG_INT_CAUSE,
+ A_SG_RSPQ_FL_STATUS,
+ A_PCIX_INT_CAUSE,
+ A_MC7_INT_CAUSE,
+ A_MC7_INT_CAUSE - MC7_PMRX_BASE_ADDR + MC7_PMTX_BASE_ADDR,
+ A_MC7_INT_CAUSE - MC7_PMRX_BASE_ADDR + MC7_CM_BASE_ADDR,
+ A_CIM_HOST_INT_CAUSE,
+ A_TP_INT_CAUSE,
+ A_MC5_DB_INT_CAUSE,
+ A_ULPRX_INT_CAUSE,
+ A_ULPTX_INT_CAUSE,
+ A_CPL_INTR_CAUSE,
+ A_PM1_TX_INT_CAUSE,
+ A_PM1_RX_INT_CAUSE,
+ A_MPS_INT_CAUSE,
+ A_T3DBG_INT_CAUSE,
+ };
+ unsigned int i;
+
+ /* Clear PHY and MAC interrupts for each port. */
+ for_each_port(adapter, i)
+ t3_port_intr_clear(adapter, i);
+
+ for (i = 0; i < ARRAY_SIZE(cause_reg_addr); ++i)
+ t3_write_reg(adapter, cause_reg_addr[i], 0xffffffff);
+
+ t3_write_reg(adapter, A_PL_INT_CAUSE0, 0xffffffff);
+ t3_read_reg(adapter, A_PL_INT_CAUSE0); /* flush */
+}
+
+/**
+ * t3_port_intr_enable - enable port-specific interrupts
+ * @adapter: associated adapter
+ * @idx: index of port whose interrupts should be enabled
+ *
+ * Enable port-specific (i.e., MAC and PHY) interrupts for the given
+ * adapter port.
+ */
+void t3_port_intr_enable(struct adapter *adapter, int idx)
+{
+ struct cphy *phy = &adap2pinfo(adapter, idx)->phy;
+
+ t3_write_reg(adapter, XGM_REG(A_XGM_INT_ENABLE, idx), XGM_INTR_MASK);
+ t3_read_reg(adapter, XGM_REG(A_XGM_INT_ENABLE, idx)); /* flush */
+ phy->ops->intr_enable(phy);
+}
+
+/**
+ * t3_port_intr_disable - disable port-specific interrupts
+ * @adapter: associated adapter
+ * @idx: index of port whose interrupts should be disabled
+ *
+ * Disable port-specific (i.e., MAC and PHY) interrupts for the given
+ * adapter port.
+ */
+void t3_port_intr_disable(struct adapter *adapter, int idx)
+{
+ struct cphy *phy = &adap2pinfo(adapter, idx)->phy;
+
+ t3_write_reg(adapter, XGM_REG(A_XGM_INT_ENABLE, idx), 0);
+ t3_read_reg(adapter, XGM_REG(A_XGM_INT_ENABLE, idx)); /* flush */
+ phy->ops->intr_disable(phy);
+}
+
+/**
+ * t3_port_intr_clear - clear port-specific interrupts
+ * @adapter: associated adapter
+ * @idx: index of port whose interrupts to clear
+ *
+ * Clear port-specific (i.e., MAC and PHY) interrupts for the given
+ * adapter port.
+ */
+void t3_port_intr_clear(struct adapter *adapter, int idx)
+{
+ struct cphy *phy = &adap2pinfo(adapter, idx)->phy;
+
+ t3_write_reg(adapter, XGM_REG(A_XGM_INT_CAUSE, idx), 0xffffffff);
+ t3_read_reg(adapter, XGM_REG(A_XGM_INT_CAUSE, idx)); /* flush */
+ phy->ops->intr_clear(phy);
+}
+
+/**
+ * t3_sge_write_context - write an SGE context
+ * @adapter: the adapter
+ * @id: the context id
+ * @type: the context type
+ *
+ * Program an SGE context with the values already loaded in the
+ * CONTEXT_DATA? registers.
+ */
+static int t3_sge_write_context(struct adapter *adapter, unsigned int id,
+ unsigned int type)
+{
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0xffffffff);
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0xffffffff);
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0xffffffff);
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0xffffffff);
+ t3_write_reg(adapter, A_SG_CONTEXT_CMD,
+ V_CONTEXT_CMD_OPCODE(1) | type | V_CONTEXT(id));
+ return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
+ 0, 5, 1);
+}
+
+/**
+ * t3_sge_init_ecntxt - initialize an SGE egress context
+ * @adapter: the adapter to configure
+ * @id: the context id
+ * @gts_enable: whether to enable GTS for the context
+ * @type: the egress context type
+ * @respq: associated response queue
+ * @base_addr: base address of queue
+ * @size: number of queue entries
+ * @token: uP token
+ * @gen: initial generation value for the context
+ * @cidx: consumer pointer
+ *
+ * Initialize an SGE egress context and make it ready for use. If the
+ * platform allows concurrent context operations, the caller is
+ * responsible for appropriate locking.
+ */
+int t3_sge_init_ecntxt(struct adapter *adapter, unsigned int id, int gts_enable,
+ enum sge_context_type type, int respq, u64 base_addr,
+ unsigned int size, unsigned int token, int gen,
+ unsigned int cidx)
+{
+ unsigned int credits = type == SGE_CNTXT_OFLD ? 0 : FW_WR_NUM;
+
+ if (base_addr & 0xfff) /* must be 4K aligned */
+ return -EINVAL;
+ if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
+ return -EBUSY;
+
+ base_addr >>= 12;
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA0, V_EC_INDEX(cidx) |
+ V_EC_CREDITS(credits) | V_EC_GTS(gts_enable));
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA1, V_EC_SIZE(size) |
+ V_EC_BASE_LO(base_addr & 0xffff));
+ base_addr >>= 16;
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA2, base_addr);
+ base_addr >>= 32;
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA3,
+ V_EC_BASE_HI(base_addr & 0xf) | V_EC_RESPQ(respq) |
+ V_EC_TYPE(type) | V_EC_GEN(gen) | V_EC_UP_TOKEN(token) |
+ F_EC_VALID);
+ return t3_sge_write_context(adapter, id, F_EGRESS);
+}
+
+/**
+ * t3_sge_init_flcntxt - initialize an SGE free-buffer list context
+ * @adapter: the adapter to configure
+ * @id: the context id
+ * @gts_enable: whether to enable GTS for the context
+ * @base_addr: base address of queue
+ * @size: number of queue entries
+ * @bsize: size of each buffer for this queue
+ * @cong_thres: threshold to signal congestion to upstream producers
+ * @gen: initial generation value for the context
+ * @cidx: consumer pointer
+ *
+ * Initialize an SGE free list context and make it ready for use. The
+ * caller is responsible for ensuring only one context operation occurs
+ * at a time.
+ */
+int t3_sge_init_flcntxt(struct adapter *adapter, unsigned int id,
+ int gts_enable, u64 base_addr, unsigned int size,
+ unsigned int bsize, unsigned int cong_thres, int gen,
+ unsigned int cidx)
+{
+ if (base_addr & 0xfff) /* must be 4K aligned */
+ return -EINVAL;
+ if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
+ return -EBUSY;
+
+ base_addr >>= 12;
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA0, base_addr);
+ base_addr >>= 32;
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA1,
+ V_FL_BASE_HI((u32) base_addr) |
+ V_FL_INDEX_LO(cidx & M_FL_INDEX_LO));
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA2, V_FL_SIZE(size) |
+ V_FL_GEN(gen) | V_FL_INDEX_HI(cidx >> 12) |
+ V_FL_ENTRY_SIZE_LO(bsize & M_FL_ENTRY_SIZE_LO));
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA3,
+ V_FL_ENTRY_SIZE_HI(bsize >> (32 - S_FL_ENTRY_SIZE_LO)) |
+ V_FL_CONG_THRES(cong_thres) | V_FL_GTS(gts_enable));
+ return t3_sge_write_context(adapter, id, F_FREELIST);
+}
+
+/**
+ * t3_sge_init_rspcntxt - initialize an SGE response queue context
+ * @adapter: the adapter to configure
+ * @id: the context id
+ * @irq_vec_idx: MSI-X interrupt vector index, 0 if no MSI-X, -1 if no IRQ
+ * @base_addr: base address of queue
+ * @size: number of queue entries
+ * @fl_thres: threshold for selecting the normal or jumbo free list
+ * @gen: initial generation value for the context
+ * @cidx: consumer pointer
+ *
+ * Initialize an SGE response queue context and make it ready for use.
+ * The caller is responsible for ensuring only one context operation
+ * occurs at a time.
+ */
+int t3_sge_init_rspcntxt(struct adapter *adapter, unsigned int id,
+ int irq_vec_idx, u64 base_addr, unsigned int size,
+ unsigned int fl_thres, int gen, unsigned int cidx)
+{
+ unsigned int intr = 0;
+
+ if (base_addr & 0xfff) /* must be 4K aligned */
+ return -EINVAL;
+ if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
+ return -EBUSY;
+
+ base_addr >>= 12;
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA0, V_CQ_SIZE(size) |
+ V_CQ_INDEX(cidx));
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA1, base_addr);
+ base_addr >>= 32;
+ if (irq_vec_idx >= 0)
+ intr = V_RQ_MSI_VEC(irq_vec_idx) | F_RQ_INTR_EN;
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA2,
+ V_CQ_BASE_HI((u32) base_addr) | intr | V_RQ_GEN(gen));
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA3, fl_thres);
+ return t3_sge_write_context(adapter, id, F_RESPONSEQ);
+}
+
+/**
+ * t3_sge_init_cqcntxt - initialize an SGE completion queue context
+ * @adapter: the adapter to configure
+ * @id: the context id
+ * @base_addr: base address of queue
+ * @size: number of queue entries
+ * @rspq: response queue for async notifications
+ * @ovfl_mode: CQ overflow mode
+ * @credits: completion queue credits
+ * @credit_thres: the credit threshold
+ *
+ * Initialize an SGE completion queue context and make it ready for use.
+ * The caller is responsible for ensuring only one context operation
+ * occurs at a time.
+ */
+int t3_sge_init_cqcntxt(struct adapter *adapter, unsigned int id, u64 base_addr,
+ unsigned int size, int rspq, int ovfl_mode,
+ unsigned int credits, unsigned int credit_thres)
+{
+ if (base_addr & 0xfff) /* must be 4K aligned */
+ return -EINVAL;
+ if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
+ return -EBUSY;
+
+ base_addr >>= 12;
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA0, V_CQ_SIZE(size));
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA1, base_addr);
+ base_addr >>= 32;
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA2,
+ V_CQ_BASE_HI((u32) base_addr) | V_CQ_RSPQ(rspq) |
+ V_CQ_GEN(1) | V_CQ_OVERFLOW_MODE(ovfl_mode));
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA3, V_CQ_CREDITS(credits) |
+ V_CQ_CREDIT_THRES(credit_thres));
+ return t3_sge_write_context(adapter, id, F_CQ);
+}
+
+/**
+ * t3_sge_enable_ecntxt - enable/disable an SGE egress context
+ * @adapter: the adapter
+ * @id: the egress context id
+ * @enable: enable (1) or disable (0) the context
+ *
+ * Enable or disable an SGE egress context. The caller is responsible for
+ * ensuring only one context operation occurs at a time.
+ */
+int t3_sge_enable_ecntxt(struct adapter *adapter, unsigned int id, int enable)
+{
+ if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
+ return -EBUSY;
+
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0);
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0);
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0);
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK3, F_EC_VALID);
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA3, V_EC_VALID(enable));
+ t3_write_reg(adapter, A_SG_CONTEXT_CMD,
+ V_CONTEXT_CMD_OPCODE(1) | F_EGRESS | V_CONTEXT(id));
+ return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
+ 0, 5, 1);
+}
+
+/**
+ * t3_sge_disable_fl - disable an SGE free-buffer list
+ * @adapter: the adapter
+ * @id: the free list context id
+ *
+ * Disable an SGE free-buffer list. The caller is responsible for
+ * ensuring only one context operation occurs at a time.
+ */
+int t3_sge_disable_fl(struct adapter *adapter, unsigned int id)
+{
+ if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
+ return -EBUSY;
+
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0);
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0);
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK2, V_FL_SIZE(M_FL_SIZE));
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0);
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA2, 0);
+ t3_write_reg(adapter, A_SG_CONTEXT_CMD,
+ V_CONTEXT_CMD_OPCODE(1) | F_FREELIST | V_CONTEXT(id));
+ return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
+ 0, 5, 1);
+}
+
+/**
+ * t3_sge_disable_rspcntxt - disable an SGE response queue
+ * @adapter: the adapter
+ * @id: the response queue context id
+ *
+ * Disable an SGE response queue. The caller is responsible for
+ * ensuring only one context operation occurs at a time.
+ */
+int t3_sge_disable_rspcntxt(struct adapter *adapter, unsigned int id)
+{
+ if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
+ return -EBUSY;
+
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK0, V_CQ_SIZE(M_CQ_SIZE));
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0);
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0);
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0);
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA0, 0);
+ t3_write_reg(adapter, A_SG_CONTEXT_CMD,
+ V_CONTEXT_CMD_OPCODE(1) | F_RESPONSEQ | V_CONTEXT(id));
+ return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
+ 0, 5, 1);
+}
+
+/**
+ * t3_sge_disable_cqcntxt - disable an SGE completion queue
+ * @adapter: the adapter
+ * @id: the completion queue context id
+ *
+ * Disable an SGE completion queue. The caller is responsible for
+ * ensuring only one context operation occurs at a time.
+ */
+int t3_sge_disable_cqcntxt(struct adapter *adapter, unsigned int id)
+{
+ if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
+ return -EBUSY;
+
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK0, V_CQ_SIZE(M_CQ_SIZE));
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0);
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0);
+ t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0);
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA0, 0);
+ t3_write_reg(adapter, A_SG_CONTEXT_CMD,
+ V_CONTEXT_CMD_OPCODE(1) | F_CQ | V_CONTEXT(id));
+ return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
+ 0, 5, 1);
+}
+
+/**
+ * t3_sge_cqcntxt_op - perform an operation on a completion queue context
+ * @adapter: the adapter
+ * @id: the context id
+ * @op: the operation to perform
+ *
+ * Perform the selected operation on an SGE completion queue context.
+ * The caller is responsible for ensuring only one context operation
+ * occurs at a time.
+ */
+int t3_sge_cqcntxt_op(struct adapter *adapter, unsigned int id, unsigned int op,
+ unsigned int credits)
+{
+ u32 val;
+
+ if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
+ return -EBUSY;
+
+ t3_write_reg(adapter, A_SG_CONTEXT_DATA0, credits << 16);
+ t3_write_reg(adapter, A_SG_CONTEXT_CMD, V_CONTEXT_CMD_OPCODE(op) |
+ V_CONTEXT(id) | F_CQ);
+ if (t3_wait_op_done_val(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
+ 0, 5, 1, &val))
+ return -EIO;
+
+ if (op >= 2 && op < 7) {
+ if (adapter->params.rev > 0)
+ return G_CQ_INDEX(val);
+
+ t3_write_reg(adapter, A_SG_CONTEXT_CMD,
+ V_CONTEXT_CMD_OPCODE(0) | F_CQ | V_CONTEXT(id));
+ if (t3_wait_op_done(adapter, A_SG_CONTEXT_CMD,
+ F_CONTEXT_CMD_BUSY, 0, 5, 1))
+ return -EIO;
+ return G_CQ_INDEX(t3_read_reg(adapter, A_SG_CONTEXT_DATA0));
+ }
+ return 0;
+}
+
+/**
+ * t3_sge_read_context - read an SGE context
+ * @type: the context type
+ * @adapter: the adapter
+ * @id: the context id
+ * @data: holds the retrieved context
+ *
+ * Read an SGE egress context. The caller is responsible for ensuring
+ * only one context operation occurs at a time.
+ */
+static int t3_sge_read_context(unsigned int type, struct adapter *adapter,
+ unsigned int id, u32 data[4])
+{
+ if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
+ return -EBUSY;
+
+ t3_write_reg(adapter, A_SG_CONTEXT_CMD,
+ V_CONTEXT_CMD_OPCODE(0) | type | V_CONTEXT(id));
+ if (t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, 0,
+ 5, 1))
+ return -EIO;
+ data[0] = t3_read_reg(adapter, A_SG_CONTEXT_DATA0);
+ data[1] = t3_read_reg(adapter, A_SG_CONTEXT_DATA1);
+ data[2] = t3_read_reg(adapter, A_SG_CONTEXT_DATA2);
+ data[3] = t3_read_reg(adapter, A_SG_CONTEXT_DATA3);
+ return 0;
+}
+
+/**
+ * t3_sge_read_ecntxt - read an SGE egress context
+ * @adapter: the adapter
+ * @id: the context id
+ * @data: holds the retrieved context
+ *
+ * Read an SGE egress context. The caller is responsible for ensuring
+ * only one context operation occurs at a time.
+ */
+int t3_sge_read_ecntxt(struct adapter *adapter, unsigned int id, u32 data[4])
+{
+ if (id >= 65536)
+ return -EINVAL;
+ return t3_sge_read_context(F_EGRESS, adapter, id, data);
+}
+
+/**
+ * t3_sge_read_cq - read an SGE CQ context
+ * @adapter: the adapter
+ * @id: the context id
+ * @data: holds the retrieved context
+ *
+ * Read an SGE CQ context. The caller is responsible for ensuring
+ * only one context operation occurs at a time.
+ */
+int t3_sge_read_cq(struct adapter *adapter, unsigned int id, u32 data[4])
+{
+ if (id >= 65536)
+ return -EINVAL;
+ return t3_sge_read_context(F_CQ, adapter, id, data);
+}
+
+/**
+ * t3_sge_read_fl - read an SGE free-list context
+ * @adapter: the adapter
+ * @id: the context id
+ * @data: holds the retrieved context
+ *
+ * Read an SGE free-list context. The caller is responsible for ensuring
+ * only one context operation occurs at a time.
+ */
+int t3_sge_read_fl(struct adapter *adapter, unsigned int id, u32 data[4])
+{
+ if (id >= SGE_QSETS * 2)
+ return -EINVAL;
+ return t3_sge_read_context(F_FREELIST, adapter, id, data);
+}
+
+/**
+ * t3_sge_read_rspq - read an SGE response queue context
+ * @adapter: the adapter
+ * @id: the context id
+ * @data: holds the retrieved context
+ *
+ * Read an SGE response queue context. The caller is responsible for
+ * ensuring only one context operation occurs at a time.
+ */
+int t3_sge_read_rspq(struct adapter *adapter, unsigned int id, u32 data[4])
+{
+ if (id >= SGE_QSETS)
+ return -EINVAL;
+ return t3_sge_read_context(F_RESPONSEQ, adapter, id, data);
+}
+
+/**
+ * t3_config_rss - configure Rx packet steering
+ * @adapter: the adapter
+ * @rss_config: RSS settings (written to TP_RSS_CONFIG)
+ * @cpus: values for the CPU lookup table (0xff terminated)
+ * @rspq: values for the response queue lookup table (0xffff terminated)
+ *
+ * Programs the receive packet steering logic. @cpus and @rspq provide
+ * the values for the CPU and response queue lookup tables. If they
+ * provide fewer values than the size of the tables the supplied values
+ * are used repeatedly until the tables are fully populated.
+ */
+void t3_config_rss(struct adapter *adapter, unsigned int rss_config,
+ const u8 * cpus, const u16 *rspq)
+{
+ int i, j, cpu_idx = 0, q_idx = 0;
+
+ if (cpus)
+ for (i = 0; i < RSS_TABLE_SIZE; ++i) {
+ u32 val = i << 16;
+
+ for (j = 0; j < 2; ++j) {
+ val |= (cpus[cpu_idx++] & 0x3f) << (8 * j);
+ if (cpus[cpu_idx] == 0xff)
+ cpu_idx = 0;
+ }
+ t3_write_reg(adapter, A_TP_RSS_LKP_TABLE, val);
+ }
+
+ if (rspq)
+ for (i = 0; i < RSS_TABLE_SIZE; ++i) {
+ t3_write_reg(adapter, A_TP_RSS_MAP_TABLE,
+ (i << 16) | rspq[q_idx++]);
+ if (rspq[q_idx] == 0xffff)
+ q_idx = 0;
+ }
+
+ t3_write_reg(adapter, A_TP_RSS_CONFIG, rss_config);
+}
+
+/**
+ * t3_read_rss - read the contents of the RSS tables
+ * @adapter: the adapter
+ * @lkup: holds the contents of the RSS lookup table
+ * @map: holds the contents of the RSS map table
+ *
+ * Reads the contents of the receive packet steering tables.
+ */
+int t3_read_rss(struct adapter *adapter, u8 * lkup, u16 *map)
+{
+ int i;
+ u32 val;
+
+ if (lkup)
+ for (i = 0; i < RSS_TABLE_SIZE; ++i) {
+ t3_write_reg(adapter, A_TP_RSS_LKP_TABLE,
+ 0xffff0000 | i);
+ val = t3_read_reg(adapter, A_TP_RSS_LKP_TABLE);
+ if (!(val & 0x80000000))
+ return -EAGAIN;
+ *lkup++ = val;
+ *lkup++ = (val >> 8);
+ }
+
+ if (map)
+ for (i = 0; i < RSS_TABLE_SIZE; ++i) {
+ t3_write_reg(adapter, A_TP_RSS_MAP_TABLE,
+ 0xffff0000 | i);
+ val = t3_read_reg(adapter, A_TP_RSS_MAP_TABLE);
+ if (!(val & 0x80000000))
+ return -EAGAIN;
+ *map++ = val;
+ }
+ return 0;
+}
+
+/**
+ * t3_tp_set_offload_mode - put TP in NIC/offload mode
+ * @adap: the adapter
+ * @enable: 1 to select offload mode, 0 for regular NIC
+ *
+ * Switches TP to NIC/offload mode.
+ */
+void t3_tp_set_offload_mode(struct adapter *adap, int enable)
+{
+ if (is_offload(adap) || !enable)
+ t3_set_reg_field(adap, A_TP_IN_CONFIG, F_NICMODE,
+ V_NICMODE(!enable));
+}
+
+/**
+ * pm_num_pages - calculate the number of pages of the payload memory
+ * @mem_size: the size of the payload memory
+ * @pg_size: the size of each payload memory page
+ *
+ * Calculate the number of pages, each of the given size, that fit in a
+ * memory of the specified size, respecting the HW requirement that the
+ * number of pages must be a multiple of 24.
+ */
+static inline unsigned int pm_num_pages(unsigned int mem_size,
+ unsigned int pg_size)
+{
+ unsigned int n = mem_size / pg_size;
+
+ return n - n % 24;
+}
+
+#define mem_region(adap, start, size, reg) \
+ t3_write_reg((adap), A_ ## reg, (start)); \
+ start += size
+
+/*
+ * partition_mem - partition memory and configure TP memory settings
+ * @adap: the adapter
+ * @p: the TP parameters
+ *
+ * Partitions context and payload memory and configures TP's memory
+ * registers.
+ */
+static void partition_mem(struct adapter *adap, const struct tp_params *p)
+{
+ unsigned int m, pstructs, tids = t3_mc5_size(&adap->mc5);
+ unsigned int timers = 0, timers_shift = 22;
+
+ if (adap->params.rev > 0) {
+ if (tids <= 16 * 1024) {
+ timers = 1;
+ timers_shift = 16;
+ } else if (tids <= 64 * 1024) {
+ timers = 2;
+ timers_shift = 18;
+ } else if (tids <= 256 * 1024) {
+ timers = 3;
+ timers_shift = 20;
+ }
+ }
+
+ t3_write_reg(adap, A_TP_PMM_SIZE,
+ p->chan_rx_size | (p->chan_tx_size >> 16));
+
+ t3_write_reg(adap, A_TP_PMM_TX_BASE, 0);
+ t3_write_reg(adap, A_TP_PMM_TX_PAGE_SIZE, p->tx_pg_size);
+ t3_write_reg(adap, A_TP_PMM_TX_MAX_PAGE, p->tx_num_pgs);
+ t3_set_reg_field(adap, A_TP_PARA_REG3, V_TXDATAACKIDX(M_TXDATAACKIDX),
+ V_TXDATAACKIDX(fls(p->tx_pg_size) - 12));
+
+ t3_write_reg(adap, A_TP_PMM_RX_BASE, 0);
+ t3_write_reg(adap, A_TP_PMM_RX_PAGE_SIZE, p->rx_pg_size);
+ t3_write_reg(adap, A_TP_PMM_RX_MAX_PAGE, p->rx_num_pgs);
+
+ pstructs = p->rx_num_pgs + p->tx_num_pgs;
+ /* Add a bit of headroom and make multiple of 24 */
+ pstructs += 48;
+ pstructs -= pstructs % 24;
+ t3_write_reg(adap, A_TP_CMM_MM_MAX_PSTRUCT, pstructs);
+
+ m = tids * TCB_SIZE;
+ mem_region(adap, m, (64 << 10) * 64, SG_EGR_CNTX_BADDR);
+ mem_region(adap, m, (64 << 10) * 64, SG_CQ_CONTEXT_BADDR);
+ t3_write_reg(adap, A_TP_CMM_TIMER_BASE, V_CMTIMERMAXNUM(timers) | m);
+ m += ((p->ntimer_qs - 1) << timers_shift) + (1 << 22);
+ mem_region(adap, m, pstructs * 64, TP_CMM_MM_BASE);
+ mem_region(adap, m, 64 * (pstructs / 24), TP_CMM_MM_PS_FLST_BASE);
+ mem_region(adap, m, 64 * (p->rx_num_pgs / 24), TP_CMM_MM_RX_FLST_BASE);
+ mem_region(adap, m, 64 * (p->tx_num_pgs / 24), TP_CMM_MM_TX_FLST_BASE);
+
+ m = (m + 4095) & ~0xfff;
+ t3_write_reg(adap, A_CIM_SDRAM_BASE_ADDR, m);
+ t3_write_reg(adap, A_CIM_SDRAM_ADDR_SIZE, p->cm_size - m);
+
+ tids = (p->cm_size - m - (3 << 20)) / 3072 - 32;
+ m = t3_mc5_size(&adap->mc5) - adap->params.mc5.nservers -
+ adap->params.mc5.nfilters - adap->params.mc5.nroutes;
+ if (tids < m)
+ adap->params.mc5.nservers += m - tids;
+}
+
+static inline void tp_wr_indirect(struct adapter *adap, unsigned int addr,
+ u32 val)
+{
+ t3_write_reg(adap, A_TP_PIO_ADDR, addr);
+ t3_write_reg(adap, A_TP_PIO_DATA, val);
+}
+
+static void tp_config(struct adapter *adap, const struct tp_params *p)
+{
+ t3_write_reg(adap, A_TP_GLOBAL_CONFIG, F_TXPACINGENABLE | F_PATHMTU |
+ F_IPCHECKSUMOFFLOAD | F_UDPCHECKSUMOFFLOAD |
+ F_TCPCHECKSUMOFFLOAD | V_IPTTL(64));
+ t3_write_reg(adap, A_TP_TCP_OPTIONS, V_MTUDEFAULT(576) |
+ F_MTUENABLE | V_WINDOWSCALEMODE(1) |
+ V_TIMESTAMPSMODE(1) | V_SACKMODE(1) | V_SACKRX(1));
+ t3_write_reg(adap, A_TP_DACK_CONFIG, V_AUTOSTATE3(1) |
+ V_AUTOSTATE2(1) | V_AUTOSTATE1(0) |
+ V_BYTETHRESHOLD(16384) | V_MSSTHRESHOLD(2) |
+ F_AUTOCAREFUL | F_AUTOENABLE | V_DACK_MODE(1));
+ t3_set_reg_field(adap, A_TP_IN_CONFIG, F_IPV6ENABLE | F_NICMODE,
+ F_IPV6ENABLE | F_NICMODE);
+ t3_write_reg(adap, A_TP_TX_RESOURCE_LIMIT, 0x18141814);
+ t3_write_reg(adap, A_TP_PARA_REG4, 0x5050105);
+ t3_set_reg_field(adap, A_TP_PARA_REG6,
+ adap->params.rev > 0 ? F_ENABLEESND : F_T3A_ENABLEESND,
+ 0);
+
+ t3_set_reg_field(adap, A_TP_PC_CONFIG,
+ F_ENABLEEPCMDAFULL | F_ENABLEOCSPIFULL,
+ F_TXDEFERENABLE | F_HEARBEATDACK | F_TXCONGESTIONMODE |
+ F_RXCONGESTIONMODE);
+ t3_set_reg_field(adap, A_TP_PC_CONFIG2, F_CHDRAFULL, 0);
+
+ if (adap->params.rev > 0) {
+ tp_wr_indirect(adap, A_TP_EGRESS_CONFIG, F_REWRITEFORCETOSIZE);
+ t3_set_reg_field(adap, A_TP_PARA_REG3, F_TXPACEAUTO,
+ F_TXPACEAUTO);
+ t3_set_reg_field(adap, A_TP_PC_CONFIG, F_LOCKTID, F_LOCKTID);
+ t3_set_reg_field(adap, A_TP_PARA_REG3, 0, F_TXPACEAUTOSTRICT);
+ } else
+ t3_set_reg_field(adap, A_TP_PARA_REG3, 0, F_TXPACEFIXED);
+
+ t3_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT1, 0x12121212);
+ t3_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT0, 0x12121212);
+ t3_write_reg(adap, A_TP_MOD_CHANNEL_WEIGHT, 0x1212);
+}
+
+/* Desired TP timer resolution in usec */
+#define TP_TMR_RES 50
+
+/* TCP timer values in ms */
+#define TP_DACK_TIMER 50
+#define TP_RTO_MIN 250
+
+/**
+ * tp_set_timers - set TP timing parameters
+ * @adap: the adapter to set
+ * @core_clk: the core clock frequency in Hz
+ *
+ * Set TP's timing parameters, such as the various timer resolutions and
+ * the TCP timer values.
+ */
+static void tp_set_timers(struct adapter *adap, unsigned int core_clk)
+{
+ unsigned int tre = fls(core_clk / (1000000 / TP_TMR_RES)) - 1;
+ unsigned int dack_re = fls(core_clk / 5000) - 1; /* 200us */
+ unsigned int tstamp_re = fls(core_clk / 1000); /* 1ms, at least */
+ unsigned int tps = core_clk >> tre;
+
+ t3_write_reg(adap, A_TP_TIMER_RESOLUTION, V_TIMERRESOLUTION(tre) |
+ V_DELAYEDACKRESOLUTION(dack_re) |
+ V_TIMESTAMPRESOLUTION(tstamp_re));
+ t3_write_reg(adap, A_TP_DACK_TIMER,
+ (core_clk >> dack_re) / (1000 / TP_DACK_TIMER));
+ t3_write_reg(adap, A_TP_TCP_BACKOFF_REG0, 0x3020100);
+ t3_write_reg(adap, A_TP_TCP_BACKOFF_REG1, 0x7060504);
+ t3_write_reg(adap, A_TP_TCP_BACKOFF_REG2, 0xb0a0908);
+ t3_write_reg(adap, A_TP_TCP_BACKOFF_REG3, 0xf0e0d0c);
+ t3_write_reg(adap, A_TP_SHIFT_CNT, V_SYNSHIFTMAX(6) |
+ V_RXTSHIFTMAXR1(4) | V_RXTSHIFTMAXR2(15) |
+ V_PERSHIFTBACKOFFMAX(8) | V_PERSHIFTMAX(8) |
+ V_KEEPALIVEMAX(9));
+
+#define SECONDS * tps
+
+ t3_write_reg(adap, A_TP_MSL, adap->params.rev > 0 ? 0 : 2 SECONDS);
+ t3_write_reg(adap, A_TP_RXT_MIN, tps / (1000 / TP_RTO_MIN));
+ t3_write_reg(adap, A_TP_RXT_MAX, 64 SECONDS);
+ t3_write_reg(adap, A_TP_PERS_MIN, 5 SECONDS);
+ t3_write_reg(adap, A_TP_PERS_MAX, 64 SECONDS);
+ t3_write_reg(adap, A_TP_KEEP_IDLE, 7200 SECONDS);
+ t3_write_reg(adap, A_TP_KEEP_INTVL, 75 SECONDS);
+ t3_write_reg(adap, A_TP_INIT_SRTT, 3 SECONDS);
+ t3_write_reg(adap, A_TP_FINWAIT2_TIMER, 600 SECONDS);
+
+#undef SECONDS
+}
+
+/**
+ * t3_tp_set_coalescing_size - set receive coalescing size
+ * @adap: the adapter
+ * @size: the receive coalescing size
+ * @psh: whether a set PSH bit should deliver coalesced data
+ *
+ * Set the receive coalescing size and PSH bit handling.
+ */
+int t3_tp_set_coalescing_size(struct adapter *adap, unsigned int size, int psh)
+{
+ u32 val;
+
+ if (size > MAX_RX_COALESCING_LEN)
+ return -EINVAL;
+
+ val = t3_read_reg(adap, A_TP_PARA_REG3);
+ val &= ~(F_RXCOALESCEENABLE | F_RXCOALESCEPSHEN);
+
+ if (size) {
+ val |= F_RXCOALESCEENABLE;
+ if (psh)
+ val |= F_RXCOALESCEPSHEN;
+ t3_write_reg(adap, A_TP_PARA_REG2, V_RXCOALESCESIZE(size) |
+ V_MAXRXDATA(MAX_RX_COALESCING_LEN));
+ }
+ t3_write_reg(adap, A_TP_PARA_REG3, val);
+ return 0;
+}
+
+/**
+ * t3_tp_set_max_rxsize - set the max receive size
+ * @adap: the adapter
+ * @size: the max receive size
+ *
+ * Set TP's max receive size. This is the limit that applies when
+ * receive coalescing is disabled.
+ */
+void t3_tp_set_max_rxsize(struct adapter *adap, unsigned int size)
+{
+ t3_write_reg(adap, A_TP_PARA_REG7,
+ V_PMMAXXFERLEN0(size) | V_PMMAXXFERLEN1(size));
+}
+
+static void __devinit init_mtus(unsigned short mtus[])
+{
+ /*
+ * See draft-mathis-plpmtud-00.txt for the values. The min is 88 so
+ * it can accomodate max size TCP/IP headers when SACK and timestamps
+ * are enabled and still have at least 8 bytes of payload.
+ */
+ mtus[0] = 88;
+ mtus[1] = 256;
+ mtus[2] = 512;
+ mtus[3] = 576;
+ mtus[4] = 808;
+ mtus[5] = 1024;
+ mtus[6] = 1280;
+ mtus[7] = 1492;
+ mtus[8] = 1500;
+ mtus[9] = 2002;
+ mtus[10] = 2048;
+ mtus[11] = 4096;
+ mtus[12] = 4352;
+ mtus[13] = 8192;
+ mtus[14] = 9000;
+ mtus[15] = 9600;
+}
+
+/*
+ * Initial congestion control parameters.
+ */
+static void __devinit init_cong_ctrl(unsigned short *a, unsigned short *b)
+{
+ a[0] = a[1] = a[2] = a[3] = a[4] = a[5] = a[6] = a[7] = a[8] = 1;
+ a[9] = 2;
+ a[10] = 3;
+ a[11] = 4;
+ a[12] = 5;
+ a[13] = 6;
+ a[14] = 7;
+ a[15] = 8;
+ a[16] = 9;
+ a[17] = 10;
+ a[18] = 14;
+ a[19] = 17;
+ a[20] = 21;
+ a[21] = 25;
+ a[22] = 30;
+ a[23] = 35;
+ a[24] = 45;
+ a[25] = 60;
+ a[26] = 80;
+ a[27] = 100;
+ a[28] = 200;
+ a[29] = 300;
+ a[30] = 400;
+ a[31] = 500;
+
+ b[0] = b[1] = b[2] = b[3] = b[4] = b[5] = b[6] = b[7] = b[8] = 0;
+ b[9] = b[10] = 1;
+ b[11] = b[12] = 2;
+ b[13] = b[14] = b[15] = b[16] = 3;
+ b[17] = b[18] = b[19] = b[20] = b[21] = 4;
+ b[22] = b[23] = b[24] = b[25] = b[26] = b[27] = 5;
+ b[28] = b[29] = 6;
+ b[30] = b[31] = 7;
+}
+
+/* The minimum additive increment value for the congestion control table */
+#define CC_MIN_INCR 2U
+
+/**
+ * t3_load_mtus - write the MTU and congestion control HW tables
+ * @adap: the adapter
+ * @mtus: the unrestricted values for the MTU table
+ * @alphs: the values for the congestion control alpha parameter
+ * @beta: the values for the congestion control beta parameter
+ * @mtu_cap: the maximum permitted effective MTU
+ *
+ * Write the MTU table with the supplied MTUs capping each at &mtu_cap.
+ * Update the high-speed congestion control table with the supplied alpha,
+ * beta, and MTUs.
+ */
+void t3_load_mtus(struct adapter *adap, unsigned short mtus[NMTUS],
+ unsigned short alpha[NCCTRL_WIN],
+ unsigned short beta[NCCTRL_WIN], unsigned short mtu_cap)
+{
+ static const unsigned int avg_pkts[NCCTRL_WIN] = {
+ 2, 6, 10, 14, 20, 28, 40, 56, 80, 112, 160, 224, 320, 448, 640,
+ 896, 1281, 1792, 2560, 3584, 5120, 7168, 10240, 14336, 20480,
+ 28672, 40960, 57344, 81920, 114688, 163840, 229376
+ };
+
+ unsigned int i, w;
+
+ for (i = 0; i < NMTUS; ++i) {
+ unsigned int mtu = min(mtus[i], mtu_cap);
+ unsigned int log2 = fls(mtu);
+
+ if (!(mtu & ((1 << log2) >> 2))) /* round */
+ log2--;
+ t3_write_reg(adap, A_TP_MTU_TABLE,
+ (i << 24) | (log2 << 16) | mtu);
+
+ for (w = 0; w < NCCTRL_WIN; ++w) {
+ unsigned int inc;
+
+ inc = max(((mtu - 40) * alpha[w]) / avg_pkts[w],
+ CC_MIN_INCR);
+
+ t3_write_reg(adap, A_TP_CCTRL_TABLE, (i << 21) |
+ (w << 16) | (beta[w] << 13) | inc);
+ }
+ }
+}
+
+/**
+ * t3_read_hw_mtus - returns the values in the HW MTU table
+ * @adap: the adapter
+ * @mtus: where to store the HW MTU values
+ *
+ * Reads the HW MTU table.
+ */
+void t3_read_hw_mtus(struct adapter *adap, unsigned short mtus[NMTUS])
+{
+ int i;
+
+ for (i = 0; i < NMTUS; ++i) {
+ unsigned int val;
+
+ t3_write_reg(adap, A_TP_MTU_TABLE, 0xff000000 | i);
+ val = t3_read_reg(adap, A_TP_MTU_TABLE);
+ mtus[i] = val & 0x3fff;
+ }
+}
+
+/**
+ * t3_get_cong_cntl_tab - reads the congestion control table
+ * @adap: the adapter
+ * @incr: where to store the alpha values
+ *
+ * Reads the additive increments programmed into the HW congestion
+ * control table.
+ */
+void t3_get_cong_cntl_tab(struct adapter *adap,
+ unsigned short incr[NMTUS][NCCTRL_WIN])
+{
+ unsigned int mtu, w;
+
+ for (mtu = 0; mtu < NMTUS; ++mtu)
+ for (w = 0; w < NCCTRL_WIN; ++w) {
+ t3_write_reg(adap, A_TP_CCTRL_TABLE,
+ 0xffff0000 | (mtu << 5) | w);
+ incr[mtu][w] = t3_read_reg(adap, A_TP_CCTRL_TABLE) &
+ 0x1fff;
+ }
+}
+
+/**
+ * t3_tp_get_mib_stats - read TP's MIB counters
+ * @adap: the adapter
+ * @tps: holds the returned counter values
+ *
+ * Returns the values of TP's MIB counters.
+ */
+void t3_tp_get_mib_stats(struct adapter *adap, struct tp_mib_stats *tps)
+{
+ t3_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_RDATA, (u32 *) tps,
+ sizeof(*tps) / sizeof(u32), 0);
+}
+
+#define ulp_region(adap, name, start, len) \
+ t3_write_reg((adap), A_ULPRX_ ## name ## _LLIMIT, (start)); \
+ t3_write_reg((adap), A_ULPRX_ ## name ## _ULIMIT, \
+ (start) + (len) - 1); \
+ start += len
+
+#define ulptx_region(adap, name, start, len) \
+ t3_write_reg((adap), A_ULPTX_ ## name ## _LLIMIT, (start)); \
+ t3_write_reg((adap), A_ULPTX_ ## name ## _ULIMIT, \
+ (start) + (len) - 1)
+
+static void ulp_config(struct adapter *adap, const struct tp_params *p)
+{
+ unsigned int m = p->chan_rx_size;
+
+ ulp_region(adap, ISCSI, m, p->chan_rx_size / 8);
+ ulp_region(adap, TDDP, m, p->chan_rx_size / 8);
+ ulptx_region(adap, TPT, m, p->chan_rx_size / 4);
+ ulp_region(adap, STAG, m, p->chan_rx_size / 4);
+ ulp_region(adap, RQ, m, p->chan_rx_size / 4);
+ ulptx_region(adap, PBL, m, p->chan_rx_size / 4);
+ ulp_region(adap, PBL, m, p->chan_rx_size / 4);
+ t3_write_reg(adap, A_ULPRX_TDDP_TAGMASK, 0xffffffff);
+}
+
+void t3_config_trace_filter(struct adapter *adapter,
+ const struct trace_params *tp, int filter_index,
+ int invert, int enable)
+{
+ u32 addr, key[4], mask[4];
+
+ key[0] = tp->sport | (tp->sip << 16);
+ key[1] = (tp->sip >> 16) | (tp->dport << 16);
+ key[2] = tp->dip;
+ key[3] = tp->proto | (tp->vlan << 8) | (tp->intf << 20);
+
+ mask[0] = tp->sport_mask | (tp->sip_mask << 16);
+ mask[1] = (tp->sip_mask >> 16) | (tp->dport_mask << 16);
+ mask[2] = tp->dip_mask;
+ mask[3] = tp->proto_mask | (tp->vlan_mask << 8) | (tp->intf_mask << 20);
+
+ if (invert)
+ key[3] |= (1 << 29);
+ if (enable)
+ key[3] |= (1 << 28);
+
+ addr = filter_index ? A_TP_RX_TRC_KEY0 : A_TP_TX_TRC_KEY0;
+ tp_wr_indirect(adapter, addr++, key[0]);
+ tp_wr_indirect(adapter, addr++, mask[0]);
+ tp_wr_indirect(adapter, addr++, key[1]);
+ tp_wr_indirect(adapter, addr++, mask[1]);
+ tp_wr_indirect(adapter, addr++, key[2]);
+ tp_wr_indirect(adapter, addr++, mask[2]);
+ tp_wr_indirect(adapter, addr++, key[3]);
+ tp_wr_indirect(adapter, addr, mask[3]);
+ t3_read_reg(adapter, A_TP_PIO_DATA);
+}
+
+/**
+ * t3_config_sched - configure a HW traffic scheduler
+ * @adap: the adapter
+ * @kbps: target rate in Kbps
+ * @sched: the scheduler index
+ *
+ * Configure a HW scheduler for the target rate
+ */
+int t3_config_sched(struct adapter *adap, unsigned int kbps, int sched)
+{
+ unsigned int v, tps, cpt, bpt, delta, mindelta = ~0;
+ unsigned int clk = adap->params.vpd.cclk * 1000;
+ unsigned int selected_cpt = 0, selected_bpt = 0;
+
+ if (kbps > 0) {
+ kbps *= 125; /* -> bytes */
+ for (cpt = 1; cpt <= 255; cpt++) {
+ tps = clk / cpt;
+ bpt = (kbps + tps / 2) / tps;
+ if (bpt > 0 && bpt <= 255) {
+ v = bpt * tps;
+ delta = v >= kbps ? v - kbps : kbps - v;
+ if (delta <= mindelta) {
+ mindelta = delta;
+ selected_cpt = cpt;
+ selected_bpt = bpt;
+ }
+ } else if (selected_cpt)
+ break;
+ }
+ if (!selected_cpt)
+ return -EINVAL;
+ }
+ t3_write_reg(adap, A_TP_TM_PIO_ADDR,
+ A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2);
+ v = t3_read_reg(adap, A_TP_TM_PIO_DATA);
+ if (sched & 1)
+ v = (v & 0xffff) | (selected_cpt << 16) | (selected_bpt << 24);
+ else
+ v = (v & 0xffff0000) | selected_cpt | (selected_bpt << 8);
+ t3_write_reg(adap, A_TP_TM_PIO_DATA, v);
+ return 0;
+}
+
+static int tp_init(struct adapter *adap, const struct tp_params *p)
+{
+ int busy = 0;
+
+ tp_config(adap, p);
+ t3_set_vlan_accel(adap, 3, 0);
+
+ if (is_offload(adap)) {
+ tp_set_timers(adap, adap->params.vpd.cclk * 1000);
+ t3_write_reg(adap, A_TP_RESET, F_FLSTINITENABLE);
+ busy = t3_wait_op_done(adap, A_TP_RESET, F_FLSTINITENABLE,
+ 0, 1000, 5);
+ if (busy)
+ CH_ERR(adap, "TP initialization timed out\n");
+ }
+
+ if (!busy)
+ t3_write_reg(adap, A_TP_RESET, F_TPRESET);
+ return busy;
+}
+
+int t3_mps_set_active_ports(struct adapter *adap, unsigned int port_mask)
+{
+ if (port_mask & ~((1 << adap->params.nports) - 1))
+ return -EINVAL;
+ t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE | F_PORT0ACTIVE,
+ port_mask << S_PORT0ACTIVE);
+ return 0;
+}
+
+/*
+ * Perform the bits of HW initialization that are dependent on the number
+ * of available ports.
+ */
+static void init_hw_for_avail_ports(struct adapter *adap, int nports)
+{
+ int i;
+
+ if (nports == 1) {
+ t3_set_reg_field(adap, A_ULPRX_CTL, F_ROUND_ROBIN, 0);
+ t3_set_reg_field(adap, A_ULPTX_CONFIG, F_CFG_RR_ARB, 0);
+ t3_write_reg(adap, A_MPS_CFG, F_TPRXPORTEN | F_TPTXPORT0EN |
+ F_PORT0ACTIVE | F_ENFORCEPKT);
+ t3_write_reg(adap, A_PM1_TX_CFG, 0xc000c000);
+ } else {
+ t3_set_reg_field(adap, A_ULPRX_CTL, 0, F_ROUND_ROBIN);
+ t3_set_reg_field(adap, A_ULPTX_CONFIG, 0, F_CFG_RR_ARB);
+ t3_write_reg(adap, A_ULPTX_DMA_WEIGHT,
+ V_D1_WEIGHT(16) | V_D0_WEIGHT(16));
+ t3_write_reg(adap, A_MPS_CFG, F_TPTXPORT0EN | F_TPTXPORT1EN |
+ F_TPRXPORTEN | F_PORT0ACTIVE | F_PORT1ACTIVE |
+ F_ENFORCEPKT);
+ t3_write_reg(adap, A_PM1_TX_CFG, 0x80008000);
+ t3_set_reg_field(adap, A_TP_PC_CONFIG, 0, F_TXTOSQUEUEMAPMODE);
+ t3_write_reg(adap, A_TP_TX_MOD_QUEUE_REQ_MAP,
+ V_TX_MOD_QUEUE_REQ_MAP(0xaa));
+ for (i = 0; i < 16; i++)
+ t3_write_reg(adap, A_TP_TX_MOD_QUE_TABLE,
+ (i << 16) | 0x1010);
+ }
+}
+
+static int calibrate_xgm(struct adapter *adapter)
+{
+ if (uses_xaui(adapter)) {
+ unsigned int v, i;
+
+ for (i = 0; i < 5; ++i) {
+ t3_write_reg(adapter, A_XGM_XAUI_IMP, 0);
+ t3_read_reg(adapter, A_XGM_XAUI_IMP);
+ msleep(1);
+ v = t3_read_reg(adapter, A_XGM_XAUI_IMP);
+ if (!(v & (F_XGM_CALFAULT | F_CALBUSY))) {
+ t3_write_reg(adapter, A_XGM_XAUI_IMP,
+ V_XAUIIMP(G_CALIMP(v) >> 2));
+ return 0;
+ }
+ }
+ CH_ERR(adapter, "MAC calibration failed\n");
+ return -1;
+ } else {
+ t3_write_reg(adapter, A_XGM_RGMII_IMP,
+ V_RGMIIIMPPD(2) | V_RGMIIIMPPU(3));
+ t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_XGM_IMPSETUPDATE,
+ F_XGM_IMPSETUPDATE);
+ }
+ return 0;
+}
+
+static void calibrate_xgm_t3b(struct adapter *adapter)
+{
+ if (!uses_xaui(adapter)) {
+ t3_write_reg(adapter, A_XGM_RGMII_IMP, F_CALRESET |
+ F_CALUPDATE | V_RGMIIIMPPD(2) | V_RGMIIIMPPU(3));
+ t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_CALRESET, 0);
+ t3_set_reg_field(adapter, A_XGM_RGMII_IMP, 0,
+ F_XGM_IMPSETUPDATE);
+ t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_XGM_IMPSETUPDATE,
+ 0);
+ t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_CALUPDATE, 0);
+ t3_set_reg_field(adapter, A_XGM_RGMII_IMP, 0, F_CALUPDATE);
+ }
+}
+
+struct mc7_timing_params {
+ unsigned char ActToPreDly;
+ unsigned char ActToRdWrDly;
+ unsigned char PreCyc;
+ unsigned char RefCyc[5];
+ unsigned char BkCyc;
+ unsigned char WrToRdDly;
+ unsigned char RdToWrDly;
+};
+
+/*
+ * Write a value to a register and check that the write completed. These
+ * writes normally complete in a cycle or two, so one read should suffice.
+ * The very first read exists to flush the posted write to the device.
+ */
+static int wrreg_wait(struct adapter *adapter, unsigned int addr, u32 val)
+{
+ t3_write_reg(adapter, addr, val);
+ t3_read_reg(adapter, addr); /* flush */
+ if (!(t3_read_reg(adapter, addr) & F_BUSY))
+ return 0;
+ CH_ERR(adapter, "write to MC7 register 0x%x timed out\n", addr);
+ return -EIO;
+}
+
+static int mc7_init(struct mc7 *mc7, unsigned int mc7_clock, int mem_type)
+{
+ static const unsigned int mc7_mode[] = {
+ 0x632, 0x642, 0x652, 0x432, 0x442
+ };
+ static const struct mc7_timing_params mc7_timings[] = {
+ {12, 3, 4, {20, 28, 34, 52, 0}, 15, 6, 4},
+ {12, 4, 5, {20, 28, 34, 52, 0}, 16, 7, 4},
+ {12, 5, 6, {20, 28, 34, 52, 0}, 17, 8, 4},
+ {9, 3, 4, {15, 21, 26, 39, 0}, 12, 6, 4},
+ {9, 4, 5, {15, 21, 26, 39, 0}, 13, 7, 4}
+ };
+
+ u32 val;
+ unsigned int width, density, slow, attempts;
+ struct adapter *adapter = mc7->adapter;
+ const struct mc7_timing_params *p = &mc7_timings[mem_type];
+
+ val = t3_read_reg(adapter, mc7->offset + A_MC7_CFG);
+ slow = val & F_SLOW;
+ width = G_WIDTH(val);
+ density = G_DEN(val);
+
+ t3_write_reg(adapter, mc7->offset + A_MC7_CFG, val | F_IFEN);
+ val = t3_read_reg(adapter, mc7->offset + A_MC7_CFG); /* flush */
+ msleep(1);
+
+ if (!slow) {
+ t3_write_reg(adapter, mc7->offset + A_MC7_CAL, F_SGL_CAL_EN);
+ t3_read_reg(adapter, mc7->offset + A_MC7_CAL);
+ msleep(1);
+ if (t3_read_reg(adapter, mc7->offset + A_MC7_CAL) &
+ (F_BUSY | F_SGL_CAL_EN | F_CAL_FAULT)) {
+ CH_ERR(adapter, "%s MC7 calibration timed out\n",
+ mc7->name);
+ goto out_fail;
+ }
+ }
+
+ t3_write_reg(adapter, mc7->offset + A_MC7_PARM,
+ V_ACTTOPREDLY(p->ActToPreDly) |
+ V_ACTTORDWRDLY(p->ActToRdWrDly) | V_PRECYC(p->PreCyc) |
+ V_REFCYC(p->RefCyc[density]) | V_BKCYC(p->BkCyc) |
+ V_WRTORDDLY(p->WrToRdDly) | V_RDTOWRDLY(p->RdToWrDly));
+
+ t3_write_reg(adapter, mc7->offset + A_MC7_CFG,
+ val | F_CLKEN | F_TERM150);
+ t3_read_reg(adapter, mc7->offset + A_MC7_CFG); /* flush */
+
+ if (!slow)
+ t3_set_reg_field(adapter, mc7->offset + A_MC7_DLL, F_DLLENB,
+ F_DLLENB);
+ udelay(1);
+
+ val = slow ? 3 : 6;
+ if (wrreg_wait(adapter, mc7->offset + A_MC7_PRE, 0) ||
+ wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE2, 0) ||
+ wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE3, 0) ||
+ wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE1, val))
+ goto out_fail;
+
+ if (!slow) {
+ t3_write_reg(adapter, mc7->offset + A_MC7_MODE, 0x100);
+ t3_set_reg_field(adapter, mc7->offset + A_MC7_DLL, F_DLLRST, 0);
+ udelay(5);
+ }
+
+ if (wrreg_wait(adapter, mc7->offset + A_MC7_PRE, 0) ||
+ wrreg_wait(adapter, mc7->offset + A_MC7_REF, 0) ||
+ wrreg_wait(adapter, mc7->offset + A_MC7_REF, 0) ||
+ wrreg_wait(adapter, mc7->offset + A_MC7_MODE,
+ mc7_mode[mem_type]) ||
+ wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE1, val | 0x380) ||
+ wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE1, val))
+ goto out_fail;
+
+ /* clock value is in KHz */
+ mc7_clock = mc7_clock * 7812 + mc7_clock / 2; /* ns */
+ mc7_clock /= 1000000; /* KHz->MHz, ns->us */
+
+ t3_write_reg(adapter, mc7->offset + A_MC7_REF,
+ F_PERREFEN | V_PREREFDIV(mc7_clock));
+ t3_read_reg(adapter, mc7->offset + A_MC7_REF); /* flush */
+
+ t3_write_reg(adapter, mc7->offset + A_MC7_ECC, F_ECCGENEN | F_ECCCHKEN);
+ t3_write_reg(adapter, mc7->offset + A_MC7_BIST_DATA, 0);
+ t3_write_reg(adapter, mc7->offset + A_MC7_BIST_ADDR_BEG, 0);
+ t3_write_reg(adapter, mc7->offset + A_MC7_BIST_ADDR_END,
+ (mc7->size << width) - 1);
+ t3_write_reg(adapter, mc7->offset + A_MC7_BIST_OP, V_OP(1));
+ t3_read_reg(adapter, mc7->offset + A_MC7_BIST_OP); /* flush */
+
+ attempts = 50;
+ do {
+ msleep(250);
+ val = t3_read_reg(adapter, mc7->offset + A_MC7_BIST_OP);
+ } while ((val & F_BUSY) && --attempts);
+ if (val & F_BUSY) {
+ CH_ERR(adapter, "%s MC7 BIST timed out\n", mc7->name);
+ goto out_fail;
+ }
+
+ /* Enable normal memory accesses. */
+ t3_set_reg_field(adapter, mc7->offset + A_MC7_CFG, 0, F_RDY);
+ return 0;
+
+out_fail:
+ return -1;
+}
+
+static void config_pcie(struct adapter *adap)
+{
+ static const u16 ack_lat[4][6] = {
+ {237, 416, 559, 1071, 2095, 4143},
+ {128, 217, 289, 545, 1057, 2081},
+ {73, 118, 154, 282, 538, 1050},
+ {67, 107, 86, 150, 278, 534}
+ };
+ static const u16 rpl_tmr[4][6] = {
+ {711, 1248, 1677, 3213, 6285, 12429},
+ {384, 651, 867, 1635, 3171, 6243},
+ {219, 354, 462, 846, 1614, 3150},
+ {201, 321, 258, 450, 834, 1602}
+ };
+
+ u16 val;
+ unsigned int log2_width, pldsize;
+ unsigned int fst_trn_rx, fst_trn_tx, acklat, rpllmt;
+
+ pci_read_config_word(adap->pdev,
+ adap->params.pci.pcie_cap_addr + PCI_EXP_DEVCTL,
+ &val);
+ pldsize = (val & PCI_EXP_DEVCTL_PAYLOAD) >> 5;
+ pci_read_config_word(adap->pdev,
+ adap->params.pci.pcie_cap_addr + PCI_EXP_LNKCTL,
+ &val);
+
+ fst_trn_tx = G_NUMFSTTRNSEQ(t3_read_reg(adap, A_PCIE_PEX_CTRL0));
+ fst_trn_rx = adap->params.rev == 0 ? fst_trn_tx :
+ G_NUMFSTTRNSEQRX(t3_read_reg(adap, A_PCIE_MODE));
+ log2_width = fls(adap->params.pci.width) - 1;
+ acklat = ack_lat[log2_width][pldsize];
+ if (val & 1) /* check LOsEnable */
+ acklat += fst_trn_tx * 4;
+ rpllmt = rpl_tmr[log2_width][pldsize] + fst_trn_rx * 4;
+
+ if (adap->params.rev == 0)
+ t3_set_reg_field(adap, A_PCIE_PEX_CTRL1,
+ V_T3A_ACKLAT(M_T3A_ACKLAT),
+ V_T3A_ACKLAT(acklat));
+ else
+ t3_set_reg_field(adap, A_PCIE_PEX_CTRL1, V_ACKLAT(M_ACKLAT),
+ V_ACKLAT(acklat));
+
+ t3_set_reg_field(adap, A_PCIE_PEX_CTRL0, V_REPLAYLMT(M_REPLAYLMT),
+ V_REPLAYLMT(rpllmt));
+
+ t3_write_reg(adap, A_PCIE_PEX_ERR, 0xffffffff);
+ t3_set_reg_field(adap, A_PCIE_CFG, F_PCIE_CLIDECEN, F_PCIE_CLIDECEN);
+}
+
+/*
+ * Initialize and configure T3 HW modules. This performs the
+ * initialization steps that need to be done once after a card is reset.
+ * MAC and PHY initialization is handled separarely whenever a port is enabled.
+ *
+ * fw_params are passed to FW and their value is platform dependent. Only the
+ * top 8 bits are available for use, the rest must be 0.
+ */
+int t3_init_hw(struct adapter *adapter, u32 fw_params)
+{
+ int err = -EIO, attempts = 100;
+ const struct vpd_params *vpd = &adapter->params.vpd;
+
+ if (adapter->params.rev > 0)
+ calibrate_xgm_t3b(adapter);
+ else if (calibrate_xgm(adapter))
+ goto out_err;
+
+ if (vpd->mclk) {
+ partition_mem(adapter, &adapter->params.tp);
+
+ if (mc7_init(&adapter->pmrx, vpd->mclk, vpd->mem_timing) ||
+ mc7_init(&adapter->pmtx, vpd->mclk, vpd->mem_timing) ||
+ mc7_init(&adapter->cm, vpd->mclk, vpd->mem_timing) ||
+ t3_mc5_init(&adapter->mc5, adapter->params.mc5.nservers,
+ adapter->params.mc5.nfilters,
+ adapter->params.mc5.nroutes))
+ goto out_err;
+ }
+
+ if (tp_init(adapter, &adapter->params.tp))
+ goto out_err;
+
+ t3_tp_set_coalescing_size(adapter,
+ min(adapter->params.sge.max_pkt_size,
+ MAX_RX_COALESCING_LEN), 1);
+ t3_tp_set_max_rxsize(adapter,
+ min(adapter->params.sge.max_pkt_size, 16384U));
+ ulp_config(adapter, &adapter->params.tp);
+
+ if (is_pcie(adapter))
+ config_pcie(adapter);
+ else
+ t3_set_reg_field(adapter, A_PCIX_CFG, 0, F_CLIDECEN);
+
+ t3_write_reg(adapter, A_PM1_RX_CFG, 0xf000f000);
+ init_hw_for_avail_ports(adapter, adapter->params.nports);
+ t3_sge_init(adapter, &adapter->params.sge);
+
+ t3_write_reg(adapter, A_CIM_HOST_ACC_DATA, vpd->uclk | fw_params);
+ t3_write_reg(adapter, A_CIM_BOOT_CFG,
+ V_BOOTADDR(FW_FLASH_BOOT_ADDR >> 2));
+ t3_read_reg(adapter, A_CIM_BOOT_CFG); /* flush */
+
+ do { /* wait for uP to initialize */
+ msleep(20);
+ } while (t3_read_reg(adapter, A_CIM_HOST_ACC_DATA) && --attempts);
+ if (!attempts)
+ goto out_err;
+
+ err = 0;
+out_err:
+ return err;
+}
+
+/**
+ * get_pci_mode - determine a card's PCI mode
+ * @adapter: the adapter
+ * @p: where to store the PCI settings
+ *
+ * Determines a card's PCI mode and associated parameters, such as speed
+ * and width.
+ */
+static void __devinit get_pci_mode(struct adapter *adapter,
+ struct pci_params *p)
+{
+ static unsigned short speed_map[] = { 33, 66, 100, 133 };
+ u32 pci_mode, pcie_cap;
+
+ pcie_cap = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP);
+ if (pcie_cap) {
+ u16 val;
+
+ p->variant = PCI_VARIANT_PCIE;
+ p->pcie_cap_addr = pcie_cap;
+ pci_read_config_word(adapter->pdev, pcie_cap + PCI_EXP_LNKSTA,
+ &val);
+ p->width = (val >> 4) & 0x3f;
+ return;
+ }
+
+ pci_mode = t3_read_reg(adapter, A_PCIX_MODE);
+ p->speed = speed_map[G_PCLKRANGE(pci_mode)];
+ p->width = (pci_mode & F_64BIT) ? 64 : 32;
+ pci_mode = G_PCIXINITPAT(pci_mode);
+ if (pci_mode == 0)
+ p->variant = PCI_VARIANT_PCI;
+ else if (pci_mode < 4)
+ p->variant = PCI_VARIANT_PCIX_MODE1_PARITY;
+ else if (pci_mode < 8)
+ p->variant = PCI_VARIANT_PCIX_MODE1_ECC;
+ else
+ p->variant = PCI_VARIANT_PCIX_266_MODE2;
+}
+
+/**
+ * init_link_config - initialize a link's SW state
+ * @lc: structure holding the link state
+ * @ai: information about the current card
+ *
+ * Initializes the SW state maintained for each link, including the link's
+ * capabilities and default speed/duplex/flow-control/autonegotiation
+ * settings.
+ */
+static void __devinit init_link_config(struct link_config *lc,
+ unsigned int caps)
+{
+ lc->supported = caps;
+ lc->requested_speed = lc->speed = SPEED_INVALID;
+ lc->requested_duplex = lc->duplex = DUPLEX_INVALID;
+ lc->requested_fc = lc->fc = PAUSE_RX | PAUSE_TX;
+ if (lc->supported & SUPPORTED_Autoneg) {
+ lc->advertising = lc->supported;
+ lc->autoneg = AUTONEG_ENABLE;
+ lc->requested_fc |= PAUSE_AUTONEG;
+ } else {
+ lc->advertising = 0;
+ lc->autoneg = AUTONEG_DISABLE;
+ }
+}
+
+/**
+ * mc7_calc_size - calculate MC7 memory size
+ * @cfg: the MC7 configuration
+ *
+ * Calculates the size of an MC7 memory in bytes from the value of its
+ * configuration register.
+ */
+static unsigned int __devinit mc7_calc_size(u32 cfg)
+{
+ unsigned int width = G_WIDTH(cfg);
+ unsigned int banks = !!(cfg & F_BKS) + 1;
+ unsigned int org = !!(cfg & F_ORG) + 1;
+ unsigned int density = G_DEN(cfg);
+ unsigned int MBs = ((256 << density) * banks) / (org << width);
+
+ return MBs << 20;
+}
+
+static void __devinit mc7_prep(struct adapter *adapter, struct mc7 *mc7,
+ unsigned int base_addr, const char *name)
+{
+ u32 cfg;
+
+ mc7->adapter = adapter;
+ mc7->name = name;
+ mc7->offset = base_addr - MC7_PMRX_BASE_ADDR;
+ cfg = t3_read_reg(adapter, mc7->offset + A_MC7_CFG);
+ mc7->size = mc7_calc_size(cfg);
+ mc7->width = G_WIDTH(cfg);
+}
+
+void mac_prep(struct cmac *mac, struct adapter *adapter, int index)
+{
+ mac->adapter = adapter;
+ mac->offset = (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR) * index;
+ mac->nucast = 1;
+
+ if (adapter->params.rev == 0 && uses_xaui(adapter)) {
+ t3_write_reg(adapter, A_XGM_SERDES_CTRL + mac->offset,
+ is_10G(adapter) ? 0x2901c04 : 0x2301c04);
+ t3_set_reg_field(adapter, A_XGM_PORT_CFG + mac->offset,
+ F_ENRGMII, 0);
+ }
+}
+
+void early_hw_init(struct adapter *adapter, const struct adapter_info *ai)
+{
+ u32 val = V_PORTSPEED(is_10G(adapter) ? 3 : 2);
+
+ mi1_init(adapter, ai);
+ t3_write_reg(adapter, A_I2C_CFG, /* set for 80KHz */
+ V_I2C_CLKDIV(adapter->params.vpd.cclk / 80 - 1));
+ t3_write_reg(adapter, A_T3DBG_GPIO_EN,
+ ai->gpio_out | F_GPIO0_OEN | F_GPIO0_OUT_VAL);
+
+ if (adapter->params.rev == 0 || !uses_xaui(adapter))
+ val |= F_ENRGMII;
+
+ /* Enable MAC clocks so we can access the registers */
+ t3_write_reg(adapter, A_XGM_PORT_CFG, val);
+ t3_read_reg(adapter, A_XGM_PORT_CFG);
+
+ val |= F_CLKDIVRESET_;
+ t3_write_reg(adapter, A_XGM_PORT_CFG, val);
+ t3_read_reg(adapter, A_XGM_PORT_CFG);
+ t3_write_reg(adapter, XGM_REG(A_XGM_PORT_CFG, 1), val);
+ t3_read_reg(adapter, A_XGM_PORT_CFG);
+}
+
+/*
+ * Reset the adapter. PCIe cards lose their config space during reset, PCI-X
+ * ones don't.
+ */
+int t3_reset_adapter(struct adapter *adapter)
+{
+ int i;
+ uint16_t devid = 0;
+
+ if (is_pcie(adapter))
+ pci_save_state(adapter->pdev);
+ t3_write_reg(adapter, A_PL_RST, F_CRSTWRM | F_CRSTWRMMODE);
+
+ /*
+ * Delay. Give Some time to device to reset fully.
+ * XXX The delay time should be modified.
+ */
+ for (i = 0; i < 10; i++) {
+ msleep(50);
+ pci_read_config_word(adapter->pdev, 0x00, &devid);
+ if (devid == 0x1425)
+ break;
+ }
+
+ if (devid != 0x1425)
+ return -1;
+
+ if (is_pcie(adapter))
+ pci_restore_state(adapter->pdev);
+ return 0;
+}
+
+/*
+ * Initialize adapter SW state for the various HW modules, set initial values
+ * for some adapter tunables, take PHYs out of reset, and initialize the MDIO
+ * interface.
+ */
+int __devinit t3_prep_adapter(struct adapter *adapter,
+ const struct adapter_info *ai, int reset)
+{
+ int ret;
+ unsigned int i, j = 0;
+
+ get_pci_mode(adapter, &adapter->params.pci);
+
+ adapter->params.info = ai;
+ adapter->params.nports = ai->nports;
+ adapter->params.rev = t3_read_reg(adapter, A_PL_REV);
+ adapter->params.linkpoll_period = 0;
+ adapter->params.stats_update_period = is_10G(adapter) ?
+ MAC_STATS_ACCUM_SECS : (MAC_STATS_ACCUM_SECS * 10);
+ adapter->params.pci.vpd_cap_addr =
+ pci_find_capability(adapter->pdev, PCI_CAP_ID_VPD);
+ ret = get_vpd_params(adapter, &adapter->params.vpd);
+ if (ret < 0)
+ return ret;
+
+ if (reset && t3_reset_adapter(adapter))
+ return -1;
+
+ t3_sge_prep(adapter, &adapter->params.sge);
+
+ if (adapter->params.vpd.mclk) {
+ struct tp_params *p = &adapter->params.tp;
+
+ mc7_prep(adapter, &adapter->pmrx, MC7_PMRX_BASE_ADDR, "PMRX");
+ mc7_prep(adapter, &adapter->pmtx, MC7_PMTX_BASE_ADDR, "PMTX");
+ mc7_prep(adapter, &adapter->cm, MC7_CM_BASE_ADDR, "CM");
+
+ p->nchan = ai->nports;
+ p->pmrx_size = t3_mc7_size(&adapter->pmrx);
+ p->pmtx_size = t3_mc7_size(&adapter->pmtx);
+ p->cm_size = t3_mc7_size(&adapter->cm);
+ p->chan_rx_size = p->pmrx_size / 2; /* only 1 Rx channel */
+ p->chan_tx_size = p->pmtx_size / p->nchan;
+ p->rx_pg_size = 64 * 1024;
+ p->tx_pg_size = is_10G(adapter) ? 64 * 1024 : 16 * 1024;
+ p->rx_num_pgs = pm_num_pages(p->chan_rx_size, p->rx_pg_size);
+ p->tx_num_pgs = pm_num_pages(p->chan_tx_size, p->tx_pg_size);
+ p->ntimer_qs = p->cm_size >= (128 << 20) ||
+ adapter->params.rev > 0 ? 12 : 6;
+
+ adapter->params.mc5.nservers = DEFAULT_NSERVERS;
+ adapter->params.mc5.nfilters = adapter->params.rev > 0 ?
+ DEFAULT_NFILTERS : 0;
+ adapter->params.mc5.nroutes = 0;
+ t3_mc5_prep(adapter, &adapter->mc5, MC5_MODE_144_BIT);
+
+ init_mtus(adapter->params.mtus);
+ init_cong_ctrl(adapter->params.a_wnd, adapter->params.b_wnd);
+ }
+
+ early_hw_init(adapter, ai);
+
+ for_each_port(adapter, i) {
+ u8 hw_addr[6];
+ struct port_info *p = adap2pinfo(adapter, i);
+
+ while (!adapter->params.vpd.port_type[j])
+ ++j;
+
+ p->port_type = &port_types[adapter->params.vpd.port_type[j]];
+ p->port_type->phy_prep(&p->phy, adapter, ai->phy_base_addr + j,
+ ai->mdio_ops);
+ mac_prep(&p->mac, adapter, j);
+ ++j;
+
+ /*
+ * The VPD EEPROM stores the base Ethernet address for the
+ * card. A port's address is derived from the base by adding
+ * the port's index to the base's low octet.
+ */
+ memcpy(hw_addr, adapter->params.vpd.eth_base, 5);
+ hw_addr[5] = adapter->params.vpd.eth_base[5] + i;
+
+ memcpy(adapter->port[i]->dev_addr, hw_addr,
+ ETH_ALEN);
+ memcpy(adapter->port[i]->perm_addr, hw_addr,
+ ETH_ALEN);
+ init_link_config(&p->link_config, p->port_type->caps);
+ p->phy.ops->power_down(&p->phy, 1);
+ if (!(p->port_type->caps & SUPPORTED_IRQ))
+ adapter->params.linkpoll_period = 10;
+ }
+
+ return 0;
+}
+
+void t3_led_ready(struct adapter *adapter)
+{
+ t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL,
+ F_GPIO0_OUT_VAL);
+}
diff --git a/drivers/net/cxgb3/t3cdev.h b/drivers/net/cxgb3/t3cdev.h
new file mode 100644
index 00000000000..fa4099bc041
--- /dev/null
+++ b/drivers/net/cxgb3/t3cdev.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2006-2007 Chelsio Communications. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef _T3CDEV_H_
+#define _T3CDEV_H_
+
+#include <linux/list.h>
+#include <asm/atomic.h>
+#include <asm/semaphore.h>
+#include <linux/netdevice.h>
+#include <linux/proc_fs.h>
+#include <linux/skbuff.h>
+#include <net/neighbour.h>
+
+#define T3CNAMSIZ 16
+
+/* Get the t3cdev associated with a net_device */
+#define T3CDEV(netdev) (struct t3cdev *)(netdev->priv)
+
+struct cxgb3_client;
+
+enum t3ctype {
+ T3A = 0,
+ T3B
+};
+
+struct t3cdev {
+ char name[T3CNAMSIZ]; /* T3C device name */
+ enum t3ctype type;
+ struct list_head ofld_dev_list; /* for list linking */
+ struct net_device *lldev; /* LL dev associated with T3C messages */
+ struct proc_dir_entry *proc_dir; /* root of proc dir for this T3C */
+ int (*send)(struct t3cdev *dev, struct sk_buff *skb);
+ int (*recv)(struct t3cdev *dev, struct sk_buff **skb, int n);
+ int (*ctl)(struct t3cdev *dev, unsigned int req, void *data);
+ void (*neigh_update)(struct t3cdev *dev, struct neighbour *neigh);
+ void *priv; /* driver private data */
+ void *l2opt; /* optional layer 2 data */
+ void *l3opt; /* optional layer 3 data */
+ void *l4opt; /* optional layer 4 data */
+ void *ulp; /* ulp stuff */
+};
+
+#endif /* _T3CDEV_H_ */
diff --git a/drivers/net/cxgb3/version.h b/drivers/net/cxgb3/version.h
new file mode 100644
index 00000000000..2b67dd523cc
--- /dev/null
+++ b/drivers/net/cxgb3/version.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/* $Date: 2006/10/31 18:57:51 $ $RCSfile: version.h,v $ $Revision: 1.3 $ */
+#ifndef __CHELSIO_VERSION_H
+#define __CHELSIO_VERSION_H
+#define DRV_DESC "Chelsio T3 Network Driver"
+#define DRV_NAME "cxgb3"
+/* Driver version */
+#define DRV_VERSION "1.0"
+#endif /* __CHELSIO_VERSION_H */
diff --git a/drivers/net/cxgb3/vsc8211.c b/drivers/net/cxgb3/vsc8211.c
new file mode 100644
index 00000000000..eee4285b31b
--- /dev/null
+++ b/drivers/net/cxgb3/vsc8211.c
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 2005-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include "common.h"
+
+/* VSC8211 PHY specific registers. */
+enum {
+ VSC8211_INTR_ENABLE = 25,
+ VSC8211_INTR_STATUS = 26,
+ VSC8211_AUX_CTRL_STAT = 28,
+};
+
+enum {
+ VSC_INTR_RX_ERR = 1 << 0,
+ VSC_INTR_MS_ERR = 1 << 1, /* master/slave resolution error */
+ VSC_INTR_CABLE = 1 << 2, /* cable impairment */
+ VSC_INTR_FALSE_CARR = 1 << 3, /* false carrier */
+ VSC_INTR_MEDIA_CHG = 1 << 4, /* AMS media change */
+ VSC_INTR_RX_FIFO = 1 << 5, /* Rx FIFO over/underflow */
+ VSC_INTR_TX_FIFO = 1 << 6, /* Tx FIFO over/underflow */
+ VSC_INTR_DESCRAMBL = 1 << 7, /* descrambler lock-lost */
+ VSC_INTR_SYMBOL_ERR = 1 << 8, /* symbol error */
+ VSC_INTR_NEG_DONE = 1 << 10, /* autoneg done */
+ VSC_INTR_NEG_ERR = 1 << 11, /* autoneg error */
+ VSC_INTR_LINK_CHG = 1 << 13, /* link change */
+ VSC_INTR_ENABLE = 1 << 15, /* interrupt enable */
+};
+
+#define CFG_CHG_INTR_MASK (VSC_INTR_LINK_CHG | VSC_INTR_NEG_ERR | \
+ VSC_INTR_NEG_DONE)
+#define INTR_MASK (CFG_CHG_INTR_MASK | VSC_INTR_TX_FIFO | VSC_INTR_RX_FIFO | \
+ VSC_INTR_ENABLE)
+
+/* PHY specific auxiliary control & status register fields */
+#define S_ACSR_ACTIPHY_TMR 0
+#define M_ACSR_ACTIPHY_TMR 0x3
+#define V_ACSR_ACTIPHY_TMR(x) ((x) << S_ACSR_ACTIPHY_TMR)
+
+#define S_ACSR_SPEED 3
+#define M_ACSR_SPEED 0x3
+#define G_ACSR_SPEED(x) (((x) >> S_ACSR_SPEED) & M_ACSR_SPEED)
+
+#define S_ACSR_DUPLEX 5
+#define F_ACSR_DUPLEX (1 << S_ACSR_DUPLEX)
+
+#define S_ACSR_ACTIPHY 6
+#define F_ACSR_ACTIPHY (1 << S_ACSR_ACTIPHY)
+
+/*
+ * Reset the PHY. This PHY completes reset immediately so we never wait.
+ */
+static int vsc8211_reset(struct cphy *cphy, int wait)
+{
+ return t3_phy_reset(cphy, 0, 0);
+}
+
+static int vsc8211_intr_enable(struct cphy *cphy)
+{
+ return mdio_write(cphy, 0, VSC8211_INTR_ENABLE, INTR_MASK);
+}
+
+static int vsc8211_intr_disable(struct cphy *cphy)
+{
+ return mdio_write(cphy, 0, VSC8211_INTR_ENABLE, 0);
+}
+
+static int vsc8211_intr_clear(struct cphy *cphy)
+{
+ u32 val;
+
+ /* Clear PHY interrupts by reading the register. */
+ return mdio_read(cphy, 0, VSC8211_INTR_STATUS, &val);
+}
+
+static int vsc8211_autoneg_enable(struct cphy *cphy)
+{
+ return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE,
+ BMCR_ANENABLE | BMCR_ANRESTART);
+}
+
+static int vsc8211_autoneg_restart(struct cphy *cphy)
+{
+ return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE,
+ BMCR_ANRESTART);
+}
+
+static int vsc8211_get_link_status(struct cphy *cphy, int *link_ok,
+ int *speed, int *duplex, int *fc)
+{
+ unsigned int bmcr, status, lpa, adv;
+ int err, sp = -1, dplx = -1, pause = 0;
+
+ err = mdio_read(cphy, 0, MII_BMCR, &bmcr);
+ if (!err)
+ err = mdio_read(cphy, 0, MII_BMSR, &status);
+ if (err)
+ return err;
+
+ if (link_ok) {
+ /*
+ * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it
+ * once more to get the current link state.
+ */
+ if (!(status & BMSR_LSTATUS))
+ err = mdio_read(cphy, 0, MII_BMSR, &status);
+ if (err)
+ return err;
+ *link_ok = (status & BMSR_LSTATUS) != 0;
+ }
+ if (!(bmcr & BMCR_ANENABLE)) {
+ dplx = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
+ if (bmcr & BMCR_SPEED1000)
+ sp = SPEED_1000;
+ else if (bmcr & BMCR_SPEED100)
+ sp = SPEED_100;
+ else
+ sp = SPEED_10;
+ } else if (status & BMSR_ANEGCOMPLETE) {
+ err = mdio_read(cphy, 0, VSC8211_AUX_CTRL_STAT, &status);
+ if (err)
+ return err;
+
+ dplx = (status & F_ACSR_DUPLEX) ? DUPLEX_FULL : DUPLEX_HALF;
+ sp = G_ACSR_SPEED(status);
+ if (sp == 0)
+ sp = SPEED_10;
+ else if (sp == 1)
+ sp = SPEED_100;
+ else
+ sp = SPEED_1000;
+
+ if (fc && dplx == DUPLEX_FULL) {
+ err = mdio_read(cphy, 0, MII_LPA, &lpa);
+ if (!err)
+ err = mdio_read(cphy, 0, MII_ADVERTISE, &adv);
+ if (err)
+ return err;
+
+ if (lpa & adv & ADVERTISE_PAUSE_CAP)
+ pause = PAUSE_RX | PAUSE_TX;
+ else if ((lpa & ADVERTISE_PAUSE_CAP) &&
+ (lpa & ADVERTISE_PAUSE_ASYM) &&
+ (adv & ADVERTISE_PAUSE_ASYM))
+ pause = PAUSE_TX;
+ else if ((lpa & ADVERTISE_PAUSE_ASYM) &&
+ (adv & ADVERTISE_PAUSE_CAP))
+ pause = PAUSE_RX;
+ }
+ }
+ if (speed)
+ *speed = sp;
+ if (duplex)
+ *duplex = dplx;
+ if (fc)
+ *fc = pause;
+ return 0;
+}
+
+static int vsc8211_power_down(struct cphy *cphy, int enable)
+{
+ return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN,
+ enable ? BMCR_PDOWN : 0);
+}
+
+static int vsc8211_intr_handler(struct cphy *cphy)
+{
+ unsigned int cause;
+ int err, cphy_cause = 0;
+
+ err = mdio_read(cphy, 0, VSC8211_INTR_STATUS, &cause);
+ if (err)
+ return err;
+
+ cause &= INTR_MASK;
+ if (cause & CFG_CHG_INTR_MASK)
+ cphy_cause |= cphy_cause_link_change;
+ if (cause & (VSC_INTR_RX_FIFO | VSC_INTR_TX_FIFO))
+ cphy_cause |= cphy_cause_fifo_error;
+ return cphy_cause;
+}
+
+static struct cphy_ops vsc8211_ops = {
+ .reset = vsc8211_reset,
+ .intr_enable = vsc8211_intr_enable,
+ .intr_disable = vsc8211_intr_disable,
+ .intr_clear = vsc8211_intr_clear,
+ .intr_handler = vsc8211_intr_handler,
+ .autoneg_enable = vsc8211_autoneg_enable,
+ .autoneg_restart = vsc8211_autoneg_restart,
+ .advertise = t3_phy_advertise,
+ .set_speed_duplex = t3_set_phy_speed_duplex,
+ .get_link_status = vsc8211_get_link_status,
+ .power_down = vsc8211_power_down,
+};
+
+void t3_vsc8211_phy_prep(struct cphy *phy, struct adapter *adapter,
+ int phy_addr, const struct mdio_ops *mdio_ops)
+{
+ cphy_init(phy, adapter, phy_addr, &vsc8211_ops, mdio_ops);
+}
diff --git a/drivers/net/cxgb3/xgmac.c b/drivers/net/cxgb3/xgmac.c
new file mode 100644
index 00000000000..907a272ae32
--- /dev/null
+++ b/drivers/net/cxgb3/xgmac.c
@@ -0,0 +1,409 @@
+/*
+ * Copyright (c) 2005-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include "common.h"
+#include "regs.h"
+
+/*
+ * # of exact address filters. The first one is used for the station address,
+ * the rest are available for multicast addresses.
+ */
+#define EXACT_ADDR_FILTERS 8
+
+static inline int macidx(const struct cmac *mac)
+{
+ return mac->offset / (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR);
+}
+
+static void xaui_serdes_reset(struct cmac *mac)
+{
+ static const unsigned int clear[] = {
+ F_PWRDN0 | F_PWRDN1, F_RESETPLL01, F_RESET0 | F_RESET1,
+ F_PWRDN2 | F_PWRDN3, F_RESETPLL23, F_RESET2 | F_RESET3
+ };
+
+ int i;
+ struct adapter *adap = mac->adapter;
+ u32 ctrl = A_XGM_SERDES_CTRL0 + mac->offset;
+
+ t3_write_reg(adap, ctrl, adap->params.vpd.xauicfg[macidx(mac)] |
+ F_RESET3 | F_RESET2 | F_RESET1 | F_RESET0 |
+ F_PWRDN3 | F_PWRDN2 | F_PWRDN1 | F_PWRDN0 |
+ F_RESETPLL23 | F_RESETPLL01);
+ t3_read_reg(adap, ctrl);
+ udelay(15);
+
+ for (i = 0; i < ARRAY_SIZE(clear); i++) {
+ t3_set_reg_field(adap, ctrl, clear[i], 0);
+ udelay(15);
+ }
+}
+
+void t3b_pcs_reset(struct cmac *mac)
+{
+ t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset,
+ F_PCS_RESET_, 0);
+ udelay(20);
+ t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset, 0,
+ F_PCS_RESET_);
+}
+
+int t3_mac_reset(struct cmac *mac)
+{
+ static const struct addr_val_pair mac_reset_avp[] = {
+ {A_XGM_TX_CTRL, 0},
+ {A_XGM_RX_CTRL, 0},
+ {A_XGM_RX_CFG, F_DISPAUSEFRAMES | F_EN1536BFRAMES |
+ F_RMFCS | F_ENJUMBO | F_ENHASHMCAST},
+ {A_XGM_RX_HASH_LOW, 0},
+ {A_XGM_RX_HASH_HIGH, 0},
+ {A_XGM_RX_EXACT_MATCH_LOW_1, 0},
+ {A_XGM_RX_EXACT_MATCH_LOW_2, 0},
+ {A_XGM_RX_EXACT_MATCH_LOW_3, 0},
+ {A_XGM_RX_EXACT_MATCH_LOW_4, 0},
+ {A_XGM_RX_EXACT_MATCH_LOW_5, 0},
+ {A_XGM_RX_EXACT_MATCH_LOW_6, 0},
+ {A_XGM_RX_EXACT_MATCH_LOW_7, 0},
+ {A_XGM_RX_EXACT_MATCH_LOW_8, 0},
+ {A_XGM_STAT_CTRL, F_CLRSTATS}
+ };
+ u32 val;
+ struct adapter *adap = mac->adapter;
+ unsigned int oft = mac->offset;
+
+ t3_write_reg(adap, A_XGM_RESET_CTRL + oft, F_MAC_RESET_);
+ t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */
+
+ t3_write_regs(adap, mac_reset_avp, ARRAY_SIZE(mac_reset_avp), oft);
+ t3_set_reg_field(adap, A_XGM_RXFIFO_CFG + oft,
+ F_RXSTRFRWRD | F_DISERRFRAMES,
+ uses_xaui(adap) ? 0 : F_RXSTRFRWRD);
+
+ if (uses_xaui(adap)) {
+ if (adap->params.rev == 0) {
+ t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0,
+ F_RXENABLE | F_TXENABLE);
+ if (t3_wait_op_done(adap, A_XGM_SERDES_STATUS1 + oft,
+ F_CMULOCK, 1, 5, 2)) {
+ CH_ERR(adap,
+ "MAC %d XAUI SERDES CMU lock failed\n",
+ macidx(mac));
+ return -1;
+ }
+ t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0,
+ F_SERDESRESET_);
+ } else
+ xaui_serdes_reset(mac);
+ }
+
+ if (adap->params.rev > 0)
+ t3_write_reg(adap, A_XGM_PAUSE_TIMER + oft, 0xf000);
+
+ val = F_MAC_RESET_;
+ if (is_10G(adap))
+ val |= F_PCS_RESET_;
+ else if (uses_xaui(adap))
+ val |= F_PCS_RESET_ | F_XG2G_RESET_;
+ else
+ val |= F_RGMII_RESET_ | F_XG2G_RESET_;
+ t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val);
+ t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */
+ if ((val & F_PCS_RESET_) && adap->params.rev) {
+ msleep(1);
+ t3b_pcs_reset(mac);
+ }
+
+ memset(&mac->stats, 0, sizeof(mac->stats));
+ return 0;
+}
+
+/*
+ * Set the exact match register 'idx' to recognize the given Ethernet address.
+ */
+static void set_addr_filter(struct cmac *mac, int idx, const u8 * addr)
+{
+ u32 addr_lo, addr_hi;
+ unsigned int oft = mac->offset + idx * 8;
+
+ addr_lo = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0];
+ addr_hi = (addr[5] << 8) | addr[4];
+
+ t3_write_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1 + oft, addr_lo);
+ t3_write_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_HIGH_1 + oft, addr_hi);
+}
+
+/* Set one of the station's unicast MAC addresses. */
+int t3_mac_set_address(struct cmac *mac, unsigned int idx, u8 addr[6])
+{
+ if (idx >= mac->nucast)
+ return -EINVAL;
+ set_addr_filter(mac, idx, addr);
+ return 0;
+}
+
+/*
+ * Specify the number of exact address filters that should be reserved for
+ * unicast addresses. Caller should reload the unicast and multicast addresses
+ * after calling this.
+ */
+int t3_mac_set_num_ucast(struct cmac *mac, int n)
+{
+ if (n > EXACT_ADDR_FILTERS)
+ return -EINVAL;
+ mac->nucast = n;
+ return 0;
+}
+
+/* Calculate the RX hash filter index of an Ethernet address */
+static int hash_hw_addr(const u8 * addr)
+{
+ int hash = 0, octet, bit, i = 0, c;
+
+ for (octet = 0; octet < 6; ++octet)
+ for (c = addr[octet], bit = 0; bit < 8; c >>= 1, ++bit) {
+ hash ^= (c & 1) << i;
+ if (++i == 6)
+ i = 0;
+ }
+ return hash;
+}
+
+int t3_mac_set_rx_mode(struct cmac *mac, struct t3_rx_mode *rm)
+{
+ 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)
+ val |= F_COPYALLFRAMES;
+ t3_write_reg(adap, A_XGM_RX_CFG + oft, val);
+
+ if (rm->dev->flags & IFF_ALLMULTI)
+ hash_lo = hash_hi = 0xffffffff;
+ else {
+ u8 *addr;
+ int exact_addr_idx = mac->nucast;
+
+ hash_lo = hash_hi = 0;
+ while ((addr = t3_get_next_mcaddr(rm)))
+ if (exact_addr_idx < EXACT_ADDR_FILTERS)
+ set_addr_filter(mac, exact_addr_idx++, addr);
+ else {
+ int hash = hash_hw_addr(addr);
+
+ if (hash < 32)
+ hash_lo |= (1 << hash);
+ else
+ hash_hi |= (1 << (hash - 32));
+ }
+ }
+
+ t3_write_reg(adap, A_XGM_RX_HASH_LOW + oft, hash_lo);
+ t3_write_reg(adap, A_XGM_RX_HASH_HIGH + oft, hash_hi);
+ return 0;
+}
+
+int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu)
+{
+ int hwm, lwm;
+ unsigned int thres, v;
+ struct adapter *adap = mac->adapter;
+
+ /*
+ * MAX_FRAME_SIZE inludes header + FCS, mtu doesn't. The HW max
+ * packet size register includes header, but not FCS.
+ */
+ mtu += 14;
+ if (mtu > MAX_FRAME_SIZE - 4)
+ return -EINVAL;
+ t3_write_reg(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset, mtu);
+
+ /*
+ * Adjust the PAUSE frame watermarks. We always set the LWM, and the
+ * HWM only if flow-control is enabled.
+ */
+ hwm = max(MAC_RXFIFO_SIZE - 3 * mtu, MAC_RXFIFO_SIZE / 2U);
+ hwm = min(hwm, 3 * MAC_RXFIFO_SIZE / 4 + 1024);
+ lwm = hwm - 1024;
+ v = t3_read_reg(adap, A_XGM_RXFIFO_CFG + mac->offset);
+ v &= ~V_RXFIFOPAUSELWM(M_RXFIFOPAUSELWM);
+ v |= V_RXFIFOPAUSELWM(lwm / 8);
+ if (G_RXFIFOPAUSEHWM(v))
+ v = (v & ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM)) |
+ V_RXFIFOPAUSEHWM(hwm / 8);
+ t3_write_reg(adap, A_XGM_RXFIFO_CFG + mac->offset, v);
+
+ /* Adjust the TX FIFO threshold based on the MTU */
+ thres = (adap->params.vpd.cclk * 1000) / 15625;
+ thres = (thres * mtu) / 1000;
+ if (is_10G(adap))
+ thres /= 10;
+ thres = mtu > thres ? (mtu - thres + 7) / 8 : 0;
+ thres = max(thres, 8U); /* need at least 8 */
+ t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + mac->offset,
+ V_TXFIFOTHRESH(M_TXFIFOTHRESH), V_TXFIFOTHRESH(thres));
+ return 0;
+}
+
+int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc)
+{
+ u32 val;
+ struct adapter *adap = mac->adapter;
+ unsigned int oft = mac->offset;
+
+ if (duplex >= 0 && duplex != DUPLEX_FULL)
+ return -EINVAL;
+ if (speed >= 0) {
+ if (speed == SPEED_10)
+ val = V_PORTSPEED(0);
+ else if (speed == SPEED_100)
+ val = V_PORTSPEED(1);
+ else if (speed == SPEED_1000)
+ val = V_PORTSPEED(2);
+ else if (speed == SPEED_10000)
+ val = V_PORTSPEED(3);
+ else
+ return -EINVAL;
+
+ t3_set_reg_field(adap, A_XGM_PORT_CFG + oft,
+ V_PORTSPEED(M_PORTSPEED), val);
+ }
+
+ val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft);
+ val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM);
+ if (fc & PAUSE_TX)
+ val |= V_RXFIFOPAUSEHWM(G_RXFIFOPAUSELWM(val) + 128); /* +1KB */
+ t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val);
+
+ t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN,
+ (fc & PAUSE_RX) ? F_TXPAUSEEN : 0);
+ return 0;
+}
+
+int t3_mac_enable(struct cmac *mac, int which)
+{
+ int idx = macidx(mac);
+ struct adapter *adap = mac->adapter;
+ unsigned int oft = mac->offset;
+
+ if (which & MAC_DIRECTION_TX) {
+ t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN);
+ t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
+ t3_write_reg(adap, A_TP_PIO_DATA, 0xbf000001);
+ t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_MODE);
+ t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx, 1 << idx);
+ }
+ if (which & MAC_DIRECTION_RX)
+ t3_write_reg(adap, A_XGM_RX_CTRL + oft, F_RXEN);
+ return 0;
+}
+
+int t3_mac_disable(struct cmac *mac, int which)
+{
+ int idx = macidx(mac);
+ struct adapter *adap = mac->adapter;
+
+ if (which & MAC_DIRECTION_TX) {
+ t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0);
+ t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
+ t3_write_reg(adap, A_TP_PIO_DATA, 0xc000001f);
+ t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_MODE);
+ t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx, 0);
+ }
+ if (which & MAC_DIRECTION_RX)
+ t3_write_reg(adap, A_XGM_RX_CTRL + mac->offset, 0);
+ return 0;
+}
+
+/*
+ * This function is called periodically to accumulate the current values of the
+ * RMON counters into the port statistics. Since the packet counters are only
+ * 32 bits they can overflow in ~286 secs at 10G, so the function should be
+ * called more frequently than that. The byte counters are 45-bit wide, they
+ * would overflow in ~7.8 hours.
+ */
+const struct mac_stats *t3_mac_update_stats(struct cmac *mac)
+{
+#define RMON_READ(mac, addr) t3_read_reg(mac->adapter, addr + mac->offset)
+#define RMON_UPDATE(mac, name, reg) \
+ (mac)->stats.name += (u64)RMON_READ(mac, A_XGM_STAT_##reg)
+#define RMON_UPDATE64(mac, name, reg_lo, reg_hi) \
+ (mac)->stats.name += RMON_READ(mac, A_XGM_STAT_##reg_lo) + \
+ ((u64)RMON_READ(mac, A_XGM_STAT_##reg_hi) << 32)
+
+ u32 v, lo;
+
+ RMON_UPDATE64(mac, rx_octets, RX_BYTES_LOW, RX_BYTES_HIGH);
+ RMON_UPDATE64(mac, rx_frames, RX_FRAMES_LOW, RX_FRAMES_HIGH);
+ RMON_UPDATE(mac, rx_mcast_frames, RX_MCAST_FRAMES);
+ RMON_UPDATE(mac, rx_bcast_frames, RX_BCAST_FRAMES);
+ RMON_UPDATE(mac, rx_fcs_errs, RX_CRC_ERR_FRAMES);
+ RMON_UPDATE(mac, rx_pause, RX_PAUSE_FRAMES);
+ RMON_UPDATE(mac, rx_jabber, RX_JABBER_FRAMES);
+ RMON_UPDATE(mac, rx_short, RX_SHORT_FRAMES);
+ RMON_UPDATE(mac, rx_symbol_errs, RX_SYM_CODE_ERR_FRAMES);
+
+ RMON_UPDATE(mac, rx_too_long, RX_OVERSIZE_FRAMES);
+ mac->stats.rx_too_long += RMON_READ(mac, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT);
+
+ RMON_UPDATE(mac, rx_frames_64, RX_64B_FRAMES);
+ RMON_UPDATE(mac, rx_frames_65_127, RX_65_127B_FRAMES);
+ RMON_UPDATE(mac, rx_frames_128_255, RX_128_255B_FRAMES);
+ RMON_UPDATE(mac, rx_frames_256_511, RX_256_511B_FRAMES);
+ RMON_UPDATE(mac, rx_frames_512_1023, RX_512_1023B_FRAMES);
+ RMON_UPDATE(mac, rx_frames_1024_1518, RX_1024_1518B_FRAMES);
+ RMON_UPDATE(mac, rx_frames_1519_max, RX_1519_MAXB_FRAMES);
+
+ RMON_UPDATE64(mac, tx_octets, TX_BYTE_LOW, TX_BYTE_HIGH);
+ RMON_UPDATE64(mac, tx_frames, TX_FRAME_LOW, TX_FRAME_HIGH);
+ RMON_UPDATE(mac, tx_mcast_frames, TX_MCAST);
+ RMON_UPDATE(mac, tx_bcast_frames, TX_BCAST);
+ RMON_UPDATE(mac, tx_pause, TX_PAUSE);
+ /* This counts error frames in general (bad FCS, underrun, etc). */
+ RMON_UPDATE(mac, tx_underrun, TX_ERR_FRAMES);
+
+ RMON_UPDATE(mac, tx_frames_64, TX_64B_FRAMES);
+ RMON_UPDATE(mac, tx_frames_65_127, TX_65_127B_FRAMES);
+ RMON_UPDATE(mac, tx_frames_128_255, TX_128_255B_FRAMES);
+ RMON_UPDATE(mac, tx_frames_256_511, TX_256_511B_FRAMES);
+ RMON_UPDATE(mac, tx_frames_512_1023, TX_512_1023B_FRAMES);
+ RMON_UPDATE(mac, tx_frames_1024_1518, TX_1024_1518B_FRAMES);
+ RMON_UPDATE(mac, tx_frames_1519_max, TX_1519_MAXB_FRAMES);
+
+ /* The next stat isn't clear-on-read. */
+ t3_write_reg(mac->adapter, A_TP_MIB_INDEX, mac->offset ? 51 : 50);
+ v = t3_read_reg(mac->adapter, A_TP_MIB_RDATA);
+ lo = (u32) mac->stats.rx_cong_drops;
+ mac->stats.rx_cong_drops += (u64) (v - lo);
+
+ return &mac->stats;
+}
diff --git a/drivers/net/declance.c b/drivers/net/declance.c
index 4ae0fed7122..9f7e1db8ce6 100644
--- a/drivers/net/declance.c
+++ b/drivers/net/declance.c
@@ -5,7 +5,7 @@
*
* adopted from sunlance.c by Richard van den Berg
*
- * Copyright (C) 2002, 2003, 2005 Maciej W. Rozycki
+ * Copyright (C) 2002, 2003, 2005, 2006 Maciej W. Rozycki
*
* additional sources:
* - PMAD-AA TURBOchannel Ethernet Module Functional Specification,
@@ -44,6 +44,8 @@
* v0.010: Fixes for the PMAD mapping of the LANCE buffer and for the
* PMAX requirement to only use halfword accesses to the
* buffer. macro
+ *
+ * v0.011: Converted the PMAD to the driver model. macro
*/
#include <linux/crc32.h>
@@ -58,6 +60,7 @@
#include <linux/spinlock.h>
#include <linux/stddef.h>
#include <linux/string.h>
+#include <linux/tc.h>
#include <linux/types.h>
#include <asm/addrspace.h>
@@ -69,15 +72,16 @@
#include <asm/dec/kn01.h>
#include <asm/dec/machtype.h>
#include <asm/dec/system.h>
-#include <asm/dec/tc.h>
static char version[] __devinitdata =
-"declance.c: v0.010 by Linux MIPS DECstation task force\n";
+"declance.c: v0.011 by Linux MIPS DECstation task force\n";
MODULE_AUTHOR("Linux MIPS DECstation task force");
MODULE_DESCRIPTION("DEC LANCE (DECstation onboard, PMAD-xx) driver");
MODULE_LICENSE("GPL");
+#define __unused __attribute__ ((unused))
+
/*
* card types
*/
@@ -246,7 +250,6 @@ struct lance_init_block {
struct lance_private {
struct net_device *next;
int type;
- int slot;
int dma_irq;
volatile struct lance_regs *ll;
@@ -288,6 +291,7 @@ struct lance_regs {
int dec_lance_debug = 2;
+static struct tc_driver dec_lance_tc_driver;
static struct net_device *root_lance_dev;
static inline void writereg(volatile unsigned short *regptr, short value)
@@ -1023,7 +1027,7 @@ static void lance_set_multicast_retry(unsigned long _opaque)
lance_set_multicast(dev);
}
-static int __init dec_lance_init(const int type, const int slot)
+static int __init dec_lance_probe(struct device *bdev, const int type)
{
static unsigned version_printed;
static const char fmt[] = "declance%d";
@@ -1031,6 +1035,7 @@ static int __init dec_lance_init(const int type, const int slot)
struct net_device *dev;
struct lance_private *lp;
volatile struct lance_regs *ll;
+ resource_size_t start = 0, len = 0;
int i, ret;
unsigned long esar_base;
unsigned char *esar;
@@ -1038,14 +1043,18 @@ static int __init dec_lance_init(const int type, const int slot)
if (dec_lance_debug && version_printed++ == 0)
printk(version);
- i = 0;
- dev = root_lance_dev;
- while (dev) {
- i++;
- lp = (struct lance_private *)dev->priv;
- dev = lp->next;
+ if (bdev)
+ snprintf(name, sizeof(name), "%s", bdev->bus_id);
+ else {
+ i = 0;
+ dev = root_lance_dev;
+ while (dev) {
+ i++;
+ lp = (struct lance_private *)dev->priv;
+ dev = lp->next;
+ }
+ snprintf(name, sizeof(name), fmt, i);
}
- snprintf(name, sizeof(name), fmt, i);
dev = alloc_etherdev(sizeof(struct lance_private));
if (!dev) {
@@ -1063,7 +1072,6 @@ static int __init dec_lance_init(const int type, const int slot)
spin_lock_init(&lp->lock);
lp->type = type;
- lp->slot = slot;
switch (type) {
case ASIC_LANCE:
dev->base_addr = CKSEG1ADDR(dec_kn_slot_base + IOASIC_LANCE);
@@ -1110,12 +1118,22 @@ static int __init dec_lance_init(const int type, const int slot)
break;
#ifdef CONFIG_TC
case PMAD_LANCE:
- claim_tc_card(slot);
+ dev_set_drvdata(bdev, dev);
+
+ start = to_tc_dev(bdev)->resource.start;
+ len = to_tc_dev(bdev)->resource.end - start + 1;
+ if (!request_mem_region(start, len, bdev->bus_id)) {
+ printk(KERN_ERR
+ "%s: Unable to reserve MMIO resource\n",
+ bdev->bus_id);
+ ret = -EBUSY;
+ goto err_out_dev;
+ }
- dev->mem_start = CKSEG1ADDR(get_tc_base_addr(slot));
+ dev->mem_start = CKSEG1ADDR(start);
dev->mem_end = dev->mem_start + 0x100000;
dev->base_addr = dev->mem_start + 0x100000;
- dev->irq = get_tc_irq_nr(slot);
+ dev->irq = to_tc_dev(bdev)->interrupt;
esar_base = dev->mem_start + 0x1c0002;
lp->dma_irq = -1;
@@ -1174,7 +1192,7 @@ static int __init dec_lance_init(const int type, const int slot)
printk(KERN_ERR "%s: declance_init called with unknown type\n",
name);
ret = -ENODEV;
- goto err_out_free_dev;
+ goto err_out_dev;
}
ll = (struct lance_regs *) dev->base_addr;
@@ -1188,7 +1206,7 @@ static int __init dec_lance_init(const int type, const int slot)
"%s: Ethernet station address prom not found!\n",
name);
ret = -ENODEV;
- goto err_out_free_dev;
+ goto err_out_resource;
}
/* Check the prom contents */
for (i = 0; i < 8; i++) {
@@ -1198,7 +1216,7 @@ static int __init dec_lance_init(const int type, const int slot)
printk(KERN_ERR "%s: Something is wrong with the "
"ethernet station address prom!\n", name);
ret = -ENODEV;
- goto err_out_free_dev;
+ goto err_out_resource;
}
}
@@ -1255,48 +1273,51 @@ static int __init dec_lance_init(const int type, const int slot)
if (ret) {
printk(KERN_ERR
"%s: Unable to register netdev, aborting.\n", name);
- goto err_out_free_dev;
+ goto err_out_resource;
}
- lp->next = root_lance_dev;
- root_lance_dev = dev;
+ if (!bdev) {
+ lp->next = root_lance_dev;
+ root_lance_dev = dev;
+ }
printk("%s: registered as %s.\n", name, dev->name);
return 0;
-err_out_free_dev:
+err_out_resource:
+ if (bdev)
+ release_mem_region(start, len);
+
+err_out_dev:
free_netdev(dev);
err_out:
return ret;
}
+static void __exit dec_lance_remove(struct device *bdev)
+{
+ struct net_device *dev = dev_get_drvdata(bdev);
+ resource_size_t start, len;
+
+ unregister_netdev(dev);
+ start = to_tc_dev(bdev)->resource.start;
+ len = to_tc_dev(bdev)->resource.end - start + 1;
+ release_mem_region(start, len);
+ free_netdev(dev);
+}
/* Find all the lance cards on the system and initialize them */
-static int __init dec_lance_probe(void)
+static int __init dec_lance_platform_probe(void)
{
int count = 0;
- /* Scan slots for PMAD-AA cards first. */
-#ifdef CONFIG_TC
- if (TURBOCHANNEL) {
- int slot;
-
- while ((slot = search_tc_card("PMAD-AA")) >= 0) {
- if (dec_lance_init(PMAD_LANCE, slot) < 0)
- break;
- count++;
- }
- }
-#endif
-
- /* Then handle onboard devices. */
if (dec_interrupt[DEC_IRQ_LANCE] >= 0) {
if (dec_interrupt[DEC_IRQ_LANCE_MERR] >= 0) {
- if (dec_lance_init(ASIC_LANCE, -1) >= 0)
+ if (dec_lance_probe(NULL, ASIC_LANCE) >= 0)
count++;
} else if (!TURBOCHANNEL) {
- if (dec_lance_init(PMAX_LANCE, -1) >= 0)
+ if (dec_lance_probe(NULL, PMAX_LANCE) >= 0)
count++;
}
}
@@ -1304,21 +1325,70 @@ static int __init dec_lance_probe(void)
return (count > 0) ? 0 : -ENODEV;
}
-static void __exit dec_lance_cleanup(void)
+static void __exit dec_lance_platform_remove(void)
{
while (root_lance_dev) {
struct net_device *dev = root_lance_dev;
struct lance_private *lp = netdev_priv(dev);
unregister_netdev(dev);
-#ifdef CONFIG_TC
- if (lp->slot >= 0)
- release_tc_card(lp->slot);
-#endif
root_lance_dev = lp->next;
free_netdev(dev);
}
}
-module_init(dec_lance_probe);
-module_exit(dec_lance_cleanup);
+#ifdef CONFIG_TC
+static int __init dec_lance_tc_probe(struct device *dev);
+static int __exit dec_lance_tc_remove(struct device *dev);
+
+static const struct tc_device_id dec_lance_tc_table[] = {
+ { "DEC ", "PMAD-AA " },
+ { }
+};
+MODULE_DEVICE_TABLE(tc, dec_lance_tc_table);
+
+static struct tc_driver dec_lance_tc_driver = {
+ .id_table = dec_lance_tc_table,
+ .driver = {
+ .name = "declance",
+ .bus = &tc_bus_type,
+ .probe = dec_lance_tc_probe,
+ .remove = __exit_p(dec_lance_tc_remove),
+ },
+};
+
+static int __init dec_lance_tc_probe(struct device *dev)
+{
+ int status = dec_lance_probe(dev, PMAD_LANCE);
+ if (!status)
+ get_device(dev);
+ return status;
+}
+
+static int __exit dec_lance_tc_remove(struct device *dev)
+{
+ put_device(dev);
+ dec_lance_remove(dev);
+ return 0;
+}
+#endif
+
+static int __init dec_lance_init(void)
+{
+ int status;
+
+ status = tc_register_driver(&dec_lance_tc_driver);
+ if (!status)
+ dec_lance_platform_probe();
+ return status;
+}
+
+static void __exit dec_lance_exit(void)
+{
+ dec_lance_platform_remove();
+ tc_unregister_driver(&dec_lance_tc_driver);
+}
+
+
+module_init(dec_lance_init);
+module_exit(dec_lance_exit);
diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c
index dc3ab3b5c8c..07d2731c1aa 100644
--- a/drivers/net/defxx.c
+++ b/drivers/net/defxx.c
@@ -10,10 +10,12 @@
*
* Abstract:
* A Linux device driver supporting the Digital Equipment Corporation
- * FDDI EISA and PCI controller families. Supported adapters include:
+ * FDDI TURBOchannel, EISA and PCI controller families. Supported
+ * adapters include:
*
- * DEC FDDIcontroller/EISA (DEFEA)
- * DEC FDDIcontroller/PCI (DEFPA)
+ * DEC FDDIcontroller/TURBOchannel (DEFTA)
+ * DEC FDDIcontroller/EISA (DEFEA)
+ * DEC FDDIcontroller/PCI (DEFPA)
*
* The original author:
* LVS Lawrence V. Stefani <lstefani@yahoo.com>
@@ -193,24 +195,27 @@
* 14 Aug 2004 macro Fix device names reported.
* 14 Jun 2005 macro Use irqreturn_t.
* 23 Oct 2006 macro Big-endian host support.
+ * 14 Dec 2006 macro TURBOchannel support.
*/
/* Include files */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
+#include <linux/bitops.h>
#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/eisa.h>
+#include <linux/errno.h>
+#include <linux/fddidevice.h>
#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/netdevice.h>
-#include <linux/fddidevice.h>
+#include <linux/pci.h>
#include <linux/skbuff.h>
-#include <linux/bitops.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/tc.h>
#include <asm/byteorder.h>
#include <asm/io.h>
@@ -219,8 +224,8 @@
/* Version information string should be updated prior to each new release! */
#define DRV_NAME "defxx"
-#define DRV_VERSION "v1.09"
-#define DRV_RELDATE "2006/10/23"
+#define DRV_VERSION "v1.10"
+#define DRV_RELDATE "2006/12/14"
static char version[] __devinitdata =
DRV_NAME ": " DRV_VERSION " " DRV_RELDATE
@@ -235,12 +240,41 @@ static char version[] __devinitdata =
*/
#define NEW_SKB_SIZE (PI_RCV_DATA_K_SIZE_MAX+128)
+#define __unused __attribute__ ((unused))
+
+#ifdef CONFIG_PCI
+#define DFX_BUS_PCI(dev) (dev->bus == &pci_bus_type)
+#else
+#define DFX_BUS_PCI(dev) 0
+#endif
+
+#ifdef CONFIG_EISA
+#define DFX_BUS_EISA(dev) (dev->bus == &eisa_bus_type)
+#else
+#define DFX_BUS_EISA(dev) 0
+#endif
+
+#ifdef CONFIG_TC
+#define DFX_BUS_TC(dev) (dev->bus == &tc_bus_type)
+#else
+#define DFX_BUS_TC(dev) 0
+#endif
+
+#ifdef CONFIG_DEFXX_MMIO
+#define DFX_MMIO 1
+#else
+#define DFX_MMIO 0
+#endif
+
/* Define module-wide (static) routines */
static void dfx_bus_init(struct net_device *dev);
+static void dfx_bus_uninit(struct net_device *dev);
static void dfx_bus_config_check(DFX_board_t *bp);
-static int dfx_driver_init(struct net_device *dev, const char *print_name);
+static int dfx_driver_init(struct net_device *dev,
+ const char *print_name,
+ resource_size_t bar_start);
static int dfx_adap_init(DFX_board_t *bp, int get_buffers);
static int dfx_open(struct net_device *dev);
@@ -273,13 +307,13 @@ static void dfx_xmt_flush(DFX_board_t *bp);
/* Define module-wide (static) variables */
-static struct net_device *root_dfx_eisa_dev;
+static struct pci_driver dfx_pci_driver;
+static struct eisa_driver dfx_eisa_driver;
+static struct tc_driver dfx_tc_driver;
/*
* =======================
- * = dfx_port_write_byte =
- * = dfx_port_read_byte =
* = dfx_port_write_long =
* = dfx_port_read_long =
* =======================
@@ -291,12 +325,11 @@ static struct net_device *root_dfx_eisa_dev;
* None
*
* Arguments:
- * bp - pointer to board information
- * offset - register offset from base I/O address
- * data - for dfx_port_write_byte and dfx_port_write_long, this
- * is a value to write.
- * for dfx_port_read_byte and dfx_port_read_byte, this
- * is a pointer to store the read value.
+ * bp - pointer to board information
+ * offset - register offset from base I/O address
+ * data - for dfx_port_write_long, this is a value to write;
+ * for dfx_port_read_long, this is a pointer to store
+ * the read value
*
* Functional Description:
* These routines perform the correct operation to read or write
@@ -310,7 +343,7 @@ static struct net_device *root_dfx_eisa_dev;
* registers using the register offsets defined in DEFXX.H.
*
* PCI port block base addresses are assigned by the PCI BIOS or system
- * firmware. There is one 128 byte port block which can be accessed. It
+ * firmware. There is one 128 byte port block which can be accessed. It
* allows for I/O mapping of both PDQ and PFI registers using the register
* offsets defined in DEFXX.H.
*
@@ -318,7 +351,7 @@ static struct net_device *root_dfx_eisa_dev;
* None
*
* Assumptions:
- * bp->base_addr is a valid base I/O address for this adapter.
+ * bp->base is a valid base I/O address for this adapter.
* offset is a valid register offset for this adapter.
*
* Side Effects:
@@ -329,69 +362,135 @@ static struct net_device *root_dfx_eisa_dev;
* advantage of strict data type checking.
*/
-static inline void dfx_port_write_byte(
- DFX_board_t *bp,
- int offset,
- u8 data
- )
+static inline void dfx_writel(DFX_board_t *bp, int offset, u32 data)
+{
+ writel(data, bp->base.mem + offset);
+ mb();
+}
- {
- u16 port = bp->base_addr + offset;
+static inline void dfx_outl(DFX_board_t *bp, int offset, u32 data)
+{
+ outl(data, bp->base.port + offset);
+}
- outb(data, port);
- }
+static void dfx_port_write_long(DFX_board_t *bp, int offset, u32 data)
+{
+ struct device __unused *bdev = bp->bus_dev;
+ int dfx_bus_tc = DFX_BUS_TC(bdev);
+ int dfx_use_mmio = DFX_MMIO || dfx_bus_tc;
-static inline void dfx_port_read_byte(
- DFX_board_t *bp,
- int offset,
- u8 *data
- )
+ if (dfx_use_mmio)
+ dfx_writel(bp, offset, data);
+ else
+ dfx_outl(bp, offset, data);
+}
- {
- u16 port = bp->base_addr + offset;
- *data = inb(port);
- }
+static inline void dfx_readl(DFX_board_t *bp, int offset, u32 *data)
+{
+ mb();
+ *data = readl(bp->base.mem + offset);
+}
-static inline void dfx_port_write_long(
- DFX_board_t *bp,
- int offset,
- u32 data
- )
+static inline void dfx_inl(DFX_board_t *bp, int offset, u32 *data)
+{
+ *data = inl(bp->base.port + offset);
+}
- {
- u16 port = bp->base_addr + offset;
+static void dfx_port_read_long(DFX_board_t *bp, int offset, u32 *data)
+{
+ struct device __unused *bdev = bp->bus_dev;
+ int dfx_bus_tc = DFX_BUS_TC(bdev);
+ int dfx_use_mmio = DFX_MMIO || dfx_bus_tc;
- outl(data, port);
- }
+ if (dfx_use_mmio)
+ dfx_readl(bp, offset, data);
+ else
+ dfx_inl(bp, offset, data);
+}
-static inline void dfx_port_read_long(
- DFX_board_t *bp,
- int offset,
- u32 *data
- )
- {
- u16 port = bp->base_addr + offset;
+/*
+ * ================
+ * = dfx_get_bars =
+ * ================
+ *
+ * Overview:
+ * Retrieves the address range used to access control and status
+ * registers.
+ *
+ * Returns:
+ * None
+ *
+ * Arguments:
+ * bdev - pointer to device information
+ * bar_start - pointer to store the start address
+ * bar_len - pointer to store the length of the area
+ *
+ * Assumptions:
+ * I am sure there are some.
+ *
+ * Side Effects:
+ * None
+ */
+static void dfx_get_bars(struct device *bdev,
+ resource_size_t *bar_start, resource_size_t *bar_len)
+{
+ int dfx_bus_pci = DFX_BUS_PCI(bdev);
+ int dfx_bus_eisa = DFX_BUS_EISA(bdev);
+ int dfx_bus_tc = DFX_BUS_TC(bdev);
+ int dfx_use_mmio = DFX_MMIO || dfx_bus_tc;
- *data = inl(port);
- }
+ if (dfx_bus_pci) {
+ int num = dfx_use_mmio ? 0 : 1;
+ *bar_start = pci_resource_start(to_pci_dev(bdev), num);
+ *bar_len = pci_resource_len(to_pci_dev(bdev), num);
+ }
+ if (dfx_bus_eisa) {
+ unsigned long base_addr = to_eisa_device(bdev)->base_addr;
+ resource_size_t bar;
+
+ if (dfx_use_mmio) {
+ bar = inb(base_addr + PI_ESIC_K_MEM_ADD_CMP_2);
+ bar <<= 8;
+ bar |= inb(base_addr + PI_ESIC_K_MEM_ADD_CMP_1);
+ bar <<= 8;
+ bar |= inb(base_addr + PI_ESIC_K_MEM_ADD_CMP_0);
+ bar <<= 16;
+ *bar_start = bar;
+ bar = inb(base_addr + PI_ESIC_K_MEM_ADD_MASK_2);
+ bar <<= 8;
+ bar |= inb(base_addr + PI_ESIC_K_MEM_ADD_MASK_1);
+ bar <<= 8;
+ bar |= inb(base_addr + PI_ESIC_K_MEM_ADD_MASK_0);
+ bar <<= 16;
+ *bar_len = (bar | PI_MEM_ADD_MASK_M) + 1;
+ } else {
+ *bar_start = base_addr;
+ *bar_len = PI_ESIC_K_CSR_IO_LEN;
+ }
+ }
+ if (dfx_bus_tc) {
+ *bar_start = to_tc_dev(bdev)->resource.start +
+ PI_TC_K_CSR_OFFSET;
+ *bar_len = PI_TC_K_CSR_LEN;
+ }
+}
/*
- * =============
- * = dfx_init_one_pci_or_eisa =
- * =============
+ * ================
+ * = dfx_register =
+ * ================
*
* Overview:
- * Initializes a supported FDDI EISA or PCI controller
+ * Initializes a supported FDDI controller
*
* Returns:
* Condition code
*
* Arguments:
- * pdev - pointer to pci device information (NULL for EISA)
- * ioaddr - pointer to port (NULL for PCI)
+ * bdev - pointer to device information
*
* Functional Description:
*
@@ -407,56 +506,74 @@ static inline void dfx_port_read_long(
* initialized and the board resources are read and stored in
* the device structure.
*/
-static int __devinit dfx_init_one_pci_or_eisa(struct pci_dev *pdev, long ioaddr)
+static int __devinit dfx_register(struct device *bdev)
{
static int version_disp;
- char *print_name = DRV_NAME;
+ int dfx_bus_pci = DFX_BUS_PCI(bdev);
+ int dfx_bus_tc = DFX_BUS_TC(bdev);
+ int dfx_use_mmio = DFX_MMIO || dfx_bus_tc;
+ char *print_name = bdev->bus_id;
struct net_device *dev;
DFX_board_t *bp; /* board pointer */
+ resource_size_t bar_start = 0; /* pointer to port */
+ resource_size_t bar_len = 0; /* resource length */
int alloc_size; /* total buffer size used */
- int err;
+ struct resource *region;
+ int err = 0;
if (!version_disp) { /* display version info if adapter is found */
version_disp = 1; /* set display flag to TRUE so that */
printk(version); /* we only display this string ONCE */
}
- if (pdev != NULL)
- print_name = pci_name(pdev);
-
dev = alloc_fddidev(sizeof(*bp));
if (!dev) {
- printk(KERN_ERR "%s: unable to allocate fddidev, aborting\n",
+ printk(KERN_ERR "%s: Unable to allocate fddidev, aborting\n",
print_name);
return -ENOMEM;
}
/* Enable PCI device. */
- if (pdev != NULL) {
- err = pci_enable_device (pdev);
- if (err) goto err_out;
- ioaddr = pci_resource_start (pdev, 1);
+ if (dfx_bus_pci && pci_enable_device(to_pci_dev(bdev))) {
+ printk(KERN_ERR "%s: Cannot enable PCI device, aborting\n",
+ print_name);
+ goto err_out;
}
SET_MODULE_OWNER(dev);
- if (pdev != NULL)
- SET_NETDEV_DEV(dev, &pdev->dev);
+ SET_NETDEV_DEV(dev, bdev);
+
+ bp = netdev_priv(dev);
+ bp->bus_dev = bdev;
+ dev_set_drvdata(bdev, dev);
- bp = dev->priv;
+ dfx_get_bars(bdev, &bar_start, &bar_len);
- if (!request_region(ioaddr,
- pdev ? PFI_K_CSR_IO_LEN : PI_ESIC_K_CSR_IO_LEN,
- print_name)) {
+ if (dfx_use_mmio)
+ region = request_mem_region(bar_start, bar_len, print_name);
+ else
+ region = request_region(bar_start, bar_len, print_name);
+ if (!region) {
printk(KERN_ERR "%s: Cannot reserve I/O resource "
- "0x%x @ 0x%lx, aborting\n", print_name,
- pdev ? PFI_K_CSR_IO_LEN : PI_ESIC_K_CSR_IO_LEN, ioaddr);
+ "0x%lx @ 0x%lx, aborting\n",
+ print_name, (long)bar_len, (long)bar_start);
err = -EBUSY;
- goto err_out;
+ goto err_out_disable;
}
- /* Initialize new device structure */
+ /* Set up I/O base address. */
+ if (dfx_use_mmio) {
+ bp->base.mem = ioremap_nocache(bar_start, bar_len);
+ if (!bp->base.mem) {
+ printk(KERN_ERR "%s: Cannot map MMIO\n", print_name);
+ goto err_out_region;
+ }
+ } else {
+ bp->base.port = bar_start;
+ dev->base_addr = bar_start;
+ }
- dev->base_addr = ioaddr; /* save port (I/O) base address */
+ /* Initialize new device structure */
dev->get_stats = dfx_ctl_get_stats;
dev->open = dfx_open;
@@ -465,22 +582,12 @@ static int __devinit dfx_init_one_pci_or_eisa(struct pci_dev *pdev, long ioaddr)
dev->set_multicast_list = dfx_ctl_set_multicast_list;
dev->set_mac_address = dfx_ctl_set_mac_address;
- if (pdev == NULL) {
- /* EISA board */
- bp->bus_type = DFX_BUS_TYPE_EISA;
- bp->next = root_dfx_eisa_dev;
- root_dfx_eisa_dev = dev;
- } else {
- /* PCI board */
- bp->bus_type = DFX_BUS_TYPE_PCI;
- bp->pci_dev = pdev;
- pci_set_drvdata (pdev, dev);
- pci_set_master (pdev);
- }
+ if (dfx_bus_pci)
+ pci_set_master(to_pci_dev(bdev));
- if (dfx_driver_init(dev, print_name) != DFX_K_SUCCESS) {
+ if (dfx_driver_init(dev, print_name, bar_start) != DFX_K_SUCCESS) {
err = -ENODEV;
- goto err_out_region;
+ goto err_out_unmap;
}
err = register_netdev(dev);
@@ -499,44 +606,28 @@ err_out_kfree:
sizeof(PI_CONSUMER_BLOCK) +
(PI_ALIGN_K_DESC_BLK - 1);
if (bp->kmalloced)
- pci_free_consistent(pdev, alloc_size,
- bp->kmalloced, bp->kmalloced_dma);
+ dma_free_coherent(bdev, alloc_size,
+ bp->kmalloced, bp->kmalloced_dma);
+
+err_out_unmap:
+ if (dfx_use_mmio)
+ iounmap(bp->base.mem);
+
err_out_region:
- release_region(ioaddr, pdev ? PFI_K_CSR_IO_LEN : PI_ESIC_K_CSR_IO_LEN);
+ if (dfx_use_mmio)
+ release_mem_region(bar_start, bar_len);
+ else
+ release_region(bar_start, bar_len);
+
+err_out_disable:
+ if (dfx_bus_pci)
+ pci_disable_device(to_pci_dev(bdev));
+
err_out:
free_netdev(dev);
return err;
}
-static int __devinit dfx_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
-{
- return dfx_init_one_pci_or_eisa(pdev, 0);
-}
-
-static int __init dfx_eisa_init(void)
-{
- int rc = -ENODEV;
- int i; /* used in for loops */
- u16 port; /* temporary I/O (port) address */
- u32 slot_id; /* EISA hardware (slot) ID read from adapter */
-
- DBG_printk("In dfx_eisa_init...\n");
-
- /* Scan for FDDI EISA controllers */
-
- for (i=0; i < DFX_MAX_EISA_SLOTS; i++) /* only scan for up to 16 EISA slots */
- {
- port = (i << 12) + PI_ESIC_K_SLOT_ID; /* port = I/O address for reading slot ID */
- slot_id = inl(port); /* read EISA HW (slot) ID */
- if ((slot_id & 0xF0FFFFFF) == DEFEA_PRODUCT_ID)
- {
- port = (i << 12); /* recalc base addr */
-
- if (dfx_init_one_pci_or_eisa(NULL, port) == 0) rc = 0;
- }
- }
- return rc;
-}
/*
* ================
@@ -544,7 +635,7 @@ static int __init dfx_eisa_init(void)
* ================
*
* Overview:
- * Initializes EISA and PCI controller bus-specific logic.
+ * Initializes the bus-specific controller logic.
*
* Returns:
* None
@@ -560,7 +651,7 @@ static int __init dfx_eisa_init(void)
* None
*
* Assumptions:
- * dev->base_addr has already been set with the proper
+ * bp->base has already been set with the proper
* base I/O address for this device.
*
* Side Effects:
@@ -571,87 +662,103 @@ static int __init dfx_eisa_init(void)
static void __devinit dfx_bus_init(struct net_device *dev)
{
- DFX_board_t *bp = dev->priv;
- u8 val; /* used for I/O read/writes */
+ DFX_board_t *bp = netdev_priv(dev);
+ struct device *bdev = bp->bus_dev;
+ int dfx_bus_pci = DFX_BUS_PCI(bdev);
+ int dfx_bus_eisa = DFX_BUS_EISA(bdev);
+ int dfx_bus_tc = DFX_BUS_TC(bdev);
+ int dfx_use_mmio = DFX_MMIO || dfx_bus_tc;
+ u8 val;
DBG_printk("In dfx_bus_init...\n");
- /*
- * Initialize base I/O address field in bp structure
- *
- * Note: bp->base_addr is the same as dev->base_addr.
- * It's useful because often we'll need to read
- * or write registers where we already have the
- * bp pointer instead of the dev pointer. Having
- * the base address in the bp structure will
- * save a pointer dereference.
- *
- * IMPORTANT!! This field must be defined before
- * any of the dfx_port_* inline functions are
- * called.
- */
-
- bp->base_addr = dev->base_addr;
-
- /* And a pointer back to the net_device struct */
+ /* Initialize a pointer back to the net_device struct */
bp->dev = dev;
/* Initialize adapter based on bus type */
- if (bp->bus_type == DFX_BUS_TYPE_EISA)
- {
- /* Get the interrupt level from the ESIC chip */
-
- dfx_port_read_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, &val);
- switch ((val & PI_CONFIG_STAT_0_M_IRQ) >> PI_CONFIG_STAT_0_V_IRQ)
- {
- case PI_CONFIG_STAT_0_IRQ_K_9:
- dev->irq = 9;
- break;
-
- case PI_CONFIG_STAT_0_IRQ_K_10:
- dev->irq = 10;
- break;
+ if (dfx_bus_tc)
+ dev->irq = to_tc_dev(bdev)->interrupt;
+ if (dfx_bus_eisa) {
+ unsigned long base_addr = to_eisa_device(bdev)->base_addr;
- case PI_CONFIG_STAT_0_IRQ_K_11:
- dev->irq = 11;
- break;
+ /* Get the interrupt level from the ESIC chip. */
+ val = inb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0);
+ val &= PI_CONFIG_STAT_0_M_IRQ;
+ val >>= PI_CONFIG_STAT_0_V_IRQ;
- case PI_CONFIG_STAT_0_IRQ_K_15:
- dev->irq = 15;
- break;
- }
-
- /* Enable access to I/O on the board by writing 0x03 to Function Control Register */
+ switch (val) {
+ case PI_CONFIG_STAT_0_IRQ_K_9:
+ dev->irq = 9;
+ break;
- dfx_port_write_byte(bp, PI_ESIC_K_FUNCTION_CNTRL, PI_ESIC_K_FUNCTION_CNTRL_IO_ENB);
+ case PI_CONFIG_STAT_0_IRQ_K_10:
+ dev->irq = 10;
+ break;
- /* Set the I/O decode range of the board */
+ case PI_CONFIG_STAT_0_IRQ_K_11:
+ dev->irq = 11;
+ break;
- val = ((dev->base_addr >> 12) << PI_IO_CMP_V_SLOT);
- dfx_port_write_byte(bp, PI_ESIC_K_IO_CMP_0_1, val);
- dfx_port_write_byte(bp, PI_ESIC_K_IO_CMP_1_1, val);
+ case PI_CONFIG_STAT_0_IRQ_K_15:
+ dev->irq = 15;
+ break;
+ }
- /* Enable access to rest of module (including PDQ and packet memory) */
+ /*
+ * Enable memory decoding (MEMCS0) and/or port decoding
+ * (IOCS1/IOCS0) as appropriate in Function Control
+ * Register. One of the port chip selects seems to be
+ * used for the Burst Holdoff register, but this bit of
+ * documentation is missing and as yet it has not been
+ * determined which of the two. This is also the reason
+ * the size of the decoded port range is twice as large
+ * as one required by the PDQ.
+ */
- dfx_port_write_byte(bp, PI_ESIC_K_SLOT_CNTRL, PI_SLOT_CNTRL_M_ENB);
+ /* Set the decode range of the board. */
+ val = ((bp->base.port >> 12) << PI_IO_CMP_V_SLOT);
+ outb(base_addr + PI_ESIC_K_IO_ADD_CMP_0_1, val);
+ outb(base_addr + PI_ESIC_K_IO_ADD_CMP_0_0, 0);
+ outb(base_addr + PI_ESIC_K_IO_ADD_CMP_1_1, val);
+ outb(base_addr + PI_ESIC_K_IO_ADD_CMP_1_0, 0);
+ val = PI_ESIC_K_CSR_IO_LEN - 1;
+ outb(base_addr + PI_ESIC_K_IO_ADD_MASK_0_1, (val >> 8) & 0xff);
+ outb(base_addr + PI_ESIC_K_IO_ADD_MASK_0_0, val & 0xff);
+ outb(base_addr + PI_ESIC_K_IO_ADD_MASK_1_1, (val >> 8) & 0xff);
+ outb(base_addr + PI_ESIC_K_IO_ADD_MASK_1_0, val & 0xff);
+
+ /* Enable the decoders. */
+ val = PI_FUNCTION_CNTRL_M_IOCS1 | PI_FUNCTION_CNTRL_M_IOCS0;
+ if (dfx_use_mmio)
+ val |= PI_FUNCTION_CNTRL_M_MEMCS0;
+ outb(base_addr + PI_ESIC_K_FUNCTION_CNTRL, val);
/*
- * Map PDQ registers into I/O space. This is done by clearing a bit
- * in Burst Holdoff register.
+ * Enable access to the rest of the module
+ * (including PDQ and packet memory).
*/
+ val = PI_SLOT_CNTRL_M_ENB;
+ outb(base_addr + PI_ESIC_K_SLOT_CNTRL, val);
- dfx_port_read_byte(bp, PI_ESIC_K_BURST_HOLDOFF, &val);
- dfx_port_write_byte(bp, PI_ESIC_K_BURST_HOLDOFF, (val & ~PI_BURST_HOLDOFF_M_MEM_MAP));
+ /*
+ * Map PDQ registers into memory or port space. This is
+ * done with a bit in the Burst Holdoff register.
+ */
+ val = inb(base_addr + PI_DEFEA_K_BURST_HOLDOFF);
+ if (dfx_use_mmio)
+ val |= PI_BURST_HOLDOFF_V_MEM_MAP;
+ else
+ val &= ~PI_BURST_HOLDOFF_V_MEM_MAP;
+ outb(base_addr + PI_DEFEA_K_BURST_HOLDOFF, val);
/* Enable interrupts at EISA bus interface chip (ESIC) */
-
- dfx_port_read_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, &val);
- dfx_port_write_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, (val | PI_CONFIG_STAT_0_M_INT_ENB));
- }
- else
- {
- struct pci_dev *pdev = bp->pci_dev;
+ val = inb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0);
+ val |= PI_CONFIG_STAT_0_M_INT_ENB;
+ outb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0, val);
+ }
+ if (dfx_bus_pci) {
+ struct pci_dev *pdev = to_pci_dev(bdev);
/* Get the interrupt level from the PCI Configuration Table */
@@ -660,17 +767,70 @@ static void __devinit dfx_bus_init(struct net_device *dev)
/* Check Latency Timer and set if less than minimal */
pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &val);
- if (val < PFI_K_LAT_TIMER_MIN) /* if less than min, override with default */
- {
+ if (val < PFI_K_LAT_TIMER_MIN) {
val = PFI_K_LAT_TIMER_DEF;
pci_write_config_byte(pdev, PCI_LATENCY_TIMER, val);
- }
+ }
/* Enable interrupts at PCI bus interface chip (PFI) */
+ val = PFI_MODE_M_PDQ_INT_ENB | PFI_MODE_M_DMA_ENB;
+ dfx_port_write_long(bp, PFI_K_REG_MODE_CTRL, val);
+ }
+}
- dfx_port_write_long(bp, PFI_K_REG_MODE_CTRL, (PFI_MODE_M_PDQ_INT_ENB | PFI_MODE_M_DMA_ENB));
- }
+/*
+ * ==================
+ * = dfx_bus_uninit =
+ * ==================
+ *
+ * Overview:
+ * Uninitializes the bus-specific controller logic.
+ *
+ * Returns:
+ * None
+ *
+ * Arguments:
+ * dev - pointer to device information
+ *
+ * Functional Description:
+ * Perform bus-specific logic uninitialization.
+ *
+ * Return Codes:
+ * None
+ *
+ * Assumptions:
+ * bp->base has already been set with the proper
+ * base I/O address for this device.
+ *
+ * Side Effects:
+ * Interrupts are disabled at the adapter bus-specific logic.
+ */
+
+static void __devinit dfx_bus_uninit(struct net_device *dev)
+{
+ DFX_board_t *bp = netdev_priv(dev);
+ struct device *bdev = bp->bus_dev;
+ int dfx_bus_pci = DFX_BUS_PCI(bdev);
+ int dfx_bus_eisa = DFX_BUS_EISA(bdev);
+ u8 val;
+
+ DBG_printk("In dfx_bus_uninit...\n");
+
+ /* Uninitialize adapter based on bus type */
+
+ if (dfx_bus_eisa) {
+ unsigned long base_addr = to_eisa_device(bdev)->base_addr;
+
+ /* Disable interrupts at EISA bus interface chip (ESIC) */
+ val = inb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0);
+ val &= ~PI_CONFIG_STAT_0_M_INT_ENB;
+ outb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0, val);
+ }
+ if (dfx_bus_pci) {
+ /* Disable interrupts at PCI bus interface chip (PFI) */
+ dfx_port_write_long(bp, PFI_K_REG_MODE_CTRL, 0);
}
+}
/*
@@ -705,18 +865,16 @@ static void __devinit dfx_bus_init(struct net_device *dev)
static void __devinit dfx_bus_config_check(DFX_board_t *bp)
{
+ struct device __unused *bdev = bp->bus_dev;
+ int dfx_bus_eisa = DFX_BUS_EISA(bdev);
int status; /* return code from adapter port control call */
- u32 slot_id; /* EISA-bus hardware id (DEC3001, DEC3002,...) */
u32 host_data; /* LW data returned from port control call */
DBG_printk("In dfx_bus_config_check...\n");
/* Configuration check only valid for EISA adapter */
- if (bp->bus_type == DFX_BUS_TYPE_EISA)
- {
- dfx_port_read_long(bp, PI_ESIC_K_SLOT_ID, &slot_id);
-
+ if (dfx_bus_eisa) {
/*
* First check if revision 2 EISA controller. Rev. 1 cards used
* PDQ revision B, so no workaround needed in this case. Rev. 3
@@ -724,14 +882,11 @@ static void __devinit dfx_bus_config_check(DFX_board_t *bp)
* case, either. Only Rev. 2 cards used either Rev. D or E
* chips, so we must verify the chip revision on Rev. 2 cards.
*/
-
- if (slot_id == DEFEA_PROD_ID_2)
- {
+ if (to_eisa_device(bdev)->id.driver_data == DEFEA_PROD_ID_2) {
/*
- * Revision 2 FDDI EISA controller found, so let's check PDQ
- * revision of adapter.
+ * Revision 2 FDDI EISA controller found,
+ * so let's check PDQ revision of adapter.
*/
-
status = dfx_hw_port_ctrl_req(bp,
PI_PCTRL_M_SUB_CMD,
PI_SUB_CMD_K_PDQ_REV_GET,
@@ -805,13 +960,20 @@ static void __devinit dfx_bus_config_check(DFX_board_t *bp)
*/
static int __devinit dfx_driver_init(struct net_device *dev,
- const char *print_name)
+ const char *print_name,
+ resource_size_t bar_start)
{
- DFX_board_t *bp = dev->priv;
- int alloc_size; /* total buffer size needed */
- char *top_v, *curr_v; /* virtual addrs into memory block */
- dma_addr_t top_p, curr_p; /* physical addrs into memory block */
- u32 data; /* host data register value */
+ DFX_board_t *bp = netdev_priv(dev);
+ struct device *bdev = bp->bus_dev;
+ int dfx_bus_pci = DFX_BUS_PCI(bdev);
+ int dfx_bus_eisa = DFX_BUS_EISA(bdev);
+ int dfx_bus_tc = DFX_BUS_TC(bdev);
+ int dfx_use_mmio = DFX_MMIO || dfx_bus_tc;
+ int alloc_size; /* total buffer size needed */
+ char *top_v, *curr_v; /* virtual addrs into memory block */
+ dma_addr_t top_p, curr_p; /* physical addrs into memory block */
+ u32 data, le32; /* host data register value */
+ char *board_name = NULL;
DBG_printk("In dfx_driver_init...\n");
@@ -860,8 +1022,8 @@ static int __devinit dfx_driver_init(struct net_device *dev,
print_name);
return(DFX_K_FAILURE);
}
- data = cpu_to_le32(data);
- memcpy(&bp->factory_mac_addr[0], &data, sizeof(u32));
+ le32 = cpu_to_le32(data);
+ memcpy(&bp->factory_mac_addr[0], &le32, sizeof(u32));
if (dfx_hw_port_ctrl_req(bp, PI_PCTRL_M_MLA, PI_PDATA_A_MLA_K_HI, 0,
&data) != DFX_K_SUCCESS) {
@@ -869,8 +1031,8 @@ static int __devinit dfx_driver_init(struct net_device *dev,
print_name);
return(DFX_K_FAILURE);
}
- data = cpu_to_le32(data);
- memcpy(&bp->factory_mac_addr[4], &data, sizeof(u16));
+ le32 = cpu_to_le32(data);
+ memcpy(&bp->factory_mac_addr[4], &le32, sizeof(u16));
/*
* Set current address to factory address
@@ -880,20 +1042,18 @@ static int __devinit dfx_driver_init(struct net_device *dev,
*/
memcpy(dev->dev_addr, bp->factory_mac_addr, FDDI_K_ALEN);
- if (bp->bus_type == DFX_BUS_TYPE_EISA)
- printk("%s: DEFEA at I/O addr = 0x%lX, IRQ = %d, "
- "Hardware addr = %02X-%02X-%02X-%02X-%02X-%02X\n",
- print_name, dev->base_addr, 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]);
- else
- printk("%s: DEFPA at I/O addr = 0x%lX, IRQ = %d, "
- "Hardware addr = %02X-%02X-%02X-%02X-%02X-%02X\n",
- print_name, dev->base_addr, 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]);
+ if (dfx_bus_tc)
+ board_name = "DEFTA";
+ if (dfx_bus_eisa)
+ 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",
+ 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]);
/*
* Get memory for descriptor block, consumer block, and other buffers
@@ -908,8 +1068,9 @@ static int __devinit dfx_driver_init(struct net_device *dev,
#endif
sizeof(PI_CONSUMER_BLOCK) +
(PI_ALIGN_K_DESC_BLK - 1);
- bp->kmalloced = top_v = pci_alloc_consistent(bp->pci_dev, alloc_size,
- &bp->kmalloced_dma);
+ bp->kmalloced = top_v = dma_alloc_coherent(bp->bus_dev, alloc_size,
+ &bp->kmalloced_dma,
+ GFP_ATOMIC);
if (top_v == NULL) {
printk("%s: Could not allocate memory for host buffers "
"and structures!\n", print_name);
@@ -1219,14 +1380,15 @@ static int dfx_adap_init(DFX_board_t *bp, int get_buffers)
static int dfx_open(struct net_device *dev)
{
+ DFX_board_t *bp = netdev_priv(dev);
int ret;
- DFX_board_t *bp = dev->priv;
DBG_printk("In dfx_open...\n");
/* Register IRQ - support shared interrupts by passing device ptr */
- ret = request_irq(dev->irq, dfx_interrupt, IRQF_SHARED, dev->name, dev);
+ ret = request_irq(dev->irq, dfx_interrupt, IRQF_SHARED, dev->name,
+ dev);
if (ret) {
printk(KERN_ERR "%s: Requested IRQ %d is busy\n", dev->name, dev->irq);
return ret;
@@ -1309,7 +1471,7 @@ static int dfx_open(struct net_device *dev)
static int dfx_close(struct net_device *dev)
{
- DFX_board_t *bp = dev->priv;
+ DFX_board_t *bp = netdev_priv(dev);
DBG_printk("In dfx_close...\n");
@@ -1645,7 +1807,7 @@ static void dfx_int_type_0_process(DFX_board_t *bp)
static void dfx_int_common(struct net_device *dev)
{
- DFX_board_t *bp = dev->priv;
+ DFX_board_t *bp = netdev_priv(dev);
PI_UINT32 port_status; /* Port Status register */
/* Process xmt interrupts - frequent case, so always call this routine */
@@ -1715,18 +1877,16 @@ static void dfx_int_common(struct net_device *dev)
static irqreturn_t dfx_interrupt(int irq, void *dev_id)
{
- struct net_device *dev = dev_id;
- DFX_board_t *bp; /* private board structure pointer */
-
- /* Get board pointer only if device structure is valid */
-
- bp = dev->priv;
-
- /* See if we're already servicing an interrupt */
+ struct net_device *dev = dev_id;
+ DFX_board_t *bp = netdev_priv(dev);
+ struct device *bdev = bp->bus_dev;
+ int dfx_bus_pci = DFX_BUS_PCI(bdev);
+ int dfx_bus_eisa = DFX_BUS_EISA(bdev);
+ int dfx_bus_tc = DFX_BUS_TC(bdev);
/* Service adapter interrupts */
- if (bp->bus_type == DFX_BUS_TYPE_PCI) {
+ if (dfx_bus_pci) {
u32 status;
dfx_port_read_long(bp, PFI_K_REG_STATUS, &status);
@@ -1750,10 +1910,12 @@ static irqreturn_t dfx_interrupt(int irq, void *dev_id)
PFI_MODE_M_DMA_ENB));
spin_unlock(&bp->lock);
- } else {
+ }
+ if (dfx_bus_eisa) {
+ unsigned long base_addr = to_eisa_device(bdev)->base_addr;
u8 status;
- dfx_port_read_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, &status);
+ status = inb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0);
if (!(status & PI_CONFIG_STAT_0_M_PEND))
return IRQ_NONE;
@@ -1761,15 +1923,35 @@ static irqreturn_t dfx_interrupt(int irq, void *dev_id)
/* Disable interrupts at the ESIC */
status &= ~PI_CONFIG_STAT_0_M_INT_ENB;
- dfx_port_write_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, status);
+ outb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0, status);
/* Call interrupt service routine for this adapter */
dfx_int_common(dev);
/* Reenable interrupts at the ESIC */
- dfx_port_read_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, &status);
+ status = inb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0);
status |= PI_CONFIG_STAT_0_M_INT_ENB;
- dfx_port_write_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, status);
+ outb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0, status);
+
+ spin_unlock(&bp->lock);
+ }
+ if (dfx_bus_tc) {
+ u32 status;
+
+ dfx_port_read_long(bp, PI_PDQ_K_REG_PORT_STATUS, &status);
+ if (!(status & (PI_PSTATUS_M_RCV_DATA_PENDING |
+ PI_PSTATUS_M_XMT_DATA_PENDING |
+ PI_PSTATUS_M_SMT_HOST_PENDING |
+ PI_PSTATUS_M_UNSOL_PENDING |
+ PI_PSTATUS_M_CMD_RSP_PENDING |
+ PI_PSTATUS_M_CMD_REQ_PENDING |
+ PI_PSTATUS_M_TYPE_0_PENDING)))
+ return IRQ_NONE;
+
+ spin_lock(&bp->lock);
+
+ /* Call interrupt service routine for this adapter */
+ dfx_int_common(dev);
spin_unlock(&bp->lock);
}
@@ -1823,7 +2005,7 @@ static irqreturn_t dfx_interrupt(int irq, void *dev_id)
static struct net_device_stats *dfx_ctl_get_stats(struct net_device *dev)
{
- DFX_board_t *bp = dev->priv;
+ DFX_board_t *bp = netdev_priv(dev);
/* Fill the bp->stats structure with driver-maintained counters */
@@ -2009,8 +2191,8 @@ static struct net_device_stats *dfx_ctl_get_stats(struct net_device *dev)
*/
static void dfx_ctl_set_multicast_list(struct net_device *dev)
- {
- DFX_board_t *bp = dev->priv;
+{
+ DFX_board_t *bp = netdev_priv(dev);
int i; /* used as index in for loop */
struct dev_mc_list *dmi; /* ptr to multicast addr entry */
@@ -2124,8 +2306,8 @@ static void dfx_ctl_set_multicast_list(struct net_device *dev)
static int dfx_ctl_set_mac_address(struct net_device *dev, void *addr)
{
- DFX_board_t *bp = dev->priv;
struct sockaddr *p_sockaddr = (struct sockaddr *)addr;
+ DFX_board_t *bp = netdev_priv(dev);
/* Copy unicast address to driver-maintained structs and update count */
@@ -2764,9 +2946,9 @@ static int dfx_rcv_init(DFX_board_t *bp, int get_buffers)
my_skb_align(newskb, 128);
bp->descr_block_virt->rcv_data[i + j].long_1 =
- (u32)pci_map_single(bp->pci_dev, newskb->data,
+ (u32)dma_map_single(bp->bus_dev, newskb->data,
NEW_SKB_SIZE,
- PCI_DMA_FROMDEVICE);
+ DMA_FROM_DEVICE);
/*
* p_rcv_buff_va is only used inside the
* kernel so we put the skb pointer here.
@@ -2880,17 +3062,17 @@ static void dfx_rcv_queue_process(
my_skb_align(newskb, 128);
skb = (struct sk_buff *)bp->p_rcv_buff_va[entry];
- pci_unmap_single(bp->pci_dev,
+ dma_unmap_single(bp->bus_dev,
bp->descr_block_virt->rcv_data[entry].long_1,
NEW_SKB_SIZE,
- PCI_DMA_FROMDEVICE);
+ DMA_FROM_DEVICE);
skb_reserve(skb, RCV_BUFF_K_PADDING);
bp->p_rcv_buff_va[entry] = (char *)newskb;
bp->descr_block_virt->rcv_data[entry].long_1 =
- (u32)pci_map_single(bp->pci_dev,
+ (u32)dma_map_single(bp->bus_dev,
newskb->data,
NEW_SKB_SIZE,
- PCI_DMA_FROMDEVICE);
+ DMA_FROM_DEVICE);
} else
skb = NULL;
} else
@@ -3010,7 +3192,7 @@ static int dfx_xmt_queue_pkt(
)
{
- DFX_board_t *bp = dev->priv;
+ DFX_board_t *bp = netdev_priv(dev);
u8 prod; /* local transmit producer index */
PI_XMT_DESCR *p_xmt_descr; /* ptr to transmit descriptor block entry */
XMT_DRIVER_DESCR *p_xmt_drv_descr; /* ptr to transmit driver descriptor */
@@ -3116,8 +3298,8 @@ static int dfx_xmt_queue_pkt(
*/
p_xmt_descr->long_0 = (u32) (PI_XMT_DESCR_M_SOP | PI_XMT_DESCR_M_EOP | ((skb->len) << PI_XMT_DESCR_V_SEG_LEN));
- p_xmt_descr->long_1 = (u32)pci_map_single(bp->pci_dev, skb->data,
- skb->len, PCI_DMA_TODEVICE);
+ p_xmt_descr->long_1 = (u32)dma_map_single(bp->bus_dev, skb->data,
+ skb->len, DMA_TO_DEVICE);
/*
* Verify that descriptor is actually available
@@ -3220,10 +3402,10 @@ static int dfx_xmt_done(DFX_board_t *bp)
/* Return skb to operating system */
comp = bp->rcv_xmt_reg.index.xmt_comp;
- pci_unmap_single(bp->pci_dev,
+ dma_unmap_single(bp->bus_dev,
bp->descr_block_virt->xmt_data[comp].long_1,
p_xmt_drv_descr->p_skb->len,
- PCI_DMA_TODEVICE);
+ DMA_TO_DEVICE);
dev_kfree_skb_irq(p_xmt_drv_descr->p_skb);
/*
@@ -3344,10 +3526,10 @@ static void dfx_xmt_flush( DFX_board_t *bp )
/* Return skb to operating system */
comp = bp->rcv_xmt_reg.index.xmt_comp;
- pci_unmap_single(bp->pci_dev,
+ dma_unmap_single(bp->bus_dev,
bp->descr_block_virt->xmt_data[comp].long_1,
p_xmt_drv_descr->p_skb->len,
- PCI_DMA_TODEVICE);
+ DMA_TO_DEVICE);
dev_kfree_skb(p_xmt_drv_descr->p_skb);
/* Increment transmit error counter */
@@ -3375,13 +3557,44 @@ static void dfx_xmt_flush( DFX_board_t *bp )
bp->cons_block_virt->xmt_rcv_data = prod_cons;
}
-static void __devexit dfx_remove_one_pci_or_eisa(struct pci_dev *pdev, struct net_device *dev)
+/*
+ * ==================
+ * = dfx_unregister =
+ * ==================
+ *
+ * Overview:
+ * Shuts down an FDDI controller
+ *
+ * Returns:
+ * Condition code
+ *
+ * Arguments:
+ * bdev - pointer to device information
+ *
+ * Functional Description:
+ *
+ * Return Codes:
+ * None
+ *
+ * Assumptions:
+ * It compiles so it should work :-( (PCI cards do :-)
+ *
+ * Side Effects:
+ * Device structures for FDDI adapters (fddi0, fddi1, etc) are
+ * freed.
+ */
+static void __devexit dfx_unregister(struct device *bdev)
{
- DFX_board_t *bp = dev->priv;
+ struct net_device *dev = dev_get_drvdata(bdev);
+ DFX_board_t *bp = netdev_priv(dev);
+ int dfx_bus_pci = DFX_BUS_PCI(bdev);
+ int dfx_bus_tc = DFX_BUS_TC(bdev);
+ int dfx_use_mmio = DFX_MMIO || dfx_bus_tc;
+ resource_size_t bar_start = 0; /* pointer to port */
+ resource_size_t bar_len = 0; /* resource length */
int alloc_size; /* total buffer size used */
unregister_netdev(dev);
- release_region(dev->base_addr, pdev ? PFI_K_CSR_IO_LEN : PI_ESIC_K_CSR_IO_LEN );
alloc_size = sizeof(PI_DESCR_BLOCK) +
PI_CMD_REQ_K_SIZE_MAX + PI_CMD_RSP_K_SIZE_MAX +
@@ -3391,78 +3604,141 @@ static void __devexit dfx_remove_one_pci_or_eisa(struct pci_dev *pdev, struct ne
sizeof(PI_CONSUMER_BLOCK) +
(PI_ALIGN_K_DESC_BLK - 1);
if (bp->kmalloced)
- pci_free_consistent(pdev, alloc_size, bp->kmalloced,
- bp->kmalloced_dma);
+ dma_free_coherent(bdev, alloc_size,
+ bp->kmalloced, bp->kmalloced_dma);
+
+ dfx_bus_uninit(dev);
+
+ dfx_get_bars(bdev, &bar_start, &bar_len);
+ if (dfx_use_mmio) {
+ iounmap(bp->base.mem);
+ release_mem_region(bar_start, bar_len);
+ } else
+ release_region(bar_start, bar_len);
+
+ if (dfx_bus_pci)
+ pci_disable_device(to_pci_dev(bdev));
+
free_netdev(dev);
}
-static void __devexit dfx_remove_one (struct pci_dev *pdev)
-{
- struct net_device *dev = pci_get_drvdata(pdev);
- dfx_remove_one_pci_or_eisa(pdev, dev);
- pci_set_drvdata(pdev, NULL);
-}
+static int __devinit __unused dfx_dev_register(struct device *);
+static int __devexit __unused dfx_dev_unregister(struct device *);
-static struct pci_device_id dfx_pci_tbl[] = {
- { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_FDDI, PCI_ANY_ID, PCI_ANY_ID, },
- { 0, }
+#ifdef CONFIG_PCI
+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[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_FDDI) },
+ { }
};
-MODULE_DEVICE_TABLE(pci, dfx_pci_tbl);
+MODULE_DEVICE_TABLE(pci, dfx_pci_table);
-static struct pci_driver dfx_driver = {
+static struct pci_driver dfx_pci_driver = {
.name = "defxx",
- .probe = dfx_init_one,
- .remove = __devexit_p(dfx_remove_one),
- .id_table = dfx_pci_tbl,
+ .id_table = dfx_pci_table,
+ .probe = dfx_pci_register,
+ .remove = __devexit_p(dfx_pci_unregister),
};
-static int dfx_have_pci;
-static int dfx_have_eisa;
-
+static __devinit int dfx_pci_register(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ return dfx_register(&pdev->dev);
+}
-static void __exit dfx_eisa_cleanup(void)
+static void __devexit dfx_pci_unregister(struct pci_dev *pdev)
{
- struct net_device *dev = root_dfx_eisa_dev;
+ dfx_unregister(&pdev->dev);
+}
+#endif /* CONFIG_PCI */
+
+#ifdef CONFIG_EISA
+static struct eisa_device_id dfx_eisa_table[] = {
+ { "DEC3001", DEFEA_PROD_ID_1 },
+ { "DEC3002", DEFEA_PROD_ID_2 },
+ { "DEC3003", DEFEA_PROD_ID_3 },
+ { "DEC3004", DEFEA_PROD_ID_4 },
+ { }
+};
+MODULE_DEVICE_TABLE(eisa, dfx_eisa_table);
+
+static struct eisa_driver dfx_eisa_driver = {
+ .id_table = dfx_eisa_table,
+ .driver = {
+ .name = "defxx",
+ .bus = &eisa_bus_type,
+ .probe = dfx_dev_register,
+ .remove = __devexit_p(dfx_dev_unregister),
+ },
+};
+#endif /* CONFIG_EISA */
+
+#ifdef CONFIG_TC
+static struct tc_device_id const dfx_tc_table[] = {
+ { "DEC ", "PMAF-FA " },
+ { "DEC ", "PMAF-FD " },
+ { "DEC ", "PMAF-FS " },
+ { "DEC ", "PMAF-FU " },
+ { }
+};
+MODULE_DEVICE_TABLE(tc, dfx_tc_table);
+
+static struct tc_driver dfx_tc_driver = {
+ .id_table = dfx_tc_table,
+ .driver = {
+ .name = "defxx",
+ .bus = &tc_bus_type,
+ .probe = dfx_dev_register,
+ .remove = __devexit_p(dfx_dev_unregister),
+ },
+};
+#endif /* CONFIG_TC */
- while (dev)
- {
- struct net_device *tmp;
- DFX_board_t *bp;
+static int __devinit __unused dfx_dev_register(struct device *dev)
+{
+ int status;
- bp = (DFX_board_t*)dev->priv;
- tmp = bp->next;
- dfx_remove_one_pci_or_eisa(NULL, dev);
- dev = tmp;
- }
+ status = dfx_register(dev);
+ if (!status)
+ get_device(dev);
+ return status;
}
-static int __init dfx_init(void)
+static int __devexit __unused dfx_dev_unregister(struct device *dev)
{
- int rc_pci, rc_eisa;
-
- rc_pci = pci_register_driver(&dfx_driver);
- if (rc_pci >= 0) dfx_have_pci = 1;
+ put_device(dev);
+ dfx_unregister(dev);
+ return 0;
+}
- rc_eisa = dfx_eisa_init();
- if (rc_eisa >= 0) dfx_have_eisa = 1;
- return ((rc_eisa < 0) ? 0 : rc_eisa) + ((rc_pci < 0) ? 0 : rc_pci);
+static int __devinit dfx_init(void)
+{
+ int status;
+
+ status = pci_register_driver(&dfx_pci_driver);
+ if (!status)
+ status = eisa_driver_register(&dfx_eisa_driver);
+ if (!status)
+ status = tc_register_driver(&dfx_tc_driver);
+ return status;
}
-static void __exit dfx_cleanup(void)
+static void __devexit dfx_cleanup(void)
{
- if (dfx_have_pci)
- pci_unregister_driver(&dfx_driver);
- if (dfx_have_eisa)
- dfx_eisa_cleanup();
-
+ tc_unregister_driver(&dfx_tc_driver);
+ eisa_driver_unregister(&dfx_eisa_driver);
+ pci_unregister_driver(&dfx_pci_driver);
}
module_init(dfx_init);
module_exit(dfx_cleanup);
MODULE_AUTHOR("Lawrence V. Stefani");
-MODULE_DESCRIPTION("DEC FDDIcontroller EISA/PCI (DEFEA/DEFPA) driver "
+MODULE_DESCRIPTION("DEC FDDIcontroller TC/EISA/PCI (DEFTA/DEFEA/DEFPA) driver "
DRV_VERSION " " DRV_RELDATE);
MODULE_LICENSE("GPL");
diff --git a/drivers/net/defxx.h b/drivers/net/defxx.h
index 2ce8f97253e..19a6f64df19 100644
--- a/drivers/net/defxx.h
+++ b/drivers/net/defxx.h
@@ -26,6 +26,7 @@
* 12-Sep-96 LVS Removed packet request header pointers.
* 04 Aug 2003 macro Converted to the DMA API.
* 23 Oct 2006 macro Big-endian host support.
+ * 14 Dec 2006 macro TURBOchannel support.
*/
#ifndef _DEFXX_H_
@@ -1471,9 +1472,17 @@ typedef union
#endif /* __BIG_ENDIAN */
+/* Define TC PDQ CSR offset and length */
+
+#define PI_TC_K_CSR_OFFSET 0x100000
+#define PI_TC_K_CSR_LEN 0x40 /* 64 bytes */
+
/* Define EISA controller register offsets */
-#define PI_ESIC_K_BURST_HOLDOFF 0x040
+#define PI_ESIC_K_CSR_IO_LEN 0x80 /* 128 bytes */
+
+#define PI_DEFEA_K_BURST_HOLDOFF 0x040
+
#define PI_ESIC_K_SLOT_ID 0xC80
#define PI_ESIC_K_SLOT_CNTRL 0xC84
#define PI_ESIC_K_MEM_ADD_CMP_0 0xC85
@@ -1488,14 +1497,14 @@ typedef union
#define PI_ESIC_K_MEM_ADD_LO_CMP_0 0xC8E
#define PI_ESIC_K_MEM_ADD_LO_CMP_1 0xC8F
#define PI_ESIC_K_MEM_ADD_LO_CMP_2 0xC90
-#define PI_ESIC_K_IO_CMP_0_0 0xC91
-#define PI_ESIC_K_IO_CMP_0_1 0xC92
-#define PI_ESIC_K_IO_CMP_1_0 0xC93
-#define PI_ESIC_K_IO_CMP_1_1 0xC94
-#define PI_ESIC_K_IO_CMP_2_0 0xC95
-#define PI_ESIC_K_IO_CMP_2_1 0xC96
-#define PI_ESIC_K_IO_CMP_3_0 0xC97
-#define PI_ESIC_K_IO_CMP_3_1 0xC98
+#define PI_ESIC_K_IO_ADD_CMP_0_0 0xC91
+#define PI_ESIC_K_IO_ADD_CMP_0_1 0xC92
+#define PI_ESIC_K_IO_ADD_CMP_1_0 0xC93
+#define PI_ESIC_K_IO_ADD_CMP_1_1 0xC94
+#define PI_ESIC_K_IO_ADD_CMP_2_0 0xC95
+#define PI_ESIC_K_IO_ADD_CMP_2_1 0xC96
+#define PI_ESIC_K_IO_ADD_CMP_3_0 0xC97
+#define PI_ESIC_K_IO_ADD_CMP_3_1 0xC98
#define PI_ESIC_K_IO_ADD_MASK_0_0 0xC99
#define PI_ESIC_K_IO_ADD_MASK_0_1 0xC9A
#define PI_ESIC_K_IO_ADD_MASK_1_0 0xC9B
@@ -1518,11 +1527,16 @@ typedef union
#define PI_ESIC_K_INPUT_PORT 0xCAC
#define PI_ESIC_K_OUTPUT_PORT 0xCAD
#define PI_ESIC_K_FUNCTION_CNTRL 0xCAE
-#define PI_ESIC_K_CSR_IO_LEN PI_ESIC_K_FUNCTION_CNTRL+1 /* always last reg + 1 */
-/* Define the value all drivers must write to the function control register. */
+/* Define the bits in the function control register. */
-#define PI_ESIC_K_FUNCTION_CNTRL_IO_ENB 0x03
+#define PI_FUNCTION_CNTRL_M_IOCS0 0x01
+#define PI_FUNCTION_CNTRL_M_IOCS1 0x02
+#define PI_FUNCTION_CNTRL_M_IOCS2 0x04
+#define PI_FUNCTION_CNTRL_M_IOCS3 0x08
+#define PI_FUNCTION_CNTRL_M_MEMCS0 0x10
+#define PI_FUNCTION_CNTRL_M_MEMCS1 0x20
+#define PI_FUNCTION_CNTRL_M_DMA 0x80
/* Define the bits in the slot control register. */
@@ -1540,6 +1554,10 @@ typedef union
#define PI_BURST_HOLDOFF_V_RESERVED 1
#define PI_BURST_HOLDOFF_V_MEM_MAP 0
+/* Define the implicit mask of the Memory Address Mask Register. */
+
+#define PI_MEM_ADD_MASK_M 0x3ff
+
/*
* Define the fields in the IO Compare registers.
* The driver must initialize the slot field with the slot ID shifted by the
@@ -1577,6 +1595,7 @@ typedef union
#define DEFEA_PROD_ID_1 0x0130A310 /* DEC product 300, rev 1 */
#define DEFEA_PROD_ID_2 0x0230A310 /* DEC product 300, rev 2 */
#define DEFEA_PROD_ID_3 0x0330A310 /* DEC product 300, rev 3 */
+#define DEFEA_PROD_ID_4 0x0430A310 /* DEC product 300, rev 4 */
/**********************************************/
/* Digital PFI Specification v1.0 Definitions */
@@ -1633,12 +1652,6 @@ typedef union
#define PFI_STATUS_V_FIFO_EMPTY 1
#define PFI_STATUS_V_DMA_IN_PROGRESS 0
-#define DFX_MAX_EISA_SLOTS 16 /* maximum number of EISA slots to scan */
-#define DFX_MAX_NUM_BOARDS 8 /* maximum number of adapters supported */
-
-#define DFX_BUS_TYPE_PCI 0 /* type code for DEC FDDIcontroller/PCI */
-#define DFX_BUS_TYPE_EISA 1 /* type code for DEC FDDIcontroller/EISA */
-
#define DFX_FC_PRH2_PRH1_PRH0 0x54003820 /* Packet Request Header bytes + FC */
#define DFX_PRH0_BYTE 0x20 /* Packet Request Header byte 0 */
#define DFX_PRH1_BYTE 0x38 /* Packet Request Header byte 1 */
@@ -1756,10 +1769,11 @@ typedef struct DFX_board_tag
/* Store device, bus-specific, and parameter information for this adapter */
struct net_device *dev; /* pointer to device structure */
- struct net_device *next;
- u32 bus_type; /* bus type (0 == PCI, 1 == EISA) */
- u16 base_addr; /* base I/O address (same as dev->base_addr) */
- struct pci_dev * pci_dev;
+ union {
+ void __iomem *mem;
+ int port;
+ } base; /* base address */
+ struct device *bus_dev;
u32 full_duplex_enb; /* FDDI Full Duplex enable (1 == on, 2 == off) */
u32 req_ttrt; /* requested TTRT value (in 80ns units) */
u32 burst_size; /* adapter burst size (enumerated) */
diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
index f091042b146..dd4b728ac4b 100644
--- a/drivers/net/e1000/e1000.h
+++ b/drivers/net/e1000/e1000.h
@@ -59,17 +59,13 @@
#include <linux/capability.h>
#include <linux/in.h>
#include <linux/ip.h>
-#ifdef NETIF_F_TSO6
#include <linux/ipv6.h>
-#endif
#include <linux/tcp.h>
#include <linux/udp.h>
#include <net/pkt_sched.h>
#include <linux/list.h>
#include <linux/reboot.h>
-#ifdef NETIF_F_TSO
#include <net/checksum.h>
-#endif
#include <linux/mii.h>
#include <linux/ethtool.h>
#include <linux/if_vlan.h>
@@ -257,7 +253,6 @@ struct e1000_adapter {
spinlock_t tx_queue_lock;
#endif
atomic_t irq_sem;
- unsigned int detect_link;
unsigned int total_tx_bytes;
unsigned int total_tx_packets;
unsigned int total_rx_bytes;
@@ -342,15 +337,12 @@ struct e1000_adapter {
struct e1000_rx_ring test_rx_ring;
- uint32_t *config_space;
int msg_enable;
#ifdef CONFIG_PCI_MSI
boolean_t have_msi;
#endif
/* to not mess up cache alignment, always add to the bottom */
-#ifdef NETIF_F_TSO
boolean_t tso_force;
-#endif
boolean_t smart_power_down; /* phy smart power down */
boolean_t quad_port_a;
unsigned long flags;
diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c
index fb96c87f9e5..6777887295f 100644
--- a/drivers/net/e1000/e1000_ethtool.c
+++ b/drivers/net/e1000/e1000_ethtool.c
@@ -166,7 +166,7 @@ e1000_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
ecmd->transceiver = XCVR_EXTERNAL;
}
- if (netif_carrier_ok(adapter->netdev)) {
+ if (E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU) {
e1000_get_speed_and_duplex(hw, &adapter->link_speed,
&adapter->link_duplex);
@@ -338,7 +338,6 @@ e1000_set_tx_csum(struct net_device *netdev, uint32_t data)
return 0;
}
-#ifdef NETIF_F_TSO
static int
e1000_set_tso(struct net_device *netdev, uint32_t data)
{
@@ -352,18 +351,15 @@ e1000_set_tso(struct net_device *netdev, uint32_t data)
else
netdev->features &= ~NETIF_F_TSO;
-#ifdef NETIF_F_TSO6
if (data)
netdev->features |= NETIF_F_TSO6;
else
netdev->features &= ~NETIF_F_TSO6;
-#endif
DPRINTK(PROBE, INFO, "TSO is %s\n", data ? "Enabled" : "Disabled");
adapter->tso_force = TRUE;
return 0;
}
-#endif /* NETIF_F_TSO */
static uint32_t
e1000_get_msglevel(struct net_device *netdev)
@@ -1971,10 +1967,8 @@ static const struct ethtool_ops e1000_ethtool_ops = {
.set_tx_csum = e1000_set_tx_csum,
.get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
-#ifdef NETIF_F_TSO
.get_tso = ethtool_op_get_tso,
.set_tso = e1000_set_tso,
-#endif
.self_test_count = e1000_diag_test_count,
.self_test = e1000_diag_test,
.get_strings = e1000_get_strings,
diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h
index d6710588334..bd000b802ee 100644
--- a/drivers/net/e1000/e1000_hw.h
+++ b/drivers/net/e1000/e1000_hw.h
@@ -3253,7 +3253,7 @@ struct e1000_host_command_info {
#define IFE_PMC_AUTO_MDIX 0x0080 /* 1=enable MDI/MDI-X feature, default 0=disabled */
#define IFE_PMC_FORCE_MDIX 0x0040 /* 1=force MDIX-X, 0=force MDI */
#define IFE_PMC_MDIX_STATUS 0x0020 /* 1=MDI-X, 0=MDI */
-#define IFE_PMC_AUTO_MDIX_COMPLETE 0x0010 /* Resolution algorthm is completed */
+#define IFE_PMC_AUTO_MDIX_COMPLETE 0x0010 /* Resolution algorithm is completed */
#define IFE_PMC_MDIX_MODE_SHIFT 6
#define IFE_PHC_MDIX_RESET_ALL_MASK 0x0000 /* Disable auto MDI-X */
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index c6259c7127f..98215fdd7d1 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -36,7 +36,7 @@ static char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver";
#else
#define DRIVERNAPI "-NAPI"
#endif
-#define DRV_VERSION "7.3.15-k2"DRIVERNAPI
+#define DRV_VERSION "7.3.20-k2"DRIVERNAPI
char e1000_driver_version[] = DRV_VERSION;
static char e1000_copyright[] = "Copyright (c) 1999-2006 Intel Corporation.";
@@ -990,16 +990,12 @@ e1000_probe(struct pci_dev *pdev,
netdev->features &= ~NETIF_F_HW_VLAN_FILTER;
}
-#ifdef NETIF_F_TSO
if ((adapter->hw.mac_type >= e1000_82544) &&
(adapter->hw.mac_type != e1000_82547))
netdev->features |= NETIF_F_TSO;
-#ifdef NETIF_F_TSO6
if (adapter->hw.mac_type > e1000_82547_rev_2)
netdev->features |= NETIF_F_TSO6;
-#endif
-#endif
if (pci_using_dac)
netdev->features |= NETIF_F_HIGHDMA;
@@ -2583,15 +2579,22 @@ e1000_watchdog(unsigned long data)
if (link) {
if (!netif_carrier_ok(netdev)) {
+ uint32_t ctrl;
boolean_t txb2b = 1;
e1000_get_speed_and_duplex(&adapter->hw,
&adapter->link_speed,
&adapter->link_duplex);
- DPRINTK(LINK, INFO, "NIC Link is Up %d Mbps %s\n",
- adapter->link_speed,
- adapter->link_duplex == FULL_DUPLEX ?
- "Full Duplex" : "Half Duplex");
+ ctrl = E1000_READ_REG(&adapter->hw, CTRL);
+ DPRINTK(LINK, INFO, "NIC Link is Up %d Mbps %s, "
+ "Flow Control: %s\n",
+ adapter->link_speed,
+ adapter->link_duplex == FULL_DUPLEX ?
+ "Full Duplex" : "Half Duplex",
+ ((ctrl & E1000_CTRL_TFCE) && (ctrl &
+ E1000_CTRL_RFCE)) ? "RX/TX" : ((ctrl &
+ E1000_CTRL_RFCE) ? "RX" : ((ctrl &
+ E1000_CTRL_TFCE) ? "TX" : "None" )));
/* tweak tx_queue_len according to speed/duplex
* and adjust the timeout factor */
@@ -2619,7 +2622,6 @@ e1000_watchdog(unsigned long data)
E1000_WRITE_REG(&adapter->hw, TARC0, tarc0);
}
-#ifdef NETIF_F_TSO
/* disable TSO for pcie and 10/100 speeds, to avoid
* some hardware issues */
if (!adapter->tso_force &&
@@ -2630,22 +2632,17 @@ e1000_watchdog(unsigned long data)
DPRINTK(PROBE,INFO,
"10/100 speed: disabling TSO\n");
netdev->features &= ~NETIF_F_TSO;
-#ifdef NETIF_F_TSO6
netdev->features &= ~NETIF_F_TSO6;
-#endif
break;
case SPEED_1000:
netdev->features |= NETIF_F_TSO;
-#ifdef NETIF_F_TSO6
netdev->features |= NETIF_F_TSO6;
-#endif
break;
default:
/* oops */
break;
}
}
-#endif
/* enable transmits in the hardware, need to do this
* after setting TARC0 */
@@ -2875,7 +2872,6 @@ static int
e1000_tso(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
struct sk_buff *skb)
{
-#ifdef NETIF_F_TSO
struct e1000_context_desc *context_desc;
struct e1000_buffer *buffer_info;
unsigned int i;
@@ -2904,7 +2900,6 @@ e1000_tso(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
0);
cmd_length = E1000_TXD_CMD_IP;
ipcse = skb->h.raw - skb->data - 1;
-#ifdef NETIF_F_TSO6
} else if (skb->protocol == htons(ETH_P_IPV6)) {
skb->nh.ipv6h->payload_len = 0;
skb->h.th->check =
@@ -2914,7 +2909,6 @@ e1000_tso(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
IPPROTO_TCP,
0);
ipcse = 0;
-#endif
}
ipcss = skb->nh.raw - skb->data;
ipcso = (void *)&(skb->nh.iph->check) - (void *)skb->data;
@@ -2947,8 +2941,6 @@ e1000_tso(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
return TRUE;
}
-#endif
-
return FALSE;
}
@@ -2968,8 +2960,9 @@ e1000_tx_csum(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
buffer_info = &tx_ring->buffer_info[i];
context_desc = E1000_CONTEXT_DESC(*tx_ring, i);
+ context_desc->lower_setup.ip_config = 0;
context_desc->upper_setup.tcp_fields.tucss = css;
- context_desc->upper_setup.tcp_fields.tucso = css + skb->csum_offset;
+ context_desc->upper_setup.tcp_fields.tucso = css + skb->csum;
context_desc->upper_setup.tcp_fields.tucse = 0;
context_desc->tcp_seg_setup.data = 0;
context_desc->cmd_and_length = cpu_to_le32(E1000_TXD_CMD_DEXT);
@@ -3005,7 +2998,6 @@ e1000_tx_map(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
while (len) {
buffer_info = &tx_ring->buffer_info[i];
size = min(len, max_per_txd);
-#ifdef NETIF_F_TSO
/* Workaround for Controller erratum --
* descriptor for non-tso packet in a linear SKB that follows a
* tso gets written back prematurely before the data is fully
@@ -3020,7 +3012,6 @@ e1000_tx_map(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
* in TSO mode. Append 4-byte sentinel desc */
if (unlikely(mss && !nr_frags && size == len && size > 8))
size -= 4;
-#endif
/* work-around for errata 10 and it applies
* to all controllers in PCI-X mode
* The fix is to make sure that the first descriptor of a
@@ -3062,12 +3053,10 @@ e1000_tx_map(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
while (len) {
buffer_info = &tx_ring->buffer_info[i];
size = min(len, max_per_txd);
-#ifdef NETIF_F_TSO
/* Workaround for premature desc write-backs
* in TSO mode. Append 4-byte sentinel desc */
if (unlikely(mss && f == (nr_frags-1) && size == len && size > 8))
size -= 4;
-#endif
/* Workaround for potential 82544 hang in PCI-X.
* Avoid terminating buffers within evenly-aligned
* dwords. */
@@ -3292,7 +3281,6 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
if (adapter->hw.mac_type >= e1000_82571)
max_per_txd = 8192;
-#ifdef NETIF_F_TSO
mss = skb_shinfo(skb)->gso_size;
/* The controller does a simple calculation to
* make sure there is enough room in the FIFO before
@@ -3346,16 +3334,10 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
if ((mss) || (skb->ip_summed == CHECKSUM_PARTIAL))
count++;
count++;
-#else
- if (skb->ip_summed == CHECKSUM_PARTIAL)
- count++;
-#endif
-#ifdef NETIF_F_TSO
/* Controller Erratum workaround */
if (!skb->data_len && tx_ring->last_tx_tso && !skb_is_gso(skb))
count++;
-#endif
count += TXD_USE_COUNT(len, max_txd_pwr);
@@ -3602,7 +3584,7 @@ e1000_update_stats(struct e1000_adapter *adapter)
*/
if (adapter->link_speed == 0)
return;
- if (pdev->error_state && pdev->error_state != pci_channel_io_normal)
+ if (pci_channel_offline(pdev))
return;
spin_lock_irqsave(&adapter->stats_lock, flags);
@@ -3765,8 +3747,8 @@ e1000_update_stats(struct e1000_adapter *adapter)
* @data: pointer to a network interface device structure
**/
-static
-irqreturn_t e1000_intr_msi(int irq, void *data)
+static irqreturn_t
+e1000_intr_msi(int irq, void *data)
{
struct net_device *netdev = data;
struct e1000_adapter *adapter = netdev_priv(netdev);
@@ -3774,49 +3756,27 @@ irqreturn_t e1000_intr_msi(int irq, void *data)
#ifndef CONFIG_E1000_NAPI
int i;
#endif
+ uint32_t icr = E1000_READ_REG(hw, ICR);
- /* this code avoids the read of ICR but has to get 1000 interrupts
- * at every link change event before it will notice the change */
- if (++adapter->detect_link >= 1000) {
- uint32_t icr = E1000_READ_REG(hw, ICR);
#ifdef CONFIG_E1000_NAPI
- /* read ICR disables interrupts using IAM, so keep up with our
- * enable/disable accounting */
- atomic_inc(&adapter->irq_sem);
+ /* read ICR disables interrupts using IAM, so keep up with our
+ * enable/disable accounting */
+ atomic_inc(&adapter->irq_sem);
#endif
- adapter->detect_link = 0;
- if ((icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) &&
- (icr & E1000_ICR_INT_ASSERTED)) {
- hw->get_link_status = 1;
- /* 80003ES2LAN workaround--
- * For packet buffer work-around on link down event;
- * disable receives here in the ISR and
- * reset adapter in watchdog
- */
- if (netif_carrier_ok(netdev) &&
- (adapter->hw.mac_type == e1000_80003es2lan)) {
- /* disable receives */
- uint32_t rctl = E1000_READ_REG(hw, RCTL);
- E1000_WRITE_REG(hw, RCTL, rctl & ~E1000_RCTL_EN);
- }
- /* guard against interrupt when we're going down */
- if (!test_bit(__E1000_DOWN, &adapter->flags))
- mod_timer(&adapter->watchdog_timer,
- jiffies + 1);
+ if (icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
+ hw->get_link_status = 1;
+ /* 80003ES2LAN workaround-- For packet buffer work-around on
+ * link down event; disable receives here in the ISR and reset
+ * adapter in watchdog */
+ if (netif_carrier_ok(netdev) &&
+ (adapter->hw.mac_type == e1000_80003es2lan)) {
+ /* disable receives */
+ uint32_t rctl = E1000_READ_REG(hw, RCTL);
+ E1000_WRITE_REG(hw, RCTL, rctl & ~E1000_RCTL_EN);
}
- } else {
- E1000_WRITE_REG(hw, ICR, (0xffffffff & ~(E1000_ICR_RXSEQ |
- E1000_ICR_LSC)));
- /* bummer we have to flush here, but things break otherwise as
- * some event appears to be lost or delayed and throughput
- * drops. In almost all tests this flush is un-necessary */
- E1000_WRITE_FLUSH(hw);
-#ifdef CONFIG_E1000_NAPI
- /* Interrupt Auto-Mask (IAM)...upon writing ICR, interrupts are
- * masked. No need for the IMC write, but it does mean we
- * should account for it ASAP. */
- atomic_inc(&adapter->irq_sem);
-#endif
+ /* guard against interrupt when we're going down */
+ if (!test_bit(__E1000_DOWN, &adapter->flags))
+ mod_timer(&adapter->watchdog_timer, jiffies + 1);
}
#ifdef CONFIG_E1000_NAPI
@@ -3836,7 +3796,7 @@ irqreturn_t e1000_intr_msi(int irq, void *data)
for (i = 0; i < E1000_MAX_INTR; i++)
if (unlikely(!adapter->clean_rx(adapter, adapter->rx_ring) &
- !e1000_clean_tx_irq(adapter, adapter->tx_ring)))
+ e1000_clean_tx_irq(adapter, adapter->tx_ring)))
break;
if (likely(adapter->itr_setting & 3))
@@ -3939,7 +3899,7 @@ e1000_intr(int irq, void *data)
for (i = 0; i < E1000_MAX_INTR; i++)
if (unlikely(!adapter->clean_rx(adapter, adapter->rx_ring) &
- !e1000_clean_tx_irq(adapter, adapter->tx_ring)))
+ e1000_clean_tx_irq(adapter, adapter->tx_ring)))
break;
if (likely(adapter->itr_setting & 3))
@@ -3989,7 +3949,7 @@ e1000_clean(struct net_device *poll_dev, int *budget)
poll_dev->quota -= work_done;
/* If no Tx and not enough Rx work done, exit the polling mode */
- if ((!tx_cleaned && (work_done == 0)) ||
+ if ((tx_cleaned && (work_done < work_to_do)) ||
!netif_running(poll_dev)) {
quit_polling:
if (likely(adapter->itr_setting & 3))
@@ -4019,7 +3979,7 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter,
#ifdef CONFIG_E1000_NAPI
unsigned int count = 0;
#endif
- boolean_t cleaned = FALSE;
+ boolean_t cleaned = TRUE;
unsigned int total_tx_bytes=0, total_tx_packets=0;
i = tx_ring->next_to_clean;
@@ -4034,10 +3994,13 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter,
if (cleaned) {
struct sk_buff *skb = buffer_info->skb;
- unsigned int segs = skb_shinfo(skb)->gso_segs;
+ unsigned int segs, bytecount;
+ segs = skb_shinfo(skb)->gso_segs ?: 1;
+ /* multiply data chunks by size of headers */
+ bytecount = ((segs - 1) * skb_headlen(skb)) +
+ skb->len;
total_tx_packets += segs;
- total_tx_packets++;
- total_tx_bytes += skb->len;
+ total_tx_bytes += bytecount;
}
e1000_unmap_and_free_tx_resource(adapter, buffer_info);
tx_desc->upper.data = 0;
@@ -4050,7 +4013,10 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter,
#ifdef CONFIG_E1000_NAPI
#define E1000_TX_WEIGHT 64
/* weight of a sort for tx, to avoid endless transmit cleanup */
- if (count++ == E1000_TX_WEIGHT) break;
+ if (count++ == E1000_TX_WEIGHT) {
+ cleaned = FALSE;
+ break;
+ }
#endif
}
@@ -5105,58 +5071,6 @@ e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx)
return 0;
}
-#ifdef CONFIG_PM
-/* Save/restore 16 or 64 dwords of PCI config space depending on which
- * bus we're on (PCI(X) vs. PCI-E)
- */
-#define PCIE_CONFIG_SPACE_LEN 256
-#define PCI_CONFIG_SPACE_LEN 64
-static int
-e1000_pci_save_state(struct e1000_adapter *adapter)
-{
- struct pci_dev *dev = adapter->pdev;
- int size;
- int i;
-
- if (adapter->hw.mac_type >= e1000_82571)
- size = PCIE_CONFIG_SPACE_LEN;
- else
- size = PCI_CONFIG_SPACE_LEN;
-
- WARN_ON(adapter->config_space != NULL);
-
- adapter->config_space = kmalloc(size, GFP_KERNEL);
- if (!adapter->config_space) {
- DPRINTK(PROBE, ERR, "unable to allocate %d bytes\n", size);
- return -ENOMEM;
- }
- for (i = 0; i < (size / 4); i++)
- pci_read_config_dword(dev, i * 4, &adapter->config_space[i]);
- return 0;
-}
-
-static void
-e1000_pci_restore_state(struct e1000_adapter *adapter)
-{
- struct pci_dev *dev = adapter->pdev;
- int size;
- int i;
-
- if (adapter->config_space == NULL)
- return;
-
- if (adapter->hw.mac_type >= e1000_82571)
- size = PCIE_CONFIG_SPACE_LEN;
- else
- size = PCI_CONFIG_SPACE_LEN;
- for (i = 0; i < (size / 4); i++)
- pci_write_config_dword(dev, i * 4, adapter->config_space[i]);
- kfree(adapter->config_space);
- adapter->config_space = NULL;
- return;
-}
-#endif /* CONFIG_PM */
-
static int
e1000_suspend(struct pci_dev *pdev, pm_message_t state)
{
@@ -5176,9 +5090,7 @@ e1000_suspend(struct pci_dev *pdev, pm_message_t state)
}
#ifdef CONFIG_PM
- /* Implement our own version of pci_save_state(pdev) because pci-
- * express adapters have 256-byte config spaces. */
- retval = e1000_pci_save_state(adapter);
+ retval = pci_save_state(pdev);
if (retval)
return retval;
#endif
@@ -5265,7 +5177,7 @@ e1000_resume(struct pci_dev *pdev)
uint32_t err;
pci_set_power_state(pdev, PCI_D0);
- e1000_pci_restore_state(adapter);
+ pci_restore_state(pdev);
if ((err = pci_enable_device(pdev))) {
printk(KERN_ERR "e1000: Cannot enable PCI device from suspend\n");
return err;
diff --git a/drivers/net/e1000/e1000_osdep.h b/drivers/net/e1000/e1000_osdep.h
index 18afc0c25da..10af742d8a2 100644
--- a/drivers/net/e1000/e1000_osdep.h
+++ b/drivers/net/e1000/e1000_osdep.h
@@ -48,8 +48,6 @@ typedef enum {
TRUE = 1
} boolean_t;
-#define MSGOUT(S, A, B) printk(KERN_DEBUG S "\n", A, B)
-
#ifdef DBG
#define DEBUGOUT(S) printk(KERN_DEBUG S "\n")
#define DEBUGOUT1(S, A...) printk(KERN_DEBUG S "\n", A)
@@ -58,7 +56,7 @@ typedef enum {
#define DEBUGOUT1(S, A...)
#endif
-#define DEBUGFUNC(F) DEBUGOUT(F)
+#define DEBUGFUNC(F) DEBUGOUT(F "\n")
#define DEBUGOUT2 DEBUGOUT1
#define DEBUGOUT3 DEBUGOUT2
#define DEBUGOUT7 DEBUGOUT3
diff --git a/drivers/net/e1000/e1000_param.c b/drivers/net/e1000/e1000_param.c
index cf2a279307e..f8862e203ac 100644
--- a/drivers/net/e1000/e1000_param.c
+++ b/drivers/net/e1000/e1000_param.c
@@ -760,22 +760,13 @@ e1000_check_copper_options(struct e1000_adapter *adapter)
case SPEED_1000:
DPRINTK(PROBE, INFO, "1000 Mbps Speed specified without "
"Duplex\n");
- DPRINTK(PROBE, INFO,
- "Using Autonegotiation at 1000 Mbps "
- "Full Duplex only\n");
- adapter->hw.autoneg = adapter->fc_autoneg = 1;
- adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL;
- break;
+ goto full_duplex_only;
case SPEED_1000 + HALF_DUPLEX:
DPRINTK(PROBE, INFO,
"Half Duplex is not supported at 1000 Mbps\n");
- DPRINTK(PROBE, INFO,
- "Using Autonegotiation at 1000 Mbps "
- "Full Duplex only\n");
- adapter->hw.autoneg = adapter->fc_autoneg = 1;
- adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL;
- break;
+ /* fall through */
case SPEED_1000 + FULL_DUPLEX:
+full_duplex_only:
DPRINTK(PROBE, INFO,
"Using Autonegotiation at 1000 Mbps Full Duplex only\n");
adapter->hw.autoneg = adapter->fc_autoneg = 1;
diff --git a/drivers/net/e2100.c b/drivers/net/e2100.c
index c62d9c6363c..b2b0a96218c 100644
--- a/drivers/net/e2100.c
+++ b/drivers/net/e2100.c
@@ -355,8 +355,7 @@ e21_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring
mem_on(ioaddr, shared_mem, (ring_offset>>8));
- /* Packet is always in one chunk -- we can copy + cksum. */
- eth_io_copy_and_sum(skb, ei_status.mem + (ring_offset & 0xff), count, 0);
+ memcpy_fromio(skb->data, ei_status.mem + (ring_offset & 0xff), count);
mem_off(ioaddr);
}
diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c
index 4a50fcb5ad6..3868b803126 100644
--- a/drivers/net/eexpress.c
+++ b/drivers/net/eexpress.c
@@ -714,13 +714,6 @@ static int eexp_xmit(struct sk_buff *buf, struct net_device *dev)
* check to make sure we've not become wedged.
*/
-/*
- * Handle an EtherExpress interrupt
- * If we've finished initializing, start the RU and CU up.
- * If we've already started, reap tx buffers, handle any received packets,
- * check to make sure we've not become wedged.
- */
-
static unsigned short eexp_start_irq(struct net_device *dev,
unsigned short status)
{
diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h
index 272e1ec51aa..42295d61ecd 100644
--- a/drivers/net/ehea/ehea.h
+++ b/drivers/net/ehea/ehea.h
@@ -39,7 +39,7 @@
#include <asm/io.h>
#define DRV_NAME "ehea"
-#define DRV_VERSION "EHEA_0045"
+#define DRV_VERSION "EHEA_0046"
#define EHEA_MSG_DEFAULT (NETIF_MSG_LINK | NETIF_MSG_TIMER \
| NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR)
diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c
index 9de2d38a532..88ad1c8bcee 100644
--- a/drivers/net/ehea/ehea_main.c
+++ b/drivers/net/ehea/ehea_main.c
@@ -76,7 +76,7 @@ void ehea_dump(void *adr, int len, char *msg) {
int x;
unsigned char *deb = adr;
for (x = 0; x < len; x += 16) {
- printk(DRV_NAME "%s adr=%p ofs=%04x %016lx %016lx\n", msg,
+ printk(DRV_NAME " %s adr=%p ofs=%04x %016lx %016lx\n", msg,
deb, x, *((u64*)&deb[0]), *((u64*)&deb[8]));
deb += 16;
}
@@ -555,6 +555,7 @@ static irqreturn_t ehea_qp_aff_irq_handler(int irq, void *param)
{
struct ehea_port *port = param;
struct ehea_eqe *eqe;
+ struct ehea_qp *qp;
u32 qp_token;
eqe = ehea_poll_eq(port->qp_eq);
@@ -563,9 +564,14 @@ static irqreturn_t ehea_qp_aff_irq_handler(int irq, void *param)
qp_token = EHEA_BMASK_GET(EHEA_EQE_QP_TOKEN, eqe->entry);
ehea_error("QP aff_err: entry=0x%lx, token=0x%x",
eqe->entry, qp_token);
+
+ qp = port->port_res[qp_token].qp;
+ ehea_error_data(port->adapter, qp->fw_handle);
eqe = ehea_poll_eq(port->qp_eq);
}
+ queue_work(port->adapter->ehea_wq, &port->reset_task);
+
return IRQ_HANDLED;
}
@@ -882,7 +888,7 @@ static int ehea_reg_interrupts(struct net_device *dev)
, "%s-recv%d", dev->name, i);
ret = ibmebus_request_irq(NULL, pr->recv_eq->attr.ist1,
ehea_recv_irq_handler,
- SA_INTERRUPT, pr->int_recv_name, pr);
+ IRQF_DISABLED, pr->int_recv_name, pr);
if (ret) {
ehea_error("failed registering irq for ehea_recv_int:"
"port_res_nr:%d, ist=%X", i,
@@ -899,7 +905,7 @@ static int ehea_reg_interrupts(struct net_device *dev)
ret = ibmebus_request_irq(NULL, port->qp_eq->attr.ist1,
ehea_qp_aff_irq_handler,
- SA_INTERRUPT, port->int_aff_name, port);
+ IRQF_DISABLED, port->int_aff_name, port);
if (ret) {
ehea_error("failed registering irq for qp_aff_irq_handler:"
"ist=%X", port->qp_eq->attr.ist1);
@@ -916,7 +922,7 @@ static int ehea_reg_interrupts(struct net_device *dev)
"%s-send%d", dev->name, i);
ret = ibmebus_request_irq(NULL, pr->send_eq->attr.ist1,
ehea_send_irq_handler,
- SA_INTERRUPT, pr->int_send_name,
+ IRQF_DISABLED, pr->int_send_name,
pr);
if (ret) {
ehea_error("failed registering irq for ehea_send "
@@ -2539,7 +2545,7 @@ static int __devinit ehea_probe(struct ibmebus_dev *dev,
(unsigned long)adapter);
ret = ibmebus_request_irq(NULL, adapter->neq->attr.ist1,
- ehea_interrupt_neq, SA_INTERRUPT,
+ ehea_interrupt_neq, IRQF_DISABLED,
"ehea_neq", adapter);
if (ret) {
dev_err(&dev->ofdev.dev, "requesting NEQ IRQ failed");
diff --git a/drivers/net/ehea/ehea_phyp.c b/drivers/net/ehea/ehea_phyp.c
index 37716e05e80..bc3c0054726 100644
--- a/drivers/net/ehea/ehea_phyp.c
+++ b/drivers/net/ehea/ehea_phyp.c
@@ -612,3 +612,13 @@ u64 ehea_h_reset_events(const u64 adapter_handle, const u64 neq_handle,
event_mask, /* R6 */
0, 0, 0, 0); /* R7-R12 */
}
+
+u64 ehea_h_error_data(const u64 adapter_handle, const u64 ressource_handle,
+ void *rblock)
+{
+ return ehea_plpar_hcall_norets(H_ERROR_DATA,
+ adapter_handle, /* R4 */
+ ressource_handle, /* R5 */
+ virt_to_abs(rblock), /* R6 */
+ 0, 0, 0, 0); /* R7-R12 */
+}
diff --git a/drivers/net/ehea/ehea_phyp.h b/drivers/net/ehea/ehea_phyp.h
index 919f94b7593..90acddb068a 100644
--- a/drivers/net/ehea/ehea_phyp.h
+++ b/drivers/net/ehea/ehea_phyp.h
@@ -454,4 +454,7 @@ u64 ehea_h_reg_dereg_bcmc(const u64 adapter_handle, const u16 port_num,
u64 ehea_h_reset_events(const u64 adapter_handle, const u64 neq_handle,
const u64 event_mask);
+u64 ehea_h_error_data(const u64 adapter_handle, const u64 ressource_handle,
+ void *rblock);
+
#endif /* __EHEA_PHYP_H__ */
diff --git a/drivers/net/ehea/ehea_qmr.c b/drivers/net/ehea/ehea_qmr.c
index f143e13b229..96ff3b67999 100644
--- a/drivers/net/ehea/ehea_qmr.c
+++ b/drivers/net/ehea/ehea_qmr.c
@@ -486,6 +486,7 @@ int ehea_destroy_qp(struct ehea_qp *qp)
if (!qp)
return 0;
+ ehea_h_disable_and_get_hea(qp->adapter->handle, qp->fw_handle);
hret = ehea_h_free_resource(qp->adapter->handle, qp->fw_handle);
if (hret != H_SUCCESS) {
ehea_error("destroy_qp failed");
@@ -581,4 +582,45 @@ out:
return ret;
}
+void print_error_data(u64 *data)
+{
+ int length;
+ u64 type = EHEA_BMASK_GET(ERROR_DATA_TYPE, data[2]);
+ u64 resource = data[1];
+
+ length = EHEA_BMASK_GET(ERROR_DATA_LENGTH, data[0]);
+
+ if (length > EHEA_PAGESIZE)
+ length = EHEA_PAGESIZE;
+
+ if (type == 0x8) /* Queue Pair */
+ ehea_error("QP (resource=%lX) state: AER=0x%lX, AERR=0x%lX, "
+ "port=%lX", resource, data[6], data[12], data[22]);
+
+ ehea_dump(data, length, "error data");
+}
+
+void ehea_error_data(struct ehea_adapter *adapter, u64 res_handle)
+{
+ unsigned long ret;
+ u64 *rblock;
+
+ rblock = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!rblock) {
+ ehea_error("Cannot allocate rblock memory.");
+ return;
+ }
+ ret = ehea_h_error_data(adapter->handle,
+ res_handle,
+ rblock);
+
+ if (ret == H_R_STATE)
+ ehea_error("No error data is available: %lX.", res_handle);
+ else if (ret == H_SUCCESS)
+ print_error_data(rblock);
+ else
+ ehea_error("Error data could not be fetched: %lX", res_handle);
+
+ kfree(rblock);
+}
diff --git a/drivers/net/ehea/ehea_qmr.h b/drivers/net/ehea/ehea_qmr.h
index 7efdc96919c..1ff60983504 100644
--- a/drivers/net/ehea/ehea_qmr.h
+++ b/drivers/net/ehea/ehea_qmr.h
@@ -180,6 +180,9 @@ struct ehea_eqe {
u64 entry;
};
+#define ERROR_DATA_LENGTH EHEA_BMASK_IBM(52,63)
+#define ERROR_DATA_TYPE EHEA_BMASK_IBM(0,7)
+
static inline void *hw_qeit_calc(struct hw_queue *queue, u64 q_offset)
{
struct ehea_page *current_page;
@@ -355,4 +358,6 @@ int ehea_destroy_qp(struct ehea_qp *qp);
int ehea_reg_mr_adapter(struct ehea_adapter *adapter);
+void ehea_error_data(struct ehea_adapter *adapter, u64 res_handle);
+
#endif /* __EHEA_QMR_H__ */
diff --git a/drivers/net/es3210.c b/drivers/net/es3210.c
index 2d2ea94a00b..822e5bfd1a7 100644
--- a/drivers/net/es3210.c
+++ b/drivers/net/es3210.c
@@ -375,7 +375,7 @@ static void es_block_input(struct net_device *dev, int count, struct sk_buff *sk
memcpy_fromio(skb->data + semi_count, ei_status.mem, count);
} else {
/* Packet is in one chunk. */
- eth_io_copy_and_sum(skb, xfer_start, count, 0);
+ memcpy_fromio(skb->data, xfer_start, count);
}
}
diff --git a/drivers/net/fec_8xx/fec_8xx-netta.c b/drivers/net/fec_8xx/fec_8xx-netta.c
index 790d9dbe42d..e492eb84f94 100644
--- a/drivers/net/fec_8xx/fec_8xx-netta.c
+++ b/drivers/net/fec_8xx/fec_8xx-netta.c
@@ -4,7 +4,6 @@
#include <linux/kernel.h>
#include <linux/types.h>
-#include <linux/sched.h>
#include <linux/string.h>
#include <linux/ptrace.h>
#include <linux/errno.h>
diff --git a/drivers/net/fec_8xx/fec_main.c b/drivers/net/fec_8xx/fec_main.c
index 8e7a56fadfd..77f747a5afa 100644
--- a/drivers/net/fec_8xx/fec_main.c
+++ b/drivers/net/fec_8xx/fec_main.c
@@ -13,7 +13,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
-#include <linux/sched.h>
#include <linux/string.h>
#include <linux/ptrace.h>
#include <linux/errno.h>
diff --git a/drivers/net/fec_8xx/fec_mii.c b/drivers/net/fec_8xx/fec_mii.c
index d3c16b85d9a..e79700abf7b 100644
--- a/drivers/net/fec_8xx/fec_mii.c
+++ b/drivers/net/fec_8xx/fec_mii.c
@@ -13,7 +13,6 @@
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/string.h>
#include <linux/ptrace.h>
#include <linux/errno.h>
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index 93f2b7a2216..a363148d019 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -111,6 +111,7 @@
* 0.57: 14 May 2006: Mac address set in probe/remove and order corrections.
* 0.58: 30 Oct 2006: Added support for sideband management unit.
* 0.59: 30 Oct 2006: Added support for recoverable error.
+ * 0.60: 20 Jan 2007: Code optimizations for rings, rx & tx data paths, and stats.
*
* Known bugs:
* We suspect that on some hardware no TX done interrupts are generated.
@@ -127,7 +128,7 @@
#else
#define DRIVERNAPI
#endif
-#define FORCEDETH_VERSION "0.59"
+#define FORCEDETH_VERSION "0.60"
#define DRV_NAME "forcedeth"
#include <linux/module.h>
@@ -173,9 +174,10 @@
#define DEV_HAS_MSI_X 0x0080 /* device supports MSI-X */
#define DEV_HAS_POWER_CNTRL 0x0100 /* device supports power savings */
#define DEV_HAS_PAUSEFRAME_TX 0x0200 /* device supports tx pause frames */
-#define DEV_HAS_STATISTICS 0x0400 /* device supports hw statistics */
-#define DEV_HAS_TEST_EXTENDED 0x0800 /* device supports extended diagnostic test */
-#define DEV_HAS_MGMT_UNIT 0x1000 /* device supports management unit */
+#define DEV_HAS_STATISTICS_V1 0x0400 /* device supports hw statistics version 1 */
+#define DEV_HAS_STATISTICS_V2 0x0800 /* device supports hw statistics version 2 */
+#define DEV_HAS_TEST_EXTENDED 0x1000 /* device supports extended diagnostic test */
+#define DEV_HAS_MGMT_UNIT 0x2000 /* device supports management unit */
enum {
NvRegIrqStatus = 0x000,
@@ -210,7 +212,7 @@ enum {
* NVREG_POLL_DEFAULT=97 would result in an interval length of 1 ms
*/
NvRegPollingInterval = 0x00c,
-#define NVREG_POLL_DEFAULT_THROUGHPUT 970
+#define NVREG_POLL_DEFAULT_THROUGHPUT 970 /* backup tx cleanup if loop max reached */
#define NVREG_POLL_DEFAULT_CPU 13
NvRegMSIMap0 = 0x020,
NvRegMSIMap1 = 0x024,
@@ -304,8 +306,8 @@ enum {
#define NVREG_TXRXCTL_RESET 0x0010
#define NVREG_TXRXCTL_RXCHECK 0x0400
#define NVREG_TXRXCTL_DESC_1 0
-#define NVREG_TXRXCTL_DESC_2 0x02100
-#define NVREG_TXRXCTL_DESC_3 0x02200
+#define NVREG_TXRXCTL_DESC_2 0x002100
+#define NVREG_TXRXCTL_DESC_3 0xc02200
#define NVREG_TXRXCTL_VLANSTRIP 0x00040
#define NVREG_TXRXCTL_VLANINS 0x00080
NvRegTxRingPhysAddrHigh = 0x148,
@@ -487,7 +489,8 @@ union ring_type {
/* Miscelaneous hardware related defines: */
#define NV_PCI_REGSZ_VER1 0x270
-#define NV_PCI_REGSZ_VER2 0x604
+#define NV_PCI_REGSZ_VER2 0x2d4
+#define NV_PCI_REGSZ_VER3 0x604
/* various timeout delays: all in usec */
#define NV_TXRX_RESET_DELAY 4
@@ -518,12 +521,6 @@ union ring_type {
#define TX_RING_MIN 64
#define RING_MAX_DESC_VER_1 1024
#define RING_MAX_DESC_VER_2_3 16384
-/*
- * Difference between the get and put pointers for the tx ring.
- * This is used to throttle the amount of data outstanding in the
- * tx ring.
- */
-#define TX_LIMIT_DIFFERENCE 1
/* rx/tx mac addr + type + vlan + align + slack*/
#define NV_RX_HEADERS (64)
@@ -611,9 +608,6 @@ static const struct nv_ethtool_str nv_estats_str[] = {
{ "tx_carrier_errors" },
{ "tx_excess_deferral" },
{ "tx_retry_error" },
- { "tx_deferral" },
- { "tx_packets" },
- { "tx_pause" },
{ "rx_frame_error" },
{ "rx_extra_byte" },
{ "rx_late_collision" },
@@ -626,11 +620,17 @@ static const struct nv_ethtool_str nv_estats_str[] = {
{ "rx_unicast" },
{ "rx_multicast" },
{ "rx_broadcast" },
+ { "rx_packets" },
+ { "rx_errors_total" },
+ { "tx_errors_total" },
+
+ /* version 2 stats */
+ { "tx_deferral" },
+ { "tx_packets" },
{ "rx_bytes" },
+ { "tx_pause" },
{ "rx_pause" },
- { "rx_drop_frame" },
- { "rx_packets" },
- { "rx_errors_total" }
+ { "rx_drop_frame" }
};
struct nv_ethtool_stats {
@@ -643,9 +643,6 @@ struct nv_ethtool_stats {
u64 tx_carrier_errors;
u64 tx_excess_deferral;
u64 tx_retry_error;
- u64 tx_deferral;
- u64 tx_packets;
- u64 tx_pause;
u64 rx_frame_error;
u64 rx_extra_byte;
u64 rx_late_collision;
@@ -658,13 +655,22 @@ struct nv_ethtool_stats {
u64 rx_unicast;
u64 rx_multicast;
u64 rx_broadcast;
+ u64 rx_packets;
+ u64 rx_errors_total;
+ u64 tx_errors_total;
+
+ /* version 2 stats */
+ u64 tx_deferral;
+ u64 tx_packets;
u64 rx_bytes;
+ u64 tx_pause;
u64 rx_pause;
u64 rx_drop_frame;
- u64 rx_packets;
- u64 rx_errors_total;
};
+#define NV_DEV_STATISTICS_V2_COUNT (sizeof(struct nv_ethtool_stats)/sizeof(u64))
+#define NV_DEV_STATISTICS_V1_COUNT (NV_DEV_STATISTICS_V2_COUNT - 6)
+
/* diagnostics */
#define NV_TEST_COUNT_BASE 3
#define NV_TEST_COUNT_EXTENDED 4
@@ -691,6 +697,12 @@ static const struct register_test nv_registers_test[] = {
{ 0,0 }
};
+struct nv_skb_map {
+ struct sk_buff *skb;
+ dma_addr_t dma;
+ unsigned int dma_len;
+};
+
/*
* SMP locking:
* All hardware access under dev->priv->lock, except the performance
@@ -741,10 +753,12 @@ struct fe_priv {
/* rx specific fields.
* Locking: Within irq hander or disable_irq+spin_lock(&np->lock);
*/
+ union ring_type get_rx, put_rx, first_rx, last_rx;
+ struct nv_skb_map *get_rx_ctx, *put_rx_ctx;
+ struct nv_skb_map *first_rx_ctx, *last_rx_ctx;
+ struct nv_skb_map *rx_skb;
+
union ring_type rx_ring;
- unsigned int cur_rx, refill_rx;
- struct sk_buff **rx_skbuff;
- dma_addr_t *rx_dma;
unsigned int rx_buf_sz;
unsigned int pkt_limit;
struct timer_list oom_kick;
@@ -761,15 +775,15 @@ struct fe_priv {
/*
* tx specific fields.
*/
+ union ring_type get_tx, put_tx, first_tx, last_tx;
+ struct nv_skb_map *get_tx_ctx, *put_tx_ctx;
+ struct nv_skb_map *first_tx_ctx, *last_tx_ctx;
+ struct nv_skb_map *tx_skb;
+
union ring_type tx_ring;
- unsigned int next_tx, nic_tx;
- struct sk_buff **tx_skbuff;
- dma_addr_t *tx_dma;
- unsigned int *tx_dma_len;
u32 tx_flags;
int tx_ring_size;
- int tx_limit_start;
- int tx_limit_stop;
+ int tx_stop;
/* vlan fields */
struct vlan_group *vlangrp;
@@ -921,16 +935,10 @@ static void free_rings(struct net_device *dev)
pci_free_consistent(np->pci_dev, sizeof(struct ring_desc_ex) * (np->rx_ring_size + np->tx_ring_size),
np->rx_ring.ex, np->ring_addr);
}
- if (np->rx_skbuff)
- kfree(np->rx_skbuff);
- if (np->rx_dma)
- kfree(np->rx_dma);
- if (np->tx_skbuff)
- kfree(np->tx_skbuff);
- if (np->tx_dma)
- kfree(np->tx_dma);
- if (np->tx_dma_len)
- kfree(np->tx_dma_len);
+ if (np->rx_skb)
+ kfree(np->rx_skb);
+ if (np->tx_skb)
+ kfree(np->tx_skb);
}
static int using_multi_irqs(struct net_device *dev)
@@ -1279,6 +1287,61 @@ static void nv_mac_reset(struct net_device *dev)
pci_push(base);
}
+static void nv_get_hw_stats(struct net_device *dev)
+{
+ struct fe_priv *np = netdev_priv(dev);
+ u8 __iomem *base = get_hwbase(dev);
+
+ np->estats.tx_bytes += readl(base + NvRegTxCnt);
+ np->estats.tx_zero_rexmt += readl(base + NvRegTxZeroReXmt);
+ np->estats.tx_one_rexmt += readl(base + NvRegTxOneReXmt);
+ np->estats.tx_many_rexmt += readl(base + NvRegTxManyReXmt);
+ np->estats.tx_late_collision += readl(base + NvRegTxLateCol);
+ np->estats.tx_fifo_errors += readl(base + NvRegTxUnderflow);
+ np->estats.tx_carrier_errors += readl(base + NvRegTxLossCarrier);
+ np->estats.tx_excess_deferral += readl(base + NvRegTxExcessDef);
+ np->estats.tx_retry_error += readl(base + NvRegTxRetryErr);
+ np->estats.rx_frame_error += readl(base + NvRegRxFrameErr);
+ np->estats.rx_extra_byte += readl(base + NvRegRxExtraByte);
+ np->estats.rx_late_collision += readl(base + NvRegRxLateCol);
+ np->estats.rx_runt += readl(base + NvRegRxRunt);
+ np->estats.rx_frame_too_long += readl(base + NvRegRxFrameTooLong);
+ np->estats.rx_over_errors += readl(base + NvRegRxOverflow);
+ np->estats.rx_crc_errors += readl(base + NvRegRxFCSErr);
+ np->estats.rx_frame_align_error += readl(base + NvRegRxFrameAlignErr);
+ np->estats.rx_length_error += readl(base + NvRegRxLenErr);
+ np->estats.rx_unicast += readl(base + NvRegRxUnicast);
+ np->estats.rx_multicast += readl(base + NvRegRxMulticast);
+ np->estats.rx_broadcast += readl(base + NvRegRxBroadcast);
+ np->estats.rx_packets =
+ np->estats.rx_unicast +
+ np->estats.rx_multicast +
+ np->estats.rx_broadcast;
+ np->estats.rx_errors_total =
+ np->estats.rx_crc_errors +
+ np->estats.rx_over_errors +
+ np->estats.rx_frame_error +
+ (np->estats.rx_frame_align_error - np->estats.rx_extra_byte) +
+ np->estats.rx_late_collision +
+ np->estats.rx_runt +
+ np->estats.rx_frame_too_long;
+ np->estats.tx_errors_total =
+ np->estats.tx_late_collision +
+ np->estats.tx_fifo_errors +
+ np->estats.tx_carrier_errors +
+ np->estats.tx_excess_deferral +
+ np->estats.tx_retry_error;
+
+ if (np->driver_data & DEV_HAS_STATISTICS_V2) {
+ np->estats.tx_deferral += readl(base + NvRegTxDef);
+ np->estats.tx_packets += readl(base + NvRegTxFrame);
+ np->estats.rx_bytes += readl(base + NvRegRxCnt);
+ np->estats.tx_pause += readl(base + NvRegTxPause);
+ np->estats.rx_pause += readl(base + NvRegRxPause);
+ np->estats.rx_drop_frame += readl(base + NvRegRxDropFrame);
+ }
+}
+
/*
* nv_get_stats: dev->get_stats function
* Get latest stats value from the nic.
@@ -1289,10 +1352,19 @@ static struct net_device_stats *nv_get_stats(struct net_device *dev)
{
struct fe_priv *np = netdev_priv(dev);
- /* It seems that the nic always generates interrupts and doesn't
- * accumulate errors internally. Thus the current values in np->stats
- * are already up to date.
- */
+ /* If the nic supports hw counters then retrieve latest values */
+ if (np->driver_data & (DEV_HAS_STATISTICS_V1|DEV_HAS_STATISTICS_V2)) {
+ nv_get_hw_stats(dev);
+
+ /* copy to net_device stats */
+ np->stats.tx_bytes = np->estats.tx_bytes;
+ np->stats.tx_fifo_errors = np->estats.tx_fifo_errors;
+ np->stats.tx_carrier_errors = np->estats.tx_carrier_errors;
+ np->stats.rx_crc_errors = np->estats.rx_crc_errors;
+ np->stats.rx_over_errors = np->estats.rx_over_errors;
+ np->stats.rx_errors = np->estats.rx_errors_total;
+ np->stats.tx_errors = np->estats.tx_errors_total;
+ }
return &np->stats;
}
@@ -1304,43 +1376,63 @@ static struct net_device_stats *nv_get_stats(struct net_device *dev)
static int nv_alloc_rx(struct net_device *dev)
{
struct fe_priv *np = netdev_priv(dev);
- unsigned int refill_rx = np->refill_rx;
- int nr;
+ struct ring_desc* less_rx;
- while (np->cur_rx != refill_rx) {
- struct sk_buff *skb;
-
- nr = refill_rx % np->rx_ring_size;
- if (np->rx_skbuff[nr] == NULL) {
-
- skb = dev_alloc_skb(np->rx_buf_sz + NV_RX_ALLOC_PAD);
- if (!skb)
- break;
+ less_rx = np->get_rx.orig;
+ if (less_rx-- == np->first_rx.orig)
+ less_rx = np->last_rx.orig;
+ while (np->put_rx.orig != less_rx) {
+ struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz + NV_RX_ALLOC_PAD);
+ if (skb) {
skb->dev = dev;
- np->rx_skbuff[nr] = skb;
+ np->put_rx_ctx->skb = skb;
+ np->put_rx_ctx->dma = pci_map_single(np->pci_dev, skb->data,
+ skb->end-skb->data, PCI_DMA_FROMDEVICE);
+ np->put_rx_ctx->dma_len = skb->end-skb->data;
+ np->put_rx.orig->buf = cpu_to_le32(np->put_rx_ctx->dma);
+ wmb();
+ np->put_rx.orig->flaglen = cpu_to_le32(np->rx_buf_sz | NV_RX_AVAIL);
+ if (unlikely(np->put_rx.orig++ == np->last_rx.orig))
+ np->put_rx.orig = np->first_rx.orig;
+ if (unlikely(np->put_rx_ctx++ == np->last_rx_ctx))
+ np->put_rx_ctx = np->first_rx_ctx;
} else {
- skb = np->rx_skbuff[nr];
+ return 1;
}
- np->rx_dma[nr] = pci_map_single(np->pci_dev, skb->data,
- skb->end-skb->data, PCI_DMA_FROMDEVICE);
- if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
- np->rx_ring.orig[nr].buf = cpu_to_le32(np->rx_dma[nr]);
+ }
+ return 0;
+}
+
+static int nv_alloc_rx_optimized(struct net_device *dev)
+{
+ struct fe_priv *np = netdev_priv(dev);
+ struct ring_desc_ex* less_rx;
+
+ less_rx = np->get_rx.ex;
+ if (less_rx-- == np->first_rx.ex)
+ less_rx = np->last_rx.ex;
+
+ while (np->put_rx.ex != less_rx) {
+ struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz + NV_RX_ALLOC_PAD);
+ if (skb) {
+ skb->dev = dev;
+ np->put_rx_ctx->skb = skb;
+ np->put_rx_ctx->dma = pci_map_single(np->pci_dev, skb->data,
+ skb->end-skb->data, PCI_DMA_FROMDEVICE);
+ np->put_rx_ctx->dma_len = skb->end-skb->data;
+ np->put_rx.ex->bufhigh = cpu_to_le64(np->put_rx_ctx->dma) >> 32;
+ np->put_rx.ex->buflow = cpu_to_le64(np->put_rx_ctx->dma) & 0x0FFFFFFFF;
wmb();
- np->rx_ring.orig[nr].flaglen = cpu_to_le32(np->rx_buf_sz | NV_RX_AVAIL);
+ np->put_rx.ex->flaglen = cpu_to_le32(np->rx_buf_sz | NV_RX2_AVAIL);
+ if (unlikely(np->put_rx.ex++ == np->last_rx.ex))
+ np->put_rx.ex = np->first_rx.ex;
+ if (unlikely(np->put_rx_ctx++ == np->last_rx_ctx))
+ np->put_rx_ctx = np->first_rx_ctx;
} else {
- np->rx_ring.ex[nr].bufhigh = cpu_to_le64(np->rx_dma[nr]) >> 32;
- np->rx_ring.ex[nr].buflow = cpu_to_le64(np->rx_dma[nr]) & 0x0FFFFFFFF;
- wmb();
- np->rx_ring.ex[nr].flaglen = cpu_to_le32(np->rx_buf_sz | NV_RX2_AVAIL);
+ return 1;
}
- dprintk(KERN_DEBUG "%s: nv_alloc_rx: Packet %d marked as Available\n",
- dev->name, refill_rx);
- refill_rx++;
}
- np->refill_rx = refill_rx;
- if (np->cur_rx - refill_rx == np->rx_ring_size)
- return 1;
return 0;
}
@@ -1358,6 +1450,7 @@ static void nv_do_rx_refill(unsigned long data)
{
struct net_device *dev = (struct net_device *) data;
struct fe_priv *np = netdev_priv(dev);
+ int retcode;
if (!using_multi_irqs(dev)) {
if (np->msi_flags & NV_MSI_X_ENABLED)
@@ -1367,7 +1460,11 @@ static void nv_do_rx_refill(unsigned long data)
} else {
disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector);
}
- if (nv_alloc_rx(dev)) {
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+ retcode = nv_alloc_rx(dev);
+ else
+ retcode = nv_alloc_rx_optimized(dev);
+ if (retcode) {
spin_lock_irq(&np->lock);
if (!np->in_shutdown)
mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
@@ -1388,56 +1485,81 @@ static void nv_init_rx(struct net_device *dev)
{
struct fe_priv *np = netdev_priv(dev);
int i;
+ np->get_rx = np->put_rx = np->first_rx = np->rx_ring;
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+ np->last_rx.orig = &np->rx_ring.orig[np->rx_ring_size-1];
+ else
+ np->last_rx.ex = &np->rx_ring.ex[np->rx_ring_size-1];
+ np->get_rx_ctx = np->put_rx_ctx = np->first_rx_ctx = np->rx_skb;
+ np->last_rx_ctx = &np->rx_skb[np->rx_ring_size-1];
- np->cur_rx = np->rx_ring_size;
- np->refill_rx = 0;
- for (i = 0; i < np->rx_ring_size; i++)
- if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+ for (i = 0; i < np->rx_ring_size; i++) {
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
np->rx_ring.orig[i].flaglen = 0;
- else
+ np->rx_ring.orig[i].buf = 0;
+ } else {
np->rx_ring.ex[i].flaglen = 0;
+ np->rx_ring.ex[i].txvlan = 0;
+ np->rx_ring.ex[i].bufhigh = 0;
+ np->rx_ring.ex[i].buflow = 0;
+ }
+ np->rx_skb[i].skb = NULL;
+ np->rx_skb[i].dma = 0;
+ }
}
static void nv_init_tx(struct net_device *dev)
{
struct fe_priv *np = netdev_priv(dev);
int i;
+ np->get_tx = np->put_tx = np->first_tx = np->tx_ring;
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+ np->last_tx.orig = &np->tx_ring.orig[np->tx_ring_size-1];
+ else
+ np->last_tx.ex = &np->tx_ring.ex[np->tx_ring_size-1];
+ np->get_tx_ctx = np->put_tx_ctx = np->first_tx_ctx = np->tx_skb;
+ np->last_tx_ctx = &np->tx_skb[np->tx_ring_size-1];
- np->next_tx = np->nic_tx = 0;
for (i = 0; i < np->tx_ring_size; i++) {
- if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
np->tx_ring.orig[i].flaglen = 0;
- else
+ np->tx_ring.orig[i].buf = 0;
+ } else {
np->tx_ring.ex[i].flaglen = 0;
- np->tx_skbuff[i] = NULL;
- np->tx_dma[i] = 0;
+ np->tx_ring.ex[i].txvlan = 0;
+ np->tx_ring.ex[i].bufhigh = 0;
+ np->tx_ring.ex[i].buflow = 0;
+ }
+ np->tx_skb[i].skb = NULL;
+ np->tx_skb[i].dma = 0;
}
}
static int nv_init_ring(struct net_device *dev)
{
+ struct fe_priv *np = netdev_priv(dev);
+
nv_init_tx(dev);
nv_init_rx(dev);
- return nv_alloc_rx(dev);
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+ return nv_alloc_rx(dev);
+ else
+ return nv_alloc_rx_optimized(dev);
}
-static int nv_release_txskb(struct net_device *dev, unsigned int skbnr)
+static int nv_release_txskb(struct net_device *dev, struct nv_skb_map* tx_skb)
{
struct fe_priv *np = netdev_priv(dev);
- dprintk(KERN_INFO "%s: nv_release_txskb for skbnr %d\n",
- dev->name, skbnr);
-
- if (np->tx_dma[skbnr]) {
- pci_unmap_page(np->pci_dev, np->tx_dma[skbnr],
- np->tx_dma_len[skbnr],
+ if (tx_skb->dma) {
+ pci_unmap_page(np->pci_dev, tx_skb->dma,
+ tx_skb->dma_len,
PCI_DMA_TODEVICE);
- np->tx_dma[skbnr] = 0;
+ tx_skb->dma = 0;
}
-
- if (np->tx_skbuff[skbnr]) {
- dev_kfree_skb_any(np->tx_skbuff[skbnr]);
- np->tx_skbuff[skbnr] = NULL;
+ if (tx_skb->skb) {
+ dev_kfree_skb_any(tx_skb->skb);
+ tx_skb->skb = NULL;
return 1;
} else {
return 0;
@@ -1450,11 +1572,16 @@ static void nv_drain_tx(struct net_device *dev)
unsigned int i;
for (i = 0; i < np->tx_ring_size; i++) {
- if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
np->tx_ring.orig[i].flaglen = 0;
- else
+ np->tx_ring.orig[i].buf = 0;
+ } else {
np->tx_ring.ex[i].flaglen = 0;
- if (nv_release_txskb(dev, i))
+ np->tx_ring.ex[i].txvlan = 0;
+ np->tx_ring.ex[i].bufhigh = 0;
+ np->tx_ring.ex[i].buflow = 0;
+ }
+ if (nv_release_txskb(dev, &np->tx_skb[i]))
np->stats.tx_dropped++;
}
}
@@ -1463,18 +1590,24 @@ static void nv_drain_rx(struct net_device *dev)
{
struct fe_priv *np = netdev_priv(dev);
int i;
+
for (i = 0; i < np->rx_ring_size; i++) {
- if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
np->rx_ring.orig[i].flaglen = 0;
- else
+ np->rx_ring.orig[i].buf = 0;
+ } else {
np->rx_ring.ex[i].flaglen = 0;
+ np->rx_ring.ex[i].txvlan = 0;
+ np->rx_ring.ex[i].bufhigh = 0;
+ np->rx_ring.ex[i].buflow = 0;
+ }
wmb();
- if (np->rx_skbuff[i]) {
- pci_unmap_single(np->pci_dev, np->rx_dma[i],
- np->rx_skbuff[i]->end-np->rx_skbuff[i]->data,
+ if (np->rx_skb[i].skb) {
+ pci_unmap_single(np->pci_dev, np->rx_skb[i].dma,
+ np->rx_skb[i].skb->end-np->rx_skb[i].skb->data,
PCI_DMA_FROMDEVICE);
- dev_kfree_skb(np->rx_skbuff[i]);
- np->rx_skbuff[i] = NULL;
+ dev_kfree_skb(np->rx_skb[i].skb);
+ np->rx_skb[i].skb = NULL;
}
}
}
@@ -1485,6 +1618,11 @@ static void drain_ring(struct net_device *dev)
nv_drain_rx(dev);
}
+static inline u32 nv_get_empty_tx_slots(struct fe_priv *np)
+{
+ return (u32)(np->tx_ring_size - ((np->tx_ring_size + (np->put_tx_ctx - np->get_tx_ctx)) % np->tx_ring_size));
+}
+
/*
* nv_start_xmit: dev->hard_start_xmit function
* Called with netif_tx_lock held.
@@ -1495,14 +1633,16 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
u32 tx_flags = 0;
u32 tx_flags_extra = (np->desc_ver == DESC_VER_1 ? NV_TX_LASTPACKET : NV_TX2_LASTPACKET);
unsigned int fragments = skb_shinfo(skb)->nr_frags;
- unsigned int nr = (np->next_tx - 1) % np->tx_ring_size;
- unsigned int start_nr = np->next_tx % np->tx_ring_size;
unsigned int i;
u32 offset = 0;
u32 bcnt;
u32 size = skb->len-skb->data_len;
u32 entries = (size >> NV_TX2_TSO_MAX_SHIFT) + ((size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0);
- u32 tx_flags_vlan = 0;
+ u32 empty_slots;
+ struct ring_desc* put_tx;
+ struct ring_desc* start_tx;
+ struct ring_desc* prev_tx;
+ struct nv_skb_map* prev_tx_ctx;
/* add fragments to entries count */
for (i = 0; i < fragments; i++) {
@@ -1510,34 +1650,35 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
((skb_shinfo(skb)->frags[i].size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0);
}
- spin_lock_irq(&np->lock);
-
- if ((np->next_tx - np->nic_tx + entries - 1) > np->tx_limit_stop) {
- spin_unlock_irq(&np->lock);
+ empty_slots = nv_get_empty_tx_slots(np);
+ if (unlikely(empty_slots <= entries)) {
+ spin_lock_irq(&np->lock);
netif_stop_queue(dev);
+ np->tx_stop = 1;
+ spin_unlock_irq(&np->lock);
return NETDEV_TX_BUSY;
}
+ start_tx = put_tx = np->put_tx.orig;
+
/* setup the header buffer */
do {
+ prev_tx = put_tx;
+ prev_tx_ctx = np->put_tx_ctx;
bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size;
- nr = (nr + 1) % np->tx_ring_size;
-
- np->tx_dma[nr] = pci_map_single(np->pci_dev, skb->data + offset, bcnt,
+ np->put_tx_ctx->dma = pci_map_single(np->pci_dev, skb->data + offset, bcnt,
PCI_DMA_TODEVICE);
- np->tx_dma_len[nr] = bcnt;
+ np->put_tx_ctx->dma_len = bcnt;
+ put_tx->buf = cpu_to_le32(np->put_tx_ctx->dma);
+ put_tx->flaglen = cpu_to_le32((bcnt-1) | tx_flags);
- if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
- np->tx_ring.orig[nr].buf = cpu_to_le32(np->tx_dma[nr]);
- np->tx_ring.orig[nr].flaglen = cpu_to_le32((bcnt-1) | tx_flags);
- } else {
- np->tx_ring.ex[nr].bufhigh = cpu_to_le64(np->tx_dma[nr]) >> 32;
- np->tx_ring.ex[nr].buflow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF;
- np->tx_ring.ex[nr].flaglen = cpu_to_le32((bcnt-1) | tx_flags);
- }
tx_flags = np->tx_flags;
offset += bcnt;
size -= bcnt;
+ if (unlikely(put_tx++ == np->last_tx.orig))
+ put_tx = np->first_tx.orig;
+ if (unlikely(np->put_tx_ctx++ == np->last_tx_ctx))
+ np->put_tx_ctx = np->first_tx_ctx;
} while (size);
/* setup the fragments */
@@ -1547,58 +1688,174 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
offset = 0;
do {
+ prev_tx = put_tx;
+ prev_tx_ctx = np->put_tx_ctx;
bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size;
- nr = (nr + 1) % np->tx_ring_size;
-
- np->tx_dma[nr] = pci_map_page(np->pci_dev, frag->page, frag->page_offset+offset, bcnt,
- PCI_DMA_TODEVICE);
- np->tx_dma_len[nr] = bcnt;
+ np->put_tx_ctx->dma = pci_map_page(np->pci_dev, frag->page, frag->page_offset+offset, bcnt,
+ PCI_DMA_TODEVICE);
+ np->put_tx_ctx->dma_len = bcnt;
+ put_tx->buf = cpu_to_le32(np->put_tx_ctx->dma);
+ put_tx->flaglen = cpu_to_le32((bcnt-1) | tx_flags);
- if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
- np->tx_ring.orig[nr].buf = cpu_to_le32(np->tx_dma[nr]);
- np->tx_ring.orig[nr].flaglen = cpu_to_le32((bcnt-1) | tx_flags);
- } else {
- np->tx_ring.ex[nr].bufhigh = cpu_to_le64(np->tx_dma[nr]) >> 32;
- np->tx_ring.ex[nr].buflow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF;
- np->tx_ring.ex[nr].flaglen = cpu_to_le32((bcnt-1) | tx_flags);
- }
offset += bcnt;
size -= bcnt;
+ if (unlikely(put_tx++ == np->last_tx.orig))
+ put_tx = np->first_tx.orig;
+ if (unlikely(np->put_tx_ctx++ == np->last_tx_ctx))
+ np->put_tx_ctx = np->first_tx_ctx;
} while (size);
}
/* set last fragment flag */
- if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
- np->tx_ring.orig[nr].flaglen |= cpu_to_le32(tx_flags_extra);
- } else {
- np->tx_ring.ex[nr].flaglen |= cpu_to_le32(tx_flags_extra);
+ prev_tx->flaglen |= cpu_to_le32(tx_flags_extra);
+
+ /* save skb in this slot's context area */
+ prev_tx_ctx->skb = skb;
+
+ if (skb_is_gso(skb))
+ tx_flags_extra = NV_TX2_TSO | (skb_shinfo(skb)->gso_size << NV_TX2_TSO_SHIFT);
+ else
+ tx_flags_extra = skb->ip_summed == CHECKSUM_PARTIAL ?
+ NV_TX2_CHECKSUM_L3 | NV_TX2_CHECKSUM_L4 : 0;
+
+ spin_lock_irq(&np->lock);
+
+ /* set tx flags */
+ start_tx->flaglen |= cpu_to_le32(tx_flags | tx_flags_extra);
+ np->put_tx.orig = put_tx;
+
+ spin_unlock_irq(&np->lock);
+
+ dprintk(KERN_DEBUG "%s: nv_start_xmit: entries %d queued for transmission. tx_flags_extra: %x\n",
+ dev->name, entries, tx_flags_extra);
+ {
+ int j;
+ for (j=0; j<64; j++) {
+ if ((j%16) == 0)
+ dprintk("\n%03x:", j);
+ dprintk(" %02x", ((unsigned char*)skb->data)[j]);
+ }
+ dprintk("\n");
+ }
+
+ dev->trans_start = jiffies;
+ writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl);
+ return NETDEV_TX_OK;
+}
+
+static int nv_start_xmit_optimized(struct sk_buff *skb, struct net_device *dev)
+{
+ struct fe_priv *np = netdev_priv(dev);
+ u32 tx_flags = 0;
+ u32 tx_flags_extra;
+ unsigned int fragments = skb_shinfo(skb)->nr_frags;
+ unsigned int i;
+ u32 offset = 0;
+ u32 bcnt;
+ u32 size = skb->len-skb->data_len;
+ u32 entries = (size >> NV_TX2_TSO_MAX_SHIFT) + ((size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0);
+ u32 empty_slots;
+ struct ring_desc_ex* put_tx;
+ struct ring_desc_ex* start_tx;
+ struct ring_desc_ex* prev_tx;
+ struct nv_skb_map* prev_tx_ctx;
+
+ /* add fragments to entries count */
+ for (i = 0; i < fragments; i++) {
+ entries += (skb_shinfo(skb)->frags[i].size >> NV_TX2_TSO_MAX_SHIFT) +
+ ((skb_shinfo(skb)->frags[i].size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0);
+ }
+
+ empty_slots = nv_get_empty_tx_slots(np);
+ if (unlikely(empty_slots <= entries)) {
+ spin_lock_irq(&np->lock);
+ netif_stop_queue(dev);
+ np->tx_stop = 1;
+ spin_unlock_irq(&np->lock);
+ return NETDEV_TX_BUSY;
+ }
+
+ start_tx = put_tx = np->put_tx.ex;
+
+ /* setup the header buffer */
+ do {
+ prev_tx = put_tx;
+ prev_tx_ctx = np->put_tx_ctx;
+ bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size;
+ np->put_tx_ctx->dma = pci_map_single(np->pci_dev, skb->data + offset, bcnt,
+ PCI_DMA_TODEVICE);
+ np->put_tx_ctx->dma_len = bcnt;
+ put_tx->bufhigh = cpu_to_le64(np->put_tx_ctx->dma) >> 32;
+ put_tx->buflow = cpu_to_le64(np->put_tx_ctx->dma) & 0x0FFFFFFFF;
+ put_tx->flaglen = cpu_to_le32((bcnt-1) | tx_flags);
+
+ tx_flags = NV_TX2_VALID;
+ offset += bcnt;
+ size -= bcnt;
+ if (unlikely(put_tx++ == np->last_tx.ex))
+ put_tx = np->first_tx.ex;
+ if (unlikely(np->put_tx_ctx++ == np->last_tx_ctx))
+ np->put_tx_ctx = np->first_tx_ctx;
+ } while (size);
+
+ /* setup the fragments */
+ for (i = 0; i < fragments; i++) {
+ skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+ u32 size = frag->size;
+ offset = 0;
+
+ do {
+ prev_tx = put_tx;
+ prev_tx_ctx = np->put_tx_ctx;
+ bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size;
+ np->put_tx_ctx->dma = pci_map_page(np->pci_dev, frag->page, frag->page_offset+offset, bcnt,
+ PCI_DMA_TODEVICE);
+ np->put_tx_ctx->dma_len = bcnt;
+ put_tx->bufhigh = cpu_to_le64(np->put_tx_ctx->dma) >> 32;
+ put_tx->buflow = cpu_to_le64(np->put_tx_ctx->dma) & 0x0FFFFFFFF;
+ put_tx->flaglen = cpu_to_le32((bcnt-1) | tx_flags);
+
+ offset += bcnt;
+ size -= bcnt;
+ if (unlikely(put_tx++ == np->last_tx.ex))
+ put_tx = np->first_tx.ex;
+ if (unlikely(np->put_tx_ctx++ == np->last_tx_ctx))
+ np->put_tx_ctx = np->first_tx_ctx;
+ } while (size);
}
- np->tx_skbuff[nr] = skb;
+ /* set last fragment flag */
+ prev_tx->flaglen |= cpu_to_le32(NV_TX2_LASTPACKET);
+
+ /* save skb in this slot's context area */
+ prev_tx_ctx->skb = skb;
-#ifdef NETIF_F_TSO
if (skb_is_gso(skb))
tx_flags_extra = NV_TX2_TSO | (skb_shinfo(skb)->gso_size << NV_TX2_TSO_SHIFT);
else
-#endif
- tx_flags_extra = skb->ip_summed == CHECKSUM_PARTIAL ?
+ tx_flags_extra = skb->ip_summed == CHECKSUM_PARTIAL ?
NV_TX2_CHECKSUM_L3 | NV_TX2_CHECKSUM_L4 : 0;
/* vlan tag */
- if (np->vlangrp && vlan_tx_tag_present(skb)) {
- tx_flags_vlan = NV_TX3_VLAN_TAG_PRESENT | vlan_tx_tag_get(skb);
+ if (likely(!np->vlangrp)) {
+ start_tx->txvlan = 0;
+ } else {
+ if (vlan_tx_tag_present(skb))
+ start_tx->txvlan = cpu_to_le32(NV_TX3_VLAN_TAG_PRESENT | vlan_tx_tag_get(skb));
+ else
+ start_tx->txvlan = 0;
}
+ spin_lock_irq(&np->lock);
+
/* set tx flags */
- if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
- np->tx_ring.orig[start_nr].flaglen |= cpu_to_le32(tx_flags | tx_flags_extra);
- } else {
- np->tx_ring.ex[start_nr].txvlan = cpu_to_le32(tx_flags_vlan);
- np->tx_ring.ex[start_nr].flaglen |= cpu_to_le32(tx_flags | tx_flags_extra);
- }
+ start_tx->flaglen |= cpu_to_le32(tx_flags | tx_flags_extra);
+ np->put_tx.ex = put_tx;
+
+ spin_unlock_irq(&np->lock);
- dprintk(KERN_DEBUG "%s: nv_start_xmit: packet %d (entries %d) queued for transmission. tx_flags_extra: %x\n",
- dev->name, np->next_tx, entries, tx_flags_extra);
+ dprintk(KERN_DEBUG "%s: nv_start_xmit_optimized: entries %d queued for transmission. tx_flags_extra: %x\n",
+ dev->name, entries, tx_flags_extra);
{
int j;
for (j=0; j<64; j++) {
@@ -1609,12 +1866,8 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
dprintk("\n");
}
- np->next_tx += entries;
-
dev->trans_start = jiffies;
- spin_unlock_irq(&np->lock);
writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl);
- pci_push(get_hwbase(dev));
return NETDEV_TX_OK;
}
@@ -1627,26 +1880,22 @@ static void nv_tx_done(struct net_device *dev)
{
struct fe_priv *np = netdev_priv(dev);
u32 flags;
- unsigned int i;
- struct sk_buff *skb;
+ struct ring_desc* orig_get_tx = np->get_tx.orig;
- while (np->nic_tx != np->next_tx) {
- i = np->nic_tx % np->tx_ring_size;
+ while ((np->get_tx.orig != np->put_tx.orig) &&
+ !((flags = le32_to_cpu(np->get_tx.orig->flaglen)) & NV_TX_VALID)) {
- if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
- flags = le32_to_cpu(np->tx_ring.orig[i].flaglen);
- else
- flags = le32_to_cpu(np->tx_ring.ex[i].flaglen);
+ dprintk(KERN_DEBUG "%s: nv_tx_done: flags 0x%x.\n",
+ dev->name, flags);
+
+ pci_unmap_page(np->pci_dev, np->get_tx_ctx->dma,
+ np->get_tx_ctx->dma_len,
+ PCI_DMA_TODEVICE);
+ np->get_tx_ctx->dma = 0;
- dprintk(KERN_DEBUG "%s: nv_tx_done: looking at packet %d, flags 0x%x.\n",
- dev->name, np->nic_tx, flags);
- if (flags & NV_TX_VALID)
- break;
if (np->desc_ver == DESC_VER_1) {
if (flags & NV_TX_LASTPACKET) {
- skb = np->tx_skbuff[i];
- if (flags & (NV_TX_RETRYERROR|NV_TX_CARRIERLOST|NV_TX_LATECOLLISION|
- NV_TX_UNDERFLOW|NV_TX_ERROR)) {
+ if (flags & NV_TX_ERROR) {
if (flags & NV_TX_UNDERFLOW)
np->stats.tx_fifo_errors++;
if (flags & NV_TX_CARRIERLOST)
@@ -1654,14 +1903,14 @@ static void nv_tx_done(struct net_device *dev)
np->stats.tx_errors++;
} else {
np->stats.tx_packets++;
- np->stats.tx_bytes += skb->len;
+ np->stats.tx_bytes += np->get_tx_ctx->skb->len;
}
+ dev_kfree_skb_any(np->get_tx_ctx->skb);
+ np->get_tx_ctx->skb = NULL;
}
} else {
if (flags & NV_TX2_LASTPACKET) {
- skb = np->tx_skbuff[i];
- if (flags & (NV_TX2_RETRYERROR|NV_TX2_CARRIERLOST|NV_TX2_LATECOLLISION|
- NV_TX2_UNDERFLOW|NV_TX2_ERROR)) {
+ if (flags & NV_TX2_ERROR) {
if (flags & NV_TX2_UNDERFLOW)
np->stats.tx_fifo_errors++;
if (flags & NV_TX2_CARRIERLOST)
@@ -1669,15 +1918,56 @@ static void nv_tx_done(struct net_device *dev)
np->stats.tx_errors++;
} else {
np->stats.tx_packets++;
- np->stats.tx_bytes += skb->len;
+ np->stats.tx_bytes += np->get_tx_ctx->skb->len;
}
+ dev_kfree_skb_any(np->get_tx_ctx->skb);
+ np->get_tx_ctx->skb = NULL;
}
}
- nv_release_txskb(dev, i);
- np->nic_tx++;
+ if (unlikely(np->get_tx.orig++ == np->last_tx.orig))
+ np->get_tx.orig = np->first_tx.orig;
+ if (unlikely(np->get_tx_ctx++ == np->last_tx_ctx))
+ np->get_tx_ctx = np->first_tx_ctx;
}
- if (np->next_tx - np->nic_tx < np->tx_limit_start)
+ if (unlikely((np->tx_stop == 1) && (np->get_tx.orig != orig_get_tx))) {
+ np->tx_stop = 0;
netif_wake_queue(dev);
+ }
+}
+
+static void nv_tx_done_optimized(struct net_device *dev, int limit)
+{
+ struct fe_priv *np = netdev_priv(dev);
+ u32 flags;
+ struct ring_desc_ex* orig_get_tx = np->get_tx.ex;
+
+ while ((np->get_tx.ex != np->put_tx.ex) &&
+ !((flags = le32_to_cpu(np->get_tx.ex->flaglen)) & NV_TX_VALID) &&
+ (limit-- > 0)) {
+
+ dprintk(KERN_DEBUG "%s: nv_tx_done_optimized: flags 0x%x.\n",
+ dev->name, flags);
+
+ pci_unmap_page(np->pci_dev, np->get_tx_ctx->dma,
+ np->get_tx_ctx->dma_len,
+ PCI_DMA_TODEVICE);
+ np->get_tx_ctx->dma = 0;
+
+ if (flags & NV_TX2_LASTPACKET) {
+ if (!(flags & NV_TX2_ERROR))
+ np->stats.tx_packets++;
+ dev_kfree_skb_any(np->get_tx_ctx->skb);
+ np->get_tx_ctx->skb = NULL;
+ }
+ if (unlikely(np->get_tx.ex++ == np->last_tx.ex))
+ np->get_tx.ex = np->first_tx.ex;
+ if (unlikely(np->get_tx_ctx++ == np->last_tx_ctx))
+ np->get_tx_ctx = np->first_tx_ctx;
+ }
+ if (unlikely((np->tx_stop == 1) && (np->get_tx.ex != orig_get_tx))) {
+ np->tx_stop = 0;
+ netif_wake_queue(dev);
+ }
}
/*
@@ -1700,9 +1990,8 @@ static void nv_tx_timeout(struct net_device *dev)
{
int i;
- printk(KERN_INFO "%s: Ring at %lx: next %d nic %d\n",
- dev->name, (unsigned long)np->ring_addr,
- np->next_tx, np->nic_tx);
+ printk(KERN_INFO "%s: Ring at %lx\n",
+ dev->name, (unsigned long)np->ring_addr);
printk(KERN_INFO "%s: Dumping tx registers\n", dev->name);
for (i=0;i<=np->register_size;i+= 32) {
printk(KERN_INFO "%3x: %08x %08x %08x %08x %08x %08x %08x %08x\n",
@@ -1750,13 +2039,16 @@ static void nv_tx_timeout(struct net_device *dev)
nv_stop_tx(dev);
/* 2) check that the packets were not sent already: */
- nv_tx_done(dev);
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+ nv_tx_done(dev);
+ else
+ nv_tx_done_optimized(dev, np->tx_ring_size);
/* 3) if there are dead entries: clear everything */
- if (np->next_tx != np->nic_tx) {
+ if (np->get_tx_ctx != np->put_tx_ctx) {
printk(KERN_DEBUG "%s: tx_timeout: dead entries!\n", dev->name);
nv_drain_tx(dev);
- np->next_tx = np->nic_tx = 0;
+ nv_init_tx(dev);
setup_hw_rings(dev, NV_SETUP_TX_RING);
netif_wake_queue(dev);
}
@@ -1823,40 +2115,27 @@ static int nv_rx_process(struct net_device *dev, int limit)
{
struct fe_priv *np = netdev_priv(dev);
u32 flags;
- u32 vlanflags = 0;
- int count;
-
- for (count = 0; count < limit; ++count) {
- struct sk_buff *skb;
- int len;
- int i;
- if (np->cur_rx - np->refill_rx >= np->rx_ring_size)
- break; /* we scanned the whole ring - do not continue */
-
- i = np->cur_rx % np->rx_ring_size;
- if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
- flags = le32_to_cpu(np->rx_ring.orig[i].flaglen);
- len = nv_descr_getlength(&np->rx_ring.orig[i], np->desc_ver);
- } else {
- flags = le32_to_cpu(np->rx_ring.ex[i].flaglen);
- len = nv_descr_getlength_ex(&np->rx_ring.ex[i], np->desc_ver);
- vlanflags = le32_to_cpu(np->rx_ring.ex[i].buflow);
- }
+ u32 rx_processed_cnt = 0;
+ struct sk_buff *skb;
+ int len;
- dprintk(KERN_DEBUG "%s: nv_rx_process: looking at packet %d, flags 0x%x.\n",
- dev->name, np->cur_rx, flags);
+ while((np->get_rx.orig != np->put_rx.orig) &&
+ !((flags = le32_to_cpu(np->get_rx.orig->flaglen)) & NV_RX_AVAIL) &&
+ (rx_processed_cnt++ < limit)) {
- if (flags & NV_RX_AVAIL)
- break; /* still owned by hardware, */
+ dprintk(KERN_DEBUG "%s: nv_rx_process: flags 0x%x.\n",
+ dev->name, flags);
/*
* the packet is for us - immediately tear down the pci mapping.
* TODO: check if a prefetch of the first cacheline improves
* the performance.
*/
- pci_unmap_single(np->pci_dev, np->rx_dma[i],
- np->rx_skbuff[i]->end-np->rx_skbuff[i]->data,
+ pci_unmap_single(np->pci_dev, np->get_rx_ctx->dma,
+ np->get_rx_ctx->dma_len,
PCI_DMA_FROMDEVICE);
+ skb = np->get_rx_ctx->skb;
+ np->get_rx_ctx->skb = NULL;
{
int j;
@@ -1864,123 +2143,228 @@ static int nv_rx_process(struct net_device *dev, int limit)
for (j=0; j<64; j++) {
if ((j%16) == 0)
dprintk("\n%03x:", j);
- dprintk(" %02x", ((unsigned char*)np->rx_skbuff[i]->data)[j]);
+ dprintk(" %02x", ((unsigned char*)skb->data)[j]);
}
dprintk("\n");
}
/* look at what we actually got: */
if (np->desc_ver == DESC_VER_1) {
- if (!(flags & NV_RX_DESCRIPTORVALID))
- goto next_pkt;
-
- if (flags & NV_RX_ERROR) {
- if (flags & NV_RX_MISSEDFRAME) {
- np->stats.rx_missed_errors++;
- np->stats.rx_errors++;
- goto next_pkt;
- }
- if (flags & (NV_RX_ERROR1|NV_RX_ERROR2|NV_RX_ERROR3)) {
- np->stats.rx_errors++;
- goto next_pkt;
- }
- if (flags & NV_RX_CRCERR) {
- np->stats.rx_crc_errors++;
- np->stats.rx_errors++;
- goto next_pkt;
- }
- if (flags & NV_RX_OVERFLOW) {
- np->stats.rx_over_errors++;
- np->stats.rx_errors++;
- goto next_pkt;
+ if (likely(flags & NV_RX_DESCRIPTORVALID)) {
+ len = flags & LEN_MASK_V1;
+ if (unlikely(flags & NV_RX_ERROR)) {
+ if (flags & NV_RX_ERROR4) {
+ len = nv_getlen(dev, skb->data, len);
+ if (len < 0) {
+ np->stats.rx_errors++;
+ dev_kfree_skb(skb);
+ goto next_pkt;
+ }
+ }
+ /* framing errors are soft errors */
+ else if (flags & NV_RX_FRAMINGERR) {
+ if (flags & NV_RX_SUBSTRACT1) {
+ len--;
+ }
+ }
+ /* the rest are hard errors */
+ else {
+ if (flags & NV_RX_MISSEDFRAME)
+ np->stats.rx_missed_errors++;
+ if (flags & NV_RX_CRCERR)
+ np->stats.rx_crc_errors++;
+ if (flags & NV_RX_OVERFLOW)
+ np->stats.rx_over_errors++;
+ np->stats.rx_errors++;
+ dev_kfree_skb(skb);
+ goto next_pkt;
+ }
}
- if (flags & NV_RX_ERROR4) {
- len = nv_getlen(dev, np->rx_skbuff[i]->data, len);
- if (len < 0) {
+ } else {
+ dev_kfree_skb(skb);
+ goto next_pkt;
+ }
+ } else {
+ if (likely(flags & NV_RX2_DESCRIPTORVALID)) {
+ len = flags & LEN_MASK_V2;
+ if (unlikely(flags & NV_RX2_ERROR)) {
+ if (flags & NV_RX2_ERROR4) {
+ len = nv_getlen(dev, skb->data, len);
+ if (len < 0) {
+ np->stats.rx_errors++;
+ dev_kfree_skb(skb);
+ goto next_pkt;
+ }
+ }
+ /* framing errors are soft errors */
+ else if (flags & NV_RX2_FRAMINGERR) {
+ if (flags & NV_RX2_SUBSTRACT1) {
+ len--;
+ }
+ }
+ /* the rest are hard errors */
+ else {
+ if (flags & NV_RX2_CRCERR)
+ np->stats.rx_crc_errors++;
+ if (flags & NV_RX2_OVERFLOW)
+ np->stats.rx_over_errors++;
np->stats.rx_errors++;
+ dev_kfree_skb(skb);
goto next_pkt;
}
}
- /* framing errors are soft errors. */
- if (flags & NV_RX_FRAMINGERR) {
- if (flags & NV_RX_SUBSTRACT1) {
- len--;
+ if ((flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK2)/*ip and tcp */ {
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ } else {
+ if ((flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK1 ||
+ (flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK3) {
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
}
}
- }
- } else {
- if (!(flags & NV_RX2_DESCRIPTORVALID))
+ } else {
+ dev_kfree_skb(skb);
goto next_pkt;
+ }
+ }
+ /* got a valid packet - forward it to the network core */
+ skb_put(skb, len);
+ skb->protocol = eth_type_trans(skb, dev);
+ dprintk(KERN_DEBUG "%s: nv_rx_process: %d bytes, proto %d accepted.\n",
+ dev->name, len, skb->protocol);
+#ifdef CONFIG_FORCEDETH_NAPI
+ netif_receive_skb(skb);
+#else
+ netif_rx(skb);
+#endif
+ dev->last_rx = jiffies;
+ np->stats.rx_packets++;
+ np->stats.rx_bytes += len;
+next_pkt:
+ if (unlikely(np->get_rx.orig++ == np->last_rx.orig))
+ np->get_rx.orig = np->first_rx.orig;
+ if (unlikely(np->get_rx_ctx++ == np->last_rx_ctx))
+ np->get_rx_ctx = np->first_rx_ctx;
+ }
- if (flags & NV_RX2_ERROR) {
- if (flags & (NV_RX2_ERROR1|NV_RX2_ERROR2|NV_RX2_ERROR3)) {
- np->stats.rx_errors++;
- goto next_pkt;
- }
- if (flags & NV_RX2_CRCERR) {
- np->stats.rx_crc_errors++;
- np->stats.rx_errors++;
- goto next_pkt;
- }
- if (flags & NV_RX2_OVERFLOW) {
- np->stats.rx_over_errors++;
- np->stats.rx_errors++;
- goto next_pkt;
- }
+ return rx_processed_cnt;
+}
+
+static int nv_rx_process_optimized(struct net_device *dev, int limit)
+{
+ struct fe_priv *np = netdev_priv(dev);
+ u32 flags;
+ u32 vlanflags = 0;
+ u32 rx_processed_cnt = 0;
+ struct sk_buff *skb;
+ int len;
+
+ while((np->get_rx.ex != np->put_rx.ex) &&
+ !((flags = le32_to_cpu(np->get_rx.ex->flaglen)) & NV_RX2_AVAIL) &&
+ (rx_processed_cnt++ < limit)) {
+
+ dprintk(KERN_DEBUG "%s: nv_rx_process_optimized: flags 0x%x.\n",
+ dev->name, flags);
+
+ /*
+ * the packet is for us - immediately tear down the pci mapping.
+ * TODO: check if a prefetch of the first cacheline improves
+ * the performance.
+ */
+ pci_unmap_single(np->pci_dev, np->get_rx_ctx->dma,
+ np->get_rx_ctx->dma_len,
+ PCI_DMA_FROMDEVICE);
+ skb = np->get_rx_ctx->skb;
+ np->get_rx_ctx->skb = NULL;
+
+ {
+ int j;
+ dprintk(KERN_DEBUG "Dumping packet (flags 0x%x).",flags);
+ for (j=0; j<64; j++) {
+ if ((j%16) == 0)
+ dprintk("\n%03x:", j);
+ dprintk(" %02x", ((unsigned char*)skb->data)[j]);
+ }
+ dprintk("\n");
+ }
+ /* look at what we actually got: */
+ if (likely(flags & NV_RX2_DESCRIPTORVALID)) {
+ len = flags & LEN_MASK_V2;
+ if (unlikely(flags & NV_RX2_ERROR)) {
if (flags & NV_RX2_ERROR4) {
- len = nv_getlen(dev, np->rx_skbuff[i]->data, len);
+ len = nv_getlen(dev, skb->data, len);
if (len < 0) {
- np->stats.rx_errors++;
+ dev_kfree_skb(skb);
goto next_pkt;
}
}
/* framing errors are soft errors */
- if (flags & NV_RX2_FRAMINGERR) {
+ else if (flags & NV_RX2_FRAMINGERR) {
if (flags & NV_RX2_SUBSTRACT1) {
len--;
}
}
+ /* the rest are hard errors */
+ else {
+ dev_kfree_skb(skb);
+ goto next_pkt;
+ }
}
- if (np->rx_csum) {
- flags &= NV_RX2_CHECKSUMMASK;
- if (flags == NV_RX2_CHECKSUMOK1 ||
- flags == NV_RX2_CHECKSUMOK2 ||
- flags == NV_RX2_CHECKSUMOK3) {
- dprintk(KERN_DEBUG "%s: hw checksum hit!.\n", dev->name);
- np->rx_skbuff[i]->ip_summed = CHECKSUM_UNNECESSARY;
- } else {
- dprintk(KERN_DEBUG "%s: hwchecksum miss!.\n", dev->name);
+
+ if ((flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK2)/*ip and tcp */ {
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ } else {
+ if ((flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK1 ||
+ (flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK3) {
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
}
}
- }
- /* got a valid packet - forward it to the network core */
- skb = np->rx_skbuff[i];
- np->rx_skbuff[i] = NULL;
- skb_put(skb, len);
- skb->protocol = eth_type_trans(skb, dev);
- dprintk(KERN_DEBUG "%s: nv_rx_process: packet %d with %d bytes, proto %d accepted.\n",
- dev->name, np->cur_rx, len, skb->protocol);
+ /* got a valid packet - forward it to the network core */
+ skb_put(skb, len);
+ skb->protocol = eth_type_trans(skb, dev);
+ prefetch(skb->data);
+
+ dprintk(KERN_DEBUG "%s: nv_rx_process_optimized: %d bytes, proto %d accepted.\n",
+ dev->name, len, skb->protocol);
+
+ if (likely(!np->vlangrp)) {
#ifdef CONFIG_FORCEDETH_NAPI
- if (np->vlangrp && (vlanflags & NV_RX3_VLAN_TAG_PRESENT))
- vlan_hwaccel_receive_skb(skb, np->vlangrp,
- vlanflags & NV_RX3_VLAN_TAG_MASK);
- else
- netif_receive_skb(skb);
+ netif_receive_skb(skb);
#else
- if (np->vlangrp && (vlanflags & NV_RX3_VLAN_TAG_PRESENT))
- vlan_hwaccel_rx(skb, np->vlangrp,
- vlanflags & NV_RX3_VLAN_TAG_MASK);
- else
- netif_rx(skb);
+ netif_rx(skb);
#endif
- dev->last_rx = jiffies;
- np->stats.rx_packets++;
- np->stats.rx_bytes += len;
+ } else {
+ vlanflags = le32_to_cpu(np->get_rx.ex->buflow);
+ if (vlanflags & NV_RX3_VLAN_TAG_PRESENT) {
+#ifdef CONFIG_FORCEDETH_NAPI
+ vlan_hwaccel_receive_skb(skb, np->vlangrp,
+ vlanflags & NV_RX3_VLAN_TAG_MASK);
+#else
+ vlan_hwaccel_rx(skb, np->vlangrp,
+ vlanflags & NV_RX3_VLAN_TAG_MASK);
+#endif
+ } else {
+#ifdef CONFIG_FORCEDETH_NAPI
+ netif_receive_skb(skb);
+#else
+ netif_rx(skb);
+#endif
+ }
+ }
+
+ dev->last_rx = jiffies;
+ np->stats.rx_packets++;
+ np->stats.rx_bytes += len;
+ } else {
+ dev_kfree_skb(skb);
+ }
next_pkt:
- np->cur_rx++;
+ if (unlikely(np->get_rx.ex++ == np->last_rx.ex))
+ np->get_rx.ex = np->first_rx.ex;
+ if (unlikely(np->get_rx_ctx++ == np->last_rx_ctx))
+ np->get_rx_ctx = np->first_rx_ctx;
}
- return count;
+ return rx_processed_cnt;
}
static void set_bufsize(struct net_device *dev)
@@ -2456,7 +2840,6 @@ static irqreturn_t nv_nic_irq(int foo, void *data)
events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQSTAT_MASK;
writel(NVREG_IRQSTAT_MASK, base + NvRegMSIXIrqStatus);
}
- pci_push(base);
dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, events);
if (!(events & np->irqmask))
break;
@@ -2465,22 +2848,46 @@ static irqreturn_t nv_nic_irq(int foo, void *data)
nv_tx_done(dev);
spin_unlock(&np->lock);
- if (events & NVREG_IRQ_LINK) {
+#ifdef CONFIG_FORCEDETH_NAPI
+ if (events & NVREG_IRQ_RX_ALL) {
+ netif_rx_schedule(dev);
+
+ /* Disable furthur receive irq's */
+ spin_lock(&np->lock);
+ np->irqmask &= ~NVREG_IRQ_RX_ALL;
+
+ if (np->msi_flags & NV_MSI_X_ENABLED)
+ writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask);
+ else
+ writel(np->irqmask, base + NvRegIrqMask);
+ spin_unlock(&np->lock);
+ }
+#else
+ if (nv_rx_process(dev, dev->weight)) {
+ if (unlikely(nv_alloc_rx(dev))) {
+ spin_lock(&np->lock);
+ if (!np->in_shutdown)
+ mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
+ spin_unlock(&np->lock);
+ }
+ }
+#endif
+ if (unlikely(events & NVREG_IRQ_LINK)) {
spin_lock(&np->lock);
nv_link_irq(dev);
spin_unlock(&np->lock);
}
- if (np->need_linktimer && time_after(jiffies, np->link_timeout)) {
+ if (unlikely(np->need_linktimer && time_after(jiffies, np->link_timeout))) {
spin_lock(&np->lock);
nv_linkchange(dev);
spin_unlock(&np->lock);
np->link_timeout = jiffies + LINK_TIMEOUT;
}
- if (events & (NVREG_IRQ_TX_ERR)) {
+ if (unlikely(events & (NVREG_IRQ_TX_ERR))) {
dprintk(KERN_DEBUG "%s: received irq with events 0x%x. Probably TX fail.\n",
dev->name, events);
}
- if (events & (NVREG_IRQ_UNKNOWN)) {
+ if (unlikely(events & (NVREG_IRQ_UNKNOWN))) {
printk(KERN_DEBUG "%s: received irq with unknown events 0x%x. Please report\n",
dev->name, events);
}
@@ -2501,6 +2908,63 @@ static irqreturn_t nv_nic_irq(int foo, void *data)
spin_unlock(&np->lock);
break;
}
+ if (unlikely(i > max_interrupt_work)) {
+ spin_lock(&np->lock);
+ /* disable interrupts on the nic */
+ if (!(np->msi_flags & NV_MSI_X_ENABLED))
+ writel(0, base + NvRegIrqMask);
+ else
+ writel(np->irqmask, base + NvRegIrqMask);
+ pci_push(base);
+
+ if (!np->in_shutdown) {
+ np->nic_poll_irq = np->irqmask;
+ mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
+ }
+ printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq.\n", dev->name, i);
+ spin_unlock(&np->lock);
+ break;
+ }
+
+ }
+ dprintk(KERN_DEBUG "%s: nv_nic_irq completed\n", dev->name);
+
+ return IRQ_RETVAL(i);
+}
+
+#define TX_WORK_PER_LOOP 64
+#define RX_WORK_PER_LOOP 64
+/**
+ * All _optimized functions are used to help increase performance
+ * (reduce CPU and increase throughput). They use descripter version 3,
+ * compiler directives, and reduce memory accesses.
+ */
+static irqreturn_t nv_nic_irq_optimized(int foo, void *data)
+{
+ struct net_device *dev = (struct net_device *) data;
+ struct fe_priv *np = netdev_priv(dev);
+ u8 __iomem *base = get_hwbase(dev);
+ u32 events;
+ int i;
+
+ dprintk(KERN_DEBUG "%s: nv_nic_irq_optimized\n", dev->name);
+
+ for (i=0; ; i++) {
+ if (!(np->msi_flags & NV_MSI_X_ENABLED)) {
+ events = readl(base + NvRegIrqStatus) & NVREG_IRQSTAT_MASK;
+ writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus);
+ } else {
+ events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQSTAT_MASK;
+ writel(NVREG_IRQSTAT_MASK, base + NvRegMSIXIrqStatus);
+ }
+ dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, events);
+ if (!(events & np->irqmask))
+ break;
+
+ spin_lock(&np->lock);
+ nv_tx_done_optimized(dev, TX_WORK_PER_LOOP);
+ spin_unlock(&np->lock);
+
#ifdef CONFIG_FORCEDETH_NAPI
if (events & NVREG_IRQ_RX_ALL) {
netif_rx_schedule(dev);
@@ -2516,15 +2980,53 @@ static irqreturn_t nv_nic_irq(int foo, void *data)
spin_unlock(&np->lock);
}
#else
- nv_rx_process(dev, dev->weight);
- if (nv_alloc_rx(dev)) {
+ if (nv_rx_process_optimized(dev, dev->weight)) {
+ if (unlikely(nv_alloc_rx_optimized(dev))) {
+ spin_lock(&np->lock);
+ if (!np->in_shutdown)
+ mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
+ spin_unlock(&np->lock);
+ }
+ }
+#endif
+ if (unlikely(events & NVREG_IRQ_LINK)) {
spin_lock(&np->lock);
- if (!np->in_shutdown)
- mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
+ nv_link_irq(dev);
spin_unlock(&np->lock);
}
-#endif
- if (i > max_interrupt_work) {
+ if (unlikely(np->need_linktimer && time_after(jiffies, np->link_timeout))) {
+ spin_lock(&np->lock);
+ nv_linkchange(dev);
+ spin_unlock(&np->lock);
+ np->link_timeout = jiffies + LINK_TIMEOUT;
+ }
+ if (unlikely(events & (NVREG_IRQ_TX_ERR))) {
+ dprintk(KERN_DEBUG "%s: received irq with events 0x%x. Probably TX fail.\n",
+ dev->name, events);
+ }
+ if (unlikely(events & (NVREG_IRQ_UNKNOWN))) {
+ printk(KERN_DEBUG "%s: received irq with unknown events 0x%x. Please report\n",
+ dev->name, events);
+ }
+ if (unlikely(events & NVREG_IRQ_RECOVER_ERROR)) {
+ spin_lock(&np->lock);
+ /* disable interrupts on the nic */
+ if (!(np->msi_flags & NV_MSI_X_ENABLED))
+ writel(0, base + NvRegIrqMask);
+ else
+ writel(np->irqmask, base + NvRegIrqMask);
+ pci_push(base);
+
+ if (!np->in_shutdown) {
+ np->nic_poll_irq = np->irqmask;
+ np->recover_error = 1;
+ mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
+ }
+ spin_unlock(&np->lock);
+ break;
+ }
+
+ if (unlikely(i > max_interrupt_work)) {
spin_lock(&np->lock);
/* disable interrupts on the nic */
if (!(np->msi_flags & NV_MSI_X_ENABLED))
@@ -2543,7 +3045,7 @@ static irqreturn_t nv_nic_irq(int foo, void *data)
}
}
- dprintk(KERN_DEBUG "%s: nv_nic_irq completed\n", dev->name);
+ dprintk(KERN_DEBUG "%s: nv_nic_irq_optimized completed\n", dev->name);
return IRQ_RETVAL(i);
}
@@ -2562,20 +3064,19 @@ static irqreturn_t nv_nic_irq_tx(int foo, void *data)
for (i=0; ; i++) {
events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQ_TX_ALL;
writel(NVREG_IRQ_TX_ALL, base + NvRegMSIXIrqStatus);
- pci_push(base);
dprintk(KERN_DEBUG "%s: tx irq: %08x\n", dev->name, events);
if (!(events & np->irqmask))
break;
spin_lock_irqsave(&np->lock, flags);
- nv_tx_done(dev);
+ nv_tx_done_optimized(dev, TX_WORK_PER_LOOP);
spin_unlock_irqrestore(&np->lock, flags);
- if (events & (NVREG_IRQ_TX_ERR)) {
+ if (unlikely(events & (NVREG_IRQ_TX_ERR))) {
dprintk(KERN_DEBUG "%s: received irq with events 0x%x. Probably TX fail.\n",
dev->name, events);
}
- if (i > max_interrupt_work) {
+ if (unlikely(i > max_interrupt_work)) {
spin_lock_irqsave(&np->lock, flags);
/* disable interrupts on the nic */
writel(NVREG_IRQ_TX_ALL, base + NvRegIrqMask);
@@ -2604,7 +3105,10 @@ static int nv_napi_poll(struct net_device *dev, int *budget)
u8 __iomem *base = get_hwbase(dev);
unsigned long flags;
- pkts = nv_rx_process(dev, limit);
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+ pkts = nv_rx_process(dev, limit);
+ else
+ pkts = nv_rx_process_optimized(dev, limit);
if (nv_alloc_rx(dev)) {
spin_lock_irqsave(&np->lock, flags);
@@ -2670,20 +3174,20 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data)
for (i=0; ; i++) {
events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQ_RX_ALL;
writel(NVREG_IRQ_RX_ALL, base + NvRegMSIXIrqStatus);
- pci_push(base);
dprintk(KERN_DEBUG "%s: rx irq: %08x\n", dev->name, events);
if (!(events & np->irqmask))
break;
- nv_rx_process(dev, dev->weight);
- if (nv_alloc_rx(dev)) {
- spin_lock_irqsave(&np->lock, flags);
- if (!np->in_shutdown)
- mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
- spin_unlock_irqrestore(&np->lock, flags);
+ if (nv_rx_process_optimized(dev, dev->weight)) {
+ if (unlikely(nv_alloc_rx_optimized(dev))) {
+ spin_lock_irqsave(&np->lock, flags);
+ if (!np->in_shutdown)
+ mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
+ spin_unlock_irqrestore(&np->lock, flags);
+ }
}
- if (i > max_interrupt_work) {
+ if (unlikely(i > max_interrupt_work)) {
spin_lock_irqsave(&np->lock, flags);
/* disable interrupts on the nic */
writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask);
@@ -2718,11 +3222,15 @@ static irqreturn_t nv_nic_irq_other(int foo, void *data)
for (i=0; ; i++) {
events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQ_OTHER;
writel(NVREG_IRQ_OTHER, base + NvRegMSIXIrqStatus);
- pci_push(base);
dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, events);
if (!(events & np->irqmask))
break;
+ /* check tx in case we reached max loop limit in tx isr */
+ spin_lock_irqsave(&np->lock, flags);
+ nv_tx_done_optimized(dev, TX_WORK_PER_LOOP);
+ spin_unlock_irqrestore(&np->lock, flags);
+
if (events & NVREG_IRQ_LINK) {
spin_lock_irqsave(&np->lock, flags);
nv_link_irq(dev);
@@ -2752,7 +3260,7 @@ static irqreturn_t nv_nic_irq_other(int foo, void *data)
printk(KERN_DEBUG "%s: received irq with unknown events 0x%x. Please report\n",
dev->name, events);
}
- if (i > max_interrupt_work) {
+ if (unlikely(i > max_interrupt_work)) {
spin_lock_irqsave(&np->lock, flags);
/* disable interrupts on the nic */
writel(NVREG_IRQ_OTHER, base + NvRegIrqMask);
@@ -2835,6 +3343,16 @@ static int nv_request_irq(struct net_device *dev, int intr_test)
u8 __iomem *base = get_hwbase(dev);
int ret = 1;
int i;
+ irqreturn_t (*handler)(int foo, void *data);
+
+ if (intr_test) {
+ handler = nv_nic_irq_test;
+ } else {
+ if (np->desc_ver == DESC_VER_3)
+ handler = nv_nic_irq_optimized;
+ else
+ handler = nv_nic_irq;
+ }
if (np->msi_flags & NV_MSI_X_CAPABLE) {
for (i = 0; i < (np->msi_flags & NV_MSI_X_VECTORS_MASK); i++) {
@@ -2872,10 +3390,7 @@ static int nv_request_irq(struct net_device *dev, int intr_test)
set_msix_vector_map(dev, NV_MSI_X_VECTOR_OTHER, NVREG_IRQ_OTHER);
} else {
/* Request irq for all interrupts */
- if ((!intr_test &&
- request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector, &nv_nic_irq, IRQF_SHARED, dev->name, dev) != 0) ||
- (intr_test &&
- request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector, &nv_nic_irq_test, IRQF_SHARED, dev->name, dev) != 0)) {
+ if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector, handler, IRQF_SHARED, dev->name, dev) != 0) {
printk(KERN_INFO "forcedeth: request_irq failed %d\n", ret);
pci_disable_msix(np->pci_dev);
np->msi_flags &= ~NV_MSI_X_ENABLED;
@@ -2891,8 +3406,7 @@ static int nv_request_irq(struct net_device *dev, int intr_test)
if (ret != 0 && np->msi_flags & NV_MSI_CAPABLE) {
if ((ret = pci_enable_msi(np->pci_dev)) == 0) {
np->msi_flags |= NV_MSI_ENABLED;
- if ((!intr_test && request_irq(np->pci_dev->irq, &nv_nic_irq, IRQF_SHARED, dev->name, dev) != 0) ||
- (intr_test && request_irq(np->pci_dev->irq, &nv_nic_irq_test, IRQF_SHARED, dev->name, dev) != 0)) {
+ if (request_irq(np->pci_dev->irq, handler, IRQF_SHARED, dev->name, dev) != 0) {
printk(KERN_INFO "forcedeth: request_irq failed %d\n", ret);
pci_disable_msi(np->pci_dev);
np->msi_flags &= ~NV_MSI_ENABLED;
@@ -2907,8 +3421,7 @@ static int nv_request_irq(struct net_device *dev, int intr_test)
}
}
if (ret != 0) {
- if ((!intr_test && request_irq(np->pci_dev->irq, &nv_nic_irq, IRQF_SHARED, dev->name, dev) != 0) ||
- (intr_test && request_irq(np->pci_dev->irq, &nv_nic_irq_test, IRQF_SHARED, dev->name, dev) != 0))
+ if (request_irq(np->pci_dev->irq, handler, IRQF_SHARED, dev->name, dev) != 0)
goto out_err;
}
@@ -3051,47 +3564,8 @@ static void nv_do_stats_poll(unsigned long data)
{
struct net_device *dev = (struct net_device *) data;
struct fe_priv *np = netdev_priv(dev);
- u8 __iomem *base = get_hwbase(dev);
- np->estats.tx_bytes += readl(base + NvRegTxCnt);
- np->estats.tx_zero_rexmt += readl(base + NvRegTxZeroReXmt);
- np->estats.tx_one_rexmt += readl(base + NvRegTxOneReXmt);
- np->estats.tx_many_rexmt += readl(base + NvRegTxManyReXmt);
- np->estats.tx_late_collision += readl(base + NvRegTxLateCol);
- np->estats.tx_fifo_errors += readl(base + NvRegTxUnderflow);
- np->estats.tx_carrier_errors += readl(base + NvRegTxLossCarrier);
- np->estats.tx_excess_deferral += readl(base + NvRegTxExcessDef);
- np->estats.tx_retry_error += readl(base + NvRegTxRetryErr);
- np->estats.tx_deferral += readl(base + NvRegTxDef);
- np->estats.tx_packets += readl(base + NvRegTxFrame);
- np->estats.tx_pause += readl(base + NvRegTxPause);
- np->estats.rx_frame_error += readl(base + NvRegRxFrameErr);
- np->estats.rx_extra_byte += readl(base + NvRegRxExtraByte);
- np->estats.rx_late_collision += readl(base + NvRegRxLateCol);
- np->estats.rx_runt += readl(base + NvRegRxRunt);
- np->estats.rx_frame_too_long += readl(base + NvRegRxFrameTooLong);
- np->estats.rx_over_errors += readl(base + NvRegRxOverflow);
- np->estats.rx_crc_errors += readl(base + NvRegRxFCSErr);
- np->estats.rx_frame_align_error += readl(base + NvRegRxFrameAlignErr);
- np->estats.rx_length_error += readl(base + NvRegRxLenErr);
- np->estats.rx_unicast += readl(base + NvRegRxUnicast);
- np->estats.rx_multicast += readl(base + NvRegRxMulticast);
- np->estats.rx_broadcast += readl(base + NvRegRxBroadcast);
- np->estats.rx_bytes += readl(base + NvRegRxCnt);
- np->estats.rx_pause += readl(base + NvRegRxPause);
- np->estats.rx_drop_frame += readl(base + NvRegRxDropFrame);
- np->estats.rx_packets =
- np->estats.rx_unicast +
- np->estats.rx_multicast +
- np->estats.rx_broadcast;
- np->estats.rx_errors_total =
- np->estats.rx_crc_errors +
- np->estats.rx_over_errors +
- np->estats.rx_frame_error +
- (np->estats.rx_frame_align_error - np->estats.rx_extra_byte) +
- np->estats.rx_late_collision +
- np->estats.rx_runt +
- np->estats.rx_frame_too_long;
+ nv_get_hw_stats(dev);
if (!np->in_shutdown)
mod_timer(&np->stats_poll, jiffies + STATS_INTERVAL);
@@ -3465,7 +3939,7 @@ static int nv_set_ringparam(struct net_device *dev, struct ethtool_ringparam* ri
{
struct fe_priv *np = netdev_priv(dev);
u8 __iomem *base = get_hwbase(dev);
- u8 *rxtx_ring, *rx_skbuff, *tx_skbuff, *rx_dma, *tx_dma, *tx_dma_len;
+ u8 *rxtx_ring, *rx_skbuff, *tx_skbuff;
dma_addr_t ring_addr;
if (ring->rx_pending < RX_RING_MIN ||
@@ -3491,12 +3965,9 @@ static int nv_set_ringparam(struct net_device *dev, struct ethtool_ringparam* ri
sizeof(struct ring_desc_ex) * (ring->rx_pending + ring->tx_pending),
&ring_addr);
}
- rx_skbuff = kmalloc(sizeof(struct sk_buff*) * ring->rx_pending, GFP_KERNEL);
- rx_dma = kmalloc(sizeof(dma_addr_t) * ring->rx_pending, GFP_KERNEL);
- tx_skbuff = kmalloc(sizeof(struct sk_buff*) * ring->tx_pending, GFP_KERNEL);
- tx_dma = kmalloc(sizeof(dma_addr_t) * ring->tx_pending, GFP_KERNEL);
- tx_dma_len = kmalloc(sizeof(unsigned int) * ring->tx_pending, GFP_KERNEL);
- if (!rxtx_ring || !rx_skbuff || !rx_dma || !tx_skbuff || !tx_dma || !tx_dma_len) {
+ rx_skbuff = kmalloc(sizeof(struct nv_skb_map) * ring->rx_pending, GFP_KERNEL);
+ tx_skbuff = kmalloc(sizeof(struct nv_skb_map) * ring->tx_pending, GFP_KERNEL);
+ if (!rxtx_ring || !rx_skbuff || !tx_skbuff) {
/* fall back to old rings */
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
if (rxtx_ring)
@@ -3509,14 +3980,8 @@ static int nv_set_ringparam(struct net_device *dev, struct ethtool_ringparam* ri
}
if (rx_skbuff)
kfree(rx_skbuff);
- if (rx_dma)
- kfree(rx_dma);
if (tx_skbuff)
kfree(tx_skbuff);
- if (tx_dma)
- kfree(tx_dma);
- if (tx_dma_len)
- kfree(tx_dma_len);
goto exit;
}
@@ -3538,8 +4003,6 @@ static int nv_set_ringparam(struct net_device *dev, struct ethtool_ringparam* ri
/* set new values */
np->rx_ring_size = ring->rx_pending;
np->tx_ring_size = ring->tx_pending;
- np->tx_limit_stop = ring->tx_pending - TX_LIMIT_DIFFERENCE;
- np->tx_limit_start = ring->tx_pending - TX_LIMIT_DIFFERENCE - 1;
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
np->rx_ring.orig = (struct ring_desc*)rxtx_ring;
np->tx_ring.orig = &np->rx_ring.orig[np->rx_ring_size];
@@ -3547,18 +4010,12 @@ static int nv_set_ringparam(struct net_device *dev, struct ethtool_ringparam* ri
np->rx_ring.ex = (struct ring_desc_ex*)rxtx_ring;
np->tx_ring.ex = &np->rx_ring.ex[np->rx_ring_size];
}
- np->rx_skbuff = (struct sk_buff**)rx_skbuff;
- np->rx_dma = (dma_addr_t*)rx_dma;
- np->tx_skbuff = (struct sk_buff**)tx_skbuff;
- np->tx_dma = (dma_addr_t*)tx_dma;
- np->tx_dma_len = (unsigned int*)tx_dma_len;
+ np->rx_skb = (struct nv_skb_map*)rx_skbuff;
+ np->tx_skb = (struct nv_skb_map*)tx_skbuff;
np->ring_addr = ring_addr;
- memset(np->rx_skbuff, 0, sizeof(struct sk_buff*) * np->rx_ring_size);
- memset(np->rx_dma, 0, sizeof(dma_addr_t) * np->rx_ring_size);
- memset(np->tx_skbuff, 0, sizeof(struct sk_buff*) * np->tx_ring_size);
- memset(np->tx_dma, 0, sizeof(dma_addr_t) * np->tx_ring_size);
- memset(np->tx_dma_len, 0, sizeof(unsigned int) * np->tx_ring_size);
+ memset(np->rx_skb, 0, sizeof(struct nv_skb_map) * np->rx_ring_size);
+ memset(np->tx_skb, 0, sizeof(struct nv_skb_map) * np->tx_ring_size);
if (netif_running(dev)) {
/* reinit driver view of the queues */
@@ -3727,8 +4184,10 @@ static int nv_get_stats_count(struct net_device *dev)
{
struct fe_priv *np = netdev_priv(dev);
- if (np->driver_data & DEV_HAS_STATISTICS)
- return sizeof(struct nv_ethtool_stats)/sizeof(u64);
+ if (np->driver_data & DEV_HAS_STATISTICS_V1)
+ return NV_DEV_STATISTICS_V1_COUNT;
+ else if (np->driver_data & DEV_HAS_STATISTICS_V2)
+ return NV_DEV_STATISTICS_V2_COUNT;
else
return 0;
}
@@ -3955,7 +4414,7 @@ static int nv_loopback_test(struct net_device *dev)
dprintk(KERN_DEBUG "%s: loopback len mismatch %d vs %d\n",
dev->name, len, pkt_len);
} else {
- rx_skb = np->rx_skbuff[0];
+ rx_skb = np->rx_skb[0].skb;
for (i = 0; i < pkt_len; i++) {
if (rx_skb->data[i] != (u8)(i & 0xff)) {
ret = 0;
@@ -4315,7 +4774,7 @@ static int nv_open(struct net_device *dev)
mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
/* start statistics timer */
- if (np->driver_data & DEV_HAS_STATISTICS)
+ if (np->driver_data & (DEV_HAS_STATISTICS_V1|DEV_HAS_STATISTICS_V2))
mod_timer(&np->stats_poll, jiffies + STATS_INTERVAL);
spin_unlock_irq(&np->lock);
@@ -4412,7 +4871,9 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
if (err < 0)
goto out_disable;
- if (id->driver_data & (DEV_HAS_VLAN|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS))
+ if (id->driver_data & (DEV_HAS_VLAN|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS_V2))
+ np->register_size = NV_PCI_REGSZ_VER3;
+ else if (id->driver_data & DEV_HAS_STATISTICS_V1)
np->register_size = NV_PCI_REGSZ_VER2;
else
np->register_size = NV_PCI_REGSZ_VER1;
@@ -4475,10 +4936,8 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
np->rx_csum = 1;
np->txrxctl_bits |= NVREG_TXRXCTL_RXCHECK;
dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG;
-#ifdef NETIF_F_TSO
dev->features |= NETIF_F_TSO;
-#endif
- }
+ }
np->vlanctl_bits = 0;
if (id->driver_data & DEV_HAS_VLAN) {
@@ -4512,8 +4971,6 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
np->rx_ring_size = RX_RING_DEFAULT;
np->tx_ring_size = TX_RING_DEFAULT;
- np->tx_limit_stop = np->tx_ring_size - TX_LIMIT_DIFFERENCE;
- np->tx_limit_start = np->tx_ring_size - TX_LIMIT_DIFFERENCE - 1;
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
np->rx_ring.orig = pci_alloc_consistent(pci_dev,
@@ -4530,22 +4987,19 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
goto out_unmap;
np->tx_ring.ex = &np->rx_ring.ex[np->rx_ring_size];
}
- np->rx_skbuff = kmalloc(sizeof(struct sk_buff*) * np->rx_ring_size, GFP_KERNEL);
- np->rx_dma = kmalloc(sizeof(dma_addr_t) * np->rx_ring_size, GFP_KERNEL);
- np->tx_skbuff = kmalloc(sizeof(struct sk_buff*) * np->tx_ring_size, GFP_KERNEL);
- np->tx_dma = kmalloc(sizeof(dma_addr_t) * np->tx_ring_size, GFP_KERNEL);
- np->tx_dma_len = kmalloc(sizeof(unsigned int) * np->tx_ring_size, GFP_KERNEL);
- if (!np->rx_skbuff || !np->rx_dma || !np->tx_skbuff || !np->tx_dma || !np->tx_dma_len)
+ np->rx_skb = kmalloc(sizeof(struct nv_skb_map) * np->rx_ring_size, GFP_KERNEL);
+ np->tx_skb = kmalloc(sizeof(struct nv_skb_map) * np->tx_ring_size, GFP_KERNEL);
+ if (!np->rx_skb || !np->tx_skb)
goto out_freering;
- memset(np->rx_skbuff, 0, sizeof(struct sk_buff*) * np->rx_ring_size);
- memset(np->rx_dma, 0, sizeof(dma_addr_t) * np->rx_ring_size);
- memset(np->tx_skbuff, 0, sizeof(struct sk_buff*) * np->tx_ring_size);
- memset(np->tx_dma, 0, sizeof(dma_addr_t) * np->tx_ring_size);
- memset(np->tx_dma_len, 0, sizeof(unsigned int) * np->tx_ring_size);
+ memset(np->rx_skb, 0, sizeof(struct nv_skb_map) * np->rx_ring_size);
+ memset(np->tx_skb, 0, sizeof(struct nv_skb_map) * np->tx_ring_size);
dev->open = nv_open;
dev->stop = nv_close;
- dev->hard_start_xmit = nv_start_xmit;
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+ dev->hard_start_xmit = nv_start_xmit;
+ else
+ dev->hard_start_xmit = nv_start_xmit_optimized;
dev->get_stats = nv_get_stats;
dev->change_mtu = nv_change_mtu;
dev->set_mac_address = nv_set_mac_address;
@@ -4553,7 +5007,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = nv_poll_controller;
#endif
- dev->weight = 64;
+ dev->weight = RX_WORK_PER_LOOP;
#ifdef CONFIG_FORCEDETH_NAPI
dev->poll = nv_napi_poll;
#endif
@@ -4868,83 +5322,83 @@ static struct pci_device_id pci_tbl[] = {
},
{ /* CK804 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_8),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1,
},
{ /* CK804 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_9),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1,
},
{ /* MCP04 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_10),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1,
},
{ /* MCP04 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_11),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1,
},
{ /* MCP51 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_12),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS_V1,
},
{ /* MCP51 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_13),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS_V1,
},
{ /* MCP55 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_14),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
},
{ /* MCP55 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_15),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
},
{ /* MCP61 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_16),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
},
{ /* MCP61 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_17),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
},
{ /* MCP61 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_18),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
},
{ /* MCP61 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_19),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
},
{ /* MCP65 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_20),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
},
{ /* MCP65 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_21),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
},
{ /* MCP65 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_22),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
},
{ /* MCP65 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_23),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
},
{ /* MCP67 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_24),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
},
{ /* MCP67 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_25),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
},
{ /* MCP67 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_26),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
},
{ /* MCP67 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_27),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
},
{0,},
};
diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c
index 889d3a13e95..4a05c14bf7e 100644
--- a/drivers/net/fs_enet/fs_enet-main.c
+++ b/drivers/net/fs_enet/fs_enet-main.c
@@ -18,7 +18,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
-#include <linux/sched.h>
#include <linux/string.h>
#include <linux/ptrace.h>
#include <linux/errno.h>
diff --git a/drivers/net/fs_enet/fs_enet.h b/drivers/net/fs_enet/fs_enet.h
index 92590d8fc24..569be225cd0 100644
--- a/drivers/net/fs_enet/fs_enet.h
+++ b/drivers/net/fs_enet/fs_enet.h
@@ -9,6 +9,7 @@
#include <linux/dma-mapping.h>
#include <linux/fs_enet_pd.h>
+#include <asm/fs_pd.h>
#ifdef CONFIG_CPM1
#include <asm/commproc.h>
diff --git a/drivers/net/fs_enet/mac-fcc.c b/drivers/net/fs_enet/mac-fcc.c
index 1ff2597b849..8545e84fc9a 100644
--- a/drivers/net/fs_enet/mac-fcc.c
+++ b/drivers/net/fs_enet/mac-fcc.c
@@ -15,7 +15,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
-#include <linux/sched.h>
#include <linux/string.h>
#include <linux/ptrace.h>
#include <linux/errno.h>
diff --git a/drivers/net/fs_enet/mac-fec.c b/drivers/net/fs_enet/mac-fec.c
index ff683947730..cdcfb96f360 100644
--- a/drivers/net/fs_enet/mac-fec.c
+++ b/drivers/net/fs_enet/mac-fec.c
@@ -15,7 +15,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
-#include <linux/sched.h>
#include <linux/string.h>
#include <linux/ptrace.h>
#include <linux/errno.h>
diff --git a/drivers/net/fs_enet/mac-scc.c b/drivers/net/fs_enet/mac-scc.c
index afd7fca7c6c..65925b5a224 100644
--- a/drivers/net/fs_enet/mac-scc.c
+++ b/drivers/net/fs_enet/mac-scc.c
@@ -15,7 +15,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
-#include <linux/sched.h>
#include <linux/string.h>
#include <linux/ptrace.h>
#include <linux/errno.h>
diff --git a/drivers/net/fs_enet/mii-bitbang.c b/drivers/net/fs_enet/mii-bitbang.c
index 0b9b8b5c847..f91447837fd 100644
--- a/drivers/net/fs_enet/mii-bitbang.c
+++ b/drivers/net/fs_enet/mii-bitbang.c
@@ -16,7 +16,6 @@
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/string.h>
#include <linux/ptrace.h>
#include <linux/errno.h>
diff --git a/drivers/net/fs_enet/mii-fec.c b/drivers/net/fs_enet/mii-fec.c
index baaae3dbf2e..235b177fb9a 100644
--- a/drivers/net/fs_enet/mii-fec.c
+++ b/drivers/net/fs_enet/mii-fec.c
@@ -15,7 +15,6 @@
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/string.h>
#include <linux/ptrace.h>
#include <linux/errno.h>
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index baa35144134..1f83988a6a6 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -10,6 +10,7 @@
* Maintainer: Kumar Gala
*
* Copyright (c) 2002-2006 Freescale Semiconductor, Inc.
+ * Copyright (c) 2007 MontaVista Software, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -65,7 +66,6 @@
*/
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/unistd.h>
@@ -1613,71 +1613,17 @@ static irqreturn_t gfar_interrupt(int irq, void *dev_id)
/* Save ievent for future reference */
u32 events = gfar_read(&priv->regs->ievent);
- /* Clear IEVENT */
- gfar_write(&priv->regs->ievent, events);
-
/* Check for reception */
- if ((events & IEVENT_RXF0) || (events & IEVENT_RXB0))
+ if (events & IEVENT_RX_MASK)
gfar_receive(irq, dev_id);
/* Check for transmit completion */
- if ((events & IEVENT_TXF) || (events & IEVENT_TXB))
+ if (events & IEVENT_TX_MASK)
gfar_transmit(irq, dev_id);
- /* Update error statistics */
- if (events & IEVENT_TXE) {
- priv->stats.tx_errors++;
-
- if (events & IEVENT_LC)
- priv->stats.tx_window_errors++;
- if (events & IEVENT_CRL)
- priv->stats.tx_aborted_errors++;
- if (events & IEVENT_XFUN) {
- if (netif_msg_tx_err(priv))
- printk(KERN_WARNING "%s: tx underrun. dropped packet\n", dev->name);
- priv->stats.tx_dropped++;
- priv->extra_stats.tx_underrun++;
-
- /* Reactivate the Tx Queues */
- gfar_write(&priv->regs->tstat, TSTAT_CLEAR_THALT);
- }
- }
- if (events & IEVENT_BSY) {
- priv->stats.rx_errors++;
- priv->extra_stats.rx_bsy++;
-
- gfar_receive(irq, dev_id);
-
-#ifndef CONFIG_GFAR_NAPI
- /* Clear the halt bit in RSTAT */
- gfar_write(&priv->regs->rstat, RSTAT_CLEAR_RHALT);
-#endif
-
- if (netif_msg_rx_err(priv))
- printk(KERN_DEBUG "%s: busy error (rhalt: %x)\n",
- dev->name,
- gfar_read(&priv->regs->rstat));
- }
- if (events & IEVENT_BABR) {
- priv->stats.rx_errors++;
- priv->extra_stats.rx_babr++;
-
- if (netif_msg_rx_err(priv))
- printk(KERN_DEBUG "%s: babbling error\n", dev->name);
- }
- if (events & IEVENT_EBERR) {
- priv->extra_stats.eberr++;
- if (netif_msg_rx_err(priv))
- printk(KERN_DEBUG "%s: EBERR\n", dev->name);
- }
- if ((events & IEVENT_RXC) && (netif_msg_rx_err(priv)))
- printk(KERN_DEBUG "%s: control frame\n", dev->name);
-
- if (events & IEVENT_BABT) {
- priv->extra_stats.tx_babt++;
- if (netif_msg_rx_err(priv))
- printk(KERN_DEBUG "%s: babt error\n", dev->name);
- }
+ /* Check for errors */
+ if (events & IEVENT_ERR_MASK)
+ gfar_error(irq, dev_id);
return IRQ_HANDLED;
}
@@ -1939,7 +1885,7 @@ static irqreturn_t gfar_error(int irq, void *dev_id)
/* Hmm... */
if (netif_msg_rx_err(priv) || netif_msg_tx_err(priv))
printk(KERN_DEBUG "%s: error interrupt (ievent=0x%08x imask=0x%08x)\n",
- dev->name, events, gfar_read(&priv->regs->imask));
+ dev->name, events, gfar_read(&priv->regs->imask));
/* Update the error counters */
if (events & IEVENT_TXE) {
@@ -1951,8 +1897,8 @@ static irqreturn_t gfar_error(int irq, void *dev_id)
priv->stats.tx_aborted_errors++;
if (events & IEVENT_XFUN) {
if (netif_msg_tx_err(priv))
- printk(KERN_DEBUG "%s: underrun. packet dropped.\n",
- dev->name);
+ printk(KERN_DEBUG "%s: TX FIFO underrun, "
+ "packet dropped.\n", dev->name);
priv->stats.tx_dropped++;
priv->extra_stats.tx_underrun++;
@@ -1974,30 +1920,28 @@ static irqreturn_t gfar_error(int irq, void *dev_id)
#endif
if (netif_msg_rx_err(priv))
- printk(KERN_DEBUG "%s: busy error (rhalt: %x)\n",
- dev->name,
- gfar_read(&priv->regs->rstat));
+ printk(KERN_DEBUG "%s: busy error (rstat: %x)\n",
+ dev->name, gfar_read(&priv->regs->rstat));
}
if (events & IEVENT_BABR) {
priv->stats.rx_errors++;
priv->extra_stats.rx_babr++;
if (netif_msg_rx_err(priv))
- printk(KERN_DEBUG "%s: babbling error\n", dev->name);
+ printk(KERN_DEBUG "%s: babbling RX error\n", dev->name);
}
if (events & IEVENT_EBERR) {
priv->extra_stats.eberr++;
if (netif_msg_rx_err(priv))
- printk(KERN_DEBUG "%s: EBERR\n", dev->name);
+ printk(KERN_DEBUG "%s: bus error\n", dev->name);
}
if ((events & IEVENT_RXC) && netif_msg_rx_status(priv))
- if (netif_msg_rx_status(priv))
- printk(KERN_DEBUG "%s: control frame\n", dev->name);
+ printk(KERN_DEBUG "%s: control frame\n", dev->name);
if (events & IEVENT_BABT) {
priv->extra_stats.tx_babt++;
if (netif_msg_tx_err(priv))
- printk(KERN_DEBUG "%s: babt error\n", dev->name);
+ printk(KERN_DEBUG "%s: babbling TX error\n", dev->name);
}
return IRQ_HANDLED;
}
diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c
index 6d71bea5e90..7b411c1514d 100644
--- a/drivers/net/gianfar_ethtool.c
+++ b/drivers/net/gianfar_ethtool.c
@@ -16,7 +16,6 @@
*/
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/slab.h>
@@ -42,8 +41,6 @@
#include "gianfar.h"
-#define is_power_of_2(x) ((x) != 0 && (((x) & ((x) - 1)) == 0))
-
extern void gfar_start(struct net_device *dev);
extern int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit);
diff --git a/drivers/net/gianfar_mii.c b/drivers/net/gianfar_mii.c
index ff684d4be96..bcc6b82f4a3 100644
--- a/drivers/net/gianfar_mii.c
+++ b/drivers/net/gianfar_mii.c
@@ -17,7 +17,6 @@
*/
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/unistd.h>
diff --git a/drivers/net/gianfar_sysfs.c b/drivers/net/gianfar_sysfs.c
index 9dd387fb3d7..aec9ab17a9a 100644
--- a/drivers/net/gianfar_sysfs.c
+++ b/drivers/net/gianfar_sysfs.c
@@ -20,7 +20,6 @@
*/
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/unistd.h>
@@ -39,13 +38,15 @@
#include "gianfar.h"
#define GFAR_ATTR(_name) \
-static ssize_t gfar_show_##_name(struct class_device *cdev, char *buf); \
-static ssize_t gfar_set_##_name(struct class_device *cdev, \
+static ssize_t gfar_show_##_name(struct device *dev, \
+ struct device_attribute *attr, char *buf); \
+static ssize_t gfar_set_##_name(struct device *dev, \
+ struct device_attribute *attr, \
const char *buf, size_t count); \
-static CLASS_DEVICE_ATTR(_name, 0644, gfar_show_##_name, gfar_set_##_name)
+static DEVICE_ATTR(_name, 0644, gfar_show_##_name, gfar_set_##_name)
#define GFAR_CREATE_FILE(_dev, _name) \
- class_device_create_file(&_dev->class_dev, &class_device_attr_##_name)
+ device_create_file(&_dev->dev, &dev_attr_##_name)
GFAR_ATTR(bd_stash);
GFAR_ATTR(rx_stash_size);
@@ -54,29 +55,28 @@ GFAR_ATTR(fifo_threshold);
GFAR_ATTR(fifo_starve);
GFAR_ATTR(fifo_starve_off);
-#define to_net_dev(cd) container_of(cd, struct net_device, class_dev)
-
-static ssize_t gfar_show_bd_stash(struct class_device *cdev, char *buf)
+static ssize_t gfar_show_bd_stash(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- struct net_device *dev = to_net_dev(cdev);
- struct gfar_private *priv = netdev_priv(dev);
+ struct gfar_private *priv = netdev_priv(to_net_dev(dev));
- return sprintf(buf, "%s\n", priv->bd_stash_en? "on" : "off");
+ return sprintf(buf, "%s\n", priv->bd_stash_en ? "on" : "off");
}
-static ssize_t gfar_set_bd_stash(struct class_device *cdev,
- const char *buf, size_t count)
+static ssize_t gfar_set_bd_stash(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
- struct net_device *dev = to_net_dev(cdev);
- struct gfar_private *priv = netdev_priv(dev);
+ struct gfar_private *priv = netdev_priv(to_net_dev(dev));
int new_setting = 0;
u32 temp;
unsigned long flags;
/* Find out the new setting */
- if (!strncmp("on", buf, count-1) || !strncmp("1", buf, count-1))
+ if (!strncmp("on", buf, count - 1) || !strncmp("1", buf, count - 1))
new_setting = 1;
- else if (!strncmp("off", buf, count-1) || !strncmp("0", buf, count-1))
+ else if (!strncmp("off", buf, count - 1)
+ || !strncmp("0", buf, count - 1))
new_setting = 0;
else
return count;
@@ -100,19 +100,19 @@ static ssize_t gfar_set_bd_stash(struct class_device *cdev,
return count;
}
-static ssize_t gfar_show_rx_stash_size(struct class_device *cdev, char *buf)
+static ssize_t gfar_show_rx_stash_size(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- struct net_device *dev = to_net_dev(cdev);
- struct gfar_private *priv = netdev_priv(dev);
+ struct gfar_private *priv = netdev_priv(to_net_dev(dev));
return sprintf(buf, "%d\n", priv->rx_stash_size);
}
-static ssize_t gfar_set_rx_stash_size(struct class_device *cdev,
- const char *buf, size_t count)
+static ssize_t gfar_set_rx_stash_size(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
- struct net_device *dev = to_net_dev(cdev);
- struct gfar_private *priv = netdev_priv(dev);
+ struct gfar_private *priv = netdev_priv(to_net_dev(dev));
unsigned int length = simple_strtoul(buf, NULL, 0);
u32 temp;
unsigned long flags;
@@ -146,21 +146,21 @@ static ssize_t gfar_set_rx_stash_size(struct class_device *cdev,
return count;
}
-
/* Stashing will only be enabled when rx_stash_size != 0 */
-static ssize_t gfar_show_rx_stash_index(struct class_device *cdev, char *buf)
+static ssize_t gfar_show_rx_stash_index(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
- struct net_device *dev = to_net_dev(cdev);
- struct gfar_private *priv = netdev_priv(dev);
+ struct gfar_private *priv = netdev_priv(to_net_dev(dev));
return sprintf(buf, "%d\n", priv->rx_stash_index);
}
-static ssize_t gfar_set_rx_stash_index(struct class_device *cdev,
- const char *buf, size_t count)
+static ssize_t gfar_set_rx_stash_index(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
- struct net_device *dev = to_net_dev(cdev);
- struct gfar_private *priv = netdev_priv(dev);
+ struct gfar_private *priv = netdev_priv(to_net_dev(dev));
unsigned short index = simple_strtoul(buf, NULL, 0);
u32 temp;
unsigned long flags;
@@ -184,19 +184,20 @@ static ssize_t gfar_set_rx_stash_index(struct class_device *cdev,
return count;
}
-static ssize_t gfar_show_fifo_threshold(struct class_device *cdev, char *buf)
+static ssize_t gfar_show_fifo_threshold(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
- struct net_device *dev = to_net_dev(cdev);
- struct gfar_private *priv = netdev_priv(dev);
+ struct gfar_private *priv = netdev_priv(to_net_dev(dev));
return sprintf(buf, "%d\n", priv->fifo_threshold);
}
-static ssize_t gfar_set_fifo_threshold(struct class_device *cdev,
- const char *buf, size_t count)
+static ssize_t gfar_set_fifo_threshold(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
- struct net_device *dev = to_net_dev(cdev);
- struct gfar_private *priv = netdev_priv(dev);
+ struct gfar_private *priv = netdev_priv(to_net_dev(dev));
unsigned int length = simple_strtoul(buf, NULL, 0);
u32 temp;
unsigned long flags;
@@ -218,20 +219,19 @@ static ssize_t gfar_set_fifo_threshold(struct class_device *cdev,
return count;
}
-static ssize_t gfar_show_fifo_starve(struct class_device *cdev, char *buf)
+static ssize_t gfar_show_fifo_starve(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- struct net_device *dev = to_net_dev(cdev);
- struct gfar_private *priv = netdev_priv(dev);
+ struct gfar_private *priv = netdev_priv(to_net_dev(dev));
return sprintf(buf, "%d\n", priv->fifo_starve);
}
-
-static ssize_t gfar_set_fifo_starve(struct class_device *cdev,
- const char *buf, size_t count)
+static ssize_t gfar_set_fifo_starve(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
- struct net_device *dev = to_net_dev(cdev);
- struct gfar_private *priv = netdev_priv(dev);
+ struct gfar_private *priv = netdev_priv(to_net_dev(dev));
unsigned int num = simple_strtoul(buf, NULL, 0);
u32 temp;
unsigned long flags;
@@ -253,19 +253,20 @@ static ssize_t gfar_set_fifo_starve(struct class_device *cdev,
return count;
}
-static ssize_t gfar_show_fifo_starve_off(struct class_device *cdev, char *buf)
+static ssize_t gfar_show_fifo_starve_off(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
- struct net_device *dev = to_net_dev(cdev);
- struct gfar_private *priv = netdev_priv(dev);
+ struct gfar_private *priv = netdev_priv(to_net_dev(dev));
return sprintf(buf, "%d\n", priv->fifo_starve_off);
}
-static ssize_t gfar_set_fifo_starve_off(struct class_device *cdev,
- const char *buf, size_t count)
+static ssize_t gfar_set_fifo_starve_off(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
- struct net_device *dev = to_net_dev(cdev);
- struct gfar_private *priv = netdev_priv(dev);
+ struct gfar_private *priv = netdev_priv(to_net_dev(dev));
unsigned int num = simple_strtoul(buf, NULL, 0);
u32 temp;
unsigned long flags;
diff --git a/drivers/net/hamradio/Kconfig b/drivers/net/hamradio/Kconfig
index feb0ada7a02..6e90619b3b4 100644
--- a/drivers/net/hamradio/Kconfig
+++ b/drivers/net/hamradio/Kconfig
@@ -138,7 +138,7 @@ config BAYCOM_SER_HDX
---help---
This is one of two drivers for Baycom style simple amateur radio
modems that connect to a serial interface. The driver supports the
- ser12 design in full-duplex mode. This is the old driver. It is
+ ser12 design in half-duplex mode. This is the old driver. It is
still provided in case your serial interface chip does not work with
the full-duplex driver. This driver is depreciated. To configure
the driver, use the sethdlc utility available in the standard ax25
@@ -190,3 +190,4 @@ config YAM
To compile this driver as a module, choose M here: the module
will be called yam.
+
diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c
index 153b6dc80af..84aa2117c0e 100644
--- a/drivers/net/hamradio/baycom_epp.c
+++ b/drivers/net/hamradio/baycom_epp.c
@@ -52,6 +52,7 @@
#include <linux/hdlcdrv.h>
#include <linux/baycom.h>
#include <linux/jiffies.h>
+#include <linux/random.h>
#include <net/ax25.h>
#include <asm/uaccess.h>
@@ -433,16 +434,6 @@ static void encode_hdlc(struct baycom_state *bc)
/* ---------------------------------------------------------------------- */
-static unsigned short random_seed;
-
-static inline unsigned short random_num(void)
-{
- random_seed = 28629 * random_seed + 157;
- return random_seed;
-}
-
-/* ---------------------------------------------------------------------- */
-
static int transmit(struct baycom_state *bc, int cnt, unsigned char stat)
{
struct parport *pp = bc->pdev->port;
@@ -464,7 +455,7 @@ static int transmit(struct baycom_state *bc, int cnt, unsigned char stat)
if ((--bc->hdlctx.slotcnt) > 0)
return 0;
bc->hdlctx.slotcnt = bc->ch_params.slottime;
- if ((random_num() % 256) > bc->ch_params.ppersist)
+ if ((random32() % 256) > bc->ch_params.ppersist)
return 0;
}
}
diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c
index 5b788d84011..d2542697e29 100644
--- a/drivers/net/hamradio/bpqether.c
+++ b/drivers/net/hamradio/bpqether.c
@@ -459,7 +459,7 @@ static int bpq_info_open(struct inode *inode, struct file *file)
return seq_open(file, &bpq_seqops);
}
-static struct file_operations bpq_info_fops = {
+static const struct file_operations bpq_info_fops = {
.owner = THIS_MODULE,
.open = bpq_info_open,
.read = seq_read,
diff --git a/drivers/net/hamradio/hdlcdrv.c b/drivers/net/hamradio/hdlcdrv.c
index 452873e7c68..f5a17ad9d3d 100644
--- a/drivers/net/hamradio/hdlcdrv.c
+++ b/drivers/net/hamradio/hdlcdrv.c
@@ -56,6 +56,7 @@
#include <linux/if_arp.h>
#include <linux/skbuff.h>
#include <linux/hdlcdrv.h>
+#include <linux/random.h>
#include <net/ax25.h>
#include <asm/uaccess.h>
@@ -371,16 +372,6 @@ static void start_tx(struct net_device *dev, struct hdlcdrv_state *s)
/* ---------------------------------------------------------------------- */
-static unsigned short random_seed;
-
-static inline unsigned short random_num(void)
-{
- random_seed = 28629 * random_seed + 157;
- return random_seed;
-}
-
-/* ---------------------------------------------------------------------- */
-
void hdlcdrv_arbitrate(struct net_device *dev, struct hdlcdrv_state *s)
{
if (!s || s->magic != HDLCDRV_MAGIC || s->hdlctx.ptt || !s->skb)
@@ -396,7 +387,7 @@ void hdlcdrv_arbitrate(struct net_device *dev, struct hdlcdrv_state *s)
if ((--s->hdlctx.slotcnt) > 0)
return;
s->hdlctx.slotcnt = s->ch_params.slottime;
- if ((random_num() % 256) > s->ch_params.ppersist)
+ if ((random32() % 256) > s->ch_params.ppersist)
return;
start_tx(dev, s);
}
diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c
index 2ce047e9d26..6fdaad5a457 100644
--- a/drivers/net/hamradio/scc.c
+++ b/drivers/net/hamradio/scc.c
@@ -2083,7 +2083,7 @@ static int scc_net_seq_open(struct inode *inode, struct file *file)
return seq_open(file, &scc_net_seq_ops);
}
-static struct file_operations scc_net_seq_fops = {
+static const struct file_operations scc_net_seq_fops = {
.owner = THIS_MODULE,
.open = scc_net_seq_open,
.read = seq_read,
diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c
index 6d74f08720d..ee3ea4fa729 100644
--- a/drivers/net/hamradio/yam.c
+++ b/drivers/net/hamradio/yam.c
@@ -50,6 +50,7 @@
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/bitops.h>
+#include <linux/random.h>
#include <asm/io.h>
#include <asm/system.h>
#include <linux/interrupt.h>
@@ -566,14 +567,6 @@ static void yam_start_tx(struct net_device *dev, struct yam_port *yp)
ptt_on(dev);
}
-static unsigned short random_seed;
-
-static inline unsigned short random_num(void)
-{
- random_seed = 28629 * random_seed + 157;
- return random_seed;
-}
-
static void yam_arbitrate(struct net_device *dev)
{
struct yam_port *yp = netdev_priv(dev);
@@ -600,7 +593,7 @@ static void yam_arbitrate(struct net_device *dev)
yp->slotcnt = yp->slot / 10;
/* is random > persist ? */
- if ((random_num() % 256) > yp->pers)
+ if ((random32() % 256) > yp->pers)
return;
yam_start_tx(dev, yp);
@@ -804,7 +797,7 @@ static int yam_info_open(struct inode *inode, struct file *file)
return seq_open(file, &yam_seqops);
}
-static struct file_operations yam_info_fops = {
+static const struct file_operations yam_info_fops = {
.owner = THIS_MODULE,
.open = yam_info_open,
.read = seq_read,
diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c
index 844c136e992..7dc5185aa2c 100644
--- a/drivers/net/hp100.c
+++ b/drivers/net/hp100.c
@@ -3034,7 +3034,7 @@ static int __init hp100_module_init(void)
goto out2;
#endif
#ifdef CONFIG_PCI
- err = pci_module_init(&hp100_pci_driver);
+ err = pci_register_driver(&hp100_pci_driver);
if (err && err != -ENODEV)
goto out3;
#endif
diff --git a/drivers/net/ibm_emac/ibm_emac_core.c b/drivers/net/ibm_emac/ibm_emac_core.c
index ffeafb28f78..dd8ad874682 100644
--- a/drivers/net/ibm_emac/ibm_emac_core.c
+++ b/drivers/net/ibm_emac/ibm_emac_core.c
@@ -21,7 +21,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c
index 99343b5836b..458db0538a9 100644
--- a/drivers/net/ibmveth.c
+++ b/drivers/net/ibmveth.c
@@ -1156,7 +1156,7 @@ static int ibmveth_proc_open(struct inode *inode, struct file *file)
return rc;
}
-static struct file_operations ibmveth_proc_fops = {
+static const struct file_operations ibmveth_proc_fops = {
.owner = THIS_MODULE,
.open = ibmveth_proc_open,
.read = seq_read,
diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c
index f0d30cf67b5..4ad780719a8 100644
--- a/drivers/net/ioc3-eth.c
+++ b/drivers/net/ioc3-eth.c
@@ -836,13 +836,17 @@ static int ioc3_mii_init(struct ioc3_private *ip)
}
ip->mii.phy_id = i;
+
+out:
+ return res;
+}
+
+static void ioc3_mii_start(struct ioc3_private *ip)
+{
ip->ioc3_timer.expires = jiffies + (12 * HZ)/10; /* 1.2 sec. */
ip->ioc3_timer.data = (unsigned long) ip;
ip->ioc3_timer.function = &ioc3_timer;
add_timer(&ip->ioc3_timer);
-
-out:
- return res;
}
static inline void ioc3_clean_rx_ring(struct ioc3_private *ip)
@@ -1071,6 +1075,7 @@ static int ioc3_open(struct net_device *dev)
ip->ehar_h = 0;
ip->ehar_l = 0;
ioc3_init(dev);
+ ioc3_mii_start(ip);
netif_start_queue(dev);
return 0;
@@ -1274,6 +1279,7 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto out_stop;
}
+ ioc3_mii_start(ip);
ioc3_ssram_disc(ip);
ioc3_get_eaddr(ip);
@@ -1314,6 +1320,7 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
out_stop:
ioc3_stop(ip);
+ del_timer_sync(&ip->ioc3_timer);
ioc3_free_rings(ip);
out_res:
pci_release_regions(pdev);
@@ -1335,6 +1342,8 @@ static void __devexit ioc3_remove_one (struct pci_dev *pdev)
struct ioc3 *ioc3 = ip->regs;
unregister_netdev(dev);
+ del_timer_sync(&ip->ioc3_timer);
+
iounmap(ioc3);
pci_release_regions(pdev);
free_netdev(dev);
@@ -1492,6 +1501,7 @@ static void ioc3_timeout(struct net_device *dev)
ioc3_stop(ip);
ioc3_init(dev);
ioc3_mii_init(ip);
+ ioc3_mii_start(ip);
spin_unlock_irq(&ip->ioc3_lock);
diff --git a/drivers/net/irda/ma600-sir.c b/drivers/net/irda/ma600-sir.c
index ebed168b7da..809906d9476 100644
--- a/drivers/net/irda/ma600-sir.c
+++ b/drivers/net/irda/ma600-sir.c
@@ -34,7 +34,6 @@
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/init.h>
-#include <linux/sched.h>
#include <net/irda/irda.h>
diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c
index e2b1af61845..3457e9d8b66 100644
--- a/drivers/net/irda/vlsi_ir.c
+++ b/drivers/net/irda/vlsi_ir.c
@@ -385,7 +385,7 @@ static int vlsi_seq_open(struct inode *inode, struct file *file)
return single_open(file, vlsi_seq_show, PDE(inode)->data);
}
-static struct file_operations vlsi_proc_fops = {
+static const struct file_operations vlsi_proc_fops = {
.owner = THIS_MODULE,
.open = vlsi_seq_open,
.read = seq_read,
diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c
index 2194b567239..0e9ba3c3faf 100644
--- a/drivers/net/iseries_veth.c
+++ b/drivers/net/iseries_veth.c
@@ -1102,7 +1102,7 @@ static struct net_device * __init veth_probe_one(int vlan,
}
kobject_init(&port->kobject);
- port->kobject.parent = &dev->class_dev.kobj;
+ port->kobject.parent = &dev->dev.kobj;
port->kobject.ktype = &veth_port_ktype;
kobject_set_name(&port->kobject, "veth_port");
if (0 != kobject_add(&port->kobject))
diff --git a/drivers/net/ixgb/ixgb.h b/drivers/net/ixgb/ixgb.h
index f4aba4355b1..cf30a1059ce 100644
--- a/drivers/net/ixgb/ixgb.h
+++ b/drivers/net/ixgb/ixgb.h
@@ -61,9 +61,7 @@
#include <net/pkt_sched.h>
#include <linux/list.h>
#include <linux/reboot.h>
-#ifdef NETIF_F_TSO
#include <net/checksum.h>
-#endif
#include <linux/ethtool.h>
#include <linux/if_vlan.h>
diff --git a/drivers/net/ixgb/ixgb_ethtool.c b/drivers/net/ixgb/ixgb_ethtool.c
index 82c044d6e08..d6628bd9590 100644
--- a/drivers/net/ixgb/ixgb_ethtool.c
+++ b/drivers/net/ixgb/ixgb_ethtool.c
@@ -82,10 +82,8 @@ static struct ixgb_stats ixgb_gstrings_stats[] = {
{"tx_restart_queue", IXGB_STAT(restart_queue) },
{"rx_long_length_errors", IXGB_STAT(stats.roc)},
{"rx_short_length_errors", IXGB_STAT(stats.ruc)},
-#ifdef NETIF_F_TSO
{"tx_tcp_seg_good", IXGB_STAT(stats.tsctc)},
{"tx_tcp_seg_failed", IXGB_STAT(stats.tsctfc)},
-#endif
{"rx_flow_control_xon", IXGB_STAT(stats.xonrxc)},
{"rx_flow_control_xoff", IXGB_STAT(stats.xoffrxc)},
{"tx_flow_control_xon", IXGB_STAT(stats.xontxc)},
@@ -240,7 +238,6 @@ ixgb_set_tx_csum(struct net_device *netdev, uint32_t data)
return 0;
}
-#ifdef NETIF_F_TSO
static int
ixgb_set_tso(struct net_device *netdev, uint32_t data)
{
@@ -250,7 +247,6 @@ ixgb_set_tso(struct net_device *netdev, uint32_t data)
netdev->features &= ~NETIF_F_TSO;
return 0;
}
-#endif /* NETIF_F_TSO */
static uint32_t
ixgb_get_msglevel(struct net_device *netdev)
@@ -722,10 +718,8 @@ static const struct ethtool_ops ixgb_ethtool_ops = {
.set_sg = ethtool_op_set_sg,
.get_msglevel = ixgb_get_msglevel,
.set_msglevel = ixgb_set_msglevel,
-#ifdef NETIF_F_TSO
.get_tso = ethtool_op_get_tso,
.set_tso = ixgb_set_tso,
-#endif
.get_strings = ixgb_get_strings,
.phys_id = ixgb_phys_id,
.get_stats_count = ixgb_get_stats_count,
diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c
index a083a918923..0c368288934 100644
--- a/drivers/net/ixgb/ixgb_main.c
+++ b/drivers/net/ixgb/ixgb_main.c
@@ -456,9 +456,7 @@ ixgb_probe(struct pci_dev *pdev,
NETIF_F_HW_VLAN_TX |
NETIF_F_HW_VLAN_RX |
NETIF_F_HW_VLAN_FILTER;
-#ifdef NETIF_F_TSO
netdev->features |= NETIF_F_TSO;
-#endif
#ifdef NETIF_F_LLTX
netdev->features |= NETIF_F_LLTX;
#endif
@@ -1176,7 +1174,6 @@ ixgb_watchdog(unsigned long data)
static int
ixgb_tso(struct ixgb_adapter *adapter, struct sk_buff *skb)
{
-#ifdef NETIF_F_TSO
struct ixgb_context_desc *context_desc;
unsigned int i;
uint8_t ipcss, ipcso, tucss, tucso, hdr_len;
@@ -1233,7 +1230,6 @@ ixgb_tso(struct ixgb_adapter *adapter, struct sk_buff *skb)
return 1;
}
-#endif
return 0;
}
@@ -1609,7 +1605,7 @@ ixgb_update_stats(struct ixgb_adapter *adapter)
struct pci_dev *pdev = adapter->pdev;
/* Prevent stats update while adapter is being reset */
- if (pdev->error_state && pdev->error_state != pci_channel_io_normal)
+ if (pci_channel_offline(pdev))
return;
if((netdev->flags & IFF_PROMISC) || (netdev->flags & IFF_ALLMULTI) ||
diff --git a/drivers/net/macb.c b/drivers/net/macb.c
index 25b559b5d5e..2e9571bf073 100644
--- a/drivers/net/macb.c
+++ b/drivers/net/macb.c
@@ -27,8 +27,6 @@
#include "macb.h"
-#define to_net_dev(class) container_of(class, struct net_device, class_dev)
-
#define RX_BUFFER_SIZE 128
#define RX_RING_SIZE 512
#define RX_RING_BYTES (sizeof(struct dma_desc) * RX_RING_SIZE)
@@ -883,27 +881,15 @@ static struct net_device_stats *macb_get_stats(struct net_device *dev)
static int macb_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct macb *bp = netdev_priv(dev);
- int ret;
- unsigned long flags;
-
- spin_lock_irqsave(&bp->lock, flags);
- ret = mii_ethtool_gset(&bp->mii, cmd);
- spin_unlock_irqrestore(&bp->lock, flags);
- return ret;
+ return mii_ethtool_gset(&bp->mii, cmd);
}
static int macb_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct macb *bp = netdev_priv(dev);
- int ret;
- unsigned long flags;
-
- spin_lock_irqsave(&bp->lock, flags);
- ret = mii_ethtool_sset(&bp->mii, cmd);
- spin_unlock_irqrestore(&bp->lock, flags);
- return ret;
+ return mii_ethtool_sset(&bp->mii, cmd);
}
static void macb_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
@@ -932,23 +918,17 @@ static struct ethtool_ops macb_ethtool_ops = {
static int macb_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
struct macb *bp = netdev_priv(dev);
- int ret;
- unsigned long flags;
if (!netif_running(dev))
return -EINVAL;
- spin_lock_irqsave(&bp->lock, flags);
- ret = generic_mii_ioctl(&bp->mii, if_mii(rq), cmd, NULL);
- spin_unlock_irqrestore(&bp->lock, flags);
-
- return ret;
+ return generic_mii_ioctl(&bp->mii, if_mii(rq), cmd, NULL);
}
-static ssize_t macb_mii_show(const struct class_device *cd, char *buf,
+static ssize_t macb_mii_show(const struct device *_dev, char *buf,
unsigned long addr)
{
- struct net_device *dev = to_net_dev(cd);
+ struct net_device *dev = to_net_dev(_dev);
struct macb *bp = netdev_priv(dev);
ssize_t ret = -EINVAL;
@@ -962,11 +942,13 @@ static ssize_t macb_mii_show(const struct class_device *cd, char *buf,
}
#define MII_ENTRY(name, addr) \
-static ssize_t show_##name(struct class_device *cd, char *buf) \
+static ssize_t show_##name(struct device *_dev, \
+ struct device_attribute *attr, \
+ char *buf) \
{ \
- return macb_mii_show(cd, buf, addr); \
+ return macb_mii_show(_dev, buf, addr); \
} \
-static CLASS_DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
+static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
MII_ENTRY(bmcr, MII_BMCR);
MII_ENTRY(bmsr, MII_BMSR);
@@ -977,13 +959,13 @@ MII_ENTRY(lpa, MII_LPA);
MII_ENTRY(expansion, MII_EXPANSION);
static struct attribute *macb_mii_attrs[] = {
- &class_device_attr_bmcr.attr,
- &class_device_attr_bmsr.attr,
- &class_device_attr_physid1.attr,
- &class_device_attr_physid2.attr,
- &class_device_attr_advertise.attr,
- &class_device_attr_lpa.attr,
- &class_device_attr_expansion.attr,
+ &dev_attr_bmcr.attr,
+ &dev_attr_bmsr.attr,
+ &dev_attr_physid1.attr,
+ &dev_attr_physid2.attr,
+ &dev_attr_advertise.attr,
+ &dev_attr_lpa.attr,
+ &dev_attr_expansion.attr,
NULL,
};
@@ -994,17 +976,17 @@ static struct attribute_group macb_mii_group = {
static void macb_unregister_sysfs(struct net_device *net)
{
- struct class_device *class_dev = &net->class_dev;
+ struct device *_dev = &net->dev;
- sysfs_remove_group(&class_dev->kobj, &macb_mii_group);
+ sysfs_remove_group(&_dev->kobj, &macb_mii_group);
}
static int macb_register_sysfs(struct net_device *net)
{
- struct class_device *class_dev = &net->class_dev;
+ struct device *_dev = &net->dev;
int ret;
- ret = sysfs_create_group(&class_dev->kobj, &macb_mii_group);
+ ret = sysfs_create_group(&_dev->kobj, &macb_mii_group);
if (ret)
printk(KERN_WARNING
"%s: sysfs mii attribute registration failed: %d\n",
@@ -1046,6 +1028,14 @@ static int __devinit macb_probe(struct platform_device *pdev)
spin_lock_init(&bp->lock);
+#if defined(CONFIG_ARCH_AT91)
+ bp->pclk = clk_get(&pdev->dev, "macb_clk");
+ if (IS_ERR(bp->pclk)) {
+ dev_err(&pdev->dev, "failed to get macb_clk\n");
+ goto err_out_free_dev;
+ }
+ clk_enable(bp->pclk);
+#else
bp->pclk = clk_get(&pdev->dev, "pclk");
if (IS_ERR(bp->pclk)) {
dev_err(&pdev->dev, "failed to get pclk\n");
@@ -1059,6 +1049,7 @@ static int __devinit macb_probe(struct platform_device *pdev)
clk_enable(bp->pclk);
clk_enable(bp->hclk);
+#endif
bp->regs = ioremap(regs->start, regs->end - regs->start + 1);
if (!bp->regs) {
@@ -1068,7 +1059,7 @@ static int __devinit macb_probe(struct platform_device *pdev)
}
dev->irq = platform_get_irq(pdev, 0);
- err = request_irq(dev->irq, macb_interrupt, SA_SAMPLE_RANDOM,
+ err = request_irq(dev->irq, macb_interrupt, IRQF_SAMPLE_RANDOM,
dev->name, dev);
if (err) {
printk(KERN_ERR
@@ -1119,9 +1110,17 @@ static int __devinit macb_probe(struct platform_device *pdev)
pdata = pdev->dev.platform_data;
if (pdata && pdata->is_rmii)
+#if defined(CONFIG_ARCH_AT91)
+ macb_writel(bp, USRIO, (MACB_BIT(RMII) | MACB_BIT(CLKEN)) );
+#else
macb_writel(bp, USRIO, 0);
+#endif
else
+#if defined(CONFIG_ARCH_AT91)
+ macb_writel(bp, USRIO, MACB_BIT(CLKEN));
+#else
macb_writel(bp, USRIO, MACB_BIT(MII));
+#endif
bp->tx_pending = DEF_TX_RING_PENDING;
@@ -1148,9 +1147,11 @@ err_out_free_irq:
err_out_iounmap:
iounmap(bp->regs);
err_out_disable_clocks:
+#ifndef CONFIG_ARCH_AT91
clk_disable(bp->hclk);
- clk_disable(bp->pclk);
clk_put(bp->hclk);
+#endif
+ clk_disable(bp->pclk);
err_out_put_pclk:
clk_put(bp->pclk);
err_out_free_dev:
@@ -1173,9 +1174,11 @@ static int __devexit macb_remove(struct platform_device *pdev)
unregister_netdev(dev);
free_irq(dev->irq, dev);
iounmap(bp->regs);
+#ifndef CONFIG_ARCH_AT91
clk_disable(bp->hclk);
- clk_disable(bp->pclk);
clk_put(bp->hclk);
+#endif
+ clk_disable(bp->pclk);
clk_put(bp->pclk);
free_netdev(dev);
platform_set_drvdata(pdev, NULL);
diff --git a/drivers/net/macb.h b/drivers/net/macb.h
index 27bf0ae0f0b..b3bb2182edd 100644
--- a/drivers/net/macb.h
+++ b/drivers/net/macb.h
@@ -200,7 +200,7 @@
#define MACB_SOF_OFFSET 30
#define MACB_SOF_SIZE 2
-/* Bitfields in USRIO */
+/* Bitfields in USRIO (AVR32) */
#define MACB_MII_OFFSET 0
#define MACB_MII_SIZE 1
#define MACB_EAM_OFFSET 1
@@ -210,6 +210,12 @@
#define MACB_TX_PAUSE_ZERO_OFFSET 3
#define MACB_TX_PAUSE_ZERO_SIZE 1
+/* Bitfields in USRIO (AT91) */
+#define MACB_RMII_OFFSET 0
+#define MACB_RMII_SIZE 1
+#define MACB_CLKEN_OFFSET 1
+#define MACB_CLKEN_SIZE 1
+
/* Bitfields in WOL */
#define MACB_IP_OFFSET 0
#define MACB_IP_SIZE 16
diff --git a/drivers/net/mace.c b/drivers/net/mace.c
index 2907cfb12ad..9ec24f0d5d6 100644
--- a/drivers/net/mace.c
+++ b/drivers/net/mace.c
@@ -15,6 +15,7 @@
#include <linux/init.h>
#include <linux/crc32.h>
#include <linux/spinlock.h>
+#include <linux/bitrev.h>
#include <asm/prom.h>
#include <asm/dbdma.h>
#include <asm/io.h>
@@ -74,7 +75,6 @@ struct mace_data {
#define PRIV_BYTES (sizeof(struct mace_data) \
+ (N_RX_RING + NCMDS_TX * N_TX_RING + 3) * sizeof(struct dbdma_cmd))
-static int bitrev(int);
static int mace_open(struct net_device *dev);
static int mace_close(struct net_device *dev);
static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev);
@@ -96,18 +96,6 @@ static void __mace_set_address(struct net_device *dev, void *addr);
*/
static unsigned char *dummy_buf;
-/* Bit-reverse one byte of an ethernet hardware address. */
-static inline int
-bitrev(int b)
-{
- int d = 0, i;
-
- for (i = 0; i < 8; ++i, b >>= 1)
- d = (d << 1) | (b & 1);
- return d;
-}
-
-
static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_id *match)
{
struct device_node *mace = macio_get_of_node(mdev);
@@ -173,7 +161,7 @@ static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_i
rev = addr[0] == 0 && addr[1] == 0xA0;
for (j = 0; j < 6; ++j) {
- dev->dev_addr[j] = rev? bitrev(addr[j]): addr[j];
+ dev->dev_addr[j] = rev ? bitrev8(addr[j]): addr[j];
}
mp->chipid = (in_8(&mp->mace->chipid_hi) << 8) |
in_8(&mp->mace->chipid_lo);
diff --git a/drivers/net/macmace.c b/drivers/net/macmace.c
index 464e4a6f3d5..5d541e87304 100644
--- a/drivers/net/macmace.c
+++ b/drivers/net/macmace.c
@@ -22,6 +22,7 @@
#include <linux/delay.h>
#include <linux/string.h>
#include <linux/crc32.h>
+#include <linux/bitrev.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/irq.h>
@@ -81,19 +82,6 @@ static irqreturn_t mace_interrupt(int irq, void *dev_id);
static irqreturn_t mace_dma_intr(int irq, void *dev_id);
static void mace_tx_timeout(struct net_device *dev);
-/* Bit-reverse one byte of an ethernet hardware address. */
-
-static int bitrev(int b)
-{
- int d = 0, i;
-
- for (i = 0; i < 8; ++i, b >>= 1) {
- d = (d << 1) | (b & 1);
- }
-
- return d;
-}
-
/*
* Load a receive DMA channel with a base address and ring length
*/
@@ -219,12 +207,12 @@ struct net_device *mace_probe(int unit)
addr = (void *)MACE_PROM;
for (j = 0; j < 6; ++j) {
- u8 v=bitrev(addr[j<<4]);
+ u8 v = bitrev8(addr[j<<4]);
checksum ^= v;
dev->dev_addr[j] = v;
}
for (; j < 8; ++j) {
- checksum ^= bitrev(addr[j<<4]);
+ checksum ^= bitrev8(addr[j<<4]);
}
if (checksum != 0xFF) {
diff --git a/drivers/net/macsonic.c b/drivers/net/macsonic.c
index 393d995f191..8ca57a0a4c1 100644
--- a/drivers/net/macsonic.c
+++ b/drivers/net/macsonic.c
@@ -49,6 +49,7 @@
#include <linux/skbuff.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
+#include <linux/bitrev.h>
#include <asm/bootinfo.h>
#include <asm/system.h>
@@ -121,16 +122,12 @@ enum macsonic_type {
* For reversing the PROM address
*/
-static unsigned char nibbletab[] = {0, 8, 4, 12, 2, 10, 6, 14,
- 1, 9, 5, 13, 3, 11, 7, 15};
-
static inline void bit_reverse_addr(unsigned char addr[6])
{
int i;
for(i = 0; i < 6; i++)
- addr[i] = ((nibbletab[addr[i] & 0xf] << 4) |
- nibbletab[(addr[i] >> 4) &0xf]);
+ addr[i] = bitrev8(addr[i]);
}
int __init macsonic_init(struct net_device* dev)
diff --git a/drivers/net/meth.c b/drivers/net/meth.c
index e1d97cdf649..7e69ca6edd9 100644
--- a/drivers/net/meth.c
+++ b/drivers/net/meth.c
@@ -11,7 +11,6 @@
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/sched.h>
#include <linux/kernel.h> /* printk() */
#include <linux/delay.h>
#include <linux/slab.h>
@@ -171,7 +170,7 @@ static int mdio_probe(struct meth_private *priv)
static void meth_check_link(struct net_device *dev)
{
- struct meth_private *priv = (struct meth_private *) dev->priv;
+ struct meth_private *priv = netdev_priv(dev);
unsigned long mii_advertising = mdio_read(priv, 4);
unsigned long mii_partner = mdio_read(priv, 5);
unsigned long negotiated = mii_advertising & mii_partner;
@@ -269,7 +268,7 @@ static void meth_free_rx_ring(struct meth_private *priv)
int meth_reset(struct net_device *dev)
{
- struct meth_private *priv = (struct meth_private *) dev->priv;
+ struct meth_private *priv = netdev_priv(dev);
/* Reset card */
mace->eth.mac_ctrl = SGI_MAC_RESET;
@@ -311,7 +310,7 @@ int meth_reset(struct net_device *dev)
*/
static int meth_open(struct net_device *dev)
{
- struct meth_private *priv = dev->priv;
+ struct meth_private *priv = netdev_priv(dev);
int ret;
priv->phy_addr = -1; /* No PHY is known yet... */
@@ -355,7 +354,7 @@ out_free_tx_ring:
static int meth_release(struct net_device *dev)
{
- struct meth_private *priv = dev->priv;
+ struct meth_private *priv = netdev_priv(dev);
DPRINTK("Stopping queue\n");
netif_stop_queue(dev); /* can't transmit any more */
@@ -377,7 +376,7 @@ static void meth_rx(struct net_device* dev, unsigned long int_status)
{
struct sk_buff *skb;
unsigned long status;
- struct meth_private *priv = (struct meth_private *) dev->priv;
+ struct meth_private *priv = netdev_priv(dev);
unsigned long fifo_rptr = (int_status & METH_INT_RX_RPTR_MASK) >> 8;
spin_lock(&priv->meth_lock);
@@ -467,14 +466,14 @@ static void meth_rx(struct net_device* dev, unsigned long int_status)
static int meth_tx_full(struct net_device *dev)
{
- struct meth_private *priv = (struct meth_private *) dev->priv;
+ struct meth_private *priv = netdev_priv(dev);
return (priv->tx_count >= TX_RING_ENTRIES - 1);
}
static void meth_tx_cleanup(struct net_device* dev, unsigned long int_status)
{
- struct meth_private *priv = dev->priv;
+ struct meth_private *priv = netdev_priv(dev);
unsigned long status;
struct sk_buff *skb;
unsigned long rptr = (int_status&TX_INFO_RPTR) >> 16;
@@ -537,7 +536,7 @@ static void meth_tx_cleanup(struct net_device* dev, unsigned long int_status)
static void meth_error(struct net_device* dev, unsigned status)
{
- struct meth_private *priv = (struct meth_private *) dev->priv;
+ struct meth_private *priv = netdev_priv(dev);
printk(KERN_WARNING "meth: error status: 0x%08x\n",status);
/* check for errors too... */
@@ -571,7 +570,7 @@ static void meth_error(struct net_device* dev, unsigned status)
static irqreturn_t meth_interrupt(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *)dev_id;
- struct meth_private *priv = (struct meth_private *) dev->priv;
+ struct meth_private *priv = netdev_priv(dev);
unsigned long status;
status = mace->eth.int_stat;
@@ -696,7 +695,7 @@ static void meth_add_to_tx_ring(struct meth_private *priv, struct sk_buff *skb)
*/
static int meth_tx(struct sk_buff *skb, struct net_device *dev)
{
- struct meth_private *priv = (struct meth_private *) dev->priv;
+ struct meth_private *priv = netdev_priv(dev);
unsigned long flags;
spin_lock_irqsave(&priv->meth_lock, flags);
@@ -727,7 +726,7 @@ static int meth_tx(struct sk_buff *skb, struct net_device *dev)
*/
static void meth_tx_timeout(struct net_device *dev)
{
- struct meth_private *priv = (struct meth_private *) dev->priv;
+ struct meth_private *priv = netdev_priv(dev);
unsigned long flags;
printk(KERN_WARNING "%s: transmit timed out\n", dev->name);
@@ -779,7 +778,7 @@ static int meth_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
*/
static struct net_device_stats *meth_stats(struct net_device *dev)
{
- struct meth_private *priv = (struct meth_private *) dev->priv;
+ struct meth_private *priv = netdev_priv(dev);
return &priv->stats;
}
@@ -808,7 +807,7 @@ static struct net_device *meth_init(void)
dev->irq = MACE_ETHERNET_IRQ;
dev->base_addr = (unsigned long)&mace->eth;
- priv = (struct meth_private *) dev->priv;
+ priv = netdev_priv(dev);
spin_lock_init(&priv->meth_lock);
ret = register_netdev(dev);
diff --git a/drivers/net/mipsnet.c b/drivers/net/mipsnet.c
index c9469985bd7..f42b9e20193 100644
--- a/drivers/net/mipsnet.c
+++ b/drivers/net/mipsnet.c
@@ -10,7 +10,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/netdevice.h>
-#include <linux/sched.h>
#include <linux/etherdevice.h>
#include <linux/netdevice.h>
#include <linux/platform_device.h>
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c
index b3bf8642273..d98e53efa2e 100644
--- a/drivers/net/mv643xx_eth.c
+++ b/drivers/net/mv643xx_eth.c
@@ -2780,7 +2780,6 @@ static const struct ethtool_ops mv643xx_ethtool_ops = {
.get_link = mv643xx_eth_get_link,
.get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
- .get_strings = mv643xx_get_strings,
.get_stats_count = mv643xx_get_stats_count,
.get_ethtool_stats = mv643xx_get_ethtool_stats,
.get_strings = mv643xx_get_strings,
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
index 61cbd4a6044..030924fb1ab 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -1412,10 +1412,8 @@ static const struct ethtool_ops myri10ge_ethtool_ops = {
.set_tx_csum = ethtool_op_set_tx_hw_csum,
.get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
-#ifdef NETIF_F_TSO
.get_tso = ethtool_op_get_tso,
.set_tso = ethtool_op_set_tso,
-#endif
.get_strings = myri10ge_get_strings,
.get_stats_count = myri10ge_get_stats_count,
.get_ethtool_stats = myri10ge_get_ethtool_stats,
@@ -1975,13 +1973,11 @@ again:
mss = 0;
max_segments = MXGEFW_MAX_SEND_DESC;
-#ifdef NETIF_F_TSO
if (skb->len > (dev->mtu + ETH_HLEN)) {
mss = skb_shinfo(skb)->gso_size;
if (mss != 0)
max_segments = MYRI10GE_MAX_SEND_DESC_TSO;
}
-#endif /*NETIF_F_TSO */
if ((unlikely(avail < max_segments))) {
/* we are out of transmit resources */
@@ -2013,7 +2009,6 @@ again:
cum_len = 0;
-#ifdef NETIF_F_TSO
if (mss) { /* TSO */
/* this removes any CKSUM flag from before */
flags = (MXGEFW_FLAGS_TSO_HDR | MXGEFW_FLAGS_FIRST);
@@ -2029,7 +2024,6 @@ again:
* the checksum by parsing the header. */
pseudo_hdr_offset = mss;
} else
-#endif /*NETIF_F_TSO */
/* Mark small packets, and pad out tiny packets */
if (skb->len <= MXGEFW_SEND_SMALL_SIZE) {
flags |= MXGEFW_FLAGS_SMALL;
@@ -2097,7 +2091,6 @@ again:
seglen = len;
flags_next = flags & ~MXGEFW_FLAGS_FIRST;
cum_len_next = cum_len + seglen;
-#ifdef NETIF_F_TSO
if (mss) { /* TSO */
(req - rdma_count)->rdma_count = rdma_count + 1;
@@ -2124,7 +2117,6 @@ again:
(small * MXGEFW_FLAGS_SMALL);
}
}
-#endif /* NETIF_F_TSO */
req->addr_high = high_swapped;
req->addr_low = htonl(low);
req->pseudo_hdr_offset = htons(pseudo_hdr_offset);
@@ -2161,14 +2153,12 @@ again:
}
(req - rdma_count)->rdma_count = rdma_count;
-#ifdef NETIF_F_TSO
if (mss)
do {
req--;
req->flags |= MXGEFW_FLAGS_TSO_LAST;
} while (!(req->flags & (MXGEFW_FLAGS_TSO_CHOP |
MXGEFW_FLAGS_FIRST)));
-#endif
idx = ((count - 1) + tx->req) & tx->mask;
tx->info[idx].last = 1;
if (tx->wc_fifo == NULL)
diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c
index ffa0afd2edd..adf29dd6679 100644
--- a/drivers/net/natsemi.c
+++ b/drivers/net/natsemi.c
@@ -244,6 +244,9 @@ enum {
MII_EN_SCRM = 0x0004, /* enable scrambler (tp) */
};
+enum {
+ NATSEMI_FLAG_IGNORE_PHY = 0x1,
+};
/* array of board data directly indexed by pci_tbl[x].driver_data */
static const struct {
@@ -251,10 +254,12 @@ static const struct {
unsigned long flags;
unsigned int eeprom_size;
} natsemi_pci_info[] __devinitdata = {
+ { "Aculab E1/T1 PMXc cPCI carrier card", NATSEMI_FLAG_IGNORE_PHY, 128 },
{ "NatSemi DP8381[56]", 0, 24 },
};
static const struct pci_device_id natsemi_pci_tbl[] __devinitdata = {
+ { PCI_VENDOR_ID_NS, 0x0020, 0x12d9, 0x000c, 0, 0, 0 },
{ PCI_VENDOR_ID_NS, 0x0020, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
{ } /* terminate list */
};
@@ -568,6 +573,8 @@ struct netdev_private {
u32 intr_status;
/* Do not touch the nic registers */
int hands_off;
+ /* Don't pay attention to the reported link state. */
+ int ignore_phy;
/* external phy that is used: only valid if dev->if_port != PORT_TP */
int mii;
int phy_addr_external;
@@ -696,7 +703,10 @@ static void __devinit natsemi_init_media (struct net_device *dev)
struct netdev_private *np = netdev_priv(dev);
u32 tmp;
- netif_carrier_off(dev);
+ if (np->ignore_phy)
+ netif_carrier_on(dev);
+ else
+ netif_carrier_off(dev);
/* get the initial settings from hardware */
tmp = mdio_read(dev, MII_BMCR);
@@ -806,8 +816,13 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
np->hands_off = 0;
np->intr_status = 0;
np->eeprom_size = natsemi_pci_info[chip_idx].eeprom_size;
+ if (natsemi_pci_info[chip_idx].flags & NATSEMI_FLAG_IGNORE_PHY)
+ np->ignore_phy = 1;
+ else
+ np->ignore_phy = 0;
/* Initial port:
+ * - If configured to ignore the PHY set up for external.
* - If the nic was configured to use an external phy and if find_mii
* finds a phy: use external port, first phy that replies.
* - Otherwise: internal port.
@@ -815,7 +830,7 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
* The address would be used to access a phy over the mii bus, but
* the internal phy is accessed through mapped registers.
*/
- if (readl(ioaddr + ChipConfig) & CfgExtPhy)
+ if (np->ignore_phy || readl(ioaddr + ChipConfig) & CfgExtPhy)
dev->if_port = PORT_MII;
else
dev->if_port = PORT_TP;
@@ -825,7 +840,9 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
if (dev->if_port != PORT_TP) {
np->phy_addr_external = find_mii(dev);
- if (np->phy_addr_external == PHY_ADDR_NONE) {
+ /* If we're ignoring the PHY it doesn't matter if we can't
+ * find one. */
+ if (!np->ignore_phy && np->phy_addr_external == PHY_ADDR_NONE) {
dev->if_port = PORT_TP;
np->phy_addr_external = PHY_ADDR_INTERNAL;
}
@@ -891,6 +908,8 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
printk("%02x, IRQ %d", dev->dev_addr[i], irq);
if (dev->if_port == PORT_TP)
printk(", port TP.\n");
+ else if (np->ignore_phy)
+ printk(", port MII, ignoring PHY\n");
else
printk(", port MII, phy ad %d.\n", np->phy_addr_external);
}
@@ -1571,9 +1590,13 @@ static void check_link(struct net_device *dev)
{
struct netdev_private *np = netdev_priv(dev);
void __iomem * ioaddr = ns_ioaddr(dev);
- int duplex;
+ int duplex = np->duplex;
u16 bmsr;
+ /* If we are ignoring the PHY then don't try reading it. */
+ if (np->ignore_phy)
+ goto propagate_state;
+
/* The link status field is latched: it remains low after a temporary
* link failure until it's read. We need the current link status,
* thus read twice.
@@ -1585,7 +1608,7 @@ static void check_link(struct net_device *dev)
if (netif_carrier_ok(dev)) {
if (netif_msg_link(np))
printk(KERN_NOTICE "%s: link down.\n",
- dev->name);
+ dev->name);
netif_carrier_off(dev);
undo_cable_magic(dev);
}
@@ -1609,6 +1632,7 @@ static void check_link(struct net_device *dev)
duplex = 1;
}
+propagate_state:
/* if duplex is set then bit 28 must be set, too */
if (duplex ^ !!(np->rx_config & RxAcceptTx)) {
if (netif_msg_link(np))
@@ -2819,6 +2843,15 @@ static int netdev_set_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
}
/*
+ * If we're ignoring the PHY then autoneg and the internal
+ * transciever are really not going to work so don't let the
+ * user select them.
+ */
+ if (np->ignore_phy && (ecmd->autoneg == AUTONEG_ENABLE ||
+ ecmd->port == PORT_TP))
+ return -EINVAL;
+
+ /*
* maxtxpkt, maxrxpkt: ignored for now.
*
* transceiver:
diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h
index e8598b80922..2807ef400fb 100644
--- a/drivers/net/netxen/netxen_nic.h
+++ b/drivers/net/netxen/netxen_nic.h
@@ -63,11 +63,14 @@
#include "netxen_nic_hw.h"
-#define NETXEN_NIC_BUILD_NO "2"
#define _NETXEN_NIC_LINUX_MAJOR 3
#define _NETXEN_NIC_LINUX_MINOR 3
#define _NETXEN_NIC_LINUX_SUBVERSION 3
-#define NETXEN_NIC_LINUX_VERSIONID "3.3.3" "-" NETXEN_NIC_BUILD_NO
+#define NETXEN_NIC_LINUX_VERSIONID "3.3.3"
+
+#define NUM_FLASH_SECTORS (64)
+#define FLASH_SECTOR_SIZE (64 * 1024)
+#define FLASH_TOTAL_SIZE (NUM_FLASH_SECTORS * FLASH_SECTOR_SIZE)
#define RCV_DESC_RINGSIZE \
(sizeof(struct rcv_desc) * adapter->max_rx_desc_count)
@@ -85,6 +88,7 @@
#define NETXEN_RCV_PRODUCER_OFFSET 0
#define NETXEN_RCV_PEG_DB_ID 2
#define NETXEN_HOST_DUMMY_DMA_SIZE 1024
+#define FLASH_SUCCESS 0
#define ADDR_IN_WINDOW1(off) \
((off > NETXEN_CRB_PCIX_HOST2) && (off < NETXEN_CRB_MAX)) ? 1 : 0
@@ -248,7 +252,7 @@ typedef u32 netxen_ctx_msg;
#define netxen_set_msg_ctxid(config_word, val) \
((config_word) &= ~(0x3ff<<18), (config_word) |= (val & 0x3ff) << 18)
#define netxen_set_msg_opcode(config_word, val) \
- ((config_word) &= ~(0xf<<24), (config_word) |= (val & 0xf) << 24)
+ ((config_word) &= ~(0xf<<28), (config_word) |= (val & 0xf) << 28)
struct netxen_rcv_context {
__le64 rcv_ring_addr;
@@ -299,14 +303,14 @@ struct netxen_ring_ctx {
(cmd_desc)->flags_opcode |= cpu_to_le16((val) & 0x7f))
#define netxen_set_cmd_desc_opcode(cmd_desc, val) \
((cmd_desc)->flags_opcode &= ~cpu_to_le16(0x3f<<7), \
- (cmd_desc)->flags_opcode |= cpu_to_le16((val) & (0x3f<<7)))
+ (cmd_desc)->flags_opcode |= cpu_to_le16(((val & 0x3f)<<7)))
#define netxen_set_cmd_desc_num_of_buff(cmd_desc, val) \
((cmd_desc)->num_of_buffers_total_length &= ~cpu_to_le32(0xff), \
(cmd_desc)->num_of_buffers_total_length |= cpu_to_le32((val) & 0xff))
#define netxen_set_cmd_desc_totallength(cmd_desc, val) \
- ((cmd_desc)->num_of_buffers_total_length &= cpu_to_le32(0xff), \
- (cmd_desc)->num_of_buffers_total_length |= cpu_to_le32(val << 24))
+ ((cmd_desc)->num_of_buffers_total_length &= ~cpu_to_le32(0xffffff00), \
+ (cmd_desc)->num_of_buffers_total_length |= cpu_to_le32(val << 8))
#define netxen_get_cmd_desc_opcode(cmd_desc) \
((le16_to_cpu((cmd_desc)->flags_opcode) >> 7) & 0x003F)
@@ -1028,6 +1032,16 @@ void netxen_phantom_init(struct netxen_adapter *adapter, int pegtune_val);
void netxen_load_firmware(struct netxen_adapter *adapter);
int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose);
int netxen_rom_fast_read(struct netxen_adapter *adapter, int addr, int *valp);
+int netxen_rom_fast_read_words(struct netxen_adapter *adapter, int addr,
+ u8 *bytes, size_t size);
+int netxen_rom_fast_write_words(struct netxen_adapter *adapter, int addr,
+ u8 *bytes, size_t size);
+int netxen_flash_unlock(struct netxen_adapter *adapter);
+int netxen_backup_crbinit(struct netxen_adapter *adapter);
+int netxen_flash_erase_secondary(struct netxen_adapter *adapter);
+int netxen_flash_erase_primary(struct netxen_adapter *adapter);
+void netxen_halt_pegs(struct netxen_adapter *adapter);
+
int netxen_rom_fast_write(struct netxen_adapter *adapter, int addr, int data);
int netxen_rom_se(struct netxen_adapter *adapter, int addr);
int netxen_do_rom_se(struct netxen_adapter *adapter, int addr);
diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c
index c381d77a733..6252e9a8727 100644
--- a/drivers/net/netxen/netxen_nic_ethtool.c
+++ b/drivers/net/netxen/netxen_nic_ethtool.c
@@ -32,6 +32,7 @@
*/
#include <linux/types.h>
+#include <linux/delay.h>
#include <asm/uaccess.h>
#include <linux/pci.h>
#include <asm/io.h>
@@ -94,17 +95,7 @@ static const char netxen_nic_gstrings_test[][ETH_GSTRING_LEN] = {
static int netxen_nic_get_eeprom_len(struct net_device *dev)
{
- struct netxen_port *port = netdev_priv(dev);
- struct netxen_adapter *adapter = port->adapter;
- int n;
-
- if ((netxen_rom_fast_read(adapter, 0, &n) == 0)
- && (n & NETXEN_ROM_ROUNDUP)) {
- n &= ~NETXEN_ROM_ROUNDUP;
- if (n < NETXEN_MAX_EEPROM_LEN)
- return n;
- }
- return 0;
+ return FLASH_TOTAL_SIZE;
}
static void
@@ -411,7 +402,7 @@ netxen_nic_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
wol->wolopts = 0;
}
-static u32 netxen_nic_get_link(struct net_device *dev)
+static u32 netxen_nic_test_link(struct net_device *dev)
{
struct netxen_port *port = netdev_priv(dev);
struct netxen_adapter *adapter = port->adapter;
@@ -440,18 +431,93 @@ netxen_nic_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
struct netxen_port *port = netdev_priv(dev);
struct netxen_adapter *adapter = port->adapter;
int offset;
+ int ret;
if (eeprom->len == 0)
return -EINVAL;
eeprom->magic = (port->pdev)->vendor | ((port->pdev)->device << 16);
- for (offset = 0; offset < eeprom->len; offset++)
- if (netxen_rom_fast_read
- (adapter, (8 * offset) + 8, (int *)eeprom->data) == -1)
- return -EIO;
+ offset = eeprom->offset;
+
+ ret = netxen_rom_fast_read_words(adapter, offset, bytes,
+ eeprom->len);
+ if (ret < 0)
+ return ret;
+
return 0;
}
+static int
+netxen_nic_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
+ u8 * bytes)
+{
+ struct netxen_port *port = netdev_priv(dev);
+ struct netxen_adapter *adapter = port->adapter;
+ int offset = eeprom->offset;
+ static int flash_start;
+ static int ready_to_flash;
+ int ret;
+
+ if (flash_start == 0) {
+ netxen_halt_pegs(adapter);
+ ret = netxen_flash_unlock(adapter);
+ if (ret < 0) {
+ printk(KERN_ERR "%s: Flash unlock failed.\n",
+ netxen_nic_driver_name);
+ return ret;
+ }
+ printk(KERN_INFO "%s: flash unlocked. \n",
+ netxen_nic_driver_name);
+ ret = netxen_flash_erase_secondary(adapter);
+ if (ret != FLASH_SUCCESS) {
+ printk(KERN_ERR "%s: Flash erase failed.\n",
+ netxen_nic_driver_name);
+ return ret;
+ }
+ printk(KERN_INFO "%s: secondary flash erased successfully.\n",
+ netxen_nic_driver_name);
+ flash_start = 1;
+ return 0;
+ }
+
+ if (offset == BOOTLD_START) {
+ ret = netxen_flash_erase_primary(adapter);
+ if (ret != FLASH_SUCCESS) {
+ printk(KERN_ERR "%s: Flash erase failed.\n",
+ netxen_nic_driver_name);
+ return ret;
+ }
+
+ ret = netxen_rom_se(adapter, USER_START);
+ if (ret != FLASH_SUCCESS)
+ return ret;
+ ret = netxen_rom_se(adapter, FIXED_START);
+ if (ret != FLASH_SUCCESS)
+ return ret;
+
+ printk(KERN_INFO "%s: primary flash erased successfully\n",
+ netxen_nic_driver_name);
+
+ ret = netxen_backup_crbinit(adapter);
+ if (ret != FLASH_SUCCESS) {
+ printk(KERN_ERR "%s: CRBinit backup failed.\n",
+ netxen_nic_driver_name);
+ return ret;
+ }
+ printk(KERN_INFO "%s: CRBinit backup done.\n",
+ netxen_nic_driver_name);
+ ready_to_flash = 1;
+ }
+
+ if (!ready_to_flash) {
+ printk(KERN_ERR "%s: Invalid write sequence, returning...\n",
+ netxen_nic_driver_name);
+ return -EINVAL;
+ }
+
+ return netxen_rom_fast_write_words(adapter, offset, bytes, eeprom->len);
+}
+
static void
netxen_nic_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ring)
{
@@ -647,7 +713,7 @@ netxen_nic_diag_test(struct net_device *dev, struct ethtool_test *eth_test,
{
if (eth_test->flags == ETH_TEST_FL_OFFLINE) { /* offline tests */
/* link test */
- if (!(data[4] = (u64) netxen_nic_get_link(dev)))
+ if (!(data[4] = (u64) netxen_nic_test_link(dev)))
eth_test->flags |= ETH_TEST_FL_FAILED;
if (netif_running(dev))
@@ -662,7 +728,7 @@ netxen_nic_diag_test(struct net_device *dev, struct ethtool_test *eth_test,
dev->open(dev);
} else { /* online tests */
/* link test */
- if (!(data[4] = (u64) netxen_nic_get_link(dev)))
+ if (!(data[4] = (u64) netxen_nic_test_link(dev)))
eth_test->flags |= ETH_TEST_FL_FAILED;
/* other tests pass by default */
@@ -718,9 +784,10 @@ struct ethtool_ops netxen_nic_ethtool_ops = {
.get_regs_len = netxen_nic_get_regs_len,
.get_regs = netxen_nic_get_regs,
.get_wol = netxen_nic_get_wol,
- .get_link = netxen_nic_get_link,
+ .get_link = ethtool_op_get_link,
.get_eeprom_len = netxen_nic_get_eeprom_len,
.get_eeprom = netxen_nic_get_eeprom,
+ .set_eeprom = netxen_nic_set_eeprom,
.get_ringparam = netxen_nic_get_ringparam,
.get_pauseparam = netxen_nic_get_pauseparam,
.set_pauseparam = netxen_nic_set_pauseparam,
diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c
index f263232f499..7195af3e8f3 100644
--- a/drivers/net/netxen/netxen_nic_hw.c
+++ b/drivers/net/netxen/netxen_nic_hw.c
@@ -420,6 +420,7 @@ static int netxen_get_flash_block(struct netxen_adapter *adapter, int base,
for (i = 0; i < size / sizeof(u32); i++) {
if (netxen_rom_fast_read(adapter, addr, ptr32) == -1)
return -1;
+ *ptr32 = cpu_to_le32(*ptr32);
ptr32++;
addr += sizeof(u32);
}
@@ -428,6 +429,7 @@ static int netxen_get_flash_block(struct netxen_adapter *adapter, int base,
if (netxen_rom_fast_read(adapter, addr, &local) == -1)
return -1;
+ local = cpu_to_le32(local);
memcpy(ptr32, &local, (char *)buf + size - (char *)ptr32);
}
diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c
index 973af96337a..2f324366784 100644
--- a/drivers/net/netxen/netxen_nic_init.c
+++ b/drivers/net/netxen/netxen_nic_init.c
@@ -110,6 +110,7 @@ static void crb_addr_transform_setup(void)
crb_addr_transform(CAM);
crb_addr_transform(C2C1);
crb_addr_transform(C2C0);
+ crb_addr_transform(SMB);
}
int netxen_init_firmware(struct netxen_adapter *adapter)
@@ -276,6 +277,7 @@ unsigned long netxen_decode_crb_addr(unsigned long addr)
static long rom_max_timeout = 10000;
static long rom_lock_timeout = 1000000;
+static long rom_write_timeout = 700;
static inline int rom_lock(struct netxen_adapter *adapter)
{
@@ -404,7 +406,7 @@ do_rom_fast_read(struct netxen_adapter *adapter, int addr, int *valp)
{
netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ADDRESS, addr);
netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ABYTE_CNT, 3);
- udelay(100); /* prevent bursting on CRB */
+ udelay(70); /* prevent bursting on CRB */
netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_DUMMY_BYTE_CNT, 0);
netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_INSTR_OPCODE, 0xb);
if (netxen_wait_rom_done(adapter)) {
@@ -413,13 +415,46 @@ do_rom_fast_read(struct netxen_adapter *adapter, int addr, int *valp)
}
/* reset abyte_cnt and dummy_byte_cnt */
netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ABYTE_CNT, 0);
- udelay(100); /* prevent bursting on CRB */
+ udelay(70); /* prevent bursting on CRB */
netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_DUMMY_BYTE_CNT, 0);
*valp = netxen_nic_reg_read(adapter, NETXEN_ROMUSB_ROM_RDATA);
return 0;
}
+static inline int
+do_rom_fast_read_words(struct netxen_adapter *adapter, int addr,
+ u8 *bytes, size_t size)
+{
+ int addridx;
+ int ret = 0;
+
+ for (addridx = addr; addridx < (addr + size); addridx += 4) {
+ ret = do_rom_fast_read(adapter, addridx, (int *)bytes);
+ if (ret != 0)
+ break;
+ bytes += 4;
+ }
+
+ return ret;
+}
+
+int
+netxen_rom_fast_read_words(struct netxen_adapter *adapter, int addr,
+ u8 *bytes, size_t size)
+{
+ int ret;
+
+ ret = rom_lock(adapter);
+ if (ret < 0)
+ return ret;
+
+ ret = do_rom_fast_read_words(adapter, addr, bytes, size);
+
+ netxen_rom_unlock(adapter);
+ return ret;
+}
+
int netxen_rom_fast_read(struct netxen_adapter *adapter, int addr, int *valp)
{
int ret;
@@ -443,6 +478,152 @@ int netxen_rom_fast_write(struct netxen_adapter *adapter, int addr, int data)
netxen_rom_unlock(adapter);
return ret;
}
+
+static inline int do_rom_fast_write_words(struct netxen_adapter *adapter,
+ int addr, u8 *bytes, size_t size)
+{
+ int addridx = addr;
+ int ret = 0;
+
+ while (addridx < (addr + size)) {
+ int last_attempt = 0;
+ int timeout = 0;
+ int data;
+
+ data = *(u32*)bytes;
+
+ ret = do_rom_fast_write(adapter, addridx, data);
+ if (ret < 0)
+ return ret;
+
+ while(1) {
+ int data1;
+
+ do_rom_fast_read(adapter, addridx, &data1);
+ if (data1 == data)
+ break;
+
+ if (timeout++ >= rom_write_timeout) {
+ if (last_attempt++ < 4) {
+ ret = do_rom_fast_write(adapter,
+ addridx, data);
+ if (ret < 0)
+ return ret;
+ }
+ else {
+ printk(KERN_INFO "Data write did not "
+ "succeed at address 0x%x\n", addridx);
+ break;
+ }
+ }
+ }
+
+ bytes += 4;
+ addridx += 4;
+ }
+
+ return ret;
+}
+
+int netxen_rom_fast_write_words(struct netxen_adapter *adapter, int addr,
+ u8 *bytes, size_t size)
+{
+ int ret = 0;
+
+ ret = rom_lock(adapter);
+ if (ret < 0)
+ return ret;
+
+ ret = do_rom_fast_write_words(adapter, addr, bytes, size);
+ netxen_rom_unlock(adapter);
+
+ return ret;
+}
+
+int netxen_rom_wrsr(struct netxen_adapter *adapter, int data)
+{
+ int ret;
+
+ ret = netxen_rom_wren(adapter);
+ if (ret < 0)
+ return ret;
+
+ netxen_crb_writelit_adapter(adapter, NETXEN_ROMUSB_ROM_WDATA, data);
+ netxen_crb_writelit_adapter(adapter,
+ NETXEN_ROMUSB_ROM_INSTR_OPCODE, 0x1);
+
+ ret = netxen_wait_rom_done(adapter);
+ if (ret < 0)
+ return ret;
+
+ return netxen_rom_wip_poll(adapter);
+}
+
+int netxen_rom_rdsr(struct netxen_adapter *adapter)
+{
+ int ret;
+
+ ret = rom_lock(adapter);
+ if (ret < 0)
+ return ret;
+
+ ret = netxen_do_rom_rdsr(adapter);
+ netxen_rom_unlock(adapter);
+ return ret;
+}
+
+int netxen_backup_crbinit(struct netxen_adapter *adapter)
+{
+ int ret = FLASH_SUCCESS;
+ int val;
+ char *buffer = kmalloc(FLASH_SECTOR_SIZE, GFP_KERNEL);
+
+ if (!buffer)
+ return -ENOMEM;
+ /* unlock sector 63 */
+ val = netxen_rom_rdsr(adapter);
+ val = val & 0xe3;
+ ret = netxen_rom_wrsr(adapter, val);
+ if (ret != FLASH_SUCCESS)
+ goto out_kfree;
+
+ ret = netxen_rom_wip_poll(adapter);
+ if (ret != FLASH_SUCCESS)
+ goto out_kfree;
+
+ /* copy sector 0 to sector 63 */
+ ret = netxen_rom_fast_read_words(adapter, CRBINIT_START,
+ buffer, FLASH_SECTOR_SIZE);
+ if (ret != FLASH_SUCCESS)
+ goto out_kfree;
+
+ ret = netxen_rom_fast_write_words(adapter, FIXED_START,
+ buffer, FLASH_SECTOR_SIZE);
+ if (ret != FLASH_SUCCESS)
+ goto out_kfree;
+
+ /* lock sector 63 */
+ val = netxen_rom_rdsr(adapter);
+ if (!(val & 0x8)) {
+ val |= (0x1 << 2);
+ /* lock sector 63 */
+ if (netxen_rom_wrsr(adapter, val) == 0) {
+ ret = netxen_rom_wip_poll(adapter);
+ if (ret != FLASH_SUCCESS)
+ goto out_kfree;
+
+ /* lock SR writes */
+ ret = netxen_rom_wip_poll(adapter);
+ if (ret != FLASH_SUCCESS)
+ goto out_kfree;
+ }
+ }
+
+out_kfree:
+ kfree(buffer);
+ return ret;
+}
+
int netxen_do_rom_se(struct netxen_adapter *adapter, int addr)
{
netxen_rom_wren(adapter);
@@ -457,6 +638,27 @@ int netxen_do_rom_se(struct netxen_adapter *adapter, int addr)
return netxen_rom_wip_poll(adapter);
}
+void check_erased_flash(struct netxen_adapter *adapter, int addr)
+{
+ int i;
+ int val;
+ int count = 0, erased_errors = 0;
+ int range;
+
+ range = (addr == USER_START) ? FIXED_START : addr + FLASH_SECTOR_SIZE;
+
+ for (i = addr; i < range; i += 4) {
+ netxen_rom_fast_read(adapter, i, &val);
+ if (val != 0xffffffff)
+ erased_errors++;
+ count++;
+ }
+
+ if (erased_errors)
+ printk(KERN_INFO "0x%x out of 0x%x words fail to be erased "
+ "for sector address: %x\n", erased_errors, count, addr);
+}
+
int netxen_rom_se(struct netxen_adapter *adapter, int addr)
{
int ret = 0;
@@ -465,6 +667,76 @@ int netxen_rom_se(struct netxen_adapter *adapter, int addr)
}
ret = netxen_do_rom_se(adapter, addr);
netxen_rom_unlock(adapter);
+ msleep(30);
+ check_erased_flash(adapter, addr);
+
+ return ret;
+}
+
+int
+netxen_flash_erase_sections(struct netxen_adapter *adapter, int start, int end)
+{
+ int ret = FLASH_SUCCESS;
+ int i;
+
+ for (i = start; i < end; i++) {
+ ret = netxen_rom_se(adapter, i * FLASH_SECTOR_SIZE);
+ if (ret)
+ break;
+ ret = netxen_rom_wip_poll(adapter);
+ if (ret < 0)
+ return ret;
+ }
+
+ return ret;
+}
+
+int
+netxen_flash_erase_secondary(struct netxen_adapter *adapter)
+{
+ int ret = FLASH_SUCCESS;
+ int start, end;
+
+ start = SECONDARY_START / FLASH_SECTOR_SIZE;
+ end = USER_START / FLASH_SECTOR_SIZE;
+ ret = netxen_flash_erase_sections(adapter, start, end);
+
+ return ret;
+}
+
+int
+netxen_flash_erase_primary(struct netxen_adapter *adapter)
+{
+ int ret = FLASH_SUCCESS;
+ int start, end;
+
+ start = PRIMARY_START / FLASH_SECTOR_SIZE;
+ end = SECONDARY_START / FLASH_SECTOR_SIZE;
+ ret = netxen_flash_erase_sections(adapter, start, end);
+
+ return ret;
+}
+
+void netxen_halt_pegs(struct netxen_adapter *adapter)
+{
+ netxen_crb_writelit_adapter(adapter, NETXEN_CRB_PEG_NET_0 + 0x3c, 1);
+ netxen_crb_writelit_adapter(adapter, NETXEN_CRB_PEG_NET_1 + 0x3c, 1);
+ netxen_crb_writelit_adapter(adapter, NETXEN_CRB_PEG_NET_2 + 0x3c, 1);
+ netxen_crb_writelit_adapter(adapter, NETXEN_CRB_PEG_NET_3 + 0x3c, 1);
+}
+
+int netxen_flash_unlock(struct netxen_adapter *adapter)
+{
+ int ret = 0;
+
+ ret = netxen_rom_wrsr(adapter, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = netxen_rom_wren(adapter);
+ if (ret < 0)
+ return ret;
+
return ret;
}
@@ -543,9 +815,13 @@ int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose)
}
for (i = 0; i < n; i++) {
- off =
- netxen_decode_crb_addr((unsigned long)buf[i].addr) +
- NETXEN_PCI_CRBSPACE;
+ off = netxen_decode_crb_addr((unsigned long)buf[i].addr);
+ if (off == NETXEN_ADDR_ERROR) {
+ printk(KERN_ERR"CRB init value out of range %lx\n",
+ buf[i].addr);
+ continue;
+ }
+ off += NETXEN_PCI_CRBSPACE;
/* skipping cold reboot MAGIC */
if (off == NETXEN_CAM_RAM(0x1fc))
continue;
@@ -662,6 +938,7 @@ void netxen_phantom_init(struct netxen_adapter *adapter, int pegtune_val)
int loops = 0;
if (!pegtune_val) {
+ val = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE));
while (val != PHAN_INITIALIZE_COMPLETE && loops < 200000) {
udelay(100);
schedule();
@@ -977,7 +1254,7 @@ int netxen_process_cmd_ring(unsigned long data)
* the netdev which is associated with that device.
*/
- consumer = *(adapter->cmd_consumer);
+ consumer = le32_to_cpu(*(adapter->cmd_consumer));
if (last_consumer == consumer) { /* Ring is empty */
DPRINTK(INFO, "last_consumer %d == consumer %d\n",
last_consumer, consumer);
@@ -1071,7 +1348,7 @@ int netxen_process_cmd_ring(unsigned long data)
if (adapter->last_cmd_consumer == consumer &&
(((adapter->cmd_producer + 1) %
adapter->max_tx_desc_count) == adapter->last_cmd_consumer)) {
- consumer = *(adapter->cmd_consumer);
+ consumer = le32_to_cpu(*(adapter->cmd_consumer));
}
done = (adapter->last_cmd_consumer == consumer);
diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c
index 69c1b9d23a1..225ff55527c 100644
--- a/drivers/net/netxen/netxen_nic_main.c
+++ b/drivers/net/netxen/netxen_nic_main.c
@@ -434,12 +434,13 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
adapter->port_count++;
adapter->port[i] = port;
}
-
+#ifndef CONFIG_PPC64
writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE));
netxen_pinit_from_rom(adapter, 0);
udelay(500);
netxen_load_firmware(adapter);
netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE);
+#endif
/*
* delay a while to ensure that the Pegs are up & running.
* Otherwise, we might see some flaky behaviour.
@@ -619,8 +620,8 @@ static int netxen_nic_open(struct net_device *netdev)
}
adapter->irq = adapter->ahw.pdev->irq;
err = request_irq(adapter->ahw.pdev->irq, &netxen_intr,
- SA_SHIRQ | SA_SAMPLE_RANDOM, netdev->name,
- adapter);
+ IRQF_SHARED | IRQF_SAMPLE_RANDOM,
+ netdev->name, adapter);
if (err) {
printk(KERN_ERR "request_irq failed with: %d\n", err);
netxen_free_hw_resources(adapter);
diff --git a/drivers/net/netxen/netxen_nic_niu.c b/drivers/net/netxen/netxen_nic_niu.c
index 40d7003a371..d5d95074e56 100644
--- a/drivers/net/netxen/netxen_nic_niu.c
+++ b/drivers/net/netxen/netxen_nic_niu.c
@@ -458,7 +458,7 @@ int netxen_niu_gbe_init_port(struct netxen_adapter *adapter, int port)
int netxen_niu_xg_init_port(struct netxen_adapter *adapter, int port)
{
- long reg = 0, ret = 0;
+ u32 reg = 0, ret = 0;
if (adapter->ahw.boardcfg.board_type == NETXEN_BRDTYPE_P2_SB31_10G_IMEZ) {
netxen_crb_writelit_adapter(adapter,
diff --git a/drivers/net/oaknet.c b/drivers/net/oaknet.c
deleted file mode 100644
index 702e3e95612..00000000000
--- a/drivers/net/oaknet.c
+++ /dev/null
@@ -1,666 +0,0 @@
-/*
- *
- * Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
- *
- * Module name: oaknet.c
- *
- * Description:
- * Driver for the National Semiconductor DP83902AV Ethernet controller
- * on-board the IBM PowerPC "Oak" evaluation board. Adapted from the
- * various other 8390 drivers written by Donald Becker and Paul Gortmaker.
- *
- * Additional inspiration from the "tcd8390.c" driver from TiVo, Inc.
- * and "enetLib.c" from IBM.
- *
- */
-
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/delay.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/init.h>
-#include <linux/jiffies.h>
-
-#include <asm/board.h>
-#include <asm/io.h>
-
-#include "8390.h"
-
-
-/* Preprocessor Defines */
-
-#if !defined(TRUE) || TRUE != 1
-#define TRUE 1
-#endif
-
-#if !defined(FALSE) || FALSE != 0
-#define FALSE 0
-#endif
-
-#define OAKNET_START_PG 0x20 /* First page of TX buffer */
-#define OAKNET_STOP_PG 0x40 /* Last pagge +1 of RX ring */
-
-#define OAKNET_WAIT (2 * HZ / 100) /* 20 ms */
-
-/* Experimenting with some fixes for a broken driver... */
-
-#define OAKNET_DISINT
-#define OAKNET_HEADCHECK
-#define OAKNET_RWFIX
-
-
-/* Global Variables */
-
-static const char *name = "National DP83902AV";
-
-static struct net_device *oaknet_devs;
-
-
-/* Function Prototypes */
-
-static int oaknet_open(struct net_device *dev);
-static int oaknet_close(struct net_device *dev);
-
-static void oaknet_reset_8390(struct net_device *dev);
-static void oaknet_get_8390_hdr(struct net_device *dev,
- struct e8390_pkt_hdr *hdr, int ring_page);
-static void oaknet_block_input(struct net_device *dev, int count,
- struct sk_buff *skb, int ring_offset);
-static void oaknet_block_output(struct net_device *dev, int count,
- const unsigned char *buf, int start_page);
-
-static void oaknet_dma_error(struct net_device *dev, const char *name);
-
-
-/*
- * int oaknet_init()
- *
- * Description:
- * This routine performs all the necessary platform-specific initiali-
- * zation and set-up for the IBM "Oak" evaluation board's National
- * Semiconductor DP83902AV "ST-NIC" Ethernet controller.
- *
- * Input(s):
- * N/A
- *
- * Output(s):
- * N/A
- *
- * Returns:
- * 0 if OK, otherwise system error number on error.
- *
- */
-static int __init oaknet_init(void)
-{
- register int i;
- int reg0, regd;
- int ret = -ENOMEM;
- struct net_device *dev;
-#if 0
- unsigned long ioaddr = OAKNET_IO_BASE;
-#else
- unsigned long ioaddr = ioremap(OAKNET_IO_BASE, OAKNET_IO_SIZE);
-#endif
- bd_t *bip = (bd_t *)__res;
-
- if (!ioaddr)
- return -ENOMEM;
-
- dev = alloc_ei_netdev();
- if (!dev)
- goto out_unmap;
-
- ret = -EBUSY;
- if (!request_region(OAKNET_IO_BASE, OAKNET_IO_SIZE, name))
- goto out_dev;
-
- /* Quick register check to see if the device is really there. */
-
- ret = -ENODEV;
- if ((reg0 = ei_ibp(ioaddr)) == 0xFF)
- goto out_region;
-
- /*
- * That worked. Now a more thorough check, using the multicast
- * address registers, that the device is definitely out there
- * and semi-functional.
- */
-
- ei_obp(E8390_NODMA + E8390_PAGE1 + E8390_STOP, ioaddr + E8390_CMD);
- regd = ei_ibp(ioaddr + 0x0D);
- ei_obp(0xFF, ioaddr + 0x0D);
- ei_obp(E8390_NODMA + E8390_PAGE0, ioaddr + E8390_CMD);
- ei_ibp(ioaddr + EN0_COUNTER0);
-
- /* It's no good. Fix things back up and leave. */
-
- ret = -ENODEV;
- if (ei_ibp(ioaddr + EN0_COUNTER0) != 0) {
- ei_obp(reg0, ioaddr);
- ei_obp(regd, ioaddr + 0x0D);
- goto out_region;
- }
-
- SET_MODULE_OWNER(dev);
-
- /*
- * This controller is on an embedded board, so the base address
- * and interrupt assignments are pre-assigned and unchageable.
- */
-
- dev->base_addr = ioaddr;
- dev->irq = OAKNET_INT;
-
- /*
- * Disable all chip interrupts for now and ACK all pending
- * interrupts.
- */
-
- ei_obp(0x0, ioaddr + EN0_IMR);
- ei_obp(0xFF, ioaddr + EN0_ISR);
-
- /* Attempt to get the interrupt line */
-
- ret = -EAGAIN;
- if (request_irq(dev->irq, ei_interrupt, 0, name, dev)) {
- printk("%s: unable to request interrupt %d.\n",
- name, dev->irq);
- goto out_region;
- }
-
- /* Tell the world about what and where we've found. */
-
- printk("%s: %s at", dev->name, name);
- for (i = 0; i < ETHER_ADDR_LEN; ++i) {
- dev->dev_addr[i] = bip->bi_enetaddr[i];
- printk("%c%.2x", (i ? ':' : ' '), dev->dev_addr[i]);
- }
- printk(", found at %#lx, using IRQ %d.\n", dev->base_addr, dev->irq);
-
- /* Set up some required driver fields and then we're done. */
-
- ei_status.name = name;
- ei_status.word16 = FALSE;
- ei_status.tx_start_page = OAKNET_START_PG;
- ei_status.rx_start_page = OAKNET_START_PG + TX_PAGES;
- ei_status.stop_page = OAKNET_STOP_PG;
-
- ei_status.reset_8390 = &oaknet_reset_8390;
- ei_status.block_input = &oaknet_block_input;
- ei_status.block_output = &oaknet_block_output;
- ei_status.get_8390_hdr = &oaknet_get_8390_hdr;
-
- dev->open = oaknet_open;
- dev->stop = oaknet_close;
-#ifdef CONFIG_NET_POLL_CONTROLLER
- dev->poll_controller = ei_poll;
-#endif
-
- NS8390_init(dev, FALSE);
- ret = register_netdev(dev);
- if (ret)
- goto out_irq;
-
- oaknet_devs = dev;
- return 0;
-
-out_irq;
- free_irq(dev->irq, dev);
-out_region:
- release_region(OAKNET_IO_BASE, OAKNET_IO_SIZE);
-out_dev:
- free_netdev(dev);
-out_unmap:
- iounmap(ioaddr);
- return ret;
-}
-
-/*
- * static int oaknet_open()
- *
- * Description:
- * This routine is a modest wrapper around ei_open, the 8390-generic,
- * driver open routine. This just increments the module usage count
- * and passes along the status from ei_open.
- *
- * Input(s):
- * *dev - Pointer to the device structure for this driver.
- *
- * Output(s):
- * *dev - Pointer to the device structure for this driver, potentially
- * modified by ei_open.
- *
- * Returns:
- * 0 if OK, otherwise < 0 on error.
- *
- */
-static int
-oaknet_open(struct net_device *dev)
-{
- int status = ei_open(dev);
- return (status);
-}
-
-/*
- * static int oaknet_close()
- *
- * Description:
- * This routine is a modest wrapper around ei_close, the 8390-generic,
- * driver close routine. This just decrements the module usage count
- * and passes along the status from ei_close.
- *
- * Input(s):
- * *dev - Pointer to the device structure for this driver.
- *
- * Output(s):
- * *dev - Pointer to the device structure for this driver, potentially
- * modified by ei_close.
- *
- * Returns:
- * 0 if OK, otherwise < 0 on error.
- *
- */
-static int
-oaknet_close(struct net_device *dev)
-{
- int status = ei_close(dev);
- return (status);
-}
-
-/*
- * static void oaknet_reset_8390()
- *
- * Description:
- * This routine resets the DP83902 chip.
- *
- * Input(s):
- * *dev - Pointer to the device structure for this driver.
- *
- * Output(s):
- * N/A
- *
- * Returns:
- * N/A
- *
- */
-static void
-oaknet_reset_8390(struct net_device *dev)
-{
- int base = E8390_BASE;
-
- /*
- * We have no provision of reseting the controller as is done
- * in other drivers, such as "ne.c". However, the following
- * seems to work well enough in the TiVo driver.
- */
-
- printk("Resetting %s...\n", dev->name);
- ei_obp(E8390_STOP | E8390_NODMA | E8390_PAGE0, base + E8390_CMD);
- ei_status.txing = 0;
- ei_status.dmaing = 0;
-}
-
-/*
- * static void oaknet_get_8390_hdr()
- *
- * Description:
- * This routine grabs the 8390-specific header. It's similar to the
- * block input routine, but we don't need to be concerned with ring wrap
- * as the header will be at the start of a page, so we optimize accordingly.
- *
- * Input(s):
- * *dev - Pointer to the device structure for this driver.
- * *hdr - Pointer to storage for the 8390-specific packet header.
- * ring_page - ?
- *
- * Output(s):
- * *hdr - Pointer to the 8390-specific packet header for the just-
- * received frame.
- *
- * Returns:
- * N/A
- *
- */
-static void
-oaknet_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
- int ring_page)
-{
- int base = dev->base_addr;
-
- /*
- * This should NOT happen. If it does, it is the LAST thing you'll
- * see.
- */
-
- if (ei_status.dmaing) {
- oaknet_dma_error(dev, "oaknet_get_8390_hdr");
- return;
- }
-
- ei_status.dmaing |= 0x01;
- outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START, base + OAKNET_CMD);
- outb_p(sizeof(struct e8390_pkt_hdr), base + EN0_RCNTLO);
- outb_p(0, base + EN0_RCNTHI);
- outb_p(0, base + EN0_RSARLO); /* On page boundary */
- outb_p(ring_page, base + EN0_RSARHI);
- outb_p(E8390_RREAD + E8390_START, base + OAKNET_CMD);
-
- if (ei_status.word16)
- insw(base + OAKNET_DATA, hdr,
- sizeof(struct e8390_pkt_hdr) >> 1);
- else
- insb(base + OAKNET_DATA, hdr,
- sizeof(struct e8390_pkt_hdr));
-
- /* Byte-swap the packet byte count */
-
- hdr->count = le16_to_cpu(hdr->count);
-
- outb_p(ENISR_RDC, base + EN0_ISR); /* ACK Remote DMA interrupt */
- ei_status.dmaing &= ~0x01;
-}
-
-/*
- * XXX - Document me.
- */
-static void
-oaknet_block_input(struct net_device *dev, int count, struct sk_buff *skb,
- int ring_offset)
-{
- int base = OAKNET_BASE;
- char *buf = skb->data;
-
- /*
- * This should NOT happen. If it does, it is the LAST thing you'll
- * see.
- */
-
- if (ei_status.dmaing) {
- oaknet_dma_error(dev, "oaknet_block_input");
- return;
- }
-
-#ifdef OAKNET_DISINT
- save_flags(flags);
- cli();
-#endif
-
- ei_status.dmaing |= 0x01;
- ei_obp(E8390_NODMA + E8390_PAGE0 + E8390_START, base + E8390_CMD);
- ei_obp(count & 0xff, base + EN0_RCNTLO);
- ei_obp(count >> 8, base + EN0_RCNTHI);
- ei_obp(ring_offset & 0xff, base + EN0_RSARLO);
- ei_obp(ring_offset >> 8, base + EN0_RSARHI);
- ei_obp(E8390_RREAD + E8390_START, base + E8390_CMD);
- if (ei_status.word16) {
- ei_isw(base + E8390_DATA, buf, count >> 1);
- if (count & 0x01) {
- buf[count - 1] = ei_ib(base + E8390_DATA);
-#ifdef OAKNET_HEADCHECK
- bytes++;
-#endif
- }
- } else {
- ei_isb(base + E8390_DATA, buf, count);
- }
-#ifdef OAKNET_HEADCHECK
- /*
- * This was for the ALPHA version only, but enough people have
- * been encountering problems so it is still here. If you see
- * this message you either 1) have a slightly incompatible clone
- * or 2) have noise/speed problems with your bus.
- */
-
- /* DMA termination address check... */
- {
- int addr, tries = 20;
- do {
- /* DON'T check for 'ei_ibp(EN0_ISR) & ENISR_RDC' here
- -- it's broken for Rx on some cards! */
- int high = ei_ibp(base + EN0_RSARHI);
- int low = ei_ibp(base + EN0_RSARLO);
- addr = (high << 8) + low;
- if (((ring_offset + bytes) & 0xff) == low)
- break;
- } while (--tries > 0);
- if (tries <= 0)
- printk("%s: RX transfer address mismatch,"
- "%#4.4x (expected) vs. %#4.4x (actual).\n",
- dev->name, ring_offset + bytes, addr);
- }
-#endif
- ei_obp(ENISR_RDC, base + EN0_ISR); /* ACK Remote DMA interrupt */
- ei_status.dmaing &= ~0x01;
-
-#ifdef OAKNET_DISINT
- restore_flags(flags);
-#endif
-}
-
-/*
- * static void oaknet_block_output()
- *
- * Description:
- * This routine...
- *
- * Input(s):
- * *dev - Pointer to the device structure for this driver.
- * count - Number of bytes to be transferred.
- * *buf -
- * start_page -
- *
- * Output(s):
- * N/A
- *
- * Returns:
- * N/A
- *
- */
-static void
-oaknet_block_output(struct net_device *dev, int count,
- const unsigned char *buf, int start_page)
-{
- int base = E8390_BASE;
-#if 0
- int bug;
-#endif
- unsigned long start;
-#ifdef OAKNET_DISINT
- unsigned long flags;
-#endif
-#ifdef OAKNET_HEADCHECK
- int retries = 0;
-#endif
-
- /* Round the count up for word writes. */
-
- if (ei_status.word16 && (count & 0x1))
- count++;
-
- /*
- * This should NOT happen. If it does, it is the LAST thing you'll
- * see.
- */
-
- if (ei_status.dmaing) {
- oaknet_dma_error(dev, "oaknet_block_output");
- return;
- }
-
-#ifdef OAKNET_DISINT
- save_flags(flags);
- cli();
-#endif
-
- ei_status.dmaing |= 0x01;
-
- /* Make sure we are in page 0. */
-
- ei_obp(E8390_PAGE0 + E8390_START + E8390_NODMA, base + E8390_CMD);
-
-#ifdef OAKNET_HEADCHECK
-retry:
-#endif
-
-#if 0
- /*
- * The 83902 documentation states that the processor needs to
- * do a "dummy read" before doing the remote write to work
- * around a chip bug they don't feel like fixing.
- */
-
- bug = 0;
- while (1) {
- unsigned int rdhi;
- unsigned int rdlo;
-
- /* Now the normal output. */
- ei_obp(ENISR_RDC, base + EN0_ISR);
- ei_obp(count & 0xff, base + EN0_RCNTLO);
- ei_obp(count >> 8, base + EN0_RCNTHI);
- ei_obp(0x00, base + EN0_RSARLO);
- ei_obp(start_page, base + EN0_RSARHI);
-
- if (bug++)
- break;
-
- /* Perform the dummy read */
- rdhi = ei_ibp(base + EN0_CRDAHI);
- rdlo = ei_ibp(base + EN0_CRDALO);
- ei_obp(E8390_RREAD + E8390_START, base + E8390_CMD);
-
- while (1) {
- unsigned int nrdhi;
- unsigned int nrdlo;
- nrdhi = ei_ibp(base + EN0_CRDAHI);
- nrdlo = ei_ibp(base + EN0_CRDALO);
- if ((rdhi != nrdhi) || (rdlo != nrdlo))
- break;
- }
- }
-#else
-#ifdef OAKNET_RWFIX
- /*
- * Handle the read-before-write bug the same way as the
- * Crynwr packet driver -- the Nat'l Semi. method doesn't work.
- * Actually this doesn't always work either, but if you have
- * problems with your 83902 this is better than nothing!
- */
-
- ei_obp(0x42, base + EN0_RCNTLO);
- ei_obp(0x00, base + EN0_RCNTHI);
- ei_obp(0x42, base + EN0_RSARLO);
- ei_obp(0x00, base + EN0_RSARHI);
- ei_obp(E8390_RREAD + E8390_START, base + E8390_CMD);
- /* Make certain that the dummy read has occurred. */
- udelay(6);
-#endif
-
- ei_obp(ENISR_RDC, base + EN0_ISR);
-
- /* Now the normal output. */
- ei_obp(count & 0xff, base + EN0_RCNTLO);
- ei_obp(count >> 8, base + EN0_RCNTHI);
- ei_obp(0x00, base + EN0_RSARLO);
- ei_obp(start_page, base + EN0_RSARHI);
-#endif /* 0/1 */
-
- ei_obp(E8390_RWRITE + E8390_START, base + E8390_CMD);
- if (ei_status.word16) {
- ei_osw(E8390_BASE + E8390_DATA, buf, count >> 1);
- } else {
- ei_osb(E8390_BASE + E8390_DATA, buf, count);
- }
-
-#ifdef OAKNET_DISINT
- restore_flags(flags);
-#endif
-
- start = jiffies;
-
-#ifdef OAKNET_HEADCHECK
- /*
- * This was for the ALPHA version only, but enough people have
- * been encountering problems so it is still here.
- */
-
- {
- /* DMA termination address check... */
- int addr, tries = 20;
- do {
- int high = ei_ibp(base + EN0_RSARHI);
- int low = ei_ibp(base + EN0_RSARLO);
- addr = (high << 8) + low;
- if ((start_page << 8) + count == addr)
- break;
- } while (--tries > 0);
-
- if (tries <= 0) {
- printk("%s: Tx packet transfer address mismatch,"
- "%#4.4x (expected) vs. %#4.4x (actual).\n",
- dev->name, (start_page << 8) + count, addr);
- if (retries++ == 0)
- goto retry;
- }
- }
-#endif
-
- while ((ei_ibp(base + EN0_ISR) & ENISR_RDC) == 0) {
- if (time_after(jiffies, start + OAKNET_WAIT)) {
- printk("%s: timeout waiting for Tx RDC.\n", dev->name);
- oaknet_reset_8390(dev);
- NS8390_init(dev, TRUE);
- break;
- }
- }
-
- ei_obp(ENISR_RDC, base + EN0_ISR); /* Ack intr. */
- ei_status.dmaing &= ~0x01;
-}
-
-/*
- * static void oaknet_dma_error()
- *
- * Description:
- * This routine prints out a last-ditch informative message to the console
- * indicating that a DMA error occurred. If you see this, it's the last
- * thing you'll see.
- *
- * Input(s):
- * *dev - Pointer to the device structure for this driver.
- * *name - Informative text (e.g. function name) indicating where the
- * DMA error occurred.
- *
- * Output(s):
- * N/A
- *
- * Returns:
- * N/A
- *
- */
-static void
-oaknet_dma_error(struct net_device *dev, const char *name)
-{
- printk(KERN_EMERG "%s: DMAing conflict in %s."
- "[DMAstat:%d][irqlock:%d][intr:%ld]\n",
- dev->name, name, ei_status.dmaing, ei_status.irqlock,
- dev->interrupt);
-}
-
-/*
- * Oak Ethernet module unload interface.
- */
-static void __exit oaknet_cleanup_module (void)
-{
- /* Convert to loop once driver supports multiple devices. */
- unregister_netdev(oaknet_dev);
- free_irq(oaknet_devs->irq, oaknet_devs);
- release_region(oaknet_devs->base_addr, OAKNET_IO_SIZE);
- iounmap(ioaddr);
- free_netdev(oaknet_devs);
-}
-
-module_init(oaknet_init);
-module_exit(oaknet_cleanup_module);
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c
new file mode 100644
index 00000000000..d670ac74824
--- /dev/null
+++ b/drivers/net/pasemi_mac.c
@@ -0,0 +1,1019 @@
+/*
+ * Copyright (C) 2006-2007 PA Semi, Inc
+ *
+ * Driver for the PA Semi PWRficient onchip 1G/10G Ethernet MACs
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/dmaengine.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <asm/dma-mapping.h>
+#include <linux/in.h>
+#include <linux/skbuff.h>
+
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <net/checksum.h>
+
+#include "pasemi_mac.h"
+
+
+/* TODO list
+ *
+ * - Get rid of pci_{read,write}_config(), map registers with ioremap
+ * for performance
+ * - PHY support
+ * - Multicast support
+ * - Large MTU support
+ * - Other performance improvements
+ */
+
+
+/* Must be a power of two */
+#define RX_RING_SIZE 512
+#define TX_RING_SIZE 512
+
+#define TX_DESC(mac, num) ((mac)->tx->desc[(num) & (TX_RING_SIZE-1)])
+#define TX_DESC_INFO(mac, num) ((mac)->tx->desc_info[(num) & (TX_RING_SIZE-1)])
+#define RX_DESC(mac, num) ((mac)->rx->desc[(num) & (RX_RING_SIZE-1)])
+#define RX_DESC_INFO(mac, num) ((mac)->rx->desc_info[(num) & (RX_RING_SIZE-1)])
+#define RX_BUFF(mac, num) ((mac)->rx->buffers[(num) & (RX_RING_SIZE-1)])
+
+#define BUF_SIZE 1646 /* 1500 MTU + ETH_HLEN + VLAN_HLEN + 2 64B cachelines */
+
+/* XXXOJN these should come out of the device tree some day */
+#define PAS_DMA_CAP_BASE 0xe00d0040
+#define PAS_DMA_CAP_SIZE 0x100
+#define PAS_DMA_COM_BASE 0xe00d0100
+#define PAS_DMA_COM_SIZE 0x100
+
+static struct pasdma_status *dma_status;
+
+static int pasemi_get_mac_addr(struct pasemi_mac *mac)
+{
+ struct pci_dev *pdev = mac->pdev;
+ struct device_node *dn = pci_device_to_OF_node(pdev);
+ const u8 *maddr;
+ u8 addr[6];
+
+ if (!dn) {
+ dev_dbg(&pdev->dev,
+ "No device node for mac, not configuring\n");
+ return -ENOENT;
+ }
+
+ maddr = get_property(dn, "mac-address", NULL);
+ if (maddr == NULL) {
+ dev_warn(&pdev->dev,
+ "no mac address in device tree, not configuring\n");
+ return -ENOENT;
+ }
+
+ if (sscanf(maddr, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &addr[0],
+ &addr[1], &addr[2], &addr[3], &addr[4], &addr[5]) != 6) {
+ dev_warn(&pdev->dev,
+ "can't parse mac address, not configuring\n");
+ return -EINVAL;
+ }
+
+ memcpy(mac->mac_addr, addr, sizeof(addr));
+ return 0;
+}
+
+static int pasemi_mac_setup_rx_resources(struct net_device *dev)
+{
+ struct pasemi_mac_rxring *ring;
+ struct pasemi_mac *mac = netdev_priv(dev);
+ int chan_id = mac->dma_rxch;
+
+ ring = kzalloc(sizeof(*ring), GFP_KERNEL);
+
+ if (!ring)
+ goto out_ring;
+
+ spin_lock_init(&ring->lock);
+
+ ring->desc_info = kzalloc(sizeof(struct pasemi_mac_buffer) *
+ RX_RING_SIZE, GFP_KERNEL);
+
+ if (!ring->desc_info)
+ goto out_desc_info;
+
+ /* Allocate descriptors */
+ ring->desc = dma_alloc_coherent(&mac->dma_pdev->dev,
+ RX_RING_SIZE *
+ sizeof(struct pas_dma_xct_descr),
+ &ring->dma, GFP_KERNEL);
+
+ if (!ring->desc)
+ goto out_desc;
+
+ memset(ring->desc, 0, RX_RING_SIZE * sizeof(struct pas_dma_xct_descr));
+
+ ring->buffers = dma_alloc_coherent(&mac->dma_pdev->dev,
+ RX_RING_SIZE * sizeof(u64),
+ &ring->buf_dma, GFP_KERNEL);
+ if (!ring->buffers)
+ goto out_buffers;
+
+ memset(ring->buffers, 0, RX_RING_SIZE * sizeof(u64));
+
+ pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXCHAN_BASEL(chan_id),
+ PAS_DMA_RXCHAN_BASEL_BRBL(ring->dma));
+
+ pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXCHAN_BASEU(chan_id),
+ PAS_DMA_RXCHAN_BASEU_BRBH(ring->dma >> 32) |
+ PAS_DMA_RXCHAN_BASEU_SIZ(RX_RING_SIZE >> 2));
+
+ pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXCHAN_CFG(chan_id),
+ PAS_DMA_RXCHAN_CFG_HBU(1));
+
+ pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXINT_BASEL(mac->dma_if),
+ PAS_DMA_RXINT_BASEL_BRBL(__pa(ring->buffers)));
+
+ pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXINT_BASEU(mac->dma_if),
+ PAS_DMA_RXINT_BASEU_BRBH(__pa(ring->buffers) >> 32) |
+ PAS_DMA_RXINT_BASEU_SIZ(RX_RING_SIZE >> 3));
+
+ ring->next_to_fill = 0;
+ ring->next_to_clean = 0;
+
+ snprintf(ring->irq_name, sizeof(ring->irq_name),
+ "%s rx", dev->name);
+ mac->rx = ring;
+
+ return 0;
+
+out_buffers:
+ dma_free_coherent(&mac->dma_pdev->dev,
+ RX_RING_SIZE * sizeof(struct pas_dma_xct_descr),
+ mac->rx->desc, mac->rx->dma);
+out_desc:
+ kfree(ring->desc_info);
+out_desc_info:
+ kfree(ring);
+out_ring:
+ return -ENOMEM;
+}
+
+
+static int pasemi_mac_setup_tx_resources(struct net_device *dev)
+{
+ struct pasemi_mac *mac = netdev_priv(dev);
+ u32 val;
+ int chan_id = mac->dma_txch;
+ struct pasemi_mac_txring *ring;
+
+ ring = kzalloc(sizeof(*ring), GFP_KERNEL);
+ if (!ring)
+ goto out_ring;
+
+ spin_lock_init(&ring->lock);
+
+ ring->desc_info = kzalloc(sizeof(struct pasemi_mac_buffer) *
+ TX_RING_SIZE, GFP_KERNEL);
+ if (!ring->desc_info)
+ goto out_desc_info;
+
+ /* Allocate descriptors */
+ ring->desc = dma_alloc_coherent(&mac->dma_pdev->dev,
+ TX_RING_SIZE *
+ sizeof(struct pas_dma_xct_descr),
+ &ring->dma, GFP_KERNEL);
+ if (!ring->desc)
+ goto out_desc;
+
+ memset(ring->desc, 0, TX_RING_SIZE * sizeof(struct pas_dma_xct_descr));
+
+ pci_write_config_dword(mac->dma_pdev, PAS_DMA_TXCHAN_BASEL(chan_id),
+ PAS_DMA_TXCHAN_BASEL_BRBL(ring->dma));
+ val = PAS_DMA_TXCHAN_BASEU_BRBH(ring->dma >> 32);
+ val |= PAS_DMA_TXCHAN_BASEU_SIZ(TX_RING_SIZE >> 2);
+
+ pci_write_config_dword(mac->dma_pdev, PAS_DMA_TXCHAN_BASEU(chan_id), val);
+
+ pci_write_config_dword(mac->dma_pdev, PAS_DMA_TXCHAN_CFG(chan_id),
+ PAS_DMA_TXCHAN_CFG_TY_IFACE |
+ PAS_DMA_TXCHAN_CFG_TATTR(mac->dma_if) |
+ PAS_DMA_TXCHAN_CFG_UP |
+ PAS_DMA_TXCHAN_CFG_WT(2));
+
+ ring->next_to_use = 0;
+ ring->next_to_clean = 0;
+
+ snprintf(ring->irq_name, sizeof(ring->irq_name),
+ "%s tx", dev->name);
+ mac->tx = ring;
+
+ return 0;
+
+out_desc:
+ kfree(ring->desc_info);
+out_desc_info:
+ kfree(ring);
+out_ring:
+ return -ENOMEM;
+}
+
+static void pasemi_mac_free_tx_resources(struct net_device *dev)
+{
+ struct pasemi_mac *mac = netdev_priv(dev);
+ unsigned int i;
+ struct pasemi_mac_buffer *info;
+ struct pas_dma_xct_descr *dp;
+
+ for (i = 0; i < TX_RING_SIZE; i++) {
+ info = &TX_DESC_INFO(mac, i);
+ dp = &TX_DESC(mac, i);
+ if (info->dma) {
+ if (info->skb) {
+ pci_unmap_single(mac->dma_pdev,
+ info->dma,
+ info->skb->len,
+ PCI_DMA_TODEVICE);
+ dev_kfree_skb_any(info->skb);
+ }
+ info->dma = 0;
+ info->skb = NULL;
+ dp->mactx = 0;
+ dp->ptr = 0;
+ }
+ }
+
+ dma_free_coherent(&mac->dma_pdev->dev,
+ TX_RING_SIZE * sizeof(struct pas_dma_xct_descr),
+ mac->tx->desc, mac->tx->dma);
+
+ kfree(mac->tx->desc_info);
+ kfree(mac->tx);
+ mac->tx = NULL;
+}
+
+static void pasemi_mac_free_rx_resources(struct net_device *dev)
+{
+ struct pasemi_mac *mac = netdev_priv(dev);
+ unsigned int i;
+ struct pasemi_mac_buffer *info;
+ struct pas_dma_xct_descr *dp;
+
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ info = &RX_DESC_INFO(mac, i);
+ dp = &RX_DESC(mac, i);
+ if (info->dma) {
+ if (info->skb) {
+ pci_unmap_single(mac->dma_pdev,
+ info->dma,
+ info->skb->len,
+ PCI_DMA_FROMDEVICE);
+ dev_kfree_skb_any(info->skb);
+ }
+ info->dma = 0;
+ info->skb = NULL;
+ dp->macrx = 0;
+ dp->ptr = 0;
+ }
+ }
+
+ dma_free_coherent(&mac->dma_pdev->dev,
+ RX_RING_SIZE * sizeof(struct pas_dma_xct_descr),
+ mac->rx->desc, mac->rx->dma);
+
+ dma_free_coherent(&mac->dma_pdev->dev, RX_RING_SIZE * sizeof(u64),
+ mac->rx->buffers, mac->rx->buf_dma);
+
+ kfree(mac->rx->desc_info);
+ kfree(mac->rx);
+ mac->rx = NULL;
+}
+
+static void pasemi_mac_replenish_rx_ring(struct net_device *dev)
+{
+ struct pasemi_mac *mac = netdev_priv(dev);
+ unsigned int i;
+ int start = mac->rx->next_to_fill;
+ unsigned int count;
+
+ count = (mac->rx->next_to_clean + RX_RING_SIZE -
+ mac->rx->next_to_fill) & (RX_RING_SIZE - 1);
+
+ /* Check to see if we're doing first-time setup */
+ if (unlikely(mac->rx->next_to_clean == 0 && mac->rx->next_to_fill == 0))
+ count = RX_RING_SIZE;
+
+ if (count <= 0)
+ return;
+
+ for (i = start; i < start + count; i++) {
+ struct pasemi_mac_buffer *info = &RX_DESC_INFO(mac, i);
+ u64 *buff = &RX_BUFF(mac, i);
+ struct sk_buff *skb;
+ dma_addr_t dma;
+
+ skb = dev_alloc_skb(BUF_SIZE);
+
+ if (!skb) {
+ count = i - start;
+ break;
+ }
+
+ skb->dev = dev;
+
+ dma = pci_map_single(mac->dma_pdev, skb->data, skb->len,
+ PCI_DMA_FROMDEVICE);
+
+ if (dma_mapping_error(dma)) {
+ dev_kfree_skb_irq(info->skb);
+ count = i - start;
+ break;
+ }
+
+ info->skb = skb;
+ info->dma = dma;
+ *buff = XCT_RXB_LEN(BUF_SIZE) | XCT_RXB_ADDR(dma);
+ }
+
+ wmb();
+
+ pci_write_config_dword(mac->dma_pdev,
+ PAS_DMA_RXCHAN_INCR(mac->dma_rxch),
+ count);
+ pci_write_config_dword(mac->dma_pdev,
+ PAS_DMA_RXINT_INCR(mac->dma_if),
+ count);
+
+ mac->rx->next_to_fill += count;
+}
+
+static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit)
+{
+ unsigned int i;
+ int start, count;
+
+ spin_lock(&mac->rx->lock);
+
+ start = mac->rx->next_to_clean;
+ count = 0;
+
+ for (i = start; i < (start + RX_RING_SIZE) && count < limit; i++) {
+ struct pas_dma_xct_descr *dp;
+ struct pasemi_mac_buffer *info;
+ struct sk_buff *skb;
+ unsigned int j, len;
+ dma_addr_t dma;
+
+ rmb();
+
+ dp = &RX_DESC(mac, i);
+
+ if (!(dp->macrx & XCT_MACRX_O))
+ break;
+
+ count++;
+
+ info = NULL;
+
+ /* We have to scan for our skb since there's no way
+ * to back-map them from the descriptor, and if we
+ * have several receive channels then they might not
+ * show up in the same order as they were put on the
+ * interface ring.
+ */
+
+ dma = (dp->ptr & XCT_PTR_ADDR_M);
+ for (j = start; j < (start + RX_RING_SIZE); j++) {
+ info = &RX_DESC_INFO(mac, j);
+ if (info->dma == dma)
+ break;
+ }
+
+ BUG_ON(!info);
+ BUG_ON(info->dma != dma);
+
+ pci_unmap_single(mac->dma_pdev, info->dma, info->skb->len,
+ PCI_DMA_FROMDEVICE);
+
+ skb = info->skb;
+
+ len = (dp->macrx & XCT_MACRX_LLEN_M) >> XCT_MACRX_LLEN_S;
+
+ skb_put(skb, len);
+
+ skb->protocol = eth_type_trans(skb, mac->netdev);
+
+ if ((dp->macrx & XCT_MACRX_HTY_M) == XCT_MACRX_HTY_IPV4_OK) {
+ skb->ip_summed = CHECKSUM_COMPLETE;
+ skb->csum = (dp->macrx & XCT_MACRX_CSUM_M) >>
+ XCT_MACRX_CSUM_S;
+ } else
+ skb->ip_summed = CHECKSUM_NONE;
+
+ mac->stats.rx_bytes += len;
+ mac->stats.rx_packets++;
+
+ netif_receive_skb(skb);
+
+ info->dma = 0;
+ info->skb = NULL;
+ dp->ptr = 0;
+ dp->macrx = 0;
+ }
+
+ mac->rx->next_to_clean += count;
+ pasemi_mac_replenish_rx_ring(mac->netdev);
+
+ spin_unlock(&mac->rx->lock);
+
+ return count;
+}
+
+static int pasemi_mac_clean_tx(struct pasemi_mac *mac)
+{
+ int i;
+ struct pasemi_mac_buffer *info;
+ struct pas_dma_xct_descr *dp;
+ int start, count;
+ int flags;
+
+ spin_lock_irqsave(&mac->tx->lock, flags);
+
+ start = mac->tx->next_to_clean;
+ count = 0;
+
+ for (i = start; i < mac->tx->next_to_use; i++) {
+ dp = &TX_DESC(mac, i);
+ if (!dp || (dp->mactx & XCT_MACTX_O))
+ break;
+
+ count++;
+
+ info = &TX_DESC_INFO(mac, i);
+
+ pci_unmap_single(mac->dma_pdev, info->dma,
+ info->skb->len, PCI_DMA_TODEVICE);
+ dev_kfree_skb_irq(info->skb);
+
+ info->skb = NULL;
+ info->dma = 0;
+ dp->mactx = 0;
+ dp->ptr = 0;
+ }
+ mac->tx->next_to_clean += count;
+ spin_unlock_irqrestore(&mac->tx->lock, flags);
+
+ return count;
+}
+
+
+static irqreturn_t pasemi_mac_rx_intr(int irq, void *data)
+{
+ struct net_device *dev = data;
+ struct pasemi_mac *mac = netdev_priv(dev);
+ unsigned int reg;
+
+ if (!(*mac->rx_status & PAS_STATUS_INT))
+ return IRQ_NONE;
+
+ netif_rx_schedule(dev);
+ pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_COM_TIMEOUTCFG,
+ PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(0));
+
+ reg = PAS_IOB_DMA_RXCH_RESET_PINTC | PAS_IOB_DMA_RXCH_RESET_SINTC |
+ PAS_IOB_DMA_RXCH_RESET_DINTC;
+ if (*mac->rx_status & PAS_STATUS_TIMER)
+ reg |= PAS_IOB_DMA_RXCH_RESET_TINTC;
+
+ pci_write_config_dword(mac->iob_pdev,
+ PAS_IOB_DMA_RXCH_RESET(mac->dma_rxch), reg);
+
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t pasemi_mac_tx_intr(int irq, void *data)
+{
+ struct net_device *dev = data;
+ struct pasemi_mac *mac = netdev_priv(dev);
+ unsigned int reg;
+ int was_full;
+
+ was_full = mac->tx->next_to_clean - mac->tx->next_to_use == TX_RING_SIZE;
+
+ if (!(*mac->tx_status & PAS_STATUS_INT))
+ return IRQ_NONE;
+
+ pasemi_mac_clean_tx(mac);
+
+ reg = PAS_IOB_DMA_TXCH_RESET_PINTC | PAS_IOB_DMA_TXCH_RESET_SINTC;
+ if (*mac->tx_status & PAS_STATUS_TIMER)
+ reg |= PAS_IOB_DMA_TXCH_RESET_TINTC;
+
+ pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_TXCH_RESET(mac->dma_txch),
+ reg);
+
+ if (was_full)
+ netif_wake_queue(dev);
+
+ return IRQ_HANDLED;
+}
+
+static int pasemi_mac_open(struct net_device *dev)
+{
+ struct pasemi_mac *mac = netdev_priv(dev);
+ unsigned int flags;
+ int ret;
+
+ /* enable rx section */
+ pci_write_config_dword(mac->dma_pdev, PAS_DMA_COM_RXCMD,
+ PAS_DMA_COM_RXCMD_EN);
+
+ /* enable tx section */
+ pci_write_config_dword(mac->dma_pdev, PAS_DMA_COM_TXCMD,
+ PAS_DMA_COM_TXCMD_EN);
+
+ flags = PAS_MAC_CFG_TXP_FCE | PAS_MAC_CFG_TXP_FPC(3) |
+ PAS_MAC_CFG_TXP_SL(3) | PAS_MAC_CFG_TXP_COB(0xf) |
+ PAS_MAC_CFG_TXP_TIFT(8) | PAS_MAC_CFG_TXP_TIFG(12);
+
+ pci_write_config_dword(mac->pdev, PAS_MAC_CFG_TXP, flags);
+
+ flags = PAS_MAC_CFG_PCFG_S1 | PAS_MAC_CFG_PCFG_PE |
+ PAS_MAC_CFG_PCFG_PR | PAS_MAC_CFG_PCFG_CE;
+
+ flags |= PAS_MAC_CFG_PCFG_TSR_1G | PAS_MAC_CFG_PCFG_SPD_1G;
+
+ pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_RXCH_CFG(mac->dma_rxch),
+ PAS_IOB_DMA_RXCH_CFG_CNTTH(30));
+
+ pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_COM_TIMEOUTCFG,
+ PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(1000000));
+
+ pci_write_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, flags);
+
+ ret = pasemi_mac_setup_rx_resources(dev);
+ if (ret)
+ goto out_rx_resources;
+
+ ret = pasemi_mac_setup_tx_resources(dev);
+ if (ret)
+ goto out_tx_resources;
+
+ pci_write_config_dword(mac->pdev, PAS_MAC_IPC_CHNL,
+ PAS_MAC_IPC_CHNL_DCHNO(mac->dma_rxch) |
+ PAS_MAC_IPC_CHNL_BCH(mac->dma_rxch));
+
+ /* enable rx if */
+ pci_write_config_dword(mac->dma_pdev,
+ PAS_DMA_RXINT_RCMDSTA(mac->dma_if),
+ PAS_DMA_RXINT_RCMDSTA_EN);
+
+ /* enable rx channel */
+ pci_write_config_dword(mac->dma_pdev,
+ PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch),
+ PAS_DMA_RXCHAN_CCMDSTA_EN |
+ PAS_DMA_RXCHAN_CCMDSTA_DU);
+
+ /* enable tx channel */
+ pci_write_config_dword(mac->dma_pdev,
+ PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch),
+ PAS_DMA_TXCHAN_TCMDSTA_EN);
+
+ pasemi_mac_replenish_rx_ring(dev);
+
+ netif_start_queue(dev);
+ netif_poll_enable(dev);
+
+ ret = request_irq(mac->dma_pdev->irq + mac->dma_txch,
+ &pasemi_mac_tx_intr, IRQF_DISABLED,
+ mac->tx->irq_name, dev);
+ if (ret) {
+ dev_err(&mac->pdev->dev, "request_irq of irq %d failed: %d\n",
+ mac->dma_pdev->irq + mac->dma_txch, ret);
+ goto out_tx_int;
+ }
+
+ ret = request_irq(mac->dma_pdev->irq + 20 + mac->dma_rxch,
+ &pasemi_mac_rx_intr, IRQF_DISABLED,
+ mac->rx->irq_name, dev);
+ if (ret) {
+ dev_err(&mac->pdev->dev, "request_irq of irq %d failed: %d\n",
+ mac->dma_pdev->irq + 20 + mac->dma_rxch, ret);
+ goto out_rx_int;
+ }
+
+ return 0;
+
+out_rx_int:
+ free_irq(mac->dma_pdev->irq + mac->dma_txch, dev);
+out_tx_int:
+ netif_poll_disable(dev);
+ netif_stop_queue(dev);
+ pasemi_mac_free_tx_resources(dev);
+out_tx_resources:
+ pasemi_mac_free_rx_resources(dev);
+out_rx_resources:
+
+ return ret;
+}
+
+#define MAX_RETRIES 5000
+
+static int pasemi_mac_close(struct net_device *dev)
+{
+ struct pasemi_mac *mac = netdev_priv(dev);
+ unsigned int stat;
+ int retries;
+
+ netif_stop_queue(dev);
+
+ /* Clean out any pending buffers */
+ pasemi_mac_clean_tx(mac);
+ pasemi_mac_clean_rx(mac, RX_RING_SIZE);
+
+ /* Disable interface */
+ pci_write_config_dword(mac->dma_pdev,
+ PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch),
+ PAS_DMA_TXCHAN_TCMDSTA_ST);
+ pci_write_config_dword(mac->dma_pdev,
+ PAS_DMA_RXINT_RCMDSTA(mac->dma_if),
+ PAS_DMA_RXINT_RCMDSTA_ST);
+ pci_write_config_dword(mac->dma_pdev,
+ PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch),
+ PAS_DMA_RXCHAN_CCMDSTA_ST);
+
+ for (retries = 0; retries < MAX_RETRIES; retries++) {
+ pci_read_config_dword(mac->dma_pdev,
+ PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch),
+ &stat);
+ if (stat & PAS_DMA_TXCHAN_TCMDSTA_ACT)
+ break;
+ cond_resched();
+ }
+
+ if (!(stat & PAS_DMA_TXCHAN_TCMDSTA_ACT)) {
+ dev_err(&mac->dma_pdev->dev, "Failed to stop tx channel\n");
+ }
+
+ for (retries = 0; retries < MAX_RETRIES; retries++) {
+ pci_read_config_dword(mac->dma_pdev,
+ PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch),
+ &stat);
+ if (stat & PAS_DMA_RXCHAN_CCMDSTA_ACT)
+ break;
+ cond_resched();
+ }
+
+ if (!(stat & PAS_DMA_RXCHAN_CCMDSTA_ACT)) {
+ dev_err(&mac->dma_pdev->dev, "Failed to stop rx channel\n");
+ }
+
+ for (retries = 0; retries < MAX_RETRIES; retries++) {
+ pci_read_config_dword(mac->dma_pdev,
+ PAS_DMA_RXINT_RCMDSTA(mac->dma_if),
+ &stat);
+ if (stat & PAS_DMA_RXINT_RCMDSTA_ACT)
+ break;
+ cond_resched();
+ }
+
+ if (!(stat & PAS_DMA_RXINT_RCMDSTA_ACT)) {
+ dev_err(&mac->dma_pdev->dev, "Failed to stop rx interface\n");
+ }
+
+ /* Then, disable the channel. This must be done separately from
+ * stopping, since you can't disable when active.
+ */
+
+ pci_write_config_dword(mac->dma_pdev,
+ PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch), 0);
+ pci_write_config_dword(mac->dma_pdev,
+ PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch), 0);
+ pci_write_config_dword(mac->dma_pdev,
+ PAS_DMA_RXINT_RCMDSTA(mac->dma_if), 0);
+
+ free_irq(mac->dma_pdev->irq + mac->dma_txch, dev);
+ free_irq(mac->dma_pdev->irq + 20 + mac->dma_rxch, dev);
+
+ /* Free resources */
+ pasemi_mac_free_rx_resources(dev);
+ pasemi_mac_free_tx_resources(dev);
+
+ return 0;
+}
+
+static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev)
+{
+ struct pasemi_mac *mac = netdev_priv(dev);
+ struct pasemi_mac_txring *txring;
+ struct pasemi_mac_buffer *info;
+ struct pas_dma_xct_descr *dp;
+ u64 dflags;
+ dma_addr_t map;
+ int flags;
+
+ dflags = XCT_MACTX_O | XCT_MACTX_ST | XCT_MACTX_SS | XCT_MACTX_CRC_PAD;
+
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ switch (skb->nh.iph->protocol) {
+ case IPPROTO_TCP:
+ dflags |= XCT_MACTX_CSUM_TCP;
+ dflags |= XCT_MACTX_IPH((skb->h.raw - skb->nh.raw) >> 2);
+ dflags |= XCT_MACTX_IPO(skb->nh.raw - skb->data);
+ break;
+ case IPPROTO_UDP:
+ dflags |= XCT_MACTX_CSUM_UDP;
+ dflags |= XCT_MACTX_IPH((skb->h.raw - skb->nh.raw) >> 2);
+ dflags |= XCT_MACTX_IPO(skb->nh.raw - skb->data);
+ break;
+ }
+ }
+
+ map = pci_map_single(mac->dma_pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
+
+ if (dma_mapping_error(map))
+ return NETDEV_TX_BUSY;
+
+ txring = mac->tx;
+
+ spin_lock_irqsave(&txring->lock, flags);
+
+ if (txring->next_to_clean - txring->next_to_use == TX_RING_SIZE) {
+ spin_unlock_irqrestore(&txring->lock, flags);
+ pasemi_mac_clean_tx(mac);
+ spin_lock_irqsave(&txring->lock, flags);
+
+ if (txring->next_to_clean - txring->next_to_use ==
+ TX_RING_SIZE) {
+ /* Still no room -- stop the queue and wait for tx
+ * intr when there's room.
+ */
+ netif_stop_queue(dev);
+ goto out_err;
+ }
+ }
+
+
+ dp = &TX_DESC(mac, txring->next_to_use);
+ info = &TX_DESC_INFO(mac, txring->next_to_use);
+
+ dp->mactx = dflags | XCT_MACTX_LLEN(skb->len);
+ dp->ptr = XCT_PTR_LEN(skb->len) | XCT_PTR_ADDR(map);
+ info->dma = map;
+ info->skb = skb;
+
+ txring->next_to_use++;
+ mac->stats.tx_packets++;
+ mac->stats.tx_bytes += skb->len;
+
+ spin_unlock_irqrestore(&txring->lock, flags);
+
+ pci_write_config_dword(mac->dma_pdev,
+ PAS_DMA_TXCHAN_INCR(mac->dma_txch), 1);
+
+ return NETDEV_TX_OK;
+
+out_err:
+ spin_unlock_irqrestore(&txring->lock, flags);
+ pci_unmap_single(mac->dma_pdev, map, skb->len, PCI_DMA_TODEVICE);
+ return NETDEV_TX_BUSY;
+}
+
+static struct net_device_stats *pasemi_mac_get_stats(struct net_device *dev)
+{
+ struct pasemi_mac *mac = netdev_priv(dev);
+
+ return &mac->stats;
+}
+
+static void pasemi_mac_set_rx_mode(struct net_device *dev)
+{
+ struct pasemi_mac *mac = netdev_priv(dev);
+ unsigned int flags;
+
+ pci_read_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, &flags);
+
+ /* Set promiscuous */
+ if (dev->flags & IFF_PROMISC)
+ flags |= PAS_MAC_CFG_PCFG_PR;
+ else
+ flags &= ~PAS_MAC_CFG_PCFG_PR;
+
+ pci_write_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, flags);
+}
+
+
+static int pasemi_mac_poll(struct net_device *dev, int *budget)
+{
+ int pkts, limit = min(*budget, dev->quota);
+ struct pasemi_mac *mac = netdev_priv(dev);
+
+ pkts = pasemi_mac_clean_rx(mac, limit);
+
+ if (pkts < limit) {
+ /* all done, no more packets present */
+ netif_rx_complete(dev);
+
+ /* re-enable receive interrupts */
+ pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_COM_TIMEOUTCFG,
+ PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(1000000));
+ return 0;
+ } else {
+ /* used up our quantum, so reschedule */
+ dev->quota -= pkts;
+ *budget -= pkts;
+ return 1;
+ }
+}
+
+static int __devinit
+pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ static int index = 0;
+ struct net_device *dev;
+ struct pasemi_mac *mac;
+ int err;
+
+ err = pci_enable_device(pdev);
+ if (err)
+ return err;
+
+ dev = alloc_etherdev(sizeof(struct pasemi_mac));
+ if (dev == NULL) {
+ dev_err(&pdev->dev,
+ "pasemi_mac: Could not allocate ethernet device.\n");
+ err = -ENOMEM;
+ goto out_disable_device;
+ }
+
+ SET_MODULE_OWNER(dev);
+ pci_set_drvdata(pdev, dev);
+ SET_NETDEV_DEV(dev, &pdev->dev);
+
+ mac = netdev_priv(dev);
+
+ mac->pdev = pdev;
+ mac->netdev = dev;
+ mac->dma_pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa007, NULL);
+
+ if (!mac->dma_pdev) {
+ dev_err(&pdev->dev, "Can't find DMA Controller\n");
+ err = -ENODEV;
+ goto out_free_netdev;
+ }
+
+ mac->iob_pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa001, NULL);
+
+ if (!mac->iob_pdev) {
+ dev_err(&pdev->dev, "Can't find I/O Bridge\n");
+ err = -ENODEV;
+ goto out_put_dma_pdev;
+ }
+
+ /* These should come out of the device tree eventually */
+ mac->dma_txch = index;
+ mac->dma_rxch = index;
+
+ /* We probe GMAC before XAUI, but the DMA interfaces are
+ * in XAUI, GMAC order.
+ */
+ if (index < 4)
+ mac->dma_if = index + 2;
+ else
+ mac->dma_if = index - 4;
+ index++;
+
+ switch (pdev->device) {
+ case 0xa005:
+ mac->type = MAC_TYPE_GMAC;
+ break;
+ case 0xa006:
+ mac->type = MAC_TYPE_XAUI;
+ break;
+ default:
+ err = -ENODEV;
+ goto out;
+ }
+
+ /* get mac addr from device tree */
+ if (pasemi_get_mac_addr(mac) || !is_valid_ether_addr(mac->mac_addr)) {
+ err = -ENODEV;
+ goto out;
+ }
+ memcpy(dev->dev_addr, mac->mac_addr, sizeof(mac->mac_addr));
+
+ dev->open = pasemi_mac_open;
+ dev->stop = pasemi_mac_close;
+ dev->hard_start_xmit = pasemi_mac_start_tx;
+ dev->get_stats = pasemi_mac_get_stats;
+ dev->set_multicast_list = pasemi_mac_set_rx_mode;
+ dev->weight = 64;
+ dev->poll = pasemi_mac_poll;
+ dev->features = NETIF_F_HW_CSUM;
+
+ /* The dma status structure is located in the I/O bridge, and
+ * is cache coherent.
+ */
+ if (!dma_status)
+ /* XXXOJN This should come from the device tree */
+ dma_status = __ioremap(0xfd800000, 0x1000, 0);
+
+ mac->rx_status = &dma_status->rx_sta[mac->dma_rxch];
+ mac->tx_status = &dma_status->tx_sta[mac->dma_txch];
+
+ err = register_netdev(dev);
+
+ if (err) {
+ dev_err(&mac->pdev->dev, "register_netdev failed with error %d\n",
+ err);
+ goto out;
+ } else
+ printk(KERN_INFO "%s: PA Semi %s: intf %d, txch %d, rxch %d, "
+ "hw addr %02x:%02x:%02x:%02x:%02x:%02x\n",
+ dev->name, mac->type == MAC_TYPE_GMAC ? "GMAC" : "XAUI",
+ mac->dma_if, mac->dma_txch, mac->dma_rxch,
+ dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
+ dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+
+ return err;
+
+out:
+ pci_dev_put(mac->iob_pdev);
+out_put_dma_pdev:
+ pci_dev_put(mac->dma_pdev);
+out_free_netdev:
+ free_netdev(dev);
+out_disable_device:
+ pci_disable_device(pdev);
+ return err;
+
+}
+
+static void __devexit pasemi_mac_remove(struct pci_dev *pdev)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct pasemi_mac *mac;
+
+ if (!netdev)
+ return;
+
+ mac = netdev_priv(netdev);
+
+ unregister_netdev(netdev);
+
+ pci_disable_device(pdev);
+ pci_dev_put(mac->dma_pdev);
+ pci_dev_put(mac->iob_pdev);
+
+ pci_set_drvdata(pdev, NULL);
+ free_netdev(netdev);
+}
+
+static struct pci_device_id pasemi_mac_pci_tbl[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_PASEMI, 0xa005) },
+ { PCI_DEVICE(PCI_VENDOR_ID_PASEMI, 0xa006) },
+};
+
+MODULE_DEVICE_TABLE(pci, pasemi_mac_pci_tbl);
+
+static struct pci_driver pasemi_mac_driver = {
+ .name = "pasemi_mac",
+ .id_table = pasemi_mac_pci_tbl,
+ .probe = pasemi_mac_probe,
+ .remove = __devexit_p(pasemi_mac_remove),
+};
+
+static void __exit pasemi_mac_cleanup_module(void)
+{
+ pci_unregister_driver(&pasemi_mac_driver);
+ __iounmap(dma_status);
+ dma_status = NULL;
+}
+
+int pasemi_mac_init_module(void)
+{
+ return pci_register_driver(&pasemi_mac_driver);
+}
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR ("Olof Johansson <olof@lixom.net>");
+MODULE_DESCRIPTION("PA Semi PWRficient Ethernet driver");
+
+module_init(pasemi_mac_init_module);
+module_exit(pasemi_mac_cleanup_module);
diff --git a/drivers/net/pasemi_mac.h b/drivers/net/pasemi_mac.h
new file mode 100644
index 00000000000..c3e37e46a18
--- /dev/null
+++ b/drivers/net/pasemi_mac.h
@@ -0,0 +1,460 @@
+/*
+ * Copyright (C) 2006 PA Semi, Inc
+ *
+ * Driver for the PA6T-1682M onchip 1G/10G Ethernet MACs, soft state and
+ * hardware register layouts.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PASEMI_MAC_H
+#define PASEMI_MAC_H
+
+#include <linux/ethtool.h>
+#include <linux/netdevice.h>
+#include <linux/spinlock.h>
+
+struct pasemi_mac_txring {
+ spinlock_t lock;
+ struct pas_dma_xct_descr *desc;
+ dma_addr_t dma;
+ unsigned int size;
+ unsigned int next_to_use;
+ unsigned int next_to_clean;
+ struct pasemi_mac_buffer *desc_info;
+ char irq_name[10]; /* "eth%d tx" */
+};
+
+struct pasemi_mac_rxring {
+ spinlock_t lock;
+ struct pas_dma_xct_descr *desc; /* RX channel descriptor ring */
+ dma_addr_t dma;
+ u64 *buffers; /* RX interface buffer ring */
+ dma_addr_t buf_dma;
+ unsigned int size;
+ unsigned int next_to_fill;
+ unsigned int next_to_clean;
+ struct pasemi_mac_buffer *desc_info;
+ char irq_name[10]; /* "eth%d rx" */
+};
+
+struct pasemi_mac {
+ struct net_device *netdev;
+ struct pci_dev *pdev;
+ struct pci_dev *dma_pdev;
+ struct pci_dev *iob_pdev;
+ struct net_device_stats stats;
+
+ /* Pointer to the cacheable per-channel status registers */
+ u64 *rx_status;
+ u64 *tx_status;
+
+ u8 type;
+#define MAC_TYPE_GMAC 1
+#define MAC_TYPE_XAUI 2
+ u32 dma_txch;
+ u32 dma_if;
+ u32 dma_rxch;
+
+ u8 mac_addr[6];
+
+ struct timer_list rxtimer;
+
+ struct pasemi_mac_txring *tx;
+ struct pasemi_mac_rxring *rx;
+};
+
+/* Software status descriptor (desc_info) */
+struct pasemi_mac_buffer {
+ struct sk_buff *skb;
+ dma_addr_t dma;
+};
+
+
+/* status register layout in IOB region, at 0xfb800000 */
+struct pasdma_status {
+ u64 rx_sta[64];
+ u64 tx_sta[20];
+};
+
+/* descriptor structure */
+struct pas_dma_xct_descr {
+ union {
+ u64 mactx;
+ u64 macrx;
+ };
+ union {
+ u64 ptr;
+ u64 rxb;
+ };
+};
+
+/* MAC CFG register offsets */
+
+enum {
+ PAS_MAC_CFG_PCFG = 0x80,
+ PAS_MAC_CFG_TXP = 0x98,
+ PAS_MAC_IPC_CHNL = 0x208,
+};
+
+/* MAC CFG register fields */
+#define PAS_MAC_CFG_PCFG_PE 0x80000000
+#define PAS_MAC_CFG_PCFG_CE 0x40000000
+#define PAS_MAC_CFG_PCFG_BU 0x20000000
+#define PAS_MAC_CFG_PCFG_TT 0x10000000
+#define PAS_MAC_CFG_PCFG_TSR_M 0x0c000000
+#define PAS_MAC_CFG_PCFG_TSR_10M 0x00000000
+#define PAS_MAC_CFG_PCFG_TSR_100M 0x04000000
+#define PAS_MAC_CFG_PCFG_TSR_1G 0x08000000
+#define PAS_MAC_CFG_PCFG_TSR_10G 0x0c000000
+#define PAS_MAC_CFG_PCFG_T24 0x02000000
+#define PAS_MAC_CFG_PCFG_PR 0x01000000
+#define PAS_MAC_CFG_PCFG_CRO_M 0x00ff0000
+#define PAS_MAC_CFG_PCFG_CRO_S 16
+#define PAS_MAC_CFG_PCFG_IPO_M 0x0000ff00
+#define PAS_MAC_CFG_PCFG_IPO_S 8
+#define PAS_MAC_CFG_PCFG_S1 0x00000080
+#define PAS_MAC_CFG_PCFG_IO_M 0x00000060
+#define PAS_MAC_CFG_PCFG_IO_MAC 0x00000000
+#define PAS_MAC_CFG_PCFG_IO_OFF 0x00000020
+#define PAS_MAC_CFG_PCFG_IO_IND_ETH 0x00000040
+#define PAS_MAC_CFG_PCFG_IO_IND_IP 0x00000060
+#define PAS_MAC_CFG_PCFG_LP 0x00000010
+#define PAS_MAC_CFG_PCFG_TS 0x00000008
+#define PAS_MAC_CFG_PCFG_HD 0x00000004
+#define PAS_MAC_CFG_PCFG_SPD_M 0x00000003
+#define PAS_MAC_CFG_PCFG_SPD_10M 0x00000000
+#define PAS_MAC_CFG_PCFG_SPD_100M 0x00000001
+#define PAS_MAC_CFG_PCFG_SPD_1G 0x00000002
+#define PAS_MAC_CFG_PCFG_SPD_10G 0x00000003
+#define PAS_MAC_CFG_TXP_FCF 0x01000000
+#define PAS_MAC_CFG_TXP_FCE 0x00800000
+#define PAS_MAC_CFG_TXP_FC 0x00400000
+#define PAS_MAC_CFG_TXP_FPC_M 0x00300000
+#define PAS_MAC_CFG_TXP_FPC_S 20
+#define PAS_MAC_CFG_TXP_FPC(x) (((x) << PAS_MAC_CFG_TXP_FPC_S) & \
+ PAS_MAC_CFG_TXP_FPC_M)
+#define PAS_MAC_CFG_TXP_RT 0x00080000
+#define PAS_MAC_CFG_TXP_BL 0x00040000
+#define PAS_MAC_CFG_TXP_SL_M 0x00030000
+#define PAS_MAC_CFG_TXP_SL_S 16
+#define PAS_MAC_CFG_TXP_SL(x) (((x) << PAS_MAC_CFG_TXP_SL_S) & \
+ PAS_MAC_CFG_TXP_SL_M)
+#define PAS_MAC_CFG_TXP_COB_M 0x0000f000
+#define PAS_MAC_CFG_TXP_COB_S 12
+#define PAS_MAC_CFG_TXP_COB(x) (((x) << PAS_MAC_CFG_TXP_COB_S) & \
+ PAS_MAC_CFG_TXP_COB_M)
+#define PAS_MAC_CFG_TXP_TIFT_M 0x00000f00
+#define PAS_MAC_CFG_TXP_TIFT_S 8
+#define PAS_MAC_CFG_TXP_TIFT(x) (((x) << PAS_MAC_CFG_TXP_TIFT_S) & \
+ PAS_MAC_CFG_TXP_TIFT_M)
+#define PAS_MAC_CFG_TXP_TIFG_M 0x000000ff
+#define PAS_MAC_CFG_TXP_TIFG_S 0
+#define PAS_MAC_CFG_TXP_TIFG(x) (((x) << PAS_MAC_CFG_TXP_TIFG_S) & \
+ PAS_MAC_CFG_TXP_TIFG_M)
+
+#define PAS_MAC_IPC_CHNL_DCHNO_M 0x003f0000
+#define PAS_MAC_IPC_CHNL_DCHNO_S 16
+#define PAS_MAC_IPC_CHNL_DCHNO(x) (((x) << PAS_MAC_IPC_CHNL_DCHNO_S) & \
+ PAS_MAC_IPC_CHNL_DCHNO_M)
+#define PAS_MAC_IPC_CHNL_BCH_M 0x0000003f
+#define PAS_MAC_IPC_CHNL_BCH_S 0
+#define PAS_MAC_IPC_CHNL_BCH(x) (((x) << PAS_MAC_IPC_CHNL_BCH_S) & \
+ PAS_MAC_IPC_CHNL_BCH_M)
+
+/* All these registers live in the PCI configuration space for the DMA PCI
+ * device. Use the normal PCI config access functions for them.
+ */
+enum {
+ PAS_DMA_COM_TXCMD = 0x100, /* Transmit Command Register */
+ PAS_DMA_COM_TXSTA = 0x104, /* Transmit Status Register */
+ PAS_DMA_COM_RXCMD = 0x108, /* Receive Command Register */
+ PAS_DMA_COM_RXSTA = 0x10c, /* Receive Status Register */
+};
+#define PAS_DMA_COM_TXCMD_EN 0x00000001 /* enable */
+#define PAS_DMA_COM_TXSTA_ACT 0x00000001 /* active */
+#define PAS_DMA_COM_RXCMD_EN 0x00000001 /* enable */
+#define PAS_DMA_COM_RXSTA_ACT 0x00000001 /* active */
+
+
+/* Per-interface and per-channel registers */
+#define _PAS_DMA_RXINT_STRIDE 0x20
+#define PAS_DMA_RXINT_RCMDSTA(i) (0x200+(i)*_PAS_DMA_RXINT_STRIDE)
+#define PAS_DMA_RXINT_RCMDSTA_EN 0x00000001
+#define PAS_DMA_RXINT_RCMDSTA_ST 0x00000002
+#define PAS_DMA_RXINT_RCMDSTA_OO 0x00000100
+#define PAS_DMA_RXINT_RCMDSTA_BP 0x00000200
+#define PAS_DMA_RXINT_RCMDSTA_DR 0x00000400
+#define PAS_DMA_RXINT_RCMDSTA_BT 0x00000800
+#define PAS_DMA_RXINT_RCMDSTA_TB 0x00001000
+#define PAS_DMA_RXINT_RCMDSTA_ACT 0x00010000
+#define PAS_DMA_RXINT_RCMDSTA_DROPS_M 0xfffe0000
+#define PAS_DMA_RXINT_RCMDSTA_DROPS_S 17
+#define PAS_DMA_RXINT_INCR(i) (0x210+(i)*_PAS_DMA_RXINT_STRIDE)
+#define PAS_DMA_RXINT_INCR_INCR_M 0x0000ffff
+#define PAS_DMA_RXINT_INCR_INCR_S 0
+#define PAS_DMA_RXINT_INCR_INCR(x) ((x) & 0x0000ffff)
+#define PAS_DMA_RXINT_BASEL(i) (0x218+(i)*_PAS_DMA_RXINT_STRIDE)
+#define PAS_DMA_RXINT_BASEL_BRBL(x) ((x) & ~0x3f)
+#define PAS_DMA_RXINT_BASEU(i) (0x21c+(i)*_PAS_DMA_RXINT_STRIDE)
+#define PAS_DMA_RXINT_BASEU_BRBH(x) ((x) & 0xfff)
+#define PAS_DMA_RXINT_BASEU_SIZ_M 0x3fff0000 /* # of cache lines worth of buffer ring */
+#define PAS_DMA_RXINT_BASEU_SIZ_S 16 /* 0 = 16K */
+#define PAS_DMA_RXINT_BASEU_SIZ(x) (((x) << PAS_DMA_RXINT_BASEU_SIZ_S) & \
+ PAS_DMA_RXINT_BASEU_SIZ_M)
+
+
+#define _PAS_DMA_TXCHAN_STRIDE 0x20 /* Size per channel */
+#define _PAS_DMA_TXCHAN_TCMDSTA 0x300 /* Command / Status */
+#define _PAS_DMA_TXCHAN_CFG 0x304 /* Configuration */
+#define _PAS_DMA_TXCHAN_DSCRBU 0x308 /* Descriptor BU Allocation */
+#define _PAS_DMA_TXCHAN_INCR 0x310 /* Descriptor increment */
+#define _PAS_DMA_TXCHAN_CNT 0x314 /* Descriptor count/offset */
+#define _PAS_DMA_TXCHAN_BASEL 0x318 /* Descriptor ring base (low) */
+#define _PAS_DMA_TXCHAN_BASEU 0x31c /* (high) */
+#define PAS_DMA_TXCHAN_TCMDSTA(c) (0x300+(c)*_PAS_DMA_TXCHAN_STRIDE)
+#define PAS_DMA_TXCHAN_TCMDSTA_EN 0x00000001 /* Enabled */
+#define PAS_DMA_TXCHAN_TCMDSTA_ST 0x00000002 /* Stop interface */
+#define PAS_DMA_TXCHAN_TCMDSTA_ACT 0x00010000 /* Active */
+#define PAS_DMA_TXCHAN_CFG(c) (0x304+(c)*_PAS_DMA_TXCHAN_STRIDE)
+#define PAS_DMA_TXCHAN_CFG_TY_IFACE 0x00000000 /* Type = interface */
+#define PAS_DMA_TXCHAN_CFG_TATTR_M 0x0000003c
+#define PAS_DMA_TXCHAN_CFG_TATTR_S 2
+#define PAS_DMA_TXCHAN_CFG_TATTR(x) (((x) << PAS_DMA_TXCHAN_CFG_TATTR_S) & \
+ PAS_DMA_TXCHAN_CFG_TATTR_M)
+#define PAS_DMA_TXCHAN_CFG_WT_M 0x000001c0
+#define PAS_DMA_TXCHAN_CFG_WT_S 6
+#define PAS_DMA_TXCHAN_CFG_WT(x) (((x) << PAS_DMA_TXCHAN_CFG_WT_S) & \
+ PAS_DMA_TXCHAN_CFG_WT_M)
+#define PAS_DMA_TXCHAN_CFG_CF 0x00001000 /* Clean first line */
+#define PAS_DMA_TXCHAN_CFG_CL 0x00002000 /* Clean last line */
+#define PAS_DMA_TXCHAN_CFG_UP 0x00004000 /* update tx descr when sent */
+#define PAS_DMA_TXCHAN_INCR(c) (0x310+(c)*_PAS_DMA_TXCHAN_STRIDE)
+#define PAS_DMA_TXCHAN_BASEL(c) (0x318+(c)*_PAS_DMA_TXCHAN_STRIDE)
+#define PAS_DMA_TXCHAN_BASEL_BRBL_M 0xffffffc0
+#define PAS_DMA_TXCHAN_BASEL_BRBL_S 0
+#define PAS_DMA_TXCHAN_BASEL_BRBL(x) (((x) << PAS_DMA_TXCHAN_BASEL_BRBL_S) & \
+ PAS_DMA_TXCHAN_BASEL_BRBL_M)
+#define PAS_DMA_TXCHAN_BASEU(c) (0x31c+(c)*_PAS_DMA_TXCHAN_STRIDE)
+#define PAS_DMA_TXCHAN_BASEU_BRBH_M 0x00000fff
+#define PAS_DMA_TXCHAN_BASEU_BRBH_S 0
+#define PAS_DMA_TXCHAN_BASEU_BRBH(x) (((x) << PAS_DMA_TXCHAN_BASEU_BRBH_S) & \
+ PAS_DMA_TXCHAN_BASEU_BRBH_M)
+/* # of cache lines worth of buffer ring */
+#define PAS_DMA_TXCHAN_BASEU_SIZ_M 0x3fff0000
+#define PAS_DMA_TXCHAN_BASEU_SIZ_S 16 /* 0 = 16K */
+#define PAS_DMA_TXCHAN_BASEU_SIZ(x) (((x) << PAS_DMA_TXCHAN_BASEU_SIZ_S) & \
+ PAS_DMA_TXCHAN_BASEU_SIZ_M)
+
+#define _PAS_DMA_RXCHAN_STRIDE 0x20 /* Size per channel */
+#define _PAS_DMA_RXCHAN_CCMDSTA 0x800 /* Command / Status */
+#define _PAS_DMA_RXCHAN_CFG 0x804 /* Configuration */
+#define _PAS_DMA_RXCHAN_INCR 0x810 /* Descriptor increment */
+#define _PAS_DMA_RXCHAN_CNT 0x814 /* Descriptor count/offset */
+#define _PAS_DMA_RXCHAN_BASEL 0x818 /* Descriptor ring base (low) */
+#define _PAS_DMA_RXCHAN_BASEU 0x81c /* (high) */
+#define PAS_DMA_RXCHAN_CCMDSTA(c) (0x800+(c)*_PAS_DMA_RXCHAN_STRIDE)
+#define PAS_DMA_RXCHAN_CCMDSTA_EN 0x00000001 /* Enabled */
+#define PAS_DMA_RXCHAN_CCMDSTA_ST 0x00000002 /* Stop interface */
+#define PAS_DMA_RXCHAN_CCMDSTA_ACT 0x00010000 /* Active */
+#define PAS_DMA_RXCHAN_CCMDSTA_DU 0x00020000
+#define PAS_DMA_RXCHAN_CFG(c) (0x804+(c)*_PAS_DMA_RXCHAN_STRIDE)
+#define PAS_DMA_RXCHAN_CFG_HBU_M 0x00000380
+#define PAS_DMA_RXCHAN_CFG_HBU_S 7
+#define PAS_DMA_RXCHAN_CFG_HBU(x) (((x) << PAS_DMA_RXCHAN_CFG_HBU_S) & \
+ PAS_DMA_RXCHAN_CFG_HBU_M)
+#define PAS_DMA_RXCHAN_INCR(c) (0x810+(c)*_PAS_DMA_RXCHAN_STRIDE)
+#define PAS_DMA_RXCHAN_BASEL(c) (0x818+(c)*_PAS_DMA_RXCHAN_STRIDE)
+#define PAS_DMA_RXCHAN_BASEL_BRBL_M 0xffffffc0
+#define PAS_DMA_RXCHAN_BASEL_BRBL_S 0
+#define PAS_DMA_RXCHAN_BASEL_BRBL(x) (((x) << PAS_DMA_RXCHAN_BASEL_BRBL_S) & \
+ PAS_DMA_RXCHAN_BASEL_BRBL_M)
+#define PAS_DMA_RXCHAN_BASEU(c) (0x81c+(c)*_PAS_DMA_RXCHAN_STRIDE)
+#define PAS_DMA_RXCHAN_BASEU_BRBH_M 0x00000fff
+#define PAS_DMA_RXCHAN_BASEU_BRBH_S 0
+#define PAS_DMA_RXCHAN_BASEU_BRBH(x) (((x) << PAS_DMA_RXCHAN_BASEU_BRBH_S) & \
+ PAS_DMA_RXCHAN_BASEU_BRBH_M)
+/* # of cache lines worth of buffer ring */
+#define PAS_DMA_RXCHAN_BASEU_SIZ_M 0x3fff0000
+#define PAS_DMA_RXCHAN_BASEU_SIZ_S 16 /* 0 = 16K */
+#define PAS_DMA_RXCHAN_BASEU_SIZ(x) (((x) << PAS_DMA_RXCHAN_BASEU_SIZ_S) & \
+ PAS_DMA_RXCHAN_BASEU_SIZ_M)
+
+#define PAS_STATUS_PCNT_M 0x000000000000ffffull
+#define PAS_STATUS_PCNT_S 0
+#define PAS_STATUS_DCNT_M 0x00000000ffff0000ull
+#define PAS_STATUS_DCNT_S 16
+#define PAS_STATUS_BPCNT_M 0x0000ffff00000000ull
+#define PAS_STATUS_BPCNT_S 32
+#define PAS_STATUS_TIMER 0x1000000000000000ull
+#define PAS_STATUS_ERROR 0x2000000000000000ull
+#define PAS_STATUS_SOFT 0x4000000000000000ull
+#define PAS_STATUS_INT 0x8000000000000000ull
+
+#define PAS_IOB_DMA_RXCH_CFG(i) (0x1100 + (i)*4)
+#define PAS_IOB_DMA_RXCH_CFG_CNTTH_M 0x00000fff
+#define PAS_IOB_DMA_RXCH_CFG_CNTTH_S 0
+#define PAS_IOB_DMA_RXCH_CFG_CNTTH(x) (((x) << PAS_IOB_DMA_RXCH_CFG_CNTTH_S) & \
+ PAS_IOB_DMA_RXCH_CFG_CNTTH_M)
+#define PAS_IOB_DMA_TXCH_CFG(i) (0x1200 + (i)*4)
+#define PAS_IOB_DMA_TXCH_CFG_CNTTH_M 0x00000fff
+#define PAS_IOB_DMA_TXCH_CFG_CNTTH_S 0
+#define PAS_IOB_DMA_TXCH_CFG_CNTTH(x) (((x) << PAS_IOB_DMA_TXCH_CFG_CNTTH_S) & \
+ PAS_IOB_DMA_TXCH_CFG_CNTTH_M)
+#define PAS_IOB_DMA_RXCH_STAT(i) (0x1300 + (i)*4)
+#define PAS_IOB_DMA_RXCH_STAT_INTGEN 0x00001000
+#define PAS_IOB_DMA_RXCH_STAT_CNTDEL_M 0x00000fff
+#define PAS_IOB_DMA_RXCH_STAT_CNTDEL_S 0
+#define PAS_IOB_DMA_RXCH_STAT_CNTDEL(x) (((x) << PAS_IOB_DMA_RXCH_STAT_CNTDEL_S) &\
+ PAS_IOB_DMA_RXCH_STAT_CNTDEL_M)
+#define PAS_IOB_DMA_TXCH_STAT(i) (0x1400 + (i)*4)
+#define PAS_IOB_DMA_TXCH_STAT_INTGEN 0x00001000
+#define PAS_IOB_DMA_TXCH_STAT_CNTDEL_M 0x00000fff
+#define PAS_IOB_DMA_TXCH_STAT_CNTDEL_S 0
+#define PAS_IOB_DMA_TXCH_STAT_CNTDEL(x) (((x) << PAS_IOB_DMA_TXCH_STAT_CNTDEL_S) &\
+ PAS_IOB_DMA_TXCH_STAT_CNTDEL_M)
+#define PAS_IOB_DMA_RXCH_RESET(i) (0x1500 + (i)*4)
+#define PAS_IOB_DMA_RXCH_RESET_PCNT_M 0xffff0000
+#define PAS_IOB_DMA_RXCH_RESET_PCNT_S 0
+#define PAS_IOB_DMA_RXCH_RESET_PCNT(x) (((x) << PAS_IOB_DMA_RXCH_RESET_PCNT_S) & \
+ PAS_IOB_DMA_RXCH_RESET_PCNT_M)
+#define PAS_IOB_DMA_RXCH_RESET_PCNTRST 0x00000020
+#define PAS_IOB_DMA_RXCH_RESET_DCNTRST 0x00000010
+#define PAS_IOB_DMA_RXCH_RESET_TINTC 0x00000008
+#define PAS_IOB_DMA_RXCH_RESET_DINTC 0x00000004
+#define PAS_IOB_DMA_RXCH_RESET_SINTC 0x00000002
+#define PAS_IOB_DMA_RXCH_RESET_PINTC 0x00000001
+#define PAS_IOB_DMA_TXCH_RESET(i) (0x1600 + (i)*4)
+#define PAS_IOB_DMA_TXCH_RESET_PCNT_M 0xffff0000
+#define PAS_IOB_DMA_TXCH_RESET_PCNT_S 0
+#define PAS_IOB_DMA_TXCH_RESET_PCNT(x) (((x) << PAS_IOB_DMA_TXCH_RESET_PCNT_S) & \
+ PAS_IOB_DMA_TXCH_RESET_PCNT_M)
+#define PAS_IOB_DMA_TXCH_RESET_PCNTRST 0x00000020
+#define PAS_IOB_DMA_TXCH_RESET_DCNTRST 0x00000010
+#define PAS_IOB_DMA_TXCH_RESET_TINTC 0x00000008
+#define PAS_IOB_DMA_TXCH_RESET_DINTC 0x00000004
+#define PAS_IOB_DMA_TXCH_RESET_SINTC 0x00000002
+#define PAS_IOB_DMA_TXCH_RESET_PINTC 0x00000001
+
+#define PAS_IOB_DMA_COM_TIMEOUTCFG 0x1700
+#define PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT_M 0x00ffffff
+#define PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT_S 0
+#define PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(x) (((x) << PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT_S) & \
+ PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT_M)
+
+/* Transmit descriptor fields */
+#define XCT_MACTX_T 0x8000000000000000ull
+#define XCT_MACTX_ST 0x4000000000000000ull
+#define XCT_MACTX_NORES 0x0000000000000000ull
+#define XCT_MACTX_8BRES 0x1000000000000000ull
+#define XCT_MACTX_24BRES 0x2000000000000000ull
+#define XCT_MACTX_40BRES 0x3000000000000000ull
+#define XCT_MACTX_I 0x0800000000000000ull
+#define XCT_MACTX_O 0x0400000000000000ull
+#define XCT_MACTX_E 0x0200000000000000ull
+#define XCT_MACTX_VLAN_M 0x0180000000000000ull
+#define XCT_MACTX_VLAN_NOP 0x0000000000000000ull
+#define XCT_MACTX_VLAN_REMOVE 0x0080000000000000ull
+#define XCT_MACTX_VLAN_INSERT 0x0100000000000000ull
+#define XCT_MACTX_VLAN_REPLACE 0x0180000000000000ull
+#define XCT_MACTX_CRC_M 0x0060000000000000ull
+#define XCT_MACTX_CRC_NOP 0x0000000000000000ull
+#define XCT_MACTX_CRC_INSERT 0x0020000000000000ull
+#define XCT_MACTX_CRC_PAD 0x0040000000000000ull
+#define XCT_MACTX_CRC_REPLACE 0x0060000000000000ull
+#define XCT_MACTX_SS 0x0010000000000000ull
+#define XCT_MACTX_LLEN_M 0x00007fff00000000ull
+#define XCT_MACTX_LLEN_S 32ull
+#define XCT_MACTX_LLEN(x) ((((long)(x)) << XCT_MACTX_LLEN_S) & \
+ XCT_MACTX_LLEN_M)
+#define XCT_MACTX_IPH_M 0x00000000f8000000ull
+#define XCT_MACTX_IPH_S 27ull
+#define XCT_MACTX_IPH(x) ((((long)(x)) << XCT_MACTX_IPH_S) & \
+ XCT_MACTX_IPH_M)
+#define XCT_MACTX_IPO_M 0x0000000007c00000ull
+#define XCT_MACTX_IPO_S 22ull
+#define XCT_MACTX_IPO(x) ((((long)(x)) << XCT_MACTX_IPO_S) & \
+ XCT_MACTX_IPO_M)
+#define XCT_MACTX_CSUM_M 0x0000000000000060ull
+#define XCT_MACTX_CSUM_NOP 0x0000000000000000ull
+#define XCT_MACTX_CSUM_TCP 0x0000000000000040ull
+#define XCT_MACTX_CSUM_UDP 0x0000000000000060ull
+#define XCT_MACTX_V6 0x0000000000000010ull
+#define XCT_MACTX_C 0x0000000000000004ull
+#define XCT_MACTX_AL2 0x0000000000000002ull
+
+/* Receive descriptor fields */
+#define XCT_MACRX_T 0x8000000000000000ull
+#define XCT_MACRX_ST 0x4000000000000000ull
+#define XCT_MACRX_NORES 0x0000000000000000ull
+#define XCT_MACRX_8BRES 0x1000000000000000ull
+#define XCT_MACRX_24BRES 0x2000000000000000ull
+#define XCT_MACRX_40BRES 0x3000000000000000ull
+#define XCT_MACRX_O 0x0400000000000000ull
+#define XCT_MACRX_E 0x0200000000000000ull
+#define XCT_MACRX_FF 0x0100000000000000ull
+#define XCT_MACRX_PF 0x0080000000000000ull
+#define XCT_MACRX_OB 0x0040000000000000ull
+#define XCT_MACRX_OD 0x0020000000000000ull
+#define XCT_MACRX_FS 0x0010000000000000ull
+#define XCT_MACRX_NB_M 0x000fc00000000000ull
+#define XCT_MACRX_NB_S 46ULL
+#define XCT_MACRX_NB(x) ((((long)(x)) << XCT_MACRX_NB_S) & \
+ XCT_MACRX_NB_M)
+#define XCT_MACRX_LLEN_M 0x00003fff00000000ull
+#define XCT_MACRX_LLEN_S 32ULL
+#define XCT_MACRX_LLEN(x) ((((long)(x)) << XCT_MACRX_LLEN_S) & \
+ XCT_MACRX_LLEN_M)
+#define XCT_MACRX_CRC 0x0000000080000000ull
+#define XCT_MACRX_LEN_M 0x0000000060000000ull
+#define XCT_MACRX_LEN_TOOSHORT 0x0000000020000000ull
+#define XCT_MACRX_LEN_BELOWMIN 0x0000000040000000ull
+#define XCT_MACRX_LEN_TRUNC 0x0000000060000000ull
+#define XCT_MACRX_CAST_M 0x0000000018000000ull
+#define XCT_MACRX_CAST_UNI 0x0000000000000000ull
+#define XCT_MACRX_CAST_MULTI 0x0000000008000000ull
+#define XCT_MACRX_CAST_BROAD 0x0000000010000000ull
+#define XCT_MACRX_CAST_PAUSE 0x0000000018000000ull
+#define XCT_MACRX_VLC_M 0x0000000006000000ull
+#define XCT_MACRX_FM 0x0000000001000000ull
+#define XCT_MACRX_HTY_M 0x0000000000c00000ull
+#define XCT_MACRX_HTY_IPV4_OK 0x0000000000000000ull
+#define XCT_MACRX_HTY_IPV6 0x0000000000400000ull
+#define XCT_MACRX_HTY_IPV4_BAD 0x0000000000800000ull
+#define XCT_MACRX_HTY_NONIP 0x0000000000c00000ull
+#define XCT_MACRX_IPP_M 0x00000000003f0000ull
+#define XCT_MACRX_IPP_S 16
+#define XCT_MACRX_CSUM_M 0x000000000000ffffull
+#define XCT_MACRX_CSUM_S 0
+
+#define XCT_PTR_T 0x8000000000000000ull
+#define XCT_PTR_LEN_M 0x7ffff00000000000ull
+#define XCT_PTR_LEN_S 44
+#define XCT_PTR_LEN(x) ((((long)(x)) << XCT_PTR_LEN_S) & \
+ XCT_PTR_LEN_M)
+#define XCT_PTR_ADDR_M 0x00000fffffffffffull
+#define XCT_PTR_ADDR_S 0
+#define XCT_PTR_ADDR(x) ((((long)(x)) << XCT_PTR_ADDR_S) & \
+ XCT_PTR_ADDR_M)
+
+/* Receive interface buffer fields */
+#define XCT_RXB_LEN_M 0x0ffff00000000000ull
+#define XCT_RXB_LEN_S 44
+#define XCT_RXB_LEN(x) ((((long)(x)) << XCT_PTR_LEN_S) & XCT_PTR_LEN_M)
+#define XCT_RXB_ADDR_M 0x00000fffffffffffull
+#define XCT_RXB_ADDR_S 0
+#define XCT_RXB_ADDR(x) ((((long)(x)) << XCT_PTR_ADDR_S) & XCT_PTR_ADDR_M)
+
+
+#endif /* PASEMI_MAC_H */
diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c
index 448bf4a7801..c7bd9c1c7f3 100644
--- a/drivers/net/pcmcia/3c574_cs.c
+++ b/drivers/net/pcmcia/3c574_cs.c
@@ -915,7 +915,7 @@ static void media_check(unsigned long arg)
if ((inw(ioaddr + EL3_STATUS) & IntLatch) && (inb(ioaddr + Timer) == 0xff)) {
if (!lp->fast_poll)
printk(KERN_INFO "%s: interrupt(s) dropped!\n", dev->name);
- el3_interrupt(dev->irq, lp);
+ el3_interrupt(dev->irq, dev);
lp->fast_poll = HZ;
}
if (lp->fast_poll) {
diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c
index 530df8883fe..2561f76033e 100644
--- a/drivers/net/pcmcia/smc91c92_cs.c
+++ b/drivers/net/pcmcia/smc91c92_cs.c
@@ -1927,7 +1927,7 @@ static void media_check(u_long arg)
if (smc->watchdog++ && ((i>>8) & i)) {
if (!smc->fast_poll)
printk(KERN_INFO "%s: interrupt(s) dropped!\n", dev->name);
- smc_interrupt(dev->irq, smc);
+ smc_interrupt(dev->irq, dev);
smc->fast_poll = HZ;
}
if (smc->fast_poll) {
diff --git a/drivers/net/phy/cicada.c b/drivers/net/phy/cicada.c
index ae60e6e4107..a1bd599c8a5 100644
--- a/drivers/net/phy/cicada.c
+++ b/drivers/net/phy/cicada.c
@@ -14,7 +14,6 @@
*
*/
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/unistd.h>
diff --git a/drivers/net/phy/davicom.c b/drivers/net/phy/davicom.c
index aa7983f5583..519baa38be8 100644
--- a/drivers/net/phy/davicom.c
+++ b/drivers/net/phy/davicom.c
@@ -14,7 +14,6 @@
*
*/
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/unistd.h>
diff --git a/drivers/net/phy/fixed.c b/drivers/net/phy/fixed.c
index 86135397f43..66da91bb138 100644
--- a/drivers/net/phy/fixed.c
+++ b/drivers/net/phy/fixed.c
@@ -14,7 +14,6 @@
*
*/
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/unistd.h>
diff --git a/drivers/net/phy/lxt.c b/drivers/net/phy/lxt.c
index 69d2325f848..4cf3324ba16 100644
--- a/drivers/net/phy/lxt.c
+++ b/drivers/net/phy/lxt.c
@@ -14,7 +14,6 @@
*
*/
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/unistd.h>
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index 0ad253282d0..22aec5cce68 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -14,7 +14,6 @@
*
*/
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/unistd.h>
@@ -43,6 +42,19 @@
#define MII_M1011_IMASK_INIT 0x6400
#define MII_M1011_IMASK_CLEAR 0x0000
+#define MII_M1011_PHY_SCR 0x10
+#define MII_M1011_PHY_SCR_AUTO_CROSS 0x0060
+
+#define MII_M1145_PHY_EXT_CR 0x14
+#define MII_M1145_RGMII_RX_DELAY 0x0080
+#define MII_M1145_RGMII_TX_DELAY 0x0002
+
+#define M1145_DEV_FLAGS_RESISTANCE 0x00000001
+
+#define MII_M1111_PHY_LED_CONTROL 0x18
+#define MII_M1111_PHY_LED_DIRECT 0x4100
+#define MII_M1111_PHY_LED_COMBINE 0x411c
+
MODULE_DESCRIPTION("Marvell PHY driver");
MODULE_AUTHOR("Andy Fleming");
MODULE_LICENSE("GPL");
@@ -64,7 +76,7 @@ static int marvell_config_intr(struct phy_device *phydev)
{
int err;
- if(phydev->interrupts == PHY_INTERRUPT_ENABLED)
+ if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
err = phy_write(phydev, MII_M1011_IMASK, MII_M1011_IMASK_INIT);
else
err = phy_write(phydev, MII_M1011_IMASK, MII_M1011_IMASK_CLEAR);
@@ -104,34 +116,153 @@ static int marvell_config_aneg(struct phy_device *phydev)
if (err < 0)
return err;
+ err = phy_write(phydev, MII_M1011_PHY_SCR,
+ MII_M1011_PHY_SCR_AUTO_CROSS);
+ if (err < 0)
+ return err;
+
+ err = phy_write(phydev, MII_M1111_PHY_LED_CONTROL,
+ MII_M1111_PHY_LED_DIRECT);
+ if (err < 0)
+ return err;
err = genphy_config_aneg(phydev);
return err;
}
+static int m88e1145_config_init(struct phy_device *phydev)
+{
+ int err;
+
+ /* Take care of errata E0 & E1 */
+ err = phy_write(phydev, 0x1d, 0x001b);
+ if (err < 0)
+ return err;
+
+ err = phy_write(phydev, 0x1e, 0x418f);
+ if (err < 0)
+ return err;
+
+ err = phy_write(phydev, 0x1d, 0x0016);
+ if (err < 0)
+ return err;
+
+ err = phy_write(phydev, 0x1e, 0xa2da);
+ if (err < 0)
+ return err;
+
+ if (phydev->interface == PHY_INTERFACE_MODE_RGMII) {
+ int temp = phy_read(phydev, MII_M1145_PHY_EXT_CR);
+ if (temp < 0)
+ return temp;
+
+ temp |= (MII_M1145_RGMII_RX_DELAY | MII_M1145_RGMII_TX_DELAY);
+
+ err = phy_write(phydev, MII_M1145_PHY_EXT_CR, temp);
+ if (err < 0)
+ return err;
+
+ if (phydev->dev_flags & M1145_DEV_FLAGS_RESISTANCE) {
+ err = phy_write(phydev, 0x1d, 0x0012);
+ if (err < 0)
+ return err;
+
+ temp = phy_read(phydev, 0x1e);
+ if (temp < 0)
+ return temp;
+
+ temp &= 0xf03f;
+ temp |= 2 << 9; /* 36 ohm */
+ temp |= 2 << 6; /* 39 ohm */
+
+ err = phy_write(phydev, 0x1e, temp);
+ if (err < 0)
+ return err;
+
+ err = phy_write(phydev, 0x1d, 0x3);
+ if (err < 0)
+ return err;
+
+ err = phy_write(phydev, 0x1e, 0x8000);
+ if (err < 0)
+ return err;
+ }
+ }
+
+ return 0;
+}
static struct phy_driver m88e1101_driver = {
- .phy_id = 0x01410c00,
- .phy_id_mask = 0xffffff00,
- .name = "Marvell 88E1101",
- .features = PHY_GBIT_FEATURES,
- .flags = PHY_HAS_INTERRUPT,
- .config_aneg = &marvell_config_aneg,
- .read_status = &genphy_read_status,
- .ack_interrupt = &marvell_ack_interrupt,
- .config_intr = &marvell_config_intr,
- .driver = { .owner = THIS_MODULE,},
+ .phy_id = 0x01410c60,
+ .phy_id_mask = 0xfffffff0,
+ .name = "Marvell 88E1101",
+ .features = PHY_GBIT_FEATURES,
+ .flags = PHY_HAS_INTERRUPT,
+ .config_aneg = &marvell_config_aneg,
+ .read_status = &genphy_read_status,
+ .ack_interrupt = &marvell_ack_interrupt,
+ .config_intr = &marvell_config_intr,
+ .driver = {.owner = THIS_MODULE,},
+};
+
+static struct phy_driver m88e1111s_driver = {
+ .phy_id = 0x01410cc0,
+ .phy_id_mask = 0xfffffff0,
+ .name = "Marvell 88E1111",
+ .features = PHY_GBIT_FEATURES,
+ .flags = PHY_HAS_INTERRUPT,
+ .config_aneg = &marvell_config_aneg,
+ .read_status = &genphy_read_status,
+ .ack_interrupt = &marvell_ack_interrupt,
+ .config_intr = &marvell_config_intr,
+ .driver = {.owner = THIS_MODULE,},
+};
+
+static struct phy_driver m88e1145_driver = {
+ .phy_id = 0x01410cd0,
+ .phy_id_mask = 0xfffffff0,
+ .name = "Marvell 88E1145",
+ .features = PHY_GBIT_FEATURES,
+ .flags = PHY_HAS_INTERRUPT,
+ .config_init = &m88e1145_config_init,
+ .config_aneg = &marvell_config_aneg,
+ .read_status = &genphy_read_status,
+ .ack_interrupt = &marvell_ack_interrupt,
+ .config_intr = &marvell_config_intr,
+ .driver = {.owner = THIS_MODULE,},
};
static int __init marvell_init(void)
{
- return phy_driver_register(&m88e1101_driver);
+ int ret;
+
+ ret = phy_driver_register(&m88e1101_driver);
+ if (ret)
+ return ret;
+
+ ret = phy_driver_register(&m88e1111s_driver);
+ if (ret)
+ goto err1111s;
+
+ ret = phy_driver_register(&m88e1145_driver);
+ if (ret)
+ goto err1145;
+
+ return 0;
+
+ err1145:
+ phy_driver_unregister(&m88e1111s_driver);
+ err1111s:
+ phy_driver_unregister(&m88e1101_driver);
+ return ret;
}
static void __exit marvell_exit(void)
{
phy_driver_unregister(&m88e1101_driver);
+ phy_driver_unregister(&m88e1111s_driver);
+ phy_driver_unregister(&m88e1145_driver);
}
module_init(marvell_init);
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index cf6660c93ff..b31ce278bf3 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -14,7 +14,6 @@
*
*/
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/unistd.h>
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 9765fa66146..c94a1fb3a4b 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -16,7 +16,6 @@
*
*/
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/unistd.h>
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index a4d7529ef41..7d5b6d1838c 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -15,7 +15,6 @@
*
*/
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/unistd.h>
@@ -139,7 +138,7 @@ void phy_prepare_link(struct phy_device *phydev,
*/
struct phy_device * phy_connect(struct net_device *dev, const char *phy_id,
void (*handler)(struct net_device *), u32 flags,
- u32 interface)
+ phy_interface_t interface)
{
struct phy_device *phydev;
@@ -188,7 +187,7 @@ static int phy_compare_id(struct device *dev, void *data)
}
struct phy_device *phy_attach(struct net_device *dev,
- const char *phy_id, u32 flags, u32 interface)
+ const char *phy_id, u32 flags, phy_interface_t interface)
{
struct bus_type *bus = &mdio_bus_type;
struct phy_device *phydev;
diff --git a/drivers/net/phy/qsemi.c b/drivers/net/phy/qsemi.c
index 2b50e1739aa..23062d06723 100644
--- a/drivers/net/phy/qsemi.c
+++ b/drivers/net/phy/qsemi.c
@@ -14,7 +14,6 @@
*
*/
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/unistd.h>
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c
index c6de566188e..11b575f8985 100644
--- a/drivers/net/ppp_generic.c
+++ b/drivers/net/ppp_generic.c
@@ -83,7 +83,7 @@ struct ppp_file {
int dead; /* unit/channel has been shut down */
};
-#define PF_TO_X(pf, X) ((X *)((char *)(pf) - offsetof(X, file)))
+#define PF_TO_X(pf, X) container_of(pf, X, file)
#define PF_TO_PPP(pf) PF_TO_X(pf, struct ppp)
#define PF_TO_CHANNEL(pf) PF_TO_X(pf, struct channel)
@@ -834,7 +834,7 @@ static int ppp_unattached_ioctl(struct ppp_file *pf, struct file *file,
return err;
}
-static struct file_operations ppp_device_fops = {
+static const struct file_operations ppp_device_fops = {
.owner = THIS_MODULE,
.read = ppp_read,
.write = ppp_write,
diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c
index 315d5c3fc66..860bb0f60f6 100644
--- a/drivers/net/pppoe.c
+++ b/drivers/net/pppoe.c
@@ -1043,7 +1043,7 @@ static int pppoe_seq_open(struct inode *inode, struct file *file)
return seq_open(file, &pppoe_seq_ops);
}
-static struct file_operations pppoe_seq_fops = {
+static const struct file_operations pppoe_seq_fops = {
.owner = THIS_MODULE,
.open = pppoe_seq_open,
.read = seq_read,
diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c
index 8844c20eac2..a142cdfd947 100644..100755
--- a/drivers/net/qla3xxx.c
+++ b/drivers/net/qla3xxx.c
@@ -22,6 +22,7 @@
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/ip.h>
+#include <linux/in.h>
#include <linux/if_arp.h>
#include <linux/if_ether.h>
#include <linux/netdevice.h>
@@ -63,6 +64,7 @@ MODULE_PARM_DESC(msi, "Turn on Message Signaled Interrupts.");
static struct pci_device_id ql3xxx_pci_tbl[] __devinitdata = {
{PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QL3022_DEVICE_ID)},
+ {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QL3032_DEVICE_ID)},
/* required last entry */
{0,}
};
@@ -1475,6 +1477,10 @@ static int ql_mii_setup(struct ql3_adapter *qdev)
2) << 7))
return -1;
+ if (qdev->device_id == QL3032_DEVICE_ID)
+ ql_write_page0_reg(qdev,
+ &port_regs->macMIIMgmtControlReg, 0x0f00000);
+
/* Divide 125MHz clock by 28 to meet PHY timing requirements */
reg = MAC_MII_CONTROL_CLK_SEL_DIV28;
@@ -1706,18 +1712,42 @@ static void ql_process_mac_tx_intr(struct ql3_adapter *qdev,
struct ob_mac_iocb_rsp *mac_rsp)
{
struct ql_tx_buf_cb *tx_cb;
+ int i;
tx_cb = &qdev->tx_buf[mac_rsp->transaction_id];
pci_unmap_single(qdev->pdev,
- pci_unmap_addr(tx_cb, mapaddr),
- pci_unmap_len(tx_cb, maplen), PCI_DMA_TODEVICE);
- dev_kfree_skb_irq(tx_cb->skb);
+ pci_unmap_addr(&tx_cb->map[0], mapaddr),
+ pci_unmap_len(&tx_cb->map[0], maplen),
+ PCI_DMA_TODEVICE);
+ tx_cb->seg_count--;
+ if (tx_cb->seg_count) {
+ for (i = 1; i < tx_cb->seg_count; i++) {
+ pci_unmap_page(qdev->pdev,
+ pci_unmap_addr(&tx_cb->map[i],
+ mapaddr),
+ pci_unmap_len(&tx_cb->map[i], maplen),
+ PCI_DMA_TODEVICE);
+ }
+ }
qdev->stats.tx_packets++;
qdev->stats.tx_bytes += tx_cb->skb->len;
+ dev_kfree_skb_irq(tx_cb->skb);
tx_cb->skb = NULL;
atomic_inc(&qdev->tx_count);
}
+/*
+ * The difference between 3022 and 3032 for inbound completions:
+ * 3022 uses two buffers per completion. The first buffer contains
+ * (some) header info, the second the remainder of the headers plus
+ * the data. For this chip we reserve some space at the top of the
+ * receive buffer so that the header info in buffer one can be
+ * prepended to the buffer two. Buffer two is the sent up while
+ * buffer one is returned to the hardware to be reused.
+ * 3032 receives all of it's data and headers in one buffer for a
+ * simpler process. 3032 also supports checksum verification as
+ * can be seen in ql_process_macip_rx_intr().
+ */
static void ql_process_mac_rx_intr(struct ql3_adapter *qdev,
struct ib_mac_iocb_rsp *ib_mac_rsp_ptr)
{
@@ -1740,14 +1770,17 @@ static void ql_process_mac_rx_intr(struct ql3_adapter *qdev,
qdev->last_rsp_offset = qdev->small_buf_phy_addr_low + offset;
qdev->small_buf_release_cnt++;
- /* start of first buffer */
- lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr);
- lrg_buf_cb1 = &qdev->lrg_buf[qdev->lrg_buf_index];
- qdev->lrg_buf_release_cnt++;
- if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS)
- qdev->lrg_buf_index = 0;
- curr_ial_ptr++; /* 64-bit pointers require two incs. */
- curr_ial_ptr++;
+ if (qdev->device_id == QL3022_DEVICE_ID) {
+ /* start of first buffer (3022 only) */
+ lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr);
+ lrg_buf_cb1 = &qdev->lrg_buf[qdev->lrg_buf_index];
+ qdev->lrg_buf_release_cnt++;
+ if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS) {
+ qdev->lrg_buf_index = 0;
+ }
+ curr_ial_ptr++; /* 64-bit pointers require two incs. */
+ curr_ial_ptr++;
+ }
/* start of second buffer */
lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr);
@@ -1778,7 +1811,8 @@ static void ql_process_mac_rx_intr(struct ql3_adapter *qdev,
qdev->ndev->last_rx = jiffies;
lrg_buf_cb2->skb = NULL;
- ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb1);
+ if (qdev->device_id == QL3022_DEVICE_ID)
+ ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb1);
ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb2);
}
@@ -1790,7 +1824,7 @@ static void ql_process_macip_rx_intr(struct ql3_adapter *qdev,
struct ql_rcv_buf_cb *lrg_buf_cb1 = NULL;
struct ql_rcv_buf_cb *lrg_buf_cb2 = NULL;
u32 *curr_ial_ptr;
- struct sk_buff *skb1, *skb2;
+ struct sk_buff *skb1 = NULL, *skb2;
struct net_device *ndev = qdev->ndev;
u16 length = le16_to_cpu(ib_ip_rsp_ptr->length);
u16 size = 0;
@@ -1806,16 +1840,20 @@ static void ql_process_macip_rx_intr(struct ql3_adapter *qdev,
qdev->last_rsp_offset = qdev->small_buf_phy_addr_low + offset;
qdev->small_buf_release_cnt++;
- /* start of first buffer */
- lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr);
- lrg_buf_cb1 = &qdev->lrg_buf[qdev->lrg_buf_index];
-
- qdev->lrg_buf_release_cnt++;
- if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS)
- qdev->lrg_buf_index = 0;
- skb1 = lrg_buf_cb1->skb;
- curr_ial_ptr++; /* 64-bit pointers require two incs. */
- curr_ial_ptr++;
+ if (qdev->device_id == QL3022_DEVICE_ID) {
+ /* start of first buffer on 3022 */
+ lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr);
+ lrg_buf_cb1 = &qdev->lrg_buf[qdev->lrg_buf_index];
+ qdev->lrg_buf_release_cnt++;
+ if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS)
+ qdev->lrg_buf_index = 0;
+ skb1 = lrg_buf_cb1->skb;
+ curr_ial_ptr++; /* 64-bit pointers require two incs. */
+ curr_ial_ptr++;
+ size = ETH_HLEN;
+ if (*((u16 *) skb1->data) != 0xFFFF)
+ size += VLAN_ETH_HLEN - ETH_HLEN;
+ }
/* start of second buffer */
lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr);
@@ -1825,18 +1863,6 @@ static void ql_process_macip_rx_intr(struct ql3_adapter *qdev,
if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS)
qdev->lrg_buf_index = 0;
- qdev->stats.rx_packets++;
- qdev->stats.rx_bytes += length;
-
- /*
- * Copy the ethhdr from first buffer to second. This
- * is necessary for IP completions.
- */
- if (*((u16 *) skb1->data) != 0xFFFF)
- size = VLAN_ETH_HLEN;
- else
- size = ETH_HLEN;
-
skb_put(skb2, length); /* Just the second buffer length here. */
pci_unmap_single(qdev->pdev,
pci_unmap_addr(lrg_buf_cb2, mapaddr),
@@ -1844,16 +1870,40 @@ static void ql_process_macip_rx_intr(struct ql3_adapter *qdev,
PCI_DMA_FROMDEVICE);
prefetch(skb2->data);
- memcpy(skb_push(skb2, size), skb1->data + VLAN_ID_LEN, size);
- skb2->dev = qdev->ndev;
skb2->ip_summed = CHECKSUM_NONE;
+ if (qdev->device_id == QL3022_DEVICE_ID) {
+ /*
+ * Copy the ethhdr from first buffer to second. This
+ * is necessary for 3022 IP completions.
+ */
+ memcpy(skb_push(skb2, size), skb1->data + VLAN_ID_LEN, size);
+ } else {
+ u16 checksum = le16_to_cpu(ib_ip_rsp_ptr->checksum);
+ if (checksum &
+ (IB_IP_IOCB_RSP_3032_ICE |
+ IB_IP_IOCB_RSP_3032_CE |
+ IB_IP_IOCB_RSP_3032_NUC)) {
+ printk(KERN_ERR
+ "%s: Bad checksum for this %s packet, checksum = %x.\n",
+ __func__,
+ ((checksum &
+ IB_IP_IOCB_RSP_3032_TCP) ? "TCP" :
+ "UDP"),checksum);
+ } else if (checksum & IB_IP_IOCB_RSP_3032_TCP) {
+ skb2->ip_summed = CHECKSUM_UNNECESSARY;
+ }
+ }
+ skb2->dev = qdev->ndev;
skb2->protocol = eth_type_trans(skb2, qdev->ndev);
netif_receive_skb(skb2);
+ qdev->stats.rx_packets++;
+ qdev->stats.rx_bytes += length;
ndev->last_rx = jiffies;
lrg_buf_cb2->skb = NULL;
- ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb1);
+ if (qdev->device_id == QL3022_DEVICE_ID)
+ ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb1);
ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb2);
}
@@ -1880,12 +1930,14 @@ static int ql_tx_rx_clean(struct ql3_adapter *qdev,
break;
case OPCODE_IB_MAC_IOCB:
+ case OPCODE_IB_3032_MAC_IOCB:
ql_process_mac_rx_intr(qdev, (struct ib_mac_iocb_rsp *)
net_rsp);
(*rx_cleaned)++;
break;
case OPCODE_IB_IP_IOCB:
+ case OPCODE_IB_3032_IP_IOCB:
ql_process_macip_rx_intr(qdev, (struct ib_ip_iocb_rsp *)
net_rsp);
(*rx_cleaned)++;
@@ -2032,13 +2084,96 @@ static irqreturn_t ql3xxx_isr(int irq, void *dev_id)
return IRQ_RETVAL(handled);
}
+/*
+ * Get the total number of segments needed for the
+ * given number of fragments. This is necessary because
+ * outbound address lists (OAL) will be used when more than
+ * two frags are given. Each address list has 5 addr/len
+ * pairs. The 5th pair in each AOL is used to point to
+ * the next AOL if more frags are coming.
+ * That is why the frags:segment count ratio is not linear.
+ */
+static int ql_get_seg_count(unsigned short frags)
+{
+ switch(frags) {
+ case 0: return 1; /* just the skb->data seg */
+ case 1: return 2; /* skb->data + 1 frag */
+ case 2: return 3; /* skb->data + 2 frags */
+ case 3: return 5; /* skb->data + 1 frag + 1 AOL containting 2 frags */
+ case 4: return 6;
+ case 5: return 7;
+ case 6: return 8;
+ case 7: return 10;
+ case 8: return 11;
+ case 9: return 12;
+ case 10: return 13;
+ case 11: return 15;
+ case 12: return 16;
+ case 13: return 17;
+ case 14: return 18;
+ case 15: return 20;
+ case 16: return 21;
+ case 17: return 22;
+ case 18: return 23;
+ }
+ return -1;
+}
+
+static void ql_hw_csum_setup(struct sk_buff *skb,
+ struct ob_mac_iocb_req *mac_iocb_ptr)
+{
+ struct ethhdr *eth;
+ struct iphdr *ip = NULL;
+ u8 offset = ETH_HLEN;
+
+ eth = (struct ethhdr *)(skb->data);
+
+ if (eth->h_proto == __constant_htons(ETH_P_IP)) {
+ ip = (struct iphdr *)&skb->data[ETH_HLEN];
+ } else if (eth->h_proto == htons(ETH_P_8021Q) &&
+ ((struct vlan_ethhdr *)skb->data)->
+ h_vlan_encapsulated_proto == __constant_htons(ETH_P_IP)) {
+ ip = (struct iphdr *)&skb->data[VLAN_ETH_HLEN];
+ offset = VLAN_ETH_HLEN;
+ }
+
+ if (ip) {
+ if (ip->protocol == IPPROTO_TCP) {
+ mac_iocb_ptr->flags1 |= OB_3032MAC_IOCB_REQ_TC;
+ mac_iocb_ptr->ip_hdr_off = offset;
+ mac_iocb_ptr->ip_hdr_len = ip->ihl;
+ } else if (ip->protocol == IPPROTO_UDP) {
+ mac_iocb_ptr->flags1 |= OB_3032MAC_IOCB_REQ_UC;
+ mac_iocb_ptr->ip_hdr_off = offset;
+ mac_iocb_ptr->ip_hdr_len = ip->ihl;
+ }
+ }
+}
+
+/*
+ * The difference between 3022 and 3032 sends:
+ * 3022 only supports a simple single segment transmission.
+ * 3032 supports checksumming and scatter/gather lists (fragments).
+ * The 3032 supports sglists by using the 3 addr/len pairs (ALP)
+ * in the IOCB plus a chain of outbound address lists (OAL) that
+ * each contain 5 ALPs. The last ALP of the IOCB (3rd) or OAL (5th)
+ * will used to point to an OAL when more ALP entries are required.
+ * The IOCB is always the top of the chain followed by one or more
+ * OALs (when necessary).
+ */
static int ql3xxx_send(struct sk_buff *skb, struct net_device *ndev)
{
struct ql3_adapter *qdev = (struct ql3_adapter *)netdev_priv(ndev);
struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
struct ql_tx_buf_cb *tx_cb;
+ u32 tot_len = skb->len;
+ struct oal *oal;
+ struct oal_entry *oal_entry;
+ int len;
struct ob_mac_iocb_req *mac_iocb_ptr;
u64 map;
+ int seg_cnt, seg = 0;
+ int frag_cnt = (int)skb_shinfo(skb)->nr_frags;
if (unlikely(atomic_read(&qdev->tx_count) < 2)) {
if (!netif_queue_stopped(ndev))
@@ -2046,21 +2181,79 @@ static int ql3xxx_send(struct sk_buff *skb, struct net_device *ndev)
return NETDEV_TX_BUSY;
}
tx_cb = &qdev->tx_buf[qdev->req_producer_index] ;
+ seg_cnt = tx_cb->seg_count = ql_get_seg_count((skb_shinfo(skb)->nr_frags));
+ if(seg_cnt == -1) {
+ printk(KERN_ERR PFX"%s: invalid segment count!\n",__func__);
+ return NETDEV_TX_OK;
+
+ }
mac_iocb_ptr = tx_cb->queue_entry;
memset((void *)mac_iocb_ptr, 0, sizeof(struct ob_mac_iocb_req));
mac_iocb_ptr->opcode = qdev->mac_ob_opcode;
mac_iocb_ptr->flags |= qdev->mb_bit_mask;
mac_iocb_ptr->transaction_id = qdev->req_producer_index;
- mac_iocb_ptr->data_len = cpu_to_le16((u16) skb->len);
+ mac_iocb_ptr->data_len = cpu_to_le16((u16) tot_len);
tx_cb->skb = skb;
- map = pci_map_single(qdev->pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
- mac_iocb_ptr->buf_addr0_low = cpu_to_le32(LS_64BITS(map));
- mac_iocb_ptr->buf_addr0_high = cpu_to_le32(MS_64BITS(map));
- mac_iocb_ptr->buf_0_len = cpu_to_le32(skb->len | OB_MAC_IOCB_REQ_E);
- pci_unmap_addr_set(tx_cb, mapaddr, map);
- pci_unmap_len_set(tx_cb, maplen, skb->len);
- atomic_dec(&qdev->tx_count);
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
+ ql_hw_csum_setup(skb, mac_iocb_ptr);
+ len = skb_headlen(skb);
+ map = pci_map_single(qdev->pdev, skb->data, len, PCI_DMA_TODEVICE);
+ oal_entry = (struct oal_entry *)&mac_iocb_ptr->buf_addr0_low;
+ oal_entry->dma_lo = cpu_to_le32(LS_64BITS(map));
+ oal_entry->dma_hi = cpu_to_le32(MS_64BITS(map));
+ oal_entry->len = cpu_to_le32(len);
+ pci_unmap_addr_set(&tx_cb->map[seg], mapaddr, map);
+ pci_unmap_len_set(&tx_cb->map[seg], maplen, len);
+ seg++;
+
+ if (!skb_shinfo(skb)->nr_frags) {
+ /* Terminate the last segment. */
+ oal_entry->len =
+ cpu_to_le32(le32_to_cpu(oal_entry->len) | OAL_LAST_ENTRY);
+ } else {
+ int i;
+ oal = tx_cb->oal;
+ for (i=0; i<frag_cnt; i++,seg++) {
+ skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+ oal_entry++;
+ if ((seg == 2 && seg_cnt > 3) || /* Check for continuation */
+ (seg == 7 && seg_cnt > 8) || /* requirements. It's strange */
+ (seg == 12 && seg_cnt > 13) || /* but necessary. */
+ (seg == 17 && seg_cnt > 18)) {
+ /* Continuation entry points to outbound address list. */
+ map = pci_map_single(qdev->pdev, oal,
+ sizeof(struct oal),
+ PCI_DMA_TODEVICE);
+ oal_entry->dma_lo = cpu_to_le32(LS_64BITS(map));
+ oal_entry->dma_hi = cpu_to_le32(MS_64BITS(map));
+ oal_entry->len =
+ cpu_to_le32(sizeof(struct oal) |
+ OAL_CONT_ENTRY);
+ pci_unmap_addr_set(&tx_cb->map[seg], mapaddr,
+ map);
+ pci_unmap_len_set(&tx_cb->map[seg], maplen,
+ len);
+ oal_entry = (struct oal_entry *)oal;
+ oal++;
+ seg++;
+ }
+ map =
+ pci_map_page(qdev->pdev, frag->page,
+ frag->page_offset, frag->size,
+ PCI_DMA_TODEVICE);
+ oal_entry->dma_lo = cpu_to_le32(LS_64BITS(map));
+ oal_entry->dma_hi = cpu_to_le32(MS_64BITS(map));
+ oal_entry->len = cpu_to_le32(frag->size);
+ pci_unmap_addr_set(&tx_cb->map[seg], mapaddr, map);
+ pci_unmap_len_set(&tx_cb->map[seg], maplen,
+ frag->size);
+ }
+ /* Terminate the last segment. */
+ oal_entry->len =
+ cpu_to_le32(le32_to_cpu(oal_entry->len) | OAL_LAST_ENTRY);
+ }
+ wmb();
qdev->req_producer_index++;
if (qdev->req_producer_index == NUM_REQ_Q_ENTRIES)
qdev->req_producer_index = 0;
@@ -2074,8 +2267,10 @@ static int ql3xxx_send(struct sk_buff *skb, struct net_device *ndev)
printk(KERN_DEBUG PFX "%s: tx queued, slot %d, len %d\n",
ndev->name, qdev->req_producer_index, skb->len);
+ atomic_dec(&qdev->tx_count);
return NETDEV_TX_OK;
}
+
static int ql_alloc_net_req_rsp_queues(struct ql3_adapter *qdev)
{
qdev->req_q_size =
@@ -2359,7 +2554,22 @@ static int ql_alloc_large_buffers(struct ql3_adapter *qdev)
return 0;
}
-static void ql_create_send_free_list(struct ql3_adapter *qdev)
+static void ql_free_send_free_list(struct ql3_adapter *qdev)
+{
+ struct ql_tx_buf_cb *tx_cb;
+ int i;
+
+ tx_cb = &qdev->tx_buf[0];
+ for (i = 0; i < NUM_REQ_Q_ENTRIES; i++) {
+ if (tx_cb->oal) {
+ kfree(tx_cb->oal);
+ tx_cb->oal = NULL;
+ }
+ tx_cb++;
+ }
+}
+
+static int ql_create_send_free_list(struct ql3_adapter *qdev)
{
struct ql_tx_buf_cb *tx_cb;
int i;
@@ -2368,11 +2578,16 @@ static void ql_create_send_free_list(struct ql3_adapter *qdev)
/* Create free list of transmit buffers */
for (i = 0; i < NUM_REQ_Q_ENTRIES; i++) {
+
tx_cb = &qdev->tx_buf[i];
tx_cb->skb = NULL;
tx_cb->queue_entry = req_q_curr;
req_q_curr++;
+ tx_cb->oal = kmalloc(512, GFP_KERNEL);
+ if (tx_cb->oal == NULL)
+ return -1;
}
+ return 0;
}
static int ql_alloc_mem_resources(struct ql3_adapter *qdev)
@@ -2447,12 +2662,14 @@ static int ql_alloc_mem_resources(struct ql3_adapter *qdev)
/* Initialize the large buffer queue. */
ql_init_large_buffers(qdev);
- ql_create_send_free_list(qdev);
+ if (ql_create_send_free_list(qdev))
+ goto err_free_list;
qdev->rsp_current = qdev->rsp_q_virt_addr;
return 0;
-
+err_free_list:
+ ql_free_send_free_list(qdev);
err_small_buffers:
ql_free_buffer_queues(qdev);
err_buffer_queues:
@@ -2468,6 +2685,7 @@ err_req_rsp:
static void ql_free_mem_resources(struct ql3_adapter *qdev)
{
+ ql_free_send_free_list(qdev);
ql_free_large_buffers(qdev);
ql_free_small_buffers(qdev);
ql_free_buffer_queues(qdev);
@@ -2766,11 +2984,20 @@ static int ql_adapter_initialize(struct ql3_adapter *qdev)
}
/* Enable Ethernet Function */
- value =
- (PORT_CONTROL_EF | PORT_CONTROL_ET | PORT_CONTROL_EI |
- PORT_CONTROL_HH);
- ql_write_page0_reg(qdev, &port_regs->portControl,
- ((value << 16) | value));
+ if (qdev->device_id == QL3032_DEVICE_ID) {
+ value =
+ (QL3032_PORT_CONTROL_EF | QL3032_PORT_CONTROL_KIE |
+ QL3032_PORT_CONTROL_EIv6 | QL3032_PORT_CONTROL_EIv4);
+ ql_write_page0_reg(qdev, &port_regs->functionControl,
+ ((value << 16) | value));
+ } else {
+ value =
+ (PORT_CONTROL_EF | PORT_CONTROL_ET | PORT_CONTROL_EI |
+ PORT_CONTROL_HH);
+ ql_write_page0_reg(qdev, &port_regs->portControl,
+ ((value << 16) | value));
+ }
+
out:
return status;
@@ -2917,8 +3144,10 @@ static void ql_display_dev_info(struct net_device *ndev)
struct pci_dev *pdev = qdev->pdev;
printk(KERN_INFO PFX
- "\n%s Adapter %d RevisionID %d found on PCI slot %d.\n",
- DRV_NAME, qdev->index, qdev->chip_rev_id, qdev->pci_slot);
+ "\n%s Adapter %d RevisionID %d found %s on PCI slot %d.\n",
+ DRV_NAME, qdev->index, qdev->chip_rev_id,
+ (qdev->device_id == QL3032_DEVICE_ID) ? "QLA3032" : "QLA3022",
+ qdev->pci_slot);
printk(KERN_INFO PFX
"%s Interface.\n",
test_bit(QL_LINK_OPTICAL,&qdev->flags) ? "OPTICAL" : "COPPER");
@@ -2999,7 +3228,7 @@ static int ql_adapter_up(struct ql3_adapter *qdev)
{
struct net_device *ndev = qdev->ndev;
int err;
- unsigned long irq_flags = SA_SAMPLE_RANDOM | SA_SHIRQ;
+ unsigned long irq_flags = IRQF_SAMPLE_RANDOM | IRQF_SHARED;
unsigned long hw_flags;
if (ql_alloc_mem_resources(qdev)) {
@@ -3018,7 +3247,7 @@ static int ql_adapter_up(struct ql3_adapter *qdev)
} else {
printk(KERN_INFO PFX "%s: MSI Enabled...\n", qdev->ndev->name);
set_bit(QL_MSI_ENABLED,&qdev->flags);
- irq_flags &= ~SA_SHIRQ;
+ irq_flags &= ~IRQF_SHARED;
}
}
@@ -3212,15 +3441,22 @@ static void ql_reset_work(struct work_struct *work)
* Loop through the active list and return the skb.
*/
for (i = 0; i < NUM_REQ_Q_ENTRIES; i++) {
+ int j;
tx_cb = &qdev->tx_buf[i];
if (tx_cb->skb) {
-
printk(KERN_DEBUG PFX
"%s: Freeing lost SKB.\n",
qdev->ndev->name);
pci_unmap_single(qdev->pdev,
- pci_unmap_addr(tx_cb, mapaddr),
- pci_unmap_len(tx_cb, maplen), PCI_DMA_TODEVICE);
+ pci_unmap_addr(&tx_cb->map[0], mapaddr),
+ pci_unmap_len(&tx_cb->map[0], maplen),
+ PCI_DMA_TODEVICE);
+ for(j=1;j<tx_cb->seg_count;j++) {
+ pci_unmap_page(qdev->pdev,
+ pci_unmap_addr(&tx_cb->map[j],mapaddr),
+ pci_unmap_len(&tx_cb->map[j],maplen),
+ PCI_DMA_TODEVICE);
+ }
dev_kfree_skb(tx_cb->skb);
tx_cb->skb = NULL;
}
@@ -3379,21 +3615,24 @@ static int __devinit ql3xxx_probe(struct pci_dev *pdev,
SET_MODULE_OWNER(ndev);
SET_NETDEV_DEV(ndev, &pdev->dev);
- if (pci_using_dac)
- ndev->features |= NETIF_F_HIGHDMA;
-
pci_set_drvdata(pdev, ndev);
qdev = netdev_priv(ndev);
qdev->index = cards_found;
qdev->ndev = ndev;
qdev->pdev = pdev;
+ qdev->device_id = pci_entry->device;
qdev->port_link_state = LS_DOWN;
if (msi)
qdev->msi = 1;
qdev->msg_enable = netif_msg_init(debug, default_msg);
+ if (pci_using_dac)
+ ndev->features |= NETIF_F_HIGHDMA;
+ if (qdev->device_id == QL3032_DEVICE_ID)
+ ndev->features |= (NETIF_F_HW_CSUM | NETIF_F_SG);
+
qdev->mem_map_registers =
ioremap_nocache(pci_resource_start(pdev, 1),
pci_resource_len(qdev->pdev, 1));
diff --git a/drivers/net/qla3xxx.h b/drivers/net/qla3xxx.h
index ea94de7fd07..b2d76ea6882 100644..100755
--- a/drivers/net/qla3xxx.h
+++ b/drivers/net/qla3xxx.h
@@ -21,7 +21,9 @@
#define OPCODE_UPDATE_NCB_IOCB 0xF0
#define OPCODE_IB_MAC_IOCB 0xF9
+#define OPCODE_IB_3032_MAC_IOCB 0x09
#define OPCODE_IB_IP_IOCB 0xFA
+#define OPCODE_IB_3032_IP_IOCB 0x0A
#define OPCODE_IB_TCP_IOCB 0xFB
#define OPCODE_DUMP_PROTO_IOCB 0xFE
#define OPCODE_BUFFER_ALERT_IOCB 0xFB
@@ -37,18 +39,23 @@
struct ob_mac_iocb_req {
u8 opcode;
u8 flags;
-#define OB_MAC_IOCB_REQ_MA 0xC0
-#define OB_MAC_IOCB_REQ_F 0x20
-#define OB_MAC_IOCB_REQ_X 0x10
+#define OB_MAC_IOCB_REQ_MA 0xe0
+#define OB_MAC_IOCB_REQ_F 0x10
+#define OB_MAC_IOCB_REQ_X 0x08
#define OB_MAC_IOCB_REQ_D 0x02
#define OB_MAC_IOCB_REQ_I 0x01
- __le16 reserved0;
+ u8 flags1;
+#define OB_3032MAC_IOCB_REQ_IC 0x04
+#define OB_3032MAC_IOCB_REQ_TC 0x02
+#define OB_3032MAC_IOCB_REQ_UC 0x01
+ u8 reserved0;
__le32 transaction_id;
__le16 data_len;
- __le16 reserved1;
+ u8 ip_hdr_off;
+ u8 ip_hdr_len;
+ __le32 reserved1;
__le32 reserved2;
- __le32 reserved3;
__le32 buf_addr0_low;
__le32 buf_addr0_high;
__le32 buf_0_len;
@@ -58,8 +65,8 @@ struct ob_mac_iocb_req {
__le32 buf_addr2_low;
__le32 buf_addr2_high;
__le32 buf_2_len;
+ __le32 reserved3;
__le32 reserved4;
- __le32 reserved5;
};
/*
* The following constants define control bits for buffer
@@ -74,6 +81,7 @@ struct ob_mac_iocb_rsp {
u8 opcode;
u8 flags;
#define OB_MAC_IOCB_RSP_P 0x08
+#define OB_MAC_IOCB_RSP_L 0x04
#define OB_MAC_IOCB_RSP_S 0x02
#define OB_MAC_IOCB_RSP_I 0x01
@@ -85,6 +93,7 @@ struct ob_mac_iocb_rsp {
struct ib_mac_iocb_rsp {
u8 opcode;
+#define IB_MAC_IOCB_RSP_V 0x80
u8 flags;
#define IB_MAC_IOCB_RSP_S 0x80
#define IB_MAC_IOCB_RSP_H1 0x40
@@ -138,6 +147,7 @@ struct ob_ip_iocb_req {
struct ob_ip_iocb_rsp {
u8 opcode;
u8 flags;
+#define OB_MAC_IOCB_RSP_H 0x10
#define OB_MAC_IOCB_RSP_E 0x08
#define OB_MAC_IOCB_RSP_L 0x04
#define OB_MAC_IOCB_RSP_S 0x02
@@ -220,6 +230,10 @@ struct ob_tcp_iocb_rsp {
struct ib_ip_iocb_rsp {
u8 opcode;
+#define IB_IP_IOCB_RSP_3032_V 0x80
+#define IB_IP_IOCB_RSP_3032_O 0x40
+#define IB_IP_IOCB_RSP_3032_I 0x20
+#define IB_IP_IOCB_RSP_3032_R 0x10
u8 flags;
#define IB_IP_IOCB_RSP_S 0x80
#define IB_IP_IOCB_RSP_H1 0x40
@@ -230,6 +244,12 @@ struct ib_ip_iocb_rsp {
__le16 length;
__le16 checksum;
+#define IB_IP_IOCB_RSP_3032_ICE 0x01
+#define IB_IP_IOCB_RSP_3032_CE 0x02
+#define IB_IP_IOCB_RSP_3032_NUC 0x04
+#define IB_IP_IOCB_RSP_3032_UDP 0x08
+#define IB_IP_IOCB_RSP_3032_TCP 0x10
+#define IB_IP_IOCB_RSP_3032_IPE 0x20
__le16 reserved;
#define IB_IP_IOCB_RSP_R 0x01
__le32 ial_low;
@@ -524,6 +544,21 @@ enum {
IP_ADDR_INDEX_REG_FUNC_2_SEC = 0x0005,
IP_ADDR_INDEX_REG_FUNC_3_PRI = 0x0006,
IP_ADDR_INDEX_REG_FUNC_3_SEC = 0x0007,
+ IP_ADDR_INDEX_REG_6 = 0x0008,
+ IP_ADDR_INDEX_REG_OFFSET_MASK = 0x0030,
+ IP_ADDR_INDEX_REG_E = 0x0040,
+};
+enum {
+ QL3032_PORT_CONTROL_DS = 0x0001,
+ QL3032_PORT_CONTROL_HH = 0x0002,
+ QL3032_PORT_CONTROL_EIv6 = 0x0004,
+ QL3032_PORT_CONTROL_EIv4 = 0x0008,
+ QL3032_PORT_CONTROL_ET = 0x0010,
+ QL3032_PORT_CONTROL_EF = 0x0020,
+ QL3032_PORT_CONTROL_DRM = 0x0040,
+ QL3032_PORT_CONTROL_RLB = 0x0080,
+ QL3032_PORT_CONTROL_RCB = 0x0100,
+ QL3032_PORT_CONTROL_KIE = 0x0200,
};
enum {
@@ -657,7 +692,8 @@ struct ql3xxx_port_registers {
u32 internalRamWDataReg;
u32 reclaimedBufferAddrRegLow;
u32 reclaimedBufferAddrRegHigh;
- u32 reserved[2];
+ u32 tcpConfiguration;
+ u32 functionControl;
u32 fpgaRevID;
u32 localRamAddr;
u32 localRamDataAutoIncr;
@@ -963,6 +999,7 @@ struct eeprom_data {
#define QL3XXX_VENDOR_ID 0x1077
#define QL3022_DEVICE_ID 0x3022
+#define QL3032_DEVICE_ID 0x3032
/* MTU & Frame Size stuff */
#define NORMAL_MTU_SIZE ETH_DATA_LEN
@@ -1038,11 +1075,41 @@ struct ql_rcv_buf_cb {
int index;
};
+/*
+ * Original IOCB has 3 sg entries:
+ * first points to skb-data area
+ * second points to first frag
+ * third points to next oal.
+ * OAL has 5 entries:
+ * 1 thru 4 point to frags
+ * fifth points to next oal.
+ */
+#define MAX_OAL_CNT ((MAX_SKB_FRAGS-1)/4 + 1)
+
+struct oal_entry {
+ u32 dma_lo;
+ u32 dma_hi;
+ u32 len;
+#define OAL_LAST_ENTRY 0x80000000 /* Last valid buffer in list. */
+#define OAL_CONT_ENTRY 0x40000000 /* points to an OAL. (continuation) */
+ u32 reserved;
+};
+
+struct oal {
+ struct oal_entry oal_entry[5];
+};
+
+struct map_list {
+ DECLARE_PCI_UNMAP_ADDR(mapaddr);
+ DECLARE_PCI_UNMAP_LEN(maplen);
+};
+
struct ql_tx_buf_cb {
struct sk_buff *skb;
struct ob_mac_iocb_req *queue_entry ;
- DECLARE_PCI_UNMAP_ADDR(mapaddr);
- DECLARE_PCI_UNMAP_LEN(maplen);
+ int seg_count;
+ struct oal *oal;
+ struct map_list map[MAX_SKB_FRAGS+1];
};
/* definitions for type field */
@@ -1189,6 +1256,7 @@ struct ql3_adapter {
struct delayed_work reset_work;
struct delayed_work tx_timeout_work;
u32 max_frame_size;
+ u32 device_id;
};
#endif /* _QLA3XXX_H_ */
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index 577babd4c93..13cf06ee97f 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -1733,6 +1733,8 @@ rtl8169_remove_one(struct pci_dev *pdev)
assert(dev != NULL);
assert(tp != NULL);
+ flush_scheduled_work();
+
unregister_netdev(dev);
rtl8169_release_board(pdev, dev, tp->mmio_addr);
pci_set_drvdata(pdev, NULL);
@@ -2016,7 +2018,7 @@ static int rtl8169_alloc_rx_skb(struct pci_dev *pdev, struct sk_buff **sk_buff,
if (!skb)
goto err_out;
- skb_reserve(skb, (align - 1) & (u32)skb->data);
+ skb_reserve(skb, (align - 1) & (unsigned long)skb->data);
*sk_buff = skb;
mapping = pci_map_single(pdev, skb->data, rx_buf_sz,
@@ -2161,10 +2163,13 @@ static void rtl8169_reinit_task(struct work_struct *work)
struct net_device *dev = tp->dev;
int ret;
- if (netif_running(dev)) {
- rtl8169_wait_for_quiescence(dev);
- rtl8169_close(dev);
- }
+ rtnl_lock();
+
+ if (!netif_running(dev))
+ goto out_unlock;
+
+ rtl8169_wait_for_quiescence(dev);
+ rtl8169_close(dev);
ret = rtl8169_open(dev);
if (unlikely(ret < 0)) {
@@ -2179,6 +2184,9 @@ static void rtl8169_reinit_task(struct work_struct *work)
}
rtl8169_schedule_work(dev, rtl8169_reinit_task);
}
+
+out_unlock:
+ rtnl_unlock();
}
static void rtl8169_reset_task(struct work_struct *work)
@@ -2187,8 +2195,10 @@ static void rtl8169_reset_task(struct work_struct *work)
container_of(work, struct rtl8169_private, task.work);
struct net_device *dev = tp->dev;
+ rtnl_lock();
+
if (!netif_running(dev))
- return;
+ goto out_unlock;
rtl8169_wait_for_quiescence(dev);
@@ -2210,6 +2220,9 @@ static void rtl8169_reset_task(struct work_struct *work)
}
rtl8169_schedule_work(dev, rtl8169_reset_task);
}
+
+out_unlock:
+ rtnl_unlock();
}
static void rtl8169_tx_timeout(struct net_device *dev)
@@ -2487,7 +2500,7 @@ static inline int rtl8169_try_rx_copy(struct sk_buff **sk_buff, int pkt_size,
skb = dev_alloc_skb(pkt_size + align);
if (skb) {
- skb_reserve(skb, (align - 1) & (u32)skb->data);
+ skb_reserve(skb, (align - 1) & (unsigned long)skb->data);
eth_copy_and_sum(skb, sk_buff[0]->data, pkt_size, 0);
*sk_buff = skb;
rtl8169_mark_to_asic(desc, rx_buf_sz);
@@ -2722,8 +2735,6 @@ static void rtl8169_down(struct net_device *dev)
netif_stop_queue(dev);
- flush_scheduled_work();
-
core_down:
spin_lock_irq(&tp->lock);
diff --git a/drivers/net/s2io-regs.h b/drivers/net/s2io-regs.h
index a914fef4430..0e345cbc2bf 100644
--- a/drivers/net/s2io-regs.h
+++ b/drivers/net/s2io-regs.h
@@ -15,7 +15,7 @@
#define TBD 0
-typedef struct _XENA_dev_config {
+struct XENA_dev_config {
/* Convention: mHAL_XXX is mask, vHAL_XXX is value */
/* General Control-Status Registers */
@@ -300,6 +300,7 @@ typedef struct _XENA_dev_config {
u64 gpio_control;
#define GPIO_CTRL_GPIO_0 BIT(8)
u64 misc_control;
+#define FAULT_BEHAVIOUR BIT(0)
#define EXT_REQ_EN BIT(1)
#define MISC_LINK_STABILITY_PRD(val) vBIT(val,29,3)
@@ -851,9 +852,9 @@ typedef struct _XENA_dev_config {
#define SPI_CONTROL_DONE BIT(6)
u64 spi_data;
#define SPI_DATA_WRITE(data,len) vBIT(data,0,len)
-} XENA_dev_config_t;
+};
-#define XENA_REG_SPACE sizeof(XENA_dev_config_t)
+#define XENA_REG_SPACE sizeof(struct XENA_dev_config)
#define XENA_EEPROM_SPACE (0x01 << 11)
#endif /* _REGS_H */
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
index 1dd66b8ea0f..fd85648d98d 100644
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -59,7 +59,6 @@
#include <linux/stddef.h>
#include <linux/ioctl.h>
#include <linux/timex.h>
-#include <linux/sched.h>
#include <linux/ethtool.h>
#include <linux/workqueue.h>
#include <linux/if_vlan.h>
@@ -77,7 +76,7 @@
#include "s2io.h"
#include "s2io-regs.h"
-#define DRV_VERSION "2.0.15.2"
+#define DRV_VERSION "2.0.16.1"
/* S2io Driver name & version. */
static char s2io_driver_name[] = "Neterion";
@@ -86,7 +85,7 @@ static char s2io_driver_version[] = DRV_VERSION;
static int rxd_size[4] = {32,48,48,64};
static int rxd_count[4] = {127,85,85,63};
-static inline int RXD_IS_UP2DT(RxD_t *rxdp)
+static inline int RXD_IS_UP2DT(struct RxD_t *rxdp)
{
int ret;
@@ -111,9 +110,9 @@ static inline int RXD_IS_UP2DT(RxD_t *rxdp)
#define TASKLET_IN_USE test_and_set_bit(0, (&sp->tasklet_status))
#define PANIC 1
#define LOW 2
-static inline int rx_buffer_level(nic_t * sp, int rxb_size, int ring)
+static inline int rx_buffer_level(struct s2io_nic * sp, int rxb_size, int ring)
{
- mac_info_t *mac_control;
+ struct mac_info *mac_control;
mac_control = &sp->mac_control;
if (rxb_size <= rxd_count[sp->rxd_mode])
@@ -286,7 +285,7 @@ static char ethtool_stats_keys[][ETH_GSTRING_LEN] = {
static void s2io_vlan_rx_register(struct net_device *dev,
struct vlan_group *grp)
{
- nic_t *nic = dev->priv;
+ struct s2io_nic *nic = dev->priv;
unsigned long flags;
spin_lock_irqsave(&nic->tx_lock, flags);
@@ -297,7 +296,7 @@ static void s2io_vlan_rx_register(struct net_device *dev,
/* Unregister the vlan */
static void s2io_vlan_rx_kill_vid(struct net_device *dev, unsigned long vid)
{
- nic_t *nic = dev->priv;
+ struct s2io_nic *nic = dev->priv;
unsigned long flags;
spin_lock_irqsave(&nic->tx_lock, flags);
@@ -401,9 +400,10 @@ S2IO_PARM_INT(lro, 0);
* aggregation happens until we hit max IP pkt size(64K)
*/
S2IO_PARM_INT(lro_max_pkts, 0xFFFF);
-#ifndef CONFIG_S2IO_NAPI
S2IO_PARM_INT(indicate_max_pkts, 0);
-#endif
+
+S2IO_PARM_INT(napi, 1);
+S2IO_PARM_INT(ufo, 0);
static unsigned int tx_fifo_len[MAX_TX_FIFOS] =
{DEFAULT_FIFO_0_LEN, [1 ...(MAX_TX_FIFOS - 1)] = DEFAULT_FIFO_1_7_LEN};
@@ -457,14 +457,14 @@ static int init_shared_mem(struct s2io_nic *nic)
u32 size;
void *tmp_v_addr, *tmp_v_addr_next;
dma_addr_t tmp_p_addr, tmp_p_addr_next;
- RxD_block_t *pre_rxd_blk = NULL;
- int i, j, blk_cnt, rx_sz, tx_sz;
+ struct RxD_block *pre_rxd_blk = NULL;
+ int i, j, blk_cnt;
int lst_size, lst_per_page;
struct net_device *dev = nic->dev;
unsigned long tmp;
- buffAdd_t *ba;
+ struct buffAdd *ba;
- mac_info_t *mac_control;
+ struct mac_info *mac_control;
struct config_param *config;
mac_control = &nic->mac_control;
@@ -482,13 +482,12 @@ static int init_shared_mem(struct s2io_nic *nic)
return -EINVAL;
}
- lst_size = (sizeof(TxD_t) * config->max_txds);
- tx_sz = lst_size * size;
+ lst_size = (sizeof(struct TxD) * config->max_txds);
lst_per_page = PAGE_SIZE / lst_size;
for (i = 0; i < config->tx_fifo_num; i++) {
int fifo_len = config->tx_cfg[i].fifo_len;
- int list_holder_size = fifo_len * sizeof(list_info_hold_t);
+ int list_holder_size = fifo_len * sizeof(struct list_info_hold);
mac_control->fifos[i].list_info = kmalloc(list_holder_size,
GFP_KERNEL);
if (!mac_control->fifos[i].list_info) {
@@ -579,10 +578,9 @@ static int init_shared_mem(struct s2io_nic *nic)
mac_control->rings[i].block_count;
}
if (nic->rxd_mode == RXD_MODE_1)
- size = (size * (sizeof(RxD1_t)));
+ size = (size * (sizeof(struct RxD1)));
else
- size = (size * (sizeof(RxD3_t)));
- rx_sz = size;
+ size = (size * (sizeof(struct RxD3)));
for (i = 0; i < config->rx_ring_num; i++) {
mac_control->rings[i].rx_curr_get_info.block_index = 0;
@@ -600,7 +598,7 @@ static int init_shared_mem(struct s2io_nic *nic)
(rxd_count[nic->rxd_mode] + 1);
/* Allocating all the Rx blocks */
for (j = 0; j < blk_cnt; j++) {
- rx_block_info_t *rx_blocks;
+ struct rx_block_info *rx_blocks;
int l;
rx_blocks = &mac_control->rings[i].rx_blocks[j];
@@ -620,9 +618,11 @@ static int init_shared_mem(struct s2io_nic *nic)
memset(tmp_v_addr, 0, size);
rx_blocks->block_virt_addr = tmp_v_addr;
rx_blocks->block_dma_addr = tmp_p_addr;
- rx_blocks->rxds = kmalloc(sizeof(rxd_info_t)*
+ rx_blocks->rxds = kmalloc(sizeof(struct rxd_info)*
rxd_count[nic->rxd_mode],
GFP_KERNEL);
+ if (!rx_blocks->rxds)
+ return -ENOMEM;
for (l=0; l<rxd_count[nic->rxd_mode];l++) {
rx_blocks->rxds[l].virt_addr =
rx_blocks->block_virt_addr +
@@ -645,7 +645,7 @@ static int init_shared_mem(struct s2io_nic *nic)
mac_control->rings[i].rx_blocks[(j + 1) %
blk_cnt].block_dma_addr;
- pre_rxd_blk = (RxD_block_t *) tmp_v_addr;
+ pre_rxd_blk = (struct RxD_block *) tmp_v_addr;
pre_rxd_blk->reserved_2_pNext_RxD_block =
(unsigned long) tmp_v_addr_next;
pre_rxd_blk->pNext_RxD_Blk_physical =
@@ -661,14 +661,14 @@ static int init_shared_mem(struct s2io_nic *nic)
blk_cnt = config->rx_cfg[i].num_rxd /
(rxd_count[nic->rxd_mode]+ 1);
mac_control->rings[i].ba =
- kmalloc((sizeof(buffAdd_t *) * blk_cnt),
+ kmalloc((sizeof(struct buffAdd *) * blk_cnt),
GFP_KERNEL);
if (!mac_control->rings[i].ba)
return -ENOMEM;
for (j = 0; j < blk_cnt; j++) {
int k = 0;
mac_control->rings[i].ba[j] =
- kmalloc((sizeof(buffAdd_t) *
+ kmalloc((sizeof(struct buffAdd) *
(rxd_count[nic->rxd_mode] + 1)),
GFP_KERNEL);
if (!mac_control->rings[i].ba[j])
@@ -700,7 +700,7 @@ static int init_shared_mem(struct s2io_nic *nic)
}
/* Allocation and initialization of Statistics block */
- size = sizeof(StatInfo_t);
+ size = sizeof(struct stat_block);
mac_control->stats_mem = pci_alloc_consistent
(nic->pdev, size, &mac_control->stats_mem_phy);
@@ -715,7 +715,7 @@ static int init_shared_mem(struct s2io_nic *nic)
mac_control->stats_mem_sz = size;
tmp_v_addr = mac_control->stats_mem;
- mac_control->stats_info = (StatInfo_t *) tmp_v_addr;
+ 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);
@@ -735,7 +735,7 @@ static void free_shared_mem(struct s2io_nic *nic)
int i, j, blk_cnt, size;
void *tmp_v_addr;
dma_addr_t tmp_p_addr;
- mac_info_t *mac_control;
+ struct mac_info *mac_control;
struct config_param *config;
int lst_size, lst_per_page;
struct net_device *dev = nic->dev;
@@ -746,7 +746,7 @@ static void free_shared_mem(struct s2io_nic *nic)
mac_control = &nic->mac_control;
config = &nic->config;
- lst_size = (sizeof(TxD_t) * config->max_txds);
+ lst_size = (sizeof(struct TxD) * config->max_txds);
lst_per_page = PAGE_SIZE / lst_size;
for (i = 0; i < config->tx_fifo_num; i++) {
@@ -809,7 +809,7 @@ static void free_shared_mem(struct s2io_nic *nic)
if (!mac_control->rings[i].ba[j])
continue;
while (k != rxd_count[nic->rxd_mode]) {
- buffAdd_t *ba =
+ struct buffAdd *ba =
&mac_control->rings[i].ba[j][k];
kfree(ba->ba_0_org);
kfree(ba->ba_1_org);
@@ -835,9 +835,9 @@ static void free_shared_mem(struct s2io_nic *nic)
* s2io_verify_pci_mode -
*/
-static int s2io_verify_pci_mode(nic_t *nic)
+static int s2io_verify_pci_mode(struct s2io_nic *nic)
{
- XENA_dev_config_t __iomem *bar0 = nic->bar0;
+ struct XENA_dev_config __iomem *bar0 = nic->bar0;
register u64 val64 = 0;
int mode;
@@ -868,9 +868,9 @@ static int bus_speed[8] = {33, 133, 133, 200, 266, 133, 200, 266};
/**
* s2io_print_pci_mode -
*/
-static int s2io_print_pci_mode(nic_t *nic)
+static int s2io_print_pci_mode(struct s2io_nic *nic)
{
- XENA_dev_config_t __iomem *bar0 = nic->bar0;
+ struct XENA_dev_config __iomem *bar0 = nic->bar0;
register u64 val64 = 0;
int mode;
struct config_param *config = &nic->config;
@@ -938,13 +938,13 @@ static int s2io_print_pci_mode(nic_t *nic)
static int init_nic(struct s2io_nic *nic)
{
- XENA_dev_config_t __iomem *bar0 = nic->bar0;
+ struct XENA_dev_config __iomem *bar0 = nic->bar0;
struct net_device *dev = nic->dev;
register u64 val64 = 0;
void __iomem *add;
u32 time;
int i, j;
- mac_info_t *mac_control;
+ struct mac_info *mac_control;
struct config_param *config;
int dtx_cnt = 0;
unsigned long long mem_share;
@@ -1414,7 +1414,7 @@ static int init_nic(struct s2io_nic *nic)
val64 = TTI_DATA2_MEM_TX_UFC_A(0x10) |
TTI_DATA2_MEM_TX_UFC_B(0x20) |
- TTI_DATA2_MEM_TX_UFC_C(0x70) | TTI_DATA2_MEM_TX_UFC_D(0x80);
+ TTI_DATA2_MEM_TX_UFC_C(0x40) | TTI_DATA2_MEM_TX_UFC_D(0x80);
writeq(val64, &bar0->tti_data2_mem);
val64 = TTI_CMD_MEM_WE | TTI_CMD_MEM_STROBE_NEW_CMD;
@@ -1610,7 +1610,8 @@ static int init_nic(struct s2io_nic *nic)
* that does not start on an ADB to reduce disconnects.
*/
if (nic->device_type == XFRAME_II_DEVICE) {
- val64 = EXT_REQ_EN | MISC_LINK_STABILITY_PRD(3);
+ val64 = FAULT_BEHAVIOUR | EXT_REQ_EN |
+ MISC_LINK_STABILITY_PRD(3);
writeq(val64, &bar0->misc_control);
val64 = readq(&bar0->pic_control2);
val64 &= ~(BIT(13)|BIT(14)|BIT(15));
@@ -1626,7 +1627,7 @@ static int init_nic(struct s2io_nic *nic)
#define LINK_UP_DOWN_INTERRUPT 1
#define MAC_RMAC_ERR_TIMER 2
-static int s2io_link_fault_indication(nic_t *nic)
+static int s2io_link_fault_indication(struct s2io_nic *nic)
{
if (nic->intr_type != INTA)
return MAC_RMAC_ERR_TIMER;
@@ -1649,14 +1650,14 @@ static int s2io_link_fault_indication(nic_t *nic)
static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag)
{
- XENA_dev_config_t __iomem *bar0 = nic->bar0;
+ struct XENA_dev_config __iomem *bar0 = nic->bar0;
register u64 val64 = 0, temp64 = 0;
/* Top level interrupt classification */
/* PIC Interrupts */
if ((mask & (TX_PIC_INTR | RX_PIC_INTR))) {
/* Enable PIC Intrs in the general intr mask register */
- val64 = TXPIC_INT_M | PIC_RX_INT_M;
+ val64 = TXPIC_INT_M;
if (flag == ENABLE_INTRS) {
temp64 = readq(&bar0->general_int_mask);
temp64 &= ~((u64) val64);
@@ -1694,70 +1695,6 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag)
}
}
- /* DMA Interrupts */
- /* Enabling/Disabling Tx DMA interrupts */
- if (mask & TX_DMA_INTR) {
- /* Enable TxDMA Intrs in the general intr mask register */
- val64 = TXDMA_INT_M;
- if (flag == ENABLE_INTRS) {
- temp64 = readq(&bar0->general_int_mask);
- temp64 &= ~((u64) val64);
- writeq(temp64, &bar0->general_int_mask);
- /*
- * Keep all interrupts other than PFC interrupt
- * and PCC interrupt disabled in DMA level.
- */
- val64 = DISABLE_ALL_INTRS & ~(TXDMA_PFC_INT_M |
- TXDMA_PCC_INT_M);
- writeq(val64, &bar0->txdma_int_mask);
- /*
- * Enable only the MISC error 1 interrupt in PFC block
- */
- val64 = DISABLE_ALL_INTRS & (~PFC_MISC_ERR_1);
- writeq(val64, &bar0->pfc_err_mask);
- /*
- * Enable only the FB_ECC error interrupt in PCC block
- */
- val64 = DISABLE_ALL_INTRS & (~PCC_FB_ECC_ERR);
- writeq(val64, &bar0->pcc_err_mask);
- } else if (flag == DISABLE_INTRS) {
- /*
- * Disable TxDMA Intrs in the general intr mask
- * register
- */
- writeq(DISABLE_ALL_INTRS, &bar0->txdma_int_mask);
- writeq(DISABLE_ALL_INTRS, &bar0->pfc_err_mask);
- temp64 = readq(&bar0->general_int_mask);
- val64 |= temp64;
- writeq(val64, &bar0->general_int_mask);
- }
- }
-
- /* Enabling/Disabling Rx DMA interrupts */
- if (mask & RX_DMA_INTR) {
- /* Enable RxDMA Intrs in the general intr mask register */
- val64 = RXDMA_INT_M;
- if (flag == ENABLE_INTRS) {
- temp64 = readq(&bar0->general_int_mask);
- temp64 &= ~((u64) val64);
- writeq(temp64, &bar0->general_int_mask);
- /*
- * All RxDMA block interrupts are disabled for now
- * TODO
- */
- writeq(DISABLE_ALL_INTRS, &bar0->rxdma_int_mask);
- } else if (flag == DISABLE_INTRS) {
- /*
- * Disable RxDMA Intrs in the general intr mask
- * register
- */
- writeq(DISABLE_ALL_INTRS, &bar0->rxdma_int_mask);
- temp64 = readq(&bar0->general_int_mask);
- val64 |= temp64;
- writeq(val64, &bar0->general_int_mask);
- }
- }
-
/* MAC Interrupts */
/* Enabling/Disabling MAC interrupts */
if (mask & (TX_MAC_INTR | RX_MAC_INTR)) {
@@ -1784,53 +1721,6 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag)
}
}
- /* XGXS Interrupts */
- if (mask & (TX_XGXS_INTR | RX_XGXS_INTR)) {
- val64 = TXXGXS_INT_M | RXXGXS_INT_M;
- if (flag == ENABLE_INTRS) {
- temp64 = readq(&bar0->general_int_mask);
- temp64 &= ~((u64) val64);
- writeq(temp64, &bar0->general_int_mask);
- /*
- * All XGXS block error interrupts are disabled for now
- * TODO
- */
- writeq(DISABLE_ALL_INTRS, &bar0->xgxs_int_mask);
- } else if (flag == DISABLE_INTRS) {
- /*
- * Disable MC Intrs in the general intr mask register
- */
- writeq(DISABLE_ALL_INTRS, &bar0->xgxs_int_mask);
- temp64 = readq(&bar0->general_int_mask);
- val64 |= temp64;
- writeq(val64, &bar0->general_int_mask);
- }
- }
-
- /* Memory Controller(MC) interrupts */
- if (mask & MC_INTR) {
- val64 = MC_INT_M;
- if (flag == ENABLE_INTRS) {
- temp64 = readq(&bar0->general_int_mask);
- temp64 &= ~((u64) val64);
- writeq(temp64, &bar0->general_int_mask);
- /*
- * Enable all MC Intrs.
- */
- writeq(0x0, &bar0->mc_int_mask);
- writeq(0x0, &bar0->mc_err_mask);
- } else if (flag == DISABLE_INTRS) {
- /*
- * Disable MC Intrs in the general intr mask register
- */
- writeq(DISABLE_ALL_INTRS, &bar0->mc_int_mask);
- temp64 = readq(&bar0->general_int_mask);
- val64 |= temp64;
- writeq(val64, &bar0->general_int_mask);
- }
- }
-
-
/* Tx traffic interrupts */
if (mask & TX_TRAFFIC_INTR) {
val64 = TXTRAFFIC_INT_M;
@@ -1877,41 +1767,36 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag)
}
}
-static int check_prc_pcc_state(u64 val64, int flag, int rev_id, int herc)
+/**
+ * verify_pcc_quiescent- Checks for PCC quiescent state
+ * Return: 1 If PCC is quiescence
+ * 0 If PCC is not quiescence
+ */
+static int verify_pcc_quiescent(struct s2io_nic *sp, int flag)
{
- int ret = 0;
+ int ret = 0, herc;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
+ u64 val64 = readq(&bar0->adapter_status);
+
+ herc = (sp->device_type == XFRAME_II_DEVICE);
if (flag == FALSE) {
- if ((!herc && (rev_id >= 4)) || herc) {
- if (!(val64 & ADAPTER_STATUS_RMAC_PCC_IDLE) &&
- ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ==
- ADAPTER_STATUS_RC_PRC_QUIESCENT)) {
+ if ((!herc && (get_xena_rev_id(sp->pdev) >= 4)) || herc) {
+ if (!(val64 & ADAPTER_STATUS_RMAC_PCC_IDLE))
ret = 1;
- }
- }else {
- if (!(val64 & ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE) &&
- ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ==
- ADAPTER_STATUS_RC_PRC_QUIESCENT)) {
+ } else {
+ if (!(val64 & ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE))
ret = 1;
- }
}
} else {
- if ((!herc && (rev_id >= 4)) || herc) {
+ if ((!herc && (get_xena_rev_id(sp->pdev) >= 4)) || herc) {
if (((val64 & ADAPTER_STATUS_RMAC_PCC_IDLE) ==
- ADAPTER_STATUS_RMAC_PCC_IDLE) &&
- (!(val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ||
- ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ==
- ADAPTER_STATUS_RC_PRC_QUIESCENT))) {
+ ADAPTER_STATUS_RMAC_PCC_IDLE))
ret = 1;
- }
} else {
if (((val64 & ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE) ==
- ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE) &&
- (!(val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ||
- ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ==
- ADAPTER_STATUS_RC_PRC_QUIESCENT))) {
+ ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE))
ret = 1;
- }
}
}
@@ -1919,9 +1804,6 @@ static int check_prc_pcc_state(u64 val64, int flag, int rev_id, int herc)
}
/**
* verify_xena_quiescence - Checks whether the H/W is ready
- * @val64 : Value read from adapter status register.
- * @flag : indicates if the adapter enable bit was ever written once
- * before.
* Description: Returns whether the H/W is ready to go or not. Depending
* on whether adapter enable bit was written or not the comparison
* differs and the calling function passes the input argument flag to
@@ -1930,24 +1812,63 @@ static int check_prc_pcc_state(u64 val64, int flag, int rev_id, int herc)
* 0 If Xena is not quiescence
*/
-static int verify_xena_quiescence(nic_t *sp, u64 val64, int flag)
+static int verify_xena_quiescence(struct s2io_nic *sp)
{
- int ret = 0, herc;
- u64 tmp64 = ~((u64) val64);
- int rev_id = get_xena_rev_id(sp->pdev);
+ int mode;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
+ u64 val64 = readq(&bar0->adapter_status);
+ mode = s2io_verify_pci_mode(sp);
- herc = (sp->device_type == XFRAME_II_DEVICE);
- if (!
- (tmp64 &
- (ADAPTER_STATUS_TDMA_READY | ADAPTER_STATUS_RDMA_READY |
- ADAPTER_STATUS_PFC_READY | ADAPTER_STATUS_TMAC_BUF_EMPTY |
- ADAPTER_STATUS_PIC_QUIESCENT | ADAPTER_STATUS_MC_DRAM_READY |
- ADAPTER_STATUS_MC_QUEUES_READY | ADAPTER_STATUS_M_PLL_LOCK |
- ADAPTER_STATUS_P_PLL_LOCK))) {
- ret = check_prc_pcc_state(val64, flag, rev_id, herc);
+ if (!(val64 & ADAPTER_STATUS_TDMA_READY)) {
+ DBG_PRINT(ERR_DBG, "%s", "TDMA is not ready!");
+ return 0;
+ }
+ if (!(val64 & ADAPTER_STATUS_RDMA_READY)) {
+ DBG_PRINT(ERR_DBG, "%s", "RDMA is not ready!");
+ return 0;
+ }
+ if (!(val64 & ADAPTER_STATUS_PFC_READY)) {
+ DBG_PRINT(ERR_DBG, "%s", "PFC is not ready!");
+ return 0;
+ }
+ if (!(val64 & ADAPTER_STATUS_TMAC_BUF_EMPTY)) {
+ DBG_PRINT(ERR_DBG, "%s", "TMAC BUF is not empty!");
+ return 0;
+ }
+ if (!(val64 & ADAPTER_STATUS_PIC_QUIESCENT)) {
+ DBG_PRINT(ERR_DBG, "%s", "PIC is not QUIESCENT!");
+ return 0;
+ }
+ if (!(val64 & ADAPTER_STATUS_MC_DRAM_READY)) {
+ DBG_PRINT(ERR_DBG, "%s", "MC_DRAM is not ready!");
+ return 0;
+ }
+ if (!(val64 & ADAPTER_STATUS_MC_QUEUES_READY)) {
+ DBG_PRINT(ERR_DBG, "%s", "MC_QUEUES is not ready!");
+ return 0;
+ }
+ if (!(val64 & ADAPTER_STATUS_M_PLL_LOCK)) {
+ DBG_PRINT(ERR_DBG, "%s", "M_PLL is not locked!");
+ return 0;
}
- return ret;
+ /*
+ * In PCI 33 mode, the P_PLL is not used, and therefore,
+ * the the P_PLL_LOCK bit in the adapter_status register will
+ * not be asserted.
+ */
+ if (!(val64 & ADAPTER_STATUS_P_PLL_LOCK) &&
+ sp->device_type == XFRAME_II_DEVICE && mode !=
+ PCI_MODE_PCI_33) {
+ DBG_PRINT(ERR_DBG, "%s", "P_PLL is not locked!");
+ return 0;
+ }
+ if (!((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ==
+ ADAPTER_STATUS_RC_PRC_QUIESCENT)) {
+ DBG_PRINT(ERR_DBG, "%s", "RC_PRC is not QUIESCENT!");
+ return 0;
+ }
+ return 1;
}
/**
@@ -1958,9 +1879,9 @@ static int verify_xena_quiescence(nic_t *sp, u64 val64, int flag)
*
*/
-static void fix_mac_address(nic_t * sp)
+static void fix_mac_address(struct s2io_nic * sp)
{
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
u64 val64;
int i = 0;
@@ -1986,11 +1907,11 @@ static void fix_mac_address(nic_t * sp)
static int start_nic(struct s2io_nic *nic)
{
- XENA_dev_config_t __iomem *bar0 = nic->bar0;
+ struct XENA_dev_config __iomem *bar0 = nic->bar0;
struct net_device *dev = nic->dev;
register u64 val64 = 0;
u16 subid, i;
- mac_info_t *mac_control;
+ struct mac_info *mac_control;
struct config_param *config;
mac_control = &nic->mac_control;
@@ -2052,7 +1973,7 @@ static int start_nic(struct s2io_nic *nic)
* it.
*/
val64 = readq(&bar0->adapter_status);
- if (!verify_xena_quiescence(nic, val64, nic->device_enabled_once)) {
+ if (!verify_xena_quiescence(nic)) {
DBG_PRINT(ERR_DBG, "%s: device is not ready, ", dev->name);
DBG_PRINT(ERR_DBG, "Adapter status reads: 0x%llx\n",
(unsigned long long) val64);
@@ -2095,11 +2016,12 @@ static int start_nic(struct s2io_nic *nic)
/**
* s2io_txdl_getskb - Get the skb from txdl, unmap and return skb
*/
-static struct sk_buff *s2io_txdl_getskb(fifo_info_t *fifo_data, TxD_t *txdlp, int get_off)
+static struct sk_buff *s2io_txdl_getskb(struct fifo_info *fifo_data, struct \
+ TxD *txdlp, int get_off)
{
- nic_t *nic = fifo_data->nic;
+ struct s2io_nic *nic = fifo_data->nic;
struct sk_buff *skb;
- TxD_t *txds;
+ struct TxD *txds;
u16 j, frg_cnt;
txds = txdlp;
@@ -2113,7 +2035,7 @@ static struct sk_buff *s2io_txdl_getskb(fifo_info_t *fifo_data, TxD_t *txdlp, in
skb = (struct sk_buff *) ((unsigned long)
txds->Host_Control);
if (!skb) {
- memset(txdlp, 0, (sizeof(TxD_t) * fifo_data->max_txds));
+ memset(txdlp, 0, (sizeof(struct TxD) * fifo_data->max_txds));
return NULL;
}
pci_unmap_single(nic->pdev, (dma_addr_t)
@@ -2132,7 +2054,7 @@ static struct sk_buff *s2io_txdl_getskb(fifo_info_t *fifo_data, TxD_t *txdlp, in
frag->size, PCI_DMA_TODEVICE);
}
}
- memset(txdlp,0, (sizeof(TxD_t) * fifo_data->max_txds));
+ memset(txdlp,0, (sizeof(struct TxD) * fifo_data->max_txds));
return(skb);
}
@@ -2148,9 +2070,9 @@ static void free_tx_buffers(struct s2io_nic *nic)
{
struct net_device *dev = nic->dev;
struct sk_buff *skb;
- TxD_t *txdp;
+ struct TxD *txdp;
int i, j;
- mac_info_t *mac_control;
+ struct mac_info *mac_control;
struct config_param *config;
int cnt = 0;
@@ -2159,7 +2081,7 @@ static void free_tx_buffers(struct s2io_nic *nic)
for (i = 0; i < config->tx_fifo_num; i++) {
for (j = 0; j < config->tx_cfg[i].fifo_len - 1; j++) {
- txdp = (TxD_t *) mac_control->fifos[i].list_info[j].
+ txdp = (struct TxD *) mac_control->fifos[i].list_info[j].
list_virt_addr;
skb = s2io_txdl_getskb(&mac_control->fifos[i], txdp, j);
if (skb) {
@@ -2187,10 +2109,10 @@ static void free_tx_buffers(struct s2io_nic *nic)
static void stop_nic(struct s2io_nic *nic)
{
- XENA_dev_config_t __iomem *bar0 = nic->bar0;
+ struct XENA_dev_config __iomem *bar0 = nic->bar0;
register u64 val64 = 0;
u16 interruptible;
- mac_info_t *mac_control;
+ struct mac_info *mac_control;
struct config_param *config;
mac_control = &nic->mac_control;
@@ -2208,14 +2130,15 @@ static void stop_nic(struct s2io_nic *nic)
writeq(val64, &bar0->adapter_control);
}
-static int fill_rxd_3buf(nic_t *nic, RxD_t *rxdp, struct sk_buff *skb)
+static int fill_rxd_3buf(struct s2io_nic *nic, struct RxD_t *rxdp, struct \
+ sk_buff *skb)
{
struct net_device *dev = nic->dev;
struct sk_buff *frag_list;
void *tmp;
/* Buffer-1 receives L3/L4 headers */
- ((RxD3_t*)rxdp)->Buffer1_ptr = pci_map_single
+ ((struct RxD3*)rxdp)->Buffer1_ptr = pci_map_single
(nic->pdev, skb->data, l3l4hdr_size + 4,
PCI_DMA_FROMDEVICE);
@@ -2226,13 +2149,14 @@ static int fill_rxd_3buf(nic_t *nic, RxD_t *rxdp, struct sk_buff *skb)
return -ENOMEM ;
}
frag_list = skb_shinfo(skb)->frag_list;
+ skb->truesize += frag_list->truesize;
frag_list->next = NULL;
tmp = (void *)ALIGN((long)frag_list->data, ALIGN_SIZE + 1);
frag_list->data = tmp;
frag_list->tail = tmp;
/* Buffer-2 receives L4 data payload */
- ((RxD3_t*)rxdp)->Buffer2_ptr = pci_map_single(nic->pdev,
+ ((struct RxD3*)rxdp)->Buffer2_ptr = pci_map_single(nic->pdev,
frag_list->data, dev->mtu,
PCI_DMA_FROMDEVICE);
rxdp->Control_2 |= SET_BUFFER1_SIZE_3(l3l4hdr_size + 4);
@@ -2266,18 +2190,16 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
{
struct net_device *dev = nic->dev;
struct sk_buff *skb;
- RxD_t *rxdp;
+ struct RxD_t *rxdp;
int off, off1, size, block_no, block_no1;
u32 alloc_tab = 0;
u32 alloc_cnt;
- mac_info_t *mac_control;
+ struct mac_info *mac_control;
struct config_param *config;
u64 tmp;
- buffAdd_t *ba;
-#ifndef CONFIG_S2IO_NAPI
+ struct buffAdd *ba;
unsigned long flags;
-#endif
- RxD_t *first_rxdp = NULL;
+ struct RxD_t *first_rxdp = NULL;
mac_control = &nic->mac_control;
config = &nic->config;
@@ -2320,12 +2242,15 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
DBG_PRINT(INTR_DBG, "%s: Next block at: %p\n",
dev->name, rxdp);
}
-#ifndef CONFIG_S2IO_NAPI
- spin_lock_irqsave(&nic->put_lock, flags);
- mac_control->rings[ring_no].put_pos =
- (block_no * (rxd_count[nic->rxd_mode] + 1)) + off;
- spin_unlock_irqrestore(&nic->put_lock, flags);
-#endif
+ if(!napi) {
+ spin_lock_irqsave(&nic->put_lock, flags);
+ mac_control->rings[ring_no].put_pos =
+ (block_no * (rxd_count[nic->rxd_mode] + 1)) + off;
+ spin_unlock_irqrestore(&nic->put_lock, flags);
+ } else {
+ mac_control->rings[ring_no].put_pos =
+ (block_no * (rxd_count[nic->rxd_mode] + 1)) + off;
+ }
if ((rxdp->Control_1 & RXD_OWN_XENA) &&
((nic->rxd_mode >= RXD_MODE_3A) &&
(rxdp->Control_2 & BIT(0)))) {
@@ -2356,9 +2281,9 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
}
if (nic->rxd_mode == RXD_MODE_1) {
/* 1 buffer mode - normal operation mode */
- memset(rxdp, 0, sizeof(RxD1_t));
+ memset(rxdp, 0, sizeof(struct RxD1));
skb_reserve(skb, NET_IP_ALIGN);
- ((RxD1_t*)rxdp)->Buffer0_ptr = pci_map_single
+ ((struct RxD1*)rxdp)->Buffer0_ptr = pci_map_single
(nic->pdev, skb->data, size - NET_IP_ALIGN,
PCI_DMA_FROMDEVICE);
rxdp->Control_2 = SET_BUFFER0_SIZE_1(size - NET_IP_ALIGN);
@@ -2375,7 +2300,7 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
* payload
*/
- memset(rxdp, 0, sizeof(RxD3_t));
+ memset(rxdp, 0, sizeof(struct RxD3));
ba = &mac_control->rings[ring_no].ba[block_no][off];
skb_reserve(skb, BUF0_LEN);
tmp = (u64)(unsigned long) skb->data;
@@ -2384,13 +2309,13 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
skb->data = (void *) (unsigned long)tmp;
skb->tail = (void *) (unsigned long)tmp;
- if (!(((RxD3_t*)rxdp)->Buffer0_ptr))
- ((RxD3_t*)rxdp)->Buffer0_ptr =
+ if (!(((struct RxD3*)rxdp)->Buffer0_ptr))
+ ((struct RxD3*)rxdp)->Buffer0_ptr =
pci_map_single(nic->pdev, ba->ba_0, BUF0_LEN,
PCI_DMA_FROMDEVICE);
else
pci_dma_sync_single_for_device(nic->pdev,
- (dma_addr_t) ((RxD3_t*)rxdp)->Buffer0_ptr,
+ (dma_addr_t) ((struct RxD3*)rxdp)->Buffer0_ptr,
BUF0_LEN, PCI_DMA_FROMDEVICE);
rxdp->Control_2 = SET_BUFFER0_SIZE_3(BUF0_LEN);
if (nic->rxd_mode == RXD_MODE_3B) {
@@ -2400,13 +2325,13 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
* Buffer2 will have L3/L4 header plus
* L4 payload
*/
- ((RxD3_t*)rxdp)->Buffer2_ptr = pci_map_single
+ ((struct RxD3*)rxdp)->Buffer2_ptr = pci_map_single
(nic->pdev, skb->data, dev->mtu + 4,
PCI_DMA_FROMDEVICE);
/* Buffer-1 will be dummy buffer. Not used */
- if (!(((RxD3_t*)rxdp)->Buffer1_ptr)) {
- ((RxD3_t*)rxdp)->Buffer1_ptr =
+ if (!(((struct RxD3*)rxdp)->Buffer1_ptr)) {
+ ((struct RxD3*)rxdp)->Buffer1_ptr =
pci_map_single(nic->pdev,
ba->ba_1, BUF1_LEN,
PCI_DMA_FROMDEVICE);
@@ -2466,9 +2391,9 @@ static void free_rxd_blk(struct s2io_nic *sp, int ring_no, int blk)
struct net_device *dev = sp->dev;
int j;
struct sk_buff *skb;
- RxD_t *rxdp;
- mac_info_t *mac_control;
- buffAdd_t *ba;
+ struct RxD_t *rxdp;
+ struct mac_info *mac_control;
+ struct buffAdd *ba;
mac_control = &sp->mac_control;
for (j = 0 ; j < rxd_count[sp->rxd_mode]; j++) {
@@ -2481,41 +2406,41 @@ static void free_rxd_blk(struct s2io_nic *sp, int ring_no, int blk)
}
if (sp->rxd_mode == RXD_MODE_1) {
pci_unmap_single(sp->pdev, (dma_addr_t)
- ((RxD1_t*)rxdp)->Buffer0_ptr,
+ ((struct RxD1*)rxdp)->Buffer0_ptr,
dev->mtu +
HEADER_ETHERNET_II_802_3_SIZE
+ HEADER_802_2_SIZE +
HEADER_SNAP_SIZE,
PCI_DMA_FROMDEVICE);
- memset(rxdp, 0, sizeof(RxD1_t));
+ memset(rxdp, 0, sizeof(struct RxD1));
} else if(sp->rxd_mode == RXD_MODE_3B) {
ba = &mac_control->rings[ring_no].
ba[blk][j];
pci_unmap_single(sp->pdev, (dma_addr_t)
- ((RxD3_t*)rxdp)->Buffer0_ptr,
+ ((struct RxD3*)rxdp)->Buffer0_ptr,
BUF0_LEN,
PCI_DMA_FROMDEVICE);
pci_unmap_single(sp->pdev, (dma_addr_t)
- ((RxD3_t*)rxdp)->Buffer1_ptr,
+ ((struct RxD3*)rxdp)->Buffer1_ptr,
BUF1_LEN,
PCI_DMA_FROMDEVICE);
pci_unmap_single(sp->pdev, (dma_addr_t)
- ((RxD3_t*)rxdp)->Buffer2_ptr,
+ ((struct RxD3*)rxdp)->Buffer2_ptr,
dev->mtu + 4,
PCI_DMA_FROMDEVICE);
- memset(rxdp, 0, sizeof(RxD3_t));
+ memset(rxdp, 0, sizeof(struct RxD3));
} else {
pci_unmap_single(sp->pdev, (dma_addr_t)
- ((RxD3_t*)rxdp)->Buffer0_ptr, BUF0_LEN,
+ ((struct RxD3*)rxdp)->Buffer0_ptr, BUF0_LEN,
PCI_DMA_FROMDEVICE);
pci_unmap_single(sp->pdev, (dma_addr_t)
- ((RxD3_t*)rxdp)->Buffer1_ptr,
+ ((struct RxD3*)rxdp)->Buffer1_ptr,
l3l4hdr_size + 4,
PCI_DMA_FROMDEVICE);
pci_unmap_single(sp->pdev, (dma_addr_t)
- ((RxD3_t*)rxdp)->Buffer2_ptr, dev->mtu,
+ ((struct RxD3*)rxdp)->Buffer2_ptr, dev->mtu,
PCI_DMA_FROMDEVICE);
- memset(rxdp, 0, sizeof(RxD3_t));
+ memset(rxdp, 0, sizeof(struct RxD3));
}
dev_kfree_skb(skb);
atomic_dec(&sp->rx_bufs_left[ring_no]);
@@ -2535,7 +2460,7 @@ static void free_rx_buffers(struct s2io_nic *sp)
{
struct net_device *dev = sp->dev;
int i, blk = 0, buf_cnt = 0;
- mac_info_t *mac_control;
+ struct mac_info *mac_control;
struct config_param *config;
mac_control = &sp->mac_control;
@@ -2568,15 +2493,13 @@ static void free_rx_buffers(struct s2io_nic *sp)
* 0 on success and 1 if there are No Rx packets to be processed.
*/
-#if defined(CONFIG_S2IO_NAPI)
static int s2io_poll(struct net_device *dev, int *budget)
{
- nic_t *nic = dev->priv;
+ struct s2io_nic *nic = dev->priv;
int pkt_cnt = 0, org_pkts_to_process;
- mac_info_t *mac_control;
+ struct mac_info *mac_control;
struct config_param *config;
- XENA_dev_config_t __iomem *bar0 = nic->bar0;
- u64 val64 = 0xFFFFFFFFFFFFFFFFULL;
+ struct XENA_dev_config __iomem *bar0 = nic->bar0;
int i;
atomic_inc(&nic->isr_cnt);
@@ -2588,8 +2511,8 @@ static int s2io_poll(struct net_device *dev, int *budget)
nic->pkts_to_process = dev->quota;
org_pkts_to_process = nic->pkts_to_process;
- writeq(val64, &bar0->rx_traffic_int);
- val64 = readl(&bar0->rx_traffic_int);
+ writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int);
+ readl(&bar0->rx_traffic_int);
for (i = 0; i < config->rx_ring_num; i++) {
rx_intr_handler(&mac_control->rings[i]);
@@ -2615,7 +2538,7 @@ static int s2io_poll(struct net_device *dev, int *budget)
}
/* Re enable the Rx interrupts. */
writeq(0x0, &bar0->rx_traffic_mask);
- val64 = readl(&bar0->rx_traffic_mask);
+ readl(&bar0->rx_traffic_mask);
atomic_dec(&nic->isr_cnt);
return 0;
@@ -2633,7 +2556,6 @@ no_rx:
atomic_dec(&nic->isr_cnt);
return 1;
}
-#endif
#ifdef CONFIG_NET_POLL_CONTROLLER
/**
@@ -2647,10 +2569,10 @@ no_rx:
*/
static void s2io_netpoll(struct net_device *dev)
{
- nic_t *nic = dev->priv;
- mac_info_t *mac_control;
+ struct s2io_nic *nic = dev->priv;
+ struct mac_info *mac_control;
struct config_param *config;
- XENA_dev_config_t __iomem *bar0 = nic->bar0;
+ struct XENA_dev_config __iomem *bar0 = nic->bar0;
u64 val64 = 0xFFFFFFFFFFFFFFFFULL;
int i;
@@ -2699,17 +2621,15 @@ static void s2io_netpoll(struct net_device *dev)
* Return Value:
* NONE.
*/
-static void rx_intr_handler(ring_info_t *ring_data)
+static void rx_intr_handler(struct ring_info *ring_data)
{
- nic_t *nic = ring_data->nic;
+ struct s2io_nic *nic = ring_data->nic;
struct net_device *dev = (struct net_device *) nic->dev;
int get_block, put_block, put_offset;
- rx_curr_get_info_t get_info, put_info;
- RxD_t *rxdp;
+ struct rx_curr_get_info get_info, put_info;
+ struct RxD_t *rxdp;
struct sk_buff *skb;
-#ifndef CONFIG_S2IO_NAPI
int pkt_cnt = 0;
-#endif
int i;
spin_lock(&nic->rx_lock);
@@ -2722,19 +2642,21 @@ static void rx_intr_handler(ring_info_t *ring_data)
get_info = ring_data->rx_curr_get_info;
get_block = get_info.block_index;
- put_info = ring_data->rx_curr_put_info;
+ memcpy(&put_info, &ring_data->rx_curr_put_info, sizeof(put_info));
put_block = put_info.block_index;
rxdp = ring_data->rx_blocks[get_block].rxds[get_info.offset].virt_addr;
-#ifndef CONFIG_S2IO_NAPI
- spin_lock(&nic->put_lock);
- put_offset = ring_data->put_pos;
- spin_unlock(&nic->put_lock);
-#else
- put_offset = (put_block * (rxd_count[nic->rxd_mode] + 1)) +
- put_info.offset;
-#endif
+ if (!napi) {
+ spin_lock(&nic->put_lock);
+ put_offset = ring_data->put_pos;
+ spin_unlock(&nic->put_lock);
+ } else
+ put_offset = ring_data->put_pos;
+
while (RXD_IS_UP2DT(rxdp)) {
- /* If your are next to put index then it's FIFO full condition */
+ /*
+ * If your are next to put index then it's
+ * FIFO full condition
+ */
if ((get_block == put_block) &&
(get_info.offset + 1) == put_info.offset) {
DBG_PRINT(INTR_DBG, "%s: Ring Full\n",dev->name);
@@ -2750,7 +2672,7 @@ static void rx_intr_handler(ring_info_t *ring_data)
}
if (nic->rxd_mode == RXD_MODE_1) {
pci_unmap_single(nic->pdev, (dma_addr_t)
- ((RxD1_t*)rxdp)->Buffer0_ptr,
+ ((struct RxD1*)rxdp)->Buffer0_ptr,
dev->mtu +
HEADER_ETHERNET_II_802_3_SIZE +
HEADER_802_2_SIZE +
@@ -2758,22 +2680,22 @@ static void rx_intr_handler(ring_info_t *ring_data)
PCI_DMA_FROMDEVICE);
} else if (nic->rxd_mode == RXD_MODE_3B) {
pci_dma_sync_single_for_cpu(nic->pdev, (dma_addr_t)
- ((RxD3_t*)rxdp)->Buffer0_ptr,
+ ((struct RxD3*)rxdp)->Buffer0_ptr,
BUF0_LEN, PCI_DMA_FROMDEVICE);
pci_unmap_single(nic->pdev, (dma_addr_t)
- ((RxD3_t*)rxdp)->Buffer2_ptr,
+ ((struct RxD3*)rxdp)->Buffer2_ptr,
dev->mtu + 4,
PCI_DMA_FROMDEVICE);
} else {
pci_dma_sync_single_for_cpu(nic->pdev, (dma_addr_t)
- ((RxD3_t*)rxdp)->Buffer0_ptr, BUF0_LEN,
+ ((struct RxD3*)rxdp)->Buffer0_ptr, BUF0_LEN,
PCI_DMA_FROMDEVICE);
pci_unmap_single(nic->pdev, (dma_addr_t)
- ((RxD3_t*)rxdp)->Buffer1_ptr,
+ ((struct RxD3*)rxdp)->Buffer1_ptr,
l3l4hdr_size + 4,
PCI_DMA_FROMDEVICE);
pci_unmap_single(nic->pdev, (dma_addr_t)
- ((RxD3_t*)rxdp)->Buffer2_ptr,
+ ((struct RxD3*)rxdp)->Buffer2_ptr,
dev->mtu, PCI_DMA_FROMDEVICE);
}
prefetch(skb->data);
@@ -2792,20 +2714,17 @@ static void rx_intr_handler(ring_info_t *ring_data)
rxdp = ring_data->rx_blocks[get_block].block_virt_addr;
}
-#ifdef CONFIG_S2IO_NAPI
nic->pkts_to_process -= 1;
- if (!nic->pkts_to_process)
+ if ((napi) && (!nic->pkts_to_process))
break;
-#else
pkt_cnt++;
if ((indicate_max_pkts) && (pkt_cnt > indicate_max_pkts))
break;
-#endif
}
if (nic->lro) {
/* Clear all LRO sessions before exiting */
for (i=0; i<MAX_LRO_SESSIONS; i++) {
- lro_t *lro = &nic->lro0_n[i];
+ struct lro *lro = &nic->lro0_n[i];
if (lro->in_use) {
update_L3L4_header(nic, lro);
queue_rx_frame(lro->parent);
@@ -2829,17 +2748,17 @@ static void rx_intr_handler(ring_info_t *ring_data)
* NONE
*/
-static void tx_intr_handler(fifo_info_t *fifo_data)
+static void tx_intr_handler(struct fifo_info *fifo_data)
{
- nic_t *nic = fifo_data->nic;
+ struct s2io_nic *nic = fifo_data->nic;
struct net_device *dev = (struct net_device *) nic->dev;
- tx_curr_get_info_t get_info, put_info;
+ struct tx_curr_get_info get_info, put_info;
struct sk_buff *skb;
- TxD_t *txdlp;
+ struct TxD *txdlp;
get_info = fifo_data->tx_curr_get_info;
- put_info = fifo_data->tx_curr_put_info;
- txdlp = (TxD_t *) fifo_data->list_info[get_info.offset].
+ memcpy(&put_info, &fifo_data->tx_curr_put_info, sizeof(put_info));
+ txdlp = (struct TxD *) fifo_data->list_info[get_info.offset].
list_virt_addr;
while ((!(txdlp->Control_1 & TXD_LIST_OWN_XENA)) &&
(get_info.offset != put_info.offset) &&
@@ -2854,11 +2773,10 @@ static void tx_intr_handler(fifo_info_t *fifo_data)
}
if ((err >> 48) == 0xA) {
DBG_PRINT(TX_DBG, "TxD returned due \
-to loss of link\n");
+ to loss of link\n");
}
else {
- DBG_PRINT(ERR_DBG, "***TxD error \
-%llx\n", err);
+ DBG_PRINT(ERR_DBG, "***TxD error %llx\n", err);
}
}
@@ -2877,7 +2795,7 @@ to loss of link\n");
get_info.offset++;
if (get_info.offset == get_info.fifo_len + 1)
get_info.offset = 0;
- txdlp = (TxD_t *) fifo_data->list_info
+ txdlp = (struct TxD *) fifo_data->list_info
[get_info.offset].list_virt_addr;
fifo_data->tx_curr_get_info.offset =
get_info.offset;
@@ -2902,8 +2820,8 @@ to loss of link\n");
static void s2io_mdio_write(u32 mmd_type, u64 addr, u16 value, struct net_device *dev)
{
u64 val64 = 0x0;
- nic_t *sp = dev->priv;
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct s2io_nic *sp = dev->priv;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
//address transaction
val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
@@ -2951,8 +2869,8 @@ static u64 s2io_mdio_read(u32 mmd_type, u64 addr, struct net_device *dev)
{
u64 val64 = 0x0;
u64 rval64 = 0x0;
- nic_t *sp = dev->priv;
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct s2io_nic *sp = dev->priv;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
/* address transaction */
val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
@@ -3055,8 +2973,8 @@ static void s2io_updt_xpak_counter(struct net_device *dev)
u64 val64 = 0x0;
u64 addr = 0x0;
- nic_t *sp = dev->priv;
- StatInfo_t *stat_info = sp->mac_control.stats_info;
+ struct s2io_nic *sp = dev->priv;
+ struct stat_block *stat_info = sp->mac_control.stats_info;
/* Check the communication with the MDIO slave */
addr = 0x0000;
@@ -3154,10 +3072,12 @@ static void s2io_updt_xpak_counter(struct net_device *dev)
static void alarm_intr_handler(struct s2io_nic *nic)
{
struct net_device *dev = (struct net_device *) nic->dev;
- XENA_dev_config_t __iomem *bar0 = nic->bar0;
+ struct XENA_dev_config __iomem *bar0 = nic->bar0;
register u64 val64 = 0, err_reg = 0;
u64 cnt;
int i;
+ if (atomic_read(&nic->card_state) == CARD_DOWN)
+ return;
nic->mac_control.stats_info->sw_stat.ring_full_cnt = 0;
/* Handling the XPAK counters update */
if(nic->mac_control.stats_info->xpak_stat.xpak_timer_count < 72000) {
@@ -3297,6 +3217,25 @@ static int wait_for_cmd_complete(void __iomem *addr, u64 busy_bit)
}
return ret;
}
+/*
+ * check_pci_device_id - Checks if the device id is supported
+ * @id : device id
+ * Description: Function to check if the pci device id is supported by driver.
+ * Return value: Actual device id if supported else PCI_ANY_ID
+ */
+static u16 check_pci_device_id(u16 id)
+{
+ switch (id) {
+ case PCI_DEVICE_ID_HERC_WIN:
+ case PCI_DEVICE_ID_HERC_UNI:
+ return XFRAME_II_DEVICE;
+ case PCI_DEVICE_ID_S2IO_UNI:
+ case PCI_DEVICE_ID_S2IO_WIN:
+ return XFRAME_I_DEVICE;
+ default:
+ return PCI_ANY_ID;
+ }
+}
/**
* s2io_reset - Resets the card.
@@ -3308,42 +3247,57 @@ static int wait_for_cmd_complete(void __iomem *addr, u64 busy_bit)
* void.
*/
-static void s2io_reset(nic_t * sp)
+static void s2io_reset(struct s2io_nic * sp)
{
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
u64 val64;
u16 subid, pci_cmd;
+ int i;
+ u16 val16;
+ DBG_PRINT(INIT_DBG,"%s - Resetting XFrame card %s\n",
+ __FUNCTION__, sp->dev->name);
/* 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));
+ if (sp->device_type == XFRAME_II_DEVICE) {
+ int ret;
+ ret = pci_set_power_state(sp->pdev, 3);
+ if (!ret)
+ ret = pci_set_power_state(sp->pdev, 0);
+ else {
+ DBG_PRINT(ERR_DBG,"%s PME based SW_Reset failed!\n",
+ __FUNCTION__);
+ goto old_way;
+ }
+ msleep(20);
+ goto new_way;
+ }
+old_way:
val64 = SW_RESET_ALL;
writeq(val64, &bar0->sw_reset);
-
- /*
- * At this stage, if the PCI write is indeed completed, the
- * card is reset and so is the PCI Config space of the device.
- * So a read cannot be issued at this stage on any of the
- * registers to ensure the write into "sw_reset" register
- * has gone through.
- * Question: Is there any system call that will explicitly force
- * all the write commands still pending on the bus to be pushed
- * through?
- * As of now I'am just giving a 250ms delay and hoping that the
- * PCI write to sw_reset register is done by this time.
- */
- msleep(250);
+new_way:
if (strstr(sp->product_name, "CX4")) {
msleep(750);
}
+ msleep(250);
+ for (i = 0; i < S2IO_MAX_PCI_CONFIG_SPACE_REINIT; i++) {
- /* Restore the PCI state saved during initialization. */
- pci_restore_state(sp->pdev);
- pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER,
- pci_cmd);
- s2io_init_pci(sp);
+ /* Restore the PCI state saved during initialization. */
+ pci_restore_state(sp->pdev);
+ pci_read_config_word(sp->pdev, 0x2, &val16);
+ if (check_pci_device_id(val16) != (u16)PCI_ANY_ID)
+ break;
+ msleep(200);
+ }
- msleep(250);
+ if (check_pci_device_id(val16) == (u16)PCI_ANY_ID) {
+ DBG_PRINT(ERR_DBG,"%s SW_Reset failed!\n", __FUNCTION__);
+ }
+
+ pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER, pci_cmd);
+
+ s2io_init_pci(sp);
/* Set swapper to enable I/O register access */
s2io_set_swapper(sp);
@@ -3399,10 +3353,10 @@ static void s2io_reset(nic_t * sp)
* SUCCESS on success and FAILURE on failure.
*/
-static int s2io_set_swapper(nic_t * sp)
+static int s2io_set_swapper(struct s2io_nic * sp)
{
struct net_device *dev = sp->dev;
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
u64 val64, valt, valr;
/*
@@ -3527,9 +3481,9 @@ static int s2io_set_swapper(nic_t * sp)
return SUCCESS;
}
-static int wait_for_msix_trans(nic_t *nic, int i)
+static int wait_for_msix_trans(struct s2io_nic *nic, int i)
{
- XENA_dev_config_t __iomem *bar0 = nic->bar0;
+ struct XENA_dev_config __iomem *bar0 = nic->bar0;
u64 val64;
int ret = 0, cnt = 0;
@@ -3548,9 +3502,9 @@ static int wait_for_msix_trans(nic_t *nic, int i)
return ret;
}
-static void restore_xmsi_data(nic_t *nic)
+static void restore_xmsi_data(struct s2io_nic *nic)
{
- XENA_dev_config_t __iomem *bar0 = nic->bar0;
+ struct XENA_dev_config __iomem *bar0 = nic->bar0;
u64 val64;
int i;
@@ -3566,9 +3520,9 @@ static void restore_xmsi_data(nic_t *nic)
}
}
-static void store_xmsi_data(nic_t *nic)
+static void store_xmsi_data(struct s2io_nic *nic)
{
- XENA_dev_config_t __iomem *bar0 = nic->bar0;
+ struct XENA_dev_config __iomem *bar0 = nic->bar0;
u64 val64, addr, data;
int i;
@@ -3589,9 +3543,9 @@ static void store_xmsi_data(nic_t *nic)
}
}
-int s2io_enable_msi(nic_t *nic)
+int s2io_enable_msi(struct s2io_nic *nic)
{
- XENA_dev_config_t __iomem *bar0 = nic->bar0;
+ struct XENA_dev_config __iomem *bar0 = nic->bar0;
u16 msi_ctrl, msg_val;
struct config_param *config = &nic->config;
struct net_device *dev = nic->dev;
@@ -3639,9 +3593,9 @@ int s2io_enable_msi(nic_t *nic)
return 0;
}
-static int s2io_enable_msi_x(nic_t *nic)
+static int s2io_enable_msi_x(struct s2io_nic *nic)
{
- XENA_dev_config_t __iomem *bar0 = nic->bar0;
+ struct XENA_dev_config __iomem *bar0 = nic->bar0;
u64 tx_mat, rx_mat;
u16 msi_control; /* Temp variable */
int ret, i, j, msix_indx = 1;
@@ -3749,7 +3703,7 @@ static int s2io_enable_msi_x(nic_t *nic)
static int s2io_open(struct net_device *dev)
{
- nic_t *sp = dev->priv;
+ struct s2io_nic *sp = dev->priv;
int err = 0;
/*
@@ -3802,9 +3756,8 @@ hw_init_failed:
static int s2io_close(struct net_device *dev)
{
- nic_t *sp = dev->priv;
+ struct s2io_nic *sp = dev->priv;
- flush_scheduled_work();
netif_stop_queue(dev);
/* Reset card, kill tasklet and free Tx and Rx buffers. */
s2io_card_down(sp);
@@ -3828,15 +3781,15 @@ static int s2io_close(struct net_device *dev)
static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
{
- nic_t *sp = dev->priv;
+ struct s2io_nic *sp = dev->priv;
u16 frg_cnt, frg_len, i, queue, queue_len, put_off, get_off;
register u64 val64;
- TxD_t *txdp;
- TxFIFO_element_t __iomem *tx_fifo;
+ struct TxD *txdp;
+ struct TxFIFO_element __iomem *tx_fifo;
unsigned long flags;
u16 vlan_tag = 0;
int vlan_priority = 0;
- mac_info_t *mac_control;
+ struct mac_info *mac_control;
struct config_param *config;
int offload_type;
@@ -3864,7 +3817,7 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
put_off = (u16) mac_control->fifos[queue].tx_curr_put_info.offset;
get_off = (u16) mac_control->fifos[queue].tx_curr_get_info.offset;
- txdp = (TxD_t *) mac_control->fifos[queue].list_info[put_off].
+ txdp = (struct TxD *) mac_control->fifos[queue].list_info[put_off].
list_virt_addr;
queue_len = mac_control->fifos[queue].tx_curr_put_info.fifo_len + 1;
@@ -3887,12 +3840,10 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
}
offload_type = s2io_offload_type(skb);
-#ifdef NETIF_F_TSO
if (offload_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)) {
txdp->Control_1 |= TXD_TCP_LSO_EN;
txdp->Control_1 |= TXD_TCP_LSO_MSS(s2io_tcp_mss(skb));
}
-#endif
if (skb->ip_summed == CHECKSUM_PARTIAL) {
txdp->Control_2 |=
(TXD_TX_CKO_IPV4_EN | TXD_TX_CKO_TCP_EN |
@@ -3993,13 +3944,13 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
static void
s2io_alarm_handle(unsigned long data)
{
- nic_t *sp = (nic_t *)data;
+ struct s2io_nic *sp = (struct s2io_nic *)data;
alarm_intr_handler(sp);
mod_timer(&sp->alarm_timer, jiffies + HZ / 2);
}
-static int s2io_chk_rx_buffers(nic_t *sp, int rng_n)
+static int s2io_chk_rx_buffers(struct s2io_nic *sp, int rng_n)
{
int rxb_size, level;
@@ -4031,9 +3982,9 @@ static int s2io_chk_rx_buffers(nic_t *sp, int rng_n)
static irqreturn_t s2io_msi_handle(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *) dev_id;
- nic_t *sp = dev->priv;
+ struct s2io_nic *sp = dev->priv;
int i;
- mac_info_t *mac_control;
+ struct mac_info *mac_control;
struct config_param *config;
atomic_inc(&sp->isr_cnt);
@@ -4063,8 +4014,8 @@ static irqreturn_t s2io_msi_handle(int irq, void *dev_id)
static irqreturn_t s2io_msix_ring_handle(int irq, void *dev_id)
{
- ring_info_t *ring = (ring_info_t *)dev_id;
- nic_t *sp = ring->nic;
+ struct ring_info *ring = (struct ring_info *)dev_id;
+ struct s2io_nic *sp = ring->nic;
atomic_inc(&sp->isr_cnt);
@@ -4077,17 +4028,17 @@ static irqreturn_t s2io_msix_ring_handle(int irq, void *dev_id)
static irqreturn_t s2io_msix_fifo_handle(int irq, void *dev_id)
{
- fifo_info_t *fifo = (fifo_info_t *)dev_id;
- nic_t *sp = fifo->nic;
+ struct fifo_info *fifo = (struct fifo_info *)dev_id;
+ struct s2io_nic *sp = fifo->nic;
atomic_inc(&sp->isr_cnt);
tx_intr_handler(fifo);
atomic_dec(&sp->isr_cnt);
return IRQ_HANDLED;
}
-static void s2io_txpic_intr_handle(nic_t *sp)
+static void s2io_txpic_intr_handle(struct s2io_nic *sp)
{
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
u64 val64;
val64 = readq(&bar0->pic_int_status);
@@ -4109,39 +4060,33 @@ static void s2io_txpic_intr_handle(nic_t *sp)
}
else if (val64 & GPIO_INT_REG_LINK_UP) {
val64 = readq(&bar0->adapter_status);
- if (verify_xena_quiescence(sp, val64,
- sp->device_enabled_once)) {
/* Enable Adapter */
- val64 = readq(&bar0->adapter_control);
- val64 |= ADAPTER_CNTL_EN;
- writeq(val64, &bar0->adapter_control);
- val64 |= ADAPTER_LED_ON;
- writeq(val64, &bar0->adapter_control);
- if (!sp->device_enabled_once)
- sp->device_enabled_once = 1;
+ val64 = readq(&bar0->adapter_control);
+ val64 |= ADAPTER_CNTL_EN;
+ writeq(val64, &bar0->adapter_control);
+ val64 |= ADAPTER_LED_ON;
+ writeq(val64, &bar0->adapter_control);
+ if (!sp->device_enabled_once)
+ sp->device_enabled_once = 1;
- s2io_link(sp, LINK_UP);
- /*
- * unmask link down interrupt and mask link-up
- * intr
- */
- val64 = readq(&bar0->gpio_int_mask);
- val64 &= ~GPIO_INT_MASK_LINK_DOWN;
- val64 |= GPIO_INT_MASK_LINK_UP;
- writeq(val64, &bar0->gpio_int_mask);
+ s2io_link(sp, LINK_UP);
+ /*
+ * unmask link down interrupt and mask link-up
+ * intr
+ */
+ val64 = readq(&bar0->gpio_int_mask);
+ val64 &= ~GPIO_INT_MASK_LINK_DOWN;
+ val64 |= GPIO_INT_MASK_LINK_UP;
+ writeq(val64, &bar0->gpio_int_mask);
- }
}else if (val64 & GPIO_INT_REG_LINK_DOWN) {
val64 = readq(&bar0->adapter_status);
- if (verify_xena_quiescence(sp, val64,
- sp->device_enabled_once)) {
- s2io_link(sp, LINK_DOWN);
- /* Link is down so unmaks link up interrupt */
- val64 = readq(&bar0->gpio_int_mask);
- val64 &= ~GPIO_INT_MASK_LINK_UP;
- val64 |= GPIO_INT_MASK_LINK_DOWN;
- writeq(val64, &bar0->gpio_int_mask);
- }
+ s2io_link(sp, LINK_DOWN);
+ /* Link is down so unmaks link up interrupt */
+ val64 = readq(&bar0->gpio_int_mask);
+ val64 &= ~GPIO_INT_MASK_LINK_UP;
+ val64 |= GPIO_INT_MASK_LINK_DOWN;
+ writeq(val64, &bar0->gpio_int_mask);
}
}
val64 = readq(&bar0->gpio_int_mask);
@@ -4163,11 +4108,11 @@ static void s2io_txpic_intr_handle(nic_t *sp)
static irqreturn_t s2io_isr(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *) dev_id;
- nic_t *sp = dev->priv;
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct s2io_nic *sp = dev->priv;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
int i;
- u64 reason = 0, val64, org_mask;
- mac_info_t *mac_control;
+ u64 reason = 0;
+ struct mac_info *mac_control;
struct config_param *config;
atomic_inc(&sp->isr_cnt);
@@ -4185,43 +4130,48 @@ static irqreturn_t s2io_isr(int irq, void *dev_id)
reason = readq(&bar0->general_int_status);
if (!reason) {
- /* The interrupt was not raised by Xena. */
+ /* The interrupt was not raised by us. */
+ atomic_dec(&sp->isr_cnt);
+ return IRQ_NONE;
+ }
+ else if (unlikely(reason == S2IO_MINUS_ONE) ) {
+ /* Disable device and get out */
atomic_dec(&sp->isr_cnt);
return IRQ_NONE;
}
- val64 = 0xFFFFFFFFFFFFFFFFULL;
- /* Store current mask before masking all interrupts */
- org_mask = readq(&bar0->general_int_mask);
- writeq(val64, &bar0->general_int_mask);
+ if (napi) {
+ if (reason & GEN_INTR_RXTRAFFIC) {
+ if ( likely ( netif_rx_schedule_prep(dev)) ) {
+ __netif_rx_schedule(dev);
+ writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_mask);
+ }
+ else
+ writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int);
+ }
+ } else {
+ /*
+ * Rx handler is called by default, without checking for the
+ * cause of interrupt.
+ * rx_traffic_int reg is an R1 register, writing all 1's
+ * will ensure that the actual interrupt causing bit get's
+ * cleared and hence a read can be avoided.
+ */
+ if (reason & GEN_INTR_RXTRAFFIC)
+ writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int);
-#ifdef CONFIG_S2IO_NAPI
- if (reason & GEN_INTR_RXTRAFFIC) {
- if (netif_rx_schedule_prep(dev)) {
- writeq(val64, &bar0->rx_traffic_mask);
- __netif_rx_schedule(dev);
+ for (i = 0; i < config->rx_ring_num; i++) {
+ rx_intr_handler(&mac_control->rings[i]);
}
}
-#else
- /*
- * Rx handler is called by default, without checking for the
- * cause of interrupt.
- * rx_traffic_int reg is an R1 register, writing all 1's
- * will ensure that the actual interrupt causing bit get's
- * cleared and hence a read can be avoided.
- */
- writeq(val64, &bar0->rx_traffic_int);
- for (i = 0; i < config->rx_ring_num; i++) {
- rx_intr_handler(&mac_control->rings[i]);
- }
-#endif
/*
* tx_traffic_int reg is an R1 register, writing all 1's
* will ensure that the actual interrupt causing bit get's
* cleared and hence a read can be avoided.
*/
- writeq(val64, &bar0->tx_traffic_int);
+ if (reason & GEN_INTR_TXTRAFFIC)
+ writeq(S2IO_MINUS_ONE, &bar0->tx_traffic_int);
for (i = 0; i < config->tx_fifo_num; i++)
tx_intr_handler(&mac_control->fifos[i]);
@@ -4233,11 +4183,14 @@ static irqreturn_t s2io_isr(int irq, void *dev_id)
* reallocate the buffers from the interrupt handler itself,
* else schedule a tasklet to reallocate the buffers.
*/
-#ifndef CONFIG_S2IO_NAPI
- for (i = 0; i < config->rx_ring_num; i++)
- s2io_chk_rx_buffers(sp, i);
-#endif
- writeq(org_mask, &bar0->general_int_mask);
+ if (!napi) {
+ for (i = 0; i < config->rx_ring_num; i++)
+ s2io_chk_rx_buffers(sp, i);
+ }
+
+ writeq(0, &bar0->general_int_mask);
+ readl(&bar0->general_int_status);
+
atomic_dec(&sp->isr_cnt);
return IRQ_HANDLED;
}
@@ -4245,9 +4198,9 @@ static irqreturn_t s2io_isr(int irq, void *dev_id)
/**
* s2io_updt_stats -
*/
-static void s2io_updt_stats(nic_t *sp)
+static void s2io_updt_stats(struct s2io_nic *sp)
{
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
u64 val64;
int cnt = 0;
@@ -4266,7 +4219,7 @@ static void s2io_updt_stats(nic_t *sp)
break; /* Updt failed */
} while(1);
} else {
- memset(sp->mac_control.stats_info, 0, sizeof(StatInfo_t));
+ memset(sp->mac_control.stats_info, 0, sizeof(struct stat_block));
}
}
@@ -4282,8 +4235,8 @@ static void s2io_updt_stats(nic_t *sp)
static struct net_device_stats *s2io_get_stats(struct net_device *dev)
{
- nic_t *sp = dev->priv;
- mac_info_t *mac_control;
+ struct s2io_nic *sp = dev->priv;
+ struct mac_info *mac_control;
struct config_param *config;
@@ -4324,8 +4277,8 @@ static void s2io_set_multicast(struct net_device *dev)
{
int i, j, prev_cnt;
struct dev_mc_list *mclist;
- nic_t *sp = dev->priv;
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct s2io_nic *sp = dev->priv;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
u64 val64 = 0, multi_mac = 0x010203040506ULL, mask =
0xfeffffffffffULL;
u64 dis_addr = 0xffffffffffffULL, mac_addr = 0;
@@ -4478,8 +4431,8 @@ static void s2io_set_multicast(struct net_device *dev)
static int s2io_set_mac_addr(struct net_device *dev, u8 * addr)
{
- nic_t *sp = dev->priv;
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct s2io_nic *sp = dev->priv;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
register u64 val64, mac_addr = 0;
int i;
@@ -4525,7 +4478,7 @@ static int s2io_set_mac_addr(struct net_device *dev, u8 * addr)
static int s2io_ethtool_sset(struct net_device *dev,
struct ethtool_cmd *info)
{
- nic_t *sp = dev->priv;
+ struct s2io_nic *sp = dev->priv;
if ((info->autoneg == AUTONEG_ENABLE) ||
(info->speed != SPEED_10000) || (info->duplex != DUPLEX_FULL))
return -EINVAL;
@@ -4551,7 +4504,7 @@ static int s2io_ethtool_sset(struct net_device *dev,
static int s2io_ethtool_gset(struct net_device *dev, struct ethtool_cmd *info)
{
- nic_t *sp = dev->priv;
+ struct s2io_nic *sp = dev->priv;
info->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
info->advertising = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
info->port = PORT_FIBRE;
@@ -4584,7 +4537,7 @@ static int s2io_ethtool_gset(struct net_device *dev, struct ethtool_cmd *info)
static void s2io_ethtool_gdrvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
- nic_t *sp = dev->priv;
+ struct s2io_nic *sp = dev->priv;
strncpy(info->driver, s2io_driver_name, sizeof(info->driver));
strncpy(info->version, s2io_driver_version, sizeof(info->version));
@@ -4616,7 +4569,7 @@ static void s2io_ethtool_gregs(struct net_device *dev,
int i;
u64 reg;
u8 *reg_space = (u8 *) space;
- nic_t *sp = dev->priv;
+ struct s2io_nic *sp = dev->priv;
regs->len = XENA_REG_SPACE;
regs->version = sp->pdev->subsystem_device;
@@ -4638,8 +4591,8 @@ static void s2io_ethtool_gregs(struct net_device *dev,
*/
static void s2io_phy_id(unsigned long data)
{
- nic_t *sp = (nic_t *) data;
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct s2io_nic *sp = (struct s2io_nic *) data;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
u64 val64 = 0;
u16 subid;
@@ -4676,8 +4629,8 @@ static void s2io_phy_id(unsigned long data)
static int s2io_ethtool_idnic(struct net_device *dev, u32 data)
{
u64 val64 = 0, last_gpio_ctrl_val;
- nic_t *sp = dev->priv;
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct s2io_nic *sp = dev->priv;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
u16 subid;
subid = sp->pdev->subsystem_device;
@@ -4725,8 +4678,8 @@ static void s2io_ethtool_getpause_data(struct net_device *dev,
struct ethtool_pauseparam *ep)
{
u64 val64;
- nic_t *sp = dev->priv;
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct s2io_nic *sp = dev->priv;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
val64 = readq(&bar0->rmac_pause_cfg);
if (val64 & RMAC_PAUSE_GEN_ENABLE)
@@ -4752,8 +4705,8 @@ static int s2io_ethtool_setpause_data(struct net_device *dev,
struct ethtool_pauseparam *ep)
{
u64 val64;
- nic_t *sp = dev->priv;
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct s2io_nic *sp = dev->priv;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
val64 = readq(&bar0->rmac_pause_cfg);
if (ep->tx_pause)
@@ -4785,12 +4738,12 @@ static int s2io_ethtool_setpause_data(struct net_device *dev,
*/
#define S2IO_DEV_ID 5
-static int read_eeprom(nic_t * sp, int off, u64 * data)
+static int read_eeprom(struct s2io_nic * sp, int off, u64 * data)
{
int ret = -1;
u32 exit_cnt = 0;
u64 val64;
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
if (sp->device_type == XFRAME_I_DEVICE) {
val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | I2C_CONTROL_ADDR(off) |
@@ -4850,11 +4803,11 @@ static int read_eeprom(nic_t * sp, int off, u64 * data)
* 0 on success, -1 on failure.
*/
-static int write_eeprom(nic_t * sp, int off, u64 data, int cnt)
+static int write_eeprom(struct s2io_nic * sp, int off, u64 data, int cnt)
{
int exit_cnt = 0, ret = -1;
u64 val64;
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
if (sp->device_type == XFRAME_I_DEVICE) {
val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | I2C_CONTROL_ADDR(off) |
@@ -4899,7 +4852,7 @@ static int write_eeprom(nic_t * sp, int off, u64 data, int cnt)
}
return ret;
}
-static void s2io_vpd_read(nic_t *nic)
+static void s2io_vpd_read(struct s2io_nic *nic)
{
u8 *vpd_data;
u8 data;
@@ -4914,6 +4867,7 @@ static void s2io_vpd_read(nic_t *nic)
strcpy(nic->product_name, "Xframe I 10GbE network adapter");
vpd_addr = 0x50;
}
+ strcpy(nic->serial_num, "NOT AVAILABLE");
vpd_data = kmalloc(256, GFP_KERNEL);
if (!vpd_data)
@@ -4937,7 +4891,22 @@ static void s2io_vpd_read(nic_t *nic)
pci_read_config_dword(nic->pdev, (vpd_addr + 4),
(u32 *)&vpd_data[i]);
}
- if ((!fail) && (vpd_data[1] < VPD_PRODUCT_NAME_LEN)) {
+
+ if(!fail) {
+ /* read serial number of adapter */
+ for (cnt = 0; cnt < 256; cnt++) {
+ if ((vpd_data[cnt] == 'S') &&
+ (vpd_data[cnt+1] == 'N') &&
+ (vpd_data[cnt+2] < VPD_STRING_LEN)) {
+ memset(nic->serial_num, 0, VPD_STRING_LEN);
+ memcpy(nic->serial_num, &vpd_data[cnt + 3],
+ vpd_data[cnt+2]);
+ break;
+ }
+ }
+ }
+
+ if ((!fail) && (vpd_data[1] < VPD_STRING_LEN)) {
memset(nic->product_name, 0, vpd_data[1]);
memcpy(nic->product_name, &vpd_data[3], vpd_data[1]);
}
@@ -4962,7 +4931,7 @@ static int s2io_ethtool_geeprom(struct net_device *dev,
{
u32 i, valid;
u64 data;
- nic_t *sp = dev->priv;
+ struct s2io_nic *sp = dev->priv;
eeprom->magic = sp->pdev->vendor | (sp->pdev->device << 16);
@@ -5000,7 +4969,7 @@ static int s2io_ethtool_seeprom(struct net_device *dev,
{
int len = eeprom->len, cnt = 0;
u64 valid = 0, data;
- nic_t *sp = dev->priv;
+ struct s2io_nic *sp = dev->priv;
if (eeprom->magic != (sp->pdev->vendor | (sp->pdev->device << 16))) {
DBG_PRINT(ERR_DBG,
@@ -5044,9 +5013,9 @@ static int s2io_ethtool_seeprom(struct net_device *dev,
* 0 on success.
*/
-static int s2io_register_test(nic_t * sp, uint64_t * data)
+static int s2io_register_test(struct s2io_nic * sp, uint64_t * data)
{
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
u64 val64 = 0, exp_val;
int fail = 0;
@@ -5111,7 +5080,7 @@ static int s2io_register_test(nic_t * sp, uint64_t * data)
* 0 on success.
*/
-static int s2io_eeprom_test(nic_t * sp, uint64_t * data)
+static int s2io_eeprom_test(struct s2io_nic * sp, uint64_t * data)
{
int fail = 0;
u64 ret_data, org_4F0, org_7F0;
@@ -5213,7 +5182,7 @@ static int s2io_eeprom_test(nic_t * sp, uint64_t * data)
* 0 on success and -1 on failure.
*/
-static int s2io_bist_test(nic_t * sp, uint64_t * data)
+static int s2io_bist_test(struct s2io_nic * sp, uint64_t * data)
{
u8 bist = 0;
int cnt = 0, ret = -1;
@@ -5249,9 +5218,9 @@ static int s2io_bist_test(nic_t * sp, uint64_t * data)
* 0 on success.
*/
-static int s2io_link_test(nic_t * sp, uint64_t * data)
+static int s2io_link_test(struct s2io_nic * sp, uint64_t * data)
{
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
u64 val64;
val64 = readq(&bar0->adapter_status);
@@ -5276,9 +5245,9 @@ static int s2io_link_test(nic_t * sp, uint64_t * data)
* 0 on success.
*/
-static int s2io_rldram_test(nic_t * sp, uint64_t * data)
+static int s2io_rldram_test(struct s2io_nic * sp, uint64_t * data)
{
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
u64 val64;
int cnt, iteration = 0, test_fail = 0;
@@ -5380,7 +5349,7 @@ static void s2io_ethtool_test(struct net_device *dev,
struct ethtool_test *ethtest,
uint64_t * data)
{
- nic_t *sp = dev->priv;
+ struct s2io_nic *sp = dev->priv;
int orig_state = netif_running(sp->dev);
if (ethtest->flags == ETH_TEST_FL_OFFLINE) {
@@ -5436,8 +5405,8 @@ static void s2io_get_ethtool_stats(struct net_device *dev,
u64 * tmp_stats)
{
int i = 0;
- nic_t *sp = dev->priv;
- StatInfo_t *stat_info = sp->mac_control.stats_info;
+ struct s2io_nic *sp = dev->priv;
+ struct stat_block *stat_info = sp->mac_control.stats_info;
s2io_updt_stats(sp);
tmp_stats[i++] =
@@ -5664,14 +5633,14 @@ static int s2io_ethtool_get_regs_len(struct net_device *dev)
static u32 s2io_ethtool_get_rx_csum(struct net_device * dev)
{
- nic_t *sp = dev->priv;
+ struct s2io_nic *sp = dev->priv;
return (sp->rx_csum);
}
static int s2io_ethtool_set_rx_csum(struct net_device *dev, u32 data)
{
- nic_t *sp = dev->priv;
+ struct s2io_nic *sp = dev->priv;
if (data)
sp->rx_csum = 1;
@@ -5750,10 +5719,8 @@ static const struct ethtool_ops netdev_ethtool_ops = {
.set_tx_csum = s2io_ethtool_op_set_tx_csum,
.get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
-#ifdef NETIF_F_TSO
.get_tso = s2io_ethtool_op_get_tso,
.set_tso = s2io_ethtool_op_set_tso,
-#endif
.get_ufo = ethtool_op_get_ufo,
.set_ufo = ethtool_op_set_ufo,
.self_test_count = s2io_ethtool_self_test_count,
@@ -5794,7 +5761,7 @@ static int s2io_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
static int s2io_change_mtu(struct net_device *dev, int new_mtu)
{
- nic_t *sp = dev->priv;
+ struct s2io_nic *sp = dev->priv;
if ((new_mtu < MIN_MTU) || (new_mtu > S2IO_JUMBO_SIZE)) {
DBG_PRINT(ERR_DBG, "%s: MTU size is invalid.\n",
@@ -5813,7 +5780,7 @@ static int s2io_change_mtu(struct net_device *dev, int new_mtu)
if (netif_queue_stopped(dev))
netif_wake_queue(dev);
} else { /* Device is down */
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
u64 val64 = new_mtu;
writeq(vBIT(val64, 2, 14), &bar0->rmac_max_pyld_len);
@@ -5838,9 +5805,9 @@ static int s2io_change_mtu(struct net_device *dev, int new_mtu)
static void s2io_tasklet(unsigned long dev_addr)
{
struct net_device *dev = (struct net_device *) dev_addr;
- nic_t *sp = dev->priv;
+ struct s2io_nic *sp = dev->priv;
int i, ret;
- mac_info_t *mac_control;
+ struct mac_info *mac_control;
struct config_param *config;
mac_control = &sp->mac_control;
@@ -5873,15 +5840,20 @@ static void s2io_tasklet(unsigned long dev_addr)
static void s2io_set_link(struct work_struct *work)
{
- nic_t *nic = container_of(work, nic_t, set_link_task);
+ struct s2io_nic *nic = container_of(work, struct s2io_nic, set_link_task);
struct net_device *dev = nic->dev;
- XENA_dev_config_t __iomem *bar0 = nic->bar0;
+ struct XENA_dev_config __iomem *bar0 = nic->bar0;
register u64 val64;
u16 subid;
+ rtnl_lock();
+
+ if (!netif_running(dev))
+ goto out_unlock;
+
if (test_and_set_bit(0, &(nic->link_state))) {
/* The card is being reset, no point doing anything */
- return;
+ goto out_unlock;
}
subid = nic->pdev->subsystem_device;
@@ -5894,57 +5866,56 @@ static void s2io_set_link(struct work_struct *work)
}
val64 = readq(&bar0->adapter_status);
- if (verify_xena_quiescence(nic, val64, nic->device_enabled_once)) {
- if (LINK_IS_UP(val64)) {
- val64 = readq(&bar0->adapter_control);
- val64 |= ADAPTER_CNTL_EN;
- writeq(val64, &bar0->adapter_control);
- if (CARDS_WITH_FAULTY_LINK_INDICATORS(nic->device_type,
- subid)) {
- val64 = readq(&bar0->gpio_control);
- val64 |= GPIO_CTRL_GPIO_0;
- writeq(val64, &bar0->gpio_control);
- val64 = readq(&bar0->gpio_control);
- } else {
- val64 |= ADAPTER_LED_ON;
+ if (LINK_IS_UP(val64)) {
+ if (!(readq(&bar0->adapter_control) & ADAPTER_CNTL_EN)) {
+ if (verify_xena_quiescence(nic)) {
+ val64 = readq(&bar0->adapter_control);
+ val64 |= ADAPTER_CNTL_EN;
writeq(val64, &bar0->adapter_control);
- }
- if (s2io_link_fault_indication(nic) ==
- MAC_RMAC_ERR_TIMER) {
- val64 = readq(&bar0->adapter_status);
- if (!LINK_IS_UP(val64)) {
- DBG_PRINT(ERR_DBG, "%s:", dev->name);
- DBG_PRINT(ERR_DBG, " Link down");
- DBG_PRINT(ERR_DBG, "after ");
- DBG_PRINT(ERR_DBG, "enabling ");
- DBG_PRINT(ERR_DBG, "device \n");
+ if (CARDS_WITH_FAULTY_LINK_INDICATORS(
+ nic->device_type, subid)) {
+ val64 = readq(&bar0->gpio_control);
+ val64 |= GPIO_CTRL_GPIO_0;
+ writeq(val64, &bar0->gpio_control);
+ val64 = readq(&bar0->gpio_control);
+ } else {
+ val64 |= ADAPTER_LED_ON;
+ writeq(val64, &bar0->adapter_control);
}
- }
- if (nic->device_enabled_once == FALSE) {
nic->device_enabled_once = TRUE;
+ } else {
+ DBG_PRINT(ERR_DBG, "%s: Error: ", dev->name);
+ DBG_PRINT(ERR_DBG, "device is not Quiescent\n");
+ netif_stop_queue(dev);
}
+ }
+ val64 = readq(&bar0->adapter_status);
+ if (!LINK_IS_UP(val64)) {
+ DBG_PRINT(ERR_DBG, "%s:", dev->name);
+ DBG_PRINT(ERR_DBG, " Link down after enabling ");
+ DBG_PRINT(ERR_DBG, "device \n");
+ } else
s2io_link(nic, LINK_UP);
- } else {
- if (CARDS_WITH_FAULTY_LINK_INDICATORS(nic->device_type,
- subid)) {
- val64 = readq(&bar0->gpio_control);
- val64 &= ~GPIO_CTRL_GPIO_0;
- writeq(val64, &bar0->gpio_control);
- val64 = readq(&bar0->gpio_control);
- }
- s2io_link(nic, LINK_DOWN);
+ } else {
+ if (CARDS_WITH_FAULTY_LINK_INDICATORS(nic->device_type,
+ subid)) {
+ val64 = readq(&bar0->gpio_control);
+ val64 &= ~GPIO_CTRL_GPIO_0;
+ writeq(val64, &bar0->gpio_control);
+ val64 = readq(&bar0->gpio_control);
}
- } else { /* NIC is not Quiescent. */
- DBG_PRINT(ERR_DBG, "%s: Error: ", dev->name);
- DBG_PRINT(ERR_DBG, "device is not Quiescent\n");
- netif_stop_queue(dev);
+ s2io_link(nic, LINK_DOWN);
}
clear_bit(0, &(nic->link_state));
+
+out_unlock:
+ rtnl_lock();
}
-static int set_rxd_buffer_pointer(nic_t *sp, RxD_t *rxdp, buffAdd_t *ba,
- struct sk_buff **skb, u64 *temp0, u64 *temp1,
- u64 *temp2, int size)
+static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp,
+ struct buffAdd *ba,
+ struct sk_buff **skb, u64 *temp0, u64 *temp1,
+ u64 *temp2, int size)
{
struct net_device *dev = sp->dev;
struct sk_buff *frag_list;
@@ -5958,7 +5929,7 @@ static int set_rxd_buffer_pointer(nic_t *sp, RxD_t *rxdp, buffAdd_t *ba,
* using same mapped address for the Rxd
* buffer pointer
*/
- ((RxD1_t*)rxdp)->Buffer0_ptr = *temp0;
+ ((struct RxD1*)rxdp)->Buffer0_ptr = *temp0;
} else {
*skb = dev_alloc_skb(size);
if (!(*skb)) {
@@ -5970,7 +5941,7 @@ static int set_rxd_buffer_pointer(nic_t *sp, RxD_t *rxdp, buffAdd_t *ba,
* such it will be used for next rxd whose
* Host Control is NULL
*/
- ((RxD1_t*)rxdp)->Buffer0_ptr = *temp0 =
+ ((struct RxD1*)rxdp)->Buffer0_ptr = *temp0 =
pci_map_single( sp->pdev, (*skb)->data,
size - NET_IP_ALIGN,
PCI_DMA_FROMDEVICE);
@@ -5979,36 +5950,36 @@ static int set_rxd_buffer_pointer(nic_t *sp, RxD_t *rxdp, buffAdd_t *ba,
} else if ((sp->rxd_mode == RXD_MODE_3B) && (rxdp->Host_Control == 0)) {
/* Two buffer Mode */
if (*skb) {
- ((RxD3_t*)rxdp)->Buffer2_ptr = *temp2;
- ((RxD3_t*)rxdp)->Buffer0_ptr = *temp0;
- ((RxD3_t*)rxdp)->Buffer1_ptr = *temp1;
+ ((struct RxD3*)rxdp)->Buffer2_ptr = *temp2;
+ ((struct RxD3*)rxdp)->Buffer0_ptr = *temp0;
+ ((struct RxD3*)rxdp)->Buffer1_ptr = *temp1;
} else {
*skb = dev_alloc_skb(size);
if (!(*skb)) {
DBG_PRINT(ERR_DBG, "%s: dev_alloc_skb failed\n",
- dev->name);
+ dev->name);
return -ENOMEM;
}
- ((RxD3_t*)rxdp)->Buffer2_ptr = *temp2 =
+ ((struct RxD3*)rxdp)->Buffer2_ptr = *temp2 =
pci_map_single(sp->pdev, (*skb)->data,
dev->mtu + 4,
PCI_DMA_FROMDEVICE);
- ((RxD3_t*)rxdp)->Buffer0_ptr = *temp0 =
+ ((struct RxD3*)rxdp)->Buffer0_ptr = *temp0 =
pci_map_single( sp->pdev, ba->ba_0, BUF0_LEN,
PCI_DMA_FROMDEVICE);
rxdp->Host_Control = (unsigned long) (*skb);
/* Buffer-1 will be dummy buffer not used */
- ((RxD3_t*)rxdp)->Buffer1_ptr = *temp1 =
+ ((struct RxD3*)rxdp)->Buffer1_ptr = *temp1 =
pci_map_single(sp->pdev, ba->ba_1, BUF1_LEN,
PCI_DMA_FROMDEVICE);
}
} else if ((rxdp->Host_Control == 0)) {
/* Three buffer mode */
if (*skb) {
- ((RxD3_t*)rxdp)->Buffer0_ptr = *temp0;
- ((RxD3_t*)rxdp)->Buffer1_ptr = *temp1;
- ((RxD3_t*)rxdp)->Buffer2_ptr = *temp2;
+ ((struct RxD3*)rxdp)->Buffer0_ptr = *temp0;
+ ((struct RxD3*)rxdp)->Buffer1_ptr = *temp1;
+ ((struct RxD3*)rxdp)->Buffer2_ptr = *temp2;
} else {
*skb = dev_alloc_skb(size);
if (!(*skb)) {
@@ -6016,11 +5987,11 @@ static int set_rxd_buffer_pointer(nic_t *sp, RxD_t *rxdp, buffAdd_t *ba,
dev->name);
return -ENOMEM;
}
- ((RxD3_t*)rxdp)->Buffer0_ptr = *temp0 =
+ ((struct RxD3*)rxdp)->Buffer0_ptr = *temp0 =
pci_map_single(sp->pdev, ba->ba_0, BUF0_LEN,
PCI_DMA_FROMDEVICE);
/* Buffer-1 receives L3/L4 headers */
- ((RxD3_t*)rxdp)->Buffer1_ptr = *temp1 =
+ ((struct RxD3*)rxdp)->Buffer1_ptr = *temp1 =
pci_map_single( sp->pdev, (*skb)->data,
l3l4hdr_size + 4,
PCI_DMA_FROMDEVICE);
@@ -6040,14 +6011,15 @@ static int set_rxd_buffer_pointer(nic_t *sp, RxD_t *rxdp, buffAdd_t *ba,
/*
* Buffer-2 receives L4 data payload
*/
- ((RxD3_t*)rxdp)->Buffer2_ptr = *temp2 =
+ ((struct RxD3*)rxdp)->Buffer2_ptr = *temp2 =
pci_map_single( sp->pdev, frag_list->data,
dev->mtu, PCI_DMA_FROMDEVICE);
}
}
return 0;
}
-static void set_rxd_buffer_size(nic_t *sp, RxD_t *rxdp, int size)
+static void set_rxd_buffer_size(struct s2io_nic *sp, struct RxD_t *rxdp,
+ int size)
{
struct net_device *dev = sp->dev;
if (sp->rxd_mode == RXD_MODE_1) {
@@ -6063,15 +6035,15 @@ static void set_rxd_buffer_size(nic_t *sp, RxD_t *rxdp, int size)
}
}
-static int rxd_owner_bit_reset(nic_t *sp)
+static int rxd_owner_bit_reset(struct s2io_nic *sp)
{
int i, j, k, blk_cnt = 0, size;
- mac_info_t * mac_control = &sp->mac_control;
+ struct mac_info * mac_control = &sp->mac_control;
struct config_param *config = &sp->config;
struct net_device *dev = sp->dev;
- RxD_t *rxdp = NULL;
+ struct RxD_t *rxdp = NULL;
struct sk_buff *skb = NULL;
- buffAdd_t *ba = NULL;
+ struct buffAdd *ba = NULL;
u64 temp0_64 = 0, temp1_64 = 0, temp2_64 = 0;
/* Calculate the size based on ring mode */
@@ -6110,7 +6082,7 @@ static int rxd_owner_bit_reset(nic_t *sp)
}
-static int s2io_add_isr(nic_t * sp)
+static int s2io_add_isr(struct s2io_nic * sp)
{
int ret = 0;
struct net_device *dev = sp->dev;
@@ -6125,7 +6097,7 @@ static int s2io_add_isr(nic_t * sp)
sp->intr_type = INTA;
}
- /* Store the values of the MSIX table in the nic_t structure */
+ /* Store the values of the MSIX table in the struct s2io_nic structure */
store_xmsi_data(sp);
/* After proper initialization of H/W, register ISR */
@@ -6180,7 +6152,7 @@ static int s2io_add_isr(nic_t * sp)
}
return 0;
}
-static void s2io_rem_isr(nic_t * sp)
+static void s2io_rem_isr(struct s2io_nic * sp)
{
int cnt = 0;
struct net_device *dev = sp->dev;
@@ -6222,10 +6194,10 @@ static void s2io_rem_isr(nic_t * sp)
} while(cnt < 5);
}
-static void s2io_card_down(nic_t * sp)
+static void s2io_card_down(struct s2io_nic * sp)
{
int cnt = 0;
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
unsigned long flags;
register u64 val64 = 0;
@@ -6256,7 +6228,8 @@ static void s2io_card_down(nic_t * sp)
rxd_owner_bit_reset(sp);
val64 = readq(&bar0->adapter_status);
- if (verify_xena_quiescence(sp, val64, sp->device_enabled_once)) {
+ if (verify_xena_quiescence(sp)) {
+ if(verify_pcc_quiescent(sp, sp->device_enabled_once))
break;
}
@@ -6285,10 +6258,10 @@ static void s2io_card_down(nic_t * sp)
clear_bit(0, &(sp->link_state));
}
-static int s2io_card_up(nic_t * sp)
+static int s2io_card_up(struct s2io_nic * sp)
{
int i, ret = 0;
- mac_info_t *mac_control;
+ struct mac_info *mac_control;
struct config_param *config;
struct net_device *dev = (struct net_device *) sp->dev;
u16 interruptible;
@@ -6319,6 +6292,13 @@ static int s2io_card_up(nic_t * sp)
DBG_PRINT(INFO_DBG, "Buf in ring:%d is %d:\n", i,
atomic_read(&sp->rx_bufs_left[i]));
}
+ /* Maintain the state prior to the open */
+ if (sp->promisc_flg)
+ sp->promisc_flg = 0;
+ if (sp->m_cast_flg) {
+ sp->m_cast_flg = 0;
+ sp->all_multi_pos= 0;
+ }
/* Setting its receive mode */
s2io_set_multicast(dev);
@@ -6380,9 +6360,14 @@ static int s2io_card_up(nic_t * sp)
static void s2io_restart_nic(struct work_struct *work)
{
- nic_t *sp = container_of(work, nic_t, rst_timer_task);
+ struct s2io_nic *sp = container_of(work, struct s2io_nic, rst_timer_task);
struct net_device *dev = sp->dev;
+ rtnl_lock();
+
+ if (!netif_running(dev))
+ goto out_unlock;
+
s2io_card_down(sp);
if (s2io_card_up(sp)) {
DBG_PRINT(ERR_DBG, "%s: Device bring up failed\n",
@@ -6391,7 +6376,8 @@ static void s2io_restart_nic(struct work_struct *work)
netif_wake_queue(dev);
DBG_PRINT(ERR_DBG, "%s: was reset by Tx watchdog timer\n",
dev->name);
-
+out_unlock:
+ rtnl_unlock();
}
/**
@@ -6409,7 +6395,7 @@ static void s2io_restart_nic(struct work_struct *work)
static void s2io_tx_watchdog(struct net_device *dev)
{
- nic_t *sp = dev->priv;
+ struct s2io_nic *sp = dev->priv;
if (netif_carrier_ok(dev)) {
schedule_work(&sp->rst_timer_task);
@@ -6434,16 +6420,16 @@ static void s2io_tx_watchdog(struct net_device *dev)
* Return value:
* SUCCESS on success and -1 on failure.
*/
-static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp)
+static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp)
{
- nic_t *sp = ring_data->nic;
+ struct s2io_nic *sp = ring_data->nic;
struct net_device *dev = (struct net_device *) sp->dev;
struct sk_buff *skb = (struct sk_buff *)
((unsigned long) rxdp->Host_Control);
int ring_no = ring_data->ring_no;
u16 l3_csum, l4_csum;
unsigned long long err = rxdp->Control_1 & RXD_T_CODE;
- lro_t *lro;
+ struct lro *lro;
skb->dev = dev;
@@ -6488,7 +6474,7 @@ static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp)
int buf2_len = RXD_GET_BUFFER2_SIZE_3(rxdp->Control_2);
unsigned char *buff = skb_push(skb, buf0_len);
- buffAdd_t *ba = &ring_data->ba[get_block][get_off];
+ struct buffAdd *ba = &ring_data->ba[get_block][get_off];
sp->stats.rx_bytes += buf0_len + buf2_len;
memcpy(buff, ba->ba_0, buf0_len);
@@ -6498,7 +6484,6 @@ static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp)
skb_put(skb, buf1_len);
skb->len += buf2_len;
skb->data_len += buf2_len;
- skb->truesize += buf2_len;
skb_put(skb_shinfo(skb)->frag_list, buf2_len);
sp->stats.rx_bytes += buf1_len;
@@ -6582,23 +6567,20 @@ static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp)
if (!sp->lro) {
skb->protocol = eth_type_trans(skb, dev);
-#ifdef CONFIG_S2IO_NAPI
- if (sp->vlgrp && RXD_GET_VLAN_TAG(rxdp->Control_2)) {
- /* Queueing the vlan frame to the upper layer */
- vlan_hwaccel_receive_skb(skb, sp->vlgrp,
- RXD_GET_VLAN_TAG(rxdp->Control_2));
- } else {
- netif_receive_skb(skb);
- }
-#else
if (sp->vlgrp && RXD_GET_VLAN_TAG(rxdp->Control_2)) {
/* Queueing the vlan frame to the upper layer */
- vlan_hwaccel_rx(skb, sp->vlgrp,
- RXD_GET_VLAN_TAG(rxdp->Control_2));
+ if (napi)
+ vlan_hwaccel_receive_skb(skb, sp->vlgrp,
+ RXD_GET_VLAN_TAG(rxdp->Control_2));
+ else
+ vlan_hwaccel_rx(skb, sp->vlgrp,
+ RXD_GET_VLAN_TAG(rxdp->Control_2));
} else {
- netif_rx(skb);
+ if (napi)
+ netif_receive_skb(skb);
+ else
+ netif_rx(skb);
}
-#endif
} else {
send_up:
queue_rx_frame(skb);
@@ -6622,7 +6604,7 @@ aggregate:
* void.
*/
-static void s2io_link(nic_t * sp, int link)
+static void s2io_link(struct s2io_nic * sp, int link)
{
struct net_device *dev = (struct net_device *) sp->dev;
@@ -6666,7 +6648,7 @@ static int get_xena_rev_id(struct pci_dev *pdev)
* void
*/
-static void s2io_init_pci(nic_t * sp)
+static void s2io_init_pci(struct s2io_nic * sp)
{
u16 pci_cmd = 0, pcix_cmd = 0;
@@ -6699,13 +6681,9 @@ static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type)
DBG_PRINT(ERR_DBG, "s2io: Default to 8 Rx rings\n");
rx_ring_num = 8;
}
-#ifdef CONFIG_S2IO_NAPI
- if (*dev_intr_type != INTA) {
- DBG_PRINT(ERR_DBG, "s2io: NAPI cannot be enabled when "
- "MSI/MSI-X is enabled. Defaulting to INTA\n");
- *dev_intr_type = INTA;
- }
-#endif
+ if (*dev_intr_type != INTA)
+ napi = 0;
+
#ifndef CONFIG_PCI_MSI
if (*dev_intr_type != INTA) {
DBG_PRINT(ERR_DBG, "s2io: This kernel does not support"
@@ -6726,6 +6704,8 @@ static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type)
"Defaulting to INTA\n");
*dev_intr_type = INTA;
}
+ if ( (rx_ring_num > 1) && (*dev_intr_type != INTA) )
+ napi = 0;
if (rx_ring_mode > 3) {
DBG_PRINT(ERR_DBG, "s2io: Requested ring mode not supported\n");
DBG_PRINT(ERR_DBG, "s2io: Defaulting to 3-buffer mode\n");
@@ -6751,15 +6731,15 @@ static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type)
static int __devinit
s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
{
- nic_t *sp;
+ struct s2io_nic *sp;
struct net_device *dev;
int i, j, ret;
int dma_flag = FALSE;
u32 mac_up, mac_down;
u64 val64 = 0, tmp64 = 0;
- XENA_dev_config_t __iomem *bar0 = NULL;
+ struct XENA_dev_config __iomem *bar0 = NULL;
u16 subid;
- mac_info_t *mac_control;
+ struct mac_info *mac_control;
struct config_param *config;
int mode;
u8 dev_intr_type = intr_type;
@@ -6814,7 +6794,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
}
}
- dev = alloc_etherdev(sizeof(nic_t));
+ dev = alloc_etherdev(sizeof(struct s2io_nic));
if (dev == NULL) {
DBG_PRINT(ERR_DBG, "Device allocation failed\n");
pci_disable_device(pdev);
@@ -6829,7 +6809,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
/* Private member variable initialized to s2io NIC structure */
sp = dev->priv;
- memset(sp, 0, sizeof(nic_t));
+ memset(sp, 0, sizeof(struct s2io_nic));
sp->dev = dev;
sp->pdev = pdev;
sp->high_dma_flag = dma_flag;
@@ -6925,7 +6905,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
sp->bar0 = ioremap(pci_resource_start(pdev, 0),
pci_resource_len(pdev, 0));
if (!sp->bar0) {
- DBG_PRINT(ERR_DBG, "%s: S2IO: cannot remap io mem1\n",
+ DBG_PRINT(ERR_DBG, "%s: Neterion: cannot remap io mem1\n",
dev->name);
ret = -ENOMEM;
goto bar0_remap_failed;
@@ -6934,7 +6914,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
sp->bar1 = ioremap(pci_resource_start(pdev, 2),
pci_resource_len(pdev, 2));
if (!sp->bar1) {
- DBG_PRINT(ERR_DBG, "%s: S2IO: cannot remap io mem2\n",
+ DBG_PRINT(ERR_DBG, "%s: Neterion: cannot remap io mem2\n",
dev->name);
ret = -ENOMEM;
goto bar1_remap_failed;
@@ -6945,7 +6925,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
/* Initializing the BAR1 address as the start of the FIFO pointer. */
for (j = 0; j < MAX_TX_FIFOS; j++) {
- mac_control->tx_FIFO_start[j] = (TxFIFO_element_t __iomem *)
+ mac_control->tx_FIFO_start[j] = (struct TxFIFO_element __iomem *)
(sp->bar1 + (j * 0x00020000));
}
@@ -6966,10 +6946,8 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
* will use eth_mac_addr() for dev->set_mac_address
* mac address will be set every time dev->open() is called
*/
-#if defined(CONFIG_S2IO_NAPI)
dev->poll = s2io_poll;
dev->weight = 32;
-#endif
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = s2io_netpoll;
@@ -6978,13 +6956,9 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
if (sp->high_dma_flag == TRUE)
dev->features |= NETIF_F_HIGHDMA;
-#ifdef NETIF_F_TSO
dev->features |= NETIF_F_TSO;
-#endif
-#ifdef NETIF_F_TSO6
dev->features |= NETIF_F_TSO6;
-#endif
- if (sp->device_type & XFRAME_II_DEVICE) {
+ if ((sp->device_type & XFRAME_II_DEVICE) && (ufo)) {
dev->features |= NETIF_F_UFO;
dev->features |= NETIF_F_HW_CSUM;
}
@@ -7065,9 +7039,9 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
/* Initialize spinlocks */
spin_lock_init(&sp->tx_lock);
-#ifndef CONFIG_S2IO_NAPI
- spin_lock_init(&sp->put_lock);
-#endif
+
+ if (!napi)
+ spin_lock_init(&sp->put_lock);
spin_lock_init(&sp->rx_lock);
/*
@@ -7098,13 +7072,14 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
DBG_PRINT(ERR_DBG, "%s: Driver version %s\n", dev->name,
s2io_driver_version);
DBG_PRINT(ERR_DBG, "%s: MAC ADDR: "
- "%02x:%02x:%02x:%02x:%02x:%02x\n", dev->name,
+ "%02x:%02x:%02x:%02x:%02x:%02x", dev->name,
sp->def_mac_addr[0].mac_addr[0],
sp->def_mac_addr[0].mac_addr[1],
sp->def_mac_addr[0].mac_addr[2],
sp->def_mac_addr[0].mac_addr[3],
sp->def_mac_addr[0].mac_addr[4],
sp->def_mac_addr[0].mac_addr[5]);
+ DBG_PRINT(ERR_DBG, "SERIAL NUMBER: %s\n", sp->serial_num);
if (sp->device_type & XFRAME_II_DEVICE) {
mode = s2io_print_pci_mode(sp);
if (mode < 0) {
@@ -7128,9 +7103,9 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
dev->name);
break;
}
-#ifdef CONFIG_S2IO_NAPI
- DBG_PRINT(ERR_DBG, "%s: NAPI enabled\n", dev->name);
-#endif
+
+ if (napi)
+ DBG_PRINT(ERR_DBG, "%s: NAPI enabled\n", dev->name);
switch(sp->intr_type) {
case INTA:
DBG_PRINT(ERR_DBG, "%s: Interrupt type INTA\n", dev->name);
@@ -7145,7 +7120,9 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
if (sp->lro)
DBG_PRINT(ERR_DBG, "%s: Large receive offload enabled\n",
dev->name);
-
+ if (ufo)
+ DBG_PRINT(ERR_DBG, "%s: UDP Fragmentation Offload(UFO)"
+ " enabled\n", dev->name);
/* Initialize device name */
sprintf(sp->name, "%s Neterion %s", dev->name, sp->product_name);
@@ -7202,20 +7179,21 @@ static void __devexit s2io_rem_nic(struct pci_dev *pdev)
{
struct net_device *dev =
(struct net_device *) pci_get_drvdata(pdev);
- nic_t *sp;
+ struct s2io_nic *sp;
if (dev == NULL) {
DBG_PRINT(ERR_DBG, "Driver Data is NULL!!\n");
return;
}
+ flush_scheduled_work();
+
sp = dev->priv;
unregister_netdev(dev);
free_shared_mem(sp);
iounmap(sp->bar0);
iounmap(sp->bar1);
- pci_disable_device(pdev);
if (sp->intr_type != MSI_X)
pci_release_regions(pdev);
else {
@@ -7226,6 +7204,7 @@ static void __devexit s2io_rem_nic(struct pci_dev *pdev)
}
pci_set_drvdata(pdev, NULL);
free_netdev(dev);
+ pci_disable_device(pdev);
}
/**
@@ -7244,7 +7223,7 @@ int __init s2io_starter(void)
* Description: This function is the cleanup routine for the driver. It unregist * ers the driver.
*/
-static void s2io_closer(void)
+static __exit void s2io_closer(void)
{
pci_unregister_driver(&s2io_driver);
DBG_PRINT(INIT_DBG, "cleanup done\n");
@@ -7254,7 +7233,7 @@ module_init(s2io_starter);
module_exit(s2io_closer);
static int check_L2_lro_capable(u8 *buffer, struct iphdr **ip,
- struct tcphdr **tcp, RxD_t *rxdp)
+ struct tcphdr **tcp, struct RxD_t *rxdp)
{
int ip_off;
u8 l2_type = (u8)((rxdp->Control_1 >> 37) & 0x7), ip_len;
@@ -7288,7 +7267,7 @@ static int check_L2_lro_capable(u8 *buffer, struct iphdr **ip,
return 0;
}
-static int check_for_socket_match(lro_t *lro, struct iphdr *ip,
+static int check_for_socket_match(struct lro *lro, struct iphdr *ip,
struct tcphdr *tcp)
{
DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
@@ -7303,7 +7282,7 @@ static inline int get_l4_pyld_length(struct iphdr *ip, struct tcphdr *tcp)
return(ntohs(ip->tot_len) - (ip->ihl << 2) - (tcp->doff << 2));
}
-static void initiate_new_session(lro_t *lro, u8 *l2h,
+static void initiate_new_session(struct lro *lro, u8 *l2h,
struct iphdr *ip, struct tcphdr *tcp, u32 tcp_pyld_len)
{
DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
@@ -7329,12 +7308,12 @@ static void initiate_new_session(lro_t *lro, u8 *l2h,
lro->in_use = 1;
}
-static void update_L3L4_header(nic_t *sp, lro_t *lro)
+static void update_L3L4_header(struct s2io_nic *sp, struct lro *lro)
{
struct iphdr *ip = lro->iph;
struct tcphdr *tcp = lro->tcph;
- u16 nchk;
- StatInfo_t *statinfo = sp->mac_control.stats_info;
+ __sum16 nchk;
+ struct stat_block *statinfo = sp->mac_control.stats_info;
DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
/* Update L3 header */
@@ -7360,7 +7339,7 @@ static void update_L3L4_header(nic_t *sp, lro_t *lro)
statinfo->sw_stat.num_aggregations++;
}
-static void aggregate_new_rx(lro_t *lro, struct iphdr *ip,
+static void aggregate_new_rx(struct lro *lro, struct iphdr *ip,
struct tcphdr *tcp, u32 l4_pyld)
{
DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
@@ -7382,7 +7361,7 @@ static void aggregate_new_rx(lro_t *lro, struct iphdr *ip,
}
}
-static int verify_l3_l4_lro_capable(lro_t *l_lro, struct iphdr *ip,
+static int verify_l3_l4_lro_capable(struct lro *l_lro, struct iphdr *ip,
struct tcphdr *tcp, u32 tcp_pyld_len)
{
u8 *ptr;
@@ -7440,8 +7419,8 @@ static int verify_l3_l4_lro_capable(lro_t *l_lro, struct iphdr *ip,
}
static int
-s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, lro_t **lro,
- RxD_t *rxdp, nic_t *sp)
+s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, struct lro **lro,
+ struct RxD_t *rxdp, struct s2io_nic *sp)
{
struct iphdr *ip;
struct tcphdr *tcph;
@@ -7458,7 +7437,7 @@ s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, lro_t **lro,
tcph = (struct tcphdr *)*tcp;
*tcp_len = get_l4_pyld_length(ip, tcph);
for (i=0; i<MAX_LRO_SESSIONS; i++) {
- lro_t *l_lro = &sp->lro0_n[i];
+ struct lro *l_lro = &sp->lro0_n[i];
if (l_lro->in_use) {
if (check_for_socket_match(l_lro, ip, tcph))
continue;
@@ -7496,7 +7475,7 @@ s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, lro_t **lro,
}
for (i=0; i<MAX_LRO_SESSIONS; i++) {
- lro_t *l_lro = &sp->lro0_n[i];
+ struct lro *l_lro = &sp->lro0_n[i];
if (!(l_lro->in_use)) {
*lro = l_lro;
ret = 3; /* Begin anew */
@@ -7535,9 +7514,9 @@ s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, lro_t **lro,
return ret;
}
-static void clear_lro_session(lro_t *lro)
+static void clear_lro_session(struct lro *lro)
{
- static u16 lro_struct_size = sizeof(lro_t);
+ static u16 lro_struct_size = sizeof(struct lro);
memset(lro, 0, lro_struct_size);
}
@@ -7547,14 +7526,14 @@ static void queue_rx_frame(struct sk_buff *skb)
struct net_device *dev = skb->dev;
skb->protocol = eth_type_trans(skb, dev);
-#ifdef CONFIG_S2IO_NAPI
- netif_receive_skb(skb);
-#else
- netif_rx(skb);
-#endif
+ if (napi)
+ netif_receive_skb(skb);
+ else
+ netif_rx(skb);
}
-static void lro_append_pkt(nic_t *sp, lro_t *lro, struct sk_buff *skb,
+static void lro_append_pkt(struct s2io_nic *sp, struct lro *lro,
+ struct sk_buff *skb,
u32 tcp_len)
{
struct sk_buff *first = lro->parent;
@@ -7566,6 +7545,7 @@ static void lro_append_pkt(nic_t *sp, lro_t *lro, struct sk_buff *skb,
lro->last_frag->next = skb;
else
skb_shinfo(first)->frag_list = skb;
+ first->truesize += skb->truesize;
lro->last_frag = skb;
sp->mac_control.stats_info->sw_stat.clubbed_frms_cnt++;
return;
diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h
index 3b0bafd273c..0de0c65f945 100644
--- a/drivers/net/s2io.h
+++ b/drivers/net/s2io.h
@@ -30,6 +30,8 @@
#undef SUCCESS
#define SUCCESS 0
#define FAILURE -1
+#define S2IO_MINUS_ONE 0xFFFFFFFFFFFFFFFFULL
+#define S2IO_MAX_PCI_CONFIG_SPACE_REINIT 100
#define CHECKBIT(value, nbit) (value & (1 << nbit))
@@ -37,7 +39,7 @@
#define MAX_FLICKER_TIME 60000 /* 60 Secs */
/* Maximum outstanding splits to be configured into xena. */
-typedef enum xena_max_outstanding_splits {
+enum {
XENA_ONE_SPLIT_TRANSACTION = 0,
XENA_TWO_SPLIT_TRANSACTION = 1,
XENA_THREE_SPLIT_TRANSACTION = 2,
@@ -46,7 +48,7 @@ typedef enum xena_max_outstanding_splits {
XENA_TWELVE_SPLIT_TRANSACTION = 5,
XENA_SIXTEEN_SPLIT_TRANSACTION = 6,
XENA_THIRTYTWO_SPLIT_TRANSACTION = 7
-} xena_max_outstanding_splits;
+};
#define XENA_MAX_OUTSTANDING_SPLITS(n) (n << 4)
/* OS concerned variables and constants */
@@ -77,7 +79,7 @@ static int debug_level = ERR_DBG;
#define S2IO_JUMBO_SIZE 9600
/* Driver statistics maintained by driver */
-typedef struct {
+struct swStat {
unsigned long long single_ecc_errs;
unsigned long long double_ecc_errs;
unsigned long long parity_err_cnt;
@@ -92,10 +94,10 @@ typedef struct {
unsigned long long flush_max_pkts;
unsigned long long sum_avg_pkts_aggregated;
unsigned long long num_aggregations;
-} swStat_t;
+};
/* Xpak releated alarm and warnings */
-typedef struct {
+struct xpakStat {
u64 alarm_transceiver_temp_high;
u64 alarm_transceiver_temp_low;
u64 alarm_laser_bias_current_high;
@@ -110,11 +112,11 @@ typedef struct {
u64 warn_laser_output_power_low;
u64 xpak_regs_stat;
u32 xpak_timer_count;
-} xpakStat_t;
+};
/* The statistics block of Xena */
-typedef struct stat_block {
+struct stat_block {
/* Tx MAC statistics counters. */
__le32 tmac_data_octets;
__le32 tmac_frms;
@@ -290,9 +292,9 @@ typedef struct stat_block {
__le32 reserved_14;
__le32 link_fault_cnt;
u8 buffer[20];
- swStat_t sw_stat;
- xpakStat_t xpak_stat;
-} StatInfo_t;
+ struct swStat sw_stat;
+ struct xpakStat xpak_stat;
+};
/*
* Structures representing different init time configuration
@@ -315,7 +317,7 @@ static int fifo_map[][MAX_TX_FIFOS] = {
};
/* Maintains Per FIFO related information. */
-typedef struct tx_fifo_config {
+struct tx_fifo_config {
#define MAX_AVAILABLE_TXDS 8192
u32 fifo_len; /* specifies len of FIFO upto 8192, ie no of TxDLs */
/* Priority definition */
@@ -332,11 +334,11 @@ typedef struct tx_fifo_config {
u8 f_no_snoop;
#define NO_SNOOP_TXD 0x01
#define NO_SNOOP_TXD_BUFFER 0x02
-} tx_fifo_config_t;
+};
/* Maintains per Ring related information */
-typedef struct rx_ring_config {
+struct rx_ring_config {
u32 num_rxd; /*No of RxDs per Rx Ring */
#define RX_RING_PRI_0 0 /* highest */
#define RX_RING_PRI_1 1
@@ -357,7 +359,7 @@ typedef struct rx_ring_config {
u8 f_no_snoop;
#define NO_SNOOP_RXD 0x01
#define NO_SNOOP_RXD_BUFFER 0x02
-} rx_ring_config_t;
+};
/* This structure provides contains values of the tunable parameters
* of the H/W
@@ -367,7 +369,7 @@ struct config_param {
u32 tx_fifo_num; /*Number of Tx FIFOs */
u8 fifo_mapping[MAX_TX_FIFOS];
- tx_fifo_config_t tx_cfg[MAX_TX_FIFOS]; /*Per-Tx FIFO config */
+ struct tx_fifo_config tx_cfg[MAX_TX_FIFOS]; /*Per-Tx FIFO config */
u32 max_txds; /*Max no. of Tx buffer descriptor per TxDL */
u64 tx_intr_type;
/* Specifies if Tx Intr is UTILZ or PER_LIST type. */
@@ -376,7 +378,7 @@ struct config_param {
u32 rx_ring_num; /*Number of receive rings */
#define MAX_RX_BLOCKS_PER_RING 150
- rx_ring_config_t rx_cfg[MAX_RX_RINGS]; /*Per-Rx Ring config */
+ struct rx_ring_config rx_cfg[MAX_RX_RINGS]; /*Per-Rx Ring config */
u8 bimodal; /*Flag for setting bimodal interrupts*/
#define HEADER_ETHERNET_II_802_3_SIZE 14
@@ -395,14 +397,14 @@ struct config_param {
};
/* Structure representing MAC Addrs */
-typedef struct mac_addr {
+struct mac_addr {
u8 mac_addr[ETH_ALEN];
-} macaddr_t;
+};
/* Structure that represent every FIFO element in the BAR1
* Address location.
*/
-typedef struct _TxFIFO_element {
+struct TxFIFO_element {
u64 TxDL_Pointer;
u64 List_Control;
@@ -413,10 +415,10 @@ typedef struct _TxFIFO_element {
#define TX_FIFO_SPECIAL_FUNC BIT(23)
#define TX_FIFO_DS_NO_SNOOP BIT(31)
#define TX_FIFO_BUFF_NO_SNOOP BIT(30)
-} TxFIFO_element_t;
+};
/* Tx descriptor structure */
-typedef struct _TxD {
+struct TxD {
u64 Control_1;
/* bit mask */
#define TXD_LIST_OWN_XENA BIT(7)
@@ -447,16 +449,16 @@ typedef struct _TxD {
u64 Buffer_Pointer;
u64 Host_Control; /* reserved for host */
-} TxD_t;
+};
/* Structure to hold the phy and virt addr of every TxDL. */
-typedef struct list_info_hold {
+struct list_info_hold {
dma_addr_t list_phy_addr;
void *list_virt_addr;
-} list_info_hold_t;
+};
/* Rx descriptor structure for 1 buffer mode */
-typedef struct _RxD_t {
+struct RxD_t {
u64 Host_Control; /* reserved for host */
u64 Control_1;
#define RXD_OWN_XENA BIT(7)
@@ -481,21 +483,21 @@ typedef struct _RxD_t {
#define SET_NUM_TAG(val) vBIT(val,16,32)
-} RxD_t;
+};
/* Rx descriptor structure for 1 buffer mode */
-typedef struct _RxD1_t {
- struct _RxD_t h;
+struct RxD1 {
+ struct RxD_t h;
#define MASK_BUFFER0_SIZE_1 vBIT(0x3FFF,2,14)
#define SET_BUFFER0_SIZE_1(val) vBIT(val,2,14)
#define RXD_GET_BUFFER0_SIZE_1(_Control_2) \
(u16)((_Control_2 & MASK_BUFFER0_SIZE_1) >> 48)
u64 Buffer0_ptr;
-} RxD1_t;
+};
/* Rx descriptor structure for 3 or 2 buffer mode */
-typedef struct _RxD3_t {
- struct _RxD_t h;
+struct RxD3 {
+ struct RxD_t h;
#define MASK_BUFFER0_SIZE_3 vBIT(0xFF,2,14)
#define MASK_BUFFER1_SIZE_3 vBIT(0xFFFF,16,16)
@@ -515,15 +517,15 @@ typedef struct _RxD3_t {
u64 Buffer0_ptr;
u64 Buffer1_ptr;
u64 Buffer2_ptr;
-} RxD3_t;
+};
/* Structure that represents the Rx descriptor block which contains
* 128 Rx descriptors.
*/
-typedef struct _RxD_block {
+struct RxD_block {
#define MAX_RXDS_PER_BLOCK_1 127
- RxD1_t rxd[MAX_RXDS_PER_BLOCK_1];
+ struct RxD1 rxd[MAX_RXDS_PER_BLOCK_1];
u64 reserved_0;
#define END_OF_BLOCK 0xFEFFFFFFFFFFFFFFULL
@@ -533,22 +535,22 @@ typedef struct _RxD_block {
u64 pNext_RxD_Blk_physical; /* Buff0_ptr.In a 32 bit arch
* the upper 32 bits should
* be 0 */
-} RxD_block_t;
+};
#define SIZE_OF_BLOCK 4096
-#define RXD_MODE_1 0
-#define RXD_MODE_3A 1
-#define RXD_MODE_3B 2
+#define RXD_MODE_1 0 /* One Buffer mode */
+#define RXD_MODE_3A 1 /* Three Buffer mode */
+#define RXD_MODE_3B 2 /* Two Buffer mode */
/* Structure to hold virtual addresses of Buf0 and Buf1 in
* 2buf mode. */
-typedef struct bufAdd {
+struct buffAdd {
void *ba_0_org;
void *ba_1_org;
void *ba_0;
void *ba_1;
-} buffAdd_t;
+};
/* Structure which stores all the MAC control parameters */
@@ -556,43 +558,46 @@ typedef struct bufAdd {
* from which the Rx Interrupt processor can start picking
* up the RxDs for processing.
*/
-typedef struct _rx_curr_get_info_t {
+struct rx_curr_get_info {
u32 block_index;
u32 offset;
u32 ring_len;
-} rx_curr_get_info_t;
+};
-typedef rx_curr_get_info_t rx_curr_put_info_t;
+struct rx_curr_put_info {
+ u32 block_index;
+ u32 offset;
+ u32 ring_len;
+};
/* This structure stores the offset of the TxDl in the FIFO
* from which the Tx Interrupt processor can start picking
* up the TxDLs for send complete interrupt processing.
*/
-typedef struct {
+struct tx_curr_get_info {
u32 offset;
u32 fifo_len;
-} tx_curr_get_info_t;
-
-typedef tx_curr_get_info_t tx_curr_put_info_t;
+};
+struct tx_curr_put_info {
+ u32 offset;
+ u32 fifo_len;
+};
-typedef struct rxd_info {
+struct rxd_info {
void *virt_addr;
dma_addr_t dma_addr;
-}rxd_info_t;
+};
/* Structure that holds the Phy and virt addresses of the Blocks */
-typedef struct rx_block_info {
+struct rx_block_info {
void *block_virt_addr;
dma_addr_t block_dma_addr;
- rxd_info_t *rxds;
-} rx_block_info_t;
-
-/* pre declaration of the nic structure */
-typedef struct s2io_nic nic_t;
+ struct rxd_info *rxds;
+};
/* Ring specific structure */
-typedef struct ring_info {
+struct ring_info {
/* The ring number */
int ring_no;
@@ -600,7 +605,7 @@ typedef struct ring_info {
* Place holders for the virtual and physical addresses of
* all the Rx Blocks
*/
- rx_block_info_t rx_blocks[MAX_RX_BLOCKS_PER_RING];
+ struct rx_block_info rx_blocks[MAX_RX_BLOCKS_PER_RING];
int block_count;
int pkt_cnt;
@@ -608,26 +613,24 @@ typedef struct ring_info {
* Put pointer info which indictes which RxD has to be replenished
* with a new buffer.
*/
- rx_curr_put_info_t rx_curr_put_info;
+ struct rx_curr_put_info rx_curr_put_info;
/*
* Get pointer info which indictes which is the last RxD that was
* processed by the driver.
*/
- rx_curr_get_info_t rx_curr_get_info;
+ struct rx_curr_get_info rx_curr_get_info;
-#ifndef CONFIG_S2IO_NAPI
/* Index to the absolute position of the put pointer of Rx ring */
int put_pos;
-#endif
/* Buffer Address store. */
- buffAdd_t **ba;
- nic_t *nic;
-} ring_info_t;
+ struct buffAdd **ba;
+ struct s2io_nic *nic;
+};
/* Fifo specific structure */
-typedef struct fifo_info {
+struct fifo_info {
/* FIFO number */
int fifo_no;
@@ -635,40 +638,40 @@ typedef struct fifo_info {
int max_txds;
/* Place holder of all the TX List's Phy and Virt addresses. */
- list_info_hold_t *list_info;
+ struct list_info_hold *list_info;
/*
* Current offset within the tx FIFO where driver would write
* new Tx frame
*/
- tx_curr_put_info_t tx_curr_put_info;
+ struct tx_curr_put_info tx_curr_put_info;
/*
* Current offset within tx FIFO from where the driver would start freeing
* the buffers
*/
- tx_curr_get_info_t tx_curr_get_info;
+ struct tx_curr_get_info tx_curr_get_info;
- nic_t *nic;
-}fifo_info_t;
+ struct s2io_nic *nic;
+};
/* Information related to the Tx and Rx FIFOs and Rings of Xena
* is maintained in this structure.
*/
-typedef struct mac_info {
+struct mac_info {
/* tx side stuff */
/* logical pointer of start of each Tx FIFO */
- TxFIFO_element_t __iomem *tx_FIFO_start[MAX_TX_FIFOS];
+ struct TxFIFO_element __iomem *tx_FIFO_start[MAX_TX_FIFOS];
/* Fifo specific structure */
- fifo_info_t fifos[MAX_TX_FIFOS];
+ struct fifo_info fifos[MAX_TX_FIFOS];
/* Save virtual address of TxD page with zero DMA addr(if any) */
void *zerodma_virt_addr;
/* rx side stuff */
/* Ring specific structure */
- ring_info_t rings[MAX_RX_RINGS];
+ struct ring_info rings[MAX_RX_RINGS];
u16 rmac_pause_time;
u16 mc_pause_threshold_q0q3;
@@ -677,14 +680,14 @@ typedef struct mac_info {
void *stats_mem; /* orignal pointer to allocated mem */
dma_addr_t stats_mem_phy; /* Physical address of the stat block */
u32 stats_mem_sz;
- StatInfo_t *stats_info; /* Logical address of the stat block */
-} mac_info_t;
+ struct stat_block *stats_info; /* Logical address of the stat block */
+};
/* structure representing the user defined MAC addresses */
-typedef struct {
+struct usr_addr {
char addr[ETH_ALEN];
int usage_cnt;
-} usr_addr_t;
+};
/* Default Tunable parameters of the NIC. */
#define DEFAULT_FIFO_0_LEN 4096
@@ -717,36 +720,34 @@ struct msix_info_st {
};
/* Data structure to represent a LRO session */
-typedef struct lro {
+struct lro {
struct sk_buff *parent;
struct sk_buff *last_frag;
u8 *l2h;
struct iphdr *iph;
struct tcphdr *tcph;
u32 tcp_next_seq;
- u32 tcp_ack;
+ __be32 tcp_ack;
int total_len;
int frags_len;
int sg_num;
int in_use;
- u16 window;
+ __be16 window;
u32 cur_tsval;
u32 cur_tsecr;
u8 saw_ts;
-}lro_t;
+};
/* Structure representing one instance of the NIC */
struct s2io_nic {
int rxd_mode;
-#ifdef CONFIG_S2IO_NAPI
/*
* Count of packets to be processed in a given iteration, it will be indicated
* by the quota field of the device structure when NAPI is enabled.
*/
int pkts_to_process;
-#endif
struct net_device *dev;
- mac_info_t mac_control;
+ struct mac_info mac_control;
struct config_param config;
struct pci_dev *pdev;
void __iomem *bar0;
@@ -754,8 +755,8 @@ struct s2io_nic {
#define MAX_MAC_SUPPORTED 16
#define MAX_SUPPORTED_MULTICASTS MAX_MAC_SUPPORTED
- macaddr_t def_mac_addr[MAX_MAC_SUPPORTED];
- macaddr_t pre_mac_addr[MAX_MAC_SUPPORTED];
+ struct mac_addr def_mac_addr[MAX_MAC_SUPPORTED];
+ struct mac_addr pre_mac_addr[MAX_MAC_SUPPORTED];
struct net_device_stats stats;
int high_dma_flag;
@@ -775,9 +776,7 @@ struct s2io_nic {
atomic_t rx_bufs_left[MAX_RX_RINGS];
spinlock_t tx_lock;
-#ifndef CONFIG_S2IO_NAPI
spinlock_t put_lock;
-#endif
#define PROMISC 1
#define ALL_MULTI 2
@@ -785,7 +784,7 @@ struct s2io_nic {
#define MAX_ADDRS_SUPPORTED 64
u16 usr_addr_count;
u16 mc_addr_count;
- usr_addr_t usr_addrs[MAX_ADDRS_SUPPORTED];
+ struct usr_addr usr_addrs[MAX_ADDRS_SUPPORTED];
u16 m_cast_flg;
u16 all_multi_pos;
@@ -841,7 +840,7 @@ struct s2io_nic {
u8 device_type;
#define MAX_LRO_SESSIONS 32
- lro_t lro0_n[MAX_LRO_SESSIONS];
+ struct lro lro0_n[MAX_LRO_SESSIONS];
unsigned long clubbed_frms_cnt;
unsigned long sending_both;
u8 lro;
@@ -855,8 +854,9 @@ struct s2io_nic {
spinlock_t rx_lock;
atomic_t isr_cnt;
u64 *ufo_in_band_v;
-#define VPD_PRODUCT_NAME_LEN 50
- u8 product_name[VPD_PRODUCT_NAME_LEN];
+#define VPD_STRING_LEN 80
+ u8 product_name[VPD_STRING_LEN];
+ u8 serial_num[VPD_STRING_LEN];
};
#define RESET_ERROR 1;
@@ -975,43 +975,50 @@ static void __devexit s2io_rem_nic(struct pci_dev *pdev);
static int init_shared_mem(struct s2io_nic *sp);
static void free_shared_mem(struct s2io_nic *sp);
static int init_nic(struct s2io_nic *nic);
-static void rx_intr_handler(ring_info_t *ring_data);
-static void tx_intr_handler(fifo_info_t *fifo_data);
+static void rx_intr_handler(struct ring_info *ring_data);
+static void tx_intr_handler(struct fifo_info *fifo_data);
static void alarm_intr_handler(struct s2io_nic *sp);
static int s2io_starter(void);
+static void s2io_closer(void);
static void s2io_tx_watchdog(struct net_device *dev);
static void s2io_tasklet(unsigned long dev_addr);
static void s2io_set_multicast(struct net_device *dev);
-static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp);
-static void s2io_link(nic_t * sp, int link);
-#if defined(CONFIG_S2IO_NAPI)
+static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp);
+static void s2io_link(struct s2io_nic * sp, int link);
+static void s2io_reset(struct s2io_nic * sp);
static int s2io_poll(struct net_device *dev, int *budget);
-#endif
-static void s2io_init_pci(nic_t * sp);
+static void s2io_init_pci(struct s2io_nic * sp);
static int s2io_set_mac_addr(struct net_device *dev, u8 * addr);
static void s2io_alarm_handle(unsigned long data);
-static int s2io_enable_msi(nic_t *nic);
+static int s2io_enable_msi(struct s2io_nic *nic);
static irqreturn_t s2io_msi_handle(int irq, void *dev_id);
static irqreturn_t
s2io_msix_ring_handle(int irq, void *dev_id);
static irqreturn_t
s2io_msix_fifo_handle(int irq, void *dev_id);
static irqreturn_t s2io_isr(int irq, void *dev_id);
-static int verify_xena_quiescence(nic_t *sp, u64 val64, int flag);
+static int verify_xena_quiescence(struct s2io_nic *sp);
static const struct ethtool_ops netdev_ethtool_ops;
static void s2io_set_link(struct work_struct *work);
-static int s2io_set_swapper(nic_t * sp);
-static void s2io_card_down(nic_t *nic);
-static int s2io_card_up(nic_t *nic);
+static int s2io_set_swapper(struct s2io_nic * sp);
+static void s2io_card_down(struct s2io_nic *nic);
+static int s2io_card_up(struct s2io_nic *nic);
static int get_xena_rev_id(struct pci_dev *pdev);
-static void restore_xmsi_data(nic_t *nic);
+static int wait_for_cmd_complete(void __iomem *addr, u64 busy_bit);
+static int s2io_add_isr(struct s2io_nic * sp);
+static void s2io_rem_isr(struct s2io_nic * sp);
+
+static void restore_xmsi_data(struct s2io_nic *nic);
-static int s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, lro_t **lro, RxD_t *rxdp, nic_t *sp);
-static void clear_lro_session(lro_t *lro);
+static int
+s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, struct lro **lro,
+ struct RxD_t *rxdp, struct s2io_nic *sp);
+static void clear_lro_session(struct lro *lro);
static void queue_rx_frame(struct sk_buff *skb);
-static void update_L3L4_header(nic_t *sp, lro_t *lro);
-static void lro_append_pkt(nic_t *sp, lro_t *lro, struct sk_buff *skb, u32 tcp_len);
+static void update_L3L4_header(struct s2io_nic *sp, struct lro *lro);
+static void lro_append_pkt(struct s2io_nic *sp, struct lro *lro,
+ struct sk_buff *skb, u32 tcp_len);
#define s2io_tcp_mss(skb) skb_shinfo(skb)->gso_size
#define s2io_udp_mss(skb) skb_shinfo(skb)->gso_size
diff --git a/drivers/net/sc92031.c b/drivers/net/sc92031.c
new file mode 100644
index 00000000000..4a926f20b6e
--- /dev/null
+++ b/drivers/net/sc92031.c
@@ -0,0 +1,1620 @@
+/* Silan SC92031 PCI Fast Ethernet Adapter driver
+ *
+ * Based on vendor drivers:
+ * Silan Fast Ethernet Netcard Driver:
+ * MODULE_AUTHOR ("gaoyonghong");
+ * MODULE_DESCRIPTION ("SILAN Fast Ethernet driver");
+ * MODULE_LICENSE("GPL");
+ * 8139D Fast Ethernet driver:
+ * (C) 2002 by gaoyonghong
+ * MODULE_AUTHOR ("gaoyonghong");
+ * MODULE_DESCRIPTION ("Rsltek 8139D PCI Fast Ethernet Adapter driver");
+ * MODULE_LICENSE("GPL");
+ * Both are almost identical and seem to be based on pci-skeleton.c
+ *
+ * Rewritten for 2.6 by Cesar Eduardo Barros
+ */
+
+/* Note about set_mac_address: I don't know how to change the hardware
+ * matching, so you need to enable IFF_PROMISC when using it.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/crc32.h>
+
+#include <asm/irq.h>
+
+#define PCI_VENDOR_ID_SILAN 0x1904
+#define PCI_DEVICE_ID_SILAN_SC92031 0x2031
+#define PCI_DEVICE_ID_SILAN_8139D 0x8139
+
+#define SC92031_NAME "sc92031"
+#define SC92031_DESCRIPTION "Silan SC92031 PCI Fast Ethernet Adapter driver"
+#define SC92031_VERSION "2.0c"
+
+/* BAR 0 is MMIO, BAR 1 is PIO */
+#ifndef SC92031_USE_BAR
+#define SC92031_USE_BAR 0
+#endif
+
+/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast). */
+static int multicast_filter_limit = 64;
+module_param(multicast_filter_limit, int, 0);
+MODULE_PARM_DESC(multicast_filter_limit,
+ "Maximum number of filtered multicast addresses");
+
+static int media;
+module_param(media, int, 0);
+MODULE_PARM_DESC(media, "Media type (0x00 = autodetect,"
+ " 0x01 = 10M half, 0x02 = 10M full,"
+ " 0x04 = 100M half, 0x08 = 100M full)");
+
+/* Size of the in-memory receive ring. */
+#define RX_BUF_LEN_IDX 3 /* 0==8K, 1==16K, 2==32K, 3==64K ,4==128K*/
+#define RX_BUF_LEN (8192 << RX_BUF_LEN_IDX)
+
+/* Number of Tx descriptor registers. */
+#define NUM_TX_DESC 4
+
+/* max supported ethernet frame size -- must be at least (dev->mtu+14+4).*/
+#define MAX_ETH_FRAME_SIZE 1536
+
+/* Size of the Tx bounce buffers -- must be at least (dev->mtu+14+4). */
+#define TX_BUF_SIZE MAX_ETH_FRAME_SIZE
+#define TX_BUF_TOT_LEN (TX_BUF_SIZE * NUM_TX_DESC)
+
+/* The following settings are log_2(bytes)-4: 0 == 16 bytes .. 6==1024, 7==end of packet. */
+#define RX_FIFO_THRESH 7 /* Rx buffer level before first PCI xfer. */
+
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT (4*HZ)
+
+#define SILAN_STATS_NUM 2 /* number of ETHTOOL_GSTATS */
+
+/* media options */
+#define AUTOSELECT 0x00
+#define M10_HALF 0x01
+#define M10_FULL 0x02
+#define M100_HALF 0x04
+#define M100_FULL 0x08
+
+ /* Symbolic offsets to registers. */
+enum silan_registers {
+ Config0 = 0x00, // Config0
+ Config1 = 0x04, // Config1
+ RxBufWPtr = 0x08, // Rx buffer writer poiter
+ IntrStatus = 0x0C, // Interrupt status
+ IntrMask = 0x10, // Interrupt mask
+ RxbufAddr = 0x14, // Rx buffer start address
+ RxBufRPtr = 0x18, // Rx buffer read pointer
+ Txstatusall = 0x1C, // Transmit status of all descriptors
+ TxStatus0 = 0x20, // Transmit status (Four 32bit registers).
+ TxAddr0 = 0x30, // Tx descriptors (also four 32bit).
+ RxConfig = 0x40, // Rx configuration
+ MAC0 = 0x44, // Ethernet hardware address.
+ MAR0 = 0x4C, // Multicast filter.
+ RxStatus0 = 0x54, // Rx status
+ TxConfig = 0x5C, // Tx configuration
+ PhyCtrl = 0x60, // physical control
+ FlowCtrlConfig = 0x64, // flow control
+ Miicmd0 = 0x68, // Mii command0 register
+ Miicmd1 = 0x6C, // Mii command1 register
+ Miistatus = 0x70, // Mii status register
+ Timercnt = 0x74, // Timer counter register
+ TimerIntr = 0x78, // Timer interrupt register
+ PMConfig = 0x7C, // Power Manager configuration
+ CRC0 = 0x80, // Power Manager CRC ( Two 32bit regisers)
+ Wakeup0 = 0x88, // power Manager wakeup( Eight 64bit regiser)
+ LSBCRC0 = 0xC8, // power Manager LSBCRC(Two 32bit regiser)
+ TestD0 = 0xD0,
+ TestD4 = 0xD4,
+ TestD8 = 0xD8,
+};
+
+#define MII_BMCR 0 // Basic mode control register
+#define MII_BMSR 1 // Basic mode status register
+#define MII_JAB 16
+#define MII_OutputStatus 24
+
+#define BMCR_FULLDPLX 0x0100 // Full duplex
+#define BMCR_ANRESTART 0x0200 // Auto negotiation restart
+#define BMCR_ANENABLE 0x1000 // Enable auto negotiation
+#define BMCR_SPEED100 0x2000 // Select 100Mbps
+#define BMSR_LSTATUS 0x0004 // Link status
+#define PHY_16_JAB_ENB 0x1000
+#define PHY_16_PORT_ENB 0x1
+
+enum IntrStatusBits {
+ LinkFail = 0x80000000,
+ LinkOK = 0x40000000,
+ TimeOut = 0x20000000,
+ RxOverflow = 0x0040,
+ RxOK = 0x0020,
+ TxOK = 0x0001,
+ IntrBits = LinkFail|LinkOK|TimeOut|RxOverflow|RxOK|TxOK,
+};
+
+enum TxStatusBits {
+ TxCarrierLost = 0x20000000,
+ TxAborted = 0x10000000,
+ TxOutOfWindow = 0x08000000,
+ TxNccShift = 22,
+ EarlyTxThresShift = 16,
+ TxStatOK = 0x8000,
+ TxUnderrun = 0x4000,
+ TxOwn = 0x2000,
+};
+
+enum RxStatusBits {
+ RxStatesOK = 0x80000,
+ RxBadAlign = 0x40000,
+ RxHugeFrame = 0x20000,
+ RxSmallFrame = 0x10000,
+ RxCRCOK = 0x8000,
+ RxCrlFrame = 0x4000,
+ Rx_Broadcast = 0x2000,
+ Rx_Multicast = 0x1000,
+ RxAddrMatch = 0x0800,
+ MiiErr = 0x0400,
+};
+
+enum RxConfigBits {
+ RxFullDx = 0x80000000,
+ RxEnb = 0x40000000,
+ RxSmall = 0x20000000,
+ RxHuge = 0x10000000,
+ RxErr = 0x08000000,
+ RxAllphys = 0x04000000,
+ RxMulticast = 0x02000000,
+ RxBroadcast = 0x01000000,
+ RxLoopBack = (1 << 23) | (1 << 22),
+ LowThresholdShift = 12,
+ HighThresholdShift = 2,
+};
+
+enum TxConfigBits {
+ TxFullDx = 0x80000000,
+ TxEnb = 0x40000000,
+ TxEnbPad = 0x20000000,
+ TxEnbHuge = 0x10000000,
+ TxEnbFCS = 0x08000000,
+ TxNoBackOff = 0x04000000,
+ TxEnbPrem = 0x02000000,
+ TxCareLostCrs = 0x1000000,
+ TxExdCollNum = 0xf00000,
+ TxDataRate = 0x80000,
+};
+
+enum PhyCtrlconfigbits {
+ PhyCtrlAne = 0x80000000,
+ PhyCtrlSpd100 = 0x40000000,
+ PhyCtrlSpd10 = 0x20000000,
+ PhyCtrlPhyBaseAddr = 0x1f000000,
+ PhyCtrlDux = 0x800000,
+ PhyCtrlReset = 0x400000,
+};
+
+enum FlowCtrlConfigBits {
+ FlowCtrlFullDX = 0x80000000,
+ FlowCtrlEnb = 0x40000000,
+};
+
+enum Config0Bits {
+ Cfg0_Reset = 0x80000000,
+ Cfg0_Anaoff = 0x40000000,
+ Cfg0_LDPS = 0x20000000,
+};
+
+enum Config1Bits {
+ Cfg1_EarlyRx = 1 << 31,
+ Cfg1_EarlyTx = 1 << 30,
+
+ //rx buffer size
+ Cfg1_Rcv8K = 0x0,
+ Cfg1_Rcv16K = 0x1,
+ Cfg1_Rcv32K = 0x3,
+ Cfg1_Rcv64K = 0x7,
+ Cfg1_Rcv128K = 0xf,
+};
+
+enum MiiCmd0Bits {
+ Mii_Divider = 0x20000000,
+ Mii_WRITE = 0x400000,
+ Mii_READ = 0x200000,
+ Mii_SCAN = 0x100000,
+ Mii_Tamod = 0x80000,
+ Mii_Drvmod = 0x40000,
+ Mii_mdc = 0x20000,
+ Mii_mdoen = 0x10000,
+ Mii_mdo = 0x8000,
+ Mii_mdi = 0x4000,
+};
+
+enum MiiStatusBits {
+ Mii_StatusBusy = 0x80000000,
+};
+
+enum PMConfigBits {
+ PM_Enable = 1 << 31,
+ PM_LongWF = 1 << 30,
+ PM_Magic = 1 << 29,
+ PM_LANWake = 1 << 28,
+ PM_LWPTN = (1 << 27 | 1<< 26),
+ PM_LinkUp = 1 << 25,
+ PM_WakeUp = 1 << 24,
+};
+
+/* Locking rules:
+ * priv->lock protects most of the fields of priv and most of the
+ * hardware registers. It does not have to protect against softirqs
+ * between sc92031_disable_interrupts and sc92031_enable_interrupts;
+ * it also does not need to be used in ->open and ->stop while the
+ * device interrupts are off.
+ * Not having to protect against softirqs is very useful due to heavy
+ * use of mdelay() at _sc92031_reset.
+ * Functions prefixed with _sc92031_ must be called with the lock held;
+ * functions prefixed with sc92031_ must be called without the lock held.
+ * Use mmiowb() before unlocking if the hardware was written to.
+ */
+
+/* Locking rules for the interrupt:
+ * - the interrupt and the tasklet never run at the same time
+ * - neither run between sc92031_disable_interrupts and
+ * sc92031_enable_interrupt
+ */
+
+struct sc92031_priv {
+ spinlock_t lock;
+ /* iomap.h cookie */
+ void __iomem *port_base;
+ /* pci device structure */
+ struct pci_dev *pdev;
+ /* tasklet */
+ struct tasklet_struct tasklet;
+
+ /* CPU address of rx ring */
+ void *rx_ring;
+ /* PCI address of rx ring */
+ dma_addr_t rx_ring_dma_addr;
+ /* PCI address of rx ring read pointer */
+ dma_addr_t rx_ring_tail;
+
+ /* tx ring write index */
+ unsigned tx_head;
+ /* tx ring read index */
+ unsigned tx_tail;
+ /* CPU address of tx bounce buffer */
+ void *tx_bufs;
+ /* PCI address of tx bounce buffer */
+ dma_addr_t tx_bufs_dma_addr;
+
+ /* copies of some hardware registers */
+ u32 intr_status;
+ atomic_t intr_mask;
+ u32 rx_config;
+ u32 tx_config;
+ u32 pm_config;
+
+ /* copy of some flags from dev->flags */
+ unsigned int mc_flags;
+
+ /* for ETHTOOL_GSTATS */
+ u64 tx_timeouts;
+ u64 rx_loss;
+
+ /* for dev->get_stats */
+ long rx_value;
+ struct net_device_stats stats;
+};
+
+/* I don't know which registers can be safely read; however, I can guess
+ * MAC0 is one of them. */
+static inline void _sc92031_dummy_read(void __iomem *port_base)
+{
+ ioread32(port_base + MAC0);
+}
+
+static u32 _sc92031_mii_wait(void __iomem *port_base)
+{
+ u32 mii_status;
+
+ do {
+ udelay(10);
+ mii_status = ioread32(port_base + Miistatus);
+ } while (mii_status & Mii_StatusBusy);
+
+ return mii_status;
+}
+
+static u32 _sc92031_mii_cmd(void __iomem *port_base, u32 cmd0, u32 cmd1)
+{
+ iowrite32(Mii_Divider, port_base + Miicmd0);
+
+ _sc92031_mii_wait(port_base);
+
+ iowrite32(cmd1, port_base + Miicmd1);
+ iowrite32(Mii_Divider | cmd0, port_base + Miicmd0);
+
+ return _sc92031_mii_wait(port_base);
+}
+
+static void _sc92031_mii_scan(void __iomem *port_base)
+{
+ _sc92031_mii_cmd(port_base, Mii_SCAN, 0x1 << 6);
+}
+
+static u16 _sc92031_mii_read(void __iomem *port_base, unsigned reg)
+{
+ return _sc92031_mii_cmd(port_base, Mii_READ, reg << 6) >> 13;
+}
+
+static void _sc92031_mii_write(void __iomem *port_base, unsigned reg, u16 val)
+{
+ _sc92031_mii_cmd(port_base, Mii_WRITE, (reg << 6) | ((u32)val << 11));
+}
+
+static void sc92031_disable_interrupts(struct net_device *dev)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+
+ /* tell the tasklet/interrupt not to enable interrupts */
+ atomic_set(&priv->intr_mask, 0);
+ wmb();
+
+ /* stop interrupts */
+ iowrite32(0, port_base + IntrMask);
+ _sc92031_dummy_read(port_base);
+ mmiowb();
+
+ /* wait for any concurrent interrupt/tasklet to finish */
+ synchronize_irq(dev->irq);
+ tasklet_disable(&priv->tasklet);
+}
+
+static void sc92031_enable_interrupts(struct net_device *dev)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+
+ tasklet_enable(&priv->tasklet);
+
+ atomic_set(&priv->intr_mask, IntrBits);
+ wmb();
+
+ iowrite32(IntrBits, port_base + IntrMask);
+ mmiowb();
+}
+
+static void _sc92031_disable_tx_rx(struct net_device *dev)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+
+ priv->rx_config &= ~RxEnb;
+ priv->tx_config &= ~TxEnb;
+ iowrite32(priv->rx_config, port_base + RxConfig);
+ iowrite32(priv->tx_config, port_base + TxConfig);
+}
+
+static void _sc92031_enable_tx_rx(struct net_device *dev)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+
+ priv->rx_config |= RxEnb;
+ priv->tx_config |= TxEnb;
+ iowrite32(priv->rx_config, port_base + RxConfig);
+ iowrite32(priv->tx_config, port_base + TxConfig);
+}
+
+static void _sc92031_tx_clear(struct net_device *dev)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+
+ while (priv->tx_head - priv->tx_tail > 0) {
+ priv->tx_tail++;
+ priv->stats.tx_dropped++;
+ }
+ priv->tx_head = priv->tx_tail = 0;
+}
+
+static void _sc92031_set_mar(struct net_device *dev)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+ u32 mar0 = 0, mar1 = 0;
+
+ if ((dev->flags & IFF_PROMISC)
+ || dev->mc_count > 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) {
+ u32 crc;
+ unsigned bit = 0;
+
+ crc = ~ether_crc(ETH_ALEN, mc_list->dmi_addr);
+ crc >>= 24;
+
+ if (crc & 0x01) bit |= 0x02;
+ if (crc & 0x02) bit |= 0x01;
+ if (crc & 0x10) bit |= 0x20;
+ if (crc & 0x20) bit |= 0x10;
+ if (crc & 0x40) bit |= 0x08;
+ if (crc & 0x80) bit |= 0x04;
+
+ if (bit > 31)
+ mar0 |= 0x1 << (bit - 32);
+ else
+ mar1 |= 0x1 << bit;
+ }
+ }
+
+ iowrite32(mar0, port_base + MAR0);
+ iowrite32(mar1, port_base + MAR0 + 4);
+}
+
+static void _sc92031_set_rx_config(struct net_device *dev)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+ unsigned int old_mc_flags;
+ u32 rx_config_bits = 0;
+
+ old_mc_flags = priv->mc_flags;
+
+ if (dev->flags & IFF_PROMISC)
+ rx_config_bits |= RxSmall | RxHuge | RxErr | RxBroadcast
+ | RxMulticast | RxAllphys;
+
+ if (dev->flags & (IFF_ALLMULTI | IFF_MULTICAST))
+ rx_config_bits |= RxMulticast;
+
+ if (dev->flags & IFF_BROADCAST)
+ rx_config_bits |= RxBroadcast;
+
+ priv->rx_config &= ~(RxSmall | RxHuge | RxErr | RxBroadcast
+ | RxMulticast | RxAllphys);
+ priv->rx_config |= rx_config_bits;
+
+ priv->mc_flags = dev->flags & (IFF_PROMISC | IFF_ALLMULTI
+ | IFF_MULTICAST | IFF_BROADCAST);
+
+ if (netif_carrier_ok(dev) && priv->mc_flags != old_mc_flags)
+ iowrite32(priv->rx_config, port_base + RxConfig);
+}
+
+static bool _sc92031_check_media(struct net_device *dev)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+ u16 bmsr;
+
+ bmsr = _sc92031_mii_read(port_base, MII_BMSR);
+ rmb();
+ if (bmsr & BMSR_LSTATUS) {
+ bool speed_100, duplex_full;
+ u32 flow_ctrl_config = 0;
+ u16 output_status = _sc92031_mii_read(port_base,
+ MII_OutputStatus);
+ _sc92031_mii_scan(port_base);
+
+ speed_100 = output_status & 0x2;
+ duplex_full = output_status & 0x4;
+
+ /* Initial Tx/Rx configuration */
+ priv->rx_config = (0x40 << LowThresholdShift) | (0x1c0 << HighThresholdShift);
+ priv->tx_config = 0x48800000;
+
+ /* NOTE: vendor driver had dead code here to enable tx padding */
+
+ if (!speed_100)
+ priv->tx_config |= 0x80000;
+
+ // configure rx mode
+ _sc92031_set_rx_config(dev);
+
+ if (duplex_full) {
+ priv->rx_config |= RxFullDx;
+ priv->tx_config |= TxFullDx;
+ flow_ctrl_config = FlowCtrlFullDX | FlowCtrlEnb;
+ } else {
+ priv->rx_config &= ~RxFullDx;
+ priv->tx_config &= ~TxFullDx;
+ }
+
+ _sc92031_set_mar(dev);
+ _sc92031_set_rx_config(dev);
+ _sc92031_enable_tx_rx(dev);
+ iowrite32(flow_ctrl_config, port_base + FlowCtrlConfig);
+
+ netif_carrier_on(dev);
+
+ if (printk_ratelimit())
+ printk(KERN_INFO "%s: link up, %sMbps, %s-duplex\n",
+ dev->name,
+ speed_100 ? "100" : "10",
+ duplex_full ? "full" : "half");
+ return true;
+ } else {
+ _sc92031_mii_scan(port_base);
+
+ netif_carrier_off(dev);
+
+ _sc92031_disable_tx_rx(dev);
+
+ if (printk_ratelimit())
+ printk(KERN_INFO "%s: link down\n", dev->name);
+ return false;
+ }
+}
+
+static void _sc92031_phy_reset(struct net_device *dev)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+ u32 phy_ctrl;
+
+ phy_ctrl = ioread32(port_base + PhyCtrl);
+ phy_ctrl &= ~(PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10);
+ phy_ctrl |= PhyCtrlAne | PhyCtrlReset;
+
+ switch (media) {
+ default:
+ case AUTOSELECT:
+ phy_ctrl |= PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10;
+ break;
+ case M10_HALF:
+ phy_ctrl |= PhyCtrlSpd10;
+ break;
+ case M10_FULL:
+ phy_ctrl |= PhyCtrlDux | PhyCtrlSpd10;
+ break;
+ case M100_HALF:
+ phy_ctrl |= PhyCtrlSpd100;
+ break;
+ case M100_FULL:
+ phy_ctrl |= PhyCtrlDux | PhyCtrlSpd100;
+ break;
+ }
+
+ iowrite32(phy_ctrl, port_base + PhyCtrl);
+ mdelay(10);
+
+ phy_ctrl &= ~PhyCtrlReset;
+ iowrite32(phy_ctrl, port_base + PhyCtrl);
+ mdelay(1);
+
+ _sc92031_mii_write(port_base, MII_JAB,
+ PHY_16_JAB_ENB | PHY_16_PORT_ENB);
+ _sc92031_mii_scan(port_base);
+
+ netif_carrier_off(dev);
+ netif_stop_queue(dev);
+}
+
+static void _sc92031_reset(struct net_device *dev)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+
+ /* disable PM */
+ iowrite32(0, port_base + PMConfig);
+
+ /* soft reset the chip */
+ iowrite32(Cfg0_Reset, port_base + Config0);
+ mdelay(200);
+
+ iowrite32(0, port_base + Config0);
+ mdelay(10);
+
+ /* disable interrupts */
+ iowrite32(0, port_base + IntrMask);
+
+ /* clear multicast address */
+ iowrite32(0, port_base + MAR0);
+ iowrite32(0, port_base + MAR0 + 4);
+
+ /* init rx ring */
+ iowrite32(priv->rx_ring_dma_addr, port_base + RxbufAddr);
+ priv->rx_ring_tail = priv->rx_ring_dma_addr;
+
+ /* init tx ring */
+ _sc92031_tx_clear(dev);
+
+ /* clear old register values */
+ priv->intr_status = 0;
+ atomic_set(&priv->intr_mask, 0);
+ priv->rx_config = 0;
+ priv->tx_config = 0;
+ priv->mc_flags = 0;
+
+ /* configure rx buffer size */
+ /* NOTE: vendor driver had dead code here to enable early tx/rx */
+ iowrite32(Cfg1_Rcv64K, port_base + Config1);
+
+ _sc92031_phy_reset(dev);
+ _sc92031_check_media(dev);
+
+ /* calculate rx fifo overflow */
+ priv->rx_value = 0;
+
+ /* enable PM */
+ iowrite32(priv->pm_config, port_base + PMConfig);
+
+ /* clear intr register */
+ ioread32(port_base + IntrStatus);
+}
+
+static void _sc92031_tx_tasklet(struct net_device *dev)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+
+ unsigned old_tx_tail;
+ unsigned entry;
+ u32 tx_status;
+
+ old_tx_tail = priv->tx_tail;
+ while (priv->tx_head - priv->tx_tail > 0) {
+ entry = priv->tx_tail % NUM_TX_DESC;
+ tx_status = ioread32(port_base + TxStatus0 + entry * 4);
+
+ if (!(tx_status & (TxStatOK | TxUnderrun | TxAborted)))
+ break;
+
+ priv->tx_tail++;
+
+ if (tx_status & TxStatOK) {
+ priv->stats.tx_bytes += tx_status & 0x1fff;
+ priv->stats.tx_packets++;
+ /* Note: TxCarrierLost is always asserted at 100mbps. */
+ priv->stats.collisions += (tx_status >> 22) & 0xf;
+ }
+
+ if (tx_status & (TxOutOfWindow | TxAborted)) {
+ priv->stats.tx_errors++;
+
+ if (tx_status & TxAborted)
+ priv->stats.tx_aborted_errors++;
+
+ if (tx_status & TxCarrierLost)
+ priv->stats.tx_carrier_errors++;
+
+ if (tx_status & TxOutOfWindow)
+ priv->stats.tx_window_errors++;
+ }
+
+ if (tx_status & TxUnderrun)
+ priv->stats.tx_fifo_errors++;
+ }
+
+ if (priv->tx_tail != old_tx_tail)
+ if (netif_queue_stopped(dev))
+ netif_wake_queue(dev);
+}
+
+static void _sc92031_rx_tasklet_error(u32 rx_status,
+ struct sc92031_priv *priv, unsigned rx_size)
+{
+ if(rx_size > (MAX_ETH_FRAME_SIZE + 4) || rx_size < 16) {
+ priv->stats.rx_errors++;
+ priv->stats.rx_length_errors++;
+ }
+
+ if (!(rx_status & RxStatesOK)) {
+ priv->stats.rx_errors++;
+
+ if (rx_status & (RxHugeFrame | RxSmallFrame))
+ priv->stats.rx_length_errors++;
+
+ if (rx_status & RxBadAlign)
+ priv->stats.rx_frame_errors++;
+
+ if (!(rx_status & RxCRCOK))
+ priv->stats.rx_crc_errors++;
+ } else
+ priv->rx_loss++;
+}
+
+static void _sc92031_rx_tasklet(struct net_device *dev)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+
+ dma_addr_t rx_ring_head;
+ unsigned rx_len;
+ unsigned rx_ring_offset;
+ void *rx_ring = priv->rx_ring;
+
+ rx_ring_head = ioread32(port_base + RxBufWPtr);
+ rmb();
+
+ /* rx_ring_head is only 17 bits in the RxBufWPtr register.
+ * we need to change it to 32 bits physical address
+ */
+ rx_ring_head &= (dma_addr_t)(RX_BUF_LEN - 1);
+ rx_ring_head |= priv->rx_ring_dma_addr & ~(dma_addr_t)(RX_BUF_LEN - 1);
+ if (rx_ring_head < priv->rx_ring_dma_addr)
+ rx_ring_head += RX_BUF_LEN;
+
+ if (rx_ring_head >= priv->rx_ring_tail)
+ rx_len = rx_ring_head - priv->rx_ring_tail;
+ else
+ rx_len = RX_BUF_LEN - (priv->rx_ring_tail - rx_ring_head);
+
+ if (!rx_len)
+ return;
+
+ if (unlikely(rx_len > RX_BUF_LEN)) {
+ if (printk_ratelimit())
+ printk(KERN_ERR "%s: rx packets length > rx buffer\n",
+ dev->name);
+ return;
+ }
+
+ rx_ring_offset = (priv->rx_ring_tail - priv->rx_ring_dma_addr) % RX_BUF_LEN;
+
+ while (rx_len) {
+ u32 rx_status;
+ unsigned rx_size, rx_size_align, pkt_size;
+ struct sk_buff *skb;
+
+ rx_status = le32_to_cpup((__le32 *)(rx_ring + rx_ring_offset));
+ rmb();
+
+ rx_size = rx_status >> 20;
+ rx_size_align = (rx_size + 3) & ~3; // for 4 bytes aligned
+ pkt_size = rx_size - 4; // Omit the four octet CRC from the length.
+
+ rx_ring_offset = (rx_ring_offset + 4) % RX_BUF_LEN;
+
+ if (unlikely(rx_status == 0
+ || rx_size > (MAX_ETH_FRAME_SIZE + 4)
+ || rx_size < 16
+ || !(rx_status & RxStatesOK))) {
+ _sc92031_rx_tasklet_error(rx_status, priv, rx_size);
+ break;
+ }
+
+ if (unlikely(rx_size_align + 4 > rx_len)) {
+ if (printk_ratelimit())
+ printk(KERN_ERR "%s: rx_len is too small\n", dev->name);
+ break;
+ }
+
+ rx_len -= rx_size_align + 4;
+
+ skb = dev_alloc_skb(pkt_size + NET_IP_ALIGN);
+ if (unlikely(!skb)) {
+ if (printk_ratelimit())
+ printk(KERN_ERR "%s: Couldn't allocate a skb_buff for a packet of size %u\n",
+ dev->name, pkt_size);
+ goto next;
+ }
+
+ skb_reserve(skb, NET_IP_ALIGN);
+
+ if ((rx_ring_offset + pkt_size) > RX_BUF_LEN) {
+ memcpy(skb_put(skb, RX_BUF_LEN - rx_ring_offset),
+ rx_ring + rx_ring_offset, RX_BUF_LEN - rx_ring_offset);
+ memcpy(skb_put(skb, pkt_size - (RX_BUF_LEN - rx_ring_offset)),
+ rx_ring, pkt_size - (RX_BUF_LEN - rx_ring_offset));
+ } else {
+ memcpy(skb_put(skb, pkt_size), rx_ring + rx_ring_offset, pkt_size);
+ }
+
+ skb->dev = dev;
+ skb->protocol = eth_type_trans(skb, dev);
+ dev->last_rx = jiffies;
+ netif_rx(skb);
+
+ priv->stats.rx_bytes += pkt_size;
+ priv->stats.rx_packets++;
+
+ if (rx_status & Rx_Multicast)
+ priv->stats.multicast++;
+
+ next:
+ rx_ring_offset = (rx_ring_offset + rx_size_align) % RX_BUF_LEN;
+ }
+ mb();
+
+ priv->rx_ring_tail = rx_ring_head;
+ iowrite32(priv->rx_ring_tail, port_base + RxBufRPtr);
+}
+
+static void _sc92031_link_tasklet(struct net_device *dev)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+
+ if (_sc92031_check_media(dev))
+ netif_wake_queue(dev);
+ else {
+ netif_stop_queue(dev);
+ priv->stats.tx_carrier_errors++;
+ }
+}
+
+static void sc92031_tasklet(unsigned long data)
+{
+ struct net_device *dev = (struct net_device *)data;
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+ u32 intr_status, intr_mask;
+
+ intr_status = priv->intr_status;
+
+ spin_lock(&priv->lock);
+
+ if (unlikely(!netif_running(dev)))
+ goto out;
+
+ if (intr_status & TxOK)
+ _sc92031_tx_tasklet(dev);
+
+ if (intr_status & RxOK)
+ _sc92031_rx_tasklet(dev);
+
+ if (intr_status & RxOverflow)
+ priv->stats.rx_errors++;
+
+ if (intr_status & TimeOut) {
+ priv->stats.rx_errors++;
+ priv->stats.rx_length_errors++;
+ }
+
+ if (intr_status & (LinkFail | LinkOK))
+ _sc92031_link_tasklet(dev);
+
+out:
+ intr_mask = atomic_read(&priv->intr_mask);
+ rmb();
+
+ iowrite32(intr_mask, port_base + IntrMask);
+ mmiowb();
+
+ spin_unlock(&priv->lock);
+}
+
+static irqreturn_t sc92031_interrupt(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+ u32 intr_status, intr_mask;
+
+ /* mask interrupts before clearing IntrStatus */
+ iowrite32(0, port_base + IntrMask);
+ _sc92031_dummy_read(port_base);
+
+ intr_status = ioread32(port_base + IntrStatus);
+ if (unlikely(intr_status == 0xffffffff))
+ return IRQ_NONE; // hardware has gone missing
+
+ intr_status &= IntrBits;
+ if (!intr_status)
+ goto out_none;
+
+ priv->intr_status = intr_status;
+ tasklet_schedule(&priv->tasklet);
+
+ return IRQ_HANDLED;
+
+out_none:
+ intr_mask = atomic_read(&priv->intr_mask);
+ rmb();
+
+ iowrite32(intr_mask, port_base + IntrMask);
+ mmiowb();
+
+ return IRQ_NONE;
+}
+
+static struct net_device_stats *sc92031_get_stats(struct net_device *dev)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+
+ // FIXME I do not understand what is this trying to do.
+ if (netif_running(dev)) {
+ int temp;
+
+ spin_lock_bh(&priv->lock);
+
+ /* Update the error count. */
+ temp = (ioread32(port_base + RxStatus0) >> 16) & 0xffff;
+
+ if (temp == 0xffff) {
+ priv->rx_value += temp;
+ priv->stats.rx_fifo_errors = priv->rx_value;
+ } else {
+ priv->stats.rx_fifo_errors = temp + priv->rx_value;
+ }
+
+ spin_unlock_bh(&priv->lock);
+ }
+
+ return &priv->stats;
+}
+
+static int sc92031_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ int err = 0;
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+
+ unsigned len;
+ unsigned entry;
+ u32 tx_status;
+
+ if (unlikely(skb->len > TX_BUF_SIZE)) {
+ err = -EMSGSIZE;
+ priv->stats.tx_dropped++;
+ goto out;
+ }
+
+ spin_lock_bh(&priv->lock);
+
+ if (unlikely(!netif_carrier_ok(dev))) {
+ err = -ENOLINK;
+ priv->stats.tx_dropped++;
+ goto out_unlock;
+ }
+
+ BUG_ON(priv->tx_head - priv->tx_tail >= NUM_TX_DESC);
+
+ entry = priv->tx_head++ % NUM_TX_DESC;
+
+ skb_copy_and_csum_dev(skb, priv->tx_bufs + entry * TX_BUF_SIZE);
+
+ len = skb->len;
+ if (unlikely(len < ETH_ZLEN)) {
+ memset(priv->tx_bufs + entry * TX_BUF_SIZE + len,
+ 0, ETH_ZLEN - len);
+ len = ETH_ZLEN;
+ }
+
+ wmb();
+
+ if (len < 100)
+ tx_status = len;
+ else if (len < 300)
+ tx_status = 0x30000 | len;
+ else
+ tx_status = 0x50000 | len;
+
+ iowrite32(priv->tx_bufs_dma_addr + entry * TX_BUF_SIZE,
+ port_base + TxAddr0 + entry * 4);
+ iowrite32(tx_status, port_base + TxStatus0 + entry * 4);
+ mmiowb();
+
+ dev->trans_start = jiffies;
+
+ if (priv->tx_head - priv->tx_tail >= NUM_TX_DESC)
+ netif_stop_queue(dev);
+
+out_unlock:
+ spin_unlock_bh(&priv->lock);
+
+out:
+ dev_kfree_skb(skb);
+
+ return err;
+}
+
+static int sc92031_open(struct net_device *dev)
+{
+ int err;
+ struct sc92031_priv *priv = netdev_priv(dev);
+ struct pci_dev *pdev = priv->pdev;
+
+ priv->rx_ring = pci_alloc_consistent(pdev, RX_BUF_LEN,
+ &priv->rx_ring_dma_addr);
+ if (unlikely(!priv->rx_ring)) {
+ err = -ENOMEM;
+ goto out_alloc_rx_ring;
+ }
+
+ priv->tx_bufs = pci_alloc_consistent(pdev, TX_BUF_TOT_LEN,
+ &priv->tx_bufs_dma_addr);
+ if (unlikely(!priv->tx_bufs)) {
+ err = -ENOMEM;
+ goto out_alloc_tx_bufs;
+ }
+ priv->tx_head = priv->tx_tail = 0;
+
+ err = request_irq(pdev->irq, sc92031_interrupt,
+ IRQF_SHARED, dev->name, dev);
+ if (unlikely(err < 0))
+ goto out_request_irq;
+
+ priv->pm_config = 0;
+
+ /* Interrupts already disabled by sc92031_stop or sc92031_probe */
+ spin_lock(&priv->lock);
+
+ _sc92031_reset(dev);
+ mmiowb();
+
+ spin_unlock(&priv->lock);
+ sc92031_enable_interrupts(dev);
+
+ if (netif_carrier_ok(dev))
+ netif_start_queue(dev);
+ else
+ netif_tx_disable(dev);
+
+ return 0;
+
+out_request_irq:
+ pci_free_consistent(pdev, TX_BUF_TOT_LEN, priv->tx_bufs,
+ priv->tx_bufs_dma_addr);
+out_alloc_tx_bufs:
+ pci_free_consistent(pdev, RX_BUF_LEN, priv->rx_ring,
+ priv->rx_ring_dma_addr);
+out_alloc_rx_ring:
+ return err;
+}
+
+static int sc92031_stop(struct net_device *dev)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+ struct pci_dev *pdev = priv->pdev;
+
+ netif_tx_disable(dev);
+
+ /* Disable interrupts, stop Tx and Rx. */
+ sc92031_disable_interrupts(dev);
+
+ spin_lock(&priv->lock);
+
+ _sc92031_disable_tx_rx(dev);
+ _sc92031_tx_clear(dev);
+ mmiowb();
+
+ spin_unlock(&priv->lock);
+
+ free_irq(pdev->irq, dev);
+ pci_free_consistent(pdev, TX_BUF_TOT_LEN, priv->tx_bufs,
+ priv->tx_bufs_dma_addr);
+ pci_free_consistent(pdev, RX_BUF_LEN, priv->rx_ring,
+ priv->rx_ring_dma_addr);
+
+ return 0;
+}
+
+static void sc92031_set_multicast_list(struct net_device *dev)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+
+ spin_lock_bh(&priv->lock);
+
+ _sc92031_set_mar(dev);
+ _sc92031_set_rx_config(dev);
+ mmiowb();
+
+ spin_unlock_bh(&priv->lock);
+}
+
+static void sc92031_tx_timeout(struct net_device *dev)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+
+ /* Disable interrupts by clearing the interrupt mask.*/
+ sc92031_disable_interrupts(dev);
+
+ spin_lock(&priv->lock);
+
+ priv->tx_timeouts++;
+
+ _sc92031_reset(dev);
+ mmiowb();
+
+ spin_unlock(&priv->lock);
+
+ /* enable interrupts */
+ sc92031_enable_interrupts(dev);
+
+ if (netif_carrier_ok(dev))
+ netif_wake_queue(dev);
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void sc92031_poll_controller(struct net_device *dev)
+{
+ disable_irq(dev->irq);
+ if (sc92031_interrupt(dev->irq, dev) != IRQ_NONE)
+ sc92031_tasklet((unsigned long)dev);
+ enable_irq(dev->irq);
+}
+#endif
+
+static int sc92031_ethtool_get_settings(struct net_device *dev,
+ struct ethtool_cmd *cmd)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+ u8 phy_address;
+ u32 phy_ctrl;
+ u16 output_status;
+
+ spin_lock_bh(&priv->lock);
+
+ phy_address = ioread32(port_base + Miicmd1) >> 27;
+ phy_ctrl = ioread32(port_base + PhyCtrl);
+
+ output_status = _sc92031_mii_read(port_base, MII_OutputStatus);
+ _sc92031_mii_scan(port_base);
+ mmiowb();
+
+ spin_unlock_bh(&priv->lock);
+
+ cmd->supported = SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full
+ | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full
+ | SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII;
+
+ cmd->advertising = ADVERTISED_TP | ADVERTISED_MII;
+
+ if ((phy_ctrl & (PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10))
+ == (PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10))
+ cmd->advertising |= ADVERTISED_Autoneg;
+
+ if ((phy_ctrl & PhyCtrlSpd10) == PhyCtrlSpd10)
+ cmd->advertising |= ADVERTISED_10baseT_Half;
+
+ if ((phy_ctrl & (PhyCtrlSpd10 | PhyCtrlDux))
+ == (PhyCtrlSpd10 | PhyCtrlDux))
+ cmd->advertising |= ADVERTISED_10baseT_Full;
+
+ if ((phy_ctrl & PhyCtrlSpd100) == PhyCtrlSpd100)
+ cmd->advertising |= ADVERTISED_100baseT_Half;
+
+ if ((phy_ctrl & (PhyCtrlSpd100 | PhyCtrlDux))
+ == (PhyCtrlSpd100 | PhyCtrlDux))
+ cmd->advertising |= ADVERTISED_100baseT_Full;
+
+ if (phy_ctrl & PhyCtrlAne)
+ cmd->advertising |= ADVERTISED_Autoneg;
+
+ cmd->speed = (output_status & 0x2) ? SPEED_100 : SPEED_10;
+ cmd->duplex = (output_status & 0x4) ? DUPLEX_FULL : DUPLEX_HALF;
+ cmd->port = PORT_MII;
+ cmd->phy_address = phy_address;
+ cmd->transceiver = XCVR_INTERNAL;
+ cmd->autoneg = (phy_ctrl & PhyCtrlAne) ? AUTONEG_ENABLE : AUTONEG_DISABLE;
+
+ return 0;
+}
+
+static int sc92031_ethtool_set_settings(struct net_device *dev,
+ struct ethtool_cmd *cmd)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+ u32 phy_ctrl;
+ u32 old_phy_ctrl;
+
+ if (!(cmd->speed == SPEED_10 || cmd->speed == SPEED_100))
+ return -EINVAL;
+ if (!(cmd->duplex == DUPLEX_HALF || cmd->duplex == DUPLEX_FULL))
+ return -EINVAL;
+ if (!(cmd->port == PORT_MII))
+ return -EINVAL;
+ if (!(cmd->phy_address == 0x1f))
+ return -EINVAL;
+ if (!(cmd->transceiver == XCVR_INTERNAL))
+ return -EINVAL;
+ if (!(cmd->autoneg == AUTONEG_DISABLE || cmd->autoneg == AUTONEG_ENABLE))
+ return -EINVAL;
+
+ if (cmd->autoneg == AUTONEG_ENABLE) {
+ if (!(cmd->advertising & (ADVERTISED_Autoneg
+ | ADVERTISED_100baseT_Full
+ | ADVERTISED_100baseT_Half
+ | ADVERTISED_10baseT_Full
+ | ADVERTISED_10baseT_Half)))
+ return -EINVAL;
+
+ phy_ctrl = PhyCtrlAne;
+
+ // FIXME: I'm not sure what the original code was trying to do
+ if (cmd->advertising & ADVERTISED_Autoneg)
+ phy_ctrl |= PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10;
+ if (cmd->advertising & ADVERTISED_100baseT_Full)
+ phy_ctrl |= PhyCtrlDux | PhyCtrlSpd100;
+ if (cmd->advertising & ADVERTISED_100baseT_Half)
+ phy_ctrl |= PhyCtrlSpd100;
+ if (cmd->advertising & ADVERTISED_10baseT_Full)
+ phy_ctrl |= PhyCtrlSpd10 | PhyCtrlDux;
+ if (cmd->advertising & ADVERTISED_10baseT_Half)
+ phy_ctrl |= PhyCtrlSpd10;
+ } else {
+ // FIXME: Whole branch guessed
+ phy_ctrl = 0;
+
+ if (cmd->speed == SPEED_10)
+ phy_ctrl |= PhyCtrlSpd10;
+ else /* cmd->speed == SPEED_100 */
+ phy_ctrl |= PhyCtrlSpd100;
+
+ if (cmd->duplex == DUPLEX_FULL)
+ phy_ctrl |= PhyCtrlDux;
+ }
+
+ spin_lock_bh(&priv->lock);
+
+ old_phy_ctrl = ioread32(port_base + PhyCtrl);
+ phy_ctrl |= old_phy_ctrl & ~(PhyCtrlAne | PhyCtrlDux
+ | PhyCtrlSpd100 | PhyCtrlSpd10);
+ if (phy_ctrl != old_phy_ctrl)
+ iowrite32(phy_ctrl, port_base + PhyCtrl);
+
+ spin_unlock_bh(&priv->lock);
+
+ return 0;
+}
+
+static void sc92031_ethtool_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *drvinfo)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+ struct pci_dev *pdev = priv->pdev;
+
+ strcpy(drvinfo->driver, SC92031_NAME);
+ strcpy(drvinfo->version, SC92031_VERSION);
+ strcpy(drvinfo->bus_info, pci_name(pdev));
+}
+
+static void sc92031_ethtool_get_wol(struct net_device *dev,
+ struct ethtool_wolinfo *wolinfo)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+ u32 pm_config;
+
+ spin_lock_bh(&priv->lock);
+ pm_config = ioread32(port_base + PMConfig);
+ spin_unlock_bh(&priv->lock);
+
+ // FIXME: Guessed
+ wolinfo->supported = WAKE_PHY | WAKE_MAGIC
+ | WAKE_UCAST | WAKE_MCAST | WAKE_BCAST;
+ wolinfo->wolopts = 0;
+
+ if (pm_config & PM_LinkUp)
+ wolinfo->wolopts |= WAKE_PHY;
+
+ if (pm_config & PM_Magic)
+ wolinfo->wolopts |= WAKE_MAGIC;
+
+ if (pm_config & PM_WakeUp)
+ // FIXME: Guessed
+ wolinfo->wolopts |= WAKE_UCAST | WAKE_MCAST | WAKE_BCAST;
+}
+
+static int sc92031_ethtool_set_wol(struct net_device *dev,
+ struct ethtool_wolinfo *wolinfo)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+ u32 pm_config;
+
+ spin_lock_bh(&priv->lock);
+
+ pm_config = ioread32(port_base + PMConfig)
+ & ~(PM_LinkUp | PM_Magic | PM_WakeUp);
+
+ if (wolinfo->wolopts & WAKE_PHY)
+ pm_config |= PM_LinkUp;
+
+ if (wolinfo->wolopts & WAKE_MAGIC)
+ pm_config |= PM_Magic;
+
+ // FIXME: Guessed
+ if (wolinfo->wolopts & (WAKE_UCAST | WAKE_MCAST | WAKE_BCAST))
+ pm_config |= PM_WakeUp;
+
+ priv->pm_config = pm_config;
+ iowrite32(pm_config, port_base + PMConfig);
+ mmiowb();
+
+ spin_unlock_bh(&priv->lock);
+
+ return 0;
+}
+
+static int sc92031_ethtool_nway_reset(struct net_device *dev)
+{
+ int err = 0;
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem *port_base = priv->port_base;
+ u16 bmcr;
+
+ spin_lock_bh(&priv->lock);
+
+ bmcr = _sc92031_mii_read(port_base, MII_BMCR);
+ if (!(bmcr & BMCR_ANENABLE)) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ _sc92031_mii_write(port_base, MII_BMCR, bmcr | BMCR_ANRESTART);
+
+out:
+ _sc92031_mii_scan(port_base);
+ mmiowb();
+
+ spin_unlock_bh(&priv->lock);
+
+ return err;
+}
+
+static const char sc92031_ethtool_stats_strings[SILAN_STATS_NUM][ETH_GSTRING_LEN] = {
+ "tx_timeout",
+ "rx_loss",
+};
+
+static void sc92031_ethtool_get_strings(struct net_device *dev,
+ u32 stringset, u8 *data)
+{
+ if (stringset == ETH_SS_STATS)
+ memcpy(data, sc92031_ethtool_stats_strings,
+ SILAN_STATS_NUM * ETH_GSTRING_LEN);
+}
+
+static int sc92031_ethtool_get_stats_count(struct net_device *dev)
+{
+ return SILAN_STATS_NUM;
+}
+
+static void sc92031_ethtool_get_ethtool_stats(struct net_device *dev,
+ struct ethtool_stats *stats, u64 *data)
+{
+ struct sc92031_priv *priv = netdev_priv(dev);
+
+ spin_lock_bh(&priv->lock);
+ data[0] = priv->tx_timeouts;
+ data[1] = priv->rx_loss;
+ spin_unlock_bh(&priv->lock);
+}
+
+static struct ethtool_ops sc92031_ethtool_ops = {
+ .get_settings = sc92031_ethtool_get_settings,
+ .set_settings = sc92031_ethtool_set_settings,
+ .get_drvinfo = sc92031_ethtool_get_drvinfo,
+ .get_wol = sc92031_ethtool_get_wol,
+ .set_wol = sc92031_ethtool_set_wol,
+ .nway_reset = sc92031_ethtool_nway_reset,
+ .get_link = ethtool_op_get_link,
+ .get_tx_csum = ethtool_op_get_tx_csum,
+ .get_sg = ethtool_op_get_sg,
+ .get_tso = ethtool_op_get_tso,
+ .get_strings = sc92031_ethtool_get_strings,
+ .get_stats_count = sc92031_ethtool_get_stats_count,
+ .get_ethtool_stats = sc92031_ethtool_get_ethtool_stats,
+ .get_perm_addr = ethtool_op_get_perm_addr,
+ .get_ufo = ethtool_op_get_ufo,
+};
+
+static int __devinit sc92031_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ int err;
+ void __iomem* port_base;
+ struct net_device *dev;
+ struct sc92031_priv *priv;
+ u32 mac0, mac1;
+
+ err = pci_enable_device(pdev);
+ if (unlikely(err < 0))
+ goto out_enable_device;
+
+ pci_set_master(pdev);
+
+ err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ if (unlikely(err < 0))
+ goto out_set_dma_mask;
+
+ err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+ if (unlikely(err < 0))
+ goto out_set_dma_mask;
+
+ err = pci_request_regions(pdev, SC92031_NAME);
+ if (unlikely(err < 0))
+ goto out_request_regions;
+
+ port_base = pci_iomap(pdev, SC92031_USE_BAR, 0);
+ if (unlikely(!port_base)) {
+ err = -EIO;
+ goto out_iomap;
+ }
+
+ dev = alloc_etherdev(sizeof(struct sc92031_priv));
+ if (unlikely(!dev)) {
+ err = -ENOMEM;
+ goto out_alloc_etherdev;
+ }
+
+ pci_set_drvdata(pdev, dev);
+
+#if SC92031_USE_BAR == 0
+ dev->mem_start = pci_resource_start(pdev, SC92031_USE_BAR);
+ dev->mem_end = pci_resource_end(pdev, SC92031_USE_BAR);
+#elif SC92031_USE_BAR == 1
+ dev->base_addr = pci_resource_start(pdev, SC92031_USE_BAR);
+#endif
+ dev->irq = pdev->irq;
+
+ /* faked with skb_copy_and_csum_dev */
+ dev->features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_HIGHDMA;
+
+ dev->get_stats = sc92031_get_stats;
+ dev->ethtool_ops = &sc92031_ethtool_ops;
+ dev->hard_start_xmit = sc92031_start_xmit;
+ dev->watchdog_timeo = TX_TIMEOUT;
+ dev->open = sc92031_open;
+ dev->stop = sc92031_stop;
+ dev->set_multicast_list = sc92031_set_multicast_list;
+ dev->tx_timeout = sc92031_tx_timeout;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ dev->poll_controller = sc92031_poll_controller;
+#endif
+
+ priv = netdev_priv(dev);
+ spin_lock_init(&priv->lock);
+ priv->port_base = port_base;
+ priv->pdev = pdev;
+ tasklet_init(&priv->tasklet, sc92031_tasklet, (unsigned long)dev);
+ /* Fudge tasklet count so the call to sc92031_enable_interrupts at
+ * sc92031_open will work correctly */
+ tasklet_disable_nosync(&priv->tasklet);
+
+ /* PCI PM Wakeup */
+ iowrite32((~PM_LongWF & ~PM_LWPTN) | PM_Enable, port_base + PMConfig);
+
+ mac0 = ioread32(port_base + MAC0);
+ mac1 = ioread32(port_base + MAC0 + 4);
+ dev->dev_addr[0] = dev->perm_addr[0] = mac0 >> 24;
+ dev->dev_addr[1] = dev->perm_addr[1] = mac0 >> 16;
+ dev->dev_addr[2] = dev->perm_addr[2] = mac0 >> 8;
+ dev->dev_addr[3] = dev->perm_addr[3] = mac0;
+ dev->dev_addr[4] = dev->perm_addr[4] = mac1 >> 8;
+ dev->dev_addr[5] = dev->perm_addr[5] = mac1;
+
+ err = register_netdev(dev);
+ if (err < 0)
+ goto out_register_netdev;
+
+ return 0;
+
+out_register_netdev:
+ free_netdev(dev);
+out_alloc_etherdev:
+ pci_iounmap(pdev, port_base);
+out_iomap:
+ pci_release_regions(pdev);
+out_request_regions:
+out_set_dma_mask:
+ pci_disable_device(pdev);
+out_enable_device:
+ return err;
+}
+
+static void __devexit sc92031_remove(struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct sc92031_priv *priv = netdev_priv(dev);
+ void __iomem* port_base = priv->port_base;
+
+ unregister_netdev(dev);
+ free_netdev(dev);
+ pci_iounmap(pdev, port_base);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+}
+
+static int sc92031_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct sc92031_priv *priv = netdev_priv(dev);
+
+ pci_save_state(pdev);
+
+ if (!netif_running(dev))
+ goto out;
+
+ netif_device_detach(dev);
+
+ /* Disable interrupts, stop Tx and Rx. */
+ sc92031_disable_interrupts(dev);
+
+ spin_lock(&priv->lock);
+
+ _sc92031_disable_tx_rx(dev);
+ _sc92031_tx_clear(dev);
+ mmiowb();
+
+ spin_unlock(&priv->lock);
+
+out:
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
+ return 0;
+}
+
+static int sc92031_resume(struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct sc92031_priv *priv = netdev_priv(dev);
+
+ pci_restore_state(pdev);
+ pci_set_power_state(pdev, PCI_D0);
+
+ if (!netif_running(dev))
+ goto out;
+
+ /* Interrupts already disabled by sc92031_suspend */
+ spin_lock(&priv->lock);
+
+ _sc92031_reset(dev);
+ mmiowb();
+
+ spin_unlock(&priv->lock);
+ sc92031_enable_interrupts(dev);
+
+ netif_device_attach(dev);
+
+ if (netif_carrier_ok(dev))
+ netif_wake_queue(dev);
+ else
+ netif_tx_disable(dev);
+
+out:
+ return 0;
+}
+
+static struct pci_device_id sc92031_pci_device_id_table[] __devinitdata = {
+ { PCI_DEVICE(PCI_VENDOR_ID_SILAN, PCI_DEVICE_ID_SILAN_SC92031) },
+ { PCI_DEVICE(PCI_VENDOR_ID_SILAN, PCI_DEVICE_ID_SILAN_8139D) },
+ { 0, }
+};
+MODULE_DEVICE_TABLE(pci, sc92031_pci_device_id_table);
+
+static struct pci_driver sc92031_pci_driver = {
+ .name = SC92031_NAME,
+ .id_table = sc92031_pci_device_id_table,
+ .probe = sc92031_probe,
+ .remove = __devexit_p(sc92031_remove),
+ .suspend = sc92031_suspend,
+ .resume = sc92031_resume,
+};
+
+static int __init sc92031_init(void)
+{
+ printk(KERN_INFO SC92031_DESCRIPTION " " SC92031_VERSION "\n");
+ return pci_register_driver(&sc92031_pci_driver);
+}
+
+static void __exit sc92031_exit(void)
+{
+ pci_unregister_driver(&sc92031_pci_driver);
+}
+
+module_init(sc92031_init);
+module_exit(sc92031_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Cesar Eduardo Barros <cesarb@cesarb.net>");
+MODULE_DESCRIPTION(SC92031_DESCRIPTION);
+MODULE_VERSION(SC92031_VERSION);
diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c
index 45d91b15910..b08508b3583 100644
--- a/drivers/net/sis190.c
+++ b/drivers/net/sis190.c
@@ -909,6 +909,9 @@ static void sis190_phy_task(struct work_struct *work)
rtnl_lock();
+ if (!netif_running(dev))
+ goto out_unlock;
+
val = mdio_read(ioaddr, phy_id, MII_BMCR);
if (val & BMCR_RESET) {
// FIXME: needlessly high ? -- FR 02/07/2005
@@ -981,6 +984,7 @@ static void sis190_phy_task(struct work_struct *work)
netif_carrier_on(dev);
}
+out_unlock:
rtnl_unlock();
}
@@ -1102,8 +1106,6 @@ static void sis190_down(struct net_device *dev)
netif_stop_queue(dev);
- flush_scheduled_work();
-
do {
spin_lock_irq(&tp->lock);
@@ -1857,6 +1859,7 @@ static void __devexit sis190_remove_one(struct pci_dev *pdev)
struct net_device *dev = pci_get_drvdata(pdev);
sis190_mii_remove(dev);
+ flush_scheduled_work();
unregister_netdev(dev);
sis190_release_board(pdev);
pci_set_drvdata(pdev, NULL);
diff --git a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c
index 92d11b961db..e94ab256b54 100644
--- a/drivers/net/sk98lin/skge.c
+++ b/drivers/net/sk98lin/skge.c
@@ -5188,6 +5188,9 @@ static struct pci_driver skge_driver = {
static int __init skge_init(void)
{
+ printk(KERN_NOTICE "sk98lin: driver has been replaced by the skge driver"
+ " and is scheduled for removal\n");
+
return pci_register_driver(&skge_driver);
}
diff --git a/drivers/net/sk_mca.c b/drivers/net/sk_mca.c
deleted file mode 100644
index 96e06c51b75..00000000000
--- a/drivers/net/sk_mca.c
+++ /dev/null
@@ -1,1216 +0,0 @@
-/*
-net-3-driver for the SKNET MCA-based cards
-
-This is an extension to the Linux operating system, and is covered by the
-same GNU General Public License that covers that work.
-
-Copyright 1999 by Alfred Arnold (alfred@ccac.rwth-aachen.de,
- alfred.arnold@lancom.de)
-
-This driver is based both on the 3C523 driver and the SK_G16 driver.
-
-paper sources:
- 'PC Hardware: Aufbau, Funktionsweise, Programmierung' by
- Hans-Peter Messmer for the basic Microchannel stuff
-
- 'Linux Geraetetreiber' by Allesandro Rubini, Kalle Dalheimer
- for help on Ethernet driver programming
-
- 'Ethernet/IEEE 802.3 Family 1992 World Network Data Book/Handbook' by AMD
- for documentation on the AM7990 LANCE
-
- 'SKNET Personal Technisches Manual', Version 1.2 by Schneider&Koch
- for documentation on the Junior board
-
- 'SK-NET MC2+ Technical Manual", Version 1.1 by Schneider&Koch for
- documentation on the MC2 bord
-
- A big thank you to the S&K support for providing me so quickly with
- documentation!
-
- Also see http://www.syskonnect.com/
-
- Missing things:
-
- -> set debug level via ioctl instead of compile-time switches
- -> I didn't follow the development of the 2.1.x kernels, so my
- assumptions about which things changed with which kernel version
- are probably nonsense
-
-History:
- May 16th, 1999
- startup
- May 22st, 1999
- added private structure, methods
- begun building data structures in RAM
- May 23nd, 1999
- can receive frames, send frames
- May 24th, 1999
- modularized initialization of LANCE
- loadable as module
- still Tx problem :-(
- May 26th, 1999
- MC2 works
- support for multiple devices
- display media type for MC2+
- May 28th, 1999
- fixed problem in GetLANCE leaving interrupts turned off
- increase TX queue to 4 packets to improve send performance
- May 29th, 1999
- a few corrections in statistics, caught rcvr overruns
- reinitialization of LANCE/board in critical situations
- MCA info implemented
- implemented LANCE multicast filter
- Jun 6th, 1999
- additions for Linux 2.2
- Dec 25th, 1999
- unfortunately there seem to be newer MC2+ boards that react
- on IRQ 3/5/9/10 instead of 3/5/10/11, so we have to autoprobe
- in questionable cases...
- Dec 28th, 1999
- integrated patches from David Weinehall & Bill Wendling for 2.3
- kernels (isa_...functions). Things are defined in a way that
- it still works with 2.0.x 8-)
- Dec 30th, 1999
- added handling of the remaining interrupt conditions. That
- should cure the spurious hangs.
- Jan 30th, 2000
- newer kernels automatically probe more than one board, so the
- 'startslot' as a variable is also needed here
- June 1st, 2000
- added changes for recent 2.3 kernels
-
- *************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/time.h>
-#include <linux/mca-legacy.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/bitops.h>
-
-#include <asm/processor.h>
-#include <asm/io.h>
-
-#define _SK_MCA_DRIVER_
-#include "sk_mca.h"
-
-/* ------------------------------------------------------------------------
- * global static data - not more since we can handle multiple boards and
- * have to pack all state info into the device struct!
- * ------------------------------------------------------------------------ */
-
-static char *MediaNames[Media_Count] =
- { "10Base2", "10BaseT", "10Base5", "Unknown" };
-
-static unsigned char poly[] =
- { 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0,
- 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0
-};
-
-/* ------------------------------------------------------------------------
- * private subfunctions
- * ------------------------------------------------------------------------ */
-
-/* dump parts of shared memory - only needed during debugging */
-
-#ifdef DEBUG
-static void dumpmem(struct net_device *dev, u32 start, u32 len)
-{
- skmca_priv *priv = netdev_priv(dev);
- int z;
-
- for (z = 0; z < len; z++) {
- if ((z & 15) == 0)
- printk("%04x:", z);
- printk(" %02x", readb(priv->base + start + z));
- if ((z & 15) == 15)
- printk("\n");
- }
-}
-
-/* print exact time - ditto */
-
-static void PrTime(void)
-{
- struct timeval tv;
-
- do_gettimeofday(&tv);
- printk("%9d:%06d: ", tv.tv_sec, tv.tv_usec);
-}
-#endif
-
-/* deduce resources out of POS registers */
-
-static void __init getaddrs(int slot, int junior, int *base, int *irq,
- skmca_medium * medium)
-{
- u_char pos0, pos1, pos2;
-
- if (junior) {
- pos0 = mca_read_stored_pos(slot, 2);
- *base = ((pos0 & 0x0e) << 13) + 0xc0000;
- *irq = ((pos0 & 0x10) >> 4) + 10;
- *medium = Media_Unknown;
- } else {
- /* reset POS 104 Bits 0+1 so the shared memory region goes to the
- configured area between 640K and 1M. Afterwards, enable the MC2.
- I really don't know what rode SK to do this... */
-
- mca_write_pos(slot, 4,
- mca_read_stored_pos(slot, 4) & 0xfc);
- mca_write_pos(slot, 2,
- mca_read_stored_pos(slot, 2) | 0x01);
-
- pos1 = mca_read_stored_pos(slot, 3);
- pos2 = mca_read_stored_pos(slot, 4);
- *base = ((pos1 & 0x07) << 14) + 0xc0000;
- switch (pos2 & 0x0c) {
- case 0:
- *irq = 3;
- break;
- case 4:
- *irq = 5;
- break;
- case 8:
- *irq = -10;
- break;
- case 12:
- *irq = -11;
- break;
- }
- *medium = (pos2 >> 6) & 3;
- }
-}
-
-/* check for both cards:
- When the MC2 is turned off, it was configured for more than 15MB RAM,
- is disabled and won't get detected using the standard probe. We
- therefore have to scan the slots manually :-( */
-
-static int __init dofind(int *junior, int firstslot)
-{
- int slot;
- unsigned int id;
-
- for (slot = firstslot; slot < MCA_MAX_SLOT_NR; slot++) {
- id = mca_read_stored_pos(slot, 0)
- + (((unsigned int) mca_read_stored_pos(slot, 1)) << 8);
-
- *junior = 0;
- if (id == SKNET_MCA_ID)
- return slot;
- *junior = 1;
- if (id == SKNET_JUNIOR_MCA_ID)
- return slot;
- }
- return MCA_NOTFOUND;
-}
-
-/* reset the whole board */
-
-static void ResetBoard(struct net_device *dev)
-{
- skmca_priv *priv = netdev_priv(dev);
-
- writeb(CTRL_RESET_ON, priv->ctrladdr);
- udelay(10);
- writeb(CTRL_RESET_OFF, priv->ctrladdr);
-}
-
-/* wait for LANCE interface to become not busy */
-
-static int WaitLANCE(struct net_device *dev)
-{
- skmca_priv *priv = netdev_priv(dev);
- int t = 0;
-
- while ((readb(priv->ctrladdr) & STAT_IO_BUSY) ==
- STAT_IO_BUSY) {
- udelay(1);
- if (++t > 1000) {
- printk("%s: LANCE access timeout", dev->name);
- return 0;
- }
- }
-
- return 1;
-}
-
-/* set LANCE register - must be atomic */
-
-static void SetLANCE(struct net_device *dev, u16 addr, u16 value)
-{
- skmca_priv *priv = netdev_priv(dev);
- unsigned long flags;
-
- /* disable interrupts */
-
- spin_lock_irqsave(&priv->lock, flags);
-
- /* wait until no transfer is pending */
-
- WaitLANCE(dev);
-
- /* transfer register address to RAP */
-
- writeb(CTRL_RESET_OFF | CTRL_RW_WRITE | CTRL_ADR_RAP, priv->ctrladdr);
- writew(addr, priv->ioregaddr);
- writeb(IOCMD_GO, priv->cmdaddr);
- udelay(1);
- WaitLANCE(dev);
-
- /* transfer data to register */
-
- writeb(CTRL_RESET_OFF | CTRL_RW_WRITE | CTRL_ADR_DATA, priv->ctrladdr);
- writew(value, priv->ioregaddr);
- writeb(IOCMD_GO, priv->cmdaddr);
- udelay(1);
- WaitLANCE(dev);
-
- /* reenable interrupts */
-
- spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-/* get LANCE register */
-
-static u16 GetLANCE(struct net_device *dev, u16 addr)
-{
- skmca_priv *priv = netdev_priv(dev);
- unsigned long flags;
- unsigned int res;
-
- /* disable interrupts */
-
- spin_lock_irqsave(&priv->lock, flags);
-
- /* wait until no transfer is pending */
-
- WaitLANCE(dev);
-
- /* transfer register address to RAP */
-
- writeb(CTRL_RESET_OFF | CTRL_RW_WRITE | CTRL_ADR_RAP, priv->ctrladdr);
- writew(addr, priv->ioregaddr);
- writeb(IOCMD_GO, priv->cmdaddr);
- udelay(1);
- WaitLANCE(dev);
-
- /* transfer data from register */
-
- writeb(CTRL_RESET_OFF | CTRL_RW_READ | CTRL_ADR_DATA, priv->ctrladdr);
- writeb(IOCMD_GO, priv->cmdaddr);
- udelay(1);
- WaitLANCE(dev);
- res = readw(priv->ioregaddr);
-
- /* reenable interrupts */
-
- spin_unlock_irqrestore(&priv->lock, flags);
-
- return res;
-}
-
-/* build up descriptors in shared RAM */
-
-static void InitDscrs(struct net_device *dev)
-{
- skmca_priv *priv = netdev_priv(dev);
- u32 bufaddr;
-
- /* Set up Tx descriptors. The board has only 16K RAM so bits 16..23
- are always 0. */
-
- bufaddr = RAM_DATABASE;
- {
- LANCE_TxDescr descr;
- int z;
-
- for (z = 0; z < TXCOUNT; z++) {
- descr.LowAddr = bufaddr;
- descr.Flags = 0;
- descr.Len = 0xf000;
- descr.Status = 0;
- memcpy_toio(priv->base + RAM_TXBASE +
- (z * sizeof(LANCE_TxDescr)), &descr,
- sizeof(LANCE_TxDescr));
- memset_io(priv->base + bufaddr, 0, RAM_BUFSIZE);
- bufaddr += RAM_BUFSIZE;
- }
- }
-
- /* do the same for the Rx descriptors */
-
- {
- LANCE_RxDescr descr;
- int z;
-
- for (z = 0; z < RXCOUNT; z++) {
- descr.LowAddr = bufaddr;
- descr.Flags = RXDSCR_FLAGS_OWN;
- descr.MaxLen = -RAM_BUFSIZE;
- descr.Len = 0;
- memcpy_toio(priv->base + RAM_RXBASE +
- (z * sizeof(LANCE_RxDescr)), &descr,
- sizeof(LANCE_RxDescr));
- memset_io(priv->base + bufaddr, 0, RAM_BUFSIZE);
- bufaddr += RAM_BUFSIZE;
- }
- }
-}
-
-/* calculate the hash bit position for a given multicast address
- taken more or less directly from the AMD datasheet... */
-
-static void UpdateCRC(unsigned char *CRC, int bit)
-{
- int j;
-
- /* shift CRC one bit */
-
- memmove(CRC + 1, CRC, 32 * sizeof(unsigned char));
- CRC[0] = 0;
-
- /* if bit XOR controlbit = 1, set CRC = CRC XOR polynomial */
-
- if (bit ^ CRC[32])
- for (j = 0; j < 32; j++)
- CRC[j] ^= poly[j];
-}
-
-static unsigned int GetHash(char *address)
-{
- unsigned char CRC[33];
- int i, byte, hashcode;
-
- /* a multicast address has bit 0 in the first byte set */
-
- if ((address[0] & 1) == 0)
- return -1;
-
- /* initialize CRC */
-
- memset(CRC, 1, sizeof(CRC));
-
- /* loop through address bits */
-
- for (byte = 0; byte < 6; byte++)
- for (i = 0; i < 8; i++)
- UpdateCRC(CRC, (address[byte] >> i) & 1);
-
- /* hashcode is the 6 least significant bits of the CRC */
-
- hashcode = 0;
- for (i = 0; i < 6; i++)
- hashcode = (hashcode << 1) + CRC[i];
- return hashcode;
-}
-
-/* feed ready-built initialization block into LANCE */
-
-static void InitLANCE(struct net_device *dev)
-{
- skmca_priv *priv = netdev_priv(dev);
-
- /* build up descriptors. */
-
- InitDscrs(dev);
-
- /* next RX descriptor to be read is the first one. Since the LANCE
- will start from the beginning after initialization, we have to
- reset out pointers too. */
-
- priv->nextrx = 0;
-
- /* no TX descriptors active */
-
- priv->nexttxput = priv->nexttxdone = priv->txbusy = 0;
-
- /* set up the LANCE bus control register - constant for SKnet boards */
-
- SetLANCE(dev, LANCE_CSR3,
- CSR3_BSWAP_OFF | CSR3_ALE_LOW | CSR3_BCON_HOLD);
-
- /* write address of initialization block into LANCE */
-
- SetLANCE(dev, LANCE_CSR1, RAM_INITBASE & 0xffff);
- SetLANCE(dev, LANCE_CSR2, (RAM_INITBASE >> 16) & 0xff);
-
- /* we don't get ready until the LANCE has read the init block */
-
- netif_stop_queue(dev);
-
- /* let LANCE read the initialization block. LANCE is ready
- when we receive the corresponding interrupt. */
-
- SetLANCE(dev, LANCE_CSR0, CSR0_INEA | CSR0_INIT);
-}
-
-/* stop the LANCE so we can reinitialize it */
-
-static void StopLANCE(struct net_device *dev)
-{
- /* can't take frames any more */
-
- netif_stop_queue(dev);
-
- /* disable interrupts, stop it */
-
- SetLANCE(dev, LANCE_CSR0, CSR0_STOP);
-}
-
-/* initialize card and LANCE for proper operation */
-
-static void InitBoard(struct net_device *dev)
-{
- skmca_priv *priv = netdev_priv(dev);
- LANCE_InitBlock block;
-
- /* Lay out the shared RAM - first we create the init block for the LANCE.
- We do not overwrite it later because we need it again when we switch
- promiscous mode on/off. */
-
- block.Mode = 0;
- if (dev->flags & IFF_PROMISC)
- block.Mode |= LANCE_INIT_PROM;
- memcpy(block.PAdr, dev->dev_addr, 6);
- memset(block.LAdrF, 0, sizeof(block.LAdrF));
- block.RdrP = (RAM_RXBASE & 0xffffff) | (LRXCOUNT << 29);
- block.TdrP = (RAM_TXBASE & 0xffffff) | (LTXCOUNT << 29);
-
- memcpy_toio(priv->base + RAM_INITBASE, &block, sizeof(block));
-
- /* initialize LANCE. Implicitly sets up other structures in RAM. */
-
- InitLANCE(dev);
-}
-
-/* deinitialize card and LANCE */
-
-static void DeinitBoard(struct net_device *dev)
-{
- /* stop LANCE */
-
- StopLANCE(dev);
-
- /* reset board */
-
- ResetBoard(dev);
-}
-
-/* probe for device's irq */
-
-static int __init ProbeIRQ(struct net_device *dev)
-{
- unsigned long imaskval, njiffies, irq;
- u16 csr0val;
-
- /* enable all interrupts */
-
- imaskval = probe_irq_on();
-
- /* initialize the board. Wait for interrupt 'Initialization done'. */
-
- ResetBoard(dev);
- InitBoard(dev);
-
- njiffies = jiffies + HZ;
- do {
- csr0val = GetLANCE(dev, LANCE_CSR0);
- }
- while (((csr0val & CSR0_IDON) == 0) && (jiffies != njiffies));
-
- /* turn of interrupts again */
-
- irq = probe_irq_off(imaskval);
-
- /* if we found something, ack the interrupt */
-
- if (irq)
- SetLANCE(dev, LANCE_CSR0, csr0val | CSR0_IDON);
-
- /* back to idle state */
-
- DeinitBoard(dev);
-
- return irq;
-}
-
-/* ------------------------------------------------------------------------
- * interrupt handler(s)
- * ------------------------------------------------------------------------ */
-
-/* LANCE has read initialization block -> start it */
-
-static u16 irqstart_handler(struct net_device *dev, u16 oldcsr0)
-{
- /* now we're ready to transmit */
-
- netif_wake_queue(dev);
-
- /* reset IDON bit, start LANCE */
-
- SetLANCE(dev, LANCE_CSR0, oldcsr0 | CSR0_IDON | CSR0_STRT);
- return GetLANCE(dev, LANCE_CSR0);
-}
-
-/* did we lose blocks due to a FIFO overrun ? */
-
-static u16 irqmiss_handler(struct net_device *dev, u16 oldcsr0)
-{
- skmca_priv *priv = netdev_priv(dev);
-
- /* update statistics */
-
- priv->stat.rx_fifo_errors++;
-
- /* reset MISS bit */
-
- SetLANCE(dev, LANCE_CSR0, oldcsr0 | CSR0_MISS);
- return GetLANCE(dev, LANCE_CSR0);
-}
-
-/* receive interrupt */
-
-static u16 irqrx_handler(struct net_device *dev, u16 oldcsr0)
-{
- skmca_priv *priv = netdev_priv(dev);
- LANCE_RxDescr descr;
- unsigned int descraddr;
-
- /* run through queue until we reach a descriptor we do not own */
-
- descraddr = RAM_RXBASE + (priv->nextrx * sizeof(LANCE_RxDescr));
- while (1) {
- /* read descriptor */
- memcpy_fromio(&descr, priv->base + descraddr,
- sizeof(LANCE_RxDescr));
-
- /* if we reach a descriptor we do not own, we're done */
- if ((descr.Flags & RXDSCR_FLAGS_OWN) != 0)
- break;
-
-#ifdef DEBUG
- PrTime();
- printk("Receive packet on descr %d len %d\n", priv->nextrx,
- descr.Len);
-#endif
-
- /* erroneous packet ? */
- if ((descr.Flags & RXDSCR_FLAGS_ERR) != 0) {
- priv->stat.rx_errors++;
- if ((descr.Flags & RXDSCR_FLAGS_CRC) != 0)
- priv->stat.rx_crc_errors++;
- else if ((descr.Flags & RXDSCR_FLAGS_CRC) != 0)
- priv->stat.rx_frame_errors++;
- else if ((descr.Flags & RXDSCR_FLAGS_OFLO) != 0)
- priv->stat.rx_fifo_errors++;
- }
-
- /* good packet ? */
- else {
- struct sk_buff *skb;
-
- skb = dev_alloc_skb(descr.Len + 2);
- if (skb == NULL)
- priv->stat.rx_dropped++;
- else {
- memcpy_fromio(skb_put(skb, descr.Len),
- priv->base +
- descr.LowAddr, descr.Len);
- skb->dev = dev;
- skb->protocol = eth_type_trans(skb, dev);
- skb->ip_summed = CHECKSUM_NONE;
- priv->stat.rx_packets++;
- priv->stat.rx_bytes += descr.Len;
- netif_rx(skb);
- dev->last_rx = jiffies;
- }
- }
-
- /* give descriptor back to LANCE */
- descr.Len = 0;
- descr.Flags |= RXDSCR_FLAGS_OWN;
-
- /* update descriptor in shared RAM */
- memcpy_toio(priv->base + descraddr, &descr,
- sizeof(LANCE_RxDescr));
-
- /* go to next descriptor */
- priv->nextrx++;
- descraddr += sizeof(LANCE_RxDescr);
- if (priv->nextrx >= RXCOUNT) {
- priv->nextrx = 0;
- descraddr = RAM_RXBASE;
- }
- }
-
- /* reset RINT bit */
-
- SetLANCE(dev, LANCE_CSR0, oldcsr0 | CSR0_RINT);
- return GetLANCE(dev, LANCE_CSR0);
-}
-
-/* transmit interrupt */
-
-static u16 irqtx_handler(struct net_device *dev, u16 oldcsr0)
-{
- skmca_priv *priv = netdev_priv(dev);
- LANCE_TxDescr descr;
- unsigned int descraddr;
-
- /* check descriptors at most until no busy one is left */
-
- descraddr =
- RAM_TXBASE + (priv->nexttxdone * sizeof(LANCE_TxDescr));
- while (priv->txbusy > 0) {
- /* read descriptor */
- memcpy_fromio(&descr, priv->base + descraddr,
- sizeof(LANCE_TxDescr));
-
- /* if the LANCE still owns this one, we've worked out all sent packets */
- if ((descr.Flags & TXDSCR_FLAGS_OWN) != 0)
- break;
-
-#ifdef DEBUG
- PrTime();
- printk("Send packet done on descr %d\n", priv->nexttxdone);
-#endif
-
- /* update statistics */
- if ((descr.Flags & TXDSCR_FLAGS_ERR) == 0) {
- priv->stat.tx_packets++;
- priv->stat.tx_bytes++;
- } else {
- priv->stat.tx_errors++;
- if ((descr.Status & TXDSCR_STATUS_UFLO) != 0) {
- priv->stat.tx_fifo_errors++;
- InitLANCE(dev);
- }
- else
- if ((descr.Status & TXDSCR_STATUS_LCOL) !=
- 0) priv->stat.tx_window_errors++;
- else if ((descr.Status & TXDSCR_STATUS_LCAR) != 0)
- priv->stat.tx_carrier_errors++;
- else if ((descr.Status & TXDSCR_STATUS_RTRY) != 0)
- priv->stat.tx_aborted_errors++;
- }
-
- /* go to next descriptor */
- priv->nexttxdone++;
- descraddr += sizeof(LANCE_TxDescr);
- if (priv->nexttxdone >= TXCOUNT) {
- priv->nexttxdone = 0;
- descraddr = RAM_TXBASE;
- }
- priv->txbusy--;
- }
-
- /* reset TX interrupt bit */
-
- SetLANCE(dev, LANCE_CSR0, oldcsr0 | CSR0_TINT);
- oldcsr0 = GetLANCE(dev, LANCE_CSR0);
-
- /* at least one descriptor is freed. Therefore we can accept
- a new one */
- /* inform upper layers we're in business again */
-
- netif_wake_queue(dev);
-
- return oldcsr0;
-}
-
-/* general interrupt entry */
-
-static irqreturn_t irq_handler(int irq, void *device)
-{
- struct net_device *dev = (struct net_device *) device;
- u16 csr0val;
-
- /* read CSR0 to get interrupt cause */
-
- csr0val = GetLANCE(dev, LANCE_CSR0);
-
- /* in case we're not meant... */
-
- if ((csr0val & CSR0_INTR) == 0)
- return IRQ_NONE;
-
-#if 0
- set_bit(LINK_STATE_RXSEM, &dev->state);
-#endif
-
- /* loop through the interrupt bits until everything is clear */
-
- do {
- if ((csr0val & CSR0_IDON) != 0)
- csr0val = irqstart_handler(dev, csr0val);
- if ((csr0val & CSR0_RINT) != 0)
- csr0val = irqrx_handler(dev, csr0val);
- if ((csr0val & CSR0_MISS) != 0)
- csr0val = irqmiss_handler(dev, csr0val);
- if ((csr0val & CSR0_TINT) != 0)
- csr0val = irqtx_handler(dev, csr0val);
- if ((csr0val & CSR0_MERR) != 0) {
- SetLANCE(dev, LANCE_CSR0, csr0val | CSR0_MERR);
- csr0val = GetLANCE(dev, LANCE_CSR0);
- }
- if ((csr0val & CSR0_BABL) != 0) {
- SetLANCE(dev, LANCE_CSR0, csr0val | CSR0_BABL);
- csr0val = GetLANCE(dev, LANCE_CSR0);
- }
- }
- while ((csr0val & CSR0_INTR) != 0);
-
-#if 0
- clear_bit(LINK_STATE_RXSEM, &dev->state);
-#endif
- return IRQ_HANDLED;
-}
-
-/* ------------------------------------------------------------------------
- * driver methods
- * ------------------------------------------------------------------------ */
-
-/* MCA info */
-
-static int skmca_getinfo(char *buf, int slot, void *d)
-{
- int len = 0, i;
- struct net_device *dev = (struct net_device *) d;
- skmca_priv *priv;
-
- /* can't say anything about an uninitialized device... */
-
- if (dev == NULL)
- return len;
- priv = netdev_priv(dev);
-
- /* print info */
-
- len += sprintf(buf + len, "IRQ: %d\n", priv->realirq);
- len += sprintf(buf + len, "Memory: %#lx-%#lx\n", dev->mem_start,
- dev->mem_end - 1);
- len +=
- sprintf(buf + len, "Transceiver: %s\n",
- MediaNames[priv->medium]);
- len += sprintf(buf + len, "Device: %s\n", dev->name);
- len += sprintf(buf + len, "MAC address:");
- for (i = 0; i < 6; i++)
- len += sprintf(buf + len, " %02x", dev->dev_addr[i]);
- buf[len++] = '\n';
- buf[len] = 0;
-
- return len;
-}
-
-/* open driver. Means also initialization and start of LANCE */
-
-static int skmca_open(struct net_device *dev)
-{
- int result;
- skmca_priv *priv = netdev_priv(dev);
-
- /* register resources - only necessary for IRQ */
- result =
- request_irq(priv->realirq, irq_handler,
- IRQF_SHARED | IRQF_SAMPLE_RANDOM, "sk_mca", dev);
- if (result != 0) {
- printk("%s: failed to register irq %d\n", dev->name,
- dev->irq);
- return result;
- }
- dev->irq = priv->realirq;
-
- /* set up the card and LANCE */
-
- InitBoard(dev);
-
- /* set up flags */
-
- netif_start_queue(dev);
-
- return 0;
-}
-
-/* close driver. Shut down board and free allocated resources */
-
-static int skmca_close(struct net_device *dev)
-{
- /* turn off board */
- DeinitBoard(dev);
-
- /* release resources */
- if (dev->irq != 0)
- free_irq(dev->irq, dev);
- dev->irq = 0;
-
- return 0;
-}
-
-/* transmit a block. */
-
-static int skmca_tx(struct sk_buff *skb, struct net_device *dev)
-{
- skmca_priv *priv = netdev_priv(dev);
- LANCE_TxDescr descr;
- unsigned int address;
- int tmplen, retval = 0;
- unsigned long flags;
-
- /* if we get called with a NULL descriptor, the Ethernet layer thinks
- our card is stuck an we should reset it. We'll do this completely: */
-
- if (skb == NULL) {
- DeinitBoard(dev);
- InitBoard(dev);
- return 0; /* don't try to free the block here ;-) */
- }
-
- /* is there space in the Tx queue ? If no, the upper layer gave us a
- packet in spite of us not being ready and is really in trouble.
- We'll do the dropping for him: */
- if (priv->txbusy >= TXCOUNT) {
- priv->stat.tx_dropped++;
- retval = -EIO;
- goto tx_done;
- }
-
- /* get TX descriptor */
- address = RAM_TXBASE + (priv->nexttxput * sizeof(LANCE_TxDescr));
- memcpy_fromio(&descr, priv->base + address, sizeof(LANCE_TxDescr));
-
- /* enter packet length as 2s complement - assure minimum length */
- tmplen = skb->len;
- if (tmplen < 60)
- tmplen = 60;
- descr.Len = 65536 - tmplen;
-
- /* copy filler into RAM - in case we're filling up...
- we're filling a bit more than necessary, but that doesn't harm
- since the buffer is far larger... */
- if (tmplen > skb->len) {
- char *fill = "NetBSD is a nice OS too! ";
- unsigned int destoffs = 0, l = strlen(fill);
-
- while (destoffs < tmplen) {
- memcpy_toio(priv->base + descr.LowAddr +
- destoffs, fill, l);
- destoffs += l;
- }
- }
-
- /* do the real data copying */
- memcpy_toio(priv->base + descr.LowAddr, skb->data, skb->len);
-
- /* hand descriptor over to LANCE - this is the first and last chunk */
- descr.Flags =
- TXDSCR_FLAGS_OWN | TXDSCR_FLAGS_STP | TXDSCR_FLAGS_ENP;
-
-#ifdef DEBUG
- PrTime();
- printk("Send packet on descr %d len %d\n", priv->nexttxput,
- skb->len);
-#endif
-
- /* one more descriptor busy */
-
- spin_lock_irqsave(&priv->lock, flags);
-
- priv->nexttxput++;
- if (priv->nexttxput >= TXCOUNT)
- priv->nexttxput = 0;
- priv->txbusy++;
-
- /* are we saturated ? */
-
- if (priv->txbusy >= TXCOUNT)
- netif_stop_queue(dev);
-
- /* write descriptor back to RAM */
- memcpy_toio(priv->base + address, &descr, sizeof(LANCE_TxDescr));
-
- /* if no descriptors were active, give the LANCE a hint to read it
- immediately */
-
- if (priv->txbusy == 0)
- SetLANCE(dev, LANCE_CSR0, CSR0_INEA | CSR0_TDMD);
-
- spin_unlock_irqrestore(&priv->lock, flags);
-
- tx_done:
-
- dev_kfree_skb(skb);
-
- return retval;
-}
-
-/* return pointer to Ethernet statistics */
-
-static struct net_device_stats *skmca_stats(struct net_device *dev)
-{
- skmca_priv *priv = netdev_priv(dev);
-
- return &(priv->stat);
-}
-
-/* switch receiver mode. We use the LANCE's multicast filter to prefilter
- multicast addresses. */
-
-static void skmca_set_multicast_list(struct net_device *dev)
-{
- skmca_priv *priv = netdev_priv(dev);
- LANCE_InitBlock block;
-
- /* first stop the LANCE... */
- StopLANCE(dev);
-
- /* ...then modify the initialization block... */
- memcpy_fromio(&block, priv->base + RAM_INITBASE, sizeof(block));
- if (dev->flags & IFF_PROMISC)
- block.Mode |= LANCE_INIT_PROM;
- else
- block.Mode &= ~LANCE_INIT_PROM;
-
- if (dev->flags & IFF_ALLMULTI) { /* get all multicasts */
- memset(block.LAdrF, 0xff, sizeof(block.LAdrF));
- } else { /* get selected/no multicasts */
-
- struct dev_mc_list *mptr;
- int code;
-
- memset(block.LAdrF, 0, sizeof(block.LAdrF));
- for (mptr = dev->mc_list; mptr != NULL; mptr = mptr->next) {
- code = GetHash(mptr->dmi_addr);
- block.LAdrF[(code >> 3) & 7] |= 1 << (code & 7);
- }
- }
-
- memcpy_toio(priv->base + RAM_INITBASE, &block, sizeof(block));
-
- /* ...then reinit LANCE with the correct flags */
- InitLANCE(dev);
-}
-
-/* ------------------------------------------------------------------------
- * hardware check
- * ------------------------------------------------------------------------ */
-
-static int startslot; /* counts through slots when probing multiple devices */
-
-static void cleanup_card(struct net_device *dev)
-{
- skmca_priv *priv = netdev_priv(dev);
- DeinitBoard(dev);
- if (dev->irq != 0)
- free_irq(dev->irq, dev);
- iounmap(priv->base);
- mca_mark_as_unused(priv->slot);
- mca_set_adapter_procfn(priv->slot, NULL, NULL);
-}
-
-struct net_device * __init skmca_probe(int unit)
-{
- struct net_device *dev;
- int force_detect = 0;
- int junior, slot, i;
- int base = 0, irq = 0;
- skmca_priv *priv;
- skmca_medium medium;
- int err;
-
- /* can't work without an MCA bus ;-) */
-
- if (MCA_bus == 0)
- return ERR_PTR(-ENODEV);
-
- dev = alloc_etherdev(sizeof(skmca_priv));
- if (!dev)
- return ERR_PTR(-ENOMEM);
-
- if (unit >= 0) {
- sprintf(dev->name, "eth%d", unit);
- netdev_boot_setup_check(dev);
- }
-
- SET_MODULE_OWNER(dev);
-
- /* start address of 1 --> forced detection */
-
- if (dev->mem_start == 1)
- force_detect = 1;
-
- /* search through slots */
-
- base = dev->mem_start;
- irq = dev->base_addr;
- for (slot = startslot; (slot = dofind(&junior, slot)) != -1; slot++) {
- /* deduce card addresses */
-
- getaddrs(slot, junior, &base, &irq, &medium);
-
- /* slot already in use ? */
-
- if (mca_is_adapter_used(slot))
- continue;
-
- /* were we looking for something different ? */
-
- if (dev->irq && dev->irq != irq)
- continue;
- if (dev->mem_start && dev->mem_start != base)
- continue;
-
- /* found something that matches */
-
- break;
- }
-
- /* nothing found ? */
-
- if (slot == -1) {
- free_netdev(dev);
- return (base || irq) ? ERR_PTR(-ENXIO) : ERR_PTR(-ENODEV);
- }
-
- /* make procfs entries */
-
- if (junior)
- mca_set_adapter_name(slot,
- "SKNET junior MC2 Ethernet Adapter");
- else
- mca_set_adapter_name(slot, "SKNET MC2+ Ethernet Adapter");
- mca_set_adapter_procfn(slot, (MCA_ProcFn) skmca_getinfo, dev);
-
- mca_mark_as_used(slot);
-
- /* announce success */
- printk("%s: SKNet %s adapter found in slot %d\n", dev->name,
- junior ? "Junior MC2" : "MC2+", slot + 1);
-
- priv = netdev_priv(dev);
- priv->base = ioremap(base, 0x4000);
- if (!priv->base) {
- mca_set_adapter_procfn(slot, NULL, NULL);
- mca_mark_as_unused(slot);
- free_netdev(dev);
- return ERR_PTR(-ENOMEM);
- }
-
- priv->slot = slot;
- priv->macbase = priv->base + 0x3fc0;
- priv->ioregaddr = priv->base + 0x3ff0;
- priv->ctrladdr = priv->base + 0x3ff2;
- priv->cmdaddr = priv->base + 0x3ff3;
- priv->medium = medium;
- memset(&priv->stat, 0, sizeof(struct net_device_stats));
- spin_lock_init(&priv->lock);
-
- /* set base + irq for this device (irq not allocated so far) */
- dev->irq = 0;
- dev->mem_start = base;
- dev->mem_end = base + 0x4000;
-
- /* autoprobe ? */
- if (irq < 0) {
- int nirq;
-
- printk
- ("%s: ambigous POS bit combination, must probe for IRQ...\n",
- dev->name);
- nirq = ProbeIRQ(dev);
- if (nirq <= 0)
- printk("%s: IRQ probe failed, assuming IRQ %d",
- dev->name, priv->realirq = -irq);
- else
- priv->realirq = nirq;
- } else
- priv->realirq = irq;
-
- /* set methods */
- dev->open = skmca_open;
- dev->stop = skmca_close;
- dev->hard_start_xmit = skmca_tx;
- dev->do_ioctl = NULL;
- dev->get_stats = skmca_stats;
- dev->set_multicast_list = skmca_set_multicast_list;
- dev->flags |= IFF_MULTICAST;
-
- /* copy out MAC address */
- for (i = 0; i < 6; i++)
- dev->dev_addr[i] = readb(priv->macbase + (i << 1));
-
- /* print config */
- printk("%s: IRQ %d, memory %#lx-%#lx, "
- "MAC address %02x:%02x:%02x:%02x:%02x:%02x.\n",
- dev->name, priv->realirq, dev->mem_start, dev->mem_end - 1,
- 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("%s: %s medium\n", dev->name, MediaNames[priv->medium]);
-
- /* reset board */
-
- ResetBoard(dev);
-
- startslot = slot + 1;
-
- err = register_netdev(dev);
- if (err) {
- cleanup_card(dev);
- free_netdev(dev);
- dev = ERR_PTR(err);
- }
- return dev;
-}
-
-/* ------------------------------------------------------------------------
- * modularization support
- * ------------------------------------------------------------------------ */
-
-#ifdef MODULE
-MODULE_LICENSE("GPL");
-
-#define DEVMAX 5
-
-static struct net_device *moddevs[DEVMAX];
-
-int init_module(void)
-{
- int z;
-
- startslot = 0;
- for (z = 0; z < DEVMAX; z++) {
- struct net_device *dev = skmca_probe(-1);
- if (IS_ERR(dev))
- break;
- moddevs[z] = dev;
- }
- if (!z)
- return -EIO;
- return 0;
-}
-
-void cleanup_module(void)
-{
- int z;
-
- for (z = 0; z < DEVMAX; z++) {
- struct net_device *dev = moddevs[z];
- if (dev) {
- unregister_netdev(dev);
- cleanup_card(dev);
- free_netdev(dev);
- }
- }
-}
-#endif /* MODULE */
diff --git a/drivers/net/sk_mca.h b/drivers/net/sk_mca.h
deleted file mode 100644
index 0dae056fed9..00000000000
--- a/drivers/net/sk_mca.h
+++ /dev/null
@@ -1,170 +0,0 @@
-#ifndef _SK_MCA_INCLUDE_
-#define _SK_MCA_INCLUDE_
-
-#ifdef _SK_MCA_DRIVER_
-
-/* Adapter ID's */
-#define SKNET_MCA_ID 0x6afd
-#define SKNET_JUNIOR_MCA_ID 0x6be9
-
-/* media enumeration - defined in a way that it fits onto the MC2+'s
- POS registers... */
-
-typedef enum { Media_10Base2, Media_10BaseT,
- Media_10Base5, Media_Unknown, Media_Count
-} skmca_medium;
-
-/* private structure */
-typedef struct {
- unsigned int slot; /* MCA-Slot-# */
- void __iomem *base;
- void __iomem *macbase; /* base address of MAC address PROM */
- void __iomem *ioregaddr;/* address of I/O-register (Lo) */
- void __iomem *ctrladdr; /* address of control/stat register */
- void __iomem *cmdaddr; /* address of I/O-command register */
- int nextrx; /* index of next RX descriptor to
- be read */
- int nexttxput; /* index of next free TX descriptor */
- int nexttxdone; /* index of next TX descriptor to
- be finished */
- int txbusy; /* # of busy TX descriptors */
- struct net_device_stats stat; /* packet statistics */
- int realirq; /* memorizes actual IRQ, even when
- currently not allocated */
- skmca_medium medium; /* physical cannector */
- spinlock_t lock;
-} skmca_priv;
-
-/* card registers: control/status register bits */
-
-#define CTRL_ADR_DATA 0 /* Bit 0 = 0 ->access data register */
-#define CTRL_ADR_RAP 1 /* Bit 0 = 1 ->access RAP register */
-#define CTRL_RW_WRITE 0 /* Bit 1 = 0 ->write register */
-#define CTRL_RW_READ 2 /* Bit 1 = 1 ->read register */
-#define CTRL_RESET_ON 0 /* Bit 3 = 0 ->reset board */
-#define CTRL_RESET_OFF 8 /* Bit 3 = 1 ->no reset of board */
-
-#define STAT_ADR_DATA 0 /* Bit 0 of ctrl register read back */
-#define STAT_ADR_RAP 1
-#define STAT_RW_WRITE 0 /* Bit 1 of ctrl register read back */
-#define STAT_RW_READ 2
-#define STAT_RESET_ON 0 /* Bit 3 of ctrl register read back */
-#define STAT_RESET_OFF 8
-#define STAT_IRQ_ACT 0 /* interrupt pending */
-#define STAT_IRQ_NOACT 16 /* no interrupt pending */
-#define STAT_IO_NOBUSY 0 /* no transfer busy */
-#define STAT_IO_BUSY 32 /* transfer busy */
-
-/* I/O command register bits */
-
-#define IOCMD_GO 128 /* Bit 7 = 1 -> start register xfer */
-
-/* LANCE registers */
-
-#define LANCE_CSR0 0 /* Status/Control */
-
-#define CSR0_ERR 0x8000 /* general error flag */
-#define CSR0_BABL 0x4000 /* transmitter timeout */
-#define CSR0_CERR 0x2000 /* collision error */
-#define CSR0_MISS 0x1000 /* lost Rx block */
-#define CSR0_MERR 0x0800 /* memory access error */
-#define CSR0_RINT 0x0400 /* receiver interrupt */
-#define CSR0_TINT 0x0200 /* transmitter interrupt */
-#define CSR0_IDON 0x0100 /* initialization done */
-#define CSR0_INTR 0x0080 /* general interrupt flag */
-#define CSR0_INEA 0x0040 /* interrupt enable */
-#define CSR0_RXON 0x0020 /* receiver enabled */
-#define CSR0_TXON 0x0010 /* transmitter enabled */
-#define CSR0_TDMD 0x0008 /* force transmission now */
-#define CSR0_STOP 0x0004 /* stop LANCE */
-#define CSR0_STRT 0x0002 /* start LANCE */
-#define CSR0_INIT 0x0001 /* read initialization block */
-
-#define LANCE_CSR1 1 /* addr bit 0..15 of initialization */
-#define LANCE_CSR2 2 /* 16..23 block */
-
-#define LANCE_CSR3 3 /* Bus control */
-#define CSR3_BCON_HOLD 0 /* Bit 0 = 0 -> BM1,BM0,HOLD */
-#define CSR3_BCON_BUSRQ 1 /* Bit 0 = 1 -> BUSAK0,BYTE,BUSRQ */
-#define CSR3_ALE_HIGH 0 /* Bit 1 = 0 -> ALE asserted high */
-#define CSR3_ALE_LOW 2 /* Bit 1 = 1 -> ALE asserted low */
-#define CSR3_BSWAP_OFF 0 /* Bit 2 = 0 -> no byte swap */
-#define CSR3_BSWAP_ON 4 /* Bit 2 = 1 -> byte swap */
-
-/* LANCE structures */
-
-typedef struct { /* LANCE initialization block */
- u16 Mode; /* mode flags */
- u8 PAdr[6]; /* MAC address */
- u8 LAdrF[8]; /* Multicast filter */
- u32 RdrP; /* Receive descriptor */
- u32 TdrP; /* Transmit descriptor */
-} LANCE_InitBlock;
-
-/* Mode flags init block */
-
-#define LANCE_INIT_PROM 0x8000 /* enable promiscous mode */
-#define LANCE_INIT_INTL 0x0040 /* internal loopback */
-#define LANCE_INIT_DRTY 0x0020 /* disable retry */
-#define LANCE_INIT_COLL 0x0010 /* force collision */
-#define LANCE_INIT_DTCR 0x0008 /* disable transmit CRC */
-#define LANCE_INIT_LOOP 0x0004 /* loopback */
-#define LANCE_INIT_DTX 0x0002 /* disable transmitter */
-#define LANCE_INIT_DRX 0x0001 /* disable receiver */
-
-typedef struct { /* LANCE Tx descriptor */
- u16 LowAddr; /* bit 0..15 of address */
- u16 Flags; /* bit 16..23 of address + Flags */
- u16 Len; /* 2s complement of packet length */
- u16 Status; /* Result of transmission */
-} LANCE_TxDescr;
-
-#define TXDSCR_FLAGS_OWN 0x8000 /* LANCE owns descriptor */
-#define TXDSCR_FLAGS_ERR 0x4000 /* summary error flag */
-#define TXDSCR_FLAGS_MORE 0x1000 /* more than one retry needed? */
-#define TXDSCR_FLAGS_ONE 0x0800 /* one retry? */
-#define TXDSCR_FLAGS_DEF 0x0400 /* transmission deferred? */
-#define TXDSCR_FLAGS_STP 0x0200 /* first packet in chain? */
-#define TXDSCR_FLAGS_ENP 0x0100 /* last packet in chain? */
-
-#define TXDSCR_STATUS_BUFF 0x8000 /* buffer error? */
-#define TXDSCR_STATUS_UFLO 0x4000 /* silo underflow during transmit? */
-#define TXDSCR_STATUS_LCOL 0x1000 /* late collision? */
-#define TXDSCR_STATUS_LCAR 0x0800 /* loss of carrier? */
-#define TXDSCR_STATUS_RTRY 0x0400 /* retry error? */
-
-typedef struct { /* LANCE Rx descriptor */
- u16 LowAddr; /* bit 0..15 of address */
- u16 Flags; /* bit 16..23 of address + Flags */
- u16 MaxLen; /* 2s complement of buffer length */
- u16 Len; /* packet length */
-} LANCE_RxDescr;
-
-#define RXDSCR_FLAGS_OWN 0x8000 /* LANCE owns descriptor */
-#define RXDSCR_FLAGS_ERR 0x4000 /* summary error flag */
-#define RXDSCR_FLAGS_FRAM 0x2000 /* framing error flag */
-#define RXDSCR_FLAGS_OFLO 0x1000 /* FIFO overflow? */
-#define RXDSCR_FLAGS_CRC 0x0800 /* CRC error? */
-#define RXDSCR_FLAGS_BUFF 0x0400 /* buffer error? */
-#define RXDSCR_FLAGS_STP 0x0200 /* first packet in chain? */
-#define RXDCSR_FLAGS_ENP 0x0100 /* last packet in chain? */
-
-/* RAM layout */
-
-#define TXCOUNT 4 /* length of TX descriptor queue */
-#define LTXCOUNT 2 /* log2 of it */
-#define RXCOUNT 4 /* length of RX descriptor queue */
-#define LRXCOUNT 2 /* log2 of it */
-
-#define RAM_INITBASE 0 /* LANCE init block */
-#define RAM_TXBASE 24 /* Start of TX descriptor queue */
-#define RAM_RXBASE \
-(RAM_TXBASE + (TXCOUNT * 8)) /* Start of RX descriptor queue */
-#define RAM_DATABASE \
-(RAM_RXBASE + (RXCOUNT * 8)) /* Start of data area for frames */
-#define RAM_BUFSIZE 1580 /* max. frame size - should never be
- reached */
-
-#endif /* _SK_MCA_DRIVER_ */
-
-#endif /* _SK_MCA_INCLUDE_ */
diff --git a/drivers/net/skfp/can.c b/drivers/net/skfp/can.c
deleted file mode 100644
index 8a49abce796..00000000000
--- a/drivers/net/skfp/can.c
+++ /dev/null
@@ -1,83 +0,0 @@
-/******************************************************************************
- *
- * (C)Copyright 1998,1999 SysKonnect,
- * a business unit of Schneider & Koch & Co. Datensysteme GmbH.
- *
- * See the file "skfddi.c" for further information.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under 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 information in this file is provided "AS IS" without warranty.
- *
- ******************************************************************************/
-
-#ifndef lint
-static const char xID_sccs[] = "@(#)can.c 1.5 97/04/07 (C) SK " ;
-#endif
-
-/*
- * canonical bit order
- */
-const u_char canonical[256] = {
- 0x00,0x80,0x40,0xc0,0x20,0xa0,0x60,0xe0,
- 0x10,0x90,0x50,0xd0,0x30,0xb0,0x70,0xf0,
- 0x08,0x88,0x48,0xc8,0x28,0xa8,0x68,0xe8,
- 0x18,0x98,0x58,0xd8,0x38,0xb8,0x78,0xf8,
- 0x04,0x84,0x44,0xc4,0x24,0xa4,0x64,0xe4,
- 0x14,0x94,0x54,0xd4,0x34,0xb4,0x74,0xf4,
- 0x0c,0x8c,0x4c,0xcc,0x2c,0xac,0x6c,0xec,
- 0x1c,0x9c,0x5c,0xdc,0x3c,0xbc,0x7c,0xfc,
- 0x02,0x82,0x42,0xc2,0x22,0xa2,0x62,0xe2,
- 0x12,0x92,0x52,0xd2,0x32,0xb2,0x72,0xf2,
- 0x0a,0x8a,0x4a,0xca,0x2a,0xaa,0x6a,0xea,
- 0x1a,0x9a,0x5a,0xda,0x3a,0xba,0x7a,0xfa,
- 0x06,0x86,0x46,0xc6,0x26,0xa6,0x66,0xe6,
- 0x16,0x96,0x56,0xd6,0x36,0xb6,0x76,0xf6,
- 0x0e,0x8e,0x4e,0xce,0x2e,0xae,0x6e,0xee,
- 0x1e,0x9e,0x5e,0xde,0x3e,0xbe,0x7e,0xfe,
- 0x01,0x81,0x41,0xc1,0x21,0xa1,0x61,0xe1,
- 0x11,0x91,0x51,0xd1,0x31,0xb1,0x71,0xf1,
- 0x09,0x89,0x49,0xc9,0x29,0xa9,0x69,0xe9,
- 0x19,0x99,0x59,0xd9,0x39,0xb9,0x79,0xf9,
- 0x05,0x85,0x45,0xc5,0x25,0xa5,0x65,0xe5,
- 0x15,0x95,0x55,0xd5,0x35,0xb5,0x75,0xf5,
- 0x0d,0x8d,0x4d,0xcd,0x2d,0xad,0x6d,0xed,
- 0x1d,0x9d,0x5d,0xdd,0x3d,0xbd,0x7d,0xfd,
- 0x03,0x83,0x43,0xc3,0x23,0xa3,0x63,0xe3,
- 0x13,0x93,0x53,0xd3,0x33,0xb3,0x73,0xf3,
- 0x0b,0x8b,0x4b,0xcb,0x2b,0xab,0x6b,0xeb,
- 0x1b,0x9b,0x5b,0xdb,0x3b,0xbb,0x7b,0xfb,
- 0x07,0x87,0x47,0xc7,0x27,0xa7,0x67,0xe7,
- 0x17,0x97,0x57,0xd7,0x37,0xb7,0x77,0xf7,
- 0x0f,0x8f,0x4f,0xcf,0x2f,0xaf,0x6f,0xef,
- 0x1f,0x9f,0x5f,0xdf,0x3f,0xbf,0x7f,0xff
-} ;
-
-#ifdef MAKE_TABLE
-int byte_reverse(x)
-int x ;
-{
- int y = 0 ;
-
- if (x & 0x01)
- y |= 0x80 ;
- if (x & 0x02)
- y |= 0x40 ;
- if (x & 0x04)
- y |= 0x20 ;
- if (x & 0x08)
- y |= 0x10 ;
- if (x & 0x10)
- y |= 0x08 ;
- if (x & 0x20)
- y |= 0x04 ;
- if (x & 0x40)
- y |= 0x02 ;
- if (x & 0x80)
- y |= 0x01 ;
- return(y) ;
-}
-#endif
diff --git a/drivers/net/skfp/drvfbi.c b/drivers/net/skfp/drvfbi.c
index 5b475833f64..4fe624b0dd2 100644
--- a/drivers/net/skfp/drvfbi.c
+++ b/drivers/net/skfp/drvfbi.c
@@ -23,6 +23,7 @@
#include "h/smc.h"
#include "h/supern_2.h"
#include "h/skfbiinc.h"
+#include <linux/bitrev.h>
#ifndef lint
static const char ID_sccs[] = "@(#)drvfbi.c 1.63 99/02/11 (C) SK " ;
@@ -445,16 +446,14 @@ void read_address(struct s_smc *smc, u_char *mac_addr)
char PmdType ;
int i ;
- extern const u_char canonical[256] ;
-
#if (defined(ISA) || defined(MCA))
for (i = 0; i < 4 ;i++) { /* read mac address from board */
smc->hw.fddi_phys_addr.a[i] =
- canonical[(inpw(PR_A(i+SA_MAC))&0xff)] ;
+ bitrev8(inpw(PR_A(i+SA_MAC)));
}
for (i = 4; i < 6; i++) {
smc->hw.fddi_phys_addr.a[i] =
- canonical[(inpw(PR_A(i+SA_MAC+PRA_OFF))&0xff)] ;
+ bitrev8(inpw(PR_A(i+SA_MAC+PRA_OFF)));
}
#endif
#ifdef EISA
@@ -464,17 +463,17 @@ void read_address(struct s_smc *smc, u_char *mac_addr)
*/
for (i = 0; i < 4 ;i++) { /* read mac address from board */
smc->hw.fddi_phys_addr.a[i] =
- canonical[inp(PR_A(i+SA_MAC))] ;
+ bitrev8(inp(PR_A(i+SA_MAC)));
}
for (i = 4; i < 6; i++) {
smc->hw.fddi_phys_addr.a[i] =
- canonical[inp(PR_A(i+SA_MAC+PRA_OFF))] ;
+ bitrev8(inp(PR_A(i+SA_MAC+PRA_OFF)));
}
#endif
#ifdef PCI
for (i = 0; i < 6; i++) { /* read mac address from board */
smc->hw.fddi_phys_addr.a[i] =
- canonical[inp(ADDR(B2_MAC_0+i))] ;
+ bitrev8(inp(ADDR(B2_MAC_0+i)));
}
#endif
#ifndef PCI
@@ -493,7 +492,7 @@ void read_address(struct s_smc *smc, u_char *mac_addr)
if (mac_addr) {
for (i = 0; i < 6 ;i++) {
smc->hw.fddi_canon_addr.a[i] = mac_addr[i] ;
- smc->hw.fddi_home_addr.a[i] = canonical[mac_addr[i]] ;
+ smc->hw.fddi_home_addr.a[i] = bitrev8(mac_addr[i]);
}
return ;
}
@@ -501,7 +500,7 @@ void read_address(struct s_smc *smc, u_char *mac_addr)
for (i = 0; i < 6 ;i++) {
smc->hw.fddi_canon_addr.a[i] =
- canonical[smc->hw.fddi_phys_addr.a[i]] ;
+ bitrev8(smc->hw.fddi_phys_addr.a[i]);
}
}
@@ -1269,11 +1268,8 @@ void driver_get_bia(struct s_smc *smc, struct fddi_addr *bia_addr)
{
int i ;
- extern const u_char canonical[256] ;
-
- for (i = 0 ; i < 6 ; i++) {
- bia_addr->a[i] = canonical[smc->hw.fddi_phys_addr.a[i]] ;
- }
+ for (i = 0 ; i < 6 ; i++)
+ bia_addr->a[i] = bitrev8(smc->hw.fddi_phys_addr.a[i]);
}
void smt_start_watchdog(struct s_smc *smc)
diff --git a/drivers/net/skfp/fplustm.c b/drivers/net/skfp/fplustm.c
index 0784f558ca9..a45205da803 100644
--- a/drivers/net/skfp/fplustm.c
+++ b/drivers/net/skfp/fplustm.c
@@ -22,7 +22,7 @@
#include "h/fddi.h"
#include "h/smc.h"
#include "h/supern_2.h"
-#include "can.c"
+#include <linux/bitrev.h>
#ifndef lint
static const char ID_sccs[] = "@(#)fplustm.c 1.32 99/02/23 (C) SK " ;
@@ -1073,7 +1073,7 @@ static struct s_fpmc* mac_get_mc_table(struct s_smc *smc,
if (can) {
p = own->a ;
for (i = 0 ; i < 6 ; i++, p++)
- *p = canonical[*p] ;
+ *p = bitrev8(*p);
}
slot = NULL;
for (i = 0, tb = smc->hw.fp.mc.table ; i < FPMAX_MULTICAST ; i++, tb++){
diff --git a/drivers/net/skfp/smt.c b/drivers/net/skfp/smt.c
index 99a776a51fb..fe847800acd 100644
--- a/drivers/net/skfp/smt.c
+++ b/drivers/net/skfp/smt.c
@@ -18,6 +18,7 @@
#include "h/fddi.h"
#include "h/smc.h"
#include "h/smt_p.h"
+#include <linux/bitrev.h>
#define KERNEL
#include "h/smtstate.h"
@@ -26,8 +27,6 @@
static const char ID_sccs[] = "@(#)smt.c 2.43 98/11/23 (C) SK " ;
#endif
-extern const u_char canonical[256] ;
-
/*
* FC in SMbuf
*/
@@ -180,7 +179,7 @@ void smt_agent_init(struct s_smc *smc)
driver_get_bia(smc,&smc->mib.fddiSMTStationId.sid_node) ;
for (i = 0 ; i < 6 ; i ++) {
smc->mib.fddiSMTStationId.sid_node.a[i] =
- canonical[smc->mib.fddiSMTStationId.sid_node.a[i]] ;
+ bitrev8(smc->mib.fddiSMTStationId.sid_node.a[i]);
}
smc->mib.fddiSMTManufacturerData[0] =
smc->mib.fddiSMTStationId.sid_node.a[0] ;
@@ -2049,9 +2048,8 @@ static void hwm_conv_can(struct s_smc *smc, char *data, int len)
SK_UNUSED(smc) ;
- for (i = len; i ; i--, data++) {
- *data = canonical[*(u_char *)data] ;
- }
+ for (i = len; i ; i--, data++)
+ *data = bitrev8(*data);
}
#endif
diff --git a/drivers/net/skge.c b/drivers/net/skge.c
index 45283f3f95e..c3d2e0a2c4e 100644
--- a/drivers/net/skge.c
+++ b/drivers/net/skge.c
@@ -42,7 +42,7 @@
#include "skge.h"
#define DRV_NAME "skge"
-#define DRV_VERSION "1.9"
+#define DRV_VERSION "1.10"
#define PFX DRV_NAME " "
#define DEFAULT_TX_RING_SIZE 128
@@ -132,18 +132,93 @@ static void skge_get_regs(struct net_device *dev, struct ethtool_regs *regs,
}
/* Wake on Lan only supported on Yukon chips with rev 1 or above */
-static int wol_supported(const struct skge_hw *hw)
+static u32 wol_supported(const struct skge_hw *hw)
{
- return !((hw->chip_id == CHIP_ID_GENESIS ||
- (hw->chip_id == CHIP_ID_YUKON && hw->chip_rev == 0)));
+ if (hw->chip_id == CHIP_ID_YUKON && hw->chip_rev != 0)
+ return WAKE_MAGIC | WAKE_PHY;
+ else
+ return 0;
+}
+
+static u32 pci_wake_enabled(struct pci_dev *dev)
+{
+ int pm = pci_find_capability(dev, PCI_CAP_ID_PM);
+ u16 value;
+
+ /* If device doesn't support PM Capabilities, but request is to disable
+ * wake events, it's a nop; otherwise fail */
+ if (!pm)
+ return 0;
+
+ pci_read_config_word(dev, pm + PCI_PM_PMC, &value);
+
+ value &= PCI_PM_CAP_PME_MASK;
+ value >>= ffs(PCI_PM_CAP_PME_MASK) - 1; /* First bit of mask */
+
+ return value != 0;
+}
+
+static void skge_wol_init(struct skge_port *skge)
+{
+ struct skge_hw *hw = skge->hw;
+ int port = skge->port;
+ enum pause_control save_mode;
+ u32 ctrl;
+
+ /* Bring hardware out of reset */
+ skge_write16(hw, B0_CTST, CS_RST_CLR);
+ skge_write16(hw, SK_REG(port, GMAC_LINK_CTRL), GMLC_RST_CLR);
+
+ skge_write8(hw, SK_REG(port, GPHY_CTRL), GPC_RST_CLR);
+ skge_write8(hw, SK_REG(port, GMAC_CTRL), GMC_RST_CLR);
+
+ /* Force to 10/100 skge_reset will re-enable on resume */
+ save_mode = skge->flow_control;
+ skge->flow_control = FLOW_MODE_SYMMETRIC;
+
+ ctrl = skge->advertising;
+ skge->advertising &= ~(ADVERTISED_1000baseT_Half|ADVERTISED_1000baseT_Full);
+
+ skge_phy_reset(skge);
+
+ skge->flow_control = save_mode;
+ skge->advertising = ctrl;
+
+ /* Set GMAC to no flow control and auto update for speed/duplex */
+ gma_write16(hw, port, GM_GP_CTRL,
+ GM_GPCR_FC_TX_DIS|GM_GPCR_TX_ENA|GM_GPCR_RX_ENA|
+ GM_GPCR_DUP_FULL|GM_GPCR_FC_RX_DIS|GM_GPCR_AU_FCT_DIS);
+
+ /* Set WOL address */
+ memcpy_toio(hw->regs + WOL_REGS(port, WOL_MAC_ADDR),
+ skge->netdev->dev_addr, ETH_ALEN);
+
+ /* Turn on appropriate WOL control bits */
+ skge_write16(hw, WOL_REGS(port, WOL_CTRL_STAT), WOL_CTL_CLEAR_RESULT);
+ ctrl = 0;
+ if (skge->wol & WAKE_PHY)
+ ctrl |= WOL_CTL_ENA_PME_ON_LINK_CHG|WOL_CTL_ENA_LINK_CHG_UNIT;
+ else
+ ctrl |= WOL_CTL_DIS_PME_ON_LINK_CHG|WOL_CTL_DIS_LINK_CHG_UNIT;
+
+ if (skge->wol & WAKE_MAGIC)
+ ctrl |= WOL_CTL_ENA_PME_ON_MAGIC_PKT|WOL_CTL_ENA_MAGIC_PKT_UNIT;
+ else
+ ctrl |= WOL_CTL_DIS_PME_ON_MAGIC_PKT|WOL_CTL_DIS_MAGIC_PKT_UNIT;;
+
+ ctrl |= WOL_CTL_DIS_PME_ON_PATTERN|WOL_CTL_DIS_PATTERN_UNIT;
+ skge_write16(hw, WOL_REGS(port, WOL_CTRL_STAT), ctrl);
+
+ /* block receiver */
+ skge_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET);
}
static void skge_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
{
struct skge_port *skge = netdev_priv(dev);
- wol->supported = wol_supported(skge->hw) ? WAKE_MAGIC : 0;
- wol->wolopts = skge->wol ? WAKE_MAGIC : 0;
+ wol->supported = wol_supported(skge->hw);
+ wol->wolopts = skge->wol;
}
static int skge_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
@@ -151,23 +226,12 @@ static int skge_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
struct skge_port *skge = netdev_priv(dev);
struct skge_hw *hw = skge->hw;
- if (wol->wolopts != WAKE_MAGIC && wol->wolopts != 0)
- return -EOPNOTSUPP;
-
- if (wol->wolopts == WAKE_MAGIC && !wol_supported(hw))
+ if (wol->wolopts & wol_supported(hw))
return -EOPNOTSUPP;
- skge->wol = wol->wolopts == WAKE_MAGIC;
-
- if (skge->wol) {
- memcpy_toio(hw->regs + WOL_MAC_ADDR, dev->dev_addr, ETH_ALEN);
-
- skge_write16(hw, WOL_CTRL_STAT,
- WOL_CTL_ENA_PME_ON_MAGIC_PKT |
- WOL_CTL_ENA_MAGIC_PKT_UNIT);
- } else
- skge_write16(hw, WOL_CTRL_STAT, WOL_CTL_DEFAULT);
-
+ skge->wol = wol->wolopts;
+ if (!netif_running(dev))
+ skge_wol_init(skge);
return 0;
}
@@ -1355,7 +1419,8 @@ static void xm_link_timer(struct work_struct *work)
mutex_unlock(&hw->phy_mutex);
nochange:
- schedule_delayed_work(&skge->link_thread, LINK_HZ);
+ if (netif_running(dev))
+ schedule_delayed_work(&skge->link_thread, LINK_HZ);
}
static void genesis_mac_init(struct skge_hw *hw, int port)
@@ -2373,6 +2438,9 @@ static int skge_up(struct net_device *dev)
size_t rx_size, tx_size;
int err;
+ 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);
@@ -2392,7 +2460,7 @@ static int skge_up(struct net_device *dev)
BUG_ON(skge->dma & 7);
if ((u64)skge->dma >> 32 != ((u64) skge->dma + skge->mem_size) >> 32) {
- printk(KERN_ERR PFX "pci_alloc_consistent region crosses 4G boundary\n");
+ dev_err(&hw->pdev->dev, "pci_alloc_consistent region crosses 4G boundary\n");
err = -EINVAL;
goto free_pci_mem;
}
@@ -2463,7 +2531,7 @@ static int skge_down(struct net_device *dev)
netif_stop_queue(dev);
if (hw->chip_id == CHIP_ID_GENESIS && hw->phy_type == SK_PHY_XMAC)
- cancel_rearming_delayed_work(&skge->link_thread);
+ cancel_delayed_work(&skge->link_thread);
skge_write8(skge->hw, SK_REG(skge->port, LNK_LED_REG), LED_OFF);
if (hw->chip_id == CHIP_ID_GENESIS)
@@ -3001,6 +3069,7 @@ static void skge_mac_intr(struct skge_hw *hw, int port)
/* Handle device specific framing and timeout interrupts */
static void skge_error_irq(struct skge_hw *hw)
{
+ struct pci_dev *pdev = hw->pdev;
u32 hwstatus = skge_read32(hw, B0_HWE_ISRC);
if (hw->chip_id == CHIP_ID_GENESIS) {
@@ -3016,12 +3085,12 @@ static void skge_error_irq(struct skge_hw *hw)
}
if (hwstatus & IS_RAM_RD_PAR) {
- printk(KERN_ERR PFX "Ram read data parity error\n");
+ dev_err(&pdev->dev, "Ram read data parity error\n");
skge_write16(hw, B3_RI_CTRL, RI_CLR_RD_PERR);
}
if (hwstatus & IS_RAM_WR_PAR) {
- printk(KERN_ERR PFX "Ram write data parity error\n");
+ dev_err(&pdev->dev, "Ram write data parity error\n");
skge_write16(hw, B3_RI_CTRL, RI_CLR_WR_PERR);
}
@@ -3032,38 +3101,38 @@ static void skge_error_irq(struct skge_hw *hw)
skge_mac_parity(hw, 1);
if (hwstatus & IS_R1_PAR_ERR) {
- printk(KERN_ERR PFX "%s: receive queue parity error\n",
- hw->dev[0]->name);
+ dev_err(&pdev->dev, "%s: receive queue parity error\n",
+ hw->dev[0]->name);
skge_write32(hw, B0_R1_CSR, CSR_IRQ_CL_P);
}
if (hwstatus & IS_R2_PAR_ERR) {
- printk(KERN_ERR PFX "%s: receive queue parity error\n",
- hw->dev[1]->name);
+ dev_err(&pdev->dev, "%s: receive queue parity error\n",
+ hw->dev[1]->name);
skge_write32(hw, B0_R2_CSR, CSR_IRQ_CL_P);
}
if (hwstatus & (IS_IRQ_MST_ERR|IS_IRQ_STAT)) {
u16 pci_status, pci_cmd;
- pci_read_config_word(hw->pdev, PCI_COMMAND, &pci_cmd);
- pci_read_config_word(hw->pdev, PCI_STATUS, &pci_status);
+ pci_read_config_word(pdev, PCI_COMMAND, &pci_cmd);
+ pci_read_config_word(pdev, PCI_STATUS, &pci_status);
- printk(KERN_ERR PFX "%s: PCI error cmd=%#x status=%#x\n",
- pci_name(hw->pdev), pci_cmd, pci_status);
+ dev_err(&pdev->dev, "PCI error cmd=%#x status=%#x\n",
+ pci_cmd, pci_status);
/* Write the error bits back to clear them. */
pci_status &= PCI_STATUS_ERROR_BITS;
skge_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
- pci_write_config_word(hw->pdev, PCI_COMMAND,
+ pci_write_config_word(pdev, PCI_COMMAND,
pci_cmd | PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
- pci_write_config_word(hw->pdev, PCI_STATUS, pci_status);
+ pci_write_config_word(pdev, PCI_STATUS, pci_status);
skge_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
/* if error still set then just ignore it */
hwstatus = skge_read32(hw, B0_HWE_ISRC);
if (hwstatus & IS_IRQ_STAT) {
- printk(KERN_INFO PFX "unable to clear error (so ignoring them)\n");
+ dev_warn(&hw->pdev->dev, "unable to clear error (so ignoring them)\n");
hw->intr_mask &= ~IS_HW_ERR;
}
}
@@ -3277,8 +3346,8 @@ static int skge_reset(struct skge_hw *hw)
hw->phy_addr = PHY_ADDR_BCOM;
break;
default:
- printk(KERN_ERR PFX "%s: unsupported phy type 0x%x\n",
- pci_name(hw->pdev), hw->phy_type);
+ dev_err(&hw->pdev->dev, "unsupported phy type 0x%x\n",
+ hw->phy_type);
return -EOPNOTSUPP;
}
break;
@@ -3293,8 +3362,8 @@ static int skge_reset(struct skge_hw *hw)
break;
default:
- printk(KERN_ERR PFX "%s: unsupported chip type 0x%x\n",
- pci_name(hw->pdev), hw->chip_id);
+ dev_err(&hw->pdev->dev, "unsupported chip type 0x%x\n",
+ hw->chip_id);
return -EOPNOTSUPP;
}
@@ -3334,7 +3403,7 @@ static int skge_reset(struct skge_hw *hw)
/* avoid boards with stuck Hardware error bits */
if ((skge_read32(hw, B0_ISRC) & IS_HW_ERR) &&
(skge_read32(hw, B0_HWE_ISRC) & IS_IRQ_SENSOR)) {
- printk(KERN_WARNING PFX "stuck hardware sensor bit\n");
+ dev_warn(&hw->pdev->dev, "stuck hardware sensor bit\n");
hw->intr_mask &= ~IS_HW_ERR;
}
@@ -3408,7 +3477,7 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port,
struct net_device *dev = alloc_etherdev(sizeof(*skge));
if (!dev) {
- printk(KERN_ERR "skge etherdev alloc failed");
+ dev_err(&hw->pdev->dev, "etherdev alloc failed\n");
return NULL;
}
@@ -3452,6 +3521,7 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port,
skge->duplex = -1;
skge->speed = -1;
skge->advertising = skge_supported_modes(hw);
+ skge->wol = pci_wake_enabled(hw->pdev) ? wol_supported(hw) : 0;
hw->dev[port] = dev;
@@ -3496,15 +3566,13 @@ static int __devinit skge_probe(struct pci_dev *pdev,
err = pci_enable_device(pdev);
if (err) {
- printk(KERN_ERR PFX "%s cannot enable PCI device\n",
- pci_name(pdev));
+ dev_err(&pdev->dev, "cannot enable PCI device\n");
goto err_out;
}
err = pci_request_regions(pdev, DRV_NAME);
if (err) {
- printk(KERN_ERR PFX "%s cannot obtain PCI resources\n",
- pci_name(pdev));
+ dev_err(&pdev->dev, "cannot obtain PCI resources\n");
goto err_out_disable_pdev;
}
@@ -3519,8 +3587,7 @@ static int __devinit skge_probe(struct pci_dev *pdev,
}
if (err) {
- printk(KERN_ERR PFX "%s no usable DMA configuration\n",
- pci_name(pdev));
+ dev_err(&pdev->dev, "no usable DMA configuration\n");
goto err_out_free_regions;
}
@@ -3538,8 +3605,7 @@ static int __devinit skge_probe(struct pci_dev *pdev,
err = -ENOMEM;
hw = kzalloc(sizeof(*hw), GFP_KERNEL);
if (!hw) {
- printk(KERN_ERR PFX "%s: cannot allocate hardware struct\n",
- pci_name(pdev));
+ dev_err(&pdev->dev, "cannot allocate hardware struct\n");
goto err_out_free_regions;
}
@@ -3550,8 +3616,7 @@ static int __devinit skge_probe(struct pci_dev *pdev,
hw->regs = ioremap_nocache(pci_resource_start(pdev, 0), 0x4000);
if (!hw->regs) {
- printk(KERN_ERR PFX "%s: cannot map device registers\n",
- pci_name(pdev));
+ dev_err(&pdev->dev, "cannot map device registers\n");
goto err_out_free_hw;
}
@@ -3567,23 +3632,19 @@ static int __devinit skge_probe(struct pci_dev *pdev,
if (!dev)
goto err_out_led_off;
- if (!is_valid_ether_addr(dev->dev_addr)) {
- printk(KERN_ERR PFX "%s: bad (zero?) ethernet address in rom\n",
- pci_name(pdev));
- err = -EIO;
- goto err_out_free_netdev;
- }
+ /* Some motherboards are broken and has zero in ROM. */
+ if (!is_valid_ether_addr(dev->dev_addr))
+ dev_warn(&pdev->dev, "bad (zero?) ethernet address in rom\n");
err = register_netdev(dev);
if (err) {
- printk(KERN_ERR PFX "%s: cannot register net device\n",
- pci_name(pdev));
+ dev_err(&pdev->dev, "cannot register net device\n");
goto err_out_free_netdev;
}
err = request_irq(pdev->irq, skge_intr, IRQF_SHARED, dev->name, hw);
if (err) {
- printk(KERN_ERR PFX "%s: cannot assign irq %d\n",
+ dev_err(&pdev->dev, "%s: cannot assign irq %d\n",
dev->name, pdev->irq);
goto err_out_unregister;
}
@@ -3594,7 +3655,7 @@ static int __devinit skge_probe(struct pci_dev *pdev,
skge_show_addr(dev1);
else {
/* Failure to register second port need not be fatal */
- printk(KERN_WARNING PFX "register of second port failed\n");
+ dev_warn(&pdev->dev, "register of second port failed\n");
hw->dev[1] = NULL;
free_netdev(dev1);
}
@@ -3630,6 +3691,8 @@ static void __devexit skge_remove(struct pci_dev *pdev)
if (!hw)
return;
+ flush_scheduled_work();
+
if ((dev1 = hw->dev[1]))
unregister_netdev(dev1);
dev0 = hw->dev[0];
@@ -3644,8 +3707,6 @@ static void __devexit skge_remove(struct pci_dev *pdev)
skge_write16(hw, B0_LED, LED_STAT_OFF);
skge_write8(hw, B0_CTST, CS_RST_SET);
- flush_scheduled_work();
-
free_irq(pdev->irq, hw);
pci_release_regions(pdev);
pci_disable_device(pdev);
@@ -3659,28 +3720,46 @@ static void __devexit skge_remove(struct pci_dev *pdev)
}
#ifdef CONFIG_PM
+static int vaux_avail(struct pci_dev *pdev)
+{
+ int pm_cap;
+
+ pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
+ if (pm_cap) {
+ u16 ctl;
+ pci_read_config_word(pdev, pm_cap + PCI_PM_PMC, &ctl);
+ if (ctl & PCI_PM_CAP_AUX_POWER)
+ return 1;
+ }
+ return 0;
+}
+
+
static int skge_suspend(struct pci_dev *pdev, pm_message_t state)
{
struct skge_hw *hw = pci_get_drvdata(pdev);
- int i, wol = 0;
+ int i, err, wol = 0;
+
+ err = pci_save_state(pdev);
+ if (err)
+ return err;
- pci_save_state(pdev);
for (i = 0; i < hw->ports; i++) {
struct net_device *dev = hw->dev[i];
+ struct skge_port *skge = netdev_priv(dev);
- if (netif_running(dev)) {
- struct skge_port *skge = netdev_priv(dev);
+ if (netif_running(dev))
+ skge_down(dev);
+ if (skge->wol)
+ skge_wol_init(skge);
- netif_carrier_off(dev);
- if (skge->wol)
- netif_stop_queue(dev);
- else
- skge_down(dev);
- wol |= skge->wol;
- }
- netif_device_detach(dev);
+ wol |= skge->wol;
}
+ if (wol && vaux_avail(pdev))
+ skge_write8(hw, B0_POWER_CTRL,
+ PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_ON | PC_VCC_OFF);
+
skge_write32(hw, B0_IMSK, 0);
pci_enable_wake(pdev, pci_choose_state(pdev, state), wol);
pci_set_power_state(pdev, pci_choose_state(pdev, state));
@@ -3693,8 +3772,14 @@ static int skge_resume(struct pci_dev *pdev)
struct skge_hw *hw = pci_get_drvdata(pdev);
int i, err;
- pci_set_power_state(pdev, PCI_D0);
- pci_restore_state(pdev);
+ err = pci_set_power_state(pdev, PCI_D0);
+ if (err)
+ goto out;
+
+ err = pci_restore_state(pdev);
+ if (err)
+ goto out;
+
pci_enable_wake(pdev, PCI_D0, 0);
err = skge_reset(hw);
@@ -3704,7 +3789,6 @@ static int skge_resume(struct pci_dev *pdev)
for (i = 0; i < hw->ports; i++) {
struct net_device *dev = hw->dev[i];
- netif_device_attach(dev);
if (netif_running(dev)) {
err = skge_up(dev);
diff --git a/drivers/net/skge.h b/drivers/net/skge.h
index f6223c533c0..17b1b479dff 100644
--- a/drivers/net/skge.h
+++ b/drivers/net/skge.h
@@ -876,11 +876,13 @@ enum {
WOL_PATT_CNT_0 = 0x0f38,/* 32 bit WOL Pattern Counter 3..0 */
WOL_PATT_CNT_4 = 0x0f3c,/* 24 bit WOL Pattern Counter 6..4 */
};
+#define WOL_REGS(port, x) (x + (port)*0x80)
enum {
WOL_PATT_RAM_1 = 0x1000,/* WOL Pattern RAM Link 1 */
WOL_PATT_RAM_2 = 0x1400,/* WOL Pattern RAM Link 2 */
};
+#define WOL_PATT_RAM_BASE(port) (WOL_PATT_RAM_1 + (port)*0x400)
enum {
BASE_XMAC_1 = 0x2000,/* XMAC 1 registers */
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index 822dd0b1313..52edbd7ac17 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -49,7 +49,7 @@
#include "sky2.h"
#define DRV_NAME "sky2"
-#define DRV_VERSION "1.10"
+#define DRV_VERSION "1.13"
#define PFX DRV_NAME " "
/*
@@ -105,6 +105,7 @@ static const struct pci_device_id sky2_id_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4b00) }, /* DGE-560T */
{ PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4001) }, /* DGE-550SX */
{ PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4B02) }, /* DGE-560SX */
+ { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4B03) }, /* DGE-550T */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4340) }, /* 88E8021 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4341) }, /* 88E8022 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4342) }, /* 88E8061 */
@@ -126,6 +127,9 @@ static const struct pci_device_id sky2_id_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4366) }, /* 88EC036 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4367) }, /* 88EC032 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4368) }, /* 88EC034 */
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4369) }, /* 88EC042 */
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x436A) }, /* 88E8058 */
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x436B) }, /* 88E8071 */
{ 0 }
};
@@ -140,7 +144,7 @@ static const u32 portirq_msk[] = { Y2_IS_PORT_1, Y2_IS_PORT_2 };
static const char *yukon2_name[] = {
"XL", /* 0xb3 */
"EC Ultra", /* 0xb4 */
- "UNKNOWN", /* 0xb5 */
+ "Extreme", /* 0xb5 */
"EC", /* 0xb6 */
"FE", /* 0xb7 */
};
@@ -192,76 +196,52 @@ static u16 gm_phy_read(struct sky2_hw *hw, unsigned port, u16 reg)
return v;
}
-static void sky2_set_power_state(struct sky2_hw *hw, pci_power_t state)
-{
- u16 power_control;
- int vaux;
-
- pr_debug("sky2_set_power_state %d\n", state);
- sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
-
- power_control = sky2_pci_read16(hw, hw->pm_cap + PCI_PM_PMC);
- vaux = (sky2_read16(hw, B0_CTST) & Y2_VAUX_AVAIL) &&
- (power_control & PCI_PM_CAP_PME_D3cold);
-
- power_control = sky2_pci_read16(hw, hw->pm_cap + PCI_PM_CTRL);
-
- power_control |= PCI_PM_CTRL_PME_STATUS;
- power_control &= ~(PCI_PM_CTRL_STATE_MASK);
-
- switch (state) {
- case PCI_D0:
- /* switch power to VCC (WA for VAUX problem) */
- sky2_write8(hw, B0_POWER_CTRL,
- PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_OFF | PC_VCC_ON);
-
- /* disable Core Clock Division, */
- sky2_write32(hw, B2_Y2_CLK_CTRL, Y2_CLK_DIV_DIS);
- if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1)
- /* enable bits are inverted */
- sky2_write8(hw, B2_Y2_CLK_GATE,
- Y2_PCI_CLK_LNK1_DIS | Y2_COR_CLK_LNK1_DIS |
- Y2_CLK_GAT_LNK1_DIS | Y2_PCI_CLK_LNK2_DIS |
- Y2_COR_CLK_LNK2_DIS | Y2_CLK_GAT_LNK2_DIS);
- else
- sky2_write8(hw, B2_Y2_CLK_GATE, 0);
+static void sky2_power_on(struct sky2_hw *hw)
+{
+ /* switch power to VCC (WA for VAUX problem) */
+ sky2_write8(hw, B0_POWER_CTRL,
+ PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_OFF | PC_VCC_ON);
- if (hw->chip_id == CHIP_ID_YUKON_EC_U) {
- u32 reg1;
+ /* disable Core Clock Division, */
+ sky2_write32(hw, B2_Y2_CLK_CTRL, Y2_CLK_DIV_DIS);
- sky2_pci_write32(hw, PCI_DEV_REG3, 0);
- reg1 = sky2_pci_read32(hw, PCI_DEV_REG4);
- reg1 &= P_ASPM_CONTROL_MSK;
- sky2_pci_write32(hw, PCI_DEV_REG4, reg1);
- sky2_pci_write32(hw, PCI_DEV_REG5, 0);
- }
+ if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1)
+ /* enable bits are inverted */
+ sky2_write8(hw, B2_Y2_CLK_GATE,
+ Y2_PCI_CLK_LNK1_DIS | Y2_COR_CLK_LNK1_DIS |
+ Y2_CLK_GAT_LNK1_DIS | Y2_PCI_CLK_LNK2_DIS |
+ Y2_COR_CLK_LNK2_DIS | Y2_CLK_GAT_LNK2_DIS);
+ else
+ sky2_write8(hw, B2_Y2_CLK_GATE, 0);
- break;
+ if (hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX) {
+ u32 reg1;
- case PCI_D3hot:
- case PCI_D3cold:
- if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1)
- sky2_write8(hw, B2_Y2_CLK_GATE, 0);
- else
- /* enable bits are inverted */
- sky2_write8(hw, B2_Y2_CLK_GATE,
- Y2_PCI_CLK_LNK1_DIS | Y2_COR_CLK_LNK1_DIS |
- Y2_CLK_GAT_LNK1_DIS | Y2_PCI_CLK_LNK2_DIS |
- Y2_COR_CLK_LNK2_DIS | Y2_CLK_GAT_LNK2_DIS);
-
- /* switch power to VAUX */
- if (vaux && state != PCI_D3cold)
- sky2_write8(hw, B0_POWER_CTRL,
- (PC_VAUX_ENA | PC_VCC_ENA |
- PC_VAUX_ON | PC_VCC_OFF));
- break;
- default:
- printk(KERN_ERR PFX "Unknown power state %d\n", state);
+ sky2_pci_write32(hw, PCI_DEV_REG3, 0);
+ reg1 = sky2_pci_read32(hw, PCI_DEV_REG4);
+ reg1 &= P_ASPM_CONTROL_MSK;
+ sky2_pci_write32(hw, PCI_DEV_REG4, reg1);
+ sky2_pci_write32(hw, PCI_DEV_REG5, 0);
}
+}
- sky2_pci_write16(hw, hw->pm_cap + PCI_PM_CTRL, power_control);
- sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
+static void sky2_power_aux(struct sky2_hw *hw)
+{
+ if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1)
+ sky2_write8(hw, B2_Y2_CLK_GATE, 0);
+ else
+ /* enable bits are inverted */
+ sky2_write8(hw, B2_Y2_CLK_GATE,
+ Y2_PCI_CLK_LNK1_DIS | Y2_COR_CLK_LNK1_DIS |
+ Y2_CLK_GAT_LNK1_DIS | Y2_PCI_CLK_LNK2_DIS |
+ Y2_COR_CLK_LNK2_DIS | Y2_CLK_GAT_LNK2_DIS);
+
+ /* switch power to VAUX */
+ if (sky2_read16(hw, B0_CTST) & Y2_VAUX_AVAIL)
+ sky2_write8(hw, B0_POWER_CTRL,
+ (PC_VAUX_ENA | PC_VCC_ENA |
+ PC_VAUX_ON | PC_VCC_OFF));
}
static void sky2_gmac_reset(struct sky2_hw *hw, unsigned port)
@@ -313,8 +293,10 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
struct sky2_port *sky2 = netdev_priv(hw->dev[port]);
u16 ctrl, ct1000, adv, pg, ledctrl, ledover, reg;
- if (sky2->autoneg == AUTONEG_ENABLE &&
- !(hw->chip_id == CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U)) {
+ if (sky2->autoneg == AUTONEG_ENABLE
+ && !(hw->chip_id == CHIP_ID_YUKON_XL
+ || hw->chip_id == CHIP_ID_YUKON_EC_U
+ || hw->chip_id == CHIP_ID_YUKON_EX)) {
u16 ectrl = gm_phy_read(hw, port, PHY_MARV_EXT_CTRL);
ectrl &= ~(PHY_M_EC_M_DSC_MSK | PHY_M_EC_S_DSC_MSK |
@@ -341,8 +323,10 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
/* enable automatic crossover */
ctrl |= PHY_M_PC_MDI_XMODE(PHY_M_PC_ENA_AUTO);
- if (sky2->autoneg == AUTONEG_ENABLE &&
- (hw->chip_id == CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U)) {
+ if (sky2->autoneg == AUTONEG_ENABLE
+ && (hw->chip_id == CHIP_ID_YUKON_XL
+ || hw->chip_id == CHIP_ID_YUKON_EC_U
+ || hw->chip_id == CHIP_ID_YUKON_EX)) {
ctrl &= ~PHY_M_PC_DSC_MSK;
ctrl |= PHY_M_PC_DSC(2) | PHY_M_PC_DOWN_S_ENA;
}
@@ -497,7 +481,9 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
/* restore page register */
gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg);
break;
+
case CHIP_ID_YUKON_EC_U:
+ case CHIP_ID_YUKON_EX:
pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR);
/* select page 3 to access LED control register */
@@ -539,7 +525,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
/* set page register to 0 */
gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg);
- } else {
+ } else if (hw->chip_id != CHIP_ID_YUKON_EX) {
gm_phy_write(hw, port, PHY_MARV_LED_CTRL, ledctrl);
if (sky2->autoneg == AUTONEG_DISABLE || sky2->speed == SPEED_100) {
@@ -591,6 +577,73 @@ static void sky2_phy_reinit(struct sky2_port *sky2)
spin_unlock_bh(&sky2->phy_lock);
}
+/* Put device in state to listen for Wake On Lan */
+static void sky2_wol_init(struct sky2_port *sky2)
+{
+ struct sky2_hw *hw = sky2->hw;
+ 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);
+ sky2_write16(hw, SK_REG(port, GMAC_LINK_CTRL), GMLC_RST_CLR);
+
+ sky2_write8(hw, SK_REG(port, GPHY_CTRL), GPC_RST_CLR);
+ sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_RST_CLR);
+
+ /* Force to 10/100
+ * sky2_reset will re-enable on resume
+ */
+ save_mode = sky2->flow_mode;
+ ctrl = sky2->advertising;
+
+ sky2->advertising &= ~(ADVERTISED_1000baseT_Half|ADVERTISED_1000baseT_Full);
+ sky2->flow_mode = FC_NONE;
+ sky2_phy_power(hw, port, 1);
+ sky2_phy_reinit(sky2);
+
+ sky2->flow_mode = save_mode;
+ sky2->advertising = ctrl;
+
+ /* Set GMAC to no flow control and auto update for speed/duplex */
+ gma_write16(hw, port, GM_GP_CTRL,
+ GM_GPCR_FC_TX_DIS|GM_GPCR_TX_ENA|GM_GPCR_RX_ENA|
+ GM_GPCR_DUP_FULL|GM_GPCR_FC_RX_DIS|GM_GPCR_AU_FCT_DIS);
+
+ /* Set WOL address */
+ memcpy_toio(hw->regs + WOL_REGS(port, WOL_MAC_ADDR),
+ sky2->netdev->dev_addr, ETH_ALEN);
+
+ /* Turn on appropriate WOL control bits */
+ sky2_write16(hw, WOL_REGS(port, WOL_CTRL_STAT), WOL_CTL_CLEAR_RESULT);
+ ctrl = 0;
+ if (sky2->wol & WAKE_PHY)
+ ctrl |= WOL_CTL_ENA_PME_ON_LINK_CHG|WOL_CTL_ENA_LINK_CHG_UNIT;
+ else
+ ctrl |= WOL_CTL_DIS_PME_ON_LINK_CHG|WOL_CTL_DIS_LINK_CHG_UNIT;
+
+ if (sky2->wol & WAKE_MAGIC)
+ ctrl |= WOL_CTL_ENA_PME_ON_MAGIC_PKT|WOL_CTL_ENA_MAGIC_PKT_UNIT;
+ else
+ ctrl |= WOL_CTL_DIS_PME_ON_MAGIC_PKT|WOL_CTL_DIS_MAGIC_PKT_UNIT;;
+
+ 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 */
+ sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
+ reg1 = sky2_pci_read32(hw, PCI_DEV_REG1);
+ reg1 |= PCI_Y2_PME_LEGACY;
+ sky2_pci_write32(hw, PCI_DEV_REG1, reg1);
+ sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
+
+ /* block receiver */
+ sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET);
+
+}
+
static void sky2_mac_init(struct sky2_hw *hw, unsigned port)
{
struct sky2_port *sky2 = netdev_priv(hw->dev[port]);
@@ -684,7 +737,7 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port)
sky2_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_CLR);
sky2_write16(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_OPER_ON);
- if (hw->chip_id == CHIP_ID_YUKON_EC_U) {
+ if (hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX) {
sky2_write8(hw, SK_REG(port, RX_GMF_LP_THR), 768/8);
sky2_write8(hw, SK_REG(port, RX_GMF_UP_THR), 1024/8);
if (hw->dev[port]->mtu > ETH_DATA_LEN) {
@@ -1467,6 +1520,9 @@ static void sky2_tx_complete(struct sky2_port *sky2, u16 done)
if (unlikely(netif_msg_tx_done(sky2)))
printk(KERN_DEBUG "%s: tx done %u\n",
dev->name, idx);
+ sky2->net_stats.tx_packets++;
+ sky2->net_stats.tx_bytes += re->skb->len;
+
dev_kfree_skb_any(re->skb);
}
@@ -1641,7 +1697,9 @@ static void sky2_link_up(struct sky2_port *sky2)
sky2_write8(hw, SK_REG(port, LNK_LED_REG),
LINKLED_ON | LINKLED_BLINK_OFF | LINKLED_LINKSYNC_OFF);
- if (hw->chip_id == CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U) {
+ if (hw->chip_id == CHIP_ID_YUKON_XL
+ || hw->chip_id == CHIP_ID_YUKON_EC_U
+ || hw->chip_id == CHIP_ID_YUKON_EX) {
u16 pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR);
u16 led = PHY_M_LEDC_LOS_CTRL(1); /* link active */
@@ -1684,13 +1742,6 @@ static void sky2_link_down(struct sky2_port *sky2)
reg &= ~(GM_GPCR_RX_ENA | GM_GPCR_TX_ENA);
gma_write16(hw, port, GM_GP_CTRL, reg);
- if (sky2->flow_status == FC_RX) {
- /* restore Asymmetric Pause bit */
- gm_phy_write(hw, port, PHY_MARV_AUNE_ADV,
- gm_phy_read(hw, port, PHY_MARV_AUNE_ADV)
- | PHY_M_AN_ASP);
- }
-
netif_carrier_off(sky2->netdev);
netif_stop_queue(sky2->netdev);
@@ -1715,10 +1766,10 @@ static int sky2_autoneg_done(struct sky2_port *sky2, u16 aux)
{
struct sky2_hw *hw = sky2->hw;
unsigned port = sky2->port;
- u16 lpa;
+ u16 advert, lpa;
+ 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);
return -1;
@@ -1733,18 +1784,40 @@ static int sky2_autoneg_done(struct sky2_port *sky2, u16 aux)
sky2->speed = sky2_phy_speed(hw, aux);
sky2->duplex = (aux & PHY_M_PS_FULL_DUP) ? DUPLEX_FULL : DUPLEX_HALF;
- /* Pause bits are offset (9..8) */
- if (hw->chip_id == CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U)
- aux >>= 6;
-
- sky2->flow_status = sky2_flow(aux & PHY_M_PS_RX_P_EN,
- aux & PHY_M_PS_TX_P_EN);
+ /* Since the pause result bits seem to in different positions on
+ * different chips. look at registers.
+ */
+ if (!sky2_is_copper(hw)) {
+ /* Shift for bits in fiber PHY */
+ advert &= ~(ADVERTISE_PAUSE_CAP|ADVERTISE_PAUSE_ASYM);
+ lpa &= ~(LPA_PAUSE_CAP|LPA_PAUSE_ASYM);
+
+ if (advert & ADVERTISE_1000XPAUSE)
+ advert |= ADVERTISE_PAUSE_CAP;
+ if (advert & ADVERTISE_1000XPSE_ASYM)
+ advert |= ADVERTISE_PAUSE_ASYM;
+ if (lpa & LPA_1000XPAUSE)
+ lpa |= LPA_PAUSE_CAP;
+ if (lpa & LPA_1000XPAUSE_ASYM)
+ lpa |= LPA_PAUSE_ASYM;
+ }
+
+ sky2->flow_status = FC_NONE;
+ if (advert & ADVERTISE_PAUSE_CAP) {
+ if (lpa & LPA_PAUSE_CAP)
+ sky2->flow_status = FC_BOTH;
+ else if (advert & ADVERTISE_PAUSE_ASYM)
+ sky2->flow_status = FC_RX;
+ } else if (advert & ADVERTISE_PAUSE_ASYM) {
+ if ((lpa & LPA_PAUSE_CAP) && (lpa & LPA_PAUSE_ASYM))
+ sky2->flow_status = FC_TX;
+ }
if (sky2->duplex == DUPLEX_HALF && sky2->speed < SPEED_1000
- && hw->chip_id != CHIP_ID_YUKON_EC_U)
+ && !(hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX))
sky2->flow_status = FC_NONE;
- if (aux & PHY_M_PS_RX_P_EN)
+ if (sky2->flow_status & FC_TX)
sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_ON);
else
sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF);
@@ -1793,49 +1866,24 @@ out:
spin_unlock(&sky2->phy_lock);
}
-
-/* Transmit timeout is only called if we are running, carries is up
+/* Transmit timeout is only called if we are running, carrier is up
* and tx queue is full (stopped).
*/
static void sky2_tx_timeout(struct net_device *dev)
{
struct sky2_port *sky2 = netdev_priv(dev);
struct sky2_hw *hw = sky2->hw;
- unsigned txq = txqaddr[sky2->port];
- u16 report, done;
if (netif_msg_timer(sky2))
printk(KERN_ERR PFX "%s: tx timeout\n", dev->name);
- report = sky2_read16(hw, sky2->port == 0 ? STAT_TXA1_RIDX : STAT_TXA2_RIDX);
- done = sky2_read16(hw, Q_ADDR(txq, Q_DONE));
-
printk(KERN_DEBUG PFX "%s: transmit ring %u .. %u report=%u done=%u\n",
- dev->name,
- sky2->tx_cons, sky2->tx_prod, report, done);
-
- if (report != done) {
- printk(KERN_INFO PFX "status burst pending (irq moderation?)\n");
-
- sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_STOP);
- sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_START);
- } else if (report != sky2->tx_cons) {
- printk(KERN_INFO PFX "status report lost?\n");
-
- netif_tx_lock_bh(dev);
- sky2_tx_complete(sky2, report);
- netif_tx_unlock_bh(dev);
- } else {
- printk(KERN_INFO PFX "hardware hung? flushing\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)));
- sky2_write32(hw, Q_ADDR(txq, Q_CSR), BMU_STOP);
- sky2_write32(hw, Y2_QADDR(txq, PREF_UNIT_CTRL), PREF_UNIT_RST_SET);
-
- sky2_tx_clean(dev);
-
- sky2_qset(hw, txq);
- sky2_prefetch_init(hw, txq, sky2->tx_le_map, TX_RING_SIZE - 1);
- }
+ /* can't restart safely under softirq */
+ schedule_work(&hw->restart_work);
}
static int sky2_change_mtu(struct net_device *dev, int new_mtu)
@@ -1849,8 +1897,9 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu)
if (new_mtu < ETH_ZLEN || new_mtu > ETH_JUMBO_MTU)
return -EINVAL;
+ /* TSO on Yukon Ultra and MTU > 1500 not supported */
if (hw->chip_id == CHIP_ID_YUKON_EC_U && new_mtu > ETH_DATA_LEN)
- return -EINVAL;
+ dev->features &= ~NETIF_F_TSO;
if (!netif_running(dev)) {
dev->mtu = new_mtu;
@@ -2007,9 +2056,6 @@ static struct sk_buff *sky2_receive(struct net_device *dev,
if (!(status & GMR_FS_RX_OK))
goto resubmit;
- if (length > dev->mtu + ETH_HLEN)
- goto oversize;
-
if (length < copybreak)
skb = receive_copy(sky2, re, length);
else
@@ -2019,14 +2065,10 @@ resubmit:
return skb;
-oversize:
- ++sky2->net_stats.rx_over_errors;
- goto resubmit;
-
error:
++sky2->net_stats.rx_errors;
if (status & GMR_FS_RX_FF_OV) {
- sky2->net_stats.rx_fifo_errors++;
+ sky2->net_stats.rx_over_errors++;
goto resubmit;
}
@@ -2089,6 +2131,8 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do)
goto force_update;
skb->protocol = eth_type_trans(skb, dev);
+ sky2->net_stats.rx_packets++;
+ sky2->net_stats.rx_bytes += skb->len;
dev->last_rx = jiffies;
#ifdef SKY2_VLAN_TAG_USED
@@ -2218,8 +2262,8 @@ static void sky2_hw_intr(struct sky2_hw *hw)
pci_err = sky2_pci_read16(hw, PCI_STATUS);
if (net_ratelimit())
- printk(KERN_ERR PFX "%s: pci hw error (0x%x)\n",
- pci_name(hw->pdev), pci_err);
+ dev_err(&hw->pdev->dev, "PCI hardware error (0x%x)\n",
+ pci_err);
sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
sky2_pci_write16(hw, PCI_STATUS,
@@ -2234,8 +2278,8 @@ static void sky2_hw_intr(struct sky2_hw *hw)
pex_err = sky2_pci_read32(hw, PEX_UNC_ERR_STAT);
if (net_ratelimit())
- printk(KERN_ERR PFX "%s: pci express error (0x%x)\n",
- pci_name(hw->pdev), pex_err);
+ dev_err(&hw->pdev->dev, "PCI Express error (0x%x)\n",
+ pex_err);
/* clear the interrupt */
sky2_write32(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
@@ -2404,6 +2448,7 @@ static inline u32 sky2_mhz(const struct sky2_hw *hw)
switch (hw->chip_id) {
case CHIP_ID_YUKON_EC:
case CHIP_ID_YUKON_EC_U:
+ case CHIP_ID_YUKON_EX:
return 125; /* 125 Mhz */
case CHIP_ID_YUKON_FE:
return 100; /* 100 Mhz */
@@ -2423,34 +2468,62 @@ static inline u32 sky2_clk2us(const struct sky2_hw *hw, u32 clk)
}
-static int sky2_reset(struct sky2_hw *hw)
+static int __devinit sky2_init(struct sky2_hw *hw)
{
- u16 status;
u8 t8;
- int i;
sky2_write8(hw, B0_CTST, CS_RST_CLR);
hw->chip_id = sky2_read8(hw, B2_CHIP_ID);
if (hw->chip_id < CHIP_ID_YUKON_XL || hw->chip_id > CHIP_ID_YUKON_FE) {
- printk(KERN_ERR PFX "%s: unsupported chip type 0x%x\n",
- pci_name(hw->pdev), hw->chip_id);
+ dev_err(&hw->pdev->dev, "unsupported chip type 0x%x\n",
+ hw->chip_id);
return -EOPNOTSUPP;
}
+ if (hw->chip_id == CHIP_ID_YUKON_EX)
+ dev_warn(&hw->pdev->dev, "this driver not yet tested on this chip type\n"
+ "Please report success or failure to <netdev@vger.kernel.org>\n");
+
+ /* Make sure and enable all clocks */
+ if (hw->chip_id == CHIP_ID_YUKON_EX || hw->chip_id == CHIP_ID_YUKON_EC_U)
+ sky2_pci_write32(hw, PCI_DEV_REG3, 0);
+
hw->chip_rev = (sky2_read8(hw, B2_MAC_CFG) & CFG_CHIP_R_MSK) >> 4;
/* This rev is really old, and requires untested workarounds */
if (hw->chip_id == CHIP_ID_YUKON_EC && hw->chip_rev == CHIP_REV_YU_EC_A1) {
- printk(KERN_ERR PFX "%s: unsupported revision Yukon-%s (0x%x) rev %d\n",
- pci_name(hw->pdev), yukon2_name[hw->chip_id - CHIP_ID_YUKON_XL],
- hw->chip_id, hw->chip_rev);
+ dev_err(&hw->pdev->dev, "unsupported revision Yukon-%s (0x%x) rev %d\n",
+ yukon2_name[hw->chip_id - CHIP_ID_YUKON_XL],
+ hw->chip_id, hw->chip_rev);
return -EOPNOTSUPP;
}
+ hw->pmd_type = sky2_read8(hw, B2_PMD_TYP);
+ hw->ports = 1;
+ t8 = sky2_read8(hw, B2_Y2_HW_RES);
+ if ((t8 & CFG_DUAL_MAC_MSK) == CFG_DUAL_MAC_MSK) {
+ if (!(sky2_read8(hw, B2_Y2_CLK_GATE) & Y2_STATUS_LNK2_INAC))
+ ++hw->ports;
+ }
+
+ return 0;
+}
+
+static void sky2_reset(struct sky2_hw *hw)
+{
+ u16 status;
+ int i;
+
/* disable ASF */
if (hw->chip_id <= CHIP_ID_YUKON_EC) {
- sky2_write8(hw, B28_Y2_ASF_STAT_CMD, Y2_ASF_RESET);
+ if (hw->chip_id == CHIP_ID_YUKON_EX) {
+ status = sky2_read16(hw, HCU_CCSR);
+ status &= ~(HCU_CCSR_AHB_RST | HCU_CCSR_CPU_RST_MODE |
+ HCU_CCSR_UC_STATE_MSK);
+ sky2_write16(hw, HCU_CCSR, status);
+ } else
+ sky2_write8(hw, B28_Y2_ASF_STAT_CMD, Y2_ASF_RESET);
sky2_write16(hw, B0_CTST, Y2_ASF_DISABLE);
}
@@ -2472,15 +2545,7 @@ static int sky2_reset(struct sky2_hw *hw)
sky2_pci_write32(hw, PEX_UNC_ERR_STAT, 0xffffffffUL);
- hw->pmd_type = sky2_read8(hw, B2_PMD_TYP);
- hw->ports = 1;
- t8 = sky2_read8(hw, B2_Y2_HW_RES);
- if ((t8 & CFG_DUAL_MAC_MSK) == CFG_DUAL_MAC_MSK) {
- if (!(sky2_read8(hw, B2_Y2_CLK_GATE) & Y2_STATUS_LNK2_INAC))
- ++hw->ports;
- }
-
- sky2_set_power_state(hw, PCI_D0);
+ sky2_power_on(hw);
for (i = 0; i < hw->ports; i++) {
sky2_write8(hw, SK_REG(i, GMAC_LINK_CTRL), GMLC_RST_SET);
@@ -2563,7 +2628,80 @@ static int sky2_reset(struct sky2_hw *hw)
sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_START);
sky2_write8(hw, STAT_LEV_TIMER_CTRL, TIM_START);
sky2_write8(hw, STAT_ISR_TIMER_CTRL, TIM_START);
+}
+static void sky2_restart(struct work_struct *work)
+{
+ struct sky2_hw *hw = container_of(work, struct sky2_hw, restart_work);
+ struct net_device *dev;
+ int i, err;
+
+ dev_dbg(&hw->pdev->dev, "restarting\n");
+
+ del_timer_sync(&hw->idle_timer);
+
+ rtnl_lock();
+ sky2_write32(hw, B0_IMSK, 0);
+ sky2_read32(hw, B0_IMSK);
+
+ netif_poll_disable(hw->dev[0]);
+
+ for (i = 0; i < hw->ports; i++) {
+ dev = hw->dev[i];
+ if (netif_running(dev))
+ sky2_down(dev);
+ }
+
+ sky2_reset(hw);
+ sky2_write32(hw, B0_IMSK, Y2_IS_BASE);
+ netif_poll_enable(hw->dev[0]);
+
+ for (i = 0; i < hw->ports; i++) {
+ dev = hw->dev[i];
+ if (netif_running(dev)) {
+ err = sky2_up(dev);
+ if (err) {
+ printk(KERN_INFO PFX "%s: could not restart %d\n",
+ dev->name, err);
+ dev_close(dev);
+ }
+ }
+ }
+
+ sky2_idle_start(hw);
+
+ rtnl_unlock();
+}
+
+static inline u8 sky2_wol_supported(const struct sky2_hw *hw)
+{
+ return sky2_is_copper(hw) ? (WAKE_PHY | WAKE_MAGIC) : 0;
+}
+
+static void sky2_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+ const struct sky2_port *sky2 = netdev_priv(dev);
+
+ wol->supported = sky2_wol_supported(sky2->hw);
+ wol->wolopts = sky2->wol;
+}
+
+static int sky2_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+ struct sky2_port *sky2 = netdev_priv(dev);
+ struct sky2_hw *hw = sky2->hw;
+
+ if (wol->wolopts & ~sky2_wol_supported(sky2->hw))
+ return -EOPNOTSUPP;
+
+ sky2->wol = wol->wolopts;
+
+ if (hw->chip_id == CHIP_ID_YUKON_EC_U)
+ sky2_write32(hw, B0_CTST, sky2->wol
+ ? Y2_HW_WOL_ON : Y2_HW_WOL_OFF);
+
+ if (!netif_running(dev))
+ sky2_wol_init(sky2);
return 0;
}
@@ -2814,25 +2952,9 @@ static void sky2_get_strings(struct net_device *dev, u32 stringset, u8 * data)
}
}
-/* Use hardware MIB variables for critical path statistics and
- * transmit feedback not reported at interrupt.
- * Other errors are accounted for in interrupt handler.
- */
static struct net_device_stats *sky2_get_stats(struct net_device *dev)
{
struct sky2_port *sky2 = netdev_priv(dev);
- u64 data[13];
-
- sky2_phy_stats(sky2, data, ARRAY_SIZE(data));
-
- sky2->net_stats.tx_bytes = data[0];
- sky2->net_stats.rx_bytes = data[1];
- sky2->net_stats.tx_packets = data[2] + data[4] + data[6];
- sky2->net_stats.rx_packets = data[3] + data[5] + data[7];
- sky2->net_stats.multicast = data[3] + data[5];
- sky2->net_stats.collisions = data[10];
- sky2->net_stats.tx_aborted_errors = data[12];
-
return &sky2->net_stats;
}
@@ -3191,7 +3313,9 @@ static void sky2_get_regs(struct net_device *dev, struct ethtool_regs *regs,
static const struct ethtool_ops sky2_ethtool_ops = {
.get_settings = sky2_get_settings,
.set_settings = sky2_set_settings,
- .get_drvinfo = sky2_get_drvinfo,
+ .get_drvinfo = sky2_get_drvinfo,
+ .get_wol = sky2_get_wol,
+ .set_wol = sky2_set_wol,
.get_msglevel = sky2_get_msglevel,
.set_msglevel = sky2_set_msglevel,
.nway_reset = sky2_nway_reset,
@@ -3221,13 +3345,14 @@ static const struct ethtool_ops sky2_ethtool_ops = {
/* Initialize network device */
static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,
- unsigned port, int highmem)
+ unsigned port,
+ int highmem, int wol)
{
struct sky2_port *sky2;
struct net_device *dev = alloc_etherdev(sizeof(*sky2));
if (!dev) {
- printk(KERN_ERR "sky2 etherdev alloc failed");
+ dev_err(&hw->pdev->dev, "etherdev alloc failed");
return NULL;
}
@@ -3269,6 +3394,7 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,
sky2->speed = -1;
sky2->advertising = sky2_supported_modes(hw);
sky2->rx_csum = 1;
+ sky2->wol = wol;
spin_lock_init(&sky2->phy_lock);
sky2->tx_pending = TX_DEF_PENDING;
@@ -3278,11 +3404,9 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,
sky2->port = port;
- if (hw->chip_id != CHIP_ID_YUKON_EC_U)
- dev->features |= NETIF_F_TSO;
+ dev->features |= NETIF_F_TSO | NETIF_F_IP_CSUM | NETIF_F_SG;
if (highmem)
dev->features |= NETIF_F_HIGHDMA;
- dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
#ifdef SKY2_VLAN_TAG_USED
dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
@@ -3343,8 +3467,7 @@ static int __devinit sky2_test_msi(struct sky2_hw *hw)
err = request_irq(pdev->irq, sky2_test_intr, 0, DRV_NAME, hw);
if (err) {
- printk(KERN_ERR PFX "%s: cannot assign irq %d\n",
- pci_name(pdev), pdev->irq);
+ dev_err(&pdev->dev, "cannot assign irq %d\n", pdev->irq);
return err;
}
@@ -3355,9 +3478,8 @@ static int __devinit sky2_test_msi(struct sky2_hw *hw)
if (!hw->msi) {
/* MSI test failed, go back to INTx mode */
- printk(KERN_INFO PFX "%s: No interrupt generated using MSI, "
- "switching to INTx mode.\n",
- pci_name(pdev));
+ dev_info(&pdev->dev, "No interrupt generated using MSI, "
+ "switching to INTx mode.\n");
err = -EOPNOTSUPP;
sky2_write8(hw, B0_CTST, CS_CL_SW_IRQ);
@@ -3371,62 +3493,62 @@ static int __devinit sky2_test_msi(struct sky2_hw *hw)
return err;
}
+static int __devinit pci_wake_enabled(struct pci_dev *dev)
+{
+ int pm = pci_find_capability(dev, PCI_CAP_ID_PM);
+ u16 value;
+
+ if (!pm)
+ return 0;
+ if (pci_read_config_word(dev, pm + PCI_PM_CTRL, &value))
+ return 0;
+ return value & PCI_PM_CTRL_PME_ENABLE;
+}
+
static int __devinit sky2_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
- struct net_device *dev, *dev1 = NULL;
+ struct net_device *dev;
struct sky2_hw *hw;
- int err, pm_cap, using_dac = 0;
+ int err, using_dac = 0, wol_default;
err = pci_enable_device(pdev);
if (err) {
- printk(KERN_ERR PFX "%s cannot enable PCI device\n",
- pci_name(pdev));
+ dev_err(&pdev->dev, "cannot enable PCI device\n");
goto err_out;
}
err = pci_request_regions(pdev, DRV_NAME);
if (err) {
- printk(KERN_ERR PFX "%s cannot obtain PCI resources\n",
- pci_name(pdev));
+ dev_err(&pdev->dev, "cannot obtain PCI resources\n");
goto err_out;
}
pci_set_master(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");
- err = -EIO;
- goto err_out_free_regions;
- }
-
if (sizeof(dma_addr_t) > sizeof(u32) &&
!(err = pci_set_dma_mask(pdev, DMA_64BIT_MASK))) {
using_dac = 1;
err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
if (err < 0) {
- printk(KERN_ERR PFX "%s unable to obtain 64 bit DMA "
- "for consistent allocations\n", pci_name(pdev));
+ dev_err(&pdev->dev, "unable to obtain 64 bit DMA "
+ "for consistent allocations\n");
goto err_out_free_regions;
}
-
} else {
err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
if (err) {
- printk(KERN_ERR PFX "%s no usable DMA configuration\n",
- pci_name(pdev));
+ dev_err(&pdev->dev, "no usable DMA configuration\n");
goto err_out_free_regions;
}
}
+ wol_default = pci_wake_enabled(pdev) ? WAKE_MAGIC : 0;
+
err = -ENOMEM;
hw = kzalloc(sizeof(*hw), GFP_KERNEL);
if (!hw) {
- printk(KERN_ERR PFX "%s: cannot allocate hardware struct\n",
- pci_name(pdev));
+ dev_err(&pdev->dev, "cannot allocate hardware struct\n");
goto err_out_free_regions;
}
@@ -3434,11 +3556,9 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
hw->regs = ioremap_nocache(pci_resource_start(pdev, 0), 0x4000);
if (!hw->regs) {
- printk(KERN_ERR PFX "%s: cannot map device registers\n",
- pci_name(pdev));
+ dev_err(&pdev->dev, "cannot map device registers\n");
goto err_out_free_hw;
}
- hw->pm_cap = pm_cap;
#ifdef __BIG_ENDIAN
/* The sk98lin vendor driver uses hardware byte swapping but
@@ -3458,18 +3578,22 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
if (!hw->st_le)
goto err_out_iounmap;
- err = sky2_reset(hw);
+ err = sky2_init(hw);
if (err)
goto err_out_iounmap;
- printk(KERN_INFO PFX "v%s addr 0x%llx irq %d Yukon-%s (0x%x) rev %d\n",
+ dev_info(&pdev->dev, "v%s addr 0x%llx irq %d Yukon-%s (0x%x) rev %d\n",
DRV_VERSION, (unsigned long long)pci_resource_start(pdev, 0),
pdev->irq, yukon2_name[hw->chip_id - CHIP_ID_YUKON_XL],
hw->chip_id, hw->chip_rev);
- dev = sky2_init_netdev(hw, 0, using_dac);
- if (!dev)
+ sky2_reset(hw);
+
+ dev = sky2_init_netdev(hw, 0, using_dac, wol_default);
+ if (!dev) {
+ err = -ENOMEM;
goto err_out_free_pci;
+ }
if (!disable_msi && pci_enable_msi(pdev) == 0) {
err = sky2_test_msi(hw);
@@ -3481,35 +3605,38 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
err = register_netdev(dev);
if (err) {
- printk(KERN_ERR PFX "%s: cannot register net device\n",
- pci_name(pdev));
+ dev_err(&pdev->dev, "cannot register net device\n");
goto err_out_free_netdev;
}
err = request_irq(pdev->irq, sky2_intr, hw->msi ? 0 : IRQF_SHARED,
dev->name, hw);
if (err) {
- printk(KERN_ERR PFX "%s: cannot assign irq %d\n",
- pci_name(pdev), pdev->irq);
+ dev_err(&pdev->dev, "cannot assign irq %d\n", pdev->irq);
goto err_out_unregister;
}
sky2_write32(hw, B0_IMSK, Y2_IS_BASE);
sky2_show_addr(dev);
- if (hw->ports > 1 && (dev1 = sky2_init_netdev(hw, 1, using_dac))) {
- if (register_netdev(dev1) == 0)
- sky2_show_addr(dev1);
- else {
- /* Failure to register second port need not be fatal */
- printk(KERN_WARNING PFX
- "register of second port failed\n");
+ if (hw->ports > 1) {
+ struct net_device *dev1;
+
+ dev1 = sky2_init_netdev(hw, 1, using_dac, wol_default);
+ if (!dev1)
+ dev_warn(&pdev->dev, "allocation for second device failed\n");
+ else if ((err = register_netdev(dev1))) {
+ dev_warn(&pdev->dev,
+ "register of second port failed (%d)\n", err);
hw->dev[1] = NULL;
free_netdev(dev1);
- }
+ } else
+ sky2_show_addr(dev1);
}
setup_timer(&hw->idle_timer, sky2_idle, (unsigned long) hw);
+ INIT_WORK(&hw->restart_work, sky2_restart);
+
sky2_idle_start(hw);
pci_set_drvdata(pdev, hw);
@@ -3546,6 +3673,8 @@ static void __devexit sky2_remove(struct pci_dev *pdev)
del_timer_sync(&hw->idle_timer);
+ flush_scheduled_work();
+
sky2_write32(hw, B0_IMSK, 0);
synchronize_irq(hw->pdev->irq);
@@ -3555,7 +3684,8 @@ static void __devexit sky2_remove(struct pci_dev *pdev)
unregister_netdev(dev1);
unregister_netdev(dev0);
- sky2_set_power_state(hw, PCI_D3hot);
+ sky2_power_aux(hw);
+
sky2_write16(hw, B0_Y2LED, LED_STAT_OFF);
sky2_write8(hw, B0_CTST, CS_RST_SET);
sky2_read8(hw, B0_CTST);
@@ -3580,27 +3710,31 @@ static void __devexit sky2_remove(struct pci_dev *pdev)
static int sky2_suspend(struct pci_dev *pdev, pm_message_t state)
{
struct sky2_hw *hw = pci_get_drvdata(pdev);
- int i;
- pci_power_t pstate = pci_choose_state(pdev, state);
-
- if (!(pstate == PCI_D3hot || pstate == PCI_D3cold))
- return -EINVAL;
+ int i, wol = 0;
del_timer_sync(&hw->idle_timer);
netif_poll_disable(hw->dev[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)) {
+ if (netif_running(dev))
sky2_down(dev);
- netif_device_detach(dev);
- }
+
+ if (sky2->wol)
+ sky2_wol_init(sky2);
+
+ wol |= sky2->wol;
}
sky2_write32(hw, B0_IMSK, 0);
+ sky2_power_aux(hw);
+
pci_save_state(pdev);
- sky2_set_power_state(hw, pstate);
+ pci_enable_wake(pdev, pci_choose_state(pdev, state), wol);
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
return 0;
}
@@ -3609,21 +3743,22 @@ static int sky2_resume(struct pci_dev *pdev)
struct sky2_hw *hw = pci_get_drvdata(pdev);
int i, err;
- pci_restore_state(pdev);
- pci_enable_wake(pdev, PCI_D0, 0);
- sky2_set_power_state(hw, PCI_D0);
+ err = pci_set_power_state(pdev, PCI_D0);
+ if (err)
+ goto out;
- err = sky2_reset(hw);
+ err = pci_restore_state(pdev);
if (err)
goto out;
+ pci_enable_wake(pdev, PCI_D0, 0);
+ sky2_reset(hw);
+
sky2_write32(hw, B0_IMSK, Y2_IS_BASE);
for (i = 0; i < hw->ports; i++) {
struct net_device *dev = hw->dev[i];
if (netif_running(dev)) {
- netif_device_attach(dev);
-
err = sky2_up(dev);
if (err) {
printk(KERN_ERR PFX "%s: could not up: %d\n",
@@ -3636,11 +3771,43 @@ static int sky2_resume(struct pci_dev *pdev)
netif_poll_enable(hw->dev[0]);
sky2_idle_start(hw);
+ return 0;
out:
+ dev_err(&pdev->dev, "resume failed (%d)\n", err);
+ pci_disable_device(pdev);
return err;
}
#endif
+static void sky2_shutdown(struct pci_dev *pdev)
+{
+ struct sky2_hw *hw = pci_get_drvdata(pdev);
+ int i, wol = 0;
+
+ del_timer_sync(&hw->idle_timer);
+ netif_poll_disable(hw->dev[0]);
+
+ 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);
+
+ 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);
+
+}
+
static struct pci_driver sky2_driver = {
.name = DRV_NAME,
.id_table = sky2_id_table,
@@ -3650,6 +3817,7 @@ static struct pci_driver sky2_driver = {
.suspend = sky2_suspend,
.resume = sky2_resume,
#endif
+ .shutdown = sky2_shutdown,
};
static int __init sky2_init_module(void)
diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h
index 6ed1d47dbbd..ac24bdc4297 100644
--- a/drivers/net/sky2.h
+++ b/drivers/net/sky2.h
@@ -32,6 +32,7 @@ enum pci_dev_reg_1 {
PCI_Y2_PHY1_COMA = 1<<28, /* Set PHY 1 to Coma Mode (YUKON-2) */
PCI_Y2_PHY2_POWD = 1<<27, /* Set PHY 2 to Power Down (YUKON-2) */
PCI_Y2_PHY1_POWD = 1<<26, /* Set PHY 1 to Power Down (YUKON-2) */
+ PCI_Y2_PME_LEGACY= 1<<15, /* PCI Express legacy power management mode */
};
enum pci_dev_reg_2 {
@@ -370,12 +371,9 @@ enum {
/* B2_CHIP_ID 8 bit Chip Identification Number */
enum {
- CHIP_ID_GENESIS = 0x0a, /* Chip ID for GENESIS */
- CHIP_ID_YUKON = 0xb0, /* Chip ID for YUKON */
- CHIP_ID_YUKON_LITE = 0xb1, /* Chip ID for YUKON-Lite (Rev. A1-A3) */
- CHIP_ID_YUKON_LP = 0xb2, /* Chip ID for YUKON-LP */
CHIP_ID_YUKON_XL = 0xb3, /* Chip ID for YUKON-2 XL */
CHIP_ID_YUKON_EC_U = 0xb4, /* Chip ID for YUKON-2 EC Ultra */
+ CHIP_ID_YUKON_EX = 0xb5, /* Chip ID for YUKON-2 Extreme */
CHIP_ID_YUKON_EC = 0xb6, /* Chip ID for YUKON-2 EC */
CHIP_ID_YUKON_FE = 0xb7, /* Chip ID for YUKON-2 FE */
@@ -767,6 +765,24 @@ enum {
POLL_LIST_ADDR_HI= 0x0e2c,/* 32 bit Poll. List Start Addr (high) */
};
+enum {
+ SMB_CFG = 0x0e40, /* 32 bit SMBus Config Register */
+ SMB_CSR = 0x0e44, /* 32 bit SMBus Control/Status Register */
+};
+
+enum {
+ CPU_WDOG = 0x0e48, /* 32 bit Watchdog Register */
+ CPU_CNTR = 0x0e4C, /* 32 bit Counter Register */
+ CPU_TIM = 0x0e50,/* 32 bit Timer Compare Register */
+ CPU_AHB_ADDR = 0x0e54, /* 32 bit CPU AHB Debug Register */
+ CPU_AHB_WDATA = 0x0e58, /* 32 bit CPU AHB Debug Register */
+ CPU_AHB_RDATA = 0x0e5C, /* 32 bit CPU AHB Debug Register */
+ HCU_MAP_BASE = 0x0e60, /* 32 bit Reset Mapping Base */
+ CPU_AHB_CTRL = 0x0e64, /* 32 bit CPU AHB Debug Register */
+ HCU_CCSR = 0x0e68, /* 32 bit CPU Control and Status Register */
+ HCU_HCSR = 0x0e6C, /* 32 bit Host Control and Status Register */
+};
+
/* ASF Subsystem Registers (Yukon-2 only) */
enum {
B28_Y2_SMB_CONFIG = 0x0e40,/* 32 bit ASF SMBus Config Register */
@@ -837,33 +853,27 @@ enum {
GMAC_LINK_CTRL = 0x0f10,/* 16 bit Link Control Reg */
/* Wake-up Frame Pattern Match Control Registers (YUKON only) */
-
- WOL_REG_OFFS = 0x20,/* HW-Bug: Address is + 0x20 against spec. */
-
WOL_CTRL_STAT = 0x0f20,/* 16 bit WOL Control/Status Reg */
WOL_MATCH_CTL = 0x0f22,/* 8 bit WOL Match Control Reg */
WOL_MATCH_RES = 0x0f23,/* 8 bit WOL Match Result Reg */
WOL_MAC_ADDR = 0x0f24,/* 32 bit WOL MAC Address */
- WOL_PATT_PME = 0x0f2a,/* 8 bit WOL PME Match Enable (Yukon-2) */
- WOL_PATT_ASFM = 0x0f2b,/* 8 bit WOL ASF Match Enable (Yukon-2) */
WOL_PATT_RPTR = 0x0f2c,/* 8 bit WOL Pattern Read Pointer */
/* WOL Pattern Length Registers (YUKON only) */
-
WOL_PATT_LEN_LO = 0x0f30,/* 32 bit WOL Pattern Length 3..0 */
WOL_PATT_LEN_HI = 0x0f34,/* 24 bit WOL Pattern Length 6..4 */
/* WOL Pattern Counter Registers (YUKON only) */
-
-
WOL_PATT_CNT_0 = 0x0f38,/* 32 bit WOL Pattern Counter 3..0 */
WOL_PATT_CNT_4 = 0x0f3c,/* 24 bit WOL Pattern Counter 6..4 */
};
+#define WOL_REGS(port, x) (x + (port)*0x80)
enum {
WOL_PATT_RAM_1 = 0x1000,/* WOL Pattern RAM Link 1 */
WOL_PATT_RAM_2 = 0x1400,/* WOL Pattern RAM Link 2 */
};
+#define WOL_PATT_RAM_BASE(port) (WOL_PATT_RAM_1 + (port)*0x400)
enum {
BASE_GMAC_1 = 0x2800,/* GMAC 1 registers */
@@ -1579,7 +1589,7 @@ enum {
GMR_FS_ANY_ERR = GMR_FS_RX_FF_OV | GMR_FS_CRC_ERR |
GMR_FS_FRAGMENT | GMR_FS_LONG_ERR |
- GMR_FS_MII_ERR | GMR_FS_GOOD_FC | GMR_FS_BAD_FC |
+ GMR_FS_MII_ERR | GMR_FS_BAD_FC |
GMR_FS_UN_SIZE | GMR_FS_JABBER,
};
@@ -1654,6 +1664,39 @@ enum {
Y2_ASF_CLR_ASFI = 1<<1, /* Clear host IRQ */
Y2_ASF_HOST_IRQ = 1<<0, /* Issue an IRQ to HOST system */
};
+/* HCU_CCSR CPU Control and Status Register */
+enum {
+ HCU_CCSR_SMBALERT_MONITOR= 1<<27, /* SMBALERT pin monitor */
+ HCU_CCSR_CPU_SLEEP = 1<<26, /* CPU sleep status */
+ /* Clock Stretching Timeout */
+ HCU_CCSR_CS_TO = 1<<25,
+ HCU_CCSR_WDOG = 1<<24, /* Watchdog Reset */
+
+ HCU_CCSR_CLR_IRQ_HOST = 1<<17, /* Clear IRQ_HOST */
+ HCU_CCSR_SET_IRQ_HCU = 1<<16, /* Set IRQ_HCU */
+
+ HCU_CCSR_AHB_RST = 1<<9, /* Reset AHB bridge */
+ HCU_CCSR_CPU_RST_MODE = 1<<8, /* CPU Reset Mode */
+
+ HCU_CCSR_SET_SYNC_CPU = 1<<5,
+ HCU_CCSR_CPU_CLK_DIVIDE_MSK = 3<<3,/* CPU Clock Divide */
+ HCU_CCSR_CPU_CLK_DIVIDE_BASE= 1<<3,
+ HCU_CCSR_OS_PRSNT = 1<<2, /* ASF OS Present */
+/* Microcontroller State */
+ HCU_CCSR_UC_STATE_MSK = 3,
+ HCU_CCSR_UC_STATE_BASE = 1<<0,
+ HCU_CCSR_ASF_RESET = 0,
+ HCU_CCSR_ASF_HALTED = 1<<1,
+ HCU_CCSR_ASF_RUNNING = 1<<0,
+};
+
+/* HCU_HCSR Host Control and Status Register */
+enum {
+ HCU_HCSR_SET_IRQ_CPU = 1<<16, /* Set IRQ_CPU */
+
+ HCU_HCSR_CLR_IRQ_HCU = 1<<1, /* Clear IRQ_HCU */
+ HCU_HCSR_SET_IRQ_HOST = 1<<0, /* Set IRQ_HOST */
+};
/* STAT_CTRL 32 bit Status BMU control register (Yukon-2 only) */
enum {
@@ -1715,14 +1758,17 @@ enum {
GM_IS_RX_COMPL = 1<<0, /* Frame Reception Complete */
#define GMAC_DEF_MSK GM_IS_TX_FF_UR
+};
/* GMAC_LINK_CTRL 16 bit GMAC Link Control Reg (YUKON only) */
- /* Bits 15.. 2: reserved */
+enum { /* Bits 15.. 2: reserved */
GMLC_RST_CLR = 1<<1, /* Clear GMAC Link Reset */
GMLC_RST_SET = 1<<0, /* Set GMAC Link Reset */
+};
/* WOL_CTRL_STAT 16 bit WOL Control/Status Reg */
+enum {
WOL_CTL_LINK_CHG_OCC = 1<<15,
WOL_CTL_MAGIC_PKT_OCC = 1<<14,
WOL_CTL_PATTERN_OCC = 1<<13,
@@ -1741,17 +1787,6 @@ enum {
WOL_CTL_DIS_PATTERN_UNIT = 1<<0,
};
-#define WOL_CTL_DEFAULT \
- (WOL_CTL_DIS_PME_ON_LINK_CHG | \
- WOL_CTL_DIS_PME_ON_PATTERN | \
- WOL_CTL_DIS_PME_ON_MAGIC_PKT | \
- WOL_CTL_DIS_LINK_CHG_UNIT | \
- WOL_CTL_DIS_PATTERN_UNIT | \
- WOL_CTL_DIS_MAGIC_PKT_UNIT)
-
-/* WOL_MATCH_CTL 8 bit WOL Match Control Reg */
-#define WOL_CTL_PATT_ENA(x) (1 << (x))
-
/* Control flags */
enum {
@@ -1875,6 +1910,7 @@ struct sky2_port {
u8 autoneg; /* AUTONEG_ENABLE, AUTONEG_DISABLE */
u8 duplex; /* DUPLEX_HALF, DUPLEX_FULL */
u8 rx_csum;
+ u8 wol;
enum flow_control flow_mode;
enum flow_control flow_status;
@@ -1887,7 +1923,6 @@ struct sky2_hw {
struct pci_dev *pdev;
struct net_device *dev[2];
- int pm_cap;
u8 chip_id;
u8 chip_rev;
u8 pmd_type;
@@ -1898,6 +1933,7 @@ struct sky2_hw {
dma_addr_t st_dma;
struct timer_list idle_timer;
+ struct work_struct restart_work;
int msi;
wait_queue_head_t msi_wait;
};
diff --git a/drivers/net/slip.c b/drivers/net/slip.c
index a0806d262fc..2f4b1de7a2b 100644
--- a/drivers/net/slip.c
+++ b/drivers/net/slip.c
@@ -1343,15 +1343,12 @@ static int __init slip_init(void)
printk(KERN_INFO "SLIP linefill/keepalive option.\n");
#endif
- slip_devs = kmalloc(sizeof(struct net_device *)*slip_maxdev, GFP_KERNEL);
+ slip_devs = kzalloc(sizeof(struct net_device *)*slip_maxdev, GFP_KERNEL);
if (!slip_devs) {
printk(KERN_ERR "SLIP: Can't allocate slip devices array! Uaargh! (-> No SLIP available)\n");
return -ENOMEM;
}
- /* Clear the pointer array, we allocate devices when we need them */
- memset(slip_devs, 0, sizeof(struct net_device *)*slip_maxdev);
-
/* Fill in our line protocol discipline, and register it */
if ((status = tty_register_ldisc(N_SLIP, &sl_ldisc)) != 0) {
printk(KERN_ERR "SLIP: can't register line discipline (err = %d)\n", status);
diff --git a/drivers/net/smc-mca.c b/drivers/net/smc-mca.c
index 7122932eac9..ae1ae343bee 100644
--- a/drivers/net/smc-mca.c
+++ b/drivers/net/smc-mca.c
@@ -482,8 +482,7 @@ static void ultramca_block_input(struct net_device *dev, int count, struct sk_bu
count -= semi_count;
memcpy_fromio(skb->data + semi_count, ei_status.mem + TX_PAGES * 256, count);
} else {
- /* Packet is in one chunk -- we can copy + cksum. */
- eth_io_copy_and_sum(skb, xfer_start, count, 0);
+ memcpy_fromio(skb->data, xfer_start, count);
}
}
diff --git a/drivers/net/smc-ultra.c b/drivers/net/smc-ultra.c
index d70bc979534..a52b22d7db6 100644
--- a/drivers/net/smc-ultra.c
+++ b/drivers/net/smc-ultra.c
@@ -454,8 +454,7 @@ ultra_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ri
count -= semi_count;
memcpy_fromio(skb->data + semi_count, ei_status.mem + TX_PAGES * 256, count);
} else {
- /* Packet is in one chunk -- we can copy + cksum. */
- eth_io_copy_and_sum(skb, xfer_start, count, 0);
+ memcpy_fromio(skb->data, xfer_start, count);
}
outb(0x00, dev->base_addr - ULTRA_NIC_OFFSET); /* Disable memory. */
diff --git a/drivers/net/smc-ultra32.c b/drivers/net/smc-ultra32.c
index 2c5319c62fa..88a30e56c64 100644
--- a/drivers/net/smc-ultra32.c
+++ b/drivers/net/smc-ultra32.c
@@ -395,8 +395,7 @@ static void ultra32_block_input(struct net_device *dev,
memcpy_fromio(skb->data + semi_count, ei_status.mem + TX_PAGES * 256, count);
}
} else {
- /* Packet is in one chunk -- we can copy + cksum. */
- eth_io_copy_and_sum(skb, xfer_start, count, 0);
+ memcpy_fromio(skb->data, xfer_start, count);
}
}
diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c
index 43af6143844..c9561413198 100644
--- a/drivers/net/smc911x.c
+++ b/drivers/net/smc911x.c
@@ -1659,7 +1659,7 @@ smc911x_ethtool_getdrvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
strncpy(info->driver, CARDNAME, sizeof(info->driver));
strncpy(info->version, version, sizeof(info->version));
- strncpy(info->bus_info, dev->class_dev.dev->bus_id, sizeof(info->bus_info));
+ strncpy(info->bus_info, dev->dev.parent->bus_id, sizeof(info->bus_info));
}
static int smc911x_ethtool_nwayreset(struct net_device *dev)
diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c
index e62a9586fb9..49f4b7712eb 100644
--- a/drivers/net/smc91x.c
+++ b/drivers/net/smc91x.c
@@ -1712,7 +1712,7 @@ smc_ethtool_getdrvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
strncpy(info->driver, CARDNAME, sizeof(info->driver));
strncpy(info->version, version, sizeof(info->version));
- strncpy(info->bus_info, dev->class_dev.dev->bus_id, sizeof(info->bus_info));
+ strncpy(info->bus_info, dev->dev.parent->bus_id, sizeof(info->bus_info));
}
static int smc_ethtool_nwayreset(struct net_device *dev)
diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c
index 8ea2fc1b96c..64ed8ff5b03 100644
--- a/drivers/net/spider_net.c
+++ b/drivers/net/spider_net.c
@@ -280,72 +280,67 @@ spider_net_free_chain(struct spider_net_card *card,
{
struct spider_net_descr *descr;
- for (descr = chain->tail; !descr->bus_addr; descr = descr->next) {
- pci_unmap_single(card->pdev, descr->bus_addr,
- SPIDER_NET_DESCR_SIZE, PCI_DMA_BIDIRECTIONAL);
+ descr = chain->ring;
+ do {
descr->bus_addr = 0;
- }
+ descr->next_descr_addr = 0;
+ descr = descr->next;
+ } while (descr != chain->ring);
+
+ dma_free_coherent(&card->pdev->dev, chain->num_desc,
+ chain->ring, chain->dma_addr);
}
/**
- * spider_net_init_chain - links descriptor chain
+ * spider_net_init_chain - alloc and link descriptor chain
* @card: card structure
* @chain: address of chain
- * @start_descr: address of descriptor array
- * @no: number of descriptors
*
- * we manage a circular list that mirrors the hardware structure,
+ * We manage a circular list that mirrors the hardware structure,
* except that the hardware uses bus addresses.
*
- * returns 0 on success, <0 on failure
+ * Returns 0 on success, <0 on failure
*/
static int
spider_net_init_chain(struct spider_net_card *card,
- struct spider_net_descr_chain *chain,
- struct spider_net_descr *start_descr,
- int no)
+ struct spider_net_descr_chain *chain)
{
int i;
struct spider_net_descr *descr;
dma_addr_t buf;
+ size_t alloc_size;
- descr = start_descr;
- memset(descr, 0, sizeof(*descr) * no);
+ alloc_size = chain->num_desc * sizeof (struct spider_net_descr);
- /* set up the hardware pointers in each descriptor */
- for (i=0; i<no; i++, descr++) {
- descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
+ chain->ring = dma_alloc_coherent(&card->pdev->dev, alloc_size,
+ &chain->dma_addr, GFP_KERNEL);
+
+ if (!chain->ring)
+ return -ENOMEM;
- buf = pci_map_single(card->pdev, descr,
- SPIDER_NET_DESCR_SIZE,
- PCI_DMA_BIDIRECTIONAL);
+ descr = chain->ring;
+ memset(descr, 0, alloc_size);
- if (pci_dma_mapping_error(buf))
- goto iommu_error;
+ /* Set up the hardware pointers in each descriptor */
+ buf = chain->dma_addr;
+ for (i=0; i < chain->num_desc; i++, descr++) {
+ descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
descr->bus_addr = buf;
+ descr->next_descr_addr = 0;
descr->next = descr + 1;
descr->prev = descr - 1;
+ buf += sizeof(struct spider_net_descr);
}
/* do actual circular list */
- (descr-1)->next = start_descr;
- start_descr->prev = descr-1;
+ (descr-1)->next = chain->ring;
+ chain->ring->prev = descr-1;
spin_lock_init(&chain->lock);
- chain->head = start_descr;
- chain->tail = start_descr;
-
+ chain->head = chain->ring;
+ chain->tail = chain->ring;
return 0;
-
-iommu_error:
- descr = start_descr;
- for (i=0; i < no; i++, descr++)
- if (descr->bus_addr)
- pci_unmap_single(card->pdev, descr->bus_addr,
- SPIDER_NET_DESCR_SIZE,
- PCI_DMA_BIDIRECTIONAL);
- return -ENOMEM;
}
/**
@@ -372,21 +367,20 @@ spider_net_free_rx_chain_contents(struct spider_net_card *card)
}
/**
- * spider_net_prepare_rx_descr - reinitializes a rx descriptor
+ * spider_net_prepare_rx_descr - Reinitialize RX descriptor
* @card: card structure
* @descr: descriptor to re-init
*
- * return 0 on succes, <0 on failure
+ * Return 0 on succes, <0 on failure.
*
- * allocates a new rx skb, iommu-maps it and attaches it to the descriptor.
- * Activate the descriptor state-wise
+ * Allocates a new rx skb, iommu-maps it and attaches it to the
+ * descriptor. Mark the descriptor as activated, ready-to-use.
*/
static int
spider_net_prepare_rx_descr(struct spider_net_card *card,
struct spider_net_descr *descr)
{
dma_addr_t buf;
- int error = 0;
int offset;
int bufsize;
@@ -414,7 +408,7 @@ spider_net_prepare_rx_descr(struct spider_net_card *card,
(SPIDER_NET_RXBUF_ALIGN - 1);
if (offset)
skb_reserve(descr->skb, SPIDER_NET_RXBUF_ALIGN - offset);
- /* io-mmu-map the skb */
+ /* iommu-map the skb */
buf = pci_map_single(card->pdev, descr->skb->data,
SPIDER_NET_MAX_FRAME, PCI_DMA_FROMDEVICE);
descr->buf_addr = buf;
@@ -425,11 +419,16 @@ spider_net_prepare_rx_descr(struct spider_net_card *card,
card->spider_stats.rx_iommu_map_error++;
descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
} else {
+ descr->next_descr_addr = 0;
+ wmb();
descr->dmac_cmd_status = SPIDER_NET_DESCR_CARDOWNED |
SPIDER_NET_DMAC_NOINTR_COMPLETE;
+
+ wmb();
+ descr->prev->next_descr_addr = descr->bus_addr;
}
- return error;
+ return 0;
}
/**
@@ -493,10 +492,10 @@ spider_net_refill_rx_chain(struct spider_net_card *card)
}
/**
- * spider_net_alloc_rx_skbs - allocates rx skbs in rx descriptor chains
+ * spider_net_alloc_rx_skbs - Allocates rx skbs in rx descriptor chains
* @card: card structure
*
- * returns 0 on success, <0 on failure
+ * Returns 0 on success, <0 on failure.
*/
static int
spider_net_alloc_rx_skbs(struct spider_net_card *card)
@@ -507,16 +506,16 @@ spider_net_alloc_rx_skbs(struct spider_net_card *card)
result = -ENOMEM;
chain = &card->rx_chain;
- /* put at least one buffer into the chain. if this fails,
- * we've got a problem. if not, spider_net_refill_rx_chain
- * will do the rest at the end of this function */
+ /* Put at least one buffer into the chain. if this fails,
+ * we've got a problem. If not, spider_net_refill_rx_chain
+ * will do the rest at the end of this function. */
if (spider_net_prepare_rx_descr(card, chain->head))
goto error;
else
chain->head = chain->head->next;
- /* this will allocate the rest of the rx buffers; if not, it's
- * business as usual later on */
+ /* This will allocate the rest of the rx buffers;
+ * if not, it's business as usual later on. */
spider_net_refill_rx_chain(card);
spider_net_enable_rxdmac(card);
return 0;
@@ -707,7 +706,7 @@ spider_net_set_low_watermark(struct spider_net_card *card)
}
/* If TX queue is short, don't even bother with interrupts */
- if (cnt < card->num_tx_desc/4)
+ if (cnt < card->tx_chain.num_desc/4)
return cnt;
/* Set low-watermark 3/4th's of the way into the queue. */
@@ -915,16 +914,13 @@ spider_net_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
* spider_net_pass_skb_up - takes an skb from a descriptor and passes it on
* @descr: descriptor to process
* @card: card structure
- * @napi: whether caller is in NAPI context
- *
- * returns 1 on success, 0 if no packet was passed to the stack
*
- * iommu-unmaps the skb, fills out skb structure and passes the data to the
- * stack. The descriptor state is not changed.
+ * Fills out skb structure and passes the data to the stack.
+ * The descriptor state is not changed.
*/
-static int
+static void
spider_net_pass_skb_up(struct spider_net_descr *descr,
- struct spider_net_card *card, int napi)
+ struct spider_net_card *card)
{
struct sk_buff *skb;
struct net_device *netdev;
@@ -932,23 +928,8 @@ spider_net_pass_skb_up(struct spider_net_descr *descr,
data_status = descr->data_status;
data_error = descr->data_error;
-
netdev = card->netdev;
- /* unmap descriptor */
- pci_unmap_single(card->pdev, descr->buf_addr, SPIDER_NET_MAX_FRAME,
- PCI_DMA_FROMDEVICE);
-
- /* the cases we'll throw away the packet immediately */
- if (data_error & SPIDER_NET_DESTROY_RX_FLAGS) {
- if (netif_msg_rx_err(card))
- pr_err("error in received descriptor found, "
- "data_status=x%08x, data_error=x%08x\n",
- data_status, data_error);
- card->spider_stats.rx_desc_error++;
- return 0;
- }
-
skb = descr->skb;
skb->dev = netdev;
skb_put(skb, descr->valid_size);
@@ -977,57 +958,72 @@ spider_net_pass_skb_up(struct spider_net_descr *descr,
}
/* pass skb up to stack */
- if (napi)
- netif_receive_skb(skb);
- else
- netif_rx_ni(skb);
+ netif_receive_skb(skb);
/* update netdevice statistics */
card->netdev_stats.rx_packets++;
card->netdev_stats.rx_bytes += skb->len;
+}
- return 1;
+#ifdef DEBUG
+static void show_rx_chain(struct spider_net_card *card)
+{
+ struct spider_net_descr_chain *chain = &card->rx_chain;
+ struct spider_net_descr *start= chain->tail;
+ struct spider_net_descr *descr= start;
+ int status;
+
+ int cnt = 0;
+ int cstat = spider_net_get_descr_status(descr);
+ printk(KERN_INFO "RX chain tail at descr=%ld\n",
+ (start - card->descr) - card->tx_chain.num_desc);
+ status = cstat;
+ do
+ {
+ status = spider_net_get_descr_status(descr);
+ if (cstat != status) {
+ printk(KERN_INFO "Have %d descrs with stat=x%08x\n", cnt, cstat);
+ cstat = status;
+ cnt = 0;
+ }
+ cnt ++;
+ descr = descr->next;
+ } while (descr != start);
+ printk(KERN_INFO "Last %d descrs with stat=x%08x\n", cnt, cstat);
}
+#endif
/**
* spider_net_decode_one_descr - processes an rx descriptor
* @card: card structure
- * @napi: whether caller is in NAPI context
*
- * returns 1 if a packet has been sent to the stack, otherwise 0
+ * Returns 1 if a packet has been sent to the stack, otherwise 0
*
- * processes an rx descriptor by iommu-unmapping the data buffer and passing
+ * Processes an rx descriptor by iommu-unmapping the data buffer and passing
* the packet up to the stack. This function is called in softirq
* context, e.g. either bottom half from interrupt or NAPI polling context
*/
static int
-spider_net_decode_one_descr(struct spider_net_card *card, int napi)
+spider_net_decode_one_descr(struct spider_net_card *card)
{
struct spider_net_descr_chain *chain = &card->rx_chain;
struct spider_net_descr *descr = chain->tail;
int status;
- int result;
status = spider_net_get_descr_status(descr);
- if (status == SPIDER_NET_DESCR_CARDOWNED) {
- /* nothing in the descriptor yet */
- result=0;
- goto out;
- }
-
- if (status == SPIDER_NET_DESCR_NOT_IN_USE) {
- /* not initialized yet, the ring must be empty */
- spider_net_refill_rx_chain(card);
- spider_net_enable_rxdmac(card);
- result=0;
- goto out;
- }
+ /* Nothing in the descriptor, or ring must be empty */
+ if ((status == SPIDER_NET_DESCR_CARDOWNED) ||
+ (status == SPIDER_NET_DESCR_NOT_IN_USE))
+ return 0;
/* descriptor definitively used -- move on tail */
chain->tail = descr->next;
- result = 0;
+ /* unmap descriptor */
+ pci_unmap_single(card->pdev, descr->buf_addr,
+ SPIDER_NET_MAX_FRAME, PCI_DMA_FROMDEVICE);
+
if ( (status == SPIDER_NET_DESCR_RESPONSE_ERROR) ||
(status == SPIDER_NET_DESCR_PROTECTION_ERROR) ||
(status == SPIDER_NET_DESCR_FORCE_END) ) {
@@ -1035,31 +1031,55 @@ spider_net_decode_one_descr(struct spider_net_card *card, int napi)
pr_err("%s: dropping RX descriptor with state %d\n",
card->netdev->name, status);
card->netdev_stats.rx_dropped++;
- pci_unmap_single(card->pdev, descr->buf_addr,
- SPIDER_NET_MAX_FRAME, PCI_DMA_FROMDEVICE);
- dev_kfree_skb_irq(descr->skb);
- goto refill;
+ goto bad_desc;
}
if ( (status != SPIDER_NET_DESCR_COMPLETE) &&
(status != SPIDER_NET_DESCR_FRAME_END) ) {
- if (netif_msg_rx_err(card)) {
- pr_err("%s: RX descriptor with state %d\n",
+ if (netif_msg_rx_err(card))
+ pr_err("%s: RX descriptor with unkown state %d\n",
card->netdev->name, status);
- card->spider_stats.rx_desc_unk_state++;
- }
- goto refill;
+ card->spider_stats.rx_desc_unk_state++;
+ goto bad_desc;
}
- /* ok, we've got a packet in descr */
- result = spider_net_pass_skb_up(descr, card, napi);
-refill:
+ /* The cases we'll throw away the packet immediately */
+ if (descr->data_error & SPIDER_NET_DESTROY_RX_FLAGS) {
+ if (netif_msg_rx_err(card))
+ pr_err("%s: error in received descriptor found, "
+ "data_status=x%08x, data_error=x%08x\n",
+ card->netdev->name,
+ descr->data_status, descr->data_error);
+ goto bad_desc;
+ }
+
+ if (descr->dmac_cmd_status & 0xfefe) {
+ pr_err("%s: bad status, cmd_status=x%08x\n",
+ card->netdev->name,
+ descr->dmac_cmd_status);
+ pr_err("buf_addr=x%08x\n", descr->buf_addr);
+ pr_err("buf_size=x%08x\n", descr->buf_size);
+ pr_err("next_descr_addr=x%08x\n", descr->next_descr_addr);
+ pr_err("result_size=x%08x\n", descr->result_size);
+ pr_err("valid_size=x%08x\n", descr->valid_size);
+ pr_err("data_status=x%08x\n", descr->data_status);
+ pr_err("data_error=x%08x\n", descr->data_error);
+ pr_err("bus_addr=x%08x\n", descr->bus_addr);
+ pr_err("which=%ld\n", descr - card->rx_chain.ring);
+
+ card->spider_stats.rx_desc_error++;
+ goto bad_desc;
+ }
+
+ /* Ok, we've got a packet in descr */
+ spider_net_pass_skb_up(descr, card);
descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
- /* change the descriptor state: */
- if (!napi)
- spider_net_refill_rx_chain(card);
-out:
- return result;
+ return 1;
+
+bad_desc:
+ dev_kfree_skb_irq(descr->skb);
+ descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
+ return 0;
}
/**
@@ -1085,7 +1105,7 @@ spider_net_poll(struct net_device *netdev, int *budget)
packets_to_do = min(*budget, netdev->quota);
while (packets_to_do) {
- if (spider_net_decode_one_descr(card, 1)) {
+ if (spider_net_decode_one_descr(card)) {
packets_done++;
packets_to_do--;
} else {
@@ -1098,6 +1118,7 @@ spider_net_poll(struct net_device *netdev, int *budget)
netdev->quota -= packets_done;
*budget -= packets_done;
spider_net_refill_rx_chain(card);
+ spider_net_enable_rxdmac(card);
/* if all packets are in the stack, enable interrupts and return 0 */
/* if not, return 1 */
@@ -1227,24 +1248,6 @@ spider_net_set_mac(struct net_device *netdev, void *p)
}
/**
- * spider_net_handle_rxram_full - cleans up RX ring upon RX RAM full interrupt
- * @card: card structure
- *
- * spider_net_handle_rxram_full empties the RX ring so that spider can put
- * more packets in it and empty its RX RAM. This is called in bottom half
- * context
- */
-static void
-spider_net_handle_rxram_full(struct spider_net_card *card)
-{
- while (spider_net_decode_one_descr(card, 0))
- ;
- spider_net_enable_rxchtails(card);
- spider_net_enable_rxdmac(card);
- netif_rx_schedule(card->netdev);
-}
-
-/**
* spider_net_handle_error_irq - handles errors raised by an interrupt
* @card: card structure
* @status_reg: interrupt status register 0 (GHIINT0STS)
@@ -1366,10 +1369,10 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg)
case SPIDER_NET_GRFAFLLINT: /* fallthrough */
case SPIDER_NET_GRMFLLINT:
if (netif_msg_intr(card) && net_ratelimit())
- pr_debug("Spider RX RAM full, incoming packets "
+ pr_err("Spider RX RAM full, incoming packets "
"might be discarded!\n");
spider_net_rx_irq_off(card);
- tasklet_schedule(&card->rxram_full_tl);
+ netif_rx_schedule(card->netdev);
show_error = 0;
break;
@@ -1384,7 +1387,7 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg)
case SPIDER_NET_GDCDCEINT: /* fallthrough */
case SPIDER_NET_GDBDCEINT: /* fallthrough */
case SPIDER_NET_GDADCEINT:
- if (netif_msg_intr(card))
+ if (netif_msg_intr(card) && net_ratelimit())
pr_err("got descriptor chain end interrupt, "
"restarting DMAC %c.\n",
'D'-(i-SPIDER_NET_GDDDCEINT)/3);
@@ -1455,7 +1458,7 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg)
break;
}
- if ((show_error) && (netif_msg_intr(card)))
+ if ((show_error) && (netif_msg_intr(card)) && net_ratelimit())
pr_err("Got error interrupt on %s, GHIINT0STS = 0x%08x, "
"GHIINT1STS = 0x%08x, GHIINT2STS = 0x%08x\n",
card->netdev->name,
@@ -1651,27 +1654,18 @@ int
spider_net_open(struct net_device *netdev)
{
struct spider_net_card *card = netdev_priv(netdev);
- struct spider_net_descr *descr;
- int i, result;
+ int result;
- result = -ENOMEM;
- if (spider_net_init_chain(card, &card->tx_chain, card->descr,
- card->num_tx_desc))
+ result = spider_net_init_chain(card, &card->tx_chain);
+ if (result)
goto alloc_tx_failed;
-
card->low_watermark = NULL;
- /* rx_chain is after tx_chain, so offset is descr + tx_count */
- if (spider_net_init_chain(card, &card->rx_chain,
- card->descr + card->num_tx_desc,
- card->num_rx_desc))
+ result = spider_net_init_chain(card, &card->rx_chain);
+ if (result)
goto alloc_rx_failed;
- descr = card->rx_chain.head;
- for (i=0; i < card->num_rx_desc; i++, descr++)
- descr->next_descr_addr = descr->next->bus_addr;
-
- /* allocate rx skbs */
+ /* Allocate rx skbs */
if (spider_net_alloc_rx_skbs(card))
goto alloc_skbs_failed;
@@ -1902,7 +1896,6 @@ spider_net_stop(struct net_device *netdev)
{
struct spider_net_card *card = netdev_priv(netdev);
- tasklet_kill(&card->rxram_full_tl);
netif_poll_disable(netdev);
netif_carrier_off(netdev);
netif_stop_queue(netdev);
@@ -1914,7 +1907,7 @@ spider_net_stop(struct net_device *netdev)
spider_net_write_reg(card, SPIDER_NET_GHIINT2MSK, 0);
/* free_irq(netdev->irq, netdev);*/
- free_irq(to_pci_dev(netdev->class_dev.dev)->irq, netdev);
+ free_irq(to_pci_dev(netdev->dev.parent)->irq, netdev);
spider_net_write_reg(card, SPIDER_NET_GDTDMACCNTR,
SPIDER_NET_DMA_TX_FEND_VALUE);
@@ -1924,6 +1917,7 @@ spider_net_stop(struct net_device *netdev)
/* release chains */
spider_net_release_tx_chain(card, 1);
+ spider_net_free_rx_chain_contents(card);
spider_net_free_rx_chain_contents(card);
@@ -2046,9 +2040,6 @@ spider_net_setup_netdev(struct spider_net_card *card)
pci_set_drvdata(card->pdev, netdev);
- card->rxram_full_tl.data = (unsigned long) card;
- card->rxram_full_tl.func =
- (void (*)(unsigned long)) spider_net_handle_rxram_full;
init_timer(&card->tx_timer);
card->tx_timer.function =
(void (*)(unsigned long)) spider_net_cleanup_tx_ring;
@@ -2057,8 +2048,8 @@ spider_net_setup_netdev(struct spider_net_card *card)
card->options.rx_csum = SPIDER_NET_RX_CSUM_DEFAULT;
- card->num_tx_desc = tx_descriptors;
- card->num_rx_desc = rx_descriptors;
+ card->tx_chain.num_desc = tx_descriptors;
+ card->rx_chain.num_desc = rx_descriptors;
spider_net_setup_netdev_ops(netdev);
@@ -2107,12 +2098,8 @@ spider_net_alloc_card(void)
{
struct net_device *netdev;
struct spider_net_card *card;
- size_t alloc_size;
- alloc_size = sizeof (*card) +
- sizeof (struct spider_net_descr) * rx_descriptors +
- sizeof (struct spider_net_descr) * tx_descriptors;
- netdev = alloc_etherdev(alloc_size);
+ netdev = alloc_etherdev(sizeof(struct spider_net_card));
if (!netdev)
return NULL;
diff --git a/drivers/net/spider_net.h b/drivers/net/spider_net.h
index 3e196df2979..2fec5cf7692 100644
--- a/drivers/net/spider_net.h
+++ b/drivers/net/spider_net.h
@@ -24,7 +24,7 @@
#ifndef _SPIDER_NET_H
#define _SPIDER_NET_H
-#define VERSION "1.6 A"
+#define VERSION "1.6 B"
#include "sungem_phy.h"
@@ -378,6 +378,9 @@ struct spider_net_descr_chain {
spinlock_t lock;
struct spider_net_descr *head;
struct spider_net_descr *tail;
+ struct spider_net_descr *ring;
+ int num_desc;
+ dma_addr_t dma_addr;
};
/* descriptor data_status bits */
@@ -397,8 +400,6 @@ struct spider_net_descr_chain {
* 701b8000 would be correct, but every packets gets that flag */
#define SPIDER_NET_DESTROY_RX_FLAGS 0x700b8000
-#define SPIDER_NET_DESCR_SIZE 32
-
/* this will be bigger some time */
struct spider_net_options {
int rx_csum; /* for rx: if 0 ip_summed=NONE,
@@ -441,25 +442,16 @@ struct spider_net_card {
struct spider_net_descr_chain rx_chain;
struct spider_net_descr *low_watermark;
- struct net_device_stats netdev_stats;
-
- struct spider_net_options options;
-
- spinlock_t intmask_lock;
- struct tasklet_struct rxram_full_tl;
struct timer_list tx_timer;
-
struct work_struct tx_timeout_task;
atomic_t tx_timeout_task_counter;
wait_queue_head_t waitq;
/* for ethtool */
int msg_enable;
- int num_rx_desc;
- int num_tx_desc;
+ struct net_device_stats netdev_stats;
struct spider_net_extra_stats spider_stats;
-
- struct spider_net_descr descr[0];
+ struct spider_net_options options;
};
#define pr_err(fmt,arg...) \
diff --git a/drivers/net/spider_net_ethtool.c b/drivers/net/spider_net_ethtool.c
index 91b99510291..6bcf03fc89b 100644
--- a/drivers/net/spider_net_ethtool.c
+++ b/drivers/net/spider_net_ethtool.c
@@ -158,9 +158,9 @@ spider_net_ethtool_get_ringparam(struct net_device *netdev,
struct spider_net_card *card = netdev->priv;
ering->tx_max_pending = SPIDER_NET_TX_DESCRIPTORS_MAX;
- ering->tx_pending = card->num_tx_desc;
+ ering->tx_pending = card->tx_chain.num_desc;
ering->rx_max_pending = SPIDER_NET_RX_DESCRIPTORS_MAX;
- ering->rx_pending = card->num_rx_desc;
+ ering->rx_pending = card->rx_chain.num_desc;
}
static int spider_net_get_stats_count(struct net_device *netdev)
diff --git a/drivers/net/sungem_phy.c b/drivers/net/sungem_phy.c
index d21991ee88c..701ba4f3b69 100644
--- a/drivers/net/sungem_phy.c
+++ b/drivers/net/sungem_phy.c
@@ -22,7 +22,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/types.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index f4bf62c2a7a..26c6ac48288 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -4,7 +4,7 @@
* Copyright (C) 2001, 2002, 2003, 2004 David S. Miller (davem@redhat.com)
* Copyright (C) 2001, 2002, 2003 Jeff Garzik (jgarzik@pobox.com)
* Copyright (C) 2004 Sun Microsystems Inc.
- * Copyright (C) 2005 Broadcom Corporation.
+ * Copyright (C) 2005-2007 Broadcom Corporation.
*
* Firmware is:
* Derived from proprietary unpublished source code,
@@ -58,18 +58,14 @@
#define TG3_VLAN_TAG_USED 0
#endif
-#ifdef NETIF_F_TSO
#define TG3_TSO_SUPPORT 1
-#else
-#define TG3_TSO_SUPPORT 0
-#endif
#include "tg3.h"
#define DRV_MODULE_NAME "tg3"
#define PFX DRV_MODULE_NAME ": "
-#define DRV_MODULE_VERSION "3.72"
-#define DRV_MODULE_RELDATE "January 8, 2007"
+#define DRV_MODULE_VERSION "3.74"
+#define DRV_MODULE_RELDATE "February 20, 2007"
#define TG3_DEF_MAC_MODE 0
#define TG3_DEF_RX_MODE 0
@@ -1179,8 +1175,18 @@ static void tg3_nvram_unlock(struct tg3 *);
static void tg3_power_down_phy(struct tg3 *tp)
{
- if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)
+ if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) {
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) {
+ u32 sg_dig_ctrl = tr32(SG_DIG_CTRL);
+ u32 serdes_cfg = tr32(MAC_SERDES_CFG);
+
+ sg_dig_ctrl |=
+ SG_DIG_USING_HW_AUTONEG | SG_DIG_SOFT_RESET;
+ tw32(SG_DIG_CTRL, sg_dig_ctrl);
+ tw32(MAC_SERDES_CFG, serdes_cfg | (1 << 15));
+ }
return;
+ }
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
u32 val;
@@ -1344,7 +1350,8 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state)
tw32_wait_f(TG3PCI_CLOCK_CTRL, base_val | CLOCK_CTRL_ALTCLK |
CLOCK_CTRL_PWRDOWN_PLL133, 40);
- } else if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) {
+ } else if ((tp->tg3_flags2 & TG3_FLG2_5780_CLASS) ||
+ (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)) {
/* do nothing */
} else if (!((tp->tg3_flags2 & TG3_FLG2_5750_PLUS) &&
(tp->tg3_flags & TG3_FLAG_ENABLE_ASF))) {
@@ -3384,7 +3391,7 @@ next_pkt:
}
next_pkt_nopost:
sw_idx++;
- sw_idx %= TG3_RX_RCB_RING_SIZE(tp);
+ sw_idx &= (TG3_RX_RCB_RING_SIZE(tp) - 1);
/* Refresh hw_idx to see if there is new work */
if (sw_idx == hw_idx) {
@@ -3728,13 +3735,23 @@ out:
tg3_full_unlock(tp);
}
+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));
+}
+
static void tg3_tx_timeout(struct net_device *dev)
{
struct tg3 *tp = netdev_priv(dev);
- if (netif_msg_tx_err(tp))
+ if (netif_msg_tx_err(tp)) {
printk(KERN_ERR PFX "%s: transmit timed out, resetting\n",
dev->name);
+ tg3_dump_short_state(tp);
+ }
schedule_work(&tp->reset_task);
}
@@ -3873,7 +3890,6 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
entry = tp->tx_prod;
base_flags = 0;
-#if TG3_TSO_SUPPORT != 0
mss = 0;
if (skb->len > (tp->dev->mtu + ETH_HLEN) &&
(mss = skb_shinfo(skb)->gso_size) != 0) {
@@ -3906,11 +3922,6 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
else if (skb->ip_summed == CHECKSUM_PARTIAL)
base_flags |= TXD_FLAG_TCPUDP_CSUM;
-#else
- mss = 0;
- if (skb->ip_summed == CHECKSUM_PARTIAL)
- base_flags |= TXD_FLAG_TCPUDP_CSUM;
-#endif
#if TG3_VLAN_TAG_USED
if (tp->vlgrp != NULL && vlan_tx_tag_present(skb))
base_flags |= (TXD_FLAG_VLAN |
@@ -3970,7 +3981,6 @@ out_unlock:
return NETDEV_TX_OK;
}
-#if TG3_TSO_SUPPORT != 0
static int tg3_start_xmit_dma_bug(struct sk_buff *, struct net_device *);
/* Use GSO to workaround a rare TSO bug that may be triggered when the
@@ -3983,7 +3993,10 @@ static int tg3_tso_bug(struct tg3 *tp, struct sk_buff *skb)
/* Estimate the number of fragments in the worst case */
if (unlikely(tg3_tx_avail(tp) <= (skb_shinfo(skb)->gso_segs * 3))) {
netif_stop_queue(tp->dev);
- return NETDEV_TX_BUSY;
+ if (tg3_tx_avail(tp) <= (skb_shinfo(skb)->gso_segs * 3))
+ return NETDEV_TX_BUSY;
+
+ netif_wake_queue(tp->dev);
}
segs = skb_gso_segment(skb, tp->dev->features & ~NETIF_F_TSO);
@@ -4002,7 +4015,6 @@ tg3_tso_bug_end:
return NETDEV_TX_OK;
}
-#endif
/* hard_start_xmit for devices that have the 4G bug and/or 40-bit bug and
* support TG3_FLG2_HW_TSO_1 or firmware TSO only.
@@ -4036,7 +4048,6 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev)
base_flags = 0;
if (skb->ip_summed == CHECKSUM_PARTIAL)
base_flags |= TXD_FLAG_TCPUDP_CSUM;
-#if TG3_TSO_SUPPORT != 0
mss = 0;
if (skb->len > (tp->dev->mtu + ETH_HLEN) &&
(mss = skb_shinfo(skb)->gso_size) != 0) {
@@ -4053,7 +4064,7 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev)
hdr_len = ip_tcp_len + tcp_opt_len;
if (unlikely((ETH_HLEN + hdr_len) > 80) &&
- (tp->tg3_flags2 & TG3_FLG2_HW_TSO_1_BUG))
+ (tp->tg3_flags2 & TG3_FLG2_TSO_BUG))
return (tg3_tso_bug(tp, skb));
base_flags |= (TXD_FLAG_CPU_PRE_DMA |
@@ -4091,9 +4102,6 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev)
}
}
}
-#else
- mss = 0;
-#endif
#if TG3_VLAN_TAG_USED
if (tp->vlgrp != NULL && vlan_tx_tag_present(skb))
base_flags |= (TXD_FLAG_VLAN |
@@ -5329,7 +5337,6 @@ static int tg3_load_5701_a0_firmware_fix(struct tg3 *tp)
return 0;
}
-#if TG3_TSO_SUPPORT != 0
#define TG3_TSO_FW_RELEASE_MAJOR 0x1
#define TG3_TSO_FW_RELASE_MINOR 0x6
@@ -5906,7 +5913,6 @@ static int tg3_load_tso_firmware(struct tg3 *tp)
return 0;
}
-#endif /* TG3_TSO_SUPPORT != 0 */
/* tp->lock is held. */
static void __tg3_set_mac_addr(struct tg3 *tp)
@@ -6120,7 +6126,6 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tw32(BUFMGR_DMA_DESC_POOL_ADDR, NIC_SRAM_DMA_DESC_POOL_BASE);
tw32(BUFMGR_DMA_DESC_POOL_SIZE, NIC_SRAM_DMA_DESC_POOL_SIZE);
}
-#if TG3_TSO_SUPPORT != 0
else if (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) {
int fw_len;
@@ -6135,7 +6140,6 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tw32(BUFMGR_MB_POOL_SIZE,
NIC_SRAM_MBUF_POOL_SIZE5705 - fw_len - 0xa00);
}
-#endif
if (tp->dev->mtu <= ETH_DATA_LEN) {
tw32(BUFMGR_MB_RDMA_LOW_WATER,
@@ -6337,10 +6341,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS)
rdmac_mode |= RDMAC_MODE_FIFO_LONG_BURST;
-#if TG3_TSO_SUPPORT != 0
if (tp->tg3_flags2 & TG3_FLG2_HW_TSO)
rdmac_mode |= (1 << 27);
-#endif
/* Receive/send statistics. */
if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) {
@@ -6511,10 +6513,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tw32(RCVBDI_MODE, RCVBDI_MODE_ENABLE | RCVBDI_MODE_RCB_ATTN_ENAB);
tw32(RCVDBDI_MODE, RCVDBDI_MODE_ENABLE | RCVDBDI_MODE_INV_RING_SZ);
tw32(SNDDATAI_MODE, SNDDATAI_MODE_ENABLE);
-#if TG3_TSO_SUPPORT != 0
if (tp->tg3_flags2 & TG3_FLG2_HW_TSO)
tw32(SNDDATAI_MODE, SNDDATAI_MODE_ENABLE | 0x8);
-#endif
tw32(SNDBDI_MODE, SNDBDI_MODE_ENABLE | SNDBDI_MODE_ATTN_ENABLE);
tw32(SNDBDS_MODE, SNDBDS_MODE_ENABLE | SNDBDS_MODE_ATTN_ENABLE);
@@ -6524,13 +6524,11 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
return err;
}
-#if TG3_TSO_SUPPORT != 0
if (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) {
err = tg3_load_tso_firmware(tp);
if (err)
return err;
}
-#endif
tp->tx_mode = TX_MODE_ENABLE;
tw32_f(MAC_TX_MODE, tp->tx_mode);
@@ -6609,8 +6607,9 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
u32 tmp;
/* Clear CRC stats. */
- if (!tg3_readphy(tp, 0x1e, &tmp)) {
- tg3_writephy(tp, 0x1e, tmp | 0x8000);
+ if (!tg3_readphy(tp, MII_TG3_TEST1, &tmp)) {
+ tg3_writephy(tp, MII_TG3_TEST1,
+ tmp | MII_TG3_TEST1_CRC_EN);
tg3_readphy(tp, 0x14, &tmp);
}
}
@@ -7434,8 +7433,9 @@ static unsigned long calc_crc_errors(struct tg3 *tp)
u32 val;
spin_lock_bh(&tp->lock);
- if (!tg3_readphy(tp, 0x1e, &val)) {
- tg3_writephy(tp, 0x1e, val | 0x8000);
+ if (!tg3_readphy(tp, MII_TG3_TEST1, &val)) {
+ tg3_writephy(tp, MII_TG3_TEST1,
+ val | MII_TG3_TEST1_CRC_EN);
tg3_readphy(tp, 0x14, &val);
} else
val = 0;
@@ -8062,7 +8062,6 @@ static void tg3_set_msglevel(struct net_device *dev, u32 value)
tp->msg_enable = value;
}
-#if TG3_TSO_SUPPORT != 0
static int tg3_set_tso(struct net_device *dev, u32 value)
{
struct tg3 *tp = netdev_priv(dev);
@@ -8081,7 +8080,6 @@ static int tg3_set_tso(struct net_device *dev, u32 value)
}
return ethtool_op_set_tso(dev, value);
}
-#endif
static int tg3_nway_reset(struct net_device *dev)
{
@@ -8142,7 +8140,7 @@ static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *e
(ering->rx_jumbo_pending > TG3_RX_JUMBO_RING_SIZE - 1) ||
(ering->tx_pending > TG3_TX_RING_SIZE - 1) ||
(ering->tx_pending <= MAX_SKB_FRAGS) ||
- ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_1_BUG) &&
+ ((tp->tg3_flags2 & TG3_FLG2_TSO_BUG) &&
(ering->tx_pending <= (MAX_SKB_FRAGS * 3))))
return -EINVAL;
@@ -9212,10 +9210,8 @@ static const struct ethtool_ops tg3_ethtool_ops = {
.set_tx_csum = tg3_set_tx_csum,
.get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
-#if TG3_TSO_SUPPORT != 0
.get_tso = ethtool_op_get_tso,
.set_tso = tg3_set_tso,
-#endif
.self_test_count = tg3_get_test_count,
.self_test = tg3_self_test,
.get_strings = tg3_get_strings,
@@ -10564,12 +10560,11 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
tp->tg3_flags2 |= TG3_FLG2_HW_TSO_2;
tp->tg3_flags2 |= TG3_FLG2_1SHOT_MSI;
} else {
- tp->tg3_flags2 |= TG3_FLG2_HW_TSO_1 |
- TG3_FLG2_HW_TSO_1_BUG;
+ tp->tg3_flags2 |= TG3_FLG2_HW_TSO_1 | TG3_FLG2_TSO_BUG;
if (GET_ASIC_REV(tp->pci_chip_rev_id) ==
ASIC_REV_5750 &&
tp->pci_chip_rev_id >= CHIPREV_ID_5750_C2)
- tp->tg3_flags2 &= ~TG3_FLG2_HW_TSO_1_BUG;
+ tp->tg3_flags2 &= ~TG3_FLG2_TSO_BUG;
}
}
@@ -10809,7 +10804,9 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) {
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) {
- tp->tg3_flags2 |= TG3_FLG2_PHY_JITTER_BUG;
+ if (tp->pdev->device != PCI_DEVICE_ID_TIGON3_5756 &&
+ tp->pdev->device != PCI_DEVICE_ID_TIGON3_5722)
+ tp->tg3_flags2 |= TG3_FLG2_PHY_JITTER_BUG;
if (tp->pdev->device == PCI_DEVICE_ID_TIGON3_5755M)
tp->tg3_flags2 |= TG3_FLG2_PHY_ADJUST_TRIM;
} else if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906)
@@ -11344,6 +11341,7 @@ static int __devinit tg3_test_dma(struct tg3 *tp)
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) {
u32 ccval = (tr32(TG3PCI_CLOCK_CTRL) & 0x1f);
+ u32 read_water = 0x7;
/* If the 5704 is behind the EPB bridge, we can
* do the less restrictive ONE_DMA workaround for
@@ -11355,8 +11353,13 @@ static int __devinit tg3_test_dma(struct tg3 *tp)
else if (ccval == 0x6 || ccval == 0x7)
tp->dma_rwctrl |= DMA_RWCTRL_ONE_DMA;
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703)
+ read_water = 4;
/* Set bit 23 to enable PCIX hw bug fix */
- tp->dma_rwctrl |= 0x009f0000;
+ tp->dma_rwctrl |=
+ (read_water << DMA_RWCTRL_READ_WATER_SHIFT) |
+ (0x3 << DMA_RWCTRL_WRITE_WATER_SHIFT) |
+ (1 << 23);
} else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780) {
/* 5780 always in PCIX mode */
tp->dma_rwctrl |= 0x00144000;
@@ -11856,7 +11859,6 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
tg3_init_bufmgr_config(tp);
-#if TG3_TSO_SUPPORT != 0
if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) {
tp->tg3_flags2 |= TG3_FLG2_TSO_CAPABLE;
}
@@ -11867,7 +11869,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
(tp->tg3_flags & TG3_FLAG_ENABLE_ASF) != 0) {
tp->tg3_flags2 &= ~TG3_FLG2_TSO_CAPABLE;
} else {
- tp->tg3_flags2 |= TG3_FLG2_TSO_CAPABLE;
+ tp->tg3_flags2 |= TG3_FLG2_TSO_CAPABLE | TG3_FLG2_TSO_BUG;
}
/* TSO is on by default on chips that support hardware TSO.
@@ -11881,7 +11883,6 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
dev->features |= NETIF_F_TSO6;
}
-#endif
if (tp->pci_chip_rev_id == CHIPREV_ID_5705_A1 &&
!(tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) &&
@@ -12048,6 +12049,9 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state)
tp->tg3_flags &= ~TG3_FLAG_INIT_COMPLETE;
tg3_full_unlock(tp);
+ /* Save MSI address and data for resume. */
+ pci_save_state(pdev);
+
err = tg3_set_power_state(tp, pci_choose_state(pdev, state));
if (err) {
tg3_full_lock(tp, 0);
diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h
index 80f59ac7ec5..086892d8c1f 100644
--- a/drivers/net/tg3.h
+++ b/drivers/net/tg3.h
@@ -1660,6 +1660,7 @@
#define MII_TG3_TEST1 0x1e
#define MII_TG3_TEST1_TRIM_EN 0x0010
+#define MII_TG3_TEST1_CRC_EN 0x8000
/* There are two ways to manage the TX descriptors on the tigon3.
* Either the descriptors are in host DMA'able memory, or they
@@ -2226,7 +2227,7 @@ struct tg3 {
#define TG3_FLAG_INIT_COMPLETE 0x80000000
u32 tg3_flags2;
#define TG3_FLG2_RESTART_TIMER 0x00000001
-#define TG3_FLG2_HW_TSO_1_BUG 0x00000002
+#define TG3_FLG2_TSO_BUG 0x00000002
#define TG3_FLG2_NO_ETH_WIRE_SPEED 0x00000004
#define TG3_FLG2_IS_5788 0x00000008
#define TG3_FLG2_MAX_RXPEND_64 0x00000010
diff --git a/drivers/net/tsi108_eth.c b/drivers/net/tsi108_eth.c
index 893808ab374..d92c5c597e1 100644
--- a/drivers/net/tsi108_eth.c
+++ b/drivers/net/tsi108_eth.c
@@ -38,7 +38,6 @@
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/slab.h>
-#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/delay.h>
#include <linux/crc32.h>
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 151a2e10e4f..5643d1e84ed 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -744,7 +744,7 @@ static int tun_chr_close(struct inode *inode, struct file *file)
return 0;
}
-static struct file_operations tun_fops = {
+static const struct file_operations tun_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = do_sync_read,
diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c
index 7e4b23c7c1b..a2fc2bbcf97 100644
--- a/drivers/net/ucc_geth.c
+++ b/drivers/net/ucc_geth.c
@@ -1709,75 +1709,13 @@ static void adjust_link(struct net_device *dev)
if (mii_info->speed != ugeth->oldspeed) {
switch (mii_info->speed) {
case 1000:
-#ifdef CONFIG_PPC_MPC836x
-/* FIXME: This code is for 100Mbs BUG fixing,
-remove this when it is fixed!!! */
- if (ugeth->ug_info->enet_interface ==
- ENET_1000_GMII)
- /* Run the commands which initialize the PHY */
- {
- tempval =
- (u32) mii_info->mdio_read(ugeth->
- dev, mii_info->mii_id, 0x1b);
- tempval |= 0x000f;
- mii_info->mdio_write(ugeth->dev,
- mii_info->mii_id, 0x1b,
- (u16) tempval);
- tempval =
- (u32) mii_info->mdio_read(ugeth->
- dev, mii_info->mii_id,
- MII_BMCR);
- mii_info->mdio_write(ugeth->dev,
- mii_info->mii_id, MII_BMCR,
- (u16) (tempval | BMCR_RESET));
- } else if (ugeth->ug_info->enet_interface ==
- ENET_1000_RGMII)
- /* Run the commands which initialize the PHY */
- {
- tempval =
- (u32) mii_info->mdio_read(ugeth->
- dev, mii_info->mii_id, 0x1b);
- tempval = (tempval & ~0x000f) | 0x000b;
- mii_info->mdio_write(ugeth->dev,
- mii_info->mii_id, 0x1b,
- (u16) tempval);
- tempval =
- (u32) mii_info->mdio_read(ugeth->
- dev, mii_info->mii_id,
- MII_BMCR);
- mii_info->mdio_write(ugeth->dev,
- mii_info->mii_id, MII_BMCR,
- (u16) (tempval | BMCR_RESET));
- }
- msleep(4000);
-#endif /* CONFIG_MPC8360 */
- adjust_enet_interface(ugeth);
+ ugeth->ug_info->enet_interface = ENET_1000_RGMII;
break;
case 100:
- case 10:
-#ifdef CONFIG_PPC_MPC836x
-/* FIXME: This code is for 100Mbs BUG fixing,
-remove this lines when it will be fixed!!! */
ugeth->ug_info->enet_interface = ENET_100_RGMII;
- tempval =
- (u32) mii_info->mdio_read(ugeth->dev,
- mii_info->mii_id,
- 0x1b);
- tempval = (tempval & ~0x000f) | 0x000b;
- mii_info->mdio_write(ugeth->dev,
- mii_info->mii_id, 0x1b,
- (u16) tempval);
- tempval =
- (u32) mii_info->mdio_read(ugeth->dev,
- mii_info->mii_id,
- MII_BMCR);
- mii_info->mdio_write(ugeth->dev,
- mii_info->mii_id, MII_BMCR,
- (u16) (tempval |
- BMCR_RESET));
- msleep(4000);
-#endif /* CONFIG_MPC8360 */
- adjust_enet_interface(ugeth);
+ break;
+ case 10:
+ ugeth->ug_info->enet_interface = ENET_10_RGMII;
break;
default:
ugeth_warn
@@ -1785,6 +1723,7 @@ remove this lines when it will be fixed!!! */
dev->name, mii_info->speed);
break;
}
+ adjust_enet_interface(ugeth);
ugeth_info("%s: Speed %dBT", dev->name,
mii_info->speed);
@@ -2865,8 +2804,8 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
if (UCC_GETH_TX_BD_RING_ALIGNMENT > 4)
align = UCC_GETH_TX_BD_RING_ALIGNMENT;
ugeth->tx_bd_ring_offset[j] =
- (u32) (kmalloc((u32) (length + align),
- GFP_KERNEL));
+ kmalloc((u32) (length + align), GFP_KERNEL);
+
if (ugeth->tx_bd_ring_offset[j] != 0)
ugeth->p_tx_bd_ring[j] =
(void*)((ugeth->tx_bd_ring_offset[j] +
@@ -2901,7 +2840,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
if (UCC_GETH_RX_BD_RING_ALIGNMENT > 4)
align = UCC_GETH_RX_BD_RING_ALIGNMENT;
ugeth->rx_bd_ring_offset[j] =
- (u32) (kmalloc((u32) (length + align), GFP_KERNEL));
+ kmalloc((u32) (length + align), GFP_KERNEL);
if (ugeth->rx_bd_ring_offset[j] != 0)
ugeth->p_rx_bd_ring[j] =
(void*)((ugeth->rx_bd_ring_offset[j] +
@@ -2927,10 +2866,9 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
/* Init Tx bds */
for (j = 0; j < ug_info->numQueuesTx; j++) {
/* Setup the skbuff rings */
- ugeth->tx_skbuff[j] =
- (struct sk_buff **)kmalloc(sizeof(struct sk_buff *) *
- ugeth->ug_info->bdRingLenTx[j],
- GFP_KERNEL);
+ ugeth->tx_skbuff[j] = kmalloc(sizeof(struct sk_buff *) *
+ ugeth->ug_info->bdRingLenTx[j],
+ GFP_KERNEL);
if (ugeth->tx_skbuff[j] == NULL) {
ugeth_err("%s: Could not allocate tx_skbuff",
@@ -2959,10 +2897,9 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
/* Init Rx bds */
for (j = 0; j < ug_info->numQueuesRx; j++) {
/* Setup the skbuff rings */
- ugeth->rx_skbuff[j] =
- (struct sk_buff **)kmalloc(sizeof(struct sk_buff *) *
- ugeth->ug_info->bdRingLenRx[j],
- GFP_KERNEL);
+ ugeth->rx_skbuff[j] = kmalloc(sizeof(struct sk_buff *) *
+ ugeth->ug_info->bdRingLenRx[j],
+ GFP_KERNEL);
if (ugeth->rx_skbuff[j] == NULL) {
ugeth_err("%s: Could not allocate rx_skbuff",
@@ -3453,8 +3390,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
* allocated resources can be released when the channel is freed.
*/
if (!(ugeth->p_init_enet_param_shadow =
- (struct ucc_geth_init_pram *) kmalloc(sizeof(struct ucc_geth_init_pram),
- GFP_KERNEL))) {
+ kmalloc(sizeof(struct ucc_geth_init_pram), GFP_KERNEL))) {
ugeth_err
("%s: Can not allocate memory for"
" p_UccInitEnetParamShadows.", __FUNCTION__);
@@ -4003,8 +3939,8 @@ static void ugeth_phy_startup_timer(unsigned long data)
/* Grab the PHY interrupt, if necessary/possible */
if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR) {
if (request_irq(ugeth->ug_info->phy_interrupt,
- phy_interrupt,
- SA_SHIRQ, "phy_interrupt", mii_info->dev) < 0) {
+ phy_interrupt, IRQF_SHARED,
+ "phy_interrupt", mii_info->dev) < 0) {
ugeth_err("%s: Can't get IRQ %d (PHY)",
mii_info->dev->name,
ugeth->ug_info->phy_interrupt);
@@ -4136,6 +4072,7 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
static int mii_mng_configured = 0;
const phandle *ph;
const unsigned int *prop;
+ const void *mac_addr;
ugeth_vdbg("%s: IN", __FUNCTION__);
@@ -4261,7 +4198,12 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
ugeth->ug_info = ug_info;
ugeth->dev = dev;
- memcpy(dev->dev_addr, get_property(np, "mac-address", NULL), 6);
+
+ mac_addr = get_property(np, "mac-address", NULL);
+ if (mac_addr == NULL)
+ mac_addr = get_property(np, "local-mac-address", NULL);
+ if (mac_addr)
+ memcpy(dev->dev_addr, mac_addr, 6);
return 0;
}
diff --git a/drivers/net/ucc_geth_phy.c b/drivers/net/ucc_geth_phy.c
index 3c86592ce03..9373d895b9e 100644
--- a/drivers/net/ucc_geth_phy.c
+++ b/drivers/net/ucc_geth_phy.c
@@ -18,7 +18,6 @@
*/
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/slab.h>
@@ -376,6 +375,8 @@ static int marvell_init(struct ugeth_mii_info *mii_info)
ugphy_vdbg("%s: IN", __FUNCTION__);
ucc_geth_phy_write(mii_info, 0x14, 0x0cd2);
+ ucc_geth_phy_write(mii_info, 0x1b,
+ (ucc_geth_phy_read(mii_info, 0x1b) & ~0x000f) | 0x000b);
ucc_geth_phy_write(mii_info, MII_BMCR,
ucc_geth_phy_read(mii_info, MII_BMCR) | BMCR_RESET);
msleep(4000);
diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig
index 21f76f51c95..8897f538a7c 100644
--- a/drivers/net/wan/Kconfig
+++ b/drivers/net/wan/Kconfig
@@ -26,7 +26,7 @@ config WAN
# There is no way to detect a comtrol sv11 - force it modular for now.
config HOSTESS_SV11
tristate "Comtrol Hostess SV-11 support"
- depends on WAN && ISA && m && ISA_DMA_API
+ depends on WAN && ISA && m && ISA_DMA_API && INET
help
Driver for Comtrol Hostess SV-11 network card which
operates on low speed synchronous serial links at up to
@@ -235,6 +235,19 @@ comment "Cyclades-PC300 MLPPP support is disabled."
comment "Refer to the file README.mlppp, provided by PC300 package."
depends on WAN && HDLC && PC300 && (PPP=n || !PPP_MULTILINK || PPP_SYNC_TTY=n || !HDLC_PPP)
+config PC300TOO
+ tristate "Cyclades PC300 RSV/X21 alternative support"
+ depends on HDLC && PCI
+ help
+ Alternative driver for PC300 RSV/X21 PCI cards made by
+ Cyclades, Inc. If you have such a card, say Y here and see
+ <http://www.kernel.org/pub/linux/utils/net/hdlc/>.
+
+ To compile this as a module, choose M here: the module
+ will be called pc300too.
+
+ If unsure, say N here.
+
config N2
tristate "SDL RISCom/N2 support"
depends on HDLC && ISA
@@ -344,17 +357,6 @@ config DLCI
To compile this driver as a module, choose M here: the
module will be called dlci.
-config DLCI_COUNT
- int "Max open DLCI"
- depends on DLCI
- default "24"
- help
- Maximal number of logical point-to-point frame relay connections
- (the identifiers of which are called DCLIs) that the driver can
- handle.
-
- The default is probably fine.
-
config DLCI_MAX
int "Max DLCI per device"
depends on DLCI
diff --git a/drivers/net/wan/Makefile b/drivers/net/wan/Makefile
index 83ec2c87ba3..d61fef36afc 100644
--- a/drivers/net/wan/Makefile
+++ b/drivers/net/wan/Makefile
@@ -41,6 +41,7 @@ obj-$(CONFIG_N2) += n2.o
obj-$(CONFIG_C101) += c101.o
obj-$(CONFIG_WANXL) += wanxl.o
obj-$(CONFIG_PCI200SYN) += pci200syn.o
+obj-$(CONFIG_PC300TOO) += pc300too.o
clean-files := wanxlfw.inc
$(obj)/wanxl.o: $(obj)/wanxlfw.inc
diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c
index 6c7dfb50143..e91b5a84a20 100644
--- a/drivers/net/wan/cosa.c
+++ b/drivers/net/wan/cosa.c
@@ -311,7 +311,7 @@ static int cosa_chardev_ioctl(struct inode *inode, struct file *file,
static int cosa_fasync(struct inode *inode, struct file *file, int on);
#endif
-static struct file_operations cosa_fops = {
+static const struct file_operations cosa_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = cosa_read,
diff --git a/drivers/net/wan/cycx_drv.c b/drivers/net/wan/cycx_drv.c
index e6d005726aa..d347d59db65 100644
--- a/drivers/net/wan/cycx_drv.c
+++ b/drivers/net/wan/cycx_drv.c
@@ -53,7 +53,6 @@
#include <linux/kernel.h> /* printk(), and other useful stuff */
#include <linux/stddef.h> /* offsetof(), etc. */
#include <linux/errno.h> /* return codes */
-#include <linux/sched.h> /* for jiffies, HZ, etc. */
#include <linux/cycx_drv.h> /* API definitions */
#include <linux/cycx_cfm.h> /* CYCX firmware module definitions */
#include <linux/delay.h> /* udelay, msleep_interruptible */
diff --git a/drivers/net/wan/hdlc.c b/drivers/net/wan/hdlc.c
index db354e0edbe..9040d7cf651 100644
--- a/drivers/net/wan/hdlc.c
+++ b/drivers/net/wan/hdlc.c
@@ -222,7 +222,7 @@ int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
return -EINVAL;
}
-void hdlc_setup(struct net_device *dev)
+static void hdlc_setup(struct net_device *dev)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
@@ -325,7 +325,6 @@ MODULE_LICENSE("GPL v2");
EXPORT_SYMBOL(hdlc_open);
EXPORT_SYMBOL(hdlc_close);
EXPORT_SYMBOL(hdlc_ioctl);
-EXPORT_SYMBOL(hdlc_setup);
EXPORT_SYMBOL(alloc_hdlcdev);
EXPORT_SYMBOL(unregister_hdlc_device);
EXPORT_SYMBOL(register_hdlc_protocol);
diff --git a/drivers/net/wan/pc300too.c b/drivers/net/wan/pc300too.c
new file mode 100644
index 00000000000..aff05dba720
--- /dev/null
+++ b/drivers/net/wan/pc300too.c
@@ -0,0 +1,565 @@
+/*
+ * Cyclades PC300 synchronous serial card driver for Linux
+ *
+ * Copyright (C) 2000-2007 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * 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.
+ *
+ * For information see <http://www.kernel.org/pub/linux/utils/net/hdlc/>.
+ *
+ * Sources of information:
+ * Hitachi HD64572 SCA-II User's Manual
+ * Cyclades PC300 Linux driver
+ *
+ * This driver currently supports only PC300/RSV (V.24/V.35) and
+ * PC300/X21 cards.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/in.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/moduleparam.h>
+#include <linux/netdevice.h>
+#include <linux/hdlc.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+
+#include "hd64572.h"
+
+static const char* version = "Cyclades PC300 driver version: 1.17";
+static const char* devname = "PC300";
+
+#undef DEBUG_PKT
+#define DEBUG_RINGS
+
+#define PC300_PLX_SIZE 0x80 /* PLX control window size (128 B) */
+#define PC300_SCA_SIZE 0x400 /* SCA window size (1 KB) */
+#define ALL_PAGES_ALWAYS_MAPPED
+#define NEED_DETECT_RAM
+#define NEED_SCA_MSCI_INTR
+#define MAX_TX_BUFFERS 10
+
+static int pci_clock_freq = 33000000;
+static int use_crystal_clock = 0;
+static unsigned int CLOCK_BASE;
+
+/* Masks to access the init_ctrl PLX register */
+#define PC300_CLKSEL_MASK (0x00000004UL)
+#define PC300_CHMEDIA_MASK(port) (0x00000020UL << ((port) * 3))
+#define PC300_CTYPE_MASK (0x00000800UL)
+
+
+enum { PC300_RSV = 1, PC300_X21, PC300_TE }; /* card types */
+
+/*
+ * PLX PCI9050-1 local configuration and shared runtime registers.
+ * This structure can be used to access 9050 registers (memory mapped).
+ */
+typedef struct {
+ u32 loc_addr_range[4]; /* 00-0Ch : Local Address Ranges */
+ u32 loc_rom_range; /* 10h : Local ROM Range */
+ u32 loc_addr_base[4]; /* 14-20h : Local Address Base Addrs */
+ u32 loc_rom_base; /* 24h : Local ROM Base */
+ u32 loc_bus_descr[4]; /* 28-34h : Local Bus Descriptors */
+ u32 rom_bus_descr; /* 38h : ROM Bus Descriptor */
+ u32 cs_base[4]; /* 3C-48h : Chip Select Base Addrs */
+ u32 intr_ctrl_stat; /* 4Ch : Interrupt Control/Status */
+ u32 init_ctrl; /* 50h : EEPROM ctrl, Init Ctrl, etc */
+}plx9050;
+
+
+
+typedef struct port_s {
+ struct net_device *dev;
+ struct card_s *card;
+ spinlock_t lock; /* TX lock */
+ sync_serial_settings settings;
+ int rxpart; /* partial frame received, next frame invalid*/
+ unsigned short encoding;
+ unsigned short parity;
+ unsigned int iface;
+ u16 rxin; /* rx ring buffer 'in' pointer */
+ u16 txin; /* tx ring buffer 'in' and 'last' pointers */
+ u16 txlast;
+ u8 rxs, txs, tmc; /* SCA registers */
+ u8 phy_node; /* physical port # - 0 or 1 */
+}port_t;
+
+
+
+typedef struct card_s {
+ int type; /* RSV, X21, etc. */
+ int n_ports; /* 1 or 2 ports */
+ u8 __iomem *rambase; /* buffer memory base (virtual) */
+ u8 __iomem *scabase; /* SCA memory base (virtual) */
+ plx9050 __iomem *plxbase; /* PLX registers memory base (virtual) */
+ u32 init_ctrl_value; /* Saved value - 9050 bug workaround */
+ u16 rx_ring_buffers; /* number of buffers in a ring */
+ u16 tx_ring_buffers;
+ u16 buff_offset; /* offset of first buffer of first channel */
+ u8 irq; /* interrupt request level */
+
+ port_t ports[2];
+}card_t;
+
+
+#define sca_in(reg, card) readb(card->scabase + (reg))
+#define sca_out(value, reg, card) writeb(value, card->scabase + (reg))
+#define sca_inw(reg, card) readw(card->scabase + (reg))
+#define sca_outw(value, reg, card) writew(value, card->scabase + (reg))
+#define sca_inl(reg, card) readl(card->scabase + (reg))
+#define sca_outl(value, reg, card) writel(value, card->scabase + (reg))
+
+#define port_to_card(port) (port->card)
+#define log_node(port) (port->phy_node)
+#define phy_node(port) (port->phy_node)
+#define winbase(card) (card->rambase)
+#define get_port(card, port) ((port) < (card)->n_ports ? \
+ (&(card)->ports[port]) : (NULL))
+
+#include "hd6457x.c"
+
+
+static void pc300_set_iface(port_t *port)
+{
+ card_t *card = port->card;
+ u32 __iomem * init_ctrl = &card->plxbase->init_ctrl;
+ u16 msci = get_msci(port);
+ u8 rxs = port->rxs & CLK_BRG_MASK;
+ u8 txs = port->txs & CLK_BRG_MASK;
+
+ sca_out(EXS_TES1, (phy_node(port) ? MSCI1_OFFSET : MSCI0_OFFSET) + EXS,
+ port_to_card(port));
+ switch(port->settings.clock_type) {
+ case CLOCK_INT:
+ rxs |= CLK_BRG; /* BRG output */
+ txs |= CLK_PIN_OUT | CLK_TX_RXCLK; /* RX clock */
+ break;
+
+ case CLOCK_TXINT:
+ rxs |= CLK_LINE; /* RXC input */
+ txs |= CLK_PIN_OUT | CLK_BRG; /* BRG output */
+ break;
+
+ case CLOCK_TXFROMRX:
+ rxs |= CLK_LINE; /* RXC input */
+ txs |= CLK_PIN_OUT | CLK_TX_RXCLK; /* RX clock */
+ break;
+
+ default: /* EXTernal clock */
+ rxs |= CLK_LINE; /* RXC input */
+ txs |= CLK_PIN_OUT | CLK_LINE; /* TXC input */
+ break;
+ }
+
+ port->rxs = rxs;
+ port->txs = txs;
+ sca_out(rxs, msci + RXS, card);
+ sca_out(txs, msci + TXS, card);
+ sca_set_port(port);
+
+ if (port->card->type == PC300_RSV) {
+ if (port->iface == IF_IFACE_V35)
+ writel(card->init_ctrl_value |
+ PC300_CHMEDIA_MASK(port->phy_node), init_ctrl);
+ else
+ writel(card->init_ctrl_value &
+ ~PC300_CHMEDIA_MASK(port->phy_node), init_ctrl);
+ }
+}
+
+
+
+static int pc300_open(struct net_device *dev)
+{
+ port_t *port = dev_to_port(dev);
+
+ int result = hdlc_open(dev);
+ if (result)
+ return result;
+
+ sca_open(dev);
+ pc300_set_iface(port);
+ return 0;
+}
+
+
+
+static int pc300_close(struct net_device *dev)
+{
+ sca_close(dev);
+ hdlc_close(dev);
+ return 0;
+}
+
+
+
+static int pc300_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+ const size_t size = sizeof(sync_serial_settings);
+ sync_serial_settings new_line;
+ sync_serial_settings __user *line = ifr->ifr_settings.ifs_ifsu.sync;
+ int new_type;
+ port_t *port = dev_to_port(dev);
+
+#ifdef DEBUG_RINGS
+ if (cmd == SIOCDEVPRIVATE) {
+ sca_dump_rings(dev);
+ return 0;
+ }
+#endif
+ if (cmd != SIOCWANDEV)
+ return hdlc_ioctl(dev, ifr, cmd);
+
+ if (ifr->ifr_settings.type == IF_GET_IFACE) {
+ ifr->ifr_settings.type = port->iface;
+ if (ifr->ifr_settings.size < size) {
+ ifr->ifr_settings.size = size; /* data size wanted */
+ return -ENOBUFS;
+ }
+ if (copy_to_user(line, &port->settings, size))
+ return -EFAULT;
+ return 0;
+
+ }
+
+ if (port->card->type == PC300_X21 &&
+ (ifr->ifr_settings.type == IF_IFACE_SYNC_SERIAL ||
+ ifr->ifr_settings.type == IF_IFACE_X21))
+ new_type = IF_IFACE_X21;
+
+ else if (port->card->type == PC300_RSV &&
+ (ifr->ifr_settings.type == IF_IFACE_SYNC_SERIAL ||
+ ifr->ifr_settings.type == IF_IFACE_V35))
+ new_type = IF_IFACE_V35;
+
+ else if (port->card->type == PC300_RSV &&
+ ifr->ifr_settings.type == IF_IFACE_V24)
+ new_type = IF_IFACE_V24;
+
+ else
+ return hdlc_ioctl(dev, ifr, cmd);
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ if (copy_from_user(&new_line, line, size))
+ return -EFAULT;
+
+ if (new_line.clock_type != CLOCK_EXT &&
+ new_line.clock_type != CLOCK_TXFROMRX &&
+ new_line.clock_type != CLOCK_INT &&
+ new_line.clock_type != CLOCK_TXINT)
+ return -EINVAL; /* No such clock setting */
+
+ if (new_line.loopback != 0 && new_line.loopback != 1)
+ return -EINVAL;
+
+ memcpy(&port->settings, &new_line, size); /* Update settings */
+ port->iface = new_type;
+ pc300_set_iface(port);
+ return 0;
+}
+
+
+
+static void pc300_pci_remove_one(struct pci_dev *pdev)
+{
+ int i;
+ card_t *card = pci_get_drvdata(pdev);
+
+ for (i = 0; i < 2; i++)
+ if (card->ports[i].card) {
+ struct net_device *dev = port_to_dev(&card->ports[i]);
+ unregister_hdlc_device(dev);
+ }
+
+ if (card->irq)
+ free_irq(card->irq, card);
+
+ if (card->rambase)
+ iounmap(card->rambase);
+ if (card->scabase)
+ iounmap(card->scabase);
+ if (card->plxbase)
+ iounmap(card->plxbase);
+
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+ if (card->ports[0].dev)
+ free_netdev(card->ports[0].dev);
+ if (card->ports[1].dev)
+ free_netdev(card->ports[1].dev);
+ kfree(card);
+}
+
+
+
+static int __devinit pc300_pci_init_one(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ card_t *card;
+ u8 rev_id;
+ u32 __iomem *p;
+ int i;
+ u32 ramsize;
+ u32 ramphys; /* buffer memory base */
+ u32 scaphys; /* SCA memory base */
+ u32 plxphys; /* PLX registers memory base */
+
+#ifndef MODULE
+ static int printed_version;
+ if (!printed_version++)
+ printk(KERN_INFO "%s\n", version);
+#endif
+
+ i = pci_enable_device(pdev);
+ if (i)
+ return i;
+
+ i = pci_request_regions(pdev, "PC300");
+ if (i) {
+ pci_disable_device(pdev);
+ return i;
+ }
+
+ card = kmalloc(sizeof(card_t), GFP_KERNEL);
+ if (card == NULL) {
+ printk(KERN_ERR "pc300: unable to allocate memory\n");
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ return -ENOBUFS;
+ }
+ memset(card, 0, sizeof(card_t));
+ pci_set_drvdata(pdev, card);
+
+ if (pdev->device == PCI_DEVICE_ID_PC300_TE_1 ||
+ pdev->device == PCI_DEVICE_ID_PC300_TE_2)
+ card->type = PC300_TE; /* not fully supported */
+ else if (card->init_ctrl_value & PC300_CTYPE_MASK)
+ card->type = PC300_X21;
+ else
+ card->type = PC300_RSV;
+
+ if (pdev->device == PCI_DEVICE_ID_PC300_RX_1 ||
+ pdev->device == PCI_DEVICE_ID_PC300_TE_1)
+ card->n_ports = 1;
+ else
+ card->n_ports = 2;
+
+ for (i = 0; i < card->n_ports; i++)
+ if (!(card->ports[i].dev = alloc_hdlcdev(&card->ports[i]))) {
+ printk(KERN_ERR "pc300: unable to allocate memory\n");
+ pc300_pci_remove_one(pdev);
+ return -ENOMEM;
+ }
+
+ pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id);
+ if (pci_resource_len(pdev, 0) != PC300_PLX_SIZE ||
+ pci_resource_len(pdev, 2) != PC300_SCA_SIZE ||
+ pci_resource_len(pdev, 3) < 16384) {
+ printk(KERN_ERR "pc300: invalid card EEPROM parameters\n");
+ pc300_pci_remove_one(pdev);
+ return -EFAULT;
+ }
+
+ plxphys = pci_resource_start(pdev,0) & PCI_BASE_ADDRESS_MEM_MASK;
+ card->plxbase = ioremap(plxphys, PC300_PLX_SIZE);
+
+ scaphys = pci_resource_start(pdev,2) & PCI_BASE_ADDRESS_MEM_MASK;
+ card->scabase = ioremap(scaphys, PC300_SCA_SIZE);
+
+ ramphys = pci_resource_start(pdev,3) & PCI_BASE_ADDRESS_MEM_MASK;
+ card->rambase = ioremap(ramphys, pci_resource_len(pdev,3));
+
+ if (card->plxbase == NULL ||
+ card->scabase == NULL ||
+ card->rambase == NULL) {
+ printk(KERN_ERR "pc300: ioremap() failed\n");
+ pc300_pci_remove_one(pdev);
+ }
+
+ /* PLX PCI 9050 workaround for local configuration register read bug */
+ pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, scaphys);
+ card->init_ctrl_value = readl(&((plx9050 __iomem *)card->scabase)->init_ctrl);
+ pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, plxphys);
+
+ /* Reset PLX */
+ p = &card->plxbase->init_ctrl;
+ writel(card->init_ctrl_value | 0x40000000, p);
+ readl(p); /* Flush the write - do not use sca_flush */
+ udelay(1);
+
+ writel(card->init_ctrl_value, p);
+ readl(p); /* Flush the write - do not use sca_flush */
+ udelay(1);
+
+ /* Reload Config. Registers from EEPROM */
+ writel(card->init_ctrl_value | 0x20000000, p);
+ readl(p); /* Flush the write - do not use sca_flush */
+ udelay(1);
+
+ writel(card->init_ctrl_value, p);
+ readl(p); /* Flush the write - do not use sca_flush */
+ udelay(1);
+
+ ramsize = sca_detect_ram(card, card->rambase,
+ pci_resource_len(pdev, 3));
+
+ if (use_crystal_clock)
+ card->init_ctrl_value &= ~PC300_CLKSEL_MASK;
+ else
+ card->init_ctrl_value |= PC300_CLKSEL_MASK;
+
+ writel(card->init_ctrl_value, &card->plxbase->init_ctrl);
+ /* number of TX + RX buffers for one port */
+ i = ramsize / (card->n_ports * (sizeof(pkt_desc) + HDLC_MAX_MRU));
+ card->tx_ring_buffers = min(i / 2, MAX_TX_BUFFERS);
+ card->rx_ring_buffers = i - card->tx_ring_buffers;
+
+ card->buff_offset = card->n_ports * sizeof(pkt_desc) *
+ (card->tx_ring_buffers + card->rx_ring_buffers);
+
+ printk(KERN_INFO "pc300: PC300/%s, %u KB RAM at 0x%x, IRQ%u, "
+ "using %u TX + %u RX packets rings\n",
+ card->type == PC300_X21 ? "X21" :
+ card->type == PC300_TE ? "TE" : "RSV",
+ ramsize / 1024, ramphys, pdev->irq,
+ card->tx_ring_buffers, card->rx_ring_buffers);
+
+ if (card->tx_ring_buffers < 1) {
+ printk(KERN_ERR "pc300: RAM test failed\n");
+ pc300_pci_remove_one(pdev);
+ return -EFAULT;
+ }
+
+ /* Enable interrupts on the PCI bridge, LINTi1 active low */
+ writew(0x0041, &card->plxbase->intr_ctrl_stat);
+
+ /* Allocate IRQ */
+ if (request_irq(pdev->irq, sca_intr, IRQF_SHARED, devname, card)) {
+ printk(KERN_WARNING "pc300: could not allocate IRQ%d.\n",
+ pdev->irq);
+ pc300_pci_remove_one(pdev);
+ return -EBUSY;
+ }
+ card->irq = pdev->irq;
+
+ sca_init(card, 0);
+
+ // COTE not set - allows better TX DMA settings
+ // sca_out(sca_in(PCR, card) | PCR_COTE, PCR, card);
+
+ sca_out(0x10, BTCR, card);
+
+ for (i = 0; i < card->n_ports; i++) {
+ port_t *port = &card->ports[i];
+ struct net_device *dev = port_to_dev(port);
+ hdlc_device *hdlc = dev_to_hdlc(dev);
+ port->phy_node = i;
+
+ spin_lock_init(&port->lock);
+ SET_MODULE_OWNER(dev);
+ dev->irq = card->irq;
+ dev->mem_start = ramphys;
+ dev->mem_end = ramphys + ramsize - 1;
+ dev->tx_queue_len = 50;
+ dev->do_ioctl = pc300_ioctl;
+ dev->open = pc300_open;
+ dev->stop = pc300_close;
+ hdlc->attach = sca_attach;
+ hdlc->xmit = sca_xmit;
+ port->settings.clock_type = CLOCK_EXT;
+ port->card = card;
+ if (card->type == PC300_X21)
+ port->iface = IF_IFACE_X21;
+ else
+ port->iface = IF_IFACE_V35;
+
+ if (register_hdlc_device(dev)) {
+ printk(KERN_ERR "pc300: unable to register hdlc "
+ "device\n");
+ port->card = NULL;
+ pc300_pci_remove_one(pdev);
+ return -ENOBUFS;
+ }
+ sca_init_sync_port(port); /* Set up SCA memory */
+
+ printk(KERN_INFO "%s: PC300 node %d\n",
+ dev->name, port->phy_node);
+ }
+ return 0;
+}
+
+
+
+static struct pci_device_id pc300_pci_tbl[] __devinitdata = {
+ { 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,
+ PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_PC300_TE_1, PCI_ANY_ID,
+ PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_PC300_TE_2, PCI_ANY_ID,
+ PCI_ANY_ID, 0, 0, 0 },
+ { 0, }
+};
+
+
+static struct pci_driver pc300_pci_driver = {
+ .name = "PC300",
+ .id_table = pc300_pci_tbl,
+ .probe = pc300_pci_init_one,
+ .remove = pc300_pci_remove_one,
+};
+
+
+static int __init pc300_init_module(void)
+{
+#ifdef MODULE
+ printk(KERN_INFO "%s\n", version);
+#endif
+ if (pci_clock_freq < 1000000 || pci_clock_freq > 80000000) {
+ printk(KERN_ERR "pc300: Invalid PCI clock frequency\n");
+ return -EINVAL;
+ }
+ if (use_crystal_clock != 0 && use_crystal_clock != 1) {
+ printk(KERN_ERR "pc300: Invalid 'use_crystal_clock' value\n");
+ return -EINVAL;
+ }
+
+ CLOCK_BASE = use_crystal_clock ? 24576000 : pci_clock_freq;
+
+ return pci_register_driver(&pc300_pci_driver);
+}
+
+
+
+static void __exit pc300_cleanup_module(void)
+{
+ pci_unregister_driver(&pc300_pci_driver);
+}
+
+MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
+MODULE_DESCRIPTION("Cyclades PC300 serial port driver");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(pci, pc300_pci_tbl);
+module_param(pci_clock_freq, int, 0444);
+MODULE_PARM_DESC(pci_clock_freq, "System PCI clock frequency in Hz");
+module_param(use_crystal_clock, int, 0444);
+MODULE_PARM_DESC(use_crystal_clock,
+ "Use 24.576 MHz clock instead of PCI clock");
+module_init(pc300_init_module);
+module_exit(pc300_cleanup_module);
diff --git a/drivers/net/wan/pci200syn.c b/drivers/net/wan/pci200syn.c
index a6b9c33b68e..ca06a00d9d8 100644
--- a/drivers/net/wan/pci200syn.c
+++ b/drivers/net/wan/pci200syn.c
@@ -17,7 +17,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
-#include <linux/sched.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/in.h>
diff --git a/drivers/net/wan/z85230.c b/drivers/net/wan/z85230.c
index 59ddd21c395..8dbcf83bb5f 100644
--- a/drivers/net/wan/z85230.c
+++ b/drivers/net/wan/z85230.c
@@ -331,8 +331,7 @@ static void z8530_rtsdtr(struct z8530_channel *c, int set)
static void z8530_rx(struct z8530_channel *c)
{
u8 ch,stat;
- spin_lock(c->lock);
-
+
while(1)
{
/* FIFO empty ? */
@@ -390,7 +389,6 @@ static void z8530_rx(struct z8530_channel *c)
*/
write_zsctrl(c, ERR_RES);
write_zsctrl(c, RES_H_IUS);
- spin_unlock(c->lock);
}
@@ -406,7 +404,6 @@ static void z8530_rx(struct z8530_channel *c)
static void z8530_tx(struct z8530_channel *c)
{
- spin_lock(c->lock);
while(c->txcount) {
/* FIFO full ? */
if(!(read_zsreg(c, R0)&4))
@@ -434,7 +431,6 @@ static void z8530_tx(struct z8530_channel *c)
z8530_tx_done(c);
write_zsctrl(c, RES_H_IUS);
- spin_unlock(c->lock);
}
/**
@@ -452,7 +448,6 @@ static void z8530_status(struct z8530_channel *chan)
{
u8 status, altered;
- spin_lock(chan->lock);
status=read_zsreg(chan, R0);
altered=chan->status^status;
@@ -487,7 +482,6 @@ static void z8530_status(struct z8530_channel *chan)
}
write_zsctrl(chan, RES_EXT_INT);
write_zsctrl(chan, RES_H_IUS);
- spin_unlock(chan->lock);
}
struct z8530_irqhandler z8530_sync=
@@ -511,7 +505,6 @@ EXPORT_SYMBOL(z8530_sync);
static void z8530_dma_rx(struct z8530_channel *chan)
{
- spin_lock(chan->lock);
if(chan->rxdma_on)
{
/* Special condition check only */
@@ -534,7 +527,6 @@ static void z8530_dma_rx(struct z8530_channel *chan)
/* DMA is off right now, drain the slow way */
z8530_rx(chan);
}
- spin_unlock(chan->lock);
}
/**
@@ -547,7 +539,6 @@ static void z8530_dma_rx(struct z8530_channel *chan)
static void z8530_dma_tx(struct z8530_channel *chan)
{
- spin_lock(chan->lock);
if(!chan->dma_tx)
{
printk(KERN_WARNING "Hey who turned the DMA off?\n");
@@ -557,7 +548,6 @@ static void z8530_dma_tx(struct z8530_channel *chan)
/* This shouldnt occur in DMA mode */
printk(KERN_ERR "DMA tx - bogus event!\n");
z8530_tx(chan);
- spin_unlock(chan->lock);
}
/**
@@ -596,7 +586,6 @@ static void z8530_dma_status(struct z8530_channel *chan)
}
}
- spin_lock(chan->lock);
if(altered&chan->dcdcheck)
{
if(status&chan->dcdcheck)
@@ -618,7 +607,6 @@ static void z8530_dma_status(struct z8530_channel *chan)
write_zsctrl(chan, RES_EXT_INT);
write_zsctrl(chan, RES_H_IUS);
- spin_unlock(chan->lock);
}
struct z8530_irqhandler z8530_dma_sync=
diff --git a/drivers/net/wd.c b/drivers/net/wd.c
index 7f38012b9c9..a0326818ff2 100644
--- a/drivers/net/wd.c
+++ b/drivers/net/wd.c
@@ -433,7 +433,7 @@ wd_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_
memcpy_fromio(skb->data + semi_count, ei_status.mem + TX_PAGES * 256, count);
} else {
/* Packet is in one chunk -- we can copy + cksum. */
- eth_io_copy_and_sum(skb, xfer_start, count, 0);
+ memcpy_fromio(skb->data, xfer_start, count);
}
/* Turn off 16 bit access so that reboot works. ISA brain-damage */
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index 44a22701da9..a8c2bfe26c2 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -1623,7 +1623,7 @@ static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen,
crypto_cipher_setkey(tfm, pkey, 16);
counter = 0;
- for (i = 0; i < (sizeof(context->coeff)/sizeof(context->coeff[0])); ) {
+ for (i = 0; i < ARRAY_SIZE(context->coeff); ) {
aes_counter[15] = (u8)(counter >> 0);
aes_counter[14] = (u8)(counter >> 8);
aes_counter[13] = (u8)(counter >> 16);
@@ -1632,7 +1632,7 @@ static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen,
memcpy (plain, aes_counter, 16);
crypto_cipher_encrypt_one(tfm, plain, plain);
cipher = plain;
- for (j=0; (j<16) && (i< (sizeof(context->coeff)/sizeof(context->coeff[0]))); ) {
+ for (j = 0; (j < 16) && (i < ARRAY_SIZE(context->coeff)); ) {
context->coeff[i++] = ntohl(*(u32 *)&cipher[j]);
j += 4;
}
@@ -4430,53 +4430,53 @@ static int proc_BSSList_open( struct inode *inode, struct file *file );
static int proc_config_open( struct inode *inode, struct file *file );
static int proc_wepkey_open( struct inode *inode, struct file *file );
-static struct file_operations proc_statsdelta_ops = {
+static const struct file_operations proc_statsdelta_ops = {
.read = proc_read,
.open = proc_statsdelta_open,
.release = proc_close
};
-static struct file_operations proc_stats_ops = {
+static const struct file_operations proc_stats_ops = {
.read = proc_read,
.open = proc_stats_open,
.release = proc_close
};
-static struct file_operations proc_status_ops = {
+static const struct file_operations proc_status_ops = {
.read = proc_read,
.open = proc_status_open,
.release = proc_close
};
-static struct file_operations proc_SSID_ops = {
+static const struct file_operations proc_SSID_ops = {
.read = proc_read,
.write = proc_write,
.open = proc_SSID_open,
.release = proc_close
};
-static struct file_operations proc_BSSList_ops = {
+static const struct file_operations proc_BSSList_ops = {
.read = proc_read,
.write = proc_write,
.open = proc_BSSList_open,
.release = proc_close
};
-static struct file_operations proc_APList_ops = {
+static const struct file_operations proc_APList_ops = {
.read = proc_read,
.write = proc_write,
.open = proc_APList_open,
.release = proc_close
};
-static struct file_operations proc_config_ops = {
+static const struct file_operations proc_config_ops = {
.read = proc_read,
.write = proc_write,
.open = proc_config_open,
.release = proc_close
};
-static struct file_operations proc_wepkey_ops = {
+static const struct file_operations proc_wepkey_ops = {
.read = proc_read,
.write = proc_write,
.open = proc_wepkey_open,
diff --git a/drivers/net/wireless/arlan-proc.c b/drivers/net/wireless/arlan-proc.c
index 5fa985435ff..015abd928ab 100644
--- a/drivers/net/wireless/arlan-proc.c
+++ b/drivers/net/wireless/arlan-proc.c
@@ -1216,7 +1216,7 @@ static ctl_table arlan_table[MAX_ARLANS + 1] =
static ctl_table arlan_root_table[] =
{
{
- .ctl_name = 254,
+ .ctl_name = CTL_ARLAN,
.procname = "arlan",
.maxlen = 0,
.mode = 0555,
@@ -1244,7 +1244,7 @@ int __init init_arlan_proc(void)
return 0;
for (i = 0; i < MAX_ARLANS && arlan_device[i]; i++)
arlan_table[i].ctl_name = i + 1;
- arlan_device_sysctl_header = register_sysctl_table(arlan_root_table, 0);
+ arlan_device_sysctl_header = register_sysctl_table(arlan_root_table);
if (!arlan_device_sysctl_header)
return -1;
diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c
index 10bcb48e80d..23eba698aec 100644
--- a/drivers/net/wireless/atmel.c
+++ b/drivers/net/wireless/atmel.c
@@ -42,7 +42,6 @@
#include <linux/init.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/string.h>
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h
index 8286678513b..95ff175d8f3 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx.h
@@ -21,7 +21,7 @@
#define PFX KBUILD_MODNAME ": "
#define BCM43xx_SWITCH_CORE_MAX_RETRIES 50
-#define BCM43xx_IRQWAIT_MAX_RETRIES 50
+#define BCM43xx_IRQWAIT_MAX_RETRIES 100
#define BCM43xx_IO_SIZE 8192
@@ -333,7 +333,7 @@
#define BCM43xx_SBF_PS2 0x04000000
#define BCM43xx_SBF_NO_SSID_BCAST 0x08000000
#define BCM43xx_SBF_TIME_UPDATE 0x10000000
-#define BCM43xx_SBF_80000000 0x80000000 /*FIXME: fix name*/
+#define BCM43xx_SBF_MODE_G 0x80000000
/* Microcode */
#define BCM43xx_UCODE_REVISION 0x0000
@@ -352,6 +352,10 @@
#define BCM43xx_UCODEFLAG_UNKPACTRL 0x0040
#define BCM43xx_UCODEFLAG_JAPAN 0x0080
+/* Hardware Radio Enable masks */
+#define BCM43xx_MMIO_RADIO_HWENABLED_HI_MASK (1 << 16)
+#define BCM43xx_MMIO_RADIO_HWENABLED_LO_MASK (1 << 4)
+
/* Generic-Interrupt reasons. */
#define BCM43xx_IRQ_READY (1 << 0)
#define BCM43xx_IRQ_BEACON (1 << 1)
@@ -503,8 +507,6 @@ struct bcm43xx_sprominfo {
u8 et1macaddr[6];
u8 et0phyaddr:5;
u8 et1phyaddr:5;
- u8 et0mdcport:1;
- u8 et1mdcport:1;
u8 boardrev;
u8 locale:4;
u8 antennas_aphy:2;
@@ -538,7 +540,7 @@ struct bcm43xx_lopair {
struct bcm43xx_phyinfo {
/* Hardware Data */
- u8 version;
+ u8 analog;
u8 type;
u8 rev;
u16 antenna_diversity;
@@ -758,7 +760,8 @@ struct bcm43xx_private {
bad_frames_preempt:1, /* Use "Bad Frames Preemption" (default off) */
reg124_set_0x4:1, /* Some variable to keep track of IRQ stuff. */
short_preamble:1, /* TRUE, if short preamble is enabled. */
- firmware_norelease:1; /* Do not release the firmware. Used on suspend. */
+ firmware_norelease:1, /* Do not release the firmware. Used on suspend. */
+ radio_hw_enable:1; /* TRUE if radio is hardware enabled */
struct bcm43xx_stats stats;
@@ -766,6 +769,7 @@ struct bcm43xx_private {
* This is currently always BCM43xx_BUSTYPE_PCI
*/
u8 bustype;
+ u64 dma_mask;
u16 board_vendor;
u16 board_type;
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c
index b9df06a06ea..35dbe455451 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c
@@ -355,37 +355,37 @@ out_up:
#undef fappend
-static struct file_operations devinfo_fops = {
+static const struct file_operations devinfo_fops = {
.read = devinfo_read_file,
.write = write_file_dummy,
.open = open_file_generic,
};
-static struct file_operations spromdump_fops = {
+static const struct file_operations spromdump_fops = {
.read = spromdump_read_file,
.write = write_file_dummy,
.open = open_file_generic,
};
-static struct file_operations drvinfo_fops = {
+static const struct file_operations drvinfo_fops = {
.read = drvinfo_read_file,
.write = write_file_dummy,
.open = open_file_generic,
};
-static struct file_operations tsf_fops = {
+static const struct file_operations tsf_fops = {
.read = tsf_read_file,
.write = tsf_write_file,
.open = open_file_generic,
};
-static struct file_operations txstat_fops = {
+static const struct file_operations txstat_fops = {
.read = txstat_read_file,
.write = write_file_dummy,
.open = open_file_generic,
};
-static struct file_operations restart_fops = {
+static const struct file_operations restart_fops = {
.write = restart_write_file,
.open = open_file_generic,
};
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
index 978ed099e28..6e0dc76400e 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
@@ -145,16 +145,14 @@ dma_addr_t map_descbuffer(struct bcm43xx_dmaring *ring,
int tx)
{
dma_addr_t dmaaddr;
+ int direction = PCI_DMA_FROMDEVICE;
- if (tx) {
- dmaaddr = dma_map_single(&ring->bcm->pci_dev->dev,
- buf, len,
- DMA_TO_DEVICE);
- } else {
- dmaaddr = dma_map_single(&ring->bcm->pci_dev->dev,
+ if (tx)
+ direction = PCI_DMA_TODEVICE;
+
+ dmaaddr = pci_map_single(ring->bcm->pci_dev,
buf, len,
- DMA_FROM_DEVICE);
- }
+ direction);
return dmaaddr;
}
@@ -166,13 +164,13 @@ void unmap_descbuffer(struct bcm43xx_dmaring *ring,
int tx)
{
if (tx) {
- dma_unmap_single(&ring->bcm->pci_dev->dev,
+ pci_unmap_single(ring->bcm->pci_dev,
addr, len,
- DMA_TO_DEVICE);
+ PCI_DMA_TODEVICE);
} else {
- dma_unmap_single(&ring->bcm->pci_dev->dev,
+ pci_unmap_single(ring->bcm->pci_dev,
addr, len,
- DMA_FROM_DEVICE);
+ PCI_DMA_FROMDEVICE);
}
}
@@ -183,8 +181,8 @@ void sync_descbuffer_for_cpu(struct bcm43xx_dmaring *ring,
{
assert(!ring->tx);
- dma_sync_single_for_cpu(&ring->bcm->pci_dev->dev,
- addr, len, DMA_FROM_DEVICE);
+ pci_dma_sync_single_for_cpu(ring->bcm->pci_dev,
+ addr, len, PCI_DMA_FROMDEVICE);
}
static inline
@@ -194,8 +192,8 @@ void sync_descbuffer_for_device(struct bcm43xx_dmaring *ring,
{
assert(!ring->tx);
- dma_sync_single_for_device(&ring->bcm->pci_dev->dev,
- addr, len, DMA_FROM_DEVICE);
+ pci_dma_sync_single_for_cpu(ring->bcm->pci_dev,
+ addr, len, PCI_DMA_TODEVICE);
}
/* Unmap and free a descriptor buffer. */
@@ -214,17 +212,53 @@ void free_descriptor_buffer(struct bcm43xx_dmaring *ring,
static int alloc_ringmemory(struct bcm43xx_dmaring *ring)
{
- struct device *dev = &(ring->bcm->pci_dev->dev);
-
- ring->descbase = dma_alloc_coherent(dev, BCM43xx_DMA_RINGMEMSIZE,
- &(ring->dmabase), GFP_KERNEL);
+ ring->descbase = pci_alloc_consistent(ring->bcm->pci_dev, BCM43xx_DMA_RINGMEMSIZE,
+ &(ring->dmabase));
if (!ring->descbase) {
- printk(KERN_ERR PFX "DMA ringmemory allocation failed\n");
- return -ENOMEM;
+ /* Allocation may have failed due to pci_alloc_consistent
+ insisting on use of GFP_DMA, which is more restrictive
+ than necessary... */
+ struct dma_desc *rx_ring;
+ dma_addr_t rx_ring_dma;
+
+ rx_ring = kzalloc(BCM43xx_DMA_RINGMEMSIZE, GFP_KERNEL);
+ if (!rx_ring)
+ goto out_err;
+
+ rx_ring_dma = pci_map_single(ring->bcm->pci_dev, rx_ring,
+ BCM43xx_DMA_RINGMEMSIZE,
+ PCI_DMA_BIDIRECTIONAL);
+
+ if (pci_dma_mapping_error(rx_ring_dma) ||
+ rx_ring_dma + BCM43xx_DMA_RINGMEMSIZE > ring->bcm->dma_mask) {
+ /* Sigh... */
+ if (!pci_dma_mapping_error(rx_ring_dma))
+ pci_unmap_single(ring->bcm->pci_dev,
+ rx_ring_dma, BCM43xx_DMA_RINGMEMSIZE,
+ PCI_DMA_BIDIRECTIONAL);
+ rx_ring_dma = pci_map_single(ring->bcm->pci_dev,
+ rx_ring, BCM43xx_DMA_RINGMEMSIZE,
+ PCI_DMA_BIDIRECTIONAL);
+ if (pci_dma_mapping_error(rx_ring_dma) ||
+ rx_ring_dma + BCM43xx_DMA_RINGMEMSIZE > ring->bcm->dma_mask) {
+ assert(0);
+ if (!pci_dma_mapping_error(rx_ring_dma))
+ pci_unmap_single(ring->bcm->pci_dev,
+ rx_ring_dma, BCM43xx_DMA_RINGMEMSIZE,
+ PCI_DMA_BIDIRECTIONAL);
+ goto out_err;
+ }
+ }
+
+ ring->descbase = rx_ring;
+ ring->dmabase = rx_ring_dma;
}
memset(ring->descbase, 0, BCM43xx_DMA_RINGMEMSIZE);
return 0;
+out_err:
+ printk(KERN_ERR PFX "DMA ringmemory allocation failed\n");
+ return -ENOMEM;
}
static void free_ringmemory(struct bcm43xx_dmaring *ring)
@@ -407,6 +441,29 @@ static int setup_rx_descbuffer(struct bcm43xx_dmaring *ring,
if (unlikely(!skb))
return -ENOMEM;
dmaaddr = map_descbuffer(ring, skb->data, ring->rx_buffersize, 0);
+ /* This hardware bug work-around adapted from the b44 driver.
+ The chip may be unable to do PCI DMA to/from anything above 1GB */
+ if (pci_dma_mapping_error(dmaaddr) ||
+ dmaaddr + ring->rx_buffersize > ring->bcm->dma_mask) {
+ /* This one has 30-bit addressing... */
+ if (!pci_dma_mapping_error(dmaaddr))
+ pci_unmap_single(ring->bcm->pci_dev,
+ dmaaddr, ring->rx_buffersize,
+ PCI_DMA_FROMDEVICE);
+ dev_kfree_skb_any(skb);
+ skb = __dev_alloc_skb(ring->rx_buffersize,GFP_DMA);
+ if (skb == NULL)
+ return -ENOMEM;
+ dmaaddr = pci_map_single(ring->bcm->pci_dev,
+ skb->data, ring->rx_buffersize,
+ PCI_DMA_FROMDEVICE);
+ if (pci_dma_mapping_error(dmaaddr) ||
+ dmaaddr + ring->rx_buffersize > ring->bcm->dma_mask) {
+ assert(0);
+ dev_kfree_skb_any(skb);
+ return -ENOMEM;
+ }
+ }
meta->skb = skb;
meta->dmaaddr = dmaaddr;
skb->dev = ring->bcm->net_dev;
@@ -636,8 +693,10 @@ struct bcm43xx_dmaring * bcm43xx_setup_dmaring(struct bcm43xx_private *bcm,
err = dmacontroller_setup(ring);
if (err)
goto err_free_ringmemory;
+ return ring;
out:
+ printk(KERN_ERR PFX "Error in bcm43xx_setup_dmaring\n");
return ring;
err_free_ringmemory:
@@ -705,30 +764,16 @@ int bcm43xx_dma_init(struct bcm43xx_private *bcm)
struct bcm43xx_dmaring *ring;
int err = -ENOMEM;
int dma64 = 0;
- u64 mask = bcm43xx_get_supported_dma_mask(bcm);
- int nobits;
- if (mask == DMA_64BIT_MASK) {
+ bcm->dma_mask = bcm43xx_get_supported_dma_mask(bcm);
+ if (bcm->dma_mask == DMA_64BIT_MASK)
dma64 = 1;
- nobits = 64;
- } else if (mask == DMA_32BIT_MASK)
- nobits = 32;
- else
- nobits = 30;
- err = pci_set_dma_mask(bcm->pci_dev, mask);
- err |= pci_set_consistent_dma_mask(bcm->pci_dev, mask);
- if (err) {
-#ifdef CONFIG_BCM43XX_PIO
- printk(KERN_WARNING PFX "DMA not supported on this device."
- " Falling back to PIO.\n");
- bcm->__using_pio = 1;
- return -ENOSYS;
-#else
- printk(KERN_ERR PFX "FATAL: DMA not supported and PIO not configured. "
- "Please recompile the driver with PIO support.\n");
- return -ENODEV;
-#endif /* CONFIG_BCM43XX_PIO */
- }
+ err = pci_set_dma_mask(bcm->pci_dev, bcm->dma_mask);
+ if (err)
+ goto no_dma;
+ err = pci_set_consistent_dma_mask(bcm->pci_dev, bcm->dma_mask);
+ if (err)
+ goto no_dma;
/* setup TX DMA channels. */
ring = bcm43xx_setup_dmaring(bcm, 0, 1, dma64);
@@ -774,7 +819,9 @@ int bcm43xx_dma_init(struct bcm43xx_private *bcm)
dma->rx_ring3 = ring;
}
- dprintk(KERN_INFO PFX "%d-bit DMA initialized\n", nobits);
+ dprintk(KERN_INFO PFX "%d-bit DMA initialized\n",
+ (bcm->dma_mask == DMA_64BIT_MASK) ? 64 :
+ (bcm->dma_mask == DMA_32BIT_MASK) ? 32 : 30);
err = 0;
out:
return err;
@@ -800,7 +847,17 @@ err_destroy_tx1:
err_destroy_tx0:
bcm43xx_destroy_dmaring(dma->tx_ring0);
dma->tx_ring0 = NULL;
- goto out;
+no_dma:
+#ifdef CONFIG_BCM43XX_PIO
+ printk(KERN_WARNING PFX "DMA not supported on this device."
+ " Falling back to PIO.\n");
+ bcm->__using_pio = 1;
+ return -ENOSYS;
+#else
+ printk(KERN_ERR PFX "FATAL: DMA not supported and PIO not configured. "
+ "Please recompile the driver with PIO support.\n");
+ return -ENODEV;
+#endif /* CONFIG_BCM43XX_PIO */
}
/* Generate a cookie for the TX header. */
@@ -905,6 +962,7 @@ static void dma_tx_fragment(struct bcm43xx_dmaring *ring,
struct bcm43xx_dmadesc_generic *desc;
struct bcm43xx_dmadesc_meta *meta;
dma_addr_t dmaaddr;
+ struct sk_buff *bounce_skb;
assert(skb_shinfo(skb)->nr_frags == 0);
@@ -924,9 +982,28 @@ static void dma_tx_fragment(struct bcm43xx_dmaring *ring,
skb->len - sizeof(struct bcm43xx_txhdr),
(cur_frag == 0),
generate_cookie(ring, slot));
+ dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
+ if (dma_mapping_error(dmaaddr) || dmaaddr + skb->len > ring->bcm->dma_mask) {
+ /* chip cannot handle DMA to/from > 1GB, use bounce buffer (copied from b44 driver) */
+ if (!dma_mapping_error(dmaaddr))
+ unmap_descbuffer(ring, dmaaddr, skb->len, 1);
+ bounce_skb = __dev_alloc_skb(skb->len, GFP_ATOMIC|GFP_DMA);
+ if (!bounce_skb)
+ return;
+ dmaaddr = map_descbuffer(ring, bounce_skb->data, bounce_skb->len, 1);
+ if (dma_mapping_error(dmaaddr) || dmaaddr + skb->len > ring->bcm->dma_mask) {
+ if (!dma_mapping_error(dmaaddr))
+ unmap_descbuffer(ring, dmaaddr, skb->len, 1);
+ dev_kfree_skb_any(bounce_skb);
+ assert(0);
+ return;
+ }
+ memcpy(skb_put(bounce_skb, skb->len), skb->data, skb->len);
+ dev_kfree_skb_any(skb);
+ skb = bounce_skb;
+ }
meta->skb = skb;
- dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
meta->dmaaddr = dmaaddr;
fill_descriptor(ring, desc, dmaaddr,
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_ilt.c b/drivers/net/wireless/bcm43xx/bcm43xx_ilt.c
index ad8e569d1fa..f2b8dbac55a 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_ilt.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_ilt.c
@@ -325,6 +325,21 @@ void bcm43xx_ilt_write(struct bcm43xx_private *bcm, u16 offset, u16 val)
}
}
+void bcm43xx_ilt_write32(struct bcm43xx_private *bcm, u16 offset, u32 val)
+{
+ if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A) {
+ bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_CTRL, offset);
+ mmiowb();
+ bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA2, (val & 0xFFFF0000) >> 16);
+ bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, val & 0x0000FFFF);
+ } else {
+ bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_CTRL, offset);
+ mmiowb();
+ bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_DATA2, (val & 0xFFFF0000) >> 16);
+ bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_DATA1, val & 0x0000FFFF);
+ }
+}
+
u16 bcm43xx_ilt_read(struct bcm43xx_private *bcm, u16 offset)
{
if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A) {
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_ilt.h b/drivers/net/wireless/bcm43xx/bcm43xx_ilt.h
index 464521abf73..d7eaf5f25b7 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_ilt.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_ilt.h
@@ -27,6 +27,7 @@ extern const u16 bcm43xx_ilt_sigmasqr2[BCM43xx_ILT_SIGMASQR_SIZE];
void bcm43xx_ilt_write(struct bcm43xx_private *bcm, u16 offset, u16 val);
+void bcm43xx_ilt_write32(struct bcm43xx_private *bcm, u16 offset, u32 val);
u16 bcm43xx_ilt_read(struct bcm43xx_private *bcm, u16 offset);
#endif /* BCM43xx_ILT_H_ */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c
index 7d383a27b92..8f198befba3 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c
@@ -26,6 +26,7 @@
*/
#include "bcm43xx_leds.h"
+#include "bcm43xx_radio.h"
#include "bcm43xx.h"
#include <asm/bitops.h>
@@ -108,6 +109,7 @@ static void bcm43xx_led_init_hardcoded(struct bcm43xx_private *bcm,
switch (led_index) {
case 0:
led->behaviour = BCM43xx_LED_ACTIVITY;
+ led->activelow = 1;
if (bcm->board_vendor == PCI_VENDOR_ID_COMPAQ)
led->behaviour = BCM43xx_LED_RADIO_ALL;
break;
@@ -199,20 +201,21 @@ void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity)
turn_on = activity;
break;
case BCM43xx_LED_RADIO_ALL:
- turn_on = radio->enabled;
+ turn_on = radio->enabled && bcm43xx_is_hw_radio_enabled(bcm);
break;
case BCM43xx_LED_RADIO_A:
case BCM43xx_LED_BCM4303_2:
- turn_on = (radio->enabled && phy->type == BCM43xx_PHYTYPE_A);
+ turn_on = (radio->enabled && bcm43xx_is_hw_radio_enabled(bcm) &&
+ phy->type == BCM43xx_PHYTYPE_A);
break;
case BCM43xx_LED_RADIO_B:
case BCM43xx_LED_BCM4303_1:
- turn_on = (radio->enabled &&
+ turn_on = (radio->enabled && bcm43xx_is_hw_radio_enabled(bcm) &&
(phy->type == BCM43xx_PHYTYPE_B ||
phy->type == BCM43xx_PHYTYPE_G));
break;
case BCM43xx_LED_MODE_BG:
- if (phy->type == BCM43xx_PHYTYPE_G &&
+ if (phy->type == BCM43xx_PHYTYPE_G && bcm43xx_is_hw_radio_enabled(bcm) &&
1/*FIXME: using G rates.*/)
turn_on = 1;
break;
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
index 91b752e3d07..73c831a3b74 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -95,13 +95,9 @@ static int modparam_noleds;
module_param_named(noleds, modparam_noleds, int, 0444);
MODULE_PARM_DESC(noleds, "Turn off all LED activity");
-#ifdef CONFIG_BCM43XX_DEBUG
static char modparam_fwpostfix[64];
module_param_string(fwpostfix, modparam_fwpostfix, 64, 0444);
-MODULE_PARM_DESC(fwpostfix, "Postfix for .fw files. Useful for debugging.");
-#else
-# define modparam_fwpostfix ""
-#endif /* CONFIG_BCM43XX_DEBUG*/
+MODULE_PARM_DESC(fwpostfix, "Postfix for .fw files. Useful for using multiple firmware image versions.");
/* If you want to debug with just a single device, enable this,
@@ -855,8 +851,6 @@ static int bcm43xx_sprom_extract(struct bcm43xx_private *bcm)
value = sprom[BCM43xx_SPROM_ETHPHY];
bcm->sprom.et0phyaddr = (value & 0x001F);
bcm->sprom.et1phyaddr = (value & 0x03E0) >> 5;
- bcm->sprom.et0mdcport = (value & (1 << 14)) >> 14;
- bcm->sprom.et1mdcport = (value & (1 << 15)) >> 15;
/* boardrev, antennas, locale */
value = sprom[BCM43xx_SPROM_BOARDREV];
@@ -1453,12 +1447,10 @@ static void handle_irq_transmit_status(struct bcm43xx_private *bcm)
bcm43xx_debugfs_log_txstat(bcm, &stat);
- if (stat.flags & BCM43xx_TXSTAT_FLAG_IGNORE)
+ if (stat.flags & BCM43xx_TXSTAT_FLAG_AMPDU)
+ continue;
+ if (stat.flags & BCM43xx_TXSTAT_FLAG_INTER)
continue;
- if (!(stat.flags & BCM43xx_TXSTAT_FLAG_ACK)) {
- //TODO: packet was not acked (was lost)
- }
- //TODO: There are more (unknown) flags to test. see bcm43xx_main.h
if (bcm43xx_using_pio(bcm))
bcm43xx_pio_handle_xmitstatus(bcm, &stat);
@@ -2441,6 +2433,9 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm)
if (err)
goto err_gpio_cleanup;
bcm43xx_radio_turn_on(bcm);
+ bcm->radio_hw_enable = bcm43xx_is_hw_radio_enabled(bcm);
+ dprintk(KERN_INFO PFX "Radio %s by hardware\n",
+ (bcm->radio_hw_enable == 0) ? "disabled" : "enabled");
bcm43xx_write16(bcm, 0x03E6, 0x0000);
err = bcm43xx_phy_init(bcm);
@@ -2980,8 +2975,10 @@ static int bcm43xx_chipset_attach(struct bcm43xx_private *bcm)
err = bcm43xx_pctl_set_crystal(bcm, 1);
if (err)
goto out;
- bcm43xx_pci_read_config16(bcm, PCI_STATUS, &pci_status);
- bcm43xx_pci_write_config16(bcm, PCI_STATUS, pci_status & ~PCI_STATUS_SIG_TARGET_ABORT);
+ err = bcm43xx_pci_read_config16(bcm, PCI_STATUS, &pci_status);
+ if (err)
+ goto out;
+ err = bcm43xx_pci_write_config16(bcm, PCI_STATUS, pci_status & ~PCI_STATUS_SIG_TARGET_ABORT);
out:
return err;
@@ -3175,9 +3172,24 @@ static void bcm43xx_periodic_every30sec(struct bcm43xx_private *bcm)
static void bcm43xx_periodic_every15sec(struct bcm43xx_private *bcm)
{
+ bcm43xx_phy_xmitpower(bcm); //FIXME: unless scanning?
+ //TODO for APHY (temperature?)
+}
+
+static void bcm43xx_periodic_every1sec(struct bcm43xx_private *bcm)
+{
struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+ int radio_hw_enable;
+ /* check if radio hardware enabled status changed */
+ radio_hw_enable = bcm43xx_is_hw_radio_enabled(bcm);
+ if (unlikely(bcm->radio_hw_enable != radio_hw_enable)) {
+ bcm->radio_hw_enable = radio_hw_enable;
+ dprintk(KERN_INFO PFX "Radio hardware status changed to %s\n",
+ (radio_hw_enable == 0) ? "disabled" : "enabled");
+ bcm43xx_leds_update(bcm, 0);
+ }
if (phy->type == BCM43xx_PHYTYPE_G) {
//TODO: update_aci_moving_average
if (radio->aci_enable && radio->aci_wlan_automatic) {
@@ -3201,21 +3213,21 @@ static void bcm43xx_periodic_every15sec(struct bcm43xx_private *bcm)
//TODO: implement rev1 workaround
}
}
- bcm43xx_phy_xmitpower(bcm); //FIXME: unless scanning?
- //TODO for APHY (temperature?)
}
static void do_periodic_work(struct bcm43xx_private *bcm)
{
- if (bcm->periodic_state % 8 == 0)
+ if (bcm->periodic_state % 120 == 0)
bcm43xx_periodic_every120sec(bcm);
- if (bcm->periodic_state % 4 == 0)
+ if (bcm->periodic_state % 60 == 0)
bcm43xx_periodic_every60sec(bcm);
- if (bcm->periodic_state % 2 == 0)
+ if (bcm->periodic_state % 30 == 0)
bcm43xx_periodic_every30sec(bcm);
- bcm43xx_periodic_every15sec(bcm);
+ if (bcm->periodic_state % 15 == 0)
+ bcm43xx_periodic_every15sec(bcm);
+ bcm43xx_periodic_every1sec(bcm);
- schedule_delayed_work(&bcm->periodic_work, HZ * 15);
+ schedule_delayed_work(&bcm->periodic_work, HZ);
}
static void bcm43xx_periodic_work_handler(struct work_struct *work)
@@ -3228,7 +3240,7 @@ static void bcm43xx_periodic_work_handler(struct work_struct *work)
unsigned long orig_trans_start = 0;
mutex_lock(&bcm->mutex);
- if (unlikely(bcm->periodic_state % 4 == 0)) {
+ if (unlikely(bcm->periodic_state % 60 == 0)) {
/* Periodic work will take a long time, so we want it to
* be preemtible.
*/
@@ -3260,7 +3272,7 @@ static void bcm43xx_periodic_work_handler(struct work_struct *work)
do_periodic_work(bcm);
- if (unlikely(bcm->periodic_state % 4 == 0)) {
+ if (unlikely(bcm->periodic_state % 60 == 0)) {
spin_lock_irqsave(&bcm->irq_lock, flags);
tasklet_enable(&bcm->isr_tasklet);
bcm43xx_interrupt_enable(bcm, savedirqs);
@@ -3680,7 +3692,7 @@ static int bcm43xx_read_phyinfo(struct bcm43xx_private *bcm)
{
struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
u16 value;
- u8 phy_version;
+ u8 phy_analog;
u8 phy_type;
u8 phy_rev;
int phy_rev_ok = 1;
@@ -3688,12 +3700,12 @@ static int bcm43xx_read_phyinfo(struct bcm43xx_private *bcm)
value = bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_VER);
- phy_version = (value & 0xF000) >> 12;
+ phy_analog = (value & 0xF000) >> 12;
phy_type = (value & 0x0F00) >> 8;
phy_rev = (value & 0x000F);
- dprintk(KERN_INFO PFX "Detected PHY: Version: %x, Type %x, Revision %x\n",
- phy_version, phy_type, phy_rev);
+ dprintk(KERN_INFO PFX "Detected PHY: Analog: %x, Type %x, Revision %x\n",
+ phy_analog, phy_type, phy_rev);
switch (phy_type) {
case BCM43xx_PHYTYPE_A:
@@ -3736,7 +3748,7 @@ static int bcm43xx_read_phyinfo(struct bcm43xx_private *bcm)
phy_rev);
}
- phy->version = phy_version;
+ phy->analog = phy_analog;
phy->type = phy_type;
phy->rev = phy_rev;
if ((phy_type == BCM43xx_PHYTYPE_B) || (phy_type == BCM43xx_PHYTYPE_G)) {
@@ -3778,12 +3790,18 @@ static int bcm43xx_attach_board(struct bcm43xx_private *bcm)
}
net_dev->base_addr = (unsigned long)bcm->mmio_addr;
- bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_VENDOR_ID,
+ err = bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_VENDOR_ID,
&bcm->board_vendor);
- bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_ID,
+ if (err)
+ goto err_iounmap;
+ err = bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_ID,
&bcm->board_type);
- bcm43xx_pci_read_config16(bcm, PCI_REVISION_ID,
+ if (err)
+ goto err_iounmap;
+ err = bcm43xx_pci_read_config16(bcm, PCI_REVISION_ID,
&bcm->board_revision);
+ if (err)
+ goto err_iounmap;
err = bcm43xx_chipset_attach(bcm);
if (err)
@@ -3874,6 +3892,7 @@ err_pci_release:
pci_release_regions(pci_dev);
err_pci_disable:
pci_disable_device(pci_dev);
+ printk(KERN_ERR PFX "Unable to attach board\n");
goto out;
}
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
index 52ce2a9334f..3a5c9c2b215 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
@@ -205,8 +205,8 @@ static void bcm43xx_phy_init_pctl(struct bcm43xx_private *bcm)
(bcm->board_type == 0x0416))
return;
- bcm43xx_write16(bcm, 0x03E6, bcm43xx_read16(bcm, 0x03E6) & 0xFFDF);
bcm43xx_phy_write(bcm, 0x0028, 0x8018);
+ bcm43xx_write16(bcm, 0x03E6, bcm43xx_read16(bcm, 0x03E6) & 0xFFDF);
if (phy->type == BCM43xx_PHYTYPE_G) {
if (!phy->connected)
@@ -317,6 +317,13 @@ static void bcm43xx_phy_agcsetup(struct bcm43xx_private *bcm)
bcm43xx_ilt_write(bcm, offset + 0x0801, 7);
bcm43xx_ilt_write(bcm, offset + 0x0802, 16);
bcm43xx_ilt_write(bcm, offset + 0x0803, 28);
+
+ if (phy->rev >= 6) {
+ bcm43xx_phy_write(bcm, 0x0426, (bcm43xx_phy_read(bcm, 0x0426)
+ & 0xFFFC));
+ bcm43xx_phy_write(bcm, 0x0426, (bcm43xx_phy_read(bcm, 0x0426)
+ & 0xEFFF));
+ }
}
static void bcm43xx_phy_setupg(struct bcm43xx_private *bcm)
@@ -337,7 +344,7 @@ static void bcm43xx_phy_setupg(struct bcm43xx_private *bcm)
for (i = 0; i < BCM43xx_ILT_NOISEG1_SIZE; i++)
bcm43xx_ilt_write(bcm, 0x1800 + i, bcm43xx_ilt_noiseg1[i]);
for (i = 0; i < BCM43xx_ILT_ROTOR_SIZE; i++)
- bcm43xx_ilt_write(bcm, 0x2000 + i, bcm43xx_ilt_rotor[i]);
+ bcm43xx_ilt_write32(bcm, 0x2000 + i, bcm43xx_ilt_rotor[i]);
} else {
/* nrssi values are signed 6-bit values. Not sure why we write 0x7654 here... */
bcm43xx_nrssi_hw_write(bcm, 0xBA98, (s16)0x7654);
@@ -377,7 +384,7 @@ static void bcm43xx_phy_setupg(struct bcm43xx_private *bcm)
if (phy->rev == 1) {
for (i = 0; i < BCM43xx_ILT_RETARD_SIZE; i++)
- bcm43xx_ilt_write(bcm, 0x2400 + i, bcm43xx_ilt_retard[i]);
+ bcm43xx_ilt_write32(bcm, 0x2400 + i, bcm43xx_ilt_retard[i]);
for (i = 0; i < 4; i++) {
bcm43xx_ilt_write(bcm, 0x5404 + i, 0x0020);
bcm43xx_ilt_write(bcm, 0x5408 + i, 0x0020);
@@ -500,10 +507,10 @@ static void bcm43xx_phy_setupa(struct bcm43xx_private *bcm)
for (i = 0; i < BCM43xx_ILT_NOISEA2_SIZE; i++)
bcm43xx_ilt_write(bcm, 0x1800 + i, bcm43xx_ilt_noisea2[i]);
for (i = 0; i < BCM43xx_ILT_ROTOR_SIZE; i++)
- bcm43xx_ilt_write(bcm, 0x2000 + i, bcm43xx_ilt_rotor[i]);
+ bcm43xx_ilt_write32(bcm, 0x2000 + i, bcm43xx_ilt_rotor[i]);
bcm43xx_phy_init_noisescaletbl(bcm);
for (i = 0; i < BCM43xx_ILT_RETARD_SIZE; i++)
- bcm43xx_ilt_write(bcm, 0x2400 + i, bcm43xx_ilt_retard[i]);
+ bcm43xx_ilt_write32(bcm, 0x2400 + i, bcm43xx_ilt_retard[i]);
break;
case 3:
for (i = 0; i < 64; i++)
@@ -729,19 +736,19 @@ static void bcm43xx_phy_initb5(struct bcm43xx_private *bcm)
struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
u16 offset;
+ u16 value;
+ u8 old_channel;
- if (phy->version == 1 &&
- radio->version == 0x2050) {
+ if (phy->analog == 1)
bcm43xx_radio_write16(bcm, 0x007A,
bcm43xx_radio_read16(bcm, 0x007A)
| 0x0050);
- }
if ((bcm->board_vendor != PCI_VENDOR_ID_BROADCOM) &&
(bcm->board_type != 0x0416)) {
+ value = 0x2120;
for (offset = 0x00A8 ; offset < 0x00C7; offset++) {
- bcm43xx_phy_write(bcm, offset,
- (bcm43xx_phy_read(bcm, offset) + 0x2020)
- & 0x3F3F);
+ bcm43xx_phy_write(bcm, offset, value);
+ value += 0x0202;
}
}
bcm43xx_phy_write(bcm, 0x0035,
@@ -750,7 +757,7 @@ static void bcm43xx_phy_initb5(struct bcm43xx_private *bcm)
if (radio->version == 0x2050)
bcm43xx_phy_write(bcm, 0x0038, 0x0667);
- if (phy->connected) {
+ if (phy->type == BCM43xx_PHYTYPE_G) {
if (radio->version == 0x2050) {
bcm43xx_radio_write16(bcm, 0x007A,
bcm43xx_radio_read16(bcm, 0x007A)
@@ -776,7 +783,7 @@ static void bcm43xx_phy_initb5(struct bcm43xx_private *bcm)
bcm43xx_phy_read(bcm, BCM43xx_PHY_RADIO_BITFIELD) | (1 << 11));
}
- if (phy->version == 1 && radio->version == 0x2050) {
+ if (phy->analog == 1) {
bcm43xx_phy_write(bcm, 0x0026, 0xCE00);
bcm43xx_phy_write(bcm, 0x0021, 0x3763);
bcm43xx_phy_write(bcm, 0x0022, 0x1BC3);
@@ -787,14 +794,15 @@ static void bcm43xx_phy_initb5(struct bcm43xx_private *bcm)
bcm43xx_phy_write(bcm, 0x0030, 0x00C6);
bcm43xx_write16(bcm, 0x03EC, 0x3F22);
- if (phy->version == 1 && radio->version == 0x2050)
+ if (phy->analog == 1)
bcm43xx_phy_write(bcm, 0x0020, 0x3E1C);
else
bcm43xx_phy_write(bcm, 0x0020, 0x301C);
- if (phy->version == 0)
+ if (phy->analog == 0)
bcm43xx_write16(bcm, 0x03E4, 0x3000);
+ old_channel = radio->channel;
/* Force to channel 7, even if not supported. */
bcm43xx_radio_selectchannel(bcm, 7, 0);
@@ -816,11 +824,11 @@ static void bcm43xx_phy_initb5(struct bcm43xx_private *bcm)
bcm43xx_radio_write16(bcm, 0x007A, bcm43xx_radio_read16(bcm, 0x007A) | 0x0007);
- bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_BG, 0);
+ bcm43xx_radio_selectchannel(bcm, old_channel, 0);
bcm43xx_phy_write(bcm, 0x0014, 0x0080);
bcm43xx_phy_write(bcm, 0x0032, 0x00CA);
- bcm43xx_phy_write(bcm, 0x88A3, 0x002A);
+ bcm43xx_phy_write(bcm, 0x002A, 0x88A3);
bcm43xx_radio_set_txpower_bg(bcm, 0xFFFF, 0xFFFF, 0xFFFF);
@@ -835,61 +843,24 @@ static void bcm43xx_phy_initb6(struct bcm43xx_private *bcm)
struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
u16 offset, val;
+ u8 old_channel;
bcm43xx_phy_write(bcm, 0x003E, 0x817A);
bcm43xx_radio_write16(bcm, 0x007A,
(bcm43xx_radio_read16(bcm, 0x007A) | 0x0058));
- if ((radio->manufact == 0x17F) &&
- (radio->version == 0x2050) &&
- (radio->revision == 3 ||
- radio->revision == 4 ||
- radio->revision == 5)) {
- bcm43xx_radio_write16(bcm, 0x0051, 0x001F);
- bcm43xx_radio_write16(bcm, 0x0052, 0x0040);
- bcm43xx_radio_write16(bcm, 0x0053, 0x005B);
- bcm43xx_radio_write16(bcm, 0x0054, 0x0098);
+ if (radio->revision == 4 ||
+ radio->revision == 5) {
+ bcm43xx_radio_write16(bcm, 0x0051, 0x0037);
+ bcm43xx_radio_write16(bcm, 0x0052, 0x0070);
+ bcm43xx_radio_write16(bcm, 0x0053, 0x00B3);
+ bcm43xx_radio_write16(bcm, 0x0054, 0x009B);
bcm43xx_radio_write16(bcm, 0x005A, 0x0088);
bcm43xx_radio_write16(bcm, 0x005B, 0x0088);
bcm43xx_radio_write16(bcm, 0x005D, 0x0088);
bcm43xx_radio_write16(bcm, 0x005E, 0x0088);
bcm43xx_radio_write16(bcm, 0x007D, 0x0088);
}
- if ((radio->manufact == 0x17F) &&
- (radio->version == 0x2050) &&
- (radio->revision == 6)) {
- bcm43xx_radio_write16(bcm, 0x0051, 0x0000);
- bcm43xx_radio_write16(bcm, 0x0052, 0x0040);
- bcm43xx_radio_write16(bcm, 0x0053, 0x00B7);
- bcm43xx_radio_write16(bcm, 0x0054, 0x0098);
- bcm43xx_radio_write16(bcm, 0x005A, 0x0088);
- bcm43xx_radio_write16(bcm, 0x005B, 0x008B);
- bcm43xx_radio_write16(bcm, 0x005C, 0x00B5);
- bcm43xx_radio_write16(bcm, 0x005D, 0x0088);
- bcm43xx_radio_write16(bcm, 0x005E, 0x0088);
- bcm43xx_radio_write16(bcm, 0x007D, 0x0088);
- bcm43xx_radio_write16(bcm, 0x007C, 0x0001);
- bcm43xx_radio_write16(bcm, 0x007E, 0x0008);
- }
- if ((radio->manufact == 0x17F) &&
- (radio->version == 0x2050) &&
- (radio->revision == 7)) {
- bcm43xx_radio_write16(bcm, 0x0051, 0x0000);
- bcm43xx_radio_write16(bcm, 0x0052, 0x0040);
- bcm43xx_radio_write16(bcm, 0x0053, 0x00B7);
- bcm43xx_radio_write16(bcm, 0x0054, 0x0098);
- bcm43xx_radio_write16(bcm, 0x005A, 0x0088);
- bcm43xx_radio_write16(bcm, 0x005B, 0x00A8);
- bcm43xx_radio_write16(bcm, 0x005C, 0x0075);
- bcm43xx_radio_write16(bcm, 0x005D, 0x00F5);
- bcm43xx_radio_write16(bcm, 0x005E, 0x00B8);
- bcm43xx_radio_write16(bcm, 0x007D, 0x00E8);
- bcm43xx_radio_write16(bcm, 0x007C, 0x0001);
- bcm43xx_radio_write16(bcm, 0x007E, 0x0008);
- bcm43xx_radio_write16(bcm, 0x007B, 0x0000);
- }
- if ((radio->manufact == 0x17F) &&
- (radio->version == 0x2050) &&
- (radio->revision == 8)) {
+ if (radio->revision == 8) {
bcm43xx_radio_write16(bcm, 0x0051, 0x0000);
bcm43xx_radio_write16(bcm, 0x0052, 0x0040);
bcm43xx_radio_write16(bcm, 0x0053, 0x00B7);
@@ -933,20 +904,26 @@ static void bcm43xx_phy_initb6(struct bcm43xx_private *bcm)
bcm43xx_phy_read(bcm, 0x0802) | 0x0100);
bcm43xx_phy_write(bcm, 0x042B,
bcm43xx_phy_read(bcm, 0x042B) | 0x2000);
+ bcm43xx_phy_write(bcm, 0x5B, 0x0000);
+ bcm43xx_phy_write(bcm, 0x5C, 0x0000);
}
- /* Force to channel 7, even if not supported. */
- bcm43xx_radio_selectchannel(bcm, 7, 0);
+ old_channel = radio->channel;
+ if (old_channel >= 8)
+ bcm43xx_radio_selectchannel(bcm, 1, 0);
+ else
+ bcm43xx_radio_selectchannel(bcm, 13, 0);
bcm43xx_radio_write16(bcm, 0x0050, 0x0020);
bcm43xx_radio_write16(bcm, 0x0050, 0x0023);
udelay(40);
- bcm43xx_radio_write16(bcm, 0x007C, (bcm43xx_radio_read16(bcm, 0x007C) | 0x0002));
- bcm43xx_radio_write16(bcm, 0x0050, 0x0020);
- if (radio->manufact == 0x17F &&
- radio->version == 0x2050 &&
- radio->revision <= 2) {
+ if (radio->revision < 6 || radio-> revision == 8) {
+ bcm43xx_radio_write16(bcm, 0x007C, (bcm43xx_radio_read16(bcm, 0x007C)
+ | 0x0002));
bcm43xx_radio_write16(bcm, 0x0050, 0x0020);
+ }
+ if (radio->revision <= 2) {
+ bcm43xx_radio_write16(bcm, 0x007C, 0x0020);
bcm43xx_radio_write16(bcm, 0x005A, 0x0070);
bcm43xx_radio_write16(bcm, 0x005B, 0x007B);
bcm43xx_radio_write16(bcm, 0x005C, 0x00B0);
@@ -954,46 +931,41 @@ static void bcm43xx_phy_initb6(struct bcm43xx_private *bcm)
bcm43xx_radio_write16(bcm, 0x007A,
(bcm43xx_radio_read16(bcm, 0x007A) & 0x00F8) | 0x0007);
- bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_BG, 0);
+ bcm43xx_radio_selectchannel(bcm, old_channel, 0);
bcm43xx_phy_write(bcm, 0x0014, 0x0200);
- if (radio->version == 0x2050){
- if (radio->revision == 3 ||
- radio->revision == 4 ||
- radio->revision == 5)
- bcm43xx_phy_write(bcm, 0x002A, 0x8AC0);
- else
- bcm43xx_phy_write(bcm, 0x002A, 0x88C2);
- }
+ if (radio->revision >= 6)
+ bcm43xx_phy_write(bcm, 0x002A, 0x88C2);
+ else
+ bcm43xx_phy_write(bcm, 0x002A, 0x8AC0);
bcm43xx_phy_write(bcm, 0x0038, 0x0668);
bcm43xx_radio_set_txpower_bg(bcm, 0xFFFF, 0xFFFF, 0xFFFF);
- if (radio->version == 0x2050) {
- if (radio->revision == 3 ||
- radio->revision == 4 ||
- radio->revision == 5)
- bcm43xx_phy_write(bcm, 0x005D, bcm43xx_phy_read(bcm, 0x005D) | 0x0003);
- else if (radio->revision <= 2)
- bcm43xx_radio_write16(bcm, 0x005D, 0x000D);
- }
+ if (radio->revision <= 5)
+ bcm43xx_phy_write(bcm, 0x005D, bcm43xx_phy_read(bcm, 0x005D) | 0x0003);
+ if (radio->revision <= 2)
+ bcm43xx_radio_write16(bcm, 0x005D, 0x000D);
- if (phy->rev == 4)
- bcm43xx_phy_write(bcm, 0x0002, (bcm43xx_phy_read(bcm, 0x0002) & 0xFFC0) | 0x0004);
- else
+ if (phy->analog == 4){
bcm43xx_write16(bcm, 0x03E4, 0x0009);
+ bcm43xx_phy_write(bcm, 0x61, bcm43xx_phy_read(bcm, 0x61) & 0xFFF);
+ } else {
+ bcm43xx_phy_write(bcm, 0x0002, (bcm43xx_phy_read(bcm, 0x0002) & 0xFFC0) | 0x0004);
+ }
+ if (phy->type == BCM43xx_PHYTYPE_G)
+ bcm43xx_write16(bcm, 0x03E6, 0x0);
if (phy->type == BCM43xx_PHYTYPE_B) {
bcm43xx_write16(bcm, 0x03E6, 0x8140);
bcm43xx_phy_write(bcm, 0x0016, 0x0410);
bcm43xx_phy_write(bcm, 0x0017, 0x0820);
bcm43xx_phy_write(bcm, 0x0062, 0x0007);
(void) bcm43xx_radio_calibrationvalue(bcm);
- bcm43xx_phy_lo_b_measure(bcm);
+ bcm43xx_phy_lo_g_measure(bcm);
if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) {
bcm43xx_calc_nrssi_slope(bcm);
bcm43xx_calc_nrssi_threshold(bcm);
}
bcm43xx_phy_init_pctl(bcm);
- } else
- bcm43xx_write16(bcm, 0x03E6, 0x0);
+ }
}
static void bcm43xx_calc_loopback_gain(struct bcm43xx_private *bcm)
@@ -1063,7 +1035,7 @@ static void bcm43xx_calc_loopback_gain(struct bcm43xx_private *bcm)
bcm43xx_phy_write(bcm, 0x005A, 0x0780);
bcm43xx_phy_write(bcm, 0x0059, 0xC810);
bcm43xx_phy_write(bcm, 0x0058, 0x000D);
- if (phy->version == 0) {
+ if (phy->analog == 0) {
bcm43xx_phy_write(bcm, 0x0003, 0x0122);
} else {
bcm43xx_phy_write(bcm, 0x000A,
@@ -1205,27 +1177,30 @@ static void bcm43xx_phy_initg(struct bcm43xx_private *bcm)
if (phy->rev >= 2) {
bcm43xx_phy_write(bcm, 0x0814, 0x0000);
bcm43xx_phy_write(bcm, 0x0815, 0x0000);
- if (phy->rev == 2)
- bcm43xx_phy_write(bcm, 0x0811, 0x0000);
- else if (phy->rev >= 3)
- bcm43xx_phy_write(bcm, 0x0811, 0x0400);
+ }
+ if (phy->rev == 2) {
+ bcm43xx_phy_write(bcm, 0x0811, 0x0000);
bcm43xx_phy_write(bcm, 0x0015, 0x00C0);
- if (phy->connected) {
- tmp = bcm43xx_phy_read(bcm, 0x0400) & 0xFF;
- if (tmp < 6) {
- bcm43xx_phy_write(bcm, 0x04C2, 0x1816);
- bcm43xx_phy_write(bcm, 0x04C3, 0x8006);
- if (tmp != 3) {
- bcm43xx_phy_write(bcm, 0x04CC,
- (bcm43xx_phy_read(bcm, 0x04CC)
- & 0x00FF) | 0x1F00);
- }
+ }
+ if (phy->rev >= 3) {
+ bcm43xx_phy_write(bcm, 0x0811, 0x0400);
+ bcm43xx_phy_write(bcm, 0x0015, 0x00C0);
+ }
+ if (phy->connected) {
+ tmp = bcm43xx_phy_read(bcm, 0x0400) & 0xFF;
+ if (tmp < 6) {
+ bcm43xx_phy_write(bcm, 0x04C2, 0x1816);
+ bcm43xx_phy_write(bcm, 0x04C3, 0x8006);
+ if (tmp != 3) {
+ bcm43xx_phy_write(bcm, 0x04CC,
+ (bcm43xx_phy_read(bcm, 0x04CC)
+ & 0x00FF) | 0x1F00);
}
}
}
if (phy->rev < 3 && phy->connected)
bcm43xx_phy_write(bcm, 0x047E, 0x0078);
- if (phy->rev >= 6 && phy->rev <= 8) {
+ if (radio->revision == 8) {
bcm43xx_phy_write(bcm, 0x0801, bcm43xx_phy_read(bcm, 0x0801) | 0x0080);
bcm43xx_phy_write(bcm, 0x043E, bcm43xx_phy_read(bcm, 0x043E) | 0x0004);
}
@@ -1638,14 +1613,14 @@ void bcm43xx_phy_set_baseband_attenuation(struct bcm43xx_private *bcm,
struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
u16 value;
- if (phy->version == 0) {
+ if (phy->analog == 0) {
value = (bcm43xx_read16(bcm, 0x03E6) & 0xFFF0);
value |= (baseband_attenuation & 0x000F);
bcm43xx_write16(bcm, 0x03E6, value);
return;
}
- if (phy->version > 1) {
+ if (phy->analog > 1) {
value = bcm43xx_phy_read(bcm, 0x0060) & ~0x003C;
value |= (baseband_attenuation << 2) & 0x003C;
} else {
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
index bb9c484d7e1..32beb91b716 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
@@ -1393,11 +1393,12 @@ u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
backup[12] = bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT);
// Initialization
- if (phy->version == 0) {
+ if (phy->analog == 0) {
bcm43xx_write16(bcm, 0x03E6, 0x0122);
} else {
- if (phy->version >= 2)
- bcm43xx_write16(bcm, 0x03E6, 0x0040);
+ if (phy->analog >= 2)
+ bcm43xx_phy_write(bcm, 0x0003, (bcm43xx_phy_read(bcm, 0x0003)
+ & 0xFFBF) | 0x0040);
bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT,
(bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT) | 0x2000));
}
@@ -1405,7 +1406,7 @@ u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
ret = bcm43xx_radio_calibrationvalue(bcm);
if (phy->type == BCM43xx_PHYTYPE_B)
- bcm43xx_radio_write16(bcm, 0x0078, 0x0003);
+ bcm43xx_radio_write16(bcm, 0x0078, 0x0026);
bcm43xx_phy_write(bcm, 0x0015, 0xBFAF);
bcm43xx_phy_write(bcm, 0x002B, 0x1403);
@@ -1416,7 +1417,7 @@ u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
(bcm43xx_radio_read16(bcm, 0x0051) | 0x0004));
bcm43xx_radio_write16(bcm, 0x0052, 0x0000);
bcm43xx_radio_write16(bcm, 0x0043,
- bcm43xx_radio_read16(bcm, 0x0043) | 0x0009);
+ (bcm43xx_radio_read16(bcm, 0x0043) & 0xFFF0) | 0x0009);
bcm43xx_phy_write(bcm, 0x0058, 0x0000);
for (i = 0; i < 16; i++) {
@@ -1488,7 +1489,7 @@ u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
bcm43xx_phy_write(bcm, 0x0059, backup[17]);
bcm43xx_phy_write(bcm, 0x0058, backup[18]);
bcm43xx_write16(bcm, 0x03E6, backup[11]);
- if (phy->version != 0)
+ if (phy->analog != 0)
bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, backup[12]);
bcm43xx_phy_write(bcm, 0x0035, backup[10]);
bcm43xx_radio_selectchannel(bcm, radio->channel, 1);
@@ -1981,6 +1982,7 @@ void bcm43xx_radio_turn_on(struct bcm43xx_private *bcm)
}
radio->enabled = 1;
dprintk(KERN_INFO PFX "Radio turned on\n");
+ bcm43xx_leds_update(bcm, 0);
}
void bcm43xx_radio_turn_off(struct bcm43xx_private *bcm)
@@ -2001,6 +2003,7 @@ void bcm43xx_radio_turn_off(struct bcm43xx_private *bcm)
bcm43xx_phy_write(bcm, 0x0015, 0xAA00);
radio->enabled = 0;
dprintk(KERN_INFO PFX "Radio turned off\n");
+ bcm43xx_leds_update(bcm, 0);
}
void bcm43xx_radio_clear_tssi(struct bcm43xx_private *bcm)
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.h b/drivers/net/wireless/bcm43xx/bcm43xx_radio.h
index 9ed18039fa3..77a98a53a2e 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_radio.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.h
@@ -65,6 +65,22 @@ void bcm43xx_radio_init2060(struct bcm43xx_private *bcm);
void bcm43xx_radio_turn_on(struct bcm43xx_private *bcm);
void bcm43xx_radio_turn_off(struct bcm43xx_private *bcm);
+static inline
+int bcm43xx_is_hw_radio_enabled(struct bcm43xx_private *bcm)
+{
+ /* function to return state of hardware enable of radio
+ * returns 0 if radio disabled, 1 if radio enabled
+ */
+ if (bcm->current_core->rev >= 3)
+ return ((bcm43xx_read32(bcm, BCM43xx_MMIO_RADIO_HWENABLED_HI)
+ & BCM43xx_MMIO_RADIO_HWENABLED_HI_MASK)
+ == 0) ? 1 : 0;
+ else
+ return ((bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_HWENABLED_LO)
+ & BCM43xx_MMIO_RADIO_HWENABLED_LO_MASK)
+ == 0) ? 0 : 1;
+}
+
int bcm43xx_radio_selectchannel(struct bcm43xx_private *bcm, u8 channel,
int synthetic_pu_workaround);
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
index a659442b9c1..7b665e2386a 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
@@ -33,7 +33,6 @@
#include <net/ieee80211softmac.h>
#include <net/ieee80211softmac_wx.h>
#include <linux/capability.h>
-#include <linux/sched.h> /* for capable() */
#include <linux/delay.h>
#include "bcm43xx.h"
@@ -261,22 +260,22 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev,
if (phy->type == BCM43xx_PHYTYPE_A ||
phy->type == BCM43xx_PHYTYPE_G) {
range->num_bitrates = 8;
- range->bitrate[i++] = IEEE80211_OFDM_RATE_6MB;
- range->bitrate[i++] = IEEE80211_OFDM_RATE_9MB;
- range->bitrate[i++] = IEEE80211_OFDM_RATE_12MB;
- range->bitrate[i++] = IEEE80211_OFDM_RATE_18MB;
- range->bitrate[i++] = IEEE80211_OFDM_RATE_24MB;
- range->bitrate[i++] = IEEE80211_OFDM_RATE_36MB;
- range->bitrate[i++] = IEEE80211_OFDM_RATE_48MB;
- range->bitrate[i++] = IEEE80211_OFDM_RATE_54MB;
+ range->bitrate[i++] = IEEE80211_OFDM_RATE_6MB * 500000;
+ range->bitrate[i++] = IEEE80211_OFDM_RATE_9MB * 500000;
+ range->bitrate[i++] = IEEE80211_OFDM_RATE_12MB * 500000;
+ range->bitrate[i++] = IEEE80211_OFDM_RATE_18MB * 500000;
+ range->bitrate[i++] = IEEE80211_OFDM_RATE_24MB * 500000;
+ range->bitrate[i++] = IEEE80211_OFDM_RATE_36MB * 500000;
+ range->bitrate[i++] = IEEE80211_OFDM_RATE_48MB * 500000;
+ range->bitrate[i++] = IEEE80211_OFDM_RATE_54MB * 500000;
}
if (phy->type == BCM43xx_PHYTYPE_B ||
phy->type == BCM43xx_PHYTYPE_G) {
range->num_bitrates += 4;
- range->bitrate[i++] = IEEE80211_CCK_RATE_1MB;
- range->bitrate[i++] = IEEE80211_CCK_RATE_2MB;
- range->bitrate[i++] = IEEE80211_CCK_RATE_5MB;
- range->bitrate[i++] = IEEE80211_CCK_RATE_11MB;
+ range->bitrate[i++] = IEEE80211_CCK_RATE_1MB * 500000;
+ range->bitrate[i++] = IEEE80211_CCK_RATE_2MB * 500000;
+ range->bitrate[i++] = IEEE80211_CCK_RATE_5MB * 500000;
+ range->bitrate[i++] = IEEE80211_CCK_RATE_11MB * 500000;
}
geo = ieee80211_get_geo(bcm->ieee);
@@ -286,7 +285,7 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev,
if (j == IW_MAX_FREQUENCIES)
break;
range->freq[j].i = j + 1;
- range->freq[j].m = geo->a[i].freq;//FIXME?
+ range->freq[j].m = geo->a[i].freq * 100000;
range->freq[j].e = 1;
j++;
}
@@ -294,7 +293,7 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev,
if (j == IW_MAX_FREQUENCIES)
break;
range->freq[j].i = j + 1;
- range->freq[j].m = geo->bg[i].freq;//FIXME?
+ range->freq[j].m = geo->bg[i].freq * 100000;
range->freq[j].e = 1;
j++;
}
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.h b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.h
index 2aed19e35c7..9ecf2bf0d25 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.h
@@ -137,14 +137,8 @@ struct bcm43xx_xmitstatus {
u16 unknown; //FIXME
};
-#define BCM43xx_TXSTAT_FLAG_ACK 0x01
-//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x02
-//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x04
-//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x08
-//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x10
-#define BCM43xx_TXSTAT_FLAG_IGNORE 0x20
-//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x40
-//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x80
+#define BCM43xx_TXSTAT_FLAG_AMPDU 0x10
+#define BCM43xx_TXSTAT_FLAG_INTER 0x20
u8 bcm43xx_plcp_get_ratecode_cck(const u8 bitrate);
u8 bcm43xx_plcp_get_ratecode_ofdm(const u8 bitrate);
diff --git a/drivers/net/wireless/hostap/hostap.h b/drivers/net/wireless/hostap/hostap.h
index e89c890d16f..ef37a75d550 100644
--- a/drivers/net/wireless/hostap/hostap.h
+++ b/drivers/net/wireless/hostap/hostap.h
@@ -2,13 +2,14 @@
#define HOSTAP_H
#include <linux/ethtool.h>
+#include <linux/kernel.h>
#include "hostap_wlan.h"
#include "hostap_ap.h"
static const long freq_list[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442,
2447, 2452, 2457, 2462, 2467, 2472, 2484 };
-#define FREQ_COUNT (sizeof(freq_list) / sizeof(freq_list[0]))
+#define FREQ_COUNT ARRAY_SIZE(freq_list)
/* hostap.c */
diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c
index 04c19cefa1d..9077e6edde3 100644
--- a/drivers/net/wireless/hostap/hostap_main.c
+++ b/drivers/net/wireless/hostap/hostap_main.c
@@ -84,7 +84,7 @@ struct net_device * hostap_add_interface(struct local_info *local,
if (strchr(dev->name, '%'))
ret = dev_alloc_name(dev, dev->name);
- SET_NETDEV_DEV(dev, mdev->class_dev.dev);
+ SET_NETDEV_DEV(dev, mdev->dev.parent);
if (ret >= 0)
ret = register_netdevice(dev);
diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c
index b85857a8487..ad6e4a42835 100644
--- a/drivers/net/wireless/ipw2100.c
+++ b/drivers/net/wireless/ipw2100.c
@@ -175,7 +175,7 @@ that only one external action is invoked at a time.
/* Debugging stuff */
#ifdef CONFIG_IPW2100_DEBUG
-#define CONFIG_IPW2100_RX_DEBUG /* Reception debugging */
+#define IPW2100_RX_DEBUG /* Reception debugging */
#endif
MODULE_DESCRIPTION(DRV_DESCRIPTION);
@@ -2239,7 +2239,7 @@ static void ipw2100_snapshot_free(struct ipw2100_priv *priv)
priv->snapshot[0] = NULL;
}
-#ifdef CONFIG_IPW2100_DEBUG_C3
+#ifdef IPW2100_DEBUG_C3
static int ipw2100_snapshot_alloc(struct ipw2100_priv *priv)
{
int i;
@@ -2314,13 +2314,13 @@ static u32 ipw2100_match_buf(struct ipw2100_priv *priv, u8 * in_buf,
* The size of the constructed ethernet
*
*/
-#ifdef CONFIG_IPW2100_RX_DEBUG
+#ifdef IPW2100_RX_DEBUG
static u8 packet_data[IPW_RX_NIC_BUFFER_LENGTH];
#endif
static void ipw2100_corruption_detected(struct ipw2100_priv *priv, int i)
{
-#ifdef CONFIG_IPW2100_DEBUG_C3
+#ifdef IPW2100_DEBUG_C3
struct ipw2100_status *status = &priv->status_queue.drv[i];
u32 match, reg;
int j;
@@ -2342,7 +2342,7 @@ static void ipw2100_corruption_detected(struct ipw2100_priv *priv, int i)
}
#endif
-#ifdef CONFIG_IPW2100_DEBUG_C3
+#ifdef IPW2100_DEBUG_C3
/* Halt the fimrware so we can get a good image */
write_register(priv->net_dev, IPW_REG_RESET_REG,
IPW_AUX_HOST_RESET_REG_STOP_MASTER);
@@ -2413,7 +2413,7 @@ static void isr_rx(struct ipw2100_priv *priv, int i,
skb_put(packet->skb, status->frame_size);
-#ifdef CONFIG_IPW2100_RX_DEBUG
+#ifdef IPW2100_RX_DEBUG
/* Make a copy of the frame so we can dump it to the logs if
* ieee80211_rx fails */
memcpy(packet_data, packet->skb->data,
@@ -2421,7 +2421,7 @@ static void isr_rx(struct ipw2100_priv *priv, int i,
#endif
if (!ieee80211_rx(priv->ieee, packet->skb, stats)) {
-#ifdef CONFIG_IPW2100_RX_DEBUG
+#ifdef IPW2100_RX_DEBUG
IPW_DEBUG_DROP("%s: Non consumed packet:\n",
priv->net_dev->name);
printk_buf(IPW_DL_DROP, packet_data, status->frame_size);
@@ -2888,7 +2888,7 @@ static int __ipw2100_tx_process(struct ipw2100_priv *priv)
#ifdef CONFIG_IPW2100_DEBUG
if (packet->info.c_struct.cmd->host_command_reg <
- sizeof(command_types) / sizeof(*command_types))
+ ARRAY_SIZE(command_types))
IPW_DEBUG_TX("Command '%s (%d)' processed: %d.\n",
command_types[packet->info.c_struct.cmd->
host_command_reg],
@@ -3736,7 +3736,7 @@ static ssize_t show_registers(struct device *d, struct device_attribute *attr,
out += sprintf(out, "%30s [Address ] : Hex\n", "Register");
- for (i = 0; i < (sizeof(hw_data) / sizeof(*hw_data)); i++) {
+ for (i = 0; i < ARRAY_SIZE(hw_data); i++) {
read_register(dev, hw_data[i].addr, &val);
out += sprintf(out, "%30s [%08X] : %08X\n",
hw_data[i].name, hw_data[i].addr, val);
@@ -3757,7 +3757,7 @@ static ssize_t show_hardware(struct device *d, struct device_attribute *attr,
out += sprintf(out, "%30s [Address ] : Hex\n", "NIC entry");
- for (i = 0; i < (sizeof(nic_data) / sizeof(*nic_data)); i++) {
+ for (i = 0; i < ARRAY_SIZE(nic_data); i++) {
u8 tmp8;
u16 tmp16;
u32 tmp32;
@@ -3894,13 +3894,11 @@ static ssize_t show_ordinals(struct device *d, struct device_attribute *attr,
if (priv->status & STATUS_RF_KILL_MASK)
return 0;
- if (loop >= sizeof(ord_data) / sizeof(*ord_data))
+ if (loop >= ARRAY_SIZE(ord_data))
loop = 0;
/* sysfs provides us PAGE_SIZE buffer */
- while (len < PAGE_SIZE - 128 &&
- loop < (sizeof(ord_data) / sizeof(*ord_data))) {
-
+ while (len < PAGE_SIZE - 128 && loop < ARRAY_SIZE(ord_data)) {
val_len = sizeof(u32);
if (ipw2100_get_ordinal(priv, ord_data[loop].index, &val,
@@ -4912,7 +4910,7 @@ static int ipw2100_set_power_mode(struct ipw2100_priv *priv, int power_level)
else
priv->power_mode = IPW_POWER_ENABLED | power_level;
-#ifdef CONFIG_IPW2100_TX_POWER
+#ifdef IPW2100_TX_POWER
if (priv->port_type == IBSS && priv->adhoc_power != DFTL_IBSS_TX_POWER) {
/* Set beacon interval */
cmd.host_command = TX_POWER_INDEX;
@@ -6589,7 +6587,7 @@ static const long ipw2100_rates_11b[] = {
11000000
};
-#define RATE_COUNT (sizeof(ipw2100_rates_11b) / sizeof(ipw2100_rates_11b[0]))
+#define RATE_COUNT ARRAY_SIZE(ipw2100_rates_11b)
static int ipw2100_wx_get_name(struct net_device *dev,
struct iw_request_info *info,
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c
index 22cb3fb7502..c878a2f3239 100644
--- a/drivers/net/wireless/ipw2200.c
+++ b/drivers/net/wireless/ipw2200.c
@@ -9166,7 +9166,7 @@ static int ipw_wx_set_rts(struct net_device *dev,
{
struct ipw_priv *priv = ieee80211_priv(dev);
mutex_lock(&priv->mutex);
- if (wrqu->rts.disabled)
+ if (wrqu->rts.disabled || !wrqu->rts.fixed)
priv->rts_threshold = DEFAULT_RTS_THRESHOLD;
else {
if (wrqu->rts.value < MIN_RTS_THRESHOLD ||
@@ -9255,7 +9255,7 @@ static int ipw_wx_set_frag(struct net_device *dev,
{
struct ipw_priv *priv = ieee80211_priv(dev);
mutex_lock(&priv->mutex);
- if (wrqu->frag.disabled)
+ if (wrqu->frag.disabled || !wrqu->frag.fixed)
priv->ieee->fts = DEFAULT_FTS;
else {
if (wrqu->frag.value < MIN_FRAG_THRESHOLD ||
diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c
index 936c888e03e..4e7f6cf5143 100644
--- a/drivers/net/wireless/orinoco.c
+++ b/drivers/net/wireless/orinoco.c
@@ -2059,7 +2059,7 @@ static int determine_firmware(struct net_device *dev)
int err;
struct comp_id nic_id, sta_id;
unsigned int firmver;
- char tmp[SYMBOL_MAX_VER_LEN+1];
+ char tmp[SYMBOL_MAX_VER_LEN+1] __attribute__((aligned(2)));
/* Get the hardware version */
err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_NICID, &nic_id);
@@ -4293,8 +4293,8 @@ static void orinoco_get_drvinfo(struct net_device *dev,
strncpy(info->driver, DRIVER_NAME, sizeof(info->driver) - 1);
strncpy(info->version, DRIVER_VERSION, sizeof(info->version) - 1);
strncpy(info->fw_version, priv->fw_name, sizeof(info->fw_version) - 1);
- if (dev->class_dev.dev)
- strncpy(info->bus_info, dev->class_dev.dev->bus_id,
+ if (dev->dev.parent)
+ strncpy(info->bus_info, dev->dev.parent->bus_id,
sizeof(info->bus_info) - 1);
else
snprintf(info->bus_info, sizeof(info->bus_info) - 1,
diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c
index d08ae8d2726..d1e502236b2 100644
--- a/drivers/net/wireless/orinoco_cs.c
+++ b/drivers/net/wireless/orinoco_cs.c
@@ -332,7 +332,7 @@ orinoco_cs_config(struct pcmcia_device *link)
/* Finally, report what we've done */
printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s, irq %d, io "
- "0x%04x-0x%04x\n", dev->name, dev->class_dev.dev->bus_id,
+ "0x%04x-0x%04x\n", dev->name, dev->dev.parent->bus_id,
link->irq.AssignedIRQ, link->io.BasePort1,
link->io.BasePort1 + link->io.NumPorts1 - 1);
diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c
index 838d510213c..841b3c136ad 100644
--- a/drivers/net/wireless/prism54/isl_ioctl.c
+++ b/drivers/net/wireless/prism54/isl_ioctl.c
@@ -1395,11 +1395,16 @@ static int prism54_set_auth(struct net_device *ndev,
break;
case IW_AUTH_RX_UNENCRYPTED_EAPOL:
- dot1x = param->value ? 1 : 0;
+ /* dot1x should be the opposite of RX_UNENCRYPTED_EAPOL;
+ * turn off dot1x when allowing receipt of unencrypted EAPOL
+ * frames, turn on dot1x when receipt should be disallowed
+ */
+ dot1x = param->value ? 0 : 0x01;
break;
case IW_AUTH_PRIVACY_INVOKED:
privinvoked = param->value ? 1 : 0;
+ break;
case IW_AUTH_DROP_UNENCRYPTED:
exunencrypt = param->value ? 1 : 0;
@@ -1589,6 +1594,7 @@ static int prism54_set_encodeext(struct net_device *ndev,
}
key.type = DOT11_PRIV_TKIP;
key.length = KEY_SIZE_TKIP;
+ break;
default:
return -EINVAL;
}
diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c
index f057fd9fcd7..a037b11dac9 100644
--- a/drivers/net/wireless/prism54/islpci_dev.c
+++ b/drivers/net/wireless/prism54/islpci_dev.c
@@ -21,6 +21,7 @@
#include <linux/module.h>
#include <linux/netdevice.h>
+#include <linux/ethtool.h>
#include <linux/pci.h>
#include <linux/etherdevice.h>
#include <linux/delay.h>
@@ -787,6 +788,17 @@ islpci_set_multicast_list(struct net_device *dev)
}
#endif
+static void islpci_ethtool_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *info)
+{
+ strcpy(info->driver, DRV_NAME);
+ strcpy(info->version, DRV_VERSION);
+}
+
+static struct ethtool_ops islpci_ethtool_ops = {
+ .get_drvinfo = islpci_ethtool_get_drvinfo,
+};
+
struct net_device *
islpci_setup(struct pci_dev *pdev)
{
@@ -813,6 +825,7 @@ islpci_setup(struct pci_dev *pdev)
ndev->do_ioctl = &prism54_ioctl;
ndev->wireless_handlers =
(struct iw_handler_def *) &prism54_handler_def;
+ ndev->ethtool_ops = &islpci_ethtool_ops;
ndev->hard_start_xmit = &islpci_eth_transmit;
/* ndev->set_multicast_list = &islpci_set_multicast_list; */
diff --git a/drivers/net/wireless/prism54/islpci_dev.h b/drivers/net/wireless/prism54/islpci_dev.h
index a9aa1662eaa..736666da6c2 100644
--- a/drivers/net/wireless/prism54/islpci_dev.h
+++ b/drivers/net/wireless/prism54/islpci_dev.h
@@ -211,4 +211,8 @@ islpci_trigger(islpci_private *priv)
int islpci_free_memory(islpci_private *);
struct net_device *islpci_setup(struct pci_dev *);
+
+#define DRV_NAME "prism54"
+#define DRV_VERSION "1.2"
+
#endif /* _ISLPCI_DEV_H */
diff --git a/drivers/net/wireless/prism54/islpci_hotplug.c b/drivers/net/wireless/prism54/islpci_hotplug.c
index 58257b40c04..3dcb13bb7d5 100644
--- a/drivers/net/wireless/prism54/islpci_hotplug.c
+++ b/drivers/net/wireless/prism54/islpci_hotplug.c
@@ -28,9 +28,6 @@
#include "islpci_mgt.h" /* for pc_debug */
#include "isl_oid.h"
-#define DRV_NAME "prism54"
-#define DRV_VERSION "1.2"
-
MODULE_AUTHOR("[Intersil] R.Bastings and W.Termorshuizen, The prism54.org Development Team <prism54-devel@prism54.org>");
MODULE_DESCRIPTION("The Prism54 802.11 Wireless LAN adapter");
MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/prism54/oid_mgt.c b/drivers/net/wireless/prism54/oid_mgt.c
index e6cf9df2c20..42780320cd5 100644
--- a/drivers/net/wireless/prism54/oid_mgt.c
+++ b/drivers/net/wireless/prism54/oid_mgt.c
@@ -16,6 +16,8 @@
*
*/
+#include <linux/kernel.h>
+
#include "prismcompat.h"
#include "islpci_dev.h"
#include "islpci_mgt.h"
@@ -692,7 +694,7 @@ mgt_update_addr(islpci_private *priv)
return ret;
}
-#define VEC_SIZE(a) (sizeof(a)/sizeof(a[0]))
+#define VEC_SIZE(a) ARRAY_SIZE(a)
int
mgt_commit(islpci_private *priv)
diff --git a/drivers/net/wireless/spectrum_cs.c b/drivers/net/wireless/spectrum_cs.c
index cf2d1486b01..af70460f008 100644
--- a/drivers/net/wireless/spectrum_cs.c
+++ b/drivers/net/wireless/spectrum_cs.c
@@ -806,7 +806,7 @@ spectrum_cs_config(struct pcmcia_device *link)
/* Finally, report what we've done */
printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s, irq %d, io "
- "0x%04x-0x%04x\n", dev->name, dev->class_dev.dev->bus_id,
+ "0x%04x-0x%04x\n", dev->name, dev->dev.parent->bus_id,
link->irq.AssignedIRQ, link->io.BasePort1,
link->io.BasePort1 + link->io.NumPorts1 - 1);
diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c
index ce3a8bac66f..f5ce1c6063d 100644
--- a/drivers/net/wireless/strip.c
+++ b/drivers/net/wireless/strip.c
@@ -1160,7 +1160,7 @@ static int strip_seq_open(struct inode *inode, struct file *file)
return seq_open(file, &strip_seq_ops);
}
-static struct file_operations strip_seq_fops = {
+static const struct file_operations strip_seq_fops = {
.owner = THIS_MODULE,
.open = strip_seq_open,
.read = seq_read,
diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c
index 24221e476cd..2aa3c761dd8 100644
--- a/drivers/net/wireless/wavelan.c
+++ b/drivers/net/wireless/wavelan.c
@@ -28,7 +28,7 @@
*/
static u8 wv_irq_to_psa(int irq)
{
- if (irq < 0 || irq >= NELS(irqvals))
+ if (irq < 0 || irq >= ARRAY_SIZE(irqvals))
return 0;
return irqvals[irq];
@@ -42,7 +42,7 @@ static int __init wv_psa_to_irq(u8 irqval)
{
int irq;
- for (irq = 0; irq < NELS(irqvals); irq++)
+ for (irq = 0; irq < ARRAY_SIZE(irqvals); irq++)
if (irqvals[irq] == irqval)
return irq;
@@ -1695,7 +1695,7 @@ static int wv_frequency_list(unsigned long ioaddr, /* I/O port of the card */
/* Look in the table if the frequency is allowed */
if (table[9 - (freq / 16)] & (1 << (freq % 16))) {
/* Compute approximate channel number */
- while ((c < NELS(channel_bands)) &&
+ while ((c < ARRAY_SIZE(channel_bands)) &&
(((channel_bands[c] >> 1) - 24) < freq))
c++;
list[i].i = c; /* Set the list index */
@@ -4269,7 +4269,7 @@ struct net_device * __init wavelan_probe(int unit)
printk(KERN_DEBUG "%s: <-wavelan_probe()\n", dev->name);
#endif
} else { /* Scan all possible addresses of the WaveLAN hardware. */
- for (i = 0; i < NELS(iobase); i++) {
+ for (i = 0; i < ARRAY_SIZE(iobase); i++) {
dev->irq = def_irq;
if (wavelan_config(dev, iobase[i]) == 0) {
#ifdef DEBUG_CALLBACK_TRACE
@@ -4280,7 +4280,7 @@ struct net_device * __init wavelan_probe(int unit)
break;
}
}
- if (i == NELS(iobase))
+ if (i == ARRAY_SIZE(iobase))
r = -ENODEV;
}
if (r)
@@ -4327,14 +4327,14 @@ int __init init_module(void)
#endif
/* Copy the basic set of address to be probed. */
- for (i = 0; i < NELS(iobase); i++)
+ for (i = 0; i < ARRAY_SIZE(iobase); i++)
io[i] = iobase[i];
}
/* Loop on all possible base addresses. */
i = -1;
- while ((io[++i] != 0) && (i < NELS(io))) {
+ while ((io[++i] != 0) && (i < ARRAY_SIZE(io))) {
struct net_device *dev = alloc_etherdev(sizeof(net_local));
if (!dev)
break;
diff --git a/drivers/net/wireless/wavelan.p.h b/drivers/net/wireless/wavelan.p.h
index 72b646c77d5..fe242812d85 100644
--- a/drivers/net/wireless/wavelan.p.h
+++ b/drivers/net/wireless/wavelan.p.h
@@ -449,9 +449,6 @@ static const char *version = "wavelan.c : v24 (SMP + wireless extensions) 11/12/
/* Watchdog temporisation */
#define WATCHDOG_JIFFIES (512*HZ/100)
-/* Macro to get the number of elements in an array */
-#define NELS(a) (sizeof(a) / sizeof(a[0]))
-
/* ------------------------ PRIVATE IOCTL ------------------------ */
#define SIOCSIPQTHR SIOCIWFIRSTPRIV /* Set quality threshold */
diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c
index 5eb81638e84..b04239792f6 100644
--- a/drivers/net/wireless/wavelan_cs.c
+++ b/drivers/net/wireless/wavelan_cs.c
@@ -1168,7 +1168,7 @@ wv_mmc_show(struct net_device * dev)
m.mmr_unused0[6],
m.mmr_unused0[7]);
#endif /* DEBUG_SHOW_UNUSED */
- printk(KERN_DEBUG "Encryption algorythm: %02X - Status: %02X\n",
+ printk(KERN_DEBUG "Encryption algorithm: %02X - Status: %02X\n",
m.mmr_des_avail, m.mmr_des_status);
#ifdef DEBUG_SHOW_UNUSED
printk(KERN_DEBUG "mmc_unused1[]: %02X:%02X:%02X:%02X:%02X\n",
@@ -3590,9 +3590,9 @@ wv_82593_config(struct net_device * dev)
cfblk.acloc = TRUE; /* Disable source addr insertion by i82593 */
cfblk.preamb_len = 0; /* 2 bytes preamble (SFD) */
cfblk.loopback = FALSE;
- cfblk.lin_prio = 0; /* conform to 802.3 backoff algoritm */
- cfblk.exp_prio = 5; /* conform to 802.3 backoff algoritm */
- cfblk.bof_met = 1; /* conform to 802.3 backoff algoritm */
+ cfblk.lin_prio = 0; /* conform to 802.3 backoff algorithm */
+ cfblk.exp_prio = 5; /* conform to 802.3 backoff algorithm */
+ cfblk.bof_met = 1; /* conform to 802.3 backoff algorithm */
cfblk.ifrm_spc = 0x20 >> 4; /* 32 bit times interframe spacing */
cfblk.slottim_low = 0x20 >> 5; /* 32 bit times slot time */
cfblk.slottim_hi = 0x0;
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c
index 78ea72fb8f0..9c64f894b71 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.c
+++ b/drivers/net/wireless/zd1211rw/zd_chip.c
@@ -84,6 +84,18 @@ static void print_id(struct zd_chip *chip)
dev_info(zd_chip_dev(chip), "%s\n", buffer);
}
+static zd_addr_t inc_addr(zd_addr_t addr)
+{
+ u16 a = (u16)addr;
+ /* Control registers use byte addressing, but everything else uses word
+ * addressing. */
+ if ((a & 0xf000) == CR_START)
+ a += 2;
+ else
+ a += 1;
+ return (zd_addr_t)a;
+}
+
/* Read a variable number of 32-bit values. Parameter count is not allowed to
* exceed USB_MAX_IOREAD32_COUNT.
*/
@@ -101,7 +113,7 @@ int zd_ioread32v_locked(struct zd_chip *chip, u32 *values, const zd_addr_t *addr
/* Allocate a single memory block for values and addresses. */
count16 = 2*count;
- a16 = kmalloc(count16 * (sizeof(zd_addr_t) + sizeof(u16)),
+ a16 = (zd_addr_t *) kmalloc(count16 * (sizeof(zd_addr_t) + sizeof(u16)),
GFP_NOFS);
if (!a16) {
dev_dbg_f(zd_chip_dev(chip),
@@ -114,7 +126,7 @@ int zd_ioread32v_locked(struct zd_chip *chip, u32 *values, const zd_addr_t *addr
for (i = 0; i < count; i++) {
int j = 2*i;
/* We read the high word always first. */
- a16[j] = zd_inc_word(addr[i]);
+ a16[j] = inc_addr(addr[i]);
a16[j+1] = addr[i];
}
@@ -163,7 +175,7 @@ int _zd_iowrite32v_locked(struct zd_chip *chip, const struct zd_ioreq32 *ioreqs,
j = 2*i;
/* We write the high word always first. */
ioreqs16[j].value = ioreqs[i].value >> 16;
- ioreqs16[j].addr = zd_inc_word(ioreqs[i].addr);
+ ioreqs16[j].addr = inc_addr(ioreqs[i].addr);
ioreqs16[j+1].value = ioreqs[i].value;
ioreqs16[j+1].addr = ioreqs[i].addr;
}
@@ -466,7 +478,8 @@ static int read_values(struct zd_chip *chip, u8 *values, size_t count,
ZD_ASSERT(mutex_is_locked(&chip->mutex));
for (i = 0;;) {
- r = zd_ioread32_locked(chip, &v, e2p_addr+i/2);
+ r = zd_ioread32_locked(chip, &v,
+ (zd_addr_t)((u16)e2p_addr+i/2));
if (r)
return r;
v -= guard;
@@ -798,47 +811,18 @@ static int hw_reset_phy(struct zd_chip *chip)
static int zd1211_hw_init_hmac(struct zd_chip *chip)
{
static const struct zd_ioreq32 ioreqs[] = {
- { CR_ACK_TIMEOUT_EXT, 0x20 },
- { CR_ADDA_MBIAS_WARMTIME, 0x30000808 },
{ CR_ZD1211_RETRY_MAX, 0x2 },
- { CR_SNIFFER_ON, 0 },
- { CR_RX_FILTER, STA_RX_FILTER },
- { CR_GROUP_HASH_P1, 0x00 },
- { CR_GROUP_HASH_P2, 0x80000000 },
- { CR_REG1, 0xa4 },
- { CR_ADDA_PWR_DWN, 0x7f },
- { CR_BCN_PLCP_CFG, 0x00f00401 },
- { CR_PHY_DELAY, 0x00 },
- { CR_ACK_TIMEOUT_EXT, 0x80 },
- { CR_ADDA_PWR_DWN, 0x00 },
- { CR_ACK_TIME_80211, 0x100 },
- { CR_RX_PE_DELAY, 0x70 },
- { CR_PS_CTRL, 0x10000000 },
- { CR_RTS_CTS_RATE, 0x02030203 },
{ CR_RX_THRESHOLD, 0x000c0640 },
- { CR_AFTER_PNP, 0x1 },
- { CR_WEP_PROTECT, 0x114 },
};
- int r;
-
dev_dbg_f(zd_chip_dev(chip), "\n");
ZD_ASSERT(mutex_is_locked(&chip->mutex));
- r = zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
-#ifdef DEBUG
- if (r) {
- dev_err(zd_chip_dev(chip),
- "error in zd_iowrite32a_locked. Error number %d\n", r);
- }
-#endif /* DEBUG */
- return r;
+ return zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
}
static int zd1211b_hw_init_hmac(struct zd_chip *chip)
{
static const struct zd_ioreq32 ioreqs[] = {
- { CR_ACK_TIMEOUT_EXT, 0x20 },
- { CR_ADDA_MBIAS_WARMTIME, 0x30000808 },
{ CR_ZD1211B_RETRY_MAX, 0x02020202 },
{ CR_ZD1211B_TX_PWR_CTL4, 0x007f003f },
{ CR_ZD1211B_TX_PWR_CTL3, 0x007f003f },
@@ -847,6 +831,20 @@ static int zd1211b_hw_init_hmac(struct zd_chip *chip)
{ CR_ZD1211B_AIFS_CTL1, 0x00280028 },
{ CR_ZD1211B_AIFS_CTL2, 0x008C003C },
{ CR_ZD1211B_TXOP, 0x01800824 },
+ { CR_RX_THRESHOLD, 0x000c0eff, },
+ };
+
+ dev_dbg_f(zd_chip_dev(chip), "\n");
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ return zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
+static int hw_init_hmac(struct zd_chip *chip)
+{
+ int r;
+ static const struct zd_ioreq32 ioreqs[] = {
+ { CR_ACK_TIMEOUT_EXT, 0x20 },
+ { CR_ADDA_MBIAS_WARMTIME, 0x30000808 },
{ CR_SNIFFER_ON, 0 },
{ CR_RX_FILTER, STA_RX_FILTER },
{ CR_GROUP_HASH_P1, 0x00 },
@@ -861,25 +859,16 @@ static int zd1211b_hw_init_hmac(struct zd_chip *chip)
{ CR_RX_PE_DELAY, 0x70 },
{ CR_PS_CTRL, 0x10000000 },
{ CR_RTS_CTS_RATE, 0x02030203 },
- { CR_RX_THRESHOLD, 0x000c0eff, },
{ CR_AFTER_PNP, 0x1 },
{ CR_WEP_PROTECT, 0x114 },
+ { CR_IFS_VALUE, IFS_VALUE_DEFAULT },
};
- int r;
-
- dev_dbg_f(zd_chip_dev(chip), "\n");
ZD_ASSERT(mutex_is_locked(&chip->mutex));
r = zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
- if (r) {
- dev_dbg_f(zd_chip_dev(chip),
- "error in zd_iowrite32a_locked. Error number %d\n", r);
- }
- return r;
-}
+ if (r)
+ return r;
-static int hw_init_hmac(struct zd_chip *chip)
-{
return chip->is_zd1211b ?
zd1211b_hw_init_hmac(chip) : zd1211_hw_init_hmac(chip);
}
@@ -974,16 +963,14 @@ static int hw_init(struct zd_chip *chip)
if (r)
return r;
- /* Although the vendor driver defaults to a different value during
- * init, it overwrites the IFS value with the following every time
- * the channel changes. We should aim to be more intelligent... */
- r = zd_iowrite32_locked(chip, IFS_VALUE_DEFAULT, CR_IFS_VALUE);
- if (r)
- return r;
-
return set_beacon_interval(chip, 100);
}
+static zd_addr_t fw_reg_addr(struct zd_chip *chip, u16 offset)
+{
+ return (zd_addr_t)((u16)chip->fw_regs_base + offset);
+}
+
#ifdef DEBUG
static int dump_cr(struct zd_chip *chip, const zd_addr_t addr,
const char *addr_string)
@@ -1018,9 +1005,11 @@ static int test_init(struct zd_chip *chip)
static void dump_fw_registers(struct zd_chip *chip)
{
- static const zd_addr_t addr[4] = {
- FW_FIRMWARE_VER, FW_USB_SPEED, FW_FIX_TX_RATE,
- FW_LINK_STATUS
+ const zd_addr_t addr[4] = {
+ fw_reg_addr(chip, FW_REG_FIRMWARE_VER),
+ fw_reg_addr(chip, FW_REG_USB_SPEED),
+ fw_reg_addr(chip, FW_REG_FIX_TX_RATE),
+ fw_reg_addr(chip, FW_REG_LED_LINK_STATUS),
};
int r;
@@ -1046,7 +1035,8 @@ static int print_fw_version(struct zd_chip *chip)
int r;
u16 version;
- r = zd_ioread16_locked(chip, &version, FW_FIRMWARE_VER);
+ r = zd_ioread16_locked(chip, &version,
+ fw_reg_addr(chip, FW_REG_FIRMWARE_VER));
if (r)
return r;
@@ -1126,6 +1116,22 @@ int zd_chip_disable_hwint(struct zd_chip *chip)
return r;
}
+static int read_fw_regs_offset(struct zd_chip *chip)
+{
+ int r;
+
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ r = zd_ioread16_locked(chip, (u16*)&chip->fw_regs_base,
+ FWRAW_REGS_ADDR);
+ if (r)
+ return r;
+ dev_dbg_f(zd_chip_dev(chip), "fw_regs_base: %#06hx\n",
+ (u16)chip->fw_regs_base);
+
+ return 0;
+}
+
+
int zd_chip_init_hw(struct zd_chip *chip, u8 device_type)
{
int r;
@@ -1145,7 +1151,7 @@ int zd_chip_init_hw(struct zd_chip *chip, u8 device_type)
if (r)
goto out;
- r = zd_usb_init_hw(&chip->usb);
+ r = read_fw_regs_offset(chip);
if (r)
goto out;
@@ -1325,15 +1331,15 @@ u8 zd_chip_get_channel(struct zd_chip *chip)
int zd_chip_control_leds(struct zd_chip *chip, enum led_status status)
{
- static const zd_addr_t a[] = {
- FW_LINK_STATUS,
+ const zd_addr_t a[] = {
+ fw_reg_addr(chip, FW_REG_LED_LINK_STATUS),
CR_LED,
};
int r;
u16 v[ARRAY_SIZE(a)];
struct zd_ioreq16 ioreqs[ARRAY_SIZE(a)] = {
- [0] = { FW_LINK_STATUS },
+ [0] = { fw_reg_addr(chip, FW_REG_LED_LINK_STATUS) },
[1] = { CR_LED },
};
u16 other_led;
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h
index a4e3cee9b59..b07569e391e 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.h
+++ b/drivers/net/wireless/zd1211rw/zd_chip.h
@@ -18,7 +18,6 @@
#ifndef _ZD_CHIP_H
#define _ZD_CHIP_H
-#include "zd_types.h"
#include "zd_rf.h"
#include "zd_usb.h"
@@ -27,6 +26,37 @@
* adds a processor for handling the USB protocol.
*/
+/* Address space */
+enum {
+ /* CONTROL REGISTERS */
+ CR_START = 0x9000,
+
+
+ /* FIRMWARE */
+ FW_START = 0xee00,
+
+
+ /* EEPROM */
+ E2P_START = 0xf800,
+ E2P_LEN = 0x800,
+
+ /* EEPROM layout */
+ E2P_LOAD_CODE_LEN = 0xe, /* base 0xf800 */
+ E2P_LOAD_VECT_LEN = 0x9, /* base 0xf80e */
+ /* E2P_DATA indexes into this */
+ E2P_DATA_LEN = 0x7e, /* base 0xf817 */
+ E2P_BOOT_CODE_LEN = 0x760, /* base 0xf895 */
+ E2P_INTR_VECT_LEN = 0xb, /* base 0xfff5 */
+
+ /* Some precomputed offsets into the EEPROM */
+ E2P_DATA_OFFSET = E2P_LOAD_CODE_LEN + E2P_LOAD_VECT_LEN,
+ E2P_BOOT_CODE_OFFSET = E2P_DATA_OFFSET + E2P_DATA_LEN,
+};
+
+#define CTL_REG(offset) ((zd_addr_t)(CR_START + (offset)))
+#define E2P_DATA(offset) ((zd_addr_t)(E2P_START + E2P_DATA_OFFSET + (offset)))
+#define FWRAW_DATA(offset) ((zd_addr_t)(FW_START + (offset)))
+
/* 8-bit hardware registers */
#define CR0 CTL_REG(0x0000)
#define CR1 CTL_REG(0x0004)
@@ -302,7 +332,7 @@
#define CR_MAX_PHY_REG 255
-/* Taken from the ZYDAS driver, not all of them are relevant for the ZSD1211
+/* Taken from the ZYDAS driver, not all of them are relevant for the ZD1211
* driver.
*/
@@ -594,81 +624,71 @@
/*
* Upper 16 bit contains the regulatory domain.
*/
-#define E2P_SUBID E2P_REG(0x00)
-#define E2P_POD E2P_REG(0x02)
-#define E2P_MAC_ADDR_P1 E2P_REG(0x04)
-#define E2P_MAC_ADDR_P2 E2P_REG(0x06)
-#define E2P_PWR_CAL_VALUE1 E2P_REG(0x08)
-#define E2P_PWR_CAL_VALUE2 E2P_REG(0x0a)
-#define E2P_PWR_CAL_VALUE3 E2P_REG(0x0c)
-#define E2P_PWR_CAL_VALUE4 E2P_REG(0x0e)
-#define E2P_PWR_INT_VALUE1 E2P_REG(0x10)
-#define E2P_PWR_INT_VALUE2 E2P_REG(0x12)
-#define E2P_PWR_INT_VALUE3 E2P_REG(0x14)
-#define E2P_PWR_INT_VALUE4 E2P_REG(0x16)
+#define E2P_SUBID E2P_DATA(0x00)
+#define E2P_POD E2P_DATA(0x02)
+#define E2P_MAC_ADDR_P1 E2P_DATA(0x04)
+#define E2P_MAC_ADDR_P2 E2P_DATA(0x06)
+#define E2P_PWR_CAL_VALUE1 E2P_DATA(0x08)
+#define E2P_PWR_CAL_VALUE2 E2P_DATA(0x0a)
+#define E2P_PWR_CAL_VALUE3 E2P_DATA(0x0c)
+#define E2P_PWR_CAL_VALUE4 E2P_DATA(0x0e)
+#define E2P_PWR_INT_VALUE1 E2P_DATA(0x10)
+#define E2P_PWR_INT_VALUE2 E2P_DATA(0x12)
+#define E2P_PWR_INT_VALUE3 E2P_DATA(0x14)
+#define E2P_PWR_INT_VALUE4 E2P_DATA(0x16)
/* Contains a bit for each allowed channel. It gives for Europe (ETSI 0x30)
* also only 11 channels. */
-#define E2P_ALLOWED_CHANNEL E2P_REG(0x18)
-
-#define E2P_PHY_REG E2P_REG(0x1a)
-#define E2P_DEVICE_VER E2P_REG(0x20)
-#define E2P_36M_CAL_VALUE1 E2P_REG(0x28)
-#define E2P_36M_CAL_VALUE2 E2P_REG(0x2a)
-#define E2P_36M_CAL_VALUE3 E2P_REG(0x2c)
-#define E2P_36M_CAL_VALUE4 E2P_REG(0x2e)
-#define E2P_11A_INT_VALUE1 E2P_REG(0x30)
-#define E2P_11A_INT_VALUE2 E2P_REG(0x32)
-#define E2P_11A_INT_VALUE3 E2P_REG(0x34)
-#define E2P_11A_INT_VALUE4 E2P_REG(0x36)
-#define E2P_48M_CAL_VALUE1 E2P_REG(0x38)
-#define E2P_48M_CAL_VALUE2 E2P_REG(0x3a)
-#define E2P_48M_CAL_VALUE3 E2P_REG(0x3c)
-#define E2P_48M_CAL_VALUE4 E2P_REG(0x3e)
-#define E2P_48M_INT_VALUE1 E2P_REG(0x40)
-#define E2P_48M_INT_VALUE2 E2P_REG(0x42)
-#define E2P_48M_INT_VALUE3 E2P_REG(0x44)
-#define E2P_48M_INT_VALUE4 E2P_REG(0x46)
-#define E2P_54M_CAL_VALUE1 E2P_REG(0x48) /* ??? */
-#define E2P_54M_CAL_VALUE2 E2P_REG(0x4a)
-#define E2P_54M_CAL_VALUE3 E2P_REG(0x4c)
-#define E2P_54M_CAL_VALUE4 E2P_REG(0x4e)
-#define E2P_54M_INT_VALUE1 E2P_REG(0x50)
-#define E2P_54M_INT_VALUE2 E2P_REG(0x52)
-#define E2P_54M_INT_VALUE3 E2P_REG(0x54)
-#define E2P_54M_INT_VALUE4 E2P_REG(0x56)
-
-/* All 16 bit values */
-#define FW_FIRMWARE_VER FW_REG(0)
-/* non-zero if USB high speed connection */
-#define FW_USB_SPEED FW_REG(1)
-#define FW_FIX_TX_RATE FW_REG(2)
-/* Seems to be able to control LEDs over the firmware */
-#define FW_LINK_STATUS FW_REG(3)
-#define FW_SOFT_RESET FW_REG(4)
-#define FW_FLASH_CHK FW_REG(5)
+#define E2P_ALLOWED_CHANNEL E2P_DATA(0x18)
+
+#define E2P_PHY_REG E2P_DATA(0x1a)
+#define E2P_DEVICE_VER E2P_DATA(0x20)
+#define E2P_36M_CAL_VALUE1 E2P_DATA(0x28)
+#define E2P_36M_CAL_VALUE2 E2P_DATA(0x2a)
+#define E2P_36M_CAL_VALUE3 E2P_DATA(0x2c)
+#define E2P_36M_CAL_VALUE4 E2P_DATA(0x2e)
+#define E2P_11A_INT_VALUE1 E2P_DATA(0x30)
+#define E2P_11A_INT_VALUE2 E2P_DATA(0x32)
+#define E2P_11A_INT_VALUE3 E2P_DATA(0x34)
+#define E2P_11A_INT_VALUE4 E2P_DATA(0x36)
+#define E2P_48M_CAL_VALUE1 E2P_DATA(0x38)
+#define E2P_48M_CAL_VALUE2 E2P_DATA(0x3a)
+#define E2P_48M_CAL_VALUE3 E2P_DATA(0x3c)
+#define E2P_48M_CAL_VALUE4 E2P_DATA(0x3e)
+#define E2P_48M_INT_VALUE1 E2P_DATA(0x40)
+#define E2P_48M_INT_VALUE2 E2P_DATA(0x42)
+#define E2P_48M_INT_VALUE3 E2P_DATA(0x44)
+#define E2P_48M_INT_VALUE4 E2P_DATA(0x46)
+#define E2P_54M_CAL_VALUE1 E2P_DATA(0x48) /* ??? */
+#define E2P_54M_CAL_VALUE2 E2P_DATA(0x4a)
+#define E2P_54M_CAL_VALUE3 E2P_DATA(0x4c)
+#define E2P_54M_CAL_VALUE4 E2P_DATA(0x4e)
+#define E2P_54M_INT_VALUE1 E2P_DATA(0x50)
+#define E2P_54M_INT_VALUE2 E2P_DATA(0x52)
+#define E2P_54M_INT_VALUE3 E2P_DATA(0x54)
+#define E2P_54M_INT_VALUE4 E2P_DATA(0x56)
+
+/* This word contains the base address of the FW_REG_ registers below */
+#define FWRAW_REGS_ADDR FWRAW_DATA(0x1d)
+
+/* All 16 bit values, offset from the address in FWRAW_REGS_ADDR */
+enum {
+ FW_REG_FIRMWARE_VER = 0,
+ /* non-zero if USB high speed connection */
+ FW_REG_USB_SPEED = 1,
+ FW_REG_FIX_TX_RATE = 2,
+ /* Seems to be able to control LEDs over the firmware */
+ FW_REG_LED_LINK_STATUS = 3,
+ FW_REG_SOFT_RESET = 4,
+ FW_REG_FLASH_CHK = 5,
+};
+/* Values for FW_LINK_STATUS */
#define FW_LINK_OFF 0x0
#define FW_LINK_TX 0x1
/* 0x2 - link led on? */
enum {
- CR_BASE_OFFSET = 0x9000,
- FW_START_OFFSET = 0xee00,
- FW_BASE_ADDR_OFFSET = FW_START_OFFSET + 0x1d,
- EEPROM_START_OFFSET = 0xf800,
- EEPROM_SIZE = 0x800, /* words */
- LOAD_CODE_SIZE = 0xe, /* words */
- LOAD_VECT_SIZE = 0x10000 - 0xfff7, /* words */
- EEPROM_REGS_OFFSET = LOAD_CODE_SIZE + LOAD_VECT_SIZE,
- EEPROM_REGS_SIZE = 0x7e, /* words */
- E2P_BASE_OFFSET = EEPROM_START_OFFSET +
- EEPROM_REGS_OFFSET,
-};
-
-#define FW_REG_TABLE_ADDR USB_ADDR(FW_START_OFFSET + 0x1d)
-
-enum {
/* indices for ofdm_cal_values */
OFDM_36M_INDEX = 0,
OFDM_48M_INDEX = 1,
@@ -679,6 +699,8 @@ struct zd_chip {
struct zd_usb usb;
struct zd_rf rf;
struct mutex mutex;
+ /* Base address of FW_REG_ registers */
+ zd_addr_t fw_regs_base;
u8 e2p_mac[ETH_ALEN];
/* EepSetPoint in the vendor driver */
u8 pwr_cal_values[E2P_CHANNEL_COUNT];
diff --git a/drivers/net/wireless/zd1211rw/zd_def.h b/drivers/net/wireless/zd1211rw/zd_def.h
index fb22f62cf1f..deb99d1eaa7 100644
--- a/drivers/net/wireless/zd1211rw/zd_def.h
+++ b/drivers/net/wireless/zd1211rw/zd_def.h
@@ -23,6 +23,8 @@
#include <linux/device.h>
#include <linux/kernel.h>
+typedef u16 __nocast zd_addr_t;
+
#define dev_printk_f(level, dev, fmt, args...) \
dev_printk(level, dev, "%s() " fmt, __func__, ##args)
diff --git a/drivers/net/wireless/zd1211rw/zd_ieee80211.h b/drivers/net/wireless/zd1211rw/zd_ieee80211.h
index 26b8298dff8..c4f36d39642 100644
--- a/drivers/net/wireless/zd1211rw/zd_ieee80211.h
+++ b/drivers/net/wireless/zd1211rw/zd_ieee80211.h
@@ -2,7 +2,6 @@
#define _ZD_IEEE80211_H
#include <net/ieee80211.h>
-#include "zd_types.h"
/* Additional definitions from the standards.
*/
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index a08524191b5..4c5f78eac34 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -156,7 +156,7 @@ void zd_mac_clear(struct zd_mac *mac)
static int reset_mode(struct zd_mac *mac)
{
struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
- struct zd_ioreq32 ioreqs[3] = {
+ struct zd_ioreq32 ioreqs[] = {
{ CR_RX_FILTER, STA_RX_FILTER },
{ CR_SNIFFER_ON, 0U },
};
@@ -164,10 +164,9 @@ static int reset_mode(struct zd_mac *mac)
if (ieee->iw_mode == IW_MODE_MONITOR) {
ioreqs[0].value = 0xffffffff;
ioreqs[1].value = 0x1;
- ioreqs[2].value = ENC_SNIFFER;
}
- return zd_iowrite32a(&mac->chip, ioreqs, 3);
+ return zd_iowrite32a(&mac->chip, ioreqs, ARRAY_SIZE(ioreqs));
}
int zd_mac_open(struct net_device *netdev)
@@ -904,16 +903,21 @@ static int fill_ctrlset(struct zd_mac *mac,
static int zd_mac_tx(struct zd_mac *mac, struct ieee80211_txb *txb, int pri)
{
int i, r;
+ struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
for (i = 0; i < txb->nr_frags; i++) {
struct sk_buff *skb = txb->fragments[i];
r = fill_ctrlset(mac, txb, i);
- if (r)
+ if (r) {
+ ieee->stats.tx_dropped++;
return r;
+ }
r = zd_usb_tx(&mac->chip.usb, skb->data, skb->len);
- if (r)
+ if (r) {
+ ieee->stats.tx_dropped++;
return r;
+ }
}
/* FIXME: shouldn't this be handled by the upper layers? */
@@ -1063,9 +1067,23 @@ static int fill_rx_stats(struct ieee80211_rx_stats *stats,
*pstatus = status = zd_tail(buffer, length, sizeof(struct rx_status));
if (status->frame_status & ZD_RX_ERROR) {
- /* FIXME: update? */
+ struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
+ ieee->stats.rx_errors++;
+ if (status->frame_status & ZD_RX_TIMEOUT_ERROR)
+ ieee->stats.rx_missed_errors++;
+ else if (status->frame_status & ZD_RX_FIFO_OVERRUN_ERROR)
+ ieee->stats.rx_fifo_errors++;
+ else if (status->frame_status & ZD_RX_DECRYPTION_ERROR)
+ ieee->ieee_stats.rx_discards_undecryptable++;
+ else if (status->frame_status & ZD_RX_CRC32_ERROR) {
+ ieee->stats.rx_crc_errors++;
+ ieee->ieee_stats.rx_fcs_errors++;
+ }
+ else if (status->frame_status & ZD_RX_CRC16_ERROR)
+ ieee->stats.rx_crc_errors++;
return -EINVAL;
}
+
memset(stats, 0, sizeof(struct ieee80211_rx_stats));
stats->len = length - (ZD_PLCP_HEADER_SIZE + IEEE80211_FCS_LEN +
+ sizeof(struct rx_status));
@@ -1094,14 +1112,16 @@ static void zd_mac_rx(struct zd_mac *mac, struct sk_buff *skb)
if (skb->len < ZD_PLCP_HEADER_SIZE + IEEE80211_1ADDR_LEN +
IEEE80211_FCS_LEN + sizeof(struct rx_status))
{
- dev_dbg_f(zd_mac_dev(mac), "Packet with length %u to small.\n",
- skb->len);
+ ieee->stats.rx_errors++;
+ ieee->stats.rx_length_errors++;
goto free_skb;
}
r = fill_rx_stats(&stats, &status, mac, skb->data, skb->len);
if (r) {
- /* Only packets with rx errors are included here. */
+ /* Only packets with rx errors are included here.
+ * The error stats have already been set in fill_rx_stats.
+ */
goto free_skb;
}
@@ -1114,8 +1134,10 @@ static void zd_mac_rx(struct zd_mac *mac, struct sk_buff *skb)
r = filter_rx(ieee, skb->data, skb->len, &stats);
if (r <= 0) {
- if (r < 0)
+ if (r < 0) {
+ ieee->stats.rx_errors++;
dev_dbg_f(zd_mac_dev(mac), "Error in packet.\n");
+ }
goto free_skb;
}
@@ -1146,7 +1168,9 @@ int zd_mac_rx_irq(struct zd_mac *mac, const u8 *buffer, unsigned int length)
skb = dev_alloc_skb(sizeof(struct zd_rt_hdr) + length);
if (!skb) {
+ struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
dev_warn(zd_mac_dev(mac), "Could not allocate skb.\n");
+ ieee->stats.rx_dropped++;
return -ENOMEM;
}
skb_reserve(skb, sizeof(struct zd_rt_hdr));
diff --git a/drivers/net/wireless/zd1211rw/zd_rf.h b/drivers/net/wireless/zd1211rw/zd_rf.h
index 676b3734f1e..a57732eb69e 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf.h
+++ b/drivers/net/wireless/zd1211rw/zd_rf.h
@@ -18,8 +18,6 @@
#ifndef _ZD_RF_H
#define _ZD_RF_H
-#include "zd_types.h"
-
#define UW2451_RF 0x2
#define UCHIP_RF 0x3
#define AL2230_RF 0x4
diff --git a/drivers/net/wireless/zd1211rw/zd_types.h b/drivers/net/wireless/zd1211rw/zd_types.h
deleted file mode 100644
index 0155a1584ed..00000000000
--- a/drivers/net/wireless/zd1211rw/zd_types.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/* zd_types.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
- */
-
-#ifndef _ZD_TYPES_H
-#define _ZD_TYPES_H
-
-#include <linux/types.h>
-
-/* We have three register spaces mapped into the overall USB address space of
- * 64K words (16-bit values). There is the control register space of
- * double-word registers, the eeprom register space and the firmware register
- * space. The control register space is byte mapped, the others are word
- * mapped.
- *
- * For that reason, we are using byte offsets for control registers and word
- * offsets for everything else.
- */
-
-typedef u32 __nocast zd_addr_t;
-
-enum {
- ADDR_BASE_MASK = 0xff000000,
- ADDR_OFFSET_MASK = 0x0000ffff,
- ADDR_ZERO_MASK = 0x00ff0000,
- NULL_BASE = 0x00000000,
- USB_BASE = 0x01000000,
- CR_BASE = 0x02000000,
- CR_MAX_OFFSET = 0x0b30,
- E2P_BASE = 0x03000000,
- E2P_MAX_OFFSET = 0x007e,
- FW_BASE = 0x04000000,
- FW_MAX_OFFSET = 0x0005,
-};
-
-#define ZD_ADDR_BASE(addr) ((u32)(addr) & ADDR_BASE_MASK)
-#define ZD_OFFSET(addr) ((u32)(addr) & ADDR_OFFSET_MASK)
-
-#define ZD_ADDR(base, offset) \
- ((zd_addr_t)(((base) & ADDR_BASE_MASK) | ((offset) & ADDR_OFFSET_MASK)))
-
-#define ZD_NULL_ADDR ((zd_addr_t)0)
-#define USB_REG(offset) ZD_ADDR(USB_BASE, offset) /* word addressing */
-#define CTL_REG(offset) ZD_ADDR(CR_BASE, offset) /* byte addressing */
-#define E2P_REG(offset) ZD_ADDR(E2P_BASE, offset) /* word addressing */
-#define FW_REG(offset) ZD_ADDR(FW_BASE, offset) /* word addressing */
-
-static inline zd_addr_t zd_inc_word(zd_addr_t addr)
-{
- u32 base = ZD_ADDR_BASE(addr);
- u32 offset = ZD_OFFSET(addr);
-
- offset += base == CR_BASE ? 2 : 1;
-
- return base | offset;
-}
-
-#endif /* _ZD_TYPES_H */
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index 605e96e7405..aac8a1c5ba0 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -58,6 +58,10 @@ static struct usb_device_id usb_ids[] = {
{ USB_DEVICE(0x079b, 0x0062), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x1582, 0x6003), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x050d, 0x705c), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x083a, 0x4505), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0471, 0x1236), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x13b1, 0x0024), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0586, 0x340f), .driver_info = DEVICE_ZD1211B },
/* "Driverless" devices that need ejecting */
{ USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER },
{}
@@ -73,96 +77,6 @@ MODULE_DEVICE_TABLE(usb, usb_ids);
#define FW_ZD1211_PREFIX "zd1211/zd1211_"
#define FW_ZD1211B_PREFIX "zd1211/zd1211b_"
-/* register address handling */
-
-#ifdef DEBUG
-static int check_addr(struct zd_usb *usb, zd_addr_t addr)
-{
- u32 base = ZD_ADDR_BASE(addr);
- u32 offset = ZD_OFFSET(addr);
-
- if ((u32)addr & ADDR_ZERO_MASK)
- goto invalid_address;
- switch (base) {
- case USB_BASE:
- break;
- case CR_BASE:
- if (offset > CR_MAX_OFFSET) {
- dev_dbg(zd_usb_dev(usb),
- "CR offset %#010x larger than"
- " CR_MAX_OFFSET %#10x\n",
- offset, CR_MAX_OFFSET);
- goto invalid_address;
- }
- if (offset & 1) {
- dev_dbg(zd_usb_dev(usb),
- "CR offset %#010x is not a multiple of 2\n",
- offset);
- goto invalid_address;
- }
- break;
- case E2P_BASE:
- if (offset > E2P_MAX_OFFSET) {
- dev_dbg(zd_usb_dev(usb),
- "E2P offset %#010x larger than"
- " E2P_MAX_OFFSET %#010x\n",
- offset, E2P_MAX_OFFSET);
- goto invalid_address;
- }
- break;
- case FW_BASE:
- if (!usb->fw_base_offset) {
- dev_dbg(zd_usb_dev(usb),
- "ERROR: fw base offset has not been set\n");
- return -EAGAIN;
- }
- if (offset > FW_MAX_OFFSET) {
- dev_dbg(zd_usb_dev(usb),
- "FW offset %#10x is larger than"
- " FW_MAX_OFFSET %#010x\n",
- offset, FW_MAX_OFFSET);
- goto invalid_address;
- }
- break;
- default:
- dev_dbg(zd_usb_dev(usb),
- "address has unsupported base %#010x\n", addr);
- goto invalid_address;
- }
-
- return 0;
-invalid_address:
- dev_dbg(zd_usb_dev(usb),
- "ERROR: invalid address: %#010x\n", addr);
- return -EINVAL;
-}
-#endif /* DEBUG */
-
-static u16 usb_addr(struct zd_usb *usb, zd_addr_t addr)
-{
- u32 base;
- u16 offset;
-
- base = ZD_ADDR_BASE(addr);
- offset = ZD_OFFSET(addr);
-
- ZD_ASSERT(check_addr(usb, addr) == 0);
-
- switch (base) {
- case CR_BASE:
- offset += CR_BASE_OFFSET;
- break;
- case E2P_BASE:
- offset += E2P_BASE_OFFSET;
- break;
- case FW_BASE:
- offset += usb->fw_base_offset;
- break;
- }
-
- return offset;
-}
-
/* USB device initialization */
static int request_fw_file(
@@ -295,14 +209,13 @@ static int handle_version_mismatch(struct usb_device *udev, u8 device_type,
if (r)
goto error;
- r = upload_code(udev, ur_fw->data, ur_fw->size, FW_START_OFFSET,
- REBOOT);
+ r = upload_code(udev, ur_fw->data, ur_fw->size, FW_START, REBOOT);
if (r)
goto error;
- offset = ((EEPROM_REGS_OFFSET + EEPROM_REGS_SIZE) * sizeof(u16));
+ offset = (E2P_BOOT_CODE_OFFSET * sizeof(u16));
r = upload_code(udev, ub_fw->data + offset, ub_fw->size - offset,
- E2P_BASE_OFFSET + EEPROM_REGS_SIZE, REBOOT);
+ E2P_START + E2P_BOOT_CODE_OFFSET, REBOOT);
/* At this point, the vendor driver downloads the whole firmware
* image, hacks around with version IDs, and uploads it again,
@@ -331,7 +244,7 @@ static int upload_firmware(struct usb_device *udev, u8 device_type)
if (r)
goto error;
- fw_bcdDevice = get_word(ub_fw->data, EEPROM_REGS_OFFSET);
+ fw_bcdDevice = get_word(ub_fw->data, E2P_DATA_OFFSET);
if (fw_bcdDevice != bcdDevice) {
dev_info(&udev->dev,
@@ -357,8 +270,7 @@ static int upload_firmware(struct usb_device *udev, u8 device_type)
if (r)
goto error;
- r = upload_code(udev, uph_fw->data, uph_fw->size, FW_START_OFFSET,
- REBOOT);
+ r = upload_code(udev, uph_fw->data, uph_fw->size, FW_START, REBOOT);
if (r) {
dev_err(&udev->dev,
"Could not upload firmware code uph. Error number %d\n",
@@ -401,6 +313,12 @@ out:
static inline void handle_retry_failed_int(struct urb *urb)
{
+ struct zd_usb *usb = urb->context;
+ struct zd_mac *mac = zd_usb_to_mac(usb);
+ struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
+
+ ieee->stats.tx_errors++;
+ ieee->ieee_stats.tx_retry_limit_exceeded++;
dev_dbg_f(urb_dev(urb), "retry failed interrupt\n");
}
@@ -575,6 +493,9 @@ static void handle_rx_packet(struct zd_usb *usb, const u8 *buffer,
if (length < sizeof(struct rx_length_info)) {
/* It's not a complete packet anyhow. */
+ struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
+ ieee->stats.rx_errors++;
+ ieee->stats.rx_length_errors++;
return;
}
length_info = (struct rx_length_info *)
@@ -858,7 +779,7 @@ static inline void init_usb_interrupt(struct zd_usb *usb)
spin_lock_init(&intr->lock);
intr->interval = int_urb_interval(zd_usb_to_usbdev(usb));
init_completion(&intr->read_regs.completion);
- intr->read_regs.cr_int_addr = cpu_to_le16(usb_addr(usb, CR_INTERRUPT));
+ intr->read_regs.cr_int_addr = cpu_to_le16((u16)CR_INTERRUPT);
}
static inline void init_usb_rx(struct zd_usb *usb)
@@ -890,22 +811,6 @@ void zd_usb_init(struct zd_usb *usb, struct net_device *netdev,
init_usb_rx(usb);
}
-int zd_usb_init_hw(struct zd_usb *usb)
-{
- int r;
- struct zd_chip *chip = zd_usb_to_chip(usb);
-
- ZD_ASSERT(mutex_is_locked(&chip->mutex));
- r = zd_ioread16_locked(chip, &usb->fw_base_offset,
- USB_REG((u16)FW_BASE_ADDR_OFFSET));
- if (r)
- return r;
- dev_dbg_f(zd_usb_dev(usb), "fw_base_offset: %#06hx\n",
- usb->fw_base_offset);
-
- return 0;
-}
-
void zd_usb_clear(struct zd_usb *usb)
{
usb_set_intfdata(usb->intf, NULL);
@@ -1027,6 +932,8 @@ static int probe(struct usb_interface *intf, const struct usb_device_id *id)
goto error;
}
+ usb_reset_device(interface_to_usbdev(intf));
+
netdev = zd_netdev_alloc(intf);
if (netdev == NULL) {
r = -ENOMEM;
@@ -1128,6 +1035,7 @@ static int __init usb_init(void)
r = usb_register(&driver);
if (r) {
+ destroy_workqueue(zd_workqueue);
printk(KERN_ERR "%s usb_register() failed. Error number %d\n",
driver.name, r);
return r;
@@ -1253,7 +1161,7 @@ int zd_usb_ioread16v(struct zd_usb *usb, u16 *values,
return -ENOMEM;
req->id = cpu_to_le16(USB_REQ_READ_REGS);
for (i = 0; i < count; i++)
- req->addr[i] = cpu_to_le16(usb_addr(usb, addresses[i]));
+ req->addr[i] = cpu_to_le16((u16)addresses[i]);
udev = zd_usb_to_usbdev(usb);
prepare_read_regs_int(usb);
@@ -1318,7 +1226,7 @@ int zd_usb_iowrite16v(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs,
req->id = cpu_to_le16(USB_REQ_WRITE_REGS);
for (i = 0; i < count; i++) {
struct reg_data *rw = &req->reg_writes[i];
- rw->addr = cpu_to_le16(usb_addr(usb, ioreqs[i].addr));
+ rw->addr = cpu_to_le16((u16)ioreqs[i].addr);
rw->value = cpu_to_le16(ioreqs[i].value);
}
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.h b/drivers/net/wireless/zd1211rw/zd_usb.h
index 317d37c3667..506ea6a7439 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.h
+++ b/drivers/net/wireless/zd1211rw/zd_usb.h
@@ -25,7 +25,6 @@
#include <linux/usb.h>
#include "zd_def.h"
-#include "zd_types.h"
enum devicetype {
DEVICE_ZD1211 = 0,
@@ -181,15 +180,14 @@ struct zd_usb_tx {
spinlock_t lock;
};
-/* Contains the usb parts. The structure doesn't require a lock, because intf
- * and fw_base_offset, will not be changed after initialization.
+/* Contains the usb parts. The structure doesn't require a lock because intf
+ * will not be changed after initialization.
*/
struct zd_usb {
struct zd_usb_interrupt intr;
struct zd_usb_rx rx;
struct zd_usb_tx tx;
struct usb_interface *intf;
- u16 fw_base_offset;
};
#define zd_usb_dev(usb) (&usb->intf->dev)
diff --git a/drivers/oprofile/event_buffer.c b/drivers/oprofile/event_buffer.c
index 04d641714d3..00e937e9240 100644
--- a/drivers/oprofile/event_buffer.c
+++ b/drivers/oprofile/event_buffer.c
@@ -181,7 +181,7 @@ out:
return retval;
}
-struct file_operations event_buffer_fops = {
+const struct file_operations event_buffer_fops = {
.open = event_buffer_open,
.release = event_buffer_release,
.read = event_buffer_read,
diff --git a/drivers/oprofile/event_buffer.h b/drivers/oprofile/event_buffer.h
index 92416276e57..9b6a4ebd03e 100644
--- a/drivers/oprofile/event_buffer.h
+++ b/drivers/oprofile/event_buffer.h
@@ -41,7 +41,7 @@ void wake_up_buffer_waiter(void);
/* add data to the event buffer */
void add_event_entry(unsigned long data);
-extern struct file_operations event_buffer_fops;
+extern const struct file_operations event_buffer_fops;
/* mutex between sync_cpu_buffers() and the
* file reading code.
diff --git a/drivers/oprofile/oprofile_files.c b/drivers/oprofile/oprofile_files.c
index a72006c08f2..ef953ba5ab6 100644
--- a/drivers/oprofile/oprofile_files.c
+++ b/drivers/oprofile/oprofile_files.c
@@ -44,7 +44,7 @@ static ssize_t depth_write(struct file * file, char const __user * buf, size_t c
}
-static struct file_operations depth_fops = {
+static const struct file_operations depth_fops = {
.read = depth_read,
.write = depth_write
};
@@ -56,7 +56,7 @@ static ssize_t pointer_size_read(struct file * file, char __user * buf, size_t c
}
-static struct file_operations pointer_size_fops = {
+static const struct file_operations pointer_size_fops = {
.read = pointer_size_read,
};
@@ -67,7 +67,7 @@ static ssize_t cpu_type_read(struct file * file, char __user * buf, size_t count
}
-static struct file_operations cpu_type_fops = {
+static const struct file_operations cpu_type_fops = {
.read = cpu_type_read,
};
@@ -101,7 +101,7 @@ static ssize_t enable_write(struct file * file, char const __user * buf, size_t
}
-static struct file_operations enable_fops = {
+static const struct file_operations enable_fops = {
.read = enable_read,
.write = enable_write,
};
@@ -114,7 +114,7 @@ static ssize_t dump_write(struct file * file, char const __user * buf, size_t co
}
-static struct file_operations dump_fops = {
+static const struct file_operations dump_fops = {
.write = dump_write,
};
diff --git a/drivers/oprofile/oprofilefs.c b/drivers/oprofile/oprofilefs.c
index 5756401fb15..6e67b42ca46 100644
--- a/drivers/oprofile/oprofilefs.c
+++ b/drivers/oprofile/oprofilefs.c
@@ -115,14 +115,14 @@ static int default_open(struct inode * inode, struct file * filp)
}
-static struct file_operations ulong_fops = {
+static const struct file_operations ulong_fops = {
.read = ulong_read_file,
.write = ulong_write_file,
.open = default_open,
};
-static struct file_operations ulong_ro_fops = {
+static const struct file_operations ulong_ro_fops = {
.read = ulong_read_file,
.open = default_open,
};
@@ -182,7 +182,7 @@ static ssize_t atomic_read_file(struct file * file, char __user * buf, size_t co
}
-static struct file_operations atomic_ro_fops = {
+static const struct file_operations atomic_ro_fops = {
.read = atomic_read_file,
.open = default_open,
};
diff --git a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c
index fe3f5f5365c..894fdb9d44c 100644
--- a/drivers/parisc/ccio-dma.c
+++ b/drivers/parisc/ccio-dma.c
@@ -1091,7 +1091,7 @@ static int ccio_proc_info_open(struct inode *inode, struct file *file)
return single_open(file, &ccio_proc_info, NULL);
}
-static struct file_operations ccio_proc_info_fops = {
+static const struct file_operations ccio_proc_info_fops = {
.owner = THIS_MODULE,
.open = ccio_proc_info_open,
.read = seq_read,
@@ -1127,7 +1127,7 @@ static int ccio_proc_bitmap_open(struct inode *inode, struct file *file)
return single_open(file, &ccio_proc_bitmap_info, NULL);
}
-static struct file_operations ccio_proc_bitmap_fops = {
+static const struct file_operations ccio_proc_bitmap_fops = {
.owner = THIS_MODULE,
.open = ccio_proc_bitmap_open,
.read = seq_read,
diff --git a/drivers/parisc/eisa.c b/drivers/parisc/eisa.c
index e97cecbc4d1..309076b3985 100644
--- a/drivers/parisc/eisa.c
+++ b/drivers/parisc/eisa.c
@@ -33,7 +33,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/eisa.h>
diff --git a/drivers/parisc/eisa_eeprom.c b/drivers/parisc/eisa_eeprom.c
index e13aafa70bf..86e9c84a965 100644
--- a/drivers/parisc/eisa_eeprom.c
+++ b/drivers/parisc/eisa_eeprom.c
@@ -97,7 +97,7 @@ static int eisa_eeprom_release(struct inode *inode, struct file *file)
/*
* The various file operations we support.
*/
-static struct file_operations eisa_eeprom_fops = {
+static const struct file_operations eisa_eeprom_fops = {
.owner = THIS_MODULE,
.llseek = eisa_eeprom_llseek,
.read = eisa_eeprom_read,
diff --git a/drivers/parisc/led.c b/drivers/parisc/led.c
index a415d9b1c71..d190c05d87e 100644
--- a/drivers/parisc/led.c
+++ b/drivers/parisc/led.c
@@ -252,7 +252,6 @@ static int __init led_create_procfs(void)
proc_pdc_root->owner = THIS_MODULE;
ent = create_proc_entry("led", S_IFREG|S_IRUGO|S_IWUSR, proc_pdc_root);
if (!ent) return -1;
- ent->nlink = 1;
ent->data = (void *)LED_NOLCD; /* LED */
ent->read_proc = led_proc_read;
ent->write_proc = led_proc_write;
@@ -262,7 +261,6 @@ static int __init led_create_procfs(void)
{
ent = create_proc_entry("lcd", S_IFREG|S_IRUGO|S_IWUSR, proc_pdc_root);
if (!ent) return -1;
- ent->nlink = 1;
ent->data = (void *)LED_HASLCD; /* LCD */
ent->read_proc = led_proc_read;
ent->write_proc = led_proc_write;
diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c
index 26fece45e73..322957ac2ad 100644
--- a/drivers/parisc/sba_iommu.c
+++ b/drivers/parisc/sba_iommu.c
@@ -1799,7 +1799,7 @@ sba_proc_open(struct inode *i, struct file *f)
return single_open(f, &sba_proc_info, NULL);
}
-static struct file_operations sba_proc_fops = {
+static const struct file_operations sba_proc_fops = {
.owner = THIS_MODULE,
.open = sba_proc_open,
.read = seq_read,
@@ -1831,7 +1831,7 @@ sba_proc_bitmap_open(struct inode *i, struct file *f)
return single_open(f, &sba_proc_bitmap_info, NULL);
}
-static struct file_operations sba_proc_bitmap_fops = {
+static const struct file_operations sba_proc_bitmap_fops = {
.owner = THIS_MODULE,
.open = sba_proc_bitmap_open,
.read = seq_read,
diff --git a/drivers/parport/parport_cs.c b/drivers/parport/parport_cs.c
index e60b4bf6bae..316c06f4423 100644
--- a/drivers/parport/parport_cs.c
+++ b/drivers/parport/parport_cs.c
@@ -37,7 +37,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/sched.h>
#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/string.h>
diff --git a/drivers/parport/parport_gsc.c b/drivers/parport/parport_gsc.c
index a7c5ead9a3d..17bf9937d27 100644
--- a/drivers/parport/parport_gsc.c
+++ b/drivers/parport/parport_gsc.c
@@ -23,7 +23,6 @@
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c
index b61c17b3e29..3de2623afa1 100644
--- a/drivers/parport/parport_pc.c
+++ b/drivers/parport/parport_pc.c
@@ -1546,7 +1546,7 @@ static void __devinit detect_and_report_smsc (void)
}
#endif /* CONFIG_PARPORT_PC_SUPERIO */
-static int __devinit get_superio_dma (struct parport *p)
+static int get_superio_dma (struct parport *p)
{
int i=0;
while( (superios[i].io != p->base) && (i<NR_SUPERIOS))
@@ -2106,7 +2106,7 @@ static int parport_irq_probe(struct parport *pb)
/* --- DMA detection -------------------------------------- */
/* Only if chipset conforms to ECP ISA Interface Standard */
-static int __devinit programmable_dma_support (struct parport *p)
+static int programmable_dma_support (struct parport *p)
{
unsigned char oecr = inb (ECONTROL (p));
int dma;
@@ -2123,7 +2123,7 @@ static int __devinit programmable_dma_support (struct parport *p)
return dma;
}
-static int __devinit parport_dma_probe (struct parport *p)
+static int parport_dma_probe (struct parport *p)
{
const struct parport_pc_private *priv = p->private_data;
if (priv->ecr)
diff --git a/drivers/parport/procfs.c b/drivers/parport/procfs.c
index 2e744a27451..bdbdab9285c 100644
--- a/drivers/parport/procfs.c
+++ b/drivers/parport/procfs.c
@@ -233,12 +233,12 @@ static int do_hardware_modes (ctl_table *table, int write,
return copy_to_user(result, buffer, len) ? -EFAULT : 0;
}
-#define PARPORT_PORT_DIR(child) { 0, NULL, NULL, 0, 0555, child }
-#define PARPORT_PARPORT_DIR(child) { DEV_PARPORT, "parport", \
- NULL, 0, 0555, child }
-#define PARPORT_DEV_DIR(child) { CTL_DEV, "dev", NULL, 0, 0555, child }
-#define PARPORT_DEVICES_ROOT_DIR { DEV_PARPORT_DEVICES, "devices", \
- NULL, 0, 0555, NULL }
+#define PARPORT_PORT_DIR(CHILD) { .ctl_name = 0, .procname = NULL, .mode = 0555, .child = CHILD }
+#define PARPORT_PARPORT_DIR(CHILD) { .ctl_name = DEV_PARPORT, .procname = "parport", \
+ .mode = 0555, .child = CHILD }
+#define PARPORT_DEV_DIR(CHILD) { .ctl_name = CTL_DEV, .procname = "dev", .mode = 0555, .child = CHILD }
+#define PARPORT_DEVICES_ROOT_DIR { .ctl_name = DEV_PARPORT_DEVICES, .procname = "devices", \
+ .mode = 0555, .child = NULL }
static const unsigned long parport_min_timeslice_value =
PARPORT_MIN_TIMESLICE_VALUE;
@@ -263,50 +263,118 @@ struct parport_sysctl_table {
};
static const struct parport_sysctl_table parport_sysctl_template = {
- NULL,
+ .sysctl_header = NULL,
{
- { DEV_PARPORT_SPINTIME, "spintime",
- NULL, sizeof(int), 0644, NULL,
- &proc_dointvec_minmax, NULL, NULL,
- (void*) &parport_min_spintime_value,
- (void*) &parport_max_spintime_value },
- { DEV_PARPORT_BASE_ADDR, "base-addr",
- NULL, 0, 0444, NULL,
- &do_hardware_base_addr },
- { DEV_PARPORT_IRQ, "irq",
- NULL, 0, 0444, NULL,
- &do_hardware_irq },
- { DEV_PARPORT_DMA, "dma",
- NULL, 0, 0444, NULL,
- &do_hardware_dma },
- { DEV_PARPORT_MODES, "modes",
- NULL, 0, 0444, NULL,
- &do_hardware_modes },
+ {
+ .ctl_name = DEV_PARPORT_SPINTIME,
+ .procname = "spintime",
+ .data = NULL,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec_minmax,
+ .extra1 = (void*) &parport_min_spintime_value,
+ .extra2 = (void*) &parport_max_spintime_value
+ },
+ {
+ .ctl_name = DEV_PARPORT_BASE_ADDR,
+ .procname = "base-addr",
+ .data = NULL,
+ .maxlen = 0,
+ .mode = 0444,
+ .proc_handler = &do_hardware_base_addr
+ },
+ {
+ .ctl_name = DEV_PARPORT_IRQ,
+ .procname = "irq",
+ .data = NULL,
+ .maxlen = 0,
+ .mode = 0444,
+ .proc_handler = &do_hardware_irq
+ },
+ {
+ .ctl_name = DEV_PARPORT_DMA,
+ .procname = "dma",
+ .data = NULL,
+ .maxlen = 0,
+ .mode = 0444,
+ .proc_handler = &do_hardware_dma
+ },
+ {
+ .ctl_name = DEV_PARPORT_MODES,
+ .procname = "modes",
+ .data = NULL,
+ .maxlen = 0,
+ .mode = 0444,
+ .proc_handler = &do_hardware_modes
+ },
PARPORT_DEVICES_ROOT_DIR,
#ifdef CONFIG_PARPORT_1284
- { DEV_PARPORT_AUTOPROBE, "autoprobe",
- NULL, 0, 0444, NULL,
- &do_autoprobe },
- { DEV_PARPORT_AUTOPROBE + 1, "autoprobe0",
- NULL, 0, 0444, NULL,
- &do_autoprobe },
- { DEV_PARPORT_AUTOPROBE + 2, "autoprobe1",
- NULL, 0, 0444, NULL,
- &do_autoprobe },
- { DEV_PARPORT_AUTOPROBE + 3, "autoprobe2",
- NULL, 0, 0444, NULL,
- &do_autoprobe },
- { DEV_PARPORT_AUTOPROBE + 4, "autoprobe3",
- NULL, 0, 0444, NULL,
- &do_autoprobe },
+ {
+ .ctl_name = DEV_PARPORT_AUTOPROBE,
+ .procname = "autoprobe",
+ .data = NULL,
+ .maxlen = 0,
+ .mode = 0444,
+ .proc_handler = &do_autoprobe
+ },
+ {
+ .ctl_name = DEV_PARPORT_AUTOPROBE + 1,
+ .procname = "autoprobe0",
+ .data = NULL,
+ .maxlen = 0,
+ .mode = 0444,
+ .proc_handler = &do_autoprobe
+ },
+ {
+ .ctl_name = DEV_PARPORT_AUTOPROBE + 2,
+ .procname = "autoprobe1",
+ .data = NULL,
+ .maxlen = 0,
+ .mode = 0444,
+ .proc_handler = &do_autoprobe
+ },
+ {
+ .ctl_name = DEV_PARPORT_AUTOPROBE + 3,
+ .procname = "autoprobe2",
+ .data = NULL,
+ .maxlen = 0,
+ .mode = 0444,
+ .proc_handler = &do_autoprobe
+ },
+ {
+ .ctl_name = DEV_PARPORT_AUTOPROBE + 4,
+ .procname = "autoprobe3",
+ .data = NULL,
+ .maxlen = 0,
+ .mode = 0444,
+ .proc_handler = &do_autoprobe
+ },
#endif /* IEEE 1284 support */
- {0}
+ {}
},
- { {DEV_PARPORT_DEVICES_ACTIVE, "active", NULL, 0, 0444, NULL,
- &do_active_device }, {0}},
- { PARPORT_PORT_DIR(NULL), {0}},
- { PARPORT_PARPORT_DIR(NULL), {0}},
- { PARPORT_DEV_DIR(NULL), {0}}
+ {
+ {
+ .ctl_name = DEV_PARPORT_DEVICES_ACTIVE,
+ .procname = "active",
+ .data = NULL,
+ .maxlen = 0,
+ .mode = 0444,
+ .proc_handler = &do_active_device
+ },
+ {}
+ },
+ {
+ PARPORT_PORT_DIR(NULL),
+ {}
+ },
+ {
+ PARPORT_PARPORT_DIR(NULL),
+ {}
+ },
+ {
+ PARPORT_DEV_DIR(NULL),
+ {}
+ }
};
struct parport_device_sysctl_table
@@ -322,19 +390,46 @@ struct parport_device_sysctl_table
static const struct parport_device_sysctl_table
parport_device_sysctl_template = {
- NULL,
+ .sysctl_header = NULL,
+ {
+ {
+ .ctl_name = DEV_PARPORT_DEVICE_TIMESLICE,
+ .procname = "timeslice",
+ .data = NULL,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_doulongvec_ms_jiffies_minmax,
+ .extra1 = (void*) &parport_min_timeslice_value,
+ .extra2 = (void*) &parport_max_timeslice_value
+ },
+ },
+ {
+ {
+ .ctl_name = 0,
+ .procname = NULL,
+ .data = NULL,
+ .maxlen = 0,
+ .mode = 0555,
+ .child = NULL
+ },
+ {}
+ },
{
- { DEV_PARPORT_DEVICE_TIMESLICE, "timeslice",
- NULL, sizeof(int), 0644, NULL,
- &proc_doulongvec_ms_jiffies_minmax, NULL, NULL,
- (void*) &parport_min_timeslice_value,
- (void*) &parport_max_timeslice_value },
+ PARPORT_DEVICES_ROOT_DIR,
+ {}
+ },
+ {
+ PARPORT_PORT_DIR(NULL),
+ {}
},
- { {0, NULL, NULL, 0, 0555, NULL}, {0}},
- { PARPORT_DEVICES_ROOT_DIR, {0}},
- { PARPORT_PORT_DIR(NULL), {0}},
- { PARPORT_PARPORT_DIR(NULL), {0}},
- { PARPORT_DEV_DIR(NULL), {0}}
+ {
+ PARPORT_PARPORT_DIR(NULL),
+ {}
+ },
+ {
+ PARPORT_DEV_DIR(NULL),
+ {}
+ }
};
struct parport_default_sysctl_table
@@ -351,28 +446,47 @@ extern int parport_default_spintime;
static struct parport_default_sysctl_table
parport_default_sysctl_table = {
- NULL,
+ .sysctl_header = NULL,
+ {
+ {
+ .ctl_name = DEV_PARPORT_DEFAULT_TIMESLICE,
+ .procname = "timeslice",
+ .data = &parport_default_timeslice,
+ .maxlen = sizeof(parport_default_timeslice),
+ .mode = 0644,
+ .proc_handler = &proc_doulongvec_ms_jiffies_minmax,
+ .extra1 = (void*) &parport_min_timeslice_value,
+ .extra2 = (void*) &parport_max_timeslice_value
+ },
+ {
+ .ctl_name = DEV_PARPORT_DEFAULT_SPINTIME,
+ .procname = "spintime",
+ .data = &parport_default_spintime,
+ .maxlen = sizeof(parport_default_spintime),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec_minmax,
+ .extra1 = (void*) &parport_min_spintime_value,
+ .extra2 = (void*) &parport_max_spintime_value
+ },
+ {}
+ },
{
- { DEV_PARPORT_DEFAULT_TIMESLICE, "timeslice",
- &parport_default_timeslice,
- sizeof(parport_default_timeslice), 0644, NULL,
- &proc_doulongvec_ms_jiffies_minmax, NULL, NULL,
- (void*) &parport_min_timeslice_value,
- (void*) &parport_max_timeslice_value },
- { DEV_PARPORT_DEFAULT_SPINTIME, "spintime",
- &parport_default_spintime,
- sizeof(parport_default_spintime), 0644, NULL,
- &proc_dointvec_minmax, NULL, NULL,
- (void*) &parport_min_spintime_value,
- (void*) &parport_max_spintime_value },
- {0}
+ {
+ .ctl_name = DEV_PARPORT_DEFAULT,
+ .procname = "default",
+ .mode = 0555,
+ .child = parport_default_sysctl_table.vars
+ },
+ {}
},
- { { DEV_PARPORT_DEFAULT, "default", NULL, 0, 0555,
- parport_default_sysctl_table.vars },{0}},
{
- PARPORT_PARPORT_DIR(parport_default_sysctl_table.default_dir),
- {0}},
- { PARPORT_DEV_DIR(parport_default_sysctl_table.parport_dir), {0}}
+ PARPORT_PARPORT_DIR(parport_default_sysctl_table.default_dir),
+ {}
+ },
+ {
+ PARPORT_DEV_DIR(parport_default_sysctl_table.parport_dir),
+ {}
+ }
};
@@ -404,7 +518,7 @@ int parport_proc_register(struct parport *port)
t->parport_dir[0].child = t->port_dir;
t->dev_dir[0].child = t->parport_dir;
- t->sysctl_header = register_sysctl_table(t->dev_dir, 0);
+ t->sysctl_header = register_sysctl_table(t->dev_dir);
if (t->sysctl_header == NULL) {
kfree(t);
t = NULL;
@@ -460,7 +574,7 @@ int parport_device_proc_register(struct pardevice *device)
t->device_dir[0].child = t->vars;
t->vars[0].data = &device->timeslice;
- t->sysctl_header = register_sysctl_table(t->dev_dir, 0);
+ t->sysctl_header = register_sysctl_table(t->dev_dir);
if (t->sysctl_header == NULL) {
kfree(t);
t = NULL;
@@ -483,7 +597,7 @@ int parport_device_proc_unregister(struct pardevice *device)
static int __init parport_default_proc_register(void)
{
parport_default_sysctl_table.sysctl_header =
- register_sysctl_table(parport_default_sysctl_table.dev_dir, 0);
+ register_sysctl_table(parport_default_sysctl_table.dev_dir);
return 0;
}
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index 3cfb0a3575e..5ea5bc70cb8 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -4,7 +4,7 @@
config PCI_MSI
bool "Message Signaled Interrupts (MSI and MSI-X)"
depends on PCI
- depends on (X86_LOCAL_APIC && X86_IO_APIC) || IA64
+ depends on (X86_LOCAL_APIC && X86_IO_APIC) || IA64 || SPARC64
help
This allows device drivers to enable MSI (Message Signaled
Interrupts). Message Signaled Interrupts enable a device to
diff --git a/drivers/pci/hotplug/Kconfig b/drivers/pci/hotplug/Kconfig
index adce4204d87..be92695a783 100644
--- a/drivers/pci/hotplug/Kconfig
+++ b/drivers/pci/hotplug/Kconfig
@@ -145,15 +145,6 @@ config HOTPLUG_PCI_SHPC
When in doubt, say N.
-config HOTPLUG_PCI_SHPC_POLL_EVENT_MODE
- bool "Use polling mechanism for hot-plug events (for testing purpose)"
- depends on HOTPLUG_PCI_SHPC
- help
- Say Y here if you want to use the polling mechanism for hot-plug
- events for early platform testing.
-
- When in doubt, say N.
-
config HOTPLUG_PCI_RPA
tristate "RPA PCI Hotplug driver"
depends on HOTPLUG_PCI && PPC_PSERIES && PPC64 && !HOTPLUG_PCI_FAKE
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index bd1faebf61a..fca978fb158 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -773,13 +773,13 @@ static int get_gsi_base(acpi_handle handle, u32 *gsi_base)
goto out;
table = obj->buffer.pointer;
- switch (((acpi_table_entry_header *)table)->type) {
- case ACPI_MADT_IOSAPIC:
- *gsi_base = ((struct acpi_table_iosapic *)table)->global_irq_base;
+ switch (((struct acpi_subtable_header *)table)->type) {
+ case ACPI_MADT_TYPE_IO_SAPIC:
+ *gsi_base = ((struct acpi_madt_io_sapic *)table)->global_irq_base;
result = 0;
break;
- case ACPI_MADT_IOAPIC:
- *gsi_base = ((struct acpi_table_ioapic *)table)->global_irq_base;
+ case ACPI_MADT_TYPE_IO_APIC:
+ *gsi_base = ((struct acpi_madt_io_apic *)table)->global_irq_base;
result = 0;
break;
default:
diff --git a/drivers/pci/hotplug/cpqphp_sysfs.c b/drivers/pci/hotplug/cpqphp_sysfs.c
index 634f74d919d..a13abf55d78 100644
--- a/drivers/pci/hotplug/cpqphp_sysfs.c
+++ b/drivers/pci/hotplug/cpqphp_sysfs.c
@@ -202,7 +202,7 @@ static int release(struct inode *inode, struct file *file)
return 0;
}
-static struct file_operations debug_ops = {
+static const struct file_operations debug_ops = {
.owner = THIS_MODULE,
.open = open,
.llseek = lseek,
diff --git a/drivers/pci/hotplug/ibmphp_ebda.c b/drivers/pci/hotplug/ibmphp_ebda.c
index 05e4f5a1927..600ed7b67ae 100644
--- a/drivers/pci/hotplug/ibmphp_ebda.c
+++ b/drivers/pci/hotplug/ibmphp_ebda.c
@@ -28,7 +28,6 @@
*/
#include <linux/module.h>
-#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/slab.h>
diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h
index 4fb12fcda56..d19fcae8a7c 100644
--- a/drivers/pci/hotplug/pciehp.h
+++ b/drivers/pci/hotplug/pciehp.h
@@ -44,15 +44,20 @@ extern int pciehp_poll_time;
extern int pciehp_debug;
extern int pciehp_force;
-/*#define dbg(format, arg...) do { if (pciehp_debug) printk(KERN_DEBUG "%s: " format, MY_NAME , ## arg); } while (0)*/
-#define dbg(format, arg...) do { if (pciehp_debug) printk("%s: " format, MY_NAME , ## arg); } while (0)
-#define err(format, arg...) printk(KERN_ERR "%s: " format, MY_NAME , ## arg)
-#define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg)
-#define warn(format, arg...) printk(KERN_WARNING "%s: " format, MY_NAME , ## arg)
-
+#define dbg(format, arg...) \
+ do { \
+ if (pciehp_debug) \
+ printk("%s: " format, MY_NAME , ## arg); \
+ } while (0)
+#define err(format, arg...) \
+ printk(KERN_ERR "%s: " format, MY_NAME , ## arg)
+#define info(format, arg...) \
+ printk(KERN_INFO "%s: " format, MY_NAME , ## arg)
+#define warn(format, arg...) \
+ printk(KERN_WARNING "%s: " format, MY_NAME , ## arg)
+#define SLOT_NAME_SIZE 10
struct slot {
- struct slot *next;
u8 bus;
u8 device;
u32 number;
@@ -63,6 +68,8 @@ struct slot {
struct hpc_ops *hpc_ops;
struct hotplug_slot *hotplug_slot;
struct list_head slot_list;
+ char name[SLOT_NAME_SIZE];
+ unsigned long last_emi_toggle;
};
struct event_info {
@@ -70,34 +77,15 @@ struct event_info {
u8 hp_slot;
};
-typedef u8(*php_intr_callback_t) (u8 hp_slot, void *instance_id);
-
-struct php_ctlr_state_s {
- struct php_ctlr_state_s *pnext;
- struct pci_dev *pci_dev;
- unsigned int irq;
- unsigned long flags; /* spinlock's */
- u32 slot_device_offset;
- u32 num_slots;
- struct timer_list int_poll_timer; /* Added for poll event */
- php_intr_callback_t attention_button_callback;
- php_intr_callback_t switch_change_callback;
- php_intr_callback_t presence_change_callback;
- php_intr_callback_t power_fault_callback;
- void *callback_instance_id;
- struct ctrl_reg *creg; /* Ptr to controller register space */
-};
-
#define MAX_EVENTS 10
struct controller {
struct controller *next;
struct mutex crit_sect; /* critical section mutex */
struct mutex ctrl_lock; /* controller lock */
- struct php_ctlr_state_s *hpc_ctlr_handle; /* HPC controller handle */
int num_slots; /* Number of slots on ctlr */
int slot_num_inc; /* 1 or -1 */
struct pci_dev *pci_dev;
- struct pci_bus *pci_bus;
+ struct list_head slot_list;
struct event_info event_queue[MAX_EVENTS];
struct slot *slot;
struct hpc_ops *hpc_ops;
@@ -112,6 +100,8 @@ struct controller {
u8 ctrlcap;
u16 vendor_id;
u8 cap_base;
+ struct timer_list poll_timer;
+ volatile int cmd_busy;
};
#define INT_BUTTON_IGNORE 0
@@ -131,8 +121,6 @@ struct controller {
#define POWERON_STATE 3
#define POWEROFF_STATE 4
-#define PCI_TO_PCI_BRIDGE_CLASS 0x00060400
-
/* Error messages */
#define INTERLOCK_OPEN 0x00000002
#define ADD_NOT_SUPPORTED 0x00000003
@@ -144,10 +132,6 @@ struct controller {
#define WRONG_BUS_FREQUENCY 0x0000000D
#define POWER_FAILURE 0x0000000E
-#define REMOVE_NOT_SUPPORTED 0x00000003
-
-#define DISABLE_CARD 1
-
/* Field definitions in Slot Capabilities Register */
#define ATTN_BUTTN_PRSN 0x00000001
#define PWR_CTRL_PRSN 0x00000002
@@ -155,6 +139,7 @@ struct controller {
#define ATTN_LED_PRSN 0x00000008
#define PWR_LED_PRSN 0x00000010
#define HP_SUPR_RM_SUP 0x00000020
+#define EMI_PRSN 0x00020000
#define ATTN_BUTTN(cap) (cap & ATTN_BUTTN_PRSN)
#define POWER_CTRL(cap) (cap & PWR_CTRL_PRSN)
@@ -162,130 +147,65 @@ struct controller {
#define ATTN_LED(cap) (cap & ATTN_LED_PRSN)
#define PWR_LED(cap) (cap & PWR_LED_PRSN)
#define HP_SUPR_RM(cap) (cap & HP_SUPR_RM_SUP)
-
-/*
- * error Messages
- */
-#define msg_initialization_err "Initialization failure, error=%d\n"
-#define msg_button_on "PCI slot #%s - powering on due to button press.\n"
-#define msg_button_off "PCI slot #%s - powering off due to button press.\n"
-#define msg_button_cancel "PCI slot #%s - action canceled due to button press.\n"
-#define msg_button_ignore "PCI slot #%s - button press ignored. (action in progress...)\n"
-
-/* controller functions */
-extern int pciehp_event_start_thread (void);
-extern void pciehp_event_stop_thread (void);
-extern int pciehp_enable_slot (struct slot *slot);
-extern int pciehp_disable_slot (struct slot *slot);
-
-extern u8 pciehp_handle_attention_button (u8 hp_slot, void *inst_id);
-extern u8 pciehp_handle_switch_change (u8 hp_slot, void *inst_id);
-extern u8 pciehp_handle_presence_change (u8 hp_slot, void *inst_id);
-extern u8 pciehp_handle_power_fault (u8 hp_slot, void *inst_id);
-/* extern void long_delay (int delay); */
-
-/* pci functions */
-extern int pciehp_configure_device (struct slot *p_slot);
-extern int pciehp_unconfigure_device (struct slot *p_slot);
-
-
+#define EMI(cap) (cap & EMI_PRSN)
+
+extern int pciehp_event_start_thread(void);
+extern void pciehp_event_stop_thread(void);
+extern int pciehp_enable_slot(struct slot *slot);
+extern int pciehp_disable_slot(struct slot *slot);
+extern u8 pciehp_handle_attention_button(u8 hp_slot, struct controller *ctrl);
+extern u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl);
+extern u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl);
+extern u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl);
+extern int pciehp_configure_device(struct slot *p_slot);
+extern int pciehp_unconfigure_device(struct slot *p_slot);
+int pcie_init(struct controller *ctrl, struct pcie_device *dev);
/* Global variables */
extern struct controller *pciehp_ctrl_list;
-/* Inline functions */
-
static inline struct slot *pciehp_find_slot(struct controller *ctrl, u8 device)
{
- struct slot *p_slot, *tmp_slot = NULL;
-
- p_slot = ctrl->slot;
+ struct slot *slot;
- while (p_slot && (p_slot->device != device)) {
- tmp_slot = p_slot;
- p_slot = p_slot->next;
+ list_for_each_entry(slot, &ctrl->slot_list, slot_list) {
+ if (slot->device == device)
+ return slot;
}
- if (p_slot == NULL) {
- err("ERROR: pciehp_find_slot device=0x%x\n", device);
- p_slot = tmp_slot;
- }
-
- return p_slot;
-}
-
-static inline int wait_for_ctrl_irq(struct controller *ctrl)
-{
- int retval = 0;
-
- DECLARE_WAITQUEUE(wait, current);
-
- add_wait_queue(&ctrl->queue, &wait);
- if (!pciehp_poll_mode)
- /* Sleep for up to 1 second */
- msleep_interruptible(1000);
- else
- msleep_interruptible(2500);
-
- remove_wait_queue(&ctrl->queue, &wait);
- if (signal_pending(current))
- retval = -EINTR;
-
- return retval;
-}
-
-#define SLOT_NAME_SIZE 10
-static inline void make_slot_name(char *buffer, int buffer_size, struct slot *slot)
-{
- snprintf(buffer, buffer_size, "%04d_%04d", slot->bus, slot->number);
+ err("%s: slot (device=0x%x) not found\n", __FUNCTION__, device);
+ return NULL;
}
-enum php_ctlr_type {
- PCI,
- ISA,
- ACPI
-};
-
-int pcie_init(struct controller *ctrl, struct pcie_device *dev);
-
-/* This has no meaning for PCI Express, as there is only 1 slot per port */
-int pcie_get_ctlr_slot_config(struct controller *ctrl,
- int *num_ctlr_slots,
- int *first_device_num,
- int *physical_slot_num,
- u8 *ctrlcap);
-
struct hpc_ops {
- int (*power_on_slot) (struct slot *slot);
- int (*power_off_slot) (struct slot *slot);
- int (*get_power_status) (struct slot *slot, u8 *status);
- int (*get_attention_status) (struct slot *slot, u8 *status);
- 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_max_lnk_width) (struct slot *slot, enum pcie_link_width *value);
- int (*get_cur_lnk_width) (struct slot *slot, enum pcie_link_width *value);
-
- int (*query_power_fault) (struct slot *slot);
- void (*green_led_on) (struct slot *slot);
- void (*green_led_off) (struct slot *slot);
- void (*green_led_blink) (struct slot *slot);
- void (*release_ctlr) (struct controller *ctrl);
- int (*check_lnk_status) (struct controller *ctrl);
+ int (*power_on_slot)(struct slot *slot);
+ int (*power_off_slot)(struct slot *slot);
+ int (*get_power_status)(struct slot *slot, u8 *status);
+ int (*get_attention_status)(struct slot *slot, u8 *status);
+ 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_emi_status)(struct slot *slot, u8 *status);
+ int (*toggle_emi)(struct slot *slot);
+ 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_max_lnk_width)(struct slot *slot, enum pcie_link_width *val);
+ int (*get_cur_lnk_width)(struct slot *slot, enum pcie_link_width *val);
+ int (*query_power_fault)(struct slot *slot);
+ void (*green_led_on)(struct slot *slot);
+ void (*green_led_off)(struct slot *slot);
+ void (*green_led_blink)(struct slot *slot);
+ void (*release_ctlr)(struct controller *ctrl);
+ int (*check_lnk_status)(struct controller *ctrl);
};
-
#ifdef CONFIG_ACPI
#include <acpi/acpi.h>
#include <acpi/acpi_bus.h>
#include <acpi/actypes.h>
#include <linux/pci-acpi.h>
-#define pciehp_get_hp_hw_control_from_firmware(dev) \
+#define pciehp_get_hp_hw_control_from_firmware(dev) \
pciehp_acpi_get_hp_hw_control_from_firmware(dev)
static inline int pciehp_get_hp_params_from_firmware(struct pci_dev *dev,
struct hotplug_params *hpp)
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c
index f13f31323e8..a92eda6e02f 100644
--- a/drivers/pci/hotplug/pciehp_core.c
+++ b/drivers/pci/hotplug/pciehp_core.c
@@ -34,6 +34,7 @@
#include <linux/pci.h>
#include "pciehp.h"
#include <linux/interrupt.h>
+#include <linux/time.h>
/* Global variables */
int pciehp_debug;
@@ -87,6 +88,95 @@ static struct hotplug_slot_ops pciehp_hotplug_slot_ops = {
.get_cur_bus_speed = get_cur_bus_speed,
};
+/*
+ * Check the status of the Electro Mechanical Interlock (EMI)
+ */
+static int get_lock_status(struct hotplug_slot *hotplug_slot, u8 *value)
+{
+ struct slot *slot = hotplug_slot->private;
+ return (slot->hpc_ops->get_emi_status(slot, value));
+}
+
+/*
+ * sysfs interface for the Electro Mechanical Interlock (EMI)
+ * 1 == locked, 0 == unlocked
+ */
+static ssize_t lock_read_file(struct hotplug_slot *slot, char *buf)
+{
+ int retval;
+ u8 value;
+
+ retval = get_lock_status(slot, &value);
+ if (retval)
+ goto lock_read_exit;
+ retval = sprintf (buf, "%d\n", value);
+
+lock_read_exit:
+ return retval;
+}
+
+/*
+ * Change the status of the Electro Mechanical Interlock (EMI)
+ * This is a toggle - in addition there must be at least 1 second
+ * in between toggles.
+ */
+static int set_lock_status(struct hotplug_slot *hotplug_slot, u8 status)
+{
+ struct slot *slot = hotplug_slot->private;
+ int retval;
+ u8 value;
+
+ mutex_lock(&slot->ctrl->crit_sect);
+
+ /* has it been >1 sec since our last toggle? */
+ if ((get_seconds() - slot->last_emi_toggle) < 1)
+ return -EINVAL;
+
+ /* see what our current state is */
+ retval = get_lock_status(hotplug_slot, &value);
+ if (retval || (value == status))
+ goto set_lock_exit;
+
+ slot->hpc_ops->toggle_emi(slot);
+set_lock_exit:
+ mutex_unlock(&slot->ctrl->crit_sect);
+ return 0;
+}
+
+/*
+ * sysfs interface which allows the user to toggle the Electro Mechanical
+ * Interlock. Valid values are either 0 or 1. 0 == unlock, 1 == lock
+ */
+static ssize_t lock_write_file(struct hotplug_slot *slot, const char *buf,
+ size_t count)
+{
+ unsigned long llock;
+ u8 lock;
+ int retval = 0;
+
+ llock = simple_strtoul(buf, NULL, 10);
+ lock = (u8)(llock & 0xff);
+
+ switch (lock) {
+ case 0:
+ case 1:
+ retval = set_lock_status(slot, lock);
+ break;
+ default:
+ err ("%d is an invalid lock value\n", lock);
+ retval = -EINVAL;
+ }
+ if (retval)
+ return retval;
+ return count;
+}
+
+static struct hotplug_slot_attribute hotplug_slot_attr_lock = {
+ .attr = {.name = "lock", .mode = S_IFREG | S_IRUGO | S_IWUSR},
+ .show = lock_read_file,
+ .store = lock_write_file
+};
+
/**
* release_slot - free up the memory used by a slot
* @hotplug_slot: slot to free
@@ -98,148 +188,108 @@ static void release_slot(struct hotplug_slot *hotplug_slot)
dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
kfree(slot->hotplug_slot->info);
- kfree(slot->hotplug_slot->name);
kfree(slot->hotplug_slot);
kfree(slot);
}
+static void make_slot_name(struct slot *slot)
+{
+ snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "%04d_%04d",
+ slot->bus, slot->number);
+}
+
static int init_slots(struct controller *ctrl)
{
struct slot *slot;
- struct hpc_ops *hpc_ops;
struct hotplug_slot *hotplug_slot;
- struct hotplug_slot_info *hotplug_slot_info;
- u8 number_of_slots;
- u8 slot_device;
- u32 slot_number;
- int result = -ENOMEM;
+ struct hotplug_slot_info *info;
+ int retval = -ENOMEM;
+ int i;
- number_of_slots = ctrl->num_slots;
- slot_device = ctrl->slot_device_offset;
- slot_number = ctrl->first_slot;
-
- while (number_of_slots) {
+ for (i = 0; i < ctrl->num_slots; i++) {
slot = kzalloc(sizeof(*slot), GFP_KERNEL);
if (!slot)
goto error;
- slot->hotplug_slot =
- kzalloc(sizeof(*(slot->hotplug_slot)),
- GFP_KERNEL);
- if (!slot->hotplug_slot)
+ hotplug_slot = kzalloc(sizeof(*hotplug_slot), GFP_KERNEL);
+ if (!hotplug_slot)
goto error_slot;
- hotplug_slot = slot->hotplug_slot;
+ slot->hotplug_slot = hotplug_slot;
- hotplug_slot->info =
- kzalloc(sizeof(*(hotplug_slot->info)),
- GFP_KERNEL);
- if (!hotplug_slot->info)
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
+ if (!info)
goto error_hpslot;
- hotplug_slot_info = hotplug_slot->info;
- hotplug_slot->name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL);
- if (!hotplug_slot->name)
- goto error_info;
+ hotplug_slot->info = info;
- slot->ctrl = ctrl;
- slot->bus = ctrl->slot_bus;
- slot->device = slot_device;
- slot->hpc_ops = hpc_ops = ctrl->hpc_ops;
+ hotplug_slot->name = slot->name;
+ slot->hp_slot = i;
+ slot->ctrl = ctrl;
+ slot->bus = ctrl->pci_dev->subordinate->number;
+ slot->device = ctrl->slot_device_offset + i;
+ slot->hpc_ops = ctrl->hpc_ops;
slot->number = ctrl->first_slot;
- slot->hp_slot = slot_device - ctrl->slot_device_offset;
/* register this slot with the hotplug pci core */
hotplug_slot->private = slot;
hotplug_slot->release = &release_slot;
- make_slot_name(hotplug_slot->name, SLOT_NAME_SIZE, slot);
+ make_slot_name(slot);
hotplug_slot->ops = &pciehp_hotplug_slot_ops;
- hpc_ops->get_power_status(slot,
- &(hotplug_slot_info->power_status));
- hpc_ops->get_attention_status(slot,
- &(hotplug_slot_info->attention_status));
- hpc_ops->get_latch_status(slot,
- &(hotplug_slot_info->latch_status));
- hpc_ops->get_adapter_status(slot,
- &(hotplug_slot_info->adapter_status));
+ get_power_status(hotplug_slot, &info->power_status);
+ get_attention_status(hotplug_slot, &info->attention_status);
+ get_latch_status(hotplug_slot, &info->latch_status);
+ get_adapter_status(hotplug_slot, &info->adapter_status);
dbg("Registering bus=%x dev=%x hp_slot=%x sun=%x "
- "slot_device_offset=%x\n",
- slot->bus, slot->device, slot->hp_slot, slot->number,
- ctrl->slot_device_offset);
- result = pci_hp_register(hotplug_slot);
- if (result) {
- err ("pci_hp_register failed with error %d\n", result);
- goto error_name;
+ "slot_device_offset=%x\n", slot->bus, slot->device,
+ slot->hp_slot, slot->number, ctrl->slot_device_offset);
+ retval = pci_hp_register(hotplug_slot);
+ if (retval) {
+ err ("pci_hp_register failed with error %d\n", retval);
+ goto error_info;
+ }
+ /* create additional sysfs entries */
+ if (EMI(ctrl->ctrlcap)) {
+ retval = sysfs_create_file(&hotplug_slot->kobj,
+ &hotplug_slot_attr_lock.attr);
+ if (retval) {
+ pci_hp_deregister(hotplug_slot);
+ err("cannot create additional sysfs entries\n");
+ goto error_info;
+ }
}
- slot->next = ctrl->slot;
- ctrl->slot = slot;
-
- number_of_slots--;
- slot_device++;
- slot_number += ctrl->slot_num_inc;
+ list_add(&slot->slot_list, &ctrl->slot_list);
}
return 0;
-
-error_name:
- kfree(hotplug_slot->name);
error_info:
- kfree(hotplug_slot_info);
+ kfree(info);
error_hpslot:
kfree(hotplug_slot);
error_slot:
kfree(slot);
error:
- return result;
-}
-
-
-static int cleanup_slots (struct controller * ctrl)
-{
- struct slot *old_slot, *next_slot;
-
- old_slot = ctrl->slot;
- ctrl->slot = NULL;
-
- while (old_slot) {
- next_slot = old_slot->next;
- pci_hp_deregister (old_slot->hotplug_slot);
- old_slot = next_slot;
- }
-
-
- return(0);
+ return retval;
}
-static int get_ctlr_slot_config(struct controller *ctrl)
+static void cleanup_slots(struct controller *ctrl)
{
- int num_ctlr_slots; /* Not needed; PCI Express has 1 slot per port*/
- int first_device_num; /* Not needed */
- int physical_slot_num;
- u8 ctrlcap;
- int rc;
+ struct list_head *tmp;
+ struct list_head *next;
+ struct slot *slot;
- rc = pcie_get_ctlr_slot_config(ctrl, &num_ctlr_slots, &first_device_num, &physical_slot_num, &ctrlcap);
- if (rc) {
- err("%s: get_ctlr_slot_config fail for b:d (%x:%x)\n", __FUNCTION__, ctrl->bus, ctrl->device);
- return (-1);
+ list_for_each_safe(tmp, next, &ctrl->slot_list) {
+ slot = list_entry(tmp, struct slot, slot_list);
+ list_del(&slot->slot_list);
+ if (EMI(ctrl->ctrlcap))
+ sysfs_remove_file(&slot->hotplug_slot->kobj,
+ &hotplug_slot_attr_lock.attr);
+ pci_hp_deregister(slot->hotplug_slot);
}
-
- ctrl->num_slots = num_ctlr_slots; /* PCI Express has 1 slot per port */
- ctrl->slot_device_offset = first_device_num;
- ctrl->first_slot = physical_slot_num;
- ctrl->ctrlcap = ctrlcap;
-
- dbg("%s: bus(0x%x) num_slot(0x%x) 1st_dev(0x%x) psn(0x%x) ctrlcap(%x) for b:d (%x:%x)\n",
- __FUNCTION__, ctrl->slot_bus, num_ctlr_slots, first_device_num, physical_slot_num, ctrlcap,
- ctrl->bus, ctrl->device);
-
- return (0);
}
-
/*
* set_attention_status - Turns the Amber LED for a slot on, off or blink
*/
@@ -378,8 +428,6 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
int rc;
struct controller *ctrl;
struct slot *t_slot;
- int first_device_num = 0 ; /* first PCI device number supported by this PCIE */
- int num_ctlr_slots; /* number of slots supported by this HPC */
u8 value;
struct pci_dev *pdev;
@@ -388,6 +436,7 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
err("%s : out of memory\n", __FUNCTION__);
goto err_out_none;
}
+ INIT_LIST_HEAD(&ctrl->slot_list);
pdev = dev->port;
ctrl->pci_dev = pdev;
@@ -400,13 +449,6 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
pci_set_drvdata(pdev, ctrl);
- ctrl->pci_bus = kmalloc(sizeof(*ctrl->pci_bus), GFP_KERNEL);
- if (!ctrl->pci_bus) {
- err("%s: out of memory\n", __FUNCTION__);
- rc = -ENOMEM;
- goto err_out_unmap_mmio_region;
- }
- memcpy (ctrl->pci_bus, pdev->bus, sizeof (*ctrl->pci_bus));
ctrl->bus = pdev->bus->number; /* ctrl bus */
ctrl->slot_bus = pdev->subordinate->number; /* bus controlled by this HPC */
@@ -415,26 +457,14 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
dbg("%s: ctrl bus=0x%x, device=%x, function=%x, irq=%x\n", __FUNCTION__,
ctrl->bus, ctrl->device, ctrl->function, pdev->irq);
- /*
- * Save configuration headers for this and subordinate PCI buses
- */
-
- rc = get_ctlr_slot_config(ctrl);
- if (rc) {
- err(msg_initialization_err, rc);
- goto err_out_free_ctrl_bus;
- }
- first_device_num = ctrl->slot_device_offset;
- num_ctlr_slots = ctrl->num_slots;
-
/* Setup the slot information structures */
rc = init_slots(ctrl);
if (rc) {
- err(msg_initialization_err, 6);
- goto err_out_free_ctrl_slot;
+ err("%s: slot initialization failed\n", PCIE_MODULE_NAME);
+ goto err_out_release_ctlr;
}
- t_slot = pciehp_find_slot(ctrl, first_device_num);
+ t_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset);
/* Finish setting up the hot plug ctrl device */
ctrl->next_event = 0;
@@ -447,32 +477,18 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
pciehp_ctrl_list = ctrl;
}
- /* Wait for exclusive access to hardware */
- mutex_lock(&ctrl->ctrl_lock);
-
t_slot->hpc_ops->get_adapter_status(t_slot, &value); /* Check if slot is occupied */
-
if ((POWER_CTRL(ctrl->ctrlcap)) && !value) {
rc = t_slot->hpc_ops->power_off_slot(t_slot); /* Power off slot if not occupied*/
- if (rc) {
- /* Done with exclusive hardware access */
- mutex_unlock(&ctrl->ctrl_lock);
+ if (rc)
goto err_out_free_ctrl_slot;
- } else
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
}
- /* Done with exclusive hardware access */
- mutex_unlock(&ctrl->ctrl_lock);
-
return 0;
err_out_free_ctrl_slot:
cleanup_slots(ctrl);
-err_out_free_ctrl_bus:
- kfree(ctrl->pci_bus);
-err_out_unmap_mmio_region:
+err_out_release_ctlr:
ctrl->hpc_ops->release_ctlr(ctrl);
err_out_free_ctrl:
kfree(ctrl);
@@ -506,8 +522,6 @@ static void __exit unload_pciehpd(void)
while (ctrl) {
cleanup_slots(ctrl);
- kfree (ctrl->pci_bus);
-
ctrl->hpc_ops->release_ctlr(ctrl);
tctrl = ctrl;
diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c
index 372c63e35aa..4283ef56dbd 100644
--- a/drivers/pci/hotplug/pciehp_ctrl.c
+++ b/drivers/pci/hotplug/pciehp_ctrl.c
@@ -48,9 +48,8 @@ static inline char *slot_name(struct slot *p_slot)
return p_slot->hotplug_slot->name;
}
-u8 pciehp_handle_attention_button(u8 hp_slot, void *inst_id)
+u8 pciehp_handle_attention_button(u8 hp_slot, struct controller *ctrl)
{
- struct controller *ctrl = (struct controller *) inst_id;
struct slot *p_slot;
u8 rc = 0;
u8 getstatus;
@@ -101,9 +100,8 @@ u8 pciehp_handle_attention_button(u8 hp_slot, void *inst_id)
}
-u8 pciehp_handle_switch_change(u8 hp_slot, void *inst_id)
+u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl)
{
- struct controller *ctrl = (struct controller *) inst_id;
struct slot *p_slot;
u8 rc = 0;
u8 getstatus;
@@ -143,9 +141,8 @@ u8 pciehp_handle_switch_change(u8 hp_slot, void *inst_id)
return rc;
}
-u8 pciehp_handle_presence_change(u8 hp_slot, void *inst_id)
+u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl)
{
- struct controller *ctrl = (struct controller *) inst_id;
struct slot *p_slot;
u8 presence_save, rc = 0;
struct event_info *taskInfo;
@@ -187,9 +184,8 @@ u8 pciehp_handle_presence_change(u8 hp_slot, void *inst_id)
return rc;
}
-u8 pciehp_handle_power_fault(u8 hp_slot, void *inst_id)
+u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl)
{
- struct controller *ctrl = (struct controller *) inst_id;
struct slot *p_slot;
u8 rc = 0;
struct event_info *taskInfo;
@@ -233,35 +229,25 @@ u8 pciehp_handle_power_fault(u8 hp_slot, void *inst_id)
static void set_slot_off(struct controller *ctrl, struct slot * pslot)
{
- /* Wait for exclusive access to hardware */
- mutex_lock(&ctrl->ctrl_lock);
-
/* turn off slot, turn on Amber LED, turn off Green LED if supported*/
if (POWER_CTRL(ctrl->ctrlcap)) {
if (pslot->hpc_ops->power_off_slot(pslot)) {
- err("%s: Issue of Slot Power Off command failed\n", __FUNCTION__);
- mutex_unlock(&ctrl->ctrl_lock);
+ err("%s: Issue of Slot Power Off command failed\n",
+ __FUNCTION__);
return;
}
- wait_for_ctrl_irq (ctrl);
}
- if (PWR_LED(ctrl->ctrlcap)) {
+ if (PWR_LED(ctrl->ctrlcap))
pslot->hpc_ops->green_led_off(pslot);
- wait_for_ctrl_irq (ctrl);
- }
- if (ATTN_LED(ctrl->ctrlcap)) {
- if (pslot->hpc_ops->set_attention_status(pslot, 1)) {
- err("%s: Issue of Set Attention Led command failed\n", __FUNCTION__);
- mutex_unlock(&ctrl->ctrl_lock);
+ if (ATTN_LED(ctrl->ctrlcap)) {
+ if (pslot->hpc_ops->set_attention_status(pslot, 1)) {
+ err("%s: Issue of Set Attention Led command failed\n",
+ __FUNCTION__);
return;
}
- wait_for_ctrl_irq (ctrl);
}
-
- /* Done with exclusive hardware access */
- mutex_unlock(&ctrl->ctrl_lock);
}
/**
@@ -274,7 +260,7 @@ static void set_slot_off(struct controller *ctrl, struct slot * pslot)
static int board_added(struct slot *p_slot)
{
u8 hp_slot;
- int rc = 0;
+ int retval = 0;
struct controller *ctrl = p_slot->ctrl;
hp_slot = p_slot->device - ctrl->slot_device_offset;
@@ -283,53 +269,38 @@ static int board_added(struct slot *p_slot)
__FUNCTION__, p_slot->device,
ctrl->slot_device_offset, hp_slot);
- /* Wait for exclusive access to hardware */
- mutex_lock(&ctrl->ctrl_lock);
-
if (POWER_CTRL(ctrl->ctrlcap)) {
/* Power on slot */
- rc = p_slot->hpc_ops->power_on_slot(p_slot);
- if (rc) {
- mutex_unlock(&ctrl->ctrl_lock);
- return -1;
- }
-
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
+ retval = p_slot->hpc_ops->power_on_slot(p_slot);
+ if (retval)
+ return retval;
}
- if (PWR_LED(ctrl->ctrlcap)) {
+ if (PWR_LED(ctrl->ctrlcap))
p_slot->hpc_ops->green_led_blink(p_slot);
-
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
- }
-
- /* Done with exclusive hardware access */
- mutex_unlock(&ctrl->ctrl_lock);
/* Wait for ~1 second */
- wait_for_ctrl_irq (ctrl);
+ msleep(1000);
- /* Check link training status */
- rc = p_slot->hpc_ops->check_lnk_status(ctrl);
- if (rc) {
+ /* Check link training status */
+ retval = p_slot->hpc_ops->check_lnk_status(ctrl);
+ if (retval) {
err("%s: Failed to check link status\n", __FUNCTION__);
set_slot_off(ctrl, p_slot);
- return rc;
+ return retval;
}
/* Check for a power fault */
if (p_slot->hpc_ops->query_power_fault(p_slot)) {
dbg("%s: power fault detected\n", __FUNCTION__);
- rc = POWER_FAILURE;
+ retval = POWER_FAILURE;
goto err_exit;
}
- rc = pciehp_configure_device(p_slot);
- if (rc) {
+ retval = pciehp_configure_device(p_slot);
+ if (retval) {
err("Cannot add device 0x%x:%x\n", p_slot->bus,
- p_slot->device);
+ p_slot->device);
goto err_exit;
}
@@ -338,26 +309,16 @@ static int board_added(struct slot *p_slot)
*/
if (pcie_mch_quirk)
pci_fixup_device(pci_fixup_final, ctrl->pci_dev);
- if (PWR_LED(ctrl->ctrlcap)) {
- /* Wait for exclusive access to hardware */
- mutex_lock(&ctrl->ctrl_lock);
-
+ if (PWR_LED(ctrl->ctrlcap))
p_slot->hpc_ops->green_led_on(p_slot);
-
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
-
- /* Done with exclusive hardware access */
- mutex_unlock(&ctrl->ctrl_lock);
- }
+
return 0;
err_exit:
set_slot_off(ctrl, p_slot);
- return -1;
+ return retval;
}
-
/**
* remove_board - Turns off slot and LED's
*
@@ -366,44 +327,32 @@ static int remove_board(struct slot *p_slot)
{
u8 device;
u8 hp_slot;
- int rc;
+ int retval = 0;
struct controller *ctrl = p_slot->ctrl;
- if (pciehp_unconfigure_device(p_slot))
- return 1;
+ retval = pciehp_unconfigure_device(p_slot);
+ if (retval)
+ return retval;
device = p_slot->device;
-
hp_slot = p_slot->device - ctrl->slot_device_offset;
p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot);
- /* Wait for exclusive access to hardware */
- mutex_lock(&ctrl->ctrl_lock);
-
if (POWER_CTRL(ctrl->ctrlcap)) {
/* power off slot */
- rc = p_slot->hpc_ops->power_off_slot(p_slot);
- if (rc) {
- err("%s: Issue of Slot Disable command failed\n", __FUNCTION__);
- mutex_unlock(&ctrl->ctrl_lock);
- return rc;
+ retval = p_slot->hpc_ops->power_off_slot(p_slot);
+ if (retval) {
+ err("%s: Issue of Slot Disable command failed\n",
+ __FUNCTION__);
+ return retval;
}
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
}
- if (PWR_LED(ctrl->ctrlcap)) {
+ if (PWR_LED(ctrl->ctrlcap))
/* turn off Green LED */
p_slot->hpc_ops->green_led_off(p_slot);
-
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
- }
-
- /* Done with exclusive hardware access */
- mutex_unlock(&ctrl->ctrl_lock);
return 0;
}
@@ -448,18 +397,10 @@ static void pciehp_pushbutton_thread(unsigned long slot)
dbg("%s: adding bus:device(%x:%x)\n", __FUNCTION__,
p_slot->bus, p_slot->device);
- if (pciehp_enable_slot(p_slot) && PWR_LED(p_slot->ctrl->ctrlcap)) {
- /* Wait for exclusive access to hardware */
- mutex_lock(&p_slot->ctrl->ctrl_lock);
-
+ if (pciehp_enable_slot(p_slot) &&
+ PWR_LED(p_slot->ctrl->ctrlcap))
p_slot->hpc_ops->green_led_off(p_slot);
- /* Wait for the command to complete */
- wait_for_ctrl_irq (p_slot->ctrl);
-
- /* Done with exclusive hardware access */
- mutex_unlock(&p_slot->ctrl->ctrl_lock);
- }
p_slot->state = STATIC_STATE;
}
@@ -498,18 +439,10 @@ static void pciehp_surprise_rm_thread(unsigned long slot)
dbg("%s: adding bus:device(%x:%x)\n",
__FUNCTION__, p_slot->bus, p_slot->device);
- if (pciehp_enable_slot(p_slot) && PWR_LED(p_slot->ctrl->ctrlcap)) {
- /* Wait for exclusive access to hardware */
- mutex_lock(&p_slot->ctrl->ctrl_lock);
-
+ if (pciehp_enable_slot(p_slot) &&
+ PWR_LED(p_slot->ctrl->ctrlcap))
p_slot->hpc_ops->green_led_off(p_slot);
- /* Wait for the command to complete */
- wait_for_ctrl_irq (p_slot->ctrl);
-
- /* Done with exclusive hardware access */
- mutex_unlock(&p_slot->ctrl->ctrl_lock);
- }
p_slot->state = STATIC_STATE;
}
@@ -620,46 +553,24 @@ static void interrupt_event_handler(struct controller *ctrl)
switch (p_slot->state) {
case BLINKINGOFF_STATE:
- /* Wait for exclusive access to hardware */
- mutex_lock(&ctrl->ctrl_lock);
-
- if (PWR_LED(ctrl->ctrlcap)) {
+ if (PWR_LED(ctrl->ctrlcap))
p_slot->hpc_ops->green_led_on(p_slot);
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
- }
- if (ATTN_LED(ctrl->ctrlcap)) {
- p_slot->hpc_ops->set_attention_status(p_slot, 0);
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
- }
- /* Done with exclusive hardware access */
- mutex_unlock(&ctrl->ctrl_lock);
+ if (ATTN_LED(ctrl->ctrlcap))
+ p_slot->hpc_ops->set_attention_status(p_slot, 0);
break;
case BLINKINGON_STATE:
- /* Wait for exclusive access to hardware */
- mutex_lock(&ctrl->ctrl_lock);
-
- if (PWR_LED(ctrl->ctrlcap)) {
+ if (PWR_LED(ctrl->ctrlcap))
p_slot->hpc_ops->green_led_off(p_slot);
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
- }
- if (ATTN_LED(ctrl->ctrlcap)){
- p_slot->hpc_ops->set_attention_status(p_slot, 0);
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
- }
- /* Done with exclusive hardware access */
- mutex_unlock(&ctrl->ctrl_lock);
+ if (ATTN_LED(ctrl->ctrlcap))
+ p_slot->hpc_ops->set_attention_status(p_slot, 0);
break;
default:
warn("Not a valid state\n");
return;
}
- info(msg_button_cancel, slot_name(p_slot));
+ info("PCI slot #%s - action canceled due to button press.\n", slot_name(p_slot));
p_slot->state = STATIC_STATE;
}
/* ***********Button Pressed (No action on 1st press...) */
@@ -672,34 +583,21 @@ static void interrupt_event_handler(struct controller *ctrl)
/* slot is on */
dbg("slot is on\n");
p_slot->state = BLINKINGOFF_STATE;
- info(msg_button_off, slot_name(p_slot));
+ info("PCI slot #%s - powering off due to button press.\n", slot_name(p_slot));
} else {
/* slot is off */
dbg("slot is off\n");
p_slot->state = BLINKINGON_STATE;
- info(msg_button_on, slot_name(p_slot));
+ info("PCI slot #%s - powering on due to button press.\n", slot_name(p_slot));
}
- /* Wait for exclusive access to hardware */
- mutex_lock(&ctrl->ctrl_lock);
-
/* blink green LED and turn off amber */
- if (PWR_LED(ctrl->ctrlcap)) {
+ if (PWR_LED(ctrl->ctrlcap))
p_slot->hpc_ops->green_led_blink(p_slot);
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
- }
- if (ATTN_LED(ctrl->ctrlcap)) {
+ if (ATTN_LED(ctrl->ctrlcap))
p_slot->hpc_ops->set_attention_status(p_slot, 0);
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
- }
-
- /* Done with exclusive hardware access */
- mutex_unlock(&ctrl->ctrl_lock);
-
init_timer(&p_slot->task_event);
p_slot->task_event.expires = jiffies + 5 * HZ; /* 5 second delay */
p_slot->task_event.function = (void (*)(unsigned long)) pushbutton_helper_thread;
@@ -712,21 +610,11 @@ static void interrupt_event_handler(struct controller *ctrl)
else if (ctrl->event_queue[loop].event_type == INT_POWER_FAULT) {
if (POWER_CTRL(ctrl->ctrlcap)) {
dbg("power fault\n");
- /* Wait for exclusive access to hardware */
- mutex_lock(&ctrl->ctrl_lock);
-
- if (ATTN_LED(ctrl->ctrlcap)) {
+ if (ATTN_LED(ctrl->ctrlcap))
p_slot->hpc_ops->set_attention_status(p_slot, 1);
- wait_for_ctrl_irq (ctrl);
- }
- if (PWR_LED(ctrl->ctrlcap)) {
+ if (PWR_LED(ctrl->ctrlcap))
p_slot->hpc_ops->green_led_off(p_slot);
- wait_for_ctrl_irq (ctrl);
- }
-
- /* Done with exclusive hardware access */
- mutex_unlock(&ctrl->ctrl_lock);
}
}
/***********SURPRISE REMOVAL********************/
@@ -754,7 +642,6 @@ static void interrupt_event_handler(struct controller *ctrl)
}
}
-
int pciehp_enable_slot(struct slot *p_slot)
{
u8 getstatus = 0;
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
index 25d3aadfddb..fbc64aa2dd6 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -35,6 +35,7 @@
#include <linux/timer.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
+#include <linux/time.h>
#include "../pci.h"
#include "pciehp.h"
@@ -105,34 +106,30 @@ enum ctrl_offsets {
ROOTCTRL = offsetof(struct ctrl_reg, root_ctrl),
ROOTSTATUS = offsetof(struct ctrl_reg, root_status),
};
-static int pcie_cap_base = 0; /* Base of the PCI Express capability item structure */
-
-#define PCIE_CAP_ID(cb) ( cb + PCIECAPID )
-#define NXT_CAP_PTR(cb) ( cb + NXTCAPPTR )
-#define CAP_REG(cb) ( cb + CAPREG )
-#define DEV_CAP(cb) ( cb + DEVCAP )
-#define DEV_CTRL(cb) ( cb + DEVCTRL )
-#define DEV_STATUS(cb) ( cb + DEVSTATUS )
-#define LNK_CAP(cb) ( cb + LNKCAP )
-#define LNK_CTRL(cb) ( cb + LNKCTRL )
-#define LNK_STATUS(cb) ( cb + LNKSTATUS )
-#define SLOT_CAP(cb) ( cb + SLOTCAP )
-#define SLOT_CTRL(cb) ( cb + SLOTCTRL )
-#define SLOT_STATUS(cb) ( cb + SLOTSTATUS )
-#define ROOT_CTRL(cb) ( cb + ROOTCTRL )
-#define ROOT_STATUS(cb) ( cb + ROOTSTATUS )
-
-#define hp_register_read_word(pdev, reg , value) \
- pci_read_config_word(pdev, reg, &value)
-
-#define hp_register_read_dword(pdev, reg , value) \
- pci_read_config_dword(pdev, reg, &value)
-
-#define hp_register_write_word(pdev, reg , value) \
- pci_write_config_word(pdev, reg, value)
-
-#define hp_register_dwrite_word(pdev, reg , value) \
- pci_write_config_dword(pdev, reg, value)
+
+static inline int pciehp_readw(struct controller *ctrl, int reg, u16 *value)
+{
+ struct pci_dev *dev = ctrl->pci_dev;
+ return pci_read_config_word(dev, ctrl->cap_base + reg, value);
+}
+
+static inline int pciehp_readl(struct controller *ctrl, int reg, u32 *value)
+{
+ struct pci_dev *dev = ctrl->pci_dev;
+ return pci_read_config_dword(dev, ctrl->cap_base + reg, value);
+}
+
+static inline int pciehp_writew(struct controller *ctrl, int reg, u16 value)
+{
+ struct pci_dev *dev = ctrl->pci_dev;
+ return pci_write_config_word(dev, ctrl->cap_base + reg, value);
+}
+
+static inline int pciehp_writel(struct controller *ctrl, int reg, u32 value)
+{
+ struct pci_dev *dev = ctrl->pci_dev;
+ return pci_write_config_dword(dev, ctrl->cap_base + reg, value);
+}
/* Field definitions in PCI Express Capabilities Register */
#define CAP_VER 0x000F
@@ -196,6 +193,7 @@ static int pcie_cap_base = 0; /* Base of the PCI Express capability item struct
#define ATTN_LED_CTRL 0x00C0
#define PWR_LED_CTRL 0x0300
#define PWR_CTRL 0x0400
+#define EMI_CTRL 0x0800
/* Attention indicator and Power indicator states */
#define LED_ON 0x01
@@ -206,6 +204,10 @@ static int pcie_cap_base = 0; /* Base of the PCI Express capability item struct
#define POWER_ON 0
#define POWER_OFF 0x0400
+/* EMI Status defines */
+#define EMI_DISENGAGED 0
+#define EMI_ENGAGED 1
+
/* Field definitions in Slot Status Register */
#define ATTN_BUTTN_PRESSED 0x0001
#define PWR_FAULT_DETECTED 0x0002
@@ -214,114 +216,117 @@ static int pcie_cap_base = 0; /* Base of the PCI Express capability item struct
#define CMD_COMPLETED 0x0010
#define MRL_STATE 0x0020
#define PRSN_STATE 0x0040
+#define EMI_STATE 0x0080
+#define EMI_STATUS_BIT 7
static spinlock_t hpc_event_lock;
DEFINE_DBG_BUFFER /* Debug string buffer for entire HPC defined here */
-static struct php_ctlr_state_s *php_ctlr_list_head; /* HPC state linked list */
static int ctlr_seq_num = 0; /* Controller sequence # */
-static spinlock_t list_lock;
-
-static irqreturn_t pcie_isr(int IRQ, void *dev_id);
-static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds);
+static irqreturn_t pcie_isr(int irq, void *dev_id);
+static void start_int_poll_timer(struct controller *ctrl, int sec);
/* This is the interrupt polling timeout function. */
-static void int_poll_timeout(unsigned long lphp_ctlr)
+static void int_poll_timeout(unsigned long data)
{
- struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *)lphp_ctlr;
+ struct controller *ctrl = (struct controller *)data;
DBG_ENTER_ROUTINE
- if ( !php_ctlr ) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return;
- }
-
/* Poll for interrupt events. regs == NULL => polling */
- pcie_isr( 0, (void *)php_ctlr );
-
- init_timer(&php_ctlr->int_poll_timer);
+ pcie_isr(0, ctrl);
+ init_timer(&ctrl->poll_timer);
if (!pciehp_poll_time)
pciehp_poll_time = 2; /* reset timer to poll in 2 secs if user doesn't specify at module installation*/
- start_int_poll_timer(php_ctlr, pciehp_poll_time);
-
- return;
+ start_int_poll_timer(ctrl, pciehp_poll_time);
}
/* This function starts the interrupt polling timer. */
-static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds)
+static void start_int_poll_timer(struct controller *ctrl, int sec)
{
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return;
- }
+ /* Clamp to sane value */
+ if ((sec <= 0) || (sec > 60))
+ sec = 2;
+
+ ctrl->poll_timer.function = &int_poll_timeout;
+ ctrl->poll_timer.data = (unsigned long)ctrl;
+ ctrl->poll_timer.expires = jiffies + sec * HZ;
+ add_timer(&ctrl->poll_timer);
+}
- if ( ( seconds <= 0 ) || ( seconds > 60 ) )
- seconds = 2; /* Clamp to sane value */
+static inline int pcie_wait_cmd(struct controller *ctrl)
+{
+ int retval = 0;
+ unsigned int msecs = pciehp_poll_mode ? 2500 : 1000;
+ unsigned long timeout = msecs_to_jiffies(msecs);
+ int rc;
- php_ctlr->int_poll_timer.function = &int_poll_timeout;
- php_ctlr->int_poll_timer.data = (unsigned long)php_ctlr; /* Instance data */
- php_ctlr->int_poll_timer.expires = jiffies + seconds * HZ;
- add_timer(&php_ctlr->int_poll_timer);
+ rc = wait_event_interruptible_timeout(ctrl->queue,
+ !ctrl->cmd_busy, timeout);
+ if (!rc)
+ dbg("Command not completed in 1000 msec\n");
+ else if (rc < 0) {
+ retval = -EINTR;
+ info("Command was interrupted by a signal\n");
+ }
- return;
+ return retval;
}
static int pcie_write_cmd(struct slot *slot, u16 cmd)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
int retval = 0;
u16 slot_status;
DBG_ENTER_ROUTINE
-
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
- }
- retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(slot->ctrl->cap_base), slot_status);
+ mutex_lock(&ctrl->ctrl_lock);
+
+ retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (retval) {
- err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
- return retval;
- }
-
+ err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
+ goto out;
+ }
+
if ((slot_status & CMD_COMPLETED) == CMD_COMPLETED ) {
- /* After 1 sec and CMD_COMPLETED still not set, just proceed forward to issue
- the next command according to spec. Just print out the error message */
- dbg("%s : CMD_COMPLETED not clear after 1 sec.\n", __FUNCTION__);
+ /* After 1 sec and CMD_COMPLETED still not set, just
+ proceed forward to issue the next command according
+ to spec. Just print out the error message */
+ dbg("%s: CMD_COMPLETED not clear after 1 sec.\n",
+ __FUNCTION__);
}
- retval = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), cmd | CMD_CMPL_INTR_ENABLE);
+ ctrl->cmd_busy = 1;
+ retval = pciehp_writew(ctrl, SLOTCTRL, (cmd | CMD_CMPL_INTR_ENABLE));
if (retval) {
- err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
- return retval;
+ err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__);
+ goto out;
}
+ /*
+ * Wait for command completion.
+ */
+ retval = pcie_wait_cmd(ctrl);
+ out:
+ mutex_unlock(&ctrl->ctrl_lock);
DBG_LEAVE_ROUTINE
return retval;
}
static int hpc_check_lnk_status(struct controller *ctrl)
{
- struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle;
u16 lnk_status;
int retval = 0;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
- }
-
- retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS(ctrl->cap_base), lnk_status);
-
+ retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status);
if (retval) {
- err("%s : hp_register_read_word LNK_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot read LNKSTATUS register\n", __FUNCTION__);
return retval;
}
@@ -340,26 +345,21 @@ static int hpc_check_lnk_status(struct controller *ctrl)
static int hpc_get_attention_status(struct slot *slot, u8 *status)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
u16 slot_ctrl;
u8 atten_led_state;
int retval = 0;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
- }
-
- retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
-
+ retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
if (retval) {
- err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
return retval;
}
- dbg("%s: SLOT_CTRL %x, value read %x\n", __FUNCTION__,SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
+ dbg("%s: SLOTCTRL %x, value read %x\n",
+ __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_ctrl);
atten_led_state = (slot_ctrl & ATTN_LED_CTRL) >> 6;
@@ -385,27 +385,22 @@ static int hpc_get_attention_status(struct slot *slot, u8 *status)
return 0;
}
-static int hpc_get_power_status(struct slot * slot, u8 *status)
+static int hpc_get_power_status(struct slot *slot, u8 *status)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
u16 slot_ctrl;
u8 pwr_state;
int retval = 0;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
- }
-
- retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
-
+ retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
if (retval) {
- err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
return retval;
}
- dbg("%s: SLOT_CTRL %x value read %x\n", __FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
+ dbg("%s: SLOTCTRL %x value read %x\n",
+ __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_ctrl);
pwr_state = (slot_ctrl & PWR_CTRL) >> 10;
@@ -428,21 +423,15 @@ static int hpc_get_power_status(struct slot * slot, u8 *status)
static int hpc_get_latch_status(struct slot *slot, u8 *status)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
u16 slot_status;
int retval = 0;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
- }
-
- retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(slot->ctrl->cap_base), slot_status);
-
+ retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (retval) {
- err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
return retval;
}
@@ -454,22 +443,16 @@ static int hpc_get_latch_status(struct slot *slot, u8 *status)
static int hpc_get_adapter_status(struct slot *slot, u8 *status)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
u16 slot_status;
u8 card_state;
int retval = 0;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
- }
-
- retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(slot->ctrl->cap_base), slot_status);
-
+ retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (retval) {
- err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
return retval;
}
card_state = (u8)((slot_status & PRSN_STATE) >> 6);
@@ -479,24 +462,18 @@ static int hpc_get_adapter_status(struct slot *slot, u8 *status)
return 0;
}
-static int hpc_query_power_fault(struct slot * slot)
+static int hpc_query_power_fault(struct slot *slot)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
u16 slot_status;
u8 pwr_fault;
int retval = 0;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
- }
-
- retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(slot->ctrl->cap_base), slot_status);
-
+ retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (retval) {
- err("%s : Cannot check for power fault\n", __FUNCTION__);
+ err("%s: Cannot check for power fault\n", __FUNCTION__);
return retval;
}
pwr_fault = (u8)((slot_status & PWR_FAULT_DETECTED) >> 1);
@@ -505,28 +482,63 @@ static int hpc_query_power_fault(struct slot * slot)
return pwr_fault;
}
-static int hpc_set_attention_status(struct slot *slot, u8 value)
+static int hpc_get_emi_status(struct slot *slot, u8 *status)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
+ u16 slot_status;
+ int retval = 0;
+
+ DBG_ENTER_ROUTINE
+
+ retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
+ if (retval) {
+ err("%s : Cannot check EMI status\n", __FUNCTION__);
+ return retval;
+ }
+ *status = (slot_status & EMI_STATE) >> EMI_STATUS_BIT;
+
+ DBG_LEAVE_ROUTINE
+ return retval;
+}
+
+static int hpc_toggle_emi(struct slot *slot)
+{
+ struct controller *ctrl = slot->ctrl;
u16 slot_cmd = 0;
u16 slot_ctrl;
int rc = 0;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
+ rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
+ if (rc) {
+ err("%s : hp_register_read_word SLOT_CTRL failed\n",
+ __FUNCTION__);
+ return rc;
}
- if (slot->hp_slot >= php_ctlr->num_slots) {
- err("%s: Invalid HPC slot number!\n", __FUNCTION__);
- return -1;
- }
- rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
+ slot_cmd = (slot_ctrl | EMI_CTRL);
+ if (!pciehp_poll_mode)
+ slot_cmd = slot_cmd | HP_INTR_ENABLE;
+ pcie_write_cmd(slot, slot_cmd);
+ slot->last_emi_toggle = get_seconds();
+ DBG_LEAVE_ROUTINE
+ return rc;
+}
+
+static int hpc_set_attention_status(struct slot *slot, u8 value)
+{
+ struct controller *ctrl = slot->ctrl;
+ u16 slot_cmd = 0;
+ u16 slot_ctrl;
+ int rc = 0;
+
+ DBG_ENTER_ROUTINE
+
+ rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
if (rc) {
- err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
return rc;
}
@@ -547,7 +559,8 @@ static int hpc_set_attention_status(struct slot *slot, u8 value)
slot_cmd = slot_cmd | HP_INTR_ENABLE;
pcie_write_cmd(slot, slot_cmd);
- dbg("%s: SLOT_CTRL %x write cmd %x\n", __FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd);
+ dbg("%s: SLOTCTRL %x write cmd %x\n",
+ __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
DBG_LEAVE_ROUTINE
return rc;
@@ -556,27 +569,16 @@ static int hpc_set_attention_status(struct slot *slot, u8 value)
static void hpc_set_green_led_on(struct slot *slot)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
u16 slot_cmd;
u16 slot_ctrl;
int rc = 0;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return ;
- }
-
- if (slot->hp_slot >= php_ctlr->num_slots) {
- err("%s: Invalid HPC slot number!\n", __FUNCTION__);
- return ;
- }
-
- rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
-
+ rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
if (rc) {
- err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
return;
}
slot_cmd = (slot_ctrl & ~PWR_LED_CTRL) | 0x0100;
@@ -585,34 +587,24 @@ static void hpc_set_green_led_on(struct slot *slot)
pcie_write_cmd(slot, slot_cmd);
- dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd);
+ dbg("%s: SLOTCTRL %x write cmd %x\n",
+ __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
DBG_LEAVE_ROUTINE
return;
}
static void hpc_set_green_led_off(struct slot *slot)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
u16 slot_cmd;
u16 slot_ctrl;
int rc = 0;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return ;
- }
-
- if (slot->hp_slot >= php_ctlr->num_slots) {
- err("%s: Invalid HPC slot number!\n", __FUNCTION__);
- return ;
- }
-
- rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
-
+ rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
if (rc) {
- err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
return;
}
@@ -621,7 +613,8 @@ static void hpc_set_green_led_off(struct slot *slot)
if (!pciehp_poll_mode)
slot_cmd = slot_cmd | HP_INTR_ENABLE;
pcie_write_cmd(slot, slot_cmd);
- dbg("%s: SLOT_CTRL %x write cmd %x\n", __FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd);
+ dbg("%s: SLOTCTRL %x write cmd %x\n",
+ __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
DBG_LEAVE_ROUTINE
return;
@@ -629,27 +622,16 @@ static void hpc_set_green_led_off(struct slot *slot)
static void hpc_set_green_led_blink(struct slot *slot)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
u16 slot_cmd;
u16 slot_ctrl;
int rc = 0;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return ;
- }
-
- if (slot->hp_slot >= php_ctlr->num_slots) {
- err("%s: Invalid HPC slot number!\n", __FUNCTION__);
- return ;
- }
-
- rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
-
+ rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
if (rc) {
- err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
return;
}
@@ -659,126 +641,54 @@ static void hpc_set_green_led_blink(struct slot *slot)
slot_cmd = slot_cmd | HP_INTR_ENABLE;
pcie_write_cmd(slot, slot_cmd);
- dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd);
+ dbg("%s: SLOTCTRL %x write cmd %x\n",
+ __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
DBG_LEAVE_ROUTINE
return;
}
-int pcie_get_ctlr_slot_config(struct controller *ctrl,
- int *num_ctlr_slots, /* number of slots in this HPC; only 1 in PCIE */
- int *first_device_num, /* PCI dev num of the first slot in this PCIE */
- int *physical_slot_num, /* phy slot num of the first slot in this PCIE */
- u8 *ctrlcap)
-{
- struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle;
- u32 slot_cap;
- int rc = 0;
-
- DBG_ENTER_ROUTINE
-
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
- }
-
- *first_device_num = 0;
- *num_ctlr_slots = 1;
-
- rc = hp_register_read_dword(php_ctlr->pci_dev, SLOT_CAP(ctrl->cap_base), slot_cap);
-
- if (rc) {
- err("%s : hp_register_read_dword SLOT_CAP failed\n", __FUNCTION__);
- return -1;
- }
-
- *physical_slot_num = slot_cap >> 19;
- dbg("%s: PSN %d \n", __FUNCTION__, *physical_slot_num);
-
- *ctrlcap = slot_cap & 0x0000007f;
-
- DBG_LEAVE_ROUTINE
- return 0;
-}
-
static void hpc_release_ctlr(struct controller *ctrl)
{
- struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle;
- struct php_ctlr_state_s *p, *p_prev;
-
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return ;
- }
-
- if (pciehp_poll_mode) {
- del_timer(&php_ctlr->int_poll_timer);
- } else {
- if (php_ctlr->irq) {
- free_irq(php_ctlr->irq, ctrl);
- php_ctlr->irq = 0;
- }
- }
- if (php_ctlr->pci_dev)
- php_ctlr->pci_dev = NULL;
-
- spin_lock(&list_lock);
- p = php_ctlr_list_head;
- p_prev = NULL;
- while (p) {
- if (p == php_ctlr) {
- if (p_prev)
- p_prev->pnext = p->pnext;
- else
- php_ctlr_list_head = p->pnext;
- break;
- } else {
- p_prev = p;
- p = p->pnext;
- }
- }
- spin_unlock(&list_lock);
-
- kfree(php_ctlr);
+ if (pciehp_poll_mode)
+ del_timer(&ctrl->poll_timer);
+ else
+ free_irq(ctrl->pci_dev->irq, ctrl);
DBG_LEAVE_ROUTINE
-
}
static int hpc_power_on_slot(struct slot * slot)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
u16 slot_cmd;
u16 slot_ctrl, slot_status;
-
int retval = 0;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
- }
-
dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot);
- if (slot->hp_slot >= php_ctlr->num_slots) {
- err("%s: Invalid HPC slot number!\n", __FUNCTION__);
- return -1;
- }
/* Clear sticky power-fault bit from previous power failures */
- hp_register_read_word(php_ctlr->pci_dev,
- SLOT_STATUS(slot->ctrl->cap_base), slot_status);
+ retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
+ if (retval) {
+ err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
+ return retval;
+ }
slot_status &= PWR_FAULT_DETECTED;
- if (slot_status)
- hp_register_write_word(php_ctlr->pci_dev,
- SLOT_STATUS(slot->ctrl->cap_base), slot_status);
-
- retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
+ if (slot_status) {
+ retval = pciehp_writew(ctrl, SLOTSTATUS, slot_status);
+ if (retval) {
+ err("%s: Cannot write to SLOTSTATUS register\n",
+ __FUNCTION__);
+ return retval;
+ }
+ }
+ retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
if (retval) {
- err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
return retval;
}
@@ -798,7 +708,8 @@ static int hpc_power_on_slot(struct slot * slot)
err("%s: Write %x command failed!\n", __FUNCTION__, slot_cmd);
return -1;
}
- dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd);
+ dbg("%s: SLOTCTRL %x write cmd %x\n",
+ __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
DBG_LEAVE_ROUTINE
@@ -807,29 +718,18 @@ static int hpc_power_on_slot(struct slot * slot)
static int hpc_power_off_slot(struct slot * slot)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
u16 slot_cmd;
u16 slot_ctrl;
-
int retval = 0;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
- }
-
dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot);
- slot->hp_slot = 0;
- if (slot->hp_slot >= php_ctlr->num_slots) {
- err("%s: Invalid HPC slot number!\n", __FUNCTION__);
- return -1;
- }
- retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
+ retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
if (retval) {
- err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
return retval;
}
@@ -854,47 +754,25 @@ static int hpc_power_off_slot(struct slot * slot)
err("%s: Write command failed!\n", __FUNCTION__);
return -1;
}
- dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd);
+ dbg("%s: SLOTCTRL %x write cmd %x\n",
+ __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
DBG_LEAVE_ROUTINE
return retval;
}
-static irqreturn_t pcie_isr(int IRQ, void *dev_id)
+static irqreturn_t pcie_isr(int irq, void *dev_id)
{
- struct controller *ctrl = NULL;
- struct php_ctlr_state_s *php_ctlr;
- u8 schedule_flag = 0;
+ struct controller *ctrl = (struct controller *)dev_id;
u16 slot_status, intr_detect, intr_loc;
u16 temp_word;
int hp_slot = 0; /* only 1 slot per PCI Express port */
int rc = 0;
- if (!dev_id)
- return IRQ_NONE;
-
- if (!pciehp_poll_mode) {
- ctrl = dev_id;
- php_ctlr = ctrl->hpc_ctlr_handle;
- } else {
- php_ctlr = dev_id;
- ctrl = (struct controller *)php_ctlr->callback_instance_id;
- }
-
- if (!ctrl) {
- dbg("%s: dev_id %p ctlr == NULL\n", __FUNCTION__, (void*) dev_id);
- return IRQ_NONE;
- }
-
- if (!php_ctlr) {
- dbg("%s: php_ctlr == NULL\n", __FUNCTION__);
- return IRQ_NONE;
- }
-
- rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status);
+ rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (rc) {
- err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
return IRQ_NONE;
}
@@ -910,33 +788,38 @@ static irqreturn_t pcie_isr(int IRQ, void *dev_id)
dbg("%s: intr_loc %x\n", __FUNCTION__, intr_loc);
/* Mask Hot-plug Interrupt Enable */
if (!pciehp_poll_mode) {
- rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), temp_word);
+ rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
if (rc) {
- err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOT_CTRL register\n",
+ __FUNCTION__);
return IRQ_NONE;
}
- dbg("%s: hp_register_read_word SLOT_CTRL with value %x\n", __FUNCTION__, temp_word);
+ dbg("%s: pciehp_readw(SLOTCTRL) with value %x\n",
+ __FUNCTION__, temp_word);
temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | 0x00;
-
- rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), temp_word);
+ rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
if (rc) {
- err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot write to SLOTCTRL register\n",
+ __FUNCTION__);
return IRQ_NONE;
}
-
- rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status);
+
+ rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (rc) {
- err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOT_STATUS register\n",
+ __FUNCTION__);
return IRQ_NONE;
}
- dbg("%s: hp_register_read_word SLOT_STATUS with value %x\n", __FUNCTION__, slot_status);
+ dbg("%s: pciehp_readw(SLOTSTATUS) with value %x\n",
+ __FUNCTION__, slot_status);
/* Clear command complete interrupt caused by this write */
temp_word = 0x1f;
- rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word);
+ rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
if (rc) {
- err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot write to SLOTSTATUS register\n",
+ __FUNCTION__);
return IRQ_NONE;
}
}
@@ -945,60 +828,65 @@ static irqreturn_t pcie_isr(int IRQ, void *dev_id)
/*
* Command Complete Interrupt Pending
*/
+ ctrl->cmd_busy = 0;
wake_up_interruptible(&ctrl->queue);
}
- if ((php_ctlr->switch_change_callback) && (intr_loc & MRL_SENS_CHANGED))
- schedule_flag += php_ctlr->switch_change_callback(
- hp_slot, php_ctlr->callback_instance_id);
- if ((php_ctlr->attention_button_callback) && (intr_loc & ATTN_BUTTN_PRESSED))
- schedule_flag += php_ctlr->attention_button_callback(
- hp_slot, php_ctlr->callback_instance_id);
- if ((php_ctlr->presence_change_callback) && (intr_loc & PRSN_DETECT_CHANGED))
- schedule_flag += php_ctlr->presence_change_callback(
- hp_slot , php_ctlr->callback_instance_id);
- if ((php_ctlr->power_fault_callback) && (intr_loc & PWR_FAULT_DETECTED))
- schedule_flag += php_ctlr->power_fault_callback(
- hp_slot, php_ctlr->callback_instance_id);
+ if (intr_loc & MRL_SENS_CHANGED)
+ pciehp_handle_switch_change(hp_slot, ctrl);
+
+ if (intr_loc & ATTN_BUTTN_PRESSED)
+ pciehp_handle_attention_button(hp_slot, ctrl);
+
+ if (intr_loc & PRSN_DETECT_CHANGED)
+ pciehp_handle_presence_change(hp_slot, ctrl);
+
+ if (intr_loc & PWR_FAULT_DETECTED)
+ pciehp_handle_power_fault(hp_slot, ctrl);
/* Clear all events after serving them */
temp_word = 0x1F;
- rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word);
+ rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
if (rc) {
- err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__);
return IRQ_NONE;
}
/* Unmask Hot-plug Interrupt Enable */
if (!pciehp_poll_mode) {
- rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), temp_word);
+ rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
if (rc) {
- err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTCTRL register\n",
+ __FUNCTION__);
return IRQ_NONE;
}
dbg("%s: Unmask Hot-plug Interrupt Enable\n", __FUNCTION__);
temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE;
- rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), temp_word);
+ rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
if (rc) {
- err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot write to SLOTCTRL register\n",
+ __FUNCTION__);
return IRQ_NONE;
}
-
- rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status);
+
+ rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (rc) {
- err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOT_STATUS register\n",
+ __FUNCTION__);
return IRQ_NONE;
}
/* Clear command complete interrupt caused by this write */
temp_word = 0x1F;
- rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word);
+ rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
if (rc) {
- err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot write to SLOTSTATUS failed\n",
+ __FUNCTION__);
return IRQ_NONE;
}
- dbg("%s: hp_register_write_word SLOT_STATUS with value %x\n", __FUNCTION__, temp_word);
+ dbg("%s: pciehp_writew(SLOTSTATUS) with value %x\n",
+ __FUNCTION__, temp_word);
}
return IRQ_HANDLED;
@@ -1006,27 +894,16 @@ static irqreturn_t pcie_isr(int IRQ, void *dev_id)
static int hpc_get_max_lnk_speed (struct slot *slot, enum pci_bus_speed *value)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
enum pcie_link_speed lnk_speed;
u32 lnk_cap;
int retval = 0;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
- }
-
- if (slot->hp_slot >= php_ctlr->num_slots) {
- err("%s: Invalid HPC slot number!\n", __FUNCTION__);
- return -1;
- }
-
- retval = hp_register_read_dword(php_ctlr->pci_dev, LNK_CAP(slot->ctrl->cap_base), lnk_cap);
-
+ retval = pciehp_readl(ctrl, LNKCAP, &lnk_cap);
if (retval) {
- err("%s : hp_register_read_dword LNK_CAP failed\n", __FUNCTION__);
+ err("%s: Cannot read LNKCAP register\n", __FUNCTION__);
return retval;
}
@@ -1047,27 +924,16 @@ static int hpc_get_max_lnk_speed (struct slot *slot, enum pci_bus_speed *value)
static int hpc_get_max_lnk_width (struct slot *slot, enum pcie_link_width *value)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
enum pcie_link_width lnk_wdth;
u32 lnk_cap;
int retval = 0;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
- }
-
- if (slot->hp_slot >= php_ctlr->num_slots) {
- err("%s: Invalid HPC slot number!\n", __FUNCTION__);
- return -1;
- }
-
- retval = hp_register_read_dword(php_ctlr->pci_dev, LNK_CAP(slot->ctrl->cap_base), lnk_cap);
-
+ retval = pciehp_readl(ctrl, LNKCAP, &lnk_cap);
if (retval) {
- err("%s : hp_register_read_dword LNK_CAP failed\n", __FUNCTION__);
+ err("%s: Cannot read LNKCAP register\n", __FUNCTION__);
return retval;
}
@@ -1109,27 +975,16 @@ static int hpc_get_max_lnk_width (struct slot *slot, enum pcie_link_width *value
static int hpc_get_cur_lnk_speed (struct slot *slot, enum pci_bus_speed *value)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
enum pcie_link_speed lnk_speed = PCI_SPEED_UNKNOWN;
int retval = 0;
u16 lnk_status;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
- }
-
- if (slot->hp_slot >= php_ctlr->num_slots) {
- err("%s: Invalid HPC slot number!\n", __FUNCTION__);
- return -1;
- }
-
- retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS(slot->ctrl->cap_base), lnk_status);
-
+ retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status);
if (retval) {
- err("%s : hp_register_read_word LNK_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot read LNKSTATUS register\n", __FUNCTION__);
return retval;
}
@@ -1150,27 +1005,16 @@ static int hpc_get_cur_lnk_speed (struct slot *slot, enum pci_bus_speed *value)
static int hpc_get_cur_lnk_width (struct slot *slot, enum pcie_link_width *value)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
enum pcie_link_width lnk_wdth = PCIE_LNK_WIDTH_UNKNOWN;
int retval = 0;
u16 lnk_status;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
- }
-
- if (slot->hp_slot >= php_ctlr->num_slots) {
- err("%s: Invalid HPC slot number!\n", __FUNCTION__);
- return -1;
- }
-
- retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS(slot->ctrl->cap_base), lnk_status);
-
+ retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status);
if (retval) {
- err("%s : hp_register_read_word LNK_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot read LNKSTATUS register\n", __FUNCTION__);
return retval;
}
@@ -1218,6 +1062,8 @@ static struct hpc_ops pciehp_hpc_ops = {
.get_attention_status = hpc_get_attention_status,
.get_latch_status = hpc_get_latch_status,
.get_adapter_status = hpc_get_adapter_status,
+ .get_emi_status = hpc_get_emi_status,
+ .toggle_emi = hpc_toggle_emi,
.get_max_bus_speed = hpc_get_max_lnk_speed,
.get_cur_bus_speed = hpc_get_cur_lnk_speed,
@@ -1305,38 +1151,24 @@ int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev)
int pcie_init(struct controller * ctrl, struct pcie_device *dev)
{
- struct php_ctlr_state_s *php_ctlr, *p;
- void *instance_id = ctrl;
int rc;
static int first = 1;
u16 temp_word;
u16 cap_reg;
u16 intr_enable = 0;
u32 slot_cap;
- int cap_base, saved_cap_base;
+ int cap_base;
u16 slot_status, slot_ctrl;
struct pci_dev *pdev;
DBG_ENTER_ROUTINE
- spin_lock_init(&list_lock);
- php_ctlr = kmalloc(sizeof(struct php_ctlr_state_s), GFP_KERNEL);
-
- if (!php_ctlr) { /* allocate controller state data */
- err("%s: HPC controller memory allocation error!\n", __FUNCTION__);
- goto abort;
- }
-
- memset(php_ctlr, 0, sizeof(struct php_ctlr_state_s));
-
pdev = dev->port;
- php_ctlr->pci_dev = pdev; /* save pci_dev in context */
+ ctrl->pci_dev = pdev; /* save pci_dev in context */
dbg("%s: hotplug controller vendor id 0x%x device id 0x%x\n",
__FUNCTION__, pdev->vendor, pdev->device);
- saved_cap_base = pcie_cap_base;
-
if ((cap_base = pci_find_capability(pdev, PCI_CAP_ID_EXP)) == 0) {
dbg("%s: Can't find PCI_CAP_ID_EXP (0x10)\n", __FUNCTION__);
goto abort_free_ctlr;
@@ -1344,14 +1176,15 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
ctrl->cap_base = cap_base;
- dbg("%s: pcie_cap_base %x\n", __FUNCTION__, pcie_cap_base);
+ dbg("%s: pcie_cap_base %x\n", __FUNCTION__, cap_base);
- rc = hp_register_read_word(pdev, CAP_REG(ctrl->cap_base), cap_reg);
+ rc = pciehp_readw(ctrl, CAPREG, &cap_reg);
if (rc) {
- err("%s : hp_register_read_word CAP_REG failed\n", __FUNCTION__);
+ err("%s: Cannot read CAPREG register\n", __FUNCTION__);
goto abort_free_ctlr;
}
- dbg("%s: CAP_REG offset %x cap_reg %x\n", __FUNCTION__, CAP_REG(ctrl->cap_base), cap_reg);
+ dbg("%s: CAPREG offset %x cap_reg %x\n",
+ __FUNCTION__, ctrl->cap_base + CAPREG, cap_reg);
if (((cap_reg & SLOT_IMPL) == 0) || (((cap_reg & DEV_PORT_TYPE) != 0x0040)
&& ((cap_reg & DEV_PORT_TYPE) != 0x0060))) {
@@ -1359,31 +1192,34 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
goto abort_free_ctlr;
}
- rc = hp_register_read_dword(php_ctlr->pci_dev, SLOT_CAP(ctrl->cap_base), slot_cap);
+ rc = pciehp_readl(ctrl, SLOTCAP, &slot_cap);
if (rc) {
- err("%s : hp_register_read_word CAP_REG failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTCAP register\n", __FUNCTION__);
goto abort_free_ctlr;
}
- dbg("%s: SLOT_CAP offset %x slot_cap %x\n", __FUNCTION__, SLOT_CAP(ctrl->cap_base), slot_cap);
+ dbg("%s: SLOTCAP offset %x slot_cap %x\n",
+ __FUNCTION__, ctrl->cap_base + SLOTCAP, slot_cap);
if (!(slot_cap & HP_CAP)) {
dbg("%s : This slot is not hot-plug capable\n", __FUNCTION__);
goto abort_free_ctlr;
}
/* For debugging purpose */
- rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status);
+ rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (rc) {
- err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
goto abort_free_ctlr;
}
- dbg("%s: SLOT_STATUS offset %x slot_status %x\n", __FUNCTION__, SLOT_STATUS(ctrl->cap_base), slot_status);
+ dbg("%s: SLOTSTATUS offset %x slot_status %x\n",
+ __FUNCTION__, ctrl->cap_base + SLOTSTATUS, slot_status);
- rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), slot_ctrl);
+ rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
if (rc) {
- err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
goto abort_free_ctlr;
}
- dbg("%s: SLOT_CTRL offset %x slot_ctrl %x\n", __FUNCTION__, SLOT_CTRL(ctrl->cap_base), slot_ctrl);
+ dbg("%s: SLOTCTRL offset %x slot_ctrl %x\n",
+ __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_ctrl);
if (first) {
spin_lock_init(&hpc_event_lock);
@@ -1405,69 +1241,64 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
/* setup wait queue */
init_waitqueue_head(&ctrl->queue);
- /* find the IRQ */
- php_ctlr->irq = dev->irq;
-
- /* Save interrupt callback info */
- php_ctlr->attention_button_callback = pciehp_handle_attention_button;
- php_ctlr->switch_change_callback = pciehp_handle_switch_change;
- php_ctlr->presence_change_callback = pciehp_handle_presence_change;
- php_ctlr->power_fault_callback = pciehp_handle_power_fault;
- php_ctlr->callback_instance_id = instance_id;
-
/* return PCI Controller Info */
- php_ctlr->slot_device_offset = 0;
- php_ctlr->num_slots = 1;
+ ctrl->slot_device_offset = 0;
+ ctrl->num_slots = 1;
+ ctrl->first_slot = slot_cap >> 19;
+ ctrl->ctrlcap = slot_cap & 0x0000007f;
/* Mask Hot-plug Interrupt Enable */
- rc = hp_register_read_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word);
+ rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
if (rc) {
- err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
goto abort_free_ctlr;
}
- dbg("%s: SLOT_CTRL %x value read %x\n", __FUNCTION__, SLOT_CTRL(ctrl->cap_base), temp_word);
+ dbg("%s: SLOTCTRL %x value read %x\n",
+ __FUNCTION__, ctrl->cap_base + SLOTCTRL, temp_word);
temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | 0x00;
- rc = hp_register_write_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word);
+ rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
if (rc) {
- err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__);
goto abort_free_ctlr;
}
- rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status);
+ rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (rc) {
- err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
goto abort_free_ctlr;
}
temp_word = 0x1F; /* Clear all events */
- rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word);
+ rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
if (rc) {
- err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__);
goto abort_free_ctlr;
}
- if (pciehp_poll_mode) {/* Install interrupt polling code */
- /* Install and start the interrupt polling timer */
- init_timer(&php_ctlr->int_poll_timer);
- start_int_poll_timer( php_ctlr, 10 ); /* start with 10 second delay */
+ if (pciehp_poll_mode) {
+ /* Install interrupt polling timer. Start with 10 sec delay */
+ init_timer(&ctrl->poll_timer);
+ start_int_poll_timer(ctrl, 10);
} else {
/* Installs the interrupt handler */
- rc = request_irq(php_ctlr->irq, pcie_isr, IRQF_SHARED, MY_NAME, (void *) ctrl);
- dbg("%s: request_irq %d for hpc%d (returns %d)\n", __FUNCTION__, php_ctlr->irq, ctlr_seq_num, rc);
+ rc = request_irq(ctrl->pci_dev->irq, pcie_isr, IRQF_SHARED,
+ MY_NAME, (void *)ctrl);
+ dbg("%s: request_irq %d for hpc%d (returns %d)\n",
+ __FUNCTION__, ctrl->pci_dev->irq, ctlr_seq_num, rc);
if (rc) {
- err("Can't get irq %d for the hotplug controller\n", php_ctlr->irq);
+ err("Can't get irq %d for the hotplug controller\n",
+ ctrl->pci_dev->irq);
goto abort_free_ctlr;
}
}
-
dbg("pciehp ctrl b:d:f:irq=0x%x:%x:%x:%x\n", pdev->bus->number,
PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), dev->irq);
- rc = hp_register_read_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word);
+ rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
if (rc) {
- err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
goto abort_free_irq;
}
@@ -1491,21 +1322,21 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
}
/* Unmask Hot-plug Interrupt Enable for the interrupt notification mechanism case */
- rc = hp_register_write_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word);
+ rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
if (rc) {
- err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__);
goto abort_free_irq;
}
- rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status);
+ rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (rc) {
- err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
goto abort_disable_intr;
}
temp_word = 0x1F; /* Clear all events */
- rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word);
+ rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
if (rc) {
- err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__);
goto abort_disable_intr;
}
@@ -1518,24 +1349,7 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
goto abort_disable_intr;
}
- /* Add this HPC instance into the HPC list */
- spin_lock(&list_lock);
- if (php_ctlr_list_head == 0) {
- php_ctlr_list_head = php_ctlr;
- p = php_ctlr_list_head;
- p->pnext = NULL;
- } else {
- p = php_ctlr_list_head;
-
- while (p->pnext)
- p = p->pnext;
-
- p->pnext = php_ctlr;
- }
- spin_unlock(&list_lock);
-
ctlr_seq_num++;
- ctrl->hpc_ctlr_handle = php_ctlr;
ctrl->hpc_ops = &pciehp_hpc_ops;
DBG_LEAVE_ROUTINE
@@ -1543,24 +1357,21 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
/* We end up here for the many possible ways to fail this API. */
abort_disable_intr:
- rc = hp_register_read_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word);
+ rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
if (!rc) {
temp_word &= ~(intr_enable | HP_INTR_ENABLE);
- rc = hp_register_write_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word);
+ rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
}
if (rc)
err("%s : disabling interrupts failed\n", __FUNCTION__);
abort_free_irq:
if (pciehp_poll_mode)
- del_timer_sync(&php_ctlr->int_poll_timer);
+ del_timer_sync(&ctrl->poll_timer);
else
- free_irq(php_ctlr->irq, ctrl);
+ free_irq(ctrl->pci_dev->irq, ctrl);
abort_free_ctlr:
- pcie_cap_base = saved_cap_base;
- kfree(php_ctlr);
-abort:
DBG_LEAVE_ROUTINE
return -1;
}
diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c
index 5d188c55838..78cf0711d1f 100644
--- a/drivers/pci/hotplug/sgi_hotplug.c
+++ b/drivers/pci/hotplug/sgi_hotplug.c
@@ -28,6 +28,8 @@
#include <asm/sn/sn_feature_sets.h>
#include <asm/sn/sn_sal.h>
#include <asm/sn/types.h>
+#include <linux/acpi.h>
+#include <asm/sn/acpi.h>
#include "../pci.h"
@@ -35,14 +37,17 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR("SGI (prarit@sgi.com, dickie@sgi.com, habeck@sgi.com)");
MODULE_DESCRIPTION("SGI Altix Hot Plug PCI Controller Driver");
-#define PCIIO_ASIC_TYPE_TIOCA 4
+
+/* SAL call error codes. Keep in sync with prom header io/include/pcibr.h */
#define PCI_SLOT_ALREADY_UP 2 /* slot already up */
#define PCI_SLOT_ALREADY_DOWN 3 /* slot already down */
#define PCI_L1_ERR 7 /* L1 console command error */
#define PCI_EMPTY_33MHZ 15 /* empty 33 MHz bus */
+
+
+#define PCIIO_ASIC_TYPE_TIOCA 4
#define PCI_L1_QSIZE 128 /* our L1 message buffer size */
#define SN_MAX_HP_SLOTS 32 /* max hotplug slots */
-#define SGI_HOTPLUG_PROM_REV 0x0430 /* Min. required PROM version */
#define SN_SLOT_NAME_SIZE 33 /* size of name string */
/* internal list head */
@@ -227,7 +232,7 @@ static void sn_bus_free_data(struct pci_dev *dev)
}
static int sn_slot_enable(struct hotplug_slot *bss_hotplug_slot,
- int device_num)
+ int device_num, char **ssdt)
{
struct slot *slot = bss_hotplug_slot->private;
struct pcibus_info *pcibus_info;
@@ -240,7 +245,8 @@ static int sn_slot_enable(struct hotplug_slot *bss_hotplug_slot,
* Power-on and initialize the slot in the SN
* PCI infrastructure.
*/
- rc = sal_pcibr_slot_enable(pcibus_info, device_num, &resp);
+ rc = sal_pcibr_slot_enable(pcibus_info, device_num, &resp, ssdt);
+
if (rc == PCI_SLOT_ALREADY_UP) {
dev_dbg(slot->pci_bus->self, "is already active\n");
@@ -335,6 +341,7 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot)
int func, num_funcs;
int new_ppb = 0;
int rc;
+ char *ssdt = NULL;
void pcibios_fixup_device_resources(struct pci_dev *);
/* Serialize the Linux PCI infrastructure */
@@ -342,14 +349,29 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot)
/*
* Power-on and initialize the slot in the SN
- * PCI infrastructure.
+ * PCI infrastructure. Also, retrieve the ACPI SSDT
+ * table for the slot (if ACPI capable PROM).
*/
- rc = sn_slot_enable(bss_hotplug_slot, slot->device_num);
+ rc = sn_slot_enable(bss_hotplug_slot, slot->device_num, &ssdt);
if (rc) {
mutex_unlock(&sn_hotplug_mutex);
return rc;
}
+ if (ssdt)
+ ssdt = __va(ssdt);
+ /* Add the new SSDT for the slot to the ACPI namespace */
+ if (SN_ACPI_BASE_SUPPORT() && ssdt) {
+ acpi_status ret;
+
+ ret = acpi_load_table((struct acpi_table_header *)ssdt);
+ if (ACPI_FAILURE(ret)) {
+ printk(KERN_ERR "%s: acpi_load_table failed (0x%x)\n",
+ __FUNCTION__, ret);
+ /* try to continue on */
+ }
+ }
+
num_funcs = pci_scan_slot(slot->pci_bus,
PCI_DEVFN(slot->device_num + 1, 0));
if (!num_funcs) {
@@ -374,7 +396,10 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot)
* pdi_host_pcidev_info).
*/
pcibios_fixup_device_resources(dev);
- sn_pci_fixup_slot(dev);
+ if (SN_ACPI_BASE_SUPPORT())
+ sn_acpi_slot_fixup(dev);
+ else
+ sn_io_slot_fixup(dev);
if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
unsigned char sec_bus;
pci_read_config_byte(dev, PCI_SECONDARY_BUS,
@@ -388,6 +413,63 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot)
}
}
+ /*
+ * Add the slot's devices to the ACPI infrastructure */
+ if (SN_ACPI_BASE_SUPPORT() && ssdt) {
+ unsigned long adr;
+ struct acpi_device *pdevice;
+ struct acpi_device *device;
+ acpi_handle phandle;
+ acpi_handle chandle = NULL;
+ acpi_handle rethandle;
+ acpi_status ret;
+
+ phandle = PCI_CONTROLLER(slot->pci_bus)->acpi_handle;
+
+ if (acpi_bus_get_device(phandle, &pdevice)) {
+ dev_dbg(slot->pci_bus->self,
+ "no parent device, assuming NULL\n");
+ pdevice = NULL;
+ }
+
+ /*
+ * Walk the rootbus node's immediate children looking for
+ * the slot's device node(s). There can be more than
+ * one for multifunction devices.
+ */
+ for (;;) {
+ rethandle = NULL;
+ ret = acpi_get_next_object(ACPI_TYPE_DEVICE,
+ phandle, chandle,
+ &rethandle);
+
+ if (ret == AE_NOT_FOUND || rethandle == NULL)
+ break;
+
+ chandle = rethandle;
+
+ ret = acpi_evaluate_integer(chandle, METHOD_NAME__ADR,
+ NULL, &adr);
+
+ if (ACPI_SUCCESS(ret) &&
+ (adr>>16) == (slot->device_num + 1)) {
+
+ ret = acpi_bus_add(&device, pdevice, chandle,
+ ACPI_BUS_TYPE_DEVICE);
+ if (ACPI_FAILURE(ret)) {
+ printk(KERN_ERR "%s: acpi_bus_add "
+ "failed (0x%x) for slot %d "
+ "func %d\n", __FUNCTION__,
+ ret, (int)(adr>>16),
+ (int)(adr&0xffff));
+ /* try to continue on */
+ } else {
+ acpi_bus_start(device);
+ }
+ }
+ }
+ }
+
/* Call the driver for the new device */
pci_bus_add_devices(slot->pci_bus);
/* Call the drivers for the new devices subordinate to PPB */
@@ -412,6 +494,7 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot)
struct pci_dev *dev;
int func;
int rc;
+ acpi_owner_id ssdt_id = 0;
/* Acquire update access to the bus */
mutex_lock(&sn_hotplug_mutex);
@@ -422,6 +505,52 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot)
if (rc)
goto leaving;
+ /* free the ACPI resources for the slot */
+ if (SN_ACPI_BASE_SUPPORT() &&
+ PCI_CONTROLLER(slot->pci_bus)->acpi_handle) {
+ unsigned long adr;
+ struct acpi_device *device;
+ acpi_handle phandle;
+ acpi_handle chandle = NULL;
+ acpi_handle rethandle;
+ acpi_status ret;
+
+ /* Get the rootbus node pointer */
+ phandle = PCI_CONTROLLER(slot->pci_bus)->acpi_handle;
+
+ /*
+ * Walk the rootbus node's immediate children looking for
+ * the slot's device node(s). There can be more than
+ * one for multifunction devices.
+ */
+ for (;;) {
+ rethandle = NULL;
+ ret = acpi_get_next_object(ACPI_TYPE_DEVICE,
+ phandle, chandle,
+ &rethandle);
+
+ if (ret == AE_NOT_FOUND || rethandle == NULL)
+ break;
+
+ chandle = rethandle;
+
+ ret = acpi_evaluate_integer(chandle,
+ METHOD_NAME__ADR,
+ NULL, &adr);
+ if (ACPI_SUCCESS(ret) &&
+ (adr>>16) == (slot->device_num + 1)) {
+ /* retain the owner id */
+ acpi_get_id(chandle, &ssdt_id);
+
+ ret = acpi_bus_get_device(chandle,
+ &device);
+ if (ACPI_SUCCESS(ret))
+ acpi_bus_trim(device, 1);
+ }
+ }
+
+ }
+
/* Free the SN resources assigned to the Linux device.*/
for (func = 0; func < 8; func++) {
dev = pci_get_slot(slot->pci_bus,
@@ -434,6 +563,18 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot)
}
}
+ /* Remove the SSDT for the slot from the ACPI namespace */
+ if (SN_ACPI_BASE_SUPPORT() && ssdt_id) {
+ acpi_status ret;
+ ret = acpi_unload_table_id(ssdt_id);
+ if (ACPI_FAILURE(ret)) {
+ printk(KERN_ERR "%s: acpi_unload_table_id "
+ "failed (0x%x) for id %d\n",
+ __FUNCTION__, ret, ssdt_id);
+ /* try to continue on */
+ }
+ }
+
/* free the collected sysdata pointers */
sn_bus_free_sysdata();
diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h
index 3ca6a4f574b..01d31a1f697 100644
--- a/drivers/pci/hotplug/shpchp.h
+++ b/drivers/pci/hotplug/shpchp.h
@@ -106,7 +106,7 @@ struct controller {
};
/* Define AMD SHPC ID */
-#define PCI_DEVICE_ID_AMD_GOLAM_7450 0x7450
+#define PCI_DEVICE_ID_AMD_GOLAM_7450 0x7450
#define PCI_DEVICE_ID_AMD_POGO_7458 0x7458
/* AMD PCIX bridge registers */
@@ -221,7 +221,7 @@ enum ctrl_offsets {
};
static inline struct slot *get_slot(struct hotplug_slot *hotplug_slot)
-{
+{
return hotplug_slot->private;
}
diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c
index 590cd3cbe01..5f4bc08a633 100644
--- a/drivers/pci/hotplug/shpchp_core.c
+++ b/drivers/pci/hotplug/shpchp_core.c
@@ -401,10 +401,6 @@ static int __init shpcd_init(void)
{
int retval = 0;
-#ifdef CONFIG_HOTPLUG_PCI_SHPC_POLL_EVENT_MODE
- shpchp_poll_mode = 1;
-#endif
-
retval = pci_register_driver(&shpc_driver);
dbg("%s: pci_register_driver = %d\n", __FUNCTION__, retval);
info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
diff --git a/drivers/pci/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c
index 6bb84734cd6..b746bd265bc 100644
--- a/drivers/pci/hotplug/shpchp_ctrl.c
+++ b/drivers/pci/hotplug/shpchp_ctrl.c
@@ -64,7 +64,7 @@ u8 shpchp_handle_attention_button(u8 hp_slot, struct controller *ctrl)
/* Attention Button Change */
dbg("shpchp: Attention button interrupt received.\n");
-
+
p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save));
@@ -128,7 +128,7 @@ u8 shpchp_handle_presence_change(u8 hp_slot, struct controller *ctrl)
p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
- /*
+ /*
* Save the presence state
*/
p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save));
@@ -184,12 +184,12 @@ u8 shpchp_handle_power_fault(u8 hp_slot, struct controller *ctrl)
return 1;
}
-/* The following routines constitute the bulk of the
+/* The following routines constitute the bulk of the
hotplug controller logic
*/
static int change_bus_speed(struct controller *ctrl, struct slot *p_slot,
enum pci_bus_speed speed)
-{
+{
int rc = 0;
dbg("%s: change to speed %d\n", __FUNCTION__, speed);
@@ -204,7 +204,7 @@ static int change_bus_speed(struct controller *ctrl, struct slot *p_slot,
static int fix_bus_speed(struct controller *ctrl, struct slot *pslot,
u8 flag, enum pci_bus_speed asp, enum pci_bus_speed bsp,
enum pci_bus_speed msp)
-{
+{
int rc = 0;
/*
@@ -257,23 +257,23 @@ static int board_added(struct slot *p_slot)
err("%s: Failed to power on slot\n", __FUNCTION__);
return -1;
}
-
+
if ((ctrl->pci_dev->vendor == 0x8086) && (ctrl->pci_dev->device == 0x0332)) {
if (slots_not_empty)
return WRONG_BUS_FREQUENCY;
-
+
if ((rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, PCI_SPEED_33MHz))) {
err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__);
return WRONG_BUS_FREQUENCY;
}
-
+
/* turn on board, blink green LED, turn off Amber LED */
if ((rc = p_slot->hpc_ops->slot_enable(p_slot))) {
err("%s: Issue of Slot Enable command failed\n", __FUNCTION__);
return rc;
}
}
-
+
rc = p_slot->hpc_ops->get_adapter_speed(p_slot, &asp);
if (rc) {
err("%s: Can't get adapter speed or bus mode mismatch\n",
@@ -378,7 +378,7 @@ static int remove_board(struct slot *p_slot)
err("%s: Issue of Slot Disable command failed\n", __FUNCTION__);
return rc;
}
-
+
rc = p_slot->hpc_ops->set_attention_status(p_slot, 0);
if (rc) {
err("%s: Issue of Set Attention command failed\n", __FUNCTION__);
diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c
index b7bede4b7c2..5183a45d45b 100644
--- a/drivers/pci/hotplug/shpchp_hpc.c
+++ b/drivers/pci/hotplug/shpchp_hpc.c
@@ -35,38 +35,6 @@
#include "shpchp.h"
-#ifdef DEBUG
-#define DBG_K_TRACE_ENTRY ((unsigned int)0x00000001) /* On function entry */
-#define DBG_K_TRACE_EXIT ((unsigned int)0x00000002) /* On function exit */
-#define DBG_K_INFO ((unsigned int)0x00000004) /* Info messages */
-#define DBG_K_ERROR ((unsigned int)0x00000008) /* Error messages */
-#define DBG_K_TRACE (DBG_K_TRACE_ENTRY|DBG_K_TRACE_EXIT)
-#define DBG_K_STANDARD (DBG_K_INFO|DBG_K_ERROR|DBG_K_TRACE)
-/* Redefine this flagword to set debug level */
-#define DEBUG_LEVEL DBG_K_STANDARD
-
-#define DEFINE_DBG_BUFFER char __dbg_str_buf[256];
-
-#define DBG_PRINT( dbg_flags, args... ) \
- do { \
- if ( DEBUG_LEVEL & ( dbg_flags ) ) \
- { \
- int len; \
- len = sprintf( __dbg_str_buf, "%s:%d: %s: ", \
- __FILE__, __LINE__, __FUNCTION__ ); \
- sprintf( __dbg_str_buf + len, args ); \
- printk( KERN_NOTICE "%s\n", __dbg_str_buf ); \
- } \
- } while (0)
-
-#define DBG_ENTER_ROUTINE DBG_PRINT (DBG_K_TRACE_ENTRY, "%s", "[Entry]");
-#define DBG_LEAVE_ROUTINE DBG_PRINT (DBG_K_TRACE_EXIT, "%s", "[Exit]");
-#else
-#define DEFINE_DBG_BUFFER
-#define DBG_ENTER_ROUTINE
-#define DBG_LEAVE_ROUTINE
-#endif /* DEBUG */
-
/* Slot Available Register I field definition */
#define SLOT_33MHZ 0x0000001f
#define SLOT_66MHZ_PCIX 0x00001f00
@@ -211,7 +179,6 @@
#define SLOT_EVENT_LATCH 0x2
#define SLOT_SERR_INT_MASK 0x3
-DEFINE_DBG_BUFFER /* Debug string buffer for entire HPC defined here */
static atomic_t shpchp_num_controllers = ATOMIC_INIT(0);
static irqreturn_t shpc_isr(int irq, void *dev_id);
@@ -268,8 +235,6 @@ static void int_poll_timeout(unsigned long data)
{
struct controller *ctrl = (struct controller *)data;
- DBG_ENTER_ROUTINE
-
/* Poll for interrupt events. regs == NULL => polling */
shpc_isr(0, ctrl);
@@ -278,8 +243,6 @@ static void int_poll_timeout(unsigned long data)
shpchp_poll_time = 2; /* default polling interval is 2 sec */
start_int_poll_timer(ctrl, shpchp_poll_time);
-
- DBG_LEAVE_ROUTINE
}
/*
@@ -353,8 +316,6 @@ static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd)
int retval = 0;
u16 temp_word;
- DBG_ENTER_ROUTINE
-
mutex_lock(&slot->ctrl->cmd_lock);
if (!shpc_poll_ctrl_busy(ctrl)) {
@@ -368,9 +329,9 @@ static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd)
++t_slot;
temp_word = (t_slot << 8) | (cmd & 0xFF);
dbg("%s: t_slot %x cmd %x\n", __FUNCTION__, t_slot, cmd);
-
+
/* To make sure the Controller Busy bit is 0 before we send out the
- * command.
+ * command.
*/
shpc_writew(ctrl, CMD, temp_word);
@@ -389,20 +350,14 @@ static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd)
}
out:
mutex_unlock(&slot->ctrl->cmd_lock);
-
- DBG_LEAVE_ROUTINE
return retval;
}
static int hpc_check_cmd_status(struct controller *ctrl)
{
- u16 cmd_status;
int retval = 0;
+ u16 cmd_status = shpc_readw(ctrl, CMD_STATUS) & 0x000F;
- DBG_ENTER_ROUTINE
-
- cmd_status = shpc_readw(ctrl, CMD_STATUS) & 0x000F;
-
switch (cmd_status >> 1) {
case 0:
retval = 0;
@@ -423,7 +378,6 @@ static int hpc_check_cmd_status(struct controller *ctrl)
retval = cmd_status;
}
- DBG_LEAVE_ROUTINE
return retval;
}
@@ -431,13 +385,8 @@ static int hpc_check_cmd_status(struct controller *ctrl)
static int hpc_get_attention_status(struct slot *slot, u8 *status)
{
struct controller *ctrl = slot->ctrl;
- u32 slot_reg;
- u8 state;
-
- DBG_ENTER_ROUTINE
-
- slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
- state = (slot_reg & ATN_LED_STATE_MASK) >> ATN_LED_STATE_SHIFT;
+ u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
+ u8 state = (slot_reg & ATN_LED_STATE_MASK) >> ATN_LED_STATE_SHIFT;
switch (state) {
case ATN_LED_STATE_ON:
@@ -454,20 +403,14 @@ static int hpc_get_attention_status(struct slot *slot, u8 *status)
break;
}
- DBG_LEAVE_ROUTINE
return 0;
}
static int hpc_get_power_status(struct slot * slot, u8 *status)
{
struct controller *ctrl = slot->ctrl;
- u32 slot_reg;
- u8 state;
-
- DBG_ENTER_ROUTINE
-
- slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
- state = (slot_reg & SLOT_STATE_MASK) >> SLOT_STATE_SHIFT;
+ u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
+ u8 state = (slot_reg & SLOT_STATE_MASK) >> SLOT_STATE_SHIFT;
switch (state) {
case SLOT_STATE_PWRONLY:
@@ -484,7 +427,6 @@ static int hpc_get_power_status(struct slot * slot, u8 *status)
break;
}
- DBG_LEAVE_ROUTINE
return 0;
}
@@ -492,30 +434,21 @@ static int hpc_get_power_status(struct slot * slot, u8 *status)
static int hpc_get_latch_status(struct slot *slot, u8 *status)
{
struct controller *ctrl = slot->ctrl;
- u32 slot_reg;
-
- DBG_ENTER_ROUTINE
+ u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
- slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
*status = !!(slot_reg & MRL_SENSOR); /* 0 -> close; 1 -> open */
- DBG_LEAVE_ROUTINE
return 0;
}
static int hpc_get_adapter_status(struct slot *slot, u8 *status)
{
struct controller *ctrl = slot->ctrl;
- u32 slot_reg;
- u8 state;
-
- DBG_ENTER_ROUTINE
+ u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
+ u8 state = (slot_reg & PRSNT_MASK) >> PRSNT_SHIFT;
- slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
- state = (slot_reg & PRSNT_MASK) >> PRSNT_SHIFT;
*status = (state != 0x3) ? 1 : 0;
- DBG_LEAVE_ROUTINE
return 0;
}
@@ -523,11 +456,8 @@ static int hpc_get_prog_int(struct slot *slot, u8 *prog_int)
{
struct controller *ctrl = slot->ctrl;
- DBG_ENTER_ROUTINE
-
*prog_int = shpc_readb(ctrl, PROG_INTERFACE);
- DBG_LEAVE_ROUTINE
return 0;
}
@@ -539,8 +469,6 @@ static int hpc_get_adapter_speed(struct slot *slot, enum pci_bus_speed *value)
u8 m66_cap = !!(slot_reg & MHZ66_CAP);
u8 pi, pcix_cap;
- DBG_ENTER_ROUTINE
-
if ((retval = hpc_get_prog_int(slot, &pi)))
return retval;
@@ -582,21 +510,15 @@ static int hpc_get_adapter_speed(struct slot *slot, enum pci_bus_speed *value)
}
dbg("Adapter speed = %d\n", *value);
- DBG_LEAVE_ROUTINE
return retval;
}
static int hpc_get_mode1_ECC_cap(struct slot *slot, u8 *mode)
{
- struct controller *ctrl = slot->ctrl;
- u16 sec_bus_status;
- u8 pi;
int retval = 0;
-
- DBG_ENTER_ROUTINE
-
- pi = shpc_readb(ctrl, PROG_INTERFACE);
- sec_bus_status = shpc_readw(ctrl, SEC_BUS_CONFIG);
+ struct controller *ctrl = slot->ctrl;
+ u16 sec_bus_status = shpc_readw(ctrl, SEC_BUS_CONFIG);
+ u8 pi = shpc_readb(ctrl, PROG_INTERFACE);
if (pi == 2) {
*mode = (sec_bus_status & 0x0100) >> 8;
@@ -605,21 +527,14 @@ static int hpc_get_mode1_ECC_cap(struct slot *slot, u8 *mode)
}
dbg("Mode 1 ECC cap = %d\n", *mode);
-
- DBG_LEAVE_ROUTINE
return retval;
}
static int hpc_query_power_fault(struct slot * slot)
{
struct controller *ctrl = slot->ctrl;
- u32 slot_reg;
-
- DBG_ENTER_ROUTINE
-
- slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
+ u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
- DBG_LEAVE_ROUTINE
/* Note: Logic 0 => fault */
return !(slot_reg & POWER_FAULT);
}
@@ -629,7 +544,7 @@ static int hpc_set_attention_status(struct slot *slot, u8 value)
u8 slot_cmd = 0;
switch (value) {
- case 0 :
+ case 0 :
slot_cmd = SET_ATTN_OFF; /* OFF */
break;
case 1:
@@ -666,8 +581,6 @@ static void hpc_release_ctlr(struct controller *ctrl)
int i;
u32 slot_reg, serr_int;
- DBG_ENTER_ROUTINE
-
/*
* Mask event interrupts and SERRs of all slots
*/
@@ -708,61 +621,43 @@ static void hpc_release_ctlr(struct controller *ctrl)
*/
if (atomic_dec_and_test(&shpchp_num_controllers))
destroy_workqueue(shpchp_wq);
-
- DBG_LEAVE_ROUTINE
}
static int hpc_power_on_slot(struct slot * slot)
{
int retval;
- DBG_ENTER_ROUTINE
-
retval = shpc_write_cmd(slot, slot->hp_slot, SET_SLOT_PWR);
- if (retval) {
+ if (retval)
err("%s: Write command failed!\n", __FUNCTION__);
- return retval;
- }
-
- DBG_LEAVE_ROUTINE
- return 0;
+ return retval;
}
static int hpc_slot_enable(struct slot * slot)
{
int retval;
- DBG_ENTER_ROUTINE
-
/* Slot - Enable, Power Indicator - Blink, Attention Indicator - Off */
retval = shpc_write_cmd(slot, slot->hp_slot,
SET_SLOT_ENABLE | SET_PWR_BLINK | SET_ATTN_OFF);
- if (retval) {
+ if (retval)
err("%s: Write command failed!\n", __FUNCTION__);
- return retval;
- }
- DBG_LEAVE_ROUTINE
- return 0;
+ return retval;
}
static int hpc_slot_disable(struct slot * slot)
{
int retval;
- DBG_ENTER_ROUTINE
-
/* Slot - Disable, Power Indicator - Off, Attention Indicator - On */
retval = shpc_write_cmd(slot, slot->hp_slot,
SET_SLOT_DISABLE | SET_PWR_OFF | SET_ATTN_ON);
- if (retval) {
+ if (retval)
err("%s: Write command failed!\n", __FUNCTION__);
- return retval;
- }
- DBG_LEAVE_ROUTINE
- return 0;
+ return retval;
}
static int hpc_set_bus_speed_mode(struct slot * slot, enum pci_bus_speed value)
@@ -771,8 +666,6 @@ static int hpc_set_bus_speed_mode(struct slot * slot, enum pci_bus_speed value)
struct controller *ctrl = slot->ctrl;
u8 pi, cmd;
- DBG_ENTER_ROUTINE
-
pi = shpc_readb(ctrl, PROG_INTERFACE);
if ((pi == 1) && (value > PCI_SPEED_133MHz_PCIX))
return -EINVAL;
@@ -828,7 +721,6 @@ static int hpc_set_bus_speed_mode(struct slot * slot, enum pci_bus_speed value)
if (retval)
err("%s: Write command failed!\n", __FUNCTION__);
- DBG_LEAVE_ROUTINE
return retval;
}
@@ -843,7 +735,7 @@ static irqreturn_t shpc_isr(int irq, void *dev_id)
if (!intr_loc)
return IRQ_NONE;
- dbg("%s: intr_loc = %x\n",__FUNCTION__, intr_loc);
+ dbg("%s: intr_loc = %x\n",__FUNCTION__, intr_loc);
if(!shpchp_poll_mode) {
/*
@@ -856,12 +748,12 @@ static irqreturn_t shpc_isr(int irq, void *dev_id)
shpc_writel(ctrl, SERR_INTR_ENABLE, serr_int);
intr_loc2 = shpc_readl(ctrl, INTR_LOC);
- dbg("%s: intr_loc2 = %x\n",__FUNCTION__, intr_loc2);
+ dbg("%s: intr_loc2 = %x\n",__FUNCTION__, intr_loc2);
}
if (intr_loc & CMD_INTR_PENDING) {
- /*
- * Command Complete Interrupt Pending
+ /*
+ * Command Complete Interrupt Pending
* RO only - clear by writing 1 to the Command Completion
* Detect bit in Controller SERR-INT register
*/
@@ -875,7 +767,7 @@ static irqreturn_t shpc_isr(int irq, void *dev_id)
if (!(intr_loc & ~CMD_INTR_PENDING))
goto out;
- for (hp_slot = 0; hp_slot < ctrl->num_slots; hp_slot++) {
+ for (hp_slot = 0; hp_slot < ctrl->num_slots; hp_slot++) {
/* To find out which slot has interrupt pending */
if (!(intr_loc & SLOT_INTR_PENDING(hp_slot)))
continue;
@@ -907,7 +799,7 @@ static irqreturn_t shpc_isr(int irq, void *dev_id)
serr_int &= ~(GLOBAL_INTR_MASK | SERR_INTR_RSVDZ_MASK);
shpc_writel(ctrl, SERR_INTR_ENABLE, serr_int);
}
-
+
return IRQ_HANDLED;
}
@@ -920,8 +812,6 @@ static int hpc_get_max_bus_speed (struct slot *slot, enum pci_bus_speed *value)
u32 slot_avail1 = shpc_readl(ctrl, SLOT_AVAIL1);
u32 slot_avail2 = shpc_readl(ctrl, SLOT_AVAIL2);
- DBG_ENTER_ROUTINE
-
if (pi == 2) {
if (slot_avail2 & SLOT_133MHZ_PCIX_533)
bus_speed = PCI_SPEED_133MHz_PCIX_533;
@@ -954,7 +844,7 @@ static int hpc_get_max_bus_speed (struct slot *slot, enum pci_bus_speed *value)
*value = bus_speed;
dbg("Max bus speed = %d\n", bus_speed);
- DBG_LEAVE_ROUTINE
+
return retval;
}
@@ -967,8 +857,6 @@ static int hpc_get_cur_bus_speed (struct slot *slot, enum pci_bus_speed *value)
u8 pi = shpc_readb(ctrl, PROG_INTERFACE);
u8 speed_mode = (pi == 2) ? (sec_bus_reg & 0xF) : (sec_bus_reg & 0x7);
- DBG_ENTER_ROUTINE
-
if ((pi == 1) && (speed_mode > 4)) {
*value = PCI_SPEED_UNKNOWN;
return -ENODEV;
@@ -1024,7 +912,6 @@ static int hpc_get_cur_bus_speed (struct slot *slot, enum pci_bus_speed *value)
}
dbg("Current bus speed = %d\n", bus_speed);
- DBG_LEAVE_ROUTINE
return retval;
}
@@ -1032,7 +919,7 @@ static struct hpc_ops shpchp_hpc_ops = {
.power_on_slot = hpc_power_on_slot,
.slot_enable = hpc_slot_enable,
.slot_disable = hpc_slot_disable,
- .set_bus_speed_mode = hpc_set_bus_speed_mode,
+ .set_bus_speed_mode = hpc_set_bus_speed_mode,
.set_attention_status = hpc_set_attention_status,
.get_power_status = hpc_get_power_status,
.get_attention_status = hpc_get_attention_status,
@@ -1049,7 +936,7 @@ static struct hpc_ops shpchp_hpc_ops = {
.green_led_on = hpc_set_green_led_on,
.green_led_off = hpc_set_green_led_off,
.green_led_blink = hpc_set_green_led_blink,
-
+
.release_ctlr = hpc_release_ctlr,
};
@@ -1061,8 +948,6 @@ int shpc_init(struct controller *ctrl, struct pci_dev *pdev)
u32 tempdword, slot_reg, slot_config;
u8 i;
- DBG_ENTER_ROUTINE
-
ctrl->pci_dev = pdev; /* pci_dev of the P2P bridge */
if ((pdev->vendor == PCI_VENDOR_ID_AMD) || (pdev->device ==
@@ -1108,9 +993,9 @@ int shpc_init(struct controller *ctrl, struct pci_dev *pdev)
ctrl->mmio_size = 0x24 + 0x4 * num_slots;
}
- info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, pdev->subsystem_vendor,
+ info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, pdev->subsystem_vendor,
pdev->subsystem_device);
-
+
rc = pci_enable_device(pdev);
if (rc) {
err("%s: pci_enable_device failed\n", __FUNCTION__);
@@ -1172,7 +1057,7 @@ int shpc_init(struct controller *ctrl, struct pci_dev *pdev)
slot_reg &= ~SLOT_REG_RSVDZ_MASK;
shpc_writel(ctrl, SLOT_REG(hp_slot), slot_reg);
}
-
+
if (shpchp_poll_mode) {
/* Install interrupt polling timer. Start with 10 sec delay */
init_timer(&ctrl->poll_timer);
@@ -1184,7 +1069,7 @@ int shpc_init(struct controller *ctrl, struct pci_dev *pdev)
info("Can't get msi for the hotplug controller\n");
info("Use INTx for the hotplug controller\n");
}
-
+
rc = request_irq(ctrl->pci_dev->irq, shpc_isr, IRQF_SHARED,
MY_NAME, (void *)ctrl);
dbg("%s: request_irq %d for hpc%d (returns %d)\n",
@@ -1235,13 +1120,11 @@ int shpc_init(struct controller *ctrl, struct pci_dev *pdev)
dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword);
}
- DBG_LEAVE_ROUTINE
return 0;
/* We end up here for the many possible ways to fail this API. */
abort_iounmap:
iounmap(ctrl->creg);
abort:
- DBG_LEAVE_ROUTINE
return rc;
}
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index ed3f7e1a563..68555c11f55 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -24,8 +24,6 @@
#include "pci.h"
#include "msi.h"
-static DEFINE_SPINLOCK(msi_lock);
-static struct msi_desc* msi_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = NULL };
static struct kmem_cache* msi_cachep;
static int pci_msi_enable = 1;
@@ -44,13 +42,13 @@ static void msi_set_mask_bit(unsigned int irq, int flag)
{
struct msi_desc *entry;
- entry = msi_desc[irq];
+ entry = get_irq_msi(irq);
BUG_ON(!entry || !entry->dev);
switch (entry->msi_attrib.type) {
case PCI_CAP_ID_MSI:
if (entry->msi_attrib.maskbit) {
- int pos;
- u32 mask_bits;
+ int pos;
+ u32 mask_bits;
pos = (long)entry->mask_base;
pci_read_config_dword(entry->dev, pos, &mask_bits);
@@ -74,7 +72,7 @@ static void msi_set_mask_bit(unsigned int irq, int flag)
void read_msi_msg(unsigned int irq, struct msi_msg *msg)
{
- struct msi_desc *entry = get_irq_data(irq);
+ struct msi_desc *entry = get_irq_msi(irq);
switch(entry->msi_attrib.type) {
case PCI_CAP_ID_MSI:
{
@@ -113,7 +111,7 @@ void read_msi_msg(unsigned int irq, struct msi_msg *msg)
void write_msi_msg(unsigned int irq, struct msi_msg *msg)
{
- struct msi_desc *entry = get_irq_data(irq);
+ struct msi_desc *entry = get_irq_msi(irq);
switch (entry->msi_attrib.type) {
case PCI_CAP_ID_MSI:
{
@@ -162,6 +160,7 @@ void unmask_msi_irq(unsigned int irq)
}
static int msi_free_irq(struct pci_dev* dev, int irq);
+
static int msi_init(void)
{
static int status = -ENOMEM;
@@ -169,13 +168,6 @@ static int msi_init(void)
if (!status)
return status;
- if (pci_msi_quirk) {
- pci_msi_enable = 0;
- printk(KERN_WARNING "PCI: MSI quirk detected. MSI disabled.\n");
- status = -EINVAL;
- return status;
- }
-
status = msi_cache_init();
if (status < 0) {
pci_msi_enable = 0;
@@ -200,46 +192,6 @@ static struct msi_desc* alloc_msi_entry(void)
return entry;
}
-static void attach_msi_entry(struct msi_desc *entry, int irq)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&msi_lock, flags);
- msi_desc[irq] = entry;
- spin_unlock_irqrestore(&msi_lock, flags);
-}
-
-static int create_msi_irq(void)
-{
- struct msi_desc *entry;
- int irq;
-
- entry = alloc_msi_entry();
- if (!entry)
- return -ENOMEM;
-
- irq = create_irq();
- if (irq < 0) {
- kmem_cache_free(msi_cachep, entry);
- return -EBUSY;
- }
-
- set_irq_data(irq, entry);
-
- return irq;
-}
-
-static void destroy_msi_irq(unsigned int irq)
-{
- struct msi_desc *entry;
-
- entry = get_irq_data(irq);
- set_irq_chip(irq, NULL);
- set_irq_data(irq, NULL);
- destroy_irq(irq);
- kmem_cache_free(msi_cachep, entry);
-}
-
static void enable_msi_mode(struct pci_dev *dev, int pos, int type)
{
u16 control;
@@ -278,36 +230,8 @@ void disable_msi_mode(struct pci_dev *dev, int pos, int type)
pci_intx(dev, 1); /* enable intx */
}
-static int msi_lookup_irq(struct pci_dev *dev, int type)
-{
- int irq;
- unsigned long flags;
-
- spin_lock_irqsave(&msi_lock, flags);
- for (irq = 0; irq < NR_IRQS; irq++) {
- if (!msi_desc[irq] || msi_desc[irq]->dev != dev ||
- msi_desc[irq]->msi_attrib.type != type ||
- msi_desc[irq]->msi_attrib.default_irq != dev->irq)
- continue;
- spin_unlock_irqrestore(&msi_lock, flags);
- /* This pre-assigned MSI irq for this device
- already exits. Override dev->irq with this irq */
- dev->irq = irq;
- return 0;
- }
- spin_unlock_irqrestore(&msi_lock, flags);
-
- return -EACCES;
-}
-
-void pci_scan_msi_device(struct pci_dev *dev)
-{
- if (!dev)
- return;
-}
-
#ifdef CONFIG_PM
-int pci_save_msi_state(struct pci_dev *dev)
+static int __pci_save_msi_state(struct pci_dev *dev)
{
int pos, i = 0;
u16 control;
@@ -345,7 +269,7 @@ int pci_save_msi_state(struct pci_dev *dev)
return 0;
}
-void pci_restore_msi_state(struct pci_dev *dev)
+static void __pci_restore_msi_state(struct pci_dev *dev)
{
int i = 0, pos;
u16 control;
@@ -373,14 +297,16 @@ void pci_restore_msi_state(struct pci_dev *dev)
kfree(save_state);
}
-int pci_save_msix_state(struct pci_dev *dev)
+static int __pci_save_msix_state(struct pci_dev *dev)
{
int pos;
- int temp;
int irq, head, tail = 0;
u16 control;
struct pci_cap_saved_state *save_state;
+ if (!dev->msix_enabled)
+ return 0;
+
pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
if (pos <= 0 || dev->no_msi)
return 0;
@@ -398,38 +324,46 @@ int pci_save_msix_state(struct pci_dev *dev)
*((u16 *)&save_state->data[0]) = control;
/* save the table */
- temp = dev->irq;
- if (msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) {
- kfree(save_state);
- return -EINVAL;
- }
-
- irq = head = dev->irq;
+ irq = head = dev->first_msi_irq;
while (head != tail) {
struct msi_desc *entry;
- entry = msi_desc[irq];
+ entry = get_irq_msi(irq);
read_msi_msg(irq, &entry->msg_save);
- tail = msi_desc[irq]->link.tail;
+ tail = entry->link.tail;
irq = tail;
}
- dev->irq = temp;
save_state->cap_nr = PCI_CAP_ID_MSIX;
pci_add_saved_cap(dev, save_state);
return 0;
}
-void pci_restore_msix_state(struct pci_dev *dev)
+int pci_save_msi_state(struct pci_dev *dev)
+{
+ int rc;
+
+ rc = __pci_save_msi_state(dev);
+ if (rc)
+ return rc;
+
+ rc = __pci_save_msix_state(dev);
+
+ return rc;
+}
+
+static void __pci_restore_msix_state(struct pci_dev *dev)
{
u16 save;
int pos;
int irq, head, tail = 0;
struct msi_desc *entry;
- int temp;
struct pci_cap_saved_state *save_state;
+ if (!dev->msix_enabled)
+ return;
+
save_state = pci_find_saved_cap(dev, PCI_CAP_ID_MSIX);
if (!save_state)
return;
@@ -442,23 +376,25 @@ void pci_restore_msix_state(struct pci_dev *dev)
return;
/* route the table */
- temp = dev->irq;
- if (msi_lookup_irq(dev, PCI_CAP_ID_MSIX))
- return;
- irq = head = dev->irq;
+ irq = head = dev->first_msi_irq;
while (head != tail) {
- entry = msi_desc[irq];
+ entry = get_irq_msi(irq);
write_msi_msg(irq, &entry->msg_save);
- tail = msi_desc[irq]->link.tail;
+ tail = entry->link.tail;
irq = tail;
}
- dev->irq = temp;
pci_write_config_word(dev, msi_control_reg(pos), save);
enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);
}
-#endif
+
+void pci_restore_msi_state(struct pci_dev *dev)
+{
+ __pci_restore_msi_state(dev);
+ __pci_restore_msix_state(dev);
+}
+#endif /* CONFIG_PM */
/**
* msi_capability_init - configure device's MSI capability structure
@@ -471,7 +407,6 @@ void pci_restore_msix_state(struct pci_dev *dev)
**/
static int msi_capability_init(struct pci_dev *dev)
{
- int status;
struct msi_desc *entry;
int pos, irq;
u16 control;
@@ -479,13 +414,10 @@ static int msi_capability_init(struct pci_dev *dev)
pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
pci_read_config_word(dev, msi_control_reg(pos), &control);
/* MSI Entry Initialization */
- irq = create_msi_irq();
- if (irq < 0)
- return irq;
+ entry = alloc_msi_entry();
+ if (!entry)
+ return -ENOMEM;
- entry = get_irq_data(irq);
- entry->link.head = irq;
- entry->link.tail = irq;
entry->msi_attrib.type = PCI_CAP_ID_MSI;
entry->msi_attrib.is_64 = is_64bit_address(control);
entry->msi_attrib.entry_nr = 0;
@@ -511,13 +443,16 @@ static int msi_capability_init(struct pci_dev *dev)
maskbits);
}
/* Configure MSI capability structure */
- status = arch_setup_msi_irq(irq, dev);
- if (status < 0) {
- destroy_msi_irq(irq);
- return status;
+ irq = arch_setup_msi_irq(dev, entry);
+ if (irq < 0) {
+ kmem_cache_free(msi_cachep, entry);
+ return irq;
}
+ entry->link.head = irq;
+ entry->link.tail = irq;
+ dev->first_msi_irq = irq;
+ set_irq_msi(irq, entry);
- attach_msi_entry(entry, irq);
/* Set MSI enabled bits */
enable_msi_mode(dev, pos, PCI_CAP_ID_MSI);
@@ -539,7 +474,6 @@ static int msix_capability_init(struct pci_dev *dev,
struct msix_entry *entries, int nvec)
{
struct msi_desc *head = NULL, *tail = NULL, *entry = NULL;
- int status;
int irq, pos, i, j, nr_entries, temp = 0;
unsigned long phys_addr;
u32 table_offset;
@@ -562,13 +496,11 @@ static int msix_capability_init(struct pci_dev *dev,
/* MSI-X Table Initialization */
for (i = 0; i < nvec; i++) {
- irq = create_msi_irq();
- if (irq < 0)
+ entry = alloc_msi_entry();
+ if (!entry)
break;
- entry = get_irq_data(irq);
j = entries[i].entry;
- entries[i].vector = irq;
entry->msi_attrib.type = PCI_CAP_ID_MSIX;
entry->msi_attrib.is_64 = 1;
entry->msi_attrib.entry_nr = j;
@@ -577,6 +509,14 @@ static int msix_capability_init(struct pci_dev *dev,
entry->msi_attrib.pos = pos;
entry->dev = dev;
entry->mask_base = base;
+
+ /* Configure MSI-X capability structure */
+ irq = arch_setup_msi_irq(dev, entry);
+ if (irq < 0) {
+ kmem_cache_free(msi_cachep, entry);
+ break;
+ }
+ entries[i].vector = irq;
if (!head) {
entry->link.head = irq;
entry->link.tail = irq;
@@ -589,14 +529,8 @@ static int msix_capability_init(struct pci_dev *dev,
}
temp = irq;
tail = entry;
- /* Configure MSI-X capability structure */
- status = arch_setup_msi_irq(irq, dev);
- if (status < 0) {
- destroy_msi_irq(irq);
- break;
- }
- attach_msi_entry(entry, irq);
+ set_irq_msi(irq, entry);
}
if (i != nvec) {
int avail = i - 1;
@@ -613,6 +547,7 @@ static int msix_capability_init(struct pci_dev *dev,
avail = -EBUSY;
return avail;
}
+ dev->first_msi_irq = entries[0].vector;
/* Set MSI-X enabled bits */
enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);
@@ -660,13 +595,11 @@ int pci_msi_supported(struct pci_dev * dev)
**/
int pci_enable_msi(struct pci_dev* dev)
{
- int pos, temp, status;
+ int pos, status;
if (pci_msi_supported(dev) < 0)
return -EINVAL;
- temp = dev->irq;
-
status = msi_init();
if (status < 0)
return status;
@@ -675,15 +608,14 @@ int pci_enable_msi(struct pci_dev* dev)
if (!pos)
return -EINVAL;
- WARN_ON(!msi_lookup_irq(dev, PCI_CAP_ID_MSI));
+ WARN_ON(!!dev->msi_enabled);
/* Check whether driver already requested for MSI-X irqs */
pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
- if (pos > 0 && !msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) {
+ if (pos > 0 && dev->msix_enabled) {
printk(KERN_INFO "PCI: %s: Can't enable MSI. "
- "Device already has MSI-X irq assigned\n",
+ "Device already has MSI-X enabled\n",
pci_name(dev));
- dev->irq = temp;
return -EINVAL;
}
status = msi_capability_init(dev);
@@ -695,13 +627,15 @@ void pci_disable_msi(struct pci_dev* dev)
struct msi_desc *entry;
int pos, default_irq;
u16 control;
- unsigned long flags;
if (!pci_msi_enable)
return;
if (!dev)
return;
+ if (!dev->msi_enabled)
+ return;
+
pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
if (!pos)
return;
@@ -710,28 +644,26 @@ void pci_disable_msi(struct pci_dev* dev)
if (!(control & PCI_MSI_FLAGS_ENABLE))
return;
+
disable_msi_mode(dev, pos, PCI_CAP_ID_MSI);
- spin_lock_irqsave(&msi_lock, flags);
- entry = msi_desc[dev->irq];
+ entry = get_irq_msi(dev->first_msi_irq);
if (!entry || !entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) {
- spin_unlock_irqrestore(&msi_lock, flags);
return;
}
- if (irq_has_action(dev->irq)) {
- spin_unlock_irqrestore(&msi_lock, flags);
+ if (irq_has_action(dev->first_msi_irq)) {
printk(KERN_WARNING "PCI: %s: pci_disable_msi() called without "
"free_irq() on MSI irq %d\n",
- pci_name(dev), dev->irq);
- BUG_ON(irq_has_action(dev->irq));
+ pci_name(dev), dev->first_msi_irq);
+ BUG_ON(irq_has_action(dev->first_msi_irq));
} else {
default_irq = entry->msi_attrib.default_irq;
- spin_unlock_irqrestore(&msi_lock, flags);
- msi_free_irq(dev, dev->irq);
+ msi_free_irq(dev, dev->first_msi_irq);
/* Restore dev->irq to its default pin-assertion irq */
dev->irq = default_irq;
}
+ dev->first_msi_irq = 0;
}
static int msi_free_irq(struct pci_dev* dev, int irq)
@@ -739,27 +671,20 @@ static int msi_free_irq(struct pci_dev* dev, int irq)
struct msi_desc *entry;
int head, entry_nr, type;
void __iomem *base;
- unsigned long flags;
- arch_teardown_msi_irq(irq);
-
- spin_lock_irqsave(&msi_lock, flags);
- entry = msi_desc[irq];
+ entry = get_irq_msi(irq);
if (!entry || entry->dev != dev) {
- spin_unlock_irqrestore(&msi_lock, flags);
return -EINVAL;
}
type = entry->msi_attrib.type;
entry_nr = entry->msi_attrib.entry_nr;
head = entry->link.head;
base = entry->mask_base;
- msi_desc[entry->link.head]->link.tail = entry->link.tail;
- msi_desc[entry->link.tail]->link.head = entry->link.head;
- entry->dev = NULL;
- msi_desc[irq] = NULL;
- spin_unlock_irqrestore(&msi_lock, flags);
+ get_irq_msi(entry->link.head)->link.tail = entry->link.tail;
+ get_irq_msi(entry->link.tail)->link.head = entry->link.head;
- destroy_msi_irq(irq);
+ arch_teardown_msi_irq(irq);
+ kmem_cache_free(msi_cachep, entry);
if (type == PCI_CAP_ID_MSIX) {
writel(1, base + entry_nr * PCI_MSIX_ENTRY_SIZE +
@@ -790,7 +715,7 @@ static int msi_free_irq(struct pci_dev* dev, int irq)
int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec)
{
int status, pos, nr_entries;
- int i, j, temp;
+ int i, j;
u16 control;
if (!entries || pci_msi_supported(dev) < 0)
@@ -818,16 +743,14 @@ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec)
return -EINVAL; /* duplicate entry */
}
}
- temp = dev->irq;
- WARN_ON(!msi_lookup_irq(dev, PCI_CAP_ID_MSIX));
+ WARN_ON(!!dev->msix_enabled);
/* Check whether driver already requested for MSI irq */
if (pci_find_capability(dev, PCI_CAP_ID_MSI) > 0 &&
- !msi_lookup_irq(dev, PCI_CAP_ID_MSI)) {
+ dev->msi_enabled) {
printk(KERN_INFO "PCI: %s: Can't enable MSI-X. "
"Device already has an MSI irq assigned\n",
pci_name(dev));
- dev->irq = temp;
return -EINVAL;
}
status = msix_capability_init(dev, entries, nvec);
@@ -836,7 +759,8 @@ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec)
void pci_disable_msix(struct pci_dev* dev)
{
- int pos, temp;
+ int irq, head, tail = 0, warning = 0;
+ int pos;
u16 control;
if (!pci_msi_enable)
@@ -844,6 +768,9 @@ void pci_disable_msix(struct pci_dev* dev)
if (!dev)
return;
+ if (!dev->msix_enabled)
+ return;
+
pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
if (!pos)
return;
@@ -854,31 +781,23 @@ void pci_disable_msix(struct pci_dev* dev)
disable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);
- temp = dev->irq;
- if (!msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) {
- int irq, head, tail = 0, warning = 0;
- unsigned long flags;
-
- irq = head = dev->irq;
- dev->irq = temp; /* Restore pin IRQ */
- while (head != tail) {
- spin_lock_irqsave(&msi_lock, flags);
- tail = msi_desc[irq]->link.tail;
- spin_unlock_irqrestore(&msi_lock, flags);
- if (irq_has_action(irq))
- warning = 1;
- else if (irq != head) /* Release MSI-X irq */
- msi_free_irq(dev, irq);
- irq = tail;
- }
- msi_free_irq(dev, irq);
- if (warning) {
- printk(KERN_WARNING "PCI: %s: pci_disable_msix() called without "
- "free_irq() on all MSI-X irqs\n",
- pci_name(dev));
- BUG_ON(warning > 0);
- }
+ irq = head = dev->first_msi_irq;
+ while (head != tail) {
+ tail = get_irq_msi(irq)->link.tail;
+ if (irq_has_action(irq))
+ warning = 1;
+ else if (irq != head) /* Release MSI-X irq */
+ msi_free_irq(dev, irq);
+ irq = tail;
+ }
+ msi_free_irq(dev, irq);
+ if (warning) {
+ printk(KERN_WARNING "PCI: %s: pci_disable_msix() called without "
+ "free_irq() on all MSI-X irqs\n",
+ pci_name(dev));
+ BUG_ON(warning > 0);
}
+ dev->first_msi_irq = 0;
}
/**
@@ -892,35 +811,26 @@ void pci_disable_msix(struct pci_dev* dev)
**/
void msi_remove_pci_irq_vectors(struct pci_dev* dev)
{
- int pos, temp;
- unsigned long flags;
-
if (!pci_msi_enable || !dev)
return;
- temp = dev->irq; /* Save IOAPIC IRQ */
- pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
- if (pos > 0 && !msi_lookup_irq(dev, PCI_CAP_ID_MSI)) {
- if (irq_has_action(dev->irq)) {
+ if (dev->msi_enabled) {
+ if (irq_has_action(dev->first_msi_irq)) {
printk(KERN_WARNING "PCI: %s: msi_remove_pci_irq_vectors() "
"called without free_irq() on MSI irq %d\n",
- pci_name(dev), dev->irq);
- BUG_ON(irq_has_action(dev->irq));
+ pci_name(dev), dev->first_msi_irq);
+ BUG_ON(irq_has_action(dev->first_msi_irq));
} else /* Release MSI irq assigned to this device */
- msi_free_irq(dev, dev->irq);
- dev->irq = temp; /* Restore IOAPIC IRQ */
+ msi_free_irq(dev, dev->first_msi_irq);
}
- pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
- if (pos > 0 && !msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) {
+ if (dev->msix_enabled) {
int irq, head, tail = 0, warning = 0;
void __iomem *base = NULL;
- irq = head = dev->irq;
+ irq = head = dev->first_msi_irq;
while (head != tail) {
- spin_lock_irqsave(&msi_lock, flags);
- tail = msi_desc[irq]->link.tail;
- base = msi_desc[irq]->mask_base;
- spin_unlock_irqrestore(&msi_lock, flags);
+ tail = get_irq_msi(irq)->link.tail;
+ base = get_irq_msi(irq)->mask_base;
if (irq_has_action(irq))
warning = 1;
else if (irq != head) /* Release MSI-X irq */
@@ -935,7 +845,6 @@ void msi_remove_pci_irq_vectors(struct pci_dev* dev)
pci_name(dev));
BUG_ON(warning > 0);
}
- dev->irq = temp; /* Restore IOAPIC IRQ */
}
}
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index 92d5e8db0de..a3c1755b2f2 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -324,8 +324,7 @@ static int pci_default_resume(struct pci_dev *pci_dev)
/* restore the PCI config space */
pci_restore_state(pci_dev);
/* if the device was enabled before suspend, reenable */
- if (atomic_read(&pci_dev->enable_cnt))
- retval = __pci_enable_device(pci_dev);
+ retval = __pci_reenable_device(pci_dev);
/* if the device was busmaster before the suspend, make it busmaster again */
if (pci_dev->is_busmaster)
pci_set_master(pci_dev);
@@ -416,13 +415,15 @@ static struct kobj_type pci_driver_kobj_type = {
* __pci_register_driver - register a new pci driver
* @drv: the driver structure to register
* @owner: owner module of drv
+ * @mod_name: module name string
*
* Adds the driver structure to the list of registered drivers.
* Returns a negative value on error, otherwise 0.
* If no error occurred, the driver remains registered even if
* no device was claimed during registration.
*/
-int __pci_register_driver(struct pci_driver *drv, struct module *owner)
+int __pci_register_driver(struct pci_driver *drv, struct module *owner,
+ const char *mod_name)
{
int error;
@@ -430,6 +431,7 @@ int __pci_register_driver(struct pci_driver *drv, struct module *owner)
drv->driver.name = drv->name;
drv->driver.bus = &pci_bus_type;
drv->driver.owner = owner;
+ drv->driver.mod_name = mod_name;
drv->driver.kobj.ktype = &pci_driver_kobj_type;
if (pci_multithread_probe)
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index 7a94076752d..cd913a2a416 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -143,6 +143,14 @@ static ssize_t is_enabled_show(struct device *dev,
return sprintf (buf, "%u\n", atomic_read(&pdev->enable_cnt));
}
+#ifdef CONFIG_NUMA
+static ssize_t
+numa_node_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ return sprintf (buf, "%d\n", dev->numa_node);
+}
+#endif
+
static ssize_t
msi_bus_show(struct device *dev, struct device_attribute *attr, char *buf)
{
@@ -194,6 +202,9 @@ struct device_attribute pci_dev_attrs[] = {
__ATTR_RO(irq),
__ATTR_RO(local_cpus),
__ATTR_RO(modalias),
+#ifdef CONFIG_NUMA
+ __ATTR_RO(numa_node),
+#endif
__ATTR(enable, 0600, is_enabled_show, is_enabled_store),
__ATTR(broken_parity_status,(S_IRUGO|S_IWUSR),
broken_parity_status_show,broken_parity_status_store),
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 206c834d263..1e74e1ee8bd 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -21,6 +21,12 @@
unsigned int pci_pm_d3_delay = 10;
+#define DEFAULT_CARDBUS_IO_SIZE (256)
+#define DEFAULT_CARDBUS_MEM_SIZE (64*1024*1024)
+/* pci=cbmemsize=nnM,cbiosize=nn can override this */
+unsigned long pci_cardbus_io_size = DEFAULT_CARDBUS_IO_SIZE;
+unsigned long pci_cardbus_mem_size = DEFAULT_CARDBUS_MEM_SIZE;
+
/**
* pci_bus_max_busnr - returns maximum PCI bus number of given bus' children
* @bus: pointer to PCI bus structure to search
@@ -392,6 +398,14 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state)
if (state > PCI_D3hot)
state = PCI_D3hot;
+ /*
+ * If the device or the parent bridge can't support PCI PM, ignore
+ * the request if we're doing anything besides putting it into D0
+ * (which would only happen on boot).
+ */
+ if ((state == PCI_D1 || state == PCI_D2) && pci_no_d1d2(dev))
+ return 0;
+
/* Validate current state:
* Can enter D0 from any state, but if we can only go deeper
* to sleep if we're already in a low power state
@@ -403,13 +417,6 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state)
} else if (dev->current_state == state)
return 0; /* we're already there */
- /*
- * If the device or the parent bridge can't support PCI PM, ignore
- * the request if we're doing anything besides putting it into D0
- * (which would only happen on boot).
- */
- if ((state == PCI_D1 || state == PCI_D2) && pci_no_d1d2(dev))
- return 0;
/* find PCI PM capability in list */
pm = pci_find_capability(dev, PCI_CAP_ID_PM);
@@ -633,8 +640,6 @@ pci_save_state(struct pci_dev *dev)
pci_read_config_dword(dev, i * 4,&dev->saved_config_space[i]);
if ((i = pci_save_msi_state(dev)) != 0)
return i;
- if ((i = pci_save_msix_state(dev)) != 0)
- return i;
if ((i = pci_save_pcie_state(dev)) != 0)
return i;
if ((i = pci_save_pcix_state(dev)) != 0)
@@ -672,22 +677,11 @@ pci_restore_state(struct pci_dev *dev)
}
pci_restore_pcix_state(dev);
pci_restore_msi_state(dev);
- pci_restore_msix_state(dev);
+
return 0;
}
-/**
- * pci_enable_device_bars - Initialize some of a device for use
- * @dev: PCI device to be initialized
- * @bars: bitmask of BAR's that must be configured
- *
- * Initialize device before it's used by a driver. Ask low-level code
- * to enable selected I/O and memory resources. Wake up the device if it
- * was suspended. Beware, this function can fail.
- */
-
-int
-pci_enable_device_bars(struct pci_dev *dev, int bars)
+static int do_pci_enable_device(struct pci_dev *dev, int bars)
{
int err;
@@ -697,30 +691,47 @@ pci_enable_device_bars(struct pci_dev *dev, int bars)
err = pcibios_enable_device(dev, bars);
if (err < 0)
return err;
+ pci_fixup_device(pci_fixup_enable, dev);
+
return 0;
}
/**
- * __pci_enable_device - Initialize device before it's used by a driver.
+ * __pci_reenable_device - Resume abandoned device
+ * @dev: PCI device to be resumed
+ *
+ * Note this function is a backend of pci_default_resume and is not supposed
+ * to be called by normal code, write proper resume handler and use it instead.
+ */
+int
+__pci_reenable_device(struct pci_dev *dev)
+{
+ if (atomic_read(&dev->enable_cnt))
+ return do_pci_enable_device(dev, (1 << PCI_NUM_RESOURCES) - 1);
+ return 0;
+}
+
+/**
+ * pci_enable_device_bars - Initialize some of a device for use
* @dev: PCI device to be initialized
+ * @bars: bitmask of BAR's that must be configured
*
* Initialize device before it's used by a driver. Ask low-level code
- * to enable I/O and memory. Wake up the device if it was suspended.
- * Beware, this function can fail.
- *
- * Note this function is a backend and is not supposed to be called by
- * normal code, use pci_enable_device() instead.
+ * to enable selected I/O and memory resources. Wake up the device if it
+ * was suspended. Beware, this function can fail.
*/
int
-__pci_enable_device(struct pci_dev *dev)
+pci_enable_device_bars(struct pci_dev *dev, int bars)
{
int err;
- err = pci_enable_device_bars(dev, (1 << PCI_NUM_RESOURCES) - 1);
- if (err)
- return err;
- pci_fixup_device(pci_fixup_enable, dev);
- return 0;
+ if (atomic_add_return(1, &dev->enable_cnt) > 1)
+ return 0; /* already enabled */
+
+ err = do_pci_enable_device(dev, bars);
+ if (err < 0)
+ atomic_dec(&dev->enable_cnt);
+ return err;
}
/**
@@ -736,13 +747,105 @@ __pci_enable_device(struct pci_dev *dev)
*/
int pci_enable_device(struct pci_dev *dev)
{
- int result;
- if (atomic_add_return(1, &dev->enable_cnt) > 1)
- return 0; /* already enabled */
- result = __pci_enable_device(dev);
- if (result < 0)
- atomic_dec(&dev->enable_cnt);
- return result;
+ return pci_enable_device_bars(dev, (1 << PCI_NUM_RESOURCES) - 1);
+}
+
+/*
+ * Managed PCI resources. This manages device on/off, intx/msi/msix
+ * on/off and BAR regions. pci_dev itself records msi/msix status, so
+ * there's no need to track it separately. pci_devres is initialized
+ * when a device is enabled using managed PCI device enable interface.
+ */
+struct pci_devres {
+ unsigned int disable:1;
+ unsigned int orig_intx:1;
+ unsigned int restore_intx:1;
+ u32 region_mask;
+};
+
+static void pcim_release(struct device *gendev, void *res)
+{
+ struct pci_dev *dev = container_of(gendev, struct pci_dev, dev);
+ struct pci_devres *this = res;
+ int i;
+
+ if (dev->msi_enabled)
+ pci_disable_msi(dev);
+ if (dev->msix_enabled)
+ pci_disable_msix(dev);
+
+ for (i = 0; i < DEVICE_COUNT_RESOURCE; i++)
+ if (this->region_mask & (1 << i))
+ pci_release_region(dev, i);
+
+ if (this->restore_intx)
+ pci_intx(dev, this->orig_intx);
+
+ if (this->disable)
+ pci_disable_device(dev);
+}
+
+static struct pci_devres * get_pci_dr(struct pci_dev *pdev)
+{
+ struct pci_devres *dr, *new_dr;
+
+ dr = devres_find(&pdev->dev, pcim_release, NULL, NULL);
+ if (dr)
+ return dr;
+
+ new_dr = devres_alloc(pcim_release, sizeof(*new_dr), GFP_KERNEL);
+ if (!new_dr)
+ return NULL;
+ return devres_get(&pdev->dev, new_dr, NULL, NULL);
+}
+
+static struct pci_devres * find_pci_dr(struct pci_dev *pdev)
+{
+ if (pci_is_managed(pdev))
+ return devres_find(&pdev->dev, pcim_release, NULL, NULL);
+ return NULL;
+}
+
+/**
+ * pcim_enable_device - Managed pci_enable_device()
+ * @pdev: PCI device to be initialized
+ *
+ * Managed pci_enable_device().
+ */
+int pcim_enable_device(struct pci_dev *pdev)
+{
+ struct pci_devres *dr;
+ int rc;
+
+ dr = get_pci_dr(pdev);
+ if (unlikely(!dr))
+ return -ENOMEM;
+ WARN_ON(!!dr->disable);
+
+ rc = pci_enable_device(pdev);
+ if (!rc) {
+ pdev->is_managed = 1;
+ dr->disable = 1;
+ }
+ return rc;
+}
+
+/**
+ * pcim_pin_device - Pin managed PCI device
+ * @pdev: PCI device to pin
+ *
+ * Pin managed PCI device @pdev. Pinned device won't be disabled on
+ * driver detach. @pdev must have been enabled with
+ * pcim_enable_device().
+ */
+void pcim_pin_device(struct pci_dev *pdev)
+{
+ struct pci_devres *dr;
+
+ dr = find_pci_dr(pdev);
+ WARN_ON(!dr || !dr->disable);
+ if (dr)
+ dr->disable = 0;
}
/**
@@ -768,8 +871,13 @@ void __attribute__ ((weak)) pcibios_disable_device (struct pci_dev *dev) {}
void
pci_disable_device(struct pci_dev *dev)
{
+ struct pci_devres *dr;
u16 pci_command;
+ dr = find_pci_dr(dev);
+ if (dr)
+ dr->disable = 0;
+
if (atomic_sub_return(1, &dev->enable_cnt) != 0)
return;
@@ -868,6 +976,8 @@ pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge)
*/
void pci_release_region(struct pci_dev *pdev, int bar)
{
+ struct pci_devres *dr;
+
if (pci_resource_len(pdev, bar) == 0)
return;
if (pci_resource_flags(pdev, bar) & IORESOURCE_IO)
@@ -876,6 +986,10 @@ void pci_release_region(struct pci_dev *pdev, int bar)
else if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM)
release_mem_region(pci_resource_start(pdev, bar),
pci_resource_len(pdev, bar));
+
+ dr = find_pci_dr(pdev);
+ if (dr)
+ dr->region_mask &= ~(1 << bar);
}
/**
@@ -894,6 +1008,8 @@ void pci_release_region(struct pci_dev *pdev, int bar)
*/
int pci_request_region(struct pci_dev *pdev, int bar, const char *res_name)
{
+ struct pci_devres *dr;
+
if (pci_resource_len(pdev, bar) == 0)
return 0;
@@ -907,7 +1023,11 @@ int pci_request_region(struct pci_dev *pdev, int bar, const char *res_name)
pci_resource_len(pdev, bar), res_name))
goto err_out;
}
-
+
+ dr = find_pci_dr(pdev);
+ if (dr)
+ dr->region_mask |= 1 << bar;
+
return 0;
err_out:
@@ -921,6 +1041,47 @@ err_out:
return -EBUSY;
}
+/**
+ * pci_release_selected_regions - Release selected PCI I/O and memory resources
+ * @pdev: PCI device whose resources were previously reserved
+ * @bars: Bitmask of BARs to be released
+ *
+ * Release selected PCI I/O and memory resources previously reserved.
+ * Call this function only after all use of the PCI regions has ceased.
+ */
+void pci_release_selected_regions(struct pci_dev *pdev, int bars)
+{
+ int i;
+
+ for (i = 0; i < 6; i++)
+ if (bars & (1 << i))
+ pci_release_region(pdev, i);
+}
+
+/**
+ * pci_request_selected_regions - Reserve selected PCI I/O and memory resources
+ * @pdev: PCI device whose resources are to be reserved
+ * @bars: Bitmask of BARs to be requested
+ * @res_name: Name to be associated with resource
+ */
+int pci_request_selected_regions(struct pci_dev *pdev, int bars,
+ const char *res_name)
+{
+ int i;
+
+ for (i = 0; i < 6; i++)
+ if (bars & (1 << i))
+ if(pci_request_region(pdev, i, res_name))
+ goto err_out;
+ return 0;
+
+err_out:
+ while(--i >= 0)
+ if (bars & (1 << i))
+ pci_release_region(pdev, i);
+
+ return -EBUSY;
+}
/**
* pci_release_regions - Release reserved PCI I/O and memory resources
@@ -933,10 +1094,7 @@ err_out:
void pci_release_regions(struct pci_dev *pdev)
{
- int i;
-
- for (i = 0; i < 6; i++)
- pci_release_region(pdev, i);
+ pci_release_selected_regions(pdev, (1 << 6) - 1);
}
/**
@@ -954,18 +1112,7 @@ void pci_release_regions(struct pci_dev *pdev)
*/
int pci_request_regions(struct pci_dev *pdev, const char *res_name)
{
- int i;
-
- for (i = 0; i < 6; i++)
- if(pci_request_region(pdev, i, res_name))
- goto err_out;
- return 0;
-
-err_out:
- while(--i >= 0)
- pci_release_region(pdev, i);
-
- return -EBUSY;
+ return pci_request_selected_regions(pdev, ((1 << 6) - 1), res_name);
}
/**
@@ -1118,7 +1265,15 @@ pci_intx(struct pci_dev *pdev, int enable)
}
if (new != pci_command) {
+ struct pci_devres *dr;
+
pci_write_config_word(pdev, PCI_COMMAND, new);
+
+ dr = find_pci_dr(pdev);
+ if (dr && !dr->restore_intx) {
+ dr->restore_intx = 1;
+ dr->orig_intx = !enable;
+ }
}
}
@@ -1148,7 +1303,23 @@ pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask)
return 0;
}
#endif
-
+
+/**
+ * pci_select_bars - Make BAR mask from the type of resource
+ * @dev: the PCI device for which BAR mask is made
+ * @flags: resource type mask to be selected
+ *
+ * This helper routine makes bar mask from the type of resource.
+ */
+int pci_select_bars(struct pci_dev *dev, unsigned long flags)
+{
+ int i, bars = 0;
+ for (i = 0; i < PCI_NUM_RESOURCES; i++)
+ if (pci_resource_flags(dev, i) & flags)
+ bars |= (1 << i);
+ return bars;
+}
+
static int __devinit pci_init(void)
{
struct pci_dev *dev = NULL;
@@ -1168,6 +1339,10 @@ static int __devinit pci_setup(char *str)
if (*str && (str = pcibios_setup(str)) && *str) {
if (!strcmp(str, "nomsi")) {
pci_no_msi();
+ } else if (!strncmp(str, "cbiosize=", 9)) {
+ pci_cardbus_io_size = memparse(str + 9, &str);
+ } else if (!strncmp(str, "cbmemsize=", 10)) {
+ pci_cardbus_mem_size = memparse(str + 10, &str);
} else {
printk(KERN_ERR "PCI: Unknown option `%s'\n",
str);
@@ -1181,15 +1356,11 @@ early_param("pci", pci_setup);
device_initcall(pci_init);
-#if defined(CONFIG_ISA) || defined(CONFIG_EISA)
-/* FIXME: Some boxes have multiple ISA bridges! */
-struct pci_dev *isa_bridge;
-EXPORT_SYMBOL(isa_bridge);
-#endif
-
EXPORT_SYMBOL_GPL(pci_restore_bars);
EXPORT_SYMBOL(pci_enable_device_bars);
EXPORT_SYMBOL(pci_enable_device);
+EXPORT_SYMBOL(pcim_enable_device);
+EXPORT_SYMBOL(pcim_pin_device);
EXPORT_SYMBOL(pci_disable_device);
EXPORT_SYMBOL(pci_find_capability);
EXPORT_SYMBOL(pci_bus_find_capability);
@@ -1197,6 +1368,8 @@ EXPORT_SYMBOL(pci_release_regions);
EXPORT_SYMBOL(pci_request_regions);
EXPORT_SYMBOL(pci_release_region);
EXPORT_SYMBOL(pci_request_region);
+EXPORT_SYMBOL(pci_release_selected_regions);
+EXPORT_SYMBOL(pci_request_selected_regions);
EXPORT_SYMBOL(pci_set_master);
EXPORT_SYMBOL(pci_set_mwi);
EXPORT_SYMBOL(pci_clear_mwi);
@@ -1205,13 +1378,10 @@ 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);
EXPORT_SYMBOL(pci_set_power_state);
EXPORT_SYMBOL(pci_save_state);
EXPORT_SYMBOL(pci_restore_state);
EXPORT_SYMBOL(pci_enable_wake);
-/* Quirk info */
-
-EXPORT_SYMBOL(isa_dma_bridge_buggy);
-EXPORT_SYMBOL(pci_pci_problems);
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 398852f526a..a4f2d580625 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -1,6 +1,6 @@
/* Functions internal to the PCI core code */
-extern int __must_check __pci_enable_device(struct pci_dev *);
+extern int __must_check __pci_reenable_device(struct pci_dev *);
extern int pci_uevent(struct device *dev, char **envp, int num_envp,
char *buffer, int buffer_size);
extern int pci_create_sysfs_dev_files(struct pci_dev *pdev);
@@ -43,12 +43,8 @@ extern void pci_remove_legacy_files(struct pci_bus *bus);
/* Lock for read/write access to pci device and bus lists */
extern struct rw_semaphore pci_bus_sem;
-#ifdef CONFIG_PCI_MSI
-extern int pci_msi_quirk;
-#else
-#define pci_msi_quirk 0
-#endif
extern unsigned int pci_pm_d3_delay;
+
#ifdef CONFIG_PCI_MSI
void disable_msi_mode(struct pci_dev *dev, int pos, int type);
void pci_no_msi(void);
@@ -56,17 +52,15 @@ void pci_no_msi(void);
static inline void disable_msi_mode(struct pci_dev *dev, int pos, int type) { }
static inline void pci_no_msi(void) { }
#endif
+
#if defined(CONFIG_PCI_MSI) && defined(CONFIG_PM)
int pci_save_msi_state(struct pci_dev *dev);
-int pci_save_msix_state(struct pci_dev *dev);
void pci_restore_msi_state(struct pci_dev *dev);
-void pci_restore_msix_state(struct pci_dev *dev);
#else
static inline int pci_save_msi_state(struct pci_dev *dev) { return 0; }
-static inline int pci_save_msix_state(struct pci_dev *dev) { return 0; }
static inline void pci_restore_msi_state(struct pci_dev *dev) {}
-static inline void pci_restore_msix_state(struct pci_dev *dev) {}
#endif
+
static inline int pci_no_d1d2(struct pci_dev *dev)
{
unsigned int parent_dstates = 0;
diff --git a/drivers/pci/pcie/aer/aerdrv.c b/drivers/pci/pcie/aer/aerdrv.c
index 6f5fabbd14e..b164de050d4 100644
--- a/drivers/pci/pcie/aer/aerdrv.c
+++ b/drivers/pci/pcie/aer/aerdrv.c
@@ -220,7 +220,7 @@ static int __devinit aer_probe (struct pcie_device *dev,
}
/* Request IRQ ISR */
- if ((status = request_irq(dev->irq, aer_irq, SA_SHIRQ, "aerdrv",
+ if ((status = request_irq(dev->irq, aer_irq, IRQF_SHARED, "aerdrv",
dev))) {
printk(KERN_DEBUG "%s: Request ISR fails on PCIE device[%s]\n",
__FUNCTION__, device->bus_id);
diff --git a/drivers/pci/pcie/aer/aerdrv.h b/drivers/pci/pcie/aer/aerdrv.h
index 3c0a58f64dd..bf655dbaf8e 100644
--- a/drivers/pci/pcie/aer/aerdrv.h
+++ b/drivers/pci/pcie/aer/aerdrv.h
@@ -85,7 +85,7 @@ struct aer_rpc {
struct mutex rpc_mutex; /*
* only one thread could do
* recovery on the same
- * root port hierachy
+ * root port hierarchy
*/
wait_queue_head_t wait_release;
};
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 0e0401dd02c..2fe1d690eb1 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -144,6 +144,32 @@ static u32 pci_size(u32 base, u32 maxbase, u32 mask)
return size;
}
+static u64 pci_size64(u64 base, u64 maxbase, u64 mask)
+{
+ u64 size = mask & maxbase; /* Find the significant bits */
+ if (!size)
+ return 0;
+
+ /* Get the lowest of them to find the decode size, and
+ from that the extent. */
+ size = (size & ~(size-1)) - 1;
+
+ /* base == maxbase can be valid only if the BAR has
+ already been programmed with all 1s. */
+ if (base == maxbase && ((base | size) & mask) != mask)
+ return 0;
+
+ return size;
+}
+
+static inline int is_64bit_memory(u32 mask)
+{
+ if ((mask & (PCI_BASE_ADDRESS_SPACE|PCI_BASE_ADDRESS_MEM_TYPE_MASK)) ==
+ (PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64))
+ return 1;
+ return 0;
+}
+
static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
{
unsigned int pos, reg, next;
@@ -151,6 +177,10 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
struct resource *res;
for(pos=0; pos<howmany; pos = next) {
+ u64 l64;
+ u64 sz64;
+ u32 raw_sz;
+
next = pos+1;
res = &dev->resource[pos];
res->name = pci_name(dev);
@@ -163,9 +193,16 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
continue;
if (l == 0xffffffff)
l = 0;
- if ((l & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY) {
+ raw_sz = sz;
+ if ((l & PCI_BASE_ADDRESS_SPACE) ==
+ PCI_BASE_ADDRESS_SPACE_MEMORY) {
sz = pci_size(l, sz, (u32)PCI_BASE_ADDRESS_MEM_MASK);
- if (!sz)
+ /*
+ * For 64bit prefetchable memory sz could be 0, if the
+ * real size is bigger than 4G, so we need to check
+ * szhi for that.
+ */
+ if (!is_64bit_memory(l) && !sz)
continue;
res->start = l & PCI_BASE_ADDRESS_MEM_MASK;
res->flags |= l & ~PCI_BASE_ADDRESS_MEM_MASK;
@@ -178,30 +215,36 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
}
res->end = res->start + (unsigned long) sz;
res->flags |= pci_calc_resource_flags(l);
- if ((l & (PCI_BASE_ADDRESS_SPACE | PCI_BASE_ADDRESS_MEM_TYPE_MASK))
- == (PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64)) {
+ if (is_64bit_memory(l)) {
u32 szhi, lhi;
+
pci_read_config_dword(dev, reg+4, &lhi);
pci_write_config_dword(dev, reg+4, ~0);
pci_read_config_dword(dev, reg+4, &szhi);
pci_write_config_dword(dev, reg+4, lhi);
- szhi = pci_size(lhi, szhi, 0xffffffff);
+ sz64 = ((u64)szhi << 32) | raw_sz;
+ l64 = ((u64)lhi << 32) | l;
+ sz64 = pci_size64(l64, sz64, PCI_BASE_ADDRESS_MEM_MASK);
next++;
#if BITS_PER_LONG == 64
- res->start |= ((unsigned long) lhi) << 32;
- res->end = res->start + sz;
- if (szhi) {
- /* This BAR needs > 4GB? Wow. */
- res->end |= (unsigned long)szhi<<32;
+ if (!sz64) {
+ res->start = 0;
+ res->end = 0;
+ res->flags = 0;
+ continue;
}
+ res->start = l64 & PCI_BASE_ADDRESS_MEM_MASK;
+ res->end = res->start + sz64;
#else
- if (szhi) {
- printk(KERN_ERR "PCI: Unable to handle 64-bit BAR for device %s\n", pci_name(dev));
+ if (sz64 > 0x100000000ULL) {
+ printk(KERN_ERR "PCI: Unable to handle 64-bit "
+ "BAR for device %s\n", pci_name(dev));
res->start = 0;
res->flags = 0;
} else if (lhi) {
/* 64-bit wide address, treat as disabled */
- pci_write_config_dword(dev, reg, l & ~(u32)PCI_BASE_ADDRESS_MEM_MASK);
+ pci_write_config_dword(dev, reg,
+ l & ~(u32)PCI_BASE_ADDRESS_MEM_MASK);
pci_write_config_dword(dev, reg+4, 0);
res->start = 0;
res->end = sz;
@@ -902,7 +945,6 @@ pci_scan_single_device(struct pci_bus *bus, int devfn)
return NULL;
pci_device_add(dev, bus);
- pci_scan_msi_device(dev);
return dev;
}
diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c
index 4a6760a3b31..ed87aa59f0b 100644
--- a/drivers/pci/proc.c
+++ b/drivers/pci/proc.c
@@ -287,7 +287,7 @@ static int proc_bus_pci_release(struct inode *inode, struct file *file)
}
#endif /* HAVE_PCI_MMAP */
-static struct file_operations proc_bus_pci_operations = {
+static const struct file_operations proc_bus_pci_operations = {
.llseek = proc_bus_pci_lseek,
.read = proc_bus_pci_read,
.write = proc_bus_pci_write,
@@ -456,7 +456,7 @@ static int proc_bus_pci_dev_open(struct inode *inode, struct file *file)
{
return seq_open(file, &proc_bus_pci_devices_op);
}
-static struct file_operations proc_bus_pci_dev_operations = {
+static const struct file_operations proc_bus_pci_dev_operations = {
.open = proc_bus_pci_dev_open,
.read = seq_read,
.llseek = seq_lseek,
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index c913ea4e545..1e6eda25c0d 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -61,7 +61,8 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, quirk_p
This appears to be BIOS not version dependent. So presumably there is a
chipset level fix */
-int isa_dma_bridge_buggy; /* Exported */
+int isa_dma_bridge_buggy;
+EXPORT_SYMBOL(isa_dma_bridge_buggy);
static void __devinit quirk_isa_dma_hangs(struct pci_dev *dev)
{
@@ -83,6 +84,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_CBUS_2, quirk_isa_d
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_CBUS_3, quirk_isa_dma_hangs );
int pci_pci_problems;
+EXPORT_SYMBOL(pci_pci_problems);
/*
* Chipsets where PCI->PCI transfers vanish or hang
@@ -94,6 +96,8 @@ static void __devinit quirk_nopcipci(struct pci_dev *dev)
pci_pci_problems |= PCIPCI_FAIL;
}
}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5597, quirk_nopcipci );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_496, quirk_nopcipci );
static void __devinit quirk_nopciamd(struct pci_dev *dev)
{
@@ -105,9 +109,6 @@ static void __devinit quirk_nopciamd(struct pci_dev *dev)
pci_pci_problems |= PCIAGP_FAIL;
}
}
-
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5597, quirk_nopcipci );
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_496, quirk_nopcipci );
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8151_0, quirk_nopciamd );
/*
@@ -870,7 +871,7 @@ static void __devinit quirk_sb600_sata(struct pci_dev *pdev)
pci_write_config_byte(pdev, 0xa, 6);
pci_write_config_byte(pdev, 0x40, tmp);
- pdev->class = 0x010601;
+ pdev->class = PCI_CLASS_STORAGE_SATA_AHCI;
}
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP600_SATA, quirk_sb600_sata);
@@ -976,52 +977,51 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev)
case 0x1626: /* L3C notebook */
asus_hides_smbus = 1;
}
- if (dev->device == PCI_DEVICE_ID_INTEL_82845G_HB)
+ else if (dev->device == PCI_DEVICE_ID_INTEL_82845G_HB)
switch(dev->subsystem_device) {
case 0x80b1: /* P4GE-V */
case 0x80b2: /* P4PE */
case 0x8093: /* P4B533-V */
asus_hides_smbus = 1;
}
- if (dev->device == PCI_DEVICE_ID_INTEL_82850_HB)
+ else if (dev->device == PCI_DEVICE_ID_INTEL_82850_HB)
switch(dev->subsystem_device) {
case 0x8030: /* P4T533 */
asus_hides_smbus = 1;
}
- if (dev->device == PCI_DEVICE_ID_INTEL_7205_0)
+ else if (dev->device == PCI_DEVICE_ID_INTEL_7205_0)
switch (dev->subsystem_device) {
case 0x8070: /* P4G8X Deluxe */
asus_hides_smbus = 1;
}
- if (dev->device == PCI_DEVICE_ID_INTEL_E7501_MCH)
+ else if (dev->device == PCI_DEVICE_ID_INTEL_E7501_MCH)
switch (dev->subsystem_device) {
case 0x80c9: /* PU-DLS */
asus_hides_smbus = 1;
}
- if (dev->device == PCI_DEVICE_ID_INTEL_82855GM_HB)
+ else if (dev->device == PCI_DEVICE_ID_INTEL_82855GM_HB)
switch (dev->subsystem_device) {
case 0x1751: /* M2N notebook */
case 0x1821: /* M5N notebook */
asus_hides_smbus = 1;
}
- if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB)
+ else if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB)
switch (dev->subsystem_device) {
case 0x184b: /* W1N notebook */
case 0x186a: /* M6Ne notebook */
asus_hides_smbus = 1;
}
- if (dev->device == PCI_DEVICE_ID_INTEL_82865_HB)
+ else if (dev->device == PCI_DEVICE_ID_INTEL_82865_HB)
switch (dev->subsystem_device) {
case 0x80f2: /* P4P800-X */
asus_hides_smbus = 1;
}
- if (dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB) {
+ else if (dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB)
switch (dev->subsystem_device) {
case 0x1882: /* M6V notebook */
case 0x1977: /* A6VA notebook */
asus_hides_smbus = 1;
}
- }
} else if (unlikely(dev->subsystem_vendor == PCI_VENDOR_ID_HP)) {
if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB)
switch(dev->subsystem_device) {
@@ -1029,25 +1029,24 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev)
case 0x0890: /* HP Compaq nc6000 */
asus_hides_smbus = 1;
}
- if (dev->device == PCI_DEVICE_ID_INTEL_82865_HB)
+ else if (dev->device == PCI_DEVICE_ID_INTEL_82865_HB)
switch (dev->subsystem_device) {
case 0x12bc: /* HP D330L */
case 0x12bd: /* HP D530 */
asus_hides_smbus = 1;
}
- if (dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB) {
+ else if (dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB)
switch (dev->subsystem_device) {
case 0x099c: /* HP Compaq nx6110 */
asus_hides_smbus = 1;
}
- }
} else if (unlikely(dev->subsystem_vendor == PCI_VENDOR_ID_TOSHIBA)) {
if (dev->device == PCI_DEVICE_ID_INTEL_82855GM_HB)
switch(dev->subsystem_device) {
case 0x0001: /* Toshiba Satellite A40 */
asus_hides_smbus = 1;
}
- if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB)
+ else if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB)
switch(dev->subsystem_device) {
case 0x0001: /* Toshiba Tecra M2 */
asus_hides_smbus = 1;
@@ -1136,6 +1135,14 @@ static void quirk_sis_96x_smbus(struct pci_dev *dev)
pci_write_config_byte(dev, 0x77, val & ~0x10);
}
}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_961, quirk_sis_96x_smbus );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_962, quirk_sis_96x_smbus );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_963, quirk_sis_96x_smbus );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC, quirk_sis_96x_smbus );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_961, quirk_sis_96x_smbus );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_962, quirk_sis_96x_smbus );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_963, quirk_sis_96x_smbus );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC, quirk_sis_96x_smbus );
/*
* ... This is further complicated by the fact that some SiS96x south
@@ -1145,8 +1152,6 @@ static void quirk_sis_96x_smbus(struct pci_dev *dev)
*
* We can also enable the sis96x bit in the discovery register..
*/
-static int __devinitdata sis_96x_compatible = 0;
-
#define SIS_DETECT_REGISTER 0x40
static void quirk_sis_503(struct pci_dev *dev)
@@ -1162,9 +1167,6 @@ static void quirk_sis_503(struct pci_dev *dev)
return;
}
- /* Make people aware that we changed the config.. */
- printk(KERN_WARNING "Uncovering SIS%x that hid as a SIS503 (compatible=%d)\n", devid, sis_96x_compatible);
-
/*
* Ok, it now shows up as a 96x.. run the 96x quirk by
* hand in case it has already been processed.
@@ -1173,20 +1175,10 @@ static void quirk_sis_503(struct pci_dev *dev)
dev->device = devid;
quirk_sis_96x_smbus(dev);
}
-
-static void __init quirk_sis_96x_compatible(struct pci_dev *dev)
-{
- sis_96x_compatible = 1;
-}
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_645, quirk_sis_96x_compatible );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_646, quirk_sis_96x_compatible );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_648, quirk_sis_96x_compatible );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_650, quirk_sis_96x_compatible );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_651, quirk_sis_96x_compatible );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_735, quirk_sis_96x_compatible );
-
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, quirk_sis_503 );
DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, quirk_sis_503 );
+
+
/*
* On ASUS A8V and A8V Deluxe boards, the onboard AC97 audio controller
* and MC97 modem controller are disabled when a second PCI soundcard is
@@ -1217,21 +1209,8 @@ static void asus_hides_ac97_lpc(struct pci_dev *dev)
}
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, asus_hides_ac97_lpc );
-
-
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_961, quirk_sis_96x_smbus );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_962, quirk_sis_96x_smbus );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_963, quirk_sis_96x_smbus );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC, quirk_sis_96x_smbus );
-
DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, asus_hides_ac97_lpc );
-
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_961, quirk_sis_96x_smbus );
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_962, quirk_sis_96x_smbus );
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_963, quirk_sis_96x_smbus );
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC, quirk_sis_96x_smbus );
-
#if defined(CONFIG_ATA) || defined(CONFIG_ATA_MODULE)
/*
@@ -1276,7 +1255,6 @@ static void quirk_jmicron_dualfn(struct pci_dev *pdev)
break;
}
}
-
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, quirk_jmicron_dualfn);
DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, quirk_jmicron_dualfn);
@@ -1420,6 +1398,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, quirk_intel_ide_co
int pcie_mch_quirk;
+EXPORT_SYMBOL(pcie_mch_quirk);
static void __devinit quirk_pcie_mch(struct pci_dev *pdev)
{
@@ -1481,6 +1460,24 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x2609, quirk_intel_pcie_pm);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x260a, quirk_intel_pcie_pm);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x260b, quirk_intel_pcie_pm);
+/*
+ * Toshiba TC86C001 IDE controller reports the standard 8-byte BAR0 size
+ * but the PIO transfers won't work if BAR0 falls at the odd 8 bytes.
+ * Re-allocate the region if needed...
+ */
+static void __init quirk_tc86c001_ide(struct pci_dev *dev)
+{
+ struct resource *r = &dev->resource[0];
+
+ if (r->start & 0x8) {
+ r->start = 0;
+ r->end = 0xf;
+ }
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TOSHIBA_2,
+ PCI_DEVICE_ID_TOSHIBA_TC86C001_IDE,
+ quirk_tc86c001_ide);
+
static void __devinit quirk_netmos(struct pci_dev *dev)
{
unsigned int num_parallel = (dev->subsystem_device & 0xf0) >> 4;
@@ -1646,6 +1643,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);
/* Enable 1k I/O space granularity on the Intel P64H2 */
static void __devinit quirk_p64h2_1k_io(struct pci_dev *dev)
@@ -1673,6 +1671,31 @@ static void __devinit quirk_p64h2_1k_io(struct pci_dev *dev)
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1460, quirk_p64h2_1k_io);
+/* Fix the IOBL_ADR for 1k I/O space granularity on the Intel P64H2
+ * The IOBL_ADR gets re-written to 4k boundaries in pci_setup_bridge()
+ * in drivers/pci/setup-bus.c
+ */
+static void __devinit quirk_p64h2_1k_io_fix_iobl(struct pci_dev *dev)
+{
+ u16 en1k, iobl_adr, iobl_adr_1k;
+ struct resource *res = dev->resource + PCI_BRIDGE_RESOURCES;
+
+ pci_read_config_word(dev, 0x40, &en1k);
+
+ if (en1k & 0x200) {
+ pci_read_config_word(dev, PCI_IO_BASE, &iobl_adr);
+
+ iobl_adr_1k = iobl_adr | (res->start >> 8) | (res->end & 0xfc00);
+
+ if (iobl_adr != iobl_adr_1k) {
+ printk(KERN_INFO "PCI: Fixing P64H2 IOBL_ADR from 0x%x to 0x%x for 1 KB Granularity\n",
+ iobl_adr,iobl_adr_1k);
+ pci_write_config_word(dev, PCI_IO_BASE, iobl_adr_1k);
+ }
+ }
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1460, quirk_p64h2_1k_io_fix_iobl);
+
/* Under some circumstances, AER is not linked with extended capabilities.
* Force it to be linked by setting the corresponding control bit in the
* config space.
@@ -1695,9 +1718,6 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_PCIE,
quirk_nvidia_ck804_pcie_aer_ext_cap);
#ifdef CONFIG_PCI_MSI
-/* To disable MSI globally */
-int pci_msi_quirk;
-
/* The Serverworks PCI-X chipset does not support MSI. We cannot easily rely
* on setting PCI_BUS_FLAGS_NO_MSI in its bus flags because there are actually
* some other busses controlled by the chipset even if Linux is not aware of it.
@@ -1706,8 +1726,8 @@ int pci_msi_quirk;
*/
static void __init quirk_svw_msi(struct pci_dev *dev)
{
- pci_msi_quirk = 1;
- printk(KERN_WARNING "PCI: MSI quirk detected. pci_msi_quirk set.\n");
+ pci_no_msi();
+ printk(KERN_WARNING "PCI: MSI quirk detected. MSI deactivated.\n");
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_GCNB_LE, quirk_svw_msi);
@@ -1788,8 +1808,3 @@ static void __devinit quirk_nvidia_ck804_msi_ht_cap(struct pci_dev *dev)
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_PCIE,
quirk_nvidia_ck804_msi_ht_cap);
#endif /* CONFIG_PCI_MSI */
-
-EXPORT_SYMBOL(pcie_mch_quirk);
-#ifdef CONFIG_HOTPLUG
-EXPORT_SYMBOL(pci_fixup_device);
-#endif
diff --git a/drivers/pci/search.c b/drivers/pci/search.c
index b2653c4afe9..ff98eaddaa7 100644
--- a/drivers/pci/search.c
+++ b/drivers/pci/search.c
@@ -358,43 +358,6 @@ exit:
}
/**
- * pci_find_device_reverse - 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 in the reverse order of
- * pci_find_device().
- * 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 previous device
- * on the global list.
- */
-struct pci_dev *
-pci_find_device_reverse(unsigned int vendor, unsigned int device, const struct pci_dev *from)
-{
- struct list_head *n;
- struct pci_dev *dev;
-
- WARN_ON(in_interrupt());
- down_read(&pci_bus_sem);
- n = from ? from->global_list.prev : pci_devices.prev;
-
- while (n && (n != &pci_devices)) {
- dev = pci_dev_g(n);
- if ((vendor == PCI_ANY_ID || dev->vendor == vendor) &&
- (device == PCI_ANY_ID || dev->device == device))
- goto exit;
- n = n->prev;
- }
- dev = NULL;
-exit:
- up_read(&pci_bus_sem);
- return dev;
-}
-
-/**
* pci_get_class - begin or continue searching for a PCI device by class
* @class: search for a PCI device with this class designation
* @from: Previous PCI device found in search, or %NULL for new search.
@@ -469,7 +432,6 @@ EXPORT_SYMBOL(pci_dev_present);
EXPORT_SYMBOL(pci_find_present);
EXPORT_SYMBOL(pci_find_device);
-EXPORT_SYMBOL(pci_find_device_reverse);
EXPORT_SYMBOL(pci_find_slot);
/* For boot time work */
EXPORT_SYMBOL(pci_find_bus);
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 89f3036f0de..3554f394881 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -36,13 +36,6 @@
#define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1))
-/*
- * FIXME: IO should be max 256 bytes. However, since we may
- * have a P2P bridge below a cardbus bridge, we need 4K.
- */
-#define CARDBUS_IO_SIZE (256)
-#define CARDBUS_MEM_SIZE (64*1024*1024)
-
static void __devinit
pbus_assign_resources_sorted(struct pci_bus *bus)
{
@@ -415,12 +408,12 @@ pci_bus_size_cardbus(struct pci_bus *bus)
* Reserve some resources for CardBus. We reserve
* a fixed amount of bus space for CardBus bridges.
*/
- b_res[0].start = CARDBUS_IO_SIZE;
- b_res[0].end = b_res[0].start + CARDBUS_IO_SIZE - 1;
+ b_res[0].start = pci_cardbus_io_size;
+ b_res[0].end = b_res[0].start + pci_cardbus_io_size - 1;
b_res[0].flags |= IORESOURCE_IO;
- b_res[1].start = CARDBUS_IO_SIZE;
- b_res[1].end = b_res[1].start + CARDBUS_IO_SIZE - 1;
+ b_res[1].start = pci_cardbus_io_size;
+ b_res[1].end = b_res[1].start + pci_cardbus_io_size - 1;
b_res[1].flags |= IORESOURCE_IO;
/*
@@ -440,16 +433,16 @@ pci_bus_size_cardbus(struct pci_bus *bus)
* twice the size.
*/
if (ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM0) {
- b_res[2].start = CARDBUS_MEM_SIZE;
- b_res[2].end = b_res[2].start + CARDBUS_MEM_SIZE - 1;
+ b_res[2].start = pci_cardbus_mem_size;
+ b_res[2].end = b_res[2].start + pci_cardbus_mem_size - 1;
b_res[2].flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH;
- b_res[3].start = CARDBUS_MEM_SIZE;
- b_res[3].end = b_res[3].start + CARDBUS_MEM_SIZE - 1;
+ b_res[3].start = pci_cardbus_mem_size;
+ b_res[3].end = b_res[3].start + pci_cardbus_mem_size - 1;
b_res[3].flags |= IORESOURCE_MEM;
} else {
- b_res[3].start = CARDBUS_MEM_SIZE * 2;
- b_res[3].end = b_res[3].start + CARDBUS_MEM_SIZE * 2 - 1;
+ b_res[3].start = pci_cardbus_mem_size * 2;
+ b_res[3].end = b_res[3].start + pci_cardbus_mem_size * 2 - 1;
b_res[3].flags |= IORESOURCE_MEM;
}
}
diff --git a/drivers/pci/setup-irq.c b/drivers/pci/setup-irq.c
index a251289c995..568f1877315 100644
--- a/drivers/pci/setup-irq.c
+++ b/drivers/pci/setup-irq.c
@@ -24,7 +24,7 @@ pdev_fixup_irq(struct pci_dev *dev,
int (*map_irq)(struct pci_dev *, u8, u8))
{
u8 pin, slot;
- int irq;
+ int irq = 0;
/* If this device is not on the primary bus, we need to figure out
which interrupt pin it will come in on. We know which slot it
@@ -33,16 +33,18 @@ pdev_fixup_irq(struct pci_dev *dev,
apply the swizzle function. */
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
- /* Cope with 0 and illegal. */
- if (pin == 0 || pin > 4)
+ /* Cope with illegal. */
+ if (pin > 4)
pin = 1;
- /* Follow the chain of bridges, swizzling as we go. */
- slot = (*swizzle)(dev, &pin);
+ if (pin != 0) {
+ /* Follow the chain of bridges, swizzling as we go. */
+ slot = (*swizzle)(dev, &pin);
- irq = (*map_irq)(dev, slot, pin);
- if (irq == -1)
- irq = 0;
+ irq = (*map_irq)(dev, slot, pin);
+ if (irq == -1)
+ irq = 0;
+ }
dev->irq = irq;
pr_debug("PCI: fixup irq: (%s) got %d\n",
diff --git a/drivers/pci/syscall.c b/drivers/pci/syscall.c
index 87fafc08cb9..9d37fec27f2 100644
--- a/drivers/pci/syscall.c
+++ b/drivers/pci/syscall.c
@@ -7,7 +7,6 @@
* magic northbridge registers..
*/
-#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/pci.h>
#include <linux/smp_lock.h>
diff --git a/drivers/pcmcia/at91_cf.c b/drivers/pcmcia/at91_cf.c
index 3334f22a86c..99baabc2359 100644
--- a/drivers/pcmcia/at91_cf.c
+++ b/drivers/pcmcia/at91_cf.c
@@ -11,7 +11,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/platform_device.h>
#include <linux/errno.h>
#include <linux/init.h>
@@ -278,7 +277,7 @@ static int __init at91_cf_probe(struct platform_device *pdev)
board->det_pin, board->irq_pin);
cf->socket.owner = THIS_MODULE;
- cf->socket.dev.dev = &pdev->dev;
+ cf->socket.dev.parent = &pdev->dev;
cf->socket.ops = &at91_cf_ops;
cf->socket.resource_ops = &pccard_static_ops;
cf->socket.features = SS_CAP_PCCARD | SS_CAP_STATIC_MAP
diff --git a/drivers/pcmcia/cardbus.c b/drivers/pcmcia/cardbus.c
index 2d7effe7990..a1bd763b4e3 100644
--- a/drivers/pcmcia/cardbus.c
+++ b/drivers/pcmcia/cardbus.c
@@ -40,8 +40,6 @@
/*====================================================================*/
-#define FIND_FIRST_BIT(n) ((n) - ((n) & ((n)-1)))
-
/* Offsets in the Expansion ROM Image Header */
#define ROM_SIGNATURE 0x0000 /* 2 bytes */
#define ROM_DATA_PTR 0x0018 /* 2 bytes */
diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c
index 912c03e5eb0..d154dee76e7 100644
--- a/drivers/pcmcia/cistpl.c
+++ b/drivers/pcmcia/cistpl.c
@@ -21,7 +21,6 @@
#include <linux/timer.h>
#include <linux/slab.h>
#include <linux/mm.h>
-#include <linux/sched.h>
#include <linux/pci.h>
#include <linux/ioport.h>
#include <asm/io.h>
diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c
index 606a4674033..ac004248324 100644
--- a/drivers/pcmcia/cs.c
+++ b/drivers/pcmcia/cs.c
@@ -110,7 +110,7 @@ int pcmcia_socket_dev_suspend(struct device *dev, pm_message_t state)
down_read(&pcmcia_socket_list_rwsem);
list_for_each_entry(socket, &pcmcia_socket_list, socket_list) {
- if (socket->dev.dev != dev)
+ if (socket->dev.parent != dev)
continue;
mutex_lock(&socket->skt_mutex);
socket_suspend(socket);
@@ -128,7 +128,7 @@ int pcmcia_socket_dev_resume(struct device *dev)
down_read(&pcmcia_socket_list_rwsem);
list_for_each_entry(socket, &pcmcia_socket_list, socket_list) {
- if (socket->dev.dev != dev)
+ if (socket->dev.parent != dev)
continue;
mutex_lock(&socket->skt_mutex);
socket_resume(socket);
@@ -143,12 +143,12 @@ EXPORT_SYMBOL(pcmcia_socket_dev_resume);
struct pcmcia_socket * pcmcia_get_socket(struct pcmcia_socket *skt)
{
- struct class_device *cl_dev = class_device_get(&skt->dev);
- if (!cl_dev)
+ struct device *dev = get_device(&skt->dev);
+ if (!dev)
return NULL;
- skt = class_get_devdata(cl_dev);
+ skt = dev_get_drvdata(dev);
if (!try_module_get(skt->owner)) {
- class_device_put(&skt->dev);
+ put_device(&skt->dev);
return NULL;
}
return (skt);
@@ -159,14 +159,14 @@ EXPORT_SYMBOL(pcmcia_get_socket);
void pcmcia_put_socket(struct pcmcia_socket *skt)
{
module_put(skt->owner);
- class_device_put(&skt->dev);
+ put_device(&skt->dev);
}
EXPORT_SYMBOL(pcmcia_put_socket);
-static void pcmcia_release_socket(struct class_device *class_dev)
+static void pcmcia_release_socket(struct device *dev)
{
- struct pcmcia_socket *socket = class_get_devdata(class_dev);
+ struct pcmcia_socket *socket = dev_get_drvdata(dev);
complete(&socket->socket_released);
}
@@ -181,7 +181,7 @@ int pcmcia_register_socket(struct pcmcia_socket *socket)
struct task_struct *tsk;
int ret;
- if (!socket || !socket->ops || !socket->dev.dev || !socket->resource_ops)
+ if (!socket || !socket->ops || !socket->dev.parent || !socket->resource_ops)
return -EINVAL;
cs_dbg(socket, 0, "pcmcia_register_socket(0x%p)\n", socket->ops);
@@ -226,9 +226,9 @@ int pcmcia_register_socket(struct pcmcia_socket *socket)
#endif
/* set proper values in socket->dev */
- socket->dev.class_data = socket;
+ dev_set_drvdata(&socket->dev, socket);
socket->dev.class = &pcmcia_socket_class;
- snprintf(socket->dev.class_id, BUS_ID_SIZE, "pcmcia_socket%u", socket->sock);
+ snprintf(socket->dev.bus_id, BUS_ID_SIZE, "pcmcia_socket%u", socket->sock);
/* base address = 0, map = 0 */
socket->cis_mem.flags = 0;
@@ -640,7 +640,7 @@ static int pccardd(void *__skt)
skt->ops->set_socket(skt, &skt->socket);
/* register with the device core */
- ret = class_device_register(&skt->dev);
+ ret = device_register(&skt->dev);
if (ret) {
printk(KERN_WARNING "PCMCIA: unable to register socket 0x%p\n",
skt);
@@ -689,7 +689,7 @@ static int pccardd(void *__skt)
remove_wait_queue(&skt->thread_wait, &wait);
/* remove from the device core */
- class_device_unregister(&skt->dev);
+ device_unregister(&skt->dev);
return 0;
}
@@ -904,7 +904,7 @@ int pcmcia_insert_card(struct pcmcia_socket *skt)
EXPORT_SYMBOL(pcmcia_insert_card);
-static int pcmcia_socket_uevent(struct class_device *dev, char **envp,
+static int pcmcia_socket_uevent(struct device *dev, char **envp,
int num_envp, char *buffer, int buffer_size)
{
struct pcmcia_socket *s = container_of(dev, struct pcmcia_socket, dev);
@@ -930,8 +930,8 @@ static void pcmcia_release_socket_class(struct class *data)
struct class pcmcia_socket_class = {
.name = "pcmcia_socket",
- .uevent = pcmcia_socket_uevent,
- .release = pcmcia_release_socket,
+ .dev_uevent = pcmcia_socket_uevent,
+ .dev_release = pcmcia_release_socket,
.class_release = pcmcia_release_socket_class,
};
EXPORT_SYMBOL(pcmcia_socket_class);
diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h
index f573ea04db6..9fa207e3c7b 100644
--- a/drivers/pcmcia/cs_internal.h
+++ b/drivers/pcmcia/cs_internal.h
@@ -142,7 +142,7 @@ struct pcmcia_callback{
int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c);
-#define cs_socket_name(skt) ((skt)->dev.class_id)
+#define cs_socket_name(skt) ((skt)->dev.bus_id)
#ifdef DEBUG
extern int cs_debug_level(int);
@@ -158,6 +158,6 @@ extern int cs_debug_level(int);
#endif
#define cs_err(skt, fmt, arg...) \
- printk(KERN_ERR "cs: %s: " fmt, (skt)->dev.class_id , ## arg)
+ printk(KERN_ERR "cs: %s: " fmt, (skt)->dev.bus_id , ## arg)
#endif /* _LINUX_CS_INTERNAL_H */
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index 7355eb455a8..18e111e1233 100644
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -572,7 +572,7 @@ struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int f
p_dev->func = function;
p_dev->dev.bus = &pcmcia_bus_type;
- p_dev->dev.parent = s->dev.dev;
+ p_dev->dev.parent = s->dev.parent;
p_dev->dev.release = pcmcia_release_dev;
bus_id_len = sprintf (p_dev->dev.bus_id, "%d.%d", p_dev->socket->sock, p_dev->device_no);
@@ -1328,10 +1328,10 @@ static struct pcmcia_callback pcmcia_bus_callback = {
.resume = pcmcia_bus_resume,
};
-static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev,
+static int __devinit pcmcia_bus_add_socket(struct device *dev,
struct class_interface *class_intf)
{
- struct pcmcia_socket *socket = class_get_devdata(class_dev);
+ struct pcmcia_socket *socket = dev_get_drvdata(dev);
int ret;
socket = pcmcia_get_socket(socket);
@@ -1364,10 +1364,10 @@ static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev,
return 0;
}
-static void pcmcia_bus_remove_socket(struct class_device *class_dev,
+static void pcmcia_bus_remove_socket(struct device *dev,
struct class_interface *class_intf)
{
- struct pcmcia_socket *socket = class_get_devdata(class_dev);
+ struct pcmcia_socket *socket = dev_get_drvdata(dev);
if (!socket)
return;
@@ -1389,8 +1389,8 @@ static void pcmcia_bus_remove_socket(struct class_device *class_dev,
/* the pcmcia_bus_interface is used to handle pcmcia socket devices */
static struct class_interface pcmcia_bus_interface = {
.class = &pcmcia_socket_class,
- .add = &pcmcia_bus_add_socket,
- .remove = &pcmcia_bus_remove_socket,
+ .add_dev = &pcmcia_bus_add_socket,
+ .remove_dev = &pcmcia_bus_remove_socket,
};
diff --git a/drivers/pcmcia/hd64465_ss.c b/drivers/pcmcia/hd64465_ss.c
index caca0dc9d30..f2e810f53c8 100644
--- a/drivers/pcmcia/hd64465_ss.c
+++ b/drivers/pcmcia/hd64465_ss.c
@@ -907,7 +907,7 @@ static int __init init_hs(void)
for (i=0; i<HS_MAX_SOCKETS; i++) {
unsigned int ret;
- hs_sockets[i].socket.dev.dev = &hd64465_device.dev;
+ hs_sockets[i].socket.dev.parent = &hd64465_device.dev;
hs_sockets[i].number = i;
ret = pcmcia_register_socket(&hs_sockets[i].socket);
if (ret && i)
diff --git a/drivers/pcmcia/i82092.c b/drivers/pcmcia/i82092.c
index c2ea07aa7a1..df21e2d16f8 100644
--- a/drivers/pcmcia/i82092.c
+++ b/drivers/pcmcia/i82092.c
@@ -161,7 +161,7 @@ static int __devinit i82092aa_pci_probe(struct pci_dev *dev, const struct pci_de
pci_set_drvdata(dev, &sockets[i].socket);
for (i = 0; i<socket_count; i++) {
- sockets[i].socket.dev.dev = &dev->dev;
+ sockets[i].socket.dev.parent = &dev->dev;
sockets[i].socket.ops = &i82092aa_operations;
sockets[i].socket.resource_ops = &pccard_nonstatic_ops;
ret = pcmcia_register_socket(&sockets[i].socket);
diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c
index ea74f98a735..71b33707117 100644
--- a/drivers/pcmcia/i82365.c
+++ b/drivers/pcmcia/i82365.c
@@ -40,7 +40,6 @@
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/timer.h>
-#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/delay.h>
@@ -1298,7 +1297,7 @@ static int __init init_i82365(void)
/* register sockets with the pcmcia core */
for (i = 0; i < sockets; i++) {
- socket[i].socket.dev.dev = &i82365_device->dev;
+ socket[i].socket.dev.parent = &i82365_device->dev;
socket[i].socket.ops = &pcic_operations;
socket[i].socket.resource_ops = &pccard_nonstatic_ops;
socket[i].socket.owner = THIS_MODULE;
diff --git a/drivers/pcmcia/m32r_cfc.c b/drivers/pcmcia/m32r_cfc.c
index 3c22ac4625c..91da15b5a81 100644
--- a/drivers/pcmcia/m32r_cfc.c
+++ b/drivers/pcmcia/m32r_cfc.c
@@ -16,7 +16,6 @@
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/timer.h>
-#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/delay.h>
@@ -761,7 +760,7 @@ static int __init init_m32r_pcc(void)
/* Set up interrupt handler(s) */
for (i = 0 ; i < pcc_sockets ; i++) {
- socket[i].socket.dev.dev = &pcc_device.dev;
+ 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.owner = THIS_MODULE;
diff --git a/drivers/pcmcia/m32r_pcc.c b/drivers/pcmcia/m32r_pcc.c
index bbf025874d0..67d28ee80f2 100644
--- a/drivers/pcmcia/m32r_pcc.c
+++ b/drivers/pcmcia/m32r_pcc.c
@@ -16,7 +16,6 @@
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/timer.h>
-#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/delay.h>
@@ -722,7 +721,7 @@ static int __init init_m32r_pcc(void)
/* Set up interrupt handler(s) */
for (i = 0 ; i < pcc_sockets ; i++) {
- socket[i].socket.dev.dev = &pcc_device.dev;
+ socket[i].socket.dev.parent = &pcc_device.dev;
socket[i].socket.ops = &pcc_operations;
socket[i].socket.resource_ops = &pccard_static_ops;
socket[i].socket.owner = THIS_MODULE;
diff --git a/drivers/pcmcia/m8xx_pcmcia.c b/drivers/pcmcia/m8xx_pcmcia.c
index 3b72be88040..9721ed7bf50 100644
--- a/drivers/pcmcia/m8xx_pcmcia.c
+++ b/drivers/pcmcia/m8xx_pcmcia.c
@@ -46,7 +46,6 @@
#include <linux/kernel.h>
#include <linux/errno.h>
-#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/timer.h>
#include <linux/ioport.h>
@@ -1322,7 +1321,7 @@ static int __init m8xx_init(void)
socket[i].socket.ops = &m8xx_services;
socket[i].socket.resource_ops = &pccard_iodyn_ops;
socket[i].socket.cb_dev = NULL;
- socket[i].socket.dev.dev = &m8xx_device.dev;
+ socket[i].socket.dev.parent = &m8xx_device.dev;
}
for (i = 0; i < PCMCIA_SOCKETS_NO; i++)
diff --git a/drivers/pcmcia/omap_cf.c b/drivers/pcmcia/omap_cf.c
index e65a6b8188f..d77f75129f8 100644
--- a/drivers/pcmcia/omap_cf.c
+++ b/drivers/pcmcia/omap_cf.c
@@ -11,7 +11,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/platform_device.h>
#include <linux/errno.h>
#include <linux/init.h>
@@ -292,7 +291,7 @@ static int __devinit omap_cf_probe(struct device *dev)
omap_cf_present() ? "present" : "(not present)");
cf->socket.owner = THIS_MODULE;
- cf->socket.dev.dev = dev;
+ cf->socket.dev.parent = dev;
cf->socket.ops = &omap_cf_ops;
cf->socket.resource_ops = &pccard_static_ops;
cf->socket.features = SS_CAP_PCCARD | SS_CAP_STATIC_MAP
diff --git a/drivers/pcmcia/pcmcia_ioctl.c b/drivers/pcmcia/pcmcia_ioctl.c
index 327372b7a54..27523c5f4da 100644
--- a/drivers/pcmcia/pcmcia_ioctl.c
+++ b/drivers/pcmcia/pcmcia_ioctl.c
@@ -59,7 +59,6 @@ typedef struct user_info_t {
#ifdef DEBUG
extern int ds_pc_debug;
-#define cs_socket_name(skt) ((skt)->dev.class_id)
#define ds_dbg(lvl, fmt, arg...) do { \
if (ds_pc_debug >= lvl) \
@@ -766,7 +765,7 @@ free_out:
/*====================================================================*/
-static struct file_operations ds_fops = {
+static const struct file_operations ds_fops = {
.owner = THIS_MODULE,
.open = ds_open,
.release = ds_release,
diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c
index b9201c2ec38..0ce39de834c 100644
--- a/drivers/pcmcia/pcmcia_resource.c
+++ b/drivers/pcmcia/pcmcia_resource.c
@@ -48,7 +48,6 @@ static u8 pcmcia_used_irq[NR_IRQS];
#ifdef DEBUG
extern int ds_pc_debug;
-#define cs_socket_name(skt) ((skt)->dev.class_id)
#define ds_dbg(skt, lvl, fmt, arg...) do { \
if (ds_pc_debug >= lvl) \
diff --git a/drivers/pcmcia/pd6729.c b/drivers/pcmcia/pd6729.c
index 360c2489654..dd0ddf19ee5 100644
--- a/drivers/pcmcia/pd6729.c
+++ b/drivers/pcmcia/pd6729.c
@@ -682,7 +682,7 @@ static int __devinit pd6729_pci_probe(struct pci_dev *dev,
socket[i].socket.ops = &pd6729_operations;
socket[i].socket.resource_ops = &pccard_nonstatic_ops;
- socket[i].socket.dev.dev = &dev->dev;
+ socket[i].socket.dev.parent = &dev->dev;
socket[i].socket.driver_data = &socket[i];
}
diff --git a/drivers/pcmcia/pxa2xx_lubbock.c b/drivers/pcmcia/pxa2xx_lubbock.c
index a92f11143c4..5e9b9a3fd02 100644
--- a/drivers/pcmcia/pxa2xx_lubbock.c
+++ b/drivers/pcmcia/pxa2xx_lubbock.c
@@ -16,7 +16,6 @@
*/
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/init.h>
diff --git a/drivers/pcmcia/rsrc_mgr.c b/drivers/pcmcia/rsrc_mgr.c
index 81dfc2cac2b..ce2226273aa 100644
--- a/drivers/pcmcia/rsrc_mgr.c
+++ b/drivers/pcmcia/rsrc_mgr.c
@@ -232,7 +232,7 @@ static struct resource *iodyn_find_io_region(unsigned long base, int num,
unsigned long align, struct pcmcia_socket *s)
{
struct resource *res = make_resource(0, num, IORESOURCE_IO,
- s->dev.class_id);
+ s->dev.bus_id);
struct pcmcia_align_data data;
unsigned long min = base;
int ret;
diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c
index c3176b16b7b..bfcaad6021c 100644
--- a/drivers/pcmcia/rsrc_nonstatic.c
+++ b/drivers/pcmcia/rsrc_nonstatic.c
@@ -616,7 +616,7 @@ static int nonstatic_adjust_io_region(struct resource *res, unsigned long r_star
static struct resource *nonstatic_find_io_region(unsigned long base, int num,
unsigned long align, struct pcmcia_socket *s)
{
- struct resource *res = make_resource(0, num, IORESOURCE_IO, s->dev.class_id);
+ struct resource *res = make_resource(0, num, IORESOURCE_IO, s->dev.bus_id);
struct socket_data *s_data = s->resource_data;
struct pcmcia_align_data data;
unsigned long min = base;
@@ -650,7 +650,7 @@ static struct resource *nonstatic_find_io_region(unsigned long base, int num,
static struct resource * nonstatic_find_mem_region(u_long base, u_long num,
u_long align, int low, struct pcmcia_socket *s)
{
- struct resource *res = make_resource(0, num, IORESOURCE_MEM, s->dev.class_id);
+ struct resource *res = make_resource(0, num, IORESOURCE_MEM, s->dev.bus_id);
struct socket_data *s_data = s->resource_data;
struct pcmcia_align_data data;
unsigned long min, max;
@@ -897,9 +897,10 @@ EXPORT_SYMBOL(pccard_nonstatic_ops);
/* sysfs interface to the resource database */
-static ssize_t show_io_db(struct class_device *class_dev, char *buf)
+static ssize_t show_io_db(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- struct pcmcia_socket *s = class_get_devdata(class_dev);
+ struct pcmcia_socket *s = dev_get_drvdata(dev);
struct socket_data *data;
struct resource_map *p;
ssize_t ret = 0;
@@ -920,9 +921,11 @@ static ssize_t show_io_db(struct class_device *class_dev, char *buf)
return (ret);
}
-static ssize_t store_io_db(struct class_device *class_dev, const char *buf, size_t count)
+static ssize_t store_io_db(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
- struct pcmcia_socket *s = class_get_devdata(class_dev);
+ struct pcmcia_socket *s = dev_get_drvdata(dev);
unsigned long start_addr, end_addr;
unsigned int add = ADD_MANAGED_RESOURCE;
ssize_t ret = 0;
@@ -947,11 +950,12 @@ static ssize_t store_io_db(struct class_device *class_dev, const char *buf, size
return ret ? ret : count;
}
-static CLASS_DEVICE_ATTR(available_resources_io, 0600, show_io_db, store_io_db);
+static DEVICE_ATTR(available_resources_io, 0600, show_io_db, store_io_db);
-static ssize_t show_mem_db(struct class_device *class_dev, char *buf)
+static ssize_t show_mem_db(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- struct pcmcia_socket *s = class_get_devdata(class_dev);
+ struct pcmcia_socket *s = dev_get_drvdata(dev);
struct socket_data *data;
struct resource_map *p;
ssize_t ret = 0;
@@ -972,9 +976,11 @@ static ssize_t show_mem_db(struct class_device *class_dev, char *buf)
return (ret);
}
-static ssize_t store_mem_db(struct class_device *class_dev, const char *buf, size_t count)
+static ssize_t store_mem_db(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
- struct pcmcia_socket *s = class_get_devdata(class_dev);
+ struct pcmcia_socket *s = dev_get_drvdata(dev);
unsigned long start_addr, end_addr;
unsigned int add = ADD_MANAGED_RESOURCE;
ssize_t ret = 0;
@@ -999,25 +1005,25 @@ static ssize_t store_mem_db(struct class_device *class_dev, const char *buf, siz
return ret ? ret : count;
}
-static CLASS_DEVICE_ATTR(available_resources_mem, 0600, show_mem_db, store_mem_db);
+static DEVICE_ATTR(available_resources_mem, 0600, show_mem_db, store_mem_db);
-static struct class_device_attribute *pccard_rsrc_attributes[] = {
- &class_device_attr_available_resources_io,
- &class_device_attr_available_resources_mem,
+static struct device_attribute *pccard_rsrc_attributes[] = {
+ &dev_attr_available_resources_io,
+ &dev_attr_available_resources_mem,
NULL,
};
-static int __devinit pccard_sysfs_add_rsrc(struct class_device *class_dev,
+static int __devinit pccard_sysfs_add_rsrc(struct device *dev,
struct class_interface *class_intf)
{
- struct pcmcia_socket *s = class_get_devdata(class_dev);
- struct class_device_attribute **attr;
+ struct pcmcia_socket *s = dev_get_drvdata(dev);
+ struct device_attribute **attr;
int ret = 0;
if (s->resource_ops != &pccard_nonstatic_ops)
return 0;
for (attr = pccard_rsrc_attributes; *attr; attr++) {
- ret = class_device_create_file(class_dev, *attr);
+ ret = device_create_file(dev, *attr);
if (ret)
break;
}
@@ -1025,23 +1031,23 @@ static int __devinit pccard_sysfs_add_rsrc(struct class_device *class_dev,
return ret;
}
-static void __devexit pccard_sysfs_remove_rsrc(struct class_device *class_dev,
+static void __devexit pccard_sysfs_remove_rsrc(struct device *dev,
struct class_interface *class_intf)
{
- struct pcmcia_socket *s = class_get_devdata(class_dev);
- struct class_device_attribute **attr;
+ struct pcmcia_socket *s = dev_get_drvdata(dev);
+ struct device_attribute **attr;
if (s->resource_ops != &pccard_nonstatic_ops)
return;
for (attr = pccard_rsrc_attributes; *attr; attr++)
- class_device_remove_file(class_dev, *attr);
+ device_remove_file(dev, *attr);
}
static struct class_interface pccard_rsrc_interface = {
.class = &pcmcia_socket_class,
- .add = &pccard_sysfs_add_rsrc,
- .remove = __devexit_p(&pccard_sysfs_remove_rsrc),
+ .add_dev = &pccard_sysfs_add_rsrc,
+ .remove_dev = __devexit_p(&pccard_sysfs_remove_rsrc),
};
static int __init nonstatic_sysfs_init(void)
diff --git a/drivers/pcmcia/sa1100_badge4.c b/drivers/pcmcia/sa1100_badge4.c
index 19b1e127622..62bfc7566ec 100644
--- a/drivers/pcmcia/sa1100_badge4.c
+++ b/drivers/pcmcia/sa1100_badge4.c
@@ -14,7 +14,6 @@
*/
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/init.h>
diff --git a/drivers/pcmcia/sa1100_cerf.c b/drivers/pcmcia/sa1100_cerf.c
index eb89928f233..549a1529fe3 100644
--- a/drivers/pcmcia/sa1100_cerf.c
+++ b/drivers/pcmcia/sa1100_cerf.c
@@ -7,7 +7,6 @@
*/
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/delay.h>
diff --git a/drivers/pcmcia/sa1100_h3600.c b/drivers/pcmcia/sa1100_h3600.c
index 64fd5e37f2d..e5491879acd 100644
--- a/drivers/pcmcia/sa1100_h3600.c
+++ b/drivers/pcmcia/sa1100_h3600.c
@@ -6,7 +6,6 @@
*/
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/init.h>
diff --git a/drivers/pcmcia/sa1100_jornada720.c b/drivers/pcmcia/sa1100_jornada720.c
index 7a87298bae9..af485ae3860 100644
--- a/drivers/pcmcia/sa1100_jornada720.c
+++ b/drivers/pcmcia/sa1100_jornada720.c
@@ -6,7 +6,6 @@
*/
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/init.h>
diff --git a/drivers/pcmcia/sa1100_neponset.c b/drivers/pcmcia/sa1100_neponset.c
index 5e34b3e8e5d..5bc9e9532b9 100644
--- a/drivers/pcmcia/sa1100_neponset.c
+++ b/drivers/pcmcia/sa1100_neponset.c
@@ -5,7 +5,6 @@
*/
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/init.h>
diff --git a/drivers/pcmcia/sa1100_shannon.c b/drivers/pcmcia/sa1100_shannon.c
index 7bc9e59c761..9456f5478d0 100644
--- a/drivers/pcmcia/sa1100_shannon.c
+++ b/drivers/pcmcia/sa1100_shannon.c
@@ -6,7 +6,6 @@
*/
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/device.h>
#include <linux/init.h>
diff --git a/drivers/pcmcia/sa1100_simpad.c b/drivers/pcmcia/sa1100_simpad.c
index c2ecf1185e9..04d6f7f75f7 100644
--- a/drivers/pcmcia/sa1100_simpad.c
+++ b/drivers/pcmcia/sa1100_simpad.c
@@ -6,7 +6,6 @@
*/
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/device.h>
#include <linux/init.h>
diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c
index e433704e026..aa7779d8975 100644
--- a/drivers/pcmcia/soc_common.c
+++ b/drivers/pcmcia/soc_common.c
@@ -478,10 +478,10 @@ dump_bits(char **p, const char *prefix, unsigned int val, struct bittbl *bits, i
*
* Returns: the number of characters added to the buffer
*/
-static ssize_t show_status(struct class_device *class_dev, char *buf)
+static ssize_t show_status(struct device *dev, struct device_attribute *attr, char *buf)
{
struct soc_pcmcia_socket *skt =
- container_of(class_dev, struct soc_pcmcia_socket, socket.dev);
+ container_of(dev, struct soc_pcmcia_socket, socket.dev);
char *p = buf;
p+=sprintf(p, "slot : %d\n", skt->nr);
@@ -501,7 +501,7 @@ static ssize_t show_status(struct class_device *class_dev, char *buf)
return p-buf;
}
-static CLASS_DEVICE_ATTR(status, S_IRUGO, show_status, NULL);
+static DEVICE_ATTR(status, S_IRUGO, show_status, NULL);
static struct pccard_operations soc_common_pcmcia_operations = {
@@ -660,7 +660,7 @@ int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops
skt->socket.ops = &soc_common_pcmcia_operations;
skt->socket.owner = ops->owner;
- skt->socket.dev.dev = dev;
+ skt->socket.dev.parent = dev;
init_timer(&skt->poll_timer);
skt->poll_timer.function = soc_common_pcmcia_poll_event;
@@ -747,7 +747,7 @@ int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops
add_timer(&skt->poll_timer);
- class_device_create_file(&skt->socket.dev, &class_device_attr_status);
+ device_create_file(&skt->socket.dev, &dev_attr_status);
}
dev_set_drvdata(dev, sinfo);
diff --git a/drivers/pcmcia/socket_sysfs.c b/drivers/pcmcia/socket_sysfs.c
index b005602d6b5..ea5765c3bdc 100644
--- a/drivers/pcmcia/socket_sysfs.c
+++ b/drivers/pcmcia/socket_sysfs.c
@@ -40,7 +40,8 @@
#define to_socket(_dev) container_of(_dev, struct pcmcia_socket, dev)
-static ssize_t pccard_show_type(struct class_device *dev, char *buf)
+static ssize_t pccard_show_type(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct pcmcia_socket *s = to_socket(dev);
@@ -50,9 +51,10 @@ static ssize_t pccard_show_type(struct class_device *dev, char *buf)
return sprintf(buf, "32-bit\n");
return sprintf(buf, "16-bit\n");
}
-static CLASS_DEVICE_ATTR(card_type, 0444, pccard_show_type, NULL);
+static DEVICE_ATTR(card_type, 0444, pccard_show_type, NULL);
-static ssize_t pccard_show_voltage(struct class_device *dev, char *buf)
+static ssize_t pccard_show_voltage(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct pcmcia_socket *s = to_socket(dev);
@@ -63,28 +65,31 @@ static ssize_t pccard_show_voltage(struct class_device *dev, char *buf)
s->socket.Vcc % 10);
return sprintf(buf, "X.XV\n");
}
-static CLASS_DEVICE_ATTR(card_voltage, 0444, pccard_show_voltage, NULL);
+static DEVICE_ATTR(card_voltage, 0444, pccard_show_voltage, NULL);
-static ssize_t pccard_show_vpp(struct class_device *dev, char *buf)
+static ssize_t pccard_show_vpp(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct pcmcia_socket *s = to_socket(dev);
if (!(s->state & SOCKET_PRESENT))
return -ENODEV;
return sprintf(buf, "%d.%dV\n", s->socket.Vpp / 10, s->socket.Vpp % 10);
}
-static CLASS_DEVICE_ATTR(card_vpp, 0444, pccard_show_vpp, NULL);
+static DEVICE_ATTR(card_vpp, 0444, pccard_show_vpp, NULL);
-static ssize_t pccard_show_vcc(struct class_device *dev, char *buf)
+static ssize_t pccard_show_vcc(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct pcmcia_socket *s = to_socket(dev);
if (!(s->state & SOCKET_PRESENT))
return -ENODEV;
return sprintf(buf, "%d.%dV\n", s->socket.Vcc / 10, s->socket.Vcc % 10);
}
-static CLASS_DEVICE_ATTR(card_vcc, 0444, pccard_show_vcc, NULL);
+static DEVICE_ATTR(card_vcc, 0444, pccard_show_vcc, NULL);
-static ssize_t pccard_store_insert(struct class_device *dev, const char *buf, size_t count)
+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);
@@ -96,16 +101,20 @@ static ssize_t pccard_store_insert(struct class_device *dev, const char *buf, si
return ret ? ret : count;
}
-static CLASS_DEVICE_ATTR(card_insert, 0200, NULL, pccard_store_insert);
+static DEVICE_ATTR(card_insert, 0200, NULL, pccard_store_insert);
-static ssize_t pccard_show_card_pm_state(struct class_device *dev, char *buf)
+static ssize_t pccard_show_card_pm_state(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
struct pcmcia_socket *s = to_socket(dev);
return sprintf(buf, "%s\n", s->state & SOCKET_SUSPEND ? "off" : "on");
}
-static ssize_t pccard_store_card_pm_state(struct class_device *dev, const char *buf, size_t count)
+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);
@@ -120,9 +129,11 @@ static ssize_t pccard_store_card_pm_state(struct class_device *dev, const char *
return ret ? -ENODEV : count;
}
-static CLASS_DEVICE_ATTR(card_pm_state, 0644, pccard_show_card_pm_state, pccard_store_card_pm_state);
+static DEVICE_ATTR(card_pm_state, 0644, pccard_show_card_pm_state, pccard_store_card_pm_state);
-static ssize_t pccard_store_eject(struct class_device *dev, const char *buf, size_t count)
+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);
@@ -134,16 +145,20 @@ static ssize_t pccard_store_eject(struct class_device *dev, const char *buf, siz
return ret ? ret : count;
}
-static CLASS_DEVICE_ATTR(card_eject, 0200, NULL, pccard_store_eject);
+static DEVICE_ATTR(card_eject, 0200, NULL, pccard_store_eject);
-static ssize_t pccard_show_irq_mask(struct class_device *dev, char *buf)
+static ssize_t pccard_show_irq_mask(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
struct pcmcia_socket *s = to_socket(dev);
return sprintf(buf, "0x%04x\n", s->irq_mask);
}
-static ssize_t pccard_store_irq_mask(struct class_device *dev, const char *buf, size_t count)
+static ssize_t pccard_store_irq_mask(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
ssize_t ret;
struct pcmcia_socket *s = to_socket(dev);
@@ -161,16 +176,19 @@ static ssize_t pccard_store_irq_mask(struct class_device *dev, const char *buf,
return ret ? ret : count;
}
-static CLASS_DEVICE_ATTR(card_irq_mask, 0600, pccard_show_irq_mask, pccard_store_irq_mask);
+static DEVICE_ATTR(card_irq_mask, 0600, pccard_show_irq_mask, pccard_store_irq_mask);
-static ssize_t pccard_show_resource(struct class_device *dev, char *buf)
+static ssize_t pccard_show_resource(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct pcmcia_socket *s = to_socket(dev);
return sprintf(buf, "%s\n", s->resource_setup_done ? "yes" : "no");
}
-static ssize_t pccard_store_resource(struct class_device *dev, const char *buf, size_t count)
+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);
@@ -196,7 +214,7 @@ static ssize_t pccard_store_resource(struct class_device *dev, const char *buf,
return count;
}
-static CLASS_DEVICE_ATTR(available_resources_setup_done, 0600, pccard_show_resource, pccard_store_resource);
+static DEVICE_ATTR(available_resources_setup_done, 0600, pccard_show_resource, pccard_store_resource);
static ssize_t pccard_extract_cis(struct pcmcia_socket *s, char *buf, loff_t off, size_t count)
@@ -279,7 +297,7 @@ static ssize_t pccard_show_cis(struct kobject *kobj, char *buf, loff_t off, size
if (off + count > size)
count = size - off;
- s = to_socket(container_of(kobj, struct class_device, kobj));
+ s = to_socket(container_of(kobj, struct device, kobj));
if (!(s->state & SOCKET_PRESENT))
return -ENODEV;
@@ -296,7 +314,7 @@ static ssize_t pccard_show_cis(struct kobject *kobj, char *buf, loff_t off, size
static ssize_t pccard_store_cis(struct kobject *kobj, char *buf, loff_t off, size_t count)
{
- struct pcmcia_socket *s = to_socket(container_of(kobj, struct class_device, kobj));
+ struct pcmcia_socket *s = to_socket(container_of(kobj, struct device, kobj));
cisdump_t *cis;
int error;
@@ -335,16 +353,16 @@ static ssize_t pccard_store_cis(struct kobject *kobj, char *buf, loff_t off, siz
}
-static struct class_device_attribute *pccard_socket_attributes[] = {
- &class_device_attr_card_type,
- &class_device_attr_card_voltage,
- &class_device_attr_card_vpp,
- &class_device_attr_card_vcc,
- &class_device_attr_card_insert,
- &class_device_attr_card_pm_state,
- &class_device_attr_card_eject,
- &class_device_attr_card_irq_mask,
- &class_device_attr_available_resources_setup_done,
+static struct device_attribute *pccard_socket_attributes[] = {
+ &dev_attr_card_type,
+ &dev_attr_card_voltage,
+ &dev_attr_card_vpp,
+ &dev_attr_card_vcc,
+ &dev_attr_card_insert,
+ &dev_attr_card_pm_state,
+ &dev_attr_card_eject,
+ &dev_attr_card_irq_mask,
+ &dev_attr_available_resources_setup_done,
NULL,
};
@@ -355,35 +373,35 @@ static struct bin_attribute pccard_cis_attr = {
.write = pccard_store_cis,
};
-static int __devinit pccard_sysfs_add_socket(struct class_device *class_dev,
+static int __devinit pccard_sysfs_add_socket(struct device *dev,
struct class_interface *class_intf)
{
- struct class_device_attribute **attr;
+ struct device_attribute **attr;
int ret = 0;
for (attr = pccard_socket_attributes; *attr; attr++) {
- ret = class_device_create_file(class_dev, *attr);
+ ret = device_create_file(dev, *attr);
if (ret)
break;
}
if (!ret)
- ret = sysfs_create_bin_file(&class_dev->kobj, &pccard_cis_attr);
+ ret = sysfs_create_bin_file(&dev->kobj, &pccard_cis_attr);
return ret;
}
-static void __devexit pccard_sysfs_remove_socket(struct class_device *class_dev,
+static void __devexit pccard_sysfs_remove_socket(struct device *dev,
struct class_interface *class_intf)
{
- struct class_device_attribute **attr;
+ struct device_attribute **attr;
- sysfs_remove_bin_file(&class_dev->kobj, &pccard_cis_attr);
+ sysfs_remove_bin_file(&dev->kobj, &pccard_cis_attr);
for (attr = pccard_socket_attributes; *attr; attr++)
- class_device_remove_file(class_dev, *attr);
+ device_remove_file(dev, *attr);
}
struct class_interface pccard_sysfs_interface = {
.class = &pcmcia_socket_class,
- .add = &pccard_sysfs_add_socket,
- .remove = __devexit_p(&pccard_sysfs_remove_socket),
+ .add_dev = &pccard_sysfs_add_socket,
+ .remove_dev = __devexit_p(&pccard_sysfs_remove_socket),
};
diff --git a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c
index 2d2f415f80a..c158cf38b9d 100644
--- a/drivers/pcmcia/tcic.c
+++ b/drivers/pcmcia/tcic.c
@@ -512,7 +512,7 @@ static int __init init_tcic(void)
for (i = 0; i < sockets; i++) {
socket_table[i].socket.ops = &tcic_operations;
socket_table[i].socket.resource_ops = &pccard_nonstatic_ops;
- socket_table[i].socket.dev.dev = &tcic_device.dev;
+ socket_table[i].socket.dev.parent = &tcic_device.dev;
ret = pcmcia_register_socket(&socket_table[i].socket);
if (ret && i)
pcmcia_unregister_socket(&socket_table[0].socket);
diff --git a/drivers/pcmcia/vrc4171_card.c b/drivers/pcmcia/vrc4171_card.c
index e90d8e8c5fd..eee2f1cb213 100644
--- a/drivers/pcmcia/vrc4171_card.c
+++ b/drivers/pcmcia/vrc4171_card.c
@@ -22,7 +22,6 @@
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/spinlock.h>
-#include <linux/sched.h>
#include <linux/types.h>
#include <linux/platform_device.h>
@@ -597,7 +596,7 @@ static int __devinit vrc4171_add_sockets(void)
}
sprintf(socket->name, "NEC VRC4171 Card Slot %1c", 'A' + slot);
- socket->pcmcia_socket.dev.dev = &vrc4171_card_device.dev;
+ socket->pcmcia_socket.dev.parent = &vrc4171_card_device.dev;
socket->pcmcia_socket.ops = &vrc4171_pccard_operations;
socket->pcmcia_socket.owner = THIS_MODULE;
diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c
index da471bddc97..20853a03202 100644
--- a/drivers/pcmcia/yenta_socket.c
+++ b/drivers/pcmcia/yenta_socket.c
@@ -12,7 +12,6 @@
*/
#include <linux/init.h>
#include <linux/pci.h>
-#include <linux/sched.h>
#include <linux/workqueue.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
@@ -1104,7 +1103,7 @@ static int __devinit yenta_probe (struct pci_dev *dev, const struct pci_device_i
/* prepare pcmcia_socket */
socket->socket.ops = &yenta_socket_operations;
socket->socket.resource_ops = &pccard_nonstatic_ops;
- socket->socket.dev.dev = &dev->dev;
+ socket->socket.dev.parent = &dev->dev;
socket->socket.driver_data = socket;
socket->socket.owner = THIS_MODULE;
socket->socket.features = SS_CAP_PAGE_REGS | SS_CAP_PCCARD;
diff --git a/drivers/pnp/base.h b/drivers/pnp/base.h
index 6b8c4cfd02a..31a633f6554 100644
--- a/drivers/pnp/base.h
+++ b/drivers/pnp/base.h
@@ -1,4 +1,3 @@
-extern struct bus_type pnp_bus_type;
extern spinlock_t pnp_lock;
void *pnp_alloc(long size);
int pnp_interface_attach_device(struct pnp_dev *dev);
diff --git a/drivers/pnp/isapnp/proc.c b/drivers/pnp/isapnp/proc.c
index d21f3c1e72f..40b724ebe23 100644
--- a/drivers/pnp/isapnp/proc.c
+++ b/drivers/pnp/isapnp/proc.c
@@ -85,7 +85,7 @@ static ssize_t isapnp_proc_bus_read(struct file *file, char __user *buf, size_t
return nbytes;
}
-static struct file_operations isapnp_proc_bus_file_operations =
+static const struct file_operations isapnp_proc_bus_file_operations =
{
.llseek = isapnp_proc_bus_lseek,
.read = isapnp_proc_bus_read,
diff --git a/drivers/pnp/pnpacpi/Kconfig b/drivers/pnp/pnpacpi/Kconfig
index b1854171b96..b04767ce273 100644
--- a/drivers/pnp/pnpacpi/Kconfig
+++ b/drivers/pnp/pnpacpi/Kconfig
@@ -2,17 +2,5 @@
# Plug and Play ACPI configuration
#
config PNPACPI
- bool "Plug and Play ACPI support (EXPERIMENTAL)"
- depends on PNP && ACPI && EXPERIMENTAL
- default y
- ---help---
- Linux uses the PNPACPI to autodetect built-in
- mainboard resources (e.g. parallel port resources).
-
- Some features (e.g. real hotplug) are not currently
- implemented.
-
- If you would like the kernel to detect and allocate resources to
- your mainboard devices (on some systems they are disabled by the
- BIOS) say Y here. Also the PNPACPI can help prevent resource
- conflicts between mainboard devices and other bus devices.
+ bool
+ default (PNP && ACPI)
diff --git a/drivers/pnp/pnpbios/rsparser.c b/drivers/pnp/pnpbios/rsparser.c
index 95b79685a9d..3c2ab8394e3 100644
--- a/drivers/pnp/pnpbios/rsparser.c
+++ b/drivers/pnp/pnpbios/rsparser.c
@@ -530,7 +530,6 @@ pnpbios_parse_compatible_ids(unsigned char *p, unsigned char *end, struct pnp_de
dev_id = kzalloc(sizeof (struct pnp_id), GFP_KERNEL);
if (!dev_id)
return NULL;
- memset(dev_id, 0, sizeof(struct pnp_id));
pnpid32_to_pnpid(p[1] | p[2] << 8 | p[3] << 16 | p[4] << 24,id);
memcpy(&dev_id->id, id, 7);
pnp_add_id(dev_id, dev);
diff --git a/drivers/pnp/system.c b/drivers/pnp/system.c
index d42015c382a..2065e74bb63 100644
--- a/drivers/pnp/system.c
+++ b/drivers/pnp/system.c
@@ -3,7 +3,8 @@
*
* Some code is based on pnpbios_core.c
* Copyright 2002 Adam Belay <ambx1@neo.rr.com>
- *
+ * (c) Copyright 2007 Hewlett-Packard Development Company, L.P.
+ * Bjorn Helgaas <bjorn.helgaas@hp.com>
*/
#include <linux/pnp.h>
@@ -21,18 +22,21 @@ static const struct pnp_device_id pnp_dev_table[] = {
{ "", 0 }
};
-static void reserve_ioport_range(char *pnpid, int start, int end)
+static void reserve_range(char *pnpid, int start, int end, int port)
{
struct resource *res;
char *regionid;
regionid = kmalloc(16, GFP_KERNEL);
- if ( regionid == NULL )
+ if (regionid == NULL)
return;
snprintf(regionid, 16, "pnp %s", pnpid);
- res = request_region(start,end-start+1,regionid);
- if ( res == NULL )
- kfree( regionid );
+ if (port)
+ res = request_region(start,end-start+1,regionid);
+ else
+ res = request_mem_region(start,end-start+1,regionid);
+ if (res == NULL)
+ kfree(regionid);
else
res->flags &= ~IORESOURCE_BUSY;
/*
@@ -41,26 +45,20 @@ static void reserve_ioport_range(char *pnpid, int start, int end)
* have double reservations.
*/
printk(KERN_INFO
- "pnp: %s: ioport range 0x%x-0x%x %s reserved\n",
- pnpid, start, end,
- NULL != res ? "has been" : "could not be"
- );
-
- return;
+ "pnp: %s: %s range 0x%x-0x%x %s reserved\n",
+ pnpid, port ? "ioport" : "iomem", start, end,
+ NULL != res ? "has been" : "could not be");
}
-static void reserve_resources_of_dev( struct pnp_dev *dev )
+static void reserve_resources_of_dev(struct pnp_dev *dev)
{
int i;
- for (i=0;i<PNP_MAX_PORT;i++) {
+ for (i = 0; i < PNP_MAX_PORT; i++) {
if (!pnp_port_valid(dev, i))
- /* end of resources */
continue;
if (pnp_port_start(dev, i) == 0)
- /* disabled */
- /* Do nothing */
- continue;
+ continue; /* disabled */
if (pnp_port_start(dev, i) < 0x100)
/*
* Below 0x100 is only standard PC hardware
@@ -72,14 +70,18 @@ static void reserve_resources_of_dev( struct pnp_dev *dev )
*/
continue;
if (pnp_port_end(dev, i) < pnp_port_start(dev, i))
- /* invalid endpoint */
- /* Do nothing */
+ continue; /* invalid */
+
+ reserve_range(dev->dev.bus_id, pnp_port_start(dev, i),
+ pnp_port_end(dev, i), 1);
+ }
+
+ for (i = 0; i < PNP_MAX_MEM; i++) {
+ if (!pnp_mem_valid(dev, i))
continue;
- reserve_ioport_range(
- dev->dev.bus_id,
- pnp_port_start(dev, i),
- pnp_port_end(dev, i)
- );
+
+ reserve_range(dev->dev.bus_id, pnp_mem_start(dev, i),
+ pnp_mem_end(dev, i), 0);
}
return;
diff --git a/drivers/ps3/Makefile b/drivers/ps3/Makefile
index 8433eb7562c..e251d1c1171 100644
--- a/drivers/ps3/Makefile
+++ b/drivers/ps3/Makefile
@@ -1,2 +1,3 @@
-obj-y += system-bus.o
obj-$(CONFIG_PS3_VUART) += vuart.o
+obj-$(CONFIG_PS3_PS3AV) += ps3av.o ps3av_cmd.o
+obj-$(CONFIG_PS3_SYS_MANAGER) += sys-manager.o
diff --git a/drivers/ps3/ps3av.c b/drivers/ps3/ps3av.c
new file mode 100644
index 00000000000..1926b4d3e1f
--- /dev/null
+++ b/drivers/ps3/ps3av.c
@@ -0,0 +1,974 @@
+/*
+ * Copyright (C) 2006 Sony Computer Entertainment Inc.
+ * Copyright 2006, 2007 Sony Corporation
+ *
+ * AV backend support for PS3
+ *
+ * This program is free software; 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.
+ *
+ * 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 <linux/module.h>
+#include <linux/delay.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/kernel.h>
+#include <linux/ioctl.h>
+#include <asm/lv1call.h>
+#include <asm/ps3av.h>
+#include <asm/ps3.h>
+
+#include "vuart.h"
+
+#define BUFSIZE 4096 /* vuart buf size */
+#define PS3AV_BUF_SIZE 512 /* max packet size */
+
+static int timeout = 5000; /* in msec ( 5 sec ) */
+module_param(timeout, int, 0644);
+
+static struct ps3av ps3av;
+
+static struct ps3_vuart_port_device ps3av_dev = {
+ .match_id = PS3_MATCH_ID_AV_SETTINGS
+};
+
+/* color space */
+#define YUV444 PS3AV_CMD_VIDEO_CS_YUV444_8
+#define RGB8 PS3AV_CMD_VIDEO_CS_RGB_8
+/* format */
+#define XRGB PS3AV_CMD_VIDEO_FMT_X8R8G8B8
+/* aspect */
+#define A_N PS3AV_CMD_AV_ASPECT_4_3
+#define A_W PS3AV_CMD_AV_ASPECT_16_9
+static const struct avset_video_mode {
+ u32 cs;
+ u32 fmt;
+ u32 vid;
+ u32 aspect;
+ u32 x;
+ u32 y;
+ u32 interlace;
+ u32 freq;
+} video_mode_table[] = {
+ { 0, }, /* auto */
+ {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_480I, A_N, 720, 480, 1, 60},
+ {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_480P, A_N, 720, 480, 0, 60},
+ {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_60HZ, A_N, 1280, 720, 0, 60},
+ {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080I_60HZ, A_W, 1920, 1080, 1, 60},
+ {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080P_60HZ, A_W, 1920, 1080, 0, 60},
+ {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_576I, A_N, 720, 576, 1, 50},
+ {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_576P, A_N, 720, 576, 0, 50},
+ {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_50HZ, A_N, 1280, 720, 0, 50},
+ {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080I_50HZ, A_W, 1920, 1080, 1, 50},
+ {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080P_50HZ, A_W, 1920, 1080, 0, 50},
+ { RGB8, XRGB, PS3AV_CMD_VIDEO_VID_WXGA, A_W, 1280, 768, 0, 60},
+ { RGB8, XRGB, PS3AV_CMD_VIDEO_VID_SXGA, A_N, 1280, 1024, 0, 60},
+ { RGB8, XRGB, PS3AV_CMD_VIDEO_VID_WUXGA, A_W, 1920, 1200, 0, 60},
+};
+
+/* supported CIDs */
+static u32 cmd_table[] = {
+ /* init */
+ PS3AV_CID_AV_INIT,
+ PS3AV_CID_AV_FIN,
+ PS3AV_CID_VIDEO_INIT,
+ PS3AV_CID_AUDIO_INIT,
+
+ /* set */
+ PS3AV_CID_AV_ENABLE_EVENT,
+ PS3AV_CID_AV_DISABLE_EVENT,
+
+ PS3AV_CID_AV_VIDEO_CS,
+ PS3AV_CID_AV_VIDEO_MUTE,
+ PS3AV_CID_AV_VIDEO_DISABLE_SIG,
+ PS3AV_CID_AV_AUDIO_PARAM,
+ PS3AV_CID_AV_AUDIO_MUTE,
+ PS3AV_CID_AV_HDMI_MODE,
+ PS3AV_CID_AV_TV_MUTE,
+
+ PS3AV_CID_VIDEO_MODE,
+ PS3AV_CID_VIDEO_FORMAT,
+ PS3AV_CID_VIDEO_PITCH,
+
+ PS3AV_CID_AUDIO_MODE,
+ PS3AV_CID_AUDIO_MUTE,
+ PS3AV_CID_AUDIO_ACTIVE,
+ PS3AV_CID_AUDIO_INACTIVE,
+ PS3AV_CID_AVB_PARAM,
+
+ /* get */
+ PS3AV_CID_AV_GET_HW_CONF,
+ PS3AV_CID_AV_GET_MONITOR_INFO,
+
+ /* event */
+ PS3AV_CID_EVENT_UNPLUGGED,
+ PS3AV_CID_EVENT_PLUGGED,
+ PS3AV_CID_EVENT_HDCP_DONE,
+ PS3AV_CID_EVENT_HDCP_FAIL,
+ PS3AV_CID_EVENT_HDCP_AUTH,
+ PS3AV_CID_EVENT_HDCP_ERROR,
+
+ 0
+};
+
+#define PS3AV_EVENT_CMD_MASK 0x10000000
+#define PS3AV_EVENT_ID_MASK 0x0000ffff
+#define PS3AV_CID_MASK 0xffffffff
+#define PS3AV_REPLY_BIT 0x80000000
+
+#define ps3av_event_get_port_id(cid) ((cid >> 16) & 0xff)
+
+static u32 *ps3av_search_cmd_table(u32 cid, u32 mask)
+{
+ u32 *table;
+ int i;
+
+ table = cmd_table;
+ for (i = 0;; table++, i++) {
+ if ((*table & mask) == (cid & mask))
+ break;
+ if (*table == 0)
+ return NULL;
+ }
+ return table;
+}
+
+static int ps3av_parse_event_packet(const struct ps3av_reply_hdr *hdr)
+{
+ u32 *table;
+
+ if (hdr->cid & PS3AV_EVENT_CMD_MASK) {
+ table = ps3av_search_cmd_table(hdr->cid, PS3AV_EVENT_CMD_MASK);
+ if (table)
+ dev_dbg(&ps3av_dev.core,
+ "recv event packet cid:%08x port:0x%x size:%d\n",
+ hdr->cid, ps3av_event_get_port_id(hdr->cid),
+ hdr->size);
+ else
+ printk(KERN_ERR
+ "%s: failed event packet, cid:%08x size:%d\n",
+ __FUNCTION__, hdr->cid, hdr->size);
+ return 1; /* receive event packet */
+ }
+ return 0;
+}
+
+static int ps3av_send_cmd_pkt(const struct ps3av_send_hdr *send_buf,
+ struct ps3av_reply_hdr *recv_buf, int write_len,
+ int read_len)
+{
+ int res;
+ u32 cmd;
+ int event;
+
+ if (!ps3av.available)
+ return -ENODEV;
+
+ /* send pkt */
+ res = ps3av_vuart_write(ps3av.dev, send_buf, write_len);
+ if (res < 0) {
+ dev_dbg(&ps3av_dev.core,
+ "%s: ps3av_vuart_write() failed (result=%d)\n",
+ __FUNCTION__, res);
+ return res;
+ }
+
+ /* recv pkt */
+ cmd = send_buf->cid;
+ do {
+ /* read header */
+ res = ps3av_vuart_read(ps3av.dev, recv_buf, PS3AV_HDR_SIZE,
+ timeout);
+ if (res != PS3AV_HDR_SIZE) {
+ dev_dbg(&ps3av_dev.core,
+ "%s: ps3av_vuart_read() failed (result=%d)\n",
+ __FUNCTION__, res);
+ return res;
+ }
+
+ /* read body */
+ res = ps3av_vuart_read(ps3av.dev, &recv_buf->cid,
+ recv_buf->size, timeout);
+ if (res < 0) {
+ dev_dbg(&ps3av_dev.core,
+ "%s: ps3av_vuart_read() failed (result=%d)\n",
+ __FUNCTION__, res);
+ return res;
+ }
+ res += PS3AV_HDR_SIZE; /* total len */
+ event = ps3av_parse_event_packet(recv_buf);
+ /* ret > 0 event packet */
+ } while (event);
+
+ if ((cmd | PS3AV_REPLY_BIT) != recv_buf->cid) {
+ dev_dbg(&ps3av_dev.core, "%s: reply err (result=%x)\n",
+ __FUNCTION__, recv_buf->cid);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int ps3av_process_reply_packet(struct ps3av_send_hdr *cmd_buf,
+ const struct ps3av_reply_hdr *recv_buf,
+ int user_buf_size)
+{
+ int return_len;
+
+ if (recv_buf->version != PS3AV_VERSION) {
+ dev_dbg(&ps3av_dev.core, "reply_packet invalid version:%x\n",
+ recv_buf->version);
+ return -EFAULT;
+ }
+ return_len = recv_buf->size + PS3AV_HDR_SIZE;
+ if (return_len > user_buf_size)
+ return_len = user_buf_size;
+ memcpy(cmd_buf, recv_buf, return_len);
+ return 0; /* success */
+}
+
+void ps3av_set_hdr(u32 cid, u16 size, struct ps3av_send_hdr *hdr)
+{
+ hdr->version = PS3AV_VERSION;
+ hdr->size = size - PS3AV_HDR_SIZE;
+ hdr->cid = cid;
+}
+
+int ps3av_do_pkt(u32 cid, u16 send_len, size_t usr_buf_size,
+ struct ps3av_send_hdr *buf)
+{
+ int res = 0;
+ union {
+ struct ps3av_reply_hdr reply_hdr;
+ u8 raw[PS3AV_BUF_SIZE];
+ } recv_buf;
+
+ u32 *table;
+
+ BUG_ON(!ps3av.available);
+
+ if (down_interruptible(&ps3av.sem))
+ return -ERESTARTSYS;
+
+ table = ps3av_search_cmd_table(cid, PS3AV_CID_MASK);
+ BUG_ON(!table);
+ BUG_ON(send_len < PS3AV_HDR_SIZE);
+ BUG_ON(usr_buf_size < send_len);
+ BUG_ON(usr_buf_size > PS3AV_BUF_SIZE);
+
+ /* create header */
+ ps3av_set_hdr(cid, send_len, buf);
+
+ /* send packet via vuart */
+ res = ps3av_send_cmd_pkt(buf, &recv_buf.reply_hdr, send_len,
+ usr_buf_size);
+ if (res < 0) {
+ printk(KERN_ERR
+ "%s: ps3av_send_cmd_pkt() failed (result=%d)\n",
+ __FUNCTION__, res);
+ goto err;
+ }
+
+ /* process reply packet */
+ res = ps3av_process_reply_packet(buf, &recv_buf.reply_hdr,
+ usr_buf_size);
+ if (res < 0) {
+ printk(KERN_ERR "%s: put_return_status() failed (result=%d)\n",
+ __FUNCTION__, res);
+ goto err;
+ }
+
+ up(&ps3av.sem);
+ return 0;
+
+ err:
+ up(&ps3av.sem);
+ printk(KERN_ERR "%s: failed cid:%x res:%d\n", __FUNCTION__, cid, res);
+ return res;
+}
+
+static int ps3av_set_av_video_mute(u32 mute)
+{
+ int i, num_of_av_port, res;
+
+ num_of_av_port = ps3av.av_hw_conf.num_of_hdmi +
+ ps3av.av_hw_conf.num_of_avmulti;
+ /* video mute on */
+ for (i = 0; i < num_of_av_port; i++) {
+ res = ps3av_cmd_av_video_mute(1, &ps3av.av_port[i], mute);
+ if (res < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+static int ps3av_set_video_disable_sig(void)
+{
+ int i, num_of_hdmi_port, num_of_av_port, res;
+
+ num_of_hdmi_port = ps3av.av_hw_conf.num_of_hdmi;
+ num_of_av_port = ps3av.av_hw_conf.num_of_hdmi +
+ ps3av.av_hw_conf.num_of_avmulti;
+
+ /* tv mute */
+ for (i = 0; i < num_of_hdmi_port; i++) {
+ res = ps3av_cmd_av_tv_mute(ps3av.av_port[i],
+ PS3AV_CMD_MUTE_ON);
+ if (res < 0)
+ return -1;
+ }
+ msleep(100);
+
+ /* video mute on */
+ for (i = 0; i < num_of_av_port; i++) {
+ res = ps3av_cmd_av_video_disable_sig(ps3av.av_port[i]);
+ if (res < 0)
+ return -1;
+ if (i < num_of_hdmi_port) {
+ res = ps3av_cmd_av_tv_mute(ps3av.av_port[i],
+ PS3AV_CMD_MUTE_OFF);
+ if (res < 0)
+ return -1;
+ }
+ }
+ msleep(300);
+
+ return 0;
+}
+
+static int ps3av_set_audio_mute(u32 mute)
+{
+ int i, num_of_av_port, num_of_opt_port, res;
+
+ num_of_av_port = ps3av.av_hw_conf.num_of_hdmi +
+ ps3av.av_hw_conf.num_of_avmulti;
+ num_of_opt_port = ps3av.av_hw_conf.num_of_spdif;
+
+ for (i = 0; i < num_of_av_port; i++) {
+ res = ps3av_cmd_av_audio_mute(1, &ps3av.av_port[i], mute);
+ if (res < 0)
+ return -1;
+ }
+ for (i = 0; i < num_of_opt_port; i++) {
+ res = ps3av_cmd_audio_mute(1, &ps3av.opt_port[i], mute);
+ if (res < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+int ps3av_set_audio_mode(u32 ch, u32 fs, u32 word_bits, u32 format, u32 source)
+{
+ struct ps3av_pkt_avb_param avb_param;
+ int i, num_of_audio, vid, res;
+ struct ps3av_pkt_audio_mode audio_mode;
+ u32 len = 0;
+
+ num_of_audio = ps3av.av_hw_conf.num_of_hdmi +
+ ps3av.av_hw_conf.num_of_avmulti +
+ ps3av.av_hw_conf.num_of_spdif;
+
+ avb_param.num_of_video_pkt = 0;
+ avb_param.num_of_audio_pkt = PS3AV_AVB_NUM_AUDIO; /* always 0 */
+ avb_param.num_of_av_video_pkt = 0;
+ avb_param.num_of_av_audio_pkt = ps3av.av_hw_conf.num_of_hdmi;
+
+ vid = video_mode_table[ps3av.ps3av_mode].vid;
+
+ /* audio mute */
+ ps3av_set_audio_mute(PS3AV_CMD_MUTE_ON);
+
+ /* audio inactive */
+ res = ps3av_cmd_audio_active(0, ps3av.audio_port);
+ if (res < 0)
+ dev_dbg(&ps3av_dev.core,
+ "ps3av_cmd_audio_active OFF failed\n");
+
+ /* audio_pkt */
+ for (i = 0; i < num_of_audio; i++) {
+ ps3av_cmd_set_audio_mode(&audio_mode, ps3av.av_port[i], ch, fs,
+ word_bits, format, source);
+ if (i < ps3av.av_hw_conf.num_of_hdmi) {
+ /* hdmi only */
+ len += ps3av_cmd_set_av_audio_param(&avb_param.buf[len],
+ ps3av.av_port[i],
+ &audio_mode, vid);
+ }
+ /* audio_mode pkt should be sent separately */
+ res = ps3av_cmd_audio_mode(&audio_mode);
+ if (res < 0)
+ dev_dbg(&ps3av_dev.core,
+ "ps3av_cmd_audio_mode failed, port:%x\n", i);
+ }
+
+ /* send command using avb pkt */
+ len += offsetof(struct ps3av_pkt_avb_param, buf);
+ res = ps3av_cmd_avb_param(&avb_param, len);
+ if (res < 0)
+ dev_dbg(&ps3av_dev.core, "ps3av_cmd_avb_param failed\n");
+
+ /* audio mute */
+ ps3av_set_audio_mute(PS3AV_CMD_MUTE_OFF);
+
+ /* audio active */
+ res = ps3av_cmd_audio_active(1, ps3av.audio_port);
+ if (res < 0)
+ dev_dbg(&ps3av_dev.core, "ps3av_cmd_audio_active ON failed\n");
+
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(ps3av_set_audio_mode);
+
+static int ps3av_set_videomode(void)
+{
+ /* av video mute */
+ ps3av_set_av_video_mute(PS3AV_CMD_MUTE_ON);
+
+ /* wake up ps3avd to do the actual video mode setting */
+ up(&ps3av.ping);
+
+ return 0;
+}
+
+static void ps3av_set_videomode_cont(u32 id, u32 old_id)
+{
+ struct ps3av_pkt_avb_param avb_param;
+ int i;
+ u32 len = 0, av_video_cs;
+ const struct avset_video_mode *video_mode;
+ int res;
+
+ video_mode = &video_mode_table[id & PS3AV_MODE_MASK];
+
+ avb_param.num_of_video_pkt = PS3AV_AVB_NUM_VIDEO; /* num of head */
+ avb_param.num_of_audio_pkt = 0;
+ avb_param.num_of_av_video_pkt = ps3av.av_hw_conf.num_of_hdmi +
+ ps3av.av_hw_conf.num_of_avmulti;
+ avb_param.num_of_av_audio_pkt = 0;
+
+ /* video signal off */
+ ps3av_set_video_disable_sig();
+
+ /* Retail PS3 product doesn't support this */
+ if (id & PS3AV_MODE_HDCP_OFF) {
+ res = ps3av_cmd_av_hdmi_mode(PS3AV_CMD_AV_HDMI_HDCP_OFF);
+ if (res == PS3AV_STATUS_UNSUPPORTED_HDMI_MODE)
+ dev_dbg(&ps3av_dev.core, "Not supported\n");
+ else if (res)
+ dev_dbg(&ps3av_dev.core,
+ "ps3av_cmd_av_hdmi_mode failed\n");
+ } else if (old_id & PS3AV_MODE_HDCP_OFF) {
+ res = ps3av_cmd_av_hdmi_mode(PS3AV_CMD_AV_HDMI_MODE_NORMAL);
+ if (res < 0 && res != PS3AV_STATUS_UNSUPPORTED_HDMI_MODE)
+ dev_dbg(&ps3av_dev.core,
+ "ps3av_cmd_av_hdmi_mode failed\n");
+ }
+
+ /* video_pkt */
+ for (i = 0; i < avb_param.num_of_video_pkt; i++)
+ len += ps3av_cmd_set_video_mode(&avb_param.buf[len],
+ ps3av.head[i], video_mode->vid,
+ video_mode->fmt, id);
+ /* av_video_pkt */
+ for (i = 0; i < avb_param.num_of_av_video_pkt; i++) {
+ if (id & PS3AV_MODE_DVI || id & PS3AV_MODE_RGB)
+ av_video_cs = RGB8;
+ else
+ av_video_cs = video_mode->cs;
+#ifndef PS3AV_HDMI_YUV
+ if (ps3av.av_port[i] == PS3AV_CMD_AVPORT_HDMI_0 ||
+ ps3av.av_port[i] == PS3AV_CMD_AVPORT_HDMI_1)
+ av_video_cs = RGB8; /* use RGB for HDMI */
+#endif
+ len += ps3av_cmd_set_av_video_cs(&avb_param.buf[len],
+ ps3av.av_port[i],
+ video_mode->vid, av_video_cs,
+ video_mode->aspect, id);
+ }
+ /* send command using avb pkt */
+ len += offsetof(struct ps3av_pkt_avb_param, buf);
+ 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",
+ __FUNCTION__);
+ else if (res)
+ dev_dbg(&ps3av_dev.core, "ps3av_cmd_avb_param failed\n");
+
+ msleep(1500);
+ /* av video mute */
+ ps3av_set_av_video_mute(PS3AV_CMD_MUTE_OFF);
+}
+
+static int ps3avd(void *p)
+{
+ struct ps3av *info = p;
+
+ daemonize("ps3avd");
+ while (1) {
+ down(&info->ping);
+ ps3av_set_videomode_cont(info->ps3av_mode,
+ info->ps3av_mode_old);
+ up(&info->pong);
+ }
+ return 0;
+}
+
+static int ps3av_vid2table_id(int vid)
+{
+ int i;
+
+ for (i = 1; i < ARRAY_SIZE(video_mode_table); i++)
+ if (video_mode_table[i].vid == vid)
+ return i;
+ return -1;
+}
+
+static int ps3av_resbit2vid(u32 res_50, u32 res_60)
+{
+ int vid = -1;
+
+ if (res_50 > res_60) { /* if res_50 == res_60, res_60 will be used */
+ if (res_50 & PS3AV_RESBIT_1920x1080P)
+ vid = PS3AV_CMD_VIDEO_VID_1080P_50HZ;
+ else if (res_50 & PS3AV_RESBIT_1920x1080I)
+ vid = PS3AV_CMD_VIDEO_VID_1080I_50HZ;
+ else if (res_50 & PS3AV_RESBIT_1280x720P)
+ vid = PS3AV_CMD_VIDEO_VID_720P_50HZ;
+ else if (res_50 & PS3AV_RESBIT_720x576P)
+ vid = PS3AV_CMD_VIDEO_VID_576P;
+ else
+ vid = -1;
+ } else {
+ if (res_60 & PS3AV_RESBIT_1920x1080P)
+ vid = PS3AV_CMD_VIDEO_VID_1080P_60HZ;
+ else if (res_60 & PS3AV_RESBIT_1920x1080I)
+ vid = PS3AV_CMD_VIDEO_VID_1080I_60HZ;
+ else if (res_60 & PS3AV_RESBIT_1280x720P)
+ vid = PS3AV_CMD_VIDEO_VID_720P_60HZ;
+ else if (res_60 & PS3AV_RESBIT_720x480P)
+ vid = PS3AV_CMD_VIDEO_VID_480P;
+ else
+ vid = -1;
+ }
+ return vid;
+}
+
+static int ps3av_hdmi_get_vid(struct ps3av_info_monitor *info)
+{
+ u32 res_50, res_60;
+ int vid = -1;
+
+ if (info->monitor_type != PS3AV_MONITOR_TYPE_HDMI)
+ return -1;
+
+ /* check native resolution */
+ res_50 = info->res_50.native & PS3AV_RES_MASK_50;
+ res_60 = info->res_60.native & PS3AV_RES_MASK_60;
+ if (res_50 || res_60) {
+ vid = ps3av_resbit2vid(res_50, res_60);
+ return vid;
+ }
+
+ /* check resolution */
+ res_50 = info->res_50.res_bits & PS3AV_RES_MASK_50;
+ res_60 = info->res_60.res_bits & PS3AV_RES_MASK_60;
+ if (res_50 || res_60) {
+ vid = ps3av_resbit2vid(res_50, res_60);
+ return vid;
+ }
+
+ if (ps3av.region & PS3AV_REGION_60)
+ vid = PS3AV_DEFAULT_HDMI_VID_REG_60;
+ else
+ vid = PS3AV_DEFAULT_HDMI_VID_REG_50;
+ return vid;
+}
+
+static int ps3av_auto_videomode(struct ps3av_pkt_av_get_hw_conf *av_hw_conf,
+ int boot)
+{
+ int i, res, vid = -1, dvi = 0, rgb = 0;
+ struct ps3av_pkt_av_get_monitor_info monitor_info;
+ struct ps3av_info_monitor *info;
+
+ /* get vid for hdmi */
+ for (i = 0; i < av_hw_conf->num_of_hdmi; i++) {
+ res = ps3av_cmd_video_get_monitor_info(&monitor_info,
+ PS3AV_CMD_AVPORT_HDMI_0 +
+ i);
+ if (res < 0)
+ return -1;
+
+ ps3av_cmd_av_monitor_info_dump(&monitor_info);
+ info = &monitor_info.info;
+ /* check DVI */
+ if (info->monitor_type == PS3AV_MONITOR_TYPE_DVI) {
+ dvi = PS3AV_MODE_DVI;
+ break;
+ }
+ /* check HDMI */
+ vid = ps3av_hdmi_get_vid(info);
+ if (vid != -1) {
+ /* got valid vid */
+ break;
+ }
+ }
+
+ if (dvi) {
+ /* DVI mode */
+ vid = PS3AV_DEFAULT_DVI_VID;
+ } else if (vid == -1) {
+ /* no HDMI interface or HDMI is off */
+ if (ps3av.region & PS3AV_REGION_60)
+ vid = PS3AV_DEFAULT_AVMULTI_VID_REG_60;
+ else
+ vid = PS3AV_DEFAULT_AVMULTI_VID_REG_50;
+ if (ps3av.region & PS3AV_REGION_RGB)
+ rgb = PS3AV_MODE_RGB;
+ } else if (boot) {
+ /* HDMI: using DEFAULT HDMI_VID while booting up */
+ info = &monitor_info.info;
+ if (ps3av.region & PS3AV_REGION_60) {
+ if (info->res_60.res_bits & PS3AV_RESBIT_720x480P)
+ vid = PS3AV_DEFAULT_HDMI_VID_REG_60;
+ else if (info->res_50.res_bits & PS3AV_RESBIT_720x576P)
+ vid = PS3AV_DEFAULT_HDMI_VID_REG_50;
+ else {
+ /* default */
+ vid = PS3AV_DEFAULT_HDMI_VID_REG_60;
+ }
+ } else {
+ if (info->res_50.res_bits & PS3AV_RESBIT_720x576P)
+ vid = PS3AV_DEFAULT_HDMI_VID_REG_50;
+ else if (info->res_60.res_bits & PS3AV_RESBIT_720x480P)
+ vid = PS3AV_DEFAULT_HDMI_VID_REG_60;
+ else {
+ /* default */
+ vid = PS3AV_DEFAULT_HDMI_VID_REG_50;
+ }
+ }
+ }
+
+ return (ps3av_vid2table_id(vid) | dvi | rgb);
+}
+
+static int ps3av_get_hw_conf(struct ps3av *ps3av)
+{
+ int i, j, k, res;
+
+ /* get av_hw_conf */
+ res = ps3av_cmd_av_get_hw_conf(&ps3av->av_hw_conf);
+ if (res < 0)
+ return -1;
+
+ ps3av_cmd_av_hw_conf_dump(&ps3av->av_hw_conf);
+
+ for (i = 0; i < PS3AV_HEAD_MAX; i++)
+ ps3av->head[i] = PS3AV_CMD_VIDEO_HEAD_A + i;
+ for (i = 0; i < PS3AV_OPT_PORT_MAX; i++)
+ ps3av->opt_port[i] = PS3AV_CMD_AVPORT_SPDIF_0 + i;
+ for (i = 0; i < ps3av->av_hw_conf.num_of_hdmi; i++)
+ ps3av->av_port[i] = PS3AV_CMD_AVPORT_HDMI_0 + i;
+ for (j = 0; j < ps3av->av_hw_conf.num_of_avmulti; j++)
+ ps3av->av_port[i + j] = PS3AV_CMD_AVPORT_AVMULTI_0 + j;
+ for (k = 0; k < ps3av->av_hw_conf.num_of_spdif; k++)
+ ps3av->av_port[i + j + k] = PS3AV_CMD_AVPORT_SPDIF_0 + k;
+
+ /* set all audio port */
+ ps3av->audio_port = PS3AV_CMD_AUDIO_PORT_HDMI_0
+ | PS3AV_CMD_AUDIO_PORT_HDMI_1
+ | PS3AV_CMD_AUDIO_PORT_AVMULTI_0
+ | PS3AV_CMD_AUDIO_PORT_SPDIF_0 | PS3AV_CMD_AUDIO_PORT_SPDIF_1;
+
+ return 0;
+}
+
+/* set mode using id */
+int ps3av_set_video_mode(u32 id, int boot)
+{
+ int size;
+ u32 option;
+
+ size = ARRAY_SIZE(video_mode_table);
+ if ((id & PS3AV_MODE_MASK) > size - 1 || id < 0) {
+ dev_dbg(&ps3av_dev.core, "%s: error id :%d\n", __FUNCTION__,
+ id);
+ return -EINVAL;
+ }
+
+ /* auto mode */
+ option = id & ~PS3AV_MODE_MASK;
+ if ((id & PS3AV_MODE_MASK) == 0) {
+ id = ps3av_auto_videomode(&ps3av.av_hw_conf, boot);
+ if (id < 1) {
+ printk(KERN_ERR "%s: invalid id :%d\n", __FUNCTION__,
+ id);
+ return -EINVAL;
+ }
+ id |= option;
+ }
+
+ /* set videomode */
+ down(&ps3av.pong);
+ ps3av.ps3av_mode_old = ps3av.ps3av_mode;
+ ps3av.ps3av_mode = id;
+ if (ps3av_set_videomode())
+ ps3av.ps3av_mode = ps3av.ps3av_mode_old;
+
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(ps3av_set_video_mode);
+
+int ps3av_set_mode(u32 id, int boot)
+{
+ int res;
+
+ res = ps3av_set_video_mode(id, boot);
+ if (res)
+ return res;
+
+ res = ps3av_set_audio_mode(PS3AV_CMD_AUDIO_NUM_OF_CH_2,
+ PS3AV_CMD_AUDIO_FS_48K,
+ PS3AV_CMD_AUDIO_WORD_BITS_16,
+ PS3AV_CMD_AUDIO_FORMAT_PCM,
+ PS3AV_CMD_AUDIO_SOURCE_SERIAL);
+ if (res)
+ return res;
+
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(ps3av_set_mode);
+
+int ps3av_get_mode(void)
+{
+ return ps3av.ps3av_mode;
+}
+
+EXPORT_SYMBOL_GPL(ps3av_get_mode);
+
+int ps3av_get_scanmode(int id)
+{
+ int size;
+
+ id = id & PS3AV_MODE_MASK;
+ size = ARRAY_SIZE(video_mode_table);
+ if (id > size - 1 || id < 0) {
+ printk(KERN_ERR "%s: invalid mode %d\n", __FUNCTION__, id);
+ return -EINVAL;
+ }
+ return video_mode_table[id].interlace;
+}
+
+EXPORT_SYMBOL_GPL(ps3av_get_scanmode);
+
+int ps3av_get_refresh_rate(int id)
+{
+ int size;
+
+ id = id & PS3AV_MODE_MASK;
+ size = ARRAY_SIZE(video_mode_table);
+ if (id > size - 1 || id < 0) {
+ printk(KERN_ERR "%s: invalid mode %d\n", __FUNCTION__, id);
+ return -EINVAL;
+ }
+ return video_mode_table[id].freq;
+}
+
+EXPORT_SYMBOL_GPL(ps3av_get_refresh_rate);
+
+/* get resolution by video_mode */
+int ps3av_video_mode2res(u32 id, u32 *xres, u32 *yres)
+{
+ int size;
+
+ id = id & PS3AV_MODE_MASK;
+ size = ARRAY_SIZE(video_mode_table);
+ if (id > size - 1 || id < 0) {
+ printk(KERN_ERR "%s: invalid mode %d\n", __FUNCTION__, id);
+ return -EINVAL;
+ }
+ *xres = video_mode_table[id].x;
+ *yres = video_mode_table[id].y;
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(ps3av_video_mode2res);
+
+/* mute */
+int ps3av_video_mute(int mute)
+{
+ return ps3av_set_av_video_mute(mute ? PS3AV_CMD_MUTE_ON
+ : PS3AV_CMD_MUTE_OFF);
+}
+
+EXPORT_SYMBOL_GPL(ps3av_video_mute);
+
+int ps3av_audio_mute(int mute)
+{
+ return ps3av_set_audio_mute(mute ? PS3AV_CMD_MUTE_ON
+ : PS3AV_CMD_MUTE_OFF);
+}
+
+EXPORT_SYMBOL_GPL(ps3av_audio_mute);
+
+int ps3av_dev_open(void)
+{
+ int status = 0;
+
+ mutex_lock(&ps3av.mutex);
+ if (!ps3av.open_count++) {
+ status = lv1_gpu_open(0);
+ if (status) {
+ printk(KERN_ERR "%s: lv1_gpu_open failed %d\n",
+ __FUNCTION__, status);
+ ps3av.open_count--;
+ }
+ }
+ mutex_unlock(&ps3av.mutex);
+
+ return status;
+}
+
+EXPORT_SYMBOL_GPL(ps3av_dev_open);
+
+int ps3av_dev_close(void)
+{
+ int status = 0;
+
+ mutex_lock(&ps3av.mutex);
+ if (ps3av.open_count <= 0) {
+ printk(KERN_ERR "%s: GPU already closed\n", __FUNCTION__);
+ status = -1;
+ } else if (!--ps3av.open_count) {
+ status = lv1_gpu_close();
+ if (status)
+ printk(KERN_WARNING "%s: lv1_gpu_close failed %d\n",
+ __FUNCTION__, status);
+ }
+ mutex_unlock(&ps3av.mutex);
+
+ return status;
+}
+
+EXPORT_SYMBOL_GPL(ps3av_dev_close);
+
+static int ps3av_probe(struct ps3_vuart_port_device *dev)
+{
+ int res;
+ u32 id;
+
+ dev_dbg(&ps3av_dev.core, "init ...\n");
+ dev_dbg(&ps3av_dev.core, " timeout=%d\n", timeout);
+
+ memset(&ps3av, 0, sizeof(ps3av));
+
+ init_MUTEX(&ps3av.sem);
+ init_MUTEX_LOCKED(&ps3av.ping);
+ init_MUTEX(&ps3av.pong);
+ mutex_init(&ps3av.mutex);
+ ps3av.ps3av_mode = 0;
+ ps3av.dev = dev;
+ kernel_thread(ps3avd, &ps3av, CLONE_KERNEL);
+
+ ps3av.available = 1;
+ switch (ps3_os_area_get_av_multi_out()) {
+ case PS3_PARAM_AV_MULTI_OUT_NTSC:
+ ps3av.region = PS3AV_REGION_60;
+ break;
+ case PS3_PARAM_AV_MULTI_OUT_PAL_YCBCR:
+ case PS3_PARAM_AV_MULTI_OUT_SECAM:
+ ps3av.region = PS3AV_REGION_50;
+ break;
+ case PS3_PARAM_AV_MULTI_OUT_PAL_RGB:
+ ps3av.region = PS3AV_REGION_50 | PS3AV_REGION_RGB;
+ break;
+ default:
+ ps3av.region = PS3AV_REGION_60;
+ break;
+ }
+
+ /* init avsetting modules */
+ res = ps3av_cmd_init();
+ if (res < 0)
+ printk(KERN_ERR "%s: ps3av_cmd_init failed %d\n", __FUNCTION__,
+ res);
+
+ ps3av_get_hw_conf(&ps3av);
+ id = ps3av_auto_videomode(&ps3av.av_hw_conf, 1);
+ mutex_lock(&ps3av.mutex);
+ ps3av.ps3av_mode = id;
+ mutex_unlock(&ps3av.mutex);
+
+ dev_dbg(&ps3av_dev.core, "init...done\n");
+
+ return 0;
+}
+
+static int ps3av_remove(struct ps3_vuart_port_device *dev)
+{
+ if (ps3av.available) {
+ ps3av_cmd_fin();
+ ps3av.available = 0;
+ }
+
+ return 0;
+}
+
+static void ps3av_shutdown(struct ps3_vuart_port_device *dev)
+{
+ ps3av_remove(dev);
+}
+
+static struct ps3_vuart_port_driver ps3av_driver = {
+ .match_id = PS3_MATCH_ID_AV_SETTINGS,
+ .core = {
+ .name = "ps3_av",
+ },
+ .probe = ps3av_probe,
+ .remove = ps3av_remove,
+ .shutdown = ps3av_shutdown,
+};
+
+static int ps3av_module_init(void)
+{
+ int error = ps3_vuart_port_driver_register(&ps3av_driver);
+ if (error) {
+ printk(KERN_ERR
+ "%s: ps3_vuart_port_driver_register failed %d\n",
+ __FUNCTION__, error);
+ return error;
+ }
+
+ error = ps3_vuart_port_device_register(&ps3av_dev);
+ if (error)
+ printk(KERN_ERR
+ "%s: ps3_vuart_port_device_register failed %d\n",
+ __FUNCTION__, error);
+
+ return error;
+}
+
+static void __exit ps3av_module_exit(void)
+{
+ device_unregister(&ps3av_dev.core);
+ ps3_vuart_port_driver_unregister(&ps3av_driver);
+}
+
+subsys_initcall(ps3av_module_init);
+module_exit(ps3av_module_exit);
diff --git a/drivers/ps3/ps3av_cmd.c b/drivers/ps3/ps3av_cmd.c
new file mode 100644
index 00000000000..21c97c80aa2
--- /dev/null
+++ b/drivers/ps3/ps3av_cmd.c
@@ -0,0 +1,1020 @@
+/*
+ * Copyright (C) 2006 Sony Computer Entertainment Inc.
+ * Copyright 2006, 2007 Sony Corporation
+ *
+ * AV backend support for PS3
+ *
+ * This program is free software; 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.
+ *
+ * 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 <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <asm/ps3av.h>
+#include <asm/ps3fb.h>
+#include <asm/ps3.h>
+
+#include "vuart.h"
+
+static const struct video_fmt {
+ u32 format;
+ u32 order;
+} ps3av_video_fmt_table[] = {
+ { PS3AV_CMD_VIDEO_FORMAT_ARGB_8BIT, PS3AV_CMD_VIDEO_ORDER_RGB },
+ { PS3AV_CMD_VIDEO_FORMAT_ARGB_8BIT, PS3AV_CMD_VIDEO_ORDER_BGR },
+};
+
+static const struct {
+ int cs;
+ u32 av;
+ u32 bl;
+} ps3av_cs_video2av_table[] = {
+ {
+ .cs = PS3AV_CMD_VIDEO_CS_RGB_8,
+ .av = PS3AV_CMD_AV_CS_RGB_8,
+ .bl = PS3AV_CMD_AV_CS_8
+ }, {
+ .cs = PS3AV_CMD_VIDEO_CS_RGB_10,
+ .av = PS3AV_CMD_AV_CS_RGB_8,
+ .bl = PS3AV_CMD_AV_CS_8
+ }, {
+ .cs = PS3AV_CMD_VIDEO_CS_RGB_12,
+ .av = PS3AV_CMD_AV_CS_RGB_8,
+ .bl = PS3AV_CMD_AV_CS_8
+ }, {
+ .cs = PS3AV_CMD_VIDEO_CS_YUV444_8,
+ .av = PS3AV_CMD_AV_CS_YUV444_8,
+ .bl = PS3AV_CMD_AV_CS_8
+ }, {
+ .cs = PS3AV_CMD_VIDEO_CS_YUV444_10,
+ .av = PS3AV_CMD_AV_CS_YUV444_8,
+ .bl = PS3AV_CMD_AV_CS_10
+ }, {
+ .cs = PS3AV_CMD_VIDEO_CS_YUV444_12,
+ .av = PS3AV_CMD_AV_CS_YUV444_8,
+ .bl = PS3AV_CMD_AV_CS_10
+ }, {
+ .cs = PS3AV_CMD_VIDEO_CS_YUV422_8,
+ .av = PS3AV_CMD_AV_CS_YUV422_8,
+ .bl = PS3AV_CMD_AV_CS_10
+ }, {
+ .cs = PS3AV_CMD_VIDEO_CS_YUV422_10,
+ .av = PS3AV_CMD_AV_CS_YUV422_8,
+ .bl = PS3AV_CMD_AV_CS_10
+ }, {
+ .cs = PS3AV_CMD_VIDEO_CS_YUV422_12,
+ .av = PS3AV_CMD_AV_CS_YUV422_8,
+ .bl = PS3AV_CMD_AV_CS_12
+ }, {
+ .cs = PS3AV_CMD_VIDEO_CS_XVYCC_8,
+ .av = PS3AV_CMD_AV_CS_XVYCC_8,
+ .bl = PS3AV_CMD_AV_CS_12
+ }, {
+ .cs = PS3AV_CMD_VIDEO_CS_XVYCC_10,
+ .av = PS3AV_CMD_AV_CS_XVYCC_8,
+ .bl = PS3AV_CMD_AV_CS_12
+ }, {
+ .cs = PS3AV_CMD_VIDEO_CS_XVYCC_12,
+ .av = PS3AV_CMD_AV_CS_XVYCC_8,
+ .bl = PS3AV_CMD_AV_CS_12
+ }
+};
+
+static u32 ps3av_cs_video2av(int cs)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(ps3av_cs_video2av_table); i++)
+ if (ps3av_cs_video2av_table[i].cs == cs)
+ return ps3av_cs_video2av_table[i].av;
+
+ return PS3AV_CMD_AV_CS_RGB_8;
+}
+
+static u32 ps3av_cs_video2av_bitlen(int cs)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(ps3av_cs_video2av_table); i++)
+ if (ps3av_cs_video2av_table[i].cs == cs)
+ return ps3av_cs_video2av_table[i].bl;
+
+ return PS3AV_CMD_AV_CS_8;
+}
+
+static const struct {
+ int vid;
+ u32 av;
+} ps3av_vid_video2av_table[] = {
+ { PS3AV_CMD_VIDEO_VID_480I, PS3AV_CMD_AV_VID_480I },
+ { PS3AV_CMD_VIDEO_VID_480P, PS3AV_CMD_AV_VID_480P },
+ { PS3AV_CMD_VIDEO_VID_576I, PS3AV_CMD_AV_VID_576I },
+ { PS3AV_CMD_VIDEO_VID_576P, PS3AV_CMD_AV_VID_576P },
+ { PS3AV_CMD_VIDEO_VID_1080I_60HZ, PS3AV_CMD_AV_VID_1080I_60HZ },
+ { PS3AV_CMD_VIDEO_VID_720P_60HZ, PS3AV_CMD_AV_VID_720P_60HZ },
+ { PS3AV_CMD_VIDEO_VID_1080P_60HZ, PS3AV_CMD_AV_VID_1080P_60HZ },
+ { PS3AV_CMD_VIDEO_VID_1080I_50HZ, PS3AV_CMD_AV_VID_1080I_50HZ },
+ { PS3AV_CMD_VIDEO_VID_720P_50HZ, PS3AV_CMD_AV_VID_720P_50HZ },
+ { PS3AV_CMD_VIDEO_VID_1080P_50HZ, PS3AV_CMD_AV_VID_1080P_50HZ },
+ { PS3AV_CMD_VIDEO_VID_WXGA, PS3AV_CMD_AV_VID_WXGA },
+ { PS3AV_CMD_VIDEO_VID_SXGA, PS3AV_CMD_AV_VID_SXGA },
+ { PS3AV_CMD_VIDEO_VID_WUXGA, PS3AV_CMD_AV_VID_WUXGA }
+};
+
+static u32 ps3av_vid_video2av(int vid)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(ps3av_vid_video2av_table); i++)
+ if (ps3av_vid_video2av_table[i].vid == vid)
+ return ps3av_vid_video2av_table[i].av;
+
+ return PS3AV_CMD_AV_VID_480P;
+}
+
+int ps3av_cmd_init(void)
+{
+ int res;
+ struct ps3av_pkt_av_init av_init;
+ struct ps3av_pkt_video_init video_init;
+ struct ps3av_pkt_audio_init audio_init;
+
+ /* video init */
+ memset(&video_init, 0, sizeof(video_init));
+
+ res = ps3av_do_pkt(PS3AV_CID_VIDEO_INIT, sizeof(video_init.send_hdr),
+ sizeof(video_init), &video_init.send_hdr);
+ if (res < 0)
+ return res;
+
+ res = get_status(&video_init);
+ if (res) {
+ printk(KERN_ERR "PS3AV_CID_VIDEO_INIT: failed %x\n", res);
+ return res;
+ }
+
+ /* audio init */
+ memset(&audio_init, 0, sizeof(audio_init));
+
+ res = ps3av_do_pkt(PS3AV_CID_AUDIO_INIT, sizeof(audio_init.send_hdr),
+ sizeof(audio_init), &audio_init.send_hdr);
+ if (res < 0)
+ return res;
+
+ res = get_status(&audio_init);
+ if (res) {
+ printk(KERN_ERR "PS3AV_CID_AUDIO_INIT: failed %x\n", res);
+ return res;
+ }
+
+ /* av init */
+ memset(&av_init, 0, sizeof(av_init));
+ av_init.event_bit = 0;
+
+ res = ps3av_do_pkt(PS3AV_CID_AV_INIT, sizeof(av_init), sizeof(av_init),
+ &av_init.send_hdr);
+ if (res < 0)
+ return res;
+
+ res = get_status(&av_init);
+ if (res)
+ printk(KERN_ERR "PS3AV_CID_AV_INIT: failed %x\n", res);
+
+ return res;
+}
+
+int ps3av_cmd_fin(void)
+{
+ int res;
+ struct ps3av_pkt_av_fin av_fin;
+
+ memset(&av_fin, 0, sizeof(av_fin));
+
+ res = ps3av_do_pkt(PS3AV_CID_AV_FIN, sizeof(av_fin.send_hdr),
+ sizeof(av_fin), &av_fin.send_hdr);
+ if (res < 0)
+ return res;
+
+ res = get_status(&av_fin);
+ if (res)
+ printk(KERN_ERR "PS3AV_CID_AV_FIN: failed %x\n", res);
+
+ return res;
+}
+
+int ps3av_cmd_av_video_mute(int num_of_port, u32 *port, u32 mute)
+{
+ int i, send_len, res;
+ struct ps3av_pkt_av_video_mute av_video_mute;
+
+ if (num_of_port > PS3AV_MUTE_PORT_MAX)
+ return -EINVAL;
+
+ memset(&av_video_mute, 0, sizeof(av_video_mute));
+ for (i = 0; i < num_of_port; i++) {
+ av_video_mute.mute[i].avport = port[i];
+ av_video_mute.mute[i].mute = mute;
+ }
+
+ send_len = sizeof(av_video_mute.send_hdr) +
+ sizeof(struct ps3av_av_mute) * num_of_port;
+ res = ps3av_do_pkt(PS3AV_CID_AV_VIDEO_MUTE, send_len,
+ sizeof(av_video_mute), &av_video_mute.send_hdr);
+ if (res < 0)
+ return res;
+
+ res = get_status(&av_video_mute);
+ if (res)
+ printk(KERN_ERR "PS3AV_CID_AV_VIDEO_MUTE: failed %x\n", res);
+
+ return res;
+}
+
+int ps3av_cmd_av_video_disable_sig(u32 port)
+{
+ int res;
+ struct ps3av_pkt_av_video_disable_sig av_video_sig;
+
+ memset(&av_video_sig, 0, sizeof(av_video_sig));
+ av_video_sig.avport = port;
+
+ res = ps3av_do_pkt(PS3AV_CID_AV_VIDEO_DISABLE_SIG,
+ sizeof(av_video_sig), sizeof(av_video_sig),
+ &av_video_sig.send_hdr);
+ if (res < 0)
+ return res;
+
+ res = get_status(&av_video_sig);
+ if (res)
+ printk(KERN_ERR
+ "PS3AV_CID_AV_VIDEO_DISABLE_SIG: failed %x port:%x\n",
+ res, port);
+
+ return res;
+}
+
+int ps3av_cmd_av_tv_mute(u32 avport, u32 mute)
+{
+ int res;
+ struct ps3av_pkt_av_tv_mute tv_mute;
+
+ memset(&tv_mute, 0, sizeof(tv_mute));
+ tv_mute.avport = avport;
+ tv_mute.mute = mute;
+
+ res = ps3av_do_pkt(PS3AV_CID_AV_TV_MUTE, sizeof(tv_mute),
+ sizeof(tv_mute), &tv_mute.send_hdr);
+ if (res < 0)
+ return res;
+
+ res = get_status(&tv_mute);
+ if (res)
+ printk(KERN_ERR "PS3AV_CID_AV_TV_MUTE: failed %x port:%x\n",
+ res, avport);
+
+ return res;
+}
+
+int ps3av_cmd_enable_event(void)
+{
+ int res;
+ struct ps3av_pkt_av_event av_event;
+
+ memset(&av_event, 0, sizeof(av_event));
+ av_event.event_bit = PS3AV_CMD_EVENT_BIT_UNPLUGGED |
+ PS3AV_CMD_EVENT_BIT_PLUGGED | PS3AV_CMD_EVENT_BIT_HDCP_DONE;
+
+ res = ps3av_do_pkt(PS3AV_CID_AV_ENABLE_EVENT, sizeof(av_event),
+ sizeof(av_event), &av_event.send_hdr);
+ if (res < 0)
+ return res;
+
+ res = get_status(&av_event);
+ if (res)
+ printk(KERN_ERR "PS3AV_CID_AV_ENABLE_EVENT: failed %x\n", res);
+
+ return res;
+}
+
+int ps3av_cmd_av_hdmi_mode(u8 mode)
+{
+ int res;
+ struct ps3av_pkt_av_hdmi_mode hdmi_mode;
+
+ memset(&hdmi_mode, 0, sizeof(hdmi_mode));
+ hdmi_mode.mode = mode;
+
+ res = ps3av_do_pkt(PS3AV_CID_AV_HDMI_MODE, sizeof(hdmi_mode),
+ sizeof(hdmi_mode), &hdmi_mode.send_hdr);
+ if (res < 0)
+ return res;
+
+ res = get_status(&hdmi_mode);
+ if (res && res != PS3AV_STATUS_UNSUPPORTED_HDMI_MODE)
+ printk(KERN_ERR "PS3AV_CID_AV_HDMI_MODE: failed %x\n", res);
+
+ return res;
+}
+
+u32 ps3av_cmd_set_av_video_cs(void *p, u32 avport, int video_vid, int cs_out,
+ int aspect, u32 id)
+{
+ struct ps3av_pkt_av_video_cs *av_video_cs;
+
+ av_video_cs = (struct ps3av_pkt_av_video_cs *)p;
+ if (video_vid == -1)
+ video_vid = PS3AV_CMD_VIDEO_VID_720P_60HZ;
+ if (cs_out == -1)
+ cs_out = PS3AV_CMD_VIDEO_CS_YUV444_8;
+ if (aspect == -1)
+ aspect = 0;
+
+ memset(av_video_cs, 0, sizeof(*av_video_cs));
+ ps3av_set_hdr(PS3AV_CID_AV_VIDEO_CS, sizeof(*av_video_cs),
+ &av_video_cs->send_hdr);
+ av_video_cs->avport = avport;
+ /* should be same as video_mode.resolution */
+ av_video_cs->av_vid = ps3av_vid_video2av(video_vid);
+ av_video_cs->av_cs_out = ps3av_cs_video2av(cs_out);
+ /* should be same as video_mode.video_cs_out */
+ av_video_cs->av_cs_in = ps3av_cs_video2av(PS3AV_CMD_VIDEO_CS_RGB_8);
+ av_video_cs->bitlen_out = ps3av_cs_video2av_bitlen(cs_out);
+ av_video_cs->aspect = aspect;
+ if (id & PS3AV_MODE_DITHER) {
+ av_video_cs->dither = PS3AV_CMD_AV_DITHER_ON
+ | PS3AV_CMD_AV_DITHER_8BIT;
+ } else {
+ /* default off */
+ av_video_cs->dither = PS3AV_CMD_AV_DITHER_OFF;
+ }
+
+ return sizeof(*av_video_cs);
+}
+
+u32 ps3av_cmd_set_video_mode(void *p, u32 head, int video_vid, int video_fmt,
+ u32 id)
+{
+ struct ps3av_pkt_video_mode *video_mode;
+ u32 x, y;
+
+ video_mode = (struct ps3av_pkt_video_mode *)p;
+ if (video_vid == -1)
+ video_vid = PS3AV_CMD_VIDEO_VID_720P_60HZ;
+ if (video_fmt == -1)
+ video_fmt = PS3AV_CMD_VIDEO_FMT_X8R8G8B8;
+
+ if (ps3av_video_mode2res(id, &x, &y))
+ return 0;
+
+ /* video mode */
+ memset(video_mode, 0, sizeof(*video_mode));
+ ps3av_set_hdr(PS3AV_CID_VIDEO_MODE, sizeof(*video_mode),
+ &video_mode->send_hdr);
+ video_mode->video_head = head;
+ if (video_vid == PS3AV_CMD_VIDEO_VID_480I
+ && head == PS3AV_CMD_VIDEO_HEAD_B)
+ video_mode->video_vid = PS3AV_CMD_VIDEO_VID_480I_A;
+ else
+ video_mode->video_vid = video_vid;
+ video_mode->width = (u16) x;
+ video_mode->height = (u16) y;
+ video_mode->pitch = video_mode->width * 4; /* line_length */
+ video_mode->video_out_format = PS3AV_CMD_VIDEO_OUT_FORMAT_RGB_12BIT;
+ video_mode->video_format = ps3av_video_fmt_table[video_fmt].format;
+ video_mode->video_order = ps3av_video_fmt_table[video_fmt].order;
+
+ pr_debug("%s: video_mode:vid:%x width:%d height:%d pitch:%d out_format:%d format:%x order:%x\n",
+ __FUNCTION__, video_vid, video_mode->width, video_mode->height,
+ video_mode->pitch, video_mode->video_out_format,
+ video_mode->video_format, video_mode->video_order);
+ return sizeof(*video_mode);
+}
+
+int ps3av_cmd_video_format_black(u32 head, u32 video_fmt, u32 mute)
+{
+ int res;
+ struct ps3av_pkt_video_format video_format;
+
+ memset(&video_format, 0, sizeof(video_format));
+ video_format.video_head = head;
+ if (mute != PS3AV_CMD_MUTE_OFF)
+ video_format.video_format = PS3AV_CMD_VIDEO_FORMAT_BLACK;
+ else
+ video_format.video_format =
+ ps3av_video_fmt_table[video_fmt].format;
+ video_format.video_order = ps3av_video_fmt_table[video_fmt].order;
+
+ res = ps3av_do_pkt(PS3AV_CID_VIDEO_FORMAT, sizeof(video_format),
+ sizeof(video_format), &video_format.send_hdr);
+ if (res < 0)
+ return res;
+
+ res = get_status(&video_format);
+ if (res)
+ printk(KERN_ERR "PS3AV_CID_VIDEO_FORMAT: failed %x\n", res);
+
+ return res;
+}
+
+
+int ps3av_cmd_av_audio_mute(int num_of_port, u32 *port, u32 mute)
+{
+ int i, res;
+ struct ps3av_pkt_av_audio_mute av_audio_mute;
+
+ if (num_of_port > PS3AV_MUTE_PORT_MAX)
+ return -EINVAL;
+
+ /* audio mute */
+ memset(&av_audio_mute, 0, sizeof(av_audio_mute));
+ for (i = 0; i < num_of_port; i++) {
+ av_audio_mute.mute[i].avport = port[i];
+ av_audio_mute.mute[i].mute = mute;
+ }
+
+ res = ps3av_do_pkt(PS3AV_CID_AV_AUDIO_MUTE,
+ sizeof(av_audio_mute.send_hdr) +
+ sizeof(struct ps3av_av_mute) * num_of_port,
+ sizeof(av_audio_mute), &av_audio_mute.send_hdr);
+ if (res < 0)
+ return res;
+
+ res = get_status(&av_audio_mute);
+ if (res)
+ printk(KERN_ERR "PS3AV_CID_AV_AUDIO_MUTE: failed %x\n", res);
+
+ return res;
+}
+
+static const struct {
+ u32 fs;
+ u8 mclk;
+} ps3av_cnv_mclk_table[] = {
+ { PS3AV_CMD_AUDIO_FS_44K, PS3AV_CMD_AV_MCLK_512 },
+ { PS3AV_CMD_AUDIO_FS_48K, PS3AV_CMD_AV_MCLK_512 },
+ { PS3AV_CMD_AUDIO_FS_88K, PS3AV_CMD_AV_MCLK_256 },
+ { PS3AV_CMD_AUDIO_FS_96K, PS3AV_CMD_AV_MCLK_256 },
+ { PS3AV_CMD_AUDIO_FS_176K, PS3AV_CMD_AV_MCLK_128 },
+ { PS3AV_CMD_AUDIO_FS_192K, PS3AV_CMD_AV_MCLK_128 }
+};
+
+static u8 ps3av_cnv_mclk(u32 fs)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(ps3av_cnv_mclk_table); i++)
+ if (ps3av_cnv_mclk_table[i].fs == fs)
+ return ps3av_cnv_mclk_table[i].mclk;
+
+ printk(KERN_ERR "%s failed, fs:%x\n", __FUNCTION__, fs);
+ return 0;
+}
+
+#define BASE PS3AV_CMD_AUDIO_FS_44K
+
+static const u32 ps3av_ns_table[][5] = {
+ /* D1, D2, D3, D4, D5 */
+ [PS3AV_CMD_AUDIO_FS_44K-BASE] { 6272, 6272, 17836, 17836, 8918 },
+ [PS3AV_CMD_AUDIO_FS_48K-BASE] { 6144, 6144, 11648, 11648, 5824 },
+ [PS3AV_CMD_AUDIO_FS_88K-BASE] { 12544, 12544, 35672, 35672, 17836 },
+ [PS3AV_CMD_AUDIO_FS_96K-BASE] { 12288, 12288, 23296, 23296, 11648 },
+ [PS3AV_CMD_AUDIO_FS_176K-BASE] { 25088, 25088, 71344, 71344, 35672 },
+ [PS3AV_CMD_AUDIO_FS_192K-BASE] { 24576, 24576, 46592, 46592, 23296 }
+};
+
+static void ps3av_cnv_ns(u8 *ns, u32 fs, u32 video_vid)
+{
+ u32 av_vid, ns_val;
+ u8 *p = ns;
+ int d;
+
+ d = ns_val = 0;
+ av_vid = ps3av_vid_video2av(video_vid);
+ switch (av_vid) {
+ case PS3AV_CMD_AV_VID_480I:
+ case PS3AV_CMD_AV_VID_576I:
+ d = 0;
+ break;
+ case PS3AV_CMD_AV_VID_480P:
+ case PS3AV_CMD_AV_VID_576P:
+ d = 1;
+ break;
+ case PS3AV_CMD_AV_VID_1080I_60HZ:
+ case PS3AV_CMD_AV_VID_1080I_50HZ:
+ d = 2;
+ break;
+ case PS3AV_CMD_AV_VID_720P_60HZ:
+ case PS3AV_CMD_AV_VID_720P_50HZ:
+ d = 3;
+ break;
+ case PS3AV_CMD_AV_VID_1080P_60HZ:
+ case PS3AV_CMD_AV_VID_1080P_50HZ:
+ case PS3AV_CMD_AV_VID_WXGA:
+ case PS3AV_CMD_AV_VID_SXGA:
+ case PS3AV_CMD_AV_VID_WUXGA:
+ d = 4;
+ break;
+ default:
+ printk(KERN_ERR "%s failed, vid:%x\n", __FUNCTION__,
+ video_vid);
+ break;
+ }
+
+ if (fs < PS3AV_CMD_AUDIO_FS_44K || fs > PS3AV_CMD_AUDIO_FS_192K)
+ printk(KERN_ERR "%s failed, fs:%x\n", __FUNCTION__, fs);
+ else
+ ns_val = ps3av_ns_table[PS3AV_CMD_AUDIO_FS_44K-BASE][d];
+
+ *p++ = ns_val & 0x000000FF;
+ *p++ = (ns_val & 0x0000FF00) >> 8;
+ *p = (ns_val & 0x00FF0000) >> 16;
+}
+
+#undef BASE
+
+static u8 ps3av_cnv_enable(u32 source, u8 *enable)
+{
+ u8 *p, ret = 0;
+
+ if (source == PS3AV_CMD_AUDIO_SOURCE_SPDIF) {
+ ret = 0x03;
+ } else if (source == PS3AV_CMD_AUDIO_SOURCE_SERIAL) {
+ p = enable;
+ ret = ((p[0] << 4) + (p[1] << 5) + (p[2] << 6) + (p[3] << 7)) |
+ 0x01;
+ } else
+ printk(KERN_ERR "%s failed, source:%x\n", __FUNCTION__,
+ source);
+ return ret;
+}
+
+static u8 ps3av_cnv_fifomap(u8 *map)
+{
+ u8 *p, ret = 0;
+
+ p = map;
+ ret = p[0] + (p[1] << 2) + (p[2] << 4) + (p[3] << 6);
+ return ret;
+}
+
+static u8 ps3av_cnv_inputlen(u32 word_bits)
+{
+ u8 ret = 0;
+
+ switch (word_bits) {
+ case PS3AV_CMD_AUDIO_WORD_BITS_16:
+ ret = PS3AV_CMD_AV_INPUTLEN_16;
+ break;
+ case PS3AV_CMD_AUDIO_WORD_BITS_20:
+ ret = PS3AV_CMD_AV_INPUTLEN_20;
+ break;
+ case PS3AV_CMD_AUDIO_WORD_BITS_24:
+ ret = PS3AV_CMD_AV_INPUTLEN_24;
+ break;
+ default:
+ printk(KERN_ERR "%s failed, word_bits:%x\n", __FUNCTION__,
+ word_bits);
+ break;
+ }
+ return ret;
+}
+
+static u8 ps3av_cnv_layout(u32 num_of_ch)
+{
+ if (num_of_ch > PS3AV_CMD_AUDIO_NUM_OF_CH_8) {
+ printk(KERN_ERR "%s failed, num_of_ch:%x\n", __FUNCTION__,
+ num_of_ch);
+ return 0;
+ }
+
+ return num_of_ch == PS3AV_CMD_AUDIO_NUM_OF_CH_2 ? 0x0 : 0x1;
+}
+
+static void ps3av_cnv_info(struct ps3av_audio_info_frame *info,
+ const struct ps3av_pkt_audio_mode *mode)
+{
+ info->pb1.cc = mode->audio_num_of_ch + 1; /* CH2:0x01 --- CH8:0x07 */
+ info->pb1.ct = 0;
+ info->pb2.sf = 0;
+ info->pb2.ss = 0;
+
+ info->pb3 = 0; /* check mode->audio_format ?? */
+ info->pb4 = mode->audio_layout;
+ info->pb5.dm = mode->audio_downmix;
+ info->pb5.lsv = mode->audio_downmix_level;
+}
+
+static void ps3av_cnv_chstat(u8 *chstat, u8 *cs_info)
+{
+ memcpy(chstat, cs_info, 5);
+}
+
+u32 ps3av_cmd_set_av_audio_param(void *p, u32 port,
+ const struct ps3av_pkt_audio_mode *audio_mode,
+ u32 video_vid)
+{
+ struct ps3av_pkt_av_audio_param *param;
+
+ param = (struct ps3av_pkt_av_audio_param *)p;
+
+ memset(param, 0, sizeof(*param));
+ ps3av_set_hdr(PS3AV_CID_AV_AUDIO_PARAM, sizeof(*param),
+ &param->send_hdr);
+
+ param->avport = port;
+ param->mclk = ps3av_cnv_mclk(audio_mode->audio_fs) | 0x80;
+ ps3av_cnv_ns(param->ns, audio_mode->audio_fs, video_vid);
+ param->enable = ps3av_cnv_enable(audio_mode->audio_source,
+ audio_mode->audio_enable);
+ param->swaplr = 0x09;
+ param->fifomap = ps3av_cnv_fifomap(audio_mode->audio_map);
+ param->inputctrl = 0x49;
+ param->inputlen = ps3av_cnv_inputlen(audio_mode->audio_word_bits);
+ param->layout = ps3av_cnv_layout(audio_mode->audio_num_of_ch);
+ ps3av_cnv_info(&param->info, audio_mode);
+ ps3av_cnv_chstat(param->chstat, audio_mode->audio_cs_info);
+
+ return sizeof(*param);
+}
+
+/* default cs val */
+static const u8 ps3av_mode_cs_info[] = {
+ 0x00, 0x09, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00
+};
+
+#define CS_44 0x00
+#define CS_48 0x02
+#define CS_88 0x08
+#define CS_96 0x0a
+#define CS_176 0x0c
+#define CS_192 0x0e
+#define CS_MASK 0x0f
+#define CS_BIT 0x40
+
+void ps3av_cmd_set_audio_mode(struct ps3av_pkt_audio_mode *audio, u32 avport,
+ u32 ch, u32 fs, u32 word_bits, u32 format,
+ u32 source)
+{
+ int spdif_through, spdif_bitstream;
+ int i;
+
+ if (!(ch | fs | format | word_bits | source)) {
+ ch = PS3AV_CMD_AUDIO_NUM_OF_CH_2;
+ fs = PS3AV_CMD_AUDIO_FS_48K;
+ word_bits = PS3AV_CMD_AUDIO_WORD_BITS_16;
+ format = PS3AV_CMD_AUDIO_FORMAT_PCM;
+ source = PS3AV_CMD_AUDIO_SOURCE_SERIAL;
+ }
+ spdif_through = spdif_bitstream = 0; /* XXX not supported */
+
+ /* audio mode */
+ memset(audio, 0, sizeof(*audio));
+ ps3av_set_hdr(PS3AV_CID_AUDIO_MODE, sizeof(*audio), &audio->send_hdr);
+
+ audio->avport = (u8) avport;
+ audio->mask = 0x0FFF; /* XXX set all */
+ audio->audio_num_of_ch = ch;
+ audio->audio_fs = fs;
+ audio->audio_word_bits = word_bits;
+ audio->audio_format = format;
+ audio->audio_source = source;
+
+ switch (ch) {
+ case PS3AV_CMD_AUDIO_NUM_OF_CH_8:
+ audio->audio_enable[3] = 1;
+ /* fall through */
+ case PS3AV_CMD_AUDIO_NUM_OF_CH_6:
+ audio->audio_enable[2] = 1;
+ audio->audio_enable[1] = 1;
+ /* fall through */
+ case PS3AV_CMD_AUDIO_NUM_OF_CH_2:
+ default:
+ audio->audio_enable[0] = 1;
+ }
+
+ /* audio swap L/R */
+ for (i = 0; i < 4; i++)
+ audio->audio_swap[i] = PS3AV_CMD_AUDIO_SWAP_0; /* no swap */
+
+ /* audio serial input mapping */
+ audio->audio_map[0] = PS3AV_CMD_AUDIO_MAP_OUTPUT_0;
+ audio->audio_map[1] = PS3AV_CMD_AUDIO_MAP_OUTPUT_1;
+ audio->audio_map[2] = PS3AV_CMD_AUDIO_MAP_OUTPUT_2;
+ audio->audio_map[3] = PS3AV_CMD_AUDIO_MAP_OUTPUT_3;
+
+ /* audio speaker layout */
+ if (avport == PS3AV_CMD_AVPORT_HDMI_0 ||
+ avport == PS3AV_CMD_AVPORT_HDMI_1) {
+ switch (ch) {
+ case PS3AV_CMD_AUDIO_NUM_OF_CH_8:
+ audio->audio_layout = PS3AV_CMD_AUDIO_LAYOUT_8CH;
+ break;
+ case PS3AV_CMD_AUDIO_NUM_OF_CH_6:
+ audio->audio_layout = PS3AV_CMD_AUDIO_LAYOUT_6CH;
+ break;
+ case PS3AV_CMD_AUDIO_NUM_OF_CH_2:
+ default:
+ audio->audio_layout = PS3AV_CMD_AUDIO_LAYOUT_2CH;
+ break;
+ }
+ } else {
+ audio->audio_layout = PS3AV_CMD_AUDIO_LAYOUT_2CH;
+ }
+
+ /* audio downmix permission */
+ audio->audio_downmix = PS3AV_CMD_AUDIO_DOWNMIX_PERMITTED;
+ /* audio downmix level shift (0:0dB to 15:15dB) */
+ audio->audio_downmix_level = 0; /* 0dB */
+
+ /* set ch status */
+ for (i = 0; i < 8; i++)
+ audio->audio_cs_info[i] = ps3av_mode_cs_info[i];
+
+ switch (fs) {
+ case PS3AV_CMD_AUDIO_FS_44K:
+ audio->audio_cs_info[3] &= ~CS_MASK;
+ audio->audio_cs_info[3] |= CS_44;
+ break;
+ case PS3AV_CMD_AUDIO_FS_88K:
+ audio->audio_cs_info[3] &= ~CS_MASK;
+ audio->audio_cs_info[3] |= CS_88;
+ break;
+ case PS3AV_CMD_AUDIO_FS_96K:
+ audio->audio_cs_info[3] &= ~CS_MASK;
+ audio->audio_cs_info[3] |= CS_96;
+ break;
+ case PS3AV_CMD_AUDIO_FS_176K:
+ audio->audio_cs_info[3] &= ~CS_MASK;
+ audio->audio_cs_info[3] |= CS_176;
+ break;
+ case PS3AV_CMD_AUDIO_FS_192K:
+ audio->audio_cs_info[3] &= ~CS_MASK;
+ audio->audio_cs_info[3] |= CS_192;
+ break;
+ default:
+ break;
+ }
+
+ /* pass through setting */
+ if (spdif_through &&
+ (avport == PS3AV_CMD_AVPORT_SPDIF_0 ||
+ avport == PS3AV_CMD_AVPORT_SPDIF_1)) {
+ audio->audio_word_bits = PS3AV_CMD_AUDIO_WORD_BITS_16;
+ audio->audio_source = PS3AV_CMD_AUDIO_SOURCE_SPDIF;
+ if (spdif_bitstream) {
+ audio->audio_format = PS3AV_CMD_AUDIO_FORMAT_BITSTREAM;
+ audio->audio_cs_info[0] |= CS_BIT;
+ }
+ }
+}
+
+int ps3av_cmd_audio_mode(struct ps3av_pkt_audio_mode *audio_mode)
+{
+ int res;
+
+ res = ps3av_do_pkt(PS3AV_CID_AUDIO_MODE, sizeof(*audio_mode),
+ sizeof(*audio_mode), &audio_mode->send_hdr);
+ if (res < 0)
+ return res;
+
+ res = get_status(audio_mode);
+ if (res)
+ printk(KERN_ERR "PS3AV_CID_AUDIO_MODE: failed %x\n", res);
+
+ return res;
+}
+
+int ps3av_cmd_audio_mute(int num_of_port, u32 *port, u32 mute)
+{
+ int i, res;
+ struct ps3av_pkt_audio_mute audio_mute;
+
+ if (num_of_port > PS3AV_OPT_PORT_MAX)
+ return -EINVAL;
+
+ /* audio mute */
+ memset(&audio_mute, 0, sizeof(audio_mute));
+ for (i = 0; i < num_of_port; i++) {
+ audio_mute.mute[i].avport = port[i];
+ audio_mute.mute[i].mute = mute;
+ }
+
+ res = ps3av_do_pkt(PS3AV_CID_AUDIO_MUTE,
+ sizeof(audio_mute.send_hdr) +
+ sizeof(struct ps3av_audio_mute) * num_of_port,
+ sizeof(audio_mute), &audio_mute.send_hdr);
+ if (res < 0)
+ return res;
+
+ res = get_status(&audio_mute);
+ if (res)
+ printk(KERN_ERR "PS3AV_CID_AUDIO_MUTE: failed %x\n", res);
+
+ return res;
+}
+
+int ps3av_cmd_audio_active(int active, u32 port)
+{
+ int res;
+ struct ps3av_pkt_audio_active audio_active;
+ u32 cid;
+
+ /* audio active */
+ memset(&audio_active, 0, sizeof(audio_active));
+ audio_active.audio_port = port;
+ cid = active ? PS3AV_CID_AUDIO_ACTIVE : PS3AV_CID_AUDIO_INACTIVE;
+
+ res = ps3av_do_pkt(cid, sizeof(audio_active), sizeof(audio_active),
+ &audio_active.send_hdr);
+ if (res < 0)
+ return res;
+
+ res = get_status(&audio_active);
+ if (res)
+ printk(KERN_ERR "PS3AV_CID_AUDIO_ACTIVE:%x failed %x\n", cid,
+ res);
+
+ return res;
+}
+
+int ps3av_cmd_avb_param(struct ps3av_pkt_avb_param *avb, u32 send_len)
+{
+ int res;
+
+ ps3fb_flip_ctl(0); /* flip off */
+
+ /* avb packet */
+ res = ps3av_do_pkt(PS3AV_CID_AVB_PARAM, send_len, sizeof(*avb),
+ &avb->send_hdr);
+ if (res < 0)
+ goto out;
+
+ res = get_status(avb);
+ if (res)
+ pr_debug("%s: PS3AV_CID_AVB_PARAM: failed %x\n", __FUNCTION__,
+ res);
+
+ out:
+ ps3fb_flip_ctl(1); /* flip on */
+ return res;
+}
+
+int ps3av_cmd_av_get_hw_conf(struct ps3av_pkt_av_get_hw_conf *hw_conf)
+{
+ int res;
+
+ memset(hw_conf, 0, sizeof(*hw_conf));
+
+ res = ps3av_do_pkt(PS3AV_CID_AV_GET_HW_CONF, sizeof(hw_conf->send_hdr),
+ sizeof(*hw_conf), &hw_conf->send_hdr);
+ if (res < 0)
+ return res;
+
+ res = get_status(hw_conf);
+ if (res)
+ printk(KERN_ERR "PS3AV_CID_AV_GET_HW_CONF: failed %x\n", res);
+
+ return res;
+}
+
+int ps3av_cmd_video_get_monitor_info(struct ps3av_pkt_av_get_monitor_info *info,
+ u32 avport)
+{
+ int res;
+
+ memset(info, 0, sizeof(*info));
+ info->avport = avport;
+
+ res = ps3av_do_pkt(PS3AV_CID_AV_GET_MONITOR_INFO,
+ sizeof(info->send_hdr) + sizeof(info->avport) +
+ sizeof(info->reserved),
+ sizeof(*info), &info->send_hdr);
+ if (res < 0)
+ return res;
+
+ res = get_status(info);
+ if (res)
+ printk(KERN_ERR "PS3AV_CID_AV_GET_MONITOR_INFO: failed %x\n",
+ res);
+
+ return res;
+}
+
+#ifdef PS3AV_DEBUG
+void ps3av_cmd_av_hw_conf_dump(const struct ps3av_pkt_av_get_hw_conf *hw_conf)
+{
+ printk("av_h_conf:num of hdmi:%d\n", hw_conf->num_of_hdmi);
+ printk("av_h_conf:num of avmulti:%d\n", hw_conf->num_of_avmulti);
+ printk("av_h_conf:num of spdif:%d\n", hw_conf->num_of_spdif);
+}
+
+void ps3av_cmd_av_monitor_info_dump(const struct ps3av_pkt_av_get_monitor_info *monitor_info)
+{
+ const struct ps3av_info_monitor *info = &monitor_info->info;
+ const struct ps3av_info_audio *audio = info->audio;
+ int i;
+
+ printk("Monitor Info: size%d\n", monitor_info->send_hdr.size);
+
+ printk("avport:%02x\n", info->avport);
+ printk("monitor_id:");
+ for (i = 0; i < 10; i++)
+ printk("%02x ", info->monitor_id[i]);
+ printk("\nmonitor_type:%02x\n", info->monitor_type);
+ printk("monitor_name:");
+ for (i = 0; i < 16; i++)
+ printk("%c", info->monitor_name[i]);
+
+ /* resolution */
+ printk("\nresolution_60: bits:%08x native:%08x\n",
+ info->res_60.res_bits, info->res_60.native);
+ printk("resolution_50: bits:%08x native:%08x\n",
+ info->res_50.res_bits, info->res_50.native);
+ printk("resolution_other: bits:%08x native:%08x\n",
+ info->res_other.res_bits, info->res_other.native);
+ printk("resolution_vesa: bits:%08x native:%08x\n",
+ info->res_vesa.res_bits, info->res_vesa.native);
+
+ /* color space */
+ printk("color space rgb:%02x\n", info->cs.rgb);
+ printk("color space yuv444:%02x\n", info->cs.yuv444);
+ printk("color space yuv422:%02x\n", info->cs.yuv422);
+
+ /* color info */
+ printk("color info red:X %04x Y %04x\n",
+ info->color.red_x, info->color.red_y);
+ printk("color info green:X %04x Y %04x\n",
+ info->color.green_x, info->color.green_y);
+ printk("color info blue:X %04x Y %04x\n",
+ info->color.blue_x, info->color.blue_y);
+ printk("color info white:X %04x Y %04x\n",
+ info->color.white_x, info->color.white_y);
+ printk("color info gamma: %08x\n", info->color.gamma);
+
+ /* other info */
+ printk("supported_AI:%02x\n", info->supported_ai);
+ printk("speaker_info:%02x\n", info->speaker_info);
+ printk("num of audio:%02x\n", info->num_of_audio_block);
+
+ /* audio block */
+ for (i = 0; i < info->num_of_audio_block; i++) {
+ printk("audio[%d] type:%02x max_ch:%02x fs:%02x sbit:%02x\n",
+ i, audio->type, audio->max_num_of_ch, audio->fs,
+ audio->sbit);
+ audio++;
+ }
+}
+#endif /* PS3AV_DEBUG */
+
+#define PS3AV_AV_LAYOUT_0 (PS3AV_CMD_AV_LAYOUT_32 \
+ | PS3AV_CMD_AV_LAYOUT_44 \
+ | PS3AV_CMD_AV_LAYOUT_48)
+
+#define PS3AV_AV_LAYOUT_1 (PS3AV_AV_LAYOUT_0 \
+ | PS3AV_CMD_AV_LAYOUT_88 \
+ | PS3AV_CMD_AV_LAYOUT_96 \
+ | PS3AV_CMD_AV_LAYOUT_176 \
+ | PS3AV_CMD_AV_LAYOUT_192)
+
+/************************* vuart ***************************/
+
+#define POLLING_INTERVAL 25 /* in msec */
+
+int ps3av_vuart_write(struct ps3_vuart_port_device *dev, const void *buf,
+ unsigned long size)
+{
+ int error = ps3_vuart_write(dev, buf, size);
+ return error ? error : size;
+}
+
+int ps3av_vuart_read(struct ps3_vuart_port_device *dev, void *buf,
+ unsigned long size, int timeout)
+{
+ int error;
+ int loopcnt = 0;
+
+ timeout = (timeout + POLLING_INTERVAL - 1) / POLLING_INTERVAL;
+ while (loopcnt++ <= timeout) {
+ error = ps3_vuart_read(dev, buf, size);
+ if (!error)
+ return size;
+ if (error != -EAGAIN) {
+ printk(KERN_ERR "%s: ps3_vuart_read failed %d\n",
+ __FUNCTION__, error);
+ return error;
+ }
+ msleep(POLLING_INTERVAL);
+ }
+ return -EWOULDBLOCK;
+}
diff --git a/drivers/ps3/sys-manager.c b/drivers/ps3/sys-manager.c
new file mode 100644
index 00000000000..0fc30be8b81
--- /dev/null
+++ b/drivers/ps3/sys-manager.c
@@ -0,0 +1,604 @@
+/*
+ * PS3 System Manager.
+ *
+ * Copyright (C) 2007 Sony Computer Entertainment Inc.
+ * Copyright 2007 Sony Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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.
+ *
+ * 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/workqueue.h>
+#include <linux/reboot.h>
+#include <asm/ps3.h>
+#include "vuart.h"
+
+MODULE_AUTHOR("Sony Corporation");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("PS3 System Manager");
+
+/**
+ * ps3_sys_manager - PS3 system manager driver.
+ *
+ * The system manager provides an asyncronous system event notification
+ * mechanism for reporting events like thermal alert and button presses to
+ * guests. It also provides support to control system shutdown and startup.
+ *
+ * The actual system manager is implemented as an application running in the
+ * system policy module in lpar_1. Guests communicate with the system manager
+ * through port 2 of the vuart using a simple packet message protocol.
+ * Messages are comprised of a fixed field header followed by a message
+ * specific payload.
+ */
+
+/**
+ * struct ps3_sys_manager_header - System manager message header.
+ * @version: Header version, currently 1.
+ * @size: Header size in bytes, curently 16.
+ * @payload_size: Message payload size in bytes.
+ * @service_id: Message type, one of enum ps3_sys_manager_service_id.
+ */
+
+struct ps3_sys_manager_header {
+ /* version 1 */
+ u8 version;
+ u8 size;
+ u16 reserved_1;
+ u32 payload_size;
+ u16 service_id;
+ u16 reserved_2[3];
+};
+
+/**
+ * @PS3_SM_RX_MSG_LEN - System manager received message length.
+ *
+ * Currently all messages received from the system manager are the same length
+ * (16 bytes header + 16 bytes payload = 32 bytes). This knowlege is used to
+ * simplify the logic.
+ */
+
+enum {
+ PS3_SM_RX_MSG_LEN = 32,
+};
+
+/**
+ * enum ps3_sys_manager_service_id - Message header service_id.
+ * @PS3_SM_SERVICE_ID_REQUEST: guest --> sys_manager.
+ * @PS3_SM_SERVICE_ID_COMMAND: guest <-- sys_manager.
+ * @PS3_SM_SERVICE_ID_RESPONSE: guest --> sys_manager.
+ * @PS3_SM_SERVICE_ID_SET_ATTR: guest --> sys_manager.
+ * @PS3_SM_SERVICE_ID_EXTERN_EVENT: guest <-- sys_manager.
+ * @PS3_SM_SERVICE_ID_SET_NEXT_OP: guest --> sys_manager.
+ */
+
+enum ps3_sys_manager_service_id {
+ /* version 1 */
+ PS3_SM_SERVICE_ID_REQUEST = 1,
+ PS3_SM_SERVICE_ID_RESPONSE = 2,
+ PS3_SM_SERVICE_ID_COMMAND = 3,
+ PS3_SM_SERVICE_ID_EXTERN_EVENT = 4,
+ PS3_SM_SERVICE_ID_SET_NEXT_OP = 5,
+ PS3_SM_SERVICE_ID_SET_ATTR = 8,
+};
+
+/**
+ * enum ps3_sys_manager_attr - Notification attribute (bit position mask).
+ * @PS3_SM_ATTR_POWER: Power button.
+ * @PS3_SM_ATTR_RESET: Reset button, not available on retail console.
+ * @PS3_SM_ATTR_THERMAL: Sytem thermal alert.
+ * @PS3_SM_ATTR_CONTROLLER: Remote controller event.
+ * @PS3_SM_ATTR_ALL: Logical OR of all.
+ *
+ * The guest tells the system manager which events it is interested in receiving
+ * notice of by sending the system manager a logical OR of notification
+ * attributes via the ps3_sys_manager_send_attr() routine.
+ */
+
+enum ps3_sys_manager_attr {
+ /* version 1 */
+ PS3_SM_ATTR_POWER = 1,
+ PS3_SM_ATTR_RESET = 2,
+ PS3_SM_ATTR_THERMAL = 4,
+ PS3_SM_ATTR_CONTROLLER = 8, /* bogus? */
+ PS3_SM_ATTR_ALL = 0x0f,
+};
+
+/**
+ * enum ps3_sys_manager_event - External event type, reported by system manager.
+ * @PS3_SM_EVENT_POWER_PRESSED: payload.value not used.
+ * @PS3_SM_EVENT_POWER_RELEASED: payload.value = time pressed in millisec.
+ * @PS3_SM_EVENT_RESET_PRESSED: payload.value not used.
+ * @PS3_SM_EVENT_RESET_RELEASED: payload.value = time pressed in millisec.
+ * @PS3_SM_EVENT_THERMAL_ALERT: payload.value = thermal zone id.
+ * @PS3_SM_EVENT_THERMAL_CLEARED: payload.value = thermal zone id.
+ */
+
+enum ps3_sys_manager_event {
+ /* version 1 */
+ PS3_SM_EVENT_POWER_PRESSED = 3,
+ PS3_SM_EVENT_POWER_RELEASED = 4,
+ PS3_SM_EVENT_RESET_PRESSED = 5,
+ PS3_SM_EVENT_RESET_RELEASED = 6,
+ PS3_SM_EVENT_THERMAL_ALERT = 7,
+ PS3_SM_EVENT_THERMAL_CLEARED = 8,
+ /* no info on controller events */
+};
+
+/**
+ * enum ps3_sys_manager_next_op - Operation to perform after lpar is destroyed.
+ */
+
+enum ps3_sys_manager_next_op {
+ /* version 3 */
+ PS3_SM_NEXT_OP_SYS_SHUTDOWN = 1,
+ PS3_SM_NEXT_OP_SYS_REBOOT = 2,
+ PS3_SM_NEXT_OP_LPAR_REBOOT = 0x82,
+};
+
+/**
+ * enum ps3_sys_manager_wake_source - Next-op wakeup source (bit position mask).
+ * @PS3_SM_WAKE_DEFAULT: Disk insert, power button, eject button, IR
+ * controller, and bluetooth controller.
+ * @PS3_SM_WAKE_RTC:
+ * @PS3_SM_WAKE_RTC_ERROR:
+ * @PS3_SM_WAKE_P_O_R: Power on reset.
+ *
+ * Additional wakeup sources when specifying PS3_SM_NEXT_OP_SYS_SHUTDOWN.
+ * System will always wake from the PS3_SM_WAKE_DEFAULT sources.
+ */
+
+enum ps3_sys_manager_wake_source {
+ /* version 3 */
+ PS3_SM_WAKE_DEFAULT = 0,
+ PS3_SM_WAKE_RTC = 0x00000040,
+ PS3_SM_WAKE_RTC_ERROR = 0x00000080,
+ PS3_SM_WAKE_P_O_R = 0x10000000,
+};
+
+/**
+ * enum ps3_sys_manager_cmd - Command from system manager to guest.
+ *
+ * The guest completes the actions needed, then acks or naks the command via
+ * ps3_sys_manager_send_response(). In the case of @PS3_SM_CMD_SHUTDOWN,
+ * the guest must be fully prepared for a system poweroff prior to acking the
+ * command.
+ */
+
+enum ps3_sys_manager_cmd {
+ /* version 1 */
+ PS3_SM_CMD_SHUTDOWN = 1, /* shutdown guest OS */
+};
+
+/**
+ * ps3_sys_manager_write - Helper to write a two part message to the vuart.
+ *
+ */
+
+static int ps3_sys_manager_write(struct ps3_vuart_port_device *dev,
+ const struct ps3_sys_manager_header *header, const void *payload)
+{
+ int result;
+
+ BUG_ON(header->version != 1);
+ BUG_ON(header->size != 16);
+ BUG_ON(header->payload_size != 8 && header->payload_size != 16);
+ BUG_ON(header->service_id > 8);
+
+ result = ps3_vuart_write(dev, header,
+ sizeof(struct ps3_sys_manager_header));
+
+ if (!result)
+ result = ps3_vuart_write(dev, payload, header->payload_size);
+
+ return result;
+}
+
+/**
+ * ps3_sys_manager_send_attr - Send a 'set attribute' to the system manager.
+ *
+ */
+
+static int ps3_sys_manager_send_attr(struct ps3_vuart_port_device *dev,
+ enum ps3_sys_manager_attr attr)
+{
+ static const struct ps3_sys_manager_header header = {
+ .version = 1,
+ .size = 16,
+ .payload_size = 16,
+ .service_id = PS3_SM_SERVICE_ID_SET_ATTR,
+ };
+ struct {
+ u8 version;
+ u8 reserved_1[3];
+ u32 attribute;
+ } payload;
+
+ BUILD_BUG_ON(sizeof(payload) != 8);
+
+ dev_dbg(&dev->core, "%s:%d: %xh\n", __func__, __LINE__, attr);
+
+ memset(&payload, 0, sizeof(payload));
+ payload.version = 1;
+ payload.attribute = attr;
+
+ return ps3_sys_manager_write(dev, &header, &payload);
+}
+
+/**
+ * ps3_sys_manager_send_next_op - Send a 'set next op' to the system manager.
+ *
+ * Tell the system manager what to do after this lpar is destroyed.
+ */
+
+static int ps3_sys_manager_send_next_op(struct ps3_vuart_port_device *dev,
+ enum ps3_sys_manager_next_op op,
+ enum ps3_sys_manager_wake_source wake_source)
+{
+ static const struct ps3_sys_manager_header header = {
+ .version = 1,
+ .size = 16,
+ .payload_size = 16,
+ .service_id = PS3_SM_SERVICE_ID_SET_NEXT_OP,
+ };
+ struct {
+ u8 version;
+ u8 type;
+ u8 gos_id;
+ u8 reserved_1;
+ u32 wake_source;
+ u8 reserved_2[8];
+ } payload;
+
+ BUILD_BUG_ON(sizeof(payload) != 16);
+
+ dev_dbg(&dev->core, "%s:%d: (%xh)\n", __func__, __LINE__, op);
+
+ memset(&payload, 0, sizeof(payload));
+ payload.version = 3;
+ payload.type = op;
+ payload.gos_id = 3; /* other os */
+ payload.wake_source = wake_source;
+
+ return ps3_sys_manager_write(dev, &header, &payload);
+}
+
+/**
+ * ps3_sys_manager_send_request_shutdown - Send 'request' to the system manager.
+ *
+ * The guest sends this message to request an operation or action of the system
+ * manager. The reply is a command message from the system manager. In the
+ * command handler the guest performs the requested operation. The result of
+ * the command is then communicated back to the system manager with a response
+ * message.
+ *
+ * Currently, the only supported request it the 'shutdown self' request.
+ */
+
+static int ps3_sys_manager_send_request_shutdown(struct ps3_vuart_port_device *dev)
+{
+ static const struct ps3_sys_manager_header header = {
+ .version = 1,
+ .size = 16,
+ .payload_size = 16,
+ .service_id = PS3_SM_SERVICE_ID_REQUEST,
+ };
+ struct {
+ u8 version;
+ u8 type;
+ u8 gos_id;
+ u8 reserved_1[13];
+ } static const payload = {
+ .version = 1,
+ .type = 1, /* shutdown */
+ .gos_id = 0, /* self */
+ };
+
+ BUILD_BUG_ON(sizeof(payload) != 16);
+
+ dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
+
+ return ps3_sys_manager_write(dev, &header, &payload);
+}
+
+/**
+ * ps3_sys_manager_send_response - Send a 'response' to the system manager.
+ * @status: zero = success, others fail.
+ *
+ * The guest sends this message to the system manager to acnowledge success or
+ * failure of a command sent by the system manager.
+ */
+
+static int ps3_sys_manager_send_response(struct ps3_vuart_port_device *dev,
+ u64 status)
+{
+ static const struct ps3_sys_manager_header header = {
+ .version = 1,
+ .size = 16,
+ .payload_size = 16,
+ .service_id = PS3_SM_SERVICE_ID_RESPONSE,
+ };
+ struct {
+ u8 version;
+ u8 reserved_1[3];
+ u8 status;
+ u8 reserved_2[11];
+ } payload;
+
+ BUILD_BUG_ON(sizeof(payload) != 16);
+
+ dev_dbg(&dev->core, "%s:%d: (%s)\n", __func__, __LINE__,
+ (status ? "nak" : "ack"));
+
+ memset(&payload, 0, sizeof(payload));
+ payload.version = 1;
+ payload.status = status;
+
+ return ps3_sys_manager_write(dev, &header, &payload);
+}
+
+/**
+ * ps3_sys_manager_handle_event - Second stage event msg handler.
+ *
+ */
+
+static int ps3_sys_manager_handle_event(struct ps3_vuart_port_device *dev)
+{
+ int result;
+ struct {
+ u8 version;
+ u8 type;
+ u8 reserved_1[2];
+ u32 value;
+ u8 reserved_2[8];
+ } event;
+
+ BUILD_BUG_ON(sizeof(event) != 16);
+
+ result = ps3_vuart_read(dev, &event, sizeof(event));
+ BUG_ON(result);
+
+ if (event.version != 1) {
+ dev_dbg(&dev->core, "%s:%d: unsupported event version (%u)\n",
+ __func__, __LINE__, event.version);
+ return -EIO;
+ }
+
+ switch (event.type) {
+ case PS3_SM_EVENT_POWER_PRESSED:
+ dev_dbg(&dev->core, "%s:%d: POWER_PRESSED\n",
+ __func__, __LINE__);
+ break;
+ case PS3_SM_EVENT_POWER_RELEASED:
+ dev_dbg(&dev->core, "%s:%d: POWER_RELEASED (%u ms)\n",
+ __func__, __LINE__, event.value);
+ kill_cad_pid(SIGINT, 1);
+ break;
+ case PS3_SM_EVENT_THERMAL_ALERT:
+ dev_dbg(&dev->core, "%s:%d: THERMAL_ALERT (zone %u)\n",
+ __func__, __LINE__, event.value);
+ printk(KERN_INFO "PS3 Thermal Alert Zone %u\n", event.value);
+ break;
+ case PS3_SM_EVENT_THERMAL_CLEARED:
+ dev_dbg(&dev->core, "%s:%d: THERMAL_CLEARED (zone %u)\n",
+ __func__, __LINE__, event.value);
+ break;
+ default:
+ dev_dbg(&dev->core, "%s:%d: unknown event (%u)\n",
+ __func__, __LINE__, event.type);
+ return -EIO;
+ }
+
+ return 0;
+}
+/**
+ * ps3_sys_manager_handle_cmd - Second stage command msg handler.
+ *
+ * The system manager sends this in reply to a 'request' message from the guest.
+ */
+
+static int ps3_sys_manager_handle_cmd(struct ps3_vuart_port_device *dev)
+{
+ int result;
+ struct {
+ u8 version;
+ u8 type;
+ u8 reserved_1[14];
+ } cmd;
+
+ BUILD_BUG_ON(sizeof(cmd) != 16);
+
+ dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
+
+ result = ps3_vuart_read(dev, &cmd, sizeof(cmd));
+
+ if(result)
+ return result;
+
+ if (cmd.version != 1) {
+ dev_dbg(&dev->core, "%s:%d: unsupported cmd version (%u)\n",
+ __func__, __LINE__, cmd.version);
+ return -EIO;
+ }
+
+ if (cmd.type != PS3_SM_CMD_SHUTDOWN) {
+ dev_dbg(&dev->core, "%s:%d: unknown cmd (%u)\n",
+ __func__, __LINE__, cmd.type);
+ return -EIO;
+ }
+
+ ps3_sys_manager_send_response(dev, 0);
+ return 0;
+}
+
+/**
+ * ps3_sys_manager_handle_msg - First stage msg handler.
+ *
+ */
+
+static int ps3_sys_manager_handle_msg(struct ps3_vuart_port_device *dev)
+{
+ int result;
+ struct ps3_sys_manager_header header;
+
+ result = ps3_vuart_read(dev, &header,
+ sizeof(struct ps3_sys_manager_header));
+
+ if(result)
+ return result;
+
+ if (header.version != 1) {
+ dev_dbg(&dev->core, "%s:%d: unsupported header version (%u)\n",
+ __func__, __LINE__, header.version);
+ goto fail_header;
+ }
+
+ BUILD_BUG_ON(sizeof(header) != 16);
+ BUG_ON(header.size != 16);
+ BUG_ON(header.payload_size != 16);
+
+ switch (header.service_id) {
+ case PS3_SM_SERVICE_ID_EXTERN_EVENT:
+ dev_dbg(&dev->core, "%s:%d: EVENT\n", __func__, __LINE__);
+ return ps3_sys_manager_handle_event(dev);
+ case PS3_SM_SERVICE_ID_COMMAND:
+ dev_dbg(&dev->core, "%s:%d: COMMAND\n", __func__, __LINE__);
+ return ps3_sys_manager_handle_cmd(dev);
+ default:
+ dev_dbg(&dev->core, "%s:%d: unknown service_id (%u)\n",
+ __func__, __LINE__, header.service_id);
+ break;
+ }
+ goto fail_id;
+
+fail_header:
+ ps3_vuart_clear_rx_bytes(dev, 0);
+ return -EIO;
+fail_id:
+ ps3_vuart_clear_rx_bytes(dev, header.payload_size);
+ return -EIO;
+}
+
+/**
+ * ps3_sys_manager_work - Asyncronous read handler.
+ *
+ * Signaled when a complete message arrives at the vuart port.
+ */
+
+static void ps3_sys_manager_work(struct work_struct *work)
+{
+ struct ps3_vuart_port_device *dev = ps3_vuart_work_to_port_device(work);
+
+ ps3_sys_manager_handle_msg(dev);
+ ps3_vuart_read_async(dev, ps3_sys_manager_work, PS3_SM_RX_MSG_LEN);
+}
+
+struct {
+ struct ps3_vuart_port_device *dev;
+} static drv_priv;
+
+/**
+ * ps3_sys_manager_restart - The final platform machine_restart routine.
+ *
+ * This routine never returns. The routine disables asyncronous vuart reads
+ * then spins calling ps3_sys_manager_handle_msg() to receive and acknowledge
+ * the shutdown command sent from the system manager. Soon after the
+ * acknowledgement is sent the lpar is destroyed by the HV. This routine
+ * should only be called from ps3_restart().
+ */
+
+void ps3_sys_manager_restart(void)
+{
+ struct ps3_vuart_port_device *dev = drv_priv.dev;
+
+ BUG_ON(!drv_priv.dev);
+
+ dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
+
+ ps3_vuart_cancel_async(dev);
+
+ ps3_sys_manager_send_attr(dev, 0);
+ ps3_sys_manager_send_next_op(dev, PS3_SM_NEXT_OP_LPAR_REBOOT,
+ PS3_SM_WAKE_DEFAULT);
+ ps3_sys_manager_send_request_shutdown(dev);
+
+ printk(KERN_EMERG "System Halted, OK to turn off power\n");
+
+ while(1)
+ ps3_sys_manager_handle_msg(dev);
+}
+
+/**
+ * ps3_sys_manager_power_off - The final platform machine_power_off routine.
+ *
+ * This routine never returns. The routine disables asyncronous vuart reads
+ * then spins calling ps3_sys_manager_handle_msg() to receive and acknowledge
+ * the shutdown command sent from the system manager. Soon after the
+ * acknowledgement is sent the lpar is destroyed by the HV. This routine
+ * should only be called from ps3_power_off().
+ */
+
+void ps3_sys_manager_power_off(void)
+{
+ struct ps3_vuart_port_device *dev = drv_priv.dev;
+
+ BUG_ON(!drv_priv.dev);
+
+ dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
+
+ ps3_vuart_cancel_async(dev);
+
+ ps3_sys_manager_send_next_op(dev, PS3_SM_NEXT_OP_SYS_SHUTDOWN,
+ PS3_SM_WAKE_DEFAULT);
+ ps3_sys_manager_send_request_shutdown(dev);
+
+ printk(KERN_EMERG "System Halted, OK to turn off power\n");
+
+ while(1)
+ ps3_sys_manager_handle_msg(dev);
+}
+
+static int ps3_sys_manager_probe(struct ps3_vuart_port_device *dev)
+{
+ int result;
+
+ dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
+
+ BUG_ON(drv_priv.dev);
+ drv_priv.dev = dev;
+
+ result = ps3_sys_manager_send_attr(dev, PS3_SM_ATTR_ALL);
+ BUG_ON(result);
+
+ result = ps3_vuart_read_async(dev, ps3_sys_manager_work,
+ PS3_SM_RX_MSG_LEN);
+ BUG_ON(result);
+
+ return result;
+}
+
+static struct ps3_vuart_port_driver ps3_sys_manager = {
+ .match_id = PS3_MATCH_ID_SYSTEM_MANAGER,
+ .core = {
+ .name = "ps3_sys_manager",
+ },
+ .probe = ps3_sys_manager_probe,
+};
+
+static int __init ps3_sys_manager_init(void)
+{
+ return ps3_vuart_port_driver_register(&ps3_sys_manager);
+}
+
+module_init(ps3_sys_manager_init);
diff --git a/drivers/ps3/system-bus.c b/drivers/ps3/system-bus.c
deleted file mode 100644
index d79f949bcb2..00000000000
--- a/drivers/ps3/system-bus.c
+++ /dev/null
@@ -1,362 +0,0 @@
-/*
- * PS3 system bus driver.
- *
- * Copyright (C) 2006 Sony Computer Entertainment Inc.
- * Copyright 2006 Sony Corp.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; 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.
- *
- * 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/init.h>
-#include <linux/module.h>
-#include <linux/dma-mapping.h>
-#include <linux/err.h>
-
-#include <asm/udbg.h>
-#include <asm/ps3.h>
-#include <asm/lv1call.h>
-#include <asm/firmware.h>
-
-#define dump_mmio_region(_a) _dump_mmio_region(_a, __func__, __LINE__)
-static void _dump_mmio_region(const struct ps3_mmio_region* r,
- const char* func, int line)
-{
- pr_debug("%s:%d: dev %u:%u\n", func, line, r->did.bus_id,
- r->did.dev_id);
- pr_debug("%s:%d: bus_addr %lxh\n", func, line, r->bus_addr);
- pr_debug("%s:%d: len %lxh\n", func, line, r->len);
- pr_debug("%s:%d: lpar_addr %lxh\n", func, line, r->lpar_addr);
-}
-
-int ps3_mmio_region_create(struct ps3_mmio_region *r)
-{
- int result;
-
- result = lv1_map_device_mmio_region(r->did.bus_id, r->did.dev_id,
- r->bus_addr, r->len, r->page_size, &r->lpar_addr);
-
- if (result) {
- pr_debug("%s:%d: lv1_map_device_mmio_region failed: %s\n",
- __func__, __LINE__, ps3_result(result));
- r->lpar_addr = r->len = r->bus_addr = 0;
- }
-
- dump_mmio_region(r);
- return result;
-}
-
-int ps3_free_mmio_region(struct ps3_mmio_region *r)
-{
- int result;
-
- result = lv1_unmap_device_mmio_region(r->did.bus_id, r->did.dev_id,
- r->bus_addr);
-
- if (result)
- pr_debug("%s:%d: lv1_unmap_device_mmio_region failed: %s\n",
- __func__, __LINE__, ps3_result(result));
-
- r->lpar_addr = r->len = r->bus_addr = 0;
- return result;
-}
-
-static int ps3_system_bus_match(struct device *_dev,
- struct device_driver *_drv)
-{
- int result;
- struct ps3_system_bus_driver *drv = to_ps3_system_bus_driver(_drv);
- struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
-
- result = dev->match_id == drv->match_id;
-
- pr_info("%s:%d: dev=%u(%s), drv=%u(%s): %s\n", __func__, __LINE__,
- dev->match_id, dev->core.bus_id, drv->match_id, drv->core.name,
- (result ? "match" : "miss"));
- return result;
-}
-
-static int ps3_system_bus_probe(struct device *_dev)
-{
- int result;
- struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
- struct ps3_system_bus_driver *drv =
- to_ps3_system_bus_driver(_dev->driver);
-
- result = lv1_open_device(dev->did.bus_id, dev->did.dev_id, 0);
-
- if (result) {
- pr_debug("%s:%d: lv1_open_device failed (%d)\n",
- __func__, __LINE__, result);
- result = -EACCES;
- goto clean_none;
- }
-
- if (dev->d_region->did.bus_id) {
- result = ps3_dma_region_create(dev->d_region);
-
- if (result) {
- pr_debug("%s:%d: ps3_dma_region_create failed (%d)\n",
- __func__, __LINE__, result);
- BUG_ON("check region type");
- result = -EINVAL;
- goto clean_device;
- }
- }
-
- BUG_ON(!drv);
-
- if (drv->probe)
- result = drv->probe(dev);
- else
- pr_info("%s:%d: %s no probe method\n", __func__, __LINE__,
- dev->core.bus_id);
-
- if (result) {
- pr_debug("%s:%d: drv->probe failed\n", __func__, __LINE__);
- goto clean_dma;
- }
-
- return result;
-
-clean_dma:
- ps3_dma_region_free(dev->d_region);
-clean_device:
- lv1_close_device(dev->did.bus_id, dev->did.dev_id);
-clean_none:
- return result;
-}
-
-static int ps3_system_bus_remove(struct device *_dev)
-{
- struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
- struct ps3_system_bus_driver *drv =
- to_ps3_system_bus_driver(_dev->driver);
-
- if (drv->remove)
- drv->remove(dev);
- else
- pr_info("%s:%d: %s no remove method\n", __func__, __LINE__,
- dev->core.bus_id);
-
- ps3_dma_region_free(dev->d_region);
- ps3_free_mmio_region(dev->m_region);
- lv1_close_device(dev->did.bus_id, dev->did.dev_id);
-
- return 0;
-}
-
-struct bus_type ps3_system_bus_type = {
- .name = "ps3_system_bus",
- .match = ps3_system_bus_match,
- .probe = ps3_system_bus_probe,
- .remove = ps3_system_bus_remove,
-};
-
-int __init ps3_system_bus_init(void)
-{
- int result;
-
- if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
- return 0;
-
- result = bus_register(&ps3_system_bus_type);
- BUG_ON(result);
- return result;
-}
-
-core_initcall(ps3_system_bus_init);
-
-/* Allocates a contiguous real buffer and creates mappings over it.
- * Returns the virtual address of the buffer and sets dma_handle
- * to the dma address (mapping) of the first page.
- */
-
-static void * ps3_alloc_coherent(struct device *_dev, size_t size,
- dma_addr_t *dma_handle, gfp_t flag)
-{
- int result;
- struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
- unsigned long virt_addr;
-
- BUG_ON(!dev->d_region->bus_addr);
-
- flag &= ~(__GFP_DMA | __GFP_HIGHMEM);
- flag |= __GFP_ZERO;
-
- virt_addr = __get_free_pages(flag, get_order(size));
-
- if (!virt_addr) {
- pr_debug("%s:%d: get_free_pages failed\n", __func__, __LINE__);
- goto clean_none;
- }
-
- result = ps3_dma_map(dev->d_region, virt_addr, size, dma_handle);
-
- if (result) {
- pr_debug("%s:%d: ps3_dma_map failed (%d)\n",
- __func__, __LINE__, result);
- BUG_ON("check region type");
- goto clean_alloc;
- }
-
- return (void*)virt_addr;
-
-clean_alloc:
- free_pages(virt_addr, get_order(size));
-clean_none:
- dma_handle = NULL;
- return NULL;
-}
-
-static void ps3_free_coherent(struct device *_dev, size_t size, void *vaddr,
- dma_addr_t dma_handle)
-{
- struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
-
- ps3_dma_unmap(dev->d_region, dma_handle, size);
- free_pages((unsigned long)vaddr, get_order(size));
-}
-
-/* Creates TCEs for a user provided buffer. The user buffer must be
- * contiguous real kernel storage (not vmalloc). The address of the buffer
- * passed here is the kernel (virtual) address of the buffer. The buffer
- * need not be page aligned, the dma_addr_t returned will point to the same
- * byte within the page as vaddr.
- */
-
-static dma_addr_t ps3_map_single(struct device *_dev, void *ptr, size_t size,
- enum dma_data_direction direction)
-{
- struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
- int result;
- unsigned long bus_addr;
-
- result = ps3_dma_map(dev->d_region, (unsigned long)ptr, size,
- &bus_addr);
-
- if (result) {
- pr_debug("%s:%d: ps3_dma_map failed (%d)\n",
- __func__, __LINE__, result);
- }
-
- return bus_addr;
-}
-
-static void ps3_unmap_single(struct device *_dev, dma_addr_t dma_addr,
- size_t size, enum dma_data_direction direction)
-{
- struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
- int result;
-
- result = ps3_dma_unmap(dev->d_region, dma_addr, size);
-
- if (result) {
- pr_debug("%s:%d: ps3_dma_unmap failed (%d)\n",
- __func__, __LINE__, result);
- }
-}
-
-static int ps3_map_sg(struct device *_dev, struct scatterlist *sg, int nents,
- enum dma_data_direction direction)
-{
-#if defined(CONFIG_PS3_DYNAMIC_DMA)
- BUG_ON("do");
-#endif
- return 0;
-}
-
-static void ps3_unmap_sg(struct device *_dev, struct scatterlist *sg,
- int nents, enum dma_data_direction direction)
-{
-#if defined(CONFIG_PS3_DYNAMIC_DMA)
- BUG_ON("do");
-#endif
-}
-
-static int ps3_dma_supported(struct device *_dev, u64 mask)
-{
- return 1;
-}
-
-static struct dma_mapping_ops ps3_dma_ops = {
- .alloc_coherent = ps3_alloc_coherent,
- .free_coherent = ps3_free_coherent,
- .map_single = ps3_map_single,
- .unmap_single = ps3_unmap_single,
- .map_sg = ps3_map_sg,
- .unmap_sg = ps3_unmap_sg,
- .dma_supported = ps3_dma_supported
-};
-
-/**
- * ps3_system_bus_release_device - remove a device from the system bus
- */
-
-static void ps3_system_bus_release_device(struct device *_dev)
-{
- struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
- kfree(dev);
-}
-
-/**
- * ps3_system_bus_device_register - add a device to the system bus
- *
- * ps3_system_bus_device_register() expects the dev object to be allocated
- * dynamically by the caller. The system bus takes ownership of the dev
- * object and frees the object in ps3_system_bus_release_device().
- */
-
-int ps3_system_bus_device_register(struct ps3_system_bus_device *dev)
-{
- int result;
- static unsigned int dev_count = 1;
-
- dev->core.parent = NULL;
- dev->core.bus = &ps3_system_bus_type;
- dev->core.release = ps3_system_bus_release_device;
-
- dev->core.archdata.of_node = NULL;
- dev->core.archdata.dma_ops = &ps3_dma_ops;
- dev->core.archdata.numa_node = 0;
-
- snprintf(dev->core.bus_id, sizeof(dev->core.bus_id), "sb_%02x",
- dev_count++);
-
- pr_debug("%s:%d add %s\n", __func__, __LINE__, dev->core.bus_id);
-
- result = device_register(&dev->core);
- return result;
-}
-
-EXPORT_SYMBOL_GPL(ps3_system_bus_device_register);
-
-int ps3_system_bus_driver_register(struct ps3_system_bus_driver *drv)
-{
- int result;
-
- drv->core.bus = &ps3_system_bus_type;
-
- result = driver_register(&drv->core);
- return result;
-}
-
-EXPORT_SYMBOL_GPL(ps3_system_bus_driver_register);
-
-void ps3_system_bus_driver_unregister(struct ps3_system_bus_driver *drv)
-{
- driver_unregister(&drv->core);
-}
-
-EXPORT_SYMBOL_GPL(ps3_system_bus_driver_unregister);
diff --git a/drivers/ps3/vuart.c b/drivers/ps3/vuart.c
index 6974f65bcda..746298107d6 100644
--- a/drivers/ps3/vuart.c
+++ b/drivers/ps3/vuart.c
@@ -21,8 +21,10 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
+#include <linux/workqueue.h>
#include <asm/ps3.h>
+#include <asm/firmware.h>
#include <asm/lv1call.h>
#include <asm/bitops.h>
@@ -30,7 +32,7 @@
MODULE_AUTHOR("Sony Corporation");
MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("ps3 vuart");
+MODULE_DESCRIPTION("PS3 vuart");
/**
* vuart - An inter-partition data link service.
@@ -157,7 +159,7 @@ int ps3_vuart_get_triggers(struct ps3_vuart_port_device *dev,
unsigned long size;
unsigned long val;
- result = lv1_get_virtual_uart_param(dev->port_number,
+ result = lv1_get_virtual_uart_param(dev->priv->port_number,
PARAM_TX_TRIGGER, &trig->tx);
if (result) {
@@ -166,7 +168,7 @@ int ps3_vuart_get_triggers(struct ps3_vuart_port_device *dev,
return result;
}
- result = lv1_get_virtual_uart_param(dev->port_number,
+ result = lv1_get_virtual_uart_param(dev->priv->port_number,
PARAM_RX_BUF_SIZE, &size);
if (result) {
@@ -175,7 +177,7 @@ int ps3_vuart_get_triggers(struct ps3_vuart_port_device *dev,
return result;
}
- result = lv1_get_virtual_uart_param(dev->port_number,
+ result = lv1_get_virtual_uart_param(dev->priv->port_number,
PARAM_RX_TRIGGER, &val);
if (result) {
@@ -198,7 +200,7 @@ int ps3_vuart_set_triggers(struct ps3_vuart_port_device *dev, unsigned int tx,
int result;
unsigned long size;
- result = lv1_set_virtual_uart_param(dev->port_number,
+ result = lv1_set_virtual_uart_param(dev->priv->port_number,
PARAM_TX_TRIGGER, tx);
if (result) {
@@ -207,7 +209,7 @@ int ps3_vuart_set_triggers(struct ps3_vuart_port_device *dev, unsigned int tx,
return result;
}
- result = lv1_get_virtual_uart_param(dev->port_number,
+ result = lv1_get_virtual_uart_param(dev->priv->port_number,
PARAM_RX_BUF_SIZE, &size);
if (result) {
@@ -216,7 +218,7 @@ int ps3_vuart_set_triggers(struct ps3_vuart_port_device *dev, unsigned int tx,
return result;
}
- result = lv1_set_virtual_uart_param(dev->port_number,
+ result = lv1_set_virtual_uart_param(dev->priv->port_number,
PARAM_RX_TRIGGER, size - rx);
if (result) {
@@ -232,9 +234,9 @@ int ps3_vuart_set_triggers(struct ps3_vuart_port_device *dev, unsigned int tx,
}
static int ps3_vuart_get_rx_bytes_waiting(struct ps3_vuart_port_device *dev,
- unsigned long *bytes_waiting)
+ u64 *bytes_waiting)
{
- int result = lv1_get_virtual_uart_param(dev->port_number,
+ int result = lv1_get_virtual_uart_param(dev->priv->port_number,
PARAM_RX_BYTES, bytes_waiting);
if (result)
@@ -253,10 +255,10 @@ static int ps3_vuart_set_interrupt_mask(struct ps3_vuart_port_device *dev,
dev_dbg(&dev->core, "%s:%d: %lxh\n", __func__, __LINE__, mask);
- dev->interrupt_mask = mask;
+ dev->priv->interrupt_mask = mask;
- result = lv1_set_virtual_uart_param(dev->port_number,
- PARAM_INTERRUPT_MASK, dev->interrupt_mask);
+ result = lv1_set_virtual_uart_param(dev->priv->port_number,
+ PARAM_INTERRUPT_MASK, dev->priv->interrupt_mask);
if (result)
dev_dbg(&dev->core, "%s:%d: interrupt_mask failed: %s\n",
@@ -265,62 +267,64 @@ static int ps3_vuart_set_interrupt_mask(struct ps3_vuart_port_device *dev,
return result;
}
-static int ps3_vuart_get_interrupt_mask(struct ps3_vuart_port_device *dev,
+static int ps3_vuart_get_interrupt_status(struct ps3_vuart_port_device *dev,
unsigned long *status)
{
- int result = lv1_get_virtual_uart_param(dev->port_number,
- PARAM_INTERRUPT_STATUS, status);
+ u64 tmp;
+ int result = lv1_get_virtual_uart_param(dev->priv->port_number,
+ PARAM_INTERRUPT_STATUS, &tmp);
if (result)
dev_dbg(&dev->core, "%s:%d: interrupt_status failed: %s\n",
__func__, __LINE__, ps3_result(result));
+ *status = tmp & dev->priv->interrupt_mask;
+
dev_dbg(&dev->core, "%s:%d: m %lxh, s %lxh, m&s %lxh\n",
- __func__, __LINE__, dev->interrupt_mask, *status,
- dev->interrupt_mask & *status);
+ __func__, __LINE__, dev->priv->interrupt_mask, tmp, *status);
return result;
}
int ps3_vuart_enable_interrupt_tx(struct ps3_vuart_port_device *dev)
{
- return (dev->interrupt_mask & INTERRUPT_MASK_TX) ? 0
- : ps3_vuart_set_interrupt_mask(dev, dev->interrupt_mask
+ return (dev->priv->interrupt_mask & INTERRUPT_MASK_TX) ? 0
+ : ps3_vuart_set_interrupt_mask(dev, dev->priv->interrupt_mask
| INTERRUPT_MASK_TX);
}
int ps3_vuart_enable_interrupt_rx(struct ps3_vuart_port_device *dev)
{
- return (dev->interrupt_mask & INTERRUPT_MASK_RX) ? 0
- : ps3_vuart_set_interrupt_mask(dev, dev->interrupt_mask
+ return (dev->priv->interrupt_mask & INTERRUPT_MASK_RX) ? 0
+ : ps3_vuart_set_interrupt_mask(dev, dev->priv->interrupt_mask
| INTERRUPT_MASK_RX);
}
int ps3_vuart_enable_interrupt_disconnect(struct ps3_vuart_port_device *dev)
{
- return (dev->interrupt_mask & INTERRUPT_MASK_DISCONNECT) ? 0
- : ps3_vuart_set_interrupt_mask(dev, dev->interrupt_mask
+ return (dev->priv->interrupt_mask & INTERRUPT_MASK_DISCONNECT) ? 0
+ : ps3_vuart_set_interrupt_mask(dev, dev->priv->interrupt_mask
| INTERRUPT_MASK_DISCONNECT);
}
int ps3_vuart_disable_interrupt_tx(struct ps3_vuart_port_device *dev)
{
- return (dev->interrupt_mask & INTERRUPT_MASK_TX)
- ? ps3_vuart_set_interrupt_mask(dev, dev->interrupt_mask
+ return (dev->priv->interrupt_mask & INTERRUPT_MASK_TX)
+ ? ps3_vuart_set_interrupt_mask(dev, dev->priv->interrupt_mask
& ~INTERRUPT_MASK_TX) : 0;
}
int ps3_vuart_disable_interrupt_rx(struct ps3_vuart_port_device *dev)
{
- return (dev->interrupt_mask & INTERRUPT_MASK_RX)
- ? ps3_vuart_set_interrupt_mask(dev, dev->interrupt_mask
+ return (dev->priv->interrupt_mask & INTERRUPT_MASK_RX)
+ ? ps3_vuart_set_interrupt_mask(dev, dev->priv->interrupt_mask
& ~INTERRUPT_MASK_RX) : 0;
}
int ps3_vuart_disable_interrupt_disconnect(struct ps3_vuart_port_device *dev)
{
- return (dev->interrupt_mask & INTERRUPT_MASK_DISCONNECT)
- ? ps3_vuart_set_interrupt_mask(dev, dev->interrupt_mask
+ return (dev->priv->interrupt_mask & INTERRUPT_MASK_DISCONNECT)
+ ? ps3_vuart_set_interrupt_mask(dev, dev->priv->interrupt_mask
& ~INTERRUPT_MASK_DISCONNECT) : 0;
}
@@ -335,9 +339,7 @@ static int ps3_vuart_raw_write(struct ps3_vuart_port_device *dev,
{
int result;
- dev_dbg(&dev->core, "%s:%d: %xh\n", __func__, __LINE__, bytes);
-
- result = lv1_write_virtual_uart(dev->port_number,
+ result = lv1_write_virtual_uart(dev->priv->port_number,
ps3_mm_phys_to_lpar(__pa(buf)), bytes, bytes_written);
if (result) {
@@ -346,10 +348,10 @@ static int ps3_vuart_raw_write(struct ps3_vuart_port_device *dev,
return result;
}
- dev->stats.bytes_written += *bytes_written;
+ dev->priv->stats.bytes_written += *bytes_written;
- dev_dbg(&dev->core, "%s:%d: wrote %lxh/%xh=>%lxh\n", __func__,
- __LINE__, *bytes_written, bytes, dev->stats.bytes_written);
+ dev_dbg(&dev->core, "%s:%d: wrote %lxh/%xh=>%lxh\n", __func__, __LINE__,
+ *bytes_written, bytes, dev->priv->stats.bytes_written);
return result;
}
@@ -367,7 +369,7 @@ static int ps3_vuart_raw_read(struct ps3_vuart_port_device *dev, void* buf,
dev_dbg(&dev->core, "%s:%d: %xh\n", __func__, __LINE__, bytes);
- result = lv1_read_virtual_uart(dev->port_number,
+ result = lv1_read_virtual_uart(dev->priv->port_number,
ps3_mm_phys_to_lpar(__pa(buf)), bytes, bytes_read);
if (result) {
@@ -376,15 +378,58 @@ static int ps3_vuart_raw_read(struct ps3_vuart_port_device *dev, void* buf,
return result;
}
- dev->stats.bytes_read += *bytes_read;
+ dev->priv->stats.bytes_read += *bytes_read;
dev_dbg(&dev->core, "%s:%d: read %lxh/%xh=>%lxh\n", __func__, __LINE__,
- *bytes_read, bytes, dev->stats.bytes_read);
+ *bytes_read, bytes, dev->priv->stats.bytes_read);
return result;
}
/**
+ * ps3_vuart_clear_rx_bytes - Discard bytes received.
+ * @bytes: Max byte count to discard, zero = all pending.
+ *
+ * Used to clear pending rx interrupt source. Will not block.
+ */
+
+void ps3_vuart_clear_rx_bytes(struct ps3_vuart_port_device *dev,
+ unsigned int bytes)
+{
+ int result;
+ u64 bytes_waiting;
+ void* tmp;
+
+ result = ps3_vuart_get_rx_bytes_waiting(dev, &bytes_waiting);
+
+ BUG_ON(result);
+
+ bytes = bytes ? min(bytes, (unsigned int)bytes_waiting) : bytes_waiting;
+
+ dev_dbg(&dev->core, "%s:%d: %u\n", __func__, __LINE__, bytes);
+
+ if (!bytes)
+ return;
+
+ /* Add some extra space for recently arrived data. */
+
+ bytes += 128;
+
+ tmp = kmalloc(bytes, GFP_KERNEL);
+
+ if (!tmp)
+ return;
+
+ ps3_vuart_raw_read(dev, tmp, bytes, &bytes_waiting);
+
+ kfree(tmp);
+
+ /* Don't include these bytes in the stats. */
+
+ dev->priv->stats.bytes_read -= bytes_waiting;
+}
+
+/**
* struct list_buffer - An element for a port device fifo buffer list.
*/
@@ -416,14 +461,14 @@ int ps3_vuart_write(struct ps3_vuart_port_device *dev, const void* buf,
dev_dbg(&dev->core, "%s:%d: %u(%xh) bytes\n", __func__, __LINE__,
bytes, bytes);
- spin_lock_irqsave(&dev->tx_list.lock, flags);
+ spin_lock_irqsave(&dev->priv->tx_list.lock, flags);
- if (list_empty(&dev->tx_list.head)) {
+ if (list_empty(&dev->priv->tx_list.head)) {
unsigned long bytes_written;
result = ps3_vuart_raw_write(dev, buf, bytes, &bytes_written);
- spin_unlock_irqrestore(&dev->tx_list.lock, flags);
+ spin_unlock_irqrestore(&dev->priv->tx_list.lock, flags);
if (result) {
dev_dbg(&dev->core,
@@ -441,7 +486,7 @@ int ps3_vuart_write(struct ps3_vuart_port_device *dev, const void* buf,
bytes -= bytes_written;
buf += bytes_written;
} else
- spin_unlock_irqrestore(&dev->tx_list.lock, flags);
+ spin_unlock_irqrestore(&dev->priv->tx_list.lock, flags);
lb = kmalloc(sizeof(struct list_buffer) + bytes, GFP_KERNEL);
@@ -454,10 +499,10 @@ int ps3_vuart_write(struct ps3_vuart_port_device *dev, const void* buf,
lb->tail = lb->data + bytes;
lb->dbg_number = ++dbg_number;
- spin_lock_irqsave(&dev->tx_list.lock, flags);
- list_add_tail(&lb->link, &dev->tx_list.head);
+ spin_lock_irqsave(&dev->priv->tx_list.lock, flags);
+ list_add_tail(&lb->link, &dev->priv->tx_list.head);
ps3_vuart_enable_interrupt_tx(dev);
- spin_unlock_irqrestore(&dev->tx_list.lock, flags);
+ spin_unlock_irqrestore(&dev->priv->tx_list.lock, flags);
dev_dbg(&dev->core, "%s:%d: queued buf_%lu, %xh bytes\n",
__func__, __LINE__, lb->dbg_number, bytes);
@@ -484,47 +529,83 @@ int ps3_vuart_read(struct ps3_vuart_port_device *dev, void* buf,
dev_dbg(&dev->core, "%s:%d: %u(%xh) bytes\n", __func__, __LINE__,
bytes, bytes);
- spin_lock_irqsave(&dev->rx_list.lock, flags);
+ spin_lock_irqsave(&dev->priv->rx_list.lock, flags);
- if (dev->rx_list.bytes_held < bytes) {
- spin_unlock_irqrestore(&dev->rx_list.lock, flags);
+ if (dev->priv->rx_list.bytes_held < bytes) {
+ spin_unlock_irqrestore(&dev->priv->rx_list.lock, flags);
dev_dbg(&dev->core, "%s:%d: starved for %lxh bytes\n",
- __func__, __LINE__, bytes - dev->rx_list.bytes_held);
+ __func__, __LINE__,
+ bytes - dev->priv->rx_list.bytes_held);
return -EAGAIN;
}
- list_for_each_entry_safe(lb, n, &dev->rx_list.head, link) {
+ list_for_each_entry_safe(lb, n, &dev->priv->rx_list.head, link) {
bytes_read = min((unsigned int)(lb->tail - lb->head), bytes);
memcpy(buf, lb->head, bytes_read);
buf += bytes_read;
bytes -= bytes_read;
- dev->rx_list.bytes_held -= bytes_read;
+ dev->priv->rx_list.bytes_held -= bytes_read;
if (bytes_read < lb->tail - lb->head) {
lb->head += bytes_read;
- spin_unlock_irqrestore(&dev->rx_list.lock, flags);
-
- dev_dbg(&dev->core,
- "%s:%d: dequeued buf_%lu, %lxh bytes\n",
- __func__, __LINE__, lb->dbg_number, bytes_read);
+ dev_dbg(&dev->core, "%s:%d: buf_%lu: dequeued %lxh "
+ "bytes\n", __func__, __LINE__, lb->dbg_number,
+ bytes_read);
+ spin_unlock_irqrestore(&dev->priv->rx_list.lock, flags);
return 0;
}
- dev_dbg(&dev->core, "%s:%d free buf_%lu\n", __func__, __LINE__,
- lb->dbg_number);
+ dev_dbg(&dev->core, "%s:%d: buf_%lu: free, dequeued %lxh "
+ "bytes\n", __func__, __LINE__, lb->dbg_number,
+ bytes_read);
list_del(&lb->link);
kfree(lb);
}
- spin_unlock_irqrestore(&dev->rx_list.lock, flags);
- dev_dbg(&dev->core, "%s:%d: dequeued buf_%lu, %xh bytes\n",
- __func__, __LINE__, lb->dbg_number, bytes);
+ spin_unlock_irqrestore(&dev->priv->rx_list.lock, flags);
+ return 0;
+}
+
+int ps3_vuart_read_async(struct ps3_vuart_port_device *dev, work_func_t func,
+ unsigned int bytes)
+{
+ unsigned long flags;
+
+ if(dev->priv->work.trigger) {
+ dev_dbg(&dev->core, "%s:%d: warning, multiple calls\n",
+ __func__, __LINE__);
+ return -EAGAIN;
+ }
+
+ BUG_ON(!bytes);
+
+ PREPARE_WORK(&dev->priv->work.work, func);
+
+ spin_lock_irqsave(&dev->priv->work.lock, flags);
+ if(dev->priv->rx_list.bytes_held >= bytes) {
+ dev_dbg(&dev->core, "%s:%d: schedule_work %xh bytes\n",
+ __func__, __LINE__, bytes);
+ schedule_work(&dev->priv->work.work);
+ spin_unlock_irqrestore(&dev->priv->work.lock, flags);
+ return 0;
+ }
+
+ dev->priv->work.trigger = bytes;
+ spin_unlock_irqrestore(&dev->priv->work.lock, flags);
+
+ dev_dbg(&dev->core, "%s:%d: waiting for %u(%xh) bytes\n", __func__,
+ __LINE__, bytes, bytes);
return 0;
}
+void ps3_vuart_cancel_async(struct ps3_vuart_port_device *dev)
+{
+ dev->priv->work.trigger = 0;
+}
+
/**
* ps3_vuart_handle_interrupt_tx - third stage transmit interrupt handler
*
@@ -542,9 +623,9 @@ static int ps3_vuart_handle_interrupt_tx(struct ps3_vuart_port_device *dev)
dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
- spin_lock_irqsave(&dev->tx_list.lock, flags);
+ spin_lock_irqsave(&dev->priv->tx_list.lock, flags);
- list_for_each_entry_safe(lb, n, &dev->tx_list.head, link) {
+ list_for_each_entry_safe(lb, n, &dev->priv->tx_list.head, link) {
unsigned long bytes_written;
@@ -578,7 +659,7 @@ static int ps3_vuart_handle_interrupt_tx(struct ps3_vuart_port_device *dev)
ps3_vuart_disable_interrupt_tx(dev);
port_full:
- spin_unlock_irqrestore(&dev->tx_list.lock, flags);
+ spin_unlock_irqrestore(&dev->priv->tx_list.lock, flags);
dev_dbg(&dev->core, "%s:%d wrote %lxh bytes total\n",
__func__, __LINE__, bytes_total);
return result;
@@ -609,7 +690,7 @@ static int ps3_vuart_handle_interrupt_rx(struct ps3_vuart_port_device *dev)
BUG_ON(!bytes);
- /* add some extra space for recently arrived data */
+ /* Add some extra space for recently arrived data. */
bytes += 128;
@@ -624,14 +705,23 @@ static int ps3_vuart_handle_interrupt_rx(struct ps3_vuart_port_device *dev)
lb->tail = lb->data + bytes;
lb->dbg_number = ++dbg_number;
- spin_lock_irqsave(&dev->rx_list.lock, flags);
- list_add_tail(&lb->link, &dev->rx_list.head);
- dev->rx_list.bytes_held += bytes;
- spin_unlock_irqrestore(&dev->rx_list.lock, flags);
+ spin_lock_irqsave(&dev->priv->rx_list.lock, flags);
+ list_add_tail(&lb->link, &dev->priv->rx_list.head);
+ dev->priv->rx_list.bytes_held += bytes;
+ spin_unlock_irqrestore(&dev->priv->rx_list.lock, flags);
- dev_dbg(&dev->core, "%s:%d: queued buf_%lu, %lxh bytes\n",
+ dev_dbg(&dev->core, "%s:%d: buf_%lu: queued %lxh bytes\n",
__func__, __LINE__, lb->dbg_number, bytes);
+ spin_lock_irqsave(&dev->priv->work.lock, flags);
+ if(dev->priv->work.trigger
+ && dev->priv->rx_list.bytes_held >= dev->priv->work.trigger) {
+ dev_dbg(&dev->core, "%s:%d: schedule_work %lxh bytes\n",
+ __func__, __LINE__, dev->priv->work.trigger);
+ dev->priv->work.trigger = 0;
+ schedule_work(&dev->priv->work.work);
+ }
+ spin_unlock_irqrestore(&dev->priv->work.lock, flags);
return 0;
}
@@ -656,7 +746,7 @@ static int ps3_vuart_handle_port_interrupt(struct ps3_vuart_port_device *dev)
int result;
unsigned long status;
- result = ps3_vuart_get_interrupt_mask(dev, &status);
+ result = ps3_vuart_get_interrupt_status(dev, &status);
if (result)
return result;
@@ -665,21 +755,21 @@ static int ps3_vuart_handle_port_interrupt(struct ps3_vuart_port_device *dev)
status);
if (status & INTERRUPT_MASK_DISCONNECT) {
- dev->stats.disconnect_interrupts++;
+ dev->priv->stats.disconnect_interrupts++;
result = ps3_vuart_handle_interrupt_disconnect(dev);
if (result)
ps3_vuart_disable_interrupt_disconnect(dev);
}
if (status & INTERRUPT_MASK_TX) {
- dev->stats.tx_interrupts++;
+ dev->priv->stats.tx_interrupts++;
result = ps3_vuart_handle_interrupt_tx(dev);
if (result)
ps3_vuart_disable_interrupt_tx(dev);
}
if (status & INTERRUPT_MASK_RX) {
- dev->stats.rx_interrupts++;
+ dev->priv->stats.rx_interrupts++;
result = ps3_vuart_handle_interrupt_rx(dev);
if (result)
ps3_vuart_disable_interrupt_rx(dev);
@@ -688,12 +778,13 @@ static int ps3_vuart_handle_port_interrupt(struct ps3_vuart_port_device *dev)
return 0;
}
-struct vuart_private {
- unsigned int in_use;
+struct vuart_bus_priv {
+ const struct ports_bmp bmp;
unsigned int virq;
+ struct semaphore probe_mutex;
+ int use_count;
struct ps3_vuart_port_device *devices[PORT_COUNT];
- const struct ports_bmp bmp;
-};
+} static vuart_bus_priv;
/**
* ps3_vuart_irq_handler - first stage interrupt handler
@@ -705,25 +796,25 @@ struct vuart_private {
static irqreturn_t ps3_vuart_irq_handler(int irq, void *_private)
{
- struct vuart_private *private;
+ struct vuart_bus_priv *bus_priv;
BUG_ON(!_private);
- private = (struct vuart_private *)_private;
+ bus_priv = (struct vuart_bus_priv *)_private;
while (1) {
unsigned int port;
- dump_ports_bmp(&private->bmp);
+ dump_ports_bmp(&bus_priv->bmp);
- port = (BITS_PER_LONG - 1) - __ilog2(private->bmp.status);
+ port = (BITS_PER_LONG - 1) - __ilog2(bus_priv->bmp.status);
if (port == BITS_PER_LONG)
break;
BUG_ON(port >= PORT_COUNT);
- BUG_ON(!private->devices[port]);
+ BUG_ON(!bus_priv->devices[port]);
- ps3_vuart_handle_port_interrupt(private->devices[port]);
+ ps3_vuart_handle_port_interrupt(bus_priv->devices[port]);
}
return IRQ_HANDLED;
@@ -744,12 +835,10 @@ static int ps3_vuart_match(struct device *_dev, struct device_driver *_drv)
return result;
}
-static struct vuart_private vuart_private;
-
static int ps3_vuart_probe(struct device *_dev)
{
int result;
- unsigned long tmp;
+ unsigned int port_number;
struct ps3_vuart_port_device *dev = to_ps3_vuart_port_device(_dev);
struct ps3_vuart_port_driver *drv =
to_ps3_vuart_port_driver(_dev->driver);
@@ -758,7 +847,12 @@ static int ps3_vuart_probe(struct device *_dev)
BUG_ON(!drv);
- result = ps3_vuart_match_id_to_port(dev->match_id, &dev->port_number);
+ down(&vuart_bus_priv.probe_mutex);
+
+ /* Setup vuart_bus_priv.devices[]. */
+
+ result = ps3_vuart_match_id_to_port(dev->match_id,
+ &port_number);
if (result) {
dev_dbg(&dev->core, "%s:%d: unknown match_id (%d)\n",
@@ -767,24 +861,41 @@ static int ps3_vuart_probe(struct device *_dev)
goto fail_match;
}
- if (vuart_private.devices[dev->port_number]) {
+ if (vuart_bus_priv.devices[port_number]) {
dev_dbg(&dev->core, "%s:%d: port busy (%d)\n", __func__,
- __LINE__, dev->port_number);
+ __LINE__, port_number);
result = -EBUSY;
goto fail_match;
}
- vuart_private.devices[dev->port_number] = dev;
+ vuart_bus_priv.devices[port_number] = dev;
+
+ /* Setup dev->priv. */
+
+ dev->priv = kzalloc(sizeof(struct ps3_vuart_port_priv), GFP_KERNEL);
+
+ if (!dev->priv) {
+ result = -ENOMEM;
+ goto fail_alloc;
+ }
+
+ dev->priv->port_number = port_number;
- INIT_LIST_HEAD(&dev->tx_list.head);
- spin_lock_init(&dev->tx_list.lock);
- INIT_LIST_HEAD(&dev->rx_list.head);
- spin_lock_init(&dev->rx_list.lock);
+ INIT_LIST_HEAD(&dev->priv->tx_list.head);
+ spin_lock_init(&dev->priv->tx_list.lock);
- vuart_private.in_use++;
- if (vuart_private.in_use == 1) {
- result = ps3_alloc_vuart_irq((void*)&vuart_private.bmp.status,
- &vuart_private.virq);
+ INIT_LIST_HEAD(&dev->priv->rx_list.head);
+ spin_lock_init(&dev->priv->rx_list.lock);
+
+ INIT_WORK(&dev->priv->work.work, NULL);
+ spin_lock_init(&dev->priv->work.lock);
+ dev->priv->work.trigger = 0;
+ dev->priv->work.dev = dev;
+
+ if (++vuart_bus_priv.use_count == 1) {
+
+ result = ps3_alloc_vuart_irq(PS3_BINDING_CPU_ANY,
+ (void*)&vuart_bus_priv.bmp.status, &vuart_bus_priv.virq);
if (result) {
dev_dbg(&dev->core,
@@ -794,8 +905,8 @@ static int ps3_vuart_probe(struct device *_dev)
goto fail_alloc_irq;
}
- result = request_irq(vuart_private.virq, ps3_vuart_irq_handler,
- IRQF_DISABLED, "vuart", &vuart_private);
+ result = request_irq(vuart_bus_priv.virq, ps3_vuart_irq_handler,
+ IRQF_DISABLED, "vuart", &vuart_bus_priv);
if (result) {
dev_info(&dev->core, "%s:%d: request_irq failed (%d)\n",
@@ -804,10 +915,11 @@ static int ps3_vuart_probe(struct device *_dev)
}
}
- ps3_vuart_set_interrupt_mask(dev, INTERRUPT_MASK_RX);
-
/* clear stale pending interrupts */
- ps3_vuart_get_interrupt_mask(dev, &tmp);
+
+ ps3_vuart_clear_rx_bytes(dev, 0);
+
+ ps3_vuart_set_interrupt_mask(dev, INTERRUPT_MASK_RX);
ps3_vuart_set_triggers(dev, 1, 1);
@@ -822,20 +934,27 @@ static int ps3_vuart_probe(struct device *_dev)
if (result) {
dev_dbg(&dev->core, "%s:%d: drv->probe failed\n",
__func__, __LINE__);
+ down(&vuart_bus_priv.probe_mutex);
goto fail_probe;
}
+ up(&vuart_bus_priv.probe_mutex);
+
return result;
fail_probe:
+ ps3_vuart_set_interrupt_mask(dev, 0);
fail_request_irq:
- vuart_private.in_use--;
- if (!vuart_private.in_use) {
- ps3_free_vuart_irq(vuart_private.virq);
- vuart_private.virq = NO_IRQ;
- }
+ ps3_free_vuart_irq(vuart_bus_priv.virq);
+ vuart_bus_priv.virq = NO_IRQ;
fail_alloc_irq:
+ --vuart_bus_priv.use_count;
+ kfree(dev->priv);
+ dev->priv = NULL;
+fail_alloc:
+ vuart_bus_priv.devices[port_number] = 0;
fail_match:
+ up(&vuart_bus_priv.probe_mutex);
dev_dbg(&dev->core, "%s:%d failed\n", __func__, __LINE__);
return result;
}
@@ -846,10 +965,12 @@ static int ps3_vuart_remove(struct device *_dev)
struct ps3_vuart_port_driver *drv =
to_ps3_vuart_port_driver(_dev->driver);
+ down(&vuart_bus_priv.probe_mutex);
+
dev_dbg(&dev->core, "%s:%d: %s\n", __func__, __LINE__,
dev->core.bus_id);
- BUG_ON(vuart_private.in_use < 1);
+ BUG_ON(vuart_bus_priv.use_count < 1);
if (drv->remove)
drv->remove(dev);
@@ -857,47 +978,76 @@ static int ps3_vuart_remove(struct device *_dev)
dev_dbg(&dev->core, "%s:%d: %s no remove method\n", __func__,
__LINE__, dev->core.bus_id);
- vuart_private.in_use--;
+ vuart_bus_priv.devices[dev->priv->port_number] = 0;
- if (!vuart_private.in_use) {
- free_irq(vuart_private.virq, &vuart_private);
- ps3_free_vuart_irq(vuart_private.virq);
- vuart_private.virq = NO_IRQ;
+ if (--vuart_bus_priv.use_count == 0) {
+ BUG();
+ free_irq(vuart_bus_priv.virq, &vuart_bus_priv);
+ ps3_free_vuart_irq(vuart_bus_priv.virq);
+ vuart_bus_priv.virq = NO_IRQ;
}
+
+ kfree(dev->priv);
+ dev->priv = NULL;
+
+ up(&vuart_bus_priv.probe_mutex);
return 0;
}
+static void ps3_vuart_shutdown(struct device *_dev)
+{
+ struct ps3_vuart_port_device *dev = to_ps3_vuart_port_device(_dev);
+ struct ps3_vuart_port_driver *drv =
+ to_ps3_vuart_port_driver(_dev->driver);
+
+ dev_dbg(&dev->core, "%s:%d: %s\n", __func__, __LINE__,
+ dev->core.bus_id);
+
+ if (drv->shutdown)
+ drv->shutdown(dev);
+ else
+ dev_dbg(&dev->core, "%s:%d: %s no shutdown method\n", __func__,
+ __LINE__, dev->core.bus_id);
+}
+
/**
- * ps3_vuart - The vuart instance.
+ * ps3_vuart_bus - The vuart bus instance.
*
* The vuart is managed as a bus that port devices connect to.
*/
-struct bus_type ps3_vuart = {
+struct bus_type ps3_vuart_bus = {
.name = "ps3_vuart",
.match = ps3_vuart_match,
.probe = ps3_vuart_probe,
.remove = ps3_vuart_remove,
+ .shutdown = ps3_vuart_shutdown,
};
-int __init ps3_vuart_init(void)
+int __init ps3_vuart_bus_init(void)
{
int result;
pr_debug("%s:%d:\n", __func__, __LINE__);
- result = bus_register(&ps3_vuart);
+
+ if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
+ return 0;
+
+ init_MUTEX(&vuart_bus_priv.probe_mutex);
+ result = bus_register(&ps3_vuart_bus);
BUG_ON(result);
+
return result;
}
-void __exit ps3_vuart_exit(void)
+void __exit ps3_vuart_bus_exit(void)
{
pr_debug("%s:%d:\n", __func__, __LINE__);
- bus_unregister(&ps3_vuart);
+ bus_unregister(&ps3_vuart_bus);
}
-core_initcall(ps3_vuart_init);
-module_exit(ps3_vuart_exit);
+core_initcall(ps3_vuart_bus_init);
+module_exit(ps3_vuart_bus_exit);
/**
* ps3_vuart_port_release_device - Remove a vuart port device.
@@ -905,11 +1055,14 @@ module_exit(ps3_vuart_exit);
static void ps3_vuart_port_release_device(struct device *_dev)
{
- struct ps3_vuart_port_device *dev = to_ps3_vuart_port_device(_dev);
#if defined(DEBUG)
- memset(dev, 0xad, sizeof(struct ps3_vuart_port_device));
+ struct ps3_vuart_port_device *dev = to_ps3_vuart_port_device(_dev);
+
+ dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
+
+ BUG_ON(dev->priv && "forgot to free");
+ memset(&dev->core, 0, sizeof(dev->core));
#endif
- kfree(dev);
}
/**
@@ -918,11 +1071,12 @@ static void ps3_vuart_port_release_device(struct device *_dev)
int ps3_vuart_port_device_register(struct ps3_vuart_port_device *dev)
{
- int result;
static unsigned int dev_count = 1;
+ BUG_ON(dev->priv && "forgot to free");
+
dev->core.parent = NULL;
- dev->core.bus = &ps3_vuart;
+ dev->core.bus = &ps3_vuart_bus;
dev->core.release = ps3_vuart_port_release_device;
snprintf(dev->core.bus_id, sizeof(dev->core.bus_id), "vuart_%02x",
@@ -930,9 +1084,7 @@ int ps3_vuart_port_device_register(struct ps3_vuart_port_device *dev)
dev_dbg(&dev->core, "%s:%d register\n", __func__, __LINE__);
- result = device_register(&dev->core);
-
- return result;
+ return device_register(&dev->core);
}
EXPORT_SYMBOL_GPL(ps3_vuart_port_device_register);
@@ -946,7 +1098,7 @@ int ps3_vuart_port_driver_register(struct ps3_vuart_port_driver *drv)
int result;
pr_debug("%s:%d: (%s)\n", __func__, __LINE__, drv->core.name);
- drv->core.bus = &ps3_vuart;
+ drv->core.bus = &ps3_vuart_bus;
result = driver_register(&drv->core);
return result;
}
@@ -959,6 +1111,7 @@ EXPORT_SYMBOL_GPL(ps3_vuart_port_driver_register);
void ps3_vuart_port_driver_unregister(struct ps3_vuart_port_driver *drv)
{
+ pr_debug("%s:%d: (%s)\n", __func__, __LINE__, drv->core.name);
driver_unregister(&drv->core);
}
diff --git a/drivers/ps3/vuart.h b/drivers/ps3/vuart.h
index 28fd89f0c8a..1be992d568c 100644
--- a/drivers/ps3/vuart.h
+++ b/drivers/ps3/vuart.h
@@ -21,6 +21,8 @@
#if !defined(_PS3_VUART_H)
#define _PS3_VUART_H
+#include <asm/ps3.h>
+
struct ps3_vuart_stats {
unsigned long bytes_written;
unsigned long bytes_read;
@@ -29,17 +31,21 @@ struct ps3_vuart_stats {
unsigned long disconnect_interrupts;
};
+struct ps3_vuart_work {
+ struct work_struct work;
+ unsigned long trigger;
+ spinlock_t lock;
+ struct ps3_vuart_port_device* dev; /* to convert work to device */
+};
+
/**
- * struct ps3_vuart_port_device - a device on a vuart port
+ * struct ps3_vuart_port_priv - private vuart device data.
*/
-struct ps3_vuart_port_device {
- enum ps3_match_id match_id;
- struct device core;
-
- /* private driver variables */
+struct ps3_vuart_port_priv {
unsigned int port_number;
- unsigned long interrupt_mask;
+ u64 interrupt_mask;
+
struct {
spinlock_t lock;
struct list_head head;
@@ -50,6 +56,7 @@ struct ps3_vuart_port_device {
struct list_head head;
} rx_list;
struct ps3_vuart_stats stats;
+ struct ps3_vuart_work work;
};
/**
@@ -61,6 +68,7 @@ struct ps3_vuart_port_driver {
struct device_driver core;
int (*probe)(struct ps3_vuart_port_device *);
int (*remove)(struct ps3_vuart_port_device *);
+ void (*shutdown)(struct ps3_vuart_port_device *);
int (*tx_event)(struct ps3_vuart_port_device *dev);
int (*rx_event)(struct ps3_vuart_port_device *dev);
int (*disconnect_event)(struct ps3_vuart_port_device *dev);
@@ -68,13 +76,9 @@ struct ps3_vuart_port_driver {
/* int (*resume)(struct ps3_vuart_port_device *); */
};
-int ps3_vuart_port_device_register(struct ps3_vuart_port_device *dev);
int ps3_vuart_port_driver_register(struct ps3_vuart_port_driver *drv);
void ps3_vuart_port_driver_unregister(struct ps3_vuart_port_driver *drv);
-int ps3_vuart_write(struct ps3_vuart_port_device *dev,
- const void* buf, unsigned int bytes);
-int ps3_vuart_read(struct ps3_vuart_port_device *dev, void* buf,
- unsigned int bytes);
+
static inline struct ps3_vuart_port_driver *to_ps3_vuart_port_driver(
struct device_driver *_drv)
{
@@ -85,10 +89,22 @@ static inline struct ps3_vuart_port_device *to_ps3_vuart_port_device(
{
return container_of(_dev, struct ps3_vuart_port_device, core);
}
+static inline struct ps3_vuart_port_device *ps3_vuart_work_to_port_device(
+ struct work_struct *_work)
+{
+ struct ps3_vuart_work *vw = container_of(_work, struct ps3_vuart_work,
+ work);
+ return vw->dev;
+}
int ps3_vuart_write(struct ps3_vuart_port_device *dev, const void* buf,
unsigned int bytes);
int ps3_vuart_read(struct ps3_vuart_port_device *dev, void* buf,
unsigned int bytes);
+int ps3_vuart_read_async(struct ps3_vuart_port_device *dev, work_func_t func,
+ unsigned int bytes);
+void ps3_vuart_cancel_async(struct ps3_vuart_port_device *dev);
+void ps3_vuart_clear_rx_bytes(struct ps3_vuart_port_device *dev,
+ unsigned int bytes);
#endif
diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c
index 7bf7b2c8824..f935c1f71a5 100644
--- a/drivers/rapidio/rio-scan.c
+++ b/drivers/rapidio/rio-scan.c
@@ -326,14 +326,17 @@ static struct rio_dev *rio_setup_device(struct rio_net *net,
rio_mport_read_config_32(port, destid, hopcount, RIO_DST_OPS_CAR,
&rdev->dst_ops);
- if (rio_device_has_destid(port, rdev->src_ops, rdev->dst_ops)
- && do_enum) {
- rio_set_device_id(port, destid, hopcount, next_destid);
- rdev->destid = next_destid++;
- if (next_destid == port->host_deviceid)
- next_destid++;
+ if (rio_device_has_destid(port, rdev->src_ops, rdev->dst_ops)) {
+ if (do_enum) {
+ rio_set_device_id(port, destid, hopcount, next_destid);
+ rdev->destid = next_destid++;
+ if (next_destid == port->host_deviceid)
+ next_destid++;
+ } else
+ rdev->destid = rio_get_device_id(port, destid, hopcount);
} else
- rdev->destid = rio_get_device_id(port, destid, hopcount);
+ /* Switch device has an associated destID */
+ rdev->destid = RIO_INVALID_DESTID;
/* If a PE has both switch and other functions, show it as a switch */
if (rio_is_switch(rdev)) {
@@ -347,7 +350,7 @@ static struct rio_dev *rio_setup_device(struct rio_net *net,
}
rswitch->switchid = next_switchid;
rswitch->hopcount = hopcount;
- rswitch->destid = 0xffff;
+ rswitch->destid = destid;
/* Initialize switch route table */
for (rdid = 0; rdid < RIO_MAX_ROUTE_ENTRIES; rdid++)
rswitch->route_table[rdid] = RIO_INVALID_ROUTE;
@@ -422,7 +425,7 @@ rio_sport_is_active(struct rio_mport *port, u16 destid, u8 hopcount, int sport)
/**
* rio_route_add_entry- Add a route entry to a switch routing table
* @mport: Master port to send transaction
- * @rdev: Switch device
+ * @rswitch: Switch device
* @table: Routing table ID
* @route_destid: Destination ID to be routed
* @route_port: Port number to be routed
@@ -434,18 +437,18 @@ rio_sport_is_active(struct rio_mport *port, u16 destid, u8 hopcount, int sport)
* %RIO_GLOBAL_TABLE in @table. Returns %0 on success or %-EINVAL
* on failure.
*/
-static int rio_route_add_entry(struct rio_mport *mport, struct rio_dev *rdev,
+static int rio_route_add_entry(struct rio_mport *mport, struct rio_switch *rswitch,
u16 table, u16 route_destid, u8 route_port)
{
- return rdev->rswitch->add_entry(mport, rdev->rswitch->destid,
- rdev->rswitch->hopcount, table,
+ return rswitch->add_entry(mport, rswitch->destid,
+ rswitch->hopcount, table,
route_destid, route_port);
}
/**
* rio_route_get_entry- Read a route entry in a switch routing table
* @mport: Master port to send transaction
- * @rdev: Switch device
+ * @rswitch: Switch device
* @table: Routing table ID
* @route_destid: Destination ID to be routed
* @route_port: Pointer to read port number into
@@ -458,11 +461,11 @@ static int rio_route_add_entry(struct rio_mport *mport, struct rio_dev *rdev,
* on failure.
*/
static int
-rio_route_get_entry(struct rio_mport *mport, struct rio_dev *rdev, u16 table,
+rio_route_get_entry(struct rio_mport *mport, struct rio_switch *rswitch, u16 table,
u16 route_destid, u8 * route_port)
{
- return rdev->rswitch->get_entry(mport, rdev->rswitch->destid,
- rdev->rswitch->hopcount, table,
+ return rswitch->get_entry(mport, rswitch->destid,
+ rswitch->hopcount, table,
route_destid, route_port);
}
@@ -552,6 +555,8 @@ static int rio_enum_peer(struct rio_net *net, struct rio_mport *port,
int port_num;
int num_ports;
int cur_destid;
+ int sw_destid;
+ int sw_inport;
struct rio_dev *rdev;
u16 destid;
int tmp;
@@ -594,15 +599,17 @@ static int rio_enum_peer(struct rio_net *net, struct rio_mport *port,
if (rio_is_switch(rdev)) {
next_switchid++;
+ sw_inport = rio_get_swpinfo_inport(port, RIO_ANY_DESTID, hopcount);
+ rio_route_add_entry(port, rdev->rswitch, RIO_GLOBAL_TABLE,
+ port->host_deviceid, sw_inport);
+ rdev->rswitch->route_table[port->host_deviceid] = sw_inport;
for (destid = 0; destid < next_destid; destid++) {
- rio_route_add_entry(port, rdev, RIO_GLOBAL_TABLE,
- destid, rio_get_swpinfo_inport(port,
- RIO_ANY_DESTID,
- hopcount));
- rdev->rswitch->route_table[destid] =
- rio_get_swpinfo_inport(port, RIO_ANY_DESTID,
- hopcount);
+ if (destid == port->host_deviceid)
+ continue;
+ rio_route_add_entry(port, rdev->rswitch, RIO_GLOBAL_TABLE,
+ destid, sw_inport);
+ rdev->rswitch->route_table[destid] = sw_inport;
}
num_ports =
@@ -610,9 +617,9 @@ static int rio_enum_peer(struct rio_net *net, struct rio_mport *port,
pr_debug(
"RIO: found %s (vid %4.4x did %4.4x) with %d ports\n",
rio_name(rdev), rdev->vid, rdev->did, num_ports);
+ sw_destid = next_destid;
for (port_num = 0; port_num < num_ports; port_num++) {
- if (rio_get_swpinfo_inport
- (port, RIO_ANY_DESTID, hopcount) == port_num)
+ if (sw_inport == port_num)
continue;
cur_destid = next_destid;
@@ -622,7 +629,7 @@ static int rio_enum_peer(struct rio_net *net, struct rio_mport *port,
pr_debug(
"RIO: scanning device on port %d\n",
port_num);
- rio_route_add_entry(port, rdev,
+ rio_route_add_entry(port, rdev->rswitch,
RIO_GLOBAL_TABLE,
RIO_ANY_DESTID, port_num);
@@ -633,7 +640,9 @@ static int rio_enum_peer(struct rio_net *net, struct rio_mport *port,
if (next_destid > cur_destid) {
for (destid = cur_destid;
destid < next_destid; destid++) {
- rio_route_add_entry(port, rdev,
+ if (destid == port->host_deviceid)
+ continue;
+ rio_route_add_entry(port, rdev->rswitch,
RIO_GLOBAL_TABLE,
destid,
port_num);
@@ -641,10 +650,18 @@ static int rio_enum_peer(struct rio_net *net, struct rio_mport *port,
route_table[destid] =
port_num;
}
- rdev->rswitch->destid = cur_destid;
}
}
}
+
+ /* Check for empty switch */
+ if (next_destid == sw_destid) {
+ next_destid++;
+ if (next_destid == port->host_deviceid)
+ next_destid++;
+ }
+
+ rdev->rswitch->destid = sw_destid;
} else
pr_debug("RIO: found %s (vid %4.4x did %4.4x)\n",
rio_name(rdev), rdev->vid, rdev->did);
@@ -721,7 +738,7 @@ rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid,
port_num);
for (ndestid = 0; ndestid < RIO_ANY_DESTID;
ndestid++) {
- rio_route_get_entry(port, rdev,
+ rio_route_get_entry(port, rdev->rswitch,
RIO_GLOBAL_TABLE,
ndestid,
&route_port);
@@ -798,6 +815,44 @@ static struct rio_net __devinit *rio_alloc_net(struct rio_mport *port)
}
/**
+ * rio_update_route_tables- Updates route tables in switches
+ * @port: Master port associated with the RIO network
+ *
+ * For each enumerated device, ensure that each switch in a system
+ * has correct routing entries. Add routes for devices that where
+ * unknown dirung the first enumeration pass through the switch.
+ */
+static void rio_update_route_tables(struct rio_mport *port)
+{
+ struct rio_dev *rdev;
+ struct rio_switch *rswitch;
+ u8 sport;
+ u16 destid;
+
+ list_for_each_entry(rdev, &rio_devices, global_list) {
+
+ destid = (rio_is_switch(rdev))?rdev->rswitch->destid:rdev->destid;
+
+ list_for_each_entry(rswitch, &rio_switches, node) {
+
+ if (rio_is_switch(rdev) && (rdev->rswitch == rswitch))
+ continue;
+
+ if (RIO_INVALID_ROUTE == rswitch->route_table[destid]) {
+
+ sport = rio_get_swpinfo_inport(port,
+ rswitch->destid, rswitch->hopcount);
+
+ if (rswitch->add_entry) {
+ rio_route_add_entry(port, rswitch, RIO_GLOBAL_TABLE, destid, sport);
+ rswitch->route_table[destid] = sport;
+ }
+ }
+ }
+ }
+}
+
+/**
* rio_enum_mport- Start enumeration through a master port
* @mport: Master port to send transactions
*
@@ -838,6 +893,7 @@ int rio_enum_mport(struct rio_mport *mport)
rc = -EBUSY;
goto out;
}
+ rio_update_route_tables(mport);
rio_clear_locks(mport);
} else {
printk(KERN_INFO "RIO: master port %d link inactive\n",
@@ -865,8 +921,8 @@ static void rio_build_route_tables(void)
if (rio_is_switch(rdev))
for (i = 0; i < RIO_MAX_ROUTE_ENTRIES; i++) {
if (rio_route_get_entry
- (rdev->net->hport, rdev, RIO_GLOBAL_TABLE, i,
- &sport) < 0)
+ (rdev->net->hport, rdev->rswitch, RIO_GLOBAL_TABLE,
+ i, &sport) < 0)
continue;
rdev->rswitch->route_table[i] = sport;
}
diff --git a/drivers/rapidio/rio-sysfs.c b/drivers/rapidio/rio-sysfs.c
index 5687b8fcbf9..eed91434417 100644
--- a/drivers/rapidio/rio-sysfs.c
+++ b/drivers/rapidio/rio-sysfs.c
@@ -14,7 +14,6 @@
#include <linux/rio.h>
#include <linux/rio_drv.h>
#include <linux/stat.h>
-#include <linux/sched.h> /* for capable() */
#include "rio.h"
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 09660e2ab05..deef29646e0 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -1,4 +1,4 @@
-\#
+#
# RTC class/drivers configuration
#
@@ -95,6 +95,29 @@ config RTC_INTF_DEV_UIE_EMUL
comment "RTC drivers"
depends on RTC_CLASS
+# this 'CMOS' RTC driver is arch dependent because <asm-generic/rtc.h>
+# requires <asm/mc146818rtc.h> defining CMOS_READ/CMOS_WRITE, and a
+# global rtc_lock ... it's not yet just another platform_device.
+
+config RTC_DRV_CMOS
+ tristate "PC-style 'CMOS' real time clock"
+ depends on RTC_CLASS && (X86 || ALPHA || ARM26 || ARM \
+ || M32R || ATARI || POWERPC)
+ help
+ Say "yes" here to get direct support for the real time clock
+ found in every PC or ACPI-based system, and some other boards.
+ Specifically the original MC146818, compatibles like those in
+ PC south bridges, the DS12887 or M48T86, some multifunction
+ or LPC bus chips, and so on.
+
+ Your system will need to define the platform device used by
+ this driver, otherwise it won't be accessible. This means
+ you can safely enable this driver if you don't know whether
+ or not your board has this kind of hardware.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-cmos.
+
config RTC_DRV_X1205
tristate "Xicor/Intersil X1205"
depends on RTC_CLASS && I2C
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index e6beedacc96..92bfe1b3a5f 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o
obj-$(CONFIG_RTC_INTF_PROC) += rtc-proc.o
obj-$(CONFIG_RTC_INTF_DEV) += rtc-dev.o
+obj-$(CONFIG_RTC_DRV_CMOS) += rtc-cmos.o
obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o
obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o
obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o
diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c
index a724ab49a79..ac0e68e2f02 100644
--- a/drivers/rtc/rtc-at91rm9200.c
+++ b/drivers/rtc/rtc-at91rm9200.c
@@ -164,6 +164,7 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
tm.tm_min = alrm->time.tm_min;
tm.tm_sec = alrm->time.tm_sec;
+ at91_sys_write(AT91_RTC_IDR, AT91_RTC_ALARM);
at91_sys_write(AT91_RTC_TIMALR,
BIN2BCD(tm.tm_sec) << 0
| BIN2BCD(tm.tm_min) << 8
@@ -174,6 +175,9 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
| BIN2BCD(tm.tm_mday) << 24
| AT91_RTC_DATEEN | AT91_RTC_MTHEN);
+ if (alrm->enabled)
+ at91_sys_write(AT91_RTC_IER, AT91_RTC_ALARM);
+
pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__,
at91_alarm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour,
tm.tm_min, tm.tm_sec);
@@ -303,6 +307,12 @@ static int __init at91_rtc_probe(struct platform_device *pdev)
return ret;
}
+ /* cpu init code should really have flagged this device as
+ * being wake-capable; if it didn't, do that here.
+ */
+ if (!device_can_wakeup(&pdev->dev))
+ device_init_wakeup(&pdev->dev, 1);
+
rtc = rtc_device_register(pdev->name, &pdev->dev,
&at91_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc)) {
@@ -310,7 +320,6 @@ static int __init at91_rtc_probe(struct platform_device *pdev)
return PTR_ERR(rtc);
}
platform_set_drvdata(pdev, rtc);
- device_init_wakeup(&pdev->dev, 1);
printk(KERN_INFO "AT91 Real Time Clock driver.\n");
return 0;
@@ -319,7 +328,7 @@ static int __init at91_rtc_probe(struct platform_device *pdev)
/*
* Disable and remove the RTC driver
*/
-static int __devexit at91_rtc_remove(struct platform_device *pdev)
+static int __exit at91_rtc_remove(struct platform_device *pdev)
{
struct rtc_device *rtc = platform_get_drvdata(pdev);
@@ -331,7 +340,6 @@ static int __devexit at91_rtc_remove(struct platform_device *pdev)
rtc_device_unregister(rtc);
platform_set_drvdata(pdev, NULL);
- device_init_wakeup(&pdev->dev, 0);
return 0;
}
@@ -404,8 +412,7 @@ static int at91_rtc_resume(struct platform_device *pdev)
#endif
static struct platform_driver at91_rtc_driver = {
- .probe = at91_rtc_probe,
- .remove = at91_rtc_remove,
+ .remove = __exit_p(at91_rtc_remove),
.suspend = at91_rtc_suspend,
.resume = at91_rtc_resume,
.driver = {
@@ -416,7 +423,7 @@ static struct platform_driver at91_rtc_driver = {
static int __init at91_rtc_init(void)
{
- return platform_driver_register(&at91_rtc_driver);
+ return platform_driver_probe(&at91_rtc_driver, at91_rtc_probe);
}
static void __exit at91_rtc_exit(void)
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
new file mode 100644
index 00000000000..85bf795abdc
--- /dev/null
+++ b/drivers/rtc/rtc-cmos.c
@@ -0,0 +1,725 @@
+/*
+ * RTC class driver for "CMOS RTC": PCs, ACPI, etc
+ *
+ * Copyright (C) 1996 Paul Gortmaker (drivers/char/rtc.c)
+ * Copyright (C) 2006 David Brownell (convert to new framework)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under 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 original "cmos clock" chip was an MC146818 chip, now obsolete.
+ * That defined the register interface now provided by all PCs, some
+ * non-PC systems, and incorporated into ACPI. Modern PC chipsets
+ * integrate an MC146818 clone in their southbridge, and boards use
+ * that instead of discrete clones like the DS12887 or M48T86. There
+ * are also clones that connect using the LPC bus.
+ *
+ * That register API is also used directly by various other drivers
+ * (notably for integrated NVRAM), infrastructure (x86 has code to
+ * bypass the RTC framework, directly reading the RTC during boot
+ * and updating minutes/seconds for systems using NTP synch) and
+ * utilities (like userspace 'hwclock', if no /dev node exists).
+ *
+ * So **ALL** calls to CMOS_READ and CMOS_WRITE must be done with
+ * interrupts disabled, holding the global rtc_lock, to exclude those
+ * other drivers and utilities on correctly configured systems.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/mod_devicetable.h>
+
+/* this is for "generic access to PC-style RTC" using CMOS_READ/CMOS_WRITE */
+#include <asm-generic/rtc.h>
+
+
+struct cmos_rtc {
+ struct rtc_device *rtc;
+ struct device *dev;
+ int irq;
+ struct resource *iomem;
+
+ u8 suspend_ctrl;
+
+ /* newer hardware extends the original register set */
+ u8 day_alrm;
+ u8 mon_alrm;
+ u8 century;
+};
+
+/* both platform and pnp busses use negative numbers for invalid irqs */
+#define is_valid_irq(n) ((n) >= 0)
+
+static const char driver_name[] = "rtc_cmos";
+
+/*----------------------------------------------------------------*/
+
+static int cmos_read_time(struct device *dev, struct rtc_time *t)
+{
+ /* REVISIT: if the clock has a "century" register, use
+ * that instead of the heuristic in get_rtc_time().
+ * That'll make Y3K compatility (year > 2070) easy!
+ */
+ get_rtc_time(t);
+ return 0;
+}
+
+static int cmos_set_time(struct device *dev, struct rtc_time *t)
+{
+ /* REVISIT: set the "century" register if available
+ *
+ * NOTE: this ignores the issue whereby updating the seconds
+ * takes effect exactly 500ms after we write the register.
+ * (Also queueing and other delays before we get this far.)
+ */
+ return set_rtc_time(t);
+}
+
+static int cmos_read_alarm(struct device *dev, struct rtc_wkalrm *t)
+{
+ struct cmos_rtc *cmos = dev_get_drvdata(dev);
+ unsigned char rtc_control;
+
+ if (!is_valid_irq(cmos->irq))
+ return -EIO;
+
+ /* Basic alarms only support hour, minute, and seconds fields.
+ * Some also support day and month, for alarms up to a year in
+ * the future.
+ */
+ t->time.tm_mday = -1;
+ t->time.tm_mon = -1;
+
+ spin_lock_irq(&rtc_lock);
+ t->time.tm_sec = CMOS_READ(RTC_SECONDS_ALARM);
+ t->time.tm_min = CMOS_READ(RTC_MINUTES_ALARM);
+ t->time.tm_hour = CMOS_READ(RTC_HOURS_ALARM);
+
+ if (cmos->day_alrm) {
+ t->time.tm_mday = CMOS_READ(cmos->day_alrm);
+ if (!t->time.tm_mday)
+ t->time.tm_mday = -1;
+
+ if (cmos->mon_alrm) {
+ t->time.tm_mon = CMOS_READ(cmos->mon_alrm);
+ if (!t->time.tm_mon)
+ t->time.tm_mon = -1;
+ }
+ }
+
+ rtc_control = CMOS_READ(RTC_CONTROL);
+ spin_unlock_irq(&rtc_lock);
+
+ /* REVISIT this assumes PC style usage: always BCD */
+
+ if (((unsigned)t->time.tm_sec) < 0x60)
+ t->time.tm_sec = BCD2BIN(t->time.tm_sec);
+ else
+ t->time.tm_sec = -1;
+ if (((unsigned)t->time.tm_min) < 0x60)
+ t->time.tm_min = BCD2BIN(t->time.tm_min);
+ else
+ t->time.tm_min = -1;
+ if (((unsigned)t->time.tm_hour) < 0x24)
+ t->time.tm_hour = BCD2BIN(t->time.tm_hour);
+ else
+ t->time.tm_hour = -1;
+
+ if (cmos->day_alrm) {
+ if (((unsigned)t->time.tm_mday) <= 0x31)
+ t->time.tm_mday = BCD2BIN(t->time.tm_mday);
+ else
+ t->time.tm_mday = -1;
+ if (cmos->mon_alrm) {
+ if (((unsigned)t->time.tm_mon) <= 0x12)
+ t->time.tm_mon = BCD2BIN(t->time.tm_mon) - 1;
+ else
+ t->time.tm_mon = -1;
+ }
+ }
+ t->time.tm_year = -1;
+
+ t->enabled = !!(rtc_control & RTC_AIE);
+ t->pending = 0;
+
+ return 0;
+}
+
+static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t)
+{
+ struct cmos_rtc *cmos = dev_get_drvdata(dev);
+ unsigned char mon, mday, hrs, min, sec;
+ unsigned char rtc_control, rtc_intr;
+
+ if (!is_valid_irq(cmos->irq))
+ return -EIO;
+
+ /* REVISIT this assumes PC style usage: always BCD */
+
+ /* Writing 0xff means "don't care" or "match all". */
+
+ mon = t->time.tm_mon;
+ mon = (mon < 12) ? BIN2BCD(mon) : 0xff;
+ mon++;
+
+ mday = t->time.tm_mday;
+ mday = (mday >= 1 && mday <= 31) ? BIN2BCD(mday) : 0xff;
+
+ hrs = t->time.tm_hour;
+ hrs = (hrs < 24) ? BIN2BCD(hrs) : 0xff;
+
+ min = t->time.tm_min;
+ min = (min < 60) ? BIN2BCD(min) : 0xff;
+
+ sec = t->time.tm_sec;
+ sec = (sec < 60) ? BIN2BCD(sec) : 0xff;
+
+ spin_lock_irq(&rtc_lock);
+
+ /* next rtc irq must not be from previous alarm setting */
+ rtc_control = CMOS_READ(RTC_CONTROL);
+ rtc_control &= ~RTC_AIE;
+ CMOS_WRITE(rtc_control, RTC_CONTROL);
+ rtc_intr = CMOS_READ(RTC_INTR_FLAGS);
+ if (rtc_intr)
+ rtc_update_irq(&cmos->rtc->class_dev, 1, rtc_intr);
+
+ /* update alarm */
+ CMOS_WRITE(hrs, RTC_HOURS_ALARM);
+ CMOS_WRITE(min, RTC_MINUTES_ALARM);
+ CMOS_WRITE(sec, RTC_SECONDS_ALARM);
+
+ /* the system may support an "enhanced" alarm */
+ if (cmos->day_alrm) {
+ CMOS_WRITE(mday, cmos->day_alrm);
+ if (cmos->mon_alrm)
+ CMOS_WRITE(mon, cmos->mon_alrm);
+ }
+
+ if (t->enabled) {
+ rtc_control |= RTC_AIE;
+ CMOS_WRITE(rtc_control, RTC_CONTROL);
+ rtc_intr = CMOS_READ(RTC_INTR_FLAGS);
+ if (rtc_intr)
+ rtc_update_irq(&cmos->rtc->class_dev, 1, rtc_intr);
+ }
+
+ spin_unlock_irq(&rtc_lock);
+
+ return 0;
+}
+
+static int cmos_set_freq(struct device *dev, int freq)
+{
+ struct cmos_rtc *cmos = dev_get_drvdata(dev);
+ int f;
+ unsigned long flags;
+
+ if (!is_valid_irq(cmos->irq))
+ return -ENXIO;
+
+ /* 0 = no irqs; 1 = 2^15 Hz ... 15 = 2^0 Hz */
+ f = ffs(freq);
+ if (f != 0) {
+ if (f-- > 16 || freq != (1 << f))
+ return -EINVAL;
+ f = 16 - f;
+ }
+
+ spin_lock_irqsave(&rtc_lock, flags);
+ CMOS_WRITE(RTC_REF_CLCK_32KHZ | f, RTC_FREQ_SELECT);
+ spin_unlock_irqrestore(&rtc_lock, flags);
+
+ return 0;
+}
+
+#if defined(CONFIG_RTC_INTF_DEV) || defined(CONFIG_RTC_INTF_DEV_MODULE)
+
+static int
+cmos_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
+{
+ struct cmos_rtc *cmos = dev_get_drvdata(dev);
+ unsigned char rtc_control, rtc_intr;
+ unsigned long flags;
+
+ switch (cmd) {
+ case RTC_AIE_OFF:
+ case RTC_AIE_ON:
+ case RTC_UIE_OFF:
+ case RTC_UIE_ON:
+ case RTC_PIE_OFF:
+ case RTC_PIE_ON:
+ if (!is_valid_irq(cmos->irq))
+ return -EINVAL;
+ break;
+ default:
+ return -ENOIOCTLCMD;
+ }
+
+ spin_lock_irqsave(&rtc_lock, flags);
+ rtc_control = CMOS_READ(RTC_CONTROL);
+ switch (cmd) {
+ case RTC_AIE_OFF: /* alarm off */
+ rtc_control &= ~RTC_AIE;
+ break;
+ case RTC_AIE_ON: /* alarm on */
+ rtc_control |= RTC_AIE;
+ break;
+ case RTC_UIE_OFF: /* update off */
+ rtc_control &= ~RTC_UIE;
+ break;
+ case RTC_UIE_ON: /* update on */
+ rtc_control |= RTC_UIE;
+ break;
+ case RTC_PIE_OFF: /* periodic off */
+ rtc_control &= ~RTC_PIE;
+ break;
+ case RTC_PIE_ON: /* periodic on */
+ rtc_control |= RTC_PIE;
+ break;
+ }
+ CMOS_WRITE(rtc_control, RTC_CONTROL);
+ rtc_intr = CMOS_READ(RTC_INTR_FLAGS);
+ if (rtc_intr)
+ rtc_update_irq(&cmos->rtc->class_dev, 1, rtc_intr);
+ spin_unlock_irqrestore(&rtc_lock, flags);
+ return 0;
+}
+
+#else
+#define cmos_rtc_ioctl NULL
+#endif
+
+#if defined(CONFIG_RTC_INTF_PROC) || defined(CONFIG_RTC_INTF_PROC_MODULE)
+
+static int cmos_procfs(struct device *dev, struct seq_file *seq)
+{
+ struct cmos_rtc *cmos = dev_get_drvdata(dev);
+ unsigned char rtc_control, valid;
+
+ spin_lock_irq(&rtc_lock);
+ rtc_control = CMOS_READ(RTC_CONTROL);
+ valid = CMOS_READ(RTC_VALID);
+ spin_unlock_irq(&rtc_lock);
+
+ /* NOTE: at least ICH6 reports battery status using a different
+ * (non-RTC) bit; and SQWE is ignored on many current systems.
+ */
+ return seq_printf(seq,
+ "periodic_IRQ\t: %s\n"
+ "update_IRQ\t: %s\n"
+ // "square_wave\t: %s\n"
+ // "BCD\t\t: %s\n"
+ "DST_enable\t: %s\n"
+ "periodic_freq\t: %d\n"
+ "batt_status\t: %s\n",
+ (rtc_control & RTC_PIE) ? "yes" : "no",
+ (rtc_control & RTC_UIE) ? "yes" : "no",
+ // (rtc_control & RTC_SQWE) ? "yes" : "no",
+ // (rtc_control & RTC_DM_BINARY) ? "no" : "yes",
+ (rtc_control & RTC_DST_EN) ? "yes" : "no",
+ cmos->rtc->irq_freq,
+ (valid & RTC_VRT) ? "okay" : "dead");
+}
+
+#else
+#define cmos_procfs NULL
+#endif
+
+static const struct rtc_class_ops cmos_rtc_ops = {
+ .ioctl = cmos_rtc_ioctl,
+ .read_time = cmos_read_time,
+ .set_time = cmos_set_time,
+ .read_alarm = cmos_read_alarm,
+ .set_alarm = cmos_set_alarm,
+ .proc = cmos_procfs,
+ .irq_set_freq = cmos_set_freq,
+};
+
+/*----------------------------------------------------------------*/
+
+static struct cmos_rtc cmos_rtc;
+
+static irqreturn_t cmos_interrupt(int irq, void *p)
+{
+ u8 irqstat;
+
+ spin_lock(&rtc_lock);
+ irqstat = CMOS_READ(RTC_INTR_FLAGS);
+ spin_unlock(&rtc_lock);
+
+ if (irqstat) {
+ /* NOTE: irqstat may have e.g. RTC_PF set
+ * even when RTC_PIE is clear...
+ */
+ rtc_update_irq(p, 1, irqstat);
+ return IRQ_HANDLED;
+ } else
+ return IRQ_NONE;
+}
+
+#ifdef CONFIG_PNPACPI
+#define is_pnpacpi() 1
+#define INITSECTION
+
+#else
+#define is_pnpacpi() 0
+#define INITSECTION __init
+#endif
+
+static int INITSECTION
+cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
+{
+ struct cmos_rtc_board_info *info = dev->platform_data;
+ int retval = 0;
+ unsigned char rtc_control;
+
+ /* there can be only one ... */
+ if (cmos_rtc.dev)
+ return -EBUSY;
+
+ if (!ports)
+ return -ENODEV;
+
+ cmos_rtc.irq = rtc_irq;
+ cmos_rtc.iomem = ports;
+
+ /* For ACPI systems the info comes from the FADT. On others,
+ * board specific setup provides it as appropriate.
+ */
+ if (info) {
+ cmos_rtc.day_alrm = info->rtc_day_alarm;
+ cmos_rtc.mon_alrm = info->rtc_mon_alarm;
+ cmos_rtc.century = info->rtc_century;
+ }
+
+ cmos_rtc.rtc = rtc_device_register(driver_name, dev,
+ &cmos_rtc_ops, THIS_MODULE);
+ if (IS_ERR(cmos_rtc.rtc))
+ return PTR_ERR(cmos_rtc.rtc);
+
+ cmos_rtc.dev = dev;
+ dev_set_drvdata(dev, &cmos_rtc);
+
+ /* platform and pnp busses handle resources incompatibly.
+ *
+ * REVISIT for non-x86 systems we may need to handle io memory
+ * resources: ioremap them, and request_mem_region().
+ */
+ if (is_pnpacpi()) {
+ retval = request_resource(&ioport_resource, ports);
+ if (retval < 0) {
+ dev_dbg(dev, "i/o registers already in use\n");
+ goto cleanup0;
+ }
+ }
+ rename_region(ports, cmos_rtc.rtc->class_dev.class_id);
+
+ spin_lock_irq(&rtc_lock);
+
+ /* force periodic irq to CMOS reset default of 1024Hz;
+ *
+ * REVISIT it's been reported that at least one x86_64 ALI mobo
+ * doesn't use 32KHz here ... for portability we might need to
+ * do something about other clock frequencies.
+ */
+ CMOS_WRITE(RTC_REF_CLCK_32KHZ | 0x06, RTC_FREQ_SELECT);
+ cmos_rtc.rtc->irq_freq = 1024;
+
+ /* disable irqs.
+ *
+ * NOTE after changing RTC_xIE bits we always read INTR_FLAGS;
+ * allegedly some older rtcs need that to handle irqs properly
+ */
+ rtc_control = CMOS_READ(RTC_CONTROL);
+ rtc_control &= ~(RTC_PIE | RTC_AIE | RTC_UIE);
+ CMOS_WRITE(rtc_control, RTC_CONTROL);
+ CMOS_READ(RTC_INTR_FLAGS);
+
+ spin_unlock_irq(&rtc_lock);
+
+ /* FIXME teach the alarm code how to handle binary mode;
+ * <asm-generic/rtc.h> doesn't know 12-hour mode either.
+ */
+ if (!(rtc_control & RTC_24H) || (rtc_control & (RTC_DM_BINARY))) {
+ dev_dbg(dev, "only 24-hr BCD mode supported\n");
+ retval = -ENXIO;
+ goto cleanup1;
+ }
+
+ if (is_valid_irq(rtc_irq))
+ retval = request_irq(rtc_irq, cmos_interrupt, IRQF_DISABLED,
+ cmos_rtc.rtc->class_dev.class_id,
+ &cmos_rtc.rtc->class_dev);
+ if (retval < 0) {
+ dev_dbg(dev, "IRQ %d is already in use\n", rtc_irq);
+ goto cleanup1;
+ }
+
+ /* REVISIT optionally make 50 or 114 bytes NVRAM available,
+ * like rtc-ds1553, rtc-ds1742 ... this will often include
+ * registers for century, and day/month alarm.
+ */
+
+ pr_info("%s: alarms up to one %s%s\n",
+ cmos_rtc.rtc->class_dev.class_id,
+ is_valid_irq(rtc_irq)
+ ? (cmos_rtc.mon_alrm
+ ? "year"
+ : (cmos_rtc.day_alrm
+ ? "month" : "day"))
+ : "no",
+ cmos_rtc.century ? ", y3k" : ""
+ );
+
+ return 0;
+
+cleanup1:
+ rename_region(ports, NULL);
+cleanup0:
+ rtc_device_unregister(cmos_rtc.rtc);
+ return retval;
+}
+
+static void cmos_do_shutdown(void)
+{
+ unsigned char rtc_control;
+
+ spin_lock_irq(&rtc_lock);
+ rtc_control = CMOS_READ(RTC_CONTROL);
+ rtc_control &= ~(RTC_PIE|RTC_AIE|RTC_UIE);
+ CMOS_WRITE(rtc_control, RTC_CONTROL);
+ CMOS_READ(RTC_INTR_FLAGS);
+ spin_unlock_irq(&rtc_lock);
+}
+
+static void __exit cmos_do_remove(struct device *dev)
+{
+ struct cmos_rtc *cmos = dev_get_drvdata(dev);
+
+ cmos_do_shutdown();
+
+ if (is_pnpacpi())
+ release_resource(cmos->iomem);
+ rename_region(cmos->iomem, NULL);
+
+ if (is_valid_irq(cmos->irq))
+ free_irq(cmos->irq, &cmos_rtc.rtc->class_dev);
+
+ rtc_device_unregister(cmos_rtc.rtc);
+
+ cmos_rtc.dev = NULL;
+ dev_set_drvdata(dev, NULL);
+}
+
+#ifdef CONFIG_PM
+
+static int cmos_suspend(struct device *dev, pm_message_t mesg)
+{
+ struct cmos_rtc *cmos = dev_get_drvdata(dev);
+ int do_wake = device_may_wakeup(dev);
+ unsigned char tmp, irqstat;
+
+ /* only the alarm might be a wakeup event source */
+ spin_lock_irq(&rtc_lock);
+ cmos->suspend_ctrl = tmp = CMOS_READ(RTC_CONTROL);
+ if (tmp & (RTC_PIE|RTC_AIE|RTC_UIE)) {
+ if (do_wake)
+ tmp &= ~(RTC_PIE|RTC_UIE);
+ else
+ tmp &= ~(RTC_PIE|RTC_AIE|RTC_UIE);
+ CMOS_WRITE(tmp, RTC_CONTROL);
+ irqstat = CMOS_READ(RTC_INTR_FLAGS);
+ } else
+ irqstat = 0;
+ spin_unlock_irq(&rtc_lock);
+
+ if (irqstat)
+ rtc_update_irq(&cmos->rtc->class_dev, 1, irqstat);
+
+ /* ACPI HOOK: enable ACPI_EVENT_RTC when (tmp & RTC_AIE)
+ * ... it'd be best if we could do that under rtc_lock.
+ */
+
+ pr_debug("%s: suspend%s, ctrl %02x\n",
+ cmos_rtc.rtc->class_dev.class_id,
+ (tmp & RTC_AIE) ? ", alarm may wake" : "",
+ tmp);
+
+ return 0;
+}
+
+static int cmos_resume(struct device *dev)
+{
+ struct cmos_rtc *cmos = dev_get_drvdata(dev);
+ unsigned char tmp = cmos->suspend_ctrl;
+
+ /* REVISIT: a mechanism to resync the system clock (jiffies)
+ * on resume should be portable between platforms ...
+ */
+
+ /* re-enable any irqs previously active */
+ if (tmp & (RTC_PIE|RTC_AIE|RTC_UIE)) {
+
+ /* ACPI HOOK: disable ACPI_EVENT_RTC when (tmp & RTC_AIE) */
+
+ spin_lock_irq(&rtc_lock);
+ CMOS_WRITE(tmp, RTC_CONTROL);
+ tmp = CMOS_READ(RTC_INTR_FLAGS);
+ spin_unlock_irq(&rtc_lock);
+ if (tmp)
+ rtc_update_irq(&cmos->rtc->class_dev, 1, tmp);
+ }
+
+ pr_debug("%s: resume, ctrl %02x\n",
+ cmos_rtc.rtc->class_dev.class_id,
+ cmos->suspend_ctrl);
+
+
+ return 0;
+}
+
+#else
+#define cmos_suspend NULL
+#define cmos_resume NULL
+#endif
+
+/*----------------------------------------------------------------*/
+
+/* The "CMOS" RTC normally lives on the platform_bus. On ACPI systems,
+ * the device node may alternatively be created as a PNP device.
+ */
+
+#ifdef CONFIG_PNPACPI
+
+#include <linux/pnp.h>
+
+static int __devinit
+cmos_pnp_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
+{
+ /* REVISIT paranoia argues for a shutdown notifier, since PNP
+ * drivers can't provide shutdown() methods to disable IRQs.
+ * Or better yet, fix PNP to allow those methods...
+ */
+ return cmos_do_probe(&pnp->dev,
+ &pnp->res.port_resource[0],
+ pnp->res.irq_resource[0].start);
+}
+
+static void __exit cmos_pnp_remove(struct pnp_dev *pnp)
+{
+ cmos_do_remove(&pnp->dev);
+}
+
+#ifdef CONFIG_PM
+
+static int cmos_pnp_suspend(struct pnp_dev *pnp, pm_message_t mesg)
+{
+ return cmos_suspend(&pnp->dev, mesg);
+}
+
+static int cmos_pnp_resume(struct pnp_dev *pnp)
+{
+ return cmos_resume(&pnp->dev);
+}
+
+#else
+#define cmos_pnp_suspend NULL
+#define cmos_pnp_resume NULL
+#endif
+
+
+static const struct pnp_device_id rtc_ids[] = {
+ { .id = "PNP0b00", },
+ { .id = "PNP0b01", },
+ { .id = "PNP0b02", },
+ { },
+};
+MODULE_DEVICE_TABLE(pnp, rtc_ids);
+
+static struct pnp_driver cmos_pnp_driver = {
+ .name = (char *) driver_name,
+ .id_table = rtc_ids,
+ .probe = cmos_pnp_probe,
+ .remove = __exit_p(cmos_pnp_remove),
+
+ /* flag ensures resume() gets called, and stops syslog spam */
+ .flags = PNP_DRIVER_RES_DO_NOT_CHANGE,
+ .suspend = cmos_pnp_suspend,
+ .resume = cmos_pnp_resume,
+};
+
+static int __init cmos_init(void)
+{
+ return pnp_register_driver(&cmos_pnp_driver);
+}
+module_init(cmos_init);
+
+static void __exit cmos_exit(void)
+{
+ pnp_unregister_driver(&cmos_pnp_driver);
+}
+module_exit(cmos_exit);
+
+#else /* no PNPACPI */
+
+/*----------------------------------------------------------------*/
+
+/* Platform setup should have set up an RTC device, when PNPACPI is
+ * unavailable ... this is the normal case, common even on PCs.
+ */
+
+static int __init cmos_platform_probe(struct platform_device *pdev)
+{
+ return cmos_do_probe(&pdev->dev,
+ platform_get_resource(pdev, IORESOURCE_IO, 0),
+ platform_get_irq(pdev, 0));
+}
+
+static int __exit cmos_platform_remove(struct platform_device *pdev)
+{
+ cmos_do_remove(&pdev->dev);
+ return 0;
+}
+
+static void cmos_platform_shutdown(struct platform_device *pdev)
+{
+ cmos_do_shutdown();
+}
+
+static struct platform_driver cmos_platform_driver = {
+ .remove = __exit_p(cmos_platform_remove),
+ .shutdown = cmos_platform_shutdown,
+ .driver = {
+ .name = (char *) driver_name,
+ .suspend = cmos_suspend,
+ .resume = cmos_resume,
+ }
+};
+
+static int __init cmos_init(void)
+{
+ return platform_driver_probe(&cmos_platform_driver,
+ cmos_platform_probe);
+}
+module_init(cmos_init);
+
+static void __exit cmos_exit(void)
+{
+ platform_driver_unregister(&cmos_platform_driver);
+}
+module_exit(cmos_exit);
+
+
+#endif /* !PNPACPI */
+
+MODULE_AUTHOR("David Brownell");
+MODULE_DESCRIPTION("Driver for PC-style 'CMOS' RTCs");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c
index 94d3df62a5f..137330b8636 100644
--- a/drivers/rtc/rtc-dev.c
+++ b/drivers/rtc/rtc-dev.c
@@ -305,7 +305,7 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file,
case RTC_IRQP_READ:
if (ops->irq_set_freq)
- err = put_user(rtc->irq_freq, (unsigned long *) arg);
+ err = put_user(rtc->irq_freq, (unsigned long __user *)uarg);
break;
case RTC_IRQP_SET:
@@ -384,7 +384,7 @@ static int rtc_dev_fasync(int fd, struct file *file, int on)
return fasync_helper(fd, file, on, &rtc->async_queue);
}
-static struct file_operations rtc_dev_fops = {
+static const struct file_operations rtc_dev_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = rtc_dev_read,
diff --git a/drivers/rtc/rtc-ds1553.c b/drivers/rtc/rtc-ds1553.c
index 001eb1123a6..e27176c0e18 100644
--- a/drivers/rtc/rtc-ds1553.c
+++ b/drivers/rtc/rtc-ds1553.c
@@ -297,7 +297,7 @@ static struct bin_attribute ds1553_nvram_attr = {
.write = ds1553_nvram_write,
};
-static int __init ds1553_rtc_probe(struct platform_device *pdev)
+static int __devinit ds1553_rtc_probe(struct platform_device *pdev)
{
struct rtc_device *rtc;
struct resource *res;
diff --git a/drivers/rtc/rtc-ds1672.c b/drivers/rtc/rtc-ds1672.c
index 205fa28593b..dfef1637bfb 100644
--- a/drivers/rtc/rtc-ds1672.c
+++ b/drivers/rtc/rtc-ds1672.c
@@ -199,7 +199,7 @@ static int ds1672_probe(struct i2c_adapter *adapter, int address, int kind)
struct i2c_client *client;
struct rtc_device *rtc;
- dev_dbg(adapter->class_dev.dev, "%s\n", __FUNCTION__);
+ dev_dbg(&adapter->dev, "%s\n", __FUNCTION__);
if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
err = -ENODEV;
diff --git a/drivers/rtc/rtc-ds1742.c b/drivers/rtc/rtc-ds1742.c
index 17633bfa848..d68288b389d 100644
--- a/drivers/rtc/rtc-ds1742.c
+++ b/drivers/rtc/rtc-ds1742.c
@@ -165,7 +165,7 @@ static struct bin_attribute ds1742_nvram_attr = {
.write = ds1742_nvram_write,
};
-static int __init ds1742_rtc_probe(struct platform_device *pdev)
+static int __devinit ds1742_rtc_probe(struct platform_device *pdev)
{
struct rtc_device *rtc;
struct resource *res;
diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c
index d59880d44fb..9de8d67f4f8 100644
--- a/drivers/rtc/rtc-omap.c
+++ b/drivers/rtc/rtc-omap.c
@@ -417,13 +417,13 @@ static int __devinit omap_rtc_probe(struct platform_device *pdev)
rtc_write(OMAP_RTC_STATUS_ALARM, OMAP_RTC_STATUS_REG);
/* handle periodic and alarm irqs */
- if (request_irq(omap_rtc_timer, rtc_irq, SA_INTERRUPT,
+ if (request_irq(omap_rtc_timer, rtc_irq, IRQF_DISABLED,
rtc->class_dev.class_id, &rtc->class_dev)) {
pr_debug("%s: RTC timer interrupt IRQ%d already claimed\n",
pdev->name, omap_rtc_timer);
goto fail0;
}
- if (request_irq(omap_rtc_alarm, rtc_irq, SA_INTERRUPT,
+ if (request_irq(omap_rtc_alarm, rtc_irq, IRQF_DISABLED,
rtc->class_dev.class_id, &rtc->class_dev)) {
pr_debug("%s: RTC alarm interrupt IRQ%d already claimed\n",
pdev->name, omap_rtc_alarm);
diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c
index 4b72b8ef5d6..0242d803ebe 100644
--- a/drivers/rtc/rtc-pcf8563.c
+++ b/drivers/rtc/rtc-pcf8563.c
@@ -53,6 +53,25 @@ I2C_CLIENT_INSMOD;
#define PCF8563_SC_LV 0x80 /* low voltage */
#define PCF8563_MO_C 0x80 /* century */
+struct pcf8563 {
+ struct i2c_client client;
+ /*
+ * The meaning of MO_C bit varies by the chip type.
+ * From PCF8563 datasheet: this bit is toggled when the years
+ * register overflows from 99 to 00
+ * 0 indicates the century is 20xx
+ * 1 indicates the century is 19xx
+ * From RTC8564 datasheet: this bit indicates change of
+ * century. When the year digit data overflows from 99 to 00,
+ * this bit is set. By presetting it to 0 while still in the
+ * 20th century, it will be set in year 2000, ...
+ * There seems no reliable way to know how the system use this
+ * bit. So let's do it heuristically, assuming we are live in
+ * 1970...2069.
+ */
+ int c_polarity; /* 0: MO_C=1 means 19xx, otherwise MO_C=1 means 20xx */
+};
+
static int pcf8563_probe(struct i2c_adapter *adapter, int address, int kind);
static int pcf8563_detach(struct i2c_client *client);
@@ -62,6 +81,7 @@ static int pcf8563_detach(struct i2c_client *client);
*/
static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm)
{
+ struct pcf8563 *pcf8563 = container_of(client, struct pcf8563, client);
unsigned char buf[13] = { PCF8563_REG_ST1 };
struct i2c_msg msgs[] = {
@@ -94,8 +114,12 @@ static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm)
tm->tm_mday = BCD2BIN(buf[PCF8563_REG_DM] & 0x3F);
tm->tm_wday = buf[PCF8563_REG_DW] & 0x07;
tm->tm_mon = BCD2BIN(buf[PCF8563_REG_MO] & 0x1F) - 1; /* rtc mn 1-12 */
- tm->tm_year = BCD2BIN(buf[PCF8563_REG_YR])
- + (buf[PCF8563_REG_MO] & PCF8563_MO_C ? 0 : 100);
+ tm->tm_year = BCD2BIN(buf[PCF8563_REG_YR]);
+ if (tm->tm_year < 70)
+ tm->tm_year += 100; /* assume we are in 1970...2069 */
+ /* detect the polarity heuristically. see note above. */
+ pcf8563->c_polarity = (buf[PCF8563_REG_MO] & PCF8563_MO_C) ?
+ (tm->tm_year >= 100) : (tm->tm_year < 100);
dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
"mday=%d, mon=%d, year=%d, wday=%d\n",
@@ -114,6 +138,7 @@ static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm)
static int pcf8563_set_datetime(struct i2c_client *client, struct rtc_time *tm)
{
+ struct pcf8563 *pcf8563 = container_of(client, struct pcf8563, client);
int i, err;
unsigned char buf[9];
@@ -135,7 +160,7 @@ static int pcf8563_set_datetime(struct i2c_client *client, struct rtc_time *tm)
/* year and century */
buf[PCF8563_REG_YR] = BIN2BCD(tm->tm_year % 100);
- if (tm->tm_year < 100)
+ if (pcf8563->c_polarity ? (tm->tm_year >= 100) : (tm->tm_year < 100))
buf[PCF8563_REG_MO] |= PCF8563_MO_C;
buf[PCF8563_REG_DW] = tm->tm_wday & 0x07;
@@ -248,23 +273,25 @@ static struct i2c_driver pcf8563_driver = {
static int pcf8563_probe(struct i2c_adapter *adapter, int address, int kind)
{
+ struct pcf8563 *pcf8563;
struct i2c_client *client;
struct rtc_device *rtc;
int err = 0;
- dev_dbg(adapter->class_dev.dev, "%s\n", __FUNCTION__);
+ dev_dbg(&adapter->dev, "%s\n", __FUNCTION__);
if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
err = -ENODEV;
goto exit;
}
- if (!(client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
+ if (!(pcf8563 = kzalloc(sizeof(struct pcf8563), GFP_KERNEL))) {
err = -ENOMEM;
goto exit;
}
+ client = &pcf8563->client;
client->addr = address;
client->driver = &pcf8563_driver;
client->adapter = adapter;
@@ -301,7 +328,7 @@ exit_detach:
i2c_detach_client(client);
exit_kfree:
- kfree(client);
+ kfree(pcf8563);
exit:
return err;
@@ -309,6 +336,7 @@ exit:
static int pcf8563_detach(struct i2c_client *client)
{
+ struct pcf8563 *pcf8563 = container_of(client, struct pcf8563, client);
int err;
struct rtc_device *rtc = i2c_get_clientdata(client);
@@ -318,7 +346,7 @@ static int pcf8563_detach(struct i2c_client *client)
if ((err = i2c_detach_client(client)))
return err;
- kfree(client);
+ kfree(pcf8563);
return 0;
}
diff --git a/drivers/rtc/rtc-proc.c b/drivers/rtc/rtc-proc.c
index c272afd6217..1bd624fc685 100644
--- a/drivers/rtc/rtc-proc.c
+++ b/drivers/rtc/rtc-proc.c
@@ -96,7 +96,7 @@ static int rtc_proc_release(struct inode *inode, struct file *file)
return res;
}
-static struct file_operations rtc_proc_fops = {
+static const struct file_operations rtc_proc_fops = {
.open = rtc_proc_open,
.read = seq_read,
.llseek = seq_lseek,
diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c
index e7851e3739a..09bbe575647 100644
--- a/drivers/rtc/rtc-rs5c372.c
+++ b/drivers/rtc/rtc-rs5c372.c
@@ -499,7 +499,7 @@ static int rs5c372_probe(struct i2c_adapter *adapter, int address, int kind)
struct rs5c372 *rs5c372;
struct rtc_time tm;
- dev_dbg(adapter->class_dev.dev, "%s\n", __FUNCTION__);
+ dev_dbg(&adapter->dev, "%s\n", __FUNCTION__);
if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
err = -ENODEV;
diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c
index f406a2b55ae..9a79a24a748 100644
--- a/drivers/rtc/rtc-s3c.c
+++ b/drivers/rtc/rtc-s3c.c
@@ -350,7 +350,7 @@ static int s3c_rtc_open(struct device *dev)
int ret;
ret = request_irq(s3c_rtc_alarmno, s3c_rtc_alarmirq,
- SA_INTERRUPT, "s3c2410-rtc alarm", rtc_dev);
+ IRQF_DISABLED, "s3c2410-rtc alarm", rtc_dev);
if (ret) {
dev_err(dev, "IRQ%d error %d\n", s3c_rtc_alarmno, ret);
@@ -358,7 +358,7 @@ static int s3c_rtc_open(struct device *dev)
}
ret = request_irq(s3c_rtc_tickno, s3c_rtc_tickirq,
- SA_INTERRUPT, "s3c2410-rtc tick", rtc_dev);
+ IRQF_DISABLED, "s3c2410-rtc tick", rtc_dev);
if (ret) {
dev_err(dev, "IRQ%d error %d\n", s3c_rtc_tickno, ret);
diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c
index 9c8ead43a59..677bae820dc 100644
--- a/drivers/rtc/rtc-sa1100.c
+++ b/drivers/rtc/rtc-sa1100.c
@@ -263,8 +263,12 @@ static int sa1100_rtc_set_time(struct device *dev, struct rtc_time *tm)
static int sa1100_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
{
+ u32 rtsr;
+
memcpy(&alrm->time, &rtc_alarm, sizeof(struct rtc_time));
- alrm->pending = RTSR & RTSR_AL ? 1 : 0;
+ rtsr = RTSR;
+ alrm->enabled = (rtsr & RTSR_ALE) ? 1 : 0;
+ alrm->pending = (rtsr & RTSR_AL) ? 1 : 0;
return 0;
}
@@ -275,12 +279,10 @@ static int sa1100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
spin_lock_irq(&sa1100_rtc_lock);
ret = rtc_update_alarm(&alrm->time);
if (ret == 0) {
- memcpy(&rtc_alarm, &alrm->time, sizeof(struct rtc_time));
-
if (alrm->enabled)
- enable_irq_wake(IRQ_RTCAlrm);
+ RTSR |= RTSR_ALE;
else
- disable_irq_wake(IRQ_RTCAlrm);
+ RTSR &= ~RTSR_ALE;
}
spin_unlock_irq(&sa1100_rtc_lock);
diff --git a/drivers/rtc/rtc-sysfs.c b/drivers/rtc/rtc-sysfs.c
index 2ddd0cf0714..899ab8c514f 100644
--- a/drivers/rtc/rtc-sysfs.c
+++ b/drivers/rtc/rtc-sysfs.c
@@ -78,6 +78,92 @@ static struct attribute_group rtc_attr_group = {
.attrs = rtc_attrs,
};
+
+static ssize_t
+rtc_sysfs_show_wakealarm(struct class_device *dev, char *buf)
+{
+ ssize_t retval;
+ unsigned long alarm;
+ struct rtc_wkalrm alm;
+
+ /* Don't show disabled alarms; but the RTC could leave the
+ * alarm enabled after it's already triggered. Alarms are
+ * conceptually one-shot, even though some common hardware
+ * (PCs) doesn't actually work that way.
+ *
+ * REVISIT maybe we should require RTC implementations to
+ * disable the RTC alarm after it triggers, for uniformity.
+ */
+ retval = rtc_read_alarm(dev, &alm);
+ if (retval == 0 && alm.enabled) {
+ rtc_tm_to_time(&alm.time, &alarm);
+ retval = sprintf(buf, "%lu\n", alarm);
+ }
+
+ return retval;
+}
+
+static ssize_t
+rtc_sysfs_set_wakealarm(struct class_device *dev, const char *buf, size_t n)
+{
+ ssize_t retval;
+ unsigned long now, alarm;
+ struct rtc_wkalrm alm;
+
+ /* Only request alarms that trigger in the future. Disable them
+ * by writing another time, e.g. 0 meaning Jan 1 1970 UTC.
+ */
+ retval = rtc_read_time(dev, &alm.time);
+ if (retval < 0)
+ return retval;
+ rtc_tm_to_time(&alm.time, &now);
+
+ alarm = simple_strtoul(buf, NULL, 0);
+ if (alarm > now) {
+ /* Avoid accidentally clobbering active alarms; we can't
+ * entirely prevent that here, without even the minimal
+ * locking from the /dev/rtcN api.
+ */
+ retval = rtc_read_alarm(dev, &alm);
+ if (retval < 0)
+ return retval;
+ if (alm.enabled)
+ return -EBUSY;
+
+ alm.enabled = 1;
+ } else {
+ alm.enabled = 0;
+
+ /* Provide a valid future alarm time. Linux isn't EFI,
+ * this time won't be ignored when disabling the alarm.
+ */
+ alarm = now + 300;
+ }
+ rtc_time_to_tm(alarm, &alm.time);
+
+ retval = rtc_set_alarm(dev, &alm);
+ return (retval < 0) ? retval : n;
+}
+static const CLASS_DEVICE_ATTR(wakealarm, S_IRUGO | S_IWUSR,
+ rtc_sysfs_show_wakealarm, rtc_sysfs_set_wakealarm);
+
+
+/* The reason to trigger an alarm with no process watching it (via sysfs)
+ * is its side effect: waking from a system state like suspend-to-RAM or
+ * suspend-to-disk. So: no attribute unless that side effect is possible.
+ * (Userspace may disable that mechanism later.)
+ */
+static inline int rtc_does_wakealarm(struct class_device *class_dev)
+{
+ struct rtc_device *rtc;
+
+ if (!device_can_wakeup(class_dev->dev))
+ return 0;
+ rtc = to_rtc_device(class_dev);
+ return rtc->ops->set_alarm != NULL;
+}
+
+
static int rtc_sysfs_add_device(struct class_device *class_dev,
struct class_interface *class_intf)
{
@@ -87,8 +173,18 @@ static int rtc_sysfs_add_device(struct class_device *class_dev,
err = sysfs_create_group(&class_dev->kobj, &rtc_attr_group);
if (err)
- dev_err(class_dev->dev,
- "failed to create sysfs attributes\n");
+ dev_err(class_dev->dev, "failed to create %s\n",
+ "sysfs attributes");
+ else if (rtc_does_wakealarm(class_dev)) {
+ /* not all RTCs support both alarms and wakeup */
+ err = class_device_create_file(class_dev,
+ &class_device_attr_wakealarm);
+ if (err) {
+ dev_err(class_dev->dev, "failed to create %s\n",
+ "alarm attribute");
+ sysfs_remove_group(&class_dev->kobj, &rtc_attr_group);
+ }
+ }
return err;
}
@@ -96,6 +192,9 @@ static int rtc_sysfs_add_device(struct class_device *class_dev,
static void rtc_sysfs_remove_device(struct class_device *class_dev,
struct class_interface *class_intf)
{
+ if (rtc_does_wakealarm(class_dev))
+ class_device_remove_file(class_dev,
+ &class_device_attr_wakealarm);
sysfs_remove_group(&class_dev->kobj, &rtc_attr_group);
}
diff --git a/drivers/rtc/rtc-x1205.c b/drivers/rtc/rtc-x1205.c
index 019ae255b0c..513d1a611aa 100644
--- a/drivers/rtc/rtc-x1205.c
+++ b/drivers/rtc/rtc-x1205.c
@@ -506,7 +506,7 @@ static int x1205_probe(struct i2c_adapter *adapter, int address, int kind)
struct i2c_client *client;
struct rtc_device *rtc;
- dev_dbg(adapter->class_dev.dev, "%s\n", __FUNCTION__);
+ dev_dbg(&adapter->dev, "%s\n", __FUNCTION__);
if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
err = -ENODEV;
diff --git a/drivers/s390/Kconfig b/drivers/s390/Kconfig
index ae89b9b8874..165af398fde 100644
--- a/drivers/s390/Kconfig
+++ b/drivers/s390/Kconfig
@@ -103,14 +103,8 @@ config CCW_CONSOLE
depends on TN3215_CONSOLE || TN3270_CONSOLE
default y
-config SCLP
- bool "Support for SCLP"
- help
- Include support for the SCLP interface to the service element.
-
config SCLP_TTY
bool "Support for SCLP line mode terminal"
- depends on SCLP
help
Include support for IBM SCLP line-mode terminals.
@@ -123,7 +117,6 @@ config SCLP_CONSOLE
config SCLP_VT220_TTY
bool "Support for SCLP VT220-compatible terminal"
- depends on SCLP
help
Include support for an IBM SCLP VT220-compatible terminal.
@@ -136,7 +129,6 @@ config SCLP_VT220_CONSOLE
config SCLP_CPI
tristate "Control-Program Identification"
- depends on SCLP
help
This option enables the hardware console interface for system
identification. This is commonly used for workload management and
diff --git a/drivers/s390/Makefile b/drivers/s390/Makefile
index 9803c9352d7..5a888704a8d 100644
--- a/drivers/s390/Makefile
+++ b/drivers/s390/Makefile
@@ -2,6 +2,8 @@
# Makefile for the S/390 specific device drivers
#
+CFLAGS_sysinfo.o += -Iinclude/math-emu -Iarch/s390/math-emu -w
+
obj-y += s390mach.o sysinfo.o s390_rdev.o
obj-y += cio/ block/ char/ crypto/ net/ scsi/
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index 492b68bcd7c..eb5dc62f0d9 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -37,6 +37,7 @@
*/
debug_info_t *dasd_debug_area;
struct dasd_discipline *dasd_diag_discipline_pointer;
+void dasd_int_handler(struct ccw_device *, unsigned long, struct irb *);
MODULE_AUTHOR("Holger Smolinski <Holger.Smolinski@de.ibm.com>");
MODULE_DESCRIPTION("Linux on S/390 DASD device driver,"
@@ -51,7 +52,6 @@ static int dasd_alloc_queue(struct dasd_device * device);
static void dasd_setup_queue(struct dasd_device * device);
static void dasd_free_queue(struct dasd_device * device);
static void dasd_flush_request_queue(struct dasd_device *);
-static void dasd_int_handler(struct ccw_device *, unsigned long, struct irb *);
static int dasd_flush_ccw_queue(struct dasd_device *, int);
static void dasd_tasklet(struct dasd_device *);
static void do_kick_device(struct work_struct *);
@@ -483,7 +483,7 @@ unsigned int dasd_profile_level = DASD_PROFILE_OFF;
/*
* Add profiling information for cqr before execution.
*/
-static inline void
+static void
dasd_profile_start(struct dasd_device *device, struct dasd_ccw_req * cqr,
struct request *req)
{
@@ -505,7 +505,7 @@ dasd_profile_start(struct dasd_device *device, struct dasd_ccw_req * cqr,
/*
* Add profiling information for cqr after execution.
*/
-static inline void
+static void
dasd_profile_end(struct dasd_device *device, struct dasd_ccw_req * cqr,
struct request *req)
{
@@ -1022,8 +1022,6 @@ dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
irb->scsw.cstat == 0 &&
!irb->esw.esw0.erw.cons)
era = dasd_era_none;
- else if (!test_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags))
- era = dasd_era_fatal; /* don't recover this request */
else if (irb->esw.esw0.erw.cons)
era = device->discipline->examine_error(cqr, irb);
else
@@ -1104,7 +1102,7 @@ __dasd_process_erp(struct dasd_device *device, struct dasd_ccw_req *cqr)
/*
* Process ccw request queue.
*/
-static inline void
+static void
__dasd_process_ccw_queue(struct dasd_device * device,
struct list_head *final_queue)
{
@@ -1127,7 +1125,9 @@ restart:
cqr->status = DASD_CQR_FAILED;
cqr->stopclk = get_clock();
} else {
- if (cqr->irb.esw.esw0.erw.cons) {
+ if (cqr->irb.esw.esw0.erw.cons &&
+ test_bit(DASD_CQR_FLAGS_USE_ERP,
+ &cqr->flags)) {
erp_fn = device->discipline->
erp_action(cqr);
erp_fn(cqr);
@@ -1181,7 +1181,7 @@ dasd_end_request_cb(struct dasd_ccw_req * cqr, void *data)
/*
* Fetch requests from the block device queue.
*/
-static inline void
+static void
__dasd_process_blk_queue(struct dasd_device * device)
{
request_queue_t *queue;
@@ -1232,6 +1232,19 @@ __dasd_process_blk_queue(struct dasd_device * device)
if (IS_ERR(cqr)) {
if (PTR_ERR(cqr) == -ENOMEM)
break; /* terminate request queue loop */
+ if (PTR_ERR(cqr) == -EAGAIN) {
+ /*
+ * The current request cannot be build right
+ * now, we have to try later. If this request
+ * is the head-of-queue we stop the device
+ * for 1/2 second.
+ */
+ if (!list_empty(&device->ccw_queue))
+ break;
+ device->stopped |= DASD_STOPPED_PENDING;
+ dasd_set_timer(device, HZ/2);
+ break;
+ }
DBF_DEV_EVENT(DBF_ERR, device,
"CCW creation failed (rc=%ld) "
"on request %p",
@@ -1254,7 +1267,7 @@ __dasd_process_blk_queue(struct dasd_device * device)
* Take a look at the first request on the ccw queue and check
* if it reached its expire time. If so, terminate the IO.
*/
-static inline void
+static void
__dasd_check_expire(struct dasd_device * device)
{
struct dasd_ccw_req *cqr;
@@ -1285,7 +1298,7 @@ __dasd_check_expire(struct dasd_device * device)
* Take a look at the first request on the ccw queue and check
* if it needs to be started.
*/
-static inline void
+static void
__dasd_start_head(struct dasd_device * device)
{
struct dasd_ccw_req *cqr;
diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c
index 4d01040c2c6..8b9d68f6e01 100644
--- a/drivers/s390/block/dasd_3990_erp.c
+++ b/drivers/s390/block/dasd_3990_erp.c
@@ -170,7 +170,6 @@ dasd_3990_erp_examine(struct dasd_ccw_req * cqr, struct irb * irb)
/* log the erp chain if fatal error occurred */
if ((era == dasd_era_fatal) && (device->state >= DASD_STATE_READY)) {
dasd_log_sense(cqr, irb);
- dasd_log_ccw(cqr, 0, irb->scsw.cpa);
}
return era;
@@ -2640,7 +2639,6 @@ dasd_3990_erp_action(struct dasd_ccw_req * cqr)
struct dasd_ccw_req *erp = NULL;
struct dasd_device *device = cqr->device;
- __u32 cpa = cqr->irb.scsw.cpa;
struct dasd_ccw_req *temp_erp = NULL;
if (device->features & DASD_FEATURE_ERPLOG) {
@@ -2706,9 +2704,6 @@ dasd_3990_erp_action(struct dasd_ccw_req * cqr)
}
}
- if (erp->status == DASD_CQR_FAILED)
- dasd_log_ccw(erp, 1, cpa);
-
/* enqueue added ERP request */
if (erp->status == DASD_CQR_FILLED) {
erp->status = DASD_CQR_QUEUED;
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c
index 5943266152f..ed70852cc91 100644
--- a/drivers/s390/block/dasd_devmap.c
+++ b/drivers/s390/block/dasd_devmap.c
@@ -136,7 +136,7 @@ __setup ("dasd=", dasd_call_setup);
/*
* Read a device busid/devno from a string.
*/
-static inline int
+static int
dasd_busid(char **str, int *id0, int *id1, int *devno)
{
int val, old_style;
@@ -182,7 +182,7 @@ dasd_busid(char **str, int *id0, int *id1, int *devno)
* only one: "ro" for read-only devices. The default feature set
* is empty (value 0).
*/
-static inline int
+static int
dasd_feature_list(char *str, char **endp)
{
int features, len, rc;
@@ -341,7 +341,7 @@ dasd_parse_range( char *parsestring ) {
return ERR_PTR(-EINVAL);
}
-static inline char *
+static char *
dasd_parse_next_element( char *parsestring ) {
char * residual_str;
residual_str = dasd_parse_keyword(parsestring);
diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c
index 53db58a6861..ab782bb46ac 100644
--- a/drivers/s390/block/dasd_diag.c
+++ b/drivers/s390/block/dasd_diag.c
@@ -43,7 +43,7 @@ MODULE_LICENSE("GPL");
#define DIAG_MAX_RETRIES 32
#define DIAG_TIMEOUT 50 * HZ
-struct dasd_discipline dasd_diag_discipline;
+static struct dasd_discipline dasd_diag_discipline;
struct dasd_diag_private {
struct dasd_diag_characteristics rdc_data;
@@ -90,7 +90,7 @@ static inline int dia250(void *iob, int cmd)
* block offset. On success, return zero and set end_block to contain the
* number of blocks on the device minus the specified offset. Return non-zero
* otherwise. */
-static __inline__ int
+static inline int
mdsk_init_io(struct dasd_device *device, unsigned int blocksize,
blocknum_t offset, blocknum_t *end_block)
{
@@ -117,7 +117,7 @@ mdsk_init_io(struct dasd_device *device, unsigned int blocksize,
/* Remove block I/O environment for device. Return zero on success, non-zero
* otherwise. */
-static __inline__ int
+static inline int
mdsk_term_io(struct dasd_device * device)
{
struct dasd_diag_private *private;
@@ -576,7 +576,7 @@ dasd_diag_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
"dump sense not available for DIAG data");
}
-struct dasd_discipline dasd_diag_discipline = {
+static struct dasd_discipline dasd_diag_discipline = {
.owner = THIS_MODULE,
.name = "DIAG",
.ebcname = "DIAG",
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index fdaa471e845..cecab2274a6 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -134,44 +134,7 @@ ceil_quot(unsigned int d1, unsigned int d2)
return (d1 + (d2 - 1)) / d2;
}
-static inline int
-bytes_per_record(struct dasd_eckd_characteristics *rdc, int kl, int dl)
-{
- unsigned int fl1, fl2, int1, int2;
- int bpr;
-
- switch (rdc->formula) {
- case 0x01:
- fl1 = round_up_multiple(ECKD_F2(rdc) + dl, ECKD_F1(rdc));
- fl2 = round_up_multiple(kl ? ECKD_F2(rdc) + kl : 0,
- ECKD_F1(rdc));
- bpr = fl1 + fl2;
- break;
- case 0x02:
- int1 = ceil_quot(dl + ECKD_F6(rdc), ECKD_F5(rdc) << 1);
- int2 = ceil_quot(kl + ECKD_F6(rdc), ECKD_F5(rdc) << 1);
- fl1 = round_up_multiple(ECKD_F1(rdc) * ECKD_F2(rdc) + dl +
- ECKD_F6(rdc) + ECKD_F4(rdc) * int1,
- ECKD_F1(rdc));
- fl2 = round_up_multiple(ECKD_F1(rdc) * ECKD_F3(rdc) + kl +
- ECKD_F6(rdc) + ECKD_F4(rdc) * int2,
- ECKD_F1(rdc));
- bpr = fl1 + fl2;
- break;
- default:
- bpr = 0;
- break;
- }
- return bpr;
-}
-
-static inline unsigned int
-bytes_per_track(struct dasd_eckd_characteristics *rdc)
-{
- return *(unsigned int *) (rdc->byte_per_track) >> 8;
-}
-
-static inline unsigned int
+static unsigned int
recs_per_track(struct dasd_eckd_characteristics * rdc,
unsigned int kl, unsigned int dl)
{
@@ -204,37 +167,39 @@ recs_per_track(struct dasd_eckd_characteristics * rdc,
return 0;
}
-static inline void
+static int
check_XRC (struct ccw1 *de_ccw,
struct DE_eckd_data *data,
struct dasd_device *device)
{
struct dasd_eckd_private *private;
+ int rc;
private = (struct dasd_eckd_private *) device->private;
+ if (!private->rdc_data.facilities.XRC_supported)
+ return 0;
/* switch on System Time Stamp - needed for XRC Support */
- if (private->rdc_data.facilities.XRC_supported) {
-
- data->ga_extended |= 0x08; /* switch on 'Time Stamp Valid' */
- data->ga_extended |= 0x02; /* switch on 'Extended Parameter' */
-
- data->ep_sys_time = get_clock ();
-
- de_ccw->count = sizeof (struct DE_eckd_data);
- de_ccw->flags |= CCW_FLAG_SLI;
- }
+ data->ga_extended |= 0x08; /* switch on 'Time Stamp Valid' */
+ data->ga_extended |= 0x02; /* switch on 'Extended Parameter' */
- return;
+ rc = get_sync_clock(&data->ep_sys_time);
+ /* Ignore return code if sync clock is switched off. */
+ if (rc == -ENOSYS || rc == -EACCES)
+ rc = 0;
-} /* end check_XRC */
+ de_ccw->count = sizeof (struct DE_eckd_data);
+ de_ccw->flags |= CCW_FLAG_SLI;
+ return rc;
+}
-static inline void
+static int
define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk,
int totrk, int cmd, struct dasd_device * device)
{
struct dasd_eckd_private *private;
struct ch_t geo, beg, end;
+ int rc = 0;
private = (struct dasd_eckd_private *) device->private;
@@ -263,12 +228,12 @@ define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk,
case DASD_ECKD_CCW_WRITE_KD_MT:
data->mask.perm = 0x02;
data->attributes.operation = private->attrib.operation;
- check_XRC (ccw, data, device);
+ rc = check_XRC (ccw, data, device);
break;
case DASD_ECKD_CCW_WRITE_CKD:
case DASD_ECKD_CCW_WRITE_CKD_MT:
data->attributes.operation = DASD_BYPASS_CACHE;
- check_XRC (ccw, data, device);
+ rc = check_XRC (ccw, data, device);
break;
case DASD_ECKD_CCW_ERASE:
case DASD_ECKD_CCW_WRITE_HOME_ADDRESS:
@@ -276,7 +241,7 @@ define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk,
data->mask.perm = 0x3;
data->mask.auth = 0x1;
data->attributes.operation = DASD_BYPASS_CACHE;
- check_XRC (ccw, data, device);
+ rc = check_XRC (ccw, data, device);
break;
default:
DEV_MESSAGE(KERN_ERR, device, "unknown opcode 0x%x", cmd);
@@ -312,9 +277,10 @@ define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk,
data->beg_ext.head = beg.head;
data->end_ext.cyl = end.cyl;
data->end_ext.head = end.head;
+ return rc;
}
-static inline void
+static void
locate_record(struct ccw1 *ccw, struct LO_eckd_data *data, int trk,
int rec_on_trk, int no_rec, int cmd,
struct dasd_device * device, int reclen)
@@ -548,7 +514,7 @@ dasd_eckd_read_conf(struct dasd_device *device)
/*
* Build CP for Perform Subsystem Function - SSC.
*/
-struct dasd_ccw_req *
+static struct dasd_ccw_req *
dasd_eckd_build_psf_ssc(struct dasd_device *device)
{
struct dasd_ccw_req *cqr;
@@ -1200,7 +1166,12 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req)
return cqr;
ccw = cqr->cpaddr;
/* First ccw is define extent. */
- define_extent(ccw++, cqr->data, first_trk, last_trk, cmd, device);
+ if (define_extent(ccw++, cqr->data, first_trk,
+ last_trk, cmd, device) == -EAGAIN) {
+ /* Clock not in sync and XRC is enabled. Try again later. */
+ dasd_sfree_request(cqr, device);
+ return ERR_PTR(-EAGAIN);
+ }
/* Build locate_record+read/write/ccws. */
idaws = (unsigned long *) (cqr->data + sizeof(struct DE_eckd_data));
LO_data = (struct LO_eckd_data *) (idaws + cidaw);
@@ -1380,7 +1351,7 @@ dasd_eckd_release(struct dasd_device *device)
cqr->device = device;
clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
- cqr->retries = 0;
+ cqr->retries = 2; /* set retry counter to enable basic ERP */
cqr->expires = 2 * HZ;
cqr->buildclk = get_clock();
cqr->status = DASD_CQR_FILLED;
@@ -1420,7 +1391,7 @@ dasd_eckd_reserve(struct dasd_device *device)
cqr->device = device;
clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
- cqr->retries = 0;
+ cqr->retries = 2; /* set retry counter to enable basic ERP */
cqr->expires = 2 * HZ;
cqr->buildclk = get_clock();
cqr->status = DASD_CQR_FILLED;
@@ -1459,7 +1430,7 @@ dasd_eckd_steal_lock(struct dasd_device *device)
cqr->device = device;
clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
- cqr->retries = 0;
+ cqr->retries = 2; /* set retry counter to enable basic ERP */
cqr->expires = 2 * HZ;
cqr->buildclk = get_clock();
cqr->status = DASD_CQR_FILLED;
@@ -1609,7 +1580,7 @@ dasd_eckd_ioctl(struct dasd_device *device, unsigned int cmd, void __user *argp)
* Dump the range of CCWs into 'page' buffer
* and return number of printed chars.
*/
-static inline int
+static int
dasd_eckd_dump_ccw_range(struct ccw1 *from, struct ccw1 *to, char *page)
{
int len, count;
diff --git a/drivers/s390/block/dasd_eer.c b/drivers/s390/block/dasd_eer.c
index e0bf30ebb21..4b8a95fba1e 100644
--- a/drivers/s390/block/dasd_eer.c
+++ b/drivers/s390/block/dasd_eer.c
@@ -650,7 +650,7 @@ static unsigned int dasd_eer_poll(struct file *filp, poll_table *ptable)
return mask;
}
-static struct file_operations dasd_eer_fops = {
+static const struct file_operations dasd_eer_fops = {
.open = &dasd_eer_open,
.release = &dasd_eer_close,
.read = &dasd_eer_read,
@@ -658,18 +658,24 @@ static struct file_operations dasd_eer_fops = {
.owner = THIS_MODULE,
};
-static struct miscdevice dasd_eer_dev = {
- .minor = MISC_DYNAMIC_MINOR,
- .name = "dasd_eer",
- .fops = &dasd_eer_fops,
-};
+static struct miscdevice *dasd_eer_dev = NULL;
int __init dasd_eer_init(void)
{
int rc;
- rc = misc_register(&dasd_eer_dev);
+ dasd_eer_dev = kzalloc(sizeof(*dasd_eer_dev), GFP_KERNEL);
+ if (!dasd_eer_dev)
+ return -ENOMEM;
+
+ dasd_eer_dev->minor = MISC_DYNAMIC_MINOR;
+ dasd_eer_dev->name = "dasd_eer";
+ dasd_eer_dev->fops = &dasd_eer_fops;
+
+ rc = misc_register(dasd_eer_dev);
if (rc) {
+ kfree(dasd_eer_dev);
+ dasd_eer_dev = NULL;
MESSAGE(KERN_ERR, "%s", "dasd_eer_init could not "
"register misc device");
return rc;
@@ -680,5 +686,9 @@ int __init dasd_eer_init(void)
void dasd_eer_exit(void)
{
- WARN_ON(misc_deregister(&dasd_eer_dev) != 0);
+ if (dasd_eer_dev) {
+ WARN_ON(misc_deregister(dasd_eer_dev) != 0);
+ kfree(dasd_eer_dev);
+ dasd_eer_dev = NULL;
+ }
}
diff --git a/drivers/s390/block/dasd_erp.c b/drivers/s390/block/dasd_erp.c
index 58a65097922..caa5d91420f 100644
--- a/drivers/s390/block/dasd_erp.c
+++ b/drivers/s390/block/dasd_erp.c
@@ -152,25 +152,6 @@ dasd_default_erp_postaction(struct dasd_ccw_req * cqr)
} /* end default_erp_postaction */
-/*
- * Print the hex dump of the memory used by a request. This includes
- * all error recovery ccws that have been chained in from of the
- * real request.
- */
-static inline void
-hex_dump_memory(struct dasd_device *device, void *data, int len)
-{
- int *pint;
-
- pint = (int *) data;
- while (len > 0) {
- DEV_MESSAGE(KERN_ERR, device, "%p: %08x %08x %08x %08x",
- pint, pint[0], pint[1], pint[2], pint[3]);
- pint += 4;
- len -= 16;
- }
-}
-
void
dasd_log_sense(struct dasd_ccw_req *cqr, struct irb *irb)
{
@@ -182,69 +163,8 @@ dasd_log_sense(struct dasd_ccw_req *cqr, struct irb *irb)
device->discipline->dump_sense(device, cqr, irb);
}
-void
-dasd_log_ccw(struct dasd_ccw_req * cqr, int caller, __u32 cpa)
-{
- struct dasd_device *device;
- struct dasd_ccw_req *lcqr;
- struct ccw1 *ccw;
- int cplength;
-
- device = cqr->device;
- /* log the channel program */
- for (lcqr = cqr; lcqr != NULL; lcqr = lcqr->refers) {
- DEV_MESSAGE(KERN_ERR, device,
- "(%s) ERP chain report for req: %p",
- caller == 0 ? "EXAMINE" : "ACTION", lcqr);
- hex_dump_memory(device, lcqr, sizeof(struct dasd_ccw_req));
-
- cplength = 1;
- ccw = lcqr->cpaddr;
- while (ccw++->flags & (CCW_FLAG_DC | CCW_FLAG_CC))
- cplength++;
-
- if (cplength > 40) { /* log only parts of the CP */
- DEV_MESSAGE(KERN_ERR, device, "%s",
- "Start of channel program:");
- hex_dump_memory(device, lcqr->cpaddr,
- 40*sizeof(struct ccw1));
-
- DEV_MESSAGE(KERN_ERR, device, "%s",
- "End of channel program:");
- hex_dump_memory(device, lcqr->cpaddr + cplength - 10,
- 10*sizeof(struct ccw1));
- } else { /* log the whole CP */
- DEV_MESSAGE(KERN_ERR, device, "%s",
- "Channel program (complete):");
- hex_dump_memory(device, lcqr->cpaddr,
- cplength*sizeof(struct ccw1));
- }
-
- if (lcqr != cqr)
- continue;
-
- /*
- * Log bytes arround failed CCW but only if we did
- * not log the whole CP of the CCW is outside the
- * logged CP.
- */
- if (cplength > 40 ||
- ((addr_t) cpa < (addr_t) lcqr->cpaddr &&
- (addr_t) cpa > (addr_t) (lcqr->cpaddr + cplength + 4))) {
-
- DEV_MESSAGE(KERN_ERR, device,
- "Failed CCW (%p) (area):",
- (void *) (long) cpa);
- hex_dump_memory(device, cqr->cpaddr - 10,
- 20*sizeof(struct ccw1));
- }
- }
-
-} /* end log_erp_chain */
-
EXPORT_SYMBOL(dasd_default_erp_action);
EXPORT_SYMBOL(dasd_default_erp_postaction);
EXPORT_SYMBOL(dasd_alloc_erp_request);
EXPORT_SYMBOL(dasd_free_erp_request);
EXPORT_SYMBOL(dasd_log_sense);
-EXPORT_SYMBOL(dasd_log_ccw);
diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c
index b857fd5893f..be0909e3922 100644
--- a/drivers/s390/block/dasd_fba.c
+++ b/drivers/s390/block/dasd_fba.c
@@ -75,7 +75,7 @@ static struct ccw_driver dasd_fba_driver = {
.notify = dasd_generic_notify,
};
-static inline void
+static void
define_extent(struct ccw1 * ccw, struct DE_fba_data *data, int rw,
int blksize, int beg, int nr)
{
@@ -95,7 +95,7 @@ define_extent(struct ccw1 * ccw, struct DE_fba_data *data, int rw,
data->ext_end = nr - 1;
}
-static inline void
+static void
locate_record(struct ccw1 * ccw, struct LO_fba_data *data, int rw,
int block_nr, int block_ct)
{
diff --git a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c
index d163632101d..47ba4462708 100644
--- a/drivers/s390/block/dasd_genhd.c
+++ b/drivers/s390/block/dasd_genhd.c
@@ -147,7 +147,7 @@ dasd_destroy_partitions(struct dasd_device * device)
*/
memset(&bpart, 0, sizeof(struct blkpg_partition));
memset(&barg, 0, sizeof(struct blkpg_ioctl_arg));
- barg.data = (void __user *) &bpart;
+ barg.data = (void __force __user *) &bpart;
barg.op = BLKPG_DEL_PARTITION;
for (bpart.pno = device->gdp->minors - 1; bpart.pno > 0; bpart.pno--)
ioctl_by_bdev(bdev, BLKPG, (unsigned long) &barg);
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index fb725e3b08f..a2cc69e1141 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -559,7 +559,6 @@ struct dasd_ccw_req *dasd_alloc_erp_request(char *, int, int,
struct dasd_device *);
void dasd_free_erp_request(struct dasd_ccw_req *, struct dasd_device *);
void dasd_log_sense(struct dasd_ccw_req *, struct irb *);
-void dasd_log_ccw(struct dasd_ccw_req *, int, __u32);
/* externals in dasd_3370_erp.c */
dasd_era_t dasd_3370_erp_examine(struct dasd_ccw_req *, struct irb *);
diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c
index bfa010f6dab..8b3b0f4a157 100644
--- a/drivers/s390/block/dasd_proc.c
+++ b/drivers/s390/block/dasd_proc.c
@@ -28,7 +28,7 @@ static struct proc_dir_entry *dasd_proc_root_entry = NULL;
static struct proc_dir_entry *dasd_devices_entry = NULL;
static struct proc_dir_entry *dasd_statistics_entry = NULL;
-static inline char *
+static char *
dasd_get_user_string(const char __user *user_buf, size_t user_len)
{
char *buffer;
@@ -147,14 +147,14 @@ static int dasd_devices_open(struct inode *inode, struct file *file)
return seq_open(file, &dasd_devices_seq_ops);
}
-static struct file_operations dasd_devices_file_ops = {
+static const struct file_operations dasd_devices_file_ops = {
.open = dasd_devices_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
-static inline int
+static int
dasd_calc_metrics(char *page, char **start, off_t off,
int count, int *eof, int len)
{
@@ -167,8 +167,8 @@ dasd_calc_metrics(char *page, char **start, off_t off,
return len;
}
-static inline char *
-dasd_statistics_array(char *str, int *array, int shift)
+static char *
+dasd_statistics_array(char *str, unsigned int *array, int shift)
{
int i;
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c
index be9b05347b4..1340451ea40 100644
--- a/drivers/s390/block/dcssblk.c
+++ b/drivers/s390/block/dcssblk.c
@@ -102,7 +102,7 @@ dcssblk_release_segment(struct device *dev)
* device needs to be enqueued before the semaphore is
* freed.
*/
-static inline int
+static int
dcssblk_assign_free_minor(struct dcssblk_dev_info *dev_info)
{
int minor, found;
@@ -230,7 +230,7 @@ dcssblk_shared_store(struct device *dev, struct device_attribute *attr, const ch
SEGMENT_SHARED);
if (rc < 0) {
BUG_ON(rc == -EINVAL);
- if (rc == -EIO || rc == -ENOENT)
+ if (rc != -EAGAIN)
goto removeseg;
} else {
dev_info->is_shared = 1;
@@ -253,7 +253,7 @@ dcssblk_shared_store(struct device *dev, struct device_attribute *attr, const ch
SEGMENT_EXCLUSIVE);
if (rc < 0) {
BUG_ON(rc == -EINVAL);
- if (rc == -EIO || rc == -ENOENT)
+ if (rc != -EAGAIN)
goto removeseg;
} else {
dev_info->is_shared = 0;
diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile
index c3e97b4fc18..293e667b50f 100644
--- a/drivers/s390/char/Makefile
+++ b/drivers/s390/char/Makefile
@@ -2,7 +2,8 @@
# S/390 character devices
#
-obj-y += ctrlchar.o keyboard.o defkeymap.o
+obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \
+ sclp_info.o
obj-$(CONFIG_TN3270) += raw3270.o
obj-$(CONFIG_TN3270_CONSOLE) += con3270.o
@@ -11,7 +12,6 @@ obj-$(CONFIG_TN3270_FS) += fs3270.o
obj-$(CONFIG_TN3215) += con3215.o
-obj-$(CONFIG_SCLP) += sclp.o sclp_rw.o sclp_quiesce.o
obj-$(CONFIG_SCLP_TTY) += sclp_tty.o
obj-$(CONFIG_SCLP_CONSOLE) += sclp_con.o
obj-$(CONFIG_SCLP_VT220_TTY) += sclp_vt220.o
diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c
index 25b5d7a6641..9a328f14a64 100644
--- a/drivers/s390/char/con3215.c
+++ b/drivers/s390/char/con3215.c
@@ -1121,7 +1121,7 @@ static const struct tty_operations tty3215_ops = {
* 3215 tty registration code called from tty_init().
* Most kernel services (incl. kmalloc) are available at this poimt.
*/
-int __init
+static int __init
tty3215_init(void)
{
struct tty_driver *driver;
diff --git a/drivers/s390/char/con3270.c b/drivers/s390/char/con3270.c
index 7566be89068..8e7f2d7633d 100644
--- a/drivers/s390/char/con3270.c
+++ b/drivers/s390/char/con3270.c
@@ -69,8 +69,7 @@ static void con3270_update(struct con3270 *);
/*
* Setup timeout for a device. On timeout trigger an update.
*/
-void
-con3270_set_timer(struct con3270 *cp, int expires)
+static void con3270_set_timer(struct con3270 *cp, int expires)
{
if (expires == 0) {
if (timer_pending(&cp->timer))
diff --git a/drivers/s390/char/defkeymap.c b/drivers/s390/char/defkeymap.c
index 17027d918cf..564baca01b7 100644
--- a/drivers/s390/char/defkeymap.c
+++ b/drivers/s390/char/defkeymap.c
@@ -5,6 +5,8 @@
#include <linux/types.h>
#include <linux/keyboard.h>
#include <linux/kd.h>
+#include <linux/kbd_kern.h>
+#include <linux/kbd_diacr.h>
u_short plain_map[NR_KEYS] = {
0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000,
diff --git a/drivers/s390/char/fs3270.c b/drivers/s390/char/fs3270.c
index 0893d306ae8..ef36f2132aa 100644
--- a/drivers/s390/char/fs3270.c
+++ b/drivers/s390/char/fs3270.c
@@ -23,7 +23,7 @@
#include "raw3270.h"
#include "ctrlchar.h"
-struct raw3270_fn fs3270_fn;
+static struct raw3270_fn fs3270_fn;
struct fs3270 {
struct raw3270_view view;
@@ -401,7 +401,7 @@ fs3270_release(struct raw3270_view *view)
}
/* View to a 3270 device. Can be console, tty or fullscreen. */
-struct raw3270_fn fs3270_fn = {
+static struct raw3270_fn fs3270_fn = {
.activate = fs3270_activate,
.deactivate = fs3270_deactivate,
.intv = (void *) fs3270_irq,
@@ -493,7 +493,7 @@ fs3270_close(struct inode *inode, struct file *filp)
return 0;
}
-static struct file_operations fs3270_fops = {
+static const struct file_operations fs3270_fops = {
.owner = THIS_MODULE, /* owner */
.read = fs3270_read, /* read */
.write = fs3270_write, /* write */
diff --git a/drivers/s390/char/keyboard.c b/drivers/s390/char/keyboard.c
index 3e86fd1756e..f62f9a4e895 100644
--- a/drivers/s390/char/keyboard.c
+++ b/drivers/s390/char/keyboard.c
@@ -148,6 +148,7 @@ kbd_ascebc(struct kbd_data *kbd, unsigned char *ascebc)
}
}
+#if 0
/*
* Generate ebcdic -> ascii translation table from kbd_data.
*/
@@ -173,6 +174,7 @@ kbd_ebcasc(struct kbd_data *kbd, unsigned char *ebcasc)
}
}
}
+#endif
/*
* We have a combining character DIACR here, followed by the character CH.
diff --git a/drivers/s390/char/monreader.c b/drivers/s390/char/monreader.c
index a138b151009..8df7b1323c0 100644
--- a/drivers/s390/char/monreader.c
+++ b/drivers/s390/char/monreader.c
@@ -3,7 +3,7 @@
*
* Character device driver for reading z/VM *MONITOR service records.
*
- * Copyright (C) 2004 IBM Corporation, IBM Deutschland Entwicklung GmbH.
+ * Copyright 2004 IBM Corporation, IBM Deutschland Entwicklung GmbH.
*
* Author: Gerald Schaefer <geraldsc@de.ibm.com>
*/
@@ -22,7 +22,7 @@
#include <asm/ebcdic.h>
#include <asm/extmem.h>
#include <linux/poll.h>
-#include "../net/iucv.h"
+#include <net/iucv/iucv.h>
//#define MON_DEBUG /* Debug messages on/off */
@@ -50,14 +50,13 @@ static char mon_dcss_name[9] = "MONDCSS\0";
struct mon_msg {
u32 pos;
u32 mca_offset;
- iucv_MessagePending local_eib;
+ struct iucv_message msg;
char msglim_reached;
char replied_msglim;
};
struct mon_private {
- u16 pathid;
- iucv_handle_t iucv_handle;
+ struct iucv_path *path;
struct mon_msg *msg_array[MON_MSGLIM];
unsigned int write_index;
unsigned int read_index;
@@ -75,8 +74,6 @@ static unsigned long mon_dcss_end;
static DECLARE_WAIT_QUEUE_HEAD(mon_read_wait_queue);
static DECLARE_WAIT_QUEUE_HEAD(mon_conn_wait_queue);
-static u8 iucv_host[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
-
static u8 user_data_connect[16] = {
/* Version code, must be 0x01 for shared mode */
0x01,
@@ -100,8 +97,7 @@ static u8 user_data_sever[16] = {
* Create the 8 bytes EBCDIC DCSS segment name from
* an ASCII name, incl. padding
*/
-static inline void
-dcss_mkname(char *ascii_name, char *ebcdic_name)
+static inline void dcss_mkname(char *ascii_name, char *ebcdic_name)
{
int i;
@@ -119,8 +115,7 @@ dcss_mkname(char *ascii_name, char *ebcdic_name)
* print appropriate error message for segment_load()/segment_type()
* return code
*/
-static void
-mon_segment_warn(int rc, char* seg_name)
+static void mon_segment_warn(int rc, char* seg_name)
{
switch (rc) {
case -ENOENT:
@@ -166,44 +161,37 @@ mon_segment_warn(int rc, char* seg_name)
}
}
-static inline unsigned long
-mon_mca_start(struct mon_msg *monmsg)
+static inline unsigned long mon_mca_start(struct mon_msg *monmsg)
{
- return monmsg->local_eib.ln1msg1.iprmmsg1_u32;
+ return *(u32 *) &monmsg->msg.rmmsg;
}
-static inline unsigned long
-mon_mca_end(struct mon_msg *monmsg)
+static inline unsigned long mon_mca_end(struct mon_msg *monmsg)
{
- return monmsg->local_eib.ln1msg2.ipbfln1f;
+ return *(u32 *) &monmsg->msg.rmmsg[4];
}
-static inline u8
-mon_mca_type(struct mon_msg *monmsg, u8 index)
+static inline u8 mon_mca_type(struct mon_msg *monmsg, u8 index)
{
return *((u8 *) mon_mca_start(monmsg) + monmsg->mca_offset + index);
}
-static inline u32
-mon_mca_size(struct mon_msg *monmsg)
+static inline u32 mon_mca_size(struct mon_msg *monmsg)
{
return mon_mca_end(monmsg) - mon_mca_start(monmsg) + 1;
}
-static inline u32
-mon_rec_start(struct mon_msg *monmsg)
+static inline u32 mon_rec_start(struct mon_msg *monmsg)
{
return *((u32 *) (mon_mca_start(monmsg) + monmsg->mca_offset + 4));
}
-static inline u32
-mon_rec_end(struct mon_msg *monmsg)
+static inline u32 mon_rec_end(struct mon_msg *monmsg)
{
return *((u32 *) (mon_mca_start(monmsg) + monmsg->mca_offset + 8));
}
-static inline int
-mon_check_mca(struct mon_msg *monmsg)
+static inline int mon_check_mca(struct mon_msg *monmsg)
{
if ((mon_rec_end(monmsg) <= mon_rec_start(monmsg)) ||
(mon_rec_start(monmsg) < mon_dcss_start) ||
@@ -221,20 +209,17 @@ mon_check_mca(struct mon_msg *monmsg)
return 0;
}
-static inline int
-mon_send_reply(struct mon_msg *monmsg, struct mon_private *monpriv)
+static inline int mon_send_reply(struct mon_msg *monmsg,
+ struct mon_private *monpriv)
{
- u8 prmmsg[8];
int rc;
P_DEBUG("read, REPLY: pathid = 0x%04X, msgid = 0x%08X, trgcls = "
"0x%08X\n\n",
- monmsg->local_eib.ippathid, monmsg->local_eib.ipmsgid,
- monmsg->local_eib.iptrgcls);
- rc = iucv_reply_prmmsg(monmsg->local_eib.ippathid,
- monmsg->local_eib.ipmsgid,
- monmsg->local_eib.iptrgcls,
- 0, prmmsg);
+ monpriv->path->pathid, monmsg->msg.id, monmsg->msg.class);
+
+ rc = iucv_message_reply(monpriv->path, &monmsg->msg,
+ IUCV_IPRMDATA, NULL, 0);
atomic_dec(&monpriv->msglim_count);
if (likely(!monmsg->msglim_reached)) {
monmsg->pos = 0;
@@ -251,10 +236,19 @@ mon_send_reply(struct mon_msg *monmsg, struct mon_private *monpriv)
return 0;
}
-static inline struct mon_private *
-mon_alloc_mem(void)
+static inline void mon_free_mem(struct mon_private *monpriv)
+{
+ int i;
+
+ for (i = 0; i < MON_MSGLIM; i++)
+ if (monpriv->msg_array[i])
+ kfree(monpriv->msg_array[i]);
+ kfree(monpriv);
+}
+
+static inline struct mon_private *mon_alloc_mem(void)
{
- int i,j;
+ int i;
struct mon_private *monpriv;
monpriv = kzalloc(sizeof(struct mon_private), GFP_KERNEL);
@@ -267,16 +261,15 @@ mon_alloc_mem(void)
GFP_KERNEL);
if (!monpriv->msg_array[i]) {
P_ERROR("open, no memory for msg_array\n");
- for (j = 0; j < i; j++)
- kfree(monpriv->msg_array[j]);
+ mon_free_mem(monpriv);
return NULL;
}
}
return monpriv;
}
-static inline void
-mon_read_debug(struct mon_msg *monmsg, struct mon_private *monpriv)
+static inline void mon_read_debug(struct mon_msg *monmsg,
+ struct mon_private *monpriv)
{
#ifdef MON_DEBUG
u8 msg_type[2], mca_type;
@@ -284,7 +277,7 @@ mon_read_debug(struct mon_msg *monmsg, struct mon_private *monpriv)
records_len = mon_rec_end(monmsg) - mon_rec_start(monmsg) + 1;
- memcpy(msg_type, &monmsg->local_eib.iptrgcls, 2);
+ memcpy(msg_type, &monmsg->msg.class, 2);
EBCASC(msg_type, 2);
mca_type = mon_mca_type(monmsg, 0);
EBCASC(&mca_type, 1);
@@ -292,8 +285,7 @@ mon_read_debug(struct mon_msg *monmsg, struct mon_private *monpriv)
P_DEBUG("read, mon_read_index = %i, mon_write_index = %i\n",
monpriv->read_index, monpriv->write_index);
P_DEBUG("read, pathid = 0x%04X, msgid = 0x%08X, trgcls = 0x%08X\n",
- monmsg->local_eib.ippathid, monmsg->local_eib.ipmsgid,
- monmsg->local_eib.iptrgcls);
+ monpriv->path->pathid, monmsg->msg.id, monmsg->msg.class);
P_DEBUG("read, msg_type = '%c%c', mca_type = '%c' / 0x%X / 0x%X\n",
msg_type[0], msg_type[1], mca_type ? mca_type : 'X',
mon_mca_type(monmsg, 1), mon_mca_type(monmsg, 2));
@@ -306,8 +298,7 @@ mon_read_debug(struct mon_msg *monmsg, struct mon_private *monpriv)
#endif
}
-static inline void
-mon_next_mca(struct mon_msg *monmsg)
+static inline void mon_next_mca(struct mon_msg *monmsg)
{
if (likely((mon_mca_size(monmsg) - monmsg->mca_offset) == 12))
return;
@@ -316,8 +307,7 @@ mon_next_mca(struct mon_msg *monmsg)
monmsg->pos = 0;
}
-static inline struct mon_msg *
-mon_next_message(struct mon_private *monpriv)
+static inline struct mon_msg *mon_next_message(struct mon_private *monpriv)
{
struct mon_msg *monmsg;
@@ -342,39 +332,37 @@ mon_next_message(struct mon_private *monpriv)
/******************************************************************************
* IUCV handler *
*****************************************************************************/
-static void
-mon_iucv_ConnectionComplete(iucv_ConnectionComplete *eib, void *pgm_data)
+static void mon_iucv_path_complete(struct iucv_path *path, u8 ipuser[16])
{
- struct mon_private *monpriv = (struct mon_private *) pgm_data;
+ struct mon_private *monpriv = path->private;
P_DEBUG("IUCV connection completed\n");
P_DEBUG("IUCV ACCEPT (from *MONITOR): Version = 0x%02X, Event = "
"0x%02X, Sample = 0x%02X\n",
- eib->ipuser[0], eib->ipuser[1], eib->ipuser[2]);
+ ipuser[0], ipuser[1], ipuser[2]);
atomic_set(&monpriv->iucv_connected, 1);
wake_up(&mon_conn_wait_queue);
}
-static void
-mon_iucv_ConnectionSevered(iucv_ConnectionSevered *eib, void *pgm_data)
+static void mon_iucv_path_severed(struct iucv_path *path, u8 ipuser[16])
{
- struct mon_private *monpriv = (struct mon_private *) pgm_data;
+ struct mon_private *monpriv = path->private;
- P_ERROR("IUCV connection severed with rc = 0x%X\n",
- (u8) eib->ipuser[0]);
+ P_ERROR("IUCV connection severed with rc = 0x%X\n", ipuser[0]);
+ iucv_path_sever(path, NULL);
atomic_set(&monpriv->iucv_severed, 1);
wake_up(&mon_conn_wait_queue);
wake_up_interruptible(&mon_read_wait_queue);
}
-static void
-mon_iucv_MessagePending(iucv_MessagePending *eib, void *pgm_data)
+static void mon_iucv_message_pending(struct iucv_path *path,
+ struct iucv_message *msg)
{
- struct mon_private *monpriv = (struct mon_private *) pgm_data;
+ struct mon_private *monpriv = path->private;
P_DEBUG("IUCV message pending\n");
- memcpy(&monpriv->msg_array[monpriv->write_index]->local_eib, eib,
- sizeof(iucv_MessagePending));
+ memcpy(&monpriv->msg_array[monpriv->write_index]->msg,
+ msg, sizeof(*msg));
if (atomic_inc_return(&monpriv->msglim_count) == MON_MSGLIM) {
P_WARNING("IUCV message pending, message limit (%i) reached\n",
MON_MSGLIM);
@@ -385,54 +373,45 @@ mon_iucv_MessagePending(iucv_MessagePending *eib, void *pgm_data)
wake_up_interruptible(&mon_read_wait_queue);
}
-static iucv_interrupt_ops_t mon_iucvops = {
- .ConnectionComplete = mon_iucv_ConnectionComplete,
- .ConnectionSevered = mon_iucv_ConnectionSevered,
- .MessagePending = mon_iucv_MessagePending,
+static struct iucv_handler monreader_iucv_handler = {
+ .path_complete = mon_iucv_path_complete,
+ .path_severed = mon_iucv_path_severed,
+ .message_pending = mon_iucv_message_pending,
};
/******************************************************************************
* file operations *
*****************************************************************************/
-static int
-mon_open(struct inode *inode, struct file *filp)
+static int mon_open(struct inode *inode, struct file *filp)
{
- int rc, i;
struct mon_private *monpriv;
+ int rc;
/*
* only one user allowed
*/
+ rc = -EBUSY;
if (test_and_set_bit(MON_IN_USE, &mon_in_use))
- return -EBUSY;
+ goto out;
+ rc = -ENOMEM;
monpriv = mon_alloc_mem();
if (!monpriv)
- return -ENOMEM;
+ goto out_use;
/*
- * Register with IUCV and connect to *MONITOR service
+ * Connect to *MONITOR service
*/
- monpriv->iucv_handle = iucv_register_program("my_monreader ",
- MON_SERVICE,
- NULL,
- &mon_iucvops,
- monpriv);
- if (!monpriv->iucv_handle) {
- P_ERROR("failed to register with iucv driver\n");
- rc = -EIO;
- goto out_error;
- }
- P_INFO("open, registered with IUCV\n");
-
- rc = iucv_connect(&monpriv->pathid, MON_MSGLIM, user_data_connect,
- MON_SERVICE, iucv_host, IPRMDATA, NULL, NULL,
- monpriv->iucv_handle, NULL);
+ monpriv->path = iucv_path_alloc(MON_MSGLIM, IUCV_IPRMDATA, GFP_KERNEL);
+ if (!monpriv->path)
+ goto out_priv;
+ rc = iucv_path_connect(monpriv->path, &monreader_iucv_handler,
+ MON_SERVICE, NULL, user_data_connect, monpriv);
if (rc) {
P_ERROR("iucv connection to *MONITOR failed with "
"IPUSER SEVER code = %i\n", rc);
rc = -EIO;
- goto out_unregister;
+ goto out_path;
}
/*
* Wait for connection confirmation
@@ -444,24 +423,23 @@ mon_open(struct inode *inode, struct file *filp)
atomic_set(&monpriv->iucv_severed, 0);
atomic_set(&monpriv->iucv_connected, 0);
rc = -EIO;
- goto out_unregister;
+ goto out_path;
}
P_INFO("open, established connection to *MONITOR service\n\n");
filp->private_data = monpriv;
return nonseekable_open(inode, filp);
-out_unregister:
- iucv_unregister_program(monpriv->iucv_handle);
-out_error:
- for (i = 0; i < MON_MSGLIM; i++)
- kfree(monpriv->msg_array[i]);
- kfree(monpriv);
+out_path:
+ kfree(monpriv->path);
+out_priv:
+ mon_free_mem(monpriv);
+out_use:
clear_bit(MON_IN_USE, &mon_in_use);
+out:
return rc;
}
-static int
-mon_close(struct inode *inode, struct file *filp)
+static int mon_close(struct inode *inode, struct file *filp)
{
int rc, i;
struct mon_private *monpriv = filp->private_data;
@@ -469,18 +447,12 @@ mon_close(struct inode *inode, struct file *filp)
/*
* Close IUCV connection and unregister
*/
- rc = iucv_sever(monpriv->pathid, user_data_sever);
+ rc = iucv_path_sever(monpriv->path, user_data_sever);
if (rc)
P_ERROR("close, iucv_sever failed with rc = %i\n", rc);
else
P_INFO("close, terminated connection to *MONITOR service\n");
- rc = iucv_unregister_program(monpriv->iucv_handle);
- if (rc)
- P_ERROR("close, iucv_unregister failed with rc = %i\n", rc);
- else
- P_INFO("close, unregistered with IUCV\n");
-
atomic_set(&monpriv->iucv_severed, 0);
atomic_set(&monpriv->iucv_connected, 0);
atomic_set(&monpriv->read_ready, 0);
@@ -495,8 +467,8 @@ mon_close(struct inode *inode, struct file *filp)
return 0;
}
-static ssize_t
-mon_read(struct file *filp, char __user *data, size_t count, loff_t *ppos)
+static ssize_t mon_read(struct file *filp, char __user *data,
+ size_t count, loff_t *ppos)
{
struct mon_private *monpriv = filp->private_data;
struct mon_msg *monmsg;
@@ -563,8 +535,7 @@ out_copy:
return count;
}
-static unsigned int
-mon_poll(struct file *filp, struct poll_table_struct *p)
+static unsigned int mon_poll(struct file *filp, struct poll_table_struct *p)
{
struct mon_private *monpriv = filp->private_data;
@@ -576,7 +547,7 @@ mon_poll(struct file *filp, struct poll_table_struct *p)
return 0;
}
-static struct file_operations mon_fops = {
+static const struct file_operations mon_fops = {
.owner = THIS_MODULE,
.open = &mon_open,
.release = &mon_close,
@@ -593,8 +564,7 @@ static struct miscdevice mon_dev = {
/******************************************************************************
* module init/exit *
*****************************************************************************/
-static int __init
-mon_init(void)
+static int __init mon_init(void)
{
int rc;
@@ -603,22 +573,34 @@ mon_init(void)
return -ENODEV;
}
+ /*
+ * Register with IUCV and connect to *MONITOR service
+ */
+ rc = iucv_register(&monreader_iucv_handler, 1);
+ if (rc) {
+ P_ERROR("failed to register with iucv driver\n");
+ return rc;
+ }
+ P_INFO("open, registered with IUCV\n");
+
rc = segment_type(mon_dcss_name);
if (rc < 0) {
mon_segment_warn(rc, mon_dcss_name);
- return rc;
+ goto out_iucv;
}
if (rc != SEG_TYPE_SC) {
P_ERROR("segment %s has unsupported type, should be SC\n",
mon_dcss_name);
- return -EINVAL;
+ rc = -EINVAL;
+ goto out_iucv;
}
rc = segment_load(mon_dcss_name, SEGMENT_SHARED,
&mon_dcss_start, &mon_dcss_end);
if (rc < 0) {
mon_segment_warn(rc, mon_dcss_name);
- return -EINVAL;
+ rc = -EINVAL;
+ goto out_iucv;
}
dcss_mkname(mon_dcss_name, &user_data_connect[8]);
@@ -634,14 +616,16 @@ mon_init(void)
out:
segment_unload(mon_dcss_name);
+out_iucv:
+ iucv_unregister(&monreader_iucv_handler, 1);
return rc;
}
-static void __exit
-mon_exit(void)
+static void __exit mon_exit(void)
{
segment_unload(mon_dcss_name);
WARN_ON(misc_deregister(&mon_dev) != 0);
+ iucv_unregister(&monreader_iucv_handler, 1);
return;
}
diff --git a/drivers/s390/char/monwriter.c b/drivers/s390/char/monwriter.c
index cdb24f52811..268598ef3ef 100644
--- a/drivers/s390/char/monwriter.c
+++ b/drivers/s390/char/monwriter.c
@@ -67,8 +67,8 @@ static int monwrite_diag(struct monwrite_hdr *myhdr, char *buffer, int fcn)
return -EINVAL;
}
-static inline struct mon_buf *monwrite_find_hdr(struct mon_private *monpriv,
- struct monwrite_hdr *monhdr)
+static struct mon_buf *monwrite_find_hdr(struct mon_private *monpriv,
+ struct monwrite_hdr *monhdr)
{
struct mon_buf *entry, *next;
@@ -255,7 +255,7 @@ out_error:
return rc;
}
-static struct file_operations monwrite_fops = {
+static const struct file_operations monwrite_fops = {
.owner = THIS_MODULE,
.open = &monwrite_open,
.release = &monwrite_close,
diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c
index 7a84014f203..8facd14adb7 100644
--- a/drivers/s390/char/raw3270.c
+++ b/drivers/s390/char/raw3270.c
@@ -29,7 +29,7 @@
#include <linux/device.h>
#include <linux/mutex.h>
-struct class *class3270;
+static struct class *class3270;
/* The main 3270 data structure. */
struct raw3270 {
@@ -86,7 +86,7 @@ DECLARE_WAIT_QUEUE_HEAD(raw3270_wait_queue);
/*
* Encode array for 12 bit 3270 addresses.
*/
-unsigned char raw3270_ebcgraf[64] = {
+static unsigned char raw3270_ebcgraf[64] = {
0x40, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
0xc8, 0xc9, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
0x50, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c
index 8a056df09d6..f171de3b0b1 100644
--- a/drivers/s390/char/sclp.c
+++ b/drivers/s390/char/sclp.c
@@ -59,7 +59,8 @@ static volatile enum sclp_init_state_t {
/* Internal state: is a request active at the sclp? */
static volatile enum sclp_running_state_t {
sclp_running_state_idle,
- sclp_running_state_running
+ sclp_running_state_running,
+ sclp_running_state_reset_pending
} sclp_running_state = sclp_running_state_idle;
/* Internal state: is a read request pending? */
@@ -88,15 +89,15 @@ static volatile enum sclp_mask_state_t {
/* Timeout intervals in seconds.*/
#define SCLP_BUSY_INTERVAL 10
-#define SCLP_RETRY_INTERVAL 15
+#define SCLP_RETRY_INTERVAL 30
static void sclp_process_queue(void);
static int sclp_init_mask(int calculate);
static int sclp_init(void);
/* Perform service call. Return 0 on success, non-zero otherwise. */
-static int
-service_call(sclp_cmdw_t command, void *sccb)
+int
+sclp_service_call(sclp_cmdw_t command, void *sccb)
{
int cc;
@@ -113,19 +114,17 @@ service_call(sclp_cmdw_t command, void *sccb)
return 0;
}
-/* Request timeout handler. Restart the request queue. If DATA is non-zero,
- * force restart of running request. */
+static inline void __sclp_make_read_req(void);
+
static void
-sclp_request_timeout(unsigned long data)
+__sclp_queue_read_req(void)
{
- unsigned long flags;
-
- if (data) {
- spin_lock_irqsave(&sclp_lock, flags);
- sclp_running_state = sclp_running_state_idle;
- spin_unlock_irqrestore(&sclp_lock, flags);
+ if (sclp_reading_state == sclp_reading_state_idle) {
+ sclp_reading_state = sclp_reading_state_reading;
+ __sclp_make_read_req();
+ /* Add request to head of queue */
+ list_add(&sclp_read_req.list, &sclp_req_queue);
}
- sclp_process_queue();
}
/* Set up request retry timer. Called while sclp_lock is locked. */
@@ -140,6 +139,29 @@ __sclp_set_request_timer(unsigned long time, void (*function)(unsigned long),
add_timer(&sclp_request_timer);
}
+/* Request timeout handler. Restart the request queue. If DATA is non-zero,
+ * force restart of running request. */
+static void
+sclp_request_timeout(unsigned long data)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&sclp_lock, flags);
+ if (data) {
+ if (sclp_running_state == sclp_running_state_running) {
+ /* Break running state and queue NOP read event request
+ * to get a defined interface state. */
+ __sclp_queue_read_req();
+ sclp_running_state = sclp_running_state_idle;
+ }
+ } else {
+ __sclp_set_request_timer(SCLP_BUSY_INTERVAL * HZ,
+ sclp_request_timeout, 0);
+ }
+ spin_unlock_irqrestore(&sclp_lock, flags);
+ sclp_process_queue();
+}
+
/* Try to start a request. Return zero if the request was successfully
* started or if it will be started at a later time. Return non-zero otherwise.
* Called while sclp_lock is locked. */
@@ -151,7 +173,7 @@ __sclp_start_request(struct sclp_req *req)
if (sclp_running_state != sclp_running_state_idle)
return 0;
del_timer(&sclp_request_timer);
- rc = service_call(req->command, req->sccb);
+ rc = sclp_service_call(req->command, req->sccb);
req->start_count++;
if (rc == 0) {
@@ -191,7 +213,15 @@ sclp_process_queue(void)
rc = __sclp_start_request(req);
if (rc == 0)
break;
- /* Request failed. */
+ /* Request failed */
+ if (req->start_count > 1) {
+ /* Cannot abort already submitted request - could still
+ * be active at the SCLP */
+ __sclp_set_request_timer(SCLP_BUSY_INTERVAL * HZ,
+ sclp_request_timeout, 0);
+ break;
+ }
+ /* Post-processing for aborted request */
list_del(&req->list);
if (req->callback) {
spin_unlock_irqrestore(&sclp_lock, flags);
@@ -221,7 +251,8 @@ sclp_add_request(struct sclp_req *req)
list_add_tail(&req->list, &sclp_req_queue);
rc = 0;
/* Start if request is first in list */
- if (req->list.prev == &sclp_req_queue) {
+ if (sclp_running_state == sclp_running_state_idle &&
+ req->list.prev == &sclp_req_queue) {
rc = __sclp_start_request(req);
if (rc)
list_del(&req->list);
@@ -294,7 +325,7 @@ __sclp_make_read_req(void)
sccb = (struct sccb_header *) sclp_read_sccb;
clear_page(sccb);
memset(&sclp_read_req, 0, sizeof(struct sclp_req));
- sclp_read_req.command = SCLP_CMDW_READDATA;
+ sclp_read_req.command = SCLP_CMDW_READ_EVENT_DATA;
sclp_read_req.status = SCLP_REQ_QUEUED;
sclp_read_req.start_count = 0;
sclp_read_req.callback = sclp_read_cb;
@@ -334,6 +365,8 @@ sclp_interrupt_handler(__u16 code)
finished_sccb = S390_lowcore.ext_params & 0xfffffff8;
evbuf_pending = S390_lowcore.ext_params & 0x3;
if (finished_sccb) {
+ del_timer(&sclp_request_timer);
+ sclp_running_state = sclp_running_state_reset_pending;
req = __sclp_find_req(finished_sccb);
if (req) {
/* Request post-processing */
@@ -348,13 +381,8 @@ sclp_interrupt_handler(__u16 code)
sclp_running_state = sclp_running_state_idle;
}
if (evbuf_pending && sclp_receive_mask != 0 &&
- sclp_reading_state == sclp_reading_state_idle &&
- sclp_activation_state == sclp_activation_state_active ) {
- sclp_reading_state = sclp_reading_state_reading;
- __sclp_make_read_req();
- /* Add request to head of queue */
- list_add(&sclp_read_req.list, &sclp_req_queue);
- }
+ sclp_activation_state == sclp_activation_state_active)
+ __sclp_queue_read_req();
spin_unlock(&sclp_lock);
sclp_process_queue();
}
@@ -374,6 +402,7 @@ sclp_sync_wait(void)
unsigned long flags;
unsigned long cr0, cr0_sync;
u64 timeout;
+ int irq_context;
/* We'll be disabling timer interrupts, so we need a custom timeout
* mechanism */
@@ -386,7 +415,9 @@ sclp_sync_wait(void)
}
local_irq_save(flags);
/* Prevent bottom half from executing once we force interrupts open */
- local_bh_disable();
+ irq_context = in_interrupt();
+ if (!irq_context)
+ local_bh_disable();
/* Enable service-signal interruption, disable timer interrupts */
trace_hardirqs_on();
__ctl_store(cr0, 0, 0);
@@ -402,19 +433,19 @@ sclp_sync_wait(void)
get_clock() > timeout &&
del_timer(&sclp_request_timer))
sclp_request_timer.function(sclp_request_timer.data);
- barrier();
cpu_relax();
}
local_irq_disable();
__ctl_load(cr0, 0, 0);
- _local_bh_enable();
+ if (!irq_context)
+ _local_bh_enable();
local_irq_restore(flags);
}
EXPORT_SYMBOL(sclp_sync_wait);
/* Dispatch changes in send and receive mask to registered listeners. */
-static inline void
+static void
sclp_dispatch_state_change(void)
{
struct list_head *l;
@@ -597,7 +628,7 @@ __sclp_make_init_req(u32 receive_mask, u32 send_mask)
sccb = (struct init_sccb *) sclp_init_sccb;
clear_page(sccb);
memset(&sclp_init_req, 0, sizeof(struct sclp_req));
- sclp_init_req.command = SCLP_CMDW_WRITEMASK;
+ sclp_init_req.command = SCLP_CMDW_WRITE_EVENT_MASK;
sclp_init_req.status = SCLP_REQ_FILLED;
sclp_init_req.start_count = 0;
sclp_init_req.callback = NULL;
@@ -800,7 +831,7 @@ sclp_check_interface(void)
for (retry = 0; retry <= SCLP_INIT_RETRY; retry++) {
__sclp_make_init_req(0, 0);
sccb = (struct init_sccb *) sclp_init_req.sccb;
- rc = service_call(sclp_init_req.command, sccb);
+ rc = sclp_service_call(sclp_init_req.command, sccb);
if (rc == -EIO)
break;
sclp_init_req.status = SCLP_REQ_RUNNING;
diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h
index 2c71d6ee7b5..7d29ab45a6e 100644
--- a/drivers/s390/char/sclp.h
+++ b/drivers/s390/char/sclp.h
@@ -12,7 +12,7 @@
#include <linux/types.h>
#include <linux/list.h>
-
+#include <asm/sclp.h>
#include <asm/ebcdic.h>
/* maximum number of pages concerning our own memory management */
@@ -49,9 +49,11 @@
typedef unsigned int sclp_cmdw_t;
-#define SCLP_CMDW_READDATA 0x00770005
-#define SCLP_CMDW_WRITEDATA 0x00760005
-#define SCLP_CMDW_WRITEMASK 0x00780005
+#define SCLP_CMDW_READ_EVENT_DATA 0x00770005
+#define SCLP_CMDW_WRITE_EVENT_DATA 0x00760005
+#define SCLP_CMDW_WRITE_EVENT_MASK 0x00780005
+#define SCLP_CMDW_READ_SCP_INFO 0x00020001
+#define SCLP_CMDW_READ_SCP_INFO_FORCED 0x00120001
#define GDS_ID_MDSMU 0x1310
#define GDS_ID_MDSRouteInfo 0x1311
@@ -66,13 +68,6 @@ typedef unsigned int sclp_cmdw_t;
typedef u32 sccb_mask_t; /* ATTENTION: assumes 32bit mask !!! */
-struct sccb_header {
- u16 length;
- u8 function_code;
- u8 control_mask[3];
- u16 response_code;
-} __attribute__((packed));
-
struct gds_subvector {
u8 length;
u8 key;
@@ -131,6 +126,7 @@ void sclp_unregister(struct sclp_register *reg);
int sclp_remove_processed(struct sccb_header *sccb);
int sclp_deactivate(void);
int sclp_reactivate(void);
+int sclp_service_call(sclp_cmdw_t command, void *sccb);
/* useful inlines */
diff --git a/drivers/s390/char/sclp_con.c b/drivers/s390/char/sclp_con.c
index 86864f64171..ead1043d788 100644
--- a/drivers/s390/char/sclp_con.c
+++ b/drivers/s390/char/sclp_con.c
@@ -66,7 +66,7 @@ sclp_conbuf_callback(struct sclp_buffer *buffer, int rc)
} while (buffer && sclp_emit_buffer(buffer, sclp_conbuf_callback));
}
-static inline void
+static void
sclp_conbuf_emit(void)
{
struct sclp_buffer* buffer;
diff --git a/drivers/s390/char/sclp_cpi.c b/drivers/s390/char/sclp_cpi.c
index 4f873ae148b..65aa2c85737 100644
--- a/drivers/s390/char/sclp_cpi.c
+++ b/drivers/s390/char/sclp_cpi.c
@@ -169,7 +169,7 @@ cpi_prepare_req(void)
}
/* prepare request data structure presented to SCLP driver */
- req->command = SCLP_CMDW_WRITEDATA;
+ req->command = SCLP_CMDW_WRITE_EVENT_DATA;
req->sccb = sccb;
req->status = SCLP_REQ_FILLED;
req->callback = cpi_callback;
diff --git a/drivers/s390/char/sclp_info.c b/drivers/s390/char/sclp_info.c
new file mode 100644
index 00000000000..7bcbe643b08
--- /dev/null
+++ b/drivers/s390/char/sclp_info.c
@@ -0,0 +1,57 @@
+/*
+ * drivers/s390/char/sclp_info.c
+ *
+ * Copyright IBM Corp. 2007
+ * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
+ */
+
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <asm/sclp.h>
+#include "sclp.h"
+
+struct sclp_readinfo_sccb s390_readinfo_sccb;
+
+void __init sclp_readinfo_early(void)
+{
+ sclp_cmdw_t command;
+ struct sccb_header *sccb;
+ int ret;
+
+ __ctl_set_bit(0, 9); /* enable service signal subclass mask */
+
+ sccb = &s390_readinfo_sccb.header;
+ command = SCLP_CMDW_READ_SCP_INFO_FORCED;
+ while (1) {
+ u16 response;
+
+ memset(&s390_readinfo_sccb, 0, sizeof(s390_readinfo_sccb));
+ sccb->length = sizeof(s390_readinfo_sccb);
+ sccb->control_mask[2] = 0x80;
+
+ ret = sclp_service_call(command, &s390_readinfo_sccb);
+
+ if (ret == -EIO)
+ goto out;
+ if (ret == -EBUSY)
+ continue;
+
+ __load_psw_mask(PSW_BASE_BITS | PSW_MASK_EXT |
+ PSW_MASK_WAIT | PSW_DEFAULT_KEY);
+ local_irq_disable();
+ barrier();
+
+ response = sccb->response_code;
+
+ if (response == 0x10)
+ break;
+
+ if (response != 0x1f0 || command == SCLP_CMDW_READ_SCP_INFO)
+ break;
+
+ command = SCLP_CMDW_READ_SCP_INFO;
+ }
+out:
+ __ctl_clear_bit(0, 9); /* disable service signal subclass mask */
+}
diff --git a/drivers/s390/char/sclp_quiesce.c b/drivers/s390/char/sclp_quiesce.c
index ffa9282ce97..baa8fe669ed 100644
--- a/drivers/s390/char/sclp_quiesce.c
+++ b/drivers/s390/char/sclp_quiesce.c
@@ -16,6 +16,7 @@
#include <asm/atomic.h>
#include <asm/ptrace.h>
#include <asm/sigp.h>
+#include <asm/smp.h>
#include "sclp.h"
diff --git a/drivers/s390/char/sclp_rw.c b/drivers/s390/char/sclp_rw.c
index 0c92d3909cc..2486783ea58 100644
--- a/drivers/s390/char/sclp_rw.c
+++ b/drivers/s390/char/sclp_rw.c
@@ -460,7 +460,7 @@ sclp_emit_buffer(struct sclp_buffer *buffer,
sccb->msg_buf.header.type = EvTyp_PMsgCmd;
else
return -ENOSYS;
- buffer->request.command = SCLP_CMDW_WRITEDATA;
+ buffer->request.command = SCLP_CMDW_WRITE_EVENT_DATA;
buffer->request.status = SCLP_REQ_FILLED;
buffer->request.callback = sclp_writedata_callback;
buffer->request.callback_data = buffer;
diff --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c
index 2d173e5c8a0..076816b9d52 100644
--- a/drivers/s390/char/sclp_tty.c
+++ b/drivers/s390/char/sclp_tty.c
@@ -13,7 +13,6 @@
#include <linux/tty.h>
#include <linux/tty_driver.h>
#include <linux/tty_flip.h>
-#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/slab.h>
#include <linux/err.h>
@@ -721,7 +720,7 @@ static const struct tty_operations sclp_ops = {
.ioctl = sclp_tty_ioctl,
};
-int __init
+static int __init
sclp_tty_init(void)
{
struct tty_driver *driver;
diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c
index 723bf4191bf..f77dc33b5f8 100644
--- a/drivers/s390/char/sclp_vt220.c
+++ b/drivers/s390/char/sclp_vt220.c
@@ -16,7 +16,6 @@
#include <linux/tty.h>
#include <linux/tty_driver.h>
#include <linux/tty_flip.h>
-#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/major.h>
@@ -207,7 +206,7 @@ __sclp_vt220_emit(struct sclp_vt220_request *request)
request->sclp_req.status = SCLP_REQ_FAILED;
return -EIO;
}
- request->sclp_req.command = SCLP_CMDW_WRITEDATA;
+ request->sclp_req.command = SCLP_CMDW_WRITE_EVENT_DATA;
request->sclp_req.status = SCLP_REQ_FILLED;
request->sclp_req.callback = sclp_vt220_callback;
request->sclp_req.callback_data = (void *) request;
@@ -669,7 +668,7 @@ static const struct tty_operations sclp_vt220_ops = {
/*
* Register driver with SCLP and Linux and initialize internal tty structures.
*/
-int __init
+static int __init
sclp_vt220_tty_init(void)
{
struct tty_driver *driver;
diff --git a/drivers/s390/char/tape.h b/drivers/s390/char/tape.h
index c9f1c4c8bb1..bb4ff537729 100644
--- a/drivers/s390/char/tape.h
+++ b/drivers/s390/char/tape.h
@@ -3,7 +3,7 @@
* tape device driver for 3480/3490E/3590 tapes.
*
* S390 and zSeries version
- * Copyright (C) 2001,2005 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Copyright IBM Corp. 2001,2006
* Author(s): Carsten Otte <cotte@de.ibm.com>
* Tuan Ngo-Anh <ngoanh@de.ibm.com>
* Martin Schwidefsky <schwidefsky@de.ibm.com>
@@ -99,7 +99,11 @@ enum tape_op {
TO_DIS, /* Tape display */
TO_ASSIGN, /* Assign tape to channel path */
TO_UNASSIGN, /* Unassign tape from channel path */
- TO_SIZE /* #entries in tape_op_t */
+ TO_CRYPT_ON, /* Enable encrpytion */
+ TO_CRYPT_OFF, /* Disable encrpytion */
+ TO_KEKL_SET, /* Set KEK label */
+ TO_KEKL_QUERY, /* Query KEK label */
+ TO_SIZE, /* #entries in tape_op_t */
};
/* Forward declaration */
@@ -112,6 +116,7 @@ enum tape_request_status {
TAPE_REQUEST_IN_IO, /* request is currently in IO */
TAPE_REQUEST_DONE, /* request is completed. */
TAPE_REQUEST_CANCEL, /* request should be canceled. */
+ TAPE_REQUEST_LONG_BUSY, /* request has to be restarted after long busy */
};
/* Tape CCW request */
@@ -164,10 +169,11 @@ struct tape_discipline {
* The discipline irq function either returns an error code (<0) which
* means that the request has failed with an error or one of the following:
*/
-#define TAPE_IO_SUCCESS 0 /* request successful */
-#define TAPE_IO_PENDING 1 /* request still running */
-#define TAPE_IO_RETRY 2 /* retry to current request */
-#define TAPE_IO_STOP 3 /* stop the running request */
+#define TAPE_IO_SUCCESS 0 /* request successful */
+#define TAPE_IO_PENDING 1 /* request still running */
+#define TAPE_IO_RETRY 2 /* retry to current request */
+#define TAPE_IO_STOP 3 /* stop the running request */
+#define TAPE_IO_LONG_BUSY 4 /* delay the running request */
/* Char Frontend Data */
struct tape_char_data {
@@ -242,6 +248,10 @@ struct tape_device {
/* Function to start or stop the next request later. */
struct delayed_work tape_dnr;
+
+ /* Timer for long busy */
+ struct timer_list lb_timeout;
+
};
/* Externals from tape_core.c */
diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c
index 9df912f6318..50f5edab83d 100644
--- a/drivers/s390/char/tape_3590.c
+++ b/drivers/s390/char/tape_3590.c
@@ -2,7 +2,7 @@
* drivers/s390/char/tape_3590.c
* tape device discipline for 3590 tapes.
*
- * Copyright (C) IBM Corp. 2001,2006
+ * Copyright IBM Corp. 2001,2006
* Author(s): Stefan Bader <shbader@de.ibm.com>
* Michael Holzheu <holzheu@de.ibm.com>
* Martin Schwidefsky <schwidefsky@de.ibm.com>
@@ -11,6 +11,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/bio.h>
+#include <asm/ebcdic.h>
#define TAPE_DBF_AREA tape_3590_dbf
@@ -30,7 +31,7 @@ EXPORT_SYMBOL(TAPE_DBF_AREA);
* - Read Device (buffered) log: BRA
* - Read Library log: BRA
* - Swap Devices: BRA
- * - Long Busy: BRA
+ * - Long Busy: implemented
* - Special Intercept: BRA
* - Read Alternate: implemented
*******************************************************************/
@@ -94,6 +95,332 @@ static const char *tape_3590_msg[TAPE_3590_MAX_MSG] = {
[0xae] = "Subsystem environmental alert",
};
+static int crypt_supported(struct tape_device *device)
+{
+ return TAPE390_CRYPT_SUPPORTED(TAPE_3590_CRYPT_INFO(device));
+}
+
+static int crypt_enabled(struct tape_device *device)
+{
+ return TAPE390_CRYPT_ON(TAPE_3590_CRYPT_INFO(device));
+}
+
+static void ext_to_int_kekl(struct tape390_kekl *in,
+ struct tape3592_kekl *out)
+{
+ int i;
+
+ memset(out, 0, sizeof(*out));
+ if (in->type == TAPE390_KEKL_TYPE_HASH)
+ out->flags |= 0x40;
+ if (in->type_on_tape == TAPE390_KEKL_TYPE_HASH)
+ out->flags |= 0x80;
+ strncpy(out->label, in->label, 64);
+ for (i = strlen(in->label); i < sizeof(out->label); i++)
+ out->label[i] = ' ';
+ ASCEBC(out->label, sizeof(out->label));
+}
+
+static void int_to_ext_kekl(struct tape3592_kekl *in,
+ struct tape390_kekl *out)
+{
+ memset(out, 0, sizeof(*out));
+ if(in->flags & 0x40)
+ out->type = TAPE390_KEKL_TYPE_HASH;
+ else
+ out->type = TAPE390_KEKL_TYPE_LABEL;
+ if(in->flags & 0x80)
+ out->type_on_tape = TAPE390_KEKL_TYPE_HASH;
+ else
+ out->type_on_tape = TAPE390_KEKL_TYPE_LABEL;
+ memcpy(out->label, in->label, sizeof(in->label));
+ EBCASC(out->label, sizeof(in->label));
+ strstrip(out->label);
+}
+
+static void int_to_ext_kekl_pair(struct tape3592_kekl_pair *in,
+ struct tape390_kekl_pair *out)
+{
+ if (in->count == 0) {
+ out->kekl[0].type = TAPE390_KEKL_TYPE_NONE;
+ out->kekl[0].type_on_tape = TAPE390_KEKL_TYPE_NONE;
+ out->kekl[1].type = TAPE390_KEKL_TYPE_NONE;
+ out->kekl[1].type_on_tape = TAPE390_KEKL_TYPE_NONE;
+ } else if (in->count == 1) {
+ int_to_ext_kekl(&in->kekl[0], &out->kekl[0]);
+ out->kekl[1].type = TAPE390_KEKL_TYPE_NONE;
+ out->kekl[1].type_on_tape = TAPE390_KEKL_TYPE_NONE;
+ } else if (in->count == 2) {
+ int_to_ext_kekl(&in->kekl[0], &out->kekl[0]);
+ int_to_ext_kekl(&in->kekl[1], &out->kekl[1]);
+ } else {
+ printk("Invalid KEKL number: %d\n", in->count);
+ BUG();
+ }
+}
+
+static int check_ext_kekl(struct tape390_kekl *kekl)
+{
+ if (kekl->type == TAPE390_KEKL_TYPE_NONE)
+ goto invalid;
+ if (kekl->type > TAPE390_KEKL_TYPE_HASH)
+ goto invalid;
+ if (kekl->type_on_tape == TAPE390_KEKL_TYPE_NONE)
+ goto invalid;
+ if (kekl->type_on_tape > TAPE390_KEKL_TYPE_HASH)
+ goto invalid;
+ if ((kekl->type == TAPE390_KEKL_TYPE_HASH) &&
+ (kekl->type_on_tape == TAPE390_KEKL_TYPE_LABEL))
+ goto invalid;
+
+ return 0;
+invalid:
+ return -EINVAL;
+}
+
+static int check_ext_kekl_pair(struct tape390_kekl_pair *kekls)
+{
+ if (check_ext_kekl(&kekls->kekl[0]))
+ goto invalid;
+ if (check_ext_kekl(&kekls->kekl[1]))
+ goto invalid;
+
+ return 0;
+invalid:
+ return -EINVAL;
+}
+
+/*
+ * Query KEKLs
+ */
+static int tape_3592_kekl_query(struct tape_device *device,
+ struct tape390_kekl_pair *ext_kekls)
+{
+ struct tape_request *request;
+ struct tape3592_kekl_query_order *order;
+ struct tape3592_kekl_query_data *int_kekls;
+ int rc;
+
+ DBF_EVENT(6, "tape3592_kekl_query\n");
+ int_kekls = kmalloc(sizeof(*int_kekls), GFP_KERNEL|GFP_DMA);
+ if (!int_kekls)
+ return -ENOMEM;
+ request = tape_alloc_request(2, sizeof(*order));
+ if (IS_ERR(request)) {
+ rc = PTR_ERR(request);
+ goto fail_malloc;
+ }
+ order = request->cpdata;
+ memset(order,0,sizeof(*order));
+ order->code = 0xe2;
+ order->max_count = 2;
+ request->op = TO_KEKL_QUERY;
+ tape_ccw_cc(request->cpaddr, PERF_SUBSYS_FUNC, sizeof(*order), order);
+ tape_ccw_end(request->cpaddr + 1, READ_SS_DATA, sizeof(*int_kekls),
+ int_kekls);
+ rc = tape_do_io(device, request);
+ if (rc)
+ goto fail_request;
+ int_to_ext_kekl_pair(&int_kekls->kekls, ext_kekls);
+
+ rc = 0;
+fail_request:
+ tape_free_request(request);
+fail_malloc:
+ kfree(int_kekls);
+ return rc;
+}
+
+/*
+ * IOCTL: Query KEKLs
+ */
+static int tape_3592_ioctl_kekl_query(struct tape_device *device,
+ unsigned long arg)
+{
+ int rc;
+ struct tape390_kekl_pair *ext_kekls;
+
+ DBF_EVENT(6, "tape_3592_ioctl_kekl_query\n");
+ if (!crypt_supported(device))
+ return -ENOSYS;
+ if (!crypt_enabled(device))
+ return -EUNATCH;
+ ext_kekls = kmalloc(sizeof(*ext_kekls), GFP_KERNEL);
+ if (!ext_kekls)
+ return -ENOMEM;
+ rc = tape_3592_kekl_query(device, ext_kekls);
+ if (rc != 0)
+ goto fail;
+ if (copy_to_user((char __user *) arg, ext_kekls, sizeof(*ext_kekls))) {
+ rc = -EFAULT;
+ goto fail;
+ }
+ rc = 0;
+fail:
+ kfree(ext_kekls);
+ return rc;
+}
+
+static int tape_3590_mttell(struct tape_device *device, int mt_count);
+
+/*
+ * Set KEKLs
+ */
+static int tape_3592_kekl_set(struct tape_device *device,
+ struct tape390_kekl_pair *ext_kekls)
+{
+ struct tape_request *request;
+ struct tape3592_kekl_set_order *order;
+
+ DBF_EVENT(6, "tape3592_kekl_set\n");
+ if (check_ext_kekl_pair(ext_kekls)) {
+ DBF_EVENT(6, "invalid kekls\n");
+ return -EINVAL;
+ }
+ if (tape_3590_mttell(device, 0) != 0)
+ return -EBADSLT;
+ request = tape_alloc_request(1, sizeof(*order));
+ if (IS_ERR(request))
+ return PTR_ERR(request);
+ order = request->cpdata;
+ memset(order, 0, sizeof(*order));
+ order->code = 0xe3;
+ order->kekls.count = 2;
+ ext_to_int_kekl(&ext_kekls->kekl[0], &order->kekls.kekl[0]);
+ ext_to_int_kekl(&ext_kekls->kekl[1], &order->kekls.kekl[1]);
+ request->op = TO_KEKL_SET;
+ tape_ccw_end(request->cpaddr, PERF_SUBSYS_FUNC, sizeof(*order), order);
+
+ return tape_do_io_free(device, request);
+}
+
+/*
+ * IOCTL: Set KEKLs
+ */
+static int tape_3592_ioctl_kekl_set(struct tape_device *device,
+ unsigned long arg)
+{
+ int rc;
+ struct tape390_kekl_pair *ext_kekls;
+
+ DBF_EVENT(6, "tape_3592_ioctl_kekl_set\n");
+ if (!crypt_supported(device))
+ return -ENOSYS;
+ if (!crypt_enabled(device))
+ return -EUNATCH;
+ ext_kekls = kmalloc(sizeof(*ext_kekls), GFP_KERNEL);
+ if (!ext_kekls)
+ return -ENOMEM;
+ if (copy_from_user(ext_kekls, (char __user *)arg, sizeof(*ext_kekls))) {
+ rc = -EFAULT;
+ goto out;
+ }
+ rc = tape_3592_kekl_set(device, ext_kekls);
+out:
+ kfree(ext_kekls);
+ return rc;
+}
+
+/*
+ * Enable encryption
+ */
+static int tape_3592_enable_crypt(struct tape_device *device)
+{
+ struct tape_request *request;
+ char *data;
+
+ DBF_EVENT(6, "tape_3592_enable_crypt\n");
+ if (!crypt_supported(device))
+ return -ENOSYS;
+ request = tape_alloc_request(2, 72);
+ if (IS_ERR(request))
+ return PTR_ERR(request);
+ data = request->cpdata;
+ memset(data,0,72);
+
+ data[0] = 0x05;
+ data[36 + 0] = 0x03;
+ data[36 + 1] = 0x03;
+ data[36 + 4] = 0x40;
+ data[36 + 6] = 0x01;
+ data[36 + 14] = 0x2f;
+ data[36 + 18] = 0xc3;
+ data[36 + 35] = 0x72;
+ request->op = TO_CRYPT_ON;
+ tape_ccw_cc(request->cpaddr, MODE_SET_CB, 36, data);
+ tape_ccw_end(request->cpaddr + 1, MODE_SET_CB, 36, data + 36);
+ return tape_do_io_free(device, request);
+}
+
+/*
+ * Disable encryption
+ */
+static int tape_3592_disable_crypt(struct tape_device *device)
+{
+ struct tape_request *request;
+ char *data;
+
+ DBF_EVENT(6, "tape_3592_disable_crypt\n");
+ if (!crypt_supported(device))
+ return -ENOSYS;
+ request = tape_alloc_request(2, 72);
+ if (IS_ERR(request))
+ return PTR_ERR(request);
+ data = request->cpdata;
+ memset(data,0,72);
+
+ data[0] = 0x05;
+ data[36 + 0] = 0x03;
+ data[36 + 1] = 0x03;
+ data[36 + 35] = 0x32;
+
+ request->op = TO_CRYPT_OFF;
+ tape_ccw_cc(request->cpaddr, MODE_SET_CB, 36, data);
+ tape_ccw_end(request->cpaddr + 1, MODE_SET_CB, 36, data + 36);
+
+ return tape_do_io_free(device, request);
+}
+
+/*
+ * IOCTL: Set encryption status
+ */
+static int tape_3592_ioctl_crypt_set(struct tape_device *device,
+ unsigned long arg)
+{
+ struct tape390_crypt_info info;
+
+ DBF_EVENT(6, "tape_3592_ioctl_crypt_set\n");
+ if (!crypt_supported(device))
+ return -ENOSYS;
+ if (copy_from_user(&info, (char __user *)arg, sizeof(info)))
+ return -EFAULT;
+ if (info.status & ~TAPE390_CRYPT_ON_MASK)
+ return -EINVAL;
+ if (info.status & TAPE390_CRYPT_ON_MASK)
+ return tape_3592_enable_crypt(device);
+ else
+ return tape_3592_disable_crypt(device);
+}
+
+static int tape_3590_sense_medium(struct tape_device *device);
+
+/*
+ * IOCTL: Query enryption status
+ */
+static int tape_3592_ioctl_crypt_query(struct tape_device *device,
+ unsigned long arg)
+{
+ DBF_EVENT(6, "tape_3592_ioctl_crypt_query\n");
+ if (!crypt_supported(device))
+ return -ENOSYS;
+ tape_3590_sense_medium(device);
+ if (copy_to_user((char __user *) arg, &TAPE_3590_CRYPT_INFO(device),
+ sizeof(TAPE_3590_CRYPT_INFO(device))))
+ return -EFAULT;
+ else
+ return 0;
+}
+
/*
* 3590 IOCTL Overload
*/
@@ -109,6 +436,14 @@ tape_3590_ioctl(struct tape_device *device, unsigned int cmd, unsigned long arg)
return tape_std_display(device, &disp);
}
+ case TAPE390_KEKL_SET:
+ return tape_3592_ioctl_kekl_set(device, arg);
+ case TAPE390_KEKL_QUERY:
+ return tape_3592_ioctl_kekl_query(device, arg);
+ case TAPE390_CRYPT_SET:
+ return tape_3592_ioctl_crypt_set(device, arg);
+ case TAPE390_CRYPT_QUERY:
+ return tape_3592_ioctl_crypt_query(device, arg);
default:
return -EINVAL; /* no additional ioctls */
}
@@ -248,6 +583,12 @@ tape_3590_work_handler(struct work_struct *work)
case TO_READ_ATTMSG:
tape_3590_read_attmsg(p->device);
break;
+ case TO_CRYPT_ON:
+ tape_3592_enable_crypt(p->device);
+ break;
+ case TO_CRYPT_OFF:
+ tape_3592_disable_crypt(p->device);
+ break;
default:
DBF_EVENT(3, "T3590: work handler undefined for "
"operation 0x%02x\n", p->op);
@@ -365,6 +706,33 @@ tape_3590_check_locate(struct tape_device *device, struct tape_request *request)
}
#endif
+static void tape_3590_med_state_set(struct tape_device *device,
+ struct tape_3590_med_sense *sense)
+{
+ struct tape390_crypt_info *c_info;
+
+ c_info = &TAPE_3590_CRYPT_INFO(device);
+
+ if (sense->masst == MSENSE_UNASSOCIATED) {
+ tape_med_state_set(device, MS_UNLOADED);
+ TAPE_3590_CRYPT_INFO(device).medium_status = 0;
+ return;
+ }
+ if (sense->masst != MSENSE_ASSOCIATED_MOUNT) {
+ PRINT_ERR("Unknown medium state: %x\n", sense->masst);
+ return;
+ }
+ tape_med_state_set(device, MS_LOADED);
+ c_info->medium_status |= TAPE390_MEDIUM_LOADED_MASK;
+ if (sense->flags & MSENSE_CRYPT_MASK) {
+ PRINT_INFO("Medium is encrypted (%04x)\n", sense->flags);
+ c_info->medium_status |= TAPE390_MEDIUM_ENCRYPTED_MASK;
+ } else {
+ DBF_EVENT(6, "Medium is not encrypted %04x\n", sense->flags);
+ c_info->medium_status &= ~TAPE390_MEDIUM_ENCRYPTED_MASK;
+ }
+}
+
/*
* The done handler is called at device/channel end and wakes up the sleeping
* process
@@ -372,9 +740,10 @@ tape_3590_check_locate(struct tape_device *device, struct tape_request *request)
static int
tape_3590_done(struct tape_device *device, struct tape_request *request)
{
- struct tape_3590_med_sense *sense;
+ struct tape_3590_disc_data *disc_data;
DBF_EVENT(6, "%s done\n", tape_op_verbose[request->op]);
+ disc_data = device->discdata;
switch (request->op) {
case TO_BSB:
@@ -394,13 +763,20 @@ tape_3590_done(struct tape_device *device, struct tape_request *request)
break;
case TO_RUN:
tape_med_state_set(device, MS_UNLOADED);
+ tape_3590_schedule_work(device, TO_CRYPT_OFF);
break;
case TO_MSEN:
- sense = (struct tape_3590_med_sense *) request->cpdata;
- if (sense->masst == MSENSE_UNASSOCIATED)
- tape_med_state_set(device, MS_UNLOADED);
- if (sense->masst == MSENSE_ASSOCIATED_MOUNT)
- tape_med_state_set(device, MS_LOADED);
+ tape_3590_med_state_set(device, request->cpdata);
+ break;
+ case TO_CRYPT_ON:
+ TAPE_3590_CRYPT_INFO(device).status
+ |= TAPE390_CRYPT_ON_MASK;
+ *(device->modeset_byte) |= 0x03;
+ break;
+ case TO_CRYPT_OFF:
+ TAPE_3590_CRYPT_INFO(device).status
+ &= ~TAPE390_CRYPT_ON_MASK;
+ *(device->modeset_byte) &= ~0x03;
break;
case TO_RBI: /* RBI seems to succeed even without medium loaded. */
case TO_NOP: /* Same to NOP. */
@@ -409,8 +785,9 @@ tape_3590_done(struct tape_device *device, struct tape_request *request)
case TO_DIS:
case TO_ASSIGN:
case TO_UNASSIGN:
- break;
case TO_SIZE:
+ case TO_KEKL_SET:
+ case TO_KEKL_QUERY:
break;
}
return TAPE_IO_SUCCESS;
@@ -540,10 +917,8 @@ static int
tape_3590_erp_long_busy(struct tape_device *device,
struct tape_request *request, struct irb *irb)
{
- /* FIXME: how about WAITING for a minute ? */
- PRINT_WARN("(%s): Device is busy! Please wait a minute!\n",
- device->cdev->dev.bus_id);
- return tape_3590_erp_basic(device, request, irb, -EBUSY);
+ DBF_EVENT(6, "Device is busy\n");
+ return TAPE_IO_LONG_BUSY;
}
/*
@@ -951,6 +1326,34 @@ tape_3590_print_era_msg(struct tape_device *device, struct irb *irb)
device->cdev->dev.bus_id, sense->mc);
}
+static int tape_3590_crypt_error(struct tape_device *device,
+ struct tape_request *request, struct irb *irb)
+{
+ u8 cu_rc, ekm_rc1;
+ u16 ekm_rc2;
+ u32 drv_rc;
+ char *bus_id, *sense;
+
+ sense = ((struct tape_3590_sense *) irb->ecw)->fmt.data;
+ bus_id = device->cdev->dev.bus_id;
+ cu_rc = sense[0];
+ drv_rc = *((u32*) &sense[5]) & 0xffffff;
+ ekm_rc1 = sense[9];
+ ekm_rc2 = *((u16*) &sense[10]);
+ if ((cu_rc == 0) && (ekm_rc2 == 0xee31))
+ /* key not defined on EKM */
+ return tape_3590_erp_basic(device, request, irb, -EKEYREJECTED);
+ if ((cu_rc == 1) || (cu_rc == 2))
+ /* No connection to EKM */
+ return tape_3590_erp_basic(device, request, irb, -ENOTCONN);
+
+ PRINT_ERR("(%s): Unable to get encryption key from EKM\n", bus_id);
+ PRINT_ERR("(%s): CU=%02X DRIVE=%06X EKM=%02X:%04X\n", bus_id, cu_rc,
+ drv_rc, ekm_rc1, ekm_rc2);
+
+ return tape_3590_erp_basic(device, request, irb, -ENOKEY);
+}
+
/*
* 3590 error Recovery routine:
* If possible, it tries to recover from the error. If this is not possible,
@@ -979,6 +1382,8 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request,
sense = (struct tape_3590_sense *) irb->ecw;
+ DBF_EVENT(6, "Unit Check: RQC = %x\n", sense->rc_rqc);
+
/*
* First check all RC-QRCs where we want to do something special
* - "break": basic error recovery is done
@@ -999,6 +1404,8 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request,
case 0x2231:
tape_3590_print_era_msg(device, irb);
return tape_3590_erp_special_interrupt(device, request, irb);
+ case 0x2240:
+ return tape_3590_crypt_error(device, request, irb);
case 0x3010:
DBF_EVENT(2, "(%08x): Backward at Beginning of Partition\n",
@@ -1020,6 +1427,7 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request,
DBF_EVENT(2, "(%08x): Rewind Unload complete\n",
device->cdev_id);
tape_med_state_set(device, MS_UNLOADED);
+ tape_3590_schedule_work(device, TO_CRYPT_OFF);
return tape_3590_erp_basic(device, request, irb, 0);
case 0x4010:
@@ -1030,9 +1438,15 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request,
PRINT_WARN("(%s): Tape operation when medium not loaded\n",
device->cdev->dev.bus_id);
tape_med_state_set(device, MS_UNLOADED);
+ tape_3590_schedule_work(device, TO_CRYPT_OFF);
return tape_3590_erp_basic(device, request, irb, -ENOMEDIUM);
case 0x4012: /* Device Long Busy */
+ /* XXX: Also use long busy handling here? */
+ DBF_EVENT(6, "(%08x): LONG BUSY\n", device->cdev_id);
tape_3590_print_era_msg(device, irb);
+ return tape_3590_erp_basic(device, request, irb, -EBUSY);
+ case 0x4014:
+ DBF_EVENT(6, "(%08x): Crypto LONG BUSY\n", device->cdev_id);
return tape_3590_erp_long_busy(device, request, irb);
case 0x5010:
@@ -1064,6 +1478,7 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request,
case 0x5120:
case 0x1120:
tape_med_state_set(device, MS_UNLOADED);
+ tape_3590_schedule_work(device, TO_CRYPT_OFF);
return tape_3590_erp_basic(device, request, irb, -ENOMEDIUM);
case 0x6020:
@@ -1142,21 +1557,47 @@ tape_3590_setup_device(struct tape_device *device)
{
int rc;
struct tape_3590_disc_data *data;
+ char *rdc_data;
DBF_EVENT(6, "3590 device setup\n");
- data = kmalloc(sizeof(struct tape_3590_disc_data),
- GFP_KERNEL | GFP_DMA);
+ data = kzalloc(sizeof(struct tape_3590_disc_data), GFP_KERNEL | GFP_DMA);
if (data == NULL)
return -ENOMEM;
data->read_back_op = READ_PREVIOUS;
device->discdata = data;
- if ((rc = tape_std_assign(device)) == 0) {
- /* Try to find out if medium is loaded */
- if ((rc = tape_3590_sense_medium(device)) != 0)
- DBF_LH(3, "3590 medium sense returned %d\n", rc);
+ rdc_data = kmalloc(64, GFP_KERNEL | GFP_DMA);
+ if (!rdc_data) {
+ rc = -ENOMEM;
+ goto fail_kmalloc;
+ }
+ rc = read_dev_chars(device->cdev, (void**)&rdc_data, 64);
+ if (rc) {
+ DBF_LH(3, "Read device characteristics failed!\n");
+ goto fail_kmalloc;
+ }
+ rc = tape_std_assign(device);
+ if (rc)
+ goto fail_rdc_data;
+ if (rdc_data[31] == 0x13) {
+ PRINT_INFO("Device has crypto support\n");
+ data->crypt_info.capability |= TAPE390_CRYPT_SUPPORTED_MASK;
+ tape_3592_disable_crypt(device);
+ } else {
+ DBF_EVENT(6, "Device has NO crypto support\n");
}
+ /* Try to find out if medium is loaded */
+ rc = tape_3590_sense_medium(device);
+ if (rc) {
+ DBF_LH(3, "3590 medium sense returned %d\n", rc);
+ goto fail_rdc_data;
+ }
+ return 0;
+fail_rdc_data:
+ kfree(rdc_data);
+fail_kmalloc:
+ kfree(data);
return rc;
}
diff --git a/drivers/s390/char/tape_3590.h b/drivers/s390/char/tape_3590.h
index cf274b9445a..aa5138807af 100644
--- a/drivers/s390/char/tape_3590.h
+++ b/drivers/s390/char/tape_3590.h
@@ -2,7 +2,7 @@
* drivers/s390/char/tape_3590.h
* tape device discipline for 3590 tapes.
*
- * Copyright (C) IBM Corp. 2001,2006
+ * Copyright IBM Corp. 2001,2006
* Author(s): Stefan Bader <shbader@de.ibm.com>
* Michael Holzheu <holzheu@de.ibm.com>
* Martin Schwidefsky <schwidefsky@de.ibm.com>
@@ -38,16 +38,22 @@
#define MSENSE_UNASSOCIATED 0x00
#define MSENSE_ASSOCIATED_MOUNT 0x01
#define MSENSE_ASSOCIATED_UMOUNT 0x02
+#define MSENSE_CRYPT_MASK 0x00000010
#define TAPE_3590_MAX_MSG 0xb0
/* Datatypes */
struct tape_3590_disc_data {
- unsigned char modeset_byte;
+ struct tape390_crypt_info crypt_info;
int read_back_op;
};
+#define TAPE_3590_CRYPT_INFO(device) \
+ ((struct tape_3590_disc_data*)(device->discdata))->crypt_info
+#define TAPE_3590_READ_BACK_OP(device) \
+ ((struct tape_3590_disc_data*)(device->discdata))->read_back_op
+
struct tape_3590_sense {
unsigned int command_rej:1;
@@ -118,7 +124,48 @@ struct tape_3590_sense {
struct tape_3590_med_sense {
unsigned int macst:4;
unsigned int masst:4;
- char pad[127];
+ char pad1[7];
+ unsigned int flags;
+ char pad2[116];
+} __attribute__ ((packed));
+
+/* Datastructures for 3592 encryption support */
+
+struct tape3592_kekl {
+ __u8 flags;
+ char label[64];
+} __attribute__ ((packed));
+
+struct tape3592_kekl_pair {
+ __u8 count;
+ struct tape3592_kekl kekl[2];
+} __attribute__ ((packed));
+
+struct tape3592_kekl_query_data {
+ __u16 len;
+ __u8 fmt;
+ __u8 mc;
+ __u32 id;
+ __u8 flags;
+ struct tape3592_kekl_pair kekls;
+ char reserved[116];
+} __attribute__ ((packed));
+
+struct tape3592_kekl_query_order {
+ __u8 code;
+ __u8 flags;
+ char reserved1[2];
+ __u8 max_count;
+ char reserved2[35];
+} __attribute__ ((packed));
+
+struct tape3592_kekl_set_order {
+ __u8 code;
+ __u8 flags;
+ char reserved1[2];
+ __u8 op;
+ struct tape3592_kekl_pair kekls;
+ char reserved2[120];
} __attribute__ ((packed));
#endif /* _TAPE_3590_H */
diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c
index c8a89b3b87d..dd0ecaed592 100644
--- a/drivers/s390/char/tape_block.c
+++ b/drivers/s390/char/tape_block.c
@@ -73,7 +73,7 @@ tapeblock_trigger_requeue(struct tape_device *device)
/*
* Post finished request.
*/
-static inline void
+static void
tapeblock_end_request(struct request *req, int uptodate)
{
if (end_that_request_first(req, uptodate, req->hard_nr_sectors))
@@ -108,7 +108,7 @@ __tapeblock_end_request(struct tape_request *ccw_req, void *data)
/*
* Feed the tape device CCW queue with requests supplied in a list.
*/
-static inline int
+static int
tapeblock_start_request(struct tape_device *device, struct request *req)
{
struct tape_request * ccw_req;
diff --git a/drivers/s390/char/tape_char.c b/drivers/s390/char/tape_char.c
index 31198c8f271..b830a8cbef7 100644
--- a/drivers/s390/char/tape_char.c
+++ b/drivers/s390/char/tape_char.c
@@ -3,7 +3,7 @@
* character device frontend for tape device driver
*
* S390 and zSeries version
- * Copyright (C) 2001,2002 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Copyright IBM Corp. 2001,2006
* Author(s): Carsten Otte <cotte@de.ibm.com>
* Michael Holzheu <holzheu@de.ibm.com>
* Tuan Ngo-Anh <ngoanh@de.ibm.com>
@@ -39,7 +39,7 @@ static int tapechar_ioctl(struct inode *, struct file *, unsigned int,
static long tapechar_compat_ioctl(struct file *, unsigned int,
unsigned long);
-static struct file_operations tape_fops =
+static const struct file_operations tape_fops =
{
.owner = THIS_MODULE,
.read = tapechar_read,
@@ -89,22 +89,7 @@ tapechar_cleanup_device(struct tape_device *device)
device->nt = NULL;
}
-/*
- * Terminate write command (we write two TMs and skip backward over last)
- * This ensures that the tape is always correctly terminated.
- * When the user writes afterwards a new file, he will overwrite the
- * second TM and therefore one TM will remain to separate the
- * two files on the tape...
- */
-static inline void
-tapechar_terminate_write(struct tape_device *device)
-{
- if (tape_mtop(device, MTWEOF, 1) == 0 &&
- tape_mtop(device, MTWEOF, 1) == 0)
- tape_mtop(device, MTBSR, 1);
-}
-
-static inline int
+static int
tapechar_check_idalbuffer(struct tape_device *device, size_t block_size)
{
struct idal_buffer *new;
@@ -137,7 +122,7 @@ tapechar_check_idalbuffer(struct tape_device *device, size_t block_size)
/*
* Tape device read function
*/
-ssize_t
+static ssize_t
tapechar_read(struct file *filp, char __user *data, size_t count, loff_t *ppos)
{
struct tape_device *device;
@@ -201,7 +186,7 @@ tapechar_read(struct file *filp, char __user *data, size_t count, loff_t *ppos)
/*
* Tape device write function
*/
-ssize_t
+static ssize_t
tapechar_write(struct file *filp, const char __user *data, size_t count, loff_t *ppos)
{
struct tape_device *device;
@@ -291,7 +276,7 @@ tapechar_write(struct file *filp, const char __user *data, size_t count, loff_t
/*
* Character frontend tape device open function.
*/
-int
+static int
tapechar_open (struct inode *inode, struct file *filp)
{
struct tape_device *device;
@@ -326,7 +311,7 @@ tapechar_open (struct inode *inode, struct file *filp)
* Character frontend tape device release function.
*/
-int
+static int
tapechar_release(struct inode *inode, struct file *filp)
{
struct tape_device *device;
diff --git a/drivers/s390/char/tape_class.c b/drivers/s390/char/tape_class.c
index 56b87618b10..2e0d29730b6 100644
--- a/drivers/s390/char/tape_class.c
+++ b/drivers/s390/char/tape_class.c
@@ -36,7 +36,7 @@ static struct class *tape_class;
struct tape_class_device *register_tape_dev(
struct device * device,
dev_t dev,
- struct file_operations *fops,
+ const struct file_operations *fops,
char * device_name,
char * mode_name)
{
diff --git a/drivers/s390/char/tape_class.h b/drivers/s390/char/tape_class.h
index 3d0ca054cde..a8bd9b47fad 100644
--- a/drivers/s390/char/tape_class.h
+++ b/drivers/s390/char/tape_class.h
@@ -52,7 +52,7 @@ struct tape_class_device {
struct tape_class_device *register_tape_dev(
struct device * device,
dev_t dev,
- struct file_operations *fops,
+ const struct file_operations *fops,
char * device_name,
char * node_name
);
diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c
index c6c2e918b99..e2a8a1a04ba 100644
--- a/drivers/s390/char/tape_core.c
+++ b/drivers/s390/char/tape_core.c
@@ -3,7 +3,7 @@
* basic function of the tape device driver
*
* S390 and zSeries version
- * Copyright (C) 2001,2005 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Copyright IBM Corp. 2001,2006
* Author(s): Carsten Otte <cotte@de.ibm.com>
* Michael Holzheu <holzheu@de.ibm.com>
* Tuan Ngo-Anh <ngoanh@de.ibm.com>
@@ -26,9 +26,11 @@
#include "tape_std.h"
#define PRINTK_HEADER "TAPE_CORE: "
+#define LONG_BUSY_TIMEOUT 180 /* seconds */
static void __tape_do_irq (struct ccw_device *, unsigned long, struct irb *);
static void tape_delayed_next_request(struct work_struct *);
+static void tape_long_busy_timeout(unsigned long data);
/*
* One list to contain all tape devices of all disciplines, so
@@ -69,10 +71,12 @@ const char *tape_op_verbose[TO_SIZE] =
[TO_LOAD] = "LOA", [TO_READ_CONFIG] = "RCF",
[TO_READ_ATTMSG] = "RAT",
[TO_DIS] = "DIS", [TO_ASSIGN] = "ASS",
- [TO_UNASSIGN] = "UAS"
+ [TO_UNASSIGN] = "UAS", [TO_CRYPT_ON] = "CON",
+ [TO_CRYPT_OFF] = "COF", [TO_KEKL_SET] = "KLS",
+ [TO_KEKL_QUERY] = "KLQ",
};
-static inline int
+static int
busid_to_int(char *bus_id)
{
int dec;
@@ -252,7 +256,7 @@ tape_med_state_set(struct tape_device *device, enum tape_medium_state newstate)
/*
* Stop running ccw. Has to be called with the device lock held.
*/
-static inline int
+static int
__tape_cancel_io(struct tape_device *device, struct tape_request *request)
{
int retries;
@@ -346,6 +350,9 @@ tape_generic_online(struct tape_device *device,
return -EINVAL;
}
+ init_timer(&device->lb_timeout);
+ device->lb_timeout.function = tape_long_busy_timeout;
+
/* Let the discipline have a go at the device. */
device->discipline = discipline;
if (!try_module_get(discipline->owner)) {
@@ -385,7 +392,7 @@ out:
return rc;
}
-static inline void
+static void
tape_cleanup_device(struct tape_device *device)
{
tapeblock_cleanup_device(device);
@@ -563,7 +570,7 @@ tape_generic_probe(struct ccw_device *cdev)
return ret;
}
-static inline void
+static void
__tape_discard_requests(struct tape_device *device)
{
struct tape_request * request;
@@ -703,7 +710,7 @@ tape_free_request (struct tape_request * request)
kfree(request);
}
-static inline int
+static int
__tape_start_io(struct tape_device *device, struct tape_request *request)
{
int rc;
@@ -733,7 +740,7 @@ __tape_start_io(struct tape_device *device, struct tape_request *request)
return rc;
}
-static inline void
+static void
__tape_start_next_request(struct tape_device *device)
{
struct list_head *l, *n;
@@ -801,7 +808,23 @@ tape_delayed_next_request(struct work_struct *work)
spin_unlock_irq(get_ccwdev_lock(device->cdev));
}
-static inline void
+static void tape_long_busy_timeout(unsigned long data)
+{
+ struct tape_request *request;
+ struct tape_device *device;
+
+ device = (struct tape_device *) data;
+ spin_lock_irq(get_ccwdev_lock(device->cdev));
+ request = list_entry(device->req_queue.next, struct tape_request, list);
+ if (request->status != TAPE_REQUEST_LONG_BUSY)
+ BUG();
+ DBF_LH(6, "%08x: Long busy timeout.\n", device->cdev_id);
+ __tape_start_next_request(device);
+ device->lb_timeout.data = (unsigned long) tape_put_device(device);
+ spin_unlock_irq(get_ccwdev_lock(device->cdev));
+}
+
+static void
__tape_end_request(
struct tape_device * device,
struct tape_request * request,
@@ -878,7 +901,7 @@ tape_dump_sense_dbf(struct tape_device *device, struct tape_request *request,
* and starts it if the tape is idle. Has to be called with
* the device lock held.
*/
-static inline int
+static int
__tape_start_request(struct tape_device *device, struct tape_request *request)
{
int rc;
@@ -1094,7 +1117,22 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
/* May be an unsolicited irq */
if(request != NULL)
request->rescnt = irb->scsw.count;
-
+ else if ((irb->scsw.dstat == 0x85 || irb->scsw.dstat == 0x80) &&
+ !list_empty(&device->req_queue)) {
+ /* Not Ready to Ready after long busy ? */
+ struct tape_request *req;
+ req = list_entry(device->req_queue.next,
+ struct tape_request, list);
+ if (req->status == TAPE_REQUEST_LONG_BUSY) {
+ DBF_EVENT(3, "(%08x): del timer\n", device->cdev_id);
+ if (del_timer(&device->lb_timeout)) {
+ device->lb_timeout.data = (unsigned long)
+ tape_put_device(device);
+ __tape_start_next_request(device);
+ }
+ return;
+ }
+ }
if (irb->scsw.dstat != 0x0c) {
/* Set the 'ONLINE' flag depending on sense byte 1 */
if(*(((__u8 *) irb->ecw) + 1) & SENSE_DRIVE_ONLINE)
@@ -1142,6 +1180,15 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
break;
case TAPE_IO_PENDING:
break;
+ case TAPE_IO_LONG_BUSY:
+ device->lb_timeout.data =
+ (unsigned long)tape_get_device_reference(device);
+ device->lb_timeout.expires = jiffies +
+ LONG_BUSY_TIMEOUT * HZ;
+ DBF_EVENT(3, "(%08x): add timer\n", device->cdev_id);
+ add_timer(&device->lb_timeout);
+ request->status = TAPE_REQUEST_LONG_BUSY;
+ break;
case TAPE_IO_RETRY:
rc = __tape_start_io(device, request);
if (rc)
diff --git a/drivers/s390/char/tape_proc.c b/drivers/s390/char/tape_proc.c
index 655d375ab22..cea49f001f8 100644
--- a/drivers/s390/char/tape_proc.c
+++ b/drivers/s390/char/tape_proc.c
@@ -109,7 +109,7 @@ static int tape_proc_open(struct inode *inode, struct file *file)
return seq_open(file, &tape_proc_seq);
}
-static struct file_operations tape_proc_ops =
+static const struct file_operations tape_proc_ops =
{
.open = tape_proc_open,
.read = seq_read,
diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c
index 09844621edc..bc33068b9ce 100644
--- a/drivers/s390/char/tty3270.c
+++ b/drivers/s390/char/tty3270.c
@@ -36,7 +36,7 @@
struct tty_driver *tty3270_driver;
static int tty3270_max_index;
-struct raw3270_fn tty3270_fn;
+static struct raw3270_fn tty3270_fn;
struct tty3270_cell {
unsigned char character;
@@ -119,8 +119,7 @@ static void tty3270_update(struct tty3270 *);
/*
* Setup timeout for a device. On timeout trigger an update.
*/
-void
-tty3270_set_timer(struct tty3270 *tp, int expires)
+static void tty3270_set_timer(struct tty3270 *tp, int expires)
{
if (expires == 0) {
if (timer_pending(&tp->timer) && del_timer(&tp->timer))
@@ -841,7 +840,7 @@ tty3270_del_views(void)
}
}
-struct raw3270_fn tty3270_fn = {
+static struct raw3270_fn tty3270_fn = {
.activate = tty3270_activate,
.deactivate = tty3270_deactivate,
.intv = (void *) tty3270_irq,
@@ -1754,8 +1753,7 @@ static const struct tty_operations tty3270_ops = {
.set_termios = tty3270_set_termios
};
-void
-tty3270_notifier(int index, int active)
+static void tty3270_notifier(int index, int active)
{
if (active)
tty_register_device(tty3270_driver, index, NULL);
@@ -1767,8 +1765,7 @@ tty3270_notifier(int index, int active)
* 3270 tty registration code called from tty_init().
* Most kernel services (incl. kmalloc) are available at this poimt.
*/
-int __init
-tty3270_init(void)
+static int __init tty3270_init(void)
{
struct tty_driver *driver;
int ret;
diff --git a/drivers/s390/char/vmcp.c b/drivers/s390/char/vmcp.c
index a420cd09904..fce3dac5cb3 100644
--- a/drivers/s390/char/vmcp.c
+++ b/drivers/s390/char/vmcp.c
@@ -173,7 +173,7 @@ static long vmcp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
}
}
-static struct file_operations vmcp_fops = {
+static const struct file_operations vmcp_fops = {
.owner = THIS_MODULE,
.open = &vmcp_open,
.release = &vmcp_release,
diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c
index 6cb23040954..b87d3b01993 100644
--- a/drivers/s390/char/vmlogrdr.c
+++ b/drivers/s390/char/vmlogrdr.c
@@ -3,7 +3,7 @@
* character device driver for reading z/VM system service records
*
*
- * Copyright (C) 2004 IBM Corporation
+ * Copyright 2004 IBM Corporation
* character device driver for reading z/VM system service records,
* Version 1.0
* Author(s): Xenia Tkatschow <xenia@us.ibm.com>
@@ -21,7 +21,7 @@
#include <asm/cpcmd.h>
#include <asm/debug.h>
#include <asm/ebcdic.h>
-#include "../net/iucv.h"
+#include <net/iucv/iucv.h>
#include <linux/kmod.h>
#include <linux/cdev.h>
#include <linux/device.h>
@@ -60,12 +60,11 @@ struct vmlogrdr_priv_t {
char system_service[8];
char internal_name[8];
char recording_name[8];
- u16 pathid;
+ struct iucv_path *path;
int connection_established;
int iucv_path_severed;
- iucv_MessagePending local_interrupt_buffer;
+ struct iucv_message local_interrupt_buffer;
atomic_t receive_ready;
- iucv_handle_t iucv_handle;
int minor_num;
char * buffer;
char * current_position;
@@ -89,7 +88,7 @@ static int vmlogrdr_release(struct inode *, struct file *);
static ssize_t vmlogrdr_read (struct file *filp, char __user *data,
size_t count, loff_t * ppos);
-static struct file_operations vmlogrdr_fops = {
+static const struct file_operations vmlogrdr_fops = {
.owner = THIS_MODULE,
.open = vmlogrdr_open,
.release = vmlogrdr_release,
@@ -97,40 +96,21 @@ static struct file_operations vmlogrdr_fops = {
};
-static u8 iucvMagic[16] = {
- 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
- 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40
-};
+static void vmlogrdr_iucv_path_complete(struct iucv_path *, u8 ipuser[16]);
+static void vmlogrdr_iucv_path_severed(struct iucv_path *, u8 ipuser[16]);
+static void vmlogrdr_iucv_message_pending(struct iucv_path *,
+ struct iucv_message *);
-static u8 mask[] = {
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+static struct iucv_handler vmlogrdr_iucv_handler = {
+ .path_complete = vmlogrdr_iucv_path_complete,
+ .path_severed = vmlogrdr_iucv_path_severed,
+ .message_pending = vmlogrdr_iucv_message_pending,
};
-static u8 iucv_host[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
-
-
-static void
-vmlogrdr_iucv_ConnectionComplete(iucv_ConnectionComplete *eib, void *pgm_data);
-static void
-vmlogrdr_iucv_ConnectionSevered(iucv_ConnectionSevered *eib, void *pgm_data);
-static void
-vmlogrdr_iucv_MessagePending(iucv_MessagePending *eib, void *pgm_data);
-
-
-static iucv_interrupt_ops_t vmlogrdr_iucvops = {
- .ConnectionComplete = vmlogrdr_iucv_ConnectionComplete,
- .ConnectionSevered = vmlogrdr_iucv_ConnectionSevered,
- .MessagePending = vmlogrdr_iucv_MessagePending,
-};
-
-
-DECLARE_WAIT_QUEUE_HEAD(conn_wait_queue);
-DECLARE_WAIT_QUEUE_HEAD(read_wait_queue);
+static DECLARE_WAIT_QUEUE_HEAD(conn_wait_queue);
+static DECLARE_WAIT_QUEUE_HEAD(read_wait_queue);
/*
* pointer to system service private structure
@@ -177,28 +157,29 @@ static struct cdev *vmlogrdr_cdev = NULL;
static int recording_class_AB;
-static void
-vmlogrdr_iucv_ConnectionComplete (iucv_ConnectionComplete * eib,
- void * pgm_data)
+static void vmlogrdr_iucv_path_complete(struct iucv_path *path, u8 ipuser[16])
{
- struct vmlogrdr_priv_t * logptr = pgm_data;
+ struct vmlogrdr_priv_t * logptr = path->private;
+
spin_lock(&logptr->priv_lock);
logptr->connection_established = 1;
spin_unlock(&logptr->priv_lock);
wake_up(&conn_wait_queue);
- return;
}
-static void
-vmlogrdr_iucv_ConnectionSevered (iucv_ConnectionSevered * eib, void * pgm_data)
+static void vmlogrdr_iucv_path_severed(struct iucv_path *path, u8 ipuser[16])
{
- u8 reason = (u8) eib->ipuser[8];
- struct vmlogrdr_priv_t * logptr = pgm_data;
+ struct vmlogrdr_priv_t * logptr = path->private;
+ u8 reason = (u8) ipuser[8];
printk (KERN_ERR "vmlogrdr: connection severed with"
" reason %i\n", reason);
+ iucv_path_sever(path, NULL);
+ kfree(path);
+ logptr->path = NULL;
+
spin_lock(&logptr->priv_lock);
logptr->connection_established = 0;
logptr->iucv_path_severed = 1;
@@ -210,10 +191,10 @@ vmlogrdr_iucv_ConnectionSevered (iucv_ConnectionSevered * eib, void * pgm_data)
}
-static void
-vmlogrdr_iucv_MessagePending (iucv_MessagePending * eib, void * pgm_data)
+static void vmlogrdr_iucv_message_pending(struct iucv_path *path,
+ struct iucv_message *msg)
{
- struct vmlogrdr_priv_t * logptr = pgm_data;
+ struct vmlogrdr_priv_t * logptr = path->private;
/*
* This function is the bottom half so it should be quick.
@@ -221,15 +202,15 @@ vmlogrdr_iucv_MessagePending (iucv_MessagePending * eib, void * pgm_data)
* the usage count
*/
spin_lock(&logptr->priv_lock);
- memcpy(&(logptr->local_interrupt_buffer), eib, sizeof(*eib));
+ memcpy(&logptr->local_interrupt_buffer, msg, sizeof(*msg));
atomic_inc(&logptr->receive_ready);
spin_unlock(&logptr->priv_lock);
wake_up_interruptible(&read_wait_queue);
}
-static int
-vmlogrdr_get_recording_class_AB(void) {
+static int vmlogrdr_get_recording_class_AB(void)
+{
char cp_command[]="QUERY COMMAND RECORDING ";
char cp_response[80];
char *tail;
@@ -259,8 +240,9 @@ vmlogrdr_get_recording_class_AB(void) {
}
-static int
-vmlogrdr_recording(struct vmlogrdr_priv_t * logptr, int action, int purge) {
+static int vmlogrdr_recording(struct vmlogrdr_priv_t * logptr,
+ int action, int purge)
+{
char cp_command[80];
char cp_response[160];
@@ -318,8 +300,7 @@ vmlogrdr_recording(struct vmlogrdr_priv_t * logptr, int action, int purge) {
}
-static int
-vmlogrdr_open (struct inode *inode, struct file *filp)
+static int vmlogrdr_open (struct inode *inode, struct file *filp)
{
int dev_num = 0;
struct vmlogrdr_priv_t * logptr = NULL;
@@ -329,10 +310,7 @@ vmlogrdr_open (struct inode *inode, struct file *filp)
dev_num = iminor(inode);
if (dev_num > MAXMINOR)
return -ENODEV;
-
logptr = &sys_ser[dev_num];
- if (logptr == NULL)
- return -ENODEV;
/*
* only allow for blocking reads to be open
@@ -345,52 +323,38 @@ vmlogrdr_open (struct inode *inode, struct file *filp)
if (logptr->dev_in_use) {
spin_unlock_bh(&logptr->priv_lock);
return -EBUSY;
- } else {
- logptr->dev_in_use = 1;
- spin_unlock_bh(&logptr->priv_lock);
}
-
+ logptr->dev_in_use = 1;
+ logptr->connection_established = 0;
+ logptr->iucv_path_severed = 0;
atomic_set(&logptr->receive_ready, 0);
logptr->buffer_free = 1;
+ spin_unlock_bh(&logptr->priv_lock);
/* set the file options */
filp->private_data = logptr;
filp->f_op = &vmlogrdr_fops;
/* start recording for this service*/
- ret=0;
- if (logptr->autorecording)
+ if (logptr->autorecording) {
ret = vmlogrdr_recording(logptr,1,logptr->autopurge);
- if (ret)
- printk (KERN_WARNING "vmlogrdr: failed to start "
- "recording automatically\n");
-
- /* Register with iucv driver */
- logptr->iucv_handle = iucv_register_program(iucvMagic,
- logptr->system_service, mask, &vmlogrdr_iucvops,
- logptr);
-
- if (logptr->iucv_handle == NULL) {
- printk (KERN_ERR "vmlogrdr: failed to register with"
- "iucv driver\n");
- goto not_registered;
+ if (ret)
+ printk (KERN_WARNING "vmlogrdr: failed to start "
+ "recording automatically\n");
}
/* create connection to the system service */
- spin_lock_bh(&logptr->priv_lock);
- logptr->connection_established = 0;
- logptr->iucv_path_severed = 0;
- spin_unlock_bh(&logptr->priv_lock);
-
- connect_rc = iucv_connect (&(logptr->pathid), 10, iucvMagic,
- logptr->system_service, iucv_host, 0,
- NULL, NULL,
- logptr->iucv_handle, NULL);
+ logptr->path = iucv_path_alloc(10, 0, GFP_KERNEL);
+ if (!logptr->path)
+ goto out_dev;
+ connect_rc = iucv_path_connect(logptr->path, &vmlogrdr_iucv_handler,
+ logptr->system_service, NULL, NULL,
+ logptr);
if (connect_rc) {
printk (KERN_ERR "vmlogrdr: iucv connection to %s "
"failed with rc %i \n", logptr->system_service,
connect_rc);
- goto not_connected;
+ goto out_path;
}
/* We've issued the connect and now we must wait for a
@@ -399,35 +363,28 @@ vmlogrdr_open (struct inode *inode, struct file *filp)
*/
wait_event(conn_wait_queue, (logptr->connection_established)
|| (logptr->iucv_path_severed));
- if (logptr->iucv_path_severed) {
- goto not_connected;
- }
-
+ if (logptr->iucv_path_severed)
+ goto out_record;
return nonseekable_open(inode, filp);
-not_connected:
- iucv_unregister_program(logptr->iucv_handle);
- logptr->iucv_handle = NULL;
-not_registered:
+out_record:
if (logptr->autorecording)
vmlogrdr_recording(logptr,0,logptr->autopurge);
+out_path:
+ kfree(logptr->path); /* kfree(NULL) is ok. */
+ logptr->path = NULL;
+out_dev:
logptr->dev_in_use = 0;
return -EIO;
-
-
}
-static int
-vmlogrdr_release (struct inode *inode, struct file *filp)
+static int vmlogrdr_release (struct inode *inode, struct file *filp)
{
int ret;
struct vmlogrdr_priv_t * logptr = filp->private_data;
- iucv_unregister_program(logptr->iucv_handle);
- logptr->iucv_handle = NULL;
-
if (logptr->autorecording) {
ret = vmlogrdr_recording(logptr,0,logptr->autopurge);
if (ret)
@@ -440,8 +397,8 @@ vmlogrdr_release (struct inode *inode, struct file *filp)
}
-static int
-vmlogrdr_receive_data(struct vmlogrdr_priv_t *priv) {
+static int vmlogrdr_receive_data(struct vmlogrdr_priv_t *priv)
+{
int rc, *temp;
/* we need to keep track of two data sizes here:
* The number of bytes we need to receive from iucv and
@@ -462,8 +419,7 @@ vmlogrdr_receive_data(struct vmlogrdr_priv_t *priv) {
* We need to return the total length of the record
* + size of FENCE in the first 4 bytes of the buffer.
*/
- iucv_data_count =
- priv->local_interrupt_buffer.ln1msg2.ipbfln1f;
+ iucv_data_count = priv->local_interrupt_buffer.length;
user_data_count = sizeof(int);
temp = (int*)priv->buffer;
*temp= iucv_data_count + sizeof(FENCE);
@@ -475,14 +431,10 @@ vmlogrdr_receive_data(struct vmlogrdr_priv_t *priv) {
*/
if (iucv_data_count > NET_BUFFER_SIZE)
iucv_data_count = NET_BUFFER_SIZE;
- rc = iucv_receive(priv->pathid,
- priv->local_interrupt_buffer.ipmsgid,
- priv->local_interrupt_buffer.iptrgcls,
- buffer,
- iucv_data_count,
- NULL,
- NULL,
- &priv->residual_length);
+ rc = iucv_message_receive(priv->path,
+ &priv->local_interrupt_buffer,
+ 0, buffer, iucv_data_count,
+ &priv->residual_length);
spin_unlock_bh(&priv->priv_lock);
/* An rc of 5 indicates that the record was bigger then
* the buffer, which is OK for us. A 9 indicates that the
@@ -514,8 +466,8 @@ vmlogrdr_receive_data(struct vmlogrdr_priv_t *priv) {
}
-static ssize_t
-vmlogrdr_read(struct file *filp, char __user *data, size_t count, loff_t * ppos)
+static ssize_t vmlogrdr_read(struct file *filp, char __user *data,
+ size_t count, loff_t * ppos)
{
int rc;
struct vmlogrdr_priv_t * priv = filp->private_data;
@@ -547,8 +499,10 @@ vmlogrdr_read(struct file *filp, char __user *data, size_t count, loff_t * ppos)
return count;
}
-static ssize_t
-vmlogrdr_autopurge_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t count) {
+static ssize_t vmlogrdr_autopurge_store(struct device * dev,
+ struct device_attribute *attr,
+ const char * buf, size_t count)
+{
struct vmlogrdr_priv_t *priv = dev->driver_data;
ssize_t ret = count;
@@ -566,8 +520,10 @@ vmlogrdr_autopurge_store(struct device * dev, struct device_attribute *attr, con
}
-static ssize_t
-vmlogrdr_autopurge_show(struct device *dev, struct device_attribute *attr, char *buf) {
+static ssize_t vmlogrdr_autopurge_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
struct vmlogrdr_priv_t *priv = dev->driver_data;
return sprintf(buf, "%u\n", priv->autopurge);
}
@@ -577,8 +533,10 @@ static DEVICE_ATTR(autopurge, 0644, vmlogrdr_autopurge_show,
vmlogrdr_autopurge_store);
-static ssize_t
-vmlogrdr_purge_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t count) {
+static ssize_t vmlogrdr_purge_store(struct device * dev,
+ struct device_attribute *attr,
+ const char * buf, size_t count)
+{
char cp_command[80];
char cp_response[80];
@@ -618,9 +576,10 @@ vmlogrdr_purge_store(struct device * dev, struct device_attribute *attr, const c
static DEVICE_ATTR(purge, 0200, NULL, vmlogrdr_purge_store);
-static ssize_t
-vmlogrdr_autorecording_store(struct device *dev, struct device_attribute *attr, const char *buf,
- size_t count) {
+static ssize_t vmlogrdr_autorecording_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
struct vmlogrdr_priv_t *priv = dev->driver_data;
ssize_t ret = count;
@@ -638,8 +597,10 @@ vmlogrdr_autorecording_store(struct device *dev, struct device_attribute *attr,
}
-static ssize_t
-vmlogrdr_autorecording_show(struct device *dev, struct device_attribute *attr, char *buf) {
+static ssize_t vmlogrdr_autorecording_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
struct vmlogrdr_priv_t *priv = dev->driver_data;
return sprintf(buf, "%u\n", priv->autorecording);
}
@@ -649,9 +610,10 @@ static DEVICE_ATTR(autorecording, 0644, vmlogrdr_autorecording_show,
vmlogrdr_autorecording_store);
-static ssize_t
-vmlogrdr_recording_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t count) {
-
+static ssize_t vmlogrdr_recording_store(struct device * dev,
+ struct device_attribute *attr,
+ const char * buf, size_t count)
+{
struct vmlogrdr_priv_t *priv = dev->driver_data;
ssize_t ret;
@@ -676,8 +638,9 @@ vmlogrdr_recording_store(struct device * dev, struct device_attribute *attr, con
static DEVICE_ATTR(recording, 0200, NULL, vmlogrdr_recording_store);
-static ssize_t
-vmlogrdr_recording_status_show(struct device_driver *driver, char *buf) {
+static ssize_t vmlogrdr_recording_status_show(struct device_driver *driver,
+ char *buf)
+{
char cp_command[] = "QUERY RECORDING ";
int len;
@@ -710,52 +673,63 @@ static struct device_driver vmlogrdr_driver = {
};
-static int
-vmlogrdr_register_driver(void) {
+static int vmlogrdr_register_driver(void)
+{
int ret;
+ /* Register with iucv driver */
+ ret = iucv_register(&vmlogrdr_iucv_handler, 1);
+ if (ret) {
+ printk (KERN_ERR "vmlogrdr: failed to register with"
+ "iucv driver\n");
+ goto out;
+ }
+
ret = driver_register(&vmlogrdr_driver);
if (ret) {
printk(KERN_ERR "vmlogrdr: failed to register driver.\n");
- return ret;
+ goto out_iucv;
}
ret = driver_create_file(&vmlogrdr_driver,
&driver_attr_recording_status);
if (ret) {
printk(KERN_ERR "vmlogrdr: failed to add driver attribute.\n");
- goto unregdriver;
+ goto out_driver;
}
vmlogrdr_class = class_create(THIS_MODULE, "vmlogrdr");
if (IS_ERR(vmlogrdr_class)) {
printk(KERN_ERR "vmlogrdr: failed to create class.\n");
- ret=PTR_ERR(vmlogrdr_class);
- vmlogrdr_class=NULL;
- goto unregattr;
+ ret = PTR_ERR(vmlogrdr_class);
+ vmlogrdr_class = NULL;
+ goto out_attr;
}
return 0;
-unregattr:
+out_attr:
driver_remove_file(&vmlogrdr_driver, &driver_attr_recording_status);
-unregdriver:
+out_driver:
driver_unregister(&vmlogrdr_driver);
+out_iucv:
+ iucv_unregister(&vmlogrdr_iucv_handler, 1);
+out:
return ret;
}
-static void
-vmlogrdr_unregister_driver(void) {
+static void vmlogrdr_unregister_driver(void)
+{
class_destroy(vmlogrdr_class);
vmlogrdr_class = NULL;
driver_remove_file(&vmlogrdr_driver, &driver_attr_recording_status);
driver_unregister(&vmlogrdr_driver);
- return;
+ iucv_unregister(&vmlogrdr_iucv_handler, 1);
}
-static int
-vmlogrdr_register_device(struct vmlogrdr_priv_t *priv) {
+static int vmlogrdr_register_device(struct vmlogrdr_priv_t *priv)
+{
struct device *dev;
int ret;
@@ -804,9 +778,10 @@ vmlogrdr_register_device(struct vmlogrdr_priv_t *priv) {
}
-static int
-vmlogrdr_unregister_device(struct vmlogrdr_priv_t *priv ) {
- class_device_destroy(vmlogrdr_class, MKDEV(vmlogrdr_major, priv->minor_num));
+static int vmlogrdr_unregister_device(struct vmlogrdr_priv_t *priv)
+{
+ class_device_destroy(vmlogrdr_class,
+ MKDEV(vmlogrdr_major, priv->minor_num));
if (priv->device != NULL) {
sysfs_remove_group(&priv->device->kobj, &vmlogrdr_attr_group);
device_unregister(priv->device);
@@ -816,8 +791,8 @@ vmlogrdr_unregister_device(struct vmlogrdr_priv_t *priv ) {
}
-static int
-vmlogrdr_register_cdev(dev_t dev) {
+static int vmlogrdr_register_cdev(dev_t dev)
+{
int rc = 0;
vmlogrdr_cdev = cdev_alloc();
if (!vmlogrdr_cdev) {
@@ -837,9 +812,10 @@ vmlogrdr_register_cdev(dev_t dev) {
}
-static void
-vmlogrdr_cleanup(void) {
+static void vmlogrdr_cleanup(void)
+{
int i;
+
if (vmlogrdr_cdev) {
cdev_del(vmlogrdr_cdev);
vmlogrdr_cdev=NULL;
@@ -856,8 +832,7 @@ vmlogrdr_cleanup(void) {
}
-static int
-vmlogrdr_init(void)
+static int vmlogrdr_init(void)
{
int rc;
int i;
@@ -907,8 +882,7 @@ cleanup:
}
-static void
-vmlogrdr_exit(void)
+static void vmlogrdr_exit(void)
{
vmlogrdr_cleanup();
printk (KERN_INFO "vmlogrdr: driver unloaded\n");
diff --git a/drivers/s390/char/vmwatchdog.c b/drivers/s390/char/vmwatchdog.c
index 4b868f72fe8..680b9b58b80 100644
--- a/drivers/s390/char/vmwatchdog.c
+++ b/drivers/s390/char/vmwatchdog.c
@@ -228,7 +228,7 @@ static ssize_t vmwdt_write(struct file *f, const char __user *buf,
return count;
}
-static struct file_operations vmwdt_fops = {
+static const struct file_operations vmwdt_fops = {
.open = &vmwdt_open,
.release = &vmwdt_close,
.ioctl = &vmwdt_ioctl,
diff --git a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c
index 12c2d6b746e..ec0404874fa 100644
--- a/drivers/s390/cio/blacklist.c
+++ b/drivers/s390/cio/blacklist.c
@@ -43,7 +43,7 @@ typedef enum {add, free} range_action;
* Function: blacklist_range
* (Un-)blacklist the devices from-to
*/
-static inline void
+static void
blacklist_range (range_action action, unsigned int from, unsigned int to,
unsigned int ssid)
{
@@ -69,7 +69,7 @@ blacklist_range (range_action action, unsigned int from, unsigned int to,
* Get devno/busid from given string.
* Shamelessly grabbed from dasd_devmap.c.
*/
-static inline int
+static int
blacklist_busid(char **str, int *id0, int *ssid, int *devno)
{
int val, old_style;
@@ -123,10 +123,10 @@ confused:
return 1;
}
-static inline int
+static int
blacklist_parse_parameters (char *str, range_action action)
{
- unsigned int from, to, from_id0, to_id0, from_ssid, to_ssid;
+ int from, to, from_id0, to_id0, from_ssid, to_ssid;
while (*str != 0 && *str != '\n') {
range_action ra = action;
@@ -227,7 +227,7 @@ is_blacklisted (int ssid, int devno)
* Function: blacklist_parse_proc_parameters
* parse the stuff which is piped to /proc/cio_ignore
*/
-static inline void
+static void
blacklist_parse_proc_parameters (char *buf)
{
if (strncmp (buf, "free ", 5) == 0) {
@@ -364,7 +364,7 @@ cio_ignore_proc_open(struct inode *inode, struct file *file)
return seq_open(file, &cio_ignore_proc_seq_ops);
}
-static struct file_operations cio_ignore_proc_fops = {
+static const struct file_operations cio_ignore_proc_fops = {
.open = cio_ignore_proc_open,
.read = seq_read,
.llseek = seq_lseek,
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c
index 38954f5cd14..d48e3ca4752 100644
--- a/drivers/s390/cio/ccwgroup.c
+++ b/drivers/s390/cio/ccwgroup.c
@@ -53,7 +53,7 @@ ccwgroup_uevent (struct device *dev, char **envp, int num_envp, char *buffer,
static struct bus_type ccwgroup_bus_type;
-static inline void
+static void
__ccwgroup_remove_symlinks(struct ccwgroup_device *gdev)
{
int i;
@@ -104,7 +104,7 @@ ccwgroup_release (struct device *dev)
kfree(gdev);
}
-static inline int
+static int
__ccwgroup_create_symlinks(struct ccwgroup_device *gdev)
{
char str[8];
@@ -424,7 +424,7 @@ ccwgroup_probe_ccwdev(struct ccw_device *cdev)
return 0;
}
-static inline struct ccwgroup_device *
+static struct ccwgroup_device *
__ccwgroup_get_gdev_by_cdev(struct ccw_device *cdev)
{
struct ccwgroup_device *gdev;
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c
index cbab8d2ce5c..6f05a44e381 100644
--- a/drivers/s390/cio/chsc.c
+++ b/drivers/s390/cio/chsc.c
@@ -93,7 +93,7 @@ chsc_get_sch_desc_irq(struct subchannel *sch, void *page)
u16 sch; /* subchannel */
u8 chpid[8]; /* chpids 0-7 */
u16 fla[8]; /* full link addresses 0-7 */
- } *ssd_area;
+ } __attribute__ ((packed)) *ssd_area;
ssd_area = page;
@@ -277,7 +277,7 @@ out_unreg:
return 0;
}
-static inline void
+static void
s390_set_chpid_offline( __u8 chpid)
{
char dbf_txt[15];
@@ -338,7 +338,7 @@ s390_process_res_acc_sch(struct res_acc_data *res_data, struct subchannel *sch)
return 0x80 >> chp;
}
-static inline int
+static int
s390_process_res_acc_new_sch(struct subchannel_id schid)
{
struct schib schib;
@@ -444,7 +444,7 @@ __get_chpid_from_lir(void *data)
u32 andesc[28];
/* incident-specific information */
u32 isinfo[28];
- } *lir;
+ } __attribute__ ((packed)) *lir;
lir = data;
if (!(lir->iq&0x80))
@@ -461,154 +461,146 @@ __get_chpid_from_lir(void *data)
return (u16) (lir->indesc[0]&0x000000ff);
}
-int
-chsc_process_crw(void)
+struct chsc_sei_area {
+ struct chsc_header request;
+ u32 reserved1;
+ u32 reserved2;
+ u32 reserved3;
+ struct chsc_header response;
+ u32 reserved4;
+ u8 flags;
+ u8 vf; /* validity flags */
+ u8 rs; /* reporting source */
+ u8 cc; /* content code */
+ u16 fla; /* full link address */
+ u16 rsid; /* reporting source id */
+ u32 reserved5;
+ u32 reserved6;
+ u8 ccdf[4096 - 16 - 24]; /* content-code dependent field */
+ /* ccdf has to be big enough for a link-incident record */
+} __attribute__ ((packed));
+
+static int chsc_process_sei_link_incident(struct chsc_sei_area *sei_area)
+{
+ int chpid;
+
+ CIO_CRW_EVENT(4, "chsc: link incident (rs=%02x, rs_id=%04x)\n",
+ sei_area->rs, sei_area->rsid);
+ if (sei_area->rs != 4)
+ return 0;
+ chpid = __get_chpid_from_lir(sei_area->ccdf);
+ if (chpid < 0)
+ CIO_CRW_EVENT(4, "chsc: link incident - invalid LIR\n");
+ else
+ s390_set_chpid_offline(chpid);
+
+ return 0;
+}
+
+static int chsc_process_sei_res_acc(struct chsc_sei_area *sei_area)
{
- int chpid, ret;
struct res_acc_data res_data;
- struct {
- struct chsc_header request;
- u32 reserved1;
- u32 reserved2;
- u32 reserved3;
- struct chsc_header response;
- u32 reserved4;
- u8 flags;
- u8 vf; /* validity flags */
- u8 rs; /* reporting source */
- u8 cc; /* content code */
- u16 fla; /* full link address */
- u16 rsid; /* reporting source id */
- u32 reserved5;
- u32 reserved6;
- u32 ccdf[96]; /* content-code dependent field */
- /* ccdf has to be big enough for a link-incident record */
- } *sei_area;
+ struct device *dev;
+ int status;
+ int rc;
+
+ CIO_CRW_EVENT(4, "chsc: resource accessibility event (rs=%02x, "
+ "rs_id=%04x)\n", sei_area->rs, sei_area->rsid);
+ if (sei_area->rs != 4)
+ return 0;
+ /* allocate a new channel path structure, if needed */
+ status = get_chp_status(sei_area->rsid);
+ if (status < 0)
+ new_channel_path(sei_area->rsid);
+ else if (!status)
+ return 0;
+ dev = get_device(&css[0]->chps[sei_area->rsid]->dev);
+ memset(&res_data, 0, sizeof(struct res_acc_data));
+ res_data.chp = to_channelpath(dev);
+ if ((sei_area->vf & 0xc0) != 0) {
+ res_data.fla = sei_area->fla;
+ if ((sei_area->vf & 0xc0) == 0xc0)
+ /* full link address */
+ res_data.fla_mask = 0xffff;
+ else
+ /* link address */
+ res_data.fla_mask = 0xff00;
+ }
+ rc = s390_process_res_acc(&res_data);
+ put_device(dev);
+
+ return rc;
+}
+
+static int chsc_process_sei(struct chsc_sei_area *sei_area)
+{
+ int rc;
+
+ /* Check if we might have lost some information. */
+ if (sei_area->flags & 0x40)
+ CIO_CRW_EVENT(2, "chsc: event overflow\n");
+ /* which kind of information was stored? */
+ rc = 0;
+ switch (sei_area->cc) {
+ case 1: /* link incident*/
+ rc = chsc_process_sei_link_incident(sei_area);
+ break;
+ case 2: /* i/o resource accessibiliy */
+ rc = chsc_process_sei_res_acc(sei_area);
+ break;
+ default: /* other stuff */
+ CIO_CRW_EVENT(4, "chsc: unhandled sei content code %d\n",
+ sei_area->cc);
+ break;
+ }
+
+ return rc;
+}
+
+int chsc_process_crw(void)
+{
+ struct chsc_sei_area *sei_area;
+ int ret;
+ int rc;
if (!sei_page)
return 0;
- /*
- * build the chsc request block for store event information
- * and do the call
- * This function is only called by the machine check handler thread,
- * so we don't need locking for the sei_page.
- */
+ /* Access to sei_page is serialized through machine check handler
+ * thread, so no need for locking. */
sei_area = sei_page;
CIO_TRACE_EVENT( 2, "prcss");
ret = 0;
do {
- int ccode, status;
- struct device *dev;
memset(sei_area, 0, sizeof(*sei_area));
- memset(&res_data, 0, sizeof(struct res_acc_data));
sei_area->request.length = 0x0010;
sei_area->request.code = 0x000e;
+ if (chsc(sei_area))
+ break;
- ccode = chsc(sei_area);
- if (ccode > 0)
- return 0;
-
- switch (sei_area->response.code) {
- /* for debug purposes, check for problems */
- case 0x0001:
- CIO_CRW_EVENT(4, "chsc_process_crw: event information "
- "successfully stored\n");
- break; /* everything ok */
- case 0x0002:
- CIO_CRW_EVENT(2,
- "chsc_process_crw: invalid command!\n");
- return 0;
- case 0x0003:
- CIO_CRW_EVENT(2, "chsc_process_crw: error in chsc "
- "request block!\n");
- return 0;
- case 0x0005:
- CIO_CRW_EVENT(2, "chsc_process_crw: no event "
- "information stored\n");
- return 0;
- default:
- CIO_CRW_EVENT(2, "chsc_process_crw: chsc response %d\n",
+ if (sei_area->response.code == 0x0001) {
+ CIO_CRW_EVENT(4, "chsc: sei successful\n");
+ rc = chsc_process_sei(sei_area);
+ if (rc)
+ ret = rc;
+ } else {
+ CIO_CRW_EVENT(2, "chsc: sei failed (rc=%04x)\n",
sei_area->response.code);
- return 0;
- }
-
- /* Check if we might have lost some information. */
- if (sei_area->flags & 0x40)
- CIO_CRW_EVENT(2, "chsc_process_crw: Event information "
- "has been lost due to overflow!\n");
-
- if (sei_area->rs != 4) {
- CIO_CRW_EVENT(2, "chsc_process_crw: reporting source "
- "(%04X) isn't a chpid!\n",
- sei_area->rsid);
- continue;
- }
-
- /* which kind of information was stored? */
- switch (sei_area->cc) {
- case 1: /* link incident*/
- CIO_CRW_EVENT(4, "chsc_process_crw: "
- "channel subsystem reports link incident,"
- " reporting source is chpid %x\n",
- sei_area->rsid);
- chpid = __get_chpid_from_lir(sei_area->ccdf);
- if (chpid < 0)
- CIO_CRW_EVENT(4, "%s: Invalid LIR, skipping\n",
- __FUNCTION__);
- else
- s390_set_chpid_offline(chpid);
- break;
-
- case 2: /* i/o resource accessibiliy */
- CIO_CRW_EVENT(4, "chsc_process_crw: "
- "channel subsystem reports some I/O "
- "devices may have become accessible\n");
- pr_debug("Data received after sei: \n");
- pr_debug("Validity flags: %x\n", sei_area->vf);
-
- /* allocate a new channel path structure, if needed */
- status = get_chp_status(sei_area->rsid);
- if (status < 0)
- new_channel_path(sei_area->rsid);
- else if (!status)
- break;
- dev = get_device(&css[0]->chps[sei_area->rsid]->dev);
- res_data.chp = to_channelpath(dev);
- pr_debug("chpid: %x", sei_area->rsid);
- if ((sei_area->vf & 0xc0) != 0) {
- res_data.fla = sei_area->fla;
- if ((sei_area->vf & 0xc0) == 0xc0) {
- pr_debug(" full link addr: %x",
- sei_area->fla);
- res_data.fla_mask = 0xffff;
- } else {
- pr_debug(" link addr: %x",
- sei_area->fla);
- res_data.fla_mask = 0xff00;
- }
- }
- ret = s390_process_res_acc(&res_data);
- pr_debug("\n\n");
- put_device(dev);
- break;
-
- default: /* other stuff */
- CIO_CRW_EVENT(4, "chsc_process_crw: event %d\n",
- sei_area->cc);
+ ret = 0;
break;
}
} while (sei_area->flags & 0x80);
+
return ret;
}
-static inline int
+static int
__chp_add_new_sch(struct subchannel_id schid)
{
struct schib schib;
int ret;
- if (stsch(schid, &schib))
+ if (stsch_err(schid, &schib))
/* We're through */
return need_rescan ? -EAGAIN : -ENXIO;
@@ -709,7 +701,7 @@ chp_process_crw(int chpid, int on)
return chp_add(chpid);
}
-static inline int check_for_io_on_path(struct subchannel *sch, int index)
+static int check_for_io_on_path(struct subchannel *sch, int index)
{
int cc;
@@ -741,7 +733,7 @@ static void terminate_internal_io(struct subchannel *sch)
sch->driver->termination(&sch->dev);
}
-static inline void
+static void
__s390_subchannel_vary_chpid(struct subchannel *sch, __u8 chpid, int on)
{
int chp, old_lpm;
@@ -967,8 +959,8 @@ static struct bin_attribute chp_measurement_attr = {
static void
chsc_remove_chp_cmg_attr(struct channel_path *chp)
{
- sysfs_remove_bin_file(&chp->dev.kobj, &chp_measurement_chars_attr);
- sysfs_remove_bin_file(&chp->dev.kobj, &chp_measurement_attr);
+ device_remove_bin_file(&chp->dev, &chp_measurement_chars_attr);
+ device_remove_bin_file(&chp->dev, &chp_measurement_attr);
}
static int
@@ -976,14 +968,12 @@ chsc_add_chp_cmg_attr(struct channel_path *chp)
{
int ret;
- ret = sysfs_create_bin_file(&chp->dev.kobj,
- &chp_measurement_chars_attr);
+ ret = device_create_bin_file(&chp->dev, &chp_measurement_chars_attr);
if (ret)
return ret;
- ret = sysfs_create_bin_file(&chp->dev.kobj, &chp_measurement_attr);
+ ret = device_create_bin_file(&chp->dev, &chp_measurement_attr);
if (ret)
- sysfs_remove_bin_file(&chp->dev.kobj,
- &chp_measurement_chars_attr);
+ device_remove_bin_file(&chp->dev, &chp_measurement_chars_attr);
return ret;
}
@@ -1042,7 +1032,7 @@ __chsc_do_secm(struct channel_subsystem *css, int enable, void *page)
u32 : 4;
u32 fmt : 4;
u32 : 16;
- } *secm_area;
+ } __attribute__ ((packed)) *secm_area;
int ret, ccode;
secm_area = page;
@@ -1253,7 +1243,7 @@ chsc_determine_channel_path_description(int chpid,
struct chsc_header response;
u32 zeroes2;
struct channel_path_desc desc;
- } *scpd_area;
+ } __attribute__ ((packed)) *scpd_area;
scpd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
if (!scpd_area)
@@ -1350,7 +1340,7 @@ chsc_get_channel_measurement_chars(struct channel_path *chp)
u32 cmg : 8;
u32 zeroes3;
u32 data[NR_MEASUREMENT_CHARS];
- } *scmc_area;
+ } __attribute__ ((packed)) *scmc_area;
scmc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
if (!scmc_area)
@@ -1517,7 +1507,7 @@ chsc_enable_facility(int operation_code)
u32 reserved5:4;
u32 format2:4;
u32 reserved6:24;
- } *sda_area;
+ } __attribute__ ((packed)) *sda_area;
sda_area = (void *)get_zeroed_page(GFP_KERNEL|GFP_DMA);
if (!sda_area)
@@ -1569,7 +1559,7 @@ chsc_determine_css_characteristics(void)
u32 reserved4;
u32 general_char[510];
u32 chsc_char[518];
- } *scsc_area;
+ } __attribute__ ((packed)) *scsc_area;
scsc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
if (!scsc_area) {
diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h
index a259245780a..0fb2b024208 100644
--- a/drivers/s390/cio/chsc.h
+++ b/drivers/s390/cio/chsc.h
@@ -10,17 +10,17 @@
struct chsc_header {
u16 length;
u16 code;
-};
+} __attribute__ ((packed));
#define NR_MEASUREMENT_CHARS 5
struct cmg_chars {
u32 values[NR_MEASUREMENT_CHARS];
-};
+} __attribute__ ((packed));
#define NR_MEASUREMENT_ENTRIES 8
struct cmg_entry {
u32 values[NR_MEASUREMENT_ENTRIES];
-};
+} __attribute__ ((packed));
struct channel_path_desc {
u8 flags;
@@ -31,7 +31,7 @@ struct channel_path_desc {
u8 zeroes;
u8 chla;
u8 chpp;
-};
+} __attribute__ ((packed));
struct channel_path {
int id;
@@ -47,6 +47,9 @@ struct channel_path {
extern void s390_process_css( void );
extern void chsc_validate_chpids(struct subchannel *);
extern void chpid_is_actually_online(int);
+extern int css_get_ssd_info(struct subchannel *);
+extern int chsc_process_crw(void);
+extern int chp_process_crw(int, int);
struct css_general_char {
u64 : 41;
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index ae1bf231d08..9cb129ab5be 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -21,6 +21,7 @@
#include <asm/irq_regs.h>
#include <asm/setup.h>
#include <asm/reset.h>
+#include <asm/ipl.h>
#include "airq.h"
#include "cio.h"
#include "css.h"
@@ -122,7 +123,7 @@ cio_get_options (struct subchannel *sch)
* Use tpi to get a pending interrupt, call the interrupt handler and
* return a pointer to the subchannel structure.
*/
-static inline int
+static int
cio_tpi(void)
{
struct tpi_info *tpi_info;
@@ -152,7 +153,7 @@ cio_tpi(void)
return 1;
}
-static inline int
+static int
cio_start_handle_notoper(struct subchannel *sch, __u8 lpm)
{
char dbf_text[15];
@@ -585,7 +586,7 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid)
* This device must not be known to Linux. So we simply
* say that there is no device and return ENODEV.
*/
- CIO_MSG_EVENT(0, "Blacklisted device detected "
+ CIO_MSG_EVENT(4, "Blacklisted device detected "
"at devno %04X, subchannel set %x\n",
sch->schib.pmcw.dev, sch->schid.ssid);
err = -ENODEV;
@@ -646,7 +647,7 @@ do_IRQ (struct pt_regs *regs)
* Make sure that the i/o interrupt did not "overtake"
* the last HZ timer interrupt.
*/
- account_ticks();
+ account_ticks(S390_lowcore.int_clock);
/*
* Get interrupt information from lowcore
*/
@@ -832,7 +833,7 @@ cio_get_console_subchannel(void)
}
#endif
-static inline int
+static int
__disable_subchannel_easy(struct subchannel_id schid, struct schib *schib)
{
int retry, cc;
@@ -850,7 +851,20 @@ __disable_subchannel_easy(struct subchannel_id schid, struct schib *schib)
return -EBUSY; /* uhm... */
}
-static inline int
+/* we can't use the normal udelay here, since it enables external interrupts */
+
+static void udelay_reset(unsigned long usecs)
+{
+ uint64_t start_cc, end_cc;
+
+ asm volatile ("STCK %0" : "=m" (start_cc));
+ do {
+ cpu_relax();
+ asm volatile ("STCK %0" : "=m" (end_cc));
+ } while (((end_cc - start_cc)/4096) < usecs);
+}
+
+static int
__clear_subchannel_easy(struct subchannel_id schid)
{
int retry;
@@ -865,7 +879,7 @@ __clear_subchannel_easy(struct subchannel_id schid)
if (schid_equal(&ti.schid, &schid))
return 0;
}
- udelay(100);
+ udelay_reset(100);
}
return -EBUSY;
}
@@ -882,11 +896,11 @@ static int stsch_reset(struct subchannel_id schid, volatile struct schib *addr)
int rc;
pgm_check_occured = 0;
- s390_reset_pgm_handler = cio_reset_pgm_check_handler;
+ s390_base_pgm_handler_fn = cio_reset_pgm_check_handler;
rc = stsch(schid, addr);
- s390_reset_pgm_handler = NULL;
+ s390_base_pgm_handler_fn = NULL;
- /* The program check handler could have changed pgm_check_occured */
+ /* The program check handler could have changed pgm_check_occured. */
barrier();
if (pgm_check_occured)
@@ -944,7 +958,7 @@ static void css_reset(void)
/* Reset subchannels. */
for_each_subchannel(__shutdown_subchannel_easy, NULL);
/* Reset channel paths. */
- s390_reset_mcck_handler = s390_reset_chpids_mcck_handler;
+ s390_base_mcck_handler_fn = s390_reset_chpids_mcck_handler;
/* Enable channel report machine checks. */
__ctl_set_bit(14, 28);
/* Temporarily reenable machine checks. */
@@ -969,7 +983,7 @@ static void css_reset(void)
local_mcck_disable();
/* Disable channel report machine checks. */
__ctl_clear_bit(14, 28);
- s390_reset_mcck_handler = NULL;
+ s390_base_mcck_handler_fn = NULL;
}
static struct reset_call css_reset_call = {
@@ -1034,7 +1048,7 @@ void reipl_ccw_dev(struct ccw_dev_id *devid)
do_reipl_asm(*((__u32*)&schid));
}
-extern struct schib ipl_schib;
+static struct schib __initdata ipl_schib;
/*
* ipl_save_parameters gets called very early. It is not allowed to access
diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c
index 828b2d334f0..90b22faabbf 100644
--- a/drivers/s390/cio/cmf.c
+++ b/drivers/s390/cio/cmf.c
@@ -519,8 +519,8 @@ struct cmb {
/* insert a single device into the cmb_area list
* called with cmb_area.lock held from alloc_cmb
*/
-static inline int alloc_cmb_single (struct ccw_device *cdev,
- struct cmb_data *cmb_data)
+static int alloc_cmb_single(struct ccw_device *cdev,
+ struct cmb_data *cmb_data)
{
struct cmb *cmb;
struct ccw_device_private *node;
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index 9d6c0244686..fe0ace7aece 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -30,7 +30,7 @@ struct channel_subsystem *css[__MAX_CSSID + 1];
int css_characteristics_avail = 0;
-inline int
+int
for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *data)
{
struct subchannel_id schid;
@@ -108,9 +108,6 @@ css_subchannel_release(struct device *dev)
}
}
-extern int css_get_ssd_info(struct subchannel *sch);
-
-
int css_sch_device_register(struct subchannel *sch)
{
int ret;
@@ -187,7 +184,7 @@ get_subchannel_by_schid(struct subchannel_id schid)
return dev ? to_subchannel(dev) : NULL;
}
-static inline int css_get_subchannel_status(struct subchannel *sch)
+static int css_get_subchannel_status(struct subchannel *sch)
{
struct schib schib;
@@ -299,7 +296,7 @@ static int css_evaluate_new_subchannel(struct subchannel_id schid, int slow)
/* Will be done on the slow path. */
return -EAGAIN;
}
- if (stsch(schid, &schib) || !schib.pmcw.dnv) {
+ if (stsch_err(schid, &schib) || !schib.pmcw.dnv) {
/* Unusable - ignore. */
return 0;
}
@@ -417,7 +414,7 @@ static void reprobe_all(struct work_struct *unused)
need_reprobe);
}
-DECLARE_WORK(css_reprobe_work, reprobe_all);
+static DECLARE_WORK(css_reprobe_work, reprobe_all);
/* Schedule reprobing of all unregistered subchannels. */
void css_schedule_reprobe(void)
@@ -578,7 +575,7 @@ css_cm_enable_store(struct device *dev, struct device_attribute *attr,
static DEVICE_ATTR(cm_enable, 0644, css_cm_enable_show, css_cm_enable_store);
-static inline int __init setup_css(int nr)
+static int __init setup_css(int nr)
{
u32 tod_high;
int ret;
diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h
index 3464c5b875c..ca2bab932a8 100644
--- a/drivers/s390/cio/css.h
+++ b/drivers/s390/cio/css.h
@@ -143,6 +143,8 @@ extern void css_sch_device_unregister(struct subchannel *);
extern struct subchannel * get_subchannel_by_schid(struct subchannel_id);
extern int css_init_done;
extern int for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *);
+extern int css_process_crw(int, int);
+extern void css_reiterate_subchannels(void);
#define __MAX_SUBCHANNEL 65535
#define __MAX_SSID 3
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index 803579053c2..e322111fb36 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -138,7 +138,6 @@ struct bus_type ccw_bus_type;
static int io_subchannel_probe (struct subchannel *);
static int io_subchannel_remove (struct subchannel *);
-void io_subchannel_irq (struct device *);
static int io_subchannel_notify(struct device *, int);
static void io_subchannel_verify(struct device *);
static void io_subchannel_ioterm(struct device *);
@@ -235,11 +234,8 @@ chpids_show (struct device * dev, struct device_attribute *attr, char * buf)
ssize_t ret = 0;
int chp;
- if (ssd)
- for (chp = 0; chp < 8; chp++)
- ret += sprintf (buf+ret, "%02x ", ssd->chpid[chp]);
- else
- ret += sprintf (buf, "n/a");
+ for (chp = 0; chp < 8; chp++)
+ ret += sprintf (buf+ret, "%02x ", ssd->chpid[chp]);
ret += sprintf (buf+ret, "\n");
return min((ssize_t)PAGE_SIZE, ret);
}
@@ -552,13 +548,13 @@ static struct attribute_group ccwdev_attr_group = {
.attrs = ccwdev_attrs,
};
-static inline int
+static int
device_add_files (struct device *dev)
{
return sysfs_create_group(&dev->kobj, &ccwdev_attr_group);
}
-static inline void
+static void
device_remove_files(struct device *dev)
{
sysfs_remove_group(&dev->kobj, &ccwdev_attr_group);
diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h
index 29db6341d63..b66338b7657 100644
--- a/drivers/s390/cio/device.h
+++ b/drivers/s390/cio/device.h
@@ -74,6 +74,7 @@ extern struct workqueue_struct *ccw_device_notify_work;
extern wait_queue_head_t ccw_device_init_wq;
extern atomic_t ccw_device_init_count;
+void io_subchannel_irq (struct device *pdev);
void io_subchannel_recog_done(struct ccw_device *cdev);
int ccw_device_cancel_halt_clear(struct ccw_device *);
@@ -118,6 +119,7 @@ int ccw_device_stlck(struct ccw_device *);
/* qdio needs this. */
void ccw_device_set_timeout(struct ccw_device *, int);
extern struct subchannel_id ccw_device_get_subchannel_id(struct ccw_device *);
+extern struct bus_type ccw_bus_type;
/* Channel measurement facility related */
void retry_set_schib(struct ccw_device *cdev);
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index eed14572fc3..51238e7555b 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -206,7 +206,7 @@ ccw_device_handle_oper(struct ccw_device *cdev)
* been varied online on the SE so we have to find out by magic (i. e. driving
* the channel subsystem to device selection and updating our path masks).
*/
-static inline void
+static void
__recover_lost_chpids(struct subchannel *sch, int old_lpm)
{
int mask, i;
@@ -387,7 +387,7 @@ ccw_device_done(struct ccw_device *cdev, int state)
put_device (&cdev->dev);
}
-static inline int cmp_pgid(struct pgid *p1, struct pgid *p2)
+static int cmp_pgid(struct pgid *p1, struct pgid *p2)
{
char *c1;
char *c2;
@@ -842,6 +842,8 @@ ccw_device_irq(struct ccw_device *cdev, enum dev_event dev_event)
call_handler_unsol:
if (cdev->handler)
cdev->handler (cdev, 0, irb);
+ if (cdev->private->flags.doverify)
+ ccw_device_online_verify(cdev, 0);
return;
}
/* Accumulate status and find out if a basic sense is needed. */
@@ -892,7 +894,7 @@ ccw_device_online_timeout(struct ccw_device *cdev, enum dev_event dev_event)
/*
* Got an interrupt for a basic sense.
*/
-void
+static void
ccw_device_w4sense(struct ccw_device *cdev, enum dev_event dev_event)
{
struct irb *irb;
diff --git a/drivers/s390/cio/device_id.c b/drivers/s390/cio/device_id.c
index f17275917fe..997f4687453 100644
--- a/drivers/s390/cio/device_id.c
+++ b/drivers/s390/cio/device_id.c
@@ -11,6 +11,7 @@
#include <linux/module.h>
#include <linux/init.h>
+#include <linux/kernel.h>
#include <asm/ccwdev.h>
#include <asm/delay.h>
@@ -138,7 +139,7 @@ VM_virtual_device_info (__u16 devno, struct senseid *ps)
ps->cu_model = 0x60;
return;
}
- for (i = 0; i < sizeof(vm_devices) / sizeof(vm_devices[0]); i++)
+ for (i = 0; i < ARRAY_SIZE(vm_devices); i++)
if (diag_data.vrdcvcla == vm_devices[i].vrdcvcla &&
diag_data.vrdcvtyp == vm_devices[i].vrdcvtyp) {
ps->cu_type = vm_devices[i].cu_type;
diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c
index d269607336e..7c7775aae38 100644
--- a/drivers/s390/cio/device_ops.c
+++ b/drivers/s390/cio/device_ops.c
@@ -23,8 +23,7 @@
#include "chsc.h"
#include "device.h"
-int
-ccw_device_set_options(struct ccw_device *cdev, unsigned long flags)
+int ccw_device_set_options_mask(struct ccw_device *cdev, unsigned long flags)
{
/*
* The flag usage is mutal exclusive ...
@@ -39,6 +38,33 @@ ccw_device_set_options(struct ccw_device *cdev, unsigned long flags)
return 0;
}
+int ccw_device_set_options(struct ccw_device *cdev, unsigned long flags)
+{
+ /*
+ * The flag usage is mutal exclusive ...
+ */
+ if (((flags & CCWDEV_EARLY_NOTIFICATION) &&
+ (flags & CCWDEV_REPORT_ALL)) ||
+ ((flags & CCWDEV_EARLY_NOTIFICATION) &&
+ cdev->private->options.repall) ||
+ ((flags & CCWDEV_REPORT_ALL) &&
+ cdev->private->options.fast))
+ return -EINVAL;
+ cdev->private->options.fast |= (flags & CCWDEV_EARLY_NOTIFICATION) != 0;
+ cdev->private->options.repall |= (flags & CCWDEV_REPORT_ALL) != 0;
+ cdev->private->options.pgroup |= (flags & CCWDEV_DO_PATHGROUP) != 0;
+ cdev->private->options.force |= (flags & CCWDEV_ALLOW_FORCE) != 0;
+ return 0;
+}
+
+void ccw_device_clear_options(struct ccw_device *cdev, unsigned long flags)
+{
+ cdev->private->options.fast &= (flags & CCWDEV_EARLY_NOTIFICATION) == 0;
+ cdev->private->options.repall &= (flags & CCWDEV_REPORT_ALL) == 0;
+ cdev->private->options.pgroup &= (flags & CCWDEV_DO_PATHGROUP) == 0;
+ cdev->private->options.force &= (flags & CCWDEV_ALLOW_FORCE) == 0;
+}
+
int
ccw_device_clear(struct ccw_device *cdev, unsigned long intparm)
{
@@ -302,7 +328,7 @@ ccw_device_wake_up(struct ccw_device *cdev, unsigned long ip, struct irb *irb)
wake_up(&cdev->private->wait_q);
}
-static inline int
+static int
__ccw_device_retry_loop(struct ccw_device *cdev, struct ccw1 *ccw, long magic, __u8 lpm)
{
int ret;
@@ -601,7 +627,9 @@ _ccw_device_get_device_number(struct ccw_device *cdev)
MODULE_LICENSE("GPL");
+EXPORT_SYMBOL(ccw_device_set_options_mask);
EXPORT_SYMBOL(ccw_device_set_options);
+EXPORT_SYMBOL(ccw_device_clear_options);
EXPORT_SYMBOL(ccw_device_clear);
EXPORT_SYMBOL(ccw_device_halt);
EXPORT_SYMBOL(ccw_device_resume);
diff --git a/drivers/s390/cio/device_status.c b/drivers/s390/cio/device_status.c
index bdcf930f7be..6b1caea622e 100644
--- a/drivers/s390/cio/device_status.c
+++ b/drivers/s390/cio/device_status.c
@@ -25,7 +25,7 @@
* Check for any kind of channel or interface control check but don't
* issue the message for the console device
*/
-static inline void
+static void
ccw_device_msg_control_check(struct ccw_device *cdev, struct irb *irb)
{
if (!(irb->scsw.cstat & (SCHN_STAT_CHN_DATA_CHK |
@@ -72,7 +72,7 @@ ccw_device_path_notoper(struct ccw_device *cdev)
/*
* Copy valid bits from the extended control word to device irb.
*/
-static inline void
+static void
ccw_device_accumulate_ecw(struct ccw_device *cdev, struct irb *irb)
{
/*
@@ -94,7 +94,7 @@ ccw_device_accumulate_ecw(struct ccw_device *cdev, struct irb *irb)
/*
* Check if extended status word is valid.
*/
-static inline int
+static int
ccw_device_accumulate_esw_valid(struct irb *irb)
{
if (!irb->scsw.eswf && irb->scsw.stctl == SCSW_STCTL_STATUS_PEND)
@@ -109,7 +109,7 @@ ccw_device_accumulate_esw_valid(struct irb *irb)
/*
* Copy valid bits from the extended status word to device irb.
*/
-static inline void
+static void
ccw_device_accumulate_esw(struct ccw_device *cdev, struct irb *irb)
{
struct irb *cdev_irb;
diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c
index 6fd1940842e..5b1e3ff26c0 100644
--- a/drivers/s390/cio/qdio.c
+++ b/drivers/s390/cio/qdio.c
@@ -66,7 +66,6 @@ MODULE_LICENSE("GPL");
/******************** HERE WE GO ***********************************/
static const char version[] = "QDIO base support version 2";
-extern struct bus_type ccw_bus_type;
static int qdio_performance_stats = 0;
static int proc_perf_file_registration;
@@ -138,7 +137,7 @@ qdio_release_q(struct qdio_q *q)
}
/*check ccq */
-static inline int
+static int
qdio_check_ccq(struct qdio_q *q, unsigned int ccq)
{
char dbf_text[15];
@@ -153,7 +152,7 @@ qdio_check_ccq(struct qdio_q *q, unsigned int ccq)
return -EIO;
}
/* EQBS: extract buffer states */
-static inline int
+static int
qdio_do_eqbs(struct qdio_q *q, unsigned char *state,
unsigned int *start, unsigned int *cnt)
{
@@ -188,7 +187,7 @@ again:
}
/* SQBS: set buffer states */
-static inline int
+static int
qdio_do_sqbs(struct qdio_q *q, unsigned char state,
unsigned int *start, unsigned int *cnt)
{
@@ -315,7 +314,7 @@ __do_siga_output(struct qdio_q *q, unsigned int *busy_bit)
* returns QDIO_SIGA_ERROR_ACCESS_EXCEPTION as cc, when SIGA returns
* an access exception
*/
-static inline int
+static int
qdio_siga_output(struct qdio_q *q)
{
int cc;
@@ -349,7 +348,7 @@ qdio_siga_output(struct qdio_q *q)
return cc;
}
-static inline int
+static int
qdio_siga_input(struct qdio_q *q)
{
int cc;
@@ -421,7 +420,7 @@ tiqdio_sched_tl(void)
tasklet_hi_schedule(&tiqdio_tasklet);
}
-static inline void
+static void
qdio_mark_tiq(struct qdio_q *q)
{
unsigned long flags;
@@ -471,7 +470,7 @@ qdio_mark_q(struct qdio_q *q)
tasklet_schedule(&q->tasklet);
}
-static inline int
+static int
qdio_stop_polling(struct qdio_q *q)
{
#ifdef QDIO_USE_PROCESSING_STATE
@@ -525,7 +524,7 @@ qdio_stop_polling(struct qdio_q *q)
* sophisticated locking outside of unmark_q, so that we don't need to
* disable the interrupts :-)
*/
-static inline void
+static void
qdio_unmark_q(struct qdio_q *q)
{
unsigned long flags;
@@ -691,7 +690,7 @@ qdio_qebsm_get_inbound_buffer_frontier(struct qdio_q *q)
return q->first_to_check;
}
-static inline int
+static int
qdio_get_outbound_buffer_frontier(struct qdio_q *q)
{
struct qdio_irq *irq;
@@ -774,7 +773,7 @@ out:
}
/* all buffers are processed */
-static inline int
+static int
qdio_is_outbound_q_done(struct qdio_q *q)
{
int no_used;
@@ -796,7 +795,7 @@ qdio_is_outbound_q_done(struct qdio_q *q)
return (no_used==0);
}
-static inline int
+static int
qdio_has_outbound_q_moved(struct qdio_q *q)
{
int i;
@@ -816,7 +815,7 @@ qdio_has_outbound_q_moved(struct qdio_q *q)
}
}
-static inline void
+static void
qdio_kick_outbound_q(struct qdio_q *q)
{
int result;
@@ -905,7 +904,7 @@ qdio_kick_outbound_q(struct qdio_q *q)
}
}
-static inline void
+static void
qdio_kick_outbound_handler(struct qdio_q *q)
{
int start, end, real_end, count;
@@ -942,7 +941,7 @@ qdio_kick_outbound_handler(struct qdio_q *q)
q->error_status_flags=0;
}
-static inline void
+static void
__qdio_outbound_processing(struct qdio_q *q)
{
int siga_attempts;
@@ -1002,7 +1001,7 @@ qdio_outbound_processing(struct qdio_q *q)
/************************* INBOUND ROUTINES *******************************/
-static inline int
+static int
qdio_get_inbound_buffer_frontier(struct qdio_q *q)
{
struct qdio_irq *irq;
@@ -1133,7 +1132,7 @@ out:
return q->first_to_check;
}
-static inline int
+static int
qdio_has_inbound_q_moved(struct qdio_q *q)
{
int i;
@@ -1167,7 +1166,7 @@ qdio_has_inbound_q_moved(struct qdio_q *q)
}
/* means, no more buffers to be filled */
-static inline int
+static int
tiqdio_is_inbound_q_done(struct qdio_q *q)
{
int no_used;
@@ -1228,7 +1227,7 @@ tiqdio_is_inbound_q_done(struct qdio_q *q)
return 0;
}
-static inline int
+static int
qdio_is_inbound_q_done(struct qdio_q *q)
{
int no_used;
@@ -1296,7 +1295,7 @@ qdio_is_inbound_q_done(struct qdio_q *q)
}
}
-static inline void
+static void
qdio_kick_inbound_handler(struct qdio_q *q)
{
int count, start, end, real_end, i;
@@ -1343,7 +1342,7 @@ qdio_kick_inbound_handler(struct qdio_q *q)
}
}
-static inline void
+static void
__tiqdio_inbound_processing(struct qdio_q *q, int spare_ind_was_set)
{
struct qdio_irq *irq_ptr;
@@ -1442,7 +1441,7 @@ tiqdio_inbound_processing(struct qdio_q *q)
__tiqdio_inbound_processing(q, atomic_read(&spare_indicator_usecount));
}
-static inline void
+static void
__qdio_inbound_processing(struct qdio_q *q)
{
int q_laps=0;
@@ -1493,7 +1492,7 @@ qdio_inbound_processing(struct qdio_q *q)
/************************* MAIN ROUTINES *******************************/
#ifdef QDIO_USE_PROCESSING_STATE
-static inline int
+static int
tiqdio_reset_processing_state(struct qdio_q *q, int q_laps)
{
if (!q) {
@@ -1545,7 +1544,7 @@ tiqdio_reset_processing_state(struct qdio_q *q, int q_laps)
}
#endif /* QDIO_USE_PROCESSING_STATE */
-static inline void
+static void
tiqdio_inbound_checks(void)
{
struct qdio_q *q;
@@ -1949,7 +1948,7 @@ qdio_set_state(struct qdio_irq *irq_ptr, enum qdio_irq_states state)
mb();
}
-static inline void
+static void
qdio_irq_check_sense(struct subchannel_id schid, struct irb *irb)
{
char dbf_text[15];
@@ -1966,7 +1965,7 @@ qdio_irq_check_sense(struct subchannel_id schid, struct irb *irb)
}
-static inline void
+static void
qdio_handle_pci(struct qdio_irq *irq_ptr)
{
int i;
@@ -2002,7 +2001,7 @@ qdio_handle_pci(struct qdio_irq *irq_ptr)
static void qdio_establish_handle_irq(struct ccw_device*, int, int);
-static inline void
+static void
qdio_handle_activate_check(struct ccw_device *cdev, unsigned long intparm,
int cstat, int dstat)
{
@@ -2229,7 +2228,7 @@ qdio_synchronize(struct ccw_device *cdev, unsigned int flags,
return cc;
}
-static inline void
+static void
qdio_check_subchannel_qebsm(struct qdio_irq *irq_ptr, unsigned char qdioac,
unsigned long token)
{
@@ -2740,7 +2739,7 @@ qdio_free(struct ccw_device *cdev)
return 0;
}
-static inline void
+static void
qdio_allocate_do_dbf(struct qdio_initialize *init_data)
{
char dbf_text[20]; /* if a printf printed out more than 8 chars */
@@ -2773,7 +2772,7 @@ qdio_allocate_do_dbf(struct qdio_initialize *init_data)
QDIO_DBF_HEX0(0,setup,&init_data->output_sbal_addr_array,sizeof(void*));
}
-static inline void
+static void
qdio_allocate_fill_input_desc(struct qdio_irq *irq_ptr, int i, int iqfmt)
{
irq_ptr->input_qs[i]->is_iqdio_q = iqfmt;
@@ -2792,7 +2791,7 @@ qdio_allocate_fill_input_desc(struct qdio_irq *irq_ptr, int i, int iqfmt)
irq_ptr->qdr->qdf0[i].dkey=QDIO_STORAGE_KEY;
}
-static inline void
+static void
qdio_allocate_fill_output_desc(struct qdio_irq *irq_ptr, int i,
int j, int iqfmt)
{
@@ -2813,7 +2812,7 @@ qdio_allocate_fill_output_desc(struct qdio_irq *irq_ptr, int i,
}
-static inline void
+static void
qdio_initialize_set_siga_flags_input(struct qdio_irq *irq_ptr)
{
int i;
@@ -2839,7 +2838,7 @@ qdio_initialize_set_siga_flags_input(struct qdio_irq *irq_ptr)
}
}
-static inline void
+static void
qdio_initialize_set_siga_flags_output(struct qdio_irq *irq_ptr)
{
int i;
@@ -2865,7 +2864,7 @@ qdio_initialize_set_siga_flags_output(struct qdio_irq *irq_ptr)
}
}
-static inline int
+static int
qdio_establish_irq_check_for_errors(struct ccw_device *cdev, int cstat,
int dstat)
{
@@ -3014,7 +3013,7 @@ qdio_allocate(struct qdio_initialize *init_data)
return 0;
}
-int qdio_fill_irq(struct qdio_initialize *init_data)
+static int qdio_fill_irq(struct qdio_initialize *init_data)
{
int i;
char dbf_text[15];
@@ -3195,7 +3194,7 @@ qdio_establish(struct qdio_initialize *init_data)
spin_lock_irqsave(get_ccwdev_lock(cdev),saveflags);
- ccw_device_set_options(cdev, 0);
+ ccw_device_set_options_mask(cdev, 0);
result=ccw_device_start_timeout(cdev,&irq_ptr->ccw,
QDIO_DOING_ESTABLISH,0, 0,
QDIO_ESTABLISH_TIMEOUT);
@@ -3367,7 +3366,7 @@ qdio_activate(struct ccw_device *cdev, int flags)
}
/* buffers filled forwards again to make Rick happy */
-static inline void
+static void
qdio_do_qdio_fill_input(struct qdio_q *q, unsigned int qidx,
unsigned int count, struct qdio_buffer *buffers)
{
@@ -3386,7 +3385,7 @@ qdio_do_qdio_fill_input(struct qdio_q *q, unsigned int qidx,
}
}
-static inline void
+static void
qdio_do_qdio_fill_output(struct qdio_q *q, unsigned int qidx,
unsigned int count, struct qdio_buffer *buffers)
{
@@ -3407,7 +3406,7 @@ qdio_do_qdio_fill_output(struct qdio_q *q, unsigned int qidx,
}
}
-static inline void
+static void
do_qdio_handle_inbound(struct qdio_q *q, unsigned int callflags,
unsigned int qidx, unsigned int count,
struct qdio_buffer *buffers)
@@ -3443,7 +3442,7 @@ do_qdio_handle_inbound(struct qdio_q *q, unsigned int callflags,
qdio_mark_q(q);
}
-static inline void
+static void
do_qdio_handle_outbound(struct qdio_q *q, unsigned int callflags,
unsigned int qidx, unsigned int count,
struct qdio_buffer *buffers)
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c
index 81b5899f401..c7d1355237b 100644
--- a/drivers/s390/crypto/ap_bus.c
+++ b/drivers/s390/crypto/ap_bus.c
@@ -465,7 +465,7 @@ static int ap_device_probe(struct device *dev)
* Flush all requests from the request/pending queue of an AP device.
* @ap_dev: pointer to the AP device.
*/
-static inline void __ap_flush_queue(struct ap_device *ap_dev)
+static void __ap_flush_queue(struct ap_device *ap_dev)
{
struct ap_message *ap_msg, *next;
@@ -587,7 +587,7 @@ static struct bus_attribute *const ap_bus_attrs[] = {
/**
* Pick one of the 16 ap domains.
*/
-static inline int ap_select_domain(void)
+static int ap_select_domain(void)
{
int queue_depth, device_type, count, max_count, best_domain;
int rc, i, j;
@@ -825,7 +825,7 @@ static inline void ap_schedule_poll_timer(void)
* required, bit 2^1 is set if the poll timer needs to get armed
* Returns 0 if the device is still present, -ENODEV if not.
*/
-static inline int ap_poll_read(struct ap_device *ap_dev, unsigned long *flags)
+static int ap_poll_read(struct ap_device *ap_dev, unsigned long *flags)
{
struct ap_queue_status status;
struct ap_message *ap_msg;
@@ -872,7 +872,7 @@ static inline int ap_poll_read(struct ap_device *ap_dev, unsigned long *flags)
* required, bit 2^1 is set if the poll timer needs to get armed
* Returns 0 if the device is still present, -ENODEV if not.
*/
-static inline int ap_poll_write(struct ap_device *ap_dev, unsigned long *flags)
+static int ap_poll_write(struct ap_device *ap_dev, unsigned long *flags)
{
struct ap_queue_status status;
struct ap_message *ap_msg;
diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c
index 1edc10a7a6f..99761391f34 100644
--- a/drivers/s390/crypto/zcrypt_api.c
+++ b/drivers/s390/crypto/zcrypt_api.c
@@ -791,7 +791,7 @@ static long trans_xcRB32(struct file *filp, unsigned int cmd,
return rc;
}
-long zcrypt_compat_ioctl(struct file *filp, unsigned int cmd,
+static long zcrypt_compat_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
if (cmd == ICARSAMODEXPO)
@@ -807,7 +807,7 @@ long zcrypt_compat_ioctl(struct file *filp, unsigned int cmd,
/**
* Misc device file operations.
*/
-static struct file_operations zcrypt_fops = {
+static const struct file_operations zcrypt_fops = {
.owner = THIS_MODULE,
.read = zcrypt_read,
.write = zcrypt_write,
@@ -833,8 +833,8 @@ static struct miscdevice zcrypt_misc_device = {
*/
static struct proc_dir_entry *zcrypt_entry;
-static inline int sprintcl(unsigned char *outaddr, unsigned char *addr,
- unsigned int len)
+static int sprintcl(unsigned char *outaddr, unsigned char *addr,
+ unsigned int len)
{
int hl, i;
@@ -845,8 +845,8 @@ static inline int sprintcl(unsigned char *outaddr, unsigned char *addr,
return hl;
}
-static inline int sprintrw(unsigned char *outaddr, unsigned char *addr,
- unsigned int len)
+static int sprintrw(unsigned char *outaddr, unsigned char *addr,
+ unsigned int len)
{
int hl, inl, c, cx;
@@ -865,8 +865,8 @@ static inline int sprintrw(unsigned char *outaddr, unsigned char *addr,
return hl;
}
-static inline int sprinthx(unsigned char *title, unsigned char *outaddr,
- unsigned char *addr, unsigned int len)
+static int sprinthx(unsigned char *title, unsigned char *outaddr,
+ unsigned char *addr, unsigned int len)
{
int hl, inl, r, rx;
@@ -885,8 +885,8 @@ static inline int sprinthx(unsigned char *title, unsigned char *outaddr,
return hl;
}
-static inline int sprinthx4(unsigned char *title, unsigned char *outaddr,
- unsigned int *array, unsigned int len)
+static int sprinthx4(unsigned char *title, unsigned char *outaddr,
+ unsigned int *array, unsigned int len)
{
int hl, r;
@@ -943,7 +943,7 @@ static int zcrypt_status_read(char *resp_buff, char **start, off_t offset,
zcrypt_qdepth_mask(workarea);
len += sprinthx("Waiting work element counts",
resp_buff+len, workarea, AP_DEVICES);
- zcrypt_perdev_reqcnt((unsigned int *) workarea);
+ zcrypt_perdev_reqcnt((int *) workarea);
len += sprinthx4("Per-device successfully completed request counts",
resp_buff+len,(unsigned int *) workarea, AP_DEVICES);
*eof = 1;
@@ -1063,7 +1063,6 @@ int __init zcrypt_api_init(void)
rc = -ENOMEM;
goto out_misc;
}
- zcrypt_entry->nlink = 1;
zcrypt_entry->data = NULL;
zcrypt_entry->read_proc = zcrypt_status_read;
zcrypt_entry->write_proc = zcrypt_status_write;
diff --git a/drivers/s390/crypto/zcrypt_pcica.c b/drivers/s390/crypto/zcrypt_pcica.c
index 32e37014345..818ffe05ac0 100644
--- a/drivers/s390/crypto/zcrypt_pcica.c
+++ b/drivers/s390/crypto/zcrypt_pcica.c
@@ -191,10 +191,10 @@ static int ICACRT_msg_to_type4CRT_msg(struct zcrypt_device *zdev,
*
* Returns 0 on success or -EFAULT.
*/
-static inline int convert_type84(struct zcrypt_device *zdev,
- struct ap_message *reply,
- char __user *outputdata,
- unsigned int outputdatalength)
+static int convert_type84(struct zcrypt_device *zdev,
+ struct ap_message *reply,
+ char __user *outputdata,
+ unsigned int outputdatalength)
{
struct type84_hdr *t84h = reply->message;
char *data;
diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c
index b7153c1e15c..252443b6bd1 100644
--- a/drivers/s390/crypto/zcrypt_pcixcc.c
+++ b/drivers/s390/crypto/zcrypt_pcixcc.c
@@ -709,7 +709,8 @@ out_free:
* PCIXCC/CEX2C device to the request distributor
* @xcRB: pointer to the send_cprb request buffer
*/
-long zcrypt_pcixcc_send_cprb(struct zcrypt_device *zdev, struct ica_xcRB *xcRB)
+static long zcrypt_pcixcc_send_cprb(struct zcrypt_device *zdev,
+ struct ica_xcRB *xcRB)
{
struct ap_message ap_msg;
struct response_type resp_type = {
diff --git a/drivers/s390/net/Kconfig b/drivers/s390/net/Kconfig
index 52625153a4f..f98fa465df0 100644
--- a/drivers/s390/net/Kconfig
+++ b/drivers/s390/net/Kconfig
@@ -22,13 +22,6 @@ config CTC
available. This option is also available as a module which will be
called ctc.ko. If you do not know what it is, it's safe to say "Y".
-config IUCV
- tristate "IUCV support (VM only)"
- help
- Select this option if you want to use inter-user communication
- under VM or VIF. If unsure, say "Y" to enable a fast communication
- link between VM guests.
-
config NETIUCV
tristate "IUCV network device support (VM only)"
depends on IUCV && NETDEVICES
diff --git a/drivers/s390/net/Makefile b/drivers/s390/net/Makefile
index 4777e36a922..bbe3ab2e93d 100644
--- a/drivers/s390/net/Makefile
+++ b/drivers/s390/net/Makefile
@@ -4,7 +4,6 @@
ctc-objs := ctcmain.o ctcdbug.o
-obj-$(CONFIG_IUCV) += iucv.o
obj-$(CONFIG_NETIUCV) += netiucv.o fsm.o
obj-$(CONFIG_SMSGIUCV) += smsgiucv.o
obj-$(CONFIG_CTC) += ctc.o fsm.o cu3088.o
diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c
index 95f4e105cb9..7809a79feec 100644
--- a/drivers/s390/net/claw.c
+++ b/drivers/s390/net/claw.c
@@ -121,7 +121,7 @@ MODULE_LICENSE("GPL");
#define DEBUG
#endif
- char debug_buffer[255];
+static char debug_buffer[255];
/**
* Debug Facility Stuff
*/
@@ -223,16 +223,14 @@ static void claw_timer ( struct chbk * p_ch );
/* Functions */
static int add_claw_reads(struct net_device *dev,
struct ccwbk* p_first, struct ccwbk* p_last);
-static void inline ccw_check_return_code (struct ccw_device *cdev,
- int return_code);
-static void inline ccw_check_unit_check (struct chbk * p_ch,
- unsigned char sense );
+static void ccw_check_return_code (struct ccw_device *cdev, int return_code);
+static void ccw_check_unit_check (struct chbk * p_ch, unsigned char sense );
static int find_link(struct net_device *dev, char *host_name, char *ws_name );
static int claw_hw_tx(struct sk_buff *skb, struct net_device *dev, long linkid);
static int init_ccw_bk(struct net_device *dev);
static void probe_error( struct ccwgroup_device *cgdev);
static struct net_device_stats *claw_stats(struct net_device *dev);
-static int inline pages_to_order_of_mag(int num_of_pages);
+static int pages_to_order_of_mag(int num_of_pages);
static struct sk_buff *claw_pack_skb(struct claw_privbk *privptr);
#ifdef DEBUG
static void dumpit (char *buf, int len);
@@ -1310,7 +1308,7 @@ claw_timer ( struct chbk * p_ch )
* of magnitude get_free_pages() has an upper order of 9 *
*--------------------------------------------------------------------*/
-static int inline
+static int
pages_to_order_of_mag(int num_of_pages)
{
int order_of_mag=1; /* assume 2 pages */
@@ -1482,7 +1480,7 @@ add_claw_reads(struct net_device *dev, struct ccwbk* p_first,
* *
*-------------------------------------------------------------------*/
-static void inline
+static void
ccw_check_return_code(struct ccw_device *cdev, int return_code)
{
#ifdef FUNCTRACE
@@ -1529,7 +1527,7 @@ ccw_check_return_code(struct ccw_device *cdev, int return_code)
* ccw_check_unit_check *
*--------------------------------------------------------------------*/
-static void inline
+static void
ccw_check_unit_check(struct chbk * p_ch, unsigned char sense )
{
struct net_device *dev = p_ch->ndev;
diff --git a/drivers/s390/net/ctcmain.c b/drivers/s390/net/ctcmain.c
index 03cc263fe0d..0d6d5fcc128 100644
--- a/drivers/s390/net/ctcmain.c
+++ b/drivers/s390/net/ctcmain.c
@@ -45,7 +45,6 @@
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/timer.h>
-#include <linux/sched.h>
#include <linux/bitops.h>
#include <linux/signal.h>
@@ -369,7 +368,7 @@ ctc_dump_skb(struct sk_buff *skb, int offset)
* @param ch The channel where this skb has been received.
* @param pskb The received skb.
*/
-static __inline__ void
+static void
ctc_unpack_skb(struct channel *ch, struct sk_buff *pskb)
{
struct net_device *dev = ch->netdev;
@@ -512,7 +511,7 @@ ctc_unpack_skb(struct channel *ch, struct sk_buff *pskb)
* @param ch The channel, the error belongs to.
* @param return_code The error code to inspect.
*/
-static void inline
+static void
ccw_check_return_code(struct channel *ch, int return_code, char *msg)
{
DBF_TEXT(trace, 5, __FUNCTION__);
@@ -547,7 +546,7 @@ ccw_check_return_code(struct channel *ch, int return_code, char *msg)
* @param ch The channel, the sense code belongs to.
* @param sense The sense code to inspect.
*/
-static void inline
+static void
ccw_unit_check(struct channel *ch, unsigned char sense)
{
DBF_TEXT(trace, 5, __FUNCTION__);
@@ -603,7 +602,7 @@ ctc_purge_skb_queue(struct sk_buff_head *q)
}
}
-static __inline__ int
+static int
ctc_checkalloc_buffer(struct channel *ch, int warn)
{
DBF_TEXT(trace, 5, __FUNCTION__);
diff --git a/drivers/s390/net/cu3088.c b/drivers/s390/net/cu3088.c
index e965f03a729..76728ae4b84 100644
--- a/drivers/s390/net/cu3088.c
+++ b/drivers/s390/net/cu3088.c
@@ -57,7 +57,7 @@ static struct ccw_device_id cu3088_ids[] = {
static struct ccw_driver cu3088_driver;
-struct device *cu3088_root_dev;
+static struct device *cu3088_root_dev;
static ssize_t
group_write(struct device_driver *drv, const char *buf, size_t count)
diff --git a/drivers/s390/net/iucv.c b/drivers/s390/net/iucv.c
deleted file mode 100644
index 229aeb5fc39..00000000000
--- a/drivers/s390/net/iucv.c
+++ /dev/null
@@ -1,2540 +0,0 @@
-/*
- * IUCV network driver
- *
- * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
- * Author(s):
- * Original source:
- * Alan Altmark (Alan_Altmark@us.ibm.com) Sept. 2000
- * Xenia Tkatschow (xenia@us.ibm.com)
- * 2Gb awareness and general cleanup:
- * Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com)
- *
- * Documentation used:
- * The original source
- * CP Programming Service, IBM document # SC24-5760
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-/* #define DEBUG */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-
-#include <linux/spinlock.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/errno.h>
-#include <linux/err.h>
-#include <linux/device.h>
-#include <asm/atomic.h>
-#include "iucv.h"
-#include <asm/io.h>
-#include <asm/s390_ext.h>
-#include <asm/ebcdic.h>
-#include <asm/smp.h>
-#include <asm/s390_rdev.h>
-
-/* FLAGS:
- * All flags are defined in the field IPFLAGS1 of each function
- * and can be found in CP Programming Services.
- * IPSRCCLS - Indicates you have specified a source class
- * IPFGMCL - Indicates you have specified a target class
- * IPFGPID - Indicates you have specified a pathid
- * IPFGMID - Indicates you have specified a message ID
- * IPANSLST - Indicates that you are using an address list for
- * reply data
- * IPBUFLST - Indicates that you are using an address list for
- * message data
- */
-
-#define IPSRCCLS 0x01
-#define IPFGMCL 0x01
-#define IPFGPID 0x02
-#define IPFGMID 0x04
-#define IPANSLST 0x08
-#define IPBUFLST 0x40
-
-static int
-iucv_bus_match (struct device *dev, struct device_driver *drv)
-{
- return 0;
-}
-
-struct bus_type iucv_bus = {
- .name = "iucv",
- .match = iucv_bus_match,
-};
-
-struct device *iucv_root;
-
-/* General IUCV interrupt structure */
-typedef struct {
- __u16 ippathid;
- __u8 res1;
- __u8 iptype;
- __u32 res2;
- __u8 ipvmid[8];
- __u8 res3[24];
-} iucv_GeneralInterrupt;
-
-static iucv_GeneralInterrupt *iucv_external_int_buffer = NULL;
-
-/* Spin Lock declaration */
-
-static DEFINE_SPINLOCK(iucv_lock);
-
-static int messagesDisabled = 0;
-
-/***************INTERRUPT HANDLING ***************/
-
-typedef struct {
- struct list_head queue;
- iucv_GeneralInterrupt data;
-} iucv_irqdata;
-
-static struct list_head iucv_irq_queue;
-static DEFINE_SPINLOCK(iucv_irq_queue_lock);
-
-/*
- *Internal function prototypes
- */
-static void iucv_tasklet_handler(unsigned long);
-static void iucv_irq_handler(__u16);
-
-static DECLARE_TASKLET(iucv_tasklet,iucv_tasklet_handler,0);
-
-/************ FUNCTION ID'S ****************************/
-
-#define ACCEPT 10
-#define CONNECT 11
-#define DECLARE_BUFFER 12
-#define PURGE 9
-#define QUERY 0
-#define QUIESCE 13
-#define RECEIVE 5
-#define REJECT 8
-#define REPLY 6
-#define RESUME 14
-#define RETRIEVE_BUFFER 2
-#define SEND 4
-#define SETMASK 16
-#define SEVER 15
-
-/**
- * Structure: handler
- * members: list - list management.
- * structure: id
- * userid - 8 char array of machine identification
- * user_data - 16 char array for user identification
- * mask - 24 char array used to compare the 2 previous
- * interrupt_table - vector of interrupt functions.
- * pgm_data - ulong, application data that is passed
- * to the interrupt handlers
-*/
-typedef struct handler_t {
- struct list_head list;
- struct {
- __u8 userid[8];
- __u8 user_data[16];
- __u8 mask[24];
- } id;
- iucv_interrupt_ops_t *interrupt_table;
- void *pgm_data;
-} handler;
-
-/**
- * iucv_handler_table: List of registered handlers.
- */
-static struct list_head iucv_handler_table;
-
-/**
- * iucv_pathid_table: an array of *handler pointing into
- * iucv_handler_table for fast indexing by pathid;
- */
-static handler **iucv_pathid_table;
-
-static unsigned long max_connections;
-
-/**
- * iucv_cpuid: contains the logical cpu number of the cpu which
- * has declared the iucv buffer by issuing DECLARE_BUFFER.
- * If no cpu has done the initialization iucv_cpuid contains -1.
- */
-static int iucv_cpuid = -1;
-/**
- * register_flag: is 0 when external interrupt has not been registered
- */
-static int register_flag;
-
-/****************FIVE 40-BYTE PARAMETER STRUCTURES******************/
-/* Data struct 1: iparml_control
- * Used for iucv_accept
- * iucv_connect
- * iucv_quiesce
- * iucv_resume
- * iucv_sever
- * iucv_retrieve_buffer
- * Data struct 2: iparml_dpl (data in parameter list)
- * Used for iucv_send_prmmsg
- * iucv_send2way_prmmsg
- * iucv_send2way_prmmsg_array
- * iucv_reply_prmmsg
- * Data struct 3: iparml_db (data in a buffer)
- * Used for iucv_receive
- * iucv_receive_array
- * iucv_reject
- * iucv_reply
- * iucv_reply_array
- * iucv_send
- * iucv_send_array
- * iucv_send2way
- * iucv_send2way_array
- * iucv_declare_buffer
- * Data struct 4: iparml_purge
- * Used for iucv_purge
- * iucv_query
- * Data struct 5: iparml_set_mask
- * Used for iucv_set_mask
- */
-
-typedef struct {
- __u16 ippathid;
- __u8 ipflags1;
- __u8 iprcode;
- __u16 ipmsglim;
- __u16 res1;
- __u8 ipvmid[8];
- __u8 ipuser[16];
- __u8 iptarget[8];
-} iparml_control;
-
-typedef struct {
- __u16 ippathid;
- __u8 ipflags1;
- __u8 iprcode;
- __u32 ipmsgid;
- __u32 iptrgcls;
- __u8 iprmmsg[8];
- __u32 ipsrccls;
- __u32 ipmsgtag;
- __u32 ipbfadr2;
- __u32 ipbfln2f;
- __u32 res;
-} iparml_dpl;
-
-typedef struct {
- __u16 ippathid;
- __u8 ipflags1;
- __u8 iprcode;
- __u32 ipmsgid;
- __u32 iptrgcls;
- __u32 ipbfadr1;
- __u32 ipbfln1f;
- __u32 ipsrccls;
- __u32 ipmsgtag;
- __u32 ipbfadr2;
- __u32 ipbfln2f;
- __u32 res;
-} iparml_db;
-
-typedef struct {
- __u16 ippathid;
- __u8 ipflags1;
- __u8 iprcode;
- __u32 ipmsgid;
- __u8 ipaudit[3];
- __u8 res1[5];
- __u32 res2;
- __u32 ipsrccls;
- __u32 ipmsgtag;
- __u32 res3[3];
-} iparml_purge;
-
-typedef struct {
- __u8 ipmask;
- __u8 res1[2];
- __u8 iprcode;
- __u32 res2[9];
-} iparml_set_mask;
-
-typedef struct {
- union {
- iparml_control p_ctrl;
- iparml_dpl p_dpl;
- iparml_db p_db;
- iparml_purge p_purge;
- iparml_set_mask p_set_mask;
- } param;
- atomic_t in_use;
- __u32 res;
-} __attribute__ ((aligned(8))) iucv_param;
-#define PARAM_POOL_SIZE (PAGE_SIZE / sizeof(iucv_param))
-
-static iucv_param * iucv_param_pool;
-
-MODULE_AUTHOR("(C) 2001 IBM Corp. by Fritz Elfert (felfert@millenux.com)");
-MODULE_DESCRIPTION("Linux for S/390 IUCV lowlevel driver");
-MODULE_LICENSE("GPL");
-
-/*
- * Debugging stuff
- *******************************************************************************/
-
-
-#ifdef DEBUG
-static int debuglevel = 0;
-
-module_param(debuglevel, int, 0);
-MODULE_PARM_DESC(debuglevel,
- "Specifies the debug level (0=off ... 3=all)");
-
-static void
-iucv_dumpit(char *title, void *buf, int len)
-{
- int i;
- __u8 *p = (__u8 *)buf;
-
- if (debuglevel < 3)
- return;
-
- printk(KERN_DEBUG "%s\n", title);
- printk(" ");
- for (i = 0; i < len; i++) {
- if (!(i % 16) && i != 0)
- printk ("\n ");
- else if (!(i % 4) && i != 0)
- printk(" ");
- printk("%02X", *p++);
- }
- if (len % 16)
- printk ("\n");
- return;
-}
-#define iucv_debug(lvl, fmt, args...) \
-do { \
- if (debuglevel >= lvl) \
- printk(KERN_DEBUG "%s: " fmt "\n", __FUNCTION__ , ## args); \
-} while (0)
-
-#else
-
-#define iucv_debug(lvl, fmt, args...) do { } while (0)
-#define iucv_dumpit(title, buf, len) do { } while (0)
-
-#endif
-
-/*
- * Internal functions
- *******************************************************************************/
-
-/**
- * print start banner
- */
-static void
-iucv_banner(void)
-{
- printk(KERN_INFO "IUCV lowlevel driver initialized\n");
-}
-
-/**
- * iucv_init - Initialization
- *
- * Allocates and initializes various data structures.
- */
-static int
-iucv_init(void)
-{
- int ret;
-
- if (iucv_external_int_buffer)
- return 0;
-
- if (!MACHINE_IS_VM) {
- printk(KERN_ERR "IUCV: IUCV connection needs VM as base\n");
- return -EPROTONOSUPPORT;
- }
-
- ret = bus_register(&iucv_bus);
- if (ret) {
- printk(KERN_ERR "IUCV: failed to register bus.\n");
- return ret;
- }
-
- iucv_root = s390_root_dev_register("iucv");
- if (IS_ERR(iucv_root)) {
- printk(KERN_ERR "IUCV: failed to register iucv root.\n");
- bus_unregister(&iucv_bus);
- return PTR_ERR(iucv_root);
- }
-
- /* Note: GFP_DMA used used to get memory below 2G */
- iucv_external_int_buffer = kzalloc(sizeof(iucv_GeneralInterrupt),
- GFP_KERNEL|GFP_DMA);
- if (!iucv_external_int_buffer) {
- printk(KERN_WARNING
- "%s: Could not allocate external interrupt buffer\n",
- __FUNCTION__);
- s390_root_dev_unregister(iucv_root);
- bus_unregister(&iucv_bus);
- return -ENOMEM;
- }
-
- /* Initialize parameter pool */
- iucv_param_pool = kzalloc(sizeof(iucv_param) * PARAM_POOL_SIZE,
- GFP_KERNEL|GFP_DMA);
- if (!iucv_param_pool) {
- printk(KERN_WARNING "%s: Could not allocate param pool\n",
- __FUNCTION__);
- kfree(iucv_external_int_buffer);
- iucv_external_int_buffer = NULL;
- s390_root_dev_unregister(iucv_root);
- bus_unregister(&iucv_bus);
- return -ENOMEM;
- }
-
- /* Initialize irq queue */
- INIT_LIST_HEAD(&iucv_irq_queue);
-
- /* Initialize handler table */
- INIT_LIST_HEAD(&iucv_handler_table);
-
- iucv_banner();
- return 0;
-}
-
-/**
- * iucv_exit - De-Initialization
- *
- * Frees everything allocated from iucv_init.
- */
-static int iucv_retrieve_buffer (void);
-
-static void
-iucv_exit(void)
-{
- iucv_retrieve_buffer();
- kfree(iucv_external_int_buffer);
- iucv_external_int_buffer = NULL;
- kfree(iucv_param_pool);
- iucv_param_pool = NULL;
- s390_root_dev_unregister(iucv_root);
- bus_unregister(&iucv_bus);
- printk(KERN_INFO "IUCV lowlevel driver unloaded\n");
-}
-
-/**
- * grab_param: - Get a parameter buffer from the pre-allocated pool.
- *
- * This function searches for an unused element in the pre-allocated pool
- * of parameter buffers. If one is found, it marks it "in use" and returns
- * a pointer to it. The calling function is responsible for releasing it
- * when it has finished its usage.
- *
- * Returns: A pointer to iucv_param.
- */
-static __inline__ iucv_param *
-grab_param(void)
-{
- iucv_param *ptr;
- static int hint = 0;
-
- ptr = iucv_param_pool + hint;
- do {
- ptr++;
- if (ptr >= iucv_param_pool + PARAM_POOL_SIZE)
- ptr = iucv_param_pool;
- } while (atomic_cmpxchg(&ptr->in_use, 0, 1) != 0);
- hint = ptr - iucv_param_pool;
-
- memset(&ptr->param, 0, sizeof(ptr->param));
- return ptr;
-}
-
-/**
- * release_param - Release a parameter buffer.
- * @p: A pointer to a struct iucv_param, previously obtained by calling
- * grab_param().
- *
- * This function marks the specified parameter buffer "unused".
- */
-static __inline__ void
-release_param(void *p)
-{
- atomic_set(&((iucv_param *)p)->in_use, 0);
-}
-
-/**
- * iucv_add_handler: - Add a new handler
- * @new_handler: handle that is being entered into chain.
- *
- * Places new handle on iucv_handler_table, if identical handler is not
- * found.
- *
- * Returns: 0 on success, !0 on failure (handler already in chain).
- */
-static int
-iucv_add_handler (handler *new)
-{
- ulong flags;
-
- iucv_debug(1, "entering");
- iucv_dumpit("handler:", new, sizeof(handler));
-
- spin_lock_irqsave (&iucv_lock, flags);
- if (!list_empty(&iucv_handler_table)) {
- struct list_head *lh;
-
- /**
- * Search list for handler with identical id. If one
- * is found, the new handler is _not_ added.
- */
- list_for_each(lh, &iucv_handler_table) {
- handler *h = list_entry(lh, handler, list);
- if (!memcmp(&new->id, &h->id, sizeof(h->id))) {
- iucv_debug(1, "ret 1");
- spin_unlock_irqrestore (&iucv_lock, flags);
- return 1;
- }
- }
- }
- /**
- * If we get here, no handler was found.
- */
- INIT_LIST_HEAD(&new->list);
- list_add(&new->list, &iucv_handler_table);
- spin_unlock_irqrestore (&iucv_lock, flags);
-
- iucv_debug(1, "exiting");
- return 0;
-}
-
-/**
- * b2f0:
- * @code: identifier of IUCV call to CP.
- * @parm: pointer to 40 byte iparml area passed to CP
- *
- * Calls CP to execute IUCV commands.
- *
- * Returns: return code from CP's IUCV call
- */
-static inline ulong b2f0(__u32 code, void *parm)
-{
- register unsigned long reg0 asm ("0");
- register unsigned long reg1 asm ("1");
- iucv_dumpit("iparml before b2f0 call:", parm, sizeof(iucv_param));
-
- reg0 = code;
- reg1 = virt_to_phys(parm);
- asm volatile(".long 0xb2f01000" : : "d" (reg0), "a" (reg1));
-
- iucv_dumpit("iparml after b2f0 call:", parm, sizeof(iucv_param));
-
- return (unsigned long)*((__u8 *)(parm + 3));
-}
-
-/*
- * Name: iucv_add_pathid
- * Purpose: Adds a path id to the system.
- * Input: pathid - pathid that is going to be entered into system
- * handle - address of handler that the pathid will be associated
- * with.
- * pgm_data - token passed in by application.
- * Output: 0: successful addition of pathid
- * - EINVAL - pathid entry is being used by another application
- * - ENOMEM - storage allocation for a new pathid table failed
-*/
-static int
-__iucv_add_pathid(__u16 pathid, handler *handler)
-{
-
- iucv_debug(1, "entering");
-
- iucv_debug(1, "handler is pointing to %p", handler);
-
- if (pathid > (max_connections - 1))
- return -EINVAL;
-
- if (iucv_pathid_table[pathid]) {
- iucv_debug(1, "pathid entry is %p", iucv_pathid_table[pathid]);
- printk(KERN_WARNING
- "%s: Pathid being used, error.\n", __FUNCTION__);
- return -EINVAL;
- }
- iucv_pathid_table[pathid] = handler;
-
- iucv_debug(1, "exiting");
- return 0;
-} /* end of add_pathid function */
-
-static int
-iucv_add_pathid(__u16 pathid, handler *handler)
-{
- ulong flags;
- int rc;
-
- spin_lock_irqsave (&iucv_lock, flags);
- rc = __iucv_add_pathid(pathid, handler);
- spin_unlock_irqrestore (&iucv_lock, flags);
- return rc;
-}
-
-static void
-iucv_remove_pathid(__u16 pathid)
-{
- ulong flags;
-
- if (pathid > (max_connections - 1))
- return;
-
- spin_lock_irqsave (&iucv_lock, flags);
- iucv_pathid_table[pathid] = NULL;
- spin_unlock_irqrestore (&iucv_lock, flags);
-}
-
-/**
- * iucv_declare_buffer_cpuid
- * Register at VM for subsequent IUCV operations. This is executed
- * on the reserved CPU iucv_cpuid. Called from iucv_declare_buffer().
- */
-static void
-iucv_declare_buffer_cpuid (void *result)
-{
- iparml_db *parm;
-
- parm = (iparml_db *)grab_param();
- parm->ipbfadr1 = virt_to_phys(iucv_external_int_buffer);
- if ((*((ulong *)result) = b2f0(DECLARE_BUFFER, parm)) == 1)
- *((ulong *)result) = parm->iprcode;
- release_param(parm);
-}
-
-/**
- * iucv_retrieve_buffer_cpuid:
- * Unregister IUCV usage at VM. This is always executed on the same
- * cpu that registered the buffer to VM.
- * Called from iucv_retrieve_buffer().
- */
-static void
-iucv_retrieve_buffer_cpuid (void *cpu)
-{
- iparml_control *parm;
-
- parm = (iparml_control *)grab_param();
- b2f0(RETRIEVE_BUFFER, parm);
- release_param(parm);
-}
-
-/**
- * Name: iucv_declare_buffer
- * Purpose: Specifies the guests real address of an external
- * interrupt.
- * Input: void
- * Output: iprcode - return code from b2f0 call
- */
-static int
-iucv_declare_buffer (void)
-{
- unsigned long flags;
- ulong b2f0_result;
-
- iucv_debug(1, "entering");
- b2f0_result = -ENODEV;
- spin_lock_irqsave (&iucv_lock, flags);
- if (iucv_cpuid == -1) {
- /* Reserve any cpu for use by iucv. */
- iucv_cpuid = smp_get_cpu(CPU_MASK_ALL);
- spin_unlock_irqrestore (&iucv_lock, flags);
- smp_call_function_on(iucv_declare_buffer_cpuid,
- &b2f0_result, 0, 1, iucv_cpuid);
- if (b2f0_result) {
- smp_put_cpu(iucv_cpuid);
- iucv_cpuid = -1;
- }
- iucv_debug(1, "Address of EIB = %p", iucv_external_int_buffer);
- } else {
- spin_unlock_irqrestore (&iucv_lock, flags);
- b2f0_result = 0;
- }
- iucv_debug(1, "exiting");
- return b2f0_result;
-}
-
-/**
- * iucv_retrieve_buffer:
- *
- * Terminates all use of IUCV.
- * Returns: return code from CP
- */
-static int
-iucv_retrieve_buffer (void)
-{
- iucv_debug(1, "entering");
- if (iucv_cpuid != -1) {
- smp_call_function_on(iucv_retrieve_buffer_cpuid,
- NULL, 0, 1, iucv_cpuid);
- /* Release the cpu reserved by iucv_declare_buffer. */
- smp_put_cpu(iucv_cpuid);
- iucv_cpuid = -1;
- }
- iucv_debug(1, "exiting");
- return 0;
-}
-
-/**
- * iucv_remove_handler:
- * @users_handler: handler to be removed
- *
- * Remove handler when application unregisters.
- */
-static void
-iucv_remove_handler(handler *handler)
-{
- unsigned long flags;
-
- if ((!iucv_pathid_table) || (!handler))
- return;
-
- iucv_debug(1, "entering");
-
- spin_lock_irqsave (&iucv_lock, flags);
- list_del(&handler->list);
- if (list_empty(&iucv_handler_table)) {
- if (register_flag) {
- unregister_external_interrupt(0x4000, iucv_irq_handler);
- register_flag = 0;
- }
- }
- spin_unlock_irqrestore (&iucv_lock, flags);
-
- iucv_debug(1, "exiting");
- return;
-}
-
-/**
- * iucv_register_program:
- * @pgmname: user identification
- * @userid: machine identification
- * @pgmmask: Indicates which bits in the pgmname and userid combined will be
- * used to determine who is given control.
- * @ops: Address of interrupt handler table.
- * @pgm_data: Application data to be passed to interrupt handlers.
- *
- * Registers an application with IUCV.
- * Returns:
- * The address of handler, or NULL on failure.
- * NOTE on pgmmask:
- * If pgmname, userid and pgmmask are provided, pgmmask is entered into the
- * handler as is.
- * If pgmmask is NULL, the internal mask is set to all 0xff's
- * When userid is NULL, the first 8 bytes of the internal mask are forced
- * to 0x00.
- * If pgmmask and userid are NULL, the first 8 bytes of the internal mask
- * are forced to 0x00 and the last 16 bytes to 0xff.
- */
-
-iucv_handle_t
-iucv_register_program (__u8 pgmname[16],
- __u8 userid[8],
- __u8 pgmmask[24],
- iucv_interrupt_ops_t * ops, void *pgm_data)
-{
- ulong rc = 0; /* return code from function calls */
- handler *new_handler;
-
- iucv_debug(1, "entering");
-
- if (ops == NULL) {
- /* interrupt table is not defined */
- printk(KERN_WARNING "%s: Interrupt table is not defined, "
- "exiting\n", __FUNCTION__);
- return NULL;
- }
- if (!pgmname) {
- printk(KERN_WARNING "%s: pgmname not provided\n", __FUNCTION__);
- return NULL;
- }
-
- /* Allocate handler entry */
- new_handler = kmalloc(sizeof(handler), GFP_ATOMIC);
- if (new_handler == NULL) {
- printk(KERN_WARNING "%s: storage allocation for new handler "
- "failed.\n", __FUNCTION__);
- return NULL;
- }
-
- if (!iucv_pathid_table) {
- if (iucv_init()) {
- kfree(new_handler);
- return NULL;
- }
-
- max_connections = iucv_query_maxconn();
- iucv_pathid_table = kcalloc(max_connections, sizeof(handler *),
- GFP_ATOMIC);
- if (iucv_pathid_table == NULL) {
- printk(KERN_WARNING "%s: iucv_pathid_table storage "
- "allocation failed\n", __FUNCTION__);
- kfree(new_handler);
- return NULL;
- }
- }
- memset(new_handler, 0, sizeof (handler));
- memcpy(new_handler->id.user_data, pgmname,
- sizeof (new_handler->id.user_data));
- if (userid) {
- memcpy (new_handler->id.userid, userid,
- sizeof (new_handler->id.userid));
- ASCEBC (new_handler->id.userid,
- sizeof (new_handler->id.userid));
- EBC_TOUPPER (new_handler->id.userid,
- sizeof (new_handler->id.userid));
-
- if (pgmmask) {
- memcpy (new_handler->id.mask, pgmmask,
- sizeof (new_handler->id.mask));
- } else {
- memset (new_handler->id.mask, 0xFF,
- sizeof (new_handler->id.mask));
- }
- } else {
- if (pgmmask) {
- memcpy (new_handler->id.mask, pgmmask,
- sizeof (new_handler->id.mask));
- } else {
- memset (new_handler->id.mask, 0xFF,
- sizeof (new_handler->id.mask));
- }
- memset (new_handler->id.userid, 0x00,
- sizeof (new_handler->id.userid));
- }
- /* fill in the rest of handler */
- new_handler->pgm_data = pgm_data;
- new_handler->interrupt_table = ops;
-
- /*
- * Check if someone else is registered with same pgmname, userid
- * and mask. If someone is already registered with same pgmname,
- * userid and mask, registration will fail and NULL will be returned
- * to the application.
- * If identical handler not found, then handler is added to list.
- */
- rc = iucv_add_handler(new_handler);
- if (rc) {
- printk(KERN_WARNING "%s: Someone already registered with same "
- "pgmname, userid, pgmmask\n", __FUNCTION__);
- kfree (new_handler);
- return NULL;
- }
-
- rc = iucv_declare_buffer();
- if (rc) {
- char *err = "Unknown";
- iucv_remove_handler(new_handler);
- kfree(new_handler);
- switch(rc) {
- case 0x03:
- err = "Directory error";
- break;
- case 0x0a:
- err = "Invalid length";
- break;
- case 0x13:
- err = "Buffer already exists";
- break;
- case 0x3e:
- err = "Buffer overlap";
- break;
- case 0x5c:
- err = "Paging or storage error";
- break;
- }
- printk(KERN_WARNING "%s: iucv_declare_buffer "
- "returned error 0x%02lx (%s)\n", __FUNCTION__, rc, err);
- return NULL;
- }
- if (!register_flag) {
- /* request the 0x4000 external interrupt */
- rc = register_external_interrupt (0x4000, iucv_irq_handler);
- if (rc) {
- iucv_remove_handler(new_handler);
- kfree (new_handler);
- printk(KERN_WARNING "%s: "
- "register_external_interrupt returned %ld\n",
- __FUNCTION__, rc);
- return NULL;
-
- }
- register_flag = 1;
- }
- iucv_debug(1, "exiting");
- return new_handler;
-} /* end of register function */
-
-/**
- * iucv_unregister_program:
- * @handle: address of handler
- *
- * Unregister application with IUCV.
- * Returns:
- * 0 on success, -EINVAL, if specified handle is invalid.
- */
-
-int
-iucv_unregister_program (iucv_handle_t handle)
-{
- handler *h = NULL;
- struct list_head *lh;
- int i;
- ulong flags;
-
- iucv_debug(1, "entering");
- iucv_debug(1, "address of handler is %p", h);
-
- /* Checking if handle is valid */
- spin_lock_irqsave (&iucv_lock, flags);
- list_for_each(lh, &iucv_handler_table) {
- if ((handler *)handle == list_entry(lh, handler, list)) {
- h = (handler *)handle;
- break;
- }
- }
- if (!h) {
- spin_unlock_irqrestore (&iucv_lock, flags);
- if (handle)
- printk(KERN_WARNING
- "%s: Handler not found in iucv_handler_table.\n",
- __FUNCTION__);
- else
- printk(KERN_WARNING
- "%s: NULL handle passed by application.\n",
- __FUNCTION__);
- return -EINVAL;
- }
-
- /**
- * First, walk thru iucv_pathid_table and sever any pathid which is
- * still pointing to the handler to be removed.
- */
- for (i = 0; i < max_connections; i++)
- if (iucv_pathid_table[i] == h) {
- spin_unlock_irqrestore (&iucv_lock, flags);
- iucv_sever(i, h->id.user_data);
- spin_lock_irqsave(&iucv_lock, flags);
- }
- spin_unlock_irqrestore (&iucv_lock, flags);
-
- iucv_remove_handler(h);
- kfree(h);
-
- iucv_debug(1, "exiting");
- return 0;
-}
-
-/**
- * iucv_accept:
- * @pathid: Path identification number
- * @msglim_reqstd: The number of outstanding messages requested.
- * @user_data: Data specified by the iucv_connect function.
- * @flags1: Contains options for this path.
- * - IPPRTY (0x20) Specifies if you want to send priority message.
- * - IPRMDATA (0x80) Specifies whether your program can handle a message
- * in the parameter list.
- * - IPQUSCE (0x40) Specifies whether you want to quiesce the path being
- * established.
- * @handle: Address of handler.
- * @pgm_data: Application data passed to interrupt handlers.
- * @flags1_out: Pointer to an int. If not NULL, on return the options for
- * the path are stored at the given location:
- * - IPPRTY (0x20) Indicates you may send a priority message.
- * @msglim: Pointer to an __u16. If not NULL, on return the maximum
- * number of outstanding messages is stored at the given
- * location.
- *
- * This function is issued after the user receives a Connection Pending external
- * interrupt and now wishes to complete the IUCV communication path.
- * Returns:
- * return code from CP
- */
-int
-iucv_accept(__u16 pathid, __u16 msglim_reqstd,
- __u8 user_data[16], int flags1,
- iucv_handle_t handle, void *pgm_data,
- int *flags1_out, __u16 * msglim)
-{
- ulong b2f0_result = 0;
- ulong flags;
- struct list_head *lh;
- handler *h = NULL;
- iparml_control *parm;
-
- iucv_debug(1, "entering");
- iucv_debug(1, "pathid = %d", pathid);
-
- /* Checking if handle is valid */
- spin_lock_irqsave (&iucv_lock, flags);
- list_for_each(lh, &iucv_handler_table) {
- if ((handler *)handle == list_entry(lh, handler, list)) {
- h = (handler *)handle;
- break;
- }
- }
- spin_unlock_irqrestore (&iucv_lock, flags);
-
- if (!h) {
- if (handle)
- printk(KERN_WARNING
- "%s: Handler not found in iucv_handler_table.\n",
- __FUNCTION__);
- else
- printk(KERN_WARNING
- "%s: NULL handle passed by application.\n",
- __FUNCTION__);
- return -EINVAL;
- }
-
- parm = (iparml_control *)grab_param();
-
- parm->ippathid = pathid;
- parm->ipmsglim = msglim_reqstd;
- if (user_data)
- memcpy(parm->ipuser, user_data, sizeof(parm->ipuser));
-
- parm->ipflags1 = (__u8)flags1;
- b2f0_result = b2f0(ACCEPT, parm);
-
- if (!b2f0_result) {
- if (msglim)
- *msglim = parm->ipmsglim;
- if (pgm_data)
- h->pgm_data = pgm_data;
- if (flags1_out)
- *flags1_out = (parm->ipflags1 & IPPRTY) ? IPPRTY : 0;
- }
- release_param(parm);
-
- iucv_debug(1, "exiting");
- return b2f0_result;
-}
-
-/**
- * iucv_connect:
- * @pathid: Path identification number
- * @msglim_reqstd: Number of outstanding messages requested
- * @user_data: 16-byte user data
- * @userid: 8-byte of user identification
- * @system_name: 8-byte identifying the system name
- * @flags1: Specifies options for this path:
- * - IPPRTY (0x20) Specifies if you want to send priority message.
- * - IPRMDATA (0x80) Specifies whether your program can handle a message
- * in the parameter list.
- * - IPQUSCE (0x40) Specifies whether you want to quiesce the path being
- * established.
- * - IPLOCAL (0x01) Allows an application to force the partner to be on the
- * local system. If local is specified then target class
- * cannot be specified.
- * @flags1_out: Pointer to an int. If not NULL, on return the options for
- * the path are stored at the given location:
- * - IPPRTY (0x20) Indicates you may send a priority message.
- * @msglim: Pointer to an __u16. If not NULL, on return the maximum
- * number of outstanding messages is stored at the given
- * location.
- * @handle: Address of handler.
- * @pgm_data: Application data to be passed to interrupt handlers.
- *
- * This function establishes an IUCV path. Although the connect may complete
- * successfully, you are not able to use the path until you receive an IUCV
- * Connection Complete external interrupt.
- * Returns: return code from CP, or one of the following
- * - ENOMEM
- * - return code from iucv_declare_buffer
- * - EINVAL - invalid handle passed by application
- * - EINVAL - pathid address is NULL
- * - ENOMEM - pathid table storage allocation failed
- * - return code from internal function add_pathid
- */
-int
-iucv_connect (__u16 *pathid, __u16 msglim_reqstd,
- __u8 user_data[16], __u8 userid[8],
- __u8 system_name[8], int flags1,
- int *flags1_out, __u16 * msglim,
- iucv_handle_t handle, void *pgm_data)
-{
- iparml_control *parm;
- iparml_control local_parm;
- struct list_head *lh;
- ulong b2f0_result = 0;
- ulong flags;
- int add_pathid_result = 0;
- handler *h = NULL;
- __u8 no_memory[16] = "NO MEMORY";
-
- iucv_debug(1, "entering");
-
- /* Checking if handle is valid */
- spin_lock_irqsave (&iucv_lock, flags);
- list_for_each(lh, &iucv_handler_table) {
- if ((handler *)handle == list_entry(lh, handler, list)) {
- h = (handler *)handle;
- break;
- }
- }
- spin_unlock_irqrestore (&iucv_lock, flags);
-
- if (!h) {
- if (handle)
- printk(KERN_WARNING
- "%s: Handler not found in iucv_handler_table.\n",
- __FUNCTION__);
- else
- printk(KERN_WARNING
- "%s: NULL handle passed by application.\n",
- __FUNCTION__);
- return -EINVAL;
- }
-
- if (pathid == NULL) {
- printk(KERN_WARNING "%s: NULL pathid pointer\n",
- __FUNCTION__);
- return -EINVAL;
- }
-
- parm = (iparml_control *)grab_param();
-
- parm->ipmsglim = msglim_reqstd;
-
- if (user_data)
- memcpy(parm->ipuser, user_data, sizeof(parm->ipuser));
-
- if (userid) {
- memcpy(parm->ipvmid, userid, sizeof(parm->ipvmid));
- ASCEBC(parm->ipvmid, sizeof(parm->ipvmid));
- EBC_TOUPPER(parm->ipvmid, sizeof(parm->ipvmid));
- }
-
- if (system_name) {
- memcpy(parm->iptarget, system_name, sizeof(parm->iptarget));
- ASCEBC(parm->iptarget, sizeof(parm->iptarget));
- EBC_TOUPPER(parm->iptarget, sizeof(parm->iptarget));
- }
-
- /* In order to establish an IUCV connection, the procedure is:
- *
- * b2f0(CONNECT)
- * take the ippathid from the b2f0 call
- * register the handler to the ippathid
- *
- * Unfortunately, the ConnectionEstablished message gets sent after the
- * b2f0(CONNECT) call but before the register is handled.
- *
- * In order for this race condition to be eliminated, the IUCV Control
- * Interrupts must be disabled for the above procedure.
- *
- * David Kennedy <dkennedy@linuxcare.com>
- */
-
- /* Enable everything but IUCV Control messages */
- iucv_setmask(~(AllInterrupts));
- messagesDisabled = 1;
-
- spin_lock_irqsave (&iucv_lock, flags);
- parm->ipflags1 = (__u8)flags1;
- b2f0_result = b2f0(CONNECT, parm);
- memcpy(&local_parm, parm, sizeof(local_parm));
- release_param(parm);
- parm = &local_parm;
- if (!b2f0_result)
- add_pathid_result = __iucv_add_pathid(parm->ippathid, h);
- spin_unlock_irqrestore (&iucv_lock, flags);
-
- if (b2f0_result) {
- iucv_setmask(~0);
- messagesDisabled = 0;
- return b2f0_result;
- }
-
- *pathid = parm->ippathid;
-
- /* Enable everything again */
- iucv_setmask(IUCVControlInterruptsFlag);
-
- if (msglim)
- *msglim = parm->ipmsglim;
- if (flags1_out)
- *flags1_out = (parm->ipflags1 & IPPRTY) ? IPPRTY : 0;
-
- if (add_pathid_result) {
- iucv_sever(*pathid, no_memory);
- printk(KERN_WARNING "%s: add_pathid failed with rc ="
- " %d\n", __FUNCTION__, add_pathid_result);
- return(add_pathid_result);
- }
-
- iucv_debug(1, "exiting");
- return b2f0_result;
-}
-
-/**
- * iucv_purge:
- * @pathid: Path identification number
- * @msgid: Message ID of message to purge.
- * @srccls: Message class of the message to purge.
- * @audit: Pointer to an __u32. If not NULL, on return, information about
- * asynchronous errors that may have affected the normal completion
- * of this message ist stored at the given location.
- *
- * Cancels a message you have sent.
- * Returns: return code from CP
- */
-int
-iucv_purge (__u16 pathid, __u32 msgid, __u32 srccls, __u32 *audit)
-{
- iparml_purge *parm;
- ulong b2f0_result = 0;
-
- iucv_debug(1, "entering");
- iucv_debug(1, "pathid = %d", pathid);
-
- parm = (iparml_purge *)grab_param();
-
- parm->ipmsgid = msgid;
- parm->ippathid = pathid;
- parm->ipsrccls = srccls;
- parm->ipflags1 |= (IPSRCCLS | IPFGMID | IPFGPID);
- b2f0_result = b2f0(PURGE, parm);
-
- if (!b2f0_result && audit) {
- memcpy(audit, parm->ipaudit, sizeof(parm->ipaudit));
- /* parm->ipaudit has only 3 bytes */
- *audit >>= 8;
- }
-
- release_param(parm);
-
- iucv_debug(1, "b2f0_result = %ld", b2f0_result);
- iucv_debug(1, "exiting");
- return b2f0_result;
-}
-
-/**
- * iucv_query_generic:
- * @want_maxconn: Flag, describing which value is to be returned.
- *
- * Helper function for iucv_query_maxconn() and iucv_query_bufsize().
- *
- * Returns: The buffersize, if want_maxconn is 0; the maximum number of
- * connections, if want_maxconn is 1 or an error-code < 0 on failure.
- */
-static int
-iucv_query_generic(int want_maxconn)
-{
- register unsigned long reg0 asm ("0");
- register unsigned long reg1 asm ("1");
- iparml_purge *parm = (iparml_purge *)grab_param();
- int bufsize, maxconn;
- int ccode;
-
- /**
- * Call b2f0 and store R0 (max buffer size),
- * R1 (max connections) and CC.
- */
- reg0 = QUERY;
- reg1 = virt_to_phys(parm);
- asm volatile(
- " .long 0xb2f01000\n"
- " ipm %0\n"
- " srl %0,28\n"
- : "=d" (ccode), "+d" (reg0), "+d" (reg1) : : "cc");
- bufsize = reg0;
- maxconn = reg1;
- release_param(parm);
-
- if (ccode)
- return -EPERM;
- if (want_maxconn)
- return maxconn;
- return bufsize;
-}
-
-/**
- * iucv_query_maxconn:
- *
- * Determines the maximum number of connections thay may be established.
- *
- * Returns: Maximum number of connections that can be.
- */
-ulong
-iucv_query_maxconn(void)
-{
- return iucv_query_generic(1);
-}
-
-/**
- * iucv_query_bufsize:
- *
- * Determines the size of the external interrupt buffer.
- *
- * Returns: Size of external interrupt buffer.
- */
-ulong
-iucv_query_bufsize (void)
-{
- return iucv_query_generic(0);
-}
-
-/**
- * iucv_quiesce:
- * @pathid: Path identification number
- * @user_data: 16-byte user data
- *
- * Temporarily suspends incoming messages on an IUCV path.
- * You can later reactivate the path by invoking the iucv_resume function.
- * Returns: return code from CP
- */
-int
-iucv_quiesce (__u16 pathid, __u8 user_data[16])
-{
- iparml_control *parm;
- ulong b2f0_result = 0;
-
- iucv_debug(1, "entering");
- iucv_debug(1, "pathid = %d", pathid);
-
- parm = (iparml_control *)grab_param();
-
- memcpy(parm->ipuser, user_data, sizeof(parm->ipuser));
- parm->ippathid = pathid;
-
- b2f0_result = b2f0(QUIESCE, parm);
- release_param(parm);
-
- iucv_debug(1, "b2f0_result = %ld", b2f0_result);
- iucv_debug(1, "exiting");
-
- return b2f0_result;
-}
-
-/**
- * iucv_receive:
- * @pathid: Path identification number.
- * @buffer: Address of buffer to receive. Must be below 2G.
- * @buflen: Length of buffer to receive.
- * @msgid: Specifies the message ID.
- * @trgcls: Specifies target class.
- * @flags1_out: Receives options for path on return.
- * - IPNORPY (0x10) Specifies whether a reply is required
- * - IPPRTY (0x20) Specifies if you want to send priority message
- * - IPRMDATA (0x80) Specifies the data is contained in the parameter list
- * @residual_buffer: Receives the address of buffer updated by the number
- * of bytes you have received on return.
- * @residual_length: On return, receives one of the following values:
- * - 0 If the receive buffer is the same length as
- * the message.
- * - Remaining bytes in buffer If the receive buffer is longer than the
- * message.
- * - Remaining bytes in message If the receive buffer is shorter than the
- * message.
- *
- * This function receives messages that are being sent to you over established
- * paths.
- * Returns: return code from CP IUCV call; If the receive buffer is shorter
- * than the message, always 5
- * -EINVAL - buffer address is pointing to NULL
- */
-int
-iucv_receive (__u16 pathid, __u32 msgid, __u32 trgcls,
- void *buffer, ulong buflen,
- int *flags1_out, ulong * residual_buffer, ulong * residual_length)
-{
- iparml_db *parm;
- ulong b2f0_result;
- int moved = 0; /* number of bytes moved from parmlist to buffer */
-
- iucv_debug(2, "entering");
-
- if (!buffer)
- return -EINVAL;
-
- parm = (iparml_db *)grab_param();
-
- parm->ipbfadr1 = (__u32) (addr_t) buffer;
- parm->ipbfln1f = (__u32) ((ulong) buflen);
- parm->ipmsgid = msgid;
- parm->ippathid = pathid;
- parm->iptrgcls = trgcls;
- parm->ipflags1 = (IPFGPID | IPFGMID | IPFGMCL);
-
- b2f0_result = b2f0(RECEIVE, parm);
-
- if (!b2f0_result || b2f0_result == 5) {
- if (flags1_out) {
- iucv_debug(2, "*flags1_out = %d", *flags1_out);
- *flags1_out = (parm->ipflags1 & (~0x07));
- iucv_debug(2, "*flags1_out = %d", *flags1_out);
- }
-
- if (!(parm->ipflags1 & IPRMDATA)) { /*msg not in parmlist */
- if (residual_length)
- *residual_length = parm->ipbfln1f;
-
- if (residual_buffer)
- *residual_buffer = parm->ipbfadr1;
- } else {
- moved = min_t (unsigned long, buflen, 8);
-
- memcpy ((char *) buffer,
- (char *) &parm->ipbfadr1, moved);
-
- if (buflen < 8)
- b2f0_result = 5;
-
- if (residual_length)
- *residual_length = abs (buflen - 8);
-
- if (residual_buffer)
- *residual_buffer = (ulong) (buffer + moved);
- }
- }
- release_param(parm);
-
- iucv_debug(2, "exiting");
- return b2f0_result;
-}
-
-/*
- * Name: iucv_receive_array
- * Purpose: This function receives messages that are being sent to you
- * over established paths.
- * Input: pathid - path identification number
- * buffer - address of array of buffers
- * buflen - total length of buffers
- * msgid - specifies the message ID.
- * trgcls - specifies target class
- * Output:
- * flags1_out: Options for path.
- * IPNORPY - 0x10 specifies whether a reply is required
- * IPPRTY - 0x20 specifies if you want to send priority message
- * IPRMDATA - 0x80 specifies the data is contained in the parameter list
- * residual_buffer - address points to the current list entry IUCV
- * is working on.
- * residual_length -
- * Contains one of the following values, if the receive buffer is:
- * The same length as the message, this field is zero.
- * Longer than the message, this field contains the number of
- * bytes remaining in the buffer.
- * Shorter than the message, this field contains the residual
- * count (that is, the number of bytes remaining in the
- * message that does not fit into the buffer. In this case
- * b2f0_result = 5.
- * Return: b2f0_result - return code from CP
- * (-EINVAL) - buffer address is NULL
- */
-int
-iucv_receive_array (__u16 pathid,
- __u32 msgid, __u32 trgcls,
- iucv_array_t * buffer, ulong buflen,
- int *flags1_out,
- ulong * residual_buffer, ulong * residual_length)
-{
- iparml_db *parm;
- ulong b2f0_result;
- int i = 0, moved = 0, need_to_move = 8, dyn_len;
-
- iucv_debug(2, "entering");
-
- if (!buffer)
- return -EINVAL;
-
- parm = (iparml_db *)grab_param();
-
- parm->ipbfadr1 = (__u32) ((ulong) buffer);
- parm->ipbfln1f = (__u32) buflen;
- parm->ipmsgid = msgid;
- parm->ippathid = pathid;
- parm->iptrgcls = trgcls;
- parm->ipflags1 = (IPBUFLST | IPFGPID | IPFGMID | IPFGMCL);
-
- b2f0_result = b2f0(RECEIVE, parm);
-
- if (!b2f0_result || b2f0_result == 5) {
-
- if (flags1_out) {
- iucv_debug(2, "*flags1_out = %d", *flags1_out);
- *flags1_out = (parm->ipflags1 & (~0x07));
- iucv_debug(2, "*flags1_out = %d", *flags1_out);
- }
-
- if (!(parm->ipflags1 & IPRMDATA)) { /*msg not in parmlist */
-
- if (residual_length)
- *residual_length = parm->ipbfln1f;
-
- if (residual_buffer)
- *residual_buffer = parm->ipbfadr1;
-
- } else {
- /* copy msg from parmlist to users array. */
-
- while ((moved < 8) && (moved < buflen)) {
- dyn_len =
- min_t (unsigned int,
- (buffer + i)->length, need_to_move);
-
- memcpy ((char *)((ulong)((buffer + i)->address)),
- ((char *) &parm->ipbfadr1) + moved,
- dyn_len);
-
- moved += dyn_len;
- need_to_move -= dyn_len;
-
- (buffer + i)->address =
- (__u32)
- ((ulong)(__u8 *) ((ulong)(buffer + i)->address)
- + dyn_len);
-
- (buffer + i)->length -= dyn_len;
- i++;
- }
-
- if (need_to_move) /* buflen < 8 bytes */
- b2f0_result = 5;
-
- if (residual_length)
- *residual_length = abs (buflen - 8);
-
- if (residual_buffer) {
- if (!moved)
- *residual_buffer = (ulong) buffer;
- else
- *residual_buffer =
- (ulong) (buffer + (i - 1));
- }
-
- }
- }
- release_param(parm);
-
- iucv_debug(2, "exiting");
- return b2f0_result;
-}
-
-/**
- * iucv_reject:
- * @pathid: Path identification number.
- * @msgid: Message ID of the message to reject.
- * @trgcls: Target class of the message to reject.
- * Returns: return code from CP
- *
- * Refuses a specified message. Between the time you are notified of a
- * message and the time that you complete the message, the message may
- * be rejected.
- */
-int
-iucv_reject (__u16 pathid, __u32 msgid, __u32 trgcls)
-{
- iparml_db *parm;
- ulong b2f0_result = 0;
-
- iucv_debug(1, "entering");
- iucv_debug(1, "pathid = %d", pathid);
-
- parm = (iparml_db *)grab_param();
-
- parm->ippathid = pathid;
- parm->ipmsgid = msgid;
- parm->iptrgcls = trgcls;
- parm->ipflags1 = (IPFGMCL | IPFGMID | IPFGPID);
-
- b2f0_result = b2f0(REJECT, parm);
- release_param(parm);
-
- iucv_debug(1, "b2f0_result = %ld", b2f0_result);
- iucv_debug(1, "exiting");
-
- return b2f0_result;
-}
-
-/*
- * Name: iucv_reply
- * Purpose: This function responds to the two-way messages that you
- * receive. You must identify completely the message to
- * which you wish to reply. ie, pathid, msgid, and trgcls.
- * Input: pathid - path identification number
- * msgid - specifies the message ID.
- * trgcls - specifies target class
- * flags1 - option for path
- * IPPRTY- 0x20 - specifies if you want to send priority message
- * buffer - address of reply buffer
- * buflen - length of reply buffer
- * Output: ipbfadr2 - Address of buffer updated by the number
- * of bytes you have moved.
- * ipbfln2f - Contains one of the following values:
- * If the answer buffer is the same length as the reply, this field
- * contains zero.
- * If the answer buffer is longer than the reply, this field contains
- * the number of bytes remaining in the buffer.
- * If the answer buffer is shorter than the reply, this field contains
- * a residual count (that is, the number of bytes remianing in the
- * reply that does not fit into the buffer. In this
- * case b2f0_result = 5.
- * Return: b2f0_result - return code from CP
- * (-EINVAL) - buffer address is NULL
- */
-int
-iucv_reply (__u16 pathid,
- __u32 msgid, __u32 trgcls,
- int flags1,
- void *buffer, ulong buflen, ulong * ipbfadr2, ulong * ipbfln2f)
-{
- iparml_db *parm;
- ulong b2f0_result;
-
- iucv_debug(2, "entering");
-
- if (!buffer)
- return -EINVAL;
-
- parm = (iparml_db *)grab_param();
-
- parm->ipbfadr2 = (__u32) ((ulong) buffer);
- parm->ipbfln2f = (__u32) buflen; /* length of message */
- parm->ippathid = pathid;
- parm->ipmsgid = msgid;
- parm->iptrgcls = trgcls;
- parm->ipflags1 = (__u8) flags1; /* priority message */
-
- b2f0_result = b2f0(REPLY, parm);
-
- if ((!b2f0_result) || (b2f0_result == 5)) {
- if (ipbfadr2)
- *ipbfadr2 = parm->ipbfadr2;
- if (ipbfln2f)
- *ipbfln2f = parm->ipbfln2f;
- }
- release_param(parm);
-
- iucv_debug(2, "exiting");
-
- return b2f0_result;
-}
-
-/*
- * Name: iucv_reply_array
- * Purpose: This function responds to the two-way messages that you
- * receive. You must identify completely the message to
- * which you wish to reply. ie, pathid, msgid, and trgcls.
- * The array identifies a list of addresses and lengths of
- * discontiguous buffers that contains the reply data.
- * Input: pathid - path identification number
- * msgid - specifies the message ID.
- * trgcls - specifies target class
- * flags1 - option for path
- * IPPRTY- specifies if you want to send priority message
- * buffer - address of array of reply buffers
- * buflen - total length of reply buffers
- * Output: ipbfadr2 - Address of buffer which IUCV is currently working on.
- * ipbfln2f - Contains one of the following values:
- * If the answer buffer is the same length as the reply, this field
- * contains zero.
- * If the answer buffer is longer than the reply, this field contains
- * the number of bytes remaining in the buffer.
- * If the answer buffer is shorter than the reply, this field contains
- * a residual count (that is, the number of bytes remianing in the
- * reply that does not fit into the buffer. In this
- * case b2f0_result = 5.
- * Return: b2f0_result - return code from CP
- * (-EINVAL) - buffer address is NULL
-*/
-int
-iucv_reply_array (__u16 pathid,
- __u32 msgid, __u32 trgcls,
- int flags1,
- iucv_array_t * buffer,
- ulong buflen, ulong * ipbfadr2, ulong * ipbfln2f)
-{
- iparml_db *parm;
- ulong b2f0_result;
-
- iucv_debug(2, "entering");
-
- if (!buffer)
- return -EINVAL;
-
- parm = (iparml_db *)grab_param();
-
- parm->ipbfadr2 = (__u32) ((ulong) buffer);
- parm->ipbfln2f = buflen; /* length of message */
- parm->ippathid = pathid;
- parm->ipmsgid = msgid;
- parm->iptrgcls = trgcls;
- parm->ipflags1 = (IPANSLST | flags1);
-
- b2f0_result = b2f0(REPLY, parm);
-
- if ((!b2f0_result) || (b2f0_result == 5)) {
-
- if (ipbfadr2)
- *ipbfadr2 = parm->ipbfadr2;
- if (ipbfln2f)
- *ipbfln2f = parm->ipbfln2f;
- }
- release_param(parm);
-
- iucv_debug(2, "exiting");
-
- return b2f0_result;
-}
-
-/*
- * Name: iucv_reply_prmmsg
- * Purpose: This function responds to the two-way messages that you
- * receive. You must identify completely the message to
- * which you wish to reply. ie, pathid, msgid, and trgcls.
- * Prmmsg signifies the data is moved into the
- * parameter list.
- * Input: pathid - path identification number
- * msgid - specifies the message ID.
- * trgcls - specifies target class
- * flags1 - option for path
- * IPPRTY- specifies if you want to send priority message
- * prmmsg - 8-bytes of data to be placed into the parameter
- * list.
- * Output: NA
- * Return: b2f0_result - return code from CP
-*/
-int
-iucv_reply_prmmsg (__u16 pathid,
- __u32 msgid, __u32 trgcls, int flags1, __u8 prmmsg[8])
-{
- iparml_dpl *parm;
- ulong b2f0_result;
-
- iucv_debug(2, "entering");
-
- parm = (iparml_dpl *)grab_param();
-
- parm->ippathid = pathid;
- parm->ipmsgid = msgid;
- parm->iptrgcls = trgcls;
- memcpy(parm->iprmmsg, prmmsg, sizeof (parm->iprmmsg));
- parm->ipflags1 = (IPRMDATA | flags1);
-
- b2f0_result = b2f0(REPLY, parm);
- release_param(parm);
-
- iucv_debug(2, "exiting");
-
- return b2f0_result;
-}
-
-/**
- * iucv_resume:
- * @pathid: Path identification number
- * @user_data: 16-byte of user data
- *
- * This function restores communication over a quiesced path.
- * Returns: return code from CP
- */
-int
-iucv_resume (__u16 pathid, __u8 user_data[16])
-{
- iparml_control *parm;
- ulong b2f0_result = 0;
-
- iucv_debug(1, "entering");
- iucv_debug(1, "pathid = %d", pathid);
-
- parm = (iparml_control *)grab_param();
-
- memcpy (parm->ipuser, user_data, sizeof (*user_data));
- parm->ippathid = pathid;
-
- b2f0_result = b2f0(RESUME, parm);
- release_param(parm);
-
- iucv_debug(1, "exiting");
-
- return b2f0_result;
-}
-
-/*
- * Name: iucv_send
- * Purpose: sends messages
- * Input: pathid - ushort, pathid
- * msgid - ulong *, id of message returned to caller
- * trgcls - ulong, target message class
- * srccls - ulong, source message class
- * msgtag - ulong, message tag
- * flags1 - Contains options for this path.
- * IPPRTY - Ox20 - specifies if you want to send a priority message.
- * buffer - pointer to buffer
- * buflen - ulong, length of buffer
- * Output: b2f0_result - return code from b2f0 call
- * msgid - returns message id
- */
-int
-iucv_send (__u16 pathid, __u32 * msgid,
- __u32 trgcls, __u32 srccls,
- __u32 msgtag, int flags1, void *buffer, ulong buflen)
-{
- iparml_db *parm;
- ulong b2f0_result;
-
- iucv_debug(2, "entering");
-
- if (!buffer)
- return -EINVAL;
-
- parm = (iparml_db *)grab_param();
-
- parm->ipbfadr1 = (__u32) ((ulong) buffer);
- parm->ippathid = pathid;
- parm->iptrgcls = trgcls;
- parm->ipbfln1f = (__u32) buflen; /* length of message */
- parm->ipsrccls = srccls;
- parm->ipmsgtag = msgtag;
- parm->ipflags1 = (IPNORPY | flags1); /* one way priority message */
-
- b2f0_result = b2f0(SEND, parm);
-
- if ((!b2f0_result) && (msgid))
- *msgid = parm->ipmsgid;
- release_param(parm);
-
- iucv_debug(2, "exiting");
-
- return b2f0_result;
-}
-
-/*
- * Name: iucv_send_array
- * Purpose: This function transmits data to another application.
- * The contents of buffer is the address of the array of
- * addresses and lengths of discontiguous buffers that hold
- * the message text. This is a one-way message and the
- * receiver will not reply to the message.
- * Input: pathid - path identification number
- * trgcls - specifies target class
- * srccls - specifies the source message class
- * msgtag - specifies a tag to be associated witht the message
- * flags1 - option for path
- * IPPRTY- specifies if you want to send priority message
- * buffer - address of array of send buffers
- * buflen - total length of send buffers
- * Output: msgid - specifies the message ID.
- * Return: b2f0_result - return code from CP
- * (-EINVAL) - buffer address is NULL
- */
-int
-iucv_send_array (__u16 pathid,
- __u32 * msgid,
- __u32 trgcls,
- __u32 srccls,
- __u32 msgtag, int flags1, iucv_array_t * buffer, ulong buflen)
-{
- iparml_db *parm;
- ulong b2f0_result;
-
- iucv_debug(2, "entering");
-
- if (!buffer)
- return -EINVAL;
-
- parm = (iparml_db *)grab_param();
-
- parm->ippathid = pathid;
- parm->iptrgcls = trgcls;
- parm->ipbfadr1 = (__u32) ((ulong) buffer);
- parm->ipbfln1f = (__u32) buflen; /* length of message */
- parm->ipsrccls = srccls;
- parm->ipmsgtag = msgtag;
- parm->ipflags1 = (IPNORPY | IPBUFLST | flags1);
- b2f0_result = b2f0(SEND, parm);
-
- if ((!b2f0_result) && (msgid))
- *msgid = parm->ipmsgid;
- release_param(parm);
-
- iucv_debug(2, "exiting");
- return b2f0_result;
-}
-
-/*
- * Name: iucv_send_prmmsg
- * Purpose: This function transmits data to another application.
- * Prmmsg specifies that the 8-bytes of data are to be moved
- * into the parameter list. This is a one-way message and the
- * receiver will not reply to the message.
- * Input: pathid - path identification number
- * trgcls - specifies target class
- * srccls - specifies the source message class
- * msgtag - specifies a tag to be associated with the message
- * flags1 - option for path
- * IPPRTY- specifies if you want to send priority message
- * prmmsg - 8-bytes of data to be placed into parameter list
- * Output: msgid - specifies the message ID.
- * Return: b2f0_result - return code from CP
-*/
-int
-iucv_send_prmmsg (__u16 pathid,
- __u32 * msgid,
- __u32 trgcls,
- __u32 srccls, __u32 msgtag, int flags1, __u8 prmmsg[8])
-{
- iparml_dpl *parm;
- ulong b2f0_result;
-
- iucv_debug(2, "entering");
-
- parm = (iparml_dpl *)grab_param();
-
- parm->ippathid = pathid;
- parm->iptrgcls = trgcls;
- parm->ipsrccls = srccls;
- parm->ipmsgtag = msgtag;
- parm->ipflags1 = (IPRMDATA | IPNORPY | flags1);
- memcpy(parm->iprmmsg, prmmsg, sizeof(parm->iprmmsg));
-
- b2f0_result = b2f0(SEND, parm);
-
- if ((!b2f0_result) && (msgid))
- *msgid = parm->ipmsgid;
- release_param(parm);
-
- iucv_debug(2, "exiting");
-
- return b2f0_result;
-}
-
-/*
- * Name: iucv_send2way
- * Purpose: This function transmits data to another application.
- * Data to be transmitted is in a buffer. The receiver
- * of the send is expected to reply to the message and
- * a buffer is provided into which IUCV moves the reply
- * to this message.
- * Input: pathid - path identification number
- * trgcls - specifies target class
- * srccls - specifies the source message class
- * msgtag - specifies a tag associated with the message
- * flags1 - option for path
- * IPPRTY- specifies if you want to send priority message
- * buffer - address of send buffer
- * buflen - length of send buffer
- * ansbuf - address of buffer to reply with
- * anslen - length of buffer to reply with
- * Output: msgid - specifies the message ID.
- * Return: b2f0_result - return code from CP
- * (-EINVAL) - buffer or ansbuf address is NULL
- */
-int
-iucv_send2way (__u16 pathid,
- __u32 * msgid,
- __u32 trgcls,
- __u32 srccls,
- __u32 msgtag,
- int flags1,
- void *buffer, ulong buflen, void *ansbuf, ulong anslen)
-{
- iparml_db *parm;
- ulong b2f0_result;
-
- iucv_debug(2, "entering");
-
- if (!buffer || !ansbuf)
- return -EINVAL;
-
- parm = (iparml_db *)grab_param();
-
- parm->ippathid = pathid;
- parm->iptrgcls = trgcls;
- parm->ipbfadr1 = (__u32) ((ulong) buffer);
- parm->ipbfln1f = (__u32) buflen; /* length of message */
- parm->ipbfadr2 = (__u32) ((ulong) ansbuf);
- parm->ipbfln2f = (__u32) anslen;
- parm->ipsrccls = srccls;
- parm->ipmsgtag = msgtag;
- parm->ipflags1 = flags1; /* priority message */
-
- b2f0_result = b2f0(SEND, parm);
-
- if ((!b2f0_result) && (msgid))
- *msgid = parm->ipmsgid;
- release_param(parm);
-
- iucv_debug(2, "exiting");
-
- return b2f0_result;
-}
-
-/*
- * Name: iucv_send2way_array
- * Purpose: This function transmits data to another application.
- * The contents of buffer is the address of the array of
- * addresses and lengths of discontiguous buffers that hold
- * the message text. The receiver of the send is expected to
- * reply to the message and a buffer is provided into which
- * IUCV moves the reply to this message.
- * Input: pathid - path identification number
- * trgcls - specifies target class
- * srccls - specifies the source message class
- * msgtag - spcifies a tag to be associated with the message
- * flags1 - option for path
- * IPPRTY- specifies if you want to send priority message
- * buffer - address of array of send buffers
- * buflen - total length of send buffers
- * ansbuf - address of buffer to reply with
- * anslen - length of buffer to reply with
- * Output: msgid - specifies the message ID.
- * Return: b2f0_result - return code from CP
- * (-EINVAL) - buffer address is NULL
- */
-int
-iucv_send2way_array (__u16 pathid,
- __u32 * msgid,
- __u32 trgcls,
- __u32 srccls,
- __u32 msgtag,
- int flags1,
- iucv_array_t * buffer,
- ulong buflen, iucv_array_t * ansbuf, ulong anslen)
-{
- iparml_db *parm;
- ulong b2f0_result;
-
- iucv_debug(2, "entering");
-
- if (!buffer || !ansbuf)
- return -EINVAL;
-
- parm = (iparml_db *)grab_param();
-
- parm->ippathid = pathid;
- parm->iptrgcls = trgcls;
- parm->ipbfadr1 = (__u32) ((ulong) buffer);
- parm->ipbfln1f = (__u32) buflen; /* length of message */
- parm->ipbfadr2 = (__u32) ((ulong) ansbuf);
- parm->ipbfln2f = (__u32) anslen;
- parm->ipsrccls = srccls;
- parm->ipmsgtag = msgtag;
- parm->ipflags1 = (IPBUFLST | IPANSLST | flags1);
- b2f0_result = b2f0(SEND, parm);
- if ((!b2f0_result) && (msgid))
- *msgid = parm->ipmsgid;
- release_param(parm);
-
- iucv_debug(2, "exiting");
- return b2f0_result;
-}
-
-/*
- * Name: iucv_send2way_prmmsg
- * Purpose: This function transmits data to another application.
- * Prmmsg specifies that the 8-bytes of data are to be moved
- * into the parameter list. This is a two-way message and the
- * receiver of the message is expected to reply. A buffer
- * is provided into which IUCV moves the reply to this
- * message.
- * Input: pathid - path identification number
- * trgcls - specifies target class
- * srccls - specifies the source message class
- * msgtag - specifies a tag to be associated with the message
- * flags1 - option for path
- * IPPRTY- specifies if you want to send priority message
- * prmmsg - 8-bytes of data to be placed in parameter list
- * ansbuf - address of buffer to reply with
- * anslen - length of buffer to reply with
- * Output: msgid - specifies the message ID.
- * Return: b2f0_result - return code from CP
- * (-EINVAL) - buffer address is NULL
-*/
-int
-iucv_send2way_prmmsg (__u16 pathid,
- __u32 * msgid,
- __u32 trgcls,
- __u32 srccls,
- __u32 msgtag,
- ulong flags1, __u8 prmmsg[8], void *ansbuf, ulong anslen)
-{
- iparml_dpl *parm;
- ulong b2f0_result;
-
- iucv_debug(2, "entering");
-
- if (!ansbuf)
- return -EINVAL;
-
- parm = (iparml_dpl *)grab_param();
-
- parm->ippathid = pathid;
- parm->iptrgcls = trgcls;
- parm->ipsrccls = srccls;
- parm->ipmsgtag = msgtag;
- parm->ipbfadr2 = (__u32) ((ulong) ansbuf);
- parm->ipbfln2f = (__u32) anslen;
- parm->ipflags1 = (IPRMDATA | flags1); /* message in prmlist */
- memcpy(parm->iprmmsg, prmmsg, sizeof(parm->iprmmsg));
-
- b2f0_result = b2f0(SEND, parm);
-
- if ((!b2f0_result) && (msgid))
- *msgid = parm->ipmsgid;
- release_param(parm);
-
- iucv_debug(2, "exiting");
-
- return b2f0_result;
-}
-
-/*
- * Name: iucv_send2way_prmmsg_array
- * Purpose: This function transmits data to another application.
- * Prmmsg specifies that the 8-bytes of data are to be moved
- * into the parameter list. This is a two-way message and the
- * receiver of the message is expected to reply. A buffer
- * is provided into which IUCV moves the reply to this
- * message. The contents of ansbuf is the address of the
- * array of addresses and lengths of discontiguous buffers
- * that contain the reply.
- * Input: pathid - path identification number
- * trgcls - specifies target class
- * srccls - specifies the source message class
- * msgtag - specifies a tag to be associated with the message
- * flags1 - option for path
- * IPPRTY- specifies if you want to send priority message
- * prmmsg - 8-bytes of data to be placed into the parameter list
- * ansbuf - address of buffer to reply with
- * anslen - length of buffer to reply with
- * Output: msgid - specifies the message ID.
- * Return: b2f0_result - return code from CP
- * (-EINVAL) - ansbuf address is NULL
- */
-int
-iucv_send2way_prmmsg_array (__u16 pathid,
- __u32 * msgid,
- __u32 trgcls,
- __u32 srccls,
- __u32 msgtag,
- int flags1,
- __u8 prmmsg[8],
- iucv_array_t * ansbuf, ulong anslen)
-{
- iparml_dpl *parm;
- ulong b2f0_result;
-
- iucv_debug(2, "entering");
-
- if (!ansbuf)
- return -EINVAL;
-
- parm = (iparml_dpl *)grab_param();
-
- parm->ippathid = pathid;
- parm->iptrgcls = trgcls;
- parm->ipsrccls = srccls;
- parm->ipmsgtag = msgtag;
- parm->ipbfadr2 = (__u32) ((ulong) ansbuf);
- parm->ipbfln2f = (__u32) anslen;
- parm->ipflags1 = (IPRMDATA | IPANSLST | flags1);
- memcpy(parm->iprmmsg, prmmsg, sizeof(parm->iprmmsg));
- b2f0_result = b2f0(SEND, parm);
- if ((!b2f0_result) && (msgid))
- *msgid = parm->ipmsgid;
- release_param(parm);
-
- iucv_debug(2, "exiting");
- return b2f0_result;
-}
-
-void
-iucv_setmask_cpuid (void *result)
-{
- iparml_set_mask *parm;
-
- iucv_debug(1, "entering");
- parm = (iparml_set_mask *)grab_param();
- parm->ipmask = *((__u8*)result);
- *((ulong *)result) = b2f0(SETMASK, parm);
- release_param(parm);
-
- iucv_debug(1, "b2f0_result = %ld", *((ulong *)result));
- iucv_debug(1, "exiting");
-}
-
-/*
- * Name: iucv_setmask
- * Purpose: This function enables or disables the following IUCV
- * external interruptions: Nonpriority and priority message
- * interrupts, nonpriority and priority reply interrupts.
- * Input: SetMaskFlag - options for interrupts
- * 0x80 - Nonpriority_MessagePendingInterruptsFlag
- * 0x40 - Priority_MessagePendingInterruptsFlag
- * 0x20 - Nonpriority_MessageCompletionInterruptsFlag
- * 0x10 - Priority_MessageCompletionInterruptsFlag
- * 0x08 - IUCVControlInterruptsFlag
- * Output: NA
- * Return: b2f0_result - return code from CP
-*/
-int
-iucv_setmask (int SetMaskFlag)
-{
- union {
- ulong result;
- __u8 param;
- } u;
- int cpu;
-
- u.param = SetMaskFlag;
- cpu = get_cpu();
- smp_call_function_on(iucv_setmask_cpuid, &u, 0, 1, iucv_cpuid);
- put_cpu();
-
- return u.result;
-}
-
-/**
- * iucv_sever:
- * @pathid: Path identification number
- * @user_data: 16-byte of user data
- *
- * This function terminates an iucv path.
- * Returns: return code from CP
- */
-int
-iucv_sever(__u16 pathid, __u8 user_data[16])
-{
- iparml_control *parm;
- ulong b2f0_result = 0;
-
- iucv_debug(1, "entering");
- parm = (iparml_control *)grab_param();
-
- memcpy(parm->ipuser, user_data, sizeof(parm->ipuser));
- parm->ippathid = pathid;
-
- b2f0_result = b2f0(SEVER, parm);
-
- if (!b2f0_result)
- iucv_remove_pathid(pathid);
- release_param(parm);
-
- iucv_debug(1, "exiting");
- return b2f0_result;
-}
-
-/*
- * Interrupt Handlers
- *******************************************************************************/
-
-/**
- * iucv_irq_handler:
- * @regs: Current registers
- * @code: irq code
- *
- * Handles external interrupts coming in from CP.
- * Places the interrupt buffer on a queue and schedules iucv_tasklet_handler().
- */
-static void
-iucv_irq_handler(__u16 code)
-{
- iucv_irqdata *irqdata;
-
- irqdata = kmalloc(sizeof(iucv_irqdata), GFP_ATOMIC);
- if (!irqdata) {
- printk(KERN_WARNING "%s: out of memory\n", __FUNCTION__);
- return;
- }
-
- memcpy(&irqdata->data, iucv_external_int_buffer,
- sizeof(iucv_GeneralInterrupt));
-
- spin_lock(&iucv_irq_queue_lock);
- list_add_tail(&irqdata->queue, &iucv_irq_queue);
- spin_unlock(&iucv_irq_queue_lock);
-
- tasklet_schedule(&iucv_tasklet);
-}
-
-/**
- * iucv_do_int:
- * @int_buf: Pointer to copy of external interrupt buffer
- *
- * The workhorse for handling interrupts queued by iucv_irq_handler().
- * This function is called from the bottom half iucv_tasklet_handler().
- */
-static void
-iucv_do_int(iucv_GeneralInterrupt * int_buf)
-{
- handler *h = NULL;
- struct list_head *lh;
- ulong flags;
- iucv_interrupt_ops_t *interrupt = NULL; /* interrupt addresses */
- __u8 temp_buff1[24], temp_buff2[24]; /* masked handler id. */
- int rc = 0, j = 0;
- __u8 no_listener[16] = "NO LISTENER";
-
- iucv_debug(2, "entering, pathid %d, type %02X",
- int_buf->ippathid, int_buf->iptype);
- iucv_dumpit("External Interrupt Buffer:",
- int_buf, sizeof(iucv_GeneralInterrupt));
-
- ASCEBC (no_listener, 16);
-
- if (int_buf->iptype != 01) {
- if ((int_buf->ippathid) > (max_connections - 1)) {
- printk(KERN_WARNING "%s: Got interrupt with pathid %d"
- " > max_connections (%ld)\n", __FUNCTION__,
- int_buf->ippathid, max_connections - 1);
- } else {
- h = iucv_pathid_table[int_buf->ippathid];
- interrupt = h->interrupt_table;
- iucv_dumpit("Handler:", h, sizeof(handler));
- }
- }
-
- /* end of if statement */
- switch (int_buf->iptype) {
- case 0x01: /* connection pending */
- if (messagesDisabled) {
- iucv_setmask(~0);
- messagesDisabled = 0;
- }
- spin_lock_irqsave(&iucv_lock, flags);
- list_for_each(lh, &iucv_handler_table) {
- h = list_entry(lh, handler, list);
- memcpy(temp_buff1, &(int_buf->ipvmid), 24);
- memcpy(temp_buff2, &(h->id.userid), 24);
- for (j = 0; j < 24; j++) {
- temp_buff1[j] &= (h->id.mask)[j];
- temp_buff2[j] &= (h->id.mask)[j];
- }
-
- iucv_dumpit("temp_buff1:",
- temp_buff1, sizeof(temp_buff1));
- iucv_dumpit("temp_buff2",
- temp_buff2, sizeof(temp_buff2));
-
- if (!memcmp (temp_buff1, temp_buff2, 24)) {
-
- iucv_debug(2,
- "found a matching handler");
- break;
- } else
- h = NULL;
- }
- spin_unlock_irqrestore (&iucv_lock, flags);
- if (h) {
- /* ADD PATH TO PATHID TABLE */
- rc = iucv_add_pathid(int_buf->ippathid, h);
- if (rc) {
- iucv_sever (int_buf->ippathid,
- no_listener);
- iucv_debug(1,
- "add_pathid failed, rc = %d",
- rc);
- } else {
- interrupt = h->interrupt_table;
- if (interrupt->ConnectionPending) {
- EBCASC (int_buf->ipvmid, 8);
- interrupt->ConnectionPending(
- (iucv_ConnectionPending *)int_buf,
- h->pgm_data);
- } else
- iucv_sever(int_buf->ippathid,
- no_listener);
- }
- } else
- iucv_sever(int_buf->ippathid, no_listener);
- break;
-
- case 0x02: /*connection complete */
- if (messagesDisabled) {
- iucv_setmask(~0);
- messagesDisabled = 0;
- }
- if (h) {
- if (interrupt->ConnectionComplete)
- {
- interrupt->ConnectionComplete(
- (iucv_ConnectionComplete *)int_buf,
- h->pgm_data);
- }
- else
- iucv_debug(1,
- "ConnectionComplete not called");
- } else
- iucv_sever(int_buf->ippathid, no_listener);
- break;
-
- case 0x03: /* connection severed */
- if (messagesDisabled) {
- iucv_setmask(~0);
- messagesDisabled = 0;
- }
- if (h) {
- if (interrupt->ConnectionSevered)
- interrupt->ConnectionSevered(
- (iucv_ConnectionSevered *)int_buf,
- h->pgm_data);
-
- else
- iucv_sever (int_buf->ippathid, no_listener);
- } else
- iucv_sever(int_buf->ippathid, no_listener);
- break;
-
- case 0x04: /* connection quiesced */
- if (messagesDisabled) {
- iucv_setmask(~0);
- messagesDisabled = 0;
- }
- if (h) {
- if (interrupt->ConnectionQuiesced)
- interrupt->ConnectionQuiesced(
- (iucv_ConnectionQuiesced *)int_buf,
- h->pgm_data);
- else
- iucv_debug(1,
- "ConnectionQuiesced not called");
- }
- break;
-
- case 0x05: /* connection resumed */
- if (messagesDisabled) {
- iucv_setmask(~0);
- messagesDisabled = 0;
- }
- if (h) {
- if (interrupt->ConnectionResumed)
- interrupt->ConnectionResumed(
- (iucv_ConnectionResumed *)int_buf,
- h->pgm_data);
- else
- iucv_debug(1,
- "ConnectionResumed not called");
- }
- break;
-
- case 0x06: /* priority message complete */
- case 0x07: /* nonpriority message complete */
- if (h) {
- if (interrupt->MessageComplete)
- interrupt->MessageComplete(
- (iucv_MessageComplete *)int_buf,
- h->pgm_data);
- else
- iucv_debug(2,
- "MessageComplete not called");
- }
- break;
-
- case 0x08: /* priority message pending */
- case 0x09: /* nonpriority message pending */
- if (h) {
- if (interrupt->MessagePending)
- interrupt->MessagePending(
- (iucv_MessagePending *) int_buf,
- h->pgm_data);
- else
- iucv_debug(2,
- "MessagePending not called");
- }
- break;
- default: /* unknown iucv type */
- printk(KERN_WARNING "%s: unknown iucv interrupt\n",
- __FUNCTION__);
- break;
- } /* end switch */
-
- iucv_debug(2, "exiting pathid %d, type %02X",
- int_buf->ippathid, int_buf->iptype);
-
- return;
-}
-
-/**
- * iucv_tasklet_handler:
- *
- * This function loops over the queue of irq buffers and runs iucv_do_int()
- * on every queue element.
- */
-static void
-iucv_tasklet_handler(unsigned long ignored)
-{
- struct list_head head;
- struct list_head *next;
- ulong flags;
-
- spin_lock_irqsave(&iucv_irq_queue_lock, flags);
- list_add(&head, &iucv_irq_queue);
- list_del_init(&iucv_irq_queue);
- spin_unlock_irqrestore (&iucv_irq_queue_lock, flags);
-
- next = head.next;
- while (next != &head) {
- iucv_irqdata *p = list_entry(next, iucv_irqdata, queue);
-
- next = next->next;
- iucv_do_int(&p->data);
- kfree(p);
- }
-
- return;
-}
-
-subsys_initcall(iucv_init);
-module_exit(iucv_exit);
-
-/**
- * Export all public stuff
- */
-EXPORT_SYMBOL (iucv_bus);
-EXPORT_SYMBOL (iucv_root);
-EXPORT_SYMBOL (iucv_accept);
-EXPORT_SYMBOL (iucv_connect);
-#if 0
-EXPORT_SYMBOL (iucv_purge);
-EXPORT_SYMBOL (iucv_query_maxconn);
-EXPORT_SYMBOL (iucv_query_bufsize);
-EXPORT_SYMBOL (iucv_quiesce);
-#endif
-EXPORT_SYMBOL (iucv_receive);
-#if 0
-EXPORT_SYMBOL (iucv_receive_array);
-#endif
-EXPORT_SYMBOL (iucv_reject);
-#if 0
-EXPORT_SYMBOL (iucv_reply);
-EXPORT_SYMBOL (iucv_reply_array);
-EXPORT_SYMBOL (iucv_resume);
-#endif
-EXPORT_SYMBOL (iucv_reply_prmmsg);
-EXPORT_SYMBOL (iucv_send);
-EXPORT_SYMBOL (iucv_send2way);
-EXPORT_SYMBOL (iucv_send2way_array);
-EXPORT_SYMBOL (iucv_send2way_prmmsg);
-EXPORT_SYMBOL (iucv_send2way_prmmsg_array);
-#if 0
-EXPORT_SYMBOL (iucv_send_array);
-EXPORT_SYMBOL (iucv_send_prmmsg);
-EXPORT_SYMBOL (iucv_setmask);
-#endif
-EXPORT_SYMBOL (iucv_sever);
-EXPORT_SYMBOL (iucv_register_program);
-EXPORT_SYMBOL (iucv_unregister_program);
diff --git a/drivers/s390/net/iucv.h b/drivers/s390/net/iucv.h
deleted file mode 100644
index 5b6b1b7241c..00000000000
--- a/drivers/s390/net/iucv.h
+++ /dev/null
@@ -1,849 +0,0 @@
-/*
- * drivers/s390/net/iucv.h
- * IUCV base support.
- *
- * S390 version
- * Copyright (C) 2000 IBM Corporation
- * Author(s):Alan Altmark (Alan_Altmark@us.ibm.com)
- * Xenia Tkatschow (xenia@us.ibm.com)
- *
- *
- * Functionality:
- * To explore any of the IUCV functions, one must first register
- * their program using iucv_register_program(). Once your program has
- * successfully completed a register, it can exploit the other functions.
- * For furthur reference on all IUCV functionality, refer to the
- * CP Programming Services book, also available on the web
- * thru www.ibm.com/s390/vm/pubs, manual # SC24-5760
- *
- * Definition of Return Codes
- * -All positive return codes including zero are reflected back
- * from CP except for iucv_register_program. The definition of each
- * return code can be found in CP Programming Services book.
- * Also available on the web thru www.ibm.com/s390/vm/pubs, manual # SC24-5760
- * - Return Code of:
- * (-EINVAL) Invalid value
- * (-ENOMEM) storage allocation failed
- * pgmask defined in iucv_register_program will be set depending on input
- * paramters.
- *
- */
-
-#include <linux/types.h>
-#include <asm/debug.h>
-
-/**
- * Debug Facility stuff
- */
-#define IUCV_DBF_SETUP_NAME "iucv_setup"
-#define IUCV_DBF_SETUP_LEN 32
-#define IUCV_DBF_SETUP_PAGES 2
-#define IUCV_DBF_SETUP_NR_AREAS 1
-#define IUCV_DBF_SETUP_LEVEL 3
-
-#define IUCV_DBF_DATA_NAME "iucv_data"
-#define IUCV_DBF_DATA_LEN 128
-#define IUCV_DBF_DATA_PAGES 2
-#define IUCV_DBF_DATA_NR_AREAS 1
-#define IUCV_DBF_DATA_LEVEL 2
-
-#define IUCV_DBF_TRACE_NAME "iucv_trace"
-#define IUCV_DBF_TRACE_LEN 16
-#define IUCV_DBF_TRACE_PAGES 4
-#define IUCV_DBF_TRACE_NR_AREAS 1
-#define IUCV_DBF_TRACE_LEVEL 3
-
-#define IUCV_DBF_TEXT(name,level,text) \
- do { \
- debug_text_event(iucv_dbf_##name,level,text); \
- } while (0)
-
-#define IUCV_DBF_HEX(name,level,addr,len) \
- do { \
- debug_event(iucv_dbf_##name,level,(void*)(addr),len); \
- } while (0)
-
-DECLARE_PER_CPU(char[256], iucv_dbf_txt_buf);
-
-#define IUCV_DBF_TEXT_(name,level,text...) \
- do { \
- char* iucv_dbf_txt_buf = get_cpu_var(iucv_dbf_txt_buf); \
- sprintf(iucv_dbf_txt_buf, text); \
- debug_text_event(iucv_dbf_##name,level,iucv_dbf_txt_buf); \
- put_cpu_var(iucv_dbf_txt_buf); \
- } while (0)
-
-#define IUCV_DBF_SPRINTF(name,level,text...) \
- do { \
- debug_sprintf_event(iucv_dbf_trace, level, ##text ); \
- debug_sprintf_event(iucv_dbf_trace, level, text ); \
- } while (0)
-
-/**
- * some more debug stuff
- */
-#define IUCV_HEXDUMP16(importance,header,ptr) \
-PRINT_##importance(header "%02x %02x %02x %02x %02x %02x %02x %02x " \
- "%02x %02x %02x %02x %02x %02x %02x %02x\n", \
- *(((char*)ptr)),*(((char*)ptr)+1),*(((char*)ptr)+2), \
- *(((char*)ptr)+3),*(((char*)ptr)+4),*(((char*)ptr)+5), \
- *(((char*)ptr)+6),*(((char*)ptr)+7),*(((char*)ptr)+8), \
- *(((char*)ptr)+9),*(((char*)ptr)+10),*(((char*)ptr)+11), \
- *(((char*)ptr)+12),*(((char*)ptr)+13), \
- *(((char*)ptr)+14),*(((char*)ptr)+15)); \
-PRINT_##importance(header "%02x %02x %02x %02x %02x %02x %02x %02x " \
- "%02x %02x %02x %02x %02x %02x %02x %02x\n", \
- *(((char*)ptr)+16),*(((char*)ptr)+17), \
- *(((char*)ptr)+18),*(((char*)ptr)+19), \
- *(((char*)ptr)+20),*(((char*)ptr)+21), \
- *(((char*)ptr)+22),*(((char*)ptr)+23), \
- *(((char*)ptr)+24),*(((char*)ptr)+25), \
- *(((char*)ptr)+26),*(((char*)ptr)+27), \
- *(((char*)ptr)+28),*(((char*)ptr)+29), \
- *(((char*)ptr)+30),*(((char*)ptr)+31));
-
-static inline void
-iucv_hex_dump(unsigned char *buf, size_t len)
-{
- size_t i;
-
- for (i = 0; i < len; i++) {
- if (i && !(i % 16))
- printk("\n");
- printk("%02x ", *(buf + i));
- }
- printk("\n");
-}
-/**
- * end of debug stuff
- */
-
-#define uchar unsigned char
-#define ushort unsigned short
-#define ulong unsigned long
-#define iucv_handle_t void *
-
-/* flags1:
- * All flags are defined in the field IPFLAGS1 of each function
- * and can be found in CP Programming Services.
- * IPLOCAL - Indicates the connect can only be satisfied on the
- * local system
- * IPPRTY - Indicates a priority message
- * IPQUSCE - Indicates you do not want to receive messages on a
- * path until an iucv_resume is issued
- * IPRMDATA - Indicates that the message is in the parameter list
- */
-#define IPLOCAL 0x01
-#define IPPRTY 0x20
-#define IPQUSCE 0x40
-#define IPRMDATA 0x80
-
-/* flags1_out:
- * All flags are defined in the output field of IPFLAGS1 for each function
- * and can be found in CP Programming Services.
- * IPNORPY - Specifies this is a one-way message and no reply is expected.
- * IPPRTY - Indicates a priority message is permitted. Defined in flags1.
- */
-#define IPNORPY 0x10
-
-#define Nonpriority_MessagePendingInterruptsFlag 0x80
-#define Priority_MessagePendingInterruptsFlag 0x40
-#define Nonpriority_MessageCompletionInterruptsFlag 0x20
-#define Priority_MessageCompletionInterruptsFlag 0x10
-#define IUCVControlInterruptsFlag 0x08
-#define AllInterrupts 0xf8
-/*
- * Mapping of external interrupt buffers should be used with the corresponding
- * interrupt types.
- * Names: iucv_ConnectionPending -> connection pending
- * iucv_ConnectionComplete -> connection complete
- * iucv_ConnectionSevered -> connection severed
- * iucv_ConnectionQuiesced -> connection quiesced
- * iucv_ConnectionResumed -> connection resumed
- * iucv_MessagePending -> message pending
- * iucv_MessageComplete -> message complete
- */
-typedef struct {
- u16 ippathid;
- uchar ipflags1;
- uchar iptype;
- u16 ipmsglim;
- u16 res1;
- uchar ipvmid[8];
- uchar ipuser[16];
- u32 res3;
- uchar ippollfg;
- uchar res4[3];
-} iucv_ConnectionPending;
-
-typedef struct {
- u16 ippathid;
- uchar ipflags1;
- uchar iptype;
- u16 ipmsglim;
- u16 res1;
- uchar res2[8];
- uchar ipuser[16];
- u32 res3;
- uchar ippollfg;
- uchar res4[3];
-} iucv_ConnectionComplete;
-
-typedef struct {
- u16 ippathid;
- uchar res1;
- uchar iptype;
- u32 res2;
- uchar res3[8];
- uchar ipuser[16];
- u32 res4;
- uchar ippollfg;
- uchar res5[3];
-} iucv_ConnectionSevered;
-
-typedef struct {
- u16 ippathid;
- uchar res1;
- uchar iptype;
- u32 res2;
- uchar res3[8];
- uchar ipuser[16];
- u32 res4;
- uchar ippollfg;
- uchar res5[3];
-} iucv_ConnectionQuiesced;
-
-typedef struct {
- u16 ippathid;
- uchar res1;
- uchar iptype;
- u32 res2;
- uchar res3[8];
- uchar ipuser[16];
- u32 res4;
- uchar ippollfg;
- uchar res5[3];
-} iucv_ConnectionResumed;
-
-typedef struct {
- u16 ippathid;
- uchar ipflags1;
- uchar iptype;
- u32 ipmsgid;
- u32 iptrgcls;
- union u2 {
- u32 iprmmsg1_u32;
- uchar iprmmsg1[4];
- } ln1msg1;
- union u1 {
- u32 ipbfln1f;
- uchar iprmmsg2[4];
- } ln1msg2;
- u32 res1[3];
- u32 ipbfln2f;
- uchar ippollfg;
- uchar res2[3];
-} iucv_MessagePending;
-
-typedef struct {
- u16 ippathid;
- uchar ipflags1;
- uchar iptype;
- u32 ipmsgid;
- u32 ipaudit;
- uchar iprmmsg[8];
- u32 ipsrccls;
- u32 ipmsgtag;
- u32 res;
- u32 ipbfln2f;
- uchar ippollfg;
- uchar res2[3];
-} iucv_MessageComplete;
-
-/*
- * iucv_interrupt_ops_t: Is a vector of functions that handle
- * IUCV interrupts.
- * Parameter list:
- * eib - is a pointer to a 40-byte area described
- * with one of the structures above.
- * pgm_data - this data is strictly for the
- * interrupt handler that is passed by
- * the application. This may be an address
- * or token.
-*/
-typedef struct {
- void (*ConnectionPending) (iucv_ConnectionPending * eib,
- void *pgm_data);
- void (*ConnectionComplete) (iucv_ConnectionComplete * eib,
- void *pgm_data);
- void (*ConnectionSevered) (iucv_ConnectionSevered * eib,
- void *pgm_data);
- void (*ConnectionQuiesced) (iucv_ConnectionQuiesced * eib,
- void *pgm_data);
- void (*ConnectionResumed) (iucv_ConnectionResumed * eib,
- void *pgm_data);
- void (*MessagePending) (iucv_MessagePending * eib, void *pgm_data);
- void (*MessageComplete) (iucv_MessageComplete * eib, void *pgm_data);
-} iucv_interrupt_ops_t;
-
-/*
- *iucv_array_t : Defines buffer array.
- * Inside the array may be 31- bit addresses and 31-bit lengths.
-*/
-typedef struct {
- u32 address;
- u32 length;
-} iucv_array_t __attribute__ ((aligned (8)));
-
-extern struct bus_type iucv_bus;
-extern struct device *iucv_root;
-
-/* -prototypes- */
-/*
- * Name: iucv_register_program
- * Purpose: Registers an application with IUCV
- * Input: prmname - user identification
- * userid - machine identification
- * pgmmask - indicates which bits in the prmname and userid combined will be
- * used to determine who is given control
- * ops - address of vector of interrupt handlers
- * pgm_data- application data passed to interrupt handlers
- * Output: NA
- * Return: address of handler
- * (0) - Error occurred, registration not completed.
- * NOTE: Exact cause of failure will be recorded in syslog.
-*/
-iucv_handle_t iucv_register_program (uchar pgmname[16],
- uchar userid[8],
- uchar pgmmask[24],
- iucv_interrupt_ops_t * ops,
- void *pgm_data);
-
-/*
- * Name: iucv_unregister_program
- * Purpose: Unregister application with IUCV
- * Input: address of handler
- * Output: NA
- * Return: (0) - Normal return
- * (-EINVAL) - Internal error, wild pointer
-*/
-int iucv_unregister_program (iucv_handle_t handle);
-
-/*
- * Name: iucv_accept
- * Purpose: This function is issued after the user receives a Connection Pending external
- * interrupt and now wishes to complete the IUCV communication path.
- * Input: pathid - u16 , Path identification number
- * msglim_reqstd - u16, The number of outstanding messages requested.
- * user_data - uchar[16], Data specified by the iucv_connect function.
- * flags1 - int, Contains options for this path.
- * -IPPRTY - 0x20- Specifies if you want to send priority message.
- * -IPRMDATA - 0x80, Specifies whether your program can handle a message
- * in the parameter list.
- * -IPQUSCE - 0x40, Specifies whether you want to quiesce the path being
- * established.
- * handle - iucv_handle_t, Address of handler.
- * pgm_data - void *, Application data passed to interrupt handlers.
- * flags1_out - int * Contains information about the path
- * - IPPRTY - 0x20, Indicates you may send priority messages.
- * msglim - *u16, Number of outstanding messages.
- * Output: return code from CP IUCV call.
-*/
-
-int iucv_accept (u16 pathid,
- u16 msglim_reqstd,
- uchar user_data[16],
- int flags1,
- iucv_handle_t handle,
- void *pgm_data, int *flags1_out, u16 * msglim);
-
-/*
- * Name: iucv_connect
- * Purpose: This function establishes an IUCV path. Although the connect may complete
- * successfully, you are not able to use the path until you receive an IUCV
- * Connection Complete external interrupt.
- * Input: pathid - u16 *, Path identification number
- * msglim_reqstd - u16, Number of outstanding messages requested
- * user_data - uchar[16], 16-byte user data
- * userid - uchar[8], User identification
- * system_name - uchar[8], 8-byte identifying the system name
- * flags1 - int, Contains options for this path.
- * -IPPRTY - 0x20, Specifies if you want to send priority message.
- * -IPRMDATA - 0x80, Specifies whether your program can handle a message
- * in the parameter list.
- * -IPQUSCE - 0x40, Specifies whether you want to quiesce the path being
- * established.
- * -IPLOCAL - 0X01, Allows an application to force the partner to be on
- * the local system. If local is specified then target class cannot be
- * specified.
- * flags1_out - int * Contains information about the path
- * - IPPRTY - 0x20, Indicates you may send priority messages.
- * msglim - * u16, Number of outstanding messages
- * handle - iucv_handle_t, Address of handler
- * pgm_data - void *, Application data passed to interrupt handlers
- * Output: return code from CP IUCV call
- * rc - return code from iucv_declare_buffer
- * -EINVAL - Invalid handle passed by application
- * -EINVAL - Pathid address is NULL
- * add_pathid_result - Return code from internal function add_pathid
-*/
-int
- iucv_connect (u16 * pathid,
- u16 msglim_reqstd,
- uchar user_data[16],
- uchar userid[8],
- uchar system_name[8],
- int flags1,
- int *flags1_out,
- u16 * msglim, iucv_handle_t handle, void *pgm_data);
-
-/*
- * Name: iucv_purge
- * Purpose: This function cancels a message that you have sent.
- * Input: pathid - Path identification number.
- * msgid - Specifies the message ID of the message to be purged.
- * srccls - Specifies the source message class.
- * Output: audit - Contains information about asynchronous error
- * that may have affected the normal completion
- * of this message.
- * Return: Return code from CP IUCV call.
-*/
-int iucv_purge (u16 pathid, u32 msgid, u32 srccls, __u32 *audit);
-/*
- * Name: iucv_query_maxconn
- * Purpose: This function determines the maximum number of communication paths you
- * may establish.
- * Return: maxconn - ulong, Maximum number of connection the virtual machine may
- * establish.
-*/
-ulong iucv_query_maxconn (void);
-
-/*
- * Name: iucv_query_bufsize
- * Purpose: This function determines how large an external interrupt
- * buffer IUCV requires to store information.
- * Return: bufsize - ulong, Size of external interrupt buffer.
- */
-ulong iucv_query_bufsize (void);
-
-/*
- * Name: iucv_quiesce
- * Purpose: This function temporarily suspends incoming messages on an
- * IUCV path. You can later reactivate the path by invoking
- * the iucv_resume function.
- * Input: pathid - Path identification number
- * user_data - 16-bytes of user data
- * Output: NA
- * Return: Return code from CP IUCV call.
-*/
-int iucv_quiesce (u16 pathid, uchar user_data[16]);
-
-/*
- * Name: iucv_receive
- * Purpose: This function receives messages that are being sent to you
- * over established paths. Data will be returned in buffer for length of
- * buflen.
- * Input:
- * pathid - Path identification number.
- * buffer - Address of buffer to receive.
- * buflen - Length of buffer to receive.
- * msgid - Specifies the message ID.
- * trgcls - Specifies target class.
- * Output:
- * flags1_out: int *, Contains information about this path.
- * IPNORPY - 0x10 Specifies this is a one-way message and no reply is
- * expected.
- * IPPRTY - 0x20 Specifies if you want to send priority message.
- * IPRMDATA - 0x80 specifies the data is contained in the parameter list
- * residual_buffer - address of buffer updated by the number
- * of bytes you have received.
- * residual_length -
- * Contains one of the following values, if the receive buffer is:
- * The same length as the message, this field is zero.
- * Longer than the message, this field contains the number of
- * bytes remaining in the buffer.
- * Shorter than the message, this field contains the residual
- * count (that is, the number of bytes remaining in the
- * message that does not fit into the buffer. In this
- * case b2f0_result = 5.
- * Return: Return code from CP IUCV call.
- * (-EINVAL) - buffer address is pointing to NULL
-*/
-int iucv_receive (u16 pathid,
- u32 msgid,
- u32 trgcls,
- void *buffer,
- ulong buflen,
- int *flags1_out,
- ulong * residual_buffer, ulong * residual_length);
-
- /*
- * Name: iucv_receive_array
- * Purpose: This function receives messages that are being sent to you
- * over established paths. Data will be returned in first buffer for
- * length of first buffer.
- * Input: pathid - Path identification number.
- * msgid - specifies the message ID.
- * trgcls - Specifies target class.
- * buffer - Address of array of buffers.
- * buflen - Total length of buffers.
- * Output:
- * flags1_out: int *, Contains information about this path.
- * IPNORPY - 0x10 Specifies this is a one-way message and no reply is
- * expected.
- * IPPRTY - 0x20 Specifies if you want to send priority message.
- * IPRMDATA - 0x80 specifies the data is contained in the parameter list
- * residual_buffer - address points to the current list entry IUCV
- * is working on.
- * residual_length -
- * Contains one of the following values, if the receive buffer is:
- * The same length as the message, this field is zero.
- * Longer than the message, this field contains the number of
- * bytes remaining in the buffer.
- * Shorter than the message, this field contains the residual
- * count (that is, the number of bytes remaining in the
- * message that does not fit into the buffer. In this
- * case b2f0_result = 5.
- * Return: Return code from CP IUCV call.
- * (-EINVAL) - Buffer address is NULL.
- */
-int iucv_receive_array (u16 pathid,
- u32 msgid,
- u32 trgcls,
- iucv_array_t * buffer,
- ulong buflen,
- int *flags1_out,
- ulong * residual_buffer, ulong * residual_length);
-
-/*
- * Name: iucv_reject
- * Purpose: The reject function refuses a specified message. Between the
- * time you are notified of a message and the time that you
- * complete the message, the message may be rejected.
- * Input: pathid - Path identification number.
- * msgid - Specifies the message ID.
- * trgcls - Specifies target class.
- * Output: NA
- * Return: Return code from CP IUCV call.
-*/
-int iucv_reject (u16 pathid, u32 msgid, u32 trgcls);
-
-/*
- * Name: iucv_reply
- * Purpose: This function responds to the two-way messages that you
- * receive. You must identify completely the message to
- * which you wish to reply. ie, pathid, msgid, and trgcls.
- * Input: pathid - Path identification number.
- * msgid - Specifies the message ID.
- * trgcls - Specifies target class.
- * flags1 - Option for path.
- * IPPRTY- 0x20, Specifies if you want to send priority message.
- * buffer - Address of reply buffer.
- * buflen - Length of reply buffer.
- * Output: residual_buffer - Address of buffer updated by the number
- * of bytes you have moved.
- * residual_length - Contains one of the following values:
- * If the answer buffer is the same length as the reply, this field
- * contains zero.
- * If the answer buffer is longer than the reply, this field contains
- * the number of bytes remaining in the buffer.
- * If the answer buffer is shorter than the reply, this field contains
- * a residual count (that is, the number of bytes remianing in the
- * reply that does not fit into the buffer. In this
- * case b2f0_result = 5.
- * Return: Return code from CP IUCV call.
- * (-EINVAL) - Buffer address is NULL.
-*/
-int iucv_reply (u16 pathid,
- u32 msgid,
- u32 trgcls,
- int flags1,
- void *buffer, ulong buflen, ulong * residual_buffer,
- ulong * residual_length);
-
-/*
- * Name: iucv_reply_array
- * Purpose: This function responds to the two-way messages that you
- * receive. You must identify completely the message to
- * which you wish to reply. ie, pathid, msgid, and trgcls.
- * The array identifies a list of addresses and lengths of
- * discontiguous buffers that contains the reply data.
- * Input: pathid - Path identification number
- * msgid - Specifies the message ID.
- * trgcls - Specifies target class.
- * flags1 - Option for path.
- * IPPRTY- 0x20, Specifies if you want to send priority message.
- * buffer - Address of array of reply buffers.
- * buflen - Total length of reply buffers.
- * Output: residual_buffer - Address of buffer which IUCV is currently working on.
- * residual_length - Contains one of the following values:
- * If the answer buffer is the same length as the reply, this field
- * contains zero.
- * If the answer buffer is longer than the reply, this field contains
- * the number of bytes remaining in the buffer.
- * If the answer buffer is shorter than the reply, this field contains
- * a residual count (that is, the number of bytes remianing in the
- * reply that does not fit into the buffer. In this
- * case b2f0_result = 5.
- * Return: Return code from CP IUCV call.
- * (-EINVAL) - Buffer address is NULL.
-*/
-int iucv_reply_array (u16 pathid,
- u32 msgid,
- u32 trgcls,
- int flags1,
- iucv_array_t * buffer,
- ulong buflen, ulong * residual_address,
- ulong * residual_length);
-
-/*
- * Name: iucv_reply_prmmsg
- * Purpose: This function responds to the two-way messages that you
- * receive. You must identify completely the message to
- * which you wish to reply. ie, pathid, msgid, and trgcls.
- * Prmmsg signifies the data is moved into the
- * parameter list.
- * Input: pathid - Path identification number.
- * msgid - Specifies the message ID.
- * trgcls - Specifies target class.
- * flags1 - Option for path.
- * IPPRTY- 0x20 Specifies if you want to send priority message.
- * prmmsg - 8-bytes of data to be placed into the parameter.
- * list.
- * Output: NA
- * Return: Return code from CP IUCV call.
-*/
-int iucv_reply_prmmsg (u16 pathid,
- u32 msgid, u32 trgcls, int flags1, uchar prmmsg[8]);
-
-/*
- * Name: iucv_resume
- * Purpose: This function restores communications over a quiesced path
- * Input: pathid - Path identification number.
- * user_data - 16-bytes of user data.
- * Output: NA
- * Return: Return code from CP IUCV call.
-*/
-int iucv_resume (u16 pathid, uchar user_data[16]);
-
-/*
- * Name: iucv_send
- * Purpose: This function transmits data to another application.
- * Data to be transmitted is in a buffer and this is a
- * one-way message and the receiver will not reply to the
- * message.
- * Input: pathid - Path identification number.
- * trgcls - Specifies target class.
- * srccls - Specifies the source message class.
- * msgtag - Specifies a tag to be associated with the message.
- * flags1 - Option for path.
- * IPPRTY- 0x20 Specifies if you want to send priority message.
- * buffer - Address of send buffer.
- * buflen - Length of send buffer.
- * Output: msgid - Specifies the message ID.
- * Return: Return code from CP IUCV call.
- * (-EINVAL) - Buffer address is NULL.
-*/
-int iucv_send (u16 pathid,
- u32 * msgid,
- u32 trgcls,
- u32 srccls, u32 msgtag, int flags1, void *buffer, ulong buflen);
-
-/*
- * Name: iucv_send_array
- * Purpose: This function transmits data to another application.
- * The contents of buffer is the address of the array of
- * addresses and lengths of discontiguous buffers that hold
- * the message text. This is a one-way message and the
- * receiver will not reply to the message.
- * Input: pathid - Path identification number.
- * trgcls - Specifies target class.
- * srccls - Specifies the source message class.
- * msgtag - Specifies a tag to be associated witht the message.
- * flags1 - Option for path.
- * IPPRTY- specifies if you want to send priority message.
- * buffer - Address of array of send buffers.
- * buflen - Total length of send buffers.
- * Output: msgid - Specifies the message ID.
- * Return: Return code from CP IUCV call.
- * (-EINVAL) - Buffer address is NULL.
-*/
-int iucv_send_array (u16 pathid,
- u32 * msgid,
- u32 trgcls,
- u32 srccls,
- u32 msgtag,
- int flags1, iucv_array_t * buffer, ulong buflen);
-
-/*
- * Name: iucv_send_prmmsg
- * Purpose: This function transmits data to another application.
- * Prmmsg specifies that the 8-bytes of data are to be moved
- * into the parameter list. This is a one-way message and the
- * receiver will not reply to the message.
- * Input: pathid - Path identification number.
- * trgcls - Specifies target class.
- * srccls - Specifies the source message class.
- * msgtag - Specifies a tag to be associated with the message.
- * flags1 - Option for path.
- * IPPRTY- 0x20 specifies if you want to send priority message.
- * prmmsg - 8-bytes of data to be placed into parameter list.
- * Output: msgid - Specifies the message ID.
- * Return: Return code from CP IUCV call.
-*/
-int iucv_send_prmmsg (u16 pathid,
- u32 * msgid,
- u32 trgcls,
- u32 srccls, u32 msgtag, int flags1, uchar prmmsg[8]);
-
-/*
- * Name: iucv_send2way
- * Purpose: This function transmits data to another application.
- * Data to be transmitted is in a buffer. The receiver
- * of the send is expected to reply to the message and
- * a buffer is provided into which IUCV moves the reply
- * to this message.
- * Input: pathid - Path identification number.
- * trgcls - Specifies target class.
- * srccls - Specifies the source message class.
- * msgtag - Specifies a tag associated with the message.
- * flags1 - Option for path.
- * IPPRTY- 0x20 Specifies if you want to send priority message.
- * buffer - Address of send buffer.
- * buflen - Length of send buffer.
- * ansbuf - Address of buffer into which IUCV moves the reply of
- * this message.
- * anslen - Address of length of buffer.
- * Output: msgid - Specifies the message ID.
- * Return: Return code from CP IUCV call.
- * (-EINVAL) - Buffer or ansbuf address is NULL.
-*/
-int iucv_send2way (u16 pathid,
- u32 * msgid,
- u32 trgcls,
- u32 srccls,
- u32 msgtag,
- int flags1,
- void *buffer, ulong buflen, void *ansbuf, ulong anslen);
-
-/*
- * Name: iucv_send2way_array
- * Purpose: This function transmits data to another application.
- * The contents of buffer is the address of the array of
- * addresses and lengths of discontiguous buffers that hold
- * the message text. The receiver of the send is expected to
- * reply to the message and a buffer is provided into which
- * IUCV moves the reply to this message.
- * Input: pathid - Path identification number.
- * trgcls - Specifies target class.
- * srccls - Specifies the source message class.
- * msgtag - Specifies a tag to be associated with the message.
- * flags1 - Option for path.
- * IPPRTY- 0x20 Specifies if you want to send priority message.
- * buffer - Sddress of array of send buffers.
- * buflen - Total length of send buffers.
- * ansbuf - Address of array of buffer into which IUCV moves the reply
- * of this message.
- * anslen - Address of length reply buffers.
- * Output: msgid - Specifies the message ID.
- * Return: Return code from CP IUCV call.
- * (-EINVAL) - Buffer address is NULL.
-*/
-int iucv_send2way_array (u16 pathid,
- u32 * msgid,
- u32 trgcls,
- u32 srccls,
- u32 msgtag,
- int flags1,
- iucv_array_t * buffer,
- ulong buflen, iucv_array_t * ansbuf, ulong anslen);
-
-/*
- * Name: iucv_send2way_prmmsg
- * Purpose: This function transmits data to another application.
- * Prmmsg specifies that the 8-bytes of data are to be moved
- * into the parameter list. This is a two-way message and the
- * receiver of the message is expected to reply. A buffer
- * is provided into which IUCV moves the reply to this
- * message.
- * Input: pathid - Rath identification number.
- * trgcls - Specifies target class.
- * srccls - Specifies the source message class.
- * msgtag - Specifies a tag to be associated with the message.
- * flags1 - Option for path.
- * IPPRTY- 0x20 Specifies if you want to send priority message.
- * prmmsg - 8-bytes of data to be placed in parameter list.
- * ansbuf - Address of buffer into which IUCV moves the reply of
- * this message.
- * anslen - Address of length of buffer.
- * Output: msgid - Specifies the message ID.
- * Return: Return code from CP IUCV call.
- * (-EINVAL) - Buffer address is NULL.
-*/
-int iucv_send2way_prmmsg (u16 pathid,
- u32 * msgid,
- u32 trgcls,
- u32 srccls,
- u32 msgtag,
- ulong flags1,
- uchar prmmsg[8], void *ansbuf, ulong anslen);
-
-/*
- * Name: iucv_send2way_prmmsg_array
- * Purpose: This function transmits data to another application.
- * Prmmsg specifies that the 8-bytes of data are to be moved
- * into the parameter list. This is a two-way message and the
- * receiver of the message is expected to reply. A buffer
- * is provided into which IUCV moves the reply to this
- * message. The contents of ansbuf is the address of the
- * array of addresses and lengths of discontiguous buffers
- * that contain the reply.
- * Input: pathid - Path identification number.
- * trgcls - Specifies target class.
- * srccls - Specifies the source message class.
- * msgtag - Specifies a tag to be associated with the message.
- * flags1 - Option for path.
- * IPPRTY- 0x20 specifies if you want to send priority message.
- * prmmsg - 8-bytes of data to be placed into the parameter list.
- * ansbuf - Address of array of buffer into which IUCV moves the reply
- * of this message.
- * anslen - Address of length of reply buffers.
- * Output: msgid - Specifies the message ID.
- * Return: Return code from CP IUCV call.
- * (-EINVAL) - Ansbuf address is NULL.
-*/
-int iucv_send2way_prmmsg_array (u16 pathid,
- u32 * msgid,
- u32 trgcls,
- u32 srccls,
- u32 msgtag,
- int flags1,
- uchar prmmsg[8],
- iucv_array_t * ansbuf, ulong anslen);
-
-/*
- * Name: iucv_setmask
- * Purpose: This function enables or disables the following IUCV
- * external interruptions: Nonpriority and priority message
- * interrupts, nonpriority and priority reply interrupts.
- * Input: SetMaskFlag - options for interrupts
- * 0x80 - Nonpriority_MessagePendingInterruptsFlag
- * 0x40 - Priority_MessagePendingInterruptsFlag
- * 0x20 - Nonpriority_MessageCompletionInterruptsFlag
- * 0x10 - Priority_MessageCompletionInterruptsFlag
- * 0x08 - IUCVControlInterruptsFlag
- * Output: NA
- * Return: Return code from CP IUCV call.
-*/
-int iucv_setmask (int SetMaskFlag);
-
-/*
- * Name: iucv_sever
- * Purpose: This function terminates an IUCV path.
- * Input: pathid - Path identification number.
- * user_data - 16-bytes of user data.
- * Output: NA
- * Return: Return code from CP IUCV call.
- * (-EINVAL) - Interal error, wild pointer.
-*/
-int iucv_sever (u16 pathid, uchar user_data[16]);
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c
index e5665b6743a..ecca1046714 100644
--- a/drivers/s390/net/lcs.c
+++ b/drivers/s390/net/lcs.c
@@ -828,7 +828,7 @@ lcs_notify_lancmd_waiters(struct lcs_card *card, struct lcs_cmd *cmd)
/**
* Emit buffer of a lan comand.
*/
-void
+static void
lcs_lancmd_timeout(unsigned long data)
{
struct lcs_reply *reply, *list_reply, *r;
@@ -1360,7 +1360,7 @@ lcs_get_problem(struct ccw_device *cdev, struct irb *irb)
return 0;
}
-void
+static void
lcs_schedule_recovery(struct lcs_card *card)
{
LCS_DBF_TEXT(2, trace, "startrec");
@@ -1511,8 +1511,7 @@ lcs_txbuffer_cb(struct lcs_channel *channel, struct lcs_buffer *buffer)
LCS_DBF_TEXT(5, trace, "txbuffcb");
/* Put buffer back to pool. */
lcs_release_buffer(channel, buffer);
- card = (struct lcs_card *)
- ((char *) channel - offsetof(struct lcs_card, write));
+ card = container_of(channel, struct lcs_card, write);
if (netif_queue_stopped(card->dev) && netif_carrier_ok(card->dev))
netif_wake_queue(card->dev);
spin_lock(&card->lock);
@@ -1810,8 +1809,7 @@ lcs_get_frames_cb(struct lcs_channel *channel, struct lcs_buffer *buffer)
LCS_DBF_TEXT(4, trace, "-eiogpkt");
return;
}
- card = (struct lcs_card *)
- ((char *) channel - offsetof(struct lcs_card, read));
+ card = container_of(channel, struct lcs_card, read);
offset = 0;
while (lcs_hdr->offset != 0) {
if (lcs_hdr->offset <= 0 ||
@@ -1990,7 +1988,7 @@ lcs_timeout_store (struct device *dev, struct device_attribute *attr, const char
}
-DEVICE_ATTR(lancmd_timeout, 0644, lcs_timeout_show, lcs_timeout_store);
+static DEVICE_ATTR(lancmd_timeout, 0644, lcs_timeout_show, lcs_timeout_store);
static ssize_t
lcs_dev_recover_store(struct device *dev, struct device_attribute *attr,
diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c
index d7d1cc0a5c8..594320ca1b7 100644
--- a/drivers/s390/net/netiucv.c
+++ b/drivers/s390/net/netiucv.c
@@ -1,7 +1,7 @@
/*
* IUCV network driver
*
- * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Copyright 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
* Author(s): Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com)
*
* Sysfs integration and all bugs therein by Cornelia Huck
@@ -41,7 +41,6 @@
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/timer.h>
-#include <linux/sched.h>
#include <linux/bitops.h>
#include <linux/signal.h>
@@ -58,13 +57,94 @@
#include <asm/io.h>
#include <asm/uaccess.h>
-#include "iucv.h"
+#include <net/iucv/iucv.h>
#include "fsm.h"
MODULE_AUTHOR
("(C) 2001 IBM Corporation by Fritz Elfert (felfert@millenux.com)");
MODULE_DESCRIPTION ("Linux for S/390 IUCV network driver");
+/**
+ * Debug Facility stuff
+ */
+#define IUCV_DBF_SETUP_NAME "iucv_setup"
+#define IUCV_DBF_SETUP_LEN 32
+#define IUCV_DBF_SETUP_PAGES 2
+#define IUCV_DBF_SETUP_NR_AREAS 1
+#define IUCV_DBF_SETUP_LEVEL 3
+
+#define IUCV_DBF_DATA_NAME "iucv_data"
+#define IUCV_DBF_DATA_LEN 128
+#define IUCV_DBF_DATA_PAGES 2
+#define IUCV_DBF_DATA_NR_AREAS 1
+#define IUCV_DBF_DATA_LEVEL 2
+
+#define IUCV_DBF_TRACE_NAME "iucv_trace"
+#define IUCV_DBF_TRACE_LEN 16
+#define IUCV_DBF_TRACE_PAGES 4
+#define IUCV_DBF_TRACE_NR_AREAS 1
+#define IUCV_DBF_TRACE_LEVEL 3
+
+#define IUCV_DBF_TEXT(name,level,text) \
+ do { \
+ debug_text_event(iucv_dbf_##name,level,text); \
+ } while (0)
+
+#define IUCV_DBF_HEX(name,level,addr,len) \
+ do { \
+ debug_event(iucv_dbf_##name,level,(void*)(addr),len); \
+ } while (0)
+
+DECLARE_PER_CPU(char[256], iucv_dbf_txt_buf);
+
+#define IUCV_DBF_TEXT_(name,level,text...) \
+ do { \
+ char* iucv_dbf_txt_buf = get_cpu_var(iucv_dbf_txt_buf); \
+ sprintf(iucv_dbf_txt_buf, text); \
+ debug_text_event(iucv_dbf_##name,level,iucv_dbf_txt_buf); \
+ put_cpu_var(iucv_dbf_txt_buf); \
+ } while (0)
+
+#define IUCV_DBF_SPRINTF(name,level,text...) \
+ do { \
+ debug_sprintf_event(iucv_dbf_trace, level, ##text ); \
+ debug_sprintf_event(iucv_dbf_trace, level, text ); \
+ } while (0)
+
+/**
+ * some more debug stuff
+ */
+#define IUCV_HEXDUMP16(importance,header,ptr) \
+PRINT_##importance(header "%02x %02x %02x %02x %02x %02x %02x %02x " \
+ "%02x %02x %02x %02x %02x %02x %02x %02x\n", \
+ *(((char*)ptr)),*(((char*)ptr)+1),*(((char*)ptr)+2), \
+ *(((char*)ptr)+3),*(((char*)ptr)+4),*(((char*)ptr)+5), \
+ *(((char*)ptr)+6),*(((char*)ptr)+7),*(((char*)ptr)+8), \
+ *(((char*)ptr)+9),*(((char*)ptr)+10),*(((char*)ptr)+11), \
+ *(((char*)ptr)+12),*(((char*)ptr)+13), \
+ *(((char*)ptr)+14),*(((char*)ptr)+15)); \
+PRINT_##importance(header "%02x %02x %02x %02x %02x %02x %02x %02x " \
+ "%02x %02x %02x %02x %02x %02x %02x %02x\n", \
+ *(((char*)ptr)+16),*(((char*)ptr)+17), \
+ *(((char*)ptr)+18),*(((char*)ptr)+19), \
+ *(((char*)ptr)+20),*(((char*)ptr)+21), \
+ *(((char*)ptr)+22),*(((char*)ptr)+23), \
+ *(((char*)ptr)+24),*(((char*)ptr)+25), \
+ *(((char*)ptr)+26),*(((char*)ptr)+27), \
+ *(((char*)ptr)+28),*(((char*)ptr)+29), \
+ *(((char*)ptr)+30),*(((char*)ptr)+31));
+
+static inline void iucv_hex_dump(unsigned char *buf, size_t len)
+{
+ size_t i;
+
+ for (i = 0; i < len; i++) {
+ if (i && !(i % 16))
+ printk("\n");
+ printk("%02x ", *(buf + i));
+ }
+ printk("\n");
+}
#define PRINTK_HEADER " iucv: " /* for debugging */
@@ -73,6 +153,25 @@ static struct device_driver netiucv_driver = {
.bus = &iucv_bus,
};
+static int netiucv_callback_connreq(struct iucv_path *,
+ u8 ipvmid[8], u8 ipuser[16]);
+static void netiucv_callback_connack(struct iucv_path *, u8 ipuser[16]);
+static void netiucv_callback_connrej(struct iucv_path *, u8 ipuser[16]);
+static void netiucv_callback_connsusp(struct iucv_path *, u8 ipuser[16]);
+static void netiucv_callback_connres(struct iucv_path *, u8 ipuser[16]);
+static void netiucv_callback_rx(struct iucv_path *, struct iucv_message *);
+static void netiucv_callback_txdone(struct iucv_path *, struct iucv_message *);
+
+static struct iucv_handler netiucv_handler = {
+ .path_pending = netiucv_callback_connreq,
+ .path_complete = netiucv_callback_connack,
+ .path_severed = netiucv_callback_connrej,
+ .path_quiesced = netiucv_callback_connsusp,
+ .path_resumed = netiucv_callback_connres,
+ .message_pending = netiucv_callback_rx,
+ .message_complete = netiucv_callback_txdone
+};
+
/**
* Per connection profiling data
*/
@@ -92,9 +191,8 @@ struct connection_profile {
* Representation of one iucv connection
*/
struct iucv_connection {
- struct iucv_connection *next;
- iucv_handle_t handle;
- __u16 pathid;
+ struct list_head list;
+ struct iucv_path *path;
struct sk_buff *rx_buff;
struct sk_buff *tx_buff;
struct sk_buff_head collect_queue;
@@ -112,12 +210,9 @@ struct iucv_connection {
/**
* Linked list of all connection structs.
*/
-struct iucv_connection_struct {
- struct iucv_connection *iucv_connections;
- rwlock_t iucv_rwlock;
-};
-
-static struct iucv_connection_struct iucv_conns;
+static struct list_head iucv_connection_list =
+ LIST_HEAD_INIT(iucv_connection_list);
+static rwlock_t iucv_connection_rwlock = RW_LOCK_UNLOCKED;
/**
* Representation of event-data for the
@@ -142,11 +237,11 @@ struct netiucv_priv {
/**
* Link level header for a packet.
*/
-typedef struct ll_header_t {
- __u16 next;
-} ll_header;
+struct ll_header {
+ u16 next;
+};
-#define NETIUCV_HDRLEN (sizeof(ll_header))
+#define NETIUCV_HDRLEN (sizeof(struct ll_header))
#define NETIUCV_BUFSIZE_MAX 32768
#define NETIUCV_BUFSIZE_DEFAULT NETIUCV_BUFSIZE_MAX
#define NETIUCV_MTU_MAX (NETIUCV_BUFSIZE_MAX - NETIUCV_HDRLEN)
@@ -158,36 +253,26 @@ typedef struct ll_header_t {
* Compatibility macros for busy handling
* of network devices.
*/
-static __inline__ void netiucv_clear_busy(struct net_device *dev)
+static inline void netiucv_clear_busy(struct net_device *dev)
{
- clear_bit(0, &(((struct netiucv_priv *)dev->priv)->tbusy));
+ struct netiucv_priv *priv = netdev_priv(dev);
+ clear_bit(0, &priv->tbusy);
netif_wake_queue(dev);
}
-static __inline__ int netiucv_test_and_set_busy(struct net_device *dev)
+static inline int netiucv_test_and_set_busy(struct net_device *dev)
{
+ struct netiucv_priv *priv = netdev_priv(dev);
netif_stop_queue(dev);
- return test_and_set_bit(0, &((struct netiucv_priv *)dev->priv)->tbusy);
+ return test_and_set_bit(0, &priv->tbusy);
}
-static __u8 iucv_host[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
-static __u8 iucvMagic[16] = {
+static u8 iucvMagic[16] = {
0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40
};
/**
- * This mask means the 16-byte IUCV "magic" and the origin userid must
- * match exactly as specified in order to give connection_pending()
- * control.
- */
-static __u8 netiucv_mask[] = {
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
-};
-
-/**
* Convert an iucv userId to its printable
* form (strip whitespace at end).
*
@@ -195,8 +280,7 @@ static __u8 netiucv_mask[] = {
*
* @returns The printable string (static data!!)
*/
-static __inline__ char *
-netiucv_printname(char *name)
+static inline char *netiucv_printname(char *name)
{
static char tmp[9];
char *p = tmp;
@@ -379,8 +463,7 @@ static debug_info_t *iucv_dbf_trace = NULL;
DEFINE_PER_CPU(char[256], iucv_dbf_txt_buf);
-static void
-iucv_unregister_dbf_views(void)
+static void iucv_unregister_dbf_views(void)
{
if (iucv_dbf_setup)
debug_unregister(iucv_dbf_setup);
@@ -389,8 +472,7 @@ iucv_unregister_dbf_views(void)
if (iucv_dbf_trace)
debug_unregister(iucv_dbf_trace);
}
-static int
-iucv_register_dbf_views(void)
+static int iucv_register_dbf_views(void)
{
iucv_dbf_setup = debug_register(IUCV_DBF_SETUP_NAME,
IUCV_DBF_SETUP_PAGES,
@@ -422,125 +504,111 @@ iucv_register_dbf_views(void)
return 0;
}
-/**
+/*
* Callback-wrappers, called from lowlevel iucv layer.
- *****************************************************************************/
+ */
-static void
-netiucv_callback_rx(iucv_MessagePending *eib, void *pgm_data)
+static void netiucv_callback_rx(struct iucv_path *path,
+ struct iucv_message *msg)
{
- struct iucv_connection *conn = (struct iucv_connection *)pgm_data;
+ struct iucv_connection *conn = path->private;
struct iucv_event ev;
ev.conn = conn;
- ev.data = (void *)eib;
-
+ ev.data = msg;
fsm_event(conn->fsm, CONN_EVENT_RX, &ev);
}
-static void
-netiucv_callback_txdone(iucv_MessageComplete *eib, void *pgm_data)
+static void netiucv_callback_txdone(struct iucv_path *path,
+ struct iucv_message *msg)
{
- struct iucv_connection *conn = (struct iucv_connection *)pgm_data;
+ struct iucv_connection *conn = path->private;
struct iucv_event ev;
ev.conn = conn;
- ev.data = (void *)eib;
+ ev.data = msg;
fsm_event(conn->fsm, CONN_EVENT_TXDONE, &ev);
}
-static void
-netiucv_callback_connack(iucv_ConnectionComplete *eib, void *pgm_data)
+static void netiucv_callback_connack(struct iucv_path *path, u8 ipuser[16])
{
- struct iucv_connection *conn = (struct iucv_connection *)pgm_data;
- struct iucv_event ev;
+ struct iucv_connection *conn = path->private;
- ev.conn = conn;
- ev.data = (void *)eib;
- fsm_event(conn->fsm, CONN_EVENT_CONN_ACK, &ev);
+ fsm_event(conn->fsm, CONN_EVENT_CONN_ACK, conn);
}
-static void
-netiucv_callback_connreq(iucv_ConnectionPending *eib, void *pgm_data)
+static int netiucv_callback_connreq(struct iucv_path *path,
+ u8 ipvmid[8], u8 ipuser[16])
{
- struct iucv_connection *conn = (struct iucv_connection *)pgm_data;
+ struct iucv_connection *conn = path->private;
struct iucv_event ev;
+ int rc;
- ev.conn = conn;
- ev.data = (void *)eib;
- fsm_event(conn->fsm, CONN_EVENT_CONN_REQ, &ev);
+ if (memcmp(iucvMagic, ipuser, sizeof(ipuser)))
+ /* ipuser must match iucvMagic. */
+ return -EINVAL;
+ rc = -EINVAL;
+ read_lock_bh(&iucv_connection_rwlock);
+ list_for_each_entry(conn, &iucv_connection_list, list) {
+ if (strncmp(ipvmid, conn->userid, 8))
+ continue;
+ /* Found a matching connection for this path. */
+ conn->path = path;
+ ev.conn = conn;
+ ev.data = path;
+ fsm_event(conn->fsm, CONN_EVENT_CONN_REQ, &ev);
+ rc = 0;
+ }
+ read_unlock_bh(&iucv_connection_rwlock);
+ return rc;
}
-static void
-netiucv_callback_connrej(iucv_ConnectionSevered *eib, void *pgm_data)
+static void netiucv_callback_connrej(struct iucv_path *path, u8 ipuser[16])
{
- struct iucv_connection *conn = (struct iucv_connection *)pgm_data;
- struct iucv_event ev;
+ struct iucv_connection *conn = path->private;
- ev.conn = conn;
- ev.data = (void *)eib;
- fsm_event(conn->fsm, CONN_EVENT_CONN_REJ, &ev);
+ fsm_event(conn->fsm, CONN_EVENT_CONN_REJ, conn);
}
-static void
-netiucv_callback_connsusp(iucv_ConnectionQuiesced *eib, void *pgm_data)
+static void netiucv_callback_connsusp(struct iucv_path *path, u8 ipuser[16])
{
- struct iucv_connection *conn = (struct iucv_connection *)pgm_data;
- struct iucv_event ev;
+ struct iucv_connection *conn = path->private;
- ev.conn = conn;
- ev.data = (void *)eib;
- fsm_event(conn->fsm, CONN_EVENT_CONN_SUS, &ev);
+ fsm_event(conn->fsm, CONN_EVENT_CONN_SUS, conn);
}
-static void
-netiucv_callback_connres(iucv_ConnectionResumed *eib, void *pgm_data)
+static void netiucv_callback_connres(struct iucv_path *path, u8 ipuser[16])
{
- struct iucv_connection *conn = (struct iucv_connection *)pgm_data;
- struct iucv_event ev;
+ struct iucv_connection *conn = path->private;
- ev.conn = conn;
- ev.data = (void *)eib;
- fsm_event(conn->fsm, CONN_EVENT_CONN_RES, &ev);
-}
-
-static iucv_interrupt_ops_t netiucv_ops = {
- .ConnectionPending = netiucv_callback_connreq,
- .ConnectionComplete = netiucv_callback_connack,
- .ConnectionSevered = netiucv_callback_connrej,
- .ConnectionQuiesced = netiucv_callback_connsusp,
- .ConnectionResumed = netiucv_callback_connres,
- .MessagePending = netiucv_callback_rx,
- .MessageComplete = netiucv_callback_txdone
-};
+ fsm_event(conn->fsm, CONN_EVENT_CONN_RES, conn);
+}
/**
* Dummy NOP action for all statemachines
*/
-static void
-fsm_action_nop(fsm_instance *fi, int event, void *arg)
+static void fsm_action_nop(fsm_instance *fi, int event, void *arg)
{
}
-/**
+/*
* Actions of the connection statemachine
- *****************************************************************************/
+ */
/**
- * Helper function for conn_action_rx()
- * Unpack a just received skb and hand it over to
- * upper layers.
+ * netiucv_unpack_skb
+ * @conn: The connection where this skb has been received.
+ * @pskb: The received skb.
*
- * @param conn The connection where this skb has been received.
- * @param pskb The received skb.
+ * Unpack a just received skb and hand it over to upper layers.
+ * Helper function for conn_action_rx.
*/
-//static __inline__ void
-static void
-netiucv_unpack_skb(struct iucv_connection *conn, struct sk_buff *pskb)
+static void netiucv_unpack_skb(struct iucv_connection *conn,
+ struct sk_buff *pskb)
{
struct net_device *dev = conn->netdev;
- struct netiucv_priv *privptr = dev->priv;
- __u16 offset = 0;
+ struct netiucv_priv *privptr = netdev_priv(dev);
+ u16 offset = 0;
skb_put(pskb, NETIUCV_HDRLEN);
pskb->dev = dev;
@@ -549,7 +617,7 @@ netiucv_unpack_skb(struct iucv_connection *conn, struct sk_buff *pskb)
while (1) {
struct sk_buff *skb;
- ll_header *header = (ll_header *)pskb->data;
+ struct ll_header *header = (struct ll_header *) pskb->data;
if (!header->next)
break;
@@ -595,40 +663,37 @@ netiucv_unpack_skb(struct iucv_connection *conn, struct sk_buff *pskb)
}
}
-static void
-conn_action_rx(fsm_instance *fi, int event, void *arg)
+static void conn_action_rx(fsm_instance *fi, int event, void *arg)
{
- struct iucv_event *ev = (struct iucv_event *)arg;
+ struct iucv_event *ev = arg;
struct iucv_connection *conn = ev->conn;
- iucv_MessagePending *eib = (iucv_MessagePending *)ev->data;
- struct netiucv_priv *privptr =(struct netiucv_priv *)conn->netdev->priv;
-
- __u32 msglen = eib->ln1msg2.ipbfln1f;
+ struct iucv_message *msg = ev->data;
+ struct netiucv_priv *privptr = netdev_priv(conn->netdev);
int rc;
IUCV_DBF_TEXT(trace, 4, __FUNCTION__);
if (!conn->netdev) {
- /* FRITZ: How to tell iucv LL to drop the msg? */
+ iucv_message_reject(conn->path, msg);
PRINT_WARN("Received data for unlinked connection\n");
IUCV_DBF_TEXT(data, 2,
- "Received data for unlinked connection\n");
+ "Received data for unlinked connection\n");
return;
}
- if (msglen > conn->max_buffsize) {
- /* FRITZ: How to tell iucv LL to drop the msg? */
+ if (msg->length > conn->max_buffsize) {
+ iucv_message_reject(conn->path, msg);
privptr->stats.rx_dropped++;
PRINT_WARN("msglen %d > max_buffsize %d\n",
- msglen, conn->max_buffsize);
+ msg->length, conn->max_buffsize);
IUCV_DBF_TEXT_(data, 2, "msglen %d > max_buffsize %d\n",
- msglen, conn->max_buffsize);
+ msg->length, conn->max_buffsize);
return;
}
conn->rx_buff->data = conn->rx_buff->tail = conn->rx_buff->head;
conn->rx_buff->len = 0;
- rc = iucv_receive(conn->pathid, eib->ipmsgid, eib->iptrgcls,
- conn->rx_buff->data, msglen, NULL, NULL, NULL);
- if (rc || msglen < 5) {
+ rc = iucv_message_receive(conn->path, msg, 0, conn->rx_buff->data,
+ msg->length, NULL);
+ if (rc || msg->length < 5) {
privptr->stats.rx_errors++;
PRINT_WARN("iucv_receive returned %08x\n", rc);
IUCV_DBF_TEXT_(data, 2, "rc %d from iucv_receive\n", rc);
@@ -637,26 +702,26 @@ conn_action_rx(fsm_instance *fi, int event, void *arg)
netiucv_unpack_skb(conn, conn->rx_buff);
}
-static void
-conn_action_txdone(fsm_instance *fi, int event, void *arg)
+static void conn_action_txdone(fsm_instance *fi, int event, void *arg)
{
- struct iucv_event *ev = (struct iucv_event *)arg;
+ struct iucv_event *ev = arg;
struct iucv_connection *conn = ev->conn;
- iucv_MessageComplete *eib = (iucv_MessageComplete *)ev->data;
+ struct iucv_message *msg = ev->data;
+ struct iucv_message txmsg;
struct netiucv_priv *privptr = NULL;
- /* Shut up, gcc! skb is always below 2G. */
- __u32 single_flag = eib->ipmsgtag;
- __u32 txbytes = 0;
- __u32 txpackets = 0;
- __u32 stat_maxcq = 0;
+ u32 single_flag = msg->tag;
+ u32 txbytes = 0;
+ u32 txpackets = 0;
+ u32 stat_maxcq = 0;
struct sk_buff *skb;
unsigned long saveflags;
- ll_header header;
+ struct ll_header header;
+ int rc;
IUCV_DBF_TEXT(trace, 4, __FUNCTION__);
- if (conn && conn->netdev && conn->netdev->priv)
- privptr = (struct netiucv_priv *)conn->netdev->priv;
+ if (conn && conn->netdev)
+ privptr = netdev_priv(conn->netdev);
conn->prof.tx_pending--;
if (single_flag) {
if ((skb = skb_dequeue(&conn->commit_queue))) {
@@ -688,56 +753,55 @@ conn_action_txdone(fsm_instance *fi, int event, void *arg)
conn->prof.maxmulti = conn->collect_len;
conn->collect_len = 0;
spin_unlock_irqrestore(&conn->collect_lock, saveflags);
- if (conn->tx_buff->len) {
- int rc;
-
- header.next = 0;
- memcpy(skb_put(conn->tx_buff, NETIUCV_HDRLEN), &header,
- NETIUCV_HDRLEN);
+ if (conn->tx_buff->len == 0) {
+ fsm_newstate(fi, CONN_STATE_IDLE);
+ return;
+ }
- conn->prof.send_stamp = xtime;
- rc = iucv_send(conn->pathid, NULL, 0, 0, 0, 0,
+ header.next = 0;
+ memcpy(skb_put(conn->tx_buff, NETIUCV_HDRLEN), &header, NETIUCV_HDRLEN);
+ conn->prof.send_stamp = xtime;
+ txmsg.class = 0;
+ txmsg.tag = 0;
+ rc = iucv_message_send(conn->path, &txmsg, 0, 0,
conn->tx_buff->data, conn->tx_buff->len);
- conn->prof.doios_multi++;
- conn->prof.txlen += conn->tx_buff->len;
- conn->prof.tx_pending++;
- if (conn->prof.tx_pending > conn->prof.tx_max_pending)
- conn->prof.tx_max_pending = conn->prof.tx_pending;
- if (rc) {
- conn->prof.tx_pending--;
- fsm_newstate(fi, CONN_STATE_IDLE);
- if (privptr)
- privptr->stats.tx_errors += txpackets;
- PRINT_WARN("iucv_send returned %08x\n", rc);
- IUCV_DBF_TEXT_(data, 2, "rc %d from iucv_send\n", rc);
- } else {
- if (privptr) {
- privptr->stats.tx_packets += txpackets;
- privptr->stats.tx_bytes += txbytes;
- }
- if (stat_maxcq > conn->prof.maxcqueue)
- conn->prof.maxcqueue = stat_maxcq;
- }
- } else
+ conn->prof.doios_multi++;
+ conn->prof.txlen += conn->tx_buff->len;
+ conn->prof.tx_pending++;
+ if (conn->prof.tx_pending > conn->prof.tx_max_pending)
+ conn->prof.tx_max_pending = conn->prof.tx_pending;
+ if (rc) {
+ conn->prof.tx_pending--;
fsm_newstate(fi, CONN_STATE_IDLE);
+ if (privptr)
+ privptr->stats.tx_errors += txpackets;
+ PRINT_WARN("iucv_send returned %08x\n", rc);
+ IUCV_DBF_TEXT_(data, 2, "rc %d from iucv_send\n", rc);
+ } else {
+ if (privptr) {
+ privptr->stats.tx_packets += txpackets;
+ privptr->stats.tx_bytes += txbytes;
+ }
+ if (stat_maxcq > conn->prof.maxcqueue)
+ conn->prof.maxcqueue = stat_maxcq;
+ }
}
-static void
-conn_action_connaccept(fsm_instance *fi, int event, void *arg)
+static void conn_action_connaccept(fsm_instance *fi, int event, void *arg)
{
- struct iucv_event *ev = (struct iucv_event *)arg;
+ struct iucv_event *ev = arg;
struct iucv_connection *conn = ev->conn;
- iucv_ConnectionPending *eib = (iucv_ConnectionPending *)ev->data;
+ struct iucv_path *path = ev->data;
struct net_device *netdev = conn->netdev;
- struct netiucv_priv *privptr = (struct netiucv_priv *)netdev->priv;
+ struct netiucv_priv *privptr = netdev_priv(netdev);
int rc;
- __u16 msglimit;
- __u8 udata[16];
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
- rc = iucv_accept(eib->ippathid, NETIUCV_QUEUELEN_DEFAULT, udata, 0,
- conn->handle, conn, NULL, &msglimit);
+ conn->path = path;
+ path->msglim = NETIUCV_QUEUELEN_DEFAULT;
+ path->flags = 0;
+ rc = iucv_path_accept(path, &netiucv_handler, NULL, conn);
if (rc) {
PRINT_WARN("%s: IUCV accept failed with error %d\n",
netdev->name, rc);
@@ -745,183 +809,126 @@ conn_action_connaccept(fsm_instance *fi, int event, void *arg)
return;
}
fsm_newstate(fi, CONN_STATE_IDLE);
- conn->pathid = eib->ippathid;
- netdev->tx_queue_len = msglimit;
+ netdev->tx_queue_len = conn->path->msglim;
fsm_event(privptr->fsm, DEV_EVENT_CONUP, netdev);
}
-static void
-conn_action_connreject(fsm_instance *fi, int event, void *arg)
+static void conn_action_connreject(fsm_instance *fi, int event, void *arg)
{
- struct iucv_event *ev = (struct iucv_event *)arg;
- struct iucv_connection *conn = ev->conn;
- struct net_device *netdev = conn->netdev;
- iucv_ConnectionPending *eib = (iucv_ConnectionPending *)ev->data;
- __u8 udata[16];
+ struct iucv_event *ev = arg;
+ struct iucv_path *path = ev->data;
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
-
- iucv_sever(eib->ippathid, udata);
- if (eib->ippathid != conn->pathid) {
- PRINT_INFO("%s: IR Connection Pending; "
- "pathid %d does not match original pathid %d\n",
- netdev->name, eib->ippathid, conn->pathid);
- IUCV_DBF_TEXT_(data, 2,
- "connreject: IR pathid %d, conn. pathid %d\n",
- eib->ippathid, conn->pathid);
- iucv_sever(conn->pathid, udata);
- }
+ iucv_path_sever(path, NULL);
}
-static void
-conn_action_connack(fsm_instance *fi, int event, void *arg)
+static void conn_action_connack(fsm_instance *fi, int event, void *arg)
{
- struct iucv_event *ev = (struct iucv_event *)arg;
- struct iucv_connection *conn = ev->conn;
- iucv_ConnectionComplete *eib = (iucv_ConnectionComplete *)ev->data;
+ struct iucv_connection *conn = arg;
struct net_device *netdev = conn->netdev;
- struct netiucv_priv *privptr = (struct netiucv_priv *)netdev->priv;
+ struct netiucv_priv *privptr = netdev_priv(netdev);
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
-
fsm_deltimer(&conn->timer);
fsm_newstate(fi, CONN_STATE_IDLE);
- if (eib->ippathid != conn->pathid) {
- PRINT_INFO("%s: IR Connection Complete; "
- "pathid %d does not match original pathid %d\n",
- netdev->name, eib->ippathid, conn->pathid);
- IUCV_DBF_TEXT_(data, 2,
- "connack: IR pathid %d, conn. pathid %d\n",
- eib->ippathid, conn->pathid);
- conn->pathid = eib->ippathid;
- }
- netdev->tx_queue_len = eib->ipmsglim;
+ netdev->tx_queue_len = conn->path->msglim;
fsm_event(privptr->fsm, DEV_EVENT_CONUP, netdev);
}
-static void
-conn_action_conntimsev(fsm_instance *fi, int event, void *arg)
+static void conn_action_conntimsev(fsm_instance *fi, int event, void *arg)
{
- struct iucv_connection *conn = (struct iucv_connection *)arg;
- __u8 udata[16];
+ struct iucv_connection *conn = arg;
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
-
fsm_deltimer(&conn->timer);
- iucv_sever(conn->pathid, udata);
+ iucv_path_sever(conn->path, NULL);
fsm_newstate(fi, CONN_STATE_STARTWAIT);
}
-static void
-conn_action_connsever(fsm_instance *fi, int event, void *arg)
+static void conn_action_connsever(fsm_instance *fi, int event, void *arg)
{
- struct iucv_event *ev = (struct iucv_event *)arg;
- struct iucv_connection *conn = ev->conn;
+ struct iucv_connection *conn = arg;
struct net_device *netdev = conn->netdev;
- struct netiucv_priv *privptr = (struct netiucv_priv *)netdev->priv;
- __u8 udata[16];
+ struct netiucv_priv *privptr = netdev_priv(netdev);
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
fsm_deltimer(&conn->timer);
- iucv_sever(conn->pathid, udata);
+ iucv_path_sever(conn->path, NULL);
PRINT_INFO("%s: Remote dropped connection\n", netdev->name);
IUCV_DBF_TEXT(data, 2,
- "conn_action_connsever: Remote dropped connection\n");
+ "conn_action_connsever: Remote dropped connection\n");
fsm_newstate(fi, CONN_STATE_STARTWAIT);
fsm_event(privptr->fsm, DEV_EVENT_CONDOWN, netdev);
}
-static void
-conn_action_start(fsm_instance *fi, int event, void *arg)
+static void conn_action_start(fsm_instance *fi, int event, void *arg)
{
- struct iucv_event *ev = (struct iucv_event *)arg;
- struct iucv_connection *conn = ev->conn;
- __u16 msglimit;
+ struct iucv_connection *conn = arg;
int rc;
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
- if (!conn->handle) {
- IUCV_DBF_TEXT(trace, 5, "calling iucv_register_program\n");
- conn->handle =
- iucv_register_program(iucvMagic, conn->userid,
- netiucv_mask,
- &netiucv_ops, conn);
- fsm_newstate(fi, CONN_STATE_STARTWAIT);
- if (!conn->handle) {
- fsm_newstate(fi, CONN_STATE_REGERR);
- conn->handle = NULL;
- IUCV_DBF_TEXT(setup, 2,
- "NULL from iucv_register_program\n");
- return;
- }
-
- PRINT_DEBUG("%s('%s'): registered successfully\n",
- conn->netdev->name, conn->userid);
- }
-
+ fsm_newstate(fi, CONN_STATE_STARTWAIT);
PRINT_DEBUG("%s('%s'): connecting ...\n",
- conn->netdev->name, conn->userid);
+ conn->netdev->name, conn->userid);
- /* We must set the state before calling iucv_connect because the callback
- * handler could be called at any point after the connection request is
- * sent */
+ /*
+ * We must set the state before calling iucv_connect because the
+ * callback handler could be called at any point after the connection
+ * request is sent
+ */
fsm_newstate(fi, CONN_STATE_SETUPWAIT);
- rc = iucv_connect(&(conn->pathid), NETIUCV_QUEUELEN_DEFAULT, iucvMagic,
- conn->userid, iucv_host, 0, NULL, &msglimit,
- conn->handle, conn);
+ conn->path = iucv_path_alloc(NETIUCV_QUEUELEN_DEFAULT, 0, GFP_KERNEL);
+ rc = iucv_path_connect(conn->path, &netiucv_handler, conn->userid,
+ NULL, iucvMagic, conn);
switch (rc) {
- case 0:
- conn->netdev->tx_queue_len = msglimit;
- fsm_addtimer(&conn->timer, NETIUCV_TIMEOUT_5SEC,
- CONN_EVENT_TIMER, conn);
- return;
- case 11:
- PRINT_INFO("%s: User %s is currently not available.\n",
- conn->netdev->name,
- netiucv_printname(conn->userid));
- fsm_newstate(fi, CONN_STATE_STARTWAIT);
- return;
- case 12:
- PRINT_INFO("%s: User %s is currently not ready.\n",
- conn->netdev->name,
- netiucv_printname(conn->userid));
- fsm_newstate(fi, CONN_STATE_STARTWAIT);
- return;
- case 13:
- PRINT_WARN("%s: Too many IUCV connections.\n",
- conn->netdev->name);
- fsm_newstate(fi, CONN_STATE_CONNERR);
- break;
- case 14:
- PRINT_WARN(
- "%s: User %s has too many IUCV connections.\n",
- conn->netdev->name,
- netiucv_printname(conn->userid));
- fsm_newstate(fi, CONN_STATE_CONNERR);
- break;
- case 15:
- PRINT_WARN(
- "%s: No IUCV authorization in CP directory.\n",
- conn->netdev->name);
- fsm_newstate(fi, CONN_STATE_CONNERR);
- break;
- default:
- PRINT_WARN("%s: iucv_connect returned error %d\n",
- conn->netdev->name, rc);
- fsm_newstate(fi, CONN_STATE_CONNERR);
- break;
+ case 0:
+ conn->netdev->tx_queue_len = conn->path->msglim;
+ fsm_addtimer(&conn->timer, NETIUCV_TIMEOUT_5SEC,
+ CONN_EVENT_TIMER, conn);
+ return;
+ case 11:
+ PRINT_INFO("%s: User %s is currently not available.\n",
+ conn->netdev->name,
+ netiucv_printname(conn->userid));
+ fsm_newstate(fi, CONN_STATE_STARTWAIT);
+ break;
+ case 12:
+ PRINT_INFO("%s: User %s is currently not ready.\n",
+ conn->netdev->name,
+ netiucv_printname(conn->userid));
+ fsm_newstate(fi, CONN_STATE_STARTWAIT);
+ break;
+ case 13:
+ PRINT_WARN("%s: Too many IUCV connections.\n",
+ conn->netdev->name);
+ fsm_newstate(fi, CONN_STATE_CONNERR);
+ break;
+ case 14:
+ PRINT_WARN("%s: User %s has too many IUCV connections.\n",
+ conn->netdev->name,
+ netiucv_printname(conn->userid));
+ fsm_newstate(fi, CONN_STATE_CONNERR);
+ break;
+ case 15:
+ PRINT_WARN("%s: No IUCV authorization in CP directory.\n",
+ conn->netdev->name);
+ fsm_newstate(fi, CONN_STATE_CONNERR);
+ break;
+ default:
+ PRINT_WARN("%s: iucv_connect returned error %d\n",
+ conn->netdev->name, rc);
+ fsm_newstate(fi, CONN_STATE_CONNERR);
+ break;
}
IUCV_DBF_TEXT_(setup, 5, "iucv_connect rc is %d\n", rc);
- IUCV_DBF_TEXT(trace, 5, "calling iucv_unregister_program\n");
- iucv_unregister_program(conn->handle);
- conn->handle = NULL;
+ kfree(conn->path);
+ conn->path = NULL;
}
-static void
-netiucv_purge_skb_queue(struct sk_buff_head *q)
+static void netiucv_purge_skb_queue(struct sk_buff_head *q)
{
struct sk_buff *skb;
@@ -931,36 +938,34 @@ netiucv_purge_skb_queue(struct sk_buff_head *q)
}
}
-static void
-conn_action_stop(fsm_instance *fi, int event, void *arg)
+static void conn_action_stop(fsm_instance *fi, int event, void *arg)
{
- struct iucv_event *ev = (struct iucv_event *)arg;
+ struct iucv_event *ev = arg;
struct iucv_connection *conn = ev->conn;
struct net_device *netdev = conn->netdev;
- struct netiucv_priv *privptr = (struct netiucv_priv *)netdev->priv;
+ struct netiucv_priv *privptr = netdev_priv(netdev);
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
fsm_deltimer(&conn->timer);
fsm_newstate(fi, CONN_STATE_STOPPED);
netiucv_purge_skb_queue(&conn->collect_queue);
- if (conn->handle)
- IUCV_DBF_TEXT(trace, 5, "calling iucv_unregister_program\n");
- iucv_unregister_program(conn->handle);
- conn->handle = NULL;
+ if (conn->path) {
+ IUCV_DBF_TEXT(trace, 5, "calling iucv_path_sever\n");
+ iucv_path_sever(conn->path, iucvMagic);
+ kfree(conn->path);
+ conn->path = NULL;
+ }
netiucv_purge_skb_queue(&conn->commit_queue);
fsm_event(privptr->fsm, DEV_EVENT_CONDOWN, netdev);
}
-static void
-conn_action_inval(fsm_instance *fi, int event, void *arg)
+static void conn_action_inval(fsm_instance *fi, int event, void *arg)
{
- struct iucv_event *ev = (struct iucv_event *)arg;
- struct iucv_connection *conn = ev->conn;
+ struct iucv_connection *conn = arg;
struct net_device *netdev = conn->netdev;
- PRINT_WARN("%s: Cannot connect without username\n",
- netdev->name);
+ PRINT_WARN("%s: Cannot connect without username\n", netdev->name);
IUCV_DBF_TEXT(data, 2, "conn_action_inval called\n");
}
@@ -999,29 +1004,27 @@ static const fsm_node conn_fsm[] = {
static const int CONN_FSM_LEN = sizeof(conn_fsm) / sizeof(fsm_node);
-/**
+/*
* Actions for interface - statemachine.
- *****************************************************************************/
+ */
/**
- * Startup connection by sending CONN_EVENT_START to it.
+ * dev_action_start
+ * @fi: An instance of an interface statemachine.
+ * @event: The event, just happened.
+ * @arg: Generic pointer, casted from struct net_device * upon call.
*
- * @param fi An instance of an interface statemachine.
- * @param event The event, just happened.
- * @param arg Generic pointer, casted from struct net_device * upon call.
+ * Startup connection by sending CONN_EVENT_START to it.
*/
-static void
-dev_action_start(fsm_instance *fi, int event, void *arg)
+static void dev_action_start(fsm_instance *fi, int event, void *arg)
{
- struct net_device *dev = (struct net_device *)arg;
- struct netiucv_priv *privptr = dev->priv;
- struct iucv_event ev;
+ struct net_device *dev = arg;
+ struct netiucv_priv *privptr = netdev_priv(dev);
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
- ev.conn = privptr->conn;
fsm_newstate(fi, DEV_STATE_STARTWAIT);
- fsm_event(privptr->conn->fsm, CONN_EVENT_START, &ev);
+ fsm_event(privptr->conn->fsm, CONN_EVENT_START, privptr->conn);
}
/**
@@ -1034,8 +1037,8 @@ dev_action_start(fsm_instance *fi, int event, void *arg)
static void
dev_action_stop(fsm_instance *fi, int event, void *arg)
{
- struct net_device *dev = (struct net_device *)arg;
- struct netiucv_priv *privptr = dev->priv;
+ struct net_device *dev = arg;
+ struct netiucv_priv *privptr = netdev_priv(dev);
struct iucv_event ev;
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
@@ -1057,8 +1060,8 @@ dev_action_stop(fsm_instance *fi, int event, void *arg)
static void
dev_action_connup(fsm_instance *fi, int event, void *arg)
{
- struct net_device *dev = (struct net_device *)arg;
- struct netiucv_priv *privptr = dev->priv;
+ struct net_device *dev = arg;
+ struct netiucv_priv *privptr = netdev_priv(dev);
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
@@ -1131,11 +1134,13 @@ static const int DEV_FSM_LEN = sizeof(dev_fsm) / sizeof(fsm_node);
*
* @return 0 on success, -ERRNO on failure. (Never fails.)
*/
-static int
-netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) {
+static int netiucv_transmit_skb(struct iucv_connection *conn,
+ struct sk_buff *skb)
+{
+ struct iucv_message msg;
unsigned long saveflags;
- ll_header header;
- int rc = 0;
+ struct ll_header header;
+ int rc;
if (fsm_getstate(conn->fsm) != CONN_STATE_IDLE) {
int l = skb->len + NETIUCV_HDRLEN;
@@ -1145,11 +1150,12 @@ netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) {
(conn->max_buffsize - NETIUCV_HDRLEN)) {
rc = -EBUSY;
IUCV_DBF_TEXT(data, 2,
- "EBUSY from netiucv_transmit_skb\n");
+ "EBUSY from netiucv_transmit_skb\n");
} else {
atomic_inc(&skb->users);
skb_queue_tail(&conn->collect_queue, skb);
conn->collect_len += l;
+ rc = 0;
}
spin_unlock_irqrestore(&conn->collect_lock, saveflags);
} else {
@@ -1188,9 +1194,10 @@ netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) {
fsm_newstate(conn->fsm, CONN_STATE_TX);
conn->prof.send_stamp = xtime;
- rc = iucv_send(conn->pathid, NULL, 0, 0, 1 /* single_flag */,
- 0, nskb->data, nskb->len);
- /* Shut up, gcc! nskb is always below 2G. */
+ msg.tag = 1;
+ msg.class = 0;
+ rc = iucv_message_send(conn->path, &msg, 0, 0,
+ nskb->data, nskb->len);
conn->prof.doios_single++;
conn->prof.txlen += skb->len;
conn->prof.tx_pending++;
@@ -1200,7 +1207,7 @@ netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) {
struct netiucv_priv *privptr;
fsm_newstate(conn->fsm, CONN_STATE_IDLE);
conn->prof.tx_pending--;
- privptr = (struct netiucv_priv *)conn->netdev->priv;
+ privptr = netdev_priv(conn->netdev);
if (privptr)
privptr->stats.tx_errors++;
if (copied)
@@ -1226,9 +1233,9 @@ netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) {
return rc;
}
-/**
+/*
* Interface API for upper network layers
- *****************************************************************************/
+ */
/**
* Open an interface.
@@ -1238,9 +1245,11 @@ netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) {
*
* @return 0 on success, -ERRNO on failure. (Never fails.)
*/
-static int
-netiucv_open(struct net_device *dev) {
- fsm_event(((struct netiucv_priv *)dev->priv)->fsm, DEV_EVENT_START,dev);
+static int netiucv_open(struct net_device *dev)
+{
+ struct netiucv_priv *priv = netdev_priv(dev);
+
+ fsm_event(priv->fsm, DEV_EVENT_START, dev);
return 0;
}
@@ -1252,9 +1261,11 @@ netiucv_open(struct net_device *dev) {
*
* @return 0 on success, -ERRNO on failure. (Never fails.)
*/
-static int
-netiucv_close(struct net_device *dev) {
- fsm_event(((struct netiucv_priv *)dev->priv)->fsm, DEV_EVENT_STOP, dev);
+static int netiucv_close(struct net_device *dev)
+{
+ struct netiucv_priv *priv = netdev_priv(dev);
+
+ fsm_event(priv->fsm, DEV_EVENT_STOP, dev);
return 0;
}
@@ -1271,8 +1282,8 @@ netiucv_close(struct net_device *dev) {
*/
static int netiucv_tx(struct sk_buff *skb, struct net_device *dev)
{
- int rc = 0;
- struct netiucv_priv *privptr = dev->priv;
+ struct netiucv_priv *privptr = netdev_priv(dev);
+ int rc;
IUCV_DBF_TEXT(trace, 4, __FUNCTION__);
/**
@@ -1312,40 +1323,41 @@ static int netiucv_tx(struct sk_buff *skb, struct net_device *dev)
return -EBUSY;
}
dev->trans_start = jiffies;
- if (netiucv_transmit_skb(privptr->conn, skb))
- rc = 1;
+ rc = netiucv_transmit_skb(privptr->conn, skb) != 0;
netiucv_clear_busy(dev);
return rc;
}
/**
- * Returns interface statistics of a device.
+ * netiucv_stats
+ * @dev: Pointer to interface struct.
*
- * @param dev Pointer to interface struct.
+ * Returns interface statistics of a device.
*
- * @return Pointer to stats struct of this interface.
+ * Returns pointer to stats struct of this interface.
*/
-static struct net_device_stats *
-netiucv_stats (struct net_device * dev)
+static struct net_device_stats *netiucv_stats (struct net_device * dev)
{
+ struct netiucv_priv *priv = netdev_priv(dev);
+
IUCV_DBF_TEXT(trace, 5, __FUNCTION__);
- return &((struct netiucv_priv *)dev->priv)->stats;
+ return &priv->stats;
}
/**
- * Sets MTU of an interface.
+ * netiucv_change_mtu
+ * @dev: Pointer to interface struct.
+ * @new_mtu: The new MTU to use for this interface.
*
- * @param dev Pointer to interface struct.
- * @param new_mtu The new MTU to use for this interface.
+ * Sets MTU of an interface.
*
- * @return 0 on success, -EINVAL if MTU is out of valid range.
+ * Returns 0 on success, -EINVAL if MTU is out of valid range.
* (valid range is 576 .. NETIUCV_MTU_MAX).
*/
-static int
-netiucv_change_mtu (struct net_device * dev, int new_mtu)
+static int netiucv_change_mtu(struct net_device * dev, int new_mtu)
{
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
- if ((new_mtu < 576) || (new_mtu > NETIUCV_MTU_MAX)) {
+ if (new_mtu < 576 || new_mtu > NETIUCV_MTU_MAX) {
IUCV_DBF_TEXT(setup, 2, "given MTU out of valid range\n");
return -EINVAL;
}
@@ -1353,12 +1365,12 @@ netiucv_change_mtu (struct net_device * dev, int new_mtu)
return 0;
}
-/**
+/*
* attributes in sysfs
- *****************************************************************************/
+ */
-static ssize_t
-user_show (struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t user_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct netiucv_priv *priv = dev->driver_data;
@@ -1366,8 +1378,8 @@ user_show (struct device *dev, struct device_attribute *attr, char *buf)
return sprintf(buf, "%s\n", netiucv_printname(priv->conn->userid));
}
-static ssize_t
-user_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t user_write(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct netiucv_priv *priv = dev->driver_data;
struct net_device *ndev = priv->conn->netdev;
@@ -1375,80 +1387,70 @@ user_write (struct device *dev, struct device_attribute *attr, const char *buf,
char *tmp;
char username[9];
int i;
- struct iucv_connection **clist = &iucv_conns.iucv_connections;
- unsigned long flags;
+ struct iucv_connection *cp;
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
- if (count>9) {
- PRINT_WARN("netiucv: username too long (%d)!\n", (int)count);
+ if (count > 9) {
+ PRINT_WARN("netiucv: username too long (%d)!\n", (int) count);
IUCV_DBF_TEXT_(setup, 2,
- "%d is length of username\n", (int)count);
+ "%d is length of username\n", (int) count);
return -EINVAL;
}
tmp = strsep((char **) &buf, "\n");
- for (i=0, p=tmp; i<8 && *p; i++, p++) {
- if (isalnum(*p) || (*p == '$'))
+ for (i = 0, p = tmp; i < 8 && *p; i++, p++) {
+ if (isalnum(*p) || (*p == '$')) {
username[i]= toupper(*p);
- else if (*p == '\n') {
+ continue;
+ }
+ if (*p == '\n') {
/* trailing lf, grr */
break;
- } else {
- PRINT_WARN("netiucv: Invalid char %c in username!\n",
- *p);
- IUCV_DBF_TEXT_(setup, 2,
- "username: invalid character %c\n",
- *p);
- return -EINVAL;
}
+ PRINT_WARN("netiucv: Invalid char %c in username!\n", *p);
+ IUCV_DBF_TEXT_(setup, 2,
+ "username: invalid character %c\n", *p);
+ return -EINVAL;
}
- while (i<8)
+ while (i < 8)
username[i++] = ' ';
username[8] = '\0';
- if (memcmp(username, priv->conn->userid, 9)) {
- /* username changed */
- if (ndev->flags & (IFF_UP | IFF_RUNNING)) {
- PRINT_WARN(
- "netiucv: device %s active, connected to %s\n",
- dev->bus_id, priv->conn->userid);
- PRINT_WARN("netiucv: user cannot be updated\n");
- IUCV_DBF_TEXT(setup, 2, "user_write: device active\n");
- return -EBUSY;
+ if (memcmp(username, priv->conn->userid, 9) &&
+ (ndev->flags & (IFF_UP | IFF_RUNNING))) {
+ /* username changed while the interface is active. */
+ PRINT_WARN("netiucv: device %s active, connected to %s\n",
+ dev->bus_id, priv->conn->userid);
+ PRINT_WARN("netiucv: user cannot be updated\n");
+ IUCV_DBF_TEXT(setup, 2, "user_write: device active\n");
+ return -EBUSY;
+ }
+ read_lock_bh(&iucv_connection_rwlock);
+ list_for_each_entry(cp, &iucv_connection_list, list) {
+ if (!strncmp(username, cp->userid, 9) && cp->netdev != ndev) {
+ read_unlock_bh(&iucv_connection_rwlock);
+ PRINT_WARN("netiucv: Connection to %s already "
+ "exists\n", username);
+ return -EEXIST;
}
}
- read_lock_irqsave(&iucv_conns.iucv_rwlock, flags);
- while (*clist) {
- if (!strncmp(username, (*clist)->userid, 9) ||
- ((*clist)->netdev != ndev))
- break;
- clist = &((*clist)->next);
- }
- read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags);
- if (*clist) {
- PRINT_WARN("netiucv: Connection to %s already exists\n",
- username);
- return -EEXIST;
- }
+ read_unlock_bh(&iucv_connection_rwlock);
memcpy(priv->conn->userid, username, 9);
-
return count;
-
}
static DEVICE_ATTR(user, 0644, user_show, user_write);
-static ssize_t
-buffer_show (struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct netiucv_priv *priv = dev->driver_data;
+static ssize_t buffer_show (struct device *dev, struct device_attribute *attr,
+ char *buf)
+{ struct netiucv_priv *priv = dev->driver_data;
IUCV_DBF_TEXT(trace, 5, __FUNCTION__);
return sprintf(buf, "%d\n", priv->conn->max_buffsize);
}
-static ssize_t
-buffer_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t buffer_write (struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct netiucv_priv *priv = dev->driver_data;
struct net_device *ndev = priv->conn->netdev;
@@ -1502,8 +1504,8 @@ buffer_write (struct device *dev, struct device_attribute *attr, const char *buf
static DEVICE_ATTR(buffer, 0644, buffer_show, buffer_write);
-static ssize_t
-dev_fsm_show (struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t dev_fsm_show (struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct netiucv_priv *priv = dev->driver_data;
@@ -1513,8 +1515,8 @@ dev_fsm_show (struct device *dev, struct device_attribute *attr, char *buf)
static DEVICE_ATTR(device_fsm_state, 0444, dev_fsm_show, NULL);
-static ssize_t
-conn_fsm_show (struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t conn_fsm_show (struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct netiucv_priv *priv = dev->driver_data;
@@ -1524,8 +1526,8 @@ conn_fsm_show (struct device *dev, struct device_attribute *attr, char *buf)
static DEVICE_ATTR(connection_fsm_state, 0444, conn_fsm_show, NULL);
-static ssize_t
-maxmulti_show (struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t maxmulti_show (struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct netiucv_priv *priv = dev->driver_data;
@@ -1533,8 +1535,9 @@ maxmulti_show (struct device *dev, struct device_attribute *attr, char *buf)
return sprintf(buf, "%ld\n", priv->conn->prof.maxmulti);
}
-static ssize_t
-maxmulti_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t maxmulti_write (struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct netiucv_priv *priv = dev->driver_data;
@@ -1545,8 +1548,8 @@ maxmulti_write (struct device *dev, struct device_attribute *attr, const char *b
static DEVICE_ATTR(max_tx_buffer_used, 0644, maxmulti_show, maxmulti_write);
-static ssize_t
-maxcq_show (struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t maxcq_show (struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct netiucv_priv *priv = dev->driver_data;
@@ -1554,8 +1557,8 @@ maxcq_show (struct device *dev, struct device_attribute *attr, char *buf)
return sprintf(buf, "%ld\n", priv->conn->prof.maxcqueue);
}
-static ssize_t
-maxcq_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t maxcq_write (struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct netiucv_priv *priv = dev->driver_data;
@@ -1566,8 +1569,8 @@ maxcq_write (struct device *dev, struct device_attribute *attr, const char *buf,
static DEVICE_ATTR(max_chained_skbs, 0644, maxcq_show, maxcq_write);
-static ssize_t
-sdoio_show (struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t sdoio_show (struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct netiucv_priv *priv = dev->driver_data;
@@ -1575,8 +1578,8 @@ sdoio_show (struct device *dev, struct device_attribute *attr, char *buf)
return sprintf(buf, "%ld\n", priv->conn->prof.doios_single);
}
-static ssize_t
-sdoio_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t sdoio_write (struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct netiucv_priv *priv = dev->driver_data;
@@ -1587,8 +1590,8 @@ sdoio_write (struct device *dev, struct device_attribute *attr, const char *buf,
static DEVICE_ATTR(tx_single_write_ops, 0644, sdoio_show, sdoio_write);
-static ssize_t
-mdoio_show (struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t mdoio_show (struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct netiucv_priv *priv = dev->driver_data;
@@ -1596,8 +1599,8 @@ mdoio_show (struct device *dev, struct device_attribute *attr, char *buf)
return sprintf(buf, "%ld\n", priv->conn->prof.doios_multi);
}
-static ssize_t
-mdoio_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t mdoio_write (struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct netiucv_priv *priv = dev->driver_data;
@@ -1608,8 +1611,8 @@ mdoio_write (struct device *dev, struct device_attribute *attr, const char *buf,
static DEVICE_ATTR(tx_multi_write_ops, 0644, mdoio_show, mdoio_write);
-static ssize_t
-txlen_show (struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t txlen_show (struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct netiucv_priv *priv = dev->driver_data;
@@ -1617,8 +1620,8 @@ txlen_show (struct device *dev, struct device_attribute *attr, char *buf)
return sprintf(buf, "%ld\n", priv->conn->prof.txlen);
}
-static ssize_t
-txlen_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t txlen_write (struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct netiucv_priv *priv = dev->driver_data;
@@ -1629,8 +1632,8 @@ txlen_write (struct device *dev, struct device_attribute *attr, const char *buf,
static DEVICE_ATTR(netto_bytes, 0644, txlen_show, txlen_write);
-static ssize_t
-txtime_show (struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t txtime_show (struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct netiucv_priv *priv = dev->driver_data;
@@ -1638,8 +1641,8 @@ txtime_show (struct device *dev, struct device_attribute *attr, char *buf)
return sprintf(buf, "%ld\n", priv->conn->prof.tx_time);
}
-static ssize_t
-txtime_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t txtime_write (struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct netiucv_priv *priv = dev->driver_data;
@@ -1650,8 +1653,8 @@ txtime_write (struct device *dev, struct device_attribute *attr, const char *buf
static DEVICE_ATTR(max_tx_io_time, 0644, txtime_show, txtime_write);
-static ssize_t
-txpend_show (struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t txpend_show (struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct netiucv_priv *priv = dev->driver_data;
@@ -1659,8 +1662,8 @@ txpend_show (struct device *dev, struct device_attribute *attr, char *buf)
return sprintf(buf, "%ld\n", priv->conn->prof.tx_pending);
}
-static ssize_t
-txpend_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t txpend_write (struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct netiucv_priv *priv = dev->driver_data;
@@ -1671,8 +1674,8 @@ txpend_write (struct device *dev, struct device_attribute *attr, const char *buf
static DEVICE_ATTR(tx_pending, 0644, txpend_show, txpend_write);
-static ssize_t
-txmpnd_show (struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t txmpnd_show (struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct netiucv_priv *priv = dev->driver_data;
@@ -1680,8 +1683,8 @@ txmpnd_show (struct device *dev, struct device_attribute *attr, char *buf)
return sprintf(buf, "%ld\n", priv->conn->prof.tx_max_pending);
}
-static ssize_t
-txmpnd_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t txmpnd_write (struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct netiucv_priv *priv = dev->driver_data;
@@ -1721,8 +1724,7 @@ static struct attribute_group netiucv_stat_attr_group = {
.attrs = netiucv_stat_attrs,
};
-static inline int
-netiucv_add_files(struct device *dev)
+static inline int netiucv_add_files(struct device *dev)
{
int ret;
@@ -1736,18 +1738,16 @@ netiucv_add_files(struct device *dev)
return ret;
}
-static inline void
-netiucv_remove_files(struct device *dev)
+static inline void netiucv_remove_files(struct device *dev)
{
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
sysfs_remove_group(&dev->kobj, &netiucv_stat_attr_group);
sysfs_remove_group(&dev->kobj, &netiucv_attr_group);
}
-static int
-netiucv_register_device(struct net_device *ndev)
+static int netiucv_register_device(struct net_device *ndev)
{
- struct netiucv_priv *priv = ndev->priv;
+ struct netiucv_priv *priv = netdev_priv(ndev);
struct device *dev = kzalloc(sizeof(struct device), GFP_KERNEL);
int ret;
@@ -1786,8 +1786,7 @@ out_unreg:
return ret;
}
-static void
-netiucv_unregister_device(struct device *dev)
+static void netiucv_unregister_device(struct device *dev)
{
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
netiucv_remove_files(dev);
@@ -1798,107 +1797,89 @@ netiucv_unregister_device(struct device *dev)
* Allocate and initialize a new connection structure.
* Add it to the list of netiucv connections;
*/
-static struct iucv_connection *
-netiucv_new_connection(struct net_device *dev, char *username)
-{
- unsigned long flags;
- struct iucv_connection **clist = &iucv_conns.iucv_connections;
- struct iucv_connection *conn =
- kzalloc(sizeof(struct iucv_connection), GFP_KERNEL);
-
- if (conn) {
- skb_queue_head_init(&conn->collect_queue);
- skb_queue_head_init(&conn->commit_queue);
- spin_lock_init(&conn->collect_lock);
- conn->max_buffsize = NETIUCV_BUFSIZE_DEFAULT;
- conn->netdev = dev;
-
- conn->rx_buff = alloc_skb(NETIUCV_BUFSIZE_DEFAULT,
- GFP_KERNEL | GFP_DMA);
- if (!conn->rx_buff) {
- kfree(conn);
- return NULL;
- }
- conn->tx_buff = alloc_skb(NETIUCV_BUFSIZE_DEFAULT,
- GFP_KERNEL | GFP_DMA);
- if (!conn->tx_buff) {
- kfree_skb(conn->rx_buff);
- kfree(conn);
- return NULL;
- }
- conn->fsm = init_fsm("netiucvconn", conn_state_names,
- conn_event_names, NR_CONN_STATES,
- NR_CONN_EVENTS, conn_fsm, CONN_FSM_LEN,
- GFP_KERNEL);
- if (!conn->fsm) {
- kfree_skb(conn->tx_buff);
- kfree_skb(conn->rx_buff);
- kfree(conn);
- return NULL;
- }
- fsm_settimer(conn->fsm, &conn->timer);
- fsm_newstate(conn->fsm, CONN_STATE_INVALID);
-
- if (username) {
- memcpy(conn->userid, username, 9);
- fsm_newstate(conn->fsm, CONN_STATE_STOPPED);
- }
+static struct iucv_connection *netiucv_new_connection(struct net_device *dev,
+ char *username)
+{
+ struct iucv_connection *conn;
- write_lock_irqsave(&iucv_conns.iucv_rwlock, flags);
- conn->next = *clist;
- *clist = conn;
- write_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags);
+ conn = kzalloc(sizeof(*conn), GFP_KERNEL);
+ if (!conn)
+ goto out;
+ skb_queue_head_init(&conn->collect_queue);
+ skb_queue_head_init(&conn->commit_queue);
+ spin_lock_init(&conn->collect_lock);
+ conn->max_buffsize = NETIUCV_BUFSIZE_DEFAULT;
+ conn->netdev = dev;
+
+ conn->rx_buff = alloc_skb(conn->max_buffsize, GFP_KERNEL | GFP_DMA);
+ if (!conn->rx_buff)
+ goto out_conn;
+ conn->tx_buff = alloc_skb(conn->max_buffsize, GFP_KERNEL | GFP_DMA);
+ if (!conn->tx_buff)
+ goto out_rx;
+ conn->fsm = init_fsm("netiucvconn", conn_state_names,
+ conn_event_names, NR_CONN_STATES,
+ NR_CONN_EVENTS, conn_fsm, CONN_FSM_LEN,
+ GFP_KERNEL);
+ if (!conn->fsm)
+ goto out_tx;
+
+ fsm_settimer(conn->fsm, &conn->timer);
+ fsm_newstate(conn->fsm, CONN_STATE_INVALID);
+
+ if (username) {
+ memcpy(conn->userid, username, 9);
+ fsm_newstate(conn->fsm, CONN_STATE_STOPPED);
}
+
+ write_lock_bh(&iucv_connection_rwlock);
+ list_add_tail(&conn->list, &iucv_connection_list);
+ write_unlock_bh(&iucv_connection_rwlock);
return conn;
+
+out_tx:
+ kfree_skb(conn->tx_buff);
+out_rx:
+ kfree_skb(conn->rx_buff);
+out_conn:
+ kfree(conn);
+out:
+ return NULL;
}
/**
* Release a connection structure and remove it from the
* list of netiucv connections.
*/
-static void
-netiucv_remove_connection(struct iucv_connection *conn)
+static void netiucv_remove_connection(struct iucv_connection *conn)
{
- struct iucv_connection **clist = &iucv_conns.iucv_connections;
- unsigned long flags;
-
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
- if (conn == NULL)
- return;
- write_lock_irqsave(&iucv_conns.iucv_rwlock, flags);
- while (*clist) {
- if (*clist == conn) {
- *clist = conn->next;
- write_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags);
- if (conn->handle) {
- iucv_unregister_program(conn->handle);
- conn->handle = NULL;
- }
- fsm_deltimer(&conn->timer);
- kfree_fsm(conn->fsm);
- kfree_skb(conn->rx_buff);
- kfree_skb(conn->tx_buff);
- return;
- }
- clist = &((*clist)->next);
+ write_lock_bh(&iucv_connection_rwlock);
+ list_del_init(&conn->list);
+ write_unlock_bh(&iucv_connection_rwlock);
+ if (conn->path) {
+ iucv_path_sever(conn->path, iucvMagic);
+ kfree(conn->path);
+ conn->path = NULL;
}
- write_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags);
+ fsm_deltimer(&conn->timer);
+ kfree_fsm(conn->fsm);
+ kfree_skb(conn->rx_buff);
+ kfree_skb(conn->tx_buff);
}
/**
* Release everything of a net device.
*/
-static void
-netiucv_free_netdevice(struct net_device *dev)
+static void netiucv_free_netdevice(struct net_device *dev)
{
- struct netiucv_priv *privptr;
+ struct netiucv_priv *privptr = netdev_priv(dev);
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
if (!dev)
return;
- privptr = (struct netiucv_priv *)dev->priv;
if (privptr) {
if (privptr->conn)
netiucv_remove_connection(privptr->conn);
@@ -1913,11 +1894,8 @@ netiucv_free_netdevice(struct net_device *dev)
/**
* Initialize a net device. (Called from kernel in alloc_netdev())
*/
-static void
-netiucv_setup_netdevice(struct net_device *dev)
+static void netiucv_setup_netdevice(struct net_device *dev)
{
- memset(dev->priv, 0, sizeof(struct netiucv_priv));
-
dev->mtu = NETIUCV_MTU_DEFAULT;
dev->hard_start_xmit = netiucv_tx;
dev->open = netiucv_open;
@@ -1936,8 +1914,7 @@ netiucv_setup_netdevice(struct net_device *dev)
/**
* Allocate and initialize everything of a net device.
*/
-static struct net_device *
-netiucv_init_netdevice(char *username)
+static struct net_device *netiucv_init_netdevice(char *username)
{
struct netiucv_priv *privptr;
struct net_device *dev;
@@ -1946,40 +1923,40 @@ netiucv_init_netdevice(char *username)
netiucv_setup_netdevice);
if (!dev)
return NULL;
- if (dev_alloc_name(dev, dev->name) < 0) {
- free_netdev(dev);
- return NULL;
- }
+ if (dev_alloc_name(dev, dev->name) < 0)
+ goto out_netdev;
- privptr = (struct netiucv_priv *)dev->priv;
+ privptr = netdev_priv(dev);
privptr->fsm = init_fsm("netiucvdev", dev_state_names,
dev_event_names, NR_DEV_STATES, NR_DEV_EVENTS,
dev_fsm, DEV_FSM_LEN, GFP_KERNEL);
- if (!privptr->fsm) {
- free_netdev(dev);
- return NULL;
- }
+ if (!privptr->fsm)
+ goto out_netdev;
+
privptr->conn = netiucv_new_connection(dev, username);
if (!privptr->conn) {
- kfree_fsm(privptr->fsm);
- free_netdev(dev);
IUCV_DBF_TEXT(setup, 2, "NULL from netiucv_new_connection\n");
- return NULL;
+ goto out_fsm;
}
fsm_newstate(privptr->fsm, DEV_STATE_STOPPED);
-
return dev;
+
+out_fsm:
+ kfree_fsm(privptr->fsm);
+out_netdev:
+ free_netdev(dev);
+ return NULL;
}
-static ssize_t
-conn_write(struct device_driver *drv, const char *buf, size_t count)
+static ssize_t conn_write(struct device_driver *drv,
+ const char *buf, size_t count)
{
- char *p;
+ const char *p;
char username[9];
- int i, ret;
+ int i, rc;
struct net_device *dev;
- struct iucv_connection **clist = &iucv_conns.iucv_connections;
- unsigned long flags;
+ struct netiucv_priv *priv;
+ struct iucv_connection *cp;
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
if (count>9) {
@@ -1988,83 +1965,82 @@ conn_write(struct device_driver *drv, const char *buf, size_t count)
return -EINVAL;
}
- for (i=0, p=(char *)buf; i<8 && *p; i++, p++) {
- if (isalnum(*p) || (*p == '$'))
- username[i]= toupper(*p);
- else if (*p == '\n') {
+ for (i = 0, p = buf; i < 8 && *p; i++, p++) {
+ if (isalnum(*p) || *p == '$') {
+ username[i] = toupper(*p);
+ continue;
+ }
+ if (*p == '\n')
/* trailing lf, grr */
break;
- } else {
- PRINT_WARN("netiucv: Invalid character in username!\n");
- IUCV_DBF_TEXT_(setup, 2,
- "conn_write: invalid character %c\n", *p);
- return -EINVAL;
- }
+ PRINT_WARN("netiucv: Invalid character in username!\n");
+ IUCV_DBF_TEXT_(setup, 2,
+ "conn_write: invalid character %c\n", *p);
+ return -EINVAL;
}
- while (i<8)
+ while (i < 8)
username[i++] = ' ';
username[8] = '\0';
- read_lock_irqsave(&iucv_conns.iucv_rwlock, flags);
- while (*clist) {
- if (!strncmp(username, (*clist)->userid, 9))
- break;
- clist = &((*clist)->next);
- }
- read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags);
- if (*clist) {
- PRINT_WARN("netiucv: Connection to %s already exists\n",
- username);
- return -EEXIST;
+ read_lock_bh(&iucv_connection_rwlock);
+ list_for_each_entry(cp, &iucv_connection_list, list) {
+ if (!strncmp(username, cp->userid, 9)) {
+ read_unlock_bh(&iucv_connection_rwlock);
+ PRINT_WARN("netiucv: Connection to %s already "
+ "exists\n", username);
+ return -EEXIST;
+ }
}
+ read_unlock_bh(&iucv_connection_rwlock);
+
dev = netiucv_init_netdevice(username);
if (!dev) {
- PRINT_WARN(
- "netiucv: Could not allocate network device structure "
- "for user '%s'\n", netiucv_printname(username));
+ PRINT_WARN("netiucv: Could not allocate network device "
+ "structure for user '%s'\n",
+ netiucv_printname(username));
IUCV_DBF_TEXT(setup, 2, "NULL from netiucv_init_netdevice\n");
return -ENODEV;
}
- if ((ret = netiucv_register_device(dev))) {
+ rc = netiucv_register_device(dev);
+ if (rc) {
IUCV_DBF_TEXT_(setup, 2,
- "ret %d from netiucv_register_device\n", ret);
+ "ret %d from netiucv_register_device\n", rc);
goto out_free_ndev;
}
/* sysfs magic */
- SET_NETDEV_DEV(dev,
- (struct device*)((struct netiucv_priv*)dev->priv)->dev);
+ priv = netdev_priv(dev);
+ SET_NETDEV_DEV(dev, priv->dev);
- if ((ret = register_netdev(dev))) {
- netiucv_unregister_device((struct device*)
- ((struct netiucv_priv*)dev->priv)->dev);
- goto out_free_ndev;
- }
+ rc = register_netdev(dev);
+ if (rc)
+ goto out_unreg;
PRINT_INFO("%s: '%s'\n", dev->name, netiucv_printname(username));
return count;
+out_unreg:
+ netiucv_unregister_device(priv->dev);
out_free_ndev:
PRINT_WARN("netiucv: Could not register '%s'\n", dev->name);
IUCV_DBF_TEXT(setup, 2, "conn_write: could not register\n");
netiucv_free_netdevice(dev);
- return ret;
+ return rc;
}
-DRIVER_ATTR(connection, 0200, NULL, conn_write);
+static DRIVER_ATTR(connection, 0200, NULL, conn_write);
-static ssize_t
-remove_write (struct device_driver *drv, const char *buf, size_t count)
+static ssize_t remove_write (struct device_driver *drv,
+ const char *buf, size_t count)
{
- struct iucv_connection **clist = &iucv_conns.iucv_connections;
- unsigned long flags;
+ struct iucv_connection *cp;
struct net_device *ndev;
struct netiucv_priv *priv;
struct device *dev;
char name[IFNAMSIZ];
- char *p;
+ const char *p;
int i;
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
@@ -2072,33 +2048,27 @@ remove_write (struct device_driver *drv, const char *buf, size_t count)
if (count >= IFNAMSIZ)
count = IFNAMSIZ - 1;;
- for (i=0, p=(char *)buf; i<count && *p; i++, p++) {
- if ((*p == '\n') || (*p == ' ')) {
+ for (i = 0, p = buf; i < count && *p; i++, p++) {
+ if (*p == '\n' || *p == ' ')
/* trailing lf, grr */
break;
- } else {
- name[i]=*p;
- }
+ name[i] = *p;
}
name[i] = '\0';
- read_lock_irqsave(&iucv_conns.iucv_rwlock, flags);
- while (*clist) {
- ndev = (*clist)->netdev;
- priv = (struct netiucv_priv*)ndev->priv;
+ read_lock_bh(&iucv_connection_rwlock);
+ list_for_each_entry(cp, &iucv_connection_list, list) {
+ ndev = cp->netdev;
+ priv = netdev_priv(ndev);
dev = priv->dev;
-
- if (strncmp(name, ndev->name, count)) {
- clist = &((*clist)->next);
- continue;
- }
- read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags);
+ if (strncmp(name, ndev->name, count))
+ continue;
+ read_unlock_bh(&iucv_connection_rwlock);
if (ndev->flags & (IFF_UP | IFF_RUNNING)) {
- PRINT_WARN(
- "netiucv: net device %s active with peer %s\n",
- ndev->name, priv->conn->userid);
+ PRINT_WARN("netiucv: net device %s active with peer "
+ "%s\n", ndev->name, priv->conn->userid);
PRINT_WARN("netiucv: %s cannot be removed\n",
- ndev->name);
+ ndev->name);
IUCV_DBF_TEXT(data, 2, "remove_write: still active\n");
return -EBUSY;
}
@@ -2106,75 +2076,94 @@ remove_write (struct device_driver *drv, const char *buf, size_t count)
netiucv_unregister_device(dev);
return count;
}
- read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags);
+ read_unlock_bh(&iucv_connection_rwlock);
PRINT_WARN("netiucv: net device %s unknown\n", name);
IUCV_DBF_TEXT(data, 2, "remove_write: unknown device\n");
return -EINVAL;
}
-DRIVER_ATTR(remove, 0200, NULL, remove_write);
+static DRIVER_ATTR(remove, 0200, NULL, remove_write);
-static void
-netiucv_banner(void)
+static struct attribute * netiucv_drv_attrs[] = {
+ &driver_attr_connection.attr,
+ &driver_attr_remove.attr,
+ NULL,
+};
+
+static struct attribute_group netiucv_drv_attr_group = {
+ .attrs = netiucv_drv_attrs,
+};
+
+static void netiucv_banner(void)
{
PRINT_INFO("NETIUCV driver initialized\n");
}
-static void __exit
-netiucv_exit(void)
+static void __exit netiucv_exit(void)
{
+ struct iucv_connection *cp;
+ struct net_device *ndev;
+ struct netiucv_priv *priv;
+ struct device *dev;
+
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
- while (iucv_conns.iucv_connections) {
- struct net_device *ndev = iucv_conns.iucv_connections->netdev;
- struct netiucv_priv *priv = (struct netiucv_priv*)ndev->priv;
- struct device *dev = priv->dev;
+ while (!list_empty(&iucv_connection_list)) {
+ cp = list_entry(iucv_connection_list.next,
+ struct iucv_connection, list);
+ list_del(&cp->list);
+ ndev = cp->netdev;
+ priv = netdev_priv(ndev);
+ dev = priv->dev;
unregister_netdev(ndev);
netiucv_unregister_device(dev);
}
- driver_remove_file(&netiucv_driver, &driver_attr_connection);
- driver_remove_file(&netiucv_driver, &driver_attr_remove);
+ sysfs_remove_group(&netiucv_driver.kobj, &netiucv_drv_attr_group);
driver_unregister(&netiucv_driver);
+ iucv_unregister(&netiucv_handler, 1);
iucv_unregister_dbf_views();
PRINT_INFO("NETIUCV driver unloaded\n");
return;
}
-static int __init
-netiucv_init(void)
+static int __init netiucv_init(void)
{
- int ret;
+ int rc;
- ret = iucv_register_dbf_views();
- if (ret) {
- PRINT_WARN("netiucv_init failed, "
- "iucv_register_dbf_views rc = %d\n", ret);
- return ret;
- }
+ rc = iucv_register_dbf_views();
+ if (rc)
+ goto out;
+ rc = iucv_register(&netiucv_handler, 1);
+ if (rc)
+ goto out_dbf;
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
- ret = driver_register(&netiucv_driver);
- if (ret) {
+ rc = driver_register(&netiucv_driver);
+ if (rc) {
PRINT_ERR("NETIUCV: failed to register driver.\n");
- IUCV_DBF_TEXT_(setup, 2, "ret %d from driver_register\n", ret);
- iucv_unregister_dbf_views();
- return ret;
+ IUCV_DBF_TEXT_(setup, 2, "ret %d from driver_register\n", rc);
+ goto out_iucv;
}
- /* Add entry for specifying connections. */
- ret = driver_create_file(&netiucv_driver, &driver_attr_connection);
- if (!ret) {
- ret = driver_create_file(&netiucv_driver, &driver_attr_remove);
- netiucv_banner();
- rwlock_init(&iucv_conns.iucv_rwlock);
- } else {
- PRINT_ERR("NETIUCV: failed to add driver attribute.\n");
- IUCV_DBF_TEXT_(setup, 2, "ret %d from driver_create_file\n", ret);
- driver_unregister(&netiucv_driver);
- iucv_unregister_dbf_views();
+ rc = sysfs_create_group(&netiucv_driver.kobj, &netiucv_drv_attr_group);
+ if (rc) {
+ PRINT_ERR("NETIUCV: failed to add driver attributes.\n");
+ IUCV_DBF_TEXT_(setup, 2,
+ "ret %d - netiucv_drv_attr_group\n", rc);
+ goto out_driver;
}
- return ret;
+ netiucv_banner();
+ return rc;
+
+out_driver:
+ driver_unregister(&netiucv_driver);
+out_iucv:
+ iucv_unregister(&netiucv_handler, 1);
+out_dbf:
+ iucv_unregister_dbf_views();
+out:
+ return rc;
}
module_init(netiucv_init);
diff --git a/drivers/s390/net/qeth_eddp.c b/drivers/s390/net/qeth_eddp.c
index 6bb558a9a03..7c735e1fe06 100644
--- a/drivers/s390/net/qeth_eddp.c
+++ b/drivers/s390/net/qeth_eddp.c
@@ -49,7 +49,7 @@ qeth_eddp_check_buffers_for_context(struct qeth_qdio_out_q *queue,
return buffers_needed;
}
-static inline void
+static void
qeth_eddp_free_context(struct qeth_eddp_context *ctx)
{
int i;
@@ -91,7 +91,7 @@ qeth_eddp_buf_release_contexts(struct qeth_qdio_out_buffer *buf)
}
}
-static inline int
+static int
qeth_eddp_buf_ref_context(struct qeth_qdio_out_buffer *buf,
struct qeth_eddp_context *ctx)
{
@@ -196,7 +196,7 @@ out:
return flush_cnt;
}
-static inline void
+static void
qeth_eddp_create_segment_hdrs(struct qeth_eddp_context *ctx,
struct qeth_eddp_data *eddp, int data_len)
{
@@ -256,7 +256,7 @@ qeth_eddp_create_segment_hdrs(struct qeth_eddp_context *ctx,
ctx->offset += eddp->thl;
}
-static inline void
+static void
qeth_eddp_copy_data_tcp(char *dst, struct qeth_eddp_data *eddp, int len,
__wsum *hcsum)
{
@@ -302,7 +302,7 @@ qeth_eddp_copy_data_tcp(char *dst, struct qeth_eddp_data *eddp, int len,
}
}
-static inline void
+static void
qeth_eddp_create_segment_data_tcp(struct qeth_eddp_context *ctx,
struct qeth_eddp_data *eddp, int data_len,
__wsum hcsum)
@@ -349,7 +349,7 @@ qeth_eddp_create_segment_data_tcp(struct qeth_eddp_context *ctx,
((struct tcphdr *)eddp->th_in_ctx)->check = csum_fold(hcsum);
}
-static inline __wsum
+static __wsum
qeth_eddp_check_tcp4_hdr(struct qeth_eddp_data *eddp, int data_len)
{
__wsum phcsum; /* pseudo header checksum */
@@ -363,7 +363,7 @@ qeth_eddp_check_tcp4_hdr(struct qeth_eddp_data *eddp, int data_len)
return csum_partial((u8 *)&eddp->th, eddp->thl, phcsum);
}
-static inline __wsum
+static __wsum
qeth_eddp_check_tcp6_hdr(struct qeth_eddp_data *eddp, int data_len)
{
__be32 proto;
@@ -381,7 +381,7 @@ qeth_eddp_check_tcp6_hdr(struct qeth_eddp_data *eddp, int data_len)
return phcsum;
}
-static inline struct qeth_eddp_data *
+static struct qeth_eddp_data *
qeth_eddp_create_eddp_data(struct qeth_hdr *qh, u8 *nh, u8 nhl, u8 *th, u8 thl)
{
struct qeth_eddp_data *eddp;
@@ -399,7 +399,7 @@ qeth_eddp_create_eddp_data(struct qeth_hdr *qh, u8 *nh, u8 nhl, u8 *th, u8 thl)
return eddp;
}
-static inline void
+static void
__qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx,
struct qeth_eddp_data *eddp)
{
@@ -464,7 +464,7 @@ __qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx,
}
}
-static inline int
+static int
qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx,
struct sk_buff *skb, struct qeth_hdr *qhdr)
{
@@ -505,7 +505,7 @@ qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx,
return 0;
}
-static inline void
+static void
qeth_eddp_calc_num_pages(struct qeth_eddp_context *ctx, struct sk_buff *skb,
int hdr_len)
{
@@ -529,7 +529,7 @@ qeth_eddp_calc_num_pages(struct qeth_eddp_context *ctx, struct sk_buff *skb,
(skb_shinfo(skb)->gso_segs + 1);
}
-static inline struct qeth_eddp_context *
+static struct qeth_eddp_context *
qeth_eddp_create_context_generic(struct qeth_card *card, struct sk_buff *skb,
int hdr_len)
{
@@ -581,7 +581,7 @@ qeth_eddp_create_context_generic(struct qeth_card *card, struct sk_buff *skb,
return ctx;
}
-static inline struct qeth_eddp_context *
+static struct qeth_eddp_context *
qeth_eddp_create_context_tcp(struct qeth_card *card, struct sk_buff *skb,
struct qeth_hdr *qhdr)
{
@@ -625,5 +625,3 @@ qeth_eddp_create_context(struct qeth_card *card, struct sk_buff *skb,
}
return NULL;
}
-
-
diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c
index d2efa5ff125..2257e45594b 100644
--- a/drivers/s390/net/qeth_main.c
+++ b/drivers/s390/net/qeth_main.c
@@ -651,7 +651,7 @@ __qeth_ref_ip_on_card(struct qeth_card *card, struct qeth_ipaddr *todo,
return 0;
}
-static inline int
+static int
__qeth_address_exists_in_list(struct list_head *list, struct qeth_ipaddr *addr,
int same_type)
{
@@ -795,7 +795,7 @@ qeth_add_ip(struct qeth_card *card, struct qeth_ipaddr *addr)
return rc;
}
-static inline void
+static void
__qeth_delete_all_mc(struct qeth_card *card, unsigned long *flags)
{
struct qeth_ipaddr *addr, *tmp;
@@ -882,7 +882,7 @@ static void qeth_layer2_add_multicast(struct qeth_card *);
static void qeth_add_multicast_ipv6(struct qeth_card *);
#endif
-static inline int
+static int
qeth_set_thread_start_bit(struct qeth_card *card, unsigned long thread)
{
unsigned long flags;
@@ -920,7 +920,7 @@ qeth_clear_thread_running_bit(struct qeth_card *card, unsigned long thread)
wake_up(&card->wait_q);
}
-static inline int
+static int
__qeth_do_run_thread(struct qeth_card *card, unsigned long thread)
{
unsigned long flags;
@@ -1764,9 +1764,9 @@ out:
qeth_release_buffer(channel,iob);
}
-static inline void
+static void
qeth_prepare_control_data(struct qeth_card *card, int len,
-struct qeth_cmd_buffer *iob)
+ struct qeth_cmd_buffer *iob)
{
qeth_setup_ccw(&card->write,iob->data,len);
iob->callback = qeth_release_buffer;
@@ -2160,7 +2160,7 @@ qeth_check_qdio_errors(struct qdio_buffer *buf, unsigned int qdio_error,
return 0;
}
-static inline struct sk_buff *
+static struct sk_buff *
qeth_get_skb(unsigned int length, struct qeth_hdr *hdr)
{
struct sk_buff* skb;
@@ -2179,7 +2179,7 @@ qeth_get_skb(unsigned int length, struct qeth_hdr *hdr)
return skb;
}
-static inline struct sk_buff *
+static struct sk_buff *
qeth_get_next_skb(struct qeth_card *card, struct qdio_buffer *buffer,
struct qdio_buffer_element **__element, int *__offset,
struct qeth_hdr **hdr)
@@ -2264,7 +2264,7 @@ no_mem:
return NULL;
}
-static inline __be16
+static __be16
qeth_type_trans(struct sk_buff *skb, struct net_device *dev)
{
struct qeth_card *card;
@@ -2297,7 +2297,7 @@ qeth_type_trans(struct sk_buff *skb, struct net_device *dev)
return htons(ETH_P_802_2);
}
-static inline void
+static void
qeth_rebuild_skb_fake_ll_tr(struct qeth_card *card, struct sk_buff *skb,
struct qeth_hdr *hdr)
{
@@ -2351,7 +2351,7 @@ qeth_rebuild_skb_fake_ll_tr(struct qeth_card *card, struct sk_buff *skb,
fake_llc->ethertype = ETH_P_IP;
}
-static inline void
+static void
qeth_rebuild_skb_fake_ll_eth(struct qeth_card *card, struct sk_buff *skb,
struct qeth_hdr *hdr)
{
@@ -2420,7 +2420,7 @@ qeth_layer2_rebuild_skb(struct qeth_card *card, struct sk_buff *skb,
*((__u32 *)skb->cb) = ++card->seqno.pkt_seqno;
}
-static inline __u16
+static __u16
qeth_rebuild_skb(struct qeth_card *card, struct sk_buff *skb,
struct qeth_hdr *hdr)
{
@@ -2476,7 +2476,7 @@ qeth_rebuild_skb(struct qeth_card *card, struct sk_buff *skb,
return vlan_id;
}
-static inline void
+static void
qeth_process_inbound_buffer(struct qeth_card *card,
struct qeth_qdio_buffer *buf, int index)
{
@@ -2528,7 +2528,7 @@ qeth_process_inbound_buffer(struct qeth_card *card,
}
}
-static inline struct qeth_buffer_pool_entry *
+static struct qeth_buffer_pool_entry *
qeth_get_buffer_pool_entry(struct qeth_card *card)
{
struct qeth_buffer_pool_entry *entry;
@@ -2543,7 +2543,7 @@ qeth_get_buffer_pool_entry(struct qeth_card *card)
return NULL;
}
-static inline void
+static void
qeth_init_input_buffer(struct qeth_card *card, struct qeth_qdio_buffer *buf)
{
struct qeth_buffer_pool_entry *pool_entry;
@@ -2570,7 +2570,7 @@ qeth_init_input_buffer(struct qeth_card *card, struct qeth_qdio_buffer *buf)
buf->state = QETH_QDIO_BUF_EMPTY;
}
-static inline void
+static void
qeth_clear_output_buffer(struct qeth_qdio_out_q *queue,
struct qeth_qdio_out_buffer *buf)
{
@@ -2595,7 +2595,7 @@ qeth_clear_output_buffer(struct qeth_qdio_out_q *queue,
atomic_set(&buf->state, QETH_QDIO_BUF_EMPTY);
}
-static inline void
+static void
qeth_queue_input_buffer(struct qeth_card *card, int index)
{
struct qeth_qdio_q *queue = card->qdio.in_q;
@@ -2699,7 +2699,7 @@ qeth_qdio_input_handler(struct ccw_device * ccwdev, unsigned int status,
card->perf_stats.inbound_start_time;
}
-static inline int
+static int
qeth_handle_send_error(struct qeth_card *card,
struct qeth_qdio_out_buffer *buffer,
unsigned int qdio_err, unsigned int siga_err)
@@ -2821,7 +2821,7 @@ qeth_flush_buffers(struct qeth_qdio_out_q *queue, int under_int,
* Switched to packing state if the number of used buffers on a queue
* reaches a certain limit.
*/
-static inline void
+static void
qeth_switch_to_packing_if_needed(struct qeth_qdio_out_q *queue)
{
if (!queue->do_pack) {
@@ -2842,7 +2842,7 @@ qeth_switch_to_packing_if_needed(struct qeth_qdio_out_q *queue)
* In that case 1 is returned to inform the caller. If no buffer
* has to be flushed, zero is returned.
*/
-static inline int
+static int
qeth_switch_to_nonpacking_if_needed(struct qeth_qdio_out_q *queue)
{
struct qeth_qdio_out_buffer *buffer;
@@ -2877,7 +2877,7 @@ qeth_switch_to_nonpacking_if_needed(struct qeth_qdio_out_q *queue)
* Checks if there is a packing buffer and prepares it to be flushed.
* In that case returns 1, otherwise zero.
*/
-static inline int
+static int
qeth_flush_buffers_on_no_pci(struct qeth_qdio_out_q *queue)
{
struct qeth_qdio_out_buffer *buffer;
@@ -2894,7 +2894,7 @@ qeth_flush_buffers_on_no_pci(struct qeth_qdio_out_q *queue)
return 0;
}
-static inline void
+static void
qeth_check_outbound_queue(struct qeth_qdio_out_q *queue)
{
int index;
@@ -3594,7 +3594,7 @@ qeth_fake_header(struct sk_buff *skb, struct net_device *dev,
}
}
-static inline int
+static int
qeth_send_packet(struct qeth_card *, struct sk_buff *);
static int
@@ -3759,7 +3759,7 @@ qeth_stop(struct net_device *dev)
return 0;
}
-static inline int
+static int
qeth_get_cast_type(struct qeth_card *card, struct sk_buff *skb)
{
int cast_type = RTN_UNSPEC;
@@ -3806,7 +3806,7 @@ qeth_get_cast_type(struct qeth_card *card, struct sk_buff *skb)
return cast_type;
}
-static inline int
+static int
qeth_get_priority_queue(struct qeth_card *card, struct sk_buff *skb,
int ipv, int cast_type)
{
@@ -3853,7 +3853,7 @@ qeth_get_ip_version(struct sk_buff *skb)
}
}
-static inline struct qeth_hdr *
+static struct qeth_hdr *
__qeth_prepare_skb(struct qeth_card *card, struct sk_buff *skb, int ipv)
{
#ifdef CONFIG_QETH_VLAN
@@ -3882,14 +3882,14 @@ __qeth_prepare_skb(struct qeth_card *card, struct sk_buff *skb, int ipv)
qeth_push_skb(card, skb, sizeof(struct qeth_hdr)));
}
-static inline void
+static void
__qeth_free_new_skb(struct sk_buff *orig_skb, struct sk_buff *new_skb)
{
if (orig_skb != new_skb)
dev_kfree_skb_any(new_skb);
}
-static inline struct sk_buff *
+static struct sk_buff *
qeth_prepare_skb(struct qeth_card *card, struct sk_buff *skb,
struct qeth_hdr **hdr, int ipv)
{
@@ -3940,7 +3940,7 @@ qeth_get_qeth_hdr_flags6(int cast_type)
return ct | QETH_CAST_UNICAST;
}
-static inline void
+static void
qeth_layer2_get_packet_type(struct qeth_card *card, struct qeth_hdr *hdr,
struct sk_buff *skb)
{
@@ -3977,7 +3977,7 @@ qeth_layer2_get_packet_type(struct qeth_card *card, struct qeth_hdr *hdr,
}
}
-static inline void
+static void
qeth_layer2_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
struct sk_buff *skb, int cast_type)
{
@@ -4068,7 +4068,7 @@ qeth_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
}
}
-static inline void
+static void
__qeth_fill_buffer(struct sk_buff *skb, struct qdio_buffer *buffer,
int is_tso, int *next_element_to_fill)
{
@@ -4112,7 +4112,7 @@ __qeth_fill_buffer(struct sk_buff *skb, struct qdio_buffer *buffer,
*next_element_to_fill = element;
}
-static inline int
+static int
qeth_fill_buffer(struct qeth_qdio_out_q *queue,
struct qeth_qdio_out_buffer *buf,
struct sk_buff *skb)
@@ -4171,7 +4171,7 @@ qeth_fill_buffer(struct qeth_qdio_out_q *queue,
return flush_cnt;
}
-static inline int
+static int
qeth_do_send_packet_fast(struct qeth_card *card, struct qeth_qdio_out_q *queue,
struct sk_buff *skb, struct qeth_hdr *hdr,
int elements_needed,
@@ -4222,7 +4222,7 @@ out:
return -EBUSY;
}
-static inline int
+static int
qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue,
struct sk_buff *skb, struct qeth_hdr *hdr,
int elements_needed, struct qeth_eddp_context *ctx)
@@ -4328,7 +4328,7 @@ out:
return rc;
}
-static inline int
+static int
qeth_get_elements_no(struct qeth_card *card, void *hdr,
struct sk_buff *skb, int elems)
{
@@ -4349,7 +4349,7 @@ qeth_get_elements_no(struct qeth_card *card, void *hdr,
}
-static inline int
+static int
qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
{
int ipv = 0;
@@ -4536,7 +4536,7 @@ qeth_mdio_read(struct net_device *dev, int phy_id, int regnum)
}
-static inline const char *
+static const char *
qeth_arp_get_error_cause(int *rc)
{
switch (*rc) {
@@ -4597,7 +4597,7 @@ qeth_arp_set_no_entries(struct qeth_card *card, int no_entries)
return rc;
}
-static inline void
+static void
qeth_copy_arp_entries_stripped(struct qeth_arp_query_info *qinfo,
struct qeth_arp_query_data *qdata,
int entry_size, int uentry_size)
@@ -5214,7 +5214,7 @@ qeth_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
spin_unlock_irqrestore(&card->vlanlock, flags);
}
-static inline void
+static void
qeth_free_vlan_buffer(struct qeth_card *card, struct qeth_qdio_out_buffer *buf,
unsigned short vid)
{
@@ -5625,7 +5625,7 @@ qeth_delete_mc_addresses(struct qeth_card *card)
spin_unlock_irqrestore(&card->ip_lock, flags);
}
-static inline void
+static void
qeth_add_mc(struct qeth_card *card, struct in_device *in4_dev)
{
struct qeth_ipaddr *ipm;
@@ -5711,7 +5711,7 @@ qeth_layer2_add_multicast(struct qeth_card *card)
}
#ifdef CONFIG_QETH_IPV6
-static inline void
+static void
qeth_add_mc6(struct qeth_card *card, struct inet6_dev *in6_dev)
{
struct qeth_ipaddr *ipm;
@@ -6022,7 +6022,7 @@ qeth_send_setdelmc(struct qeth_card *card, struct qeth_ipaddr *addr, int ipacmd)
return rc;
}
-static inline void
+static void
qeth_fill_netmask(u8 *netmask, unsigned int len)
{
int i,j;
@@ -6626,7 +6626,7 @@ qeth_send_setadp_mode(struct qeth_card *card, __u32 command, __u32 mode)
return rc;
}
-static inline int
+static int
qeth_setadapter_hstr(struct qeth_card *card)
{
int rc;
@@ -6889,7 +6889,7 @@ qeth_send_simple_setassparms(struct qeth_card *card,
return rc;
}
-static inline int
+static int
qeth_start_ipa_arp_processing(struct qeth_card *card)
{
int rc;
@@ -7529,7 +7529,7 @@ qeth_set_allowed_threads(struct qeth_card *card, unsigned long threads,
wake_up(&card->wait_q);
}
-static inline int
+static int
qeth_threads_running(struct qeth_card *card, unsigned long threads)
{
unsigned long flags;
@@ -8118,7 +8118,7 @@ qeth_del_ipato_entry(struct qeth_card *card, enum qeth_prot_versions proto,
spin_unlock_irqrestore(&card->ip_lock, flags);
}
-static inline void
+static void
qeth_convert_addr_to_bits(u8 *addr, u8 *bits, int len)
{
int i, j;
diff --git a/drivers/s390/net/qeth_proc.c b/drivers/s390/net/qeth_proc.c
index faa768e5925..81f805cc5ee 100644
--- a/drivers/s390/net/qeth_proc.c
+++ b/drivers/s390/net/qeth_proc.c
@@ -161,7 +161,7 @@ qeth_procfile_open(struct inode *inode, struct file *file)
return seq_open(file, &qeth_procfile_seq_ops);
}
-static struct file_operations qeth_procfile_fops = {
+static const struct file_operations qeth_procfile_fops = {
.owner = THIS_MODULE,
.open = qeth_procfile_open,
.read = seq_read,
@@ -273,7 +273,7 @@ qeth_perf_procfile_open(struct inode *inode, struct file *file)
return seq_open(file, &qeth_perf_procfile_seq_ops);
}
-static struct file_operations qeth_perf_procfile_fops = {
+static const struct file_operations qeth_perf_procfile_fops = {
.owner = THIS_MODULE,
.open = qeth_perf_procfile_open,
.read = seq_read,
diff --git a/drivers/s390/net/qeth_sys.c b/drivers/s390/net/qeth_sys.c
index 5836737ac58..d518419cd0c 100644
--- a/drivers/s390/net/qeth_sys.c
+++ b/drivers/s390/net/qeth_sys.c
@@ -328,7 +328,7 @@ qeth_dev_bufcnt_store(struct device *dev, struct device_attribute *attr, const c
static DEVICE_ATTR(buffer_count, 0644, qeth_dev_bufcnt_show,
qeth_dev_bufcnt_store);
-static inline ssize_t
+static ssize_t
qeth_dev_route_show(struct qeth_card *card, struct qeth_routing_info *route,
char *buf)
{
@@ -368,7 +368,7 @@ qeth_dev_route4_show(struct device *dev, struct device_attribute *attr, char *bu
return qeth_dev_route_show(card, &card->options.route4, buf);
}
-static inline ssize_t
+static ssize_t
qeth_dev_route_store(struct qeth_card *card, struct qeth_routing_info *route,
enum qeth_prot_versions prot, const char *buf, size_t count)
{
@@ -998,7 +998,7 @@ struct device_attribute dev_attr_##_id = { \
.store = _store, \
};
-int
+static int
qeth_check_layer2(struct qeth_card *card)
{
if (card->options.layer2)
@@ -1100,7 +1100,7 @@ static QETH_DEVICE_ATTR(ipato_invert4, invert4, 0644,
qeth_dev_ipato_invert4_show,
qeth_dev_ipato_invert4_store);
-static inline ssize_t
+static ssize_t
qeth_dev_ipato_add_show(char *buf, struct qeth_card *card,
enum qeth_prot_versions proto)
{
@@ -1146,7 +1146,7 @@ qeth_dev_ipato_add4_show(struct device *dev, struct device_attribute *attr, char
return qeth_dev_ipato_add_show(buf, card, QETH_PROT_IPV4);
}
-static inline int
+static int
qeth_parse_ipatoe(const char* buf, enum qeth_prot_versions proto,
u8 *addr, int *mask_bits)
{
@@ -1178,7 +1178,7 @@ qeth_parse_ipatoe(const char* buf, enum qeth_prot_versions proto,
return 0;
}
-static inline ssize_t
+static ssize_t
qeth_dev_ipato_add_store(const char *buf, size_t count,
struct qeth_card *card, enum qeth_prot_versions proto)
{
@@ -1223,7 +1223,7 @@ static QETH_DEVICE_ATTR(ipato_add4, add4, 0644,
qeth_dev_ipato_add4_show,
qeth_dev_ipato_add4_store);
-static inline ssize_t
+static ssize_t
qeth_dev_ipato_del_store(const char *buf, size_t count,
struct qeth_card *card, enum qeth_prot_versions proto)
{
@@ -1361,7 +1361,7 @@ static struct attribute_group qeth_device_ipato_group = {
.attrs = (struct attribute **)qeth_ipato_device_attrs,
};
-static inline ssize_t
+static ssize_t
qeth_dev_vipa_add_show(char *buf, struct qeth_card *card,
enum qeth_prot_versions proto)
{
@@ -1407,7 +1407,7 @@ qeth_dev_vipa_add4_show(struct device *dev, struct device_attribute *attr, char
return qeth_dev_vipa_add_show(buf, card, QETH_PROT_IPV4);
}
-static inline int
+static int
qeth_parse_vipae(const char* buf, enum qeth_prot_versions proto,
u8 *addr)
{
@@ -1418,7 +1418,7 @@ qeth_parse_vipae(const char* buf, enum qeth_prot_versions proto,
return 0;
}
-static inline ssize_t
+static ssize_t
qeth_dev_vipa_add_store(const char *buf, size_t count,
struct qeth_card *card, enum qeth_prot_versions proto)
{
@@ -1451,7 +1451,7 @@ static QETH_DEVICE_ATTR(vipa_add4, add4, 0644,
qeth_dev_vipa_add4_show,
qeth_dev_vipa_add4_store);
-static inline ssize_t
+static ssize_t
qeth_dev_vipa_del_store(const char *buf, size_t count,
struct qeth_card *card, enum qeth_prot_versions proto)
{
@@ -1542,7 +1542,7 @@ static struct attribute_group qeth_device_vipa_group = {
.attrs = (struct attribute **)qeth_vipa_device_attrs,
};
-static inline ssize_t
+static ssize_t
qeth_dev_rxip_add_show(char *buf, struct qeth_card *card,
enum qeth_prot_versions proto)
{
@@ -1588,7 +1588,7 @@ qeth_dev_rxip_add4_show(struct device *dev, struct device_attribute *attr, char
return qeth_dev_rxip_add_show(buf, card, QETH_PROT_IPV4);
}
-static inline int
+static int
qeth_parse_rxipe(const char* buf, enum qeth_prot_versions proto,
u8 *addr)
{
@@ -1599,7 +1599,7 @@ qeth_parse_rxipe(const char* buf, enum qeth_prot_versions proto,
return 0;
}
-static inline ssize_t
+static ssize_t
qeth_dev_rxip_add_store(const char *buf, size_t count,
struct qeth_card *card, enum qeth_prot_versions proto)
{
@@ -1632,7 +1632,7 @@ static QETH_DEVICE_ATTR(rxip_add4, add4, 0644,
qeth_dev_rxip_add4_show,
qeth_dev_rxip_add4_store);
-static inline ssize_t
+static ssize_t
qeth_dev_rxip_del_store(const char *buf, size_t count,
struct qeth_card *card, enum qeth_prot_versions proto)
{
diff --git a/drivers/s390/net/smsgiucv.c b/drivers/s390/net/smsgiucv.c
index b8179c27ceb..3ccca5871fd 100644
--- a/drivers/s390/net/smsgiucv.c
+++ b/drivers/s390/net/smsgiucv.c
@@ -1,7 +1,7 @@
/*
* IUCV special message driver
*
- * Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Copyright 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
* Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
*
* This program is free software; you can redistribute it and/or modify
@@ -23,10 +23,10 @@
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/device.h>
+#include <net/iucv/iucv.h>
#include <asm/cpcmd.h>
#include <asm/ebcdic.h>
-
-#include "iucv.h"
+#include "smsgiucv.h"
struct smsg_callback {
struct list_head list;
@@ -39,38 +39,46 @@ MODULE_AUTHOR
("(C) 2003 IBM Corporation by Martin Schwidefsky (schwidefsky@de.ibm.com)");
MODULE_DESCRIPTION ("Linux for S/390 IUCV special message driver");
-static iucv_handle_t smsg_handle;
-static unsigned short smsg_pathid;
+static struct iucv_path *smsg_path;
+
static DEFINE_SPINLOCK(smsg_list_lock);
static struct list_head smsg_list = LIST_HEAD_INIT(smsg_list);
-static void
-smsg_connection_complete(iucv_ConnectionComplete *eib, void *pgm_data)
+static int smsg_path_pending(struct iucv_path *, u8 ipvmid[8], u8 ipuser[16]);
+static void smsg_message_pending(struct iucv_path *, struct iucv_message *);
+
+static struct iucv_handler smsg_handler = {
+ .path_pending = smsg_path_pending,
+ .message_pending = smsg_message_pending,
+};
+
+static int smsg_path_pending(struct iucv_path *path, u8 ipvmid[8],
+ u8 ipuser[16])
{
+ if (strncmp(ipvmid, "*MSG ", sizeof(ipvmid)) != 0)
+ return -EINVAL;
+ /* Path pending from *MSG. */
+ return iucv_path_accept(path, &smsg_handler, "SMSGIUCV ", NULL);
}
-
-static void
-smsg_message_pending(iucv_MessagePending *eib, void *pgm_data)
+static void smsg_message_pending(struct iucv_path *path,
+ struct iucv_message *msg)
{
struct smsg_callback *cb;
- unsigned char *msg;
+ unsigned char *buffer;
unsigned char sender[9];
- unsigned short len;
int rc, i;
- len = eib->ln1msg2.ipbfln1f;
- msg = kmalloc(len + 1, GFP_ATOMIC|GFP_DMA);
- if (!msg) {
- iucv_reject(eib->ippathid, eib->ipmsgid, eib->iptrgcls);
+ buffer = kmalloc(msg->length + 1, GFP_ATOMIC | GFP_DMA);
+ if (!buffer) {
+ iucv_message_reject(path, msg);
return;
}
- rc = iucv_receive(eib->ippathid, eib->ipmsgid, eib->iptrgcls,
- msg, len, NULL, NULL, NULL);
+ rc = iucv_message_receive(path, msg, 0, buffer, msg->length, NULL);
if (rc == 0) {
- msg[len] = 0;
- EBCASC(msg, len);
- memcpy(sender, msg, 8);
+ buffer[msg->length] = 0;
+ EBCASC(buffer, msg->length);
+ memcpy(sender, buffer, 8);
sender[8] = 0;
/* Remove trailing whitespace from the sender name. */
for (i = 7; i >= 0; i--) {
@@ -80,27 +88,17 @@ smsg_message_pending(iucv_MessagePending *eib, void *pgm_data)
}
spin_lock(&smsg_list_lock);
list_for_each_entry(cb, &smsg_list, list)
- if (strncmp(msg + 8, cb->prefix, cb->len) == 0) {
- cb->callback(sender, msg + 8);
+ if (strncmp(buffer + 8, cb->prefix, cb->len) == 0) {
+ cb->callback(sender, buffer + 8);
break;
}
spin_unlock(&smsg_list_lock);
}
- kfree(msg);
+ kfree(buffer);
}
-static iucv_interrupt_ops_t smsg_ops = {
- .ConnectionComplete = smsg_connection_complete,
- .MessagePending = smsg_message_pending,
-};
-
-static struct device_driver smsg_driver = {
- .name = "SMSGIUCV",
- .bus = &iucv_bus,
-};
-
-int
-smsg_register_callback(char *prefix, void (*callback)(char *from, char *str))
+int smsg_register_callback(char *prefix,
+ void (*callback)(char *from, char *str))
{
struct smsg_callback *cb;
@@ -110,18 +108,18 @@ smsg_register_callback(char *prefix, void (*callback)(char *from, char *str))
cb->prefix = prefix;
cb->len = strlen(prefix);
cb->callback = callback;
- spin_lock(&smsg_list_lock);
+ spin_lock_bh(&smsg_list_lock);
list_add_tail(&cb->list, &smsg_list);
- spin_unlock(&smsg_list_lock);
+ spin_unlock_bh(&smsg_list_lock);
return 0;
}
-void
-smsg_unregister_callback(char *prefix, void (*callback)(char *from, char *str))
+void smsg_unregister_callback(char *prefix,
+ void (*callback)(char *from, char *str))
{
struct smsg_callback *cb, *tmp;
- spin_lock(&smsg_list_lock);
+ spin_lock_bh(&smsg_list_lock);
cb = NULL;
list_for_each_entry(tmp, &smsg_list, list)
if (tmp->callback == callback &&
@@ -130,55 +128,58 @@ smsg_unregister_callback(char *prefix, void (*callback)(char *from, char *str))
list_del(&cb->list);
break;
}
- spin_unlock(&smsg_list_lock);
+ spin_unlock_bh(&smsg_list_lock);
kfree(cb);
}
-static void __exit
-smsg_exit(void)
+static struct device_driver smsg_driver = {
+ .name = "SMSGIUCV",
+ .bus = &iucv_bus,
+};
+
+static void __exit smsg_exit(void)
{
- if (smsg_handle > 0) {
- cpcmd("SET SMSG OFF", NULL, 0, NULL);
- iucv_sever(smsg_pathid, NULL);
- iucv_unregister_program(smsg_handle);
- driver_unregister(&smsg_driver);
- }
- return;
+ cpcmd("SET SMSG IUCV", NULL, 0, NULL);
+ iucv_unregister(&smsg_handler, 1);
+ driver_unregister(&smsg_driver);
}
-static int __init
-smsg_init(void)
+static int __init smsg_init(void)
{
- static unsigned char pgmmask[24] = {
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
- };
int rc;
rc = driver_register(&smsg_driver);
- if (rc != 0) {
- printk(KERN_ERR "SMSGIUCV: failed to register driver.\n");
- return rc;
- }
- smsg_handle = iucv_register_program("SMSGIUCV ", "*MSG ",
- pgmmask, &smsg_ops, NULL);
- if (!smsg_handle) {
+ if (rc != 0)
+ goto out;
+ rc = iucv_register(&smsg_handler, 1);
+ if (rc) {
printk(KERN_ERR "SMSGIUCV: failed to register to iucv");
- driver_unregister(&smsg_driver);
- return -EIO; /* better errno ? */
+ rc = -EIO; /* better errno ? */
+ goto out_driver;
+ }
+ smsg_path = iucv_path_alloc(255, 0, GFP_KERNEL);
+ if (!smsg_path) {
+ rc = -ENOMEM;
+ goto out_register;
}
- rc = iucv_connect (&smsg_pathid, 255, NULL, "*MSG ", NULL, 0,
- NULL, NULL, smsg_handle, NULL);
+ rc = iucv_path_connect(smsg_path, &smsg_handler, "*MSG ",
+ NULL, NULL, NULL);
if (rc) {
printk(KERN_ERR "SMSGIUCV: failed to connect to *MSG");
- iucv_unregister_program(smsg_handle);
- driver_unregister(&smsg_driver);
- smsg_handle = NULL;
- return -EIO;
+ rc = -EIO; /* better errno ? */
+ goto out_free;
}
cpcmd("SET SMSG IUCV", NULL, 0, NULL);
return 0;
+
+out_free:
+ iucv_path_free(smsg_path);
+out_register:
+ iucv_unregister(&smsg_handler, 1);
+out_driver:
+ driver_unregister(&smsg_driver);
+out:
+ return rc;
}
module_init(smsg_init);
diff --git a/drivers/s390/s390mach.c b/drivers/s390/s390mach.c
index e088b5e2871..806bb1a921e 100644
--- a/drivers/s390/s390mach.c
+++ b/drivers/s390/s390mach.c
@@ -13,22 +13,18 @@
#include <linux/errno.h>
#include <linux/workqueue.h>
#include <linux/time.h>
+#include <linux/device.h>
#include <linux/kthread.h>
-
+#include <asm/etr.h>
#include <asm/lowcore.h>
-
+#include <asm/cio.h>
+#include "cio/cio.h"
+#include "cio/chsc.h"
+#include "cio/css.h"
#include "s390mach.h"
static struct semaphore m_sem;
-extern int css_process_crw(int, int);
-extern int chsc_process_crw(void);
-extern int chp_process_crw(int, int);
-extern void css_reiterate_subchannels(void);
-
-extern struct workqueue_struct *slow_path_wq;
-extern struct work_struct slow_path_work;
-
static NORET_TYPE void
s390_handle_damage(char *msg)
{
@@ -470,6 +466,19 @@ s390_do_machine_check(struct pt_regs *regs)
s390_handle_damage("unable to revalidate registers.");
}
+ if (mci->cd) {
+ /* Timing facility damage */
+ s390_handle_damage("TOD clock damaged");
+ }
+
+ if (mci->ed && mci->ec) {
+ /* External damage */
+ if (S390_lowcore.external_damage_code & (1U << ED_ETR_SYNC))
+ etr_sync_check();
+ if (S390_lowcore.external_damage_code & (1U << ED_ETR_SWITCH))
+ etr_switch_to_local();
+ }
+
if (mci->se)
/* Storage error uncorrected */
s390_handle_damage("received storage error uncorrected "
@@ -508,7 +517,7 @@ static int
machine_check_init(void)
{
init_MUTEX_LOCKED(&m_sem);
- ctl_clear_bit(14, 25); /* disable external damage MCH */
+ ctl_set_bit(14, 25); /* enable external damage MCH */
ctl_set_bit(14, 27); /* enable system recovery MCH */
#ifdef CONFIG_MACHCHK_WARNING
ctl_set_bit(14, 24); /* enable warning MCH */
@@ -529,7 +538,11 @@ arch_initcall(machine_check_init);
static int __init
machine_check_crw_init (void)
{
- kthread_run(s390_collect_crw_info, &m_sem, "kmcheck");
+ struct task_struct *task;
+
+ task = kthread_run(s390_collect_crw_info, &m_sem, "kmcheck");
+ if (IS_ERR(task))
+ return PTR_ERR(task);
ctl_set_bit(14, 28); /* enable channel report MCH */
return 0;
}
diff --git a/drivers/s390/s390mach.h b/drivers/s390/s390mach.h
index 7abb42a09ae..d3ca4281a49 100644
--- a/drivers/s390/s390mach.h
+++ b/drivers/s390/s390mach.h
@@ -102,4 +102,7 @@ static inline int stcrw(struct crw *pcrw )
return ccode;
}
+#define ED_ETR_SYNC 12 /* External damage ETR sync check */
+#define ED_ETR_SWITCH 13 /* External damage ETR switch to local */
+
#endif /* __s390mach */
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c
index 85093b71f9f..1f9554e0801 100644
--- a/drivers/s390/scsi/zfcp_aux.c
+++ b/drivers/s390/scsi/zfcp_aux.c
@@ -47,13 +47,12 @@ static int __init zfcp_module_init(void);
static void zfcp_ns_gid_pn_handler(unsigned long);
/* miscellaneous */
-static inline int zfcp_sg_list_alloc(struct zfcp_sg_list *, size_t);
-static inline void zfcp_sg_list_free(struct zfcp_sg_list *);
-static inline int zfcp_sg_list_copy_from_user(struct zfcp_sg_list *,
- void __user *, size_t);
-static inline int zfcp_sg_list_copy_to_user(void __user *,
- struct zfcp_sg_list *, size_t);
-
+static int zfcp_sg_list_alloc(struct zfcp_sg_list *, size_t);
+static void zfcp_sg_list_free(struct zfcp_sg_list *);
+static int zfcp_sg_list_copy_from_user(struct zfcp_sg_list *,
+ void __user *, size_t);
+static int zfcp_sg_list_copy_to_user(void __user *,
+ struct zfcp_sg_list *, size_t);
static long zfcp_cfdc_dev_ioctl(struct file *, unsigned int, unsigned long);
#define ZFCP_CFDC_IOC_MAGIC 0xDD
@@ -61,7 +60,7 @@ static long zfcp_cfdc_dev_ioctl(struct file *, unsigned int, unsigned long);
_IOWR(ZFCP_CFDC_IOC_MAGIC, 0, struct zfcp_cfdc_sense_data)
-static struct file_operations zfcp_cfdc_fops = {
+static const struct file_operations zfcp_cfdc_fops = {
.unlocked_ioctl = zfcp_cfdc_dev_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = zfcp_cfdc_dev_ioctl
@@ -605,7 +604,7 @@ zfcp_cfdc_dev_ioctl(struct file *file, unsigned int command,
* elements of the scatter-gather list. The maximum size of a single element
* in the scatter-gather list is PAGE_SIZE.
*/
-static inline int
+static int
zfcp_sg_list_alloc(struct zfcp_sg_list *sg_list, size_t size)
{
struct scatterlist *sg;
@@ -652,7 +651,7 @@ zfcp_sg_list_alloc(struct zfcp_sg_list *sg_list, size_t size)
* Memory for each element in the scatter-gather list is freed.
* Finally sg_list->sg is freed itself and sg_list->count is reset.
*/
-static inline void
+static void
zfcp_sg_list_free(struct zfcp_sg_list *sg_list)
{
struct scatterlist *sg;
@@ -697,7 +696,7 @@ zfcp_sg_size(struct scatterlist *sg, unsigned int sg_count)
* @size: number of bytes to be copied
* Return: 0 on success, -EFAULT if copy_from_user fails.
*/
-static inline int
+static int
zfcp_sg_list_copy_from_user(struct zfcp_sg_list *sg_list,
void __user *user_buffer,
size_t size)
@@ -735,7 +734,7 @@ zfcp_sg_list_copy_from_user(struct zfcp_sg_list *sg_list,
* @size: number of bytes to be copied
* Return: 0 on success, -EFAULT if copy_to_user fails
*/
-static inline int
+static int
zfcp_sg_list_copy_to_user(void __user *user_buffer,
struct zfcp_sg_list *sg_list,
size_t size)
@@ -1799,7 +1798,7 @@ static const struct zfcp_rc_entry zfcp_p_rjt_rc[] = {
* @code: reason code
* @rc_table: table of reason codes and descriptions
*/
-static inline const char *
+static const char *
zfcp_rc_description(u8 code, const struct zfcp_rc_entry *rc_table)
{
const char *descr = "unknown reason code";
@@ -1847,7 +1846,7 @@ zfcp_check_ct_response(struct ct_hdr *rjt)
* @rjt_par: reject parameter acc. to FC-PH/FC-FS
* @rc_table: table of reason codes and descriptions
*/
-static inline void
+static void
zfcp_print_els_rjt(struct zfcp_ls_rjt_par *rjt_par,
const struct zfcp_rc_entry *rc_table)
{
diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c
index 0aa3b1ac76a..d8191d115c1 100644
--- a/drivers/s390/scsi/zfcp_dbf.c
+++ b/drivers/s390/scsi/zfcp_dbf.c
@@ -31,7 +31,7 @@ MODULE_PARM_DESC(dbfsize,
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_OTHER
-static inline int
+static int
zfcp_dbf_stck(char *out_buf, const char *label, unsigned long long stck)
{
unsigned long long sec;
@@ -106,7 +106,7 @@ zfcp_dbf_view_dump(char *out_buf, const char *label,
return len;
}
-static inline int
+static int
zfcp_dbf_view_header(debug_info_t * id, struct debug_view *view, int area,
debug_entry_t * entry, char *out_buf)
{
@@ -130,7 +130,7 @@ zfcp_dbf_view_header(debug_info_t * id, struct debug_view *view, int area,
return len;
}
-inline void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *fsf_req)
+void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *fsf_req)
{
struct zfcp_adapter *adapter = fsf_req->adapter;
struct fsf_qtcb *qtcb = fsf_req->qtcb;
@@ -241,7 +241,7 @@ inline void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *fsf_req)
spin_unlock_irqrestore(&adapter->hba_dbf_lock, flags);
}
-inline void
+void
zfcp_hba_dbf_event_fsf_unsol(const char *tag, struct zfcp_adapter *adapter,
struct fsf_status_read_buffer *status_buffer)
{
@@ -295,7 +295,7 @@ zfcp_hba_dbf_event_fsf_unsol(const char *tag, struct zfcp_adapter *adapter,
spin_unlock_irqrestore(&adapter->hba_dbf_lock, flags);
}
-inline void
+void
zfcp_hba_dbf_event_qdio(struct zfcp_adapter *adapter, unsigned int status,
unsigned int qdio_error, unsigned int siga_error,
int sbal_index, int sbal_count)
@@ -316,7 +316,7 @@ zfcp_hba_dbf_event_qdio(struct zfcp_adapter *adapter, unsigned int status,
spin_unlock_irqrestore(&adapter->hba_dbf_lock, flags);
}
-static inline int
+static int
zfcp_hba_dbf_view_response(char *out_buf,
struct zfcp_hba_dbf_record_response *rec)
{
@@ -403,7 +403,7 @@ zfcp_hba_dbf_view_response(char *out_buf,
return len;
}
-static inline int
+static int
zfcp_hba_dbf_view_status(char *out_buf, struct zfcp_hba_dbf_record_status *rec)
{
int len = 0;
@@ -424,7 +424,7 @@ zfcp_hba_dbf_view_status(char *out_buf, struct zfcp_hba_dbf_record_status *rec)
return len;
}
-static inline int
+static int
zfcp_hba_dbf_view_qdio(char *out_buf, struct zfcp_hba_dbf_record_qdio *rec)
{
int len = 0;
@@ -469,7 +469,7 @@ zfcp_hba_dbf_view_format(debug_info_t * id, struct debug_view *view,
return len;
}
-struct debug_view zfcp_hba_dbf_view = {
+static struct debug_view zfcp_hba_dbf_view = {
"structured",
NULL,
&zfcp_dbf_view_header,
@@ -478,7 +478,7 @@ struct debug_view zfcp_hba_dbf_view = {
NULL
};
-inline void
+void
_zfcp_san_dbf_event_common_ct(const char *tag, struct zfcp_fsf_req *fsf_req,
u32 s_id, u32 d_id, void *buffer, int buflen)
{
@@ -519,7 +519,7 @@ _zfcp_san_dbf_event_common_ct(const char *tag, struct zfcp_fsf_req *fsf_req,
spin_unlock_irqrestore(&adapter->san_dbf_lock, flags);
}
-inline void zfcp_san_dbf_event_ct_request(struct zfcp_fsf_req *fsf_req)
+void zfcp_san_dbf_event_ct_request(struct zfcp_fsf_req *fsf_req)
{
struct zfcp_send_ct *ct = (struct zfcp_send_ct *)fsf_req->data;
struct zfcp_port *port = ct->port;
@@ -531,7 +531,7 @@ inline void zfcp_san_dbf_event_ct_request(struct zfcp_fsf_req *fsf_req)
ct->req->length);
}
-inline void zfcp_san_dbf_event_ct_response(struct zfcp_fsf_req *fsf_req)
+void zfcp_san_dbf_event_ct_response(struct zfcp_fsf_req *fsf_req)
{
struct zfcp_send_ct *ct = (struct zfcp_send_ct *)fsf_req->data;
struct zfcp_port *port = ct->port;
@@ -543,7 +543,7 @@ inline void zfcp_san_dbf_event_ct_response(struct zfcp_fsf_req *fsf_req)
ct->resp->length);
}
-static inline void
+static void
_zfcp_san_dbf_event_common_els(const char *tag, int level,
struct zfcp_fsf_req *fsf_req, u32 s_id,
u32 d_id, u8 ls_code, void *buffer, int buflen)
@@ -585,7 +585,7 @@ _zfcp_san_dbf_event_common_els(const char *tag, int level,
spin_unlock_irqrestore(&adapter->san_dbf_lock, flags);
}
-inline void zfcp_san_dbf_event_els_request(struct zfcp_fsf_req *fsf_req)
+void zfcp_san_dbf_event_els_request(struct zfcp_fsf_req *fsf_req)
{
struct zfcp_send_els *els = (struct zfcp_send_els *)fsf_req->data;
@@ -597,7 +597,7 @@ inline void zfcp_san_dbf_event_els_request(struct zfcp_fsf_req *fsf_req)
els->req->length);
}
-inline void zfcp_san_dbf_event_els_response(struct zfcp_fsf_req *fsf_req)
+void zfcp_san_dbf_event_els_response(struct zfcp_fsf_req *fsf_req)
{
struct zfcp_send_els *els = (struct zfcp_send_els *)fsf_req->data;
@@ -608,7 +608,7 @@ inline void zfcp_san_dbf_event_els_response(struct zfcp_fsf_req *fsf_req)
els->resp->length);
}
-inline void zfcp_san_dbf_event_incoming_els(struct zfcp_fsf_req *fsf_req)
+void zfcp_san_dbf_event_incoming_els(struct zfcp_fsf_req *fsf_req)
{
struct zfcp_adapter *adapter = fsf_req->adapter;
struct fsf_status_read_buffer *status_buffer =
@@ -693,7 +693,7 @@ zfcp_san_dbf_view_format(debug_info_t * id, struct debug_view *view,
return len;
}
-struct debug_view zfcp_san_dbf_view = {
+static struct debug_view zfcp_san_dbf_view = {
"structured",
NULL,
&zfcp_dbf_view_header,
@@ -702,7 +702,7 @@ struct debug_view zfcp_san_dbf_view = {
NULL
};
-static inline void
+static void
_zfcp_scsi_dbf_event_common(const char *tag, const char *tag2, int level,
struct zfcp_adapter *adapter,
struct scsi_cmnd *scsi_cmnd,
@@ -786,7 +786,7 @@ _zfcp_scsi_dbf_event_common(const char *tag, const char *tag2, int level,
spin_unlock_irqrestore(&adapter->scsi_dbf_lock, flags);
}
-inline void
+void
zfcp_scsi_dbf_event_result(const char *tag, int level,
struct zfcp_adapter *adapter,
struct scsi_cmnd *scsi_cmnd,
@@ -796,7 +796,7 @@ zfcp_scsi_dbf_event_result(const char *tag, int level,
adapter, scsi_cmnd, fsf_req, 0);
}
-inline void
+void
zfcp_scsi_dbf_event_abort(const char *tag, struct zfcp_adapter *adapter,
struct scsi_cmnd *scsi_cmnd,
struct zfcp_fsf_req *new_fsf_req,
@@ -806,7 +806,7 @@ zfcp_scsi_dbf_event_abort(const char *tag, struct zfcp_adapter *adapter,
adapter, scsi_cmnd, new_fsf_req, old_req_id);
}
-inline void
+void
zfcp_scsi_dbf_event_devreset(const char *tag, u8 flag, struct zfcp_unit *unit,
struct scsi_cmnd *scsi_cmnd)
{
@@ -884,7 +884,7 @@ zfcp_scsi_dbf_view_format(debug_info_t * id, struct debug_view *view,
return len;
}
-struct debug_view zfcp_scsi_dbf_view = {
+static struct debug_view zfcp_scsi_dbf_view = {
"structured",
NULL,
&zfcp_dbf_view_header,
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c
index c88babce9bc..421da1e7c0e 100644
--- a/drivers/s390/scsi/zfcp_erp.c
+++ b/drivers/s390/scsi/zfcp_erp.c
@@ -200,7 +200,7 @@ void zfcp_fsf_start_timer(struct zfcp_fsf_req *fsf_req, unsigned long timeout)
* returns: 0 - initiated action successfully
* <0 - failed to initiate action
*/
-int
+static int
zfcp_erp_adapter_reopen_internal(struct zfcp_adapter *adapter, int clear_mask)
{
int retval;
@@ -295,7 +295,7 @@ zfcp_erp_unit_shutdown(struct zfcp_unit *unit, int clear_mask)
* zfcp_erp_adisc - send ADISC ELS command
* @port: port structure
*/
-int
+static int
zfcp_erp_adisc(struct zfcp_port *port)
{
struct zfcp_adapter *adapter = port->adapter;
@@ -380,7 +380,7 @@ zfcp_erp_adisc(struct zfcp_port *port)
*
* If ADISC failed (LS_RJT or timed out) forced reopen of the port is triggered.
*/
-void
+static void
zfcp_erp_adisc_handler(unsigned long data)
{
struct zfcp_send_els *send_els;
@@ -838,32 +838,28 @@ zfcp_erp_action_exists(struct zfcp_erp_action *erp_action)
* and does appropriate preparations (dismiss fsf request, ...)
*
* locks: called under erp_lock (disabled interrupts)
- *
- * returns: 0
*/
-static int
+static void
zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *erp_action)
{
- int retval = 0;
- struct zfcp_fsf_req *fsf_req = NULL;
struct zfcp_adapter *adapter = erp_action->adapter;
if (erp_action->fsf_req) {
/* take lock to ensure that request is not deleted meanwhile */
spin_lock(&adapter->req_list_lock);
- if ((!zfcp_reqlist_ismember(adapter,
- erp_action->fsf_req->req_id)) &&
- (fsf_req->erp_action == erp_action)) {
+ if (zfcp_reqlist_ismember(adapter,
+ erp_action->fsf_req->req_id)) {
/* fsf_req still exists */
debug_text_event(adapter->erp_dbf, 3, "a_ca_req");
- debug_event(adapter->erp_dbf, 3, &fsf_req,
+ debug_event(adapter->erp_dbf, 3, &erp_action->fsf_req,
sizeof (unsigned long));
/* dismiss fsf_req of timed out/dismissed erp_action */
if (erp_action->status & (ZFCP_STATUS_ERP_DISMISSED |
ZFCP_STATUS_ERP_TIMEDOUT)) {
debug_text_event(adapter->erp_dbf, 3,
"a_ca_disreq");
- fsf_req->status |= ZFCP_STATUS_FSFREQ_DISMISSED;
+ erp_action->fsf_req->status |=
+ ZFCP_STATUS_FSFREQ_DISMISSED;
}
if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT) {
ZFCP_LOG_NORMAL("error: erp step timed out "
@@ -876,11 +872,11 @@ zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *erp_action)
* then keep it running asynchronously and don't mess
* with the association of erp_action and fsf_req.
*/
- if (fsf_req->status & (ZFCP_STATUS_FSFREQ_COMPLETED |
+ if (erp_action->fsf_req->status &
+ (ZFCP_STATUS_FSFREQ_COMPLETED |
ZFCP_STATUS_FSFREQ_DISMISSED)) {
/* forget about association between fsf_req
and erp_action */
- fsf_req->erp_action = NULL;
erp_action->fsf_req = NULL;
}
} else {
@@ -894,8 +890,6 @@ zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *erp_action)
spin_unlock(&adapter->req_list_lock);
} else
debug_text_event(adapter->erp_dbf, 3, "a_ca_noreq");
-
- return retval;
}
/**
@@ -3141,7 +3135,6 @@ zfcp_erp_action_cleanup(int action, struct zfcp_adapter *adapter,
break;
case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
if (result != ZFCP_ERP_SUCCEEDED) {
- struct zfcp_port *port;
list_for_each_entry(port, &adapter->port_list_head, list)
if (port->rport &&
!atomic_test_mask(ZFCP_STATUS_PORT_WKA,
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h
index b8794d77285..01386ac688a 100644
--- a/drivers/s390/scsi/zfcp_ext.h
+++ b/drivers/s390/scsi/zfcp_ext.h
@@ -89,7 +89,7 @@ extern int zfcp_fsf_control_file(struct zfcp_adapter *, struct zfcp_fsf_req **,
u32, u32, struct zfcp_sg_list *);
extern void zfcp_fsf_start_timer(struct zfcp_fsf_req *, unsigned long);
extern void zfcp_erp_start_timer(struct zfcp_fsf_req *);
-extern int zfcp_fsf_req_dismiss_all(struct zfcp_adapter *);
+extern void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *);
extern int zfcp_fsf_status_read(struct zfcp_adapter *, int);
extern int zfcp_fsf_req_create(struct zfcp_adapter *, u32, int, mempool_t *,
unsigned long *, struct zfcp_fsf_req **);
@@ -119,8 +119,8 @@ extern int zfcp_adapter_scsi_register(struct zfcp_adapter *);
extern void zfcp_adapter_scsi_unregister(struct zfcp_adapter *);
extern void zfcp_set_fcp_dl(struct fcp_cmnd_iu *, fcp_dl_t);
extern char *zfcp_get_fcp_rsp_info_ptr(struct fcp_rsp_iu *);
-extern void set_host_byte(u32 *, char);
-extern void set_driver_byte(u32 *, char);
+extern void set_host_byte(int *, char);
+extern void set_driver_byte(int *, char);
extern char *zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *);
extern fcp_dl_t zfcp_get_fcp_dl(struct fcp_cmnd_iu *);
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
index 067f1519eb0..ef16f7ca4bb 100644
--- a/drivers/s390/scsi/zfcp_fsf.c
+++ b/drivers/s390/scsi/zfcp_fsf.c
@@ -176,28 +176,25 @@ static void zfcp_fsf_req_dismiss(struct zfcp_adapter *adapter,
/**
* zfcp_fsf_req_dismiss_all - dismiss all remaining fsf requests
*/
-int zfcp_fsf_req_dismiss_all(struct zfcp_adapter *adapter)
+void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *adapter)
{
struct zfcp_fsf_req *request, *tmp;
unsigned long flags;
+ LIST_HEAD(remove_queue);
unsigned int i, counter;
spin_lock_irqsave(&adapter->req_list_lock, flags);
atomic_set(&adapter->reqs_active, 0);
- for (i=0; i<REQUEST_LIST_SIZE; i++) {
- if (list_empty(&adapter->req_list[i]))
- continue;
-
- counter = 0;
- list_for_each_entry_safe(request, tmp,
- &adapter->req_list[i], list) {
- zfcp_fsf_req_dismiss(adapter, request, counter);
- counter++;
- }
- }
+ 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);
- return 0;
+ counter = 0;
+ list_for_each_entry_safe(request, tmp, &remove_queue, list) {
+ zfcp_fsf_req_dismiss(adapter, request, counter);
+ counter++;
+ }
}
/*
@@ -4563,7 +4560,7 @@ zfcp_fsf_req_sbal_check(unsigned long *flags,
/*
* set qtcb pointer in fsf_req and initialize QTCB
*/
-static inline void
+static void
zfcp_fsf_req_qtcb_init(struct zfcp_fsf_req *fsf_req)
{
if (likely(fsf_req->qtcb != NULL)) {
diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c
index dbd9f48e863..1e12a78e8ed 100644
--- a/drivers/s390/scsi/zfcp_qdio.c
+++ b/drivers/s390/scsi/zfcp_qdio.c
@@ -21,22 +21,22 @@
#include "zfcp_ext.h"
-static inline void zfcp_qdio_sbal_limit(struct zfcp_fsf_req *, int);
+static void zfcp_qdio_sbal_limit(struct zfcp_fsf_req *, int);
static inline volatile struct qdio_buffer_element *zfcp_qdio_sbale_get
(struct zfcp_qdio_queue *, int, int);
static inline volatile struct qdio_buffer_element *zfcp_qdio_sbale_resp
(struct zfcp_fsf_req *, int, int);
-static inline volatile struct qdio_buffer_element *zfcp_qdio_sbal_chain
+static volatile struct qdio_buffer_element *zfcp_qdio_sbal_chain
(struct zfcp_fsf_req *, unsigned long);
-static inline volatile struct qdio_buffer_element *zfcp_qdio_sbale_next
+static volatile struct qdio_buffer_element *zfcp_qdio_sbale_next
(struct zfcp_fsf_req *, unsigned long);
-static inline int zfcp_qdio_sbals_zero(struct zfcp_qdio_queue *, int, int);
+static int zfcp_qdio_sbals_zero(struct zfcp_qdio_queue *, int, int);
static inline int zfcp_qdio_sbals_wipe(struct zfcp_fsf_req *);
-static inline void zfcp_qdio_sbale_fill
+static void zfcp_qdio_sbale_fill
(struct zfcp_fsf_req *, unsigned long, void *, int);
-static inline int zfcp_qdio_sbals_from_segment
+static int zfcp_qdio_sbals_from_segment
(struct zfcp_fsf_req *, unsigned long, void *, unsigned long);
-static inline int zfcp_qdio_sbals_from_buffer
+static int zfcp_qdio_sbals_from_buffer
(struct zfcp_fsf_req *, unsigned long, void *, unsigned long, int);
static qdio_handler_t zfcp_qdio_request_handler;
@@ -201,7 +201,7 @@ zfcp_qdio_allocate(struct zfcp_adapter *adapter)
* returns: error flag
*
*/
-static inline int
+static int
zfcp_qdio_handler_error_check(struct zfcp_adapter *adapter, unsigned int status,
unsigned int qdio_error, unsigned int siga_error,
int first_element, int elements_processed)
@@ -462,7 +462,7 @@ zfcp_qdio_sbale_get(struct zfcp_qdio_queue *queue, int sbal, int sbale)
* zfcp_qdio_sbale_req - return pointer to SBALE of request_queue for
* a struct zfcp_fsf_req
*/
-inline volatile struct qdio_buffer_element *
+volatile struct qdio_buffer_element *
zfcp_qdio_sbale_req(struct zfcp_fsf_req *fsf_req, int sbal, int sbale)
{
return zfcp_qdio_sbale_get(&fsf_req->adapter->request_queue,
@@ -484,7 +484,7 @@ zfcp_qdio_sbale_resp(struct zfcp_fsf_req *fsf_req, int sbal, int sbale)
* zfcp_qdio_sbale_curr - return current SBALE on request_queue for
* a struct zfcp_fsf_req
*/
-inline volatile struct qdio_buffer_element *
+volatile struct qdio_buffer_element *
zfcp_qdio_sbale_curr(struct zfcp_fsf_req *fsf_req)
{
return zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr,
@@ -499,7 +499,7 @@ zfcp_qdio_sbale_curr(struct zfcp_fsf_req *fsf_req)
*
* Note: We can assume at least one free SBAL in the request_queue when called.
*/
-static inline void
+static void
zfcp_qdio_sbal_limit(struct zfcp_fsf_req *fsf_req, int max_sbals)
{
int count = atomic_read(&fsf_req->adapter->request_queue.free_count);
@@ -517,7 +517,7 @@ zfcp_qdio_sbal_limit(struct zfcp_fsf_req *fsf_req, int max_sbals)
*
* This function changes sbal_curr, sbale_curr, sbal_number of fsf_req.
*/
-static inline volatile struct qdio_buffer_element *
+static volatile struct qdio_buffer_element *
zfcp_qdio_sbal_chain(struct zfcp_fsf_req *fsf_req, unsigned long sbtype)
{
volatile struct qdio_buffer_element *sbale;
@@ -554,7 +554,7 @@ zfcp_qdio_sbal_chain(struct zfcp_fsf_req *fsf_req, unsigned long sbtype)
/**
* zfcp_qdio_sbale_next - switch to next SBALE, chain SBALs if needed
*/
-static inline volatile struct qdio_buffer_element *
+static volatile struct qdio_buffer_element *
zfcp_qdio_sbale_next(struct zfcp_fsf_req *fsf_req, unsigned long sbtype)
{
if (fsf_req->sbale_curr == ZFCP_LAST_SBALE_PER_SBAL)
@@ -569,7 +569,7 @@ zfcp_qdio_sbale_next(struct zfcp_fsf_req *fsf_req, unsigned long sbtype)
* zfcp_qdio_sbals_zero - initialize SBALs between first and last in queue
* with zero from
*/
-static inline int
+static int
zfcp_qdio_sbals_zero(struct zfcp_qdio_queue *queue, int first, int last)
{
struct qdio_buffer **buf = queue->buffer;
@@ -603,7 +603,7 @@ zfcp_qdio_sbals_wipe(struct zfcp_fsf_req *fsf_req)
* zfcp_qdio_sbale_fill - set address and lenght in current SBALE
* on request_queue
*/
-static inline void
+static void
zfcp_qdio_sbale_fill(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
void *addr, int length)
{
@@ -624,7 +624,7 @@ zfcp_qdio_sbale_fill(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
* Alignment and length of the segment determine how many SBALEs are needed
* for the memory segment.
*/
-static inline int
+static int
zfcp_qdio_sbals_from_segment(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
void *start_addr, unsigned long total_length)
{
@@ -659,7 +659,7 @@ zfcp_qdio_sbals_from_segment(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
* @sg_count: number of elements in scatter-gather list
* @max_sbals: upper bound for number of SBALs to be used
*/
-inline int
+int
zfcp_qdio_sbals_from_sg(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
struct scatterlist *sg, int sg_count, int max_sbals)
{
@@ -707,7 +707,7 @@ out:
* @length: length of buffer
* @max_sbals: upper bound for number of SBALs to be used
*/
-static inline int
+static int
zfcp_qdio_sbals_from_buffer(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
void *buffer, unsigned long length, int max_sbals)
{
@@ -728,7 +728,7 @@ zfcp_qdio_sbals_from_buffer(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
* @scsi_cmnd: either scatter-gather list or buffer contained herein is used
* to fill SBALs
*/
-inline int
+int
zfcp_qdio_sbals_from_scsicmnd(struct zfcp_fsf_req *fsf_req,
unsigned long sbtype, struct scsi_cmnd *scsi_cmnd)
{
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c
index 452d96f92a1..99db02062c3 100644
--- a/drivers/s390/scsi/zfcp_scsi.c
+++ b/drivers/s390/scsi/zfcp_scsi.c
@@ -90,7 +90,7 @@ zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *fcp_rsp_iu)
return fcp_sns_info_ptr;
}
-fcp_dl_t *
+static fcp_dl_t *
zfcp_get_fcp_dl_ptr(struct fcp_cmnd_iu * fcp_cmd)
{
int additional_length = fcp_cmd->add_fcp_cdb_length << 2;
@@ -124,19 +124,19 @@ zfcp_set_fcp_dl(struct fcp_cmnd_iu *fcp_cmd, fcp_dl_t fcp_dl)
* regarding the specified byte
*/
static inline void
-set_byte(u32 * result, char status, char pos)
+set_byte(int *result, char status, char pos)
{
*result |= status << (pos * 8);
}
void
-set_host_byte(u32 * result, char status)
+set_host_byte(int *result, char status)
{
set_byte(result, status, 2);
}
void
-set_driver_byte(u32 * result, char status)
+set_driver_byte(int *result, char status)
{
set_byte(result, status, 3);
}
@@ -280,7 +280,7 @@ out:
return retval;
}
-void
+static void
zfcp_scsi_command_sync_handler(struct scsi_cmnd *scpnt)
{
struct completion *wait = (struct completion *) scpnt->SCp.ptr;
@@ -324,7 +324,7 @@ zfcp_scsi_command_sync(struct zfcp_unit *unit, struct scsi_cmnd *scpnt,
* returns: 0 - success, SCSI command enqueued
* !0 - failure
*/
-int
+static int
zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt,
void (*done) (struct scsi_cmnd *))
{
@@ -380,7 +380,7 @@ zfcp_unit_lookup(struct zfcp_adapter *adapter, int channel, unsigned int id,
* will handle late commands. (Usually, the normal completion of late
* commands is ignored with respect to the running abort operation.)
*/
-int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
+static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
{
struct Scsi_Host *scsi_host;
struct zfcp_adapter *adapter;
@@ -445,7 +445,7 @@ int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
return retval;
}
-int
+static int
zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *scpnt)
{
int retval;
@@ -541,7 +541,7 @@ zfcp_task_management_function(struct zfcp_unit *unit, u8 tm_flags,
/**
* zfcp_scsi_eh_host_reset_handler - handler for host and bus reset
*/
-int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt)
+static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt)
{
struct zfcp_unit *unit;
struct zfcp_adapter *adapter;
diff --git a/drivers/s390/sysinfo.c b/drivers/s390/sysinfo.c
index 1e788e815ce..090743d2f91 100644
--- a/drivers/s390/sysinfo.c
+++ b/drivers/s390/sysinfo.c
@@ -9,8 +9,14 @@
#include <linux/mm.h>
#include <linux/proc_fs.h>
#include <linux/init.h>
+#include <linux/delay.h>
#include <asm/ebcdic.h>
+/* Sigh, math-emu. Don't ask. */
+#include <asm/sfp-util.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/single.h>
+
struct sysinfo_1_1_1 {
char reserved_0[32];
char manufacturer[16];
@@ -198,7 +204,7 @@ static int stsi_1_2_2(struct sysinfo_1_2_2 *info, char *page, int len)
* if the higher order 8 bits are not zero. Printing
* a floating point number in the kernel is a no-no,
* always print the number as 32 bit unsigned integer.
- * The user-space needs to know about the stange
+ * The user-space needs to know about the strange
* encoding of the alternate cpu capability.
*/
len += sprintf(page + len, "Capability: %u %u\n",
@@ -351,3 +357,58 @@ static __init int create_proc_sysinfo(void)
__initcall(create_proc_sysinfo);
+/*
+ * CPU capability might have changed. Therefore recalculate loops_per_jiffy.
+ */
+void s390_adjust_jiffies(void)
+{
+ struct sysinfo_1_2_2 *info;
+ const unsigned int fmil = 0x4b189680; /* 1e7 as 32-bit float. */
+ FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
+ FP_DECL_EX;
+ unsigned int capability;
+
+ info = (void *) get_zeroed_page(GFP_KERNEL);
+ if (!info)
+ return;
+
+ if (stsi(info, 1, 2, 2) != -ENOSYS) {
+ /*
+ * Major sigh. The cpu capability encoding is "special".
+ * If the first 9 bits of info->capability are 0 then it
+ * is a 32 bit unsigned integer in the range 0 .. 2^23.
+ * If the first 9 bits are != 0 then it is a 32 bit float.
+ * In addition a lower value indicates a proportionally
+ * higher cpu capacity. Bogomips are the other way round.
+ * To get to a halfway suitable number we divide 1e7
+ * by the cpu capability number. Yes, that means a floating
+ * point division .. math-emu here we come :-)
+ */
+ FP_UNPACK_SP(SA, &fmil);
+ if ((info->capability >> 23) == 0)
+ FP_FROM_INT_S(SB, info->capability, 32, int);
+ else
+ FP_UNPACK_SP(SB, &info->capability);
+ FP_DIV_S(SR, SA, SB);
+ FP_TO_INT_S(capability, SR, 32, 0);
+ } else
+ /*
+ * Really old machine without stsi block for basic
+ * cpu information. Report 42.0 bogomips.
+ */
+ capability = 42;
+ loops_per_jiffy = capability * (500000/HZ);
+ free_page((unsigned long) info);
+}
+
+/*
+ * calibrate the delay loop
+ */
+void __init calibrate_delay(void)
+{
+ s390_adjust_jiffies();
+ /* Print the good old Bogomips line .. */
+ printk(KERN_DEBUG "Calibrating delay loop (skipped)... "
+ "%lu.%02lu BogoMIPS preset\n", loops_per_jiffy/(500000/HZ),
+ (loops_per_jiffy/(5000/HZ)) % 100);
+}
diff --git a/drivers/sbus/char/Kconfig b/drivers/sbus/char/Kconfig
index 3a8152906bf..35a73168333 100644
--- a/drivers/sbus/char/Kconfig
+++ b/drivers/sbus/char/Kconfig
@@ -46,13 +46,6 @@ config SUN_VIDEOPIX
based on the Phillips SAA9051, can handle NTSC and PAL/SECAM and
SVIDEO signals.
-config SUN_AURORA
- tristate "Aurora Multiboard 1600se (EXPERIMENTAL)"
- depends on EXPERIMENTAL && BROKEN
- help
- The Aurora Multiboard is a multi-port high-speed serial controller.
- If you have one of these, say Y.
-
config TADPOLE_TS102_UCTRL
tristate "Tadpole TS102 Microcontroller support (EXPERIMENTAL)"
depends on EXPERIMENTAL && SPARC32
diff --git a/drivers/sbus/char/Makefile b/drivers/sbus/char/Makefile
index 3a5ea1dc789..7ab060e9a5f 100644
--- a/drivers/sbus/char/Makefile
+++ b/drivers/sbus/char/Makefile
@@ -19,7 +19,6 @@ obj-$(CONFIG_SUN_OPENPROMIO) += openprom.o
obj-$(CONFIG_SUN_MOSTEK_RTC) += rtc.o
obj-$(CONFIG_SUN_BPP) += bpp.o
obj-$(CONFIG_SUN_VIDEOPIX) += vfc.o
-obj-$(CONFIG_SUN_AURORA) += aurora.o
obj-$(CONFIG_TADPOLE_TS102_UCTRL) += uctrl.o
obj-$(CONFIG_SUN_JSFLASH) += jsflash.o
obj-$(CONFIG_BBC_I2C) += bbc.o
diff --git a/drivers/sbus/char/aurora.c b/drivers/sbus/char/aurora.c
deleted file mode 100644
index a54b4ac6756..00000000000
--- a/drivers/sbus/char/aurora.c
+++ /dev/null
@@ -1,2364 +0,0 @@
-/* $Id: aurora.c,v 1.19 2002/01/08 16:00:16 davem Exp $
- * linux/drivers/sbus/char/aurora.c -- Aurora multiport driver
- *
- * Copyright (c) 1999 by Oliver Aldulea (oli at bv dot ro)
- *
- * This code is based on the RISCom/8 multiport serial driver written
- * by Dmitry Gorodchanin (pgmdsg@ibi.com), based on the Linux serial
- * driver, written by Linus Torvalds, Theodore T'so and others.
- * The Aurora multiport programming info was obtained mainly from the
- * Cirrus Logic CD180 documentation (available on the web), and by
- * doing heavy tests on the board. Many thanks to Eddie C. Dost for the
- * help on the sbus interface.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under 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.
- *
- * Revision 1.0
- *
- * This is the first public release.
- *
- * Most of the information you need is in the aurora.h file. Please
- * read that file before reading this one.
- *
- * Several parts of the code do not have comments yet.
- *
- * n.b. The board can support 115.2 bit rates, but only on a few
- * ports. The total badwidth of one chip (ports 0-7 or 8-15) is equal
- * to OSC_FREQ div 16. In case of my board, each chip can take 6
- * channels of 115.2 kbaud. This information is not well-tested.
- *
- * Fixed to use tty_get_baud_rate().
- * Theodore Ts'o <tytso@mit.edu>, 2001-Oct-12
- */
-
-#include <linux/module.h>
-
-#include <linux/errno.h>
-#include <linux/sched.h>
-#ifdef AURORA_INT_DEBUG
-#include <linux/timer.h>
-#endif
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/major.h>
-#include <linux/string.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/bitops.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/oplib.h>
-#include <asm/system.h>
-#include <asm/kdebug.h>
-#include <asm/sbus.h>
-#include <asm/uaccess.h>
-
-#include "aurora.h"
-#include "cd180.h"
-
-unsigned char irqs[4] = {
- 0, 0, 0, 0
-};
-
-#ifdef AURORA_INT_DEBUG
-int irqhit=0;
-#endif
-
-static struct tty_driver *aurora_driver;
-static struct Aurora_board aurora_board[AURORA_NBOARD] = {
- {0,},
-};
-
-static struct Aurora_port aurora_port[AURORA_TNPORTS] = {
- { 0, },
-};
-
-/* no longer used. static struct Aurora_board * IRQ_to_board[16] = { NULL, } ;*/
-static unsigned char * tmp_buf = NULL;
-
-DECLARE_TASK_QUEUE(tq_aurora);
-
-static inline int aurora_paranoia_check(struct Aurora_port const * port,
- char *name, const char *routine)
-{
-#ifdef AURORA_PARANOIA_CHECK
- static const char *badmagic =
- KERN_DEBUG "aurora: Warning: bad aurora port magic number for device %s in %s\n";
- static const char *badinfo =
- KERN_DEBUG "aurora: Warning: null aurora port for device %s in %s\n";
-
- if (!port) {
- printk(badinfo, name, routine);
- return 1;
- }
- if (port->magic != AURORA_MAGIC) {
- printk(badmagic, name, routine);
- return 1;
- }
-#endif
- return 0;
-}
-
-/*
- *
- * Service functions for aurora driver.
- *
- */
-
-/* Get board number from pointer */
-static inline int board_No (struct Aurora_board const * bp)
-{
- return bp - aurora_board;
-}
-
-/* Get port number from pointer */
-static inline int port_No (struct Aurora_port const * port)
-{
- return AURORA_PORT(port - aurora_port);
-}
-
-/* Get pointer to board from pointer to port */
-static inline struct Aurora_board * port_Board(struct Aurora_port const * port)
-{
- return &aurora_board[AURORA_BOARD(port - aurora_port)];
-}
-
-/* Wait for Channel Command Register ready */
-static inline void aurora_wait_CCR(struct aurora_reg128 * r)
-{
- unsigned long delay;
-
-#ifdef AURORA_DEBUG
-printk("aurora_wait_CCR\n");
-#endif
- /* FIXME: need something more descriptive than 100000 :) */
- for (delay = 100000; delay; delay--)
- if (!sbus_readb(&r->r[CD180_CCR]))
- return;
- printk(KERN_DEBUG "aurora: Timeout waiting for CCR.\n");
-}
-
-/*
- * aurora probe functions.
- */
-
-/* Must be called with enabled interrupts */
-static inline void aurora_long_delay(unsigned long delay)
-{
- unsigned long i;
-
-#ifdef AURORA_DEBUG
- printk("aurora_long_delay: start\n");
-#endif
- for (i = jiffies + delay; time_before(jiffies, i); ) ;
-#ifdef AURORA_DEBUG
- printk("aurora_long_delay: end\n");
-#endif
-}
-
-/* Reset and setup CD180 chip */
-static int aurora_init_CD180(struct Aurora_board * bp, int chip)
-{
- unsigned long flags;
- int id;
-
-#ifdef AURORA_DEBUG
- printk("aurora_init_CD180: start %d:%d\n",
- board_No(bp), chip);
-#endif
- save_flags(flags); cli();
- sbus_writeb(0, &bp->r[chip]->r[CD180_CAR]);
- sbus_writeb(0, &bp->r[chip]->r[CD180_GSVR]);
-
- /* Wait for CCR ready */
- aurora_wait_CCR(bp->r[chip]);
-
- /* Reset CD180 chip */
- sbus_writeb(CCR_HARDRESET, &bp->r[chip]->r[CD180_CCR]);
- udelay(1);
- sti();
- id=1000;
- while((--id) &&
- (sbus_readb(&bp->r[chip]->r[CD180_GSVR])!=0xff))udelay(100);
- if(!id) {
- printk(KERN_ERR "aurora%d: Chip %d failed init.\n",
- board_No(bp), chip);
- restore_flags(flags);
- return(-1);
- }
- cli();
- sbus_writeb((board_No(bp)<<5)|((chip+1)<<3),
- &bp->r[chip]->r[CD180_GSVR]); /* Set ID for this chip */
- sbus_writeb(0x80|bp->ACK_MINT,
- &bp->r[chip]->r[CD180_MSMR]); /* Prio for modem intr */
- sbus_writeb(0x80|bp->ACK_TINT,
- &bp->r[chip]->r[CD180_TSMR]); /* Prio for transmitter intr */
- sbus_writeb(0x80|bp->ACK_RINT,
- &bp->r[chip]->r[CD180_RSMR]); /* Prio for receiver intr */
- /* Setting up prescaler. We need 4 tick per 1 ms */
- sbus_writeb((bp->oscfreq/(1000000/AURORA_TPS)) >> 8,
- &bp->r[chip]->r[CD180_PPRH]);
- sbus_writeb((bp->oscfreq/(1000000/AURORA_TPS)) & 0xff,
- &bp->r[chip]->r[CD180_PPRL]);
-
- sbus_writeb(SRCR_AUTOPRI|SRCR_GLOBPRI,
- &bp->r[chip]->r[CD180_SRCR]);
-
- id = sbus_readb(&bp->r[chip]->r[CD180_GFRCR]);
- printk(KERN_INFO "aurora%d: Chip %d id %02x: ",
- board_No(bp), chip,id);
- if(sbus_readb(&bp->r[chip]->r[CD180_SRCR]) & 128) {
- switch (id) {
- case 0x82:printk("CL-CD1864 rev A\n");break;
- case 0x83:printk("CL-CD1865 rev A\n");break;
- case 0x84:printk("CL-CD1865 rev B\n");break;
- case 0x85:printk("CL-CD1865 rev C\n");break;
- default:printk("Unknown.\n");
- };
- } else {
- switch (id) {
- case 0x81:printk("CL-CD180 rev B\n");break;
- case 0x82:printk("CL-CD180 rev C\n");break;
- default:printk("Unknown.\n");
- };
- }
- restore_flags(flags);
-#ifdef AURORA_DEBUG
- printk("aurora_init_CD180: end\n");
-#endif
- return 0;
-}
-
-static int valid_irq(unsigned char irq)
-{
-int i;
-for(i=0;i<TYPE_1_IRQS;i++)
- if (type_1_irq[i]==irq) return 1;
-return 0;
-}
-
-static irqreturn_t aurora_interrupt(int irq, void * dev_id);
-
-/* Main probing routine, also sets irq. */
-static int aurora_probe(void)
-{
- struct sbus_bus *sbus;
- struct sbus_dev *sdev;
- int grrr;
- char buf[30];
- int bn = 0;
- struct Aurora_board *bp;
-
- for_each_sbus(sbus) {
- for_each_sbusdev(sdev, sbus) {
-/* printk("Try: %x %s\n",sdev,sdev->prom_name);*/
- if (!strcmp(sdev->prom_name, "sio16")) {
-#ifdef AURORA_DEBUG
- printk(KERN_INFO "aurora: sio16 at %p\n",sdev);
-#endif
- if((sdev->reg_addrs[0].reg_size!=1) &&
- (sdev->reg_addrs[1].reg_size!=128) &&
- (sdev->reg_addrs[2].reg_size!=128) &&
- (sdev->reg_addrs[3].reg_size!=4)) {
- printk(KERN_ERR "aurora%d: registers' sizes "
- "do not match.\n", bn);
- break;
- }
- bp = &aurora_board[bn];
- bp->r0 = (struct aurora_reg1 *)
- sbus_ioremap(&sdev->resource[0], 0,
- sdev->reg_addrs[0].reg_size,
- "sio16");
- if (bp->r0 == NULL) {
- printk(KERN_ERR "aurora%d: can't map "
- "reg_addrs[0]\n", bn);
- break;
- }
-#ifdef AURORA_DEBUG
- printk("Map reg 0: %p\n", bp->r0);
-#endif
- bp->r[0] = (struct aurora_reg128 *)
- sbus_ioremap(&sdev->resource[1], 0,
- sdev->reg_addrs[1].reg_size,
- "sio16");
- if (bp->r[0] == NULL) {
- printk(KERN_ERR "aurora%d: can't map "
- "reg_addrs[1]\n", bn);
- break;
- }
-#ifdef AURORA_DEBUG
- printk("Map reg 1: %p\n", bp->r[0]);
-#endif
- bp->r[1] = (struct aurora_reg128 *)
- sbus_ioremap(&sdev->resource[2], 0,
- sdev->reg_addrs[2].reg_size,
- "sio16");
- if (bp->r[1] == NULL) {
- printk(KERN_ERR "aurora%d: can't map "
- "reg_addrs[2]\n", bn);
- break;
- }
-#ifdef AURORA_DEBUG
- printk("Map reg 2: %p\n", bp->r[1]);
-#endif
- bp->r3 = (struct aurora_reg4 *)
- sbus_ioremap(&sdev->resource[3], 0,
- sdev->reg_addrs[3].reg_size,
- "sio16");
- if (bp->r3 == NULL) {
- printk(KERN_ERR "aurora%d: can't map "
- "reg_addrs[3]\n", bn);
- break;
- }
-#ifdef AURORA_DEBUG
- printk("Map reg 3: %p\n", bp->r3);
-#endif
- /* Variables setup */
- bp->flags = 0;
-#ifdef AURORA_DEBUG
- grrr=prom_getint(sdev->prom_node,"intr");
- printk("intr pri %d\n", grrr);
-#endif
- if ((bp->irq=irqs[bn]) && valid_irq(bp->irq) &&
- !request_irq(bp->irq|0x30, aurora_interrupt, IRQF_SHARED, "sio16", bp)) {
- free_irq(bp->irq|0x30, bp);
- } else
- if ((bp->irq=prom_getint(sdev->prom_node, "bintr")) && valid_irq(bp->irq) &&
- !request_irq(bp->irq|0x30, aurora_interrupt, IRQF_SHARED, "sio16", bp)) {
- free_irq(bp->irq|0x30, bp);
- } else
- if ((bp->irq=prom_getint(sdev->prom_node, "intr")) && valid_irq(bp->irq) &&
- !request_irq(bp->irq|0x30, aurora_interrupt, IRQF_SHARED, "sio16", bp)) {
- free_irq(bp->irq|0x30, bp);
- } else
- for(grrr=0;grrr<TYPE_1_IRQS;grrr++) {
- if ((bp->irq=type_1_irq[grrr])&&!request_irq(bp->irq|0x30, aurora_interrupt, IRQF_SHARED, "sio16", bp)) {
- free_irq(bp->irq|0x30, bp);
- break;
- } else {
- printk(KERN_ERR "aurora%d: Could not get an irq for this board !!!\n",bn);
- bp->flags=0xff;
- }
- }
- if(bp->flags==0xff)break;
- printk(KERN_INFO "aurora%d: irq %d\n",bn,bp->irq&0x0f);
- buf[0]=0;
- grrr=prom_getproperty(sdev->prom_node,"dtr_rts",buf,sizeof(buf));
- if(!strcmp(buf,"swapped")){
- printk(KERN_INFO "aurora%d: Swapped DTR and RTS\n",bn);
- bp->DTR=MSVR_RTS;
- bp->RTS=MSVR_DTR;
- bp->MSVDTR=CD180_MSVRTS;
- bp->MSVRTS=CD180_MSVDTR;
- bp->flags|=AURORA_BOARD_DTR_FLOW_OK;
- }else{
- #ifdef AURORA_FORCE_DTR_FLOW
- printk(KERN_INFO "aurora%d: Forcing swapped DTR-RTS\n",bn);
- bp->DTR=MSVR_RTS;
- bp->RTS=MSVR_DTR;
- bp->MSVDTR=CD180_MSVRTS;
- bp->MSVRTS=CD180_MSVDTR;
- bp->flags|=AURORA_BOARD_DTR_FLOW_OK;
- #else
- printk(KERN_INFO "aurora%d: Normal DTR and RTS\n",bn);
- bp->DTR=MSVR_DTR;
- bp->RTS=MSVR_RTS;
- bp->MSVDTR=CD180_MSVDTR;
- bp->MSVRTS=CD180_MSVRTS;
- #endif
- }
- bp->oscfreq=prom_getint(sdev->prom_node,"clk")*100;
- printk(KERN_INFO "aurora%d: Oscillator: %d Hz\n",bn,bp->oscfreq);
- grrr=prom_getproperty(sdev->prom_node,"chip",buf,sizeof(buf));
- printk(KERN_INFO "aurora%d: Chips: %s\n",bn,buf);
- grrr=prom_getproperty(sdev->prom_node,"manu",buf,sizeof(buf));
- printk(KERN_INFO "aurora%d: Manufacturer: %s\n",bn,buf);
- grrr=prom_getproperty(sdev->prom_node,"model",buf,sizeof(buf));
- printk(KERN_INFO "aurora%d: Model: %s\n",bn,buf);
- grrr=prom_getproperty(sdev->prom_node,"rev",buf,sizeof(buf));
- printk(KERN_INFO "aurora%d: Revision: %s\n",bn,buf);
- grrr=prom_getproperty(sdev->prom_node,"mode",buf,sizeof(buf));
- printk(KERN_INFO "aurora%d: Mode: %s\n",bn,buf);
- #ifdef MODULE
- bp->count=0;
- #endif
- bp->flags = AURORA_BOARD_PRESENT;
- /* hardware ack */
- bp->ACK_MINT=1;
- bp->ACK_TINT=2;
- bp->ACK_RINT=3;
- bn++;
- }
- }
- }
- return bn;
-}
-
-static void aurora_release_io_range(struct Aurora_board *bp)
-{
- sbus_iounmap((unsigned long)bp->r0, 1);
- sbus_iounmap((unsigned long)bp->r[0], 128);
- sbus_iounmap((unsigned long)bp->r[1], 128);
- sbus_iounmap((unsigned long)bp->r3, 4);
-}
-
-static inline void aurora_mark_event(struct Aurora_port * port, int event)
-{
-#ifdef AURORA_DEBUG
- printk("aurora_mark_event: start\n");
-#endif
- set_bit(event, &port->event);
- queue_task(&port->tqueue, &tq_aurora);
- mark_bh(AURORA_BH);
-#ifdef AURORA_DEBUG
- printk("aurora_mark_event: end\n");
-#endif
-}
-
-static __inline__ struct Aurora_port * aurora_get_port(struct Aurora_board const * bp,
- int chip,
- unsigned char const *what)
-{
- unsigned char channel;
- struct Aurora_port * port;
-
- channel = ((chip << 3) |
- ((sbus_readb(&bp->r[chip]->r[CD180_GSCR]) & GSCR_CHAN) >> GSCR_CHAN_OFF));
- port = &aurora_port[board_No(bp) * AURORA_NPORT * AURORA_NCD180 + channel];
- if (port->flags & ASYNC_INITIALIZED)
- return port;
-
- printk(KERN_DEBUG "aurora%d: %s interrupt from invalid port %d\n",
- board_No(bp), what, channel);
- return NULL;
-}
-
-static void aurora_receive_exc(struct Aurora_board const * bp, int chip)
-{
- struct Aurora_port *port;
- struct tty_struct *tty;
- unsigned char status;
- unsigned char ch;
-
- if (!(port = aurora_get_port(bp, chip, "Receive_x")))
- return;
-
- tty = port->tty;
- if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
-#ifdef AURORA_INTNORM
- printk("aurora%d: port %d: Working around flip buffer overflow.\n",
- board_No(bp), port_No(port));
-#endif
- return;
- }
-
-#ifdef AURORA_REPORT_OVERRUN
- status = sbus_readb(&bp->r[chip]->r[CD180_RCSR]);
- if (status & RCSR_OE) {
- port->overrun++;
-#if 1
- printk("aurora%d: port %d: Overrun. Total %ld overruns.\n",
- board_No(bp), port_No(port), port->overrun);
-#endif
- }
- status &= port->mark_mask;
-#else
- status = sbus_readb(&bp->r[chip]->r[CD180_RCSR]) & port->mark_mask;
-#endif
- ch = sbus_readb(&bp->r[chip]->r[CD180_RDR]);
- if (!status)
- return;
-
- if (status & RCSR_TOUT) {
-/* printk("aurora%d: port %d: Receiver timeout. Hardware problems ?\n",
- board_No(bp), port_No(port));*/
- return;
-
- } else if (status & RCSR_BREAK) {
- printk(KERN_DEBUG "aurora%d: port %d: Handling break...\n",
- board_No(bp), port_No(port));
- *tty->flip.flag_buf_ptr++ = TTY_BREAK;
- if (port->flags & ASYNC_SAK)
- do_SAK(tty);
-
- } else if (status & RCSR_PE)
- *tty->flip.flag_buf_ptr++ = TTY_PARITY;
-
- else if (status & RCSR_FE)
- *tty->flip.flag_buf_ptr++ = TTY_FRAME;
-
- else if (status & RCSR_OE)
- *tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
-
- else
- *tty->flip.flag_buf_ptr++ = 0;
-
- *tty->flip.char_buf_ptr++ = ch;
- tty->flip.count++;
- queue_task(&tty->flip.tqueue, &tq_timer);
-}
-
-static void aurora_receive(struct Aurora_board const * bp, int chip)
-{
- struct Aurora_port *port;
- struct tty_struct *tty;
- unsigned char count,cnt;
-
- if (!(port = aurora_get_port(bp, chip, "Receive")))
- return;
-
- tty = port->tty;
-
- count = sbus_readb(&bp->r[chip]->r[CD180_RDCR]);
-
-#ifdef AURORA_REPORT_FIFO
- port->hits[count > 8 ? 9 : count]++;
-#endif
-
- while (count--) {
- if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
-#ifdef AURORA_INTNORM
- printk("aurora%d: port %d: Working around flip buffer overflow.\n",
- board_No(bp), port_No(port));
-#endif
- break;
- }
- cnt = sbus_readb(&bp->r[chip]->r[CD180_RDR]);
- *tty->flip.char_buf_ptr++ = cnt;
- *tty->flip.flag_buf_ptr++ = 0;
- tty->flip.count++;
- }
- queue_task(&tty->flip.tqueue, &tq_timer);
-}
-
-static void aurora_transmit(struct Aurora_board const * bp, int chip)
-{
- struct Aurora_port *port;
- struct tty_struct *tty;
- unsigned char count;
-
- if (!(port = aurora_get_port(bp, chip, "Transmit")))
- return;
-
- tty = port->tty;
-
- if (port->SRER & SRER_TXEMPTY) {
- /* FIFO drained */
- sbus_writeb(port_No(port) & 7,
- &bp->r[chip]->r[CD180_CAR]);
- udelay(1);
- port->SRER &= ~SRER_TXEMPTY;
- sbus_writeb(port->SRER, &bp->r[chip]->r[CD180_SRER]);
- return;
- }
-
- if ((port->xmit_cnt <= 0 && !port->break_length)
- || tty->stopped || tty->hw_stopped) {
- sbus_writeb(port_No(port) & 7,
- &bp->r[chip]->r[CD180_CAR]);
- udelay(1);
- port->SRER &= ~SRER_TXRDY;
- sbus_writeb(port->SRER,
- &bp->r[chip]->r[CD180_SRER]);
- return;
- }
-
- if (port->break_length) {
- if (port->break_length > 0) {
- if (port->COR2 & COR2_ETC) {
- sbus_writeb(CD180_C_ESC,
- &bp->r[chip]->r[CD180_TDR]);
- sbus_writeb(CD180_C_SBRK,
- &bp->r[chip]->r[CD180_TDR]);
- port->COR2 &= ~COR2_ETC;
- }
- count = min(port->break_length, 0xff);
- sbus_writeb(CD180_C_ESC,
- &bp->r[chip]->r[CD180_TDR]);
- sbus_writeb(CD180_C_DELAY,
- &bp->r[chip]->r[CD180_TDR]);
- sbus_writeb(count,
- &bp->r[chip]->r[CD180_TDR]);
- if (!(port->break_length -= count))
- port->break_length--;
- } else {
- sbus_writeb(CD180_C_ESC,
- &bp->r[chip]->r[CD180_TDR]);
- sbus_writeb(CD180_C_EBRK,
- &bp->r[chip]->r[CD180_TDR]);
- sbus_writeb(port->COR2,
- &bp->r[chip]->r[CD180_COR2]);
- aurora_wait_CCR(bp->r[chip]);
- sbus_writeb(CCR_CORCHG2,
- &bp->r[chip]->r[CD180_CCR]);
- port->break_length = 0;
- }
- return;
- }
-
- count = CD180_NFIFO;
- do {
- u8 byte = port->xmit_buf[port->xmit_tail++];
-
- sbus_writeb(byte, &bp->r[chip]->r[CD180_TDR]);
- port->xmit_tail = port->xmit_tail & (SERIAL_XMIT_SIZE-1);
- if (--port->xmit_cnt <= 0)
- break;
- } while (--count > 0);
-
- if (port->xmit_cnt <= 0) {
- sbus_writeb(port_No(port) & 7,
- &bp->r[chip]->r[CD180_CAR]);
- udelay(1);
- port->SRER &= ~SRER_TXRDY;
- sbus_writeb(port->SRER,
- &bp->r[chip]->r[CD180_SRER]);
- }
- if (port->xmit_cnt <= port->wakeup_chars)
- aurora_mark_event(port, RS_EVENT_WRITE_WAKEUP);
-}
-
-static void aurora_check_modem(struct Aurora_board const * bp, int chip)
-{
- struct Aurora_port *port;
- struct tty_struct *tty;
- unsigned char mcr;
-
- if (!(port = aurora_get_port(bp, chip, "Modem")))
- return;
-
- tty = port->tty;
-
- mcr = sbus_readb(&bp->r[chip]->r[CD180_MCR]);
- if (mcr & MCR_CDCHG) {
- if (sbus_readb(&bp->r[chip]->r[CD180_MSVR]) & MSVR_CD)
- wake_up_interruptible(&port->open_wait);
- else
- schedule_task(&port->tqueue_hangup);
- }
-
-/* We don't have such things yet. My aurora board has DTR and RTS swapped, but that doesn't count in this driver. Let's hope
- * Aurora didn't made any boards with CTS or DSR broken...
- */
-/* #ifdef AURORA_BRAIN_DAMAGED_CTS
- if (mcr & MCR_CTSCHG) {
- if (aurora_in(bp, CD180_MSVR) & MSVR_CTS) {
- tty->hw_stopped = 0;
- port->SRER |= SRER_TXRDY;
- if (port->xmit_cnt <= port->wakeup_chars)
- aurora_mark_event(port, RS_EVENT_WRITE_WAKEUP);
- } else {
- tty->hw_stopped = 1;
- port->SRER &= ~SRER_TXRDY;
- }
- sbus_writeb(port->SRER, &bp->r[chip]->r[CD180_SRER]);
- }
- if (mcr & MCR_DSRCHG) {
- if (aurora_in(bp, CD180_MSVR) & MSVR_DSR) {
- tty->hw_stopped = 0;
- port->SRER |= SRER_TXRDY;
- if (port->xmit_cnt <= port->wakeup_chars)
- aurora_mark_event(port, RS_EVENT_WRITE_WAKEUP);
- } else {
- tty->hw_stopped = 1;
- port->SRER &= ~SRER_TXRDY;
- }
- sbus_writeb(port->SRER, &bp->r[chip]->r[CD180_SRER]);
- }
-#endif AURORA_BRAIN_DAMAGED_CTS */
-
- /* Clear change bits */
- sbus_writeb(0, &bp->r[chip]->r[CD180_MCR]);
-}
-
-/* The main interrupt processing routine */
-static irqreturn_t aurora_interrupt(int irq, void * dev_id)
-{
- unsigned char status;
- unsigned char ack,chip/*,chip_id*/;
- struct Aurora_board * bp = (struct Aurora_board *) dev_id;
- unsigned long loop = 0;
-
-#ifdef AURORA_INT_DEBUG
- printk("IRQ%d %d\n",irq,++irqhit);
-#ifdef AURORA_FLOODPRO
- if (irqhit>=AURORA_FLOODPRO)
- sbus_writeb(8, &bp->r0->r);
-#endif
-#endif
-
-/* old bp = IRQ_to_board[irq&0x0f];*/
-
- if (!bp || !(bp->flags & AURORA_BOARD_ACTIVE))
- return IRQ_NONE;
-
-/* The while() below takes care of this.
- status = sbus_readb(&bp->r[0]->r[CD180_SRSR]);
-#ifdef AURORA_INT_DEBUG
- printk("mumu: %02x\n", status);
-#endif
- if (!(status&SRSR_ANYINT))
- return IRQ_NONE; * Nobody has anything to say, so exit *
-*/
- while ((loop++ < 48) &&
- (status = sbus_readb(&bp->r[0]->r[CD180_SRSR]) & SRSR_ANYINT)){
-#ifdef AURORA_INT_DEBUG
- printk("SRSR: %02x\n", status);
-#endif
- if (status & SRSR_REXT) {
- ack = sbus_readb(&bp->r3->r[bp->ACK_RINT]);
-#ifdef AURORA_INT_DEBUG
- printk("R-ACK %02x\n", ack);
-#endif
- if ((ack >> 5) == board_No(bp)) {
- if ((chip=((ack>>3)&3)-1) < AURORA_NCD180) {
- if ((ack&GSVR_ITMASK)==GSVR_IT_RGD) {
- aurora_receive(bp,chip);
- sbus_writeb(0,
- &bp->r[chip]->r[CD180_EOSRR]);
- } else if ((ack & GSVR_ITMASK) == GSVR_IT_REXC) {
- aurora_receive_exc(bp,chip);
- sbus_writeb(0,
- &bp->r[chip]->r[CD180_EOSRR]);
- }
- }
- }
- } else if (status & SRSR_TEXT) {
- ack = sbus_readb(&bp->r3->r[bp->ACK_TINT]);
-#ifdef AURORA_INT_DEBUG
- printk("T-ACK %02x\n", ack);
-#endif
- if ((ack >> 5) == board_No(bp)) {
- if ((chip=((ack>>3)&3)-1) < AURORA_NCD180) {
- if ((ack&GSVR_ITMASK)==GSVR_IT_TX) {
- aurora_transmit(bp,chip);
- sbus_writeb(0,
- &bp->r[chip]->r[CD180_EOSRR]);
- }
- }
- }
- } else if (status & SRSR_MEXT) {
- ack = sbus_readb(&bp->r3->r[bp->ACK_MINT]);
-#ifdef AURORA_INT_DEBUG
- printk("M-ACK %02x\n", ack);
-#endif
- if ((ack >> 5) == board_No(bp)) {
- if ((chip = ((ack>>3)&3)-1) < AURORA_NCD180) {
- if ((ack&GSVR_ITMASK)==GSVR_IT_MDM) {
- aurora_check_modem(bp,chip);
- sbus_writeb(0,
- &bp->r[chip]->r[CD180_EOSRR]);
- }
- }
- }
- }
- }
-/* I guess this faster code can be used with CD1865, using AUROPRI and GLOBPRI. */
-#if 0
- while ((loop++ < 48)&&(status=bp->r[0]->r[CD180_SRSR]&SRSR_ANYINT)){
-#ifdef AURORA_INT_DEBUG
- printk("SRSR: %02x\n",status);
-#endif
- ack = sbus_readb(&bp->r3->r[0]);
-#ifdef AURORA_INT_DEBUG
- printk("ACK: %02x\n",ack);
-#endif
- if ((ack>>5)==board_No(bp)) {
- if ((chip=((ack>>3)&3)-1) < AURORA_NCD180) {
- ack&=GSVR_ITMASK;
- if (ack==GSVR_IT_RGD) {
- aurora_receive(bp,chip);
- sbus_writeb(0,
- &bp->r[chip]->r[CD180_EOSRR]);
- } else if (ack==GSVR_IT_REXC) {
- aurora_receive_exc(bp,chip);
- sbus_writeb(0,
- &bp->r[chip]->r[CD180_EOSRR]);
- } else if (ack==GSVR_IT_TX) {
- aurora_transmit(bp,chip);
- sbus_writeb(0,
- &bp->r[chip]->r[CD180_EOSRR]);
- } else if (ack==GSVR_IT_MDM) {
- aurora_check_modem(bp,chip);
- sbus_writeb(0,
- &bp->r[chip]->r[CD180_EOSRR]);
- }
- }
- }
- }
-#endif
-
-/* This is the old handling routine, used in riscom8 for only one CD180. I keep it here for reference. */
-#if 0
- for(chip=0;chip<AURORA_NCD180;chip++){
- chip_id=(board_No(bp)<<5)|((chip+1)<<3);
- loop=0;
- while ((loop++ < 1) &&
- ((status = sbus_readb(&bp->r[chip]->r[CD180_SRSR])) &
- (SRSR_TEXT | SRSR_MEXT | SRSR_REXT))) {
-
- if (status & SRSR_REXT) {
- ack = sbus_readb(&bp->r3->r[bp->ACK_RINT]);
- if (ack == (chip_id | GSVR_IT_RGD)) {
-#ifdef AURORA_INTMSG
- printk("RX ACK\n");
-#endif
- aurora_receive(bp,chip);
- } else if (ack == (chip_id | GSVR_IT_REXC)) {
-#ifdef AURORA_INTMSG
- printk("RXC ACK\n");
-#endif
- aurora_receive_exc(bp,chip);
- } else {
-#ifdef AURORA_INTNORM
- printk("aurora%d-%d: Bad receive ack 0x%02x.\n",
- board_No(bp), chip, ack);
-#endif
- }
- } else if (status & SRSR_TEXT) {
- ack = sbus_readb(&bp->r3->r[bp->ACK_TINT]);
- if (ack == (chip_id | GSVR_IT_TX)){
-#ifdef AURORA_INTMSG
- printk("TX ACK\n");
-#endif
- aurora_transmit(bp,chip);
- } else {
-#ifdef AURORA_INTNORM
- printk("aurora%d-%d: Bad transmit ack 0x%02x.\n",
- board_No(bp), chip, ack);
-#endif
- }
- } else if (status & SRSR_MEXT) {
- ack = sbus_readb(&bp->r3->r[bp->ACK_MINT]);
- if (ack == (chip_id | GSVR_IT_MDM)){
-#ifdef AURORA_INTMSG
- printk("MDM ACK\n");
-#endif
- aurora_check_modem(bp,chip);
- } else {
-#ifdef AURORA_INTNORM
- printk("aurora%d-%d: Bad modem ack 0x%02x.\n",
- board_No(bp), chip, ack);
-#endif
- }
- }
- sbus_writeb(0, &bp->r[chip]->r[CD180_EOSRR]);
- }
- }
-#endif
-
- return IRQ_HANDLED;
-}
-
-#ifdef AURORA_INT_DEBUG
-static void aurora_timer (unsigned long ignored);
-
-static DEFINE_TIMER(aurora_poll_timer, aurora_timer, 0, 0);
-
-static void
-aurora_timer (unsigned long ignored)
-{
- unsigned long flags;
- int i;
-
- save_flags(flags); cli();
-
- printk("SRSR: %02x,%02x - ",
- sbus_readb(&aurora_board[0].r[0]->r[CD180_SRSR]),
- sbus_readb(&aurora_board[0].r[1]->r[CD180_SRSR]));
- for (i = 0; i < 4; i++) {
- udelay(1);
- printk("%02x ",
- sbus_readb(&aurora_board[0].r3->r[i]));
- }
- printk("\n");
-
- aurora_poll_timer.expires = jiffies + 300;
- add_timer (&aurora_poll_timer);
-
- restore_flags(flags);
-}
-#endif
-
-/*
- * Routines for open & close processing.
- */
-
-/* Called with disabled interrupts */
-static int aurora_setup_board(struct Aurora_board * bp)
-{
- int error;
-
-#ifdef AURORA_ALLIRQ
- int i;
- for (i = 0; i < AURORA_ALLIRQ; i++) {
- error = request_irq(allirq[i]|0x30, aurora_interrupt, IRQF_SHARED,
- "sio16", bp);
- if (error)
- printk(KERN_ERR "IRQ%d request error %d\n",
- allirq[i], error);
- }
-#else
- error = request_irq(bp->irq|0x30, aurora_interrupt, IRQF_SHARED,
- "sio16", bp);
- if (error) {
- printk(KERN_ERR "IRQ request error %d\n", error);
- return error;
- }
-#endif
- /* Board reset */
- sbus_writeb(0, &bp->r0->r);
- udelay(1);
- if (bp->flags & AURORA_BOARD_TYPE_2) {
- /* unknown yet */
- } else {
- sbus_writeb((AURORA_CFG_ENABLE_IO | AURORA_CFG_ENABLE_IRQ |
- (((bp->irq)&0x0f)>>2)),
- &bp->r0->r);
- }
- udelay(10000);
-
- if (aurora_init_CD180(bp,0))error=1;error=0;
- if (aurora_init_CD180(bp,1))error++;
- if (error == AURORA_NCD180) {
- printk(KERN_ERR "Both chips failed initialisation.\n");
- return -EIO;
- }
-
-#ifdef AURORA_INT_DEBUG
- aurora_poll_timer.expires= jiffies + 1;
- add_timer(&aurora_poll_timer);
-#endif
-#ifdef AURORA_DEBUG
- printk("aurora_setup_board: end\n");
-#endif
- return 0;
-}
-
-/* Called with disabled interrupts */
-static void aurora_shutdown_board(struct Aurora_board *bp)
-{
- int i;
-
-#ifdef AURORA_DEBUG
- printk("aurora_shutdown_board: start\n");
-#endif
-
-#ifdef AURORA_INT_DEBUG
- del_timer(&aurora_poll_timer);
-#endif
-
-#ifdef AURORA_ALLIRQ
- for(i=0;i<AURORA_ALLIRQ;i++){
- free_irq(allirq[i]|0x30, bp);
-/* IRQ_to_board[allirq[i]&0xf] = NULL;*/
- }
-#else
- free_irq(bp->irq|0x30, bp);
-/* IRQ_to_board[bp->irq&0xf] = NULL;*/
-#endif
- /* Drop all DTR's */
- for(i=0;i<16;i++){
- sbus_writeb(i & 7, &bp->r[i>>3]->r[CD180_CAR]);
- udelay(1);
- sbus_writeb(0, &bp->r[i>>3]->r[CD180_MSVR]);
- udelay(1);
- }
- /* Board shutdown */
- sbus_writeb(0, &bp->r0->r);
-
-#ifdef AURORA_DEBUG
- printk("aurora_shutdown_board: end\n");
-#endif
-}
-
-/* Setting up port characteristics.
- * Must be called with disabled interrupts
- */
-static void aurora_change_speed(struct Aurora_board *bp, struct Aurora_port *port)
-{
- struct tty_struct *tty;
- unsigned long baud;
- long tmp;
- unsigned char cor1 = 0, cor3 = 0;
- unsigned char mcor1 = 0, mcor2 = 0,chip;
-
-#ifdef AURORA_DEBUG
- printk("aurora_change_speed: start\n");
-#endif
- if (!(tty = port->tty) || !tty->termios)
- return;
-
- chip = AURORA_CD180(port_No(port));
-
- port->SRER = 0;
- port->COR2 = 0;
- port->MSVR = MSVR_RTS|MSVR_DTR;
-
- baud = tty_get_baud_rate(tty);
-
- /* Select port on the board */
- sbus_writeb(port_No(port) & 7,
- &bp->r[chip]->r[CD180_CAR]);
- udelay(1);
-
- if (!baud) {
- /* Drop DTR & exit */
- port->MSVR &= ~(bp->DTR|bp->RTS);
- sbus_writeb(port->MSVR,
- &bp->r[chip]->r[CD180_MSVR]);
- return;
- } else {
- /* Set DTR on */
- port->MSVR |= bp->DTR;
- sbus_writeb(port->MSVR,
- &bp->r[chip]->r[CD180_MSVR]);
- }
-
- /* Now we must calculate some speed dependent things. */
-
- /* Set baud rate for port. */
- tmp = (((bp->oscfreq + baud/2) / baud +
- CD180_TPC/2) / CD180_TPC);
-
-/* tmp = (bp->oscfreq/7)/baud;
- if((tmp%10)>4)tmp=tmp/10+1;else tmp=tmp/10;*/
-/* printk("Prescaler period: %d\n",tmp);*/
-
- sbus_writeb((tmp >> 8) & 0xff,
- &bp->r[chip]->r[CD180_RBPRH]);
- sbus_writeb((tmp >> 8) & 0xff,
- &bp->r[chip]->r[CD180_TBPRH]);
- sbus_writeb(tmp & 0xff, &bp->r[chip]->r[CD180_RBPRL]);
- sbus_writeb(tmp & 0xff, &bp->r[chip]->r[CD180_TBPRL]);
-
- baud = (baud + 5) / 10; /* Estimated CPS */
-
- /* Two timer ticks seems enough to wakeup something like SLIP driver */
- tmp = ((baud + HZ/2) / HZ) * 2 - CD180_NFIFO;
- port->wakeup_chars = (tmp < 0) ? 0 : ((tmp >= SERIAL_XMIT_SIZE) ?
- SERIAL_XMIT_SIZE - 1 : tmp);
-
- /* Receiver timeout will be transmission time for 1.5 chars */
- tmp = (AURORA_TPS + AURORA_TPS/2 + baud/2) / baud;
- tmp = (tmp > 0xff) ? 0xff : tmp;
- sbus_writeb(tmp, &bp->r[chip]->r[CD180_RTPR]);
-
- switch (C_CSIZE(tty)) {
- case CS5:
- cor1 |= COR1_5BITS;
- break;
- case CS6:
- cor1 |= COR1_6BITS;
- break;
- case CS7:
- cor1 |= COR1_7BITS;
- break;
- case CS8:
- cor1 |= COR1_8BITS;
- break;
- }
-
- if (C_CSTOPB(tty))
- cor1 |= COR1_2SB;
-
- cor1 |= COR1_IGNORE;
- if (C_PARENB(tty)) {
- cor1 |= COR1_NORMPAR;
- if (C_PARODD(tty))
- cor1 |= COR1_ODDP;
- if (I_INPCK(tty))
- cor1 &= ~COR1_IGNORE;
- }
- /* Set marking of some errors */
- port->mark_mask = RCSR_OE | RCSR_TOUT;
- if (I_INPCK(tty))
- port->mark_mask |= RCSR_FE | RCSR_PE;
- if (I_BRKINT(tty) || I_PARMRK(tty))
- port->mark_mask |= RCSR_BREAK;
- if (I_IGNPAR(tty))
- port->mark_mask &= ~(RCSR_FE | RCSR_PE);
- if (I_IGNBRK(tty)) {
- port->mark_mask &= ~RCSR_BREAK;
- if (I_IGNPAR(tty))
- /* Real raw mode. Ignore all */
- port->mark_mask &= ~RCSR_OE;
- }
- /* Enable Hardware Flow Control */
- if (C_CRTSCTS(tty)) {
-/*#ifdef AURORA_BRAIN_DAMAGED_CTS
- port->SRER |= SRER_DSR | SRER_CTS;
- mcor1 |= MCOR1_DSRZD | MCOR1_CTSZD;
- mcor2 |= MCOR2_DSROD | MCOR2_CTSOD;
- tty->hw_stopped = !(aurora_in(bp, CD180_MSVR) & (MSVR_CTS|MSVR_DSR));
-#else*/
- port->COR2 |= COR2_CTSAE;
-/*#endif*/
- if (bp->flags&AURORA_BOARD_DTR_FLOW_OK) {
- mcor1 |= AURORA_RXTH;
- }
- }
- /* Enable Software Flow Control. FIXME: I'm not sure about this */
- /* Some people reported that it works, but I still doubt */
- if (I_IXON(tty)) {
- port->COR2 |= COR2_TXIBE;
- cor3 |= (COR3_FCT | COR3_SCDE);
- if (I_IXANY(tty))
- port->COR2 |= COR2_IXM;
- sbus_writeb(START_CHAR(tty),
- &bp->r[chip]->r[CD180_SCHR1]);
- sbus_writeb(STOP_CHAR(tty),
- &bp->r[chip]->r[CD180_SCHR2]);
- sbus_writeb(START_CHAR(tty),
- &bp->r[chip]->r[CD180_SCHR3]);
- sbus_writeb(STOP_CHAR(tty),
- &bp->r[chip]->r[CD180_SCHR4]);
- }
- if (!C_CLOCAL(tty)) {
- /* Enable CD check */
- port->SRER |= SRER_CD;
- mcor1 |= MCOR1_CDZD;
- mcor2 |= MCOR2_CDOD;
- }
-
- if (C_CREAD(tty))
- /* Enable receiver */
- port->SRER |= SRER_RXD;
-
- /* Set input FIFO size (1-8 bytes) */
- cor3 |= AURORA_RXFIFO;
- /* Setting up CD180 channel registers */
- sbus_writeb(cor1, &bp->r[chip]->r[CD180_COR1]);
- sbus_writeb(port->COR2, &bp->r[chip]->r[CD180_COR2]);
- sbus_writeb(cor3, &bp->r[chip]->r[CD180_COR3]);
- /* Make CD180 know about registers change */
- aurora_wait_CCR(bp->r[chip]);
- sbus_writeb(CCR_CORCHG1 | CCR_CORCHG2 | CCR_CORCHG3,
- &bp->r[chip]->r[CD180_CCR]);
- /* Setting up modem option registers */
- sbus_writeb(mcor1, &bp->r[chip]->r[CD180_MCOR1]);
- sbus_writeb(mcor2, &bp->r[chip]->r[CD180_MCOR2]);
- /* Enable CD180 transmitter & receiver */
- aurora_wait_CCR(bp->r[chip]);
- sbus_writeb(CCR_TXEN | CCR_RXEN, &bp->r[chip]->r[CD180_CCR]);
- /* Enable interrupts */
- sbus_writeb(port->SRER, &bp->r[chip]->r[CD180_SRER]);
- /* And finally set RTS on */
- sbus_writeb(port->MSVR, &bp->r[chip]->r[CD180_MSVR]);
-#ifdef AURORA_DEBUG
- printk("aurora_change_speed: end\n");
-#endif
-}
-
-/* Must be called with interrupts enabled */
-static int aurora_setup_port(struct Aurora_board *bp, struct Aurora_port *port)
-{
- unsigned long flags;
-
-#ifdef AURORA_DEBUG
- printk("aurora_setup_port: start %d\n",port_No(port));
-#endif
- if (port->flags & ASYNC_INITIALIZED)
- return 0;
-
- if (!port->xmit_buf) {
- /* We may sleep in get_zeroed_page() */
- unsigned long tmp;
-
- if (!(tmp = get_zeroed_page(GFP_KERNEL)))
- return -ENOMEM;
-
- if (port->xmit_buf) {
- free_page(tmp);
- return -ERESTARTSYS;
- }
- port->xmit_buf = (unsigned char *) tmp;
- }
-
- save_flags(flags); cli();
-
- if (port->tty)
- clear_bit(TTY_IO_ERROR, &port->tty->flags);
-
-#ifdef MODULE
- if ((port->count == 1) && ((++bp->count) == 1))
- bp->flags |= AURORA_BOARD_ACTIVE;
-#endif
-
- port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
- aurora_change_speed(bp, port);
- port->flags |= ASYNC_INITIALIZED;
-
- restore_flags(flags);
-#ifdef AURORA_DEBUG
- printk("aurora_setup_port: end\n");
-#endif
- return 0;
-}
-
-/* Must be called with interrupts disabled */
-static void aurora_shutdown_port(struct Aurora_board *bp, struct Aurora_port *port)
-{
- struct tty_struct *tty;
- unsigned char chip;
-
-#ifdef AURORA_DEBUG
- printk("aurora_shutdown_port: start\n");
-#endif
- if (!(port->flags & ASYNC_INITIALIZED))
- return;
-
- chip = AURORA_CD180(port_No(port));
-
-#ifdef AURORA_REPORT_OVERRUN
- printk("aurora%d: port %d: Total %ld overruns were detected.\n",
- board_No(bp), port_No(port), port->overrun);
-#endif
-#ifdef AURORA_REPORT_FIFO
- {
- int i;
-
- printk("aurora%d: port %d: FIFO hits [ ",
- board_No(bp), port_No(port));
- for (i = 0; i < 10; i++) {
- printk("%ld ", port->hits[i]);
- }
- printk("].\n");
- }
-#endif
- if (port->xmit_buf) {
- free_page((unsigned long) port->xmit_buf);
- port->xmit_buf = NULL;
- }
-
- if (!(tty = port->tty) || C_HUPCL(tty)) {
- /* Drop DTR */
- port->MSVR &= ~(bp->DTR|bp->RTS);
- sbus_writeb(port->MSVR,
- &bp->r[chip]->r[CD180_MSVR]);
- }
-
- /* Select port */
- sbus_writeb(port_No(port) & 7,
- &bp->r[chip]->r[CD180_CAR]);
- udelay(1);
-
- /* Reset port */
- aurora_wait_CCR(bp->r[chip]);
- sbus_writeb(CCR_SOFTRESET, &bp->r[chip]->r[CD180_CCR]);
-
- /* Disable all interrupts from this port */
- port->SRER = 0;
- sbus_writeb(port->SRER, &bp->r[chip]->r[CD180_SRER]);
-
- if (tty)
- set_bit(TTY_IO_ERROR, &tty->flags);
- port->flags &= ~ASYNC_INITIALIZED;
-
-#ifdef MODULE
- if (--bp->count < 0) {
- printk(KERN_DEBUG "aurora%d: aurora_shutdown_port: "
- "bad board count: %d\n",
- board_No(bp), bp->count);
- bp->count = 0;
- }
-
- if (!bp->count)
- bp->flags &= ~AURORA_BOARD_ACTIVE;
-#endif
-
-#ifdef AURORA_DEBUG
- printk("aurora_shutdown_port: end\n");
-#endif
-}
-
-
-static int block_til_ready(struct tty_struct *tty, struct file * filp,
- struct Aurora_port *port)
-{
- DECLARE_WAITQUEUE(wait, current);
- struct Aurora_board *bp = port_Board(port);
- int retval;
- int do_clocal = 0;
- int CD;
- unsigned char chip;
-
-#ifdef AURORA_DEBUG
- printk("block_til_ready: start\n");
-#endif
- chip = AURORA_CD180(port_No(port));
-
- /* If the device is in the middle of being closed, then block
- * until it's done, and then try again.
- */
- if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
- interruptible_sleep_on(&port->close_wait);
- if (port->flags & ASYNC_HUP_NOTIFY)
- return -EAGAIN;
- else
- return -ERESTARTSYS;
- }
-
- /* If non-blocking mode is set, or the port is not enabled,
- * then make the check up front and then exit.
- */
- if ((filp->f_flags & O_NONBLOCK) ||
- (tty->flags & (1 << TTY_IO_ERROR))) {
- port->flags |= ASYNC_NORMAL_ACTIVE;
- return 0;
- }
-
- if (C_CLOCAL(tty))
- do_clocal = 1;
-
- /* Block waiting for the carrier detect and the line to become
- * free (i.e., not in use by the callout). While we are in
- * this loop, info->count is dropped by one, so that
- * rs_close() knows when to free things. We restore it upon
- * exit, either normal or abnormal.
- */
- retval = 0;
- add_wait_queue(&port->open_wait, &wait);
- cli();
- if (!tty_hung_up_p(filp))
- port->count--;
- sti();
- port->blocked_open++;
- while (1) {
- cli();
- sbus_writeb(port_No(port) & 7,
- &bp->r[chip]->r[CD180_CAR]);
- udelay(1);
- CD = sbus_readb(&bp->r[chip]->r[CD180_MSVR]) & MSVR_CD;
- port->MSVR=bp->RTS;
-
- /* auto drops DTR */
- sbus_writeb(port->MSVR, &bp->r[chip]->r[CD180_MSVR]);
- sti();
- set_current_state(TASK_INTERRUPTIBLE);
- if (tty_hung_up_p(filp) ||
- !(port->flags & ASYNC_INITIALIZED)) {
- if (port->flags & ASYNC_HUP_NOTIFY)
- retval = -EAGAIN;
- else
- retval = -ERESTARTSYS;
- break;
- }
- if (!(port->flags & ASYNC_CLOSING) &&
- (do_clocal || CD))
- break;
- if (signal_pending(current)) {
- retval = -ERESTARTSYS;
- break;
- }
- schedule();
- }
- current->state = TASK_RUNNING;
- remove_wait_queue(&port->open_wait, &wait);
- if (!tty_hung_up_p(filp))
- port->count++;
- port->blocked_open--;
- if (retval)
- return retval;
-
- port->flags |= ASYNC_NORMAL_ACTIVE;
-#ifdef AURORA_DEBUG
- printk("block_til_ready: end\n");
-#endif
- return 0;
-}
-
-static int aurora_open(struct tty_struct * tty, struct file * filp)
-{
- int board;
- int error;
- struct Aurora_port * port;
- struct Aurora_board * bp;
- unsigned long flags;
-
-#ifdef AURORA_DEBUG
- printk("aurora_open: start\n");
-#endif
-
- board = AURORA_BOARD(tty->index);
- if (board > AURORA_NBOARD ||
- !(aurora_board[board].flags & AURORA_BOARD_PRESENT)) {
-#ifdef AURORA_DEBUG
- printk("aurora_open: error board %d present %d\n",
- board, aurora_board[board].flags & AURORA_BOARD_PRESENT);
-#endif
- return -ENODEV;
- }
-
- bp = &aurora_board[board];
- port = aurora_port + board * AURORA_NPORT * AURORA_NCD180 + AURORA_PORT(tty->index);
- if ((aurora_paranoia_check(port, tty->name, "aurora_open")) {
-#ifdef AURORA_DEBUG
- printk("aurora_open: error paranoia check\n");
-#endif
- return -ENODEV;
- }
-
- port->count++;
- tty->driver_data = port;
- port->tty = tty;
-
- if ((error = aurora_setup_port(bp, port))) {
-#ifdef AURORA_DEBUG
- printk("aurora_open: error aurora_setup_port ret %d\n",error);
-#endif
- return error;
- }
-
- if ((error = block_til_ready(tty, filp, port))) {
-#ifdef AURORA_DEBUG
- printk("aurora_open: error block_til_ready ret %d\n",error);
-#endif
- return error;
- }
-
-#ifdef AURORA_DEBUG
- printk("aurora_open: end\n");
-#endif
- return 0;
-}
-
-static void aurora_close(struct tty_struct * tty, struct file * filp)
-{
- struct Aurora_port *port = (struct Aurora_port *) tty->driver_data;
- struct Aurora_board *bp;
- unsigned long flags;
- unsigned long timeout;
- unsigned char chip;
-
-#ifdef AURORA_DEBUG
- printk("aurora_close: start\n");
-#endif
-
- if (!port || (aurora_paranoia_check(port, tty->name, "close"))
- return;
-
- chip = AURORA_CD180(port_No(port));
-
- save_flags(flags); cli();
- if (tty_hung_up_p(filp)) {
- restore_flags(flags);
- return;
- }
-
- bp = port_Board(port);
- if ((tty->count == 1) && (port->count != 1)) {
- printk(KERN_DEBUG "aurora%d: aurora_close: bad port count; "
- "tty->count is 1, port count is %d\n",
- board_No(bp), port->count);
- port->count = 1;
- }
- if (--port->count < 0) {
- printk(KERN_DEBUG "aurora%d: aurora_close: bad port "
- "count for tty%d: %d\n",
- board_No(bp), port_No(port), port->count);
- port->count = 0;
- }
- if (port->count) {
- restore_flags(flags);
- return;
- }
- port->flags |= ASYNC_CLOSING;
-
- /* Now we wait for the transmit buffer to clear; and we notify
- * the line discipline to only process XON/XOFF characters.
- */
- tty->closing = 1;
- if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE){
-#ifdef AURORA_DEBUG
- printk("aurora_close: waiting to flush...\n");
-#endif
- tty_wait_until_sent(tty, port->closing_wait);
- }
-
- /* At this point we stop accepting input. To do this, we
- * disable the receive line status interrupts, and tell the
- * interrupt driver to stop checking the data ready bit in the
- * line status register.
- */
- port->SRER &= ~SRER_RXD;
- if (port->flags & ASYNC_INITIALIZED) {
- port->SRER &= ~SRER_TXRDY;
- port->SRER |= SRER_TXEMPTY;
- sbus_writeb(port_No(port) & 7,
- &bp->r[chip]->r[CD180_CAR]);
- udelay(1);
- sbus_writeb(port->SRER, &bp->r[chip]->r[CD180_SRER]);
- /*
- * Before we drop DTR, make sure the UART transmitter
- * has completely drained; this is especially
- * important if there is a transmit FIFO!
- */
- timeout = jiffies+HZ;
- while(port->SRER & SRER_TXEMPTY) {
- msleep_interruptible(jiffies_to_msecs(port->timeout));
- if (time_after(jiffies, timeout))
- break;
- }
- }
-#ifdef AURORA_DEBUG
- printk("aurora_close: shutdown_port\n");
-#endif
- aurora_shutdown_port(bp, port);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
- tty_ldisc_flush(tty);
- tty->closing = 0;
- port->event = 0;
- port->tty = 0;
- if (port->blocked_open) {
- if (port->close_delay) {
- msleep_interruptible(jiffies_to_msecs(port->close_delay));
- }
- wake_up_interruptible(&port->open_wait);
- }
- port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
- wake_up_interruptible(&port->close_wait);
- restore_flags(flags);
-#ifdef AURORA_DEBUG
- printk("aurora_close: end\n");
-#endif
-}
-
-static int aurora_write(struct tty_struct * tty,
- const unsigned char *buf, int count)
-{
- struct Aurora_port *port = (struct Aurora_port *) tty->driver_data;
- struct Aurora_board *bp;
- int c, total = 0;
- unsigned long flags;
- unsigned char chip;
-
-#ifdef AURORA_DEBUG
- printk("aurora_write: start %d\n",count);
-#endif
- if ((aurora_paranoia_check(port, tty->name, "aurora_write"))
- return 0;
-
- chip = AURORA_CD180(port_No(port));
-
- bp = port_Board(port);
-
- if (!tty || !port->xmit_buf || !tmp_buf)
- return 0;
-
- save_flags(flags);
- while (1) {
- cli();
- c = min(count, min(SERIAL_XMIT_SIZE - port->xmit_cnt - 1,
- SERIAL_XMIT_SIZE - port->xmit_head));
- if (c <= 0) {
- restore_flags(flags);
- break;
- }
- memcpy(port->xmit_buf + port->xmit_head, buf, c);
- port->xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
- port->xmit_cnt += c;
- restore_flags(flags);
-
- buf += c;
- count -= c;
- total += c;
- }
-
- cli();
- if (port->xmit_cnt && !tty->stopped && !tty->hw_stopped &&
- !(port->SRER & SRER_TXRDY)) {
- port->SRER |= SRER_TXRDY;
- sbus_writeb(port_No(port) & 7,
- &bp->r[chip]->r[CD180_CAR]);
- udelay(1);
- sbus_writeb(port->SRER, &bp->r[chip]->r[CD180_SRER]);
- }
- restore_flags(flags);
-#ifdef AURORA_DEBUG
- printk("aurora_write: end %d\n",total);
-#endif
- return total;
-}
-
-static void aurora_put_char(struct tty_struct * tty, unsigned char ch)
-{
- struct Aurora_port *port = (struct Aurora_port *) tty->driver_data;
- unsigned long flags;
-
-#ifdef AURORA_DEBUG
- printk("aurora_put_char: start %c\n",ch);
-#endif
- if ((aurora_paranoia_check(port, tty->name, "aurora_put_char"))
- return;
-
- if (!tty || !port->xmit_buf)
- return;
-
- save_flags(flags); cli();
-
- if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {
- restore_flags(flags);
- return;
- }
-
- port->xmit_buf[port->xmit_head++] = ch;
- port->xmit_head &= SERIAL_XMIT_SIZE - 1;
- port->xmit_cnt++;
- restore_flags(flags);
-#ifdef AURORA_DEBUG
- printk("aurora_put_char: end\n");
-#endif
-}
-
-static void aurora_flush_chars(struct tty_struct * tty)
-{
- struct Aurora_port *port = (struct Aurora_port *) tty->driver_data;
- unsigned long flags;
- unsigned char chip;
-
-/*#ifdef AURORA_DEBUG
- printk("aurora_flush_chars: start\n");
-#endif*/
- if ((aurora_paranoia_check(port, tty->name, "aurora_flush_chars"))
- return;
-
- chip = AURORA_CD180(port_No(port));
-
- if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
- !port->xmit_buf)
- return;
-
- save_flags(flags); cli();
- port->SRER |= SRER_TXRDY;
- sbus_writeb(port_No(port) & 7,
- &port_Board(port)->r[chip]->r[CD180_CAR]);
- udelay(1);
- sbus_writeb(port->SRER,
- &port_Board(port)->r[chip]->r[CD180_SRER]);
- restore_flags(flags);
-/*#ifdef AURORA_DEBUG
- printk("aurora_flush_chars: end\n");
-#endif*/
-}
-
-static int aurora_write_room(struct tty_struct * tty)
-{
- struct Aurora_port *port = (struct Aurora_port *) tty->driver_data;
- int ret;
-
-#ifdef AURORA_DEBUG
- printk("aurora_write_room: start\n");
-#endif
- if ((aurora_paranoia_check(port, tty->name, "aurora_write_room"))
- return 0;
-
- ret = SERIAL_XMIT_SIZE - port->xmit_cnt - 1;
- if (ret < 0)
- ret = 0;
-#ifdef AURORA_DEBUG
- printk("aurora_write_room: end\n");
-#endif
- return ret;
-}
-
-static int aurora_chars_in_buffer(struct tty_struct *tty)
-{
- struct Aurora_port *port = (struct Aurora_port *) tty->driver_data;
-
- if ((aurora_paranoia_check(port, tty->name, "aurora_chars_in_buffer"))
- return 0;
-
- return port->xmit_cnt;
-}
-
-static void aurora_flush_buffer(struct tty_struct *tty)
-{
- struct Aurora_port *port = (struct Aurora_port *) tty->driver_data;
- unsigned long flags;
-
-#ifdef AURORA_DEBUG
- printk("aurora_flush_buffer: start\n");
-#endif
- if ((aurora_paranoia_check(port, tty->name, "aurora_flush_buffer"))
- return;
-
- save_flags(flags); cli();
- port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
- restore_flags(flags);
-
- tty_wakeup(tty);
-#ifdef AURORA_DEBUG
- printk("aurora_flush_buffer: end\n");
-#endif
-}
-
-static int aurora_tiocmget(struct tty_struct *tty, struct file *file)
-{
- struct Aurora_port *port = (struct Aurora_port *) tty->driver_data;
- struct Aurora_board * bp;
- unsigned char status,chip;
- unsigned int result;
- unsigned long flags;
-
-#ifdef AURORA_DEBUG
- printk("aurora_get_modem_info: start\n");
-#endif
- if ((aurora_paranoia_check(port, tty->name, __FUNCTION__))
- return -ENODEV;
-
- chip = AURORA_CD180(port_No(port));
-
- bp = port_Board(port);
-
- save_flags(flags); cli();
-
- sbus_writeb(port_No(port) & 7, &bp->r[chip]->r[CD180_CAR]);
- udelay(1);
-
- status = sbus_readb(&bp->r[chip]->r[CD180_MSVR]);
- result = 0/*bp->r[chip]->r[AURORA_RI] & (1u << port_No(port)) ? 0 : TIOCM_RNG*/;
-
- restore_flags(flags);
-
- result |= ((status & bp->RTS) ? TIOCM_RTS : 0)
- | ((status & bp->DTR) ? TIOCM_DTR : 0)
- | ((status & MSVR_CD) ? TIOCM_CAR : 0)
- | ((status & MSVR_DSR) ? TIOCM_DSR : 0)
- | ((status & MSVR_CTS) ? TIOCM_CTS : 0);
-
-#ifdef AURORA_DEBUG
- printk("aurora_get_modem_info: end\n");
-#endif
- return result;
-}
-
-static int aurora_tiocmset(struct tty_struct *tty, struct file *file,
- unsigned int set, unsigned int clear)
-{
- struct Aurora_port *port = (struct Aurora_port *) tty->driver_data;
- unsigned int arg;
- unsigned long flags;
- struct Aurora_board *bp = port_Board(port);
- unsigned char chip;
-
-#ifdef AURORA_DEBUG
- printk("aurora_set_modem_info: start\n");
-#endif
- if ((aurora_paranoia_check(port, tty->name, __FUNCTION__))
- return -ENODEV;
-
- chip = AURORA_CD180(port_No(port));
-
- save_flags(flags); cli();
- if (set & TIOCM_RTS)
- port->MSVR |= bp->RTS;
- if (set & TIOCM_DTR)
- port->MSVR |= bp->DTR;
- if (clear & TIOCM_RTS)
- port->MSVR &= ~bp->RTS;
- if (clear & TIOCM_DTR)
- port->MSVR &= ~bp->DTR;
-
- sbus_writeb(port_No(port) & 7, &bp->r[chip]->r[CD180_CAR]);
- udelay(1);
-
- sbus_writeb(port->MSVR, &bp->r[chip]->r[CD180_MSVR]);
-
- restore_flags(flags);
-#ifdef AURORA_DEBUG
- printk("aurora_set_modem_info: end\n");
-#endif
- return 0;
-}
-
-static void aurora_send_break(struct Aurora_port * port, unsigned long length)
-{
- struct Aurora_board *bp = port_Board(port);
- unsigned long flags;
- unsigned char chip;
-
-#ifdef AURORA_DEBUG
- printk("aurora_send_break: start\n");
-#endif
- chip = AURORA_CD180(port_No(port));
-
- save_flags(flags); cli();
-
- port->break_length = AURORA_TPS / HZ * length;
- port->COR2 |= COR2_ETC;
- port->SRER |= SRER_TXRDY;
- sbus_writeb(port_No(port) & 7, &bp->r[chip]->r[CD180_CAR]);
- udelay(1);
-
- sbus_writeb(port->COR2, &bp->r[chip]->r[CD180_COR2]);
- sbus_writeb(port->SRER, &bp->r[chip]->r[CD180_SRER]);
- aurora_wait_CCR(bp->r[chip]);
-
- sbus_writeb(CCR_CORCHG2, &bp->r[chip]->r[CD180_CCR]);
- aurora_wait_CCR(bp->r[chip]);
-
- restore_flags(flags);
-#ifdef AURORA_DEBUG
- printk("aurora_send_break: end\n");
-#endif
-}
-
-static int aurora_set_serial_info(struct Aurora_port * port,
- struct serial_struct * newinfo)
-{
- struct serial_struct tmp;
- struct Aurora_board *bp = port_Board(port);
- int change_speed;
- unsigned long flags;
-
-#ifdef AURORA_DEBUG
- printk("aurora_set_serial_info: start\n");
-#endif
- if (copy_from_user(&tmp, newinfo, sizeof(tmp)))
- return -EFAULT;
-#if 0
- if ((tmp.irq != bp->irq) ||
- (tmp.port != bp->base) ||
- (tmp.type != PORT_CIRRUS) ||
- (tmp.baud_base != (bp->oscfreq + CD180_TPC/2) / CD180_TPC) ||
- (tmp.custom_divisor != 0) ||
- (tmp.xmit_fifo_size != CD180_NFIFO) ||
- (tmp.flags & ~AURORA_LEGAL_FLAGS))
- return -EINVAL;
-#endif
-
- change_speed = ((port->flags & ASYNC_SPD_MASK) !=
- (tmp.flags & ASYNC_SPD_MASK));
-
- if (!capable(CAP_SYS_ADMIN)) {
- if ((tmp.close_delay != port->close_delay) ||
- (tmp.closing_wait != port->closing_wait) ||
- ((tmp.flags & ~ASYNC_USR_MASK) !=
- (port->flags & ~ASYNC_USR_MASK)))
- return -EPERM;
- port->flags = ((port->flags & ~ASYNC_USR_MASK) |
- (tmp.flags & ASYNC_USR_MASK));
- } else {
- port->flags = ((port->flags & ~ASYNC_FLAGS) |
- (tmp.flags & ASYNC_FLAGS));
- port->close_delay = tmp.close_delay;
- port->closing_wait = tmp.closing_wait;
- }
- if (change_speed) {
- save_flags(flags); cli();
- aurora_change_speed(bp, port);
- restore_flags(flags);
- }
-#ifdef AURORA_DEBUG
- printk("aurora_set_serial_info: end\n");
-#endif
- return 0;
-}
-
-extern int aurora_get_serial_info(struct Aurora_port * port,
- struct serial_struct * retinfo)
-{
- struct serial_struct tmp;
- struct Aurora_board *bp = port_Board(port);
-
-#ifdef AURORA_DEBUG
- printk("aurora_get_serial_info: start\n");
-#endif
- if (!access_ok(VERIFY_WRITE, (void *) retinfo, sizeof(tmp)))
- return -EFAULT;
-
- memset(&tmp, 0, sizeof(tmp));
- tmp.type = PORT_CIRRUS;
- tmp.line = port - aurora_port;
- tmp.port = 0;
- tmp.irq = bp->irq;
- tmp.flags = port->flags;
- tmp.baud_base = (bp->oscfreq + CD180_TPC/2) / CD180_TPC;
- tmp.close_delay = port->close_delay * HZ/100;
- tmp.closing_wait = port->closing_wait * HZ/100;
- tmp.xmit_fifo_size = CD180_NFIFO;
- copy_to_user(retinfo, &tmp, sizeof(tmp));
-#ifdef AURORA_DEBUG
-printk("aurora_get_serial_info: end\n");
-#endif
- return 0;
-}
-
-static int aurora_ioctl(struct tty_struct * tty, struct file * filp,
- unsigned int cmd, unsigned long arg)
-
-{
- struct Aurora_port *port = (struct Aurora_port *) tty->driver_data;
- int retval;
-
-#ifdef AURORA_DEBUG
- printk("aurora_ioctl: start\n");
-#endif
- if ((aurora_paranoia_check(port, tty->name, "aurora_ioctl"))
- return -ENODEV;
-
- switch (cmd) {
- case TCSBRK: /* SVID version: non-zero arg --> no break */
- retval = tty_check_change(tty);
- if (retval)
- return retval;
- tty_wait_until_sent(tty, 0);
- if (!arg)
- aurora_send_break(port, HZ/4); /* 1/4 second */
- return 0;
- case TCSBRKP: /* support for POSIX tcsendbreak() */
- retval = tty_check_change(tty);
- if (retval)
- return retval;
- tty_wait_until_sent(tty, 0);
- aurora_send_break(port, arg ? arg*(HZ/10) : HZ/4);
- return 0;
- case TIOCGSOFTCAR:
- return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *)arg);
- case TIOCSSOFTCAR:
- if (get_user(arg,(unsigned long *)arg))
- return -EFAULT;
- tty->termios->c_cflag =
- ((tty->termios->c_cflag & ~CLOCAL) |
- (arg ? CLOCAL : 0));
- return 0;
- case TIOCGSERIAL:
- return aurora_get_serial_info(port, (struct serial_struct *) arg);
- case TIOCSSERIAL:
- return aurora_set_serial_info(port, (struct serial_struct *) arg);
- default:
- return -ENOIOCTLCMD;
- };
-#ifdef AURORA_DEBUG
- printk("aurora_ioctl: end\n");
-#endif
- return 0;
-}
-
-static void aurora_throttle(struct tty_struct * tty)
-{
- struct Aurora_port *port = (struct Aurora_port *) tty->driver_data;
- struct Aurora_board *bp;
- unsigned long flags;
- unsigned char chip;
-
-#ifdef AURORA_DEBUG
- printk("aurora_throttle: start\n");
-#endif
- if ((aurora_paranoia_check(port, tty->name, "aurora_throttle"))
- return;
-
- bp = port_Board(port);
- chip = AURORA_CD180(port_No(port));
-
- save_flags(flags); cli();
- port->MSVR &= ~bp->RTS;
- sbus_writeb(port_No(port) & 7, &bp->r[chip]->r[CD180_CAR]);
- udelay(1);
- if (I_IXOFF(tty)) {
- aurora_wait_CCR(bp->r[chip]);
- sbus_writeb(CCR_SSCH2, &bp->r[chip]->r[CD180_CCR]);
- aurora_wait_CCR(bp->r[chip]);
- }
- sbus_writeb(port->MSVR, &bp->r[chip]->r[CD180_MSVR]);
- restore_flags(flags);
-#ifdef AURORA_DEBUG
- printk("aurora_throttle: end\n");
-#endif
-}
-
-static void aurora_unthrottle(struct tty_struct * tty)
-{
- struct Aurora_port *port = (struct Aurora_port *) tty->driver_data;
- struct Aurora_board *bp;
- unsigned long flags;
- unsigned char chip;
-
-#ifdef AURORA_DEBUG
- printk("aurora_unthrottle: start\n");
-#endif
- if ((aurora_paranoia_check(port, tty->name, "aurora_unthrottle"))
- return;
-
- bp = port_Board(port);
-
- chip = AURORA_CD180(port_No(port));
-
- save_flags(flags); cli();
- port->MSVR |= bp->RTS;
- sbus_writeb(port_No(port) & 7,
- &bp->r[chip]->r[CD180_CAR]);
- udelay(1);
- if (I_IXOFF(tty)) {
- aurora_wait_CCR(bp->r[chip]);
- sbus_writeb(CCR_SSCH1,
- &bp->r[chip]->r[CD180_CCR]);
- aurora_wait_CCR(bp->r[chip]);
- }
- sbus_writeb(port->MSVR, &bp->r[chip]->r[CD180_MSVR]);
- restore_flags(flags);
-#ifdef AURORA_DEBUG
- printk("aurora_unthrottle: end\n");
-#endif
-}
-
-static void aurora_stop(struct tty_struct * tty)
-{
- struct Aurora_port *port = (struct Aurora_port *) tty->driver_data;
- struct Aurora_board *bp;
- unsigned long flags;
- unsigned char chip;
-
-#ifdef AURORA_DEBUG
- printk("aurora_stop: start\n");
-#endif
- if ((aurora_paranoia_check(port, tty->name, "aurora_stop"))
- return;
-
- bp = port_Board(port);
-
- chip = AURORA_CD180(port_No(port));
-
- save_flags(flags); cli();
- port->SRER &= ~SRER_TXRDY;
- sbus_writeb(port_No(port) & 7,
- &bp->r[chip]->r[CD180_CAR]);
- udelay(1);
- sbus_writeb(port->SRER,
- &bp->r[chip]->r[CD180_SRER]);
- restore_flags(flags);
-#ifdef AURORA_DEBUG
- printk("aurora_stop: end\n");
-#endif
-}
-
-static void aurora_start(struct tty_struct * tty)
-{
- struct Aurora_port *port = (struct Aurora_port *) tty->driver_data;
- struct Aurora_board *bp;
- unsigned long flags;
- unsigned char chip;
-
-#ifdef AURORA_DEBUG
- printk("aurora_start: start\n");
-#endif
- if ((aurora_paranoia_check(port, tty->name, "aurora_start"))
- return;
-
- bp = port_Board(port);
-
- chip = AURORA_CD180(port_No(port));
-
- save_flags(flags); cli();
- if (port->xmit_cnt && port->xmit_buf && !(port->SRER & SRER_TXRDY)) {
- port->SRER |= SRER_TXRDY;
- sbus_writeb(port_No(port) & 7,
- &bp->r[chip]->r[CD180_CAR]);
- udelay(1);
- sbus_writeb(port->SRER,
- &bp->r[chip]->r[CD180_SRER]);
- }
- restore_flags(flags);
-#ifdef AURORA_DEBUG
- printk("aurora_start: end\n");
-#endif
-}
-
-/*
- * This routine is called from the scheduler tqueue when the interrupt
- * routine has signalled that a hangup has occurred. The path of
- * hangup processing is:
- *
- * serial interrupt routine -> (scheduler tqueue) ->
- * do_aurora_hangup() -> tty->hangup() -> aurora_hangup()
- *
- */
-static void do_aurora_hangup(void *private_)
-{
- struct Aurora_port *port = (struct Aurora_port *) private_;
- struct tty_struct *tty;
-
-#ifdef AURORA_DEBUG
- printk("do_aurora_hangup: start\n");
-#endif
- tty = port->tty;
- if (tty != NULL) {
- tty_hangup(tty); /* FIXME: module removal race - AKPM */
-#ifdef AURORA_DEBUG
- printk("do_aurora_hangup: end\n");
-#endif
- }
-}
-
-static void aurora_hangup(struct tty_struct * tty)
-{
- struct Aurora_port *port = (struct Aurora_port *) tty->driver_data;
- struct Aurora_board *bp;
-
-#ifdef AURORA_DEBUG
- printk("aurora_hangup: start\n");
-#endif
- if ((aurora_paranoia_check(port, tty->name, "aurora_hangup"))
- return;
-
- bp = port_Board(port);
-
- aurora_shutdown_port(bp, port);
- port->event = 0;
- port->count = 0;
- port->flags &= ~ASYNC_NORMAL_ACTIVE;
- port->tty = 0;
- wake_up_interruptible(&port->open_wait);
-#ifdef AURORA_DEBUG
- printk("aurora_hangup: end\n");
-#endif
-}
-
-static void aurora_set_termios(struct tty_struct * tty, struct termios * old_termios)
-{
- struct Aurora_port *port = (struct Aurora_port *) tty->driver_data;
- unsigned long flags;
-
-#ifdef AURORA_DEBUG
- printk("aurora_set_termios: start\n");
-#endif
- if ((aurora_paranoia_check(port, tty->name, "aurora_set_termios"))
- return;
-
- if (tty->termios->c_cflag == old_termios->c_cflag &&
- tty->termios->c_iflag == old_termios->c_iflag)
- return;
-
- save_flags(flags); cli();
- aurora_change_speed(port_Board(port), port);
- restore_flags(flags);
-
- if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios->c_cflag & CRTSCTS)) {
- tty->hw_stopped = 0;
- aurora_start(tty);
- }
-#ifdef AURORA_DEBUG
- printk("aurora_set_termios: end\n");
-#endif
-}
-
-static void do_aurora_bh(void)
-{
- run_task_queue(&tq_aurora);
-}
-
-static void do_softint(void *private_)
-{
- struct Aurora_port *port = (struct Aurora_port *) private_;
- struct tty_struct *tty;
-
-#ifdef AURORA_DEBUG
- printk("do_softint: start\n");
-#endif
- tty = port->tty;
- if (tty == NULL)
- return;
-
- if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) {
- tty_wakeup(tty);
- }
-#ifdef AURORA_DEBUG
- printk("do_softint: end\n");
-#endif
-}
-
-static const struct tty_operations aurora_ops = {
- .open = aurora_open,
- .close = aurora_close,
- .write = aurora_write,
- .put_char = aurora_put_char,
- .flush_chars = aurora_flush_chars,
- .write_room = aurora_write_room,
- .chars_in_buffer = aurora_chars_in_buffer,
- .flush_buffer = aurora_flush_buffer,
- .ioctl = aurora_ioctl,
- .throttle = aurora_throttle,
- .unthrottle = aurora_unthrottle,
- .set_termios = aurora_set_termios,
- .stop = aurora_stop,
- .start = aurora_start,
- .hangup = aurora_hangup,
- .tiocmget = aurora_tiocmget,
- .tiocmset = aurora_tiocmset,
-};
-
-static int aurora_init_drivers(void)
-{
- int error;
- int i;
-
-#ifdef AURORA_DEBUG
- printk("aurora_init_drivers: start\n");
-#endif
- tmp_buf = (unsigned char *) get_zeroed_page(GFP_KERNEL);
- if (tmp_buf == NULL) {
- printk(KERN_ERR "aurora: Couldn't get free page.\n");
- return 1;
- }
- init_bh(AURORA_BH, do_aurora_bh);
- aurora_driver = alloc_tty_driver(AURORA_INPORTS);
- if (!aurora_driver) {
- printk(KERN_ERR "aurora: Couldn't allocate tty driver.\n");
- free_page((unsigned long) tmp_buf);
- return 1;
- }
- aurora_driver->owner = THIS_MODULE;
- aurora_driver->name = "ttyA";
- aurora_driver->major = AURORA_MAJOR;
- aurora_driver->type = TTY_DRIVER_TYPE_SERIAL;
- aurora_driver->subtype = SERIAL_TYPE_NORMAL;
- aurora_driver->init_termios = tty_std_termios;
- aurora_driver->init_termios.c_cflag =
- B9600 | CS8 | CREAD | HUPCL | CLOCAL;
- aurora_driver->flags = TTY_DRIVER_REAL_RAW;
- tty_set_operations(aurora_driver, &aurora_ops);
- error = tty_register_driver(aurora_driver);
- if (error) {
- put_tty_driver(aurora_driver);
- free_page((unsigned long) tmp_buf);
- printk(KERN_ERR "aurora: Couldn't register aurora driver, error = %d\n",
- error);
- return 1;
- }
-
- memset(aurora_port, 0, sizeof(aurora_port));
- for (i = 0; i < AURORA_TNPORTS; i++) {
- aurora_port[i].magic = AURORA_MAGIC;
- aurora_port[i].tqueue.routine = do_softint;
- aurora_port[i].tqueue.data = &aurora_port[i];
- aurora_port[i].tqueue_hangup.routine = do_aurora_hangup;
- aurora_port[i].tqueue_hangup.data = &aurora_port[i];
- aurora_port[i].close_delay = 50 * HZ/100;
- aurora_port[i].closing_wait = 3000 * HZ/100;
- init_waitqueue_head(&aurora_port[i].open_wait);
- init_waitqueue_head(&aurora_port[i].close_wait);
- }
-#ifdef AURORA_DEBUG
- printk("aurora_init_drivers: end\n");
-#endif
- return 0;
-}
-
-static void aurora_release_drivers(void)
-{
-#ifdef AURORA_DEBUG
- printk("aurora_release_drivers: start\n");
-#endif
- free_page((unsigned long)tmp_buf);
- tty_unregister_driver(aurora_driver);
- put_tty_driver(aurora_driver);
-#ifdef AURORA_DEBUG
- printk("aurora_release_drivers: end\n");
-#endif
-}
-
-/*
- * Called at boot time.
- *
- * You can specify IO base for up to RC_NBOARD cards,
- * using line "riscom8=0xiobase1,0xiobase2,.." at LILO prompt.
- * Note that there will be no probing at default
- * addresses in this case.
- *
- */
-void __init aurora_setup(char *str, int *ints)
-{
- int i;
-
- for(i=0;(i<ints[0])&&(i<4);i++) {
- if (ints[i+1]) irqs[i]=ints[i+1];
- }
-}
-
-static int __init aurora_real_init(void)
-{
- int found;
- int i;
-
- printk(KERN_INFO "aurora: Driver starting.\n");
- if(aurora_init_drivers())
- return -EIO;
- found = aurora_probe();
- if(!found) {
- aurora_release_drivers();
- printk(KERN_INFO "aurora: No Aurora Multiport boards detected.\n");
- return -EIO;
- } else {
- printk(KERN_INFO "aurora: %d boards found.\n", found);
- }
- for (i = 0; i < found; i++) {
- int ret = aurora_setup_board(&aurora_board[i]);
-
- if (ret) {
-#ifdef AURORA_DEBUG
- printk(KERN_ERR "aurora_init: error aurora_setup_board ret %d\n",
- ret);
-#endif
- return ret;
- }
- }
- return 0;
-}
-
-int irq = 0;
-int irq1 = 0;
-int irq2 = 0;
-int irq3 = 0;
-module_param(irq , int, 0);
-module_param(irq1, int, 0);
-module_param(irq2, int, 0);
-module_param(irq3, int, 0);
-
-static int __init aurora_init(void)
-{
- if (irq ) irqs[0]=irq ;
- if (irq1) irqs[1]=irq1;
- if (irq2) irqs[2]=irq2;
- if (irq3) irqs[3]=irq3;
- return aurora_real_init();
-}
-
-static void __exit aurora_cleanup(void)
-{
- int i;
-
-#ifdef AURORA_DEBUG
-printk("cleanup_module: aurora_release_drivers\n");
-#endif
-
- aurora_release_drivers();
- for (i = 0; i < AURORA_NBOARD; i++)
- if (aurora_board[i].flags & AURORA_BOARD_PRESENT) {
- aurora_shutdown_board(&aurora_board[i]);
- aurora_release_io_range(&aurora_board[i]);
- }
-}
-
-module_init(aurora_init);
-module_exit(aurora_cleanup);
-MODULE_LICENSE("GPL");
diff --git a/drivers/sbus/char/aurora.h b/drivers/sbus/char/aurora.h
deleted file mode 100644
index b8b5476d986..00000000000
--- a/drivers/sbus/char/aurora.h
+++ /dev/null
@@ -1,276 +0,0 @@
-/* $Id: aurora.h,v 1.6 2001/06/05 12:23:38 davem Exp $
- * linux/drivers/sbus/char/aurora.h -- Aurora multiport driver
- *
- * Copyright (c) 1999 by Oliver Aldulea (oli@bv.ro)
- *
- * This code is based on the RISCom/8 multiport serial driver written
- * by Dmitry Gorodchanin (pgmdsg@ibi.com), based on the Linux serial
- * driver, written by Linus Torvalds, Theodore T'so and others.
- * The Aurora multiport programming info was obtained mainly from the
- * Cirrus Logic CD180 documentation (available on the web), and by
- * doing heavy tests on the board. Many thanks to Eddie C. Dost for the
- * help on the sbus interface.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under 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.
- *
- * Revision 1.0
- *
- * This is the first public release.
- *
- * This version needs a lot of feedback. This is the version that works
- * with _my_ board. My board is model 1600se, revision '@(#)1600se.fth
- * 1.2 3/28/95 1'. The driver might work with your board, but I do not
- * guarantee it. If you have _any_ type of board, I need to know if the
- * driver works or not, I need to know exactly your board parameters
- * (get them with 'cd /proc/openprom/iommu/sbus/sio16/; ls *; cat *')
- * Also, I need your board revision code, which is written on the board.
- * Send me the output of my driver too (it outputs through klogd).
- *
- * If the driver does not work, you can try enabling the debug options
- * to see what's wrong or what should be done.
- *
- * I'm sorry about the alignment of the code. It was written in a
- * 128x48 environment.
- *
- * I must say that I do not like Aurora Technologies' policy. I asked
- * them to help me do this driver faster, but they ended by something
- * like "don't call us, we'll call you", and I never heard anything
- * from them. They told me "knowing the way the board works, I don't
- * doubt you and others on the net will make the driver."
- * The truth about this board is that it has nothing intelligent on it.
- * If you want to say to somebody what kind of board you have, say that
- * it uses Cirrus Logic processors (CD180). The power of the board is
- * in those two chips. The rest of the board is the interface to the
- * sbus and to the peripherals. Still, they did something smart: they
- * reversed DTR and RTS to make on-board automatic hardware flow
- * control usable.
- * Thanks to Aurora Technologies for wasting my time, nerves and money.
- */
-
-#ifndef __LINUX_AURORA_H
-#define __LINUX_AURORA_H
-
-#include <linux/serial.h>
-#include <linux/serialP.h>
-
-#ifdef __KERNEL__
-
-/* This is the number of boards to support. I've only tested this driver with
- * one board, so it might not work.
- */
-#define AURORA_NBOARD 1
-
-/* Useful ? Yes. But you can safely comment the warnings if they annoy you
- * (let me say that again: the warnings in the code, not this define).
- */
-#define AURORA_PARANOIA_CHECK
-
-/* Well, after many lost nights, I found that the IRQ for this board is
- * selected from four built-in values by writing some bits in the
- * configuration register. This causes a little problem to occur: which
- * IRQ to select ? Which one is the best for the user ? Well, I finally
- * decided for the following algorithm: if the "bintr" value is not acceptable
- * (not within type_1_irq[], then test the "intr" value, if that fails too,
- * try each value from type_1_irq until succeded. Hope it's ok.
- * You can safely reorder the irq's.
- */
-#define TYPE_1_IRQS 4
-unsigned char type_1_irq[TYPE_1_IRQS] = {
- 3, 5, 9, 13
-};
-/* I know something about another method of interrupt setting, but not enough.
- * Also, this is for another type of board, so I first have to learn how to
- * detect it.
-#define TYPE_2_IRQS 3
-unsigned char type_2_irq[TYPE_2_IRQS] = {
- 0, 0, 0 ** could anyone find these for me ? (see AURORA_ALLIRQ below) **
- };
-unsigned char type_2_mask[TYPE_2_IRQS] = {
- 32, 64, 128
- };
-*/
-
-/* The following section should only be modified by those who know what
- * they're doing (or don't, but want to help with some feedback). Modifying
- * anything raises a _big_ probability for your system to hang, but the
- * sacrifice worths. (I sacrificed my ext2fs many, many times...)
- */
-
-/* This one tries to dump to console the name of almost every function called,
- * and many other debugging info.
- */
-#undef AURORA_DEBUG
-
-/* These are the most dangerous and useful defines. They do printk() during
- * the interrupt processing routine(s), so if you manage to get "flooded" by
- * irq's, start thinking about the "Power off/on" button...
- */
-#undef AURORA_INTNORM /* This one enables the "normal" messages, but some
- * of them cause flood, so I preffered putting
- * them under a define */
-#undef AURORA_INT_DEBUG /* This one is really bad. */
-
-/* Here's something helpful: after n irq's, the board will be disabled. This
- * prevents irq flooding during debug (no need to think about power
- * off/on anymore...)
- */
-#define AURORA_FLOODPRO 10
-
-/* This one helps finding which irq the board calls, in case of a strange/
- * unsupported board. AURORA_INT_DEBUG should be enabled, because I don't
- * think /proc/interrupts or any command will be available in case of an irq
- * flood... "allirq" is the list of all free irq's.
- */
-/*
-#define AURORA_ALLIRQ 6
-int allirq[AURORA_ALLIRQ]={
- 2,3,5,7,9,13
- };
-*/
-
-/* These must not be modified. These values are assumed during the code for
- * performance optimisations.
- */
-#define AURORA_NCD180 2 /* two chips per board */
-#define AURORA_NPORT 8 /* 8 ports per chip */
-
-/* several utilities */
-#define AURORA_BOARD(line) (((line) >> 4) & 0x01)
-#define AURORA_CD180(line) (((line) >> 3) & 0x01)
-#define AURORA_PORT(line) ((line) & 15)
-
-#define AURORA_TNPORTS (AURORA_NBOARD*AURORA_NCD180*AURORA_NPORT)
-
-/* Ticks per sec. Used for setting receiver timeout and break length */
-#define AURORA_TPS 4000
-
-#define AURORA_MAGIC 0x0A18
-
-/* Yeah, after heavy testing I decided it must be 6.
- * Sure, You can change it if needed.
- */
-#define AURORA_RXFIFO 6 /* Max. receiver FIFO size (1-8) */
-
-#define AURORA_RXTH 7
-
-struct aurora_reg1 {
- __volatile__ unsigned char r;
-};
-
-struct aurora_reg128 {
- __volatile__ unsigned char r[128];
-};
-
-struct aurora_reg4 {
- __volatile__ unsigned char r[4];
-};
-
-struct Aurora_board {
- unsigned long flags;
- struct aurora_reg1 * r0; /* This is the board configuration
- * register (write-only). */
- struct aurora_reg128 * r[2]; /* These are the registers for the
- * two chips. */
- struct aurora_reg4 * r3; /* These are used for hardware-based
- * acknowledge. Software-based ack is
- * not supported by CD180. */
- unsigned int oscfreq; /* The on-board oscillator
- * frequency, in Hz. */
- unsigned char irq;
-#ifdef MODULE
- signed char count; /* counts the use of the board */
-#endif
- /* Values for the dtr_rts swapped mode. */
- unsigned char DTR;
- unsigned char RTS;
- unsigned char MSVDTR;
- unsigned char MSVRTS;
- /* Values for hardware acknowledge. */
- unsigned char ACK_MINT, ACK_TINT, ACK_RINT;
-};
-
-/* Board configuration register */
-#define AURORA_CFG_ENABLE_IO 8
-#define AURORA_CFG_ENABLE_IRQ 4
-
-/* Board flags */
-#define AURORA_BOARD_PRESENT 0x00000001
-#define AURORA_BOARD_ACTIVE 0x00000002
-#define AURORA_BOARD_TYPE_2 0x00000004 /* don't know how to
- * detect this yet */
-#define AURORA_BOARD_DTR_FLOW_OK 0x00000008
-
-/* The story goes like this: Cirrus programmed the CD-180 chip to do automatic
- * hardware flow control, and do it using CTS and DTR. CTS is ok, but, if you
- * have a modem and the chip drops DTR, then the modem will drop the carrier
- * (ain't that cute...). Luckily, the guys at Aurora decided to swap DTR and
- * RTS, which makes the flow control usable. I hope that all the boards made
- * by Aurora have these two signals swapped. If your's doesn't but you have a
- * breakout box, you can try to reverse them yourself, then set the following
- * flag.
- */
-#undef AURORA_FORCE_DTR_FLOW
-
-/* In fact, a few more words have to be said about hardware flow control.
- * This driver handles "output" flow control through the on-board facility
- * CTS Auto Enable. For the "input" flow control there are two cases when
- * the flow should be controlled. The first case is when the kernel is so
- * busy that it cannot process IRQ's in time; this flow control can only be
- * activated by the on-board chip, and if the board has RTS and DTR swapped,
- * this facility is usable. The second case is when the application is so
- * busy that it cannot receive bytes from the kernel, and this flow must be
- * activated by software. This second case is not yet implemented in this
- * driver. Unfortunately, I estimate that the second case is the one that
- * occurs the most.
- */
-
-
-struct Aurora_port {
- int magic;
- int baud_base;
- int flags;
- struct tty_struct * tty;
- int count;
- int blocked_open;
- long event;
- int timeout;
- int close_delay;
- unsigned char * xmit_buf;
- int custom_divisor;
- int xmit_head;
- int xmit_tail;
- int xmit_cnt;
- wait_queue_head_t open_wait;
- wait_queue_head_t close_wait;
- struct tq_struct tqueue;
- struct tq_struct tqueue_hangup;
- short wakeup_chars;
- short break_length;
- unsigned short closing_wait;
- unsigned char mark_mask;
- unsigned char SRER;
- unsigned char MSVR;
- unsigned char COR2;
-#ifdef AURORA_REPORT_OVERRUN
- unsigned long overrun;
-#endif
-#ifdef AURORA_REPORT_FIFO
- unsigned long hits[10];
-#endif
-};
-
-#endif
-#endif /*__LINUX_AURORA_H*/
-
diff --git a/drivers/sbus/char/bbc_i2c.c b/drivers/sbus/char/bbc_i2c.c
index 22631f8b9b4..8410587348f 100644
--- a/drivers/sbus/char/bbc_i2c.c
+++ b/drivers/sbus/char/bbc_i2c.c
@@ -187,19 +187,20 @@ static int wait_for_pin(struct bbc_i2c_bus *bp, u8 *status)
bp->waiting = 1;
add_wait_queue(&bp->wq, &wait);
while (limit-- > 0) {
- u8 val;
-
- set_current_state(TASK_INTERRUPTIBLE);
- *status = val = readb(bp->i2c_control_regs + 0);
- if ((val & I2C_PCF_PIN) == 0) {
+ unsigned long val;
+
+ val = wait_event_interruptible_timeout(
+ bp->wq,
+ (((*status = readb(bp->i2c_control_regs + 0))
+ & I2C_PCF_PIN) == 0),
+ msecs_to_jiffies(250));
+ if (val > 0) {
ret = 0;
break;
}
- msleep_interruptible(250);
}
remove_wait_queue(&bp->wq, &wait);
bp->waiting = 0;
- current->state = TASK_RUNNING;
return ret;
}
@@ -340,7 +341,7 @@ static irqreturn_t bbc_i2c_interrupt(int irq, void *dev_id)
*/
if (bp->waiting &&
!(readb(bp->i2c_control_regs + 0x0) & I2C_PCF_PIN))
- wake_up(&bp->wq);
+ wake_up_interruptible(&bp->wq);
return IRQ_HANDLED;
}
diff --git a/drivers/sbus/char/bpp.c b/drivers/sbus/char/bpp.c
index ac7d1258efe..a39ee80c971 100644
--- a/drivers/sbus/char/bpp.c
+++ b/drivers/sbus/char/bpp.c
@@ -846,7 +846,7 @@ static int bpp_ioctl(struct inode *inode, struct file *f, unsigned int cmd,
return errno;
}
-static struct file_operations bpp_fops = {
+static const struct file_operations bpp_fops = {
.owner = THIS_MODULE,
.read = bpp_read,
.write = bpp_write,
diff --git a/drivers/sbus/char/cd180.h b/drivers/sbus/char/cd180.h
deleted file mode 100644
index 445b86cc65e..00000000000
--- a/drivers/sbus/char/cd180.h
+++ /dev/null
@@ -1,240 +0,0 @@
-
-/* Definitions for Cirrus Logic CL-CD180 8-port async mux chip */
-#define CD180_NCH 8 /* Total number of channels */
-#define CD180_TPC 16 /* Ticks per character */
-#define CD180_NFIFO 8 /* TX FIFO size */
-
-/* Global registers */
-#define CD180_GFRCR 0x6b /* Global Firmware Revision Code Register */
-#define CD180_SRCR 0x66 /* Service Request Configuration Register */
-#define CD180_PPRH 0x70 /* Prescaler Period Register High */
-#define CD180_PPRL 0x71 /* Prescaler Period Register Low */
-#define CD180_MSMR 0x61 /* Modem Service Match Register */
-#define CD180_TSMR 0x62 /* Transmit Service Match Register */
-#define CD180_RSMR 0x63 /* Receive Service Match Register */
-#define CD180_GSVR 0x40 /* Global Service Vector Register */
-#define CD180_SRSR 0x65 /* Service Request Status Register */
-#define CD180_GSCR 0x41 /* Global Service Channel Register */
-#define CD180_CAR 0x64 /* Channel Access Register */
-
-/* Indexed registers */
-#define CD180_RDCR 0x07 /* Receive Data Count Register */
-#define CD180_RDR 0x78 /* Receiver Data Register */
-#define CD180_RCSR 0x7a /* Receiver Character Status Register */
-#define CD180_TDR 0x7b /* Transmit Data Register */
-#define CD180_EOSRR 0x7f /* End of Service Request Register */
-
-/* Channel Registers */
-#define CD180_SRER 0x02 /* Service Request Enable Register */
-#define CD180_CCR 0x01 /* Channel Command Register */
-#define CD180_COR1 0x03 /* Channel Option Register 1 */
-#define CD180_COR2 0x04 /* Channel Option Register 2 */
-#define CD180_COR3 0x05 /* Channel Option Register 3 */
-#define CD180_CCSR 0x06 /* Channel Control Status Register */
-#define CD180_RTPR 0x18 /* Receive Timeout Period Register */
-#define CD180_RBPRH 0x31 /* Receive Bit Rate Period Register High */
-#define CD180_RBPRL 0x32 /* Receive Bit Rate Period Register Low */
-#define CD180_TBPRH 0x39 /* Transmit Bit Rate Period Register High */
-#define CD180_TBPRL 0x3a /* Transmit Bit Rate Period Register Low */
-#define CD180_SCHR1 0x09 /* Special Character Register 1 */
-#define CD180_SCHR2 0x0a /* Special Character Register 2 */
-#define CD180_SCHR3 0x0b /* Special Character Register 3 */
-#define CD180_SCHR4 0x0c /* Special Character Register 4 */
-#define CD180_MCR 0x12 /* Modem Change Register */
-#define CD180_MCOR1 0x10 /* Modem Change Option 1 Register */
-#define CD180_MCOR2 0x11 /* Modem Change Option 2 Register */
-#define CD180_MSVR 0x28 /* Modem Signal Value Register */
-#define CD180_MSVRTS 0x29 /* Modem Signal Value RTS */
-#define CD180_MSVDTR 0x2a /* Modem Signal Value DTR */
-
-/* Global Interrupt Vector Register (R/W) */
-
-#define GSVR_ITMASK 0x07 /* Interrupt type mask */
-#define GSVR_IT_MDM 0x01 /* Modem Signal Change Interrupt */
-#define GSVR_IT_TX 0x02 /* Transmit Data Interrupt */
-#define GSVR_IT_RGD 0x03 /* Receive Good Data Interrupt */
-#define GSVR_IT_REXC 0x07 /* Receive Exception Interrupt */
-
-
-/* Global Interrupt Channel Register (R/W) */
-
-#define GSCR_CHAN 0x1c /* Channel Number Mask */
-#define GSCR_CHAN_OFF 2 /* Channel Number Offset */
-
-
-/* Channel Address Register (R/W) */
-
-#define CAR_CHAN 0x07 /* Channel Number Mask */
-
-
-/* Receive Character Status Register (R/O) */
-
-#define RCSR_TOUT 0x80 /* Rx Timeout */
-#define RCSR_SCDET 0x70 /* Special Character Detected Mask */
-#define RCSR_NO_SC 0x00 /* No Special Characters Detected */
-#define RCSR_SC_1 0x10 /* Special Char 1 (or 1 & 3) Detected */
-#define RCSR_SC_2 0x20 /* Special Char 2 (or 2 & 4) Detected */
-#define RCSR_SC_3 0x30 /* Special Char 3 Detected */
-#define RCSR_SC_4 0x40 /* Special Char 4 Detected */
-#define RCSR_BREAK 0x08 /* Break has been detected */
-#define RCSR_PE 0x04 /* Parity Error */
-#define RCSR_FE 0x02 /* Frame Error */
-#define RCSR_OE 0x01 /* Overrun Error */
-
-
-/* Channel Command Register (R/W) (commands in groups can be OR-ed) */
-
-#define CCR_HARDRESET 0x81 /* Reset the chip */
-
-#define CCR_SOFTRESET 0x80 /* Soft Channel Reset */
-
-#define CCR_CORCHG1 0x42 /* Channel Option Register 1 Changed */
-#define CCR_CORCHG2 0x44 /* Channel Option Register 2 Changed */
-#define CCR_CORCHG3 0x48 /* Channel Option Register 3 Changed */
-
-#define CCR_SSCH1 0x21 /* Send Special Character 1 */
-
-#define CCR_SSCH2 0x22 /* Send Special Character 2 */
-
-#define CCR_SSCH3 0x23 /* Send Special Character 3 */
-
-#define CCR_SSCH4 0x24 /* Send Special Character 4 */
-
-#define CCR_TXEN 0x18 /* Enable Transmitter */
-#define CCR_RXEN 0x12 /* Enable Receiver */
-
-#define CCR_TXDIS 0x14 /* Disable Transmitter */
-#define CCR_RXDIS 0x11 /* Disable Receiver */
-
-
-/* Service Request Enable Register (R/W) */
-
-#define SRER_DSR 0x80 /* Enable interrupt on DSR change */
-#define SRER_CD 0x40 /* Enable interrupt on CD change */
-#define SRER_CTS 0x20 /* Enable interrupt on CTS change */
-#define SRER_RXD 0x10 /* Enable interrupt on Receive Data */
-#define SRER_RXSC 0x08 /* Enable interrupt on Receive Spec. Char */
-#define SRER_TXRDY 0x04 /* Enable interrupt on TX FIFO empty */
-#define SRER_TXEMPTY 0x02 /* Enable interrupt on TX completely empty */
-#define SRER_RET 0x01 /* Enable interrupt on RX Exc. Timeout */
-
-
-/* Channel Option Register 1 (R/W) */
-
-#define COR1_ODDP 0x80 /* Odd Parity */
-#define COR1_PARMODE 0x60 /* Parity Mode mask */
-#define COR1_NOPAR 0x00 /* No Parity */
-#define COR1_FORCEPAR 0x20 /* Force Parity */
-#define COR1_NORMPAR 0x40 /* Normal Parity */
-#define COR1_IGNORE 0x10 /* Ignore Parity on RX */
-#define COR1_STOPBITS 0x0c /* Number of Stop Bits */
-#define COR1_1SB 0x00 /* 1 Stop Bit */
-#define COR1_15SB 0x04 /* 1.5 Stop Bits */
-#define COR1_2SB 0x08 /* 2 Stop Bits */
-#define COR1_CHARLEN 0x03 /* Character Length */
-#define COR1_5BITS 0x00 /* 5 bits */
-#define COR1_6BITS 0x01 /* 6 bits */
-#define COR1_7BITS 0x02 /* 7 bits */
-#define COR1_8BITS 0x03 /* 8 bits */
-
-
-/* Channel Option Register 2 (R/W) */
-
-#define COR2_IXM 0x80 /* Implied XON mode */
-#define COR2_TXIBE 0x40 /* Enable In-Band (XON/XOFF) Flow Control */
-#define COR2_ETC 0x20 /* Embedded Tx Commands Enable */
-#define COR2_LLM 0x10 /* Local Loopback Mode */
-#define COR2_RLM 0x08 /* Remote Loopback Mode */
-#define COR2_RTSAO 0x04 /* RTS Automatic Output Enable */
-#define COR2_CTSAE 0x02 /* CTS Automatic Enable */
-#define COR2_DSRAE 0x01 /* DSR Automatic Enable */
-
-
-/* Channel Option Register 3 (R/W) */
-
-#define COR3_XONCH 0x80 /* XON is a pair of characters (1 & 3) */
-#define COR3_XOFFCH 0x40 /* XOFF is a pair of characters (2 & 4) */
-#define COR3_FCT 0x20 /* Flow-Control Transparency Mode */
-#define COR3_SCDE 0x10 /* Special Character Detection Enable */
-#define COR3_RXTH 0x0f /* RX FIFO Threshold value (1-8) */
-
-
-/* Channel Control Status Register (R/O) */
-
-#define CCSR_RXEN 0x80 /* Receiver Enabled */
-#define CCSR_RXFLOFF 0x40 /* Receive Flow Off (XOFF was sent) */
-#define CCSR_RXFLON 0x20 /* Receive Flow On (XON was sent) */
-#define CCSR_TXEN 0x08 /* Transmitter Enabled */
-#define CCSR_TXFLOFF 0x04 /* Transmit Flow Off (got XOFF) */
-#define CCSR_TXFLON 0x02 /* Transmit Flow On (got XON) */
-
-
-/* Modem Change Option Register 1 (R/W) */
-
-#define MCOR1_DSRZD 0x80 /* Detect 0->1 transition of DSR */
-#define MCOR1_CDZD 0x40 /* Detect 0->1 transition of CD */
-#define MCOR1_CTSZD 0x20 /* Detect 0->1 transition of CTS */
-#define MCOR1_DTRTH 0x0f /* Auto DTR flow control Threshold (1-8) */
-#define MCOR1_NODTRFC 0x0 /* Automatic DTR flow control disabled */
-
-
-/* Modem Change Option Register 2 (R/W) */
-
-#define MCOR2_DSROD 0x80 /* Detect 1->0 transition of DSR */
-#define MCOR2_CDOD 0x40 /* Detect 1->0 transition of CD */
-#define MCOR2_CTSOD 0x20 /* Detect 1->0 transition of CTS */
-
-
-/* Modem Change Register (R/W) */
-
-#define MCR_DSRCHG 0x80 /* DSR Changed */
-#define MCR_CDCHG 0x40 /* CD Changed */
-#define MCR_CTSCHG 0x20 /* CTS Changed */
-
-
-/* Modem Signal Value Register (R/W) */
-
-#define MSVR_DSR 0x80 /* Current state of DSR input */
-#define MSVR_CD 0x40 /* Current state of CD input */
-#define MSVR_CTS 0x20 /* Current state of CTS input */
-#define MSVR_DTR 0x02 /* Current state of DTR output */
-#define MSVR_RTS 0x01 /* Current state of RTS output */
-
-
-/* Service Request Status Register */
-
-#define SRSR_CMASK 0xC0 /* Current Service Context Mask */
-#define SRSR_CNONE 0x00 /* Not in a service context */
-#define SRSR_CRX 0x40 /* Rx Context */
-#define SRSR_CTX 0x80 /* Tx Context */
-#define SRSR_CMDM 0xC0 /* Modem Context */
-#define SRSR_ANYINT 0x6F /* Any interrupt flag */
-#define SRSR_RINT 0x10 /* Receive Interrupt */
-#define SRSR_TINT 0x04 /* Transmit Interrupt */
-#define SRSR_MINT 0x01 /* Modem Interrupt */
-#define SRSR_REXT 0x20 /* Receive External Interrupt */
-#define SRSR_TEXT 0x08 /* Transmit External Interrupt */
-#define SRSR_MEXT 0x02 /* Modem External Interrupt */
-
-
-/* Service Request Configuration Register */
-
-#define SRCR_PKGTYPE 0x80
-#define SRCR_REGACKEN 0x40
-#define SRCR_DAISYEN 0x20
-#define SRCR_GLOBPRI 0x10
-#define SRCR_UNFAIR 0x08
-#define SRCR_AUTOPRI 0x02
-#define SRCR_PRISEL 0x01
-
-/* Values for register-based Interrupt ACKs */
-#define CD180_ACK_MINT 0x75 /* goes to MSMR */
-#define CD180_ACK_TINT 0x76 /* goes to TSMR */
-#define CD180_ACK_RINT 0x77 /* goes to RSMR */
-
-/* Escape characters */
-
-#define CD180_C_ESC 0x00 /* Escape character */
-#define CD180_C_SBRK 0x81 /* Start sending BREAK */
-#define CD180_C_DELAY 0x82 /* Delay output */
-#define CD180_C_EBRK 0x83 /* Stop sending BREAK */
diff --git a/drivers/sbus/char/cpwatchdog.c b/drivers/sbus/char/cpwatchdog.c
index ad1c7db96cb..022e869c44d 100644
--- a/drivers/sbus/char/cpwatchdog.c
+++ b/drivers/sbus/char/cpwatchdog.c
@@ -20,7 +20,6 @@
#include <linux/major.h>
#include <linux/init.h>
#include <linux/miscdevice.h>
-#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/timer.h>
@@ -459,7 +458,7 @@ static irqreturn_t wd_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static struct file_operations wd_fops = {
+static const struct file_operations wd_fops = {
.owner = THIS_MODULE,
.ioctl = wd_ioctl,
.compat_ioctl = wd_compat_ioctl,
diff --git a/drivers/sbus/char/display7seg.c b/drivers/sbus/char/display7seg.c
index a4909e0c7f8..2d14a29effe 100644
--- a/drivers/sbus/char/display7seg.c
+++ b/drivers/sbus/char/display7seg.c
@@ -166,7 +166,7 @@ static long d7s_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
return error;
}
-static struct file_operations d7s_fops = {
+static const struct file_operations d7s_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = d7s_ioctl,
.compat_ioctl = d7s_ioctl,
diff --git a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c
index fff4660cdf9..2cea4f5d208 100644
--- a/drivers/sbus/char/envctrl.c
+++ b/drivers/sbus/char/envctrl.c
@@ -705,7 +705,7 @@ envctrl_release(struct inode *inode, struct file *file)
return 0;
}
-static struct file_operations envctrl_fops = {
+static const struct file_operations envctrl_fops = {
.owner = THIS_MODULE,
.read = envctrl_read,
.unlocked_ioctl = envctrl_ioctl,
diff --git a/drivers/sbus/char/flash.c b/drivers/sbus/char/flash.c
index fa2418f7ad3..6e99507aeb1 100644
--- a/drivers/sbus/char/flash.c
+++ b/drivers/sbus/char/flash.c
@@ -142,7 +142,7 @@ flash_release(struct inode *inode, struct file *file)
return 0;
}
-static struct file_operations flash_fops = {
+static const struct file_operations flash_fops = {
/* no write to the Flash, use mmap
* and play flash dependent tricks.
*/
diff --git a/drivers/sbus/char/jsflash.c b/drivers/sbus/char/jsflash.c
index 14631ac11bc..512857a2316 100644
--- a/drivers/sbus/char/jsflash.c
+++ b/drivers/sbus/char/jsflash.c
@@ -431,7 +431,7 @@ static int jsf_release(struct inode *inode, struct file *file)
return 0;
}
-static struct file_operations jsf_fops = {
+static const struct file_operations jsf_fops = {
.owner = THIS_MODULE,
.llseek = jsf_lseek,
.read = jsf_read,
diff --git a/drivers/sbus/char/openprom.c b/drivers/sbus/char/openprom.c
index 4e2a0e2dcc2..eec28c142a5 100644
--- a/drivers/sbus/char/openprom.c
+++ b/drivers/sbus/char/openprom.c
@@ -31,7 +31,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/string.h>
@@ -704,7 +703,7 @@ static int openprom_release(struct inode * inode, struct file * file)
return 0;
}
-static struct file_operations openprom_fops = {
+static const struct file_operations openprom_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.ioctl = openprom_ioctl,
diff --git a/drivers/sbus/char/riowatchdog.c b/drivers/sbus/char/riowatchdog.c
index 2a9cc820442..a2fc6b8c133 100644
--- a/drivers/sbus/char/riowatchdog.c
+++ b/drivers/sbus/char/riowatchdog.c
@@ -193,7 +193,7 @@ static ssize_t riowd_write(struct file *file, const char __user *buf, size_t cou
return 0;
}
-static struct file_operations riowd_fops = {
+static const struct file_operations riowd_fops = {
.owner = THIS_MODULE,
.ioctl = riowd_ioctl,
.open = riowd_open,
diff --git a/drivers/sbus/char/rtc.c b/drivers/sbus/char/rtc.c
index 9b988baf0b5..94d18582911 100644
--- a/drivers/sbus/char/rtc.c
+++ b/drivers/sbus/char/rtc.c
@@ -233,7 +233,7 @@ static int rtc_release(struct inode *inode, struct file *file)
return 0;
}
-static struct file_operations rtc_fops = {
+static const struct file_operations rtc_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.ioctl = rtc_ioctl,
diff --git a/drivers/sbus/char/uctrl.c b/drivers/sbus/char/uctrl.c
index b30372f17f1..44d2ef906ac 100644
--- a/drivers/sbus/char/uctrl.c
+++ b/drivers/sbus/char/uctrl.c
@@ -5,7 +5,6 @@
*/
#include <linux/module.h>
-#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
@@ -224,7 +223,7 @@ static irqreturn_t uctrl_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static struct file_operations uctrl_fops = {
+static const struct file_operations uctrl_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.ioctl = uctrl_ioctl,
@@ -365,6 +364,7 @@ static int __init ts102_uctrl_init(void)
struct linux_prom_irqs tmp_irq[2];
unsigned int vaddr[2] = { 0, 0 };
int tmpnode, uctrlnode = prom_getchild(prom_root_node);
+ int err;
tmpnode = prom_searchsiblings(uctrlnode, "obio");
@@ -390,7 +390,12 @@ static int __init ts102_uctrl_init(void)
if(!driver->irq)
driver->irq = tmp_irq[0].pri;
- request_irq(driver->irq, uctrl_interrupt, 0, "uctrl", driver);
+ err = request_irq(driver->irq, uctrl_interrupt, 0, "uctrl", driver);
+ if (err) {
+ printk("%s: unable to register irq %d\n",
+ __FUNCTION__, driver->irq);
+ return err;
+ }
if (misc_register(&uctrl_dev)) {
printk("%s: unable to get misc minor %d\n",
diff --git a/drivers/sbus/char/vfc_dev.c b/drivers/sbus/char/vfc_dev.c
index 386e7de0b7e..8bfb67ccdcd 100644
--- a/drivers/sbus/char/vfc_dev.c
+++ b/drivers/sbus/char/vfc_dev.c
@@ -19,7 +19,6 @@
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/errno.h>
-#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/smp_lock.h>
#include <linux/delay.h>
@@ -44,7 +43,7 @@
#include "vfc.h"
#include <asm/vfc_ioctls.h>
-static struct file_operations vfc_fops;
+static const struct file_operations vfc_fops;
struct vfc_dev **vfc_dev_lst;
static char vfcstr[]="vfc";
static unsigned char saa9051_init_array[VFC_SAA9051_NR] = {
@@ -633,7 +632,7 @@ static int vfc_mmap(struct file *file, struct vm_area_struct *vma)
}
-static struct file_operations vfc_fops = {
+static const struct file_operations vfc_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.ioctl = vfc_ioctl,
diff --git a/drivers/sbus/char/vfc_i2c.c b/drivers/sbus/char/vfc_i2c.c
index ceec30648f4..9efed771f6c 100644
--- a/drivers/sbus/char/vfc_i2c.c
+++ b/drivers/sbus/char/vfc_i2c.c
@@ -14,7 +14,7 @@
/* NOTE: It seems to me that the documentation regarding the
pcd8584t/pcf8584 does not show the correct way to address the i2c bus.
Based on the information on the I2C bus itself and the remainder of
-the Phillips docs the following algorithims apper to be correct. I am
+the Phillips docs the following algorithms appear to be correct. I am
fairly certain that the flowcharts in the phillips docs are wrong. */
diff --git a/drivers/sbus/sbus.c b/drivers/sbus/sbus.c
index 98fcbb3d556..6349dd617f8 100644
--- a/drivers/sbus/sbus.c
+++ b/drivers/sbus/sbus.c
@@ -7,6 +7,7 @@
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/pci.h>
+#include <linux/device.h>
#include <asm/system.h>
#include <asm/sbus.h>
@@ -17,13 +18,25 @@
#include <asm/bpp.h>
#include <asm/irq.h>
+static ssize_t
+show_sbusobppath_attr(struct device * dev, struct device_attribute * attr, char * buf)
+{
+ struct sbus_dev *sbus;
+
+ sbus = to_sbus_device(dev);
+
+ return snprintf (buf, PAGE_SIZE, "%s\n", sbus->ofdev.node->full_name);
+}
+
+static DEVICE_ATTR(obppath, S_IRUSR | S_IRGRP | S_IROTH, show_sbusobppath_attr, NULL);
+
struct sbus_bus *sbus_root;
static void __init fill_sbus_device(struct device_node *dp, struct sbus_dev *sdev)
{
unsigned long base;
void *pval;
- int len;
+ int len, err;
sdev->prom_node = dp->node;
strcpy(sdev->prom_name, dp->name);
@@ -66,6 +79,9 @@ static void __init fill_sbus_device(struct device_node *dp, struct sbus_dev *sde
if (of_device_register(&sdev->ofdev) != 0)
printk(KERN_DEBUG "sbus: device registration error for %s!\n",
dp->path_component_name);
+
+ /* WE HAVE BEEN INVADED BY ALIENS! */
+ err = sysfs_create_file(&sdev->ofdev.dev.kobj, &dev_attr_obppath.attr);
}
static void __init sbus_bus_ranges_init(struct device_node *dp, struct sbus_bus *sbus)
diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c
index b091a0fc4eb..eb766c3af1c 100644
--- a/drivers/scsi/3w-9xxx.c
+++ b/drivers/scsi/3w-9xxx.c
@@ -197,7 +197,7 @@ static struct class_device_attribute *twa_host_attrs[] = {
};
/* File operations struct for character device */
-static struct file_operations twa_fops = {
+static const struct file_operations twa_fops = {
.owner = THIS_MODULE,
.ioctl = twa_chrdev_ioctl,
.open = twa_chrdev_open,
diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c
index e1b44d6c0c3..bf5d63e1bee 100644
--- a/drivers/scsi/3w-xxxx.c
+++ b/drivers/scsi/3w-xxxx.c
@@ -1040,7 +1040,7 @@ static int tw_chrdev_open(struct inode *inode, struct file *file)
} /* End tw_chrdev_open() */
/* File operations struct for character device */
-static struct file_operations tw_fops = {
+static const struct file_operations tw_fops = {
.owner = THIS_MODULE,
.ioctl = tw_chrdev_ioctl,
.open = tw_chrdev_open,
diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c
index 68103e508db..cb02656eb54 100644
--- a/drivers/scsi/53c700.c
+++ b/drivers/scsi/53c700.c
@@ -121,7 +121,6 @@
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/completion.h>
-#include <linux/sched.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/blkdev.h>
@@ -667,12 +666,30 @@ NCR_700_chip_setup(struct Scsi_Host *host)
__u8 min_xferp = (hostdata->chip710 ? NCR_710_MIN_XFERP : NCR_700_MIN_XFERP);
if(hostdata->chip710) {
- __u8 burst_disable = hostdata->burst_disable
- ? BURST_DISABLE : 0;
+ __u8 burst_disable = 0;
+ __u8 burst_length = 0;
+
+ switch (hostdata->burst_length) {
+ case 1:
+ burst_length = BURST_LENGTH_1;
+ break;
+ case 2:
+ burst_length = BURST_LENGTH_2;
+ break;
+ case 4:
+ burst_length = BURST_LENGTH_4;
+ break;
+ case 8:
+ burst_length = BURST_LENGTH_8;
+ break;
+ default:
+ burst_disable = BURST_DISABLE;
+ break;
+ }
dcntl_extra = COMPAT_700_MODE;
NCR_700_writeb(dcntl_extra, host, DCNTL_REG);
- NCR_700_writeb(BURST_LENGTH_8 | hostdata->dmode_extra,
+ NCR_700_writeb(burst_length | hostdata->dmode_extra,
host, DMODE_710_REG);
NCR_700_writeb(burst_disable | (hostdata->differential ?
DIFF : 0), host, CTEST7_REG);
diff --git a/drivers/scsi/53c700.h b/drivers/scsi/53c700.h
index f38822db421..841e1bb27d5 100644
--- a/drivers/scsi/53c700.h
+++ b/drivers/scsi/53c700.h
@@ -203,7 +203,7 @@ struct NCR_700_Host_Parameters {
__u32 force_le_on_be:1;
#endif
__u32 chip710:1; /* set if really a 710 not 700 */
- __u32 burst_disable:1; /* set to 1 to disable 710 bursting */
+ __u32 burst_length:4; /* set to 0 to disable 710 bursting */
/* NOTHING BELOW HERE NEEDS ALTERING */
__u32 fast:1; /* if we can alter the SCSI bus clock
diff --git a/drivers/scsi/53c7xx.c b/drivers/scsi/53c7xx.c
index 640536ef77d..93b41f45638 100644
--- a/drivers/scsi/53c7xx.c
+++ b/drivers/scsi/53c7xx.c
@@ -3099,7 +3099,6 @@ allocate_cmd (Scsi_Cmnd *cmd) {
real = get_zeroed_page(GFP_ATOMIC);
if (real == 0)
return NULL;
- memset((void *)real, 0, 4096);
cache_push(virt_to_phys((void *)real), 4096);
cache_clear(virt_to_phys((void *)real), 4096);
kernel_set_cachemode((void *)real, 4096, IOMAP_NOCACHE_SER);
@@ -4400,7 +4399,7 @@ abort_connected (struct Scsi_Host *host) {
* account the current synchronous offset)
*/
- sstat = (NCR53c8x0_read8 (SSTAT2_REG);
+ sstat = NCR53c8x0_read8 (SSTAT2_REG);
offset = OFFSET (sstat & SSTAT2_FF_MASK) >> SSTAT2_FF_SHIFT;
phase = sstat & SSTAT2_PHASE_MASK;
@@ -5423,7 +5422,7 @@ insn_to_offset (Scsi_Cmnd *cmd, u32 *insn) {
--buffers, offset += segment->length, ++segment)
#if 0
printk("scsi%d: comparing 0x%p to 0x%p\n",
- cmd->device->host->host_no, saved, page_address(segment->page+segment->offset);
+ cmd->device->host->host_no, saved, page_address(segment->page+segment->offset));
#else
;
#endif
diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c
index 3075204915c..e874b894487 100644
--- a/drivers/scsi/BusLogic.c
+++ b/drivers/scsi/BusLogic.c
@@ -192,7 +192,7 @@ static void BusLogic_InitializeCCBs(struct BusLogic_HostAdapter *HostAdapter, vo
BusLogic_CreateInitialCCBs allocates the initial CCBs for Host Adapter.
*/
-static boolean __init BusLogic_CreateInitialCCBs(struct BusLogic_HostAdapter *HostAdapter)
+static bool __init BusLogic_CreateInitialCCBs(struct BusLogic_HostAdapter *HostAdapter)
{
int BlockSize = BusLogic_CCB_AllocationGroupSize * sizeof(struct BusLogic_CCB);
void *BlockPointer;
@@ -238,7 +238,7 @@ static void BusLogic_DestroyCCBs(struct BusLogic_HostAdapter *HostAdapter)
multiple host adapters share the same IRQ Channel.
*/
-static void BusLogic_CreateAdditionalCCBs(struct BusLogic_HostAdapter *HostAdapter, int AdditionalCCBs, boolean SuccessMessageP)
+static void BusLogic_CreateAdditionalCCBs(struct BusLogic_HostAdapter *HostAdapter, int AdditionalCCBs, bool SuccessMessageP)
{
int BlockSize = BusLogic_CCB_AllocationGroupSize * sizeof(struct BusLogic_CCB);
int PreviouslyAllocated = HostAdapter->AllocatedCCBs;
@@ -362,10 +362,8 @@ static int BusLogic_Command(struct BusLogic_HostAdapter *HostAdapter, enum BusLo
interrupt could occur if the IRQ Channel was previously enabled by another
BusLogic Host Adapter or another driver sharing the same IRQ Channel.
*/
- if (!HostAdapter->IRQ_ChannelAcquired) {
+ if (!HostAdapter->IRQ_ChannelAcquired)
local_irq_save(ProcessorFlags);
- local_irq_disable();
- }
/*
Wait for the Host Adapter Ready bit to be set and the Command/Parameter
Register Busy bit to be reset in the Status Register.
@@ -639,9 +637,9 @@ static int __init BusLogic_InitializeMultiMasterProbeInfo(struct BusLogic_HostAd
struct BusLogic_ProbeInfo *PrimaryProbeInfo = &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount];
int NonPrimaryPCIMultiMasterIndex = BusLogic_ProbeInfoCount + 1;
int NonPrimaryPCIMultiMasterCount = 0, PCIMultiMasterCount = 0;
- boolean ForceBusDeviceScanningOrder = false;
- boolean ForceBusDeviceScanningOrderChecked = false;
- boolean StandardAddressSeen[6];
+ bool ForceBusDeviceScanningOrder = false;
+ bool ForceBusDeviceScanningOrderChecked = false;
+ bool StandardAddressSeen[6];
struct pci_dev *PCI_Device = NULL;
int i;
if (BusLogic_ProbeInfoCount >= BusLogic_MaxHostAdapters)
@@ -1011,7 +1009,7 @@ static void __init BusLogic_InitializeProbeInfoList(struct BusLogic_HostAdapter
BusLogic_Failure prints a standardized error message, and then returns false.
*/
-static boolean BusLogic_Failure(struct BusLogic_HostAdapter *HostAdapter, char *ErrorMessage)
+static bool BusLogic_Failure(struct BusLogic_HostAdapter *HostAdapter, char *ErrorMessage)
{
BusLogic_AnnounceDriver(HostAdapter);
if (HostAdapter->HostAdapterBusType == BusLogic_PCI_Bus) {
@@ -1030,7 +1028,7 @@ static boolean BusLogic_Failure(struct BusLogic_HostAdapter *HostAdapter, char *
BusLogic_ProbeHostAdapter probes for a BusLogic Host Adapter.
*/
-static boolean __init BusLogic_ProbeHostAdapter(struct BusLogic_HostAdapter *HostAdapter)
+static bool __init BusLogic_ProbeHostAdapter(struct BusLogic_HostAdapter *HostAdapter)
{
union BusLogic_StatusRegister StatusRegister;
union BusLogic_InterruptRegister InterruptRegister;
@@ -1101,8 +1099,8 @@ static boolean __init BusLogic_ProbeHostAdapter(struct BusLogic_HostAdapter *Hos
SCSI Bus Reset.
*/
-static boolean BusLogic_HardwareResetHostAdapter(struct BusLogic_HostAdapter
- *HostAdapter, boolean HardReset)
+static bool BusLogic_HardwareResetHostAdapter(struct BusLogic_HostAdapter
+ *HostAdapter, bool HardReset)
{
union BusLogic_StatusRegister StatusRegister;
int TimeoutCounter;
@@ -1205,11 +1203,11 @@ static boolean BusLogic_HardwareResetHostAdapter(struct BusLogic_HostAdapter
Host Adapter.
*/
-static boolean __init BusLogic_CheckHostAdapter(struct BusLogic_HostAdapter *HostAdapter)
+static bool __init BusLogic_CheckHostAdapter(struct BusLogic_HostAdapter *HostAdapter)
{
struct BusLogic_ExtendedSetupInformation ExtendedSetupInformation;
unsigned char RequestedReplyLength;
- boolean Result = true;
+ bool Result = true;
/*
FlashPoint Host Adapters do not require this protection.
*/
@@ -1239,7 +1237,7 @@ static boolean __init BusLogic_CheckHostAdapter(struct BusLogic_HostAdapter *Hos
from Host Adapter and initializes the Host Adapter structure.
*/
-static boolean __init BusLogic_ReadHostAdapterConfiguration(struct BusLogic_HostAdapter
+static bool __init BusLogic_ReadHostAdapterConfiguration(struct BusLogic_HostAdapter
*HostAdapter)
{
struct BusLogic_BoardID BoardID;
@@ -1686,14 +1684,14 @@ static boolean __init BusLogic_ReadHostAdapterConfiguration(struct BusLogic_Host
Host Adapter.
*/
-static boolean __init BusLogic_ReportHostAdapterConfiguration(struct BusLogic_HostAdapter
+static bool __init BusLogic_ReportHostAdapterConfiguration(struct BusLogic_HostAdapter
*HostAdapter)
{
unsigned short AllTargetsMask = (1 << HostAdapter->MaxTargetDevices) - 1;
unsigned short SynchronousPermitted, FastPermitted;
unsigned short UltraPermitted, WidePermitted;
unsigned short DisconnectPermitted, TaggedQueuingPermitted;
- boolean CommonSynchronousNegotiation, CommonTaggedQueueDepth;
+ bool CommonSynchronousNegotiation, CommonTaggedQueueDepth;
char SynchronousString[BusLogic_MaxTargetDevices + 1];
char WideString[BusLogic_MaxTargetDevices + 1];
char DisconnectString[BusLogic_MaxTargetDevices + 1];
@@ -1835,7 +1833,7 @@ static boolean __init BusLogic_ReportHostAdapterConfiguration(struct BusLogic_Ho
Host Adapter.
*/
-static boolean __init BusLogic_AcquireResources(struct BusLogic_HostAdapter *HostAdapter)
+static bool __init BusLogic_AcquireResources(struct BusLogic_HostAdapter *HostAdapter)
{
if (HostAdapter->IRQ_Channel == 0) {
BusLogic_Error("NO LEGAL INTERRUPT CHANNEL ASSIGNED - DETACHING\n", HostAdapter);
@@ -1903,7 +1901,7 @@ static void BusLogic_ReleaseResources(struct BusLogic_HostAdapter *HostAdapter)
of the Host Adapter from its initial power on or hard reset state.
*/
-static boolean BusLogic_InitializeHostAdapter(struct BusLogic_HostAdapter
+static bool BusLogic_InitializeHostAdapter(struct BusLogic_HostAdapter
*HostAdapter)
{
struct BusLogic_ExtendedMailboxRequest ExtendedMailboxRequest;
@@ -2002,7 +2000,7 @@ static boolean BusLogic_InitializeHostAdapter(struct BusLogic_HostAdapter
through Host Adapter.
*/
-static boolean __init BusLogic_TargetDeviceInquiry(struct BusLogic_HostAdapter
+static bool __init BusLogic_TargetDeviceInquiry(struct BusLogic_HostAdapter
*HostAdapter)
{
u16 InstalledDevices;
@@ -2739,7 +2737,7 @@ static irqreturn_t BusLogic_InterruptHandler(int IRQ_Channel, void *DeviceIdenti
already have been acquired by the caller.
*/
-static boolean BusLogic_WriteOutgoingMailbox(struct BusLogic_HostAdapter
+static bool BusLogic_WriteOutgoingMailbox(struct BusLogic_HostAdapter
*HostAdapter, enum BusLogic_ActionCode ActionCode, struct BusLogic_CCB *CCB)
{
struct BusLogic_OutgoingMailbox *NextOutgoingMailbox;
@@ -3058,7 +3056,7 @@ static int BusLogic_AbortCommand(struct scsi_cmnd *Command)
currently executing SCSI Commands as having been Reset.
*/
-static int BusLogic_ResetHostAdapter(struct BusLogic_HostAdapter *HostAdapter, boolean HardReset)
+static int BusLogic_ResetHostAdapter(struct BusLogic_HostAdapter *HostAdapter, bool HardReset)
{
struct BusLogic_CCB *CCB;
int TargetID;
@@ -3309,7 +3307,7 @@ Target Requested Completed Requested Completed Requested Completed\n\
static void BusLogic_Message(enum BusLogic_MessageLevel MessageLevel, char *Format, struct BusLogic_HostAdapter *HostAdapter, ...)
{
static char Buffer[BusLogic_LineBufferSize];
- static boolean BeginningOfLine = true;
+ static bool BeginningOfLine = true;
va_list Arguments;
int Length = 0;
va_start(Arguments, HostAdapter);
@@ -3347,7 +3345,7 @@ static void BusLogic_Message(enum BusLogic_MessageLevel MessageLevel, char *Form
and updates the pointer if the keyword is recognized and false otherwise.
*/
-static boolean __init BusLogic_ParseKeyword(char **StringPointer, char *Keyword)
+static bool __init BusLogic_ParseKeyword(char **StringPointer, char *Keyword)
{
char *Pointer = *StringPointer;
while (*Keyword != '\0') {
diff --git a/drivers/scsi/BusLogic.h b/drivers/scsi/BusLogic.h
index cca6d45eee4..bfbfb5c3a8f 100644
--- a/drivers/scsi/BusLogic.h
+++ b/drivers/scsi/BusLogic.h
@@ -234,12 +234,6 @@ enum BusLogic_BIOS_DiskGeometryTranslation {
/*
- Define a Boolean data type.
-*/
-
-typedef bool boolean;
-
-/*
Define a 10^18 Statistics Byte Counter data type.
*/
@@ -269,19 +263,19 @@ struct BusLogic_ProbeInfo {
*/
struct BusLogic_ProbeOptions {
- boolean NoProbe:1; /* Bit 0 */
- boolean NoProbeISA:1; /* Bit 1 */
- boolean NoProbePCI:1; /* Bit 2 */
- boolean NoSortPCI:1; /* Bit 3 */
- boolean MultiMasterFirst:1; /* Bit 4 */
- boolean FlashPointFirst:1; /* Bit 5 */
- boolean LimitedProbeISA:1; /* Bit 6 */
- boolean Probe330:1; /* Bit 7 */
- boolean Probe334:1; /* Bit 8 */
- boolean Probe230:1; /* Bit 9 */
- boolean Probe234:1; /* Bit 10 */
- boolean Probe130:1; /* Bit 11 */
- boolean Probe134:1; /* Bit 12 */
+ bool NoProbe:1; /* Bit 0 */
+ bool NoProbeISA:1; /* Bit 1 */
+ bool NoProbePCI:1; /* Bit 2 */
+ bool NoSortPCI:1; /* Bit 3 */
+ bool MultiMasterFirst:1;/* Bit 4 */
+ bool FlashPointFirst:1; /* Bit 5 */
+ bool LimitedProbeISA:1; /* Bit 6 */
+ bool Probe330:1; /* Bit 7 */
+ bool Probe334:1; /* Bit 8 */
+ bool Probe230:1; /* Bit 9 */
+ bool Probe234:1; /* Bit 10 */
+ bool Probe130:1; /* Bit 11 */
+ bool Probe134:1; /* Bit 12 */
};
/*
@@ -289,10 +283,10 @@ struct BusLogic_ProbeOptions {
*/
struct BusLogic_GlobalOptions {
- boolean TraceProbe:1; /* Bit 0 */
- boolean TraceHardwareReset:1; /* Bit 1 */
- boolean TraceConfiguration:1; /* Bit 2 */
- boolean TraceErrors:1; /* Bit 3 */
+ bool TraceProbe:1; /* Bit 0 */
+ bool TraceHardwareReset:1; /* Bit 1 */
+ bool TraceConfiguration:1; /* Bit 2 */
+ bool TraceErrors:1; /* Bit 3 */
};
/*
@@ -300,7 +294,7 @@ struct BusLogic_GlobalOptions {
*/
struct BusLogic_LocalOptions {
- boolean InhibitTargetInquiry:1; /* Bit 0 */
+ bool InhibitTargetInquiry:1; /* Bit 0 */
};
/*
@@ -322,10 +316,10 @@ union BusLogic_ControlRegister {
unsigned char All;
struct {
unsigned char:4; /* Bits 0-3 */
- boolean SCSIBusReset:1; /* Bit 4 */
- boolean InterruptReset:1; /* Bit 5 */
- boolean SoftReset:1; /* Bit 6 */
- boolean HardReset:1; /* Bit 7 */
+ bool SCSIBusReset:1; /* Bit 4 */
+ bool InterruptReset:1; /* Bit 5 */
+ bool SoftReset:1; /* Bit 6 */
+ bool HardReset:1; /* Bit 7 */
} cr;
};
@@ -336,14 +330,14 @@ union BusLogic_ControlRegister {
union BusLogic_StatusRegister {
unsigned char All;
struct {
- boolean CommandInvalid:1; /* Bit 0 */
- boolean Reserved:1; /* Bit 1 */
- boolean DataInRegisterReady:1; /* Bit 2 */
- boolean CommandParameterRegisterBusy:1; /* Bit 3 */
- boolean HostAdapterReady:1; /* Bit 4 */
- boolean InitializationRequired:1; /* Bit 5 */
- boolean DiagnosticFailure:1; /* Bit 6 */
- boolean DiagnosticActive:1; /* Bit 7 */
+ bool CommandInvalid:1; /* Bit 0 */
+ bool Reserved:1; /* Bit 1 */
+ bool DataInRegisterReady:1; /* Bit 2 */
+ bool CommandParameterRegisterBusy:1; /* Bit 3 */
+ bool HostAdapterReady:1; /* Bit 4 */
+ bool InitializationRequired:1; /* Bit 5 */
+ bool DiagnosticFailure:1; /* Bit 6 */
+ bool DiagnosticActive:1; /* Bit 7 */
} sr;
};
@@ -354,12 +348,12 @@ union BusLogic_StatusRegister {
union BusLogic_InterruptRegister {
unsigned char All;
struct {
- boolean IncomingMailboxLoaded:1; /* Bit 0 */
- boolean OutgoingMailboxAvailable:1; /* Bit 1 */
- boolean CommandComplete:1; /* Bit 2 */
- boolean ExternalBusReset:1; /* Bit 3 */
+ bool IncomingMailboxLoaded:1; /* Bit 0 */
+ bool OutgoingMailboxAvailable:1;/* Bit 1 */
+ bool CommandComplete:1; /* Bit 2 */
+ bool ExternalBusReset:1; /* Bit 3 */
unsigned char Reserved:3; /* Bits 4-6 */
- boolean InterruptValid:1; /* Bit 7 */
+ bool InterruptValid:1; /* Bit 7 */
} ir;
};
@@ -373,7 +367,7 @@ union BusLogic_GeometryRegister {
enum BusLogic_BIOS_DiskGeometryTranslation Drive0Geometry:2; /* Bits 0-1 */
enum BusLogic_BIOS_DiskGeometryTranslation Drive1Geometry:2; /* Bits 2-3 */
unsigned char:3; /* Bits 4-6 */
- boolean ExtendedTranslationEnabled:1; /* Bit 7 */
+ bool ExtendedTranslationEnabled:1; /* Bit 7 */
} gr;
};
@@ -445,16 +439,16 @@ struct BusLogic_BoardID {
struct BusLogic_Configuration {
unsigned char:5; /* Byte 0 Bits 0-4 */
- boolean DMA_Channel5:1; /* Byte 0 Bit 5 */
- boolean DMA_Channel6:1; /* Byte 0 Bit 6 */
- boolean DMA_Channel7:1; /* Byte 0 Bit 7 */
- boolean IRQ_Channel9:1; /* Byte 1 Bit 0 */
- boolean IRQ_Channel10:1; /* Byte 1 Bit 1 */
- boolean IRQ_Channel11:1; /* Byte 1 Bit 2 */
- boolean IRQ_Channel12:1; /* Byte 1 Bit 3 */
+ bool DMA_Channel5:1; /* Byte 0 Bit 5 */
+ bool DMA_Channel6:1; /* Byte 0 Bit 6 */
+ bool DMA_Channel7:1; /* Byte 0 Bit 7 */
+ bool IRQ_Channel9:1; /* Byte 1 Bit 0 */
+ bool IRQ_Channel10:1; /* Byte 1 Bit 1 */
+ bool IRQ_Channel11:1; /* Byte 1 Bit 2 */
+ bool IRQ_Channel12:1; /* Byte 1 Bit 3 */
unsigned char:1; /* Byte 1 Bit 4 */
- boolean IRQ_Channel14:1; /* Byte 1 Bit 5 */
- boolean IRQ_Channel15:1; /* Byte 1 Bit 6 */
+ bool IRQ_Channel14:1; /* Byte 1 Bit 5 */
+ bool IRQ_Channel15:1; /* Byte 1 Bit 6 */
unsigned char:1; /* Byte 1 Bit 7 */
unsigned char HostAdapterID:4; /* Byte 2 Bits 0-3 */
unsigned char:4; /* Byte 2 Bits 4-7 */
@@ -467,12 +461,12 @@ struct BusLogic_Configuration {
struct BusLogic_SynchronousValue {
unsigned char Offset:4; /* Bits 0-3 */
unsigned char TransferPeriod:3; /* Bits 4-6 */
- boolean Synchronous:1; /* Bit 7 */
+ bool Synchronous:1; /* Bit 7 */
};
struct BusLogic_SetupInformation {
- boolean SynchronousInitiationEnabled:1; /* Byte 0 Bit 0 */
- boolean ParityCheckingEnabled:1; /* Byte 0 Bit 1 */
+ bool SynchronousInitiationEnabled:1; /* Byte 0 Bit 0 */
+ bool ParityCheckingEnabled:1; /* Byte 0 Bit 1 */
unsigned char:6; /* Byte 0 Bits 2-7 */
unsigned char BusTransferRate; /* Byte 1 */
unsigned char PreemptTimeOnBus; /* Byte 2 */
@@ -523,13 +517,13 @@ enum BusLogic_ISACompatibleIOPort {
struct BusLogic_PCIHostAdapterInformation {
enum BusLogic_ISACompatibleIOPort ISACompatibleIOPort; /* Byte 0 */
unsigned char PCIAssignedIRQChannel; /* Byte 1 */
- boolean LowByteTerminated:1; /* Byte 2 Bit 0 */
- boolean HighByteTerminated:1; /* Byte 2 Bit 1 */
+ bool LowByteTerminated:1; /* Byte 2 Bit 0 */
+ bool HighByteTerminated:1; /* Byte 2 Bit 1 */
unsigned char:2; /* Byte 2 Bits 2-3 */
- boolean JP1:1; /* Byte 2 Bit 4 */
- boolean JP2:1; /* Byte 2 Bit 5 */
- boolean JP3:1; /* Byte 2 Bit 6 */
- boolean GenericInfoValid:1; /* Byte 2 Bit 7 */
+ bool JP1:1; /* Byte 2 Bit 4 */
+ bool JP2:1; /* Byte 2 Bit 5 */
+ bool JP3:1; /* Byte 2 Bit 6 */
+ bool GenericInfoValid:1;/* Byte 2 Bit 7 */
unsigned char:8; /* Byte 3 */
};
@@ -545,17 +539,17 @@ struct BusLogic_ExtendedSetupInformation {
u32 BaseMailboxAddress; /* Bytes 5-8 */
struct {
unsigned char:2; /* Byte 9 Bits 0-1 */
- boolean FastOnEISA:1; /* Byte 9 Bit 2 */
+ bool FastOnEISA:1; /* Byte 9 Bit 2 */
unsigned char:3; /* Byte 9 Bits 3-5 */
- boolean LevelSensitiveInterrupt:1; /* Byte 9 Bit 6 */
+ bool LevelSensitiveInterrupt:1; /* Byte 9 Bit 6 */
unsigned char:1; /* Byte 9 Bit 7 */
} Misc;
unsigned char FirmwareRevision[3]; /* Bytes 10-12 */
- boolean HostWideSCSI:1; /* Byte 13 Bit 0 */
- boolean HostDifferentialSCSI:1; /* Byte 13 Bit 1 */
- boolean HostSupportsSCAM:1; /* Byte 13 Bit 2 */
- boolean HostUltraSCSI:1; /* Byte 13 Bit 3 */
- boolean HostSmartTermination:1; /* Byte 13 Bit 4 */
+ bool HostWideSCSI:1; /* Byte 13 Bit 0 */
+ bool HostDifferentialSCSI:1; /* Byte 13 Bit 1 */
+ bool HostSupportsSCAM:1; /* Byte 13 Bit 2 */
+ bool HostUltraSCSI:1; /* Byte 13 Bit 3 */
+ bool HostSmartTermination:1; /* Byte 13 Bit 4 */
unsigned char:3; /* Byte 13 Bits 5-7 */
} PACKED;
@@ -590,35 +584,35 @@ struct BusLogic_AutoSCSIData {
unsigned char InformationByteCount; /* Byte 2 */
unsigned char HostAdapterType[6]; /* Bytes 3-8 */
unsigned char:8; /* Byte 9 */
- boolean FloppyEnabled:1; /* Byte 10 Bit 0 */
- boolean FloppySecondary:1; /* Byte 10 Bit 1 */
- boolean LevelSensitiveInterrupt:1; /* Byte 10 Bit 2 */
+ bool FloppyEnabled:1; /* Byte 10 Bit 0 */
+ bool FloppySecondary:1; /* Byte 10 Bit 1 */
+ bool LevelSensitiveInterrupt:1; /* Byte 10 Bit 2 */
unsigned char:2; /* Byte 10 Bits 3-4 */
unsigned char SystemRAMAreaForBIOS:3; /* Byte 10 Bits 5-7 */
unsigned char DMA_Channel:7; /* Byte 11 Bits 0-6 */
- boolean DMA_AutoConfiguration:1; /* Byte 11 Bit 7 */
+ bool DMA_AutoConfiguration:1; /* Byte 11 Bit 7 */
unsigned char IRQ_Channel:7; /* Byte 12 Bits 0-6 */
- boolean IRQ_AutoConfiguration:1; /* Byte 12 Bit 7 */
+ bool IRQ_AutoConfiguration:1; /* Byte 12 Bit 7 */
unsigned char DMA_TransferRate; /* Byte 13 */
unsigned char SCSI_ID; /* Byte 14 */
- boolean LowByteTerminated:1; /* Byte 15 Bit 0 */
- boolean ParityCheckingEnabled:1; /* Byte 15 Bit 1 */
- boolean HighByteTerminated:1; /* Byte 15 Bit 2 */
- boolean NoisyCablingEnvironment:1; /* Byte 15 Bit 3 */
- boolean FastSynchronousNegotiation:1; /* Byte 15 Bit 4 */
- boolean BusResetEnabled:1; /* Byte 15 Bit 5 */
- boolean:1; /* Byte 15 Bit 6 */
- boolean ActiveNegationEnabled:1; /* Byte 15 Bit 7 */
+ bool LowByteTerminated:1; /* Byte 15 Bit 0 */
+ bool ParityCheckingEnabled:1; /* Byte 15 Bit 1 */
+ bool HighByteTerminated:1; /* Byte 15 Bit 2 */
+ bool NoisyCablingEnvironment:1; /* Byte 15 Bit 3 */
+ bool FastSynchronousNegotiation:1; /* Byte 15 Bit 4 */
+ bool BusResetEnabled:1; /* Byte 15 Bit 5 */
+ bool:1; /* Byte 15 Bit 6 */
+ bool ActiveNegationEnabled:1; /* Byte 15 Bit 7 */
unsigned char BusOnDelay; /* Byte 16 */
unsigned char BusOffDelay; /* Byte 17 */
- boolean HostAdapterBIOSEnabled:1; /* Byte 18 Bit 0 */
- boolean BIOSRedirectionOfINT19Enabled:1; /* Byte 18 Bit 1 */
- boolean ExtendedTranslationEnabled:1; /* Byte 18 Bit 2 */
- boolean MapRemovableAsFixedEnabled:1; /* Byte 18 Bit 3 */
- boolean:1; /* Byte 18 Bit 4 */
- boolean BIOSSupportsMoreThan2DrivesEnabled:1; /* Byte 18 Bit 5 */
- boolean BIOSInterruptModeEnabled:1; /* Byte 18 Bit 6 */
- boolean FlopticalSupportEnabled:1; /* Byte 19 Bit 7 */
+ bool HostAdapterBIOSEnabled:1; /* Byte 18 Bit 0 */
+ bool BIOSRedirectionOfINT19Enabled:1; /* Byte 18 Bit 1 */
+ bool ExtendedTranslationEnabled:1; /* Byte 18 Bit 2 */
+ bool MapRemovableAsFixedEnabled:1; /* Byte 18 Bit 3 */
+ bool:1; /* Byte 18 Bit 4 */
+ bool BIOSSupportsMoreThan2DrivesEnabled:1; /* Byte 18 Bit 5 */
+ bool BIOSInterruptModeEnabled:1; /* Byte 18 Bit 6 */
+ bool FlopticalSupportEnabled:1; /* Byte 19 Bit 7 */
unsigned short DeviceEnabled; /* Bytes 19-20 */
unsigned short WidePermitted; /* Bytes 21-22 */
unsigned short FastPermitted; /* Bytes 23-24 */
@@ -628,22 +622,22 @@ struct BusLogic_AutoSCSIData {
unsigned short IgnoreInBIOSScan; /* Bytes 31-32 */
unsigned char PCIInterruptPin:2; /* Byte 33 Bits 0-1 */
unsigned char HostAdapterIOPortAddress:2; /* Byte 33 Bits 2-3 */
- boolean StrictRoundRobinModeEnabled:1; /* Byte 33 Bit 4 */
- boolean VESABusSpeedGreaterThan33MHz:1; /* Byte 33 Bit 5 */
- boolean VESABurstWriteEnabled:1; /* Byte 33 Bit 6 */
- boolean VESABurstReadEnabled:1; /* Byte 33 Bit 7 */
+ bool StrictRoundRobinModeEnabled:1; /* Byte 33 Bit 4 */
+ bool VESABusSpeedGreaterThan33MHz:1; /* Byte 33 Bit 5 */
+ bool VESABurstWriteEnabled:1; /* Byte 33 Bit 6 */
+ bool VESABurstReadEnabled:1; /* Byte 33 Bit 7 */
unsigned short UltraPermitted; /* Bytes 34-35 */
unsigned int:32; /* Bytes 36-39 */
unsigned char:8; /* Byte 40 */
unsigned char AutoSCSIMaximumLUN; /* Byte 41 */
- boolean:1; /* Byte 42 Bit 0 */
- boolean SCAM_Dominant:1; /* Byte 42 Bit 1 */
- boolean SCAM_Enabled:1; /* Byte 42 Bit 2 */
- boolean SCAM_Level2:1; /* Byte 42 Bit 3 */
+ bool:1; /* Byte 42 Bit 0 */
+ bool SCAM_Dominant:1; /* Byte 42 Bit 1 */
+ bool SCAM_Enabled:1; /* Byte 42 Bit 2 */
+ bool SCAM_Level2:1; /* Byte 42 Bit 3 */
unsigned char:4; /* Byte 42 Bits 4-7 */
- boolean INT13ExtensionEnabled:1; /* Byte 43 Bit 0 */
- boolean:1; /* Byte 43 Bit 1 */
- boolean CDROMBootEnabled:1; /* Byte 43 Bit 2 */
+ bool INT13ExtensionEnabled:1; /* Byte 43 Bit 0 */
+ bool:1; /* Byte 43 Bit 1 */
+ bool CDROMBootEnabled:1; /* Byte 43 Bit 2 */
unsigned char:5; /* Byte 43 Bits 3-7 */
unsigned char BootTargetID:4; /* Byte 44 Bits 0-3 */
unsigned char BootChannel:4; /* Byte 44 Bits 4-7 */
@@ -852,7 +846,7 @@ struct BusLogic_CCB {
enum BusLogic_CCB_Opcode Opcode; /* Byte 0 */
unsigned char:3; /* Byte 1 Bits 0-2 */
enum BusLogic_DataDirection DataDirection:2; /* Byte 1 Bits 3-4 */
- boolean TagEnable:1; /* Byte 1 Bit 5 */
+ bool TagEnable:1; /* Byte 1 Bit 5 */
enum BusLogic_QueueTag QueueTag:2; /* Byte 1 Bits 6-7 */
unsigned char CDB_Length; /* Byte 2 */
unsigned char SenseDataLength; /* Byte 3 */
@@ -864,7 +858,7 @@ struct BusLogic_CCB {
enum BusLogic_TargetDeviceStatus TargetDeviceStatus; /* Byte 15 */
unsigned char TargetID; /* Byte 16 */
unsigned char LogicalUnit:5; /* Byte 17 Bits 0-4 */
- boolean LegacyTagEnable:1; /* Byte 17 Bit 5 */
+ bool LegacyTagEnable:1; /* Byte 17 Bit 5 */
enum BusLogic_QueueTag LegacyQueueTag:2; /* Byte 17 Bits 6-7 */
SCSI_CDB_T CDB; /* Bytes 18-29 */
unsigned char:8; /* Byte 30 */
@@ -939,13 +933,13 @@ struct BusLogic_DriverOptions {
*/
struct BusLogic_TargetFlags {
- boolean TargetExists:1;
- boolean TaggedQueuingSupported:1;
- boolean WideTransfersSupported:1;
- boolean TaggedQueuingActive:1;
- boolean WideTransfersActive:1;
- boolean CommandSuccessfulFlag:1;
- boolean TargetInfoReported:1;
+ bool TargetExists:1;
+ bool TaggedQueuingSupported:1;
+ bool WideTransfersSupported:1;
+ bool TaggedQueuingActive:1;
+ bool WideTransfersActive:1;
+ bool CommandSuccessfulFlag:1;
+ bool TargetInfoReported:1;
};
/*
@@ -992,7 +986,7 @@ typedef unsigned int FlashPoint_CardHandle_T;
struct FlashPoint_Info {
u32 BaseAddress; /* Bytes 0-3 */
- boolean Present; /* Byte 4 */
+ bool Present; /* Byte 4 */
unsigned char IRQ_Channel; /* Byte 5 */
unsigned char SCSI_ID; /* Byte 6 */
unsigned char SCSI_LUN; /* Byte 7 */
@@ -1002,15 +996,15 @@ struct FlashPoint_Info {
unsigned short UltraPermitted; /* Bytes 14-15 */
unsigned short DisconnectPermitted; /* Bytes 16-17 */
unsigned short WidePermitted; /* Bytes 18-19 */
- boolean ParityCheckingEnabled:1; /* Byte 20 Bit 0 */
- boolean HostWideSCSI:1; /* Byte 20 Bit 1 */
- boolean HostSoftReset:1; /* Byte 20 Bit 2 */
- boolean ExtendedTranslationEnabled:1; /* Byte 20 Bit 3 */
- boolean LowByteTerminated:1; /* Byte 20 Bit 4 */
- boolean HighByteTerminated:1; /* Byte 20 Bit 5 */
- boolean ReportDataUnderrun:1; /* Byte 20 Bit 6 */
- boolean SCAM_Enabled:1; /* Byte 20 Bit 7 */
- boolean SCAM_Level2:1; /* Byte 21 Bit 0 */
+ bool ParityCheckingEnabled:1; /* Byte 20 Bit 0 */
+ bool HostWideSCSI:1; /* Byte 20 Bit 1 */
+ bool HostSoftReset:1; /* Byte 20 Bit 2 */
+ bool ExtendedTranslationEnabled:1; /* Byte 20 Bit 3 */
+ bool LowByteTerminated:1; /* Byte 20 Bit 4 */
+ bool HighByteTerminated:1; /* Byte 20 Bit 5 */
+ bool ReportDataUnderrun:1; /* Byte 20 Bit 6 */
+ bool SCAM_Enabled:1; /* Byte 20 Bit 7 */
+ bool SCAM_Level2:1; /* Byte 21 Bit 0 */
unsigned char:7; /* Byte 21 Bits 1-7 */
unsigned char Family; /* Byte 22 */
unsigned char BusType; /* Byte 23 */
@@ -1044,29 +1038,29 @@ struct BusLogic_HostAdapter {
unsigned char IRQ_Channel;
unsigned char DMA_Channel;
unsigned char SCSI_ID;
- boolean IRQ_ChannelAcquired:1;
- boolean DMA_ChannelAcquired:1;
- boolean ExtendedTranslationEnabled:1;
- boolean ParityCheckingEnabled:1;
- boolean BusResetEnabled:1;
- boolean LevelSensitiveInterrupt:1;
- boolean HostWideSCSI:1;
- boolean HostDifferentialSCSI:1;
- boolean HostSupportsSCAM:1;
- boolean HostUltraSCSI:1;
- boolean ExtendedLUNSupport:1;
- boolean TerminationInfoValid:1;
- boolean LowByteTerminated:1;
- boolean HighByteTerminated:1;
- boolean BounceBuffersRequired:1;
- boolean StrictRoundRobinModeSupport:1;
- boolean SCAM_Enabled:1;
- boolean SCAM_Level2:1;
- boolean HostAdapterInitialized:1;
- boolean HostAdapterExternalReset:1;
- boolean HostAdapterInternalError:1;
- boolean ProcessCompletedCCBsActive;
- volatile boolean HostAdapterCommandCompleted;
+ bool IRQ_ChannelAcquired:1;
+ bool DMA_ChannelAcquired:1;
+ bool ExtendedTranslationEnabled:1;
+ bool ParityCheckingEnabled:1;
+ bool BusResetEnabled:1;
+ bool LevelSensitiveInterrupt:1;
+ bool HostWideSCSI:1;
+ bool HostDifferentialSCSI:1;
+ bool HostSupportsSCAM:1;
+ bool HostUltraSCSI:1;
+ bool ExtendedLUNSupport:1;
+ bool TerminationInfoValid:1;
+ bool LowByteTerminated:1;
+ bool HighByteTerminated:1;
+ bool BounceBuffersRequired:1;
+ bool StrictRoundRobinModeSupport:1;
+ bool SCAM_Enabled:1;
+ bool SCAM_Level2:1;
+ bool HostAdapterInitialized:1;
+ bool HostAdapterExternalReset:1;
+ bool HostAdapterInternalError:1;
+ bool ProcessCompletedCCBsActive;
+ volatile bool HostAdapterCommandCompleted;
unsigned short HostAdapterScatterGatherLimit;
unsigned short DriverScatterGatherLimit;
unsigned short MaxTargetDevices;
@@ -1141,25 +1135,25 @@ struct SCSI_Inquiry {
unsigned char PeripheralDeviceType:5; /* Byte 0 Bits 0-4 */
unsigned char PeripheralQualifier:3; /* Byte 0 Bits 5-7 */
unsigned char DeviceTypeModifier:7; /* Byte 1 Bits 0-6 */
- boolean RMB:1; /* Byte 1 Bit 7 */
+ bool RMB:1; /* Byte 1 Bit 7 */
unsigned char ANSI_ApprovedVersion:3; /* Byte 2 Bits 0-2 */
unsigned char ECMA_Version:3; /* Byte 2 Bits 3-5 */
unsigned char ISO_Version:2; /* Byte 2 Bits 6-7 */
unsigned char ResponseDataFormat:4; /* Byte 3 Bits 0-3 */
unsigned char:2; /* Byte 3 Bits 4-5 */
- boolean TrmIOP:1; /* Byte 3 Bit 6 */
- boolean AENC:1; /* Byte 3 Bit 7 */
+ bool TrmIOP:1; /* Byte 3 Bit 6 */
+ bool AENC:1; /* Byte 3 Bit 7 */
unsigned char AdditionalLength; /* Byte 4 */
unsigned char:8; /* Byte 5 */
unsigned char:8; /* Byte 6 */
- boolean SftRe:1; /* Byte 7 Bit 0 */
- boolean CmdQue:1; /* Byte 7 Bit 1 */
- boolean:1; /* Byte 7 Bit 2 */
- boolean Linked:1; /* Byte 7 Bit 3 */
- boolean Sync:1; /* Byte 7 Bit 4 */
- boolean WBus16:1; /* Byte 7 Bit 5 */
- boolean WBus32:1; /* Byte 7 Bit 6 */
- boolean RelAdr:1; /* Byte 7 Bit 7 */
+ bool SftRe:1; /* Byte 7 Bit 0 */
+ bool CmdQue:1; /* Byte 7 Bit 1 */
+ bool:1; /* Byte 7 Bit 2 */
+ bool Linked:1; /* Byte 7 Bit 3 */
+ bool Sync:1; /* Byte 7 Bit 4 */
+ bool WBus16:1; /* Byte 7 Bit 5 */
+ bool WBus32:1; /* Byte 7 Bit 6 */
+ bool RelAdr:1; /* Byte 7 Bit 7 */
unsigned char VendorIdentification[8]; /* Bytes 8-15 */
unsigned char ProductIdentification[16]; /* Bytes 16-31 */
unsigned char ProductRevisionLevel[4]; /* Bytes 32-35 */
@@ -1348,7 +1342,7 @@ static int BusLogic_ProcDirectoryInfo(struct Scsi_Host *, char *, char **, off_t
static int BusLogic_SlaveConfigure(struct scsi_device *);
static void BusLogic_QueueCompletedCCB(struct BusLogic_CCB *);
static irqreturn_t BusLogic_InterruptHandler(int, void *);
-static int BusLogic_ResetHostAdapter(struct BusLogic_HostAdapter *, boolean HardReset);
+static int BusLogic_ResetHostAdapter(struct BusLogic_HostAdapter *, bool HardReset);
static void BusLogic_Message(enum BusLogic_MessageLevel, char *, struct BusLogic_HostAdapter *, ...);
static int __init BusLogic_Setup(char *);
diff --git a/drivers/scsi/FlashPoint.c b/drivers/scsi/FlashPoint.c
index 7c006804958..a7f916c0c9c 100644
--- a/drivers/scsi/FlashPoint.c
+++ b/drivers/scsi/FlashPoint.c
@@ -7609,7 +7609,7 @@ FlashPoint__AbortCCB(FlashPoint_CardHandle_T CardHandle,
FlashPoint_AbortCCB(CardHandle, (struct sccb *)CCB);
}
-static inline boolean
+static inline bool
FlashPoint__InterruptPending(FlashPoint_CardHandle_T CardHandle)
{
return FlashPoint_InterruptPending(CardHandle);
@@ -7640,7 +7640,7 @@ extern FlashPoint_CardHandle_T
FlashPoint_HardwareResetHostAdapter(struct FlashPoint_Info *);
extern void FlashPoint_StartCCB(FlashPoint_CardHandle_T, struct BusLogic_CCB *);
extern int FlashPoint_AbortCCB(FlashPoint_CardHandle_T, struct BusLogic_CCB *);
-extern boolean FlashPoint_InterruptPending(FlashPoint_CardHandle_T);
+extern bool FlashPoint_InterruptPending(FlashPoint_CardHandle_T);
extern int FlashPoint_HandleInterrupt(FlashPoint_CardHandle_T);
extern void FlashPoint_ReleaseHostAdapter(FlashPoint_CardHandle_T);
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 7869c34a4a3..4cd280e8696 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -230,6 +230,7 @@ config SCSI_SCAN_ASYNC
The SCSI subsystem can probe for devices while the rest of the
system continues booting, and even probe devices on different
busses in parallel, leading to a significant speed-up.
+
If you have built SCSI as modules, enabling this option can
be a problem as the devices may not have been found by the
time your system expects them to have been. You can load the
@@ -237,8 +238,8 @@ config SCSI_SCAN_ASYNC
If you build your SCSI drivers into the kernel, then everything
will work fine if you say Y here.
- You can override this choice by specifying scsi_mod.scan="sync"
- or "async" on the kernel's command line.
+ You can override this choice by specifying "scsi_mod.scan=sync"
+ or async on the kernel's command line.
menu "SCSI Transports"
depends on SCSI
@@ -973,6 +974,15 @@ config SCSI_LASI700
many PA-RISC workstations & servers. If you do not know whether you
have a Lasi chip, it is safe to say "Y" here.
+config SCSI_SNI_53C710
+ tristate "SNI RM SCSI support for 53c710"
+ depends on SNI_RM && SCSI
+ select SCSI_SPI_ATTRS
+ select 53C700_LE_ON_BE
+ help
+ This is a driver for the onboard SCSI controller found in older
+ SNI RM workstations & servers.
+
config 53C700_LE_ON_BE
bool
depends on SCSI_LASI700
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index bd7c9888f7f..79ecf4ebe6e 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -124,6 +124,7 @@ obj-$(CONFIG_JAZZ_ESP) += NCR53C9x.o jazz_esp.o
obj-$(CONFIG_SUN3X_ESP) += NCR53C9x.o sun3x_esp.o
obj-$(CONFIG_SCSI_FCAL) += fcal.o
obj-$(CONFIG_SCSI_LASI700) += 53c700.o lasi700.o
+obj-$(CONFIG_SCSI_SNI_53C710) += 53c700.o sni_53c710.o
obj-$(CONFIG_SCSI_NSP32) += nsp32.o
obj-$(CONFIG_SCSI_IPR) += ipr.o
obj-$(CONFIG_SCSI_SRP) += libsrp.o
diff --git a/drivers/scsi/NCR53C9x.c b/drivers/scsi/NCR53C9x.c
index 3c912ee29da..8b5334c56f0 100644
--- a/drivers/scsi/NCR53C9x.c
+++ b/drivers/scsi/NCR53C9x.c
@@ -528,12 +528,16 @@ void esp_bootup_reset(struct NCR_ESP *esp, struct ESP_regs *eregs)
/* Allocate structure and insert basic data such as SCSI chip frequency
* data and a pointer to the device
*/
-struct NCR_ESP* esp_allocate(struct scsi_host_template *tpnt, void *esp_dev)
+struct NCR_ESP* esp_allocate(struct scsi_host_template *tpnt, void *esp_dev,
+ int hotplug)
{
struct NCR_ESP *esp, *elink;
struct Scsi_Host *esp_host;
- esp_host = scsi_register(tpnt, sizeof(struct NCR_ESP));
+ if (hotplug)
+ esp_host = scsi_host_alloc(tpnt, sizeof(struct NCR_ESP));
+ else
+ esp_host = scsi_register(tpnt, sizeof(struct NCR_ESP));
if(!esp_host)
panic("Cannot register ESP SCSI host");
esp = (struct NCR_ESP *) esp_host->hostdata;
diff --git a/drivers/scsi/NCR53C9x.h b/drivers/scsi/NCR53C9x.h
index 521e3f842cf..d85cb73a9f6 100644
--- a/drivers/scsi/NCR53C9x.h
+++ b/drivers/scsi/NCR53C9x.h
@@ -652,7 +652,7 @@ extern int nesps, esps_in_use, esps_running;
/* External functions */
extern void esp_bootup_reset(struct NCR_ESP *esp, struct ESP_regs *eregs);
-extern struct NCR_ESP *esp_allocate(struct scsi_host_template *, void *);
+extern struct NCR_ESP *esp_allocate(struct scsi_host_template *, void *, int);
extern void esp_deallocate(struct NCR_ESP *);
extern void esp_release(void);
extern void esp_initialize(struct NCR_ESP *);
diff --git a/drivers/scsi/NCR53c406a.c b/drivers/scsi/NCR53c406a.c
index 8578555d58f..7c0b17f8690 100644
--- a/drivers/scsi/NCR53c406a.c
+++ b/drivers/scsi/NCR53c406a.c
@@ -41,7 +41,6 @@
#include <linux/errno.h>
#include <linux/ioport.h>
-#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
diff --git a/drivers/scsi/NCR_D700.c b/drivers/scsi/NCR_D700.c
index 9859cd17fc5..f12864abed2 100644
--- a/drivers/scsi/NCR_D700.c
+++ b/drivers/scsi/NCR_D700.c
@@ -200,6 +200,7 @@ NCR_D700_probe_one(struct NCR_D700_private *p, int siop, int irq,
hostdata->base = ioport_map(region, 64);
hostdata->differential = (((1<<siop) & differential) != 0);
hostdata->clock = NCR_D700_CLOCK_MHZ;
+ hostdata->burst_length = 8;
/* and register the siop */
host = NCR_700_detect(&NCR_D700_driver_template, hostdata, p->dev);
diff --git a/drivers/scsi/a100u2w.c b/drivers/scsi/a100u2w.c
index 2650a5d0a16..7f4241bfb9c 100644
--- a/drivers/scsi/a100u2w.c
+++ b/drivers/scsi/a100u2w.c
@@ -1067,7 +1067,7 @@ static int __devinit inia100_probe_one(struct pci_dev *pdev,
goto out_disable_device;
}
- /* <02> read from base address + 0x50 offset to get the bios balue. */
+ /* <02> read from base address + 0x50 offset to get the bios value. */
bios = ORC_RDWORD(port, 0x50);
diff --git a/drivers/scsi/a2091.c b/drivers/scsi/a2091.c
index f77016d31ca..b7c5385e2ef 100644
--- a/drivers/scsi/a2091.c
+++ b/drivers/scsi/a2091.c
@@ -1,7 +1,6 @@
#include <linux/types.h>
#include <linux/mm.h>
#include <linux/blkdev.h>
-#include <linux/sched.h>
#include <linux/init.h>
#include <linux/interrupt.h>
diff --git a/drivers/scsi/a3000.c b/drivers/scsi/a3000.c
index 1299bc8edef..796f1c4d772 100644
--- a/drivers/scsi/a3000.c
+++ b/drivers/scsi/a3000.c
@@ -1,7 +1,6 @@
#include <linux/types.h>
#include <linux/mm.h>
#include <linux/blkdev.h>
-#include <linux/sched.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/spinlock.h>
diff --git a/drivers/scsi/aacraid/Makefile b/drivers/scsi/aacraid/Makefile
index 28d133a3094..f1cca4ee541 100644
--- a/drivers/scsi/aacraid/Makefile
+++ b/drivers/scsi/aacraid/Makefile
@@ -3,6 +3,6 @@
obj-$(CONFIG_SCSI_AACRAID) := aacraid.o
aacraid-objs := linit.o aachba.o commctrl.o comminit.o commsup.o \
- dpcsup.o rx.o sa.o rkt.o
+ dpcsup.o rx.o sa.o rkt.o nark.o
EXTRA_CFLAGS := -Idrivers/scsi
diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
index 426cd6f49f5..d789e61bdc4 100644
--- a/drivers/scsi/aacraid/aachba.c
+++ b/drivers/scsi/aacraid/aachba.c
@@ -26,7 +26,6 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/types.h>
-#include <linux/sched.h>
#include <linux/pci.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
@@ -170,9 +169,9 @@ int acbsize = -1;
module_param(acbsize, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(acbsize, "Request a specific adapter control block (FIB) size. Valid values are 512, 2048, 4096 and 8192. Default is to use suggestion from Firmware.");
-int expose_physicals = 0;
+int expose_physicals = -1;
module_param(expose_physicals, int, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(expose_physicals, "Expose physical components of the arrays. 0=off, 1=on");
+MODULE_PARM_DESC(expose_physicals, "Expose physical components of the arrays. -1=protect 0=off, 1=on");
/**
* aac_get_config_status - check the adapter configuration
* @common: adapter to query
@@ -706,6 +705,309 @@ static void set_sense(u8 *sense_buf, u8 sense_key, u8 sense_code,
}
}
+static int aac_bounds_32(struct aac_dev * dev, struct scsi_cmnd * cmd, u64 lba)
+{
+ if (lba & 0xffffffff00000000LL) {
+ int cid = scmd_id(cmd);
+ dprintk((KERN_DEBUG "aacraid: Illegal lba\n"));
+ cmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
+ SAM_STAT_CHECK_CONDITION;
+ set_sense((u8 *) &dev->fsa_dev[cid].sense_data,
+ HARDWARE_ERROR,
+ SENCODE_INTERNAL_TARGET_FAILURE,
+ ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0,
+ 0, 0);
+ memcpy(cmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
+ (sizeof(dev->fsa_dev[cid].sense_data) > sizeof(cmd->sense_buffer))
+ ? sizeof(cmd->sense_buffer)
+ : sizeof(dev->fsa_dev[cid].sense_data));
+ cmd->scsi_done(cmd);
+ return 1;
+ }
+ return 0;
+}
+
+static int aac_bounds_64(struct aac_dev * dev, struct scsi_cmnd * cmd, u64 lba)
+{
+ return 0;
+}
+
+static void io_callback(void *context, struct fib * fibptr);
+
+static int aac_read_raw_io(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count)
+{
+ u16 fibsize;
+ struct aac_raw_io *readcmd;
+ aac_fib_init(fib);
+ readcmd = (struct aac_raw_io *) fib_data(fib);
+ readcmd->block[0] = cpu_to_le32((u32)(lba&0xffffffff));
+ readcmd->block[1] = cpu_to_le32((u32)((lba&0xffffffff00000000LL)>>32));
+ readcmd->count = cpu_to_le32(count<<9);
+ readcmd->cid = cpu_to_le16(scmd_id(cmd));
+ readcmd->flags = cpu_to_le16(1);
+ readcmd->bpTotal = 0;
+ readcmd->bpComplete = 0;
+
+ aac_build_sgraw(cmd, &readcmd->sg);
+ fibsize = sizeof(struct aac_raw_io) + ((le32_to_cpu(readcmd->sg.count) - 1) * sizeof (struct sgentryraw));
+ BUG_ON(fibsize > (fib->dev->max_fib_size - sizeof(struct aac_fibhdr)));
+ /*
+ * Now send the Fib to the adapter
+ */
+ return aac_fib_send(ContainerRawIo,
+ fib,
+ fibsize,
+ FsaNormal,
+ 0, 1,
+ (fib_callback) io_callback,
+ (void *) cmd);
+}
+
+static int aac_read_block64(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count)
+{
+ u16 fibsize;
+ struct aac_read64 *readcmd;
+ aac_fib_init(fib);
+ readcmd = (struct aac_read64 *) fib_data(fib);
+ readcmd->command = cpu_to_le32(VM_CtHostRead64);
+ readcmd->cid = cpu_to_le16(scmd_id(cmd));
+ readcmd->sector_count = cpu_to_le16(count);
+ readcmd->block = cpu_to_le32((u32)(lba&0xffffffff));
+ readcmd->pad = 0;
+ readcmd->flags = 0;
+
+ aac_build_sg64(cmd, &readcmd->sg);
+ fibsize = sizeof(struct aac_read64) +
+ ((le32_to_cpu(readcmd->sg.count) - 1) *
+ sizeof (struct sgentry64));
+ BUG_ON (fibsize > (fib->dev->max_fib_size -
+ sizeof(struct aac_fibhdr)));
+ /*
+ * Now send the Fib to the adapter
+ */
+ return aac_fib_send(ContainerCommand64,
+ fib,
+ fibsize,
+ FsaNormal,
+ 0, 1,
+ (fib_callback) io_callback,
+ (void *) cmd);
+}
+
+static int aac_read_block(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count)
+{
+ u16 fibsize;
+ struct aac_read *readcmd;
+ aac_fib_init(fib);
+ readcmd = (struct aac_read *) fib_data(fib);
+ readcmd->command = cpu_to_le32(VM_CtBlockRead);
+ readcmd->cid = cpu_to_le16(scmd_id(cmd));
+ readcmd->block = cpu_to_le32((u32)(lba&0xffffffff));
+ readcmd->count = cpu_to_le32(count * 512);
+
+ aac_build_sg(cmd, &readcmd->sg);
+ fibsize = sizeof(struct aac_read) +
+ ((le32_to_cpu(readcmd->sg.count) - 1) *
+ sizeof (struct sgentry));
+ BUG_ON (fibsize > (fib->dev->max_fib_size -
+ sizeof(struct aac_fibhdr)));
+ /*
+ * Now send the Fib to the adapter
+ */
+ return aac_fib_send(ContainerCommand,
+ fib,
+ fibsize,
+ FsaNormal,
+ 0, 1,
+ (fib_callback) io_callback,
+ (void *) cmd);
+}
+
+static int aac_write_raw_io(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count)
+{
+ u16 fibsize;
+ struct aac_raw_io *writecmd;
+ aac_fib_init(fib);
+ writecmd = (struct aac_raw_io *) fib_data(fib);
+ writecmd->block[0] = cpu_to_le32((u32)(lba&0xffffffff));
+ writecmd->block[1] = cpu_to_le32((u32)((lba&0xffffffff00000000LL)>>32));
+ writecmd->count = cpu_to_le32(count<<9);
+ writecmd->cid = cpu_to_le16(scmd_id(cmd));
+ writecmd->flags = 0;
+ writecmd->bpTotal = 0;
+ writecmd->bpComplete = 0;
+
+ aac_build_sgraw(cmd, &writecmd->sg);
+ fibsize = sizeof(struct aac_raw_io) + ((le32_to_cpu(writecmd->sg.count) - 1) * sizeof (struct sgentryraw));
+ BUG_ON(fibsize > (fib->dev->max_fib_size - sizeof(struct aac_fibhdr)));
+ /*
+ * Now send the Fib to the adapter
+ */
+ return aac_fib_send(ContainerRawIo,
+ fib,
+ fibsize,
+ FsaNormal,
+ 0, 1,
+ (fib_callback) io_callback,
+ (void *) cmd);
+}
+
+static int aac_write_block64(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count)
+{
+ u16 fibsize;
+ struct aac_write64 *writecmd;
+ aac_fib_init(fib);
+ writecmd = (struct aac_write64 *) fib_data(fib);
+ writecmd->command = cpu_to_le32(VM_CtHostWrite64);
+ writecmd->cid = cpu_to_le16(scmd_id(cmd));
+ writecmd->sector_count = cpu_to_le16(count);
+ writecmd->block = cpu_to_le32((u32)(lba&0xffffffff));
+ writecmd->pad = 0;
+ writecmd->flags = 0;
+
+ aac_build_sg64(cmd, &writecmd->sg);
+ fibsize = sizeof(struct aac_write64) +
+ ((le32_to_cpu(writecmd->sg.count) - 1) *
+ sizeof (struct sgentry64));
+ BUG_ON (fibsize > (fib->dev->max_fib_size -
+ sizeof(struct aac_fibhdr)));
+ /*
+ * Now send the Fib to the adapter
+ */
+ return aac_fib_send(ContainerCommand64,
+ fib,
+ fibsize,
+ FsaNormal,
+ 0, 1,
+ (fib_callback) io_callback,
+ (void *) cmd);
+}
+
+static int aac_write_block(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count)
+{
+ u16 fibsize;
+ struct aac_write *writecmd;
+ aac_fib_init(fib);
+ writecmd = (struct aac_write *) fib_data(fib);
+ writecmd->command = cpu_to_le32(VM_CtBlockWrite);
+ writecmd->cid = cpu_to_le16(scmd_id(cmd));
+ writecmd->block = cpu_to_le32((u32)(lba&0xffffffff));
+ writecmd->count = cpu_to_le32(count * 512);
+ writecmd->sg.count = cpu_to_le32(1);
+ /* ->stable is not used - it did mean which type of write */
+
+ aac_build_sg(cmd, &writecmd->sg);
+ fibsize = sizeof(struct aac_write) +
+ ((le32_to_cpu(writecmd->sg.count) - 1) *
+ sizeof (struct sgentry));
+ BUG_ON (fibsize > (fib->dev->max_fib_size -
+ sizeof(struct aac_fibhdr)));
+ /*
+ * Now send the Fib to the adapter
+ */
+ return aac_fib_send(ContainerCommand,
+ fib,
+ fibsize,
+ FsaNormal,
+ 0, 1,
+ (fib_callback) io_callback,
+ (void *) cmd);
+}
+
+static struct aac_srb * aac_scsi_common(struct fib * fib, struct scsi_cmnd * cmd)
+{
+ struct aac_srb * srbcmd;
+ u32 flag;
+ u32 timeout;
+
+ aac_fib_init(fib);
+ switch(cmd->sc_data_direction){
+ case DMA_TO_DEVICE:
+ flag = SRB_DataOut;
+ break;
+ case DMA_BIDIRECTIONAL:
+ flag = SRB_DataIn | SRB_DataOut;
+ break;
+ case DMA_FROM_DEVICE:
+ flag = SRB_DataIn;
+ break;
+ case DMA_NONE:
+ default: /* shuts up some versions of gcc */
+ flag = SRB_NoDataXfer;
+ break;
+ }
+
+ srbcmd = (struct aac_srb*) fib_data(fib);
+ srbcmd->function = cpu_to_le32(SRBF_ExecuteScsi);
+ srbcmd->channel = cpu_to_le32(aac_logical_to_phys(scmd_channel(cmd)));
+ srbcmd->id = cpu_to_le32(scmd_id(cmd));
+ srbcmd->lun = cpu_to_le32(cmd->device->lun);
+ srbcmd->flags = cpu_to_le32(flag);
+ timeout = cmd->timeout_per_command/HZ;
+ if (timeout == 0)
+ timeout = 1;
+ srbcmd->timeout = cpu_to_le32(timeout); // timeout in seconds
+ srbcmd->retry_limit = 0; /* Obsolete parameter */
+ srbcmd->cdb_size = cpu_to_le32(cmd->cmd_len);
+ return srbcmd;
+}
+
+static void aac_srb_callback(void *context, struct fib * fibptr);
+
+static int aac_scsi_64(struct fib * fib, struct scsi_cmnd * cmd)
+{
+ u16 fibsize;
+ struct aac_srb * srbcmd = aac_scsi_common(fib, cmd);
+
+ aac_build_sg64(cmd, (struct sgmap64*) &srbcmd->sg);
+ srbcmd->count = cpu_to_le32(cmd->request_bufflen);
+
+ memset(srbcmd->cdb, 0, sizeof(srbcmd->cdb));
+ memcpy(srbcmd->cdb, cmd->cmnd, cmd->cmd_len);
+ /*
+ * Build Scatter/Gather list
+ */
+ fibsize = sizeof (struct aac_srb) - sizeof (struct sgentry) +
+ ((le32_to_cpu(srbcmd->sg.count) & 0xff) *
+ sizeof (struct sgentry64));
+ BUG_ON (fibsize > (fib->dev->max_fib_size -
+ sizeof(struct aac_fibhdr)));
+
+ /*
+ * Now send the Fib to the adapter
+ */
+ return aac_fib_send(ScsiPortCommand64, fib,
+ fibsize, FsaNormal, 0, 1,
+ (fib_callback) aac_srb_callback,
+ (void *) cmd);
+}
+
+static int aac_scsi_32(struct fib * fib, struct scsi_cmnd * cmd)
+{
+ u16 fibsize;
+ struct aac_srb * srbcmd = aac_scsi_common(fib, cmd);
+
+ aac_build_sg(cmd, (struct sgmap*)&srbcmd->sg);
+ srbcmd->count = cpu_to_le32(cmd->request_bufflen);
+
+ memset(srbcmd->cdb, 0, sizeof(srbcmd->cdb));
+ memcpy(srbcmd->cdb, cmd->cmnd, cmd->cmd_len);
+ /*
+ * Build Scatter/Gather list
+ */
+ fibsize = sizeof (struct aac_srb) +
+ (((le32_to_cpu(srbcmd->sg.count) & 0xff) - 1) *
+ sizeof (struct sgentry));
+ BUG_ON (fibsize > (fib->dev->max_fib_size -
+ sizeof(struct aac_fibhdr)));
+
+ /*
+ * Now send the Fib to the adapter
+ */
+ return aac_fib_send(ScsiPortCommand, fib, fibsize, FsaNormal, 0, 1,
+ (fib_callback) aac_srb_callback, (void *) cmd);
+}
+
int aac_get_adapter_info(struct aac_dev* dev)
{
struct fib* fibptr;
@@ -874,14 +1176,27 @@ int aac_get_adapter_info(struct aac_dev* dev)
}
}
/*
- * 57 scatter gather elements
+ * Deal with configuring for the individualized limits of each packet
+ * interface.
*/
- if (!(dev->raw_io_interface)) {
+ dev->a_ops.adapter_scsi = (dev->dac_support)
+ ? aac_scsi_64
+ : aac_scsi_32;
+ if (dev->raw_io_interface) {
+ dev->a_ops.adapter_bounds = (dev->raw_io_64)
+ ? aac_bounds_64
+ : aac_bounds_32;
+ dev->a_ops.adapter_read = aac_read_raw_io;
+ dev->a_ops.adapter_write = aac_write_raw_io;
+ } else {
+ dev->a_ops.adapter_bounds = aac_bounds_32;
dev->scsi_host_ptr->sg_tablesize = (dev->max_fib_size -
sizeof(struct aac_fibhdr) -
sizeof(struct aac_write) + sizeof(struct sgentry)) /
sizeof(struct sgentry);
if (dev->dac_support) {
+ dev->a_ops.adapter_read = aac_read_block64;
+ dev->a_ops.adapter_write = aac_write_block64;
/*
* 38 scatter gather elements
*/
@@ -891,6 +1206,9 @@ int aac_get_adapter_info(struct aac_dev* dev)
sizeof(struct aac_write64) +
sizeof(struct sgentry64)) /
sizeof(struct sgentry64);
+ } else {
+ dev->a_ops.adapter_read = aac_read_block;
+ dev->a_ops.adapter_write = aac_write_block;
}
dev->scsi_host_ptr->max_sectors = AAC_MAX_32BIT_SGBCOUNT;
if(!(dev->adapter_info.options & AAC_OPT_NEW_COMM)) {
@@ -1004,8 +1322,6 @@ static int aac_read(struct scsi_cmnd * scsicmd, int cid)
u64 lba;
u32 count;
int status;
-
- u16 fibsize;
struct aac_dev *dev;
struct fib * cmd_fibcontext;
@@ -1059,23 +1375,8 @@ static int aac_read(struct scsi_cmnd * scsicmd, int cid)
}
dprintk((KERN_DEBUG "aac_read[cpu %d]: lba = %llu, t = %ld.\n",
smp_processor_id(), (unsigned long long)lba, jiffies));
- if ((!(dev->raw_io_interface) || !(dev->raw_io_64)) &&
- (lba & 0xffffffff00000000LL)) {
- dprintk((KERN_DEBUG "aac_read: Illegal lba\n"));
- scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
- SAM_STAT_CHECK_CONDITION;
- set_sense((u8 *) &dev->fsa_dev[cid].sense_data,
- HARDWARE_ERROR,
- SENCODE_INTERNAL_TARGET_FAILURE,
- ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0,
- 0, 0);
- memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
- (sizeof(dev->fsa_dev[cid].sense_data) > sizeof(scsicmd->sense_buffer))
- ? sizeof(scsicmd->sense_buffer)
- : sizeof(dev->fsa_dev[cid].sense_data));
- scsicmd->scsi_done(scsicmd);
+ if (aac_adapter_bounds(dev,scsicmd,lba))
return 0;
- }
/*
* Alocate and initialize a Fib
*/
@@ -1083,85 +1384,7 @@ static int aac_read(struct scsi_cmnd * scsicmd, int cid)
return -1;
}
- aac_fib_init(cmd_fibcontext);
-
- if (dev->raw_io_interface) {
- struct aac_raw_io *readcmd;
- readcmd = (struct aac_raw_io *) fib_data(cmd_fibcontext);
- readcmd->block[0] = cpu_to_le32((u32)(lba&0xffffffff));
- readcmd->block[1] = cpu_to_le32((u32)((lba&0xffffffff00000000LL)>>32));
- readcmd->count = cpu_to_le32(count<<9);
- readcmd->cid = cpu_to_le16(cid);
- readcmd->flags = cpu_to_le16(1);
- readcmd->bpTotal = 0;
- readcmd->bpComplete = 0;
-
- aac_build_sgraw(scsicmd, &readcmd->sg);
- fibsize = sizeof(struct aac_raw_io) + ((le32_to_cpu(readcmd->sg.count) - 1) * sizeof (struct sgentryraw));
- BUG_ON(fibsize > (dev->max_fib_size - sizeof(struct aac_fibhdr)));
- /*
- * Now send the Fib to the adapter
- */
- status = aac_fib_send(ContainerRawIo,
- cmd_fibcontext,
- fibsize,
- FsaNormal,
- 0, 1,
- (fib_callback) io_callback,
- (void *) scsicmd);
- } else if (dev->dac_support == 1) {
- struct aac_read64 *readcmd;
- readcmd = (struct aac_read64 *) fib_data(cmd_fibcontext);
- readcmd->command = cpu_to_le32(VM_CtHostRead64);
- readcmd->cid = cpu_to_le16(cid);
- readcmd->sector_count = cpu_to_le16(count);
- readcmd->block = cpu_to_le32((u32)(lba&0xffffffff));
- readcmd->pad = 0;
- readcmd->flags = 0;
-
- aac_build_sg64(scsicmd, &readcmd->sg);
- fibsize = sizeof(struct aac_read64) +
- ((le32_to_cpu(readcmd->sg.count) - 1) *
- sizeof (struct sgentry64));
- BUG_ON (fibsize > (dev->max_fib_size -
- sizeof(struct aac_fibhdr)));
- /*
- * Now send the Fib to the adapter
- */
- status = aac_fib_send(ContainerCommand64,
- cmd_fibcontext,
- fibsize,
- FsaNormal,
- 0, 1,
- (fib_callback) io_callback,
- (void *) scsicmd);
- } else {
- struct aac_read *readcmd;
- readcmd = (struct aac_read *) fib_data(cmd_fibcontext);
- readcmd->command = cpu_to_le32(VM_CtBlockRead);
- readcmd->cid = cpu_to_le32(cid);
- readcmd->block = cpu_to_le32((u32)(lba&0xffffffff));
- readcmd->count = cpu_to_le32(count * 512);
-
- aac_build_sg(scsicmd, &readcmd->sg);
- fibsize = sizeof(struct aac_read) +
- ((le32_to_cpu(readcmd->sg.count) - 1) *
- sizeof (struct sgentry));
- BUG_ON (fibsize > (dev->max_fib_size -
- sizeof(struct aac_fibhdr)));
- /*
- * Now send the Fib to the adapter
- */
- status = aac_fib_send(ContainerCommand,
- cmd_fibcontext,
- fibsize,
- FsaNormal,
- 0, 1,
- (fib_callback) io_callback,
- (void *) scsicmd);
- }
-
-
+ status = aac_adapter_read(cmd_fibcontext, scsicmd, lba, count);
/*
* Check that the command queued to the controller
@@ -1187,7 +1410,6 @@ static int aac_write(struct scsi_cmnd * scsicmd, int cid)
u64 lba;
u32 count;
int status;
- u16 fibsize;
struct aac_dev *dev;
struct fib * cmd_fibcontext;
@@ -1227,22 +1449,8 @@ static int aac_write(struct scsi_cmnd * scsicmd, int cid)
}
dprintk((KERN_DEBUG "aac_write[cpu %d]: lba = %llu, t = %ld.\n",
smp_processor_id(), (unsigned long long)lba, jiffies));
- if ((!(dev->raw_io_interface) || !(dev->raw_io_64))
- && (lba & 0xffffffff00000000LL)) {
- dprintk((KERN_DEBUG "aac_write: Illegal lba\n"));
- scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
- set_sense((u8 *) &dev->fsa_dev[cid].sense_data,
- HARDWARE_ERROR,
- SENCODE_INTERNAL_TARGET_FAILURE,
- ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0,
- 0, 0);
- memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
- (sizeof(dev->fsa_dev[cid].sense_data) > sizeof(scsicmd->sense_buffer))
- ? sizeof(scsicmd->sense_buffer)
- : sizeof(dev->fsa_dev[cid].sense_data));
- scsicmd->scsi_done(scsicmd);
+ if (aac_adapter_bounds(dev,scsicmd,lba))
return 0;
- }
/*
* Allocate and initialize a Fib then setup a BlockWrite command
*/
@@ -1251,85 +1459,8 @@ static int aac_write(struct scsi_cmnd * scsicmd, int cid)
scsicmd->scsi_done(scsicmd);
return 0;
}
- aac_fib_init(cmd_fibcontext);
- if (dev->raw_io_interface) {
- struct aac_raw_io *writecmd;
- writecmd = (struct aac_raw_io *) fib_data(cmd_fibcontext);
- writecmd->block[0] = cpu_to_le32((u32)(lba&0xffffffff));
- writecmd->block[1] = cpu_to_le32((u32)((lba&0xffffffff00000000LL)>>32));
- writecmd->count = cpu_to_le32(count<<9);
- writecmd->cid = cpu_to_le16(cid);
- writecmd->flags = 0;
- writecmd->bpTotal = 0;
- writecmd->bpComplete = 0;
-
- aac_build_sgraw(scsicmd, &writecmd->sg);
- fibsize = sizeof(struct aac_raw_io) + ((le32_to_cpu(writecmd->sg.count) - 1) * sizeof (struct sgentryraw));
- BUG_ON(fibsize > (dev->max_fib_size - sizeof(struct aac_fibhdr)));
- /*
- * Now send the Fib to the adapter
- */
- status = aac_fib_send(ContainerRawIo,
- cmd_fibcontext,
- fibsize,
- FsaNormal,
- 0, 1,
- (fib_callback) io_callback,
- (void *) scsicmd);
- } else if (dev->dac_support == 1) {
- struct aac_write64 *writecmd;
- writecmd = (struct aac_write64 *) fib_data(cmd_fibcontext);
- writecmd->command = cpu_to_le32(VM_CtHostWrite64);
- writecmd->cid = cpu_to_le16(cid);
- writecmd->sector_count = cpu_to_le16(count);
- writecmd->block = cpu_to_le32((u32)(lba&0xffffffff));
- writecmd->pad = 0;
- writecmd->flags = 0;
-
- aac_build_sg64(scsicmd, &writecmd->sg);
- fibsize = sizeof(struct aac_write64) +
- ((le32_to_cpu(writecmd->sg.count) - 1) *
- sizeof (struct sgentry64));
- BUG_ON (fibsize > (dev->max_fib_size -
- sizeof(struct aac_fibhdr)));
- /*
- * Now send the Fib to the adapter
- */
- status = aac_fib_send(ContainerCommand64,
- cmd_fibcontext,
- fibsize,
- FsaNormal,
- 0, 1,
- (fib_callback) io_callback,
- (void *) scsicmd);
- } else {
- struct aac_write *writecmd;
- writecmd = (struct aac_write *) fib_data(cmd_fibcontext);
- writecmd->command = cpu_to_le32(VM_CtBlockWrite);
- writecmd->cid = cpu_to_le32(cid);
- writecmd->block = cpu_to_le32((u32)(lba&0xffffffff));
- writecmd->count = cpu_to_le32(count * 512);
- writecmd->sg.count = cpu_to_le32(1);
- /* ->stable is not used - it did mean which type of write */
-
- aac_build_sg(scsicmd, &writecmd->sg);
- fibsize = sizeof(struct aac_write) +
- ((le32_to_cpu(writecmd->sg.count) - 1) *
- sizeof (struct sgentry));
- BUG_ON (fibsize > (dev->max_fib_size -
- sizeof(struct aac_fibhdr)));
- /*
- * Now send the Fib to the adapter
- */
- status = aac_fib_send(ContainerCommand,
- cmd_fibcontext,
- fibsize,
- FsaNormal,
- 0, 1,
- (fib_callback) io_callback,
- (void *) scsicmd);
- }
+ status = aac_adapter_write(cmd_fibcontext, scsicmd, lba, count);
/*
* Check that the command queued to the controller
@@ -2099,10 +2230,6 @@ static int aac_send_srb_fib(struct scsi_cmnd* scsicmd)
struct fib* cmd_fibcontext;
struct aac_dev* dev;
int status;
- struct aac_srb *srbcmd;
- u16 fibsize;
- u32 flag;
- u32 timeout;
dev = (struct aac_dev *)scsicmd->device->host->hostdata;
if (scmd_id(scsicmd) >= dev->maximum_num_physicals ||
@@ -2112,88 +2239,14 @@ static int aac_send_srb_fib(struct scsi_cmnd* scsicmd)
return 0;
}
- switch(scsicmd->sc_data_direction){
- case DMA_TO_DEVICE:
- flag = SRB_DataOut;
- break;
- case DMA_BIDIRECTIONAL:
- flag = SRB_DataIn | SRB_DataOut;
- break;
- case DMA_FROM_DEVICE:
- flag = SRB_DataIn;
- break;
- case DMA_NONE:
- default: /* shuts up some versions of gcc */
- flag = SRB_NoDataXfer;
- break;
- }
-
-
/*
* Allocate and initialize a Fib then setup a BlockWrite command
*/
if (!(cmd_fibcontext = aac_fib_alloc(dev))) {
return -1;
}
- aac_fib_init(cmd_fibcontext);
-
- srbcmd = (struct aac_srb*) fib_data(cmd_fibcontext);
- srbcmd->function = cpu_to_le32(SRBF_ExecuteScsi);
- srbcmd->channel = cpu_to_le32(aac_logical_to_phys(scmd_channel(scsicmd)));
- srbcmd->id = cpu_to_le32(scmd_id(scsicmd));
- srbcmd->lun = cpu_to_le32(scsicmd->device->lun);
- srbcmd->flags = cpu_to_le32(flag);
- timeout = scsicmd->timeout_per_command/HZ;
- if(timeout == 0){
- timeout = 1;
- }
- srbcmd->timeout = cpu_to_le32(timeout); // timeout in seconds
- srbcmd->retry_limit = 0; /* Obsolete parameter */
- srbcmd->cdb_size = cpu_to_le32(scsicmd->cmd_len);
-
- if( dev->dac_support == 1 ) {
- aac_build_sg64(scsicmd, (struct sgmap64*) &srbcmd->sg);
- srbcmd->count = cpu_to_le32(scsicmd->request_bufflen);
-
- memset(srbcmd->cdb, 0, sizeof(srbcmd->cdb));
- memcpy(srbcmd->cdb, scsicmd->cmnd, scsicmd->cmd_len);
- /*
- * Build Scatter/Gather list
- */
- fibsize = sizeof (struct aac_srb) - sizeof (struct sgentry) +
- ((le32_to_cpu(srbcmd->sg.count) & 0xff) *
- sizeof (struct sgentry64));
- BUG_ON (fibsize > (dev->max_fib_size -
- sizeof(struct aac_fibhdr)));
+ status = aac_adapter_scsi(cmd_fibcontext, scsicmd);
- /*
- * Now send the Fib to the adapter
- */
- status = aac_fib_send(ScsiPortCommand64, cmd_fibcontext,
- fibsize, FsaNormal, 0, 1,
- (fib_callback) aac_srb_callback,
- (void *) scsicmd);
- } else {
- aac_build_sg(scsicmd, (struct sgmap*)&srbcmd->sg);
- srbcmd->count = cpu_to_le32(scsicmd->request_bufflen);
-
- memset(srbcmd->cdb, 0, sizeof(srbcmd->cdb));
- memcpy(srbcmd->cdb, scsicmd->cmnd, scsicmd->cmd_len);
- /*
- * Build Scatter/Gather list
- */
- fibsize = sizeof (struct aac_srb) +
- (((le32_to_cpu(srbcmd->sg.count) & 0xff) - 1) *
- sizeof (struct sgentry));
- BUG_ON (fibsize > (dev->max_fib_size -
- sizeof(struct aac_fibhdr)));
-
- /*
- * Now send the Fib to the adapter
- */
- status = aac_fib_send(ScsiPortCommand, cmd_fibcontext, fibsize, FsaNormal, 0, 1,
- (fib_callback) aac_srb_callback, (void *) scsicmd);
- }
/*
* Check that the command queued to the controller
*/
diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h
index 4f8b4c53d43..39ecd0d22eb 100644
--- a/drivers/scsi/aacraid/aacraid.h
+++ b/drivers/scsi/aacraid/aacraid.h
@@ -5,6 +5,7 @@
#define _nblank(x) #x
#define nblank(x) _nblank(x)[0]
+#include <linux/interrupt.h>
/*------------------------------------------------------------------------------
* D E F I N E S
@@ -485,16 +486,28 @@ enum aac_log_level {
struct aac_dev;
struct fib;
+struct scsi_cmnd;
struct adapter_ops
{
+ /* Low level operations */
void (*adapter_interrupt)(struct aac_dev *dev);
void (*adapter_notify)(struct aac_dev *dev, u32 event);
void (*adapter_disable_int)(struct aac_dev *dev);
+ void (*adapter_enable_int)(struct aac_dev *dev);
int (*adapter_sync_cmd)(struct aac_dev *dev, u32 command, u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6, u32 *status, u32 *r1, u32 *r2, u32 *r3, u32 *r4);
int (*adapter_check_health)(struct aac_dev *dev);
- int (*adapter_send)(struct fib * fib);
+ /* Transport operations */
int (*adapter_ioremap)(struct aac_dev * dev, u32 size);
+ irqreturn_t (*adapter_intr)(int irq, void *dev_id);
+ /* Packet operations */
+ int (*adapter_deliver)(struct fib * fib);
+ int (*adapter_bounds)(struct aac_dev * dev, struct scsi_cmnd * cmd, u64 lba);
+ int (*adapter_read)(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count);
+ int (*adapter_write)(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count);
+ int (*adapter_scsi)(struct fib * fib, struct scsi_cmnd * cmd);
+ /* Administrative operations */
+ int (*adapter_comm)(struct aac_dev * dev, int comm);
};
/*
@@ -1018,7 +1031,9 @@ struct aac_dev
u8 nondasd_support;
u8 dac_support;
u8 raid_scsi_mode;
- u8 new_comm_interface;
+ u8 comm_interface;
+# define AAC_COMM_PRODUCER 0
+# define AAC_COMM_MESSAGE 1
/* macro side-effects BEWARE */
# define raw_io_interface \
init->InitStructRevision==cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION_4)
@@ -1036,18 +1051,36 @@ struct aac_dev
#define aac_adapter_disable_int(dev) \
(dev)->a_ops.adapter_disable_int(dev)
+#define aac_adapter_enable_int(dev) \
+ (dev)->a_ops.adapter_enable_int(dev)
+
#define aac_adapter_sync_cmd(dev, command, p1, p2, p3, p4, p5, p6, status, r1, r2, r3, r4) \
(dev)->a_ops.adapter_sync_cmd(dev, command, p1, p2, p3, p4, p5, p6, status, r1, r2, r3, r4)
#define aac_adapter_check_health(dev) \
(dev)->a_ops.adapter_check_health(dev)
-#define aac_adapter_send(fib) \
- ((fib)->dev)->a_ops.adapter_send(fib)
-
#define aac_adapter_ioremap(dev, size) \
(dev)->a_ops.adapter_ioremap(dev, size)
+#define aac_adapter_deliver(fib) \
+ ((fib)->dev)->a_ops.adapter_deliver(fib)
+
+#define aac_adapter_bounds(dev,cmd,lba) \
+ dev->a_ops.adapter_bounds(dev,cmd,lba)
+
+#define aac_adapter_read(fib,cmd,lba,count) \
+ ((fib)->dev)->a_ops.adapter_read(fib,cmd,lba,count)
+
+#define aac_adapter_write(fib,cmd,lba,count) \
+ ((fib)->dev)->a_ops.adapter_write(fib,cmd,lba,count)
+
+#define aac_adapter_scsi(fib,cmd) \
+ ((fib)->dev)->a_ops.adapter_scsi(fib,cmd)
+
+#define aac_adapter_comm(dev,comm) \
+ (dev)->a_ops.adapter_comm(dev, comm)
+
#define FIB_CONTEXT_FLAG_TIMED_OUT (0x00000001)
/*
@@ -1767,7 +1800,6 @@ static inline u32 cap_to_cyls(sector_t capacity, u32 divisor)
return (u32)capacity;
}
-struct scsi_cmnd;
/* SCp.phase values */
#define AAC_OWNER_MIDLEVEL 0x101
#define AAC_OWNER_LOWLEVEL 0x102
@@ -1794,7 +1826,9 @@ int aac_dev_ioctl(struct aac_dev *dev, int cmd, void __user *arg);
int aac_do_ioctl(struct aac_dev * dev, int cmd, void __user *arg);
int aac_rx_init(struct aac_dev *dev);
int aac_rkt_init(struct aac_dev *dev);
+int aac_nark_init(struct aac_dev *dev);
int aac_sa_init(struct aac_dev *dev);
+int aac_queue_get(struct aac_dev * dev, u32 * index, u32 qid, struct hw_fib * hw_fib, int wait, struct fib * fibptr, unsigned long *nonotify);
unsigned int aac_response_normal(struct aac_queue * q);
unsigned int aac_command_normal(struct aac_queue * q);
unsigned int aac_intr_normal(struct aac_dev * dev, u32 Index);
diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c
index da1d3a9212f..e21070f4eac 100644
--- a/drivers/scsi/aacraid/commctrl.c
+++ b/drivers/scsi/aacraid/commctrl.c
@@ -31,7 +31,6 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/types.h>
-#include <linux/sched.h>
#include <linux/pci.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c
index 6d305b2f854..ae34768987a 100644
--- a/drivers/scsi/aacraid/comminit.c
+++ b/drivers/scsi/aacraid/comminit.c
@@ -32,7 +32,6 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/types.h>
-#include <linux/sched.h>
#include <linux/pci.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
@@ -95,7 +94,7 @@ static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long co
init->HostPhysMemPages = cpu_to_le32(AAC_MAX_HOSTPHYSMEMPAGES);
init->InitFlags = 0;
- if (dev->new_comm_interface) {
+ if (dev->comm_interface == AAC_COMM_MESSAGE) {
init->InitFlags = cpu_to_le32(INITFLAGS_NEW_COMM_SUPPORTED);
dprintk((KERN_WARNING"aacraid: New Comm Interface enabled\n"));
}
@@ -297,21 +296,23 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev)
- sizeof(struct aac_fibhdr)
- sizeof(struct aac_write) + sizeof(struct sgentry))
/ sizeof(struct sgentry);
- dev->new_comm_interface = 0;
+ dev->comm_interface = AAC_COMM_PRODUCER;
dev->raw_io_64 = 0;
if ((!aac_adapter_sync_cmd(dev, GET_ADAPTER_PROPERTIES,
0, 0, 0, 0, 0, 0, status+0, status+1, status+2, NULL, NULL)) &&
(status[0] == 0x00000001)) {
if (status[1] & AAC_OPT_NEW_COMM_64)
dev->raw_io_64 = 1;
- if (status[1] & AAC_OPT_NEW_COMM)
- dev->new_comm_interface = dev->a_ops.adapter_send != 0;
- if (dev->new_comm_interface && (status[2] > dev->base_size)) {
+ if (dev->a_ops.adapter_comm &&
+ (status[1] & AAC_OPT_NEW_COMM))
+ dev->comm_interface = AAC_COMM_MESSAGE;
+ if ((dev->comm_interface == AAC_COMM_MESSAGE) &&
+ (status[2] > dev->base_size)) {
aac_adapter_ioremap(dev, 0);
dev->base_size = status[2];
if (aac_adapter_ioremap(dev, status[2])) {
/* remap failed, go back ... */
- dev->new_comm_interface = 0;
+ dev->comm_interface = AAC_COMM_PRODUCER;
if (aac_adapter_ioremap(dev, AAC_MIN_FOOTPRINT_SIZE)) {
printk(KERN_WARNING
"aacraid: unable to map adapter.\n");
diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c
index 4893a6d06a3..1b97f60652b 100644
--- a/drivers/scsi/aacraid/commsup.c
+++ b/drivers/scsi/aacraid/commsup.c
@@ -317,7 +317,7 @@ static int aac_get_entry (struct aac_dev * dev, u32 qid, struct aac_entry **entr
* success.
*/
-static int aac_queue_get(struct aac_dev * dev, u32 * index, u32 qid, struct hw_fib * hw_fib, int wait, struct fib * fibptr, unsigned long *nonotify)
+int aac_queue_get(struct aac_dev * dev, u32 * index, u32 qid, struct hw_fib * hw_fib, int wait, struct fib * fibptr, unsigned long *nonotify)
{
struct aac_entry * entry = NULL;
int map = 0;
@@ -387,7 +387,6 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
{
struct aac_dev * dev = fibptr->dev;
struct hw_fib * hw_fib = fibptr->hw_fib;
- struct aac_queue * q;
unsigned long flags = 0;
unsigned long qflags;
@@ -469,38 +468,10 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
if (!dev->queues)
return -EBUSY;
- q = &dev->queues->queue[AdapNormCmdQueue];
if(wait)
spin_lock_irqsave(&fibptr->event_lock, flags);
- spin_lock_irqsave(q->lock, qflags);
- if (dev->new_comm_interface) {
- unsigned long count = 10000000L; /* 50 seconds */
- q->numpending++;
- spin_unlock_irqrestore(q->lock, qflags);
- while (aac_adapter_send(fibptr) != 0) {
- if (--count == 0) {
- if (wait)
- spin_unlock_irqrestore(&fibptr->event_lock, flags);
- spin_lock_irqsave(q->lock, qflags);
- q->numpending--;
- spin_unlock_irqrestore(q->lock, qflags);
- return -ETIMEDOUT;
- }
- udelay(5);
- }
- } else {
- u32 index;
- unsigned long nointr = 0;
- aac_queue_get( dev, &index, AdapNormCmdQueue, hw_fib, 1, fibptr, &nointr);
-
- q->numpending++;
- *(q->headers.producer) = cpu_to_le32(index + 1);
- spin_unlock_irqrestore(q->lock, qflags);
- dprintk((KERN_DEBUG "aac_fib_send: inserting a queue entry at index %d.\n",index));
- if (!(nointr & aac_config.irq_mod))
- aac_adapter_notify(dev, AdapNormCmdQueue);
- }
+ aac_adapter_deliver(fibptr);
/*
* If the caller wanted us to wait for response wait now.
@@ -520,6 +491,7 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
while (down_trylock(&fibptr->event_wait)) {
int blink;
if (--count == 0) {
+ struct aac_queue * q = &dev->queues->queue[AdapNormCmdQueue];
spin_lock_irqsave(q->lock, qflags);
q->numpending--;
spin_unlock_irqrestore(q->lock, qflags);
@@ -659,7 +631,7 @@ int aac_fib_adapter_complete(struct fib *fibptr, unsigned short size)
unsigned long qflags;
if (hw_fib->header.XferState == 0) {
- if (dev->new_comm_interface)
+ if (dev->comm_interface == AAC_COMM_MESSAGE)
kfree (hw_fib);
return 0;
}
@@ -667,7 +639,7 @@ int aac_fib_adapter_complete(struct fib *fibptr, unsigned short size)
* If we plan to do anything check the structure type first.
*/
if ( hw_fib->header.StructType != FIB_MAGIC ) {
- if (dev->new_comm_interface)
+ if (dev->comm_interface == AAC_COMM_MESSAGE)
kfree (hw_fib);
return -EINVAL;
}
@@ -679,7 +651,7 @@ int aac_fib_adapter_complete(struct fib *fibptr, unsigned short size)
* send the completed cdb to the adapter.
*/
if (hw_fib->header.XferState & cpu_to_le32(SentFromAdapter)) {
- if (dev->new_comm_interface) {
+ if (dev->comm_interface == AAC_COMM_MESSAGE) {
kfree (hw_fib);
} else {
u32 index;
diff --git a/drivers/scsi/aacraid/dpcsup.c b/drivers/scsi/aacraid/dpcsup.c
index 8335f07b772..d38b628be1a 100644
--- a/drivers/scsi/aacraid/dpcsup.c
+++ b/drivers/scsi/aacraid/dpcsup.c
@@ -32,7 +32,6 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/types.h>
-#include <linux/sched.h>
#include <linux/pci.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c
index d2cf875af59..0f948c2fb60 100644
--- a/drivers/scsi/aacraid/linit.c
+++ b/drivers/scsi/aacraid/linit.c
@@ -157,6 +157,7 @@ static struct pci_device_id aac_pci_tbl[] = {
{ 0x9005, 0x0285, 0x17aa, PCI_ANY_ID, 0, 0, 58 }, /* Legend Catchall */
{ 0x9005, 0x0285, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 59 }, /* Adaptec Catch All */
{ 0x9005, 0x0286, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 60 }, /* Adaptec Rocket Catch All */
+ { 0x9005, 0x0288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 61 }, /* Adaptec NEMER/ARK Catch All */
{ 0,}
};
MODULE_DEVICE_TABLE(pci, aac_pci_tbl);
@@ -230,7 +231,8 @@ static struct aac_driver_ident aac_drivers[] = {
{ aac_rx_init, "aacraid", "DELL ", "RAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Dell Catchall */
{ aac_rx_init, "aacraid", "Legend ", "RAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Legend Catchall */
{ aac_rx_init, "aacraid", "ADAPTEC ", "RAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Adaptec Catch All */
- { aac_rkt_init, "aacraid", "ADAPTEC ", "RAID ", 2 } /* Adaptec Rocket Catch All */
+ { aac_rkt_init, "aacraid", "ADAPTEC ", "RAID ", 2 }, /* Adaptec Rocket Catch All */
+ { aac_nark_init, "aacraid", "ADAPTEC ", "RAID ", 2 } /* Adaptec NEMER/ARK Catch All */
};
/**
@@ -396,11 +398,15 @@ static int aac_slave_configure(struct scsi_device *sdev)
sdev->skip_ms_page_3f = 1;
}
if ((sdev->type == TYPE_DISK) &&
- !expose_physicals &&
(sdev_channel(sdev) != CONTAINER_CHANNEL)) {
- struct aac_dev *aac = (struct aac_dev *)sdev->host->hostdata;
- if (!aac->raid_scsi_mode || (sdev_channel(sdev) != 2))
- sdev->no_uld_attach = 1;
+ if (expose_physicals == 0)
+ return -ENXIO;
+ if (expose_physicals < 0) {
+ struct aac_dev *aac =
+ (struct aac_dev *)sdev->host->hostdata;
+ if (!aac->raid_scsi_mode || (sdev_channel(sdev) != 2))
+ sdev->no_uld_attach = 1;
+ }
}
if (sdev->tagged_supported && (sdev->type == TYPE_DISK) &&
(sdev_channel(sdev) == CONTAINER_CHANNEL)) {
@@ -768,7 +774,7 @@ static struct class_device_attribute *aac_attrs[] = {
};
-static struct file_operations aac_cfg_fops = {
+static const struct file_operations aac_cfg_fops = {
.owner = THIS_MODULE,
.ioctl = aac_cfg_ioctl,
#ifdef CONFIG_COMPAT
@@ -804,7 +810,6 @@ static struct scsi_host_template aac_driver_template = {
.emulated = 1,
};
-
static int __devinit aac_probe_one(struct pci_dev *pdev,
const struct pci_device_id *id)
{
diff --git a/drivers/scsi/aacraid/nark.c b/drivers/scsi/aacraid/nark.c
new file mode 100644
index 00000000000..c76b611b6af
--- /dev/null
+++ b/drivers/scsi/aacraid/nark.c
@@ -0,0 +1,87 @@
+/*
+ * Adaptec AAC series RAID controller driver
+ * (c) Copyright 2001 Red Hat Inc. <alan@redhat.com>
+ *
+ * based on the old aacraid driver that is..
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ * nark.c
+ *
+ * Abstract: Hardware Device Interface for NEMER/ARK
+ *
+ */
+
+#include <linux/pci.h>
+#include <linux/blkdev.h>
+
+#include <scsi/scsi_host.h>
+
+#include "aacraid.h"
+
+/**
+ * aac_nark_ioremap
+ * @size: mapping resize request
+ *
+ */
+static int aac_nark_ioremap(struct aac_dev * dev, u32 size)
+{
+ if (!size) {
+ iounmap(dev->regs.rx);
+ dev->regs.rx = NULL;
+ iounmap(dev->base);
+ dev->base = NULL;
+ return 0;
+ }
+ dev->scsi_host_ptr->base = pci_resource_start(dev->pdev, 2);
+ dev->regs.rx = ioremap((u64)pci_resource_start(dev->pdev, 0) |
+ ((u64)pci_resource_start(dev->pdev, 1) << 32),
+ sizeof(struct rx_registers) - sizeof(struct rx_inbound));
+ dev->base = NULL;
+ if (dev->regs.rx == NULL)
+ return -1;
+ dev->base = ioremap(dev->scsi_host_ptr->base, size);
+ if (dev->base == NULL) {
+ iounmap(dev->regs.rx);
+ dev->regs.rx = NULL;
+ return -1;
+ }
+ dev->IndexRegs = &((struct rx_registers __iomem *)dev->base)->IndexRegs;
+ return 0;
+}
+
+/**
+ * aac_nark_init - initialize an NEMER/ARK Split Bar card
+ * @dev: device to configure
+ *
+ */
+
+int aac_nark_init(struct aac_dev * dev)
+{
+ extern int _aac_rx_init(struct aac_dev *dev);
+ extern int aac_rx_select_comm(struct aac_dev *dev, int comm);
+
+ /*
+ * Fill in the function dispatch table.
+ */
+ dev->a_ops.adapter_ioremap = aac_nark_ioremap;
+ dev->a_ops.adapter_comm = aac_rx_select_comm;
+
+ return _aac_rx_init(dev);
+}
diff --git a/drivers/scsi/aacraid/rkt.c b/drivers/scsi/aacraid/rkt.c
index 643f23b5ded..d953c3fe998 100644
--- a/drivers/scsi/aacraid/rkt.c
+++ b/drivers/scsi/aacraid/rkt.c
@@ -34,6 +34,40 @@
#include "aacraid.h"
+#define AAC_NUM_IO_FIB_RKT (246 - AAC_NUM_MGT_FIB)
+
+/**
+ * aac_rkt_select_comm - Select communications method
+ * @dev: Adapter
+ * @comm: communications method
+ */
+
+static int aac_rkt_select_comm(struct aac_dev *dev, int comm)
+{
+ int retval;
+ extern int aac_rx_select_comm(struct aac_dev *dev, int comm);
+ retval = aac_rx_select_comm(dev, comm);
+ if (comm == AAC_COMM_MESSAGE) {
+ /*
+ * FIB Setup has already been done, but we can minimize the
+ * damage by at least ensuring the OS never issues more
+ * commands than we can handle. The Rocket adapters currently
+ * can only handle 246 commands and 8 AIFs at the same time,
+ * and in fact do notify us accordingly if we negotiate the
+ * FIB size. The problem that causes us to add this check is
+ * to ensure that we do not overdo it with the adapter when a
+ * hard coded FIB override is being utilized. This special
+ * case warrants this half baked, but convenient, check here.
+ */
+ if (dev->scsi_host_ptr->can_queue > AAC_NUM_IO_FIB_RKT) {
+ dev->init->MaxIoCommands =
+ cpu_to_le32(AAC_NUM_IO_FIB_RKT + AAC_NUM_MGT_FIB);
+ dev->scsi_host_ptr->can_queue = AAC_NUM_IO_FIB_RKT;
+ }
+ }
+ return retval;
+}
+
/**
* aac_rkt_ioremap
* @size: mapping resize request
@@ -63,39 +97,13 @@ static int aac_rkt_ioremap(struct aac_dev * dev, u32 size)
int aac_rkt_init(struct aac_dev *dev)
{
- int retval;
extern int _aac_rx_init(struct aac_dev *dev);
- extern void aac_rx_start_adapter(struct aac_dev *dev);
/*
* Fill in the function dispatch table.
*/
dev->a_ops.adapter_ioremap = aac_rkt_ioremap;
+ dev->a_ops.adapter_comm = aac_rkt_select_comm;
- retval = _aac_rx_init(dev);
- if (retval)
- return retval;
- if (dev->new_comm_interface) {
- /*
- * FIB Setup has already been done, but we can minimize the
- * damage by at least ensuring the OS never issues more
- * commands than we can handle. The Rocket adapters currently
- * can only handle 246 commands and 8 AIFs at the same time,
- * and in fact do notify us accordingly if we negotiate the
- * FIB size. The problem that causes us to add this check is
- * to ensure that we do not overdo it with the adapter when a
- * hard coded FIB override is being utilized. This special
- * case warrants this half baked, but convenient, check here.
- */
- if (dev->scsi_host_ptr->can_queue > (246 - AAC_NUM_MGT_FIB)) {
- dev->init->MaxIoCommands = cpu_to_le32(246);
- dev->scsi_host_ptr->can_queue = 246 - AAC_NUM_MGT_FIB;
- }
- }
- /*
- * Tell the adapter that all is configured, and it can start
- * accepting requests
- */
- aac_rx_start_adapter(dev);
- return 0;
+ return _aac_rx_init(dev);
}
diff --git a/drivers/scsi/aacraid/rx.c b/drivers/scsi/aacraid/rx.c
index dcc8b0ea7a9..d242e2611d6 100644
--- a/drivers/scsi/aacraid/rx.c
+++ b/drivers/scsi/aacraid/rx.c
@@ -31,7 +31,6 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/types.h>
-#include <linux/sched.h>
#include <linux/pci.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
@@ -46,60 +45,60 @@
#include "aacraid.h"
-static irqreturn_t aac_rx_intr(int irq, void *dev_id)
+static irqreturn_t aac_rx_intr_producer(int irq, void *dev_id)
{
struct aac_dev *dev = dev_id;
+ unsigned long bellbits;
+ u8 intstat = rx_readb(dev, MUnit.OISR);
- dprintk((KERN_DEBUG "aac_rx_intr(%d,%p)\n", irq, dev_id));
- if (dev->new_comm_interface) {
- u32 Index = rx_readl(dev, MUnit.OutboundQueue);
- if (Index == 0xFFFFFFFFL)
- Index = rx_readl(dev, MUnit.OutboundQueue);
- if (Index != 0xFFFFFFFFL) {
- do {
- if (aac_intr_normal(dev, Index)) {
- rx_writel(dev, MUnit.OutboundQueue, Index);
- rx_writel(dev, MUnit.ODR, DoorBellAdapterNormRespReady);
- }
- Index = rx_readl(dev, MUnit.OutboundQueue);
- } while (Index != 0xFFFFFFFFL);
- return IRQ_HANDLED;
+ /*
+ * Read mask and invert because drawbridge is reversed.
+ * This allows us to only service interrupts that have
+ * been enabled.
+ * Check to see if this is our interrupt. If it isn't just return
+ */
+ if (intstat & ~(dev->OIMR)) {
+ bellbits = rx_readl(dev, OutboundDoorbellReg);
+ if (bellbits & DoorBellPrintfReady) {
+ aac_printf(dev, readl (&dev->IndexRegs->Mailbox[5]));
+ rx_writel(dev, MUnit.ODR,DoorBellPrintfReady);
+ rx_writel(dev, InboundDoorbellReg,DoorBellPrintfDone);
}
- } else {
- unsigned long bellbits;
- u8 intstat;
- intstat = rx_readb(dev, MUnit.OISR);
- /*
- * Read mask and invert because drawbridge is reversed.
- * This allows us to only service interrupts that have
- * been enabled.
- * Check to see if this is our interrupt. If it isn't just return
- */
- if (intstat & ~(dev->OIMR))
- {
- bellbits = rx_readl(dev, OutboundDoorbellReg);
- if (bellbits & DoorBellPrintfReady) {
- aac_printf(dev, readl (&dev->IndexRegs->Mailbox[5]));
- rx_writel(dev, MUnit.ODR,DoorBellPrintfReady);
- rx_writel(dev, InboundDoorbellReg,DoorBellPrintfDone);
- }
- else if (bellbits & DoorBellAdapterNormCmdReady) {
- rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdReady);
- aac_command_normal(&dev->queues->queue[HostNormCmdQueue]);
- }
- else if (bellbits & DoorBellAdapterNormRespReady) {
- rx_writel(dev, MUnit.ODR,DoorBellAdapterNormRespReady);
- aac_response_normal(&dev->queues->queue[HostNormRespQueue]);
- }
- else if (bellbits & DoorBellAdapterNormCmdNotFull) {
- rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull);
- }
- else if (bellbits & DoorBellAdapterNormRespNotFull) {
- rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull);
- rx_writel(dev, MUnit.ODR, DoorBellAdapterNormRespNotFull);
- }
- return IRQ_HANDLED;
+ else if (bellbits & DoorBellAdapterNormCmdReady) {
+ rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdReady);
+ aac_command_normal(&dev->queues->queue[HostNormCmdQueue]);
+ }
+ else if (bellbits & DoorBellAdapterNormRespReady) {
+ rx_writel(dev, MUnit.ODR,DoorBellAdapterNormRespReady);
+ aac_response_normal(&dev->queues->queue[HostNormRespQueue]);
+ }
+ else if (bellbits & DoorBellAdapterNormCmdNotFull) {
+ rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull);
}
+ else if (bellbits & DoorBellAdapterNormRespNotFull) {
+ rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull);
+ rx_writel(dev, MUnit.ODR, DoorBellAdapterNormRespNotFull);
+ }
+ return IRQ_HANDLED;
+ }
+ return IRQ_NONE;
+}
+
+static irqreturn_t aac_rx_intr_message(int irq, void *dev_id)
+{
+ struct aac_dev *dev = dev_id;
+ u32 Index = rx_readl(dev, MUnit.OutboundQueue);
+ if (Index == 0xFFFFFFFFL)
+ Index = rx_readl(dev, MUnit.OutboundQueue);
+ if (Index != 0xFFFFFFFFL) {
+ do {
+ if (aac_intr_normal(dev, Index)) {
+ rx_writel(dev, MUnit.OutboundQueue, Index);
+ rx_writel(dev, MUnit.ODR, DoorBellAdapterNormRespReady);
+ }
+ Index = rx_readl(dev, MUnit.OutboundQueue);
+ } while (Index != 0xFFFFFFFFL);
+ return IRQ_HANDLED;
}
return IRQ_NONE;
}
@@ -115,6 +114,26 @@ static void aac_rx_disable_interrupt(struct aac_dev *dev)
}
/**
+ * aac_rx_enable_interrupt_producer - Enable interrupts
+ * @dev: Adapter
+ */
+
+static void aac_rx_enable_interrupt_producer(struct aac_dev *dev)
+{
+ rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xfb);
+}
+
+/**
+ * aac_rx_enable_interrupt_message - Enable interrupts
+ * @dev: Adapter
+ */
+
+static void aac_rx_enable_interrupt_message(struct aac_dev *dev)
+{
+ rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xf7);
+}
+
+/**
* rx_sync_cmd - send a command and wait
* @dev: Adapter
* @command: Command to execute
@@ -189,10 +208,7 @@ static int rx_sync_cmd(struct aac_dev *dev, u32 command,
/*
* Restore interrupt mask even though we timed out
*/
- if (dev->new_comm_interface)
- rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xf7);
- else
- rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xfb);
+ aac_adapter_enable_int(dev);
return -ETIMEDOUT;
}
/*
@@ -215,10 +231,7 @@ static int rx_sync_cmd(struct aac_dev *dev, u32 command,
/*
* Restore interrupt mask
*/
- if (dev->new_comm_interface)
- rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xf7);
- else
- rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xfb);
+ aac_adapter_enable_int(dev);
return 0;
}
@@ -360,35 +373,72 @@ static int aac_rx_check_health(struct aac_dev *dev)
}
/**
- * aac_rx_send
+ * aac_rx_deliver_producer
* @fib: fib to issue
*
* Will send a fib, returning 0 if successful.
*/
-static int aac_rx_send(struct fib * fib)
+static int aac_rx_deliver_producer(struct fib * fib)
{
- u64 addr = fib->hw_fib_pa;
struct aac_dev *dev = fib->dev;
- volatile void __iomem *device = dev->regs.rx;
+ struct aac_queue *q = &dev->queues->queue[AdapNormCmdQueue];
+ unsigned long qflags;
u32 Index;
+ unsigned long nointr = 0;
- dprintk((KERN_DEBUG "%p->aac_rx_send(%p->%llx)\n", dev, fib, addr));
- Index = rx_readl(dev, MUnit.InboundQueue);
- if (Index == 0xFFFFFFFFL)
+ spin_lock_irqsave(q->lock, qflags);
+ aac_queue_get( dev, &Index, AdapNormCmdQueue, fib->hw_fib, 1, fib, &nointr);
+
+ q->numpending++;
+ *(q->headers.producer) = cpu_to_le32(Index + 1);
+ spin_unlock_irqrestore(q->lock, qflags);
+ if (!(nointr & aac_config.irq_mod))
+ aac_adapter_notify(dev, AdapNormCmdQueue);
+
+ return 0;
+}
+
+/**
+ * aac_rx_deliver_message
+ * @fib: fib to issue
+ *
+ * Will send a fib, returning 0 if successful.
+ */
+static int aac_rx_deliver_message(struct fib * fib)
+{
+ struct aac_dev *dev = fib->dev;
+ struct aac_queue *q = &dev->queues->queue[AdapNormCmdQueue];
+ unsigned long qflags;
+ u32 Index;
+ u64 addr;
+ volatile void __iomem *device;
+
+ unsigned long count = 10000000L; /* 50 seconds */
+ spin_lock_irqsave(q->lock, qflags);
+ q->numpending++;
+ spin_unlock_irqrestore(q->lock, qflags);
+ for(;;) {
Index = rx_readl(dev, MUnit.InboundQueue);
- dprintk((KERN_DEBUG "Index = 0x%x\n", Index));
- if (Index == 0xFFFFFFFFL)
- return Index;
+ if (Index == 0xFFFFFFFFL)
+ Index = rx_readl(dev, MUnit.InboundQueue);
+ if (Index != 0xFFFFFFFFL)
+ break;
+ if (--count == 0) {
+ spin_lock_irqsave(q->lock, qflags);
+ q->numpending--;
+ spin_unlock_irqrestore(q->lock, qflags);
+ return -ETIMEDOUT;
+ }
+ udelay(5);
+ }
device = dev->base + Index;
- dprintk((KERN_DEBUG "entry = %x %x %u\n", (u32)(addr & 0xffffffff),
- (u32)(addr >> 32), (u32)le16_to_cpu(fib->hw_fib->header.Size)));
+ addr = fib->hw_fib_pa;
writel((u32)(addr & 0xffffffff), device);
device += sizeof(u32);
writel((u32)(addr >> 32), device);
device += sizeof(u32);
writel(le16_to_cpu(fib->hw_fib->header.Size), device);
rx_writel(dev, MUnit.InboundQueue, Index);
- dprintk((KERN_DEBUG "aac_rx_send - return 0\n"));
return 0;
}
@@ -430,6 +480,31 @@ static int aac_rx_restart_adapter(struct aac_dev *dev)
}
/**
+ * aac_rx_select_comm - Select communications method
+ * @dev: Adapter
+ * @comm: communications method
+ */
+
+int aac_rx_select_comm(struct aac_dev *dev, int comm)
+{
+ switch (comm) {
+ case AAC_COMM_PRODUCER:
+ dev->a_ops.adapter_enable_int = aac_rx_enable_interrupt_producer;
+ dev->a_ops.adapter_intr = aac_rx_intr_producer;
+ dev->a_ops.adapter_deliver = aac_rx_deliver_producer;
+ break;
+ case AAC_COMM_MESSAGE:
+ dev->a_ops.adapter_enable_int = aac_rx_enable_interrupt_message;
+ dev->a_ops.adapter_intr = aac_rx_intr_message;
+ dev->a_ops.adapter_deliver = aac_rx_deliver_message;
+ break;
+ default:
+ return 1;
+ }
+ return 0;
+}
+
+/**
* aac_rx_init - initialize an i960 based AAC card
* @dev: device to configure
*
@@ -489,40 +564,42 @@ int _aac_rx_init(struct aac_dev *dev)
}
msleep(1);
}
- if (request_irq(dev->scsi_host_ptr->irq, aac_rx_intr, IRQF_SHARED|IRQF_DISABLED, "aacraid", (void *)dev)<0)
- {
- printk(KERN_ERR "%s%d: Interrupt unavailable.\n", name, instance);
- goto error_iounmap;
- }
/*
- * Fill in the function dispatch table.
+ * Fill in the common function dispatch table.
*/
dev->a_ops.adapter_interrupt = aac_rx_interrupt_adapter;
dev->a_ops.adapter_disable_int = aac_rx_disable_interrupt;
dev->a_ops.adapter_notify = aac_rx_notify_adapter;
dev->a_ops.adapter_sync_cmd = rx_sync_cmd;
dev->a_ops.adapter_check_health = aac_rx_check_health;
- dev->a_ops.adapter_send = aac_rx_send;
/*
* First clear out all interrupts. Then enable the one's that we
* can handle.
*/
- rx_writeb(dev, MUnit.OIMR, 0xff);
+ aac_adapter_comm(dev, AAC_COMM_PRODUCER);
+ aac_adapter_disable_int(dev);
rx_writel(dev, MUnit.ODR, 0xffffffff);
- rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xfb);
+ aac_adapter_enable_int(dev);
if (aac_init_adapter(dev) == NULL)
- goto error_irq;
- if (dev->new_comm_interface)
- rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xf7);
+ goto error_iounmap;
+ aac_adapter_comm(dev, dev->comm_interface);
+ if (request_irq(dev->scsi_host_ptr->irq, dev->a_ops.adapter_intr,
+ IRQF_SHARED|IRQF_DISABLED, "aacraid", dev) < 0) {
+ printk(KERN_ERR "%s%d: Interrupt unavailable.\n",
+ name, instance);
+ goto error_iounmap;
+ }
+ aac_adapter_enable_int(dev);
+ /*
+ * Tell the adapter that all is configured, and it can
+ * start accepting requests
+ */
+ aac_rx_start_adapter(dev);
return 0;
-error_irq:
- rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xff);
- free_irq(dev->scsi_host_ptr->irq, (void *)dev);
-
error_iounmap:
return -1;
@@ -530,20 +607,11 @@ error_iounmap:
int aac_rx_init(struct aac_dev *dev)
{
- int retval;
-
/*
* Fill in the function dispatch table.
*/
dev->a_ops.adapter_ioremap = aac_rx_ioremap;
+ dev->a_ops.adapter_comm = aac_rx_select_comm;
- retval = _aac_rx_init(dev);
- if (!retval) {
- /*
- * Tell the adapter that all is configured, and it can
- * start accepting requests
- */
- aac_rx_start_adapter(dev);
- }
- return retval;
+ return _aac_rx_init(dev);
}
diff --git a/drivers/scsi/aacraid/sa.c b/drivers/scsi/aacraid/sa.c
index 511b0a938fb..6f1a1780efc 100644
--- a/drivers/scsi/aacraid/sa.c
+++ b/drivers/scsi/aacraid/sa.c
@@ -31,7 +31,6 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/types.h>
-#include <linux/sched.h>
#include <linux/pci.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
@@ -92,6 +91,17 @@ static void aac_sa_disable_interrupt (struct aac_dev *dev)
}
/**
+ * aac_sa_enable_interrupt - enable interrupt
+ * @dev: Which adapter to enable.
+ */
+
+static void aac_sa_enable_interrupt (struct aac_dev *dev)
+{
+ sa_writew(dev, SaDbCSR.PRICLEARIRQMASK, (PrintfReady | DOORBELL_1 |
+ DOORBELL_2 | DOORBELL_3 | DOORBELL_4));
+}
+
+/**
* aac_sa_notify_adapter - handle adapter notification
* @dev: Adapter that notification is for
* @event: Event to notidy
@@ -347,32 +357,36 @@ int aac_sa_init(struct aac_dev *dev)
msleep(1);
}
- if (request_irq(dev->scsi_host_ptr->irq, aac_sa_intr, IRQF_SHARED|IRQF_DISABLED, "aacraid", (void *)dev ) < 0) {
- printk(KERN_WARNING "%s%d: Interrupt unavailable.\n", name, instance);
- goto error_iounmap;
- }
-
/*
* Fill in the function dispatch table.
*/
dev->a_ops.adapter_interrupt = aac_sa_interrupt_adapter;
dev->a_ops.adapter_disable_int = aac_sa_disable_interrupt;
+ dev->a_ops.adapter_enable_int = aac_sa_enable_interrupt;
dev->a_ops.adapter_notify = aac_sa_notify_adapter;
dev->a_ops.adapter_sync_cmd = sa_sync_cmd;
dev->a_ops.adapter_check_health = aac_sa_check_health;
+ dev->a_ops.adapter_intr = aac_sa_intr;
dev->a_ops.adapter_ioremap = aac_sa_ioremap;
/*
* First clear out all interrupts. Then enable the one's that
* we can handle.
*/
- sa_writew(dev, SaDbCSR.PRISETIRQMASK, 0xffff);
- sa_writew(dev, SaDbCSR.PRICLEARIRQMASK, (PrintfReady | DOORBELL_1 |
- DOORBELL_2 | DOORBELL_3 | DOORBELL_4));
+ aac_adapter_disable_int(dev);
+ aac_adapter_enable_int(dev);
if(aac_init_adapter(dev) == NULL)
goto error_irq;
+ if (request_irq(dev->scsi_host_ptr->irq, dev->a_ops.adapter_intr,
+ IRQF_SHARED|IRQF_DISABLED,
+ "aacraid", (void *)dev ) < 0) {
+ printk(KERN_WARNING "%s%d: Interrupt unavailable.\n",
+ name, instance);
+ goto error_iounmap;
+ }
+ aac_adapter_enable_int(dev);
/*
* Tell the adapter that all is configure, and it can start
@@ -382,7 +396,7 @@ int aac_sa_init(struct aac_dev *dev)
return 0;
error_irq:
- sa_writew(dev, SaDbCSR.PRISETIRQMASK, 0xffff);
+ aac_sa_disable_interrupt(dev);
free_irq(dev->scsi_host_ptr->irq, (void *)dev);
error_iounmap:
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
index 306bec355e4..9b3303b6411 100644
--- a/drivers/scsi/advansys.c
+++ b/drivers/scsi/advansys.c
@@ -4403,7 +4403,7 @@ advansys_detect(struct scsi_host_template *tpnt)
ASC_DBG1(1,
"advansys_detect: probing I/O port 0x%x...\n",
iop);
- if (check_region(iop, ASC_IOADR_GAP) != 0) {
+ if (!request_region(iop, ASC_IOADR_GAP, "advansys")){
printk(
"AdvanSys SCSI: specified I/O Port 0x%X is busy\n", iop);
/* Don't try this I/O port twice. */
@@ -4413,6 +4413,7 @@ advansys_detect(struct scsi_host_template *tpnt)
printk(
"AdvanSys SCSI: specified I/O Port 0x%X has no adapter\n", iop);
/* Don't try this I/O port twice. */
+ release_region(iop, ASC_IOADR_GAP);
asc_ioport[ioport] = 0;
goto ioport_try_again;
} else {
@@ -4431,6 +4432,7 @@ advansys_detect(struct scsi_host_template *tpnt)
* 'ioport' past this board.
*/
ioport++;
+ release_region(iop, ASC_IOADR_GAP);
goto ioport_try_again;
}
}
@@ -9740,13 +9742,14 @@ AscSearchIOPortAddr11(
}
for (; i < ASC_IOADR_TABLE_MAX_IX; i++) {
iop_base = _asc_def_iop_base[i];
- if (check_region(iop_base, ASC_IOADR_GAP) != 0) {
+ if (!request_region(iop_base, ASC_IOADR_GAP, "advansys")){
ASC_DBG1(1,
"AscSearchIOPortAddr11: check_region() failed I/O port 0x%x\n",
iop_base);
continue;
}
ASC_DBG1(1, "AscSearchIOPortAddr11: probing I/O port 0x%x\n", iop_base);
+ release_region(iop_base, ASC_IOADR_GAP);
if (AscFindSignature(iop_base)) {
return (iop_base);
}
diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c
index 0cec742d12e..4b4d1233ce8 100644
--- a/drivers/scsi/aha152x.c
+++ b/drivers/scsi/aha152x.c
@@ -236,7 +236,6 @@
**************************************************************************/
#include <linux/module.h>
-#include <linux/sched.h>
#include <asm/irq.h>
#include <linux/io.h>
#include <linux/blkdev.h>
diff --git a/drivers/scsi/aic7xxx/aic79xx.h b/drivers/scsi/aic7xxx/aic79xx.h
index 170a4344cbb..27adbb294ac 100644
--- a/drivers/scsi/aic7xxx/aic79xx.h
+++ b/drivers/scsi/aic7xxx/aic79xx.h
@@ -1337,9 +1337,6 @@ int ahd_pci_test_register_access(struct ahd_softc *);
/************************** SCB and SCB queue management **********************/
void ahd_qinfifo_requeue_tail(struct ahd_softc *ahd,
struct scb *scb);
-int ahd_match_scb(struct ahd_softc *ahd, struct scb *scb,
- int target, char channel, int lun,
- u_int tag, role_t role);
/****************************** Initialization ********************************/
struct ahd_softc *ahd_alloc(void *platform_arg, char *name);
diff --git a/drivers/scsi/aic7xxx/aic79xx_core.c b/drivers/scsi/aic7xxx/aic79xx_core.c
index 07a86a30f67..9ddc6e4a74b 100644
--- a/drivers/scsi/aic7xxx/aic79xx_core.c
+++ b/drivers/scsi/aic7xxx/aic79xx_core.c
@@ -262,6 +262,9 @@ static void ahd_update_coalescing_values(struct ahd_softc *ahd,
u_int mincmds);
static int ahd_verify_vpd_cksum(struct vpd_config *vpd);
static int ahd_wait_seeprom(struct ahd_softc *ahd);
+static int ahd_match_scb(struct ahd_softc *ahd, struct scb *scb,
+ int target, char channel, int lun,
+ u_int tag, role_t role);
/******************************** Private Inlines *****************************/
@@ -7256,7 +7259,7 @@ ahd_busy_tcl(struct ahd_softc *ahd, u_int tcl, u_int scbid)
}
/************************** SCB and SCB queue management **********************/
-int
+static int
ahd_match_scb(struct ahd_softc *ahd, struct scb *scb, int target,
char channel, int lun, u_int tag, role_t role)
{
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c
index 9bfcca5ede0..2be03e975d9 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.c
@@ -418,7 +418,6 @@ ahd_linux_info(struct Scsi_Host *host)
strcat(bp, " ");
ahd_controller_info(ahd, ahd_info);
strcat(bp, ahd_info);
- strcat(bp, "\n");
return (bp);
}
@@ -1126,15 +1125,6 @@ ahd_linux_register_host(struct ahd_softc *ahd, struct scsi_host_template *templa
return 0;
}
-uint64_t
-ahd_linux_get_memsize(void)
-{
- struct sysinfo si;
-
- si_meminfo(&si);
- return ((uint64_t)si.totalram << PAGE_SHIFT);
-}
-
/*
* Place the SCSI bus into a known state by either resetting it,
* or forcing transfer negotiations on the next command to any
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.h b/drivers/scsi/aic7xxx/aic79xx_osm.h
index 3a67fc578d7..147c83c456a 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.h
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.h
@@ -496,8 +496,6 @@ ahd_insb(struct ahd_softc * ahd, long port, uint8_t *array, int count)
int ahd_linux_register_host(struct ahd_softc *,
struct scsi_host_template *);
-uint64_t ahd_linux_get_memsize(void);
-
/*************************** Pretty Printing **********************************/
struct info_str {
char *buffer;
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
index 1a3ab6aa856..c62ce41f279 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
@@ -132,6 +132,7 @@ ahd_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
struct ahd_pci_identity *entry;
char *name;
int error;
+ struct device *dev = &pdev->dev;
pci = pdev;
entry = ahd_find_pci_device(pci);
@@ -161,20 +162,18 @@ ahd_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
pci_set_master(pdev);
if (sizeof(dma_addr_t) > 4) {
- uint64_t memsize;
- const uint64_t mask_39bit = 0x7FFFFFFFFFULL;
+ const u64 required_mask = dma_get_required_mask(dev);
- memsize = ahd_linux_get_memsize();
-
- if (memsize >= 0x8000000000ULL
- && pci_set_dma_mask(pdev, DMA_64BIT_MASK) == 0) {
+ if (required_mask > DMA_39BIT_MASK &&
+ dma_set_mask(dev, DMA_64BIT_MASK) == 0)
ahd->flags |= AHD_64BIT_ADDRESSING;
- } else if (memsize > 0x80000000
- && pci_set_dma_mask(pdev, mask_39bit) == 0) {
+ else if (required_mask > DMA_32BIT_MASK &&
+ dma_set_mask(dev, DMA_39BIT_MASK) == 0)
ahd->flags |= AHD_39BIT_ADDRESSING;
- }
+ else
+ dma_set_mask(dev, DMA_32BIT_MASK);
} else {
- pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ dma_set_mask(dev, DMA_32BIT_MASK);
}
ahd->dev_softc = pci;
error = ahd_pci_config(ahd, entry);
diff --git a/drivers/scsi/aic7xxx/aic79xx_pci.c b/drivers/scsi/aic7xxx/aic79xx_pci.c
index 2cf7bb3123f..8d72bbae96a 100644
--- a/drivers/scsi/aic7xxx/aic79xx_pci.c
+++ b/drivers/scsi/aic7xxx/aic79xx_pci.c
@@ -88,7 +88,7 @@ ahd_compose_id(u_int device, u_int vendor, u_int subdevice, u_int subvendor)
#define SUBID_9005_LEGACYCONN_FUNC(id) ((id) & 0x20)
-#define SUBID_9005_SEEPTYPE(id) ((id) & 0x0C0) >> 6)
+#define SUBID_9005_SEEPTYPE(id) (((id) & 0x0C0) >> 6)
#define SUBID_9005_SEEPTYPE_NONE 0x0
#define SUBID_9005_SEEPTYPE_4K 0x1
diff --git a/drivers/scsi/aic7xxx_old.c b/drivers/scsi/aic7xxx_old.c
index 7d1fec62094..a988d5abf70 100644
--- a/drivers/scsi/aic7xxx_old.c
+++ b/drivers/scsi/aic7xxx_old.c
@@ -229,7 +229,6 @@
#include <linux/kernel.h>
#include <linux/ioport.h>
#include <linux/delay.h>
-#include <linux/sched.h>
#include <linux/pci.h>
#include <linux/proc_fs.h>
#include <linux/blkdev.h>
diff --git a/drivers/scsi/aic94xx/aic94xx_dev.c b/drivers/scsi/aic94xx/aic94xx_dev.c
index 6f8901b748f..c520e5b41fb 100644
--- a/drivers/scsi/aic94xx/aic94xx_dev.c
+++ b/drivers/scsi/aic94xx/aic94xx_dev.c
@@ -37,18 +37,14 @@
static inline int asd_get_ddb(struct asd_ha_struct *asd_ha)
{
- unsigned long flags;
int ddb, i;
- spin_lock_irqsave(&asd_ha->hw_prof.ddb_lock, flags);
ddb = FIND_FREE_DDB(asd_ha);
if (ddb >= asd_ha->hw_prof.max_ddbs) {
ddb = -ENOMEM;
- spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags);
goto out;
}
SET_DDB(ddb, asd_ha);
- spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags);
for (i = 0; i < sizeof(struct asd_ddb_ssp_smp_target_port); i+= 4)
asd_ddbsite_write_dword(asd_ha, ddb, i, 0);
@@ -77,14 +73,10 @@ out:
static inline void asd_free_ddb(struct asd_ha_struct *asd_ha, int ddb)
{
- unsigned long flags;
-
if (!ddb || ddb >= 0xFFFF)
return;
asd_ddbsite_write_byte(asd_ha, ddb, DDB_TYPE, DDB_TYPE_UNUSED);
- spin_lock_irqsave(&asd_ha->hw_prof.ddb_lock, flags);
CLEAR_DDB(ddb, asd_ha);
- spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags);
}
static inline void asd_set_ddb_type(struct domain_device *dev)
@@ -320,8 +312,11 @@ out:
int asd_dev_found(struct domain_device *dev)
{
+ unsigned long flags;
int res = 0;
+ struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
+ spin_lock_irqsave(&asd_ha->hw_prof.ddb_lock, flags);
switch (dev->dev_type) {
case SATA_PM:
res = asd_init_sata_pm_ddb(dev);
@@ -335,14 +330,18 @@ int asd_dev_found(struct domain_device *dev)
else
res = asd_init_initiator_ddb(dev);
}
+ spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags);
+
return res;
}
void asd_dev_gone(struct domain_device *dev)
{
int ddb, sister_ddb;
+ unsigned long flags;
struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
+ spin_lock_irqsave(&asd_ha->hw_prof.ddb_lock, flags);
ddb = (int) (unsigned long) dev->lldd_dev;
sister_ddb = asd_ddbsite_read_word(asd_ha, ddb, SISTER_DDB);
@@ -350,4 +349,5 @@ void asd_dev_gone(struct domain_device *dev)
asd_free_ddb(asd_ha, sister_ddb);
asd_free_ddb(asd_ha, ddb);
dev->lldd_dev = NULL;
+ spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags);
}
diff --git a/drivers/scsi/aic94xx/aic94xx_dump.c b/drivers/scsi/aic94xx/aic94xx_dump.c
index e6ade5996d9..6bd8e3059d2 100644
--- a/drivers/scsi/aic94xx/aic94xx_dump.c
+++ b/drivers/scsi/aic94xx/aic94xx_dump.c
@@ -556,7 +556,7 @@ static void asd_dump_lseq_state(struct asd_ha_struct *asd_ha, int lseq)
PRINT_LMIP_word(asd_ha, lseq, Q_TGTXFR_TAIL);
PRINT_LMIP_byte(asd_ha, lseq, LINK_NUMBER);
PRINT_LMIP_byte(asd_ha, lseq, SCRATCH_FLAGS);
- PRINT_LMIP_qword(asd_ha, lseq, CONNECTION_STATE);
+ PRINT_LMIP_dword(asd_ha, lseq, CONNECTION_STATE);
PRINT_LMIP_word(asd_ha, lseq, CONCTL);
PRINT_LMIP_byte(asd_ha, lseq, CONSTAT);
PRINT_LMIP_byte(asd_ha, lseq, CONNECTION_MODES);
diff --git a/drivers/scsi/aic94xx/aic94xx_hwi.c b/drivers/scsi/aic94xx/aic94xx_hwi.c
index da94e126ca8..0cd7eed9196 100644
--- a/drivers/scsi/aic94xx/aic94xx_hwi.c
+++ b/drivers/scsi/aic94xx/aic94xx_hwi.c
@@ -1052,10 +1052,9 @@ static inline struct asd_ascb *asd_ascb_alloc(struct asd_ha_struct *asd_ha,
struct asd_ascb *ascb;
unsigned long flags;
- ascb = kmem_cache_alloc(asd_ascb_cache, gfp_flags);
+ ascb = kmem_cache_zalloc(asd_ascb_cache, gfp_flags);
if (ascb) {
- memset(ascb, 0, sizeof(*ascb));
ascb->dma_scb.size = sizeof(struct scb);
ascb->dma_scb.vaddr = dma_pool_alloc(asd_ha->scb_pool,
gfp_flags,
diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c
index fbc82b00a41..27852b43b90 100644
--- a/drivers/scsi/aic94xx/aic94xx_init.c
+++ b/drivers/scsi/aic94xx/aic94xx_init.c
@@ -38,7 +38,7 @@
#include "aic94xx_seq.h"
/* The format is "version.release.patchlevel" */
-#define ASD_DRIVER_VERSION "1.0.2"
+#define ASD_DRIVER_VERSION "1.0.3"
static int use_msi = 0;
module_param_named(use_msi, use_msi, int, S_IRUGO);
@@ -57,6 +57,8 @@ MODULE_PARM_DESC(collector, "\n"
char sas_addr_str[2*SAS_ADDR_SIZE + 1] = "";
static struct scsi_transport_template *aic94xx_transport_template;
+static int asd_scan_finished(struct Scsi_Host *, unsigned long);
+static void asd_scan_start(struct Scsi_Host *);
static struct scsi_host_template aic94xx_sht = {
.module = THIS_MODULE,
@@ -66,6 +68,8 @@ static struct scsi_host_template aic94xx_sht = {
.target_alloc = sas_target_alloc,
.slave_configure = sas_slave_configure,
.slave_destroy = sas_slave_destroy,
+ .scan_finished = asd_scan_finished,
+ .scan_start = asd_scan_start,
.change_queue_depth = sas_change_queue_depth,
.change_queue_type = sas_change_queue_type,
.bios_param = sas_bios_param,
@@ -75,6 +79,8 @@ static struct scsi_host_template aic94xx_sht = {
.sg_tablesize = SG_ALL,
.max_sectors = SCSI_DEFAULT_MAX_SECTORS,
.use_clustering = ENABLE_CLUSTERING,
+ .eh_device_reset_handler = sas_eh_device_reset_handler,
+ .eh_bus_reset_handler = sas_eh_bus_reset_handler,
};
static int __devinit asd_map_memio(struct asd_ha_struct *asd_ha)
@@ -234,7 +240,7 @@ static int __devinit asd_common_setup(struct asd_ha_struct *asd_ha)
}
/* Provide some sane default values. */
asd_ha->hw_prof.max_scbs = 512;
- asd_ha->hw_prof.max_ddbs = 128;
+ asd_ha->hw_prof.max_ddbs = ASD_MAX_DDBS;
asd_ha->hw_prof.num_phys = ASD_MAX_PHYS;
/* All phys are enabled, by default. */
asd_ha->hw_prof.enabled_phys = 0xFF;
@@ -526,6 +532,7 @@ static int asd_register_sas_ha(struct asd_ha_struct *asd_ha)
asd_ha->sas_ha.num_phys= ASD_MAX_PHYS;
asd_ha->sas_ha.lldd_queue_size = asd_ha->seq.can_queue;
+ asd_ha->sas_ha.lldd_max_execute_num = lldd_max_execute_num;
return sas_register_ha(&asd_ha->sas_ha);
}
@@ -646,7 +653,7 @@ static int __devinit asd_pci_probe(struct pci_dev *dev,
if (use_msi)
pci_enable_msi(asd_ha->pcidev);
- err = request_irq(asd_ha->pcidev->irq, asd_hw_isr, SA_SHIRQ,
+ err = request_irq(asd_ha->pcidev->irq, asd_hw_isr, IRQF_SHARED,
ASD_DRIVER_NAME, asd_ha);
if (err) {
asd_printk("couldn't get irq %d for %s\n",
@@ -671,21 +678,10 @@ static int __devinit asd_pci_probe(struct pci_dev *dev,
if (err)
goto Err_reg_sas;
- err = asd_enable_phys(asd_ha, asd_ha->hw_prof.enabled_phys);
- if (err) {
- asd_printk("coudln't enable phys, err:%d\n", err);
- goto Err_en_phys;
- }
- ASD_DPRINTK("enabled phys\n");
- /* give the phy enabling interrupt event time to come in (1s
- * is empirically about all it takes) */
- ssleep(1);
- /* Wait for discovery to finish */
- scsi_flush_work(asd_ha->sas_ha.core.shost);
+ scsi_scan_host(shost);
return 0;
-Err_en_phys:
- asd_unregister_sas_ha(asd_ha);
+
Err_reg_sas:
asd_remove_dev_attrs(asd_ha);
Err_dev_attrs:
@@ -778,6 +774,28 @@ static void __devexit asd_pci_remove(struct pci_dev *dev)
return;
}
+static void asd_scan_start(struct Scsi_Host *shost)
+{
+ struct asd_ha_struct *asd_ha;
+ int err;
+
+ asd_ha = SHOST_TO_SAS_HA(shost)->lldd_ha;
+ err = asd_enable_phys(asd_ha, asd_ha->hw_prof.enabled_phys);
+ if (err)
+ asd_printk("Couldn't enable phys, err:%d\n", err);
+}
+
+static int asd_scan_finished(struct Scsi_Host *shost, unsigned long time)
+{
+ /* give the phy enabling interrupt event time to come in (1s
+ * is empirically about all it takes) */
+ if (time < HZ)
+ return 0;
+ /* Wait for discovery to finish */
+ scsi_flush_work(shost);
+ return 1;
+}
+
static ssize_t asd_version_show(struct device_driver *driver, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%s\n", ASD_DRIVER_VERSION);
@@ -885,6 +903,7 @@ static void __exit aic94xx_exit(void)
asd_remove_driver_attrs(&aic94xx_pci_driver.driver);
pci_unregister_driver(&aic94xx_pci_driver);
sas_release_transport(aic94xx_transport_template);
+ asd_release_firmware();
asd_destroy_global_caches();
asd_printk("%s version %s unloaded\n", ASD_DRIVER_DESCRIPTION,
ASD_DRIVER_VERSION);
diff --git a/drivers/scsi/aic94xx/aic94xx_reg_def.h b/drivers/scsi/aic94xx/aic94xx_reg_def.h
index a11f4e6d8bd..a43e8cdf4ee 100644
--- a/drivers/scsi/aic94xx/aic94xx_reg_def.h
+++ b/drivers/scsi/aic94xx/aic94xx_reg_def.h
@@ -2226,9 +2226,10 @@
#define LmSEQ_SAS_RESET_MODE(LinkNum) (LmSCRATCH(LinkNum) + 0x0074)
#define LmSEQ_LINK_RESET_RETRY_COUNT(LinkNum) (LmSCRATCH(LinkNum) + 0x0075)
#define LmSEQ_NUM_LINK_RESET_RETRIES(LinkNum) (LmSCRATCH(LinkNum) + 0x0076)
-#define LmSEQ_OOB_INT_ENABLES(LinkNum) (LmSCRATCH(LinkNum) + 0x007A)
+#define LmSEQ_OOB_INT_ENABLES(LinkNum) (LmSCRATCH(LinkNum) + 0x0078)
+#define LmSEQ_NOTIFY_TIMER_DOWN_COUNT(LinkNum) (LmSCRATCH(LinkNum) + 0x007A)
#define LmSEQ_NOTIFY_TIMER_TIMEOUT(LinkNum) (LmSCRATCH(LinkNum) + 0x007C)
-#define LmSEQ_NOTIFY_TIMER_DOWN_COUNT(LinkNum) (LmSCRATCH(LinkNum) + 0x007E)
+#define LmSEQ_NOTIFY_TIMER_INITIAL_COUNT(LinkNum) (LmSCRATCH(LinkNum) + 0x007E)
/* Mode dependent scratch page 1, mode 0 and mode 1 */
#define LmSEQ_SG_LIST_PTR_ADDR0(LinkNum) (LmSCRATCH(LinkNum) + 0x0020)
diff --git a/drivers/scsi/aic94xx/aic94xx_sas.h b/drivers/scsi/aic94xx/aic94xx_sas.h
index 9050e93bfd5..fa7c5290257 100644
--- a/drivers/scsi/aic94xx/aic94xx_sas.h
+++ b/drivers/scsi/aic94xx/aic94xx_sas.h
@@ -34,6 +34,7 @@
* domain that this sequencer can maintain low-level connections for
* us. They are be 64 bytes.
*/
+#define ASD_MAX_DDBS 128
struct asd_ddb_ssp_smp_target_port {
u8 conn_type; /* byte 0 */
diff --git a/drivers/scsi/aic94xx/aic94xx_scb.c b/drivers/scsi/aic94xx/aic94xx_scb.c
index 75ed6b0569d..8f43ff772f2 100644
--- a/drivers/scsi/aic94xx/aic94xx_scb.c
+++ b/drivers/scsi/aic94xx/aic94xx_scb.c
@@ -413,40 +413,6 @@ void asd_invalidate_edb(struct asd_ascb *ascb, int edb_id)
}
}
-/* hard reset a phy later */
-static void do_phy_reset_later(struct work_struct *work)
-{
- struct sas_phy *sas_phy =
- container_of(work, struct sas_phy, reset_work);
- int error;
-
- ASD_DPRINTK("%s: About to hard reset phy %d\n", __FUNCTION__,
- sas_phy->identify.phy_identifier);
- /* Reset device port */
- error = sas_phy_reset(sas_phy, 1);
- if (error)
- ASD_DPRINTK("%s: Hard reset of phy %d failed (%d).\n",
- __FUNCTION__, sas_phy->identify.phy_identifier, error);
-}
-
-static void phy_reset_later(struct sas_phy *sas_phy, struct Scsi_Host *shost)
-{
- INIT_WORK(&sas_phy->reset_work, do_phy_reset_later);
- queue_work(shost->work_q, &sas_phy->reset_work);
-}
-
-/* start up the ABORT TASK tmf... */
-static void task_kill_later(struct asd_ascb *ascb)
-{
- struct asd_ha_struct *asd_ha = ascb->ha;
- struct sas_ha_struct *sas_ha = &asd_ha->sas_ha;
- struct Scsi_Host *shost = sas_ha->core.shost;
- struct sas_task *task = ascb->uldd_task;
-
- INIT_WORK(&task->abort_work, sas_task_abort);
- queue_work(shost->work_q, &task->abort_work);
-}
-
static void escb_tasklet_complete(struct asd_ascb *ascb,
struct done_list_struct *dl)
{
@@ -479,26 +445,55 @@ static void escb_tasklet_complete(struct asd_ascb *ascb,
case REQ_TASK_ABORT: {
struct asd_ascb *a, *b;
u16 tc_abort;
+ struct domain_device *failed_dev = NULL;
+
+ ASD_DPRINTK("%s: REQ_TASK_ABORT, reason=0x%X\n",
+ __FUNCTION__, dl->status_block[3]);
+ /*
+ * Find the task that caused the abort and abort it first.
+ * The sequencer won't put anything on the done list until
+ * that happens.
+ */
tc_abort = *((u16*)(&dl->status_block[1]));
tc_abort = le16_to_cpu(tc_abort);
- ASD_DPRINTK("%s: REQ_TASK_ABORT, reason=0x%X\n",
- __FUNCTION__, dl->status_block[3]);
+ list_for_each_entry_safe(a, b, &asd_ha->seq.pend_q, list) {
+ struct sas_task *task = ascb->uldd_task;
- /* Find the pending task and abort it. */
- list_for_each_entry_safe(a, b, &asd_ha->seq.pend_q, list)
- if (a->tc_index == tc_abort) {
- task_kill_later(a);
+ if (task && a->tc_index == tc_abort) {
+ failed_dev = task->dev;
+ sas_task_abort(task);
break;
}
+ }
+
+ if (!failed_dev) {
+ ASD_DPRINTK("%s: Can't find task (tc=%d) to abort!\n",
+ __FUNCTION__, tc_abort);
+ goto out;
+ }
+
+ /*
+ * Now abort everything else for that device (hba?) so
+ * that the EH will wake up and do something.
+ */
+ list_for_each_entry_safe(a, b, &asd_ha->seq.pend_q, list) {
+ struct sas_task *task = ascb->uldd_task;
+
+ if (task &&
+ task->dev == failed_dev &&
+ a->tc_index != tc_abort)
+ sas_task_abort(task);
+ }
+
goto out;
}
case REQ_DEVICE_RESET: {
- struct Scsi_Host *shost = sas_ha->core.shost;
- struct sas_phy *dev_phy;
struct asd_ascb *a;
u16 conn_handle;
+ unsigned long flags;
+ struct sas_task *last_dev_task = NULL;
conn_handle = *((u16*)(&dl->status_block[1]));
conn_handle = le16_to_cpu(conn_handle);
@@ -506,32 +501,47 @@ static void escb_tasklet_complete(struct asd_ascb *ascb,
ASD_DPRINTK("%s: REQ_DEVICE_RESET, reason=0x%X\n", __FUNCTION__,
dl->status_block[3]);
- /* Kill all pending tasks and reset the device */
- dev_phy = NULL;
+ /* Find the last pending task for the device... */
list_for_each_entry(a, &asd_ha->seq.pend_q, list) {
- struct sas_task *task;
- struct domain_device *dev;
u16 x;
+ struct domain_device *dev;
+ struct sas_task *task = a->uldd_task;
- task = a->uldd_task;
if (!task)
continue;
dev = task->dev;
x = (unsigned long)dev->lldd_dev;
- if (x == conn_handle) {
- dev_phy = dev->port->phy;
- task_kill_later(a);
- }
+ if (x == conn_handle)
+ last_dev_task = task;
}
- /* Reset device port */
- if (!dev_phy) {
- ASD_DPRINTK("%s: No pending commands; can't reset.\n",
- __FUNCTION__);
+ if (!last_dev_task) {
+ ASD_DPRINTK("%s: Device reset for idle device %d?\n",
+ __FUNCTION__, conn_handle);
goto out;
}
- phy_reset_later(dev_phy, shost);
+
+ /* ...and set the reset flag */
+ spin_lock_irqsave(&last_dev_task->task_state_lock, flags);
+ last_dev_task->task_state_flags |= SAS_TASK_NEED_DEV_RESET;
+ spin_unlock_irqrestore(&last_dev_task->task_state_lock, flags);
+
+ /* Kill all pending tasks for the device */
+ list_for_each_entry(a, &asd_ha->seq.pend_q, list) {
+ u16 x;
+ struct domain_device *dev;
+ struct sas_task *task = a->uldd_task;
+
+ if (!task)
+ continue;
+ dev = task->dev;
+
+ x = (unsigned long)dev->lldd_dev;
+ if (x == conn_handle)
+ sas_task_abort(task);
+ }
+
goto out;
}
case SIGNAL_NCQ_ERROR:
diff --git a/drivers/scsi/aic94xx/aic94xx_sds.c b/drivers/scsi/aic94xx/aic94xx_sds.c
index e5a0ec37e95..5b0932f6147 100644
--- a/drivers/scsi/aic94xx/aic94xx_sds.c
+++ b/drivers/scsi/aic94xx/aic94xx_sds.c
@@ -427,7 +427,7 @@ struct asd_manuf_sec {
struct asd_manuf_phy_desc {
u8 state; /* low 4 bits */
-#define MS_PHY_STATE_ENABLEABLE 0
+#define MS_PHY_STATE_ENABLED 0
#define MS_PHY_STATE_REPORTED 1
#define MS_PHY_STATE_HIDDEN 2
u8 phy_id;
@@ -756,11 +756,11 @@ static void *asd_find_ll_by_id(void * const start, const u8 id0, const u8 id1)
*
* HIDDEN phys do not count in the total count. REPORTED phys cannot
* be enabled but are reported and counted towards the total.
- * ENEBLEABLE phys are enabled by default and count towards the total.
+ * ENABLED phys are enabled by default and count towards the total.
* The absolute total phy number is ASD_MAX_PHYS. hw_prof->num_phys
* merely specifies the number of phys the host adapter decided to
* report. E.g., it is possible for phys 0, 1 and 2 to be HIDDEN,
- * phys 3, 4 and 5 to be REPORTED and phys 6 and 7 to be ENEBLEABLE.
+ * phys 3, 4 and 5 to be REPORTED and phys 6 and 7 to be ENABLED.
* In this case ASD_MAX_PHYS is 8, hw_prof->num_phys is 5, and only 2
* are actually enabled (enabled by default, max number of phys
* enableable in this case).
@@ -816,8 +816,8 @@ static int asd_ms_get_phy_params(struct asd_ha_struct *asd_ha,
asd_ha->hw_prof.enabled_phys &= ~(1 << i);
rep_phys++;
continue;
- case MS_PHY_STATE_ENABLEABLE:
- ASD_DPRINTK("ms: phy%d: ENEBLEABLE\n", i);
+ case MS_PHY_STATE_ENABLED:
+ ASD_DPRINTK("ms: phy%d: ENABLED\n", i);
asd_ha->hw_prof.enabled_phys |= (1 << i);
en_phys++;
break;
diff --git a/drivers/scsi/aic94xx/aic94xx_seq.c b/drivers/scsi/aic94xx/aic94xx_seq.c
index 845112539d0..c750fbf7013 100644
--- a/drivers/scsi/aic94xx/aic94xx_seq.c
+++ b/drivers/scsi/aic94xx/aic94xx_seq.c
@@ -44,7 +44,6 @@
#define PAUSE_TRIES 1000
static const struct firmware *sequencer_fw;
-static const char *sequencer_version;
static u16 cseq_vecs[CSEQ_NUM_VECS], lseq_vecs[LSEQ_NUM_VECS], mode2_task,
cseq_idle_loop, lseq_idle_loop;
static u8 *cseq_code, *lseq_code;
@@ -810,6 +809,8 @@ static void asd_init_lseq_mdp(struct asd_ha_struct *asd_ha, int lseq)
/* No delay for the first NOTIFY to be sent to the attached target. */
asd_write_reg_word(asd_ha, LmSEQ_NOTIFY_TIMER_DOWN_COUNT(lseq),
ASD_NOTIFY_DOWN_COUNT);
+ asd_write_reg_word(asd_ha, LmSEQ_NOTIFY_TIMER_INITIAL_COUNT(lseq),
+ ASD_NOTIFY_DOWN_COUNT);
/* LSEQ Mode dependent, mode 0 and 1, page 1 setup. */
for (i = 0; i < 2; i++) {
@@ -907,6 +908,16 @@ static void asd_init_scb_sites(struct asd_ha_struct *asd_ha)
for (i = 0; i < ASD_SCB_SIZE; i += 4)
asd_scbsite_write_dword(asd_ha, site_no, i, 0);
+ /* Initialize SCB Site Opcode field to invalid. */
+ asd_scbsite_write_byte(asd_ha, site_no,
+ offsetof(struct scb_header, opcode),
+ 0xFF);
+
+ /* Initialize SCB Site Flags field to mean a response
+ * frame has been received. This means inadvertent
+ * frames received to be dropped. */
+ asd_scbsite_write_byte(asd_ha, site_no, 0x49, 0x01);
+
/* Workaround needed by SEQ to fix a SATA issue is to exclude
* certain SCB sites from the free list. */
if (!SCB_SITE_VALID(site_no))
@@ -922,16 +933,6 @@ static void asd_init_scb_sites(struct asd_ha_struct *asd_ha)
/* Q_NEXT field of the last SCB is invalidated. */
asd_scbsite_write_word(asd_ha, site_no, 0, first_scb_site_no);
- /* Initialize SCB Site Opcode field to invalid. */
- asd_scbsite_write_byte(asd_ha, site_no,
- offsetof(struct scb_header, opcode),
- 0xFF);
-
- /* Initialize SCB Site Flags field to mean a response
- * frame has been received. This means inadvertent
- * frames received to be dropped. */
- asd_scbsite_write_byte(asd_ha, site_no, 0x49, 0x01);
-
first_scb_site_no = site_no;
max_scbs++;
}
@@ -1173,6 +1174,16 @@ static void asd_init_ddb_0(struct asd_ha_struct *asd_ha)
set_bit(0, asd_ha->hw_prof.ddb_bitmap);
}
+static void asd_seq_init_ddb_sites(struct asd_ha_struct *asd_ha)
+{
+ unsigned int i;
+ unsigned int ddb_site;
+
+ for (ddb_site = 0 ; ddb_site < ASD_MAX_DDBS; ddb_site++)
+ for (i = 0; i < sizeof(struct asd_ddb_ssp_smp_target_port); i+= 4)
+ asd_ddbsite_write_dword(asd_ha, ddb_site, i, 0);
+}
+
/**
* asd_seq_setup_seqs -- setup and initialize central and link sequencers
* @asd_ha: pointer to host adapter structure
@@ -1182,6 +1193,9 @@ static void asd_seq_setup_seqs(struct asd_ha_struct *asd_ha)
int lseq;
u8 lseq_mask;
+ /* Initialize DDB sites */
+ asd_seq_init_ddb_sites(asd_ha);
+
/* Initialize SCB sites. Done first to compute some values which
* the rest of the init code depends on. */
asd_init_scb_sites(asd_ha);
@@ -1232,6 +1246,13 @@ static int asd_seq_start_lseq(struct asd_ha_struct *asd_ha, int lseq)
return asd_seq_unpause_lseq(asd_ha, lseq);
}
+int asd_release_firmware(void)
+{
+ if (sequencer_fw)
+ release_firmware(sequencer_fw);
+ return 0;
+}
+
static int asd_request_firmware(struct asd_ha_struct *asd_ha)
{
int err, i;
@@ -1254,7 +1275,6 @@ static int asd_request_firmware(struct asd_ha_struct *asd_ha)
header.csum = le32_to_cpu(hdr_ptr->csum);
header.major = le32_to_cpu(hdr_ptr->major);
header.minor = le32_to_cpu(hdr_ptr->minor);
- sequencer_version = hdr_ptr->version;
header.cseq_table_offset = le32_to_cpu(hdr_ptr->cseq_table_offset);
header.cseq_table_size = le32_to_cpu(hdr_ptr->cseq_table_size);
header.lseq_table_offset = le32_to_cpu(hdr_ptr->lseq_table_offset);
@@ -1281,6 +1301,16 @@ static int asd_request_firmware(struct asd_ha_struct *asd_ha)
return -EINVAL;
}
+ asd_printk("Found sequencer Firmware version %d.%d (%s)\n",
+ header.major, header.minor, hdr_ptr->version);
+
+ if (header.major != SAS_RAZOR_SEQUENCER_FW_MAJOR) {
+ asd_printk("Firmware Major Version Mismatch;"
+ "driver requires version %d.X",
+ SAS_RAZOR_SEQUENCER_FW_MAJOR);
+ return -EINVAL;
+ }
+
ptr_cseq_vecs = (u16 *)&sequencer_fw->data[header.cseq_table_offset];
ptr_lseq_vecs = (u16 *)&sequencer_fw->data[header.lseq_table_offset];
mode2_task = header.mode2_task;
@@ -1313,7 +1343,6 @@ int asd_init_seqs(struct asd_ha_struct *asd_ha)
return err;
}
- asd_printk("using sequencer %s\n", sequencer_version);
err = asd_seq_download_seqs(asd_ha);
if (err) {
asd_printk("couldn't download sequencers for %s\n",
@@ -1375,7 +1404,9 @@ void asd_update_port_links(struct asd_ha_struct *asd_ha, struct asd_phy *phy)
u8 phy_is_up;
u8 mask;
int i, err;
+ unsigned long flags;
+ spin_lock_irqsave(&asd_ha->hw_prof.ddb_lock, flags);
for_each_phy(phy_mask, mask, i)
asd_ddbsite_write_byte(asd_ha, 0,
offsetof(struct asd_ddb_seq_shared,
@@ -1395,6 +1426,7 @@ void asd_update_port_links(struct asd_ha_struct *asd_ha, struct asd_phy *phy)
break;
}
}
+ spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags);
if (err)
asd_printk("couldn't update DDB 0:error:%d\n", err);
diff --git a/drivers/scsi/aic94xx/aic94xx_seq.h b/drivers/scsi/aic94xx/aic94xx_seq.h
index 9e715e5496a..2ea6a0d5220 100644
--- a/drivers/scsi/aic94xx/aic94xx_seq.h
+++ b/drivers/scsi/aic94xx/aic94xx_seq.h
@@ -31,6 +31,7 @@
#define LSEQ_NUM_VECS 11
#define SAS_RAZOR_SEQUENCER_FW_FILE "aic94xx-seq.fw"
+#define SAS_RAZOR_SEQUENCER_FW_MAJOR 1
/* Note: All quantites in the sequencer file are little endian */
struct sequencer_file_header {
@@ -63,6 +64,7 @@ int asd_pause_lseq(struct asd_ha_struct *asd_ha, u8 lseq_mask);
int asd_unpause_lseq(struct asd_ha_struct *asd_ha, u8 lseq_mask);
int asd_init_seqs(struct asd_ha_struct *asd_ha);
int asd_start_seqs(struct asd_ha_struct *asd_ha);
+int asd_release_firmware(void);
void asd_update_port_links(struct asd_ha_struct *asd_ha, struct asd_phy *phy);
#endif
diff --git a/drivers/scsi/aic94xx/aic94xx_task.c b/drivers/scsi/aic94xx/aic94xx_task.c
index d202ed5a670..e2ad5bed940 100644
--- a/drivers/scsi/aic94xx/aic94xx_task.c
+++ b/drivers/scsi/aic94xx/aic94xx_task.c
@@ -349,6 +349,7 @@ Again:
spin_lock_irqsave(&task->task_state_lock, flags);
task->task_state_flags &= ~SAS_TASK_STATE_PENDING;
+ task->task_state_flags &= ~SAS_TASK_AT_INITIATOR;
task->task_state_flags |= SAS_TASK_STATE_DONE;
if (unlikely((task->task_state_flags & SAS_TASK_STATE_ABORTED))) {
spin_unlock_irqrestore(&task->task_state_lock, flags);
@@ -557,6 +558,7 @@ int asd_execute_task(struct sas_task *task, const int num,
struct sas_task *t = task;
struct asd_ascb *ascb = NULL, *a;
struct asd_ha_struct *asd_ha = task->dev->port->ha->lldd_ha;
+ unsigned long flags;
res = asd_can_queue(asd_ha, num);
if (res)
@@ -599,6 +601,10 @@ int asd_execute_task(struct sas_task *task, const int num,
}
if (res)
goto out_err_unmap;
+
+ spin_lock_irqsave(&t->task_state_lock, flags);
+ t->task_state_flags |= SAS_TASK_AT_INITIATOR;
+ spin_unlock_irqrestore(&t->task_state_lock, flags);
}
list_del_init(&alist);
@@ -617,6 +623,9 @@ out_err_unmap:
if (a == b)
break;
t = a->uldd_task;
+ spin_lock_irqsave(&t->task_state_lock, flags);
+ t->task_state_flags &= ~SAS_TASK_AT_INITIATOR;
+ spin_unlock_irqrestore(&t->task_state_lock, flags);
switch (t->task_proto) {
case SATA_PROTO:
case SAS_PROTO_STP:
diff --git a/drivers/scsi/aic94xx/aic94xx_tmf.c b/drivers/scsi/aic94xx/aic94xx_tmf.c
index 61234384503..9a14a6d9727 100644
--- a/drivers/scsi/aic94xx/aic94xx_tmf.c
+++ b/drivers/scsi/aic94xx/aic94xx_tmf.c
@@ -566,9 +566,7 @@ static int asd_initiate_ssp_tmf(struct domain_device *dev, u8 *lun,
res = TMF_RESP_FUNC_ESUPP;
break;
default:
- ASD_DPRINTK("%s: converting result 0x%x to TMF_RESP_FUNC_FAILED\n",
- __FUNCTION__, res);
- res = TMF_RESP_FUNC_FAILED;
+ /* Allow TMF response codes to propagate upwards */
break;
}
out_err:
diff --git a/drivers/scsi/amiga7xx.c b/drivers/scsi/amiga7xx.c
index 9099d531d5a..d5d3c4d5a25 100644
--- a/drivers/scsi/amiga7xx.c
+++ b/drivers/scsi/amiga7xx.c
@@ -10,7 +10,6 @@
#include <linux/types.h>
#include <linux/mm.h>
#include <linux/blkdev.h>
-#include <linux/sched.h>
#include <linux/zorro.h>
#include <linux/stat.h>
diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c
index 086cc97eee8..8b46158cc04 100644
--- a/drivers/scsi/arcmsr/arcmsr_hba.c
+++ b/drivers/scsi/arcmsr/arcmsr_hba.c
@@ -322,7 +322,7 @@ static int arcmsr_probe(struct pci_dev *pdev,
goto out_iounmap;
error = request_irq(pdev->irq, arcmsr_do_interrupt,
- SA_INTERRUPT | SA_SHIRQ, "arcmsr", acb);
+ IRQF_DISABLED | IRQF_SHARED, "arcmsr", acb);
if (error)
goto out_free_ccb_pool;
diff --git a/drivers/scsi/arm/acornscsi.c b/drivers/scsi/arm/acornscsi.c
index 9cf902b7a12..eceacf6d49e 100644
--- a/drivers/scsi/arm/acornscsi.c
+++ b/drivers/scsi/arm/acornscsi.c
@@ -131,7 +131,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/string.h>
#include <linux/signal.h>
#include <linux/errno.h>
diff --git a/drivers/scsi/arm/arxescsi.c b/drivers/scsi/arm/arxescsi.c
index 4385e9e3ded..7e132c5bacf 100644
--- a/drivers/scsi/arm/arxescsi.c
+++ b/drivers/scsi/arm/arxescsi.c
@@ -23,7 +23,6 @@
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/ioport.h>
-#include <linux/sched.h>
#include <linux/proc_fs.h>
#include <linux/unistd.h>
#include <linux/stat.h>
diff --git a/drivers/scsi/arm/cumana_1.c b/drivers/scsi/arm/cumana_1.c
index 3bdfc36481a..cf9a21cea6d 100644
--- a/drivers/scsi/arm/cumana_1.c
+++ b/drivers/scsi/arm/cumana_1.c
@@ -5,7 +5,6 @@
*/
#include <linux/module.h>
#include <linux/signal.h>
-#include <linux/sched.h>
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/blkdev.h>
diff --git a/drivers/scsi/arm/cumana_2.c b/drivers/scsi/arm/cumana_2.c
index 19edd9c853d..d2d51dc51ab 100644
--- a/drivers/scsi/arm/cumana_2.c
+++ b/drivers/scsi/arm/cumana_2.c
@@ -21,7 +21,6 @@
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/ioport.h>
-#include <linux/sched.h>
#include <linux/proc_fs.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
diff --git a/drivers/scsi/arm/ecoscsi.c b/drivers/scsi/arm/ecoscsi.c
index 6adcccbf444..378e7af0c5d 100644
--- a/drivers/scsi/arm/ecoscsi.c
+++ b/drivers/scsi/arm/ecoscsi.c
@@ -23,7 +23,6 @@
#include <linux/module.h>
#include <linux/signal.h>
-#include <linux/sched.h>
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/init.h>
diff --git a/drivers/scsi/arm/eesox.c b/drivers/scsi/arm/eesox.c
index 3f876fb7546..d4136524fc4 100644
--- a/drivers/scsi/arm/eesox.c
+++ b/drivers/scsi/arm/eesox.c
@@ -27,7 +27,6 @@
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/ioport.h>
-#include <linux/sched.h>
#include <linux/proc_fs.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
@@ -197,7 +196,7 @@ static void eesoxscsi_buffer_in(void *buf, int length, void __iomem *base)
const void __iomem *reg_fas = base + EESOX_FAS216_OFFSET;
const void __iomem *reg_dmastat = base + EESOX_DMASTAT;
const void __iomem *reg_dmadata = base + EESOX_DMADATA;
- const register unsigned long mask = 0xffff;
+ register const unsigned long mask = 0xffff;
do {
unsigned int status;
diff --git a/drivers/scsi/arm/fas216.c b/drivers/scsi/arm/fas216.c
index e05f0c2fc91..2969cc0ff25 100644
--- a/drivers/scsi/arm/fas216.c
+++ b/drivers/scsi/arm/fas216.c
@@ -39,7 +39,6 @@
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/ioport.h>
-#include <linux/sched.h>
#include <linux/proc_fs.h>
#include <linux/delay.h>
#include <linux/bitops.h>
diff --git a/drivers/scsi/arm/oak.c b/drivers/scsi/arm/oak.c
index d806b024c3b..c21b8392c92 100644
--- a/drivers/scsi/arm/oak.c
+++ b/drivers/scsi/arm/oak.c
@@ -6,7 +6,6 @@
#include <linux/module.h>
#include <linux/signal.h>
-#include <linux/sched.h>
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/blkdev.h>
diff --git a/drivers/scsi/arm/powertec.c b/drivers/scsi/arm/powertec.c
index ce159c15bc8..f9cd20bfb95 100644
--- a/drivers/scsi/arm/powertec.c
+++ b/drivers/scsi/arm/powertec.c
@@ -12,7 +12,6 @@
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/ioport.h>
-#include <linux/sched.h>
#include <linux/proc_fs.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c
index dfb1bcfae82..642de7b2b7a 100644
--- a/drivers/scsi/atari_scsi.c
+++ b/drivers/scsi/atari_scsi.c
@@ -86,7 +86,6 @@
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/blkdev.h>
-#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/nvram.h>
diff --git a/drivers/scsi/blz1230.c b/drivers/scsi/blz1230.c
index 329a8f297b3..23f7c24ab80 100644
--- a/drivers/scsi/blz1230.c
+++ b/drivers/scsi/blz1230.c
@@ -121,7 +121,8 @@ int __init blz1230_esp_detect(struct scsi_host_template *tpnt)
*/
address = ZTWO_VADDR(board);
eregs = (struct ESP_regs *)(address + REAL_BLZ1230_ESP_ADDR);
- esp = esp_allocate(tpnt, (void *)board+REAL_BLZ1230_ESP_ADDR);
+ esp = esp_allocate(tpnt, (void *)board + REAL_BLZ1230_ESP_ADDR,
+ 0);
esp_write(eregs->esp_cfg1, (ESP_CONFIG1_PENABLE | 7));
udelay(5);
diff --git a/drivers/scsi/blz2060.c b/drivers/scsi/blz2060.c
index b6c137b9735..b6203ec0096 100644
--- a/drivers/scsi/blz2060.c
+++ b/drivers/scsi/blz2060.c
@@ -100,7 +100,7 @@ int __init blz2060_esp_detect(struct scsi_host_template *tpnt)
unsigned long board = z->resource.start;
if (request_mem_region(board+BLZ2060_ESP_ADDR,
sizeof(struct ESP_regs), "NCR53C9x")) {
- esp = esp_allocate(tpnt, (void *)board+BLZ2060_ESP_ADDR);
+ esp = esp_allocate(tpnt, (void *)board + BLZ2060_ESP_ADDR, 0);
/* Do command transfer with programmed I/O */
esp->do_pio_cmds = 1;
diff --git a/drivers/scsi/bvme6000.c b/drivers/scsi/bvme6000.c
index 2958b8c2bfb..599b400a3c4 100644
--- a/drivers/scsi/bvme6000.c
+++ b/drivers/scsi/bvme6000.c
@@ -6,7 +6,6 @@
#include <linux/types.h>
#include <linux/mm.h>
#include <linux/blkdev.h>
-#include <linux/sched.h>
#include <linux/zorro.h>
#include <asm/setup.h>
diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c
index f6caa430776..2a2cc6cf118 100644
--- a/drivers/scsi/ch.c
+++ b/drivers/scsi/ch.c
@@ -11,7 +11,6 @@
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/major.h>
#include <linux/string.h>
@@ -129,7 +128,7 @@ static struct scsi_driver ch_template =
},
};
-static struct file_operations changer_fops =
+static const struct file_operations changer_fops =
{
.owner = THIS_MODULE,
.open = ch_open,
diff --git a/drivers/scsi/cyberstorm.c b/drivers/scsi/cyberstorm.c
index 7c7cfb54e89..c6b98a42e89 100644
--- a/drivers/scsi/cyberstorm.c
+++ b/drivers/scsi/cyberstorm.c
@@ -126,7 +126,7 @@ int __init cyber_esp_detect(struct scsi_host_template *tpnt)
sizeof(struct ESP_regs));
return 0;
}
- esp = esp_allocate(tpnt, (void *)board+CYBER_ESP_ADDR);
+ esp = esp_allocate(tpnt, (void *)board + CYBER_ESP_ADDR, 0);
/* Do command transfer with programmed I/O */
esp->do_pio_cmds = 1;
diff --git a/drivers/scsi/cyberstormII.c b/drivers/scsi/cyberstormII.c
index d88cb9cf091..e336e853e66 100644
--- a/drivers/scsi/cyberstormII.c
+++ b/drivers/scsi/cyberstormII.c
@@ -98,7 +98,7 @@ int __init cyberII_esp_detect(struct scsi_host_template *tpnt)
address = (unsigned long)ZTWO_VADDR(board);
eregs = (struct ESP_regs *)(address + CYBERII_ESP_ADDR);
- esp = esp_allocate(tpnt, (void *)board+CYBERII_ESP_ADDR);
+ esp = esp_allocate(tpnt, (void *)board + CYBERII_ESP_ADDR, 0);
esp_write(eregs->esp_cfg1, (ESP_CONFIG1_PENABLE | 7));
udelay(5);
diff --git a/drivers/scsi/dec_esp.c b/drivers/scsi/dec_esp.c
index c29ccbc4469..d42ad663ffe 100644
--- a/drivers/scsi/dec_esp.c
+++ b/drivers/scsi/dec_esp.c
@@ -18,7 +18,7 @@
* 20001005 - Initialization fixes for 2.4.0-test9
* Florian Lohoff <flo@rfc822.org>
*
- * Copyright (C) 2002, 2003, 2005 Maciej W. Rozycki
+ * Copyright (C) 2002, 2003, 2005, 2006 Maciej W. Rozycki
*/
#include <linux/kernel.h>
@@ -30,6 +30,7 @@
#include <linux/proc_fs.h>
#include <linux/spinlock.h>
#include <linux/stat.h>
+#include <linux/tc.h>
#include <asm/dma.h>
#include <asm/irq.h>
@@ -42,7 +43,6 @@
#include <asm/dec/ioasic_ints.h>
#include <asm/dec/machtype.h>
#include <asm/dec/system.h>
-#include <asm/dec/tc.h>
#define DEC_SCSI_SREG 0
#define DEC_SCSI_DMAREG 0x40000
@@ -98,51 +98,33 @@ static irqreturn_t scsi_dma_merr_int(int, void *);
static irqreturn_t scsi_dma_err_int(int, void *);
static irqreturn_t scsi_dma_int(int, void *);
-static int dec_esp_detect(struct scsi_host_template * tpnt);
-
-static int dec_esp_release(struct Scsi_Host *shost)
-{
- if (shost->irq)
- free_irq(shost->irq, NULL);
- if (shost->io_port && shost->n_io_port)
- release_region(shost->io_port, shost->n_io_port);
- scsi_unregister(shost);
- return 0;
-}
-
-static struct scsi_host_template driver_template = {
- .proc_name = "dec_esp",
- .proc_info = esp_proc_info,
+static struct scsi_host_template dec_esp_template = {
+ .module = THIS_MODULE,
.name = "NCR53C94",
- .detect = dec_esp_detect,
- .slave_alloc = esp_slave_alloc,
- .slave_destroy = esp_slave_destroy,
- .release = dec_esp_release,
.info = esp_info,
.queuecommand = esp_queue,
.eh_abort_handler = esp_abort,
.eh_bus_reset_handler = esp_reset,
+ .slave_alloc = esp_slave_alloc,
+ .slave_destroy = esp_slave_destroy,
+ .proc_info = esp_proc_info,
+ .proc_name = "dec_esp",
.can_queue = 7,
- .this_id = 7,
.sg_tablesize = SG_ALL,
.cmd_per_lun = 1,
.use_clustering = DISABLE_CLUSTERING,
};
-
-#include "scsi_module.c"
+static struct NCR_ESP *dec_esp_platform;
/***************************************************************** Detection */
-static int dec_esp_detect(struct scsi_host_template * tpnt)
+static int dec_esp_platform_probe(void)
{
struct NCR_ESP *esp;
- struct ConfigDev *esp_dev;
- int slot;
- unsigned long mem_start;
+ int err = 0;
if (IOASIC) {
- esp_dev = 0;
- esp = esp_allocate(tpnt, (void *) esp_dev);
+ esp = esp_allocate(&dec_esp_template, NULL, 1);
/* Do command transfer with programmed I/O */
esp->do_pio_cmds = 1;
@@ -200,112 +182,175 @@ static int dec_esp_detect(struct scsi_host_template * tpnt)
/* Check for differential SCSI-bus */
esp->diff = 0;
+ err = request_irq(esp->irq, esp_intr, IRQF_DISABLED,
+ "ncr53c94", esp->ehost);
+ if (err)
+ goto err_alloc;
+ err = request_irq(dec_interrupt[DEC_IRQ_ASC_MERR],
+ scsi_dma_merr_int, IRQF_DISABLED,
+ "ncr53c94 error", esp->ehost);
+ if (err)
+ goto err_irq;
+ err = request_irq(dec_interrupt[DEC_IRQ_ASC_ERR],
+ scsi_dma_err_int, IRQF_DISABLED,
+ "ncr53c94 overrun", esp->ehost);
+ if (err)
+ goto err_irq_merr;
+ err = request_irq(dec_interrupt[DEC_IRQ_ASC_DMA], scsi_dma_int,
+ IRQF_DISABLED, "ncr53c94 dma", esp->ehost);
+ if (err)
+ goto err_irq_err;
+
esp_initialize(esp);
- if (request_irq(esp->irq, esp_intr, IRQF_DISABLED,
- "ncr53c94", esp->ehost))
- goto err_dealloc;
- if (request_irq(dec_interrupt[DEC_IRQ_ASC_MERR],
- scsi_dma_merr_int, IRQF_DISABLED,
- "ncr53c94 error", esp->ehost))
- goto err_free_irq;
- if (request_irq(dec_interrupt[DEC_IRQ_ASC_ERR],
- scsi_dma_err_int, IRQF_DISABLED,
- "ncr53c94 overrun", esp->ehost))
- goto err_free_irq_merr;
- if (request_irq(dec_interrupt[DEC_IRQ_ASC_DMA],
- scsi_dma_int, IRQF_DISABLED,
- "ncr53c94 dma", esp->ehost))
- goto err_free_irq_err;
+ err = scsi_add_host(esp->ehost, NULL);
+ if (err) {
+ printk(KERN_ERR "ESP: Unable to register adapter\n");
+ goto err_irq_dma;
+ }
+
+ scsi_scan_host(esp->ehost);
+ dec_esp_platform = esp;
}
- if (TURBOCHANNEL) {
- while ((slot = search_tc_card("PMAZ-AA")) >= 0) {
- claim_tc_card(slot);
-
- esp_dev = 0;
- esp = esp_allocate(tpnt, (void *) esp_dev);
-
- mem_start = get_tc_base_addr(slot);
-
- /* Store base addr into esp struct */
- esp->slot = CPHYSADDR(mem_start);
-
- esp->dregs = 0;
- esp->eregs = (void *)CKSEG1ADDR(mem_start +
- DEC_SCSI_SREG);
- esp->do_pio_cmds = 1;
-
- /* Set the command buffer */
- esp->esp_command = (volatile unsigned char *) pmaz_cmd_buffer;
-
- /* get virtual dma address for command buffer */
- esp->esp_command_dvma = virt_to_phys(pmaz_cmd_buffer);
-
- esp->cfreq = get_tc_speed();
-
- esp->irq = get_tc_irq_nr(slot);
-
- /* Required functions */
- esp->dma_bytes_sent = &dma_bytes_sent;
- esp->dma_can_transfer = &dma_can_transfer;
- esp->dma_dump_state = &dma_dump_state;
- esp->dma_init_read = &pmaz_dma_init_read;
- esp->dma_init_write = &pmaz_dma_init_write;
- esp->dma_ints_off = &pmaz_dma_ints_off;
- esp->dma_ints_on = &pmaz_dma_ints_on;
- esp->dma_irq_p = &dma_irq_p;
- esp->dma_ports_p = &dma_ports_p;
- esp->dma_setup = &pmaz_dma_setup;
-
- /* Optional functions */
- esp->dma_barrier = 0;
- esp->dma_drain = &pmaz_dma_drain;
- esp->dma_invalidate = 0;
- esp->dma_irq_entry = 0;
- esp->dma_irq_exit = 0;
- esp->dma_poll = 0;
- esp->dma_reset = 0;
- esp->dma_led_off = 0;
- esp->dma_led_on = 0;
-
- esp->dma_mmu_get_scsi_one = pmaz_dma_mmu_get_scsi_one;
- esp->dma_mmu_get_scsi_sgl = 0;
- esp->dma_mmu_release_scsi_one = 0;
- esp->dma_mmu_release_scsi_sgl = 0;
- esp->dma_advance_sg = 0;
-
- if (request_irq(esp->irq, esp_intr, IRQF_DISABLED,
- "PMAZ_AA", esp->ehost)) {
- esp_deallocate(esp);
- release_tc_card(slot);
- continue;
- }
- esp->scsi_id = 7;
- esp->diff = 0;
- esp_initialize(esp);
- }
+ return 0;
+
+err_irq_dma:
+ free_irq(dec_interrupt[DEC_IRQ_ASC_DMA], esp->ehost);
+err_irq_err:
+ free_irq(dec_interrupt[DEC_IRQ_ASC_ERR], esp->ehost);
+err_irq_merr:
+ free_irq(dec_interrupt[DEC_IRQ_ASC_MERR], esp->ehost);
+err_irq:
+ free_irq(esp->irq, esp->ehost);
+err_alloc:
+ esp_deallocate(esp);
+ scsi_host_put(esp->ehost);
+ return err;
+}
+
+static int __init dec_esp_probe(struct device *dev)
+{
+ struct NCR_ESP *esp;
+ resource_size_t start, len;
+ int err;
+
+ esp = esp_allocate(&dec_esp_template, NULL, 1);
+
+ dev_set_drvdata(dev, esp);
+
+ start = to_tc_dev(dev)->resource.start;
+ len = to_tc_dev(dev)->resource.end - start + 1;
+
+ if (!request_mem_region(start, len, dev->bus_id)) {
+ printk(KERN_ERR "%s: Unable to reserve MMIO resource\n",
+ dev->bus_id);
+ err = -EBUSY;
+ goto err_alloc;
}
- if(nesps) {
- printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps, esps_in_use);
- esps_running = esps_in_use;
- return esps_in_use;
+ /* Store base addr into esp struct. */
+ esp->slot = start;
+
+ esp->dregs = 0;
+ esp->eregs = (void *)CKSEG1ADDR(start + DEC_SCSI_SREG);
+ esp->do_pio_cmds = 1;
+
+ /* Set the command buffer. */
+ esp->esp_command = (volatile unsigned char *)pmaz_cmd_buffer;
+
+ /* Get virtual dma address for command buffer. */
+ esp->esp_command_dvma = virt_to_phys(pmaz_cmd_buffer);
+
+ esp->cfreq = tc_get_speed(to_tc_dev(dev)->bus);
+
+ esp->irq = to_tc_dev(dev)->interrupt;
+
+ /* Required functions. */
+ esp->dma_bytes_sent = &dma_bytes_sent;
+ esp->dma_can_transfer = &dma_can_transfer;
+ esp->dma_dump_state = &dma_dump_state;
+ esp->dma_init_read = &pmaz_dma_init_read;
+ esp->dma_init_write = &pmaz_dma_init_write;
+ esp->dma_ints_off = &pmaz_dma_ints_off;
+ esp->dma_ints_on = &pmaz_dma_ints_on;
+ esp->dma_irq_p = &dma_irq_p;
+ esp->dma_ports_p = &dma_ports_p;
+ esp->dma_setup = &pmaz_dma_setup;
+
+ /* Optional functions. */
+ esp->dma_barrier = 0;
+ esp->dma_drain = &pmaz_dma_drain;
+ esp->dma_invalidate = 0;
+ esp->dma_irq_entry = 0;
+ esp->dma_irq_exit = 0;
+ esp->dma_poll = 0;
+ esp->dma_reset = 0;
+ esp->dma_led_off = 0;
+ esp->dma_led_on = 0;
+
+ esp->dma_mmu_get_scsi_one = pmaz_dma_mmu_get_scsi_one;
+ esp->dma_mmu_get_scsi_sgl = 0;
+ esp->dma_mmu_release_scsi_one = 0;
+ esp->dma_mmu_release_scsi_sgl = 0;
+ esp->dma_advance_sg = 0;
+
+ err = request_irq(esp->irq, esp_intr, IRQF_DISABLED, "PMAZ_AA",
+ esp->ehost);
+ if (err) {
+ printk(KERN_ERR "%s: Unable to get IRQ %d\n",
+ dev->bus_id, esp->irq);
+ goto err_resource;
+ }
+
+ esp->scsi_id = 7;
+ esp->diff = 0;
+ esp_initialize(esp);
+
+ err = scsi_add_host(esp->ehost, dev);
+ if (err) {
+ printk(KERN_ERR "%s: Unable to register adapter\n",
+ dev->bus_id);
+ goto err_irq;
}
+
+ scsi_scan_host(esp->ehost);
+
return 0;
-err_free_irq_err:
- free_irq(dec_interrupt[DEC_IRQ_ASC_ERR], scsi_dma_err_int);
-err_free_irq_merr:
- free_irq(dec_interrupt[DEC_IRQ_ASC_MERR], scsi_dma_merr_int);
-err_free_irq:
- free_irq(esp->irq, esp_intr);
-err_dealloc:
+err_irq:
+ free_irq(esp->irq, esp->ehost);
+
+err_resource:
+ release_mem_region(start, len);
+
+err_alloc:
esp_deallocate(esp);
- return 0;
+ scsi_host_put(esp->ehost);
+ return err;
+}
+
+static void __exit dec_esp_platform_remove(void)
+{
+ struct NCR_ESP *esp = dec_esp_platform;
+
+ free_irq(esp->irq, esp->ehost);
+ esp_deallocate(esp);
+ scsi_host_put(esp->ehost);
+ dec_esp_platform = NULL;
}
+static void __exit dec_esp_remove(struct device *dev)
+{
+ struct NCR_ESP *esp = dev_get_drvdata(dev);
+
+ free_irq(esp->irq, esp->ehost);
+ esp_deallocate(esp);
+ scsi_host_put(esp->ehost);
+}
+
+
/************************************************************* DMA Functions */
static irqreturn_t scsi_dma_merr_int(int irq, void *dev_id)
{
@@ -576,3 +621,67 @@ static void pmaz_dma_mmu_get_scsi_one(struct NCR_ESP *esp, struct scsi_cmnd * sp
{
sp->SCp.ptr = (char *)virt_to_phys(sp->request_buffer);
}
+
+
+#ifdef CONFIG_TC
+static int __init dec_esp_tc_probe(struct device *dev);
+static int __exit dec_esp_tc_remove(struct device *dev);
+
+static const struct tc_device_id dec_esp_tc_table[] = {
+ { "DEC ", "PMAZ-AA " },
+ { }
+};
+MODULE_DEVICE_TABLE(tc, dec_esp_tc_table);
+
+static struct tc_driver dec_esp_tc_driver = {
+ .id_table = dec_esp_tc_table,
+ .driver = {
+ .name = "dec_esp",
+ .bus = &tc_bus_type,
+ .probe = dec_esp_tc_probe,
+ .remove = __exit_p(dec_esp_tc_remove),
+ },
+};
+
+static int __init dec_esp_tc_probe(struct device *dev)
+{
+ int status = dec_esp_probe(dev);
+ if (!status)
+ get_device(dev);
+ return status;
+}
+
+static int __exit dec_esp_tc_remove(struct device *dev)
+{
+ put_device(dev);
+ dec_esp_remove(dev);
+ return 0;
+}
+#endif
+
+static int __init dec_esp_init(void)
+{
+ int status;
+
+ status = tc_register_driver(&dec_esp_tc_driver);
+ if (!status)
+ dec_esp_platform_probe();
+
+ if (nesps) {
+ pr_info("ESP: Total of %d ESP hosts found, "
+ "%d actually in use.\n", nesps, esps_in_use);
+ esps_running = esps_in_use;
+ }
+
+ return status;
+}
+
+static void __exit dec_esp_exit(void)
+{
+ dec_esp_platform_remove();
+ tc_unregister_driver(&dec_esp_tc_driver);
+}
+
+
+module_init(dec_esp_init);
+module_exit(dec_esp_exit);
diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c
index 365db537a28..cd36e81b2d9 100644
--- a/drivers/scsi/dpt_i2o.c
+++ b/drivers/scsi/dpt_i2o.c
@@ -116,7 +116,7 @@ static int sys_tbl_len = 0;
static adpt_hba* hba_chain = NULL;
static int hba_count = 0;
-static struct file_operations adpt_fops = {
+static const struct file_operations adpt_fops = {
.ioctl = adpt_ioctl,
.open = adpt_open,
.release = adpt_close
diff --git a/drivers/scsi/dtc.c b/drivers/scsi/dtc.c
index 54756722dd5..9d52e45c7d3 100644
--- a/drivers/scsi/dtc.c
+++ b/drivers/scsi/dtc.c
@@ -75,7 +75,6 @@
#include <asm/system.h>
#include <linux/module.h>
#include <linux/signal.h>
-#include <linux/sched.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/stat.h>
diff --git a/drivers/scsi/eata_pio.c b/drivers/scsi/eata_pio.c
index 2dbb66d2f0a..f33ad01064a 100644
--- a/drivers/scsi/eata_pio.c
+++ b/drivers/scsi/eata_pio.c
@@ -48,7 +48,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/string.h>
#include <linux/ioport.h>
#include <linux/slab.h>
diff --git a/drivers/scsi/fastlane.c b/drivers/scsi/fastlane.c
index 2a1c5c22b9e..4266a2139b5 100644
--- a/drivers/scsi/fastlane.c
+++ b/drivers/scsi/fastlane.c
@@ -142,7 +142,7 @@ int __init fastlane_esp_detect(struct scsi_host_template *tpnt)
if (board < 0x1000000) {
goto err_release;
}
- esp = esp_allocate(tpnt, (void *)board+FASTLANE_ESP_ADDR);
+ esp = esp_allocate(tpnt, (void *)board + FASTLANE_ESP_ADDR, 0);
/* Do command transfer with programmed I/O */
esp->do_pio_cmds = 1;
diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c
index cdd893bb4e2..880f70d24e6 100644
--- a/drivers/scsi/g_NCR5380.c
+++ b/drivers/scsi/g_NCR5380.c
@@ -103,7 +103,6 @@
#include <asm/system.h>
#include <asm/io.h>
#include <linux/signal.h>
-#include <linux/sched.h>
#include <linux/blkdev.h>
#include "scsi.h"
#include <scsi/scsi_host.h>
diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c
index 4c698a71f66..8c81cec8529 100644
--- a/drivers/scsi/gdth.c
+++ b/drivers/scsi/gdth.c
@@ -387,7 +387,6 @@
#include <linux/ctype.h>
#include <linux/ioport.h>
#include <linux/delay.h>
-#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/in.h>
#include <linux/proc_fs.h>
@@ -687,7 +686,7 @@ MODULE_AUTHOR("Achim Leubner");
MODULE_LICENSE("GPL");
/* ioctl interface */
-static struct file_operations gdth_fops = {
+static const struct file_operations gdth_fops = {
.ioctl = gdth_ioctl,
.open = gdth_open,
.release = gdth_close,
diff --git a/drivers/scsi/gvp11.c b/drivers/scsi/gvp11.c
index 2f6c1137a6e..37741e9b5c3 100644
--- a/drivers/scsi/gvp11.c
+++ b/drivers/scsi/gvp11.c
@@ -1,7 +1,6 @@
#include <linux/types.h>
#include <linux/mm.h>
#include <linux/blkdev.h>
-#include <linux/sched.h>
#include <linux/init.h>
#include <linux/interrupt.h>
diff --git a/drivers/scsi/ibmvscsi/ibmvstgt.c b/drivers/scsi/ibmvscsi/ibmvstgt.c
index e28260f05d6..4368ca0e827 100644
--- a/drivers/scsi/ibmvscsi/ibmvstgt.c
+++ b/drivers/scsi/ibmvscsi/ibmvstgt.c
@@ -580,7 +580,7 @@ static int crq_queue_create(struct crq_queue *queue, struct srp_target *target)
}
err = request_irq(vport->dma_dev->irq, &ibmvstgt_interrupt,
- SA_INTERRUPT, "ibmvstgt", target);
+ IRQF_DISABLED, "ibmvstgt", target);
if (err)
goto req_irq_failed;
diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c
index 8f6b5bf580f..2b5b8a93bc1 100644
--- a/drivers/scsi/ide-scsi.c
+++ b/drivers/scsi/ide-scsi.c
@@ -801,15 +801,10 @@ static int idescsi_ide_open(struct inode *inode, struct file *filp)
{
struct gendisk *disk = inode->i_bdev->bd_disk;
struct ide_scsi_obj *scsi;
- ide_drive_t *drive;
if (!(scsi = ide_scsi_get(disk)))
return -ENXIO;
- drive = scsi->drive;
-
- drive->usage++;
-
return 0;
}
@@ -817,9 +812,6 @@ static int idescsi_ide_release(struct inode *inode, struct file *filp)
{
struct gendisk *disk = inode->i_bdev->bd_disk;
struct ide_scsi_obj *scsi = ide_scsi_g(disk);
- ide_drive_t *drive = scsi->drive;
-
- drive->usage--;
ide_scsi_put(scsi);
diff --git a/drivers/scsi/initio.c b/drivers/scsi/initio.c
index d561663fb4e..7e7635ca78f 100644
--- a/drivers/scsi/initio.c
+++ b/drivers/scsi/initio.c
@@ -123,7 +123,6 @@
#include <linux/string.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
-#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/dma-mapping.h>
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index b318500785e..95045e33710 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -595,10 +595,8 @@ static int ipr_save_pcix_cmd_reg(struct ipr_ioa_cfg *ioa_cfg)
{
int pcix_cmd_reg = pci_find_capability(ioa_cfg->pdev, PCI_CAP_ID_PCIX);
- if (pcix_cmd_reg == 0) {
- dev_err(&ioa_cfg->pdev->dev, "Failed to save PCI-X command register\n");
- return -EIO;
- }
+ if (pcix_cmd_reg == 0)
+ return 0;
if (pci_read_config_word(ioa_cfg->pdev, pcix_cmd_reg + PCI_X_CMD,
&ioa_cfg->saved_pcix_cmd_reg) != PCIBIOS_SUCCESSFUL) {
@@ -627,10 +625,6 @@ static int ipr_set_pcix_cmd_reg(struct ipr_ioa_cfg *ioa_cfg)
dev_err(&ioa_cfg->pdev->dev, "Failed to setup PCI-X command register\n");
return -EIO;
}
- } else {
- dev_err(&ioa_cfg->pdev->dev,
- "Failed to setup PCI-X command register\n");
- return -EIO;
}
return 0;
@@ -6314,7 +6308,6 @@ static int ipr_reset_restore_cfg_space(struct ipr_cmnd *ipr_cmd)
int rc;
ENTER;
- pci_unblock_user_cfg_access(ioa_cfg->pdev);
rc = pci_restore_state(ioa_cfg->pdev);
if (rc != PCIBIOS_SUCCESSFUL) {
@@ -6355,6 +6348,24 @@ static int ipr_reset_restore_cfg_space(struct ipr_cmnd *ipr_cmd)
}
/**
+ * ipr_reset_bist_done - BIST has completed on the adapter.
+ * @ipr_cmd: ipr command struct
+ *
+ * Description: Unblock config space and resume the reset process.
+ *
+ * Return value:
+ * IPR_RC_JOB_CONTINUE
+ **/
+static int ipr_reset_bist_done(struct ipr_cmnd *ipr_cmd)
+{
+ ENTER;
+ pci_unblock_user_cfg_access(ipr_cmd->ioa_cfg->pdev);
+ ipr_cmd->job_step = ipr_reset_restore_cfg_space;
+ LEAVE;
+ return IPR_RC_JOB_CONTINUE;
+}
+
+/**
* ipr_reset_start_bist - Run BIST on the adapter.
* @ipr_cmd: ipr command struct
*
@@ -6376,7 +6387,7 @@ static int ipr_reset_start_bist(struct ipr_cmnd *ipr_cmd)
ipr_cmd->ioasa.ioasc = cpu_to_be32(IPR_IOASC_PCI_ACCESS_ERROR);
rc = IPR_RC_JOB_CONTINUE;
} else {
- ipr_cmd->job_step = ipr_reset_restore_cfg_space;
+ ipr_cmd->job_step = ipr_reset_bist_done;
ipr_reset_start_timer(ipr_cmd, IPR_WAIT_FOR_BIST_TIMEOUT);
rc = IPR_RC_JOB_RETURN;
}
@@ -7166,9 +7177,6 @@ ipr_get_chip_cfg(const struct pci_device_id *dev_id)
{
int i;
- if (dev_id->driver_data)
- return (const struct ipr_chip_cfg_t *)dev_id->driver_data;
-
for (i = 0; i < ARRAY_SIZE(ipr_chip); i++)
if (ipr_chip[i].vendor == dev_id->vendor &&
ipr_chip[i].device == dev_id->device)
@@ -7517,65 +7525,43 @@ static void ipr_shutdown(struct pci_dev *pdev)
static struct pci_device_id ipr_pci_table[] __devinitdata = {
{ PCI_VENDOR_ID_MYLEX, PCI_DEVICE_ID_IBM_GEMSTONE,
- PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_5702,
- 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_5702, 0, 0, 0 },
{ PCI_VENDOR_ID_MYLEX, PCI_DEVICE_ID_IBM_GEMSTONE,
- PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_5703,
- 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_5703, 0, 0, 0 },
{ PCI_VENDOR_ID_MYLEX, PCI_DEVICE_ID_IBM_GEMSTONE,
- PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_573D,
- 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_573D, 0, 0, 0 },
{ PCI_VENDOR_ID_MYLEX, PCI_DEVICE_ID_IBM_GEMSTONE,
- PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_573E,
- 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_573E, 0, 0, 0 },
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE,
- PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571B,
- 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571B, 0, 0, 0 },
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE,
- PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572E,
- 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572E, 0, 0, 0 },
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE,
- PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571A,
- 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571A, 0, 0, 0 },
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE,
- PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575B,
- 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575B, 0, 0, 0 },
{ PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN,
- PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572A,
- 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572A, 0, 0, 0 },
{ PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN,
- PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572B,
- 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572B, 0, 0, 0 },
{ PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN,
- PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575C,
- 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
- { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN,
- PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572A,
- 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575C, 0, 0, 0 },
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN,
- PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572B,
- 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572A, 0, 0, 0 },
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN,
- PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575C,
- 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572B, 0, 0, 0 },
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN,
- PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B8,
- 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575C, 0, 0, 0 },
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E,
- PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B7,
- 0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B7, 0, 0, 0 },
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SNIPE,
- PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_2780,
- 0, 0, (kernel_ulong_t)&ipr_chip_cfg[1] },
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_2780, 0, 0, 0 },
{ PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP,
- PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571E,
- 0, 0, (kernel_ulong_t)&ipr_chip_cfg[1] },
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571E, 0, 0, 0 },
{ PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP,
- PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571F,
- 0, 0, (kernel_ulong_t)&ipr_chip_cfg[1] },
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571F, 0, 0, 0 },
{ PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP,
- PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572F,
- 0, 0, (kernel_ulong_t)&ipr_chip_cfg[1] },
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572F, 0, 0, 0 },
{ }
};
MODULE_DEVICE_TABLE(pci, ipr_pci_table);
diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h
index 9f62a1d4d51..88f285de97b 100644
--- a/drivers/scsi/ipr.h
+++ b/drivers/scsi/ipr.h
@@ -37,8 +37,8 @@
/*
* Literals
*/
-#define IPR_DRIVER_VERSION "2.3.0"
-#define IPR_DRIVER_DATE "(November 8, 2006)"
+#define IPR_DRIVER_VERSION "2.3.1"
+#define IPR_DRIVER_DATE "(January 23, 2007)"
/*
* IPR_MAX_CMD_PER_LUN: This defines the maximum number of outstanding
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index 43768408437..8f55e143143 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -1375,7 +1375,7 @@ iscsi_tcp_mtask_xmit(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask)
}
BUG_ON(tcp_mtask->xmstate != XMSTATE_IDLE);
- if (mtask->hdr->itt == cpu_to_be32(ISCSI_RESERVED_TAG)) {
+ if (mtask->hdr->itt == RESERVED_ITT) {
struct iscsi_session *session = conn->session;
spin_lock_bh(&session->lock);
diff --git a/drivers/scsi/jazz_esp.c b/drivers/scsi/jazz_esp.c
index bfac4441d89..19dd4b962e1 100644
--- a/drivers/scsi/jazz_esp.c
+++ b/drivers/scsi/jazz_esp.c
@@ -75,7 +75,7 @@ static int jazz_esp_detect(struct scsi_host_template *tpnt)
*/
if (1) {
esp_dev = NULL;
- esp = esp_allocate(tpnt, (void *) esp_dev);
+ esp = esp_allocate(tpnt, esp_dev, 0);
/* Do command transfer with programmed I/O */
esp->do_pio_cmds = 1;
diff --git a/drivers/scsi/lasi700.c b/drivers/scsi/lasi700.c
index f0871c3ac3d..5c32a69e41b 100644
--- a/drivers/scsi/lasi700.c
+++ b/drivers/scsi/lasi700.c
@@ -38,7 +38,6 @@
#include <linux/stat.h>
#include <linux/mm.h>
#include <linux/blkdev.h>
-#include <linux/sched.h>
#include <linux/ioport.h>
#include <linux/dma-mapping.h>
@@ -123,6 +122,7 @@ lasi700_probe(struct parisc_device *dev)
hostdata->force_le_on_be = 0;
hostdata->chip710 = 1;
hostdata->dmode_extra = DMODE_FC2;
+ hostdata->burst_length = 8;
}
host = NCR_700_detect(&lasi700_template, hostdata, &dev->dev);
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index d37048c96ea..7c75771c77f 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -113,8 +113,7 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
hdr->opcode = ISCSI_OP_SCSI_CMD;
hdr->flags = ISCSI_ATTR_SIMPLE;
int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun);
- hdr->itt = ctask->itt | (conn->id << ISCSI_CID_SHIFT) |
- (session->age << ISCSI_AGE_SHIFT);
+ hdr->itt = build_itt(ctask->itt, conn->id, session->age);
hdr->data_length = cpu_to_be32(sc->request_bufflen);
hdr->cmdsn = cpu_to_be32(session->cmdsn);
session->cmdsn++;
@@ -270,7 +269,7 @@ invalid_datalen:
goto out;
}
- senselen = be16_to_cpu(*(uint16_t *)data);
+ senselen = be16_to_cpu(*(__be16 *)data);
if (datalen < senselen)
goto invalid_datalen;
@@ -338,7 +337,7 @@ static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
if (ntoh24(reject->dlength) >= sizeof(struct iscsi_hdr)) {
memcpy(&rejected_pdu, data, sizeof(struct iscsi_hdr));
- itt = rejected_pdu.itt & ISCSI_ITT_MASK;
+ itt = get_itt(rejected_pdu.itt);
printk(KERN_ERR "itt 0x%x had pdu (op 0x%x) rejected "
"due to DataDigest error.\n", itt,
rejected_pdu.opcode);
@@ -367,10 +366,10 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
struct iscsi_mgmt_task *mtask;
uint32_t itt;
- if (hdr->itt != cpu_to_be32(ISCSI_RESERVED_TAG))
- itt = hdr->itt & ISCSI_ITT_MASK;
+ if (hdr->itt != RESERVED_ITT)
+ itt = get_itt(hdr->itt);
else
- itt = hdr->itt;
+ itt = ~0U;
if (itt < session->cmds_max) {
ctask = session->cmds[itt];
@@ -440,7 +439,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
iscsi_tmf_rsp(conn, hdr);
break;
case ISCSI_OP_NOOP_IN:
- if (hdr->ttt != ISCSI_RESERVED_TAG || datalen) {
+ if (hdr->ttt != cpu_to_be32(ISCSI_RESERVED_TAG) || datalen) {
rc = ISCSI_ERR_PROTO;
break;
}
@@ -457,7 +456,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
rc = ISCSI_ERR_BAD_OPCODE;
break;
}
- } else if (itt == ISCSI_RESERVED_TAG) {
+ } else if (itt == ~0U) {
rc = iscsi_check_assign_cmdsn(session,
(struct iscsi_nopin*)hdr);
if (rc)
@@ -470,7 +469,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
break;
}
- if (hdr->ttt == ISCSI_RESERVED_TAG)
+ if (hdr->ttt == cpu_to_be32(ISCSI_RESERVED_TAG))
break;
if (iscsi_recv_pdu(conn->cls_conn, hdr, NULL, 0))
@@ -516,24 +515,24 @@ int iscsi_verify_itt(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
struct iscsi_cmd_task *ctask;
uint32_t itt;
- if (hdr->itt != cpu_to_be32(ISCSI_RESERVED_TAG)) {
- if ((hdr->itt & ISCSI_AGE_MASK) !=
+ if (hdr->itt != RESERVED_ITT) {
+ if (((__force u32)hdr->itt & ISCSI_AGE_MASK) !=
(session->age << ISCSI_AGE_SHIFT)) {
printk(KERN_ERR "iscsi: received itt %x expected "
- "session age (%x)\n", hdr->itt,
+ "session age (%x)\n", (__force u32)hdr->itt,
session->age & ISCSI_AGE_MASK);
return ISCSI_ERR_BAD_ITT;
}
- if ((hdr->itt & ISCSI_CID_MASK) !=
+ if (((__force u32)hdr->itt & ISCSI_CID_MASK) !=
(conn->id << ISCSI_CID_SHIFT)) {
printk(KERN_ERR "iscsi: received itt %x, expected "
- "CID (%x)\n", hdr->itt, conn->id);
+ "CID (%x)\n", (__force u32)hdr->itt, conn->id);
return ISCSI_ERR_BAD_ITT;
}
- itt = hdr->itt & ISCSI_ITT_MASK;
+ itt = get_itt(hdr->itt);
} else
- itt = hdr->itt;
+ itt = ~0U;
if (itt < session->cmds_max) {
ctask = session->cmds[itt];
@@ -896,9 +895,8 @@ iscsi_conn_send_generic(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
/*
* pre-format CmdSN for outgoing PDU.
*/
- if (hdr->itt != cpu_to_be32(ISCSI_RESERVED_TAG)) {
- hdr->itt = mtask->itt | (conn->id << ISCSI_CID_SHIFT) |
- (session->age << ISCSI_AGE_SHIFT);
+ if (hdr->itt != RESERVED_ITT) {
+ hdr->itt = build_itt(mtask->itt, conn->id, session->age);
nop->cmdsn = cpu_to_be32(session->cmdsn);
if (conn->c_stage == ISCSI_CONN_STARTED &&
!(hdr->opcode & ISCSI_OP_IMMEDIATE))
@@ -1064,7 +1062,7 @@ static int iscsi_exec_abort_task(struct scsi_cmnd *sc,
spin_lock_bh(&session->lock);
ctask->mtask = (struct iscsi_mgmt_task *)
- session->mgmt_cmds[(hdr->itt & ISCSI_ITT_MASK) -
+ session->mgmt_cmds[get_itt(hdr->itt) -
ISCSI_MGMT_ITT_OFFSET];
if (conn->tmabort_state == TMABORT_INITIAL) {
diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c
index fb7df7b7581..a65598b1e53 100644
--- a/drivers/scsi/libsas/sas_discover.c
+++ b/drivers/scsi/libsas/sas_discover.c
@@ -548,7 +548,7 @@ int sas_discover_sata(struct domain_device *dev)
res = sas_notify_lldd_dev_found(dev);
if (res)
- return res;
+ goto out_err2;
switch (dev->dev_type) {
case SATA_DEV:
@@ -560,11 +560,23 @@ int sas_discover_sata(struct domain_device *dev)
default:
break;
}
+ if (res)
+ goto out_err;
sas_notify_lldd_dev_gone(dev);
- if (!res) {
- sas_notify_lldd_dev_found(dev);
- }
+ res = sas_notify_lldd_dev_found(dev);
+ if (res)
+ goto out_err2;
+
+ res = sas_rphy_add(dev->rphy);
+ if (res)
+ goto out_err;
+
+ return res;
+
+out_err:
+ sas_notify_lldd_dev_gone(dev);
+out_err2:
return res;
}
@@ -580,21 +592,17 @@ int sas_discover_end_dev(struct domain_device *dev)
res = sas_notify_lldd_dev_found(dev);
if (res)
- return res;
+ goto out_err2;
res = sas_rphy_add(dev->rphy);
if (res)
goto out_err;
- /* do this to get the end device port attributes which will have
- * been scanned in sas_rphy_add */
- sas_notify_lldd_dev_gone(dev);
- sas_notify_lldd_dev_found(dev);
-
return 0;
out_err:
sas_notify_lldd_dev_gone(dev);
+out_err2:
return res;
}
@@ -649,6 +657,7 @@ void sas_unregister_domain_devices(struct asd_sas_port *port)
*/
static void sas_discover_domain(struct work_struct *work)
{
+ struct domain_device *dev;
int error = 0;
struct sas_discovery_event *ev =
container_of(work, struct sas_discovery_event, work);
@@ -658,35 +667,42 @@ static void sas_discover_domain(struct work_struct *work)
&port->disc.pending);
if (port->port_dev)
- return ;
- else {
- error = sas_get_port_device(port);
- if (error)
- return;
- }
+ return;
+
+ error = sas_get_port_device(port);
+ if (error)
+ return;
+ dev = port->port_dev;
SAS_DPRINTK("DOING DISCOVERY on port %d, pid:%d\n", port->id,
current->pid);
- switch (port->port_dev->dev_type) {
+ switch (dev->dev_type) {
case SAS_END_DEV:
- error = sas_discover_end_dev(port->port_dev);
+ error = sas_discover_end_dev(dev);
break;
case EDGE_DEV:
case FANOUT_DEV:
- error = sas_discover_root_expander(port->port_dev);
+ error = sas_discover_root_expander(dev);
break;
case SATA_DEV:
case SATA_PM:
- error = sas_discover_sata(port->port_dev);
+ error = sas_discover_sata(dev);
break;
default:
- SAS_DPRINTK("unhandled device %d\n", port->port_dev->dev_type);
+ SAS_DPRINTK("unhandled device %d\n", dev->dev_type);
break;
}
if (error) {
- kfree(port->port_dev); /* not kobject_register-ed yet */
+ sas_rphy_free(dev->rphy);
+ dev->rphy = NULL;
+
+ spin_lock(&port->dev_list_lock);
+ list_del_init(&dev->dev_list_node);
+ spin_unlock(&port->dev_list_lock);
+
+ kfree(dev); /* not kobject_register-ed yet */
port->port_dev = NULL;
}
@@ -726,7 +742,7 @@ int sas_discover_event(struct asd_sas_port *port, enum discover_event ev)
BUG_ON(ev >= DISC_NUM_EVENTS);
sas_queue_event(ev, &disc->disc_event_lock, &disc->pending,
- &disc->disc_work[ev].work, port->ha->core.shost);
+ &disc->disc_work[ev].work, port->ha);
return 0;
}
diff --git a/drivers/scsi/libsas/sas_event.c b/drivers/scsi/libsas/sas_event.c
index d83392ee682..9db30fb5caf 100644
--- a/drivers/scsi/libsas/sas_event.c
+++ b/drivers/scsi/libsas/sas_event.c
@@ -31,7 +31,7 @@ static void notify_ha_event(struct sas_ha_struct *sas_ha, enum ha_event event)
BUG_ON(event >= HA_NUM_EVENTS);
sas_queue_event(event, &sas_ha->event_lock, &sas_ha->pending,
- &sas_ha->ha_events[event].work, sas_ha->core.shost);
+ &sas_ha->ha_events[event].work, sas_ha);
}
static void notify_port_event(struct asd_sas_phy *phy, enum port_event event)
@@ -41,7 +41,7 @@ static void notify_port_event(struct asd_sas_phy *phy, enum port_event event)
BUG_ON(event >= PORT_NUM_EVENTS);
sas_queue_event(event, &ha->event_lock, &phy->port_events_pending,
- &phy->port_events[event].work, ha->core.shost);
+ &phy->port_events[event].work, ha);
}
static void notify_phy_event(struct asd_sas_phy *phy, enum phy_event event)
@@ -51,7 +51,7 @@ static void notify_phy_event(struct asd_sas_phy *phy, enum phy_event event)
BUG_ON(event >= PHY_NUM_EVENTS);
sas_queue_event(event, &ha->event_lock, &phy->phy_events_pending,
- &phy->phy_events[event].work, ha->core.shost);
+ &phy->phy_events[event].work, ha);
}
int sas_init_events(struct sas_ha_struct *sas_ha)
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
index d31e6fa466f..dc70c180e11 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -667,8 +667,9 @@ static struct domain_device *sas_ex_discover_end_dev(
return child;
out_list_del:
+ sas_rphy_free(child->rphy);
+ child->rphy = NULL;
list_del(&child->dev_list_node);
- sas_rphy_free(rphy);
out_free:
sas_port_delete(phy->port);
out_err:
@@ -677,6 +678,29 @@ static struct domain_device *sas_ex_discover_end_dev(
return NULL;
}
+/* See if this phy is part of a wide port */
+static int sas_ex_join_wide_port(struct domain_device *parent, int phy_id)
+{
+ struct ex_phy *phy = &parent->ex_dev.ex_phy[phy_id];
+ int i;
+
+ for (i = 0; i < parent->ex_dev.num_phys; i++) {
+ struct ex_phy *ephy = &parent->ex_dev.ex_phy[i];
+
+ if (ephy == phy)
+ continue;
+
+ if (!memcmp(phy->attached_sas_addr, ephy->attached_sas_addr,
+ SAS_ADDR_SIZE) && ephy->port) {
+ sas_port_add_phy(ephy->port, phy->phy);
+ phy->phy_state = PHY_DEVICE_DISCOVERED;
+ return 0;
+ }
+ }
+
+ return -ENODEV;
+}
+
static struct domain_device *sas_ex_discover_expander(
struct domain_device *parent, int phy_id)
{
@@ -809,6 +833,13 @@ static int sas_ex_discover_dev(struct domain_device *dev, int phy_id)
return res;
}
+ res = sas_ex_join_wide_port(dev, phy_id);
+ if (!res) {
+ SAS_DPRINTK("Attaching ex phy%d to wide port %016llx\n",
+ phy_id, SAS_ADDR(ex_phy->attached_sas_addr));
+ return res;
+ }
+
switch (ex_phy->attached_dev_type) {
case SAS_END_DEV:
child = sas_ex_discover_end_dev(dev, phy_id);
@@ -1431,14 +1462,23 @@ int sas_discover_root_expander(struct domain_device *dev)
int res;
struct sas_expander_device *ex = rphy_to_expander_device(dev->rphy);
- sas_rphy_add(dev->rphy);
+ res = sas_rphy_add(dev->rphy);
+ if (res)
+ goto out_err;
ex->level = dev->port->disc.max_level; /* 0 */
res = sas_discover_expander(dev);
- if (!res)
- sas_ex_bfs_disc(dev->port);
+ if (res)
+ goto out_err2;
+
+ sas_ex_bfs_disc(dev->port);
return res;
+
+out_err2:
+ sas_rphy_remove(dev->rphy);
+out_err:
+ return res;
}
/* ---------- Domain revalidation ---------- */
diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c
index 2f0c07fc3f4..965698c8b7b 100644
--- a/drivers/scsi/libsas/sas_init.c
+++ b/drivers/scsi/libsas/sas_init.c
@@ -87,6 +87,9 @@ int sas_register_ha(struct sas_ha_struct *sas_ha)
else if (sas_ha->lldd_queue_size == -1)
sas_ha->lldd_queue_size = 128; /* Sanity */
+ sas_ha->state = SAS_HA_REGISTERED;
+ spin_lock_init(&sas_ha->state_lock);
+
error = sas_register_phys(sas_ha);
if (error) {
printk(KERN_NOTICE "couldn't register sas phys:%d\n", error);
@@ -127,12 +130,22 @@ Undo_phys:
int sas_unregister_ha(struct sas_ha_struct *sas_ha)
{
+ unsigned long flags;
+
+ /* Set the state to unregistered to avoid further
+ * events to be queued */
+ spin_lock_irqsave(&sas_ha->state_lock, flags);
+ sas_ha->state = SAS_HA_UNREGISTERED;
+ spin_unlock_irqrestore(&sas_ha->state_lock, flags);
+ scsi_flush_work(sas_ha->core.shost);
+
+ sas_unregister_ports(sas_ha);
+
if (sas_ha->lldd_max_execute_num > 1) {
sas_shutdown_queue(sas_ha);
+ sas_ha->lldd_max_execute_num = 1;
}
- sas_unregister_ports(sas_ha);
-
return 0;
}
@@ -146,6 +159,36 @@ static int sas_get_linkerrors(struct sas_phy *phy)
return sas_smp_get_phy_events(phy);
}
+int sas_phy_enable(struct sas_phy *phy, int enable)
+{
+ int ret;
+ enum phy_func command;
+
+ if (enable)
+ command = PHY_FUNC_LINK_RESET;
+ else
+ command = PHY_FUNC_DISABLE;
+
+ if (scsi_is_sas_phy_local(phy)) {
+ struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
+ struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost);
+ struct asd_sas_phy *asd_phy = sas_ha->sas_phy[phy->number];
+ struct sas_internal *i =
+ to_sas_internal(sas_ha->core.shost->transportt);
+
+ if (!enable) {
+ sas_phy_disconnected(asd_phy);
+ sas_ha->notify_phy_event(asd_phy, PHYE_LOSS_OF_SIGNAL);
+ }
+ ret = i->dft->lldd_control_phy(asd_phy, command, NULL);
+ } else {
+ struct sas_rphy *rphy = dev_to_rphy(phy->dev.parent);
+ struct domain_device *ddev = sas_find_dev_by_rphy(rphy);
+ ret = sas_smp_phy_control(ddev, phy->number, command, NULL);
+ }
+ return ret;
+}
+
int sas_phy_reset(struct sas_phy *phy, int hard_reset)
{
int ret;
@@ -172,8 +215,8 @@ int sas_phy_reset(struct sas_phy *phy, int hard_reset)
return ret;
}
-static int sas_set_phy_speed(struct sas_phy *phy,
- struct sas_phy_linkrates *rates)
+int sas_set_phy_speed(struct sas_phy *phy,
+ struct sas_phy_linkrates *rates)
{
int ret;
@@ -212,6 +255,7 @@ static int sas_set_phy_speed(struct sas_phy *phy,
}
static struct sas_function_template sft = {
+ .phy_enable = sas_phy_enable,
.phy_reset = sas_phy_reset,
.set_phy_speed = sas_set_phy_speed,
.get_linkerrors = sas_get_linkerrors,
diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h
index 137d7e496b6..a78638df201 100644
--- a/drivers/scsi/libsas/sas_internal.h
+++ b/drivers/scsi/libsas/sas_internal.h
@@ -80,7 +80,7 @@ void sas_hae_reset(struct work_struct *work);
static inline void sas_queue_event(int event, spinlock_t *lock,
unsigned long *pending,
struct work_struct *work,
- struct Scsi_Host *shost)
+ struct sas_ha_struct *sas_ha)
{
unsigned long flags;
@@ -91,7 +91,12 @@ static inline void sas_queue_event(int event, spinlock_t *lock,
}
__set_bit(event, pending);
spin_unlock_irqrestore(lock, flags);
- scsi_queue_work(shost, work);
+
+ spin_lock_irqsave(&sas_ha->state_lock, flags);
+ if (sas_ha->state != SAS_HA_UNREGISTERED) {
+ scsi_queue_work(sas_ha->core.shost, work);
+ }
+ spin_unlock_irqrestore(&sas_ha->state_lock, flags);
}
static inline void sas_begin_event(int event, spinlock_t *lock,
diff --git a/drivers/scsi/libsas/sas_port.c b/drivers/scsi/libsas/sas_port.c
index 971c37ceecb..e1e2d085c92 100644
--- a/drivers/scsi/libsas/sas_port.c
+++ b/drivers/scsi/libsas/sas_port.c
@@ -42,10 +42,11 @@ static void sas_form_port(struct asd_sas_phy *phy)
struct asd_sas_port *port = phy->port;
struct sas_internal *si =
to_sas_internal(sas_ha->core.shost->transportt);
+ unsigned long flags;
if (port) {
if (memcmp(port->attached_sas_addr, phy->attached_sas_addr,
- SAS_ADDR_SIZE) == 0)
+ SAS_ADDR_SIZE) != 0)
sas_deform_port(phy);
else {
SAS_DPRINTK("%s: phy%d belongs to port%d already(%d)!\n",
@@ -56,7 +57,7 @@ static void sas_form_port(struct asd_sas_phy *phy)
}
/* find a port */
- spin_lock(&sas_ha->phy_port_lock);
+ spin_lock_irqsave(&sas_ha->phy_port_lock, flags);
for (i = 0; i < sas_ha->num_phys; i++) {
port = sas_ha->sas_port[i];
spin_lock(&port->phy_list_lock);
@@ -78,7 +79,7 @@ static void sas_form_port(struct asd_sas_phy *phy)
if (i >= sas_ha->num_phys) {
printk(KERN_NOTICE "%s: couldn't find a free port, bug?\n",
__FUNCTION__);
- spin_unlock(&sas_ha->phy_port_lock);
+ spin_unlock_irqrestore(&sas_ha->phy_port_lock, flags);
return;
}
@@ -105,7 +106,7 @@ static void sas_form_port(struct asd_sas_phy *phy)
} else
port->linkrate = max(port->linkrate, phy->linkrate);
spin_unlock(&port->phy_list_lock);
- spin_unlock(&sas_ha->phy_port_lock);
+ spin_unlock_irqrestore(&sas_ha->phy_port_lock, flags);
if (!port->port) {
port->port = sas_port_alloc(phy->phy->dev.parent, port->id);
@@ -137,6 +138,7 @@ void sas_deform_port(struct asd_sas_phy *phy)
struct asd_sas_port *port = phy->port;
struct sas_internal *si =
to_sas_internal(sas_ha->core.shost->transportt);
+ unsigned long flags;
if (!port)
return; /* done by a phy event */
@@ -155,7 +157,7 @@ void sas_deform_port(struct asd_sas_phy *phy)
if (si->dft->lldd_port_deformed)
si->dft->lldd_port_deformed(phy);
- spin_lock(&sas_ha->phy_port_lock);
+ spin_lock_irqsave(&sas_ha->phy_port_lock, flags);
spin_lock(&port->phy_list_lock);
list_del_init(&phy->port_phy_el);
@@ -174,7 +176,7 @@ void sas_deform_port(struct asd_sas_phy *phy)
port->phy_mask = 0;
}
spin_unlock(&port->phy_list_lock);
- spin_unlock(&sas_ha->phy_port_lock);
+ spin_unlock_irqrestore(&sas_ha->phy_port_lock, flags);
return;
}
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c
index 22672d54aa2..897a5e2c55e 100644
--- a/drivers/scsi/libsas/sas_scsi_host.c
+++ b/drivers/scsi/libsas/sas_scsi_host.c
@@ -34,6 +34,7 @@
#include <scsi/scsi_transport_sas.h>
#include "../scsi_sas_internal.h"
#include "../scsi_transport_api.h"
+#include "../scsi_priv.h"
#include <linux/err.h>
#include <linux/blkdev.h>
@@ -130,7 +131,7 @@ static enum task_attribute sas_scsi_get_task_attr(struct scsi_cmnd *cmd)
if (cmd->request && blk_rq_tagged(cmd->request)) {
if (cmd->device->ordered_tags &&
(cmd->request->cmd_flags & REQ_HARDBARRIER))
- ta = TASK_ATTR_HOQ;
+ ta = TASK_ATTR_ORDERED;
}
return ta;
}
@@ -281,6 +282,7 @@ enum task_disposition {
TASK_IS_ABORTED,
TASK_IS_AT_LU,
TASK_IS_NOT_AT_LU,
+ TASK_ABORT_FAILED,
};
static enum task_disposition sas_scsi_find_task(struct sas_task *task)
@@ -310,15 +312,6 @@ static enum task_disposition sas_scsi_find_task(struct sas_task *task)
spin_unlock_irqrestore(&core->task_queue_lock, flags);
}
- spin_lock_irqsave(&task->task_state_lock, flags);
- if (task->task_state_flags & SAS_TASK_INITIATOR_ABORTED) {
- spin_unlock_irqrestore(&task->task_state_lock, flags);
- SAS_DPRINTK("%s: task 0x%p already aborted\n",
- __FUNCTION__, task);
- return TASK_IS_ABORTED;
- }
- spin_unlock_irqrestore(&task->task_state_lock, flags);
-
for (i = 0; i < 5; i++) {
SAS_DPRINTK("%s: aborting task 0x%p\n", __FUNCTION__, task);
res = si->dft->lldd_abort_task(task);
@@ -340,15 +333,21 @@ static enum task_disposition sas_scsi_find_task(struct sas_task *task)
SAS_DPRINTK("%s: querying task 0x%p\n",
__FUNCTION__, task);
res = si->dft->lldd_query_task(task);
- if (res == TMF_RESP_FUNC_SUCC) {
+ switch (res) {
+ case TMF_RESP_FUNC_SUCC:
SAS_DPRINTK("%s: task 0x%p at LU\n",
__FUNCTION__, task);
return TASK_IS_AT_LU;
- } else if (res == TMF_RESP_FUNC_COMPLETE) {
+ case TMF_RESP_FUNC_COMPLETE:
SAS_DPRINTK("%s: task 0x%p not at LU\n",
__FUNCTION__, task);
return TASK_IS_NOT_AT_LU;
- }
+ case TMF_RESP_FUNC_FAILED:
+ SAS_DPRINTK("%s: task 0x%p failed to abort\n",
+ __FUNCTION__, task);
+ return TASK_ABORT_FAILED;
+ }
+
}
}
return res;
@@ -398,35 +397,113 @@ static int sas_recover_I_T(struct domain_device *dev)
return res;
}
-void sas_scsi_recover_host(struct Scsi_Host *shost)
+/* Find the sas_phy that's attached to this device */
+struct sas_phy *find_local_sas_phy(struct domain_device *dev)
+{
+ struct domain_device *pdev = dev->parent;
+ struct ex_phy *exphy = NULL;
+ int i;
+
+ /* Directly attached device */
+ if (!pdev)
+ return dev->port->phy;
+
+ /* Otherwise look in the expander */
+ for (i = 0; i < pdev->ex_dev.num_phys; i++)
+ if (!memcmp(dev->sas_addr,
+ pdev->ex_dev.ex_phy[i].attached_sas_addr,
+ SAS_ADDR_SIZE)) {
+ exphy = &pdev->ex_dev.ex_phy[i];
+ break;
+ }
+
+ BUG_ON(!exphy);
+ return exphy->phy;
+}
+
+/* Attempt to send a LUN reset message to a device */
+int sas_eh_device_reset_handler(struct scsi_cmnd *cmd)
+{
+ struct domain_device *dev = cmd_to_domain_dev(cmd);
+ struct sas_internal *i =
+ to_sas_internal(dev->port->ha->core.shost->transportt);
+ struct scsi_lun lun;
+ int res;
+
+ int_to_scsilun(cmd->device->lun, &lun);
+
+ if (!i->dft->lldd_lu_reset)
+ return FAILED;
+
+ res = i->dft->lldd_lu_reset(dev, lun.scsi_lun);
+ if (res == TMF_RESP_FUNC_SUCC || res == TMF_RESP_FUNC_COMPLETE)
+ return SUCCESS;
+
+ return FAILED;
+}
+
+/* Attempt to send a phy (bus) reset */
+int sas_eh_bus_reset_handler(struct scsi_cmnd *cmd)
+{
+ struct domain_device *dev = cmd_to_domain_dev(cmd);
+ struct sas_phy *phy = find_local_sas_phy(dev);
+ int res;
+
+ res = sas_phy_reset(phy, 1);
+ if (res)
+ SAS_DPRINTK("Bus reset of %s failed 0x%x\n",
+ phy->dev.kobj.k_name,
+ res);
+ if (res == TMF_RESP_FUNC_SUCC || res == TMF_RESP_FUNC_COMPLETE)
+ return SUCCESS;
+
+ return FAILED;
+}
+
+/* Try to reset a device */
+static int try_to_reset_cmd_device(struct Scsi_Host *shost,
+ struct scsi_cmnd *cmd)
+{
+ int res;
+
+ if (!shost->hostt->eh_device_reset_handler)
+ goto try_bus_reset;
+
+ res = shost->hostt->eh_device_reset_handler(cmd);
+ if (res == SUCCESS)
+ return res;
+
+try_bus_reset:
+ if (shost->hostt->eh_bus_reset_handler)
+ return shost->hostt->eh_bus_reset_handler(cmd);
+
+ return FAILED;
+}
+
+static int sas_eh_handle_sas_errors(struct Scsi_Host *shost,
+ struct list_head *work_q,
+ struct list_head *done_q)
{
- struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost);
- unsigned long flags;
- LIST_HEAD(error_q);
struct scsi_cmnd *cmd, *n;
enum task_disposition res = TASK_IS_DONE;
- int tmf_resp;
+ int tmf_resp, need_reset;
struct sas_internal *i = to_sas_internal(shost->transportt);
+ unsigned long flags;
+ struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost);
- spin_lock_irqsave(shost->host_lock, flags);
- list_splice_init(&shost->eh_cmd_q, &error_q);
- spin_unlock_irqrestore(shost->host_lock, flags);
-
- SAS_DPRINTK("Enter %s\n", __FUNCTION__);
-
- /* All tasks on this list were marked SAS_TASK_STATE_ABORTED
- * by sas_scsi_timed_out() callback.
- */
Again:
- SAS_DPRINTK("going over list...\n");
- list_for_each_entry_safe(cmd, n, &error_q, eh_entry) {
+ list_for_each_entry_safe(cmd, n, work_q, eh_entry) {
struct sas_task *task = TO_SAS_TASK(cmd);
- list_del_init(&cmd->eh_entry);
- if (!task) {
- SAS_DPRINTK("%s: taskless cmd?!\n", __FUNCTION__);
+ if (!task)
continue;
- }
+
+ list_del_init(&cmd->eh_entry);
+
+ spin_lock_irqsave(&task->task_state_lock, flags);
+ need_reset = task->task_state_flags & SAS_TASK_NEED_DEV_RESET;
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+
SAS_DPRINTK("trying to find task 0x%p\n", task);
res = sas_scsi_find_task(task);
@@ -437,11 +514,15 @@ Again:
SAS_DPRINTK("%s: task 0x%p is done\n", __FUNCTION__,
task);
task->task_done(task);
+ if (need_reset)
+ try_to_reset_cmd_device(shost, cmd);
continue;
case TASK_IS_ABORTED:
SAS_DPRINTK("%s: task 0x%p is aborted\n",
__FUNCTION__, task);
task->task_done(task);
+ if (need_reset)
+ try_to_reset_cmd_device(shost, cmd);
continue;
case TASK_IS_AT_LU:
SAS_DPRINTK("task 0x%p is at LU: lu recover\n", task);
@@ -452,11 +533,14 @@ Again:
SAS_ADDR(task->dev),
cmd->device->lun);
task->task_done(task);
- sas_scsi_clear_queue_lu(&error_q, cmd);
+ if (need_reset)
+ try_to_reset_cmd_device(shost, cmd);
+ sas_scsi_clear_queue_lu(work_q, cmd);
goto Again;
}
/* fallthrough */
case TASK_IS_NOT_AT_LU:
+ case TASK_ABORT_FAILED:
SAS_DPRINTK("task 0x%p is not at LU: I_T recover\n",
task);
tmf_resp = sas_recover_I_T(task->dev);
@@ -464,7 +548,9 @@ Again:
SAS_DPRINTK("I_T %016llx recovered\n",
SAS_ADDR(task->dev->sas_addr));
task->task_done(task);
- sas_scsi_clear_queue_I_T(&error_q, task->dev);
+ if (need_reset)
+ try_to_reset_cmd_device(shost, cmd);
+ sas_scsi_clear_queue_I_T(work_q, task->dev);
goto Again;
}
/* Hammer time :-) */
@@ -477,7 +563,9 @@ Again:
SAS_DPRINTK("clear nexus port:%d "
"succeeded\n", port->id);
task->task_done(task);
- sas_scsi_clear_queue_port(&error_q,
+ if (need_reset)
+ try_to_reset_cmd_device(shost, cmd);
+ sas_scsi_clear_queue_port(work_q,
port);
goto Again;
}
@@ -489,6 +577,8 @@ Again:
SAS_DPRINTK("clear nexus ha "
"succeeded\n");
task->task_done(task);
+ if (need_reset)
+ try_to_reset_cmd_device(shost, cmd);
goto out;
}
}
@@ -502,20 +592,54 @@ Again:
cmd->device->lun);
task->task_done(task);
+ if (need_reset)
+ try_to_reset_cmd_device(shost, cmd);
goto clear_q;
}
}
out:
- scsi_eh_flush_done_q(&ha->eh_done_q);
- SAS_DPRINTK("--- Exit %s\n", __FUNCTION__);
- return;
+ return list_empty(work_q);
clear_q:
SAS_DPRINTK("--- Exit %s -- clear_q\n", __FUNCTION__);
- list_for_each_entry_safe(cmd, n, &error_q, eh_entry) {
+ list_for_each_entry_safe(cmd, n, work_q, eh_entry) {
struct sas_task *task = TO_SAS_TASK(cmd);
list_del_init(&cmd->eh_entry);
task->task_done(task);
}
+ return list_empty(work_q);
+}
+
+void sas_scsi_recover_host(struct Scsi_Host *shost)
+{
+ struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost);
+ unsigned long flags;
+ LIST_HEAD(eh_work_q);
+
+ spin_lock_irqsave(shost->host_lock, flags);
+ list_splice_init(&shost->eh_cmd_q, &eh_work_q);
+ spin_unlock_irqrestore(shost->host_lock, flags);
+
+ SAS_DPRINTK("Enter %s\n", __FUNCTION__);
+ /*
+ * Deal with commands that still have SAS tasks (i.e. they didn't
+ * complete via the normal sas_task completion mechanism)
+ */
+ if (sas_eh_handle_sas_errors(shost, &eh_work_q, &ha->eh_done_q))
+ goto out;
+
+ /*
+ * Now deal with SCSI commands that completed ok but have a an error
+ * code (and hopefully sense data) attached. This is roughly what
+ * scsi_unjam_host does, but we skip scsi_eh_abort_cmds because any
+ * command we see here has no sas_task and is thus unknown to the HA.
+ */
+ if (!scsi_eh_get_sense(&eh_work_q, &ha->eh_done_q))
+ scsi_eh_ready_devs(shost, &eh_work_q, &ha->eh_done_q);
+
+out:
+ scsi_eh_flush_done_q(&ha->eh_done_q);
+ SAS_DPRINTK("--- Exit %s\n", __FUNCTION__);
+ return;
}
enum scsi_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd)
@@ -524,24 +648,30 @@ enum scsi_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd)
unsigned long flags;
if (!task) {
- SAS_DPRINTK("command 0x%p, task 0x%p, gone: EH_HANDLED\n",
- cmd, task);
- return EH_HANDLED;
+ cmd->timeout_per_command /= 2;
+ SAS_DPRINTK("command 0x%p, task 0x%p, gone: %s\n",
+ cmd, task, (cmd->timeout_per_command ?
+ "EH_RESET_TIMER" : "EH_NOT_HANDLED"));
+ if (!cmd->timeout_per_command)
+ return EH_NOT_HANDLED;
+ return EH_RESET_TIMER;
}
spin_lock_irqsave(&task->task_state_lock, flags);
- if (task->task_state_flags & SAS_TASK_INITIATOR_ABORTED) {
- spin_unlock_irqrestore(&task->task_state_lock, flags);
- SAS_DPRINTK("command 0x%p, task 0x%p, aborted by initiator: "
- "EH_NOT_HANDLED\n", cmd, task);
- return EH_NOT_HANDLED;
- }
+ BUG_ON(task->task_state_flags & SAS_TASK_STATE_ABORTED);
if (task->task_state_flags & SAS_TASK_STATE_DONE) {
spin_unlock_irqrestore(&task->task_state_lock, flags);
SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_HANDLED\n",
cmd, task);
return EH_HANDLED;
}
+ if (!(task->task_state_flags & SAS_TASK_AT_INITIATOR)) {
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+ SAS_DPRINTK("command 0x%p, task 0x%p, not at initiator: "
+ "EH_RESET_TIMER\n",
+ cmd, task);
+ return EH_RESET_TIMER;
+ }
task->task_state_flags |= SAS_TASK_STATE_ABORTED;
spin_unlock_irqrestore(&task->task_state_lock, flags);
@@ -557,8 +687,9 @@ struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy)
struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost);
struct domain_device *found_dev = NULL;
int i;
+ unsigned long flags;
- spin_lock(&ha->phy_port_lock);
+ spin_lock_irqsave(&ha->phy_port_lock, flags);
for (i = 0; i < ha->num_phys; i++) {
struct asd_sas_port *port = ha->sas_port[i];
struct domain_device *dev;
@@ -574,7 +705,7 @@ struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy)
spin_unlock(&port->dev_list_lock);
}
found:
- spin_unlock(&ha->phy_port_lock);
+ spin_unlock_irqrestore(&ha->phy_port_lock, flags);
return found_dev;
}
@@ -623,6 +754,8 @@ int sas_slave_configure(struct scsi_device *scsi_dev)
scsi_deactivate_tcq(scsi_dev, 1);
}
+ scsi_dev->allow_restart = 1;
+
return 0;
}
@@ -799,46 +932,42 @@ void sas_shutdown_queue(struct sas_ha_struct *sas_ha)
spin_unlock_irqrestore(&core->task_queue_lock, flags);
}
-static int do_sas_task_abort(struct sas_task *task)
+/*
+ * Call the LLDD task abort routine directly. This function is intended for
+ * use by upper layers that need to tell the LLDD to abort a task.
+ */
+int __sas_task_abort(struct sas_task *task)
{
- struct scsi_cmnd *sc = task->uldd_task;
struct sas_internal *si =
to_sas_internal(task->dev->port->ha->core.shost->transportt);
unsigned long flags;
int res;
spin_lock_irqsave(&task->task_state_lock, flags);
- if (task->task_state_flags & SAS_TASK_STATE_ABORTED) {
+ if (task->task_state_flags & SAS_TASK_STATE_ABORTED ||
+ task->task_state_flags & SAS_TASK_STATE_DONE) {
spin_unlock_irqrestore(&task->task_state_lock, flags);
- SAS_DPRINTK("%s: Task %p already aborted.\n", __FUNCTION__,
+ SAS_DPRINTK("%s: Task %p already finished.\n", __FUNCTION__,
task);
return 0;
}
-
- task->task_state_flags |= SAS_TASK_INITIATOR_ABORTED;
- if (!(task->task_state_flags & SAS_TASK_STATE_DONE))
- task->task_state_flags |= SAS_TASK_STATE_ABORTED;
+ task->task_state_flags |= SAS_TASK_STATE_ABORTED;
spin_unlock_irqrestore(&task->task_state_lock, flags);
if (!si->dft->lldd_abort_task)
return -ENODEV;
res = si->dft->lldd_abort_task(task);
+
+ spin_lock_irqsave(&task->task_state_lock, flags);
if ((task->task_state_flags & SAS_TASK_STATE_DONE) ||
(res == TMF_RESP_FUNC_COMPLETE))
{
- /* SMP commands don't have scsi_cmds(?) */
- if (!sc) {
- task->task_done(task);
- return 0;
- }
- scsi_req_abort_cmd(sc);
- scsi_schedule_eh(sc->device->host);
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+ task->task_done(task);
return 0;
}
- spin_lock_irqsave(&task->task_state_lock, flags);
- task->task_state_flags &= ~SAS_TASK_INITIATOR_ABORTED;
if (!(task->task_state_flags & SAS_TASK_STATE_DONE))
task->task_state_flags &= ~SAS_TASK_STATE_ABORTED;
spin_unlock_irqrestore(&task->task_state_lock, flags);
@@ -846,17 +975,24 @@ static int do_sas_task_abort(struct sas_task *task)
return -EAGAIN;
}
-void sas_task_abort(struct work_struct *work)
+/*
+ * Tell an upper layer that it needs to initiate an abort for a given task.
+ * This should only ever be called by an LLDD.
+ */
+void sas_task_abort(struct sas_task *task)
{
- struct sas_task *task =
- container_of(work, struct sas_task, abort_work);
- int i;
+ struct scsi_cmnd *sc = task->uldd_task;
- for (i = 0; i < 5; i++)
- if (!do_sas_task_abort(task))
+ /* Escape for libsas internal commands */
+ if (!sc) {
+ if (!del_timer(&task->timer))
return;
+ task->timer.function(task->timer.data);
+ return;
+ }
- SAS_DPRINTK("%s: Could not kill task!\n", __FUNCTION__);
+ scsi_req_abort_cmd(sc);
+ scsi_schedule_eh(sc->device->host);
}
EXPORT_SYMBOL_GPL(sas_queuecommand);
@@ -866,5 +1002,9 @@ EXPORT_SYMBOL_GPL(sas_slave_destroy);
EXPORT_SYMBOL_GPL(sas_change_queue_depth);
EXPORT_SYMBOL_GPL(sas_change_queue_type);
EXPORT_SYMBOL_GPL(sas_bios_param);
+EXPORT_SYMBOL_GPL(__sas_task_abort);
EXPORT_SYMBOL_GPL(sas_task_abort);
EXPORT_SYMBOL_GPL(sas_phy_reset);
+EXPORT_SYMBOL_GPL(sas_phy_enable);
+EXPORT_SYMBOL_GPL(sas_eh_device_reset_handler);
+EXPORT_SYMBOL_GPL(sas_eh_bus_reset_handler);
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index afca45cdbce..9d014e5a81c 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -518,6 +518,10 @@ lpfc_handle_eratt(struct lpfc_hba * phba)
struct lpfc_sli *psli = &phba->sli;
struct lpfc_sli_ring *pring;
uint32_t event_data;
+ /* If the pci channel is offline, ignore possible errors,
+ * since we cannot communicate with the pci card anyway. */
+ if (pci_channel_offline(phba->pcidev))
+ return;
if (phba->work_hs & HS_FFER6 ||
phba->work_hs & HS_FFER5) {
@@ -1797,6 +1801,92 @@ lpfc_pci_remove_one(struct pci_dev *pdev)
pci_set_drvdata(pdev, NULL);
}
+/**
+ * lpfc_io_error_detected - called when PCI error is detected
+ * @pdev: Pointer to PCI device
+ * @state: The current pci conneection state
+ *
+ * This function is called after a PCI bus error affecting
+ * this device has been detected.
+ */
+static pci_ers_result_t lpfc_io_error_detected(struct pci_dev *pdev,
+ pci_channel_state_t state)
+{
+ struct Scsi_Host *host = pci_get_drvdata(pdev);
+ struct lpfc_hba *phba = (struct lpfc_hba *)host->hostdata;
+ struct lpfc_sli *psli = &phba->sli;
+ struct lpfc_sli_ring *pring;
+
+ if (state == pci_channel_io_perm_failure) {
+ lpfc_pci_remove_one(pdev);
+ return PCI_ERS_RESULT_DISCONNECT;
+ }
+ pci_disable_device(pdev);
+ /*
+ * There may be I/Os dropped by the firmware.
+ * Error iocb (I/O) on txcmplq and let the SCSI layer
+ * retry it after re-establishing link.
+ */
+ pring = &psli->ring[psli->fcp_ring];
+ lpfc_sli_abort_iocb_ring(phba, pring);
+
+ /* Request a slot reset. */
+ return PCI_ERS_RESULT_NEED_RESET;
+}
+
+/**
+ * lpfc_io_slot_reset - called after the pci bus has been reset.
+ * @pdev: Pointer to PCI device
+ *
+ * Restart the card from scratch, as if from a cold-boot.
+ */
+static pci_ers_result_t lpfc_io_slot_reset(struct pci_dev *pdev)
+{
+ struct Scsi_Host *host = pci_get_drvdata(pdev);
+ struct lpfc_hba *phba = (struct lpfc_hba *)host->hostdata;
+ struct lpfc_sli *psli = &phba->sli;
+ int bars = pci_select_bars(pdev, IORESOURCE_MEM);
+
+ dev_printk(KERN_INFO, &pdev->dev, "recovering from a slot reset.\n");
+ if (pci_enable_device_bars(pdev, bars)) {
+ printk(KERN_ERR "lpfc: Cannot re-enable "
+ "PCI device after reset.\n");
+ return PCI_ERS_RESULT_DISCONNECT;
+ }
+
+ pci_set_master(pdev);
+
+ /* Re-establishing Link */
+ spin_lock_irq(phba->host->host_lock);
+ phba->fc_flag |= FC_ESTABLISH_LINK;
+ psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
+ spin_unlock_irq(phba->host->host_lock);
+
+
+ /* Take device offline; this will perform cleanup */
+ lpfc_offline(phba);
+ lpfc_sli_brdrestart(phba);
+
+ return PCI_ERS_RESULT_RECOVERED;
+}
+
+/**
+ * lpfc_io_resume - called when traffic can start flowing again.
+ * @pdev: Pointer to PCI device
+ *
+ * This callback is called when the error recovery driver tells us that
+ * its OK to resume normal operation.
+ */
+static void lpfc_io_resume(struct pci_dev *pdev)
+{
+ struct Scsi_Host *host = pci_get_drvdata(pdev);
+ struct lpfc_hba *phba = (struct lpfc_hba *)host->hostdata;
+
+ if (lpfc_online(phba) == 0) {
+ mod_timer(&phba->fc_estabtmo, jiffies + HZ * 60);
+ }
+}
+
static struct pci_device_id lpfc_id_table[] = {
{PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_VIPER,
PCI_ANY_ID, PCI_ANY_ID, },
@@ -1857,11 +1947,18 @@ static struct pci_device_id lpfc_id_table[] = {
MODULE_DEVICE_TABLE(pci, lpfc_id_table);
+static struct pci_error_handlers lpfc_err_handler = {
+ .error_detected = lpfc_io_error_detected,
+ .slot_reset = lpfc_io_slot_reset,
+ .resume = lpfc_io_resume,
+};
+
static struct pci_driver lpfc_driver = {
.name = LPFC_DRIVER_NAME,
.id_table = lpfc_id_table,
.probe = lpfc_pci_probe_one,
.remove = __devexit_p(lpfc_pci_remove_one),
+ .err_handler = &lpfc_err_handler,
};
static int __init
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index a4128e19338..9fb6960a8ad 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -2104,6 +2104,10 @@ lpfc_sli_issue_mbox(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmbox, uint32_t flag)
volatile uint32_t word0, ldata;
void __iomem *to_slim;
+ /* If the PCI channel is in offline state, do not post mbox. */
+ if (unlikely(pci_channel_offline(phba->pcidev)))
+ return MBX_NOT_FINISHED;
+
psli = &phba->sli;
spin_lock_irqsave(phba->host->host_lock, drvr_flag);
@@ -2407,6 +2411,10 @@ lpfc_sli_issue_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
struct lpfc_iocbq *nextiocb;
IOCB_t *iocb;
+ /* If the PCI channel is in offline state, do not post iocbs. */
+ if (unlikely(pci_channel_offline(phba->pcidev)))
+ return IOCB_ERROR;
+
/*
* We should never get an IOCB if we are in a < LINK_DOWN state
*/
@@ -3154,6 +3162,10 @@ lpfc_intr_handler(int irq, void *dev_id)
if (unlikely(!phba))
return IRQ_NONE;
+ /* If the pci channel is offline, ignore all the interrupts. */
+ if (unlikely(pci_channel_offline(phba->pcidev)))
+ return IRQ_NONE;
+
phba->sli.slistat.sli_intr++;
/*
diff --git a/drivers/scsi/mac_esp.c b/drivers/scsi/mac_esp.c
index 3586fac9be9..bcb49021b7e 100644
--- a/drivers/scsi/mac_esp.c
+++ b/drivers/scsi/mac_esp.c
@@ -351,7 +351,7 @@ int mac_esp_detect(struct scsi_host_template * tpnt)
for (chipnum = 0; chipnum < chipspresent; chipnum ++) {
struct NCR_ESP * esp;
- esp = esp_allocate(tpnt, (void *) NULL);
+ esp = esp_allocate(tpnt, NULL, 0);
esp->eregs = (struct ESP_regs *) get_base(chipnum);
esp->dma_irq_p = &esp_dafb_dma_irq_p;
diff --git a/drivers/scsi/mac_scsi.c b/drivers/scsi/mac_scsi.c
index a942a21dd87..cdbcaa5ad6c 100644
--- a/drivers/scsi/mac_scsi.c
+++ b/drivers/scsi/mac_scsi.c
@@ -36,7 +36,6 @@
#include <linux/module.h>
#include <linux/signal.h>
-#include <linux/sched.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/blkdev.h>
diff --git a/drivers/scsi/mca_53c9x.c b/drivers/scsi/mca_53c9x.c
index 998a8bbc1a4..d693d0f2139 100644
--- a/drivers/scsi/mca_53c9x.c
+++ b/drivers/scsi/mca_53c9x.c
@@ -122,7 +122,7 @@ static int mca_esp_detect(struct scsi_host_template *tpnt)
if ((slot = mca_find_adapter(*id_to_check, 0)) !=
MCA_NOTFOUND)
{
- esp = esp_allocate(tpnt, (void *) NULL);
+ esp = esp_allocate(tpnt, NULL, 0);
pos[0] = mca_read_stored_pos(slot, 2);
pos[1] = mca_read_stored_pos(slot, 3);
diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
index 77d9d3804cc..0aa3304f6b9 100644
--- a/drivers/scsi/megaraid.c
+++ b/drivers/scsi/megaraid.c
@@ -92,7 +92,7 @@ static struct mega_hbas mega_hbas[MAX_CONTROLLERS];
/*
* The File Operations structure for the serial/ioctl interface of the driver
*/
-static struct file_operations megadev_fops = {
+static const struct file_operations megadev_fops = {
.owner = THIS_MODULE,
.ioctl = megadev_ioctl,
.open = megadev_open,
@@ -5072,7 +5072,7 @@ static int __init megaraid_init(void)
"megaraid: failed to create megaraid root\n");
}
#endif
- error = pci_module_init(&megaraid_pci_driver);
+ error = pci_register_driver(&megaraid_pci_driver);
if (error) {
#ifdef CONFIG_PROC_FS
remove_proc_entry("megaraid", &proc_root);
diff --git a/drivers/scsi/megaraid/mbox_defs.h b/drivers/scsi/megaraid/mbox_defs.h
index 3052869f51f..170399ef06f 100644
--- a/drivers/scsi/megaraid/mbox_defs.h
+++ b/drivers/scsi/megaraid/mbox_defs.h
@@ -748,7 +748,7 @@ typedef struct {
/**
- * private_bios_data - bios private data for boot devices
+ * struct private_bios_data - bios private data for boot devices
* @geometry : bits 0-3 - BIOS geometry, 0x0001 - 1GB, 0x0010 - 2GB,
* 0x1000 - 8GB, Others values are invalid
* @unused : bits 4-7 are unused
diff --git a/drivers/scsi/megaraid/mega_common.h b/drivers/scsi/megaraid/mega_common.h
index b50e27e6602..26e1e6c5565 100644
--- a/drivers/scsi/megaraid/mega_common.h
+++ b/drivers/scsi/megaraid/mega_common.h
@@ -46,17 +46,17 @@
/**
* scb_t - scsi command control block
- * @param ccb : command control block for individual driver
- * @param list : list of control blocks
- * @param gp : general purpose field for LLDs
- * @param sno : all SCBs have a serial number
- * @param scp : associated scsi command
- * @param state : current state of scb
- * @param dma_dir : direction of data transfer
- * @param dma_type : transfer with sg list, buffer, or no data transfer
- * @param dev_channel : actual channel on the device
- * @param dev_target : actual target on the device
- * @param status : completion status
+ * @ccb : command control block for individual driver
+ * @list : list of control blocks
+ * @gp : general purpose field for LLDs
+ * @sno : all SCBs have a serial number
+ * @scp : associated scsi command
+ * @state : current state of scb
+ * @dma_dir : direction of data transfer
+ * @dma_type : transfer with sg list, buffer, or no data transfer
+ * @dev_channel : actual channel on the device
+ * @dev_target : actual target on the device
+ * @status : completion status
*
* This is our central data structure to issue commands the each driver.
* Driver specific data structures are maintained in the ccb field.
@@ -99,42 +99,42 @@ typedef struct {
/**
* struct adapter_t - driver's initialization structure
- * @param dpc_h : tasklet handle
- * @param pdev : pci configuration pointer for kernel
- * @param host : pointer to host structure of mid-layer
- * @param lock : synchronization lock for mid-layer and driver
- * @param quiescent : driver is quiescent for now.
- * @param outstanding_cmds : number of commands pending in the driver
- * @param kscb_list : pointer to the bulk of SCBs pointers for IO
- * @param kscb_pool : pool of free scbs for IO
- * @param kscb_pool_lock : lock for pool of free scbs
- * @param pend_list : pending commands list
- * @param pend_list_lock : exlusion lock for pending commands list
- * @param completed_list : list of completed commands
- * @param completed_list_lock : exclusion lock for list of completed commands
- * @param sglen : max sg elements supported
- * @param device_ids : to convert kernel device addr to our devices.
- * @param raid_device : raid adapter specific pointer
- * @param max_channel : maximum channel number supported - inclusive
- * @param max_target : max target supported - inclusive
- * @param max_lun : max lun supported - inclusive
- * @param unique_id : unique identifier for each adapter
- * @param irq : IRQ for this adapter
- * @param ito : internal timeout value, (-1) means no timeout
- * @param ibuf : buffer to issue internal commands
- * @param ibuf_dma_h : dma handle for the above buffer
- * @param uscb_list : SCB pointers for user cmds, common mgmt module
- * @param uscb_pool : pool of SCBs for user commands
- * @param uscb_pool_lock : exclusion lock for these SCBs
- * @param max_cmds : max outstanding commands
- * @param fw_version : firmware version
- * @param bios_version : bios version
- * @param max_cdb_sz : biggest CDB size supported.
- * @param ha : is high availability present - clustering
- * @param init_id : initiator ID, the default value should be 7
- * @param max_sectors : max sectors per request
- * @param cmd_per_lun : max outstanding commands per LUN
- * @param being_detached : set when unloading, no more mgmt calls
+ * @aram dpc_h : tasklet handle
+ * @pdev : pci configuration pointer for kernel
+ * @host : pointer to host structure of mid-layer
+ * @lock : synchronization lock for mid-layer and driver
+ * @quiescent : driver is quiescent for now.
+ * @outstanding_cmds : number of commands pending in the driver
+ * @kscb_list : pointer to the bulk of SCBs pointers for IO
+ * @kscb_pool : pool of free scbs for IO
+ * @kscb_pool_lock : lock for pool of free scbs
+ * @pend_list : pending commands list
+ * @pend_list_lock : exclusion lock for pending commands list
+ * @completed_list : list of completed commands
+ * @completed_list_lock : exclusion lock for list of completed commands
+ * @sglen : max sg elements supported
+ * @device_ids : to convert kernel device addr to our devices.
+ * @raid_device : raid adapter specific pointer
+ * @max_channel : maximum channel number supported - inclusive
+ * @max_target : max target supported - inclusive
+ * @max_lun : max lun supported - inclusive
+ * @unique_id : unique identifier for each adapter
+ * @irq : IRQ for this adapter
+ * @ito : internal timeout value, (-1) means no timeout
+ * @ibuf : buffer to issue internal commands
+ * @ibuf_dma_h : dma handle for the above buffer
+ * @uscb_list : SCB pointers for user cmds, common mgmt module
+ * @uscb_pool : pool of SCBs for user commands
+ * @uscb_pool_lock : exclusion lock for these SCBs
+ * @max_cmds : max outstanding commands
+ * @fw_version : firmware version
+ * @bios_version : bios version
+ * @max_cdb_sz : biggest CDB size supported.
+ * @ha : is high availability present - clustering
+ * @init_id : initiator ID, the default value should be 7
+ * @max_sectors : max sectors per request
+ * @cmd_per_lun : max outstanding commands per LUN
+ * @being_detached : set when unloading, no more mgmt calls
*
*
* mraid_setup_device_map() can be called anytime after the device map is
@@ -211,23 +211,23 @@ typedef struct {
#define SCP2ADAPTER(scp) (adapter_t *)SCSIHOST2ADAP(SCP2HOST(scp))
-/**
- * MRAID_GET_DEVICE_MAP - device ids
- * @param adp - Adapter's soft state
- * @param scp - mid-layer scsi command pointer
- * @param p_chan - physical channel on the controller
- * @param target - target id of the device or logical drive number
- * @param islogical - set if the command is for the logical drive
- *
- * Macro to retrieve information about device class, logical or physical and
- * the corresponding physical channel and target or logical drive number
- **/
#define MRAID_IS_LOGICAL(adp, scp) \
(SCP2CHANNEL(scp) == (adp)->max_channel) ? 1 : 0
#define MRAID_IS_LOGICAL_SDEV(adp, sdev) \
(sdev->channel == (adp)->max_channel) ? 1 : 0
+/**
+ * MRAID_GET_DEVICE_MAP - device ids
+ * @adp : adapter's soft state
+ * @scp : mid-layer scsi command pointer
+ * @p_chan : physical channel on the controller
+ * @target : target id of the device or logical drive number
+ * @islogical : set if the command is for the logical drive
+ *
+ * Macro to retrieve information about device class, logical or physical and
+ * the corresponding physical channel and target or logical drive number
+ */
#define MRAID_GET_DEVICE_MAP(adp, scp, p_chan, target, islogical) \
/* \
* Is the request coming for the virtual channel \
@@ -271,10 +271,10 @@ typedef struct {
#define ASSERT(expression)
#endif
-/*
+/**
* struct mraid_pci_blk - structure holds DMA memory block info
- * @param vaddr : virtual address to a memory block
- * @param dma_addr : DMA handle to a memory block
+ * @vaddr : virtual address to a memory block
+ * @dma_addr : DMA handle to a memory block
*
* This structure is filled up for the caller. It is the responsibilty of the
* caller to allocate this array big enough to store addresses for all
diff --git a/drivers/scsi/megaraid/megaraid_ioctl.h b/drivers/scsi/megaraid/megaraid_ioctl.h
index b8aa34202ec..706fa05a187 100644
--- a/drivers/scsi/megaraid/megaraid_ioctl.h
+++ b/drivers/scsi/megaraid/megaraid_ioctl.h
@@ -22,23 +22,23 @@
#include "mbox_defs.h"
+/*
+ * console messages debug levels
+ */
+#define CL_ANN 0 /* print unconditionally, announcements */
+#define CL_DLEVEL1 1 /* debug level 1, informative */
+#define CL_DLEVEL2 2 /* debug level 2, verbose */
+#define CL_DLEVEL3 3 /* debug level 3, very verbose */
+
/**
* con_log() - console log routine
- * @param level : indicates the severity of the message.
- * @fparam mt : format string
+ * @level : indicates the severity of the message.
+ * @fmt : format string
*
* con_log displays the error messages on the console based on the current
* debug level. Also it attaches the appropriate kernel severity level with
* the message.
- *
- *
- * consolge messages debug levels
*/
-#define CL_ANN 0 /* print unconditionally, announcements */
-#define CL_DLEVEL1 1 /* debug level 1, informative */
-#define CL_DLEVEL2 2 /* debug level 2, verbose */
-#define CL_DLEVEL3 3 /* debug level 3, very verbose */
-
#define con_log(level, fmt) if (LSI_DBGLVL >= level) printk fmt;
/*
@@ -157,14 +157,14 @@ typedef struct uioc {
/**
* struct mraid_hba_info - information about the controller
*
- * @param pci_vendor_id : PCI vendor id
- * @param pci_device_id : PCI device id
- * @param subsystem_vendor_id : PCI subsystem vendor id
- * @param subsystem_device_id : PCI subsystem device id
- * @param baseport : base port of hba memory
- * @param pci_bus : PCI bus
- * @param pci_dev_fn : PCI device/function values
- * @param irq : interrupt vector for the device
+ * @pci_vendor_id : PCI vendor id
+ * @pci_device_id : PCI device id
+ * @subsystem_vendor_id : PCI subsystem vendor id
+ * @subsystem_device_id : PCI subsystem device id
+ * @baseport : base port of hba memory
+ * @pci_bus : PCI bus
+ * @pci_dev_fn : PCI device/function values
+ * @irq : interrupt vector for the device
*
* Extended information of 256 bytes about the controller. Align on the single
* byte boundary so that 32-bit applications can be run on 64-bit platform
diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c
index 7bac86dda88..04d0b6918c6 100644
--- a/drivers/scsi/megaraid/megaraid_mbox.c
+++ b/drivers/scsi/megaraid/megaraid_mbox.c
@@ -10,13 +10,13 @@
* 2 of the License, or (at your option) any later version.
*
* FILE : megaraid_mbox.c
- * Version : v2.20.4.9 (Jul 16 2006)
+ * Version : v2.20.5.1 (Nov 16 2006)
*
* Authors:
- * Atul Mukker <Atul.Mukker@lsil.com>
- * Sreenivas Bagalkote <Sreenivas.Bagalkote@lsil.com>
- * Manoj Jose <Manoj.Jose@lsil.com>
- * Seokmann Ju <Seokmann.Ju@lsil.com>
+ * Atul Mukker <Atul.Mukker@lsi.com>
+ * Sreenivas Bagalkote <Sreenivas.Bagalkote@lsi.com>
+ * Manoj Jose <Manoj.Jose@lsi.com>
+ * Seokmann Ju
*
* List of supported controllers
*
@@ -107,6 +107,7 @@ static int megaraid_mbox_support_random_del(adapter_t *);
static int megaraid_mbox_get_max_sg(adapter_t *);
static void megaraid_mbox_enum_raid_scsi(adapter_t *);
static void megaraid_mbox_flush_cache(adapter_t *);
+static int megaraid_mbox_fire_sync_cmd(adapter_t *);
static void megaraid_mbox_display_scb(adapter_t *, scb_t *);
static void megaraid_mbox_setup_device_map(adapter_t *);
@@ -137,7 +138,7 @@ static int wait_till_fw_empty(adapter_t *);
-MODULE_AUTHOR("sju@lsil.com");
+MODULE_AUTHOR("megaraidlinux@lsi.com");
MODULE_DESCRIPTION("LSI Logic MegaRAID Mailbox Driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(MEGARAID_VERSION);
@@ -146,7 +147,7 @@ MODULE_VERSION(MEGARAID_VERSION);
* ### modules parameters for driver ###
*/
-/**
+/*
* Set to enable driver to expose unconfigured disk to kernel
*/
static int megaraid_expose_unconf_disks = 0;
@@ -154,7 +155,7 @@ module_param_named(unconf_disks, megaraid_expose_unconf_disks, int, 0);
MODULE_PARM_DESC(unconf_disks,
"Set to expose unconfigured disks to kernel (default=0)");
-/**
+/*
* driver wait time if the adapter's mailbox is busy
*/
static unsigned int max_mbox_busy_wait = MBOX_BUSY_WAIT;
@@ -162,7 +163,7 @@ module_param_named(busy_wait, max_mbox_busy_wait, int, 0);
MODULE_PARM_DESC(busy_wait,
"Max wait for mailbox in microseconds if busy (default=10)");
-/**
+/*
* number of sectors per IO command
*/
static unsigned int megaraid_max_sectors = MBOX_MAX_SECTORS;
@@ -170,7 +171,7 @@ module_param_named(max_sectors, megaraid_max_sectors, int, 0);
MODULE_PARM_DESC(max_sectors,
"Maximum number of sectors per IO command (default=128)");
-/**
+/*
* number of commands per logical unit
*/
static unsigned int megaraid_cmd_per_lun = MBOX_DEF_CMD_PER_LUN;
@@ -179,7 +180,7 @@ MODULE_PARM_DESC(cmd_per_lun,
"Maximum number of commands per logical unit (default=64)");
-/**
+/*
* Fast driver load option, skip scanning for physical devices during load.
* This would result in non-disk devices being skipped during driver load
* time. These can be later added though, using /proc/scsi/scsi
@@ -190,7 +191,7 @@ MODULE_PARM_DESC(fast_load,
"Faster loading of the driver, skips physical devices! (default=0)");
-/**
+/*
* mraid_debug level - threshold for amount of information to be displayed by
* the driver. This level can be changed through modules parameters, ioctl or
* sysfs/proc interface. By default, print the announcement messages only.
@@ -337,7 +338,7 @@ static struct device_attribute *megaraid_sdev_attrs[] = {
*
* Return value:
* actual depth set
- **/
+ */
static int megaraid_change_queue_depth(struct scsi_device *sdev, int qdepth)
{
if (qdepth > MBOX_MAX_SCSI_CMDS)
@@ -369,8 +370,8 @@ static struct scsi_host_template megaraid_template_g = {
* megaraid_init - module load hook
*
* We register ourselves as hotplug enabled module and let PCI subsystem
- * discover our adaters
- **/
+ * discover our adapters.
+ */
static int __init
megaraid_init(void)
{
@@ -405,7 +406,7 @@ megaraid_init(void)
/**
* megaraid_exit - driver unload entry point
*
- * We simply unwrap the megaraid_init routine here
+ * We simply unwrap the megaraid_init routine here.
*/
static void __exit
megaraid_exit(void)
@@ -421,12 +422,12 @@ megaraid_exit(void)
/**
* megaraid_probe_one - PCI hotplug entry point
- * @param pdev : handle to this controller's PCI configuration space
- * @param id : pci device id of the class of controllers
+ * @pdev : handle to this controller's PCI configuration space
+ * @id : pci device id of the class of controllers
*
* This routine should be called whenever a new adapter is detected by the
* PCI hotplug susbsytem.
- **/
+ */
static int __devinit
megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
{
@@ -542,16 +543,15 @@ out_probe_one:
/**
- * megaraid_detach_one - release the framework resources and call LLD release
- * routine
- * @param pdev : handle for our PCI cofiguration space
+ * megaraid_detach_one - release framework resources and call LLD release routine
+ * @pdev : handle for our PCI cofiguration space
*
* This routine is called during driver unload. We free all the allocated
* resources and call the corresponding LLD so that it can also release all
* its resources.
*
- * This routine is also called from the PCI hotplug system
- **/
+ * This routine is also called from the PCI hotplug system.
+ */
static void
megaraid_detach_one(struct pci_dev *pdev)
{
@@ -615,9 +615,9 @@ megaraid_detach_one(struct pci_dev *pdev)
/**
* megaraid_mbox_shutdown - PCI shutdown for megaraid HBA
- * @param device : generice driver model device
+ * @pdev : generic driver model device
*
- * Shutdown notification, perform flush cache
+ * Shutdown notification, perform flush cache.
*/
static void
megaraid_mbox_shutdown(struct pci_dev *pdev)
@@ -643,10 +643,10 @@ megaraid_mbox_shutdown(struct pci_dev *pdev)
/**
* megaraid_io_attach - attach a device with the IO subsystem
- * @param adapter : controller's soft state
+ * @adapter : controller's soft state
*
- * Attach this device with the IO subsystem
- **/
+ * Attach this device with the IO subsystem.
+ */
static int
megaraid_io_attach(adapter_t *adapter)
{
@@ -695,10 +695,10 @@ megaraid_io_attach(adapter_t *adapter)
/**
* megaraid_io_detach - detach a device from the IO subsystem
- * @param adapter : controller's soft state
+ * @adapter : controller's soft state
*
- * Detach this device from the IO subsystem
- **/
+ * Detach this device from the IO subsystem.
+ */
static void
megaraid_io_detach(adapter_t *adapter)
{
@@ -722,13 +722,13 @@ megaraid_io_detach(adapter_t *adapter)
/**
* megaraid_init_mbox - initialize controller
- * @param adapter - our soft state
+ * @adapter : our soft state
*
- * . Allocate 16-byte aligned mailbox memory for firmware handshake
- * . Allocate controller's memory resources
- * . Find out all initialization data
- * . Allocate memory required for all the commands
- * . Use internal library of FW routines, build up complete soft state
+ * - Allocate 16-byte aligned mailbox memory for firmware handshake
+ * - Allocate controller's memory resources
+ * - Find out all initialization data
+ * - Allocate memory required for all the commands
+ * - Use internal library of FW routines, build up complete soft state
*/
static int __devinit
megaraid_init_mbox(adapter_t *adapter)
@@ -779,33 +779,39 @@ megaraid_init_mbox(adapter_t *adapter)
goto out_release_regions;
}
- //
- // Setup the rest of the soft state using the library of FW routines
- //
+ /* initialize the mutual exclusion lock for the mailbox */
+ spin_lock_init(&raid_dev->mailbox_lock);
- // request IRQ and register the interrupt service routine
+ /* allocate memory required for commands */
+ if (megaraid_alloc_cmd_packets(adapter) != 0)
+ goto out_iounmap;
+
+ /*
+ * Issue SYNC cmd to flush the pending cmds in the adapter
+ * and initialize its internal state
+ */
+
+ if (megaraid_mbox_fire_sync_cmd(adapter))
+ con_log(CL_ANN, ("megaraid: sync cmd failed\n"));
+
+ /*
+ * Setup the rest of the soft state using the library of
+ * FW routines
+ */
+
+ /* request IRQ and register the interrupt service routine */
if (request_irq(adapter->irq, megaraid_isr, IRQF_SHARED, "megaraid",
adapter)) {
con_log(CL_ANN, (KERN_WARNING
"megaraid: Couldn't register IRQ %d!\n", adapter->irq));
+ goto out_alloc_cmds;
- goto out_iounmap;
- }
-
-
- // initialize the mutual exclusion lock for the mailbox
- spin_lock_init(&raid_dev->mailbox_lock);
-
- // allocate memory required for commands
- if (megaraid_alloc_cmd_packets(adapter) != 0) {
- goto out_free_irq;
}
// Product info
- if (megaraid_mbox_product_info(adapter) != 0) {
- goto out_alloc_cmds;
- }
+ if (megaraid_mbox_product_info(adapter) != 0)
+ goto out_free_irq;
// Do we support extended CDBs
adapter->max_cdb_sz = 10;
@@ -874,9 +880,8 @@ megaraid_init_mbox(adapter_t *adapter)
* Allocate resources required to issue FW calls, when sysfs is
* accessed
*/
- if (megaraid_sysfs_alloc_resources(adapter) != 0) {
- goto out_alloc_cmds;
- }
+ if (megaraid_sysfs_alloc_resources(adapter) != 0)
+ goto out_free_irq;
// Set the DMA mask to 64-bit. All supported controllers as capable of
// DMA in this range
@@ -920,10 +925,10 @@ megaraid_init_mbox(adapter_t *adapter)
out_free_sysfs_res:
megaraid_sysfs_free_resources(adapter);
-out_alloc_cmds:
- megaraid_free_cmd_packets(adapter);
out_free_irq:
free_irq(adapter->irq, adapter);
+out_alloc_cmds:
+ megaraid_free_cmd_packets(adapter);
out_iounmap:
iounmap(raid_dev->baseaddr);
out_release_regions:
@@ -937,7 +942,7 @@ out_free_raid_dev:
/**
* megaraid_fini_mbox - undo controller initialization
- * @param adapter : our soft state
+ * @adapter : our soft state
*/
static void
megaraid_fini_mbox(adapter_t *adapter)
@@ -967,12 +972,12 @@ megaraid_fini_mbox(adapter_t *adapter)
/**
* megaraid_alloc_cmd_packets - allocate shared mailbox
- * @param adapter : soft state of the raid controller
+ * @adapter : soft state of the raid controller
*
* Allocate and align the shared mailbox. This maibox is used to issue
* all the commands. For IO based controllers, the mailbox is also regsitered
* with the FW. Allocate memory for all commands as well.
- * This is our big allocator
+ * This is our big allocator.
*/
static int
megaraid_alloc_cmd_packets(adapter_t *adapter)
@@ -1132,9 +1137,9 @@ out_free_common_mbox:
/**
* megaraid_free_cmd_packets - free memory
- * @param adapter : soft state of the raid controller
+ * @adapter : soft state of the raid controller
*
- * Release memory resources allocated for commands
+ * Release memory resources allocated for commands.
*/
static void
megaraid_free_cmd_packets(adapter_t *adapter)
@@ -1156,10 +1161,10 @@ megaraid_free_cmd_packets(adapter_t *adapter)
/**
* megaraid_mbox_setup_dma_pools - setup dma pool for command packets
- * @param adapter : HBA soft state
+ * @adapter : HBA soft state
*
- * setup the dma pools for mailbox, passthru and extended passthru structures,
- * and scatter-gather lists
+ * Setup the dma pools for mailbox, passthru and extended passthru structures,
+ * and scatter-gather lists.
*/
static int
megaraid_mbox_setup_dma_pools(adapter_t *adapter)
@@ -1252,10 +1257,10 @@ fail_setup_dma_pool:
/**
* megaraid_mbox_teardown_dma_pools - teardown dma pools for command packets
- * @param adapter : HBA soft state
+ * @adapter : HBA soft state
*
- * teardown the dma pool for mailbox, passthru and extended passthru
- * structures, and scatter-gather lists
+ * Teardown the dma pool for mailbox, passthru and extended passthru
+ * structures, and scatter-gather lists.
*/
static void
megaraid_mbox_teardown_dma_pools(adapter_t *adapter)
@@ -1300,10 +1305,11 @@ megaraid_mbox_teardown_dma_pools(adapter_t *adapter)
/**
* megaraid_alloc_scb - detach and return a scb from the free list
* @adapter : controller's soft state
+ * @scp : pointer to the scsi command to be executed
*
- * return the scb from the head of the free list. NULL if there are none
- * available
- **/
+ * Return the scb from the head of the free list. %NULL if there are none
+ * available.
+ */
static scb_t *
megaraid_alloc_scb(adapter_t *adapter, struct scsi_cmnd *scp)
{
@@ -1337,11 +1343,11 @@ megaraid_alloc_scb(adapter_t *adapter, struct scsi_cmnd *scp)
* @adapter : controller's soft state
* @scb : scb to be freed
*
- * return the scb back to the free list of scbs. The caller must 'flush' the
+ * Return the scb back to the free list of scbs. The caller must 'flush' the
* SCB before calling us. E.g., performing pci_unamp and/or pci_sync etc.
* NOTE NOTE: Make sure the scb is not on any list before calling this
* routine.
- **/
+ */
static inline void
megaraid_dealloc_scb(adapter_t *adapter, scb_t *scb)
{
@@ -1362,10 +1368,10 @@ megaraid_dealloc_scb(adapter_t *adapter, scb_t *scb)
/**
* megaraid_mbox_mksgl - make the scatter-gather list
- * @adapter - controller's soft state
- * @scb - scsi control block
+ * @adapter : controller's soft state
+ * @scb : scsi control block
*
- * prepare the scatter-gather list
+ * Prepare the scatter-gather list.
*/
static int
megaraid_mbox_mksgl(adapter_t *adapter, scb_t *scb)
@@ -1435,10 +1441,10 @@ megaraid_mbox_mksgl(adapter_t *adapter, scb_t *scb)
/**
* mbox_post_cmd - issue a mailbox command
- * @adapter - controller's soft state
- * @scb - command to be issued
+ * @adapter : controller's soft state
+ * @scb : command to be issued
*
- * post the command to the controller if mailbox is availble.
+ * Post the command to the controller if mailbox is available.
*/
static int
mbox_post_cmd(adapter_t *adapter, scb_t *scb)
@@ -1518,7 +1524,7 @@ mbox_post_cmd(adapter_t *adapter, scb_t *scb)
* Queue entry point for mailbox based controllers.
*/
static int
-megaraid_queue_command(struct scsi_cmnd *scp, void (* done)(struct scsi_cmnd *))
+megaraid_queue_command(struct scsi_cmnd *scp, void (*done)(struct scsi_cmnd *))
{
adapter_t *adapter;
scb_t *scb;
@@ -1548,15 +1554,15 @@ megaraid_queue_command(struct scsi_cmnd *scp, void (* done)(struct scsi_cmnd *))
}
/**
- * megaraid_mbox_build_cmd - transform the mid-layer scsi command to megaraid
- * firmware lingua
- * @adapter - controller's soft state
- * @scp - mid-layer scsi command pointer
- * @busy - set if request could not be completed because of lack of
+ * megaraid_mbox_build_cmd - transform the mid-layer scsi commands
+ * @adapter : controller's soft state
+ * @scp : mid-layer scsi command pointer
+ * @busy : set if request could not be completed because of lack of
* resources
*
- * convert the command issued by mid-layer to format understood by megaraid
- * firmware. We also complete certain command without sending them to firmware
+ * Transform the mid-layer scsi command to megaraid firmware lingua.
+ * Convert the command issued by mid-layer to format understood by megaraid
+ * firmware. We also complete certain commands without sending them to firmware.
*/
static scb_t *
megaraid_mbox_build_cmd(adapter_t *adapter, struct scsi_cmnd *scp, int *busy)
@@ -1937,9 +1943,9 @@ megaraid_mbox_build_cmd(adapter_t *adapter, struct scsi_cmnd *scp, int *busy)
/**
* megaraid_mbox_runpendq - execute commands queued in the pending queue
* @adapter : controller's soft state
- * @scb : SCB to be queued in the pending list
+ * @scb_q : SCB to be queued in the pending list
*
- * scan the pending list for commands which are not yet issued and try to
+ * Scan the pending list for commands which are not yet issued and try to
* post to the controller. The SCB can be a null pointer, which would indicate
* no SCB to be queue, just try to execute the ones in the pending list.
*
@@ -2012,11 +2018,11 @@ megaraid_mbox_runpendq(adapter_t *adapter, scb_t *scb_q)
/**
* megaraid_mbox_prepare_pthru - prepare a command for physical devices
- * @adapter - pointer to controller's soft state
- * @scb - scsi control block
- * @scp - scsi command from the mid-layer
+ * @adapter : pointer to controller's soft state
+ * @scb : scsi control block
+ * @scp : scsi command from the mid-layer
*
- * prepare a command for the scsi physical devices
+ * Prepare a command for the scsi physical devices.
*/
static void
megaraid_mbox_prepare_pthru(adapter_t *adapter, scb_t *scb,
@@ -2060,12 +2066,12 @@ megaraid_mbox_prepare_pthru(adapter_t *adapter, scb_t *scb,
/**
* megaraid_mbox_prepare_epthru - prepare a command for physical devices
- * @adapter - pointer to controller's soft state
- * @scb - scsi control block
- * @scp - scsi command from the mid-layer
+ * @adapter : pointer to controller's soft state
+ * @scb : scsi control block
+ * @scp : scsi command from the mid-layer
*
- * prepare a command for the scsi physical devices. This rountine prepares
- * commands for devices which can take extended CDBs (>10 bytes)
+ * Prepare a command for the scsi physical devices. This rountine prepares
+ * commands for devices which can take extended CDBs (>10 bytes).
*/
static void
megaraid_mbox_prepare_epthru(adapter_t *adapter, scb_t *scb,
@@ -2109,9 +2115,9 @@ megaraid_mbox_prepare_epthru(adapter_t *adapter, scb_t *scb,
/**
* megaraid_ack_sequence - interrupt ack sequence for memory mapped HBAs
- * @adapter - controller's soft state
+ * @adapter : controller's soft state
*
- * Interrupt ackrowledgement sequence for memory mapped HBAs. Find out the
+ * Interrupt acknowledgement sequence for memory mapped HBAs. Find out the
* completed command and put them on the completed list for later processing.
*
* Returns: 1 if the interrupt is valid, 0 otherwise
@@ -2224,9 +2230,8 @@ megaraid_ack_sequence(adapter_t *adapter)
/**
* megaraid_isr - isr for memory based mailbox based controllers
- * @irq - irq
- * @devp - pointer to our soft state
- * @regs - unused
+ * @irq : irq
+ * @devp : pointer to our soft state
*
* Interrupt service routine for memory-mapped mailbox controllers.
*/
@@ -2671,7 +2676,7 @@ megaraid_abort_handler(struct scsi_cmnd *scp)
* the FW is still live, in which case the outstanding commands counter mut go
* down to 0. If that happens, also issue the reservation reset command to
* relinquish (possible) reservations on the logical drives connected to this
- * host
+ * host.
**/
static int
megaraid_reset_handler(struct scsi_cmnd *scp)
@@ -2823,11 +2828,11 @@ megaraid_reset_handler(struct scsi_cmnd *scp)
/**
* mbox_post_sync_cmd() - blocking command to the mailbox based controllers
- * @adapter - controller's soft state
- * @raw_mbox - the mailbox
+ * @adapter : controller's soft state
+ * @raw_mbox : the mailbox
*
* Issue a scb in synchronous and non-interrupt mode for mailbox based
- * controllers
+ * controllers.
*/
static int
mbox_post_sync_cmd(adapter_t *adapter, uint8_t raw_mbox[])
@@ -2955,12 +2960,12 @@ blocked_mailbox:
/**
* mbox_post_sync_cmd_fast - blocking command to the mailbox based controllers
- * @adapter - controller's soft state
- * @raw_mbox - the mailbox
+ * @adapter : controller's soft state
+ * @raw_mbox : the mailbox
*
* Issue a scb in synchronous and non-interrupt mode for mailbox based
* controllers. This is a faster version of the synchronous command and
- * therefore can be called in interrupt-context as well
+ * therefore can be called in interrupt-context as well.
*/
static int
mbox_post_sync_cmd_fast(adapter_t *adapter, uint8_t raw_mbox[])
@@ -3008,10 +3013,10 @@ mbox_post_sync_cmd_fast(adapter_t *adapter, uint8_t raw_mbox[])
/**
* megaraid_busywait_mbox() - Wait until the controller's mailbox is available
- * @raid_dev - RAID device (HBA) soft state
+ * @raid_dev : RAID device (HBA) soft state
*
- * wait until the controller's mailbox is available to accept more commands.
- * wait for at most 1 second
+ * Wait until the controller's mailbox is available to accept more commands.
+ * Wait for at most 1 second.
*/
static int
megaraid_busywait_mbox(mraid_device_t *raid_dev)
@@ -3032,9 +3037,9 @@ megaraid_busywait_mbox(mraid_device_t *raid_dev)
/**
* megaraid_mbox_product_info - some static information about the controller
- * @adapter - our soft state
+ * @adapter : our soft state
*
- * issue commands to the controller to grab some parameters required by our
+ * Issue commands to the controller to grab some parameters required by our
* caller.
*/
static int
@@ -3157,10 +3162,10 @@ megaraid_mbox_product_info(adapter_t *adapter)
/**
* megaraid_mbox_extended_cdb - check for support for extended CDBs
- * @adapter - soft state for the controller
+ * @adapter : soft state for the controller
*
- * this routine check whether the controller in question supports extended
- * ( > 10 bytes ) CDBs
+ * This routine check whether the controller in question supports extended
+ * ( > 10 bytes ) CDBs.
*/
static int
megaraid_mbox_extended_cdb(adapter_t *adapter)
@@ -3193,8 +3198,8 @@ megaraid_mbox_extended_cdb(adapter_t *adapter)
/**
* megaraid_mbox_support_ha - Do we support clustering
- * @adapter - soft state for the controller
- * @init_id - ID of the initiator
+ * @adapter : soft state for the controller
+ * @init_id : ID of the initiator
*
* Determine if the firmware supports clustering and the ID of the initiator.
*/
@@ -3236,9 +3241,9 @@ megaraid_mbox_support_ha(adapter_t *adapter, uint16_t *init_id)
/**
* megaraid_mbox_support_random_del - Do we support random deletion
- * @adapter - soft state for the controller
+ * @adapter : soft state for the controller
*
- * Determine if the firmware supports random deletion
+ * Determine if the firmware supports random deletion.
* Return: 1 is operation supported, 0 otherwise
*/
static int
@@ -3271,10 +3276,10 @@ megaraid_mbox_support_random_del(adapter_t *adapter)
/**
* megaraid_mbox_get_max_sg - maximum sg elements supported by the firmware
- * @adapter - soft state for the controller
+ * @adapter : soft state for the controller
*
* Find out the maximum number of scatter-gather elements supported by the
- * firmware
+ * firmware.
*/
static int
megaraid_mbox_get_max_sg(adapter_t *adapter)
@@ -3311,10 +3316,10 @@ megaraid_mbox_get_max_sg(adapter_t *adapter)
/**
* megaraid_mbox_enum_raid_scsi - enumerate the RAID and SCSI channels
- * @adapter - soft state for the controller
+ * @adapter : soft state for the controller
*
- * Enumerate the RAID and SCSI channels for ROMB platoforms so that channels
- * can be exported as regular SCSI channels
+ * Enumerate the RAID and SCSI channels for ROMB platforms so that channels
+ * can be exported as regular SCSI channels.
*/
static void
megaraid_mbox_enum_raid_scsi(adapter_t *adapter)
@@ -3348,9 +3353,9 @@ megaraid_mbox_enum_raid_scsi(adapter_t *adapter)
/**
* megaraid_mbox_flush_cache - flush adapter and disks cache
- * @param adapter : soft state for the controller
+ * @adapter : soft state for the controller
*
- * Flush adapter cache followed by disks cache
+ * Flush adapter cache followed by disks cache.
*/
static void
megaraid_mbox_flush_cache(adapter_t *adapter)
@@ -3380,13 +3385,91 @@ megaraid_mbox_flush_cache(adapter_t *adapter)
/**
+ * megaraid_mbox_fire_sync_cmd - fire the sync cmd
+ * @adapter : soft state for the controller
+ *
+ * Clears the pending cmds in FW and reinits its RAID structs.
+ */
+static int
+megaraid_mbox_fire_sync_cmd(adapter_t *adapter)
+{
+ mbox_t *mbox;
+ uint8_t raw_mbox[sizeof(mbox_t)];
+ mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter);
+ mbox64_t *mbox64;
+ int status = 0;
+ int i;
+ uint32_t dword;
+
+ mbox = (mbox_t *)raw_mbox;
+
+ memset((caddr_t)raw_mbox, 0, sizeof(mbox_t));
+
+ raw_mbox[0] = 0xFF;
+
+ mbox64 = raid_dev->mbox64;
+ mbox = raid_dev->mbox;
+
+ /* Wait until mailbox is free */
+ if (megaraid_busywait_mbox(raid_dev) != 0) {
+ status = 1;
+ goto blocked_mailbox;
+ }
+
+ /* Copy mailbox data into host structure */
+ memcpy((caddr_t)mbox, (caddr_t)raw_mbox, 16);
+ mbox->cmdid = 0xFE;
+ mbox->busy = 1;
+ mbox->poll = 0;
+ mbox->ack = 0;
+ mbox->numstatus = 0;
+ mbox->status = 0;
+
+ wmb();
+ WRINDOOR(raid_dev, raid_dev->mbox_dma | 0x1);
+
+ /* Wait for maximum 1 min for status to post.
+ * If the Firmware SUPPORTS the ABOVE COMMAND,
+ * mbox->cmd will be set to 0
+ * else
+ * the firmware will reject the command with
+ * mbox->numstatus set to 1
+ */
+
+ i = 0;
+ status = 0;
+ while (!mbox->numstatus && mbox->cmd == 0xFF) {
+ rmb();
+ msleep(1);
+ i++;
+ if (i > 1000 * 60) {
+ status = 1;
+ break;
+ }
+ }
+ if (mbox->numstatus == 1)
+ status = 1; /*cmd not supported*/
+
+ /* Check for interrupt line */
+ dword = RDOUTDOOR(raid_dev);
+ WROUTDOOR(raid_dev, dword);
+ WRINDOOR(raid_dev,2);
+
+ return status;
+
+blocked_mailbox:
+ con_log(CL_ANN, (KERN_WARNING "megaraid: blocked mailbox\n"));
+ return status;
+}
+
+/**
* megaraid_mbox_display_scb - display SCB information, mostly debug purposes
- * @param adapter : controllers' soft state
- * @param scb : SCB to be displayed
- * @param level : debug level for console print
+ * @adapter : controller's soft state
+ * @scb : SCB to be displayed
+ * @level : debug level for console print
*
* Diplay information about the given SCB iff the current debug level is
- * verbose
+ * verbose.
*/
static void
megaraid_mbox_display_scb(adapter_t *adapter, scb_t *scb)
@@ -3434,7 +3517,7 @@ megaraid_mbox_display_scb(adapter_t *adapter, scb_t *scb)
* scsi addresses and megaraid scsi and logical drive addresses. We export
* scsi devices on their actual addresses, whereas the logical drives are
* exported on a virtual scsi channel.
- **/
+ */
static void
megaraid_mbox_setup_device_map(adapter_t *adapter)
{
@@ -3472,7 +3555,7 @@ megaraid_mbox_setup_device_map(adapter_t *adapter)
/**
* megaraid_cmm_register - register with the mangement module
- * @param adapter : HBA soft state
+ * @adapter : HBA soft state
*
* Register with the management module, which allows applications to issue
* ioctl calls to the drivers. This interface is used by the management module
@@ -3562,11 +3645,11 @@ megaraid_cmm_register(adapter_t *adapter)
/**
* megaraid_cmm_unregister - un-register with the mangement module
- * @param adapter : HBA soft state
+ * @adapter : HBA soft state
*
* Un-register with the management module.
* FIXME: mgmt module must return failure for unregister if it has pending
- * commands in LLD
+ * commands in LLD.
*/
static int
megaraid_cmm_unregister(adapter_t *adapter)
@@ -3579,9 +3662,9 @@ megaraid_cmm_unregister(adapter_t *adapter)
/**
* megaraid_mbox_mm_handler - interface for CMM to issue commands to LLD
- * @param drvr_data : LLD specific data
- * @param kioc : CMM interface packet
- * @param action : command action
+ * @drvr_data : LLD specific data
+ * @kioc : CMM interface packet
+ * @action : command action
*
* This routine is invoked whenever the Common Mangement Module (CMM) has a
* command for us. The 'action' parameter specifies if this is a new command
@@ -3634,8 +3717,8 @@ megaraid_mbox_mm_handler(unsigned long drvr_data, uioc_t *kioc, uint32_t action)
/**
* megaraid_mbox_mm_command - issues commands routed through CMM
- * @param adapter : HBA soft state
- * @param kioc : management command packet
+ * @adapter : HBA soft state
+ * @kioc : management command packet
*
* Issues commands, which are routed through the management module.
*/
@@ -3804,8 +3887,8 @@ megaraid_mbox_mm_done(adapter_t *adapter, scb_t *scb)
/**
* gather_hbainfo - HBA characteristics for the applications
- * @param adapter : HBA soft state
- * @param hinfo : pointer to the caller's host info strucuture
+ * @adapter : HBA soft state
+ * @hinfo : pointer to the caller's host info strucuture
*/
static int
gather_hbainfo(adapter_t *adapter, mraid_hba_info_t *hinfo)
@@ -3839,16 +3922,15 @@ gather_hbainfo(adapter_t *adapter, mraid_hba_info_t *hinfo)
/**
* megaraid_sysfs_alloc_resources - allocate sysfs related resources
+ * @adapter : controller's soft state
*
* Allocate packets required to issue FW calls whenever the sysfs attributes
* are read. These attributes would require up-to-date information from the
* FW. Also set up resources for mutual exclusion to share these resources and
* the wait queue.
*
- * @param adapter : controller's soft state
- *
- * @return 0 on success
- * @return -ERROR_CODE on failure
+ * Return 0 on success.
+ * Return -ERROR_CODE on failure.
*/
static int
megaraid_sysfs_alloc_resources(adapter_t *adapter)
@@ -3885,10 +3967,9 @@ megaraid_sysfs_alloc_resources(adapter_t *adapter)
/**
* megaraid_sysfs_free_resources - free sysfs related resources
+ * @adapter : controller's soft state
*
* Free packets allocated for sysfs FW commands
- *
- * @param adapter : controller's soft state
*/
static void
megaraid_sysfs_free_resources(adapter_t *adapter)
@@ -3907,10 +3988,9 @@ megaraid_sysfs_free_resources(adapter_t *adapter)
/**
* megaraid_sysfs_get_ldmap_done - callback for get ldmap
+ * @uioc : completed packet
*
* Callback routine called in the ISR/tasklet context for get ldmap call
- *
- * @param uioc : completed packet
*/
static void
megaraid_sysfs_get_ldmap_done(uioc_t *uioc)
@@ -3926,12 +4006,11 @@ megaraid_sysfs_get_ldmap_done(uioc_t *uioc)
/**
* megaraid_sysfs_get_ldmap_timeout - timeout handling for get ldmap
+ * @data : timed out packet
*
* Timeout routine to recover and return to application, in case the adapter
- * has stopped responding. A timeout of 60 seconds for this command seem like
- * a good value
- *
- * @param uioc : timed out packet
+ * has stopped responding. A timeout of 60 seconds for this command seems like
+ * a good value.
*/
static void
megaraid_sysfs_get_ldmap_timeout(unsigned long data)
@@ -3948,6 +4027,7 @@ megaraid_sysfs_get_ldmap_timeout(unsigned long data)
/**
* megaraid_sysfs_get_ldmap - get update logical drive map
+ * @adapter : controller's soft state
*
* This routine will be called whenever user reads the logical drive
* attributes, go get the current logical drive mapping table from the
@@ -3959,10 +4039,8 @@ megaraid_sysfs_get_ldmap_timeout(unsigned long data)
* standalone libary. For now, this should suffice since there is no other
* user of this interface.
*
- * @param adapter : controller's soft state
- *
- * @return 0 on success
- * @return -1 on failure
+ * Return 0 on success.
+ * Return -1 on failure.
*/
static int
megaraid_sysfs_get_ldmap(adapter_t *adapter)
@@ -4064,13 +4142,12 @@ megaraid_sysfs_get_ldmap(adapter_t *adapter)
/**
* megaraid_sysfs_show_app_hndl - display application handle for this adapter
+ * @cdev : class device object representation for the host
+ * @buf : buffer to send data to
*
* Display the handle used by the applications while executing management
* tasks on the adapter. We invoke a management module API to get the adapter
* handle, since we do not interface with applications directly.
- *
- * @param cdev : class device object representation for the host
- * @param buf : buffer to send data to
*/
static ssize_t
megaraid_sysfs_show_app_hndl(struct class_device *cdev, char *buf)
@@ -4087,16 +4164,18 @@ megaraid_sysfs_show_app_hndl(struct class_device *cdev, char *buf)
/**
* megaraid_sysfs_show_ldnum - display the logical drive number for this device
+ * @dev : device object representation for the scsi device
+ * @attr : device attribute to show
+ * @buf : buffer to send data to
*
* Display the logical drive number for the device in question, if it a valid
- * logical drive. For physical devices, "-1" is returned
- * The logical drive number is displayed in following format
+ * logical drive. For physical devices, "-1" is returned.
+ *
+ * The logical drive number is displayed in following format:
*
* <SCSI ID> <LD NUM> <LD STICKY ID> <APP ADAPTER HANDLE>
- * <int> <int> <int> <int>
*
- * @param dev : device object representation for the scsi device
- * @param buf : buffer to send data to
+ * <int> <int> <int> <int>
*/
static ssize_t
megaraid_sysfs_show_ldnum(struct device *dev, struct device_attribute *attr, char *buf)
diff --git a/drivers/scsi/megaraid/megaraid_mbox.h b/drivers/scsi/megaraid/megaraid_mbox.h
index 2b5a3285f79..9de803cebd4 100644
--- a/drivers/scsi/megaraid/megaraid_mbox.h
+++ b/drivers/scsi/megaraid/megaraid_mbox.h
@@ -21,8 +21,8 @@
#include "megaraid_ioctl.h"
-#define MEGARAID_VERSION "2.20.4.9"
-#define MEGARAID_EXT_VERSION "(Release Date: Sun Jul 16 12:27:22 EST 2006)"
+#define MEGARAID_VERSION "2.20.5.1"
+#define MEGARAID_EXT_VERSION "(Release Date: Thu Nov 16 15:32:35 EST 2006)"
/*
@@ -146,27 +146,27 @@ typedef struct {
/**
* mraid_device_t - adapter soft state structure for mailbox controllers
- * @param una_mbox64 : 64-bit mbox - unaligned
- * @param una_mbox64_dma : mbox dma addr - unaligned
- * @param mbox : 32-bit mbox - aligned
- * @param mbox64 : 64-bit mbox - aligned
- * @param mbox_dma : mbox dma addr - aligned
- * @param mailbox_lock : exclusion lock for the mailbox
- * @param baseport : base port of hba memory
- * @param baseaddr : mapped addr of hba memory
- * @param mbox_pool : pool of mailboxes
- * @param mbox_pool_handle : handle for the mailbox pool memory
- * @param epthru_pool : a pool for extended passthru commands
- * @param epthru_pool_handle : handle to the pool above
- * @param sg_pool : pool of scatter-gather lists for this driver
- * @param sg_pool_handle : handle to the pool above
- * @param ccb_list : list of our command control blocks
- * @param uccb_list : list of cmd control blocks for mgmt module
- * @param umbox64 : array of mailbox for user commands (cmm)
- * @param pdrv_state : array for state of each physical drive.
- * @param last_disp : flag used to show device scanning
- * @param hw_error : set if FW not responding
- * @param fast_load : If set, skip physical device scanning
+ * @una_mbox64 : 64-bit mbox - unaligned
+ * @una_mbox64_dma : mbox dma addr - unaligned
+ * @mbox : 32-bit mbox - aligned
+ * @mbox64 : 64-bit mbox - aligned
+ * @mbox_dma : mbox dma addr - aligned
+ * @mailbox_lock : exclusion lock for the mailbox
+ * @baseport : base port of hba memory
+ * @baseaddr : mapped addr of hba memory
+ * @mbox_pool : pool of mailboxes
+ * @mbox_pool_handle : handle for the mailbox pool memory
+ * @epthru_pool : a pool for extended passthru commands
+ * @epthru_pool_handle : handle to the pool above
+ * @sg_pool : pool of scatter-gather lists for this driver
+ * @sg_pool_handle : handle to the pool above
+ * @ccb_list : list of our command control blocks
+ * @uccb_list : list of cmd control blocks for mgmt module
+ * @umbox64 : array of mailbox for user commands (cmm)
+ * @pdrv_state : array for state of each physical drive.
+ * @last_disp : flag used to show device scanning
+ * @hw_error : set if FW not responding
+ * @fast_load : If set, skip physical device scanning
* @channel_class : channel class, RAID or SCSI
* @sysfs_sem : semaphore to serialize access to sysfs res.
* @sysfs_uioc : management packet to issue FW calls from sysfs
diff --git a/drivers/scsi/megaraid/megaraid_mm.c b/drivers/scsi/megaraid/megaraid_mm.c
index d85b9a8f1b8..f33a678f089 100644
--- a/drivers/scsi/megaraid/megaraid_mm.c
+++ b/drivers/scsi/megaraid/megaraid_mm.c
@@ -67,7 +67,7 @@ static struct list_head adapters_list_g;
static wait_queue_head_t wait_q;
-static struct file_operations lsi_fops = {
+static const struct file_operations lsi_fops = {
.open = mraid_mm_open,
.ioctl = mraid_mm_ioctl,
#ifdef CONFIG_COMPAT
@@ -78,10 +78,10 @@ static struct file_operations lsi_fops = {
/**
* mraid_mm_open - open routine for char node interface
- * @inod : unused
+ * @inode : unused
* @filep : unused
*
- * allow ioctl operations by apps only if they superuser privilege
+ * Allow ioctl operations by apps only if they have superuser privilege.
*/
static int
mraid_mm_open(struct inode *inode, struct file *filep)
@@ -214,7 +214,9 @@ mraid_mm_ioctl(struct inode *inode, struct file *filep, unsigned int cmd,
/**
* mraid_mm_get_adapter - Returns corresponding adapters for the mimd packet
* @umimd : User space mimd_t ioctl packet
- * @adapter : pointer to the adapter (OUT)
+ * @rval : returned success/error status
+ *
+ * The function return value is a pointer to the located @adapter.
*/
static mraid_mmadp_t *
mraid_mm_get_adapter(mimd_t __user *umimd, int *rval)
@@ -252,11 +254,11 @@ mraid_mm_get_adapter(mimd_t __user *umimd, int *rval)
return adapter;
}
-/*
- * handle_drvrcmd - This routine checks if the opcode is a driver
- * cmd and if it is, handles it.
+/**
+ * handle_drvrcmd - Checks if the opcode is a driver cmd and if it is, handles it.
* @arg : packet sent by the user app
* @old_ioctl : mimd if 1; uioc otherwise
+ * @rval : pointer for command's returned value (not function status)
*/
static int
handle_drvrcmd(void __user *arg, uint8_t old_ioctl, int *rval)
@@ -322,8 +324,8 @@ old_packet:
/**
* mimd_to_kioc - Converter from old to new ioctl format
- *
* @umimd : user space old MIMD IOCTL
+ * @adp : adapter softstate
* @kioc : kernel space new format IOCTL
*
* Routine to convert MIMD interface IOCTL to new interface IOCTL packet. The
@@ -474,7 +476,6 @@ mimd_to_kioc(mimd_t __user *umimd, mraid_mmadp_t *adp, uioc_t *kioc)
/**
* mraid_mm_attch_buf - Attach a free dma buffer for required size
- *
* @adp : Adapter softstate
* @kioc : kioc that the buffer needs to be attached to
* @xferlen : required length for buffer
@@ -607,7 +608,6 @@ mraid_mm_alloc_kioc(mraid_mmadp_t *adp)
/**
* mraid_mm_dealloc_kioc - Return kioc to free pool
- *
* @adp : Adapter softstate
* @kioc : uioc_t node to be returned to free pool
*/
@@ -652,7 +652,6 @@ mraid_mm_dealloc_kioc(mraid_mmadp_t *adp, uioc_t *kioc)
/**
* lld_ioctl - Routine to issue ioctl to low level drvr
- *
* @adp : The adapter handle
* @kioc : The ioctl packet with kernel addresses
*/
@@ -705,7 +704,6 @@ lld_ioctl(mraid_mmadp_t *adp, uioc_t *kioc)
/**
* ioctl_done - callback from the low level driver
- *
* @kioc : completed ioctl packet
*/
static void
@@ -756,9 +754,8 @@ ioctl_done(uioc_t *kioc)
}
-/*
- * lld_timedout : callback from the expired timer
- *
+/**
+ * lld_timedout - callback from the expired timer
* @ptr : ioctl packet that timed out
*/
static void
@@ -776,8 +773,7 @@ lld_timedout(unsigned long ptr)
/**
- * kioc_to_mimd : Converter from new back to old format
- *
+ * kioc_to_mimd - Converter from new back to old format
* @kioc : Kernel space IOCTL packet (successfully issued)
* @mimd : User space MIMD packet
*/
@@ -855,7 +851,6 @@ kioc_to_mimd(uioc_t *kioc, mimd_t __user *mimd)
/**
* hinfo_to_cinfo - Convert new format hba info into old format
- *
* @hinfo : New format, more comprehensive adapter info
* @cinfo : Old format adapter info to support mimd_t apps
*/
@@ -878,10 +873,9 @@ hinfo_to_cinfo(mraid_hba_info_t *hinfo, mcontroller_t *cinfo)
}
-/*
- * mraid_mm_register_adp - Registration routine for low level drvrs
- *
- * @adp : Adapter objejct
+/**
+ * mraid_mm_register_adp - Registration routine for low level drivers
+ * @lld_adp : Adapter objejct
*/
int
mraid_mm_register_adp(mraid_mmadp_t *lld_adp)
@@ -1007,15 +1001,14 @@ memalloc_error:
/**
* mraid_mm_adapter_app_handle - return the application handle for this adapter
+ * @unique_id : adapter unique identifier
*
- * For the given driver data, locate the adadpter in our global list and
+ * For the given driver data, locate the adapter in our global list and
* return the corresponding handle, which is also used by applications to
* uniquely identify an adapter.
*
- * @param unique_id : adapter unique identifier
- *
- * @return adapter handle if found in the list
- * @return 0 if adapter could not be located, should never happen though
+ * Return adapter handle if found in the list.
+ * Return 0 if adapter could not be located, should never happen though.
*/
uint32_t
mraid_mm_adapter_app_handle(uint32_t unique_id)
@@ -1040,7 +1033,6 @@ mraid_mm_adapter_app_handle(uint32_t unique_id)
/**
* mraid_mm_setup_dma_pools - Set up dma buffer pools per adapter
- *
* @adp : Adapter softstate
*
* We maintain a pool of dma buffers per each adapter. Each pool has one
@@ -1093,11 +1085,11 @@ dma_pool_setup_error:
}
-/*
+/**
* mraid_mm_unregister_adp - Unregister routine for low level drivers
- * Assume no outstanding ioctls to llds.
- *
* @unique_id : UID of the adpater
+ *
+ * Assumes no outstanding ioctls to llds.
*/
int
mraid_mm_unregister_adp(uint32_t unique_id)
@@ -1131,7 +1123,6 @@ mraid_mm_unregister_adp(uint32_t unique_id)
/**
* mraid_mm_free_adp_resources - Free adapter softstate
- *
* @adp : Adapter softstate
*/
static void
@@ -1162,7 +1153,6 @@ mraid_mm_free_adp_resources(mraid_mmadp_t *adp)
/**
* mraid_mm_teardown_dma_pools - Free all per adapter dma buffers
- *
* @adp : Adapter softstate
*/
static void
@@ -1190,7 +1180,7 @@ mraid_mm_teardown_dma_pools(mraid_mmadp_t *adp)
}
/**
- * mraid_mm_init : Module entry point
+ * mraid_mm_init - Module entry point
*/
static int __init
mraid_mm_init(void)
@@ -1214,10 +1204,13 @@ mraid_mm_init(void)
}
+#ifdef CONFIG_COMPAT
/**
- * mraid_mm_compat_ioctl : 32bit to 64bit ioctl conversion routine
+ * mraid_mm_compat_ioctl - 32bit to 64bit ioctl conversion routine
+ * @filep : file operations pointer (ignored)
+ * @cmd : ioctl command
+ * @arg : user ioctl packet
*/
-#ifdef CONFIG_COMPAT
static long
mraid_mm_compat_ioctl(struct file *filep, unsigned int cmd,
unsigned long arg)
@@ -1231,7 +1224,7 @@ mraid_mm_compat_ioctl(struct file *filep, unsigned int cmd,
#endif
/**
- * mraid_mm_exit : Module exit point
+ * mraid_mm_exit - Module exit point
*/
static void __exit
mraid_mm_exit(void)
diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c
index b5bdd0d7a8b..7a812677ff8 100644
--- a/drivers/scsi/megaraid/megaraid_sas.c
+++ b/drivers/scsi/megaraid/megaraid_sas.c
@@ -10,11 +10,13 @@
* 2 of the License, or (at your option) any later version.
*
* FILE : megaraid_sas.c
- * Version : v00.00.03.05
+ * Version : v00.00.03.10-rc1
*
* Authors:
- * Sreenivas Bagalkote <Sreenivas.Bagalkote@lsi.com>
- * Sumant Patro <Sumant.Patro@lsi.com>
+ * (email-id : megaraidlinux@lsi.com)
+ * Sreenivas Bagalkote
+ * Sumant Patro
+ * Bo Yang
*
* List of supported controllers
*
@@ -35,6 +37,7 @@
#include <asm/uaccess.h>
#include <linux/fs.h>
#include <linux/compat.h>
+#include <linux/blkdev.h>
#include <linux/mutex.h>
#include <scsi/scsi.h>
@@ -841,6 +844,11 @@ megasas_queue_command(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd *))
instance = (struct megasas_instance *)
scmd->device->host->hostdata;
+
+ /* Don't process if we have already declared adapter dead */
+ if (instance->hw_crit_error)
+ return SCSI_MLQUEUE_HOST_BUSY;
+
scmd->scsi_done = done;
scmd->result = 0;
@@ -850,6 +858,18 @@ megasas_queue_command(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd *))
goto out_done;
}
+ switch (scmd->cmnd[0]) {
+ case SYNCHRONIZE_CACHE:
+ /*
+ * FW takes care of flush cache on its own
+ * No need to send it down
+ */
+ scmd->result = DID_OK << 16;
+ goto out_done;
+ default:
+ break;
+ }
+
cmd = megasas_get_cmd(instance);
if (!cmd)
return SCSI_MLQUEUE_HOST_BUSY;
@@ -1010,6 +1030,49 @@ static int megasas_reset_bus_host(struct scsi_cmnd *scmd)
}
/**
+ * megasas_bios_param - Returns disk geometry for a disk
+ * @sdev: device handle
+ * @bdev: block device
+ * @capacity: drive capacity
+ * @geom: geometry parameters
+ */
+static int
+megasas_bios_param(struct scsi_device *sdev, struct block_device *bdev,
+ sector_t capacity, int geom[])
+{
+ int heads;
+ int sectors;
+ sector_t cylinders;
+ unsigned long tmp;
+ /* Default heads (64) & sectors (32) */
+ heads = 64;
+ sectors = 32;
+
+ tmp = heads * sectors;
+ cylinders = capacity;
+
+ sector_div(cylinders, tmp);
+
+ /*
+ * Handle extended translation size for logical drives > 1Gb
+ */
+
+ if (capacity >= 0x200000) {
+ heads = 255;
+ sectors = 63;
+ tmp = heads*sectors;
+ cylinders = capacity;
+ sector_div(cylinders, tmp);
+ }
+
+ geom[0] = heads;
+ geom[1] = sectors;
+ geom[2] = cylinders;
+
+ return 0;
+}
+
+/**
* megasas_service_aen - Processes an event notification
* @instance: Adapter soft state
* @cmd: AEN command completed by the ISR
@@ -1049,6 +1112,7 @@ static struct scsi_host_template megasas_template = {
.eh_device_reset_handler = megasas_reset_device,
.eh_bus_reset_handler = megasas_reset_bus_host,
.eh_host_reset_handler = megasas_reset_bus_host,
+ .bios_param = megasas_bios_param,
.use_clustering = ENABLE_CLUSTERING,
};
@@ -1282,11 +1346,13 @@ megasas_deplete_reply_queue(struct megasas_instance *instance, u8 alt_status)
if(instance->instancet->clear_intr(instance->reg_set))
return IRQ_NONE;
+ if (instance->hw_crit_error)
+ goto out_done;
/*
* Schedule the tasklet for cmd completion
*/
tasklet_schedule(&instance->isr_tasklet);
-
+out_done:
return IRQ_HANDLED;
}
@@ -1741,6 +1807,10 @@ static void megasas_complete_cmd_dpc(unsigned long instance_addr)
struct megasas_cmd *cmd;
struct megasas_instance *instance = (struct megasas_instance *)instance_addr;
+ /* If we have already declared adapter dead, donot complete cmds */
+ if (instance->hw_crit_error)
+ return;
+
producer = *instance->producer;
consumer = *instance->consumer;
@@ -2655,9 +2725,9 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
* For each user buffer, create a mirror buffer and copy in
*/
for (i = 0; i < ioc->sge_count; i++) {
- kbuff_arr[i] = pci_alloc_consistent(instance->pdev,
+ kbuff_arr[i] = dma_alloc_coherent(&instance->pdev->dev,
ioc->sgl[i].iov_len,
- &buf_handle);
+ &buf_handle, GFP_KERNEL);
if (!kbuff_arr[i]) {
printk(KERN_DEBUG "megasas: Failed to alloc "
"kernel SGL buffer for IOCTL \n");
@@ -2684,8 +2754,8 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
}
if (ioc->sense_len) {
- sense = pci_alloc_consistent(instance->pdev, ioc->sense_len,
- &sense_handle);
+ sense = dma_alloc_coherent(&instance->pdev->dev, ioc->sense_len,
+ &sense_handle, GFP_KERNEL);
if (!sense) {
error = -ENOMEM;
goto out;
@@ -2744,12 +2814,12 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
out:
if (sense) {
- pci_free_consistent(instance->pdev, ioc->sense_len,
+ dma_free_coherent(&instance->pdev->dev, ioc->sense_len,
sense, sense_handle);
}
for (i = 0; i < ioc->sge_count && kbuff_arr[i]; i++) {
- pci_free_consistent(instance->pdev,
+ dma_free_coherent(&instance->pdev->dev,
kern_sge32[i].length,
kbuff_arr[i], kern_sge32[i].phys_addr);
}
@@ -2913,7 +2983,7 @@ megasas_mgmt_compat_ioctl(struct file *file, unsigned int cmd,
/*
* File operations structure for management interface
*/
-static struct file_operations megasas_mgmt_fops = {
+static const struct file_operations megasas_mgmt_fops = {
.owner = THIS_MODULE,
.open = megasas_mgmt_open,
.release = megasas_mgmt_release,
diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
index 55eddcf8eb1..e862992ee37 100644
--- a/drivers/scsi/megaraid/megaraid_sas.h
+++ b/drivers/scsi/megaraid/megaraid_sas.h
@@ -15,12 +15,12 @@
#ifndef LSI_MEGARAID_SAS_H
#define LSI_MEGARAID_SAS_H
-/**
+/*
* MegaRAID SAS Driver meta data
*/
-#define MEGASAS_VERSION "00.00.03.05"
-#define MEGASAS_RELDATE "Oct 02, 2006"
-#define MEGASAS_EXT_VERSION "Mon Oct 02 11:21:32 PDT 2006"
+#define MEGASAS_VERSION "00.00.03.10-rc1"
+#define MEGASAS_RELDATE "Feb 14, 2007"
+#define MEGASAS_EXT_VERSION "Wed Feb 14 10:14:25 PST 2007"
/*
* Device IDs
@@ -40,7 +40,7 @@
* "message frames"
*/
-/**
+/*
* FW posts its state in upper 4 bits of outbound_msg_0 register
*/
#define MFI_STATE_MASK 0xF0000000
@@ -58,7 +58,7 @@
#define MEGAMFI_FRAME_SIZE 64
-/**
+/*
* During FW init, clear pending cmds & reset state using inbound_msg_0
*
* ABORT : Abort all pending cmds
@@ -78,7 +78,7 @@
MFI_INIT_MFIMODE| \
MFI_INIT_ABORT
-/**
+/*
* MFI frame flags
*/
#define MFI_FRAME_POST_IN_REPLY_QUEUE 0x0000
@@ -92,12 +92,12 @@
#define MFI_FRAME_DIR_READ 0x0010
#define MFI_FRAME_DIR_BOTH 0x0018
-/**
+/*
* Definition for cmd_status
*/
#define MFI_CMD_STATUS_POLL_MODE 0xFF
-/**
+/*
* MFI command opcodes
*/
#define MFI_CMD_INIT 0x00
@@ -128,7 +128,7 @@
#define MR_DCMD_CLUSTER_RESET_ALL 0x08010100
#define MR_DCMD_CLUSTER_RESET_LD 0x08010200
-/**
+/*
* MFI command completion codes
*/
enum MFI_STAT {
diff --git a/drivers/scsi/mvme147.c b/drivers/scsi/mvme147.c
index 1ddd7a11a95..be41aadccae 100644
--- a/drivers/scsi/mvme147.c
+++ b/drivers/scsi/mvme147.c
@@ -1,7 +1,6 @@
#include <linux/types.h>
#include <linux/mm.h>
#include <linux/blkdev.h>
-#include <linux/sched.h>
#include <linux/interrupt.h>
#include <asm/page.h>
diff --git a/drivers/scsi/mvme16x.c b/drivers/scsi/mvme16x.c
index 890e9e232da..575fe6f7e0e 100644
--- a/drivers/scsi/mvme16x.c
+++ b/drivers/scsi/mvme16x.c
@@ -6,7 +6,6 @@
#include <linux/types.h>
#include <linux/mm.h>
#include <linux/blkdev.h>
-#include <linux/sched.h>
#include <asm/page.h>
#include <asm/pgtable.h>
diff --git a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c
index 7c13f6f4a4c..f6f561d26bf 100644
--- a/drivers/scsi/nsp32.c
+++ b/drivers/scsi/nsp32.c
@@ -27,7 +27,6 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/timer.h>
diff --git a/drivers/scsi/oktagon_esp.c b/drivers/scsi/oktagon_esp.c
index c116a6ae3c5..26a6d55faf3 100644
--- a/drivers/scsi/oktagon_esp.c
+++ b/drivers/scsi/oktagon_esp.c
@@ -133,7 +133,7 @@ int oktagon_esp_detect(struct scsi_host_template *tpnt)
eregs = (struct ESP_regs *)(address + OKTAGON_ESP_ADDR);
/* This line was 5 lines lower */
- esp = esp_allocate(tpnt, (void *)board+OKTAGON_ESP_ADDR);
+ esp = esp_allocate(tpnt, (void *)board + OKTAGON_ESP_ADDR, 0);
/* we have to shift the registers only one bit for oktagon */
esp->shift = 1;
diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c
index 7d231106790..a967fadb743 100644
--- a/drivers/scsi/osst.c
+++ b/drivers/scsi/osst.c
@@ -521,10 +521,10 @@ static void osst_init_aux(struct osst_tape * STp, int frame_type, int frame_seq_
break;
default: ; /* probably FILL */
}
- aux->filemark_cnt = ntohl(STp->filemark_cnt);
- aux->phys_fm = ntohl(0xffffffff);
- aux->last_mark_ppos = ntohl(STp->last_mark_ppos);
- aux->last_mark_lbn = ntohl(STp->last_mark_lbn);
+ aux->filemark_cnt = htonl(STp->filemark_cnt);
+ aux->phys_fm = htonl(0xffffffff);
+ aux->last_mark_ppos = htonl(STp->last_mark_ppos);
+ aux->last_mark_lbn = htonl(STp->last_mark_lbn);
}
/*
@@ -5522,7 +5522,7 @@ __setup("osst=", osst_setup);
#endif
-static struct file_operations osst_fops = {
+static const struct file_operations osst_fops = {
.owner = THIS_MODULE,
.read = osst_read,
.write = osst_write,
@@ -5574,14 +5574,14 @@ static ssize_t osst_version_show(struct device_driver *ddd, char *buf)
static DRIVER_ATTR(version, S_IRUGO, osst_version_show, NULL);
-static int osst_create_driverfs_files(struct device_driver *driverfs)
+static int osst_create_sysfs_files(struct device_driver *sysfs)
{
- return driver_create_file(driverfs, &driver_attr_version);
+ return driver_create_file(sysfs, &driver_attr_version);
}
-static void osst_remove_driverfs_files(struct device_driver *driverfs)
+static void osst_remove_sysfs_files(struct device_driver *sysfs)
{
- driver_remove_file(driverfs, &driver_attr_version);
+ driver_remove_file(sysfs, &driver_attr_version);
}
/*
@@ -5953,7 +5953,7 @@ static int __init init_osst(void)
if (err)
goto err_out_chrdev;
- err = osst_create_driverfs_files(&osst_template.gendrv);
+ err = osst_create_sysfs_files(&osst_template.gendrv);
if (err)
goto err_out_scsidrv;
@@ -5973,7 +5973,7 @@ static void __exit exit_osst (void)
int i;
struct osst_tape * STp;
- osst_remove_driverfs_files(&osst_template.gendrv);
+ osst_remove_sysfs_files(&osst_template.gendrv);
scsi_unregister_driver(&osst_template.gendrv);
unregister_chrdev(OSST_MAJOR, "osst");
osst_sysfs_cleanup();
diff --git a/drivers/scsi/osst.h b/drivers/scsi/osst.h
index 1e426f5d0ed..2cc7b5a1606 100644
--- a/drivers/scsi/osst.h
+++ b/drivers/scsi/osst.h
@@ -288,11 +288,11 @@ typedef struct {
#else
#error "Please fix <asm/byteorder.h>"
#endif
- u16 max_speed; /* Maximum speed supported in KBps */
+ __be16 max_speed; /* Maximum speed supported in KBps */
u8 reserved10, reserved11;
- u16 ctl; /* Continuous Transfer Limit in blocks */
- u16 speed; /* Current Speed, in KBps */
- u16 buffer_size; /* Buffer Size, in 512 bytes */
+ __be16 ctl; /* Continuous Transfer Limit in blocks */
+ __be16 speed; /* Current Speed, in KBps */
+ __be16 buffer_size; /* Buffer Size, in 512 bytes */
u8 reserved18, reserved19;
} osst_capabilities_page_t;
@@ -352,8 +352,8 @@ typedef struct {
u8 reserved2;
u8 density;
u8 reserved3,reserved4;
- u16 segtrk;
- u16 trks;
+ __be16 segtrk;
+ __be16 trks;
u8 reserved5,reserved6,reserved7,reserved8,reserved9,reserved10;
} osst_tape_paramtr_page_t;
@@ -369,18 +369,18 @@ typedef struct {
typedef struct os_partition_s {
__u8 partition_num;
__u8 par_desc_ver;
- __u16 wrt_pass_cntr;
- __u32 first_frame_ppos;
- __u32 last_frame_ppos;
- __u32 eod_frame_ppos;
+ __be16 wrt_pass_cntr;
+ __be32 first_frame_ppos;
+ __be32 last_frame_ppos;
+ __be32 eod_frame_ppos;
} os_partition_t;
/*
* DAT entry
*/
typedef struct os_dat_entry_s {
- __u32 blk_sz;
- __u16 blk_cnt;
+ __be32 blk_sz;
+ __be16 blk_cnt;
__u8 flags;
__u8 reserved;
} os_dat_entry_t;
@@ -412,23 +412,23 @@ typedef struct os_dat_s {
* AUX
*/
typedef struct os_aux_s {
- __u32 format_id; /* hardware compability AUX is based on */
+ __be32 format_id; /* hardware compability AUX is based on */
char application_sig[4]; /* driver used to write this media */
- __u32 hdwr; /* reserved */
- __u32 update_frame_cntr; /* for configuration frame */
+ __be32 hdwr; /* reserved */
+ __be32 update_frame_cntr; /* for configuration frame */
__u8 frame_type;
__u8 frame_type_reserved;
__u8 reserved_18_19[2];
os_partition_t partition;
__u8 reserved_36_43[8];
- __u32 frame_seq_num;
- __u32 logical_blk_num_high;
- __u32 logical_blk_num;
+ __be32 frame_seq_num;
+ __be32 logical_blk_num_high;
+ __be32 logical_blk_num;
os_dat_t dat;
__u8 reserved188_191[4];
- __u32 filemark_cnt;
- __u32 phys_fm;
- __u32 last_mark_ppos;
+ __be32 filemark_cnt;
+ __be32 phys_fm;
+ __be32 last_mark_ppos;
__u8 reserved204_223[20];
/*
@@ -436,8 +436,8 @@ typedef struct os_aux_s {
*
* Linux specific fields:
*/
- __u32 next_mark_ppos; /* when known, points to next marker */
- __u32 last_mark_lbn; /* storing log_blk_num of last mark is extends ADR spec */
+ __be32 next_mark_ppos; /* when known, points to next marker */
+ __be32 last_mark_lbn; /* storing log_blk_num of last mark is extends ADR spec */
__u8 linux_specific[24];
__u8 reserved_256_511[256];
@@ -450,19 +450,19 @@ typedef struct os_fm_tab_s {
__u8 reserved_1;
__u8 fm_tab_ent_sz;
__u8 reserved_3;
- __u16 fm_tab_ent_cnt;
+ __be16 fm_tab_ent_cnt;
__u8 reserved6_15[10];
- __u32 fm_tab_ent[OS_FM_TAB_MAX];
+ __be32 fm_tab_ent[OS_FM_TAB_MAX];
} os_fm_tab_t;
typedef struct os_ext_trk_ey_s {
__u8 et_part_num;
__u8 fmt;
- __u16 fm_tab_off;
+ __be16 fm_tab_off;
__u8 reserved4_7[4];
- __u32 last_hlb_hi;
- __u32 last_hlb;
- __u32 last_pp;
+ __be32 last_hlb_hi;
+ __be32 last_hlb;
+ __be32 last_pp;
__u8 reserved20_31[12];
} os_ext_trk_ey_t;
@@ -479,17 +479,17 @@ typedef struct os_header_s {
char ident_str[8];
__u8 major_rev;
__u8 minor_rev;
- __u16 ext_trk_tb_off;
+ __be16 ext_trk_tb_off;
__u8 reserved12_15[4];
__u8 pt_par_num;
__u8 pt_reserved1_3[3];
os_partition_t partition[16];
- __u32 cfg_col_width;
- __u32 dat_col_width;
- __u32 qfa_col_width;
+ __be32 cfg_col_width;
+ __be32 dat_col_width;
+ __be32 qfa_col_width;
__u8 cartridge[16];
__u8 reserved304_511[208];
- __u32 old_filemark_list[16680/4]; /* in ADR 1.4 __u8 track_table[16680] */
+ __be32 old_filemark_list[16680/4]; /* in ADR 1.4 __u8 track_table[16680] */
os_ext_trk_tb_t ext_track_tb;
__u8 reserved17272_17735[464];
os_fm_tab_t dat_fm_tab;
diff --git a/drivers/scsi/pas16.c b/drivers/scsi/pas16.c
index 1434209a8ac..ee596565997 100644
--- a/drivers/scsi/pas16.c
+++ b/drivers/scsi/pas16.c
@@ -116,7 +116,6 @@
#include <asm/system.h>
#include <linux/signal.h>
#include <linux/proc_fs.h>
-#include <linux/sched.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <linux/blkdev.h>
diff --git a/drivers/scsi/pcmcia/aha152x_stub.c b/drivers/scsi/pcmcia/aha152x_stub.c
index aad362ba02e..370802d24ac 100644
--- a/drivers/scsi/pcmcia/aha152x_stub.c
+++ b/drivers/scsi/pcmcia/aha152x_stub.c
@@ -37,7 +37,6 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/ioport.h>
diff --git a/drivers/scsi/pcmcia/fdomain_stub.c b/drivers/scsi/pcmcia/fdomain_stub.c
index a1c5f265069..4b82b202198 100644
--- a/drivers/scsi/pcmcia/fdomain_stub.c
+++ b/drivers/scsi/pcmcia/fdomain_stub.c
@@ -34,7 +34,6 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/ioport.h>
diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c
index e16fe361436..c6f8c6e65e0 100644
--- a/drivers/scsi/pcmcia/nsp_cs.c
+++ b/drivers/scsi/pcmcia/nsp_cs.c
@@ -31,7 +31,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/timer.h>
diff --git a/drivers/scsi/pcmcia/nsp_cs.h b/drivers/scsi/pcmcia/nsp_cs.h
index 625ca97da52..9102cbdf135 100644
--- a/drivers/scsi/pcmcia/nsp_cs.h
+++ b/drivers/scsi/pcmcia/nsp_cs.h
@@ -290,7 +290,6 @@ typedef struct _nsp_hw_data {
#endif
} nsp_hw_data;
-
/****************************************************************************
*
*/
@@ -302,22 +301,13 @@ static int nsp_cs_config (struct pcmcia_device *link);
/* Linux SCSI subsystem specific functions */
static struct Scsi_Host *nsp_detect (struct scsi_host_template *sht);
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
-static int nsp_detect_old (struct scsi_host_template *sht);
-static int nsp_release_old(struct Scsi_Host *shpnt);
-#endif
static const char *nsp_info (struct Scsi_Host *shpnt);
static int nsp_proc_info (
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
struct Scsi_Host *host,
-#endif
char *buffer,
char **start,
off_t offset,
int length,
-#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
- int hostno,
-#endif
int inout);
static int nsp_queuecommand(struct scsi_cmnd *SCpnt,
void (* done)(struct scsi_cmnd *SCpnt));
@@ -356,7 +346,6 @@ static struct Scsi_Host *nsp_detect(struct scsi_host_template *sht);
static int __init nsp_cs_init(void);
static void __exit nsp_cs_exit(void);
-
/* Debug */
#ifdef NSP_DEBUG
static void show_command (struct scsi_cmnd *SCpnt);
@@ -401,7 +390,6 @@ enum _burst_mode {
BURST_MEM32 = 2,
};
-
/**************************************************************************
* SCSI messaage
*/
@@ -413,62 +401,8 @@ enum _burst_mode {
#define MSG_EXT_SDTR 0x01
-
-/**************************************************************************
- * Compatibility functions
- */
-
-/* for Kernel 2.4 */
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0))
-# define scsi_register_host(template) scsi_register_module(MODULE_SCSI_HA, template)
-# define scsi_unregister_host(template) scsi_unregister_module(MODULE_SCSI_HA, template)
-# define scsi_host_put(host) scsi_unregister(host)
-
-typedef void irqreturn_t;
-# define IRQ_NONE /* */
-# define IRQ_HANDLED /* */
-# define IRQ_RETVAL(x) /* */
-
-/* This is ad-hoc version of scsi_host_get_next() */
-static inline struct Scsi_Host *scsi_host_get_next(struct Scsi_Host *host)
-{
- if (host == NULL) {
- return scsi_hostlist;
- } else {
- return host->next;
- }
-}
-
-/* This is ad-hoc version of scsi_host_hn_get() */
-static inline struct Scsi_Host *scsi_host_hn_get(unsigned short hostno)
-{
- struct Scsi_Host *host;
-
- for (host = scsi_host_get_next(NULL); host != NULL;
- host = scsi_host_get_next(host)) {
- if (host->host_no == hostno) {
- break;
- }
- }
-
- return host;
-}
-
-static void cs_error(struct pcmcia_device *handle, int func, int ret)
-{
- error_info_t err = { func, ret };
- pcmcia_report_error(handle, &err);
-}
-
-/* scatter-gather table */
-# define BUFFER_ADDR (SCpnt->SCp.buffer->address)
-#endif
-
-/* for Kernel 2.6 */
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))
/* scatter-gather table */
# define BUFFER_ADDR ((char *)((unsigned int)(SCpnt->SCp.buffer->page) + SCpnt->SCp.buffer->offset))
-#endif
#endif /*__nsp_cs__*/
/* end */
diff --git a/drivers/scsi/pcmcia/qlogic_stub.c b/drivers/scsi/pcmcia/qlogic_stub.c
index 9d431fe7f47..697cfb76c3a 100644
--- a/drivers/scsi/pcmcia/qlogic_stub.c
+++ b/drivers/scsi/pcmcia/qlogic_stub.c
@@ -34,7 +34,6 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/ioport.h>
diff --git a/drivers/scsi/pcmcia/sym53c500_cs.c b/drivers/scsi/pcmcia/sym53c500_cs.c
index 5b458d2478f..ffe75c431b2 100644
--- a/drivers/scsi/pcmcia/sym53c500_cs.c
+++ b/drivers/scsi/pcmcia/sym53c500_cs.c
@@ -54,7 +54,6 @@
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/ioport.h>
diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
index 1548d42a3b4..6777e8a6915 100644
--- a/drivers/scsi/qla1280.c
+++ b/drivers/scsi/qla1280.c
@@ -341,7 +341,6 @@
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/timer.h>
-#include <linux/sched.h>
#include <linux/pci.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index 7b18a6c7b7e..8081b637d97 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -140,6 +140,8 @@ qla2x00_sysfs_write_nvram(struct kobject *kobj, char *buf, loff_t off,
ha->isp_ops.write_nvram(ha, (uint8_t *)buf, ha->nvram_base, count);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
+
return (count);
}
@@ -653,6 +655,43 @@ qla2x00_beacon_store(struct class_device *cdev, const char *buf,
return count;
}
+static ssize_t
+qla2x00_optrom_bios_version_show(struct class_device *cdev, char *buf)
+{
+ scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+
+ return snprintf(buf, PAGE_SIZE, "%d.%02d\n", ha->bios_revision[1],
+ ha->bios_revision[0]);
+}
+
+static ssize_t
+qla2x00_optrom_efi_version_show(struct class_device *cdev, char *buf)
+{
+ scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+
+ return snprintf(buf, PAGE_SIZE, "%d.%02d\n", ha->efi_revision[1],
+ ha->efi_revision[0]);
+}
+
+static ssize_t
+qla2x00_optrom_fcode_version_show(struct class_device *cdev, char *buf)
+{
+ scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+
+ return snprintf(buf, PAGE_SIZE, "%d.%02d\n", ha->fcode_revision[1],
+ ha->fcode_revision[0]);
+}
+
+static ssize_t
+qla2x00_optrom_fw_version_show(struct class_device *cdev, char *buf)
+{
+ scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+
+ return snprintf(buf, PAGE_SIZE, "%d.%02d.%02d %d\n",
+ ha->fw_revision[0], ha->fw_revision[1], ha->fw_revision[2],
+ ha->fw_revision[3]);
+}
+
static CLASS_DEVICE_ATTR(driver_version, S_IRUGO, qla2x00_drvr_version_show,
NULL);
static CLASS_DEVICE_ATTR(fw_version, S_IRUGO, qla2x00_fw_version_show, NULL);
@@ -669,6 +708,14 @@ static CLASS_DEVICE_ATTR(zio_timer, S_IRUGO | S_IWUSR, qla2x00_zio_timer_show,
qla2x00_zio_timer_store);
static CLASS_DEVICE_ATTR(beacon, S_IRUGO | S_IWUSR, qla2x00_beacon_show,
qla2x00_beacon_store);
+static CLASS_DEVICE_ATTR(optrom_bios_version, S_IRUGO,
+ qla2x00_optrom_bios_version_show, NULL);
+static CLASS_DEVICE_ATTR(optrom_efi_version, S_IRUGO,
+ qla2x00_optrom_efi_version_show, NULL);
+static CLASS_DEVICE_ATTR(optrom_fcode_version, S_IRUGO,
+ qla2x00_optrom_fcode_version_show, NULL);
+static CLASS_DEVICE_ATTR(optrom_fw_version, S_IRUGO,
+ qla2x00_optrom_fw_version_show, NULL);
struct class_device_attribute *qla2x00_host_attrs[] = {
&class_device_attr_driver_version,
@@ -683,6 +730,10 @@ struct class_device_attribute *qla2x00_host_attrs[] = {
&class_device_attr_zio,
&class_device_attr_zio_timer,
&class_device_attr_beacon,
+ &class_device_attr_optrom_bios_version,
+ &class_device_attr_optrom_efi_version,
+ &class_device_attr_optrom_fcode_version,
+ &class_device_attr_optrom_fw_version,
NULL,
};
@@ -836,21 +887,24 @@ qla2x00_get_fc_host_stats(struct Scsi_Host *shost)
link_stat_t stat_buf;
struct fc_host_statistics *pfc_host_stat;
+ rval = QLA_FUNCTION_FAILED;
pfc_host_stat = &ha->fc_host_stat;
memset(pfc_host_stat, -1, sizeof(struct fc_host_statistics));
if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
rval = qla24xx_get_isp_stats(ha, (uint32_t *)&stat_buf,
sizeof(stat_buf) / 4, mb_stat);
- } else {
+ } else if (atomic_read(&ha->loop_state) == LOOP_READY &&
+ !test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags) &&
+ !test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags) &&
+ !ha->dpc_active) {
+ /* Must be in a 'READY' state for statistics retrieval. */
rval = qla2x00_get_link_status(ha, ha->loop_id, &stat_buf,
mb_stat);
}
- if (rval != 0) {
- qla_printk(KERN_WARNING, ha,
- "Unable to retrieve host statistics (%d).\n", mb_stat[0]);
- return pfc_host_stat;
- }
+
+ if (rval != QLA_SUCCESS)
+ goto done;
pfc_host_stat->link_failure_count = stat_buf.link_fail_cnt;
pfc_host_stat->loss_of_sync_count = stat_buf.loss_sync_cnt;
@@ -858,7 +912,7 @@ qla2x00_get_fc_host_stats(struct Scsi_Host *shost)
pfc_host_stat->prim_seq_protocol_err_count = stat_buf.prim_seq_err_cnt;
pfc_host_stat->invalid_tx_word_count = stat_buf.inval_xmit_word_cnt;
pfc_host_stat->invalid_crc_count = stat_buf.inval_crc_cnt;
-
+done:
return pfc_host_stat;
}
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 2c10130d9e0..05f4f2a378e 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -2045,6 +2045,29 @@ struct isp_operations {
uint32_t, uint32_t);
int (*write_optrom) (struct scsi_qla_host *, uint8_t *, uint32_t,
uint32_t);
+
+ int (*get_flash_version) (struct scsi_qla_host *, void *);
+};
+
+/* MSI-X Support *************************************************************/
+
+#define QLA_MSIX_CHIP_REV_24XX 3
+#define QLA_MSIX_FW_MODE(m) (((m) & (BIT_7|BIT_8|BIT_9)) >> 7)
+#define QLA_MSIX_FW_MODE_1(m) (QLA_MSIX_FW_MODE(m) == 1)
+
+#define QLA_MSIX_DEFAULT 0x00
+#define QLA_MSIX_RSP_Q 0x01
+
+#define QLA_MSIX_ENTRIES 2
+#define QLA_MIDX_DEFAULT 0
+#define QLA_MIDX_RSP_Q 1
+
+struct scsi_qla_host;
+
+struct qla_msix_entry {
+ int have_irq;
+ uint16_t msix_vector;
+ uint16_t msix_entry;
};
/*
@@ -2077,6 +2100,7 @@ typedef struct scsi_qla_host {
uint32_t enable_lip_full_login :1;
uint32_t enable_target_reset :1;
uint32_t enable_led_scheme :1;
+ uint32_t inta_enabled :1;
uint32_t msi_enabled :1;
uint32_t msix_enabled :1;
uint32_t disable_serdes :1;
@@ -2316,8 +2340,6 @@ typedef struct scsi_qla_host {
#define MBX_INTR_WAIT 2
#define MBX_UPDATE_FLASH_ACTIVE 3
- spinlock_t mbx_reg_lock; /* Mbx Cmd Register Lock */
-
struct semaphore mbx_cmd_sem; /* Serialialize mbx access */
struct semaphore mbx_intr_sem; /* Used for completion notification */
@@ -2358,6 +2380,7 @@ typedef struct scsi_qla_host {
uint8_t host_str[16];
uint32_t pci_attr;
+ uint16_t chip_revision;
uint16_t product_id[4];
@@ -2379,6 +2402,15 @@ typedef struct scsi_qla_host {
#define QLA_SREADING 1
#define QLA_SWRITING 2
+ /* PCI expansion ROM image information. */
+#define ROM_CODE_TYPE_BIOS 0
+#define ROM_CODE_TYPE_FCODE 1
+#define ROM_CODE_TYPE_EFI 3
+ uint8_t bios_revision[2];
+ uint8_t efi_revision[2];
+ uint8_t fcode_revision[16];
+ uint32_t fw_revision[4];
+
/* Needed for BEACON */
uint16_t beacon_blink_led;
uint8_t beacon_color_state;
@@ -2391,6 +2423,8 @@ typedef struct scsi_qla_host {
uint16_t zio_mode;
uint16_t zio_timer;
struct fc_host_statistics fc_host_stat;
+
+ struct qla_msix_entry msix_entries[QLA_MSIX_ENTRIES];
} scsi_qla_host_t;
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index e4dd12f4b80..74544ae4b0e 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -224,6 +224,9 @@ extern irqreturn_t qla24xx_intr_handler(int, void *);
extern void qla2x00_process_response_queue(struct scsi_qla_host *);
extern void qla24xx_process_response_queue(struct scsi_qla_host *);
+extern int qla2x00_request_irqs(scsi_qla_host_t *);
+extern void qla2x00_free_irqs(scsi_qla_host_t *);
+
/*
* Global Function Prototypes in qla_sup.c source file.
*/
@@ -259,6 +262,9 @@ extern uint8_t *qla24xx_read_optrom_data(struct scsi_qla_host *, uint8_t *,
extern int qla24xx_write_optrom_data(struct scsi_qla_host *, uint8_t *,
uint32_t, uint32_t);
+extern int qla2x00_get_flash_version(scsi_qla_host_t *, void *);
+extern int qla24xx_get_flash_version(scsi_qla_host_t *, void *);
+
/*
* Global Function Prototypes in qla_dbg.c source file.
*/
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index b3dac26ddba..98c01cd5e1a 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -65,7 +65,7 @@ qla2x00_initialize_adapter(scsi_qla_host_t *ha)
ha->flags.reset_active = 0;
atomic_set(&ha->loop_down_timer, LOOP_DOWN_TIME);
atomic_set(&ha->loop_state, LOOP_DOWN);
- ha->device_flags = 0;
+ ha->device_flags = DFLG_NO_CABLE;
ha->dpc_flags = 0;
ha->flags.management_server_logged_in = 0;
ha->marker_needed = 0;
@@ -77,16 +77,23 @@ qla2x00_initialize_adapter(scsi_qla_host_t *ha)
qla_printk(KERN_INFO, ha, "Configuring PCI space...\n");
rval = ha->isp_ops.pci_config(ha);
if (rval) {
- DEBUG2(printk("scsi(%ld): Unable to configure PCI space=n",
+ DEBUG2(printk("scsi(%ld): Unable to configure PCI space.\n",
ha->host_no));
return (rval);
}
ha->isp_ops.reset_chip(ha);
+ ha->isp_ops.get_flash_version(ha, ha->request_ring);
+
qla_printk(KERN_INFO, ha, "Configure NVRAM parameters...\n");
- ha->isp_ops.nvram_config(ha);
+ rval = ha->isp_ops.nvram_config(ha);
+ if (rval) {
+ DEBUG2(printk("scsi(%ld): Unable to verify NVRAM data.\n",
+ ha->host_no));
+ return rval;
+ }
if (ha->flags.disable_serdes) {
/* Mask HBA via NVRAM settings? */
@@ -293,6 +300,8 @@ qla24xx_pci_config(scsi_qla_host_t *ha)
d &= ~PCI_ROM_ADDRESS_ENABLE;
pci_write_config_dword(ha->pdev, PCI_ROM_ADDRESS, d);
+ pci_read_config_word(ha->pdev, PCI_REVISION_ID, &ha->chip_revision);
+
/* Get PCI bus information. */
spin_lock_irqsave(&ha->hardware_lock, flags);
ha->pci_attr = RD_REG_DWORD(&reg->ctrl_status);
@@ -1351,6 +1360,39 @@ qla2x00_configure_hba(scsi_qla_host_t *ha)
return(rval);
}
+static inline void
+qla2x00_set_model_info(scsi_qla_host_t *ha, uint8_t *model, size_t len, char *def)
+{
+ char *st, *en;
+ uint16_t index;
+
+ if (memcmp(model, BINZERO, len) != 0) {
+ strncpy(ha->model_number, model, len);
+ st = en = ha->model_number;
+ en += len - 1;
+ while (en > st) {
+ if (*en != 0x20 && *en != 0x00)
+ break;
+ *en-- = '\0';
+ }
+
+ index = (ha->pdev->subsystem_device & 0xff);
+ if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC &&
+ index < QLA_MODEL_NAMES)
+ ha->model_desc = qla2x00_model_name[index * 2 + 1];
+ } else {
+ index = (ha->pdev->subsystem_device & 0xff);
+ if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC &&
+ index < QLA_MODEL_NAMES) {
+ strcpy(ha->model_number,
+ qla2x00_model_name[index * 2]);
+ ha->model_desc = qla2x00_model_name[index * 2 + 1];
+ } else {
+ strcpy(ha->model_number, def);
+ }
+ }
+}
+
/*
* NVRAM configuration for ISP 2xxx
*
@@ -1367,7 +1409,6 @@ qla2x00_configure_hba(scsi_qla_host_t *ha)
int
qla2x00_nvram_config(scsi_qla_host_t *ha)
{
- int rval;
uint8_t chksum = 0;
uint16_t cnt;
uint8_t *dptr1, *dptr2;
@@ -1376,8 +1417,6 @@ qla2x00_nvram_config(scsi_qla_host_t *ha)
uint8_t *ptr = (uint8_t *)ha->request_ring;
struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
- rval = QLA_SUCCESS;
-
/* Determine NVRAM starting address. */
ha->nvram_size = sizeof(nvram_t);
ha->nvram_base = 0;
@@ -1401,55 +1440,7 @@ qla2x00_nvram_config(scsi_qla_host_t *ha)
qla_printk(KERN_WARNING, ha, "Inconsistent NVRAM detected: "
"checksum=0x%x id=%c version=0x%x.\n", chksum, nv->id[0],
nv->nvram_version);
- qla_printk(KERN_WARNING, ha, "Falling back to functioning (yet "
- "invalid -- WWPN) defaults.\n");
-
- /*
- * Set default initialization control block.
- */
- memset(nv, 0, ha->nvram_size);
- nv->parameter_block_version = ICB_VERSION;
-
- if (IS_QLA23XX(ha)) {
- nv->firmware_options[0] = BIT_2 | BIT_1;
- nv->firmware_options[1] = BIT_7 | BIT_5;
- nv->add_firmware_options[0] = BIT_5;
- nv->add_firmware_options[1] = BIT_5 | BIT_4;
- nv->frame_payload_size = __constant_cpu_to_le16(2048);
- nv->special_options[1] = BIT_7;
- } else if (IS_QLA2200(ha)) {
- nv->firmware_options[0] = BIT_2 | BIT_1;
- nv->firmware_options[1] = BIT_7 | BIT_5;
- nv->add_firmware_options[0] = BIT_5;
- nv->add_firmware_options[1] = BIT_5 | BIT_4;
- nv->frame_payload_size = __constant_cpu_to_le16(1024);
- } else if (IS_QLA2100(ha)) {
- nv->firmware_options[0] = BIT_3 | BIT_1;
- nv->firmware_options[1] = BIT_5;
- nv->frame_payload_size = __constant_cpu_to_le16(1024);
- }
-
- nv->max_iocb_allocation = __constant_cpu_to_le16(256);
- nv->execution_throttle = __constant_cpu_to_le16(16);
- nv->retry_count = 8;
- nv->retry_delay = 1;
-
- nv->port_name[0] = 33;
- nv->port_name[3] = 224;
- nv->port_name[4] = 139;
-
- nv->login_timeout = 4;
-
- /*
- * Set default host adapter parameters
- */
- nv->host_p[1] = BIT_2;
- nv->reset_delay = 5;
- nv->port_down_retry_count = 8;
- nv->max_luns_per_target = __constant_cpu_to_le16(8);
- nv->link_down_timeout = 60;
-
- rval = 1;
+ return QLA_FUNCTION_FAILED;
}
#if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_SGI_SN2)
@@ -1489,33 +1480,8 @@ qla2x00_nvram_config(scsi_qla_host_t *ha)
strcpy(ha->model_number, "QLA2300");
}
} else {
- if (rval == 0 &&
- memcmp(nv->model_number, BINZERO,
- sizeof(nv->model_number)) != 0) {
- char *st, *en;
-
- strncpy(ha->model_number, nv->model_number,
- sizeof(nv->model_number));
- st = en = ha->model_number;
- en += sizeof(nv->model_number) - 1;
- while (en > st) {
- if (*en != 0x20 && *en != 0x00)
- break;
- *en-- = '\0';
- }
- } else {
- uint16_t index;
-
- index = (ha->pdev->subsystem_device & 0xff);
- if (index < QLA_MODEL_NAMES) {
- strcpy(ha->model_number,
- qla2x00_model_name[index * 2]);
- ha->model_desc =
- qla2x00_model_name[index * 2 + 1];
- } else {
- strcpy(ha->model_number, "QLA23xx");
- }
- }
+ qla2x00_set_model_info(ha, nv->model_number,
+ sizeof(nv->model_number), "QLA23xx");
}
} else if (IS_QLA2200(ha)) {
nv->firmware_options[0] |= BIT_2;
@@ -1687,11 +1653,7 @@ qla2x00_nvram_config(scsi_qla_host_t *ha)
}
}
- if (rval) {
- DEBUG2_3(printk(KERN_WARNING
- "scsi(%ld): NVRAM configuration failed!\n", ha->host_no));
- }
- return (rval);
+ return QLA_SUCCESS;
}
static void
@@ -3107,7 +3069,11 @@ qla2x00_abort_isp(scsi_qla_host_t *ha)
}
spin_unlock_irqrestore(&ha->hardware_lock, flags);
- ha->isp_ops.nvram_config(ha);
+ ha->isp_ops.get_flash_version(ha, ha->request_ring);
+
+ rval = ha->isp_ops.nvram_config(ha);
+ if (rval)
+ goto isp_abort_retry;
if (!qla2x00_restart_isp(ha)) {
clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
@@ -3137,6 +3103,7 @@ qla2x00_abort_isp(scsi_qla_host_t *ha)
}
}
} else { /* failed the ISP abort */
+isp_abort_retry:
ha->flags.online = 1;
if (test_bit(ISP_ABORT_RETRY, &ha->dpc_flags)) {
if (ha->isp_abort_cnt == 0) {
@@ -3326,7 +3293,6 @@ qla24xx_reset_adapter(scsi_qla_host_t *ha)
int
qla24xx_nvram_config(scsi_qla_host_t *ha)
{
- int rval;
struct init_cb_24xx *icb;
struct nvram_24xx *nv;
uint32_t *dptr;
@@ -3334,7 +3300,6 @@ qla24xx_nvram_config(scsi_qla_host_t *ha)
uint32_t chksum;
uint16_t cnt;
- rval = QLA_SUCCESS;
icb = (struct init_cb_24xx *)ha->init_cb;
nv = (struct nvram_24xx *)ha->request_ring;
@@ -3367,51 +3332,7 @@ qla24xx_nvram_config(scsi_qla_host_t *ha)
qla_printk(KERN_WARNING, ha, "Inconsistent NVRAM detected: "
"checksum=0x%x id=%c version=0x%x.\n", chksum, nv->id[0],
le16_to_cpu(nv->nvram_version));
- qla_printk(KERN_WARNING, ha, "Falling back to functioning (yet "
- "invalid -- WWPN) defaults.\n");
-
- /*
- * Set default initialization control block.
- */
- memset(nv, 0, ha->nvram_size);
- nv->nvram_version = __constant_cpu_to_le16(ICB_VERSION);
- nv->version = __constant_cpu_to_le16(ICB_VERSION);
- nv->frame_payload_size = __constant_cpu_to_le16(2048);
- nv->execution_throttle = __constant_cpu_to_le16(0xFFFF);
- nv->exchange_count = __constant_cpu_to_le16(0);
- nv->hard_address = __constant_cpu_to_le16(124);
- nv->port_name[0] = 0x21;
- nv->port_name[1] = 0x00 + PCI_FUNC(ha->pdev->devfn);
- nv->port_name[2] = 0x00;
- nv->port_name[3] = 0xe0;
- nv->port_name[4] = 0x8b;
- nv->port_name[5] = 0x1c;
- nv->port_name[6] = 0x55;
- nv->port_name[7] = 0x86;
- nv->node_name[0] = 0x20;
- nv->node_name[1] = 0x00;
- nv->node_name[2] = 0x00;
- nv->node_name[3] = 0xe0;
- nv->node_name[4] = 0x8b;
- nv->node_name[5] = 0x1c;
- nv->node_name[6] = 0x55;
- nv->node_name[7] = 0x86;
- nv->login_retry_count = __constant_cpu_to_le16(8);
- nv->interrupt_delay_timer = __constant_cpu_to_le16(0);
- nv->login_timeout = __constant_cpu_to_le16(0);
- nv->firmware_options_1 =
- __constant_cpu_to_le32(BIT_14|BIT_13|BIT_2|BIT_1);
- nv->firmware_options_2 = __constant_cpu_to_le32(2 << 4);
- nv->firmware_options_2 |= __constant_cpu_to_le32(BIT_12);
- nv->firmware_options_3 = __constant_cpu_to_le32(2 << 13);
- nv->host_p = __constant_cpu_to_le32(BIT_11|BIT_10);
- nv->efi_parameters = __constant_cpu_to_le32(0);
- nv->reset_delay = 5;
- nv->max_luns_per_target = __constant_cpu_to_le16(128);
- nv->port_down_retry_count = __constant_cpu_to_le16(30);
- nv->link_down_timeout = __constant_cpu_to_le16(30);
-
- rval = 1;
+ return QLA_FUNCTION_FAILED;
}
/* Reset Initialization control block */
@@ -3438,25 +3359,8 @@ qla24xx_nvram_config(scsi_qla_host_t *ha)
/*
* Setup driver NVRAM options.
*/
- if (memcmp(nv->model_name, BINZERO, sizeof(nv->model_name)) != 0) {
- char *st, *en;
- uint16_t index;
-
- strncpy(ha->model_number, nv->model_name,
- sizeof(nv->model_name));
- st = en = ha->model_number;
- en += sizeof(nv->model_name) - 1;
- while (en > st) {
- if (*en != 0x20 && *en != 0x00)
- break;
- *en-- = '\0';
- }
-
- index = (ha->pdev->subsystem_device & 0xff);
- if (index < QLA_MODEL_NAMES)
- ha->model_desc = qla2x00_model_name[index * 2 + 1];
- } else
- strcpy(ha->model_number, "QLA2462");
+ qla2x00_set_model_info(ha, nv->model_name, sizeof(nv->model_name),
+ "QLA2462");
/* Use alternate WWN? */
if (nv->host_p & __constant_cpu_to_le32(BIT_15)) {
@@ -3575,11 +3479,7 @@ qla24xx_nvram_config(scsi_qla_host_t *ha)
ha->flags.process_response_queue = 1;
}
- if (rval) {
- DEBUG2_3(printk(KERN_WARNING
- "scsi(%ld): NVRAM configuration failed!\n", ha->host_no));
- }
- return (rval);
+ return QLA_SUCCESS;
}
static int
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index 39fd17b05be..d4885616cd3 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -86,12 +86,8 @@ qla2100_intr_handler(int irq, void *dev_id)
if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
(status & MBX_INTERRUPT) && ha->flags.mbox_int) {
- spin_lock_irqsave(&ha->mbx_reg_lock, flags);
-
set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
up(&ha->mbx_intr_sem);
-
- spin_unlock_irqrestore(&ha->mbx_reg_lock, flags);
}
return (IRQ_HANDLED);
@@ -199,12 +195,8 @@ qla2300_intr_handler(int irq, void *dev_id)
if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
(status & MBX_INTERRUPT) && ha->flags.mbox_int) {
- spin_lock_irqsave(&ha->mbx_reg_lock, flags);
-
set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
up(&ha->mbx_intr_sem);
-
- spin_unlock_irqrestore(&ha->mbx_reg_lock, flags);
}
return (IRQ_HANDLED);
@@ -654,10 +646,8 @@ qla2x00_ramp_up_queue_depth(scsi_qla_host_t *ha, srb_t *sp)
fcport->last_queue_full + ql2xqfullrampup * HZ))
return;
- spin_unlock_irq(&ha->hardware_lock);
starget_for_each_device(sdev->sdev_target, fcport,
qla2x00_adjust_sdev_qdepth_up);
- spin_lock_irq(&ha->hardware_lock);
}
/**
@@ -927,10 +917,8 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
/* Adjust queue depth for all luns on the port. */
fcport->last_queue_full = jiffies;
- spin_unlock_irq(&ha->hardware_lock);
starget_for_each_device(cp->device->sdev_target,
fcport, qla2x00_adjust_sdev_qdepth_down);
- spin_lock_irq(&ha->hardware_lock);
break;
}
if (lscsi_status != SS_CHECK_CONDITION)
@@ -995,6 +983,22 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
if (lscsi_status != 0) {
cp->result = DID_OK << 16 | lscsi_status;
+ if (lscsi_status == SAM_STAT_TASK_SET_FULL) {
+ DEBUG2(printk(KERN_INFO
+ "scsi(%ld): QUEUE FULL status detected "
+ "0x%x-0x%x.\n", ha->host_no, comp_status,
+ scsi_status));
+
+ /*
+ * Adjust queue depth for all luns on the
+ * port.
+ */
+ fcport->last_queue_full = jiffies;
+ starget_for_each_device(
+ cp->device->sdev_target, fcport,
+ qla2x00_adjust_sdev_qdepth_down);
+ break;
+ }
if (lscsi_status != SS_CHECK_CONDITION)
break;
@@ -1482,12 +1486,8 @@ qla24xx_intr_handler(int irq, void *dev_id)
if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
(status & MBX_INTERRUPT) && ha->flags.mbox_int) {
- spin_lock_irqsave(&ha->mbx_reg_lock, flags);
-
set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
up(&ha->mbx_intr_sem);
-
- spin_unlock_irqrestore(&ha->mbx_reg_lock, flags);
}
return IRQ_HANDLED;
@@ -1536,3 +1536,216 @@ qla24xx_ms_entry(scsi_qla_host_t *ha, struct ct_entry_24xx *pkt)
qla2x00_sp_compl(ha, sp);
}
+static irqreturn_t
+qla24xx_msix_rsp_q(int irq, void *dev_id)
+{
+ scsi_qla_host_t *ha;
+ struct device_reg_24xx __iomem *reg;
+ unsigned long flags;
+
+ ha = dev_id;
+ reg = &ha->iobase->isp24;
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+
+ qla24xx_process_response_queue(ha);
+
+ WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
+ RD_REG_DWORD_RELAXED(&reg->hccr);
+
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t
+qla24xx_msix_default(int irq, void *dev_id)
+{
+ scsi_qla_host_t *ha;
+ struct device_reg_24xx __iomem *reg;
+ int status;
+ unsigned long flags;
+ unsigned long iter;
+ uint32_t stat;
+ uint32_t hccr;
+ uint16_t mb[4];
+
+ ha = dev_id;
+ reg = &ha->iobase->isp24;
+ status = 0;
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ for (iter = 50; iter--; ) {
+ stat = RD_REG_DWORD(&reg->host_status);
+ if (stat & HSRX_RISC_PAUSED) {
+ hccr = RD_REG_DWORD(&reg->hccr);
+
+ qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, "
+ "Dumping firmware!\n", hccr);
+ ha->isp_ops.fw_dump(ha, 1);
+ set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
+ break;
+ } else if ((stat & HSRX_RISC_INT) == 0)
+ break;
+
+ switch (stat & 0xff) {
+ case 0x1:
+ case 0x2:
+ case 0x10:
+ case 0x11:
+ qla24xx_mbx_completion(ha, MSW(stat));
+ status |= MBX_INTERRUPT;
+
+ break;
+ case 0x12:
+ mb[0] = MSW(stat);
+ mb[1] = RD_REG_WORD(&reg->mailbox1);
+ mb[2] = RD_REG_WORD(&reg->mailbox2);
+ mb[3] = RD_REG_WORD(&reg->mailbox3);
+ qla2x00_async_event(ha, mb);
+ break;
+ case 0x13:
+ qla24xx_process_response_queue(ha);
+ break;
+ default:
+ DEBUG2(printk("scsi(%ld): Unrecognized interrupt type "
+ "(%d).\n",
+ ha->host_no, stat & 0xff));
+ break;
+ }
+ WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
+ RD_REG_DWORD_RELAXED(&reg->hccr);
+ }
+ 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);
+ up(&ha->mbx_intr_sem);
+ }
+
+ return IRQ_HANDLED;
+}
+
+/* Interrupt handling helpers. */
+
+struct qla_init_msix_entry {
+ uint16_t entry;
+ uint16_t index;
+ const char *name;
+ irqreturn_t (*handler)(int, void *);
+};
+
+static struct qla_init_msix_entry imsix_entries[QLA_MSIX_ENTRIES] = {
+ { QLA_MSIX_DEFAULT, QLA_MIDX_DEFAULT,
+ "qla2xxx (default)", qla24xx_msix_default },
+
+ { QLA_MSIX_RSP_Q, QLA_MIDX_RSP_Q,
+ "qla2xxx (rsp_q)", qla24xx_msix_rsp_q },
+};
+
+static void
+qla24xx_disable_msix(scsi_qla_host_t *ha)
+{
+ int i;
+ struct qla_msix_entry *qentry;
+
+ for (i = 0; i < QLA_MSIX_ENTRIES; i++) {
+ qentry = &ha->msix_entries[imsix_entries[i].index];
+ if (qentry->have_irq)
+ free_irq(qentry->msix_vector, ha);
+ }
+ pci_disable_msix(ha->pdev);
+}
+
+static int
+qla24xx_enable_msix(scsi_qla_host_t *ha)
+{
+ int i, ret;
+ struct msix_entry entries[QLA_MSIX_ENTRIES];
+ struct qla_msix_entry *qentry;
+
+ for (i = 0; i < QLA_MSIX_ENTRIES; i++)
+ entries[i].entry = imsix_entries[i].entry;
+
+ ret = pci_enable_msix(ha->pdev, entries, ARRAY_SIZE(entries));
+ if (ret) {
+ qla_printk(KERN_WARNING, ha,
+ "MSI-X: Failed to enable support -- %d/%d\n",
+ QLA_MSIX_ENTRIES, ret);
+ goto msix_out;
+ }
+ ha->flags.msix_enabled = 1;
+
+ for (i = 0; i < QLA_MSIX_ENTRIES; i++) {
+ qentry = &ha->msix_entries[imsix_entries[i].index];
+ qentry->msix_vector = entries[i].vector;
+ qentry->msix_entry = entries[i].entry;
+ qentry->have_irq = 0;
+ ret = request_irq(qentry->msix_vector,
+ imsix_entries[i].handler, 0, imsix_entries[i].name, ha);
+ if (ret) {
+ qla_printk(KERN_WARNING, ha,
+ "MSI-X: Unable to register handler -- %x/%d.\n",
+ imsix_entries[i].index, ret);
+ qla24xx_disable_msix(ha);
+ goto msix_out;
+ }
+ qentry->have_irq = 1;
+ }
+
+msix_out:
+ return ret;
+}
+
+int
+qla2x00_request_irqs(scsi_qla_host_t *ha)
+{
+ int ret;
+
+ /* If possible, enable MSI-X. */
+ if (!IS_QLA2432(ha))
+ goto skip_msix;
+
+ if (ha->chip_revision < QLA_MSIX_CHIP_REV_24XX ||
+ !QLA_MSIX_FW_MODE_1(ha->fw_attributes)) {
+ DEBUG2(qla_printk(KERN_WARNING, ha,
+ "MSI-X: Unsupported ISP2432 (0x%X, 0x%X).\n",
+ ha->chip_revision, ha->fw_attributes));
+
+ goto skip_msix;
+ }
+
+ ret = qla24xx_enable_msix(ha);
+ if (!ret) {
+ DEBUG2(qla_printk(KERN_INFO, ha,
+ "MSI-X: Enabled (0x%X, 0x%X).\n", ha->chip_revision,
+ ha->fw_attributes));
+ return ret;
+ }
+ qla_printk(KERN_WARNING, ha,
+ "MSI-X: Falling back-to INTa mode -- %d.\n", ret);
+skip_msix:
+ ret = request_irq(ha->pdev->irq, ha->isp_ops.intr_handler,
+ IRQF_DISABLED|IRQF_SHARED, QLA2XXX_DRIVER_NAME, ha);
+ if (!ret) {
+ ha->flags.inta_enabled = 1;
+ ha->host->irq = ha->pdev->irq;
+ } else {
+ qla_printk(KERN_WARNING, ha,
+ "Failed to reserve interrupt %d already in use.\n",
+ ha->pdev->irq);
+ }
+
+ return ret;
+}
+
+void
+qla2x00_free_irqs(scsi_qla_host_t *ha)
+{
+
+ if (ha->flags.msix_enabled)
+ qla24xx_disable_msix(ha);
+ else if (ha->flags.inta_enabled)
+ free_irq(ha->host->irq, ha);
+}
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index 077e5789bee..83376f6ac3d 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -55,7 +55,6 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp)
uint16_t __iomem *optr;
uint32_t cnt;
uint32_t mboxes;
- unsigned long mbx_flags = 0;
unsigned long wait_time;
rval = QLA_SUCCESS;
@@ -81,10 +80,6 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp)
/* Save mailbox command for debug */
ha->mcp = mcp;
- /* Try to get mailbox register access */
- if (!abort_active)
- spin_lock_irqsave(&ha->mbx_reg_lock, mbx_flags);
-
DEBUG11(printk("scsi(%ld): prepare to issue mbox cmd=0x%x.\n",
ha->host_no, mcp->mb[0]));
@@ -161,9 +156,6 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp)
WRT_REG_WORD(&reg->isp.hccr, HCCR_SET_HOST_INT);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
- if (!abort_active)
- spin_unlock_irqrestore(&ha->mbx_reg_lock, mbx_flags);
-
/* Wait for either the timer to expire
* or the mbox completion interrupt
*/
@@ -184,8 +176,6 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp)
else
WRT_REG_WORD(&reg->isp.hccr, HCCR_SET_HOST_INT);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
- if (!abort_active)
- spin_unlock_irqrestore(&ha->mbx_reg_lock, mbx_flags);
wait_time = jiffies + mcp->tov * HZ; /* wait at most tov secs */
while (!ha->flags.mbox_int) {
@@ -201,9 +191,6 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp)
} /* while */
}
- if (!abort_active)
- spin_lock_irqsave(&ha->mbx_reg_lock, mbx_flags);
-
/* Check whether we timed out */
if (ha->flags.mbox_int) {
uint16_t *iptr2;
@@ -256,9 +243,6 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp)
rval = QLA_FUNCTION_TIMEOUT;
}
- if (!abort_active)
- spin_unlock_irqrestore(&ha->mbx_reg_lock, mbx_flags);
-
ha->flags.mbox_busy = 0;
/* Clean up */
@@ -1713,7 +1697,7 @@ qla24xx_fabric_logout(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain,
lg->entry_count = 1;
lg->nport_handle = cpu_to_le16(loop_id);
lg->control_flags =
- __constant_cpu_to_le16(LCF_COMMAND_LOGO|LCF_EXPL_LOGO);
+ __constant_cpu_to_le16(LCF_COMMAND_LOGO|LCF_IMPL_LOGO);
lg->port_id[0] = al_pa;
lg->port_id[1] = area;
lg->port_id[2] = domain;
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index d6445ae841b..68f5d24b938 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -1485,6 +1485,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ha->isp_ops.fw_dump = qla2100_fw_dump;
ha->isp_ops.read_optrom = qla2x00_read_optrom_data;
ha->isp_ops.write_optrom = qla2x00_write_optrom_data;
+ ha->isp_ops.get_flash_version = qla2x00_get_flash_version;
if (IS_QLA2100(ha)) {
host->max_id = MAX_TARGETS_2100;
ha->mbx_count = MAILBOX_REGISTER_COUNT_2100;
@@ -1550,6 +1551,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ha->isp_ops.beacon_on = qla24xx_beacon_on;
ha->isp_ops.beacon_off = qla24xx_beacon_off;
ha->isp_ops.beacon_blink = qla24xx_beacon_blink;
+ ha->isp_ops.get_flash_version = qla24xx_get_flash_version;
ha->gid_list_info_size = 8;
ha->optrom_size = OPTROM_SIZE_24XX;
}
@@ -1564,14 +1566,6 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
INIT_LIST_HEAD(&ha->list);
INIT_LIST_HEAD(&ha->fcports);
- /*
- * These locks are used to prevent more than one CPU
- * from modifying the queue at the same time. The
- * higher level "host_lock" will reduce most
- * contention for these locks.
- */
- spin_lock_init(&ha->mbx_reg_lock);
-
qla2x00_config_dma_addressing(ha);
if (qla2x00_mem_alloc(ha)) {
qla_printk(KERN_WARNING, ha,
@@ -1615,15 +1609,9 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
host->max_lun = MAX_LUNS;
host->transportt = qla2xxx_transport_template;
- ret = request_irq(pdev->irq, ha->isp_ops.intr_handler,
- IRQF_DISABLED|IRQF_SHARED, QLA2XXX_DRIVER_NAME, ha);
- if (ret) {
- qla_printk(KERN_WARNING, ha,
- "Failed to reserve interrupt %d already in use.\n",
- pdev->irq);
+ ret = qla2x00_request_irqs(ha);
+ if (ret)
goto probe_failed;
- }
- host->irq = pdev->irq;
/* Initialized the timer */
qla2x00_start_timer(ha, qla2x00_timer, WATCH_INTERVAL);
@@ -1753,9 +1741,7 @@ qla2x00_free_device(scsi_qla_host_t *ha)
qla2x00_mem_free(ha);
- /* Detach interrupts */
- if (ha->host->irq)
- free_irq(ha->host->irq, ha);
+ qla2x00_free_irqs(ha);
/* release io space registers */
if (ha->iobase)
diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c
index 15390ad8745..ff1dd4175a7 100644
--- a/drivers/scsi/qla2xxx/qla_sup.c
+++ b/drivers/scsi/qla2xxx/qla_sup.c
@@ -611,7 +611,6 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr,
flash_conf_to_access_addr(0x0339),
(fdata & 0xff00) | ((fdata << 16) &
0xff0000) | ((fdata >> 16) & 0xff));
- fdata = (faddr & sec_mask) << 2;
ret = qla24xx_write_flash_dword(ha, conf_addr,
(fdata & 0xff00) |((fdata << 16) &
0xff0000) | ((fdata >> 16) & 0xff));
@@ -1383,6 +1382,29 @@ qla2x00_get_flash_manufacturer(scsi_qla_host_t *ha, uint8_t *man_id,
qla2x00_write_flash_byte(ha, 0x5555, 0xf0);
}
+static void
+qla2x00_read_flash_data(scsi_qla_host_t *ha, uint8_t *tmp_buf, uint32_t saddr,
+ uint32_t length)
+{
+ struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
+ uint32_t midpoint, ilength;
+ uint8_t data;
+
+ midpoint = length / 2;
+
+ WRT_REG_WORD(&reg->nvram, 0);
+ RD_REG_WORD(&reg->nvram);
+ for (ilength = 0; ilength < length; saddr++, ilength++, tmp_buf++) {
+ if (ilength == midpoint) {
+ WRT_REG_WORD(&reg->nvram, NVR_SELECT);
+ RD_REG_WORD(&reg->nvram);
+ }
+ data = qla2x00_read_flash_byte(ha, saddr);
+ if (saddr % 100)
+ udelay(10);
+ *tmp_buf = data;
+ }
+}
static inline void
qla2x00_suspend_hba(struct scsi_qla_host *ha)
@@ -1722,3 +1744,327 @@ qla24xx_write_optrom_data(struct scsi_qla_host *ha, uint8_t *buf,
return rval;
}
+
+/**
+ * qla2x00_get_fcode_version() - Determine an FCODE image's version.
+ * @ha: HA context
+ * @pcids: Pointer to the FCODE PCI data structure
+ *
+ * The process of retrieving the FCODE version information is at best
+ * described as interesting.
+ *
+ * Within the first 100h bytes of the image an ASCII string is present
+ * which contains several pieces of information including the FCODE
+ * version. Unfortunately it seems the only reliable way to retrieve
+ * the version is by scanning for another sentinel within the string,
+ * the FCODE build date:
+ *
+ * ... 2.00.02 10/17/02 ...
+ *
+ * Returns QLA_SUCCESS on successful retrieval of version.
+ */
+static void
+qla2x00_get_fcode_version(scsi_qla_host_t *ha, uint32_t pcids)
+{
+ int ret = QLA_FUNCTION_FAILED;
+ uint32_t istart, iend, iter, vend;
+ uint8_t do_next, rbyte, *vbyte;
+
+ memset(ha->fcode_revision, 0, sizeof(ha->fcode_revision));
+
+ /* Skip the PCI data structure. */
+ istart = pcids +
+ ((qla2x00_read_flash_byte(ha, pcids + 0x0B) << 8) |
+ qla2x00_read_flash_byte(ha, pcids + 0x0A));
+ iend = istart + 0x100;
+ do {
+ /* Scan for the sentinel date string...eeewww. */
+ do_next = 0;
+ iter = istart;
+ while ((iter < iend) && !do_next) {
+ iter++;
+ if (qla2x00_read_flash_byte(ha, iter) == '/') {
+ if (qla2x00_read_flash_byte(ha, iter + 2) ==
+ '/')
+ do_next++;
+ else if (qla2x00_read_flash_byte(ha,
+ iter + 3) == '/')
+ do_next++;
+ }
+ }
+ if (!do_next)
+ break;
+
+ /* Backtrack to previous ' ' (space). */
+ do_next = 0;
+ while ((iter > istart) && !do_next) {
+ iter--;
+ if (qla2x00_read_flash_byte(ha, iter) == ' ')
+ do_next++;
+ }
+ if (!do_next)
+ break;
+
+ /*
+ * Mark end of version tag, and find previous ' ' (space) or
+ * string length (recent FCODE images -- major hack ahead!!!).
+ */
+ vend = iter - 1;
+ do_next = 0;
+ while ((iter > istart) && !do_next) {
+ iter--;
+ rbyte = qla2x00_read_flash_byte(ha, iter);
+ if (rbyte == ' ' || rbyte == 0xd || rbyte == 0x10)
+ do_next++;
+ }
+ if (!do_next)
+ break;
+
+ /* Mark beginning of version tag, and copy data. */
+ iter++;
+ if ((vend - iter) &&
+ ((vend - iter) < sizeof(ha->fcode_revision))) {
+ vbyte = ha->fcode_revision;
+ while (iter <= vend) {
+ *vbyte++ = qla2x00_read_flash_byte(ha, iter);
+ iter++;
+ }
+ ret = QLA_SUCCESS;
+ }
+ } while (0);
+
+ if (ret != QLA_SUCCESS)
+ memset(ha->fcode_revision, 0, sizeof(ha->fcode_revision));
+}
+
+int
+qla2x00_get_flash_version(scsi_qla_host_t *ha, void *mbuf)
+{
+ int ret = QLA_SUCCESS;
+ uint8_t code_type, last_image;
+ uint32_t pcihdr, pcids;
+ uint8_t *dbyte;
+ uint16_t *dcode;
+
+ if (!ha->pio_address || !mbuf)
+ return QLA_FUNCTION_FAILED;
+
+ memset(ha->bios_revision, 0, sizeof(ha->bios_revision));
+ memset(ha->efi_revision, 0, sizeof(ha->efi_revision));
+ memset(ha->fcode_revision, 0, sizeof(ha->fcode_revision));
+ memset(ha->fw_revision, 0, sizeof(ha->fw_revision));
+
+ qla2x00_flash_enable(ha);
+
+ /* Begin with first PCI expansion ROM header. */
+ pcihdr = 0;
+ last_image = 1;
+ do {
+ /* Verify PCI expansion ROM header. */
+ if (qla2x00_read_flash_byte(ha, pcihdr) != 0x55 ||
+ qla2x00_read_flash_byte(ha, pcihdr + 0x01) != 0xaa) {
+ /* No signature */
+ DEBUG2(printk("scsi(%ld): No matching ROM "
+ "signature.\n", ha->host_no));
+ ret = QLA_FUNCTION_FAILED;
+ break;
+ }
+
+ /* Locate PCI data structure. */
+ pcids = pcihdr +
+ ((qla2x00_read_flash_byte(ha, pcihdr + 0x19) << 8) |
+ qla2x00_read_flash_byte(ha, pcihdr + 0x18));
+
+ /* Validate signature of PCI data structure. */
+ if (qla2x00_read_flash_byte(ha, pcids) != 'P' ||
+ qla2x00_read_flash_byte(ha, pcids + 0x1) != 'C' ||
+ qla2x00_read_flash_byte(ha, pcids + 0x2) != 'I' ||
+ qla2x00_read_flash_byte(ha, pcids + 0x3) != 'R') {
+ /* Incorrect header. */
+ DEBUG2(printk("%s(): PCI data struct not found "
+ "pcir_adr=%x.\n", __func__, pcids));
+ ret = QLA_FUNCTION_FAILED;
+ break;
+ }
+
+ /* Read version */
+ code_type = qla2x00_read_flash_byte(ha, pcids + 0x14);
+ switch (code_type) {
+ case ROM_CODE_TYPE_BIOS:
+ /* Intel x86, PC-AT compatible. */
+ ha->bios_revision[0] =
+ qla2x00_read_flash_byte(ha, pcids + 0x12);
+ ha->bios_revision[1] =
+ qla2x00_read_flash_byte(ha, pcids + 0x13);
+ DEBUG3(printk("%s(): read BIOS %d.%d.\n", __func__,
+ ha->bios_revision[1], ha->bios_revision[0]));
+ break;
+ case ROM_CODE_TYPE_FCODE:
+ /* Open Firmware standard for PCI (FCode). */
+ /* Eeeewww... */
+ qla2x00_get_fcode_version(ha, pcids);
+ break;
+ case ROM_CODE_TYPE_EFI:
+ /* Extensible Firmware Interface (EFI). */
+ ha->efi_revision[0] =
+ qla2x00_read_flash_byte(ha, pcids + 0x12);
+ ha->efi_revision[1] =
+ qla2x00_read_flash_byte(ha, pcids + 0x13);
+ DEBUG3(printk("%s(): read EFI %d.%d.\n", __func__,
+ ha->efi_revision[1], ha->efi_revision[0]));
+ break;
+ default:
+ DEBUG2(printk("%s(): Unrecognized code type %x at "
+ "pcids %x.\n", __func__, code_type, pcids));
+ break;
+ }
+
+ last_image = qla2x00_read_flash_byte(ha, pcids + 0x15) & BIT_7;
+
+ /* Locate next PCI expansion ROM. */
+ pcihdr += ((qla2x00_read_flash_byte(ha, pcids + 0x11) << 8) |
+ qla2x00_read_flash_byte(ha, pcids + 0x10)) * 512;
+ } while (!last_image);
+
+ if (IS_QLA2322(ha)) {
+ /* Read firmware image information. */
+ memset(ha->fw_revision, 0, sizeof(ha->fw_revision));
+ dbyte = mbuf;
+ memset(dbyte, 0, 8);
+ dcode = (uint16_t *)dbyte;
+
+ qla2x00_read_flash_data(ha, dbyte, FA_RISC_CODE_ADDR * 4 + 10,
+ 8);
+ DEBUG3(printk("%s(%ld): dumping fw ver from flash:\n",
+ __func__, ha->host_no));
+ DEBUG3(qla2x00_dump_buffer((uint8_t *)dbyte, 8));
+
+ if ((dcode[0] == 0xffff && dcode[1] == 0xffff &&
+ dcode[2] == 0xffff && dcode[3] == 0xffff) ||
+ (dcode[0] == 0 && dcode[1] == 0 && dcode[2] == 0 &&
+ dcode[3] == 0)) {
+ DEBUG2(printk("%s(): Unrecognized fw revision at "
+ "%x.\n", __func__, FA_RISC_CODE_ADDR * 4));
+ } else {
+ /* values are in big endian */
+ ha->fw_revision[0] = dbyte[0] << 16 | dbyte[1];
+ ha->fw_revision[1] = dbyte[2] << 16 | dbyte[3];
+ ha->fw_revision[2] = dbyte[4] << 16 | dbyte[5];
+ }
+ }
+
+ qla2x00_flash_disable(ha);
+
+ return ret;
+}
+
+int
+qla24xx_get_flash_version(scsi_qla_host_t *ha, void *mbuf)
+{
+ int ret = QLA_SUCCESS;
+ uint32_t pcihdr, pcids;
+ uint32_t *dcode;
+ uint8_t *bcode;
+ uint8_t code_type, last_image;
+ int i;
+
+ if (!mbuf)
+ return QLA_FUNCTION_FAILED;
+
+ memset(ha->bios_revision, 0, sizeof(ha->bios_revision));
+ memset(ha->efi_revision, 0, sizeof(ha->efi_revision));
+ memset(ha->fcode_revision, 0, sizeof(ha->fcode_revision));
+ memset(ha->fw_revision, 0, sizeof(ha->fw_revision));
+
+ dcode = mbuf;
+
+ /* Begin with first PCI expansion ROM header. */
+ pcihdr = 0;
+ last_image = 1;
+ do {
+ /* Verify PCI expansion ROM header. */
+ qla24xx_read_flash_data(ha, dcode, pcihdr >> 2, 0x20);
+ bcode = mbuf + (pcihdr % 4);
+ if (bcode[0x0] != 0x55 || bcode[0x1] != 0xaa) {
+ /* No signature */
+ DEBUG2(printk("scsi(%ld): No matching ROM "
+ "signature.\n", ha->host_no));
+ ret = QLA_FUNCTION_FAILED;
+ break;
+ }
+
+ /* Locate PCI data structure. */
+ pcids = pcihdr + ((bcode[0x19] << 8) | bcode[0x18]);
+
+ qla24xx_read_flash_data(ha, dcode, pcids >> 2, 0x20);
+ bcode = mbuf + (pcihdr % 4);
+
+ /* Validate signature of PCI data structure. */
+ if (bcode[0x0] != 'P' || bcode[0x1] != 'C' ||
+ bcode[0x2] != 'I' || bcode[0x3] != 'R') {
+ /* Incorrect header. */
+ DEBUG2(printk("%s(): PCI data struct not found "
+ "pcir_adr=%x.\n", __func__, pcids));
+ ret = QLA_FUNCTION_FAILED;
+ break;
+ }
+
+ /* Read version */
+ code_type = bcode[0x14];
+ switch (code_type) {
+ case ROM_CODE_TYPE_BIOS:
+ /* Intel x86, PC-AT compatible. */
+ ha->bios_revision[0] = bcode[0x12];
+ ha->bios_revision[1] = bcode[0x13];
+ DEBUG3(printk("%s(): read BIOS %d.%d.\n", __func__,
+ ha->bios_revision[1], ha->bios_revision[0]));
+ break;
+ case ROM_CODE_TYPE_FCODE:
+ /* Open Firmware standard for PCI (FCode). */
+ ha->fcode_revision[0] = bcode[0x12];
+ ha->fcode_revision[1] = bcode[0x13];
+ DEBUG3(printk("%s(): read FCODE %d.%d.\n", __func__,
+ ha->fcode_revision[1], ha->fcode_revision[0]));
+ break;
+ case ROM_CODE_TYPE_EFI:
+ /* Extensible Firmware Interface (EFI). */
+ ha->efi_revision[0] = bcode[0x12];
+ ha->efi_revision[1] = bcode[0x13];
+ DEBUG3(printk("%s(): read EFI %d.%d.\n", __func__,
+ ha->efi_revision[1], ha->efi_revision[0]));
+ break;
+ default:
+ DEBUG2(printk("%s(): Unrecognized code type %x at "
+ "pcids %x.\n", __func__, code_type, pcids));
+ break;
+ }
+
+ last_image = bcode[0x15] & BIT_7;
+
+ /* Locate next PCI expansion ROM. */
+ pcihdr += ((bcode[0x11] << 8) | bcode[0x10]) * 512;
+ } while (!last_image);
+
+ /* Read firmware image information. */
+ memset(ha->fw_revision, 0, sizeof(ha->fw_revision));
+ dcode = mbuf;
+
+ qla24xx_read_flash_data(ha, dcode, FA_RISC_CODE_ADDR + 4, 4);
+ for (i = 0; i < 4; i++)
+ dcode[i] = be32_to_cpu(dcode[i]);
+
+ if ((dcode[0] == 0xffffffff && dcode[1] == 0xffffffff &&
+ dcode[2] == 0xffffffff && dcode[3] == 0xffffffff) ||
+ (dcode[0] == 0 && dcode[1] == 0 && dcode[2] == 0 &&
+ dcode[3] == 0)) {
+ DEBUG2(printk("%s(): Unrecognized fw version at %x.\n",
+ __func__, FA_RISC_CODE_ADDR));
+ } else {
+ ha->fw_revision[0] = dcode[0];
+ ha->fw_revision[1] = dcode[1];
+ ha->fw_revision[2] = dcode[2];
+ ha->fw_revision[3] = dcode[3];
+ }
+
+ return ret;
+}
diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
index 459e0d6bd2b..61347aee55c 100644
--- a/drivers/scsi/qla2xxx/qla_version.h
+++ b/drivers/scsi/qla2xxx/qla_version.h
@@ -7,7 +7,7 @@
/*
* Driver version
*/
-#define QLA2XXX_VERSION "8.01.07-k4"
+#define QLA2XXX_VERSION "8.01.07-k5"
#define QLA_DRIVER_MAJOR_VER 8
#define QLA_DRIVER_MINOR_VER 1
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index 81fb7bd44f0..0bfddf893ed 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -1270,7 +1270,7 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev,
INIT_WORK(&ha->dpc_work, qla4xxx_do_dpc);
ret = request_irq(pdev->irq, qla4xxx_intr_handler,
- SA_INTERRUPT|SA_SHIRQ, "qla4xxx", ha);
+ IRQF_DISABLED | IRQF_SHARED, "qla4xxx", ha);
if (ret) {
dev_warn(&ha->pdev->dev, "Failed to reserve interrupt %d"
" already in use.\n", pdev->irq);
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 24cffd98ee6..1c89ee3e69b 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -40,7 +40,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/string.h>
#include <linux/slab.h>
@@ -673,27 +672,6 @@ void __scsi_done(struct scsi_cmnd *cmd)
}
/*
- * Function: scsi_retry_command
- *
- * Purpose: Send a command back to the low level to be retried.
- *
- * Notes: This command is always executed in the context of the
- * bottom half handler, or the error handler thread. Low
- * level drivers should not become re-entrant as a result of
- * this.
- */
-int scsi_retry_command(struct scsi_cmnd *cmd)
-{
- /*
- * Zero the sense information from the last time we tried
- * this command.
- */
- memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
-
- return scsi_queue_insert(cmd, SCSI_MLQUEUE_EH_RETRY);
-}
-
-/*
* Function: scsi_finish_command
*
* Purpose: Pass command off to upper layer for finishing of I/O
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 30ee3d72c02..3e2930b7ee2 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -28,7 +28,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/timer.h>
#include <linux/types.h>
@@ -51,10 +50,10 @@
#include "scsi_logging.h"
#include "scsi_debug.h"
-#define SCSI_DEBUG_VERSION "1.80"
-static const char * scsi_debug_version_date = "20061018";
+#define SCSI_DEBUG_VERSION "1.81"
+static const char * scsi_debug_version_date = "20070104";
-/* Additional Sense Code (ASC) used */
+/* Additional Sense Code (ASC) */
#define NO_ADDITIONAL_SENSE 0x0
#define LOGICAL_UNIT_NOT_READY 0x4
#define UNRECOVERED_READ_ERR 0x11
@@ -65,9 +64,13 @@ static const char * scsi_debug_version_date = "20061018";
#define INVALID_FIELD_IN_PARAM_LIST 0x26
#define POWERON_RESET 0x29
#define SAVING_PARAMS_UNSUP 0x39
+#define TRANSPORT_PROBLEM 0x4b
#define THRESHOLD_EXCEEDED 0x5d
#define LOW_POWER_COND_ON 0x5e
+/* Additional Sense Code Qualifier (ASCQ) */
+#define ACK_NAK_TO 0x3
+
#define SDEBUG_TAGGED_QUEUING 0 /* 0 | MSG_SIMPLE_TAG | MSG_ORDERED_TAG */
/* Default values for driver parameters */
@@ -95,15 +98,20 @@ static const char * scsi_debug_version_date = "20061018";
#define SCSI_DEBUG_OPT_MEDIUM_ERR 2
#define SCSI_DEBUG_OPT_TIMEOUT 4
#define SCSI_DEBUG_OPT_RECOVERED_ERR 8
+#define SCSI_DEBUG_OPT_TRANSPORT_ERR 16
/* When "every_nth" > 0 then modulo "every_nth" commands:
* - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
* - a RECOVERED_ERROR is simulated on successful read and write
* commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
+ * - a TRANSPORT_ERROR is simulated on successful read and write
+ * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
*
* When "every_nth" < 0 then after "- every_nth" commands:
* - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
* - a RECOVERED_ERROR is simulated on successful read and write
* commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
+ * - a TRANSPORT_ERROR is simulated on successful read and write
+ * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
* This will continue until some other action occurs (e.g. the user
* writing a new value (other than -1 or 1) to every_nth via sysfs).
*/
@@ -315,6 +323,7 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
int target = SCpnt->device->id;
struct sdebug_dev_info * devip = NULL;
int inj_recovered = 0;
+ int inj_transport = 0;
int delay_override = 0;
if (done == NULL)
@@ -352,6 +361,8 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
return 0; /* ignore command causing timeout */
else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts)
inj_recovered = 1; /* to reads and writes below */
+ else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts)
+ inj_transport = 1; /* to reads and writes below */
}
if (devip->wlun) {
@@ -468,7 +479,11 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
mk_sense_buffer(devip, RECOVERED_ERROR,
THRESHOLD_EXCEEDED, 0);
errsts = check_condition_result;
- }
+ } else if (inj_transport && (0 == errsts)) {
+ mk_sense_buffer(devip, ABORTED_COMMAND,
+ TRANSPORT_PROBLEM, ACK_NAK_TO);
+ errsts = check_condition_result;
+ }
break;
case REPORT_LUNS: /* mandatory, ignore unit attention */
delay_override = 1;
@@ -531,6 +546,9 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
delay_override = 1;
errsts = check_readiness(SCpnt, 0, devip);
break;
+ case WRITE_BUFFER:
+ errsts = check_readiness(SCpnt, 1, devip);
+ break;
default:
if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
printk(KERN_INFO "scsi_debug: Opcode: 0x%x not "
@@ -954,7 +972,9 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target,
int alloc_len, n, ret;
alloc_len = (cmd[3] << 8) + cmd[4];
- arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_KERNEL);
+ arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
+ if (! arr)
+ return DID_REQUEUE << 16;
if (devip->wlun)
pq_pdt = 0x1e; /* present, wlun */
else if (scsi_debug_no_lun_0 && (0 == devip->lun))
@@ -1217,7 +1237,9 @@ static int resp_report_tgtpgs(struct scsi_cmnd * scp,
alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8)
+ cmd[9]);
- arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_KERNEL);
+ arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
+ if (! arr)
+ return DID_REQUEUE << 16;
/*
* EVPD page 0x88 states we have two ports, one
* real and a fake port with no device connected.
@@ -1996,6 +2018,8 @@ static int scsi_debug_slave_configure(struct scsi_device * sdp)
if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
devip = devInfoReg(sdp);
+ if (NULL == devip)
+ return 1; /* no resources, will be marked offline */
sdp->hostdata = devip;
if (sdp->host->cmd_per_lun)
scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING,
@@ -2044,7 +2068,7 @@ static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
}
}
if (NULL == open_devip) { /* try and make a new one */
- open_devip = kzalloc(sizeof(*open_devip),GFP_KERNEL);
+ open_devip = kzalloc(sizeof(*open_devip),GFP_ATOMIC);
if (NULL == open_devip) {
printk(KERN_ERR "%s: out of memory at line %d\n",
__FUNCTION__, __LINE__);
@@ -2388,7 +2412,7 @@ MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
-MODULE_PARM_DESC(opts, "1->noise, 2->medium_error, 4->... (def=0)");
+MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])");
MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)");
@@ -2943,7 +2967,6 @@ static int sdebug_add_adapter(void)
struct list_head *lh, *lh_sf;
sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
-
if (NULL == sdbg_host) {
printk(KERN_ERR "%s: out of memory at line %d\n",
__FUNCTION__, __LINE__);
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 2ecb6ff4244..b8edcf5b545 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -359,6 +359,11 @@ static int scsi_check_sense(struct scsi_cmnd *scmd)
return SUCCESS;
case MEDIUM_ERROR:
+ if (sshdr.asc == 0x11 || /* UNRECOVERED READ ERR */
+ sshdr.asc == 0x13 || /* AMNF DATA FIELD */
+ sshdr.asc == 0x14) { /* RECORD NOT FOUND */
+ return SUCCESS;
+ }
return NEEDS_RETRY;
case HARDWARE_ERROR:
@@ -453,6 +458,128 @@ static void scsi_eh_done(struct scsi_cmnd *scmd)
}
/**
+ * scsi_try_host_reset - ask host adapter to reset itself
+ * @scmd: SCSI cmd to send hsot reset.
+ **/
+static int scsi_try_host_reset(struct scsi_cmnd *scmd)
+{
+ unsigned long flags;
+ int rtn;
+
+ SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Snd Host RST\n",
+ __FUNCTION__));
+
+ if (!scmd->device->host->hostt->eh_host_reset_handler)
+ return FAILED;
+
+ rtn = scmd->device->host->hostt->eh_host_reset_handler(scmd);
+
+ if (rtn == SUCCESS) {
+ if (!scmd->device->host->hostt->skip_settle_delay)
+ ssleep(HOST_RESET_SETTLE_TIME);
+ spin_lock_irqsave(scmd->device->host->host_lock, flags);
+ scsi_report_bus_reset(scmd->device->host,
+ scmd_channel(scmd));
+ spin_unlock_irqrestore(scmd->device->host->host_lock, flags);
+ }
+
+ return rtn;
+}
+
+/**
+ * scsi_try_bus_reset - ask host to perform a bus reset
+ * @scmd: SCSI cmd to send bus reset.
+ **/
+static int scsi_try_bus_reset(struct scsi_cmnd *scmd)
+{
+ unsigned long flags;
+ int rtn;
+
+ SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Snd Bus RST\n",
+ __FUNCTION__));
+
+ if (!scmd->device->host->hostt->eh_bus_reset_handler)
+ return FAILED;
+
+ rtn = scmd->device->host->hostt->eh_bus_reset_handler(scmd);
+
+ if (rtn == SUCCESS) {
+ if (!scmd->device->host->hostt->skip_settle_delay)
+ ssleep(BUS_RESET_SETTLE_TIME);
+ spin_lock_irqsave(scmd->device->host->host_lock, flags);
+ scsi_report_bus_reset(scmd->device->host,
+ scmd_channel(scmd));
+ spin_unlock_irqrestore(scmd->device->host->host_lock, flags);
+ }
+
+ return rtn;
+}
+
+/**
+ * scsi_try_bus_device_reset - Ask host to perform a BDR on a dev
+ * @scmd: SCSI cmd used to send BDR
+ *
+ * Notes:
+ * There is no timeout for this operation. if this operation is
+ * unreliable for a given host, then the host itself needs to put a
+ * timer on it, and set the host back to a consistent state prior to
+ * returning.
+ **/
+static int scsi_try_bus_device_reset(struct scsi_cmnd *scmd)
+{
+ int rtn;
+
+ if (!scmd->device->host->hostt->eh_device_reset_handler)
+ return FAILED;
+
+ rtn = scmd->device->host->hostt->eh_device_reset_handler(scmd);
+ if (rtn == SUCCESS) {
+ scmd->device->was_reset = 1;
+ scmd->device->expecting_cc_ua = 1;
+ }
+
+ return rtn;
+}
+
+static int __scsi_try_to_abort_cmd(struct scsi_cmnd *scmd)
+{
+ if (!scmd->device->host->hostt->eh_abort_handler)
+ return FAILED;
+
+ return scmd->device->host->hostt->eh_abort_handler(scmd);
+}
+
+/**
+ * scsi_try_to_abort_cmd - Ask host to abort a running command.
+ * @scmd: SCSI cmd to abort from Lower Level.
+ *
+ * Notes:
+ * This function will not return until the user's completion function
+ * has been called. there is no timeout on this operation. if the
+ * author of the low-level driver wishes this operation to be timed,
+ * they can provide this facility themselves. helper functions in
+ * scsi_error.c can be supplied to make this easier to do.
+ **/
+static int scsi_try_to_abort_cmd(struct scsi_cmnd *scmd)
+{
+ /*
+ * scsi_done was called just after the command timed out and before
+ * we had a chance to process it. (db)
+ */
+ if (scmd->serial_number == 0)
+ return SUCCESS;
+ return __scsi_try_to_abort_cmd(scmd);
+}
+
+static void scsi_abort_eh_cmnd(struct scsi_cmnd *scmd)
+{
+ if (__scsi_try_to_abort_cmd(scmd) != SUCCESS)
+ if (scsi_try_bus_device_reset(scmd) != SUCCESS)
+ if (scsi_try_bus_reset(scmd) != SUCCESS)
+ scsi_try_host_reset(scmd);
+}
+
+/**
* scsi_send_eh_cmnd - submit a scsi command as part of error recory
* @scmd: SCSI command structure to hijack
* @cmnd: CDB to send
@@ -579,13 +706,7 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
break;
}
} else {
- /*
- * FIXME(eric) - we are not tracking whether we could
- * abort a timed out command or not. not sure how
- * we should treat them differently anyways.
- */
- if (shost->hostt->eh_abort_handler)
- shost->hostt->eh_abort_handler(scmd);
+ scsi_abort_eh_cmnd(scmd);
rtn = FAILED;
}
@@ -672,8 +793,8 @@ EXPORT_SYMBOL(scsi_eh_finish_cmd);
* XXX: Long term this code should go away, but that needs an audit of
* all LLDDs first.
**/
-static int scsi_eh_get_sense(struct list_head *work_q,
- struct list_head *done_q)
+int scsi_eh_get_sense(struct list_head *work_q,
+ struct list_head *done_q)
{
struct scsi_cmnd *scmd, *next;
int rtn;
@@ -715,31 +836,7 @@ static int scsi_eh_get_sense(struct list_head *work_q,
return list_empty(work_q);
}
-
-/**
- * scsi_try_to_abort_cmd - Ask host to abort a running command.
- * @scmd: SCSI cmd to abort from Lower Level.
- *
- * Notes:
- * This function will not return until the user's completion function
- * has been called. there is no timeout on this operation. if the
- * author of the low-level driver wishes this operation to be timed,
- * they can provide this facility themselves. helper functions in
- * scsi_error.c can be supplied to make this easier to do.
- **/
-static int scsi_try_to_abort_cmd(struct scsi_cmnd *scmd)
-{
- if (!scmd->device->host->hostt->eh_abort_handler)
- return FAILED;
-
- /*
- * scsi_done was called just after the command timed out and before
- * we had a chance to process it. (db)
- */
- if (scmd->serial_number == 0)
- return SUCCESS;
- return scmd->device->host->hostt->eh_abort_handler(scmd);
-}
+EXPORT_SYMBOL_GPL(scsi_eh_get_sense);
/**
* scsi_eh_tur - Send TUR to device.
@@ -815,32 +912,6 @@ static int scsi_eh_abort_cmds(struct list_head *work_q,
}
/**
- * scsi_try_bus_device_reset - Ask host to perform a BDR on a dev
- * @scmd: SCSI cmd used to send BDR
- *
- * Notes:
- * There is no timeout for this operation. if this operation is
- * unreliable for a given host, then the host itself needs to put a
- * timer on it, and set the host back to a consistent state prior to
- * returning.
- **/
-static int scsi_try_bus_device_reset(struct scsi_cmnd *scmd)
-{
- int rtn;
-
- if (!scmd->device->host->hostt->eh_device_reset_handler)
- return FAILED;
-
- rtn = scmd->device->host->hostt->eh_device_reset_handler(scmd);
- if (rtn == SUCCESS) {
- scmd->device->was_reset = 1;
- scmd->device->expecting_cc_ua = 1;
- }
-
- return rtn;
-}
-
-/**
* scsi_eh_try_stu - Send START_UNIT to device.
* @scmd: Scsi cmd to send START_UNIT
*
@@ -971,64 +1042,6 @@ static int scsi_eh_bus_device_reset(struct Scsi_Host *shost,
}
/**
- * scsi_try_bus_reset - ask host to perform a bus reset
- * @scmd: SCSI cmd to send bus reset.
- **/
-static int scsi_try_bus_reset(struct scsi_cmnd *scmd)
-{
- unsigned long flags;
- int rtn;
-
- SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Snd Bus RST\n",
- __FUNCTION__));
-
- if (!scmd->device->host->hostt->eh_bus_reset_handler)
- return FAILED;
-
- rtn = scmd->device->host->hostt->eh_bus_reset_handler(scmd);
-
- if (rtn == SUCCESS) {
- if (!scmd->device->host->hostt->skip_settle_delay)
- ssleep(BUS_RESET_SETTLE_TIME);
- spin_lock_irqsave(scmd->device->host->host_lock, flags);
- scsi_report_bus_reset(scmd->device->host,
- scmd_channel(scmd));
- spin_unlock_irqrestore(scmd->device->host->host_lock, flags);
- }
-
- return rtn;
-}
-
-/**
- * scsi_try_host_reset - ask host adapter to reset itself
- * @scmd: SCSI cmd to send hsot reset.
- **/
-static int scsi_try_host_reset(struct scsi_cmnd *scmd)
-{
- unsigned long flags;
- int rtn;
-
- SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Snd Host RST\n",
- __FUNCTION__));
-
- if (!scmd->device->host->hostt->eh_host_reset_handler)
- return FAILED;
-
- rtn = scmd->device->host->hostt->eh_host_reset_handler(scmd);
-
- if (rtn == SUCCESS) {
- if (!scmd->device->host->hostt->skip_settle_delay)
- ssleep(HOST_RESET_SETTLE_TIME);
- spin_lock_irqsave(scmd->device->host->host_lock, flags);
- scsi_report_bus_reset(scmd->device->host,
- scmd_channel(scmd));
- spin_unlock_irqrestore(scmd->device->host->host_lock, flags);
- }
-
- return rtn;
-}
-
-/**
* scsi_eh_bus_reset - send a bus reset
* @shost: scsi host being recovered.
* @eh_done_q: list_head for processed commands.
@@ -1411,9 +1424,9 @@ static void scsi_restart_operations(struct Scsi_Host *shost)
* @eh_done_q: list_head for processed commands.
*
**/
-static void scsi_eh_ready_devs(struct Scsi_Host *shost,
- struct list_head *work_q,
- struct list_head *done_q)
+void scsi_eh_ready_devs(struct Scsi_Host *shost,
+ struct list_head *work_q,
+ struct list_head *done_q)
{
if (!scsi_eh_stu(shost, work_q, done_q))
if (!scsi_eh_bus_device_reset(shost, work_q, done_q))
@@ -1421,6 +1434,7 @@ static void scsi_eh_ready_devs(struct Scsi_Host *shost,
if (!scsi_eh_host_reset(work_q, done_q))
scsi_eh_offline_sdevs(work_q, done_q);
}
+EXPORT_SYMBOL_GPL(scsi_eh_ready_devs);
/**
* scsi_eh_flush_done_q - finish processed commands or retry them.
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index f02f48a882a..9f7482d0b59 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -388,10 +388,9 @@ int scsi_execute_async(struct scsi_device *sdev, const unsigned char *cmd,
int err = 0;
int write = (data_direction == DMA_TO_DEVICE);
- sioc = kmem_cache_alloc(scsi_io_context_cache, gfp);
+ sioc = kmem_cache_zalloc(scsi_io_context_cache, gfp);
if (!sioc)
return DRIVER_ERROR << 24;
- memset(sioc, 0, sizeof(*sioc));
req = blk_get_request(sdev->request_queue, write, gfp);
if (!req)
@@ -1400,7 +1399,7 @@ static void scsi_softirq_done(struct request *rq)
scsi_finish_command(cmd);
break;
case NEEDS_RETRY:
- scsi_retry_command(cmd);
+ scsi_queue_insert(cmd, SCSI_MLQUEUE_EH_RETRY);
break;
case ADD_TO_MLQUEUE:
scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY);
@@ -2250,6 +2249,8 @@ void *scsi_kmap_atomic_sg(struct scatterlist *sg, int sg_count,
size_t sg_len = 0, len_complete = 0;
struct page *page;
+ WARN_ON(!irqs_disabled());
+
for (i = 0; i < sg_count; i++) {
len_complete = sg_len; /* Complete sg-entries */
sg_len += sg[i].length;
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
index f458c2f686d..ee8efe849bf 100644
--- a/drivers/scsi/scsi_priv.h
+++ b/drivers/scsi/scsi_priv.h
@@ -28,7 +28,6 @@ extern int scsi_dispatch_cmd(struct scsi_cmnd *cmd);
extern int scsi_setup_command_freelist(struct Scsi_Host *shost);
extern void scsi_destroy_command_freelist(struct Scsi_Host *shost);
extern void __scsi_done(struct scsi_cmnd *cmd);
-extern int scsi_retry_command(struct scsi_cmnd *cmd);
#ifdef CONFIG_SCSI_LOGGING
void scsi_log_send(struct scsi_cmnd *cmd);
void scsi_log_completion(struct scsi_cmnd *cmd, int disposition);
@@ -58,6 +57,11 @@ extern int scsi_error_handler(void *host);
extern int scsi_decide_disposition(struct scsi_cmnd *cmd);
extern void scsi_eh_wakeup(struct Scsi_Host *shost);
extern int scsi_eh_scmd_add(struct scsi_cmnd *, int);
+void scsi_eh_ready_devs(struct Scsi_Host *shost,
+ struct list_head *work_q,
+ struct list_head *done_q);
+int scsi_eh_get_sense(struct list_head *work_q,
+ struct list_head *done_q);
/* scsi_lib.c */
extern int scsi_maybe_unblock_host(struct scsi_device *sdev);
diff --git a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c
index 524a5f7a519..bb6f051beda 100644
--- a/drivers/scsi/scsi_proc.c
+++ b/drivers/scsi/scsi_proc.c
@@ -179,9 +179,8 @@ static int proc_print_scsidevice(struct device *dev, void *data)
seq_printf(s, "\n");
seq_printf(s, " Type: %s ", scsi_device_type(sdev->type));
- seq_printf(s, " ANSI"
- " SCSI revision: %02x", (sdev->scsi_level - 1) ?
- sdev->scsi_level - 1 : 1);
+ seq_printf(s, " ANSI SCSI revision: %02x",
+ sdev->scsi_level - (sdev->scsi_level > 1));
if (sdev->scsi_level == 2)
seq_printf(s, " CCS\n");
else
@@ -308,7 +307,7 @@ static int proc_scsi_open(struct inode *inode, struct file *file)
return single_open(file, proc_scsi_show, NULL);
}
-static struct file_operations proc_scsi_operations = {
+static const struct file_operations proc_scsi_operations = {
.open = proc_scsi_open,
.read = seq_read,
.write = proc_scsi_write,
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 96b7cbd746a..0949145304e 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -54,7 +54,7 @@
#define SCSI_TIMEOUT (2*HZ)
/*
- * Prefix values for the SCSI id's (stored in driverfs name field)
+ * Prefix values for the SCSI id's (stored in sysfs name field)
*/
#define SCSI_UID_SER_NUM 'S'
#define SCSI_UID_UNKNOWN 'Z'
@@ -385,6 +385,7 @@ static struct scsi_target *scsi_alloc_target(struct device *parent,
INIT_LIST_HEAD(&starget->siblings);
INIT_LIST_HEAD(&starget->devices);
starget->state = STARGET_RUNNING;
+ starget->scsi_level = SCSI_2;
retry:
spin_lock_irqsave(shost->host_lock, flags);
@@ -654,6 +655,19 @@ static int scsi_probe_lun(struct scsi_device *sdev, unsigned char *inq_result,
* short INQUIRY), an abort here prevents any further use of the
* device, including spin up.
*
+ * On the whole, the best approach seems to be to assume the first
+ * 36 bytes are valid no matter what the device says. That's
+ * better than copying < 36 bytes to the inquiry-result buffer
+ * and displaying garbage for the Vendor, Product, or Revision
+ * strings.
+ */
+ if (sdev->inquiry_len < 36) {
+ printk(KERN_INFO "scsi scan: INQUIRY result too short (%d),"
+ " using 36\n", sdev->inquiry_len);
+ sdev->inquiry_len = 36;
+ }
+
+ /*
* Related to the above issue:
*
* XXX Devices (disk or all?) should be sent a TEST UNIT READY,
@@ -1029,7 +1043,7 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget,
sdev_printk(KERN_INFO, sdev,
"scsi scan: consider passing scsi_mod."
- "dev_flags=%s:%s:0x240 or 0x800240\n",
+ "dev_flags=%s:%s:0x240 or 0x1000240\n",
scsi_inq_str(vend, result, 8, 16),
scsi_inq_str(mod, result, 16, 32));
});
diff --git a/drivers/scsi/scsi_sysctl.c b/drivers/scsi/scsi_sysctl.c
index 04d06c25132..6cfaaa2d0c8 100644
--- a/drivers/scsi/scsi_sysctl.c
+++ b/drivers/scsi/scsi_sysctl.c
@@ -41,7 +41,7 @@ static struct ctl_table_header *scsi_table_header;
int __init scsi_init_sysctl(void)
{
- scsi_table_header = register_sysctl_table(scsi_root_table, 1);
+ scsi_table_header = register_sysctl_table(scsi_root_table);
if (!scsi_table_header)
return -ENOMEM;
return 0;
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 259c90cfa36..c275dcac3f1 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -922,7 +922,7 @@ void scsi_sysfs_device_initialize(struct scsi_device *sdev)
snprintf(sdev->sdev_classdev.class_id, BUS_ID_SIZE,
"%d:%d:%d:%d", sdev->host->host_no,
sdev->channel, sdev->id, sdev->lun);
- sdev->scsi_level = SCSI_2;
+ sdev->scsi_level = starget->scsi_level;
transport_setup_device(&sdev->sdev_gendev);
spin_lock_irqsave(shost->host_lock, flags);
list_add_tail(&sdev->same_target_siblings, &starget->devices);
diff --git a/drivers/scsi/scsi_tgt_if.c b/drivers/scsi/scsi_tgt_if.c
index 37bbfbdb870..0e08817fdec 100644
--- a/drivers/scsi/scsi_tgt_if.c
+++ b/drivers/scsi/scsi_tgt_if.c
@@ -33,6 +33,14 @@
#include "scsi_tgt_priv.h"
+#if TGT_RING_SIZE < PAGE_SIZE
+# define TGT_RING_SIZE PAGE_SIZE
+#endif
+
+#define TGT_RING_PAGES (TGT_RING_SIZE >> PAGE_SHIFT)
+#define TGT_EVENT_PER_PAGE (PAGE_SIZE / sizeof(struct tgt_event))
+#define TGT_MAX_EVENTS (TGT_EVENT_PER_PAGE * TGT_RING_PAGES)
+
struct tgt_ring {
u32 tr_idx;
unsigned long tr_pages[TGT_RING_PAGES];
@@ -280,7 +288,7 @@ static int tgt_open(struct inode *inode, struct file *file)
return 0;
}
-static struct file_operations tgt_fops = {
+static const struct file_operations tgt_fops = {
.owner = THIS_MODULE,
.open = tgt_open,
.poll = tgt_poll,
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
index 3571ce8934e..58afdb40170 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -26,7 +26,6 @@
*/
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/sched.h> /* workqueue stuff, HZ */
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_transport.h>
@@ -856,7 +855,7 @@ static FC_CLASS_DEVICE_ATTR(rport, fast_io_fail_tmo, S_IRUGO | S_IWUSR,
/*
* Note: in the target show function we recognize when the remote
- * port is in the heirarchy and do not allow the driver to get
+ * port is in the hierarchy and do not allow the driver to get
* involved in sysfs functions. The driver only gets involved if
* it's the "old" style that doesn't use rports.
*/
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c
index 5c0b75bbfa1..b2ef71a8629 100644
--- a/drivers/scsi/scsi_transport_sas.c
+++ b/drivers/scsi/scsi_transport_sas.c
@@ -336,6 +336,51 @@ show_sas_device_type(struct class_device *cdev, char *buf)
}
static CLASS_DEVICE_ATTR(device_type, S_IRUGO, show_sas_device_type, NULL);
+static ssize_t do_sas_phy_enable(struct class_device *cdev,
+ size_t count, int enable)
+{
+ struct sas_phy *phy = transport_class_to_phy(cdev);
+ struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
+ struct sas_internal *i = to_sas_internal(shost->transportt);
+ int error;
+
+ error = i->f->phy_enable(phy, enable);
+ if (error)
+ return error;
+ phy->enabled = enable;
+ return count;
+};
+
+static ssize_t store_sas_phy_enable(struct class_device *cdev,
+ const char *buf, size_t count)
+{
+ if (count < 1)
+ return -EINVAL;
+
+ switch (buf[0]) {
+ case '0':
+ do_sas_phy_enable(cdev, count, 0);
+ break;
+ case '1':
+ do_sas_phy_enable(cdev, count, 1);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return count;
+}
+
+static ssize_t show_sas_phy_enable(struct class_device *cdev, char *buf)
+{
+ struct sas_phy *phy = transport_class_to_phy(cdev);
+
+ return snprintf(buf, 20, "%d", phy->enabled);
+}
+
+static CLASS_DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, show_sas_phy_enable,
+ store_sas_phy_enable);
+
static ssize_t do_sas_phy_reset(struct class_device *cdev,
size_t count, int hard_reset)
{
@@ -435,6 +480,7 @@ struct sas_phy *sas_phy_alloc(struct device *parent, int number)
return NULL;
phy->number = number;
+ phy->enabled = 1;
device_initialize(&phy->dev);
phy->dev.parent = get_device(parent);
@@ -454,7 +500,7 @@ struct sas_phy *sas_phy_alloc(struct device *parent, int number)
EXPORT_SYMBOL(sas_phy_alloc);
/**
- * sas_phy_add -- add a SAS PHY to the device hierachy
+ * sas_phy_add -- add a SAS PHY to the device hierarchy
* @phy: The PHY to be added
*
* Publishes a SAS PHY to the rest of the system.
@@ -579,8 +625,19 @@ static void sas_port_release(struct device *dev)
static void sas_port_create_link(struct sas_port *port,
struct sas_phy *phy)
{
- sysfs_create_link(&port->dev.kobj, &phy->dev.kobj, phy->dev.bus_id);
- sysfs_create_link(&phy->dev.kobj, &port->dev.kobj, "port");
+ int res;
+
+ res = sysfs_create_link(&port->dev.kobj, &phy->dev.kobj,
+ phy->dev.bus_id);
+ if (res)
+ goto err;
+ res = sysfs_create_link(&phy->dev.kobj, &port->dev.kobj, "port");
+ if (res)
+ goto err;
+ return;
+err:
+ printk(KERN_ERR "%s: Cannot create port links, err=%d\n",
+ __FUNCTION__, res);
}
static void sas_port_delete_link(struct sas_port *port,
@@ -818,13 +875,20 @@ EXPORT_SYMBOL(sas_port_delete_phy);
void sas_port_mark_backlink(struct sas_port *port)
{
+ int res;
struct device *parent = port->dev.parent->parent->parent;
if (port->is_backlink)
return;
port->is_backlink = 1;
- sysfs_create_link(&port->dev.kobj, &parent->kobj,
- parent->bus_id);
+ res = sysfs_create_link(&port->dev.kobj, &parent->kobj,
+ parent->bus_id);
+ if (res)
+ goto err;
+ return;
+err:
+ printk(KERN_ERR "%s: Cannot create port backlink, err=%d\n",
+ __FUNCTION__, res);
}
EXPORT_SYMBOL(sas_port_mark_backlink);
@@ -1201,7 +1265,7 @@ struct sas_rphy *sas_expander_alloc(struct sas_port *parent,
EXPORT_SYMBOL(sas_expander_alloc);
/**
- * sas_rphy_add -- add a SAS remote PHY to the device hierachy
+ * sas_rphy_add -- add a SAS remote PHY to the device hierarchy
* @rphy: The remote PHY to be added
*
* Publishes a SAS remote PHY to the rest of the system.
@@ -1237,7 +1301,7 @@ int sas_rphy_add(struct sas_rphy *rphy)
if (identify->device_type == SAS_END_DEVICE &&
rphy->scsi_target_id != -1) {
scsi_scan_target(&rphy->dev, 0,
- rphy->scsi_target_id, ~0, 0);
+ rphy->scsi_target_id, SCAN_WILD_CARD, 0);
}
return 0;
@@ -1253,7 +1317,7 @@ EXPORT_SYMBOL(sas_rphy_add);
* Note:
* This function must only be called on a remote
* PHY that has not sucessfully been added using
- * sas_rphy_add().
+ * sas_rphy_add() (or has been sas_rphy_remove()'d)
*/
void sas_rphy_free(struct sas_rphy *rphy)
{
@@ -1272,18 +1336,30 @@ void sas_rphy_free(struct sas_rphy *rphy)
EXPORT_SYMBOL(sas_rphy_free);
/**
- * sas_rphy_delete -- remove SAS remote PHY
- * @rphy: SAS remote PHY to remove
+ * sas_rphy_delete -- remove and free SAS remote PHY
+ * @rphy: SAS remote PHY to remove and free
*
- * Removes the specified SAS remote PHY.
+ * Removes the specified SAS remote PHY and frees it.
*/
void
sas_rphy_delete(struct sas_rphy *rphy)
{
+ sas_rphy_remove(rphy);
+ sas_rphy_free(rphy);
+}
+EXPORT_SYMBOL(sas_rphy_delete);
+
+/**
+ * sas_rphy_remove -- remove SAS remote PHY
+ * @rphy: SAS remote phy to remove
+ *
+ * Removes the specified SAS remote PHY.
+ */
+void
+sas_rphy_remove(struct sas_rphy *rphy)
+{
struct device *dev = &rphy->dev;
struct sas_port *parent = dev_to_sas_port(dev->parent);
- struct Scsi_Host *shost = dev_to_shost(parent->dev.parent);
- struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
switch (rphy->identify.device_type) {
case SAS_END_DEVICE:
@@ -1299,17 +1375,10 @@ sas_rphy_delete(struct sas_rphy *rphy)
transport_remove_device(dev);
device_del(dev);
- transport_destroy_device(dev);
-
- mutex_lock(&sas_host->lock);
- list_del(&rphy->list);
- mutex_unlock(&sas_host->lock);
parent->rphy = NULL;
-
- put_device(dev);
}
-EXPORT_SYMBOL(sas_rphy_delete);
+EXPORT_SYMBOL(sas_rphy_remove);
/**
* scsi_is_sas_rphy -- check if a struct device represents a SAS remote PHY
@@ -1389,6 +1458,10 @@ static int sas_user_scan(struct Scsi_Host *shost, uint channel,
SETUP_TEMPLATE_RW(phy_attrs, field, S_IRUGO | S_IWUSR, 1, \
!i->f->set_phy_speed, S_IRUGO)
+#define SETUP_OPTIONAL_PHY_ATTRIBUTE_RW(field, func) \
+ SETUP_TEMPLATE_RW(phy_attrs, field, S_IRUGO | S_IWUSR, 1, \
+ !i->f->func, S_IRUGO)
+
#define SETUP_PORT_ATTRIBUTE(field) \
SETUP_TEMPLATE(port_attrs, field, S_IRUGO, 1)
@@ -1396,10 +1469,10 @@ static int sas_user_scan(struct Scsi_Host *shost, uint channel,
SETUP_TEMPLATE(phy_attrs, field, S_IRUGO, i->f->func)
#define SETUP_PHY_ATTRIBUTE_WRONLY(field) \
- SETUP_TEMPLATE(phy_attrs, field, S_IWUGO, 1)
+ SETUP_TEMPLATE(phy_attrs, field, S_IWUSR, 1)
#define SETUP_OPTIONAL_PHY_ATTRIBUTE_WRONLY(field, func) \
- SETUP_TEMPLATE(phy_attrs, field, S_IWUGO, i->f->func)
+ SETUP_TEMPLATE(phy_attrs, field, S_IWUSR, i->f->func)
#define SETUP_END_DEV_ATTRIBUTE(field) \
SETUP_TEMPLATE(end_dev_attrs, field, S_IRUGO, 1)
@@ -1479,6 +1552,7 @@ sas_attach_transport(struct sas_function_template *ft)
SETUP_PHY_ATTRIBUTE(phy_reset_problem_count);
SETUP_OPTIONAL_PHY_ATTRIBUTE_WRONLY(link_reset, phy_reset);
SETUP_OPTIONAL_PHY_ATTRIBUTE_WRONLY(hard_reset, phy_reset);
+ SETUP_OPTIONAL_PHY_ATTRIBUTE_RW(enable, phy_enable);
i->phy_attrs[count] = NULL;
count = 0;
@@ -1587,7 +1661,7 @@ static void __exit sas_transport_exit(void)
}
MODULE_AUTHOR("Christoph Hellwig");
-MODULE_DESCRIPTION("SAS Transphy Attributes");
+MODULE_DESCRIPTION("SAS Transport Attributes");
MODULE_LICENSE("GPL");
module_init(sas_transport_init);
diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c
index 014d7fea1ff..6f56f875063 100644
--- a/drivers/scsi/scsi_transport_spi.c
+++ b/drivers/scsi/scsi_transport_spi.c
@@ -46,7 +46,6 @@
* two cc/ua clears */
/* Private data accessors (keep these out of the header file) */
-#define spi_dv_pending(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dv_pending)
#define spi_dv_in_progress(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dv_in_progress)
#define spi_dv_mutex(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dv_mutex)
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index b781a90d669..5a8f55fea5f 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -35,7 +35,6 @@
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/bio.h>
#include <linux/genhd.h>
@@ -1270,9 +1269,18 @@ repeat:
/* Some devices return the total number of sectors, not the
* highest sector number. Make the necessary adjustment. */
- if (sdp->fix_capacity)
+ if (sdp->fix_capacity) {
--sdkp->capacity;
+ /* Some devices have version which report the correct sizes
+ * and others which do not. We guess size according to a heuristic
+ * and err on the side of lowering the capacity. */
+ } else {
+ if (sdp->guess_capacity)
+ if (sdkp->capacity & 0x01) /* odd sizes are odd */
+ --sdkp->capacity;
+ }
+
got_data:
if (sector_size == 0) {
sector_size = 512;
diff --git a/drivers/scsi/sgiwd93.c b/drivers/scsi/sgiwd93.c
index e81f97a35bc..a15752b3799 100644
--- a/drivers/scsi/sgiwd93.c
+++ b/drivers/scsi/sgiwd93.c
@@ -244,9 +244,10 @@ static struct Scsi_Host * __init sgiwd93_setup_scsi(
regs.SASR = wdregs + 3;
regs.SCMD = wdregs + 7;
- wd33c93_init(host, regs, dma_setup, dma_stop, WD33C93_FS_16_20);
+ wd33c93_init(host, regs, dma_setup, dma_stop, WD33C93_FS_MHZ(20));
- hdata->wh.no_sync = 0;
+ if (hdata->wh.no_sync == 0xff)
+ hdata->wh.no_sync = 0;
if (request_irq(irq, sgiwd93_intr, 0, "SGI WD93", (void *) host)) {
printk(KERN_WARNING "sgiwd93: Could not register irq %d "
diff --git a/drivers/scsi/sim710.c b/drivers/scsi/sim710.c
index 551baccec52..018c65f73ac 100644
--- a/drivers/scsi/sim710.c
+++ b/drivers/scsi/sim710.c
@@ -123,6 +123,7 @@ sim710_probe_common(struct device *dev, unsigned long base_addr,
hostdata->differential = differential;
hostdata->clock = clock;
hostdata->chip710 = 1;
+ hostdata->burst_length = 8;
/* and register the chip */
if((host = NCR_700_detect(&sim710_driver_template, hostdata, dev))
diff --git a/drivers/scsi/sni_53c710.c b/drivers/scsi/sni_53c710.c
new file mode 100644
index 00000000000..6bc50511584
--- /dev/null
+++ b/drivers/scsi/sni_53c710.c
@@ -0,0 +1,159 @@
+/* -*- mode: c; c-basic-offset: 8 -*- */
+
+/* SNI RM driver
+ *
+ * Copyright (C) 2001 by James.Bottomley@HansenPartnership.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.
+**
+**-----------------------------------------------------------------------------
+ */
+
+/*
+ * Based on lasi700.c
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/stat.h>
+#include <linux/mm.h>
+#include <linux/blkdev.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/irq.h>
+#include <asm/delay.h>
+
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_spi.h>
+
+#include "53c700.h"
+
+MODULE_AUTHOR("Thomas Bogendörfer");
+MODULE_DESCRIPTION("SNI RM 53c710 SCSI Driver");
+MODULE_LICENSE("GPL");
+
+#define SNIRM710_CLOCK 32
+
+static struct scsi_host_template snirm710_template = {
+ .name = "SNI RM SCSI 53c710",
+ .proc_name = "snirm_53c710",
+ .this_id = 7,
+ .module = THIS_MODULE,
+};
+
+static int __init snirm710_probe(struct platform_device *dev)
+{
+ unsigned long base;
+ struct NCR_700_Host_Parameters *hostdata;
+ struct Scsi_Host *host;
+ struct resource *res;
+
+ res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ base = res->start;
+ hostdata = kzalloc(sizeof(*hostdata), GFP_KERNEL);
+ if (!hostdata) {
+ printk(KERN_ERR "%s: Failed to allocate host data\n",
+ dev->dev.bus_id);
+ return -ENOMEM;
+ }
+
+ hostdata->dev = &dev->dev;
+ dma_set_mask(&dev->dev, DMA_32BIT_MASK);
+ hostdata->base = ioremap_nocache(CPHYSADDR(base), 0x100);
+ hostdata->differential = 0;
+
+ hostdata->clock = SNIRM710_CLOCK;
+ hostdata->force_le_on_be = 1;
+ hostdata->chip710 = 1;
+ hostdata->burst_length = 4;
+
+ host = NCR_700_detect(&snirm710_template, hostdata, &dev->dev);
+ if (!host)
+ goto out_kfree;
+ host->this_id = 7;
+ host->base = base;
+ host->irq = platform_get_irq(dev, 0);
+ if(request_irq(host->irq, NCR_700_intr, SA_SHIRQ, "snirm710", host)) {
+ printk(KERN_ERR "snirm710: request_irq failed!\n");
+ goto out_put_host;
+ }
+
+ dev_set_drvdata(&dev->dev, host);
+ scsi_scan_host(host);
+
+ return 0;
+
+ out_put_host:
+ scsi_host_put(host);
+ out_kfree:
+ iounmap(hostdata->base);
+ kfree(hostdata);
+ return -ENODEV;
+}
+
+static int __exit snirm710_driver_remove(struct platform_device *dev)
+{
+ struct Scsi_Host *host = dev_get_drvdata(&dev->dev);
+ struct NCR_700_Host_Parameters *hostdata =
+ (struct NCR_700_Host_Parameters *)host->hostdata[0];
+
+ scsi_remove_host(host);
+ NCR_700_release(host);
+ free_irq(host->irq, host);
+ iounmap(hostdata->base);
+ kfree(hostdata);
+
+ return 0;
+}
+
+static struct platform_driver snirm710_driver = {
+ .probe = snirm710_probe,
+ .remove = __devexit_p(snirm710_driver_remove),
+ .driver = {
+ .name = "snirm_53c710",
+ },
+};
+
+static int __init snirm710_init(void)
+{
+ int err;
+
+ if ((err = platform_driver_register(&snirm710_driver))) {
+ printk(KERN_ERR "Driver registration failed\n");
+ return err;
+ }
+ return 0;
+}
+
+static void __exit snirm710_exit(void)
+{
+ platform_driver_unregister(&snirm710_driver);
+}
+
+module_init(snirm710_init);
+module_exit(snirm710_exit);
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index 89e9b36b178..1857d68e719 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -35,7 +35,6 @@
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/bio.h>
#include <linux/string.h>
diff --git a/drivers/scsi/sr_ioctl.c b/drivers/scsi/sr_ioctl.c
index 0578ba42718..e1589f91706 100644
--- a/drivers/scsi/sr_ioctl.c
+++ b/drivers/scsi/sr_ioctl.c
@@ -1,5 +1,4 @@
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/errno.h>
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 488ec7948a5..98d8411bbcc 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -9,7 +9,7 @@
Steve Hirsch, Andreas Koppenh"ofer, Michael Leodolter, Eyal Lebedinsky,
Michael Schaefer, J"org Weule, and Eric Youngdale.
- Copyright 1992 - 2006 Kai Makisara
+ Copyright 1992 - 2007 Kai Makisara
email Kai.Makisara@kolumbus.fi
Some small formal changes - aeb, 950809
@@ -17,7 +17,7 @@
Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
*/
-static const char *verstr = "20061107";
+static const char *verstr = "20070203";
#include <linux/module.h>
@@ -195,8 +195,8 @@ static int sgl_unmap_user_pages(struct scatterlist *, const unsigned int, int);
static int st_probe(struct device *);
static int st_remove(struct device *);
-static int do_create_driverfs_files(void);
-static void do_remove_driverfs_files(void);
+static int do_create_sysfs_files(void);
+static void do_remove_sysfs_files(void);
static int do_create_class_files(struct scsi_tape *, int, int);
static struct scsi_driver st_template = {
@@ -1168,6 +1168,7 @@ static int st_open(struct inode *inode, struct file *filp)
STps = &(STp->ps[i]);
STps->rw = ST_IDLE;
}
+ STp->try_dio_now = STp->try_dio;
STp->recover_count = 0;
DEB( STp->nbr_waits = STp->nbr_finished = 0;
STp->nbr_requests = STp->nbr_dio = STp->nbr_pages = STp->nbr_combinable = 0; )
@@ -1400,9 +1401,9 @@ static int setup_buffering(struct scsi_tape *STp, const char __user *buf,
struct st_buffer *STbp = STp->buffer;
if (is_read)
- i = STp->try_dio && try_rdio;
+ i = STp->try_dio_now && try_rdio;
else
- i = STp->try_dio && try_wdio;
+ i = STp->try_dio_now && try_wdio;
if (i && ((unsigned long)buf & queue_dma_alignment(
STp->device->request_queue)) == 0) {
@@ -1599,7 +1600,7 @@ st_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
STm->do_async_writes && STps->eof < ST_EOM_OK;
if (STp->block_size != 0 && STm->do_buffer_writes &&
- !(STp->try_dio && try_wdio) && STps->eof < ST_EOM_OK &&
+ !(STp->try_dio_now && try_wdio) && STps->eof < ST_EOM_OK &&
STbp->buffer_bytes < STbp->buffer_size) {
STp->dirty = 1;
/* Don't write a buffer that is not full enough. */
@@ -1769,7 +1770,7 @@ static long read_tape(struct scsi_tape *STp, long count,
if (STp->block_size == 0)
blks = bytes = count;
else {
- if (!(STp->try_dio && try_rdio) && STm->do_read_ahead) {
+ if (!(STp->try_dio_now && try_rdio) && STm->do_read_ahead) {
blks = (STp->buffer)->buffer_blocks;
bytes = blks * STp->block_size;
} else {
@@ -1948,10 +1949,12 @@ st_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos)
goto out;
STm = &(STp->modes[STp->current_mode]);
- if (!(STm->do_read_ahead) && STp->block_size != 0 &&
- (count % STp->block_size) != 0) {
- retval = (-EINVAL); /* Read must be integral number of blocks */
- goto out;
+ if (STp->block_size != 0 && (count % STp->block_size) != 0) {
+ if (!STm->do_read_ahead) {
+ retval = (-EINVAL); /* Read must be integral number of blocks */
+ goto out;
+ }
+ STp->try_dio_now = 0; /* Direct i/o can't handle split blocks */
}
STps = &(STp->ps[STp->partition]);
@@ -3861,7 +3864,7 @@ __setup("st=", st_setup);
#endif
-static struct file_operations st_fops =
+static const struct file_operations st_fops =
{
.owner = THIS_MODULE,
.read = st_read,
@@ -4190,7 +4193,7 @@ static int __init init_st(void)
if (err)
goto err_chrdev;
- err = do_create_driverfs_files();
+ err = do_create_sysfs_files();
if (err)
goto err_scsidrv;
@@ -4208,7 +4211,7 @@ err_class:
static void __exit exit_st(void)
{
- do_remove_driverfs_files();
+ do_remove_sysfs_files();
scsi_unregister_driver(&st_template.gendrv);
unregister_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0),
ST_MAX_TAPE_ENTRIES);
@@ -4246,43 +4249,43 @@ static ssize_t st_version_show(struct device_driver *ddd, char *buf)
}
static DRIVER_ATTR(version, S_IRUGO, st_version_show, NULL);
-static int do_create_driverfs_files(void)
+static int do_create_sysfs_files(void)
{
- struct device_driver *driverfs = &st_template.gendrv;
+ struct device_driver *sysfs = &st_template.gendrv;
int err;
- err = driver_create_file(driverfs, &driver_attr_try_direct_io);
+ err = driver_create_file(sysfs, &driver_attr_try_direct_io);
if (err)
return err;
- err = driver_create_file(driverfs, &driver_attr_fixed_buffer_size);
+ err = driver_create_file(sysfs, &driver_attr_fixed_buffer_size);
if (err)
goto err_try_direct_io;
- err = driver_create_file(driverfs, &driver_attr_max_sg_segs);
+ err = driver_create_file(sysfs, &driver_attr_max_sg_segs);
if (err)
goto err_attr_fixed_buf;
- err = driver_create_file(driverfs, &driver_attr_version);
+ err = driver_create_file(sysfs, &driver_attr_version);
if (err)
goto err_attr_max_sg;
return 0;
err_attr_max_sg:
- driver_remove_file(driverfs, &driver_attr_max_sg_segs);
+ driver_remove_file(sysfs, &driver_attr_max_sg_segs);
err_attr_fixed_buf:
- driver_remove_file(driverfs, &driver_attr_fixed_buffer_size);
+ driver_remove_file(sysfs, &driver_attr_fixed_buffer_size);
err_try_direct_io:
- driver_remove_file(driverfs, &driver_attr_try_direct_io);
+ driver_remove_file(sysfs, &driver_attr_try_direct_io);
return err;
}
-static void do_remove_driverfs_files(void)
+static void do_remove_sysfs_files(void)
{
- struct device_driver *driverfs = &st_template.gendrv;
+ struct device_driver *sysfs = &st_template.gendrv;
- driver_remove_file(driverfs, &driver_attr_version);
- driver_remove_file(driverfs, &driver_attr_max_sg_segs);
- driver_remove_file(driverfs, &driver_attr_fixed_buffer_size);
- driver_remove_file(driverfs, &driver_attr_try_direct_io);
+ driver_remove_file(sysfs, &driver_attr_version);
+ driver_remove_file(sysfs, &driver_attr_max_sg_segs);
+ driver_remove_file(sysfs, &driver_attr_fixed_buffer_size);
+ driver_remove_file(sysfs, &driver_attr_try_direct_io);
}
diff --git a/drivers/scsi/st.h b/drivers/scsi/st.h
index 05a5cae126e..50f3deb1f9e 100644
--- a/drivers/scsi/st.h
+++ b/drivers/scsi/st.h
@@ -117,7 +117,8 @@ struct scsi_tape {
unsigned char cln_sense_value;
unsigned char cln_sense_mask;
unsigned char use_pf; /* Set Page Format bit in all mode selects? */
- unsigned char try_dio; /* try direct i/o? */
+ unsigned char try_dio; /* try direct i/o in general? */
+ unsigned char try_dio_now; /* try direct i/o before next close? */
unsigned char c_algo; /* compression algorithm */
unsigned char pos_unknown; /* after reset position unknown */
int tape_type;
diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c
index ba6bcdaf2a6..69be1324b11 100644
--- a/drivers/scsi/stex.c
+++ b/drivers/scsi/stex.c
@@ -17,7 +17,6 @@
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/delay.h>
-#include <linux/sched.h>
#include <linux/time.h>
#include <linux/pci.h>
#include <linux/blkdev.h>
diff --git a/drivers/scsi/sun3_scsi.c b/drivers/scsi/sun3_scsi.c
index 69ee3e4a820..5e46d842c6f 100644
--- a/drivers/scsi/sun3_scsi.c
+++ b/drivers/scsi/sun3_scsi.c
@@ -58,7 +58,6 @@
#include <linux/module.h>
#include <linux/signal.h>
-#include <linux/sched.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/blkdev.h>
diff --git a/drivers/scsi/sun3_scsi_vme.c b/drivers/scsi/sun3_scsi_vme.c
index bb0c9fd99e6..7cb4a31453e 100644
--- a/drivers/scsi/sun3_scsi_vme.c
+++ b/drivers/scsi/sun3_scsi_vme.c
@@ -20,7 +20,6 @@
#include <linux/module.h>
#include <linux/signal.h>
-#include <linux/sched.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/blkdev.h>
diff --git a/drivers/scsi/sun3x_esp.c b/drivers/scsi/sun3x_esp.c
index 6b60536ac92..80fb3f88af2 100644
--- a/drivers/scsi/sun3x_esp.c
+++ b/drivers/scsi/sun3x_esp.c
@@ -53,7 +53,7 @@ int sun3x_esp_detect(struct scsi_host_template *tpnt)
struct ConfigDev *esp_dev;
esp_dev = 0;
- esp = esp_allocate(tpnt, (void *) esp_dev);
+ esp = esp_allocate(tpnt, esp_dev, 0);
/* Do command transfer with DMA */
esp->do_pio_cmds = 0;
diff --git a/drivers/scsi/sym53c416.c b/drivers/scsi/sym53c416.c
index 32c883f1efa..2ca950582bc 100644
--- a/drivers/scsi/sym53c416.c
+++ b/drivers/scsi/sym53c416.c
@@ -32,7 +32,6 @@
#include <linux/init.h>
#include <linux/string.h>
#include <linux/ioport.h>
-#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/proc_fs.h>
diff --git a/drivers/scsi/sym53c8xx_2/sym_fw1.h b/drivers/scsi/sym53c8xx_2/sym_fw1.h
index 7b39f4a35e9..7b08d6caaa9 100644
--- a/drivers/scsi/sym53c8xx_2/sym_fw1.h
+++ b/drivers/scsi/sym53c8xx_2/sym_fw1.h
@@ -1020,7 +1020,7 @@ static struct SYM_FWA_SCR SYM_FWA_SCR = {
* It shall be a tagged command.
* Read SIMPLE+TAG.
* The C code will deal with errors.
- * Agressive optimization, is'nt it? :)
+ * Aggressive optimization, isn't it? :)
*/
SCR_MOVE_ABS (2) ^ SCR_MSG_IN,
HADDR_1 (msgin),
@@ -1044,7 +1044,7 @@ static struct SYM_FWA_SCR SYM_FWA_SCR = {
RADDR_1 (dsa),
/*
* The SIDL still contains the TAG value.
- * Agressive optimization, isn't it? :):)
+ * Aggressive optimization, isn't it? :):)
*/
SCR_REG_SFBR (sidl, SCR_SHL, 0),
0,
diff --git a/drivers/scsi/sym53c8xx_2/sym_fw2.h b/drivers/scsi/sym53c8xx_2/sym_fw2.h
index 851f2706f22..6e5b952312e 100644
--- a/drivers/scsi/sym53c8xx_2/sym_fw2.h
+++ b/drivers/scsi/sym53c8xx_2/sym_fw2.h
@@ -956,7 +956,7 @@ static struct SYM_FWA_SCR SYM_FWA_SCR = {
* It shall be a tagged command.
* Read SIMPLE+TAG.
* The C code will deal with errors.
- * Agressive optimization, is'nt it? :)
+ * Aggressive optimization, isn't it? :)
*/
SCR_MOVE_ABS (2) ^ SCR_MSG_IN,
HADDR_1 (msgin),
@@ -968,7 +968,7 @@ static struct SYM_FWA_SCR SYM_FWA_SCR = {
offsetof(struct sym_lcb, head.itlq_tbl_sa),
/*
* The SIDL still contains the TAG value.
- * Agressive optimization, isn't it? :):)
+ * Aggressive optimization, isn't it? :):)
*/
SCR_REG_SFBR (sidl, SCR_SHL, 0),
0,
diff --git a/drivers/scsi/t128.c b/drivers/scsi/t128.c
index 0b7a70f61e0..248d60b8d89 100644
--- a/drivers/scsi/t128.c
+++ b/drivers/scsi/t128.c
@@ -108,7 +108,6 @@
#include <asm/system.h>
#include <linux/signal.h>
-#include <linux/sched.h>
#include <linux/io.h>
#include <linux/blkdev.h>
#include <linux/interrupt.h>
diff --git a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c
index fa5382e354b..a583e89238f 100644
--- a/drivers/scsi/tmscsim.c
+++ b/drivers/scsi/tmscsim.c
@@ -221,7 +221,6 @@
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/signal.h>
-#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
diff --git a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c
index 2083454db51..fa4e08e508a 100644
--- a/drivers/scsi/wd33c93.c
+++ b/drivers/scsi/wd33c93.c
@@ -69,11 +69,15 @@
* Added support for pre -A chips, which don't have advanced features
* and will generate CSR_RESEL rather than CSR_RESEL_AM.
* Richard Hirst <richard@sleepie.demon.co.uk> August 2000
+ *
+ * Added support for Burst Mode DMA and Fast SCSI. Enabled the use of
+ * default_sx_per for asynchronous data transfers. Added adjustment
+ * of transfer periods in sx_table to the actual input-clock.
+ * peter fuerst <post@pfrst.de> February 2007
*/
#include <linux/module.h>
-#include <linux/sched.h>
#include <linux/string.h>
#include <linux/delay.h>
#include <linux/init.h>
@@ -87,9 +91,11 @@
#include "wd33c93.h"
+#define optimum_sx_per(hostdata) (hostdata)->sx_table[1].period_ns
+
-#define WD33C93_VERSION "1.26"
-#define WD33C93_DATE "22/Feb/2003"
+#define WD33C93_VERSION "1.26++"
+#define WD33C93_DATE "10/Feb/2007"
MODULE_AUTHOR("John Shifflett");
MODULE_DESCRIPTION("Generic WD33C93 SCSI driver");
@@ -123,6 +129,13 @@ MODULE_LICENSE("GPL");
* defines in wd33c93.h
* - clock:x -x = clock input in MHz for WD33c93 chip. Normal values
* would be from 8 through 20. Default is 8.
+ * - burst:x -x = 1 to use Burst Mode (or Demand-Mode) DMA, x = 0 to use
+ * Single Byte DMA, which is the default. Argument is
+ * optional - if not present, same as "burst:1".
+ * - fast:x -x = 1 to enable Fast SCSI, which is only effective with
+ * input-clock divisor 4 (WD33C93_FS_16_20), x = 0 to disable
+ * it, which is the default. Argument is optional - if not
+ * present, same as "fast:1".
* - next -No argument. Used to separate blocks of keywords when
* there's more than one host adapter in the system.
*
@@ -149,7 +162,7 @@ MODULE_LICENSE("GPL");
*/
/* Normally, no defaults are specified */
-static char *setup_args[] = { "", "", "", "", "", "", "", "", "" };
+static char *setup_args[] = { "", "", "", "", "", "", "", "", "", "" };
static char *setup_strings;
module_param(setup_strings, charp, 0);
@@ -299,20 +312,8 @@ read_1_byte(const wd33c93_regs regs)
return x;
}
-static struct sx_period sx_table[] = {
- {1, 0x20},
- {252, 0x20},
- {376, 0x30},
- {500, 0x40},
- {624, 0x50},
- {752, 0x60},
- {876, 0x70},
- {1000, 0x00},
- {0, 0}
-};
-
static int
-round_period(unsigned int period)
+round_period(unsigned int period, const struct sx_period *sx_table)
{
int x;
@@ -325,17 +326,49 @@ round_period(unsigned int period)
return 7;
}
+/*
+ * Calculate Synchronous Transfer Register value from SDTR code.
+ */
static uchar
-calc_sync_xfer(unsigned int period, unsigned int offset)
+calc_sync_xfer(unsigned int period, unsigned int offset, unsigned int fast,
+ const struct sx_period *sx_table)
{
+ /* When doing Fast SCSI synchronous data transfers, the corresponding
+ * value in 'sx_table' is two times the actually used transfer period.
+ */
uchar result;
+ if (offset && fast) {
+ fast = STR_FSS;
+ period *= 2;
+ } else {
+ fast = 0;
+ }
period *= 4; /* convert SDTR code to ns */
- result = sx_table[round_period(period)].reg_value;
+ result = sx_table[round_period(period,sx_table)].reg_value;
result |= (offset < OPTIMUM_SX_OFF) ? offset : OPTIMUM_SX_OFF;
+ result |= fast;
return result;
}
+/*
+ * Calculate SDTR code bytes [3],[4] from period and offset.
+ */
+static inline void
+calc_sync_msg(unsigned int period, unsigned int offset, unsigned int fast,
+ uchar msg[2])
+{
+ /* 'period' is a "normal"-mode value, like the ones in 'sx_table'. The
+ * actually used transfer period for Fast SCSI synchronous data
+ * transfers is half that value.
+ */
+ period /= 4;
+ if (offset && fast)
+ period /= 2;
+ msg[0] = period;
+ msg[1] = offset;
+}
+
int
wd33c93_queuecommand(struct scsi_cmnd *cmd,
void (*done)(struct scsi_cmnd *))
@@ -633,7 +666,7 @@ wd33c93_execute(struct Scsi_Host *instance)
write_wd33c93_count(regs,
cmd->SCp.this_residual);
write_wd33c93(regs, WD_CONTROL,
- CTRL_IDI | CTRL_EDI | CTRL_DMA);
+ CTRL_IDI | CTRL_EDI | hostdata->dma_mode);
hostdata->dma = D_DMA_RUNNING;
}
} else
@@ -713,6 +746,8 @@ transfer_bytes(const wd33c93_regs regs, struct scsi_cmnd *cmd,
cmd->SCp.ptr = page_address(cmd->SCp.buffer->page) +
cmd->SCp.buffer->offset;
}
+ if (!cmd->SCp.this_residual) /* avoid bogus setups */
+ return;
write_wd33c93(regs, WD_SYNCHRONOUS_TRANSFER,
hostdata->sync_xfer[cmd->device->id]);
@@ -745,7 +780,7 @@ transfer_bytes(const wd33c93_regs regs, struct scsi_cmnd *cmd,
#ifdef PROC_STATISTICS
hostdata->dma_cnt++;
#endif
- write_wd33c93(regs, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_DMA);
+ write_wd33c93(regs, WD_CONTROL, CTRL_IDI | CTRL_EDI | hostdata->dma_mode);
write_wd33c93_count(regs, cmd->SCp.this_residual);
if ((hostdata->level2 >= L2_DATA) ||
@@ -863,9 +898,6 @@ wd33c93_intr(struct Scsi_Host *instance)
hostdata->outgoing_msg[0] |= 0x40;
if (hostdata->sync_stat[cmd->device->id] == SS_FIRST) {
-#ifdef SYNC_DEBUG
- printk(" sending SDTR ");
-#endif
hostdata->sync_stat[cmd->device->id] = SS_WAITING;
@@ -879,14 +911,20 @@ wd33c93_intr(struct Scsi_Host *instance)
hostdata->outgoing_msg[2] = 3;
hostdata->outgoing_msg[3] = EXTENDED_SDTR;
if (hostdata->no_sync & (1 << cmd->device->id)) {
- hostdata->outgoing_msg[4] =
- hostdata->default_sx_per / 4;
- hostdata->outgoing_msg[5] = 0;
+ calc_sync_msg(hostdata->default_sx_per, 0,
+ 0, hostdata->outgoing_msg + 4);
} else {
- hostdata->outgoing_msg[4] = OPTIMUM_SX_PER / 4;
- hostdata->outgoing_msg[5] = OPTIMUM_SX_OFF;
+ calc_sync_msg(optimum_sx_per(hostdata),
+ OPTIMUM_SX_OFF,
+ hostdata->fast,
+ hostdata->outgoing_msg + 4);
}
hostdata->outgoing_len = 6;
+#ifdef SYNC_DEBUG
+ ucp = hostdata->outgoing_msg + 1;
+ printk(" sending SDTR %02x03%02x%02x%02x ",
+ ucp[0], ucp[2], ucp[3], ucp[4]);
+#endif
} else
hostdata->outgoing_len = 1;
@@ -1002,8 +1040,13 @@ wd33c93_intr(struct Scsi_Host *instance)
#ifdef SYNC_DEBUG
printk("-REJ-");
#endif
- if (hostdata->sync_stat[cmd->device->id] == SS_WAITING)
+ if (hostdata->sync_stat[cmd->device->id] == SS_WAITING) {
hostdata->sync_stat[cmd->device->id] = SS_SET;
+ /* we want default_sx_per, not DEFAULT_SX_PER */
+ hostdata->sync_xfer[cmd->device->id] =
+ calc_sync_xfer(hostdata->default_sx_per
+ / 4, 0, 0, hostdata->sx_table);
+ }
write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK);
hostdata->state = S_CONNECTED;
break;
@@ -1023,7 +1066,10 @@ wd33c93_intr(struct Scsi_Host *instance)
switch (ucp[2]) { /* what's the EXTENDED code? */
case EXTENDED_SDTR:
- id = calc_sync_xfer(ucp[3], ucp[4]);
+ /* default to default async period */
+ id = calc_sync_xfer(hostdata->
+ default_sx_per / 4, 0,
+ 0, hostdata->sx_table);
if (hostdata->sync_stat[cmd->device->id] !=
SS_WAITING) {
@@ -1042,20 +1088,22 @@ wd33c93_intr(struct Scsi_Host *instance)
hostdata->outgoing_msg[1] = 3;
hostdata->outgoing_msg[2] =
EXTENDED_SDTR;
- hostdata->outgoing_msg[3] =
- hostdata->default_sx_per /
- 4;
- hostdata->outgoing_msg[4] = 0;
+ calc_sync_msg(hostdata->
+ default_sx_per, 0,
+ 0, hostdata->outgoing_msg + 3);
hostdata->outgoing_len = 5;
- hostdata->sync_xfer[cmd->device->id] =
- calc_sync_xfer(hostdata->
- default_sx_per
- / 4, 0);
} else {
- hostdata->sync_xfer[cmd->device->id] = id;
+ if (ucp[4]) /* well, sync transfer */
+ id = calc_sync_xfer(ucp[3], ucp[4],
+ hostdata->fast,
+ hostdata->sx_table);
+ else if (ucp[3]) /* very unlikely... */
+ id = calc_sync_xfer(ucp[3], ucp[4],
+ 0, hostdata->sx_table);
}
+ hostdata->sync_xfer[cmd->device->id] = id;
#ifdef SYNC_DEBUG
- printk("sync_xfer=%02x",
+ printk(" sync_xfer=%02x\n",
hostdata->sync_xfer[cmd->device->id]);
#endif
hostdata->sync_stat[cmd->device->id] =
@@ -1487,7 +1535,7 @@ reset_wd33c93(struct Scsi_Host *instance)
write_wd33c93(regs, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
write_wd33c93(regs, WD_SYNCHRONOUS_TRANSFER,
calc_sync_xfer(hostdata->default_sx_per / 4,
- DEFAULT_SX_OFF));
+ DEFAULT_SX_OFF, 0, hostdata->sx_table));
write_wd33c93(regs, WD_COMMAND, WD_CMD_RESET);
@@ -1513,6 +1561,9 @@ reset_wd33c93(struct Scsi_Host *instance)
} else
hostdata->chip = C_UNKNOWN_CHIP;
+ if (hostdata->chip != C_WD33C93B) /* Fast SCSI unavailable */
+ hostdata->fast = 0;
+
write_wd33c93(regs, WD_TIMEOUT_PERIOD, TIMEOUT_PERIOD_VALUE);
write_wd33c93(regs, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
}
@@ -1534,7 +1585,8 @@ wd33c93_host_reset(struct scsi_cmnd * SCpnt)
for (i = 0; i < 8; i++) {
hostdata->busy[i] = 0;
hostdata->sync_xfer[i] =
- calc_sync_xfer(DEFAULT_SX_PER / 4, DEFAULT_SX_OFF);
+ calc_sync_xfer(DEFAULT_SX_PER / 4, DEFAULT_SX_OFF,
+ 0, hostdata->sx_table);
hostdata->sync_stat[i] = SS_UNSET; /* using default sync values */
}
hostdata->input_Q = NULL;
@@ -1783,6 +1835,98 @@ check_setup_args(char *key, int *flags, int *val, char *buf)
return ++x;
}
+/*
+ * Calculate internal data-transfer-clock cycle from input-clock
+ * frequency (/MHz) and fill 'sx_table'.
+ *
+ * The original driver used to rely on a fixed sx_table, containing periods
+ * for (only) the lower limits of the respective input-clock-frequency ranges
+ * (8-10/12-15/16-20 MHz). Although it seems, that no problems ocurred with
+ * this setting so far, it might be desirable to adjust the transfer periods
+ * closer to the really attached, possibly 25% higher, input-clock, since
+ * - the wd33c93 may really use a significant shorter period, than it has
+ * negotiated (eg. thrashing the target, which expects 4/8MHz, with 5/10MHz
+ * instead).
+ * - the wd33c93 may ask the target for a lower transfer rate, than the target
+ * is capable of (eg. negotiating for an assumed minimum of 252ns instead of
+ * possible 200ns, which indeed shows up in tests as an approx. 10% lower
+ * transfer rate).
+ */
+static inline unsigned int
+round_4(unsigned int x)
+{
+ switch (x & 3) {
+ case 1: --x;
+ break;
+ case 2: ++x;
+ case 3: ++x;
+ }
+ return x;
+}
+
+static void
+calc_sx_table(unsigned int mhz, struct sx_period sx_table[9])
+{
+ unsigned int d, i;
+ if (mhz < 11)
+ d = 2; /* divisor for 8-10 MHz input-clock */
+ else if (mhz < 16)
+ d = 3; /* divisor for 12-15 MHz input-clock */
+ else
+ d = 4; /* divisor for 16-20 MHz input-clock */
+
+ d = (100000 * d) / 2 / mhz; /* 100 x DTCC / nanosec */
+
+ sx_table[0].period_ns = 1;
+ sx_table[0].reg_value = 0x20;
+ for (i = 1; i < 8; i++) {
+ sx_table[i].period_ns = round_4((i+1)*d / 100);
+ sx_table[i].reg_value = (i+1)*0x10;
+ }
+ sx_table[7].reg_value = 0;
+ sx_table[8].period_ns = 0;
+ sx_table[8].reg_value = 0;
+}
+
+/*
+ * check and, maybe, map an init- or "clock:"- argument.
+ */
+static uchar
+set_clk_freq(int freq, int *mhz)
+{
+ int x = freq;
+ if (WD33C93_FS_8_10 == freq)
+ freq = 8;
+ else if (WD33C93_FS_12_15 == freq)
+ freq = 12;
+ else if (WD33C93_FS_16_20 == freq)
+ freq = 16;
+ else if (freq > 7 && freq < 11)
+ x = WD33C93_FS_8_10;
+ else if (freq > 11 && freq < 16)
+ x = WD33C93_FS_12_15;
+ else if (freq > 15 && freq < 21)
+ x = WD33C93_FS_16_20;
+ else {
+ /* Hmm, wouldn't it be safer to assume highest freq here? */
+ x = WD33C93_FS_8_10;
+ freq = 8;
+ }
+ *mhz = freq;
+ return x;
+}
+
+/*
+ * to be used with the resync: fast: ... options
+ */
+static inline void set_resync ( struct WD33C93_hostdata *hd, int mask )
+{
+ int i;
+ for (i = 0; i < 8; i++)
+ if (mask & (1 << i))
+ hd->sync_stat[i] = SS_UNSET;
+}
+
void
wd33c93_init(struct Scsi_Host *instance, const wd33c93_regs regs,
dma_setup_t setup, dma_stop_t stop, int clock_freq)
@@ -1799,7 +1943,8 @@ wd33c93_init(struct Scsi_Host *instance, const wd33c93_regs regs,
hostdata = (struct WD33C93_hostdata *) instance->hostdata;
hostdata->regs = regs;
- hostdata->clock_freq = clock_freq;
+ hostdata->clock_freq = set_clk_freq(clock_freq, &i);
+ calc_sx_table(i, hostdata->sx_table);
hostdata->dma_setup = setup;
hostdata->dma_stop = stop;
hostdata->dma_bounce_buffer = NULL;
@@ -1807,7 +1952,8 @@ wd33c93_init(struct Scsi_Host *instance, const wd33c93_regs regs,
for (i = 0; i < 8; i++) {
hostdata->busy[i] = 0;
hostdata->sync_xfer[i] =
- calc_sync_xfer(DEFAULT_SX_PER / 4, DEFAULT_SX_OFF);
+ calc_sync_xfer(DEFAULT_SX_PER / 4, DEFAULT_SX_OFF,
+ 0, hostdata->sx_table);
hostdata->sync_stat[i] = SS_UNSET; /* using default sync values */
#ifdef PROC_STATISTICS
hostdata->cmd_cnt[i] = 0;
@@ -1829,6 +1975,8 @@ wd33c93_init(struct Scsi_Host *instance, const wd33c93_regs regs,
hostdata->default_sx_per = DEFAULT_SX_PER;
hostdata->no_sync = 0xff; /* sync defaults to off */
hostdata->no_dma = 0; /* default is DMA enabled */
+ hostdata->fast = 0; /* default is Fast SCSI transfers disabled */
+ hostdata->dma_mode = CTRL_DMA; /* default is Single Byte DMA */
#ifdef PROC_INTERFACE
hostdata->proc = PR_VERSION | PR_INFO | PR_STATISTICS |
@@ -1840,6 +1988,11 @@ wd33c93_init(struct Scsi_Host *instance, const wd33c93_regs regs,
#endif
#endif
+ if (check_setup_args("clock", &flags, &val, buf)) {
+ hostdata->clock_freq = set_clk_freq(val, &val);
+ calc_sx_table(val, hostdata->sx_table);
+ }
+
if (check_setup_args("nosync", &flags, &val, buf))
hostdata->no_sync = val;
@@ -1848,7 +2001,8 @@ wd33c93_init(struct Scsi_Host *instance, const wd33c93_regs regs,
if (check_setup_args("period", &flags, &val, buf))
hostdata->default_sx_per =
- sx_table[round_period((unsigned int) val)].period_ns;
+ hostdata->sx_table[round_period((unsigned int) val,
+ hostdata->sx_table)].period_ns;
if (check_setup_args("disconnect", &flags, &val, buf)) {
if ((val >= DIS_NEVER) && (val <= DIS_ALWAYS))
@@ -1863,17 +2017,12 @@ wd33c93_init(struct Scsi_Host *instance, const wd33c93_regs regs,
if (check_setup_args("debug", &flags, &val, buf))
hostdata->args = val & DB_MASK;
- if (check_setup_args("clock", &flags, &val, buf)) {
- if (val > 7 && val < 11)
- val = WD33C93_FS_8_10;
- else if (val > 11 && val < 16)
- val = WD33C93_FS_12_15;
- else if (val > 15 && val < 21)
- val = WD33C93_FS_16_20;
- else
- val = WD33C93_FS_8_10;
- hostdata->clock_freq = val;
- }
+ if (check_setup_args("burst", &flags, &val, buf))
+ hostdata->dma_mode = val ? CTRL_BURST:CTRL_DMA;
+
+ if (WD33C93_FS_16_20 == hostdata->clock_freq /* divisor 4 */
+ && check_setup_args("fast", &flags, &val, buf))
+ hostdata->fast = !!val;
if ((i = check_setup_args("next", &flags, &val, buf))) {
while (i)
@@ -1918,53 +2067,65 @@ wd33c93_proc_info(struct Scsi_Host *instance, char *buf, char **start, off_t off
char tbuf[128];
struct WD33C93_hostdata *hd;
struct scsi_cmnd *cmd;
- int x, i;
+ int x;
static int stop = 0;
hd = (struct WD33C93_hostdata *) instance->hostdata;
/* If 'in' is TRUE we need to _read_ the proc file. We accept the following
- * keywords (same format as command-line, but only ONE per read):
+ * keywords (same format as command-line, but arguments are not optional):
* debug
* disconnect
* period
* resync
* proc
* nodma
+ * level2
+ * burst
+ * fast
+ * nosync
*/
if (in) {
buf[len] = '\0';
- bp = buf;
+ for (bp = buf; *bp; ) {
+ while (',' == *bp || ' ' == *bp)
+ ++bp;
if (!strncmp(bp, "debug:", 6)) {
- bp += 6;
- hd->args = simple_strtoul(bp, NULL, 0) & DB_MASK;
+ hd->args = simple_strtoul(bp+6, &bp, 0) & DB_MASK;
} else if (!strncmp(bp, "disconnect:", 11)) {
- bp += 11;
- x = simple_strtoul(bp, NULL, 0);
+ x = simple_strtoul(bp+11, &bp, 0);
if (x < DIS_NEVER || x > DIS_ALWAYS)
x = DIS_ADAPTIVE;
hd->disconnect = x;
} else if (!strncmp(bp, "period:", 7)) {
- bp += 7;
- x = simple_strtoul(bp, NULL, 0);
+ x = simple_strtoul(bp+7, &bp, 0);
hd->default_sx_per =
- sx_table[round_period((unsigned int) x)].period_ns;
+ hd->sx_table[round_period((unsigned int) x,
+ hd->sx_table)].period_ns;
} else if (!strncmp(bp, "resync:", 7)) {
- bp += 7;
- x = simple_strtoul(bp, NULL, 0);
- for (i = 0; i < 7; i++)
- if (x & (1 << i))
- hd->sync_stat[i] = SS_UNSET;
+ set_resync(hd, (int)simple_strtoul(bp+7, &bp, 0));
} else if (!strncmp(bp, "proc:", 5)) {
- bp += 5;
- hd->proc = simple_strtoul(bp, NULL, 0);
+ hd->proc = simple_strtoul(bp+5, &bp, 0);
} else if (!strncmp(bp, "nodma:", 6)) {
- bp += 6;
- hd->no_dma = simple_strtoul(bp, NULL, 0);
+ hd->no_dma = simple_strtoul(bp+6, &bp, 0);
} else if (!strncmp(bp, "level2:", 7)) {
- bp += 7;
- hd->level2 = simple_strtoul(bp, NULL, 0);
+ hd->level2 = simple_strtoul(bp+7, &bp, 0);
+ } else if (!strncmp(bp, "burst:", 6)) {
+ hd->dma_mode =
+ simple_strtol(bp+6, &bp, 0) ? CTRL_BURST:CTRL_DMA;
+ } else if (!strncmp(bp, "fast:", 5)) {
+ x = !!simple_strtol(bp+5, &bp, 0);
+ if (x != hd->fast)
+ set_resync(hd, 0xff);
+ hd->fast = x;
+ } else if (!strncmp(bp, "nosync:", 7)) {
+ x = simple_strtoul(bp+7, &bp, 0);
+ set_resync(hd, x ^ hd->no_sync);
+ hd->no_sync = x;
+ } else {
+ break; /* unknown keyword,syntax-error,... */
+ }
}
return len;
}
@@ -1978,8 +2139,9 @@ wd33c93_proc_info(struct Scsi_Host *instance, char *buf, char **start, off_t off
strcat(bp, tbuf);
}
if (hd->proc & PR_INFO) {
- sprintf(tbuf, "\nclock_freq=%02x no_sync=%02x no_dma=%d",
- hd->clock_freq, hd->no_sync, hd->no_dma);
+ sprintf(tbuf, "\nclock_freq=%02x no_sync=%02x no_dma=%d"
+ " dma_mode=%02x fast=%d",
+ hd->clock_freq, hd->no_sync, hd->no_dma, hd->dma_mode, hd->fast);
strcat(bp, tbuf);
strcat(bp, "\nsync_xfer[] = ");
for (x = 0; x < 7; x++) {
diff --git a/drivers/scsi/wd33c93.h b/drivers/scsi/wd33c93.h
index edcb0365cf0..61ffb860dac 100644
--- a/drivers/scsi/wd33c93.h
+++ b/drivers/scsi/wd33c93.h
@@ -155,6 +155,9 @@
#define WD33C93_FS_12_15 OWNID_FS_12
#define WD33C93_FS_16_20 OWNID_FS_16
+ /* pass input-clock explicitely. accepted mhz values are 8-10,12-20 */
+#define WD33C93_FS_MHZ(mhz) (mhz)
+
/* Control register */
#define CTRL_HSP 0x01
#define CTRL_HA 0x02
@@ -253,6 +256,9 @@ struct WD33C93_hostdata {
uchar sync_stat[8]; /* status of sync negotiation per target */
uchar no_sync; /* bitmask: don't do sync on these targets */
uchar no_dma; /* set this flag to disable DMA */
+ uchar dma_mode; /* DMA Burst Mode or Single Byte DMA */
+ uchar fast; /* set this flag to enable Fast SCSI */
+ struct sx_period sx_table[9]; /* transfer periods for actual DTC-setting */
#ifdef PROC_INTERFACE
uchar proc; /* bitmask: what's in proc output */
#ifdef PROC_STATISTICS
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index 5261f0af8b1..c129a0e8e80 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -364,6 +364,23 @@ serial_out(struct uart_8250_port *up, int offset, int value)
}
}
+static void
+serial_out_sync(struct uart_8250_port *up, int offset, int value)
+{
+ switch (up->port.iotype) {
+ case UPIO_MEM:
+ case UPIO_MEM32:
+#ifdef CONFIG_SERIAL_8250_AU1X00
+ case UPIO_AU:
+#endif
+ serial_out(up, offset, value);
+ serial_in(up, UART_LCR); /* safe, no side-effects */
+ break;
+ default:
+ serial_out(up, offset, value);
+ }
+}
+
/*
* We used to support using pause I/O for certain machines. We
* haven't supported this for a while, but just in case it's badly
@@ -920,12 +937,16 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
#ifdef __i386__
outb(0xff, 0x080);
#endif
- scratch2 = serial_inp(up, UART_IER);
+ /*
+ * Mask out IER[7:4] bits for test as some UARTs (e.g. TL
+ * 16C754B) allow only to modify them if an EFR bit is set.
+ */
+ scratch2 = serial_inp(up, UART_IER) & 0x0f;
serial_outp(up, UART_IER, 0x0F);
#ifdef __i386__
outb(0, 0x080);
#endif
- scratch3 = serial_inp(up, UART_IER);
+ scratch3 = serial_inp(up, UART_IER) & 0x0f;
serial_outp(up, UART_IER, scratch);
if (scratch2 != 0 || scratch3 != 0x0F) {
/*
@@ -1041,7 +1062,7 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
#endif
serial_outp(up, UART_MCR, save_mcr);
serial8250_clear_fifos(up);
- (void)serial_in(up, UART_RX);
+ serial_in(up, UART_RX);
if (up->capabilities & UART_CAP_UUE)
serial_outp(up, UART_IER, UART_IER_UUE);
else
@@ -1175,7 +1196,7 @@ static void serial8250_enable_ms(struct uart_port *port)
}
static void
-receive_chars(struct uart_8250_port *up, int *status)
+receive_chars(struct uart_8250_port *up, unsigned int *status)
{
struct tty_struct *tty = up->port.info->tty;
unsigned char ch, lsr = *status;
@@ -1447,6 +1468,12 @@ static void serial_unlink_irq_chain(struct uart_8250_port *up)
serial_do_unlink(i, up);
}
+/* Base timer interval for polling */
+static inline int poll_timeout(int timeout)
+{
+ return timeout > 6 ? (timeout / 2 - 2) : 1;
+}
+
/*
* This function is used to handle ports that do not have an
* interrupt. This doesn't work very well for 16450's, but gives
@@ -1456,16 +1483,51 @@ static void serial_unlink_irq_chain(struct uart_8250_port *up)
static void serial8250_timeout(unsigned long data)
{
struct uart_8250_port *up = (struct uart_8250_port *)data;
- unsigned int timeout;
unsigned int iir;
iir = serial_in(up, UART_IIR);
if (!(iir & UART_IIR_NO_INT))
serial8250_handle_port(up);
+ mod_timer(&up->timer, jiffies + poll_timeout(up->port.timeout));
+}
+
+static void serial8250_backup_timeout(unsigned long data)
+{
+ struct uart_8250_port *up = (struct uart_8250_port *)data;
+ unsigned int iir, ier = 0;
+
+ /*
+ * Must disable interrupts or else we risk racing with the interrupt
+ * based handler.
+ */
+ if (is_real_interrupt(up->port.irq)) {
+ ier = serial_in(up, UART_IER);
+ serial_out(up, UART_IER, 0);
+ }
+
+ iir = serial_in(up, UART_IIR);
+
+ /*
+ * This should be a safe test for anyone who doesn't trust the
+ * IIR bits on their UART, but it's specifically designed for
+ * the "Diva" UART used on the management processor on many HP
+ * ia64 and parisc boxes.
+ */
+ if ((iir & UART_IIR_NO_INT) && (up->ier & UART_IER_THRI) &&
+ (!uart_circ_empty(&up->port.info->xmit) || up->port.x_char) &&
+ (serial_in(up, UART_LSR) & UART_LSR_THRE)) {
+ iir &= ~(UART_IIR_ID | UART_IIR_NO_INT);
+ iir |= UART_IIR_THRI;
+ }
+
+ if (!(iir & UART_IIR_NO_INT))
+ serial8250_handle_port(up);
+
+ if (is_real_interrupt(up->port.irq))
+ serial_out(up, UART_IER, ier);
- timeout = up->port.timeout;
- timeout = timeout > 6 ? (timeout / 2 - 2) : 1;
- mod_timer(&up->timer, jiffies + timeout);
+ /* Standard timer interval plus 0.2s to keep the port running */
+ mod_timer(&up->timer, jiffies + poll_timeout(up->port.timeout) + HZ/5);
}
static unsigned int serial8250_tx_empty(struct uart_port *port)
@@ -1536,6 +1598,37 @@ 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
+ */
+static inline void wait_for_xmitr(struct uart_8250_port *up, int bits)
+{
+ unsigned int status, tmout = 10000;
+
+ /* Wait up to 10ms for the character(s) to be sent. */
+ do {
+ status = serial_in(up, UART_LSR);
+
+ if (status & UART_LSR_BI)
+ up->lsr_break_flag = UART_LSR_BI;
+
+ if (--tmout == 0)
+ break;
+ udelay(1);
+ } while ((status & bits) != bits);
+
+ /* Wait up to 1s for flow control if necessary */
+ if (up->port.flags & UPF_CONS_FLOW) {
+ tmout = 1000000;
+ while (!(serial_in(up, UART_MSR) & UART_MSR_CTS) && --tmout) {
+ udelay(1);
+ touch_nmi_watchdog();
+ }
+ }
+}
+
static int serial8250_startup(struct uart_port *port)
{
struct uart_8250_port *up = (struct uart_8250_port *)port;
@@ -1609,18 +1702,50 @@ static int serial8250_startup(struct uart_port *port)
serial_outp(up, UART_LCR, 0);
}
+ if (is_real_interrupt(up->port.irq)) {
+ /*
+ * Test for UARTs that do not reassert THRE when the
+ * transmitter is idle and the interrupt has already
+ * been cleared. Real 16550s should always reassert
+ * this interrupt whenever the transmitter is idle and
+ * the interrupt is enabled. Delays are necessary to
+ * allow register changes to become visible.
+ */
+ spin_lock_irqsave(&up->port.lock, flags);
+
+ wait_for_xmitr(up, UART_LSR_THRE);
+ serial_out_sync(up, UART_IER, UART_IER_THRI);
+ udelay(1); /* allow THRE to set */
+ serial_in(up, UART_IIR);
+ serial_out(up, UART_IER, 0);
+ serial_out_sync(up, UART_IER, UART_IER_THRI);
+ udelay(1); /* allow a working UART time to re-assert THRE */
+ iir = serial_in(up, UART_IIR);
+ serial_out(up, UART_IER, 0);
+
+ spin_unlock_irqrestore(&up->port.lock, flags);
+
+ /*
+ * If the interrupt is not reasserted, setup a timer to
+ * kick the UART on a regular basis.
+ */
+ if (iir & UART_IIR_NO_INT) {
+ pr_debug("ttyS%d - using backup timer\n", port->line);
+ up->timer.function = serial8250_backup_timeout;
+ up->timer.data = (unsigned long)up;
+ mod_timer(&up->timer, jiffies +
+ poll_timeout(up->port.timeout) + HZ/5);
+ }
+ }
+
/*
* If the "interrupt" for this port doesn't correspond with any
* hardware interrupt, we use a timer-based system. The original
* driver used to do this with IRQ0.
*/
if (!is_real_interrupt(up->port.irq)) {
- unsigned int timeout = up->port.timeout;
-
- timeout = timeout > 6 ? (timeout / 2 - 2) : 1;
-
up->timer.data = (unsigned long)up;
- mod_timer(&up->timer, jiffies + timeout);
+ mod_timer(&up->timer, jiffies + poll_timeout(up->port.timeout));
} else {
retval = serial_link_irq_chain(up);
if (retval)
@@ -1736,9 +1861,9 @@ static void serial8250_shutdown(struct uart_port *port)
*/
(void) serial_in(up, UART_RX);
- if (!is_real_interrupt(up->port.irq))
- del_timer_sync(&up->timer);
- else
+ del_timer_sync(&up->timer);
+ up->timer.function = serial8250_timeout;
+ if (is_real_interrupt(up->port.irq))
serial_unlink_irq_chain(up);
}
@@ -2208,37 +2333,6 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev)
#ifdef CONFIG_SERIAL_8250_CONSOLE
-#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
-
-/*
- * Wait for transmitter & holding register to empty
- */
-static inline void wait_for_xmitr(struct uart_8250_port *up, int bits)
-{
- unsigned int status, tmout = 10000;
-
- /* Wait up to 10ms for the character(s) to be sent. */
- do {
- status = serial_in(up, UART_LSR);
-
- if (status & UART_LSR_BI)
- up->lsr_break_flag = UART_LSR_BI;
-
- if (--tmout == 0)
- break;
- udelay(1);
- } while ((status & bits) != bits);
-
- /* Wait up to 1s for flow control if necessary */
- if (up->port.flags & UPF_CONS_FLOW) {
- tmout = 1000000;
- while (!(serial_in(up, UART_MSR) & UART_MSR_CTS) && --tmout) {
- udelay(1);
- touch_nmi_watchdog();
- }
- }
-}
-
static void serial8250_console_putchar(struct uart_port *port, int ch)
{
struct uart_8250_port *up = (struct uart_8250_port *)port;
diff --git a/drivers/serial/8250_acorn.c b/drivers/serial/8250_acorn.c
index ef8cc8a70c6..562ba745a04 100644
--- a/drivers/serial/8250_acorn.c
+++ b/drivers/serial/8250_acorn.c
@@ -47,11 +47,10 @@ serial_card_probe(struct expansion_card *ec, const struct ecard_id *id)
unsigned long bus_addr;
unsigned int i;
- info = kmalloc(sizeof(struct serial_card_info), GFP_KERNEL);
+ info = kzalloc(sizeof(struct serial_card_info), GFP_KERNEL);
if (!info)
return -ENOMEM;
- memset(info, 0, sizeof(struct serial_card_info));
info->num_ports = type->num_ports;
bus_addr = ecard_resource_start(ec, type->type);
diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c
index 52e2e64c664..6d7d616e9cc 100644
--- a/drivers/serial/8250_pci.c
+++ b/drivers/serial/8250_pci.c
@@ -16,7 +16,6 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/pci.h>
-#include <linux/sched.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/slab.h>
@@ -679,6 +678,13 @@ static struct pci_serial_quirk pci_serial_quirks[] = {
*/
{
.vendor = PCI_VENDOR_ID_PLX,
+ .device = PCI_DEVICE_ID_PLX_9030,
+ .subvendor = PCI_SUBVENDOR_ID_PERLE,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_PLX,
.device = PCI_DEVICE_ID_PLX_9050,
.subvendor = PCI_SUBVENDOR_ID_EXSYS,
.subdevice = PCI_SUBDEVICE_ID_EXSYS_4055,
@@ -936,6 +942,7 @@ enum pci_board_num_t {
pbn_b2_1_115200,
pbn_b2_2_115200,
+ pbn_b2_4_115200,
pbn_b2_8_115200,
pbn_b2_1_460800,
@@ -1249,6 +1256,12 @@ static struct pciserial_board pci_boards[] __devinitdata = {
.base_baud = 115200,
.uart_offset = 8,
},
+ [pbn_b2_4_115200] = {
+ .flags = FL_BASE2,
+ .num_ports = 4,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
[pbn_b2_8_115200] = {
.flags = FL_BASE2,
.num_ports = 8,
@@ -1614,7 +1627,7 @@ pciserial_init_ports(struct pci_dev *dev, struct pciserial_board *board)
nr_ports = rc;
}
- priv = kmalloc(sizeof(struct serial_private) +
+ priv = kzalloc(sizeof(struct serial_private) +
sizeof(unsigned int) * nr_ports,
GFP_KERNEL);
if (!priv) {
@@ -1622,9 +1635,6 @@ pciserial_init_ports(struct pci_dev *dev, struct pciserial_board *board)
goto err_deinit;
}
- memset(priv, 0, sizeof(struct serial_private) +
- sizeof(unsigned int) * nr_ports);
-
priv->dev = dev;
priv->quirk = quirk;
@@ -1990,6 +2000,10 @@ static struct pci_device_id serial_pci_tbl[] = {
{ PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_DUALMODEM,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_panacom2 },
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030,
+ PCI_VENDOR_ID_ESDGMBH,
+ PCI_DEVICE_ID_ESDGMBH_CPCIASIO4, 0, 0,
+ pbn_b2_4_115200 },
{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
PCI_SUBVENDOR_ID_CHASE_PCIFAST,
PCI_SUBDEVICE_ID_CHASE_PCIFAST4, 0, 0,
@@ -2379,6 +2393,15 @@ static struct pci_device_id serial_pci_tbl[] = {
pbn_b2_2_115200 },
/*
+ * Perle PCI-RAS cards
+ */
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030,
+ PCI_SUBVENDOR_ID_PERLE, PCI_SUBDEVICE_ID_PCI_RAS4,
+ 0, 0, pbn_b2_4_921600 },
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030,
+ PCI_SUBVENDOR_ID_PERLE, PCI_SUBDEVICE_ID_PCI_RAS8,
+ 0, 0, pbn_b2_8_921600 },
+ /*
* 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 d3d6b82706b..cde5db44abf 100644
--- a/drivers/serial/8250_pnp.c
+++ b/drivers/serial/8250_pnp.c
@@ -450,11 +450,11 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
port.dev = &dev->dev;
line = serial8250_register_port(&port);
+ if (line < 0)
+ return -ENODEV;
- if (line >= 0)
- pnp_set_drvdata(dev, (void *)((long)line + 1));
- return line >= 0 ? 0 : -ENODEV;
-
+ pnp_set_drvdata(dev, (void *)((long)line + 1));
+ return 0;
}
static void __devexit serial_pnp_remove(struct pnp_dev *dev)
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 2978c09860e..ad9f321968e 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -262,7 +262,8 @@ config SERIAL_AMBA_PL010
select SERIAL_CORE
help
This selects the ARM(R) AMBA(R) PrimeCell PL010 UART. If you have
- an Integrator/AP or Integrator/PP2 platform, say Y or M here.
+ an Integrator/AP or Integrator/PP2 platform, or if you have a
+ Cirrus Logic EP93xx CPU, say Y or M here.
If unsure, say N.
@@ -686,6 +687,22 @@ config SERIAL_SH_SCI_CONSOLE
depends on SERIAL_SH_SCI=y
select SERIAL_CORE_CONSOLE
+config SERIAL_PNX8XXX
+ bool "Enable PNX8XXX SoCs' UART Support"
+ depends on MIPS && SOC_PNX8550
+ select SERIAL_CORE
+ help
+ If you have a MIPS-based Philips SoC such as PNX8550 or PNX8330
+ and you want to use serial ports, say Y. Otherwise, say N.
+
+config SERIAL_PNX8XXX_CONSOLE
+ bool "Enable PNX8XX0 serial console"
+ depends on SERIAL_PNX8XXX
+ select SERIAL_CORE_CONSOLE
+ help
+ If you have a MIPS-based Philips SoC such as PNX8550 or PNX8330
+ and you want to use serial console, say Y. Otherwise, say N.
+
config SERIAL_CORE
tristate
@@ -916,6 +933,11 @@ config SERIAL_TXX9
config HAS_TXX9_SERIAL
bool
+config SERIAL_TXX9_NR_UARTS
+ int "Maximum number of TMPTX39XX/49XX SIO ports"
+ depends on SERIAL_TXX9
+ default "6"
+
config SERIAL_TXX9_CONSOLE
bool "TMPTX39XX/49XX SIO Console support"
depends on SERIAL_TXX9=y
@@ -994,4 +1016,14 @@ config SERIAL_NETX_CONSOLE
If you have enabled the serial port on the Motorola IMX
CPU you can make it the console by answering Y to this option.
+config SERIAL_OF_PLATFORM
+ tristate "Serial port on Open Firmware platform bus"
+ depends on PPC_OF
+ depends on SERIAL_8250
+ help
+ If you have a PowerPC based system that has serial ports
+ on a platform specific bus, you should enable this option.
+ Currently, only 8250 compatible ports are supported, but
+ others can easily be added.
+
endmenu
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index df3632cd7df..6b3560c5749 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -25,6 +25,7 @@ obj-$(CONFIG_SERIAL_AMBA_PL010) += amba-pl010.o
obj-$(CONFIG_SERIAL_AMBA_PL011) += amba-pl011.o
obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o
obj-$(CONFIG_SERIAL_PXA) += pxa.o
+obj-$(CONFIG_SERIAL_PNX8XXX) += pnx8xxx_uart.o
obj-$(CONFIG_SERIAL_SA1100) += sa1100.o
obj-$(CONFIG_SERIAL_S3C2410) += s3c2410.o
obj-$(CONFIG_SERIAL_SUNCORE) += suncore.o
@@ -58,3 +59,4 @@ obj-$(CONFIG_SERIAL_SGI_IOC3) += ioc3_serial.o
obj-$(CONFIG_SERIAL_ATMEL) += atmel_serial.o
obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o
obj-$(CONFIG_SERIAL_NETX) += netx-serial.o
+obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o
diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c
index 881f886b91c..935f48fa501 100644
--- a/drivers/serial/atmel_serial.c
+++ b/drivers/serial/atmel_serial.c
@@ -33,12 +33,13 @@
#include <linux/sysrq.h>
#include <linux/tty_flip.h>
#include <linux/platform_device.h>
+#include <linux/atmel_pdc.h>
#include <asm/io.h>
#include <asm/mach/serial_at91.h>
#include <asm/arch/board.h>
-#include <asm/arch/at91_pdc.h>
+
#ifdef CONFIG_ARM
#include <asm/arch/cpu.h>
#include <asm/arch/gpio.h>
@@ -73,35 +74,35 @@
#define ATMEL_ISR_PASS_LIMIT 256
-#define UART_PUT_CR(port,v) writel(v, (port)->membase + ATMEL_US_CR)
-#define UART_GET_MR(port) readl((port)->membase + ATMEL_US_MR)
-#define UART_PUT_MR(port,v) writel(v, (port)->membase + ATMEL_US_MR)
-#define UART_PUT_IER(port,v) writel(v, (port)->membase + ATMEL_US_IER)
-#define UART_PUT_IDR(port,v) writel(v, (port)->membase + ATMEL_US_IDR)
-#define UART_GET_IMR(port) readl((port)->membase + ATMEL_US_IMR)
-#define UART_GET_CSR(port) readl((port)->membase + ATMEL_US_CSR)
-#define UART_GET_CHAR(port) readl((port)->membase + ATMEL_US_RHR)
-#define UART_PUT_CHAR(port,v) writel(v, (port)->membase + ATMEL_US_THR)
-#define UART_GET_BRGR(port) readl((port)->membase + ATMEL_US_BRGR)
-#define UART_PUT_BRGR(port,v) writel(v, (port)->membase + ATMEL_US_BRGR)
-#define UART_PUT_RTOR(port,v) writel(v, (port)->membase + ATMEL_US_RTOR)
-
-// #define UART_GET_CR(port) readl((port)->membase + ATMEL_US_CR) // is write-only
+#define UART_PUT_CR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_CR)
+#define UART_GET_MR(port) __raw_readl((port)->membase + ATMEL_US_MR)
+#define UART_PUT_MR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_MR)
+#define UART_PUT_IER(port,v) __raw_writel(v, (port)->membase + ATMEL_US_IER)
+#define UART_PUT_IDR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_IDR)
+#define UART_GET_IMR(port) __raw_readl((port)->membase + ATMEL_US_IMR)
+#define UART_GET_CSR(port) __raw_readl((port)->membase + ATMEL_US_CSR)
+#define UART_GET_CHAR(port) __raw_readl((port)->membase + ATMEL_US_RHR)
+#define UART_PUT_CHAR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_THR)
+#define UART_GET_BRGR(port) __raw_readl((port)->membase + ATMEL_US_BRGR)
+#define UART_PUT_BRGR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_BRGR)
+#define UART_PUT_RTOR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_RTOR)
+
+// #define UART_GET_CR(port) __raw_readl((port)->membase + ATMEL_US_CR) // is write-only
/* PDC registers */
-#define UART_PUT_PTCR(port,v) writel(v, (port)->membase + ATMEL_PDC_PTCR)
-#define UART_GET_PTSR(port) readl((port)->membase + ATMEL_PDC_PTSR)
-
-#define UART_PUT_RPR(port,v) writel(v, (port)->membase + ATMEL_PDC_RPR)
-#define UART_GET_RPR(port) readl((port)->membase + ATMEL_PDC_RPR)
-#define UART_PUT_RCR(port,v) writel(v, (port)->membase + ATMEL_PDC_RCR)
-#define UART_PUT_RNPR(port,v) writel(v, (port)->membase + ATMEL_PDC_RNPR)
-#define UART_PUT_RNCR(port,v) writel(v, (port)->membase + ATMEL_PDC_RNCR)
-
-#define UART_PUT_TPR(port,v) writel(v, (port)->membase + ATMEL_PDC_TPR)
-#define UART_PUT_TCR(port,v) writel(v, (port)->membase + ATMEL_PDC_TCR)
-//#define UART_PUT_TNPR(port,v) writel(v, (port)->membase + ATMEL_PDC_TNPR)
-//#define UART_PUT_TNCR(port,v) writel(v, (port)->membase + ATMEL_PDC_TNCR)
+#define UART_PUT_PTCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_PTCR)
+#define UART_GET_PTSR(port) __raw_readl((port)->membase + ATMEL_PDC_PTSR)
+
+#define UART_PUT_RPR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_RPR)
+#define UART_GET_RPR(port) __raw_readl((port)->membase + ATMEL_PDC_RPR)
+#define UART_PUT_RCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_RCR)
+#define UART_PUT_RNPR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_RNPR)
+#define UART_PUT_RNCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_RNCR)
+
+#define UART_PUT_TPR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_TPR)
+#define UART_PUT_TCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_TCR)
+//#define UART_PUT_TNPR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_TNPR)
+//#define UART_PUT_TNCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_TNCR)
static int (*atmel_open_hook)(struct uart_port *);
static void (*atmel_close_hook)(struct uart_port *);
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.c b/drivers/serial/cpm_uart/cpm_uart_cpm1.c
index 08e55fdc882..925fb607d8c 100644
--- a/drivers/serial/cpm_uart/cpm_uart_cpm1.c
+++ b/drivers/serial/cpm_uart/cpm_uart_cpm1.c
@@ -40,6 +40,7 @@
#include <asm/io.h>
#include <asm/irq.h>
+#include <asm/fs_pd.h>
#include <linux/serial_core.h>
#include <linux/kernel.h>
@@ -145,7 +146,7 @@ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con)
/* was hostalloc but changed cause it blows away the */
/* large tlb mapping when pinning the kernel area */
mem_addr = (u8 *) cpm_dpram_addr(cpm_dpalloc(memsz, 8));
- dma_addr = (u32)mem_addr;
+ dma_addr = (u32)cpm_dpram_phys(mem_addr);
} else
mem_addr = dma_alloc_coherent(NULL, memsz, &dma_addr,
GFP_KERNEL);
@@ -205,7 +206,7 @@ int __init cpm_uart_init_portdesc(void)
(unsigned long)&cpmp->cp_smc[0];
cpm_uart_ports[UART_SMC1].smcp->smc_smcm |= (SMCM_RX | SMCM_TX);
cpm_uart_ports[UART_SMC1].smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
- cpm_uart_ports[UART_SMC1].port.uartclk = (((bd_t *) __res)->bi_intfreq);
+ cpm_uart_ports[UART_SMC1].port.uartclk = uart_clock();
cpm_uart_port_map[cpm_uart_nr++] = UART_SMC1;
#endif
@@ -217,7 +218,7 @@ int __init cpm_uart_init_portdesc(void)
(unsigned long)&cpmp->cp_smc[1];
cpm_uart_ports[UART_SMC2].smcp->smc_smcm |= (SMCM_RX | SMCM_TX);
cpm_uart_ports[UART_SMC2].smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
- cpm_uart_ports[UART_SMC2].port.uartclk = (((bd_t *) __res)->bi_intfreq);
+ cpm_uart_ports[UART_SMC2].port.uartclk = uart_clock();
cpm_uart_port_map[cpm_uart_nr++] = UART_SMC2;
#endif
@@ -231,7 +232,7 @@ int __init cpm_uart_init_portdesc(void)
~(UART_SCCM_TX | UART_SCCM_RX);
cpm_uart_ports[UART_SCC1].sccp->scc_gsmrl &=
~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
- cpm_uart_ports[UART_SCC1].port.uartclk = (((bd_t *) __res)->bi_intfreq);
+ cpm_uart_ports[UART_SCC1].port.uartclk = uart_clock();
cpm_uart_port_map[cpm_uart_nr++] = UART_SCC1;
#endif
@@ -245,7 +246,7 @@ int __init cpm_uart_init_portdesc(void)
~(UART_SCCM_TX | UART_SCCM_RX);
cpm_uart_ports[UART_SCC2].sccp->scc_gsmrl &=
~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
- cpm_uart_ports[UART_SCC2].port.uartclk = (((bd_t *) __res)->bi_intfreq);
+ cpm_uart_ports[UART_SCC2].port.uartclk = uart_clock();
cpm_uart_port_map[cpm_uart_nr++] = UART_SCC2;
#endif
@@ -259,7 +260,7 @@ int __init cpm_uart_init_portdesc(void)
~(UART_SCCM_TX | UART_SCCM_RX);
cpm_uart_ports[UART_SCC3].sccp->scc_gsmrl &=
~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
- cpm_uart_ports[UART_SCC3].port.uartclk = (((bd_t *) __res)->bi_intfreq);
+ cpm_uart_ports[UART_SCC3].port.uartclk = uart_clock();
cpm_uart_port_map[cpm_uart_nr++] = UART_SCC3;
#endif
@@ -273,7 +274,7 @@ int __init cpm_uart_init_portdesc(void)
~(UART_SCCM_TX | UART_SCCM_RX);
cpm_uart_ports[UART_SCC4].sccp->scc_gsmrl &=
~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
- cpm_uart_ports[UART_SCC4].port.uartclk = (((bd_t *) __res)->bi_intfreq);
+ cpm_uart_ports[UART_SCC4].port.uartclk = uart_clock();
cpm_uart_port_map[cpm_uart_nr++] = UART_SCC4;
#endif
return 0;
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.h b/drivers/serial/cpm_uart/cpm_uart_cpm1.h
index 5eb49ea63bf..a99e45e2b6d 100644
--- a/drivers/serial/cpm_uart/cpm_uart_cpm1.h
+++ b/drivers/serial/cpm_uart/cpm_uart_cpm1.h
@@ -20,9 +20,6 @@
#define SCC3_IRQ (CPM_IRQ_OFFSET + CPMVEC_SCC3)
#define SCC4_IRQ (CPM_IRQ_OFFSET + CPMVEC_SCC4)
-/* the CPM address */
-#define CPM_ADDR IMAP_ADDR
-
static inline void cpm_set_brg(int brg, int baud)
{
cpm_setbrg(brg, baud);
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.c b/drivers/serial/cpm_uart/cpm_uart_cpm2.c
index 787a8f13467..fa455996ad8 100644
--- a/drivers/serial/cpm_uart/cpm_uart_cpm2.c
+++ b/drivers/serial/cpm_uart/cpm_uart_cpm2.c
@@ -285,7 +285,7 @@ void cpm_uart_freebuf(struct uart_cpm_port *pinfo)
int __init cpm_uart_init_portdesc(void)
{
#if defined(CONFIG_SERIAL_CPM_SMC1) || defined(CONFIG_SERIAL_CPM_SMC2)
- u32 addr;
+ u16 *addr;
#endif
pr_debug("CPM uart[-]:init portdesc\n");
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.h b/drivers/serial/cpm_uart/cpm_uart_cpm2.h
index 4b779111eaf..1b3219f56c8 100644
--- a/drivers/serial/cpm_uart/cpm_uart_cpm2.h
+++ b/drivers/serial/cpm_uart/cpm_uart_cpm2.h
@@ -20,9 +20,6 @@
#define SCC3_IRQ SIU_INT_SCC3
#define SCC4_IRQ SIU_INT_SCC4
-/* the CPM address */
-#define CPM_ADDR CPM_MAP_ADDR
-
static inline void cpm_set_brg(int brg, int baud)
{
cpm_setbrg(brg, baud);
diff --git a/drivers/serial/crisv10.c b/drivers/serial/crisv10.c
index 42b050c46ab..312bef6bd58 100644
--- a/drivers/serial/crisv10.c
+++ b/drivers/serial/crisv10.c
@@ -3173,12 +3173,8 @@ do_softint(void *private_)
if (!tty)
return;
- if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
- tty->ldisc.write_wakeup)
- (tty->ldisc.write_wakeup)(tty);
- wake_up_interruptible(&tty->write_wait);
- }
+ if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event))
+ tty_wakeup(tty);
}
static int
@@ -3798,11 +3794,7 @@ rs_flush_buffer(struct tty_struct *tty)
info->xmit.head = info->xmit.tail = 0;
restore_flags(flags);
- wake_up_interruptible(&tty->write_wait);
-
- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
- tty->ldisc.write_wakeup)
- (tty->ldisc.write_wakeup)(tty);
+ tty_wakeup(tty);
}
/*
diff --git a/drivers/serial/icom.c b/drivers/serial/icom.c
index 71e6a24d8c2..41431d0d551 100644
--- a/drivers/serial/icom.c
+++ b/drivers/serial/icom.c
@@ -27,7 +27,6 @@
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/signal.h>
-#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/interrupt.h>
#include <linux/tty.h>
@@ -1417,14 +1416,12 @@ static int __devinit icom_alloc_adapter(struct icom_adapter
struct list_head *tmp;
icom_adapter = (struct icom_adapter *)
- kmalloc(sizeof(struct icom_adapter), GFP_KERNEL);
+ kzalloc(sizeof(struct icom_adapter), GFP_KERNEL);
if (!icom_adapter) {
return -ENOMEM;
}
- memset(icom_adapter, 0, sizeof(struct icom_adapter));
-
list_for_each(tmp, &icom_adapter_head) {
cur_adapter_entry =
list_entry(tmp, struct icom_adapter,
diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c
index e216dcf2937..04cc88cc528 100644
--- a/drivers/serial/imx.c
+++ b/drivers/serial/imx.c
@@ -154,7 +154,7 @@ static inline void imx_transmit_buffer(struct imx_port *sport)
{
struct circ_buf *xmit = &sport->port.info->xmit;
- do {
+ while (!(UTS((u32)sport->port.membase) & UTS_TXFULL)) {
/* send xmit->buf[xmit->tail]
* out the port here */
URTX0((u32)sport->port.membase) = xmit->buf[xmit->tail];
@@ -163,7 +163,7 @@ static inline void imx_transmit_buffer(struct imx_port *sport)
sport->port.icount.tx++;
if (uart_circ_empty(xmit))
break;
- } while (!(UTS((u32)sport->port.membase) & UTS_TXFULL));
+ }
if (uart_circ_empty(xmit))
imx_stop_tx(&sport->port);
@@ -178,8 +178,7 @@ static void imx_start_tx(struct uart_port *port)
UCR1((u32)sport->port.membase) |= UCR1_TXMPTYEN;
- if(UTS((u32)sport->port.membase) & UTS_TXEMPTY)
- imx_transmit_buffer(sport);
+ imx_transmit_buffer(sport);
}
static irqreturn_t imx_rtsint(int irq, void *dev_id)
@@ -404,7 +403,8 @@ static int imx_startup(struct uart_port *port)
if (retval) goto error_out2;
retval = request_irq(sport->rtsirq, imx_rtsint,
- IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+ (sport->rtsirq < IMX_IRQS) ? 0 :
+ IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
DRIVER_NAME, sport);
if (retval) goto error_out3;
@@ -678,7 +678,7 @@ static struct imx_port imx_ports[] = {
.mapbase = IMX_UART1_BASE, /* FIXME */
.irq = UART1_MINT_RX,
.uartclk = 16000000,
- .fifosize = 8,
+ .fifosize = 32,
.flags = UPF_BOOT_AUTOCONF,
.ops = &imx_pops,
.line = 0,
@@ -694,7 +694,7 @@ static struct imx_port imx_ports[] = {
.mapbase = IMX_UART2_BASE, /* FIXME */
.irq = UART2_MINT_RX,
.uartclk = 16000000,
- .fifosize = 8,
+ .fifosize = 32,
.flags = UPF_BOOT_AUTOCONF,
.ops = &imx_pops,
.line = 1,
diff --git a/drivers/serial/ioc3_serial.c b/drivers/serial/ioc3_serial.c
index 9cc0be93231..168073f12ce 100644
--- a/drivers/serial/ioc3_serial.c
+++ b/drivers/serial/ioc3_serial.c
@@ -2019,13 +2019,12 @@ ioc3uart_probe(struct ioc3_submodule *is, struct ioc3_driver_data *idd)
DPRINT_CONFIG(("%s (0x%p, 0x%p)\n", __FUNCTION__, is, idd));
- card_ptr = kmalloc(sizeof(struct ioc3_card), GFP_KERNEL);
+ card_ptr = kzalloc(sizeof(struct ioc3_card), GFP_KERNEL);
if (!card_ptr) {
printk(KERN_WARNING "ioc3_attach_one"
": unable to get memory for the IOC3\n");
return -ENOMEM;
}
- memset(card_ptr, 0, sizeof(struct ioc3_card));
idd->data[is->id] = card_ptr;
Submodule_slot = is->id;
@@ -2040,13 +2039,12 @@ ioc3uart_probe(struct ioc3_submodule *is, struct ioc3_driver_data *idd)
/* Create port structures for each port */
for (phys_port = 0; phys_port < PORTS_PER_CARD; phys_port++) {
- port = kmalloc(sizeof(struct ioc3_port), GFP_KERNEL);
+ port = kzalloc(sizeof(struct ioc3_port), GFP_KERNEL);
if (!port) {
printk(KERN_WARNING
"IOC3 serial memory not available for port\n");
goto out4;
}
- memset(port, 0, sizeof(struct ioc3_port));
spin_lock_init(&port->ip_lock);
/* we need to remember the previous ones, to point back to
diff --git a/drivers/serial/ioc4_serial.c b/drivers/serial/ioc4_serial.c
index c862f67c985..0c179384fb0 100644
--- a/drivers/serial/ioc4_serial.c
+++ b/drivers/serial/ioc4_serial.c
@@ -1076,13 +1076,12 @@ static int inline ioc4_attach_local(struct ioc4_driver_data *idd)
/* Create port structures for each port */
for (port_number = 0; port_number < IOC4_NUM_SERIAL_PORTS;
port_number++) {
- port = kmalloc(sizeof(struct ioc4_port), GFP_KERNEL);
+ port = kzalloc(sizeof(struct ioc4_port), GFP_KERNEL);
if (!port) {
printk(KERN_WARNING
"IOC4 serial memory not available for port\n");
return -ENOMEM;
}
- memset(port, 0, sizeof(struct ioc4_port));
spin_lock_init(&port->ip_lock);
/* we need to remember the previous ones, to point back to
@@ -2685,7 +2684,7 @@ static int ioc4_serial_remove_one(struct ioc4_driver_data *idd)
free_irq(control->ic_irq, soft);
if (soft->is_ioc4_serial_addr) {
iounmap(soft->is_ioc4_serial_addr);
- release_region((unsigned long)
+ release_mem_region((unsigned long)
soft->is_ioc4_serial_addr,
sizeof(struct ioc4_serial));
}
@@ -2790,7 +2789,7 @@ ioc4_serial_attach_one(struct ioc4_driver_data *idd)
/* request serial registers */
tmp_addr1 = idd->idd_bar0 + IOC4_SERIAL_OFFSET;
- if (!request_region(tmp_addr1, sizeof(struct ioc4_serial),
+ if (!request_mem_region(tmp_addr1, sizeof(struct ioc4_serial),
"sioc4_uart")) {
printk(KERN_WARNING
"ioc4 (%p): unable to get request region for "
@@ -2811,7 +2810,7 @@ ioc4_serial_attach_one(struct ioc4_driver_data *idd)
(void *)serial));
/* Get memory for the new card */
- control = kmalloc(sizeof(struct ioc4_control), GFP_KERNEL);
+ control = kzalloc(sizeof(struct ioc4_control), GFP_KERNEL);
if (!control) {
printk(KERN_WARNING "ioc4_attach_one"
@@ -2819,11 +2818,10 @@ ioc4_serial_attach_one(struct ioc4_driver_data *idd)
ret = -ENOMEM;
goto out2;
}
- memset(control, 0, sizeof(struct ioc4_control));
idd->idd_serial_data = control;
/* Allocate the soft structure */
- soft = kmalloc(sizeof(struct ioc4_soft), GFP_KERNEL);
+ soft = kzalloc(sizeof(struct ioc4_soft), GFP_KERNEL);
if (!soft) {
printk(KERN_WARNING
"ioc4 (%p): unable to get memory for the soft struct\n",
@@ -2831,7 +2829,6 @@ ioc4_serial_attach_one(struct ioc4_driver_data *idd)
ret = -ENOMEM;
goto out3;
}
- memset(soft, 0, sizeof(struct ioc4_soft));
spin_lock_init(&soft->is_ir_lock);
soft->is_ioc4_misc_addr = idd->idd_misc_regs;
@@ -2889,7 +2886,7 @@ out3:
out2:
if (serial)
iounmap(serial);
- release_region(tmp_addr1, sizeof(struct ioc4_serial));
+ release_mem_region(tmp_addr1, sizeof(struct ioc4_serial));
out1:
return ret;
diff --git a/drivers/serial/ip22zilog.c b/drivers/serial/ip22zilog.c
index 0746c9446ae..c3abfb39f31 100644
--- a/drivers/serial/ip22zilog.c
+++ b/drivers/serial/ip22zilog.c
@@ -14,7 +14,6 @@
*/
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/delay.h>
#include <linux/tty.h>
@@ -922,13 +921,7 @@ static int zilog_irq = -1;
static void * __init alloc_one_table(unsigned long size)
{
- void *ret;
-
- ret = kmalloc(size, GFP_KERNEL);
- if (ret != NULL)
- memset(ret, 0, size);
-
- return ret;
+ return kzalloc(size, GFP_KERNEL);
}
static void __init ip22zilog_alloc_tables(void)
diff --git a/drivers/serial/jsm/jsm_driver.c b/drivers/serial/jsm/jsm_driver.c
index 244f63be3a0..81792e6eeb2 100644
--- a/drivers/serial/jsm/jsm_driver.c
+++ b/drivers/serial/jsm/jsm_driver.c
@@ -71,14 +71,13 @@ static int jsm_probe_one(struct pci_dev *pdev, const struct pci_device_id *ent)
goto out_disable_device;
}
- brd = kmalloc(sizeof(struct jsm_board), GFP_KERNEL);
+ brd = kzalloc(sizeof(struct jsm_board), GFP_KERNEL);
if (!brd) {
dev_err(&pdev->dev,
"memory allocation for board structure failed\n");
rc = -ENOMEM;
goto out_release_regions;
}
- memset(brd, 0, sizeof(struct jsm_board));
/* store the info for the board we've found */
brd->boardnum = adapter_count++;
@@ -152,7 +151,7 @@ static int jsm_probe_one(struct pci_dev *pdev, const struct pci_device_id *ent)
* Okay to malloc with GFP_KERNEL, we are not at interrupt
* context, and there are no locks held.
*/
- brd->flipbuf = kmalloc(MYFLIPLEN, GFP_KERNEL);
+ brd->flipbuf = kzalloc(MYFLIPLEN, GFP_KERNEL);
if (!brd->flipbuf) {
/* XXX: leaking all resources from jsm_tty_init and
jsm_uart_port_init here! */
@@ -160,7 +159,6 @@ static int jsm_probe_one(struct pci_dev *pdev, const struct pci_device_id *ent)
retval = -ENOMEM;
goto out_free_irq;
}
- memset(brd->flipbuf, 0, MYFLIPLEN);
pci_set_drvdata(pdev, brd);
diff --git a/drivers/serial/jsm/jsm_tty.c b/drivers/serial/jsm/jsm_tty.c
index 7cf1c60027f..be22bbdbc8e 100644
--- a/drivers/serial/jsm/jsm_tty.c
+++ b/drivers/serial/jsm/jsm_tty.c
@@ -194,31 +194,28 @@ static int jsm_tty_open(struct uart_port *port)
/* Drop locks, as malloc with GFP_KERNEL can sleep */
if (!channel->ch_rqueue) {
- channel->ch_rqueue = (u8 *) kmalloc(RQUEUESIZE, GFP_KERNEL);
+ channel->ch_rqueue = kzalloc(RQUEUESIZE, GFP_KERNEL);
if (!channel->ch_rqueue) {
jsm_printk(INIT, ERR, &channel->ch_bd->pci_dev,
"unable to allocate read queue buf");
return -ENOMEM;
}
- memset(channel->ch_rqueue, 0, RQUEUESIZE);
}
if (!channel->ch_equeue) {
- channel->ch_equeue = (u8 *) kmalloc(EQUEUESIZE, GFP_KERNEL);
+ channel->ch_equeue = kzalloc(EQUEUESIZE, GFP_KERNEL);
if (!channel->ch_equeue) {
jsm_printk(INIT, ERR, &channel->ch_bd->pci_dev,
"unable to allocate error queue buf");
return -ENOMEM;
}
- memset(channel->ch_equeue, 0, EQUEUESIZE);
}
if (!channel->ch_wqueue) {
- channel->ch_wqueue = (u8 *) kmalloc(WQUEUESIZE, GFP_KERNEL);
+ channel->ch_wqueue = kzalloc(WQUEUESIZE, GFP_KERNEL);
if (!channel->ch_wqueue) {
jsm_printk(INIT, ERR, &channel->ch_bd->pci_dev,
"unable to allocate write queue buf");
return -ENOMEM;
}
- memset(channel->ch_wqueue, 0, WQUEUESIZE);
}
channel->ch_flags &= ~(CH_OPENING);
@@ -392,13 +389,12 @@ int jsm_tty_init(struct jsm_board *brd)
* Okay to malloc with GFP_KERNEL, we are not at
* interrupt context, and there are no locks held.
*/
- brd->channels[i] = kmalloc(sizeof(struct jsm_channel), GFP_KERNEL);
+ brd->channels[i] = kzalloc(sizeof(struct jsm_channel), GFP_KERNEL);
if (!brd->channels[i]) {
jsm_printk(CORE, ERR, &brd->pci_dev,
"%s:%d Unable to allocate memory for channel struct\n",
__FILE__, __LINE__);
}
- memset(brd->channels[i], 0, sizeof(struct jsm_channel));
}
}
diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c
index 3c4b6c24371..8d24cd52105 100644
--- a/drivers/serial/mpc52xx_uart.c
+++ b/drivers/serial/mpc52xx_uart.c
@@ -127,8 +127,7 @@ static irqreturn_t mpc52xx_uart_int(int irq,void *dev_id);
#if defined(CONFIG_PPC_MERGE)
static struct of_device_id mpc52xx_uart_of_match[] = {
- { .type = "serial", .compatible = "mpc52xx-psc-uart", },
- { .type = "serial", .compatible = "mpc5200-psc", }, /* Efika only! */
+ { .type = "serial", .compatible = "mpc5200-psc-uart", },
{},
};
#endif
@@ -996,8 +995,10 @@ 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;
}
@@ -1068,7 +1069,7 @@ mpc52xx_uart_of_enumerate(void)
continue;
/* Is a particular device number requested? */
- devno = get_property(np, "device_no", NULL);
+ devno = get_property(np, "port-number", NULL);
mpc52xx_uart_of_assign(of_node_get(np), devno ? *devno : -1);
}
diff --git a/drivers/serial/of_serial.c b/drivers/serial/of_serial.c
new file mode 100644
index 00000000000..09b0b736a75
--- /dev/null
+++ b/drivers/serial/of_serial.c
@@ -0,0 +1,143 @@
+/*
+ * Serial Port driver for Open Firmware platform devices
+ *
+ * Copyright (C) 2006 Arnd Bergmann <arnd@arndb.de>, IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
+
+#include <asm/of_platform.h>
+#include <asm/prom.h>
+
+/*
+ * Fill a struct uart_port for a given device node
+ */
+static int __devinit of_platform_serial_setup(struct of_device *ofdev,
+ int type, struct uart_port *port)
+{
+ struct resource resource;
+ struct device_node *np = ofdev->node;
+ const unsigned int *clk, *spd;
+ int ret;
+
+ memset(port, 0, sizeof *port);
+ spd = get_property(np, "current-speed", NULL);
+ clk = get_property(np, "clock-frequency", NULL);
+ if (!clk) {
+ dev_warn(&ofdev->dev, "no clock-frequency property set\n");
+ return -ENODEV;
+ }
+
+ ret = of_address_to_resource(np, 0, &resource);
+ if (ret) {
+ dev_warn(&ofdev->dev, "invalid address\n");
+ return ret;
+ }
+
+ spin_lock_init(&port->lock);
+ port->mapbase = resource.start;
+ port->irq = irq_of_parse_and_map(np, 0);
+ port->iotype = UPIO_MEM;
+ port->type = type;
+ port->uartclk = *clk;
+ port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP;
+ port->dev = &ofdev->dev;
+ port->custom_divisor = *clk / (16 * (*spd));
+
+ return 0;
+}
+
+/*
+ * Try to register a serial port
+ */
+static int __devinit of_platform_serial_probe(struct of_device *ofdev,
+ const struct of_device_id *id)
+{
+ struct uart_port port;
+ int port_type;
+ int ret;
+
+ if (of_find_property(ofdev->node, "used-by-rtas", NULL))
+ return -EBUSY;
+
+ port_type = (unsigned long)id->data;
+ ret = of_platform_serial_setup(ofdev, port_type, &port);
+ if (ret)
+ goto out;
+
+ switch (port_type) {
+ case PORT_UNKNOWN:
+ dev_info(&ofdev->dev, "Unknown serial port found, "
+ "attempting to use 8250 driver\n");
+ /* fallthrough */
+ case PORT_8250 ... PORT_MAX_8250:
+ ret = serial8250_register_port(&port);
+ break;
+ default:
+ /* need to add code for these */
+ ret = -ENODEV;
+ break;
+ }
+ if (ret < 0)
+ goto out;
+
+ ofdev->dev.driver_data = (void *)(unsigned long)ret;
+ return 0;
+out:
+ irq_dispose_mapping(port.irq);
+ return ret;
+}
+
+/*
+ * Release a line
+ */
+static int of_platform_serial_remove(struct of_device *ofdev)
+{
+ int line = (unsigned long)ofdev->dev.driver_data;
+ serial8250_unregister_port(line);
+ return 0;
+}
+
+/*
+ * A few common types, add more as needed.
+ */
+static struct of_device_id __devinitdata of_platform_serial_table[] = {
+ { .type = "serial", .compatible = "ns8250", .data = (void *)PORT_8250, },
+ { .type = "serial", .compatible = "ns16450", .data = (void *)PORT_16450, },
+ { .type = "serial", .compatible = "ns16550", .data = (void *)PORT_16550, },
+ { .type = "serial", .compatible = "ns16750", .data = (void *)PORT_16750, },
+ { .type = "serial", .data = (void *)PORT_UNKNOWN, },
+ { /* end of list */ },
+};
+
+static struct of_platform_driver __devinitdata of_platform_serial_driver = {
+ .owner = THIS_MODULE,
+ .name = "of_serial",
+ .probe = of_platform_serial_probe,
+ .remove = of_platform_serial_remove,
+ .match_table = of_platform_serial_table,
+};
+
+static int __init of_platform_serial_init(void)
+{
+ return of_register_platform_driver(&of_platform_serial_driver);
+}
+module_init(of_platform_serial_init);
+
+static void __exit of_platform_serial_exit(void)
+{
+ return of_unregister_platform_driver(&of_platform_serial_driver);
+};
+module_exit(of_platform_serial_exit);
+
+MODULE_AUTHOR("Arnd Bergmann <arnd@arndb.de>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Serial Port driver for Open Firmware platform devices");
diff --git a/drivers/serial/pnx8xxx_uart.c b/drivers/serial/pnx8xxx_uart.c
new file mode 100644
index 00000000000..8d01c59e8d0
--- /dev/null
+++ b/drivers/serial/pnx8xxx_uart.c
@@ -0,0 +1,852 @@
+/*
+ * UART driver for PNX8XXX SoCs
+ *
+ * Author: Per Hallsmark per.hallsmark@mvista.com
+ * Ported to 2.6 kernel by EmbeddedAlley
+ * Reworked by Vitaly Wool <vitalywool@gmail.com>
+ *
+ * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ * Copyright (C) 2000 Deep Blue Solutions Ltd.
+ *
+ * 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.
+ *
+ */
+
+#if defined(CONFIG_SERIAL_PNX8XXX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/serial_pnx8xxx.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+/* We'll be using StrongARM sa1100 serial port major/minor */
+#define SERIAL_PNX8XXX_MAJOR 204
+#define MINOR_START 5
+
+#define NR_PORTS 2
+
+#define PNX8XXX_ISR_PASS_LIMIT 256
+
+/*
+ * Convert from ignore_status_mask or read_status_mask to FIFO
+ * and interrupt status bits
+ */
+#define SM_TO_FIFO(x) ((x) >> 10)
+#define SM_TO_ISTAT(x) ((x) & 0x000001ff)
+#define FIFO_TO_SM(x) ((x) << 10)
+#define ISTAT_TO_SM(x) ((x) & 0x000001ff)
+
+/*
+ * This is the size of our serial port register set.
+ */
+#define UART_PORT_SIZE 0x1000
+
+/*
+ * This determines how often we check the modem status signals
+ * for any change. They generally aren't connected to an IRQ
+ * so we have to poll them. We also check immediately before
+ * filling the TX fifo incase CTS has been dropped.
+ */
+#define MCTRL_TIMEOUT (250*HZ/1000)
+
+extern struct pnx8xxx_port pnx8xxx_ports[];
+
+static inline int serial_in(struct pnx8xxx_port *sport, int offset)
+{
+ return (__raw_readl(sport->port.membase + offset));
+}
+
+static inline void serial_out(struct pnx8xxx_port *sport, int offset, int value)
+{
+ __raw_writel(value, sport->port.membase + offset);
+}
+
+/*
+ * Handle any change of modem status signal since we were last called.
+ */
+static void pnx8xxx_mctrl_check(struct pnx8xxx_port *sport)
+{
+ unsigned int status, changed;
+
+ status = sport->port.ops->get_mctrl(&sport->port);
+ changed = status ^ sport->old_status;
+
+ if (changed == 0)
+ return;
+
+ sport->old_status = status;
+
+ if (changed & TIOCM_RI)
+ sport->port.icount.rng++;
+ if (changed & TIOCM_DSR)
+ sport->port.icount.dsr++;
+ if (changed & TIOCM_CAR)
+ uart_handle_dcd_change(&sport->port, status & TIOCM_CAR);
+ if (changed & TIOCM_CTS)
+ uart_handle_cts_change(&sport->port, status & TIOCM_CTS);
+
+ wake_up_interruptible(&sport->port.info->delta_msr_wait);
+}
+
+/*
+ * This is our per-port timeout handler, for checking the
+ * modem status signals.
+ */
+static void pnx8xxx_timeout(unsigned long data)
+{
+ struct pnx8xxx_port *sport = (struct pnx8xxx_port *)data;
+ unsigned long flags;
+
+ if (sport->port.info) {
+ spin_lock_irqsave(&sport->port.lock, flags);
+ pnx8xxx_mctrl_check(sport);
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+
+ mod_timer(&sport->timer, jiffies + MCTRL_TIMEOUT);
+ }
+}
+
+/*
+ * interrupts disabled on entry
+ */
+static void pnx8xxx_stop_tx(struct uart_port *port)
+{
+ struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
+ u32 ien;
+
+ /* Disable TX intr */
+ ien = serial_in(sport, PNX8XXX_IEN);
+ serial_out(sport, PNX8XXX_IEN, ien & ~PNX8XXX_UART_INT_ALLTX);
+
+ /* Clear all pending TX intr */
+ serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLTX);
+}
+
+/*
+ * interrupts may not be disabled on entry
+ */
+static void pnx8xxx_start_tx(struct uart_port *port)
+{
+ struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
+ u32 ien;
+
+ /* Clear all pending TX intr */
+ serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLTX);
+
+ /* Enable TX intr */
+ ien = serial_in(sport, PNX8XXX_IEN);
+ serial_out(sport, PNX8XXX_IEN, ien | PNX8XXX_UART_INT_ALLTX);
+}
+
+/*
+ * Interrupts enabled
+ */
+static void pnx8xxx_stop_rx(struct uart_port *port)
+{
+ struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
+ u32 ien;
+
+ /* Disable RX intr */
+ ien = serial_in(sport, PNX8XXX_IEN);
+ serial_out(sport, PNX8XXX_IEN, ien & ~PNX8XXX_UART_INT_ALLRX);
+
+ /* Clear all pending RX intr */
+ serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLRX);
+}
+
+/*
+ * Set the modem control timer to fire immediately.
+ */
+static void pnx8xxx_enable_ms(struct uart_port *port)
+{
+ struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
+
+ mod_timer(&sport->timer, jiffies);
+}
+
+static void pnx8xxx_rx_chars(struct pnx8xxx_port *sport)
+{
+ struct tty_struct *tty = sport->port.info->tty;
+ unsigned int status, ch, flg;
+
+ status = FIFO_TO_SM(serial_in(sport, PNX8XXX_FIFO)) |
+ ISTAT_TO_SM(serial_in(sport, PNX8XXX_ISTAT));
+ while (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFIFO)) {
+ ch = serial_in(sport, PNX8XXX_FIFO);
+
+ sport->port.icount.rx++;
+
+ flg = TTY_NORMAL;
+
+ /*
+ * note that the error handling code is
+ * out of the main execution path
+ */
+ if (status & (FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE |
+ PNX8XXX_UART_FIFO_RXPAR) |
+ ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN))) {
+ if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR))
+ sport->port.icount.parity++;
+ else if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE))
+ sport->port.icount.frame++;
+ if (status & ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN))
+ sport->port.icount.overrun++;
+
+ status &= sport->port.read_status_mask;
+
+ if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR))
+ flg = TTY_PARITY;
+ else if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE))
+ flg = TTY_FRAME;
+
+#ifdef SUPPORT_SYSRQ
+ sport->port.sysrq = 0;
+#endif
+ }
+
+ if (uart_handle_sysrq_char(&sport->port, ch))
+ goto ignore_char;
+
+ uart_insert_char(&sport->port, status,
+ ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN), ch, flg);
+
+ ignore_char:
+ serial_out(sport, PNX8XXX_LCR, serial_in(sport, PNX8XXX_LCR) |
+ PNX8XXX_UART_LCR_RX_NEXT);
+ status = FIFO_TO_SM(serial_in(sport, PNX8XXX_FIFO)) |
+ ISTAT_TO_SM(serial_in(sport, PNX8XXX_ISTAT));
+ }
+ tty_flip_buffer_push(tty);
+}
+
+static void pnx8xxx_tx_chars(struct pnx8xxx_port *sport)
+{
+ struct circ_buf *xmit = &sport->port.info->xmit;
+
+ if (sport->port.x_char) {
+ serial_out(sport, PNX8XXX_FIFO, sport->port.x_char);
+ sport->port.icount.tx++;
+ sport->port.x_char = 0;
+ return;
+ }
+
+ /*
+ * Check the modem control lines before
+ * transmitting anything.
+ */
+ pnx8xxx_mctrl_check(sport);
+
+ if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) {
+ pnx8xxx_stop_tx(&sport->port);
+ return;
+ }
+
+ /*
+ * TX while bytes available
+ */
+ while (((serial_in(sport, PNX8XXX_FIFO) &
+ PNX8XXX_UART_FIFO_TXFIFO) >> 16) < 16) {
+ serial_out(sport, PNX8XXX_FIFO, xmit->buf[xmit->tail]);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ sport->port.icount.tx++;
+ if (uart_circ_empty(xmit))
+ break;
+ }
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(&sport->port);
+
+ if (uart_circ_empty(xmit))
+ pnx8xxx_stop_tx(&sport->port);
+}
+
+static irqreturn_t pnx8xxx_int(int irq, void *dev_id)
+{
+ struct pnx8xxx_port *sport = dev_id;
+ unsigned int status;
+
+ spin_lock(&sport->port.lock);
+ /* Get the interrupts */
+ status = serial_in(sport, PNX8XXX_ISTAT) & serial_in(sport, PNX8XXX_IEN);
+
+ /* Break signal received */
+ if (status & PNX8XXX_UART_INT_BREAK) {
+ sport->port.icount.brk++;
+ uart_handle_break(&sport->port);
+ }
+
+ /* Byte received */
+ if (status & PNX8XXX_UART_INT_RX)
+ pnx8xxx_rx_chars(sport);
+
+ /* TX holding register empty - transmit a byte */
+ if (status & PNX8XXX_UART_INT_TX)
+ pnx8xxx_tx_chars(sport);
+
+ /* Clear the ISTAT register */
+ serial_out(sport, PNX8XXX_ICLR, status);
+
+ spin_unlock(&sport->port.lock);
+ return IRQ_HANDLED;
+}
+
+/*
+ * Return TIOCSER_TEMT when transmitter is not busy.
+ */
+static unsigned int pnx8xxx_tx_empty(struct uart_port *port)
+{
+ struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
+
+ return serial_in(sport, PNX8XXX_FIFO) & PNX8XXX_UART_FIFO_TXFIFO_STA ? 0 : TIOCSER_TEMT;
+}
+
+static unsigned int pnx8xxx_get_mctrl(struct uart_port *port)
+{
+ struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
+ unsigned int mctrl = TIOCM_DSR;
+ unsigned int msr;
+
+ /* REVISIT */
+
+ msr = serial_in(sport, PNX8XXX_MCR);
+
+ mctrl |= msr & PNX8XXX_UART_MCR_CTS ? TIOCM_CTS : 0;
+ mctrl |= msr & PNX8XXX_UART_MCR_DCD ? TIOCM_CAR : 0;
+
+ return mctrl;
+}
+
+static void pnx8xxx_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+#if 0 /* FIXME */
+ struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
+ unsigned int msr;
+#endif
+}
+
+/*
+ * Interrupts always disabled.
+ */
+static void pnx8xxx_break_ctl(struct uart_port *port, int break_state)
+{
+ struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
+ unsigned long flags;
+ unsigned int lcr;
+
+ spin_lock_irqsave(&sport->port.lock, flags);
+ lcr = serial_in(sport, PNX8XXX_LCR);
+ if (break_state == -1)
+ lcr |= PNX8XXX_UART_LCR_TXBREAK;
+ else
+ lcr &= ~PNX8XXX_UART_LCR_TXBREAK;
+ serial_out(sport, PNX8XXX_LCR, lcr);
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+}
+
+static int pnx8xxx_startup(struct uart_port *port)
+{
+ struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
+ int retval;
+
+ /*
+ * Allocate the IRQ
+ */
+ retval = request_irq(sport->port.irq, pnx8xxx_int, 0,
+ "pnx8xxx-uart", sport);
+ if (retval)
+ return retval;
+
+ /*
+ * Finally, clear and enable interrupts
+ */
+
+ serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLRX |
+ PNX8XXX_UART_INT_ALLTX);
+
+ serial_out(sport, PNX8XXX_IEN, serial_in(sport, PNX8XXX_IEN) |
+ PNX8XXX_UART_INT_ALLRX |
+ PNX8XXX_UART_INT_ALLTX);
+
+ /*
+ * Enable modem status interrupts
+ */
+ spin_lock_irq(&sport->port.lock);
+ pnx8xxx_enable_ms(&sport->port);
+ spin_unlock_irq(&sport->port.lock);
+
+ return 0;
+}
+
+static void pnx8xxx_shutdown(struct uart_port *port)
+{
+ struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
+ int lcr;
+
+ /*
+ * Stop our timer.
+ */
+ del_timer_sync(&sport->timer);
+
+ /*
+ * Disable all interrupts
+ */
+ serial_out(sport, PNX8XXX_IEN, 0);
+
+ /*
+ * Reset the Tx and Rx FIFOS, disable the break condition
+ */
+ lcr = serial_in(sport, PNX8XXX_LCR);
+ lcr &= ~PNX8XXX_UART_LCR_TXBREAK;
+ lcr |= PNX8XXX_UART_LCR_TX_RST | PNX8XXX_UART_LCR_RX_RST;
+ serial_out(sport, PNX8XXX_LCR, lcr);
+
+ /*
+ * Clear all interrupts
+ */
+ serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_ALLRX |
+ PNX8XXX_UART_INT_ALLTX);
+
+ /*
+ * Free the interrupt
+ */
+ free_irq(sport->port.irq, sport);
+}
+
+static void
+pnx8xxx_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
+{
+ struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
+ unsigned long flags;
+ unsigned int lcr_fcr, old_ien, baud, quot;
+ unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
+
+ /*
+ * We only support CS7 and CS8.
+ */
+ while ((termios->c_cflag & CSIZE) != CS7 &&
+ (termios->c_cflag & CSIZE) != CS8) {
+ termios->c_cflag &= ~CSIZE;
+ termios->c_cflag |= old_csize;
+ old_csize = CS8;
+ }
+
+ if ((termios->c_cflag & CSIZE) == CS8)
+ lcr_fcr = PNX8XXX_UART_LCR_8BIT;
+ else
+ lcr_fcr = 0;
+
+ if (termios->c_cflag & CSTOPB)
+ lcr_fcr |= PNX8XXX_UART_LCR_2STOPB;
+ if (termios->c_cflag & PARENB) {
+ lcr_fcr |= PNX8XXX_UART_LCR_PAREN;
+ if (!(termios->c_cflag & PARODD))
+ lcr_fcr |= PNX8XXX_UART_LCR_PAREVN;
+ }
+
+ /*
+ * Ask the core to calculate the divisor for us.
+ */
+ baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
+ quot = uart_get_divisor(port, baud);
+
+ spin_lock_irqsave(&sport->port.lock, flags);
+
+ sport->port.read_status_mask = ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN) |
+ ISTAT_TO_SM(PNX8XXX_UART_INT_EMPTY) |
+ ISTAT_TO_SM(PNX8XXX_UART_INT_RX);
+ if (termios->c_iflag & INPCK)
+ sport->port.read_status_mask |=
+ FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE) |
+ FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR);
+ if (termios->c_iflag & (BRKINT | PARMRK))
+ sport->port.read_status_mask |=
+ ISTAT_TO_SM(PNX8XXX_UART_INT_BREAK);
+
+ /*
+ * Characters to ignore
+ */
+ sport->port.ignore_status_mask = 0;
+ if (termios->c_iflag & IGNPAR)
+ sport->port.ignore_status_mask |=
+ FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE) |
+ FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR);
+ if (termios->c_iflag & IGNBRK) {
+ sport->port.ignore_status_mask |=
+ ISTAT_TO_SM(PNX8XXX_UART_INT_BREAK);
+ /*
+ * If we're ignoring parity and break indicators,
+ * ignore overruns too (for real raw support).
+ */
+ if (termios->c_iflag & IGNPAR)
+ sport->port.ignore_status_mask |=
+ ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN);
+ }
+
+ /*
+ * ignore all characters if CREAD is not set
+ */
+ if ((termios->c_cflag & CREAD) == 0)
+ sport->port.ignore_status_mask |=
+ ISTAT_TO_SM(PNX8XXX_UART_INT_RX);
+
+ del_timer_sync(&sport->timer);
+
+ /*
+ * Update the per-port timeout.
+ */
+ uart_update_timeout(port, termios->c_cflag, baud);
+
+ /*
+ * disable interrupts and drain transmitter
+ */
+ old_ien = serial_in(sport, PNX8XXX_IEN);
+ serial_out(sport, PNX8XXX_IEN, old_ien & ~(PNX8XXX_UART_INT_ALLTX |
+ PNX8XXX_UART_INT_ALLRX));
+
+ while (serial_in(sport, PNX8XXX_FIFO) & PNX8XXX_UART_FIFO_TXFIFO_STA)
+ barrier();
+
+ /* then, disable everything */
+ serial_out(sport, PNX8XXX_IEN, 0);
+
+ /* Reset the Rx and Tx FIFOs too */
+ lcr_fcr |= PNX8XXX_UART_LCR_TX_RST;
+ lcr_fcr |= PNX8XXX_UART_LCR_RX_RST;
+
+ /* set the parity, stop bits and data size */
+ serial_out(sport, PNX8XXX_LCR, lcr_fcr);
+
+ /* set the baud rate */
+ quot -= 1;
+ serial_out(sport, PNX8XXX_BAUD, quot);
+
+ serial_out(sport, PNX8XXX_ICLR, -1);
+
+ serial_out(sport, PNX8XXX_IEN, old_ien);
+
+ if (UART_ENABLE_MS(&sport->port, termios->c_cflag))
+ pnx8xxx_enable_ms(&sport->port);
+
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+}
+
+static const char *pnx8xxx_type(struct uart_port *port)
+{
+ struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
+
+ return sport->port.type == PORT_PNX8XXX ? "PNX8XXX" : NULL;
+}
+
+/*
+ * Release the memory region(s) being used by 'port'.
+ */
+static void pnx8xxx_release_port(struct uart_port *port)
+{
+ struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
+
+ release_mem_region(sport->port.mapbase, UART_PORT_SIZE);
+}
+
+/*
+ * Request the memory region(s) being used by 'port'.
+ */
+static int pnx8xxx_request_port(struct uart_port *port)
+{
+ struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
+ return request_mem_region(sport->port.mapbase, UART_PORT_SIZE,
+ "pnx8xxx-uart") != NULL ? 0 : -EBUSY;
+}
+
+/*
+ * Configure/autoconfigure the port.
+ */
+static void pnx8xxx_config_port(struct uart_port *port, int flags)
+{
+ struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
+
+ if (flags & UART_CONFIG_TYPE &&
+ pnx8xxx_request_port(&sport->port) == 0)
+ sport->port.type = PORT_PNX8XXX;
+}
+
+/*
+ * Verify the new serial_struct (for TIOCSSERIAL).
+ * The only change we allow are to the flags and type, and
+ * even then only between PORT_PNX8XXX and PORT_UNKNOWN
+ */
+static int
+pnx8xxx_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+ struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
+ int ret = 0;
+
+ if (ser->type != PORT_UNKNOWN && ser->type != PORT_PNX8XXX)
+ ret = -EINVAL;
+ if (sport->port.irq != ser->irq)
+ ret = -EINVAL;
+ if (ser->io_type != SERIAL_IO_MEM)
+ ret = -EINVAL;
+ if (sport->port.uartclk / 16 != ser->baud_base)
+ ret = -EINVAL;
+ if ((void *)sport->port.mapbase != ser->iomem_base)
+ ret = -EINVAL;
+ if (sport->port.iobase != ser->port)
+ ret = -EINVAL;
+ if (ser->hub6 != 0)
+ ret = -EINVAL;
+ return ret;
+}
+
+static struct uart_ops pnx8xxx_pops = {
+ .tx_empty = pnx8xxx_tx_empty,
+ .set_mctrl = pnx8xxx_set_mctrl,
+ .get_mctrl = pnx8xxx_get_mctrl,
+ .stop_tx = pnx8xxx_stop_tx,
+ .start_tx = pnx8xxx_start_tx,
+ .stop_rx = pnx8xxx_stop_rx,
+ .enable_ms = pnx8xxx_enable_ms,
+ .break_ctl = pnx8xxx_break_ctl,
+ .startup = pnx8xxx_startup,
+ .shutdown = pnx8xxx_shutdown,
+ .set_termios = pnx8xxx_set_termios,
+ .type = pnx8xxx_type,
+ .release_port = pnx8xxx_release_port,
+ .request_port = pnx8xxx_request_port,
+ .config_port = pnx8xxx_config_port,
+ .verify_port = pnx8xxx_verify_port,
+};
+
+
+/*
+ * Setup the PNX8XXX serial ports.
+ *
+ * Note also that we support "console=ttySx" where "x" is either 0 or 1.
+ */
+static void __init pnx8xxx_init_ports(void)
+{
+ static int first = 1;
+ int i;
+
+ if (!first)
+ return;
+ first = 0;
+
+ for (i = 0; i < NR_PORTS; i++) {
+ init_timer(&pnx8xxx_ports[i].timer);
+ pnx8xxx_ports[i].timer.function = pnx8xxx_timeout;
+ pnx8xxx_ports[i].timer.data = (unsigned long)&pnx8xxx_ports[i];
+ pnx8xxx_ports[i].port.ops = &pnx8xxx_pops;
+ }
+}
+
+#ifdef CONFIG_SERIAL_PNX8XXX_CONSOLE
+
+static void pnx8xxx_console_putchar(struct uart_port *port, int ch)
+{
+ struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
+ int status;
+
+ do {
+ /* Wait for UART_TX register to empty */
+ status = serial_in(sport, PNX8XXX_FIFO);
+ } while (status & PNX8XXX_UART_FIFO_TXFIFO);
+ serial_out(sport, PNX8XXX_FIFO, ch);
+}
+
+/*
+ * Interrupts are disabled on entering
+ */static void
+pnx8xxx_console_write(struct console *co, const char *s, unsigned int count)
+{
+ struct pnx8xxx_port *sport = &pnx8xxx_ports[co->index];
+ unsigned int old_ien, status;
+
+ /*
+ * First, save IEN and then disable interrupts
+ */
+ old_ien = serial_in(sport, PNX8XXX_IEN);
+ serial_out(sport, PNX8XXX_IEN, old_ien & ~(PNX8XXX_UART_INT_ALLTX |
+ PNX8XXX_UART_INT_ALLRX));
+
+ uart_console_write(&sport->port, s, count, pnx8xxx_console_putchar);
+
+ /*
+ * Finally, wait for transmitter to become empty
+ * and restore IEN
+ */
+ do {
+ /* Wait for UART_TX register to empty */
+ status = serial_in(sport, PNX8XXX_FIFO);
+ } while (status & PNX8XXX_UART_FIFO_TXFIFO);
+
+ /* Clear TX and EMPTY interrupt */
+ serial_out(sport, PNX8XXX_ICLR, PNX8XXX_UART_INT_TX |
+ PNX8XXX_UART_INT_EMPTY);
+
+ serial_out(sport, PNX8XXX_IEN, old_ien);
+}
+
+static int __init
+pnx8xxx_console_setup(struct console *co, char *options)
+{
+ struct pnx8xxx_port *sport;
+ int baud = 38400;
+ int bits = 8;
+ int parity = 'n';
+ int flow = 'n';
+
+ /*
+ * Check whether an invalid uart number has been specified, and
+ * if so, search for the first available port that does have
+ * console support.
+ */
+ if (co->index == -1 || co->index >= NR_PORTS)
+ co->index = 0;
+ sport = &pnx8xxx_ports[co->index];
+
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+ return uart_set_options(&sport->port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver pnx8xxx_reg;
+static struct console pnx8xxx_console = {
+ .name = "ttyS",
+ .write = pnx8xxx_console_write,
+ .device = uart_console_device,
+ .setup = pnx8xxx_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+ .data = &pnx8xxx_reg,
+};
+
+static int __init pnx8xxx_rs_console_init(void)
+{
+ pnx8xxx_init_ports();
+ register_console(&pnx8xxx_console);
+ return 0;
+}
+console_initcall(pnx8xxx_rs_console_init);
+
+#define PNX8XXX_CONSOLE &pnx8xxx_console
+#else
+#define PNX8XXX_CONSOLE NULL
+#endif
+
+static struct uart_driver pnx8xxx_reg = {
+ .owner = THIS_MODULE,
+ .driver_name = "ttyS",
+ .dev_name = "ttyS",
+ .major = SERIAL_PNX8XXX_MAJOR,
+ .minor = MINOR_START,
+ .nr = NR_PORTS,
+ .cons = PNX8XXX_CONSOLE,
+};
+
+static int pnx8xxx_serial_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct pnx8xxx_port *sport = platform_get_drvdata(pdev);
+
+ return uart_suspend_port(&pnx8xxx_reg, &sport->port);
+}
+
+static int pnx8xxx_serial_resume(struct platform_device *pdev)
+{
+ struct pnx8xxx_port *sport = platform_get_drvdata(pdev);
+
+ return uart_resume_port(&pnx8xxx_reg, &sport->port);
+}
+
+static int pnx8xxx_serial_probe(struct platform_device *pdev)
+{
+ struct resource *res = pdev->resource;
+ int i;
+
+ for (i = 0; i < pdev->num_resources; i++, res++) {
+ if (!(res->flags & IORESOURCE_MEM))
+ continue;
+
+ for (i = 0; i < NR_PORTS; i++) {
+ if (pnx8xxx_ports[i].port.mapbase != res->start)
+ continue;
+
+ pnx8xxx_ports[i].port.dev = &pdev->dev;
+ uart_add_one_port(&pnx8xxx_reg, &pnx8xxx_ports[i].port);
+ platform_set_drvdata(pdev, &pnx8xxx_ports[i]);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int pnx8xxx_serial_remove(struct platform_device *pdev)
+{
+ struct pnx8xxx_port *sport = platform_get_drvdata(pdev);
+
+ platform_set_drvdata(pdev, NULL);
+
+ if (sport)
+ uart_remove_one_port(&pnx8xxx_reg, &sport->port);
+
+ return 0;
+}
+
+static struct platform_driver pnx8xxx_serial_driver = {
+ .driver = {
+ .name = "pnx8xxx-uart",
+ .owner = THIS_MODULE,
+ },
+ .probe = pnx8xxx_serial_probe,
+ .remove = pnx8xxx_serial_remove,
+ .suspend = pnx8xxx_serial_suspend,
+ .resume = pnx8xxx_serial_resume,
+};
+
+static int __init pnx8xxx_serial_init(void)
+{
+ int ret;
+
+ printk(KERN_INFO "Serial: PNX8XXX driver $Revision: 1.2 $\n");
+
+ pnx8xxx_init_ports();
+
+ ret = uart_register_driver(&pnx8xxx_reg);
+ if (ret == 0) {
+ ret = platform_driver_register(&pnx8xxx_serial_driver);
+ if (ret)
+ uart_unregister_driver(&pnx8xxx_reg);
+ }
+ return ret;
+}
+
+static void __exit pnx8xxx_serial_exit(void)
+{
+ platform_driver_unregister(&pnx8xxx_serial_driver);
+ uart_unregister_driver(&pnx8xxx_reg);
+}
+
+module_init(pnx8xxx_serial_init);
+module_exit(pnx8xxx_serial_exit);
+
+MODULE_AUTHOR("Embedded Alley Solutions, Inc.");
+MODULE_DESCRIPTION("PNX8XXX SoCs serial port driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_CHARDEV_MAJOR(SERIAL_PNX8XXX_MAJOR);
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
index f84982e508c..0422c0f1f85 100644
--- a/drivers/serial/serial_core.c
+++ b/drivers/serial/serial_core.c
@@ -1523,9 +1523,8 @@ static struct uart_state *uart_get(struct uart_driver *drv, int line)
}
if (!state->info) {
- state->info = kmalloc(sizeof(struct uart_info), GFP_KERNEL);
+ state->info = kzalloc(sizeof(struct uart_info), GFP_KERNEL);
if (state->info) {
- memset(state->info, 0, sizeof(struct uart_info));
init_waitqueue_head(&state->info->open_wait);
init_waitqueue_head(&state->info->delta_msr_wait);
@@ -1660,6 +1659,7 @@ static const char *uart_type(struct uart_port *port)
static int uart_line_info(char *buf, struct uart_driver *drv, int i)
{
struct uart_state *state = drv->state + i;
+ int pm_state;
struct uart_port *port = state->port;
char stat_buf[32];
unsigned int status;
@@ -1682,9 +1682,16 @@ static int uart_line_info(char *buf, struct uart_driver *drv, int i)
if(capable(CAP_SYS_ADMIN))
{
+ mutex_lock(&state->mutex);
+ pm_state = state->pm_state;
+ if (pm_state)
+ uart_change_pm(state, 0);
spin_lock_irq(&port->lock);
status = port->ops->get_mctrl(port);
spin_unlock_irq(&port->lock);
+ if (pm_state)
+ uart_change_pm(state, pm_state);
+ mutex_unlock(&state->mutex);
ret += sprintf(buf + ret, " tx:%d rx:%d",
port->icount.tx, port->icount.rx);
@@ -2100,6 +2107,9 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state,
uart_report_port(drv, port);
+ /* Power up port for set_mctrl() */
+ uart_change_pm(state, 0);
+
/*
* Ensure that the modem control lines are de-activated.
* We probably don't need a spinlock around this, but
@@ -2167,13 +2177,11 @@ int uart_register_driver(struct uart_driver *drv)
* Maybe we should be using a slab cache for this, especially if
* we have a large number of ports to handle.
*/
- drv->state = kmalloc(sizeof(struct uart_state) * drv->nr, GFP_KERNEL);
+ drv->state = kzalloc(sizeof(struct uart_state) * drv->nr, GFP_KERNEL);
retval = -ENOMEM;
if (!drv->state)
goto out;
- memset(drv->state, 0, sizeof(struct uart_state) * drv->nr);
-
normal = alloc_tty_driver(drv->nr);
if (!normal)
goto out;
diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c
index 431433f4dd6..6b76babc7fb 100644
--- a/drivers/serial/serial_cs.c
+++ b/drivers/serial/serial_cs.c
@@ -35,7 +35,6 @@
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/sched.h>
#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/string.h>
@@ -249,6 +248,10 @@ static const struct serial_quirk quirks[] = {
.multi = 2,
}, {
.manfid = MANFID_QUATECH,
+ .prodid = PRODID_QUATECH_DUAL_RS232_G,
+ .multi = 2,
+ }, {
+ .manfid = MANFID_QUATECH,
.prodid = PRODID_QUATECH_QUAD_RS232,
.multi = 4,
}, {
@@ -334,10 +337,9 @@ static int serial_probe(struct pcmcia_device *link)
DEBUG(0, "serial_attach()\n");
/* Create new serial device */
- info = kmalloc(sizeof (*info), GFP_KERNEL);
+ info = kzalloc(sizeof (*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
- memset(info, 0, sizeof (*info));
info->p_dev = link;
link->priv = info;
@@ -893,6 +895,7 @@ static struct pcmcia_device_id serial_ids[] = {
PCMCIA_DEVICE_PROD_ID12("OEM ", "C288MX ", 0xb572d360, 0xd2385b7a),
PCMCIA_DEVICE_PROD_ID12("PCMCIA ", "C336MX ", 0x99bcafe9, 0xaa25bcab),
PCMCIA_DEVICE_PROD_ID12("Quatech Inc", "PCMCIA Dual RS-232 Serial Port Card", 0xc4420b35, 0x92abc92f),
+ PCMCIA_DEVICE_PROD_ID12("Quatech Inc", "Dual RS-232 Serial Port PC Card", 0xc4420b35, 0x031a380d),
PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "PCMCIA", "EN2218-LAN/MODEM", 0x281f1c5d, 0x570f348e, "PCMLM28.cis"),
PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "PCMCIA", "UE2218-LAN/MODEM", 0x281f1c5d, 0x6fdcacee, "PCMLM28.cis"),
PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "Psion Dacom", "Gold Card V34 Ethernet", 0xf5f025c2, 0x338e8155, "PCMLM28.cis"),
diff --git a/drivers/serial/serial_txx9.c b/drivers/serial/serial_txx9.c
index 7186a82c475..509ace7e688 100644
--- a/drivers/serial/serial_txx9.c
+++ b/drivers/serial/serial_txx9.c
@@ -37,6 +37,9 @@
* 1.06 Do not insert a char caused previous overrun.
* Fix some spin_locks.
* Do not call uart_add_one_port for absent ports.
+ * 1.07 Use CONFIG_SERIAL_TXX9_NR_UARTS. Cleanup.
+ * 1.08 Use platform_device.
+ * Fix and cleanup suspend/resume/initialization codes.
*/
#if defined(CONFIG_SERIAL_TXX9_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
@@ -49,7 +52,7 @@
#include <linux/console.h>
#include <linux/sysrq.h>
#include <linux/delay.h>
-#include <linux/device.h>
+#include <linux/platform_device.h>
#include <linux/pci.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
@@ -58,9 +61,8 @@
#include <linux/mutex.h>
#include <asm/io.h>
-#include <asm/irq.h>
-static char *serial_version = "1.06";
+static char *serial_version = "1.08";
static char *serial_name = "TX39/49 Serial driver";
#define PASS_LIMIT 256
@@ -88,23 +90,13 @@ static char *serial_name = "TX39/49 Serial driver";
/*
* Number of serial ports
*/
-#ifdef ENABLE_SERIAL_TXX9_PCI
-#define NR_PCI_BOARDS 4
-#define UART_NR (4 + NR_PCI_BOARDS)
-#else
-#define UART_NR 4
-#endif
+#define UART_NR CONFIG_SERIAL_TXX9_NR_UARTS
#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
struct uart_txx9_port {
struct uart_port port;
-
- /*
- * We provide a per-port pm hook.
- */
- void (*pm)(struct uart_port *port,
- unsigned int state, unsigned int old);
+ /* No additional info for now */
};
#define TXX9_REGION_SIZE 0x24
@@ -282,6 +274,31 @@ static void serial_txx9_enable_ms(struct uart_port *port)
/* TXX9-SIO can not control DTR... */
}
+static void serial_txx9_initialize(struct uart_port *port)
+{
+ struct uart_txx9_port *up = (struct uart_txx9_port *)port;
+ unsigned int tmout = 10000;
+
+ sio_out(up, TXX9_SIFCR, TXX9_SIFCR_SWRST);
+ /* TX4925 BUG WORKAROUND. Accessing SIOC register
+ * immediately after soft reset causes bus error. */
+ mmiowb();
+ udelay(1);
+ while ((sio_in(up, TXX9_SIFCR) & TXX9_SIFCR_SWRST) && --tmout)
+ udelay(1);
+ /* TX Int by FIFO Empty, RX Int by Receiving 1 char. */
+ sio_set(up, TXX9_SIFCR,
+ TXX9_SIFCR_TDIL_MAX | TXX9_SIFCR_RDIL_1);
+ /* initial settings */
+ sio_out(up, TXX9_SILCR,
+ TXX9_SILCR_UMODE_8BIT | TXX9_SILCR_USBL_1BIT |
+ ((up->port.flags & UPF_TXX9_USE_SCLK) ?
+ TXX9_SILCR_SCS_SCLK_BG : TXX9_SILCR_SCS_IMCLK_BG));
+ sio_quot_set(up, uart_get_divisor(port, 9600));
+ sio_out(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSTL_MAX /* 15 */);
+ sio_out(up, TXX9_SIDICR, 0);
+}
+
static inline void
receive_chars(struct uart_txx9_port *up, unsigned int *status)
{
@@ -662,9 +679,8 @@ static void
serial_txx9_pm(struct uart_port *port, unsigned int state,
unsigned int oldstate)
{
- struct uart_txx9_port *up = (struct uart_txx9_port *)port;
- if (up->pm)
- up->pm(port, state, oldstate);
+ if (state == 0)
+ serial_txx9_initialize(port);
}
static int serial_txx9_request_resource(struct uart_txx9_port *up)
@@ -737,7 +753,6 @@ static int serial_txx9_request_port(struct uart_port *port)
static void serial_txx9_config_port(struct uart_port *port, int uflags)
{
struct uart_txx9_port *up = (struct uart_txx9_port *)port;
- unsigned long flags;
int ret;
/*
@@ -754,30 +769,7 @@ static void serial_txx9_config_port(struct uart_port *port, int uflags)
if (up->port.line == up->port.cons->index)
return;
#endif
- spin_lock_irqsave(&up->port.lock, flags);
- /*
- * Reset the UART.
- */
- sio_out(up, TXX9_SIFCR, TXX9_SIFCR_SWRST);
-#ifdef CONFIG_CPU_TX49XX
- /* TX4925 BUG WORKAROUND. Accessing SIOC register
- * immediately after soft reset causes bus error. */
- iob();
- udelay(1);
-#endif
- while (sio_in(up, TXX9_SIFCR) & TXX9_SIFCR_SWRST)
- ;
- /* TX Int by FIFO Empty, RX Int by Receiving 1 char. */
- sio_set(up, TXX9_SIFCR,
- TXX9_SIFCR_TDIL_MAX | TXX9_SIFCR_RDIL_1);
- /* initial settings */
- sio_out(up, TXX9_SILCR,
- TXX9_SILCR_UMODE_8BIT | TXX9_SILCR_USBL_1BIT |
- ((up->port.flags & UPF_TXX9_USE_SCLK) ?
- TXX9_SILCR_SCS_SCLK_BG : TXX9_SILCR_SCS_IMCLK_BG));
- sio_quot_set(up, uart_get_divisor(port, 9600));
- sio_out(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSTL_MAX /* 15 */);
- spin_unlock_irqrestore(&up->port.lock, flags);
+ serial_txx9_initialize(port);
}
static int
@@ -823,7 +815,8 @@ static struct uart_ops serial_txx9_pops = {
static struct uart_txx9_port serial_txx9_ports[UART_NR];
-static void __init serial_txx9_register_ports(struct uart_driver *drv)
+static void __init serial_txx9_register_ports(struct uart_driver *drv,
+ struct device *dev)
{
int i;
@@ -832,6 +825,7 @@ static void __init serial_txx9_register_ports(struct uart_driver *drv)
up->port.line = i;
up->port.ops = &serial_txx9_pops;
+ up->port.dev = dev;
if (up->port.iobase || up->port.mapbase)
uart_add_one_port(drv, &up->port);
}
@@ -903,7 +897,7 @@ serial_txx9_console_write(struct console *co, const char *s, unsigned int count)
sio_out(up, TXX9_SIDICR, ier);
}
-static int serial_txx9_console_setup(struct console *co, char *options)
+static int __init serial_txx9_console_setup(struct console *co, char *options)
{
struct uart_port *port;
struct uart_txx9_port *up;
@@ -924,17 +918,7 @@ static int serial_txx9_console_setup(struct console *co, char *options)
if (!port->ops)
return -ENODEV;
- /*
- * Disable UART interrupts, set DTR and RTS high
- * and set speed.
- */
- sio_out(up, TXX9_SIDICR, 0);
- /* initial settings */
- sio_out(up, TXX9_SILCR,
- TXX9_SILCR_UMODE_8BIT | TXX9_SILCR_USBL_1BIT |
- ((port->flags & UPF_TXX9_USE_SCLK) ?
- TXX9_SILCR_SCS_SCLK_BG : TXX9_SILCR_SCS_IMCLK_BG));
- sio_out(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSTL_MAX /* 15 */);
+ serial_txx9_initialize(&up->port);
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
@@ -986,29 +970,6 @@ int __init early_serial_txx9_setup(struct uart_port *port)
return 0;
}
-#ifdef ENABLE_SERIAL_TXX9_PCI
-/**
- * serial_txx9_suspend_port - suspend one serial port
- * @line: serial line number
- *
- * Suspend one serial port.
- */
-static void serial_txx9_suspend_port(int line)
-{
- uart_suspend_port(&serial_txx9_reg, &serial_txx9_ports[line].port);
-}
-
-/**
- * serial_txx9_resume_port - resume one serial port
- * @line: serial line number
- *
- * Resume one serial port.
- */
-static void serial_txx9_resume_port(int line)
-{
- uart_resume_port(&serial_txx9_reg, &serial_txx9_ports[line].port);
-}
-
static DEFINE_MUTEX(serial_txx9_mutex);
/**
@@ -1031,8 +992,18 @@ static int __devinit serial_txx9_register_port(struct uart_port *port)
mutex_lock(&serial_txx9_mutex);
for (i = 0; i < UART_NR; i++) {
uart = &serial_txx9_ports[i];
- if (!(uart->port.iobase || uart->port.mapbase))
+ if (uart_match_port(&uart->port, port)) {
+ uart_remove_one_port(&serial_txx9_reg, &uart->port);
break;
+ }
+ }
+ if (i == UART_NR) {
+ /* Find unused port */
+ for (i = 0; i < UART_NR; i++) {
+ uart = &serial_txx9_ports[i];
+ if (!(uart->port.iobase || uart->port.mapbase))
+ break;
+ }
}
if (i < UART_NR) {
uart->port.iobase = port->iobase;
@@ -1075,6 +1046,95 @@ static void __devexit serial_txx9_unregister_port(int line)
}
/*
+ * Register a set of serial devices attached to a platform device.
+ */
+static int __devinit serial_txx9_probe(struct platform_device *dev)
+{
+ struct uart_port *p = dev->dev.platform_data;
+ struct uart_port port;
+ int ret, i;
+
+ memset(&port, 0, sizeof(struct uart_port));
+ for (i = 0; p && p->uartclk != 0; p++, i++) {
+ port.iobase = p->iobase;
+ port.membase = p->membase;
+ port.irq = p->irq;
+ port.uartclk = p->uartclk;
+ port.iotype = p->iotype;
+ port.flags = p->flags;
+ port.mapbase = p->mapbase;
+ port.dev = &dev->dev;
+ ret = serial_txx9_register_port(&port);
+ if (ret < 0) {
+ dev_err(&dev->dev, "unable to register port at index %d "
+ "(IO%x MEM%lx IRQ%d): %d\n", i,
+ p->iobase, p->mapbase, p->irq, ret);
+ }
+ }
+ return 0;
+}
+
+/*
+ * Remove serial ports registered against a platform device.
+ */
+static int __devexit serial_txx9_remove(struct platform_device *dev)
+{
+ int i;
+
+ for (i = 0; i < UART_NR; i++) {
+ struct uart_txx9_port *up = &serial_txx9_ports[i];
+
+ if (up->port.dev == &dev->dev)
+ serial_txx9_unregister_port(i);
+ }
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int serial_txx9_suspend(struct platform_device *dev, pm_message_t state)
+{
+ int i;
+
+ for (i = 0; i < UART_NR; i++) {
+ struct uart_txx9_port *up = &serial_txx9_ports[i];
+
+ if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev)
+ uart_suspend_port(&serial_txx9_reg, &up->port);
+ }
+
+ return 0;
+}
+
+static int serial_txx9_resume(struct platform_device *dev)
+{
+ int i;
+
+ for (i = 0; i < UART_NR; i++) {
+ struct uart_txx9_port *up = &serial_txx9_ports[i];
+
+ if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev)
+ uart_resume_port(&serial_txx9_reg, &up->port);
+ }
+
+ return 0;
+}
+#endif
+
+static struct platform_driver serial_txx9_plat_driver = {
+ .probe = serial_txx9_probe,
+ .remove = __devexit_p(serial_txx9_remove),
+#ifdef CONFIG_PM
+ .suspend = serial_txx9_suspend,
+ .resume = serial_txx9_resume,
+#endif
+ .driver = {
+ .name = "serial_txx9",
+ .owner = THIS_MODULE,
+ },
+};
+
+#ifdef ENABLE_SERIAL_TXX9_PCI
+/*
* Probe one serial board. Unfortunately, there is no rhyme nor reason
* to the arrangement of serial ports on a PCI card.
*/
@@ -1100,30 +1160,33 @@ pciserial_txx9_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
line = serial_txx9_register_port(&port);
if (line < 0) {
printk(KERN_WARNING "Couldn't register serial port %s: %d\n", pci_name(dev), line);
+ pci_disable_device(dev);
+ return line;
}
- pci_set_drvdata(dev, (void *)(long)line);
+ pci_set_drvdata(dev, &serial_txx9_ports[line]);
return 0;
}
static void __devexit pciserial_txx9_remove_one(struct pci_dev *dev)
{
- int line = (int)(long)pci_get_drvdata(dev);
+ struct uart_txx9_port *up = pci_get_drvdata(dev);
pci_set_drvdata(dev, NULL);
- if (line) {
- serial_txx9_unregister_port(line);
+ if (up) {
+ serial_txx9_unregister_port(up->port.line);
pci_disable_device(dev);
}
}
+#ifdef CONFIG_PM
static int pciserial_txx9_suspend_one(struct pci_dev *dev, pm_message_t state)
{
- int line = (int)(long)pci_get_drvdata(dev);
+ struct uart_txx9_port *up = pci_get_drvdata(dev);
- if (line)
- serial_txx9_suspend_port(line);
+ if (up)
+ uart_suspend_port(&serial_txx9_reg, &up->port);
pci_save_state(dev);
pci_set_power_state(dev, pci_choose_state(dev, state));
return 0;
@@ -1131,22 +1194,18 @@ static int pciserial_txx9_suspend_one(struct pci_dev *dev, pm_message_t state)
static int pciserial_txx9_resume_one(struct pci_dev *dev)
{
- int line = (int)(long)pci_get_drvdata(dev);
+ struct uart_txx9_port *up = pci_get_drvdata(dev);
pci_set_power_state(dev, PCI_D0);
pci_restore_state(dev);
-
- if (line) {
- pci_enable_device(dev);
- serial_txx9_resume_port(line);
- }
+ if (up)
+ uart_resume_port(&serial_txx9_reg, &up->port);
return 0;
}
+#endif
-static struct pci_device_id serial_txx9_pci_tbl[] = {
- { PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC86C001_MISC,
- PCI_ANY_ID, PCI_ANY_ID,
- 0, 0, 0 },
+static const struct pci_device_id serial_txx9_pci_tbl[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC86C001_MISC) },
{ 0, }
};
@@ -1154,14 +1213,18 @@ static struct pci_driver serial_txx9_pci_driver = {
.name = "serial_txx9",
.probe = pciserial_txx9_init_one,
.remove = __devexit_p(pciserial_txx9_remove_one),
+#ifdef CONFIG_PM
.suspend = pciserial_txx9_suspend_one,
.resume = pciserial_txx9_resume_one,
+#endif
.id_table = serial_txx9_pci_tbl,
};
MODULE_DEVICE_TABLE(pci, serial_txx9_pci_tbl);
#endif /* ENABLE_SERIAL_TXX9_PCI */
+static struct platform_device *serial_txx9_plat_devs;
+
static int __init serial_txx9_init(void)
{
int ret;
@@ -1169,13 +1232,39 @@ static int __init serial_txx9_init(void)
printk(KERN_INFO "%s version %s\n", serial_name, serial_version);
ret = uart_register_driver(&serial_txx9_reg);
- if (ret >= 0) {
- serial_txx9_register_ports(&serial_txx9_reg);
+ if (ret)
+ goto out;
+
+ serial_txx9_plat_devs = platform_device_alloc("serial_txx9", -1);
+ if (!serial_txx9_plat_devs) {
+ ret = -ENOMEM;
+ goto unreg_uart_drv;
+ }
+
+ ret = platform_device_add(serial_txx9_plat_devs);
+ if (ret)
+ goto put_dev;
+
+ serial_txx9_register_ports(&serial_txx9_reg,
+ &serial_txx9_plat_devs->dev);
+
+ ret = platform_driver_register(&serial_txx9_plat_driver);
+ if (ret)
+ goto del_dev;
#ifdef ENABLE_SERIAL_TXX9_PCI
- ret = pci_register_driver(&serial_txx9_pci_driver);
+ ret = pci_register_driver(&serial_txx9_pci_driver);
#endif
- }
+ if (ret == 0)
+ goto out;
+
+ del_dev:
+ platform_device_del(serial_txx9_plat_devs);
+ put_dev:
+ platform_device_put(serial_txx9_plat_devs);
+ unreg_uart_drv:
+ uart_unregister_driver(&serial_txx9_reg);
+ out:
return ret;
}
@@ -1186,6 +1275,8 @@ static void __exit serial_txx9_exit(void)
#ifdef ENABLE_SERIAL_TXX9_PCI
pci_unregister_driver(&serial_txx9_pci_driver);
#endif
+ platform_driver_unregister(&serial_txx9_plat_driver);
+ platform_device_unregister(serial_txx9_plat_devs);
for (i = 0; i < UART_NR; i++) {
struct uart_txx9_port *up = &serial_txx9_ports[i];
if (up->port.iobase || up->port.mapbase)
diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c
index 145d6236954..deb9ab4b5a0 100644
--- a/drivers/serial/sunsab.c
+++ b/drivers/serial/sunsab.c
@@ -17,7 +17,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c
index 3ec3df21816..96a852aa190 100644
--- a/drivers/serial/sunsu.c
+++ b/drivers/serial/sunsu.c
@@ -17,7 +17,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/errno.h>
#include <linux/tty.h>
diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c
index 244f796dc62..da73205e54c 100644
--- a/drivers/serial/sunzilog.c
+++ b/drivers/serial/sunzilog.c
@@ -14,7 +14,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/delay.h>
#include <linux/tty.h>
diff --git a/drivers/serial/uartlite.c b/drivers/serial/uartlite.c
index db8607e3d53..f5051cf1a0c 100644
--- a/drivers/serial/uartlite.c
+++ b/drivers/serial/uartlite.c
@@ -256,7 +256,7 @@ static void ulite_release_port(struct uart_port *port)
{
release_mem_region(port->mapbase, ULITE_REGION);
iounmap(port->membase);
- port->membase = 0;
+ port->membase = NULL;
}
static int ulite_request_port(struct uart_port *port)
@@ -438,7 +438,7 @@ static int __devinit ulite_probe(struct platform_device *pdev)
port->iotype = UPIO_MEM;
port->iobase = 1; /* mark port in use */
port->mapbase = res->start;
- port->membase = 0;
+ port->membase = NULL;
port->ops = &ulite_ops;
port->irq = res2->start;
port->flags = UPF_BOOT_AUTOCONF;
@@ -462,7 +462,7 @@ static int ulite_remove(struct platform_device *pdev)
uart_remove_one_port(&ulite_uart_driver, port);
/* mark port as free */
- port->membase = 0;
+ port->membase = NULL;
return 0;
}
diff --git a/drivers/sn/ioc3.c b/drivers/sn/ioc3.c
index cd6b65333b7..2dd6eed50aa 100644
--- a/drivers/sn/ioc3.c
+++ b/drivers/sn/ioc3.c
@@ -654,7 +654,7 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
ret = -ENODEV;
goto out_pci;
}
- if (!request_region(idd->pma, IOC3_PCI_SIZE, "ioc3")) {
+ if (!request_mem_region(idd->pma, IOC3_PCI_SIZE, "ioc3")) {
printk(KERN_WARNING
"%s: Unable to request IOC3 region "
"for pci_dev %s.\n",
@@ -744,7 +744,7 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
return 0;
out_misc_region:
- release_region(idd->pma, IOC3_PCI_SIZE);
+ release_mem_region(idd->pma, IOC3_PCI_SIZE);
out_pci:
kfree(idd);
out_idd:
@@ -785,7 +785,7 @@ static void ioc3_remove(struct pci_dev *pdev)
if(idd->dual_irq)
free_irq(idd->irq_eth, (void *)idd);
iounmap(idd->vma);
- release_region(idd->pma, IOC3_PCI_SIZE);
+ release_mem_region(idd->pma, IOC3_PCI_SIZE);
/* Disable IOC3 and relinquish */
pci_disable_device(pdev);
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index d895a1adb42..7e54e48efd5 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -51,6 +51,13 @@ config SPI_MASTER
comment "SPI Master Controller Drivers"
depends on SPI_MASTER
+config SPI_ATMEL
+ tristate "Atmel SPI Controller"
+ depends on (ARCH_AT91 || AVR32) && SPI_MASTER
+ help
+ This selects a driver for the Atmel SPI Controller, present on
+ many AT32 (AVR32) and AT91 (ARM) chips.
+
config SPI_BITBANG
tristate "Bitbanging SPI master"
depends on SPI_MASTER && EXPERIMENTAL
@@ -75,6 +82,13 @@ config SPI_BUTTERFLY
inexpensive battery powered microcontroller evaluation board.
This same cable can be used to flash new firmware.
+config SPI_IMX
+ tristate "Freescale iMX SPI controller"
+ depends on SPI_MASTER && ARCH_IMX && EXPERIMENTAL
+ help
+ This enables using the Freescale iMX SPI controller in master
+ mode.
+
config SPI_MPC83xx
tristate "Freescale MPC83xx SPI controller"
depends on SPI_MASTER && PPC_83xx && EXPERIMENTAL
@@ -87,6 +101,14 @@ config SPI_MPC83xx
family of PowerPC processors. The MPC83xx uses a simple set of shift
registers for data (opposed to the CPM based descriptor model).
+config SPI_OMAP_UWIRE
+ tristate "OMAP1 MicroWire"
+ depends on SPI_MASTER && ARCH_OMAP1
+ select SPI_BITBANG
+ help
+ This hooks up to the MicroWire controller on OMAP1 chips.
+
+
config SPI_PXA2XX
tristate "PXA2xx SSP SPI master"
depends on SPI_MASTER && ARCH_PXA && EXPERIMENTAL
@@ -95,6 +117,12 @@ config SPI_PXA2XX
The driver can be configured to use any SSP port and additional
documentation can be found a Documentation/spi/pxa2xx.
+config SPI_S3C24XX
+ tristate "Samsung S3C24XX series SPI"
+ depends on SPI_MASTER && ARCH_S3C2410 && EXPERIMENTAL
+ help
+ SPI driver for Samsung S3C24XX series ARM SoCs
+
config SPI_S3C24XX_GPIO
tristate "Samsung S3C24XX series SPI by GPIO"
depends on SPI_MASTER && ARCH_S3C2410 && SPI_BITBANG && EXPERIMENTAL
@@ -107,13 +135,6 @@ config SPI_S3C24XX_GPIO
# Add new SPI master controllers in alphabetical order above this line
#
-
-config SPI_S3C24XX
- tristate "Samsung S3C24XX series SPI"
- depends on SPI_MASTER && ARCH_S3C2410 && EXPERIMENTAL
- help
- SPI driver for Samsung S3C24XX series ARM SoCs
-
#
# There are lots of SPI device types, with sensors and memory
# being probably the most widely used ones.
@@ -121,6 +142,16 @@ config SPI_S3C24XX
comment "SPI Protocol Masters"
depends on SPI_MASTER
+config SPI_AT25
+ tristate "SPI EEPROMs from most vendors"
+ depends on SPI_MASTER && SYSFS
+ help
+ Enable this driver to get read/write support to most SPI EEPROMs,
+ after you configure the board init code to know about each eeprom
+ on your target board.
+
+ This driver can also be built as a module. If so, the module
+ will be called at25.
#
# Add new SPI protocol masters in alphabetical order above this line
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 8f4cb67997b..3c280ad8920 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -12,14 +12,18 @@ obj-$(CONFIG_SPI_MASTER) += spi.o
# SPI master controller drivers (bus)
obj-$(CONFIG_SPI_BITBANG) += spi_bitbang.o
+obj-$(CONFIG_SPI_ATMEL) += atmel_spi.o
obj-$(CONFIG_SPI_BUTTERFLY) += spi_butterfly.o
+obj-$(CONFIG_SPI_IMX) += spi_imx.o
obj-$(CONFIG_SPI_PXA2XX) += pxa2xx_spi.o
+obj-$(CONFIG_SPI_OMAP_UWIRE) += omap_uwire.o
obj-$(CONFIG_SPI_MPC83xx) += spi_mpc83xx.o
obj-$(CONFIG_SPI_S3C24XX_GPIO) += spi_s3c24xx_gpio.o
obj-$(CONFIG_SPI_S3C24XX) += spi_s3c24xx.o
# ... add above this line ...
# SPI protocol drivers (device/link on bus)
+obj-$(CONFIG_SPI_AT25) += at25.o
# ... add above this line ...
# SPI slave controller drivers (upstream link)
diff --git a/drivers/spi/at25.c b/drivers/spi/at25.c
new file mode 100644
index 00000000000..48e4f48e779
--- /dev/null
+++ b/drivers/spi/at25.c
@@ -0,0 +1,381 @@
+/*
+ * at25.c -- support most SPI EEPROMs, such as Atmel AT25 models
+ *
+ * Copyright (C) 2006 David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/sched.h>
+
+#include <linux/spi/spi.h>
+#include <linux/spi/eeprom.h>
+
+
+struct at25_data {
+ struct spi_device *spi;
+ struct mutex lock;
+ struct spi_eeprom chip;
+ struct bin_attribute bin;
+ unsigned addrlen;
+};
+
+#define AT25_WREN 0x06 /* latch the write enable */
+#define AT25_WRDI 0x04 /* reset the write enable */
+#define AT25_RDSR 0x05 /* read status register */
+#define AT25_WRSR 0x01 /* write status register */
+#define AT25_READ 0x03 /* read byte(s) */
+#define AT25_WRITE 0x02 /* write byte(s)/sector */
+
+#define AT25_SR_nRDY 0x01 /* nRDY = write-in-progress */
+#define AT25_SR_WEN 0x02 /* write enable (latched) */
+#define AT25_SR_BP0 0x04 /* BP for software writeprotect */
+#define AT25_SR_BP1 0x08
+#define AT25_SR_WPEN 0x80 /* writeprotect enable */
+
+
+#define EE_MAXADDRLEN 3 /* 24 bit addresses, up to 2 MBytes */
+
+/* Specs often allow 5 msec for a page write, sometimes 20 msec;
+ * it's important to recover from write timeouts.
+ */
+#define EE_TIMEOUT 25
+
+/*-------------------------------------------------------------------------*/
+
+#define io_limit PAGE_SIZE /* bytes */
+
+static ssize_t
+at25_ee_read(
+ struct at25_data *at25,
+ char *buf,
+ unsigned offset,
+ size_t count
+)
+{
+ u8 command[EE_MAXADDRLEN + 1];
+ u8 *cp;
+ ssize_t status;
+ struct spi_transfer t[2];
+ struct spi_message m;
+
+ cp = command;
+ *cp++ = AT25_READ;
+
+ /* 8/16/24-bit address is written MSB first */
+ switch (at25->addrlen) {
+ default: /* case 3 */
+ *cp++ = offset >> 16;
+ case 2:
+ *cp++ = offset >> 8;
+ case 1:
+ case 0: /* can't happen: for better codegen */
+ *cp++ = offset >> 0;
+ }
+
+ spi_message_init(&m);
+ memset(t, 0, sizeof t);
+
+ t[0].tx_buf = command;
+ t[0].len = at25->addrlen + 1;
+ spi_message_add_tail(&t[0], &m);
+
+ t[1].rx_buf = buf;
+ t[1].len = count;
+ spi_message_add_tail(&t[1], &m);
+
+ mutex_lock(&at25->lock);
+
+ /* Read it all at once.
+ *
+ * REVISIT that's potentially a problem with large chips, if
+ * other devices on the bus need to be accessed regularly or
+ * this chip is clocked very slowly
+ */
+ status = spi_sync(at25->spi, &m);
+ dev_dbg(&at25->spi->dev,
+ "read %Zd bytes at %d --> %d\n",
+ count, offset, (int) status);
+
+ mutex_unlock(&at25->lock);
+ return status ? status : count;
+}
+
+static ssize_t
+at25_bin_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
+{
+ struct device *dev;
+ struct at25_data *at25;
+
+ dev = container_of(kobj, struct device, kobj);
+ at25 = dev_get_drvdata(dev);
+
+ if (unlikely(off >= at25->bin.size))
+ return 0;
+ if ((off + count) > at25->bin.size)
+ count = at25->bin.size - off;
+ if (unlikely(!count))
+ return count;
+
+ return at25_ee_read(at25, buf, off, count);
+}
+
+
+static ssize_t
+at25_ee_write(struct at25_data *at25, char *buf, loff_t off, size_t count)
+{
+ ssize_t status = 0;
+ unsigned written = 0;
+ unsigned buf_size;
+ u8 *bounce;
+
+ /* Temp buffer starts with command and address */
+ buf_size = at25->chip.page_size;
+ if (buf_size > io_limit)
+ buf_size = io_limit;
+ bounce = kmalloc(buf_size + at25->addrlen + 1, GFP_KERNEL);
+ if (!bounce)
+ return -ENOMEM;
+
+ /* For write, rollover is within the page ... so we write at
+ * most one page, then manually roll over to the next page.
+ */
+ bounce[0] = AT25_WRITE;
+ mutex_lock(&at25->lock);
+ do {
+ unsigned long timeout, retries;
+ unsigned segment;
+ unsigned offset = (unsigned) off;
+ u8 *cp = bounce + 1;
+
+ *cp = AT25_WREN;
+ status = spi_write(at25->spi, cp, 1);
+ if (status < 0) {
+ dev_dbg(&at25->spi->dev, "WREN --> %d\n",
+ (int) status);
+ break;
+ }
+
+ /* 8/16/24-bit address is written MSB first */
+ switch (at25->addrlen) {
+ default: /* case 3 */
+ *cp++ = offset >> 16;
+ case 2:
+ *cp++ = offset >> 8;
+ case 1:
+ case 0: /* can't happen: for better codegen */
+ *cp++ = offset >> 0;
+ }
+
+ /* Write as much of a page as we can */
+ segment = buf_size - (offset % buf_size);
+ if (segment > count)
+ segment = count;
+ memcpy(cp, buf, segment);
+ status = spi_write(at25->spi, bounce,
+ segment + at25->addrlen + 1);
+ dev_dbg(&at25->spi->dev,
+ "write %u bytes at %u --> %d\n",
+ segment, offset, (int) status);
+ if (status < 0)
+ break;
+
+ /* REVISIT this should detect (or prevent) failed writes
+ * to readonly sections of the EEPROM...
+ */
+
+ /* Wait for non-busy status */
+ timeout = jiffies + msecs_to_jiffies(EE_TIMEOUT);
+ retries = 0;
+ do {
+ int sr;
+
+ sr = spi_w8r8(at25->spi, AT25_RDSR);
+ if (sr < 0 || (sr & AT25_SR_nRDY)) {
+ dev_dbg(&at25->spi->dev,
+ "rdsr --> %d (%02x)\n", sr, sr);
+ /* at HZ=100, this is sloooow */
+ msleep(1);
+ continue;
+ }
+ if (!(sr & AT25_SR_nRDY))
+ break;
+ } while (retries++ < 3 || time_before_eq(jiffies, timeout));
+
+ if (time_after(jiffies, timeout)) {
+ dev_err(&at25->spi->dev,
+ "write %d bytes offset %d, "
+ "timeout after %u msecs\n",
+ segment, offset,
+ jiffies_to_msecs(jiffies -
+ (timeout - EE_TIMEOUT)));
+ status = -ETIMEDOUT;
+ break;
+ }
+
+ off += segment;
+ buf += segment;
+ count -= segment;
+ written += segment;
+
+ } while (count > 0);
+
+ mutex_unlock(&at25->lock);
+
+ kfree(bounce);
+ return written ? written : status;
+}
+
+static ssize_t
+at25_bin_write(struct kobject *kobj, char *buf, loff_t off, size_t count)
+{
+ struct device *dev;
+ struct at25_data *at25;
+
+ dev = container_of(kobj, struct device, kobj);
+ at25 = dev_get_drvdata(dev);
+
+ if (unlikely(off >= at25->bin.size))
+ return -EFBIG;
+ if ((off + count) > at25->bin.size)
+ count = at25->bin.size - off;
+ if (unlikely(!count))
+ return count;
+
+ return at25_ee_write(at25, buf, off, count);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int at25_probe(struct spi_device *spi)
+{
+ struct at25_data *at25 = NULL;
+ const struct spi_eeprom *chip;
+ int err;
+ int sr;
+ int addrlen;
+
+ /* Chip description */
+ chip = spi->dev.platform_data;
+ if (!chip) {
+ dev_dbg(&spi->dev, "no chip description\n");
+ err = -ENODEV;
+ goto fail;
+ }
+
+ /* For now we only support 8/16/24 bit addressing */
+ if (chip->flags & EE_ADDR1)
+ addrlen = 1;
+ else if (chip->flags & EE_ADDR2)
+ addrlen = 2;
+ else if (chip->flags & EE_ADDR3)
+ addrlen = 3;
+ else {
+ dev_dbg(&spi->dev, "unsupported address type\n");
+ err = -EINVAL;
+ goto fail;
+ }
+
+ /* Ping the chip ... the status register is pretty portable,
+ * unlike probing manufacturer IDs. We do expect that system
+ * firmware didn't write it in the past few milliseconds!
+ */
+ sr = spi_w8r8(spi, AT25_RDSR);
+ if (sr < 0 || sr & AT25_SR_nRDY) {
+ dev_dbg(&at25->spi->dev, "rdsr --> %d (%02x)\n", sr, sr);
+ err = -ENXIO;
+ goto fail;
+ }
+
+ if (!(at25 = kzalloc(sizeof *at25, GFP_KERNEL))) {
+ err = -ENOMEM;
+ goto fail;
+ }
+
+ mutex_init(&at25->lock);
+ at25->chip = *chip;
+ at25->spi = spi_dev_get(spi);
+ dev_set_drvdata(&spi->dev, at25);
+ at25->addrlen = addrlen;
+
+ /* Export the EEPROM bytes through sysfs, since that's convenient.
+ * Default to root-only access to the data; EEPROMs often hold data
+ * that's sensitive for read and/or write, like ethernet addresses,
+ * security codes, board-specific manufacturing calibrations, etc.
+ */
+ at25->bin.attr.name = "eeprom";
+ at25->bin.attr.mode = S_IRUSR;
+ at25->bin.attr.owner = THIS_MODULE;
+ at25->bin.read = at25_bin_read;
+
+ at25->bin.size = at25->chip.byte_len;
+ if (!(chip->flags & EE_READONLY)) {
+ at25->bin.write = at25_bin_write;
+ at25->bin.attr.mode |= S_IWUSR;
+ }
+
+ err = sysfs_create_bin_file(&spi->dev.kobj, &at25->bin);
+ if (err)
+ goto fail;
+
+ dev_info(&spi->dev, "%Zd %s %s eeprom%s, pagesize %u\n",
+ (at25->bin.size < 1024)
+ ? at25->bin.size
+ : (at25->bin.size / 1024),
+ (at25->bin.size < 1024) ? "Byte" : "KByte",
+ at25->chip.name,
+ (chip->flags & EE_READONLY) ? " (readonly)" : "",
+ at25->chip.page_size);
+ return 0;
+fail:
+ dev_dbg(&spi->dev, "probe err %d\n", err);
+ kfree(at25);
+ return err;
+}
+
+static int __devexit at25_remove(struct spi_device *spi)
+{
+ struct at25_data *at25;
+
+ at25 = dev_get_drvdata(&spi->dev);
+ sysfs_remove_bin_file(&spi->dev.kobj, &at25->bin);
+ kfree(at25);
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static struct spi_driver at25_driver = {
+ .driver = {
+ .name = "at25",
+ .owner = THIS_MODULE,
+ },
+ .probe = at25_probe,
+ .remove = __devexit_p(at25_remove),
+};
+
+static int __init at25_init(void)
+{
+ return spi_register_driver(&at25_driver);
+}
+module_init(at25_init);
+
+static void __exit at25_exit(void)
+{
+ spi_unregister_driver(&at25_driver);
+}
+module_exit(at25_exit);
+
+MODULE_DESCRIPTION("Driver for most SPI EEPROMs");
+MODULE_AUTHOR("David Brownell");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c
new file mode 100644
index 00000000000..6fa260d1a9b
--- /dev/null
+++ b/drivers/spi/atmel_spi.c
@@ -0,0 +1,682 @@
+/*
+ * Driver for Atmel AT32 and AT91 SPI Controllers
+ *
+ * Copyright (C) 2006 Atmel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/spi/spi.h>
+
+#include <asm/io.h>
+#include <asm/arch/board.h>
+#include <asm/arch/gpio.h>
+
+#ifdef CONFIG_ARCH_AT91
+#include <asm/arch/cpu.h>
+#endif
+
+#include "atmel_spi.h"
+
+/*
+ * The core SPI transfer engine just talks to a register bank to set up
+ * DMA transfers; transfer queue progress is driven by IRQs. The clock
+ * framework provides the base clock, subdivided for each spi_device.
+ *
+ * Newer controllers, marked with "new_1" flag, have:
+ * - CR.LASTXFER
+ * - SPI_MR.DIV32 may become FDIV or must-be-zero (here: always zero)
+ * - SPI_SR.TXEMPTY, SPI_SR.NSSR (and corresponding irqs)
+ * - SPI_CSRx.CSAAT
+ * - SPI_CSRx.SBCR allows faster clocking
+ */
+struct atmel_spi {
+ spinlock_t lock;
+
+ void __iomem *regs;
+ int irq;
+ struct clk *clk;
+ struct platform_device *pdev;
+ unsigned new_1:1;
+
+ u8 stopping;
+ struct list_head queue;
+ struct spi_transfer *current_transfer;
+ unsigned long remaining_bytes;
+
+ void *buffer;
+ dma_addr_t buffer_dma;
+};
+
+#define BUFFER_SIZE PAGE_SIZE
+#define INVALID_DMA_ADDRESS 0xffffffff
+
+/*
+ * Earlier SPI controllers (e.g. on at91rm9200) have a design bug whereby
+ * they assume that spi slave device state will not change on deselect, so
+ * that automagic deselection is OK. Not so! Workaround uses nCSx pins
+ * as GPIOs; or newer controllers have CSAAT and friends.
+ *
+ * Since the CSAAT functionality is a bit weird on newer controllers
+ * as well, we use GPIO to control nCSx pins on all controllers.
+ */
+
+static inline void cs_activate(struct spi_device *spi)
+{
+ unsigned gpio = (unsigned) spi->controller_data;
+ unsigned active = spi->mode & SPI_CS_HIGH;
+
+ dev_dbg(&spi->dev, "activate %u%s\n", gpio, active ? " (high)" : "");
+ gpio_set_value(gpio, active);
+}
+
+static inline void cs_deactivate(struct spi_device *spi)
+{
+ unsigned gpio = (unsigned) spi->controller_data;
+ unsigned active = spi->mode & SPI_CS_HIGH;
+
+ dev_dbg(&spi->dev, "DEactivate %u%s\n", gpio, active ? " (low)" : "");
+ gpio_set_value(gpio, !active);
+}
+
+/*
+ * Submit next transfer for DMA.
+ * lock is held, spi irq is blocked
+ */
+static void atmel_spi_next_xfer(struct spi_master *master,
+ struct spi_message *msg)
+{
+ struct atmel_spi *as = spi_master_get_devdata(master);
+ struct spi_transfer *xfer;
+ u32 len;
+ dma_addr_t tx_dma, rx_dma;
+
+ xfer = as->current_transfer;
+ if (!xfer || as->remaining_bytes == 0) {
+ if (xfer)
+ xfer = list_entry(xfer->transfer_list.next,
+ struct spi_transfer, transfer_list);
+ else
+ xfer = list_entry(msg->transfers.next,
+ struct spi_transfer, transfer_list);
+ as->remaining_bytes = xfer->len;
+ as->current_transfer = xfer;
+ }
+
+ len = as->remaining_bytes;
+
+ tx_dma = xfer->tx_dma;
+ rx_dma = xfer->rx_dma;
+
+ /* use scratch buffer only when rx or tx data is unspecified */
+ if (rx_dma == INVALID_DMA_ADDRESS) {
+ rx_dma = as->buffer_dma;
+ if (len > BUFFER_SIZE)
+ len = BUFFER_SIZE;
+ }
+ if (tx_dma == INVALID_DMA_ADDRESS) {
+ tx_dma = as->buffer_dma;
+ if (len > BUFFER_SIZE)
+ len = BUFFER_SIZE;
+ memset(as->buffer, 0, len);
+ dma_sync_single_for_device(&as->pdev->dev,
+ as->buffer_dma, len, DMA_TO_DEVICE);
+ }
+
+ spi_writel(as, RPR, rx_dma);
+ spi_writel(as, TPR, tx_dma);
+
+ as->remaining_bytes -= len;
+ if (msg->spi->bits_per_word > 8)
+ len >>= 1;
+
+ /* REVISIT: when xfer->delay_usecs == 0, the PDC "next transfer"
+ * mechanism might help avoid the IRQ latency between transfers
+ *
+ * We're also waiting for ENDRX before we start the next
+ * transfer because we need to handle some difficult timing
+ * issues otherwise. If we wait for ENDTX in one transfer and
+ * then starts waiting for ENDRX in the next, it's difficult
+ * to tell the difference between the ENDRX interrupt we're
+ * actually waiting for and the ENDRX interrupt of the
+ * previous transfer.
+ *
+ * It should be doable, though. Just not now...
+ */
+ spi_writel(as, TNCR, 0);
+ spi_writel(as, RNCR, 0);
+ spi_writel(as, IER, SPI_BIT(ENDRX) | SPI_BIT(OVRES));
+
+ dev_dbg(&msg->spi->dev,
+ " start xfer %p: len %u tx %p/%08x rx %p/%08x imr %03x\n",
+ xfer, xfer->len, xfer->tx_buf, xfer->tx_dma,
+ xfer->rx_buf, xfer->rx_dma, spi_readl(as, IMR));
+
+ spi_writel(as, TCR, len);
+ spi_writel(as, RCR, len);
+ spi_writel(as, PTCR, SPI_BIT(TXTEN) | SPI_BIT(RXTEN));
+}
+
+static void atmel_spi_next_message(struct spi_master *master)
+{
+ struct atmel_spi *as = spi_master_get_devdata(master);
+ struct spi_message *msg;
+ u32 mr;
+
+ BUG_ON(as->current_transfer);
+
+ msg = list_entry(as->queue.next, struct spi_message, queue);
+
+ /* Select the chip */
+ mr = spi_readl(as, MR);
+ mr = SPI_BFINS(PCS, ~(1 << msg->spi->chip_select), mr);
+ spi_writel(as, MR, mr);
+ cs_activate(msg->spi);
+
+ atmel_spi_next_xfer(master, msg);
+}
+
+static void
+atmel_spi_dma_map_xfer(struct atmel_spi *as, struct spi_transfer *xfer)
+{
+ xfer->tx_dma = xfer->rx_dma = INVALID_DMA_ADDRESS;
+ if (xfer->tx_buf)
+ xfer->tx_dma = dma_map_single(&as->pdev->dev,
+ (void *) xfer->tx_buf, xfer->len,
+ DMA_TO_DEVICE);
+ if (xfer->rx_buf)
+ xfer->rx_dma = dma_map_single(&as->pdev->dev,
+ xfer->rx_buf, xfer->len,
+ DMA_FROM_DEVICE);
+}
+
+static void atmel_spi_dma_unmap_xfer(struct spi_master *master,
+ struct spi_transfer *xfer)
+{
+ if (xfer->tx_dma != INVALID_DMA_ADDRESS)
+ dma_unmap_single(master->cdev.dev, xfer->tx_dma,
+ xfer->len, DMA_TO_DEVICE);
+ if (xfer->rx_dma != INVALID_DMA_ADDRESS)
+ dma_unmap_single(master->cdev.dev, xfer->rx_dma,
+ xfer->len, DMA_FROM_DEVICE);
+}
+
+static void
+atmel_spi_msg_done(struct spi_master *master, struct atmel_spi *as,
+ struct spi_message *msg, int status)
+{
+ cs_deactivate(msg->spi);
+ list_del(&msg->queue);
+ msg->status = status;
+
+ dev_dbg(master->cdev.dev,
+ "xfer complete: %u bytes transferred\n",
+ msg->actual_length);
+
+ spin_unlock(&as->lock);
+ msg->complete(msg->context);
+ spin_lock(&as->lock);
+
+ as->current_transfer = NULL;
+
+ /* continue if needed */
+ if (list_empty(&as->queue) || as->stopping)
+ spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS));
+ else
+ atmel_spi_next_message(master);
+}
+
+static irqreturn_t
+atmel_spi_interrupt(int irq, void *dev_id)
+{
+ struct spi_master *master = dev_id;
+ struct atmel_spi *as = spi_master_get_devdata(master);
+ struct spi_message *msg;
+ struct spi_transfer *xfer;
+ u32 status, pending, imr;
+ int ret = IRQ_NONE;
+
+ spin_lock(&as->lock);
+
+ xfer = as->current_transfer;
+ msg = list_entry(as->queue.next, struct spi_message, queue);
+
+ imr = spi_readl(as, IMR);
+ status = spi_readl(as, SR);
+ pending = status & imr;
+
+ if (pending & SPI_BIT(OVRES)) {
+ int timeout;
+
+ ret = IRQ_HANDLED;
+
+ spi_writel(as, IDR, (SPI_BIT(ENDTX) | SPI_BIT(ENDRX)
+ | SPI_BIT(OVRES)));
+
+ /*
+ * When we get an overrun, we disregard the current
+ * transfer. Data will not be copied back from any
+ * bounce buffer and msg->actual_len will not be
+ * updated with the last xfer.
+ *
+ * We will also not process any remaning transfers in
+ * the message.
+ *
+ * First, stop the transfer and unmap the DMA buffers.
+ */
+ spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS));
+ if (!msg->is_dma_mapped)
+ atmel_spi_dma_unmap_xfer(master, xfer);
+
+ /* REVISIT: udelay in irq is unfriendly */
+ if (xfer->delay_usecs)
+ udelay(xfer->delay_usecs);
+
+ dev_warn(master->cdev.dev, "fifo overrun (%u/%u remaining)\n",
+ spi_readl(as, TCR), spi_readl(as, RCR));
+
+ /*
+ * Clean up DMA registers and make sure the data
+ * registers are empty.
+ */
+ spi_writel(as, RNCR, 0);
+ spi_writel(as, TNCR, 0);
+ spi_writel(as, RCR, 0);
+ spi_writel(as, TCR, 0);
+ for (timeout = 1000; timeout; timeout--)
+ if (spi_readl(as, SR) & SPI_BIT(TXEMPTY))
+ break;
+ if (!timeout)
+ dev_warn(master->cdev.dev,
+ "timeout waiting for TXEMPTY");
+ while (spi_readl(as, SR) & SPI_BIT(RDRF))
+ spi_readl(as, RDR);
+
+ /* Clear any overrun happening while cleaning up */
+ spi_readl(as, SR);
+
+ atmel_spi_msg_done(master, as, msg, -EIO);
+ } else if (pending & SPI_BIT(ENDRX)) {
+ ret = IRQ_HANDLED;
+
+ spi_writel(as, IDR, pending);
+
+ if (as->remaining_bytes == 0) {
+ msg->actual_length += xfer->len;
+
+ if (!msg->is_dma_mapped)
+ atmel_spi_dma_unmap_xfer(master, xfer);
+
+ /* REVISIT: udelay in irq is unfriendly */
+ if (xfer->delay_usecs)
+ udelay(xfer->delay_usecs);
+
+ if (msg->transfers.prev == &xfer->transfer_list) {
+ /* report completed message */
+ atmel_spi_msg_done(master, as, msg, 0);
+ } else {
+ if (xfer->cs_change) {
+ cs_deactivate(msg->spi);
+ udelay(1);
+ cs_activate(msg->spi);
+ }
+
+ /*
+ * Not done yet. Submit the next transfer.
+ *
+ * FIXME handle protocol options for xfer
+ */
+ atmel_spi_next_xfer(master, msg);
+ }
+ } else {
+ /*
+ * Keep going, we still have data to send in
+ * the current transfer.
+ */
+ atmel_spi_next_xfer(master, msg);
+ }
+ }
+
+ spin_unlock(&as->lock);
+
+ return ret;
+}
+
+#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH)
+
+static int atmel_spi_setup(struct spi_device *spi)
+{
+ struct atmel_spi *as;
+ u32 scbr, csr;
+ unsigned int bits = spi->bits_per_word;
+ unsigned long bus_hz, sck_hz;
+ unsigned int npcs_pin;
+ int ret;
+
+ as = spi_master_get_devdata(spi->master);
+
+ if (as->stopping)
+ return -ESHUTDOWN;
+
+ if (spi->chip_select > spi->master->num_chipselect) {
+ dev_dbg(&spi->dev,
+ "setup: invalid chipselect %u (%u defined)\n",
+ spi->chip_select, spi->master->num_chipselect);
+ return -EINVAL;
+ }
+
+ if (bits == 0)
+ bits = 8;
+ if (bits < 8 || bits > 16) {
+ dev_dbg(&spi->dev,
+ "setup: invalid bits_per_word %u (8 to 16)\n",
+ bits);
+ return -EINVAL;
+ }
+
+ if (spi->mode & ~MODEBITS) {
+ dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n",
+ spi->mode & ~MODEBITS);
+ return -EINVAL;
+ }
+
+ /* speed zero convention is used by some upper layers */
+ bus_hz = clk_get_rate(as->clk);
+ if (spi->max_speed_hz) {
+ /* assume div32/fdiv/mbz == 0 */
+ if (!as->new_1)
+ bus_hz /= 2;
+ scbr = ((bus_hz + spi->max_speed_hz - 1)
+ / spi->max_speed_hz);
+ if (scbr >= (1 << SPI_SCBR_SIZE)) {
+ dev_dbg(&spi->dev, "setup: %d Hz too slow, scbr %u\n",
+ spi->max_speed_hz, scbr);
+ return -EINVAL;
+ }
+ } else
+ scbr = 0xff;
+ sck_hz = bus_hz / scbr;
+
+ csr = SPI_BF(SCBR, scbr) | SPI_BF(BITS, bits - 8);
+ if (spi->mode & SPI_CPOL)
+ csr |= SPI_BIT(CPOL);
+ if (!(spi->mode & SPI_CPHA))
+ csr |= SPI_BIT(NCPHA);
+
+ /* TODO: DLYBS and DLYBCT */
+ csr |= SPI_BF(DLYBS, 10);
+ csr |= SPI_BF(DLYBCT, 10);
+
+ /* chipselect must have been muxed as GPIO (e.g. in board setup) */
+ npcs_pin = (unsigned int)spi->controller_data;
+ if (!spi->controller_state) {
+ ret = gpio_request(npcs_pin, "spi_npcs");
+ if (ret)
+ return ret;
+ spi->controller_state = (void *)npcs_pin;
+ gpio_direction_output(npcs_pin);
+ }
+
+ dev_dbg(&spi->dev,
+ "setup: %lu Hz bpw %u mode 0x%x -> csr%d %08x\n",
+ sck_hz, bits, spi->mode, spi->chip_select, csr);
+
+ spi_writel(as, CSR0 + 4 * spi->chip_select, csr);
+
+ return 0;
+}
+
+static int atmel_spi_transfer(struct spi_device *spi, struct spi_message *msg)
+{
+ struct atmel_spi *as;
+ struct spi_transfer *xfer;
+ unsigned long flags;
+ struct device *controller = spi->master->cdev.dev;
+
+ as = spi_master_get_devdata(spi->master);
+
+ dev_dbg(controller, "new message %p submitted for %s\n",
+ msg, spi->dev.bus_id);
+
+ if (unlikely(list_empty(&msg->transfers)
+ || !spi->max_speed_hz))
+ return -EINVAL;
+
+ if (as->stopping)
+ return -ESHUTDOWN;
+
+ list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+ if (!(xfer->tx_buf || xfer->rx_buf)) {
+ dev_dbg(&spi->dev, "missing rx or tx buf\n");
+ return -EINVAL;
+ }
+
+ /* FIXME implement these protocol options!! */
+ if (xfer->bits_per_word || xfer->speed_hz) {
+ dev_dbg(&spi->dev, "no protocol options yet\n");
+ return -ENOPROTOOPT;
+ }
+ }
+
+ /* scrub dcache "early" */
+ if (!msg->is_dma_mapped) {
+ list_for_each_entry(xfer, &msg->transfers, transfer_list)
+ atmel_spi_dma_map_xfer(as, xfer);
+ }
+
+ list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+ dev_dbg(controller,
+ " xfer %p: len %u tx %p/%08x rx %p/%08x\n",
+ xfer, xfer->len,
+ xfer->tx_buf, xfer->tx_dma,
+ xfer->rx_buf, xfer->rx_dma);
+ }
+
+ msg->status = -EINPROGRESS;
+ msg->actual_length = 0;
+
+ spin_lock_irqsave(&as->lock, flags);
+ list_add_tail(&msg->queue, &as->queue);
+ if (!as->current_transfer)
+ atmel_spi_next_message(spi->master);
+ spin_unlock_irqrestore(&as->lock, flags);
+
+ return 0;
+}
+
+static void atmel_spi_cleanup(struct spi_device *spi)
+{
+ if (spi->controller_state)
+ gpio_free((unsigned int)spi->controller_data);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int __init atmel_spi_probe(struct platform_device *pdev)
+{
+ struct resource *regs;
+ int irq;
+ struct clk *clk;
+ int ret;
+ struct spi_master *master;
+ struct atmel_spi *as;
+
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!regs)
+ return -ENXIO;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ clk = clk_get(&pdev->dev, "spi_clk");
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ /* setup spi core then atmel-specific driver state */
+ ret = -ENOMEM;
+ master = spi_alloc_master(&pdev->dev, sizeof *as);
+ if (!master)
+ goto out_free;
+
+ master->bus_num = pdev->id;
+ master->num_chipselect = 4;
+ master->setup = atmel_spi_setup;
+ master->transfer = atmel_spi_transfer;
+ master->cleanup = atmel_spi_cleanup;
+ platform_set_drvdata(pdev, master);
+
+ as = spi_master_get_devdata(master);
+
+ as->buffer = dma_alloc_coherent(&pdev->dev, BUFFER_SIZE,
+ &as->buffer_dma, GFP_KERNEL);
+ if (!as->buffer)
+ goto out_free;
+
+ spin_lock_init(&as->lock);
+ INIT_LIST_HEAD(&as->queue);
+ as->pdev = pdev;
+ as->regs = ioremap(regs->start, (regs->end - regs->start) + 1);
+ if (!as->regs)
+ goto out_free_buffer;
+ as->irq = irq;
+ as->clk = clk;
+#ifdef CONFIG_ARCH_AT91
+ if (!cpu_is_at91rm9200())
+ as->new_1 = 1;
+#endif
+
+ ret = request_irq(irq, atmel_spi_interrupt, 0,
+ pdev->dev.bus_id, master);
+ if (ret)
+ goto out_unmap_regs;
+
+ /* Initialize the hardware */
+ clk_enable(clk);
+ spi_writel(as, CR, SPI_BIT(SWRST));
+ spi_writel(as, MR, SPI_BIT(MSTR) | SPI_BIT(MODFDIS));
+ spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS));
+ spi_writel(as, CR, SPI_BIT(SPIEN));
+
+ /* go! */
+ dev_info(&pdev->dev, "Atmel SPI Controller at 0x%08lx (irq %d)\n",
+ (unsigned long)regs->start, irq);
+
+ ret = spi_register_master(master);
+ if (ret)
+ goto out_reset_hw;
+
+ return 0;
+
+out_reset_hw:
+ spi_writel(as, CR, SPI_BIT(SWRST));
+ clk_disable(clk);
+ free_irq(irq, master);
+out_unmap_regs:
+ iounmap(as->regs);
+out_free_buffer:
+ dma_free_coherent(&pdev->dev, BUFFER_SIZE, as->buffer,
+ as->buffer_dma);
+out_free:
+ clk_put(clk);
+ spi_master_put(master);
+ return ret;
+}
+
+static int __exit atmel_spi_remove(struct platform_device *pdev)
+{
+ struct spi_master *master = platform_get_drvdata(pdev);
+ struct atmel_spi *as = spi_master_get_devdata(master);
+ struct spi_message *msg;
+
+ /* reset the hardware and block queue progress */
+ spin_lock_irq(&as->lock);
+ as->stopping = 1;
+ spi_writel(as, CR, SPI_BIT(SWRST));
+ spi_readl(as, SR);
+ spin_unlock_irq(&as->lock);
+
+ /* Terminate remaining queued transfers */
+ list_for_each_entry(msg, &as->queue, queue) {
+ /* REVISIT unmapping the dma is a NOP on ARM and AVR32
+ * but we shouldn't depend on that...
+ */
+ msg->status = -ESHUTDOWN;
+ msg->complete(msg->context);
+ }
+
+ dma_free_coherent(&pdev->dev, BUFFER_SIZE, as->buffer,
+ as->buffer_dma);
+
+ clk_disable(as->clk);
+ clk_put(as->clk);
+ free_irq(as->irq, master);
+ iounmap(as->regs);
+
+ spi_unregister_master(master);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+
+static int atmel_spi_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+ struct spi_master *master = platform_get_drvdata(pdev);
+ struct atmel_spi *as = spi_master_get_devdata(master);
+
+ clk_disable(as->clk);
+ return 0;
+}
+
+static int atmel_spi_resume(struct platform_device *pdev)
+{
+ struct spi_master *master = platform_get_drvdata(pdev);
+ struct atmel_spi *as = spi_master_get_devdata(master);
+
+ clk_enable(as->clk);
+ return 0;
+}
+
+#else
+#define atmel_spi_suspend NULL
+#define atmel_spi_resume NULL
+#endif
+
+
+static struct platform_driver atmel_spi_driver = {
+ .driver = {
+ .name = "atmel_spi",
+ .owner = THIS_MODULE,
+ },
+ .suspend = atmel_spi_suspend,
+ .resume = atmel_spi_resume,
+ .remove = __exit_p(atmel_spi_remove),
+};
+
+static int __init atmel_spi_init(void)
+{
+ return platform_driver_probe(&atmel_spi_driver, atmel_spi_probe);
+}
+module_init(atmel_spi_init);
+
+static void __exit atmel_spi_exit(void)
+{
+ platform_driver_unregister(&atmel_spi_driver);
+}
+module_exit(atmel_spi_exit);
+
+MODULE_DESCRIPTION("Atmel AT32/AT91 SPI Controller driver");
+MODULE_AUTHOR("Haavard Skinnemoen <hskinnemoen@atmel.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/atmel_spi.h b/drivers/spi/atmel_spi.h
new file mode 100644
index 00000000000..6e06b6ad3a4
--- /dev/null
+++ b/drivers/spi/atmel_spi.h
@@ -0,0 +1,167 @@
+/*
+ * Register definitions for Atmel Serial Peripheral Interface (SPI)
+ *
+ * Copyright (C) 2006 Atmel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __ATMEL_SPI_H__
+#define __ATMEL_SPI_H__
+
+/* SPI register offsets */
+#define SPI_CR 0x0000
+#define SPI_MR 0x0004
+#define SPI_RDR 0x0008
+#define SPI_TDR 0x000c
+#define SPI_SR 0x0010
+#define SPI_IER 0x0014
+#define SPI_IDR 0x0018
+#define SPI_IMR 0x001c
+#define SPI_CSR0 0x0030
+#define SPI_CSR1 0x0034
+#define SPI_CSR2 0x0038
+#define SPI_CSR3 0x003c
+#define SPI_RPR 0x0100
+#define SPI_RCR 0x0104
+#define SPI_TPR 0x0108
+#define SPI_TCR 0x010c
+#define SPI_RNPR 0x0110
+#define SPI_RNCR 0x0114
+#define SPI_TNPR 0x0118
+#define SPI_TNCR 0x011c
+#define SPI_PTCR 0x0120
+#define SPI_PTSR 0x0124
+
+/* Bitfields in CR */
+#define SPI_SPIEN_OFFSET 0
+#define SPI_SPIEN_SIZE 1
+#define SPI_SPIDIS_OFFSET 1
+#define SPI_SPIDIS_SIZE 1
+#define SPI_SWRST_OFFSET 7
+#define SPI_SWRST_SIZE 1
+#define SPI_LASTXFER_OFFSET 24
+#define SPI_LASTXFER_SIZE 1
+
+/* Bitfields in MR */
+#define SPI_MSTR_OFFSET 0
+#define SPI_MSTR_SIZE 1
+#define SPI_PS_OFFSET 1
+#define SPI_PS_SIZE 1
+#define SPI_PCSDEC_OFFSET 2
+#define SPI_PCSDEC_SIZE 1
+#define SPI_FDIV_OFFSET 3
+#define SPI_FDIV_SIZE 1
+#define SPI_MODFDIS_OFFSET 4
+#define SPI_MODFDIS_SIZE 1
+#define SPI_LLB_OFFSET 7
+#define SPI_LLB_SIZE 1
+#define SPI_PCS_OFFSET 16
+#define SPI_PCS_SIZE 4
+#define SPI_DLYBCS_OFFSET 24
+#define SPI_DLYBCS_SIZE 8
+
+/* Bitfields in RDR */
+#define SPI_RD_OFFSET 0
+#define SPI_RD_SIZE 16
+
+/* Bitfields in TDR */
+#define SPI_TD_OFFSET 0
+#define SPI_TD_SIZE 16
+
+/* Bitfields in SR */
+#define SPI_RDRF_OFFSET 0
+#define SPI_RDRF_SIZE 1
+#define SPI_TDRE_OFFSET 1
+#define SPI_TDRE_SIZE 1
+#define SPI_MODF_OFFSET 2
+#define SPI_MODF_SIZE 1
+#define SPI_OVRES_OFFSET 3
+#define SPI_OVRES_SIZE 1
+#define SPI_ENDRX_OFFSET 4
+#define SPI_ENDRX_SIZE 1
+#define SPI_ENDTX_OFFSET 5
+#define SPI_ENDTX_SIZE 1
+#define SPI_RXBUFF_OFFSET 6
+#define SPI_RXBUFF_SIZE 1
+#define SPI_TXBUFE_OFFSET 7
+#define SPI_TXBUFE_SIZE 1
+#define SPI_NSSR_OFFSET 8
+#define SPI_NSSR_SIZE 1
+#define SPI_TXEMPTY_OFFSET 9
+#define SPI_TXEMPTY_SIZE 1
+#define SPI_SPIENS_OFFSET 16
+#define SPI_SPIENS_SIZE 1
+
+/* Bitfields in CSR0 */
+#define SPI_CPOL_OFFSET 0
+#define SPI_CPOL_SIZE 1
+#define SPI_NCPHA_OFFSET 1
+#define SPI_NCPHA_SIZE 1
+#define SPI_CSAAT_OFFSET 3
+#define SPI_CSAAT_SIZE 1
+#define SPI_BITS_OFFSET 4
+#define SPI_BITS_SIZE 4
+#define SPI_SCBR_OFFSET 8
+#define SPI_SCBR_SIZE 8
+#define SPI_DLYBS_OFFSET 16
+#define SPI_DLYBS_SIZE 8
+#define SPI_DLYBCT_OFFSET 24
+#define SPI_DLYBCT_SIZE 8
+
+/* Bitfields in RCR */
+#define SPI_RXCTR_OFFSET 0
+#define SPI_RXCTR_SIZE 16
+
+/* Bitfields in TCR */
+#define SPI_TXCTR_OFFSET 0
+#define SPI_TXCTR_SIZE 16
+
+/* Bitfields in RNCR */
+#define SPI_RXNCR_OFFSET 0
+#define SPI_RXNCR_SIZE 16
+
+/* Bitfields in TNCR */
+#define SPI_TXNCR_OFFSET 0
+#define SPI_TXNCR_SIZE 16
+
+/* Bitfields in PTCR */
+#define SPI_RXTEN_OFFSET 0
+#define SPI_RXTEN_SIZE 1
+#define SPI_RXTDIS_OFFSET 1
+#define SPI_RXTDIS_SIZE 1
+#define SPI_TXTEN_OFFSET 8
+#define SPI_TXTEN_SIZE 1
+#define SPI_TXTDIS_OFFSET 9
+#define SPI_TXTDIS_SIZE 1
+
+/* Constants for BITS */
+#define SPI_BITS_8_BPT 0
+#define SPI_BITS_9_BPT 1
+#define SPI_BITS_10_BPT 2
+#define SPI_BITS_11_BPT 3
+#define SPI_BITS_12_BPT 4
+#define SPI_BITS_13_BPT 5
+#define SPI_BITS_14_BPT 6
+#define SPI_BITS_15_BPT 7
+#define SPI_BITS_16_BPT 8
+
+/* Bit manipulation macros */
+#define SPI_BIT(name) \
+ (1 << SPI_##name##_OFFSET)
+#define SPI_BF(name,value) \
+ (((value) & ((1 << SPI_##name##_SIZE) - 1)) << SPI_##name##_OFFSET)
+#define SPI_BFEXT(name,value) \
+ (((value) >> SPI_##name##_OFFSET) & ((1 << SPI_##name##_SIZE) - 1))
+#define SPI_BFINS(name,value,old) \
+ ( ((old) & ~(((1 << SPI_##name##_SIZE) - 1) << SPI_##name##_OFFSET)) \
+ | SPI_BF(name,value))
+
+/* Register access macros */
+#define spi_readl(port,reg) \
+ __raw_readl((port)->regs + SPI_##reg)
+#define spi_writel(port,reg,value) \
+ __raw_writel((value), (port)->regs + SPI_##reg)
+
+#endif /* __ATMEL_SPI_H__ */
diff --git a/drivers/spi/omap_uwire.c b/drivers/spi/omap_uwire.c
new file mode 100644
index 00000000000..96f62b2df30
--- /dev/null
+++ b/drivers/spi/omap_uwire.c
@@ -0,0 +1,572 @@
+/*
+ * omap_uwire.c -- MicroWire interface driver for OMAP
+ *
+ * Copyright 2003 MontaVista Software Inc. <source@mvista.com>
+ *
+ * Ported to 2.6 OMAP uwire interface.
+ * Copyright (C) 2004 Texas Instruments.
+ *
+ * Generalization patches by Juha Yrjola <juha.yrjola@nokia.com>
+ *
+ * Copyright (C) 2005 David Brownell (ported to 2.6 SPI interface)
+ * Copyright (C) 2006 Nokia
+ *
+ * Many updates by Imre Deak <imre.deak@nokia.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 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/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/mach-types.h>
+
+#include <asm/arch/mux.h>
+#include <asm/arch/omap730.h> /* OMAP730_IO_CONF registers */
+
+
+/* FIXME address is now a platform device resource,
+ * and irqs should show there too...
+ */
+#define UWIRE_BASE_PHYS 0xFFFB3000
+#define UWIRE_BASE ((void *__iomem)IO_ADDRESS(UWIRE_BASE_PHYS))
+
+/* uWire Registers: */
+#define UWIRE_IO_SIZE 0x20
+#define UWIRE_TDR 0x00
+#define UWIRE_RDR 0x00
+#define UWIRE_CSR 0x01
+#define UWIRE_SR1 0x02
+#define UWIRE_SR2 0x03
+#define UWIRE_SR3 0x04
+#define UWIRE_SR4 0x05
+#define UWIRE_SR5 0x06
+
+/* CSR bits */
+#define RDRB (1 << 15)
+#define CSRB (1 << 14)
+#define START (1 << 13)
+#define CS_CMD (1 << 12)
+
+/* SR1 or SR2 bits */
+#define UWIRE_READ_FALLING_EDGE 0x0001
+#define UWIRE_READ_RISING_EDGE 0x0000
+#define UWIRE_WRITE_FALLING_EDGE 0x0000
+#define UWIRE_WRITE_RISING_EDGE 0x0002
+#define UWIRE_CS_ACTIVE_LOW 0x0000
+#define UWIRE_CS_ACTIVE_HIGH 0x0004
+#define UWIRE_FREQ_DIV_2 0x0000
+#define UWIRE_FREQ_DIV_4 0x0008
+#define UWIRE_FREQ_DIV_8 0x0010
+#define UWIRE_CHK_READY 0x0020
+#define UWIRE_CLK_INVERTED 0x0040
+
+
+struct uwire_spi {
+ struct spi_bitbang bitbang;
+ struct clk *ck;
+};
+
+struct uwire_state {
+ unsigned bits_per_word;
+ unsigned div1_idx;
+};
+
+/* REVISIT compile time constant for idx_shift? */
+static unsigned int uwire_idx_shift;
+
+static inline void uwire_write_reg(int idx, u16 val)
+{
+ __raw_writew(val, UWIRE_BASE + (idx << uwire_idx_shift));
+}
+
+static inline u16 uwire_read_reg(int idx)
+{
+ return __raw_readw(UWIRE_BASE + (idx << uwire_idx_shift));
+}
+
+static inline void omap_uwire_configure_mode(u8 cs, unsigned long flags)
+{
+ u16 w, val = 0;
+ int shift, reg;
+
+ if (flags & UWIRE_CLK_INVERTED)
+ val ^= 0x03;
+ val = flags & 0x3f;
+ if (cs & 1)
+ shift = 6;
+ else
+ shift = 0;
+ if (cs <= 1)
+ reg = UWIRE_SR1;
+ else
+ reg = UWIRE_SR2;
+
+ w = uwire_read_reg(reg);
+ w &= ~(0x3f << shift);
+ w |= val << shift;
+ uwire_write_reg(reg, w);
+}
+
+static int wait_uwire_csr_flag(u16 mask, u16 val, int might_not_catch)
+{
+ u16 w;
+ int c = 0;
+ unsigned long max_jiffies = jiffies + HZ;
+
+ for (;;) {
+ w = uwire_read_reg(UWIRE_CSR);
+ if ((w & mask) == val)
+ break;
+ if (time_after(jiffies, max_jiffies)) {
+ printk(KERN_ERR "%s: timeout. reg=%#06x "
+ "mask=%#06x val=%#06x\n",
+ __FUNCTION__, w, mask, val);
+ return -1;
+ }
+ c++;
+ if (might_not_catch && c > 64)
+ break;
+ }
+ return 0;
+}
+
+static void uwire_set_clk1_div(int div1_idx)
+{
+ u16 w;
+
+ w = uwire_read_reg(UWIRE_SR3);
+ w &= ~(0x03 << 1);
+ w |= div1_idx << 1;
+ uwire_write_reg(UWIRE_SR3, w);
+}
+
+static void uwire_chipselect(struct spi_device *spi, int value)
+{
+ struct uwire_state *ust = spi->controller_state;
+ u16 w;
+ int old_cs;
+
+
+ BUG_ON(wait_uwire_csr_flag(CSRB, 0, 0));
+
+ w = uwire_read_reg(UWIRE_CSR);
+ old_cs = (w >> 10) & 0x03;
+ if (value == BITBANG_CS_INACTIVE || old_cs != spi->chip_select) {
+ /* Deselect this CS, or the previous CS */
+ w &= ~CS_CMD;
+ uwire_write_reg(UWIRE_CSR, w);
+ }
+ /* activate specfied chipselect */
+ if (value == BITBANG_CS_ACTIVE) {
+ uwire_set_clk1_div(ust->div1_idx);
+ /* invert clock? */
+ if (spi->mode & SPI_CPOL)
+ uwire_write_reg(UWIRE_SR4, 1);
+ else
+ uwire_write_reg(UWIRE_SR4, 0);
+
+ w = spi->chip_select << 10;
+ w |= CS_CMD;
+ uwire_write_reg(UWIRE_CSR, w);
+ }
+}
+
+static int uwire_txrx(struct spi_device *spi, struct spi_transfer *t)
+{
+ struct uwire_state *ust = spi->controller_state;
+ unsigned len = t->len;
+ unsigned bits = ust->bits_per_word;
+ unsigned bytes;
+ u16 val, w;
+ int status = 0;;
+
+ if (!t->tx_buf && !t->rx_buf)
+ return 0;
+
+ /* Microwire doesn't read and write concurrently */
+ if (t->tx_buf && t->rx_buf)
+ return -EPERM;
+
+ w = spi->chip_select << 10;
+ w |= CS_CMD;
+
+ if (t->tx_buf) {
+ const u8 *buf = t->tx_buf;
+
+ /* NOTE: DMA could be used for TX transfers */
+
+ /* write one or two bytes at a time */
+ while (len >= 1) {
+ /* tx bit 15 is first sent; we byteswap multibyte words
+ * (msb-first) on the way out from memory.
+ */
+ val = *buf++;
+ if (bits > 8) {
+ bytes = 2;
+ val |= *buf++ << 8;
+ } else
+ bytes = 1;
+ val <<= 16 - bits;
+
+#ifdef VERBOSE
+ pr_debug("%s: write-%d =%04x\n",
+ spi->dev.bus_id, bits, val);
+#endif
+ if (wait_uwire_csr_flag(CSRB, 0, 0))
+ goto eio;
+
+ uwire_write_reg(UWIRE_TDR, val);
+
+ /* start write */
+ val = START | w | (bits << 5);
+
+ uwire_write_reg(UWIRE_CSR, val);
+ len -= bytes;
+
+ /* Wait till write actually starts.
+ * This is needed with MPU clock 60+ MHz.
+ * REVISIT: we may not have time to catch it...
+ */
+ if (wait_uwire_csr_flag(CSRB, CSRB, 1))
+ goto eio;
+
+ status += bytes;
+ }
+
+ /* REVISIT: save this for later to get more i/o overlap */
+ if (wait_uwire_csr_flag(CSRB, 0, 0))
+ goto eio;
+
+ } else if (t->rx_buf) {
+ u8 *buf = t->rx_buf;
+
+ /* read one or two bytes at a time */
+ while (len) {
+ if (bits > 8) {
+ bytes = 2;
+ } else
+ bytes = 1;
+
+ /* start read */
+ val = START | w | (bits << 0);
+ uwire_write_reg(UWIRE_CSR, val);
+ len -= bytes;
+
+ /* Wait till read actually starts */
+ (void) wait_uwire_csr_flag(CSRB, CSRB, 1);
+
+ if (wait_uwire_csr_flag(RDRB | CSRB,
+ RDRB, 0))
+ goto eio;
+
+ /* rx bit 0 is last received; multibyte words will
+ * be properly byteswapped on the way to memory.
+ */
+ val = uwire_read_reg(UWIRE_RDR);
+ val &= (1 << bits) - 1;
+ *buf++ = (u8) val;
+ if (bytes == 2)
+ *buf++ = val >> 8;
+ status += bytes;
+#ifdef VERBOSE
+ pr_debug("%s: read-%d =%04x\n",
+ spi->dev.bus_id, bits, val);
+#endif
+
+ }
+ }
+ return status;
+eio:
+ return -EIO;
+}
+
+static int uwire_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
+{
+ struct uwire_state *ust = spi->controller_state;
+ struct uwire_spi *uwire;
+ unsigned flags = 0;
+ unsigned bits;
+ unsigned hz;
+ unsigned long rate;
+ int div1_idx;
+ int div1;
+ int div2;
+ int status;
+
+ uwire = spi_master_get_devdata(spi->master);
+
+ if (spi->chip_select > 3) {
+ pr_debug("%s: cs%d?\n", spi->dev.bus_id, spi->chip_select);
+ status = -ENODEV;
+ goto done;
+ }
+
+ bits = spi->bits_per_word;
+ if (t != NULL && t->bits_per_word)
+ bits = t->bits_per_word;
+ if (!bits)
+ bits = 8;
+
+ if (bits > 16) {
+ pr_debug("%s: wordsize %d?\n", spi->dev.bus_id, bits);
+ status = -ENODEV;
+ goto done;
+ }
+ ust->bits_per_word = bits;
+
+ /* mode 0..3, clock inverted separately;
+ * standard nCS signaling;
+ * don't treat DI=high as "not ready"
+ */
+ if (spi->mode & SPI_CS_HIGH)
+ flags |= UWIRE_CS_ACTIVE_HIGH;
+
+ if (spi->mode & SPI_CPOL)
+ flags |= UWIRE_CLK_INVERTED;
+
+ switch (spi->mode & (SPI_CPOL | SPI_CPHA)) {
+ case SPI_MODE_0:
+ case SPI_MODE_3:
+ flags |= UWIRE_WRITE_RISING_EDGE | UWIRE_READ_FALLING_EDGE;
+ break;
+ case SPI_MODE_1:
+ case SPI_MODE_2:
+ flags |= UWIRE_WRITE_FALLING_EDGE | UWIRE_READ_RISING_EDGE;
+ break;
+ }
+
+ /* assume it's already enabled */
+ rate = clk_get_rate(uwire->ck);
+
+ hz = spi->max_speed_hz;
+ if (t != NULL && t->speed_hz)
+ hz = t->speed_hz;
+
+ if (!hz) {
+ pr_debug("%s: zero speed?\n", spi->dev.bus_id);
+ status = -EINVAL;
+ goto done;
+ }
+
+ /* F_INT = mpu_xor_clk / DIV1 */
+ for (div1_idx = 0; div1_idx < 4; div1_idx++) {
+ switch (div1_idx) {
+ case 0:
+ div1 = 2;
+ break;
+ case 1:
+ div1 = 4;
+ break;
+ case 2:
+ div1 = 7;
+ break;
+ default:
+ case 3:
+ div1 = 10;
+ break;
+ }
+ div2 = (rate / div1 + hz - 1) / hz;
+ if (div2 <= 8)
+ break;
+ }
+ if (div1_idx == 4) {
+ pr_debug("%s: lowest clock %ld, need %d\n",
+ spi->dev.bus_id, rate / 10 / 8, hz);
+ status = -EDOM;
+ goto done;
+ }
+
+ /* we have to cache this and reset in uwire_chipselect as this is a
+ * global parameter and another uwire device can change it under
+ * us */
+ ust->div1_idx = div1_idx;
+ uwire_set_clk1_div(div1_idx);
+
+ rate /= div1;
+
+ switch (div2) {
+ case 0:
+ case 1:
+ case 2:
+ flags |= UWIRE_FREQ_DIV_2;
+ rate /= 2;
+ break;
+ case 3:
+ case 4:
+ flags |= UWIRE_FREQ_DIV_4;
+ rate /= 4;
+ break;
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ flags |= UWIRE_FREQ_DIV_8;
+ rate /= 8;
+ break;
+ }
+ omap_uwire_configure_mode(spi->chip_select, flags);
+ pr_debug("%s: uwire flags %02x, armxor %lu KHz, SCK %lu KHz\n",
+ __FUNCTION__, flags,
+ clk_get_rate(uwire->ck) / 1000,
+ rate / 1000);
+ status = 0;
+done:
+ return status;
+}
+
+static int uwire_setup(struct spi_device *spi)
+{
+ struct uwire_state *ust = spi->controller_state;
+
+ if (ust == NULL) {
+ ust = kzalloc(sizeof(*ust), GFP_KERNEL);
+ if (ust == NULL)
+ return -ENOMEM;
+ spi->controller_state = ust;
+ }
+
+ return uwire_setup_transfer(spi, NULL);
+}
+
+static void uwire_cleanup(struct spi_device *spi)
+{
+ kfree(spi->controller_state);
+}
+
+static void uwire_off(struct uwire_spi *uwire)
+{
+ uwire_write_reg(UWIRE_SR3, 0);
+ clk_disable(uwire->ck);
+ clk_put(uwire->ck);
+ spi_master_put(uwire->bitbang.master);
+}
+
+static int uwire_probe(struct platform_device *pdev)
+{
+ struct spi_master *master;
+ struct uwire_spi *uwire;
+ int status;
+
+ master = spi_alloc_master(&pdev->dev, sizeof *uwire);
+ if (!master)
+ return -ENODEV;
+
+ uwire = spi_master_get_devdata(master);
+ dev_set_drvdata(&pdev->dev, uwire);
+
+ uwire->ck = clk_get(&pdev->dev, "armxor_ck");
+ if (!uwire->ck || IS_ERR(uwire->ck)) {
+ dev_dbg(&pdev->dev, "no mpu_xor_clk ?\n");
+ spi_master_put(master);
+ return -ENODEV;
+ }
+ clk_enable(uwire->ck);
+
+ if (cpu_is_omap730())
+ uwire_idx_shift = 1;
+ else
+ uwire_idx_shift = 2;
+
+ uwire_write_reg(UWIRE_SR3, 1);
+
+ master->bus_num = 2; /* "official" */
+ master->num_chipselect = 4;
+ master->setup = uwire_setup;
+ master->cleanup = uwire_cleanup;
+
+ uwire->bitbang.master = master;
+ uwire->bitbang.chipselect = uwire_chipselect;
+ uwire->bitbang.setup_transfer = uwire_setup_transfer;
+ uwire->bitbang.txrx_bufs = uwire_txrx;
+
+ status = spi_bitbang_start(&uwire->bitbang);
+ if (status < 0)
+ uwire_off(uwire);
+ return status;
+}
+
+static int uwire_remove(struct platform_device *pdev)
+{
+ struct uwire_spi *uwire = dev_get_drvdata(&pdev->dev);
+ int status;
+
+ // FIXME remove all child devices, somewhere ...
+
+ status = spi_bitbang_stop(&uwire->bitbang);
+ uwire_off(uwire);
+ return status;
+}
+
+static struct platform_driver uwire_driver = {
+ .driver = {
+ .name = "omap_uwire",
+ .bus = &platform_bus_type,
+ .owner = THIS_MODULE,
+ },
+ .probe = uwire_probe,
+ .remove = uwire_remove,
+ // suspend ... unuse ck
+ // resume ... use ck
+};
+
+static int __init omap_uwire_init(void)
+{
+ /* FIXME move these into the relevant board init code. also, include
+ * H3 support; it uses tsc2101 like H2 (on a different chipselect).
+ */
+
+ if (machine_is_omap_h2()) {
+ /* defaults: W21 SDO, U18 SDI, V19 SCL */
+ omap_cfg_reg(N14_1610_UWIRE_CS0);
+ omap_cfg_reg(N15_1610_UWIRE_CS1);
+ }
+ if (machine_is_omap_perseus2()) {
+ /* configure pins: MPU_UW_nSCS1, MPU_UW_SDO, MPU_UW_SCLK */
+ int val = omap_readl(OMAP730_IO_CONF_9) & ~0x00EEE000;
+ omap_writel(val | 0x00AAA000, OMAP730_IO_CONF_9);
+ }
+
+ return platform_driver_register(&uwire_driver);
+}
+
+static void __exit omap_uwire_exit(void)
+{
+ platform_driver_unregister(&uwire_driver);
+}
+
+subsys_initcall(omap_uwire_init);
+module_exit(omap_uwire_exit);
+
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/spi/pxa2xx_spi.c b/drivers/spi/pxa2xx_spi.c
index 8b41f9cc256..9f2c887ffa0 100644
--- a/drivers/spi/pxa2xx_spi.c
+++ b/drivers/spi/pxa2xx_spi.c
@@ -1214,9 +1214,9 @@ static int setup(struct spi_device *spi)
return 0;
}
-static void cleanup(const struct spi_device *spi)
+static void cleanup(struct spi_device *spi)
{
- struct chip_data *chip = spi_get_ctldata((struct spi_device *)spi);
+ struct chip_data *chip = spi_get_ctldata(spi);
kfree(chip);
}
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 6307428d2c9..2328128728b 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -32,7 +32,7 @@
*/
static void spidev_release(struct device *dev)
{
- const struct spi_device *spi = to_spi_device(dev);
+ struct spi_device *spi = to_spi_device(dev);
/* spi masters may cleanup for released devices */
if (spi->master->cleanup)
diff --git a/drivers/spi/spi_bitbang.c b/drivers/spi/spi_bitbang.c
index 57289b61d0b..24a330d8239 100644
--- a/drivers/spi/spi_bitbang.c
+++ b/drivers/spi/spi_bitbang.c
@@ -210,7 +210,7 @@ int spi_bitbang_setup(struct spi_device *spi)
if (!cs->txrx_word)
return -EINVAL;
- retval = spi_bitbang_setup_transfer(spi, NULL);
+ retval = bitbang->setup_transfer(spi, NULL);
if (retval < 0)
return retval;
@@ -238,7 +238,7 @@ EXPORT_SYMBOL_GPL(spi_bitbang_setup);
/**
* spi_bitbang_cleanup - default cleanup for per-word I/O loops
*/
-void spi_bitbang_cleanup(const struct spi_device *spi)
+void spi_bitbang_cleanup(struct spi_device *spi)
{
kfree(spi->controller_state);
}
@@ -442,9 +442,10 @@ EXPORT_SYMBOL_GPL(spi_bitbang_transfer);
* hardware that basically exposes a shift register) or per-spi_transfer
* (which takes better advantage of hardware like fifos or DMA engines).
*
- * Drivers using per-word I/O loops should use (or call) spi_bitbang_setup and
- * spi_bitbang_cleanup to handle those spi master methods. Those methods are
- * the defaults if the bitbang->txrx_bufs routine isn't initialized.
+ * Drivers using per-word I/O loops should use (or call) spi_bitbang_setup,
+ * spi_bitbang_cleanup and spi_bitbang_setup_transfer to handle those spi
+ * master methods. Those methods are the defaults if the bitbang->txrx_bufs
+ * routine isn't initialized.
*
* This routine registers the spi_master, which will process requests in a
* dedicated task, keeping IRQs unblocked most of the time. To stop
diff --git a/drivers/spi/spi_imx.c b/drivers/spi/spi_imx.c
new file mode 100644
index 00000000000..51daa212c6b
--- /dev/null
+++ b/drivers/spi/spi_imx.c
@@ -0,0 +1,1768 @@
+/*
+ * drivers/spi/spi_imx.c
+ *
+ * Copyright (C) 2006 SWAPP
+ * Andrea Paterniani <a.paterniani@swapp-eng.it>
+ *
+ * Initial version inspired by:
+ * linux-2.6.17-rc3-mm1/drivers/spi/pxa2xx_spi.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/ioport.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/spi/spi.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/hardware.h>
+#include <asm/delay.h>
+
+#include <asm/arch/hardware.h>
+#include <asm/arch/imx-dma.h>
+#include <asm/arch/spi_imx.h>
+
+/*-------------------------------------------------------------------------*/
+/* SPI Registers offsets from peripheral base address */
+#define SPI_RXDATA (0x00)
+#define SPI_TXDATA (0x04)
+#define SPI_CONTROL (0x08)
+#define SPI_INT_STATUS (0x0C)
+#define SPI_TEST (0x10)
+#define SPI_PERIOD (0x14)
+#define SPI_DMA (0x18)
+#define SPI_RESET (0x1C)
+
+/* SPI Control Register Bit Fields & Masks */
+#define SPI_CONTROL_BITCOUNT_MASK (0xF) /* Bit Count Mask */
+#define SPI_CONTROL_BITCOUNT(n) (((n) - 1) & SPI_CONTROL_BITCOUNT_MASK)
+#define SPI_CONTROL_POL (0x1 << 4) /* Clock Polarity Mask */
+#define SPI_CONTROL_POL_ACT_HIGH (0x0 << 4) /* Active high pol. (0=idle) */
+#define SPI_CONTROL_POL_ACT_LOW (0x1 << 4) /* Active low pol. (1=idle) */
+#define SPI_CONTROL_PHA (0x1 << 5) /* Clock Phase Mask */
+#define SPI_CONTROL_PHA_0 (0x0 << 5) /* Clock Phase 0 */
+#define SPI_CONTROL_PHA_1 (0x1 << 5) /* Clock Phase 1 */
+#define SPI_CONTROL_SSCTL (0x1 << 6) /* /SS Waveform Select Mask */
+#define SPI_CONTROL_SSCTL_0 (0x0 << 6) /* Master: /SS stays low between SPI burst
+ Slave: RXFIFO advanced by BIT_COUNT */
+#define SPI_CONTROL_SSCTL_1 (0x1 << 6) /* Master: /SS insert pulse between SPI burst
+ Slave: RXFIFO advanced by /SS rising edge */
+#define SPI_CONTROL_SSPOL (0x1 << 7) /* /SS Polarity Select Mask */
+#define SPI_CONTROL_SSPOL_ACT_LOW (0x0 << 7) /* /SS Active low */
+#define SPI_CONTROL_SSPOL_ACT_HIGH (0x1 << 7) /* /SS Active high */
+#define SPI_CONTROL_XCH (0x1 << 8) /* Exchange */
+#define SPI_CONTROL_SPIEN (0x1 << 9) /* SPI Module Enable */
+#define SPI_CONTROL_MODE (0x1 << 10) /* SPI Mode Select Mask */
+#define SPI_CONTROL_MODE_SLAVE (0x0 << 10) /* SPI Mode Slave */
+#define SPI_CONTROL_MODE_MASTER (0x1 << 10) /* SPI Mode Master */
+#define SPI_CONTROL_DRCTL (0x3 << 11) /* /SPI_RDY Control Mask */
+#define SPI_CONTROL_DRCTL_0 (0x0 << 11) /* Ignore /SPI_RDY */
+#define SPI_CONTROL_DRCTL_1 (0x1 << 11) /* /SPI_RDY falling edge triggers input */
+#define SPI_CONTROL_DRCTL_2 (0x2 << 11) /* /SPI_RDY active low level triggers input */
+#define SPI_CONTROL_DATARATE (0x7 << 13) /* Data Rate Mask */
+#define SPI_PERCLK2_DIV_MIN (0) /* PERCLK2:4 */
+#define SPI_PERCLK2_DIV_MAX (7) /* PERCLK2:512 */
+#define SPI_CONTROL_DATARATE_MIN (SPI_PERCLK2_DIV_MAX << 13)
+#define SPI_CONTROL_DATARATE_MAX (SPI_PERCLK2_DIV_MIN << 13)
+#define SPI_CONTROL_DATARATE_BAD (SPI_CONTROL_DATARATE_MIN + 1)
+
+/* SPI Interrupt/Status Register Bit Fields & Masks */
+#define SPI_STATUS_TE (0x1 << 0) /* TXFIFO Empty Status */
+#define SPI_STATUS_TH (0x1 << 1) /* TXFIFO Half Status */
+#define SPI_STATUS_TF (0x1 << 2) /* TXFIFO Full Status */
+#define SPI_STATUS_RR (0x1 << 3) /* RXFIFO Data Ready Status */
+#define SPI_STATUS_RH (0x1 << 4) /* RXFIFO Half Status */
+#define SPI_STATUS_RF (0x1 << 5) /* RXFIFO Full Status */
+#define SPI_STATUS_RO (0x1 << 6) /* RXFIFO Overflow */
+#define SPI_STATUS_BO (0x1 << 7) /* Bit Count Overflow */
+#define SPI_STATUS (0xFF) /* SPI Status Mask */
+#define SPI_INTEN_TE (0x1 << 8) /* TXFIFO Empty Interrupt Enable */
+#define SPI_INTEN_TH (0x1 << 9) /* TXFIFO Half Interrupt Enable */
+#define SPI_INTEN_TF (0x1 << 10) /* TXFIFO Full Interrupt Enable */
+#define SPI_INTEN_RE (0x1 << 11) /* RXFIFO Data Ready Interrupt Enable */
+#define SPI_INTEN_RH (0x1 << 12) /* RXFIFO Half Interrupt Enable */
+#define SPI_INTEN_RF (0x1 << 13) /* RXFIFO Full Interrupt Enable */
+#define SPI_INTEN_RO (0x1 << 14) /* RXFIFO Overflow Interrupt Enable */
+#define SPI_INTEN_BO (0x1 << 15) /* Bit Count Overflow Interrupt Enable */
+#define SPI_INTEN (0xFF << 8) /* SPI Interrupt Enable Mask */
+
+/* SPI Test Register Bit Fields & Masks */
+#define SPI_TEST_TXCNT (0xF << 0) /* TXFIFO Counter */
+#define SPI_TEST_RXCNT_LSB (4) /* RXFIFO Counter LSB */
+#define SPI_TEST_RXCNT (0xF << 4) /* RXFIFO Counter */
+#define SPI_TEST_SSTATUS (0xF << 8) /* State Machine Status */
+#define SPI_TEST_LBC (0x1 << 14) /* Loop Back Control */
+
+/* SPI Period Register Bit Fields & Masks */
+#define SPI_PERIOD_WAIT (0x7FFF << 0) /* Wait Between Transactions */
+#define SPI_PERIOD_MAX_WAIT (0x7FFF) /* Max Wait Between
+ Transactions */
+#define SPI_PERIOD_CSRC (0x1 << 15) /* Period Clock Source Mask */
+#define SPI_PERIOD_CSRC_BCLK (0x0 << 15) /* Period Clock Source is
+ Bit Clock */
+#define SPI_PERIOD_CSRC_32768 (0x1 << 15) /* Period Clock Source is
+ 32.768 KHz Clock */
+
+/* SPI DMA Register Bit Fields & Masks */
+#define SPI_DMA_RHDMA (0xF << 4) /* RXFIFO Half Status */
+#define SPI_DMA_RFDMA (0x1 << 5) /* RXFIFO Full Status */
+#define SPI_DMA_TEDMA (0x1 << 6) /* TXFIFO Empty Status */
+#define SPI_DMA_THDMA (0x1 << 7) /* TXFIFO Half Status */
+#define SPI_DMA_RHDEN (0x1 << 12) /* RXFIFO Half DMA Request Enable */
+#define SPI_DMA_RFDEN (0x1 << 13) /* RXFIFO Full DMA Request Enable */
+#define SPI_DMA_TEDEN (0x1 << 14) /* TXFIFO Empty DMA Request Enable */
+#define SPI_DMA_THDEN (0x1 << 15) /* TXFIFO Half DMA Request Enable */
+
+/* SPI Soft Reset Register Bit Fields & Masks */
+#define SPI_RESET_START (0x1) /* Start */
+
+/* Default SPI configuration values */
+#define SPI_DEFAULT_CONTROL \
+( \
+ SPI_CONTROL_BITCOUNT(16) | \
+ SPI_CONTROL_POL_ACT_HIGH | \
+ SPI_CONTROL_PHA_0 | \
+ SPI_CONTROL_SPIEN | \
+ SPI_CONTROL_SSCTL_1 | \
+ SPI_CONTROL_MODE_MASTER | \
+ SPI_CONTROL_DRCTL_0 | \
+ SPI_CONTROL_DATARATE_MIN \
+)
+#define SPI_DEFAULT_ENABLE_LOOPBACK (0)
+#define SPI_DEFAULT_ENABLE_DMA (0)
+#define SPI_DEFAULT_PERIOD_WAIT (8)
+/*-------------------------------------------------------------------------*/
+
+
+/*-------------------------------------------------------------------------*/
+/* TX/RX SPI FIFO size */
+#define SPI_FIFO_DEPTH (8)
+#define SPI_FIFO_BYTE_WIDTH (2)
+#define SPI_FIFO_OVERFLOW_MARGIN (2)
+
+/* DMA burst lenght for half full/empty request trigger */
+#define SPI_DMA_BLR (SPI_FIFO_DEPTH * SPI_FIFO_BYTE_WIDTH / 2)
+
+/* Dummy char output to achieve reads.
+ Choosing something different from all zeroes may help pattern recogition
+ for oscilloscope analysis, but may break some drivers. */
+#define SPI_DUMMY_u8 0
+#define SPI_DUMMY_u16 ((SPI_DUMMY_u8 << 8) | SPI_DUMMY_u8)
+#define SPI_DUMMY_u32 ((SPI_DUMMY_u16 << 16) | SPI_DUMMY_u16)
+
+/**
+ * Macro to change a u32 field:
+ * @r : register to edit
+ * @m : bit mask
+ * @v : new value for the field correctly bit-alligned
+*/
+#define u32_EDIT(r, m, v) r = (r & ~(m)) | (v)
+
+/* Message state */
+#define START_STATE ((void*)0)
+#define RUNNING_STATE ((void*)1)
+#define DONE_STATE ((void*)2)
+#define ERROR_STATE ((void*)-1)
+
+/* Queue state */
+#define QUEUE_RUNNING (0)
+#define QUEUE_STOPPED (1)
+
+#define IS_DMA_ALIGNED(x) (((u32)(x) & 0x03) == 0)
+/*-------------------------------------------------------------------------*/
+
+
+/*-------------------------------------------------------------------------*/
+/* Driver data structs */
+
+/* Context */
+struct driver_data {
+ /* Driver model hookup */
+ struct platform_device *pdev;
+
+ /* SPI framework hookup */
+ struct spi_master *master;
+
+ /* IMX hookup */
+ struct spi_imx_master *master_info;
+
+ /* Memory resources and SPI regs virtual address */
+ struct resource *ioarea;
+ void __iomem *regs;
+
+ /* SPI RX_DATA physical address */
+ dma_addr_t rd_data_phys;
+
+ /* Driver message queue */
+ struct workqueue_struct *workqueue;
+ struct work_struct work;
+ spinlock_t lock;
+ struct list_head queue;
+ int busy;
+ int run;
+
+ /* Message Transfer pump */
+ struct tasklet_struct pump_transfers;
+
+ /* Current message, transfer and state */
+ struct spi_message *cur_msg;
+ struct spi_transfer *cur_transfer;
+ struct chip_data *cur_chip;
+
+ /* Rd / Wr buffers pointers */
+ size_t len;
+ void *tx;
+ void *tx_end;
+ void *rx;
+ void *rx_end;
+
+ u8 rd_only;
+ u8 n_bytes;
+ int cs_change;
+
+ /* Function pointers */
+ irqreturn_t (*transfer_handler)(struct driver_data *drv_data);
+ void (*cs_control)(u32 command);
+
+ /* DMA setup */
+ int rx_channel;
+ int tx_channel;
+ dma_addr_t rx_dma;
+ dma_addr_t tx_dma;
+ int rx_dma_needs_unmap;
+ int tx_dma_needs_unmap;
+ size_t tx_map_len;
+ u32 dummy_dma_buf ____cacheline_aligned;
+};
+
+/* Runtime state */
+struct chip_data {
+ u32 control;
+ u32 period;
+ u32 test;
+
+ u8 enable_dma:1;
+ u8 bits_per_word;
+ u8 n_bytes;
+ u32 max_speed_hz;
+
+ void (*cs_control)(u32 command);
+};
+/*-------------------------------------------------------------------------*/
+
+
+static void pump_messages(struct work_struct *work);
+
+static int flush(struct driver_data *drv_data)
+{
+ unsigned long limit = loops_per_jiffy << 1;
+ void __iomem *regs = drv_data->regs;
+ volatile u32 d;
+
+ dev_dbg(&drv_data->pdev->dev, "flush\n");
+ do {
+ while (readl(regs + SPI_INT_STATUS) & SPI_STATUS_RR)
+ d = readl(regs + SPI_RXDATA);
+ } while ((readl(regs + SPI_CONTROL) & SPI_CONTROL_XCH) && limit--);
+
+ return limit;
+}
+
+static void restore_state(struct driver_data *drv_data)
+{
+ void __iomem *regs = drv_data->regs;
+ struct chip_data *chip = drv_data->cur_chip;
+
+ /* Load chip registers */
+ dev_dbg(&drv_data->pdev->dev,
+ "restore_state\n"
+ " test = 0x%08X\n"
+ " control = 0x%08X\n",
+ chip->test,
+ chip->control);
+ writel(chip->test, regs + SPI_TEST);
+ writel(chip->period, regs + SPI_PERIOD);
+ writel(0, regs + SPI_INT_STATUS);
+ writel(chip->control, regs + SPI_CONTROL);
+}
+
+static void null_cs_control(u32 command)
+{
+}
+
+static inline u32 data_to_write(struct driver_data *drv_data)
+{
+ return ((u32)(drv_data->tx_end - drv_data->tx)) / drv_data->n_bytes;
+}
+
+static inline u32 data_to_read(struct driver_data *drv_data)
+{
+ return ((u32)(drv_data->rx_end - drv_data->rx)) / drv_data->n_bytes;
+}
+
+static int write(struct driver_data *drv_data)
+{
+ void __iomem *regs = drv_data->regs;
+ void *tx = drv_data->tx;
+ void *tx_end = drv_data->tx_end;
+ u8 n_bytes = drv_data->n_bytes;
+ u32 remaining_writes;
+ u32 fifo_avail_space;
+ u32 n;
+ u16 d;
+
+ /* Compute how many fifo writes to do */
+ remaining_writes = (u32)(tx_end - tx) / n_bytes;
+ fifo_avail_space = SPI_FIFO_DEPTH -
+ (readl(regs + SPI_TEST) & SPI_TEST_TXCNT);
+ if (drv_data->rx && (fifo_avail_space > SPI_FIFO_OVERFLOW_MARGIN))
+ /* Fix misunderstood receive overflow */
+ fifo_avail_space -= SPI_FIFO_OVERFLOW_MARGIN;
+ n = min(remaining_writes, fifo_avail_space);
+
+ dev_dbg(&drv_data->pdev->dev,
+ "write type %s\n"
+ " remaining writes = %d\n"
+ " fifo avail space = %d\n"
+ " fifo writes = %d\n",
+ (n_bytes == 1) ? "u8" : "u16",
+ remaining_writes,
+ fifo_avail_space,
+ n);
+
+ if (n > 0) {
+ /* Fill SPI TXFIFO */
+ if (drv_data->rd_only) {
+ tx += n * n_bytes;
+ while (n--)
+ writel(SPI_DUMMY_u16, regs + SPI_TXDATA);
+ } else {
+ if (n_bytes == 1) {
+ while (n--) {
+ d = *(u8*)tx;
+ writel(d, regs + SPI_TXDATA);
+ tx += 1;
+ }
+ } else {
+ while (n--) {
+ d = *(u16*)tx;
+ writel(d, regs + SPI_TXDATA);
+ tx += 2;
+ }
+ }
+ }
+
+ /* Trigger transfer */
+ writel(readl(regs + SPI_CONTROL) | SPI_CONTROL_XCH,
+ regs + SPI_CONTROL);
+
+ /* Update tx pointer */
+ drv_data->tx = tx;
+ }
+
+ return (tx >= tx_end);
+}
+
+static int read(struct driver_data *drv_data)
+{
+ void __iomem *regs = drv_data->regs;
+ void *rx = drv_data->rx;
+ void *rx_end = drv_data->rx_end;
+ u8 n_bytes = drv_data->n_bytes;
+ u32 remaining_reads;
+ u32 fifo_rxcnt;
+ u32 n;
+ u16 d;
+
+ /* Compute how many fifo reads to do */
+ remaining_reads = (u32)(rx_end - rx) / n_bytes;
+ fifo_rxcnt = (readl(regs + SPI_TEST) & SPI_TEST_RXCNT) >>
+ SPI_TEST_RXCNT_LSB;
+ n = min(remaining_reads, fifo_rxcnt);
+
+ dev_dbg(&drv_data->pdev->dev,
+ "read type %s\n"
+ " remaining reads = %d\n"
+ " fifo rx count = %d\n"
+ " fifo reads = %d\n",
+ (n_bytes == 1) ? "u8" : "u16",
+ remaining_reads,
+ fifo_rxcnt,
+ n);
+
+ if (n > 0) {
+ /* Read SPI RXFIFO */
+ if (n_bytes == 1) {
+ while (n--) {
+ d = readl(regs + SPI_RXDATA);
+ *((u8*)rx) = d;
+ rx += 1;
+ }
+ } else {
+ while (n--) {
+ d = readl(regs + SPI_RXDATA);
+ *((u16*)rx) = d;
+ rx += 2;
+ }
+ }
+
+ /* Update rx pointer */
+ drv_data->rx = rx;
+ }
+
+ return (rx >= rx_end);
+}
+
+static void *next_transfer(struct driver_data *drv_data)
+{
+ struct spi_message *msg = drv_data->cur_msg;
+ struct spi_transfer *trans = drv_data->cur_transfer;
+
+ /* Move to next transfer */
+ if (trans->transfer_list.next != &msg->transfers) {
+ drv_data->cur_transfer =
+ list_entry(trans->transfer_list.next,
+ struct spi_transfer,
+ transfer_list);
+ return RUNNING_STATE;
+ }
+
+ return DONE_STATE;
+}
+
+static int map_dma_buffers(struct driver_data *drv_data)
+{
+ struct spi_message *msg;
+ struct device *dev;
+ void *buf;
+
+ drv_data->rx_dma_needs_unmap = 0;
+ drv_data->tx_dma_needs_unmap = 0;
+
+ if (!drv_data->master_info->enable_dma ||
+ !drv_data->cur_chip->enable_dma)
+ return -1;
+
+ msg = drv_data->cur_msg;
+ dev = &msg->spi->dev;
+ if (msg->is_dma_mapped) {
+ if (drv_data->tx_dma)
+ /* The caller provided at least dma and cpu virtual
+ address for write; pump_transfers() will consider the
+ transfer as write only if cpu rx virtual address is
+ NULL */
+ return 0;
+
+ if (drv_data->rx_dma) {
+ /* The caller provided dma and cpu virtual address to
+ performe read only transfer -->
+ use drv_data->dummy_dma_buf for dummy writes to
+ achive reads */
+ buf = &drv_data->dummy_dma_buf;
+ drv_data->tx_map_len = sizeof(drv_data->dummy_dma_buf);
+ drv_data->tx_dma = dma_map_single(dev,
+ buf,
+ drv_data->tx_map_len,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(drv_data->tx_dma))
+ return -1;
+
+ drv_data->tx_dma_needs_unmap = 1;
+
+ /* Flags transfer as rd_only for pump_transfers() DMA
+ regs programming (should be redundant) */
+ drv_data->tx = NULL;
+
+ return 0;
+ }
+ }
+
+ if (!IS_DMA_ALIGNED(drv_data->rx) || !IS_DMA_ALIGNED(drv_data->tx))
+ return -1;
+
+ /* NULL rx means write-only transfer and no map needed
+ since rx DMA will not be used */
+ if (drv_data->rx) {
+ buf = drv_data->rx;
+ drv_data->rx_dma = dma_map_single(
+ dev,
+ buf,
+ drv_data->len,
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(drv_data->rx_dma))
+ return -1;
+ drv_data->rx_dma_needs_unmap = 1;
+ }
+
+ if (drv_data->tx == NULL) {
+ /* Read only message --> use drv_data->dummy_dma_buf for dummy
+ writes to achive reads */
+ buf = &drv_data->dummy_dma_buf;
+ drv_data->tx_map_len = sizeof(drv_data->dummy_dma_buf);
+ } else {
+ buf = drv_data->tx;
+ drv_data->tx_map_len = drv_data->len;
+ }
+ drv_data->tx_dma = dma_map_single(dev,
+ buf,
+ drv_data->tx_map_len,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(drv_data->tx_dma)) {
+ if (drv_data->rx_dma) {
+ dma_unmap_single(dev,
+ drv_data->rx_dma,
+ drv_data->len,
+ DMA_FROM_DEVICE);
+ drv_data->rx_dma_needs_unmap = 0;
+ }
+ return -1;
+ }
+ drv_data->tx_dma_needs_unmap = 1;
+
+ return 0;
+}
+
+static void unmap_dma_buffers(struct driver_data *drv_data)
+{
+ struct spi_message *msg = drv_data->cur_msg;
+ struct device *dev = &msg->spi->dev;
+
+ if (drv_data->rx_dma_needs_unmap) {
+ dma_unmap_single(dev,
+ drv_data->rx_dma,
+ drv_data->len,
+ DMA_FROM_DEVICE);
+ drv_data->rx_dma_needs_unmap = 0;
+ }
+ if (drv_data->tx_dma_needs_unmap) {
+ dma_unmap_single(dev,
+ drv_data->tx_dma,
+ drv_data->tx_map_len,
+ DMA_TO_DEVICE);
+ drv_data->tx_dma_needs_unmap = 0;
+ }
+}
+
+/* Caller already set message->status (dma is already blocked) */
+static void giveback(struct spi_message *message, struct driver_data *drv_data)
+{
+ void __iomem *regs = drv_data->regs;
+
+ /* Bring SPI to sleep; restore_state() and pump_transfer()
+ will do new setup */
+ writel(0, regs + SPI_INT_STATUS);
+ writel(0, regs + SPI_DMA);
+
+ drv_data->cs_control(SPI_CS_DEASSERT);
+
+ message->state = NULL;
+ if (message->complete)
+ message->complete(message->context);
+
+ drv_data->cur_msg = NULL;
+ drv_data->cur_transfer = NULL;
+ drv_data->cur_chip = NULL;
+ queue_work(drv_data->workqueue, &drv_data->work);
+}
+
+static void dma_err_handler(int channel, void *data, int errcode)
+{
+ struct driver_data *drv_data = data;
+ struct spi_message *msg = drv_data->cur_msg;
+
+ dev_dbg(&drv_data->pdev->dev, "dma_err_handler\n");
+
+ /* Disable both rx and tx dma channels */
+ imx_dma_disable(drv_data->rx_channel);
+ imx_dma_disable(drv_data->tx_channel);
+
+ if (flush(drv_data) == 0)
+ dev_err(&drv_data->pdev->dev,
+ "dma_err_handler - flush failed\n");
+
+ unmap_dma_buffers(drv_data);
+
+ msg->state = ERROR_STATE;
+ tasklet_schedule(&drv_data->pump_transfers);
+}
+
+static void dma_tx_handler(int channel, void *data)
+{
+ struct driver_data *drv_data = data;
+
+ dev_dbg(&drv_data->pdev->dev, "dma_tx_handler\n");
+
+ imx_dma_disable(channel);
+
+ /* Now waits for TX FIFO empty */
+ writel(readl(drv_data->regs + SPI_INT_STATUS) | SPI_INTEN_TE,
+ drv_data->regs + SPI_INT_STATUS);
+}
+
+static irqreturn_t dma_transfer(struct driver_data *drv_data)
+{
+ u32 status;
+ struct spi_message *msg = drv_data->cur_msg;
+ void __iomem *regs = drv_data->regs;
+ unsigned long limit;
+
+ status = readl(regs + SPI_INT_STATUS);
+
+ if ((status & SPI_INTEN_RO) && (status & SPI_STATUS_RO)) {
+ writel(status & ~SPI_INTEN, regs + SPI_INT_STATUS);
+
+ imx_dma_disable(drv_data->rx_channel);
+ unmap_dma_buffers(drv_data);
+
+ if (flush(drv_data) == 0)
+ dev_err(&drv_data->pdev->dev,
+ "dma_transfer - flush failed\n");
+
+ dev_warn(&drv_data->pdev->dev,
+ "dma_transfer - fifo overun\n");
+
+ msg->state = ERROR_STATE;
+ tasklet_schedule(&drv_data->pump_transfers);
+
+ return IRQ_HANDLED;
+ }
+
+ if (status & SPI_STATUS_TE) {
+ writel(status & ~SPI_INTEN_TE, regs + SPI_INT_STATUS);
+
+ if (drv_data->rx) {
+ /* Wait end of transfer before read trailing data */
+ limit = loops_per_jiffy << 1;
+ while ((readl(regs + SPI_CONTROL) & SPI_CONTROL_XCH) &&
+ limit--);
+
+ if (limit == 0)
+ dev_err(&drv_data->pdev->dev,
+ "dma_transfer - end of tx failed\n");
+ else
+ dev_dbg(&drv_data->pdev->dev,
+ "dma_transfer - end of tx\n");
+
+ imx_dma_disable(drv_data->rx_channel);
+ unmap_dma_buffers(drv_data);
+
+ /* Calculate number of trailing data and read them */
+ dev_dbg(&drv_data->pdev->dev,
+ "dma_transfer - test = 0x%08X\n",
+ readl(regs + SPI_TEST));
+ drv_data->rx = drv_data->rx_end -
+ ((readl(regs + SPI_TEST) &
+ SPI_TEST_RXCNT) >>
+ SPI_TEST_RXCNT_LSB)*drv_data->n_bytes;
+ read(drv_data);
+ } else {
+ /* Write only transfer */
+ unmap_dma_buffers(drv_data);
+
+ if (flush(drv_data) == 0)
+ dev_err(&drv_data->pdev->dev,
+ "dma_transfer - flush failed\n");
+ }
+
+ /* End of transfer, update total byte transfered */
+ msg->actual_length += drv_data->len;
+
+ /* Release chip select if requested, transfer delays are
+ handled in pump_transfers() */
+ if (drv_data->cs_change)
+ drv_data->cs_control(SPI_CS_DEASSERT);
+
+ /* Move to next transfer */
+ msg->state = next_transfer(drv_data);
+
+ /* Schedule transfer tasklet */
+ tasklet_schedule(&drv_data->pump_transfers);
+
+ return IRQ_HANDLED;
+ }
+
+ /* Opps problem detected */
+ return IRQ_NONE;
+}
+
+static irqreturn_t interrupt_wronly_transfer(struct driver_data *drv_data)
+{
+ struct spi_message *msg = drv_data->cur_msg;
+ void __iomem *regs = drv_data->regs;
+ u32 status;
+ irqreturn_t handled = IRQ_NONE;
+
+ status = readl(regs + SPI_INT_STATUS);
+
+ while (status & SPI_STATUS_TH) {
+ dev_dbg(&drv_data->pdev->dev,
+ "interrupt_wronly_transfer - status = 0x%08X\n", status);
+
+ /* Pump data */
+ if (write(drv_data)) {
+ writel(readl(regs + SPI_INT_STATUS) & ~SPI_INTEN,
+ regs + SPI_INT_STATUS);
+
+ dev_dbg(&drv_data->pdev->dev,
+ "interrupt_wronly_transfer - end of tx\n");
+
+ if (flush(drv_data) == 0)
+ dev_err(&drv_data->pdev->dev,
+ "interrupt_wronly_transfer - "
+ "flush failed\n");
+
+ /* End of transfer, update total byte transfered */
+ msg->actual_length += drv_data->len;
+
+ /* Release chip select if requested, transfer delays are
+ handled in pump_transfers */
+ if (drv_data->cs_change)
+ drv_data->cs_control(SPI_CS_DEASSERT);
+
+ /* Move to next transfer */
+ msg->state = next_transfer(drv_data);
+
+ /* Schedule transfer tasklet */
+ tasklet_schedule(&drv_data->pump_transfers);
+
+ return IRQ_HANDLED;
+ }
+
+ status = readl(regs + SPI_INT_STATUS);
+
+ /* We did something */
+ handled = IRQ_HANDLED;
+ }
+
+ return handled;
+}
+
+static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
+{
+ struct spi_message *msg = drv_data->cur_msg;
+ void __iomem *regs = drv_data->regs;
+ u32 status;
+ irqreturn_t handled = IRQ_NONE;
+ unsigned long limit;
+
+ status = readl(regs + SPI_INT_STATUS);
+
+ while (status & (SPI_STATUS_TH | SPI_STATUS_RO)) {
+ dev_dbg(&drv_data->pdev->dev,
+ "interrupt_transfer - status = 0x%08X\n", status);
+
+ if (status & SPI_STATUS_RO) {
+ writel(readl(regs + SPI_INT_STATUS) & ~SPI_INTEN,
+ regs + SPI_INT_STATUS);
+
+ dev_warn(&drv_data->pdev->dev,
+ "interrupt_transfer - fifo overun\n"
+ " data not yet written = %d\n"
+ " data not yet read = %d\n",
+ data_to_write(drv_data),
+ data_to_read(drv_data));
+
+ if (flush(drv_data) == 0)
+ dev_err(&drv_data->pdev->dev,
+ "interrupt_transfer - flush failed\n");
+
+ msg->state = ERROR_STATE;
+ tasklet_schedule(&drv_data->pump_transfers);
+
+ return IRQ_HANDLED;
+ }
+
+ /* Pump data */
+ read(drv_data);
+ if (write(drv_data)) {
+ writel(readl(regs + SPI_INT_STATUS) & ~SPI_INTEN,
+ regs + SPI_INT_STATUS);
+
+ dev_dbg(&drv_data->pdev->dev,
+ "interrupt_transfer - end of tx\n");
+
+ /* Read trailing bytes */
+ limit = loops_per_jiffy << 1;
+ while ((read(drv_data) == 0) && limit--);
+
+ if (limit == 0)
+ dev_err(&drv_data->pdev->dev,
+ "interrupt_transfer - "
+ "trailing byte read failed\n");
+ else
+ dev_dbg(&drv_data->pdev->dev,
+ "interrupt_transfer - end of rx\n");
+
+ /* End of transfer, update total byte transfered */
+ msg->actual_length += drv_data->len;
+
+ /* Release chip select if requested, transfer delays are
+ handled in pump_transfers */
+ if (drv_data->cs_change)
+ drv_data->cs_control(SPI_CS_DEASSERT);
+
+ /* Move to next transfer */
+ msg->state = next_transfer(drv_data);
+
+ /* Schedule transfer tasklet */
+ tasklet_schedule(&drv_data->pump_transfers);
+
+ return IRQ_HANDLED;
+ }
+
+ status = readl(regs + SPI_INT_STATUS);
+
+ /* We did something */
+ handled = IRQ_HANDLED;
+ }
+
+ return handled;
+}
+
+static irqreturn_t spi_int(int irq, void *dev_id)
+{
+ struct driver_data *drv_data = (struct driver_data *)dev_id;
+
+ if (!drv_data->cur_msg) {
+ dev_err(&drv_data->pdev->dev,
+ "spi_int - bad message state\n");
+ /* Never fail */
+ return IRQ_HANDLED;
+ }
+
+ return drv_data->transfer_handler(drv_data);
+}
+
+static inline u32 spi_speed_hz(u32 data_rate)
+{
+ return imx_get_perclk2() / (4 << ((data_rate) >> 13));
+}
+
+static u32 spi_data_rate(u32 speed_hz)
+{
+ u32 div;
+ u32 quantized_hz = imx_get_perclk2() >> 2;
+
+ for (div = SPI_PERCLK2_DIV_MIN;
+ div <= SPI_PERCLK2_DIV_MAX;
+ div++, quantized_hz >>= 1) {
+ if (quantized_hz <= speed_hz)
+ /* Max available speed LEQ required speed */
+ return div << 13;
+ }
+ return SPI_CONTROL_DATARATE_BAD;
+}
+
+static void pump_transfers(unsigned long data)
+{
+ struct driver_data *drv_data = (struct driver_data *)data;
+ struct spi_message *message;
+ struct spi_transfer *transfer, *previous;
+ struct chip_data *chip;
+ void __iomem *regs;
+ u32 tmp, control;
+
+ dev_dbg(&drv_data->pdev->dev, "pump_transfer\n");
+
+ message = drv_data->cur_msg;
+
+ /* Handle for abort */
+ if (message->state == ERROR_STATE) {
+ message->status = -EIO;
+ giveback(message, drv_data);
+ return;
+ }
+
+ /* Handle end of message */
+ if (message->state == DONE_STATE) {
+ message->status = 0;
+ giveback(message, drv_data);
+ return;
+ }
+
+ chip = drv_data->cur_chip;
+
+ /* Delay if requested at end of transfer*/
+ transfer = drv_data->cur_transfer;
+ if (message->state == RUNNING_STATE) {
+ previous = list_entry(transfer->transfer_list.prev,
+ struct spi_transfer,
+ transfer_list);
+ if (previous->delay_usecs)
+ udelay(previous->delay_usecs);
+ } else {
+ /* START_STATE */
+ message->state = RUNNING_STATE;
+ drv_data->cs_control = chip->cs_control;
+ }
+
+ transfer = drv_data->cur_transfer;
+ drv_data->tx = (void *)transfer->tx_buf;
+ drv_data->tx_end = drv_data->tx + transfer->len;
+ drv_data->rx = transfer->rx_buf;
+ drv_data->rx_end = drv_data->rx + transfer->len;
+ drv_data->rx_dma = transfer->rx_dma;
+ drv_data->tx_dma = transfer->tx_dma;
+ drv_data->len = transfer->len;
+ drv_data->cs_change = transfer->cs_change;
+ drv_data->rd_only = (drv_data->tx == NULL);
+
+ regs = drv_data->regs;
+ control = readl(regs + SPI_CONTROL);
+
+ /* Bits per word setup */
+ tmp = transfer->bits_per_word;
+ if (tmp == 0) {
+ /* Use device setup */
+ tmp = chip->bits_per_word;
+ drv_data->n_bytes = chip->n_bytes;
+ } else
+ /* Use per-transfer setup */
+ drv_data->n_bytes = (tmp <= 8) ? 1 : 2;
+ u32_EDIT(control, SPI_CONTROL_BITCOUNT_MASK, tmp - 1);
+
+ /* Speed setup (surely valid because already checked) */
+ tmp = transfer->speed_hz;
+ if (tmp == 0)
+ tmp = chip->max_speed_hz;
+ tmp = spi_data_rate(tmp);
+ u32_EDIT(control, SPI_CONTROL_DATARATE, tmp);
+
+ writel(control, regs + SPI_CONTROL);
+
+ /* Assert device chip-select */
+ drv_data->cs_control(SPI_CS_ASSERT);
+
+ /* DMA cannot read/write SPI FIFOs other than 16 bits at a time; hence
+ if bits_per_word is less or equal 8 PIO transfers are performed.
+ Moreover DMA is convinient for transfer length bigger than FIFOs
+ byte size. */
+ if ((drv_data->n_bytes == 2) &&
+ (drv_data->len > SPI_FIFO_DEPTH*SPI_FIFO_BYTE_WIDTH) &&
+ (map_dma_buffers(drv_data) == 0)) {
+ dev_dbg(&drv_data->pdev->dev,
+ "pump dma transfer\n"
+ " tx = %p\n"
+ " tx_dma = %08X\n"
+ " rx = %p\n"
+ " rx_dma = %08X\n"
+ " len = %d\n",
+ drv_data->tx,
+ (unsigned int)drv_data->tx_dma,
+ drv_data->rx,
+ (unsigned int)drv_data->rx_dma,
+ drv_data->len);
+
+ /* Ensure we have the correct interrupt handler */
+ drv_data->transfer_handler = dma_transfer;
+
+ /* Trigger transfer */
+ writel(readl(regs + SPI_CONTROL) | SPI_CONTROL_XCH,
+ regs + SPI_CONTROL);
+
+ /* Setup tx DMA */
+ if (drv_data->tx)
+ /* Linear source address */
+ CCR(drv_data->tx_channel) =
+ CCR_DMOD_FIFO |
+ CCR_SMOD_LINEAR |
+ CCR_SSIZ_32 | CCR_DSIZ_16 |
+ CCR_REN;
+ else
+ /* Read only transfer -> fixed source address for
+ dummy write to achive read */
+ CCR(drv_data->tx_channel) =
+ CCR_DMOD_FIFO |
+ CCR_SMOD_FIFO |
+ CCR_SSIZ_32 | CCR_DSIZ_16 |
+ CCR_REN;
+
+ imx_dma_setup_single(
+ drv_data->tx_channel,
+ drv_data->tx_dma,
+ drv_data->len,
+ drv_data->rd_data_phys + 4,
+ DMA_MODE_WRITE);
+
+ if (drv_data->rx) {
+ /* Setup rx DMA for linear destination address */
+ CCR(drv_data->rx_channel) =
+ CCR_DMOD_LINEAR |
+ CCR_SMOD_FIFO |
+ CCR_DSIZ_32 | CCR_SSIZ_16 |
+ CCR_REN;
+ imx_dma_setup_single(
+ drv_data->rx_channel,
+ drv_data->rx_dma,
+ drv_data->len,
+ drv_data->rd_data_phys,
+ DMA_MODE_READ);
+ imx_dma_enable(drv_data->rx_channel);
+
+ /* Enable SPI interrupt */
+ writel(SPI_INTEN_RO, regs + SPI_INT_STATUS);
+
+ /* Set SPI to request DMA service on both
+ Rx and Tx half fifo watermark */
+ writel(SPI_DMA_RHDEN | SPI_DMA_THDEN, regs + SPI_DMA);
+ } else
+ /* Write only access -> set SPI to request DMA
+ service on Tx half fifo watermark */
+ writel(SPI_DMA_THDEN, regs + SPI_DMA);
+
+ imx_dma_enable(drv_data->tx_channel);
+ } else {
+ dev_dbg(&drv_data->pdev->dev,
+ "pump pio transfer\n"
+ " tx = %p\n"
+ " rx = %p\n"
+ " len = %d\n",
+ drv_data->tx,
+ drv_data->rx,
+ drv_data->len);
+
+ /* Ensure we have the correct interrupt handler */
+ if (drv_data->rx)
+ drv_data->transfer_handler = interrupt_transfer;
+ else
+ drv_data->transfer_handler = interrupt_wronly_transfer;
+
+ /* Enable SPI interrupt */
+ if (drv_data->rx)
+ writel(SPI_INTEN_TH | SPI_INTEN_RO,
+ regs + SPI_INT_STATUS);
+ else
+ writel(SPI_INTEN_TH, regs + SPI_INT_STATUS);
+ }
+}
+
+static void pump_messages(struct work_struct *work)
+{
+ struct driver_data *drv_data =
+ container_of(work, struct driver_data, work);
+ unsigned long flags;
+
+ /* Lock queue and check for queue work */
+ spin_lock_irqsave(&drv_data->lock, flags);
+ if (list_empty(&drv_data->queue) || drv_data->run == QUEUE_STOPPED) {
+ drv_data->busy = 0;
+ spin_unlock_irqrestore(&drv_data->lock, flags);
+ return;
+ }
+
+ /* Make sure we are not already running a message */
+ if (drv_data->cur_msg) {
+ spin_unlock_irqrestore(&drv_data->lock, flags);
+ return;
+ }
+
+ /* Extract head of queue */
+ drv_data->cur_msg = list_entry(drv_data->queue.next,
+ struct spi_message, queue);
+ list_del_init(&drv_data->cur_msg->queue);
+ drv_data->busy = 1;
+ spin_unlock_irqrestore(&drv_data->lock, flags);
+
+ /* Initial message state */
+ drv_data->cur_msg->state = START_STATE;
+ drv_data->cur_transfer = list_entry(drv_data->cur_msg->transfers.next,
+ struct spi_transfer,
+ transfer_list);
+
+ /* Setup the SPI using the per chip configuration */
+ drv_data->cur_chip = spi_get_ctldata(drv_data->cur_msg->spi);
+ restore_state(drv_data);
+
+ /* Mark as busy and launch transfers */
+ tasklet_schedule(&drv_data->pump_transfers);
+}
+
+static int transfer(struct spi_device *spi, struct spi_message *msg)
+{
+ struct driver_data *drv_data = spi_master_get_devdata(spi->master);
+ u32 min_speed_hz, max_speed_hz, tmp;
+ struct spi_transfer *trans;
+ unsigned long flags;
+
+ msg->actual_length = 0;
+
+ /* Per transfer setup check */
+ min_speed_hz = spi_speed_hz(SPI_CONTROL_DATARATE_MIN);
+ max_speed_hz = spi->max_speed_hz;
+ list_for_each_entry(trans, &msg->transfers, transfer_list) {
+ tmp = trans->bits_per_word;
+ if (tmp > 16) {
+ dev_err(&drv_data->pdev->dev,
+ "message rejected : "
+ "invalid transfer bits_per_word (%d bits)\n",
+ tmp);
+ goto msg_rejected;
+ }
+ tmp = trans->speed_hz;
+ if (tmp) {
+ if (tmp < min_speed_hz) {
+ dev_err(&drv_data->pdev->dev,
+ "message rejected : "
+ "device min speed (%d Hz) exceeds "
+ "required transfer speed (%d Hz)\n",
+ min_speed_hz,
+ tmp);
+ goto msg_rejected;
+ } else if (tmp > max_speed_hz) {
+ dev_err(&drv_data->pdev->dev,
+ "message rejected : "
+ "transfer speed (%d Hz) exceeds "
+ "device max speed (%d Hz)\n",
+ tmp,
+ max_speed_hz);
+ goto msg_rejected;
+ }
+ }
+ }
+
+ /* Message accepted */
+ msg->status = -EINPROGRESS;
+ msg->state = START_STATE;
+
+ spin_lock_irqsave(&drv_data->lock, flags);
+ if (drv_data->run == QUEUE_STOPPED) {
+ spin_unlock_irqrestore(&drv_data->lock, flags);
+ return -ESHUTDOWN;
+ }
+
+ list_add_tail(&msg->queue, &drv_data->queue);
+ if (drv_data->run == QUEUE_RUNNING && !drv_data->busy)
+ queue_work(drv_data->workqueue, &drv_data->work);
+
+ spin_unlock_irqrestore(&drv_data->lock, flags);
+ return 0;
+
+msg_rejected:
+ /* Message rejected and not queued */
+ msg->status = -EINVAL;
+ msg->state = ERROR_STATE;
+ if (msg->complete)
+ msg->complete(msg->context);
+ return -EINVAL;
+}
+
+/* On first setup bad values must free chip_data memory since will cause
+ spi_new_device to fail. Bad value setup from protocol driver are simply not
+ applied and notified to the calling driver. */
+static int setup(struct spi_device *spi)
+{
+ struct spi_imx_chip *chip_info;
+ struct chip_data *chip;
+ int first_setup = 0;
+ u32 tmp;
+ int status = 0;
+
+ /* Get controller data */
+ chip_info = spi->controller_data;
+
+ /* Get controller_state */
+ chip = spi_get_ctldata(spi);
+ if (chip == NULL) {
+ first_setup = 1;
+
+ chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL);
+ if (!chip) {
+ dev_err(&spi->dev,
+ "setup - cannot allocate controller state");
+ return -ENOMEM;
+ }
+ chip->control = SPI_DEFAULT_CONTROL;
+
+ if (chip_info == NULL) {
+ /* spi_board_info.controller_data not is supplied */
+ chip_info = kzalloc(sizeof(struct spi_imx_chip),
+ GFP_KERNEL);
+ if (!chip_info) {
+ dev_err(&spi->dev,
+ "setup - "
+ "cannot allocate controller data");
+ status = -ENOMEM;
+ goto err_first_setup;
+ }
+ /* Set controller data default value */
+ chip_info->enable_loopback =
+ SPI_DEFAULT_ENABLE_LOOPBACK;
+ chip_info->enable_dma = SPI_DEFAULT_ENABLE_DMA;
+ chip_info->ins_ss_pulse = 1;
+ chip_info->bclk_wait = SPI_DEFAULT_PERIOD_WAIT;
+ chip_info->cs_control = null_cs_control;
+ }
+ }
+
+ /* Now set controller state based on controller data */
+
+ if (first_setup) {
+ /* SPI loopback */
+ if (chip_info->enable_loopback)
+ chip->test = SPI_TEST_LBC;
+ else
+ chip->test = 0;
+
+ /* SPI dma driven */
+ chip->enable_dma = chip_info->enable_dma;
+
+ /* SPI /SS pulse between spi burst */
+ if (chip_info->ins_ss_pulse)
+ u32_EDIT(chip->control,
+ SPI_CONTROL_SSCTL, SPI_CONTROL_SSCTL_1);
+ else
+ u32_EDIT(chip->control,
+ SPI_CONTROL_SSCTL, SPI_CONTROL_SSCTL_0);
+
+ /* SPI bclk waits between each bits_per_word spi burst */
+ if (chip_info->bclk_wait > SPI_PERIOD_MAX_WAIT) {
+ dev_err(&spi->dev,
+ "setup - "
+ "bclk_wait exceeds max allowed (%d)\n",
+ SPI_PERIOD_MAX_WAIT);
+ goto err_first_setup;
+ }
+ chip->period = SPI_PERIOD_CSRC_BCLK |
+ (chip_info->bclk_wait & SPI_PERIOD_WAIT);
+ }
+
+ /* SPI mode */
+ tmp = spi->mode;
+ if (tmp & SPI_LSB_FIRST) {
+ status = -EINVAL;
+ if (first_setup) {
+ dev_err(&spi->dev,
+ "setup - "
+ "HW doesn't support LSB first transfer\n");
+ goto err_first_setup;
+ } else {
+ dev_err(&spi->dev,
+ "setup - "
+ "HW doesn't support LSB first transfer, "
+ "default to MSB first\n");
+ spi->mode &= ~SPI_LSB_FIRST;
+ }
+ }
+ if (tmp & SPI_CS_HIGH) {
+ u32_EDIT(chip->control,
+ SPI_CONTROL_SSPOL, SPI_CONTROL_SSPOL_ACT_HIGH);
+ }
+ switch (tmp & SPI_MODE_3) {
+ case SPI_MODE_0:
+ tmp = 0;
+ break;
+ case SPI_MODE_1:
+ tmp = SPI_CONTROL_PHA_1;
+ break;
+ case SPI_MODE_2:
+ tmp = SPI_CONTROL_POL_ACT_LOW;
+ break;
+ default:
+ /* SPI_MODE_3 */
+ tmp = SPI_CONTROL_PHA_1 | SPI_CONTROL_POL_ACT_LOW;
+ break;
+ }
+ u32_EDIT(chip->control, SPI_CONTROL_POL | SPI_CONTROL_PHA, tmp);
+
+ /* SPI word width */
+ tmp = spi->bits_per_word;
+ if (tmp == 0) {
+ tmp = 8;
+ spi->bits_per_word = 8;
+ } else if (tmp > 16) {
+ status = -EINVAL;
+ dev_err(&spi->dev,
+ "setup - "
+ "invalid bits_per_word (%d)\n",
+ tmp);
+ if (first_setup)
+ goto err_first_setup;
+ else {
+ /* Undo setup using chip as backup copy */
+ tmp = chip->bits_per_word;
+ spi->bits_per_word = tmp;
+ }
+ }
+ chip->bits_per_word = tmp;
+ u32_EDIT(chip->control, SPI_CONTROL_BITCOUNT_MASK, tmp - 1);
+ chip->n_bytes = (tmp <= 8) ? 1 : 2;
+
+ /* SPI datarate */
+ tmp = spi_data_rate(spi->max_speed_hz);
+ if (tmp == SPI_CONTROL_DATARATE_BAD) {
+ status = -EINVAL;
+ dev_err(&spi->dev,
+ "setup - "
+ "HW min speed (%d Hz) exceeds required "
+ "max speed (%d Hz)\n",
+ spi_speed_hz(SPI_CONTROL_DATARATE_MIN),
+ spi->max_speed_hz);
+ if (first_setup)
+ goto err_first_setup;
+ else
+ /* Undo setup using chip as backup copy */
+ spi->max_speed_hz = chip->max_speed_hz;
+ } else {
+ u32_EDIT(chip->control, SPI_CONTROL_DATARATE, tmp);
+ /* Actual rounded max_speed_hz */
+ tmp = spi_speed_hz(tmp);
+ spi->max_speed_hz = tmp;
+ chip->max_speed_hz = tmp;
+ }
+
+ /* SPI chip-select management */
+ if (chip_info->cs_control)
+ chip->cs_control = chip_info->cs_control;
+ else
+ chip->cs_control = null_cs_control;
+
+ /* Save controller_state */
+ spi_set_ctldata(spi, chip);
+
+ /* Summary */
+ dev_dbg(&spi->dev,
+ "setup succeded\n"
+ " loopback enable = %s\n"
+ " dma enable = %s\n"
+ " insert /ss pulse = %s\n"
+ " period wait = %d\n"
+ " mode = %d\n"
+ " bits per word = %d\n"
+ " min speed = %d Hz\n"
+ " rounded max speed = %d Hz\n",
+ chip->test & SPI_TEST_LBC ? "Yes" : "No",
+ chip->enable_dma ? "Yes" : "No",
+ chip->control & SPI_CONTROL_SSCTL ? "Yes" : "No",
+ chip->period & SPI_PERIOD_WAIT,
+ spi->mode,
+ spi->bits_per_word,
+ spi_speed_hz(SPI_CONTROL_DATARATE_MIN),
+ spi->max_speed_hz);
+
+err_first_setup:
+ kfree(chip);
+ return status;
+}
+
+static void cleanup(struct spi_device *spi)
+{
+ kfree(spi_get_ctldata(spi));
+}
+
+static int init_queue(struct driver_data *drv_data)
+{
+ INIT_LIST_HEAD(&drv_data->queue);
+ spin_lock_init(&drv_data->lock);
+
+ drv_data->run = QUEUE_STOPPED;
+ drv_data->busy = 0;
+
+ tasklet_init(&drv_data->pump_transfers,
+ pump_transfers, (unsigned long)drv_data);
+
+ INIT_WORK(&drv_data->work, pump_messages);
+ drv_data->workqueue = create_singlethread_workqueue(
+ drv_data->master->cdev.dev->bus_id);
+ if (drv_data->workqueue == NULL)
+ return -EBUSY;
+
+ return 0;
+}
+
+static int start_queue(struct driver_data *drv_data)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&drv_data->lock, flags);
+
+ if (drv_data->run == QUEUE_RUNNING || drv_data->busy) {
+ spin_unlock_irqrestore(&drv_data->lock, flags);
+ return -EBUSY;
+ }
+
+ drv_data->run = QUEUE_RUNNING;
+ drv_data->cur_msg = NULL;
+ drv_data->cur_transfer = NULL;
+ drv_data->cur_chip = NULL;
+ spin_unlock_irqrestore(&drv_data->lock, flags);
+
+ queue_work(drv_data->workqueue, &drv_data->work);
+
+ return 0;
+}
+
+static int stop_queue(struct driver_data *drv_data)
+{
+ unsigned long flags;
+ unsigned limit = 500;
+ int status = 0;
+
+ spin_lock_irqsave(&drv_data->lock, flags);
+
+ /* This is a bit lame, but is optimized for the common execution path.
+ * A wait_queue on the drv_data->busy could be used, but then the common
+ * execution path (pump_messages) would be required to call wake_up or
+ * friends on every SPI message. Do this instead */
+ drv_data->run = QUEUE_STOPPED;
+ while (!list_empty(&drv_data->queue) && drv_data->busy && limit--) {
+ spin_unlock_irqrestore(&drv_data->lock, flags);
+ msleep(10);
+ spin_lock_irqsave(&drv_data->lock, flags);
+ }
+
+ if (!list_empty(&drv_data->queue) || drv_data->busy)
+ status = -EBUSY;
+
+ spin_unlock_irqrestore(&drv_data->lock, flags);
+
+ return status;
+}
+
+static int destroy_queue(struct driver_data *drv_data)
+{
+ int status;
+
+ status = stop_queue(drv_data);
+ if (status != 0)
+ return status;
+
+ if (drv_data->workqueue)
+ destroy_workqueue(drv_data->workqueue);
+
+ return 0;
+}
+
+static int spi_imx_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct spi_imx_master *platform_info;
+ struct spi_master *master;
+ struct driver_data *drv_data = NULL;
+ struct resource *res;
+ int irq, status = 0;
+
+ platform_info = dev->platform_data;
+ if (platform_info == NULL) {
+ dev_err(&pdev->dev, "probe - no platform data supplied\n");
+ status = -ENODEV;
+ goto err_no_pdata;
+ }
+
+ /* Allocate master with space for drv_data */
+ master = spi_alloc_master(dev, sizeof(struct driver_data));
+ if (!master) {
+ dev_err(&pdev->dev, "probe - cannot alloc spi_master\n");
+ status = -ENOMEM;
+ goto err_no_mem;
+ }
+ drv_data = spi_master_get_devdata(master);
+ drv_data->master = master;
+ drv_data->master_info = platform_info;
+ drv_data->pdev = pdev;
+
+ master->bus_num = pdev->id;
+ master->num_chipselect = platform_info->num_chipselect;
+ master->cleanup = cleanup;
+ master->setup = setup;
+ master->transfer = transfer;
+
+ drv_data->dummy_dma_buf = SPI_DUMMY_u32;
+
+ /* Find and map resources */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "probe - MEM resources not defined\n");
+ status = -ENODEV;
+ goto err_no_iores;
+ }
+ drv_data->ioarea = request_mem_region(res->start,
+ res->end - res->start + 1,
+ pdev->name);
+ if (drv_data->ioarea == NULL) {
+ dev_err(&pdev->dev, "probe - cannot reserve region\n");
+ status = -ENXIO;
+ goto err_no_iores;
+ }
+ drv_data->regs = ioremap(res->start, res->end - res->start + 1);
+ if (drv_data->regs == NULL) {
+ dev_err(&pdev->dev, "probe - cannot map IO\n");
+ status = -ENXIO;
+ goto err_no_iomap;
+ }
+ drv_data->rd_data_phys = (dma_addr_t)res->start;
+
+ /* Attach to IRQ */
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "probe - IRQ resource not defined\n");
+ status = -ENODEV;
+ goto err_no_irqres;
+ }
+ status = request_irq(irq, spi_int, IRQF_DISABLED, dev->bus_id, drv_data);
+ if (status < 0) {
+ dev_err(&pdev->dev, "probe - cannot get IRQ (%d)\n", status);
+ goto err_no_irqres;
+ }
+
+ /* Setup DMA if requested */
+ drv_data->tx_channel = -1;
+ drv_data->rx_channel = -1;
+ if (platform_info->enable_dma) {
+ /* Get rx DMA channel */
+ status = imx_dma_request_by_prio(&drv_data->rx_channel,
+ "spi_imx_rx", DMA_PRIO_HIGH);
+ if (status < 0) {
+ dev_err(dev,
+ "probe - problem (%d) requesting rx channel\n",
+ status);
+ goto err_no_rxdma;
+ } else
+ imx_dma_setup_handlers(drv_data->rx_channel, NULL,
+ dma_err_handler, drv_data);
+
+ /* Get tx DMA channel */
+ status = imx_dma_request_by_prio(&drv_data->tx_channel,
+ "spi_imx_tx", DMA_PRIO_MEDIUM);
+ if (status < 0) {
+ dev_err(dev,
+ "probe - problem (%d) requesting tx channel\n",
+ status);
+ imx_dma_free(drv_data->rx_channel);
+ goto err_no_txdma;
+ } else
+ imx_dma_setup_handlers(drv_data->tx_channel,
+ dma_tx_handler, dma_err_handler,
+ drv_data);
+
+ /* Set request source and burst length for allocated channels */
+ switch (drv_data->pdev->id) {
+ case 1:
+ /* Using SPI1 */
+ RSSR(drv_data->rx_channel) = DMA_REQ_SPI1_R;
+ RSSR(drv_data->tx_channel) = DMA_REQ_SPI1_T;
+ break;
+ case 2:
+ /* Using SPI2 */
+ RSSR(drv_data->rx_channel) = DMA_REQ_SPI2_R;
+ RSSR(drv_data->tx_channel) = DMA_REQ_SPI2_T;
+ break;
+ default:
+ dev_err(dev, "probe - bad SPI Id\n");
+ imx_dma_free(drv_data->rx_channel);
+ imx_dma_free(drv_data->tx_channel);
+ status = -ENODEV;
+ goto err_no_devid;
+ }
+ BLR(drv_data->rx_channel) = SPI_DMA_BLR;
+ BLR(drv_data->tx_channel) = SPI_DMA_BLR;
+ }
+
+ /* Load default SPI configuration */
+ writel(SPI_RESET_START, drv_data->regs + SPI_RESET);
+ writel(0, drv_data->regs + SPI_RESET);
+ writel(SPI_DEFAULT_CONTROL, drv_data->regs + SPI_CONTROL);
+
+ /* Initial and start queue */
+ status = init_queue(drv_data);
+ if (status != 0) {
+ dev_err(&pdev->dev, "probe - problem initializing queue\n");
+ goto err_init_queue;
+ }
+ status = start_queue(drv_data);
+ if (status != 0) {
+ dev_err(&pdev->dev, "probe - problem starting queue\n");
+ goto err_start_queue;
+ }
+
+ /* Register with the SPI framework */
+ platform_set_drvdata(pdev, drv_data);
+ status = spi_register_master(master);
+ if (status != 0) {
+ dev_err(&pdev->dev, "probe - problem registering spi master\n");
+ goto err_spi_register;
+ }
+
+ dev_dbg(dev, "probe succeded\n");
+ return 0;
+
+err_init_queue:
+err_start_queue:
+err_spi_register:
+ destroy_queue(drv_data);
+
+err_no_rxdma:
+err_no_txdma:
+err_no_devid:
+ free_irq(irq, drv_data);
+
+err_no_irqres:
+ iounmap(drv_data->regs);
+
+err_no_iomap:
+ release_resource(drv_data->ioarea);
+ kfree(drv_data->ioarea);
+
+err_no_iores:
+ spi_master_put(master);
+
+err_no_pdata:
+err_no_mem:
+ return status;
+}
+
+static int __devexit spi_imx_remove(struct platform_device *pdev)
+{
+ struct driver_data *drv_data = platform_get_drvdata(pdev);
+ int irq;
+ int status = 0;
+
+ if (!drv_data)
+ return 0;
+
+ tasklet_kill(&drv_data->pump_transfers);
+
+ /* Remove the queue */
+ status = destroy_queue(drv_data);
+ if (status != 0) {
+ dev_err(&pdev->dev, "queue remove failed (%d)\n", status);
+ return status;
+ }
+
+ /* Reset SPI */
+ writel(SPI_RESET_START, drv_data->regs + SPI_RESET);
+ writel(0, drv_data->regs + SPI_RESET);
+
+ /* Release DMA */
+ if (drv_data->master_info->enable_dma) {
+ RSSR(drv_data->rx_channel) = 0;
+ RSSR(drv_data->tx_channel) = 0;
+ imx_dma_free(drv_data->tx_channel);
+ imx_dma_free(drv_data->rx_channel);
+ }
+
+ /* Release IRQ */
+ irq = platform_get_irq(pdev, 0);
+ if (irq >= 0)
+ free_irq(irq, drv_data);
+
+ /* Release map resources */
+ iounmap(drv_data->regs);
+ release_resource(drv_data->ioarea);
+ kfree(drv_data->ioarea);
+
+ /* Disconnect from the SPI framework */
+ spi_unregister_master(drv_data->master);
+ spi_master_put(drv_data->master);
+
+ /* Prevent double remove */
+ platform_set_drvdata(pdev, NULL);
+
+ dev_dbg(&pdev->dev, "remove succeded\n");
+
+ return 0;
+}
+
+static void spi_imx_shutdown(struct platform_device *pdev)
+{
+ struct driver_data *drv_data = platform_get_drvdata(pdev);
+
+ /* Reset SPI */
+ writel(SPI_RESET_START, drv_data->regs + SPI_RESET);
+ writel(0, drv_data->regs + SPI_RESET);
+
+ dev_dbg(&pdev->dev, "shutdown succeded\n");
+}
+
+#ifdef CONFIG_PM
+static int suspend_devices(struct device *dev, void *pm_message)
+{
+ pm_message_t *state = pm_message;
+
+ if (dev->power.power_state.event != state->event) {
+ dev_warn(dev, "pm state does not match request\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int spi_imx_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct driver_data *drv_data = platform_get_drvdata(pdev);
+ int status = 0;
+
+ status = stop_queue(drv_data);
+ if (status != 0) {
+ dev_warn(&pdev->dev, "suspend cannot stop queue\n");
+ return status;
+ }
+
+ dev_dbg(&pdev->dev, "suspended\n");
+
+ return 0;
+}
+
+static int spi_imx_resume(struct platform_device *pdev)
+{
+ struct driver_data *drv_data = platform_get_drvdata(pdev);
+ int status = 0;
+
+ /* Start the queue running */
+ status = start_queue(drv_data);
+ if (status != 0)
+ dev_err(&pdev->dev, "problem starting queue (%d)\n", status);
+ else
+ dev_dbg(&pdev->dev, "resumed\n");
+
+ return status;
+}
+#else
+#define spi_imx_suspend NULL
+#define spi_imx_resume NULL
+#endif /* CONFIG_PM */
+
+static struct platform_driver driver = {
+ .driver = {
+ .name = "imx-spi",
+ .bus = &platform_bus_type,
+ .owner = THIS_MODULE,
+ },
+ .probe = spi_imx_probe,
+ .remove = __devexit_p(spi_imx_remove),
+ .shutdown = spi_imx_shutdown,
+ .suspend = spi_imx_suspend,
+ .resume = spi_imx_resume,
+};
+
+static int __init spi_imx_init(void)
+{
+ return platform_driver_register(&driver);
+}
+module_init(spi_imx_init);
+
+static void __exit spi_imx_exit(void)
+{
+ platform_driver_unregister(&driver);
+}
+module_exit(spi_imx_exit);
+
+MODULE_AUTHOR("Andrea Paterniani, <a.paterniani@swapp-eng.it>");
+MODULE_DESCRIPTION("iMX SPI Contoller Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi_s3c24xx_gpio.c b/drivers/spi/spi_s3c24xx_gpio.c
index eda53ed04cb..611ac22b7cd 100644
--- a/drivers/spi/spi_s3c24xx_gpio.c
+++ b/drivers/spi/spi_s3c24xx_gpio.c
@@ -73,6 +73,19 @@ static u32 s3c2410_spigpio_txrx_mode1(struct spi_device *spi,
return bitbang_txrx_be_cpha1(spi, nsecs, 0, word, bits);
}
+static u32 s3c2410_spigpio_txrx_mode2(struct spi_device *spi,
+ unsigned nsecs, u32 word, u8 bits)
+{
+ return bitbang_txrx_be_cpha0(spi, nsecs, 1, word, bits);
+}
+
+static u32 s3c2410_spigpio_txrx_mode3(struct spi_device *spi,
+ unsigned nsecs, u32 word, u8 bits)
+{
+ return bitbang_txrx_be_cpha1(spi, nsecs, 1, word, bits);
+}
+
+
static void s3c2410_spigpio_chipselect(struct spi_device *dev, int value)
{
struct s3c2410_spigpio *sg = spidev_to_sg(dev);
@@ -108,6 +121,8 @@ static int s3c2410_spigpio_probe(struct platform_device *dev)
sp->bitbang.txrx_word[SPI_MODE_0] = s3c2410_spigpio_txrx_mode0;
sp->bitbang.txrx_word[SPI_MODE_1] = s3c2410_spigpio_txrx_mode1;
+ sp->bitbang.txrx_word[SPI_MODE_2] = s3c2410_spigpio_txrx_mode2;
+ sp->bitbang.txrx_word[SPI_MODE_3] = s3c2410_spigpio_txrx_mode3;
/* set state of spi pins */
s3c2410_gpio_setpin(sp->info->pin_clk, 0);
diff --git a/drivers/tc/Makefile b/drivers/tc/Makefile
index 83b5bd75ce2..96734269221 100644
--- a/drivers/tc/Makefile
+++ b/drivers/tc/Makefile
@@ -4,7 +4,7 @@
# Object file lists.
-obj-$(CONFIG_TC) += tc.o
+obj-$(CONFIG_TC) += tc.o tc-driver.o
obj-$(CONFIG_ZS) += zs.o
obj-$(CONFIG_VT) += lk201.o lk201-map.o lk201-remap.o
diff --git a/drivers/tc/lk201.c b/drivers/tc/lk201.c
index 757dec9c7ee..a90c255f079 100644
--- a/drivers/tc/lk201.c
+++ b/drivers/tc/lk201.c
@@ -10,7 +10,6 @@
#include <linux/errno.h>
-#include <linux/sched.h>
#include <linux/tty.h>
#include <linux/kernel.h>
#include <linux/init.h>
diff --git a/drivers/tc/tc-driver.c b/drivers/tc/tc-driver.c
new file mode 100644
index 00000000000..16b5bae63c7
--- /dev/null
+++ b/drivers/tc/tc-driver.c
@@ -0,0 +1,110 @@
+/*
+ * TURBOchannel driver services.
+ *
+ * Copyright (c) 2005 James Simmons
+ * Copyright (c) 2006 Maciej W. Rozycki
+ *
+ * Loosely based on drivers/dio/dio-driver.c and
+ * drivers/pci/pci-driver.c.
+ *
+ * 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.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/tc.h>
+
+/**
+ * tc_register_driver - register a new TC driver
+ * @drv: the driver structure to register
+ *
+ * Adds the driver structure to the list of registered drivers
+ * Returns a negative value on error, otherwise 0.
+ * If no error occurred, the driver remains registered even if
+ * no device was claimed during registration.
+ */
+int tc_register_driver(struct tc_driver *tdrv)
+{
+ return driver_register(&tdrv->driver);
+}
+EXPORT_SYMBOL(tc_register_driver);
+
+/**
+ * tc_unregister_driver - unregister a TC driver
+ * @drv: the driver structure to unregister
+ *
+ * Deletes the driver structure from the list of registered TC drivers,
+ * gives it a chance to clean up by calling its remove() function for
+ * each device it was responsible for, and marks those devices as
+ * driverless.
+ */
+void tc_unregister_driver(struct tc_driver *tdrv)
+{
+ driver_unregister(&tdrv->driver);
+}
+EXPORT_SYMBOL(tc_unregister_driver);
+
+/**
+ * tc_match_device - tell if a TC device structure has a matching
+ * TC device ID structure
+ * @tdrv: the TC driver to earch for matching TC device ID strings
+ * @tdev: the TC device structure to match against
+ *
+ * Used by a driver to check whether a TC device present in the
+ * system is in its list of supported devices. Returns the matching
+ * tc_device_id structure or %NULL if there is no match.
+ */
+const struct tc_device_id *tc_match_device(struct tc_driver *tdrv,
+ struct tc_dev *tdev)
+{
+ const struct tc_device_id *id = tdrv->id_table;
+
+ if (id) {
+ while (id->name[0] || id->vendor[0]) {
+ if (strcmp(tdev->name, id->name) == 0 &&
+ strcmp(tdev->vendor, id->vendor) == 0)
+ return id;
+ id++;
+ }
+ }
+ return NULL;
+}
+EXPORT_SYMBOL(tc_match_device);
+
+/**
+ * tc_bus_match - Tell if a device structure has a matching
+ * TC device ID structure
+ * @dev: the device structure to match against
+ * @drv: the device driver to search for matching TC device ID strings
+ *
+ * Used by a driver to check whether a TC device present in the
+ * system is in its list of supported devices. Returns 1 if there
+ * is a match or 0 otherwise.
+ */
+static int tc_bus_match(struct device *dev, struct device_driver *drv)
+{
+ struct tc_dev *tdev = to_tc_dev(dev);
+ struct tc_driver *tdrv = to_tc_driver(drv);
+ const struct tc_device_id *id;
+
+ id = tc_match_device(tdrv, tdev);
+ if (id)
+ return 1;
+
+ return 0;
+}
+
+struct bus_type tc_bus_type = {
+ .name = "tc",
+ .match = tc_bus_match,
+};
+EXPORT_SYMBOL(tc_bus_type);
+
+static int __init tc_driver_init(void)
+{
+ return bus_register(&tc_bus_type);
+}
+
+postcore_initcall(tc_driver_init);
diff --git a/drivers/tc/tc.c b/drivers/tc/tc.c
index 4a51e56f85b..f77f62a4b32 100644
--- a/drivers/tc/tc.c
+++ b/drivers/tc/tc.c
@@ -1,254 +1,193 @@
/*
- * tc-init: We assume the TURBOchannel to be up and running so
- * just probe for Modules and fill in the global data structure
- * tc_bus.
+ * TURBOchannel bus services.
*
- * 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.
+ * Copyright (c) Harald Koerfgen, 1998
+ * Copyright (c) 2001, 2003, 2005, 2006 Maciej W. Rozycki
+ * Copyright (c) 2005 James Simmons
*
- * Copyright (c) Harald Koerfgen, 1998
- * Copyright (c) 2001, 2003, 2005 Maciej W. Rozycki
+ * 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.
*/
+#include <linux/compiler.h>
+#include <linux/errno.h>
#include <linux/init.h>
+#include <linux/ioport.h>
#include <linux/kernel.h>
+#include <linux/list.h>
#include <linux/module.h>
#include <linux/string.h>
+#include <linux/tc.h>
#include <linux/types.h>
-#include <asm/addrspace.h>
-#include <asm/errno.h>
#include <asm/io.h>
-#include <asm/paccess.h>
-#include <asm/dec/machtype.h>
-#include <asm/dec/prom.h>
-#include <asm/dec/tcinfo.h>
-#include <asm/dec/tcmodule.h>
-#include <asm/dec/interrupts.h>
-
-MODULE_LICENSE("GPL");
-slot_info tc_bus[MAX_SLOT];
-static int num_tcslots;
-static tcinfo *info;
+static struct tc_bus tc_bus = {
+ .name = "TURBOchannel",
+};
/*
- * Interface to the world. Read comment in include/asm-mips/tc.h.
+ * Probing for TURBOchannel modules.
*/
-
-int search_tc_card(const char *name)
-{
- int slot;
- slot_info *sip;
-
- for (slot = 0; slot < num_tcslots; slot++) {
- sip = &tc_bus[slot];
- if ((sip->flags & FREE) &&
- (strncmp(sip->name, name, strlen(name)) == 0)) {
- return slot;
- }
- }
-
- return -ENODEV;
-}
-
-void claim_tc_card(int slot)
-{
- if (tc_bus[slot].flags & IN_USE) {
- printk("claim_tc_card: attempting to claim a card already in use\n");
- return;
- }
- tc_bus[slot].flags &= ~FREE;
- tc_bus[slot].flags |= IN_USE;
-}
-
-void release_tc_card(int slot)
+static void __init tc_bus_add_devices(struct tc_bus *tbus)
{
- if (tc_bus[slot].flags & FREE) {
- printk("release_tc_card: "
- "attempting to release a card already free\n");
- return;
- }
- tc_bus[slot].flags &= ~IN_USE;
- tc_bus[slot].flags |= FREE;
-}
-
-unsigned long get_tc_base_addr(int slot)
-{
- return tc_bus[slot].base_addr;
-}
-
-unsigned long get_tc_irq_nr(int slot)
-{
- return tc_bus[slot].interrupt;
-}
-
-unsigned long get_tc_speed(void)
-{
- return 100000 * (10000 / (unsigned long)info->clk_period);
-}
-
-/*
- * Probing for TURBOchannel modules
- */
-static void __init tc_probe(unsigned long startaddr, unsigned long size,
- int slots)
-{
- unsigned long slotaddr;
+ resource_size_t slotsize = tbus->info.slot_size << 20;
+ resource_size_t extslotsize = tbus->ext_slot_size;
+ resource_size_t slotaddr;
+ resource_size_t extslotaddr;
+ resource_size_t devsize;
+ void __iomem *module;
+ struct tc_dev *tdev;
int i, slot, err;
- long offset;
u8 pattern[4];
- volatile u8 *module;
+ long offset;
- for (slot = 0; slot < slots; slot++) {
- slotaddr = startaddr + slot * size;
- module = ioremap_nocache(slotaddr, size);
+ for (slot = 0; slot < tbus->num_tcslots; slot++) {
+ slotaddr = tbus->slot_base + slot * slotsize;
+ extslotaddr = tbus->ext_slot_base + slot * extslotsize;
+ module = ioremap_nocache(slotaddr, slotsize);
BUG_ON(!module);
- offset = OLDCARD;
+ offset = TC_OLDCARD;
err = 0;
- err |= get_dbe(pattern[0], module + OLDCARD + TC_PATTERN0);
- err |= get_dbe(pattern[1], module + OLDCARD + TC_PATTERN1);
- err |= get_dbe(pattern[2], module + OLDCARD + TC_PATTERN2);
- err |= get_dbe(pattern[3], module + OLDCARD + TC_PATTERN3);
- if (err) {
- iounmap(module);
- continue;
- }
+ err |= tc_preadb(pattern + 0, module + offset + TC_PATTERN0);
+ err |= tc_preadb(pattern + 1, module + offset + TC_PATTERN1);
+ err |= tc_preadb(pattern + 2, module + offset + TC_PATTERN2);
+ err |= tc_preadb(pattern + 3, module + offset + TC_PATTERN3);
+ if (err)
+ goto out_err;
if (pattern[0] != 0x55 || pattern[1] != 0x00 ||
pattern[2] != 0xaa || pattern[3] != 0xff) {
- offset = NEWCARD;
+ offset = TC_NEWCARD;
err = 0;
- err |= get_dbe(pattern[0], module + TC_PATTERN0);
- err |= get_dbe(pattern[1], module + TC_PATTERN1);
- err |= get_dbe(pattern[2], module + TC_PATTERN2);
- err |= get_dbe(pattern[3], module + TC_PATTERN3);
- if (err) {
- iounmap(module);
- continue;
- }
+ err |= tc_preadb(pattern + 0,
+ module + offset + TC_PATTERN0);
+ err |= tc_preadb(pattern + 1,
+ module + offset + TC_PATTERN1);
+ err |= tc_preadb(pattern + 2,
+ module + offset + TC_PATTERN2);
+ err |= tc_preadb(pattern + 3,
+ module + offset + TC_PATTERN3);
+ if (err)
+ goto out_err;
}
if (pattern[0] != 0x55 || pattern[1] != 0x00 ||
- pattern[2] != 0xaa || pattern[3] != 0xff) {
- iounmap(module);
- continue;
+ pattern[2] != 0xaa || pattern[3] != 0xff)
+ goto out_err;
+
+ /* Found a board, allocate it an entry in the list */
+ tdev = kzalloc(sizeof(*tdev), GFP_KERNEL);
+ if (!tdev) {
+ printk(KERN_ERR "tc%x: unable to allocate tc_dev\n",
+ slot);
+ goto out_err;
}
+ sprintf(tdev->dev.bus_id, "tc%x", slot);
+ tdev->bus = tbus;
+ tdev->dev.parent = &tbus->dev;
+ tdev->dev.bus = &tc_bus_type;
+ tdev->slot = slot;
- tc_bus[slot].base_addr = slotaddr;
for (i = 0; i < 8; i++) {
- tc_bus[slot].firmware[i] =
- module[TC_FIRM_VER + offset + 4 * i];
- tc_bus[slot].vendor[i] =
- module[TC_VENDOR + offset + 4 * i];
- tc_bus[slot].name[i] =
- module[TC_MODULE + offset + 4 * i];
+ tdev->firmware[i] =
+ readb(module + offset + TC_FIRM_VER + 4 * i);
+ tdev->vendor[i] =
+ readb(module + offset + TC_VENDOR + 4 * i);
+ tdev->name[i] =
+ readb(module + offset + TC_MODULE + 4 * i);
}
- tc_bus[slot].firmware[8] = 0;
- tc_bus[slot].vendor[8] = 0;
- tc_bus[slot].name[8] = 0;
- /*
- * Looks unneccesary, but we may change
- * TC? in the future
- */
- switch (slot) {
- case 0:
- tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC0];
- break;
- case 1:
- tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC1];
- break;
- case 2:
- tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC2];
- break;
- /*
- * Yuck! DS5000/200 onboard devices
- */
- case 5:
- tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC5];
- break;
- case 6:
- tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC6];
- break;
- default:
- tc_bus[slot].interrupt = -1;
- break;
+ tdev->firmware[8] = 0;
+ tdev->vendor[8] = 0;
+ tdev->name[8] = 0;
+
+ pr_info("%s: %s %s %s\n", tdev->dev.bus_id, tdev->vendor,
+ tdev->name, tdev->firmware);
+
+ devsize = readb(module + offset + TC_SLOT_SIZE);
+ devsize <<= 22;
+ if (devsize <= slotsize) {
+ tdev->resource.start = slotaddr;
+ tdev->resource.end = slotaddr + devsize - 1;
+ } else if (devsize <= extslotsize) {
+ tdev->resource.start = extslotaddr;
+ tdev->resource.end = extslotaddr + devsize - 1;
+ } else {
+ printk(KERN_ERR "%s: Cannot provide slot space "
+ "(%dMiB required, up to %dMiB supported)\n",
+ tdev->dev.bus_id, devsize >> 20,
+ max(slotsize, extslotsize) >> 20);
+ kfree(tdev);
+ goto out_err;
}
+ tdev->resource.name = tdev->name;
+ tdev->resource.flags = IORESOURCE_MEM;
+
+ tc_device_get_irq(tdev);
+ device_register(&tdev->dev);
+ list_add_tail(&tdev->node, &tbus->devices);
+
+out_err:
iounmap(module);
}
}
/*
- * the main entry
+ * The main entry.
*/
static int __init tc_init(void)
{
- int tc_clock;
- int i;
- unsigned long slot0addr;
- unsigned long slot_size;
-
- if (!TURBOCHANNEL)
+ /* Initialize the TURBOchannel bus */
+ if (tc_bus_get_info(&tc_bus))
return 0;
- for (i = 0; i < MAX_SLOT; i++) {
- tc_bus[i].base_addr = 0;
- tc_bus[i].name[0] = 0;
- tc_bus[i].vendor[0] = 0;
- tc_bus[i].firmware[0] = 0;
- tc_bus[i].interrupt = -1;
- tc_bus[i].flags = FREE;
- }
-
- info = rex_gettcinfo();
- slot0addr = CPHYSADDR((long)rex_slot_address(0));
-
- switch (mips_machtype) {
- case MACH_DS5000_200:
- num_tcslots = 7;
- break;
- case MACH_DS5000_1XX:
- case MACH_DS5000_2X0:
- case MACH_DS5900:
- num_tcslots = 3;
- break;
- case MACH_DS5000_XX:
- default:
- num_tcslots = 2;
- break;
- }
-
- tc_clock = 10000 / info->clk_period;
-
- if (info->slot_size && slot0addr) {
- pr_info("TURBOchannel rev. %d at %d.%d MHz (with%s parity)\n",
- info->revision, tc_clock / 10, tc_clock % 10,
- info->parity ? "" : "out");
-
- slot_size = info->slot_size << 20;
-
- tc_probe(slot0addr, slot_size, num_tcslots);
-
- for (i = 0; i < num_tcslots; i++) {
- if (!tc_bus[i].base_addr)
- continue;
- pr_info(" slot %d: %s %s %s\n", i, tc_bus[i].vendor,
- tc_bus[i].name, tc_bus[i].firmware);
+ INIT_LIST_HEAD(&tc_bus.devices);
+ strcpy(tc_bus.dev.bus_id, "tc");
+ device_register(&tc_bus.dev);
+
+ if (tc_bus.info.slot_size) {
+ unsigned int tc_clock = tc_get_speed(&tc_bus) / 100000;
+
+ pr_info("tc: TURBOchannel rev. %d at %d.%d MHz "
+ "(with%s parity)\n", tc_bus.info.revision,
+ tc_clock / 10, tc_clock % 10,
+ tc_bus.info.parity ? "" : "out");
+
+ tc_bus.resource[0].start = tc_bus.slot_base;
+ tc_bus.resource[0].end = tc_bus.slot_base +
+ (tc_bus.info.slot_size << 20) *
+ tc_bus.num_tcslots - 1;
+ tc_bus.resource[0].name = tc_bus.name;
+ tc_bus.resource[0].flags = IORESOURCE_MEM;
+ if (request_resource(&iomem_resource,
+ &tc_bus.resource[0]) < 0) {
+ printk(KERN_ERR "tc: Cannot reserve resource\n");
+ return 0;
+ }
+ if (tc_bus.ext_slot_size) {
+ tc_bus.resource[1].start = tc_bus.ext_slot_base;
+ tc_bus.resource[1].end = tc_bus.ext_slot_base +
+ tc_bus.ext_slot_size *
+ tc_bus.num_tcslots - 1;
+ tc_bus.resource[1].name = tc_bus.name;
+ tc_bus.resource[1].flags = IORESOURCE_MEM;
+ if (request_resource(&iomem_resource,
+ &tc_bus.resource[1]) < 0) {
+ printk(KERN_ERR
+ "tc: Cannot reserve resource\n");
+ release_resource(&tc_bus.resource[0]);
+ return 0;
+ }
}
+
+ tc_bus_add_devices(&tc_bus);
}
return 0;
}
subsys_initcall(tc_init);
-
-EXPORT_SYMBOL(search_tc_card);
-EXPORT_SYMBOL(claim_tc_card);
-EXPORT_SYMBOL(release_tc_card);
-EXPORT_SYMBOL(get_tc_base_addr);
-EXPORT_SYMBOL(get_tc_irq_nr);
-EXPORT_SYMBOL(get_tc_speed);
diff --git a/drivers/tc/zs.c b/drivers/tc/zs.c
index fc319727366..3d72aa5cfc7 100644
--- a/drivers/tc/zs.c
+++ b/drivers/tc/zs.c
@@ -626,10 +626,8 @@ static void do_softint(unsigned long private_)
if (!tty)
return;
- if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
+ if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event))
tty_wakeup(tty);
- wake_up_interruptible(&tty->write_wait);
- }
}
static int zs_startup(struct dec_serial * info)
diff --git a/drivers/telephony/ixj.c b/drivers/telephony/ixj.c
index df4cc1fb5f6..71cb64e41a1 100644
--- a/drivers/telephony/ixj.c
+++ b/drivers/telephony/ixj.c
@@ -648,9 +648,9 @@ static inline BYTE SLIC_GetState(IXJ *j)
return j->pld_slicr.bits.state;
}
-static BOOL SLIC_SetState(BYTE byState, IXJ *j)
+static bool SLIC_SetState(BYTE byState, IXJ *j)
{
- BOOL fRetVal = FALSE;
+ bool fRetVal = false;
if (j->cardtype == QTI_PHONECARD) {
if (j->flags.pcmciasct) {
@@ -659,14 +659,14 @@ static BOOL SLIC_SetState(BYTE byState, IXJ *j)
case PLD_SLIC_STATE_OC:
j->pslic.bits.powerdown = 1;
j->pslic.bits.ring0 = j->pslic.bits.ring1 = 0;
- fRetVal = TRUE;
+ fRetVal = true;
break;
case PLD_SLIC_STATE_RINGING:
if (j->readers || j->writers) {
j->pslic.bits.powerdown = 0;
j->pslic.bits.ring0 = 1;
j->pslic.bits.ring1 = 0;
- fRetVal = TRUE;
+ fRetVal = true;
}
break;
case PLD_SLIC_STATE_OHT: /* On-hook transmit */
@@ -679,14 +679,14 @@ static BOOL SLIC_SetState(BYTE byState, IXJ *j)
j->pslic.bits.powerdown = 1;
}
j->pslic.bits.ring0 = j->pslic.bits.ring1 = 0;
- fRetVal = TRUE;
+ fRetVal = true;
break;
case PLD_SLIC_STATE_APR: /* Active polarity reversal */
case PLD_SLIC_STATE_OHTPR: /* OHT polarity reversal */
default:
- fRetVal = FALSE;
+ fRetVal = false;
break;
}
j->psccr.bits.dev = 3;
@@ -703,7 +703,7 @@ static BOOL SLIC_SetState(BYTE byState, IXJ *j)
j->pld_slicw.bits.c3 = 0;
j->pld_slicw.bits.b2en = 0;
outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
- fRetVal = TRUE;
+ fRetVal = true;
break;
case PLD_SLIC_STATE_RINGING:
j->pld_slicw.bits.c1 = 1;
@@ -711,7 +711,7 @@ static BOOL SLIC_SetState(BYTE byState, IXJ *j)
j->pld_slicw.bits.c3 = 0;
j->pld_slicw.bits.b2en = 1;
outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
- fRetVal = TRUE;
+ fRetVal = true;
break;
case PLD_SLIC_STATE_ACTIVE:
j->pld_slicw.bits.c1 = 0;
@@ -719,7 +719,7 @@ static BOOL SLIC_SetState(BYTE byState, IXJ *j)
j->pld_slicw.bits.c3 = 0;
j->pld_slicw.bits.b2en = 0;
outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
- fRetVal = TRUE;
+ fRetVal = true;
break;
case PLD_SLIC_STATE_OHT: /* On-hook transmit */
@@ -728,7 +728,7 @@ static BOOL SLIC_SetState(BYTE byState, IXJ *j)
j->pld_slicw.bits.c3 = 0;
j->pld_slicw.bits.b2en = 0;
outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
- fRetVal = TRUE;
+ fRetVal = true;
break;
case PLD_SLIC_STATE_TIPOPEN:
j->pld_slicw.bits.c1 = 0;
@@ -736,7 +736,7 @@ static BOOL SLIC_SetState(BYTE byState, IXJ *j)
j->pld_slicw.bits.c3 = 1;
j->pld_slicw.bits.b2en = 0;
outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
- fRetVal = TRUE;
+ fRetVal = true;
break;
case PLD_SLIC_STATE_STANDBY:
j->pld_slicw.bits.c1 = 1;
@@ -744,7 +744,7 @@ static BOOL SLIC_SetState(BYTE byState, IXJ *j)
j->pld_slicw.bits.c3 = 1;
j->pld_slicw.bits.b2en = 1;
outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
- fRetVal = TRUE;
+ fRetVal = true;
break;
case PLD_SLIC_STATE_APR: /* Active polarity reversal */
@@ -753,7 +753,7 @@ static BOOL SLIC_SetState(BYTE byState, IXJ *j)
j->pld_slicw.bits.c3 = 1;
j->pld_slicw.bits.b2en = 0;
outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
- fRetVal = TRUE;
+ fRetVal = true;
break;
case PLD_SLIC_STATE_OHTPR: /* OHT polarity reversal */
@@ -762,10 +762,10 @@ static BOOL SLIC_SetState(BYTE byState, IXJ *j)
j->pld_slicw.bits.c3 = 1;
j->pld_slicw.bits.b2en = 0;
outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01);
- fRetVal = TRUE;
+ fRetVal = true;
break;
default:
- fRetVal = FALSE;
+ fRetVal = false;
break;
}
}
@@ -4969,7 +4969,8 @@ static int ixj_daa_cid_read(IXJ *j)
{
int i;
BYTES bytes;
- char CID[ALISDAA_CALLERID_SIZE], mContinue;
+ char CID[ALISDAA_CALLERID_SIZE];
+ bool mContinue;
char *pIn, *pOut;
if (!SCI_Prepare(j))
@@ -5013,7 +5014,7 @@ static int ixj_daa_cid_read(IXJ *j)
pIn = CID;
pOut = j->m_DAAShadowRegs.CAO_REGS.CAO.CallerID;
- mContinue = 1;
+ mContinue = true;
while (mContinue) {
if ((pIn[1] & 0x03) == 0x01) {
pOut[0] = pIn[0];
@@ -5027,7 +5028,7 @@ static int ixj_daa_cid_read(IXJ *j)
if ((pIn[4] & 0xc0) == 0x40) {
pOut[3] = ((pIn[4] & 0x3f) << 2) | ((pIn[3] & 0xc0) >> 6);
} else {
- mContinue = FALSE;
+ mContinue = false;
}
pIn += 5, pOut += 4;
}
@@ -6662,7 +6663,7 @@ static int ixj_fasync(int fd, struct file *file_p, int mode)
return fasync_helper(fd, file_p, mode, &j->async_queue);
}
-static struct file_operations ixj_fops =
+static const struct file_operations ixj_fops =
{
.owner = THIS_MODULE,
.read = ixj_enhanced_read,
@@ -7498,7 +7499,7 @@ static BYTE PCIEE_ReadBit(WORD wEEPROMAddress, BYTE lastLCC)
return ((inb(wEEPROMAddress) >> 3) & 1);
}
-static BOOL PCIEE_ReadWord(WORD wAddress, WORD wLoc, WORD * pwResult)
+static bool PCIEE_ReadWord(WORD wAddress, WORD wLoc, WORD * pwResult)
{
BYTE lastLCC;
WORD wEEPROMAddress = wAddress + 3;
diff --git a/drivers/telephony/ixj.h b/drivers/telephony/ixj.h
index 8d69bcdc29c..4c32a43b791 100644
--- a/drivers/telephony/ixj.h
+++ b/drivers/telephony/ixj.h
@@ -48,15 +48,11 @@
typedef __u16 WORD;
typedef __u32 DWORD;
typedef __u8 BYTE;
-typedef __u8 BOOL;
#ifndef IXJMAX
#define IXJMAX 16
#endif
-#define TRUE 1
-#define FALSE 0
-
/******************************************************************************
*
* This structure when unioned with the structures below makes simple byte
diff --git a/drivers/telephony/ixj_pcmcia.c b/drivers/telephony/ixj_pcmcia.c
index 164a5dcf1f1..3e658dc7c2d 100644
--- a/drivers/telephony/ixj_pcmcia.c
+++ b/drivers/telephony/ixj_pcmcia.c
@@ -3,7 +3,6 @@
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/sched.h>
#include <linux/kernel.h> /* printk() */
#include <linux/fs.h> /* everything... */
#include <linux/errno.h> /* error codes */
diff --git a/drivers/telephony/phonedev.c b/drivers/telephony/phonedev.c
index e41f49afd0f..4d8c2a5b329 100644
--- a/drivers/telephony/phonedev.c
+++ b/drivers/telephony/phonedev.c
@@ -127,7 +127,7 @@ void phone_unregister_device(struct phone_device *pfd)
}
-static struct file_operations phone_fops =
+static const struct file_operations phone_fops =
{
.owner = THIS_MODULE,
.open = phone_open,
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index 825bf884537..8b7ff467d26 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -51,6 +51,7 @@ obj-$(CONFIG_USB_SERIAL) += serial/
obj-$(CONFIG_USB_ADUTUX) += misc/
obj-$(CONFIG_USB_APPLEDISPLAY) += misc/
obj-$(CONFIG_USB_AUERSWALD) += misc/
+obj-$(CONFIG_USB_BERRY_CHARGE) += misc/
obj-$(CONFIG_USB_CYPRESS_CY7C63)+= misc/
obj-$(CONFIG_USB_CYTHERM) += misc/
obj-$(CONFIG_USB_EMI26) += misc/
diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c
index 8ed6c75adf0..638b8009b3b 100644
--- a/drivers/usb/atm/speedtch.c
+++ b/drivers/usb/atm/speedtch.c
@@ -36,7 +36,7 @@
#include <linux/stat.h>
#include <linux/timer.h>
#include <linux/types.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
#include <linux/workqueue.h>
#include "usbatm.h"
diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c
index dae4ef1e8fe..4973e147bc7 100644
--- a/drivers/usb/atm/ueagle-atm.c
+++ b/drivers/usb/atm/ueagle-atm.c
@@ -61,6 +61,7 @@
#include <linux/usb.h>
#include <linux/firmware.h>
#include <linux/ctype.h>
+#include <linux/sched.h>
#include <linux/kthread.h>
#include <linux/version.h>
#include <linux/mutex.h>
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 98199628e39..d38a25f36ea 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -326,10 +326,16 @@ static void acm_rx_tasklet(unsigned long _acm)
struct tty_struct *tty = acm->tty;
struct acm_ru *rcv;
unsigned long flags;
- int i = 0;
+ unsigned char throttled;
dbg("Entering acm_rx_tasklet");
- if (!ACM_READY(acm) || acm->throttle)
+ if (!ACM_READY(acm))
+ return;
+
+ spin_lock(&acm->throttle_lock);
+ throttled = acm->throttle;
+ spin_unlock(&acm->throttle_lock);
+ if (throttled)
return;
next_buffer:
@@ -346,22 +352,20 @@ next_buffer:
dbg("acm_rx_tasklet: procesing buf 0x%p, size = %d", buf, buf->size);
tty_buffer_request_room(tty, buf->size);
- if (!acm->throttle)
+ spin_lock(&acm->throttle_lock);
+ throttled = acm->throttle;
+ spin_unlock(&acm->throttle_lock);
+ if (!throttled)
tty_insert_flip_string(tty, buf->base, buf->size);
tty_flip_buffer_push(tty);
- spin_lock(&acm->throttle_lock);
- if (acm->throttle) {
- dbg("Throtteling noticed");
- memmove(buf->base, buf->base + i, buf->size - i);
- buf->size -= i;
- spin_unlock(&acm->throttle_lock);
+ if (throttled) {
+ dbg("Throttling noticed");
spin_lock_irqsave(&acm->read_lock, flags);
list_add(&buf->list, &acm->filled_read_bufs);
spin_unlock_irqrestore(&acm->read_lock, flags);
return;
}
- spin_unlock(&acm->throttle_lock);
spin_lock_irqsave(&acm->read_lock, flags);
list_add(&buf->list, &acm->spare_read_bufs);
@@ -467,7 +471,8 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
goto bail_out;
}
- if (0 > acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS))
+ if (0 > acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS) &&
+ (acm->ctrl_caps & USB_CDC_CAP_LINE))
goto full_bailout;
INIT_LIST_HEAD(&acm->spare_read_urbs);
@@ -480,6 +485,8 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
list_add(&(acm->rb[i].list), &acm->spare_read_bufs);
}
+ acm->throttle = 0;
+
tasklet_schedule(&acm->urb_task);
done:
@@ -1092,6 +1099,10 @@ static struct usb_device_id acm_ids[] = {
{ USB_DEVICE(0x0ace, 0x1611), /* ZyDAS 56K USB MODEM - new version */
.driver_info = SINGLE_RX_URB, /* firmware bug */
},
+ { USB_DEVICE(0x22b8, 0x7000), /* Motorola Q Phone */
+ .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
+ },
+
/* control interfaces with various AT-command sets */
{ USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
USB_CDC_ACM_PROTO_AT_V25TER) },
diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c
index 6377db1b446..63e50a1f139 100644
--- a/drivers/usb/class/usblp.c
+++ b/drivers/usb/class/usblp.c
@@ -398,6 +398,9 @@ static int usblp_open(struct inode *inode, struct file *file)
retval = 0;
#endif
+ retval = usb_autopm_get_interface(intf);
+ if (retval < 0)
+ goto out;
usblp->used = 1;
file->private_data = usblp;
@@ -442,6 +445,7 @@ static int usblp_release(struct inode *inode, struct file *file)
usblp->used = 0;
if (usblp->present) {
usblp_unlink_urbs(usblp);
+ usb_autopm_put_interface(usblp->intf);
} else /* finish cleanup from disconnect */
usblp_cleanup (usblp);
mutex_unlock (&usblp_mutex);
@@ -1203,14 +1207,9 @@ static int usblp_suspend (struct usb_interface *intf, pm_message_t message)
{
struct usblp *usblp = usb_get_intfdata (intf);
- /* this races against normal access and open */
- mutex_lock (&usblp_mutex);
- mutex_lock (&usblp->mut);
/* we take no more IO */
usblp->sleeping = 1;
usblp_unlink_urbs(usblp);
- mutex_unlock (&usblp->mut);
- mutex_unlock (&usblp_mutex);
return 0;
}
@@ -1220,15 +1219,9 @@ static int usblp_resume (struct usb_interface *intf)
struct usblp *usblp = usb_get_intfdata (intf);
int r;
- mutex_lock (&usblp_mutex);
- mutex_lock (&usblp->mut);
-
usblp->sleeping = 0;
r = handle_bidir (usblp);
- mutex_unlock (&usblp->mut);
- mutex_unlock (&usblp_mutex);
-
return r;
}
@@ -1251,6 +1244,7 @@ static struct usb_driver usblp_driver = {
.suspend = usblp_suspend,
.resume = usblp_resume,
.id_table = usblp_ids,
+ .supports_autosuspend = 1,
};
static int __init usblp_init(void)
diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig
index 3e66b2a9974..2fc0f88a3d8 100644
--- a/drivers/usb/core/Kconfig
+++ b/drivers/usb/core/Kconfig
@@ -33,19 +33,6 @@ config USB_DEVICEFS
Most users want to say Y here.
-config USB_BANDWIDTH
- bool "Enforce USB bandwidth allocation (EXPERIMENTAL)"
- depends on USB && EXPERIMENTAL
- help
- If you say Y here, the USB subsystem enforces USB bandwidth
- allocation and will prevent some device opens from succeeding
- if they would cause USB bandwidth usage to go above 90% of
- the bus bandwidth.
-
- If you say N here, these conditions will cause warning messages
- about USB bandwidth usage to be logged and some devices or
- drivers may not work correctly.
-
config USB_DYNAMIC_MINORS
bool "Dynamic USB minor allocation (EXPERIMENTAL)"
depends on USB && EXPERIMENTAL
diff --git a/drivers/usb/core/Makefile b/drivers/usb/core/Makefile
index 34e9bac319b..b6078706fb9 100644
--- a/drivers/usb/core/Makefile
+++ b/drivers/usb/core/Makefile
@@ -4,7 +4,7 @@
usbcore-objs := usb.o hub.o hcd.o urb.o message.o driver.o \
config.o file.o buffer.o sysfs.o endpoint.o \
- devio.o notify.o generic.o
+ devio.o notify.o generic.o quirks.o
ifeq ($(CONFIG_PCI),y)
usbcore-objs += hcd-pci.o
diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c
index c3915dc2860..ead2475406b 100644
--- a/drivers/usb/core/buffer.c
+++ b/drivers/usb/core/buffer.c
@@ -49,9 +49,9 @@ static const size_t pool_max [HCD_BUFFER_POOLS] = {
*
* Call hcd_buffer_destroy() to clean up after using those pools.
*/
-int hcd_buffer_create (struct usb_hcd *hcd)
+int hcd_buffer_create(struct usb_hcd *hcd)
{
- char name [16];
+ char name[16];
int i, size;
if (!hcd->self.controller->dma_mask)
@@ -60,11 +60,11 @@ int hcd_buffer_create (struct usb_hcd *hcd)
for (i = 0; i < HCD_BUFFER_POOLS; i++) {
if (!(size = pool_max [i]))
continue;
- snprintf (name, sizeof name, "buffer-%d", size);
- hcd->pool [i] = dma_pool_create (name, hcd->self.controller,
+ snprintf(name, sizeof name, "buffer-%d", size);
+ hcd->pool[i] = dma_pool_create(name, hcd->self.controller,
size, size, 0);
if (!hcd->pool [i]) {
- hcd_buffer_destroy (hcd);
+ hcd_buffer_destroy(hcd);
return -ENOMEM;
}
}
@@ -79,14 +79,14 @@ int hcd_buffer_create (struct usb_hcd *hcd)
*
* This frees the buffer pools created by hcd_buffer_create().
*/
-void hcd_buffer_destroy (struct usb_hcd *hcd)
+void hcd_buffer_destroy(struct usb_hcd *hcd)
{
int i;
for (i = 0; i < HCD_BUFFER_POOLS; i++) {
- struct dma_pool *pool = hcd->pool [i];
+ struct dma_pool *pool = hcd->pool[i];
if (pool) {
- dma_pool_destroy (pool);
+ dma_pool_destroy(pool);
hcd->pool[i] = NULL;
}
}
@@ -97,8 +97,8 @@ void hcd_buffer_destroy (struct usb_hcd *hcd)
* better sharing and to leverage mm/slab.c intelligence.
*/
-void *hcd_buffer_alloc (
- struct usb_bus *bus,
+void *hcd_buffer_alloc(
+ struct usb_bus *bus,
size_t size,
gfp_t mem_flags,
dma_addr_t *dma
@@ -110,18 +110,18 @@ void *hcd_buffer_alloc (
/* some USB hosts just use PIO */
if (!bus->controller->dma_mask) {
*dma = ~(dma_addr_t) 0;
- return kmalloc (size, mem_flags);
+ return kmalloc(size, mem_flags);
}
for (i = 0; i < HCD_BUFFER_POOLS; i++) {
if (size <= pool_max [i])
- return dma_pool_alloc (hcd->pool [i], mem_flags, dma);
+ return dma_pool_alloc(hcd->pool [i], mem_flags, dma);
}
- return dma_alloc_coherent (hcd->self.controller, size, dma, 0);
+ return dma_alloc_coherent(hcd->self.controller, size, dma, 0);
}
-void hcd_buffer_free (
- struct usb_bus *bus,
+void hcd_buffer_free(
+ struct usb_bus *bus,
size_t size,
void *addr,
dma_addr_t dma
@@ -134,15 +134,15 @@ void hcd_buffer_free (
return;
if (!bus->controller->dma_mask) {
- kfree (addr);
+ kfree(addr);
return;
}
for (i = 0; i < HCD_BUFFER_POOLS; i++) {
if (size <= pool_max [i]) {
- dma_pool_free (hcd->pool [i], addr, dma);
+ dma_pool_free(hcd->pool [i], addr, dma);
return;
}
}
- dma_free_coherent (hcd->self.controller, size, addr, dma);
+ dma_free_coherent(hcd->self.controller, size, addr, dma);
}
diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c
index ea398e5d50a..aefc7987120 100644
--- a/drivers/usb/core/devices.c
+++ b/drivers/usb/core/devices.c
@@ -104,7 +104,7 @@ static const char *format_config =
static const char *format_iface =
/* I: If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=xxxx*/
- "I: If#=%2d Alt=%2d #EPs=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x Driver=%s\n";
+ "I:%c If#=%2d Alt=%2d #EPs=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x Driver=%s\n";
static const char *format_endpt =
/* E: Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=D?s */
@@ -164,10 +164,10 @@ static const char *class_decode(const int class)
for (ix = 0; clas_info[ix].class != -1; ix++)
if (clas_info[ix].class == class)
break;
- return (clas_info[ix].class_name);
+ return clas_info[ix].class_name;
}
-static char *usb_dump_endpoint_descriptor (
+static char *usb_dump_endpoint_descriptor(
int speed,
char *start,
char *end,
@@ -212,9 +212,9 @@ static char *usb_dump_endpoint_descriptor (
break;
case USB_ENDPOINT_XFER_INT:
type = "Int.";
- if (speed == USB_SPEED_HIGH) {
+ if (speed == USB_SPEED_HIGH)
interval = 1 << (desc->bInterval - 1);
- } else
+ else
interval = desc->bInterval;
break;
default: /* "can't happen" */
@@ -242,15 +242,19 @@ static char *usb_dump_interface_descriptor(char *start, char *end,
{
const struct usb_interface_descriptor *desc = &intfc->altsetting[setno].desc;
const char *driver_name = "";
+ int active = 0;
if (start > end)
return start;
down_read(&usb_bus_type.subsys.rwsem);
- if (iface)
+ if (iface) {
driver_name = (iface->dev.driver
? iface->dev.driver->name
: "(none)");
+ active = (desc == &iface->cur_altsetting->desc);
+ }
start += sprintf(start, format_iface,
+ active ? '*' : ' ', /* mark active altsetting */
desc->bInterfaceNumber,
desc->bAlternateSetting,
desc->bNumEndpoints,
@@ -343,7 +347,7 @@ static char *usb_dump_device_descriptor(char *start, char *end, const struct usb
if (start > end)
return start;
- start += sprintf (start, format_device1,
+ start += sprintf(start, format_device1,
bcdUSB >> 8, bcdUSB & 0xff,
desc->bDeviceClass,
class_decode (desc->bDeviceClass),
@@ -363,7 +367,7 @@ static char *usb_dump_device_descriptor(char *start, char *end, const struct usb
/*
* Dump the different strings that this device holds.
*/
-static char *usb_dump_device_strings (char *start, char *end, struct usb_device *dev)
+static char *usb_dump_device_strings(char *start, char *end, struct usb_device *dev)
{
if (start > end)
return start;
@@ -395,7 +399,7 @@ static char *usb_dump_desc(char *start, char *end, struct usb_device *dev)
if (start > end)
return start;
- start = usb_dump_device_strings (start, end, dev);
+ start = usb_dump_device_strings(start, end, dev);
for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
if (start > end)
@@ -600,10 +604,6 @@ static unsigned int usb_device_poll(struct file *file, struct poll_table_struct
lock_kernel();
if (!st) {
st = kmalloc(sizeof(struct usb_device_status), GFP_KERNEL);
- if (!st) {
- unlock_kernel();
- return POLLIN;
- }
/* we may have dropped BKL - need to check for having lost the race */
if (file->private_data) {
@@ -611,6 +611,11 @@ static unsigned int usb_device_poll(struct file *file, struct poll_table_struct
st = file->private_data;
goto lost_race;
}
+ /* we haven't lost - check for allocation failure now */
+ if (!st) {
+ unlock_kernel();
+ return POLLIN;
+ }
/*
* need to prevent the module from being unloaded, since
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 4b3a6ab29bd..274f14f1633 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -522,19 +522,19 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, unsig
static struct usb_device *usbdev_lookup_minor(int minor)
{
- struct class_device *class_dev;
- struct usb_device *dev = NULL;
+ struct device *device;
+ struct usb_device *udev = NULL;
down(&usb_device_class->sem);
- list_for_each_entry(class_dev, &usb_device_class->children, node) {
- if (class_dev->devt == MKDEV(USB_DEVICE_MAJOR, minor)) {
- dev = class_dev->class_data;
+ list_for_each_entry(device, &usb_device_class->devices, node) {
+ if (device->devt == MKDEV(USB_DEVICE_MAJOR, minor)) {
+ udev = device->platform_data;
break;
}
}
up(&usb_device_class->sem);
- return dev;
+ return udev;
};
/*
@@ -570,6 +570,7 @@ static int usbdev_open(struct inode *inode, struct file *file)
ps->dev = dev;
ps->file = file;
spin_lock_init(&ps->lock);
+ INIT_LIST_HEAD(&ps->list);
INIT_LIST_HEAD(&ps->async_pending);
INIT_LIST_HEAD(&ps->async_completed);
init_waitqueue_head(&ps->wait);
@@ -856,11 +857,11 @@ static int proc_setintf(struct dev_state *ps, void __user *arg)
static int proc_setconfig(struct dev_state *ps, void __user *arg)
{
- unsigned int u;
+ int u;
int status = 0;
struct usb_host_config *actconfig;
- if (get_user(u, (unsigned int __user *)arg))
+ if (get_user(u, (int __user *)arg))
return -EFAULT;
actconfig = ps->dev->actconfig;
@@ -1596,19 +1597,19 @@ static int usbdev_add(struct usb_device *dev)
{
int minor = ((dev->bus->busnum-1) * 128) + (dev->devnum-1);
- dev->class_dev = class_device_create(usb_device_class, NULL,
- MKDEV(USB_DEVICE_MAJOR, minor), &dev->dev,
+ dev->usbfs_dev = device_create(usb_device_class, &dev->dev,
+ MKDEV(USB_DEVICE_MAJOR, minor),
"usbdev%d.%d", dev->bus->busnum, dev->devnum);
- if (IS_ERR(dev->class_dev))
- return PTR_ERR(dev->class_dev);
+ if (IS_ERR(dev->usbfs_dev))
+ return PTR_ERR(dev->usbfs_dev);
- dev->class_dev->class_data = dev;
+ dev->usbfs_dev->platform_data = dev;
return 0;
}
static void usbdev_remove(struct usb_device *dev)
{
- class_device_unregister(dev->class_dev);
+ device_unregister(dev->usbfs_dev);
}
static int usbdev_notify(struct notifier_block *self, unsigned long action,
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index d6eb5ce1dd1..9e3e943f313 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -28,24 +28,16 @@
#include "hcd.h"
#include "usb.h"
-static int usb_match_one_id(struct usb_interface *interface,
- const struct usb_device_id *id);
-
-struct usb_dynid {
- struct list_head node;
- struct usb_device_id id;
-};
-
#ifdef CONFIG_HOTPLUG
/*
* Adds a new dynamic USBdevice ID to this driver,
* and cause the driver to probe for all devices again.
*/
-static ssize_t store_new_id(struct device_driver *driver,
- const char *buf, size_t count)
+ssize_t usb_store_new_id(struct usb_dynids *dynids,
+ struct device_driver *driver,
+ const char *buf, size_t count)
{
- struct usb_driver *usb_drv = to_usb_driver(driver);
struct usb_dynid *dynid;
u32 idVendor = 0;
u32 idProduct = 0;
@@ -65,9 +57,9 @@ static ssize_t store_new_id(struct device_driver *driver,
dynid->id.idProduct = idProduct;
dynid->id.match_flags = USB_DEVICE_ID_MATCH_DEVICE;
- spin_lock(&usb_drv->dynids.lock);
- list_add_tail(&usb_drv->dynids.list, &dynid->node);
- spin_unlock(&usb_drv->dynids.lock);
+ spin_lock(&dynids->lock);
+ list_add_tail(&dynids->list, &dynid->node);
+ spin_unlock(&dynids->lock);
if (get_driver(driver)) {
retval = driver_attach(driver);
@@ -78,6 +70,15 @@ static ssize_t store_new_id(struct device_driver *driver,
return retval;
return count;
}
+EXPORT_SYMBOL_GPL(usb_store_new_id);
+
+static ssize_t store_new_id(struct device_driver *driver,
+ const char *buf, size_t count)
+{
+ struct usb_driver *usb_drv = to_usb_driver(driver);
+
+ return usb_store_new_id(&usb_drv->dynids, driver, buf, count);
+}
static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id);
static int usb_create_newid_file(struct usb_driver *usb_drv)
@@ -365,19 +366,8 @@ void usb_driver_release_interface(struct usb_driver *driver,
EXPORT_SYMBOL(usb_driver_release_interface);
/* returns 0 if no match, 1 if match */
-static int usb_match_one_id(struct usb_interface *interface,
- const struct usb_device_id *id)
+int usb_match_device(struct usb_device *dev, const struct usb_device_id *id)
{
- struct usb_host_interface *intf;
- struct usb_device *dev;
-
- /* proc_connectinfo in devio.c may call us with id == NULL. */
- if (id == NULL)
- return 0;
-
- intf = interface->cur_altsetting;
- dev = interface_to_usbdev(interface);
-
if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
id->idVendor != le16_to_cpu(dev->descriptor.idVendor))
return 0;
@@ -408,6 +398,26 @@ static int usb_match_one_id(struct usb_interface *interface,
(id->bDeviceProtocol != dev->descriptor.bDeviceProtocol))
return 0;
+ return 1;
+}
+
+/* returns 0 if no match, 1 if match */
+int usb_match_one_id(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ struct usb_host_interface *intf;
+ struct usb_device *dev;
+
+ /* proc_connectinfo in devio.c may call us with id == NULL. */
+ if (id == NULL)
+ return 0;
+
+ intf = interface->cur_altsetting;
+ dev = interface_to_usbdev(interface);
+
+ if (!usb_match_device(dev, id))
+ return 0;
+
/* The interface class, subclass, and protocol should never be
* checked for a match if the device class is Vendor Specific,
* unless the match record specifies the Vendor ID. */
@@ -432,6 +442,8 @@ static int usb_match_one_id(struct usb_interface *interface,
return 1;
}
+EXPORT_SYMBOL_GPL(usb_match_one_id);
+
/**
* usb_match_id - find first usb_device_id matching device or interface
* @interface: the interface of interest
@@ -740,6 +752,7 @@ EXPORT_SYMBOL_GPL(usb_deregister_device_driver);
* usb_register_driver - register a USB interface driver
* @new_driver: USB operations for the interface driver
* @owner: module owner of this driver.
+ * @mod_name: module name string
*
* Registers a USB interface driver with the USB core. The list of
* unattached interfaces will be rescanned whenever a new driver is
@@ -750,7 +763,8 @@ EXPORT_SYMBOL_GPL(usb_deregister_device_driver);
* usb_register_dev() to enable that functionality. This function no longer
* takes care of that.
*/
-int usb_register_driver(struct usb_driver *new_driver, struct module *owner)
+int usb_register_driver(struct usb_driver *new_driver, struct module *owner,
+ const char *mod_name)
{
int retval = 0;
@@ -763,6 +777,7 @@ int usb_register_driver(struct usb_driver *new_driver, struct module *owner)
new_driver->drvwrap.driver.probe = usb_probe_interface;
new_driver->drvwrap.driver.remove = usb_unbind_interface;
new_driver->drvwrap.driver.owner = owner;
+ new_driver->drvwrap.driver.mod_name = mod_name;
spin_lock_init(&new_driver->dynids.lock);
INIT_LIST_HEAD(&new_driver->dynids.list);
@@ -948,12 +963,16 @@ static int autosuspend_check(struct usb_device *udev)
int i;
struct usb_interface *intf;
- /* For autosuspend, fail fast if anything is in use.
- * Also fail if any interfaces require remote wakeup but it
- * isn't available. */
+ /* 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.
+ */
udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
if (udev->pm_usage_cnt > 0)
return -EBUSY;
+ if (!udev->autosuspend_delay)
+ return -EPERM;
+
if (udev->actconfig) {
for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
intf = udev->actconfig->interface[i];
@@ -976,7 +995,7 @@ static int autosuspend_check(struct usb_device *udev)
#define autosuspend_check(udev) 0
-#endif
+#endif /* CONFIG_USB_SUSPEND */
/**
* usb_suspend_both - suspend a USB device and its interfaces
@@ -1171,7 +1190,7 @@ static int usb_autopm_do_device(struct usb_device *udev, int inc_usage_cnt)
udev->pm_usage_cnt -= inc_usage_cnt;
} else if (inc_usage_cnt <= 0 && autosuspend_check(udev) == 0)
queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
- USB_AUTOSUSPEND_DELAY);
+ udev->autosuspend_delay);
usb_pm_unlock(udev);
return status;
}
@@ -1206,6 +1225,26 @@ void usb_autosuspend_device(struct usb_device *udev)
}
/**
+ * usb_try_autosuspend_device - attempt an autosuspend of a USB device and its interfaces
+ * @udev: the usb_device to autosuspend
+ *
+ * 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.
+ *
+ * This routine can run only in process context.
+ */
+void usb_try_autosuspend_device(struct usb_device *udev)
+{
+ usb_autopm_do_device(udev, 0);
+ // dev_dbg(&udev->dev, "%s: cnt %d\n",
+ // __FUNCTION__, udev->pm_usage_cnt);
+}
+
+/**
* usb_autoresume_device - immediately autoresume a USB device and its interfaces
* @udev: the usb_device to autoresume
*
@@ -1255,7 +1294,7 @@ static int usb_autopm_do_interface(struct usb_interface *intf,
intf->pm_usage_cnt -= inc_usage_cnt;
} else if (inc_usage_cnt <= 0 && autosuspend_check(udev) == 0)
queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
- USB_AUTOSUSPEND_DELAY);
+ udev->autosuspend_delay);
}
usb_pm_unlock(udev);
return status;
diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c
index 5e628ae3aec..e0ec7045e86 100644
--- a/drivers/usb/core/endpoint.c
+++ b/drivers/usb/core/endpoint.c
@@ -229,7 +229,7 @@ static int init_endpoint_class(void)
kref_init(&ep_class->kref);
ep_class->class = class_create(THIS_MODULE, "usb_endpoint");
if (IS_ERR(ep_class->class)) {
- result = IS_ERR(ep_class->class);
+ result = PTR_ERR(ep_class->class);
goto class_create_error;
}
diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c
index f794f07cfb3..01c857ac27a 100644
--- a/drivers/usb/core/file.c
+++ b/drivers/usb/core/file.c
@@ -194,14 +194,13 @@ int usb_register_dev(struct usb_interface *intf,
++temp;
else
temp = name;
- intf->class_dev = class_device_create(usb_class->class, NULL,
- MKDEV(USB_MAJOR, minor),
- &intf->dev, "%s", temp);
- if (IS_ERR(intf->class_dev)) {
+ intf->usb_dev = device_create(usb_class->class, &intf->dev,
+ MKDEV(USB_MAJOR, minor), "%s", temp);
+ if (IS_ERR(intf->usb_dev)) {
spin_lock (&minor_lock);
usb_minors[intf->minor] = NULL;
spin_unlock (&minor_lock);
- retval = PTR_ERR(intf->class_dev);
+ retval = PTR_ERR(intf->usb_dev);
}
exit:
return retval;
@@ -242,8 +241,8 @@ void usb_deregister_dev(struct usb_interface *intf,
spin_unlock (&minor_lock);
snprintf(name, BUS_ID_SIZE, class_driver->name, intf->minor - minor_base);
- class_device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor));
- intf->class_dev = NULL;
+ device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor));
+ intf->usb_dev = NULL;
intf->minor = -1;
destroy_usb_class();
}
diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c
index ebb20ff7ac5..9bbcb20e2d9 100644
--- a/drivers/usb/core/generic.c
+++ b/drivers/usb/core/generic.c
@@ -25,6 +25,20 @@ static inline const char *plural(int n)
return (n == 1 ? "" : "s");
}
+static int is_rndis(struct usb_interface_descriptor *desc)
+{
+ return desc->bInterfaceClass == USB_CLASS_COMM
+ && desc->bInterfaceSubClass == 2
+ && desc->bInterfaceProtocol == 0xff;
+}
+
+static int is_activesync(struct usb_interface_descriptor *desc)
+{
+ return desc->bInterfaceClass == USB_CLASS_MISC
+ && desc->bInterfaceSubClass == 1
+ && desc->bInterfaceProtocol == 1;
+}
+
static int choose_configuration(struct usb_device *udev)
{
int i;
@@ -87,14 +101,12 @@ static int choose_configuration(struct usb_device *udev)
continue;
}
- /* If the first config's first interface is COMM/2/0xff
- * (MSFT RNDIS), rule it out unless Linux has host-side
- * RNDIS support. */
- if (i == 0 && desc
- && desc->bInterfaceClass == USB_CLASS_COMM
- && desc->bInterfaceSubClass == 2
- && desc->bInterfaceProtocol == 0xff) {
-#ifndef CONFIG_USB_NET_RNDIS_HOST
+ /* When the first config's first interface is one of Microsoft's
+ * pet nonstandard Ethernet-over-USB protocols, ignore it unless
+ * this kernel has enabled the necessary host side driver.
+ */
+ if (i == 0 && desc && (is_rndis(desc) || is_activesync(desc))) {
+#if !defined(CONFIG_USB_NET_RNDIS_HOST) && !defined(CONFIG_USB_NET_RNDIS_HOST_MODULE)
continue;
#else
best = c;
@@ -172,7 +184,7 @@ static void generic_disconnect(struct usb_device *udev)
/* if this is only an unbind, not a physical disconnect, then
* unconfigure the device */
if (udev->actconfig)
- usb_set_configuration(udev, 0);
+ usb_set_configuration(udev, -1);
usb_remove_sysfs_dev_files(udev);
}
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 10064af65d1..b26c19e8d19 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -45,8 +45,6 @@
#include "hub.h"
-// #define USB_BANDWIDTH_MESSAGES
-
/*-------------------------------------------------------------------------*/
/*
@@ -891,136 +889,6 @@ long usb_calc_bus_time (int speed, int is_input, int isoc, int bytecount)
}
EXPORT_SYMBOL (usb_calc_bus_time);
-/*
- * usb_check_bandwidth():
- *
- * old_alloc is from host_controller->bandwidth_allocated in microseconds;
- * bustime is from calc_bus_time(), but converted to microseconds.
- *
- * returns <bustime in us> if successful,
- * or -ENOSPC if bandwidth request fails.
- *
- * FIXME:
- * This initial implementation does not use Endpoint.bInterval
- * in managing bandwidth allocation.
- * It probably needs to be expanded to use Endpoint.bInterval.
- * This can be done as a later enhancement (correction).
- *
- * This will also probably require some kind of
- * frame allocation tracking...meaning, for example,
- * that if multiple drivers request interrupts every 10 USB frames,
- * they don't all have to be allocated at
- * frame numbers N, N+10, N+20, etc. Some of them could be at
- * N+11, N+21, N+31, etc., and others at
- * N+12, N+22, N+32, etc.
- *
- * Similarly for isochronous transfers...
- *
- * Individual HCDs can schedule more directly ... this logic
- * is not correct for high speed transfers.
- */
-int usb_check_bandwidth (struct usb_device *dev, struct urb *urb)
-{
- unsigned int pipe = urb->pipe;
- long bustime;
- int is_in = usb_pipein (pipe);
- int is_iso = usb_pipeisoc (pipe);
- int old_alloc = dev->bus->bandwidth_allocated;
- int new_alloc;
-
-
- bustime = NS_TO_US (usb_calc_bus_time (dev->speed, is_in, is_iso,
- usb_maxpacket (dev, pipe, !is_in)));
- if (is_iso)
- bustime /= urb->number_of_packets;
-
- new_alloc = old_alloc + (int) bustime;
- if (new_alloc > FRAME_TIME_MAX_USECS_ALLOC) {
-#ifdef DEBUG
- char *mode =
-#ifdef CONFIG_USB_BANDWIDTH
- "";
-#else
- "would have ";
-#endif
- dev_dbg (&dev->dev, "usb_check_bandwidth %sFAILED: %d + %ld = %d usec\n",
- mode, old_alloc, bustime, new_alloc);
-#endif
-#ifdef CONFIG_USB_BANDWIDTH
- bustime = -ENOSPC; /* report error */
-#endif
- }
-
- return bustime;
-}
-EXPORT_SYMBOL (usb_check_bandwidth);
-
-
-/**
- * usb_claim_bandwidth - records bandwidth for a periodic transfer
- * @dev: source/target of request
- * @urb: request (urb->dev == dev)
- * @bustime: bandwidth consumed, in (average) microseconds per frame
- * @isoc: true iff the request is isochronous
- *
- * Bus bandwidth reservations are recorded purely for diagnostic purposes.
- * HCDs are expected not to overcommit periodic bandwidth, and to record such
- * reservations whenever endpoints are added to the periodic schedule.
- *
- * FIXME averaging per-frame is suboptimal. Better to sum over the HCD's
- * entire periodic schedule ... 32 frames for OHCI, 1024 for UHCI, settable
- * for EHCI (256/512/1024 frames, default 1024) and have the bus expose how
- * large its periodic schedule is.
- */
-void usb_claim_bandwidth (struct usb_device *dev, struct urb *urb, int bustime, int isoc)
-{
- dev->bus->bandwidth_allocated += bustime;
- if (isoc)
- dev->bus->bandwidth_isoc_reqs++;
- else
- dev->bus->bandwidth_int_reqs++;
- urb->bandwidth = bustime;
-
-#ifdef USB_BANDWIDTH_MESSAGES
- dev_dbg (&dev->dev, "bandwidth alloc increased by %d (%s) to %d for %d requesters\n",
- bustime,
- isoc ? "ISOC" : "INTR",
- dev->bus->bandwidth_allocated,
- dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs);
-#endif
-}
-EXPORT_SYMBOL (usb_claim_bandwidth);
-
-
-/**
- * usb_release_bandwidth - reverses effect of usb_claim_bandwidth()
- * @dev: source/target of request
- * @urb: request (urb->dev == dev)
- * @isoc: true iff the request is isochronous
- *
- * This records that previously allocated bandwidth has been released.
- * Bandwidth is released when endpoints are removed from the host controller's
- * periodic schedule.
- */
-void usb_release_bandwidth (struct usb_device *dev, struct urb *urb, int isoc)
-{
- dev->bus->bandwidth_allocated -= urb->bandwidth;
- if (isoc)
- dev->bus->bandwidth_isoc_reqs--;
- else
- dev->bus->bandwidth_int_reqs--;
-
-#ifdef USB_BANDWIDTH_MESSAGES
- dev_dbg (&dev->dev, "bandwidth alloc reduced by %d (%s) to %d for %d requesters\n",
- urb->bandwidth,
- isoc ? "ISOC" : "INTR",
- dev->bus->bandwidth_allocated,
- dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs);
-#endif
- urb->bandwidth = 0;
-}
-EXPORT_SYMBOL (usb_release_bandwidth);
-
/*-------------------------------------------------------------------------*/
@@ -1034,11 +902,6 @@ static void urb_unlink (struct urb *urb)
{
unsigned long flags;
- /* Release any periodic transfer bandwidth */
- if (urb->bandwidth)
- usb_release_bandwidth (urb->dev, urb,
- usb_pipeisoc (urb->pipe));
-
/* clear all state linking urb to this dev (and hcd) */
spin_lock_irqsave (&hcd_data_lock, flags);
diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
index 8f8df0d4382..2a269ca2051 100644
--- a/drivers/usb/core/hcd.h
+++ b/drivers/usb/core/hcd.h
@@ -308,10 +308,6 @@ extern void usb_destroy_configuration(struct usb_device *dev);
#define NS_TO_US(ns) ((ns + 500L) / 1000L)
/* convert & round nanoseconds to microseconds */
-extern void usb_claim_bandwidth (struct usb_device *dev, struct urb *urb,
- int bustime, int isoc);
-extern void usb_release_bandwidth (struct usb_device *dev, struct urb *urb,
- int isoc);
/*
* Full/low speed bandwidth allocation constants/support.
@@ -324,8 +320,6 @@ extern void usb_release_bandwidth (struct usb_device *dev, struct urb *urb,
#define FRAME_TIME_MAX_BITS_ALLOC (90L * FRAME_TIME_BITS / 100L)
#define FRAME_TIME_MAX_USECS_ALLOC (90L * FRAME_TIME_USECS / 100L)
-extern int usb_check_bandwidth (struct usb_device *dev, struct urb *urb);
-
/*
* Ceiling [nano/micro]seconds (typical) for that many bytes at high speed
* ISO is a bit less, no ACK ... from USB 2.0 spec, 5.11.3 (and needed
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 1988224b362..41400743ce2 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -44,6 +44,7 @@ struct usb_hub {
struct usb_hub_status hub;
struct usb_port_status port;
} *status; /* buffer for status reports */
+ struct mutex status_mutex; /* for the status buffer */
int error; /* last reported error */
int nerrors; /* track consecutive errors */
@@ -87,9 +88,6 @@ static DECLARE_WAIT_QUEUE_HEAD(khubd_wait);
static struct task_struct *khubd_task;
-/* multithreaded probe logic */
-static int multithread_probe = 0;
-
/* cycle leds on hubs that aren't blinking for attention */
static int blinkenlights = 0;
module_param (blinkenlights, bool, S_IRUGO);
@@ -538,6 +536,7 @@ static int hub_hub_status(struct usb_hub *hub,
{
int ret;
+ mutex_lock(&hub->status_mutex);
ret = get_hub_status(hub->hdev, &hub->status->hub);
if (ret < 0)
dev_err (hub->intfdev,
@@ -547,6 +546,7 @@ static int hub_hub_status(struct usb_hub *hub,
*change = le16_to_cpu(hub->status->hub.wHubChange);
ret = 0;
}
+ mutex_unlock(&hub->status_mutex);
return ret;
}
@@ -620,6 +620,7 @@ static int hub_configure(struct usb_hub *hub,
ret = -ENOMEM;
goto fail;
}
+ mutex_init(&hub->status_mutex);
hub->descriptor = kmalloc(sizeof(*hub->descriptor), GFP_KERNEL);
if (!hub->descriptor) {
@@ -1256,9 +1257,28 @@ static inline void show_string(struct usb_device *udev, char *id, char *string)
static int __usb_port_suspend(struct usb_device *, int port1);
#endif
-static int __usb_new_device(void *void_data)
+/**
+ * usb_new_device - perform initial device setup (usbcore-internal)
+ * @udev: newly addressed device (in ADDRESS state)
+ *
+ * This is called with devices which have been enumerated, but not yet
+ * configured. The device descriptor is available, but not descriptors
+ * for any device configuration. The caller must have locked either
+ * the parent hub (if udev is a normal device) or else the
+ * usb_bus_list_lock (if udev is a root hub). The parent's pointer to
+ * udev has already been installed, but udev is not yet visible through
+ * sysfs or other filesystem code.
+ *
+ * It will return if the device is configured properly or not. Zero if
+ * the interface was registered with the driver core; else a negative
+ * errno value.
+ *
+ * This call is synchronous, and may not be used in an interrupt context.
+ *
+ * Only the hub driver or root-hub registrar should ever call this.
+ */
+int usb_new_device(struct usb_device *udev)
{
- struct usb_device *udev = void_data;
int err;
/* Lock ourself into memory in order to keep a probe sequence
@@ -1267,6 +1287,9 @@ static int __usb_new_device(void *void_data)
if (!try_module_get(THIS_MODULE))
return -EINVAL;
+ /* Determine quirks */
+ usb_detect_quirks(udev);
+
err = usb_get_configuration(udev);
if (err < 0) {
dev_err(&udev->dev, "can't read configurations, error %d\n",
@@ -1375,49 +1398,12 @@ fail:
goto exit;
}
-/**
- * usb_new_device - perform initial device setup (usbcore-internal)
- * @udev: newly addressed device (in ADDRESS state)
- *
- * This is called with devices which have been enumerated, but not yet
- * configured. The device descriptor is available, but not descriptors
- * for any device configuration. The caller must have locked either
- * the parent hub (if udev is a normal device) or else the
- * usb_bus_list_lock (if udev is a root hub). The parent's pointer to
- * udev has already been installed, but udev is not yet visible through
- * sysfs or other filesystem code.
- *
- * The return value for this function depends on if the
- * multithread_probe variable is set or not. If it's set, it will
- * return a if the probe thread was successfully created or not. If the
- * variable is not set, it will return if the device is configured
- * properly or not. interfaces, in sysfs); else a negative errno value.
- *
- * This call is synchronous, and may not be used in an interrupt context.
- *
- * Only the hub driver or root-hub registrar should ever call this.
- */
-int usb_new_device(struct usb_device *udev)
-{
- struct task_struct *probe_task;
- int ret = 0;
-
- if (multithread_probe) {
- probe_task = kthread_run(__usb_new_device, udev,
- "usb-probe-%s", udev->devnum);
- if (IS_ERR(probe_task))
- ret = PTR_ERR(probe_task);
- } else
- ret = __usb_new_device(udev);
-
- return ret;
-}
-
static int hub_port_status(struct usb_hub *hub, int port1,
u16 *status, u16 *change)
{
int ret;
+ mutex_lock(&hub->status_mutex);
ret = get_port_status(hub->hdev, port1, &hub->status->port);
if (ret < 4) {
dev_err (hub->intfdev,
@@ -1429,6 +1415,7 @@ static int hub_port_status(struct usb_hub *hub, int port1,
*change = le16_to_cpu(hub->status->port.wPortChange);
ret = 0;
}
+ mutex_unlock(&hub->status_mutex);
return ret;
}
@@ -1926,6 +1913,7 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
struct usb_hub *hub = usb_get_intfdata (intf);
struct usb_device *hdev = hub->hdev;
unsigned port1;
+ int status = 0;
/* fail if children aren't already suspended */
for (port1 = 1; port1 <= hdev->maxchild; port1++) {
@@ -1949,24 +1937,18 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
dev_dbg(&intf->dev, "%s\n", __FUNCTION__);
+ /* stop khubd and related activity */
+ hub_quiesce(hub);
+
/* "global suspend" of the downstream HC-to-USB interface */
if (!hdev->parent) {
- struct usb_bus *bus = hdev->bus;
- if (bus) {
- int status = hcd_bus_suspend (bus);
-
- if (status != 0) {
- dev_dbg(&hdev->dev, "'global' suspend %d\n",
- status);
- return status;
- }
- } else
- return -EOPNOTSUPP;
+ status = hcd_bus_suspend(hdev->bus);
+ if (status != 0) {
+ dev_dbg(&hdev->dev, "'global' suspend %d\n", status);
+ hub_activate(hub);
+ }
}
-
- /* stop khubd and related activity */
- hub_quiesce(hub);
- return 0;
+ return status;
}
static int hub_resume(struct usb_interface *intf)
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index 149aa8bfb1f..2f17468b5c1 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -11,6 +11,7 @@
#include <linux/timer.h>
#include <linux/ctype.h>
#include <linux/device.h>
+#include <linux/usb/quirks.h>
#include <asm/byteorder.h>
#include <asm/scatterlist.h>
@@ -685,7 +686,10 @@ static int usb_string_sub(struct usb_device *dev, unsigned int langid,
/* Try to read the string descriptor by asking for the maximum
* possible number of bytes */
- rc = usb_get_string(dev, langid, index, buf, 255);
+ if (dev->quirks & USB_QUIRK_STRING_FETCH_255)
+ rc = -EIO;
+ else
+ rc = usb_get_string(dev, langid, index, buf, 255);
/* If that failed try to read the descriptor length, then
* ask for just that many bytes */
@@ -1316,6 +1320,14 @@ static void release_interface(struct device *dev)
* use this kind of configurability; many devices only have one
* configuration.
*
+ * @configuration is the value of the configuration to be installed.
+ * According to the USB spec (e.g. section 9.1.1.5), configuration values
+ * must be non-zero; a value of zero indicates that the device in
+ * unconfigured. However some devices erroneously use 0 as one of their
+ * configuration values. To help manage such devices, this routine will
+ * accept @configuration = -1 as indicating the device should be put in
+ * an unconfigured state.
+ *
* USB device configurations may affect Linux interoperability,
* power consumption and the functionality available. For example,
* the default configuration is limited to using 100mA of bus power,
@@ -1347,10 +1359,15 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
struct usb_interface **new_interfaces = NULL;
int n, nintf;
- for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
- if (dev->config[i].desc.bConfigurationValue == configuration) {
- cp = &dev->config[i];
- break;
+ if (configuration == -1)
+ configuration = 0;
+ else {
+ for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
+ if (dev->config[i].desc.bConfigurationValue ==
+ configuration) {
+ cp = &dev->config[i];
+ break;
+ }
}
}
if ((!cp && configuration != 0))
@@ -1359,6 +1376,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
/* The USB spec says configuration 0 means unconfigured.
* But if a device includes a configuration numbered 0,
* we will accept it as a correctly configured state.
+ * Use -1 if you really want to unconfigure the device.
*/
if (cp && configuration == 0)
dev_warn(&dev->dev, "config 0 descriptor??\n");
@@ -1545,11 +1563,7 @@ int usb_driver_set_configuration(struct usb_device *udev, int config)
INIT_WORK(&req->work, driver_set_config_work);
usb_get_dev(udev);
- if (!schedule_work(&req->work)) {
- usb_put_dev(udev);
- kfree(req);
- return -EINVAL;
- }
+ schedule_work(&req->work);
return 0;
}
EXPORT_SYMBOL_GPL(usb_driver_set_configuration);
diff --git a/drivers/usb/core/otg_whitelist.h b/drivers/usb/core/otg_whitelist.h
index 627a5a2fc9c..7f31a495a25 100644
--- a/drivers/usb/core/otg_whitelist.h
+++ b/drivers/usb/core/otg_whitelist.h
@@ -31,7 +31,7 @@ static struct usb_device_id whitelist_table [] = {
{ USB_DEVICE_INFO(7, 1, 3) },
#endif
-#ifdef CONFIG_USB_CDCETHER
+#ifdef CONFIG_USB_NET_CDCETHER
/* Linux-USB CDC Ethernet gadget */
{ USB_DEVICE(0x0525, 0xa4a1), },
/* Linux-USB CDC Ethernet + RNDIS gadget */
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
new file mode 100644
index 00000000000..0e5c646cb4f
--- /dev/null
+++ b/drivers/usb/core/quirks.c
@@ -0,0 +1,77 @@
+/*
+ * USB device quirk handling logic and table
+ *
+ * Copyright (c) 2007 Oliver Neukum
+ * 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.
+ *
+ *
+ */
+
+#include <linux/usb.h>
+#include <linux/usb/quirks.h>
+#include "usb.h"
+
+/* List of quirky USB devices. Please keep this list ordered by:
+ * 1) Vendor ID
+ * 2) Product ID
+ * 3) Class ID
+ *
+ * as we want specific devices to be overridden first, and only after that, any
+ * class specific quirks.
+ *
+ * Right now the logic aborts if it finds a valid device in the table, we might
+ * want to change that in the future if it turns out that a whole class of
+ * devices is broken...
+ */
+static const struct usb_device_id usb_quirk_list[] = {
+ /* HP 5300/5370C scanner */
+ { USB_DEVICE(0x03f0, 0x0701), .driver_info = USB_QUIRK_STRING_FETCH_255 },
+
+ /* Elsa MicroLink 56k (V.250) */
+ { USB_DEVICE(0x05cc, 0x2267), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
+
+ { } /* terminating entry must be last */
+};
+
+static void usb_autosuspend_quirk(struct usb_device *udev)
+{
+#ifdef CONFIG_USB_SUSPEND
+ /* disable autosuspend, but allow the user to re-enable it via sysfs */
+ udev->autosuspend_delay = 0;
+#endif
+}
+
+static const struct usb_device_id *find_id(struct usb_device *udev)
+{
+ const struct usb_device_id *id = usb_quirk_list;
+
+ for (; id->idVendor || id->bDeviceClass || id->bInterfaceClass ||
+ id->driver_info; id++) {
+ if (usb_match_device(udev, id))
+ return id;
+ }
+ return NULL;
+}
+
+/*
+ * Detect any quirks the device has, and do any housekeeping for it if needed.
+ */
+void usb_detect_quirks(struct usb_device *udev)
+{
+ const struct usb_device_id *id = usb_quirk_list;
+
+ id = find_id(udev);
+ if (id)
+ udev->quirks = (u32)(id->driver_info);
+ if (udev->quirks)
+ dev_dbg(&udev->dev, "USB quirks for this device: %x\n",
+ udev->quirks);
+
+ /* do any special quirk handling here if needed */
+ if (udev->quirks & USB_QUIRK_NO_AUTOSUSPEND)
+ usb_autosuspend_quirk(udev);
+}
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index 55d8f575206..311d5df8038 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -16,16 +16,16 @@
/* Active configuration fields */
#define usb_actconfig_show(field, multiplier, format_string) \
-static ssize_t show_##field (struct device *dev, \
+static ssize_t show_##field(struct device *dev, \
struct device_attribute *attr, char *buf) \
{ \
struct usb_device *udev; \
struct usb_host_config *actconfig; \
\
- udev = to_usb_device (dev); \
+ udev = to_usb_device(dev); \
actconfig = udev->actconfig; \
if (actconfig) \
- return sprintf (buf, format_string, \
+ return sprintf(buf, format_string, \
actconfig->desc.field * multiplier); \
else \
return 0; \
@@ -35,9 +35,9 @@ static ssize_t show_##field (struct device *dev, \
usb_actconfig_show(field, multiplier, format_string) \
static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
-usb_actconfig_attr (bNumInterfaces, 1, "%2d\n")
-usb_actconfig_attr (bmAttributes, 1, "%2x\n")
-usb_actconfig_attr (bMaxPower, 2, "%3dmA\n")
+usb_actconfig_attr(bNumInterfaces, 1, "%2d\n")
+usb_actconfig_attr(bmAttributes, 1, "%2x\n")
+usb_actconfig_attr(bMaxPower, 2, "%3dmA\n")
static ssize_t show_configuration_string(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -45,7 +45,7 @@ static ssize_t show_configuration_string(struct device *dev,
struct usb_device *udev;
struct usb_host_config *actconfig;
- udev = to_usb_device (dev);
+ udev = to_usb_device(dev);
actconfig = udev->actconfig;
if ((!actconfig) || (!actconfig->string))
return 0;
@@ -57,16 +57,16 @@ static DEVICE_ATTR(configuration, S_IRUGO, show_configuration_string, NULL);
usb_actconfig_show(bConfigurationValue, 1, "%u\n");
static ssize_t
-set_bConfigurationValue (struct device *dev, struct device_attribute *attr,
+set_bConfigurationValue(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct usb_device *udev = to_usb_device (dev);
+ struct usb_device *udev = to_usb_device(dev);
int config, value;
- if (sscanf (buf, "%u", &config) != 1 || config > 255)
+ if (sscanf(buf, "%d", &config) != 1 || config < -1 || config > 255)
return -EINVAL;
usb_lock_device(udev);
- value = usb_set_configuration (udev, config);
+ value = usb_set_configuration(udev, config);
usb_unlock_device(udev);
return (value < 0) ? value : count;
}
@@ -81,7 +81,7 @@ static ssize_t show_##name(struct device *dev, \
{ \
struct usb_device *udev; \
\
- udev = to_usb_device (dev); \
+ udev = to_usb_device(dev); \
return sprintf(buf, "%s\n", udev->name); \
} \
static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL);
@@ -91,12 +91,12 @@ usb_string_attr(manufacturer);
usb_string_attr(serial);
static ssize_t
-show_speed (struct device *dev, struct device_attribute *attr, char *buf)
+show_speed(struct device *dev, struct device_attribute *attr, char *buf)
{
struct usb_device *udev;
char *speed;
- udev = to_usb_device (dev);
+ udev = to_usb_device(dev);
switch (udev->speed) {
case USB_SPEED_LOW:
@@ -112,22 +112,22 @@ show_speed (struct device *dev, struct device_attribute *attr, char *buf)
default:
speed = "unknown";
}
- return sprintf (buf, "%s\n", speed);
+ return sprintf(buf, "%s\n", speed);
}
static DEVICE_ATTR(speed, S_IRUGO, show_speed, NULL);
static ssize_t
-show_devnum (struct device *dev, struct device_attribute *attr, char *buf)
+show_devnum(struct device *dev, struct device_attribute *attr, char *buf)
{
struct usb_device *udev;
- udev = to_usb_device (dev);
- return sprintf (buf, "%d\n", udev->devnum);
+ udev = to_usb_device(dev);
+ return sprintf(buf, "%d\n", udev->devnum);
}
static DEVICE_ATTR(devnum, S_IRUGO, show_devnum, NULL);
static ssize_t
-show_version (struct device *dev, struct device_attribute *attr, char *buf)
+show_version(struct device *dev, struct device_attribute *attr, char *buf)
{
struct usb_device *udev;
u16 bcdUSB;
@@ -139,25 +139,94 @@ show_version (struct device *dev, struct device_attribute *attr, char *buf)
static DEVICE_ATTR(version, S_IRUGO, show_version, NULL);
static ssize_t
-show_maxchild (struct device *dev, struct device_attribute *attr, char *buf)
+show_maxchild(struct device *dev, struct device_attribute *attr, char *buf)
{
struct usb_device *udev;
- udev = to_usb_device (dev);
- return sprintf (buf, "%d\n", udev->maxchild);
+ udev = to_usb_device(dev);
+ return sprintf(buf, "%d\n", udev->maxchild);
}
static DEVICE_ATTR(maxchild, S_IRUGO, show_maxchild, NULL);
+static ssize_t
+show_quirks(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct usb_device *udev;
+
+ udev = to_usb_device(dev);
+ return sprintf(buf, "0x%x\n", udev->quirks);
+}
+static DEVICE_ATTR(quirks, S_IRUGO, show_quirks, NULL);
+
+#ifdef CONFIG_USB_SUSPEND
+
+static ssize_t
+show_autosuspend(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct usb_device *udev = to_usb_device(dev);
+
+ return sprintf(buf, "%u\n", udev->autosuspend_delay / HZ);
+}
+
+static ssize_t
+set_autosuspend(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct usb_device *udev = to_usb_device(dev);
+ unsigned value, old;
+
+ if (sscanf(buf, "%u", &value) != 1 || value >= INT_MAX/HZ)
+ return -EINVAL;
+ value *= HZ;
+
+ old = udev->autosuspend_delay;
+ udev->autosuspend_delay = value;
+ if (value > 0 && old == 0)
+ usb_try_autosuspend_device(udev);
+
+ return count;
+}
+
+static DEVICE_ATTR(autosuspend, S_IRUGO | S_IWUSR,
+ show_autosuspend, set_autosuspend);
+
+static char power_group[] = "power";
+
+static int add_power_attributes(struct device *dev)
+{
+ int rc = 0;
+
+ if (is_usb_device(dev))
+ rc = sysfs_add_file_to_group(&dev->kobj,
+ &dev_attr_autosuspend.attr,
+ power_group);
+ return rc;
+}
+
+static void remove_power_attributes(struct device *dev)
+{
+ sysfs_remove_file_from_group(&dev->kobj,
+ &dev_attr_autosuspend.attr,
+ power_group);
+}
+
+#else
+
+#define add_power_attributes(dev) 0
+#define remove_power_attributes(dev) do {} while (0)
+
+#endif /* CONFIG_USB_SUSPEND */
+
/* Descriptor fields */
#define usb_descriptor_attr_le16(field, format_string) \
static ssize_t \
-show_##field (struct device *dev, struct device_attribute *attr, \
+show_##field(struct device *dev, struct device_attribute *attr, \
char *buf) \
{ \
struct usb_device *udev; \
\
- udev = to_usb_device (dev); \
- return sprintf (buf, format_string, \
+ udev = to_usb_device(dev); \
+ return sprintf(buf, format_string, \
le16_to_cpu(udev->descriptor.field)); \
} \
static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
@@ -168,21 +237,21 @@ usb_descriptor_attr_le16(bcdDevice, "%04x\n")
#define usb_descriptor_attr(field, format_string) \
static ssize_t \
-show_##field (struct device *dev, struct device_attribute *attr, \
+show_##field(struct device *dev, struct device_attribute *attr, \
char *buf) \
{ \
struct usb_device *udev; \
\
- udev = to_usb_device (dev); \
- return sprintf (buf, format_string, udev->descriptor.field); \
+ udev = to_usb_device(dev); \
+ return sprintf(buf, format_string, udev->descriptor.field); \
} \
static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
-usb_descriptor_attr (bDeviceClass, "%02x\n")
-usb_descriptor_attr (bDeviceSubClass, "%02x\n")
-usb_descriptor_attr (bDeviceProtocol, "%02x\n")
-usb_descriptor_attr (bNumConfigurations, "%d\n")
-usb_descriptor_attr (bMaxPacketSize0, "%d\n")
+usb_descriptor_attr(bDeviceClass, "%02x\n")
+usb_descriptor_attr(bDeviceSubClass, "%02x\n")
+usb_descriptor_attr(bDeviceProtocol, "%02x\n")
+usb_descriptor_attr(bNumConfigurations, "%d\n")
+usb_descriptor_attr(bMaxPacketSize0, "%d\n")
static struct attribute *dev_attrs[] = {
/* current configuration's attributes */
@@ -204,6 +273,7 @@ static struct attribute *dev_attrs[] = {
&dev_attr_devnum.attr,
&dev_attr_version.attr,
&dev_attr_maxchild.attr,
+ &dev_attr_quirks.attr,
NULL,
};
static struct attribute_group dev_attr_grp = {
@@ -219,18 +289,22 @@ int usb_create_sysfs_dev_files(struct usb_device *udev)
if (retval)
return retval;
+ retval = add_power_attributes(dev);
+ if (retval)
+ goto error;
+
if (udev->manufacturer) {
- retval = device_create_file (dev, &dev_attr_manufacturer);
+ retval = device_create_file(dev, &dev_attr_manufacturer);
if (retval)
goto error;
}
if (udev->product) {
- retval = device_create_file (dev, &dev_attr_product);
+ retval = device_create_file(dev, &dev_attr_product);
if (retval)
goto error;
}
if (udev->serial) {
- retval = device_create_file (dev, &dev_attr_serial);
+ retval = device_create_file(dev, &dev_attr_serial);
if (retval)
goto error;
}
@@ -239,47 +313,41 @@ int usb_create_sysfs_dev_files(struct usb_device *udev)
goto error;
return 0;
error:
- usb_remove_ep_files(&udev->ep0);
- device_remove_file(dev, &dev_attr_manufacturer);
- device_remove_file(dev, &dev_attr_product);
- device_remove_file(dev, &dev_attr_serial);
+ usb_remove_sysfs_dev_files(udev);
return retval;
}
-void usb_remove_sysfs_dev_files (struct usb_device *udev)
+void usb_remove_sysfs_dev_files(struct usb_device *udev)
{
struct device *dev = &udev->dev;
usb_remove_ep_files(&udev->ep0);
+ device_remove_file(dev, &dev_attr_manufacturer);
+ device_remove_file(dev, &dev_attr_product);
+ device_remove_file(dev, &dev_attr_serial);
+ remove_power_attributes(dev);
sysfs_remove_group(&dev->kobj, &dev_attr_grp);
-
- if (udev->manufacturer)
- device_remove_file(dev, &dev_attr_manufacturer);
- if (udev->product)
- device_remove_file(dev, &dev_attr_product);
- if (udev->serial)
- device_remove_file(dev, &dev_attr_serial);
}
/* Interface fields */
#define usb_intf_attr(field, format_string) \
static ssize_t \
-show_##field (struct device *dev, struct device_attribute *attr, \
+show_##field(struct device *dev, struct device_attribute *attr, \
char *buf) \
{ \
- struct usb_interface *intf = to_usb_interface (dev); \
+ struct usb_interface *intf = to_usb_interface(dev); \
\
- return sprintf (buf, format_string, \
+ return sprintf(buf, format_string, \
intf->cur_altsetting->desc.field); \
} \
static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
-usb_intf_attr (bInterfaceNumber, "%02x\n")
-usb_intf_attr (bAlternateSetting, "%2d\n")
-usb_intf_attr (bNumEndpoints, "%02x\n")
-usb_intf_attr (bInterfaceClass, "%02x\n")
-usb_intf_attr (bInterfaceSubClass, "%02x\n")
-usb_intf_attr (bInterfaceProtocol, "%02x\n")
+usb_intf_attr(bInterfaceNumber, "%02x\n")
+usb_intf_attr(bAlternateSetting, "%2d\n")
+usb_intf_attr(bNumEndpoints, "%02x\n")
+usb_intf_attr(bInterfaceClass, "%02x\n")
+usb_intf_attr(bInterfaceSubClass, "%02x\n")
+usb_intf_attr(bInterfaceProtocol, "%02x\n")
static ssize_t show_interface_string(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -288,8 +356,8 @@ static ssize_t show_interface_string(struct device *dev,
struct usb_device *udev;
int len;
- intf = to_usb_interface (dev);
- udev = interface_to_usbdev (intf);
+ intf = to_usb_interface(dev);
+ udev = interface_to_usbdev(intf);
len = snprintf(buf, 256, "%s", intf->cur_altsetting->string);
if (len < 0)
return 0;
@@ -362,33 +430,28 @@ static inline void usb_remove_intf_ep_files(struct usb_interface *intf)
int usb_create_sysfs_intf_files(struct usb_interface *intf)
{
+ struct device *dev = &intf->dev;
struct usb_device *udev = interface_to_usbdev(intf);
struct usb_host_interface *alt = intf->cur_altsetting;
int retval;
- retval = sysfs_create_group(&intf->dev.kobj, &intf_attr_grp);
+ retval = sysfs_create_group(&dev->kobj, &intf_attr_grp);
if (retval)
- goto error;
+ return retval;
if (alt->string == NULL)
alt->string = usb_cache_string(udev, alt->desc.iInterface);
if (alt->string)
- retval = device_create_file(&intf->dev, &dev_attr_interface);
+ retval = device_create_file(dev, &dev_attr_interface);
usb_create_intf_ep_files(intf, udev);
return 0;
-error:
- if (alt->string)
- device_remove_file(&intf->dev, &dev_attr_interface);
- sysfs_remove_group(&intf->dev.kobj, &intf_attr_grp);
- usb_remove_intf_ep_files(intf);
- return retval;
}
-void usb_remove_sysfs_intf_files (struct usb_interface *intf)
+void usb_remove_sysfs_intf_files(struct usb_interface *intf)
{
- usb_remove_intf_ep_files(intf);
- sysfs_remove_group(&intf->dev.kobj, &intf_attr_grp);
+ struct device *dev = &intf->dev;
- if (intf->cur_altsetting->string)
- device_remove_file(&intf->dev, &dev_attr_interface);
+ usb_remove_intf_ep_files(intf);
+ device_remove_file(dev, &dev_attr_interface);
+ sysfs_remove_group(&dev->kobj, &intf_attr_grp);
}
diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
index 9801d08edac..94ea9727ff5 100644
--- a/drivers/usb/core/urb.c
+++ b/drivers/usb/core/urb.c
@@ -235,16 +235,15 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
urb->status = -EINPROGRESS;
urb->actual_length = 0;
- urb->bandwidth = 0;
/* Lots of sanity checks, so HCDs can rely on clean data
* and don't need to duplicate tests
*/
pipe = urb->pipe;
- temp = usb_pipetype (pipe);
- is_out = usb_pipeout (pipe);
+ temp = usb_pipetype(pipe);
+ is_out = usb_pipeout(pipe);
- if (!usb_pipecontrol (pipe) && dev->state < USB_STATE_CONFIGURED)
+ if (!usb_pipecontrol(pipe) && dev->state < USB_STATE_CONFIGURED)
return -ENODEV;
/* FIXME there should be a sharable lock protecting us against
@@ -253,11 +252,11 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
* checks get made.)
*/
- max = usb_maxpacket (dev, pipe, is_out);
+ max = usb_maxpacket(dev, pipe, is_out);
if (max <= 0) {
dev_dbg(&dev->dev,
"bogus endpoint ep%d%s in %s (bad maxpacket %d)\n",
- usb_pipeendpoint (pipe), is_out ? "out" : "in",
+ usb_pipeendpoint(pipe), is_out ? "out" : "in",
__FUNCTION__, max);
return -EMSGSIZE;
}
@@ -279,11 +278,11 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
if (urb->number_of_packets <= 0)
return -EINVAL;
for (n = 0; n < urb->number_of_packets; n++) {
- len = urb->iso_frame_desc [n].length;
+ len = urb->iso_frame_desc[n].length;
if (len < 0 || len > max)
return -EMSGSIZE;
- urb->iso_frame_desc [n].status = -EXDEV;
- urb->iso_frame_desc [n].actual_length = 0;
+ urb->iso_frame_desc[n].status = -EXDEV;
+ urb->iso_frame_desc[n].actual_length = 0;
}
}
@@ -322,7 +321,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
/* fail if submitter gave bogus flags */
if (urb->transfer_flags != orig_flags) {
- err ("BOGUS urb flags, %x --> %x",
+ err("BOGUS urb flags, %x --> %x",
orig_flags, urb->transfer_flags);
return -EINVAL;
}
@@ -373,7 +372,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
urb->interval = temp;
}
- return usb_hcd_submit_urb (urb, mem_flags);
+ return usb_hcd_submit_urb(urb, mem_flags);
}
/*-------------------------------------------------------------------*/
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 02426d0b9a3..54b42ce311c 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -22,6 +22,7 @@
*/
#include <linux/module.h>
+#include <linux/moduleparam.h>
#include <linux/string.h>
#include <linux/bitops.h>
#include <linux/slab.h>
@@ -50,6 +51,16 @@ static int nousb; /* Disable USB when built into kernel image */
struct workqueue_struct *ksuspend_usb_wq; /* For autosuspend */
+#ifdef CONFIG_USB_SUSPEND
+static int usb_autosuspend_delay = 2; /* Default delay value,
+ * in seconds */
+module_param_named(autosuspend, usb_autosuspend_delay, uint, 0644);
+MODULE_PARM_DESC(autosuspend, "default autosuspend delay");
+
+#else
+#define usb_autosuspend_delay 0
+#endif
+
/**
* usb_ifnum_to_if - get the interface object with a given interface number
@@ -233,7 +244,7 @@ static void usb_autosuspend_work(struct work_struct *work)
* @parent: hub to which device is connected; null to allocate a root hub
* @bus: bus used to access the device
* @port1: one-based index of port; ignored for root hubs
- * Context: !in_interrupt ()
+ * Context: !in_interrupt()
*
* Only hub drivers (including virtual root hub drivers for host
* controllers) should ever call this.
@@ -277,22 +288,22 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
* as stable: bus->busnum changes easily from modprobe order,
* cardbus or pci hotplugging, and so on.
*/
- if (unlikely (!parent)) {
- dev->devpath [0] = '0';
+ if (unlikely(!parent)) {
+ dev->devpath[0] = '0';
dev->dev.parent = bus->controller;
- sprintf (&dev->dev.bus_id[0], "usb%d", bus->busnum);
+ sprintf(&dev->dev.bus_id[0], "usb%d", bus->busnum);
} else {
/* match any labeling on the hubs; it's one-based */
- if (parent->devpath [0] == '0')
- snprintf (dev->devpath, sizeof dev->devpath,
+ if (parent->devpath[0] == '0')
+ snprintf(dev->devpath, sizeof dev->devpath,
"%d", port1);
else
- snprintf (dev->devpath, sizeof dev->devpath,
+ snprintf(dev->devpath, sizeof dev->devpath,
"%s.%d", parent->devpath, port1);
dev->dev.parent = &parent->dev;
- sprintf (&dev->dev.bus_id[0], "%d-%s",
+ sprintf(&dev->dev.bus_id[0], "%d-%s",
bus->busnum, dev->devpath);
/* hub driver sets up TT records */
@@ -306,6 +317,7 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
#ifdef CONFIG_PM
mutex_init(&dev->pm_mutex);
INIT_DELAYED_WORK(&dev->autosuspend, usb_autosuspend_work);
+ dev->autosuspend_delay = usb_autosuspend_delay * HZ;
#endif
return dev;
}
@@ -463,7 +475,7 @@ static struct usb_device *match_device(struct usb_device *dev,
/* see if this device matches */
if ((vendor_id == le16_to_cpu(dev->descriptor.idVendor)) &&
(product_id == le16_to_cpu(dev->descriptor.idProduct))) {
- dev_dbg (&dev->dev, "matched this device!\n");
+ dev_dbg(&dev->dev, "matched this device!\n");
ret_dev = usb_get_dev(dev);
goto exit;
}
@@ -535,7 +547,7 @@ exit:
*/
int usb_get_current_frame_number(struct usb_device *dev)
{
- return usb_hcd_get_frame_number (dev);
+ return usb_hcd_get_frame_number(dev);
}
/*-------------------------------------------------------------------*/
@@ -593,7 +605,7 @@ int __usb_get_extra_descriptor(char *buffer, unsigned size,
*
* When the buffer is no longer used, free it with usb_buffer_free().
*/
-void *usb_buffer_alloc (
+void *usb_buffer_alloc(
struct usb_device *dev,
size_t size,
gfp_t mem_flags,
@@ -602,7 +614,7 @@ void *usb_buffer_alloc (
{
if (!dev || !dev->bus)
return NULL;
- return hcd_buffer_alloc (dev->bus, size, mem_flags, dma);
+ return hcd_buffer_alloc(dev->bus, size, mem_flags, dma);
}
/**
@@ -616,7 +628,7 @@ void *usb_buffer_alloc (
* been allocated using usb_buffer_alloc(), and the parameters must match
* those provided in that allocation request.
*/
-void usb_buffer_free (
+void usb_buffer_free(
struct usb_device *dev,
size_t size,
void *addr,
@@ -627,7 +639,7 @@ void usb_buffer_free (
return;
if (!addr)
return;
- hcd_buffer_free (dev->bus, size, addr, dma);
+ hcd_buffer_free(dev->bus, size, addr, dma);
}
/**
@@ -647,7 +659,7 @@ void usb_buffer_free (
* Reverse the effect of this call with usb_buffer_unmap().
*/
#if 0
-struct urb *usb_buffer_map (struct urb *urb)
+struct urb *usb_buffer_map(struct urb *urb)
{
struct usb_bus *bus;
struct device *controller;
@@ -659,14 +671,14 @@ struct urb *usb_buffer_map (struct urb *urb)
return NULL;
if (controller->dma_mask) {
- urb->transfer_dma = dma_map_single (controller,
+ urb->transfer_dma = dma_map_single(controller,
urb->transfer_buffer, urb->transfer_buffer_length,
- usb_pipein (urb->pipe)
+ usb_pipein(urb->pipe)
? DMA_FROM_DEVICE : DMA_TO_DEVICE);
- if (usb_pipecontrol (urb->pipe))
- urb->setup_dma = dma_map_single (controller,
+ if (usb_pipecontrol(urb->pipe))
+ urb->setup_dma = dma_map_single(controller,
urb->setup_packet,
- sizeof (struct usb_ctrlrequest),
+ sizeof(struct usb_ctrlrequest),
DMA_TO_DEVICE);
// FIXME generic api broken like pci, can't report errors
// if (urb->transfer_dma == DMA_ADDR_INVALID) return 0;
@@ -689,7 +701,7 @@ struct urb *usb_buffer_map (struct urb *urb)
* usb_buffer_dmasync - synchronize DMA and CPU view of buffer(s)
* @urb: urb whose transfer_buffer/setup_packet will be synchronized
*/
-void usb_buffer_dmasync (struct urb *urb)
+void usb_buffer_dmasync(struct urb *urb)
{
struct usb_bus *bus;
struct device *controller;
@@ -702,14 +714,14 @@ void usb_buffer_dmasync (struct urb *urb)
return;
if (controller->dma_mask) {
- dma_sync_single (controller,
+ dma_sync_single(controller,
urb->transfer_dma, urb->transfer_buffer_length,
- usb_pipein (urb->pipe)
+ usb_pipein(urb->pipe)
? DMA_FROM_DEVICE : DMA_TO_DEVICE);
- if (usb_pipecontrol (urb->pipe))
- dma_sync_single (controller,
+ if (usb_pipecontrol(urb->pipe))
+ dma_sync_single(controller,
urb->setup_dma,
- sizeof (struct usb_ctrlrequest),
+ sizeof(struct usb_ctrlrequest),
DMA_TO_DEVICE);
}
}
@@ -722,7 +734,7 @@ void usb_buffer_dmasync (struct urb *urb)
* Reverses the effect of usb_buffer_map().
*/
#if 0
-void usb_buffer_unmap (struct urb *urb)
+void usb_buffer_unmap(struct urb *urb)
{
struct usb_bus *bus;
struct device *controller;
@@ -735,14 +747,14 @@ void usb_buffer_unmap (struct urb *urb)
return;
if (controller->dma_mask) {
- dma_unmap_single (controller,
+ dma_unmap_single(controller,
urb->transfer_dma, urb->transfer_buffer_length,
- usb_pipein (urb->pipe)
+ usb_pipein(urb->pipe)
? DMA_FROM_DEVICE : DMA_TO_DEVICE);
- if (usb_pipecontrol (urb->pipe))
- dma_unmap_single (controller,
+ if (usb_pipecontrol(urb->pipe))
+ dma_unmap_single(controller,
urb->setup_dma,
- sizeof (struct usb_ctrlrequest),
+ sizeof(struct usb_ctrlrequest),
DMA_TO_DEVICE);
}
urb->transfer_flags &= ~(URB_NO_TRANSFER_DMA_MAP
@@ -783,15 +795,15 @@ int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe,
struct device *controller;
if (!dev
- || usb_pipecontrol (pipe)
+ || usb_pipecontrol(pipe)
|| !(bus = dev->bus)
|| !(controller = bus->controller)
|| !controller->dma_mask)
return -1;
// FIXME generic api broken like pci, can't report errors
- return dma_map_sg (controller, sg, nents,
- usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+ return dma_map_sg(controller, sg, nents,
+ usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
/* XXX DISABLED, no users currently. If you wish to re-enable this
@@ -823,8 +835,8 @@ void usb_buffer_dmasync_sg(const struct usb_device *dev, unsigned pipe,
|| !controller->dma_mask)
return;
- dma_sync_sg (controller, sg, n_hw_ents,
- usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+ dma_sync_sg(controller, sg, n_hw_ents,
+ usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
#endif
@@ -849,8 +861,8 @@ void usb_buffer_unmap_sg(const struct usb_device *dev, unsigned pipe,
|| !controller->dma_mask)
return;
- dma_unmap_sg (controller, sg, n_hw_ents,
- usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+ dma_unmap_sg(controller, sg, n_hw_ents,
+ usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
/* format to disable USB on kernel command line is: nousb */
@@ -871,7 +883,7 @@ static int __init usb_init(void)
{
int retval;
if (nousb) {
- pr_info ("%s: USB support disabled\n", usbcore_name);
+ pr_info("%s: USB support disabled\n", usbcore_name);
return 0;
}
@@ -971,19 +983,19 @@ EXPORT_SYMBOL(__usb_get_extra_descriptor);
EXPORT_SYMBOL(usb_find_device);
EXPORT_SYMBOL(usb_get_current_frame_number);
-EXPORT_SYMBOL (usb_buffer_alloc);
-EXPORT_SYMBOL (usb_buffer_free);
+EXPORT_SYMBOL(usb_buffer_alloc);
+EXPORT_SYMBOL(usb_buffer_free);
#if 0
-EXPORT_SYMBOL (usb_buffer_map);
-EXPORT_SYMBOL (usb_buffer_dmasync);
-EXPORT_SYMBOL (usb_buffer_unmap);
+EXPORT_SYMBOL(usb_buffer_map);
+EXPORT_SYMBOL(usb_buffer_dmasync);
+EXPORT_SYMBOL(usb_buffer_unmap);
#endif
-EXPORT_SYMBOL (usb_buffer_map_sg);
+EXPORT_SYMBOL(usb_buffer_map_sg);
#if 0
-EXPORT_SYMBOL (usb_buffer_dmasync_sg);
+EXPORT_SYMBOL(usb_buffer_dmasync_sg);
#endif
-EXPORT_SYMBOL (usb_buffer_unmap_sg);
+EXPORT_SYMBOL(usb_buffer_unmap_sg);
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index 17830a81be1..08b5a04e375 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -13,6 +13,7 @@ extern void usb_disable_interface (struct usb_device *dev,
struct usb_interface *intf);
extern void usb_release_interface_cache(struct kref *ref);
extern void usb_disable_device (struct usb_device *dev, int skip_ep0);
+extern void usb_detect_quirks(struct usb_device *udev);
extern int usb_get_device_descriptor(struct usb_device *dev,
unsigned int size);
@@ -21,6 +22,8 @@ extern int usb_set_configuration(struct usb_device *dev, int configuration);
extern void usb_kick_khubd(struct usb_device *dev);
extern void usb_resume_root_hub(struct usb_device *dev);
+extern int usb_match_device(struct usb_device *dev,
+ const struct usb_device_id *id);
extern int usb_hub_init(void);
extern void usb_hub_cleanup(void);
@@ -62,14 +65,14 @@ static inline void usb_pm_unlock(struct usb_device *udev) {}
#ifdef CONFIG_USB_SUSPEND
-#define USB_AUTOSUSPEND_DELAY (HZ*2)
-
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);
#else
-#define usb_autosuspend_device(udev) do {} while (0)
+#define usb_autosuspend_device(udev) do {} while (0)
+#define usb_try_autosuspend_device(udev) do {} while (0)
static inline int usb_autoresume_device(struct usb_device *udev)
{
return 0;
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
index 812c733ba8c..a4677802fb2 100644
--- a/drivers/usb/gadget/at91_udc.c
+++ b/drivers/usb/gadget/at91_udc.c
@@ -30,7 +30,6 @@
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/ioport.h>
-#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/smp_lock.h>
#include <linux/errno.h>
@@ -39,7 +38,7 @@
#include <linux/interrupt.h>
#include <linux/proc_fs.h>
#include <linux/clk.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include <asm/byteorder.h>
@@ -785,7 +784,7 @@ static int at91_ep_set_halt(struct usb_ep *_ep, int value)
return status;
}
-static struct usb_ep_ops at91_ep_ops = {
+static const struct usb_ep_ops at91_ep_ops = {
.enable = at91_ep_enable,
.disable = at91_ep_disable,
.alloc_request = at91_ep_alloc_request,
@@ -913,7 +912,7 @@ static void pullup(struct at91_udc *udc, int is_on)
at91_udp_write(udc, AT91_UDP_TXVC, 0);
if (cpu_is_at91rm9200())
at91_set_gpio_value(udc->board.pullup_pin, 1);
- else if (cpu_is_at91sam9260()) {
+ else if (cpu_is_at91sam9260() || cpu_is_at91sam9263()) {
u32 txvc = at91_udp_read(udc, AT91_UDP_TXVC);
txvc |= AT91_UDP_TXVC_PUON;
@@ -930,7 +929,7 @@ static void pullup(struct at91_udc *udc, int is_on)
at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS);
if (cpu_is_at91rm9200())
at91_set_gpio_value(udc->board.pullup_pin, 0);
- else if (cpu_is_at91sam9260()) {
+ else if (cpu_is_at91sam9260() || cpu_is_at91sam9263()) {
u32 txvc = at91_udp_read(udc, AT91_UDP_TXVC);
txvc &= ~AT91_UDP_TXVC_PUON;
@@ -1652,7 +1651,7 @@ static void at91udc_shutdown(struct platform_device *dev)
pullup(platform_get_drvdata(dev), 0);
}
-static int __devinit at91udc_probe(struct platform_device *pdev)
+static int __init at91udc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct at91_udc *udc;
@@ -1763,7 +1762,7 @@ fail0:
return retval;
}
-static int __devexit at91udc_remove(struct platform_device *pdev)
+static int __exit at91udc_remove(struct platform_device *pdev)
{
struct at91_udc *udc = platform_get_drvdata(pdev);
struct resource *res;
@@ -1807,16 +1806,13 @@ static int at91udc_suspend(struct platform_device *pdev, pm_message_t mesg)
|| !wake
|| at91_suspend_entering_slow_clock()) {
pullup(udc, 0);
- disable_irq_wake(udc->udp_irq);
+ wake = 0;
} else
enable_irq_wake(udc->udp_irq);
- if (udc->board.vbus_pin > 0) {
- if (wake)
- enable_irq_wake(udc->board.vbus_pin);
- else
- disable_irq_wake(udc->board.vbus_pin);
- }
+ udc->active_suspend = wake;
+ if (udc->board.vbus_pin > 0 && wake)
+ enable_irq_wake(udc->board.vbus_pin);
return 0;
}
@@ -1824,8 +1820,14 @@ static int at91udc_resume(struct platform_device *pdev)
{
struct at91_udc *udc = platform_get_drvdata(pdev);
+ if (udc->board.vbus_pin > 0 && udc->active_suspend)
+ disable_irq_wake(udc->board.vbus_pin);
+
/* maybe reconnect to host; if so, clocks on */
- pullup(udc, 1);
+ if (udc->active_suspend)
+ disable_irq_wake(udc->udp_irq);
+ else
+ pullup(udc, 1);
return 0;
}
#else
@@ -1834,8 +1836,7 @@ static int at91udc_resume(struct platform_device *pdev)
#endif
static struct platform_driver at91_udc = {
- .probe = at91udc_probe,
- .remove = __devexit_p(at91udc_remove),
+ .remove = __exit_p(at91udc_remove),
.shutdown = at91udc_shutdown,
.suspend = at91udc_suspend,
.resume = at91udc_resume,
@@ -1845,13 +1846,13 @@ static struct platform_driver at91_udc = {
},
};
-static int __devinit udc_init_module(void)
+static int __init udc_init_module(void)
{
- return platform_driver_register(&at91_udc);
+ return platform_driver_probe(&at91_udc, at91udc_probe);
}
module_init(udc_init_module);
-static void __devexit udc_exit_module(void)
+static void __exit udc_exit_module(void)
{
platform_driver_unregister(&at91_udc);
}
diff --git a/drivers/usb/gadget/at91_udc.h b/drivers/usb/gadget/at91_udc.h
index 677089baa59..7e34e2f864f 100644
--- a/drivers/usb/gadget/at91_udc.h
+++ b/drivers/usb/gadget/at91_udc.h
@@ -136,6 +136,7 @@ struct at91_udc {
unsigned wait_for_addr_ack:1;
unsigned wait_for_config_ack:1;
unsigned selfpowered:1;
+ unsigned active_suspend:1;
u8 addr;
struct at91_udc_data board;
struct clk *iclk, *fclk;
diff --git a/drivers/usb/gadget/config.c b/drivers/usb/gadget/config.c
index 83b4866df9a..d18901b92cd 100644
--- a/drivers/usb/gadget/config.c
+++ b/drivers/usb/gadget/config.c
@@ -24,7 +24,7 @@
#include <linux/string.h>
#include <linux/device.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index 3c2bc075ef4..7d7909cf255 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -40,7 +40,6 @@
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ioport.h>
-#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/smp_lock.h>
#include <linux/errno.h>
diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c
index 53d584589c2..f28af06905a 100644
--- a/drivers/usb/gadget/epautoconf.c
+++ b/drivers/usb/gadget/epautoconf.c
@@ -27,7 +27,7 @@
#include <linux/ctype.h>
#include <linux/string.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include "gadget_chips.h"
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index d15bf22b9a0..04e6b8508fb 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -27,7 +27,6 @@
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ioport.h>
-#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/smp_lock.h>
#include <linux/errno.h>
@@ -47,7 +46,7 @@
#include <asm/uaccess.h>
#include <asm/unaligned.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
#include <linux/usb/cdc.h>
#include <linux/usb_gadget.h>
@@ -72,9 +71,18 @@
*
* There's some hardware that can't talk CDC. We make that hardware
* implement a "minimalist" vendor-agnostic CDC core: same framing, but
- * link-level setup only requires activating the configuration.
- * Linux supports it, but other host operating systems may not.
- * (This is a subset of CDC Ethernet.)
+ * link-level setup only requires activating the configuration. Only the
+ * endpoint descriptors, and product/vendor IDs, are relevant; no control
+ * operations are available. Linux supports it, but other host operating
+ * systems may not. (This is a subset of CDC Ethernet.)
+ *
+ * It turns out that if you add a few descriptors to that "CDC Subset",
+ * (Windows) host side drivers from MCCI can treat it as one submode of
+ * a proprietary scheme called "SAFE" ... without needing to know about
+ * specific product/vendor IDs. So we do that, making it easier to use
+ * those MS-Windows drivers. Those added descriptors make it resemble a
+ * CDC MDLM device, but they don't change device behavior at all. (See
+ * MCCI Engineering report 950198 "SAFE Networking Functions".)
*
* A third option is also in use. Rather than CDC Ethernet, or something
* simpler, Microsoft pushes their own approach: RNDIS. The published
@@ -254,6 +262,10 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
#define DEV_CONFIG_CDC
#endif
+#ifdef CONFIG_USB_GADGET_S3C2410
+#define DEV_CONFIG_CDC
+#endif
+
#ifdef CONFIG_USB_GADGET_AT91
#define DEV_CONFIG_CDC
#endif
@@ -266,6 +278,10 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
#define DEV_CONFIG_CDC
#endif
+#ifdef CONFIG_USB_GADGET_HUSB2DEV
+#define DEV_CONFIG_CDC
+#endif
+
/* For CDC-incapable hardware, choose the simple cdc subset.
* Anything that talks bulk (without notable bugs) can do this.
@@ -283,9 +299,6 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
#define DEV_CONFIG_SUBSET
#endif
-#ifdef CONFIG_USB_GADGET_S3C2410
-#define DEV_CONFIG_CDC
-#endif
/*-------------------------------------------------------------------------*/
@@ -487,8 +500,17 @@ rndis_config = {
* endpoint. Both have a "data" interface and two bulk endpoints.
* There are also differences in how control requests are handled.
*
- * RNDIS shares a lot with CDC-Ethernet, since it's a variant of
- * the CDC-ACM (modem) spec.
+ * RNDIS shares a lot with CDC-Ethernet, since it's a variant of the
+ * CDC-ACM (modem) spec. Unfortunately MSFT's RNDIS driver is buggy; it
+ * may hang or oops. Since bugfixes (or accurate specs, letting Linux
+ * work around those bugs) are unlikely to ever come from MSFT, you may
+ * wish to avoid using RNDIS.
+ *
+ * MCCI offers an alternative to RNDIS if you need to connect to Windows
+ * but have hardware that can't support CDC Ethernet. We add descriptors
+ * to present the CDC Subset as a (nonconformant) CDC MDLM variant called
+ * "SAFE". That borrows from both CDC Ethernet and CDC MDLM. You can
+ * get those drivers from MCCI, or bundled with various products.
*/
#ifdef DEV_CONFIG_CDC
@@ -522,8 +544,6 @@ rndis_control_intf = {
};
#endif
-#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
-
static const struct usb_cdc_header_desc header_desc = {
.bLength = sizeof header_desc,
.bDescriptorType = USB_DT_CS_INTERFACE,
@@ -532,6 +552,8 @@ static const struct usb_cdc_header_desc header_desc = {
.bcdCDC = __constant_cpu_to_le16 (0x0110),
};
+#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
+
static const struct usb_cdc_union_desc union_desc = {
.bLength = sizeof union_desc,
.bDescriptorType = USB_DT_CS_INTERFACE,
@@ -564,7 +586,40 @@ static const struct usb_cdc_acm_descriptor acm_descriptor = {
#endif
-#ifdef DEV_CONFIG_CDC
+#ifndef DEV_CONFIG_CDC
+
+/* "SAFE" loosely follows CDC WMC MDLM, violating the spec in various
+ * ways: data endpoints live in the control interface, there's no data
+ * interface, and it's not used to talk to a cell phone radio.
+ */
+
+static const struct usb_cdc_mdlm_desc mdlm_desc = {
+ .bLength = sizeof mdlm_desc,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubType = USB_CDC_MDLM_TYPE,
+
+ .bcdVersion = __constant_cpu_to_le16(0x0100),
+ .bGUID = {
+ 0x5d, 0x34, 0xcf, 0x66, 0x11, 0x18, 0x11, 0xd6,
+ 0xa2, 0x1a, 0x00, 0x01, 0x02, 0xca, 0x9a, 0x7f,
+ },
+};
+
+/* since "usb_cdc_mdlm_detail_desc" is a variable length structure, we
+ * can't really use its struct. All we do here is say that we're using
+ * the submode of "SAFE" which directly matches the CDC Subset.
+ */
+static const u8 mdlm_detail_desc[] = {
+ 6,
+ USB_DT_CS_INTERFACE,
+ USB_CDC_MDLM_DETAIL_TYPE,
+
+ 0, /* "SAFE" */
+ 0, /* network control capabilities (none) */
+ 0, /* network data capabilities ("raw" encapsulation) */
+};
+
+#endif
static const struct usb_cdc_ether_desc ether_desc = {
.bLength = sizeof ether_desc,
@@ -579,7 +634,6 @@ static const struct usb_cdc_ether_desc ether_desc = {
.bNumberPowerFilters = 0,
};
-#endif
#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
@@ -672,6 +726,9 @@ rndis_data_intf = {
/*
* "Simple" CDC-subset option is a simple vendor-neutral model that most
* full speed controllers can handle: one interface, two bulk endpoints.
+ *
+ * To assist host side drivers, we fancy it up a bit, and add descriptors
+ * so some host side drivers will understand it as a "SAFE" variant.
*/
static const struct usb_interface_descriptor
@@ -682,8 +739,8 @@ subset_data_intf = {
.bInterfaceNumber = 0,
.bAlternateSetting = 0,
.bNumEndpoints = 2,
- .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
- .bInterfaceSubClass = 0,
+ .bInterfaceClass = USB_CLASS_COMM,
+ .bInterfaceSubClass = USB_CDC_SUBCLASS_MDLM,
.bInterfaceProtocol = 0,
.iInterface = STRING_DATA,
};
@@ -731,10 +788,15 @@ static const struct usb_descriptor_header *fs_eth_function [11] = {
static inline void __init fs_subset_descriptors(void)
{
#ifdef DEV_CONFIG_SUBSET
+ /* behavior is "CDC Subset"; extra descriptors say "SAFE" */
fs_eth_function[1] = (struct usb_descriptor_header *) &subset_data_intf;
- fs_eth_function[2] = (struct usb_descriptor_header *) &fs_source_desc;
- fs_eth_function[3] = (struct usb_descriptor_header *) &fs_sink_desc;
- fs_eth_function[4] = NULL;
+ fs_eth_function[2] = (struct usb_descriptor_header *) &header_desc;
+ fs_eth_function[3] = (struct usb_descriptor_header *) &mdlm_desc;
+ fs_eth_function[4] = (struct usb_descriptor_header *) &mdlm_detail_desc;
+ fs_eth_function[5] = (struct usb_descriptor_header *) &ether_desc;
+ fs_eth_function[6] = (struct usb_descriptor_header *) &fs_source_desc;
+ fs_eth_function[7] = (struct usb_descriptor_header *) &fs_sink_desc;
+ fs_eth_function[8] = NULL;
#else
fs_eth_function[1] = NULL;
#endif
@@ -828,10 +890,15 @@ static const struct usb_descriptor_header *hs_eth_function [11] = {
static inline void __init hs_subset_descriptors(void)
{
#ifdef DEV_CONFIG_SUBSET
+ /* behavior is "CDC Subset"; extra descriptors say "SAFE" */
hs_eth_function[1] = (struct usb_descriptor_header *) &subset_data_intf;
- hs_eth_function[2] = (struct usb_descriptor_header *) &fs_source_desc;
- hs_eth_function[3] = (struct usb_descriptor_header *) &fs_sink_desc;
- hs_eth_function[4] = NULL;
+ hs_eth_function[2] = (struct usb_descriptor_header *) &header_desc;
+ hs_eth_function[3] = (struct usb_descriptor_header *) &mdlm_desc;
+ hs_eth_function[4] = (struct usb_descriptor_header *) &mdlm_detail_desc;
+ hs_eth_function[5] = (struct usb_descriptor_header *) &ether_desc;
+ hs_eth_function[6] = (struct usb_descriptor_header *) &hs_source_desc;
+ hs_eth_function[7] = (struct usb_descriptor_header *) &hs_sink_desc;
+ hs_eth_function[8] = NULL;
#else
hs_eth_function[1] = NULL;
#endif
@@ -878,10 +945,8 @@ static char manufacturer [50];
static char product_desc [40] = DRIVER_DESC;
static char serial_number [20];
-#ifdef DEV_CONFIG_CDC
/* address that the host will use ... usually assigned at random */
static char ethaddr [2 * ETH_ALEN + 1];
-#endif
/* static strings, in UTF-8 */
static struct usb_string strings [] = {
@@ -889,9 +954,9 @@ static struct usb_string strings [] = {
{ STRING_PRODUCT, product_desc, },
{ STRING_SERIALNUMBER, serial_number, },
{ STRING_DATA, "Ethernet Data", },
+ { STRING_ETHADDR, ethaddr, },
#ifdef DEV_CONFIG_CDC
{ STRING_CDC, "CDC Ethernet", },
- { STRING_ETHADDR, ethaddr, },
{ STRING_CONTROL, "CDC Communications Control", },
#endif
#ifdef DEV_CONFIG_SUBSET
@@ -986,10 +1051,10 @@ set_ether_config (struct eth_dev *dev, gfp_t gfp_flags)
}
#endif
- dev->in = ep_desc (dev->gadget, &hs_source_desc, &fs_source_desc);
+ dev->in = ep_desc(gadget, &hs_source_desc, &fs_source_desc);
dev->in_ep->driver_data = dev;
- dev->out = ep_desc (dev->gadget, &hs_sink_desc, &fs_sink_desc);
+ dev->out = ep_desc(gadget, &hs_sink_desc, &fs_sink_desc);
dev->out_ep->driver_data = dev;
/* With CDC, the host isn't allowed to use these two data
@@ -2278,10 +2343,10 @@ eth_bind (struct usb_gadget *gadget)
"RNDIS/%s", driver_desc);
/* CDC subset ... recognized by Linux since 2.4.10, but Windows
- * drivers aren't widely available.
+ * drivers aren't widely available. (That may be improved by
+ * supporting one submode of the "SAFE" variant of MDLM.)
*/
} else if (!cdc) {
- device_desc.bDeviceClass = USB_CLASS_VENDOR_SPEC;
device_desc.idVendor =
__constant_cpu_to_le16(SIMPLE_VENDOR_NUM);
device_desc.idProduct =
@@ -2352,6 +2417,10 @@ autoconf_fail:
if (!cdc) {
eth_config.bNumInterfaces = 1;
eth_config.iConfiguration = STRING_SUBSET;
+
+ /* use functions to set these up, in case we're built to work
+ * with multiple controllers and must override CDC Ethernet.
+ */
fs_subset_descriptors();
hs_subset_descriptors();
}
@@ -2415,22 +2484,20 @@ autoconf_fail:
/* Module params for these addresses should come from ID proms.
* The host side address is used with CDC and RNDIS, and commonly
- * ends up in a persistent config database.
+ * ends up in a persistent config database. It's not clear if
+ * host side code for the SAFE thing cares -- its original BLAN
+ * thing didn't, Sharp never assigned those addresses on Zaurii.
*/
if (get_ether_addr(dev_addr, net->dev_addr))
dev_warn(&gadget->dev,
"using random %s ethernet address\n", "self");
- if (cdc || rndis) {
- if (get_ether_addr(host_addr, dev->host_mac))
- dev_warn(&gadget->dev,
- "using random %s ethernet address\n", "host");
-#ifdef DEV_CONFIG_CDC
- snprintf (ethaddr, sizeof ethaddr, "%02X%02X%02X%02X%02X%02X",
- dev->host_mac [0], dev->host_mac [1],
- dev->host_mac [2], dev->host_mac [3],
- dev->host_mac [4], dev->host_mac [5]);
-#endif
- }
+ if (get_ether_addr(host_addr, dev->host_mac))
+ dev_warn(&gadget->dev,
+ "using random %s ethernet address\n", "host");
+ snprintf (ethaddr, sizeof ethaddr, "%02X%02X%02X%02X%02X%02X",
+ dev->host_mac [0], dev->host_mac [1],
+ dev->host_mac [2], dev->host_mac [3],
+ dev->host_mac [4], dev->host_mac [5]);
if (rndis) {
status = rndis_init();
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index 72f2ae96fbf..c6b6479fa4d 100644
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -253,7 +253,7 @@
#include <linux/freezer.h>
#include <linux/utsname.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include "gadget_chips.h"
@@ -1148,7 +1148,7 @@ static int ep0_queue(struct fsg_dev *fsg)
static void ep0_complete(struct usb_ep *ep, struct usb_request *req)
{
- struct fsg_dev *fsg = (struct fsg_dev *) ep->driver_data;
+ struct fsg_dev *fsg = ep->driver_data;
if (req->actual > 0)
dump_msg(fsg, fsg->ep0req_name, req->buf, req->actual);
@@ -1170,8 +1170,8 @@ static void ep0_complete(struct usb_ep *ep, struct usb_request *req)
static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req)
{
- struct fsg_dev *fsg = (struct fsg_dev *) ep->driver_data;
- struct fsg_buffhd *bh = (struct fsg_buffhd *) req->context;
+ struct fsg_dev *fsg = ep->driver_data;
+ struct fsg_buffhd *bh = req->context;
if (req->status || req->actual != req->length)
DBG(fsg, "%s --> %d, %u/%u\n", __FUNCTION__,
@@ -1190,8 +1190,8 @@ static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req)
static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req)
{
- struct fsg_dev *fsg = (struct fsg_dev *) ep->driver_data;
- struct fsg_buffhd *bh = (struct fsg_buffhd *) req->context;
+ struct fsg_dev *fsg = ep->driver_data;
+ struct fsg_buffhd *bh = req->context;
dump_msg(fsg, "bulk-out", req->buf, req->actual);
if (req->status || req->actual != bh->bulk_out_intended_length)
@@ -1214,8 +1214,8 @@ static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req)
#ifdef CONFIG_USB_FILE_STORAGE_TEST
static void intr_in_complete(struct usb_ep *ep, struct usb_request *req)
{
- struct fsg_dev *fsg = (struct fsg_dev *) ep->driver_data;
- struct fsg_buffhd *bh = (struct fsg_buffhd *) req->context;
+ struct fsg_dev *fsg = ep->driver_data;
+ struct fsg_buffhd *bh = req->context;
if (req->status || req->actual != req->length)
DBG(fsg, "%s --> %d, %u/%u\n", __FUNCTION__,
@@ -1953,7 +1953,7 @@ static void invalidate_sub(struct lun *curlun)
struct inode *inode = filp->f_path.dentry->d_inode;
unsigned long rc;
- rc = invalidate_inode_pages(inode->i_mapping);
+ rc = invalidate_mapping_pages(inode->i_mapping, 0, -1);
VLDBG(curlun, "invalidate_inode_pages -> %ld\n", rc);
}
@@ -2577,7 +2577,7 @@ static int send_status(struct fsg_dev *fsg)
}
if (transport_is_bbb()) {
- struct bulk_cs_wrap *csw = (struct bulk_cs_wrap *) bh->buf;
+ struct bulk_cs_wrap *csw = bh->buf;
/* Store and send the Bulk-only CSW */
csw->Signature = __constant_cpu_to_le32(USB_BULK_CS_SIG);
@@ -2596,8 +2596,7 @@ static int send_status(struct fsg_dev *fsg)
return 0;
} else { // USB_PR_CBI
- struct interrupt_data *buf = (struct interrupt_data *)
- bh->buf;
+ struct interrupt_data *buf = bh->buf;
/* Store and send the Interrupt data. UFI sends the ASC
* and ASCQ bytes. Everything else sends a Type (which
@@ -2982,7 +2981,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
{
struct usb_request *req = bh->outreq;
- struct bulk_cb_wrap *cbw = (struct bulk_cb_wrap *) req->buf;
+ struct bulk_cb_wrap *cbw = req->buf;
/* Was this a real packet? */
if (req->status)
@@ -3428,7 +3427,7 @@ static void handle_exception(struct fsg_dev *fsg)
static int fsg_main_thread(void *fsg_)
{
- struct fsg_dev *fsg = (struct fsg_dev *) fsg_;
+ struct fsg_dev *fsg = fsg_;
/* Allow the thread to be killed by a signal, but set the signal mask
* to block everything but INT, TERM, KILL, and USR1. */
@@ -3600,7 +3599,7 @@ static ssize_t show_ro(struct device *dev, struct device_attribute *attr, char *
static ssize_t show_file(struct device *dev, struct device_attribute *attr, char *buf)
{
struct lun *curlun = dev_to_lun(dev);
- struct fsg_dev *fsg = (struct fsg_dev *) dev_get_drvdata(dev);
+ struct fsg_dev *fsg = dev_get_drvdata(dev);
char *p;
ssize_t rc;
@@ -3629,7 +3628,7 @@ static ssize_t store_ro(struct device *dev, struct device_attribute *attr, const
{
ssize_t rc = count;
struct lun *curlun = dev_to_lun(dev);
- struct fsg_dev *fsg = (struct fsg_dev *) dev_get_drvdata(dev);
+ struct fsg_dev *fsg = dev_get_drvdata(dev);
int i;
if (sscanf(buf, "%d", &i) != 1)
@@ -3652,7 +3651,7 @@ static ssize_t store_ro(struct device *dev, struct device_attribute *attr, const
static ssize_t store_file(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct lun *curlun = dev_to_lun(dev);
- struct fsg_dev *fsg = (struct fsg_dev *) dev_get_drvdata(dev);
+ struct fsg_dev *fsg = dev_get_drvdata(dev);
int rc = 0;
if (curlun->prevent_medium_removal && backing_file_is_open(curlun)) {
@@ -3700,7 +3699,7 @@ static void fsg_release(struct kref *ref)
static void lun_release(struct device *dev)
{
- struct fsg_dev *fsg = (struct fsg_dev *) dev_get_drvdata(dev);
+ struct fsg_dev *fsg = dev_get_drvdata(dev);
kref_put(&fsg->ref, fsg_release);
}
diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
index aa80f091072..2e3d6620d21 100644
--- a/drivers/usb/gadget/gadget_chips.h
+++ b/drivers/usb/gadget/gadget_chips.h
@@ -75,6 +75,12 @@
#define gadget_is_pxa27x(g) 0
#endif
+#ifdef CONFIG_USB_GADGET_HUSB2DEV
+#define gadget_is_husb2dev(g) !strcmp("husb2_udc", (g)->name)
+#else
+#define gadget_is_husb2dev(g) 0
+#endif
+
#ifdef CONFIG_USB_GADGET_S3C2410
#define gadget_is_s3c2410(g) !strcmp("s3c2410_udc", (g)->name)
#else
@@ -169,5 +175,7 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
return 0x16;
else if (gadget_is_mpc8272(gadget))
return 0x17;
+ else if (gadget_is_husb2dev(gadget))
+ return 0x18;
return -ENOENT;
}
diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c
index f1a679656c9..d08a8d0e642 100644
--- a/drivers/usb/gadget/gmidi.c
+++ b/drivers/usb/gadget/gmidi.c
@@ -35,7 +35,7 @@
#include <sound/initval.h>
#include <sound/rawmidi.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include <linux/usb/audio.h>
#include <linux/usb/midi.h>
diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c
index d0ef1d6b3fa..7b3a326b57a 100644
--- a/drivers/usb/gadget/goku_udc.c
+++ b/drivers/usb/gadget/goku_udc.c
@@ -29,7 +29,6 @@
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/ioport.h>
-#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/smp_lock.h>
#include <linux/errno.h>
@@ -39,7 +38,7 @@
#include <linux/interrupt.h>
#include <linux/proc_fs.h>
#include <linux/device.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include <asm/byteorder.h>
diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c
index 3fb1044a4db..188c74a9521 100644
--- a/drivers/usb/gadget/inode.c
+++ b/drivers/usb/gadget/inode.c
@@ -20,7 +20,7 @@
*/
-// #define DEBUG /* data to help fault diagnosis */
+// #define DEBUG /* data to help fault diagnosis */
// #define VERBOSE /* extra debug messages (success too) */
#include <linux/init.h>
@@ -59,11 +59,11 @@
* may serve as a source of device events, used to handle all control
* requests other than basic enumeration.
*
- * - Then either immediately, or after a SET_CONFIGURATION control request,
- * ep_config() is called when each /dev/gadget/ep* file is configured
- * (by writing endpoint descriptors). Afterwards these files are used
- * to write() IN data or to read() OUT data. To halt the endpoint, a
- * "wrong direction" request is issued (like reading an IN endpoint).
+ * - Then, after a SET_CONFIGURATION control request, ep_config() is
+ * called when each /dev/gadget/ep* file is configured (by writing
+ * endpoint descriptors). Afterwards these files are used to write()
+ * IN data or to read() OUT data. To halt the endpoint, a "wrong
+ * direction" request is issued (like reading an IN endpoint).
*
* Unlike "usbfs" the only ioctl()s are for things that are rare, and maybe
* not possible on all hardware. For example, precise fault handling with
@@ -98,16 +98,16 @@ enum ep0_state {
* must always write descriptors to initialize the device, then
* the device becomes UNCONNECTED until enumeration.
*/
- STATE_OPENED,
+ STATE_DEV_OPENED,
/* From then on, ep0 fd is in either of two basic modes:
* - (UN)CONNECTED: read usb_gadgetfs_event(s) from it
* - SETUP: read/write will transfer control data and succeed;
* or if "wrong direction", performs protocol stall
*/
- STATE_UNCONNECTED,
- STATE_CONNECTED,
- STATE_SETUP,
+ STATE_DEV_UNCONNECTED,
+ STATE_DEV_CONNECTED,
+ STATE_DEV_SETUP,
/* UNBOUND means the driver closed ep0, so the device won't be
* accessible again (DEV_DISABLED) until all fds are closed.
@@ -121,7 +121,7 @@ enum ep0_state {
struct dev_data {
spinlock_t lock;
atomic_t count;
- enum ep0_state state;
+ enum ep0_state state; /* P: lock */
struct usb_gadgetfs_event event [N_EVENT];
unsigned ev_next;
struct fasync_struct *fasync;
@@ -188,7 +188,6 @@ static struct dev_data *dev_new (void)
enum ep_state {
STATE_EP_DISABLED = 0,
STATE_EP_READY,
- STATE_EP_DEFER_ENABLE,
STATE_EP_ENABLED,
STATE_EP_UNBOUND,
};
@@ -313,18 +312,10 @@ nonblock:
if ((val = down_interruptible (&epdata->lock)) < 0)
return val;
-newstate:
+
switch (epdata->state) {
case STATE_EP_ENABLED:
break;
- case STATE_EP_DEFER_ENABLE:
- DBG (epdata->dev, "%s wait for host\n", epdata->name);
- if ((val = wait_event_interruptible (epdata->wait,
- epdata->state != STATE_EP_DEFER_ENABLE
- || epdata->dev->state == STATE_DEV_UNBOUND
- )) < 0)
- goto fail;
- goto newstate;
// case STATE_EP_DISABLED: /* "can't happen" */
// case STATE_EP_READY: /* "can't happen" */
default: /* error! */
@@ -333,7 +324,6 @@ newstate:
// FALLTHROUGH
case STATE_EP_UNBOUND: /* clean disconnect */
val = -ENODEV;
-fail:
up (&epdata->lock);
}
return val;
@@ -563,31 +553,33 @@ static ssize_t ep_aio_read_retry(struct kiocb *iocb)
{
struct kiocb_priv *priv = iocb->private;
ssize_t len, total;
+ void *to_copy;
int i;
- /* we "retry" to get the right mm context for this: */
-
- /* copy stuff into user buffers */
- total = priv->actual;
- len = 0;
- for (i=0; i < priv->nr_segs; i++) {
- ssize_t this = min((ssize_t)(priv->iv[i].iov_len), total);
-
- if (copy_to_user(priv->iv[i].iov_base, priv->buf, this)) {
- if (len == 0)
- len = -EFAULT;
- break;
- }
-
- total -= this;
- len += this;
- if (total == 0)
- break;
- }
- kfree(priv->buf);
- kfree(priv);
- aio_put_req(iocb);
- return len;
+ /* we "retry" to get the right mm context for this: */
+
+ /* copy stuff into user buffers */
+ total = priv->actual;
+ len = 0;
+ to_copy = priv->buf;
+ for (i=0; i < priv->nr_segs; i++) {
+ ssize_t this = min((ssize_t)(priv->iv[i].iov_len), total);
+
+ if (copy_to_user(priv->iv[i].iov_base, to_copy, this)) {
+ if (len == 0)
+ len = -EFAULT;
+ break;
+ }
+
+ total -= this;
+ len += this;
+ to_copy += this;
+ if (total == 0)
+ break;
+ }
+ kfree(priv->buf);
+ kfree(priv);
+ return len;
}
static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req)
@@ -600,18 +592,17 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req)
spin_lock(&epdata->dev->lock);
priv->req = NULL;
priv->epdata = NULL;
- if (priv->iv == NULL
- || unlikely(req->actual == 0)
- || unlikely(kiocbIsCancelled(iocb))) {
+
+ /* if this was a write or a read returning no data then we
+ * don't need to copy anything to userspace, so we can
+ * complete the aio request immediately.
+ */
+ if (priv->iv == NULL || unlikely(req->actual == 0)) {
kfree(req->buf);
kfree(priv);
iocb->private = NULL;
/* aio_complete() reports bytes-transferred _and_ faults */
- if (unlikely(kiocbIsCancelled(iocb)))
- aio_put_req(iocb);
- else
- aio_complete(iocb,
- req->actual ? req->actual : req->status,
+ aio_complete(iocb, req->actual ? req->actual : req->status,
req->status);
} else {
/* retry() won't report both; so we hide some faults */
@@ -636,7 +627,7 @@ ep_aio_rwtail(
size_t len,
struct ep_data *epdata,
const struct iovec *iv,
- unsigned long nr_segs
+ unsigned long nr_segs
)
{
struct kiocb_priv *priv;
@@ -852,9 +843,9 @@ ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
break;
#endif
default:
- DBG (data->dev, "unconnected, %s init deferred\n",
+ DBG(data->dev, "unconnected, %s init abandoned\n",
data->name);
- data->state = STATE_EP_DEFER_ENABLE;
+ value = -EINVAL;
}
if (value == 0) {
fd->f_op = &ep_io_operations;
@@ -943,22 +934,24 @@ static void clean_req (struct usb_ep *ep, struct usb_request *req)
static void ep0_complete (struct usb_ep *ep, struct usb_request *req)
{
struct dev_data *dev = ep->driver_data;
+ unsigned long flags;
int free = 1;
/* for control OUT, data must still get to userspace */
+ spin_lock_irqsave(&dev->lock, flags);
if (!dev->setup_in) {
dev->setup_out_error = (req->status != 0);
if (!dev->setup_out_error)
free = 0;
dev->setup_out_ready = 1;
ep0_readable (dev);
- } else if (dev->state == STATE_SETUP)
- dev->state = STATE_CONNECTED;
+ }
/* clean up as appropriate */
if (free && req->buf != &dev->rbuf)
clean_req (ep, req);
req->complete = epio_complete;
+ spin_unlock_irqrestore(&dev->lock, flags);
}
static int setup_req (struct usb_ep *ep, struct usb_request *req, u16 len)
@@ -998,13 +991,13 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
}
/* control DATA stage */
- if ((state = dev->state) == STATE_SETUP) {
+ if ((state = dev->state) == STATE_DEV_SETUP) {
if (dev->setup_in) { /* stall IN */
VDEBUG(dev, "ep0in stall\n");
(void) usb_ep_set_halt (dev->gadget->ep0);
retval = -EL2HLT;
- dev->state = STATE_CONNECTED;
+ dev->state = STATE_DEV_CONNECTED;
} else if (len == 0) { /* ack SET_CONFIGURATION etc */
struct usb_ep *ep = dev->gadget->ep0;
@@ -1012,7 +1005,7 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
if ((retval = setup_req (ep, req, 0)) == 0)
retval = usb_ep_queue (ep, req, GFP_ATOMIC);
- dev->state = STATE_CONNECTED;
+ dev->state = STATE_DEV_CONNECTED;
/* assume that was SET_CONFIGURATION */
if (dev->current_config) {
@@ -1040,6 +1033,13 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
spin_lock_irq (&dev->lock);
if (retval)
goto done;
+
+ if (dev->state != STATE_DEV_SETUP) {
+ retval = -ECANCELED;
+ goto done;
+ }
+ dev->state = STATE_DEV_CONNECTED;
+
if (dev->setup_out_error)
retval = -EIO;
else {
@@ -1066,39 +1066,36 @@ scan:
/* return queued events right away */
if (dev->ev_next != 0) {
unsigned i, n;
- int tmp = dev->ev_next;
- len = min (len, tmp * sizeof (struct usb_gadgetfs_event));
n = len / sizeof (struct usb_gadgetfs_event);
+ if (dev->ev_next < n)
+ n = dev->ev_next;
- /* ep0 can't deliver events when STATE_SETUP */
+ /* ep0 i/o has special semantics during STATE_DEV_SETUP */
for (i = 0; i < n; i++) {
if (dev->event [i].type == GADGETFS_SETUP) {
- len = i + 1;
- len *= sizeof (struct usb_gadgetfs_event);
- n = 0;
+ dev->state = STATE_DEV_SETUP;
+ n = i + 1;
break;
}
}
spin_unlock_irq (&dev->lock);
+ len = n * sizeof (struct usb_gadgetfs_event);
if (copy_to_user (buf, &dev->event, len))
retval = -EFAULT;
else
retval = len;
if (len > 0) {
- len /= sizeof (struct usb_gadgetfs_event);
-
/* NOTE this doesn't guard against broken drivers;
* concurrent ep0 readers may lose events.
*/
spin_lock_irq (&dev->lock);
- dev->ev_next -= len;
- if (dev->ev_next != 0)
- memmove (&dev->event, &dev->event [len],
+ if (dev->ev_next > n) {
+ memmove(&dev->event[0], &dev->event[n],
sizeof (struct usb_gadgetfs_event)
- * (tmp - len));
- if (n == 0)
- dev->state = STATE_SETUP;
+ * (dev->ev_next - n));
+ }
+ dev->ev_next -= n;
spin_unlock_irq (&dev->lock);
}
return retval;
@@ -1113,8 +1110,8 @@ scan:
DBG (dev, "fail %s, state %d\n", __FUNCTION__, state);
retval = -ESRCH;
break;
- case STATE_UNCONNECTED:
- case STATE_CONNECTED:
+ case STATE_DEV_UNCONNECTED:
+ case STATE_DEV_CONNECTED:
spin_unlock_irq (&dev->lock);
DBG (dev, "%s wait\n", __FUNCTION__);
@@ -1141,7 +1138,7 @@ next_event (struct dev_data *dev, enum usb_gadgetfs_event_type type)
switch (type) {
/* these events purge the queue */
case GADGETFS_DISCONNECT:
- if (dev->state == STATE_SETUP)
+ if (dev->state == STATE_DEV_SETUP)
dev->setup_abort = 1;
// FALL THROUGH
case GADGETFS_CONNECT:
@@ -1153,7 +1150,7 @@ next_event (struct dev_data *dev, enum usb_gadgetfs_event_type type)
for (i = 0; i != dev->ev_next; i++) {
if (dev->event [i].type != type)
continue;
- DBG (dev, "discard old event %d\n", type);
+ DBG(dev, "discard old event[%d] %d\n", i, type);
dev->ev_next--;
if (i == dev->ev_next)
break;
@@ -1166,9 +1163,9 @@ next_event (struct dev_data *dev, enum usb_gadgetfs_event_type type)
default:
BUG ();
}
+ VDEBUG(dev, "event[%d] = %d\n", dev->ev_next, type);
event = &dev->event [dev->ev_next++];
BUG_ON (dev->ev_next > N_EVENT);
- VDEBUG (dev, "ev %d, next %d\n", type, dev->ev_next);
memset (event, 0, sizeof *event);
event->type = type;
return event;
@@ -1188,12 +1185,13 @@ ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
retval = -EIDRM;
/* data and/or status stage for control request */
- } else if (dev->state == STATE_SETUP) {
+ } else if (dev->state == STATE_DEV_SETUP) {
/* IN DATA+STATUS caller makes len <= wLength */
if (dev->setup_in) {
retval = setup_req (dev->gadget->ep0, dev->req, len);
if (retval == 0) {
+ dev->state = STATE_DEV_CONNECTED;
spin_unlock_irq (&dev->lock);
if (copy_from_user (dev->req->buf, buf, len))
retval = -EFAULT;
@@ -1219,7 +1217,7 @@ ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
VDEBUG(dev, "ep0out stall\n");
(void) usb_ep_set_halt (dev->gadget->ep0);
retval = -EL2HLT;
- dev->state = STATE_CONNECTED;
+ dev->state = STATE_DEV_CONNECTED;
} else {
DBG(dev, "bogus ep0out stall!\n");
}
@@ -1261,7 +1259,9 @@ dev_release (struct inode *inode, struct file *fd)
put_dev (dev);
/* other endpoints were all decoupled from this device */
+ spin_lock_irq(&dev->lock);
dev->state = STATE_DEV_DISABLED;
+ spin_unlock_irq(&dev->lock);
return 0;
}
@@ -1282,7 +1282,7 @@ ep0_poll (struct file *fd, poll_table *wait)
goto out;
}
- if (dev->state == STATE_SETUP) {
+ if (dev->state == STATE_DEV_SETUP) {
if (dev->setup_in || dev->setup_can_stall)
mask = POLLOUT;
} else {
@@ -1392,52 +1392,29 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
spin_lock (&dev->lock);
dev->setup_abort = 0;
- if (dev->state == STATE_UNCONNECTED) {
- struct usb_ep *ep;
- struct ep_data *data;
-
- dev->state = STATE_CONNECTED;
- dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket;
-
+ if (dev->state == STATE_DEV_UNCONNECTED) {
#ifdef CONFIG_USB_GADGET_DUALSPEED
if (gadget->speed == USB_SPEED_HIGH && dev->hs_config == 0) {
+ spin_unlock(&dev->lock);
ERROR (dev, "no high speed config??\n");
return -EINVAL;
}
#endif /* CONFIG_USB_GADGET_DUALSPEED */
+ dev->state = STATE_DEV_CONNECTED;
+ dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket;
+
INFO (dev, "connected\n");
event = next_event (dev, GADGETFS_CONNECT);
event->u.speed = gadget->speed;
ep0_readable (dev);
- list_for_each_entry (ep, &gadget->ep_list, ep_list) {
- data = ep->driver_data;
- /* ... down_trylock (&data->lock) ... */
- if (data->state != STATE_EP_DEFER_ENABLE)
- continue;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
- if (gadget->speed == USB_SPEED_HIGH)
- value = usb_ep_enable (ep, &data->hs_desc);
- else
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
- value = usb_ep_enable (ep, &data->desc);
- if (value) {
- ERROR (dev, "deferred %s enable --> %d\n",
- data->name, value);
- continue;
- }
- data->state = STATE_EP_ENABLED;
- wake_up (&data->wait);
- DBG (dev, "woke up %s waiters\n", data->name);
- }
-
/* host may have given up waiting for response. we can miss control
* requests handled lower down (device/endpoint status and features);
* then ep0_{read,write} will report the wrong status. controller
* driver will have aborted pending i/o.
*/
- } else if (dev->state == STATE_SETUP)
+ } else if (dev->state == STATE_DEV_SETUP)
dev->setup_abort = 1;
req->buf = dev->rbuf;
@@ -1583,7 +1560,7 @@ delegate:
}
/* proceed with data transfer and status phases? */
- if (value >= 0 && dev->state != STATE_SETUP) {
+ if (value >= 0 && dev->state != STATE_DEV_SETUP) {
req->length = value;
req->zero = value < w_length;
value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC);
@@ -1747,7 +1724,9 @@ gadgetfs_bind (struct usb_gadget *gadget)
goto enomem;
INFO (dev, "bound to %s driver\n", gadget->name);
- dev->state = STATE_UNCONNECTED;
+ spin_lock_irq(&dev->lock);
+ dev->state = STATE_DEV_UNCONNECTED;
+ spin_unlock_irq(&dev->lock);
get_dev (dev);
return 0;
@@ -1762,11 +1741,9 @@ gadgetfs_disconnect (struct usb_gadget *gadget)
struct dev_data *dev = get_gadget_data (gadget);
spin_lock (&dev->lock);
- if (dev->state == STATE_UNCONNECTED) {
- DBG (dev, "already unconnected\n");
+ if (dev->state == STATE_DEV_UNCONNECTED)
goto exit;
- }
- dev->state = STATE_UNCONNECTED;
+ dev->state = STATE_DEV_UNCONNECTED;
INFO (dev, "disconnected\n");
next_event (dev, GADGETFS_DISCONNECT);
@@ -1783,9 +1760,9 @@ gadgetfs_suspend (struct usb_gadget *gadget)
INFO (dev, "suspended from state %d\n", dev->state);
spin_lock (&dev->lock);
switch (dev->state) {
- case STATE_SETUP: // VERY odd... host died??
- case STATE_CONNECTED:
- case STATE_UNCONNECTED:
+ case STATE_DEV_SETUP: // VERY odd... host died??
+ case STATE_DEV_CONNECTED:
+ case STATE_DEV_UNCONNECTED:
next_event (dev, GADGETFS_SUSPEND);
ep0_readable (dev);
/* FALLTHROUGH */
@@ -1808,7 +1785,7 @@ static struct usb_gadget_driver gadgetfs_driver = {
.disconnect = gadgetfs_disconnect,
.suspend = gadgetfs_suspend,
- .driver = {
+ .driver = {
.name = (char *) shortname,
},
};
@@ -1829,7 +1806,7 @@ static struct usb_gadget_driver probe_driver = {
.unbind = gadgetfs_nop,
.setup = (void *)gadgetfs_nop,
.disconnect = gadgetfs_nop,
- .driver = {
+ .driver = {
.name = "nop",
},
};
@@ -1849,19 +1826,16 @@ static struct usb_gadget_driver probe_driver = {
* . full/low speed config ... all wTotalLength bytes (with interface,
* class, altsetting, endpoint, and other descriptors)
* . high speed config ... all descriptors, for high speed operation;
- * this one's optional except for high-speed hardware
+ * this one's optional except for high-speed hardware
* . device descriptor
*
- * Endpoints are not yet enabled. Drivers may want to immediately
- * initialize them, using the /dev/gadget/ep* files that are available
- * as soon as the kernel sees the configuration, or they can wait
- * until device configuration and interface altsetting changes create
+ * Endpoints are not yet enabled. Drivers must wait until device
+ * configuration and interface altsetting changes create
* the need to configure (or unconfigure) them.
*
* After initialization, the device stays active for as long as that
- * $CHIP file is open. Events may then be read from that descriptor,
- * such as configuration notifications. More complex drivers will handle
- * some control requests in user space.
+ * $CHIP file is open. Events must then be read from that descriptor,
+ * such as configuration notifications.
*/
static int is_valid_config (struct usb_config_descriptor *config)
@@ -1884,9 +1858,6 @@ dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
u32 tag;
char *kbuf;
- if (dev->state != STATE_OPENED)
- return -EEXIST;
-
if (len < (USB_DT_CONFIG_SIZE + USB_DT_DEVICE_SIZE + 4))
return -EINVAL;
@@ -1978,13 +1949,15 @@ dev_open (struct inode *inode, struct file *fd)
struct dev_data *dev = inode->i_private;
int value = -EBUSY;
+ spin_lock_irq(&dev->lock);
if (dev->state == STATE_DEV_DISABLED) {
dev->ev_next = 0;
- dev->state = STATE_OPENED;
+ dev->state = STATE_DEV_OPENED;
fd->private_data = dev;
get_dev (dev);
value = 0;
}
+ spin_unlock_irq(&dev->lock);
return value;
}
diff --git a/drivers/usb/gadget/lh7a40x_udc.h b/drivers/usb/gadget/lh7a40x_udc.h
index e3bb78524c8..b3fe197e1ee 100644
--- a/drivers/usb/gadget/lh7a40x_udc.h
+++ b/drivers/usb/gadget/lh7a40x_udc.h
@@ -49,7 +49,7 @@
#include <asm/unaligned.h>
#include <asm/hardware.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
/*
diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c
index 569eb8ccf23..49d737725f7 100644
--- a/drivers/usb/gadget/net2280.c
+++ b/drivers/usb/gadget/net2280.c
@@ -53,7 +53,6 @@
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ioport.h>
-#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/smp_lock.h>
#include <linux/errno.h>
@@ -63,7 +62,7 @@
#include <linux/interrupt.h>
#include <linux/moduleparam.h>
#include <linux/device.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include <asm/byteorder.h>
diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c
index cdcfd42843d..8f9a2b61542 100644
--- a/drivers/usb/gadget/omap_udc.c
+++ b/drivers/usb/gadget/omap_udc.c
@@ -28,7 +28,6 @@
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/delay.h>
-#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/timer.h>
@@ -38,7 +37,7 @@
#include <linux/mm.h>
#include <linux/moduleparam.h>
#include <linux/platform_device.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include <linux/usb/otg.h>
#include <linux/dma-mapping.h>
diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c
index b78de969466..f01890dc875 100644
--- a/drivers/usb/gadget/pxa2xx_udc.c
+++ b/drivers/usb/gadget/pxa2xx_udc.c
@@ -33,7 +33,6 @@
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/delay.h>
-#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/timer.h>
@@ -56,7 +55,7 @@
#include <asm/arch/pxa-regs.h>
#endif
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include <asm/arch/udc.h>
@@ -156,7 +155,7 @@ static int is_vbus_present(void)
struct pxa2xx_udc_mach_info *mach = the_controller->mach;
if (mach->gpio_vbus)
- return pxa_gpio_get(mach->gpio_vbus);
+ return udc_gpio_get(mach->gpio_vbus);
if (mach->udc_is_connected)
return mach->udc_is_connected();
return 1;
@@ -168,7 +167,7 @@ static void pullup_off(void)
struct pxa2xx_udc_mach_info *mach = the_controller->mach;
if (mach->gpio_pullup)
- pxa_gpio_set(mach->gpio_pullup, 0);
+ udc_gpio_set(mach->gpio_pullup, 0);
else if (mach->udc_command)
mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT);
}
@@ -178,7 +177,7 @@ static void pullup_on(void)
struct pxa2xx_udc_mach_info *mach = the_controller->mach;
if (mach->gpio_pullup)
- pxa_gpio_set(mach->gpio_pullup, 1);
+ udc_gpio_set(mach->gpio_pullup, 1);
else if (mach->udc_command)
mach->udc_command(PXA2XX_UDC_CMD_CONNECT);
}
@@ -1756,7 +1755,7 @@ lubbock_vbus_irq(int irq, void *_dev)
static irqreturn_t udc_vbus_irq(int irq, void *_dev)
{
struct pxa2xx_udc *dev = _dev;
- int vbus = pxa_gpio_get(dev->mach->gpio_vbus);
+ int vbus = udc_gpio_get(dev->mach->gpio_vbus);
pxa2xx_udc_vbus_session(&dev->gadget, vbus);
return IRQ_HANDLED;
@@ -2546,15 +2545,13 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev)
dev->dev = &pdev->dev;
dev->mach = pdev->dev.platform_data;
if (dev->mach->gpio_vbus) {
- vbus_irq = IRQ_GPIO(dev->mach->gpio_vbus & GPIO_MD_MASK_NR);
- pxa_gpio_mode((dev->mach->gpio_vbus & GPIO_MD_MASK_NR)
- | GPIO_IN);
+ udc_gpio_init_vbus(dev->mach->gpio_vbus);
+ vbus_irq = udc_gpio_to_irq(dev->mach->gpio_vbus);
set_irq_type(vbus_irq, IRQT_BOTHEDGE);
} else
vbus_irq = 0;
if (dev->mach->gpio_pullup)
- pxa_gpio_mode((dev->mach->gpio_pullup & GPIO_MD_MASK_NR)
- | GPIO_OUT | GPIO_DFLT_LOW);
+ udc_gpio_init_pullup(dev->mach->gpio_pullup);
init_timer(&dev->timer);
dev->timer.function = udc_watchdog;
@@ -2614,7 +2611,7 @@ lubbock_fail0:
#endif
if (vbus_irq) {
retval = request_irq(vbus_irq, udc_vbus_irq,
- SA_INTERRUPT | SA_SAMPLE_RANDOM,
+ IRQF_DISABLED | IRQF_SAMPLE_RANDOM,
driver_name, dev);
if (retval != 0) {
printk(KERN_ERR "%s: can't get irq %i, err %d\n",
diff --git a/drivers/usb/gadget/pxa2xx_udc.h b/drivers/usb/gadget/pxa2xx_udc.h
index 8e598c8bf4e..773e549aff3 100644
--- a/drivers/usb/gadget/pxa2xx_udc.h
+++ b/drivers/usb/gadget/pxa2xx_udc.h
@@ -177,21 +177,6 @@ struct pxa2xx_udc {
static struct pxa2xx_udc *the_controller;
-static inline int pxa_gpio_get(unsigned gpio)
-{
- return (GPLR(gpio) & GPIO_bit(gpio)) != 0;
-}
-
-static inline void pxa_gpio_set(unsigned gpio, int is_on)
-{
- int mask = GPIO_bit(gpio);
-
- if (is_on)
- GPSR(gpio) = mask;
- else
- GPCR(gpio) = mask;
-}
-
/*-------------------------------------------------------------------------*/
/*
diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c
index 408c3380d60..6ec8cf1a3cc 100644
--- a/drivers/usb/gadget/rndis.c
+++ b/drivers/usb/gadget/rndis.c
@@ -1419,7 +1419,6 @@ int __devinit rndis_init (void)
return -EIO;
}
- rndis_connect_state [i]->nlink = 1;
rndis_connect_state [i]->write_proc = rndis_proc_write;
rndis_connect_state [i]->read_proc = rndis_proc_read;
rndis_connect_state [i]->data = (void *)
diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c
index f8a3ec64635..e552668d36b 100644
--- a/drivers/usb/gadget/serial.c
+++ b/drivers/usb/gadget/serial.c
@@ -21,7 +21,6 @@
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ioport.h>
-#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/smp_lock.h>
#include <linux/errno.h>
@@ -43,7 +42,7 @@
#include <asm/unaligned.h>
#include <asm/uaccess.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
#include <linux/usb/cdc.h>
#include <linux/usb_gadget.h>
@@ -1700,6 +1699,7 @@ static int gs_setup_class(struct usb_gadget *gadget,
memcpy(&port->port_line_coding, req->buf, ret);
spin_unlock(&port->port_lock);
}
+ ret = 0;
break;
case USB_CDC_REQ_GET_LINE_CODING:
diff --git a/drivers/usb/gadget/usbstring.c b/drivers/usb/gadget/usbstring.c
index b1735767660..3459ea6c6c0 100644
--- a/drivers/usb/gadget/usbstring.c
+++ b/drivers/usb/gadget/usbstring.c
@@ -14,7 +14,7 @@
#include <linux/device.h>
#include <linux/init.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include <asm/unaligned.h>
diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c
index 40710ea1b49..8c85e33f74a 100644
--- a/drivers/usb/gadget/zero.c
+++ b/drivers/usb/gadget/zero.c
@@ -66,7 +66,6 @@
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ioport.h>
-#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/smp_lock.h>
#include <linux/errno.h>
@@ -84,7 +83,7 @@
#include <asm/system.h>
#include <asm/unaligned.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include "gadget_chips.h"
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index cc60759083b..62711870f8e 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -67,6 +67,11 @@ config USB_EHCI_TT_NEWSCHED
If unsure, say N.
+config USB_EHCI_BIG_ENDIAN_MMIO
+ bool
+ depends on USB_EHCI_HCD
+ default n
+
config USB_ISP116X_HCD
tristate "ISP116X HCD support"
depends on USB
@@ -101,21 +106,48 @@ config USB_OHCI_HCD_PPC_SOC
bool "OHCI support for on-chip PPC USB controller"
depends on USB_OHCI_HCD && (STB03xxx || PPC_MPC52xx)
default y
- select USB_OHCI_BIG_ENDIAN
+ select USB_OHCI_BIG_ENDIAN_DESC
+ select USB_OHCI_BIG_ENDIAN_MMIO
---help---
Enables support for the USB controller on the MPC52xx or
STB03xxx processor chip. If unsure, say Y.
+config USB_OHCI_HCD_PPC_OF
+ bool "OHCI support for PPC USB controller on OF platform bus"
+ depends on USB_OHCI_HCD && PPC_OF
+ default y
+ ---help---
+ Enables support for the USB controller PowerPC present on the
+ OpenFirmware platform bus.
+
+config USB_OHCI_HCD_PPC_OF_BE
+ bool "Support big endian HC"
+ depends on USB_OHCI_HCD_PPC_OF
+ default y
+ select USB_OHCI_BIG_ENDIAN_DESC
+ select USB_OHCI_BIG_ENDIAN_MMIO
+
+config USB_OHCI_HCD_PPC_OF_LE
+ bool "Support little endian HC"
+ depends on USB_OHCI_HCD_PPC_OF
+ default n
+ select USB_OHCI_LITTLE_ENDIAN
+
config USB_OHCI_HCD_PCI
bool "OHCI support for PCI-bus USB controllers"
- depends on USB_OHCI_HCD && PCI && (STB03xxx || PPC_MPC52xx)
+ depends on USB_OHCI_HCD && PCI && (STB03xxx || PPC_MPC52xx || USB_OHCI_HCD_PPC_OF)
default y
select USB_OHCI_LITTLE_ENDIAN
---help---
Enables support for PCI-bus plug-in USB controller cards.
If unsure, say Y.
-config USB_OHCI_BIG_ENDIAN
+config USB_OHCI_BIG_ENDIAN_DESC
+ bool
+ depends on USB_OHCI_HCD
+ default n
+
+config USB_OHCI_BIG_ENDIAN_MMIO
bool
depends on USB_OHCI_HCD
default n
diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c
index 56349d21e6e..43eddaecc3d 100644
--- a/drivers/usb/host/ehci-dbg.c
+++ b/drivers/usb/host/ehci-dbg.c
@@ -43,7 +43,7 @@
*/
static void dbg_hcs_params (struct ehci_hcd *ehci, char *label)
{
- u32 params = readl (&ehci->caps->hcs_params);
+ u32 params = ehci_readl(ehci, &ehci->caps->hcs_params);
ehci_dbg (ehci,
"%s hcs_params 0x%x dbg=%d%s cc=%d pcc=%d%s%s ports=%d\n",
@@ -87,7 +87,7 @@ static inline void dbg_hcs_params (struct ehci_hcd *ehci, char *label) {}
* */
static void dbg_hcc_params (struct ehci_hcd *ehci, char *label)
{
- u32 params = readl (&ehci->caps->hcc_params);
+ u32 params = ehci_readl(ehci, &ehci->caps->hcc_params);
if (HCC_ISOC_CACHE (params)) {
ehci_dbg (ehci,
@@ -322,7 +322,7 @@ static inline void remove_debug_files (struct ehci_hcd *bus) { }
#else
-/* troubleshooting help: expose state in driverfs */
+/* troubleshooting help: expose state in sysfs */
#define speed_char(info1) ({ char tmp; \
switch (info1 & (3 << 12)) { \
@@ -653,7 +653,7 @@ show_registers (struct class_device *class_dev, char *buf)
}
/* Capability Registers */
- i = HC_VERSION(readl (&ehci->caps->hc_capbase));
+ i = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase));
temp = scnprintf (next, size,
"bus %s, device %s (driver " DRIVER_VERSION ")\n"
"%s\n"
@@ -673,7 +673,7 @@ show_registers (struct class_device *class_dev, char *buf)
unsigned count = 256/4;
pdev = to_pci_dev(ehci_to_hcd(ehci)->self.controller);
- offset = HCC_EXT_CAPS (readl (&ehci->caps->hcc_params));
+ offset = HCC_EXT_CAPS (ehci_readl(ehci, &ehci->caps->hcc_params));
while (offset && count--) {
pci_read_config_dword (pdev, offset, &cap);
switch (cap & 0xff) {
@@ -704,50 +704,50 @@ show_registers (struct class_device *class_dev, char *buf)
#endif
// FIXME interpret both types of params
- i = readl (&ehci->caps->hcs_params);
+ i = ehci_readl(ehci, &ehci->caps->hcs_params);
temp = scnprintf (next, size, "structural params 0x%08x\n", i);
size -= temp;
next += temp;
- i = readl (&ehci->caps->hcc_params);
+ i = ehci_readl(ehci, &ehci->caps->hcc_params);
temp = scnprintf (next, size, "capability params 0x%08x\n", i);
size -= temp;
next += temp;
/* Operational Registers */
temp = dbg_status_buf (scratch, sizeof scratch, label,
- readl (&ehci->regs->status));
+ ehci_readl(ehci, &ehci->regs->status));
temp = scnprintf (next, size, fmt, temp, scratch);
size -= temp;
next += temp;
temp = dbg_command_buf (scratch, sizeof scratch, label,
- readl (&ehci->regs->command));
+ ehci_readl(ehci, &ehci->regs->command));
temp = scnprintf (next, size, fmt, temp, scratch);
size -= temp;
next += temp;
temp = dbg_intr_buf (scratch, sizeof scratch, label,
- readl (&ehci->regs->intr_enable));
+ ehci_readl(ehci, &ehci->regs->intr_enable));
temp = scnprintf (next, size, fmt, temp, scratch);
size -= temp;
next += temp;
temp = scnprintf (next, size, "uframe %04x\n",
- readl (&ehci->regs->frame_index));
+ ehci_readl(ehci, &ehci->regs->frame_index));
size -= temp;
next += temp;
for (i = 1; i <= HCS_N_PORTS (ehci->hcs_params); i++) {
temp = dbg_port_buf (scratch, sizeof scratch, label, i,
- readl (&ehci->regs->port_status [i - 1]));
+ ehci_readl(ehci, &ehci->regs->port_status [i - 1]));
temp = scnprintf (next, size, fmt, temp, scratch);
size -= temp;
next += temp;
if (i == HCS_DEBUG_PORT(ehci->hcs_params) && ehci->debug) {
temp = scnprintf (next, size,
" debug control %08x\n",
- readl (&ehci->debug->control));
+ ehci_readl(ehci, &ehci->debug->control));
size -= temp;
next += temp;
}
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index 1a915e982c1..a52480505f7 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -177,7 +177,7 @@ static void mpc83xx_setup_phy(struct ehci_hcd *ehci,
case FSL_USB2_PHY_NONE:
break;
}
- writel(portsc, &ehci->regs->port_status[port_offset]);
+ ehci_writel(ehci, portsc, &ehci->regs->port_status[port_offset]);
}
static void mpc83xx_usb_setup(struct usb_hcd *hcd)
@@ -214,7 +214,7 @@ static void mpc83xx_usb_setup(struct usb_hcd *hcd)
}
/* put controller in host mode. */
- writel(0x00000003, non_ehci + FSL_SOC_USB_USBMODE);
+ ehci_writel(ehci, 0x00000003, non_ehci + FSL_SOC_USB_USBMODE);
out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x0000000c);
out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000040);
out_be32(non_ehci + FSL_SOC_USB_SICTRL, 0x00000001);
@@ -238,12 +238,12 @@ static int ehci_fsl_setup(struct usb_hcd *hcd)
/* EHCI registers start at offset 0x100 */
ehci->caps = hcd->regs + 0x100;
ehci->regs = hcd->regs + 0x100 +
- HC_LENGTH(readl(&ehci->caps->hc_capbase));
+ HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
dbg_hcs_params(ehci, "reset");
dbg_hcc_params(ehci, "reset");
/* cache this readonly data; minimize chip reads */
- ehci->hcs_params = readl(&ehci->caps->hcs_params);
+ ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
retval = ehci_halt(ehci);
if (retval)
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 025d3331368..a7405648823 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -42,6 +42,9 @@
#include <asm/irq.h>
#include <asm/system.h>
#include <asm/unaligned.h>
+#ifdef CONFIG_PPC_PS3
+#include <asm/firmware.h>
+#endif
/*-------------------------------------------------------------------------*/
@@ -157,12 +160,13 @@ MODULE_PARM_DESC (ignore_oc, "ignore bogus hardware overcurrent indications");
* before driver shutdown. But it also seems to be caused by bugs in cardbus
* bridge shutdown: shutting down the bridge before the devices using it.
*/
-static int handshake (void __iomem *ptr, u32 mask, u32 done, int usec)
+static int handshake (struct ehci_hcd *ehci, void __iomem *ptr,
+ u32 mask, u32 done, int usec)
{
u32 result;
do {
- result = readl (ptr);
+ result = ehci_readl(ehci, ptr);
if (result == ~(u32)0) /* card removed */
return -ENODEV;
result &= mask;
@@ -177,18 +181,19 @@ static int handshake (void __iomem *ptr, u32 mask, u32 done, int usec)
/* force HC to halt state from unknown (EHCI spec section 2.3) */
static int ehci_halt (struct ehci_hcd *ehci)
{
- u32 temp = readl (&ehci->regs->status);
+ u32 temp = ehci_readl(ehci, &ehci->regs->status);
/* disable any irqs left enabled by previous code */
- writel (0, &ehci->regs->intr_enable);
+ ehci_writel(ehci, 0, &ehci->regs->intr_enable);
if ((temp & STS_HALT) != 0)
return 0;
- temp = readl (&ehci->regs->command);
+ temp = ehci_readl(ehci, &ehci->regs->command);
temp &= ~CMD_RUN;
- writel (temp, &ehci->regs->command);
- return handshake (&ehci->regs->status, STS_HALT, STS_HALT, 16 * 125);
+ ehci_writel(ehci, temp, &ehci->regs->command);
+ return handshake (ehci, &ehci->regs->status,
+ STS_HALT, STS_HALT, 16 * 125);
}
/* put TDI/ARC silicon into EHCI mode */
@@ -198,23 +203,24 @@ static void tdi_reset (struct ehci_hcd *ehci)
u32 tmp;
reg_ptr = (u32 __iomem *)(((u8 __iomem *)ehci->regs) + 0x68);
- tmp = readl (reg_ptr);
+ tmp = ehci_readl(ehci, reg_ptr);
tmp |= 0x3;
- writel (tmp, reg_ptr);
+ ehci_writel(ehci, tmp, reg_ptr);
}
/* reset a non-running (STS_HALT == 1) controller */
static int ehci_reset (struct ehci_hcd *ehci)
{
int retval;
- u32 command = readl (&ehci->regs->command);
+ u32 command = ehci_readl(ehci, &ehci->regs->command);
command |= CMD_RESET;
dbg_cmd (ehci, "reset", command);
- writel (command, &ehci->regs->command);
+ ehci_writel(ehci, command, &ehci->regs->command);
ehci_to_hcd(ehci)->state = HC_STATE_HALT;
ehci->next_statechange = jiffies;
- retval = handshake (&ehci->regs->command, CMD_RESET, 0, 250 * 1000);
+ retval = handshake (ehci, &ehci->regs->command,
+ CMD_RESET, 0, 250 * 1000);
if (retval)
return retval;
@@ -236,21 +242,21 @@ static void ehci_quiesce (struct ehci_hcd *ehci)
#endif
/* wait for any schedule enables/disables to take effect */
- temp = readl (&ehci->regs->command) << 10;
+ temp = ehci_readl(ehci, &ehci->regs->command) << 10;
temp &= STS_ASS | STS_PSS;
- if (handshake (&ehci->regs->status, STS_ASS | STS_PSS,
+ if (handshake (ehci, &ehci->regs->status, STS_ASS | STS_PSS,
temp, 16 * 125) != 0) {
ehci_to_hcd(ehci)->state = HC_STATE_HALT;
return;
}
/* then disable anything that's still active */
- temp = readl (&ehci->regs->command);
+ temp = ehci_readl(ehci, &ehci->regs->command);
temp &= ~(CMD_ASE | CMD_IAAD | CMD_PSE);
- writel (temp, &ehci->regs->command);
+ ehci_writel(ehci, temp, &ehci->regs->command);
/* hardware can take 16 microframes to turn off ... */
- if (handshake (&ehci->regs->status, STS_ASS | STS_PSS,
+ if (handshake (ehci, &ehci->regs->status, STS_ASS | STS_PSS,
0, 16 * 125) != 0) {
ehci_to_hcd(ehci)->state = HC_STATE_HALT;
return;
@@ -277,11 +283,11 @@ static void ehci_watchdog (unsigned long param)
/* lost IAA irqs wedge things badly; seen with a vt8235 */
if (ehci->reclaim) {
- u32 status = readl (&ehci->regs->status);
+ u32 status = ehci_readl(ehci, &ehci->regs->status);
if (status & STS_IAA) {
ehci_vdbg (ehci, "lost IAA\n");
COUNT (ehci->stats.lost_iaa);
- writel (STS_IAA, &ehci->regs->status);
+ ehci_writel(ehci, STS_IAA, &ehci->regs->status);
ehci->reclaim_ready = 1;
}
}
@@ -296,6 +302,19 @@ static void ehci_watchdog (unsigned long param)
spin_unlock_irqrestore (&ehci->lock, flags);
}
+/* On some systems, leaving remote wakeup enabled prevents system shutdown.
+ * The firmware seems to think that powering off is a wakeup event!
+ * This routine turns off remote wakeup and everything else, on all ports.
+ */
+static void ehci_turn_off_all_ports(struct ehci_hcd *ehci)
+{
+ int port = HCS_N_PORTS(ehci->hcs_params);
+
+ while (port--)
+ ehci_writel(ehci, PORT_RWC_BITS,
+ &ehci->regs->port_status[port]);
+}
+
/* ehci_shutdown kick in for silicon on any bus (not just pci, etc).
* This forcibly disables dma and IRQs, helping kexec and other cases
* where the next system software may expect clean state.
@@ -307,9 +326,13 @@ ehci_shutdown (struct usb_hcd *hcd)
ehci = hcd_to_ehci (hcd);
(void) ehci_halt (ehci);
+ ehci_turn_off_all_ports(ehci);
/* make BIOS/etc use companion controller during reboot */
- writel (0, &ehci->regs->configured_flag);
+ ehci_writel(ehci, 0, &ehci->regs->configured_flag);
+
+ /* unblock posted writes */
+ ehci_readl(ehci, &ehci->regs->configured_flag);
}
static void ehci_port_power (struct ehci_hcd *ehci, int is_on)
@@ -379,12 +402,13 @@ static void ehci_stop (struct usb_hcd *hcd)
ehci_quiesce (ehci);
ehci_reset (ehci);
- writel (0, &ehci->regs->intr_enable);
+ ehci_writel(ehci, 0, &ehci->regs->intr_enable);
spin_unlock_irq(&ehci->lock);
/* let companion controllers work when we aren't */
- writel (0, &ehci->regs->configured_flag);
+ ehci_writel(ehci, 0, &ehci->regs->configured_flag);
+ remove_companion_file(ehci);
remove_debug_files (ehci);
/* root hub is shut down separately (first, when possible) */
@@ -402,7 +426,8 @@ static void ehci_stop (struct usb_hcd *hcd)
ehci->stats.complete, ehci->stats.unlink);
#endif
- dbg_status (ehci, "ehci_stop completed", readl (&ehci->regs->status));
+ dbg_status (ehci, "ehci_stop completed",
+ ehci_readl(ehci, &ehci->regs->status));
}
/* one-time init, only for memory state */
@@ -428,7 +453,7 @@ static int ehci_init(struct usb_hcd *hcd)
return retval;
/* controllers may cache some of the periodic schedule ... */
- hcc_params = readl(&ehci->caps->hcc_params);
+ hcc_params = ehci_readl(ehci, &ehci->caps->hcc_params);
if (HCC_ISOC_CACHE(hcc_params)) // full frame cache
ehci->i_thresh = 8;
else // N microframes cached
@@ -496,13 +521,16 @@ static int ehci_run (struct usb_hcd *hcd)
u32 temp;
u32 hcc_params;
+ hcd->uses_new_polling = 1;
+ hcd->poll_rh = 0;
+
/* EHCI spec section 4.1 */
if ((retval = ehci_reset(ehci)) != 0) {
ehci_mem_cleanup(ehci);
return retval;
}
- writel(ehci->periodic_dma, &ehci->regs->frame_list);
- writel((u32)ehci->async->qh_dma, &ehci->regs->async_next);
+ ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list);
+ ehci_writel(ehci, (u32)ehci->async->qh_dma, &ehci->regs->async_next);
/*
* hcc_params controls whether ehci->regs->segment must (!!!)
@@ -516,9 +544,9 @@ static int ehci_run (struct usb_hcd *hcd)
* Scsi_Host.highmem_io, and so forth. It's readonly to all
* host side drivers though.
*/
- hcc_params = readl(&ehci->caps->hcc_params);
+ hcc_params = ehci_readl(ehci, &ehci->caps->hcc_params);
if (HCC_64BIT_ADDR(hcc_params)) {
- writel(0, &ehci->regs->segment);
+ ehci_writel(ehci, 0, &ehci->regs->segment);
#if 0
// this is deeply broken on almost all architectures
if (!dma_set_mask(hcd->self.controller, DMA_64BIT_MASK))
@@ -531,7 +559,7 @@ static int ehci_run (struct usb_hcd *hcd)
// root hub will detect new devices (why?); NEC doesn't
ehci->command &= ~(CMD_LRESET|CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET);
ehci->command |= CMD_RUN;
- writel (ehci->command, &ehci->regs->command);
+ ehci_writel(ehci, ehci->command, &ehci->regs->command);
dbg_cmd (ehci, "init", ehci->command);
/*
@@ -541,23 +569,25 @@ static int ehci_run (struct usb_hcd *hcd)
* and there's no companion controller unless maybe for USB OTG.)
*/
hcd->state = HC_STATE_RUNNING;
- writel (FLAG_CF, &ehci->regs->configured_flag);
- readl (&ehci->regs->command); /* unblock posted writes */
+ ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
+ ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
- temp = HC_VERSION(readl (&ehci->caps->hc_capbase));
+ temp = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase));
ehci_info (ehci,
"USB %x.%x started, EHCI %x.%02x, driver %s%s\n",
((ehci->sbrn & 0xf0)>>4), (ehci->sbrn & 0x0f),
temp >> 8, temp & 0xff, DRIVER_VERSION,
ignore_oc ? ", overcurrent ignored" : "");
- writel (INTR_MASK, &ehci->regs->intr_enable); /* Turn On Interrupts */
+ ehci_writel(ehci, INTR_MASK,
+ &ehci->regs->intr_enable); /* Turn On Interrupts */
/* GRR this is run-once init(), being done every time the HC starts.
* So long as they're part of class devices, we can't do it init()
* since the class device isn't created that early.
*/
create_debug_files(ehci);
+ create_companion_file(ehci);
return 0;
}
@@ -567,12 +597,12 @@ static int ehci_run (struct usb_hcd *hcd)
static irqreturn_t ehci_irq (struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
- u32 status;
+ u32 status, pcd_status = 0;
int bh;
spin_lock (&ehci->lock);
- status = readl (&ehci->regs->status);
+ status = ehci_readl(ehci, &ehci->regs->status);
/* e.g. cardbus physical eject */
if (status == ~(u32) 0) {
@@ -587,8 +617,8 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
}
/* clear (just) interrupts */
- writel (status, &ehci->regs->status);
- readl (&ehci->regs->command); /* unblock posted write */
+ ehci_writel(ehci, status, &ehci->regs->status);
+ ehci_readl(ehci, &ehci->regs->command); /* unblock posted write */
bh = 0;
#ifdef EHCI_VERBOSE_DEBUG
@@ -617,13 +647,15 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
/* remote wakeup [4.3.1] */
if (status & STS_PCD) {
unsigned i = HCS_N_PORTS (ehci->hcs_params);
+ pcd_status = status;
/* resume root hub? */
- if (!(readl(&ehci->regs->command) & CMD_RUN))
+ if (!(ehci_readl(ehci, &ehci->regs->command) & CMD_RUN))
usb_hcd_resume_root_hub(hcd);
while (i--) {
- int pstatus = readl (&ehci->regs->port_status [i]);
+ int pstatus = ehci_readl(ehci,
+ &ehci->regs->port_status [i]);
if (pstatus & PORT_OWNER)
continue;
@@ -643,14 +675,15 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
/* PCI errors [4.15.2.4] */
if (unlikely ((status & STS_FATAL) != 0)) {
/* bogus "fatal" IRQs appear on some chips... why? */
- status = readl (&ehci->regs->status);
- dbg_cmd (ehci, "fatal", readl (&ehci->regs->command));
+ status = ehci_readl(ehci, &ehci->regs->status);
+ dbg_cmd (ehci, "fatal", ehci_readl(ehci,
+ &ehci->regs->command));
dbg_status (ehci, "fatal", status);
if (status & STS_HALT) {
ehci_err (ehci, "fatal error\n");
dead:
ehci_reset (ehci);
- writel (0, &ehci->regs->configured_flag);
+ ehci_writel(ehci, 0, &ehci->regs->configured_flag);
/* generic layer kills/unlinks all urbs, then
* uses ehci_stop to clean up the rest
*/
@@ -661,6 +694,8 @@ dead:
if (bh)
ehci_work (ehci);
spin_unlock (&ehci->lock);
+ if (pcd_status & STS_PCD)
+ usb_hcd_poll_rh_status(hcd);
return IRQ_HANDLED;
}
@@ -873,7 +908,8 @@ done:
static int ehci_get_frame (struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
- return (readl (&ehci->regs->frame_index) >> 3) % ehci->periodic_size;
+ return (ehci_readl(ehci, &ehci->regs->frame_index) >> 3) %
+ ehci->periodic_size;
}
/*-------------------------------------------------------------------------*/
@@ -899,7 +935,13 @@ MODULE_LICENSE ("GPL");
#define PLATFORM_DRIVER ehci_hcd_au1xxx_driver
#endif
-#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER)
+#ifdef CONFIG_PPC_PS3
+#include "ehci-ps3.c"
+#define PS3_SYSTEM_BUS_DRIVER ps3_ehci_sb_driver
+#endif
+
+#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
+ !defined(PS3_SYSTEM_BUS_DRIVER)
#error "missing bus glue for ehci-hcd"
#endif
@@ -924,6 +966,23 @@ static int __init ehci_hcd_init(void)
#ifdef PLATFORM_DRIVER
platform_driver_unregister(&PLATFORM_DRIVER);
#endif
+ return retval;
+ }
+#endif
+
+#ifdef PS3_SYSTEM_BUS_DRIVER
+ if (firmware_has_feature(FW_FEATURE_PS3_LV1)) {
+ retval = ps3_system_bus_driver_register(
+ &PS3_SYSTEM_BUS_DRIVER);
+ if (retval < 0) {
+#ifdef PLATFORM_DRIVER
+ platform_driver_unregister(&PLATFORM_DRIVER);
+#endif
+#ifdef PCI_DRIVER
+ pci_unregister_driver(&PCI_DRIVER);
+#endif
+ return retval;
+ }
}
#endif
@@ -939,6 +998,10 @@ static void __exit ehci_hcd_cleanup(void)
#ifdef PCI_DRIVER
pci_unregister_driver(&PCI_DRIVER);
#endif
+#ifdef PS3_SYSTEM_BUS_DRIVER
+ if (firmware_has_feature(FW_FEATURE_PS3_LV1))
+ ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
+#endif
}
module_exit(ehci_hcd_cleanup);
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index bfe5f307cba..9af529d22b3 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -36,6 +36,8 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
int port;
int mask;
+ ehci_dbg(ehci, "suspend root hub\n");
+
if (time_before (jiffies, ehci->next_statechange))
msleep(5);
@@ -47,7 +49,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
ehci_quiesce (ehci);
hcd->state = HC_STATE_QUIESCING;
}
- ehci->command = readl (&ehci->regs->command);
+ ehci->command = ehci_readl(ehci, &ehci->regs->command);
if (ehci->reclaim)
ehci->reclaim_ready = 1;
ehci_work(ehci);
@@ -60,7 +62,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
ehci->bus_suspended = 0;
while (port--) {
u32 __iomem *reg = &ehci->regs->port_status [port];
- u32 t1 = readl (reg) & ~PORT_RWC_BITS;
+ u32 t1 = ehci_readl(ehci, reg) & ~PORT_RWC_BITS;
u32 t2 = t1;
/* keep track of which ports we suspend */
@@ -79,7 +81,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
if (t1 != t2) {
ehci_vdbg (ehci, "port %d, %08x -> %08x\n",
port + 1, t1, t2);
- writel (t2, reg);
+ ehci_writel(ehci, t2, reg);
}
}
@@ -92,8 +94,8 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
mask = INTR_MASK;
if (!device_may_wakeup(&hcd->self.root_hub->dev))
mask &= ~STS_PCD;
- writel(mask, &ehci->regs->intr_enable);
- readl(&ehci->regs->intr_enable);
+ ehci_writel(ehci, mask, &ehci->regs->intr_enable);
+ ehci_readl(ehci, &ehci->regs->intr_enable);
ehci->next_statechange = jiffies + msecs_to_jiffies(10);
spin_unlock_irq (&ehci->lock);
@@ -118,26 +120,26 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
* the last user of the controller, not reset/pm hardware keeping
* state we gave to it.
*/
- temp = readl(&ehci->regs->intr_enable);
+ temp = ehci_readl(ehci, &ehci->regs->intr_enable);
ehci_dbg(ehci, "resume root hub%s\n", temp ? "" : " after power loss");
/* at least some APM implementations will try to deliver
* IRQs right away, so delay them until we're ready.
*/
- writel(0, &ehci->regs->intr_enable);
+ ehci_writel(ehci, 0, &ehci->regs->intr_enable);
/* re-init operational registers */
- writel(0, &ehci->regs->segment);
- writel(ehci->periodic_dma, &ehci->regs->frame_list);
- writel((u32) ehci->async->qh_dma, &ehci->regs->async_next);
+ ehci_writel(ehci, 0, &ehci->regs->segment);
+ ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list);
+ ehci_writel(ehci, (u32) ehci->async->qh_dma, &ehci->regs->async_next);
/* restore CMD_RUN, framelist size, and irq threshold */
- writel (ehci->command, &ehci->regs->command);
+ ehci_writel(ehci, ehci->command, &ehci->regs->command);
/* manually resume the ports we suspended during bus_suspend() */
i = HCS_N_PORTS (ehci->hcs_params);
while (i--) {
- temp = readl (&ehci->regs->port_status [i]);
+ temp = ehci_readl(ehci, &ehci->regs->port_status [i]);
temp &= ~(PORT_RWC_BITS
| PORT_WKOC_E | PORT_WKDISC_E | PORT_WKCONN_E);
if (test_bit(i, &ehci->bus_suspended) &&
@@ -145,20 +147,20 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
ehci->reset_done [i] = jiffies + msecs_to_jiffies (20);
temp |= PORT_RESUME;
}
- writel (temp, &ehci->regs->port_status [i]);
+ ehci_writel(ehci, temp, &ehci->regs->port_status [i]);
}
i = HCS_N_PORTS (ehci->hcs_params);
mdelay (20);
while (i--) {
- temp = readl (&ehci->regs->port_status [i]);
+ temp = ehci_readl(ehci, &ehci->regs->port_status [i]);
if (test_bit(i, &ehci->bus_suspended) &&
(temp & PORT_SUSPEND)) {
temp &= ~(PORT_RWC_BITS | PORT_RESUME);
- writel (temp, &ehci->regs->port_status [i]);
+ ehci_writel(ehci, temp, &ehci->regs->port_status [i]);
ehci_vdbg (ehci, "resumed port %d\n", i + 1);
}
}
- (void) readl (&ehci->regs->command);
+ (void) ehci_readl(ehci, &ehci->regs->command);
/* maybe re-activate the schedule(s) */
temp = 0;
@@ -168,14 +170,14 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
temp |= CMD_PSE;
if (temp) {
ehci->command |= temp;
- writel (ehci->command, &ehci->regs->command);
+ ehci_writel(ehci, ehci->command, &ehci->regs->command);
}
ehci->next_statechange = jiffies + msecs_to_jiffies(5);
hcd->state = HC_STATE_RUNNING;
/* Now we can safely re-enable irqs */
- writel(INTR_MASK, &ehci->regs->intr_enable);
+ ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable);
spin_unlock_irq (&ehci->lock);
return 0;
@@ -190,9 +192,107 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
/*-------------------------------------------------------------------------*/
+/* Display the ports dedicated to the companion controller */
+static ssize_t show_companion(struct class_device *class_dev, char *buf)
+{
+ struct ehci_hcd *ehci;
+ int nports, index, n;
+ int count = PAGE_SIZE;
+ char *ptr = buf;
+
+ ehci = hcd_to_ehci(bus_to_hcd(class_get_devdata(class_dev)));
+ nports = HCS_N_PORTS(ehci->hcs_params);
+
+ for (index = 0; index < nports; ++index) {
+ if (test_bit(index, &ehci->companion_ports)) {
+ n = scnprintf(ptr, count, "%d\n", index + 1);
+ ptr += n;
+ count -= n;
+ }
+ }
+ return ptr - buf;
+}
+
+/*
+ * Dedicate or undedicate a port to the companion controller.
+ * Syntax is "[-]portnum", where a leading '-' sign means
+ * return control of the port to the EHCI controller.
+ */
+static ssize_t store_companion(struct class_device *class_dev,
+ const char *buf, size_t count)
+{
+ struct ehci_hcd *ehci;
+ int portnum, new_owner, try;
+ u32 __iomem *status_reg;
+ u32 port_status;
+
+ ehci = hcd_to_ehci(bus_to_hcd(class_get_devdata(class_dev)));
+ new_owner = PORT_OWNER; /* Owned by companion */
+ if (sscanf(buf, "%d", &portnum) != 1)
+ return -EINVAL;
+ if (portnum < 0) {
+ portnum = - portnum;
+ new_owner = 0; /* Owned by EHCI */
+ }
+ if (portnum <= 0 || portnum > HCS_N_PORTS(ehci->hcs_params))
+ return -ENOENT;
+ status_reg = &ehci->regs->port_status[--portnum];
+ if (new_owner)
+ set_bit(portnum, &ehci->companion_ports);
+ else
+ clear_bit(portnum, &ehci->companion_ports);
+
+ /*
+ * The controller won't set the OWNER bit if the port is
+ * enabled, so this loop will sometimes require at least two
+ * iterations: one to disable the port and one to set OWNER.
+ */
+
+ for (try = 4; try > 0; --try) {
+ spin_lock_irq(&ehci->lock);
+ port_status = ehci_readl(ehci, status_reg);
+ if ((port_status & PORT_OWNER) == new_owner
+ || (port_status & (PORT_OWNER | PORT_CONNECT))
+ == 0)
+ try = 0;
+ else {
+ port_status ^= PORT_OWNER;
+ port_status &= ~(PORT_PE | PORT_RWC_BITS);
+ ehci_writel(ehci, port_status, status_reg);
+ }
+ spin_unlock_irq(&ehci->lock);
+ if (try > 1)
+ msleep(5);
+ }
+ return count;
+}
+static CLASS_DEVICE_ATTR(companion, 0644, show_companion, store_companion);
+
+static inline void create_companion_file(struct ehci_hcd *ehci)
+{
+ int i;
+
+ /* with integrated TT there is no companion! */
+ if (!ehci_is_TDI(ehci))
+ i = class_device_create_file(ehci_to_hcd(ehci)->self.class_dev,
+ &class_device_attr_companion);
+}
+
+static inline void remove_companion_file(struct ehci_hcd *ehci)
+{
+ /* with integrated TT there is no companion! */
+ if (!ehci_is_TDI(ehci))
+ class_device_remove_file(ehci_to_hcd(ehci)->self.class_dev,
+ &class_device_attr_companion);
+}
+
+
+/*-------------------------------------------------------------------------*/
+
static int check_reset_complete (
struct ehci_hcd *ehci,
int index,
+ u32 __iomem *status_reg,
int port_status
) {
if (!(port_status & PORT_CONNECT)) {
@@ -217,7 +317,7 @@ static int check_reset_complete (
// what happens if HCS_N_CC(params) == 0 ?
port_status |= PORT_OWNER;
port_status &= ~PORT_RWC_BITS;
- writel (port_status, &ehci->regs->port_status [index]);
+ ehci_writel(ehci, port_status, status_reg);
} else
ehci_dbg (ehci, "port %d high speed\n", index + 1);
@@ -268,22 +368,21 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
/* port N changes (bit N)? */
spin_lock_irqsave (&ehci->lock, flags);
for (i = 0; i < ports; i++) {
- temp = readl (&ehci->regs->port_status [i]);
- if (temp & PORT_OWNER) {
- /* don't report this in GetPortStatus */
- if (temp & PORT_CSC) {
- temp &= ~PORT_RWC_BITS;
- temp |= PORT_CSC;
- writel (temp, &ehci->regs->port_status [i]);
- }
- continue;
- }
+ temp = ehci_readl(ehci, &ehci->regs->port_status [i]);
+
+ /*
+ * Return status information even for ports with OWNER set.
+ * Otherwise khubd wouldn't see the disconnect event when a
+ * high-speed device is switched over to the companion
+ * controller by the user.
+ */
+
if (!(temp & PORT_CONNECT))
ehci->reset_done [i] = 0;
if ((temp & mask) != 0
|| ((temp & PORT_RESUME) != 0
- && time_after (jiffies,
- ehci->reset_done [i]))) {
+ && time_after_eq(jiffies,
+ ehci->reset_done[i]))) {
if (i < 7)
buf [0] |= 1 << (i + 1);
else
@@ -345,6 +444,7 @@ static int ehci_hub_control (
) {
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
int ports = HCS_N_PORTS (ehci->hcs_params);
+ u32 __iomem *status_reg = &ehci->regs->port_status[wIndex - 1];
u32 temp, status;
unsigned long flags;
int retval = 0;
@@ -373,18 +473,22 @@ static int ehci_hub_control (
if (!wIndex || wIndex > ports)
goto error;
wIndex--;
- temp = readl (&ehci->regs->port_status [wIndex]);
- if (temp & PORT_OWNER)
- break;
+ temp = ehci_readl(ehci, status_reg);
+
+ /*
+ * Even if OWNER is set, so the port is owned by the
+ * companion controller, khubd needs to be able to clear
+ * the port-change status bits (especially
+ * USB_PORT_FEAT_C_CONNECTION).
+ */
switch (wValue) {
case USB_PORT_FEAT_ENABLE:
- writel (temp & ~PORT_PE,
- &ehci->regs->port_status [wIndex]);
+ ehci_writel(ehci, temp & ~PORT_PE, status_reg);
break;
case USB_PORT_FEAT_C_ENABLE:
- writel((temp & ~PORT_RWC_BITS) | PORT_PEC,
- &ehci->regs->port_status [wIndex]);
+ ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_PEC,
+ status_reg);
break;
case USB_PORT_FEAT_SUSPEND:
if (temp & PORT_RESET)
@@ -396,8 +500,8 @@ static int ehci_hub_control (
goto error;
/* resume signaling for 20 msec */
temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
- writel (temp | PORT_RESUME,
- &ehci->regs->port_status [wIndex]);
+ ehci_writel(ehci, temp | PORT_RESUME,
+ status_reg);
ehci->reset_done [wIndex] = jiffies
+ msecs_to_jiffies (20);
}
@@ -407,16 +511,17 @@ static int ehci_hub_control (
break;
case USB_PORT_FEAT_POWER:
if (HCS_PPC (ehci->hcs_params))
- writel (temp & ~(PORT_RWC_BITS | PORT_POWER),
- &ehci->regs->port_status [wIndex]);
+ ehci_writel(ehci,
+ temp & ~(PORT_RWC_BITS | PORT_POWER),
+ status_reg);
break;
case USB_PORT_FEAT_C_CONNECTION:
- writel((temp & ~PORT_RWC_BITS) | PORT_CSC,
- &ehci->regs->port_status [wIndex]);
+ ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_CSC,
+ status_reg);
break;
case USB_PORT_FEAT_C_OVER_CURRENT:
- writel((temp & ~PORT_RWC_BITS) | PORT_OCC,
- &ehci->regs->port_status [wIndex]);
+ ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_OCC,
+ status_reg);
break;
case USB_PORT_FEAT_C_RESET:
/* GetPortStatus clears reset */
@@ -424,7 +529,7 @@ static int ehci_hub_control (
default:
goto error;
}
- readl (&ehci->regs->command); /* unblock posted write */
+ ehci_readl(ehci, &ehci->regs->command); /* unblock posted write */
break;
case GetHubDescriptor:
ehci_hub_descriptor (ehci, (struct usb_hub_descriptor *)
@@ -440,7 +545,7 @@ static int ehci_hub_control (
goto error;
wIndex--;
status = 0;
- temp = readl (&ehci->regs->port_status [wIndex]);
+ temp = ehci_readl(ehci, status_reg);
// wPortChange bits
if (temp & PORT_CSC)
@@ -451,42 +556,55 @@ static int ehci_hub_control (
status |= 1 << USB_PORT_FEAT_C_OVER_CURRENT;
/* whoever resumes must GetPortStatus to complete it!! */
- if ((temp & PORT_RESUME)
- && time_after (jiffies,
- ehci->reset_done [wIndex])) {
- status |= 1 << USB_PORT_FEAT_C_SUSPEND;
- ehci->reset_done [wIndex] = 0;
+ if (temp & PORT_RESUME) {
- /* stop resume signaling */
- temp = readl (&ehci->regs->port_status [wIndex]);
- writel (temp & ~(PORT_RWC_BITS | PORT_RESUME),
- &ehci->regs->port_status [wIndex]);
- retval = handshake (
- &ehci->regs->port_status [wIndex],
- PORT_RESUME, 0, 2000 /* 2msec */);
- if (retval != 0) {
- ehci_err (ehci, "port %d resume error %d\n",
- wIndex + 1, retval);
- goto error;
+ /* Remote Wakeup received? */
+ if (!ehci->reset_done[wIndex]) {
+ /* resume signaling for 20 msec */
+ ehci->reset_done[wIndex] = jiffies
+ + msecs_to_jiffies(20);
+ /* check the port again */
+ mod_timer(&ehci_to_hcd(ehci)->rh_timer,
+ ehci->reset_done[wIndex]);
+ }
+
+ /* resume completed? */
+ else if (time_after_eq(jiffies,
+ ehci->reset_done[wIndex])) {
+ status |= 1 << USB_PORT_FEAT_C_SUSPEND;
+ ehci->reset_done[wIndex] = 0;
+
+ /* stop resume signaling */
+ temp = ehci_readl(ehci, status_reg);
+ ehci_writel(ehci,
+ temp & ~(PORT_RWC_BITS | PORT_RESUME),
+ status_reg);
+ retval = handshake(ehci, status_reg,
+ PORT_RESUME, 0, 2000 /* 2msec */);
+ if (retval != 0) {
+ ehci_err(ehci,
+ "port %d resume error %d\n",
+ wIndex + 1, retval);
+ goto error;
+ }
+ temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10));
}
- temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10));
}
/* whoever resets must GetPortStatus to complete it!! */
if ((temp & PORT_RESET)
- && time_after (jiffies,
- ehci->reset_done [wIndex])) {
+ && time_after_eq(jiffies,
+ ehci->reset_done[wIndex])) {
status |= 1 << USB_PORT_FEAT_C_RESET;
ehci->reset_done [wIndex] = 0;
/* force reset to complete */
- writel (temp & ~(PORT_RWC_BITS | PORT_RESET),
- &ehci->regs->port_status [wIndex]);
+ ehci_writel(ehci, temp & ~(PORT_RWC_BITS | PORT_RESET),
+ status_reg);
/* REVISIT: some hardware needs 550+ usec to clear
* this bit; seems too long to spin routinely...
*/
- retval = handshake (
- &ehci->regs->port_status [wIndex],
+ retval = handshake(ehci, status_reg,
PORT_RESET, 0, 750);
if (retval != 0) {
ehci_err (ehci, "port %d reset error %d\n",
@@ -495,28 +613,41 @@ static int ehci_hub_control (
}
/* see what we found out */
- temp = check_reset_complete (ehci, wIndex,
- readl (&ehci->regs->port_status [wIndex]));
+ temp = check_reset_complete (ehci, wIndex, status_reg,
+ ehci_readl(ehci, status_reg));
}
- // don't show wPortStatus if it's owned by a companion hc
- if (!(temp & PORT_OWNER)) {
- if (temp & PORT_CONNECT) {
- status |= 1 << USB_PORT_FEAT_CONNECTION;
- // status may be from integrated TT
- status |= ehci_port_speed(ehci, temp);
- }
- if (temp & PORT_PE)
- status |= 1 << USB_PORT_FEAT_ENABLE;
- if (temp & (PORT_SUSPEND|PORT_RESUME))
- status |= 1 << USB_PORT_FEAT_SUSPEND;
- if (temp & PORT_OC)
- status |= 1 << USB_PORT_FEAT_OVER_CURRENT;
- if (temp & PORT_RESET)
- status |= 1 << USB_PORT_FEAT_RESET;
- if (temp & PORT_POWER)
- status |= 1 << USB_PORT_FEAT_POWER;
+ /* transfer dedicated ports to the companion hc */
+ if ((temp & PORT_CONNECT) &&
+ test_bit(wIndex, &ehci->companion_ports)) {
+ temp &= ~PORT_RWC_BITS;
+ temp |= PORT_OWNER;
+ ehci_writel(ehci, temp, status_reg);
+ ehci_dbg(ehci, "port %d --> companion\n", wIndex + 1);
+ temp = ehci_readl(ehci, status_reg);
+ }
+
+ /*
+ * Even if OWNER is set, there's no harm letting khubd
+ * see the wPortStatus values (they should all be 0 except
+ * for PORT_POWER anyway).
+ */
+
+ if (temp & PORT_CONNECT) {
+ status |= 1 << USB_PORT_FEAT_CONNECTION;
+ // status may be from integrated TT
+ status |= ehci_port_speed(ehci, temp);
}
+ if (temp & PORT_PE)
+ status |= 1 << USB_PORT_FEAT_ENABLE;
+ if (temp & (PORT_SUSPEND|PORT_RESUME))
+ status |= 1 << USB_PORT_FEAT_SUSPEND;
+ if (temp & PORT_OC)
+ status |= 1 << USB_PORT_FEAT_OVER_CURRENT;
+ if (temp & PORT_RESET)
+ status |= 1 << USB_PORT_FEAT_RESET;
+ if (temp & PORT_POWER)
+ status |= 1 << USB_PORT_FEAT_POWER;
#ifndef EHCI_VERBOSE_DEBUG
if (status & ~0xffff) /* only if wPortChange is interesting */
@@ -541,7 +672,7 @@ static int ehci_hub_control (
if (!wIndex || wIndex > ports)
goto error;
wIndex--;
- temp = readl (&ehci->regs->port_status [wIndex]);
+ temp = ehci_readl(ehci, status_reg);
if (temp & PORT_OWNER)
break;
@@ -555,13 +686,12 @@ static int ehci_hub_control (
goto error;
if (device_may_wakeup(&hcd->self.root_hub->dev))
temp |= PORT_WAKE_BITS;
- writel (temp | PORT_SUSPEND,
- &ehci->regs->port_status [wIndex]);
+ ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
break;
case USB_PORT_FEAT_POWER:
if (HCS_PPC (ehci->hcs_params))
- writel (temp | PORT_POWER,
- &ehci->regs->port_status [wIndex]);
+ ehci_writel(ehci, temp | PORT_POWER,
+ status_reg);
break;
case USB_PORT_FEAT_RESET:
if (temp & PORT_RESUME)
@@ -589,7 +719,7 @@ static int ehci_hub_control (
ehci->reset_done [wIndex] = jiffies
+ msecs_to_jiffies (50);
}
- writel (temp, &ehci->regs->port_status [wIndex]);
+ ehci_writel(ehci, temp, status_reg);
break;
/* For downstream facing ports (these): one hub port is put
@@ -604,13 +734,13 @@ static int ehci_hub_control (
ehci_quiesce(ehci);
ehci_halt(ehci);
temp |= selector << 16;
- writel (temp, &ehci->regs->port_status [wIndex]);
+ ehci_writel(ehci, temp, status_reg);
break;
default:
goto error;
}
- readl (&ehci->regs->command); /* unblock posted writes */
+ ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
break;
default:
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index 4bc7970ba3e..12edc723ec7 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -38,7 +38,7 @@ static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev)
if ((temp & (3 << 13)) == (1 << 13)) {
temp &= 0x1fff;
ehci->debug = ehci_to_hcd(ehci)->regs + temp;
- temp = readl(&ehci->debug->control);
+ temp = ehci_readl(ehci, &ehci->debug->control);
ehci_info(ehci, "debug port %d%s\n",
HCS_DEBUG_PORT(ehci->hcs_params),
(temp & DBGP_ENABLED)
@@ -71,8 +71,24 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
u32 temp;
int retval;
+ switch (pdev->vendor) {
+ case PCI_VENDOR_ID_TOSHIBA_2:
+ /* celleb's companion chip */
+ if (pdev->device == 0x01b5) {
+#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
+ ehci->big_endian_mmio = 1;
+#else
+ ehci_warn(ehci,
+ "unsupported big endian Toshiba quirk\n");
+#endif
+ }
+ break;
+ }
+
ehci->caps = hcd->regs;
- ehci->regs = hcd->regs + HC_LENGTH(readl(&ehci->caps->hc_capbase));
+ ehci->regs = hcd->regs +
+ HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+
dbg_hcs_params(ehci, "reset");
dbg_hcc_params(ehci, "reset");
@@ -101,7 +117,7 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
}
/* cache this readonly data; minimize chip reads */
- ehci->hcs_params = readl(&ehci->caps->hcs_params);
+ ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
retval = ehci_halt(ehci);
if (retval)
@@ -235,8 +251,8 @@ static int ehci_pci_suspend(struct usb_hcd *hcd, pm_message_t message)
rc = -EINVAL;
goto bail;
}
- writel (0, &ehci->regs->intr_enable);
- (void)readl(&ehci->regs->intr_enable);
+ ehci_writel(ehci, 0, &ehci->regs->intr_enable);
+ (void)ehci_readl(ehci, &ehci->regs->intr_enable);
/* make sure snapshot being resumed re-enumerates everything */
if (message.event == PM_EVENT_PRETHAW) {
@@ -270,13 +286,13 @@ static int ehci_pci_resume(struct usb_hcd *hcd)
/* If CF is still set, we maintained PCI Vaux power.
* Just undo the effect of ehci_pci_suspend().
*/
- if (readl(&ehci->regs->configured_flag) == FLAG_CF) {
+ if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) {
int mask = INTR_MASK;
if (!device_may_wakeup(&hcd->self.root_hub->dev))
mask &= ~STS_PCD;
- writel(mask, &ehci->regs->intr_enable);
- readl(&ehci->regs->intr_enable);
+ ehci_writel(ehci, mask, &ehci->regs->intr_enable);
+ ehci_readl(ehci, &ehci->regs->intr_enable);
return 0;
}
@@ -300,9 +316,9 @@ static int ehci_pci_resume(struct usb_hcd *hcd)
/* here we "know" root ports should always stay powered */
ehci_port_power(ehci, 1);
- writel(ehci->command, &ehci->regs->command);
- writel(FLAG_CF, &ehci->regs->configured_flag);
- readl(&ehci->regs->command); /* unblock posted writes */
+ ehci_writel(ehci, ehci->command, &ehci->regs->command);
+ ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
+ ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
hcd->state = HC_STATE_SUSPENDED;
return 0;
diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c
new file mode 100644
index 00000000000..4d781a2a980
--- /dev/null
+++ b/drivers/usb/host/ehci-ps3.c
@@ -0,0 +1,193 @@
+/*
+ * PS3 EHCI Host Controller driver
+ *
+ * Copyright (C) 2006 Sony Computer Entertainment Inc.
+ * Copyright 2006 Sony Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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.
+ *
+ * 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 <asm/ps3.h>
+
+static int ps3_ehci_hc_reset(struct usb_hcd *hcd)
+{
+ int result;
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+
+ ehci->big_endian_mmio = 1;
+
+ ehci->caps = hcd->regs;
+ ehci->regs = hcd->regs + HC_LENGTH(ehci_readl(ehci,
+ &ehci->caps->hc_capbase));
+
+ dbg_hcs_params(ehci, "reset");
+ dbg_hcc_params(ehci, "reset");
+
+ ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
+
+ result = ehci_halt(ehci);
+
+ if (result)
+ return result;
+
+ result = ehci_init(hcd);
+
+ if (result)
+ return result;
+
+ ehci_port_power(ehci, 0);
+
+ return result;
+}
+
+static const struct hc_driver ps3_ehci_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "PS3 EHCI Host Controller",
+ .hcd_priv_size = sizeof(struct ehci_hcd),
+ .irq = ehci_irq,
+ .flags = HCD_MEMORY | HCD_USB2,
+ .reset = ps3_ehci_hc_reset,
+ .start = ehci_run,
+ .stop = ehci_stop,
+ .shutdown = ehci_shutdown,
+ .urb_enqueue = ehci_urb_enqueue,
+ .urb_dequeue = ehci_urb_dequeue,
+ .endpoint_disable = ehci_endpoint_disable,
+ .get_frame_number = ehci_get_frame,
+ .hub_status_data = ehci_hub_status_data,
+ .hub_control = ehci_hub_control,
+#if defined(CONFIG_PM)
+ .bus_suspend = ehci_bus_suspend,
+ .bus_resume = ehci_bus_resume,
+#endif
+};
+
+#if !defined(DEBUG)
+#undef dev_dbg
+static inline int __attribute__ ((format (printf, 2, 3))) dev_dbg(
+ const struct device *_dev, const char *fmt, ...) {return 0;}
+#endif
+
+
+static int ps3_ehci_sb_probe(struct ps3_system_bus_device *dev)
+{
+ int result;
+ struct usb_hcd *hcd;
+ unsigned int virq;
+ static u64 dummy_mask = DMA_32BIT_MASK;
+
+ if (usb_disabled()) {
+ result = -ENODEV;
+ goto fail_start;
+ }
+
+ result = ps3_mmio_region_create(dev->m_region);
+
+ if (result) {
+ dev_dbg(&dev->core, "%s:%d: ps3_map_mmio_region failed\n",
+ __func__, __LINE__);
+ result = -EPERM;
+ goto fail_mmio;
+ }
+
+ dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh\n", __func__,
+ __LINE__, dev->m_region->lpar_addr);
+
+ result = ps3_alloc_io_irq(PS3_BINDING_CPU_ANY, dev->interrupt_id, &virq);
+
+ if (result) {
+ dev_dbg(&dev->core, "%s:%d: ps3_construct_io_irq(%d) failed.\n",
+ __func__, __LINE__, virq);
+ result = -EPERM;
+ goto fail_irq;
+ }
+
+ dev->core.power.power_state = PMSG_ON;
+ dev->core.dma_mask = &dummy_mask; /* FIXME: for improper usb code */
+
+ hcd = usb_create_hcd(&ps3_ehci_hc_driver, &dev->core, dev->core.bus_id);
+
+ if (!hcd) {
+ dev_dbg(&dev->core, "%s:%d: usb_create_hcd failed\n", __func__,
+ __LINE__);
+ result = -ENOMEM;
+ goto fail_create_hcd;
+ }
+
+ hcd->rsrc_start = dev->m_region->lpar_addr;
+ hcd->rsrc_len = dev->m_region->len;
+ hcd->regs = ioremap(dev->m_region->lpar_addr, dev->m_region->len);
+
+ if (!hcd->regs) {
+ dev_dbg(&dev->core, "%s:%d: ioremap failed\n", __func__,
+ __LINE__);
+ result = -EPERM;
+ goto fail_ioremap;
+ }
+
+ dev_dbg(&dev->core, "%s:%d: hcd->rsrc_start %lxh\n", __func__, __LINE__,
+ (unsigned long)hcd->rsrc_start);
+ dev_dbg(&dev->core, "%s:%d: hcd->rsrc_len %lxh\n", __func__, __LINE__,
+ (unsigned long)hcd->rsrc_len);
+ dev_dbg(&dev->core, "%s:%d: hcd->regs %lxh\n", __func__, __LINE__,
+ (unsigned long)hcd->regs);
+ dev_dbg(&dev->core, "%s:%d: virq %lu\n", __func__, __LINE__,
+ (unsigned long)virq);
+
+ ps3_system_bus_set_driver_data(dev, hcd);
+
+ result = usb_add_hcd(hcd, virq, IRQF_DISABLED);
+
+ if (result) {
+ dev_dbg(&dev->core, "%s:%d: usb_add_hcd failed (%d)\n",
+ __func__, __LINE__, result);
+ goto fail_add_hcd;
+ }
+
+ return result;
+
+fail_add_hcd:
+ iounmap(hcd->regs);
+fail_ioremap:
+ usb_put_hcd(hcd);
+fail_create_hcd:
+ ps3_free_io_irq(virq);
+fail_irq:
+ ps3_free_mmio_region(dev->m_region);
+fail_mmio:
+fail_start:
+ return result;
+}
+
+static int ps3_ehci_sb_remove(struct ps3_system_bus_device *dev)
+{
+ struct usb_hcd *hcd =
+ (struct usb_hcd *)ps3_system_bus_get_driver_data(dev);
+
+ usb_put_hcd(hcd);
+ ps3_system_bus_set_driver_data(dev, NULL);
+
+ return 0;
+}
+
+MODULE_ALIAS("ps3-ehci");
+
+static struct ps3_system_bus_driver ps3_ehci_sb_driver = {
+ .match_id = PS3_MATCH_ID_EHCI,
+ .core = {
+ .name = "ps3-ehci-driver",
+ },
+ .probe = ps3_ehci_sb_probe,
+ .remove = ps3_ehci_sb_remove,
+};
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index 62e46dc60e8..e7fbbd00e7c 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -789,13 +789,14 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
head = ehci->async;
timer_action_done (ehci, TIMER_ASYNC_OFF);
if (!head->qh_next.qh) {
- u32 cmd = readl (&ehci->regs->command);
+ u32 cmd = ehci_readl(ehci, &ehci->regs->command);
if (!(cmd & CMD_ASE)) {
/* in case a clear of CMD_ASE didn't take yet */
- (void) handshake (&ehci->regs->status, STS_ASS, 0, 150);
+ (void)handshake(ehci, &ehci->regs->status,
+ STS_ASS, 0, 150);
cmd |= CMD_ASE | CMD_RUN;
- writel (cmd, &ehci->regs->command);
+ ehci_writel(ehci, cmd, &ehci->regs->command);
ehci_to_hcd(ehci)->state = HC_STATE_RUNNING;
/* posted write need not be known to HC yet ... */
}
@@ -1007,7 +1008,7 @@ static void end_unlink_async (struct ehci_hcd *ehci)
static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
{
- int cmd = readl (&ehci->regs->command);
+ int cmd = ehci_readl(ehci, &ehci->regs->command);
struct ehci_qh *prev;
#ifdef DEBUG
@@ -1025,7 +1026,8 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
if (ehci_to_hcd(ehci)->state != HC_STATE_HALT
&& !ehci->reclaim) {
/* ... and CMD_IAAD clear */
- writel (cmd & ~CMD_ASE, &ehci->regs->command);
+ ehci_writel(ehci, cmd & ~CMD_ASE,
+ &ehci->regs->command);
wmb ();
// handshake later, if we need to
timer_action_done (ehci, TIMER_ASYNC_OFF);
@@ -1054,8 +1056,8 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
ehci->reclaim_ready = 0;
cmd |= CMD_IAAD;
- writel (cmd, &ehci->regs->command);
- (void) readl (&ehci->regs->command);
+ ehci_writel(ehci, cmd, &ehci->regs->command);
+ (void)ehci_readl(ehci, &ehci->regs->command);
timer_action (ehci, TIMER_IAA_WATCHDOG);
}
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index 65c402a0fa7..7b5ae7111f2 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -433,20 +433,20 @@ static int enable_periodic (struct ehci_hcd *ehci)
/* did clearing PSE did take effect yet?
* takes effect only at frame boundaries...
*/
- status = handshake (&ehci->regs->status, STS_PSS, 0, 9 * 125);
+ status = handshake(ehci, &ehci->regs->status, STS_PSS, 0, 9 * 125);
if (status != 0) {
ehci_to_hcd(ehci)->state = HC_STATE_HALT;
return status;
}
- cmd = readl (&ehci->regs->command) | CMD_PSE;
- writel (cmd, &ehci->regs->command);
+ cmd = ehci_readl(ehci, &ehci->regs->command) | CMD_PSE;
+ ehci_writel(ehci, cmd, &ehci->regs->command);
/* posted write ... PSS happens later */
ehci_to_hcd(ehci)->state = HC_STATE_RUNNING;
/* make sure ehci_work scans these */
- ehci->next_uframe = readl (&ehci->regs->frame_index)
- % (ehci->periodic_size << 3);
+ ehci->next_uframe = ehci_readl(ehci, &ehci->regs->frame_index)
+ % (ehci->periodic_size << 3);
return 0;
}
@@ -458,14 +458,14 @@ static int disable_periodic (struct ehci_hcd *ehci)
/* did setting PSE not take effect yet?
* takes effect only at frame boundaries...
*/
- status = handshake (&ehci->regs->status, STS_PSS, STS_PSS, 9 * 125);
+ status = handshake(ehci, &ehci->regs->status, STS_PSS, STS_PSS, 9 * 125);
if (status != 0) {
ehci_to_hcd(ehci)->state = HC_STATE_HALT;
return status;
}
- cmd = readl (&ehci->regs->command) & ~CMD_PSE;
- writel (cmd, &ehci->regs->command);
+ cmd = ehci_readl(ehci, &ehci->regs->command) & ~CMD_PSE;
+ ehci_writel(ehci, cmd, &ehci->regs->command);
/* posted write ... */
ehci->next_uframe = -1;
@@ -1336,7 +1336,7 @@ iso_stream_schedule (
goto fail;
}
- now = readl (&ehci->regs->frame_index) % mod;
+ now = ehci_readl(ehci, &ehci->regs->frame_index) % mod;
/* when's the last uframe this urb could start? */
max = now + mod;
@@ -2088,7 +2088,7 @@ scan_periodic (struct ehci_hcd *ehci)
*/
now_uframe = ehci->next_uframe;
if (HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
- clock = readl (&ehci->regs->frame_index);
+ clock = ehci_readl(ehci, &ehci->regs->frame_index);
else
clock = now_uframe + mod - 1;
clock %= mod;
@@ -2213,7 +2213,7 @@ restart:
if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
break;
ehci->next_uframe = now_uframe;
- now = readl (&ehci->regs->frame_index) % mod;
+ now = ehci_readl(ehci, &ehci->regs->frame_index) % mod;
if (now_uframe == now)
break;
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 74dbc6c8228..46fa57a520d 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -74,7 +74,11 @@ struct ehci_hcd { /* one per controller */
/* per root hub port */
unsigned long reset_done [EHCI_MAX_ROOT_PORTS];
- unsigned long bus_suspended;
+ /* bit vectors (one bit per port) */
+ unsigned long bus_suspended; /* which ports were
+ already suspended at the start of a bus suspend */
+ unsigned long companion_ports; /* which ports are
+ dedicated to the companion controller */
/* per-HC memory pools (could be per-bus, but ...) */
struct dma_pool *qh_pool; /* qh per active urb */
@@ -92,6 +96,7 @@ struct ehci_hcd { /* one per controller */
unsigned is_tdi_rh_tt:1; /* TDI roothub with TT */
unsigned no_selective_suspend:1;
unsigned has_fsl_port_bug:1; /* FreeScale */
+ unsigned big_endian_mmio:1;
u8 sbrn; /* packed release number */
@@ -651,6 +656,45 @@ ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc)
#define ehci_has_fsl_portno_bug(e) (0)
#endif
+/*
+ * While most USB host controllers implement their registers in
+ * little-endian format, a minority (celleb companion chip) implement
+ * them in big endian format.
+ *
+ * This attempts to support either format at compile time without a
+ * runtime penalty, or both formats with the additional overhead
+ * of checking a flag bit.
+ */
+
+#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
+#define ehci_big_endian_mmio(e) ((e)->big_endian_mmio)
+#else
+#define ehci_big_endian_mmio(e) 0
+#endif
+
+static inline unsigned int ehci_readl (const struct ehci_hcd *ehci,
+ __u32 __iomem * regs)
+{
+#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
+ return ehci_big_endian_mmio(ehci) ?
+ readl_be(regs) :
+ readl(regs);
+#else
+ return readl(regs);
+#endif
+}
+
+static inline void ehci_writel (const struct ehci_hcd *ehci,
+ const unsigned int val, __u32 __iomem *regs)
+{
+#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
+ ehci_big_endian_mmio(ehci) ?
+ writel_be(val, regs) :
+ writel(val, regs);
+#else
+ writel(val, regs);
+#endif
+}
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/host/hc_crisv10.c b/drivers/usb/host/hc_crisv10.c
index 282d82efc0b..32f7caf2474 100644
--- a/drivers/usb/host/hc_crisv10.c
+++ b/drivers/usb/host/hc_crisv10.c
@@ -7,7 +7,6 @@
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ioport.h>
-#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/unistd.h>
@@ -2163,9 +2162,8 @@ static void etrax_usb_add_to_bulk_sb_list(struct urb *urb, int epid)
maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
- sb_desc = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, SLAB_FLAG);
+ sb_desc = kmem_cache_zalloc(usb_desc_cache, SLAB_FLAG);
assert(sb_desc != NULL);
- memset(sb_desc, 0, sizeof(USB_SB_Desc_t));
if (usb_pipeout(urb->pipe)) {
diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c
index 2718b5dc4ec..46873f2534b 100644
--- a/drivers/usb/host/isp116x-hcd.c
+++ b/drivers/usb/host/isp116x-hcd.c
@@ -1577,7 +1577,7 @@ static int isp116x_remove(struct platform_device *pdev)
#define resource_len(r) (((r)->end - (r)->start) + 1)
-static int __init isp116x_probe(struct platform_device *pdev)
+static int __devinit isp116x_probe(struct platform_device *pdev)
{
struct usb_hcd *hcd;
struct isp116x *isp116x;
diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index cc405512fa1..d849c809acb 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -18,19 +18,38 @@
#include <asm/mach-types.h>
#include <asm/hardware.h>
#include <asm/arch/board.h>
+#include <asm/arch/cpu.h>
#ifndef CONFIG_ARCH_AT91
#error "CONFIG_ARCH_AT91 must be defined."
#endif
-/* interface and function clocks */
-static struct clk *iclk, *fclk;
+/* interface and function clocks; sometimes also an AHB clock */
+static struct clk *iclk, *fclk, *hclk;
static int clocked;
extern int usb_disabled(void);
/*-------------------------------------------------------------------------*/
+static void at91_start_clock(void)
+{
+ if (cpu_is_at91sam9261())
+ clk_enable(hclk);
+ clk_enable(iclk);
+ clk_enable(fclk);
+ clocked = 1;
+}
+
+static void at91_stop_clock(void)
+{
+ clk_disable(fclk);
+ clk_disable(iclk);
+ if (cpu_is_at91sam9261())
+ clk_disable(hclk);
+ clocked = 0;
+}
+
static void at91_start_hc(struct platform_device *pdev)
{
struct usb_hcd *hcd = platform_get_drvdata(pdev);
@@ -41,9 +60,7 @@ static void at91_start_hc(struct platform_device *pdev)
/*
* Start the USB clocks.
*/
- clk_enable(iclk);
- clk_enable(fclk);
- clocked = 1;
+ at91_start_clock();
/*
* The USB host controller must remain in reset.
@@ -66,9 +83,7 @@ static void at91_stop_hc(struct platform_device *pdev)
/*
* Stop the USB clocks.
*/
- clk_disable(fclk);
- clk_disable(iclk);
- clocked = 0;
+ at91_stop_clock();
}
@@ -126,6 +141,8 @@ static int usb_hcd_at91_probe(const struct hc_driver *driver,
iclk = clk_get(&pdev->dev, "ohci_clk");
fclk = clk_get(&pdev->dev, "uhpck");
+ if (cpu_is_at91sam9261())
+ hclk = clk_get(&pdev->dev, "hck0");
at91_start_hc(pdev);
ohci_hcd_init(hcd_to_ohci(hcd));
@@ -137,6 +154,8 @@ static int usb_hcd_at91_probe(const struct hc_driver *driver,
/* Error handling */
at91_stop_hc(pdev);
+ if (cpu_is_at91sam9261())
+ clk_put(hclk);
clk_put(fclk);
clk_put(iclk);
@@ -170,11 +189,12 @@ static int usb_hcd_at91_remove(struct usb_hcd *hcd,
at91_stop_hc(pdev);
iounmap(hcd->regs);
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
- disable_irq_wake(hcd->irq);
+ if (cpu_is_at91sam9261())
+ clk_put(hclk);
clk_put(fclk);
clk_put(iclk);
- fclk = iclk = NULL;
+ fclk = iclk = hclk = NULL;
dev_set_drvdata(&pdev->dev, NULL);
return 0;
@@ -271,8 +291,6 @@ ohci_hcd_at91_drv_suspend(struct platform_device *pdev, pm_message_t mesg)
if (device_may_wakeup(&pdev->dev))
enable_irq_wake(hcd->irq);
- else
- disable_irq_wake(hcd->irq);
/*
* The integrated transceivers seem unable to notice disconnect,
@@ -283,9 +301,7 @@ ohci_hcd_at91_drv_suspend(struct platform_device *pdev, pm_message_t mesg)
*/
if (at91_suspend_entering_slow_clock()) {
ohci_usb_reset (ohci);
- clk_disable(fclk);
- clk_disable(iclk);
- clocked = 0;
+ at91_stop_clock();
}
return 0;
@@ -293,11 +309,13 @@ ohci_hcd_at91_drv_suspend(struct platform_device *pdev, pm_message_t mesg)
static int ohci_hcd_at91_drv_resume(struct platform_device *pdev)
{
- if (!clocked) {
- clk_enable(iclk);
- clk_enable(fclk);
- clocked = 1;
- }
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+
+ if (device_may_wakeup(&pdev->dev))
+ disable_irq_wake(hcd->irq);
+
+ if (!clocked)
+ at91_start_clock();
return 0;
}
@@ -320,18 +338,3 @@ static struct platform_driver ohci_hcd_at91_driver = {
},
};
-static int __init ohci_hcd_at91_init (void)
-{
- if (usb_disabled())
- return -ENODEV;
-
- return platform_driver_register(&ohci_hcd_at91_driver);
-}
-
-static void __exit ohci_hcd_at91_cleanup (void)
-{
- platform_driver_unregister(&ohci_hcd_at91_driver);
-}
-
-module_init (ohci_hcd_at91_init);
-module_exit (ohci_hcd_at91_cleanup);
diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c
index e70b2430e2a..663a0600b6e 100644
--- a/drivers/usb/host/ohci-au1xxx.c
+++ b/drivers/usb/host/ohci-au1xxx.c
@@ -345,19 +345,3 @@ static struct platform_driver ohci_hcd_au1xxx_driver = {
},
};
-static int __init ohci_hcd_au1xxx_init (void)
-{
- pr_debug (DRIVER_INFO " (Au1xxx)");
- pr_debug ("block sizes: ed %d td %d\n",
- sizeof (struct ed), sizeof (struct td));
-
- return platform_driver_register(&ohci_hcd_au1xxx_driver);
-}
-
-static void __exit ohci_hcd_au1xxx_cleanup (void)
-{
- platform_driver_unregister(&ohci_hcd_au1xxx_driver);
-}
-
-module_init (ohci_hcd_au1xxx_init);
-module_exit (ohci_hcd_au1xxx_cleanup);
diff --git a/drivers/usb/host/ohci-ep93xx.c b/drivers/usb/host/ohci-ep93xx.c
index 3348b07f0fe..a68ce9d3c52 100644
--- a/drivers/usb/host/ohci-ep93xx.c
+++ b/drivers/usb/host/ohci-ep93xx.c
@@ -78,7 +78,7 @@ static int usb_hcd_ep93xx_probe(const struct hc_driver *driver,
ohci_hcd_init(hcd_to_ohci(hcd));
- retval = usb_add_hcd(hcd, pdev->resource[1].start, SA_INTERRUPT);
+ retval = usb_add_hcd(hcd, pdev->resource[1].start, IRQF_DISABLED);
if (retval == 0)
return retval;
@@ -214,15 +214,3 @@ static struct platform_driver ohci_hcd_ep93xx_driver = {
},
};
-static int __init ohci_hcd_ep93xx_init(void)
-{
- return platform_driver_register(&ohci_hcd_ep93xx_driver);
-}
-
-static void __exit ohci_hcd_ep93xx_cleanup(void)
-{
- platform_driver_unregister(&ohci_hcd_ep93xx_driver);
-}
-
-module_init(ohci_hcd_ep93xx_init);
-module_exit(ohci_hcd_ep93xx_cleanup);
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index c1c1d871aba..f0d29eda3c6 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -42,6 +42,9 @@
#include <asm/system.h>
#include <asm/unaligned.h>
#include <asm/byteorder.h>
+#ifdef CONFIG_PPC_PS3
+#include <asm/firmware.h>
+#endif
#include "../core/hcd.h"
@@ -855,63 +858,172 @@ MODULE_LICENSE ("GPL");
#ifdef CONFIG_PCI
#include "ohci-pci.c"
+#define PCI_DRIVER ohci_pci_driver
#endif
#ifdef CONFIG_SA1111
#include "ohci-sa1111.c"
+#define SA1111_DRIVER ohci_hcd_sa1111_driver
#endif
#ifdef CONFIG_ARCH_S3C2410
#include "ohci-s3c2410.c"
+#define PLATFORM_DRIVER ohci_hcd_s3c2410_driver
#endif
#ifdef CONFIG_ARCH_OMAP
#include "ohci-omap.c"
+#define PLATFORM_DRIVER ohci_hcd_omap_driver
#endif
#ifdef CONFIG_ARCH_LH7A404
#include "ohci-lh7a404.c"
+#define PLATFORM_DRIVER ohci_hcd_lh7a404_driver
#endif
#ifdef CONFIG_PXA27x
#include "ohci-pxa27x.c"
+#define PLATFORM_DRIVER ohci_hcd_pxa27x_driver
#endif
#ifdef CONFIG_ARCH_EP93XX
#include "ohci-ep93xx.c"
+#define PLATFORM_DRIVER ohci_hcd_ep93xx_driver
#endif
#ifdef CONFIG_SOC_AU1X00
#include "ohci-au1xxx.c"
+#define PLATFORM_DRIVER ohci_hcd_au1xxx_driver
#endif
#ifdef CONFIG_PNX8550
#include "ohci-pnx8550.c"
+#define PLATFORM_DRIVER ohci_hcd_pnx8550_driver
#endif
#ifdef CONFIG_USB_OHCI_HCD_PPC_SOC
#include "ohci-ppc-soc.c"
+#define PLATFORM_DRIVER ohci_hcd_ppc_soc_driver
#endif
#ifdef CONFIG_ARCH_AT91
#include "ohci-at91.c"
+#define PLATFORM_DRIVER ohci_hcd_at91_driver
#endif
#ifdef CONFIG_ARCH_PNX4008
#include "ohci-pnx4008.c"
+#define PLATFORM_DRIVER usb_hcd_pnx4008_driver
+#endif
+
+
+#ifdef CONFIG_USB_OHCI_HCD_PPC_OF
+#include "ohci-ppc-of.c"
+#define OF_PLATFORM_DRIVER ohci_hcd_ppc_of_driver
+#endif
+
+#ifdef CONFIG_PPC_PS3
+#include "ohci-ps3.c"
+#define PS3_SYSTEM_BUS_DRIVER ps3_ohci_sb_driver
#endif
-#if !(defined(CONFIG_PCI) \
- || defined(CONFIG_SA1111) \
- || defined(CONFIG_ARCH_S3C2410) \
- || defined(CONFIG_ARCH_OMAP) \
- || defined (CONFIG_ARCH_LH7A404) \
- || defined (CONFIG_PXA27x) \
- || defined (CONFIG_ARCH_EP93XX) \
- || defined (CONFIG_SOC_AU1X00) \
- || defined (CONFIG_USB_OHCI_HCD_PPC_SOC) \
- || defined (CONFIG_ARCH_AT91) \
- || defined (CONFIG_ARCH_PNX4008) \
- )
+#if !defined(PCI_DRIVER) && \
+ !defined(PLATFORM_DRIVER) && \
+ !defined(OF_PLATFORM_DRIVER) && \
+ !defined(SA1111_DRIVER) && \
+ !defined(PS3_SYSTEM_BUS_DRIVER)
#error "missing bus glue for ohci-hcd"
#endif
+
+static int __init ohci_hcd_mod_init(void)
+{
+ int retval = 0;
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ printk (KERN_DEBUG "%s: " DRIVER_INFO "\n", hcd_name);
+ pr_debug ("%s: block sizes: ed %Zd td %Zd\n", hcd_name,
+ sizeof (struct ed), sizeof (struct td));
+
+#ifdef PS3_SYSTEM_BUS_DRIVER
+ if (firmware_has_feature(FW_FEATURE_PS3_LV1)) {
+ retval = ps3_system_bus_driver_register(
+ &PS3_SYSTEM_BUS_DRIVER);
+ if (retval < 0)
+ goto error_ps3;
+ }
+#endif
+
+#ifdef PLATFORM_DRIVER
+ retval = platform_driver_register(&PLATFORM_DRIVER);
+ if (retval < 0)
+ goto error_platform;
+#endif
+
+#ifdef OF_PLATFORM_DRIVER
+ retval = of_register_platform_driver(&OF_PLATFORM_DRIVER);
+ if (retval < 0)
+ goto error_of_platform;
+#endif
+
+#ifdef SA1111_DRIVER
+ retval = sa1111_driver_register(&SA1111_DRIVER);
+ if (retval < 0)
+ goto error_sa1111;
+#endif
+
+#ifdef PCI_DRIVER
+ retval = pci_register_driver(&PCI_DRIVER);
+ if (retval < 0)
+ goto error_pci;
+#endif
+
+ return retval;
+
+ /* Error path */
+#ifdef PCI_DRIVER
+ error_pci:
+#endif
+#ifdef SA1111_DRIVER
+ sa1111_driver_unregister(&SA1111_DRIVER);
+ error_sa1111:
+#endif
+#ifdef OF_PLATFORM_DRIVER
+ of_unregister_platform_driver(&OF_PLATFORM_DRIVER);
+ error_of_platform:
+#endif
+#ifdef PLATFORM_DRIVER
+ platform_driver_unregister(&PLATFORM_DRIVER);
+ error_platform:
+#endif
+#ifdef PS3_SYSTEM_BUS_DRIVER
+ if (firmware_has_feature(FW_FEATURE_PS3_LV1))
+ ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
+ error_ps3:
+#endif
+ return retval;
+}
+module_init(ohci_hcd_mod_init);
+
+static void __exit ohci_hcd_mod_exit(void)
+{
+#ifdef PCI_DRIVER
+ pci_unregister_driver(&PCI_DRIVER);
+#endif
+#ifdef SA1111_DRIVER
+ sa1111_driver_unregister(&SA1111_DRIVER);
+#endif
+#ifdef OF_PLATFORM_DRIVER
+ of_unregister_platform_driver(&OF_PLATFORM_DRIVER);
+#endif
+#ifdef PLATFORM_DRIVER
+ platform_driver_unregister(&PLATFORM_DRIVER);
+#endif
+#ifdef PS3_SYSTEM_BUS_DRIVER
+ if (firmware_has_feature(FW_FEATURE_PS3_LV1))
+ ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
+#endif
+}
+module_exit(ohci_hcd_mod_exit);
+
diff --git a/drivers/usb/host/ohci-lh7a404.c b/drivers/usb/host/ohci-lh7a404.c
index e9807cf73a2..4a043abd85e 100644
--- a/drivers/usb/host/ohci-lh7a404.c
+++ b/drivers/usb/host/ohci-lh7a404.c
@@ -251,19 +251,3 @@ static struct platform_driver ohci_hcd_lh7a404_driver = {
},
};
-static int __init ohci_hcd_lh7a404_init (void)
-{
- pr_debug (DRIVER_INFO " (LH7A404)");
- pr_debug ("block sizes: ed %d td %d\n",
- sizeof (struct ed), sizeof (struct td));
-
- return platform_driver_register(&ohci_hcd_lh7a404_driver);
-}
-
-static void __exit ohci_hcd_lh7a404_cleanup (void)
-{
- platform_driver_unregister(&ohci_hcd_lh7a404_driver);
-}
-
-module_init (ohci_hcd_lh7a404_init);
-module_exit (ohci_hcd_lh7a404_cleanup);
diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c
index 27be1f93688..5cfa3d1c441 100644
--- a/drivers/usb/host/ohci-omap.c
+++ b/drivers/usb/host/ohci-omap.c
@@ -544,22 +544,3 @@ static struct platform_driver ohci_hcd_omap_driver = {
},
};
-static int __init ohci_hcd_omap_init (void)
-{
- printk (KERN_DEBUG "%s: " DRIVER_INFO " (OMAP)\n", hcd_name);
- if (usb_disabled())
- return -ENODEV;
-
- pr_debug("%s: block sizes: ed %Zd td %Zd\n", hcd_name,
- sizeof (struct ed), sizeof (struct td));
-
- return platform_driver_register(&ohci_hcd_omap_driver);
-}
-
-static void __exit ohci_hcd_omap_cleanup (void)
-{
- platform_driver_unregister(&ohci_hcd_omap_driver);
-}
-
-module_init (ohci_hcd_omap_init);
-module_exit (ohci_hcd_omap_cleanup);
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
index 596e0b41e60..b331ac4d0d6 100644
--- a/drivers/usb/host/ohci-pci.c
+++ b/drivers/usb/host/ohci-pci.c
@@ -20,79 +20,154 @@
/*-------------------------------------------------------------------------*/
-static int
-ohci_pci_reset (struct usb_hcd *hcd)
+/* AMD 756, for most chips (early revs), corrupts register
+ * values on read ... so enable the vendor workaround.
+ */
+static int __devinit ohci_quirk_amd756(struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
- ohci_hcd_init (ohci);
- return ohci_init (ohci);
+ ohci->flags = OHCI_QUIRK_AMD756;
+ ohci_dbg (ohci, "AMD756 erratum 4 workaround\n");
+
+ /* also erratum 10 (suspend/resume issues) */
+ device_init_wakeup(&hcd->self.root_hub->dev, 0);
+
+ return 0;
}
-static int __devinit
-ohci_pci_start (struct usb_hcd *hcd)
+/* Apple's OHCI driver has a lot of bizarre workarounds
+ * for this chip. Evidently control and bulk lists
+ * can get confused. (B&W G3 models, and ...)
+ */
+static int __devinit ohci_quirk_opti(struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
- int ret;
- /* REVISIT this whole block should move to reset(), which handles
- * all the other one-time init.
+ ohci_dbg (ohci, "WARNING: OPTi workarounds unavailable\n");
+
+ return 0;
+}
+
+/* Check for NSC87560. We have to look at the bridge (fn1) to
+ * identify the USB (fn2). This quirk might apply to more or
+ * even all NSC stuff.
+ */
+static int __devinit ohci_quirk_ns(struct usb_hcd *hcd)
+{
+ struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
+ struct pci_dev *b;
+
+ b = pci_get_slot (pdev->bus, PCI_DEVFN (PCI_SLOT (pdev->devfn), 1));
+ if (b && b->device == PCI_DEVICE_ID_NS_87560_LIO
+ && b->vendor == PCI_VENDOR_ID_NS) {
+ struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+
+ ohci->flags |= OHCI_QUIRK_SUPERIO;
+ ohci_dbg (ohci, "Using NSC SuperIO setup\n");
+ }
+ pci_dev_put(b);
+
+ return 0;
+}
+
+/* Check for Compaq's ZFMicro chipset, which needs short
+ * delays before control or bulk queues get re-activated
+ * in finish_unlinks()
+ */
+static int __devinit ohci_quirk_zfmicro(struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+
+ ohci->flags |= OHCI_QUIRK_ZFMICRO;
+ ohci_dbg (ohci, "enabled Compaq ZFMicro chipset quirk\n");
+
+ return 0;
+}
+
+/* Check for Toshiba SCC OHCI which has big endian registers
+ * and little endian in memory data structures
+ */
+static int __devinit ohci_quirk_toshiba_scc(struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+
+ /* That chip is only present in the southbridge of some
+ * cell based platforms which are supposed to select
+ * CONFIG_USB_OHCI_BIG_ENDIAN_MMIO. We verify here if
+ * that was the case though.
+ */
+#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO
+ ohci->flags |= OHCI_QUIRK_BE_MMIO;
+ ohci_dbg (ohci, "enabled big endian Toshiba quirk\n");
+ return 0;
+#else
+ ohci_err (ohci, "unsupported big endian Toshiba quirk\n");
+ return -ENXIO;
+#endif
+}
+
+/* List of quirks for OHCI */
+static const struct pci_device_id ohci_pci_quirks[] = {
+ {
+ PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x740c),
+ .driver_data = (unsigned long)ohci_quirk_amd756,
+ },
+ {
+ PCI_DEVICE(PCI_VENDOR_ID_OPTI, 0xc861),
+ .driver_data = (unsigned long)ohci_quirk_opti,
+ },
+ {
+ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_ANY_ID),
+ .driver_data = (unsigned long)ohci_quirk_ns,
+ },
+ {
+ PCI_DEVICE(PCI_VENDOR_ID_COMPAQ, 0xa0f8),
+ .driver_data = (unsigned long)ohci_quirk_zfmicro,
+ },
+ {
+ PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, 0x01b6),
+ .driver_data = (unsigned long)ohci_quirk_toshiba_scc,
+ },
+ /* FIXME for some of the early AMD 760 southbridges, OHCI
+ * won't work at all. blacklist them.
*/
+
+ {},
+};
+
+static int ohci_pci_reset (struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+ int ret = 0;
+
if (hcd->self.controller) {
struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
+ const struct pci_device_id *quirk_id;
- /* AMD 756, for most chips (early revs), corrupts register
- * values on read ... so enable the vendor workaround.
- */
- if (pdev->vendor == PCI_VENDOR_ID_AMD
- && pdev->device == 0x740c) {
- ohci->flags = OHCI_QUIRK_AMD756;
- ohci_dbg (ohci, "AMD756 erratum 4 workaround\n");
- /* also erratum 10 (suspend/resume issues) */
- device_init_wakeup(&hcd->self.root_hub->dev, 0);
+ quirk_id = pci_match_id(ohci_pci_quirks, pdev);
+ if (quirk_id != NULL) {
+ int (*quirk)(struct usb_hcd *ohci);
+ quirk = (void *)quirk_id->driver_data;
+ ret = quirk(hcd);
}
+ }
+ if (ret == 0) {
+ ohci_hcd_init (ohci);
+ return ohci_init (ohci);
+ }
+ return ret;
+}
- /* FIXME for some of the early AMD 760 southbridges, OHCI
- * won't work at all. blacklist them.
- */
-
- /* Apple's OHCI driver has a lot of bizarre workarounds
- * for this chip. Evidently control and bulk lists
- * can get confused. (B&W G3 models, and ...)
- */
- else if (pdev->vendor == PCI_VENDOR_ID_OPTI
- && pdev->device == 0xc861) {
- ohci_dbg (ohci,
- "WARNING: OPTi workarounds unavailable\n");
- }
- /* Check for NSC87560. We have to look at the bridge (fn1) to
- * identify the USB (fn2). This quirk might apply to more or
- * even all NSC stuff.
- */
- else if (pdev->vendor == PCI_VENDOR_ID_NS) {
- struct pci_dev *b;
-
- b = pci_get_slot (pdev->bus,
- PCI_DEVFN (PCI_SLOT (pdev->devfn), 1));
- if (b && b->device == PCI_DEVICE_ID_NS_87560_LIO
- && b->vendor == PCI_VENDOR_ID_NS) {
- ohci->flags |= OHCI_QUIRK_SUPERIO;
- ohci_dbg (ohci, "Using NSC SuperIO setup\n");
- }
- pci_dev_put(b);
- }
+static int __devinit ohci_pci_start (struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+ int ret;
- /* Check for Compaq's ZFMicro chipset, which needs short
- * delays before control or bulk queues get re-activated
- * in finish_unlinks()
- */
- else if (pdev->vendor == PCI_VENDOR_ID_COMPAQ
- && pdev->device == 0xa0f8) {
- ohci->flags |= OHCI_QUIRK_ZFMICRO;
- ohci_dbg (ohci,
- "enabled Compaq ZFMicro chipset quirk\n");
- }
+#ifdef CONFIG_PM /* avoid warnings about unused pdev */
+ if (hcd->self.controller) {
+ struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
/* RWC may not be set for add-in PCI cards, since boot
* firmware probably ignored them. This transfers PCI
@@ -101,16 +176,14 @@ ohci_pci_start (struct usb_hcd *hcd)
if (device_may_wakeup(&pdev->dev))
ohci->hc_control |= OHCI_CTRL_RWC;
}
+#endif /* CONFIG_PM */
- /* NOTE: there may have already been a first reset, to
- * keep bios/smm irqs from making trouble
- */
- if ((ret = ohci_run (ohci)) < 0) {
+ ret = ohci_run (ohci);
+ if (ret < 0) {
ohci_err (ohci, "can't start\n");
ohci_stop (hcd);
- return ret;
}
- return 0;
+ return ret;
}
#ifdef CONFIG_PM
@@ -238,23 +311,3 @@ static struct pci_driver ohci_pci_driver = {
.shutdown = usb_hcd_pci_shutdown,
};
-
-static int __init ohci_hcd_pci_init (void)
-{
- printk (KERN_DEBUG "%s: " DRIVER_INFO " (PCI)\n", hcd_name);
- if (usb_disabled())
- return -ENODEV;
-
- pr_debug ("%s: block sizes: ed %Zd td %Zd\n", hcd_name,
- sizeof (struct ed), sizeof (struct td));
- return pci_register_driver (&ohci_pci_driver);
-}
-module_init (ohci_hcd_pci_init);
-
-/*-------------------------------------------------------------------------*/
-
-static void __exit ohci_hcd_pci_cleanup (void)
-{
- pci_unregister_driver (&ohci_pci_driver);
-}
-module_exit (ohci_hcd_pci_cleanup);
diff --git a/drivers/usb/host/ohci-pnx4008.c b/drivers/usb/host/ohci-pnx4008.c
index 3a8cbfb6905..d601bbb9387 100644
--- a/drivers/usb/host/ohci-pnx4008.c
+++ b/drivers/usb/host/ohci-pnx4008.c
@@ -421,7 +421,7 @@ static int __devinit usb_hcd_pnx4008_probe(struct platform_device *pdev)
ohci_hcd_init(ohci);
dev_info(&pdev->dev, "at 0x%p, irq %d\n", hcd->regs, hcd->irq);
- ret = usb_add_hcd(hcd, irq, SA_INTERRUPT);
+ ret = usb_add_hcd(hcd, irq, IRQF_DISABLED);
if (ret == 0)
return ret;
@@ -465,15 +465,3 @@ static struct platform_driver usb_hcd_pnx4008_driver = {
.remove = usb_hcd_pnx4008_remove,
};
-static int __init usb_hcd_pnx4008_init(void)
-{
- return platform_driver_register(&usb_hcd_pnx4008_driver);
-}
-
-static void __exit usb_hcd_pnx4008_cleanup(void)
-{
- return platform_driver_unregister(&usb_hcd_pnx4008_driver);
-}
-
-module_init(usb_hcd_pnx4008_init);
-module_exit(usb_hcd_pnx4008_cleanup);
diff --git a/drivers/usb/host/ohci-pnx8550.c b/drivers/usb/host/ohci-pnx8550.c
index 6922b91b170..85fdfd2a7ad 100644
--- a/drivers/usb/host/ohci-pnx8550.c
+++ b/drivers/usb/host/ohci-pnx8550.c
@@ -107,7 +107,7 @@ int usb_hcd_pnx8550_probe (const struct hc_driver *driver,
ohci_hcd_init(hcd_to_ohci(hcd));
- retval = usb_add_hcd(hcd, dev->resource[1].start, SA_INTERRUPT);
+ retval = usb_add_hcd(hcd, dev->resource[1].start, IRQF_DISABLED);
if (retval == 0)
return retval;
@@ -240,19 +240,3 @@ static struct platform_driver ohci_hcd_pnx8550_driver = {
.remove = ohci_hcd_pnx8550_drv_remove,
};
-static int __init ohci_hcd_pnx8550_init (void)
-{
- pr_debug (DRIVER_INFO " (pnx8550)");
- pr_debug ("block sizes: ed %d td %d\n",
- sizeof (struct ed), sizeof (struct td));
-
- return platform_driver_register(&ohci_hcd_pnx8550_driver);
-}
-
-static void __exit ohci_hcd_pnx8550_cleanup (void)
-{
- platform_driver_unregister(&ohci_hcd_pnx8550_driver);
-}
-
-module_init (ohci_hcd_pnx8550_init);
-module_exit (ohci_hcd_pnx8550_cleanup);
diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c
new file mode 100644
index 00000000000..08e237c7bc4
--- /dev/null
+++ b/drivers/usb/host/ohci-ppc-of.c
@@ -0,0 +1,232 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
+ * (C) Copyright 2002 Hewlett-Packard Company
+ * (C) Copyright 2006 Sylvain Munaut <tnt@246tNt.com>
+ *
+ * Bus glue for OHCI HC on the of_platform bus
+ *
+ * Modified for of_platform bus from ohci-sa1111.c
+ *
+ * This file is licenced under the GPL.
+ */
+
+#include <linux/signal.h>
+
+#include <asm/of_platform.h>
+#include <asm/prom.h>
+
+
+static int __devinit
+ohci_ppc_of_start(struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+ int ret;
+
+ if ((ret = ohci_init(ohci)) < 0)
+ return ret;
+
+ if ((ret = ohci_run(ohci)) < 0) {
+ err("can't start %s", ohci_to_hcd(ohci)->self.bus_name);
+ ohci_stop(hcd);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct hc_driver ohci_ppc_of_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "OF OHCI",
+ .hcd_priv_size = sizeof(struct ohci_hcd),
+
+ /*
+ * generic hardware linkage
+ */
+ .irq = ohci_irq,
+ .flags = HCD_USB11 | HCD_MEMORY,
+
+ /*
+ * basic lifecycle operations
+ */
+ .start = ohci_ppc_of_start,
+ .stop = ohci_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_hub_status_data,
+ .hub_control = ohci_hub_control,
+ .hub_irq_enable = ohci_rhsc_enable,
+#ifdef CONFIG_PM
+ .bus_suspend = ohci_bus_suspend,
+ .bus_resume = ohci_bus_resume,
+#endif
+ .start_port_reset = ohci_start_port_reset,
+};
+
+
+static int __devinit
+ohci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match)
+{
+ struct device_node *dn = op->node;
+ struct usb_hcd *hcd;
+ struct ohci_hcd *ohci;
+ struct resource res;
+ int irq;
+
+ int rv;
+ int is_bigendian;
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ is_bigendian =
+ device_is_compatible(dn, "ohci-bigendian") ||
+ device_is_compatible(dn, "ohci-be");
+
+ dev_dbg(&op->dev, "initializing PPC-OF USB Controller\n");
+
+ rv = of_address_to_resource(dn, 0, &res);
+ if (rv)
+ return rv;
+
+ hcd = usb_create_hcd(&ohci_ppc_of_hc_driver, &op->dev, "PPC-OF USB");
+ if (!hcd)
+ return -ENOMEM;
+
+ hcd->rsrc_start = res.start;
+ 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");
+ 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");
+ rv = -EBUSY;
+ goto err_irq;
+ }
+
+ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+ if (!hcd->regs) {
+ printk(KERN_ERR __FILE__ ": ioremap failed\n");
+ rv = -ENOMEM;
+ goto err_ioremap;
+ }
+
+ ohci = hcd_to_ohci(hcd);
+ if (is_bigendian)
+ ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC;
+
+ ohci_hcd_init(ohci);
+
+ rv = usb_add_hcd(hcd, irq, 0);
+ if (rv == 0)
+ return 0;
+
+ iounmap(hcd->regs);
+err_ioremap:
+ irq_dispose_mapping(irq);
+err_irq:
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+err_rmr:
+ usb_put_hcd(hcd);
+
+ return rv;
+}
+
+static int ohci_hcd_ppc_of_remove(struct of_device *op)
+{
+ struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
+ dev_set_drvdata(&op->dev, NULL);
+
+ dev_dbg(&op->dev, "stopping PPC-OF USB Controller\n");
+
+ usb_remove_hcd(hcd);
+
+ iounmap(hcd->regs);
+ irq_dispose_mapping(hcd->irq);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+
+ usb_put_hcd(hcd);
+
+ return 0;
+}
+
+static int ohci_hcd_ppc_of_shutdown(struct of_device *op)
+{
+ struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
+
+ if (hcd->driver->shutdown)
+ hcd->driver->shutdown(hcd);
+
+ return 0;
+}
+
+
+static struct of_device_id ohci_hcd_ppc_of_match[] = {
+#ifdef CONFIG_USB_OHCI_HCD_PPC_OF_BE
+ {
+ .name = "usb",
+ .compatible = "ohci-bigendian",
+ },
+ {
+ .name = "usb",
+ .compatible = "ohci-be",
+ },
+#endif
+#ifdef CONFIG_USB_OHCI_HCD_PPC_OF_LE
+ {
+ .name = "usb",
+ .compatible = "ohci-littledian",
+ },
+ {
+ .name = "usb",
+ .compatible = "ohci-le",
+ },
+#endif
+ {},
+};
+MODULE_DEVICE_TABLE(of, ohci_hcd_ppc_of_match);
+
+#if !defined(CONFIG_USB_OHCI_HCD_PPC_OF_BE) && \
+ !defined(CONFIG_USB_OHCI_HCD_PPC_OF_LE)
+#error "No endianess selected for ppc-of-ohci"
+#endif
+
+
+static struct of_platform_driver ohci_hcd_ppc_of_driver = {
+ .name = "ppc-of-ohci",
+ .match_table = ohci_hcd_ppc_of_match,
+ .probe = ohci_hcd_ppc_of_probe,
+ .remove = ohci_hcd_ppc_of_remove,
+ .shutdown = ohci_hcd_ppc_of_shutdown,
+#ifdef CONFIG_PM
+ /*.suspend = ohci_hcd_ppc_soc_drv_suspend,*/
+ /*.resume = ohci_hcd_ppc_soc_drv_resume,*/
+#endif
+ .driver = {
+ .name = "ppc-of-ohci",
+ .owner = THIS_MODULE,
+ },
+};
+
diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c
index e1a7eb81731..1a2e1777ca6 100644
--- a/drivers/usb/host/ohci-ppc-soc.c
+++ b/drivers/usb/host/ohci-ppc-soc.c
@@ -72,7 +72,7 @@ static int usb_hcd_ppc_soc_probe(const struct hc_driver *driver,
}
ohci = hcd_to_ohci(hcd);
- ohci->flags |= OHCI_BIG_ENDIAN;
+ ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC;
ohci_hcd_init(ohci);
retval = usb_add_hcd(hcd, irq, IRQF_DISABLED);
@@ -208,19 +208,3 @@ static struct platform_driver ohci_hcd_ppc_soc_driver = {
},
};
-static int __init ohci_hcd_ppc_soc_init(void)
-{
- pr_debug(DRIVER_INFO " (PPC SOC)\n");
- pr_debug("block sizes: ed %d td %d\n", sizeof(struct ed),
- sizeof(struct td));
-
- return platform_driver_register(&ohci_hcd_ppc_soc_driver);
-}
-
-static void __exit ohci_hcd_ppc_soc_cleanup(void)
-{
- platform_driver_unregister(&ohci_hcd_ppc_soc_driver);
-}
-
-module_init(ohci_hcd_ppc_soc_init);
-module_exit(ohci_hcd_ppc_soc_cleanup);
diff --git a/drivers/usb/host/ohci-ps3.c b/drivers/usb/host/ohci-ps3.c
new file mode 100644
index 00000000000..62283a3926d
--- /dev/null
+++ b/drivers/usb/host/ohci-ps3.c
@@ -0,0 +1,196 @@
+/*
+ * PS3 OHCI Host Controller driver
+ *
+ * Copyright (C) 2006 Sony Computer Entertainment Inc.
+ * Copyright 2006 Sony Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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.
+ *
+ * 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 <asm/ps3.h>
+
+static int ps3_ohci_hc_reset(struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+
+ ohci->flags |= OHCI_QUIRK_BE_MMIO;
+ ohci_hcd_init(ohci);
+ return ohci_init(ohci);
+}
+
+static int __devinit ps3_ohci_hc_start(struct usb_hcd *hcd)
+{
+ int result;
+ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+
+ /* Handle root hub init quirk in spider south bridge. */
+ /* Also set PwrOn2PwrGood to 0x7f (254ms). */
+
+ ohci_writel(ohci, 0x7f000000 | RH_A_PSM | RH_A_OCPM,
+ &ohci->regs->roothub.a);
+ ohci_writel(ohci, 0x00060000, &ohci->regs->roothub.b);
+
+ result = ohci_run(ohci);
+
+ if (result < 0) {
+ err("can't start %s", hcd->self.bus_name);
+ ohci_stop(hcd);
+ }
+
+ return result;
+}
+
+static const struct hc_driver ps3_ohci_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "PS3 OHCI Host Controller",
+ .hcd_priv_size = sizeof(struct ohci_hcd),
+ .irq = ohci_irq,
+ .flags = HCD_MEMORY | HCD_USB11,
+ .reset = ps3_ohci_hc_reset,
+ .start = ps3_ohci_hc_start,
+ .stop = ohci_stop,
+ .shutdown = ohci_shutdown,
+ .urb_enqueue = ohci_urb_enqueue,
+ .urb_dequeue = ohci_urb_dequeue,
+ .endpoint_disable = ohci_endpoint_disable,
+ .get_frame_number = ohci_get_frame,
+ .hub_status_data = ohci_hub_status_data,
+ .hub_control = ohci_hub_control,
+ .hub_irq_enable = ohci_rhsc_enable,
+ .start_port_reset = ohci_start_port_reset,
+#if defined(CONFIG_PM)
+ .bus_suspend = ohci_bus_suspend,
+ .bus_resume = ohci_bus_resume,
+#endif
+};
+
+/* redefine dev_dbg to do a syntax check */
+
+#if !defined(DEBUG)
+#undef dev_dbg
+static inline int __attribute__ ((format (printf, 2, 3))) dev_dbg(
+ const struct device *_dev, const char *fmt, ...) {return 0;}
+#endif
+
+static int ps3_ohci_sb_probe(struct ps3_system_bus_device *dev)
+{
+ int result;
+ struct usb_hcd *hcd;
+ unsigned int virq;
+ static u64 dummy_mask = DMA_32BIT_MASK;
+
+ if (usb_disabled()) {
+ result = -ENODEV;
+ goto fail_start;
+ }
+
+ result = ps3_mmio_region_create(dev->m_region);
+
+ if (result) {
+ dev_dbg(&dev->core, "%s:%d: ps3_map_mmio_region failed\n",
+ __func__, __LINE__);
+ result = -EPERM;
+ goto fail_mmio;
+ }
+
+ dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh\n", __func__,
+ __LINE__, dev->m_region->lpar_addr);
+
+ result = ps3_alloc_io_irq(PS3_BINDING_CPU_ANY, dev->interrupt_id, &virq);
+
+ if (result) {
+ dev_dbg(&dev->core, "%s:%d: ps3_construct_io_irq(%d) failed.\n",
+ __func__, __LINE__, virq);
+ result = -EPERM;
+ goto fail_irq;
+ }
+
+ dev->core.power.power_state = PMSG_ON;
+ dev->core.dma_mask = &dummy_mask; /* FIXME: for improper usb code */
+
+ hcd = usb_create_hcd(&ps3_ohci_hc_driver, &dev->core, dev->core.bus_id);
+
+ if (!hcd) {
+ dev_dbg(&dev->core, "%s:%d: usb_create_hcd failed\n", __func__,
+ __LINE__);
+ result = -ENOMEM;
+ goto fail_create_hcd;
+ }
+
+ hcd->rsrc_start = dev->m_region->lpar_addr;
+ hcd->rsrc_len = dev->m_region->len;
+ hcd->regs = ioremap(dev->m_region->lpar_addr, dev->m_region->len);
+
+ if (!hcd->regs) {
+ dev_dbg(&dev->core, "%s:%d: ioremap failed\n", __func__,
+ __LINE__);
+ result = -EPERM;
+ goto fail_ioremap;
+ }
+
+ dev_dbg(&dev->core, "%s:%d: hcd->rsrc_start %lxh\n", __func__, __LINE__,
+ (unsigned long)hcd->rsrc_start);
+ dev_dbg(&dev->core, "%s:%d: hcd->rsrc_len %lxh\n", __func__, __LINE__,
+ (unsigned long)hcd->rsrc_len);
+ dev_dbg(&dev->core, "%s:%d: hcd->regs %lxh\n", __func__, __LINE__,
+ (unsigned long)hcd->regs);
+ dev_dbg(&dev->core, "%s:%d: virq %lu\n", __func__, __LINE__,
+ (unsigned long)virq);
+
+ ps3_system_bus_set_driver_data(dev, hcd);
+
+ result = usb_add_hcd(hcd, virq, IRQF_DISABLED);
+
+ if (result) {
+ dev_dbg(&dev->core, "%s:%d: usb_add_hcd failed (%d)\n",
+ __func__, __LINE__, result);
+ goto fail_add_hcd;
+ }
+
+ return result;
+
+fail_add_hcd:
+ iounmap(hcd->regs);
+fail_ioremap:
+ usb_put_hcd(hcd);
+fail_create_hcd:
+ ps3_free_io_irq(virq);
+fail_irq:
+ ps3_free_mmio_region(dev->m_region);
+fail_mmio:
+fail_start:
+ return result;
+}
+
+static int ps3_ohci_sb_remove (struct ps3_system_bus_device *dev)
+{
+ struct usb_hcd *hcd =
+ (struct usb_hcd *)ps3_system_bus_get_driver_data(dev);
+
+ usb_put_hcd(hcd);
+ ps3_system_bus_set_driver_data(dev, NULL);
+
+ return 0;
+}
+
+MODULE_ALIAS("ps3-ohci");
+
+static struct ps3_system_bus_driver ps3_ohci_sb_driver = {
+ .match_id = PS3_MATCH_ID_OHCI,
+ .core = {
+ .name = "ps3-ohci-driver",
+ },
+ .probe = ps3_ohci_sb_probe,
+ .remove = ps3_ohci_sb_remove,
+};
diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c
index 3bbea844a9e..f1563dc319d 100644
--- a/drivers/usb/host/ohci-pxa27x.c
+++ b/drivers/usb/host/ohci-pxa27x.c
@@ -369,19 +369,3 @@ static struct platform_driver ohci_hcd_pxa27x_driver = {
},
};
-static int __init ohci_hcd_pxa27x_init (void)
-{
- pr_debug (DRIVER_INFO " (pxa27x)");
- pr_debug ("block sizes: ed %d td %d\n",
- sizeof (struct ed), sizeof (struct td));
-
- return platform_driver_register(&ohci_hcd_pxa27x_driver);
-}
-
-static void __exit ohci_hcd_pxa27x_cleanup (void)
-{
- platform_driver_unregister(&ohci_hcd_pxa27x_driver);
-}
-
-module_init (ohci_hcd_pxa27x_init);
-module_exit (ohci_hcd_pxa27x_cleanup);
diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c
index b350d45033e..6829814b7aa 100644
--- a/drivers/usb/host/ohci-s3c2410.c
+++ b/drivers/usb/host/ohci-s3c2410.c
@@ -501,15 +501,3 @@ static struct platform_driver ohci_hcd_s3c2410_driver = {
},
};
-static int __init ohci_hcd_s3c2410_init (void)
-{
- return platform_driver_register(&ohci_hcd_s3c2410_driver);
-}
-
-static void __exit ohci_hcd_s3c2410_cleanup (void)
-{
- platform_driver_unregister(&ohci_hcd_s3c2410_driver);
-}
-
-module_init (ohci_hcd_s3c2410_init);
-module_exit (ohci_hcd_s3c2410_cleanup);
diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c
index fe0090e3367..0f48f2d9922 100644
--- a/drivers/usb/host/ohci-sa1111.c
+++ b/drivers/usb/host/ohci-sa1111.c
@@ -269,19 +269,3 @@ static struct sa1111_driver ohci_hcd_sa1111_driver = {
.remove = ohci_hcd_sa1111_drv_remove,
};
-static int __init ohci_hcd_sa1111_init (void)
-{
- dbg (DRIVER_INFO " (SA-1111)");
- dbg ("block sizes: ed %d td %d",
- sizeof (struct ed), sizeof (struct td));
-
- return sa1111_driver_register(&ohci_hcd_sa1111_driver);
-}
-
-static void __exit ohci_hcd_sa1111_cleanup (void)
-{
- sa1111_driver_unregister(&ohci_hcd_sa1111_driver);
-}
-
-module_init (ohci_hcd_sa1111_init);
-module_exit (ohci_hcd_sa1111_cleanup);
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
index 405257f3e85..c2b5ecfe5e9 100644
--- a/drivers/usb/host/ohci.h
+++ b/drivers/usb/host/ohci.h
@@ -394,8 +394,9 @@ struct ohci_hcd {
#define OHCI_QUIRK_AMD756 0x01 /* erratum #4 */
#define OHCI_QUIRK_SUPERIO 0x02 /* natsemi */
#define OHCI_QUIRK_INITRESET 0x04 /* SiS, OPTi, ... */
-#define OHCI_BIG_ENDIAN 0x08 /* big endian HC */
-#define OHCI_QUIRK_ZFMICRO 0x10 /* Compaq ZFMicro chipset*/
+#define OHCI_QUIRK_BE_DESC 0x08 /* BE descriptors */
+#define OHCI_QUIRK_BE_MMIO 0x10 /* BE registers */
+#define OHCI_QUIRK_ZFMICRO 0x20 /* Compaq ZFMicro chipset*/
// there are also chip quirks/bugs in init logic
};
@@ -439,117 +440,164 @@ static inline struct usb_hcd *ohci_to_hcd (const struct ohci_hcd *ohci)
* a minority (notably the IBM STB04XXX and the Motorola MPC5200
* processors) implement them in big endian format.
*
+ * In addition some more exotic implementations like the Toshiba
+ * Spider (aka SCC) cell southbridge are "mixed" endian, that is,
+ * they have a different endianness for registers vs. in-memory
+ * descriptors.
+ *
* This attempts to support either format at compile time without a
* runtime penalty, or both formats with the additional overhead
* of checking a flag bit.
+ *
+ * That leads to some tricky Kconfig rules howevber. There are
+ * different defaults based on some arch/ppc platforms, though
+ * the basic rules are:
+ *
+ * Controller type Kconfig options needed
+ * --------------- ----------------------
+ * little endian CONFIG_USB_OHCI_LITTLE_ENDIAN
+ *
+ * fully big endian CONFIG_USB_OHCI_BIG_ENDIAN_DESC _and_
+ * CONFIG_USB_OHCI_BIG_ENDIAN_MMIO
+ *
+ * mixed endian CONFIG_USB_OHCI_LITTLE_ENDIAN _and_
+ * CONFIG_USB_OHCI_BIG_ENDIAN_{MMIO,DESC}
+ *
+ * (If you have a mixed endian controller, you -must- also define
+ * CONFIG_USB_OHCI_LITTLE_ENDIAN or things will not work when building
+ * both your mixed endian and a fully big endian controller support in
+ * the same kernel image).
*/
-#ifdef CONFIG_USB_OHCI_BIG_ENDIAN
+#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_DESC
+#ifdef CONFIG_USB_OHCI_LITTLE_ENDIAN
+#define big_endian_desc(ohci) (ohci->flags & OHCI_QUIRK_BE_DESC)
+#else
+#define big_endian_desc(ohci) 1 /* only big endian */
+#endif
+#else
+#define big_endian_desc(ohci) 0 /* only little endian */
+#endif
+#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO
#ifdef CONFIG_USB_OHCI_LITTLE_ENDIAN
-#define big_endian(ohci) (ohci->flags & OHCI_BIG_ENDIAN) /* either */
+#define big_endian_mmio(ohci) (ohci->flags & OHCI_QUIRK_BE_MMIO)
#else
-#define big_endian(ohci) 1 /* only big endian */
+#define big_endian_mmio(ohci) 1 /* only big endian */
+#endif
+#else
+#define big_endian_mmio(ohci) 0 /* only little endian */
#endif
/*
* Big-endian read/write functions are arch-specific.
* Other arches can be added if/when they're needed.
+ *
+ * REVISIT: arch/powerpc now has readl/writel_be, so the
+ * definition below can die once the STB04xxx support is
+ * finally ported over.
*/
-#if defined(CONFIG_PPC)
+#if defined(CONFIG_PPC) && !defined(CONFIG_PPC_MERGE)
#define readl_be(addr) in_be32((__force unsigned *)addr)
#define writel_be(val, addr) out_be32((__force unsigned *)addr, val)
#endif
-static inline unsigned int ohci_readl (const struct ohci_hcd *ohci,
- __hc32 __iomem * regs)
+static inline unsigned int _ohci_readl (const struct ohci_hcd *ohci,
+ __hc32 __iomem * regs)
{
- return big_endian(ohci) ? readl_be (regs) : readl ((__force u32 *)regs);
+#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO
+ return big_endian_mmio(ohci) ?
+ readl_be (regs) :
+ readl (regs);
+#else
+ return readl (regs);
+#endif
}
-static inline void ohci_writel (const struct ohci_hcd *ohci,
- const unsigned int val, __hc32 __iomem *regs)
+static inline void _ohci_writel (const struct ohci_hcd *ohci,
+ const unsigned int val, __hc32 __iomem *regs)
{
- big_endian(ohci) ? writel_be (val, regs) :
- writel (val, (__force u32 *)regs);
+#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO
+ big_endian_mmio(ohci) ?
+ writel_be (val, regs) :
+ writel (val, regs);
+#else
+ writel (val, regs);
+#endif
}
-#else /* !CONFIG_USB_OHCI_BIG_ENDIAN */
-
-#define big_endian(ohci) 0 /* only little endian */
-
#ifdef CONFIG_ARCH_LH7A404
- /* Marc Singer: at the time this code was written, the LH7A404
- * had a problem reading the USB host registers. This
- * implementation of the ohci_readl function performs the read
- * twice as a work-around.
- */
-static inline unsigned int
-ohci_readl (const struct ohci_hcd *ohci, const __hc32 *regs)
-{
- *(volatile __force unsigned int*) regs;
- return *(volatile __force unsigned int*) regs;
-}
+/* Marc Singer: at the time this code was written, the LH7A404
+ * had a problem reading the USB host registers. This
+ * implementation of the ohci_readl function performs the read
+ * twice as a work-around.
+ */
+#define ohci_readl(o,r) (_ohci_readl(o,r),_ohci_readl(o,r))
+#define ohci_writel(o,v,r) _ohci_writel(o,v,r)
#else
- /* Standard version of ohci_readl uses standard, platform
- * specific implementation. */
-static inline unsigned int
-ohci_readl (const struct ohci_hcd *ohci, __hc32 __iomem * regs)
-{
- return readl(regs);
-}
+#define ohci_readl(o,r) _ohci_readl(o,r)
+#define ohci_writel(o,v,r) _ohci_writel(o,v,r)
#endif
-static inline void ohci_writel (const struct ohci_hcd *ohci,
- const unsigned int val, __hc32 __iomem *regs)
-{
- writel (val, regs);
-}
-
-#endif /* !CONFIG_USB_OHCI_BIG_ENDIAN */
/*-------------------------------------------------------------------------*/
/* cpu to ohci */
static inline __hc16 cpu_to_hc16 (const struct ohci_hcd *ohci, const u16 x)
{
- return big_endian(ohci) ? (__force __hc16)cpu_to_be16(x) : (__force __hc16)cpu_to_le16(x);
+ return big_endian_desc(ohci) ?
+ (__force __hc16)cpu_to_be16(x) :
+ (__force __hc16)cpu_to_le16(x);
}
static inline __hc16 cpu_to_hc16p (const struct ohci_hcd *ohci, const u16 *x)
{
- return big_endian(ohci) ? cpu_to_be16p(x) : cpu_to_le16p(x);
+ return big_endian_desc(ohci) ?
+ cpu_to_be16p(x) :
+ cpu_to_le16p(x);
}
static inline __hc32 cpu_to_hc32 (const struct ohci_hcd *ohci, const u32 x)
{
- return big_endian(ohci) ? (__force __hc32)cpu_to_be32(x) : (__force __hc32)cpu_to_le32(x);
+ return big_endian_desc(ohci) ?
+ (__force __hc32)cpu_to_be32(x) :
+ (__force __hc32)cpu_to_le32(x);
}
static inline __hc32 cpu_to_hc32p (const struct ohci_hcd *ohci, const u32 *x)
{
- return big_endian(ohci) ? cpu_to_be32p(x) : cpu_to_le32p(x);
+ return big_endian_desc(ohci) ?
+ cpu_to_be32p(x) :
+ cpu_to_le32p(x);
}
/* ohci to cpu */
static inline u16 hc16_to_cpu (const struct ohci_hcd *ohci, const __hc16 x)
{
- return big_endian(ohci) ? be16_to_cpu((__force __be16)x) : le16_to_cpu((__force __le16)x);
+ return big_endian_desc(ohci) ?
+ be16_to_cpu((__force __be16)x) :
+ le16_to_cpu((__force __le16)x);
}
static inline u16 hc16_to_cpup (const struct ohci_hcd *ohci, const __hc16 *x)
{
- return big_endian(ohci) ? be16_to_cpup((__force __be16 *)x) : le16_to_cpup((__force __le16 *)x);
+ return big_endian_desc(ohci) ?
+ be16_to_cpup((__force __be16 *)x) :
+ le16_to_cpup((__force __le16 *)x);
}
static inline u32 hc32_to_cpu (const struct ohci_hcd *ohci, const __hc32 x)
{
- return big_endian(ohci) ? be32_to_cpu((__force __be32)x) : le32_to_cpu((__force __le32)x);
+ return big_endian_desc(ohci) ?
+ be32_to_cpu((__force __be32)x) :
+ le32_to_cpu((__force __le32)x);
}
static inline u32 hc32_to_cpup (const struct ohci_hcd *ohci, const __hc32 *x)
{
- return big_endian(ohci) ? be32_to_cpup((__force __be32 *)x) : le32_to_cpup((__force __le32 *)x);
+ return big_endian_desc(ohci) ?
+ be32_to_cpup((__force __be32 *)x) :
+ le32_to_cpup((__force __le32 *)x);
}
/*-------------------------------------------------------------------------*/
@@ -557,6 +605,9 @@ static inline u32 hc32_to_cpup (const struct ohci_hcd *ohci, const __hc32 *x)
/* HCCA frame number is 16 bits, but is accessed as 32 bits since not all
* hardware handles 16 bit reads. That creates a different confusion on
* some big-endian SOC implementations. Same thing happens with PSW access.
+ *
+ * FIXME: Deal with that as a runtime quirk when STB03xxx is ported over
+ * to arch/powerpc
*/
#ifdef CONFIG_STB03xxx
@@ -568,7 +619,7 @@ static inline u32 hc32_to_cpup (const struct ohci_hcd *ohci, const __hc32 *x)
static inline u16 ohci_frame_no(const struct ohci_hcd *ohci)
{
u32 tmp;
- if (big_endian(ohci)) {
+ if (big_endian_desc(ohci)) {
tmp = be32_to_cpup((__force __be32 *)&ohci->hcca->frame_no);
tmp >>= OHCI_BE_FRAME_NO_SHIFT;
} else
@@ -580,7 +631,7 @@ static inline u16 ohci_frame_no(const struct ohci_hcd *ohci)
static inline __hc16 *ohci_hwPSWp(const struct ohci_hcd *ohci,
const struct td *td, int index)
{
- return (__hc16 *)(big_endian(ohci) ?
+ return (__hc16 *)(big_endian_desc(ohci) ?
&td->hwPSW[index ^ 1] : &td->hwPSW[index]);
}
diff --git a/drivers/usb/host/sl811_cs.c b/drivers/usb/host/sl811_cs.c
index ac9f11d1981..2d0e73b2009 100644
--- a/drivers/usb/host/sl811_cs.c
+++ b/drivers/usb/host/sl811_cs.c
@@ -13,7 +13,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/sched.h>
#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/string.h>
diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c
index e345f15b7d8..8d24d3dc0a6 100644
--- a/drivers/usb/host/uhci-debug.c
+++ b/drivers/usb/host/uhci-debug.c
@@ -168,9 +168,13 @@ static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space)
space, "", qh, qtype,
le32_to_cpu(qh->link), le32_to_cpu(element));
if (qh->type == USB_ENDPOINT_XFER_ISOC)
- out += sprintf(out, "%*s period %d frame %x desc [%p]\n",
- space, "", qh->period, qh->iso_frame,
- qh->iso_packet_desc);
+ out += sprintf(out, "%*s period %d phase %d load %d us, "
+ "frame %x desc [%p]\n",
+ space, "", qh->period, qh->phase, qh->load,
+ qh->iso_frame, qh->iso_packet_desc);
+ else if (qh->type == USB_ENDPOINT_XFER_INT)
+ out += sprintf(out, "%*s period %d phase %d load %d us\n",
+ space, "", qh->period, qh->phase, qh->load);
if (element & UHCI_PTR_QH)
out += sprintf(out, "%*s Element points to QH (bug?)\n", space, "");
@@ -192,7 +196,7 @@ static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space)
struct uhci_td *td = list_entry(urbp->td_list.next,
struct uhci_td, list);
- if (cpu_to_le32(td->dma_handle) != (element & ~UHCI_PTR_BITS))
+ if (element != LINK_TO_TD(td))
out += sprintf(out, "%*s Element != First TD\n",
space, "");
i = nurbs = 0;
@@ -208,7 +212,7 @@ static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space)
space, "", nurbs);
}
- if (qh->udev) {
+ if (qh->dummy_td) {
out += sprintf(out, "%*s Dummy TD\n", space, "");
out += uhci_show_td(qh->dummy_td, out, len - (out - buf), 0);
}
@@ -216,16 +220,6 @@ static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space)
return out - buf;
}
-static const char * const qh_names[] = {
- "skel_unlink_qh", "skel_iso_qh",
- "skel_int128_qh", "skel_int64_qh",
- "skel_int32_qh", "skel_int16_qh",
- "skel_int8_qh", "skel_int4_qh",
- "skel_int2_qh", "skel_int1_qh",
- "skel_ls_control_qh", "skel_fs_control_qh",
- "skel_bulk_qh", "skel_term_qh"
-};
-
static int uhci_show_sc(int port, unsigned short status, char *buf, int len)
{
char *out = buf;
@@ -347,53 +341,106 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
struct uhci_qh *qh;
struct uhci_td *td;
struct list_head *tmp, *head;
+ int nframes, nerrs;
+ __le32 link;
+
+ static const char * const qh_names[] = {
+ "unlink", "iso", "int128", "int64", "int32", "int16",
+ "int8", "int4", "int2", "async", "term"
+ };
out += uhci_show_root_hub_state(uhci, out, len - (out - buf));
out += sprintf(out, "HC status\n");
out += uhci_show_status(uhci, out, len - (out - buf));
+
+ out += sprintf(out, "Periodic load table\n");
+ for (i = 0; i < MAX_PHASE; ++i) {
+ out += sprintf(out, "\t%d", uhci->load[i]);
+ if (i % 8 == 7)
+ *out++ = '\n';
+ }
+ out += sprintf(out, "Total: %d, #INT: %d, #ISO: %d\n",
+ uhci->total_load,
+ uhci_to_hcd(uhci)->self.bandwidth_int_reqs,
+ uhci_to_hcd(uhci)->self.bandwidth_isoc_reqs);
if (debug <= 1)
return out - buf;
out += sprintf(out, "Frame List\n");
+ nframes = 10;
+ nerrs = 0;
for (i = 0; i < UHCI_NUMFRAMES; ++i) {
+ __le32 qh_dma;
+
+ j = 0;
td = uhci->frame_cpu[i];
+ link = uhci->frame[i];
if (!td)
- continue;
+ goto check_link;
- out += sprintf(out, "- Frame %d\n", i); \
- if (td->dma_handle != (dma_addr_t)uhci->frame[i])
- out += sprintf(out, " frame list does not match td->dma_handle!\n");
+ if (nframes > 0) {
+ out += sprintf(out, "- Frame %d -> (%08x)\n",
+ i, le32_to_cpu(link));
+ j = 1;
+ }
head = &td->fl_list;
tmp = head;
do {
td = list_entry(tmp, struct uhci_td, fl_list);
tmp = tmp->next;
- out += uhci_show_td(td, out, len - (out - buf), 4);
+ if (link != LINK_TO_TD(td)) {
+ if (nframes > 0)
+ out += sprintf(out, " link does "
+ "not match list entry!\n");
+ else
+ ++nerrs;
+ }
+ if (nframes > 0)
+ out += uhci_show_td(td, out,
+ len - (out - buf), 4);
+ link = td->link;
} while (tmp != head);
+
+check_link:
+ qh_dma = uhci_frame_skel_link(uhci, i);
+ if (link != qh_dma) {
+ if (nframes > 0) {
+ if (!j) {
+ out += sprintf(out,
+ "- Frame %d -> (%08x)\n",
+ i, le32_to_cpu(link));
+ j = 1;
+ }
+ out += sprintf(out, " link does not match "
+ "QH (%08x)!\n", le32_to_cpu(qh_dma));
+ } else
+ ++nerrs;
+ }
+ nframes -= j;
}
+ if (nerrs > 0)
+ out += sprintf(out, "Skipped %d bad links\n", nerrs);
out += sprintf(out, "Skeleton QHs\n");
for (i = 0; i < UHCI_NUM_SKELQH; ++i) {
int cnt = 0;
+ __le32 fsbr_link = 0;
qh = uhci->skelqh[i];
- out += sprintf(out, "- %s\n", qh_names[i]); \
+ out += sprintf(out, "- skel_%s_qh\n", qh_names[i]); \
out += uhci_show_qh(qh, out, len - (out - buf), 4);
/* Last QH is the Terminating QH, it's different */
- if (i == UHCI_NUM_SKELQH - 1) {
- if (qh->link != UHCI_PTR_TERM)
- out += sprintf(out, " bandwidth reclamation on!\n");
-
- if (qh_element(qh) != cpu_to_le32(uhci->term_td->dma_handle))
+ if (i == SKEL_TERM) {
+ if (qh_element(qh) != LINK_TO_TD(uhci->term_td))
out += sprintf(out, " skel_term_qh element is not set to term_td!\n");
-
+ if (link == LINK_TO_QH(uhci->skel_term_qh))
+ goto check_qh_link;
continue;
}
- j = (i < 9) ? 9 : i+1; /* Next skeleton */
head = &qh->node;
tmp = head->next;
@@ -403,15 +450,26 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
if (++cnt <= 10)
out += uhci_show_qh(qh, out,
len - (out - buf), 4);
+ if (!fsbr_link && qh->skel >= SKEL_FSBR)
+ fsbr_link = LINK_TO_QH(qh);
}
if ((cnt -= 10) > 0)
out += sprintf(out, " Skipped %d QHs\n", cnt);
- if (i > 1 && i < UHCI_NUM_SKELQH - 1) {
- if (qh->link !=
- (cpu_to_le32(uhci->skelqh[j]->dma_handle) | UHCI_PTR_QH))
- out += sprintf(out, " last QH not linked to next skeleton!\n");
- }
+ link = UHCI_PTR_TERM;
+ if (i <= SKEL_ISO)
+ ;
+ else if (i < SKEL_ASYNC)
+ link = LINK_TO_QH(uhci->skel_async_qh);
+ else if (!uhci->fsbr_is_on)
+ ;
+ else if (fsbr_link)
+ link = fsbr_link;
+ else
+ link = LINK_TO_QH(uhci->skel_term_qh);
+check_qh_link:
+ if (qh->link != link)
+ out += sprintf(out, " last QH not linked to next skeleton!\n");
}
return out - buf;
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index e0d4c2358b3..44da4334f1d 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -13,7 +13,7 @@
* (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface
* support from usb-ohci.c by Adam Richter, adam@yggdrasil.com).
* (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c)
- * (C) Copyright 2004-2006 Alan Stern, stern@rowland.harvard.edu
+ * (C) Copyright 2004-2007 Alan Stern, stern@rowland.harvard.edu
*
* Intel documents this fairly well, and as far as I know there
* are no royalties or anything like that, but even so there are
@@ -28,7 +28,6 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/ioport.h>
-#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/unistd.h>
@@ -92,6 +91,34 @@ static void suspend_rh(struct uhci_hcd *uhci, enum uhci_rh_state new_state);
static void wakeup_rh(struct uhci_hcd *uhci);
static void uhci_get_current_frame_number(struct uhci_hcd *uhci);
+/*
+ * Calculate the link pointer DMA value for the first Skeleton QH in a frame.
+ */
+static __le32 uhci_frame_skel_link(struct uhci_hcd *uhci, int frame)
+{
+ int skelnum;
+
+ /*
+ * The interrupt queues will be interleaved as evenly as possible.
+ * There's not much to be done about period-1 interrupts; they have
+ * to occur in every frame. But we can schedule period-2 interrupts
+ * in odd-numbered frames, period-4 interrupts in frames congruent
+ * to 2 (mod 4), and so on. This way each frame only has two
+ * interrupt QHs, which will help spread out bandwidth utilization.
+ *
+ * ffs (Find First bit Set) does exactly what we need:
+ * 1,3,5,... => ffs = 0 => use period-2 QH = skelqh[8],
+ * 2,6,10,... => ffs = 1 => use period-4 QH = skelqh[7], etc.
+ * ffs >= 7 => not on any high-period queue, so use
+ * period-1 QH = skelqh[9].
+ * Add in UHCI_NUMFRAMES to insure at least one bit is set.
+ */
+ skelnum = 8 - (int) __ffs(frame | UHCI_NUMFRAMES);
+ if (skelnum <= 1)
+ skelnum = 9;
+ return LINK_TO_QH(uhci->skelqh[skelnum]);
+}
+
#include "uhci-debug.c"
#include "uhci-q.c"
#include "uhci-hub.c"
@@ -513,16 +540,18 @@ static void uhci_shutdown(struct pci_dev *pdev)
*
* The hardware doesn't really know any difference
* in the queues, but the order does matter for the
- * protocols higher up. The order is:
+ * protocols higher up. The order in which the queues
+ * are encountered by the hardware is:
*
- * - any isochronous events handled before any
+ * - All isochronous events are handled before any
* of the queues. We don't do that here, because
* we'll create the actual TD entries on demand.
- * - The first queue is the interrupt queue.
- * - The second queue is the control queue, split into low- and full-speed
- * - The third queue is bulk queue.
- * - The fourth queue is the bandwidth reclamation queue, which loops back
- * to the full-speed control queue.
+ * - The first queue is the high-period interrupt queue.
+ * - The second queue is the period-1 interrupt and async
+ * (low-speed control, full-speed control, then bulk) queue.
+ * - The third queue is the terminating bandwidth reclamation queue,
+ * which contains no members, loops back to itself, and is present
+ * only when FSBR is on and there are no full-speed control or bulk QHs.
*/
static int uhci_start(struct usb_hcd *hcd)
{
@@ -599,64 +628,27 @@ static int uhci_start(struct usb_hcd *hcd)
}
/*
- * 8 Interrupt queues; link all higher int queues to int1,
- * then link int1 to control and control to bulk
+ * 8 Interrupt queues; link all higher int queues to int1 = async
*/
- uhci->skel_int128_qh->link =
- uhci->skel_int64_qh->link =
- uhci->skel_int32_qh->link =
- uhci->skel_int16_qh->link =
- uhci->skel_int8_qh->link =
- uhci->skel_int4_qh->link =
- uhci->skel_int2_qh->link = UHCI_PTR_QH |
- cpu_to_le32(uhci->skel_int1_qh->dma_handle);
-
- uhci->skel_int1_qh->link = UHCI_PTR_QH |
- cpu_to_le32(uhci->skel_ls_control_qh->dma_handle);
- uhci->skel_ls_control_qh->link = UHCI_PTR_QH |
- cpu_to_le32(uhci->skel_fs_control_qh->dma_handle);
- uhci->skel_fs_control_qh->link = UHCI_PTR_QH |
- cpu_to_le32(uhci->skel_bulk_qh->dma_handle);
- uhci->skel_bulk_qh->link = UHCI_PTR_QH |
- cpu_to_le32(uhci->skel_term_qh->dma_handle);
+ for (i = SKEL_ISO + 1; i < SKEL_ASYNC; ++i)
+ uhci->skelqh[i]->link = LINK_TO_QH(uhci->skel_async_qh);
+ uhci->skel_async_qh->link = uhci->skel_term_qh->link = UHCI_PTR_TERM;
/* This dummy TD is to work around a bug in Intel PIIX controllers */
uhci_fill_td(uhci->term_td, 0, uhci_explen(0) |
- (0x7f << TD_TOKEN_DEVADDR_SHIFT) | USB_PID_IN, 0);
- uhci->term_td->link = cpu_to_le32(uhci->term_td->dma_handle);
-
- uhci->skel_term_qh->link = UHCI_PTR_TERM;
- uhci->skel_term_qh->element = cpu_to_le32(uhci->term_td->dma_handle);
+ (0x7f << TD_TOKEN_DEVADDR_SHIFT) | USB_PID_IN, 0);
+ uhci->term_td->link = UHCI_PTR_TERM;
+ uhci->skel_async_qh->element = uhci->skel_term_qh->element =
+ LINK_TO_TD(uhci->term_td);
/*
* Fill the frame list: make all entries point to the proper
* interrupt queue.
- *
- * The interrupt queues will be interleaved as evenly as possible.
- * There's not much to be done about period-1 interrupts; they have
- * to occur in every frame. But we can schedule period-2 interrupts
- * in odd-numbered frames, period-4 interrupts in frames congruent
- * to 2 (mod 4), and so on. This way each frame only has two
- * interrupt QHs, which will help spread out bandwidth utilization.
*/
for (i = 0; i < UHCI_NUMFRAMES; i++) {
- int irq;
-
- /*
- * ffs (Find First bit Set) does exactly what we need:
- * 1,3,5,... => ffs = 0 => use skel_int2_qh = skelqh[8],
- * 2,6,10,... => ffs = 1 => use skel_int4_qh = skelqh[7], etc.
- * ffs >= 7 => not on any high-period queue, so use
- * skel_int1_qh = skelqh[9].
- * Add UHCI_NUMFRAMES to insure at least one bit is set.
- */
- irq = 8 - (int) __ffs(i + UHCI_NUMFRAMES);
- if (irq <= 1)
- irq = 9;
/* Only place we don't use the frame list routines */
- uhci->frame[i] = UHCI_PTR_QH |
- cpu_to_le32(uhci->skelqh[irq]->dma_handle);
+ uhci->frame[i] = uhci_frame_skel_link(uhci, i);
}
/*
diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h
index 108e3de2dc2..1b3d23406ac 100644
--- a/drivers/usb/host/uhci-hcd.h
+++ b/drivers/usb/host/uhci-hcd.h
@@ -83,6 +83,7 @@
#define UHCI_MAX_SOF_NUMBER 2047 /* in an SOF packet */
#define CAN_SCHEDULE_FRAMES 1000 /* how far in the future frames
* can be scheduled */
+#define MAX_PHASE 32 /* Periodic scheduling length */
/* When no queues need Full-Speed Bandwidth Reclamation,
* delay this long before turning FSBR off */
@@ -128,11 +129,12 @@ struct uhci_qh {
__le32 element; /* Queue element (TD) pointer */
/* Software fields */
+ dma_addr_t dma_handle;
+
struct list_head node; /* Node in the list of QHs */
struct usb_host_endpoint *hep; /* Endpoint information */
struct usb_device *udev;
struct list_head queue; /* Queue of urbps for this QH */
- struct uhci_qh *skel; /* Skeleton for this QH */
struct uhci_td *dummy_td; /* Dummy TD to end the queue */
struct uhci_td *post_td; /* Last TD completed */
@@ -141,18 +143,21 @@ struct uhci_qh {
unsigned long advance_jiffies; /* Time of last queue advance */
unsigned int unlink_frame; /* When the QH was unlinked */
unsigned int period; /* For Interrupt and Isochronous QHs */
+ short phase; /* Between 0 and period-1 */
+ short load; /* Periodic time requirement, in us */
unsigned int iso_frame; /* Frame # for iso_packet_desc */
int iso_status; /* Status for Isochronous URBs */
int state; /* QH_STATE_xxx; see above */
int type; /* Queue type (control, bulk, etc) */
-
- dma_addr_t dma_handle;
+ int skel; /* Skeleton queue number */
unsigned int initial_toggle:1; /* Endpoint's current toggle value */
unsigned int needs_fixup:1; /* Must fix the TD toggle values */
unsigned int is_stopped:1; /* Queue was stopped by error/unlink */
unsigned int wait_expired:1; /* QH_WAIT_TIMEOUT has expired */
+ unsigned int bandwidth_reserved:1; /* Periodic bandwidth has
+ * been allocated */
} __attribute__((aligned(16)));
/*
@@ -166,6 +171,8 @@ static inline __le32 qh_element(struct uhci_qh *qh) {
return element;
}
+#define LINK_TO_QH(qh) (UHCI_PTR_QH | cpu_to_le32((qh)->dma_handle))
+
/*
* Transfer Descriptors
@@ -259,6 +266,8 @@ static inline u32 td_status(struct uhci_td *td) {
return le32_to_cpu(status);
}
+#define LINK_TO_TD(td) (cpu_to_le32((td)->dma_handle))
+
/*
* Skeleton Queue Headers
@@ -267,12 +276,13 @@ static inline u32 td_status(struct uhci_td *td) {
/*
* The UHCI driver uses QHs with Interrupt, Control and Bulk URBs for
* automatic queuing. To make it easy to insert entries into the schedule,
- * we have a skeleton of QHs for each predefined Interrupt latency,
- * low-speed control, full-speed control, bulk, and terminating QH
- * (see explanation for the terminating QH below).
+ * we have a skeleton of QHs for each predefined Interrupt latency.
+ * Asynchronous QHs (low-speed control, full-speed control, and bulk)
+ * go onto the period-1 interrupt list, since they all get accessed on
+ * every frame.
*
- * When we want to add a new QH, we add it to the end of the list for the
- * skeleton QH. For instance, the schedule list can look like this:
+ * When we want to add a new QH, we add it to the list starting from the
+ * appropriate skeleton QH. For instance, the schedule can look like this:
*
* skel int128 QH
* dev 1 interrupt QH
@@ -280,50 +290,47 @@ static inline u32 td_status(struct uhci_td *td) {
* skel int64 QH
* skel int32 QH
* ...
- * skel int1 QH
- * skel low-speed control QH
- * dev 5 control QH
- * skel full-speed control QH
- * skel bulk QH
+ * skel int1 + async QH
+ * dev 5 low-speed control QH
* dev 1 bulk QH
* dev 2 bulk QH
- * skel terminating QH
*
- * The terminating QH is used for 2 reasons:
- * - To place a terminating TD which is used to workaround a PIIX bug
- * (see Intel errata for explanation), and
- * - To loop back to the full-speed control queue for full-speed bandwidth
- * reclamation.
+ * There is a special terminating QH used to keep full-speed bandwidth
+ * reclamation active when no full-speed control or bulk QHs are linked
+ * into the schedule. It has an inactive TD (to work around a PIIX bug,
+ * see the Intel errata) and it points back to itself.
*
- * There's a special skeleton QH for Isochronous QHs. It never appears
- * on the schedule, and Isochronous TDs go on the schedule before the
+ * There's a special skeleton QH for Isochronous QHs which never appears
+ * on the schedule. Isochronous TDs go on the schedule before the
* the skeleton QHs. The hardware accesses them directly rather than
* through their QH, which is used only for bookkeeping purposes.
* While the UHCI spec doesn't forbid the use of QHs for Isochronous,
* it doesn't use them either. And the spec says that queues never
* advance on an error completion status, which makes them totally
* unsuitable for Isochronous transfers.
+ *
+ * There's also a special skeleton QH used for QHs which are in the process
+ * of unlinking and so may still be in use by the hardware. It too never
+ * appears on the schedule.
*/
-#define UHCI_NUM_SKELQH 14
-#define skel_unlink_qh skelqh[0]
-#define skel_iso_qh skelqh[1]
-#define skel_int128_qh skelqh[2]
-#define skel_int64_qh skelqh[3]
-#define skel_int32_qh skelqh[4]
-#define skel_int16_qh skelqh[5]
-#define skel_int8_qh skelqh[6]
-#define skel_int4_qh skelqh[7]
-#define skel_int2_qh skelqh[8]
-#define skel_int1_qh skelqh[9]
-#define skel_ls_control_qh skelqh[10]
-#define skel_fs_control_qh skelqh[11]
-#define skel_bulk_qh skelqh[12]
-#define skel_term_qh skelqh[13]
-
-/* Find the skelqh entry corresponding to an interval exponent */
-#define UHCI_SKEL_INDEX(exponent) (9 - exponent)
-
+#define UHCI_NUM_SKELQH 11
+#define SKEL_UNLINK 0
+#define skel_unlink_qh skelqh[SKEL_UNLINK]
+#define SKEL_ISO 1
+#define skel_iso_qh skelqh[SKEL_ISO]
+ /* int128, int64, ..., int1 = 2, 3, ..., 9 */
+#define SKEL_INDEX(exponent) (9 - exponent)
+#define SKEL_ASYNC 9
+#define skel_async_qh skelqh[SKEL_ASYNC]
+#define SKEL_TERM 10
+#define skel_term_qh skelqh[SKEL_TERM]
+
+/* The following entries refer to sublists of skel_async_qh */
+#define SKEL_LS_CONTROL 20
+#define SKEL_FS_CONTROL 21
+#define SKEL_FSBR SKEL_FS_CONTROL
+#define SKEL_BULK 22
/*
* The UHCI controller and root hub
@@ -414,6 +421,9 @@ struct uhci_hcd {
wait_queue_head_t waitqh; /* endpoint_disable waiters */
int num_waiting; /* Number of waiters */
+
+ int total_load; /* Sum of array values */
+ short load[MAX_PHASE]; /* Periodic allocations */
};
/* Convert between a usb_hcd pointer and the corresponding uhci_hcd */
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
index 30b88459ac7..f4ebdb3e488 100644
--- a/drivers/usb/host/uhci-q.c
+++ b/drivers/usb/host/uhci-q.c
@@ -13,7 +13,7 @@
* (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface
* support from usb-ohci.c by Adam Richter, adam@yggdrasil.com).
* (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c)
- * (C) Copyright 2004-2006 Alan Stern, stern@rowland.harvard.edu
+ * (C) Copyright 2004-2007 Alan Stern, stern@rowland.harvard.edu
*/
@@ -45,15 +45,43 @@ static inline void uhci_clear_next_interrupt(struct uhci_hcd *uhci)
*/
static void uhci_fsbr_on(struct uhci_hcd *uhci)
{
+ struct uhci_qh *fsbr_qh, *lqh, *tqh;
+
uhci->fsbr_is_on = 1;
- uhci->skel_term_qh->link = cpu_to_le32(
- uhci->skel_fs_control_qh->dma_handle) | UHCI_PTR_QH;
+ lqh = list_entry(uhci->skel_async_qh->node.prev,
+ struct uhci_qh, node);
+
+ /* Find the first FSBR QH. Linear search through the list is
+ * acceptable because normally FSBR gets turned on as soon as
+ * one QH needs it. */
+ fsbr_qh = NULL;
+ list_for_each_entry_reverse(tqh, &uhci->skel_async_qh->node, node) {
+ if (tqh->skel < SKEL_FSBR)
+ break;
+ fsbr_qh = tqh;
+ }
+
+ /* No FSBR QH means we must insert the terminating skeleton QH */
+ if (!fsbr_qh) {
+ uhci->skel_term_qh->link = LINK_TO_QH(uhci->skel_term_qh);
+ wmb();
+ lqh->link = uhci->skel_term_qh->link;
+
+ /* Otherwise loop the last QH to the first FSBR QH */
+ } else
+ lqh->link = LINK_TO_QH(fsbr_qh);
}
static void uhci_fsbr_off(struct uhci_hcd *uhci)
{
+ struct uhci_qh *lqh;
+
uhci->fsbr_is_on = 0;
- uhci->skel_term_qh->link = UHCI_PTR_TERM;
+ lqh = list_entry(uhci->skel_async_qh->node.prev,
+ struct uhci_qh, node);
+
+ /* End the async list normally and unlink the terminating QH */
+ lqh->link = uhci->skel_term_qh->link = UHCI_PTR_TERM;
}
static void uhci_add_fsbr(struct uhci_hcd *uhci, struct urb *urb)
@@ -158,11 +186,11 @@ static inline void uhci_insert_td_in_frame_list(struct uhci_hcd *uhci,
td->link = ltd->link;
wmb();
- ltd->link = cpu_to_le32(td->dma_handle);
+ ltd->link = LINK_TO_TD(td);
} else {
td->link = uhci->frame[framenum];
wmb();
- uhci->frame[framenum] = cpu_to_le32(td->dma_handle);
+ uhci->frame[framenum] = LINK_TO_TD(td);
uhci->frame_cpu[framenum] = td;
}
}
@@ -184,7 +212,7 @@ static inline void uhci_remove_td_from_frame_list(struct uhci_hcd *uhci,
struct uhci_td *ntd;
ntd = list_entry(td->fl_list.next, struct uhci_td, fl_list);
- uhci->frame[td->frame] = cpu_to_le32(ntd->dma_handle);
+ uhci->frame[td->frame] = LINK_TO_TD(ntd);
uhci->frame_cpu[td->frame] = ntd;
}
} else {
@@ -248,16 +276,26 @@ static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci,
INIT_LIST_HEAD(&qh->node);
if (udev) { /* Normal QH */
- qh->dummy_td = uhci_alloc_td(uhci);
- if (!qh->dummy_td) {
- dma_pool_free(uhci->qh_pool, qh, dma_handle);
- return NULL;
+ qh->type = hep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+ if (qh->type != USB_ENDPOINT_XFER_ISOC) {
+ qh->dummy_td = uhci_alloc_td(uhci);
+ if (!qh->dummy_td) {
+ dma_pool_free(uhci->qh_pool, qh, dma_handle);
+ return NULL;
+ }
}
qh->state = QH_STATE_IDLE;
qh->hep = hep;
qh->udev = udev;
hep->hcpriv = qh;
- qh->type = hep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+
+ if (qh->type == USB_ENDPOINT_XFER_INT ||
+ qh->type == USB_ENDPOINT_XFER_ISOC)
+ qh->load = usb_calc_bus_time(udev->speed,
+ usb_endpoint_dir_in(&hep->desc),
+ qh->type == USB_ENDPOINT_XFER_ISOC,
+ le16_to_cpu(hep->desc.wMaxPacketSize))
+ / 1000 + 1;
} else { /* Skeleton QH */
qh->state = QH_STATE_ACTIVE;
@@ -275,7 +313,8 @@ static void uhci_free_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
list_del(&qh->node);
if (qh->udev) {
qh->hep->hcpriv = NULL;
- uhci_free_td(uhci, qh->dummy_td);
+ if (qh->dummy_td)
+ uhci_free_td(uhci, qh->dummy_td);
}
dma_pool_free(uhci->qh_pool, qh, qh->dma_handle);
}
@@ -327,7 +366,7 @@ static int uhci_cleanup_queue(struct uhci_hcd *uhci, struct uhci_qh *qh,
goto done;
qh->element = UHCI_PTR_TERM;
- /* Control pipes have to worry about toggles */
+ /* Control pipes don't have to worry about toggles */
if (qh->type == USB_ENDPOINT_XFER_CONTROL)
goto done;
@@ -394,12 +433,81 @@ static void uhci_fixup_toggles(struct uhci_qh *qh, int skip_first)
}
/*
- * Put a QH on the schedule in both hardware and software
+ * Link an Isochronous QH into its skeleton's list
*/
-static void uhci_activate_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
+static inline void link_iso(struct uhci_hcd *uhci, struct uhci_qh *qh)
+{
+ list_add_tail(&qh->node, &uhci->skel_iso_qh->node);
+
+ /* Isochronous QHs aren't linked by the hardware */
+}
+
+/*
+ * Link a high-period interrupt QH into the schedule at the end of its
+ * skeleton's list
+ */
+static void link_interrupt(struct uhci_hcd *uhci, struct uhci_qh *qh)
{
struct uhci_qh *pqh;
+ list_add_tail(&qh->node, &uhci->skelqh[qh->skel]->node);
+
+ pqh = list_entry(qh->node.prev, struct uhci_qh, node);
+ qh->link = pqh->link;
+ wmb();
+ pqh->link = LINK_TO_QH(qh);
+}
+
+/*
+ * Link a period-1 interrupt or async QH into the schedule at the
+ * correct spot in the async skeleton's list, and update the FSBR link
+ */
+static void link_async(struct uhci_hcd *uhci, struct uhci_qh *qh)
+{
+ struct uhci_qh *pqh, *lqh;
+ __le32 link_to_new_qh;
+ __le32 *extra_link = &link_to_new_qh;
+
+ /* Find the predecessor QH for our new one and insert it in the list.
+ * The list of QHs is expected to be short, so linear search won't
+ * take too long. */
+ list_for_each_entry_reverse(pqh, &uhci->skel_async_qh->node, node) {
+ if (pqh->skel <= qh->skel)
+ break;
+ }
+ list_add(&qh->node, &pqh->node);
+ qh->link = pqh->link;
+
+ link_to_new_qh = LINK_TO_QH(qh);
+
+ /* If this is now the first FSBR QH, take special action */
+ if (uhci->fsbr_is_on && pqh->skel < SKEL_FSBR &&
+ qh->skel >= SKEL_FSBR) {
+ lqh = list_entry(uhci->skel_async_qh->node.prev,
+ struct uhci_qh, node);
+
+ /* If the new QH is also the last one, we must unlink
+ * the terminating skeleton QH and make the new QH point
+ * back to itself. */
+ if (qh == lqh) {
+ qh->link = link_to_new_qh;
+ extra_link = &uhci->skel_term_qh->link;
+
+ /* Otherwise the last QH must point to the new QH */
+ } else
+ extra_link = &lqh->link;
+ }
+
+ /* Link it into the schedule */
+ wmb();
+ *extra_link = pqh->link = link_to_new_qh;
+}
+
+/*
+ * Put a QH on the schedule in both hardware and software
+ */
+static void uhci_activate_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
+{
WARN_ON(list_empty(&qh->queue));
/* Set the element pointer if it isn't set already.
@@ -410,7 +518,7 @@ static void uhci_activate_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
struct uhci_td *td = list_entry(urbp->td_list.next,
struct uhci_td, list);
- qh->element = cpu_to_le32(td->dma_handle);
+ qh->element = LINK_TO_TD(td);
}
/* Treat the queue as if it has just advanced */
@@ -421,18 +529,64 @@ static void uhci_activate_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
return;
qh->state = QH_STATE_ACTIVE;
- /* Move the QH from its old list to the end of the appropriate
+ /* Move the QH from its old list to the correct spot in the appropriate
* skeleton's list */
if (qh == uhci->next_qh)
uhci->next_qh = list_entry(qh->node.next, struct uhci_qh,
node);
- list_move_tail(&qh->node, &qh->skel->node);
+ list_del(&qh->node);
+
+ if (qh->skel == SKEL_ISO)
+ link_iso(uhci, qh);
+ else if (qh->skel < SKEL_ASYNC)
+ link_interrupt(uhci, qh);
+ else
+ link_async(uhci, qh);
+}
+
+/*
+ * Unlink a high-period interrupt QH from the schedule
+ */
+static void unlink_interrupt(struct uhci_hcd *uhci, struct uhci_qh *qh)
+{
+ struct uhci_qh *pqh;
- /* Link it into the schedule */
pqh = list_entry(qh->node.prev, struct uhci_qh, node);
- qh->link = pqh->link;
- wmb();
- pqh->link = UHCI_PTR_QH | cpu_to_le32(qh->dma_handle);
+ pqh->link = qh->link;
+ mb();
+}
+
+/*
+ * Unlink a period-1 interrupt or async QH from the schedule
+ */
+static void unlink_async(struct uhci_hcd *uhci, struct uhci_qh *qh)
+{
+ struct uhci_qh *pqh, *lqh;
+ __le32 link_to_next_qh = qh->link;
+
+ pqh = list_entry(qh->node.prev, struct uhci_qh, node);
+
+ /* If this is the first FSBQ QH, take special action */
+ if (uhci->fsbr_is_on && pqh->skel < SKEL_FSBR &&
+ qh->skel >= SKEL_FSBR) {
+ lqh = list_entry(uhci->skel_async_qh->node.prev,
+ struct uhci_qh, node);
+
+ /* If this QH is also the last one, we must link in
+ * the terminating skeleton QH. */
+ if (qh == lqh) {
+ link_to_next_qh = LINK_TO_QH(uhci->skel_term_qh);
+ uhci->skel_term_qh->link = link_to_next_qh;
+ wmb();
+ qh->link = link_to_next_qh;
+
+ /* Otherwise the last QH must point to the new first FSBR QH */
+ } else
+ lqh->link = link_to_next_qh;
+ }
+
+ pqh->link = link_to_next_qh;
+ mb();
}
/*
@@ -440,17 +594,18 @@ static void uhci_activate_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
*/
static void uhci_unlink_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
{
- struct uhci_qh *pqh;
-
if (qh->state == QH_STATE_UNLINKING)
return;
WARN_ON(qh->state != QH_STATE_ACTIVE || !qh->udev);
qh->state = QH_STATE_UNLINKING;
/* Unlink the QH from the schedule and record when we did it */
- pqh = list_entry(qh->node.prev, struct uhci_qh, node);
- pqh->link = qh->link;
- mb();
+ if (qh->skel == SKEL_ISO)
+ ;
+ else if (qh->skel < SKEL_ASYNC)
+ unlink_interrupt(uhci, qh);
+ else
+ unlink_async(uhci, qh);
uhci_get_current_frame_number(uhci);
qh->unlink_frame = uhci->frame_number;
@@ -493,17 +648,130 @@ static void uhci_make_qh_idle(struct uhci_hcd *uhci, struct uhci_qh *qh)
wake_up_all(&uhci->waitqh);
}
+/*
+ * Find the highest existing bandwidth load for a given phase and period.
+ */
+static int uhci_highest_load(struct uhci_hcd *uhci, int phase, int period)
+{
+ int highest_load = uhci->load[phase];
+
+ for (phase += period; phase < MAX_PHASE; phase += period)
+ highest_load = max_t(int, highest_load, uhci->load[phase]);
+ return highest_load;
+}
+
+/*
+ * Set qh->phase to the optimal phase for a periodic transfer and
+ * check whether the bandwidth requirement is acceptable.
+ */
+static int uhci_check_bandwidth(struct uhci_hcd *uhci, struct uhci_qh *qh)
+{
+ int minimax_load;
+
+ /* Find the optimal phase (unless it is already set) and get
+ * its load value. */
+ if (qh->phase >= 0)
+ minimax_load = uhci_highest_load(uhci, qh->phase, qh->period);
+ else {
+ int phase, load;
+ int max_phase = min_t(int, MAX_PHASE, qh->period);
+
+ qh->phase = 0;
+ minimax_load = uhci_highest_load(uhci, qh->phase, qh->period);
+ for (phase = 1; phase < max_phase; ++phase) {
+ load = uhci_highest_load(uhci, phase, qh->period);
+ if (load < minimax_load) {
+ minimax_load = load;
+ qh->phase = phase;
+ }
+ }
+ }
+
+ /* Maximum allowable periodic bandwidth is 90%, or 900 us per frame */
+ if (minimax_load + qh->load > 900) {
+ dev_dbg(uhci_dev(uhci), "bandwidth allocation failed: "
+ "period %d, phase %d, %d + %d us\n",
+ qh->period, qh->phase, minimax_load, qh->load);
+ return -ENOSPC;
+ }
+ return 0;
+}
+
+/*
+ * Reserve a periodic QH's bandwidth in the schedule
+ */
+static void uhci_reserve_bandwidth(struct uhci_hcd *uhci, struct uhci_qh *qh)
+{
+ int i;
+ int load = qh->load;
+ char *p = "??";
+
+ for (i = qh->phase; i < MAX_PHASE; i += qh->period) {
+ uhci->load[i] += load;
+ uhci->total_load += load;
+ }
+ uhci_to_hcd(uhci)->self.bandwidth_allocated =
+ uhci->total_load / MAX_PHASE;
+ switch (qh->type) {
+ case USB_ENDPOINT_XFER_INT:
+ ++uhci_to_hcd(uhci)->self.bandwidth_int_reqs;
+ p = "INT";
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+ ++uhci_to_hcd(uhci)->self.bandwidth_isoc_reqs;
+ p = "ISO";
+ break;
+ }
+ qh->bandwidth_reserved = 1;
+ dev_dbg(uhci_dev(uhci),
+ "%s dev %d ep%02x-%s, period %d, phase %d, %d us\n",
+ "reserve", qh->udev->devnum,
+ qh->hep->desc.bEndpointAddress, p,
+ qh->period, qh->phase, load);
+}
+
+/*
+ * Release a periodic QH's bandwidth reservation
+ */
+static void uhci_release_bandwidth(struct uhci_hcd *uhci, struct uhci_qh *qh)
+{
+ int i;
+ int load = qh->load;
+ char *p = "??";
+
+ for (i = qh->phase; i < MAX_PHASE; i += qh->period) {
+ uhci->load[i] -= load;
+ uhci->total_load -= load;
+ }
+ uhci_to_hcd(uhci)->self.bandwidth_allocated =
+ uhci->total_load / MAX_PHASE;
+ switch (qh->type) {
+ case USB_ENDPOINT_XFER_INT:
+ --uhci_to_hcd(uhci)->self.bandwidth_int_reqs;
+ p = "INT";
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+ --uhci_to_hcd(uhci)->self.bandwidth_isoc_reqs;
+ p = "ISO";
+ break;
+ }
+ qh->bandwidth_reserved = 0;
+ dev_dbg(uhci_dev(uhci),
+ "%s dev %d ep%02x-%s, period %d, phase %d, %d us\n",
+ "release", qh->udev->devnum,
+ qh->hep->desc.bEndpointAddress, p,
+ qh->period, qh->phase, load);
+}
+
static inline struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci,
struct urb *urb)
{
struct urb_priv *urbp;
- urbp = kmem_cache_alloc(uhci_up_cachep, GFP_ATOMIC);
+ urbp = kmem_cache_zalloc(uhci_up_cachep, GFP_ATOMIC);
if (!urbp)
return NULL;
- memset((void *)urbp, 0, sizeof(*urbp));
-
urbp->urb = urb;
urb->hcpriv = urbp;
@@ -573,6 +841,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
dma_addr_t data = urb->transfer_dma;
__le32 *plink;
struct urb_priv *urbp = urb->hcpriv;
+ int skel;
/* The "pipe" thing contains the destination in bits 8--18 */
destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP;
@@ -613,7 +882,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
td = uhci_alloc_td(uhci);
if (!td)
goto nomem;
- *plink = cpu_to_le32(td->dma_handle);
+ *plink = LINK_TO_TD(td);
/* Alternate Data0/1 (start with Data1) */
destination ^= TD_TOKEN_TOGGLE;
@@ -633,7 +902,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
td = uhci_alloc_td(uhci);
if (!td)
goto nomem;
- *plink = cpu_to_le32(td->dma_handle);
+ *plink = LINK_TO_TD(td);
/*
* It's IN if the pipe is an output pipe or we're not expecting
@@ -660,7 +929,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
td = uhci_alloc_td(uhci);
if (!td)
goto nomem;
- *plink = cpu_to_le32(td->dma_handle);
+ *plink = LINK_TO_TD(td);
uhci_fill_td(td, 0, USB_PID_OUT | uhci_explen(0), 0);
wmb();
@@ -673,11 +942,13 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
* isn't in the CONFIGURED state. */
if (urb->dev->speed == USB_SPEED_LOW ||
urb->dev->state != USB_STATE_CONFIGURED)
- qh->skel = uhci->skel_ls_control_qh;
+ skel = SKEL_LS_CONTROL;
else {
- qh->skel = uhci->skel_fs_control_qh;
+ skel = SKEL_FS_CONTROL;
uhci_add_fsbr(uhci, urb);
}
+ if (qh->state != QH_STATE_ACTIVE)
+ qh->skel = skel;
urb->actual_length = -8; /* Account for the SETUP packet */
return 0;
@@ -736,7 +1007,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
td = uhci_alloc_td(uhci);
if (!td)
goto nomem;
- *plink = cpu_to_le32(td->dma_handle);
+ *plink = LINK_TO_TD(td);
}
uhci_add_td_to_urbp(td, urbp);
uhci_fill_td(td, status,
@@ -764,7 +1035,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
td = uhci_alloc_td(uhci);
if (!td)
goto nomem;
- *plink = cpu_to_le32(td->dma_handle);
+ *plink = LINK_TO_TD(td);
uhci_add_td_to_urbp(td, urbp);
uhci_fill_td(td, status,
@@ -790,13 +1061,12 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
td = uhci_alloc_td(uhci);
if (!td)
goto nomem;
- *plink = cpu_to_le32(td->dma_handle);
+ *plink = LINK_TO_TD(td);
uhci_fill_td(td, 0, USB_PID_OUT | uhci_explen(0), 0);
wmb();
qh->dummy_td->status |= __constant_cpu_to_le32(TD_CTRL_ACTIVE);
qh->dummy_td = td;
- qh->period = urb->interval;
usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
usb_pipeout(urb->pipe), toggle);
@@ -808,7 +1078,7 @@ nomem:
return -ENOMEM;
}
-static inline int uhci_submit_bulk(struct uhci_hcd *uhci, struct urb *urb,
+static int uhci_submit_bulk(struct uhci_hcd *uhci, struct urb *urb,
struct uhci_qh *qh)
{
int ret;
@@ -817,7 +1087,8 @@ static inline int uhci_submit_bulk(struct uhci_hcd *uhci, struct urb *urb,
if (urb->dev->speed == USB_SPEED_LOW)
return -EINVAL;
- qh->skel = uhci->skel_bulk_qh;
+ if (qh->state != QH_STATE_ACTIVE)
+ qh->skel = SKEL_BULK;
ret = uhci_submit_common(uhci, urb, qh);
if (ret == 0)
uhci_add_fsbr(uhci, urb);
@@ -827,28 +1098,42 @@ static inline int uhci_submit_bulk(struct uhci_hcd *uhci, struct urb *urb,
static int uhci_submit_interrupt(struct uhci_hcd *uhci, struct urb *urb,
struct uhci_qh *qh)
{
- int exponent;
+ int ret;
/* USB 1.1 interrupt transfers only involve one packet per interval.
* Drivers can submit URBs of any length, but longer ones will need
* multiple intervals to complete.
*/
- /* Figure out which power-of-two queue to use */
- for (exponent = 7; exponent >= 0; --exponent) {
- if ((1 << exponent) <= urb->interval)
- break;
- }
- if (exponent < 0)
- return -EINVAL;
- urb->interval = 1 << exponent;
+ if (!qh->bandwidth_reserved) {
+ int exponent;
- if (qh->period == 0)
- qh->skel = uhci->skelqh[UHCI_SKEL_INDEX(exponent)];
- else if (qh->period != urb->interval)
- return -EINVAL; /* Can't change the period */
+ /* Figure out which power-of-two queue to use */
+ for (exponent = 7; exponent >= 0; --exponent) {
+ if ((1 << exponent) <= urb->interval)
+ break;
+ }
+ if (exponent < 0)
+ return -EINVAL;
+ qh->period = 1 << exponent;
+ qh->skel = SKEL_INDEX(exponent);
+
+ /* For now, interrupt phase is fixed by the layout
+ * of the QH lists. */
+ qh->phase = (qh->period / 2) & (MAX_PHASE - 1);
+ ret = uhci_check_bandwidth(uhci, qh);
+ if (ret)
+ return ret;
+ } else if (qh->period > urb->interval)
+ return -EINVAL; /* Can't decrease the period */
- return uhci_submit_common(uhci, urb, qh);
+ ret = uhci_submit_common(uhci, urb, qh);
+ if (ret == 0) {
+ urb->interval = qh->period;
+ if (!qh->bandwidth_reserved)
+ uhci_reserve_bandwidth(uhci, qh);
+ }
+ return ret;
}
/*
@@ -868,7 +1153,7 @@ static int uhci_fixup_short_transfer(struct uhci_hcd *uhci,
* the queue at the status stage transaction, which is
* the last TD. */
WARN_ON(list_empty(&urbp->td_list));
- qh->element = cpu_to_le32(td->dma_handle);
+ qh->element = LINK_TO_TD(td);
tmp = td->list.prev;
ret = -EINPROGRESS;
@@ -995,15 +1280,32 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
return -EFBIG;
/* Check the period and figure out the starting frame number */
- if (qh->period == 0) {
+ if (!qh->bandwidth_reserved) {
+ qh->period = urb->interval;
if (urb->transfer_flags & URB_ISO_ASAP) {
+ qh->phase = -1; /* Find the best phase */
+ i = uhci_check_bandwidth(uhci, qh);
+ if (i)
+ return i;
+
+ /* Allow a little time to allocate the TDs */
uhci_get_current_frame_number(uhci);
- urb->start_frame = uhci->frame_number + 10;
+ frame = uhci->frame_number + 10;
+
+ /* Move forward to the first frame having the
+ * correct phase */
+ urb->start_frame = frame + ((qh->phase - frame) &
+ (qh->period - 1));
} else {
i = urb->start_frame - uhci->last_iso_frame;
if (i <= 0 || i >= UHCI_NUMFRAMES)
return -EINVAL;
+ qh->phase = urb->start_frame & (qh->period - 1);
+ i = uhci_check_bandwidth(uhci, qh);
+ if (i)
+ return i;
}
+
} else if (qh->period != urb->interval) {
return -EINVAL; /* Can't change the period */
@@ -1049,9 +1351,6 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
/* Set the interrupt-on-completion flag on the last packet. */
td->status |= __constant_cpu_to_le32(TD_CTRL_IOC);
- qh->skel = uhci->skel_iso_qh;
- qh->period = urb->interval;
-
/* Add the TDs to the frame list */
frame = urb->start_frame;
list_for_each_entry(td, &urbp->td_list, list) {
@@ -1065,6 +1364,9 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
qh->iso_status = 0;
}
+ qh->skel = SKEL_ISO;
+ if (!qh->bandwidth_reserved)
+ uhci_reserve_bandwidth(uhci, qh);
return 0;
}
@@ -1119,7 +1421,6 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd,
unsigned long flags;
struct urb_priv *urbp;
struct uhci_qh *qh;
- int bustime;
spin_lock_irqsave(&uhci->lock, flags);
@@ -1149,35 +1450,11 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd,
ret = uhci_submit_bulk(uhci, urb, qh);
break;
case USB_ENDPOINT_XFER_INT:
- if (list_empty(&qh->queue)) {
- bustime = usb_check_bandwidth(urb->dev, urb);
- if (bustime < 0)
- ret = bustime;
- else {
- ret = uhci_submit_interrupt(uhci, urb, qh);
- if (ret == 0)
- usb_claim_bandwidth(urb->dev, urb, bustime, 0);
- }
- } else { /* inherit from parent */
- struct urb_priv *eurbp;
-
- eurbp = list_entry(qh->queue.prev, struct urb_priv,
- node);
- urb->bandwidth = eurbp->urb->bandwidth;
- ret = uhci_submit_interrupt(uhci, urb, qh);
- }
+ ret = uhci_submit_interrupt(uhci, urb, qh);
break;
case USB_ENDPOINT_XFER_ISOC:
urb->error_count = 0;
- bustime = usb_check_bandwidth(urb->dev, urb);
- if (bustime < 0) {
- ret = bustime;
- break;
- }
-
ret = uhci_submit_isochronous(uhci, urb, qh);
- if (ret == 0)
- usb_claim_bandwidth(urb->dev, urb, bustime, 1);
break;
}
if (ret != 0)
@@ -1274,24 +1551,6 @@ __acquires(uhci->lock)
uhci_free_urb_priv(uhci, urbp);
- switch (qh->type) {
- case USB_ENDPOINT_XFER_ISOC:
- /* Release bandwidth for Interrupt or Isoc. transfers */
- if (urb->bandwidth)
- usb_release_bandwidth(urb->dev, urb, 1);
- break;
- case USB_ENDPOINT_XFER_INT:
- /* Release bandwidth for Interrupt or Isoc. transfers */
- /* Make sure we don't release if we have a queued URB */
- if (list_empty(&qh->queue) && urb->bandwidth)
- usb_release_bandwidth(urb->dev, urb, 0);
- else
- /* bandwidth was passed on to queued URB, */
- /* so don't let usb_unlink_urb() release it */
- urb->bandwidth = 0;
- break;
- }
-
spin_unlock(&uhci->lock);
usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb);
spin_lock(&uhci->lock);
@@ -1300,9 +1559,8 @@ __acquires(uhci->lock)
* reserved bandwidth. */
if (list_empty(&qh->queue)) {
uhci_unlink_qh(uhci, qh);
-
- /* Bandwidth stuff not yet implemented */
- qh->period = 0;
+ if (qh->bandwidth_reserved)
+ uhci_release_bandwidth(uhci, qh);
}
}
@@ -1456,8 +1714,7 @@ static int uhci_advance_check(struct uhci_hcd *uhci, struct uhci_qh *qh)
if (time_after(jiffies, qh->advance_jiffies + QH_WAIT_TIMEOUT)) {
/* Detect the Intel bug and work around it */
- if (qh->post_td && qh_element(qh) ==
- cpu_to_le32(qh->post_td->dma_handle)) {
+ if (qh->post_td && qh_element(qh) == LINK_TO_TD(qh->post_td)) {
qh->element = qh->post_td->link;
qh->advance_jiffies = jiffies;
ret = 1;
diff --git a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c
index 63a84bbc310..d308afd0693 100644
--- a/drivers/usb/image/mdc800.c
+++ b/drivers/usb/image/mdc800.c
@@ -565,11 +565,15 @@ static void mdc800_usb_disconnect (struct usb_interface *intf)
usb_deregister_dev(intf, &mdc800_class);
+ /* must be under lock to make sure no URB
+ is submitted after usb_kill_urb() */
+ mutex_lock(&mdc800->io_lock);
mdc800->state=NOT_CONNECTED;
usb_kill_urb(mdc800->irq_urb);
usb_kill_urb(mdc800->write_urb);
usb_kill_urb(mdc800->download_urb);
+ mutex_unlock(&mdc800->io_lock);
mdc800->dev = NULL;
usb_set_intfdata(intf, NULL);
diff --git a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c
index 8ccddf74534..896cb2b7102 100644
--- a/drivers/usb/image/microtek.c
+++ b/drivers/usb/image/microtek.c
@@ -121,7 +121,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/signal.h>
#include <linux/errno.h>
#include <linux/random.h>
diff --git a/drivers/usb/input/Kconfig b/drivers/usb/input/Kconfig
index c7d887540d8..69a9f3b6d0a 100644
--- a/drivers/usb/input/Kconfig
+++ b/drivers/usb/input/Kconfig
@@ -58,17 +58,29 @@ config HID_PID
devices.
config LOGITECH_FF
- bool "Logitech WingMan *3D support"
+ bool "Logitech devices support"
depends on HID_FF
select INPUT_FF_MEMLESS if USB_HID
help
Say Y here if you have one of these devices:
- Logitech WingMan Cordless RumblePad
+ - Logitech WingMan Cordless RumblePad 2
- Logitech WingMan Force 3D
+ - Logitech Formula Force EX
+ - Logitech MOMO Force wheel
+
and if you want to enable force feedback for them.
Note: if you say N here, this device will still be supported, but without
force feedback.
+config PANTHERLORD_FF
+ bool "PantherLord USB/PS2 2in1 Adapter support"
+ depends on HID_FF
+ select INPUT_FF_MEMLESS if USB_HID
+ help
+ Say Y here if you have a PantherLord USB/PS2 2in1 Adapter and want
+ to enable force feedback support for it.
+
config THRUSTMASTER_FF
bool "ThrustMaster FireStorm Dual Power 2 support (EXPERIMENTAL)"
depends on HID_FF && EXPERIMENTAL
@@ -344,3 +356,15 @@ config USB_APPLETOUCH
To compile this driver as a module, choose M here: the
module will be called appletouch.
+
+config USB_GTCO
+ tristate "GTCO CalComp/InterWrite USB Support"
+ depends on USB && INPUT
+ ---help---
+ Say Y here if you want to use the USB version of the GTCO
+ CalComp/InterWrite Tablet. Make sure to say Y to "Mouse support"
+ (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support"
+ (CONFIG_INPUT_EVDEV) as well.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gtco.
diff --git a/drivers/usb/input/Makefile b/drivers/usb/input/Makefile
index 1a24b5bfa05..a9d206c945e 100644
--- a/drivers/usb/input/Makefile
+++ b/drivers/usb/input/Makefile
@@ -17,6 +17,9 @@ endif
ifeq ($(CONFIG_LOGITECH_FF),y)
usbhid-objs += hid-lgff.o
endif
+ifeq ($(CONFIG_PANTHERLORD_FF),y)
+ usbhid-objs += hid-plff.o
+endif
ifeq ($(CONFIG_THRUSTMASTER_FF),y)
usbhid-objs += hid-tmff.o
endif
@@ -45,6 +48,7 @@ obj-$(CONFIG_USB_ACECAD) += acecad.o
obj-$(CONFIG_USB_YEALINK) += yealink.o
obj-$(CONFIG_USB_XPAD) += xpad.o
obj-$(CONFIG_USB_APPLETOUCH) += appletouch.o
+obj-$(CONFIG_USB_GTCO) += gtco.o
ifeq ($(CONFIG_USB_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG
diff --git a/drivers/usb/input/aiptek.c b/drivers/usb/input/aiptek.c
index 9f52429ce65..f857935e615 100644
--- a/drivers/usb/input/aiptek.c
+++ b/drivers/usb/input/aiptek.c
@@ -76,7 +76,6 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/usb/input.h>
-#include <linux/sched.h>
#include <asm/uaccess.h>
#include <asm/unaligned.h>
diff --git a/drivers/usb/input/gtco.c b/drivers/usb/input/gtco.c
new file mode 100644
index 00000000000..203cdc1bbba
--- /dev/null
+++ b/drivers/usb/input/gtco.c
@@ -0,0 +1,1104 @@
+/* -*- linux-c -*-
+
+GTCO digitizer USB driver
+
+Use the err(), dbg() and info() macros from usb.h for system logging
+
+TO CHECK: Is pressure done right on report 5?
+
+Copyright (C) 2006 GTCO CalComp
+
+This program is free software; 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.
+
+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.
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation, and that the name of GTCO-CalComp not be used in advertising
+or publicity pertaining to distribution of the software without specific,
+written prior permission. GTCO-CalComp makes no representations about the
+suitability of this software for any purpose. It is provided "as is"
+without express or implied warranty.
+
+GTCO-CALCOMP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+EVENT SHALL GTCO-CALCOMP BE LIABLE FOR ANY SPECIAL, 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 ACTIONS, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
+
+GTCO CalComp, Inc.
+7125 Riverwood Drive
+Columbia, MD 21046
+
+Jeremy Roberson jroberson@gtcocalcomp.com
+Scott Hill shill@gtcocalcomp.com
+*/
+
+
+
+/*#define DEBUG*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/usb.h>
+#include <asm/uaccess.h>
+#include <asm/unaligned.h>
+#include <asm/byteorder.h>
+
+
+#include <linux/version.h>
+#include <linux/usb/input.h>
+
+/* Version with a Major number of 2 is for kernel inclusion only. */
+#define GTCO_VERSION "2.00.0006"
+
+
+/* MACROS */
+
+#define VENDOR_ID_GTCO 0x078C
+#define PID_400 0x400
+#define PID_401 0x401
+#define PID_1000 0x1000
+#define PID_1001 0x1001
+#define PID_1002 0x1002
+
+/* Max size of a single report */
+#define REPORT_MAX_SIZE 10
+
+
+/* Bitmask whether pen is in range */
+#define MASK_INRANGE 0x20
+#define MASK_BUTTON 0x01F
+
+#define PATHLENGTH 64
+
+/* DATA STRUCTURES */
+
+/* Device table */
+static 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) },
+ { USB_DEVICE(VENDOR_ID_GTCO, PID_1001) },
+ { USB_DEVICE(VENDOR_ID_GTCO, PID_1002) },
+ { }
+};
+MODULE_DEVICE_TABLE (usb, gtco_usbid_table);
+
+
+/* Structure to hold all of our device specific stuff */
+struct gtco {
+
+ struct input_dev *inputdevice; /* input device struct pointer */
+ struct usb_device *usbdev; /* the usb device for this device */
+ struct urb *urbinfo; /* urb for incoming reports */
+ dma_addr_t buf_dma; /* dma addr of the data buffer*/
+ unsigned char * buffer; /* databuffer for reports */
+
+ char usbpath[PATHLENGTH];
+ int openCount;
+
+ /* Information pulled from Report Descriptor */
+ u32 usage;
+ u32 min_X;
+ u32 max_X;
+ u32 min_Y;
+ u32 max_Y;
+ s8 mintilt_X;
+ s8 maxtilt_X;
+ s8 mintilt_Y;
+ s8 maxtilt_Y;
+ u32 maxpressure;
+ u32 minpressure;
+};
+
+
+
+/* Code for parsing the HID REPORT DESCRIPTOR */
+
+/* From HID1.11 spec */
+struct hid_descriptor
+{
+ struct usb_descriptor_header header;
+ __le16 bcdHID;
+ u8 bCountryCode;
+ u8 bNumDescriptors;
+ u8 bDescriptorType;
+ __le16 wDescriptorLength;
+} __attribute__ ((packed));
+
+
+#define HID_DESCRIPTOR_SIZE 9
+#define HID_DEVICE_TYPE 33
+#define REPORT_DEVICE_TYPE 34
+
+
+#define PREF_TAG(x) ((x)>>4)
+#define PREF_TYPE(x) ((x>>2)&0x03)
+#define PREF_SIZE(x) ((x)&0x03)
+
+#define TYPE_MAIN 0
+#define TYPE_GLOBAL 1
+#define TYPE_LOCAL 2
+#define TYPE_RESERVED 3
+
+#define TAG_MAIN_INPUT 0x8
+#define TAG_MAIN_OUTPUT 0x9
+#define TAG_MAIN_FEATURE 0xB
+#define TAG_MAIN_COL_START 0xA
+#define TAG_MAIN_COL_END 0xC
+
+#define TAG_GLOB_USAGE 0
+#define TAG_GLOB_LOG_MIN 1
+#define TAG_GLOB_LOG_MAX 2
+#define TAG_GLOB_PHYS_MIN 3
+#define TAG_GLOB_PHYS_MAX 4
+#define TAG_GLOB_UNIT_EXP 5
+#define TAG_GLOB_UNIT 6
+#define TAG_GLOB_REPORT_SZ 7
+#define TAG_GLOB_REPORT_ID 8
+#define TAG_GLOB_REPORT_CNT 9
+#define TAG_GLOB_PUSH 10
+#define TAG_GLOB_POP 11
+
+#define TAG_GLOB_MAX 12
+
+#define DIGITIZER_USAGE_TIP_PRESSURE 0x30
+#define DIGITIZER_USAGE_TILT_X 0x3D
+#define DIGITIZER_USAGE_TILT_Y 0x3E
+
+
+/*
+ *
+ * This is an abbreviated parser for the HID Report Descriptor. We
+ * know what devices we are talking to, so this is by no means meant
+ * to be generic. We can make some safe assumptions:
+ *
+ * - We know there are no LONG tags, all short
+ * - We know that we have no MAIN Feature and MAIN Output items
+ * - We know what the IRQ reports are supposed to look like.
+ *
+ * The main purpose of this is to use the HID report desc to figure
+ * out the mins and maxs of the fields in the IRQ reports. The IRQ
+ * reports for 400/401 change slightly if the max X is bigger than 64K.
+ *
+ */
+static void parse_hid_report_descriptor(struct gtco *device, char * report,
+ int length)
+{
+ int x,i=0;
+
+ /* Tag primitive vars */
+ __u8 prefix;
+ __u8 size;
+ __u8 tag;
+ __u8 type;
+ __u8 data = 0;
+ __u16 data16 = 0;
+ __u32 data32 = 0;
+
+
+ /* For parsing logic */
+ int inputnum = 0;
+ __u32 usage = 0;
+
+ /* Global Values, indexed by TAG */
+ __u32 globalval[TAG_GLOB_MAX];
+ __u32 oldval[TAG_GLOB_MAX];
+
+ /* Debug stuff */
+ char maintype='x';
+ char globtype[12];
+ int indent=0;
+ char indentstr[10]="";
+
+
+
+ dbg("======>>>>>>PARSE<<<<<<======");
+
+ /* Walk this report and pull out the info we need */
+ while (i<length){
+ prefix=report[i];
+
+ /* Skip over prefix */
+ i++;
+
+ /* Determine data size and save the data in the proper variable */
+ size = PREF_SIZE(prefix);
+ switch(size){
+ case 1:
+ data = report[i];
+ break;
+ case 2:
+ data16 = le16_to_cpu(get_unaligned((__le16*)(&(report[i]))));
+ break;
+ case 3:
+ size = 4;
+ data32 = le32_to_cpu(get_unaligned((__le32*)(&(report[i]))));
+ }
+
+ /* Skip size of data */
+ i+=size;
+
+ /* What we do depends on the tag type */
+ tag = PREF_TAG(prefix);
+ type = PREF_TYPE(prefix);
+ switch(type){
+ case TYPE_MAIN:
+ strcpy(globtype,"");
+ switch(tag){
+
+ case TAG_MAIN_INPUT:
+ /*
+ * The INPUT MAIN tag signifies this is
+ * information from a report. We need to
+ * figure out what it is and store the
+ * min/max values
+ */
+
+ maintype='I';
+ if (data==2){
+ strcpy(globtype,"Variable");
+ }
+ if (data==3){
+ strcpy(globtype,"Var|Const");
+ }
+
+ dbg("::::: Saving Report: %d input #%d Max: 0x%X(%d) Min:0x%X(%d) of %d bits",
+ globalval[TAG_GLOB_REPORT_ID],inputnum,
+ globalval[TAG_GLOB_LOG_MAX],globalval[TAG_GLOB_LOG_MAX],
+ globalval[TAG_GLOB_LOG_MIN],globalval[TAG_GLOB_LOG_MIN],
+ (globalval[TAG_GLOB_REPORT_SZ] * globalval[TAG_GLOB_REPORT_CNT]));
+
+
+ /*
+ We can assume that the first two input items
+ are always the X and Y coordinates. After
+ that, we look for everything else by
+ local usage value
+ */
+ switch (inputnum){
+ case 0: /* X coord */
+ dbg("GER: X Usage: 0x%x",usage);
+ if (device->max_X == 0){
+ device->max_X = globalval[TAG_GLOB_LOG_MAX];
+ device->min_X = globalval[TAG_GLOB_LOG_MIN];
+ }
+
+ break;
+ case 1: /* Y coord */
+ dbg("GER: Y Usage: 0x%x",usage);
+ if (device->max_Y == 0){
+ device->max_Y = globalval[TAG_GLOB_LOG_MAX];
+ device->min_Y = globalval[TAG_GLOB_LOG_MIN];
+ }
+ break;
+ default:
+ /* Tilt X */
+ if (usage == DIGITIZER_USAGE_TILT_X){
+ if (device->maxtilt_X == 0){
+ device->maxtilt_X = globalval[TAG_GLOB_LOG_MAX];
+ device->mintilt_X = globalval[TAG_GLOB_LOG_MIN];
+ }
+ }
+
+ /* Tilt Y */
+ if (usage == DIGITIZER_USAGE_TILT_Y){
+ if (device->maxtilt_Y == 0){
+ device->maxtilt_Y = globalval[TAG_GLOB_LOG_MAX];
+ device->mintilt_Y = globalval[TAG_GLOB_LOG_MIN];
+ }
+ }
+
+
+ /* Pressure */
+ if (usage == DIGITIZER_USAGE_TIP_PRESSURE){
+ if (device->maxpressure == 0){
+ device->maxpressure = globalval[TAG_GLOB_LOG_MAX];
+ device->minpressure = globalval[TAG_GLOB_LOG_MIN];
+ }
+ }
+
+ break;
+ }
+
+ inputnum++;
+
+
+ break;
+ case TAG_MAIN_OUTPUT:
+ maintype='O';
+ break;
+ case TAG_MAIN_FEATURE:
+ maintype='F';
+ break;
+ case TAG_MAIN_COL_START:
+ maintype='S';
+
+ if (data==0){
+ dbg("======>>>>>> Physical");
+ strcpy(globtype,"Physical");
+ }else{
+ dbg("======>>>>>>");
+ }
+
+ /* Indent the debug output */
+ indent++;
+ for (x=0;x<indent;x++){
+ indentstr[x]='-';
+ }
+ indentstr[x]=0;
+
+ /* Save global tags */
+ for (x=0;x<TAG_GLOB_MAX;x++){
+ oldval[x] = globalval[x];
+ }
+
+ break;
+ case TAG_MAIN_COL_END:
+ dbg("<<<<<<======");
+ maintype='E';
+ indent--;
+ for (x=0;x<indent;x++){
+ indentstr[x]='-';
+ }
+ indentstr[x]=0;
+
+ /* Copy global tags back */
+ for (x=0;x<TAG_GLOB_MAX;x++){
+ globalval[x] = oldval[x];
+ }
+
+ break;
+ }
+
+ switch (size){
+ case 1:
+ dbg("%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x",
+ indentstr,tag,maintype,size,globtype,data);
+ break;
+ case 2:
+ dbg("%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x",
+ indentstr,tag,maintype,size,globtype, data16);
+ break;
+ case 4:
+ dbg("%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x",
+ indentstr,tag,maintype,size,globtype,data32);
+ break;
+ }
+ break;
+ case TYPE_GLOBAL:
+ switch(tag){
+ case TAG_GLOB_USAGE:
+ /*
+ * First time we hit the global usage tag,
+ * it should tell us the type of device
+ */
+ if (device->usage == 0){
+ device->usage = data;
+ }
+ strcpy(globtype,"USAGE");
+ break;
+ case TAG_GLOB_LOG_MIN :
+ strcpy(globtype,"LOG_MIN");
+ break;
+ case TAG_GLOB_LOG_MAX :
+ strcpy(globtype,"LOG_MAX");
+ break;
+ case TAG_GLOB_PHYS_MIN :
+ strcpy(globtype,"PHYS_MIN");
+ break;
+ case TAG_GLOB_PHYS_MAX :
+ strcpy(globtype,"PHYS_MAX");
+ break;
+ case TAG_GLOB_UNIT_EXP :
+ strcpy(globtype,"EXP");
+ break;
+ case TAG_GLOB_UNIT :
+ strcpy(globtype,"UNIT");
+ break;
+ case TAG_GLOB_REPORT_SZ :
+ strcpy(globtype,"REPORT_SZ");
+ break;
+ case TAG_GLOB_REPORT_ID :
+ strcpy(globtype,"REPORT_ID");
+ /* New report, restart numbering */
+ inputnum=0;
+ break;
+ case TAG_GLOB_REPORT_CNT:
+ strcpy(globtype,"REPORT_CNT");
+ break;
+ case TAG_GLOB_PUSH :
+ strcpy(globtype,"PUSH");
+ break;
+ case TAG_GLOB_POP:
+ strcpy(globtype,"POP");
+ break;
+ }
+
+
+ /* Check to make sure we have a good tag number
+ so we don't overflow array */
+ if (tag < TAG_GLOB_MAX){
+ switch (size){
+ case 1:
+ dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",indentstr,globtype,tag,size,data);
+ globalval[tag]=data;
+ break;
+ case 2:
+ dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",indentstr,globtype,tag,size,data16);
+ globalval[tag]=data16;
+ break;
+ case 4:
+ dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",indentstr,globtype,tag,size,data32);
+ globalval[tag]=data32;
+ break;
+ }
+ }else{
+ dbg("%sGLOBALTAG: ILLEGAL TAG:%d SIZE: %d ",
+ indentstr,tag,size);
+ }
+
+
+ break;
+
+ case TYPE_LOCAL:
+ switch(tag){
+ case TAG_GLOB_USAGE:
+ strcpy(globtype,"USAGE");
+ /* Always 1 byte */
+ usage = data;
+ break;
+ case TAG_GLOB_LOG_MIN :
+ strcpy(globtype,"MIN");
+ break;
+ case TAG_GLOB_LOG_MAX :
+ strcpy(globtype,"MAX");
+ break;
+ default:
+ strcpy(globtype,"UNKNOWN");
+ }
+
+ switch (size){
+ case 1:
+ dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x",
+ indentstr,tag,globtype,size,data);
+ break;
+ case 2:
+ dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x",
+ indentstr,tag,globtype,size,data16);
+ break;
+ case 4:
+ dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x",
+ indentstr,tag,globtype,size,data32);
+ break;
+ }
+
+ break;
+ }
+
+ }
+
+}
+
+
+
+/* INPUT DRIVER Routines */
+
+
+/*
+ * Called when opening the input device. This will submit the URB to
+ * the usb system so we start getting reports
+ */
+static int gtco_input_open(struct input_dev *inputdev)
+{
+ struct gtco *device;
+ device = inputdev->private;
+
+ device->urbinfo->dev = device->usbdev;
+ if (usb_submit_urb(device->urbinfo, GFP_KERNEL)) {
+ return -EIO;
+ }
+ return 0;
+}
+
+/**
+ Called when closing the input device. This will unlink the URB
+*/
+static void gtco_input_close(struct input_dev *inputdev)
+{
+ struct gtco *device = inputdev->private;
+
+ usb_kill_urb(device->urbinfo);
+
+}
+
+
+/*
+ * Setup input device capabilities. Tell the input system what this
+ * device is capable of generating.
+ *
+ * This information is based on what is read from the HID report and
+ * placed in the struct gtco structure
+ *
+ */
+static void gtco_setup_caps(struct input_dev *inputdev)
+{
+ struct gtco *device = inputdev->private;
+
+
+ /* Which events */
+ inputdev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_MSC);
+
+
+ /* Misc event menu block */
+ inputdev->mscbit[0] = BIT(MSC_SCAN)|BIT(MSC_SERIAL)|BIT(MSC_RAW) ;
+
+
+ /* Absolute values based on HID report info */
+ input_set_abs_params(inputdev, ABS_X, device->min_X, device->max_X,
+ 0, 0);
+ input_set_abs_params(inputdev, ABS_Y, device->min_Y, device->max_Y,
+ 0, 0);
+
+ /* Proximity */
+ input_set_abs_params(inputdev, ABS_DISTANCE, 0, 1, 0, 0);
+
+ /* Tilt & pressure */
+ input_set_abs_params(inputdev, ABS_TILT_X, device->mintilt_X,
+ device->maxtilt_X, 0, 0);
+ input_set_abs_params(inputdev, ABS_TILT_Y, device->mintilt_Y,
+ device->maxtilt_Y, 0, 0);
+ input_set_abs_params(inputdev, ABS_PRESSURE, device->minpressure,
+ device->maxpressure, 0, 0);
+
+
+ /* Transducer */
+ input_set_abs_params(inputdev, ABS_MISC, 0,0xFF, 0, 0);
+
+}
+
+
+
+/* USB Routines */
+
+
+/*
+ * URB callback routine. Called when we get IRQ reports from the
+ * digitizer.
+ *
+ * This bridges the USB and input device worlds. It generates events
+ * on the input device based on the USB reports.
+ */
+static void gtco_urb_callback(struct urb *urbinfo)
+{
+
+
+ struct gtco *device = urbinfo->context;
+ struct input_dev *inputdev;
+ int rc;
+ u32 val = 0;
+ s8 valsigned = 0;
+ char le_buffer[2];
+
+ inputdev = device->inputdevice;
+
+
+ /* Was callback OK? */
+ if ((urbinfo->status == -ECONNRESET ) ||
+ (urbinfo->status == -ENOENT ) ||
+ (urbinfo->status == -ESHUTDOWN )){
+
+ /* Shutdown is occurring. Return and don't queue up any more */
+ return;
+ }
+
+ if (urbinfo->status != 0 ) {
+ /* Some unknown error. Hopefully temporary. Just go and */
+ /* requeue an URB */
+ goto resubmit;
+ }
+
+ /*
+ * Good URB, now process
+ */
+
+ /* PID dependent when we interpret the report */
+ if ((inputdev->id.product == PID_1000 )||
+ (inputdev->id.product == PID_1001 )||
+ (inputdev->id.product == PID_1002 ))
+ {
+
+ /*
+ * Switch on the report ID
+ * Conveniently, the reports have more information, the higher
+ * the report number. We can just fall through the case
+ * statements if we start with the highest number report
+ */
+ switch(device->buffer[0]){
+ case 5:
+ /* Pressure is 9 bits */
+ val = ((u16)(device->buffer[8]) << 1);
+ val |= (u16)(device->buffer[7] >> 7);
+ input_report_abs(inputdev, ABS_PRESSURE,
+ device->buffer[8]);
+
+ /* Mask out the Y tilt value used for pressure */
+ device->buffer[7] = (u8)((device->buffer[7]) & 0x7F);
+
+
+ /* Fall thru */
+ case 4:
+ /* Tilt */
+
+ /* Sign extend these 7 bit numbers. */
+ if (device->buffer[6] & 0x40)
+ device->buffer[6] |= 0x80;
+
+ if (device->buffer[7] & 0x40)
+ device->buffer[7] |= 0x80;
+
+
+ valsigned = (device->buffer[6]);
+ input_report_abs(inputdev, ABS_TILT_X, (s32)valsigned);
+
+ valsigned = (device->buffer[7]);
+ input_report_abs(inputdev, ABS_TILT_Y, (s32)valsigned);
+
+ /* Fall thru */
+
+ case 2:
+ case 3:
+ /* Convert buttons, only 5 bits possible */
+ val = (device->buffer[5])&MASK_BUTTON;
+
+ /* We don't apply any meaning to the bitmask,
+ just report */
+ input_event(inputdev, EV_MSC, MSC_SERIAL, val);
+
+ /* Fall thru */
+ case 1:
+
+ /* All reports have X and Y coords in the same place */
+ val = le16_to_cpu(get_unaligned((__le16 *) &(device->buffer[1])));
+ input_report_abs(inputdev, ABS_X, val);
+
+ val = le16_to_cpu(get_unaligned((__le16 *) &(device->buffer[3])));
+ input_report_abs(inputdev, ABS_Y, val);
+
+
+ /* Ditto for proximity bit */
+ if (device->buffer[5]& MASK_INRANGE){
+ val = 1;
+ }else{
+ val=0;
+ }
+ input_report_abs(inputdev, ABS_DISTANCE, val);
+
+
+ /* Report 1 is an exception to how we handle buttons */
+ /* Buttons are an index, not a bitmask */
+ if (device->buffer[0] == 1){
+
+ /* Convert buttons, 5 bit index */
+ /* Report value of index set as one,
+ the rest as 0 */
+ val = device->buffer[5]& MASK_BUTTON;
+ dbg("======>>>>>>REPORT 1: val 0x%X(%d)",
+ val,val);
+
+ /*
+ * We don't apply any meaning to the button
+ * index, just report it
+ */
+ input_event(inputdev, EV_MSC, MSC_SERIAL, val);
+
+
+ }
+
+ break;
+ case 7:
+ /* Menu blocks */
+ input_event(inputdev, EV_MSC, MSC_SCAN,
+ device->buffer[1]);
+
+
+ break;
+
+ }
+
+
+ }
+ /* Other pid class */
+ if ((inputdev->id.product == PID_400 )||
+ (inputdev->id.product == PID_401 ))
+ {
+
+ /* Report 2 */
+ if (device->buffer[0] == 2){
+ /* Menu blocks */
+ input_event(inputdev, EV_MSC, MSC_SCAN,
+ device->buffer[1]);
+ }
+
+ /* Report 1 */
+ if (device->buffer[0] == 1){
+ char buttonbyte;
+
+
+ /* IF X max > 64K, we still a bit from the y report */
+ if (device->max_X > 0x10000){
+
+ val = (u16)(((u16)(device->buffer[2]<<8))|((u8)(device->buffer[1])));
+ val |= (u32)(((u8)device->buffer[3]&0x1)<< 16);
+
+ input_report_abs(inputdev, ABS_X, val);
+
+ le_buffer[0] = (u8)((u8)(device->buffer[3])>>1);
+ le_buffer[0] |= (u8)((device->buffer[3]&0x1)<<7);
+
+ le_buffer[1] = (u8)(device->buffer[4]>>1);
+ le_buffer[1] |= (u8)((device->buffer[5]&0x1)<<7);
+
+ val = le16_to_cpu(get_unaligned((__le16 *)(le_buffer)));
+
+ input_report_abs(inputdev, ABS_Y, val);
+
+
+ /*
+ * Shift the button byte right by one to
+ * make it look like the standard report
+ */
+ buttonbyte = (device->buffer[5])>>1;
+ }else{
+
+ val = le16_to_cpu(get_unaligned((__le16 *) (&(device->buffer[1]))));
+ input_report_abs(inputdev, ABS_X, val);
+
+ val = le16_to_cpu(get_unaligned((__le16 *) (&(device->buffer[3]))));
+ input_report_abs(inputdev, ABS_Y, val);
+
+ buttonbyte = device->buffer[5];
+
+ }
+
+
+ /* BUTTONS and PROXIMITY */
+ if (buttonbyte& MASK_INRANGE){
+ val = 1;
+ }else{
+ val=0;
+ }
+ input_report_abs(inputdev, ABS_DISTANCE, val);
+
+ /* Convert buttons, only 4 bits possible */
+ val = buttonbyte&0x0F;
+#ifdef USE_BUTTONS
+ for ( i=0;i<5;i++){
+ input_report_key(inputdev, BTN_DIGI+i,val&(1<<i));
+ }
+#else
+ /* We don't apply any meaning to the bitmask, just report */
+ input_event(inputdev, EV_MSC, MSC_SERIAL, val);
+#endif
+ /* TRANSDUCER */
+ input_report_abs(inputdev, ABS_MISC, device->buffer[6]);
+
+ }
+ }
+
+ /* Everybody gets report ID's */
+ input_event(inputdev, EV_MSC, MSC_RAW, device->buffer[0]);
+
+ /* Sync it up */
+ input_sync(inputdev);
+
+ resubmit:
+ rc = usb_submit_urb(urbinfo, GFP_ATOMIC);
+ if (rc != 0) {
+ err("usb_submit_urb failed rc=0x%x",rc);
+ }
+
+}
+
+/*
+ * The probe routine. This is called when the kernel find the matching USB
+ * vendor/product. We do the following:
+ *
+ * - Allocate mem for a local structure to manage the device
+ * - Request a HID Report Descriptor from the device and parse it to
+ * find out the device parameters
+ * - Create an input device and assign it attributes
+ * - Allocate an URB so the device can talk to us when the input
+ * queue is open
+ */
+static int gtco_probe(struct usb_interface *usbinterface,
+ const struct usb_device_id *id)
+{
+
+ struct gtco *device = NULL;
+ char path[PATHLENGTH];
+ struct input_dev *inputdev;
+ struct hid_descriptor *hid_desc;
+ char *report;
+ int result=0, retry;
+ struct usb_endpoint_descriptor *endpoint;
+
+ /* Allocate memory for device structure */
+ device = kzalloc(sizeof(struct gtco), GFP_KERNEL);
+ if (device == NULL) {
+ err("No more memory");
+ return -ENOMEM;
+ }
+
+
+ device->inputdevice = input_allocate_device();
+ if (!device->inputdevice){
+ kfree(device);
+ err("No more memory");
+ return -ENOMEM;
+ }
+
+ /* Get pointer to the input device */
+ inputdev = device->inputdevice;
+
+ /* Save interface information */
+ device->usbdev = usb_get_dev(interface_to_usbdev(usbinterface));
+
+
+ /* Allocate some data for incoming reports */
+ device->buffer = usb_buffer_alloc(device->usbdev, REPORT_MAX_SIZE,
+ GFP_KERNEL, &(device->buf_dma));
+ if (!device->buffer){
+ input_free_device(device->inputdevice);
+ kfree(device);
+ err("No more memory");
+ return -ENOMEM;
+ }
+
+ /* Allocate URB for reports */
+ device->urbinfo = usb_alloc_urb(0, GFP_KERNEL);
+ if (!device->urbinfo) {
+ usb_buffer_free(device->usbdev, REPORT_MAX_SIZE,
+ device->buffer, device->buf_dma);
+ input_free_device(device->inputdevice);
+ kfree(device);
+ err("No more memory");
+ return -ENOMEM;
+ }
+
+
+ /*
+ * The endpoint is always altsetting 0, we know this since we know
+ * this device only has one interrupt endpoint
+ */
+ endpoint = &usbinterface->altsetting[0].endpoint[0].desc;
+
+ /* Some debug */
+ dbg("gtco # interfaces: %d",usbinterface->num_altsetting);
+ dbg("num endpoints: %d",usbinterface->cur_altsetting->desc.bNumEndpoints);
+ dbg("interface class: %d",usbinterface->cur_altsetting->desc.bInterfaceClass);
+ dbg("endpoint: attribute:0x%x type:0x%x",endpoint->bmAttributes,endpoint->bDescriptorType);
+ if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)
+ dbg("endpoint: we have interrupt endpoint\n");
+
+ dbg("endpoint extra len:%d ",usbinterface->altsetting[0].extralen);
+
+
+
+ /*
+ * Find the HID descriptor so we can find out the size of the
+ * HID report descriptor
+ */
+ if (usb_get_extra_descriptor(usbinterface->cur_altsetting,
+ HID_DEVICE_TYPE,&hid_desc) != 0){
+ err("Can't retrieve exta USB descriptor to get hid report descriptor length");
+ usb_buffer_free(device->usbdev, REPORT_MAX_SIZE,
+ device->buffer, device->buf_dma);
+ input_free_device(device->inputdevice);
+ kfree(device);
+ return -EIO;
+ }
+
+ dbg("Extra descriptor success: type:%d len:%d",
+ hid_desc->bDescriptorType, hid_desc->wDescriptorLength);
+
+ if (!(report = kzalloc(hid_desc->wDescriptorLength, GFP_KERNEL))) {
+ usb_buffer_free(device->usbdev, REPORT_MAX_SIZE,
+ device->buffer, device->buf_dma);
+
+ input_free_device(device->inputdevice);
+ kfree(device);
+ err("No more memory");
+ return -ENOMEM;
+ }
+
+ /* Couple of tries to get reply */
+ for (retry=0;retry<3;retry++) {
+ result = usb_control_msg(device->usbdev,
+ usb_rcvctrlpipe(device->usbdev, 0),
+ USB_REQ_GET_DESCRIPTOR,
+ USB_RECIP_INTERFACE | USB_DIR_IN,
+ (REPORT_DEVICE_TYPE << 8),
+ 0, /* interface */
+ report,
+ hid_desc->wDescriptorLength,
+ 5000); /* 5 secs */
+
+ if (result == hid_desc->wDescriptorLength)
+ break;
+ }
+
+ /* If we didn't get the report, fail */
+ dbg("usb_control_msg result: :%d", result);
+ if (result != hid_desc->wDescriptorLength){
+ kfree(report);
+ usb_buffer_free(device->usbdev, REPORT_MAX_SIZE,
+ device->buffer, device->buf_dma);
+ input_free_device(device->inputdevice);
+ kfree(device);
+ err("Failed to get HID Report Descriptor of size: %d",
+ hid_desc->wDescriptorLength);
+ return -EIO;
+ }
+
+
+ /* Now we parse the report */
+ parse_hid_report_descriptor(device,report,result);
+
+ /* Now we delete it */
+ kfree(report);
+
+ /* Create a device file node */
+ usb_make_path(device->usbdev, path, PATHLENGTH);
+ sprintf(device->usbpath, "%s/input0", path);
+
+
+ /* Set Input device functions */
+ inputdev->open = gtco_input_open;
+ inputdev->close = gtco_input_close;
+
+ /* Set input device information */
+ inputdev->name = "GTCO_CalComp";
+ inputdev->phys = device->usbpath;
+ inputdev->private = device;
+
+
+ /* Now set up all the input device capabilities */
+ gtco_setup_caps(inputdev);
+
+ /* Set input device required ID information */
+ usb_to_input_id(device->usbdev, &device->inputdevice->id);
+ inputdev->cdev.dev = &usbinterface->dev;
+
+ /* Setup the URB, it will be posted later on open of input device */
+ endpoint = &usbinterface->altsetting[0].endpoint[0].desc;
+
+ usb_fill_int_urb(device->urbinfo,
+ device->usbdev,
+ usb_rcvintpipe(device->usbdev,
+ endpoint->bEndpointAddress),
+ device->buffer,
+ REPORT_MAX_SIZE,
+ gtco_urb_callback,
+ device,
+ endpoint->bInterval);
+
+ device->urbinfo->transfer_dma = device->buf_dma;
+ device->urbinfo->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+
+ /* Save device pointer in USB interface device */
+ usb_set_intfdata(usbinterface, device);
+
+ /* All done, now register the input device */
+ input_register_device(inputdev);
+
+ info( "gtco driver created usb: %s\n", path);
+ return 0;
+
+}
+
+/*
+ * This function is a standard USB function called when the USB device
+ * is disconnected. We will get rid of the URV, de-register the input
+ * device, and free up allocated memory
+ */
+static void gtco_disconnect(struct usb_interface *interface)
+{
+
+ /* Grab private device ptr */
+ struct gtco *device = usb_get_intfdata (interface);
+ struct input_dev *inputdev;
+
+ inputdev = device->inputdevice;
+
+ /* Now reverse all the registration stuff */
+ if (device) {
+ input_unregister_device(inputdev);
+ usb_kill_urb(device->urbinfo);
+ usb_free_urb(device->urbinfo);
+ usb_buffer_free(device->usbdev, REPORT_MAX_SIZE,
+ device->buffer, device->buf_dma);
+ kfree(device);
+ }
+
+ info("gtco driver disconnected");
+}
+
+
+/* STANDARD MODULE LOAD ROUTINES */
+
+static struct usb_driver gtco_driverinfo_table = {
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16))
+ .owner = THIS_MODULE,
+#endif
+ .name = "gtco",
+ .id_table = gtco_usbid_table,
+ .probe = gtco_probe,
+ .disconnect = gtco_disconnect,
+};
+/*
+ * Register this module with the USB subsystem
+ */
+static int __init gtco_init(void)
+{
+ int rc;
+ rc = usb_register(&gtco_driverinfo_table);
+ if (rc) {
+ err("usb_register() failed rc=0x%x", rc);
+ }
+ printk("GTCO usb driver version: %s",GTCO_VERSION);
+ return rc;
+}
+
+/*
+ * Deregister this module with the USB subsystem
+ */
+static void __exit gtco_exit(void)
+{
+ usb_deregister(&gtco_driverinfo_table);
+}
+
+module_init (gtco_init);
+module_exit (gtco_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c
index c6c9e72e5fd..ef09952f203 100644
--- a/drivers/usb/input/hid-core.c
+++ b/drivers/usb/input/hid-core.c
@@ -18,7 +18,6 @@
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/list.h>
#include <linux/mm.h>
#include <linux/smp_lock.h>
@@ -35,6 +34,7 @@
#include <linux/hid.h>
#include <linux/hiddev.h>
+#include <linux/hid-debug.h>
#include "usbhid.h"
/*
@@ -220,23 +220,6 @@ static void hid_irq_in(struct urb *urb)
}
}
-/*
- * Find a report field with a specified HID usage.
- */
-#if 0
-struct hid_field *hid_find_field_by_usage(struct hid_device *hid, __u32 wanted_usage, int type)
-{
- struct hid_report *report;
- int i;
-
- list_for_each_entry(report, &hid->report_enum[type].report_list, list)
- for (i = 0; i < report->maxfield; i++)
- if (report->field[i]->logical == wanted_usage)
- return report->field[i];
- return NULL;
-}
-#endif /* 0 */
-
static int hid_submit_out(struct hid_device *hid)
{
struct hid_report *report;
@@ -501,7 +484,7 @@ static int hid_get_class_descriptor(struct usb_device *dev, int ifnum,
{
int result, retries = 4;
- memset(buf,0,size); // Make sure we parse really received data
+ memset(buf, 0, size);
do {
result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
@@ -528,22 +511,11 @@ void usbhid_close(struct hid_device *hid)
usb_kill_urb(usbhid->urbin);
}
-static int hidinput_open(struct input_dev *dev)
-{
- struct hid_device *hid = dev->private;
- return usbhid_open(hid);
-}
-
-static void hidinput_close(struct input_dev *dev)
-{
- struct hid_device *hid = dev->private;
- usbhid_close(hid);
-}
-
#define USB_VENDOR_ID_PANJIT 0x134c
#define USB_VENDOR_ID_TURBOX 0x062a
#define USB_DEVICE_ID_TURBOX_KEYBOARD 0x0201
+#define USB_VENDOR_ID_CIDC 0x1677
/*
* Initialize all reports
@@ -577,7 +549,6 @@ void usbhid_init_reports(struct hid_device *hid)
}
#define USB_VENDOR_ID_GTCO 0x078c
-#define USB_VENDOR_ID_GTCO_IPANEL_2 0x5543
#define USB_DEVICE_ID_GTCO_90 0x0090
#define USB_DEVICE_ID_GTCO_100 0x0100
#define USB_DEVICE_ID_GTCO_101 0x0101
@@ -623,8 +594,6 @@ void usbhid_init_reports(struct hid_device *hid)
#define USB_DEVICE_ID_GTCO_1004 0x1004
#define USB_DEVICE_ID_GTCO_1005 0x1005
#define USB_DEVICE_ID_GTCO_1006 0x1006
-#define USB_DEVICE_ID_GTCO_8 0x0008
-#define USB_DEVICE_ID_GTCO_d 0x000d
#define USB_VENDOR_ID_WACOM 0x056a
@@ -770,6 +739,7 @@ void usbhid_init_reports(struct hid_device *hid)
#define USB_DEVICE_ID_APPLE_GEYSER4_JIS 0x021c
#define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY 0x030a
#define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY 0x030b
+#define USB_DEVICE_ID_APPLE_IR 0x8240
#define USB_VENDOR_ID_CHERRY 0x046a
#define USB_DEVICE_ID_CHERRY_CYMOTION 0x0023
@@ -792,6 +762,12 @@ void usbhid_init_reports(struct hid_device *hid)
#define USB_VENDOR_ID_IMATION 0x0718
#define USB_DEVICE_ID_DISC_STAKKA 0xd000
+#define USB_VENDOR_ID_PANTHERLORD 0x0810
+#define USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK 0x0001
+
+#define USB_VENDOR_ID_SONY 0x054c
+#define USB_DEVICE_ID_SONY_PS3_CONTROLLER 0x0268
+
/*
* Alphabetically sorted blacklist by quirk type.
*/
@@ -876,8 +852,6 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1004, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1005, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1006, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO_IPANEL_2, USB_DEVICE_ID_GTCO_8, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO_IPANEL_2, USB_DEVICE_ID_GTCO_d, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_IMATION, USB_DEVICE_ID_DISC_STAKKA, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_CASSY, HID_QUIRK_IGNORE },
@@ -946,19 +920,21 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION, HID_QUIRK_CYMOTION },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI, HID_QUIRK_POWERBOOK_HAS_FN },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO, HID_QUIRK_POWERBOOK_HAS_FN },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI, HID_QUIRK_POWERBOOK_HAS_FN },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS, HID_QUIRK_POWERBOOK_HAS_FN },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI, HID_QUIRK_POWERBOOK_HAS_FN },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS, HID_QUIRK_POWERBOOK_HAS_FN },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI, HID_QUIRK_POWERBOOK_HAS_FN },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_POWERBOOK_HAS_FN },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IR, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_PANJIT, 0x0001, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_PANJIT, 0x0002, HID_QUIRK_IGNORE },
@@ -969,6 +945,12 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_USB_RECEIVER, HID_QUIRK_BAD_RELATIVE_KEYS },
+ { USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS },
+
+ { USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER, HID_QUIRK_SONY_PS3_CONTROLLER },
+
+ { USB_VENDOR_ID_CIDC, 0x0103, HID_QUIRK_IGNORE },
+
{ 0, 0 }
};
@@ -1033,6 +1015,32 @@ static void hid_fixup_cymotion_descriptor(char *rdesc, int rsize)
}
}
+/*
+ * Sending HID_REQ_GET_REPORT changes the operation mode of the ps3 controller
+ * to "operational". Without this, the ps3 controller will not report any
+ * events.
+ */
+static void hid_fixup_sony_ps3_controller(struct usb_device *dev, int ifnum)
+{
+ int result;
+ char *buf = kmalloc(18, GFP_KERNEL);
+
+ if (!buf)
+ return;
+
+ result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ HID_REQ_GET_REPORT,
+ USB_DIR_IN | USB_TYPE_CLASS |
+ USB_RECIP_INTERFACE,
+ (3 << 8) | 0xf2, ifnum, buf, 17,
+ USB_CTRL_GET_TIMEOUT);
+
+ if (result < 0)
+ err("%s failed: %d\n", __func__, result);
+
+ kfree(buf);
+}
+
static struct hid_device *usb_hid_configure(struct usb_interface *intf)
{
struct usb_host_interface *interface = intf->cur_altsetting;
@@ -1064,6 +1072,11 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
if (quirks & HID_QUIRK_IGNORE)
return NULL;
+ if ((quirks & HID_QUIRK_IGNORE_MOUSE) &&
+ (interface->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE))
+ return NULL;
+
+
if (usb_get_extra_descriptor(interface, HID_DT_HID, &hdesc) &&
(!interface->desc.bNumEndpoints ||
usb_get_extra_descriptor(&interface->endpoint[0], HID_DT_HID, &hdesc))) {
@@ -1235,8 +1248,8 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
usbhid->urbctrl->transfer_dma = usbhid->ctrlbuf_dma;
usbhid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP);
hid->hidinput_input_event = usb_hidinput_input_event;
- hid->hidinput_open = hidinput_open;
- hid->hidinput_close = hidinput_close;
+ hid->hid_open = usbhid_open;
+ hid->hid_close = usbhid_close;
#ifdef CONFIG_USB_HIDDEV
hid->hiddev_hid_event = hiddev_hid_event;
hid->hiddev_report_event = hiddev_report_event;
@@ -1315,13 +1328,13 @@ static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id)
return -ENODEV;
}
- /* This only gets called when we are a single-input (most of the
- * time). IOW, not a HID_QUIRK_MULTI_INPUT. The hid_ff_init() is
- * only useful in this case, and not for multi-input quirks. */
- if ((hid->claimed & HID_CLAIMED_INPUT) &&
- !(hid->quirks & HID_QUIRK_MULTI_INPUT))
+ if ((hid->claimed & HID_CLAIMED_INPUT))
hid_ff_init(hid);
+ if (hid->quirks & HID_QUIRK_SONY_PS3_CONTROLLER)
+ hid_fixup_sony_ps3_controller(interface_to_usbdev(intf),
+ intf->cur_altsetting->desc.bInterfaceNumber);
+
printk(KERN_INFO);
if (hid->claimed & HID_CLAIMED_INPUT)
diff --git a/drivers/usb/input/hid-ff.c b/drivers/usb/input/hid-ff.c
index 59ed65e7a62..e431faaa6ab 100644
--- a/drivers/usb/input/hid-ff.c
+++ b/drivers/usb/input/hid-ff.c
@@ -54,9 +54,14 @@ struct hid_ff_initializer {
static struct hid_ff_initializer inits[] = {
#ifdef CONFIG_LOGITECH_FF
{ 0x46d, 0xc211, hid_lgff_init }, /* Logitech Cordless rumble pad */
+ { 0x46d, 0xc219, hid_lgff_init }, /* Logitech Cordless rumble pad 2 */
{ 0x46d, 0xc283, hid_lgff_init }, /* Logitech Wingman Force 3d */
+ { 0x46d, 0xc294, hid_lgff_init }, /* Logitech Formula Force EX */
{ 0x46d, 0xc295, hid_lgff_init }, /* Logitech MOMO force wheel */
- { 0x46d, 0xc219, hid_lgff_init }, /* Logitech Cordless rumble pad 2 */
+ { 0x46d, 0xca03, hid_lgff_init }, /* Logitech MOMO force wheel */
+#endif
+#ifdef CONFIG_PANTHERLORD_FF
+ { 0x810, 0x0001, hid_plff_init },
#endif
#ifdef CONFIG_THRUSTMASTER_FF
{ 0x44f, 0xb304, hid_tmff_init },
diff --git a/drivers/usb/input/hid-lgff.c b/drivers/usb/input/hid-lgff.c
index e4746626856..e6f3af3e66d 100644
--- a/drivers/usb/input/hid-lgff.c
+++ b/drivers/usb/input/hid-lgff.c
@@ -32,7 +32,7 @@
#include <linux/hid.h>
#include "usbhid.h"
-struct device_type {
+struct dev_type {
u16 idVendor;
u16 idProduct;
const signed short *ff;
@@ -48,11 +48,13 @@ static const signed short ff_joystick[] = {
-1
};
-static const struct device_type devices[] = {
+static const struct dev_type devices[] = {
{ 0x046d, 0xc211, ff_rumble },
{ 0x046d, 0xc219, ff_rumble },
{ 0x046d, 0xc283, ff_joystick },
- { 0x0000, 0x0000, ff_joystick }
+ { 0x046d, 0xc294, ff_joystick },
+ { 0x046d, 0xc295, ff_joystick },
+ { 0x046d, 0xca03, ff_joystick },
};
static int hid_lgff_play(struct input_dev *dev, void *data, struct ff_effect *effect)
@@ -104,8 +106,9 @@ int hid_lgff_init(struct hid_device* hid)
struct input_dev *dev = hidinput->input;
struct hid_report *report;
struct hid_field *field;
+ const signed short *ff_bits = ff_joystick;
int error;
- int i, j;
+ int i;
/* Find the report to use */
if (list_empty(report_list)) {
@@ -129,12 +132,14 @@ int hid_lgff_init(struct hid_device* hid)
for (i = 0; i < ARRAY_SIZE(devices); i++) {
if (dev->id.vendor == devices[i].idVendor &&
dev->id.product == devices[i].idProduct) {
- for (j = 0; devices[i].ff[j] >= 0; j++)
- set_bit(devices[i].ff[j], dev->ffbit);
+ ff_bits = devices[i].ff;
break;
}
}
+ for (i = 0; ff_bits[i] >= 0; i++)
+ set_bit(ff_bits[i], dev->ffbit);
+
error = input_ff_create_memless(dev, NULL, hid_lgff_play);
if (error)
return error;
diff --git a/drivers/usb/input/hid-pidff.c b/drivers/usb/input/hid-pidff.c
index cbd2d53feff..f5a90e950e6 100644
--- a/drivers/usb/input/hid-pidff.c
+++ b/drivers/usb/input/hid-pidff.c
@@ -24,7 +24,6 @@
#define debug(format, arg...) pr_debug("hid-pidff: " format "\n" , ## arg)
-#include <linux/sched.h>
#include <linux/input.h>
#include <linux/usb.h>
diff --git a/drivers/usb/input/hid-plff.c b/drivers/usb/input/hid-plff.c
new file mode 100644
index 00000000000..76d2e6e14db
--- /dev/null
+++ b/drivers/usb/input/hid-plff.c
@@ -0,0 +1,129 @@
+/*
+ * Force feedback support for PantherLord USB/PS2 2in1 Adapter devices
+ *
+ * Copyright (c) 2007 Anssi Hannula <anssi.hannula@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
+ */
+
+
+/* #define DEBUG */
+
+#define debug(format, arg...) pr_debug("hid-plff: " format "\n" , ## arg)
+
+#include <linux/input.h>
+#include <linux/usb.h>
+#include <linux/hid.h>
+#include "usbhid.h"
+
+struct plff_device {
+ struct hid_report *report;
+};
+
+static int hid_plff_play(struct input_dev *dev, void *data,
+ struct ff_effect *effect)
+{
+ struct hid_device *hid = dev->private;
+ struct plff_device *plff = data;
+ int left, right;
+
+ left = effect->u.rumble.strong_magnitude;
+ right = effect->u.rumble.weak_magnitude;
+ debug("called with 0x%04x 0x%04x", left, right);
+
+ left = left * 0x7f / 0xffff;
+ right = right * 0x7f / 0xffff;
+
+ plff->report->field[0]->value[2] = left;
+ plff->report->field[0]->value[3] = right;
+ debug("running with 0x%02x 0x%02x", left, right);
+ usbhid_submit_report(hid, plff->report, USB_DIR_OUT);
+
+ return 0;
+}
+
+int hid_plff_init(struct hid_device *hid)
+{
+ struct plff_device *plff;
+ struct hid_report *report;
+ struct hid_input *hidinput;
+ struct list_head *report_list =
+ &hid->report_enum[HID_OUTPUT_REPORT].report_list;
+ struct list_head *report_ptr = report_list;
+ struct input_dev *dev;
+ int error;
+
+ /* The device contains 2 output reports (one for each
+ HID_QUIRK_MULTI_INPUT device), both containing 1 field, which
+ contains 4 ff00.0002 usages and 4 16bit absolute values.
+
+ The 2 input reports also contain a field which contains
+ 8 ff00.0001 usages and 8 boolean values. Their meaning is
+ currently unknown. */
+
+ if (list_empty(report_list)) {
+ printk(KERN_ERR "hid-plff: no output reports found\n");
+ return -ENODEV;
+ }
+
+ list_for_each_entry(hidinput, &hid->inputs, list) {
+
+ report_ptr = report_ptr->next;
+
+ if (report_ptr == report_list) {
+ printk(KERN_ERR "hid-plff: required output report is missing\n");
+ return -ENODEV;
+ }
+
+ report = list_entry(report_ptr, struct hid_report, list);
+ if (report->maxfield < 1) {
+ printk(KERN_ERR "hid-plff: no fields in the report\n");
+ return -ENODEV;
+ }
+
+ if (report->field[0]->report_count < 4) {
+ printk(KERN_ERR "hid-plff: not enough values in the field\n");
+ return -ENODEV;
+ }
+
+ plff = kzalloc(sizeof(struct plff_device), GFP_KERNEL);
+ if (!plff)
+ return -ENOMEM;
+
+ dev = hidinput->input;
+
+ set_bit(FF_RUMBLE, dev->ffbit);
+
+ error = input_ff_create_memless(dev, plff, hid_plff_play);
+ if (error) {
+ kfree(plff);
+ return error;
+ }
+
+ plff->report = report;
+ plff->report->field[0]->value[0] = 0x00;
+ plff->report->field[0]->value[1] = 0x00;
+ plff->report->field[0]->value[2] = 0x00;
+ plff->report->field[0]->value[3] = 0x00;
+ usbhid_submit_report(hid, plff->report, USB_DIR_OUT);
+ }
+
+ printk(KERN_INFO "hid-plff: Force feedback for PantherLord USB/PS2 "
+ "2in1 Adapters by Anssi Hannula <anssi.hannula@gmail.com>\n");
+
+ return 0;
+}
diff --git a/drivers/usb/input/usbkbd.c b/drivers/usb/input/usbkbd.c
index 8505824848f..3749f4a235f 100644
--- a/drivers/usb/input/usbkbd.c
+++ b/drivers/usb/input/usbkbd.c
@@ -31,6 +31,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/usb/input.h>
+#include <linux/hid.h>
/*
* Version Information
@@ -330,7 +331,8 @@ static void usb_kbd_disconnect(struct usb_interface *intf)
}
static struct usb_device_id usb_kbd_id_table [] = {
- { USB_INTERFACE_INFO(3, 1, 1) },
+ { USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
+ USB_INTERFACE_PROTOCOL_KEYBOARD) },
{ } /* Terminating entry */
};
diff --git a/drivers/usb/input/usbmouse.c b/drivers/usb/input/usbmouse.c
index 64a33e420cf..692fd608777 100644
--- a/drivers/usb/input/usbmouse.c
+++ b/drivers/usb/input/usbmouse.c
@@ -31,6 +31,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/usb/input.h>
+#include <linux/hid.h>
/*
* Version Information
@@ -213,7 +214,8 @@ static void usb_mouse_disconnect(struct usb_interface *intf)
}
static struct usb_device_id usb_mouse_id_table [] = {
- { USB_INTERFACE_INFO(3, 1, 2) },
+ { USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
+ USB_INTERFACE_PROTOCOL_MOUSE) },
{ } /* Terminating entry */
};
diff --git a/drivers/usb/input/wacom_wac.c b/drivers/usb/input/wacom_wac.c
index 4142e36730f..4f3e9bc7177 100644
--- a/drivers/usb/input/wacom_wac.c
+++ b/drivers/usb/input/wacom_wac.c
@@ -163,7 +163,7 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo)
}
id = STYLUS_DEVICE_ID;
- if (data[1] & 0x10) { /* in prox */
+ if (data[1] & 0x80) { /* in prox */
switch ((data[1] >> 5) & 3) {
@@ -196,9 +196,6 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo)
wacom_report_abs(wcombo, ABS_DISTANCE, data[7] & 0x3f);
break;
}
- }
-
- if (data[1] & 0x90) {
x = wacom_le16_to_cpu(&data[2]);
y = wacom_le16_to_cpu(&data[4]);
wacom_report_abs(wcombo, ABS_X, x);
@@ -210,19 +207,28 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo)
wacom_report_key(wcombo, BTN_STYLUS2, data[1] & 0x04);
}
wacom_report_abs(wcombo, ABS_MISC, id); /* report tool id */
- }
- else
- wacom_report_abs(wcombo, ABS_MISC, 0); /* reset tool id */
-
- if (data[1] & 0x10) /* only report prox-in when in area */
wacom_report_key(wcombo, wacom->tool[0], 1);
- if (!(data[1] & 0x90)) /* report prox-out when physically out */
+ } else if (!(data[1] & 0x90)) {
+ 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_abs(wcombo, ABS_MISC, 0); /* reset tool id */
wacom_report_key(wcombo, wacom->tool[0], 0);
- wacom_input_sync(wcombo);
+ }
/* send pad data */
if (wacom->features->type == WACOM_G4) {
- if ( (wacom->serial[1] & 0xc0) != (data[7] & 0xf8) ) {
+ if (data[7] & 0xf8) {
+ wacom_input_sync(wcombo); /* sync last event */
wacom->id[1] = 1;
wacom->serial[1] = (data[7] & 0xf8);
wacom_report_key(wcombo, BTN_0, (data[7] & 0x40));
@@ -230,10 +236,15 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo)
rw = ((data[7] & 0x18) >> 3) - ((data[7] & 0x20) >> 3);
wacom_report_rel(wcombo, REL_WHEEL, rw);
wacom_report_key(wcombo, BTN_TOOL_FINGER, 0xf0);
+ wacom_report_abs(wcombo, ABS_MISC, PAD_DEVICE_ID);
wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xf0);
} else if (wacom->id[1]) {
+ wacom_input_sync(wcombo); /* sync last event */
wacom->id[1] = 0;
+ wacom_report_key(wcombo, BTN_0, (data[7] & 0x40));
+ wacom_report_key(wcombo, BTN_4, (data[7] & 0x80));
wacom_report_key(wcombo, BTN_TOOL_FINGER, 0);
+ wacom_report_abs(wcombo, ABS_MISC, 0);
wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xf0);
}
}
@@ -304,28 +315,35 @@ static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo)
default: /* Unknown tool */
wacom->tool[idx] = BTN_TOOL_PEN;
}
- /* only large I3 support Lens Cursor */
- if(!((wacom->tool[idx] == BTN_TOOL_LENS)
- && ((wacom->features->type == INTUOS3)
- || (wacom->features->type == INTUOS3S)))) {
- wacom_report_abs(wcombo, ABS_MISC, wacom->id[idx]); /* report tool id */
- wacom_report_key(wcombo, wacom->tool[idx], 1);
- wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
- return 2;
- }
return 1;
}
/* Exit report */
if ((data[1] & 0xfe) == 0x80) {
- if(!((wacom->tool[idx] == BTN_TOOL_LENS)
- && ((wacom->features->type == INTUOS3)
- || (wacom->features->type == INTUOS3S)))) {
- wacom_report_key(wcombo, wacom->tool[idx], 0);
- wacom_report_abs(wcombo, ABS_MISC, 0); /* reset tool id */
- wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
- return 2;
+ wacom_report_abs(wcombo, ABS_X, 0);
+ wacom_report_abs(wcombo, ABS_Y, 0);
+ wacom_report_abs(wcombo, ABS_DISTANCE, 0);
+ if (wacom->tool[idx] >= BTN_TOOL_MOUSE) {
+ wacom_report_key(wcombo, BTN_LEFT, 0);
+ wacom_report_key(wcombo, BTN_MIDDLE, 0);
+ wacom_report_key(wcombo, BTN_RIGHT, 0);
+ wacom_report_key(wcombo, BTN_SIDE, 0);
+ wacom_report_key(wcombo, BTN_EXTRA, 0);
+ wacom_report_abs(wcombo, ABS_THROTTLE, 0);
+ wacom_report_abs(wcombo, ABS_RZ, 0);
+ } else {
+ wacom_report_abs(wcombo, ABS_PRESSURE, 0);
+ wacom_report_abs(wcombo, ABS_TILT_X, 0);
+ wacom_report_abs(wcombo, ABS_TILT_Y, 0);
+ wacom_report_key(wcombo, BTN_STYLUS, 0);
+ wacom_report_key(wcombo, BTN_STYLUS2, 0);
+ wacom_report_key(wcombo, BTN_TOUCH, 0);
+ wacom_report_abs(wcombo, ABS_WHEEL, 0);
}
+ wacom_report_key(wcombo, wacom->tool[idx], 0);
+ wacom_report_abs(wcombo, ABS_MISC, 0); /* reset tool id */
+ wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
+ return 2;
}
return 0;
}
@@ -394,6 +412,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
wacom_report_key(wcombo, wacom->tool[1], 1);
else
wacom_report_key(wcombo, wacom->tool[1], 0);
+ wacom_report_abs(wcombo, ABS_MISC, PAD_DEVICE_ID);
wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xffffffff);
return 1;
}
@@ -403,6 +422,12 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
if (result)
return result-1;
+ /* Only large I3 and I1 & I2 support Lense Cursor */
+ if((wacom->tool[idx] == BTN_TOOL_LENS)
+ && ((wacom->features->type == INTUOS3)
+ || (wacom->features->type == INTUOS3S)))
+ return 0;
+
/* Cintiq doesn't send data when RDY bit isn't set */
if ((wacom->features->type == CINTIQ) && !(data[1] & 0x40))
return 0;
@@ -554,11 +579,11 @@ static struct wacom_features wacom_features[] = {
{ "Wacom Volito2 4x5", 8, 5104, 3712, 511, 63, GRAPHIRE },
{ "Wacom Volito2 2x3", 8, 3248, 2320, 511, 63, GRAPHIRE },
{ "Wacom PenPartner2", 8, 3250, 2320, 255, 63, GRAPHIRE },
- { "Wacom Intuos 4x5", 10, 12700, 10600, 1023, 63, INTUOS },
- { "Wacom Intuos 6x8", 10, 20320, 16240, 1023, 63, INTUOS },
- { "Wacom Intuos 9x12", 10, 30480, 24060, 1023, 63, INTUOS },
- { "Wacom Intuos 12x12", 10, 30480, 31680, 1023, 63, INTUOS },
- { "Wacom Intuos 12x18", 10, 45720, 31680, 1023, 63, INTUOS },
+ { "Wacom Intuos 4x5", 10, 12700, 10600, 1023, 31, INTUOS },
+ { "Wacom Intuos 6x8", 10, 20320, 16240, 1023, 31, INTUOS },
+ { "Wacom Intuos 9x12", 10, 30480, 24060, 1023, 31, INTUOS },
+ { "Wacom Intuos 12x12", 10, 30480, 31680, 1023, 31, INTUOS },
+ { "Wacom Intuos 12x18", 10, 45720, 31680, 1023, 31, INTUOS },
{ "Wacom PL400", 8, 5408, 4056, 255, 0, PL },
{ "Wacom PL500", 8, 6144, 4608, 255, 0, PL },
{ "Wacom PL600", 8, 6126, 4604, 255, 0, PL },
@@ -571,11 +596,11 @@ static struct wacom_features wacom_features[] = {
{ "Wacom DTF521", 8, 6282, 4762, 511, 0, PL },
{ "Wacom DTF720", 8, 6858, 5506, 511, 0, PL },
{ "Wacom Cintiq Partner",8, 20480, 15360, 511, 0, PTU },
- { "Wacom Intuos2 4x5", 10, 12700, 10600, 1023, 63, INTUOS },
- { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 63, INTUOS },
- { "Wacom Intuos2 9x12", 10, 30480, 24060, 1023, 63, INTUOS },
- { "Wacom Intuos2 12x12", 10, 30480, 31680, 1023, 63, INTUOS },
- { "Wacom Intuos2 12x18", 10, 45720, 31680, 1023, 63, INTUOS },
+ { "Wacom Intuos2 4x5", 10, 12700, 10600, 1023, 31, INTUOS },
+ { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 31, INTUOS },
+ { "Wacom Intuos2 9x12", 10, 30480, 24060, 1023, 31, INTUOS },
+ { "Wacom Intuos2 12x12", 10, 30480, 31680, 1023, 31, INTUOS },
+ { "Wacom Intuos2 12x18", 10, 45720, 31680, 1023, 31, INTUOS },
{ "Wacom Intuos3 4x5", 10, 25400, 20320, 1023, 63, INTUOS3S },
{ "Wacom Intuos3 6x8", 10, 40640, 30480, 1023, 63, INTUOS3 },
{ "Wacom Intuos3 9x12", 10, 60960, 45720, 1023, 63, INTUOS3 },
@@ -584,7 +609,7 @@ static struct wacom_features wacom_features[] = {
{ "Wacom Intuos3 6x11", 10, 54204, 31750, 1023, 63, INTUOS3 },
{ "Wacom Intuos3 4x6", 10, 31496, 19685, 1023, 63, INTUOS3S },
{ "Wacom Cintiq 21UX", 10, 87200, 65600, 1023, 63, CINTIQ },
- { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 63, INTUOS },
+ { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 31, INTUOS },
{ }
};
diff --git a/drivers/usb/input/wacom_wac.h b/drivers/usb/input/wacom_wac.h
index a1d9ce00797..a2302228724 100644
--- a/drivers/usb/input/wacom_wac.h
+++ b/drivers/usb/input/wacom_wac.h
@@ -12,6 +12,7 @@
#define STYLUS_DEVICE_ID 0x02
#define CURSOR_DEVICE_ID 0x06
#define ERASER_DEVICE_ID 0x0A
+#define PAD_DEVICE_ID 0x0F
enum {
PENPARTNER = 0,
diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig
index a74bf8617e7..9c7eb6144d0 100644
--- a/drivers/usb/misc/Kconfig
+++ b/drivers/usb/misc/Kconfig
@@ -88,6 +88,17 @@ 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
@@ -233,6 +244,20 @@ config USB_TRANCEVIBRATOR
To compile this driver as a module, choose M here: the
module will be called trancevibrator.
+config USB_IOWARRIOR
+ tristate "IO Warrior driver support"
+ depends on USB
+ help
+ Say Y here if you want to support the IO Warrior devices from Code
+ Mercenaries. This includes support for the following devices:
+ IO Warrior 40
+ IO Warrior 24
+ IO Warrior 56
+ IO Warrior 24 Power Vampire
+
+ To compile this driver as a module, choose M here: the
+ module will be called iowarrior.
+
config USB_TEST
tristate "USB testing driver (DEVELOPMENT)"
depends on USB && USB_DEVICEFS && EXPERIMENTAL
diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile
index 2cba07d3197..b68e6b774f1 100644
--- a/drivers/usb/misc/Makefile
+++ b/drivers/usb/misc/Makefile
@@ -6,12 +6,14 @@
obj-$(CONFIG_USB_ADUTUX) += adutux.o
obj-$(CONFIG_USB_APPLEDISPLAY) += appledisplay.o
obj-$(CONFIG_USB_AUERSWALD) += auerswald.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
obj-$(CONFIG_USB_EMI62) += emi62.o
obj-$(CONFIG_USB_FTDI_ELAN) += ftdi-elan.o
obj-$(CONFIG_USB_IDMOUSE) += idmouse.o
+obj-$(CONFIG_USB_IOWARRIOR) += iowarrior.o
obj-$(CONFIG_USB_LCD) += usblcd.o
obj-$(CONFIG_USB_LD) += ldusb.o
obj-$(CONFIG_USB_LED) += usbled.o
diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c
index af2934e016a..75bfab95ab3 100644
--- a/drivers/usb/misc/adutux.c
+++ b/drivers/usb/misc/adutux.c
@@ -644,7 +644,7 @@ exit:
}
/* file operations needed when we register this driver */
-static struct file_operations adu_fops = {
+static const struct file_operations adu_fops = {
.owner = THIS_MODULE,
.read = adu_read,
.write = adu_write,
diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c
index a7932a72d29..cf70c16f0e3 100644
--- a/drivers/usb/misc/appledisplay.c
+++ b/drivers/usb/misc/appledisplay.c
@@ -141,7 +141,7 @@ static int appledisplay_bl_update_status(struct backlight_device *bd)
int retval;
pdata->msgdata[0] = 0x10;
- pdata->msgdata[1] = bd->props->brightness;
+ pdata->msgdata[1] = bd->props.brightness;
retval = usb_control_msg(
pdata->udev,
@@ -177,11 +177,9 @@ static int appledisplay_bl_get_brightness(struct backlight_device *bd)
return pdata->msgdata[1];
}
-static struct backlight_properties appledisplay_bl_data = {
- .owner = THIS_MODULE,
+static struct backlight_ops appledisplay_bl_data = {
.get_brightness = appledisplay_bl_get_brightness,
.update_status = appledisplay_bl_update_status,
- .max_brightness = 0xFF
};
static void appledisplay_work(struct work_struct *work)
@@ -190,11 +188,9 @@ static void appledisplay_work(struct work_struct *work)
container_of(work, struct appledisplay, work.work);
int retval;
- up(&pdata->bd->sem);
retval = appledisplay_bl_get_brightness(pdata->bd);
if (retval >= 0)
- pdata->bd->props->brightness = retval;
- down(&pdata->bd->sem);
+ pdata->bd->props.brightness = retval;
/* Poll again in about 125ms if there's still a button pressed */
if (pdata->button_pressed)
@@ -281,17 +277,17 @@ static int appledisplay_probe(struct usb_interface *iface,
/* Register backlight device */
snprintf(bl_name, sizeof(bl_name), "appledisplay%d",
atomic_inc_return(&count_displays) - 1);
- pdata->bd = backlight_device_register(bl_name, NULL, NULL,
+ pdata->bd = backlight_device_register(bl_name, NULL, pdata,
&appledisplay_bl_data);
if (IS_ERR(pdata->bd)) {
err("appledisplay: Backlight registration failed");
goto error;
}
+ pdata->bd->props.max_brightness = 0xff;
+
/* Try to get brightness */
- up(&pdata->bd->sem);
brightness = appledisplay_bl_get_brightness(pdata->bd);
- down(&pdata->bd->sem);
if (brightness < 0) {
retval = brightness;
@@ -300,9 +296,7 @@ static int appledisplay_probe(struct usb_interface *iface,
}
/* Set brightness in backlight device */
- up(&pdata->bd->sem);
- pdata->bd->props->brightness = brightness;
- down(&pdata->bd->sem);
+ pdata->bd->props.brightness = brightness;
/* save our data pointer in the interface device */
usb_set_intfdata(iface, pdata);
diff --git a/drivers/usb/misc/berry_charge.c b/drivers/usb/misc/berry_charge.c
new file mode 100644
index 00000000000..60893c6c822
--- /dev/null
+++ b/drivers/usb/misc/berry_charge.c
@@ -0,0 +1,140 @@
+/*
+ * 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
+
+static int debug;
+
+#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) },
+ { }, /* 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);
+ return retval;
+ }
+
+ dbg(&udev->dev, "Sending first 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);
+ return 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);
+
+ return retval;
+}
+
+static int berry_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct usb_device *udev = interface_to_usbdev(intf);
+
+ 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);
+
+ /* 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");
diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c
index 41c0161abdb..0c1d66ddb81 100644
--- a/drivers/usb/misc/ftdi-elan.c
+++ b/drivers/usb/misc/ftdi-elan.c
@@ -1209,7 +1209,7 @@ error_1:
return retval;
}
-static struct file_operations ftdi_elan_fops = {
+static const struct file_operations ftdi_elan_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.ioctl = ftdi_elan_ioctl,
diff --git a/drivers/usb/misc/idmouse.c b/drivers/usb/misc/idmouse.c
index c9418535bef..15c70bd048c 100644
--- a/drivers/usb/misc/idmouse.c
+++ b/drivers/usb/misc/idmouse.c
@@ -269,7 +269,7 @@ static int idmouse_release(struct inode *inode, struct file *file)
/* prevent a race condition with open() */
mutex_lock(&disconnect_mutex);
- dev = (struct usb_idmouse *) file->private_data;
+ dev = file->private_data;
if (dev == NULL) {
mutex_unlock(&disconnect_mutex);
@@ -304,17 +304,15 @@ static int idmouse_release(struct inode *inode, struct file *file)
static ssize_t idmouse_read(struct file *file, char __user *buffer, size_t count,
loff_t * ppos)
{
- struct usb_idmouse *dev;
+ struct usb_idmouse *dev = file->private_data;
int result;
- dev = (struct usb_idmouse *) file->private_data;
-
/* lock this object */
- down (&dev->sem);
+ down(&dev->sem);
/* verify that the device wasn't unplugged */
if (!dev->present) {
- up (&dev->sem);
+ up(&dev->sem);
return -ENODEV;
}
diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c
new file mode 100644
index 00000000000..d69665c8de0
--- /dev/null
+++ b/drivers/usb/misc/iowarrior.c
@@ -0,0 +1,925 @@
+/*
+ * Native support for the I/O-Warrior USB devices
+ *
+ * Copyright (c) 2003-2005 Code Mercenaries GmbH
+ * written by Christian Lucht <lucht@codemercs.com>
+ *
+ * based on
+
+ * usb-skeleton.c by Greg Kroah-Hartman <greg@kroah.com>
+ * brlvger.c by Stephane Dalton <sdalton@videotron.ca>
+ * and St�hane Doyon <s.doyon@videotron.ca>
+ *
+ * Released under the GPLv2.
+ */
+
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/poll.h>
+#include <linux/version.h>
+#include <linux/usb/iowarrior.h>
+
+/* Version Information */
+#define DRIVER_VERSION "v0.4.0"
+#define DRIVER_AUTHOR "Christian Lucht <lucht@codemercs.com>"
+#define DRIVER_DESC "USB IO-Warrior driver (Linux 2.6.x)"
+
+#define USB_VENDOR_ID_CODEMERCS 1984
+/* low speed iowarrior */
+#define USB_DEVICE_ID_CODEMERCS_IOW40 0x1500
+#define USB_DEVICE_ID_CODEMERCS_IOW24 0x1501
+#define USB_DEVICE_ID_CODEMERCS_IOWPV1 0x1511
+#define USB_DEVICE_ID_CODEMERCS_IOWPV2 0x1512
+/* full speed iowarrior */
+#define USB_DEVICE_ID_CODEMERCS_IOW56 0x1503
+
+/* Get a minor range for your devices from the usb maintainer */
+#ifdef CONFIG_USB_DYNAMIC_MINORS
+#define IOWARRIOR_MINOR_BASE 0
+#else
+#define IOWARRIOR_MINOR_BASE 208 // SKELETON_MINOR_BASE 192 + 16, not offical yet
+#endif
+
+/* interrupt input queue size */
+#define MAX_INTERRUPT_BUFFER 16
+/*
+ maximum number of urbs that are submitted for writes at the same time,
+ this applies to the IOWarrior56 only!
+ IOWarrior24 and IOWarrior40 use synchronous usb_control_msg calls.
+*/
+#define MAX_WRITES_IN_FLIGHT 4
+
+/* Use our own dbg macro */
+#undef dbg
+#define dbg( format, arg... ) do { if( debug ) printk( KERN_DEBUG __FILE__ ": " format "\n" , ## arg ); } while ( 0 )
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+/* Module parameters */
+static int debug = 0;
+module_param(debug, bool, 0644);
+MODULE_PARM_DESC(debug, "debug=1 enables debugging messages");
+
+static struct usb_driver iowarrior_driver;
+
+/*--------------*/
+/* data */
+/*--------------*/
+
+/* Structure to hold all of our device specific stuff */
+struct iowarrior {
+ struct mutex mutex; /* locks this structure */
+ struct usb_device *udev; /* save off the usb device pointer */
+ struct usb_interface *interface; /* the interface for this device */
+ unsigned char minor; /* the starting minor number for this device */
+ struct usb_endpoint_descriptor *int_out_endpoint; /* endpoint for reading (needed for IOW56 only) */
+ struct usb_endpoint_descriptor *int_in_endpoint; /* endpoint for reading */
+ struct urb *int_in_urb; /* the urb for reading data */
+ unsigned char *int_in_buffer; /* buffer for data to be read */
+ unsigned char serial_number; /* to detect lost packages */
+ unsigned char *read_queue; /* size is MAX_INTERRUPT_BUFFER * packet size */
+ wait_queue_head_t read_wait;
+ wait_queue_head_t write_wait; /* wait-queue for writing to the device */
+ atomic_t write_busy; /* number of write-urbs submitted */
+ atomic_t read_idx;
+ atomic_t intr_idx;
+ spinlock_t intr_idx_lock; /* protects intr_idx */
+ atomic_t overflow_flag; /* signals an index 'rollover' */
+ int present; /* this is 1 as long as the device is connected */
+ int opened; /* this is 1 if the device is currently open */
+ char chip_serial[9]; /* the serial number string of the chip connected */
+ int report_size; /* number of bytes in a report */
+ u16 product_id;
+};
+
+/*--------------*/
+/* globals */
+/*--------------*/
+/* prevent races between open() and disconnect() */
+static DECLARE_MUTEX(disconnect_sem);
+
+/*
+ * USB spec identifies 5 second timeouts.
+ */
+#define GET_TIMEOUT 5
+#define USB_REQ_GET_REPORT 0x01
+//#if 0
+static int usb_get_report(struct usb_device *dev,
+ struct usb_host_interface *inter, unsigned char type,
+ unsigned char id, void *buf, int size)
+{
+ return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ USB_REQ_GET_REPORT,
+ USB_DIR_IN | USB_TYPE_CLASS |
+ USB_RECIP_INTERFACE, (type << 8) + id,
+ inter->desc.bInterfaceNumber, buf, size,
+ GET_TIMEOUT);
+}
+//#endif
+
+#define USB_REQ_SET_REPORT 0x09
+
+static int usb_set_report(struct usb_interface *intf, unsigned char type,
+ unsigned char id, void *buf, int size)
+{
+ return usb_control_msg(interface_to_usbdev(intf),
+ usb_sndctrlpipe(interface_to_usbdev(intf), 0),
+ USB_REQ_SET_REPORT,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ (type << 8) + id,
+ intf->cur_altsetting->desc.bInterfaceNumber, buf,
+ size, 1);
+}
+
+/*---------------------*/
+/* driver registration */
+/*---------------------*/
+/* table of devices that work with this driver */
+static 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)},
+ {USB_DEVICE(USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOWPV2)},
+ {USB_DEVICE(USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW56)},
+ {} /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, iowarrior_ids);
+
+/*
+ * USB callback handler for reading data
+ */
+static void iowarrior_callback(struct urb *urb)
+{
+ struct iowarrior *dev = (struct iowarrior *)urb->context;
+ int intr_idx;
+ int read_idx;
+ int aux_idx;
+ int offset;
+ int status;
+
+ switch (urb->status) {
+ case 0:
+ /* success */
+ break;
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ return;
+ default:
+ goto exit;
+ }
+
+ spin_lock(&dev->intr_idx_lock);
+ intr_idx = atomic_read(&dev->intr_idx);
+ /* aux_idx become previous intr_idx */
+ aux_idx = (intr_idx == 0) ? (MAX_INTERRUPT_BUFFER - 1) : (intr_idx - 1);
+ read_idx = atomic_read(&dev->read_idx);
+
+ /* queue is not empty and it's interface 0 */
+ if ((intr_idx != read_idx)
+ && (dev->interface->cur_altsetting->desc.bInterfaceNumber == 0)) {
+ /* + 1 for serial number */
+ offset = aux_idx * (dev->report_size + 1);
+ if (!memcmp
+ (dev->read_queue + offset, urb->transfer_buffer,
+ dev->report_size)) {
+ /* equal values on interface 0 will be ignored */
+ spin_unlock(&dev->intr_idx_lock);
+ goto exit;
+ }
+ }
+
+ /* aux_idx become next intr_idx */
+ aux_idx = (intr_idx == (MAX_INTERRUPT_BUFFER - 1)) ? 0 : (intr_idx + 1);
+ if (read_idx == aux_idx) {
+ /* queue full, dropping oldest input */
+ read_idx = (++read_idx == MAX_INTERRUPT_BUFFER) ? 0 : read_idx;
+ atomic_set(&dev->read_idx, read_idx);
+ atomic_set(&dev->overflow_flag, 1);
+ }
+
+ /* +1 for serial number */
+ offset = intr_idx * (dev->report_size + 1);
+ memcpy(dev->read_queue + offset, urb->transfer_buffer,
+ dev->report_size);
+ *(dev->read_queue + offset + (dev->report_size)) = dev->serial_number++;
+
+ atomic_set(&dev->intr_idx, aux_idx);
+ spin_unlock(&dev->intr_idx_lock);
+ /* tell the blocking read about the new data */
+ wake_up_interruptible(&dev->read_wait);
+
+exit:
+ status = usb_submit_urb(urb, GFP_ATOMIC);
+ if (status)
+ dev_err(&dev->interface->dev, "%s - usb_submit_urb failed with result %d",
+ __FUNCTION__, status);
+
+}
+
+/*
+ * USB Callback handler for write-ops
+ */
+static void iowarrior_write_callback(struct urb *urb)
+{
+ struct iowarrior *dev;
+ dev = (struct iowarrior *)urb->context;
+ /* sync/async unlink faults aren't errors */
+ if (urb->status &&
+ !(urb->status == -ENOENT ||
+ urb->status == -ECONNRESET || urb->status == -ESHUTDOWN)) {
+ dbg("%s - nonzero write bulk status received: %d",
+ __func__, urb->status);
+ }
+ /* free up our allocated buffer */
+ usb_buffer_free(urb->dev, urb->transfer_buffer_length,
+ urb->transfer_buffer, urb->transfer_dma);
+ /* tell a waiting writer the interrupt-out-pipe is available again */
+ atomic_dec(&dev->write_busy);
+ wake_up_interruptible(&dev->write_wait);
+}
+
+/**
+ * iowarrior_delete
+ */
+static inline void iowarrior_delete(struct iowarrior *dev)
+{
+ dbg("%s - minor %d", __func__, dev->minor);
+ kfree(dev->int_in_buffer);
+ usb_free_urb(dev->int_in_urb);
+ kfree(dev->read_queue);
+ kfree(dev);
+}
+
+/*---------------------*/
+/* fops implementation */
+/*---------------------*/
+
+static int read_index(struct iowarrior *dev)
+{
+ int intr_idx, read_idx;
+
+ read_idx = atomic_read(&dev->read_idx);
+ intr_idx = atomic_read(&dev->intr_idx);
+
+ return (read_idx == intr_idx ? -1 : read_idx);
+}
+
+/**
+ * iowarrior_read
+ */
+static ssize_t iowarrior_read(struct file *file, char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ struct iowarrior *dev;
+ int read_idx;
+ int offset;
+
+ dev = (struct iowarrior *)file->private_data;
+
+ /* verify that the device wasn't unplugged */
+ if (dev == NULL || !dev->present)
+ return -ENODEV;
+
+ dbg("%s - minor %d, count = %zd", __func__, dev->minor, count);
+
+ /* read count must be packet size (+ time stamp) */
+ if ((count != dev->report_size)
+ && (count != (dev->report_size + 1)))
+ return -EINVAL;
+
+ /* repeat until no buffer overrun in callback handler occur */
+ do {
+ atomic_set(&dev->overflow_flag, 0);
+ if ((read_idx = read_index(dev)) == -1) {
+ /* queue emty */
+ if (file->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+ else {
+ //next line will return when there is either new data, or the device is unplugged
+ int r = wait_event_interruptible(dev->read_wait,
+ (!dev->present
+ || (read_idx =
+ read_index
+ (dev)) !=
+ -1));
+ if (r) {
+ //we were interrupted by a signal
+ return -ERESTART;
+ }
+ if (!dev->present) {
+ //The device was unplugged
+ return -ENODEV;
+ }
+ if (read_idx == -1) {
+ // Can this happen ???
+ return 0;
+ }
+ }
+ }
+
+ offset = read_idx * (dev->report_size + 1);
+ if (copy_to_user(buffer, dev->read_queue + offset, count)) {
+ return -EFAULT;
+ }
+ } while (atomic_read(&dev->overflow_flag));
+
+ read_idx = ++read_idx == MAX_INTERRUPT_BUFFER ? 0 : read_idx;
+ atomic_set(&dev->read_idx, read_idx);
+ return count;
+}
+
+/*
+ * iowarrior_write
+ */
+static ssize_t iowarrior_write(struct file *file,
+ const char __user *user_buffer,
+ size_t count, loff_t *ppos)
+{
+ struct iowarrior *dev;
+ int retval = 0;
+ char *buf = NULL; /* for IOW24 and IOW56 we need a buffer */
+ struct urb *int_out_urb = NULL;
+
+ dev = (struct iowarrior *)file->private_data;
+
+ mutex_lock(&dev->mutex);
+ /* verify that the device wasn't unplugged */
+ if (dev == NULL || !dev->present) {
+ retval = -ENODEV;
+ goto exit;
+ }
+ dbg("%s - minor %d, count = %zd", __func__, dev->minor, count);
+ /* if count is 0 we're already done */
+ if (count == 0) {
+ retval = 0;
+ goto exit;
+ }
+ /* We only accept full reports */
+ if (count != dev->report_size) {
+ retval = -EINVAL;
+ goto exit;
+ }
+ switch (dev->product_id) {
+ case USB_DEVICE_ID_CODEMERCS_IOW24:
+ case USB_DEVICE_ID_CODEMERCS_IOWPV1:
+ case USB_DEVICE_ID_CODEMERCS_IOWPV2:
+ case USB_DEVICE_ID_CODEMERCS_IOW40:
+ /* IOW24 and IOW40 use a synchronous call */
+ buf = kmalloc(8, GFP_KERNEL); /* 8 bytes are enough for both products */
+ if (!buf) {
+ retval = -ENOMEM;
+ goto exit;
+ }
+ if (copy_from_user(buf, user_buffer, count)) {
+ retval = -EFAULT;
+ kfree(buf);
+ goto exit;
+ }
+ retval = usb_set_report(dev->interface, 2, 0, buf, count);
+ kfree(buf);
+ goto exit;
+ break;
+ case USB_DEVICE_ID_CODEMERCS_IOW56:
+ /* The IOW56 uses asynchronous IO and more urbs */
+ if (atomic_read(&dev->write_busy) == MAX_WRITES_IN_FLIGHT) {
+ /* Wait until we are below the limit for submitted urbs */
+ if (file->f_flags & O_NONBLOCK) {
+ retval = -EAGAIN;
+ goto exit;
+ } else {
+ retval = wait_event_interruptible(dev->write_wait,
+ (!dev->present || (atomic_read (&dev-> write_busy) < MAX_WRITES_IN_FLIGHT)));
+ if (retval) {
+ /* we were interrupted by a signal */
+ retval = -ERESTART;
+ goto exit;
+ }
+ if (!dev->present) {
+ /* The device was unplugged */
+ retval = -ENODEV;
+ goto exit;
+ }
+ if (!dev->opened) {
+ /* We were closed while waiting for an URB */
+ retval = -ENODEV;
+ goto exit;
+ }
+ }
+ }
+ atomic_inc(&dev->write_busy);
+ int_out_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!int_out_urb) {
+ retval = -ENOMEM;
+ dbg("%s Unable to allocate urb ", __func__);
+ goto error;
+ }
+ buf = usb_buffer_alloc(dev->udev, dev->report_size,
+ GFP_KERNEL, &int_out_urb->transfer_dma);
+ if (!buf) {
+ retval = -ENOMEM;
+ dbg("%s Unable to allocate buffer ", __func__);
+ goto error;
+ }
+ usb_fill_int_urb(int_out_urb, dev->udev,
+ usb_sndintpipe(dev->udev,
+ dev->int_out_endpoint->bEndpointAddress),
+ buf, dev->report_size,
+ iowarrior_write_callback, dev,
+ dev->int_out_endpoint->bInterval);
+ int_out_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ if (copy_from_user(buf, user_buffer, count)) {
+ retval = -EFAULT;
+ goto error;
+ }
+ retval = usb_submit_urb(int_out_urb, GFP_KERNEL);
+ if (retval) {
+ dbg("%s submit error %d for urb nr.%d", __func__,
+ retval, atomic_read(&dev->write_busy));
+ goto error;
+ }
+ /* submit was ok */
+ retval = count;
+ usb_free_urb(int_out_urb);
+ goto exit;
+ break;
+ default:
+ /* what do we have here ? An unsupported Product-ID ? */
+ dev_err(&dev->interface->dev, "%s - not supported for product=0x%x",
+ __FUNCTION__, dev->product_id);
+ retval = -EFAULT;
+ goto exit;
+ break;
+ }
+error:
+ usb_buffer_free(dev->udev, dev->report_size, buf,
+ int_out_urb->transfer_dma);
+ usb_free_urb(int_out_urb);
+ atomic_dec(&dev->write_busy);
+ wake_up_interruptible(&dev->write_wait);
+exit:
+ mutex_unlock(&dev->mutex);
+ return retval;
+}
+
+/**
+ * iowarrior_ioctl
+ */
+static int iowarrior_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct iowarrior *dev = NULL;
+ __u8 *buffer;
+ __u8 __user *user_buffer;
+ int retval;
+ int io_res; /* checks for bytes read/written and copy_to/from_user results */
+
+ dev = (struct iowarrior *)file->private_data;
+ if (dev == NULL) {
+ return -ENODEV;
+ }
+
+ buffer = kzalloc(dev->report_size, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
+ /* lock this object */
+ mutex_lock(&dev->mutex);
+
+ /* verify that the device wasn't unplugged */
+ if (!dev->present) {
+ mutex_unlock(&dev->mutex);
+ return -ENODEV;
+ }
+
+ dbg("%s - minor %d, cmd 0x%.4x, arg %ld", __func__, dev->minor, cmd,
+ arg);
+
+ retval = 0;
+ io_res = 0;
+ switch (cmd) {
+ case IOW_WRITE:
+ if (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW24 ||
+ dev->product_id == USB_DEVICE_ID_CODEMERCS_IOWPV1 ||
+ dev->product_id == USB_DEVICE_ID_CODEMERCS_IOWPV2 ||
+ dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW40) {
+ user_buffer = (__u8 __user *)arg;
+ io_res = copy_from_user(buffer, user_buffer,
+ dev->report_size);
+ if (io_res) {
+ retval = -EFAULT;
+ } else {
+ io_res = usb_set_report(dev->interface, 2, 0,
+ buffer,
+ dev->report_size);
+ if (io_res < 0)
+ retval = io_res;
+ }
+ } else {
+ retval = -EINVAL;
+ dev_err(&dev->interface->dev,
+ "ioctl 'IOW_WRITE' is not supported for product=0x%x.",
+ dev->product_id);
+ }
+ break;
+ case IOW_READ:
+ user_buffer = (__u8 __user *)arg;
+ io_res = usb_get_report(dev->udev,
+ dev->interface->cur_altsetting, 1, 0,
+ buffer, dev->report_size);
+ if (io_res < 0)
+ retval = io_res;
+ else {
+ io_res = copy_to_user(user_buffer, buffer, dev->report_size);
+ if (io_res < 0)
+ retval = -EFAULT;
+ }
+ break;
+ case IOW_GETINFO:
+ {
+ /* Report available information for the device */
+ struct iowarrior_info info;
+ /* needed for power consumption */
+ struct usb_config_descriptor *cfg_descriptor = &dev->udev->actconfig->desc;
+
+ /* directly from the descriptor */
+ info.vendor = le16_to_cpu(dev->udev->descriptor.idVendor);
+ info.product = dev->product_id;
+ info.revision = le16_to_cpu(dev->udev->descriptor.bcdDevice);
+
+ /* 0==UNKNOWN, 1==LOW(usb1.1) ,2=FULL(usb1.1), 3=HIGH(usb2.0) */
+ info.speed = le16_to_cpu(dev->udev->speed);
+ info.if_num = dev->interface->cur_altsetting->desc.bInterfaceNumber;
+ info.report_size = dev->report_size;
+
+ /* serial number string has been read earlier 8 chars or empty string */
+ memcpy(info.serial, dev->chip_serial,
+ sizeof(dev->chip_serial));
+ if (cfg_descriptor == NULL) {
+ info.power = -1; /* no information available */
+ } else {
+ /* the MaxPower is stored in units of 2mA to make it fit into a byte-value */
+ info.power = cfg_descriptor->bMaxPower * 2;
+ }
+ io_res = copy_to_user((struct iowarrior_info __user *)arg, &info,
+ sizeof(struct iowarrior_info));
+ if (io_res < 0)
+ retval = -EFAULT;
+ break;
+ }
+ default:
+ /* return that we did not understand this ioctl call */
+ retval = -ENOTTY;
+ break;
+ }
+
+ /* unlock the device */
+ mutex_unlock(&dev->mutex);
+ return retval;
+}
+
+/**
+ * iowarrior_open
+ */
+static int iowarrior_open(struct inode *inode, struct file *file)
+{
+ struct iowarrior *dev = NULL;
+ struct usb_interface *interface;
+ int subminor;
+ int retval = 0;
+
+ dbg("%s", __func__);
+
+ subminor = iminor(inode);
+
+ /* prevent disconnects */
+ down(&disconnect_sem);
+
+ interface = usb_find_interface(&iowarrior_driver, subminor);
+ if (!interface) {
+ err("%s - error, can't find device for minor %d", __FUNCTION__,
+ subminor);
+ retval = -ENODEV;
+ goto out;
+ }
+
+ dev = usb_get_intfdata(interface);
+ if (!dev) {
+ retval = -ENODEV;
+ goto out;
+ }
+
+ /* Only one process can open each device, no sharing. */
+ if (dev->opened) {
+ retval = -EBUSY;
+ goto out;
+ }
+
+ /* setup interrupt handler for receiving values */
+ if ((retval = usb_submit_urb(dev->int_in_urb, GFP_KERNEL)) < 0) {
+ dev_err(&interface->dev, "Error %d while submitting URB\n", retval);
+ retval = -EFAULT;
+ goto out;
+ }
+ /* increment our usage count for the driver */
+ ++dev->opened;
+ /* save our object in the file's private structure */
+ file->private_data = dev;
+ retval = 0;
+
+out:
+ up(&disconnect_sem);
+ return retval;
+}
+
+/**
+ * iowarrior_release
+ */
+static int iowarrior_release(struct inode *inode, struct file *file)
+{
+ struct iowarrior *dev;
+ int retval = 0;
+
+ dev = (struct iowarrior *)file->private_data;
+ if (dev == NULL) {
+ return -ENODEV;
+ }
+
+ dbg("%s - minor %d", __func__, dev->minor);
+
+ /* lock our device */
+ mutex_lock(&dev->mutex);
+
+ if (dev->opened <= 0) {
+ retval = -ENODEV; /* close called more than once */
+ mutex_unlock(&dev->mutex);
+ } else {
+ dev->opened = 0; /* we're closeing now */
+ retval = 0;
+ if (dev->present) {
+ /*
+ The device is still connected so we only shutdown
+ pending read-/write-ops.
+ */
+ usb_kill_urb(dev->int_in_urb);
+ wake_up_interruptible(&dev->read_wait);
+ wake_up_interruptible(&dev->write_wait);
+ mutex_unlock(&dev->mutex);
+ } else {
+ /* The device was unplugged, cleanup resources */
+ mutex_unlock(&dev->mutex);
+ iowarrior_delete(dev);
+ }
+ }
+ return retval;
+}
+
+static unsigned iowarrior_poll(struct file *file, poll_table * wait)
+{
+ struct iowarrior *dev = file->private_data;
+ unsigned int mask = 0;
+
+ if (!dev->present)
+ return POLLERR | POLLHUP;
+
+ poll_wait(file, &dev->read_wait, wait);
+ poll_wait(file, &dev->write_wait, wait);
+
+ if (!dev->present)
+ return POLLERR | POLLHUP;
+
+ if (read_index(dev) != -1)
+ mask |= POLLIN | POLLRDNORM;
+
+ if (atomic_read(&dev->write_busy) < MAX_WRITES_IN_FLIGHT)
+ mask |= POLLOUT | POLLWRNORM;
+ return mask;
+}
+
+/*
+ * File operations needed when we register this driver.
+ * This assumes that this driver NEEDS file operations,
+ * of course, which means that the driver is expected
+ * to have a node in the /dev directory. If the USB
+ * device were for a network interface then the driver
+ * would use "struct net_driver" instead, and a serial
+ * device would use "struct tty_driver".
+ */
+static struct file_operations iowarrior_fops = {
+ .owner = THIS_MODULE,
+ .write = iowarrior_write,
+ .read = iowarrior_read,
+ .ioctl = iowarrior_ioctl,
+ .open = iowarrior_open,
+ .release = iowarrior_release,
+ .poll = iowarrior_poll,
+};
+
+/*
+ * usb class driver info in order to get a minor number from the usb core,
+ * and to have the device registered with devfs and the driver core
+ */
+static struct usb_class_driver iowarrior_class = {
+ .name = "iowarrior%d",
+ .fops = &iowarrior_fops,
+ .minor_base = IOWARRIOR_MINOR_BASE,
+};
+
+/*---------------------------------*/
+/* probe and disconnect functions */
+/*---------------------------------*/
+/**
+ * iowarrior_probe
+ *
+ * Called by the usb core when a new device is connected that it thinks
+ * this driver might be interested in.
+ */
+static int iowarrior_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ struct usb_device *udev = interface_to_usbdev(interface);
+ struct iowarrior *dev = NULL;
+ struct usb_host_interface *iface_desc;
+ struct usb_endpoint_descriptor *endpoint;
+ int i;
+ int retval = -ENOMEM;
+ int idele = 0;
+
+ /* allocate memory for our device state and intialize it */
+ dev = kzalloc(sizeof(struct iowarrior), GFP_KERNEL);
+ if (dev == NULL) {
+ dev_err(&interface->dev, "Out of memory");
+ return retval;
+ }
+
+ mutex_init(&dev->mutex);
+
+ atomic_set(&dev->intr_idx, 0);
+ atomic_set(&dev->read_idx, 0);
+ spin_lock_init(&dev->intr_idx_lock);
+ atomic_set(&dev->overflow_flag, 0);
+ init_waitqueue_head(&dev->read_wait);
+ atomic_set(&dev->write_busy, 0);
+ init_waitqueue_head(&dev->write_wait);
+
+ dev->udev = udev;
+ dev->interface = interface;
+
+ iface_desc = interface->cur_altsetting;
+ dev->product_id = le16_to_cpu(udev->descriptor.idProduct);
+
+ /* set up the endpoint information */
+ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+ endpoint = &iface_desc->endpoint[i].desc;
+
+ if (usb_endpoint_is_int_in(endpoint))
+ dev->int_in_endpoint = endpoint;
+ if (usb_endpoint_is_int_out(endpoint))
+ /* this one will match for the IOWarrior56 only */
+ dev->int_out_endpoint = endpoint;
+ }
+ /* we have to check the report_size often, so remember it in the endianess suitable for our machine */
+ dev->report_size = le16_to_cpu(dev->int_in_endpoint->wMaxPacketSize);
+ if ((dev->interface->cur_altsetting->desc.bInterfaceNumber == 0) &&
+ (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW56))
+ /* IOWarrior56 has wMaxPacketSize different from report size */
+ dev->report_size = 7;
+
+ /* create the urb and buffer for reading */
+ dev->int_in_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!dev->int_in_urb) {
+ dev_err(&interface->dev, "Couldn't allocate interrupt_in_urb\n");
+ goto error;
+ }
+ dev->int_in_buffer = kmalloc(dev->report_size, GFP_KERNEL);
+ if (!dev->int_in_buffer) {
+ dev_err(&interface->dev, "Couldn't allocate int_in_buffer\n");
+ goto error;
+ }
+ usb_fill_int_urb(dev->int_in_urb, dev->udev,
+ usb_rcvintpipe(dev->udev,
+ dev->int_in_endpoint->bEndpointAddress),
+ dev->int_in_buffer, dev->report_size,
+ iowarrior_callback, dev,
+ dev->int_in_endpoint->bInterval);
+ /* create an internal buffer for interrupt data from the device */
+ dev->read_queue =
+ kmalloc(((dev->report_size + 1) * MAX_INTERRUPT_BUFFER),
+ GFP_KERNEL);
+ if (!dev->read_queue) {
+ dev_err(&interface->dev, "Couldn't allocate read_queue\n");
+ goto error;
+ }
+ /* Get the serial-number of the chip */
+ memset(dev->chip_serial, 0x00, sizeof(dev->chip_serial));
+ usb_string(udev, udev->descriptor.iSerialNumber, dev->chip_serial,
+ sizeof(dev->chip_serial));
+ if (strlen(dev->chip_serial) != 8)
+ memset(dev->chip_serial, 0x00, sizeof(dev->chip_serial));
+
+ /* Set the idle timeout to 0, if this is interface 0 */
+ if (dev->interface->cur_altsetting->desc.bInterfaceNumber == 0) {
+ idele = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ 0x0A,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0,
+ 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
+ dbg("idele = %d", idele);
+ }
+ /* allow device read and ioctl */
+ dev->present = 1;
+
+ /* we can register the device now, as it is ready */
+ usb_set_intfdata(interface, dev);
+
+ retval = usb_register_dev(interface, &iowarrior_class);
+ if (retval) {
+ /* something prevented us from registering this driver */
+ dev_err(&interface->dev, "Not able to get a minor for this device.\n");
+ usb_set_intfdata(interface, NULL);
+ goto error;
+ }
+
+ dev->minor = interface->minor;
+
+ /* let the user know what node this device is now attached to */
+ dev_info(&interface->dev, "IOWarrior product=0x%x, serial=%s interface=%d "
+ "now attached to iowarrior%d\n", dev->product_id, dev->chip_serial,
+ iface_desc->desc.bInterfaceNumber, dev->minor - IOWARRIOR_MINOR_BASE);
+ return retval;
+
+error:
+ iowarrior_delete(dev);
+ return retval;
+}
+
+/**
+ * iowarrior_disconnect
+ *
+ * Called by the usb core when the device is removed from the system.
+ */
+static void iowarrior_disconnect(struct usb_interface *interface)
+{
+ struct iowarrior *dev;
+ int minor;
+
+ /* prevent races with open() */
+ down(&disconnect_sem);
+
+ dev = usb_get_intfdata(interface);
+ usb_set_intfdata(interface, NULL);
+
+ mutex_lock(&dev->mutex);
+
+ minor = dev->minor;
+
+ /* give back our minor */
+ usb_deregister_dev(interface, &iowarrior_class);
+
+ /* prevent device read, write and ioctl */
+ dev->present = 0;
+
+ mutex_unlock(&dev->mutex);
+
+ if (dev->opened) {
+ /* There is a process that holds a filedescriptor to the device ,
+ so we only shutdown read-/write-ops going on.
+ Deleting the device is postponed until close() was called.
+ */
+ usb_kill_urb(dev->int_in_urb);
+ wake_up_interruptible(&dev->read_wait);
+ wake_up_interruptible(&dev->write_wait);
+ } else {
+ /* no process is using the device, cleanup now */
+ iowarrior_delete(dev);
+ }
+ up(&disconnect_sem);
+
+ dev_info(&interface->dev, "I/O-Warror #%d now disconnected\n",
+ minor - IOWARRIOR_MINOR_BASE);
+}
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver iowarrior_driver = {
+ .name = "iowarrior",
+ .probe = iowarrior_probe,
+ .disconnect = iowarrior_disconnect,
+ .id_table = iowarrior_ids,
+};
+
+static int __init iowarrior_init(void)
+{
+ return usb_register(&iowarrior_driver);
+}
+
+static void __exit iowarrior_exit(void)
+{
+ usb_deregister(&iowarrior_driver);
+}
+
+module_init(iowarrior_init);
+module_exit(iowarrior_exit);
diff --git a/drivers/usb/misc/rio500.c b/drivers/usb/misc/rio500.c
index 384fa376980..fdf68479a16 100644
--- a/drivers/usb/misc/rio500.c
+++ b/drivers/usb/misc/rio500.c
@@ -69,7 +69,7 @@ struct rio_usb_data {
char *obuf, *ibuf; /* transfer buffers */
char bulk_in_ep, bulk_out_ep; /* Endpoint assignments */
wait_queue_head_t wait_q; /* for timeouts */
- struct semaphore lock; /* general race avoidance */
+ struct mutex lock; /* general race avoidance */
};
static struct rio_usb_data rio_instance;
@@ -78,17 +78,17 @@ static int open_rio(struct inode *inode, struct file *file)
{
struct rio_usb_data *rio = &rio_instance;
- down(&(rio->lock));
+ mutex_lock(&(rio->lock));
if (rio->isopen || !rio->present) {
- up(&(rio->lock));
+ mutex_unlock(&(rio->lock));
return -EBUSY;
}
rio->isopen = 1;
init_waitqueue_head(&rio->wait_q);
- up(&(rio->lock));
+ mutex_unlock(&(rio->lock));
info("Rio opened.");
@@ -117,7 +117,7 @@ ioctl_rio(struct inode *inode, struct file *file, unsigned int cmd,
int retries;
int retval=0;
- down(&(rio->lock));
+ mutex_lock(&(rio->lock));
/* Sanity check to make sure rio is connected, powered, etc */
if ( rio == NULL ||
rio->present == 0 ||
@@ -257,7 +257,7 @@ ioctl_rio(struct inode *inode, struct file *file, unsigned int cmd,
err_out:
- up(&(rio->lock));
+ mutex_unlock(&(rio->lock));
return retval;
}
@@ -275,14 +275,17 @@ write_rio(struct file *file, const char __user *buffer,
int result = 0;
int maxretry;
int errn = 0;
+ int intr;
- down(&(rio->lock));
+ intr = mutex_lock_interruptible(&(rio->lock));
+ if (intr)
+ return -EINTR;
/* Sanity check to make sure rio is connected, powered, etc */
if ( rio == NULL ||
rio->present == 0 ||
rio->rio_dev == NULL )
{
- up(&(rio->lock));
+ mutex_unlock(&(rio->lock));
return -ENODEV;
}
@@ -305,7 +308,7 @@ write_rio(struct file *file, const char __user *buffer,
goto error;
}
if (signal_pending(current)) {
- up(&(rio->lock));
+ mutex_unlock(&(rio->lock));
return bytes_written ? bytes_written : -EINTR;
}
@@ -341,12 +344,12 @@ write_rio(struct file *file, const char __user *buffer,
buffer += copy_size;
} while (count > 0);
- up(&(rio->lock));
+ mutex_unlock(&(rio->lock));
return bytes_written ? bytes_written : -EIO;
error:
- up(&(rio->lock));
+ mutex_unlock(&(rio->lock));
return errn;
}
@@ -361,14 +364,17 @@ read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos)
int result;
int maxretry = 10;
char *ibuf;
+ int intr;
- down(&(rio->lock));
+ intr = mutex_lock_interruptible(&(rio->lock));
+ if (intr)
+ return -EINTR;
/* Sanity check to make sure rio is connected, powered, etc */
if ( rio == NULL ||
rio->present == 0 ||
rio->rio_dev == NULL )
{
- up(&(rio->lock));
+ mutex_unlock(&(rio->lock));
return -ENODEV;
}
@@ -379,11 +385,11 @@ read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos)
while (count > 0) {
if (signal_pending(current)) {
- up(&(rio->lock));
+ mutex_unlock(&(rio->lock));
return read_count ? read_count : -EINTR;
}
if (!rio->rio_dev) {
- up(&(rio->lock));
+ mutex_unlock(&(rio->lock));
return -ENODEV;
}
this_read = (count >= IBUF_SIZE) ? IBUF_SIZE : count;
@@ -400,7 +406,7 @@ read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos)
count = this_read = partial;
} else if (result == -ETIMEDOUT || result == 15) { /* FIXME: 15 ??? */
if (!maxretry--) {
- up(&(rio->lock));
+ mutex_unlock(&(rio->lock));
err("read_rio: maxretry timeout");
return -ETIME;
}
@@ -409,18 +415,18 @@ read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos)
finish_wait(&rio->wait_q, &wait);
continue;
} else if (result != -EREMOTEIO) {
- up(&(rio->lock));
+ mutex_unlock(&(rio->lock));
err("Read Whoops - result:%u partial:%u this_read:%u",
result, partial, this_read);
return -EIO;
} else {
- up(&(rio->lock));
+ mutex_unlock(&(rio->lock));
return (0);
}
if (this_read) {
if (copy_to_user(buffer, ibuf, this_read)) {
- up(&(rio->lock));
+ mutex_unlock(&(rio->lock));
return -EFAULT;
}
count -= this_read;
@@ -428,7 +434,7 @@ read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos)
buffer += this_read;
}
}
- up(&(rio->lock));
+ mutex_unlock(&(rio->lock));
return read_count;
}
@@ -480,7 +486,7 @@ static int probe_rio(struct usb_interface *intf,
}
dbg("probe_rio: ibuf address:%p", rio->ibuf);
- init_MUTEX(&(rio->lock));
+ mutex_init(&(rio->lock));
usb_set_intfdata (intf, rio);
rio->present = 1;
@@ -496,12 +502,12 @@ static void disconnect_rio(struct usb_interface *intf)
if (rio) {
usb_deregister_dev(intf, &usb_rio_class);
- down(&(rio->lock));
+ mutex_lock(&(rio->lock));
if (rio->isopen) {
rio->isopen = 0;
/* better let it finish - the release will do whats needed */
rio->rio_dev = NULL;
- up(&(rio->lock));
+ mutex_unlock(&(rio->lock));
return;
}
kfree(rio->ibuf);
@@ -510,7 +516,7 @@ static void disconnect_rio(struct usb_interface *intf)
info("USB Rio disconnected.");
rio->present = 0;
- up(&(rio->lock));
+ mutex_unlock(&(rio->lock));
}
}
diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c
index 0398908b15d..6f8b134a79c 100644
--- a/drivers/usb/misc/sisusbvga/sisusb.c
+++ b/drivers/usb/misc/sisusbvga/sisusb.c
@@ -40,7 +40,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/signal.h>
-#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/poll.h>
#include <linux/init.h>
diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c
index 9148694627d..1730d8642a4 100644
--- a/drivers/usb/misc/sisusbvga/sisusb_con.c
+++ b/drivers/usb/misc/sisusbvga/sisusb_con.c
@@ -51,7 +51,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/signal.h>
-#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/tty.h>
#include <linux/console.h>
diff --git a/drivers/usb/mon/Makefile b/drivers/usb/mon/Makefile
index 3cf3ea3a88e..90c59535778 100644
--- a/drivers/usb/mon/Makefile
+++ b/drivers/usb/mon/Makefile
@@ -2,7 +2,7 @@
# Makefile for USB Core files and filesystem
#
-usbmon-objs := mon_main.o mon_stat.o mon_text.o mon_dma.o
+usbmon-objs := mon_main.o mon_stat.o mon_text.o mon_bin.o mon_dma.o
# This does not use CONFIG_USB_MON because we want this to use a tristate.
obj-$(CONFIG_USB) += usbmon.o
diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c
new file mode 100644
index 00000000000..b2bedd974ac
--- /dev/null
+++ b/drivers/usb/mon/mon_bin.c
@@ -0,0 +1,1172 @@
+/*
+ * The USB Monitor, inspired by Dave Harding's USBMon.
+ *
+ * This is a binary format reader.
+ *
+ * Copyright (C) 2006 Paolo Abeni (paolo.abeni@email.it)
+ * Copyright (C) 2006 Pete Zaitcev (zaitcev@redhat.com)
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/usb.h>
+#include <linux/poll.h>
+#include <linux/compat.h>
+#include <linux/mm.h>
+
+#include <asm/uaccess.h>
+
+#include "usb_mon.h"
+
+/*
+ * Defined by USB 2.0 clause 9.3, table 9.2.
+ */
+#define SETUP_LEN 8
+
+/* ioctl macros */
+#define MON_IOC_MAGIC 0x92
+
+#define MON_IOCQ_URB_LEN _IO(MON_IOC_MAGIC, 1)
+/* #2 used to be MON_IOCX_URB, removed before it got into Linus tree */
+#define MON_IOCG_STATS _IOR(MON_IOC_MAGIC, 3, struct mon_bin_stats)
+#define MON_IOCT_RING_SIZE _IO(MON_IOC_MAGIC, 4)
+#define MON_IOCQ_RING_SIZE _IO(MON_IOC_MAGIC, 5)
+#define MON_IOCX_GET _IOW(MON_IOC_MAGIC, 6, struct mon_bin_get)
+#define MON_IOCX_MFETCH _IOWR(MON_IOC_MAGIC, 7, struct mon_bin_mfetch)
+#define MON_IOCH_MFLUSH _IO(MON_IOC_MAGIC, 8)
+#ifdef CONFIG_COMPAT
+#define MON_IOCX_GET32 _IOW(MON_IOC_MAGIC, 6, struct mon_bin_get32)
+#define MON_IOCX_MFETCH32 _IOWR(MON_IOC_MAGIC, 7, struct mon_bin_mfetch32)
+#endif
+
+/*
+ * Some architectures have enormous basic pages (16KB for ia64, 64KB for ppc).
+ * But it's all right. Just use a simple way to make sure the chunk is never
+ * smaller than a page.
+ *
+ * N.B. An application does not know our chunk size.
+ *
+ * Woops, get_zeroed_page() returns a single page. I guess we're stuck with
+ * page-sized chunks for the time being.
+ */
+#define CHUNK_SIZE PAGE_SIZE
+#define CHUNK_ALIGN(x) (((x)+CHUNK_SIZE-1) & ~(CHUNK_SIZE-1))
+
+/*
+ * The magic limit was calculated so that it allows the monitoring
+ * application to pick data once in two ticks. This way, another application,
+ * which presumably drives the bus, gets to hog CPU, yet we collect our data.
+ * If HZ is 100, a 480 mbit/s bus drives 614 KB every jiffy. USB has an
+ * enormous overhead built into the bus protocol, so we need about 1000 KB.
+ *
+ * This is still too much for most cases, where we just snoop a few
+ * descriptor fetches for enumeration. So, the default is a "reasonable"
+ * amount for systems with HZ=250 and incomplete bus saturation.
+ *
+ * XXX What about multi-megabyte URBs which take minutes to transfer?
+ */
+#define BUFF_MAX CHUNK_ALIGN(1200*1024)
+#define BUFF_DFL CHUNK_ALIGN(300*1024)
+#define BUFF_MIN CHUNK_ALIGN(8*1024)
+
+/*
+ * The per-event API header (2 per URB).
+ *
+ * This structure is seen in userland as defined by the documentation.
+ */
+struct mon_bin_hdr {
+ u64 id; /* URB ID - from submission to callback */
+ unsigned char type; /* Same as in text API; extensible. */
+ unsigned char xfer_type; /* ISO, Intr, Control, Bulk */
+ unsigned char epnum; /* Endpoint number and transfer direction */
+ unsigned char devnum; /* Device address */
+ unsigned short busnum; /* Bus number */
+ char flag_setup;
+ char flag_data;
+ s64 ts_sec; /* gettimeofday */
+ s32 ts_usec; /* gettimeofday */
+ int status;
+ unsigned int len_urb; /* Length of data (submitted or actual) */
+ unsigned int len_cap; /* Delivered length */
+ unsigned char setup[SETUP_LEN]; /* Only for Control S-type */
+};
+
+/* per file statistic */
+struct mon_bin_stats {
+ u32 queued;
+ u32 dropped;
+};
+
+struct mon_bin_get {
+ struct mon_bin_hdr __user *hdr; /* Only 48 bytes, not 64. */
+ void __user *data;
+ size_t alloc; /* Length of data (can be zero) */
+};
+
+struct mon_bin_mfetch {
+ u32 __user *offvec; /* Vector of events fetched */
+ u32 nfetch; /* Number of events to fetch (out: fetched) */
+ u32 nflush; /* Number of events to flush */
+};
+
+#ifdef CONFIG_COMPAT
+struct mon_bin_get32 {
+ u32 hdr32;
+ u32 data32;
+ u32 alloc32;
+};
+
+struct mon_bin_mfetch32 {
+ u32 offvec32;
+ u32 nfetch32;
+ u32 nflush32;
+};
+#endif
+
+/* Having these two values same prevents wrapping of the mon_bin_hdr */
+#define PKT_ALIGN 64
+#define PKT_SIZE 64
+
+/* max number of USB bus supported */
+#define MON_BIN_MAX_MINOR 128
+
+/*
+ * The buffer: map of used pages.
+ */
+struct mon_pgmap {
+ struct page *pg;
+ unsigned char *ptr; /* XXX just use page_to_virt everywhere? */
+};
+
+/*
+ * This gets associated with an open file struct.
+ */
+struct mon_reader_bin {
+ /* The buffer: one per open. */
+ spinlock_t b_lock; /* Protect b_cnt, b_in */
+ unsigned int b_size; /* Current size of the buffer - bytes */
+ unsigned int b_cnt; /* Bytes used */
+ unsigned int b_in, b_out; /* Offsets into buffer - bytes */
+ unsigned int b_read; /* Amount of read data in curr. pkt. */
+ struct mon_pgmap *b_vec; /* The map array */
+ wait_queue_head_t b_wait; /* Wait for data here */
+
+ struct mutex fetch_lock; /* Protect b_read, b_out */
+ int mmap_active;
+
+ /* A list of these is needed for "bus 0". Some time later. */
+ struct mon_reader r;
+
+ /* Stats */
+ unsigned int cnt_lost;
+};
+
+static inline struct mon_bin_hdr *MON_OFF2HDR(const struct mon_reader_bin *rp,
+ unsigned int offset)
+{
+ return (struct mon_bin_hdr *)
+ (rp->b_vec[offset / CHUNK_SIZE].ptr + offset % CHUNK_SIZE);
+}
+
+#define MON_RING_EMPTY(rp) ((rp)->b_cnt == 0)
+
+static dev_t mon_bin_dev0;
+static struct cdev mon_bin_cdev;
+
+static void mon_buff_area_fill(const struct mon_reader_bin *rp,
+ unsigned int offset, unsigned int size);
+static int mon_bin_wait_event(struct file *file, struct mon_reader_bin *rp);
+static int mon_alloc_buff(struct mon_pgmap *map, int npages);
+static void mon_free_buff(struct mon_pgmap *map, int npages);
+
+/*
+ * This is a "chunked memcpy". It does not manipulate any counters.
+ * But it returns the new offset for repeated application.
+ */
+unsigned int mon_copy_to_buff(const struct mon_reader_bin *this,
+ unsigned int off, const unsigned char *from, unsigned int length)
+{
+ unsigned int step_len;
+ unsigned char *buf;
+ unsigned int in_page;
+
+ while (length) {
+ /*
+ * Determine step_len.
+ */
+ step_len = length;
+ in_page = CHUNK_SIZE - (off & (CHUNK_SIZE-1));
+ if (in_page < step_len)
+ step_len = in_page;
+
+ /*
+ * Copy data and advance pointers.
+ */
+ buf = this->b_vec[off / CHUNK_SIZE].ptr + off % CHUNK_SIZE;
+ memcpy(buf, from, step_len);
+ if ((off += step_len) >= this->b_size) off = 0;
+ from += step_len;
+ length -= step_len;
+ }
+ return off;
+}
+
+/*
+ * This is a little worse than the above because it's "chunked copy_to_user".
+ * The return value is an error code, not an offset.
+ */
+static int copy_from_buf(const struct mon_reader_bin *this, unsigned int off,
+ char __user *to, int length)
+{
+ unsigned int step_len;
+ unsigned char *buf;
+ unsigned int in_page;
+
+ while (length) {
+ /*
+ * Determine step_len.
+ */
+ step_len = length;
+ in_page = CHUNK_SIZE - (off & (CHUNK_SIZE-1));
+ if (in_page < step_len)
+ step_len = in_page;
+
+ /*
+ * Copy data and advance pointers.
+ */
+ buf = this->b_vec[off / CHUNK_SIZE].ptr + off % CHUNK_SIZE;
+ if (copy_to_user(to, buf, step_len))
+ return -EINVAL;
+ if ((off += step_len) >= this->b_size) off = 0;
+ to += step_len;
+ length -= step_len;
+ }
+ return 0;
+}
+
+/*
+ * Allocate an (aligned) area in the buffer.
+ * This is called under b_lock.
+ * Returns ~0 on failure.
+ */
+static unsigned int mon_buff_area_alloc(struct mon_reader_bin *rp,
+ unsigned int size)
+{
+ unsigned int offset;
+
+ size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
+ if (rp->b_cnt + size > rp->b_size)
+ return ~0;
+ offset = rp->b_in;
+ rp->b_cnt += size;
+ if ((rp->b_in += size) >= rp->b_size)
+ rp->b_in -= rp->b_size;
+ return offset;
+}
+
+/*
+ * This is the same thing as mon_buff_area_alloc, only it does not allow
+ * buffers to wrap. This is needed by applications which pass references
+ * into mmap-ed buffers up their stacks (libpcap can do that).
+ *
+ * Currently, we always have the header stuck with the data, although
+ * it is not strictly speaking necessary.
+ *
+ * When a buffer would wrap, we place a filler packet to mark the space.
+ */
+static unsigned int mon_buff_area_alloc_contiguous(struct mon_reader_bin *rp,
+ unsigned int size)
+{
+ unsigned int offset;
+ unsigned int fill_size;
+
+ size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
+ if (rp->b_cnt + size > rp->b_size)
+ return ~0;
+ if (rp->b_in + size > rp->b_size) {
+ /*
+ * This would wrap. Find if we still have space after
+ * skipping to the end of the buffer. If we do, place
+ * a filler packet and allocate a new packet.
+ */
+ fill_size = rp->b_size - rp->b_in;
+ if (rp->b_cnt + size + fill_size > rp->b_size)
+ return ~0;
+ mon_buff_area_fill(rp, rp->b_in, fill_size);
+
+ offset = 0;
+ rp->b_in = size;
+ rp->b_cnt += size + fill_size;
+ } else if (rp->b_in + size == rp->b_size) {
+ offset = rp->b_in;
+ rp->b_in = 0;
+ rp->b_cnt += size;
+ } else {
+ offset = rp->b_in;
+ rp->b_in += size;
+ rp->b_cnt += size;
+ }
+ return offset;
+}
+
+/*
+ * Return a few (kilo-)bytes to the head of the buffer.
+ * This is used if a DMA fetch fails.
+ */
+static void mon_buff_area_shrink(struct mon_reader_bin *rp, unsigned int size)
+{
+
+ size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
+ rp->b_cnt -= size;
+ if (rp->b_in < size)
+ rp->b_in += rp->b_size;
+ rp->b_in -= size;
+}
+
+/*
+ * This has to be called under both b_lock and fetch_lock, because
+ * it accesses both b_cnt and b_out.
+ */
+static void mon_buff_area_free(struct mon_reader_bin *rp, unsigned int size)
+{
+
+ size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
+ rp->b_cnt -= size;
+ if ((rp->b_out += size) >= rp->b_size)
+ rp->b_out -= rp->b_size;
+}
+
+static void mon_buff_area_fill(const struct mon_reader_bin *rp,
+ unsigned int offset, unsigned int size)
+{
+ struct mon_bin_hdr *ep;
+
+ ep = MON_OFF2HDR(rp, offset);
+ memset(ep, 0, PKT_SIZE);
+ ep->type = '@';
+ ep->len_cap = size - PKT_SIZE;
+}
+
+static inline char mon_bin_get_setup(unsigned char *setupb,
+ const struct urb *urb, char ev_type)
+{
+
+ if (!usb_pipecontrol(urb->pipe) || ev_type != 'S')
+ return '-';
+
+ if (urb->transfer_flags & URB_NO_SETUP_DMA_MAP)
+ return mon_dmapeek(setupb, urb->setup_dma, SETUP_LEN);
+ if (urb->setup_packet == NULL)
+ return 'Z';
+
+ memcpy(setupb, urb->setup_packet, SETUP_LEN);
+ return 0;
+}
+
+static char mon_bin_get_data(const struct mon_reader_bin *rp,
+ unsigned int offset, struct urb *urb, unsigned int length)
+{
+
+ if (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP) {
+ mon_dmapeek_vec(rp, offset, urb->transfer_dma, length);
+ return 0;
+ }
+
+ if (urb->transfer_buffer == NULL)
+ return 'Z';
+
+ mon_copy_to_buff(rp, offset, urb->transfer_buffer, length);
+ return 0;
+}
+
+static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
+ char ev_type)
+{
+ unsigned long flags;
+ struct timeval ts;
+ unsigned int urb_length;
+ unsigned int offset;
+ unsigned int length;
+ struct mon_bin_hdr *ep;
+ char data_tag = 0;
+
+ do_gettimeofday(&ts);
+
+ spin_lock_irqsave(&rp->b_lock, flags);
+
+ /*
+ * Find the maximum allowable length, then allocate space.
+ */
+ urb_length = (ev_type == 'S') ?
+ urb->transfer_buffer_length : urb->actual_length;
+ length = urb_length;
+
+ if (length >= rp->b_size/5)
+ length = rp->b_size/5;
+
+ if (usb_pipein(urb->pipe)) {
+ if (ev_type == 'S') {
+ length = 0;
+ data_tag = '<';
+ }
+ } else {
+ if (ev_type == 'C') {
+ length = 0;
+ data_tag = '>';
+ }
+ }
+
+ if (rp->mmap_active)
+ offset = mon_buff_area_alloc_contiguous(rp, length + PKT_SIZE);
+ else
+ offset = mon_buff_area_alloc(rp, length + PKT_SIZE);
+ if (offset == ~0) {
+ rp->cnt_lost++;
+ spin_unlock_irqrestore(&rp->b_lock, flags);
+ return;
+ }
+
+ ep = MON_OFF2HDR(rp, offset);
+ if ((offset += PKT_SIZE) >= rp->b_size) offset = 0;
+
+ /*
+ * Fill the allocated area.
+ */
+ memset(ep, 0, PKT_SIZE);
+ ep->type = ev_type;
+ ep->xfer_type = usb_pipetype(urb->pipe);
+ /* We use the fact that usb_pipein() returns 0x80 */
+ ep->epnum = usb_pipeendpoint(urb->pipe) | usb_pipein(urb->pipe);
+ ep->devnum = usb_pipedevice(urb->pipe);
+ ep->busnum = rp->r.m_bus->u_bus->busnum;
+ ep->id = (unsigned long) urb;
+ ep->ts_sec = ts.tv_sec;
+ ep->ts_usec = ts.tv_usec;
+ ep->status = urb->status;
+ ep->len_urb = urb_length;
+ ep->len_cap = length;
+
+ ep->flag_setup = mon_bin_get_setup(ep->setup, urb, ev_type);
+ if (length != 0) {
+ ep->flag_data = mon_bin_get_data(rp, offset, urb, length);
+ if (ep->flag_data != 0) { /* Yes, it's 0x00, not '0' */
+ ep->len_cap = 0;
+ mon_buff_area_shrink(rp, length);
+ }
+ } else {
+ ep->flag_data = data_tag;
+ }
+
+ spin_unlock_irqrestore(&rp->b_lock, flags);
+
+ wake_up(&rp->b_wait);
+}
+
+static void mon_bin_submit(void *data, struct urb *urb)
+{
+ struct mon_reader_bin *rp = data;
+ mon_bin_event(rp, urb, 'S');
+}
+
+static void mon_bin_complete(void *data, struct urb *urb)
+{
+ struct mon_reader_bin *rp = data;
+ mon_bin_event(rp, urb, 'C');
+}
+
+static void mon_bin_error(void *data, struct urb *urb, int error)
+{
+ struct mon_reader_bin *rp = data;
+ unsigned long flags;
+ unsigned int offset;
+ struct mon_bin_hdr *ep;
+
+ spin_lock_irqsave(&rp->b_lock, flags);
+
+ offset = mon_buff_area_alloc(rp, PKT_SIZE);
+ if (offset == ~0) {
+ /* Not incrementing cnt_lost. Just because. */
+ spin_unlock_irqrestore(&rp->b_lock, flags);
+ return;
+ }
+
+ ep = MON_OFF2HDR(rp, offset);
+
+ memset(ep, 0, PKT_SIZE);
+ ep->type = 'E';
+ ep->xfer_type = usb_pipetype(urb->pipe);
+ /* We use the fact that usb_pipein() returns 0x80 */
+ ep->epnum = usb_pipeendpoint(urb->pipe) | usb_pipein(urb->pipe);
+ ep->devnum = usb_pipedevice(urb->pipe);
+ ep->busnum = rp->r.m_bus->u_bus->busnum;
+ ep->id = (unsigned long) urb;
+ ep->status = error;
+
+ ep->flag_setup = '-';
+ ep->flag_data = 'E';
+
+ spin_unlock_irqrestore(&rp->b_lock, flags);
+
+ wake_up(&rp->b_wait);
+}
+
+static int mon_bin_open(struct inode *inode, struct file *file)
+{
+ struct mon_bus *mbus;
+ struct usb_bus *ubus;
+ struct mon_reader_bin *rp;
+ size_t size;
+ int rc;
+
+ mutex_lock(&mon_lock);
+ if ((mbus = mon_bus_lookup(iminor(inode))) == NULL) {
+ mutex_unlock(&mon_lock);
+ return -ENODEV;
+ }
+ if ((ubus = mbus->u_bus) == NULL) {
+ printk(KERN_ERR TAG ": consistency error on open\n");
+ mutex_unlock(&mon_lock);
+ return -ENODEV;
+ }
+
+ rp = kzalloc(sizeof(struct mon_reader_bin), GFP_KERNEL);
+ if (rp == NULL) {
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+ spin_lock_init(&rp->b_lock);
+ init_waitqueue_head(&rp->b_wait);
+ mutex_init(&rp->fetch_lock);
+
+ rp->b_size = BUFF_DFL;
+
+ size = sizeof(struct mon_pgmap) * (rp->b_size/CHUNK_SIZE);
+ if ((rp->b_vec = kzalloc(size, GFP_KERNEL)) == NULL) {
+ rc = -ENOMEM;
+ goto err_allocvec;
+ }
+
+ if ((rc = mon_alloc_buff(rp->b_vec, rp->b_size/CHUNK_SIZE)) < 0)
+ goto err_allocbuff;
+
+ rp->r.m_bus = mbus;
+ rp->r.r_data = rp;
+ rp->r.rnf_submit = mon_bin_submit;
+ rp->r.rnf_error = mon_bin_error;
+ rp->r.rnf_complete = mon_bin_complete;
+
+ mon_reader_add(mbus, &rp->r);
+
+ file->private_data = rp;
+ mutex_unlock(&mon_lock);
+ return 0;
+
+err_allocbuff:
+ kfree(rp->b_vec);
+err_allocvec:
+ kfree(rp);
+err_alloc:
+ mutex_unlock(&mon_lock);
+ return rc;
+}
+
+/*
+ * Extract an event from buffer and copy it to user space.
+ * Wait if there is no event ready.
+ * Returns zero or error.
+ */
+static int mon_bin_get_event(struct file *file, struct mon_reader_bin *rp,
+ struct mon_bin_hdr __user *hdr, void __user *data, unsigned int nbytes)
+{
+ unsigned long flags;
+ struct mon_bin_hdr *ep;
+ size_t step_len;
+ unsigned int offset;
+ int rc;
+
+ mutex_lock(&rp->fetch_lock);
+
+ if ((rc = mon_bin_wait_event(file, rp)) < 0) {
+ mutex_unlock(&rp->fetch_lock);
+ return rc;
+ }
+
+ ep = MON_OFF2HDR(rp, rp->b_out);
+
+ if (copy_to_user(hdr, ep, sizeof(struct mon_bin_hdr))) {
+ mutex_unlock(&rp->fetch_lock);
+ return -EFAULT;
+ }
+
+ step_len = min(ep->len_cap, nbytes);
+ if ((offset = rp->b_out + PKT_SIZE) >= rp->b_size) offset = 0;
+
+ if (copy_from_buf(rp, offset, data, step_len)) {
+ mutex_unlock(&rp->fetch_lock);
+ return -EFAULT;
+ }
+
+ spin_lock_irqsave(&rp->b_lock, flags);
+ mon_buff_area_free(rp, PKT_SIZE + ep->len_cap);
+ spin_unlock_irqrestore(&rp->b_lock, flags);
+ rp->b_read = 0;
+
+ mutex_unlock(&rp->fetch_lock);
+ return 0;
+}
+
+static int mon_bin_release(struct inode *inode, struct file *file)
+{
+ struct mon_reader_bin *rp = file->private_data;
+ struct mon_bus* mbus = rp->r.m_bus;
+
+ mutex_lock(&mon_lock);
+
+ if (mbus->nreaders <= 0) {
+ printk(KERN_ERR TAG ": consistency error on close\n");
+ mutex_unlock(&mon_lock);
+ return 0;
+ }
+ mon_reader_del(mbus, &rp->r);
+
+ mon_free_buff(rp->b_vec, rp->b_size/CHUNK_SIZE);
+ kfree(rp->b_vec);
+ kfree(rp);
+
+ mutex_unlock(&mon_lock);
+ return 0;
+}
+
+static ssize_t mon_bin_read(struct file *file, char __user *buf,
+ size_t nbytes, loff_t *ppos)
+{
+ struct mon_reader_bin *rp = file->private_data;
+ unsigned long flags;
+ struct mon_bin_hdr *ep;
+ unsigned int offset;
+ size_t step_len;
+ char *ptr;
+ ssize_t done = 0;
+ int rc;
+
+ mutex_lock(&rp->fetch_lock);
+
+ if ((rc = mon_bin_wait_event(file, rp)) < 0) {
+ mutex_unlock(&rp->fetch_lock);
+ return rc;
+ }
+
+ ep = MON_OFF2HDR(rp, rp->b_out);
+
+ if (rp->b_read < sizeof(struct mon_bin_hdr)) {
+ step_len = min(nbytes, sizeof(struct mon_bin_hdr) - rp->b_read);
+ ptr = ((char *)ep) + rp->b_read;
+ if (step_len && copy_to_user(buf, ptr, step_len)) {
+ mutex_unlock(&rp->fetch_lock);
+ return -EFAULT;
+ }
+ nbytes -= step_len;
+ buf += step_len;
+ rp->b_read += step_len;
+ done += step_len;
+ }
+
+ if (rp->b_read >= sizeof(struct mon_bin_hdr)) {
+ step_len = min(nbytes, (size_t)ep->len_cap);
+ offset = rp->b_out + PKT_SIZE;
+ offset += rp->b_read - sizeof(struct mon_bin_hdr);
+ if (offset >= rp->b_size)
+ offset -= rp->b_size;
+ if (copy_from_buf(rp, offset, buf, step_len)) {
+ mutex_unlock(&rp->fetch_lock);
+ return -EFAULT;
+ }
+ nbytes -= step_len;
+ buf += step_len;
+ rp->b_read += step_len;
+ done += step_len;
+ }
+
+ /*
+ * Check if whole packet was read, and if so, jump to the next one.
+ */
+ if (rp->b_read >= sizeof(struct mon_bin_hdr) + ep->len_cap) {
+ spin_lock_irqsave(&rp->b_lock, flags);
+ mon_buff_area_free(rp, PKT_SIZE + ep->len_cap);
+ spin_unlock_irqrestore(&rp->b_lock, flags);
+ rp->b_read = 0;
+ }
+
+ mutex_unlock(&rp->fetch_lock);
+ return done;
+}
+
+/*
+ * Remove at most nevents from chunked buffer.
+ * Returns the number of removed events.
+ */
+static int mon_bin_flush(struct mon_reader_bin *rp, unsigned nevents)
+{
+ unsigned long flags;
+ struct mon_bin_hdr *ep;
+ int i;
+
+ mutex_lock(&rp->fetch_lock);
+ spin_lock_irqsave(&rp->b_lock, flags);
+ for (i = 0; i < nevents; ++i) {
+ if (MON_RING_EMPTY(rp))
+ break;
+
+ ep = MON_OFF2HDR(rp, rp->b_out);
+ mon_buff_area_free(rp, PKT_SIZE + ep->len_cap);
+ }
+ spin_unlock_irqrestore(&rp->b_lock, flags);
+ rp->b_read = 0;
+ mutex_unlock(&rp->fetch_lock);
+ return i;
+}
+
+/*
+ * Fetch at most max event offsets into the buffer and put them into vec.
+ * The events are usually freed later with mon_bin_flush.
+ * Return the effective number of events fetched.
+ */
+static int mon_bin_fetch(struct file *file, struct mon_reader_bin *rp,
+ u32 __user *vec, unsigned int max)
+{
+ unsigned int cur_out;
+ unsigned int bytes, avail;
+ unsigned int size;
+ unsigned int nevents;
+ struct mon_bin_hdr *ep;
+ unsigned long flags;
+ int rc;
+
+ mutex_lock(&rp->fetch_lock);
+
+ if ((rc = mon_bin_wait_event(file, rp)) < 0) {
+ mutex_unlock(&rp->fetch_lock);
+ return rc;
+ }
+
+ spin_lock_irqsave(&rp->b_lock, flags);
+ avail = rp->b_cnt;
+ spin_unlock_irqrestore(&rp->b_lock, flags);
+
+ cur_out = rp->b_out;
+ nevents = 0;
+ bytes = 0;
+ while (bytes < avail) {
+ if (nevents >= max)
+ break;
+
+ ep = MON_OFF2HDR(rp, cur_out);
+ if (put_user(cur_out, &vec[nevents])) {
+ mutex_unlock(&rp->fetch_lock);
+ return -EFAULT;
+ }
+
+ nevents++;
+ size = ep->len_cap + PKT_SIZE;
+ size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
+ if ((cur_out += size) >= rp->b_size)
+ cur_out -= rp->b_size;
+ bytes += size;
+ }
+
+ mutex_unlock(&rp->fetch_lock);
+ return nevents;
+}
+
+/*
+ * Count events. This is almost the same as the above mon_bin_fetch,
+ * only we do not store offsets into user vector, and we have no limit.
+ */
+static int mon_bin_queued(struct mon_reader_bin *rp)
+{
+ unsigned int cur_out;
+ unsigned int bytes, avail;
+ unsigned int size;
+ unsigned int nevents;
+ struct mon_bin_hdr *ep;
+ unsigned long flags;
+
+ mutex_lock(&rp->fetch_lock);
+
+ spin_lock_irqsave(&rp->b_lock, flags);
+ avail = rp->b_cnt;
+ spin_unlock_irqrestore(&rp->b_lock, flags);
+
+ cur_out = rp->b_out;
+ nevents = 0;
+ bytes = 0;
+ while (bytes < avail) {
+ ep = MON_OFF2HDR(rp, cur_out);
+
+ nevents++;
+ size = ep->len_cap + PKT_SIZE;
+ size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
+ if ((cur_out += size) >= rp->b_size)
+ cur_out -= rp->b_size;
+ bytes += size;
+ }
+
+ mutex_unlock(&rp->fetch_lock);
+ return nevents;
+}
+
+/*
+ */
+static int mon_bin_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct mon_reader_bin *rp = file->private_data;
+ // struct mon_bus* mbus = rp->r.m_bus;
+ int ret = 0;
+ struct mon_bin_hdr *ep;
+ unsigned long flags;
+
+ switch (cmd) {
+
+ case MON_IOCQ_URB_LEN:
+ /*
+ * N.B. This only returns the size of data, without the header.
+ */
+ spin_lock_irqsave(&rp->b_lock, flags);
+ if (!MON_RING_EMPTY(rp)) {
+ ep = MON_OFF2HDR(rp, rp->b_out);
+ ret = ep->len_cap;
+ }
+ spin_unlock_irqrestore(&rp->b_lock, flags);
+ break;
+
+ case MON_IOCQ_RING_SIZE:
+ ret = rp->b_size;
+ break;
+
+ case MON_IOCT_RING_SIZE:
+ /*
+ * Changing the buffer size will flush it's contents; the new
+ * buffer is allocated before releasing the old one to be sure
+ * the device will stay functional also in case of memory
+ * pressure.
+ */
+ {
+ int size;
+ struct mon_pgmap *vec;
+
+ if (arg < BUFF_MIN || arg > BUFF_MAX)
+ return -EINVAL;
+
+ size = CHUNK_ALIGN(arg);
+ if ((vec = kzalloc(sizeof(struct mon_pgmap) * (size/CHUNK_SIZE),
+ GFP_KERNEL)) == NULL) {
+ ret = -ENOMEM;
+ break;
+ }
+
+ ret = mon_alloc_buff(vec, size/CHUNK_SIZE);
+ if (ret < 0) {
+ kfree(vec);
+ break;
+ }
+
+ mutex_lock(&rp->fetch_lock);
+ spin_lock_irqsave(&rp->b_lock, flags);
+ mon_free_buff(rp->b_vec, size/CHUNK_SIZE);
+ kfree(rp->b_vec);
+ rp->b_vec = vec;
+ rp->b_size = size;
+ rp->b_read = rp->b_in = rp->b_out = rp->b_cnt = 0;
+ rp->cnt_lost = 0;
+ spin_unlock_irqrestore(&rp->b_lock, flags);
+ mutex_unlock(&rp->fetch_lock);
+ }
+ break;
+
+ case MON_IOCH_MFLUSH:
+ ret = mon_bin_flush(rp, arg);
+ break;
+
+ case MON_IOCX_GET:
+ {
+ struct mon_bin_get getb;
+
+ if (copy_from_user(&getb, (void __user *)arg,
+ sizeof(struct mon_bin_get)))
+ return -EFAULT;
+
+ if (getb.alloc > 0x10000000) /* Want to cast to u32 */
+ return -EINVAL;
+ ret = mon_bin_get_event(file, rp,
+ getb.hdr, getb.data, (unsigned int)getb.alloc);
+ }
+ break;
+
+#ifdef CONFIG_COMPAT
+ case MON_IOCX_GET32: {
+ struct mon_bin_get32 getb;
+
+ if (copy_from_user(&getb, (void __user *)arg,
+ sizeof(struct mon_bin_get32)))
+ return -EFAULT;
+
+ ret = mon_bin_get_event(file, rp,
+ compat_ptr(getb.hdr32), compat_ptr(getb.data32),
+ getb.alloc32);
+ }
+ break;
+#endif
+
+ case MON_IOCX_MFETCH:
+ {
+ struct mon_bin_mfetch mfetch;
+ struct mon_bin_mfetch __user *uptr;
+
+ uptr = (struct mon_bin_mfetch __user *)arg;
+
+ if (copy_from_user(&mfetch, uptr, sizeof(mfetch)))
+ return -EFAULT;
+
+ if (mfetch.nflush) {
+ ret = mon_bin_flush(rp, mfetch.nflush);
+ if (ret < 0)
+ return ret;
+ if (put_user(ret, &uptr->nflush))
+ return -EFAULT;
+ }
+ ret = mon_bin_fetch(file, rp, mfetch.offvec, mfetch.nfetch);
+ if (ret < 0)
+ return ret;
+ if (put_user(ret, &uptr->nfetch))
+ return -EFAULT;
+ ret = 0;
+ }
+ break;
+
+#ifdef CONFIG_COMPAT
+ case MON_IOCX_MFETCH32:
+ {
+ struct mon_bin_mfetch32 mfetch;
+ struct mon_bin_mfetch32 __user *uptr;
+
+ uptr = (struct mon_bin_mfetch32 __user *) compat_ptr(arg);
+
+ if (copy_from_user(&mfetch, uptr, sizeof(mfetch)))
+ return -EFAULT;
+
+ if (mfetch.nflush32) {
+ ret = mon_bin_flush(rp, mfetch.nflush32);
+ if (ret < 0)
+ return ret;
+ if (put_user(ret, &uptr->nflush32))
+ return -EFAULT;
+ }
+ ret = mon_bin_fetch(file, rp, compat_ptr(mfetch.offvec32),
+ mfetch.nfetch32);
+ if (ret < 0)
+ return ret;
+ if (put_user(ret, &uptr->nfetch32))
+ return -EFAULT;
+ ret = 0;
+ }
+ break;
+#endif
+
+ case MON_IOCG_STATS: {
+ struct mon_bin_stats __user *sp;
+ unsigned int nevents;
+ unsigned int ndropped;
+
+ spin_lock_irqsave(&rp->b_lock, flags);
+ ndropped = rp->cnt_lost;
+ rp->cnt_lost = 0;
+ spin_unlock_irqrestore(&rp->b_lock, flags);
+ nevents = mon_bin_queued(rp);
+
+ sp = (struct mon_bin_stats __user *)arg;
+ if (put_user(rp->cnt_lost, &sp->dropped))
+ return -EFAULT;
+ if (put_user(nevents, &sp->queued))
+ return -EFAULT;
+
+ }
+ break;
+
+ default:
+ return -ENOTTY;
+ }
+
+ return ret;
+}
+
+static unsigned int
+mon_bin_poll(struct file *file, struct poll_table_struct *wait)
+{
+ struct mon_reader_bin *rp = file->private_data;
+ unsigned int mask = 0;
+ unsigned long flags;
+
+ if (file->f_mode & FMODE_READ)
+ poll_wait(file, &rp->b_wait, wait);
+
+ spin_lock_irqsave(&rp->b_lock, flags);
+ if (!MON_RING_EMPTY(rp))
+ mask |= POLLIN | POLLRDNORM; /* readable */
+ spin_unlock_irqrestore(&rp->b_lock, flags);
+ return mask;
+}
+
+/*
+ * open and close: just keep track of how many times the device is
+ * mapped, to use the proper memory allocation function.
+ */
+static void mon_bin_vma_open(struct vm_area_struct *vma)
+{
+ struct mon_reader_bin *rp = vma->vm_private_data;
+ rp->mmap_active++;
+}
+
+static void mon_bin_vma_close(struct vm_area_struct *vma)
+{
+ struct mon_reader_bin *rp = vma->vm_private_data;
+ rp->mmap_active--;
+}
+
+/*
+ * Map ring pages to user space.
+ */
+struct page *mon_bin_vma_nopage(struct vm_area_struct *vma,
+ unsigned long address, int *type)
+{
+ struct mon_reader_bin *rp = vma->vm_private_data;
+ unsigned long offset, chunk_idx;
+ struct page *pageptr;
+
+ offset = (address - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT);
+ if (offset >= rp->b_size)
+ return NOPAGE_SIGBUS;
+ chunk_idx = offset / CHUNK_SIZE;
+ pageptr = rp->b_vec[chunk_idx].pg;
+ get_page(pageptr);
+ if (type)
+ *type = VM_FAULT_MINOR;
+ return pageptr;
+}
+
+struct vm_operations_struct mon_bin_vm_ops = {
+ .open = mon_bin_vma_open,
+ .close = mon_bin_vma_close,
+ .nopage = mon_bin_vma_nopage,
+};
+
+int mon_bin_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ /* don't do anything here: "nopage" will set up page table entries */
+ vma->vm_ops = &mon_bin_vm_ops;
+ vma->vm_flags |= VM_RESERVED;
+ vma->vm_private_data = filp->private_data;
+ mon_bin_vma_open(vma);
+ return 0;
+}
+
+struct file_operations mon_fops_binary = {
+ .owner = THIS_MODULE,
+ .open = mon_bin_open,
+ .llseek = no_llseek,
+ .read = mon_bin_read,
+ /* .write = mon_text_write, */
+ .poll = mon_bin_poll,
+ .ioctl = mon_bin_ioctl,
+ .release = mon_bin_release,
+};
+
+static int mon_bin_wait_event(struct file *file, struct mon_reader_bin *rp)
+{
+ DECLARE_WAITQUEUE(waita, current);
+ unsigned long flags;
+
+ add_wait_queue(&rp->b_wait, &waita);
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ spin_lock_irqsave(&rp->b_lock, flags);
+ while (MON_RING_EMPTY(rp)) {
+ spin_unlock_irqrestore(&rp->b_lock, flags);
+
+ if (file->f_flags & O_NONBLOCK) {
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&rp->b_wait, &waita);
+ return -EWOULDBLOCK; /* Same as EAGAIN in Linux */
+ }
+ schedule();
+ if (signal_pending(current)) {
+ remove_wait_queue(&rp->b_wait, &waita);
+ return -EINTR;
+ }
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ spin_lock_irqsave(&rp->b_lock, flags);
+ }
+ spin_unlock_irqrestore(&rp->b_lock, flags);
+
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&rp->b_wait, &waita);
+ return 0;
+}
+
+static int mon_alloc_buff(struct mon_pgmap *map, int npages)
+{
+ int n;
+ unsigned long vaddr;
+
+ for (n = 0; n < npages; n++) {
+ vaddr = get_zeroed_page(GFP_KERNEL);
+ if (vaddr == 0) {
+ while (n-- != 0)
+ free_page((unsigned long) map[n].ptr);
+ return -ENOMEM;
+ }
+ map[n].ptr = (unsigned char *) vaddr;
+ map[n].pg = virt_to_page(vaddr);
+ }
+ return 0;
+}
+
+static void mon_free_buff(struct mon_pgmap *map, int npages)
+{
+ int n;
+
+ for (n = 0; n < npages; n++)
+ free_page((unsigned long) map[n].ptr);
+}
+
+int __init mon_bin_init(void)
+{
+ int rc;
+
+ rc = alloc_chrdev_region(&mon_bin_dev0, 0, MON_BIN_MAX_MINOR, "usbmon");
+ if (rc < 0)
+ goto err_dev;
+
+ cdev_init(&mon_bin_cdev, &mon_fops_binary);
+ mon_bin_cdev.owner = THIS_MODULE;
+
+ rc = cdev_add(&mon_bin_cdev, mon_bin_dev0, MON_BIN_MAX_MINOR);
+ if (rc < 0)
+ goto err_add;
+
+ return 0;
+
+err_add:
+ unregister_chrdev_region(mon_bin_dev0, MON_BIN_MAX_MINOR);
+err_dev:
+ return rc;
+}
+
+void mon_bin_exit(void)
+{
+ cdev_del(&mon_bin_cdev);
+ unregister_chrdev_region(mon_bin_dev0, MON_BIN_MAX_MINOR);
+}
diff --git a/drivers/usb/mon/mon_dma.c b/drivers/usb/mon/mon_dma.c
index ddcfc01e77a..140cc80bd2b 100644
--- a/drivers/usb/mon/mon_dma.c
+++ b/drivers/usb/mon/mon_dma.c
@@ -48,6 +48,36 @@ char mon_dmapeek(unsigned char *dst, dma_addr_t dma_addr, int len)
local_irq_restore(flags);
return 0;
}
+
+void mon_dmapeek_vec(const struct mon_reader_bin *rp,
+ unsigned int offset, dma_addr_t dma_addr, unsigned int length)
+{
+ unsigned long flags;
+ unsigned int step_len;
+ struct page *pg;
+ unsigned char *map;
+ unsigned long page_off, page_len;
+
+ local_irq_save(flags);
+ while (length) {
+ /* compute number of bytes we are going to copy in this page */
+ step_len = length;
+ page_off = dma_addr & (PAGE_SIZE-1);
+ page_len = PAGE_SIZE - page_off;
+ if (page_len < step_len)
+ step_len = page_len;
+
+ /* copy data and advance pointers */
+ pg = phys_to_page(dma_addr);
+ map = kmap_atomic(pg, KM_IRQ0);
+ offset = mon_copy_to_buff(rp, offset, map + page_off, step_len);
+ kunmap_atomic(map, KM_IRQ0);
+ dma_addr += step_len;
+ length -= step_len;
+ }
+ local_irq_restore(flags);
+}
+
#endif /* __i386__ */
#ifndef MON_HAS_UNMAP
@@ -55,4 +85,11 @@ char mon_dmapeek(unsigned char *dst, dma_addr_t dma_addr, int len)
{
return 'D';
}
-#endif
+
+void mon_dmapeek_vec(const struct mon_reader_bin *rp,
+ unsigned int offset, dma_addr_t dma_addr, unsigned int length)
+{
+ ;
+}
+
+#endif /* MON_HAS_UNMAP */
diff --git a/drivers/usb/mon/mon_main.c b/drivers/usb/mon/mon_main.c
index 394bbf2f68d..c9739e7b35e 100644
--- a/drivers/usb/mon/mon_main.c
+++ b/drivers/usb/mon/mon_main.c
@@ -9,7 +9,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/usb.h>
-#include <linux/debugfs.h>
#include <linux/smp_lock.h>
#include <linux/notifier.h>
#include <linux/mutex.h>
@@ -22,11 +21,10 @@ static void mon_complete(struct usb_bus *ubus, struct urb *urb);
static void mon_stop(struct mon_bus *mbus);
static void mon_dissolve(struct mon_bus *mbus, struct usb_bus *ubus);
static void mon_bus_drop(struct kref *r);
-static void mon_bus_init(struct dentry *mondir, struct usb_bus *ubus);
+static void mon_bus_init(struct usb_bus *ubus);
DEFINE_MUTEX(mon_lock);
-static struct dentry *mon_dir; /* /dbg/usbmon */
static LIST_HEAD(mon_buses); /* All buses we know: struct mon_bus */
/*
@@ -200,7 +198,7 @@ static void mon_stop(struct mon_bus *mbus)
*/
static void mon_bus_add(struct usb_bus *ubus)
{
- mon_bus_init(mon_dir, ubus);
+ mon_bus_init(ubus);
}
/*
@@ -212,8 +210,8 @@ static void mon_bus_remove(struct usb_bus *ubus)
mutex_lock(&mon_lock);
list_del(&mbus->bus_link);
- debugfs_remove(mbus->dent_t);
- debugfs_remove(mbus->dent_s);
+ if (mbus->text_inited)
+ mon_text_del(mbus);
mon_dissolve(mbus, ubus);
kref_put(&mbus->ref, mon_bus_drop);
@@ -281,13 +279,9 @@ static void mon_bus_drop(struct kref *r)
* - refcount USB bus struct
* - link
*/
-static void mon_bus_init(struct dentry *mondir, struct usb_bus *ubus)
+static void mon_bus_init(struct usb_bus *ubus)
{
- struct dentry *d;
struct mon_bus *mbus;
- enum { NAMESZ = 10 };
- char name[NAMESZ];
- int rc;
if ((mbus = kzalloc(sizeof(struct mon_bus), GFP_KERNEL)) == NULL)
goto err_alloc;
@@ -303,57 +297,54 @@ static void mon_bus_init(struct dentry *mondir, struct usb_bus *ubus)
ubus->mon_bus = mbus;
mbus->uses_dma = ubus->uses_dma;
- rc = snprintf(name, NAMESZ, "%dt", ubus->busnum);
- if (rc <= 0 || rc >= NAMESZ)
- goto err_print_t;
- d = debugfs_create_file(name, 0600, mondir, mbus, &mon_fops_text);
- if (d == NULL)
- goto err_create_t;
- mbus->dent_t = d;
-
- rc = snprintf(name, NAMESZ, "%ds", ubus->busnum);
- if (rc <= 0 || rc >= NAMESZ)
- goto err_print_s;
- d = debugfs_create_file(name, 0600, mondir, mbus, &mon_fops_stat);
- if (d == NULL)
- goto err_create_s;
- mbus->dent_s = d;
+ mbus->text_inited = mon_text_add(mbus, ubus);
+ // mon_bin_add(...)
mutex_lock(&mon_lock);
list_add_tail(&mbus->bus_link, &mon_buses);
mutex_unlock(&mon_lock);
return;
-err_create_s:
-err_print_s:
- debugfs_remove(mbus->dent_t);
-err_create_t:
-err_print_t:
- kfree(mbus);
err_alloc:
return;
}
+/*
+ * Search a USB bus by number. Notice that USB bus numbers start from one,
+ * which we may later use to identify "all" with zero.
+ *
+ * This function must be called with mon_lock held.
+ *
+ * This is obviously inefficient and may be revised in the future.
+ */
+struct mon_bus *mon_bus_lookup(unsigned int num)
+{
+ struct list_head *p;
+ struct mon_bus *mbus;
+
+ list_for_each (p, &mon_buses) {
+ mbus = list_entry(p, struct mon_bus, bus_link);
+ if (mbus->u_bus->busnum == num) {
+ return mbus;
+ }
+ }
+ return NULL;
+}
+
static int __init mon_init(void)
{
struct usb_bus *ubus;
- struct dentry *mondir;
+ int rc;
- mondir = debugfs_create_dir("usbmon", NULL);
- if (IS_ERR(mondir)) {
- printk(KERN_NOTICE TAG ": debugfs is not available\n");
- return -ENODEV;
- }
- if (mondir == NULL) {
- printk(KERN_NOTICE TAG ": unable to create usbmon directory\n");
- return -ENODEV;
- }
- mon_dir = mondir;
+ if ((rc = mon_text_init()) != 0)
+ goto err_text;
+ if ((rc = mon_bin_init()) != 0)
+ goto err_bin;
if (usb_mon_register(&mon_ops_0) != 0) {
printk(KERN_NOTICE TAG ": unable to register with the core\n");
- debugfs_remove(mondir);
- return -ENODEV;
+ rc = -ENODEV;
+ goto err_reg;
}
// MOD_INC_USE_COUNT(which_module?);
@@ -361,10 +352,17 @@ static int __init mon_init(void)
mutex_lock(&usb_bus_list_lock);
list_for_each_entry (ubus, &usb_bus_list, bus_list) {
- mon_bus_init(mondir, ubus);
+ mon_bus_init(ubus);
}
mutex_unlock(&usb_bus_list_lock);
return 0;
+
+err_reg:
+ mon_bin_exit();
+err_bin:
+ mon_text_exit();
+err_text:
+ return rc;
}
static void __exit mon_exit(void)
@@ -381,8 +379,8 @@ static void __exit mon_exit(void)
mbus = list_entry(p, struct mon_bus, bus_link);
list_del(p);
- debugfs_remove(mbus->dent_t);
- debugfs_remove(mbus->dent_s);
+ if (mbus->text_inited)
+ mon_text_del(mbus);
/*
* This never happens, because the open/close paths in
@@ -401,7 +399,8 @@ static void __exit mon_exit(void)
}
mutex_unlock(&mon_lock);
- debugfs_remove(mon_dir);
+ mon_text_exit();
+ mon_bin_exit();
}
module_init(mon_init);
diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c
index 05cf2c9a8f8..494ee3b9a22 100644
--- a/drivers/usb/mon/mon_text.c
+++ b/drivers/usb/mon/mon_text.c
@@ -9,6 +9,7 @@
#include <linux/usb.h>
#include <linux/time.h>
#include <linux/mutex.h>
+#include <linux/debugfs.h>
#include <asm/uaccess.h>
#include "usb_mon.h"
@@ -63,6 +64,8 @@ struct mon_reader_text {
char slab_name[SLAB_NAME_SZ];
};
+static struct dentry *mon_dir; /* Usually /sys/kernel/debug/usbmon */
+
static void mon_text_ctor(void *, struct kmem_cache *, unsigned long);
/*
@@ -436,7 +439,7 @@ static int mon_text_release(struct inode *inode, struct file *file)
return 0;
}
-const struct file_operations mon_fops_text = {
+static const struct file_operations mon_fops_text = {
.owner = THIS_MODULE,
.open = mon_text_open,
.llseek = no_llseek,
@@ -447,6 +450,47 @@ const struct file_operations mon_fops_text = {
.release = mon_text_release,
};
+int mon_text_add(struct mon_bus *mbus, const struct usb_bus *ubus)
+{
+ struct dentry *d;
+ enum { NAMESZ = 10 };
+ char name[NAMESZ];
+ int rc;
+
+ rc = snprintf(name, NAMESZ, "%dt", ubus->busnum);
+ if (rc <= 0 || rc >= NAMESZ)
+ goto err_print_t;
+ d = debugfs_create_file(name, 0600, mon_dir, mbus, &mon_fops_text);
+ if (d == NULL)
+ goto err_create_t;
+ mbus->dent_t = d;
+
+ /* XXX The stats do not belong to here (text API), but oh well... */
+ rc = snprintf(name, NAMESZ, "%ds", ubus->busnum);
+ if (rc <= 0 || rc >= NAMESZ)
+ goto err_print_s;
+ d = debugfs_create_file(name, 0600, mon_dir, mbus, &mon_fops_stat);
+ if (d == NULL)
+ goto err_create_s;
+ mbus->dent_s = d;
+
+ return 1;
+
+err_create_s:
+err_print_s:
+ debugfs_remove(mbus->dent_t);
+ mbus->dent_t = NULL;
+err_create_t:
+err_print_t:
+ return 0;
+}
+
+void mon_text_del(struct mon_bus *mbus)
+{
+ debugfs_remove(mbus->dent_t);
+ debugfs_remove(mbus->dent_s);
+}
+
/*
* Slab interface: constructor.
*/
@@ -459,3 +503,24 @@ static void mon_text_ctor(void *mem, struct kmem_cache *slab, unsigned long sfla
memset(mem, 0xe5, sizeof(struct mon_event_text));
}
+int __init mon_text_init(void)
+{
+ struct dentry *mondir;
+
+ mondir = debugfs_create_dir("usbmon", NULL);
+ if (IS_ERR(mondir)) {
+ printk(KERN_NOTICE TAG ": debugfs is not available\n");
+ return -ENODEV;
+ }
+ if (mondir == NULL) {
+ printk(KERN_NOTICE TAG ": unable to create usbmon directory\n");
+ return -ENODEV;
+ }
+ mon_dir = mondir;
+ return 0;
+}
+
+void mon_text_exit(void)
+{
+ debugfs_remove(mon_dir);
+}
diff --git a/drivers/usb/mon/usb_mon.h b/drivers/usb/mon/usb_mon.h
index ab9d02d5df7..efdfd8993d9 100644
--- a/drivers/usb/mon/usb_mon.h
+++ b/drivers/usb/mon/usb_mon.h
@@ -17,9 +17,11 @@
struct mon_bus {
struct list_head bus_link;
spinlock_t lock;
+ struct usb_bus *u_bus;
+
+ int text_inited;
struct dentry *dent_s; /* Debugging file */
struct dentry *dent_t; /* Text interface file */
- struct usb_bus *u_bus;
int uses_dma;
/* Ref */
@@ -48,13 +50,35 @@ struct mon_reader {
void mon_reader_add(struct mon_bus *mbus, struct mon_reader *r);
void mon_reader_del(struct mon_bus *mbus, struct mon_reader *r);
+struct mon_bus *mon_bus_lookup(unsigned int num);
+
+int /*bool*/ mon_text_add(struct mon_bus *mbus, const struct usb_bus *ubus);
+void mon_text_del(struct mon_bus *mbus);
+// void mon_bin_add(struct mon_bus *);
+
+int __init mon_text_init(void);
+void mon_text_exit(void);
+int __init mon_bin_init(void);
+void mon_bin_exit(void);
+
/*
- */
+ * DMA interface.
+ *
+ * XXX The vectored side needs a serious re-thinking. Abstracting vectors,
+ * like in Paolo's original patch, produces a double pkmap. We need an idea.
+*/
extern char mon_dmapeek(unsigned char *dst, dma_addr_t dma_addr, int len);
+struct mon_reader_bin;
+extern void mon_dmapeek_vec(const struct mon_reader_bin *rp,
+ unsigned int offset, dma_addr_t dma_addr, unsigned int len);
+extern unsigned int mon_copy_to_buff(const struct mon_reader_bin *rp,
+ unsigned int offset, const unsigned char *from, unsigned int len);
+
+/*
+ */
extern struct mutex mon_lock;
-extern const struct file_operations mon_fops_text;
extern const struct file_operations mon_fops_stat;
#endif /* __USB_MON_H */
diff --git a/drivers/usb/net/Kconfig b/drivers/usb/net/Kconfig
index e081836014a..3de564b2314 100644
--- a/drivers/usb/net/Kconfig
+++ b/drivers/usb/net/Kconfig
@@ -84,6 +84,7 @@ config USB_PEGASUS
config USB_RTL8150
tristate "USB RTL8150 based ethernet device support (EXPERIMENTAL)"
depends on EXPERIMENTAL
+ select MII
help
Say Y here if you have RTL8150 based usb-ethernet adapter.
Send me <petkan@users.sourceforge.net> any comments you may have.
@@ -98,7 +99,7 @@ config USB_USBNET_MII
config USB_USBNET
tristate "Multi-purpose USB Networking Framework"
- select MII if USBNET_MII != n
+ select MII if USB_USBNET_MII != n
---help---
This driver supports several kinds of network links over USB,
with "minidrivers" built around a common network driver core
@@ -185,6 +186,15 @@ config USB_NET_CDCETHER
IEEE 802 "local assignment" bit is set in the address, a "usbX"
name is used instead.
+config USB_NET_DM9601
+ tristate "Davicom DM9601 based USB 1.1 10/100 ethernet devices"
+ depends on USB_USBNET
+ select CRC32
+ select USB_USBNET_MII
+ help
+ This option adds support for Davicom DM9601 based USB 1.1
+ 10/100 Ethernet adapters.
+
config USB_NET_GL620A
tristate "GeneSys GL620USB-A based cables"
depends on USB_USBNET
@@ -222,13 +232,15 @@ config USB_NET_MCS7830
adapters marketed under the DeLOCK brand.
config USB_NET_RNDIS_HOST
- tristate "Host for RNDIS devices (EXPERIMENTAL)"
+ tristate "Host for RNDIS and ActiveSync devices (EXPERIMENTAL)"
depends on USB_USBNET && EXPERIMENTAL
select USB_NET_CDCETHER
help
This option enables hosting "Remote NDIS" USB networking links,
as encouraged by Microsoft (instead of CDC Ethernet!) for use in
- various devices that may only support this protocol.
+ various devices that may only support this protocol. A variant
+ of this protocol (with even less public documentation) seems to
+ be at the root of Microsoft's "ActiveSync" too.
Avoid using this protocol unless you have no better options.
The protocol specification is incomplete, and is controlled by
@@ -237,6 +249,7 @@ config USB_NET_RNDIS_HOST
config USB_NET_CDC_SUBSET
tristate "Simple USB Network Links (CDC Ethernet subset)"
depends on USB_USBNET
+ default y
help
This driver module supports USB network devices that can work
without any device-specific information. Select it if you have
@@ -296,6 +309,13 @@ config USB_EPSON2888
Choose this option to support the usb networking links used
by some sample firmware from Epson.
+config USB_KC2190
+ boolean "KT Technology KC2190 based cables (InstaNet)"
+ depends on USB_NET_CDC_SUBSET && EXPERIMENTAL
+ help
+  Choose this option if you're using a host-to-host cable
+  with one of these chips.
+
config USB_NET_ZAURUS
tristate "Sharp Zaurus (stock ROMs) and compatible"
depends on USB_USBNET
diff --git a/drivers/usb/net/Makefile b/drivers/usb/net/Makefile
index 7b51964de17..595a539f838 100644
--- a/drivers/usb/net/Makefile
+++ b/drivers/usb/net/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_USB_PEGASUS) += pegasus.o
obj-$(CONFIG_USB_RTL8150) += rtl8150.o
obj-$(CONFIG_USB_NET_AX8817X) += asix.o
obj-$(CONFIG_USB_NET_CDCETHER) += cdc_ether.o
+obj-$(CONFIG_USB_NET_DM9601) += dm9601.o
obj-$(CONFIG_USB_NET_GL620A) += gl620a.o
obj-$(CONFIG_USB_NET_NET1080) += net1080.o
obj-$(CONFIG_USB_NET_PLUSB) += plusb.o
diff --git a/drivers/usb/net/asix.c b/drivers/usb/net/asix.c
index 896449f0cf8..5808ea08245 100644
--- a/drivers/usb/net/asix.c
+++ b/drivers/usb/net/asix.c
@@ -25,7 +25,6 @@
#include <linux/module.h>
#include <linux/kmod.h>
-#include <linux/sched.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
@@ -352,9 +351,11 @@ static struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
skb_push(skb, 4);
packet_len = (((skb->len - 4) ^ 0x0000ffff) << 16) + (skb->len - 4);
+ cpu_to_le32s(&packet_len);
memcpy(skb->data, &packet_len, sizeof(packet_len));
if ((skb->len % 512) == 0) {
+ cpu_to_le32s(&padbytes);
memcpy( skb->tail, &padbytes, sizeof(padbytes));
skb_put(skb, sizeof(padbytes));
}
@@ -1394,9 +1395,9 @@ static const struct usb_device_id products [] = {
USB_DEVICE (0x07b8, 0x420a),
.driver_info = (unsigned long) &hawking_uf200_info,
}, {
- // Billionton Systems, USB2AR
- USB_DEVICE (0x08dd, 0x90ff),
- .driver_info = (unsigned long) &ax8817x_info,
+ // Billionton Systems, USB2AR
+ USB_DEVICE (0x08dd, 0x90ff),
+ .driver_info = (unsigned long) &ax8817x_info,
}, {
// ATEN UC210T
USB_DEVICE (0x0557, 0x2009),
@@ -1422,9 +1423,13 @@ static const struct usb_device_id products [] = {
USB_DEVICE (0x1631, 0x6200),
.driver_info = (unsigned long) &ax8817x_info,
}, {
+ // JVC MP-PRX1 Port Replicator
+ USB_DEVICE (0x04f1, 0x3008),
+ .driver_info = (unsigned long) &ax8817x_info,
+}, {
// ASIX AX88772 10/100
- USB_DEVICE (0x0b95, 0x7720),
- .driver_info = (unsigned long) &ax88772_info,
+ USB_DEVICE (0x0b95, 0x7720),
+ .driver_info = (unsigned long) &ax88772_info,
}, {
// ASIX AX88178 10/100/1000
USB_DEVICE (0x0b95, 0x1780),
@@ -1449,6 +1454,10 @@ static const struct usb_device_id products [] = {
// Linksys USB1000
USB_DEVICE (0x1737, 0x0039),
.driver_info = (unsigned long) &ax88178_info,
+}, {
+ // IO-DATA ETG-US2
+ USB_DEVICE (0x04bb, 0x0930),
+ .driver_info = (unsigned long) &ax88178_info,
},
{ }, // END
};
diff --git a/drivers/usb/net/cdc_ether.c b/drivers/usb/net/cdc_ether.c
index 44a91547146..5a21f06bf8a 100644
--- a/drivers/usb/net/cdc_ether.c
+++ b/drivers/usb/net/cdc_ether.c
@@ -1,6 +1,7 @@
/*
* CDC Ethernet based networking peripherals
* Copyright (C) 2003-2005 by David Brownell
+ * Copyright (C) 2006 by Ole Andre Vadla Ravnas (ActiveSync)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -21,7 +22,6 @@
// #define VERBOSE // more; success messages
#include <linux/module.h>
-#include <linux/sched.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
@@ -35,6 +35,29 @@
#include "usbnet.h"
+#if defined(CONFIG_USB_NET_RNDIS_HOST) || defined(CONFIG_USB_NET_RNDIS_HOST_MODULE)
+
+static int is_rndis(struct usb_interface_descriptor *desc)
+{
+ return desc->bInterfaceClass == USB_CLASS_COMM
+ && desc->bInterfaceSubClass == 2
+ && desc->bInterfaceProtocol == 0xff;
+}
+
+static int is_activesync(struct usb_interface_descriptor *desc)
+{
+ return desc->bInterfaceClass == USB_CLASS_MISC
+ && desc->bInterfaceSubClass == 1
+ && desc->bInterfaceProtocol == 1;
+}
+
+#else
+
+#define is_rndis(desc) 0
+#define is_activesync(desc) 0
+
+#endif
+
/*
* probes control interface, claims data interface, collects the bulk
* endpoints, activates data interface (if needed), maybe sets MTU.
@@ -71,7 +94,8 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
/* this assumes that if there's a non-RNDIS vendor variant
* of cdc-acm, it'll fail RNDIS requests cleanly.
*/
- rndis = (intf->cur_altsetting->desc.bInterfaceProtocol == 0xff);
+ rndis = is_rndis(&intf->cur_altsetting->desc)
+ || is_activesync(&intf->cur_altsetting->desc);
memset(info, 0, sizeof *info);
info->control = intf;
@@ -99,6 +123,23 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
goto bad_desc;
}
break;
+ case USB_CDC_ACM_TYPE:
+ /* paranoia: disambiguate a "real" vendor-specific
+ * modem interface from an RNDIS non-modem.
+ */
+ if (rndis) {
+ struct usb_cdc_acm_descriptor *d;
+
+ d = (void *) buf;
+ if (d->bmCapabilities) {
+ dev_dbg(&intf->dev,
+ "ACM capabilities %02x, "
+ "not really RNDIS?\n",
+ d->bmCapabilities);
+ goto bad_desc;
+ }
+ }
+ break;
case USB_CDC_UNION_TYPE:
if (info->u) {
dev_dbg(&intf->dev, "extra CDC union\n");
@@ -171,7 +212,21 @@ next_desc:
buf += buf [0];
}
- if (!info->header || !info->u || (!rndis && !info->ether)) {
+ /* Microsoft ActiveSync based RNDIS devices lack the CDC descriptors,
+ * so we'll hard-wire the interfaces and not check for descriptors.
+ */
+ if (is_activesync(&intf->cur_altsetting->desc) && !info->u) {
+ info->control = usb_ifnum_to_if(dev->udev, 0);
+ info->data = usb_ifnum_to_if(dev->udev, 1);
+ if (!info->control || !info->data) {
+ dev_dbg(&intf->dev,
+ "activesync: master #0/%p slave #1/%p\n",
+ info->control,
+ info->data);
+ goto bad_desc;
+ }
+
+ } else if (!info->header || !info->u || (!rndis && !info->ether)) {
dev_dbg(&intf->dev, "missing cdc %s%s%sdescriptor\n",
info->header ? "" : "header ",
info->u ? "" : "union ",
diff --git a/drivers/usb/net/cdc_subset.c b/drivers/usb/net/cdc_subset.c
index e2fae85851a..bc62b012602 100644
--- a/drivers/usb/net/cdc_subset.c
+++ b/drivers/usb/net/cdc_subset.c
@@ -19,7 +19,6 @@
#include <linux/module.h>
#include <linux/kmod.h>
-#include <linux/sched.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
@@ -80,13 +79,19 @@ static int always_connected (struct usbnet *dev)
*
* ALi M5632 driver ... does high speed
*
+ * NOTE that the MS-Windows drivers for this chip use some funky and
+ * (naturally) undocumented 7-byte prefix to each packet, so this is a
+ * case where we don't currently interoperate. Also, once you unplug
+ * one end of the cable, you need to replug the other end too ... since
+ * chip docs are unavailable, there's no way to reset the relevant state
+ * short of a power cycle.
+ *
*-------------------------------------------------------------------------*/
static const struct driver_info ali_m5632_info = {
.description = "ALi M5632",
};
-
#endif
@@ -160,6 +165,11 @@ static const struct driver_info epson2888_info = {
#endif /* CONFIG_USB_EPSON2888 */
+/*-------------------------------------------------------------------------
+ *
+ * info from Jonathan McDowell <noodles@earth.li>
+ *
+ *-------------------------------------------------------------------------*/
#ifdef CONFIG_USB_KC2190
#define HAVE_HARDWARE
static const struct driver_info kc2190_info = {
@@ -224,6 +234,10 @@ static const struct usb_device_id products [] = {
USB_DEVICE (0x0402, 0x5632), // ALi defaults
.driver_info = (unsigned long) &ali_m5632_info,
},
+{
+ USB_DEVICE (0x182d,0x207c), // SiteCom CN-124
+ .driver_info = (unsigned long) &ali_m5632_info,
+},
#endif
#ifdef CONFIG_USB_AN2720
@@ -315,13 +329,13 @@ static struct usb_driver cdc_subset_driver = {
static int __init cdc_subset_init(void)
{
- return usb_register(&cdc_subset_driver);
+ return usb_register(&cdc_subset_driver);
}
module_init(cdc_subset_init);
static void __exit cdc_subset_exit(void)
{
- usb_deregister(&cdc_subset_driver);
+ usb_deregister(&cdc_subset_driver);
}
module_exit(cdc_subset_exit);
diff --git a/drivers/usb/net/dm9601.c b/drivers/usb/net/dm9601.c
new file mode 100644
index 00000000000..4a932e1cd93
--- /dev/null
+++ b/drivers/usb/net/dm9601.c
@@ -0,0 +1,606 @@
+/*
+ * Davicom DM9601 USB 1.1 10/100Mbps ethernet devices
+ *
+ * Peter Korsgaard <jacmet@sunsite.dk>
+ *
+ * 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.
+ */
+
+//#define DEBUG
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/usb.h>
+#include <linux/crc32.h>
+
+#include "usbnet.h"
+
+/* datasheet:
+ http://www.davicom.com.tw/big5/download/Data%20Sheet/DM9601-DS-P01-930914.pdf
+*/
+
+/* control requests */
+#define DM_READ_REGS 0x00
+#define DM_WRITE_REGS 0x01
+#define DM_READ_MEMS 0x02
+#define DM_WRITE_REG 0x03
+#define DM_WRITE_MEMS 0x05
+#define DM_WRITE_MEM 0x07
+
+/* registers */
+#define DM_NET_CTRL 0x00
+#define DM_RX_CTRL 0x05
+#define DM_SHARED_CTRL 0x0b
+#define DM_SHARED_ADDR 0x0c
+#define DM_SHARED_DATA 0x0d /* low + high */
+#define DM_PHY_ADDR 0x10 /* 6 bytes */
+#define DM_MCAST_ADDR 0x16 /* 8 bytes */
+#define DM_GPR_CTRL 0x1e
+#define DM_GPR_DATA 0x1f
+
+#define DM_MAX_MCAST 64
+#define DM_MCAST_SIZE 8
+#define DM_EEPROM_LEN 256
+#define DM_TX_OVERHEAD 2 /* 2 byte header */
+#define DM_RX_OVERHEAD 7 /* 3 byte header + 4 byte crc tail */
+#define DM_TIMEOUT 1000
+
+
+static int dm_read(struct usbnet *dev, u8 reg, u16 length, void *data)
+{
+ devdbg(dev, "dm_read() reg=0x%02x length=%d", reg, length);
+ return usb_control_msg(dev->udev,
+ usb_rcvctrlpipe(dev->udev, 0),
+ DM_READ_REGS,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, reg, data, length, USB_CTRL_SET_TIMEOUT);
+}
+
+static int dm_read_reg(struct usbnet *dev, u8 reg, u8 *value)
+{
+ return dm_read(dev, reg, 1, value);
+}
+
+static int dm_write(struct usbnet *dev, u8 reg, u16 length, void *data)
+{
+ devdbg(dev, "dm_write() reg=0x%02x, length=%d", reg, length);
+ return usb_control_msg(dev->udev,
+ usb_sndctrlpipe(dev->udev, 0),
+ DM_WRITE_REGS,
+ USB_DIR_OUT | USB_TYPE_VENDOR |USB_RECIP_DEVICE,
+ 0, reg, data, length, USB_CTRL_SET_TIMEOUT);
+}
+
+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);
+ return usb_control_msg(dev->udev,
+ usb_sndctrlpipe(dev->udev, 0),
+ DM_WRITE_REG,
+ USB_DIR_OUT | USB_TYPE_VENDOR |USB_RECIP_DEVICE,
+ value, reg, 0, 0, USB_CTRL_SET_TIMEOUT);
+}
+
+static void dm_write_async_callback(struct urb *urb)
+{
+ struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context;
+
+ if (urb->status < 0)
+ printk(KERN_DEBUG "dm_write_async_callback() failed with %d",
+ urb->status);
+
+ kfree(req);
+ usb_free_urb(urb);
+}
+
+static void dm_write_async(struct usbnet *dev, u8 reg, u16 length, void *data)
+{
+ struct usb_ctrlrequest *req;
+ struct urb *urb;
+ int status;
+
+ devdbg(dev, "dm_write_async() reg=0x%02x length=%d", reg, length);
+
+ urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!urb) {
+ deverr(dev, "Error allocating URB in dm_write_async!");
+ return;
+ }
+
+ req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC);
+ if (!req) {
+ deverr(dev, "Failed to allocate memory for control request");
+ usb_free_urb(urb);
+ return;
+ }
+
+ req->bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE;
+ req->bRequest = DM_WRITE_REGS;
+ req->wValue = 0;
+ req->wIndex = cpu_to_le16(reg);
+ req->wLength = cpu_to_le16(length);
+
+ usb_fill_control_urb(urb, dev->udev,
+ usb_sndctrlpipe(dev->udev, 0),
+ (void *)req, data, length,
+ dm_write_async_callback, req);
+
+ status = usb_submit_urb(urb, GFP_ATOMIC);
+ if (status < 0) {
+ deverr(dev, "Error submitting the control message: status=%d",
+ status);
+ kfree(req);
+ usb_free_urb(urb);
+ }
+}
+
+static void dm_write_reg_async(struct usbnet *dev, u8 reg, u8 value)
+{
+ struct usb_ctrlrequest *req;
+ struct urb *urb;
+ int status;
+
+ devdbg(dev, "dm_write_reg_async() reg=0x%02x value=0x%02x",
+ reg, value);
+
+ urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!urb) {
+ deverr(dev, "Error allocating URB in dm_write_async!");
+ return;
+ }
+
+ req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC);
+ if (!req) {
+ deverr(dev, "Failed to allocate memory for control request");
+ usb_free_urb(urb);
+ return;
+ }
+
+ req->bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE;
+ req->bRequest = DM_WRITE_REG;
+ req->wValue = cpu_to_le16(value);
+ req->wIndex = cpu_to_le16(reg);
+ req->wLength = 0;
+
+ usb_fill_control_urb(urb, dev->udev,
+ usb_sndctrlpipe(dev->udev, 0),
+ (void *)req, 0, 0, dm_write_async_callback, req);
+
+ status = usb_submit_urb(urb, GFP_ATOMIC);
+ if (status < 0) {
+ deverr(dev, "Error submitting the control message: status=%d",
+ status);
+ kfree(req);
+ usb_free_urb(urb);
+ }
+}
+
+static int dm_read_shared_word(struct usbnet *dev, int phy, u8 reg, u16 *value)
+{
+ int ret, i;
+
+ mutex_lock(&dev->phy_mutex);
+
+ dm_write_reg(dev, DM_SHARED_ADDR, phy ? (reg | 0x40) : reg);
+ dm_write_reg(dev, DM_SHARED_CTRL, phy ? 0xc : 0x4);
+
+ for (i = 0; i < DM_TIMEOUT; i++) {
+ u8 tmp;
+
+ udelay(1);
+ ret = dm_read_reg(dev, DM_SHARED_CTRL, &tmp);
+ if (ret < 0)
+ goto out;
+
+ /* ready */
+ if ((tmp & 1) == 0)
+ break;
+ }
+
+ if (i == DM_TIMEOUT) {
+ deverr(dev, "%s read timed out!", phy ? "phy" : "eeprom");
+ ret = -EIO;
+ goto out;
+ }
+
+ 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);
+
+ out:
+ mutex_unlock(&dev->phy_mutex);
+ return ret;
+}
+
+static int dm_write_shared_word(struct usbnet *dev, int phy, u8 reg, u16 value)
+{
+ int ret, i;
+
+ mutex_lock(&dev->phy_mutex);
+
+ ret = dm_write(dev, DM_SHARED_DATA, 2, &value);
+ if (ret < 0)
+ goto out;
+
+ dm_write_reg(dev, DM_SHARED_ADDR, phy ? (reg | 0x40) : reg);
+ dm_write_reg(dev, DM_SHARED_CTRL, phy ? 0x1c : 0x14);
+
+ for (i = 0; i < DM_TIMEOUT; i++) {
+ u8 tmp;
+
+ udelay(1);
+ ret = dm_read_reg(dev, DM_SHARED_CTRL, &tmp);
+ if (ret < 0)
+ goto out;
+
+ /* ready */
+ if ((tmp & 1) == 0)
+ break;
+ }
+
+ if (i == DM_TIMEOUT) {
+ deverr(dev, "%s write timed out!", phy ? "phy" : "eeprom");
+ ret = -EIO;
+ goto out;
+ }
+
+ dm_write_reg(dev, DM_SHARED_CTRL, 0x0);
+
+out:
+ mutex_unlock(&dev->phy_mutex);
+ return ret;
+}
+
+static int dm_read_eeprom_word(struct usbnet *dev, u8 offset, void *value)
+{
+ return dm_read_shared_word(dev, 0, offset, value);
+}
+
+
+
+static int dm9601_get_eeprom_len(struct net_device *dev)
+{
+ return DM_EEPROM_LEN;
+}
+
+static int dm9601_get_eeprom(struct net_device *net,
+ struct ethtool_eeprom *eeprom, u8 * data)
+{
+ struct usbnet *dev = netdev_priv(net);
+ u16 *ebuf = (u16 *) data;
+ int i;
+
+ /* access is 16bit */
+ if ((eeprom->offset % 2) || (eeprom->len % 2))
+ return -EINVAL;
+
+ for (i = 0; i < eeprom->len / 2; i++) {
+ if (dm_read_eeprom_word(dev, eeprom->offset / 2 + i,
+ &ebuf[i]) < 0)
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int dm9601_mdio_read(struct net_device *netdev, int phy_id, int loc)
+{
+ struct usbnet *dev = netdev_priv(netdev);
+
+ u16 res;
+
+ if (phy_id) {
+ devdbg(dev, "Only internal phy supported");
+ 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));
+
+ return le16_to_cpu(res);
+}
+
+static void dm9601_mdio_write(struct net_device *netdev, int phy_id, int loc,
+ int val)
+{
+ struct usbnet *dev = netdev_priv(netdev);
+ u16 res = cpu_to_le16(val);
+
+ if (phy_id) {
+ devdbg(dev, "Only internal phy supported");
+ return;
+ }
+
+ devdbg(dev,"dm9601_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x",
+ phy_id, loc, val);
+
+ dm_write_shared_word(dev, 1, loc, res);
+}
+
+static void dm9601_get_drvinfo(struct net_device *net,
+ struct ethtool_drvinfo *info)
+{
+ /* Inherit standard device info */
+ usbnet_get_drvinfo(net, info);
+ info->eedump_len = DM_EEPROM_LEN;
+}
+
+static u32 dm9601_get_link(struct net_device *net)
+{
+ struct usbnet *dev = netdev_priv(net);
+
+ return mii_link_ok(&dev->mii);
+}
+
+static int dm9601_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
+{
+ struct usbnet *dev = netdev_priv(net);
+
+ return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
+}
+
+static struct ethtool_ops dm9601_ethtool_ops = {
+ .get_drvinfo = dm9601_get_drvinfo,
+ .get_link = dm9601_get_link,
+ .get_msglevel = usbnet_get_msglevel,
+ .set_msglevel = usbnet_set_msglevel,
+ .get_eeprom_len = dm9601_get_eeprom_len,
+ .get_eeprom = dm9601_get_eeprom,
+ .get_settings = usbnet_get_settings,
+ .set_settings = usbnet_set_settings,
+ .nway_reset = usbnet_nway_reset,
+};
+
+static void dm9601_set_multicast(struct net_device *net)
+{
+ struct usbnet *dev = netdev_priv(net);
+ /* We use the 20 byte dev->data for our 8 byte filter buffer
+ * to avoid allocating memory that is tricky to free later */
+ u8 *hashes = (u8 *) & dev->data;
+ u8 rx_ctl = 0x01;
+
+ memset(hashes, 0x00, DM_MCAST_SIZE);
+ hashes[DM_MCAST_SIZE - 1] |= 0x80; /* broadcast address */
+
+ if (net->flags & IFF_PROMISC) {
+ rx_ctl |= 0x02;
+ } else if (net->flags & IFF_ALLMULTI || net->mc_count > DM_MAX_MCAST) {
+ rx_ctl |= 0x04;
+ } else if (net->mc_count) {
+ struct dev_mc_list *mc_list = net->mc_list;
+ int i;
+
+ for (i = 0; i < net->mc_count; i++) {
+ u32 crc = ether_crc(ETH_ALEN, mc_list->dmi_addr) >> 26;
+ hashes[crc >> 3] |= 1 << (crc & 0x7);
+ }
+ }
+
+ dm_write_async(dev, DM_MCAST_ADDR, DM_MCAST_SIZE, hashes);
+ dm_write_reg_async(dev, DM_RX_CTRL, rx_ctl);
+}
+
+static int dm9601_bind(struct usbnet *dev, struct usb_interface *intf)
+{
+ int ret;
+
+ ret = usbnet_get_endpoints(dev, intf);
+ if (ret)
+ goto out;
+
+ dev->net->do_ioctl = dm9601_ioctl;
+ dev->net->set_multicast_list = dm9601_set_multicast;
+ dev->net->ethtool_ops = &dm9601_ethtool_ops;
+ dev->net->hard_header_len += DM_TX_OVERHEAD;
+ dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len;
+ dev->rx_urb_size = dev->net->mtu + DM_RX_OVERHEAD;
+
+ dev->mii.dev = dev->net;
+ dev->mii.mdio_read = dm9601_mdio_read;
+ dev->mii.mdio_write = dm9601_mdio_write;
+ dev->mii.phy_id_mask = 0x1f;
+ dev->mii.reg_num_mask = 0x1f;
+
+ /* reset */
+ ret = dm_write_reg(dev, DM_NET_CTRL, 1);
+ udelay(20);
+
+ /* read MAC */
+ ret = dm_read(dev, DM_PHY_ADDR, ETH_ALEN, dev->net->dev_addr);
+ if (ret < 0) {
+ printk(KERN_ERR "Error reading MAC address\n");
+ ret = -ENODEV;
+ goto out;
+ }
+
+
+ /* power up phy */
+ dm_write_reg(dev, DM_GPR_CTRL, 1);
+ dm_write_reg(dev, DM_GPR_DATA, 0);
+
+ /* receive broadcast packets */
+ dm9601_set_multicast(dev->net);
+
+ dm9601_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
+ dm9601_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE,
+ ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
+ mii_nway_restart(&dev->mii);
+
+out:
+ return ret;
+}
+
+static int dm9601_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
+{
+ u8 status;
+ int len;
+
+ /* format:
+ b0: rx status
+ b1: packet length (incl crc) low
+ b2: packet length (incl crc) high
+ b3..n-4: packet data
+ bn-3..bn: ethernet crc
+ */
+
+ if (unlikely(skb->len < DM_RX_OVERHEAD)) {
+ dev_err(&dev->udev->dev, "unexpected tiny rx frame\n");
+ return 0;
+ }
+
+ status = skb->data[0];
+ len = (skb->data[1] | (skb->data[2] << 8)) - 4;
+
+ if (unlikely(status & 0xbf)) {
+ if (status & 0x01) dev->stats.rx_fifo_errors++;
+ if (status & 0x02) dev->stats.rx_crc_errors++;
+ if (status & 0x04) dev->stats.rx_frame_errors++;
+ if (status & 0x20) dev->stats.rx_missed_errors++;
+ if (status & 0x90) dev->stats.rx_length_errors++;
+ return 0;
+ }
+
+ skb_pull(skb, 3);
+ skb_trim(skb, len);
+
+ return 1;
+}
+
+static struct sk_buff *dm9601_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
+ gfp_t flags)
+{
+ int len;
+
+ /* format:
+ b0: packet length low
+ b1: packet length high
+ b3..n: packet data
+ */
+
+ if (skb_headroom(skb) < DM_TX_OVERHEAD) {
+ struct sk_buff *skb2;
+
+ skb2 = skb_copy_expand(skb, DM_TX_OVERHEAD, 0, flags);
+ dev_kfree_skb_any(skb);
+ skb = skb2;
+ if (!skb)
+ return NULL;
+ }
+
+ __skb_push(skb, DM_TX_OVERHEAD);
+
+ len = skb->len;
+ /* usbnet adds padding if length is a multiple of packet size
+ if so, adjust length value in header */
+ if ((len % dev->maxpacket) == 0)
+ len++;
+
+ skb->data[0] = len;
+ skb->data[1] = len >> 8;
+
+ return skb;
+}
+
+static void dm9601_status(struct usbnet *dev, struct urb *urb)
+{
+ int link;
+ u8 *buf;
+
+ /* format:
+ b0: net status
+ b1: tx status 1
+ b2: tx status 2
+ b3: rx status
+ b4: rx overflow
+ b5: rx count
+ b6: tx count
+ b7: gpr
+ */
+
+ if (urb->actual_length < 8)
+ return;
+
+ buf = urb->transfer_buffer;
+
+ link = !!(buf[0] & 0x40);
+ if (netif_carrier_ok(dev->net) != link) {
+ if (link) {
+ netif_carrier_on(dev->net);
+ usbnet_defer_kevent (dev, EVENT_LINK_RESET);
+ }
+ else
+ netif_carrier_off(dev->net);
+ devdbg(dev, "Link Status is: %d", link);
+ }
+}
+
+static int dm9601_link_reset(struct usbnet *dev)
+{
+ struct ethtool_cmd ecmd;
+
+ 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);
+
+ return 0;
+}
+
+static const struct driver_info dm9601_info = {
+ .description = "Davicom DM9601 USB Ethernet",
+ .flags = FLAG_ETHER,
+ .bind = dm9601_bind,
+ .rx_fixup = dm9601_rx_fixup,
+ .tx_fixup = dm9601_tx_fixup,
+ .status = dm9601_status,
+ .link_reset = dm9601_link_reset,
+ .reset = dm9601_link_reset,
+};
+
+static const struct usb_device_id products[] = {
+ {
+ USB_DEVICE(0x0a46, 0x9601), /* Davicom USB-100 */
+ .driver_info = (unsigned long)&dm9601_info,
+ },
+ {}, // END
+};
+
+MODULE_DEVICE_TABLE(usb, products);
+
+static struct usb_driver dm9601_driver = {
+ .name = "dm9601",
+ .id_table = products,
+ .probe = usbnet_probe,
+ .disconnect = usbnet_disconnect,
+ .suspend = usbnet_suspend,
+ .resume = usbnet_resume,
+};
+
+static int __init dm9601_init(void)
+{
+ return usb_register(&dm9601_driver);
+}
+
+static void __exit dm9601_exit(void)
+{
+ usb_deregister(&dm9601_driver);
+}
+
+module_init(dm9601_init);
+module_exit(dm9601_exit);
+
+MODULE_AUTHOR("Peter Korsgaard <jacmet@sunsite.dk>");
+MODULE_DESCRIPTION("Davicom DM9601 USB 1.1 ethernet devices");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/net/gl620a.c b/drivers/usb/net/gl620a.c
index a6f0f4d934d..d257a8e026d 100644
--- a/drivers/usb/net/gl620a.c
+++ b/drivers/usb/net/gl620a.c
@@ -22,7 +22,6 @@
// #define VERBOSE // more; success messages
#include <linux/module.h>
-#include <linux/sched.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
@@ -70,12 +69,12 @@
(((GL_MAX_PACKET_LEN + 4) * GL_MAX_TRANSMIT_PACKETS) + 4)
struct gl_packet {
- u32 packet_length;
+ __le32 packet_length;
char packet_data [1];
};
struct gl_header {
- u32 packet_count;
+ __le32 packet_count;
struct gl_packet packets;
};
@@ -85,15 +84,14 @@ static int genelink_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
struct gl_packet *packet;
struct sk_buff *gl_skb;
u32 size;
+ u32 count;
header = (struct gl_header *) skb->data;
// get the packet count of the received skb
- le32_to_cpus(&header->packet_count);
- if ((header->packet_count > GL_MAX_TRANSMIT_PACKETS)
- || (header->packet_count < 0)) {
- dbg("genelink: invalid received packet count %d",
- header->packet_count);
+ count = le32_to_cpu(header->packet_count);
+ if (count > GL_MAX_TRANSMIT_PACKETS) {
+ dbg("genelink: invalid received packet count %u", count);
return 0;
}
@@ -103,7 +101,7 @@ static int genelink_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
// decrement the length for the packet count size 4 bytes
skb_pull(skb, 4);
- while (header->packet_count > 1) {
+ while (count > 1) {
// get the packet length
size = le32_to_cpu(packet->packet_length);
@@ -124,9 +122,8 @@ static int genelink_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
}
// advance to the next packet
- packet = (struct gl_packet *)
- &packet->packet_data [size];
- header->packet_count--;
+ packet = (struct gl_packet *)&packet->packet_data[size];
+ count--;
// shift the data pointer to the next gl_packet
skb_pull(skb, size + 4);
@@ -149,8 +146,8 @@ genelink_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
int length = skb->len;
int headroom = skb_headroom(skb);
int tailroom = skb_tailroom(skb);
- u32 *packet_count;
- u32 *packet_len;
+ __le32 *packet_count;
+ __le32 *packet_len;
// FIXME: magic numbers, bleech
padlen = ((skb->len + (4 + 4*1)) % 64) ? 0 : 1;
@@ -172,7 +169,7 @@ genelink_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
}
// attach the packet count to the header
- packet_count = (u32 *) skb_push(skb, (4 + 4*1));
+ packet_count = (__le32 *) skb_push(skb, (4 + 4*1));
packet_len = packet_count + 1;
*packet_count = cpu_to_le32(1);
diff --git a/drivers/usb/net/kaweth.c b/drivers/usb/net/kaweth.c
index fa78326d0bf..de95268ae4b 100644
--- a/drivers/usb/net/kaweth.c
+++ b/drivers/usb/net/kaweth.c
@@ -46,7 +46,6 @@
*/
#include <linux/module.h>
-#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/init.h>
@@ -179,6 +178,7 @@ static struct usb_driver kaweth_driver = {
.suspend = kaweth_suspend,
.resume = kaweth_resume,
.id_table = usb_klsi_table,
+ .supports_autosuspend = 1,
};
typedef __u8 eth_addr_t[6];
@@ -225,6 +225,7 @@ struct kaweth_device
struct delayed_work lowmem_work;
struct usb_device *dev;
+ struct usb_interface *intf;
struct net_device *net;
wait_queue_head_t term_wait;
@@ -662,9 +663,14 @@ static int kaweth_open(struct net_device *net)
dbg("Opening network device.");
+ res = usb_autopm_get_interface(kaweth->intf);
+ if (res) {
+ err("Interface cannot be resumed.");
+ return -EIO;
+ }
res = kaweth_resubmit_rx_urb(kaweth, GFP_KERNEL);
if (res)
- return -EIO;
+ goto err_out;
usb_fill_int_urb(
kaweth->irq_urb,
@@ -681,7 +687,7 @@ static int kaweth_open(struct net_device *net)
res = usb_submit_urb(kaweth->irq_urb, GFP_KERNEL);
if (res) {
usb_kill_urb(kaweth->rx_urb);
- return -EIO;
+ goto err_out;
}
kaweth->opened = 1;
@@ -689,10 +695,14 @@ static int kaweth_open(struct net_device *net)
kaweth_async_set_rx_mode(kaweth);
return 0;
+
+err_out:
+ usb_autopm_enable(kaweth->intf);
+ return -EIO;
}
/****************************************************************
- * kaweth_close
+ * kaweth_kill_urbs
****************************************************************/
static void kaweth_kill_urbs(struct kaweth_device *kaweth)
{
@@ -724,17 +734,29 @@ static int kaweth_close(struct net_device *net)
kaweth->status &= ~KAWETH_STATUS_CLOSING;
+ usb_autopm_enable(kaweth->intf);
+
return 0;
}
static void kaweth_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
+ struct kaweth_device *kaweth = netdev_priv(dev);
strlcpy(info->driver, driver_name, sizeof(info->driver));
+ usb_make_path(kaweth->dev, info->bus_info, sizeof (info->bus_info));
+}
+
+static u32 kaweth_get_link(struct net_device *dev)
+{
+ struct kaweth_device *kaweth = netdev_priv(dev);
+
+ return kaweth->linkstate;
}
static struct ethtool_ops ops = {
- .get_drvinfo = kaweth_get_drvinfo
+ .get_drvinfo = kaweth_get_drvinfo,
+ .get_link = kaweth_get_link
};
/****************************************************************
@@ -908,6 +930,7 @@ static int kaweth_suspend(struct usb_interface *intf, pm_message_t message)
struct kaweth_device *kaweth = usb_get_intfdata(intf);
unsigned long flags;
+ dbg("Suspending device");
spin_lock_irqsave(&kaweth->device_lock, flags);
kaweth->status |= KAWETH_STATUS_SUSPENDING;
spin_unlock_irqrestore(&kaweth->device_lock, flags);
@@ -924,6 +947,7 @@ static int kaweth_resume(struct usb_interface *intf)
struct kaweth_device *kaweth = usb_get_intfdata(intf);
unsigned long flags;
+ dbg("Resuming device");
spin_lock_irqsave(&kaweth->device_lock, flags);
kaweth->status &= ~KAWETH_STATUS_SUSPENDING;
spin_unlock_irqrestore(&kaweth->device_lock, flags);
@@ -1086,6 +1110,8 @@ err_fw:
dbg("Initializing net device.");
+ kaweth->intf = intf;
+
kaweth->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!kaweth->tx_urb)
goto err_free_netdev;
@@ -1265,7 +1291,7 @@ static int kaweth_internal_control_msg(struct usb_device *usb_dev,
{
struct urb *urb;
int retv;
- int length;
+ int length = 0; /* shut up GCC */
urb = usb_alloc_urb(0, GFP_NOIO);
if (!urb)
diff --git a/drivers/usb/net/net1080.c b/drivers/usb/net/net1080.c
index 49363595451..ccebfdef475 100644
--- a/drivers/usb/net/net1080.c
+++ b/drivers/usb/net/net1080.c
@@ -21,7 +21,6 @@
// #define VERBOSE // more; success messages
#include <linux/module.h>
-#include <linux/sched.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
diff --git a/drivers/usb/net/pegasus.h b/drivers/usb/net/pegasus.h
index 98f6898cae1..c7467823cd1 100644
--- a/drivers/usb/net/pegasus.h
+++ b/drivers/usb/net/pegasus.h
@@ -214,9 +214,9 @@ PEGASUS_DEV( "Billionton USBEL-100", VENDOR_BILLIONTON, 0x0988,
DEFAULT_GPIO_RESET )
PEGASUS_DEV( "Billionton USBE-100", VENDOR_BILLIONTON, 0x8511,
DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "Corega FEter USB-TX", VENDOR_COREGA, 0x0004,
+PEGASUS_DEV( "Corega FEther USB-TX", VENDOR_COREGA, 0x0004,
DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "Corega FEter USB-TXS", VENDOR_COREGA, 0x000d,
+PEGASUS_DEV( "Corega FEther USB-TXS", VENDOR_COREGA, 0x000d,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x4001,
DEFAULT_GPIO_RESET )
diff --git a/drivers/usb/net/plusb.c b/drivers/usb/net/plusb.c
index 5d17cdfc7ba..45300939d18 100644
--- a/drivers/usb/net/plusb.c
+++ b/drivers/usb/net/plusb.c
@@ -21,7 +21,6 @@
// #define VERBOSE // more; success messages
#include <linux/module.h>
-#include <linux/sched.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
diff --git a/drivers/usb/net/rndis_host.c b/drivers/usb/net/rndis_host.c
index a322a16d9cf..39a21c74fdf 100644
--- a/drivers/usb/net/rndis_host.c
+++ b/drivers/usb/net/rndis_host.c
@@ -21,7 +21,6 @@
// #define VERBOSE // more; success messages
#include <linux/module.h>
-#include <linux/sched.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
@@ -49,6 +48,8 @@
* - In some cases, MS-Windows will emit undocumented requests; this
* matters more to peripheral implementations than host ones.
*
+ * Moreover there's a no-open-specs variant of RNDIS called "ActiveSync".
+ *
* For these reasons and others, ** USE OF RNDIS IS STRONGLY DISCOURAGED ** in
* favor of such non-proprietary alternatives as CDC Ethernet or the newer (and
* currently rare) "Ethernet Emulation Model" (EEM).
@@ -61,6 +62,9 @@
* - control-in: GET_ENCAPSULATED
*
* We'll try to ignore the RESPONSE_AVAILABLE notifications.
+ *
+ * REVISIT some RNDIS implementations seem to have curious issues still
+ * to be resolved.
*/
struct rndis_msg_hdr {
__le32 msg_type; /* RNDIS_MSG_* */
@@ -71,8 +75,14 @@ struct rndis_msg_hdr {
// ... and more
} __attribute__ ((packed));
-/* RNDIS defines this (absurdly huge) control timeout */
-#define RNDIS_CONTROL_TIMEOUT_MS (10 * 1000)
+/* MS-Windows uses this strange size, but RNDIS spec says 1024 minimum */
+#define CONTROL_BUFFER_SIZE 1025
+
+/* RNDIS defines an (absurdly huge) 10 second control timeout,
+ * but ActiveSync seems to use a more usual 5 second timeout
+ * (which matches the USB 2.0 spec).
+ */
+#define RNDIS_CONTROL_TIMEOUT_MS (5 * 1000)
#define ccpu2 __constant_cpu_to_le32
@@ -270,6 +280,7 @@ static void rndis_status(struct usbnet *dev, struct urb *urb)
static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
{
struct cdc_state *info = (void *) &dev->data;
+ int master_ifnum;
int retval;
unsigned count;
__le32 rsp;
@@ -279,7 +290,7 @@ static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
* disconnect(): either serialize, or dispatch responses on xid
*/
- /* Issue the request; don't bother byteswapping our xid */
+ /* Issue the request; xid is unique, don't bother byteswapping it */
if (likely(buf->msg_type != RNDIS_MSG_HALT
&& buf->msg_type != RNDIS_MSG_RESET)) {
xid = dev->xid++;
@@ -287,11 +298,12 @@ static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
xid = dev->xid++;
buf->request_id = (__force __le32) xid;
}
+ master_ifnum = info->control->cur_altsetting->desc.bInterfaceNumber;
retval = usb_control_msg(dev->udev,
usb_sndctrlpipe(dev->udev, 0),
USB_CDC_SEND_ENCAPSULATED_COMMAND,
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- 0, info->u->bMasterInterface0,
+ 0, master_ifnum,
buf, le32_to_cpu(buf->msg_len),
RNDIS_CONTROL_TIMEOUT_MS);
if (unlikely(retval < 0 || xid == 0))
@@ -306,13 +318,13 @@ static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
*/
rsp = buf->msg_type | RNDIS_MSG_COMPLETION;
for (count = 0; count < 10; count++) {
- memset(buf, 0, 1024);
+ memset(buf, 0, CONTROL_BUFFER_SIZE);
retval = usb_control_msg(dev->udev,
usb_rcvctrlpipe(dev->udev, 0),
USB_CDC_GET_ENCAPSULATED_RESPONSE,
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- 0, info->u->bMasterInterface0,
- buf, 1024,
+ 0, master_ifnum,
+ buf, CONTROL_BUFFER_SIZE,
RNDIS_CONTROL_TIMEOUT_MS);
if (likely(retval >= 8)) {
msg_len = le32_to_cpu(buf->msg_len);
@@ -350,7 +362,7 @@ static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
usb_sndctrlpipe(dev->udev, 0),
USB_CDC_SEND_ENCAPSULATED_COMMAND,
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- 0, info->u->bMasterInterface0,
+ 0, master_ifnum,
msg, sizeof *msg,
RNDIS_CONTROL_TIMEOUT_MS);
if (unlikely(retval < 0))
@@ -393,38 +405,64 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf)
u32 tmp;
/* we can't rely on i/o from stack working, or stack allocation */
- u.buf = kmalloc(1024, GFP_KERNEL);
+ u.buf = kmalloc(CONTROL_BUFFER_SIZE, GFP_KERNEL);
if (!u.buf)
return -ENOMEM;
retval = usbnet_generic_cdc_bind(dev, intf);
if (retval < 0)
goto fail;
- net->hard_header_len += sizeof (struct rndis_data_hdr);
-
- /* initialize; max transfer is 16KB at full speed */
u.init->msg_type = RNDIS_MSG_INIT;
u.init->msg_len = ccpu2(sizeof *u.init);
u.init->major_version = ccpu2(1);
u.init->minor_version = ccpu2(0);
- u.init->max_transfer_size = ccpu2(net->mtu + net->hard_header_len);
+ /* max transfer (in spec) is 0x4000 at full speed, but for
+ * TX we'll stick to one Ethernet packet plus RNDIS framing.
+ * For RX we handle drivers that zero-pad to end-of-packet.
+ * Don't let userspace change these settings.
+ */
+ net->hard_header_len += sizeof (struct rndis_data_hdr);
+ dev->hard_mtu = net->mtu + net->hard_header_len;
+
+ dev->rx_urb_size = dev->hard_mtu + (dev->maxpacket + 1);
+ dev->rx_urb_size &= ~(dev->maxpacket - 1);
+ u.init->max_transfer_size = cpu_to_le32(dev->rx_urb_size);
+
+ net->change_mtu = NULL;
retval = rndis_command(dev, u.header);
if (unlikely(retval < 0)) {
/* it might not even be an RNDIS device!! */
dev_err(&intf->dev, "RNDIS init failed, %d\n", retval);
+ goto fail_and_release;
+ }
+ tmp = le32_to_cpu(u.init_c->max_transfer_size);
+ if (tmp < dev->hard_mtu) {
+ dev_err(&intf->dev,
+ "dev can't take %u byte packets (max %u)\n",
+ dev->hard_mtu, tmp);
goto fail_and_release;
}
- dev->hard_mtu = le32_to_cpu(u.init_c->max_transfer_size);
+
/* REVISIT: peripheral "alignment" request is ignored ... */
- dev_dbg(&intf->dev, "hard mtu %u, align %d\n", dev->hard_mtu,
+ dev_dbg(&intf->dev,
+ "hard mtu %u (%u from dev), rx buflen %Zu, align %d\n",
+ dev->hard_mtu, tmp, dev->rx_urb_size,
1 << le32_to_cpu(u.init_c->packet_alignment));
- /* get designated host ethernet address */
- memset(u.get, 0, sizeof *u.get);
+ /* Get designated host ethernet address.
+ *
+ * Adding a payload exactly the same size as the expected response
+ * payload is an evident requirement MSFT added for ActiveSync.
+ * This undocumented (and nonsensical) issue was found by sniffing
+ * protocol requests from the ActiveSync 4.1 Windows driver.
+ */
+ memset(u.get, 0, sizeof *u.get + 48);
u.get->msg_type = RNDIS_MSG_QUERY;
- u.get->msg_len = ccpu2(sizeof *u.get);
+ u.get->msg_len = ccpu2(sizeof *u.get + 48);
u.get->oid = OID_802_3_PERMANENT_ADDRESS;
+ u.get->len = ccpu2(48);
+ u.get->offset = ccpu2(20);
retval = rndis_command(dev, u.header);
if (unlikely(retval < 0)) {
@@ -432,7 +470,7 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf)
goto fail_and_release;
}
tmp = le32_to_cpu(u.get_c->offset);
- if (unlikely((tmp + 8) > (1024 - ETH_ALEN)
+ if (unlikely((tmp + 8) > (CONTROL_BUFFER_SIZE - ETH_ALEN)
|| u.get_c->len != ccpu2(ETH_ALEN))) {
dev_err(&intf->dev, "rndis ethaddr off %d len %d ?\n",
tmp, le32_to_cpu(u.get_c->len));
@@ -598,6 +636,10 @@ static const struct usb_device_id products [] = {
/* RNDIS is MSFT's un-official variant of CDC ACM */
USB_INTERFACE_INFO(USB_CLASS_COMM, 2 /* ACM */, 0x0ff),
.driver_info = (unsigned long) &rndis_info,
+}, {
+ /* "ActiveSync" is an undocumented variant of RNDIS, used in WM5 */
+ USB_INTERFACE_INFO(USB_CLASS_MISC, 1, 1),
+ .driver_info = (unsigned long) &rndis_info,
},
{ }, // END
};
diff --git a/drivers/usb/net/rtl8150.c b/drivers/usb/net/rtl8150.c
index 670262a38a0..ea153dc9b0a 100644
--- a/drivers/usb/net/rtl8150.c
+++ b/drivers/usb/net/rtl8150.c
@@ -6,7 +6,6 @@
* version 2 as published by the Free Software Foundation.
*/
-#include <linux/sched.h>
#include <linux/init.h>
#include <linux/signal.h>
#include <linux/slab.h>
diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c
index 6e39e998825..de69b183bd2 100644
--- a/drivers/usb/net/usbnet.c
+++ b/drivers/usb/net/usbnet.c
@@ -34,7 +34,6 @@
// #define VERBOSE // more; success messages
#include <linux/module.h>
-#include <linux/sched.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
@@ -148,7 +147,7 @@ int usbnet_get_endpoints(struct usbnet *dev, struct usb_interface *intf)
if (tmp < 0)
return tmp;
}
-
+
dev->in = usb_rcvbulkpipe (dev->udev,
in->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
dev->out = usb_sndbulkpipe (dev->udev,
@@ -328,7 +327,7 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags)
if (netif_running (dev->net)
&& netif_device_present (dev->net)
&& !test_bit (EVENT_RX_HALT, &dev->flags)) {
- switch (retval = usb_submit_urb (urb, GFP_ATOMIC)){
+ switch (retval = usb_submit_urb (urb, GFP_ATOMIC)){
case -EPIPE:
usbnet_defer_kevent (dev, EVENT_RX_HALT);
break;
@@ -444,7 +443,7 @@ block:
case -EOVERFLOW:
dev->stats.rx_over_errors++;
// FALLTHROUGH
-
+
default:
entry->state = rx_cleanup;
dev->stats.rx_errors++;
@@ -561,7 +560,7 @@ static int usbnet_stop (struct net_device *net)
if (netif_msg_ifdown (dev))
devinfo (dev, "stop stats: rx/tx %ld/%ld, errs %ld/%ld",
- dev->stats.rx_packets, dev->stats.tx_packets,
+ dev->stats.rx_packets, dev->stats.tx_packets,
dev->stats.rx_errors, dev->stats.tx_errors
);
@@ -579,7 +578,7 @@ static int usbnet_stop (struct net_device *net)
devdbg (dev, "waited for %d urb completions", temp);
}
dev->wait = NULL;
- remove_wait_queue (&unlink_wakeup, &wait);
+ remove_wait_queue (&unlink_wakeup, &wait);
usb_kill_urb(dev->interrupt);
@@ -835,7 +834,7 @@ kevent (struct work_struct *work)
}
if (test_bit (EVENT_LINK_RESET, &dev->flags)) {
- struct driver_info *info = dev->driver_info;
+ struct driver_info *info = dev->driver_info;
int retval = 0;
clear_bit (EVENT_LINK_RESET, &dev->flags);
@@ -1067,7 +1066,7 @@ static void usbnet_bh (unsigned long param)
* USB Device Driver support
*
*-------------------------------------------------------------------------*/
-
+
// precondition: never called in_interrupt
void usbnet_disconnect (struct usb_interface *intf)
@@ -1088,7 +1087,7 @@ void usbnet_disconnect (struct usb_interface *intf)
intf->dev.driver->name,
xdev->bus->bus_name, xdev->devpath,
dev->driver_info->description);
-
+
net = dev->net;
unregister_netdev (net);
@@ -1112,7 +1111,7 @@ int
usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
{
struct usbnet *dev;
- struct net_device *net;
+ struct net_device *net;
struct usb_host_interface *interface;
struct driver_info *info;
struct usb_device *xdev;
@@ -1182,6 +1181,9 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
// NOTE net->name still not usable ...
if (info->bind) {
status = info->bind (dev, udev);
+ if (status < 0)
+ goto out1;
+
// heuristic: "usb%d" for links we know are two-host,
// else "eth%d" when there's reasonable doubt. userspace
// can rename the link if it knows better.
@@ -1208,12 +1210,12 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
if (status == 0 && dev->status)
status = init_status (dev, udev);
if (status < 0)
- goto out1;
+ goto out3;
if (!dev->rx_urb_size)
dev->rx_urb_size = dev->hard_mtu;
dev->maxpacket = usb_maxpacket (dev->udev, dev->out, 1);
-
+
SET_NETDEV_DEV(net, &udev->dev);
status = register_netdev (net);
if (status)
@@ -1256,7 +1258,7 @@ EXPORT_SYMBOL_GPL(usbnet_probe);
int usbnet_suspend (struct usb_interface *intf, pm_message_t message)
{
struct usbnet *dev = usb_get_intfdata(intf);
-
+
/* accelerate emptying of the rx and queues, to avoid
* having everything error out.
*/
@@ -1287,7 +1289,7 @@ static int __init usbnet_init(void)
< sizeof (struct skb_data));
random_ether_addr(node_id);
- return 0;
+ return 0;
}
module_init(usbnet_init);
diff --git a/drivers/usb/net/zaurus.c b/drivers/usb/net/zaurus.c
index 144566bda58..9f98e8ce487 100644
--- a/drivers/usb/net/zaurus.c
+++ b/drivers/usb/net/zaurus.c
@@ -21,7 +21,6 @@
// #define VERBOSE // more; success messages
#include <linux/module.h>
-#include <linux/sched.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/ethtool.h>
diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c
index 86bcf63b6ba..11dad42c3c6 100644
--- a/drivers/usb/serial/aircable.c
+++ b/drivers/usb/serial/aircable.c
@@ -572,8 +572,20 @@ static void aircable_unthrottle(struct usb_serial_port *port)
schedule_work(&priv->rx_work);
}
+static struct usb_driver aircable_driver = {
+ .name = "aircable",
+ .probe = usb_serial_probe,
+ .disconnect = usb_serial_disconnect,
+ .id_table = id_table,
+ .no_dynamic_id = 1,
+};
+
static struct usb_serial_driver aircable_device = {
- .description = "aircable",
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "aircable",
+ },
+ .usb_driver = &aircable_driver,
.id_table = id_table,
.num_ports = 1,
.attach = aircable_attach,
@@ -587,13 +599,6 @@ static struct usb_serial_driver aircable_device = {
.unthrottle = aircable_unthrottle,
};
-static struct usb_driver aircable_driver = {
- .name = "aircable",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
-};
-
static int __init aircable_init (void)
{
int retval;
diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c
index f2ca76a9cba..18816bf96a4 100644
--- a/drivers/usb/serial/airprime.c
+++ b/drivers/usb/serial/airprime.c
@@ -58,11 +58,6 @@ static void airprime_read_bulk_callback(struct urb *urb)
if (urb->status) {
dbg("%s - nonzero read bulk status received: %d",
__FUNCTION__, urb->status);
- /* something happened, so free up the memory for this urb */
- if (urb->transfer_buffer) {
- kfree (urb->transfer_buffer);
- urb->transfer_buffer = NULL;
- }
return;
}
usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data);
@@ -146,6 +141,8 @@ static int airprime_open(struct usb_serial_port *port, struct file *filp)
airprime_read_bulk_callback, port);
result = usb_submit_urb(urb, GFP_KERNEL);
if (result) {
+ usb_free_urb(urb);
+ kfree(buffer);
dev_err(&port->dev,
"%s - failed submitting read urb %d for port %d, error %d\n",
__FUNCTION__, i, port->number, result);
@@ -160,27 +157,12 @@ static int airprime_open(struct usb_serial_port *port, struct file *filp)
/* some error happened, cancel any submitted urbs and clean up anything that
got allocated successfully */
- for ( ; i >= 0; --i) {
+ while (i-- != 0) {
urb = priv->read_urbp[i];
- if (urb) {
- /* This urb was submitted successfully. So we have to
- cancel it.
- Unlinking the urb will invoke read_bulk_callback()
- with an error status, so its transfer buffer will
- be freed there */
- if (usb_unlink_urb (urb) != -EINPROGRESS) {
- /* comments in drivers/usb/core/urb.c say this
- can only happen if the urb was never submitted,
- or has completed already.
- Either way we may have to free the transfer
- buffer here. */
- if (urb->transfer_buffer) {
- kfree (urb->transfer_buffer);
- urb->transfer_buffer = NULL;
- }
- }
- usb_free_urb (urb);
- }
+ buffer = urb->transfer_buffer;
+ usb_kill_urb (urb);
+ usb_free_urb (urb);
+ kfree (buffer);
}
out:
@@ -194,10 +176,9 @@ static void airprime_close(struct usb_serial_port *port, struct file * filp)
dbg("%s - port %d", __FUNCTION__, port->number);
- /* killing the urb will invoke read_bulk_callback() with an error status,
- so the transfer buffer will be freed there */
for (i = 0; i < NUM_READ_URBS; ++i) {
usb_kill_urb (priv->read_urbp[i]);
+ kfree (priv->read_urbp[i]->transfer_buffer);
usb_free_urb (priv->read_urbp[i]);
}
@@ -277,6 +258,7 @@ static struct usb_serial_driver airprime_device = {
.owner = THIS_MODULE,
.name = "airprime",
},
+ .usb_driver = &airprime_driver,
.id_table = id_table,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = NUM_DONT_CARE,
diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c
index 5261cd22ee6..edd685791a6 100644
--- a/drivers/usb/serial/ark3116.c
+++ b/drivers/usb/serial/ark3116.c
@@ -444,6 +444,7 @@ static struct usb_driver ark3116_driver = {
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table,
+ .no_dynamic_id = 1,
};
static struct usb_serial_driver ark3116_device = {
@@ -452,6 +453,7 @@ static struct usb_serial_driver ark3116_device = {
.name = "ark3116",
},
.id_table = id_table,
+ .usb_driver = &ark3116_driver,
.num_interrupt_in = 1,
.num_bulk_in = 1,
.num_bulk_out = 1,
diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c
index 38b4dae319e..3b800d277c4 100644
--- a/drivers/usb/serial/belkin_sa.c
+++ b/drivers/usb/serial/belkin_sa.c
@@ -126,6 +126,7 @@ static struct usb_serial_driver belkin_device = {
.name = "belkin",
},
.description = "Belkin / Peracom / GoHubs USB Serial Adapter",
+ .usb_driver = &belkin_driver,
.id_table = id_table_combined,
.num_interrupt_in = 1,
.num_bulk_in = 1,
diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c
index 6542f220468..c08a38402b9 100644
--- a/drivers/usb/serial/bus.c
+++ b/drivers/usb/serial/bus.c
@@ -103,11 +103,52 @@ exit:
return retval;
}
+#ifdef CONFIG_HOTPLUG
+static ssize_t store_new_id(struct device_driver *driver,
+ const char *buf, size_t count)
+{
+ struct usb_serial_driver *usb_drv = to_usb_serial_driver(driver);
+ ssize_t retval = usb_store_new_id(&usb_drv->dynids, driver, buf, count);
+
+ if (retval >= 0 && usb_drv->usb_driver != NULL)
+ retval = usb_store_new_id(&usb_drv->usb_driver->dynids,
+ &usb_drv->usb_driver->drvwrap.driver,
+ buf, count);
+ return retval;
+}
+
+static struct driver_attribute drv_attrs[] = {
+ __ATTR(new_id, S_IWUSR, NULL, store_new_id),
+ __ATTR_NULL,
+};
+
+static void free_dynids(struct usb_serial_driver *drv)
+{
+ struct usb_dynid *dynid, *n;
+
+ spin_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);
+}
+
+#else
+static struct driver_attribute drv_attrs[] = {
+ __ATTR_NULL,
+};
+static inline void free_dynids(struct usb_driver *drv)
+{
+}
+#endif
+
struct bus_type usb_serial_bus_type = {
.name = "usb-serial",
.match = usb_serial_device_match,
.probe = usb_serial_device_probe,
.remove = usb_serial_device_remove,
+ .drv_attrs = drv_attrs,
};
int usb_serial_bus_register(struct usb_serial_driver *driver)
@@ -115,6 +156,9 @@ int usb_serial_bus_register(struct usb_serial_driver *driver)
int retval;
driver->driver.bus = &usb_serial_bus_type;
+ spin_lock_init(&driver->dynids.lock);
+ INIT_LIST_HEAD(&driver->dynids.list);
+
retval = driver_register(&driver->driver);
return retval;
@@ -122,6 +166,7 @@ int usb_serial_bus_register(struct usb_serial_driver *driver)
void usb_serial_bus_deregister(struct usb_serial_driver *driver)
{
+ free_dynids(driver);
driver_unregister(&driver->driver);
}
diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c
index 7ebaffd6ed8..db623e75489 100644
--- a/drivers/usb/serial/cp2101.c
+++ b/drivers/usb/serial/cp2101.c
@@ -69,6 +69,7 @@ static struct usb_device_id id_table [] = {
{ USB_DEVICE(0x10C4, 0x8218) }, /* Lipowsky Industrie Elektronik GmbH, HARP-1 */
{ USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */
{ USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */
+ { USB_DEVICE(0x10C5, 0xEA61) }, /* Silicon Labs MobiData GPRS USB Modem */
{ USB_DEVICE(0x13AD, 0x9999) }, /* Baltech card reader */
{ USB_DEVICE(0x16D6, 0x0001) }, /* Jablotron serial interface */
{ } /* Terminating Entry */
@@ -89,6 +90,7 @@ static struct usb_serial_driver cp2101_device = {
.owner = THIS_MODULE,
.name = "cp2101",
},
+ .usb_driver = &cp2101_driver,
.id_table = id_table,
.num_interrupt_in = 0,
.num_bulk_in = 0,
@@ -169,13 +171,13 @@ static int cp2101_get_config(struct usb_serial_port* port, u8 request,
unsigned int *data, int size)
{
struct usb_serial *serial = port->serial;
- u32 *buf;
+ __le32 *buf;
int result, i, length;
/* Number of integers required to contain the array */
length = (((size - 1) | 3) + 1)/4;
- buf = kcalloc(length, sizeof(u32), GFP_KERNEL);
+ buf = kcalloc(length, sizeof(__le32), GFP_KERNEL);
if (!buf) {
dev_err(&port->dev, "%s - out of memory.\n", __FUNCTION__);
return -ENOMEM;
@@ -215,13 +217,13 @@ static int cp2101_set_config(struct usb_serial_port* port, u8 request,
unsigned int *data, int size)
{
struct usb_serial *serial = port->serial;
- u32 *buf;
+ __le32 *buf;
int result, i, length;
/* Number of integers required to contain the array */
length = (((size - 1) | 3) + 1)/4;
- buf = kmalloc(length * sizeof(u32), GFP_KERNEL);
+ buf = kmalloc(length * sizeof(__le32), GFP_KERNEL);
if (!buf) {
dev_err(&port->dev, "%s - out of memory.\n",
__FUNCTION__);
diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c
index a63c3286caa..4167753ed31 100644
--- a/drivers/usb/serial/cyberjack.c
+++ b/drivers/usb/serial/cyberjack.c
@@ -88,6 +88,7 @@ static struct usb_serial_driver cyberjack_device = {
.name = "cyberjack",
},
.description = "Reiner SCT Cyberjack USB card reader",
+ .usb_driver = &cyberjack_driver,
.id_table = id_table,
.num_interrupt_in = 1,
.num_bulk_in = 1,
@@ -98,7 +99,7 @@ static struct usb_serial_driver cyberjack_device = {
.open = cyberjack_open,
.close = cyberjack_close,
.write = cyberjack_write,
- .write_room = cyberjack_write_room,
+ .write_room = cyberjack_write_room,
.read_int_callback = cyberjack_read_int_callback,
.read_bulk_callback = cyberjack_read_bulk_callback,
.write_bulk_callback = cyberjack_write_bulk_callback,
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
index 6bc1f404e18..57b8e27285f 100644
--- a/drivers/usb/serial/cypress_m8.c
+++ b/drivers/usb/serial/cypress_m8.c
@@ -193,6 +193,7 @@ static struct usb_serial_driver cypress_earthmate_device = {
.name = "earthmate",
},
.description = "DeLorme Earthmate USB",
+ .usb_driver = &cypress_driver,
.id_table = id_table_earthmate,
.num_interrupt_in = 1,
.num_interrupt_out = 1,
@@ -222,6 +223,7 @@ static struct usb_serial_driver cypress_hidcom_device = {
.name = "cyphidcom",
},
.description = "HID->COM RS232 Adapter",
+ .usb_driver = &cypress_driver,
.id_table = id_table_cyphidcomrs232,
.num_interrupt_in = 1,
.num_interrupt_out = 1,
@@ -251,6 +253,7 @@ static struct usb_serial_driver cypress_ca42v2_device = {
.name = "nokiaca42v2",
},
.description = "Nokia CA-42 V2 Adapter",
+ .usb_driver = &cypress_driver,
.id_table = id_table_nokiaca42v2,
.num_interrupt_in = 1,
.num_interrupt_out = 1,
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index efd9ce3f931..d78692c01cf 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -509,6 +509,7 @@ static struct usb_serial_driver digi_acceleport_2_device = {
.name = "digi_2",
},
.description = "Digi 2 port USB adapter",
+ .usb_driver = &digi_driver,
.id_table = id_table_2,
.num_interrupt_in = 0,
.num_bulk_in = 4,
@@ -538,6 +539,7 @@ static struct usb_serial_driver digi_acceleport_4_device = {
.name = "digi_4",
},
.description = "Digi 4 port USB adapter",
+ .usb_driver = &digi_driver,
.id_table = id_table_4,
.num_interrupt_in = 0,
.num_bulk_in = 5,
@@ -614,15 +616,7 @@ static void digi_wakeup_write_lock(struct work_struct *work)
static void digi_wakeup_write( struct usb_serial_port *port )
{
-
- struct tty_struct *tty = port->tty;
-
-
- /* wake up port processes */
- wake_up_interruptible( &port->write_wait );
-
- /* wake up line discipline */
- tty_wakeup(tty);
+ tty_wakeup(port->tty);
}
diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c
index 92beeb19795..4703c8f8538 100644
--- a/drivers/usb/serial/empeg.c
+++ b/drivers/usb/serial/empeg.c
@@ -117,6 +117,7 @@ static struct usb_serial_driver empeg_device = {
.name = "empeg",
},
.id_table = id_table,
+ .usb_driver = &empeg_driver,
.num_interrupt_in = 0,
.num_bulk_in = 1,
.num_bulk_out = 1,
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 6986e756f7c..c525b42dadd 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -464,7 +464,6 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(BANDB_VID, BANDB_USTL4_PID) },
{ USB_DEVICE(BANDB_VID, BANDB_USO9ML2_PID) },
{ USB_DEVICE(FTDI_VID, EVER_ECO_PRO_CDS) },
- { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_0_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_1_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_2_PID) },
{ USB_DEVICE(FTDI_VID, XSENS_CONVERTER_0_PID) },
@@ -514,6 +513,7 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13S_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13U_PID) },
{ USB_DEVICE(ELEKTOR_VID, ELEKTOR_FT323R_PID) },
+ { USB_DEVICE(TELLDUS_VID, TELLDUS_TELLSTICK_PID) },
{ }, /* Optional parameter entry */
{ } /* Terminating entry */
};
@@ -615,6 +615,7 @@ static struct usb_serial_driver ftdi_sio_device = {
.name = "ftdi_sio",
},
.description = "FTDI USB Serial Device",
+ .usb_driver = &ftdi_driver ,
.id_table = id_table_combined,
.num_interrupt_in = 0,
.num_bulk_in = 1,
diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
index 40dd394de58..1bdda935f7d 100644
--- a/drivers/usb/serial/ftdi_sio.h
+++ b/drivers/usb/serial/ftdi_sio.h
@@ -364,7 +364,6 @@
* USB-TTY activ, 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_0_PID 0x8372
#define FTDI_4N_GALAXY_DE_1_PID 0xF3C0
#define FTDI_4N_GALAXY_DE_2_PID 0xF3C1
@@ -492,6 +491,12 @@
#define FTDI_TACTRIX_OPENPORT_13S_PID 0xCC49 /* OpenPort 1.3 Subaru */
#define FTDI_TACTRIX_OPENPORT_13U_PID 0xCC4A /* OpenPort 1.3 Universal */
+/*
+ * Telldus Technologies
+ */
+#define TELLDUS_VID 0x1781 /* Vendor ID */
+#define TELLDUS_TELLSTICK_PID 0x0C30 /* RF control dongle 433 MHz using FT232RL */
+
/* Commands */
#define FTDI_SIO_RESET 0 /* Reset the port */
#define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */
diff --git a/drivers/usb/serial/funsoft.c b/drivers/usb/serial/funsoft.c
index 2bebd63d5ed..4092f6dc9ef 100644
--- a/drivers/usb/serial/funsoft.c
+++ b/drivers/usb/serial/funsoft.c
@@ -58,6 +58,7 @@ static struct usb_serial_driver funsoft_device = {
.name = "funsoft",
},
.id_table = id_table,
+ .usb_driver = &funsoft_driver,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = NUM_DONT_CARE,
.num_bulk_out = NUM_DONT_CARE,
diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c
index 6530d391ebe..74660a3aa67 100644
--- a/drivers/usb/serial/garmin_gps.c
+++ b/drivers/usb/serial/garmin_gps.c
@@ -1566,6 +1566,7 @@ static struct usb_serial_driver garmin_device = {
.name = "garmin_gps",
},
.description = "Garmin GPS usb/tty",
+ .usb_driver = &garmin_driver,
.id_table = id_table,
.num_interrupt_in = 1,
.num_bulk_in = 1,
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c
index 36042937e77..53baeec8f26 100644
--- a/drivers/usb/serial/generic.c
+++ b/drivers/usb/serial/generic.c
@@ -20,6 +20,10 @@
#include <linux/usb/serial.h>
#include <asm/uaccess.h>
+static int generic_probe(struct usb_interface *interface,
+ const struct usb_device_id *id);
+
+
static int debug;
#ifdef CONFIG_USB_SERIAL_GENERIC
@@ -34,6 +38,21 @@ MODULE_PARM_DESC(product, "User specified USB idProduct");
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[] = {
+ {.driver_info = 42},
+ {}
+};
+
+static struct usb_driver generic_driver = {
+ .name = "usbserial_generic",
+ .probe = generic_probe,
+ .disconnect = usb_serial_disconnect,
+ .id_table = generic_serial_ids,
+ .no_dynamic_id = 1,
+};
+
/* All of the device info needed for the Generic Serial Converter */
struct usb_serial_driver usb_serial_generic_device = {
.driver = {
@@ -41,18 +60,14 @@ struct usb_serial_driver usb_serial_generic_device = {
.name = "generic",
},
.id_table = generic_device_ids,
+ .usb_driver = &generic_driver,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = NUM_DONT_CARE,
.num_bulk_out = NUM_DONT_CARE,
.num_ports = 1,
.shutdown = usb_serial_generic_shutdown,
-};
-
-/* 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[] = {
- {.driver_info = 42},
- {}
+ .throttle = usb_serial_generic_throttle,
+ .unthrottle = usb_serial_generic_unthrottle,
};
static int generic_probe(struct usb_interface *interface,
@@ -65,14 +80,6 @@ static int generic_probe(struct usb_interface *interface,
return usb_serial_probe(interface, id);
return -ENODEV;
}
-
-static struct usb_driver generic_driver = {
- .name = "usbserial_generic",
- .probe = generic_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = generic_serial_ids,
- .no_dynamic_id = 1,
-};
#endif
int usb_serial_generic_register (int _debug)
@@ -110,6 +117,7 @@ int usb_serial_generic_open (struct usb_serial_port *port, struct file *filp)
{
struct usb_serial *serial = port->serial;
int result = 0;
+ unsigned long flags;
dbg("%s - port %d", __FUNCTION__, port->number);
@@ -119,7 +127,13 @@ int usb_serial_generic_open (struct usb_serial_port *port, struct file *filp)
if (port->tty)
port->tty->low_latency = 1;
- /* if we have a bulk interrupt, start reading from it */
+ /* clear the throttle flags */
+ spin_lock_irqsave(&port->lock, flags);
+ port->throttled = 0;
+ port->throttle_req = 0;
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ /* if we have a bulk endpoint, start reading from it */
if (serial->num_bulk_in) {
/* Start reading from the device */
usb_fill_bulk_urb (port->read_urb, serial->dev,
@@ -248,31 +262,22 @@ int usb_serial_generic_chars_in_buffer (struct usb_serial_port *port)
return (chars);
}
-void usb_serial_generic_read_bulk_callback (struct urb *urb)
+/* Push data to tty layer and resubmit the bulk read URB */
+static void flush_and_resubmit_read_urb (struct usb_serial_port *port)
{
- struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct usb_serial *serial = port->serial;
- struct tty_struct *tty;
- unsigned char *data = urb->transfer_buffer;
+ struct urb *urb = port->read_urb;
+ struct tty_struct *tty = port->tty;
int result;
- dbg("%s - port %d", __FUNCTION__, port->number);
-
- if (urb->status) {
- dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status);
- return;
- }
-
- usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data);
-
- tty = port->tty;
+ /* Push data to tty */
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);
+ tty_insert_flip_string(tty, urb->transfer_buffer, urb->actual_length);
+ tty_flip_buffer_push(tty); /* is this allowed from an URB callback ? */
}
- /* Continue trying to always read */
+ /* Continue reading from device */
usb_fill_bulk_urb (port->read_urb, serial->dev,
usb_rcvbulkpipe (serial->dev,
port->bulk_in_endpointAddress),
@@ -285,6 +290,40 @@ void usb_serial_generic_read_bulk_callback (struct urb *urb)
if (result)
dev_err(&port->dev, "%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result);
}
+
+void usb_serial_generic_read_bulk_callback (struct urb *urb)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ unsigned char *data = urb->transfer_buffer;
+ int is_throttled;
+ unsigned long flags;
+
+ dbg("%s - port %d", __FUNCTION__, port->number);
+
+ if (urb->status) {
+ dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status);
+ return;
+ }
+
+ usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data);
+
+ /* Throttle the device if requested by tty */
+ if (urb->actual_length) {
+ spin_lock_irqsave(&port->lock, flags);
+ is_throttled = port->throttled = port->throttle_req;
+ spin_unlock_irqrestore(&port->lock, flags);
+ if (is_throttled) {
+ /* Let the received data linger in the read URB;
+ * usb_serial_generic_unthrottle() will pick it
+ * up later. */
+ dbg("%s - throttling device", __FUNCTION__);
+ return;
+ }
+ }
+
+ /* Handle data and continue reading from device */
+ flush_and_resubmit_read_urb(port);
+}
EXPORT_SYMBOL_GPL(usb_serial_generic_read_bulk_callback);
void usb_serial_generic_write_bulk_callback (struct urb *urb)
@@ -303,6 +342,38 @@ void usb_serial_generic_write_bulk_callback (struct urb *urb)
}
EXPORT_SYMBOL_GPL(usb_serial_generic_write_bulk_callback);
+void usb_serial_generic_throttle (struct usb_serial_port *port)
+{
+ unsigned long flags;
+
+ dbg("%s - port %d", __FUNCTION__, port->number);
+
+ /* Set the throttle request flag. It will be picked up
+ * by usb_serial_generic_read_bulk_callback(). */
+ spin_lock_irqsave(&port->lock, flags);
+ port->throttle_req = 1;
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+void usb_serial_generic_unthrottle (struct usb_serial_port *port)
+{
+ int was_throttled;
+ unsigned long flags;
+
+ dbg("%s - port %d", __FUNCTION__, port->number);
+
+ /* Clear the throttle flags */
+ spin_lock_irqsave(&port->lock, flags);
+ was_throttled = port->throttled;
+ port->throttled = port->throttle_req = 0;
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ if (was_throttled) {
+ /* Handle pending data and resume reading from device */
+ flush_and_resubmit_read_urb(port);
+ }
+}
+
void usb_serial_generic_shutdown (struct usb_serial *serial)
{
int i;
diff --git a/drivers/usb/serial/hp4x.c b/drivers/usb/serial/hp4x.c
index ebcac701b06..6c6ebae741c 100644
--- a/drivers/usb/serial/hp4x.c
+++ b/drivers/usb/serial/hp4x.c
@@ -49,6 +49,7 @@ static struct usb_serial_driver hp49gp_device = {
.name = "hp4X",
},
.id_table = id_table,
+ .usb_driver = &hp49gp_driver,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = NUM_DONT_CARE,
.num_bulk_out = NUM_DONT_CARE,
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index f623d58370a..6a26a2e683a 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -146,6 +146,8 @@ struct edgeport_serial {
struct edge_manuf_descriptor manuf_descriptor; /* the manufacturer descriptor */
struct edge_boot_descriptor boot_descriptor; /* the boot firmware descriptor */
struct edgeport_product_info product_info; /* Product Info */
+ struct edge_compatibility_descriptor epic_descriptor; /* Edgeport compatible descriptor */
+ int is_epic; /* flag if EPiC device or not */
__u8 interrupt_in_endpoint; /* the interrupt endpoint handle */
unsigned char * interrupt_in_buffer; /* the buffer we use for the interrupt endpoint */
@@ -240,14 +242,6 @@ static void edge_shutdown (struct usb_serial *serial);
#include "io_tables.h" /* all of the devices that this driver supports */
-static struct usb_driver io_driver = {
- .name = "io_edgeport",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table_combined,
- .no_dynamic_id = 1,
-};
-
/* function prototypes for all of our local functions */
static void process_rcvd_data (struct edgeport_serial *edge_serial, unsigned char *buffer, __u16 bufferLength);
static void process_rcvd_status (struct edgeport_serial *edge_serial, __u8 byte2, __u8 byte3);
@@ -397,6 +391,7 @@ static int get_string (struct usb_device *dev, int Id, char *string, int buflen)
unicode_to_ascii(string, buflen, pStringDesc->wData, pStringDesc->bLength/2);
kfree(pStringDesc);
+ dbg("%s - USB String %s", __FUNCTION__, string);
return strlen(string);
}
@@ -434,6 +429,34 @@ static int get_string_desc (struct usb_device *dev, int Id, struct usb_string_de
}
#endif
+static void dump_product_info(struct edgeport_product_info *product_info)
+{
+ // Dump Product Info structure
+ dbg("**Product Information:");
+ dbg(" ProductId %x", product_info->ProductId );
+ dbg(" NumPorts %d", product_info->NumPorts );
+ dbg(" ProdInfoVer %d", product_info->ProdInfoVer );
+ dbg(" IsServer %d", product_info->IsServer);
+ dbg(" IsRS232 %d", product_info->IsRS232 );
+ dbg(" IsRS422 %d", product_info->IsRS422 );
+ dbg(" IsRS485 %d", product_info->IsRS485 );
+ dbg(" RomSize %d", product_info->RomSize );
+ dbg(" RamSize %d", product_info->RamSize );
+ dbg(" CpuRev %x", product_info->CpuRev );
+ dbg(" BoardRev %x", product_info->BoardRev);
+ dbg(" BootMajorVersion %d.%d.%d", product_info->BootMajorVersion,
+ product_info->BootMinorVersion,
+ le16_to_cpu(product_info->BootBuildNumber));
+ dbg(" FirmwareMajorVersion %d.%d.%d", product_info->FirmwareMajorVersion,
+ product_info->FirmwareMinorVersion,
+ le16_to_cpu(product_info->FirmwareBuildNumber));
+ dbg(" ManufactureDescDate %d/%d/%d", product_info->ManufactureDescDate[0],
+ product_info->ManufactureDescDate[1],
+ product_info->ManufactureDescDate[2]+1900);
+ dbg(" iDownloadFile 0x%x", product_info->iDownloadFile);
+ dbg(" EpicVer %d", product_info->EpicVer);
+}
+
static void get_product_info(struct edgeport_serial *edge_serial)
{
struct edgeport_product_info *product_info = &edge_serial->product_info;
@@ -495,30 +518,60 @@ static void get_product_info(struct edgeport_serial *edge_serial)
break;
}
- // Dump Product Info structure
- dbg("**Product Information:");
- dbg(" ProductId %x", product_info->ProductId );
- dbg(" NumPorts %d", product_info->NumPorts );
- dbg(" ProdInfoVer %d", product_info->ProdInfoVer );
- dbg(" IsServer %d", product_info->IsServer);
- dbg(" IsRS232 %d", product_info->IsRS232 );
- dbg(" IsRS422 %d", product_info->IsRS422 );
- dbg(" IsRS485 %d", product_info->IsRS485 );
- dbg(" RomSize %d", product_info->RomSize );
- dbg(" RamSize %d", product_info->RamSize );
- dbg(" CpuRev %x", product_info->CpuRev );
- dbg(" BoardRev %x", product_info->BoardRev);
- dbg(" BootMajorVersion %d.%d.%d", product_info->BootMajorVersion,
- product_info->BootMinorVersion,
- le16_to_cpu(product_info->BootBuildNumber));
- dbg(" FirmwareMajorVersion %d.%d.%d", product_info->FirmwareMajorVersion,
- product_info->FirmwareMinorVersion,
- le16_to_cpu(product_info->FirmwareBuildNumber));
- dbg(" ManufactureDescDate %d/%d/%d", product_info->ManufactureDescDate[0],
- product_info->ManufactureDescDate[1],
- product_info->ManufactureDescDate[2]+1900);
- dbg(" iDownloadFile 0x%x", product_info->iDownloadFile);
+ dump_product_info(product_info);
+}
+static int get_epic_descriptor(struct edgeport_serial *ep)
+{
+ int result;
+ struct usb_serial *serial = ep->serial;
+ struct edgeport_product_info *product_info = &ep->product_info;
+ struct edge_compatibility_descriptor *epic = &ep->epic_descriptor;
+ struct edge_compatibility_bits *bits;
+
+ ep->is_epic = 0;
+ result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+ USB_REQUEST_ION_GET_EPIC_DESC,
+ 0xC0, 0x00, 0x00,
+ &ep->epic_descriptor,
+ sizeof(struct edge_compatibility_descriptor),
+ 300);
+
+ dbg("%s result = %d", __FUNCTION__, result);
+
+ if (result > 0) {
+ ep->is_epic = 1;
+ memset(product_info, 0, sizeof(struct edgeport_product_info));
+
+ product_info->NumPorts = epic->NumPorts;
+ product_info->ProdInfoVer = 0;
+ product_info->FirmwareMajorVersion = epic->MajorVersion;
+ product_info->FirmwareMinorVersion = epic->MinorVersion;
+ product_info->FirmwareBuildNumber = epic->BuildNumber;
+ product_info->iDownloadFile = epic->iDownloadFile;
+ product_info->EpicVer = epic->EpicVer;
+ product_info->Epic = epic->Supports;
+ product_info->ProductId = ION_DEVICE_ID_EDGEPORT_COMPATIBLE;
+ dump_product_info(product_info);
+
+ bits = &ep->epic_descriptor.Supports;
+ dbg("**EPIC descriptor:");
+ dbg(" VendEnableSuspend: %s", bits->VendEnableSuspend ? "TRUE": "FALSE");
+ dbg(" IOSPOpen : %s", bits->IOSPOpen ? "TRUE": "FALSE" );
+ dbg(" IOSPClose : %s", bits->IOSPClose ? "TRUE": "FALSE" );
+ dbg(" IOSPChase : %s", bits->IOSPChase ? "TRUE": "FALSE" );
+ dbg(" IOSPSetRxFlow : %s", bits->IOSPSetRxFlow ? "TRUE": "FALSE" );
+ dbg(" IOSPSetTxFlow : %s", bits->IOSPSetTxFlow ? "TRUE": "FALSE" );
+ dbg(" IOSPSetXChar : %s", bits->IOSPSetXChar ? "TRUE": "FALSE" );
+ dbg(" IOSPRxCheck : %s", bits->IOSPRxCheck ? "TRUE": "FALSE" );
+ dbg(" IOSPSetClrBreak : %s", bits->IOSPSetClrBreak ? "TRUE": "FALSE" );
+ dbg(" IOSPWriteMCR : %s", bits->IOSPWriteMCR ? "TRUE": "FALSE" );
+ dbg(" IOSPWriteLCR : %s", bits->IOSPWriteLCR ? "TRUE": "FALSE" );
+ dbg(" IOSPSetBaudRate : %s", bits->IOSPSetBaudRate ? "TRUE": "FALSE" );
+ dbg(" TrueEdgeport : %s", bits->TrueEdgeport ? "TRUE": "FALSE" );
+ }
+
+ return result;
}
@@ -1017,21 +1070,29 @@ static void edge_close (struct usb_serial_port *port, struct file * filp)
edge_port->closePending = TRUE;
- /* flush and chase */
- edge_port->chaseResponsePending = TRUE;
-
- dbg("%s - Sending IOSP_CMD_CHASE_PORT", __FUNCTION__);
- status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0);
- if (status == 0) {
- // block until chase finished
- block_until_chase_response(edge_port);
- } else {
- edge_port->chaseResponsePending = FALSE;
+ if ((!edge_serial->is_epic) ||
+ ((edge_serial->is_epic) &&
+ (edge_serial->epic_descriptor.Supports.IOSPChase))) {
+ /* flush and chase */
+ edge_port->chaseResponsePending = TRUE;
+
+ dbg("%s - Sending IOSP_CMD_CHASE_PORT", __FUNCTION__);
+ status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0);
+ if (status == 0) {
+ // block until chase finished
+ block_until_chase_response(edge_port);
+ } else {
+ edge_port->chaseResponsePending = FALSE;
+ }
}
- /* close the port */
- dbg("%s - Sending IOSP_CMD_CLOSE_PORT", __FUNCTION__);
- send_iosp_ext_cmd (edge_port, IOSP_CMD_CLOSE_PORT, 0);
+ if ((!edge_serial->is_epic) ||
+ ((edge_serial->is_epic) &&
+ (edge_serial->epic_descriptor.Supports.IOSPClose))) {
+ /* close the port */
+ dbg("%s - Sending IOSP_CMD_CLOSE_PORT", __FUNCTION__);
+ send_iosp_ext_cmd (edge_port, IOSP_CMD_CLOSE_PORT, 0);
+ }
//port->close = TRUE;
edge_port->closePending = FALSE;
@@ -1694,29 +1755,38 @@ static int edge_ioctl (struct usb_serial_port *port, struct file *file, unsigned
static void edge_break (struct usb_serial_port *port, int break_state)
{
struct edgeport_port *edge_port = usb_get_serial_port_data(port);
+ struct edgeport_serial *edge_serial = usb_get_serial_data(port->serial);
int status;
- /* flush and chase */
- edge_port->chaseResponsePending = TRUE;
-
- dbg("%s - Sending IOSP_CMD_CHASE_PORT", __FUNCTION__);
- status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0);
- if (status == 0) {
- // block until chase finished
- block_until_chase_response(edge_port);
- } else {
- edge_port->chaseResponsePending = FALSE;
+ if ((!edge_serial->is_epic) ||
+ ((edge_serial->is_epic) &&
+ (edge_serial->epic_descriptor.Supports.IOSPChase))) {
+ /* flush and chase */
+ edge_port->chaseResponsePending = TRUE;
+
+ dbg("%s - Sending IOSP_CMD_CHASE_PORT", __FUNCTION__);
+ status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0);
+ if (status == 0) {
+ // block until chase finished
+ block_until_chase_response(edge_port);
+ } else {
+ edge_port->chaseResponsePending = FALSE;
+ }
}
- if (break_state == -1) {
- dbg("%s - Sending IOSP_CMD_SET_BREAK", __FUNCTION__);
- status = send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_BREAK, 0);
- } else {
- dbg("%s - Sending IOSP_CMD_CLEAR_BREAK", __FUNCTION__);
- status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CLEAR_BREAK, 0);
- }
- if (status) {
- dbg("%s - error sending break set/clear command.", __FUNCTION__);
+ if ((!edge_serial->is_epic) ||
+ ((edge_serial->is_epic) &&
+ (edge_serial->epic_descriptor.Supports.IOSPSetClrBreak))) {
+ if (break_state == -1) {
+ dbg("%s - Sending IOSP_CMD_SET_BREAK", __FUNCTION__);
+ status = send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_BREAK, 0);
+ } else {
+ dbg("%s - Sending IOSP_CMD_CLEAR_BREAK", __FUNCTION__);
+ status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CLEAR_BREAK, 0);
+ }
+ if (status) {
+ dbg("%s - error sending break set/clear command.", __FUNCTION__);
+ }
}
return;
@@ -2288,6 +2358,7 @@ static int write_cmd_usb (struct edgeport_port *edge_port, unsigned char *buffer
*****************************************************************************/
static int send_cmd_write_baud_rate (struct edgeport_port *edge_port, int baudRate)
{
+ struct edgeport_serial *edge_serial = usb_get_serial_data(edge_port->port->serial);
unsigned char *cmdBuffer;
unsigned char *currCmd;
int cmdLen = 0;
@@ -2295,6 +2366,14 @@ static int send_cmd_write_baud_rate (struct edgeport_port *edge_port, int baudRa
int status;
unsigned char number = edge_port->port->number - edge_port->port->serial->minor;
+ if ((!edge_serial->is_epic) ||
+ ((edge_serial->is_epic) &&
+ (!edge_serial->epic_descriptor.Supports.IOSPSetBaudRate))) {
+ dbg("SendCmdWriteBaudRate - NOT Setting baud rate for port = %d, baud = %d",
+ edge_port->port->number, baudRate);
+ return 0;
+ }
+
dbg("%s - port = %d, baud = %d", __FUNCTION__, edge_port->port->number, baudRate);
status = calc_baud_rate_divisor (baudRate, &divisor);
@@ -2374,6 +2453,7 @@ static int calc_baud_rate_divisor (int baudrate, int *divisor)
*****************************************************************************/
static int send_cmd_write_uart_register (struct edgeport_port *edge_port, __u8 regNum, __u8 regValue)
{
+ struct edgeport_serial *edge_serial = usb_get_serial_data(edge_port->port->serial);
unsigned char *cmdBuffer;
unsigned char *currCmd;
unsigned long cmdLen = 0;
@@ -2381,6 +2461,22 @@ static int send_cmd_write_uart_register (struct edgeport_port *edge_port, __u8 r
dbg("%s - write to %s register 0x%02x", (regNum == MCR) ? "MCR" : "LCR", __FUNCTION__, regValue);
+ if ((!edge_serial->is_epic) ||
+ ((edge_serial->is_epic) &&
+ (!edge_serial->epic_descriptor.Supports.IOSPWriteMCR) &&
+ (regNum == MCR))) {
+ dbg("SendCmdWriteUartReg - Not writting to MCR Register");
+ return 0;
+ }
+
+ if ((!edge_serial->is_epic) ||
+ ((edge_serial->is_epic) &&
+ (!edge_serial->epic_descriptor.Supports.IOSPWriteLCR) &&
+ (regNum == LCR))) {
+ dbg ("SendCmdWriteUartReg - Not writting to LCR Register");
+ return 0;
+ }
+
// Alloc memory for the string of commands.
cmdBuffer = kmalloc (0x10, GFP_ATOMIC);
if (cmdBuffer == NULL ) {
@@ -2414,6 +2510,7 @@ static int send_cmd_write_uart_register (struct edgeport_port *edge_port, __u8 r
#endif
static void change_port_settings (struct edgeport_port *edge_port, struct ktermios *old_termios)
{
+ struct edgeport_serial *edge_serial = usb_get_serial_data(edge_port->port->serial);
struct tty_struct *tty;
int baud;
unsigned cflag;
@@ -2494,8 +2591,12 @@ static void change_port_settings (struct edgeport_port *edge_port, struct ktermi
unsigned char stop_char = STOP_CHAR(tty);
unsigned char start_char = START_CHAR(tty);
- send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_XON_CHAR, start_char);
- send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_XOFF_CHAR, stop_char);
+ if ((!edge_serial->is_epic) ||
+ ((edge_serial->is_epic) &&
+ (edge_serial->epic_descriptor.Supports.IOSPSetXChar))) {
+ send_iosp_ext_cmd(edge_port, IOSP_CMD_SET_XON_CHAR, start_char);
+ send_iosp_ext_cmd(edge_port, IOSP_CMD_SET_XOFF_CHAR, stop_char);
+ }
/* if we are implementing INBOUND XON/XOFF */
if (I_IXOFF(tty)) {
@@ -2515,8 +2616,14 @@ static void change_port_settings (struct edgeport_port *edge_port, struct ktermi
}
/* Set flow control to the configured value */
- send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_RX_FLOW, rxFlow);
- send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_TX_FLOW, txFlow);
+ if ((!edge_serial->is_epic) ||
+ ((edge_serial->is_epic) &&
+ (edge_serial->epic_descriptor.Supports.IOSPSetRxFlow)))
+ send_iosp_ext_cmd(edge_port, IOSP_CMD_SET_RX_FLOW, rxFlow);
+ if ((!edge_serial->is_epic) ||
+ ((edge_serial->is_epic) &&
+ (edge_serial->epic_descriptor.Supports.IOSPSetTxFlow)))
+ send_iosp_ext_cmd(edge_port, IOSP_CMD_SET_TX_FLOW, txFlow);
edge_port->shadowLCR &= ~(LCR_BITS_MASK | LCR_STOP_MASK | LCR_PAR_MASK);
@@ -2728,6 +2835,13 @@ static int edge_startup (struct usb_serial *serial)
struct edgeport_port *edge_port;
struct usb_device *dev;
int i, j;
+ int response;
+ int interrupt_in_found;
+ int bulk_in_found;
+ int bulk_out_found;
+ static __u32 descriptor[3] = { EDGE_COMPATIBILITY_MASK0,
+ EDGE_COMPATIBILITY_MASK1,
+ EDGE_COMPATIBILITY_MASK2 };
dev = serial->dev;
@@ -2750,38 +2864,50 @@ static int edge_startup (struct usb_serial *serial)
dev_info(&serial->dev->dev, "%s detected\n", edge_serial->name);
- /* get the manufacturing descriptor for this device */
- get_manufacturing_desc (edge_serial);
+ /* Read the epic descriptor */
+ if (get_epic_descriptor(edge_serial) <= 0) {
+ /* memcpy descriptor to Supports structures */
+ memcpy(&edge_serial->epic_descriptor.Supports, descriptor,
+ sizeof(struct edge_compatibility_bits));
+
+ /* get the manufacturing descriptor for this device */
+ get_manufacturing_desc (edge_serial);
- /* get the boot descriptor */
- get_boot_desc (edge_serial);
+ /* get the boot descriptor */
+ get_boot_desc (edge_serial);
- get_product_info(edge_serial);
+ get_product_info(edge_serial);
+ }
/* set the number of ports from the manufacturing description */
/* serial->num_ports = serial->product_info.NumPorts; */
- if (edge_serial->product_info.NumPorts != serial->num_ports) {
- warn("%s - Device Reported %d serial ports vs core "
- "thinking we have %d ports, email greg@kroah.com this info.",
- __FUNCTION__, edge_serial->product_info.NumPorts,
- serial->num_ports);
+ if ((!edge_serial->is_epic) &&
+ (edge_serial->product_info.NumPorts != serial->num_ports)) {
+ dev_warn(&serial->dev->dev, "Device Reported %d serial ports "
+ "vs. core thinking we have %d ports, email "
+ "greg@kroah.com this information.",
+ edge_serial->product_info.NumPorts,
+ serial->num_ports);
}
dbg("%s - time 1 %ld", __FUNCTION__, jiffies);
- /* now load the application firmware into this device */
- load_application_firmware (edge_serial);
+ /* If not an EPiC device */
+ if (!edge_serial->is_epic) {
+ /* now load the application firmware into this device */
+ load_application_firmware (edge_serial);
- dbg("%s - time 2 %ld", __FUNCTION__, jiffies);
+ dbg("%s - time 2 %ld", __FUNCTION__, jiffies);
- /* Check current Edgeport EEPROM and update if necessary */
- update_edgeport_E2PROM (edge_serial);
-
- dbg("%s - time 3 %ld", __FUNCTION__, jiffies);
+ /* Check current Edgeport EEPROM and update if necessary */
+ update_edgeport_E2PROM (edge_serial);
- /* set the configuration to use #1 */
-// dbg("set_configuration 1");
-// usb_set_configuration (dev, 1);
+ dbg("%s - time 3 %ld", __FUNCTION__, jiffies);
+
+ /* set the configuration to use #1 */
+// dbg("set_configuration 1");
+// usb_set_configuration (dev, 1);
+ }
/* we set up the pointers to the endpoints in the edge_open function,
* as the structures aren't created yet. */
@@ -2804,8 +2930,101 @@ static int edge_startup (struct usb_serial *serial)
edge_port->port = serial->port[i];
usb_set_serial_port_data(serial->port[i], edge_port);
}
-
- return 0;
+
+ response = 0;
+
+ if (edge_serial->is_epic) {
+ /* EPIC thing, set up our interrupt polling now and our read urb, so
+ * that the device knows it really is connected. */
+ interrupt_in_found = bulk_in_found = bulk_out_found = FALSE;
+ for (i = 0; i < serial->interface->altsetting[0].desc.bNumEndpoints; ++i) {
+ struct usb_endpoint_descriptor *endpoint;
+ int buffer_size;
+
+ endpoint = &serial->interface->altsetting[0].endpoint[i].desc;
+ buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+ if ((!interrupt_in_found) &&
+ (usb_endpoint_is_int_in(endpoint))) {
+ /* we found a interrupt in endpoint */
+ dbg("found interrupt in");
+
+ /* not set up yet, so do it now */
+ edge_serial->interrupt_read_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!edge_serial->interrupt_read_urb) {
+ err("out of memory");
+ return -ENOMEM;
+ }
+ edge_serial->interrupt_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
+ if (!edge_serial->interrupt_in_buffer) {
+ err("out of memory");
+ usb_free_urb(edge_serial->interrupt_read_urb);
+ return -ENOMEM;
+ }
+ edge_serial->interrupt_in_endpoint = endpoint->bEndpointAddress;
+
+ /* set up our interrupt urb */
+ usb_fill_int_urb(edge_serial->interrupt_read_urb,
+ dev,
+ usb_rcvintpipe(dev, endpoint->bEndpointAddress),
+ edge_serial->interrupt_in_buffer,
+ buffer_size,
+ edge_interrupt_callback,
+ edge_serial,
+ endpoint->bInterval);
+
+ interrupt_in_found = TRUE;
+ }
+
+ if ((!bulk_in_found) &&
+ (usb_endpoint_is_bulk_in(endpoint))) {
+ /* we found a bulk in endpoint */
+ dbg("found bulk in");
+
+ /* not set up yet, so do it now */
+ edge_serial->read_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!edge_serial->read_urb) {
+ err("out of memory");
+ return -ENOMEM;
+ }
+ edge_serial->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
+ if (!edge_serial->bulk_in_buffer) {
+ err ("out of memory");
+ usb_free_urb(edge_serial->read_urb);
+ return -ENOMEM;
+ }
+ edge_serial->bulk_in_endpoint = endpoint->bEndpointAddress;
+
+ /* set up our bulk in urb */
+ usb_fill_bulk_urb(edge_serial->read_urb, dev,
+ usb_rcvbulkpipe(dev, endpoint->bEndpointAddress),
+ edge_serial->bulk_in_buffer,
+ endpoint->wMaxPacketSize,
+ edge_bulk_in_callback,
+ edge_serial);
+ bulk_in_found = TRUE;
+ }
+
+ if ((!bulk_out_found) &&
+ (usb_endpoint_is_bulk_out(endpoint))) {
+ /* we found a bulk out endpoint */
+ dbg("found bulk out");
+ edge_serial->bulk_out_endpoint = endpoint->bEndpointAddress;
+ bulk_out_found = TRUE;
+ }
+ }
+
+ if ((!interrupt_in_found) || (!bulk_in_found) || (!bulk_out_found)) {
+ err ("Error - the proper endpoints were not found!");
+ return -ENODEV;
+ }
+
+ /* start interrupt read for this edgeport this interrupt will
+ * continue as long as the edgeport is connected */
+ response = usb_submit_urb(edge_serial->interrupt_read_urb, GFP_KERNEL);
+ if (response)
+ err("%s - Error %d submitting control urb", __FUNCTION__, response);
+ }
+ return response;
}
@@ -2815,6 +3034,7 @@ static int edge_startup (struct usb_serial *serial)
****************************************************************************/
static void edge_shutdown (struct usb_serial *serial)
{
+ struct edgeport_serial *edge_serial = usb_get_serial_data(serial);
int i;
dbg("%s", __FUNCTION__);
@@ -2824,7 +3044,18 @@ static void edge_shutdown (struct usb_serial *serial)
kfree (usb_get_serial_port_data(serial->port[i]));
usb_set_serial_port_data(serial->port[i], NULL);
}
- kfree (usb_get_serial_data(serial));
+ /* free up our endpoint stuff */
+ if (edge_serial->is_epic) {
+ usb_unlink_urb(edge_serial->interrupt_read_urb);
+ usb_free_urb(edge_serial->interrupt_read_urb);
+ kfree(edge_serial->interrupt_in_buffer);
+
+ usb_unlink_urb(edge_serial->read_urb);
+ usb_free_urb(edge_serial->read_urb);
+ kfree(edge_serial->bulk_in_buffer);
+ }
+
+ kfree(edge_serial);
usb_set_serial_data(serial, NULL);
}
@@ -2846,6 +3077,9 @@ static int __init edgeport_init(void)
retval = usb_serial_register(&edgeport_8port_device);
if (retval)
goto failed_8port_device_register;
+ retval = usb_serial_register(&epic_device);
+ if (retval)
+ goto failed_epic_device_register;
retval = usb_register(&io_driver);
if (retval)
goto failed_usb_register;
@@ -2853,6 +3087,8 @@ static int __init edgeport_init(void)
return 0;
failed_usb_register:
+ usb_serial_deregister(&epic_device);
+failed_epic_device_register:
usb_serial_deregister(&edgeport_8port_device);
failed_8port_device_register:
usb_serial_deregister(&edgeport_4port_device);
@@ -2873,6 +3109,7 @@ static void __exit edgeport_exit (void)
usb_serial_deregister (&edgeport_2port_device);
usb_serial_deregister (&edgeport_4port_device);
usb_serial_deregister (&edgeport_8port_device);
+ usb_serial_deregister (&epic_device);
}
module_init(edgeport_init);
diff --git a/drivers/usb/serial/io_edgeport.h b/drivers/usb/serial/io_edgeport.h
index 123fa8a904e..29a913a6dac 100644
--- a/drivers/usb/serial/io_edgeport.h
+++ b/drivers/usb/serial/io_edgeport.h
@@ -111,10 +111,12 @@ struct edgeport_product_info {
__le16 FirmwareBuildNumber; /* zzzz (LE format) */
__u8 ManufactureDescDate[3]; /* MM/DD/YY when descriptor template was compiled */
- __u8 Unused1[1]; /* Available */
+ __u8 HardwareType;
__u8 iDownloadFile; /* What to download to EPiC device */
- __u8 Unused2[2]; /* Available */
+ __u8 EpicVer; /* What version of EPiC spec this device supports */
+
+ struct edge_compatibility_bits Epic;
};
/*
diff --git a/drivers/usb/serial/io_tables.h b/drivers/usb/serial/io_tables.h
index fad561c04c7..6d300877254 100644
--- a/drivers/usb/serial/io_tables.h
+++ b/drivers/usb/serial/io_tables.h
@@ -47,6 +47,18 @@ static struct usb_device_id edgeport_8port_id_table [] = {
{ }
};
+static 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) },
+ { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0311) },
+ { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0312) },
+ { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A758) },
+ { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A794) },
+ { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A225) },
+ { }
+};
+
/* Devices that this driver supports */
static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4) },
@@ -70,17 +82,34 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8R) },
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8RR) },
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_412_8) },
+ { 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) },
+ { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0311) },
+ { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0312) },
+ { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A758) },
+ { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A794) },
+ { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A225) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, id_table_combined);
+static struct usb_driver io_driver = {
+ .name = "io_edgeport",
+ .probe = usb_serial_probe,
+ .disconnect = usb_serial_disconnect,
+ .id_table = id_table_combined,
+ .no_dynamic_id = 1,
+};
+
static struct usb_serial_driver edgeport_2port_device = {
.driver = {
.owner = THIS_MODULE,
.name = "edgeport_2",
},
.description = "Edgeport 2 port adapter",
+ .usb_driver = &io_driver,
.id_table = edgeport_2port_id_table,
.num_interrupt_in = 1,
.num_bulk_in = 1,
@@ -111,6 +140,7 @@ static struct usb_serial_driver edgeport_4port_device = {
.name = "edgeport_4",
},
.description = "Edgeport 4 port adapter",
+ .usb_driver = &io_driver,
.id_table = edgeport_4port_id_table,
.num_interrupt_in = 1,
.num_bulk_in = 1,
@@ -141,6 +171,7 @@ static struct usb_serial_driver edgeport_8port_device = {
.name = "edgeport_8",
},
.description = "Edgeport 8 port adapter",
+ .usb_driver = &io_driver,
.id_table = edgeport_8port_id_table,
.num_interrupt_in = 1,
.num_bulk_in = 1,
@@ -165,5 +196,35 @@ static struct usb_serial_driver edgeport_8port_device = {
.write_bulk_callback = edge_bulk_out_data_callback,
};
+static struct usb_serial_driver epic_device = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "epic",
+ },
+ .description = "EPiC device",
+ .id_table = Epic_port_id_table,
+ .num_interrupt_in = 1,
+ .num_bulk_in = 1,
+ .num_bulk_out = 1,
+ .num_ports = 1,
+ .open = edge_open,
+ .close = edge_close,
+ .throttle = edge_throttle,
+ .unthrottle = edge_unthrottle,
+ .attach = edge_startup,
+ .shutdown = edge_shutdown,
+ .ioctl = edge_ioctl,
+ .set_termios = edge_set_termios,
+ .tiocmget = edge_tiocmget,
+ .tiocmset = edge_tiocmset,
+ .write = edge_write,
+ .write_room = edge_write_room,
+ .chars_in_buffer = edge_chars_in_buffer,
+ .break_ctl = edge_break,
+ .read_int_callback = edge_interrupt_callback,
+ .read_bulk_callback = edge_bulk_in_callback,
+ .write_bulk_callback = edge_bulk_out_data_callback,
+};
+
#endif
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
index 980285c0233..544098d2b77 100644
--- a/drivers/usb/serial/io_ti.c
+++ b/drivers/usb/serial/io_ti.c
@@ -2979,6 +2979,7 @@ static struct usb_serial_driver edgeport_1port_device = {
.name = "edgeport_ti_1",
},
.description = "Edgeport TI 1 port adapter",
+ .usb_driver = &io_driver,
.id_table = edgeport_1port_id_table,
.num_interrupt_in = 1,
.num_bulk_in = 1,
@@ -3009,6 +3010,7 @@ static struct usb_serial_driver edgeport_2port_device = {
.name = "edgeport_ti_2",
},
.description = "Edgeport TI 2 port adapter",
+ .usb_driver = &io_driver,
.id_table = edgeport_2port_id_table,
.num_interrupt_in = 1,
.num_bulk_in = 2,
diff --git a/drivers/usb/serial/io_usbvend.h b/drivers/usb/serial/io_usbvend.h
index f1804fd5a3d..e57fa117e48 100644
--- a/drivers/usb/serial/io_usbvend.h
+++ b/drivers/usb/serial/io_usbvend.h
@@ -30,6 +30,7 @@
#define USB_VENDOR_ID_ION 0x1608 // Our VID
#define USB_VENDOR_ID_TI 0x0451 // TI VID
+#define USB_VENDOR_ID_AXIOHM 0x05D9 /* Axiohm VID */
//
// Definitions of USB product IDs (PID)
@@ -334,6 +335,10 @@ struct edge_compatibility_bits
};
+#define EDGE_COMPATIBILITY_MASK0 0x0001
+#define EDGE_COMPATIBILITY_MASK1 0x3FFF
+#define EDGE_COMPATIBILITY_MASK2 0x0001
+
struct edge_compatibility_descriptor
{
__u8 Length; // Descriptor Length (per USB spec)
diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c
index 42f757a5b87..a408184334e 100644
--- a/drivers/usb/serial/ipaq.c
+++ b/drivers/usb/serial/ipaq.c
@@ -563,6 +563,7 @@ static struct usb_serial_driver ipaq_device = {
.name = "ipaq",
},
.description = "PocketPC PDA",
+ .usb_driver = &ipaq_driver,
.id_table = ipaq_id_table,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = 1,
diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c
index d3b9a351cef..1bc586064c7 100644
--- a/drivers/usb/serial/ipw.c
+++ b/drivers/usb/serial/ipw.c
@@ -442,6 +442,7 @@ static struct usb_serial_driver ipw_device = {
.name = "ipw",
},
.description = "IPWireless converter",
+ .usb_driver = &usb_ipw_driver,
.id_table = usb_ipw_ids,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = 1,
diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c
index 8fdf486e346..9d847f69291 100644
--- a/drivers/usb/serial/ir-usb.c
+++ b/drivers/usb/serial/ir-usb.c
@@ -138,6 +138,7 @@ static struct usb_serial_driver ir_device = {
.name = "ir-usb",
},
.description = "IR Dongle",
+ .usb_driver = &ir_driver,
.id_table = id_table,
.num_interrupt_in = 1,
.num_bulk_in = 1,
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
index 9d2fdfd6865..e6966f12ed5 100644
--- a/drivers/usb/serial/keyspan.c
+++ b/drivers/usb/serial/keyspan.c
@@ -1275,11 +1275,31 @@ static int keyspan_fake_startup (struct usb_serial *serial)
}
/* Helper functions used by keyspan_setup_urbs */
+static struct usb_endpoint_descriptor const *find_ep(struct usb_serial const *serial,
+ int endpoint)
+{
+ struct usb_host_interface *iface_desc;
+ struct usb_endpoint_descriptor *ep;
+ int i;
+
+ iface_desc = serial->interface->cur_altsetting;
+ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+ ep = &iface_desc->endpoint[i].desc;
+ if (ep->bEndpointAddress == endpoint)
+ return ep;
+ }
+ dev_warn(&serial->interface->dev, "found no endpoint descriptor for "
+ "endpoint %x\n", endpoint);
+ return NULL;
+}
+
static struct urb *keyspan_setup_urb (struct usb_serial *serial, int endpoint,
int dir, void *ctx, char *buf, int len,
void (*callback)(struct urb *))
{
struct urb *urb;
+ struct usb_endpoint_descriptor const *ep_desc;
+ char const *ep_type_name;
if (endpoint == -1)
return NULL; /* endpoint not needed */
@@ -1291,11 +1311,32 @@ static struct urb *keyspan_setup_urb (struct usb_serial *serial, int endpoint,
return NULL;
}
- /* Fill URB using supplied data. */
- usb_fill_bulk_urb(urb, serial->dev,
- usb_sndbulkpipe(serial->dev, endpoint) | dir,
- buf, len, callback, ctx);
+ ep_desc = find_ep(serial, endpoint);
+ if (!ep_desc) {
+ /* leak the urb, something's wrong and the callers don't care */
+ return urb;
+ }
+ if (usb_endpoint_xfer_int(ep_desc)) {
+ ep_type_name = "INT";
+ usb_fill_int_urb(urb, serial->dev,
+ usb_sndintpipe(serial->dev, endpoint) | dir,
+ buf, len, callback, ctx,
+ ep_desc->bInterval);
+ } else if (usb_endpoint_xfer_bulk(ep_desc)) {
+ ep_type_name = "BULK";
+ usb_fill_bulk_urb(urb, serial->dev,
+ usb_sndbulkpipe(serial->dev, endpoint) | dir,
+ buf, len, callback, ctx);
+ } else {
+ dev_warn(&serial->interface->dev,
+ "unsupported endpoint type %x\n",
+ ep_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK);
+ usb_free_urb(urb);
+ return NULL;
+ }
+ dbg("%s - using urb %p for %s endpoint %x",
+ __func__, urb, ep_type_name, endpoint);
return urb;
}
diff --git a/drivers/usb/serial/keyspan.h b/drivers/usb/serial/keyspan.h
index 6413d73c139..c6830cbdc6d 100644
--- a/drivers/usb/serial/keyspan.h
+++ b/drivers/usb/serial/keyspan.h
@@ -229,7 +229,6 @@ struct ezusb_hex_record {
#define keyspan_usa28_product_id 0x010f
#define keyspan_usa28x_product_id 0x0110
#define keyspan_usa28xa_product_id 0x0115
-#define keyspan_usa28xb_product_id 0x0110
#define keyspan_usa49w_product_id 0x010a
#define keyspan_usa49wlc_product_id 0x012a
@@ -511,7 +510,6 @@ static struct usb_device_id keyspan_ids_combined[] = {
{ 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) },
- { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xb_product_id) },
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_product_id)},
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_product_id)},
{ } /* Terminating entry */
@@ -559,7 +557,6 @@ static 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) },
- { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xb_product_id) },
{ } /* Terminating entry */
};
@@ -576,6 +573,7 @@ static struct usb_serial_driver keyspan_pre_device = {
.name = "keyspan_no_firm",
},
.description = "Keyspan - (without firmware)",
+ .usb_driver = &keyspan_driver,
.id_table = keyspan_pre_ids,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = NUM_DONT_CARE,
@@ -590,6 +588,7 @@ static struct usb_serial_driver keyspan_1port_device = {
.name = "keyspan_1",
},
.description = "Keyspan 1 port adapter",
+ .usb_driver = &keyspan_driver,
.id_table = keyspan_1port_ids,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = NUM_DONT_CARE,
@@ -617,6 +616,7 @@ static struct usb_serial_driver keyspan_2port_device = {
.name = "keyspan_2",
},
.description = "Keyspan 2 port adapter",
+ .usb_driver = &keyspan_driver,
.id_table = keyspan_2port_ids,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = NUM_DONT_CARE,
@@ -644,6 +644,7 @@ static struct usb_serial_driver keyspan_4port_device = {
.name = "keyspan_4",
},
.description = "Keyspan 4 port adapter",
+ .usb_driver = &keyspan_driver,
.id_table = keyspan_4port_ids,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = 5,
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
index 126b9703bba..dd0b66a6ed5 100644
--- a/drivers/usb/serial/keyspan_pda.c
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -182,13 +182,8 @@ static void keyspan_pda_wakeup_write(struct work_struct *work)
struct keyspan_pda_private *priv =
container_of(work, struct keyspan_pda_private, wakeup_work);
struct usb_serial_port *port = priv->port;
- struct tty_struct *tty = port->tty;
- /* wake up port processes */
- wake_up_interruptible( &port->write_wait );
-
- /* wake up line discipline */
- tty_wakeup(tty);
+ tty_wakeup(port->tty);
}
static void keyspan_pda_request_unthrottle(struct work_struct *work)
@@ -793,6 +788,7 @@ static struct usb_serial_driver keyspan_pda_fake_device = {
.name = "keyspan_pda_pre",
},
.description = "Keyspan PDA - (prerenumeration)",
+ .usb_driver = &keyspan_pda_driver,
.id_table = id_table_fake,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = NUM_DONT_CARE,
@@ -809,6 +805,7 @@ static struct usb_serial_driver xircom_pgs_fake_device = {
.name = "xircom_no_firm",
},
.description = "Xircom / Entregra PGS - (prerenumeration)",
+ .usb_driver = &keyspan_pda_driver,
.id_table = id_table_fake_xircom,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = NUM_DONT_CARE,
@@ -824,6 +821,7 @@ static struct usb_serial_driver keyspan_pda_device = {
.name = "keyspan_pda",
},
.description = "Keyspan PDA",
+ .usb_driver = &keyspan_pda_driver,
.id_table = id_table_std,
.num_interrupt_in = 1,
.num_bulk_in = 0,
diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
index 5c4b06a99ac..b2097c45a23 100644
--- a/drivers/usb/serial/kl5kusb105.c
+++ b/drivers/usb/serial/kl5kusb105.c
@@ -124,6 +124,7 @@ static struct usb_serial_driver kl5kusb105d_device = {
.name = "kl5kusb105d",
},
.description = "KL5KUSB105D / PalmConnect",
+ .usb_driver = &kl5kusb105d_driver,
.id_table = id_table,
.num_interrupt_in = 1,
.num_bulk_in = 1,
diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c
index 62bea0c923b..0683b51f093 100644
--- a/drivers/usb/serial/kobil_sct.c
+++ b/drivers/usb/serial/kobil_sct.c
@@ -110,6 +110,7 @@ static struct usb_serial_driver kobil_device = {
.name = "kobil",
},
.description = "KOBIL USB smart card terminal",
+ .usb_driver = &kobil_driver,
.id_table = id_table,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = 0,
diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
index 38b1d17e06e..4cd839b1407 100644
--- a/drivers/usb/serial/mct_u232.c
+++ b/drivers/usb/serial/mct_u232.c
@@ -137,6 +137,7 @@ static struct usb_serial_driver mct_u232_device = {
.name = "mct_u232",
},
.description = "MCT U232",
+ .usb_driver = &mct_u232_driver,
.id_table = id_table_combined,
.num_interrupt_in = 2,
.num_bulk_in = 0,
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c
index e55f4ed81d7..2d588fb8257 100644
--- a/drivers/usb/serial/mos7720.c
+++ b/drivers/usb/serial/mos7720.c
@@ -269,18 +269,8 @@ static void mos7720_bulk_out_data_callback(struct urb *urb)
tty = mos7720_port->port->tty;
- if (tty && mos7720_port->open) {
- /* let the tty driver wakeup if it has a special *
- * write_wakeup function */
- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
- tty->ldisc.write_wakeup)
- (tty->ldisc.write_wakeup)(tty);
-
- /* tell the tty driver that something has changed */
- wake_up_interruptible(&tty->write_wait);
- }
-
- /* schedule_work(&mos7720_port->port->work); */
+ if (tty && mos7720_port->open)
+ tty_wakeup(tty);
}
/*
@@ -1605,12 +1595,21 @@ static void mos7720_shutdown(struct usb_serial *serial)
usb_set_serial_data(serial, NULL);
}
+static struct usb_driver usb_driver = {
+ .name = "moschip7720",
+ .probe = usb_serial_probe,
+ .disconnect = usb_serial_disconnect,
+ .id_table = moschip_port_id_table,
+ .no_dynamic_id = 1,
+};
+
static struct usb_serial_driver moschip7720_2port_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "moschip7720",
},
.description = "Moschip 2 port adapter",
+ .usb_driver = &usb_driver,
.id_table = moschip_port_id_table,
.num_interrupt_in = 1,
.num_bulk_in = 2,
@@ -1631,13 +1630,6 @@ static struct usb_serial_driver moschip7720_2port_driver = {
.read_bulk_callback = mos7720_bulk_in_callback,
};
-static struct usb_driver usb_driver = {
- .name = "moschip7720",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = moschip_port_id_table,
-};
-
static int __init moschip7720_init(void)
{
int retval;
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index 83f661403ba..c6cca859af4 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -755,18 +755,8 @@ static void mos7840_bulk_out_data_callback(struct urb *urb)
tty = mos7840_port->port->tty;
- if (tty && mos7840_port->open) {
- /* let the tty driver wakeup if it has a special *
- * write_wakeup function */
-
- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP))
- && tty->ldisc.write_wakeup) {
- (tty->ldisc.write_wakeup) (tty);
- }
-
- /* tell the tty driver that something has changed */
- wake_up_interruptible(&tty->write_wait);
- }
+ if (tty && mos7840_port->open)
+ tty_wakeup(tty);
}
@@ -2834,12 +2824,21 @@ static void mos7840_shutdown(struct usb_serial *serial)
}
+static struct usb_driver io_driver = {
+ .name = "mos7840",
+ .probe = usb_serial_probe,
+ .disconnect = usb_serial_disconnect,
+ .id_table = moschip_id_table_combined,
+ .no_dynamic_id = 1,
+};
+
static struct usb_serial_driver moschip7840_4port_device = {
.driver = {
.owner = THIS_MODULE,
.name = "mos7840",
},
.description = DRIVER_DESC,
+ .usb_driver = &io_driver,
.id_table = moschip_port_id_table,
.num_interrupt_in = 1, //NUM_DONT_CARE,//1,
#ifdef check
@@ -2869,13 +2868,6 @@ static struct usb_serial_driver moschip7840_4port_device = {
.read_int_callback = mos7840_interrupt_callback,
};
-static struct usb_driver io_driver = {
- .name = "mos7840",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = moschip_id_table_combined,
-};
-
/****************************************************************************
* moschip7840_init
* This is called by the module subsystem, or on startup to initialize us
diff --git a/drivers/usb/serial/navman.c b/drivers/usb/serial/navman.c
index 054abee8165..90701111d74 100644
--- a/drivers/usb/serial/navman.c
+++ b/drivers/usb/serial/navman.c
@@ -119,6 +119,7 @@ static struct usb_serial_driver navman_device = {
.name = "navman",
},
.id_table = id_table,
+ .usb_driver = &navman_driver,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = NUM_DONT_CARE,
.num_bulk_out = NUM_DONT_CARE,
diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c
index bc91d3b726f..0216ac12a27 100644
--- a/drivers/usb/serial/omninet.c
+++ b/drivers/usb/serial/omninet.c
@@ -93,6 +93,7 @@ static struct usb_serial_driver zyxel_omninet_device = {
.name = "omninet",
},
.description = "ZyXEL - omni.net lcd plus usb",
+ .usb_driver = &omninet_driver,
.id_table = id_table,
.num_interrupt_in = 1,
.num_bulk_in = 1,
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 0fed43a9687..db92a7fb1f7 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -67,54 +67,95 @@ static int option_tiocmset(struct usb_serial_port *port, struct file *file,
static int option_send_setup(struct usb_serial_port *port);
/* Vendor and product IDs */
-#define OPTION_VENDOR_ID 0x0AF0
-#define HUAWEI_VENDOR_ID 0x12D1
-#define AUDIOVOX_VENDOR_ID 0x0F3D
-#define NOVATELWIRELESS_VENDOR_ID 0x1410
-#define ANYDATA_VENDOR_ID 0x16d5
-
-#define OPTION_PRODUCT_OLD 0x5000
-#define OPTION_PRODUCT_FUSION 0x6000
-#define OPTION_PRODUCT_FUSION2 0x6300
-#define OPTION_PRODUCT_COBRA 0x6500
-#define OPTION_PRODUCT_COBRA2 0x6600
-#define OPTION_PRODUCT_GTMAX36 0x6701
-#define HUAWEI_PRODUCT_E600 0x1001
-#define HUAWEI_PRODUCT_E220 0x1003
-#define AUDIOVOX_PRODUCT_AIRCARD 0x0112
-#define NOVATELWIRELESS_PRODUCT_U740 0x1400
-#define ANYDATA_PRODUCT_ID 0x6501
+#define OPTION_VENDOR_ID 0x0AF0
+#define OPTION_PRODUCT_COLT 0x5000
+#define OPTION_PRODUCT_RICOLA 0x6000
+#define OPTION_PRODUCT_RICOLA_LIGHT 0x6100
+#define OPTION_PRODUCT_RICOLA_QUAD 0x6200
+#define OPTION_PRODUCT_RICOLA_QUAD_LIGHT 0x6300
+#define OPTION_PRODUCT_RICOLA_NDIS 0x6050
+#define OPTION_PRODUCT_RICOLA_NDIS_LIGHT 0x6150
+#define OPTION_PRODUCT_RICOLA_NDIS_QUAD 0x6250
+#define OPTION_PRODUCT_RICOLA_NDIS_QUAD_LIGHT 0x6350
+#define OPTION_PRODUCT_COBRA 0x6500
+#define OPTION_PRODUCT_COBRA_BUS 0x6501
+#define OPTION_PRODUCT_VIPER 0x6600
+#define OPTION_PRODUCT_VIPER_BUS 0x6601
+#define OPTION_PRODUCT_GT_MAX_READY 0x6701
+#define OPTION_PRODUCT_GT_MAX 0x6711
+#define OPTION_PRODUCT_FUJI_MODEM_LIGHT 0x6721
+#define OPTION_PRODUCT_FUJI_MODEM_GT 0x6741
+#define OPTION_PRODUCT_FUJI_MODEM_EX 0x6761
+#define OPTION_PRODUCT_FUJI_NETWORK_LIGHT 0x6731
+#define OPTION_PRODUCT_FUJI_NETWORK_GT 0x6751
+#define OPTION_PRODUCT_FUJI_NETWORK_EX 0x6771
+#define OPTION_PRODUCT_KOI_MODEM 0x6800
+#define OPTION_PRODUCT_KOI_NETWORK 0x6811
+#define OPTION_PRODUCT_SCORPION_MODEM 0x6901
+#define OPTION_PRODUCT_SCORPION_NETWORK 0x6911
+#define OPTION_PRODUCT_ETNA_MODEM 0x7001
+#define OPTION_PRODUCT_ETNA_NETWORK 0x7011
+#define OPTION_PRODUCT_ETNA_MODEM_LITE 0x7021
+#define OPTION_PRODUCT_ETNA_MODEM_GT 0x7041
+#define OPTION_PRODUCT_ETNA_MODEM_EX 0x7061
+#define OPTION_PRODUCT_ETNA_NETWORK_LITE 0x7031
+#define OPTION_PRODUCT_ETNA_NETWORK_GT 0x7051
+#define OPTION_PRODUCT_ETNA_NETWORK_EX 0x7071
+#define OPTION_PRODUCT_ETNA_KOI_MODEM 0x7100
+#define OPTION_PRODUCT_ETNA_KOI_NETWORK 0x7111
+
+#define HUAWEI_VENDOR_ID 0x12D1
+#define HUAWEI_PRODUCT_E600 0x1001
+#define HUAWEI_PRODUCT_E220 0x1003
+
+#define NOVATELWIRELESS_VENDOR_ID 0x1410
+#define NOVATELWIRELESS_PRODUCT_U740 0x1400
+
+#define ANYDATA_VENDOR_ID 0x16d5
+#define ANYDATA_PRODUCT_ID 0x6501
static struct usb_device_id option_ids[] = {
- { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_OLD) },
- { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION) },
- { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION2) },
+ { 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) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_QUAD) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_QUAD_LIGHT) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_NDIS) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_NDIS_LIGHT) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_NDIS_QUAD) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_NDIS_QUAD_LIGHT) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA) },
- { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA2) },
- { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_GTMAX36) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA_BUS) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_VIPER) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_VIPER_BUS) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_GT_MAX_READY) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_GT_MAX) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUJI_MODEM_LIGHT) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUJI_MODEM_GT) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUJI_MODEM_EX) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUJI_NETWORK_LIGHT) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUJI_NETWORK_GT) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUJI_NETWORK_EX) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_KOI_MODEM) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_KOI_NETWORK) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_SCORPION_MODEM) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_SCORPION_NETWORK) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_MODEM) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_NETWORK) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_MODEM_LITE) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_MODEM_GT) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_MODEM_EX) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_NETWORK_LITE) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_NETWORK_GT) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_NETWORK_EX) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_KOI_MODEM) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_KOI_NETWORK) },
{ USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) },
{ USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220) },
- { USB_DEVICE(AUDIOVOX_VENDOR_ID, AUDIOVOX_PRODUCT_AIRCARD) },
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID,NOVATELWIRELESS_PRODUCT_U740) },
{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ID) },
{ } /* Terminating entry */
};
-
-static struct usb_device_id option_ids1[] = {
- { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_OLD) },
- { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION) },
- { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION2) },
- { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA) },
- { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA2) },
- { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_GTMAX36) },
- { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) },
- { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220) },
- { USB_DEVICE(AUDIOVOX_VENDOR_ID, AUDIOVOX_PRODUCT_AIRCARD) },
- { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID,NOVATELWIRELESS_PRODUCT_U740) },
- { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ID) },
- { } /* Terminating entry */
-};
-
MODULE_DEVICE_TABLE(usb, option_ids);
static struct usb_driver option_driver = {
@@ -135,7 +176,8 @@ static struct usb_serial_driver option_1port_device = {
.name = "option1",
},
.description = "GSM modem (1-port)",
- .id_table = option_ids1,
+ .usb_driver = &option_driver,
+ .id_table = option_ids,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = NUM_DONT_CARE,
.num_bulk_out = NUM_DONT_CARE,
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index 5dc2ac9afa9..83dfae93a45 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -83,6 +83,7 @@ static struct usb_device_id id_table [] = {
{ USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) },
{ USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_PRODUCT_ID) },
{ USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_ID) },
+ { USB_DEVICE(WS002IN_VENDOR_ID, WS002IN_PRODUCT_ID) },
{ } /* Terminating entry */
};
@@ -1118,6 +1119,7 @@ static struct usb_serial_driver pl2303_device = {
.name = "pl2303",
},
.id_table = id_table,
+ .usb_driver = &pl2303_driver,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = 1,
.num_bulk_out = 1,
diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h
index 65a5039665e..f9a71d0c102 100644
--- a/drivers/usb/serial/pl2303.h
+++ b/drivers/usb/serial/pl2303.h
@@ -97,3 +97,8 @@
/* Huawei E620 UMTS/HSDPA card (ID: 12d1:1001) */
#define HUAWEI_VENDOR_ID 0x12d1
#define HUAWEI_PRODUCT_ID 0x1001
+
+/* Willcom WS002IN Data Driver (by NetIndex Inc.) */
+#define WS002IN_VENDOR_ID 0x11f6
+#define WS002IN_PRODUCT_ID 0x2001
+
diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c
index 30b7ebc8d45..5a03a3fc938 100644
--- a/drivers/usb/serial/safe_serial.c
+++ b/drivers/usb/serial/safe_serial.c
@@ -402,6 +402,7 @@ static struct usb_serial_driver safe_device = {
.name = "safe_serial",
},
.id_table = id_table,
+ .usb_driver = &safe_driver,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = NUM_DONT_CARE,
.num_bulk_out = NUM_DONT_CARE,
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c
index 6d8e91e00ec..ecedd833818 100644
--- a/drivers/usb/serial/sierra.c
+++ b/drivers/usb/serial/sierra.c
@@ -13,10 +13,9 @@
Portions based on the option driver by Matthias Urlichs <smurf@smurf.noris.de>
Whom based his on the Keyspan driver by Hugh Blemings <hugh@blemings.org>
- History:
*/
-#define DRIVER_VERSION "v.1.0.5"
+#define DRIVER_VERSION "v.1.0.6"
#define DRIVER_AUTHOR "Kevin Lloyd <linux@sierrawireless.com>"
#define DRIVER_DESC "USB Driver for Sierra Wireless USB modems"
@@ -31,14 +30,15 @@
static struct usb_device_id id_table [] = {
+ { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */
{ USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */
+ { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */
{ USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */
- { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */
{ USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */
- { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */
+ { USB_DEVICE(0x1199, 0x0021) }, /* Sierra Wireless AirCard 597E */
{ USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */
+ { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 */
{ USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */
- { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 for Europe */
{ USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 */
{ USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */
@@ -55,14 +55,15 @@ static struct usb_device_id id_table_1port [] = {
};
static struct usb_device_id id_table_3port [] = {
+ { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */
{ USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */
+ { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */
{ USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */
- { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */
{ USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */
- { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */
+ { USB_DEVICE(0x1199, 0x0021) }, /* Sierra Wireless AirCard 597E */
{ USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */
+ { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 */
{ USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */
- { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 for Europe */
{ USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 */
{ USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */
{ }
@@ -81,7 +82,7 @@ static int debug;
/* per port private data */
#define N_IN_URB 4
-#define N_OUT_URB 1
+#define N_OUT_URB 4
#define IN_BUFLEN 4096
#define OUT_BUFLEN 128
@@ -396,6 +397,8 @@ static int sierra_open(struct usb_serial_port *port, struct file *filp)
struct usb_serial *serial = port->serial;
int i, err;
struct urb *urb;
+ int result;
+ __u16 set_mode_dzero = 0x0000;
portdata = usb_get_serial_port_data(port);
@@ -442,6 +445,12 @@ static int sierra_open(struct usb_serial_port *port, struct file *filp)
port->tty->low_latency = 1;
+ /* set mode to D0 */
+ result = usb_control_msg(serial->dev,
+ usb_rcvctrlpipe(serial->dev, 0),
+ 0x00, 0x40, set_mode_dzero, 0, NULL,
+ 0, USB_CTRL_SET_TIMEOUT);
+
sierra_send_setup(port);
return (0);
@@ -614,6 +623,7 @@ static struct usb_serial_driver sierra_1port_device = {
},
.description = "Sierra USB modem (1 port)",
.id_table = id_table_1port,
+ .usb_driver = &sierra_driver,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = 1,
.num_bulk_out = 1,
@@ -642,6 +652,7 @@ static struct usb_serial_driver sierra_3port_device = {
},
.description = "Sierra USB modem (3 port)",
.id_table = id_table_3port,
+ .usb_driver = &sierra_driver,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = 3,
.num_bulk_out = 3,
diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c
index 83189005c6f..4203e2b1a76 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.c
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
@@ -262,6 +262,7 @@ static struct usb_serial_driver ti_1port_device = {
.name = "ti_usb_3410_5052_1",
},
.description = "TI USB 3410 1 port adapter",
+ .usb_driver = &ti_usb_driver,
.id_table = ti_id_table_3410,
.num_interrupt_in = 1,
.num_bulk_in = 1,
@@ -292,6 +293,7 @@ static struct usb_serial_driver ti_2port_device = {
.name = "ti_usb_3410_5052_2",
},
.description = "TI USB 5052 2 port adapter",
+ .usb_driver = &ti_usb_driver,
.id_table = ti_id_table_5052,
.num_interrupt_in = 1,
.num_bulk_in = 2,
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 716f6806cc8..6bf22a28adb 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -59,14 +59,19 @@ static struct usb_driver usb_serial_driver = {
static int debug;
static struct usb_serial *serial_table[SERIAL_TTY_MINORS]; /* initially all NULL */
+static spinlock_t table_lock;
static LIST_HEAD(usb_serial_driver_list);
struct usb_serial *usb_serial_get_by_index(unsigned index)
{
- struct usb_serial *serial = serial_table[index];
+ struct usb_serial *serial;
+
+ spin_lock(&table_lock);
+ serial = serial_table[index];
if (serial)
kref_get(&serial->kref);
+ spin_unlock(&table_lock);
return serial;
}
@@ -78,6 +83,7 @@ static struct usb_serial *get_free_serial (struct usb_serial *serial, int num_po
dbg("%s %d", __FUNCTION__, num_ports);
*minor = 0;
+ spin_lock(&table_lock);
for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
if (serial_table[i])
continue;
@@ -96,8 +102,10 @@ static struct usb_serial *get_free_serial (struct usb_serial *serial, int num_po
dbg("%s - minor base = %d", __FUNCTION__, *minor);
for (i = *minor; (i < (*minor + num_ports)) && (i < SERIAL_TTY_MINORS); ++i)
serial_table[i] = serial;
+ spin_unlock(&table_lock);
return serial;
}
+ spin_unlock(&table_lock);
return NULL;
}
@@ -110,9 +118,11 @@ static void return_serial(struct usb_serial *serial)
if (serial == NULL)
return;
+ spin_lock(&table_lock);
for (i = 0; i < serial->num_ports; ++i) {
serial_table[serial->minor + i] = NULL;
}
+ spin_unlock(&table_lock);
}
static void destroy_serial(struct kref *kref)
@@ -271,7 +281,7 @@ static void serial_close(struct tty_struct *tty, struct file * filp)
static int serial_write (struct tty_struct * tty, const unsigned char *buf, int count)
{
struct usb_serial_port *port = tty->driver_data;
- int retval = -EINVAL;
+ int retval = -ENODEV;
if (!port || port->serial->dev->state == USB_STATE_NOTATTACHED)
goto exit;
@@ -279,6 +289,7 @@ static int serial_write (struct tty_struct * tty, const unsigned char *buf, int
dbg("%s - port %d, %d byte(s)", __FUNCTION__, port->number, count);
if (!port->open_count) {
+ retval = -EINVAL;
dbg("%s - port not opened", __FUNCTION__);
goto exit;
}
@@ -559,15 +570,20 @@ static void port_release(struct device *dev)
port_free(port);
}
-static void port_free(struct usb_serial_port *port)
+static void kill_traffic(struct usb_serial_port *port)
{
usb_kill_urb(port->read_urb);
- usb_free_urb(port->read_urb);
usb_kill_urb(port->write_urb);
- usb_free_urb(port->write_urb);
usb_kill_urb(port->interrupt_in_urb);
- usb_free_urb(port->interrupt_in_urb);
usb_kill_urb(port->interrupt_out_urb);
+}
+
+static void port_free(struct usb_serial_port *port)
+{
+ kill_traffic(port);
+ usb_free_urb(port->read_urb);
+ usb_free_urb(port->write_urb);
+ usb_free_urb(port->interrupt_in_urb);
usb_free_urb(port->interrupt_out_urb);
kfree(port->bulk_in_buffer);
kfree(port->bulk_out_buffer);
@@ -596,6 +612,39 @@ static struct usb_serial * create_serial (struct usb_device *dev,
return serial;
}
+static const struct usb_device_id *match_dynamic_id(struct usb_interface *intf,
+ struct usb_serial_driver *drv)
+{
+ struct usb_dynid *dynid;
+
+ spin_lock(&drv->dynids.lock);
+ list_for_each_entry(dynid, &drv->dynids.list, node) {
+ if (usb_match_one_id(intf, &dynid->id)) {
+ spin_unlock(&drv->dynids.lock);
+ return &dynid->id;
+ }
+ }
+ spin_unlock(&drv->dynids.lock);
+ return NULL;
+}
+
+static const struct usb_device_id *get_iface_id(struct usb_serial_driver *drv,
+ struct usb_interface *intf)
+{
+ const struct usb_device_id *id;
+
+ id = usb_match_id(intf, drv->id_table);
+ if (id) {
+ dbg("static descriptor matches");
+ goto exit;
+ }
+ id = match_dynamic_id(intf, drv);
+ if (id)
+ dbg("dynamic descriptor matches");
+exit:
+ return id;
+}
+
static struct usb_serial_driver *search_serial_device(struct usb_interface *iface)
{
struct list_head *p;
@@ -605,11 +654,9 @@ static struct usb_serial_driver *search_serial_device(struct usb_interface *ifac
/* Check if the usb id matches a known device */
list_for_each(p, &usb_serial_driver_list) {
t = list_entry(p, struct usb_serial_driver, driver_list);
- id = usb_match_id(iface, t->id_table);
- if (id != NULL) {
- dbg("descriptor matches");
+ id = get_iface_id(t, iface);
+ if (id)
return t;
- }
}
return NULL;
@@ -639,14 +686,17 @@ int usb_serial_probe(struct usb_interface *interface,
int num_ports = 0;
int max_endpoints;
+ lock_kernel(); /* guard against unloading a serial driver module */
type = search_serial_device(interface);
if (!type) {
+ unlock_kernel();
dbg("none matched");
return -ENODEV;
}
serial = create_serial (dev, interface, type);
if (!serial) {
+ unlock_kernel();
dev_err(&interface->dev, "%s - out of memory\n", __FUNCTION__);
return -ENOMEM;
}
@@ -656,16 +706,18 @@ int usb_serial_probe(struct usb_interface *interface,
const struct usb_device_id *id;
if (!try_module_get(type->driver.owner)) {
+ unlock_kernel();
dev_err(&interface->dev, "module get failed, exiting\n");
kfree (serial);
return -EIO;
}
- id = usb_match_id(interface, type->id_table);
+ id = get_iface_id(type, interface);
retval = type->probe(serial, id);
module_put(type->driver.owner);
if (retval) {
+ unlock_kernel();
dbg ("sub driver rejected device");
kfree (serial);
return retval;
@@ -735,6 +787,7 @@ int usb_serial_probe(struct usb_interface *interface,
* properly during a later invocation of usb_serial_probe
*/
if (num_bulk_in == 0 || num_bulk_out == 0) {
+ unlock_kernel();
dev_info(&interface->dev, "PL-2303 hack: descriptors matched but endpoints did not\n");
kfree (serial);
return -ENODEV;
@@ -750,6 +803,7 @@ int usb_serial_probe(struct usb_interface *interface,
if (type == &usb_serial_generic_device) {
num_ports = num_bulk_out;
if (num_ports == 0) {
+ unlock_kernel();
dev_err(&interface->dev, "Generic device with no bulk out, not allowed.\n");
kfree (serial);
return -EIO;
@@ -760,6 +814,7 @@ int usb_serial_probe(struct usb_interface *interface,
/* if this device type has a calc_num_ports function, call it */
if (type->calc_num_ports) {
if (!try_module_get(type->driver.owner)) {
+ unlock_kernel();
dev_err(&interface->dev, "module get failed, exiting\n");
kfree (serial);
return -EIO;
@@ -771,12 +826,6 @@ int usb_serial_probe(struct usb_interface *interface,
num_ports = type->num_ports;
}
- if (get_free_serial (serial, num_ports, &minor) == NULL) {
- dev_err(&interface->dev, "No more free serial devices\n");
- kfree (serial);
- return -ENOMEM;
- }
-
serial->minor = minor;
serial->num_ports = num_ports;
serial->num_bulk_in = num_bulk_in;
@@ -791,6 +840,8 @@ int usb_serial_probe(struct usb_interface *interface,
max_endpoints = max(max_endpoints, num_interrupt_out);
max_endpoints = max(max_endpoints, (int)serial->num_ports);
serial->num_port_pointers = max_endpoints;
+ unlock_kernel();
+
dbg("%s - setting up %d port structures for this device", __FUNCTION__, max_endpoints);
for (i = 0; i < max_endpoints; ++i) {
port = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL);
@@ -925,6 +976,11 @@ int usb_serial_probe(struct usb_interface *interface,
}
}
+ if (get_free_serial (serial, num_ports, &minor) == NULL) {
+ dev_err(&interface->dev, "No more free serial devices\n");
+ goto probe_error;
+ }
+
/* register all of the individual ports with the driver core */
for (i = 0; i < num_ports; ++i) {
port = serial->port[i];
@@ -1002,8 +1058,11 @@ void usb_serial_disconnect(struct usb_interface *interface)
if (serial) {
for (i = 0; i < serial->num_ports; ++i) {
port = serial->port[i];
- if (port && port->tty)
- tty_hangup(port->tty);
+ if (port) {
+ if (port->tty)
+ tty_hangup(port->tty);
+ kill_traffic(port);
+ }
}
/* let the last holder of this object
* cause it to be cleaned up */
@@ -1040,6 +1099,7 @@ static int __init usb_serial_init(void)
return -ENOMEM;
/* Initialize our global data */
+ spin_lock_init(&table_lock);
for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
serial_table[i] = NULL;
}
@@ -1138,7 +1198,7 @@ static void fixup_generic(struct usb_serial_driver *device)
set_to_generic_if_null(device, shutdown);
}
-int usb_serial_register(struct usb_serial_driver *driver)
+int usb_serial_register(struct usb_serial_driver *driver) /* must be called with BKL held */
{
int retval;
@@ -1162,7 +1222,7 @@ int usb_serial_register(struct usb_serial_driver *driver)
}
-void usb_serial_deregister(struct usb_serial_driver *device)
+void usb_serial_deregister(struct usb_serial_driver *device) /* must be called with BKL held */
{
info("USB Serial deregistering driver %s", device->description);
list_del(&device->driver_list);
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
index b09f0609605..2f59ff226e2 100644
--- a/drivers/usb/serial/visor.c
+++ b/drivers/usb/serial/visor.c
@@ -90,8 +90,6 @@ static struct usb_device_id id_table [] = {
.driver_info = (kernel_ulong_t)&palm_os_4_probe },
{ USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_Z_ID),
.driver_info = (kernel_ulong_t)&palm_os_4_probe },
- { USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE31_ID),
- .driver_info = (kernel_ulong_t)&palm_os_4_probe },
{ USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE_ID),
.driver_info = (kernel_ulong_t)&palm_os_4_probe },
{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID),
@@ -151,7 +149,6 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_T_ID) },
{ USB_DEVICE(PALM_VENDOR_ID, PALM_TREO_650) },
{ USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_Z_ID) },
- { USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE31_ID) },
{ USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE_ID) },
{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_3_5_ID) },
{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID) },
@@ -189,6 +186,7 @@ static struct usb_serial_driver handspring_device = {
.name = "visor",
},
.description = "Handspring Visor / Palm OS",
+ .usb_driver = &visor_driver,
.id_table = id_table,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = 2,
@@ -219,6 +217,7 @@ static struct usb_serial_driver clie_5_device = {
.name = "clie_5",
},
.description = "Sony Clie 5.0",
+ .usb_driver = &visor_driver,
.id_table = clie_id_5_table,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = 2,
@@ -249,6 +248,7 @@ static struct usb_serial_driver clie_3_5_device = {
.name = "clie_3.5",
},
.description = "Sony Clie 3.5",
+ .usb_driver = &visor_driver,
.id_table = clie_id_3_5_table,
.num_interrupt_in = 0,
.num_bulk_in = 1,
diff --git a/drivers/usb/serial/visor.h b/drivers/usb/serial/visor.h
index 765118d83fb..4ce6f62a6f3 100644
--- a/drivers/usb/serial/visor.h
+++ b/drivers/usb/serial/visor.h
@@ -32,7 +32,6 @@
#define PALM_TUNGSTEN_T_ID 0x0060
#define PALM_TREO_650 0x0061
#define PALM_TUNGSTEN_Z_ID 0x0031
-#define PALM_ZIRE31_ID 0x0061
#define PALM_ZIRE_ID 0x0070
#define PALM_M100_ID 0x0080
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
index 5483d8564c1..bf16e9e1d84 100644
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -161,6 +161,7 @@ static struct usb_serial_driver whiteheat_fake_device = {
.name = "whiteheatnofirm",
},
.description = "Connect Tech - WhiteHEAT - (prerenumeration)",
+ .usb_driver = &whiteheat_driver,
.id_table = id_table_prerenumeration,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = NUM_DONT_CARE,
@@ -176,6 +177,7 @@ static struct usb_serial_driver whiteheat_device = {
.name = "whiteheat",
},
.description = "Connect Tech - WhiteHEAT",
+ .usb_driver = &whiteheat_driver,
.id_table = id_table_std,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = NUM_DONT_CARE,
diff --git a/drivers/usb/storage/datafab.c b/drivers/usb/storage/datafab.c
index 01d8971ad7d..c87ad1bae1d 100644
--- a/drivers/usb/storage/datafab.c
+++ b/drivers/usb/storage/datafab.c
@@ -50,7 +50,6 @@
* in that routine.
*/
-#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/slab.h>
diff --git a/drivers/usb/storage/initializers.c b/drivers/usb/storage/initializers.c
index 5b06f9240d0..3a41740cad9 100644
--- a/drivers/usb/storage/initializers.c
+++ b/drivers/usb/storage/initializers.c
@@ -37,7 +37,6 @@
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/sched.h>
#include <linux/errno.h>
#include "usb.h"
diff --git a/drivers/usb/storage/jumpshot.c b/drivers/usb/storage/jumpshot.c
index 5031aa98f6a..003fcf54588 100644
--- a/drivers/usb/storage/jumpshot.c
+++ b/drivers/usb/storage/jumpshot.c
@@ -47,7 +47,6 @@
* in that routine.
*/
-#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/slab.h>
diff --git a/drivers/usb/storage/onetouch.c b/drivers/usb/storage/onetouch.c
index e565d3d2ab2..6d3dad3d1da 100644
--- a/drivers/usb/storage/onetouch.c
+++ b/drivers/usb/storage/onetouch.c
@@ -33,7 +33,6 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
-#include <linux/usb_ch9.h>
#include <linux/usb/input.h>
#include "usb.h"
#include "onetouch.h"
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
index e1072d52d64..e227f64d564 100644
--- a/drivers/usb/storage/scsiglue.c
+++ b/drivers/usb/storage/scsiglue.c
@@ -110,23 +110,6 @@ static int slave_configure(struct scsi_device *sdev)
* the end, scatter-gather buffers follow page boundaries. */
blk_queue_dma_alignment(sdev->request_queue, (512 - 1));
- /* Set the SCSI level to at least 2. We'll leave it at 3 if that's
- * what is originally reported. We need this to avoid confusing
- * the SCSI layer with devices that report 0 or 1, but need 10-byte
- * commands (ala ATAPI devices behind certain bridges, or devices
- * which simply have broken INQUIRY data).
- *
- * NOTE: This means /dev/sg programs (ala cdrecord) will get the
- * actual information. This seems to be the preference for
- * programs like that.
- *
- * NOTE: This also means that /proc/scsi/scsi and sysfs may report
- * the actual value or the modified one, depending on where the
- * data comes from.
- */
- if (sdev->scsi_level < SCSI_2)
- sdev->scsi_level = sdev->sdev_target->scsi_level = SCSI_2;
-
/* Many devices have trouble transfering more than 32KB at a time,
* while others have trouble with more than 64K. At this time we
* are limiting both to 32K (64 sectores).
@@ -170,13 +153,21 @@ static int slave_configure(struct scsi_device *sdev)
if (us->flags & US_FL_FIX_CAPACITY)
sdev->fix_capacity = 1;
+ /* A few disks have two indistinguishable version, one of
+ * which reports the correct capacity and the other does not.
+ * The sd driver has to guess which is the case. */
+ if (us->flags & US_FL_CAPACITY_HEURISTICS)
+ sdev->guess_capacity = 1;
+
/* Some devices report a SCSI revision level above 2 but are
* unable to handle the REPORT LUNS command (for which
* support is mandatory at level 3). Since we already have
* a Get-Max-LUN request, we won't lose much by setting the
* revision level down to 2. The only devices that would be
* affected are those with sparse LUNs. */
- sdev->scsi_level = sdev->sdev_target->scsi_level = SCSI_2;
+ if (sdev->scsi_level > SCSI_2)
+ sdev->sdev_target->scsi_level =
+ sdev->scsi_level = SCSI_2;
/* USB-IDE bridges tend to report SK = 0x04 (Non-recoverable
* Hardware Error) when any low-level error occurs,
@@ -194,6 +185,16 @@ static int slave_configure(struct scsi_device *sdev)
sdev->use_10_for_ms = 1;
}
+ /* The CB and CBI transports have no way to pass LUN values
+ * other than the bits in the second byte of a CDB. But those
+ * bits don't get set to the LUN value if the device reports
+ * scsi_level == 0 (UNKNOWN). Hence such devices must necessarily
+ * be single-LUN.
+ */
+ if ((us->protocol == US_PR_CB || us->protocol == US_PR_CBI) &&
+ sdev->scsi_level == SCSI_UNKNOWN)
+ us->max_lun = 0;
+
/* Some devices choke when they receive a PREVENT-ALLOW MEDIUM
* REMOVAL command, so suppress those commands. */
if (us->flags & US_FL_NOT_LOCKABLE)
diff --git a/drivers/usb/storage/sddr09.c b/drivers/usb/storage/sddr09.c
index e3528eca29a..b2ed2a3e6fc 100644
--- a/drivers/usb/storage/sddr09.c
+++ b/drivers/usb/storage/sddr09.c
@@ -41,7 +41,6 @@
* EF: compute checksum (?)
*/
-#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/slab.h>
diff --git a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c
index 8fcec01dc62..5e27297c017 100644
--- a/drivers/usb/storage/shuttle_usbat.c
+++ b/drivers/usb/storage/shuttle_usbat.c
@@ -43,7 +43,6 @@
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/cdrom.h>
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index b49f2a78189..9644a8ea4aa 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -573,7 +573,7 @@ UNUSUAL_DEV( 0x054c, 0x002b, 0x0100, 0x0110,
#endif
/* Submitted by Olaf Hering, <olh@suse.de> SuSE Bugzilla #49049 */
-UNUSUAL_DEV( 0x054c, 0x002c, 0x0501, 0x0501,
+UNUSUAL_DEV( 0x054c, 0x002c, 0x0501, 0x2000,
"Sony",
"USB Floppy Drive",
US_SC_DEVICE, US_PR_DEVICE, NULL,
@@ -1101,6 +1101,15 @@ UNUSUAL_DEV( 0x08bd, 0x1100, 0x0000, 0x0000,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_SINGLE_LUN),
+/* Submitted by Dylan Taft <d13f00l@gmail.com>
+ * US_FL_IGNORE_RESIDUE Needed
+ */
+UNUSUAL_DEV( 0x08ca, 0x3103, 0x0100, 0x0100,
+ "AIPTEK",
+ "Aiptek USB Keychain MP3 Player",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE),
+
/* Entry needed for flags. Moreover, all devices with this ID use
* bulk-only transport, but _some_ falsely report Control/Bulk instead.
* One example is "Trumpion Digital Research MYMP3".
@@ -1311,12 +1320,13 @@ UNUSUAL_DEV( 0x0fce, 0xd008, 0x0000, 0x0000,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_NO_WP_DETECT ),
-/* Reported by Jan Mate <mate@fiit.stuba.sk> */
+/* Reported by Jan Mate <mate@fiit.stuba.sk>
+ * and by Soeren Sonnenburg <kernel@nn7.de> */
UNUSUAL_DEV( 0x0fce, 0xe030, 0x0000, 0x0000,
"Sony Ericsson",
"P990i",
US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_FIX_CAPACITY ),
+ US_FL_FIX_CAPACITY | US_FL_IGNORE_RESIDUE ),
/* Reported by Emmanuel Vasilakis <evas@forthnet.gr> */
UNUSUAL_DEV( 0x0fce, 0xe031, 0x0000, 0x0000,
@@ -1325,13 +1335,6 @@ UNUSUAL_DEV( 0x0fce, 0xe031, 0x0000, 0x0000,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_FIX_CAPACITY ),
-/* Reported by Jan Mate <mate@fiit.stuba.sk> */
-UNUSUAL_DEV( 0x0fce, 0xe030, 0x0000, 0x0000,
- "Sony Ericsson",
- "P990i",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_FIX_CAPACITY ),
-
/* Reported by Kevin Cernekee <kpc-usbdev@gelato.uiuc.edu>
* Tested on hardware version 1.10.
* Entry is needed only for the initializer function override.
@@ -1392,6 +1395,16 @@ UNUSUAL_DEV( 0x1652, 0x6600, 0x0201, 0x0201,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_IGNORE_RESIDUE ),
+/* Reported by Thomas Baechler <thomas@archlinux.org>
+ * Fixes I/O errors with Teac HD-35PU devices
+ */
+
+UNUSUAL_DEV( 0x1652, 0x6600, 0x0201, 0x0201,
+ "Super Top",
+ "USB 2.0 IDE DEVICE",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE),
+
/* patch submitted by Davide Perini <perini.davide@dpsoftware.org>
* and Renato Perini <rperini@email.it>
*/
@@ -1430,7 +1443,7 @@ UNUSUAL_DEV( 0xed06, 0x4500, 0x0001, 0x0001,
"DataStor",
"USB4500 FW1.04",
US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_FIX_CAPACITY),
+ US_FL_CAPACITY_HEURISTICS),
/* Control/Bulk transport for all SubClass values */
USUAL_DEV(US_SC_RBC, US_PR_CB, USB_US_TYPE_STOR),
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index 70644506651..7e7ec29782f 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -731,26 +731,27 @@ static int get_pipes(struct us_data *us)
struct usb_endpoint_descriptor *ep_int = NULL;
/*
- * Find the endpoints we need.
+ * Find the first endpoint of each type we need.
* We are expecting a minimum of 2 endpoints - in and out (bulk).
- * An optional interrupt is OK (necessary for CBI protocol).
+ * An optional interrupt-in is OK (necessary for CBI protocol).
* We will ignore any others.
*/
for (i = 0; i < altsetting->desc.bNumEndpoints; i++) {
ep = &altsetting->endpoint[i].desc;
- /* Is it a BULK endpoint? */
if (usb_endpoint_xfer_bulk(ep)) {
- /* BULK in or out? */
- if (usb_endpoint_dir_in(ep))
- ep_in = ep;
- else
- ep_out = ep;
+ if (usb_endpoint_dir_in(ep)) {
+ if (!ep_in)
+ ep_in = ep;
+ } else {
+ if (!ep_out)
+ ep_out = ep;
+ }
}
- /* Is it an interrupt endpoint? */
- else if (usb_endpoint_xfer_int(ep)) {
- ep_int = ep;
+ else if (usb_endpoint_is_int_in(ep)) {
+ if (!ep_int)
+ ep_int = ep;
}
}
diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c
index 296b091cf16..46929a1b6f2 100644
--- a/drivers/usb/usb-skeleton.c
+++ b/drivers/usb/usb-skeleton.c
@@ -90,13 +90,15 @@ static int skel_open(struct inode *inode, struct file *file)
goto exit;
}
+ /* increment our usage count for the device */
+ kref_get(&dev->kref);
+
/* prevent the device from being autosuspended */
retval = usb_autopm_get_interface(interface);
- if (retval)
+ if (retval) {
+ kref_put(&dev->kref, skel_delete);
goto exit;
-
- /* increment our usage count for the device */
- kref_get(&dev->kref);
+ }
/* save our object in the file's private structure */
file->private_data = dev;
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 4e83f01e894..c1536d78555 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -4,20 +4,7 @@
menu "Graphics support"
-config FIRMWARE_EDID
- bool "Enable firmware EDID"
- default y
- ---help---
- This enables access to the EDID transferred from the firmware.
- On the i386, this is from the Video BIOS. Enable this if DDC/I2C
- transfers do not work for your driver and if you are using
- nvidiafb, i810fb or savagefb.
-
- In general, choosing Y for this option is safe. If you
- experience extremely long delays while booting before you get
- something on your display, try setting this to N. Matrox cards in
- combination with certain motherboards and monitors are known to
- suffer from this problem.
+source "drivers/video/backlight/Kconfig"
config FB
tristate "Support for frame buffer devices"
@@ -53,9 +40,27 @@ config FB
(e.g. an accelerated X server) and that are not frame buffer
device-aware may cause unexpected results. If unsure, say N.
+config FIRMWARE_EDID
+ bool "Enable firmware EDID"
+ depends on FB
+ default n
+ ---help---
+ This enables access to the EDID transferred from the firmware.
+ On the i386, this is from the Video BIOS. Enable this if DDC/I2C
+ transfers do not work for your driver and if you are using
+ nvidiafb, i810fb or savagefb.
+
+ In general, choosing Y for this option is safe. If you
+ experience extremely long delays while booting before you get
+ something on your display, try setting this to N. Matrox cards in
+ combination with certain motherboards and monitors are known to
+ suffer from this problem.
+
config FB_DDC
tristate
- depends on FB && I2C && I2C_ALGOBIT
+ depends on FB
+ select I2C_ALGOBIT
+ select I2C
default n
config FB_CFB_FILLRECT
@@ -85,6 +90,14 @@ config FB_CFB_IMAGEBLIT
blitting. This is used by drivers that don't provide their own
(accelerated) version.
+config FB_SVGALIB
+ tristate
+ depends on FB
+ default n
+ ---help---
+ Common utility functions useful to fbdev drivers of VGA-based
+ cards.
+
config FB_MACMODES
tristate
depends on FB
@@ -126,6 +139,9 @@ config FB_TILEBLITTING
This is particularly important to one driver, matroxfb. If
unsure, say N.
+comment "Frambuffer hardware drivers"
+ depends on FB
+
config FB_CIRRUS
tristate "Cirrus Logic support"
depends on FB && (ZORRO || PCI)
@@ -346,42 +362,6 @@ config FB_AMIGA_AGA
and CD32. If you intend to run Linux on any of these systems, say Y;
otherwise say N.
-config FB_CYBER
- tristate "Amiga CyberVision 64 support"
- depends on FB && ZORRO && BROKEN
- select FB_CFB_FILLRECT
- select FB_CFB_COPYAREA
- select FB_CFB_IMAGEBLIT
- help
- This enables support for the Cybervision 64 graphics card from
- Phase5. Please note that its use is not all that intuitive (i.e. if
- you have any questions, be sure to ask!). Say N unless you have a
- Cybervision 64 or plan to get one before you next recompile the
- kernel. Please note that this driver DOES NOT support the
- Cybervision 64/3D card, as they use incompatible video chips.
-
-config FB_VIRGE
- bool "Amiga CyberVision 64/3D support "
- depends on (FB = y) && ZORRO && BROKEN
- select FB_CFB_FILLRECT
- select FB_CFB_COPYAREA
- select FB_CFB_IMAGEBLIT
- help
- This enables support for the Cybervision 64/3D graphics card from
- Phase5. Please note that its use is not all that intuitive (i.e. if
- you have any questions, be sure to ask!). Say N unless you have a
- Cybervision 64/3D or plan to get one before you next recompile the
- kernel. Please note that this driver DOES NOT support the older
- Cybervision 64 card, as they use incompatible video chips.
-
-config FB_RETINAZ3
- tristate "Amiga Retina Z3 support"
- depends on (FB = y) && ZORRO && BROKEN
- help
- This enables support for the Retina Z3 graphics card. Say N unless
- you have a Retina Z3 or plan to get one before you next recompile
- the kernel.
-
config FB_FM2
bool "Amiga FrameMaster II/Rainbow II support"
depends on (FB = y) && ZORRO
@@ -617,10 +597,6 @@ config FB_GBE_MEM
This is the amount of memory reserved for the framebuffer,
which can be any value between 1MB and 8MB.
-config FB_SUN3
- bool "Sun3 framebuffer support"
- depends on (FB = y) && (SUN3 || SUN3X) && BROKEN
-
config FB_SBUS
bool "SBUS and UPA framebuffers"
depends on (FB = y) && SPARC
@@ -629,7 +605,7 @@ config FB_SBUS
config FB_BW2
bool "BWtwo support"
- depends on (FB = y) && (SPARC && FB_SBUS || (SUN3 || SUN3X) && FB_SUN3)
+ depends on (FB = y) && (SPARC && FB_SBUS)
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
@@ -638,7 +614,7 @@ config FB_BW2
config FB_CG3
bool "CGthree support"
- depends on (FB = y) && (SPARC && FB_SBUS || (SUN3 || SUN3X) && FB_SUN3)
+ depends on (FB = y) && (SPARC && FB_SBUS)
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
@@ -647,7 +623,7 @@ config FB_CG3
config FB_CG6
bool "CGsix (GX,TurboGX) support"
- depends on (FB = y) && (SPARC && FB_SBUS || (SUN3 || SUN3X) && FB_SUN3)
+ depends on (FB = y) && (SPARC && FB_SBUS)
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
help
@@ -703,6 +679,7 @@ config FB_NVIDIA
depends on FB && PCI
select I2C_ALGOBIT if FB_NVIDIA_I2C
select I2C if FB_NVIDIA_I2C
+ select FB_BACKLIGHT if FB_NVIDIA_BACKLIGHT
select FB_MODE_HELPERS
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
@@ -731,8 +708,7 @@ config FB_NVIDIA_I2C
config FB_NVIDIA_BACKLIGHT
bool "Support for backlight control"
- depends on FB_NVIDIA && PMAC_BACKLIGHT
- select FB_BACKLIGHT
+ depends on FB_NVIDIA
default y
help
Say Y here if you want to control the backlight of your display.
@@ -740,9 +716,8 @@ config FB_NVIDIA_BACKLIGHT
config FB_RIVA
tristate "nVidia Riva support"
depends on FB && PCI
- select I2C_ALGOBIT if FB_RIVA_I2C
- select I2C if FB_RIVA_I2C
select FB_DDC if FB_RIVA_I2C
+ select FB_BACKLIGHT if FB_RIVA_BACKLIGHT
select FB_MODE_HELPERS
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
@@ -779,8 +754,7 @@ config FB_RIVA_DEBUG
config FB_RIVA_BACKLIGHT
bool "Support for backlight control"
- depends on FB_RIVA && PMAC_BACKLIGHT
- select FB_BACKLIGHT
+ depends on FB_RIVA
default y
help
Say Y here if you want to control the backlight of your display.
@@ -830,8 +804,6 @@ config FB_I810_GTF
config FB_I810_I2C
bool "Enable DDC Support"
depends on FB_I810 && FB_I810_GTF
- select I2C
- select I2C_ALGOBIT
select FB_DDC
help
@@ -1021,9 +993,8 @@ config FB_MATROX_MULTIHEAD
config FB_RADEON
tristate "ATI Radeon display support"
depends on FB && PCI
- select I2C_ALGOBIT if FB_RADEON_I2C
- select I2C if FB_RADEON_I2C
select FB_DDC if FB_RADEON_I2C
+ select FB_BACKLIGHT if FB_RADEON_BACKLIGHT
select FB_MODE_HELPERS
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
@@ -1053,8 +1024,7 @@ config FB_RADEON_I2C
config FB_RADEON_BACKLIGHT
bool "Support for backlight control"
- depends on FB_RADEON && PMAC_BACKLIGHT
- select FB_BACKLIGHT
+ depends on FB_RADEON
default y
help
Say Y here if you want to control the backlight of your display.
@@ -1074,6 +1044,7 @@ config FB_ATY128
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
+ select FB_BACKLIGHT if FB_ATY128_BACKLIGHT
select FB_MACMODES if PPC_PMAC
help
This driver supports graphics boards with the ATI Rage128 chips.
@@ -1085,8 +1056,7 @@ config FB_ATY128
config FB_ATY128_BACKLIGHT
bool "Support for backlight control"
- depends on FB_ATY128 && PMAC_BACKLIGHT
- select FB_BACKLIGHT
+ depends on FB_ATY128
default y
help
Say Y here if you want to control the backlight of your display.
@@ -1097,6 +1067,7 @@ config FB_ATY
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
+ select FB_BACKLIGHT if FB_ATY_BACKLIGHT
select FB_MACMODES if PPC
help
This driver supports graphics boards with the ATI Mach64 chips.
@@ -1135,23 +1106,25 @@ config FB_ATY_GX
config FB_ATY_BACKLIGHT
bool "Support for backlight control"
- depends on FB_ATY && PMAC_BACKLIGHT
- select FB_BACKLIGHT
+ depends on FB_ATY
default y
help
Say Y here if you want to control the backlight of your display.
-config FB_S3TRIO
- bool "S3 Trio display support"
- depends on (FB = y) && PPC && BROKEN
- help
- If you have a S3 Trio say Y. Say N for S3 Virge.
+config FB_S3
+ tristate "S3 Trio/Virge support"
+ depends on FB && PCI
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ select FB_TILEBLITTING
+ select FB_SVGALIB
+ ---help---
+ Driver for graphics boards with S3 Trio / S3 Virge chip.
config FB_SAVAGE
tristate "S3 Savage support"
depends on FB && PCI && EXPERIMENTAL
- select I2C_ALGOBIT if FB_SAVAGE_I2C
- select I2C if FB_SAVAGE_I2C
select FB_DDC if FB_SAVAGE_I2C
select FB_MODE_HELPERS
select FB_CFB_FILLRECT
@@ -1444,8 +1417,8 @@ config FB_PMAG_AA
used mainly in the MIPS-based DECstation series.
config FB_PMAG_BA
- bool "PMAG-BA TURBOchannel framebuffer support"
- depends on (FB = y) && TC
+ tristate "PMAG-BA TURBOchannel framebuffer support"
+ depends on FB && TC
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
@@ -1454,8 +1427,8 @@ config FB_PMAG_BA
used mainly in the MIPS-based DECstation series.
config FB_PMAGB_B
- bool "PMAGB-B TURBOchannel framebuffer support"
- depends on (FB = y) && TC
+ tristate "PMAGB-B TURBOchannel framebuffer support"
+ depends on TC
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
@@ -1600,6 +1573,24 @@ config FB_S3C2410_DEBUG
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
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ ---help---
+ Frame buffer driver for the CRT and LCD controllers in the Silicon
+ Motion SM501.
+
+ This driver is also available as a module ( = code which can be
+ inserted and removed from the running kernel whenever you want). The
+ module will be called sm501fb. If you want to compile it as a module,
+ say M here and read <file:Documentation/modules.txt>.
+
+ If unsure, say N.
+
+
config FB_PNX4008_DUM
tristate "Display Update Module support on Philips PNX4008 board"
depends on FB && ARCH_PNX4008
@@ -1625,6 +1616,26 @@ config FB_IBM_GXT4500
Say Y here to enable support for the IBM GXT4500P display
adaptor, found on some IBM System P (pSeries) machines.
+config FB_PS3
+ bool "PS3 GPU framebuffer driver"
+ depends on FB && PPC_PS3
+ select PS3_PS3AV
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ ---help---
+ Include support for the virtual frame buffer in the PS3 platform.
+
+config FB_PS3_DEFAULT_SIZE_M
+ int "PS3 default frame buffer size (in MiB)"
+ depends on FB_PS3
+ default 18
+ ---help---
+ This is the default size (in MiB) of the virtual frame buffer in
+ the PS3.
+ The default value can be overridden on the kernel command line
+ using the "ps3fb" option (e.g. "ps3fb=9M");
+
config FB_VIRTUAL
tristate "Virtual Frame Buffer support (ONLY FOR TESTING!)"
depends on FB
@@ -1646,6 +1657,7 @@ config FB_VIRTUAL
the vfb_enable=1 option.
If unsure, say N.
+
if VT
source "drivers/video/console/Kconfig"
endif
@@ -1654,9 +1666,5 @@ if FB || SGI_NEWPORT_CONSOLE
source "drivers/video/logo/Kconfig"
endif
-if SYSFS
- source "drivers/video/backlight/Kconfig"
-endif
-
endmenu
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 309a26dd164..760305c8a84 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -12,20 +12,19 @@ fb-objs := $(fb-y)
obj-$(CONFIG_VT) += console/
obj-$(CONFIG_LOGO) += logo/
-obj-$(CONFIG_SYSFS) += backlight/
+obj-y += backlight/
obj-$(CONFIG_FB_CFB_FILLRECT) += cfbfillrect.o
obj-$(CONFIG_FB_CFB_COPYAREA) += cfbcopyarea.o
obj-$(CONFIG_FB_CFB_IMAGEBLIT) += cfbimgblt.o
+obj-$(CONFIG_FB_SVGALIB) += svgalib.o
obj-$(CONFIG_FB_MACMODES) += macmodes.o
obj-$(CONFIG_FB_DDC) += fb_ddc.o
# Hardware specific drivers go first
-obj-$(CONFIG_FB_RETINAZ3) += retz3fb.o
obj-$(CONFIG_FB_AMIGA) += amifb.o c2p.o
obj-$(CONFIG_FB_ARC) += arcfb.o
obj-$(CONFIG_FB_CLPS711X) += clps711xfb.o
-obj-$(CONFIG_FB_CYBER) += cyberfb.o
obj-$(CONFIG_FB_CYBER2000) += cyber2000fb.o
obj-$(CONFIG_FB_PM2) += pm2fb.o
obj-$(CONFIG_FB_PM3) += pm3fb.o
@@ -43,17 +42,16 @@ obj-$(CONFIG_FB_GEODE) += geode/
obj-$(CONFIG_FB_MBX) += mbx/
obj-$(CONFIG_FB_I810) += vgastate.o
obj-$(CONFIG_FB_NEOMAGIC) += neofb.o vgastate.o
-obj-$(CONFIG_FB_VIRGE) += virgefb.o
obj-$(CONFIG_FB_3DFX) += tdfxfb.o
obj-$(CONFIG_FB_CONTROL) += controlfb.o
obj-$(CONFIG_FB_PLATINUM) += platinumfb.o
obj-$(CONFIG_FB_VALKYRIE) += valkyriefb.o
obj-$(CONFIG_FB_CT65550) += chipsfb.o
obj-$(CONFIG_FB_IMSTT) += imsttfb.o
-obj-$(CONFIG_FB_S3TRIO) += S3triofb.o
obj-$(CONFIG_FB_FM2) += fm2fb.o
obj-$(CONFIG_FB_CYBLA) += cyblafb.o
obj-$(CONFIG_FB_TRIDENT) += tridentfb.o
+obj-$(CONFIG_FB_S3) += s3fb.o vgastate.o
obj-$(CONFIG_FB_STI) += stifb.o
obj-$(CONFIG_FB_FFB) += ffb.o sbuslib.o
obj-$(CONFIG_FB_CG6) += cg6.o sbuslib.o
@@ -75,7 +73,6 @@ obj-$(CONFIG_FB_TGA) += tgafb.o
obj-$(CONFIG_FB_HP300) += hpfb.o
obj-$(CONFIG_FB_G364) += g364fb.o
obj-$(CONFIG_FB_SA1100) += sa1100fb.o
-obj-$(CONFIG_FB_SUN3) += sun3fb.o
obj-$(CONFIG_FB_HIT) += hitfb.o
obj-$(CONFIG_FB_EPSON1355) += epson1355fb.o
obj-$(CONFIG_FB_PVR2) += pvr2fb.o
@@ -100,6 +97,8 @@ obj-$(CONFIG_FB_S3C2410) += s3c2410fb.o
obj-$(CONFIG_FB_PNX4008_DUM) += pnx4008/
obj-$(CONFIG_FB_PNX4008_DUM_RGB) += pnx4008/
obj-$(CONFIG_FB_IBM_GXT4500) += gxt4500.o
+obj-$(CONFIG_FB_PS3) += ps3fb.o
+obj-$(CONFIG_FB_SM501) += sm501fb.o
# Platform or fallback drivers go here
obj-$(CONFIG_FB_VESA) += vesafb.o
diff --git a/drivers/video/S3triofb.c b/drivers/video/S3triofb.c
deleted file mode 100644
index b3717c8f1bc..00000000000
--- a/drivers/video/S3triofb.c
+++ /dev/null
@@ -1,790 +0,0 @@
-/*
- * linux/drivers/video/S3Triofb.c -- Open Firmware based frame buffer device
- *
- * Copyright (C) 1997 Peter De Schrijver
- *
- * This driver is partly based on the PowerMac console driver:
- *
- * Copyright (C) 1996 Paul Mackerras
- *
- * and on the Open Firmware based frame buffer device:
- *
- * Copyright (C) 1997 Geert Uytterhoeven
- *
- * 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.
- */
-
-/*
- Bugs : + OF dependencies should be removed.
- + This driver should be merged with the CyberVision driver. The
- CyberVision is a Zorro III implementation of the S3Trio64 chip.
-
-*/
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/fb.h>
-#include <linux/init.h>
-#include <linux/selection.h>
-#include <asm/io.h>
-#include <asm/prom.h>
-#include <asm/pci-bridge.h>
-#include <linux/pci.h>
-
-#include <video/fbcon.h>
-#include <video/fbcon-cfb8.h>
-#include <video/s3blit.h>
-
-
-#define mem_in8(addr) in_8((void *)(addr))
-#define mem_in16(addr) in_le16((void *)(addr))
-#define mem_in32(addr) in_le32((void *)(addr))
-
-#define mem_out8(val, addr) out_8((void *)(addr), val)
-#define mem_out16(val, addr) out_le16((void *)(addr), val)
-#define mem_out32(val, addr) out_le32((void *)(addr), val)
-
-#define IO_OUT16VAL(v, r) (((v) << 8) | (r))
-
-static struct display disp;
-static struct fb_info fb_info;
-static struct { u_char red, green, blue, pad; } palette[256];
-static char s3trio_name[16] = "S3Trio ";
-static char *s3trio_base;
-
-static struct fb_fix_screeninfo fb_fix;
-static struct fb_var_screeninfo fb_var = { 0, };
-
-
- /*
- * Interface used by the world
- */
-
-static void __init s3triofb_of_init(struct device_node *dp);
-static int s3trio_get_fix(struct fb_fix_screeninfo *fix, int con,
- struct fb_info *info);
-static int s3trio_get_var(struct fb_var_screeninfo *var, int con,
- struct fb_info *info);
-static int s3trio_set_var(struct fb_var_screeninfo *var, int con,
- struct fb_info *info);
-static int s3trio_get_cmap(struct fb_cmap *cmap, int kspc, int con,
- struct fb_info *info);
-static int s3trio_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
- u_int transp, struct fb_info *info);
-static int s3trio_pan_display(struct fb_var_screeninfo *var, int con,
- struct fb_info *info);
-static void s3triofb_blank(int blank, struct fb_info *info);
-
- /*
- * Interface to the low level console driver
- */
-
-int s3triofb_init(void);
-static int s3triofbcon_switch(int con, struct fb_info *info);
-static int s3triofbcon_updatevar(int con, struct fb_info *info);
-
- /*
- * Text console acceleration
- */
-
-#ifdef FBCON_HAS_CFB8
-static struct display_switch fbcon_trio8;
-#endif
-
- /*
- * Accelerated Functions used by the low level console driver
- */
-
-static void Trio_WaitQueue(u_short fifo);
-static void Trio_WaitBlit(void);
-static void Trio_BitBLT(u_short curx, u_short cury, u_short destx,
- u_short desty, u_short width, u_short height,
- u_short mode);
-static void Trio_RectFill(u_short x, u_short y, u_short width, u_short height,
- u_short mode, u_short color);
-static void Trio_MoveCursor(u_short x, u_short y);
-
-
- /*
- * Internal routines
- */
-
-static int s3trio_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
- u_int *transp, struct fb_info *info);
-
-static struct fb_ops s3trio_ops = {
- .owner = THIS_MODULE,
- .fb_get_fix = s3trio_get_fix,
- .fb_get_var = s3trio_get_var,
- .fb_set_var = s3trio_set_var,
- .fb_get_cmap = s3trio_get_cmap,
- .fb_set_cmap = gen_set_cmap,
- .fb_setcolreg = s3trio_setcolreg,
- .fb_pan_display =s3trio_pan_display,
- .fb_blank = s3triofb_blank,
-};
-
- /*
- * Get the Fixed Part of the Display
- */
-
-static int s3trio_get_fix(struct fb_fix_screeninfo *fix, int con,
- struct fb_info *info)
-{
- memcpy(fix, &fb_fix, sizeof(fb_fix));
- return 0;
-}
-
-
- /*
- * Get the User Defined Part of the Display
- */
-
-static int s3trio_get_var(struct fb_var_screeninfo *var, int con,
- struct fb_info *info)
-{
- memcpy(var, &fb_var, sizeof(fb_var));
- return 0;
-}
-
-
- /*
- * Set the User Defined Part of the Display
- */
-
-static int s3trio_set_var(struct fb_var_screeninfo *var, int con,
- struct fb_info *info)
-{
- if (var->xres > fb_var.xres || var->yres > fb_var.yres ||
- var->bits_per_pixel > fb_var.bits_per_pixel )
- /* || var->nonstd || var->vmode != FB_VMODE_NONINTERLACED) */
- return -EINVAL;
- if (var->xres_virtual > fb_var.xres_virtual) {
- outw(IO_OUT16VAL((var->xres_virtual /8) & 0xff, 0x13), 0x3d4);
- outw(IO_OUT16VAL(((var->xres_virtual /8 ) & 0x300) >> 3, 0x51), 0x3d4);
- fb_var.xres_virtual = var->xres_virtual;
- fb_fix.line_length = var->xres_virtual;
- }
- fb_var.yres_virtual = var->yres_virtual;
- memcpy(var, &fb_var, sizeof(fb_var));
- return 0;
-}
-
-
- /*
- * Pan or Wrap the Display
- *
- * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
- */
-
-static int s3trio_pan_display(struct fb_var_screeninfo *var, int con,
- struct fb_info *info)
-{
- unsigned int base;
-
- if (var->xoffset > (var->xres_virtual - var->xres))
- return -EINVAL;
- if (var->yoffset > (var->yres_virtual - var->yres))
- return -EINVAL;
-
- fb_var.xoffset = var->xoffset;
- fb_var.yoffset = var->yoffset;
-
- base = var->yoffset * fb_fix.line_length + var->xoffset;
-
- outw(IO_OUT16VAL((base >> 8) & 0xff, 0x0c),0x03D4);
- outw(IO_OUT16VAL(base & 0xff, 0x0d),0x03D4);
- outw(IO_OUT16VAL((base >> 16) & 0xf, 0x69),0x03D4);
- return 0;
-}
-
-
- /*
- * Get the Colormap
- */
-
-static int s3trio_get_cmap(struct fb_cmap *cmap, int kspc, int con,
- struct fb_info *info)
-{
- if (con == info->currcon) /* current console? */
- return fb_get_cmap(cmap, kspc, s3trio_getcolreg, info);
- else if (fb_display[con].cmap.len) /* non default colormap? */
- fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
- else
- fb_copy_cmap(fb_default_cmap(1 << fb_display[con].var.bits_per_pixel),
- cmap, kspc ? 0 : 2);
- return 0;
-}
-
-int __init s3triofb_init(void)
-{
- struct device_node *dp;
-
- dp = find_devices("S3Trio");
- if (dp != 0)
- s3triofb_of_init(dp);
- return 0;
-}
-
-void __init s3trio_resetaccel(void){
-
-
-#define EC01_ENH_ENB 0x0005
-#define EC01_LAW_ENB 0x0010
-#define EC01_MMIO_ENB 0x0020
-
-#define EC00_RESET 0x8000
-#define EC00_ENABLE 0x4000
-#define MF_MULT_MISC 0xE000
-#define SRC_FOREGROUND 0x0020
-#define SRC_BACKGROUND 0x0000
-#define MIX_SRC 0x0007
-#define MF_T_CLIP 0x1000
-#define MF_L_CLIP 0x2000
-#define MF_B_CLIP 0x3000
-#define MF_R_CLIP 0x4000
-#define MF_PIX_CONTROL 0xA000
-#define MFA_SRC_FOREGR_MIX 0x0000
-#define MF_PIX_CONTROL 0xA000
-
- outw(EC00_RESET, 0x42e8);
- inw( 0x42e8);
- outw(EC00_ENABLE, 0x42e8);
- inw( 0x42e8);
- outw(EC01_ENH_ENB | EC01_LAW_ENB,
- 0x4ae8);
- outw(MF_MULT_MISC, 0xbee8); /* 16 bit I/O registers */
-
- /* Now set some basic accelerator registers */
- Trio_WaitQueue(0x0400);
- outw(SRC_FOREGROUND | MIX_SRC, 0xbae8);
- outw(SRC_BACKGROUND | MIX_SRC, 0xb6e8);/* direct color*/
- outw(MF_T_CLIP | 0, 0xbee8 ); /* clip virtual area */
- outw(MF_L_CLIP | 0, 0xbee8 );
- outw(MF_R_CLIP | (640 - 1), 0xbee8);
- outw(MF_B_CLIP | (480 - 1), 0xbee8);
- Trio_WaitQueue(0x0400);
- outw(0xffff, 0xaae8); /* Enable all planes */
- outw(0xffff, 0xaae8); /* Enable all planes */
- outw( MF_PIX_CONTROL | MFA_SRC_FOREGR_MIX, 0xbee8);
-}
-
-int __init s3trio_init(struct device_node *dp){
-
- u_char bus, dev;
- unsigned int t32;
- unsigned short cmd;
-
- pci_device_loc(dp,&bus,&dev);
- pcibios_read_config_dword(bus, dev, PCI_VENDOR_ID, &t32);
- if(t32 == (PCI_DEVICE_ID_S3_TRIO << 16) + PCI_VENDOR_ID_S3) {
- pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_0, &t32);
- pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_1, &t32);
- pcibios_read_config_word(bus, dev, PCI_COMMAND,&cmd);
-
- pcibios_write_config_word(bus, dev, PCI_COMMAND, PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
-
- pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_0,0xffffffff);
- pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_0, &t32);
-
-/* This is a gross hack as OF only maps enough memory for the framebuffer and
- we want to use MMIO too. We should find out which chunk of address space
- we can use here */
- pcibios_write_config_dword(bus,dev,PCI_BASE_ADDRESS_0,0xc6000000);
-
- /* unlock s3 */
-
- outb(0x01, 0x3C3);
-
- outb(inb(0x03CC) | 1, 0x3c2);
-
- outw(IO_OUT16VAL(0x48, 0x38),0x03D4);
- outw(IO_OUT16VAL(0xA0, 0x39),0x03D4);
- outb(0x33,0x3d4);
- outw(IO_OUT16VAL((inb(0x3d5) & ~(0x2 | 0x10 | 0x40)) |
- 0x20, 0x33), 0x3d4);
-
- outw(IO_OUT16VAL(0x6, 0x8), 0x3c4);
-
- /* switch to MMIO only mode */
-
- outb(0x58, 0x3d4);
- outw(IO_OUT16VAL(inb(0x3d5) | 3 | 0x10, 0x58), 0x3d4);
- outw(IO_OUT16VAL(8, 0x53), 0x3d4);
-
- /* switch off I/O accesses */
-
-#if 0
- pcibios_write_config_word(bus, dev, PCI_COMMAND,
- PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
-#endif
- return 1;
- }
-
- return 0;
-}
-
-
- /*
- * Initialisation
- * We heavily rely on OF for the moment. This needs fixing.
- */
-
-static void __init s3triofb_of_init(struct device_node *dp)
-{
- int i, *pp, len;
- unsigned long address, size;
- u_long *CursorBase;
-
- strncat(s3trio_name, dp->name, sizeof(s3trio_name));
- s3trio_name[sizeof(s3trio_name)-1] = '\0';
- strcpy(fb_fix.id, s3trio_name);
-
- if((pp = get_property(dp, "vendor-id", &len)) != NULL
- && *pp!=PCI_VENDOR_ID_S3) {
- printk("%s: can't find S3 Trio board\n", dp->full_name);
- return;
- }
-
- if((pp = get_property(dp, "device-id", &len)) != NULL
- && *pp!=PCI_DEVICE_ID_S3_TRIO) {
- printk("%s: can't find S3 Trio board\n", dp->full_name);
- return;
- }
-
- if ((pp = get_property(dp, "depth", &len)) != NULL
- && len == sizeof(int) && *pp != 8) {
- printk("%s: can't use depth = %d\n", dp->full_name, *pp);
- return;
- }
- if ((pp = get_property(dp, "width", &len)) != NULL
- && len == sizeof(int))
- fb_var.xres = fb_var.xres_virtual = *pp;
- if ((pp = get_property(dp, "height", &len)) != NULL
- && len == sizeof(int))
- fb_var.yres = fb_var.yres_virtual = *pp;
- if ((pp = get_property(dp, "linebytes", &len)) != NULL
- && len == sizeof(int))
- fb_fix.line_length = *pp;
- else
- fb_fix.line_length = fb_var.xres_virtual;
- fb_fix.smem_len = fb_fix.line_length*fb_var.yres;
-
- address = 0xc6000000;
- size = 64*1024*1024;
- if (!request_mem_region(address, size, "S3triofb"))
- return;
-
- s3trio_init(dp);
- s3trio_base = ioremap(address, size);
- fb_fix.smem_start = address;
- fb_fix.type = FB_TYPE_PACKED_PIXELS;
- fb_fix.type_aux = 0;
- fb_fix.accel = FB_ACCEL_S3_TRIO64;
- fb_fix.mmio_start = address+0x1000000;
- fb_fix.mmio_len = 0x1000000;
-
- fb_fix.xpanstep = 1;
- fb_fix.ypanstep = 1;
-
- s3trio_resetaccel();
-
- mem_out8(0x30, s3trio_base+0x1008000 + 0x03D4);
- mem_out8(0x2d, s3trio_base+0x1008000 + 0x03D4);
- mem_out8(0x2e, s3trio_base+0x1008000 + 0x03D4);
-
- mem_out8(0x50, s3trio_base+0x1008000 + 0x03D4);
-
- /* disable HW cursor */
-
- mem_out8(0x39, s3trio_base+0x1008000 + 0x03D4);
- mem_out8(0xa0, s3trio_base+0x1008000 + 0x03D5);
-
- mem_out8(0x45, s3trio_base+0x1008000 + 0x03D4);
- mem_out8(0, s3trio_base+0x1008000 + 0x03D5);
-
- mem_out8(0x4e, s3trio_base+0x1008000 + 0x03D4);
- mem_out8(0, s3trio_base+0x1008000 + 0x03D5);
-
- mem_out8(0x4f, s3trio_base+0x1008000 + 0x03D4);
- mem_out8(0, s3trio_base+0x1008000 + 0x03D5);
-
- /* init HW cursor */
-
- CursorBase = (u_long *)(s3trio_base + 2*1024*1024 - 0x400);
- for (i = 0; i < 8; i++) {
- *(CursorBase +(i*4)) = 0xffffff00;
- *(CursorBase+1+(i*4)) = 0xffff0000;
- *(CursorBase+2+(i*4)) = 0xffff0000;
- *(CursorBase+3+(i*4)) = 0xffff0000;
- }
- for (i = 8; i < 64; i++) {
- *(CursorBase +(i*4)) = 0xffff0000;
- *(CursorBase+1+(i*4)) = 0xffff0000;
- *(CursorBase+2+(i*4)) = 0xffff0000;
- *(CursorBase+3+(i*4)) = 0xffff0000;
- }
-
-
- mem_out8(0x4c, s3trio_base+0x1008000 + 0x03D4);
- mem_out8(((2*1024 - 1)&0xf00)>>8, s3trio_base+0x1008000 + 0x03D5);
-
- mem_out8(0x4d, s3trio_base+0x1008000 + 0x03D4);
- mem_out8((2*1024 - 1) & 0xff, s3trio_base+0x1008000 + 0x03D5);
-
- mem_out8(0x45, s3trio_base+0x1008000 + 0x03D4);
- mem_in8(s3trio_base+0x1008000 + 0x03D4);
-
- mem_out8(0x4a, s3trio_base+0x1008000 + 0x03D4);
- mem_out8(0x80, s3trio_base+0x1008000 + 0x03D5);
- mem_out8(0x80, s3trio_base+0x1008000 + 0x03D5);
- mem_out8(0x80, s3trio_base+0x1008000 + 0x03D5);
-
- mem_out8(0x4b, s3trio_base+0x1008000 + 0x03D4);
- mem_out8(0x00, s3trio_base+0x1008000 + 0x03D5);
- mem_out8(0x00, s3trio_base+0x1008000 + 0x03D5);
- mem_out8(0x00, s3trio_base+0x1008000 + 0x03D5);
-
- mem_out8(0x45, s3trio_base+0x1008000 + 0x03D4);
- mem_out8(0, s3trio_base+0x1008000 + 0x03D5);
-
- /* setup default color table */
-
- for(i = 0; i < 16; i++) {
- int j = color_table[i];
- palette[i].red=default_red[j];
- palette[i].green=default_grn[j];
- palette[i].blue=default_blu[j];
- }
-
- s3trio_setcolreg(255, 56, 100, 160, 0, NULL /* not used */);
- s3trio_setcolreg(254, 0, 0, 0, 0, NULL /* not used */);
- memset((char *)s3trio_base, 0, 640*480);
-
-#if 0
- Trio_RectFill(0, 0, 90, 90, 7, 1);
-#endif
-
- fb_fix.visual = FB_VISUAL_PSEUDOCOLOR ;
- fb_var.xoffset = fb_var.yoffset = 0;
- fb_var.bits_per_pixel = 8;
- fb_var.grayscale = 0;
- fb_var.red.offset = fb_var.green.offset = fb_var.blue.offset = 0;
- fb_var.red.length = fb_var.green.length = fb_var.blue.length = 8;
- fb_var.red.msb_right = fb_var.green.msb_right = fb_var.blue.msb_right = 0;
- fb_var.transp.offset = fb_var.transp.length = fb_var.transp.msb_right = 0;
- fb_var.nonstd = 0;
- fb_var.activate = 0;
- fb_var.height = fb_var.width = -1;
- fb_var.accel_flags = FB_ACCELF_TEXT;
-#warning FIXME: always obey fb_var.accel_flags
- fb_var.pixclock = 1;
- fb_var.left_margin = fb_var.right_margin = 0;
- fb_var.upper_margin = fb_var.lower_margin = 0;
- fb_var.hsync_len = fb_var.vsync_len = 0;
- fb_var.sync = 0;
- fb_var.vmode = FB_VMODE_NONINTERLACED;
-
- disp.var = fb_var;
- disp.cmap.start = 0;
- disp.cmap.len = 0;
- disp.cmap.red = disp.cmap.green = disp.cmap.blue = disp.cmap.transp = NULL;
- disp.visual = fb_fix.visual;
- disp.type = fb_fix.type;
- disp.type_aux = fb_fix.type_aux;
- disp.ypanstep = 0;
- disp.ywrapstep = 0;
- disp.line_length = fb_fix.line_length;
- disp.can_soft_blank = 1;
- disp.inverse = 0;
-#ifdef FBCON_HAS_CFB8
- if (fb_var.accel_flags & FB_ACCELF_TEXT)
- disp.dispsw = &fbcon_trio8;
- else
- disp.dispsw = &fbcon_cfb8;
-#else
- disp.dispsw = &fbcon_dummy;
-#endif
- disp.scrollmode = fb_var.accel_flags & FB_ACCELF_TEXT ? 0 : SCROLL_YREDRAW;
-
- strcpy(fb_info.modename, "Trio64 ");
- strncat(fb_info.modename, dp->full_name, sizeof(fb_info.modename));
- fb_info.currcon = -1;
- fb_info.fbops = &s3trio_ops;
- fb_info.screen_base = s3trio_base;
-#if 0
- fb_info.fbvar_num = 1;
- fb_info.fbvar = &fb_var;
-#endif
- fb_info.disp = &disp;
- fb_info.fontname[0] = '\0';
- fb_info.changevar = NULL;
- fb_info.switch_con = &s3triofbcon_switch;
- fb_info.updatevar = &s3triofbcon_updatevar;
-#if 0
- fb_info.setcmap = &s3triofbcon_setcmap;
-#endif
-
- fb_info.flags = FBINFO_FLAG_DEFAULT;
- if (register_framebuffer(&fb_info) < 0) {
- iounmap(fb_info.screen_base);
- fb_info.screen_base = NULL;
- return;
- }
-
- printk("fb%d: S3 Trio frame buffer device on %s\n",
- fb_info.node, dp->full_name);
-}
-
-
-static int s3triofbcon_switch(int con, struct fb_info *info)
-{
- /* Do we have to save the colormap? */
- if (fb_display[info->currcon].cmap.len)
- fb_get_cmap(&fb_display[info->currcon].cmap, 1, s3trio_getcolreg, info);
-
- info->currcon = con;
- /* Install new colormap */
- do_install_cmap(con,info);
- return 0;
-}
-
- /*
- * Update the `var' structure (called by fbcon.c)
- */
-
-static int s3triofbcon_updatevar(int con, struct fb_info *info)
-{
- /* Nothing */
- return 0;
-}
-
- /*
- * Blank the display.
- */
-
-static int s3triofb_blank(int blank, struct fb_info *info)
-{
- unsigned char x;
-
- mem_out8(0x1, s3trio_base+0x1008000 + 0x03c4);
- x = mem_in8(s3trio_base+0x1008000 + 0x03c5);
- mem_out8((x & (~0x20)) | (blank << 5), s3trio_base+0x1008000 + 0x03c5);
- return 0;
-}
-
- /*
- * Read a single color register and split it into
- * colors/transparent. Return != 0 for invalid regno.
- */
-
-static int s3trio_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
- u_int *transp, struct fb_info *info)
-{
- if (regno > 255)
- return 1;
- *red = (palette[regno].red << 8) | palette[regno].red;
- *green = (palette[regno].green << 8) | palette[regno].green;
- *blue = (palette[regno].blue << 8) | palette[regno].blue;
- *transp = 0;
- return 0;
-}
-
-
- /*
- * Set a single color register. Return != 0 for invalid regno.
- */
-
-static int s3trio_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
- u_int transp, struct fb_info *info)
-{
- if (regno > 255)
- return 1;
-
- red >>= 8;
- green >>= 8;
- blue >>= 8;
- palette[regno].red = red;
- palette[regno].green = green;
- palette[regno].blue = blue;
-
- mem_out8(regno,s3trio_base+0x1008000 + 0x3c8);
- mem_out8((red & 0xff) >> 2,s3trio_base+0x1008000 + 0x3c9);
- mem_out8((green & 0xff) >> 2,s3trio_base+0x1008000 + 0x3c9);
- mem_out8((blue & 0xff) >> 2,s3trio_base+0x1008000 + 0x3c9);
-
- return 0;
-}
-
-static void Trio_WaitQueue(u_short fifo) {
-
- u_short status;
-
- do
- {
- status = mem_in16(s3trio_base + 0x1000000 + 0x9AE8);
- } while (!(status & fifo));
-
-}
-
-static void Trio_WaitBlit(void) {
-
- u_short status;
-
- do
- {
- status = mem_in16(s3trio_base + 0x1000000 + 0x9AE8);
- } while (status & 0x200);
-
-}
-
-static void Trio_BitBLT(u_short curx, u_short cury, u_short destx,
- u_short desty, u_short width, u_short height,
- u_short mode) {
-
- u_short blitcmd = 0xc011;
-
- /* Set drawing direction */
- /* -Y, X maj, -X (default) */
-
- if (curx > destx)
- blitcmd |= 0x0020; /* Drawing direction +X */
- else {
- curx += (width - 1);
- destx += (width - 1);
- }
-
- if (cury > desty)
- blitcmd |= 0x0080; /* Drawing direction +Y */
- else {
- cury += (height - 1);
- desty += (height - 1);
- }
-
- Trio_WaitQueue(0x0400);
-
- outw(0xa000, 0xBEE8);
- outw(0x60 | mode, 0xBAE8);
-
- outw(curx, 0x86E8);
- outw(cury, 0x82E8);
-
- outw(destx, 0x8EE8);
- outw(desty, 0x8AE8);
-
- outw(height - 1, 0xBEE8);
- outw(width - 1, 0x96E8);
-
- outw(blitcmd, 0x9AE8);
-
-}
-
-static void Trio_RectFill(u_short x, u_short y, u_short width, u_short height,
- u_short mode, u_short color) {
-
- u_short blitcmd = 0x40b1;
-
- Trio_WaitQueue(0x0400);
-
- outw(0xa000, 0xBEE8);
- outw((0x20 | mode), 0xBAE8);
- outw(0xe000, 0xBEE8);
- outw(color, 0xA6E8);
- outw(x, 0x86E8);
- outw(y, 0x82E8);
- outw((height - 1), 0xBEE8);
- outw((width - 1), 0x96E8);
- outw(blitcmd, 0x9AE8);
-
-}
-
-
-static void Trio_MoveCursor(u_short x, u_short y) {
-
- mem_out8(0x39, s3trio_base + 0x1008000 + 0x3d4);
- mem_out8(0xa0, s3trio_base + 0x1008000 + 0x3d5);
-
- mem_out8(0x46, s3trio_base + 0x1008000 + 0x3d4);
- mem_out8((x & 0x0700) >> 8, s3trio_base + 0x1008000 + 0x3d5);
- mem_out8(0x47, s3trio_base + 0x1008000 + 0x3d4);
- mem_out8(x & 0x00ff, s3trio_base + 0x1008000 + 0x3d5);
-
- mem_out8(0x48, s3trio_base + 0x1008000 + 0x3d4);
- mem_out8((y & 0x0700) >> 8, s3trio_base + 0x1008000 + 0x3d5);
- mem_out8(0x49, s3trio_base + 0x1008000 + 0x3d4);
- mem_out8(y & 0x00ff, s3trio_base + 0x1008000 + 0x3d5);
-
-}
-
-
- /*
- * Text console acceleration
- */
-
-#ifdef FBCON_HAS_CFB8
-static void fbcon_trio8_bmove(struct display *p, int sy, int sx, int dy,
- int dx, int height, int width)
-{
- sx *= 8; dx *= 8; width *= 8;
- Trio_BitBLT((u_short)sx, (u_short)(sy*fontheight(p)), (u_short)dx,
- (u_short)(dy*fontheight(p)), (u_short)width,
- (u_short)(height*fontheight(p)), (u_short)S3_NEW);
-}
-
-static void fbcon_trio8_clear(struct vc_data *conp, struct display *p, int sy,
- int sx, int height, int width)
-{
- unsigned char bg;
-
- sx *= 8; width *= 8;
- bg = attr_bgcol_ec(p,conp);
- Trio_RectFill((u_short)sx,
- (u_short)(sy*fontheight(p)),
- (u_short)width,
- (u_short)(height*fontheight(p)),
- (u_short)S3_NEW,
- (u_short)bg);
-}
-
-static void fbcon_trio8_putc(struct vc_data *conp, struct display *p, int c,
- int yy, int xx)
-{
- Trio_WaitBlit();
- fbcon_cfb8_putc(conp, p, c, yy, xx);
-}
-
-static void fbcon_trio8_putcs(struct vc_data *conp, struct display *p,
- const unsigned short *s, int count, int yy, int xx)
-{
- Trio_WaitBlit();
- fbcon_cfb8_putcs(conp, p, s, count, yy, xx);
-}
-
-static void fbcon_trio8_revc(struct display *p, int xx, int yy)
-{
- Trio_WaitBlit();
- fbcon_cfb8_revc(p, xx, yy);
-}
-
-static struct display_switch fbcon_trio8 = {
- .setup = fbcon_cfb8_setup,
- .bmove = fbcon_trio8_bmove,
- .clear = fbcon_trio8_clear,
- .putc = fbcon_trio8_putc,
- .putcs = fbcon_trio8_putcs,
- .revc = fbcon_trio8_revc,
- .clear_margins = fbcon_cfb8_clear_margins,
- .fontwidthmask = FONTWIDTH(8)
-};
-#endif
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/video/atafb.c b/drivers/video/atafb.c
index 602db660bc7..bffe2b94634 100644
--- a/drivers/video/atafb.c
+++ b/drivers/video/atafb.c
@@ -49,7 +49,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c
index 2e976ffcde0..8726c366971 100644
--- a/drivers/video/aty/aty128fb.c
+++ b/drivers/video/aty/aty128fb.c
@@ -1695,9 +1695,6 @@ static int __devinit aty128fb_setup(char *options)
#ifdef CONFIG_FB_ATY128_BACKLIGHT
#define MAX_LEVEL 0xFF
-static struct backlight_properties aty128_bl_data;
-
-/* Call with fb_info->bl_mutex held */
static int aty128_bl_get_level_brightness(struct aty128fb_par *par,
int level)
{
@@ -1705,6 +1702,7 @@ static int aty128_bl_get_level_brightness(struct aty128fb_par *par,
int atylevel;
/* Get and convert the value */
+ /* No locking of bl_curve since we read a single value */
atylevel = MAX_LEVEL -
(info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_LEVEL);
@@ -1724,19 +1722,18 @@ static int aty128_bl_get_level_brightness(struct aty128fb_par *par,
/* That one prevents proper CRT output with LCD off */
#undef BACKLIGHT_DAC_OFF
-/* Call with fb_info->bl_mutex held */
-static int __aty128_bl_update_status(struct backlight_device *bd)
+static int aty128_bl_update_status(struct backlight_device *bd)
{
struct aty128fb_par *par = class_get_devdata(&bd->class_dev);
unsigned int reg = aty_ld_le32(LVDS_GEN_CNTL);
int level;
- if (bd->props->power != FB_BLANK_UNBLANK ||
- bd->props->fb_blank != FB_BLANK_UNBLANK ||
+ if (bd->props.power != FB_BLANK_UNBLANK ||
+ bd->props.fb_blank != FB_BLANK_UNBLANK ||
!par->lcd_on)
level = 0;
else
- level = bd->props->brightness;
+ level = bd->props.brightness;
reg |= LVDS_BL_MOD_EN | LVDS_BLON;
if (level > 0) {
@@ -1778,43 +1775,22 @@ static int __aty128_bl_update_status(struct backlight_device *bd)
return 0;
}
-static int aty128_bl_update_status(struct backlight_device *bd)
-{
- struct aty128fb_par *par = class_get_devdata(&bd->class_dev);
- struct fb_info *info = pci_get_drvdata(par->pdev);
- int ret;
-
- mutex_lock(&info->bl_mutex);
- ret = __aty128_bl_update_status(bd);
- mutex_unlock(&info->bl_mutex);
-
- return ret;
-}
-
static int aty128_bl_get_brightness(struct backlight_device *bd)
{
- return bd->props->brightness;
+ return bd->props.brightness;
}
-static struct backlight_properties aty128_bl_data = {
- .owner = THIS_MODULE,
+static struct backlight_ops aty128_bl_data = {
.get_brightness = aty128_bl_get_brightness,
.update_status = aty128_bl_update_status,
- .max_brightness = (FB_BACKLIGHT_LEVELS - 1),
};
static void aty128_bl_set_power(struct fb_info *info, int power)
{
- mutex_lock(&info->bl_mutex);
-
if (info->bl_dev) {
- down(&info->bl_dev->sem);
- info->bl_dev->props->power = power;
- __aty128_bl_update_status(info->bl_dev);
- up(&info->bl_dev->sem);
+ info->bl_dev->props.power = power;
+ backlight_update_status(info->bl_dev);
}
-
- mutex_unlock(&info->bl_mutex);
}
static void aty128_bl_init(struct aty128fb_par *par)
@@ -1841,25 +1817,15 @@ static void aty128_bl_init(struct aty128fb_par *par)
goto error;
}
- mutex_lock(&info->bl_mutex);
info->bl_dev = bd;
fb_bl_default_curve(info, 0,
63 * FB_BACKLIGHT_MAX / MAX_LEVEL,
219 * FB_BACKLIGHT_MAX / MAX_LEVEL);
- mutex_unlock(&info->bl_mutex);
- down(&bd->sem);
- bd->props->brightness = aty128_bl_data.max_brightness;
- bd->props->power = FB_BLANK_UNBLANK;
- bd->props->update_status(bd);
- up(&bd->sem);
-
-#ifdef CONFIG_PMAC_BACKLIGHT
- mutex_lock(&pmac_backlight_mutex);
- if (!pmac_backlight)
- pmac_backlight = bd;
- mutex_unlock(&pmac_backlight_mutex);
-#endif
+ bd->props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
+ bd->props.brightness = bd->props.max_brightness;
+ bd->props.power = FB_BLANK_UNBLANK;
+ backlight_update_status(bd);
printk("aty128: Backlight initialized (%s)\n", name);
@@ -1869,31 +1835,10 @@ error:
return;
}
-static void aty128_bl_exit(struct aty128fb_par *par)
+static void aty128_bl_exit(struct backlight_device *bd)
{
- struct fb_info *info = pci_get_drvdata(par->pdev);
-
-#ifdef CONFIG_PMAC_BACKLIGHT
- mutex_lock(&pmac_backlight_mutex);
-#endif
-
- mutex_lock(&info->bl_mutex);
- if (info->bl_dev) {
-#ifdef CONFIG_PMAC_BACKLIGHT
- if (pmac_backlight == info->bl_dev)
- pmac_backlight = NULL;
-#endif
-
- backlight_device_unregister(info->bl_dev);
- info->bl_dev = NULL;
-
- printk("aty128: Backlight unloaded\n");
- }
- mutex_unlock(&info->bl_mutex);
-
-#ifdef CONFIG_PMAC_BACKLIGHT
- mutex_unlock(&pmac_backlight_mutex);
-#endif
+ backlight_device_unregister(bd);
+ printk("aty128: Backlight unloaded\n");
}
#endif /* CONFIG_FB_ATY128_BACKLIGHT */
@@ -2180,11 +2125,12 @@ static void __devexit aty128_remove(struct pci_dev *pdev)
par = info->par;
+ unregister_framebuffer(info);
+
#ifdef CONFIG_FB_ATY128_BACKLIGHT
- aty128_bl_exit(par);
+ aty128_bl_exit(info->bl_dev);
#endif
- unregister_framebuffer(info);
#ifdef CONFIG_MTRR
if (par->mtrr.vram_valid)
mtrr_del(par->mtrr.vram, info->fix.smem_start,
@@ -2214,11 +2160,6 @@ static int aty128fb_blank(int blank, struct fb_info *fb)
if (par->lock_blank || par->asleep)
return 0;
-#ifdef CONFIG_FB_ATY128_BACKLIGHT
- if (machine_is(powermac) && blank)
- aty128_bl_set_power(fb, FB_BLANK_POWERDOWN);
-#endif
-
if (blank & FB_BLANK_VSYNC_SUSPEND)
state |= 2;
if (blank & FB_BLANK_HSYNC_SUSPEND)
@@ -2233,11 +2174,6 @@ static int aty128fb_blank(int blank, struct fb_info *fb)
aty128_set_lcd_enable(par, par->lcd_on && !blank);
}
-#ifdef CONFIG_FB_ATY128_BACKLIGHT
- if (machine_is(powermac) && !blank)
- aty128_bl_set_power(fb, FB_BLANK_UNBLANK);
-#endif
-
return 0;
}
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
index f2ebdd88008..a7e0062233f 100644
--- a/drivers/video/aty/atyfb_base.c
+++ b/drivers/video/aty/atyfb_base.c
@@ -2114,15 +2114,13 @@ static int atyfb_pci_resume(struct pci_dev *pdev)
#ifdef CONFIG_FB_ATY_BACKLIGHT
#define MAX_LEVEL 0xFF
-static struct backlight_properties aty_bl_data;
-
-/* Call with fb_info->bl_mutex held */
static int aty_bl_get_level_brightness(struct atyfb_par *par, int level)
{
struct fb_info *info = pci_get_drvdata(par->pdev);
int atylevel;
/* Get and convert the value */
+ /* No locking of bl_curve since we read a single value */
atylevel = info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_LEVEL;
if (atylevel < 0)
@@ -2133,18 +2131,17 @@ static int aty_bl_get_level_brightness(struct atyfb_par *par, int level)
return atylevel;
}
-/* Call with fb_info->bl_mutex held */
-static int __aty_bl_update_status(struct backlight_device *bd)
+static int aty_bl_update_status(struct backlight_device *bd)
{
struct atyfb_par *par = class_get_devdata(&bd->class_dev);
unsigned int reg = aty_ld_lcd(LCD_MISC_CNTL, par);
int level;
- if (bd->props->power != FB_BLANK_UNBLANK ||
- bd->props->fb_blank != FB_BLANK_UNBLANK)
+ if (bd->props.power != FB_BLANK_UNBLANK ||
+ bd->props.fb_blank != FB_BLANK_UNBLANK)
level = 0;
else
- level = bd->props->brightness;
+ level = bd->props.brightness;
reg |= (BLMOD_EN | BIASMOD_EN);
if (level > 0) {
@@ -2159,45 +2156,16 @@ static int __aty_bl_update_status(struct backlight_device *bd)
return 0;
}
-static int aty_bl_update_status(struct backlight_device *bd)
-{
- struct atyfb_par *par = class_get_devdata(&bd->class_dev);
- struct fb_info *info = pci_get_drvdata(par->pdev);
- int ret;
-
- mutex_lock(&info->bl_mutex);
- ret = __aty_bl_update_status(bd);
- mutex_unlock(&info->bl_mutex);
-
- return ret;
-}
-
static int aty_bl_get_brightness(struct backlight_device *bd)
{
- return bd->props->brightness;
+ return bd->props.brightness;
}
-static struct backlight_properties aty_bl_data = {
- .owner = THIS_MODULE,
+static struct backlight_ops aty_bl_data = {
.get_brightness = aty_bl_get_brightness,
.update_status = aty_bl_update_status,
- .max_brightness = (FB_BACKLIGHT_LEVELS - 1),
};
-static void aty_bl_set_power(struct fb_info *info, int power)
-{
- mutex_lock(&info->bl_mutex);
-
- if (info->bl_dev) {
- down(&info->bl_dev->sem);
- info->bl_dev->props->power = power;
- __aty_bl_update_status(info->bl_dev);
- up(&info->bl_dev->sem);
- }
-
- mutex_unlock(&info->bl_mutex);
-}
-
static void aty_bl_init(struct atyfb_par *par)
{
struct fb_info *info = pci_get_drvdata(par->pdev);
@@ -2218,25 +2186,15 @@ static void aty_bl_init(struct atyfb_par *par)
goto error;
}
- mutex_lock(&info->bl_mutex);
info->bl_dev = bd;
fb_bl_default_curve(info, 0,
0x3F * FB_BACKLIGHT_MAX / MAX_LEVEL,
0xFF * FB_BACKLIGHT_MAX / MAX_LEVEL);
- mutex_unlock(&info->bl_mutex);
- down(&bd->sem);
- bd->props->brightness = aty_bl_data.max_brightness;
- bd->props->power = FB_BLANK_UNBLANK;
- bd->props->update_status(bd);
- up(&bd->sem);
-
-#ifdef CONFIG_PMAC_BACKLIGHT
- mutex_lock(&pmac_backlight_mutex);
- if (!pmac_backlight)
- pmac_backlight = bd;
- mutex_unlock(&pmac_backlight_mutex);
-#endif
+ bd->props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
+ bd->props.brightness = bd->props.max_brightness;
+ bd->props.power = FB_BLANK_UNBLANK;
+ backlight_update_status(bd);
printk("aty: Backlight initialized (%s)\n", name);
@@ -2246,30 +2204,10 @@ error:
return;
}
-static void aty_bl_exit(struct atyfb_par *par)
+static void aty_bl_exit(struct backlight_device *bd)
{
- struct fb_info *info = pci_get_drvdata(par->pdev);
-
-#ifdef CONFIG_PMAC_BACKLIGHT
- mutex_lock(&pmac_backlight_mutex);
-#endif
-
- mutex_lock(&info->bl_mutex);
- if (info->bl_dev) {
-#ifdef CONFIG_PMAC_BACKLIGHT
- if (pmac_backlight == info->bl_dev)
- pmac_backlight = NULL;
-#endif
-
- backlight_device_unregister(info->bl_dev);
-
- printk("aty: Backlight unloaded\n");
- }
- mutex_unlock(&info->bl_mutex);
-
-#ifdef CONFIG_PMAC_BACKLIGHT
- mutex_unlock(&pmac_backlight_mutex);
-#endif
+ backlight_device_unregister(bd);
+ printk("aty: Backlight unloaded\n");
}
#endif /* CONFIG_FB_ATY_BACKLIGHT */
@@ -2566,7 +2504,7 @@ static int __devinit aty_init(struct fb_info *info)
info->fix.smem_len == 0x80000 ? 'K' : 'M', ramname, xtal, par->pll_limits.pll_max,
par->pll_limits.mclk, par->pll_limits.xclk);
-#if defined(DEBUG) && defined(CONFIG_ATY_CT)
+#if defined(DEBUG) && defined(CONFIG_FB_ATY_CT)
if (M64_HAS(INTEGRATED)) {
int i;
printk("debug atyfb: BUS_CNTL DAC_CNTL MEM_CNTL EXT_MEM_CNTL CRTC_GEN_CNTL "
@@ -2814,8 +2752,6 @@ static int atyfb_blank(int blank, struct fb_info *info)
return 0;
#ifdef CONFIG_FB_ATY_BACKLIGHT
- if (machine_is(powermac) && blank > FB_BLANK_NORMAL)
- aty_bl_set_power(info, FB_BLANK_POWERDOWN);
#elif defined(CONFIG_FB_ATY_GENERIC_LCD)
if (par->lcd_table && blank > FB_BLANK_NORMAL &&
(aty_ld_lcd(LCD_GEN_CNTL, par) & LCD_ON)) {
@@ -2846,8 +2782,6 @@ static int atyfb_blank(int blank, struct fb_info *info)
aty_st_le32(CRTC_GEN_CNTL, gen_cntl, par);
#ifdef CONFIG_FB_ATY_BACKLIGHT
- if (machine_is(powermac) && blank <= FB_BLANK_NORMAL)
- aty_bl_set_power(info, FB_BLANK_UNBLANK);
#elif defined(CONFIG_FB_ATY_GENERIC_LCD)
if (par->lcd_table && blank <= FB_BLANK_NORMAL &&
(aty_ld_lcd(LCD_GEN_CNTL, par) & LCD_ON)) {
@@ -2957,8 +2891,6 @@ extern void (*prom_palette) (int);
static int __devinit atyfb_setup_sparc(struct pci_dev *pdev,
struct fb_info *info, unsigned long addr)
{
- extern int con_is_present(void);
-
struct atyfb_par *par = info->par;
struct pcidev_cookie *pcp;
char prop[128];
@@ -3728,13 +3660,13 @@ static void __devexit atyfb_remove(struct fb_info *info)
aty_set_crtc(par, &saved_crtc);
par->pll_ops->set_pll(info, &saved_pll);
+ unregister_framebuffer(info);
+
#ifdef CONFIG_FB_ATY_BACKLIGHT
if (M64_HAS(MOBIL_BUS))
- aty_bl_exit(par);
+ aty_bl_exit(info->bl_dev);
#endif
- unregister_framebuffer(info);
-
#ifdef CONFIG_MTRR
if (par->mtrr_reg >= 0) {
mtrr_del(par->mtrr_reg, 0, 0);
diff --git a/drivers/video/aty/mach64_accel.c b/drivers/video/aty/mach64_accel.c
index 1490e5e1c23..a8f60c33863 100644
--- a/drivers/video/aty/mach64_accel.c
+++ b/drivers/video/aty/mach64_accel.c
@@ -3,7 +3,6 @@
* ATI Mach64 Hardware Acceleration
*/
-#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/fb.h>
#include <video/mach64.h>
diff --git a/drivers/video/aty/mach64_gx.c b/drivers/video/aty/mach64_gx.c
index 2045639cb67..10c988aef58 100644
--- a/drivers/video/aty/mach64_gx.c
+++ b/drivers/video/aty/mach64_gx.c
@@ -5,7 +5,6 @@
#include <linux/delay.h>
#include <linux/fb.h>
-#include <linux/sched.h>
#include <asm/io.h>
diff --git a/drivers/video/aty/radeon_backlight.c b/drivers/video/aty/radeon_backlight.c
index 3abfd4a380c..0be25fa5540 100644
--- a/drivers/video/aty/radeon_backlight.c
+++ b/drivers/video/aty/radeon_backlight.c
@@ -19,8 +19,6 @@
#define MAX_RADEON_LEVEL 0xFF
-static struct backlight_properties radeon_bl_data;
-
struct radeon_bl_privdata {
struct radeonfb_info *rinfo;
uint8_t negative;
@@ -29,17 +27,13 @@ struct radeon_bl_privdata {
static int radeon_bl_get_level_brightness(struct radeon_bl_privdata *pdata,
int level)
{
- struct fb_info *info = pdata->rinfo->info;
int rlevel;
- mutex_lock(&info->bl_mutex);
-
/* Get and convert the value */
+ /* No locking of bl_curve since we read a single value */
rlevel = pdata->rinfo->info->bl_curve[level] *
FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL;
- mutex_unlock(&info->bl_mutex);
-
if (rlevel < 0)
rlevel = 0;
else if (rlevel > MAX_RADEON_LEVEL)
@@ -65,11 +59,11 @@ static int radeon_bl_update_status(struct backlight_device *bd)
* backlight. This provides some greater power saving and the display
* is useless without backlight anyway.
*/
- if (bd->props->power != FB_BLANK_UNBLANK ||
- bd->props->fb_blank != FB_BLANK_UNBLANK)
+ if (bd->props.power != FB_BLANK_UNBLANK ||
+ bd->props.fb_blank != FB_BLANK_UNBLANK)
level = 0;
else
- level = bd->props->brightness;
+ level = bd->props.brightness;
del_timer_sync(&rinfo->lvds_timer);
radeon_engine_idle();
@@ -130,14 +124,12 @@ static int radeon_bl_update_status(struct backlight_device *bd)
static int radeon_bl_get_brightness(struct backlight_device *bd)
{
- return bd->props->brightness;
+ return bd->props.brightness;
}
-static struct backlight_properties radeon_bl_data = {
- .owner = THIS_MODULE,
+static struct backlight_ops radeon_bl_data = {
.get_brightness = radeon_bl_get_brightness,
.update_status = radeon_bl_update_status,
- .max_brightness = (FB_BACKLIGHT_LEVELS - 1),
};
void radeonfb_bl_init(struct radeonfb_info *rinfo)
@@ -188,25 +180,15 @@ void radeonfb_bl_init(struct radeonfb_info *rinfo)
machine_is_compatible("PowerBook6,5");
#endif
- mutex_lock(&rinfo->info->bl_mutex);
rinfo->info->bl_dev = bd;
fb_bl_default_curve(rinfo->info, 0,
63 * FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL,
217 * FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL);
- mutex_unlock(&rinfo->info->bl_mutex);
- down(&bd->sem);
- bd->props->brightness = radeon_bl_data.max_brightness;
- bd->props->power = FB_BLANK_UNBLANK;
- bd->props->update_status(bd);
- up(&bd->sem);
-
-#ifdef CONFIG_PMAC_BACKLIGHT
- mutex_lock(&pmac_backlight_mutex);
- if (!pmac_backlight)
- pmac_backlight = bd;
- mutex_unlock(&pmac_backlight_mutex);
-#endif
+ bd->props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
+ bd->props.brightness = bd->props.max_brightness;
+ bd->props.power = FB_BLANK_UNBLANK;
+ backlight_update_status(bd);
printk("radeonfb: Backlight initialized (%s)\n", name);
@@ -219,29 +201,16 @@ error:
void radeonfb_bl_exit(struct radeonfb_info *rinfo)
{
-#ifdef CONFIG_PMAC_BACKLIGHT
- mutex_lock(&pmac_backlight_mutex);
-#endif
+ struct backlight_device *bd = rinfo->info->bl_dev;
- mutex_lock(&rinfo->info->bl_mutex);
- if (rinfo->info->bl_dev) {
+ if (bd) {
struct radeon_bl_privdata *pdata;
-#ifdef CONFIG_PMAC_BACKLIGHT
- if (pmac_backlight == rinfo->info->bl_dev)
- pmac_backlight = NULL;
-#endif
-
- pdata = class_get_devdata(&rinfo->info->bl_dev->class_dev);
- backlight_device_unregister(rinfo->info->bl_dev);
+ pdata = class_get_devdata(&bd->class_dev);
+ backlight_device_unregister(bd);
kfree(pdata);
rinfo->info->bl_dev = NULL;
printk("radeonfb: Backlight unloaded\n");
}
- mutex_unlock(&rinfo->info->bl_mutex);
-
-#ifdef CONFIG_PMAC_BACKLIGHT
- mutex_unlock(&pmac_backlight_mutex);
-#endif
}
diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c
index 0ed577e7cc2..7e228aded4c 100644
--- a/drivers/video/aty/radeon_base.c
+++ b/drivers/video/aty/radeon_base.c
@@ -2393,7 +2393,6 @@ static void __devexit radeonfb_pci_unregister (struct pci_dev *pdev)
if (!rinfo)
return;
- radeonfb_bl_exit(rinfo);
radeonfb_pm_exit(rinfo);
if (rinfo->mon1_EDID)
@@ -2420,6 +2419,8 @@ static void __devexit radeonfb_pci_unregister (struct pci_dev *pdev)
unregister_framebuffer(info);
+ radeonfb_bl_exit(rinfo);
+
iounmap(rinfo->mmio_base);
iounmap(rinfo->fb_base);
diff --git a/drivers/video/aty/radeon_i2c.c b/drivers/video/aty/radeon_i2c.c
index e7c5b219ad1..50847992070 100644
--- a/drivers/video/aty/radeon_i2c.c
+++ b/drivers/video/aty/radeon_i2c.c
@@ -1,6 +1,5 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/fb.h>
diff --git a/drivers/video/au1100fb.c b/drivers/video/au1100fb.c
index ef5c16f7f5a..80a81eccad3 100644
--- a/drivers/video/au1100fb.c
+++ b/drivers/video/au1100fb.c
@@ -468,11 +468,10 @@ int au1100fb_drv_probe(struct device *dev)
return -EINVAL;
/* Allocate new device private */
- if (!(fbdev = kmalloc(sizeof(struct au1100fb_device), GFP_KERNEL))) {
+ if (!(fbdev = kzalloc(sizeof(struct au1100fb_device), GFP_KERNEL))) {
print_err("fail to allocate device private record");
return -ENOMEM;
}
- memset((void*)fbdev, 0, sizeof(struct au1100fb_device));
fbdev->panel = &known_lcd_panels[drv_info.panel_idx];
@@ -549,10 +548,9 @@ int au1100fb_drv_probe(struct device *dev)
fbdev->info.fbops = &au1100fb_ops;
fbdev->info.fix = au1100fb_fix;
- if (!(fbdev->info.pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL))) {
+ if (!(fbdev->info.pseudo_palette = kzalloc(sizeof(u32) * 16, GFP_KERNEL))) {
return -ENOMEM;
}
- memset(fbdev->info.pseudo_palette, 0, sizeof(u32) * 16);
if (fb_alloc_cmap(&fbdev->info.cmap, AU1100_LCD_NBR_PALETTE_ENTRIES, 0) < 0) {
print_err("Fail to allocate colormap (%d entries)",
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index 02f15297a02..47d15b5d985 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -19,11 +19,6 @@ config BACKLIGHT_CLASS_DEVICE
To have support for your specific LCD panel you will have to
select the proper drivers which depend on this option.
-config BACKLIGHT_DEVICE
- bool
- depends on BACKLIGHT_CLASS_DEVICE
- default y
-
config LCD_CLASS_DEVICE
tristate "Lowlevel LCD controls"
depends on BACKLIGHT_LCD_SUPPORT
@@ -37,14 +32,9 @@ config LCD_CLASS_DEVICE
To have support for your specific LCD panel you will have to
select the proper drivers which depend on this option.
-config LCD_DEVICE
- bool
- depends on LCD_CLASS_DEVICE
- default y
-
config BACKLIGHT_CORGI
tristate "Sharp Corgi Backlight Driver (SL Series)"
- depends on BACKLIGHT_DEVICE && PXA_SHARPSL
+ depends on BACKLIGHT_CLASS_DEVICE && PXA_SHARPSL
default y
help
If you have a Sharp Zaurus SL-C7xx, SL-Cxx00 or SL-6000x say y to enable the
@@ -52,7 +42,7 @@ config BACKLIGHT_CORGI
config BACKLIGHT_LOCOMO
tristate "Sharp LOCOMO LCD/Backlight Driver"
- depends on BACKLIGHT_DEVICE && SHARP_LOCOMO
+ depends on BACKLIGHT_CLASS_DEVICE && SHARP_LOCOMO
default y
help
If you have a Sharp Zaurus SL-5500 (Collie) or SL-5600 (Poodle) say y to
@@ -60,9 +50,16 @@ config BACKLIGHT_LOCOMO
config BACKLIGHT_HP680
tristate "HP Jornada 680 Backlight Driver"
- depends on BACKLIGHT_DEVICE && SH_HP6XX
+ depends on BACKLIGHT_CLASS_DEVICE && SH_HP6XX
default y
help
If you have a HP Jornada 680, say y to enable the
backlight driver.
+config BACKLIGHT_PROGEAR
+ tristate "Frontpath ProGear Backlight Driver"
+ depends on BACKLIGHT_CLASS_DEVICE && PCI && X86
+ default n
+ help
+ If you have a Frontpath ProGear say Y to enable the
+ backlight driver.
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index 65e5553fc84..0c3ce46f509 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -5,3 +5,4 @@ obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o
obj-$(CONFIG_BACKLIGHT_CORGI) += corgi_bl.o
obj-$(CONFIG_BACKLIGHT_HP680) += hp680_bl.o
obj-$(CONFIG_BACKLIGHT_LOCOMO) += locomolcd.o
+obj-$(CONFIG_BACKLIGHT_PROGEAR) += progear_bl.o
diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c
index 9601bfe309a..c65e81ff357 100644
--- a/drivers/video/backlight/backlight.c
+++ b/drivers/video/backlight/backlight.c
@@ -14,6 +14,9 @@
#include <linux/err.h>
#include <linux/fb.h>
+#ifdef CONFIG_PMAC_BACKLIGHT
+#include <asm/backlight.h>
+#endif
#if defined(CONFIG_FB) || (defined(CONFIG_FB_MODULE) && \
defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE))
@@ -28,19 +31,18 @@ static int fb_notifier_callback(struct notifier_block *self,
struct fb_event *evdata = data;
/* If we aren't interested in this event, skip it immediately ... */
- if (event != FB_EVENT_BLANK)
+ if (event != FB_EVENT_BLANK && event != FB_EVENT_CONBLANK)
return 0;
bd = container_of(self, struct backlight_device, fb_notif);
- down(&bd->sem);
- if (bd->props)
- if (!bd->props->check_fb ||
- bd->props->check_fb(evdata->info)) {
- bd->props->fb_blank = *(int *)evdata->data;
- if (likely(bd->props && bd->props->update_status))
- bd->props->update_status(bd);
+ mutex_lock(&bd->ops_lock);
+ if (bd->ops)
+ if (!bd->ops->check_fb ||
+ bd->ops->check_fb(evdata->info)) {
+ bd->props.fb_blank = *(int *)evdata->data;
+ backlight_update_status(bd);
}
- up(&bd->sem);
+ mutex_unlock(&bd->ops_lock);
return 0;
}
@@ -69,15 +71,9 @@ static inline void backlight_unregister_fb(struct backlight_device *bd)
static ssize_t backlight_show_power(struct class_device *cdev, char *buf)
{
- int rc = -ENXIO;
struct backlight_device *bd = to_backlight_device(cdev);
- down(&bd->sem);
- if (likely(bd->props))
- rc = sprintf(buf, "%d\n", bd->props->power);
- up(&bd->sem);
-
- return rc;
+ return sprintf(buf, "%d\n", bd->props.power);
}
static ssize_t backlight_store_power(struct class_device *cdev, const char *buf, size_t count)
@@ -93,30 +89,23 @@ static ssize_t backlight_store_power(struct class_device *cdev, const char *buf,
if (size != count)
return -EINVAL;
- down(&bd->sem);
- if (likely(bd->props)) {
+ mutex_lock(&bd->ops_lock);
+ if (bd->ops) {
pr_debug("backlight: set power to %d\n", power);
- bd->props->power = power;
- if (likely(bd->props->update_status))
- bd->props->update_status(bd);
+ bd->props.power = power;
+ backlight_update_status(bd);
rc = count;
}
- up(&bd->sem);
+ mutex_unlock(&bd->ops_lock);
return rc;
}
static ssize_t backlight_show_brightness(struct class_device *cdev, char *buf)
{
- int rc = -ENXIO;
struct backlight_device *bd = to_backlight_device(cdev);
- down(&bd->sem);
- if (likely(bd->props))
- rc = sprintf(buf, "%d\n", bd->props->brightness);
- up(&bd->sem);
-
- return rc;
+ return sprintf(buf, "%d\n", bd->props.brightness);
}
static ssize_t backlight_store_brightness(struct class_device *cdev, const char *buf, size_t count)
@@ -132,35 +121,28 @@ static ssize_t backlight_store_brightness(struct class_device *cdev, const char
if (size != count)
return -EINVAL;
- down(&bd->sem);
- if (likely(bd->props)) {
- if (brightness > bd->props->max_brightness)
+ mutex_lock(&bd->ops_lock);
+ if (bd->ops) {
+ if (brightness > bd->props.max_brightness)
rc = -EINVAL;
else {
pr_debug("backlight: set brightness to %d\n",
brightness);
- bd->props->brightness = brightness;
- if (likely(bd->props->update_status))
- bd->props->update_status(bd);
+ bd->props.brightness = brightness;
+ backlight_update_status(bd);
rc = count;
}
}
- up(&bd->sem);
+ mutex_unlock(&bd->ops_lock);
return rc;
}
static ssize_t backlight_show_max_brightness(struct class_device *cdev, char *buf)
{
- int rc = -ENXIO;
struct backlight_device *bd = to_backlight_device(cdev);
- down(&bd->sem);
- if (likely(bd->props))
- rc = sprintf(buf, "%d\n", bd->props->max_brightness);
- up(&bd->sem);
-
- return rc;
+ return sprintf(buf, "%d\n", bd->props.max_brightness);
}
static ssize_t backlight_show_actual_brightness(struct class_device *cdev,
@@ -169,10 +151,10 @@ static ssize_t backlight_show_actual_brightness(struct class_device *cdev,
int rc = -ENXIO;
struct backlight_device *bd = to_backlight_device(cdev);
- down(&bd->sem);
- if (likely(bd->props && bd->props->get_brightness))
- rc = sprintf(buf, "%d\n", bd->props->get_brightness(bd));
- up(&bd->sem);
+ mutex_lock(&bd->ops_lock);
+ if (bd->ops && bd->ops->get_brightness)
+ rc = sprintf(buf, "%d\n", bd->ops->get_brightness(bd));
+ mutex_unlock(&bd->ops_lock);
return rc;
}
@@ -211,7 +193,7 @@ static const struct class_device_attribute bl_class_device_attributes[] = {
* respective framebuffer device).
* @devdata: an optional pointer to be stored in the class_device. The
* methods may retrieve it by using class_get_devdata(&bd->class_dev).
- * @bp: the backlight properties structure.
+ * @ops: the backlight operations structure.
*
* Creates and registers new backlight class_device. Returns either an
* ERR_PTR() or a pointer to the newly allocated device.
@@ -219,39 +201,42 @@ static const struct class_device_attribute bl_class_device_attributes[] = {
struct backlight_device *backlight_device_register(const char *name,
struct device *dev,
void *devdata,
- struct backlight_properties *bp)
+ struct backlight_ops *ops)
{
int i, rc;
struct backlight_device *new_bd;
pr_debug("backlight_device_alloc: name=%s\n", name);
- new_bd = kmalloc(sizeof(struct backlight_device), GFP_KERNEL);
- if (unlikely(!new_bd))
+ new_bd = kzalloc(sizeof(struct backlight_device), GFP_KERNEL);
+ if (!new_bd)
return ERR_PTR(-ENOMEM);
- init_MUTEX(&new_bd->sem);
- new_bd->props = bp;
- memset(&new_bd->class_dev, 0, sizeof(new_bd->class_dev));
+ mutex_init(&new_bd->update_lock);
+ mutex_init(&new_bd->ops_lock);
+ new_bd->ops = ops;
new_bd->class_dev.class = &backlight_class;
new_bd->class_dev.dev = dev;
strlcpy(new_bd->class_dev.class_id, name, KOBJ_NAME_LEN);
class_set_devdata(&new_bd->class_dev, devdata);
rc = class_device_register(&new_bd->class_dev);
- if (unlikely(rc)) {
-error: kfree(new_bd);
+ if (rc) {
+ kfree(new_bd);
return ERR_PTR(rc);
}
rc = backlight_register_fb(new_bd);
- if (unlikely(rc))
- goto error;
+ if (rc) {
+ class_device_unregister(&new_bd->class_dev);
+ return ERR_PTR(rc);
+ }
+
for (i = 0; i < ARRAY_SIZE(bl_class_device_attributes); i++) {
rc = class_device_create_file(&new_bd->class_dev,
&bl_class_device_attributes[i]);
- if (unlikely(rc)) {
+ if (rc) {
while (--i >= 0)
class_device_remove_file(&new_bd->class_dev,
&bl_class_device_attributes[i]);
@@ -261,6 +246,13 @@ error: kfree(new_bd);
}
}
+#ifdef CONFIG_PMAC_BACKLIGHT
+ mutex_lock(&pmac_backlight_mutex);
+ if (!pmac_backlight)
+ pmac_backlight = new_bd;
+ mutex_unlock(&pmac_backlight_mutex);
+#endif
+
return new_bd;
}
EXPORT_SYMBOL(backlight_device_register);
@@ -280,13 +272,20 @@ void backlight_device_unregister(struct backlight_device *bd)
pr_debug("backlight_device_unregister: name=%s\n", bd->class_dev.class_id);
+#ifdef CONFIG_PMAC_BACKLIGHT
+ mutex_lock(&pmac_backlight_mutex);
+ if (pmac_backlight == bd)
+ pmac_backlight = NULL;
+ mutex_unlock(&pmac_backlight_mutex);
+#endif
+
for (i = 0; i < ARRAY_SIZE(bl_class_device_attributes); i++)
class_device_remove_file(&bd->class_dev,
&bl_class_device_attributes[i]);
- down(&bd->sem);
- bd->props = NULL;
- up(&bd->sem);
+ mutex_lock(&bd->ops_lock);
+ bd->ops = NULL;
+ mutex_unlock(&bd->ops_lock);
backlight_unregister_fb(bd);
diff --git a/drivers/video/backlight/corgi_bl.c b/drivers/video/backlight/corgi_bl.c
index fde1d951812..ce00e18a4e5 100644
--- a/drivers/video/backlight/corgi_bl.c
+++ b/drivers/video/backlight/corgi_bl.c
@@ -22,7 +22,6 @@
#include <asm/hardware/sharpsl_pm.h>
static int corgibl_intensity;
-static DEFINE_MUTEX(bl_mutex);
static struct backlight_properties corgibl_data;
static struct backlight_device *corgi_backlight_device;
static struct corgibl_machinfo *bl_machinfo;
@@ -34,20 +33,18 @@ static unsigned long corgibl_flags;
static int corgibl_send_intensity(struct backlight_device *bd)
{
void (*corgi_kick_batt)(void);
- int intensity = bd->props->brightness;
+ int intensity = bd->props.brightness;
- if (bd->props->power != FB_BLANK_UNBLANK)
+ if (bd->props.power != FB_BLANK_UNBLANK)
intensity = 0;
- if (bd->props->fb_blank != FB_BLANK_UNBLANK)
+ if (bd->props.fb_blank != FB_BLANK_UNBLANK)
intensity = 0;
if (corgibl_flags & CORGIBL_SUSPENDED)
intensity = 0;
if (corgibl_flags & CORGIBL_BATTLOW)
intensity &= bl_machinfo->limit_mask;
- mutex_lock(&bl_mutex);
bl_machinfo->set_bl_intensity(intensity);
- mutex_unlock(&bl_mutex);
corgibl_intensity = intensity;
@@ -61,17 +58,21 @@ static int corgibl_send_intensity(struct backlight_device *bd)
}
#ifdef CONFIG_PM
-static int corgibl_suspend(struct platform_device *dev, pm_message_t state)
+static int corgibl_suspend(struct platform_device *pdev, pm_message_t state)
{
+ struct backlight_device *bd = platform_get_drvdata(pdev);
+
corgibl_flags |= CORGIBL_SUSPENDED;
- corgibl_send_intensity(corgi_backlight_device);
+ backlight_update_status(bd);
return 0;
}
-static int corgibl_resume(struct platform_device *dev)
+static int corgibl_resume(struct platform_device *pdev)
{
+ struct backlight_device *bd = platform_get_drvdata(pdev);
+
corgibl_flags &= ~CORGIBL_SUSPENDED;
- corgibl_send_intensity(corgi_backlight_device);
+ backlight_update_status(bd);
return 0;
}
#else
@@ -84,12 +85,6 @@ static int corgibl_get_intensity(struct backlight_device *bd)
return corgibl_intensity;
}
-static int corgibl_set_intensity(struct backlight_device *bd)
-{
- corgibl_send_intensity(corgi_backlight_device);
- return 0;
-}
-
/*
* Called when the battery is low to limit the backlight intensity.
* If limit==0 clear any limit, otherwise limit the intensity
@@ -100,15 +95,14 @@ void corgibl_limit_intensity(int limit)
corgibl_flags |= CORGIBL_BATTLOW;
else
corgibl_flags &= ~CORGIBL_BATTLOW;
- corgibl_send_intensity(corgi_backlight_device);
+ backlight_update_status(corgi_backlight_device);
}
EXPORT_SYMBOL(corgibl_limit_intensity);
-static struct backlight_properties corgibl_data = {
- .owner = THIS_MODULE,
+static struct backlight_ops corgibl_ops = {
.get_brightness = corgibl_get_intensity,
- .update_status = corgibl_set_intensity,
+ .update_status = corgibl_send_intensity,
};
static int corgibl_probe(struct platform_device *pdev)
@@ -116,30 +110,34 @@ static int corgibl_probe(struct platform_device *pdev)
struct corgibl_machinfo *machinfo = pdev->dev.platform_data;
bl_machinfo = machinfo;
- corgibl_data.max_brightness = machinfo->max_intensity;
if (!machinfo->limit_mask)
machinfo->limit_mask = -1;
corgi_backlight_device = backlight_device_register ("corgi-bl",
- &pdev->dev, NULL, &corgibl_data);
+ &pdev->dev, NULL, &corgibl_ops);
if (IS_ERR (corgi_backlight_device))
return PTR_ERR (corgi_backlight_device);
- corgibl_data.power = FB_BLANK_UNBLANK;
- corgibl_data.brightness = machinfo->default_intensity;
- corgibl_send_intensity(corgi_backlight_device);
+ platform_set_drvdata(pdev, corgi_backlight_device);
+
+ corgi_backlight_device->props.max_brightness = machinfo->max_intensity;
+ corgi_backlight_device->props.power = FB_BLANK_UNBLANK;
+ corgi_backlight_device->props.brightness = machinfo->default_intensity;
+ backlight_update_status(corgi_backlight_device);
printk("Corgi Backlight Driver Initialized.\n");
return 0;
}
-static int corgibl_remove(struct platform_device *dev)
+static int corgibl_remove(struct platform_device *pdev)
{
+ struct backlight_device *bd = platform_get_drvdata(pdev);
+
corgibl_data.power = 0;
corgibl_data.brightness = 0;
- corgibl_send_intensity(corgi_backlight_device);
+ backlight_update_status(bd);
- backlight_device_unregister(corgi_backlight_device);
+ backlight_device_unregister(bd);
printk("Corgi Backlight Driver Unloaded\n");
return 0;
diff --git a/drivers/video/backlight/hp680_bl.c b/drivers/video/backlight/hp680_bl.c
index c07d8207fb5..0899fccbd57 100644
--- a/drivers/video/backlight/hp680_bl.c
+++ b/drivers/video/backlight/hp680_bl.c
@@ -28,17 +28,16 @@
static int hp680bl_suspended;
static int current_intensity = 0;
static DEFINE_SPINLOCK(bl_lock);
-static struct backlight_device *hp680_backlight_device;
static void hp680bl_send_intensity(struct backlight_device *bd)
{
unsigned long flags;
u16 v;
- int intensity = bd->props->brightness;
+ int intensity = bd->props.brightness;
- if (bd->props->power != FB_BLANK_UNBLANK)
+ if (bd->props.power != FB_BLANK_UNBLANK)
intensity = 0;
- if (bd->props->fb_blank != FB_BLANK_UNBLANK)
+ if (bd->props.fb_blank != FB_BLANK_UNBLANK)
intensity = 0;
if (hp680bl_suspended)
intensity = 0;
@@ -66,17 +65,21 @@ static void hp680bl_send_intensity(struct backlight_device *bd)
#ifdef CONFIG_PM
-static int hp680bl_suspend(struct platform_device *dev, pm_message_t state)
+static int hp680bl_suspend(struct platform_device *pdev, pm_message_t state)
{
+ struct backlight_device *bd = platform_get_drvdata(pdev);
+
hp680bl_suspended = 1;
- hp680bl_send_intensity(hp680_backlight_device);
+ hp680bl_send_intensity(bd);
return 0;
}
-static int hp680bl_resume(struct platform_device *dev)
+static int hp680bl_resume(struct platform_device *pdev)
{
+ struct backlight_device *bd = platform_get_drvdata(pdev);
+
hp680bl_suspended = 0;
- hp680bl_send_intensity(hp680_backlight_device);
+ hp680bl_send_intensity(bd);
return 0;
}
#else
@@ -95,33 +98,38 @@ static int hp680bl_get_intensity(struct backlight_device *bd)
return current_intensity;
}
-static struct backlight_properties hp680bl_data = {
- .owner = THIS_MODULE,
- .max_brightness = HP680_MAX_INTENSITY,
+static struct backlight_ops hp680bl_ops = {
.get_brightness = hp680bl_get_intensity,
.update_status = hp680bl_set_intensity,
};
-static int __init hp680bl_probe(struct platform_device *dev)
+static int __init hp680bl_probe(struct platform_device *pdev)
{
- hp680_backlight_device = backlight_device_register ("hp680-bl",
- &dev->dev, NULL, &hp680bl_data);
- if (IS_ERR (hp680_backlight_device))
- return PTR_ERR (hp680_backlight_device);
+ struct backlight_device *bd;
+
+ bd = backlight_device_register ("hp680-bl", &pdev->dev, NULL,
+ &hp680bl_ops);
+ if (IS_ERR(bd))
+ return PTR_ERR(bd);
- hp680_backlight_device->props->brightness = HP680_DEFAULT_INTENSITY;
- hp680bl_send_intensity(hp680_backlight_device);
+ platform_set_drvdata(pdev, bd);
+
+ bd->props.max_brightness = HP680_MAX_INTENSITY;
+ bd->props.brightness = HP680_DEFAULT_INTENSITY;
+ hp680bl_send_intensity(bd);
return 0;
}
-static int hp680bl_remove(struct platform_device *dev)
+static int hp680bl_remove(struct platform_device *pdev)
{
+ struct backlight_device *bd = platform_get_drvdata(pdev);
+
hp680bl_data.brightness = 0;
hp680bl_data.power = 0;
- hp680bl_send_intensity(hp680_backlight_device);
+ hp680bl_send_intensity(bd);
- backlight_device_unregister(hp680_backlight_device);
+ backlight_device_unregister(bd);
return 0;
}
diff --git a/drivers/video/backlight/lcd.c b/drivers/video/backlight/lcd.c
index f6e041627ed..6ef8f0a7a13 100644
--- a/drivers/video/backlight/lcd.c
+++ b/drivers/video/backlight/lcd.c
@@ -31,11 +31,11 @@ static int fb_notifier_callback(struct notifier_block *self,
return 0;
ld = container_of(self, struct lcd_device, fb_notif);
- down(&ld->sem);
- if (ld->props)
- if (!ld->props->check_fb || ld->props->check_fb(evdata->info))
- ld->props->set_power(ld, *(int *)evdata->data);
- up(&ld->sem);
+ mutex_lock(&ld->ops_lock);
+ if (ld->ops)
+ if (!ld->ops->check_fb || ld->ops->check_fb(evdata->info))
+ ld->ops->set_power(ld, *(int *)evdata->data);
+ mutex_unlock(&ld->ops_lock);
return 0;
}
@@ -66,12 +66,12 @@ static ssize_t lcd_show_power(struct class_device *cdev, char *buf)
int rc;
struct lcd_device *ld = to_lcd_device(cdev);
- down(&ld->sem);
- if (likely(ld->props && ld->props->get_power))
- rc = sprintf(buf, "%d\n", ld->props->get_power(ld));
+ mutex_lock(&ld->ops_lock);
+ if (ld->ops && ld->ops->get_power)
+ rc = sprintf(buf, "%d\n", ld->ops->get_power(ld));
else
rc = -ENXIO;
- up(&ld->sem);
+ mutex_unlock(&ld->ops_lock);
return rc;
}
@@ -89,13 +89,13 @@ static ssize_t lcd_store_power(struct class_device *cdev, const char *buf, size_
if (size != count)
return -EINVAL;
- down(&ld->sem);
- if (likely(ld->props && ld->props->set_power)) {
+ mutex_lock(&ld->ops_lock);
+ if (ld->ops && ld->ops->set_power) {
pr_debug("lcd: set power to %d\n", power);
- ld->props->set_power(ld, power);
+ ld->ops->set_power(ld, power);
rc = count;
}
- up(&ld->sem);
+ mutex_unlock(&ld->ops_lock);
return rc;
}
@@ -105,10 +105,10 @@ static ssize_t lcd_show_contrast(struct class_device *cdev, char *buf)
int rc = -ENXIO;
struct lcd_device *ld = to_lcd_device(cdev);
- down(&ld->sem);
- if (likely(ld->props && ld->props->get_contrast))
- rc = sprintf(buf, "%d\n", ld->props->get_contrast(ld));
- up(&ld->sem);
+ mutex_lock(&ld->ops_lock);
+ if (ld->ops && ld->ops->get_contrast)
+ rc = sprintf(buf, "%d\n", ld->ops->get_contrast(ld));
+ mutex_unlock(&ld->ops_lock);
return rc;
}
@@ -126,28 +126,22 @@ static ssize_t lcd_store_contrast(struct class_device *cdev, const char *buf, si
if (size != count)
return -EINVAL;
- down(&ld->sem);
- if (likely(ld->props && ld->props->set_contrast)) {
+ mutex_lock(&ld->ops_lock);
+ if (ld->ops && ld->ops->set_contrast) {
pr_debug("lcd: set contrast to %d\n", contrast);
- ld->props->set_contrast(ld, contrast);
+ ld->ops->set_contrast(ld, contrast);
rc = count;
}
- up(&ld->sem);
+ mutex_unlock(&ld->ops_lock);
return rc;
}
static ssize_t lcd_show_max_contrast(struct class_device *cdev, char *buf)
{
- int rc = -ENXIO;
struct lcd_device *ld = to_lcd_device(cdev);
- down(&ld->sem);
- if (likely(ld->props))
- rc = sprintf(buf, "%d\n", ld->props->max_contrast);
- up(&ld->sem);
-
- return rc;
+ return sprintf(buf, "%d\n", ld->props.max_contrast);
}
static void lcd_class_release(struct class_device *dev)
@@ -180,45 +174,46 @@ static const struct class_device_attribute lcd_class_device_attributes[] = {
* respective framebuffer device).
* @devdata: an optional pointer to be stored in the class_device. The
* methods may retrieve it by using class_get_devdata(ld->class_dev).
- * @lp: the lcd properties structure.
+ * @ops: the lcd operations structure.
*
* Creates and registers a new lcd class_device. Returns either an ERR_PTR()
* or a pointer to the newly allocated device.
*/
struct lcd_device *lcd_device_register(const char *name, void *devdata,
- struct lcd_properties *lp)
+ struct lcd_ops *ops)
{
int i, rc;
struct lcd_device *new_ld;
pr_debug("lcd_device_register: name=%s\n", name);
- new_ld = kmalloc(sizeof(struct lcd_device), GFP_KERNEL);
- if (unlikely(!new_ld))
+ new_ld = kzalloc(sizeof(struct lcd_device), GFP_KERNEL);
+ if (!new_ld)
return ERR_PTR(-ENOMEM);
- init_MUTEX(&new_ld->sem);
- new_ld->props = lp;
- memset(&new_ld->class_dev, 0, sizeof(new_ld->class_dev));
+ mutex_init(&new_ld->ops_lock);
+ mutex_init(&new_ld->update_lock);
+ new_ld->ops = ops;
new_ld->class_dev.class = &lcd_class;
strlcpy(new_ld->class_dev.class_id, name, KOBJ_NAME_LEN);
class_set_devdata(&new_ld->class_dev, devdata);
rc = class_device_register(&new_ld->class_dev);
- if (unlikely(rc)) {
-error: kfree(new_ld);
+ if (rc) {
+ kfree(new_ld);
return ERR_PTR(rc);
}
rc = lcd_register_fb(new_ld);
-
- if (unlikely(rc))
- goto error;
+ if (rc) {
+ class_device_unregister(&new_ld->class_dev);
+ return ERR_PTR(rc);
+ }
for (i = 0; i < ARRAY_SIZE(lcd_class_device_attributes); i++) {
rc = class_device_create_file(&new_ld->class_dev,
&lcd_class_device_attributes[i]);
- if (unlikely(rc)) {
+ if (rc) {
while (--i >= 0)
class_device_remove_file(&new_ld->class_dev,
&lcd_class_device_attributes[i]);
@@ -251,9 +246,9 @@ void lcd_device_unregister(struct lcd_device *ld)
class_device_remove_file(&ld->class_dev,
&lcd_class_device_attributes[i]);
- down(&ld->sem);
- ld->props = NULL;
- up(&ld->sem);
+ mutex_lock(&ld->ops_lock);
+ ld->ops = NULL;
+ mutex_unlock(&ld->ops_lock);
lcd_unregister_fb(ld);
class_device_unregister(&ld->class_dev);
}
diff --git a/drivers/video/backlight/locomolcd.c b/drivers/video/backlight/locomolcd.c
index fc812d96c31..d1312477813 100644
--- a/drivers/video/backlight/locomolcd.c
+++ b/drivers/video/backlight/locomolcd.c
@@ -112,11 +112,11 @@ static int current_intensity;
static int locomolcd_set_intensity(struct backlight_device *bd)
{
- int intensity = bd->props->brightness;
+ int intensity = bd->props.brightness;
- if (bd->props->power != FB_BLANK_UNBLANK)
+ if (bd->props.power != FB_BLANK_UNBLANK)
intensity = 0;
- if (bd->props->fb_blank != FB_BLANK_UNBLANK)
+ if (bd->props.fb_blank != FB_BLANK_UNBLANK)
intensity = 0;
if (locomolcd_flags & LOCOMOLCD_SUSPENDED)
intensity = 0;
@@ -141,11 +141,9 @@ static int locomolcd_get_intensity(struct backlight_device *bd)
return current_intensity;
}
-static struct backlight_properties locomobl_data = {
- .owner = THIS_MODULE,
+static struct backlight_ops locomobl_data = {
.get_brightness = locomolcd_get_intensity,
.update_status = locomolcd_set_intensity,
- .max_brightness = 4,
};
#ifdef CONFIG_PM
@@ -190,7 +188,8 @@ static int locomolcd_probe(struct locomo_dev *ldev)
return PTR_ERR (locomolcd_bl_device);
/* Set up frontlight so that screen is readable */
- locomobl_data.brightness = 2;
+ locomolcd_bl_device->props.max_brightness = 4,
+ locomolcd_bl_device->props.brightness = 2;
locomolcd_set_intensity(locomolcd_bl_device);
return 0;
diff --git a/drivers/video/backlight/progear_bl.c b/drivers/video/backlight/progear_bl.c
new file mode 100644
index 00000000000..70226935786
--- /dev/null
+++ b/drivers/video/backlight/progear_bl.c
@@ -0,0 +1,153 @@
+/*
+ * Backlight Driver for Frontpath ProGear HX1050+
+ *
+ * Copyright (c) 2006 Marcin Juszkiewicz
+ *
+ * Based on Progear LCD driver by M Schacht
+ * <mschacht at alumni dot washington dot edu>
+ *
+ * Based on Sharp's Corgi Backlight Driver
+ * Based on Backlight Driver for HP Jornada 680
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/fb.h>
+#include <linux/backlight.h>
+#include <linux/pci.h>
+#include <asm/uaccess.h>
+
+#define PMU_LPCR 0xB0
+#define SB_MPS1 0x61
+#define HW_LEVEL_MAX 0x77
+#define HW_LEVEL_MIN 0x4f
+
+static struct pci_dev *pmu_dev = NULL;
+static struct pci_dev *sb_dev = NULL;
+
+static int progearbl_set_intensity(struct backlight_device *bd)
+{
+ int intensity = bd->props.brightness;
+
+ if (bd->props.power != FB_BLANK_UNBLANK)
+ intensity = 0;
+ if (bd->props.fb_blank != FB_BLANK_UNBLANK)
+ intensity = 0;
+
+ pci_write_config_byte(pmu_dev, PMU_LPCR, intensity + HW_LEVEL_MIN);
+
+ return 0;
+}
+
+static int progearbl_get_intensity(struct backlight_device *bd)
+{
+ u8 intensity;
+ pci_read_config_byte(pmu_dev, PMU_LPCR, &intensity);
+
+ return intensity - HW_LEVEL_MIN;
+}
+
+static struct backlight_ops progearbl_ops = {
+ .get_brightness = progearbl_get_intensity,
+ .update_status = progearbl_set_intensity,
+};
+
+static int progearbl_probe(struct platform_device *pdev)
+{
+ u8 temp;
+ struct backlight_device *progear_backlight_device;
+
+ pmu_dev = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, 0);
+ if (!pmu_dev) {
+ printk("ALI M7101 PMU not found.\n");
+ return -ENODEV;
+ }
+
+ sb_dev = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, 0);
+ if (!sb_dev) {
+ printk("ALI 1533 SB not found.\n");
+ pci_dev_put(pmu_dev);
+ return -ENODEV;
+ }
+
+ /* Set SB_MPS1 to enable brightness control. */
+ pci_read_config_byte(sb_dev, SB_MPS1, &temp);
+ pci_write_config_byte(sb_dev, SB_MPS1, temp | 0x20);
+
+ progear_backlight_device = backlight_device_register("progear-bl",
+ &pdev->dev, NULL,
+ &progearbl_ops);
+ if (IS_ERR(progear_backlight_device))
+ return PTR_ERR(progear_backlight_device);
+
+ platform_set_drvdata(pdev, progear_backlight_device);
+
+ progear_backlight_device->props.power = FB_BLANK_UNBLANK;
+ progear_backlight_device->props.brightness = HW_LEVEL_MAX - HW_LEVEL_MIN;
+ progear_backlight_device->props.max_brightness = HW_LEVEL_MAX - HW_LEVEL_MIN;
+ progearbl_set_intensity(progear_backlight_device);
+
+ return 0;
+}
+
+static int progearbl_remove(struct platform_device *pdev)
+{
+ struct backlight_device *bd = platform_get_drvdata(pdev);
+ backlight_device_unregister(bd);
+
+ return 0;
+}
+
+static struct platform_driver progearbl_driver = {
+ .probe = progearbl_probe,
+ .remove = progearbl_remove,
+ .driver = {
+ .name = "progear-bl",
+ },
+};
+
+static struct platform_device *progearbl_device;
+
+static int __init progearbl_init(void)
+{
+ int ret = platform_driver_register(&progearbl_driver);
+
+ if (!ret) {
+ progearbl_device = platform_device_alloc("progear-bl", -1);
+ if (!progearbl_device)
+ return -ENOMEM;
+
+ ret = platform_device_add(progearbl_device);
+
+ if (ret) {
+ platform_device_put(progearbl_device);
+ platform_driver_unregister(&progearbl_driver);
+ }
+ }
+
+ return ret;
+}
+
+static void __exit progearbl_exit(void)
+{
+ pci_dev_put(pmu_dev);
+ pci_dev_put(sb_dev);
+
+ platform_device_unregister(progearbl_device);
+ platform_driver_unregister(&progearbl_driver);
+}
+
+module_init(progearbl_init);
+module_exit(progearbl_exit);
+
+MODULE_AUTHOR("Marcin Juszkiewicz <linux@hrw.one.pl>");
+MODULE_DESCRIPTION("ProGear Backlight Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/chipsfb.c b/drivers/video/chipsfb.c
index 73cb426bf2d..af313bf1a2d 100644
--- a/drivers/video/chipsfb.c
+++ b/drivers/video/chipsfb.c
@@ -145,26 +145,6 @@ static int chipsfb_set_par(struct fb_info *info)
static int chipsfb_blank(int blank, struct fb_info *info)
{
-#ifdef CONFIG_PMAC_BACKLIGHT
- mutex_lock(&pmac_backlight_mutex);
-
- if (pmac_backlight) {
- /* used to disable backlight only for blank > 1, but it seems
- * useful at blank = 1 too (saves battery, extends backlight
- * life)
- */
- down(&pmac_backlight->sem);
- if (blank)
- pmac_backlight->props->power = FB_BLANK_POWERDOWN;
- else
- pmac_backlight->props->power = FB_BLANK_UNBLANK;
- pmac_backlight->props->update_status(pmac_backlight);
- up(&pmac_backlight->sem);
- }
-
- mutex_unlock(&pmac_backlight_mutex);
-#endif /* CONFIG_PMAC_BACKLIGHT */
-
return 1; /* get fb_blank to set the colormap to all black */
}
@@ -415,10 +395,8 @@ chipsfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent)
/* turn on the backlight */
mutex_lock(&pmac_backlight_mutex);
if (pmac_backlight) {
- down(&pmac_backlight->sem);
- pmac_backlight->props->power = FB_BLANK_UNBLANK;
- pmac_backlight->props->update_status(pmac_backlight);
- up(&pmac_backlight->sem);
+ pmac_backlight->props.power = FB_BLANK_UNBLANK;
+ backlight_update_status(pmac_backlight);
}
mutex_unlock(&pmac_backlight_mutex);
#endif /* CONFIG_PMAC_BACKLIGHT */
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index 31f476a6479..0429fd2cece 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -60,7 +60,6 @@
#include <linux/module.h>
#include <linux/types.h>
-#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/delay.h> /* MSch: for IRQ probe */
@@ -2071,7 +2070,7 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width,
y_diff = info->var.yres - var.yres;
if (x_diff < 0 || x_diff > virt_fw ||
y_diff < 0 || y_diff > virt_fh) {
- struct fb_videomode *mode;
+ const struct fb_videomode *mode;
DPRINTK("attempting resize %ix%i\n", var.xres, var.yres);
mode = fb_find_best_mode(&var, &info->modelist);
@@ -2234,6 +2233,8 @@ static int fbcon_switch(struct vc_data *vc)
static void fbcon_generic_blank(struct vc_data *vc, struct fb_info *info,
int blank)
{
+ struct fb_event event;
+
if (blank) {
unsigned short charmask = vc->vc_hi_font_mask ?
0x1ff : 0xff;
@@ -2244,6 +2245,11 @@ static void fbcon_generic_blank(struct vc_data *vc, struct fb_info *info,
fbcon_clear(vc, 0, 0, vc->vc_rows, vc->vc_cols);
vc->vc_video_erase_char = oldc;
}
+
+
+ event.info = info;
+ event.data = &blank;
+ fb_notifier_call_chain(FB_EVENT_CONBLANK, &event);
}
static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch)
@@ -2975,7 +2981,7 @@ static void fbcon_new_modelist(struct fb_info *info)
int i;
struct vc_data *vc;
struct fb_var_screeninfo var;
- struct fb_videomode *mode;
+ const struct fb_videomode *mode;
for (i = first_fb_vc; i <= last_fb_vc; i++) {
if (registered_fb[con2fb_map[i]] != info)
diff --git a/drivers/video/console/fbcon.h b/drivers/video/console/fbcon.h
index b9386d168c0..71f24e00fcd 100644
--- a/drivers/video/console/fbcon.h
+++ b/drivers/video/console/fbcon.h
@@ -48,7 +48,7 @@ struct display {
struct fb_bitfield green;
struct fb_bitfield blue;
struct fb_bitfield transp;
- struct fb_videomode *mode;
+ const struct fb_videomode *mode;
};
struct fbcon_ops {
diff --git a/drivers/video/console/mdacon.c b/drivers/video/console/mdacon.c
index eb4d03fa539..124ecbe6f88 100644
--- a/drivers/video/console/mdacon.c
+++ b/drivers/video/console/mdacon.c
@@ -27,7 +27,6 @@
*/
#include <linux/types.h>
-#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/module.h>
diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c
index 4a9bde2c839..91a20785108 100644
--- a/drivers/video/console/vgacon.c
+++ b/drivers/video/console/vgacon.c
@@ -35,7 +35,6 @@
#include <linux/module.h>
#include <linux/types.h>
-#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/console.h>
diff --git a/drivers/video/controlfb.c b/drivers/video/controlfb.c
index 04c6d928189..fd60dba294d 100644
--- a/drivers/video/controlfb.c
+++ b/drivers/video/controlfb.c
@@ -696,11 +696,10 @@ static int __init control_of_init(struct device_node *dp)
printk(KERN_ERR "can't get 2 addresses for control\n");
return -ENXIO;
}
- p = kmalloc(sizeof(*p), GFP_KERNEL);
+ p = kzalloc(sizeof(*p), GFP_KERNEL);
if (p == 0)
return -ENXIO;
control_fb = p; /* save it for cleanups */
- memset(p, 0, sizeof(*p));
/* Map in frame buffer and registers */
p->fb_orig_base = fb_res.start;
diff --git a/drivers/video/cyber2000fb.c b/drivers/video/cyber2000fb.c
index aae6d9c26e8..7a6eeda5ae9 100644
--- a/drivers/video/cyber2000fb.c
+++ b/drivers/video/cyber2000fb.c
@@ -1539,16 +1539,21 @@ static int cyberpro_pci_enable_mmio(struct cfb_info *cfb)
/*
* Allow the CyberPro to accept PCI burst accesses
*/
- val = cyber2000_grphr(EXT_BUS_CTL, cfb);
- if (!(val & EXT_BUS_CTL_PCIBURST_WRITE)) {
- printk(KERN_INFO "%s: enabling PCI bursts\n", cfb->fb.fix.id);
+ if (cfb->id == ID_CYBERPRO_2010) {
+ printk(KERN_INFO "%s: NOT enabling PCI bursts\n", cfb->fb.fix.id);
+ } else {
+ val = cyber2000_grphr(EXT_BUS_CTL, cfb);
+ if (!(val & EXT_BUS_CTL_PCIBURST_WRITE)) {
+ printk(KERN_INFO "%s: enabling PCI bursts\n",
+ cfb->fb.fix.id);
- val |= EXT_BUS_CTL_PCIBURST_WRITE;
+ val |= EXT_BUS_CTL_PCIBURST_WRITE;
- if (cfb->id == ID_CYBERPRO_5000)
- val |= EXT_BUS_CTL_PCIBURST_READ;
+ if (cfb->id == ID_CYBERPRO_5000)
+ val |= EXT_BUS_CTL_PCIBURST_READ;
- cyber2000_grphw(EXT_BUS_CTL, val, cfb);
+ cyber2000_grphw(EXT_BUS_CTL, val, cfb);
+ }
}
return 0;
diff --git a/drivers/video/cyberfb.c b/drivers/video/cyberfb.c
deleted file mode 100644
index 0b8d5b12115..00000000000
--- a/drivers/video/cyberfb.c
+++ /dev/null
@@ -1,2295 +0,0 @@
-/*
-* linux/drivers/video/cyberfb.c -- CyberVision64 frame buffer device
-* $Id: cyberfb.c,v 1.6 1998/09/11 04:54:58 abair Exp $
-*
-* Copyright (C) 1998 Alan Bair
-*
-* This file is based on two CyberVision64 frame buffer device drivers
-*
-* The second CyberVision64 frame buffer device (cvision.c cvision_core.c):
-*
-* Copyright (c) 1997 Antonio Santos
-*
-* Released as a patch to 2.1.35, but never included in the source tree.
-* This is based on work from the NetBSD CyberVision64 frame buffer driver
-* and support files (grf_cv.c, grf_cvreg.h, ite_cv.c):
-* Permission to use the source of this driver was obtained from the
-* author Michael Teske by Alan Bair.
-*
-* Copyright (c) 1995 Michael Teske
-*
-* The first CyberVision64 frame buffer device (cyberfb.c):
-*
-* Copyright (C) 1996 Martin Apel
-* Geert Uytterhoeven
-*
-* Which is based on the Amiga frame buffer device (amifb.c):
-*
-* Copyright (C) 1995 Geert Uytterhoeven
-*
-*
-* History:
-* - 22 Dec 95: Original version by Martin Apel
-* - 05 Jan 96: Geert: integration into the current source tree
-* - 01 Aug 98: Alan: Merge in code from cvision.c and cvision_core.c
-* $Log: cyberfb.c,v $
-* Revision 1.6 1998/09/11 04:54:58 abair
-* Update for 2.1.120 change in include file location.
-* Clean up for public release.
-*
-* Revision 1.5 1998/09/03 04:27:13 abair
-* Move cv64_load_video_mode to cyber_set_video so a new video mode is install
-* with each change of the 'var' data.
-*
-* Revision 1.4 1998/09/01 00:31:17 abair
-* Put in a set of default 8,16,24 bpp modes and map cyber8,16 to them.
-* Update operations with 'par' to handle a more complete set of parameter
-* values for encode/decode process.
-*
-* Revision 1.3 1998/08/31 21:31:33 abair
-* Swap 800x490 for 640x480 video mode and more cleanup.
-* Abandon idea to resurrect "custom" mode setting via kernel opts,
-* instead work on making use of fbset program to do this.
-*
-* Revision 1.2 1998/08/31 06:17:08 abair
-* Make updates for changes in cyberfb.c released in 2.1.119
-* and do some cleanup of the code.
-*
-* Revision 1.1 1998/08/29 18:38:31 abair
-* Initial revision
-*
-* Revision 1.3 1998/08/17 06:21:53 abair
-* Remove more redundant code after merging in cvision_core.c
-* Set blanking by colormap to pale red to detect this vs trying to
-* use video blanking. More formating to Linux code style.
-*
-* Revision 1.2 1998/08/15 17:51:37 abair
-* Added cvision_core.c code from 2.1.35 patches.
-* Changed to compile correctly and switch to using initialization
-* code. Added debugging and dropping of duplicate code.
-*
-*
-*
-* 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.
-*/
-
-
-#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/zorro.h>
-#include <linux/fb.h>
-#include <linux/init.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <asm/irq.h>
-#include <asm/pgtable.h>
-#include <asm/amigahw.h>
-#include <asm/io.h>
-
-#include "cyberfb.h"
-#include <video/fbcon.h>
-#include <video/fbcon-cfb8.h>
-#include <video/fbcon-cfb16.h>
-
-/*#define CYBERFBDEBUG*/
-#ifdef CYBERFBDEBUG
-#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
-static void cv64_dump(void);
-#else
-#define DPRINTK(fmt, args...)
-#endif
-
-#define wb_64(regs,reg,dat) (*(((volatile unsigned char *)regs) + reg) = dat)
-#define rb_64(regs, reg) (*(((volatile unsigned char *)regs) + reg))
-
-struct cyberfb_par {
- struct fb_var_screeninfo var;
- __u32 type;
- __u32 type_aux;
- __u32 visual;
- __u32 line_length;
-};
-
-static struct cyberfb_par current_par;
-
-static int current_par_valid = 0;
-
-static struct display disp;
-static struct fb_info fb_info;
-
-
-/*
- * Frame Buffer Name
- */
-
-static char cyberfb_name[16] = "Cybervision";
-
-
-/*
- * CyberVision Graphics Board
- */
-
-static unsigned char Cyber_colour_table [256][3];
-static unsigned long CyberSize;
-static volatile unsigned char *CyberBase;
-static volatile unsigned char *CyberMem;
-static volatile unsigned char *CyberRegs;
-static unsigned long CyberMem_phys;
-static unsigned long CyberRegs_phys;
-
-/*
- * Predefined Video Modes
- */
-
-static struct {
- const char *name;
- struct fb_var_screeninfo var;
-} cyberfb_predefined[] __initdata = {
- { "640x480-8", { /* Default 8 BPP mode (cyber8) */
- 640, 480, 640, 480, 0, 0, 8, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 39722, 40, 24, 32, 11, 96, 2,
- FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
- FB_VMODE_NONINTERLACED
- }},
- { "640x480-16", { /* Default 16 BPP mode (cyber16) */
- 640, 480, 640, 480, 0, 0, 16, 0,
- {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 39722, 40, 24, 32, 11, 96, 2,
- FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
- FB_VMODE_NONINTERLACED
- }},
- { "640x480-24", { /* Default 24 BPP mode */
- 640, 480, 640, 480, 0, 0, 24, 0,
- {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 39722, 40, 24, 32, 11, 96, 2,
- FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
- FB_VMODE_NONINTERLACED
- }},
- { "800x490-8", { /* Cybervision 8 bpp */
- /* NO Acceleration */
- 800, 490, 800, 490, 0, 0, 8, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_NONE, 33333, 80, 24, 23, 1, 56, 8,
- FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
- FB_VMODE_NONINTERLACED
- }},
-/* I can't test these with my monitor, but I suspect they will
- * be OK, since Antonio Santos indicated he had tested them in
- * his system.
- */
- { "800x600-8", { /* Cybervision 8 bpp */
- 800, 600, 800, 600, 0, 0, 8, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 27778, 64, 24, 22, 1, 72, 2,
- FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
- FB_VMODE_NONINTERLACED
- }},
- { "1024x768-8", { /* Cybervision 8 bpp */
- 1024, 768, 1024, 768, 0, 0, 8, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 16667, 224, 72, 60, 12, 168, 4,
- FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
- FB_VMODE_NONINTERLACED
- }},
- { "1152x886-8", { /* Cybervision 8 bpp */
- 1152, 886, 1152, 886, 0, 0, 8, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 15873, 184, 40, 24, 1, 56, 16,
- FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
- FB_VMODE_NONINTERLACED
- }},
- { "1280x1024-8", { /* Cybervision 8 bpp */
- 1280, 1024, 1280, 1024, 0, 0, 8, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 16667, 256, 48, 50, 12, 72, 4,
- FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
- FB_VMODE_INTERLACED
- }}
-};
-
-#define NUM_TOTAL_MODES ARRAY_SIZE(cyberfb_predefined)
-
-static int Cyberfb_inverse = 0;
-
-/*
- * Some default modes
- */
-
-#define CYBER8_DEFMODE (0)
-#define CYBER16_DEFMODE (1)
-
-static struct fb_var_screeninfo cyberfb_default;
-static int cyberfb_usermode __initdata = 0;
-
-/*
- * Interface used by the world
- */
-
-int cyberfb_setup(char *options);
-
-static int cyberfb_get_fix(struct fb_fix_screeninfo *fix, int con,
- struct fb_info *info);
-static int cyberfb_get_var(struct fb_var_screeninfo *var, int con,
- struct fb_info *info);
-static int cyberfb_set_var(struct fb_var_screeninfo *var, int con,
- struct fb_info *info);
-static int cyberfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
- struct fb_info *info);
-static int cyberfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
- u_int transp, struct fb_info *info);
-static int cyberfb_blank(int blank, struct fb_info *info);
-
-/*
- * Interface to the low level console driver
- */
-
-int cyberfb_init(void);
-static int Cyberfb_switch(int con, struct fb_info *info);
-static int Cyberfb_updatevar(int con, struct fb_info *info);
-
-/*
- * Text console acceleration
- */
-
-#ifdef FBCON_HAS_CFB8
-static struct display_switch fbcon_cyber8;
-#endif
-
-/*
- * Accelerated Functions used by the low level console driver
- */
-
-static void Cyber_WaitQueue(u_short fifo);
-static void Cyber_WaitBlit(void);
-static void Cyber_BitBLT(u_short curx, u_short cury, u_short destx,
- u_short desty, u_short width, u_short height,
- u_short mode);
-static void Cyber_RectFill(u_short x, u_short y, u_short width, u_short height,
- u_short mode, u_short color);
-#if 0
-static void Cyber_MoveCursor(u_short x, u_short y);
-#endif
-
-/*
- * Hardware Specific Routines
- */
-
-static int Cyber_init(void);
-static int Cyber_encode_fix(struct fb_fix_screeninfo *fix,
- struct cyberfb_par *par);
-static int Cyber_decode_var(struct fb_var_screeninfo *var,
- struct cyberfb_par *par);
-static int Cyber_encode_var(struct fb_var_screeninfo *var,
- struct cyberfb_par *par);
-static int Cyber_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
- u_int *transp, struct fb_info *info);
-
-/*
- * Internal routines
- */
-
-static void cyberfb_get_par(struct cyberfb_par *par);
-static void cyberfb_set_par(struct cyberfb_par *par);
-static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive);
-static void cyberfb_set_disp(int con, struct fb_info *info);
-static int get_video_mode(const char *name);
-
-/* For cvision_core.c */
-static unsigned short cv64_compute_clock(unsigned long);
-static int cv_has_4mb (volatile unsigned char *);
-static void cv64_board_init (void);
-static void cv64_load_video_mode (struct fb_var_screeninfo *);
-
-
-/* -------------------- Hardware specific routines ------------------------- */
-
-
-/*
- * Initialization
- *
- * Set the default video mode for this chipset. If a video mode was
- * specified on the command line, it will override the default mode.
- */
-
-static int Cyber_init(void)
-{
- volatile unsigned char *regs = CyberRegs;
- volatile unsigned long *CursorBase;
- int i;
- DPRINTK("ENTER\n");
-
-/* Init local cmap as greyscale levels */
- for (i = 0; i < 256; i++) {
- Cyber_colour_table [i][0] = i;
- Cyber_colour_table [i][1] = i;
- Cyber_colour_table [i][2] = i;
- }
-
-/* Initialize the board and determine fbmem size */
- cv64_board_init();
-#ifdef CYBERFBDEBUG
- DPRINTK("Register state after initing board\n");
- cv64_dump();
-#endif
-/* Clear framebuffer memory */
- DPRINTK("Clear framebuffer memory\n");
- memset ((char *)CyberMem, 0, CyberSize);
-
-/* Disable hardware cursor */
- DPRINTK("Disable HW cursor\n");
- wb_64(regs, S3_CRTC_ADR, S3_REG_LOCK2);
- wb_64(regs, S3_CRTC_DATA, 0xa0);
- wb_64(regs, S3_CRTC_ADR, S3_HGC_MODE);
- wb_64(regs, S3_CRTC_DATA, 0x00);
- wb_64(regs, S3_CRTC_ADR, S3_HWGC_DX);
- wb_64(regs, S3_CRTC_DATA, 0x00);
- wb_64(regs, S3_CRTC_ADR, S3_HWGC_DY);
- wb_64(regs, S3_CRTC_DATA, 0x00);
-
-/* Initialize hardware cursor */
- DPRINTK("Init HW cursor\n");
- CursorBase = (u_long *)((char *)(CyberMem) + CyberSize - 0x400);
- for (i=0; i < 8; i++)
- {
- *(CursorBase +(i*4)) = 0xffffff00;
- *(CursorBase+1+(i*4)) = 0xffff0000;
- *(CursorBase+2+(i*4)) = 0xffff0000;
- *(CursorBase+3+(i*4)) = 0xffff0000;
- }
- for (i=8; i < 64; i++)
- {
- *(CursorBase +(i*4)) = 0xffff0000;
- *(CursorBase+1+(i*4)) = 0xffff0000;
- *(CursorBase+2+(i*4)) = 0xffff0000;
- *(CursorBase+3+(i*4)) = 0xffff0000;
- }
-
- cyberfb_setcolreg (255, 56<<8, 100<<8, 160<<8, 0, NULL /* unused */);
- cyberfb_setcolreg (254, 0, 0, 0, 0, NULL /* unused */);
-
- DPRINTK("EXIT\n");
- return 0;
-}
-
-
-/*
- * This function should fill in the `fix' structure based on the
- * values in the `par' structure.
- */
-
-static int Cyber_encode_fix(struct fb_fix_screeninfo *fix,
- struct cyberfb_par *par)
-{
- DPRINTK("ENTER\n");
- memset(fix, 0, sizeof(struct fb_fix_screeninfo));
- strcpy(fix->id, cyberfb_name);
- fix->smem_start = CyberMem_phys;
- fix->smem_len = CyberSize;
- fix->mmio_start = CyberRegs_phys;
- fix->mmio_len = 0x10000;
-
- fix->type = FB_TYPE_PACKED_PIXELS;
- fix->type_aux = 0;
- if (par->var.bits_per_pixel == 15 || par->var.bits_per_pixel == 16 ||
- par->var.bits_per_pixel == 24 || par->var.bits_per_pixel == 32) {
- fix->visual = FB_VISUAL_DIRECTCOLOR;
- } else {
- fix->visual = FB_VISUAL_PSEUDOCOLOR;
- }
-
- fix->xpanstep = 0;
- fix->ypanstep = 0;
- fix->ywrapstep = 0;
- fix->line_length = 0;
- fix->accel = FB_ACCEL_S3_TRIO64;
-
- DPRINTK("EXIT\n");
- return(0);
-}
-
-
-/*
-* Fill the `par' structure based on the values in `var'.
-* TODO: Verify and adjust values, return -EINVAL if bad.
-*/
-
-static int Cyber_decode_var(struct fb_var_screeninfo *var,
- struct cyberfb_par *par)
-{
- DPRINTK("ENTER\n");
- par->var.xres = var->xres;
- par->var.yres = var->yres;
- par->var.xres_virtual = var->xres_virtual;
- par->var.yres_virtual = var->yres_virtual;
- par->var.xoffset = var->xoffset;
- par->var.yoffset = var->yoffset;
- par->var.bits_per_pixel = var->bits_per_pixel;
- par->var.grayscale = var->grayscale;
- par->var.red = var->red;
- par->var.green = var->green;
- par->var.blue = var->blue;
- par->var.transp = var->transp;
- par->var.nonstd = var->nonstd;
- par->var.activate = var->activate;
- par->var.height = var->height;
- par->var.width = var->width;
- if (var->accel_flags & FB_ACCELF_TEXT) {
- par->var.accel_flags = FB_ACCELF_TEXT;
- } else {
- par->var.accel_flags = 0;
- }
- par->var.pixclock = var->pixclock;
- par->var.left_margin = var->left_margin;
- par->var.right_margin = var->right_margin;
- par->var.upper_margin = var->upper_margin;
- par->var.lower_margin = var->lower_margin;
- par->var.hsync_len = var->hsync_len;
- par->var.vsync_len = var->vsync_len;
- par->var.sync = var->sync;
- par->var.vmode = var->vmode;
- DPRINTK("EXIT\n");
- return(0);
-}
-
-/*
-* Fill the `var' structure based on the values in `par' and maybe
-* other values read out of the hardware.
-*/
-
-static int Cyber_encode_var(struct fb_var_screeninfo *var,
- struct cyberfb_par *par)
-{
- DPRINTK("ENTER\n");
- var->xres = par->var.xres;
- var->yres = par->var.yres;
- var->xres_virtual = par->var.xres_virtual;
- var->yres_virtual = par->var.yres_virtual;
- var->xoffset = par->var.xoffset;
- var->yoffset = par->var.yoffset;
-
- var->bits_per_pixel = par->var.bits_per_pixel;
- var->grayscale = par->var.grayscale;
-
- var->red = par->var.red;
- var->green = par->var.green;
- var->blue = par->var.blue;
- var->transp = par->var.transp;
-
- var->nonstd = par->var.nonstd;
- var->activate = par->var.activate;
-
- var->height = par->var.height;
- var->width = par->var.width;
-
- var->accel_flags = par->var.accel_flags;
-
- var->pixclock = par->var.pixclock;
- var->left_margin = par->var.left_margin;
- var->right_margin = par->var.right_margin;
- var->upper_margin = par->var.upper_margin;
- var->lower_margin = par->var.lower_margin;
- var->hsync_len = par->var.hsync_len;
- var->vsync_len = par->var.vsync_len;
- var->sync = par->var.sync;
- var->vmode = par->var.vmode;
-
- DPRINTK("EXIT\n");
- return(0);
-}
-
-
-/*
- * Set a single color register. Return != 0 for invalid regno.
- */
-
-static int cyberfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
- u_int transp, struct fb_info *info)
-{
- volatile unsigned char *regs = CyberRegs;
-
- /*DPRINTK("ENTER\n");*/
- if (regno > 255) {
- DPRINTK("EXIT - Register # > 255\n");
- return (1);
- }
-
- wb_64(regs, 0x3c8, (unsigned char) regno);
-
- red >>= 10;
- green >>= 10;
- blue >>= 10;
-
- Cyber_colour_table [regno][0] = red;
- Cyber_colour_table [regno][1] = green;
- Cyber_colour_table [regno][2] = blue;
-
- wb_64(regs, 0x3c9, red);
- wb_64(regs, 0x3c9, green);
- wb_64(regs, 0x3c9, blue);
-
- /*DPRINTK("EXIT\n");*/
- return (0);
-}
-
-
-/*
-* Read a single color register and split it into
-* colors/transparent. Return != 0 for invalid regno.
-*/
-
-static int Cyber_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
- u_int *transp, struct fb_info *info)
-{
- int t;
-
- /*DPRINTK("ENTER\n");*/
- if (regno > 255) {
- DPRINTK("EXIT - Register # > 255\n");
- return (1);
- }
- /* ARB This shifting & oring seems VERY strange */
- t = Cyber_colour_table [regno][0];
- *red = (t<<10) | (t<<4) | (t>>2);
- t = Cyber_colour_table [regno][1];
- *green = (t<<10) | (t<<4) | (t>>2);
- t = Cyber_colour_table [regno][2];
- *blue = (t<<10) | (t<<4) | (t>>2);
- *transp = 0;
- /*DPRINTK("EXIT\n");*/
- return (0);
-}
-
-
-/*
-* (Un)Blank the screen
-* blank: 1 = zero fb cmap
-* 0 = restore fb cmap from local cmap
-*/
-static int cyberfb_blank(int blank, struct fb_info *info)
-{
- volatile unsigned char *regs = CyberRegs;
- int i;
-
- DPRINTK("ENTER\n");
-#if 0
-/* Blank by turning gfx off */
- gfx_on_off (1, regs);
-#else
- if (blank) {
- for (i = 0; i < 256; i++) {
- wb_64(regs, 0x3c8, (unsigned char) i);
- /* ARB Pale red to detect this blanking method */
- wb_64(regs, 0x3c9, 48);
- wb_64(regs, 0x3c9, 0);
- wb_64(regs, 0x3c9, 0);
- }
- } else {
- for (i = 0; i < 256; i++) {
- wb_64(regs, 0x3c8, (unsigned char) i);
- wb_64(regs, 0x3c9, Cyber_colour_table[i][0]);
- wb_64(regs, 0x3c9, Cyber_colour_table[i][1]);
- wb_64(regs, 0x3c9, Cyber_colour_table[i][2]);
- }
- }
-#endif
- DPRINTK("EXIT\n");
- return 0;
-}
-
-
-/**************************************************************
- * We are waiting for "fifo" FIFO-slots empty
- */
-static void Cyber_WaitQueue (u_short fifo)
-{
- unsigned short status;
-
- DPRINTK("ENTER\n");
- do {
- status = *((u_short volatile *)(CyberRegs + S3_GP_STAT));
- } while (status & fifo);
- DPRINTK("EXIT\n");
-}
-
-/**************************************************************
- * We are waiting for Hardware (Graphics Engine) not busy
- */
-static void Cyber_WaitBlit (void)
-{
- unsigned short status;
-
- DPRINTK("ENTER\n");
- do {
- status = *((u_short volatile *)(CyberRegs + S3_GP_STAT));
- } while (status & S3_HDW_BUSY);
- DPRINTK("EXIT\n");
-}
-
-/**************************************************************
- * BitBLT - Through the Plane
- */
-static void Cyber_BitBLT (u_short curx, u_short cury, u_short destx,
- u_short desty, u_short width, u_short height,
- u_short mode)
-{
- volatile unsigned char *regs = CyberRegs;
- u_short blitcmd = S3_BITBLT;
-
- DPRINTK("ENTER\n");
- /* Set drawing direction */
- /* -Y, X maj, -X (default) */
- if (curx > destx) {
- blitcmd |= 0x0020; /* Drawing direction +X */
- } else {
- curx += (width - 1);
- destx += (width - 1);
- }
-
- if (cury > desty) {
- blitcmd |= 0x0080; /* Drawing direction +Y */
- } else {
- cury += (height - 1);
- desty += (height - 1);
- }
-
- Cyber_WaitQueue (0x8000);
-
- *((u_short volatile *)(regs + S3_PIXEL_CNTL)) = 0xa000;
- *((u_short volatile *)(regs + S3_FRGD_MIX)) = (0x0060 | mode);
-
- *((u_short volatile *)(regs + S3_CUR_X)) = curx;
- *((u_short volatile *)(regs + S3_CUR_Y)) = cury;
-
- *((u_short volatile *)(regs + S3_DESTX_DIASTP)) = destx;
- *((u_short volatile *)(regs + S3_DESTY_AXSTP)) = desty;
-
- *((u_short volatile *)(regs + S3_MIN_AXIS_PCNT)) = height - 1;
- *((u_short volatile *)(regs + S3_MAJ_AXIS_PCNT)) = width - 1;
-
- *((u_short volatile *)(regs + S3_CMD)) = blitcmd;
- DPRINTK("EXIT\n");
-}
-
-/**************************************************************
- * Rectangle Fill Solid
- */
-static void Cyber_RectFill (u_short x, u_short y, u_short width,
- u_short height, u_short mode, u_short color)
-{
- volatile unsigned char *regs = CyberRegs;
- u_short blitcmd = S3_FILLEDRECT;
-
- DPRINTK("ENTER\n");
- Cyber_WaitQueue (0x8000);
-
- *((u_short volatile *)(regs + S3_PIXEL_CNTL)) = 0xa000;
- *((u_short volatile *)(regs + S3_FRGD_MIX)) = (0x0020 | mode);
-
- *((u_short volatile *)(regs + S3_MULT_MISC)) = 0xe000;
- *((u_short volatile *)(regs + S3_FRGD_COLOR)) = color;
-
- *((u_short volatile *)(regs + S3_CUR_X)) = x;
- *((u_short volatile *)(regs + S3_CUR_Y)) = y;
-
- *((u_short volatile *)(regs + S3_MIN_AXIS_PCNT)) = height - 1;
- *((u_short volatile *)(regs + S3_MAJ_AXIS_PCNT)) = width - 1;
-
- *((u_short volatile *)(regs + S3_CMD)) = blitcmd;
- DPRINTK("EXIT\n");
-}
-
-
-#if 0
-/**************************************************************
- * Move cursor to x, y
- */
-static void Cyber_MoveCursor (u_short x, u_short y)
-{
- volatile unsigned char *regs = CyberRegs;
- DPRINTK("ENTER\n");
- *(regs + S3_CRTC_ADR) = 0x39;
- *(regs + S3_CRTC_DATA) = 0xa0;
-
- *(regs + S3_CRTC_ADR) = S3_HWGC_ORGX_H;
- *(regs + S3_CRTC_DATA) = (char)((x & 0x0700) >> 8);
- *(regs + S3_CRTC_ADR) = S3_HWGC_ORGX_L;
- *(regs + S3_CRTC_DATA) = (char)(x & 0x00ff);
-
- *(regs + S3_CRTC_ADR) = S3_HWGC_ORGY_H;
- *(regs + S3_CRTC_DATA) = (char)((y & 0x0700) >> 8);
- *(regs + S3_CRTC_ADR) = S3_HWGC_ORGY_L;
- *(regs + S3_CRTC_DATA) = (char)(y & 0x00ff);
- DPRINTK("EXIT\n");
-}
-#endif
-
-
-/* -------------------- Generic routines ---------------------------------- */
-
-
-/*
- * Fill the hardware's `par' structure.
- */
-
-static void cyberfb_get_par(struct cyberfb_par *par)
-{
- DPRINTK("ENTER\n");
- if (current_par_valid) {
- *par = current_par;
- } else {
- Cyber_decode_var(&cyberfb_default, par);
- }
- DPRINTK("EXIT\n");
-}
-
-
-static void cyberfb_set_par(struct cyberfb_par *par)
-{
- DPRINTK("ENTER\n");
- current_par = *par;
- current_par_valid = 1;
- DPRINTK("EXIT\n");
-}
-
-
-static void cyber_set_video(struct fb_var_screeninfo *var)
-{
-
- /* Load the video mode defined by the 'var' data */
- cv64_load_video_mode (var);
-#ifdef CYBERFBDEBUG
- DPRINTK("Register state after loading video mode\n");
- cv64_dump();
-#endif
-}
-
-
-static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive)
-{
- int err, activate;
- struct cyberfb_par par;
-
- DPRINTK("ENTER\n");
- if ((err = Cyber_decode_var(var, &par))) {
- DPRINTK("EXIT - decode_var failed\n");
- return(err);
- }
- activate = var->activate;
- if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW && isactive)
- cyberfb_set_par(&par);
- Cyber_encode_var(var, &par);
- var->activate = activate;
-
- cyber_set_video(var);
- DPRINTK("EXIT\n");
- return 0;
-}
-
-/*
- * Get the Fixed Part of the Display
- */
-
-static int cyberfb_get_fix(struct fb_fix_screeninfo *fix, int con,
- struct fb_info *info)
-{
- struct cyberfb_par par;
- int error = 0;
-
- DPRINTK("ENTER\n");
- if (con == -1) {
- cyberfb_get_par(&par);
- } else {
- error = Cyber_decode_var(&fb_display[con].var, &par);
- }
- DPRINTK("EXIT\n");
- return(error ? error : Cyber_encode_fix(fix, &par));
-}
-
-
-/*
- * Get the User Defined Part of the Display
- */
-
-static int cyberfb_get_var(struct fb_var_screeninfo *var, int con,
- struct fb_info *info)
-{
- struct cyberfb_par par;
- int error = 0;
-
- DPRINTK("ENTER\n");
- if (con == -1) {
- cyberfb_get_par(&par);
- error = Cyber_encode_var(var, &par);
- disp.var = *var; /* ++Andre: don't know if this is the right place */
- } else {
- *var = fb_display[con].var;
- }
-
- DPRINTK("EXIT\n");
- return(error);
-}
-
-
-static void cyberfb_set_disp(int con, struct fb_info *info)
-{
- struct fb_fix_screeninfo fix;
- struct display *display;
-
- DPRINTK("ENTER\n");
- if (con >= 0)
- display = &fb_display[con];
- else
- display = &disp; /* used during initialization */
-
- cyberfb_get_fix(&fix, con, info);
- if (con == -1)
- con = 0;
- display->visual = fix.visual;
- display->type = fix.type;
- display->type_aux = fix.type_aux;
- display->ypanstep = fix.ypanstep;
- display->ywrapstep = fix.ywrapstep;
- display->can_soft_blank = 1;
- display->inverse = Cyberfb_inverse;
- switch (display->var.bits_per_pixel) {
-#ifdef FBCON_HAS_CFB8
- case 8:
- if (display->var.accel_flags & FB_ACCELF_TEXT) {
- display->dispsw = &fbcon_cyber8;
-#warning FIXME: We should reinit the graphics engine here
- } else
- display->dispsw = &fbcon_cfb8;
- break;
-#endif
-#ifdef FBCON_HAS_CFB16
- case 16:
- display->dispsw = &fbcon_cfb16;
- break;
-#endif
- default:
- display->dispsw = NULL;
- break;
- }
- DPRINTK("EXIT\n");
-}
-
-
-/*
- * Set the User Defined Part of the Display
- */
-
-static int cyberfb_set_var(struct fb_var_screeninfo *var, int con,
- struct fb_info *info)
-{
- int err, oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldaccel;
-
- DPRINTK("ENTER\n");
- if ((err = do_fb_set_var(var, con == info->currcon))) {
- DPRINTK("EXIT - do_fb_set_var failed\n");
- return(err);
- }
- if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
- oldxres = fb_display[con].var.xres;
- oldyres = fb_display[con].var.yres;
- oldvxres = fb_display[con].var.xres_virtual;
- oldvyres = fb_display[con].var.yres_virtual;
- oldbpp = fb_display[con].var.bits_per_pixel;
- oldaccel = fb_display[con].var.accel_flags;
- fb_display[con].var = *var;
- if (oldxres != var->xres || oldyres != var->yres ||
- oldvxres != var->xres_virtual ||
- oldvyres != var->yres_virtual ||
- oldbpp != var->bits_per_pixel ||
- oldaccel != var->accel_flags) {
- cyberfb_set_disp(con, info);
- (*fb_info.changevar)(con);
- fb_alloc_cmap(&fb_display[con].cmap, 0, 0);
- do_install_cmap(con, info);
- }
- }
- var->activate = 0;
- DPRINTK("EXIT\n");
- return(0);
-}
-
-
-/*
- * Get the Colormap
- */
-
-static int cyberfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
- struct fb_info *info)
-{
- DPRINTK("ENTER\n");
- if (con == info->currcon) { /* current console? */
- DPRINTK("EXIT - console is current console\n");
- return(fb_get_cmap(cmap, kspc, Cyber_getcolreg, info));
- } else if (fb_display[con].cmap.len) { /* non default colormap? */
- DPRINTK("Use console cmap\n");
- fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
- } else {
- DPRINTK("Use default cmap\n");
- fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
- cmap, kspc ? 0 : 2);
- }
- DPRINTK("EXIT\n");
- return(0);
-}
-
-static struct fb_ops cyberfb_ops = {
- .owner = THIS_MODULE,
- .fb_get_fix = cyberfb_get_fix,
- .fb_get_var = cyberfb_get_var,
- .fb_set_var = cyberfb_set_var,
- .fb_get_cmap = cyberfb_get_cmap,
- .fb_set_cmap = gen_set_cmap,
- .fb_setcolreg = cyberfb_setcolreg,
- .fb_blank = cyberfb_blank,
-};
-
-int __init cyberfb_setup(char *options)
-{
- char *this_opt;
- DPRINTK("ENTER\n");
-
- fb_info.fontname[0] = '\0';
-
- if (!options || !*options) {
- DPRINTK("EXIT - no options\n");
- return 0;
- }
-
- while ((this_opt = strsep(&options, ",")) != NULL) {
- if (!*this_opt)
- continue;
- if (!strcmp(this_opt, "inverse")) {
- Cyberfb_inverse = 1;
- fb_invert_cmaps();
- } else if (!strncmp(this_opt, "font:", 5)) {
- strcpy(fb_info.fontname, this_opt+5);
- } else if (!strcmp (this_opt, "cyber8")) {
- cyberfb_default = cyberfb_predefined[CYBER8_DEFMODE].var;
- cyberfb_usermode = 1;
- } else if (!strcmp (this_opt, "cyber16")) {
- cyberfb_default = cyberfb_predefined[CYBER16_DEFMODE].var;
- cyberfb_usermode = 1;
- } else get_video_mode(this_opt);
- }
-
- DPRINTK("default mode: xres=%d, yres=%d, bpp=%d\n",
- cyberfb_default.xres,
- cyberfb_default.yres,
- cyberfb_default.bits_per_pixel);
- DPRINTK("EXIT\n");
- return 0;
-}
-
-/*
- * Initialization
- */
-
-int __init cyberfb_init(void)
-{
- unsigned long board_addr, board_size;
- struct cyberfb_par par;
- struct zorro_dev *z = NULL;
- DPRINTK("ENTER\n");
-
- while ((z = zorro_find_device(ZORRO_PROD_PHASE5_CYBERVISION64, z))) {
- board_addr = z->resource.start;
- board_size = z->resource.end-z->resource.start+1;
- CyberMem_phys = board_addr + 0x01400000;
- CyberRegs_phys = CyberMem_phys + 0x00c00000;
- if (!request_mem_region(CyberRegs_phys, 0x10000, "S3 Trio64"))
- continue;
- if (!request_mem_region(CyberMem_phys, 0x400000, "RAM")) {
- release_mem_region(CyberRegs_phys, 0x10000);
- continue;
- }
- DPRINTK("board_addr=%08lx\n", board_addr);
- DPRINTK("board_size=%08lx\n", board_size);
-
- CyberBase = ioremap(board_addr, board_size);
- CyberRegs = CyberBase + 0x02000000;
- CyberMem = CyberBase + 0x01400000;
- DPRINTK("CyberBase=%08lx CyberRegs=%08lx CyberMem=%08lx\n",
- CyberBase, (long unsigned int)CyberRegs, CyberMem);
-
-#ifdef CYBERFBDEBUG
- DPRINTK("Register state just after mapping memory\n");
- cv64_dump();
-#endif
-
- strcpy(fb_info.modename, cyberfb_name);
- fb_info.changevar = NULL;
- fb_info.fbops = &cyberfb_ops;
- fb_info.screen_base = (unsigned char *)CyberMem;
- fb_info.disp = &disp;
- fb_info.currcon = -1;
- fb_info.switch_con = &Cyberfb_switch;
- fb_info.updatevar = &Cyberfb_updatevar;
-
- Cyber_init();
- /* ++Andre: set cyberfb default mode */
- if (!cyberfb_usermode) {
- cyberfb_default = cyberfb_predefined[CYBER8_DEFMODE].var;
- DPRINTK("Use default cyber8 mode\n");
- }
- Cyber_decode_var(&cyberfb_default, &par);
- Cyber_encode_var(&cyberfb_default, &par);
-
- do_fb_set_var(&cyberfb_default, 1);
- cyberfb_get_var(&fb_display[0].var, -1, &fb_info);
- cyberfb_set_disp(-1, &fb_info);
- do_install_cmap(0, &fb_info);
-
- if (register_framebuffer(&fb_info) < 0) {
- DPRINTK("EXIT - register_framebuffer failed\n");
- if (CyberBase)
- iounmap(CyberBase);
- release_mem_region(CyberMem_phys, 0x400000);
- release_mem_region(CyberRegs_phys, 0x10000);
- return -EINVAL;
- }
-
- printk("fb%d: %s frame buffer device, using %ldK of video memory\n",
- fb_info.node, fb_info.modename, CyberSize>>10);
-
- /* TODO: This driver cannot be unloaded yet */
- DPRINTK("EXIT\n");
- return 0;
- }
- return -ENXIO;
-}
-
-
-static int Cyberfb_switch(int con, struct fb_info *info)
-{
- DPRINTK("ENTER\n");
- /* Do we have to save the colormap? */
- if (fb_display[info->currcon].cmap.len) {
- fb_get_cmap(&fb_display[info->currcon].cmap, 1, Cyber_getcolreg,
- info);
- }
-
- do_fb_set_var(&fb_display[con].var, 1);
- info->currcon = con;
- /* Install new colormap */
- do_install_cmap(con, info);
- DPRINTK("EXIT\n");
- return(0);
-}
-
-
-/*
- * Update the `var' structure (called by fbcon.c)
- *
- * This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'.
- * Since it's called by a kernel driver, no range checking is done.
- */
-
-static int Cyberfb_updatevar(int con, struct fb_info *info)
-{
- DPRINTK("Enter - Exit\n");
- return(0);
-}
-
-
-/*
- * Get a Video Mode
- */
-
-static int __init get_video_mode(const char *name)
-{
- int i;
-
- DPRINTK("ENTER\n");
- for (i = 0; i < NUM_TOTAL_MODES; i++) {
- if (!strcmp(name, cyberfb_predefined[i].name)) {
- cyberfb_default = cyberfb_predefined[i].var;
- cyberfb_usermode = 1;
- DPRINTK("EXIT - Matched predefined mode\n");
- return(i);
- }
- }
- return(0);
-}
-
-
-/*
- * Text console acceleration
- */
-
-#ifdef FBCON_HAS_CFB8
-static void fbcon_cyber8_bmove(struct display *p, int sy, int sx, int dy,
- int dx, int height, int width)
-{
- DPRINTK("ENTER\n");
- sx *= 8; dx *= 8; width *= 8;
- Cyber_BitBLT((u_short)sx, (u_short)(sy*fontheight(p)), (u_short)dx,
- (u_short)(dy*fontheight(p)), (u_short)width,
- (u_short)(height*fontheight(p)), (u_short)S3_NEW);
- DPRINTK("EXIT\n");
-}
-
-static void fbcon_cyber8_clear(struct vc_data *conp, struct display *p, int sy,
- int sx, int height, int width)
-{
- unsigned char bg;
-
- DPRINTK("ENTER\n");
- sx *= 8; width *= 8;
- bg = attr_bgcol_ec(p,conp);
- Cyber_RectFill((u_short)sx,
- (u_short)(sy*fontheight(p)),
- (u_short)width,
- (u_short)(height*fontheight(p)),
- (u_short)S3_NEW,
- (u_short)bg);
- DPRINTK("EXIT\n");
-}
-
-static void fbcon_cyber8_putc(struct vc_data *conp, struct display *p, int c,
- int yy, int xx)
-{
- DPRINTK("ENTER\n");
- Cyber_WaitBlit();
- fbcon_cfb8_putc(conp, p, c, yy, xx);
- DPRINTK("EXIT\n");
-}
-
-static void fbcon_cyber8_putcs(struct vc_data *conp, struct display *p,
- const unsigned short *s, int count,
- int yy, int xx)
-{
- DPRINTK("ENTER\n");
- Cyber_WaitBlit();
- fbcon_cfb8_putcs(conp, p, s, count, yy, xx);
- DPRINTK("EXIT\n");
-}
-
-static void fbcon_cyber8_revc(struct display *p, int xx, int yy)
-{
- DPRINTK("ENTER\n");
- Cyber_WaitBlit();
- fbcon_cfb8_revc(p, xx, yy);
- DPRINTK("EXIT\n");
-}
-
-static struct display_switch fbcon_cyber8 = {
- .setup = fbcon_cfb8_setup,
- .bmove = fbcon_cyber8_bmove,
- .clear = fbcon_cyber8_clear,
- .putc = fbcon_cyber8_putc,
- .putcs = fbcon_cyber8_putcs,
- .revc = fbcon_cyber8_revc,
- .clear_margins =fbcon_cfb8_clear_margins,
- .fontwidthmask =FONTWIDTH(8)
-};
-#endif
-
-
-#ifdef MODULE
-MODULE_LICENSE("GPL");
-
-int init_module(void)
-{
- return cyberfb_init();
-}
-#endif /* MODULE */
-
-/*
- *
- * Low level initialization routines for the CyberVision64 graphics card
- *
- * Most of the following code is from cvision_core.c
- *
- */
-
-#define MAXPIXELCLOCK 135000000 /* safety */
-
-#ifdef CV_AGGRESSIVE_TIMING
-long cv64_memclk = 55000000;
-#else
-long cv64_memclk = 50000000;
-#endif
-
-/*********************/
-
-static unsigned char clocks[]={
- 0x13, 0x61, 0x6b, 0x6d, 0x51, 0x69, 0x54, 0x69,
- 0x4f, 0x68, 0x6b, 0x6b, 0x18, 0x61, 0x7b, 0x6c,
- 0x51, 0x67, 0x24, 0x62, 0x56, 0x67, 0x77, 0x6a,
- 0x1d, 0x61, 0x53, 0x66, 0x6b, 0x68, 0x79, 0x69,
- 0x7c, 0x69, 0x7f, 0x69, 0x22, 0x61, 0x54, 0x65,
- 0x56, 0x65, 0x58, 0x65, 0x67, 0x66, 0x41, 0x63,
- 0x27, 0x61, 0x13, 0x41, 0x37, 0x62, 0x6b, 0x4d,
- 0x23, 0x43, 0x51, 0x49, 0x79, 0x66, 0x54, 0x49,
- 0x7d, 0x66, 0x34, 0x56, 0x4f, 0x63, 0x1f, 0x42,
- 0x6b, 0x4b, 0x7e, 0x4d, 0x18, 0x41, 0x2a, 0x43,
- 0x7b, 0x4c, 0x74, 0x4b, 0x51, 0x47, 0x65, 0x49,
- 0x24, 0x42, 0x68, 0x49, 0x56, 0x47, 0x75, 0x4a,
- 0x77, 0x4a, 0x31, 0x43, 0x1d, 0x41, 0x71, 0x49,
- 0x53, 0x46, 0x29, 0x42, 0x6b, 0x48, 0x1f, 0x41,
- 0x79, 0x49, 0x6f, 0x48, 0x7c, 0x49, 0x38, 0x43,
- 0x7f, 0x49, 0x5d, 0x46, 0x22, 0x41, 0x53, 0x45,
- 0x54, 0x45, 0x55, 0x45, 0x56, 0x45, 0x57, 0x45,
- 0x58, 0x45, 0x25, 0x41, 0x67, 0x46, 0x5b, 0x45,
- 0x41, 0x43, 0x78, 0x47, 0x27, 0x41, 0x51, 0x44,
- 0x13, 0x21, 0x7d, 0x47, 0x37, 0x42, 0x71, 0x46,
- 0x6b, 0x2d, 0x14, 0x21, 0x23, 0x23, 0x7d, 0x2f,
- 0x51, 0x29, 0x61, 0x2b, 0x79, 0x46, 0x1d, 0x22,
- 0x54, 0x29, 0x45, 0x27, 0x7d, 0x46, 0x7f, 0x46,
- 0x4f, 0x43, 0x2f, 0x41, 0x1f, 0x22, 0x6a, 0x2b,
- 0x6b, 0x2b, 0x5b, 0x29, 0x7e, 0x2d, 0x65, 0x44,
- 0x18, 0x21, 0x5e, 0x29, 0x2a, 0x23, 0x45, 0x26,
- 0x7b, 0x2c, 0x19, 0x21, 0x74, 0x2b, 0x75, 0x2b,
- 0x51, 0x27, 0x3f, 0x25, 0x65, 0x29, 0x40, 0x25,
- 0x24, 0x22, 0x41, 0x25, 0x68, 0x29, 0x42, 0x25,
- 0x56, 0x27, 0x7e, 0x2b, 0x75, 0x2a, 0x1c, 0x21,
- 0x77, 0x2a, 0x4f, 0x26, 0x31, 0x23, 0x6f, 0x29,
- 0x1d, 0x21, 0x32, 0x23, 0x71, 0x29, 0x72, 0x29,
- 0x53, 0x26, 0x69, 0x28, 0x29, 0x22, 0x75, 0x29,
- 0x6b, 0x28, 0x1f, 0x21, 0x1f, 0x21, 0x6d, 0x28,
- 0x79, 0x29, 0x2b, 0x22, 0x6f, 0x28, 0x59, 0x26,
- 0x7c, 0x29, 0x7d, 0x29, 0x38, 0x23, 0x21, 0x21,
- 0x7f, 0x29, 0x39, 0x23, 0x5d, 0x26, 0x75, 0x28,
- 0x22, 0x21, 0x77, 0x28, 0x53, 0x25, 0x6c, 0x27,
- 0x54, 0x25, 0x61, 0x26, 0x55, 0x25, 0x30, 0x22,
- 0x56, 0x25, 0x63, 0x26, 0x57, 0x25, 0x71, 0x27,
- 0x58, 0x25, 0x7f, 0x28, 0x25, 0x21, 0x74, 0x27,
- 0x67, 0x26, 0x40, 0x23, 0x5b, 0x25, 0x26, 0x21,
- 0x41, 0x23, 0x34, 0x22, 0x78, 0x27, 0x6b, 0x26,
- 0x27, 0x21, 0x35, 0x22, 0x51, 0x24, 0x7b, 0x27,
- 0x13, 0x1, 0x13, 0x1, 0x7d, 0x27, 0x4c, 0x9,
- 0x37, 0x22, 0x5b, 0xb, 0x71, 0x26, 0x5c, 0xb,
- 0x6b, 0xd, 0x47, 0x23, 0x14, 0x1, 0x4f, 0x9,
- 0x23, 0x3, 0x75, 0x26, 0x7d, 0xf, 0x1c, 0x2,
- 0x51, 0x9, 0x59, 0x24, 0x61, 0xb, 0x69, 0x25,
- 0x79, 0x26, 0x34, 0x5, 0x1d, 0x2, 0x6b, 0x25,
- 0x54, 0x9, 0x35, 0x5, 0x45, 0x7, 0x6d, 0x25,
- 0x7d, 0x26, 0x16, 0x1, 0x7f, 0x26, 0x77, 0xd,
- 0x4f, 0x23, 0x78, 0xd, 0x2f, 0x21, 0x27, 0x3,
- 0x1f, 0x2, 0x59, 0x9, 0x6a, 0xb, 0x73, 0x25,
- 0x6b, 0xb, 0x63, 0x24, 0x5b, 0x9, 0x20, 0x2,
- 0x7e, 0xd, 0x4b, 0x7, 0x65, 0x24, 0x43, 0x22,
- 0x18, 0x1, 0x6f, 0xb, 0x5e, 0x9, 0x70, 0xb,
- 0x2a, 0x3, 0x33, 0x4, 0x45, 0x6, 0x60, 0x9,
- 0x7b, 0xc, 0x19, 0x1, 0x19, 0x1, 0x7d, 0xc,
- 0x74, 0xb, 0x50, 0x7, 0x75, 0xb, 0x63, 0x9,
- 0x51, 0x7, 0x23, 0x2, 0x3f, 0x5, 0x1a, 0x1,
- 0x65, 0x9, 0x2d, 0x3, 0x40, 0x5, 0x0, 0x0,
-};
-
-/* Console colors */
-unsigned char cvconscolors[16][3] = { /* background, foreground, hilite */
- /* R G B */
- {0x30, 0x30, 0x30},
- {0x00, 0x00, 0x00},
- {0x80, 0x00, 0x00},
- {0x00, 0x80, 0x00},
- {0x00, 0x00, 0x80},
- {0x80, 0x80, 0x00},
- {0x00, 0x80, 0x80},
- {0x80, 0x00, 0x80},
- {0xff, 0xff, 0xff},
- {0x40, 0x40, 0x40},
- {0xff, 0x00, 0x00},
- {0x00, 0xff, 0x00},
- {0x00, 0x00, 0xff},
- {0xff, 0xff, 0x00},
- {0x00, 0xff, 0xff},
- {0x00, 0x00, 0xff}
-};
-
-/* -------------------- Hardware specific routines ------------------------- */
-
-/* Read Attribute Controller Register=idx */
-inline unsigned char RAttr (volatile unsigned char *regs, short idx)
-{
- wb_64 (regs, ACT_ADDRESS_W, idx);
- mb();
- udelay(100);
- return (rb_64(regs, ACT_ADDRESS_R));
-}
-
-/* Read Sequencer Register=idx */
-inline unsigned char RSeq (volatile unsigned char *regs, short idx)
-{
- wb_64 (regs, SEQ_ADDRESS, idx);
- mb();
- return (rb_64(regs, SEQ_ADDRESS_R));
-}
-
-/* Read CRT Controller Register=idx */
-inline unsigned char RCrt (volatile unsigned char *regs, short idx)
-{
- wb_64 (regs, CRT_ADDRESS, idx);
- mb();
- return (rb_64(regs, CRT_ADDRESS_R));
-}
-
-/* Read Graphics Controller Register=idx */
-inline unsigned char RGfx (volatile unsigned char *regs, short idx)
-{
- wb_64 (regs, GCT_ADDRESS, idx);
- mb();
- return (rb_64(regs, GCT_ADDRESS_R));
-}
-
-/*
- * Special wakeup/passthrough registers on graphics boards
- */
-
-inline void cv64_write_port (unsigned short bits,
- volatile unsigned char *base)
-{
- volatile unsigned char *addr;
- static unsigned char cvportbits = 0; /* Mirror port bits here */
- DPRINTK("ENTER\n");
-
- addr = base + 0x40001;
- if (bits & 0x8000) {
- cvportbits |= bits & 0xff; /* Set bits */
- DPRINTK("Set bits: %04x\n", bits);
- } else {
- bits = bits & 0xff;
- bits = (~bits) & 0xff;
- cvportbits &= bits; /* Clear bits */
- DPRINTK("Clear bits: %04x\n", bits);
- }
-
- *addr = cvportbits;
- DPRINTK("EXIT\n");
-}
-
-/*
- * Monitor switch on CyberVision board
- *
- * toggle:
- * 0 = CyberVision Signal
- * 1 = Amiga Signal
- * board = board addr
- *
- */
-inline void cvscreen (int toggle, volatile unsigned char *board)
-{
- DPRINTK("ENTER\n");
- if (toggle == 1) {
- DPRINTK("Show Amiga video\n");
- cv64_write_port (0x10, board);
- } else {
- DPRINTK("Show CyberVision video\n");
- cv64_write_port (0x8010, board);
- }
- DPRINTK("EXIT\n");
-}
-
-/* Control screen display */
-/* toggle: 0 = on, 1 = off */
-/* board = registerbase */
-inline void gfx_on_off(int toggle, volatile unsigned char *regs)
-{
- int r;
- DPRINTK("ENTER\n");
-
- toggle &= 0x1;
- toggle = toggle << 5;
- DPRINTK("Turn display %s\n", (toggle ? "off" : "on"));
-
- r = (int) RSeq(regs, SEQ_ID_CLOCKING_MODE);
- r &= 0xdf; /* Set bit 5 to 0 */
-
- WSeq (regs, SEQ_ID_CLOCKING_MODE, r | toggle);
- DPRINTK("EXIT\n");
-}
-
-/*
- * Computes M, N, and R values from
- * given input frequency. It uses a table of
- * precomputed values, to keep CPU time low.
- *
- * The return value consist of:
- * lower byte: Bits 4-0: N Divider Value
- * Bits 5-6: R Value for e.g. SR10 or SR12
- * higher byte: Bits 0-6: M divider value for e.g. SR11 or SR13
- */
-static unsigned short cv64_compute_clock(unsigned long freq)
-{
- static unsigned char *mnr, *save; /* M, N + R vals */
- unsigned long work_freq, r;
- unsigned short erg;
- long diff, d2;
-
- DPRINTK("ENTER\n");
- if (freq < 12500000 || freq > MAXPIXELCLOCK) {
- printk("CV64 driver: Illegal clock frequency %ld, using 25MHz\n",
- freq);
- freq = 25000000;
- }
- DPRINTK("Freq = %ld\n", freq);
- mnr = clocks; /* there the vals are stored */
- d2 = 0x7fffffff;
-
- while (*mnr) { /* mnr vals are 0-terminated */
- work_freq = (0x37EE * (mnr[0] + 2)) / ((mnr[1] & 0x1F) + 2);
-
- r = (mnr[1] >> 5) & 0x03;
- if (r != 0) {
- work_freq = work_freq >> r; /* r is the freq divider */
- }
-
- work_freq *= 0x3E8; /* 2nd part of OSC */
-
- diff = abs(freq - work_freq);
-
- if (d2 >= diff) {
- d2 = diff;
- /* In save are the vals for minimal diff */
- save = mnr;
- }
- mnr += 2;
- }
- erg = *((unsigned short *)save);
-
- DPRINTK("EXIT\n");
- return (erg);
-}
-
-static int cv_has_4mb (volatile unsigned char *fb)
-{
- volatile unsigned long *tr, *tw;
- DPRINTK("ENTER\n");
-
- /* write patterns in memory and test if they can be read */
- tw = (volatile unsigned long *) fb;
- tr = (volatile unsigned long *) (fb + 0x02000000);
-
- *tw = 0x87654321;
-
- if (*tr != 0x87654321) {
- DPRINTK("EXIT - <4MB\n");
- return (0);
- }
-
- /* upper memory region */
- tw = (volatile unsigned long *) (fb + 0x00200000);
- tr = (volatile unsigned long *) (fb + 0x02200000);
-
- *tw = 0x87654321;
-
- if (*tr != 0x87654321) {
- DPRINTK("EXIT - <4MB\n");
- return (0);
- }
-
- *tw = 0xAAAAAAAA;
-
- if (*tr != 0xAAAAAAAA) {
- DPRINTK("EXIT - <4MB\n");
- return (0);
- }
-
- *tw = 0x55555555;
-
- if (*tr != 0x55555555) {
- DPRINTK("EXIT - <4MB\n");
- return (0);
- }
-
- DPRINTK("EXIT\n");
- return (1);
-}
-
-static void cv64_board_init (void)
-{
- volatile unsigned char *regs = CyberRegs;
- int i;
- unsigned int clockpar;
- unsigned char test;
-
- DPRINTK("ENTER\n");
-
- /*
- * Special CyberVision 64 board operations
- */
- /* Reset board */
- for (i = 0; i < 6; i++) {
- cv64_write_port (0xff, CyberBase);
- }
- /* Return to operational mode */
- cv64_write_port (0x8004, CyberBase);
-
- /*
- * Generic (?) S3 chip wakeup
- */
- /* Disable I/O & memory decoders, video in setup mode */
- wb_64 (regs, SREG_VIDEO_SUBS_ENABLE, 0x10);
- /* Video responds to cmds, addrs & data */
- wb_64 (regs, SREG_OPTION_SELECT, 0x1);
- /* Enable I/O & memory decoders, video in operational mode */
- wb_64 (regs, SREG_VIDEO_SUBS_ENABLE, 0x8);
- /* VGA color emulation, enable cpu access to display mem */
- wb_64 (regs, GREG_MISC_OUTPUT_W, 0x03);
- /* Unlock S3 VGA regs */
- WCrt (regs, CRT_ID_REGISTER_LOCK_1, 0x48);
- /* Unlock system control & extension registers */
- WCrt (regs, CRT_ID_REGISTER_LOCK_2, 0xA5);
-/* GRF - Enable interrupts */
- /* Enable enhanced regs access, Ready cntl 0 wait states */
- test = RCrt (regs, CRT_ID_SYSTEM_CONFIG);
- test = test | 0x01; /* enable enhanced register access */
- test = test & 0xEF; /* clear bit 4, 0 wait state */
- WCrt (regs, CRT_ID_SYSTEM_CONFIG, test);
- /*
- * bit 0=1: Enable enhaced mode functions
- * bit 2=0: Enhanced mode 8+ bits/pixel
- * bit 4=1: Enable linear addressing
- * bit 5=1: Enable MMIO
- */
- wb_64 (regs, ECR_ADV_FUNC_CNTL, 0x31);
- /*
- * bit 0=1: Color emulation
- * bit 1=1: Enable CPU access to display memory
- * bit 5=1: Select high 64K memory page
- */
-/* GRF - 0xE3 */
- wb_64 (regs, GREG_MISC_OUTPUT_W, 0x23);
-
- /* Cpu base addr */
- WCrt (regs, CRT_ID_EXT_SYS_CNTL_4, 0x0);
-
- /* Reset. This does nothing on Trio, but standard VGA practice */
- /* WSeq (CyberRegs, SEQ_ID_RESET, 0x03); */
- /* Character clocks 8 dots wide */
- WSeq (regs, SEQ_ID_CLOCKING_MODE, 0x01);
- /* Enable cpu write to all color planes */
- WSeq (regs, SEQ_ID_MAP_MASK, 0x0F);
- /* Font table in 1st 8k of plane 2, font A=B disables swtich */
- WSeq (regs, SEQ_ID_CHAR_MAP_SELECT, 0x0);
- /* Allow mem access to 256kb */
- WSeq (regs, SEQ_ID_MEMORY_MODE, 0x2);
- /* Unlock S3 extensions to VGA Sequencer regs */
- WSeq (regs, SEQ_ID_UNLOCK_EXT, 0x6);
-
- /* Enable 4MB fast page mode */
- test = RSeq (regs, SEQ_ID_BUS_REQ_CNTL);
- test = test | 1 << 6;
- WSeq (regs, SEQ_ID_BUS_REQ_CNTL, test);
-
- /* Faster LUT write: 1 DCLK LUT write cycle, RAMDAC clk doubled */
- WSeq (regs, SEQ_ID_RAMDAC_CNTL, 0xC0);
-
- /* Clear immediate clock load bit */
- test = RSeq (regs, SEQ_ID_CLKSYN_CNTL_2);
- test = test & 0xDF;
- /* If > 55MHz, enable 2 cycle memory write */
- if (cv64_memclk >= 55000000) {
- test |= 0x80;
- }
- WSeq (regs, SEQ_ID_CLKSYN_CNTL_2, test);
-
- /* Set MCLK value */
- clockpar = cv64_compute_clock (cv64_memclk);
- test = (clockpar & 0xFF00) >> 8;
- WSeq (regs, SEQ_ID_MCLK_HI, test);
- test = clockpar & 0xFF;
- WSeq (regs, SEQ_ID_MCLK_LO, test);
-
- /* Chip rev specific: Not in my Trio manual!!! */
- if (RCrt (regs, CRT_ID_REVISION) == 0x10)
- WSeq (regs, SEQ_ID_MORE_MAGIC, test);
-
- /* We now load an 25 MHz, 31kHz, 640x480 standard VGA Mode. */
-
- /* Set DCLK value */
- WSeq (regs, SEQ_ID_DCLK_HI, 0x13);
- WSeq (regs, SEQ_ID_DCLK_LO, 0x41);
-
- /* Load DCLK (and MCLK?) immediately */
- test = RSeq (regs, SEQ_ID_CLKSYN_CNTL_2);
- test = test | 0x22;
- WSeq (regs, SEQ_ID_CLKSYN_CNTL_2, test);
-
- /* Enable loading of DCLK */
- test = rb_64(regs, GREG_MISC_OUTPUT_R);
- test = test | 0x0C;
- wb_64 (regs, GREG_MISC_OUTPUT_W, test);
-
- /* Turn off immediate xCLK load */
- WSeq (regs, SEQ_ID_CLKSYN_CNTL_2, 0x2);
-
- /* Horizontal character clock counts */
- /* 8 LSB of 9 bits = total line - 5 */
- WCrt (regs, CRT_ID_HOR_TOTAL, 0x5F);
- /* Active display line */
- WCrt (regs, CRT_ID_HOR_DISP_ENA_END, 0x4F);
- /* Blank assertion start */
- WCrt (regs, CRT_ID_START_HOR_BLANK, 0x50);
- /* Blank assertion end */
- WCrt (regs, CRT_ID_END_HOR_BLANK, 0x82);
- /* HSYNC assertion start */
- WCrt (regs, CRT_ID_START_HOR_RETR, 0x54);
- /* HSYNC assertion end */
- WCrt (regs, CRT_ID_END_HOR_RETR, 0x80);
- WCrt (regs, CRT_ID_VER_TOTAL, 0xBF);
- WCrt (regs, CRT_ID_OVERFLOW, 0x1F);
- WCrt (regs, CRT_ID_PRESET_ROW_SCAN, 0x0);
- WCrt (regs, CRT_ID_MAX_SCAN_LINE, 0x40);
- WCrt (regs, CRT_ID_CURSOR_START, 0x00);
- WCrt (regs, CRT_ID_CURSOR_END, 0x00);
- WCrt (regs, CRT_ID_START_ADDR_HIGH, 0x00);
- WCrt (regs, CRT_ID_START_ADDR_LOW, 0x00);
- WCrt (regs, CRT_ID_CURSOR_LOC_HIGH, 0x00);
- WCrt (regs, CRT_ID_CURSOR_LOC_LOW, 0x00);
- WCrt (regs, CRT_ID_START_VER_RETR, 0x9C);
- WCrt (regs, CRT_ID_END_VER_RETR, 0x0E);
- WCrt (regs, CRT_ID_VER_DISP_ENA_END, 0x8F);
- WCrt (regs, CRT_ID_SCREEN_OFFSET, 0x50);
- WCrt (regs, CRT_ID_UNDERLINE_LOC, 0x00);
- WCrt (regs, CRT_ID_START_VER_BLANK, 0x96);
- WCrt (regs, CRT_ID_END_VER_BLANK, 0xB9);
- WCrt (regs, CRT_ID_MODE_CONTROL, 0xE3);
- WCrt (regs, CRT_ID_LINE_COMPARE, 0xFF);
- WCrt (regs, CRT_ID_BACKWAD_COMP_3, 0x10); /* FIFO enabled */
- WCrt (regs, CRT_ID_MISC_1, 0x35);
- WCrt (regs, CRT_ID_DISPLAY_FIFO, 0x5A);
- WCrt (regs, CRT_ID_EXT_MEM_CNTL_2, 0x70);
- WCrt (regs, CRT_ID_LAW_POS_LO, 0x40);
- WCrt (regs, CRT_ID_EXT_MEM_CNTL_3, 0xFF);
-
- WGfx (regs, GCT_ID_SET_RESET, 0x0);
- WGfx (regs, GCT_ID_ENABLE_SET_RESET, 0x0);
- WGfx (regs, GCT_ID_COLOR_COMPARE, 0x0);
- WGfx (regs, GCT_ID_DATA_ROTATE, 0x0);
- WGfx (regs, GCT_ID_READ_MAP_SELECT, 0x0);
- WGfx (regs, GCT_ID_GRAPHICS_MODE, 0x40);
- WGfx (regs, GCT_ID_MISC, 0x01);
- WGfx (regs, GCT_ID_COLOR_XCARE, 0x0F);
- WGfx (regs, GCT_ID_BITMASK, 0xFF);
-
- /* Colors for text mode */
- for (i = 0; i < 0xf; i++)
- WAttr (regs, i, i);
-
- WAttr (regs, ACT_ID_ATTR_MODE_CNTL, 0x41);
- WAttr (regs, ACT_ID_OVERSCAN_COLOR, 0x01);
- WAttr (regs, ACT_ID_COLOR_PLANE_ENA, 0x0F);
- WAttr (regs, ACT_ID_HOR_PEL_PANNING, 0x0);
- WAttr (regs, ACT_ID_COLOR_SELECT, 0x0);
-
- wb_64 (regs, VDAC_MASK, 0xFF);
-
- *((unsigned long *) (regs + ECR_FRGD_COLOR)) = 0xFF;
- *((unsigned long *) (regs + ECR_BKGD_COLOR)) = 0;
-
- /* Colors initially set to grayscale */
-
- wb_64 (regs, VDAC_ADDRESS_W, 0);
- for (i = 255; i >= 0; i--) {
- wb_64(regs, VDAC_DATA, i);
- wb_64(regs, VDAC_DATA, i);
- wb_64(regs, VDAC_DATA, i);
- }
-
- /* GFx hardware cursor off */
- WCrt (regs, CRT_ID_HWGC_MODE, 0x00);
-
- /* Set first to 4MB, so test will work */
- WCrt (regs, CRT_ID_LAW_CNTL, 0x13);
- /* Find "correct" size of fbmem of Z3 board */
- if (cv_has_4mb (CyberMem)) {
- CyberSize = 1024 * 1024 * 4;
- WCrt (regs, CRT_ID_LAW_CNTL, 0x13);
- DPRINTK("4MB board\n");
- } else {
- CyberSize = 1024 * 1024 * 2;
- WCrt (regs, CRT_ID_LAW_CNTL, 0x12);
- DPRINTK("2MB board\n");
- }
-
- /* Initialize graphics engine */
- Cyber_WaitBlit();
- vgaw16 (regs, ECR_FRGD_MIX, 0x27);
- vgaw16 (regs, ECR_BKGD_MIX, 0x07);
- vgaw16 (regs, ECR_READ_REG_DATA, 0x1000);
- udelay(200);
- vgaw16 (regs, ECR_READ_REG_DATA, 0x2000);
- Cyber_WaitBlit();
- vgaw16 (regs, ECR_READ_REG_DATA, 0x3FFF);
- Cyber_WaitBlit();
- udelay(200);
- vgaw16 (regs, ECR_READ_REG_DATA, 0x4FFF);
- Cyber_WaitBlit();
- vgaw16 (regs, ECR_BITPLANE_WRITE_MASK, ~0);
- Cyber_WaitBlit();
- vgaw16 (regs, ECR_READ_REG_DATA, 0xE000);
- vgaw16 (regs, ECR_CURRENT_Y_POS2, 0x00);
- vgaw16 (regs, ECR_CURRENT_X_POS2, 0x00);
- vgaw16 (regs, ECR_READ_REG_DATA, 0xA000);
- vgaw16 (regs, ECR_DEST_Y__AX_STEP, 0x00);
- vgaw16 (regs, ECR_DEST_Y2__AX_STEP2, 0x00);
- vgaw16 (regs, ECR_DEST_X__DIA_STEP, 0x00);
- vgaw16 (regs, ECR_DEST_X2__DIA_STEP2, 0x00);
- vgaw16 (regs, ECR_SHORT_STROKE, 0x00);
- vgaw16 (regs, ECR_DRAW_CMD, 0x01);
-
- Cyber_WaitBlit();
-
- vgaw16 (regs, ECR_READ_REG_DATA, 0x4FFF);
- vgaw16 (regs, ECR_BKGD_COLOR, 0x01);
- vgaw16 (regs, ECR_FRGD_COLOR, 0x00);
-
-
- /* Enable video display (set bit 5) */
-/* ARB - Would also seem to write to AR13.
- * May want to use parts of WAttr to set JUST bit 5
- */
- WAttr (regs, 0x33, 0);
-
-/* GRF - function code ended here */
-
- /* Turn gfx on again */
- gfx_on_off (0, regs);
-
- /* Pass-through */
- cvscreen (0, CyberBase);
-
- DPRINTK("EXIT\n");
-}
-
-static void cv64_load_video_mode (struct fb_var_screeninfo *video_mode)
-{
- volatile unsigned char *regs = CyberRegs;
- int fx, fy;
- unsigned short mnr;
- unsigned short HT, HDE, HBS, HBE, HSS, HSE, VDE, VBS, VBE, VSS, VSE, VT;
- char LACE, DBLSCAN, TEXT, CONSOLE;
- int cr50, sr15, sr18, clock_mode, test;
- int m, n;
- int tfillm, temptym;
- int hmul;
-
- /* ---------------- */
- int xres, hfront, hsync, hback;
- int yres, vfront, vsync, vback;
- int bpp;
-#if 0
- float freq_f;
-#endif
- long freq;
- /* ---------------- */
-
- DPRINTK("ENTER\n");
- TEXT = 0; /* if depth == 4 */
- CONSOLE = 0; /* mode num == 255 (console) */
- fx = fy = 8; /* force 8x8 font */
-
-/* GRF - Disable interrupts */
-
- gfx_on_off (1, regs);
-
- switch (video_mode->bits_per_pixel) {
- case 15:
- case 16:
- hmul = 2;
- break;
-
- default:
- hmul = 1;
- break;
- }
-
- bpp = video_mode->bits_per_pixel;
- xres = video_mode->xres;
- hfront = video_mode->right_margin;
- hsync = video_mode->hsync_len;
- hback = video_mode->left_margin;
-
- LACE = 0;
- DBLSCAN = 0;
-
- if (video_mode->vmode & FB_VMODE_DOUBLE) {
- yres = video_mode->yres * 2;
- vfront = video_mode->lower_margin * 2;
- vsync = video_mode->vsync_len * 2;
- vback = video_mode->upper_margin * 2;
- DBLSCAN = 1;
- } else if (video_mode->vmode & FB_VMODE_INTERLACED) {
- yres = (video_mode->yres + 1) / 2;
- vfront = (video_mode->lower_margin + 1) / 2;
- vsync = (video_mode->vsync_len + 1) / 2;
- vback = (video_mode->upper_margin + 1) / 2;
- LACE = 1;
- } else {
- yres = video_mode->yres;
- vfront = video_mode->lower_margin;
- vsync = video_mode->vsync_len;
- vback = video_mode->upper_margin;
- }
-
- /* ARB Dropping custom setup method from cvision.c */
-#if 0
- if (cvision_custom_mode) {
- HBS = hbs / 8 * hmul;
- HBE = hbe / 8 * hmul;
- HSS = hss / 8 * hmul;
- HSE = hse / 8 * hmul;
- HT = ht / 8 * hmul - 5;
-
- VBS = vbs - 1;
- VSS = vss;
- VSE = vse;
- VBE = vbe;
- VT = vt - 2;
- } else {
-#else
- {
-#endif
- HBS = hmul * (xres / 8);
- HBE = hmul * ((xres/8) + (hfront/8) + (hsync/8) + (hback/8) - 2);
- HSS = hmul * ((xres/8) + (hfront/8) + 2);
- HSE = hmul * ((xres/8) + (hfront/8) + (hsync/8) + 1);
- HT = hmul * ((xres/8) + (hfront/8) + (hsync/8) + (hback/8));
-
- VBS = yres;
- VBE = yres + vfront + vsync + vback - 2;
- VSS = yres + vfront - 1;
- VSE = yres + vfront + vsync - 1;
- VT = yres + vfront + vsync + vback - 2;
- }
-
- wb_64 (regs, ECR_ADV_FUNC_CNTL, (TEXT ? 0x00 : 0x31));
-
- if (TEXT)
- HDE = ((video_mode->xres + fx - 1) / fx) - 1;
- else
- HDE = (video_mode->xres + 3) * hmul / 8 - 1;
-
- VDE = video_mode->yres - 1;
-
- WCrt (regs, CRT_ID_HWGC_MODE, 0x00);
- WCrt (regs, CRT_ID_EXT_DAC_CNTL, 0x00);
-
- WSeq (regs, SEQ_ID_MEMORY_MODE,
- (TEXT || (video_mode->bits_per_pixel == 1)) ? 0x06 : 0x0e);
- WGfx (regs, GCT_ID_READ_MAP_SELECT, 0x00);
- WSeq (regs, SEQ_ID_MAP_MASK,
- (video_mode->bits_per_pixel == 1) ? 0x01 : 0xFF);
- WSeq (regs, SEQ_ID_CHAR_MAP_SELECT, 0x00);
-
- /* cv64_compute_clock accepts arguments in Hz */
- /* pixclock is in ps ... convert to Hz */
-
-#if 0
- freq_f = (1.0 / (float) video_mode->pixclock) * 1000000000;
- freq = ((long) freq_f) * 1000;
-#else
-/* freq = (long) ((long long)1000000000000 / (long long) video_mode->pixclock);
- */
- freq = (1000000000 / video_mode->pixclock) * 1000;
-#endif
-
- mnr = cv64_compute_clock (freq);
- WSeq (regs, SEQ_ID_DCLK_HI, ((mnr & 0xFF00) >> 8));
- WSeq (regs, SEQ_ID_DCLK_LO, (mnr & 0xFF));
-
- /* Load display parameters into board */
- WCrt (regs, CRT_ID_EXT_HOR_OVF,
- ((HT & 0x100) ? 0x01 : 0x00) |
- ((HDE & 0x100) ? 0x02 : 0x00) |
- ((HBS & 0x100) ? 0x04 : 0x00) |
- /* ((HBE & 0x40) ? 0x08 : 0x00) | */
- ((HSS & 0x100) ? 0x10 : 0x00) |
- /* ((HSE & 0x20) ? 0x20 : 0x00) | */
- (((HT-5) & 0x100) ? 0x40 : 0x00)
- );
-
- WCrt (regs, CRT_ID_EXT_VER_OVF,
- 0x40 |
- ((VT & 0x400) ? 0x01 : 0x00) |
- ((VDE & 0x400) ? 0x02 : 0x00) |
- ((VBS & 0x400) ? 0x04 : 0x00) |
- ((VSS & 0x400) ? 0x10 : 0x00)
- );
-
- WCrt (regs, CRT_ID_HOR_TOTAL, HT);
- WCrt (regs, CRT_ID_DISPLAY_FIFO, HT - 5);
- WCrt (regs, CRT_ID_HOR_DISP_ENA_END, ((HDE >= HBS) ? (HBS - 1) : HDE));
- WCrt (regs, CRT_ID_START_HOR_BLANK, HBS);
- WCrt (regs, CRT_ID_END_HOR_BLANK, ((HBE & 0x1F) | 0x80));
- WCrt (regs, CRT_ID_START_HOR_RETR, HSS);
- WCrt (regs, CRT_ID_END_HOR_RETR,
- (HSE & 0x1F) |
- ((HBE & 0x20) ? 0x80 : 0x00)
- );
- WCrt (regs, CRT_ID_VER_TOTAL, VT);
- WCrt (regs, CRT_ID_OVERFLOW,
- 0x10 |
- ((VT & 0x100) ? 0x01 : 0x00) |
- ((VDE & 0x100) ? 0x02 : 0x00) |
- ((VSS & 0x100) ? 0x04 : 0x00) |
- ((VBS & 0x100) ? 0x08 : 0x00) |
- ((VT & 0x200) ? 0x20 : 0x00) |
- ((VDE & 0x200) ? 0x40 : 0x00) |
- ((VSS & 0x200) ? 0x80 : 0x00)
- );
- WCrt (regs, CRT_ID_MAX_SCAN_LINE,
- 0x40 |
- (DBLSCAN ? 0x80 : 0x00) |
- ((VBS & 0x200) ? 0x20 : 0x00) |
- (TEXT ? ((fy - 1) & 0x1F) : 0x00)
- );
-
- WCrt (regs, CRT_ID_MODE_CONTROL, 0xE3);
-
- /* Text cursor */
-
- if (TEXT) {
-#if 1
- WCrt (regs, CRT_ID_CURSOR_START, (fy & 0x1f) - 2);
- WCrt (regs, CRT_ID_CURSOR_END, (fy & 0x1F) - 1);
-#else
- WCrt (regs, CRT_ID_CURSOR_START, 0x00);
- WCrt (regs, CRT_ID_CURSOR_END, fy & 0x1F);
-#endif
- WCrt (regs, CRT_ID_UNDERLINE_LOC, (fy - 1) & 0x1F);
- WCrt (regs, CRT_ID_CURSOR_LOC_HIGH, 0x00);
- WCrt (regs, CRT_ID_CURSOR_LOC_LOW, 0x00);
- }
-
- WCrt (regs, CRT_ID_START_ADDR_HIGH, 0x00);
- WCrt (regs, CRT_ID_START_ADDR_LOW, 0x00);
- WCrt (regs, CRT_ID_START_VER_RETR, VSS);
- WCrt (regs, CRT_ID_END_VER_RETR, (VSE & 0x0F));
- WCrt (regs, CRT_ID_VER_DISP_ENA_END, VDE);
- WCrt (regs, CRT_ID_START_VER_BLANK, VBS);
- WCrt (regs, CRT_ID_END_VER_BLANK, VBE);
- WCrt (regs, CRT_ID_LINE_COMPARE, 0xFF);
- WCrt (regs, CRT_ID_LACE_RETR_START, HT / 2);
- WCrt (regs, CRT_ID_LACE_CONTROL, (LACE ? 0x20 : 0x00));
- WGfx (regs, GCT_ID_GRAPHICS_MODE,
- ((TEXT || (video_mode->bits_per_pixel == 1)) ? 0x00 : 0x40));
- WGfx (regs, GCT_ID_MISC, (TEXT ? 0x04 : 0x01));
- WSeq (regs, SEQ_ID_MEMORY_MODE,
- ((TEXT || (video_mode->bits_per_pixel == 1)) ? 0x06 : 0x02));
-
- wb_64 (regs, VDAC_MASK, 0xFF);
-
- /* Blank border */
- test = RCrt (regs, CRT_ID_BACKWAD_COMP_2);
- WCrt (regs, CRT_ID_BACKWAD_COMP_2, (test | 0x20));
-
- sr15 = RSeq (regs, SEQ_ID_CLKSYN_CNTL_2);
- sr15 &= 0xEF;
- sr18 = RSeq (regs, SEQ_ID_RAMDAC_CNTL);
- sr18 &= 0x7F;
- clock_mode = 0x00;
- cr50 = 0x00;
-
- test = RCrt (regs, CRT_ID_EXT_MISC_CNTL_2);
- test &= 0xD;
-
- /* Clear roxxler byte-swapping... */
- cv64_write_port (0x0040, CyberBase);
- cv64_write_port (0x0020, CyberBase);
-
- switch (video_mode->bits_per_pixel) {
- case 1:
- case 4: /* text */
- HDE = video_mode->xres / 16;
- break;
-
- case 8:
- if (freq > 80000000) {
- clock_mode = 0x10 | 0x02;
- sr15 |= 0x10;
- sr18 |= 0x80;
- }
- HDE = video_mode->xres / 8;
- cr50 |= 0x00;
- break;
-
- case 15:
- cv64_write_port (0x8020, CyberBase);
- clock_mode = 0x30;
- HDE = video_mode->xres / 4;
- cr50 |= 0x10;
- break;
-
- case 16:
- cv64_write_port (0x8020, CyberBase);
- clock_mode = 0x50;
- HDE = video_mode->xres / 4;
- cr50 |= 0x10;
- break;
-
- case 24:
- case 32:
- cv64_write_port (0x8040, CyberBase);
- clock_mode = 0xD0;
- HDE = video_mode->xres / 2;
- cr50 |= 0x30;
- break;
- }
-
- WCrt (regs, CRT_ID_EXT_MISC_CNTL_2, clock_mode | test);
- WSeq (regs, SEQ_ID_CLKSYN_CNTL_2, sr15);
- WSeq (regs, SEQ_ID_RAMDAC_CNTL, sr18);
- WCrt (regs, CRT_ID_SCREEN_OFFSET, HDE);
-
- WCrt (regs, CRT_ID_MISC_1, (TEXT ? 0x05 : 0x35));
-
- test = RCrt (regs, CRT_ID_EXT_SYS_CNTL_2);
- test &= ~0x30;
- test |= (HDE >> 4) & 0x30;
- WCrt (regs, CRT_ID_EXT_SYS_CNTL_2, test);
-
- /* Set up graphics engine */
- switch (video_mode->xres) {
- case 1024:
- cr50 |= 0x00;
- break;
-
- case 640:
- cr50 |= 0x40;
- break;
-
- case 800:
- cr50 |= 0x80;
- break;
-
- case 1280:
- cr50 |= 0xC0;
- break;
-
- case 1152:
- cr50 |= 0x01;
- break;
-
- case 1600:
- cr50 |= 0x81;
- break;
-
- default: /* XXX */
- break;
- }
-
- WCrt (regs, CRT_ID_EXT_SYS_CNTL_1, cr50);
-
- udelay(100);
- WAttr (regs, ACT_ID_ATTR_MODE_CNTL, (TEXT ? 0x08 : 0x41));
- udelay(100);
- WAttr (regs, ACT_ID_COLOR_PLANE_ENA,
- (video_mode->bits_per_pixel == 1) ? 0x01 : 0x0F);
- udelay(100);
-
- tfillm = (96 * (cv64_memclk / 1000)) / 240000;
-
- switch (video_mode->bits_per_pixel) {
- case 32:
- case 24:
- temptym = (24 * (cv64_memclk / 1000)) / (freq / 1000);
- break;
- case 15:
- case 16:
- temptym = (48 * (cv64_memclk / 1000)) / (freq / 1000);
- break;
- case 4:
- temptym = (192 * (cv64_memclk / 1000)) / (freq / 1000);
- break;
- default:
- temptym = (96 * (cv64_memclk / 1000)) / (freq / 1000);
- break;
- }
-
- m = (temptym - tfillm - 9) / 2;
- if (m < 0)
- m = 0;
- m = (m & 0x1F) << 3;
- if (m < 0x18)
- m = 0x18;
- n = 0xFF;
-
- WCrt (regs, CRT_ID_EXT_MEM_CNTL_2, m);
- WCrt (regs, CRT_ID_EXT_MEM_CNTL_3, n);
- udelay(10);
-
- /* Text initialization */
-
- if (TEXT) {
- /* Do text initialization here ! */
- }
-
- if (CONSOLE) {
- int i;
- wb_64 (regs, VDAC_ADDRESS_W, 0);
- for (i = 0; i < 4; i++) {
- wb_64 (regs, VDAC_DATA, cvconscolors [i][0]);
- wb_64 (regs, VDAC_DATA, cvconscolors [i][1]);
- wb_64 (regs, VDAC_DATA, cvconscolors [i][2]);
- }
- }
-
- WAttr (regs, 0x33, 0);
-
- /* Turn gfx on again */
- gfx_on_off (0, (volatile unsigned char *) regs);
-
- /* Pass-through */
- cvscreen (0, CyberBase);
-
-DPRINTK("EXIT\n");
-}
-
-void cvision_bitblt (u_short sx, u_short sy, u_short dx, u_short dy,
- u_short w, u_short h)
-{
- volatile unsigned char *regs = CyberRegs;
- unsigned short drawdir = 0;
-
- DPRINTK("ENTER\n");
- if (sx > dx) {
- drawdir |= 1 << 5;
- } else {
- sx += w - 1;
- dx += w - 1;
- }
-
- if (sy > dy) {
- drawdir |= 1 << 7;
- } else {
- sy += h - 1;
- dy += h - 1;
- }
-
- Cyber_WaitBlit();
- vgaw16 (regs, ECR_READ_REG_DATA, 0xA000);
- vgaw16 (regs, ECR_BKGD_MIX, 0x7);
- vgaw16 (regs, ECR_FRGD_MIX, 0x67);
- vgaw16 (regs, ECR_BKGD_COLOR, 0x0);
- vgaw16 (regs, ECR_FRGD_COLOR, 0x1);
- vgaw16 (regs, ECR_BITPLANE_READ_MASK, 0x1);
- vgaw16 (regs, ECR_BITPLANE_WRITE_MASK, 0xFFF);
- vgaw16 (regs, ECR_CURRENT_Y_POS, sy);
- vgaw16 (regs, ECR_CURRENT_X_POS, sx);
- vgaw16 (regs, ECR_DEST_Y__AX_STEP, dy);
- vgaw16 (regs, ECR_DEST_X__DIA_STEP, dx);
- vgaw16 (regs, ECR_READ_REG_DATA, h - 1);
- vgaw16 (regs, ECR_MAJ_AXIS_PIX_CNT, w - 1);
- vgaw16 (regs, ECR_DRAW_CMD, 0xC051 | drawdir);
- DPRINTK("EXIT\n");
-}
-
-void cvision_clear (u_short dx, u_short dy, u_short w, u_short h, u_short bg)
-{
- volatile unsigned char *regs = CyberRegs;
- DPRINTK("ENTER\n");
- Cyber_WaitBlit();
- vgaw16 (regs, ECR_FRGD_MIX, 0x0027);
- vgaw16 (regs, ECR_FRGD_COLOR, bg);
- vgaw16 (regs, ECR_READ_REG_DATA, 0xA000);
- vgaw16 (regs, ECR_CURRENT_Y_POS, dy);
- vgaw16 (regs, ECR_CURRENT_X_POS, dx);
- vgaw16 (regs, ECR_READ_REG_DATA, h - 1);
- vgaw16 (regs, ECR_MAJ_AXIS_PIX_CNT, w - 1);
- vgaw16 (regs, ECR_DRAW_CMD, 0x40B1);
- DPRINTK("EXIT\n");
-}
-
-#ifdef CYBERFBDEBUG
-/*
- * Dump internal settings of CyberVision board
- */
-static void cv64_dump (void)
-{
- volatile unsigned char *regs = CyberRegs;
- DPRINTK("ENTER\n");
- /* Dump the VGA setup values */
- *(regs + S3_CRTC_ADR) = 0x00;
- DPRINTK("CR00 = %x\n", *(regs + S3_CRTC_DATA));
- *(regs + S3_CRTC_ADR) = 0x01;
- DPRINTK("CR01 = %x\n", *(regs + S3_CRTC_DATA));
- *(regs + S3_CRTC_ADR) = 0x02;
- DPRINTK("CR02 = %x\n", *(regs + S3_CRTC_DATA));
- *(regs + S3_CRTC_ADR) = 0x03;
- DPRINTK("CR03 = %x\n", *(regs + S3_CRTC_DATA));
- *(regs + S3_CRTC_ADR) = 0x04;
- DPRINTK("CR04 = %x\n", *(regs + S3_CRTC_DATA));
- *(regs + S3_CRTC_ADR) = 0x05;
- DPRINTK("CR05 = %x\n", *(regs + S3_CRTC_DATA));
- *(regs + S3_CRTC_ADR) = 0x06;
- DPRINTK("CR06 = %x\n", *(regs + S3_CRTC_DATA));
- *(regs + S3_CRTC_ADR) = 0x07;
- DPRINTK("CR07 = %x\n", *(regs + S3_CRTC_DATA));
- *(regs + S3_CRTC_ADR) = 0x08;
- DPRINTK("CR08 = %x\n", *(regs + S3_CRTC_DATA));
- *(regs + S3_CRTC_ADR) = 0x09;
- DPRINTK("CR09 = %x\n", *(regs + S3_CRTC_DATA));
- *(regs + S3_CRTC_ADR) = 0x10;
- DPRINTK("CR10 = %x\n", *(regs + S3_CRTC_DATA));
- *(regs + S3_CRTC_ADR) = 0x11;
- DPRINTK("CR11 = %x\n", *(regs + S3_CRTC_DATA));
- *(regs + S3_CRTC_ADR) = 0x12;
- DPRINTK("CR12 = %x\n", *(regs + S3_CRTC_DATA));
- *(regs + S3_CRTC_ADR) = 0x13;
- DPRINTK("CR13 = %x\n", *(regs + S3_CRTC_DATA));
- *(regs + S3_CRTC_ADR) = 0x15;
- DPRINTK("CR15 = %x\n", *(regs + S3_CRTC_DATA));
- *(regs + S3_CRTC_ADR) = 0x16;
- DPRINTK("CR16 = %x\n", *(regs + S3_CRTC_DATA));
- *(regs + S3_CRTC_ADR) = 0x36;
- DPRINTK("CR36 = %x\n", *(regs + S3_CRTC_DATA));
- *(regs + S3_CRTC_ADR) = 0x37;
- DPRINTK("CR37 = %x\n", *(regs + S3_CRTC_DATA));
- *(regs + S3_CRTC_ADR) = 0x42;
- DPRINTK("CR42 = %x\n", *(regs + S3_CRTC_DATA));
- *(regs + S3_CRTC_ADR) = 0x43;
- DPRINTK("CR43 = %x\n", *(regs + S3_CRTC_DATA));
- *(regs + S3_CRTC_ADR) = 0x50;
- DPRINTK("CR50 = %x\n", *(regs + S3_CRTC_DATA));
- *(regs + S3_CRTC_ADR) = 0x51;
- DPRINTK("CR51 = %x\n", *(regs + S3_CRTC_DATA));
- *(regs + S3_CRTC_ADR) = 0x53;
- DPRINTK("CR53 = %x\n", *(regs + S3_CRTC_DATA));
- *(regs + S3_CRTC_ADR) = 0x58;
- DPRINTK("CR58 = %x\n", *(regs + S3_CRTC_DATA));
- *(regs + S3_CRTC_ADR) = 0x59;
- DPRINTK("CR59 = %x\n", *(regs + S3_CRTC_DATA));
- *(regs + S3_CRTC_ADR) = 0x5A;
- DPRINTK("CR5A = %x\n", *(regs + S3_CRTC_DATA));
- *(regs + S3_CRTC_ADR) = 0x5D;
- DPRINTK("CR5D = %x\n", *(regs + S3_CRTC_DATA));
- *(regs + S3_CRTC_ADR) = 0x5E;
- DPRINTK("CR5E = %x\n", *(regs + S3_CRTC_DATA));
- DPRINTK("MISC = %x\n", *(regs + GREG_MISC_OUTPUT_R));
- *(regs + SEQ_ADDRESS) = 0x01;
- DPRINTK("SR01 = %x\n", *(regs + SEQ_ADDRESS_R));
- *(regs + SEQ_ADDRESS) = 0x02;
- DPRINTK("SR02 = %x\n", *(regs + SEQ_ADDRESS_R));
- *(regs + SEQ_ADDRESS) = 0x03;
- DPRINTK("SR03 = %x\n", *(regs + SEQ_ADDRESS_R));
- *(regs + SEQ_ADDRESS) = 0x09;
- DPRINTK("SR09 = %x\n", *(regs + SEQ_ADDRESS_R));
- *(regs + SEQ_ADDRESS) = 0x10;
- DPRINTK("SR10 = %x\n", *(regs + SEQ_ADDRESS_R));
- *(regs + SEQ_ADDRESS) = 0x11;
- DPRINTK("SR11 = %x\n", *(regs + SEQ_ADDRESS_R));
- *(regs + SEQ_ADDRESS) = 0x12;
- DPRINTK("SR12 = %x\n", *(regs + SEQ_ADDRESS_R));
- *(regs + SEQ_ADDRESS) = 0x13;
- DPRINTK("SR13 = %x\n", *(regs + SEQ_ADDRESS_R));
- *(regs + SEQ_ADDRESS) = 0x15;
- DPRINTK("SR15 = %x\n", *(regs + SEQ_ADDRESS_R));
-
- return;
-}
-#endif
diff --git a/drivers/video/cyberfb.h b/drivers/video/cyberfb.h
deleted file mode 100644
index 8435c430ad2..00000000000
--- a/drivers/video/cyberfb.h
+++ /dev/null
@@ -1,415 +0,0 @@
-/*
- * linux/arch/m68k/console/cvision.h -- CyberVision64 definitions for the
- * text console driver.
- *
- * Copyright (c) 1998 Alan Bair
- *
- * This file is based on the initial port to Linux of grf_cvreg.h:
- *
- * Copyright (c) 1997 Antonio Santos
- *
- * The original work is from the NetBSD CyberVision 64 framebuffer driver
- * and support files (grf_cv.c, grf_cvreg.h, ite_cv.c):
- * Permission to use the source of this driver was obtained from the
- * author Michael Teske by Alan Bair.
- *
- * Copyright (c) 1995 Michael Teske
- *
- * History:
- *
- *
- *
- * 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.
- */
-
-/* s3 commands */
-#define S3_BITBLT 0xc011
-#define S3_TWOPOINTLINE 0x2811
-#define S3_FILLEDRECT 0x40b1
-
-#define S3_FIFO_EMPTY 0x0400
-#define S3_HDW_BUSY 0x0200
-
-/* Enhanced register mapping (MMIO mode) */
-
-#define S3_READ_SEL 0xbee8 /* offset f */
-#define S3_MULT_MISC 0xbee8 /* offset e */
-#define S3_ERR_TERM 0x92e8
-#define S3_FRGD_COLOR 0xa6e8
-#define S3_BKGD_COLOR 0xa2e8
-#define S3_PIXEL_CNTL 0xbee8 /* offset a */
-#define S3_FRGD_MIX 0xbae8
-#define S3_BKGD_MIX 0xb6e8
-#define S3_CUR_Y 0x82e8
-#define S3_CUR_X 0x86e8
-#define S3_DESTY_AXSTP 0x8ae8
-#define S3_DESTX_DIASTP 0x8ee8
-#define S3_MIN_AXIS_PCNT 0xbee8 /* offset 0 */
-#define S3_MAJ_AXIS_PCNT 0x96e8
-#define S3_CMD 0x9ae8
-#define S3_GP_STAT 0x9ae8
-#define S3_ADVFUNC_CNTL 0x4ae8
-#define S3_WRT_MASK 0xaae8
-#define S3_RD_MASK 0xaee8
-
-/* Enhanced register mapping (Packed MMIO mode, write only) */
-#define S3_ALT_CURXY 0x8100
-#define S3_ALT_CURXY2 0x8104
-#define S3_ALT_STEP 0x8108
-#define S3_ALT_STEP2 0x810c
-#define S3_ALT_ERR 0x8110
-#define S3_ALT_CMD 0x8118
-#define S3_ALT_MIX 0x8134
-#define S3_ALT_PCNT 0x8148
-#define S3_ALT_PAT 0x8168
-
-/* Drawing modes */
-#define S3_NOTCUR 0x0000
-#define S3_LOGICALZERO 0x0001
-#define S3_LOGICALONE 0x0002
-#define S3_LEAVEASIS 0x0003
-#define S3_NOTNEW 0x0004
-#define S3_CURXORNEW 0x0005
-#define S3_NOT_CURXORNEW 0x0006
-#define S3_NEW 0x0007
-#define S3_NOTCURORNOTNEW 0x0008
-#define S3_CURORNOTNEW 0x0009
-#define S3_NOTCURORNEW 0x000a
-#define S3_CURORNEW 0x000b
-#define S3_CURANDNEW 0x000c
-#define S3_NOTCURANDNEW 0x000d
-#define S3_CURANDNOTNEW 0x000e
-#define S3_NOTCURANDNOTNEW 0x000f
-
-#define S3_CRTC_ADR 0x03d4
-#define S3_CRTC_DATA 0x03d5
-
-#define S3_REG_LOCK2 0x39
-#define S3_HGC_MODE 0x45
-
-#define S3_HWGC_ORGX_H 0x46
-#define S3_HWGC_ORGX_L 0x47
-#define S3_HWGC_ORGY_H 0x48
-#define S3_HWGC_ORGY_L 0x49
-#define S3_HWGC_DX 0x4e
-#define S3_HWGC_DY 0x4f
-
-#define S3_LAW_CTL 0x58
-
-/**************************************************/
-
-/* support for a BitBlt operation. The op-codes are identical
- to X11 GCs */
-#define GRFBBOPclear 0x0 /* 0 */
-#define GRFBBOPand 0x1 /* src AND dst */
-#define GRFBBOPandReverse 0x2 /* src AND NOT dst */
-#define GRFBBOPcopy 0x3 /* src */
-#define GRFBBOPandInverted 0x4 /* NOT src AND dst */
-#define GRFBBOPnoop 0x5 /* dst */
-#define GRFBBOPxor 0x6 /* src XOR dst */
-#define GRFBBOPor 0x7 /* src OR dst */
-#define GRFBBOPnor 0x8 /* NOT src AND NOT dst */
-#define GRFBBOPequiv 0x9 /* NOT src XOR dst */
-#define GRFBBOPinvert 0xa /* NOT dst */
-#define GRFBBOPorReverse 0xb /* src OR NOT dst */
-#define GRFBBOPcopyInverted 0xc /* NOT src */
-#define GRFBBOPorInverted 0xd /* NOT src OR dst */
-#define GRFBBOPnand 0xe /* NOT src OR NOT dst */
-#define GRFBBOPset 0xf /* 1 */
-
-
-/* Write 16 Bit VGA register */
-#define vgaw16(ba, reg, val) \
-*((unsigned short *) (((volatile unsigned char *)ba)+reg)) = val
-
-/*
- * Defines for the used register addresses (mw)
- *
- * NOTE: There are some registers that have different addresses when
- * in mono or color mode. We only support color mode, and thus
- * some addresses won't work in mono-mode!
- *
- * General and VGA-registers taken from retina driver. Fixed a few
- * bugs in it. (SR and GR read address is Port + 1, NOT Port)
- *
- */
-
-/* General Registers: */
-#define GREG_MISC_OUTPUT_R 0x03CC
-#define GREG_MISC_OUTPUT_W 0x03C2
-#define GREG_FEATURE_CONTROL_R 0x03CA
-#define GREG_FEATURE_CONTROL_W 0x03DA
-#define GREG_INPUT_STATUS0_R 0x03C2
-#define GREG_INPUT_STATUS1_R 0x03DA
-
-/* Setup Registers: */
-#define SREG_OPTION_SELECT 0x0102
-#define SREG_VIDEO_SUBS_ENABLE 0x46E8
-
-/* Attribute Controller: */
-#define ACT_ADDRESS 0x03C0
-#define ACT_ADDRESS_R 0x03C1
-#define ACT_ADDRESS_W 0x03C0
-#define ACT_ADDRESS_RESET 0x03DA
-#define ACT_ID_PALETTE0 0x00
-#define ACT_ID_PALETTE1 0x01
-#define ACT_ID_PALETTE2 0x02
-#define ACT_ID_PALETTE3 0x03
-#define ACT_ID_PALETTE4 0x04
-#define ACT_ID_PALETTE5 0x05
-#define ACT_ID_PALETTE6 0x06
-#define ACT_ID_PALETTE7 0x07
-#define ACT_ID_PALETTE8 0x08
-#define ACT_ID_PALETTE9 0x09
-#define ACT_ID_PALETTE10 0x0A
-#define ACT_ID_PALETTE11 0x0B
-#define ACT_ID_PALETTE12 0x0C
-#define ACT_ID_PALETTE13 0x0D
-#define ACT_ID_PALETTE14 0x0E
-#define ACT_ID_PALETTE15 0x0F
-#define ACT_ID_ATTR_MODE_CNTL 0x10
-#define ACT_ID_OVERSCAN_COLOR 0x11
-#define ACT_ID_COLOR_PLANE_ENA 0x12
-#define ACT_ID_HOR_PEL_PANNING 0x13
-#define ACT_ID_COLOR_SELECT 0x14
-
-/* Graphics Controller: */
-#define GCT_ADDRESS 0x03CE
-#define GCT_ADDRESS_R 0x03CF
-#define GCT_ADDRESS_W 0x03CF
-#define GCT_ID_SET_RESET 0x00
-#define GCT_ID_ENABLE_SET_RESET 0x01
-#define GCT_ID_COLOR_COMPARE 0x02
-#define GCT_ID_DATA_ROTATE 0x03
-#define GCT_ID_READ_MAP_SELECT 0x04
-#define GCT_ID_GRAPHICS_MODE 0x05
-#define GCT_ID_MISC 0x06
-#define GCT_ID_COLOR_XCARE 0x07
-#define GCT_ID_BITMASK 0x08
-
-/* Sequencer: */
-#define SEQ_ADDRESS 0x03C4
-#define SEQ_ADDRESS_R 0x03C5
-#define SEQ_ADDRESS_W 0x03C5
-#define SEQ_ID_RESET 0x00
-#define SEQ_ID_CLOCKING_MODE 0x01
-#define SEQ_ID_MAP_MASK 0x02
-#define SEQ_ID_CHAR_MAP_SELECT 0x03
-#define SEQ_ID_MEMORY_MODE 0x04
-#define SEQ_ID_UNKNOWN1 0x05
-#define SEQ_ID_UNKNOWN2 0x06
-#define SEQ_ID_UNKNOWN3 0x07
-/* S3 extensions */
-#define SEQ_ID_UNLOCK_EXT 0x08
-#define SEQ_ID_EXT_SEQ_REG9 0x09
-#define SEQ_ID_BUS_REQ_CNTL 0x0A
-#define SEQ_ID_EXT_MISC_SEQ 0x0B
-#define SEQ_ID_UNKNOWN4 0x0C
-#define SEQ_ID_EXT_SEQ 0x0D
-#define SEQ_ID_UNKNOWN5 0x0E
-#define SEQ_ID_UNKNOWN6 0x0F
-#define SEQ_ID_MCLK_LO 0x10
-#define SEQ_ID_MCLK_HI 0x11
-#define SEQ_ID_DCLK_LO 0x12
-#define SEQ_ID_DCLK_HI 0x13
-#define SEQ_ID_CLKSYN_CNTL_1 0x14
-#define SEQ_ID_CLKSYN_CNTL_2 0x15
-#define SEQ_ID_CLKSYN_TEST_HI 0x16 /* reserved for S3 testing of the */
-#define SEQ_ID_CLKSYN_TEST_LO 0x17 /* internal clock synthesizer */
-#define SEQ_ID_RAMDAC_CNTL 0x18
-#define SEQ_ID_MORE_MAGIC 0x1A
-
-/* CRT Controller: */
-#define CRT_ADDRESS 0x03D4
-#define CRT_ADDRESS_R 0x03D5
-#define CRT_ADDRESS_W 0x03D5
-#define CRT_ID_HOR_TOTAL 0x00
-#define CRT_ID_HOR_DISP_ENA_END 0x01
-#define CRT_ID_START_HOR_BLANK 0x02
-#define CRT_ID_END_HOR_BLANK 0x03
-#define CRT_ID_START_HOR_RETR 0x04
-#define CRT_ID_END_HOR_RETR 0x05
-#define CRT_ID_VER_TOTAL 0x06
-#define CRT_ID_OVERFLOW 0x07
-#define CRT_ID_PRESET_ROW_SCAN 0x08
-#define CRT_ID_MAX_SCAN_LINE 0x09
-#define CRT_ID_CURSOR_START 0x0A
-#define CRT_ID_CURSOR_END 0x0B
-#define CRT_ID_START_ADDR_HIGH 0x0C
-#define CRT_ID_START_ADDR_LOW 0x0D
-#define CRT_ID_CURSOR_LOC_HIGH 0x0E
-#define CRT_ID_CURSOR_LOC_LOW 0x0F
-#define CRT_ID_START_VER_RETR 0x10
-#define CRT_ID_END_VER_RETR 0x11
-#define CRT_ID_VER_DISP_ENA_END 0x12
-#define CRT_ID_SCREEN_OFFSET 0x13
-#define CRT_ID_UNDERLINE_LOC 0x14
-#define CRT_ID_START_VER_BLANK 0x15
-#define CRT_ID_END_VER_BLANK 0x16
-#define CRT_ID_MODE_CONTROL 0x17
-#define CRT_ID_LINE_COMPARE 0x18
-#define CRT_ID_GD_LATCH_RBACK 0x22
-#define CRT_ID_ACT_TOGGLE_RBACK 0x24
-#define CRT_ID_ACT_INDEX_RBACK 0x26
-/* S3 extensions: S3 VGA Registers */
-#define CRT_ID_DEVICE_HIGH 0x2D
-#define CRT_ID_DEVICE_LOW 0x2E
-#define CRT_ID_REVISION 0x2F
-#define CRT_ID_CHIP_ID_REV 0x30
-#define CRT_ID_MEMORY_CONF 0x31
-#define CRT_ID_BACKWAD_COMP_1 0x32
-#define CRT_ID_BACKWAD_COMP_2 0x33
-#define CRT_ID_BACKWAD_COMP_3 0x34
-#define CRT_ID_REGISTER_LOCK 0x35
-#define CRT_ID_CONFIG_1 0x36
-#define CRT_ID_CONFIG_2 0x37
-#define CRT_ID_REGISTER_LOCK_1 0x38
-#define CRT_ID_REGISTER_LOCK_2 0x39
-#define CRT_ID_MISC_1 0x3A
-#define CRT_ID_DISPLAY_FIFO 0x3B
-#define CRT_ID_LACE_RETR_START 0x3C
-/* S3 extensions: System Control Registers */
-#define CRT_ID_SYSTEM_CONFIG 0x40
-#define CRT_ID_BIOS_FLAG 0x41
-#define CRT_ID_LACE_CONTROL 0x42
-#define CRT_ID_EXT_MODE 0x43
-#define CRT_ID_HWGC_MODE 0x45 /* HWGC = Hardware Graphics Cursor */
-#define CRT_ID_HWGC_ORIGIN_X_HI 0x46
-#define CRT_ID_HWGC_ORIGIN_X_LO 0x47
-#define CRT_ID_HWGC_ORIGIN_Y_HI 0x48
-#define CRT_ID_HWGC_ORIGIN_Y_LO 0x49
-#define CRT_ID_HWGC_FG_STACK 0x4A
-#define CRT_ID_HWGC_BG_STACK 0x4B
-#define CRT_ID_HWGC_START_AD_HI 0x4C
-#define CRT_ID_HWGC_START_AD_LO 0x4D
-#define CRT_ID_HWGC_DSTART_X 0x4E
-#define CRT_ID_HWGC_DSTART_Y 0x4F
-/* S3 extensions: System Extension Registers */
-#define CRT_ID_EXT_SYS_CNTL_1 0x50
-#define CRT_ID_EXT_SYS_CNTL_2 0x51
-#define CRT_ID_EXT_BIOS_FLAG_1 0x52
-#define CRT_ID_EXT_MEM_CNTL_1 0x53
-#define CRT_ID_EXT_MEM_CNTL_2 0x54
-#define CRT_ID_EXT_DAC_CNTL 0x55
-#define CRT_ID_EX_SYNC_1 0x56
-#define CRT_ID_EX_SYNC_2 0x57
-#define CRT_ID_LAW_CNTL 0x58 /* LAW = Linear Address Window */
-#define CRT_ID_LAW_POS_HI 0x59
-#define CRT_ID_LAW_POS_LO 0x5A
-#define CRT_ID_GOUT_PORT 0x5C
-#define CRT_ID_EXT_HOR_OVF 0x5D
-#define CRT_ID_EXT_VER_OVF 0x5E
-#define CRT_ID_EXT_MEM_CNTL_3 0x60
-#define CRT_ID_EX_SYNC_3 0x63
-#define CRT_ID_EXT_MISC_CNTL 0x65
-#define CRT_ID_EXT_MISC_CNTL_1 0x66
-#define CRT_ID_EXT_MISC_CNTL_2 0x67
-#define CRT_ID_CONFIG_3 0x68
-#define CRT_ID_EXT_SYS_CNTL_3 0x69
-#define CRT_ID_EXT_SYS_CNTL_4 0x6A
-#define CRT_ID_EXT_BIOS_FLAG_3 0x6B
-#define CRT_ID_EXT_BIOS_FLAG_4 0x6C
-
-/* Enhanced Commands Registers: */
-#define ECR_SUBSYSTEM_STAT 0x42E8
-#define ECR_SUBSYSTEM_CNTL 0x42E8
-#define ECR_ADV_FUNC_CNTL 0x4AE8
-#define ECR_CURRENT_Y_POS 0x82E8
-#define ECR_CURRENT_Y_POS2 0x82EA /* Trio64 only */
-#define ECR_CURRENT_X_POS 0x86E8
-#define ECR_CURRENT_X_POS2 0x86EA /* Trio64 only */
-#define ECR_DEST_Y__AX_STEP 0x8AE8
-#define ECR_DEST_Y2__AX_STEP2 0x8AEA /* Trio64 only */
-#define ECR_DEST_X__DIA_STEP 0x8EE8
-#define ECR_DEST_X2__DIA_STEP2 0x8EEA /* Trio64 only */
-#define ECR_ERR_TERM 0x92E8
-#define ECR_ERR_TERM2 0x92EA /* Trio64 only */
-#define ECR_MAJ_AXIS_PIX_CNT 0x96E8
-#define ECR_MAJ_AXIS_PIX_CNT2 0x96EA /* Trio64 only */
-#define ECR_GP_STAT 0x9AE8 /* GP = Graphics Processor */
-#define ECR_DRAW_CMD 0x9AE8
-#define ECR_DRAW_CMD2 0x9AEA /* Trio64 only */
-#define ECR_SHORT_STROKE 0x9EE8
-#define ECR_BKGD_COLOR 0xA2E8 /* BKGD = Background */
-#define ECR_FRGD_COLOR 0xA6E8 /* FRGD = Foreground */
-#define ECR_BITPLANE_WRITE_MASK 0xAAE8
-#define ECR_BITPLANE_READ_MASK 0xAEE8
-#define ECR_COLOR_COMPARE 0xB2E8
-#define ECR_BKGD_MIX 0xB6E8
-#define ECR_FRGD_MIX 0xBAE8
-#define ECR_READ_REG_DATA 0xBEE8
-#define ECR_ID_MIN_AXIS_PIX_CNT 0x00
-#define ECR_ID_SCISSORS_TOP 0x01
-#define ECR_ID_SCISSORS_LEFT 0x02
-#define ECR_ID_SCISSORS_BUTTOM 0x03
-#define ECR_ID_SCISSORS_RIGHT 0x04
-#define ECR_ID_PIX_CNTL 0x0A
-#define ECR_ID_MULT_CNTL_MISC_2 0x0D
-#define ECR_ID_MULT_CNTL_MISC 0x0E
-#define ECR_ID_READ_SEL 0x0F
-#define ECR_PIX_TRANS 0xE2E8
-#define ECR_PIX_TRANS_EXT 0xE2EA
-#define ECR_PATTERN_Y 0xEAE8 /* Trio64 only */
-#define ECR_PATTERN_X 0xEAEA /* Trio64 only */
-
-
-/* Pass-through */
-#define PASS_ADDRESS 0x40001
-#define PASS_ADDRESS_W 0x40001
-
-/* Video DAC */
-#define VDAC_ADDRESS 0x03c8
-#define VDAC_ADDRESS_W 0x03c8
-#define VDAC_ADDRESS_R 0x03c7
-#define VDAC_STATE 0x03c7
-#define VDAC_DATA 0x03c9
-#define VDAC_MASK 0x03c6
-
-
-#define WGfx(ba, idx, val) \
-do { wb_64(ba, GCT_ADDRESS, idx); wb_64(ba, GCT_ADDRESS_W , val); } while (0)
-
-#define WSeq(ba, idx, val) \
-do { wb_64(ba, SEQ_ADDRESS, idx); wb_64(ba, SEQ_ADDRESS_W , val); } while (0)
-
-#define WCrt(ba, idx, val) \
-do { wb_64(ba, CRT_ADDRESS, idx); wb_64(ba, CRT_ADDRESS_W , val); } while (0)
-
-#define WAttr(ba, idx, val) \
-do { \
- unsigned char tmp;\
- tmp = rb_64(ba, ACT_ADDRESS_RESET);\
- wb_64(ba, ACT_ADDRESS_W, idx);\
- wb_64(ba, ACT_ADDRESS_W, val);\
-} while (0)
-
-#define SetTextPlane(ba, m) \
-do { \
- WGfx(ba, GCT_ID_READ_MAP_SELECT, m & 3 );\
- WSeq(ba, SEQ_ID_MAP_MASK, (1 << (m & 3)));\
-} while (0)
-
- /* --------------------------------- */
- /* prototypes */
- /* --------------------------------- */
-
-inline unsigned char RAttr(volatile unsigned char * board, short idx);
-inline unsigned char RSeq(volatile unsigned char * board, short idx);
-inline unsigned char RCrt(volatile unsigned char * board, short idx);
-inline unsigned char RGfx(volatile unsigned char * board, short idx);
-inline void cv64_write_port(unsigned short bits,
- volatile unsigned char *board);
-inline void cvscreen(int toggle, volatile unsigned char *board);
-inline void gfx_on_off(int toggle, volatile unsigned char *board);
-#if 0
-unsigned short cv64_compute_clock(unsigned long freq);
-int cv_has_4mb(volatile unsigned char * fb);
-void cv64_board_init(void);
-void cv64_load_video_mode(struct fb_var_screeninfo *video_mode);
-#endif
-
-void cvision_bitblt(u_short sx, u_short sy, u_short dx, u_short dy, u_short w,
- u_short h);
-void cvision_clear(u_short dx, u_short dy, u_short w, u_short h, u_short bg);
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index 3cfea315a48..28225265159 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -16,7 +16,6 @@
#include <linux/compat.h>
#include <linux/types.h>
#include <linux/errno.h>
-#include <linux/sched.h>
#include <linux/smp_lock.h>
#include <linux/kernel.h>
#include <linux/major.h>
diff --git a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c
index 323bdf6fc7d..40c80c8190e 100644
--- a/drivers/video/fbsysfs.c
+++ b/drivers/video/fbsysfs.c
@@ -59,7 +59,7 @@ struct fb_info *framebuffer_alloc(size_t size, struct device *dev)
info->device = dev;
#ifdef CONFIG_FB_BACKLIGHT
- mutex_init(&info->bl_mutex);
+ mutex_init(&info->bl_curve_mutex);
#endif
return info;
@@ -175,7 +175,7 @@ static ssize_t store_modes(struct device *device,
acquire_console_sem();
list_splice(&fb_info->modelist, &old_list);
- fb_videomode_to_modelist((struct fb_videomode *)buf, i,
+ fb_videomode_to_modelist((const struct fb_videomode *)buf, i,
&fb_info->modelist);
if (fb_new_modelist(fb_info)) {
fb_destroy_modelist(&fb_info->modelist);
@@ -445,10 +445,10 @@ static ssize_t store_bl_curve(struct device *device,
/* If there has been an error in the input data, we won't
* reach this loop.
*/
- mutex_lock(&fb_info->bl_mutex);
+ mutex_lock(&fb_info->bl_curve_mutex);
for (i = 0; i < FB_BACKLIGHT_LEVELS; ++i)
fb_info->bl_curve[i] = tmp_curve[i];
- mutex_unlock(&fb_info->bl_mutex);
+ mutex_unlock(&fb_info->bl_curve_mutex);
return count;
}
@@ -466,7 +466,7 @@ static ssize_t show_bl_curve(struct device *device,
if (!fb_info || !fb_info->bl_dev)
return -ENODEV;
- mutex_lock(&fb_info->bl_mutex);
+ mutex_lock(&fb_info->bl_curve_mutex);
for (i = 0; i < FB_BACKLIGHT_LEVELS; i += 8)
len += snprintf(&buf[len], PAGE_SIZE,
"%02x %02x %02x %02x %02x %02x %02x %02x\n",
@@ -478,7 +478,7 @@ static ssize_t show_bl_curve(struct device *device,
fb_info->bl_curve[i + 5],
fb_info->bl_curve[i + 6],
fb_info->bl_curve[i + 7]);
- mutex_unlock(&fb_info->bl_mutex);
+ mutex_unlock(&fb_info->bl_curve_mutex);
return len;
}
@@ -552,6 +552,8 @@ void fb_bl_default_curve(struct fb_info *fb_info, u8 off, u8 min, u8 max)
{
unsigned int i, flat, count, range = (max - min);
+ mutex_lock(&fb_info->bl_curve_mutex);
+
fb_info->bl_curve[0] = off;
for (flat = 1; flat < (FB_BACKLIGHT_LEVELS / 16); ++flat)
@@ -560,6 +562,8 @@ void fb_bl_default_curve(struct fb_info *fb_info, u8 off, u8 min, u8 max)
count = FB_BACKLIGHT_LEVELS * 15 / 16;
for (i = 0; i < count; ++i)
fb_info->bl_curve[flat + i] = min + (range * (i + 1) / count);
+
+ mutex_unlock(&fb_info->bl_curve_mutex);
}
EXPORT_SYMBOL_GPL(fb_bl_default_curve);
#endif
diff --git a/drivers/video/g364fb.c b/drivers/video/g364fb.c
index 1b981b63567..ca93a75f299 100644
--- a/drivers/video/g364fb.c
+++ b/drivers/video/g364fb.c
@@ -16,7 +16,6 @@
#include <linux/module.h>
#include <linux/console.h>
-#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
diff --git a/drivers/video/geode/gx1fb_core.c b/drivers/video/geode/gx1fb_core.c
index bcf9cea54d8..bb20a228976 100644
--- a/drivers/video/geode/gx1fb_core.c
+++ b/drivers/video/geode/gx1fb_core.c
@@ -401,6 +401,30 @@ static void gx1fb_remove(struct pci_dev *pdev)
framebuffer_release(info);
}
+#ifndef MODULE
+static void __init gx1fb_setup(char *options)
+{
+ char *this_opt;
+
+ if (!options || !*options)
+ return;
+
+ while ((this_opt = strsep(&options, ","))) {
+ if (!*this_opt)
+ continue;
+
+ if (!strncmp(this_opt, "mode:", 5))
+ strlcpy(mode_option, this_opt + 5, sizeof(mode_option));
+ else if (!strncmp(this_opt, "crt:", 4))
+ crt_option = !!simple_strtoul(this_opt + 4, NULL, 0);
+ else if (!strncmp(this_opt, "panel:", 6))
+ strlcpy(panel_option, this_opt + 6, sizeof(panel_option));
+ else
+ strlcpy(mode_option, this_opt, sizeof(mode_option));
+ }
+}
+#endif
+
static struct pci_device_id gx1fb_id_table[] = {
{ PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_VIDEO,
PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,
@@ -420,8 +444,11 @@ static struct pci_driver gx1fb_driver = {
static int __init gx1fb_init(void)
{
#ifndef MODULE
- if (fb_get_options("gx1fb", NULL))
+ char *option = NULL;
+
+ if (fb_get_options("gx1fb", &option))
return -ENODEV;
+ gx1fb_setup(option);
#endif
return pci_register_driver(&gx1fb_driver);
}
diff --git a/drivers/video/hitfb.c b/drivers/video/hitfb.c
index 3dc49424dc7..756c0ce8591 100644
--- a/drivers/video/hitfb.c
+++ b/drivers/video/hitfb.c
@@ -13,7 +13,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
diff --git a/drivers/video/hpfb.c b/drivers/video/hpfb.c
index 9ab9b839a0f..b18486ad8e1 100644
--- a/drivers/video/hpfb.c
+++ b/drivers/video/hpfb.c
@@ -7,7 +7,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
diff --git a/drivers/video/i810/i810-i2c.c b/drivers/video/i810/i810-i2c.c
index 961f4d40446..7787c3322ff 100644
--- a/drivers/video/i810/i810-i2c.c
+++ b/drivers/video/i810/i810-i2c.c
@@ -10,7 +10,6 @@
*/
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/fb.h>
diff --git a/drivers/video/i810/i810.h b/drivers/video/i810/i810.h
index 579195c2bea..aa65ffce915 100644
--- a/drivers/video/i810/i810.h
+++ b/drivers/video/i810/i810.h
@@ -264,7 +264,8 @@ struct i810fb_par {
struct heap_data cursor_heap;
struct vgastate state;
struct i810fb_i2c_chan chan[3];
- atomic_t use_count;
+ struct mutex open_lock;
+ unsigned int use_count;
u32 pseudo_palette[17];
unsigned long mmio_start_phys;
u8 __iomem *mmio_start_virtual;
diff --git a/drivers/video/i810/i810_main.c b/drivers/video/i810/i810_main.c
index b55a12d95eb..7e760197cf2 100644
--- a/drivers/video/i810/i810_main.c
+++ b/drivers/video/i810/i810_main.c
@@ -142,7 +142,7 @@ static int hsync2 __devinitdata;
static int vsync1 __devinitdata;
static int vsync2 __devinitdata;
static int xres __devinitdata;
-static int yres __devinitdata;
+static int yres;
static int vyres __devinitdata;
static int sync __devinitdata;
static int extvga __devinitdata;
@@ -1049,7 +1049,7 @@ static int i810_check_params(struct fb_var_screeninfo *var,
mode_valid = 1;
if (!mode_valid && info->monspecs.modedb_len) {
- struct fb_videomode *mode;
+ const struct fb_videomode *mode;
mode = fb_find_best_mode(var, &info->modelist);
if (mode) {
@@ -1235,9 +1235,9 @@ static int i810fb_getcolreg(u8 regno, u8 *red, u8 *green, u8 *blue,
static int i810fb_open(struct fb_info *info, int user)
{
struct i810fb_par *par = info->par;
- u32 count = atomic_read(&par->use_count);
-
- if (count == 0) {
+
+ mutex_lock(&par->open_lock);
+ if (par->use_count == 0) {
memset(&par->state, 0, sizeof(struct vgastate));
par->state.flags = VGA_SAVE_CMAP;
par->state.vgabase = par->mmio_start_virtual;
@@ -1246,7 +1246,8 @@ static int i810fb_open(struct fb_info *info, int user)
i810_save_vga_state(par);
}
- atomic_inc(&par->use_count);
+ par->use_count++;
+ mutex_unlock(&par->open_lock);
return 0;
}
@@ -1254,18 +1255,20 @@ static int i810fb_open(struct fb_info *info, int user)
static int i810fb_release(struct fb_info *info, int user)
{
struct i810fb_par *par = info->par;
- u32 count;
-
- count = atomic_read(&par->use_count);
- if (count == 0)
+
+ mutex_lock(&par->open_lock);
+ if (par->use_count == 0) {
+ mutex_unlock(&par->open_lock);
return -EINVAL;
+ }
- if (count == 1) {
+ if (par->use_count == 1) {
i810_restore_vga_state(par);
restore_vga(&par->state);
}
- atomic_dec(&par->use_count);
+ par->use_count--;
+ mutex_unlock(&par->open_lock);
return 0;
}
@@ -1752,6 +1755,8 @@ static void __devinit i810_init_monspecs(struct fb_info *info)
static void __devinit i810_init_defaults(struct i810fb_par *par,
struct fb_info *info)
{
+ mutex_init(&par->open_lock);
+
if (voffset)
v_offset_default = voffset;
else if (par->aperture.size > 32 * 1024 * 1024)
@@ -1919,7 +1924,7 @@ static void __devinit i810fb_find_init_mode(struct fb_info *info)
fb_videomode_to_modelist(specs->modedb, specs->modedb_len,
&info->modelist);
if (specs->modedb != NULL) {
- struct fb_videomode *m;
+ const struct fb_videomode *m;
if (xres && yres) {
if ((m = fb_find_best_mode(&var, &info->modelist))) {
@@ -2016,11 +2021,10 @@ static int __devinit i810fb_init_pci (struct pci_dev *dev,
par = info->par;
par->dev = dev;
- if (!(info->pixmap.addr = kmalloc(8*1024, GFP_KERNEL))) {
+ if (!(info->pixmap.addr = kzalloc(8*1024, GFP_KERNEL))) {
i810fb_release_resource(info, par);
return -ENOMEM;
}
- memset(info->pixmap.addr, 0, 8*1024);
info->pixmap.size = 8*1024;
info->pixmap.buf_align = 8;
info->pixmap.access_align = 32;
diff --git a/drivers/video/igafb.c b/drivers/video/igafb.c
index 655ae0fa99c..90592fb5915 100644
--- a/drivers/video/igafb.c
+++ b/drivers/video/igafb.c
@@ -370,7 +370,6 @@ static int __init iga_init(struct fb_info *info, struct iga_par *par)
int __init igafb_init(void)
{
- extern int con_is_present(void);
struct fb_info *info;
struct pci_dev *pdev;
struct iga_par *par;
@@ -402,12 +401,11 @@ int __init igafb_init(void)
size = sizeof(struct fb_info) + sizeof(struct iga_par) + sizeof(u32)*16;
- info = kmalloc(size, GFP_ATOMIC);
+ info = kzalloc(size, GFP_ATOMIC);
if (!info) {
printk("igafb_init: can't alloc fb_info\n");
return -ENOMEM;
}
- memset(info, 0, size);
par = (struct iga_par *) (info + 1);
@@ -466,7 +464,7 @@ int __init igafb_init(void)
* one additional region with size == 0.
*/
- par->mmap_map = kmalloc(4 * sizeof(*par->mmap_map), GFP_ATOMIC);
+ par->mmap_map = kzalloc(4 * sizeof(*par->mmap_map), GFP_ATOMIC);
if (!par->mmap_map) {
printk("igafb_init: can't alloc mmap_map\n");
iounmap((void *)par->io_base);
@@ -475,8 +473,6 @@ int __init igafb_init(void)
return -ENOMEM;
}
- memset(par->mmap_map, 0, 4 * sizeof(*par->mmap_map));
-
/*
* Set default vmode and cmode from PROM properties.
*/
diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c
index 0f9b2fdc28b..267c1ff9ebd 100644
--- a/drivers/video/imxfb.c
+++ b/drivers/video/imxfb.c
@@ -20,7 +20,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/interrupt.h>
diff --git a/drivers/video/intelfb/intelfb_i2c.c b/drivers/video/intelfb/intelfb_i2c.c
index 33bc41f5054..f4ede5f6b58 100644
--- a/drivers/video/intelfb/intelfb_i2c.c
+++ b/drivers/video/intelfb/intelfb_i2c.c
@@ -27,7 +27,6 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/fb.h>
diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c
index 664fc5cf962..b75eda84858 100644
--- a/drivers/video/intelfb/intelfbdrv.c
+++ b/drivers/video/intelfb/intelfbdrv.c
@@ -540,12 +540,11 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
dinfo->pdev = pdev;
/* Reserve pixmap space. */
- info->pixmap.addr = kmalloc(64 * 1024, GFP_KERNEL);
+ info->pixmap.addr = kzalloc(64 * 1024, GFP_KERNEL);
if (info->pixmap.addr == NULL) {
ERR_MSG("Cannot reserve pixmap memory.\n");
goto err_out_pixmap;
}
- memset(info->pixmap.addr, 0, 64 * 1024);
/* set early this option because it could be changed by tv encoder
driver */
diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c
index a95836839e1..c1eb18bf088 100644
--- a/drivers/video/intelfb/intelfbhw.c
+++ b/drivers/video/intelfb/intelfbhw.c
@@ -1990,7 +1990,8 @@ int
intelfbhw_enable_irq(struct intelfb_info *dinfo, int reenable) {
if (!test_and_set_bit(0, &dinfo->irq_flags)) {
- if (request_irq(dinfo->pdev->irq, intelfbhw_irq, SA_SHIRQ, "intelfb", dinfo)) {
+ if (request_irq(dinfo->pdev->irq, intelfbhw_irq, IRQF_SHARED,
+ "intelfb", dinfo)) {
clear_bit(0, &dinfo->irq_flags);
return -EINVAL;
}
diff --git a/drivers/video/kyro/fbdev.c b/drivers/video/kyro/fbdev.c
index f0d614a80f1..1c557990739 100644
--- a/drivers/video/kyro/fbdev.c
+++ b/drivers/video/kyro/fbdev.c
@@ -12,7 +12,6 @@
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/errno.h>
#include <linux/string.h>
diff --git a/drivers/video/macfb.c b/drivers/video/macfb.c
index 180d94c2b4d..f7d647dda97 100644
--- a/drivers/video/macfb.c
+++ b/drivers/video/macfb.c
@@ -20,7 +20,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
diff --git a/drivers/video/matrox/i2c-matroxfb.c b/drivers/video/matrox/i2c-matroxfb.c
index fe28848e7b5..5ec718a5fe2 100644
--- a/drivers/video/matrox/i2c-matroxfb.c
+++ b/drivers/video/matrox/i2c-matroxfb.c
@@ -115,6 +115,7 @@ static int i2c_bus_reg(struct i2c_bit_adapter* b, struct matrox_fb_info* minfo,
minfo->fbcon.node);
i2c_set_adapdata(&b->adapter, b);
b->adapter.algo_data = &b->bac;
+ b->adapter.dev.parent = &ACCESS_FBINFO(pcidev)->dev;
b->bac = matrox_i2c_algo_template;
b->bac.data = b;
err = i2c_bit_add_bus(&b->adapter);
@@ -146,7 +147,7 @@ static void* i2c_matroxfb_probe(struct matrox_fb_info* minfo) {
unsigned long flags;
struct matroxfb_dh_maven_info* m2info;
- m2info = kmalloc(sizeof(*m2info), GFP_KERNEL);
+ m2info = kzalloc(sizeof(*m2info), GFP_KERNEL);
if (!m2info)
return NULL;
@@ -155,8 +156,6 @@ static void* i2c_matroxfb_probe(struct matrox_fb_info* minfo) {
matroxfb_DAC_out(PMINFO DAC_XGENIOCTRL, 0x00);
matroxfb_DAC_unlock_irqrestore(flags);
- memset(m2info, 0, sizeof(*m2info));
-
switch (ACCESS_FBINFO(chip)) {
case MGA_2064:
case MGA_2164:
diff --git a/drivers/video/matrox/matroxfb_crtc2.c b/drivers/video/matrox/matroxfb_crtc2.c
index 2c9801090fa..03ae55b168f 100644
--- a/drivers/video/matrox/matroxfb_crtc2.c
+++ b/drivers/video/matrox/matroxfb_crtc2.c
@@ -694,12 +694,11 @@ static void* matroxfb_crtc2_probe(struct matrox_fb_info* minfo) {
/* hardware is CRTC2 incapable... */
if (!ACCESS_FBINFO(devflags.crtc2))
return NULL;
- m2info = kmalloc(sizeof(*m2info), GFP_KERNEL);
+ m2info = kzalloc(sizeof(*m2info), GFP_KERNEL);
if (!m2info) {
printk(KERN_ERR "matroxfb_crtc2: Not enough memory for CRTC2 control structs\n");
return NULL;
}
- memset(m2info, 0, sizeof(*m2info));
m2info->primary_dev = MINFO;
if (matroxfb_dh_registerfb(m2info)) {
kfree(m2info);
diff --git a/drivers/video/maxinefb.c b/drivers/video/maxinefb.c
index 38c8d38de4f..5e91c2b30af 100644
--- a/drivers/video/maxinefb.c
+++ b/drivers/video/maxinefb.c
@@ -25,7 +25,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
diff --git a/drivers/video/mbx/mbxdebugfs.c b/drivers/video/mbx/mbxdebugfs.c
index 472a3ca3d92..15b8b3c4330 100644
--- a/drivers/video/mbx/mbxdebugfs.c
+++ b/drivers/video/mbx/mbxdebugfs.c
@@ -170,37 +170,37 @@ static ssize_t misc_read_file(struct file *file, char __user *userbuf,
}
-static struct file_operations sysconf_fops = {
+static const struct file_operations sysconf_fops = {
.read = sysconf_read_file,
.write = write_file_dummy,
.open = open_file_generic,
};
-static struct file_operations clock_fops = {
+static const struct file_operations clock_fops = {
.read = clock_read_file,
.write = write_file_dummy,
.open = open_file_generic,
};
-static struct file_operations display_fops = {
+static const struct file_operations display_fops = {
.read = display_read_file,
.write = write_file_dummy,
.open = open_file_generic,
};
-static struct file_operations gsctl_fops = {
+static const struct file_operations gsctl_fops = {
.read = gsctl_read_file,
.write = write_file_dummy,
.open = open_file_generic,
};
-static struct file_operations sdram_fops = {
+static const struct file_operations sdram_fops = {
.read = sdram_read_file,
.write = write_file_dummy,
.open = open_file_generic,
};
-static struct file_operations misc_fops = {
+static const struct file_operations misc_fops = {
.read = misc_read_file,
.write = write_file_dummy,
.open = open_file_generic,
diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c
index 5df41f6f2b8..3e517940c5a 100644
--- a/drivers/video/modedb.c
+++ b/drivers/video/modedb.c
@@ -13,7 +13,6 @@
#include <linux/module.h>
#include <linux/fb.h>
-#include <linux/sched.h>
#undef DEBUG
@@ -610,10 +609,8 @@ done:
diff = refresh;
best = -1;
for (i = 0; i < dbsize; i++) {
- if ((name_matches(db[i], name, namelen) &&
- !fb_try_mode(var, info, &db[i], bpp)))
- return 1;
- if (res_specified && res_matches(db[i], xres, yres)) {
+ if (name_matches(db[i], name, namelen) ||
+ (res_specified && res_matches(db[i], xres, yres))) {
if(!fb_try_mode(var, info, &db[i], bpp)) {
if(!refresh_specified || db[i].refresh == refresh)
return 1;
@@ -670,7 +667,7 @@ done:
* @var: pointer to struct fb_var_screeninfo
*/
void fb_var_to_videomode(struct fb_videomode *mode,
- struct fb_var_screeninfo *var)
+ const struct fb_var_screeninfo *var)
{
u32 pixclock, hfreq, htotal, vtotal;
@@ -714,17 +711,21 @@ void fb_var_to_videomode(struct fb_videomode *mode,
* @mode: pointer to struct fb_videomode
*/
void fb_videomode_to_var(struct fb_var_screeninfo *var,
- struct fb_videomode *mode)
+ const struct fb_videomode *mode)
{
var->xres = mode->xres;
var->yres = mode->yres;
+ var->xres_virtual = mode->xres;
+ var->yres_virtual = mode->yres;
+ var->xoffset = 0;
+ var->yoffset = 0;
var->pixclock = mode->pixclock;
var->left_margin = mode->left_margin;
- var->hsync_len = mode->hsync_len;
- var->vsync_len = mode->vsync_len;
var->right_margin = mode->right_margin;
var->upper_margin = mode->upper_margin;
var->lower_margin = mode->lower_margin;
+ var->hsync_len = mode->hsync_len;
+ var->vsync_len = mode->vsync_len;
var->sync = mode->sync;
var->vmode = mode->vmode & FB_VMODE_MASK;
}
@@ -737,8 +738,8 @@ void fb_videomode_to_var(struct fb_var_screeninfo *var,
* RETURNS:
* 1 if equal, 0 if not
*/
-int fb_mode_is_equal(struct fb_videomode *mode1,
- struct fb_videomode *mode2)
+int fb_mode_is_equal(const struct fb_videomode *mode1,
+ const struct fb_videomode *mode2)
{
return (mode1->xres == mode2->xres &&
mode1->yres == mode2->yres &&
@@ -770,8 +771,8 @@ int fb_mode_is_equal(struct fb_videomode *mode1,
* var->xres and var->yres. If more than 1 videomode is found, will return
* the videomode with the highest refresh rate
*/
-struct fb_videomode *fb_find_best_mode(struct fb_var_screeninfo *var,
- struct list_head *head)
+const struct fb_videomode *fb_find_best_mode(const struct fb_var_screeninfo *var,
+ struct list_head *head)
{
struct list_head *pos;
struct fb_modelist *modelist;
@@ -808,8 +809,8 @@ struct fb_videomode *fb_find_best_mode(struct fb_var_screeninfo *var,
* If more than 1 videomode is found, will return the videomode with
* the closest refresh rate.
*/
-struct fb_videomode *fb_find_nearest_mode(struct fb_videomode *mode,
- struct list_head *head)
+const struct fb_videomode *fb_find_nearest_mode(const struct fb_videomode *mode,
+ struct list_head *head)
{
struct list_head *pos;
struct fb_modelist *modelist;
@@ -847,8 +848,8 @@ struct fb_videomode *fb_find_nearest_mode(struct fb_videomode *mode,
* RETURNS:
* struct fb_videomode, NULL if none found
*/
-struct fb_videomode *fb_match_mode(struct fb_var_screeninfo *var,
- struct list_head *head)
+const struct fb_videomode *fb_match_mode(const struct fb_var_screeninfo *var,
+ struct list_head *head)
{
struct list_head *pos;
struct fb_modelist *modelist;
@@ -872,7 +873,7 @@ struct fb_videomode *fb_match_mode(struct fb_var_screeninfo *var,
* NOTES:
* Will only add unmatched mode entries
*/
-int fb_add_videomode(struct fb_videomode *mode, struct list_head *head)
+int fb_add_videomode(const struct fb_videomode *mode, struct list_head *head)
{
struct list_head *pos;
struct fb_modelist *modelist;
@@ -907,7 +908,8 @@ int fb_add_videomode(struct fb_videomode *mode, struct list_head *head)
* NOTES:
* Will remove all matching mode entries
*/
-void fb_delete_videomode(struct fb_videomode *mode, struct list_head *head)
+void fb_delete_videomode(const struct fb_videomode *mode,
+ struct list_head *head)
{
struct list_head *pos, *n;
struct fb_modelist *modelist;
@@ -943,7 +945,7 @@ void fb_destroy_modelist(struct list_head *head)
* @num: number of entries in array
* @head: struct list_head of modelist
*/
-void fb_videomode_to_modelist(struct fb_videomode *modedb, int num,
+void fb_videomode_to_modelist(const struct fb_videomode *modedb, int num,
struct list_head *head)
{
int i;
@@ -956,12 +958,12 @@ void fb_videomode_to_modelist(struct fb_videomode *modedb, int num,
}
}
-struct fb_videomode *fb_find_best_display(struct fb_monspecs *specs,
- struct list_head *head)
+const struct fb_videomode *fb_find_best_display(const struct fb_monspecs *specs,
+ struct list_head *head)
{
struct list_head *pos;
struct fb_modelist *modelist;
- struct fb_videomode *m, *m1 = NULL, *md = NULL, *best = NULL;
+ const struct fb_videomode *m, *m1 = NULL, *md = NULL, *best = NULL;
int first = 0;
if (!head->prev || !head->next || list_empty(head))
diff --git a/drivers/video/neofb.c b/drivers/video/neofb.c
index deaf820cb38..395ccedde9a 100644
--- a/drivers/video/neofb.c
+++ b/drivers/video/neofb.c
@@ -66,7 +66,6 @@
#include <linux/init.h>
#ifdef CONFIG_TOSHIBA
#include <linux/toshiba.h>
-extern int tosh_smm(SMMRegisters *regs);
#endif
#include <asm/io.h>
@@ -557,14 +556,16 @@ static int
neofb_open(struct fb_info *info, int user)
{
struct neofb_par *par = info->par;
- int cnt = atomic_read(&par->ref_count);
- if (!cnt) {
+ mutex_lock(&par->open_lock);
+ if (!par->ref_count) {
memset(&par->state, 0, sizeof(struct vgastate));
par->state.flags = VGA_SAVE_MODE | VGA_SAVE_FONTS;
save_vga(&par->state);
}
- atomic_inc(&par->ref_count);
+ par->ref_count++;
+ mutex_unlock(&par->open_lock);
+
return 0;
}
@@ -572,14 +573,18 @@ static int
neofb_release(struct fb_info *info, int user)
{
struct neofb_par *par = info->par;
- int cnt = atomic_read(&par->ref_count);
- if (!cnt)
+ mutex_lock(&par->open_lock);
+ if (!par->ref_count) {
+ mutex_unlock(&par->open_lock);
return -EINVAL;
- if (cnt == 1) {
+ }
+ if (par->ref_count == 1) {
restore_vga(&par->state);
}
- atomic_dec(&par->ref_count);
+ par->ref_count--;
+ mutex_unlock(&par->open_lock);
+
return 0;
}
@@ -2048,6 +2053,7 @@ static struct fb_info *__devinit neo_alloc_fb_info(struct pci_dev *dev, const st
info->fix.accel = id->driver_data;
+ mutex_init(&par->open_lock);
par->pci_burst = !nopciburst;
par->lcd_stretch = !nostretch;
par->libretto = libretto;
diff --git a/drivers/video/nvidia/nv_backlight.c b/drivers/video/nvidia/nv_backlight.c
index df934bd2189..b7016e9b9e1 100644
--- a/drivers/video/nvidia/nv_backlight.c
+++ b/drivers/video/nvidia/nv_backlight.c
@@ -16,11 +16,6 @@
#include "nv_type.h"
#include "nv_proto.h"
-#ifdef CONFIG_PMAC_BACKLIGHT
-#include <asm/backlight.h>
-#include <asm/machdep.h>
-#endif
-
/* We do not have any information about which values are allowed, thus
* we used safe values.
*/
@@ -30,7 +25,6 @@
static struct backlight_properties nvidia_bl_data;
-/* Call with fb_info->bl_mutex held */
static int nvidia_bl_get_level_brightness(struct nvidia_par *par,
int level)
{
@@ -38,6 +32,7 @@ static int nvidia_bl_get_level_brightness(struct nvidia_par *par,
int nlevel;
/* Get and convert the value */
+ /* No locking of bl_curve since we read a single value */
nlevel = MIN_LEVEL + info->bl_curve[level] * LEVEL_STEP;
if (nlevel < 0)
@@ -50,8 +45,7 @@ static int nvidia_bl_get_level_brightness(struct nvidia_par *par,
return nlevel;
}
-/* Call with fb_info->bl_mutex held */
-static int __nvidia_bl_update_status(struct backlight_device *bd)
+static int nvidia_bl_update_status(struct backlight_device *bd)
{
struct nvidia_par *par = class_get_devdata(&bd->class_dev);
u32 tmp_pcrt, tmp_pmc, fpcontrol;
@@ -60,11 +54,11 @@ static int __nvidia_bl_update_status(struct backlight_device *bd)
if (!par->FlatPanel)
return 0;
- if (bd->props->power != FB_BLANK_UNBLANK ||
- bd->props->fb_blank != FB_BLANK_UNBLANK)
+ if (bd->props.power != FB_BLANK_UNBLANK ||
+ bd->props.fb_blank != FB_BLANK_UNBLANK)
level = 0;
else
- level = bd->props->brightness;
+ level = bd->props.brightness;
tmp_pmc = NV_RD32(par->PMC, 0x10F0) & 0x0000FFFF;
tmp_pcrt = NV_RD32(par->PCRTC0, 0x081C) & 0xFFFFFFFC;
@@ -85,45 +79,16 @@ static int __nvidia_bl_update_status(struct backlight_device *bd)
return 0;
}
-static int nvidia_bl_update_status(struct backlight_device *bd)
-{
- struct nvidia_par *par = class_get_devdata(&bd->class_dev);
- struct fb_info *info = pci_get_drvdata(par->pci_dev);
- int ret;
-
- mutex_lock(&info->bl_mutex);
- ret = __nvidia_bl_update_status(bd);
- mutex_unlock(&info->bl_mutex);
-
- return ret;
-}
-
static int nvidia_bl_get_brightness(struct backlight_device *bd)
{
- return bd->props->brightness;
+ return bd->props.brightness;
}
-static struct backlight_properties nvidia_bl_data = {
- .owner = THIS_MODULE,
+static struct backlight_ops nvidia_bl_ops = {
.get_brightness = nvidia_bl_get_brightness,
.update_status = nvidia_bl_update_status,
- .max_brightness = (FB_BACKLIGHT_LEVELS - 1),
};
-void nvidia_bl_set_power(struct fb_info *info, int power)
-{
- mutex_lock(&info->bl_mutex);
-
- if (info->bl_dev) {
- down(&info->bl_dev->sem);
- info->bl_dev->props->power = power;
- __nvidia_bl_update_status(info->bl_dev);
- up(&info->bl_dev->sem);
- }
-
- mutex_unlock(&info->bl_mutex);
-}
-
void nvidia_bl_init(struct nvidia_par *par)
{
struct fb_info *info = pci_get_drvdata(par->pci_dev);
@@ -141,32 +106,22 @@ void nvidia_bl_init(struct nvidia_par *par)
snprintf(name, sizeof(name), "nvidiabl%d", info->node);
- bd = backlight_device_register(name, info->dev, par, &nvidia_bl_data);
+ bd = backlight_device_register(name, info->dev, par, &nvidia_bl_ops);
if (IS_ERR(bd)) {
info->bl_dev = NULL;
printk(KERN_WARNING "nvidia: Backlight registration failed\n");
goto error;
}
- mutex_lock(&info->bl_mutex);
info->bl_dev = bd;
fb_bl_default_curve(info, 0,
0x158 * FB_BACKLIGHT_MAX / MAX_LEVEL,
0x534 * FB_BACKLIGHT_MAX / MAX_LEVEL);
- mutex_unlock(&info->bl_mutex);
- down(&bd->sem);
- bd->props->brightness = nvidia_bl_data.max_brightness;
- bd->props->power = FB_BLANK_UNBLANK;
- bd->props->update_status(bd);
- up(&bd->sem);
-
-#ifdef CONFIG_PMAC_BACKLIGHT
- mutex_lock(&pmac_backlight_mutex);
- if (!pmac_backlight)
- pmac_backlight = bd;
- mutex_unlock(&pmac_backlight_mutex);
-#endif
+ bd->props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
+ bd->props.brightness = nvidia_bl_data.max_brightness;
+ bd->props.power = FB_BLANK_UNBLANK;
+ backlight_update_status(bd);
printk("nvidia: Backlight initialized (%s)\n", name);
@@ -179,25 +134,8 @@ error:
void nvidia_bl_exit(struct nvidia_par *par)
{
struct fb_info *info = pci_get_drvdata(par->pci_dev);
+ struct backlight_device *bd = info->bl_dev;
-#ifdef CONFIG_PMAC_BACKLIGHT
- mutex_lock(&pmac_backlight_mutex);
-#endif
-
- mutex_lock(&info->bl_mutex);
- if (info->bl_dev) {
-#ifdef CONFIG_PMAC_BACKLIGHT
- if (pmac_backlight == info->bl_dev)
- pmac_backlight = NULL;
-#endif
-
- backlight_device_unregister(info->bl_dev);
-
- printk("nvidia: Backlight unloaded\n");
- }
- mutex_unlock(&info->bl_mutex);
-
-#ifdef CONFIG_PMAC_BACKLIGHT
- mutex_unlock(&pmac_backlight_mutex);
-#endif
+ backlight_device_unregister(bd);
+ printk("nvidia: Backlight unloaded\n");
}
diff --git a/drivers/video/nvidia/nv_i2c.c b/drivers/video/nvidia/nv_i2c.c
index 8454adf2d17..b8588973e40 100644
--- a/drivers/video/nvidia/nv_i2c.c
+++ b/drivers/video/nvidia/nv_i2c.c
@@ -12,7 +12,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/fb.h>
diff --git a/drivers/video/nvidia/nv_of.c b/drivers/video/nvidia/nv_of.c
index 181875fe35c..163a774a1b3 100644
--- a/drivers/video/nvidia/nv_of.c
+++ b/drivers/video/nvidia/nv_of.c
@@ -12,7 +12,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/fb.h>
diff --git a/drivers/video/nvidia/nv_proto.h b/drivers/video/nvidia/nv_proto.h
index 43058d0cf5b..ff5c410355e 100644
--- a/drivers/video/nvidia/nv_proto.h
+++ b/drivers/video/nvidia/nv_proto.h
@@ -67,11 +67,9 @@ extern int nvidiafb_sync(struct fb_info *info);
#ifdef CONFIG_FB_NVIDIA_BACKLIGHT
extern void nvidia_bl_init(struct nvidia_par *par);
extern void nvidia_bl_exit(struct nvidia_par *par);
-extern void nvidia_bl_set_power(struct fb_info *info, int power);
#else
static inline void nvidia_bl_init(struct nvidia_par *par) {}
static inline void nvidia_bl_exit(struct nvidia_par *par) {}
-static inline void nvidia_bl_set_power(struct fb_info *info, int power) {}
#endif
#endif /* __NV_PROTO_H__ */
diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c
index 538e947610e..c18e9557ca3 100644
--- a/drivers/video/nvidia/nvidia.c
+++ b/drivers/video/nvidia/nvidia.c
@@ -829,7 +829,7 @@ static int nvidiafb_check_var(struct fb_var_screeninfo *var,
}
if (!mode_valid) {
- struct fb_videomode *mode;
+ const struct fb_videomode *mode;
mode = fb_find_best_mode(var, &info->modelist);
if (mode) {
@@ -938,8 +938,6 @@ static int nvidiafb_blank(int blank, struct fb_info *info)
NVWriteSeq(par, 0x01, tmp);
NVWriteCrtc(par, 0x1a, vesa);
- nvidia_bl_set_power(info, blank);
-
NVTRACE_LEAVE();
return 0;
@@ -1046,10 +1044,10 @@ static int __devinit nvidia_set_fbinfo(struct fb_info *info)
}
if (specs->modedb != NULL) {
- struct fb_videomode *modedb;
+ const struct fb_videomode *mode;
- modedb = fb_find_best_display(specs, &info->modelist);
- fb_videomode_to_var(&nvidiafb_default_var, modedb);
+ mode = fb_find_best_display(specs, &info->modelist);
+ fb_videomode_to_var(&nvidiafb_default_var, mode);
nvidiafb_default_var.bits_per_pixel = bpp;
} else if (par->fpWidth && par->fpHeight) {
char buf[16];
@@ -1205,13 +1203,11 @@ static int __devinit nvidiafb_probe(struct pci_dev *pd,
par = info->par;
par->pci_dev = pd;
- info->pixmap.addr = kmalloc(8 * 1024, GFP_KERNEL);
+ info->pixmap.addr = kzalloc(8 * 1024, GFP_KERNEL);
if (info->pixmap.addr == NULL)
goto err_out_kfree;
- memset(info->pixmap.addr, 0, 8 * 1024);
-
if (pci_enable_device(pd)) {
printk(KERN_ERR PFX "cannot enable PCI device\n");
goto err_out_enable;
@@ -1347,16 +1343,17 @@ err_out:
return -ENODEV;
}
-static void __exit nvidiafb_remove(struct pci_dev *pd)
+static void __devexit nvidiafb_remove(struct pci_dev *pd)
{
struct fb_info *info = pci_get_drvdata(pd);
struct nvidia_par *par = info->par;
NVTRACE_ENTER();
+ unregister_framebuffer(info);
+
nvidia_bl_exit(par);
- unregister_framebuffer(info);
#ifdef CONFIG_MTRR
if (par->mtrr.vram_valid)
mtrr_del(par->mtrr.vram, info->fix.smem_start,
@@ -1433,7 +1430,7 @@ static struct pci_driver nvidiafb_driver = {
.probe = nvidiafb_probe,
.suspend = nvidiafb_suspend,
.resume = nvidiafb_resume,
- .remove = __exit_p(nvidiafb_remove),
+ .remove = __devexit_p(nvidiafb_remove),
};
/* ------------------------------------------------------------------------- *
diff --git a/drivers/video/output.c b/drivers/video/output.c
new file mode 100644
index 00000000000..1473f2c892d
--- /dev/null
+++ b/drivers/video/output.c
@@ -0,0 +1,129 @@
+/*
+ * output.c - Display Output Switch driver
+ *
+ * Copyright (C) 2006 Luming Yu <luming.yu@intel.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/video_output.h>
+#include <linux/err.h>
+#include <linux/ctype.h>
+
+
+MODULE_DESCRIPTION("Display Output Switcher Lowlevel Control Abstraction");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Luming Yu <luming.yu@intel.com>");
+
+static ssize_t video_output_show_state(struct class_device *dev,char *buf)
+{
+ ssize_t ret_size = 0;
+ struct output_device *od = to_output_device(dev);
+ if (od->props)
+ ret_size = sprintf(buf,"%.8x\n",od->props->get_status(od));
+ return ret_size;
+}
+
+static ssize_t video_output_store_state(struct class_device *dev,
+ const char *buf,size_t count)
+{
+ char *endp;
+ struct output_device *od = to_output_device(dev);
+ int request_state = simple_strtoul(buf,&endp,0);
+ size_t size = endp - buf;
+
+ if (*endp && isspace(*endp))
+ size++;
+ if (size != count)
+ return -EINVAL;
+
+ if (od->props) {
+ od->request_state = request_state;
+ od->props->set_state(od);
+ }
+ return count;
+}
+
+static void video_output_class_release(struct class_device *dev)
+{
+ struct output_device *od = to_output_device(dev);
+ kfree(od);
+}
+
+static struct class_device_attribute video_output_attributes[] = {
+ __ATTR(state, 0644, video_output_show_state, video_output_store_state),
+ __ATTR_NULL,
+};
+
+static struct class video_output_class = {
+ .name = "video_output",
+ .release = video_output_class_release,
+ .class_dev_attrs = video_output_attributes,
+};
+
+struct output_device *video_output_register(const char *name,
+ struct device *dev,
+ void *devdata,
+ struct output_properties *op)
+{
+ struct output_device *new_dev;
+ int ret_code = 0;
+
+ new_dev = kzalloc(sizeof(struct output_device),GFP_KERNEL);
+ if (!new_dev) {
+ ret_code = -ENOMEM;
+ goto error_return;
+ }
+ new_dev->props = op;
+ new_dev->class_dev.class = &video_output_class;
+ new_dev->class_dev.dev = dev;
+ strlcpy(new_dev->class_dev.class_id,name,KOBJ_NAME_LEN);
+ class_set_devdata(&new_dev->class_dev,devdata);
+ ret_code = class_device_register(&new_dev->class_dev);
+ if (ret_code) {
+ kfree(new_dev);
+ goto error_return;
+ }
+ return new_dev;
+
+error_return:
+ return ERR_PTR(ret_code);
+}
+EXPORT_SYMBOL(video_output_register);
+
+void video_output_unregister(struct output_device *dev)
+{
+ if (!dev)
+ return;
+ class_device_unregister(&dev->class_dev);
+}
+EXPORT_SYMBOL(video_output_unregister);
+
+static void __exit video_output_class_exit(void)
+{
+ class_unregister(&video_output_class);
+}
+
+static int __init video_output_class_init(void)
+{
+ return class_register(&video_output_class);
+}
+
+postcore_initcall(video_output_class_init);
+module_exit(video_output_class_exit);
diff --git a/drivers/video/pm3fb.c b/drivers/video/pm3fb.c
index 1d81ef47efd..bd787e80177 100644
--- a/drivers/video/pm3fb.c
+++ b/drivers/video/pm3fb.c
@@ -3299,14 +3299,12 @@ static void pm3fb_detect(void)
fb_info[i].dev = NULL;
}
- dev =
- pci_find_device(PCI_VENDOR_ID_3DLABS,
+ dev = pci_get_device(PCI_VENDOR_ID_3DLABS,
PCI_DEVICE_ID_3DLABS_PERMEDIA3, dev);
for (i = 0; ((i < PM3_MAX_BOARD) && dev); i++) {
dev_array[i] = dev;
- dev =
- pci_find_device(PCI_VENDOR_ID_3DLABS,
+ dev = pci_get_device(PCI_VENDOR_ID_3DLABS,
PCI_DEVICE_ID_3DLABS_PERMEDIA3, dev);
}
@@ -3353,7 +3351,7 @@ static void pm3fb_detect(void)
/* now, initialize... or not */
for (i = 0; i < PM3_MAX_BOARD; i++) {
l_fb_info = &(fb_info[i]);
- if ((l_fb_info->dev) && (!disable[i])) { /* PCI device was found and not disabled by user */
+ if (l_fb_info->dev && !disable[i]) { /* PCI device was found and not disabled by user */
DPRINTK(2,
"found @%lx Vendor %lx Device %lx ; base @ : %lx - %lx - %lx - %lx - %lx - %lx, irq %ld\n",
(unsigned long) l_fb_info->dev,
@@ -3608,7 +3606,7 @@ int init_module(void)
pm3fb_init();
- return (0);
+ return 0;
}
void cleanup_module(void)
@@ -3619,23 +3617,18 @@ void cleanup_module(void)
struct pm3fb_info *l_fb_info;
for (i = 0; i < PM3_MAX_BOARD; i++) {
l_fb_info = &(fb_info[i]);
- if ((l_fb_info->dev != NULL)
- && (!(disable[l_fb_info->board_num]))) {
- if (l_fb_info->vIOBase !=
- (unsigned char *) -1) {
+ pci_dev_put(l_fb_info->dev);
+ if (l_fb_info->dev != NULL && !(disable[l_fb_info->board_num])) {
+ if (l_fb_info->vIOBase != (unsigned char *) -1) {
pm3fb_unmapIO(l_fb_info);
release_mem_region(l_fb_info->p_fb,
- l_fb_info->
- fb_size);
- release_mem_region(l_fb_info->
- pIOBase,
- PM3_REGS_SIZE);
+ l_fb_info->fb_size);
+ release_mem_region(l_fb_info->pIOBase,
+ PM3_REGS_SIZE);
}
- unregister_framebuffer(&l_fb_info->gen.
- info);
+ unregister_framebuffer(&l_fb_info->gen.info);
}
}
}
- return;
}
#endif /* MODULE */
diff --git a/drivers/video/pmag-aa-fb.c b/drivers/video/pmag-aa-fb.c
index 68ca3cc4077..a864438b600 100644
--- a/drivers/video/pmag-aa-fb.c
+++ b/drivers/video/pmag-aa-fb.c
@@ -24,7 +24,6 @@
*/
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/timer.h>
diff --git a/drivers/video/pmag-ba-fb.c b/drivers/video/pmag-ba-fb.c
index f5361cd8ccc..264d37243fa 100644
--- a/drivers/video/pmag-ba-fb.c
+++ b/drivers/video/pmag-ba-fb.c
@@ -15,7 +15,8 @@
* Michael Engel <engel@unix-ag.org>,
* Karsten Merker <merker@linuxtag.org> and
* Harald Koerfgen.
- * Copyright (c) 2005 Maciej W. Rozycki
+ * Copyright (c) 2005, 2006 Maciej W. Rozycki
+ * Copyright (c) 2005 James Simmons
*
* 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
@@ -28,26 +29,21 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/tc.h>
#include <linux/types.h>
#include <asm/io.h>
#include <asm/system.h>
-#include <asm/dec/tc.h>
-
#include <video/pmag-ba-fb.h>
struct pmagbafb_par {
- struct fb_info *next;
volatile void __iomem *mmio;
volatile u32 __iomem *dac;
- int slot;
};
-static struct fb_info *root_pmagbafb_dev;
-
static struct fb_var_screeninfo pmagbafb_defined __initdata = {
.xres = 1024,
.yres = 864,
@@ -145,24 +141,19 @@ static void __init pmagbafb_erase_cursor(struct fb_info *info)
}
-static int __init pmagbafb_init_one(int slot)
+static int __init pmagbafb_probe(struct device *dev)
{
+ struct tc_dev *tdev = to_tc_dev(dev);
+ resource_size_t start, len;
struct fb_info *info;
struct pmagbafb_par *par;
- unsigned long base_addr;
- info = framebuffer_alloc(sizeof(struct pmagbafb_par), NULL);
+ info = framebuffer_alloc(sizeof(struct pmagbafb_par), dev);
if (!info)
return -ENOMEM;
par = info->par;
- par->slot = slot;
- claim_tc_card(par->slot);
-
- base_addr = get_tc_base_addr(par->slot);
-
- par->next = root_pmagbafb_dev;
- root_pmagbafb_dev = info;
+ dev_set_drvdata(dev, info);
if (fb_alloc_cmap(&info->cmap, 256, 0) < 0)
goto err_alloc;
@@ -172,15 +163,21 @@ static int __init pmagbafb_init_one(int slot)
info->var = pmagbafb_defined;
info->flags = FBINFO_DEFAULT;
+ /* Request the I/O MEM resource. */
+ start = tdev->resource.start;
+ len = tdev->resource.end - start + 1;
+ if (!request_mem_region(start, len, dev->bus_id))
+ goto err_cmap;
+
/* MMIO mapping setup. */
- info->fix.mmio_start = base_addr;
+ info->fix.mmio_start = start;
par->mmio = ioremap_nocache(info->fix.mmio_start, info->fix.mmio_len);
if (!par->mmio)
- goto err_cmap;
+ goto err_resource;
par->dac = par->mmio + PMAG_BA_BT459;
/* Frame buffer mapping setup. */
- info->fix.smem_start = base_addr + PMAG_BA_FBMEM;
+ info->fix.smem_start = start + PMAG_BA_FBMEM;
info->screen_base = ioremap_nocache(info->fix.smem_start,
info->fix.smem_len);
if (!info->screen_base)
@@ -192,8 +189,10 @@ static int __init pmagbafb_init_one(int slot)
if (register_framebuffer(info) < 0)
goto err_smem_map;
- pr_info("fb%d: %s frame buffer device in slot %d\n",
- info->node, info->fix.id, par->slot);
+ get_device(dev);
+
+ pr_info("fb%d: %s frame buffer device at %s\n",
+ info->node, info->fix.id, dev->bus_id);
return 0;
@@ -204,54 +203,68 @@ err_smem_map:
err_mmio_map:
iounmap(par->mmio);
+err_resource:
+ release_mem_region(start, len);
+
err_cmap:
fb_dealloc_cmap(&info->cmap);
err_alloc:
- root_pmagbafb_dev = par->next;
- release_tc_card(par->slot);
framebuffer_release(info);
return -ENXIO;
}
-static void __exit pmagbafb_exit_one(void)
+static int __exit pmagbafb_remove(struct device *dev)
{
- struct fb_info *info = root_pmagbafb_dev;
+ struct tc_dev *tdev = to_tc_dev(dev);
+ struct fb_info *info = dev_get_drvdata(dev);
struct pmagbafb_par *par = info->par;
+ resource_size_t start, len;
+ put_device(dev);
unregister_framebuffer(info);
iounmap(info->screen_base);
iounmap(par->mmio);
+ start = tdev->resource.start;
+ len = tdev->resource.end - start + 1;
+ release_mem_region(start, len);
fb_dealloc_cmap(&info->cmap);
- root_pmagbafb_dev = par->next;
- release_tc_card(par->slot);
framebuffer_release(info);
+ return 0;
}
/*
- * Initialise the framebuffer.
+ * Initialize the framebuffer.
*/
+static const struct tc_device_id pmagbafb_tc_table[] = {
+ { "DEC ", "PMAG-BA " },
+ { }
+};
+MODULE_DEVICE_TABLE(tc, pmagbafb_tc_table);
+
+static struct tc_driver pmagbafb_driver = {
+ .id_table = pmagbafb_tc_table,
+ .driver = {
+ .name = "pmagbafb",
+ .bus = &tc_bus_type,
+ .probe = pmagbafb_probe,
+ .remove = __exit_p(pmagbafb_remove),
+ },
+};
+
static int __init pmagbafb_init(void)
{
- int count = 0;
- int slot;
-
+#ifndef MODULE
if (fb_get_options("pmagbafb", NULL))
return -ENXIO;
-
- while ((slot = search_tc_card("PMAG-BA")) >= 0) {
- if (pmagbafb_init_one(slot) < 0)
- break;
- count++;
- }
- return (count > 0) ? 0 : -ENXIO;
+#endif
+ return tc_register_driver(&pmagbafb_driver);
}
static void __exit pmagbafb_exit(void)
{
- while (root_pmagbafb_dev)
- pmagbafb_exit_one();
+ tc_unregister_driver(&pmagbafb_driver);
}
diff --git a/drivers/video/pmagb-b-fb.c b/drivers/video/pmagb-b-fb.c
index a06a064ad75..7a0ce7d5af6 100644
--- a/drivers/video/pmagb-b-fb.c
+++ b/drivers/video/pmagb-b-fb.c
@@ -11,7 +11,7 @@
* Michael Engel <engel@unix-ag.org>,
* Karsten Merker <merker@linuxtag.org> and
* Harald Koerfgen.
- * Copyright (c) 2005 Maciej W. Rozycki
+ * Copyright (c) 2005, 2006 Maciej W. Rozycki
*
* 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
@@ -25,18 +25,16 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/tc.h>
#include <linux/types.h>
#include <asm/io.h>
#include <asm/system.h>
-#include <asm/dec/tc.h>
-
#include <video/pmagb-b-fb.h>
struct pmagbbfb_par {
- struct fb_info *next;
volatile void __iomem *mmio;
volatile void __iomem *smem;
volatile u32 __iomem *sfb;
@@ -47,8 +45,6 @@ struct pmagbbfb_par {
};
-static struct fb_info *root_pmagbbfb_dev;
-
static struct fb_var_screeninfo pmagbbfb_defined __initdata = {
.bits_per_pixel = 8,
.red.length = 8,
@@ -190,8 +186,9 @@ static void __init pmagbbfb_osc_setup(struct fb_info *info)
69197, 66000, 65000, 50350, 36000, 32000, 25175
};
struct pmagbbfb_par *par = info->par;
+ struct tc_bus *tbus = to_tc_dev(info->device)->bus;
u32 count0 = 8, count1 = 8, counttc = 16 * 256 + 8;
- u32 freq0, freq1, freqtc = get_tc_speed() / 250;
+ u32 freq0, freq1, freqtc = tc_get_speed(tbus) / 250;
int i, j;
gp0_write(par, 0); /* select Osc0 */
@@ -249,26 +246,21 @@ static void __init pmagbbfb_osc_setup(struct fb_info *info)
};
-static int __init pmagbbfb_init_one(int slot)
+static int __init pmagbbfb_probe(struct device *dev)
{
- char freq0[12], freq1[12];
+ struct tc_dev *tdev = to_tc_dev(dev);
+ resource_size_t start, len;
struct fb_info *info;
struct pmagbbfb_par *par;
- unsigned long base_addr;
+ char freq0[12], freq1[12];
u32 vid_base;
- info = framebuffer_alloc(sizeof(struct pmagbbfb_par), NULL);
+ info = framebuffer_alloc(sizeof(struct pmagbbfb_par), dev);
if (!info)
return -ENOMEM;
par = info->par;
- par->slot = slot;
- claim_tc_card(par->slot);
-
- base_addr = get_tc_base_addr(par->slot);
-
- par->next = root_pmagbbfb_dev;
- root_pmagbbfb_dev = info;
+ dev_set_drvdata(dev, info);
if (fb_alloc_cmap(&info->cmap, 256, 0) < 0)
goto err_alloc;
@@ -278,16 +270,22 @@ static int __init pmagbbfb_init_one(int slot)
info->var = pmagbbfb_defined;
info->flags = FBINFO_DEFAULT;
+ /* Request the I/O MEM resource. */
+ start = tdev->resource.start;
+ len = tdev->resource.end - start + 1;
+ if (!request_mem_region(start, len, dev->bus_id))
+ goto err_cmap;
+
/* MMIO mapping setup. */
- info->fix.mmio_start = base_addr;
+ info->fix.mmio_start = start;
par->mmio = ioremap_nocache(info->fix.mmio_start, info->fix.mmio_len);
if (!par->mmio)
- goto err_cmap;
+ goto err_resource;
par->sfb = par->mmio + PMAGB_B_SFB;
par->dac = par->mmio + PMAGB_B_BT459;
/* Frame buffer mapping setup. */
- info->fix.smem_start = base_addr + PMAGB_B_FBMEM;
+ info->fix.smem_start = start + PMAGB_B_FBMEM;
par->smem = ioremap_nocache(info->fix.smem_start, info->fix.smem_len);
if (!par->smem)
goto err_mmio_map;
@@ -302,13 +300,15 @@ static int __init pmagbbfb_init_one(int slot)
if (register_framebuffer(info) < 0)
goto err_smem_map;
+ get_device(dev);
+
snprintf(freq0, sizeof(freq0), "%u.%03uMHz",
par->osc0 / 1000, par->osc0 % 1000);
snprintf(freq1, sizeof(freq1), "%u.%03uMHz",
par->osc1 / 1000, par->osc1 % 1000);
- pr_info("fb%d: %s frame buffer device in slot %d\n",
- info->node, info->fix.id, par->slot);
+ pr_info("fb%d: %s frame buffer device at %s\n",
+ info->node, info->fix.id, dev->bus_id);
pr_info("fb%d: Osc0: %s, Osc1: %s, Osc%u selected\n",
info->node, freq0, par->osc1 ? freq1 : "disabled",
par->osc1 != 0);
@@ -322,54 +322,68 @@ err_smem_map:
err_mmio_map:
iounmap(par->mmio);
+err_resource:
+ release_mem_region(start, len);
+
err_cmap:
fb_dealloc_cmap(&info->cmap);
err_alloc:
- root_pmagbbfb_dev = par->next;
- release_tc_card(par->slot);
framebuffer_release(info);
return -ENXIO;
}
-static void __exit pmagbbfb_exit_one(void)
+static int __exit pmagbbfb_remove(struct device *dev)
{
- struct fb_info *info = root_pmagbbfb_dev;
+ struct tc_dev *tdev = to_tc_dev(dev);
+ struct fb_info *info = dev_get_drvdata(dev);
struct pmagbbfb_par *par = info->par;
+ resource_size_t start, len;
+ put_device(dev);
unregister_framebuffer(info);
iounmap(par->smem);
iounmap(par->mmio);
+ start = tdev->resource.start;
+ len = tdev->resource.end - start + 1;
+ release_mem_region(start, len);
fb_dealloc_cmap(&info->cmap);
- root_pmagbbfb_dev = par->next;
- release_tc_card(par->slot);
framebuffer_release(info);
+ return 0;
}
/*
- * Initialise the framebuffer.
+ * Initialize the framebuffer.
*/
+static const struct tc_device_id pmagbbfb_tc_table[] = {
+ { "DEC ", "PMAGB-BA" },
+ { }
+};
+MODULE_DEVICE_TABLE(tc, pmagbbfb_tc_table);
+
+static struct tc_driver pmagbbfb_driver = {
+ .id_table = pmagbbfb_tc_table,
+ .driver = {
+ .name = "pmagbbfb",
+ .bus = &tc_bus_type,
+ .probe = pmagbbfb_probe,
+ .remove = __exit_p(pmagbbfb_remove),
+ },
+};
+
static int __init pmagbbfb_init(void)
{
- int count = 0;
- int slot;
-
+#ifndef MODULE
if (fb_get_options("pmagbbfb", NULL))
return -ENXIO;
-
- while ((slot = search_tc_card("PMAGB-BA")) >= 0) {
- if (pmagbbfb_init_one(slot) < 0)
- break;
- count++;
- }
- return (count > 0) ? 0 : -ENXIO;
+#endif
+ return tc_register_driver(&pmagbbfb_driver);
}
static void __exit pmagbbfb_exit(void)
{
- while (root_pmagbbfb_dev)
- pmagbbfb_exit_one();
+ tc_unregister_driver(&pmagbbfb_driver);
}
diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c
new file mode 100644
index 00000000000..81e43cda7d8
--- /dev/null
+++ b/drivers/video/ps3fb.c
@@ -0,0 +1,1229 @@
+/*
+ * linux/drivers/video/ps3fb.c -- PS3 GPU frame buffer device
+ *
+ * Copyright (C) 2006 Sony Computer Entertainment Inc.
+ * Copyright 2006, 2007 Sony Corporation
+ *
+ * This file is based on :
+ *
+ * linux/drivers/video/vfb.c -- Virtual frame buffer device
+ *
+ * Copyright (C) 2002 James Simmons
+ *
+ * Copyright (C) 1997 Geert Uytterhoeven
+ *
+ * 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.
+ */
+
+#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/vmalloc.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/console.h>
+#include <linux/ioctl.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+
+#include <asm/uaccess.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <asm/time.h>
+
+#include <asm/abs_addr.h>
+#include <asm/lv1call.h>
+#include <asm/ps3av.h>
+#include <asm/ps3fb.h>
+#include <asm/ps3.h>
+
+#ifdef PS3FB_DEBUG
+#define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ##args)
+#else
+#define DPRINTK(fmt, args...)
+#endif
+
+#define L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC 0x101
+#define L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP 0x102
+#define L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP 0x600
+#define L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT 0x601
+#define L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT_SYNC 0x602
+
+#define L1GPU_FB_BLIT_WAIT_FOR_COMPLETION (1ULL << 32)
+
+#define L1GPU_DISPLAY_SYNC_HSYNC 1
+#define L1GPU_DISPLAY_SYNC_VSYNC 2
+
+#define DDR_SIZE (0) /* used no ddr */
+#define GPU_OFFSET (64 * 1024)
+#define GPU_IOIF (0x0d000000UL)
+
+#define PS3FB_FULL_MODE_BIT 0x80
+
+#define GPU_INTR_STATUS_VSYNC_0 0 /* vsync on head A */
+#define GPU_INTR_STATUS_VSYNC_1 1 /* vsync on head B */
+#define GPU_INTR_STATUS_FLIP_0 3 /* flip head A */
+#define GPU_INTR_STATUS_FLIP_1 4 /* flip head B */
+#define GPU_INTR_STATUS_QUEUE_0 5 /* queue head A */
+#define GPU_INTR_STATUS_QUEUE_1 6 /* queue head B */
+
+#define GPU_DRIVER_INFO_VERSION 0x211
+
+/* gpu internals */
+struct display_head {
+ u64 be_time_stamp;
+ u32 status;
+ u32 offset;
+ u32 res1;
+ u32 res2;
+ u32 field;
+ u32 reserved1;
+
+ u64 res3;
+ u32 raster;
+
+ u64 vblank_count;
+ u32 field_vsync;
+ u32 reserved2;
+};
+
+struct gpu_irq {
+ u32 irq_outlet;
+ u32 status;
+ u32 mask;
+ u32 video_cause;
+ u32 graph_cause;
+ u32 user_cause;
+
+ u32 res1;
+ u64 res2;
+
+ u32 reserved[4];
+};
+
+struct gpu_driver_info {
+ u32 version_driver;
+ u32 version_gpu;
+ u32 memory_size;
+ u32 hardware_channel;
+
+ u32 nvcore_frequency;
+ u32 memory_frequency;
+
+ u32 reserved[1063];
+ struct display_head display_head[8];
+ struct gpu_irq irq;
+};
+
+struct ps3fb_priv {
+ unsigned int irq_no;
+ void *dev;
+
+ u64 context_handle, memory_handle;
+ void *xdr_ea;
+ struct gpu_driver_info *dinfo;
+ struct semaphore sem;
+ u32 res_index;
+
+ u64 vblank_count; /* frame count */
+ wait_queue_head_t wait_vsync;
+
+ u32 num_frames; /* num of frame buffers */
+ atomic_t ext_flip; /* on/off flip with vsync */
+ atomic_t f_count; /* fb_open count */
+ int is_blanked;
+};
+static struct ps3fb_priv ps3fb;
+
+struct ps3fb_res_table {
+ u32 xres;
+ u32 yres;
+ u32 xoff;
+ u32 yoff;
+ u32 type;
+};
+#define PS3FB_RES_FULL 1
+static const struct ps3fb_res_table ps3fb_res[] = {
+ /* res_x,y margin_x,y full */
+ { 720, 480, 72, 48 , 0},
+ { 720, 576, 72, 58 , 0},
+ { 1280, 720, 78, 38 , 0},
+ { 1920, 1080, 116, 58 , 0},
+ /* full mode */
+ { 720, 480, 0, 0 , PS3FB_RES_FULL},
+ { 720, 576, 0, 0 , PS3FB_RES_FULL},
+ { 1280, 720, 0, 0 , PS3FB_RES_FULL},
+ { 1920, 1080, 0, 0 , PS3FB_RES_FULL},
+ /* vesa: normally full mode */
+ { 1280, 768, 0, 0 , 0},
+ { 1280, 1024, 0, 0 , 0},
+ { 1920, 1200, 0, 0 , 0},
+ { 0, 0, 0, 0 , 0} };
+
+/* default resolution */
+#define GPU_RES_INDEX 0 /* 720 x 480 */
+
+static const struct fb_videomode ps3fb_modedb[] = {
+ /* 60 Hz broadcast modes (modes "1" to "5") */
+ {
+ /* 480i */
+ "480i", 60, 576, 384, 74074, 130, 89, 78, 57, 63, 6,
+ FB_SYNC_BROADCAST, FB_VMODE_INTERLACED
+ }, {
+ /* 480p */
+ "480p", 60, 576, 384, 37037, 130, 89, 78, 57, 63, 6,
+ FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
+ }, {
+ /* 720p */
+ "720p", 60, 1124, 644, 13481, 298, 148, 57, 44, 80, 5,
+ FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
+ }, {
+ /* 1080i */
+ "1080i", 60, 1688, 964, 13481, 264, 160, 94, 62, 88, 5,
+ FB_SYNC_BROADCAST, FB_VMODE_INTERLACED
+ }, {
+ /* 1080p */
+ "1080p", 60, 1688, 964, 6741, 264, 160, 94, 62, 88, 5,
+ FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
+ },
+
+ /* 50 Hz broadcast modes (modes "6" to "10") */
+ {
+ /* 576i */
+ "576i", 50, 576, 460, 74074, 142, 83, 97, 63, 63, 5,
+ FB_SYNC_BROADCAST, FB_VMODE_INTERLACED
+ }, {
+ /* 576p */
+ "576p", 50, 576, 460, 37037, 142, 83, 97, 63, 63, 5,
+ FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
+ }, {
+ /* 720p */
+ "720p", 50, 1124, 644, 13468, 298, 478, 57, 44, 80, 5,
+ FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
+ }, {
+ /* 1080 */
+ "1080i", 50, 1688, 964, 13468, 264, 600, 94, 62, 88, 5,
+ FB_SYNC_BROADCAST, FB_VMODE_INTERLACED
+ }, {
+ /* 1080p */
+ "1080p", 50, 1688, 964, 6734, 264, 600, 94, 62, 88, 5,
+ FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
+ },
+
+ /* VESA modes (modes "11" to "13") */
+ {
+ /* WXGA */
+ "wxga", 60, 1280, 768, 12924, 160, 24, 29, 3, 136, 6,
+ 0, FB_VMODE_NONINTERLACED,
+ FB_MODE_IS_VESA
+ }, {
+ /* SXGA */
+ "sxga", 60, 1280, 1024, 9259, 248, 48, 38, 1, 112, 3,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED,
+ FB_MODE_IS_VESA
+ }, {
+ /* WUXGA */
+ "wuxga", 60, 1920, 1200, 6494, 80, 48, 26, 3, 32, 6,
+ FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED,
+ FB_MODE_IS_VESA
+ },
+
+ /* 60 Hz broadcast modes (full resolution versions of modes "1" to "5") */
+ {
+ /* 480if */
+ "480if", 60, 720, 480, 74074, 58, 17, 30, 9, 63, 6,
+ FB_SYNC_BROADCAST, FB_VMODE_INTERLACED
+ }, {
+ /* 480pf */
+ "480pf", 60, 720, 480, 37037, 58, 17, 30, 9, 63, 6,
+ FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
+ }, {
+ /* 720pf */
+ "720pf", 60, 1280, 720, 13481, 220, 70, 19, 6, 80, 5,
+ FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
+ }, {
+ /* 1080if */
+ "1080if", 60, 1920, 1080, 13481, 148, 44, 36, 4, 88, 5,
+ FB_SYNC_BROADCAST, FB_VMODE_INTERLACED
+ }, {
+ /* 1080pf */
+ "1080pf", 60, 1920, 1080, 6741, 148, 44, 36, 4, 88, 5,
+ FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
+ },
+
+ /* 50 Hz broadcast modes (full resolution versions of modes "6" to "10") */
+ {
+ /* 576if */
+ "576if", 50, 720, 576, 74074, 70, 11, 39, 5, 63, 5,
+ FB_SYNC_BROADCAST, FB_VMODE_INTERLACED
+ }, {
+ /* 576pf */
+ "576pf", 50, 720, 576, 37037, 70, 11, 39, 5, 63, 5,
+ FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
+ }, {
+ /* 720pf */
+ "720pf", 50, 1280, 720, 13468, 220, 400, 19, 6, 80, 5,
+ FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
+ }, {
+ /* 1080if */
+ "1080f", 50, 1920, 1080, 13468, 148, 484, 36, 4, 88, 5,
+ FB_SYNC_BROADCAST, FB_VMODE_INTERLACED
+ }, {
+ /* 1080pf */
+ "1080pf", 50, 1920, 1080, 6734, 148, 484, 36, 4, 88, 5,
+ FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
+ }
+};
+
+
+#define HEAD_A
+#define HEAD_B
+
+#define X_OFF(i) (ps3fb_res[i].xoff) /* left/right margin (pixel) */
+#define Y_OFF(i) (ps3fb_res[i].yoff) /* top/bottom margin (pixel) */
+#define WIDTH(i) (ps3fb_res[i].xres) /* width of FB */
+#define HEIGHT(i) (ps3fb_res[i].yres) /* height of FB */
+#define BPP 4 /* number of bytes per pixel */
+#define VP_OFF(i) (WIDTH(i) * Y_OFF(i) * BPP + X_OFF(i) * BPP)
+#define FB_OFF(i) (GPU_OFFSET - VP_OFF(i) % GPU_OFFSET)
+
+static int ps3fb_mode = 0;
+module_param(ps3fb_mode, bool, 0);
+
+static char *mode_option __initdata = NULL;
+
+
+static int ps3fb_get_res_table(u32 xres, u32 yres)
+{
+ int full_mode;
+ unsigned int i;
+ u32 x, y, f;
+
+ full_mode = (ps3fb_mode & PS3FB_FULL_MODE_BIT) ? PS3FB_RES_FULL : 0;
+ for (i = 0;; i++) {
+ x = ps3fb_res[i].xres;
+ y = ps3fb_res[i].yres;
+ f = ps3fb_res[i].type;
+
+ if (!x) {
+ DPRINTK("ERROR: ps3fb_get_res_table()\n");
+ return -1;
+ }
+
+ if (full_mode == PS3FB_RES_FULL && f != PS3FB_RES_FULL)
+ continue;
+
+ if (x == xres && (yres == 0 || y == yres))
+ break;
+
+ x = x - 2 * ps3fb_res[i].xoff;
+ y = y - 2 * ps3fb_res[i].yoff;
+ if (x == xres && (yres == 0 || y == yres))
+ break;
+ }
+ return i;
+}
+
+static unsigned int ps3fb_find_mode(const struct fb_var_screeninfo *var,
+ u32 *line_length)
+{
+ unsigned int i, mode;
+
+ for (i = 0; i < ARRAY_SIZE(ps3fb_modedb); i++)
+ if (var->xres == ps3fb_modedb[i].xres &&
+ var->yres == ps3fb_modedb[i].yres &&
+ var->pixclock == ps3fb_modedb[i].pixclock &&
+ var->hsync_len == ps3fb_modedb[i].hsync_len &&
+ var->vsync_len == ps3fb_modedb[i].vsync_len &&
+ var->left_margin == ps3fb_modedb[i].left_margin &&
+ var->right_margin == ps3fb_modedb[i].right_margin &&
+ var->upper_margin == ps3fb_modedb[i].upper_margin &&
+ var->lower_margin == ps3fb_modedb[i].lower_margin &&
+ var->sync == ps3fb_modedb[i].sync &&
+ (var->vmode & FB_VMODE_MASK) == ps3fb_modedb[i].vmode) {
+ /* Cropped broadcast modes use the full line_length */
+ *line_length =
+ ps3fb_modedb[i < 10 ? i + 13 : i].xres * 4;
+ /* Full broadcast modes have the full mode bit set */
+ mode = i > 12 ? (i - 12) | PS3FB_FULL_MODE_BIT : i + 1;
+
+ DPRINTK("ps3fb_find_mode: mode %u\n", mode);
+ return mode;
+ }
+
+ DPRINTK("ps3fb_find_mode: mode not found\n");
+ return 0;
+
+}
+
+static const struct fb_videomode *ps3fb_default_mode(void)
+{
+ u32 mode = ps3fb_mode & PS3AV_MODE_MASK;
+ u32 flags;
+
+ if (mode < 1 || mode > 13)
+ return NULL;
+
+ flags = ps3fb_mode & ~PS3AV_MODE_MASK;
+
+ if (mode <= 10 && flags & PS3FB_FULL_MODE_BIT) {
+ /* Full broadcast mode */
+ return &ps3fb_modedb[mode + 12];
+ }
+
+ return &ps3fb_modedb[mode - 1];
+}
+
+static int ps3fb_sync(u32 frame)
+{
+ int i, status;
+ u32 xres, yres;
+ u64 fb_ioif, offset;
+
+ i = ps3fb.res_index;
+ xres = ps3fb_res[i].xres;
+ yres = ps3fb_res[i].yres;
+
+ if (frame > ps3fb.num_frames - 1) {
+ printk(KERN_WARNING "%s: invalid frame number (%u)\n",
+ __FUNCTION__, frame);
+ return -EINVAL;
+ }
+ offset = xres * yres * BPP * frame;
+
+ fb_ioif = GPU_IOIF + FB_OFF(i) + offset;
+ status = lv1_gpu_context_attribute(ps3fb.context_handle,
+ L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT,
+ offset, fb_ioif,
+ L1GPU_FB_BLIT_WAIT_FOR_COMPLETION |
+ (xres << 16) | yres,
+ xres * BPP); /* line_length */
+ if (status)
+ printk(KERN_ERR "%s: lv1_gpu_context_attribute FB_BLIT failed: %d\n",
+ __FUNCTION__, status);
+#ifdef HEAD_A
+ status = lv1_gpu_context_attribute(ps3fb.context_handle,
+ L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP,
+ 0, offset, 0, 0);
+ if (status)
+ printk(KERN_ERR "%s: lv1_gpu_context_attribute FLIP failed: %d\n",
+ __FUNCTION__, status);
+#endif
+#ifdef HEAD_B
+ status = lv1_gpu_context_attribute(ps3fb.context_handle,
+ L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP,
+ 1, offset, 0, 0);
+ if (status)
+ printk(KERN_ERR "%s: lv1_gpu_context_attribute FLIP failed: %d\n",
+ __FUNCTION__, status);
+#endif
+ return 0;
+}
+
+
+static int ps3fb_open(struct fb_info *info, int user)
+{
+ atomic_inc(&ps3fb.f_count);
+ return 0;
+}
+
+static int ps3fb_release(struct fb_info *info, int user)
+{
+ if (atomic_dec_and_test(&ps3fb.f_count)) {
+ if (atomic_read(&ps3fb.ext_flip)) {
+ atomic_set(&ps3fb.ext_flip, 0);
+ ps3fb_sync(0); /* single buffer */
+ }
+ }
+ return 0;
+}
+
+ /*
+ * Setting the video mode has been split into two parts.
+ * First part, xxxfb_check_var, must not write anything
+ * to hardware, it should only verify and adjust var.
+ * This means it doesn't alter par but it does use hardware
+ * data from it to check this var.
+ */
+
+static int ps3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ u32 line_length;
+ int mode;
+ int i;
+
+ DPRINTK("var->xres:%u info->var.xres:%u\n", var->xres, info->var.xres);
+ DPRINTK("var->yres:%u info->var.yres:%u\n", var->yres, info->var.yres);
+
+ /* FIXME For now we do exact matches only */
+ mode = ps3fb_find_mode(var, &line_length);
+ if (!mode)
+ return -EINVAL;
+
+ /*
+ * FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal!
+ * as FB_VMODE_SMOOTH_XPAN is only used internally
+ */
+
+ if (var->vmode & FB_VMODE_CONUPDATE) {
+ var->vmode |= FB_VMODE_YWRAP;
+ var->xoffset = info->var.xoffset;
+ var->yoffset = info->var.yoffset;
+ }
+
+ /* Virtual screen and panning are not supported */
+ if (var->xres_virtual > var->xres || var->yres_virtual > var->yres ||
+ var->xoffset || var->yoffset) {
+ DPRINTK("Virtual screen and panning are not supported\n");
+ return -EINVAL;
+ }
+
+ var->xres_virtual = var->xres;
+ var->yres_virtual = var->yres;
+
+ /* We support ARGB8888 only */
+ if (var->bits_per_pixel > 32 || var->grayscale ||
+ var->red.offset > 16 || var->green.offset > 8 ||
+ var->blue.offset > 0 || var->transp.offset > 24 ||
+ var->red.length > 8 || var->green.length > 8 ||
+ var->blue.length > 8 || var->transp.length > 8 ||
+ var->red.msb_right || var->green.msb_right ||
+ var->blue.msb_right || var->transp.msb_right || var->nonstd) {
+ DPRINTK("We support ARGB8888 only\n");
+ return -EINVAL;
+ }
+
+ var->bits_per_pixel = 32;
+ var->red.offset = 16;
+ var->green.offset = 8;
+ var->blue.offset = 0;
+ var->transp.offset = 24;
+ var->red.length = 8;
+ var->green.length = 8;
+ var->blue.length = 8;
+ var->transp.length = 8;
+ var->red.msb_right = 0;
+ var->green.msb_right = 0;
+ var->blue.msb_right = 0;
+ var->transp.msb_right = 0;
+
+ /* Rotation is not supported */
+ if (var->rotate) {
+ DPRINTK("Rotation is not supported\n");
+ return -EINVAL;
+ }
+
+ /* Memory limit */
+ i = ps3fb_get_res_table(var->xres, var->yres);
+ if (ps3fb_res[i].xres*ps3fb_res[i].yres*BPP > ps3fb_videomemory.size) {
+ DPRINTK("Not enough memory\n");
+ return -ENOMEM;
+ }
+
+ var->height = -1;
+ var->width = -1;
+
+ return 0;
+}
+
+ /*
+ * This routine actually sets the video mode.
+ */
+
+static int ps3fb_set_par(struct fb_info *info)
+{
+ unsigned int mode;
+ int i;
+ unsigned long offset;
+ static int first = 1;
+
+ DPRINTK("xres:%d xv:%d yres:%d yv:%d clock:%d\n",
+ info->var.xres, info->var.xres_virtual,
+ info->var.yres, info->var.yres_virtual, info->var.pixclock);
+ i = ps3fb_get_res_table(info->var.xres, info->var.yres);
+ ps3fb.res_index = i;
+
+ mode = ps3fb_find_mode(&info->var, &info->fix.line_length);
+ if (!mode)
+ return -EINVAL;
+
+ offset = FB_OFF(i) + VP_OFF(i);
+ info->fix.smem_len = ps3fb_videomemory.size - offset;
+ info->screen_base = (char __iomem *)ps3fb.xdr_ea + offset;
+ memset(ps3fb.xdr_ea, 0, ps3fb_videomemory.size);
+
+ ps3fb.num_frames = ps3fb_videomemory.size/
+ (ps3fb_res[i].xres*ps3fb_res[i].yres*BPP);
+
+ /* Keep the special bits we cannot set using fb_var_screeninfo */
+ ps3fb_mode = (ps3fb_mode & ~PS3AV_MODE_MASK) | mode;
+
+ if (ps3av_set_video_mode(ps3fb_mode, first))
+ return -EINVAL;
+
+ first = 0;
+ return 0;
+}
+
+ /*
+ * 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.
+ */
+
+static int ps3fb_setcolreg(unsigned int regno, unsigned int red,
+ unsigned int green, unsigned int blue,
+ unsigned int transp, struct fb_info *info)
+{
+ if (regno >= 16)
+ return 1;
+
+ red >>= 8;
+ green >>= 8;
+ blue >>= 8;
+ transp >>= 8;
+
+ ((u32 *)info->pseudo_palette)[regno] = transp << 24 | red << 16 |
+ green << 8 | blue;
+ return 0;
+}
+
+ /*
+ * As we have a virtual frame buffer, we need our own mmap function
+ */
+
+static int ps3fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+ unsigned long size, offset;
+ int i;
+
+ i = ps3fb_get_res_table(info->var.xres, info->var.yres);
+ if (i == -1)
+ return -EINVAL;
+
+ size = vma->vm_end - vma->vm_start;
+ offset = vma->vm_pgoff << PAGE_SHIFT;
+ if (offset + size > info->fix.smem_len)
+ return -EINVAL;
+
+ offset += info->fix.smem_start + FB_OFF(i) + VP_OFF(i);
+ if (remap_pfn_range(vma, vma->vm_start, offset >> PAGE_SHIFT,
+ size, vma->vm_page_prot))
+ return -EAGAIN;
+
+ printk(KERN_DEBUG "ps3fb: mmap framebuffer P(%lx)->V(%lx)\n", offset,
+ vma->vm_start);
+ return 0;
+}
+
+ /*
+ * Blank the display
+ */
+
+static int ps3fb_blank(int blank, struct fb_info *info)
+{
+ int retval;
+
+ DPRINTK("%s: blank:%d\n", __FUNCTION__, blank);
+ switch (blank) {
+ case FB_BLANK_POWERDOWN:
+ case FB_BLANK_HSYNC_SUSPEND:
+ case FB_BLANK_VSYNC_SUSPEND:
+ case FB_BLANK_NORMAL:
+ retval = ps3av_video_mute(1); /* mute on */
+ if (!retval)
+ ps3fb.is_blanked = 1;
+ break;
+
+ default: /* unblank */
+ retval = ps3av_video_mute(0); /* mute off */
+ if (!retval)
+ ps3fb.is_blanked = 0;
+ break;
+ }
+ return retval;
+}
+
+static int ps3fb_get_vblank(struct fb_vblank *vblank)
+{
+ memset(vblank, 0, sizeof(&vblank));
+ vblank->flags = FB_VBLANK_HAVE_VSYNC;
+ return 0;
+}
+
+int ps3fb_wait_for_vsync(u32 crtc)
+{
+ int ret;
+ u64 count;
+
+ count = ps3fb.vblank_count;
+ ret = wait_event_interruptible_timeout(ps3fb.wait_vsync,
+ count != ps3fb.vblank_count,
+ HZ / 10);
+ if (!ret)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(ps3fb_wait_for_vsync);
+
+void ps3fb_flip_ctl(int on)
+{
+ if (on) {
+ if (atomic_read(&ps3fb.ext_flip) > 0) {
+ atomic_dec(&ps3fb.ext_flip);
+ }
+ } else {
+ atomic_inc(&ps3fb.ext_flip);
+ }
+}
+
+EXPORT_SYMBOL_GPL(ps3fb_flip_ctl);
+
+ /*
+ * ioctl
+ */
+
+static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd,
+ unsigned long arg)
+{
+ void __user *argp = (void __user *)arg;
+ u32 val, old_mode;
+ int retval = -EFAULT;
+
+ switch (cmd) {
+ case FBIOGET_VBLANK:
+ {
+ struct fb_vblank vblank;
+ DPRINTK("FBIOGET_VBLANK:\n");
+ retval = ps3fb_get_vblank(&vblank);
+ if (retval)
+ break;
+
+ if (copy_to_user(argp, &vblank, sizeof(vblank)))
+ retval = -EFAULT;
+ break;
+ }
+
+ case FBIO_WAITFORVSYNC:
+ {
+ u32 crt;
+ DPRINTK("FBIO_WAITFORVSYNC:\n");
+ if (get_user(crt, (u32 __user *) arg))
+ break;
+
+ retval = ps3fb_wait_for_vsync(crt);
+ break;
+ }
+
+ case PS3FB_IOCTL_SETMODE:
+ {
+ const struct fb_videomode *mode;
+ struct fb_var_screeninfo var;
+
+ if (copy_from_user(&val, argp, sizeof(val)))
+ break;
+
+ DPRINTK("PS3FB_IOCTL_SETMODE:%x\n", val);
+ retval = -EINVAL;
+ old_mode = ps3fb_mode;
+ ps3fb_mode = val;
+ mode = ps3fb_default_mode();
+ if (mode) {
+ var = info->var;
+ fb_videomode_to_var(&var, mode);
+ acquire_console_sem();
+ info->flags |= FBINFO_MISC_USEREVENT;
+ /* Force, in case only special bits changed */
+ var.activate |= FB_ACTIVATE_FORCE;
+ retval = fb_set_var(info, &var);
+ info->flags &= ~FBINFO_MISC_USEREVENT;
+ release_console_sem();
+ }
+ if (retval)
+ ps3fb_mode = old_mode;
+ break;
+ }
+
+ case PS3FB_IOCTL_GETMODE:
+ val = ps3av_get_mode();
+ DPRINTK("PS3FB_IOCTL_GETMODE:%x\n", val);
+ if (!copy_to_user(argp, &val, sizeof(val)))
+ retval = 0;
+ break;
+
+ case PS3FB_IOCTL_SCREENINFO:
+ {
+ struct ps3fb_ioctl_res res;
+ int i = ps3fb.res_index;
+ DPRINTK("PS3FB_IOCTL_SCREENINFO:\n");
+ res.xres = ps3fb_res[i].xres;
+ res.yres = ps3fb_res[i].yres;
+ res.xoff = ps3fb_res[i].xoff;
+ res.yoff = ps3fb_res[i].yoff;
+ res.num_frames = ps3fb.num_frames;
+ if (!copy_to_user(argp, &res, sizeof(res)))
+ retval = 0;
+ break;
+ }
+
+ case PS3FB_IOCTL_ON:
+ DPRINTK("PS3FB_IOCTL_ON:\n");
+ atomic_inc(&ps3fb.ext_flip);
+ retval = 0;
+ break;
+
+ case PS3FB_IOCTL_OFF:
+ DPRINTK("PS3FB_IOCTL_OFF:\n");
+ if (atomic_read(&ps3fb.ext_flip) > 0)
+ atomic_dec(&ps3fb.ext_flip);
+ retval = 0;
+ break;
+
+ case PS3FB_IOCTL_FSEL:
+ if (copy_from_user(&val, argp, sizeof(val)))
+ break;
+
+ DPRINTK("PS3FB_IOCTL_FSEL:%d\n", val);
+ retval = ps3fb_sync(val);
+ break;
+
+ default:
+ retval = -ENOIOCTLCMD;
+ break;
+ }
+ return retval;
+}
+
+static int ps3fbd(void *arg)
+{
+ daemonize("ps3fbd");
+ for (;;) {
+ down(&ps3fb.sem);
+ if (atomic_read(&ps3fb.ext_flip) == 0)
+ ps3fb_sync(0); /* single buffer */
+ }
+ return 0;
+}
+
+static irqreturn_t ps3fb_vsync_interrupt(int irq, void *ptr)
+{
+ u64 v1;
+ int status;
+ struct display_head *head = &ps3fb.dinfo->display_head[1];
+
+ status = lv1_gpu_context_intr(ps3fb.context_handle, &v1);
+ if (status) {
+ printk(KERN_ERR "%s: lv1_gpu_context_intr failed: %d\n",
+ __FUNCTION__, status);
+ return IRQ_NONE;
+ }
+
+ if (v1 & (1 << GPU_INTR_STATUS_VSYNC_1)) {
+ /* VSYNC */
+ ps3fb.vblank_count = head->vblank_count;
+ if (!ps3fb.is_blanked)
+ up(&ps3fb.sem);
+ wake_up_interruptible(&ps3fb.wait_vsync);
+ }
+
+ return IRQ_HANDLED;
+}
+
+#ifndef MODULE
+static int __init ps3fb_setup(char *options)
+{
+ char *this_opt;
+ int mode = 0;
+
+ if (!options || !*options)
+ return 0; /* no options */
+
+ while ((this_opt = strsep(&options, ",")) != NULL) {
+ if (!*this_opt)
+ continue;
+ if (!strncmp(this_opt, "mode:", 5))
+ mode = simple_strtoul(this_opt + 5, NULL, 0);
+ else
+ mode_option = this_opt;
+ }
+ return mode;
+}
+#endif /* MODULE */
+
+ /*
+ * Initialisation
+ */
+
+static void ps3fb_platform_release(struct device *device)
+{
+ /* This is called when the reference count goes to zero. */
+}
+
+static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo, void *dev)
+{
+ int error;
+
+ DPRINTK("version_driver:%x\n", dinfo->version_driver);
+ DPRINTK("irq outlet:%x\n", dinfo->irq.irq_outlet);
+ DPRINTK("version_gpu:%x memory_size:%x ch:%x core_freq:%d mem_freq:%d\n",
+ dinfo->version_gpu, dinfo->memory_size, dinfo->hardware_channel,
+ dinfo->nvcore_frequency/1000000, dinfo->memory_frequency/1000000);
+
+ if (dinfo->version_driver != GPU_DRIVER_INFO_VERSION) {
+ printk(KERN_ERR "%s: version_driver err:%x\n", __FUNCTION__,
+ dinfo->version_driver);
+ return -EINVAL;
+ }
+
+ ps3fb.dev = dev;
+ error = ps3_alloc_irq(PS3_BINDING_CPU_ANY, dinfo->irq.irq_outlet,
+ &ps3fb.irq_no);
+ if (error) {
+ printk(KERN_ERR "%s: ps3_alloc_irq failed %d\n", __FUNCTION__,
+ error);
+ return error;
+ }
+
+ error = request_irq(ps3fb.irq_no, ps3fb_vsync_interrupt, IRQF_DISABLED,
+ "ps3fb vsync", ps3fb.dev);
+ if (error) {
+ printk(KERN_ERR "%s: request_irq failed %d\n", __FUNCTION__,
+ error);
+ ps3_free_irq(ps3fb.irq_no);
+ return error;
+ }
+
+ dinfo->irq.mask = (1 << GPU_INTR_STATUS_VSYNC_1) |
+ (1 << GPU_INTR_STATUS_FLIP_1);
+ return 0;
+}
+
+static int ps3fb_xdr_settings(u64 xdr_lpar)
+{
+ int status;
+
+ status = lv1_gpu_context_iomap(ps3fb.context_handle, GPU_IOIF,
+ xdr_lpar, ps3fb_videomemory.size, 0);
+ if (status) {
+ printk(KERN_ERR "%s: lv1_gpu_context_iomap failed: %d\n",
+ __FUNCTION__, status);
+ return -ENXIO;
+ }
+ DPRINTK("video:%p xdr_ea:%p ioif:%lx lpar:%lx phys:%lx size:%lx\n",
+ ps3fb_videomemory.address, ps3fb.xdr_ea, GPU_IOIF, xdr_lpar,
+ virt_to_abs(ps3fb.xdr_ea), ps3fb_videomemory.size);
+
+ status = lv1_gpu_context_attribute(ps3fb.context_handle,
+ L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP,
+ xdr_lpar, ps3fb_videomemory.size,
+ GPU_IOIF, 0);
+ if (status) {
+ printk(KERN_ERR "%s: lv1_gpu_context_attribute FB_SETUP failed: %d\n",
+ __FUNCTION__, status);
+ return -ENXIO;
+ }
+ return 0;
+}
+
+static struct fb_ops ps3fb_ops = {
+ .fb_open = ps3fb_open,
+ .fb_release = ps3fb_release,
+ .fb_check_var = ps3fb_check_var,
+ .fb_set_par = ps3fb_set_par,
+ .fb_setcolreg = ps3fb_setcolreg,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+ .fb_mmap = ps3fb_mmap,
+ .fb_blank = ps3fb_blank,
+ .fb_ioctl = ps3fb_ioctl,
+ .fb_compat_ioctl = ps3fb_ioctl
+};
+
+static struct fb_fix_screeninfo ps3fb_fix __initdata = {
+ .id = "PS3 FB",
+ .type = FB_TYPE_PACKED_PIXELS,
+ .visual = FB_VISUAL_TRUECOLOR,
+ .accel = FB_ACCEL_NONE,
+};
+
+static int __init ps3fb_probe(struct platform_device *dev)
+{
+ struct fb_info *info;
+ int retval = -ENOMEM;
+ u64 ddr_lpar = 0;
+ u64 lpar_dma_control = 0;
+ u64 lpar_driver_info = 0;
+ u64 lpar_reports = 0;
+ u64 lpar_reports_size = 0;
+ u64 xdr_lpar;
+ int status;
+ unsigned long offset;
+
+ /* get gpu context handle */
+ status = lv1_gpu_memory_allocate(DDR_SIZE, 0, 0, 0, 0,
+ &ps3fb.memory_handle, &ddr_lpar);
+ if (status) {
+ printk(KERN_ERR "%s: lv1_gpu_memory_allocate failed: %d\n",
+ __FUNCTION__, status);
+ goto err;
+ }
+ DPRINTK("ddr:lpar:0x%lx\n", ddr_lpar);
+
+ status = lv1_gpu_context_allocate(ps3fb.memory_handle, 0,
+ &ps3fb.context_handle,
+ &lpar_dma_control, &lpar_driver_info,
+ &lpar_reports, &lpar_reports_size);
+ if (status) {
+ printk(KERN_ERR "%s: lv1_gpu_context_attribute failed: %d\n",
+ __FUNCTION__, status);
+ goto err_gpu_memory_free;
+ }
+
+ /* vsync interrupt */
+ ps3fb.dinfo = ioremap(lpar_driver_info, 128 * 1024);
+ if (!ps3fb.dinfo) {
+ printk(KERN_ERR "%s: ioremap failed\n", __FUNCTION__);
+ goto err_gpu_context_free;
+ }
+
+ retval = ps3fb_vsync_settings(ps3fb.dinfo, dev);
+ if (retval)
+ goto err_iounmap_dinfo;
+
+ /* xdr frame buffer */
+ ps3fb.xdr_ea = ps3fb_videomemory.address;
+ xdr_lpar = ps3_mm_phys_to_lpar(__pa(ps3fb.xdr_ea));
+ retval = ps3fb_xdr_settings(xdr_lpar);
+ if (retval)
+ goto err_free_irq;
+
+ /*
+ * ps3fb must clear memory to prevent kernel info
+ * leakage into userspace
+ */
+ memset(ps3fb.xdr_ea, 0, ps3fb_videomemory.size);
+ info = framebuffer_alloc(sizeof(u32) * 16, &dev->dev);
+ if (!info)
+ goto err_free_irq;
+
+ offset = FB_OFF(ps3fb.res_index) + VP_OFF(ps3fb.res_index);
+ info->screen_base = (char __iomem *)ps3fb.xdr_ea + offset;
+ info->fbops = &ps3fb_ops;
+
+ info->fix = ps3fb_fix;
+ info->fix.smem_start = virt_to_abs(ps3fb.xdr_ea);
+ info->fix.smem_len = ps3fb_videomemory.size - offset;
+ info->pseudo_palette = info->par;
+ info->par = NULL;
+ info->flags = FBINFO_FLAG_DEFAULT;
+
+ retval = fb_alloc_cmap(&info->cmap, 256, 0);
+ if (retval < 0)
+ goto err_framebuffer_release;
+
+ if (!fb_find_mode(&info->var, info, mode_option, ps3fb_modedb,
+ ARRAY_SIZE(ps3fb_modedb), ps3fb_default_mode(), 32)) {
+ retval = -EINVAL;
+ goto err_fb_dealloc;
+ }
+
+ fb_videomode_to_modelist(ps3fb_modedb, ARRAY_SIZE(ps3fb_modedb),
+ &info->modelist);
+
+ retval = register_framebuffer(info);
+ if (retval < 0)
+ goto err_fb_dealloc;
+
+ platform_set_drvdata(dev, info);
+
+ printk(KERN_INFO
+ "fb%d: PS3 frame buffer device, using %ld KiB of video memory\n",
+ info->node, ps3fb_videomemory.size >> 10);
+
+ kernel_thread(ps3fbd, info, CLONE_KERNEL);
+ return 0;
+
+err_fb_dealloc:
+ fb_dealloc_cmap(&info->cmap);
+err_framebuffer_release:
+ framebuffer_release(info);
+err_free_irq:
+ free_irq(ps3fb.irq_no, ps3fb.dev);
+ ps3_free_irq(ps3fb.irq_no);
+err_iounmap_dinfo:
+ iounmap((u8 __iomem *)ps3fb.dinfo);
+err_gpu_context_free:
+ lv1_gpu_context_free(ps3fb.context_handle);
+err_gpu_memory_free:
+ lv1_gpu_memory_free(ps3fb.memory_handle);
+err:
+ return retval;
+}
+
+static void ps3fb_shutdown(struct platform_device *dev)
+{
+ ps3fb_flip_ctl(0); /* flip off */
+ ps3fb.dinfo->irq.mask = 0;
+ free_irq(ps3fb.irq_no, ps3fb.dev);
+ ps3_free_irq(ps3fb.irq_no);
+ iounmap((u8 __iomem *)ps3fb.dinfo);
+}
+
+void ps3fb_cleanup(void)
+{
+ int status;
+
+ if (ps3fb.irq_no) {
+ free_irq(ps3fb.irq_no, ps3fb.dev);
+ ps3_free_irq(ps3fb.irq_no);
+ }
+ iounmap((u8 __iomem *)ps3fb.dinfo);
+
+ status = lv1_gpu_context_free(ps3fb.context_handle);
+ if (status)
+ DPRINTK("lv1_gpu_context_free failed: %d\n", status);
+
+ status = lv1_gpu_memory_free(ps3fb.memory_handle);
+ if (status)
+ DPRINTK("lv1_gpu_memory_free failed: %d\n", status);
+
+ ps3av_dev_close();
+}
+
+EXPORT_SYMBOL_GPL(ps3fb_cleanup);
+
+static int ps3fb_remove(struct platform_device *dev)
+{
+ struct fb_info *info = platform_get_drvdata(dev);
+
+ if (info) {
+ unregister_framebuffer(info);
+ fb_dealloc_cmap(&info->cmap);
+ framebuffer_release(info);
+ }
+ ps3fb_cleanup();
+ return 0;
+}
+
+static struct platform_driver ps3fb_driver = {
+ .probe = ps3fb_probe,
+ .remove = ps3fb_remove,
+ .shutdown = ps3fb_shutdown,
+ .driver = { .name = "ps3fb" }
+};
+
+static struct platform_device ps3fb_device = {
+ .name = "ps3fb",
+ .id = 0,
+ .dev = { .release = ps3fb_platform_release }
+};
+
+int ps3fb_set_sync(void)
+{
+ int status;
+
+#ifdef HEAD_A
+ status = lv1_gpu_context_attribute(0x0,
+ L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC,
+ 0, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0);
+ if (status) {
+ printk(KERN_ERR "%s: lv1_gpu_context_attribute DISPLAY_SYNC failed: %d\n",
+ __FUNCTION__, status);
+ return -1;
+ }
+#endif
+#ifdef HEAD_B
+ status = lv1_gpu_context_attribute(0x0,
+ L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC,
+ 1, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0);
+
+ if (status) {
+ printk(KERN_ERR "%s: lv1_gpu_context_attribute DISPLAY_MODE failed: %d\n",
+ __FUNCTION__, status);
+ return -1;
+ }
+#endif
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(ps3fb_set_sync);
+
+static int __init ps3fb_init(void)
+{
+ int error;
+#ifndef MODULE
+ int mode;
+ char *option = NULL;
+
+ if (fb_get_options("ps3fb", &option))
+ goto err;
+#endif
+
+ if (!ps3fb_videomemory.address)
+ goto err;
+
+ error = ps3av_dev_open();
+ if (error) {
+ printk(KERN_ERR "%s: ps3av_dev_open failed\n", __FUNCTION__);
+ goto err;
+ }
+
+ ps3fb_mode = ps3av_get_mode();
+ DPRINTK("ps3av_mode:%d\n", ps3fb_mode);
+#ifndef MODULE
+ mode = ps3fb_setup(option); /* check boot option */
+ if (mode)
+ ps3fb_mode = mode;
+#endif
+ if (ps3fb_mode > 0) {
+ u32 xres, yres;
+ ps3av_video_mode2res(ps3fb_mode, &xres, &yres);
+ ps3fb.res_index = ps3fb_get_res_table(xres, yres);
+ DPRINTK("res_index:%d\n", ps3fb.res_index);
+ } else
+ ps3fb.res_index = GPU_RES_INDEX;
+
+ atomic_set(&ps3fb.f_count, -1); /* fbcon opens ps3fb */
+ atomic_set(&ps3fb.ext_flip, 0); /* for flip with vsync */
+ init_MUTEX(&ps3fb.sem);
+ init_waitqueue_head(&ps3fb.wait_vsync);
+ ps3fb.num_frames = 1;
+
+ error = platform_driver_register(&ps3fb_driver);
+ if (!error) {
+ error = platform_device_register(&ps3fb_device);
+ if (error)
+ platform_driver_unregister(&ps3fb_driver);
+ }
+
+ ps3fb_set_sync();
+
+ return error;
+
+err:
+ return -ENXIO;
+}
+
+module_init(ps3fb_init);
+
+#ifdef MODULE
+static void __exit ps3fb_exit(void)
+{
+ platform_device_unregister(&ps3fb_device);
+ platform_driver_unregister(&ps3fb_driver);
+}
+
+module_exit(ps3fb_exit);
+
+MODULE_LICENSE("GPL");
+#endif /* MODULE */
diff --git a/drivers/video/retz3fb.c b/drivers/video/retz3fb.c
deleted file mode 100644
index bc7ffc84e18..00000000000
--- a/drivers/video/retz3fb.c
+++ /dev/null
@@ -1,1588 +0,0 @@
-/*
- * Linux/drivers/video/retz3fb.c -- RetinaZ3 frame buffer device
- *
- * Copyright (C) 1997 Jes Sorensen
- *
- * This file is based on the CyberVision64 frame buffer device and
- * the generic Cirrus Logic driver.
- *
- * cyberfb.c: Copyright (C) 1996 Martin Apel,
- * Geert Uytterhoeven
- * clgen.c: Copyright (C) 1996 Frank Neumann
- *
- * History:
- * - 22 Jan 97: Initial work
- * - 14 Feb 97: Screen initialization works somewhat, still only
- * 8-bit packed pixel is supported.
- *
- * 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.
- */
-
-#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/fb.h>
-#include <linux/zorro.h>
-#include <linux/init.h>
-
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <asm/irq.h>
-#include <asm/pgtable.h>
-#include <asm/io.h>
-
-#include <video/fbcon.h>
-#include <video/fbcon-cfb8.h>
-#include <video/fbcon-cfb16.h>
-
-#include "retz3fb.h"
-
-/* #define DEBUG if(1) */
-#define DEBUG if(0)
-
-/*
- * Reserve space for one pattern line.
- *
- * For the time being we only support 4MB boards!
- */
-
-#define PAT_MEM_SIZE 16*3
-#define PAT_MEM_OFF (4*1024*1024 - PAT_MEM_SIZE)
-
-struct retz3fb_par {
- int xres;
- int yres;
- int xres_vir;
- int yres_vir;
- int xoffset;
- int yoffset;
- int bpp;
-
- struct fb_bitfield red;
- struct fb_bitfield green;
- struct fb_bitfield blue;
- struct fb_bitfield transp;
-
- int pixclock;
- int left_margin; /* time from sync to picture */
- int right_margin; /* time from picture to sync */
- int upper_margin; /* time from sync to picture */
- int lower_margin;
- int hsync_len; /* length of horizontal sync */
- int vsync_len; /* length of vertical sync */
- int vmode;
-
- int accel;
-};
-
-struct display_data {
- long h_total; /* Horizontal Total */
- long h_sstart; /* Horizontal Sync Start */
- long h_sstop; /* Horizontal Sync Stop */
- long h_bstart; /* Horizontal Blank Start */
- long h_bstop; /* Horizontal Blank Stop */
- long h_dispend; /* Horizontal Display End */
- long v_total; /* Vertical Total */
- long v_sstart; /* Vertical Sync Start */
- long v_sstop; /* Vertical Sync Stop */
- long v_bstart; /* Vertical Blank Start */
- long v_bstop; /* Vertical Blank Stop */
- long v_dispend; /* Horizontal Display End */
-};
-
-struct retz3_fb_info {
- struct fb_info info;
- unsigned char *base;
- unsigned char *fbmem;
- unsigned long fbsize;
- volatile unsigned char *regs;
- unsigned long physfbmem;
- unsigned long physregs;
- int current_par_valid; /* set to 0 by memset */
- int blitbusy;
- struct display disp;
- struct retz3fb_par current_par;
- unsigned char color_table [256][3];
-};
-
-
-static char fontname[40] __initdata = { 0 };
-
-#define retz3info(info) ((struct retz3_fb_info *)(info))
-#define fbinfo(info) ((struct fb_info *)(info))
-
-
-/*
- * Frame Buffer Name
- */
-
-static char retz3fb_name[16] = "RetinaZ3";
-
-
-/*
- * A small info on how to convert XFree86 timing values into fb
- * timings - by Frank Neumann:
- *
-An XFree86 mode line consists of the following fields:
- "800x600" 50 800 856 976 1040 600 637 643 666
- < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL
-
-The fields in the fb_var_screeninfo structure are:
- unsigned long pixclock; * pixel clock in ps (pico seconds) *
- unsigned long left_margin; * time from sync to picture *
- unsigned long right_margin; * time from picture to sync *
- unsigned long upper_margin; * time from sync to picture *
- unsigned long lower_margin;
- unsigned long hsync_len; * length of horizontal sync *
- unsigned long vsync_len; * length of vertical sync *
-
-1) Pixelclock:
- xfree: in MHz
- fb: In Picoseconds (ps)
-
- pixclock = 1000000 / DCF
-
-2) horizontal timings:
- left_margin = HFL - SH2
- right_margin = SH1 - HR
- hsync_len = SH2 - SH1
-
-3) vertical timings:
- upper_margin = VFL - SV2
- lower_margin = SV1 - VR
- vsync_len = SV2 - SV1
-
-Good examples for VESA timings can be found in the XFree86 source tree,
-under "programs/Xserver/hw/xfree86/doc/modeDB.txt".
-*/
-
-/*
- * Predefined Video Modes
- */
-
-static struct {
- const char *name;
- struct fb_var_screeninfo var;
-} retz3fb_predefined[] __initdata = {
- /*
- * NB: it is very important to adjust the pixel-clock to the color-depth.
- */
-
- {
- "640x480", { /* 640x480, 8 bpp */
- 640, 480, 640, 480, 0, 0, 8, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_NONE, 39722, 48, 16, 33, 10, 96, 2,
- FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,FB_VMODE_NONINTERLACED
- }
- },
- /*
- ModeLine "800x600" 36 800 824 896 1024 600 601 603 625
- < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL
- */
- {
- "800x600", { /* 800x600, 8 bpp */
- 800, 600, 800, 600, 0, 0, 8, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 27778, 64, 24, 22, 1, 120, 2,
- FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
- }
- },
- {
- "800x600-60", { /* 800x600, 8 bpp */
- 800, 600, 800, 600, 0, 0, 8, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 25000, 88, 40, 23, 1, 128, 4,
- FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
- }
- },
- {
- "800x600-70", { /* 800x600, 8 bpp */
- 800, 600, 800, 600, 0, 0, 8, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 22272, 40, 24, 15, 9, 144, 12,
- FB_SYNC_COMP_HIGH_ACT, FB_VMODE_NONINTERLACED
- }
- },
- /*
- ModeLine "1024x768i" 45 1024 1064 1224 1264 768 777 785 817 interlace
- < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL
- */
- {
- "1024x768i", { /* 1024x768, 8 bpp, interlaced */
- 1024, 768, 1024, 768, 0, 0, 8, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 22222, 40, 40, 32, 9, 160, 8,
- FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_INTERLACED
- }
- },
- {
- "1024x768", {
- 1024, 768, 1024, 768, 0, 0, 8, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCEL_NONE, 12500, 92, 112, 31, 2, 204, 4,
- FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
- }
- },
- {
- "640x480-16", { /* 640x480, 16 bpp */
- 640, 480, 640, 480, 0, 0, 16, 0,
- {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
- 0, 0, -1, -1, 0, 38461/2, 28, 32, 12, 10, 96, 2,
- FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,FB_VMODE_NONINTERLACED
- }
- },
- {
- "640x480-24", { /* 640x480, 24 bpp */
- 640, 480, 640, 480, 0, 0, 24, 0,
- {8, 8, 8}, {8, 8, 8}, {8, 8, 8}, {0, 0, 0},
- 0, 0, -1, -1, 0, 38461/3, 28, 32, 12, 10, 96, 2,
- FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,FB_VMODE_NONINTERLACED
- }
- },
-};
-
-
-#define NUM_TOTAL_MODES ARRAY_SIZE(retz3fb_predefined)
-
-static struct fb_var_screeninfo retz3fb_default;
-
-static int z3fb_inverse = 0;
-static int z3fb_mode __initdata = 0;
-
-
-/*
- * Interface used by the world
- */
-
-int retz3fb_setup(char *options);
-
-static int retz3fb_get_fix(struct fb_fix_screeninfo *fix, int con,
- struct fb_info *info);
-static int retz3fb_get_var(struct fb_var_screeninfo *var, int con,
- struct fb_info *info);
-static int retz3fb_set_var(struct fb_var_screeninfo *var, int con,
- struct fb_info *info);
-static int retz3fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
- struct fb_info *info);
-static int retz3fb_setcolreg(unsigned int regno, unsigned int red,
- unsigned int green, unsigned int blue,
- unsigned int transp, struct fb_info *info);
-static int retz3fb_blank(int blank, struct fb_info *info);
-
-
-/*
- * Interface to the low level console driver
- */
-
-int retz3fb_init(void);
-static int z3fb_switch(int con, struct fb_info *info);
-static int z3fb_updatevar(int con, struct fb_info *info);
-
-
-/*
- * Text console acceleration
- */
-
-#ifdef FBCON_HAS_CFB8
-static struct display_switch fbcon_retz3_8;
-#endif
-
-
-/*
- * Accelerated Functions used by the low level console driver
- */
-
-static void retz3_bitblt(struct display *p,
- unsigned short curx, unsigned short cury, unsigned
- short destx, unsigned short desty, unsigned short
- width, unsigned short height, unsigned short cmd,
- unsigned short mask);
-
-/*
- * Hardware Specific Routines
- */
-
-static int retz3_encode_fix(struct fb_info *info,
- struct fb_fix_screeninfo *fix,
- struct retz3fb_par *par);
-static int retz3_decode_var(struct fb_var_screeninfo *var,
- struct retz3fb_par *par);
-static int retz3_encode_var(struct fb_var_screeninfo *var,
- struct retz3fb_par *par);
-static int retz3_getcolreg(unsigned int regno, unsigned int *red,
- unsigned int *green, unsigned int *blue,
- unsigned int *transp, struct fb_info *info);
-
-/*
- * Internal routines
- */
-
-static void retz3fb_get_par(struct fb_info *info, struct retz3fb_par *par);
-static void retz3fb_set_par(struct fb_info *info, struct retz3fb_par *par);
-static int do_fb_set_var(struct fb_info *info,
- struct fb_var_screeninfo *var, int isactive);
-static void retz3fb_set_disp(int con, struct fb_info *info);
-static int get_video_mode(const char *name);
-
-
-/* -------------------- Hardware specific routines ------------------------- */
-
-static unsigned short find_fq(unsigned int freq)
-{
- unsigned long f;
- long tmp;
- long prev = 0x7fffffff;
- long n2, n1 = 3;
- unsigned long m;
- unsigned short res = 0;
-
- if (freq <= 31250000)
- n2 = 3;
- else if (freq <= 62500000)
- n2 = 2;
- else if (freq <= 125000000)
- n2 = 1;
- else if (freq <= 250000000)
- n2 = 0;
- else
- return 0;
-
-
- do {
- f = freq >> (10 - n2);
-
- m = (f * n1) / (14318180/1024);
-
- if (m > 129)
- break;
-
- tmp = (((m * 14318180) >> n2) / n1) - freq;
- if (tmp < 0)
- tmp = -tmp;
-
- if (tmp < prev) {
- prev = tmp;
- res = (((n2 << 5) | (n1-2)) << 8) | (m-2);
- }
-
- } while ( (++n1) <= 21);
-
- return res;
-}
-
-
-static int retz3_set_video(struct fb_info *info,
- struct fb_var_screeninfo *var,
- struct retz3fb_par *par)
-{
- volatile unsigned char *regs = retz3info(info)->regs;
- unsigned int freq;
-
- int xres, hfront, hsync, hback;
- int yres, vfront, vsync, vback;
- unsigned char tmp;
- unsigned short best_freq;
- struct display_data data;
-
- short clocksel = 0; /* Apparantly this is always zero */
-
- int bpp = var->bits_per_pixel;
-
- /*
- * XXX
- */
- if (bpp == 24)
- return 0;
-
- if ((bpp != 8) && (bpp != 16) && (bpp != 24))
- return -EFAULT;
-
- par->xoffset = 0;
- par->yoffset = 0;
-
- xres = var->xres * bpp / 4;
- hfront = var->right_margin * bpp / 4;
- hsync = var->hsync_len * bpp / 4;
- hback = var->left_margin * bpp / 4;
-
- if (var->vmode & FB_VMODE_DOUBLE)
- {
- yres = var->yres * 2;
- vfront = var->lower_margin * 2;
- vsync = var->vsync_len * 2;
- vback = var->upper_margin * 2;
- }
- else if (var->vmode & FB_VMODE_INTERLACED)
- {
- yres = (var->yres + 1) / 2;
- vfront = (var->lower_margin + 1) / 2;
- vsync = (var->vsync_len + 1) / 2;
- vback = (var->upper_margin + 1) / 2;
- }
- else
- {
- yres = var->yres; /* -1 ? */
- vfront = var->lower_margin;
- vsync = var->vsync_len;
- vback = var->upper_margin;
- }
-
- data.h_total = (hback / 8) + (xres / 8)
- + (hfront / 8) + (hsync / 8) - 1 /* + 1 */;
- data.h_dispend = ((xres + bpp - 1)/ 8) - 1;
- data.h_bstart = xres / 8 - 1 /* + 1 */;
-
- data.h_bstop = data.h_total+1 + 2 + 1;
- data.h_sstart = (xres / 8) + (hfront / 8) + 1;
- data.h_sstop = (xres / 8) + (hfront / 8) + (hsync / 8) + 1;
-
- data.v_total = yres + vfront + vsync + vback - 1;
-
- data.v_dispend = yres - 1;
- data.v_bstart = yres - 1;
-
- data.v_bstop = data.v_total;
- data.v_sstart = yres + vfront - 1 - 2;
- data.v_sstop = yres + vfront + vsync - 1;
-
-#if 0 /* testing */
-
- printk("HBS: %i\n", data.h_bstart);
- printk("HSS: %i\n", data.h_sstart);
- printk("HSE: %i\n", data.h_sstop);
- printk("HBE: %i\n", data.h_bstop);
- printk("HT: %i\n", data.h_total);
-
- printk("hsync: %i\n", hsync);
- printk("hfront: %i\n", hfront);
- printk("hback: %i\n", hback);
-
- printk("VBS: %i\n", data.v_bstart);
- printk("VSS: %i\n", data.v_sstart);
- printk("VSE: %i\n", data.v_sstop);
- printk("VBE: %i\n", data.v_bstop);
- printk("VT: %i\n", data.v_total);
-
- printk("vsync: %i\n", vsync);
- printk("vfront: %i\n", vfront);
- printk("vback: %i\n", vback);
-#endif
-
- if (data.v_total >= 1024)
- printk(KERN_ERR "MAYDAY: v_total >= 1024; bailing out!\n");
-
- reg_w(regs, GREG_MISC_OUTPUT_W, 0xe3 | ((clocksel & 3) * 0x04));
- reg_w(regs, GREG_FEATURE_CONTROL_W, 0x00);
-
- seq_w(regs, SEQ_RESET, 0x00);
- seq_w(regs, SEQ_RESET, 0x03); /* reset sequencer logic */
-
- /*
- * CLOCKING_MODE bits:
- * 2: This one is only set for certain text-modes, wonder if
- * it may be for EGA-lines? (it was referred to as CLKDIV2)
- * (The CL drivers sets it to 0x21 with the comment:
- * FullBandwidth (video off) and 8/9 dot clock)
- */
- seq_w(regs, SEQ_CLOCKING_MODE, 0x01 | 0x00 /* 0x08 */);
-
- seq_w(regs, SEQ_MAP_MASK, 0x0f); /* enable writing to plane 0-3 */
- seq_w(regs, SEQ_CHAR_MAP_SELECT, 0x00); /* doesn't matter in gfx-mode */
- seq_w(regs, SEQ_MEMORY_MODE, 0x06); /* CL driver says 0x0e for 256 col mode*/
- seq_w(regs, SEQ_RESET, 0x01);
- seq_w(regs, SEQ_RESET, 0x03);
-
- seq_w(regs, SEQ_EXTENDED_ENABLE, 0x05);
-
- seq_w(regs, SEQ_CURSOR_CONTROL, 0x00); /* disable cursor */
- seq_w(regs, SEQ_PRIM_HOST_OFF_HI, 0x00);
- seq_w(regs, SEQ_PRIM_HOST_OFF_HI, 0x00);
- seq_w(regs, SEQ_LINEAR_0, 0x4a);
- seq_w(regs, SEQ_LINEAR_1, 0x00);
-
- seq_w(regs, SEQ_SEC_HOST_OFF_HI, 0x00);
- seq_w(regs, SEQ_SEC_HOST_OFF_LO, 0x00);
- seq_w(regs, SEQ_EXTENDED_MEM_ENA, 0x3 | 0x4 | 0x10 | 0x40);
-
- /*
- * The lower 4 bits (0-3) are used to set the font-width for
- * text-mode - DON'T try to set this for gfx-mode.
- */
- seq_w(regs, SEQ_EXT_CLOCK_MODE, 0x10);
- seq_w(regs, SEQ_EXT_VIDEO_ADDR, 0x03);
-
- /*
- * Extended Pixel Control:
- * bit 0: text-mode=0, gfx-mode=1 (Graphics Byte ?)
- * bit 1: (Packed/Nibble Pixel Format ?)
- * bit 4-5: depth, 0=1-8bpp, 1=9-16bpp, 2=17-24bpp
- */
- seq_w(regs, SEQ_EXT_PIXEL_CNTL, 0x01 | (((bpp / 8) - 1) << 4));
-
- seq_w(regs, SEQ_BUS_WIDTH_FEEDB, 0x04);
- seq_w(regs, SEQ_COLOR_EXP_WFG, 0x01);
- seq_w(regs, SEQ_COLOR_EXP_WBG, 0x00);
- seq_w(regs, SEQ_EXT_RW_CONTROL, 0x00);
- seq_w(regs, SEQ_MISC_FEATURE_SEL, (0x51 | (clocksel & 8)));
- seq_w(regs, SEQ_COLOR_KEY_CNTL, 0x40);
- seq_w(regs, SEQ_COLOR_KEY_MATCH0, 0x00);
- seq_w(regs, SEQ_COLOR_KEY_MATCH1, 0x00);
- seq_w(regs, SEQ_COLOR_KEY_MATCH2, 0x00);
- seq_w(regs, SEQ_CRC_CONTROL, 0x00);
- seq_w(regs, SEQ_PERF_SELECT, 0x10);
- seq_w(regs, SEQ_ACM_APERTURE_1, 0x00);
- seq_w(regs, SEQ_ACM_APERTURE_2, 0x30);
- seq_w(regs, SEQ_ACM_APERTURE_3, 0x00);
- seq_w(regs, SEQ_MEMORY_MAP_CNTL, 0x03);
-
-
- /* unlock register CRT0..CRT7 */
- crt_w(regs, CRT_END_VER_RETR, (data.v_sstop & 0x0f) | 0x20);
-
- /* Zuerst zu schreibende Werte nur per printk ausgeben */
- DEBUG printk("CRT_HOR_TOTAL: %ld\n", data.h_total);
- crt_w(regs, CRT_HOR_TOTAL, data.h_total & 0xff);
-
- DEBUG printk("CRT_HOR_DISP_ENA_END: %ld\n", data.h_dispend);
- crt_w(regs, CRT_HOR_DISP_ENA_END, (data.h_dispend) & 0xff);
-
- DEBUG printk("CRT_START_HOR_BLANK: %ld\n", data.h_bstart);
- crt_w(regs, CRT_START_HOR_BLANK, data.h_bstart & 0xff);
-
- DEBUG printk("CRT_END_HOR_BLANK: 128+%ld\n", data.h_bstop % 32);
- crt_w(regs, CRT_END_HOR_BLANK, 0x80 | (data.h_bstop & 0x1f));
-
- DEBUG printk("CRT_START_HOR_RETR: %ld\n", data.h_sstart);
- crt_w(regs, CRT_START_HOR_RETR, data.h_sstart & 0xff);
-
- tmp = (data.h_sstop & 0x1f);
- if (data.h_bstop & 0x20)
- tmp |= 0x80;
- DEBUG printk("CRT_END_HOR_RETR: %d\n", tmp);
- crt_w(regs, CRT_END_HOR_RETR, tmp);
-
- DEBUG printk("CRT_VER_TOTAL: %ld\n", data.v_total & 0xff);
- crt_w(regs, CRT_VER_TOTAL, (data.v_total & 0xff));
-
- tmp = 0x10; /* LineCompare bit #9 */
- if (data.v_total & 256)
- tmp |= 0x01;
- if (data.v_dispend & 256)
- tmp |= 0x02;
- if (data.v_sstart & 256)
- tmp |= 0x04;
- if (data.v_bstart & 256)
- tmp |= 0x08;
- if (data.v_total & 512)
- tmp |= 0x20;
- if (data.v_dispend & 512)
- tmp |= 0x40;
- if (data.v_sstart & 512)
- tmp |= 0x80;
- DEBUG printk("CRT_OVERFLOW: %d\n", tmp);
- crt_w(regs, CRT_OVERFLOW, tmp);
-
- crt_w(regs, CRT_PRESET_ROW_SCAN, 0x00); /* not CL !!! */
-
- tmp = 0x40; /* LineCompare bit #8 */
- if (data.v_bstart & 512)
- tmp |= 0x20;
- if (var->vmode & FB_VMODE_DOUBLE)
- tmp |= 0x80;
- DEBUG printk("CRT_MAX_SCAN_LINE: %d\n", tmp);
- crt_w(regs, CRT_MAX_SCAN_LINE, tmp);
-
- crt_w(regs, CRT_CURSOR_START, 0x00);
- crt_w(regs, CRT_CURSOR_END, 8 & 0x1f); /* font height */
-
- crt_w(regs, CRT_START_ADDR_HIGH, 0x00);
- crt_w(regs, CRT_START_ADDR_LOW, 0x00);
-
- crt_w(regs, CRT_CURSOR_LOC_HIGH, 0x00);
- crt_w(regs, CRT_CURSOR_LOC_LOW, 0x00);
-
- DEBUG printk("CRT_START_VER_RETR: %ld\n", data.v_sstart & 0xff);
- crt_w(regs, CRT_START_VER_RETR, (data.v_sstart & 0xff));
-
-#if 1
- /* 5 refresh cycles per scanline */
- DEBUG printk("CRT_END_VER_RETR: 64+32+%ld\n", data.v_sstop % 16);
- crt_w(regs, CRT_END_VER_RETR, ((data.v_sstop & 0x0f) | 0x40 | 0x20));
-#else
- DEBUG printk("CRT_END_VER_RETR: 128+32+%ld\n", data.v_sstop % 16);
- crt_w(regs, CRT_END_VER_RETR, ((data.v_sstop & 0x0f) | 128 | 32));
-#endif
- DEBUG printk("CRT_VER_DISP_ENA_END: %ld\n", data.v_dispend & 0xff);
- crt_w(regs, CRT_VER_DISP_ENA_END, (data.v_dispend & 0xff));
-
- DEBUG printk("CRT_START_VER_BLANK: %ld\n", data.v_bstart & 0xff);
- crt_w(regs, CRT_START_VER_BLANK, (data.v_bstart & 0xff));
-
- DEBUG printk("CRT_END_VER_BLANK: %ld\n", data.v_bstop & 0xff);
- crt_w(regs, CRT_END_VER_BLANK, (data.v_bstop & 0xff));
-
- DEBUG printk("CRT_MODE_CONTROL: 0xe3\n");
- crt_w(regs, CRT_MODE_CONTROL, 0xe3);
-
- DEBUG printk("CRT_LINE_COMPARE: 0xff\n");
- crt_w(regs, CRT_LINE_COMPARE, 0xff);
-
- tmp = (var->xres_virtual / 8) * (bpp / 8);
- crt_w(regs, CRT_OFFSET, tmp);
-
- crt_w(regs, CRT_UNDERLINE_LOC, 0x07); /* probably font-height - 1 */
-
- tmp = 0x20; /* Enable extended end bits */
- if (data.h_total & 0x100)
- tmp |= 0x01;
- if ((data.h_dispend) & 0x100)
- tmp |= 0x02;
- if (data.h_bstart & 0x100)
- tmp |= 0x04;
- if (data.h_sstart & 0x100)
- tmp |= 0x08;
- if (var->vmode & FB_VMODE_INTERLACED)
- tmp |= 0x10;
- DEBUG printk("CRT_EXT_HOR_TIMING1: %d\n", tmp);
- crt_w(regs, CRT_EXT_HOR_TIMING1, tmp);
-
- tmp = 0x00;
- if (((var->xres_virtual / 8) * (bpp / 8)) & 0x100)
- tmp |= 0x10;
- crt_w(regs, CRT_EXT_START_ADDR, tmp);
-
- tmp = 0x00;
- if (data.h_total & 0x200)
- tmp |= 0x01;
- if ((data.h_dispend) & 0x200)
- tmp |= 0x02;
- if (data.h_bstart & 0x200)
- tmp |= 0x04;
- if (data.h_sstart & 0x200)
- tmp |= 0x08;
- tmp |= ((data.h_bstop & 0xc0) >> 2);
- tmp |= ((data.h_sstop & 0x60) << 1);
- crt_w(regs, CRT_EXT_HOR_TIMING2, tmp);
- DEBUG printk("CRT_EXT_HOR_TIMING2: %d\n", tmp);
-
- tmp = 0x10; /* Line compare bit 10 */
- if (data.v_total & 0x400)
- tmp |= 0x01;
- if ((data.v_dispend) & 0x400)
- tmp |= 0x02;
- if (data.v_bstart & 0x400)
- tmp |= 0x04;
- if (data.v_sstart & 0x400)
- tmp |= 0x08;
- tmp |= ((data.v_bstop & 0x300) >> 3);
- if (data.v_sstop & 0x10)
- tmp |= 0x80;
- crt_w(regs, CRT_EXT_VER_TIMING, tmp);
- DEBUG printk("CRT_EXT_VER_TIMING: %d\n", tmp);
-
- crt_w(regs, CRT_MONITOR_POWER, 0x00);
-
- /*
- * Convert from ps to Hz.
- */
- freq = 2000000000 / var->pixclock;
- freq = freq * 500;
-
- best_freq = find_fq(freq);
- pll_w(regs, 0x02, best_freq);
- best_freq = find_fq(61000000);
- pll_w(regs, 0x0a, best_freq);
- pll_w(regs, 0x0e, 0x22);
-
- gfx_w(regs, GFX_SET_RESET, 0x00);
- gfx_w(regs, GFX_ENABLE_SET_RESET, 0x00);
- gfx_w(regs, GFX_COLOR_COMPARE, 0x00);
- gfx_w(regs, GFX_DATA_ROTATE, 0x00);
- gfx_w(regs, GFX_READ_MAP_SELECT, 0x00);
- gfx_w(regs, GFX_GRAPHICS_MODE, 0x00);
- gfx_w(regs, GFX_MISC, 0x05);
- gfx_w(regs, GFX_COLOR_XCARE, 0x0f);
- gfx_w(regs, GFX_BITMASK, 0xff);
-
- reg_r(regs, ACT_ADDRESS_RESET);
- attr_w(regs, ACT_PALETTE0 , 0x00);
- attr_w(regs, ACT_PALETTE1 , 0x01);
- attr_w(regs, ACT_PALETTE2 , 0x02);
- attr_w(regs, ACT_PALETTE3 , 0x03);
- attr_w(regs, ACT_PALETTE4 , 0x04);
- attr_w(regs, ACT_PALETTE5 , 0x05);
- attr_w(regs, ACT_PALETTE6 , 0x06);
- attr_w(regs, ACT_PALETTE7 , 0x07);
- attr_w(regs, ACT_PALETTE8 , 0x08);
- attr_w(regs, ACT_PALETTE9 , 0x09);
- attr_w(regs, ACT_PALETTE10, 0x0a);
- attr_w(regs, ACT_PALETTE11, 0x0b);
- attr_w(regs, ACT_PALETTE12, 0x0c);
- attr_w(regs, ACT_PALETTE13, 0x0d);
- attr_w(regs, ACT_PALETTE14, 0x0e);
- attr_w(regs, ACT_PALETTE15, 0x0f);
- reg_r(regs, ACT_ADDRESS_RESET);
-
- attr_w(regs, ACT_ATTR_MODE_CNTL, 0x09); /* 0x01 for CL */
-
- attr_w(regs, ACT_OVERSCAN_COLOR, 0x00);
- attr_w(regs, ACT_COLOR_PLANE_ENA, 0x0f);
- attr_w(regs, ACT_HOR_PEL_PANNING, 0x00);
- attr_w(regs, ACT_COLOR_SELECT, 0x00);
-
- reg_r(regs, ACT_ADDRESS_RESET);
- reg_w(regs, ACT_DATA, 0x20);
-
- reg_w(regs, VDAC_MASK, 0xff);
-
- /*
- * Extended palette addressing ???
- */
- switch (bpp){
- case 8:
- reg_w(regs, 0x83c6, 0x00);
- break;
- case 16:
- reg_w(regs, 0x83c6, 0x60);
- break;
- case 24:
- reg_w(regs, 0x83c6, 0xe0);
- break;
- default:
- printk(KERN_INFO "Illegal color-depth: %i\n", bpp);
- }
-
- reg_w(regs, VDAC_ADDRESS, 0x00);
-
- seq_w(regs, SEQ_MAP_MASK, 0x0f );
-
- return 0;
-}
-
-
-/*
- * This function should fill in the `fix' structure based on the
- * values in the `par' structure.
- */
-
-static int retz3_encode_fix(struct fb_info *info,
- struct fb_fix_screeninfo *fix,
- struct retz3fb_par *par)
-{
- struct retz3_fb_info *zinfo = retz3info(info);
-
- memset(fix, 0, sizeof(struct fb_fix_screeninfo));
- strcpy(fix->id, retz3fb_name);
- fix->smem_start = zinfo->physfbmem;
- fix->smem_len = zinfo->fbsize;
- fix->mmio_start = zinfo->physregs;
- fix->mmio_len = 0x00c00000;
-
- fix->type = FB_TYPE_PACKED_PIXELS;
- fix->type_aux = 0;
- if (par->bpp == 8)
- fix->visual = FB_VISUAL_PSEUDOCOLOR;
- else
- fix->visual = FB_VISUAL_TRUECOLOR;
-
- fix->xpanstep = 0;
- fix->ypanstep = 0;
- fix->ywrapstep = 0;
- fix->line_length = 0;
-
- fix->accel = FB_ACCEL_NCR_77C32BLT;
-
- return 0;
-}
-
-
-/*
- * Get the video params out of `var'. If a value doesn't fit, round
- * it up, if it's too big, return -EINVAL.
- */
-
-static int retz3_decode_var(struct fb_var_screeninfo *var,
- struct retz3fb_par *par)
-{
- par->xres = var->xres;
- par->yres = var->yres;
- par->xres_vir = var->xres_virtual;
- par->yres_vir = var->yres_virtual;
- par->bpp = var->bits_per_pixel;
- par->pixclock = var->pixclock;
- par->vmode = var->vmode;
-
- par->red = var->red;
- par->green = var->green;
- par->blue = var->blue;
- par->transp = var->transp;
-
- par->left_margin = var->left_margin;
- par->right_margin = var->right_margin;
- par->upper_margin = var->upper_margin;
- par->lower_margin = var->lower_margin;
- par->hsync_len = var->hsync_len;
- par->vsync_len = var->vsync_len;
-
- if (var->accel_flags & FB_ACCELF_TEXT)
- par->accel = FB_ACCELF_TEXT;
- else
- par->accel = 0;
-
- return 0;
-}
-
-
-/*
- * Fill the `var' structure based on the values in `par' and maybe
- * other values read out of the hardware.
- */
-
-static int retz3_encode_var(struct fb_var_screeninfo *var,
- struct retz3fb_par *par)
-{
- memset(var, 0, sizeof(struct fb_var_screeninfo));
- var->xres = par->xres;
- var->yres = par->yres;
- var->xres_virtual = par->xres_vir;
- var->yres_virtual = par->yres_vir;
- var->xoffset = 0;
- var->yoffset = 0;
-
- var->bits_per_pixel = par->bpp;
- var->grayscale = 0;
-
- var->red = par->red;
- var->green = par->green;
- var->blue = par->blue;
- var->transp = par->transp;
-
- var->nonstd = 0;
- var->activate = 0;
-
- var->height = -1;
- var->width = -1;
-
- var->accel_flags = (par->accel && par->bpp == 8) ? FB_ACCELF_TEXT : 0;
-
- var->pixclock = par->pixclock;
-
- var->sync = 0; /* ??? */
- var->left_margin = par->left_margin;
- var->right_margin = par->right_margin;
- var->upper_margin = par->upper_margin;
- var->lower_margin = par->lower_margin;
- var->hsync_len = par->hsync_len;
- var->vsync_len = par->vsync_len;
-
- var->vmode = par->vmode;
- return 0;
-}
-
-
-/*
- * Set a single color register. Return != 0 for invalid regno.
- */
-
-static int retz3fb_setcolreg(unsigned int regno, unsigned int red,
- unsigned int green, unsigned int blue,
- unsigned int transp, struct fb_info *info)
-{
- struct retz3_fb_info *zinfo = retz3info(info);
- volatile unsigned char *regs = zinfo->regs;
-
- /* We'll get to this */
-
- if (regno > 255)
- return 1;
-
- red >>= 10;
- green >>= 10;
- blue >>= 10;
-
- zinfo->color_table[regno][0] = red;
- zinfo->color_table[regno][1] = green;
- zinfo->color_table[regno][2] = blue;
-
- reg_w(regs, VDAC_ADDRESS_W, regno);
- reg_w(regs, VDAC_DATA, red);
- reg_w(regs, VDAC_DATA, green);
- reg_w(regs, VDAC_DATA, blue);
-
- return 0;
-}
-
-
-/*
- * Read a single color register and split it into
- * colors/transparent. Return != 0 for invalid regno.
- */
-
-static int retz3_getcolreg(unsigned int regno, unsigned int *red,
- unsigned int *green, unsigned int *blue,
- unsigned int *transp, struct fb_info *info)
-{
- struct retz3_fb_info *zinfo = retz3info(info);
- int t;
-
- if (regno > 255)
- return 1;
- t = zinfo->color_table[regno][0];
- *red = (t<<10) | (t<<4) | (t>>2);
- t = zinfo->color_table[regno][1];
- *green = (t<<10) | (t<<4) | (t>>2);
- t = zinfo->color_table[regno][2];
- *blue = (t<<10) | (t<<4) | (t>>2);
- *transp = 0;
- return 0;
-}
-
-
-static inline void retz3_busy(struct display *p)
-{
- struct retz3_fb_info *zinfo = retz3info(p->fb_info);
- volatile unsigned char *acm = zinfo->base + ACM_OFFSET;
- unsigned char blt_status;
-
- if (zinfo->blitbusy) {
- do{
- blt_status = *((acm) + (ACM_START_STATUS + 2));
- }while ((blt_status & 1) == 0);
- zinfo->blitbusy = 0;
- }
-}
-
-
-static void retz3_bitblt (struct display *p,
- unsigned short srcx, unsigned short srcy,
- unsigned short destx, unsigned short desty,
- unsigned short width, unsigned short height,
- unsigned short cmd, unsigned short mask)
-{
- struct fb_var_screeninfo *var = &p->var;
- struct retz3_fb_info *zinfo = retz3info(p->fb_info);
- volatile unsigned long *acm = (unsigned long *)(zinfo->base + ACM_OFFSET);
- unsigned long *pattern = (unsigned long *)(zinfo->fbmem + PAT_MEM_OFF);
-
- unsigned short mod;
- unsigned long tmp;
- unsigned long pat, src, dst;
-
- int i, xres_virtual = var->xres_virtual;
- short bpp = (var->bits_per_pixel & 0xff);
-
- if (bpp < 8)
- bpp = 8;
-
- tmp = mask | (mask << 16);
-
- retz3_busy(p);
-
- i = 0;
- do{
- *pattern++ = tmp;
- }while(i++ < bpp/4);
-
- tmp = cmd << 8;
- *(acm + ACM_RASTEROP_ROTATION/4) = tmp;
-
- mod = 0xc0c2;
-
- pat = 8 * PAT_MEM_OFF;
- dst = bpp * (destx + desty * xres_virtual);
-
- /*
- * Source is not set for clear.
- */
- if ((cmd != Z3BLTclear) && (cmd != Z3BLTset)) {
- src = bpp * (srcx + srcy * xres_virtual);
-
- if (destx > srcx) {
- mod &= ~0x8000;
- src += bpp * (width - 1);
- dst += bpp * (width - 1);
- pat += bpp * 2;
- }
- if (desty > srcy) {
- mod &= ~0x4000;
- src += bpp * (height - 1) * xres_virtual;
- dst += bpp * (height - 1) * xres_virtual;
- pat += bpp * 4;
- }
-
- *(acm + ACM_SOURCE/4) = cpu_to_le32(src);
- }
-
- *(acm + ACM_PATTERN/4) = cpu_to_le32(pat);
-
- *(acm + ACM_DESTINATION/4) = cpu_to_le32(dst);
-
- tmp = mod << 16;
- *(acm + ACM_CONTROL/4) = tmp;
-
- tmp = width | (height << 16);
-
- *(acm + ACM_BITMAP_DIMENSION/4) = cpu_to_le32(tmp);
-
- *(((volatile unsigned char *)acm) + ACM_START_STATUS) = 0x00;
- *(((volatile unsigned char *)acm) + ACM_START_STATUS) = 0x01;
- zinfo->blitbusy = 1;
-}
-
-#if 0
-/*
- * Move cursor to x, y
- */
-static void retz3_MoveCursor (unsigned short x, unsigned short y)
-{
- /* Guess we gotta deal with the cursor at some point */
-}
-#endif
-
-
-/*
- * Fill the hardware's `par' structure.
- */
-
-static void retz3fb_get_par(struct fb_info *info, struct retz3fb_par *par)
-{
- struct retz3_fb_info *zinfo = retz3info(info);
-
- if (zinfo->current_par_valid)
- *par = zinfo->current_par;
- else
- retz3_decode_var(&retz3fb_default, par);
-}
-
-
-static void retz3fb_set_par(struct fb_info *info, struct retz3fb_par *par)
-{
- struct retz3_fb_info *zinfo = retz3info(info);
-
- zinfo->current_par = *par;
- zinfo->current_par_valid = 1;
-}
-
-
-static int do_fb_set_var(struct fb_info *info,
- struct fb_var_screeninfo *var, int isactive)
-{
- int err, activate;
- struct retz3fb_par par;
- struct retz3_fb_info *zinfo = retz3info(info);
-
- if ((err = retz3_decode_var(var, &par)))
- return err;
- activate = var->activate;
-
- /* XXX ... what to do about isactive ? */
-
- if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW && isactive)
- retz3fb_set_par(info, &par);
- retz3_encode_var(var, &par);
- var->activate = activate;
-
- retz3_set_video(info, var, &zinfo->current_par);
-
- return 0;
-}
-
-/*
- * Get the Fixed Part of the Display
- */
-
-static int retz3fb_get_fix(struct fb_fix_screeninfo *fix, int con,
- struct fb_info *info)
-{
- struct retz3fb_par par;
- int error = 0;
-
- if (con == -1)
- retz3fb_get_par(info, &par);
- else
- error = retz3_decode_var(&fb_display[con].var, &par);
- return(error ? error : retz3_encode_fix(info, fix, &par));
-}
-
-
-/*
- * Get the User Defined Part of the Display
- */
-
-static int retz3fb_get_var(struct fb_var_screeninfo *var, int con,
- struct fb_info *info)
-{
- struct retz3fb_par par;
- int error = 0;
-
- if (con == -1) {
- retz3fb_get_par(info, &par);
- error = retz3_encode_var(var, &par);
- } else
- *var = fb_display[con].var;
- return error;
-}
-
-
-static void retz3fb_set_disp(int con, struct fb_info *info)
-{
- struct fb_fix_screeninfo fix;
- struct display *display;
- struct retz3_fb_info *zinfo = retz3info(info);
-
- if (con >= 0)
- display = &fb_display[con];
- else
- display = &zinfo->disp; /* used during initialization */
-
- retz3fb_get_fix(&fix, con, info);
-
- if (con == -1)
- con = 0;
-
- display->visual = fix.visual;
- display->type = fix.type;
- display->type_aux = fix.type_aux;
- display->ypanstep = fix.ypanstep;
- display->ywrapstep = fix.ywrapstep;
- display->can_soft_blank = 1;
- display->inverse = z3fb_inverse;
-
- /*
- * This seems to be about 20% faster.
- */
- display->scrollmode = SCROLL_YREDRAW;
-
- switch (display->var.bits_per_pixel) {
-#ifdef FBCON_HAS_CFB8
- case 8:
- if (display->var.accel_flags & FB_ACCELF_TEXT) {
- display->dispsw = &fbcon_retz3_8;
- retz3_set_video(info, &display->var, &zinfo->current_par);
- } else
- display->dispsw = &fbcon_cfb8;
- break;
-#endif
-#ifdef FBCON_HAS_CFB16
- case 16:
- display->dispsw = &fbcon_cfb16;
- break;
-#endif
- default:
- display->dispsw = &fbcon_dummy;
- break;
- }
-}
-
-
-/*
- * Set the User Defined Part of the Display
- */
-
-static int retz3fb_set_var(struct fb_var_screeninfo *var, int con,
- struct fb_info *info)
-{
- int err, oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldaccel;
- struct display *display;
- struct retz3_fb_info *zinfo = retz3info(info);
-
- if (con >= 0)
- display = &fb_display[con];
- else
- display = &zinfo->disp; /* used during initialization */
-
- if ((err = do_fb_set_var(info, var, con == info->currcon)))
- return err;
- if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
- oldxres = display->var.xres;
- oldyres = display->var.yres;
- oldvxres = display->var.xres_virtual;
- oldvyres = display->var.yres_virtual;
- oldbpp = display->var.bits_per_pixel;
- oldaccel = display->var.accel_flags;
- display->var = *var;
-
- if (oldxres != var->xres || oldyres != var->yres ||
- oldvxres != var->xres_virtual ||
- oldvyres != var->yres_virtual ||
- oldbpp != var->bits_per_pixel ||
- oldaccel != var->accel_flags) {
-
- struct fb_fix_screeninfo fix;
- retz3fb_get_fix(&fix, con, info);
-
- display->visual = fix.visual;
- display->type = fix.type;
- display->type_aux = fix.type_aux;
- display->ypanstep = fix.ypanstep;
- display->ywrapstep = fix.ywrapstep;
- display->line_length = fix.line_length;
- display->can_soft_blank = 1;
- display->inverse = z3fb_inverse;
- switch (display->var.bits_per_pixel) {
-#ifdef FBCON_HAS_CFB8
- case 8:
- if (var->accel_flags & FB_ACCELF_TEXT) {
- display->dispsw = &fbcon_retz3_8;
- } else
- display->dispsw = &fbcon_cfb8;
- break;
-#endif
-#ifdef FBCON_HAS_CFB16
- case 16:
- display->dispsw = &fbcon_cfb16;
- break;
-#endif
- default:
- display->dispsw = &fbcon_dummy;
- break;
- }
- /*
- * We still need to find a way to tell the X
- * server that the video mem has been fiddled with
- * so it redraws the entire screen when switching
- * between X and a text console.
- */
- retz3_set_video(info, var, &zinfo->current_par);
-
- if (info->changevar)
- (*info->changevar)(con);
- }
-
- if (oldbpp != var->bits_per_pixel) {
- if ((err = fb_alloc_cmap(&display->cmap, 0, 0)))
- return err;
- do_install_cmap(con, info);
- }
- }
- return 0;
-}
-
-
-/*
- * Get the Colormap
- */
-
-static int retz3fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
- struct fb_info *info)
-{
- if (con == info->currcon) /* current console? */
- return(fb_get_cmap(cmap, kspc, retz3_getcolreg, info));
- else if (fb_display[con].cmap.len) /* non default colormap? */
- fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
- else
- fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
- cmap, kspc ? 0 : 2);
- return 0;
-}
-
-/*
- * Blank the display.
- */
-
-static int retz3fb_blank(int blank, struct fb_info *info)
-{
- struct retz3_fb_info *zinfo = retz3info(info);
- volatile unsigned char *regs = retz3info(info)->regs;
- short i;
-
- if (blank)
- for (i = 0; i < 256; i++){
- reg_w(regs, VDAC_ADDRESS_W, i);
- reg_w(regs, VDAC_DATA, 0);
- reg_w(regs, VDAC_DATA, 0);
- reg_w(regs, VDAC_DATA, 0);
- }
- else
- for (i = 0; i < 256; i++){
- reg_w(regs, VDAC_ADDRESS_W, i);
- reg_w(regs, VDAC_DATA, zinfo->color_table[i][0]);
- reg_w(regs, VDAC_DATA, zinfo->color_table[i][1]);
- reg_w(regs, VDAC_DATA, zinfo->color_table[i][2]);
- }
- return 0;
-}
-
-static struct fb_ops retz3fb_ops = {
- .owner = THIS_MODULE,
- .fb_get_fix = retz3fb_get_fix,
- .fb_get_var = retz3fb_get_var,
- .fb_set_var = retz3fb_set_var,
- .fb_get_cmap = retz3fb_get_cmap,
- .fb_set_cmap = gen_set_cmap,
- .fb_setcolreg = retz3fb_setcolreg,
- .fb_blank = retz3fb_blank,
-};
-
-int __init retz3fb_setup(char *options)
-{
- char *this_opt;
-
- if (!options || !*options)
- return 0;
-
- while ((this_opt = strsep(&options, ",")) != NULL) {
- if (!*this_opt)
- continue;
- if (!strcmp(this_opt, "inverse")) {
- z3fb_inverse = 1;
- fb_invert_cmaps();
- } else if (!strncmp(this_opt, "font:", 5)) {
- strlcpy(fontname, this_opt+5, sizeof(fontname));
- } else
- z3fb_mode = get_video_mode(this_opt);
- }
- return 0;
-}
-
-
-/*
- * Initialization
- */
-
-int __init retz3fb_init(void)
-{
- unsigned long board_addr, board_size;
- struct zorro_dev *z = NULL;
- volatile unsigned char *regs;
- struct retz3fb_par par;
- struct retz3_fb_info *zinfo;
- struct fb_info *fb_info;
- short i;
- int res = -ENXIO;
-
- while ((z = zorro_find_device(ZORRO_PROD_MACROSYSTEMS_RETINA_Z3, z))) {
- board_addr = z->resource.start;
- board_size = z->resource.end-z->resource.start+1;
- if (!request_mem_region(board_addr, 0x0c00000,
- "ncr77c32blt")) {
- continue;
- if (!request_mem_region(board_addr+VIDEO_MEM_OFFSET,
- 0x00400000, "RAM"))
- release_mem_region(board_addr, 0x00c00000);
- continue;
- }
- if (!(zinfo = kmalloc(sizeof(struct retz3_fb_info),
- GFP_KERNEL)))
- return -ENOMEM;
- memset(zinfo, 0, sizeof(struct retz3_fb_info));
-
- zinfo->base = ioremap(board_addr, board_size);
- zinfo->regs = zinfo->base;
- zinfo->fbmem = zinfo->base + VIDEO_MEM_OFFSET;
- /* Get memory size - for now we asume it's a 4MB board */
- zinfo->fbsize = 0x00400000; /* 4 MB */
- zinfo->physregs = board_addr;
- zinfo->physfbmem = board_addr + VIDEO_MEM_OFFSET;
-
- fb_info = fbinfo(zinfo);
-
- for (i = 0; i < 256; i++){
- for (i = 0; i < 256; i++){
- zinfo->color_table[i][0] = i;
- zinfo->color_table[i][1] = i;
- zinfo->color_table[i][2] = i;
- }
- }
-
- regs = zinfo->regs;
- /* Disable hardware cursor */
- seq_w(regs, SEQ_CURSOR_Y_INDEX, 0x00);
-
- retz3fb_setcolreg (255, 56<<8, 100<<8, 160<<8, 0, fb_info);
- retz3fb_setcolreg (254, 0, 0, 0, 0, fb_info);
-
- strcpy(fb_info->modename, retz3fb_name);
- fb_info->changevar = NULL;
- fb_info->fbops = &retz3fb_ops;
- fb_info->screen_base = zinfo->fbmem;
- fb_info->disp = &zinfo->disp;
- fb_info->currcon = -1;
- fb_info->switch_con = &z3fb_switch;
- fb_info->updatevar = &z3fb_updatevar;
- fb_info->flags = FBINFO_FLAG_DEFAULT;
- strlcpy(fb_info->fontname, fontname, sizeof(fb_info->fontname));
-
- if (z3fb_mode == -1)
- retz3fb_default = retz3fb_predefined[0].var;
-
- retz3_decode_var(&retz3fb_default, &par);
- retz3_encode_var(&retz3fb_default, &par);
-
- do_fb_set_var(fb_info, &retz3fb_default, 0);
- retz3fb_get_var(&zinfo->disp.var, -1, fb_info);
-
- retz3fb_set_disp(-1, fb_info);
-
- do_install_cmap(0, fb_info);
-
- if (register_framebuffer(fb_info) < 0) {
- iounmap(zinfo->base);
- return -EINVAL;
- }
-
- printk(KERN_INFO "fb%d: %s frame buffer device, using %ldK of "
- "video memory\n", fb_info->node,
- fb_info->modename, zinfo->fbsize>>10);
-
- /* FIXME: This driver cannot be unloaded yet */
- res = 0;
- }
- return res;
-}
-
-
-static int z3fb_switch(int con, struct fb_info *info)
-{
- /* Do we have to save the colormap? */
- if (fb_display[info->currcon].cmap.len)
- fb_get_cmap(&fb_display[info->currcon].cmap, 1,
- retz3_getcolreg, info);
-
- do_fb_set_var(info, &fb_display[con].var, 1);
- info->currcon = con;
- /* Install new colormap */
- do_install_cmap(con, info);
- return 0;
-}
-
-
-/*
- * Update the `var' structure (called by fbcon.c)
- *
- * This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'.
- * Since it's called by a kernel driver, no range checking is done.
- */
-
-static int z3fb_updatevar(int con, struct fb_info *info)
-{
- return 0;
-}
-
-/*
- * Get a Video Mode
- */
-
-static int __init get_video_mode(const char *name)
-{
- short i;
-
- for (i = 0; i < NUM_TOTAL_MODES; i++)
- if (!strcmp(name, retz3fb_predefined[i].name)){
- retz3fb_default = retz3fb_predefined[i].var;
- return i;
- }
- return -1;
-}
-
-
-#ifdef MODULE
-MODULE_LICENSE("GPL");
-
-int init_module(void)
-{
- return retz3fb_init();
-}
-#endif
-
-
-/*
- * Text console acceleration
- */
-
-#ifdef FBCON_HAS_CFB8
-static void retz3_8_bmove(struct display *p, int sy, int sx,
- int dy, int dx, int height, int width)
-{
- int fontwidth = fontwidth(p);
-
- sx *= fontwidth;
- dx *= fontwidth;
- width *= fontwidth;
-
- retz3_bitblt(p,
- (unsigned short)sx,
- (unsigned short)(sy*fontheight(p)),
- (unsigned short)dx,
- (unsigned short)(dy*fontheight(p)),
- (unsigned short)width,
- (unsigned short)(height*fontheight(p)),
- Z3BLTcopy,
- 0xffff);
-}
-
-static void retz3_8_clear(struct vc_data *conp, struct display *p,
- int sy, int sx, int height, int width)
-{
- unsigned short col;
- int fontwidth = fontwidth(p);
-
- sx *= fontwidth;
- width *= fontwidth;
-
- col = attr_bgcol_ec(p, conp);
- col &= 0xff;
- col |= (col << 8);
-
- retz3_bitblt(p,
- (unsigned short)sx,
- (unsigned short)(sy*fontheight(p)),
- (unsigned short)sx,
- (unsigned short)(sy*fontheight(p)),
- (unsigned short)width,
- (unsigned short)(height*fontheight(p)),
- Z3BLTset,
- col);
-}
-
-
-static void retz3_putc(struct vc_data *conp, struct display *p, int c,
- int yy, int xx)
-{
- retz3_busy(p);
- fbcon_cfb8_putc(conp, p, c, yy, xx);
-}
-
-
-static void retz3_putcs(struct vc_data *conp, struct display *p,
- const unsigned short *s, int count,
- int yy, int xx)
-{
- retz3_busy(p);
- fbcon_cfb8_putcs(conp, p, s, count, yy, xx);
-}
-
-
-static void retz3_revc(struct display *p, int xx, int yy)
-{
- retz3_busy(p);
- fbcon_cfb8_revc(p, xx, yy);
-}
-
-
-static void retz3_clear_margins(struct vc_data* conp, struct display* p,
- int bottom_only)
-{
- retz3_busy(p);
- fbcon_cfb8_clear_margins(conp, p, bottom_only);
-}
-
-
-static struct display_switch fbcon_retz3_8 = {
- .setup = fbcon_cfb8_setup,
- .bmove = retz3_8_bmove,
- .clear = retz3_8_clear,
- .putc = retz3_putc,
- .putcs = retz3_putcs,
- .revc = retz3_revc,
- .clear_margins = retz3_clear_margins,
- .fontwidthmask = FONTWIDTH(8)
-};
-#endif
diff --git a/drivers/video/retz3fb.h b/drivers/video/retz3fb.h
deleted file mode 100644
index 5cc75106772..00000000000
--- a/drivers/video/retz3fb.h
+++ /dev/null
@@ -1,286 +0,0 @@
-/*
- * linux/drivers/video/retz3fb.h -- Defines and macros for the RetinaZ3 frame
- * buffer device
- *
- * Copyright (C) 1997 Jes Sorensen
- *
- * History:
- * - 22 Jan 97: Initial work
- *
- *
- * 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.
- */
-
-/*
- * Macros to read and write to registers.
- */
-#define reg_w(regs, reg,dat) (*(regs + reg) = dat)
-#define reg_r(regs, reg) (*(regs + reg))
-
-/*
- * Macro to access the sequencer.
- */
-#define seq_w(regs, sreg, sdat) \
- do{ reg_w(regs, SEQ_IDX, sreg); reg_w(regs, SEQ_DATA, sdat); } while(0)
-
-/*
- * Macro to access the CRT controller.
- */
-#define crt_w(regs, creg, cdat) \
- do{ reg_w(regs, CRT_IDX, creg); reg_w(regs, CRT_DATA, cdat); } while(0)
-
-/*
- * Macro to access the graphics controller.
- */
-#define gfx_w(regs, greg, gdat) \
- do{ reg_w(regs, GFX_IDX, greg); reg_w(regs, GFX_DATA, gdat); } while(0)
-
-/*
- * Macro to access the attribute controller.
- */
-#define attr_w(regs, areg, adat) \
- do{ reg_w(regs, ACT_IDX, areg); reg_w(regs, ACT_DATA, adat); } while(0)
-
-/*
- * Macro to access the pll.
- */
-#define pll_w(regs, preg, pdat) \
- do{ reg_w(regs, PLL_IDX, preg); \
- reg_w(regs, PLL_DATA, (pdat & 0xff)); \
- reg_w(regs, PLL_DATA, (pdat >> 8));\
- } while(0)
-
-/*
- * Offsets
- */
-#define VIDEO_MEM_OFFSET 0x00c00000
-#define ACM_OFFSET 0x00b00000
-
-/*
- * Accelerator Control Menu
- */
-#define ACM_PRIMARY_OFFSET 0x00
-#define ACM_SECONDARY_OFFSET 0x04
-#define ACM_MODE_CONTROL 0x08
-#define ACM_CURSOR_POSITION 0x0c
-#define ACM_START_STATUS 0x30
-#define ACM_CONTROL 0x34
-#define ACM_RASTEROP_ROTATION 0x38
-#define ACM_BITMAP_DIMENSION 0x3c
-#define ACM_DESTINATION 0x40
-#define ACM_SOURCE 0x44
-#define ACM_PATTERN 0x48
-#define ACM_FOREGROUND 0x4c
-#define ACM_BACKGROUND 0x50
-
-/*
- * Video DAC addresses
- */
-#define VDAC_ADDRESS 0x03c8
-#define VDAC_ADDRESS_W 0x03c8
-#define VDAC_ADDRESS_R 0x03c7
-#define VDAC_STATE 0x03c7
-#define VDAC_DATA 0x03c9
-#define VDAC_MASK 0x03c6
-
-/*
- * Sequencer
- */
-#define SEQ_IDX 0x03c4 /* Sequencer Index */
-#define SEQ_DATA 0x03c5
-#define SEQ_RESET 0x00
-#define SEQ_CLOCKING_MODE 0x01
-#define SEQ_MAP_MASK 0x02
-#define SEQ_CHAR_MAP_SELECT 0x03
-#define SEQ_MEMORY_MODE 0x04
-#define SEQ_EXTENDED_ENABLE 0x05 /* NCR extensions */
-#define SEQ_UNKNOWN1 0x06
-#define SEQ_UNKNOWN2 0x07
-#define SEQ_CHIP_ID 0x08
-#define SEQ_UNKNOWN3 0x09
-#define SEQ_CURSOR_COLOR1 0x0a
-#define SEQ_CURSOR_COLOR0 0x0b
-#define SEQ_CURSOR_CONTROL 0x0c
-#define SEQ_CURSOR_X_LOC_HI 0x0d
-#define SEQ_CURSOR_X_LOC_LO 0x0e
-#define SEQ_CURSOR_Y_LOC_HI 0x0f
-#define SEQ_CURSOR_Y_LOC_LO 0x10
-#define SEQ_CURSOR_X_INDEX 0x11
-#define SEQ_CURSOR_Y_INDEX 0x12
-#define SEQ_CURSOR_STORE_HI 0x13
-#define SEQ_CURSOR_STORE_LO 0x14
-#define SEQ_CURSOR_ST_OFF_HI 0x15
-#define SEQ_CURSOR_ST_OFF_LO 0x16
-#define SEQ_CURSOR_PIXELMASK 0x17
-#define SEQ_PRIM_HOST_OFF_HI 0x18
-#define SEQ_PRIM_HOST_OFF_LO 0x19
-#define SEQ_LINEAR_0 0x1a
-#define SEQ_LINEAR_1 0x1b
-#define SEQ_SEC_HOST_OFF_HI 0x1c
-#define SEQ_SEC_HOST_OFF_LO 0x1d
-#define SEQ_EXTENDED_MEM_ENA 0x1e
-#define SEQ_EXT_CLOCK_MODE 0x1f
-#define SEQ_EXT_VIDEO_ADDR 0x20
-#define SEQ_EXT_PIXEL_CNTL 0x21
-#define SEQ_BUS_WIDTH_FEEDB 0x22
-#define SEQ_PERF_SELECT 0x23
-#define SEQ_COLOR_EXP_WFG 0x24
-#define SEQ_COLOR_EXP_WBG 0x25
-#define SEQ_EXT_RW_CONTROL 0x26
-#define SEQ_MISC_FEATURE_SEL 0x27
-#define SEQ_COLOR_KEY_CNTL 0x28
-#define SEQ_COLOR_KEY_MATCH0 0x29
-#define SEQ_COLOR_KEY_MATCH1 0x2a
-#define SEQ_COLOR_KEY_MATCH2 0x2b
-#define SEQ_UNKNOWN6 0x2c
-#define SEQ_CRC_CONTROL 0x2d
-#define SEQ_CRC_DATA_LOW 0x2e
-#define SEQ_CRC_DATA_HIGH 0x2f
-#define SEQ_MEMORY_MAP_CNTL 0x30
-#define SEQ_ACM_APERTURE_1 0x31
-#define SEQ_ACM_APERTURE_2 0x32
-#define SEQ_ACM_APERTURE_3 0x33
-#define SEQ_BIOS_UTILITY_0 0x3e
-#define SEQ_BIOS_UTILITY_1 0x3f
-
-/*
- * Graphics Controller
- */
-#define GFX_IDX 0x03ce
-#define GFX_DATA 0x03cf
-#define GFX_SET_RESET 0x00
-#define GFX_ENABLE_SET_RESET 0x01
-#define GFX_COLOR_COMPARE 0x02
-#define GFX_DATA_ROTATE 0x03
-#define GFX_READ_MAP_SELECT 0x04
-#define GFX_GRAPHICS_MODE 0x05
-#define GFX_MISC 0x06
-#define GFX_COLOR_XCARE 0x07
-#define GFX_BITMASK 0x08
-
-/*
- * CRT Controller
- */
-#define CRT_IDX 0x03d4
-#define CRT_DATA 0x03d5
-#define CRT_HOR_TOTAL 0x00
-#define CRT_HOR_DISP_ENA_END 0x01
-#define CRT_START_HOR_BLANK 0x02
-#define CRT_END_HOR_BLANK 0x03
-#define CRT_START_HOR_RETR 0x04
-#define CRT_END_HOR_RETR 0x05
-#define CRT_VER_TOTAL 0x06
-#define CRT_OVERFLOW 0x07
-#define CRT_PRESET_ROW_SCAN 0x08
-#define CRT_MAX_SCAN_LINE 0x09
-#define CRT_CURSOR_START 0x0a
-#define CRT_CURSOR_END 0x0b
-#define CRT_START_ADDR_HIGH 0x0c
-#define CRT_START_ADDR_LOW 0x0d
-#define CRT_CURSOR_LOC_HIGH 0x0e
-#define CRT_CURSOR_LOC_LOW 0x0f
-#define CRT_START_VER_RETR 0x10
-#define CRT_END_VER_RETR 0x11
-#define CRT_VER_DISP_ENA_END 0x12
-#define CRT_OFFSET 0x13
-#define CRT_UNDERLINE_LOC 0x14
-#define CRT_START_VER_BLANK 0x15
-#define CRT_END_VER_BLANK 0x16
-#define CRT_MODE_CONTROL 0x17
-#define CRT_LINE_COMPARE 0x18
-#define CRT_UNKNOWN1 0x19
-#define CRT_UNKNOWN2 0x1a
-#define CRT_UNKNOWN3 0x1b
-#define CRT_UNKNOWN4 0x1c
-#define CRT_UNKNOWN5 0x1d
-#define CRT_UNKNOWN6 0x1e
-#define CRT_UNKNOWN7 0x1f
-#define CRT_UNKNOWN8 0x20
-#define CRT_UNKNOWN9 0x21
-#define CRT_UNKNOWN10 0x22
-#define CRT_UNKNOWN11 0x23
-#define CRT_UNKNOWN12 0x24
-#define CRT_UNKNOWN13 0x25
-#define CRT_UNKNOWN14 0x26
-#define CRT_UNKNOWN15 0x27
-#define CRT_UNKNOWN16 0x28
-#define CRT_UNKNOWN17 0x29
-#define CRT_UNKNOWN18 0x2a
-#define CRT_UNKNOWN19 0x2b
-#define CRT_UNKNOWN20 0x2c
-#define CRT_UNKNOWN21 0x2d
-#define CRT_UNKNOWN22 0x2e
-#define CRT_UNKNOWN23 0x2f
-#define CRT_EXT_HOR_TIMING1 0x30 /* NCR crt extensions */
-#define CRT_EXT_START_ADDR 0x31
-#define CRT_EXT_HOR_TIMING2 0x32
-#define CRT_EXT_VER_TIMING 0x33
-#define CRT_MONITOR_POWER 0x34
-
-/*
- * General Registers
- */
-#define GREG_STATUS0_R 0x03c2
-#define GREG_STATUS1_R 0x03da
-#define GREG_MISC_OUTPUT_R 0x03cc
-#define GREG_MISC_OUTPUT_W 0x03c2
-#define GREG_FEATURE_CONTROL_R 0x03ca
-#define GREG_FEATURE_CONTROL_W 0x03da
-#define GREG_POS 0x0102
-
-/*
- * Attribute Controller
- */
-#define ACT_IDX 0x03C0
-#define ACT_ADDRESS_R 0x03C0
-#define ACT_DATA 0x03C0
-#define ACT_ADDRESS_RESET 0x03DA
-#define ACT_PALETTE0 0x00
-#define ACT_PALETTE1 0x01
-#define ACT_PALETTE2 0x02
-#define ACT_PALETTE3 0x03
-#define ACT_PALETTE4 0x04
-#define ACT_PALETTE5 0x05
-#define ACT_PALETTE6 0x06
-#define ACT_PALETTE7 0x07
-#define ACT_PALETTE8 0x08
-#define ACT_PALETTE9 0x09
-#define ACT_PALETTE10 0x0A
-#define ACT_PALETTE11 0x0B
-#define ACT_PALETTE12 0x0C
-#define ACT_PALETTE13 0x0D
-#define ACT_PALETTE14 0x0E
-#define ACT_PALETTE15 0x0F
-#define ACT_ATTR_MODE_CNTL 0x10
-#define ACT_OVERSCAN_COLOR 0x11
-#define ACT_COLOR_PLANE_ENA 0x12
-#define ACT_HOR_PEL_PANNING 0x13
-#define ACT_COLOR_SELECT 0x14
-
-/*
- * PLL
- */
-#define PLL_IDX 0x83c8
-#define PLL_DATA 0x83c9
-
-/*
- * Blitter operations
- */
-#define Z3BLTclear 0x00 /* 0 */
-#define Z3BLTand 0x80 /* src AND dst */
-#define Z3BLTandReverse 0x40 /* src AND NOT dst */
-#define Z3BLTcopy 0xc0 /* src */
-#define Z3BLTandInverted 0x20 /* NOT src AND dst */
-#define Z3BLTnoop 0xa0 /* dst */
-#define Z3BLTxor 0x60 /* src XOR dst */
-#define Z3BLTor 0xe0 /* src OR dst */
-#define Z3BLTnor 0x10 /* NOT src AND NOT dst */
-#define Z3BLTequiv 0x90 /* NOT src XOR dst */
-#define Z3BLTinvert 0x50 /* NOT dst */
-#define Z3BLTorReverse 0xd0 /* src OR NOT dst */
-#define Z3BLTcopyInverted 0x30 /* NOT src */
-#define Z3BLTorInverted 0xb0 /* NOT src OR dst */
-#define Z3BLTnand 0x70 /* NOT src OR NOT dst */
-#define Z3BLTset 0xf0 /* 1 */
diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c
index 1a13966b7d5..f8a3d608b20 100644
--- a/drivers/video/riva/fbdev.c
+++ b/drivers/video/riva/fbdev.c
@@ -282,7 +282,6 @@ static const struct riva_regs reg_template = {
static struct backlight_properties riva_bl_data;
-/* Call with fb_info->bl_mutex held */
static int riva_bl_get_level_brightness(struct riva_par *par,
int level)
{
@@ -290,6 +289,7 @@ static int riva_bl_get_level_brightness(struct riva_par *par,
int nlevel;
/* Get and convert the value */
+ /* No locking on bl_curve since accessing a single value */
nlevel = MIN_LEVEL + info->bl_curve[level] * LEVEL_STEP;
if (nlevel < 0)
@@ -302,18 +302,17 @@ static int riva_bl_get_level_brightness(struct riva_par *par,
return nlevel;
}
-/* Call with fb_info->bl_mutex held */
-static int __riva_bl_update_status(struct backlight_device *bd)
+static int riva_bl_update_status(struct backlight_device *bd)
{
struct riva_par *par = class_get_devdata(&bd->class_dev);
U032 tmp_pcrt, tmp_pmc;
int level;
- if (bd->props->power != FB_BLANK_UNBLANK ||
- bd->props->fb_blank != FB_BLANK_UNBLANK)
+ if (bd->props.power != FB_BLANK_UNBLANK ||
+ bd->props.fb_blank != FB_BLANK_UNBLANK)
level = 0;
else
- level = bd->props->brightness;
+ level = bd->props.brightness;
tmp_pmc = par->riva.PMC[0x10F0/4] & 0x0000FFFF;
tmp_pcrt = par->riva.PCRTC0[0x081C/4] & 0xFFFFFFFC;
@@ -328,45 +327,16 @@ static int __riva_bl_update_status(struct backlight_device *bd)
return 0;
}
-static int riva_bl_update_status(struct backlight_device *bd)
-{
- struct riva_par *par = class_get_devdata(&bd->class_dev);
- struct fb_info *info = pci_get_drvdata(par->pdev);
- int ret;
-
- mutex_lock(&info->bl_mutex);
- ret = __riva_bl_update_status(bd);
- mutex_unlock(&info->bl_mutex);
-
- return ret;
-}
-
static int riva_bl_get_brightness(struct backlight_device *bd)
{
- return bd->props->brightness;
+ return bd->props.brightness;
}
-static struct backlight_properties riva_bl_data = {
- .owner = THIS_MODULE,
+static struct backlight_ops riva_bl_ops = {
.get_brightness = riva_bl_get_brightness,
.update_status = riva_bl_update_status,
- .max_brightness = (FB_BACKLIGHT_LEVELS - 1),
};
-static void riva_bl_set_power(struct fb_info *info, int power)
-{
- mutex_lock(&info->bl_mutex);
-
- if (info->bl_dev) {
- down(&info->bl_dev->sem);
- info->bl_dev->props->power = power;
- __riva_bl_update_status(info->bl_dev);
- up(&info->bl_dev->sem);
- }
-
- mutex_unlock(&info->bl_mutex);
-}
-
static void riva_bl_init(struct riva_par *par)
{
struct fb_info *info = pci_get_drvdata(par->pdev);
@@ -384,32 +354,22 @@ static void riva_bl_init(struct riva_par *par)
snprintf(name, sizeof(name), "rivabl%d", info->node);
- bd = backlight_device_register(name, info->dev, par, &riva_bl_data);
+ bd = backlight_device_register(name, info->dev, par, &riva_bl_ops);
if (IS_ERR(bd)) {
info->bl_dev = NULL;
printk(KERN_WARNING "riva: Backlight registration failed\n");
goto error;
}
- mutex_lock(&info->bl_mutex);
info->bl_dev = bd;
fb_bl_default_curve(info, 0,
MIN_LEVEL * FB_BACKLIGHT_MAX / MAX_LEVEL,
FB_BACKLIGHT_MAX);
- mutex_unlock(&info->bl_mutex);
- down(&bd->sem);
- bd->props->brightness = riva_bl_data.max_brightness;
- bd->props->power = FB_BLANK_UNBLANK;
- bd->props->update_status(bd);
- up(&bd->sem);
-
-#ifdef CONFIG_PMAC_BACKLIGHT
- mutex_lock(&pmac_backlight_mutex);
- if (!pmac_backlight)
- pmac_backlight = bd;
- mutex_unlock(&pmac_backlight_mutex);
-#endif
+ bd->props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
+ bd->props.brightness = riva_bl_data.max_brightness;
+ bd->props.power = FB_BLANK_UNBLANK;
+ backlight_update_status(bd);
printk("riva: Backlight initialized (%s)\n", name);
@@ -419,35 +379,16 @@ error:
return;
}
-static void riva_bl_exit(struct riva_par *par)
+static void riva_bl_exit(struct fb_info *info)
{
- struct fb_info *info = pci_get_drvdata(par->pdev);
-
-#ifdef CONFIG_PMAC_BACKLIGHT
- mutex_lock(&pmac_backlight_mutex);
-#endif
-
- mutex_lock(&info->bl_mutex);
- if (info->bl_dev) {
-#ifdef CONFIG_PMAC_BACKLIGHT
- if (pmac_backlight == info->bl_dev)
- pmac_backlight = NULL;
-#endif
-
- backlight_device_unregister(info->bl_dev);
+ struct backlight_device *bd = info->bl_dev;
- printk("riva: Backlight unloaded\n");
- }
- mutex_unlock(&info->bl_mutex);
-
-#ifdef CONFIG_PMAC_BACKLIGHT
- mutex_unlock(&pmac_backlight_mutex);
-#endif
+ backlight_device_unregister(bd);
+ printk("riva: Backlight unloaded\n");
}
#else
static inline void riva_bl_init(struct riva_par *par) {}
-static inline void riva_bl_exit(struct riva_par *par) {}
-static inline void riva_bl_set_power(struct fb_info *info, int power) {}
+static inline void riva_bl_exit(struct fb_info *info) {}
#endif /* CONFIG_FB_RIVA_BACKLIGHT */
/* ------------------------------------------------------------------------- *
@@ -894,7 +835,8 @@ out:
return rc;
}
-static void riva_update_var(struct fb_var_screeninfo *var, struct fb_videomode *modedb)
+static void riva_update_var(struct fb_var_screeninfo *var,
+ const struct fb_videomode *modedb)
{
NVTRACE_ENTER();
var->xres = var->xres_virtual = modedb->xres;
@@ -1101,10 +1043,10 @@ static int riva_get_cmap_len(const struct fb_var_screeninfo *var)
static int rivafb_open(struct fb_info *info, int user)
{
struct riva_par *par = info->par;
- int cnt = atomic_read(&par->ref_count);
NVTRACE_ENTER();
- if (!cnt) {
+ mutex_lock(&par->open_lock);
+ if (!par->ref_count) {
#ifdef CONFIG_X86
memset(&par->state, 0, sizeof(struct vgastate));
par->state.flags = VGA_SAVE_MODE | VGA_SAVE_FONTS;
@@ -1119,7 +1061,8 @@ static int rivafb_open(struct fb_info *info, int user)
riva_save_state(par, &par->initial_state);
}
- atomic_inc(&par->ref_count);
+ par->ref_count++;
+ mutex_unlock(&par->open_lock);
NVTRACE_LEAVE();
return 0;
}
@@ -1127,12 +1070,14 @@ static int rivafb_open(struct fb_info *info, int user)
static int rivafb_release(struct fb_info *info, int user)
{
struct riva_par *par = info->par;
- int cnt = atomic_read(&par->ref_count);
NVTRACE_ENTER();
- if (!cnt)
+ mutex_lock(&par->open_lock);
+ if (!par->ref_count) {
+ mutex_unlock(&par->open_lock);
return -EINVAL;
- if (cnt == 1) {
+ }
+ if (par->ref_count == 1) {
par->riva.LockUnlock(&par->riva, 0);
par->riva.LoadStateExt(&par->riva, &par->initial_state.ext);
riva_load_state(par, &par->initial_state);
@@ -1141,14 +1086,15 @@ static int rivafb_release(struct fb_info *info, int user)
#endif
par->riva.LockUnlock(&par->riva, 1);
}
- atomic_dec(&par->ref_count);
+ par->ref_count--;
+ mutex_unlock(&par->open_lock);
NVTRACE_LEAVE();
return 0;
}
static int rivafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
{
- struct fb_videomode *mode;
+ const struct fb_videomode *mode;
struct riva_par *par = info->par;
int nom, den; /* translating from pixels->bytes */
int mode_valid = 0;
@@ -1343,8 +1289,6 @@ static int rivafb_blank(int blank, struct fb_info *info)
SEQout(par, 0x01, tmp);
CRTCout(par, 0x1a, vesa);
- riva_bl_set_power(info, blank);
-
NVTRACE_LEAVE();
return 0;
@@ -1980,12 +1924,11 @@ static int __devinit rivafb_probe(struct pci_dev *pd,
default_par = info->par;
default_par->pdev = pd;
- info->pixmap.addr = kmalloc(8 * 1024, GFP_KERNEL);
+ info->pixmap.addr = kzalloc(8 * 1024, GFP_KERNEL);
if (info->pixmap.addr == NULL) {
ret = -ENOMEM;
goto err_framebuffer_release;
}
- memset(info->pixmap.addr, 0, 8 * 1024);
ret = pci_enable_device(pd);
if (ret < 0) {
@@ -1999,6 +1942,7 @@ static int __devinit rivafb_probe(struct pci_dev *pd,
goto err_disable_device;
}
+ mutex_init(&default_par->open_lock);
default_par->riva.Architecture = riva_get_arch(pd);
default_par->Chipset = (pd->vendor << 16) | pd->device;
@@ -2161,14 +2105,15 @@ static void __exit rivafb_remove(struct pci_dev *pd)
NVTRACE_ENTER();
- riva_bl_exit(par);
-
#ifdef CONFIG_FB_RIVA_I2C
riva_delete_i2c_busses(par);
kfree(par->EDID);
#endif
unregister_framebuffer(info);
+
+ riva_bl_exit(info);
+
#ifdef CONFIG_MTRR
if (par->mtrr.vram_valid)
mtrr_del(par->mtrr.vram, info->fix.smem_start,
diff --git a/drivers/video/riva/rivafb-i2c.c b/drivers/video/riva/rivafb-i2c.c
index 01b85e3b0ae..0405e839ff9 100644
--- a/drivers/video/riva/rivafb-i2c.c
+++ b/drivers/video/riva/rivafb-i2c.c
@@ -14,7 +14,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/fb.h>
diff --git a/drivers/video/riva/rivafb.h b/drivers/video/riva/rivafb.h
index 7fa13fc9c41..48ead6d72f2 100644
--- a/drivers/video/riva/rivafb.h
+++ b/drivers/video/riva/rivafb.h
@@ -53,7 +53,8 @@ struct riva_par {
#ifdef CONFIG_X86
struct vgastate state;
#endif
- atomic_t ref_count;
+ struct mutex open_lock;
+ unsigned int ref_count;
unsigned char *EDID;
unsigned int Chipset;
int forceCRTC;
diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c
index ccef56d0c15..ed3426062a8 100644
--- a/drivers/video/s3c2410fb.c
+++ b/drivers/video/s3c2410fb.c
@@ -791,6 +791,8 @@ static int __init s3c2410fb_probe(struct platform_device *pdev)
info = fbinfo->par;
info->fb = fbinfo;
+ info->dev = &pdev->dev;
+
platform_set_drvdata(pdev, fbinfo);
dprintk("devinit\n");
diff --git a/drivers/video/s3fb.c b/drivers/video/s3fb.c
new file mode 100644
index 00000000000..3162c37b144
--- /dev/null
+++ b/drivers/video/s3fb.c
@@ -0,0 +1,1180 @@
+/*
+ * linux/drivers/video/s3fb.c -- Frame buffer device driver for S3 Trio/Virge
+ *
+ * Copyright (c) 2006-2007 Ondrej Zajicek <santiago@crfreenet.org>
+ *
+ * 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.
+ *
+ * Code is based on David Boucher's viafb (http://davesdomain.org.uk/viafb/)
+ * which is based on the code of neofb.
+ */
+
+#include <linux/version.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/svga.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/console.h> /* Why should fb driver call console functions? because acquire_console_sem() */
+#include <video/vga.h>
+
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+
+struct s3fb_info {
+ int chip, rev, mclk_freq;
+ int mtrr_reg;
+ struct vgastate state;
+ struct mutex open_lock;
+ unsigned int ref_count;
+ u32 pseudo_palette[16];
+};
+
+
+/* ------------------------------------------------------------------------- */
+
+static const struct svga_fb_format s3fb_formats[] = {
+ { 0, {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 0,
+ FB_TYPE_TEXT, FB_AUX_TEXT_SVGA_STEP4, FB_VISUAL_PSEUDOCOLOR, 8, 16},
+ { 4, {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 0,
+ FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_PSEUDOCOLOR, 8, 16},
+ { 4, {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 1,
+ FB_TYPE_INTERLEAVED_PLANES, 1, FB_VISUAL_PSEUDOCOLOR, 8, 16},
+ { 8, {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 0,
+ FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_PSEUDOCOLOR, 4, 8},
+ {16, {10, 5, 0}, {5, 5, 0}, {0, 5, 0}, {0, 0, 0}, 0,
+ FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_TRUECOLOR, 2, 4},
+ {16, {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, 0,
+ FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_TRUECOLOR, 2, 4},
+ {24, {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {0, 0, 0}, 0,
+ FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_TRUECOLOR, 1, 2},
+ {32, {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {0, 0, 0}, 0,
+ FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_TRUECOLOR, 1, 2},
+ SVGA_FORMAT_END
+};
+
+
+static const struct svga_pll s3_pll = {3, 129, 3, 33, 0, 3,
+ 60000, 240000, 14318};
+
+static const int s3_memsizes[] = {4096, 0, 3072, 8192, 2048, 6144, 1024, 512};
+
+static const char * const s3_names[] = {"S3 Unknown", "S3 Trio32", "S3 Trio64", "S3 Trio64V+",
+ "S3 Trio64UV+", "S3 Trio64V2/DX", "S3 Trio64V2/GX",
+ "S3 Plato/PX", "S3 Aurora64VP", "S3 Virge",
+ "S3 Virge/VX", "S3 Virge/DX", "S3 Virge/GX",
+ "S3 Virge/GX2", "S3 Virge/GX2P", "S3 Virge/GX2P"};
+
+#define CHIP_UNKNOWN 0x00
+#define CHIP_732_TRIO32 0x01
+#define CHIP_764_TRIO64 0x02
+#define CHIP_765_TRIO64VP 0x03
+#define CHIP_767_TRIO64UVP 0x04
+#define CHIP_775_TRIO64V2_DX 0x05
+#define CHIP_785_TRIO64V2_GX 0x06
+#define CHIP_551_PLATO_PX 0x07
+#define CHIP_M65_AURORA64VP 0x08
+#define CHIP_325_VIRGE 0x09
+#define CHIP_988_VIRGE_VX 0x0A
+#define CHIP_375_VIRGE_DX 0x0B
+#define CHIP_385_VIRGE_GX 0x0C
+#define CHIP_356_VIRGE_GX2 0x0D
+#define CHIP_357_VIRGE_GX2P 0x0E
+#define CHIP_359_VIRGE_GX2P 0x0F
+
+#define CHIP_XXX_TRIO 0x80
+#define CHIP_XXX_TRIO64V2_DXGX 0x81
+#define CHIP_XXX_VIRGE_DXGX 0x82
+
+#define CHIP_UNDECIDED_FLAG 0x80
+#define CHIP_MASK 0xFF
+
+/* CRT timing register sets */
+
+static const struct vga_regset s3_h_total_regs[] = {{0x00, 0, 7}, {0x5D, 0, 0}, VGA_REGSET_END};
+static const struct vga_regset s3_h_display_regs[] = {{0x01, 0, 7}, {0x5D, 1, 1}, VGA_REGSET_END};
+static const struct vga_regset s3_h_blank_start_regs[] = {{0x02, 0, 7}, {0x5D, 2, 2}, VGA_REGSET_END};
+static const struct vga_regset s3_h_blank_end_regs[] = {{0x03, 0, 4}, {0x05, 7, 7}, VGA_REGSET_END};
+static const struct vga_regset s3_h_sync_start_regs[] = {{0x04, 0, 7}, {0x5D, 4, 4}, VGA_REGSET_END};
+static const struct vga_regset s3_h_sync_end_regs[] = {{0x05, 0, 4}, VGA_REGSET_END};
+
+static const struct vga_regset s3_v_total_regs[] = {{0x06, 0, 7}, {0x07, 0, 0}, {0x07, 5, 5}, {0x5E, 0, 0}, VGA_REGSET_END};
+static const struct vga_regset s3_v_display_regs[] = {{0x12, 0, 7}, {0x07, 1, 1}, {0x07, 6, 6}, {0x5E, 1, 1}, VGA_REGSET_END};
+static const struct vga_regset s3_v_blank_start_regs[] = {{0x15, 0, 7}, {0x07, 3, 3}, {0x09, 5, 5}, {0x5E, 2, 2}, VGA_REGSET_END};
+static const struct vga_regset s3_v_blank_end_regs[] = {{0x16, 0, 7}, VGA_REGSET_END};
+static const struct vga_regset s3_v_sync_start_regs[] = {{0x10, 0, 7}, {0x07, 2, 2}, {0x07, 7, 7}, {0x5E, 4, 4}, VGA_REGSET_END};
+static const struct vga_regset s3_v_sync_end_regs[] = {{0x11, 0, 3}, VGA_REGSET_END};
+
+static const struct vga_regset s3_line_compare_regs[] = {{0x18, 0, 7}, {0x07, 4, 4}, {0x09, 6, 6}, {0x5E, 6, 6}, VGA_REGSET_END};
+static const struct vga_regset s3_start_address_regs[] = {{0x0d, 0, 7}, {0x0c, 0, 7}, {0x31, 4, 5}, {0x51, 0, 1}, VGA_REGSET_END};
+static const struct vga_regset s3_offset_regs[] = {{0x13, 0, 7}, {0x51, 4, 5}, VGA_REGSET_END}; /* set 0x43 bit 2 to 0 */
+
+static const struct svga_timing_regs s3_timing_regs = {
+ s3_h_total_regs, s3_h_display_regs, s3_h_blank_start_regs,
+ s3_h_blank_end_regs, s3_h_sync_start_regs, s3_h_sync_end_regs,
+ s3_v_total_regs, s3_v_display_regs, s3_v_blank_start_regs,
+ s3_v_blank_end_regs, s3_v_sync_start_regs, s3_v_sync_end_regs,
+};
+
+
+/* ------------------------------------------------------------------------- */
+
+/* Module parameters */
+
+
+static char *mode = "640x480-8@60";
+
+#ifdef CONFIG_MTRR
+static int mtrr = 1;
+#endif
+
+static int fasttext = 1;
+
+
+MODULE_AUTHOR("(c) 2006-2007 Ondrej Zajicek <santiago@crfreenet.org>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("fbdev driver for S3 Trio/Virge");
+
+module_param(mode, charp, 0444);
+MODULE_PARM_DESC(mode, "Default video mode ('640x480-8@60', etc)");
+
+#ifdef CONFIG_MTRR
+module_param(mtrr, int, 0444);
+MODULE_PARM_DESC(mtrr, "Enable write-combining with MTRR (1=enable, 0=disable, default=1)");
+#endif
+
+module_param(fasttext, int, 0644);
+MODULE_PARM_DESC(fasttext, "Enable S3 fast text mode (1=enable, 0=disable, default=1)");
+
+
+/* ------------------------------------------------------------------------- */
+
+/* Set font in S3 fast text mode */
+
+static void s3fb_settile_fast(struct fb_info *info, struct fb_tilemap *map)
+{
+ const u8 *font = map->data;
+ u8* fb = (u8 *) info->screen_base;
+ int i, c;
+
+ if ((map->width != 8) || (map->height != 16) ||
+ (map->depth != 1) || (map->length != 256)) {
+ printk(KERN_ERR "fb%d: unsupported font parameters: width %d, height %d, depth %d, length %d\n",
+ info->node, map->width, map->height, map->depth, map->length);
+ return;
+ }
+
+ fb += 2;
+ for (i = 0; i < map->height; i++) {
+ for (c = 0; c < map->length; c++) {
+ fb[c * 4] = font[c * map->height + i];
+ }
+ fb += 1024;
+ }
+}
+
+
+
+static struct fb_tile_ops s3fb_tile_ops = {
+ .fb_settile = svga_settile,
+ .fb_tilecopy = svga_tilecopy,
+ .fb_tilefill = svga_tilefill,
+ .fb_tileblit = svga_tileblit,
+ .fb_tilecursor = svga_tilecursor,
+};
+
+static struct fb_tile_ops s3fb_fast_tile_ops = {
+ .fb_settile = s3fb_settile_fast,
+ .fb_tilecopy = svga_tilecopy,
+ .fb_tilefill = svga_tilefill,
+ .fb_tileblit = svga_tileblit,
+ .fb_tilecursor = svga_tilecursor,
+};
+
+
+/* ------------------------------------------------------------------------- */
+
+/* image data is MSB-first, fb structure is MSB-first too */
+static inline u32 expand_color(u32 c)
+{
+ return ((c & 1) | ((c & 2) << 7) | ((c & 4) << 14) | ((c & 8) << 21)) * 0xFF;
+}
+
+/* s3fb_iplan_imageblit silently assumes that almost everything is 8-pixel aligned */
+static void s3fb_iplan_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+ u32 fg = expand_color(image->fg_color);
+ u32 bg = expand_color(image->bg_color);
+ const u8 *src1, *src;
+ u8 __iomem *dst1;
+ u32 __iomem *dst;
+ u32 val;
+ int x, y;
+
+ src1 = image->data;
+ dst1 = info->screen_base + (image->dy * info->fix.line_length)
+ + ((image->dx / 8) * 4);
+
+ for (y = 0; y < image->height; y++) {
+ src = src1;
+ dst = (u32 __iomem *) dst1;
+ for (x = 0; x < image->width; x += 8) {
+ val = *(src++) * 0x01010101;
+ val = (val & fg) | (~val & bg);
+ fb_writel(val, dst++);
+ }
+ src1 += image->width / 8;
+ dst1 += info->fix.line_length;
+ }
+
+}
+
+/* s3fb_iplan_fillrect silently assumes that almost everything is 8-pixel aligned */
+static void s3fb_iplan_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+{
+ u32 fg = expand_color(rect->color);
+ u8 __iomem *dst1;
+ u32 __iomem *dst;
+ int x, y;
+
+ dst1 = info->screen_base + (rect->dy * info->fix.line_length)
+ + ((rect->dx / 8) * 4);
+
+ for (y = 0; y < rect->height; y++) {
+ dst = (u32 __iomem *) dst1;
+ for (x = 0; x < rect->width; x += 8) {
+ fb_writel(fg, dst++);
+ }
+ dst1 += info->fix.line_length;
+ }
+}
+
+
+/* image data is MSB-first, fb structure is high-nibble-in-low-byte-first */
+static inline u32 expand_pixel(u32 c)
+{
+ return (((c & 1) << 24) | ((c & 2) << 27) | ((c & 4) << 14) | ((c & 8) << 17) |
+ ((c & 16) << 4) | ((c & 32) << 7) | ((c & 64) >> 6) | ((c & 128) >> 3)) * 0xF;
+}
+
+/* s3fb_cfb4_imageblit silently assumes that almost everything is 8-pixel aligned */
+static void s3fb_cfb4_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+ u32 fg = image->fg_color * 0x11111111;
+ u32 bg = image->bg_color * 0x11111111;
+ const u8 *src1, *src;
+ u8 __iomem *dst1;
+ u32 __iomem *dst;
+ u32 val;
+ int x, y;
+
+ src1 = image->data;
+ dst1 = info->screen_base + (image->dy * info->fix.line_length)
+ + ((image->dx / 8) * 4);
+
+ for (y = 0; y < image->height; y++) {
+ src = src1;
+ dst = (u32 __iomem *) dst1;
+ for (x = 0; x < image->width; x += 8) {
+ val = expand_pixel(*(src++));
+ val = (val & fg) | (~val & bg);
+ fb_writel(val, dst++);
+ }
+ src1 += image->width / 8;
+ dst1 += info->fix.line_length;
+ }
+}
+
+static void s3fb_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+ if ((info->var.bits_per_pixel == 4) && (image->depth == 1)
+ && ((image->width % 8) == 0) && ((image->dx % 8) == 0)) {
+ if (info->fix.type == FB_TYPE_INTERLEAVED_PLANES)
+ s3fb_iplan_imageblit(info, image);
+ else
+ s3fb_cfb4_imageblit(info, image);
+ } else
+ cfb_imageblit(info, image);
+}
+
+static void s3fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+{
+ if ((info->var.bits_per_pixel == 4)
+ && ((rect->width % 8) == 0) && ((rect->dx % 8) == 0)
+ && (info->fix.type == FB_TYPE_INTERLEAVED_PLANES))
+ s3fb_iplan_fillrect(info, rect);
+ else
+ cfb_fillrect(info, rect);
+}
+
+
+
+/* ------------------------------------------------------------------------- */
+
+
+static void s3_set_pixclock(struct fb_info *info, u32 pixclock)
+{
+ u16 m, n, r;
+ u8 regval;
+
+ svga_compute_pll(&s3_pll, 1000000000 / pixclock, &m, &n, &r, info->node);
+
+ /* Set VGA misc register */
+ regval = vga_r(NULL, VGA_MIS_R);
+ vga_w(NULL, VGA_MIS_W, regval | VGA_MIS_ENB_PLL_LOAD);
+
+ /* Set S3 clock registers */
+ vga_wseq(NULL, 0x12, ((n - 2) | (r << 5)));
+ vga_wseq(NULL, 0x13, m - 2);
+
+ udelay(1000);
+
+ /* Activate clock - write 0, 1, 0 to seq/15 bit 5 */
+ regval = vga_rseq (NULL, 0x15); /* | 0x80; */
+ vga_wseq(NULL, 0x15, regval & ~(1<<5));
+ vga_wseq(NULL, 0x15, regval | (1<<5));
+ vga_wseq(NULL, 0x15, regval & ~(1<<5));
+}
+
+
+/* Open framebuffer */
+
+static int s3fb_open(struct fb_info *info, int user)
+{
+ struct s3fb_info *par = info->par;
+
+ mutex_lock(&(par->open_lock));
+ if (par->ref_count == 0) {
+ memset(&(par->state), 0, sizeof(struct vgastate));
+ par->state.flags = VGA_SAVE_MODE | VGA_SAVE_FONTS | VGA_SAVE_CMAP;
+ par->state.num_crtc = 0x70;
+ par->state.num_seq = 0x20;
+ save_vga(&(par->state));
+ }
+
+ par->ref_count++;
+ mutex_unlock(&(par->open_lock));
+
+ return 0;
+}
+
+/* Close framebuffer */
+
+static int s3fb_release(struct fb_info *info, int user)
+{
+ struct s3fb_info *par = info->par;
+
+ mutex_lock(&(par->open_lock));
+ if (par->ref_count == 0) {
+ mutex_unlock(&(par->open_lock));
+ return -EINVAL;
+ }
+
+ if (par->ref_count == 1)
+ restore_vga(&(par->state));
+
+ par->ref_count--;
+ mutex_unlock(&(par->open_lock));
+
+ return 0;
+}
+
+/* Validate passed in var */
+
+static int s3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ struct s3fb_info *par = info->par;
+ int rv, mem, step;
+
+ /* Find appropriate format */
+ rv = svga_match_format (s3fb_formats, var, NULL);
+ if ((rv < 0) || ((par->chip == CHIP_988_VIRGE_VX) ? (rv == 7) : (rv == 6)))
+ { /* 24bpp on VIRGE VX, 32bpp on others */
+ printk(KERN_ERR "fb%d: unsupported mode requested\n", info->node);
+ return rv;
+ }
+
+ /* Do not allow to have real resoulution larger than virtual */
+ if (var->xres > var->xres_virtual)
+ var->xres_virtual = var->xres;
+
+ if (var->yres > var->yres_virtual)
+ var->yres_virtual = var->yres;
+
+ /* Round up xres_virtual to have proper alignment of lines */
+ step = s3fb_formats[rv].xresstep - 1;
+ var->xres_virtual = (var->xres_virtual+step) & ~step;
+
+ /* Check whether have enough memory */
+ mem = ((var->bits_per_pixel * var->xres_virtual) >> 3) * var->yres_virtual;
+ if (mem > info->screen_size)
+ {
+ printk(KERN_ERR "fb%d: not enough framebuffer memory (%d kB requested , %d kB available)\n",
+ info->node, mem >> 10, (unsigned int) (info->screen_size >> 10));
+ return -EINVAL;
+ }
+
+ rv = svga_check_timings (&s3_timing_regs, var, info->node);
+ if (rv < 0)
+ {
+ printk(KERN_ERR "fb%d: invalid timings requested\n", info->node);
+ return rv;
+ }
+
+ return 0;
+}
+
+/* Set video mode from par */
+
+static int s3fb_set_par(struct fb_info *info)
+{
+ struct s3fb_info *par = info->par;
+ u32 value, mode, hmul, offset_value, screen_size, multiplex;
+ u32 bpp = info->var.bits_per_pixel;
+
+ if (bpp != 0) {
+ info->fix.ypanstep = 1;
+ info->fix.line_length = (info->var.xres_virtual * bpp) / 8;
+
+ info->flags &= ~FBINFO_MISC_TILEBLITTING;
+ info->tileops = NULL;
+
+ offset_value = (info->var.xres_virtual * bpp) / 64;
+ screen_size = info->var.yres_virtual * info->fix.line_length;
+ } else {
+ info->fix.ypanstep = 16;
+ info->fix.line_length = 0;
+
+ info->flags |= FBINFO_MISC_TILEBLITTING;
+ info->tileops = fasttext ? &s3fb_fast_tile_ops : &s3fb_tile_ops;
+
+ offset_value = info->var.xres_virtual / 16;
+ screen_size = (info->var.xres_virtual * info->var.yres_virtual) / 64;
+ }
+
+ info->var.xoffset = 0;
+ info->var.yoffset = 0;
+ info->var.activate = FB_ACTIVATE_NOW;
+
+ /* Unlock registers */
+ vga_wcrt(NULL, 0x38, 0x48);
+ vga_wcrt(NULL, 0x39, 0xA5);
+ vga_wseq(NULL, 0x08, 0x06);
+ svga_wcrt_mask(0x11, 0x00, 0x80);
+
+ /* Blank screen and turn off sync */
+ svga_wseq_mask(0x01, 0x20, 0x20);
+ svga_wcrt_mask(0x17, 0x00, 0x80);
+
+ /* Set default values */
+ svga_set_default_gfx_regs();
+ svga_set_default_atc_regs();
+ svga_set_default_seq_regs();
+ svga_set_default_crt_regs();
+ svga_wcrt_multi(s3_line_compare_regs, 0xFFFFFFFF);
+ svga_wcrt_multi(s3_start_address_regs, 0);
+
+ /* S3 specific initialization */
+ svga_wcrt_mask(0x58, 0x10, 0x10); /* enable linear framebuffer */
+ svga_wcrt_mask(0x31, 0x08, 0x08); /* enable sequencer access to framebuffer above 256 kB */
+
+/* svga_wcrt_mask(0x33, 0x08, 0x08); */ /* DDR ? */
+/* svga_wcrt_mask(0x43, 0x01, 0x01); */ /* DDR ? */
+ svga_wcrt_mask(0x33, 0x00, 0x08); /* no DDR ? */
+ svga_wcrt_mask(0x43, 0x00, 0x01); /* no DDR ? */
+
+ svga_wcrt_mask(0x5D, 0x00, 0x28); // Clear strange HSlen bits
+
+/* svga_wcrt_mask(0x58, 0x03, 0x03); */
+
+/* svga_wcrt_mask(0x53, 0x12, 0x13); */ /* enable MMIO */
+/* svga_wcrt_mask(0x40, 0x08, 0x08); */ /* enable write buffer */
+
+
+ /* Set the offset register */
+ pr_debug("fb%d: offset register : %d\n", info->node, offset_value);
+ svga_wcrt_multi(s3_offset_regs, offset_value);
+
+ vga_wcrt(NULL, 0x54, 0x18); /* M parameter */
+ vga_wcrt(NULL, 0x60, 0xff); /* N parameter */
+ vga_wcrt(NULL, 0x61, 0xff); /* L parameter */
+ vga_wcrt(NULL, 0x62, 0xff); /* L parameter */
+
+ vga_wcrt(NULL, 0x3A, 0x35);
+ svga_wattr(0x33, 0x00);
+
+ if (info->var.vmode & FB_VMODE_DOUBLE)
+ svga_wcrt_mask(0x09, 0x80, 0x80);
+ else
+ svga_wcrt_mask(0x09, 0x00, 0x80);
+
+ if (info->var.vmode & FB_VMODE_INTERLACED)
+ svga_wcrt_mask(0x42, 0x20, 0x20);
+ else
+ svga_wcrt_mask(0x42, 0x00, 0x20);
+
+ /* Disable hardware graphics cursor */
+ svga_wcrt_mask(0x45, 0x00, 0x01);
+ /* Disable Streams engine */
+ svga_wcrt_mask(0x67, 0x00, 0x0C);
+
+ mode = svga_match_format(s3fb_formats, &(info->var), &(info->fix));
+
+ /* S3 virge DX hack */
+ if (par->chip == CHIP_375_VIRGE_DX) {
+ vga_wcrt(NULL, 0x86, 0x80);
+ vga_wcrt(NULL, 0x90, 0x00);
+ }
+
+ /* S3 virge VX hack */
+ if (par->chip == CHIP_988_VIRGE_VX) {
+ vga_wcrt(NULL, 0x50, 0x00);
+ vga_wcrt(NULL, 0x67, 0x50);
+
+ vga_wcrt(NULL, 0x63, (mode <= 2) ? 0x90 : 0x09);
+ vga_wcrt(NULL, 0x66, 0x90);
+ }
+
+ svga_wcrt_mask(0x31, 0x00, 0x40);
+ multiplex = 0;
+ hmul = 1;
+
+ /* Set mode-specific register values */
+ switch (mode) {
+ case 0:
+ pr_debug("fb%d: text mode\n", info->node);
+ svga_set_textmode_vga_regs();
+
+ /* Set additional registers like in 8-bit mode */
+ svga_wcrt_mask(0x50, 0x00, 0x30);
+ svga_wcrt_mask(0x67, 0x00, 0xF0);
+
+ /* Disable enhanced mode */
+ svga_wcrt_mask(0x3A, 0x00, 0x30);
+
+ if (fasttext) {
+ pr_debug("fb%d: high speed text mode set\n", info->node);
+ svga_wcrt_mask(0x31, 0x40, 0x40);
+ }
+ break;
+ case 1:
+ pr_debug("fb%d: 4 bit pseudocolor\n", info->node);
+ vga_wgfx(NULL, VGA_GFX_MODE, 0x40);
+
+ /* Set additional registers like in 8-bit mode */
+ svga_wcrt_mask(0x50, 0x00, 0x30);
+ svga_wcrt_mask(0x67, 0x00, 0xF0);
+
+ /* disable enhanced mode */
+ svga_wcrt_mask(0x3A, 0x00, 0x30);
+ break;
+ case 2:
+ pr_debug("fb%d: 4 bit pseudocolor, planar\n", info->node);
+
+ /* Set additional registers like in 8-bit mode */
+ svga_wcrt_mask(0x50, 0x00, 0x30);
+ svga_wcrt_mask(0x67, 0x00, 0xF0);
+
+ /* disable enhanced mode */
+ svga_wcrt_mask(0x3A, 0x00, 0x30);
+ break;
+ case 3:
+ pr_debug("fb%d: 8 bit pseudocolor\n", info->node);
+ if (info->var.pixclock > 20000) {
+ svga_wcrt_mask(0x50, 0x00, 0x30);
+ svga_wcrt_mask(0x67, 0x00, 0xF0);
+ } else {
+ svga_wcrt_mask(0x50, 0x00, 0x30);
+ svga_wcrt_mask(0x67, 0x10, 0xF0);
+ multiplex = 1;
+ }
+ break;
+ case 4:
+ pr_debug("fb%d: 5/5/5 truecolor\n", info->node);
+ if (par->chip == CHIP_988_VIRGE_VX) {
+ if (info->var.pixclock > 20000)
+ svga_wcrt_mask(0x67, 0x20, 0xF0);
+ else
+ svga_wcrt_mask(0x67, 0x30, 0xF0);
+ } else {
+ svga_wcrt_mask(0x50, 0x10, 0x30);
+ svga_wcrt_mask(0x67, 0x30, 0xF0);
+ hmul = 2;
+ }
+ break;
+ case 5:
+ pr_debug("fb%d: 5/6/5 truecolor\n", info->node);
+ if (par->chip == CHIP_988_VIRGE_VX) {
+ if (info->var.pixclock > 20000)
+ svga_wcrt_mask(0x67, 0x40, 0xF0);
+ else
+ svga_wcrt_mask(0x67, 0x50, 0xF0);
+ } else {
+ svga_wcrt_mask(0x50, 0x10, 0x30);
+ svga_wcrt_mask(0x67, 0x50, 0xF0);
+ hmul = 2;
+ }
+ break;
+ case 6:
+ /* VIRGE VX case */
+ pr_debug("fb%d: 8/8/8 truecolor\n", info->node);
+ svga_wcrt_mask(0x67, 0xD0, 0xF0);
+ break;
+ case 7:
+ pr_debug("fb%d: 8/8/8/8 truecolor\n", info->node);
+ svga_wcrt_mask(0x50, 0x30, 0x30);
+ svga_wcrt_mask(0x67, 0xD0, 0xF0);
+ break;
+ default:
+ printk(KERN_ERR "fb%d: unsupported mode - bug\n", info->node);
+ return -EINVAL;
+ }
+
+ if (par->chip != CHIP_988_VIRGE_VX) {
+ svga_wseq_mask(0x15, multiplex ? 0x10 : 0x00, 0x10);
+ svga_wseq_mask(0x18, multiplex ? 0x80 : 0x00, 0x80);
+ }
+
+ s3_set_pixclock(info, info->var.pixclock);
+ svga_set_timings(&s3_timing_regs, &(info->var), hmul, 1,
+ (info->var.vmode & FB_VMODE_DOUBLE) ? 2 : 1,
+ (info->var.vmode & FB_VMODE_INTERLACED) ? 2 : 1,
+ hmul, info->node);
+
+ /* Set interlaced mode start/end register */
+ value = info->var.xres + info->var.left_margin + info->var.right_margin + info->var.hsync_len;
+ value = ((value * hmul) / 8) - 5;
+ vga_wcrt(NULL, 0x3C, (value + 1) / 2);
+
+ memset((u8*)info->screen_base, 0x00, screen_size);
+ /* Device and screen back on */
+ svga_wcrt_mask(0x17, 0x80, 0x80);
+ svga_wseq_mask(0x01, 0x00, 0x20);
+
+ return 0;
+}
+
+/* Set a colour register */
+
+static int s3fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+ u_int transp, struct fb_info *fb)
+{
+ switch (fb->var.bits_per_pixel) {
+ case 0:
+ case 4:
+ if (regno >= 16)
+ return -EINVAL;
+
+ if ((fb->var.bits_per_pixel == 4) &&
+ (fb->var.nonstd == 0)) {
+ outb(0xF0, VGA_PEL_MSK);
+ outb(regno*16, VGA_PEL_IW);
+ } else {
+ outb(0x0F, VGA_PEL_MSK);
+ outb(regno, VGA_PEL_IW);
+ }
+ outb(red >> 10, VGA_PEL_D);
+ outb(green >> 10, VGA_PEL_D);
+ outb(blue >> 10, VGA_PEL_D);
+ break;
+ case 8:
+ if (regno >= 256)
+ return -EINVAL;
+
+ outb(0xFF, VGA_PEL_MSK);
+ outb(regno, VGA_PEL_IW);
+ outb(red >> 10, VGA_PEL_D);
+ outb(green >> 10, VGA_PEL_D);
+ outb(blue >> 10, VGA_PEL_D);
+ break;
+ case 16:
+ if (regno >= 16)
+ return -EINVAL;
+
+ if (fb->var.green.length == 5)
+ ((u32*)fb->pseudo_palette)[regno] = ((red & 0xF800) >> 1) |
+ ((green & 0xF800) >> 6) | ((blue & 0xF800) >> 11);
+ else if (fb->var.green.length == 6)
+ ((u32*)fb->pseudo_palette)[regno] = (red & 0xF800) |
+ ((green & 0xFC00) >> 5) | ((blue & 0xF800) >> 11);
+ else return -EINVAL;
+ break;
+ case 24:
+ case 32:
+ if (regno >= 16)
+ return -EINVAL;
+
+ ((u32*)fb->pseudo_palette)[regno] = ((transp & 0xFF00) << 16) | ((red & 0xFF00) << 8) |
+ (green & 0xFF00) | ((blue & 0xFF00) >> 8);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+
+/* Set the display blanking state */
+
+static int s3fb_blank(int blank_mode, struct fb_info *info)
+{
+ switch (blank_mode) {
+ case FB_BLANK_UNBLANK:
+ pr_debug("fb%d: unblank\n", info->node);
+ svga_wcrt_mask(0x56, 0x00, 0x06);
+ svga_wseq_mask(0x01, 0x00, 0x20);
+ break;
+ case FB_BLANK_NORMAL:
+ pr_debug("fb%d: blank\n", info->node);
+ svga_wcrt_mask(0x56, 0x00, 0x06);
+ svga_wseq_mask(0x01, 0x20, 0x20);
+ break;
+ case FB_BLANK_HSYNC_SUSPEND:
+ pr_debug("fb%d: hsync\n", info->node);
+ svga_wcrt_mask(0x56, 0x02, 0x06);
+ svga_wseq_mask(0x01, 0x20, 0x20);
+ break;
+ case FB_BLANK_VSYNC_SUSPEND:
+ pr_debug("fb%d: vsync\n", info->node);
+ svga_wcrt_mask(0x56, 0x04, 0x06);
+ svga_wseq_mask(0x01, 0x20, 0x20);
+ break;
+ case FB_BLANK_POWERDOWN:
+ pr_debug("fb%d: sync down\n", info->node);
+ svga_wcrt_mask(0x56, 0x06, 0x06);
+ svga_wseq_mask(0x01, 0x20, 0x20);
+ break;
+ }
+
+ return 0;
+}
+
+
+/* Pan the display */
+
+static int s3fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) {
+
+ unsigned int offset;
+
+ /* Validate the offsets */
+ if ((var->xoffset + var->xres) > var->xres_virtual)
+ return -EINVAL;
+ if ((var->yoffset + var->yres) > var->yres_virtual)
+ return -EINVAL;
+
+ /* Calculate the offset */
+ if (var->bits_per_pixel == 0) {
+ offset = (var->yoffset / 16) * (var->xres_virtual / 2) + (var->xoffset / 2);
+ offset = offset >> 2;
+ } else {
+ offset = (var->yoffset * info->fix.line_length) +
+ (var->xoffset * var->bits_per_pixel / 8);
+ offset = offset >> 2;
+ }
+
+ /* Set the offset */
+ svga_wcrt_multi(s3_start_address_regs, offset);
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* Frame buffer operations */
+
+static struct fb_ops s3fb_ops = {
+ .owner = THIS_MODULE,
+ .fb_open = s3fb_open,
+ .fb_release = s3fb_release,
+ .fb_check_var = s3fb_check_var,
+ .fb_set_par = s3fb_set_par,
+ .fb_setcolreg = s3fb_setcolreg,
+ .fb_blank = s3fb_blank,
+ .fb_pan_display = s3fb_pan_display,
+ .fb_fillrect = s3fb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = s3fb_imageblit,
+};
+
+/* ------------------------------------------------------------------------- */
+
+static int __devinit s3_identification(int chip)
+{
+ if (chip == CHIP_XXX_TRIO) {
+ u8 cr30 = vga_rcrt(NULL, 0x30);
+ u8 cr2e = vga_rcrt(NULL, 0x2e);
+ u8 cr2f = vga_rcrt(NULL, 0x2f);
+
+ if ((cr30 == 0xE0) || (cr30 == 0xE1)) {
+ if (cr2e == 0x10)
+ return CHIP_732_TRIO32;
+ if (cr2e == 0x11) {
+ if (! (cr2f & 0x40))
+ return CHIP_764_TRIO64;
+ else
+ return CHIP_765_TRIO64VP;
+ }
+ }
+ }
+
+ if (chip == CHIP_XXX_TRIO64V2_DXGX) {
+ u8 cr6f = vga_rcrt(NULL, 0x6f);
+
+ if (! (cr6f & 0x01))
+ return CHIP_775_TRIO64V2_DX;
+ else
+ return CHIP_785_TRIO64V2_GX;
+ }
+
+ if (chip == CHIP_XXX_VIRGE_DXGX) {
+ u8 cr6f = vga_rcrt(NULL, 0x6f);
+
+ if (! (cr6f & 0x01))
+ return CHIP_375_VIRGE_DX;
+ else
+ return CHIP_385_VIRGE_GX;
+ }
+
+ return CHIP_UNKNOWN;
+}
+
+
+/* PCI probe */
+
+static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ struct fb_info *info;
+ struct s3fb_info *par;
+ int rc;
+ u8 regval, cr38, cr39;
+
+ /* Ignore secondary VGA device because there is no VGA arbitration */
+ if (! svga_primary_device(dev)) {
+ dev_info(&(dev->dev), "ignoring secondary device\n");
+ return -ENODEV;
+ }
+
+ /* Allocate and fill driver data structure */
+ info = framebuffer_alloc(sizeof(struct s3fb_info), NULL);
+ if (!info) {
+ dev_err(&(dev->dev), "cannot allocate memory\n");
+ return -ENOMEM;
+ }
+
+ par = info->par;
+ mutex_init(&par->open_lock);
+
+ info->flags = FBINFO_PARTIAL_PAN_OK | FBINFO_HWACCEL_YPAN;
+ info->fbops = &s3fb_ops;
+
+ /* Prepare PCI device */
+ rc = pci_enable_device(dev);
+ if (rc < 0) {
+ dev_err(&(dev->dev), "cannot enable PCI device\n");
+ goto err_enable_device;
+ }
+
+ rc = pci_request_regions(dev, "s3fb");
+ if (rc < 0) {
+ dev_err(&(dev->dev), "cannot reserve framebuffer region\n");
+ goto err_request_regions;
+ }
+
+
+ info->fix.smem_start = pci_resource_start(dev, 0);
+ info->fix.smem_len = pci_resource_len(dev, 0);
+
+ /* Map physical IO memory address into kernel space */
+ info->screen_base = pci_iomap(dev, 0, 0);
+ if (! info->screen_base) {
+ rc = -ENOMEM;
+ dev_err(&(dev->dev), "iomap for framebuffer failed\n");
+ goto err_iomap;
+ }
+
+ /* Unlock regs */
+ cr38 = vga_rcrt(NULL, 0x38);
+ cr39 = vga_rcrt(NULL, 0x39);
+ vga_wseq(NULL, 0x08, 0x06);
+ vga_wcrt(NULL, 0x38, 0x48);
+ vga_wcrt(NULL, 0x39, 0xA5);
+
+ /* Find how many physical memory there is on card */
+ /* 0x36 register is accessible even if other registers are locked */
+ regval = vga_rcrt(NULL, 0x36);
+ info->screen_size = s3_memsizes[regval >> 5] << 10;
+ info->fix.smem_len = info->screen_size;
+
+ par->chip = id->driver_data & CHIP_MASK;
+ par->rev = vga_rcrt(NULL, 0x2f);
+ if (par->chip & CHIP_UNDECIDED_FLAG)
+ par->chip = s3_identification(par->chip);
+
+ /* Find MCLK frequency */
+ regval = vga_rseq(NULL, 0x10);
+ par->mclk_freq = ((vga_rseq(NULL, 0x11) + 2) * 14318) / ((regval & 0x1F) + 2);
+ par->mclk_freq = par->mclk_freq >> (regval >> 5);
+
+ /* Restore locks */
+ vga_wcrt(NULL, 0x38, cr38);
+ vga_wcrt(NULL, 0x39, cr39);
+
+ strcpy(info->fix.id, s3_names [par->chip]);
+ info->fix.mmio_start = 0;
+ info->fix.mmio_len = 0;
+ info->fix.type = FB_TYPE_PACKED_PIXELS;
+ info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+ info->fix.ypanstep = 0;
+ info->fix.accel = FB_ACCEL_NONE;
+ info->pseudo_palette = (void*) (par->pseudo_palette);
+
+ /* Prepare startup mode */
+ rc = fb_find_mode(&(info->var), info, mode, NULL, 0, NULL, 8);
+ if (! ((rc == 1) || (rc == 2))) {
+ rc = -EINVAL;
+ dev_err(&(dev->dev), "mode %s not found\n", mode);
+ goto err_find_mode;
+ }
+
+ rc = fb_alloc_cmap(&info->cmap, 256, 0);
+ if (rc < 0) {
+ dev_err(&(dev->dev), "cannot allocate colormap\n");
+ goto err_alloc_cmap;
+ }
+
+ rc = register_framebuffer(info);
+ if (rc < 0) {
+ dev_err(&(dev->dev), "cannot register framebuffer\n");
+ goto err_reg_fb;
+ }
+
+ printk(KERN_INFO "fb%d: %s on %s, %d MB RAM, %d MHz MCLK\n", info->node, info->fix.id,
+ pci_name(dev), info->fix.smem_len >> 20, (par->mclk_freq + 500) / 1000);
+
+ if (par->chip == CHIP_UNKNOWN)
+ printk(KERN_INFO "fb%d: unknown chip, CR2D=%x, CR2E=%x, CRT2F=%x, CRT30=%x\n",
+ info->node, vga_rcrt(NULL, 0x2d), vga_rcrt(NULL, 0x2e),
+ vga_rcrt(NULL, 0x2f), vga_rcrt(NULL, 0x30));
+
+ /* Record a reference to the driver data */
+ pci_set_drvdata(dev, info);
+
+#ifdef CONFIG_MTRR
+ if (mtrr) {
+ par->mtrr_reg = -1;
+ par->mtrr_reg = mtrr_add(info->fix.smem_start, info->fix.smem_len, MTRR_TYPE_WRCOMB, 1);
+ }
+#endif
+
+ return 0;
+
+ /* Error handling */
+err_reg_fb:
+ fb_dealloc_cmap(&info->cmap);
+err_alloc_cmap:
+err_find_mode:
+ pci_iounmap(dev, info->screen_base);
+err_iomap:
+ pci_release_regions(dev);
+err_request_regions:
+/* pci_disable_device(dev); */
+err_enable_device:
+ framebuffer_release(info);
+ return rc;
+}
+
+
+/* PCI remove */
+
+static void __devexit s3_pci_remove(struct pci_dev *dev)
+{
+ struct fb_info *info = pci_get_drvdata(dev);
+ struct s3fb_info *par = info->par;
+
+ if (info) {
+
+#ifdef CONFIG_MTRR
+ if (par->mtrr_reg >= 0) {
+ mtrr_del(par->mtrr_reg, 0, 0);
+ par->mtrr_reg = -1;
+ }
+#endif
+
+ unregister_framebuffer(info);
+ fb_dealloc_cmap(&info->cmap);
+
+ pci_iounmap(dev, info->screen_base);
+ pci_release_regions(dev);
+/* pci_disable_device(dev); */
+
+ pci_set_drvdata(dev, NULL);
+ framebuffer_release(info);
+ }
+}
+
+/* PCI suspend */
+
+static int s3_pci_suspend(struct pci_dev* dev, pm_message_t state)
+{
+ struct fb_info *info = pci_get_drvdata(dev);
+ struct s3fb_info *par = info->par;
+
+ dev_info(&(dev->dev), "suspend\n");
+
+ acquire_console_sem();
+ mutex_lock(&(par->open_lock));
+
+ if ((state.event == PM_EVENT_FREEZE) || (par->ref_count == 0)) {
+ mutex_unlock(&(par->open_lock));
+ release_console_sem();
+ return 0;
+ }
+
+ fb_set_suspend(info, 1);
+
+ pci_save_state(dev);
+ pci_disable_device(dev);
+ pci_set_power_state(dev, pci_choose_state(dev, state));
+
+ mutex_unlock(&(par->open_lock));
+ release_console_sem();
+
+ return 0;
+}
+
+
+/* PCI resume */
+
+static int s3_pci_resume(struct pci_dev* dev)
+{
+ struct fb_info *info = pci_get_drvdata(dev);
+ struct s3fb_info *par = info->par;
+
+ dev_info(&(dev->dev), "resume\n");
+
+ acquire_console_sem();
+ mutex_lock(&(par->open_lock));
+
+ if (par->ref_count == 0) {
+ mutex_unlock(&(par->open_lock));
+ release_console_sem();
+ return 0;
+ }
+
+ pci_set_power_state(dev, PCI_D0);
+ pci_restore_state(dev);
+ pci_enable_device(dev);
+ pci_set_master(dev);
+
+ s3fb_set_par(info);
+ fb_set_suspend(info, 0);
+
+ mutex_unlock(&(par->open_lock));
+ release_console_sem();
+
+ return 0;
+}
+
+
+/* List of boards that we are trying to support */
+
+static struct pci_device_id s3_devices[] __devinitdata = {
+ {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8810), .driver_data = CHIP_XXX_TRIO},
+ {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8811), .driver_data = CHIP_XXX_TRIO},
+ {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8812), .driver_data = CHIP_M65_AURORA64VP},
+ {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8814), .driver_data = CHIP_767_TRIO64UVP},
+ {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8901), .driver_data = CHIP_XXX_TRIO64V2_DXGX},
+ {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8902), .driver_data = CHIP_551_PLATO_PX},
+
+ {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x5631), .driver_data = CHIP_325_VIRGE},
+ {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x883D), .driver_data = CHIP_988_VIRGE_VX},
+ {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A01), .driver_data = CHIP_XXX_VIRGE_DXGX},
+ {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A10), .driver_data = CHIP_356_VIRGE_GX2},
+ {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A11), .driver_data = CHIP_357_VIRGE_GX2P},
+ {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A12), .driver_data = CHIP_359_VIRGE_GX2P},
+
+ {0, 0, 0, 0, 0, 0, 0}
+};
+
+
+MODULE_DEVICE_TABLE(pci, s3_devices);
+
+static struct pci_driver s3fb_pci_driver = {
+ .name = "s3fb",
+ .id_table = s3_devices,
+ .probe = s3_pci_probe,
+ .remove = __devexit_p(s3_pci_remove),
+ .suspend = s3_pci_suspend,
+ .resume = s3_pci_resume,
+};
+
+/* Parse user speficied options */
+
+#ifndef MODULE
+static int __init s3fb_setup(char *options)
+{
+ char *opt;
+
+ if (!options || !*options)
+ return 0;
+
+ while ((opt = strsep(&options, ",")) != NULL) {
+
+ if (!*opt)
+ continue;
+#ifdef CONFIG_MTRR
+ else if (!strcmp(opt, "mtrr:"))
+ mtrr = simple_strtoul(opt + 5, NULL, 0);
+#endif
+ else if (!strcmp(opt, "fasttext:"))
+ mtrr = simple_strtoul(opt + 9, NULL, 0);
+ else
+ mode = opt;
+ }
+
+ return 0;
+}
+#endif
+
+/* Cleanup */
+
+static void __exit s3fb_cleanup(void)
+{
+ pr_debug("s3fb: cleaning up\n");
+ pci_unregister_driver(&s3fb_pci_driver);
+}
+
+/* Driver Initialisation */
+
+static int __init s3fb_init(void)
+{
+
+#ifndef MODULE
+ char *option = NULL;
+
+ if (fb_get_options("s3fb", &option))
+ return -ENODEV;
+ s3fb_setup(option);
+#endif
+
+ pr_debug("s3fb: initializing\n");
+ return pci_register_driver(&s3fb_pci_driver);
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* Modularization */
+
+module_init(s3fb_init);
+module_exit(s3fb_cleanup);
diff --git a/drivers/video/sa1100fb.h b/drivers/video/sa1100fb.h
index 0b07f6ae336..48066ef3af0 100644
--- a/drivers/video/sa1100fb.h
+++ b/drivers/video/sa1100fb.h
@@ -110,9 +110,7 @@ struct sa1100fb_info {
#endif
};
-#define __type_entry(ptr,type,member) ((type *)((char *)(ptr)-offsetof(type,member)))
-
-#define TO_INF(ptr,member) __type_entry(ptr,struct sa1100fb_info,member)
+#define TO_INF(ptr,member) container_of(ptr,struct sa1100fb_info,member)
#define SA1100_PALETTE_MODE_VAL(bpp) (((bpp) & 0x018) << 9)
diff --git a/drivers/video/savage/savagefb-i2c.c b/drivers/video/savage/savagefb-i2c.c
index 1411f3b6a00..8db066ccca6 100644
--- a/drivers/video/savage/savagefb-i2c.c
+++ b/drivers/video/savage/savagefb-i2c.c
@@ -12,7 +12,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/fb.h>
diff --git a/drivers/video/savage/savagefb_driver.c b/drivers/video/savage/savagefb_driver.c
index 82b3deaae02..4afa30522fd 100644
--- a/drivers/video/savage/savagefb_driver.c
+++ b/drivers/video/savage/savagefb_driver.c
@@ -833,7 +833,8 @@ static void savage_set_default_par(struct savagefb_par *par,
vga_out8(0x3d5, cr66, par);
}
-static void savage_update_var(struct fb_var_screeninfo *var, struct fb_videomode *modedb)
+static void savage_update_var(struct fb_var_screeninfo *var,
+ const struct fb_videomode *modedb)
{
var->xres = var->xres_virtual = modedb->xres;
var->yres = modedb->yres;
@@ -902,7 +903,7 @@ static int savagefb_check_var(struct fb_var_screeninfo *var,
}
if (!mode_valid) {
- struct fb_videomode *mode;
+ const struct fb_videomode *mode;
mode = fb_find_best_mode(var, &info->modelist);
if (mode) {
@@ -2206,11 +2207,10 @@ static int __devinit savagefb_probe(struct pci_dev* dev,
info->monspecs.modedb, info->monspecs.modedb_len,
NULL, 8);
} else if (info->monspecs.modedb != NULL) {
- struct fb_videomode *modedb;
+ const struct fb_videomode *mode;
- modedb = fb_find_best_display(&info->monspecs,
- &info->modelist);
- savage_update_var(&info->var, modedb);
+ mode = fb_find_best_display(&info->monspecs, &info->modelist);
+ savage_update_var(&info->var, mode);
}
/* maximize virtual vertical length */
diff --git a/drivers/video/sis/init.c b/drivers/video/sis/init.c
index 2ab3868efde..c311ad3c368 100644
--- a/drivers/video/sis/init.c
+++ b/drivers/video/sis/init.c
@@ -317,23 +317,23 @@ InitTo310Pointer(struct SiS_Private *SiS_Pr)
}
#endif
-BOOLEAN
+bool
SiSInitPtr(struct SiS_Private *SiS_Pr)
{
if(SiS_Pr->ChipType < SIS_315H) {
#ifdef SIS300
InitTo300Pointer(SiS_Pr);
#else
- return FALSE;
+ return false;
#endif
} else {
#ifdef SIS315H
InitTo310Pointer(SiS_Pr);
#else
- return FALSE;
+ return false;
#endif
}
- return TRUE;
+ return true;
}
/*********************************************/
@@ -345,7 +345,7 @@ static
#endif
unsigned short
SiS_GetModeID(int VGAEngine, unsigned int VBFlags, int HDisplay, int VDisplay,
- int Depth, BOOLEAN FSTN, int LCDwidth, int LCDheight)
+ int Depth, bool FSTN, int LCDwidth, int LCDheight)
{
unsigned short ModeIndex = 0;
@@ -483,7 +483,7 @@ SiS_GetModeID(int VGAEngine, unsigned int VBFlags, int HDisplay, int VDisplay,
unsigned short
SiS_GetModeID_LCD(int VGAEngine, unsigned int VBFlags, int HDisplay, int VDisplay,
- int Depth, BOOLEAN FSTN, unsigned short CustomT, int LCDwidth, int LCDheight,
+ int Depth, bool FSTN, unsigned short CustomT, int LCDwidth, int LCDheight,
unsigned int VBFlags2)
{
unsigned short ModeIndex = 0;
@@ -873,7 +873,7 @@ SiS_GetModeID_VGA2(int VGAEngine, unsigned int VBFlags, int HDisplay, int VDispl
break;
}
- return SiS_GetModeID(VGAEngine, 0, HDisplay, VDisplay, Depth, FALSE, 0, 0);
+ return SiS_GetModeID(VGAEngine, 0, HDisplay, VDisplay, Depth, false, 0, 0);
}
@@ -1020,12 +1020,12 @@ SiS_GetSysFlags(struct SiS_Private *SiS_Pr)
/* 661 and newer: NEVER write non-zero to SR11[7:4] */
/* (SR11 is used for DDC and in enable/disablebridge) */
- SiS_Pr->SiS_SensibleSR11 = FALSE;
+ SiS_Pr->SiS_SensibleSR11 = false;
SiS_Pr->SiS_MyCR63 = 0x63;
if(SiS_Pr->ChipType >= SIS_330) {
SiS_Pr->SiS_MyCR63 = 0x53;
if(SiS_Pr->ChipType >= SIS_661) {
- SiS_Pr->SiS_SensibleSR11 = TRUE;
+ SiS_Pr->SiS_SensibleSR11 = true;
}
}
@@ -1253,7 +1253,7 @@ SiS_GetModeFlag(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
/* HELPER: Determine ROM usage */
/*********************************************/
-BOOLEAN
+bool
SiSDetermineROMLayout661(struct SiS_Private *SiS_Pr)
{
unsigned char *ROMAddr = SiS_Pr->VirtualRomBase;
@@ -1261,16 +1261,16 @@ SiSDetermineROMLayout661(struct SiS_Private *SiS_Pr)
if(SiS_Pr->ChipType >= XGI_20) {
/* XGI ROMs don't qualify */
- return FALSE;
+ return false;
} else if(SiS_Pr->ChipType >= SIS_761) {
/* I very much assume 761, 340 and newer will use new layout */
- return TRUE;
+ return true;
} else if(SiS_Pr->ChipType >= SIS_661) {
if((ROMAddr[0x1a] == 'N') &&
(ROMAddr[0x1b] == 'e') &&
(ROMAddr[0x1c] == 'w') &&
(ROMAddr[0x1d] == 'V')) {
- return TRUE;
+ return true;
}
romversoffs = ROMAddr[0x16] | (ROMAddr[0x17] << 8);
if(romversoffs) {
@@ -1280,17 +1280,17 @@ SiSDetermineROMLayout661(struct SiS_Private *SiS_Pr)
}
}
if((romvmaj != 0) || (romvmin >= 92)) {
- return TRUE;
+ return true;
}
} else if(IS_SIS650740) {
if((ROMAddr[0x1a] == 'N') &&
(ROMAddr[0x1b] == 'e') &&
(ROMAddr[0x1c] == 'w') &&
(ROMAddr[0x1d] == 'V')) {
- return TRUE;
+ return true;
}
}
- return FALSE;
+ return false;
}
static void
@@ -1299,8 +1299,8 @@ SiSDetermineROMUsage(struct SiS_Private *SiS_Pr)
unsigned char *ROMAddr = SiS_Pr->VirtualRomBase;
unsigned short romptr = 0;
- SiS_Pr->SiS_UseROM = FALSE;
- SiS_Pr->SiS_ROMNew = FALSE;
+ SiS_Pr->SiS_UseROM = false;
+ SiS_Pr->SiS_ROMNew = false;
SiS_Pr->SiS_PWDOffset = 0;
if(SiS_Pr->ChipType >= XGI_20) return;
@@ -1312,15 +1312,15 @@ SiSDetermineROMUsage(struct SiS_Private *SiS_Pr)
* of the BIOS image.
*/
if((ROMAddr[3] == 0xe9) && ((ROMAddr[5] << 8) | ROMAddr[4]) > 0x21a)
- SiS_Pr->SiS_UseROM = TRUE;
+ SiS_Pr->SiS_UseROM = true;
} else if(SiS_Pr->ChipType < SIS_315H) {
/* Sony's VAIO BIOS 1.09 follows the standard, so perhaps
* the others do as well
*/
- SiS_Pr->SiS_UseROM = TRUE;
+ SiS_Pr->SiS_UseROM = true;
} else {
/* 315/330 series stick to the standard(s) */
- SiS_Pr->SiS_UseROM = TRUE;
+ SiS_Pr->SiS_UseROM = true;
if((SiS_Pr->SiS_ROMNew = SiSDetermineROMLayout661(SiS_Pr))) {
SiS_Pr->SiS_EMIOffset = 14;
SiS_Pr->SiS_PWDOffset = 17;
@@ -1488,7 +1488,7 @@ SiS_GetVBType(struct SiS_Private *SiS_Pr)
/*********************************************/
#ifdef SIS_LINUX_KERNEL
-static BOOLEAN
+static bool
SiS_CheckMemorySize(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
unsigned short ModeIdIndex)
{
@@ -1496,10 +1496,10 @@ SiS_CheckMemorySize(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
unsigned short modeflag = SiS_GetModeFlag(SiS_Pr, ModeNo, ModeIdIndex);
unsigned short memorysize = ((modeflag & MemoryInfoFlag) >> MemorySizeShift) + 1;
- if(!AdapterMemSize) return TRUE;
+ if(!AdapterMemSize) return true;
- if(AdapterMemSize < memorysize) return FALSE;
- return TRUE;
+ if(AdapterMemSize < memorysize) return false;
+ return true;
}
#endif
@@ -1605,7 +1605,7 @@ SiS_ClearBuffer(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
/* HELPER: SearchModeID */
/*********************************************/
-BOOLEAN
+bool
SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo,
unsigned short *ModeIdIndex)
{
@@ -1617,7 +1617,7 @@ SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo,
for((*ModeIdIndex) = 0; ;(*ModeIdIndex)++) {
if(SiS_Pr->SiS_SModeIDTable[(*ModeIdIndex)].St_ModeID == (*ModeNo)) break;
- if(SiS_Pr->SiS_SModeIDTable[(*ModeIdIndex)].St_ModeID == 0xFF) return FALSE;
+ if(SiS_Pr->SiS_SModeIDTable[(*ModeIdIndex)].St_ModeID == 0xFF) return false;
}
if((*ModeNo) == 0x07) {
@@ -1635,11 +1635,11 @@ SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo,
for((*ModeIdIndex) = 0; ;(*ModeIdIndex)++) {
if(SiS_Pr->SiS_EModeIDTable[(*ModeIdIndex)].Ext_ModeID == (*ModeNo)) break;
- if(SiS_Pr->SiS_EModeIDTable[(*ModeIdIndex)].Ext_ModeID == 0xFF) return FALSE;
+ if(SiS_Pr->SiS_EModeIDTable[(*ModeIdIndex)].Ext_ModeID == 0xFF) return false;
}
}
- return TRUE;
+ return true;
}
/*********************************************/
@@ -1696,13 +1696,13 @@ SiS_GetRefCRT1CRTC(struct SiS_Private *SiS_Pr, unsigned short Index, int UseWide
/* HELPER: LowModeTests */
/*********************************************/
-static BOOLEAN
+static bool
SiS_DoLowModeTest(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
{
unsigned short temp, temp1, temp2;
if((ModeNo != 0x03) && (ModeNo != 0x10) && (ModeNo != 0x12))
- return TRUE;
+ return true;
temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x11);
SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x11,0x80);
temp1 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x00);
@@ -1712,13 +1712,13 @@ SiS_DoLowModeTest(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
SiS_SetReg(SiS_Pr->SiS_P3d4,0x11,temp);
if((SiS_Pr->ChipType >= SIS_315H) ||
(SiS_Pr->ChipType == SIS_300)) {
- if(temp2 == 0x55) return FALSE;
- else return TRUE;
+ if(temp2 == 0x55) return false;
+ else return true;
} else {
- if(temp2 != 0x55) return TRUE;
+ if(temp2 != 0x55) return true;
else {
SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x35,0x01);
- return FALSE;
+ return false;
}
}
}
@@ -3237,14 +3237,14 @@ static void
SiS_SetPitch(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn)
{
SISPtr pSiS = SISPTR(pScrn);
- BOOLEAN isslavemode = FALSE;
+ bool isslavemode = false;
if( (pSiS->VBFlags2 & VB2_VIDEOBRIDGE) &&
( ((pSiS->VGAEngine == SIS_300_VGA) &&
(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0xa0) == 0x20) ||
((pSiS->VGAEngine == SIS_315_VGA) &&
(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0x50) == 0x10) ) ) {
- isslavemode = TRUE;
+ isslavemode = true;
}
/* We need to set pitch for CRT1 if bridge is in slave mode, too */
@@ -3264,10 +3264,10 @@ SiS_SetPitch(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn)
#ifdef SIS_XORG_XF86
/* We need pScrn for setting the pitch correctly */
-BOOLEAN
-SiSSetMode(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn, unsigned short ModeNo, BOOLEAN dosetpitch)
+bool
+SiSSetMode(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn, unsigned short ModeNo, bool dosetpitch)
#else
-BOOLEAN
+bool
SiSSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
#endif
{
@@ -3277,8 +3277,8 @@ SiSSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
#ifdef SIS_LINUX_KERNEL
unsigned short KeepLockReg;
- SiS_Pr->UseCustomMode = FALSE;
- SiS_Pr->CRT1UsesCustomMode = FALSE;
+ SiS_Pr->UseCustomMode = false;
+ SiS_Pr->CRT1UsesCustomMode = false;
#endif
SiS_Pr->SiS_flag_clearbuffer = 0;
@@ -3317,7 +3317,7 @@ SiSSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
SiS_UnLockCRT2(SiS_Pr);
if(!SiS_Pr->UseCustomMode) {
- if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) return FALSE;
+ if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) return false;
} else {
ModeIdIndex = 0;
}
@@ -3347,18 +3347,18 @@ SiSSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
#ifdef SIS_LINUX_KERNEL
/* Check memory size (kernel framebuffer driver only) */
if(!SiS_CheckMemorySize(SiS_Pr, ModeNo, ModeIdIndex)) {
- return FALSE;
+ return false;
}
#endif
SiS_OpenCRTC(SiS_Pr);
if(SiS_Pr->UseCustomMode) {
- SiS_Pr->CRT1UsesCustomMode = TRUE;
+ SiS_Pr->CRT1UsesCustomMode = true;
SiS_Pr->CSRClock_CRT1 = SiS_Pr->CSRClock;
SiS_Pr->CModeFlag_CRT1 = SiS_Pr->CModeFlag;
} else {
- SiS_Pr->CRT1UsesCustomMode = FALSE;
+ SiS_Pr->CRT1UsesCustomMode = false;
}
/* Set mode on CRT1 */
@@ -3445,7 +3445,7 @@ SiSSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
if(KeepLockReg != 0xA1) SiS_SetReg(SiS_Pr->SiS_P3c4,0x05,0x00);
#endif
- return TRUE;
+ return true;
}
/*********************************************/
@@ -3454,14 +3454,14 @@ SiSSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
/*********************************************/
#ifdef SIS_XORG_XF86
-BOOLEAN
+bool
SiSBIOSSetMode(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn,
- DisplayModePtr mode, BOOLEAN IsCustom)
+ DisplayModePtr mode, bool IsCustom)
{
SISPtr pSiS = SISPTR(pScrn);
unsigned short ModeNo = 0;
- SiS_Pr->UseCustomMode = FALSE;
+ SiS_Pr->UseCustomMode = false;
if((IsCustom) && (SiS_CheckBuildCustomMode(pScrn, mode, pSiS->VBFlags))) {
@@ -3475,13 +3475,13 @@ SiSBIOSSetMode(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn,
/* Don't need vbflags here; checks done earlier */
ModeNo = SiS_GetModeNumber(pScrn, mode, pSiS->VBFlags);
- if(!ModeNo) return FALSE;
+ if(!ModeNo) return false;
xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, "Setting standard mode 0x%x\n", ModeNo);
}
- return(SiSSetMode(SiS_Pr, pScrn, ModeNo, TRUE));
+ return(SiSSetMode(SiS_Pr, pScrn, ModeNo, true));
}
/*********************************************/
@@ -3489,9 +3489,9 @@ SiSBIOSSetMode(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn,
/* for Dual-Head modes */
/*********************************************/
-BOOLEAN
+bool
SiSBIOSSetModeCRT2(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn,
- DisplayModePtr mode, BOOLEAN IsCustom)
+ DisplayModePtr mode, bool IsCustom)
{
SISIOADDRESS BaseAddr = SiS_Pr->IOAddress;
SISPtr pSiS = SISPTR(pScrn);
@@ -3502,7 +3502,7 @@ SiSBIOSSetModeCRT2(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn,
unsigned short ModeNo = 0;
unsigned char backupreg = 0;
- SiS_Pr->UseCustomMode = FALSE;
+ SiS_Pr->UseCustomMode = false;
/* Remember: Custom modes for CRT2 are ONLY supported
* -) on the 30x/B/C, and
@@ -3516,7 +3516,7 @@ SiSBIOSSetModeCRT2(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn,
} else {
ModeNo = SiS_GetModeNumber(pScrn, mode, pSiS->VBFlags);
- if(!ModeNo) return FALSE;
+ if(!ModeNo) return false;
}
@@ -3550,10 +3550,10 @@ SiSBIOSSetModeCRT2(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn,
if(pSiSEnt->CRT1ModeNo == -1) {
xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
"Setting CRT2 mode delayed until after setting CRT1 mode\n");
- return TRUE;
+ return true;
}
#endif
- pSiSEnt->CRT2ModeSet = TRUE;
+ pSiSEnt->CRT2ModeSet = true;
}
#endif
@@ -3578,7 +3578,7 @@ SiSBIOSSetModeCRT2(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn,
SiS_UnLockCRT2(SiS_Pr);
if(!SiS_Pr->UseCustomMode) {
- if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) return FALSE;
+ if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) return false;
} else {
ModeIdIndex = 0;
}
@@ -3658,7 +3658,7 @@ SiSBIOSSetModeCRT2(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn,
SiS_Handle760(SiS_Pr);
- return TRUE;
+ return true;
}
/*********************************************/
@@ -3666,9 +3666,9 @@ SiSBIOSSetModeCRT2(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn,
/* for Dual-Head modes */
/*********************************************/
-BOOLEAN
+bool
SiSBIOSSetModeCRT1(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn,
- DisplayModePtr mode, BOOLEAN IsCustom)
+ DisplayModePtr mode, bool IsCustom)
{
SISIOADDRESS BaseAddr = SiS_Pr->IOAddress;
SISPtr pSiS = SISPTR(pScrn);
@@ -3677,10 +3677,10 @@ SiSBIOSSetModeCRT1(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn,
#ifdef SISDUALHEAD
SISEntPtr pSiSEnt = pSiS->entityPrivate;
unsigned char backupcr30, backupcr31, backupcr38, backupcr35, backupp40d=0;
- BOOLEAN backupcustom;
+ bool backupcustom;
#endif
- SiS_Pr->UseCustomMode = FALSE;
+ SiS_Pr->UseCustomMode = false;
if((IsCustom) && (SiS_CheckBuildCustomMode(pScrn, mode, pSiS->VBFlags))) {
@@ -3697,7 +3697,7 @@ SiSBIOSSetModeCRT1(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn,
} else {
ModeNo = SiS_GetModeNumber(pScrn, mode, 0); /* don't give VBFlags */
- if(!ModeNo) return FALSE;
+ if(!ModeNo) return false;
xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3,
"Setting standard mode 0x%x on CRT1\n", ModeNo);
@@ -3721,7 +3721,7 @@ SiSBIOSSetModeCRT1(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn,
SiS_UnLockCRT2(SiS_Pr);
if(!SiS_Pr->UseCustomMode) {
- if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) return FALSE;
+ if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) return false;
} else {
ModeIdIndex = 0;
}
@@ -3771,11 +3771,11 @@ SiSBIOSSetModeCRT1(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn,
#endif
if(SiS_Pr->UseCustomMode) {
- SiS_Pr->CRT1UsesCustomMode = TRUE;
+ SiS_Pr->CRT1UsesCustomMode = true;
SiS_Pr->CSRClock_CRT1 = SiS_Pr->CSRClock;
SiS_Pr->CModeFlag_CRT1 = SiS_Pr->CModeFlag;
} else {
- SiS_Pr->CRT1UsesCustomMode = FALSE;
+ SiS_Pr->CRT1UsesCustomMode = false;
}
/* Reset CRT2 if changing mode on CRT1 */
@@ -3838,7 +3838,7 @@ SiSBIOSSetModeCRT1(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn,
/* Backup/Set ModeNo in BIOS scratch area */
SiS_GetSetModeID(pScrn,ModeNo);
- return TRUE;
+ return true;
}
#endif /* Linux_XF86 */
@@ -4082,7 +4082,7 @@ SiS_Generic_ConvertCRData(struct SiS_Private *SiS_Pr, unsigned char *crdata,
DisplayModePtr current
#endif
#ifdef SIS_LINUX_KERNEL
- struct fb_var_screeninfo *var, BOOLEAN writeres
+ struct fb_var_screeninfo *var, bool writeres
#endif
)
{
diff --git a/drivers/video/sis/init.h b/drivers/video/sis/init.h
index 59d12844b4d..f40a680df86 100644
--- a/drivers/video/sis/init.h
+++ b/drivers/video/sis/init.h
@@ -1521,13 +1521,13 @@ static const struct SiS_LVDSCRT1Data SiS_LVDSCRT1640x480_1_H[] =
0x00}}
};
-BOOLEAN SiSInitPtr(struct SiS_Private *SiS_Pr);
+bool SiSInitPtr(struct SiS_Private *SiS_Pr);
#ifdef SIS_XORG_XF86
unsigned short SiS_GetModeID(int VGAEngine, unsigned int VBFlags, int HDisplay, int VDisplay,
- int Depth, BOOLEAN FSTN, int LCDwith, int LCDheight);
+ int Depth, bool FSTN, int LCDwith, int LCDheight);
#endif
unsigned short SiS_GetModeID_LCD(int VGAEngine, unsigned int VBFlags, int HDisplay,
- int VDisplay, int Depth, BOOLEAN FSTN,
+ int VDisplay, int Depth, bool FSTN,
unsigned short CustomT, int LCDwith, int LCDheight,
unsigned int VBFlags2);
unsigned short SiS_GetModeID_TV(int VGAEngine, unsigned int VBFlags, int HDisplay,
@@ -1558,12 +1558,12 @@ void SiS_SetEnableDstn(struct SiS_Private *SiS_Pr, int enable);
void SiS_SetEnableFstn(struct SiS_Private *SiS_Pr, int enable);
unsigned short SiS_GetModeFlag(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
unsigned short ModeIdIndex);
-BOOLEAN SiSDetermineROMLayout661(struct SiS_Private *SiS_Pr);
+bool SiSDetermineROMLayout661(struct SiS_Private *SiS_Pr);
#ifndef SIS_LINUX_KERNEL
void SiS_GetVBType(struct SiS_Private *SiS_Pr);
#endif
-BOOLEAN SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo,
+bool SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo,
unsigned short *ModeIdIndex);
unsigned short SiS_GetModePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
unsigned short ModeIdIndex);
@@ -1581,17 +1581,17 @@ unsigned short SiS_GetLatencyFactor630(struct SiS_Private *SiS_Pr, unsigned shor
#endif
void SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex);
#ifdef SIS_XORG_XF86
-BOOLEAN SiSSetMode(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn, unsigned short ModeNo,
- BOOLEAN dosetpitch);
-BOOLEAN SiSBIOSSetMode(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn,
- DisplayModePtr mode, BOOLEAN IsCustom);
-BOOLEAN SiSBIOSSetModeCRT2(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn,
- DisplayModePtr mode, BOOLEAN IsCustom);
-BOOLEAN SiSBIOSSetModeCRT1(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn,
- DisplayModePtr mode, BOOLEAN IsCustom);
+bool SiSSetMode(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn, unsigned short ModeNo,
+ bool dosetpitch);
+bool SiSBIOSSetMode(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn,
+ DisplayModePtr mode, bool IsCustom);
+bool SiSBIOSSetModeCRT2(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn,
+ DisplayModePtr mode, bool IsCustom);
+bool SiSBIOSSetModeCRT1(struct SiS_Private *SiS_Pr, ScrnInfoPtr pScrn,
+ DisplayModePtr mode, bool IsCustom);
#endif
#ifdef SIS_LINUX_KERNEL
-BOOLEAN SiSSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo);
+bool SiSSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo);
#endif
void SiS_CalcCRRegisters(struct SiS_Private *SiS_Pr, int depth);
void SiS_CalcLCDACRT1Timing(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
@@ -1602,7 +1602,7 @@ void SiS_Generic_ConvertCRData(struct SiS_Private *SiS_Pr, unsigned char *crdat
#endif
#ifdef SIS_LINUX_KERNEL
void SiS_Generic_ConvertCRData(struct SiS_Private *SiS_Pr, unsigned char *crdata, int xres,
- int yres, struct fb_var_screeninfo *var, BOOLEAN writeres);
+ int yres, struct fb_var_screeninfo *var, bool writeres);
#endif
/* From init301.c: */
@@ -1615,7 +1615,7 @@ extern void SiS_SetTVMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
unsigned short ModeIdIndex);
extern void SiS_UnLockCRT2(struct SiS_Private *SiS_Pr);
extern void SiS_DisableBridge(struct SiS_Private *);
-extern BOOLEAN SiS_SetCRT2Group(struct SiS_Private *, unsigned short);
+extern bool SiS_SetCRT2Group(struct SiS_Private *, unsigned short);
extern unsigned short SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
unsigned short ModeIdIndex);
extern void SiS_WaitRetrace1(struct SiS_Private *SiS_Pr);
@@ -1624,8 +1624,8 @@ extern unsigned short SiS_GetResInfo(struct SiS_Private *SiS_Pr, unsigned short
extern unsigned short SiS_GetCH700x(struct SiS_Private *SiS_Pr, unsigned short tempax);
extern unsigned short SiS_GetVCLK2Ptr(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
unsigned short ModeIdIndex, unsigned short RRTI);
-extern BOOLEAN SiS_IsVAMode(struct SiS_Private *);
-extern BOOLEAN SiS_IsDualEdge(struct SiS_Private *);
+extern bool SiS_IsVAMode(struct SiS_Private *);
+extern bool SiS_IsDualEdge(struct SiS_Private *);
#ifdef SIS_XORG_XF86
/* From other modules: */
diff --git a/drivers/video/sis/init301.c b/drivers/video/sis/init301.c
index 47e1896cffe..da33d801c22 100644
--- a/drivers/video/sis/init301.c
+++ b/drivers/video/sis/init301.c
@@ -200,7 +200,7 @@ GetLCDStructPtr661_2(struct SiS_Private *SiS_Pr)
/* Adjust Rate for CRT2 */
/*********************************************/
-static BOOLEAN
+static bool
SiS_AdjustCRT2Rate(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex,
unsigned short RRTI, unsigned short *i)
{
@@ -269,7 +269,7 @@ SiS_AdjustCRT2Rate(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned s
/* Look backwards in table for matching CRT2 mode */
for(; SiS_Pr->SiS_RefIndex[RRTI + (*i)].ModeID == modeid; (*i)--) {
infoflag = SiS_Pr->SiS_RefIndex[RRTI + (*i)].Ext_InfoFlag;
- if(infoflag & checkmask) return TRUE;
+ if(infoflag & checkmask) return true;
if((*i) == 0) break;
}
@@ -279,9 +279,9 @@ SiS_AdjustCRT2Rate(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned s
for((*i) = 0; ; (*i)++) {
if(SiS_Pr->SiS_RefIndex[RRTI + (*i)].ModeID != modeid) break;
infoflag = SiS_Pr->SiS_RefIndex[RRTI + (*i)].Ext_InfoFlag;
- if(infoflag & checkmask) return TRUE;
+ if(infoflag & checkmask) return true;
}
- return FALSE;
+ return false;
}
/*********************************************/
@@ -405,7 +405,7 @@ SiS_SaveCRT2Info(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
/*********************************************/
#ifdef SIS300
-static BOOLEAN
+static bool
SiS_CR36BIOSWord23b(struct SiS_Private *SiS_Pr)
{
unsigned char *ROMAddr = SiS_Pr->VirtualRomBase;
@@ -415,13 +415,13 @@ SiS_CR36BIOSWord23b(struct SiS_Private *SiS_Pr)
if((ROMAddr[0x233] == 0x12) && (ROMAddr[0x234] == 0x34)) {
temp = 1 << ((SiS_GetReg(SiS_Pr->SiS_P3d4,0x36) >> 4) & 0x0f);
temp1 = SISGETROMW(0x23b);
- if(temp1 & temp) return TRUE;
+ if(temp1 & temp) return true;
}
}
- return FALSE;
+ return false;
}
-static BOOLEAN
+static bool
SiS_CR36BIOSWord23d(struct SiS_Private *SiS_Pr)
{
unsigned char *ROMAddr = SiS_Pr->VirtualRomBase;
@@ -431,10 +431,10 @@ SiS_CR36BIOSWord23d(struct SiS_Private *SiS_Pr)
if((ROMAddr[0x233] == 0x12) && (ROMAddr[0x234] == 0x34)) {
temp = 1 << ((SiS_GetReg(SiS_Pr->SiS_P3d4,0x36) >> 4) & 0x0f);
temp1 = SISGETROMW(0x23d);
- if(temp1 & temp) return TRUE;
+ if(temp1 & temp) return true;
}
}
- return FALSE;
+ return false;
}
#endif
@@ -687,38 +687,38 @@ SiS_VBLongWait(struct SiS_Private *SiS_Pr)
/*********************************************/
#ifdef SIS300
-static BOOLEAN
+static bool
SiS_Is301B(struct SiS_Private *SiS_Pr)
{
- if(SiS_GetReg(SiS_Pr->SiS_Part4Port,0x01) >= 0xb0) return TRUE;
- return FALSE;
+ if(SiS_GetReg(SiS_Pr->SiS_Part4Port,0x01) >= 0xb0) return true;
+ return false;
}
#endif
-static BOOLEAN
+static bool
SiS_CRT2IsLCD(struct SiS_Private *SiS_Pr)
{
if(SiS_Pr->ChipType == SIS_730) {
- if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x13) & 0x20) return TRUE;
+ if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x13) & 0x20) return true;
}
- if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x30) & 0x20) return TRUE;
- return FALSE;
+ if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x30) & 0x20) return true;
+ return false;
}
-BOOLEAN
+bool
SiS_IsDualEdge(struct SiS_Private *SiS_Pr)
{
#ifdef SIS315H
if(SiS_Pr->ChipType >= SIS_315H) {
if((SiS_Pr->ChipType != SIS_650) || (SiS_GetReg(SiS_Pr->SiS_P3d4,0x5f) & 0xf0)) {
- if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x38) & EnableDualEdge) return TRUE;
+ if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x38) & EnableDualEdge) return true;
}
}
#endif
- return FALSE;
+ return false;
}
-BOOLEAN
+bool
SiS_IsVAMode(struct SiS_Private *SiS_Pr)
{
#ifdef SIS315H
@@ -726,70 +726,70 @@ SiS_IsVAMode(struct SiS_Private *SiS_Pr)
if(SiS_Pr->ChipType >= SIS_315H) {
flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38);
- if((flag & EnableDualEdge) && (flag & SetToLCDA)) return TRUE;
+ if((flag & EnableDualEdge) && (flag & SetToLCDA)) return true;
}
#endif
- return FALSE;
+ return false;
}
#ifdef SIS315H
-static BOOLEAN
+static bool
SiS_IsVAorLCD(struct SiS_Private *SiS_Pr)
{
- if(SiS_IsVAMode(SiS_Pr)) return TRUE;
- if(SiS_CRT2IsLCD(SiS_Pr)) return TRUE;
- return FALSE;
+ if(SiS_IsVAMode(SiS_Pr)) return true;
+ if(SiS_CRT2IsLCD(SiS_Pr)) return true;
+ return false;
}
#endif
-static BOOLEAN
+static bool
SiS_IsDualLink(struct SiS_Private *SiS_Pr)
{
#ifdef SIS315H
if(SiS_Pr->ChipType >= SIS_315H) {
if((SiS_CRT2IsLCD(SiS_Pr)) ||
(SiS_IsVAMode(SiS_Pr))) {
- if(SiS_Pr->SiS_LCDInfo & LCDDualLink) return TRUE;
+ if(SiS_Pr->SiS_LCDInfo & LCDDualLink) return true;
}
}
#endif
- return FALSE;
+ return false;
}
#ifdef SIS315H
-static BOOLEAN
+static bool
SiS_TVEnabled(struct SiS_Private *SiS_Pr)
{
- if((SiS_GetReg(SiS_Pr->SiS_Part2Port,0x00) & 0x0f) != 0x0c) return TRUE;
+ if((SiS_GetReg(SiS_Pr->SiS_Part2Port,0x00) & 0x0f) != 0x0c) return true;
if(SiS_Pr->SiS_VBType & VB_SISYPBPR) {
- if(SiS_GetReg(SiS_Pr->SiS_Part2Port,0x4d) & 0x10) return TRUE;
+ if(SiS_GetReg(SiS_Pr->SiS_Part2Port,0x4d) & 0x10) return true;
}
- return FALSE;
+ return false;
}
#endif
#ifdef SIS315H
-static BOOLEAN
+static bool
SiS_LCDAEnabled(struct SiS_Private *SiS_Pr)
{
- if(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x13) & 0x04) return TRUE;
- return FALSE;
+ if(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x13) & 0x04) return true;
+ return false;
}
#endif
#ifdef SIS315H
-static BOOLEAN
+static bool
SiS_WeHaveBacklightCtrl(struct SiS_Private *SiS_Pr)
{
if((SiS_Pr->ChipType >= SIS_315H) && (SiS_Pr->ChipType < SIS_661)) {
- if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x79) & 0x10) return TRUE;
+ if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x79) & 0x10) return true;
}
- return FALSE;
+ return false;
}
#endif
#ifdef SIS315H
-static BOOLEAN
+static bool
SiS_IsNotM650orLater(struct SiS_Private *SiS_Pr)
{
unsigned short flag;
@@ -798,90 +798,90 @@ SiS_IsNotM650orLater(struct SiS_Private *SiS_Pr)
flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x5f) & 0xf0;
/* Check for revision != A0 only */
if((flag == 0xe0) || (flag == 0xc0) ||
- (flag == 0xb0) || (flag == 0x90)) return FALSE;
- } else if(SiS_Pr->ChipType >= SIS_661) return FALSE;
- return TRUE;
+ (flag == 0xb0) || (flag == 0x90)) return false;
+ } else if(SiS_Pr->ChipType >= SIS_661) return false;
+ return true;
}
#endif
#ifdef SIS315H
-static BOOLEAN
+static bool
SiS_IsYPbPr(struct SiS_Private *SiS_Pr)
{
if(SiS_Pr->ChipType >= SIS_315H) {
/* YPrPb = 0x08 */
- if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x38) & EnableCHYPbPr) return TRUE;
+ if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x38) & EnableCHYPbPr) return true;
}
- return FALSE;
+ return false;
}
#endif
#ifdef SIS315H
-static BOOLEAN
+static bool
SiS_IsChScart(struct SiS_Private *SiS_Pr)
{
if(SiS_Pr->ChipType >= SIS_315H) {
/* Scart = 0x04 */
- if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x38) & EnableCHScart) return TRUE;
+ if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x38) & EnableCHScart) return true;
}
- return FALSE;
+ return false;
}
#endif
#ifdef SIS315H
-static BOOLEAN
+static bool
SiS_IsTVOrYPbPrOrScart(struct SiS_Private *SiS_Pr)
{
unsigned short flag;
if(SiS_Pr->ChipType >= SIS_315H) {
flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30);
- if(flag & SetCRT2ToTV) return TRUE;
+ if(flag & SetCRT2ToTV) return true;
flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38);
- if(flag & EnableCHYPbPr) return TRUE; /* = YPrPb = 0x08 */
- if(flag & EnableCHScart) return TRUE; /* = Scart = 0x04 - TW */
+ if(flag & EnableCHYPbPr) return true; /* = YPrPb = 0x08 */
+ if(flag & EnableCHScart) return true; /* = Scart = 0x04 - TW */
} else {
flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30);
- if(flag & SetCRT2ToTV) return TRUE;
+ if(flag & SetCRT2ToTV) return true;
}
- return FALSE;
+ return false;
}
#endif
#ifdef SIS315H
-static BOOLEAN
+static bool
SiS_IsLCDOrLCDA(struct SiS_Private *SiS_Pr)
{
unsigned short flag;
if(SiS_Pr->ChipType >= SIS_315H) {
flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30);
- if(flag & SetCRT2ToLCD) return TRUE;
+ if(flag & SetCRT2ToLCD) return true;
flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38);
- if(flag & SetToLCDA) return TRUE;
+ if(flag & SetToLCDA) return true;
} else {
flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30);
- if(flag & SetCRT2ToLCD) return TRUE;
+ if(flag & SetCRT2ToLCD) return true;
}
- return FALSE;
+ return false;
}
#endif
-static BOOLEAN
+static bool
SiS_HaveBridge(struct SiS_Private *SiS_Pr)
{
unsigned short flag;
if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
- return TRUE;
+ return true;
} else if(SiS_Pr->SiS_VBType & VB_SISVB) {
flag = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x00);
- if((flag == 1) || (flag == 2)) return TRUE;
+ if((flag == 1) || (flag == 2)) return true;
}
- return FALSE;
+ return false;
}
-static BOOLEAN
+static bool
SiS_BridgeIsEnabled(struct SiS_Private *SiS_Pr)
{
unsigned short flag;
@@ -890,23 +890,23 @@ SiS_BridgeIsEnabled(struct SiS_Private *SiS_Pr)
flag = SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00);
if(SiS_Pr->ChipType < SIS_315H) {
flag &= 0xa0;
- if((flag == 0x80) || (flag == 0x20)) return TRUE;
+ if((flag == 0x80) || (flag == 0x20)) return true;
} else {
flag &= 0x50;
- if((flag == 0x40) || (flag == 0x10)) return TRUE;
+ if((flag == 0x40) || (flag == 0x10)) return true;
}
}
- return FALSE;
+ return false;
}
-static BOOLEAN
+static bool
SiS_BridgeInSlavemode(struct SiS_Private *SiS_Pr)
{
unsigned short flag1;
flag1 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x31);
- if(flag1 & (SetInSlaveMode >> 8)) return TRUE;
- return FALSE;
+ if(flag1 & (SetInSlaveMode >> 8)) return true;
+ return false;
}
/*********************************************/
@@ -1461,11 +1461,11 @@ SiS_GetLCDInfoBIOS(struct SiS_Private *SiS_Pr)
if((ROMAddr = GetLCDStructPtr661(SiS_Pr))) {
if((temp = SISGETROMW(6)) != SiS_Pr->PanelHT) {
- SiS_Pr->SiS_NeedRomModeData = TRUE;
+ SiS_Pr->SiS_NeedRomModeData = true;
SiS_Pr->PanelHT = temp;
}
if((temp = SISGETROMW(8)) != SiS_Pr->PanelVT) {
- SiS_Pr->SiS_NeedRomModeData = TRUE;
+ SiS_Pr->SiS_NeedRomModeData = true;
SiS_Pr->PanelVT = temp;
}
SiS_Pr->PanelHRS = SISGETROMW(10);
@@ -1516,7 +1516,7 @@ void
SiS_GetLCDResInfo(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex)
{
unsigned short temp,modeflag,resinfo=0,modexres=0,modeyres=0;
- BOOLEAN panelcanscale = FALSE;
+ bool panelcanscale = false;
#ifdef SIS300
unsigned char *ROMAddr = SiS_Pr->VirtualRomBase;
static const unsigned char SiS300SeriesLCDRes[] =
@@ -1534,10 +1534,10 @@ SiS_GetLCDResInfo(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned sh
SiS_Pr->PanelHRE = 999; /* HSync end */
SiS_Pr->PanelVRS = 999; /* VSync start */
SiS_Pr->PanelVRE = 999; /* VSync end */
- SiS_Pr->SiS_NeedRomModeData = FALSE;
+ SiS_Pr->SiS_NeedRomModeData = false;
/* Alternative 1600x1200@60 timing for 1600x1200 LCDA */
- SiS_Pr->Alternate1600x1200 = FALSE;
+ SiS_Pr->Alternate1600x1200 = false;
if(!(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA))) return;
@@ -1633,7 +1633,7 @@ SiS_GetLCDResInfo(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned sh
SiS_Pr->SiS_LCDInfo |= DontExpandLCD;
}
- panelcanscale = (SiS_Pr->SiS_LCDInfo & DontExpandLCD) ? TRUE : FALSE;
+ panelcanscale = (bool)(SiS_Pr->SiS_LCDInfo & DontExpandLCD);
if(!SiS_Pr->UsePanelScaler) SiS_Pr->SiS_LCDInfo &= ~DontExpandLCD;
else if(SiS_Pr->UsePanelScaler == 1) SiS_Pr->SiS_LCDInfo |= DontExpandLCD;
@@ -1833,7 +1833,7 @@ SiS_GetLCDResInfo(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned sh
SiS_Pr->PanelHRS = 48; SiS_Pr->PanelHRE = 32;
SiS_Pr->PanelVRS = 2; SiS_Pr->PanelVRE = 4;
SiS_Pr->PanelVCLKIdx315 = VCLK130_315;
- SiS_Pr->Alternate1600x1200 = TRUE;
+ SiS_Pr->Alternate1600x1200 = true;
}
} else if(SiS_Pr->SiS_IF_DEF_LVDS) {
SiS_Pr->PanelHT = 2048; SiS_Pr->PanelVT = 1320;
@@ -3448,7 +3448,7 @@ SiS_GetCRT2Data301(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned s
} else {
- BOOLEAN gotit = FALSE;
+ bool gotit = false;
if((SiS_Pr->SiS_LCDInfo & DontExpandLCD) && (!(SiS_Pr->SiS_LCDInfo & LCDPass11))) {
@@ -3456,7 +3456,7 @@ SiS_GetCRT2Data301(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned s
SiS_Pr->SiS_VGAVT = SiS_Pr->PanelVT;
SiS_Pr->SiS_HT = SiS_Pr->PanelHT;
SiS_Pr->SiS_VT = SiS_Pr->PanelVT;
- gotit = TRUE;
+ gotit = true;
} else if( (!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) && (romptr) && (ROMAddr) ) {
@@ -3474,7 +3474,7 @@ SiS_GetCRT2Data301(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned s
if(ROMAddr[romptr+9] & 0x80) SiS_Pr->SiS_RVBHRS2 -= tempax;
else SiS_Pr->SiS_RVBHRS2 += tempax;
}
- if(SiS_Pr->SiS_VGAHT) gotit = TRUE;
+ if(SiS_Pr->SiS_VGAHT) gotit = true;
else {
SiS_Pr->SiS_LCDInfo |= DontExpandLCD;
SiS_Pr->SiS_LCDInfo &= ~LCDPass11;
@@ -3485,7 +3485,7 @@ SiS_GetCRT2Data301(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned s
SiS_Pr->SiS_HT = SiS_Pr->PanelHT;
SiS_Pr->SiS_VT = SiS_Pr->PanelVT;
SiS_Pr->SiS_RVBHRS2 = 0;
- gotit = TRUE;
+ gotit = true;
}
#endif
@@ -3960,8 +3960,8 @@ SiS_DisableBridge(struct SiS_Private *SiS_Pr)
#ifdef SIS315H /* 315 series */
int didpwd = 0;
- BOOLEAN custom1 = ((SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) ||
- (SiS_Pr->SiS_CustomT == CUT_CLEVO1400)) ? TRUE : FALSE;
+ bool custom1 = (SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) ||
+ (SiS_Pr->SiS_CustomT == CUT_CLEVO1400);
modenum = SiS_GetReg(SiS_Pr->SiS_P3d4,0x34) & 0x7f;
@@ -4313,7 +4313,7 @@ SiS_EnableBridge(struct SiS_Private *SiS_Pr)
unsigned short temp=0, tempah;
#ifdef SIS315H
unsigned short temp1, pushax=0;
- BOOLEAN delaylong = FALSE;
+ bool delaylong = false;
#endif
if(SiS_Pr->SiS_VBType & VB_SISVB) {
@@ -4448,7 +4448,7 @@ SiS_EnableBridge(struct SiS_Private *SiS_Pr)
if(!(SiS_GetReg(SiS_Pr->SiS_P3d4,0x31) & 0x40)) {
SiS_PanelDelayLoop(SiS_Pr, 3, 10);
- delaylong = TRUE;
+ delaylong = true;
}
}
@@ -4530,7 +4530,7 @@ SiS_EnableBridge(struct SiS_Private *SiS_Pr)
SiS_Pr->EMI_33 = ROMAddr[romptr + SiS_Pr->SiS_EMIOffset + 2];
if(ROMAddr[romptr + 1] & 0x10) SiS_Pr->EMI_30 = 0x40;
/* emidelay = SISGETROMW((romptr + 0x22)); */
- SiS_Pr->HaveEMI = SiS_Pr->HaveEMILCD = SiS_Pr->OverruleEMI = TRUE;
+ SiS_Pr->HaveEMI = SiS_Pr->HaveEMILCD = SiS_Pr->OverruleEMI = true;
}
}
@@ -4644,7 +4644,7 @@ SiS_EnableBridge(struct SiS_Private *SiS_Pr)
SiS_PanelDelayLoop(SiS_Pr, 3, 5);
if(delaylong) {
SiS_PanelDelayLoop(SiS_Pr, 3, 5);
- delaylong = FALSE;
+ delaylong = false;
}
SiS_WaitVBRetrace(SiS_Pr);
SiS_WaitVBRetrace(SiS_Pr);
@@ -5454,7 +5454,7 @@ SiS_SetGroup1_LVDS(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned s
unsigned short modeflag, resinfo = 0;
unsigned short push2, tempax, tempbx, tempcx, temp;
unsigned int tempeax = 0, tempebx, tempecx, tempvcfact = 0;
- BOOLEAN islvds = FALSE, issis = FALSE, chkdclkfirst = FALSE;
+ bool islvds = false, issis = false, chkdclkfirst = false;
#ifdef SIS300
unsigned short crt2crtc = 0;
#endif
@@ -5480,17 +5480,17 @@ SiS_SetGroup1_LVDS(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned s
/* is lvds if really LVDS, or 301B-DH with external LVDS transmitter */
if((SiS_Pr->SiS_IF_DEF_LVDS == 1) || (SiS_Pr->SiS_VBType & VB_NoLCD)) {
- islvds = TRUE;
+ islvds = true;
}
/* is really sis if sis bridge, but not 301B-DH */
if((SiS_Pr->SiS_VBType & VB_SISVB) && (!(SiS_Pr->SiS_VBType & VB_NoLCD))) {
- issis = TRUE;
+ issis = true;
}
if((SiS_Pr->ChipType >= SIS_315H) && (islvds) && (!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA))) {
if((!SiS_Pr->SiS_IF_DEF_FSTN) && (!SiS_Pr->SiS_IF_DEF_DSTN)) {
- chkdclkfirst = TRUE;
+ chkdclkfirst = true;
}
}
@@ -6447,13 +6447,13 @@ SiS_SetGroup2_C_ELV(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned
SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x4e,0xeb,temp);
}
-static BOOLEAN
+static bool
SiS_GetCRT2Part2Ptr(struct SiS_Private *SiS_Pr,unsigned short ModeNo,unsigned short ModeIdIndex,
unsigned short RefreshRateTableIndex,unsigned short *CRT2Index,
unsigned short *ResIndex)
{
- if(SiS_Pr->ChipType < SIS_315H) return FALSE;
+ if(SiS_Pr->ChipType < SIS_315H) return false;
if(ModeNo <= 0x13)
(*ResIndex) = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
@@ -6688,7 +6688,7 @@ SiS_SetGroup2(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short
unsigned short i, j, tempax, tempbx, tempcx, tempch, tempcl, temp;
unsigned short push2, modeflag, crt2crtc, bridgeoffset;
unsigned int longtemp, PhaseIndex;
- BOOLEAN newtvphase;
+ bool newtvphase;
const unsigned char *TimingPoint;
#ifdef SIS315H
unsigned short resindex, CRT2Index;
@@ -6721,11 +6721,11 @@ SiS_SetGroup2(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short
PhaseIndex = 0x01; /* SiS_PALPhase */
TimingPoint = SiS_Pr->SiS_PALTiming;
- newtvphase = FALSE;
+ newtvphase = false;
if( (SiS_Pr->SiS_VBType & VB_SIS30xBLV) &&
( (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) ||
(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) ) ) {
- newtvphase = TRUE;
+ newtvphase = true;
}
if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) {
@@ -7754,13 +7754,13 @@ SiS_SetGroup5(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short
/* MODIFY CRT1 GROUP FOR SLAVE MODE */
/*********************************************/
-static BOOLEAN
+static bool
SiS_GetLVDSCRT1Ptr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex,
unsigned short RefreshRateTableIndex, unsigned short *ResIndex,
unsigned short *DisplayType)
{
unsigned short modeflag = 0;
- BOOLEAN checkhd = TRUE;
+ bool checkhd = true;
/* Pass 1:1 not supported here */
@@ -7792,7 +7792,7 @@ SiS_GetLVDSCRT1Ptr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned s
(*DisplayType = 0);
switch(SiS_Pr->SiS_LCDResInfo) {
case Panel_320x240_1: (*DisplayType) = 50;
- checkhd = FALSE;
+ checkhd = false;
break;
case Panel_320x240_2: (*DisplayType) = 14;
break;
@@ -7802,7 +7802,7 @@ SiS_GetLVDSCRT1Ptr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned s
break;
case Panel_1024x600: (*DisplayType) = 26;
break;
- default: return TRUE;
+ default: return true;
}
if(checkhd) {
@@ -7815,7 +7815,7 @@ SiS_GetLVDSCRT1Ptr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned s
}
- return TRUE;
+ return true;
}
static void
@@ -8654,7 +8654,7 @@ SiS_ChrontelDoSomething1(struct SiS_Private *SiS_Pr)
/* MAIN: SET CRT2 REGISTER GROUP */
/*********************************************/
-BOOLEAN
+bool
SiS_SetCRT2Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
{
#ifdef SIS300
@@ -8690,7 +8690,7 @@ SiS_SetCRT2Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
if(SiS_Pr->SiS_VBInfo & DisableCRT2Display) {
SiS_LockCRT2(SiS_Pr);
SiS_DisplayOn(SiS_Pr);
- return TRUE;
+ return true;
}
SiS_GetCRT2Data(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex);
@@ -8828,7 +8828,7 @@ SiS_SetCRT2Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
SiS_LockCRT2(SiS_Pr);
}
- return TRUE;
+ return true;
}
@@ -8908,7 +8908,7 @@ SiS_SetTrumpBlockLoop(struct SiS_Private *SiS_Pr, unsigned char *dataptr)
return NULL;
}
-static BOOLEAN
+static bool
SiS_SetTrumpionBlock(struct SiS_Private *SiS_Pr, unsigned char *dataptr)
{
SiS_Pr->SiS_DDC_DeviceAddr = 0xF0; /* DAB (Device Address Byte) */
@@ -8921,14 +8921,14 @@ SiS_SetTrumpionBlock(struct SiS_Private *SiS_Pr, unsigned char *dataptr)
while(*dataptr) {
dataptr = SiS_SetTrumpBlockLoop(SiS_Pr, dataptr);
- if(!dataptr) return FALSE;
+ if(!dataptr) return false;
}
#ifdef SIS_XORG_XF86
#ifdef TWDEBUG
xf86DrvMsg(0, X_INFO, "Trumpion block success\n");
#endif
#endif
- return TRUE;
+ return true;
}
#endif
@@ -8939,7 +8939,7 @@ SiS_SetTrumpionBlock(struct SiS_Private *SiS_Pr, unsigned char *dataptr)
* 0x0a, possibly for working around the DDC problems
*/
-static BOOLEAN
+static bool
SiS_SetChReg(struct SiS_Private *SiS_Pr, unsigned short reg, unsigned char val, unsigned short myor)
{
unsigned short temp, i;
@@ -8958,9 +8958,9 @@ SiS_SetChReg(struct SiS_Private *SiS_Pr, unsigned short reg, unsigned char val,
if(temp) continue; /* (ERROR: no ack) */
if(SiS_SetStop(SiS_Pr)) continue; /* Set stop condition */
SiS_Pr->SiS_ChrontelInit = 1;
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
/* Write to Chrontel 700x */
@@ -9119,7 +9119,7 @@ static
#endif
unsigned short
SiS_InitDDCRegs(struct SiS_Private *SiS_Pr, unsigned int VBFlags, int VGAEngine,
- unsigned short adaptnum, unsigned short DDCdatatype, BOOLEAN checkcr32,
+ unsigned short adaptnum, unsigned short DDCdatatype, bool checkcr32,
unsigned int VBFlags2)
{
unsigned char ddcdtype[] = { 0xa0, 0xa0, 0xa0, 0xa2, 0xa6 };
@@ -9287,7 +9287,7 @@ SiS_DoProbeDDC(struct SiS_Private *SiS_Pr)
{
unsigned char mask, value;
unsigned short temp, ret=0;
- BOOLEAN failed = FALSE;
+ bool failed = false;
SiS_SetSwitchDDC2(SiS_Pr);
if(SiS_PrepareDDC(SiS_Pr)) {
@@ -9308,7 +9308,7 @@ SiS_DoProbeDDC(struct SiS_Private *SiS_Pr)
mask = 0xff;
value = 0xff;
} else {
- failed = TRUE;
+ failed = true;
ret = 0xFFFF;
#ifdef SIS_XORG_XF86
#ifdef TWDEBUG
@@ -9317,7 +9317,7 @@ SiS_DoProbeDDC(struct SiS_Private *SiS_Pr)
#endif
}
}
- if(failed == FALSE) {
+ if(!failed) {
temp = (unsigned char)SiS_ReadDDC2Data(SiS_Pr);
SiS_SendACK(SiS_Pr, 1);
temp &= mask;
@@ -9431,7 +9431,7 @@ SiS_HandleDDC(struct SiS_Private *SiS_Pr, unsigned int VBFlags, int VGAEngine,
if((!(VBFlags2 & VB2_VIDEOBRIDGE)) && (adaptnum > 0))
return 0xFFFF;
- if(SiS_InitDDCRegs(SiS_Pr, VBFlags, VGAEngine, adaptnum, DDCdatatype, FALSE, VBFlags2) == 0xFFFF)
+ if(SiS_InitDDCRegs(SiS_Pr, VBFlags, VGAEngine, adaptnum, DDCdatatype, false, VBFlags2) == 0xFFFF)
return 0xFFFF;
sr1f = SiS_GetReg(SiS_Pr->SiS_P3c4,0x1f);
@@ -9829,7 +9829,7 @@ SetDelayComp(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
{
unsigned char *ROMAddr = SiS_Pr->VirtualRomBase;
unsigned short delay=0,index,myindex,temp,romptr=0;
- BOOLEAN dochiptest = TRUE;
+ bool dochiptest = true;
if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x20,0xbf);
@@ -9864,7 +9864,7 @@ SetDelayComp(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
} else if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD|SetCRT2ToLCDA)) { /* ---------- LCD/LCDA */
- BOOLEAN gotitfrompci = FALSE;
+ bool gotitfrompci = false;
/* Could we detect a PDC for LCD or did we get a user-defined? If yes, use it */
@@ -9916,22 +9916,22 @@ SetDelayComp(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
case CUT_COMPAQ1280:
case CUT_COMPAQ12802:
if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) {
- gotitfrompci = TRUE;
- dochiptest = FALSE;
+ gotitfrompci = true;
+ dochiptest = false;
delay = 0x03;
}
break;
case CUT_CLEVO1400:
case CUT_CLEVO14002:
- gotitfrompci = TRUE;
- dochiptest = FALSE;
+ gotitfrompci = true;
+ dochiptest = false;
delay = 0x02;
break;
case CUT_CLEVO1024:
case CUT_CLEVO10242:
if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) {
- gotitfrompci = TRUE;
- dochiptest = FALSE;
+ gotitfrompci = true;
+ dochiptest = false;
delay = 0x33;
SiS_SetReg(SiS_Pr->SiS_Part1Port,0x2D,delay);
delay &= 0x0f;
@@ -10009,7 +10009,7 @@ SetDelayComp(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2D,0x0F,((delay << 4) & 0xf0));
- dochiptest = FALSE;
+ dochiptest = false;
}
} else if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) { /* ------------ TV */
@@ -10043,12 +10043,12 @@ SetDelayComp(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
case CUT_CLEVO1400:
case CUT_CLEVO14002:
delay = 0x02;
- dochiptest = FALSE;
+ dochiptest = false;
break;
case CUT_CLEVO1024:
case CUT_CLEVO10242:
delay = 0x03;
- dochiptest = FALSE;
+ dochiptest = false;
break;
default:
delay = SiS310_TVDelayCompensation_651301LV[index];
@@ -10085,7 +10085,7 @@ SetDelayComp(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
if(SiS_LCDAEnabled(SiS_Pr)) {
delay &= 0x0f;
- dochiptest = FALSE;
+ dochiptest = false;
}
} else return;
@@ -10728,7 +10728,7 @@ SiS_FinalizeLCD(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned shor
SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1c,0x00);
SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1d,0x1b);
}
- if((SiS_Pr->Backup == TRUE) && (SiS_Pr->Backup_Mode == ModeNo)) {
+ if(SiS_Pr->Backup && (SiS_Pr->Backup_Mode == ModeNo)) {
SiS_SetReg(SiS_Pr->SiS_Part1Port,0x14,SiS_Pr->Backup_14);
SiS_SetReg(SiS_Pr->SiS_Part1Port,0x15,SiS_Pr->Backup_15);
SiS_SetReg(SiS_Pr->SiS_Part1Port,0x16,SiS_Pr->Backup_16);
diff --git a/drivers/video/sis/init301.h b/drivers/video/sis/init301.h
index 4f3a28699d3..7708e1e1d99 100644
--- a/drivers/video/sis/init301.h
+++ b/drivers/video/sis/init301.h
@@ -363,8 +363,8 @@ void SiS_LockCRT2(struct SiS_Private *SiS_Pr);
void SiS_EnableCRT2(struct SiS_Private *SiS_Pr);
unsigned short SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex);
void SiS_WaitRetrace1(struct SiS_Private *SiS_Pr);
-BOOLEAN SiS_IsDualEdge(struct SiS_Private *SiS_Pr);
-BOOLEAN SiS_IsVAMode(struct SiS_Private *SiS_Pr);
+bool SiS_IsDualEdge(struct SiS_Private *SiS_Pr);
+bool SiS_IsVAMode(struct SiS_Private *SiS_Pr);
void SiS_GetVBInfo(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
unsigned short ModeIdIndex, int checkcrt2mode);
void SiS_SetYPbPr(struct SiS_Private *SiS_Pr);
@@ -379,7 +379,7 @@ void SiS_DisableBridge(struct SiS_Private *SiS_Pr);
#ifndef SIS_LINUX_KERNEL
void SiS_EnableBridge(struct SiS_Private *SiS_Pr);
#endif
-BOOLEAN SiS_SetCRT2Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo);
+bool SiS_SetCRT2Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo);
void SiS_SiS30xBLOn(struct SiS_Private *SiS_Pr);
void SiS_SiS30xBLOff(struct SiS_Private *SiS_Pr);
@@ -403,7 +403,7 @@ void SiS_Chrontel701xBLOff(struct SiS_Private *SiS_Pr);
#endif /* 315 */
#ifdef SIS300
-static BOOLEAN SiS_SetTrumpionBlock(struct SiS_Private *SiS_Pr, unsigned char *dataptr);
+static bool SiS_SetTrumpionBlock(struct SiS_Private *SiS_Pr, unsigned char *dataptr);
void SiS_SetChrontelGPIO(struct SiS_Private *SiS_Pr, unsigned short myvbinfo);
#endif
@@ -416,14 +416,14 @@ unsigned short SiS_HandleDDC(struct SiS_Private *SiS_Pr, unsigned int VBFlags, i
#ifdef SIS_XORG_XF86
unsigned short SiS_InitDDCRegs(struct SiS_Private *SiS_Pr, unsigned int VBFlags,
int VGAEngine, unsigned short adaptnum, unsigned short DDCdatatype,
- BOOLEAN checkcr32, unsigned int VBFlags2);
+ bool checkcr32, unsigned int VBFlags2);
unsigned short SiS_ProbeDDC(struct SiS_Private *SiS_Pr);
unsigned short SiS_ReadDDC(struct SiS_Private *SiS_Pr, unsigned short DDCdatatype,
unsigned char *buffer);
#else
static unsigned short SiS_InitDDCRegs(struct SiS_Private *SiS_Pr, unsigned int VBFlags,
int VGAEngine, unsigned short adaptnum, unsigned short DDCdatatype,
- BOOLEAN checkcr32, unsigned int VBFlags2);
+ bool checkcr32, unsigned int VBFlags2);
static unsigned short SiS_ProbeDDC(struct SiS_Private *SiS_Pr);
static unsigned short SiS_ReadDDC(struct SiS_Private *SiS_Pr, unsigned short DDCdatatype,
unsigned char *buffer);
@@ -469,7 +469,7 @@ extern void SiS_SetRegOR(SISIOADDRESS, unsigned short, unsigned short);
extern void SiS_SetRegAND(SISIOADDRESS, unsigned short, unsigned short);
extern void SiS_DisplayOff(struct SiS_Private *SiS_Pr);
extern void SiS_DisplayOn(struct SiS_Private *SiS_Pr);
-extern BOOLEAN SiS_SearchModeID(struct SiS_Private *, unsigned short *, unsigned short *);
+extern bool SiS_SearchModeID(struct SiS_Private *, unsigned short *, unsigned short *);
extern unsigned short SiS_GetModeFlag(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
unsigned short ModeIdIndex);
extern unsigned short SiS_GetModePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short ModeIdIndex);
diff --git a/drivers/video/sis/initextlfb.c b/drivers/video/sis/initextlfb.c
index c3884a29f4c..47a33501549 100644
--- a/drivers/video/sis/initextlfb.c
+++ b/drivers/video/sis/initextlfb.c
@@ -38,14 +38,14 @@ int sisfb_mode_rate_to_dclock(struct SiS_Private *SiS_Pr,
unsigned char modeno, unsigned char rateindex);
int sisfb_mode_rate_to_ddata(struct SiS_Private *SiS_Pr, unsigned char modeno,
unsigned char rateindex, struct fb_var_screeninfo *var);
-BOOLEAN sisfb_gettotalfrommode(struct SiS_Private *SiS_Pr, unsigned char modeno,
+bool sisfb_gettotalfrommode(struct SiS_Private *SiS_Pr, unsigned char modeno,
int *htotal, int *vtotal, unsigned char rateindex);
-extern BOOLEAN SiSInitPtr(struct SiS_Private *SiS_Pr);
-extern BOOLEAN SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo,
+extern bool SiSInitPtr(struct SiS_Private *SiS_Pr);
+extern bool SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo,
unsigned short *ModeIdIndex);
extern void SiS_Generic_ConvertCRData(struct SiS_Private *SiS_Pr, unsigned char *crdata,
- int xres, int yres, struct fb_var_screeninfo *var, BOOLEAN writeres);
+ int xres, int yres, struct fb_var_screeninfo *var, bool writeres);
int
sisfb_mode_rate_to_dclock(struct SiS_Private *SiS_Pr, unsigned char modeno,
@@ -131,7 +131,7 @@ sisfb_mode_rate_to_ddata(struct SiS_Private *SiS_Pr, unsigned char modeno,
(unsigned char *)&SiS_Pr->SiS_CRT1Table[index].CR[0],
SiS_Pr->SiS_RefIndex[RRTI].XRes,
SiS_Pr->SiS_RefIndex[RRTI].YRes,
- var, FALSE);
+ var, false);
if(SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag & 0x8000)
var->sync &= ~FB_SYNC_VERT_HIGH_ACT;
@@ -175,7 +175,7 @@ sisfb_mode_rate_to_ddata(struct SiS_Private *SiS_Pr, unsigned char modeno,
return 1;
}
-BOOLEAN
+bool
sisfb_gettotalfrommode(struct SiS_Private *SiS_Pr, unsigned char modeno, int *htotal,
int *vtotal, unsigned char rateindex)
{
@@ -184,7 +184,7 @@ sisfb_gettotalfrommode(struct SiS_Private *SiS_Pr, unsigned char modeno, int *ht
unsigned short RRTI = 0;
unsigned char sr_data, cr_data, cr_data2;
- if(!SiSInitPtr(SiS_Pr)) return FALSE;
+ if(!SiSInitPtr(SiS_Pr)) return false;
if(rateindex > 0) rateindex--;
@@ -195,7 +195,7 @@ sisfb_gettotalfrommode(struct SiS_Private *SiS_Pr, unsigned char modeno, int *ht
}
#endif
- if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) return FALSE;
+ if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) return false;
RRTI = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex;
if(SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag & HaveWideTiming) {
@@ -226,7 +226,7 @@ sisfb_gettotalfrommode(struct SiS_Private *SiS_Pr, unsigned char modeno, int *ht
if(SiS_Pr->SiS_RefIndex[RRTI].Ext_InfoFlag & InterlaceMode)
*vtotal *= 2;
- return TRUE;
+ return true;
}
diff --git a/drivers/video/sis/sis.h b/drivers/video/sis/sis.h
index a259446ca7f..7d5ee2145e2 100644
--- a/drivers/video/sis/sis.h
+++ b/drivers/video/sis/sis.h
@@ -526,7 +526,7 @@ struct sis_video_info {
u16 vmax;
u32 dclockmax;
u8 feature;
- BOOLEAN datavalid;
+ bool datavalid;
} sisfb_thismonitor;
unsigned short chip_id; /* PCI ID of chip */
diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c
index baaf495a0a6..01197d74021 100644
--- a/drivers/video/sis/sis_main.c
+++ b/drivers/video/sis/sis_main.c
@@ -110,7 +110,7 @@ sisfb_setdefaultparms(void)
/* ------------- Parameter parsing -------------- */
static void __devinit
-sisfb_search_vesamode(unsigned int vesamode, BOOLEAN quiet)
+sisfb_search_vesamode(unsigned int vesamode, bool quiet)
{
int i = 0, j = 0;
@@ -150,7 +150,7 @@ sisfb_search_vesamode(unsigned int vesamode, BOOLEAN quiet)
}
static void __devinit
-sisfb_search_mode(char *name, BOOLEAN quiet)
+sisfb_search_mode(char *name, bool quiet)
{
unsigned int j = 0, xres = 0, yres = 0, depth = 0, rate = 0;
int i = 0;
@@ -251,7 +251,7 @@ sisfb_get_vga_mode_from_kernel(void)
"sisfb: Using vga mode %s pre-set by kernel as default\n",
mymode);
- sisfb_search_mode(mymode, TRUE);
+ sisfb_search_mode(mymode, true);
}
#endif
return;
@@ -307,7 +307,7 @@ static void __init
sisfb_search_specialtiming(const char *name)
{
int i = 0;
- BOOLEAN found = FALSE;
+ bool found = false;
/* We don't know the hardware specs yet and there is no ivideo */
@@ -322,7 +322,7 @@ sisfb_search_specialtiming(const char *name)
if(!strnicmp(name,mycustomttable[i].optionName,
strlen(mycustomttable[i].optionName))) {
sisfb_specialtiming = mycustomttable[i].SpecialID;
- found = TRUE;
+ found = true;
printk(KERN_INFO "sisfb: Special timing for %s %s forced (\"%s\")\n",
mycustomttable[i].vendorName,
mycustomttable[i].cardName,
@@ -353,7 +353,7 @@ sisfb_detect_custom_timing(struct sis_video_info *ivideo)
{
unsigned char *biosver = NULL;
unsigned char *biosdate = NULL;
- BOOLEAN footprint;
+ bool footprint;
u32 chksum = 0;
int i, j;
@@ -380,16 +380,16 @@ sisfb_detect_custom_timing(struct sis_video_info *ivideo)
(mycustomttable[i].bioschksum == chksum))) &&
(mycustomttable[i].pcisubsysvendor == ivideo->subsysvendor) &&
(mycustomttable[i].pcisubsyscard == ivideo->subsysdevice) ) {
- footprint = TRUE;
+ footprint = true;
for(j = 0; j < 5; j++) {
if(mycustomttable[i].biosFootprintAddr[j]) {
if(ivideo->SiS_Pr.UseROM) {
if(ivideo->SiS_Pr.VirtualRomBase[mycustomttable[i].biosFootprintAddr[j]] !=
mycustomttable[i].biosFootprintData[j]) {
- footprint = FALSE;
+ footprint = false;
}
} else
- footprint = FALSE;
+ footprint = false;
}
}
if(footprint) {
@@ -406,7 +406,7 @@ sisfb_detect_custom_timing(struct sis_video_info *ivideo)
} while(mycustomttable[i].chipID);
}
-static BOOLEAN __devinit
+static bool __devinit
sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer)
{
int i, j, xres, yres, refresh, index;
@@ -417,13 +417,13 @@ sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer)
buffer[4] != 0xff || buffer[5] != 0xff ||
buffer[6] != 0xff || buffer[7] != 0x00) {
printk(KERN_DEBUG "sisfb: Bad EDID header\n");
- return FALSE;
+ return false;
}
if(buffer[0x12] != 0x01) {
printk(KERN_INFO "sisfb: EDID version %d not supported\n",
buffer[0x12]);
- return FALSE;
+ return false;
}
monitor->feature = buffer[0x18];
@@ -449,7 +449,7 @@ sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer)
monitor->vmin = buffer[j + 5];
monitor->vmax = buffer[j + 6];
monitor->dclockmax = buffer[j + 9] * 10 * 1000;
- monitor->datavalid = TRUE;
+ monitor->datavalid = true;
break;
}
j += 18;
@@ -501,7 +501,7 @@ sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer)
index += 2;
}
if((monitor->hmin <= monitor->hmax) && (monitor->vmin <= monitor->vmax)) {
- monitor->datavalid = TRUE;
+ monitor->datavalid = true;
}
}
@@ -514,7 +514,7 @@ sisfb_handle_ddc(struct sis_video_info *ivideo, struct sisfb_monitor *monitor, i
unsigned short temp, i, realcrtno = crtno;
unsigned char buffer[256];
- monitor->datavalid = FALSE;
+ monitor->datavalid = false;
if(crtno) {
if(ivideo->vbflags & CRT2_LCD) realcrtno = 1;
@@ -563,7 +563,7 @@ sisfb_handle_ddc(struct sis_video_info *ivideo, struct sisfb_monitor *monitor, i
/* -------------- Mode validation --------------- */
-static BOOLEAN
+static bool
sisfb_verify_rate(struct sis_video_info *ivideo, struct sisfb_monitor *monitor,
int mode_idx, int rate_idx, int rate)
{
@@ -571,10 +571,10 @@ sisfb_verify_rate(struct sis_video_info *ivideo, struct sisfb_monitor *monitor,
unsigned int dclock, hsync;
if(!monitor->datavalid)
- return TRUE;
+ return true;
if(mode_idx < 0)
- return FALSE;
+ return false;
/* Skip for 320x200, 320x240, 640x400 */
switch(sisbios_mode[mode_idx].mode_no[ivideo->mni]) {
@@ -587,34 +587,34 @@ sisfb_verify_rate(struct sis_video_info *ivideo, struct sisfb_monitor *monitor,
case 0x2f:
case 0x5d:
case 0x5e:
- return TRUE;
+ return true;
#ifdef CONFIG_FB_SIS_315
case 0x5a:
case 0x5b:
- if(ivideo->sisvga_engine == SIS_315_VGA) return TRUE;
+ if(ivideo->sisvga_engine == SIS_315_VGA) return true;
#endif
}
if(rate < (monitor->vmin - 1))
- return FALSE;
+ return false;
if(rate > (monitor->vmax + 1))
- return FALSE;
+ return false;
if(sisfb_gettotalfrommode(&ivideo->SiS_Pr,
sisbios_mode[mode_idx].mode_no[ivideo->mni],
&htotal, &vtotal, rate_idx)) {
dclock = (htotal * vtotal * rate) / 1000;
if(dclock > (monitor->dclockmax + 1000))
- return FALSE;
+ return false;
hsync = dclock / htotal;
if(hsync < (monitor->hmin - 1))
- return FALSE;
+ return false;
if(hsync > (monitor->hmax + 1))
- return FALSE;
+ return false;
} else {
- return FALSE;
+ return false;
}
- return TRUE;
+ return true;
}
static int
@@ -732,49 +732,49 @@ sisfb_search_refresh_rate(struct sis_video_info *ivideo, unsigned int rate, int
}
}
-static BOOLEAN
+static bool
sisfb_bridgeisslave(struct sis_video_info *ivideo)
{
unsigned char P1_00;
if(!(ivideo->vbflags2 & VB2_VIDEOBRIDGE))
- return FALSE;
+ return false;
inSISIDXREG(SISPART1,0x00,P1_00);
if( ((ivideo->sisvga_engine == SIS_300_VGA) && (P1_00 & 0xa0) == 0x20) ||
((ivideo->sisvga_engine == SIS_315_VGA) && (P1_00 & 0x50) == 0x10) ) {
- return TRUE;
+ return true;
} else {
- return FALSE;
+ return false;
}
}
-static BOOLEAN
+static bool
sisfballowretracecrt1(struct sis_video_info *ivideo)
{
u8 temp;
inSISIDXREG(SISCR,0x17,temp);
if(!(temp & 0x80))
- return FALSE;
+ return false;
inSISIDXREG(SISSR,0x1f,temp);
if(temp & 0xc0)
- return FALSE;
+ return false;
- return TRUE;
+ return true;
}
-static BOOLEAN
+static bool
sisfbcheckvretracecrt1(struct sis_video_info *ivideo)
{
if(!sisfballowretracecrt1(ivideo))
- return FALSE;
+ return false;
if(inSISREG(SISINPSTAT) & 0x08)
- return TRUE;
+ return true;
else
- return FALSE;
+ return false;
}
static void
@@ -791,7 +791,7 @@ sisfbwaitretracecrt1(struct sis_video_info *ivideo)
while((inSISREG(SISINPSTAT) & 0x08) && --watchdog);
}
-static BOOLEAN
+static bool
sisfbcheckvretracecrt2(struct sis_video_info *ivideo)
{
unsigned char temp, reg;
@@ -799,17 +799,17 @@ sisfbcheckvretracecrt2(struct sis_video_info *ivideo)
switch(ivideo->sisvga_engine) {
case SIS_300_VGA: reg = 0x25; break;
case SIS_315_VGA: reg = 0x30; break;
- default: return FALSE;
+ default: return false;
}
inSISIDXREG(SISPART1, reg, temp);
if(temp & 0x02)
- return TRUE;
+ return true;
else
- return FALSE;
+ return false;
}
-static BOOLEAN
+static bool
sisfb_CheckVBRetrace(struct sis_video_info *ivideo)
{
if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
@@ -874,7 +874,7 @@ static int
sisfb_myblank(struct sis_video_info *ivideo, int blank)
{
u8 sr01, sr11, sr1f, cr63=0, p2_0, p1_13;
- BOOLEAN backlight = TRUE;
+ bool backlight = true;
switch(blank) {
case FB_BLANK_UNBLANK: /* on */
@@ -884,7 +884,7 @@ sisfb_myblank(struct sis_video_info *ivideo, int blank)
cr63 = 0x00;
p2_0 = 0x20;
p1_13 = 0x00;
- backlight = TRUE;
+ backlight = true;
break;
case FB_BLANK_NORMAL: /* blank */
sr01 = 0x20;
@@ -893,7 +893,7 @@ sisfb_myblank(struct sis_video_info *ivideo, int blank)
cr63 = 0x00;
p2_0 = 0x20;
p1_13 = 0x00;
- backlight = TRUE;
+ backlight = true;
break;
case FB_BLANK_VSYNC_SUSPEND: /* no vsync */
sr01 = 0x20;
@@ -902,7 +902,7 @@ sisfb_myblank(struct sis_video_info *ivideo, int blank)
cr63 = 0x40;
p2_0 = 0x40;
p1_13 = 0x80;
- backlight = FALSE;
+ backlight = false;
break;
case FB_BLANK_HSYNC_SUSPEND: /* no hsync */
sr01 = 0x20;
@@ -911,7 +911,7 @@ sisfb_myblank(struct sis_video_info *ivideo, int blank)
cr63 = 0x40;
p2_0 = 0x80;
p1_13 = 0x40;
- backlight = FALSE;
+ backlight = false;
break;
case FB_BLANK_POWERDOWN: /* off */
sr01 = 0x20;
@@ -920,7 +920,7 @@ sisfb_myblank(struct sis_video_info *ivideo, int blank)
cr63 = 0x40;
p2_0 = 0xc0;
p1_13 = 0xc0;
- backlight = FALSE;
+ backlight = false;
break;
default:
return 1;
@@ -1109,11 +1109,11 @@ sisfb_calc_pitch(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
static void
sisfb_set_pitch(struct sis_video_info *ivideo)
{
- BOOLEAN isslavemode = FALSE;
+ bool isslavemode = false;
unsigned short HDisplay1 = ivideo->scrnpitchCRT1 >> 3;
unsigned short HDisplay2 = ivideo->video_linelength >> 3;
- if(sisfb_bridgeisslave(ivideo)) isslavemode = TRUE;
+ if(sisfb_bridgeisslave(ivideo)) isslavemode = true;
/* We need to set pitch for CRT1 if bridge is in slave mode, too */
if((ivideo->currentvbflags & VB_DISPTYPE_DISP1) || (isslavemode)) {
@@ -1178,7 +1178,7 @@ sisfb_set_mode(struct sis_video_info *ivideo, int clrscrn)
sisfb_pre_setmode(ivideo);
- if(SiSSetMode(&ivideo->SiS_Pr, modeno) == 0) {
+ if(!SiSSetMode(&ivideo->SiS_Pr, modeno)) {
printk(KERN_ERR "sisfb: Setting mode[0x%x] failed\n", ivideo->mode_no);
return -EINVAL;
}
@@ -1446,7 +1446,7 @@ sisfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
unsigned int drate = 0, hrate = 0, maxyres;
int found_mode = 0;
int refresh_rate, search_idx, tidx;
- BOOLEAN recalc_clock = FALSE;
+ bool recalc_clock = false;
u32 pixclock;
htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
@@ -1524,7 +1524,7 @@ sisfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
(var->bits_per_pixel == 8) ) {
/* Slave modes on LVDS and 301B-DH */
refresh_rate = 60;
- recalc_clock = TRUE;
+ recalc_clock = true;
} else if( (ivideo->current_htotal == htotal) &&
(ivideo->current_vtotal == vtotal) &&
(ivideo->current_pixclock == pixclock) ) {
@@ -1545,17 +1545,17 @@ sisfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
} else {
refresh_rate = 60;
}
- recalc_clock = TRUE;
+ recalc_clock = true;
} else if((pixclock) && (htotal) && (vtotal)) {
drate = 1000000000 / pixclock;
hrate = (drate * 1000) / htotal;
refresh_rate = (unsigned int) (hrate * 2 / vtotal);
} else if(ivideo->current_refresh_rate) {
refresh_rate = ivideo->current_refresh_rate;
- recalc_clock = TRUE;
+ recalc_clock = true;
} else {
refresh_rate = 60;
- recalc_clock = TRUE;
+ recalc_clock = true;
}
myrateindex = sisfb_search_refresh_rate(ivideo, refresh_rate, search_idx);
@@ -2181,7 +2181,7 @@ sisfb_detect_VB_connect(struct sis_video_info *ivideo)
/* ------------------ Sensing routines ------------------ */
-static BOOLEAN __devinit
+static bool __devinit
sisfb_test_DDC1(struct sis_video_info *ivideo)
{
unsigned short old;
@@ -2191,13 +2191,13 @@ sisfb_test_DDC1(struct sis_video_info *ivideo)
do {
if(old != SiS_ReadDDC1Bit(&ivideo->SiS_Pr)) break;
} while(count--);
- return (count == -1) ? FALSE : TRUE;
+ return (count != -1);
}
static void __devinit
sisfb_sense_crt1(struct sis_video_info *ivideo)
{
- BOOLEAN mustwait = FALSE;
+ bool mustwait = false;
u8 sr1F, cr17;
#ifdef CONFIG_FB_SIS_315
u8 cr63=0;
@@ -2208,7 +2208,7 @@ sisfb_sense_crt1(struct sis_video_info *ivideo)
inSISIDXREG(SISSR,0x1F,sr1F);
orSISIDXREG(SISSR,0x1F,0x04);
andSISIDXREG(SISSR,0x1F,0x3F);
- if(sr1F & 0xc0) mustwait = TRUE;
+ if(sr1F & 0xc0) mustwait = true;
#ifdef CONFIG_FB_SIS_315
if(ivideo->sisvga_engine == SIS_315_VGA) {
@@ -2222,7 +2222,7 @@ sisfb_sense_crt1(struct sis_video_info *ivideo)
cr17 &= 0x80;
if(!cr17) {
orSISIDXREG(SISCR,0x17,0x80);
- mustwait = TRUE;
+ mustwait = true;
outSISIDXREG(SISSR, 0x00, 0x01);
outSISIDXREG(SISSR, 0x00, 0x03);
}
@@ -2284,7 +2284,7 @@ SiS_SenseLCD(struct sis_video_info *ivideo)
u8 reg, cr37 = 0, paneltype = 0;
u16 xres, yres;
- ivideo->SiS_Pr.PanelSelfDetected = FALSE;
+ ivideo->SiS_Pr.PanelSelfDetected = false;
/* LCD detection only for TMDS bridges */
if(!(ivideo->vbflags2 & VB2_SISTMDSBRIDGE))
@@ -2361,7 +2361,7 @@ SiS_SenseLCD(struct sis_video_info *ivideo)
setSISIDXREG(SISCR, 0x37, 0x0c, cr37);
orSISIDXREG(SISCR, 0x32, 0x08);
- ivideo->SiS_Pr.PanelSelfDetected = TRUE;
+ ivideo->SiS_Pr.PanelSelfDetected = true;
}
static int __devinit
@@ -3016,7 +3016,7 @@ sisfb_save_pdc_emi(struct sis_video_info *ivideo)
int tmp;
inSISIDXREG(SISPART1,0x13,tmp);
if(tmp & 0x04) {
- ivideo->SiS_Pr.SiS_UseLCDA = TRUE;
+ ivideo->SiS_Pr.SiS_UseLCDA = true;
ivideo->detectedlcda = 0x03;
}
}
@@ -3071,9 +3071,9 @@ sisfb_save_pdc_emi(struct sis_video_info *ivideo)
inSISIDXREG(SISPART4,0x31,ivideo->SiS_Pr.EMI_31);
inSISIDXREG(SISPART4,0x32,ivideo->SiS_Pr.EMI_32);
inSISIDXREG(SISPART4,0x33,ivideo->SiS_Pr.EMI_33);
- ivideo->SiS_Pr.HaveEMI = TRUE;
+ ivideo->SiS_Pr.HaveEMI = true;
if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
- ivideo->SiS_Pr.HaveEMILCD = TRUE;
+ ivideo->SiS_Pr.HaveEMILCD = true;
}
}
}
@@ -3558,8 +3558,8 @@ sisfb_pre_setmode(struct sis_video_info *ivideo)
}
#endif
- SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
- SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
+ SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
+ SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
ivideo->curFSTN = ivideo->curDSTN = 0;
switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
@@ -3814,8 +3814,8 @@ sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val)
static void
sisfb_post_setmode(struct sis_video_info *ivideo)
{
- BOOLEAN crt1isoff = FALSE;
- BOOLEAN doit = TRUE;
+ bool crt1isoff = false;
+ bool doit = true;
#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
u8 reg;
#endif
@@ -3834,17 +3834,17 @@ sisfb_post_setmode(struct sis_video_info *ivideo)
/* We can't switch off CRT1 if bridge is in slave mode */
if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
- if(sisfb_bridgeisslave(ivideo)) doit = FALSE;
+ if(sisfb_bridgeisslave(ivideo)) doit = false;
} else
ivideo->sisfb_crt1off = 0;
#ifdef CONFIG_FB_SIS_300
if(ivideo->sisvga_engine == SIS_300_VGA) {
if((ivideo->sisfb_crt1off) && (doit)) {
- crt1isoff = TRUE;
+ crt1isoff = true;
reg = 0x00;
} else {
- crt1isoff = FALSE;
+ crt1isoff = false;
reg = 0x80;
}
setSISIDXREG(SISCR, 0x17, 0x7f, reg);
@@ -3853,11 +3853,11 @@ sisfb_post_setmode(struct sis_video_info *ivideo)
#ifdef CONFIG_FB_SIS_315
if(ivideo->sisvga_engine == SIS_315_VGA) {
if((ivideo->sisfb_crt1off) && (doit)) {
- crt1isoff = TRUE;
+ crt1isoff = true;
reg = 0x40;
reg1 = 0xc0;
} else {
- crt1isoff = FALSE;
+ crt1isoff = false;
reg = 0x00;
reg1 = 0x00;
}
@@ -4004,9 +4004,9 @@ sisfb_setup(char *options)
} else if(!strnicmp(this_opt, "tvstandard:",11)) {
sisfb_search_tvstd(this_opt + 11);
} else if(!strnicmp(this_opt, "mode:", 5)) {
- sisfb_search_mode(this_opt + 5, FALSE);
+ sisfb_search_mode(this_opt + 5, false);
} else if(!strnicmp(this_opt, "vesa:", 5)) {
- sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0), FALSE);
+ sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0), false);
} else if(!strnicmp(this_opt, "rate:", 5)) {
sisfb_parm_rate = simple_strtoul(this_opt + 5, NULL, 0);
} else if(!strnicmp(this_opt, "forcecrt1:", 10)) {
@@ -4062,7 +4062,7 @@ sisfb_setup(char *options)
sisfb_lvdshl = temp;
}
} else if(this_opt[0] >= '0' && this_opt[0] <= '9') {
- sisfb_search_mode(this_opt, TRUE);
+ sisfb_search_mode(this_opt, true);
#if !defined(__i386__) && !defined(__x86_64__)
} else if(!strnicmp(this_opt, "resetcard", 9)) {
sisfb_resetcard = 1;
@@ -4564,9 +4564,9 @@ sisfb_post_sis300(struct pci_dev *pdev)
sisfb_sense_crt1(ivideo);
/* Set default mode, don't clear screen */
- ivideo->SiS_Pr.SiS_UseOEM = FALSE;
- SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
- SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
+ ivideo->SiS_Pr.SiS_UseOEM = false;
+ SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
+ SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
ivideo->curFSTN = ivideo->curDSTN = 0;
ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
@@ -5680,9 +5680,9 @@ sisfb_post_xgi(struct pci_dev *pdev)
} else {
/* Set default mode, don't clear screen */
- ivideo->SiS_Pr.SiS_UseOEM = FALSE;
- SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
- SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
+ ivideo->SiS_Pr.SiS_UseOEM = false;
+ SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
+ SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
ivideo->curFSTN = ivideo->curDSTN = 0;
ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
@@ -5723,9 +5723,9 @@ sisfb_post_xgi(struct pci_dev *pdev)
}
/* Set default mode, don't clear screen */
- ivideo->SiS_Pr.SiS_UseOEM = FALSE;
- SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
- SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
+ ivideo->SiS_Pr.SiS_UseOEM = false;
+ SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
+ SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
ivideo->curFSTN = ivideo->curDSTN = 0;
SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
@@ -5819,7 +5819,7 @@ sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
ivideo->detectedpdca = 0xff;
ivideo->detectedlcda = 0xff;
- ivideo->sisfb_thismonitor.datavalid = FALSE;
+ ivideo->sisfb_thismonitor.datavalid = false;
ivideo->current_base = 0;
@@ -5871,21 +5871,21 @@ sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
ivideo->SiS_Pr.SiS_Backup70xx = 0xff;
ivideo->SiS_Pr.SiS_CHOverScan = -1;
- ivideo->SiS_Pr.SiS_ChSW = FALSE;
- ivideo->SiS_Pr.SiS_UseLCDA = FALSE;
- ivideo->SiS_Pr.HaveEMI = FALSE;
- ivideo->SiS_Pr.HaveEMILCD = FALSE;
- ivideo->SiS_Pr.OverruleEMI = FALSE;
- ivideo->SiS_Pr.SiS_SensibleSR11 = FALSE;
+ ivideo->SiS_Pr.SiS_ChSW = false;
+ ivideo->SiS_Pr.SiS_UseLCDA = false;
+ ivideo->SiS_Pr.HaveEMI = false;
+ ivideo->SiS_Pr.HaveEMILCD = false;
+ ivideo->SiS_Pr.OverruleEMI = false;
+ ivideo->SiS_Pr.SiS_SensibleSR11 = false;
ivideo->SiS_Pr.SiS_MyCR63 = 0x63;
ivideo->SiS_Pr.PDC = -1;
ivideo->SiS_Pr.PDCA = -1;
- ivideo->SiS_Pr.DDCPortMixup = FALSE;
+ ivideo->SiS_Pr.DDCPortMixup = false;
#ifdef CONFIG_FB_SIS_315
if(ivideo->chip >= SIS_330) {
ivideo->SiS_Pr.SiS_MyCR63 = 0x53;
if(ivideo->chip >= SIS_661) {
- ivideo->SiS_Pr.SiS_SensibleSR11 = TRUE;
+ ivideo->SiS_Pr.SiS_SensibleSR11 = true;
}
}
#endif
@@ -5969,7 +5969,7 @@ sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
do {
if(mychswtable[i].subsysVendor == ivideo->subsysvendor &&
mychswtable[i].subsysCard == ivideo->subsysdevice) {
- ivideo->SiS_Pr.SiS_ChSW = TRUE;
+ ivideo->SiS_Pr.SiS_ChSW = true;
printk(KERN_DEBUG "sisfb: Identified [%s %s] "
"requiring Chrontel/GPIO setup\n",
mychswtable[i].vendorName,
@@ -6018,20 +6018,20 @@ sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Search and copy ROM image */
ivideo->bios_abase = NULL;
ivideo->SiS_Pr.VirtualRomBase = NULL;
- ivideo->SiS_Pr.UseROM = FALSE;
- ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = FALSE;
+ ivideo->SiS_Pr.UseROM = false;
+ ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = false;
if(ivideo->sisfb_userom) {
ivideo->SiS_Pr.VirtualRomBase = sisfb_find_rom(pdev);
ivideo->bios_abase = ivideo->SiS_Pr.VirtualRomBase;
- ivideo->SiS_Pr.UseROM = (ivideo->SiS_Pr.VirtualRomBase) ? TRUE : FALSE;
+ ivideo->SiS_Pr.UseROM = (bool)(ivideo->SiS_Pr.VirtualRomBase);
printk(KERN_INFO "sisfb: Video ROM %sfound\n",
ivideo->SiS_Pr.UseROM ? "" : "not ");
if((ivideo->SiS_Pr.UseROM) && (ivideo->chip >= XGI_20)) {
- ivideo->SiS_Pr.UseROM = FALSE;
- ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = TRUE;
+ ivideo->SiS_Pr.UseROM = false;
+ ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = true;
if( (ivideo->revision_id == 2) &&
(!(ivideo->bios_abase[0x1d1] & 0x01)) ) {
- ivideo->SiS_Pr.DDCPortMixup = TRUE;
+ ivideo->SiS_Pr.DDCPortMixup = true;
}
}
} else {
@@ -6677,9 +6677,9 @@ static int __init sisfb_init_module(void)
sisfb_search_tvstd(tvstandard);
if(mode)
- sisfb_search_mode(mode, FALSE);
+ sisfb_search_mode(mode, false);
else if(vesa != -1)
- sisfb_search_vesamode(vesa, FALSE);
+ sisfb_search_vesamode(vesa, false);
sisfb_crt1off = (crt1off == 0) ? 1 : 0;
diff --git a/drivers/video/sis/sis_main.h b/drivers/video/sis/sis_main.h
index 88e4f1e4147..3e3b7fa05d6 100644
--- a/drivers/video/sis/sis_main.h
+++ b/drivers/video/sis/sis_main.h
@@ -411,54 +411,54 @@ static const struct _sis_vrate {
u16 xres;
u16 yres;
u16 refresh;
- BOOLEAN SiS730valid32bpp;
+ bool SiS730valid32bpp;
} sisfb_vrate[] = {
- {1, 320, 200, 70, TRUE},
- {1, 320, 240, 60, TRUE},
- {1, 400, 300, 60, TRUE},
- {1, 512, 384, 60, TRUE},
- {1, 640, 400, 72, TRUE},
- {1, 640, 480, 60, TRUE}, {2, 640, 480, 72, TRUE}, {3, 640, 480, 75, TRUE},
- {4, 640, 480, 85, TRUE}, {5, 640, 480, 100, TRUE}, {6, 640, 480, 120, TRUE},
- {7, 640, 480, 160, TRUE}, {8, 640, 480, 200, TRUE},
- {1, 720, 480, 60, TRUE},
- {1, 720, 576, 58, TRUE},
- {1, 768, 576, 58, TRUE},
- {1, 800, 480, 60, TRUE}, {2, 800, 480, 75, TRUE}, {3, 800, 480, 85, TRUE},
- {1, 800, 600, 56, TRUE}, {2, 800, 600, 60, TRUE}, {3, 800, 600, 72, TRUE},
- {4, 800, 600, 75, TRUE}, {5, 800, 600, 85, TRUE}, {6, 800, 600, 105, TRUE},
- {7, 800, 600, 120, TRUE}, {8, 800, 600, 160, TRUE},
- {1, 848, 480, 39, TRUE}, {2, 848, 480, 60, TRUE},
- {1, 856, 480, 39, TRUE}, {2, 856, 480, 60, TRUE},
- {1, 960, 540, 60, TRUE},
- {1, 960, 600, 60, TRUE},
- {1, 1024, 576, 60, TRUE}, {2, 1024, 576, 75, TRUE}, {3, 1024, 576, 85, TRUE},
- {1, 1024, 600, 60, TRUE},
- {1, 1024, 768, 43, TRUE}, {2, 1024, 768, 60, TRUE}, {3, 1024, 768, 70, FALSE},
- {4, 1024, 768, 75, FALSE}, {5, 1024, 768, 85, TRUE}, {6, 1024, 768, 100, TRUE},
- {7, 1024, 768, 120, TRUE},
- {1, 1152, 768, 60, TRUE},
- {1, 1152, 864, 60, TRUE}, {2, 1152, 864, 75, TRUE}, {3, 1152, 864, 84, TRUE},
- {1, 1280, 720, 60, TRUE}, {2, 1280, 720, 75, TRUE}, {3, 1280, 720, 85, TRUE},
- {1, 1280, 768, 60, TRUE},
- {1, 1280, 800, 60, TRUE},
- {1, 1280, 854, 60, TRUE},
- {1, 1280, 960, 60, TRUE}, {2, 1280, 960, 85, TRUE},
- {1, 1280, 1024, 43, TRUE}, {2, 1280, 1024, 60, TRUE}, {3, 1280, 1024, 75, TRUE},
- {4, 1280, 1024, 85, TRUE},
- {1, 1360, 768, 60, TRUE},
- {1, 1360, 1024, 59, TRUE},
- {1, 1400, 1050, 60, TRUE}, {2, 1400, 1050, 75, TRUE},
- {1, 1600, 1200, 60, TRUE}, {2, 1600, 1200, 65, TRUE}, {3, 1600, 1200, 70, TRUE},
- {4, 1600, 1200, 75, TRUE}, {5, 1600, 1200, 85, TRUE}, {6, 1600, 1200, 100, TRUE},
- {7, 1600, 1200, 120, TRUE},
- {1, 1680, 1050, 60, TRUE},
- {1, 1920, 1080, 30, TRUE},
- {1, 1920, 1440, 60, TRUE}, {2, 1920, 1440, 65, TRUE}, {3, 1920, 1440, 70, TRUE},
- {4, 1920, 1440, 75, TRUE}, {5, 1920, 1440, 85, TRUE}, {6, 1920, 1440, 100, TRUE},
- {1, 2048, 1536, 60, TRUE}, {2, 2048, 1536, 65, TRUE}, {3, 2048, 1536, 70, TRUE},
- {4, 2048, 1536, 75, TRUE}, {5, 2048, 1536, 85, TRUE},
- {0, 0, 0, 0, FALSE}
+ {1, 320, 200, 70, true},
+ {1, 320, 240, 60, true},
+ {1, 400, 300, 60, true},
+ {1, 512, 384, 60, true},
+ {1, 640, 400, 72, true},
+ {1, 640, 480, 60, true}, {2, 640, 480, 72, true}, {3, 640, 480, 75, true},
+ {4, 640, 480, 85, true}, {5, 640, 480, 100, true}, {6, 640, 480, 120, true},
+ {7, 640, 480, 160, true}, {8, 640, 480, 200, true},
+ {1, 720, 480, 60, true},
+ {1, 720, 576, 58, true},
+ {1, 768, 576, 58, true},
+ {1, 800, 480, 60, true}, {2, 800, 480, 75, true}, {3, 800, 480, 85, true},
+ {1, 800, 600, 56, true}, {2, 800, 600, 60, true}, {3, 800, 600, 72, true},
+ {4, 800, 600, 75, true}, {5, 800, 600, 85, true}, {6, 800, 600, 105, true},
+ {7, 800, 600, 120, true}, {8, 800, 600, 160, true},
+ {1, 848, 480, 39, true}, {2, 848, 480, 60, true},
+ {1, 856, 480, 39, true}, {2, 856, 480, 60, true},
+ {1, 960, 540, 60, true},
+ {1, 960, 600, 60, true},
+ {1, 1024, 576, 60, true}, {2, 1024, 576, 75, true}, {3, 1024, 576, 85, true},
+ {1, 1024, 600, 60, true},
+ {1, 1024, 768, 43, true}, {2, 1024, 768, 60, true}, {3, 1024, 768, 70, false},
+ {4, 1024, 768, 75, false}, {5, 1024, 768, 85, true}, {6, 1024, 768, 100, true},
+ {7, 1024, 768, 120, true},
+ {1, 1152, 768, 60, true},
+ {1, 1152, 864, 60, true}, {2, 1152, 864, 75, true}, {3, 1152, 864, 84, true},
+ {1, 1280, 720, 60, true}, {2, 1280, 720, 75, true}, {3, 1280, 720, 85, true},
+ {1, 1280, 768, 60, true},
+ {1, 1280, 800, 60, true},
+ {1, 1280, 854, 60, true},
+ {1, 1280, 960, 60, true}, {2, 1280, 960, 85, true},
+ {1, 1280, 1024, 43, true}, {2, 1280, 1024, 60, true}, {3, 1280, 1024, 75, true},
+ {4, 1280, 1024, 85, true},
+ {1, 1360, 768, 60, true},
+ {1, 1360, 1024, 59, true},
+ {1, 1400, 1050, 60, true}, {2, 1400, 1050, 75, true},
+ {1, 1600, 1200, 60, true}, {2, 1600, 1200, 65, true}, {3, 1600, 1200, 70, true},
+ {4, 1600, 1200, 75, true}, {5, 1600, 1200, 85, true}, {6, 1600, 1200, 100, true},
+ {7, 1600, 1200, 120, true},
+ {1, 1680, 1050, 60, true},
+ {1, 1920, 1080, 30, true},
+ {1, 1920, 1440, 60, true}, {2, 1920, 1440, 65, true}, {3, 1920, 1440, 70, true},
+ {4, 1920, 1440, 75, true}, {5, 1920, 1440, 85, true}, {6, 1920, 1440, 100, true},
+ {1, 2048, 1536, 60, true}, {2, 2048, 1536, 65, true}, {3, 2048, 1536, 70, true},
+ {4, 2048, 1536, 75, true}, {5, 2048, 1536, 85, true},
+ {0, 0, 0, 0, false}
};
static struct _sisfbddcsmodes {
@@ -691,7 +691,7 @@ extern int sisfb_initaccel(struct sis_video_info *ivideo);
extern void sisfb_syncaccel(struct sis_video_info *ivideo);
/* Internal general routines */
-static void sisfb_search_mode(char *name, BOOLEAN quiet);
+static void sisfb_search_mode(char *name, bool quiet);
static int sisfb_validate_mode(struct sis_video_info *ivideo, int modeindex, u32 vbflags);
static u8 sisfb_search_refresh_rate(struct sis_video_info *ivideo, unsigned int rate,
int index);
@@ -702,10 +702,10 @@ static int sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive,
struct fb_info *info);
static void sisfb_pre_setmode(struct sis_video_info *ivideo);
static void sisfb_post_setmode(struct sis_video_info *ivideo);
-static BOOLEAN sisfb_CheckVBRetrace(struct sis_video_info *ivideo);
-static BOOLEAN sisfbcheckvretracecrt2(struct sis_video_info *ivideo);
-static BOOLEAN sisfbcheckvretracecrt1(struct sis_video_info *ivideo);
-static BOOLEAN sisfb_bridgeisslave(struct sis_video_info *ivideo);
+static bool sisfb_CheckVBRetrace(struct sis_video_info *ivideo);
+static bool sisfbcheckvretracecrt2(struct sis_video_info *ivideo);
+static bool sisfbcheckvretracecrt1(struct sis_video_info *ivideo);
+static bool sisfb_bridgeisslave(struct sis_video_info *ivideo);
static void sisfb_detect_VB_connect(struct sis_video_info *ivideo);
static void sisfb_get_VB_type(struct sis_video_info *ivideo);
static void sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val);
@@ -737,20 +737,20 @@ static void sisfb_free_node(struct SIS_HEAP *memheap, struct SIS_OH *poh);
/* Routines from init.c/init301.c */
extern unsigned short SiS_GetModeID_LCD(int VGAEngine, unsigned int VBFlags, int HDisplay,
- int VDisplay, int Depth, BOOLEAN FSTN, unsigned short CustomT,
+ int VDisplay, int Depth, bool FSTN, unsigned short CustomT,
int LCDwith, int LCDheight, unsigned int VBFlags2);
extern unsigned short SiS_GetModeID_TV(int VGAEngine, unsigned int VBFlags, int HDisplay,
int VDisplay, int Depth, unsigned int VBFlags2);
extern unsigned short SiS_GetModeID_VGA2(int VGAEngine, unsigned int VBFlags, int HDisplay,
int VDisplay, int Depth, unsigned int VBFlags2);
extern void SiSRegInit(struct SiS_Private *SiS_Pr, SISIOADDRESS BaseAddr);
-extern BOOLEAN SiSSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo);
+extern bool SiSSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo);
extern void SiS_SetEnableDstn(struct SiS_Private *SiS_Pr, int enable);
extern void SiS_SetEnableFstn(struct SiS_Private *SiS_Pr, int enable);
-extern BOOLEAN SiSDetermineROMLayout661(struct SiS_Private *SiS_Pr);
+extern bool SiSDetermineROMLayout661(struct SiS_Private *SiS_Pr);
-extern BOOLEAN sisfb_gettotalfrommode(struct SiS_Private *SiS_Pr, unsigned char modeno,
+extern bool sisfb_gettotalfrommode(struct SiS_Private *SiS_Pr, unsigned char modeno,
int *htotal, int *vtotal, unsigned char rateindex);
extern int sisfb_mode_rate_to_dclock(struct SiS_Private *SiS_Pr,
unsigned char modeno, unsigned char rateindex);
diff --git a/drivers/video/sis/vgatypes.h b/drivers/video/sis/vgatypes.h
index 05d08b7889a..b532fbd2b04 100644
--- a/drivers/video/sis/vgatypes.h
+++ b/drivers/video/sis/vgatypes.h
@@ -57,18 +57,6 @@
#include <linux/version.h>
#endif
-#ifndef FALSE
-#define FALSE 0
-#endif
-
-#ifndef TRUE
-#define TRUE 1
-#endif
-
-#ifndef BOOLEAN
-typedef unsigned int BOOLEAN;
-#endif
-
#define SISIOMEMTYPE
#ifdef SIS_LINUX_KERNEL
diff --git a/drivers/video/sis/vstruct.h b/drivers/video/sis/vstruct.h
index 9ae32923c14..705c8536052 100644
--- a/drivers/video/sis/vstruct.h
+++ b/drivers/video/sis/vstruct.h
@@ -240,7 +240,7 @@ struct SiS_Private
void *ivideo;
#endif
unsigned char *VirtualRomBase;
- BOOLEAN UseROM;
+ bool UseROM;
#ifdef SIS_LINUX_KERNEL
unsigned char SISIOMEMTYPE *VideoMemoryAddress;
unsigned int VideoMemorySize;
@@ -283,24 +283,24 @@ struct SiS_Private
#ifdef SIS_XORG_XF86
unsigned short SiS_CP1, SiS_CP2, SiS_CP3, SiS_CP4;
#endif
- BOOLEAN SiS_UseROM;
- BOOLEAN SiS_ROMNew;
- BOOLEAN SiS_XGIROM;
- BOOLEAN SiS_NeedRomModeData;
- BOOLEAN PanelSelfDetected;
- BOOLEAN DDCPortMixup;
+ bool SiS_UseROM;
+ bool SiS_ROMNew;
+ bool SiS_XGIROM;
+ bool SiS_NeedRomModeData;
+ bool PanelSelfDetected;
+ bool DDCPortMixup;
int SiS_CHOverScan;
- BOOLEAN SiS_CHSOverScan;
- BOOLEAN SiS_ChSW;
- BOOLEAN SiS_UseLCDA;
+ bool SiS_CHSOverScan;
+ bool SiS_ChSW;
+ bool SiS_UseLCDA;
int SiS_UseOEM;
unsigned int SiS_CustomT;
int SiS_UseWide, SiS_UseWideCRT2;
int SiS_TVBlue;
unsigned short SiS_Backup70xx;
- BOOLEAN HaveEMI;
- BOOLEAN HaveEMILCD;
- BOOLEAN OverruleEMI;
+ bool HaveEMI;
+ bool HaveEMILCD;
+ bool OverruleEMI;
unsigned char EMI_30,EMI_31,EMI_32,EMI_33;
unsigned short SiS_EMIOffset;
unsigned short SiS_PWDOffset;
@@ -352,7 +352,7 @@ struct SiS_Private
unsigned short SiS_DDC_ReadAddr;
unsigned short SiS_DDC_SecAddr;
unsigned short SiS_ChrontelInit;
- BOOLEAN SiS_SensibleSR11;
+ bool SiS_SensibleSR11;
unsigned short SiS661LCD2TableSize;
unsigned short SiS_PanelMinLVDS;
@@ -494,10 +494,10 @@ struct SiS_Private
unsigned short PanelVRS, PanelVRE;
unsigned short PanelVCLKIdx300;
unsigned short PanelVCLKIdx315;
- BOOLEAN Alternate1600x1200;
+ bool Alternate1600x1200;
- BOOLEAN UseCustomMode;
- BOOLEAN CRT1UsesCustomMode;
+ bool UseCustomMode;
+ bool CRT1UsesCustomMode;
unsigned short CHDisplay;
unsigned short CHSyncStart;
unsigned short CHSyncEnd;
@@ -523,7 +523,7 @@ struct SiS_Private
int LVDSHL;
- BOOLEAN Backup;
+ bool Backup;
unsigned char Backup_Mode;
unsigned char Backup_14;
unsigned char Backup_15;
@@ -542,12 +542,12 @@ struct SiS_Private
int CenterScreen;
unsigned short CP_Vendor, CP_Product;
- BOOLEAN CP_HaveCustomData;
+ bool CP_HaveCustomData;
int CP_PreferredX, CP_PreferredY, CP_PreferredIndex;
int CP_MaxX, CP_MaxY, CP_MaxClock;
unsigned char CP_PrefSR2B, CP_PrefSR2C;
unsigned short CP_PrefClock;
- BOOLEAN CP_Supports64048075;
+ bool CP_Supports64048075;
int CP_HDisplay[7], CP_VDisplay[7]; /* For Custom LCD panel dimensions */
int CP_HTotal[7], CP_VTotal[7];
int CP_HSyncStart[7], CP_VSyncStart[7];
@@ -555,8 +555,8 @@ struct SiS_Private
int CP_HBlankStart[7], CP_VBlankStart[7];
int CP_HBlankEnd[7], CP_VBlankEnd[7];
int CP_Clock[7];
- BOOLEAN CP_DataValid[7];
- BOOLEAN CP_HSync_P[7], CP_VSync_P[7], CP_SyncValid[7];
+ bool CP_DataValid[7];
+ bool CP_HSync_P[7], CP_VSync_P[7], CP_SyncValid[7];
};
#endif
diff --git a/drivers/video/sm501fb.c b/drivers/video/sm501fb.c
new file mode 100644
index 00000000000..02b290ca01e
--- /dev/null
+++ b/drivers/video/sm501fb.c
@@ -0,0 +1,1786 @@
+/* linux/drivers/video/sm501fb.c
+ *
+ * Copyright (c) 2006 Simtec Electronics
+ * Vincent Sanders <vince@simtec.co.uk>
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Framebuffer driver for the Silicon Motion SM501
+ */
+
+#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/vmalloc.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 <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/div64.h>
+
+#ifdef CONFIG_PM
+#include <linux/pm.h>
+#endif
+
+#include <linux/sm501.h>
+#include <linux/sm501-regs.h>
+
+#define NR_PALETTE 256
+
+enum sm501_controller {
+ HEAD_CRT = 0,
+ HEAD_PANEL = 1,
+};
+
+/* SM501 memory adress */
+struct sm501_mem {
+ unsigned long size;
+ unsigned long sm_addr;
+ void __iomem *k_addr;
+};
+
+/* private data that is shared between all frambuffers* */
+struct sm501fb_info {
+ struct device *dev;
+ struct fb_info *fb[2]; /* fb info for both heads */
+ struct resource *fbmem_res; /* framebuffer resource */
+ struct resource *regs_res; /* registers resource */
+ struct sm501_platdata_fb *pdata; /* our platform data */
+
+ int irq;
+ int swap_endian; /* set to swap rgb=>bgr */
+ void __iomem *regs; /* remapped registers */
+ void __iomem *fbmem; /* remapped framebuffer */
+ size_t fbmem_len; /* length of remapped region */
+};
+
+/* per-framebuffer private data */
+struct sm501fb_par {
+ u32 pseudo_palette[16];
+
+ enum sm501_controller head;
+ struct sm501_mem cursor;
+ struct sm501_mem screen;
+ struct fb_ops ops;
+
+ void *store_fb;
+ void *store_cursor;
+ void __iomem *cursor_regs;
+ struct sm501fb_info *info;
+};
+
+/* Helper functions */
+
+static inline int h_total(struct fb_var_screeninfo *var)
+{
+ return var->xres + var->left_margin +
+ var->right_margin + var->hsync_len;
+}
+
+static inline int v_total(struct fb_var_screeninfo *var)
+{
+ return var->yres + var->upper_margin +
+ var->lower_margin + var->vsync_len;
+}
+
+/* sm501fb_sync_regs()
+ *
+ * This call is mainly for PCI bus systems where we need to
+ * ensure that any writes to the bus are completed before the
+ * next phase, or after completing a function.
+*/
+
+static inline void sm501fb_sync_regs(struct sm501fb_info *info)
+{
+ readl(info->regs);
+}
+
+/* sm501_alloc_mem
+ *
+ * This is an attempt to lay out memory for the two framebuffers and
+ * everything else
+ *
+ * |fbmem_res->start fbmem_res->end|
+ * | |
+ * |fb[0].fix.smem_start | |fb[1].fix.smem_start | 2K |
+ * |-> fb[0].fix.smem_len <-| spare |-> fb[1].fix.smem_len <-|-> cursors <-|
+ *
+ * The "spare" space is for the 2d engine data
+ * the fixed is space for the cursors (2x1Kbyte)
+ *
+ * we need to allocate memory for the 2D acceleration engine
+ * command list and the data for the engine to deal with.
+ *
+ * - all allocations must be 128bit aligned
+ * - cursors are 64x64x2 bits (1Kbyte)
+ *
+ */
+
+#define SM501_MEMF_CURSOR (1)
+#define SM501_MEMF_PANEL (2)
+#define SM501_MEMF_CRT (4)
+#define SM501_MEMF_ACCEL (8)
+
+int sm501_alloc_mem(struct sm501fb_info *inf, struct sm501_mem *mem,
+ unsigned int why, size_t size)
+{
+ unsigned int ptr = 0;
+
+ switch (why) {
+ case SM501_MEMF_CURSOR:
+ ptr = inf->fbmem_len - size;
+ inf->fbmem_len = ptr;
+ break;
+
+ case SM501_MEMF_PANEL:
+ ptr = inf->fbmem_len - size;
+ if (ptr < inf->fb[0]->fix.smem_len)
+ return -ENOMEM;
+
+ break;
+
+ case SM501_MEMF_CRT:
+ ptr = 0;
+ break;
+
+ case SM501_MEMF_ACCEL:
+ ptr = inf->fb[0]->fix.smem_len;
+
+ if ((ptr + size) >
+ (inf->fb[1]->fix.smem_start - inf->fbmem_res->start))
+ return -ENOMEM;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ mem->size = size;
+ mem->sm_addr = ptr;
+ mem->k_addr = inf->fbmem + ptr;
+
+ dev_dbg(inf->dev, "%s: result %08lx, %p - %u, %zd\n",
+ __func__, mem->sm_addr, mem->k_addr, why, size);
+
+ return 0;
+}
+
+/* sm501fb_ps_to_hz
+ *
+ * Converts a period in picoseconds to Hz.
+ *
+ * Note, we try to keep this in Hz to minimise rounding with
+ * the limited PLL settings on the SM501.
+*/
+
+static unsigned long sm501fb_ps_to_hz(unsigned long psvalue)
+{
+ unsigned long long numerator=1000000000000ULL;
+
+ /* 10^12 / picosecond period gives frequency in Hz */
+ do_div(numerator, psvalue);
+ return (unsigned long)numerator;
+}
+
+/* sm501fb_hz_to_ps is identical to the oposite transform */
+
+#define sm501fb_hz_to_ps(x) sm501fb_ps_to_hz(x)
+
+/* sm501fb_setup_gamma
+ *
+ * Programs a linear 1.0 gamma ramp in case the gamma
+ * correction is enabled without programming anything else.
+*/
+
+static void sm501fb_setup_gamma(struct sm501fb_info *fbi,
+ unsigned long palette)
+{
+ unsigned long value = 0;
+ int offset;
+
+ /* set gamma values */
+ for (offset = 0; offset < 256 * 4; offset += 4) {
+ writel(value, fbi->regs + palette + offset);
+ value += 0x010101; /* Advance RGB by 1,1,1.*/
+ }
+}
+
+/* sm501fb_check_var
+ *
+ * check common variables for both panel and crt
+*/
+
+static int sm501fb_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ struct sm501fb_par *par = info->par;
+ struct sm501fb_info *sm = par->info;
+ unsigned long tmp;
+
+ /* check we can fit these values into the registers */
+
+ if (var->hsync_len > 255 || var->vsync_len > 255)
+ return -EINVAL;
+
+ if ((var->xres + var->right_margin) >= 4096)
+ return -EINVAL;
+
+ if ((var->yres + var->lower_margin) > 2048)
+ return -EINVAL;
+
+ /* hard limits of device */
+
+ if (h_total(var) > 4096 || v_total(var) > 2048)
+ return -EINVAL;
+
+ /* check our line length is going to be 128 bit aligned */
+
+ tmp = (var->xres * var->bits_per_pixel) / 8;
+ if ((tmp & 15) != 0)
+ return -EINVAL;
+
+ /* check the virtual size */
+
+ if (var->xres_virtual > 4096 || var->yres_virtual > 2048)
+ return -EINVAL;
+
+ /* can cope with 8,16 or 32bpp */
+
+ if (var->bits_per_pixel <= 8)
+ var->bits_per_pixel = 8;
+ else if (var->bits_per_pixel <= 16)
+ var->bits_per_pixel = 16;
+ else if (var->bits_per_pixel == 24)
+ var->bits_per_pixel = 32;
+
+ /* set r/g/b positions and validate bpp */
+ switch(var->bits_per_pixel) {
+ case 8:
+ var->red.length = var->bits_per_pixel;
+ var->red.offset = 0;
+ var->green.length = var->bits_per_pixel;
+ var->green.offset = 0;
+ var->blue.length = var->bits_per_pixel;
+ var->blue.offset = 0;
+ var->transp.length = 0;
+
+ break;
+
+ case 16:
+ if (sm->pdata->flags & SM501_FBPD_SWAP_FB_ENDIAN) {
+ var->red.offset = 11;
+ var->green.offset = 5;
+ var->blue.offset = 0;
+ } else {
+ var->blue.offset = 11;
+ var->green.offset = 5;
+ var->red.offset = 0;
+ }
+
+ var->red.length = 5;
+ var->green.length = 6;
+ var->blue.length = 5;
+ var->transp.length = 0;
+ break;
+
+ case 32:
+ if (sm->pdata->flags & SM501_FBPD_SWAP_FB_ENDIAN) {
+ var->transp.offset = 0;
+ var->red.offset = 8;
+ var->green.offset = 16;
+ var->blue.offset = 24;
+ } else {
+ var->transp.offset = 24;
+ var->red.offset = 16;
+ var->green.offset = 8;
+ var->blue.offset = 0;
+ }
+
+ var->red.length = 8;
+ var->green.length = 8;
+ var->blue.length = 8;
+ var->transp.length = 0;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ * sm501fb_check_var_crt():
+ *
+ * check the parameters for the CRT head, and either bring them
+ * back into range, or return -EINVAL.
+*/
+
+static int sm501fb_check_var_crt(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ return sm501fb_check_var(var, info);
+}
+
+/* sm501fb_check_var_pnl():
+ *
+ * check the parameters for the CRT head, and either bring them
+ * back into range, or return -EINVAL.
+*/
+
+static int sm501fb_check_var_pnl(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ return sm501fb_check_var(var, info);
+}
+
+/* sm501fb_set_par_common
+ *
+ * set common registers for framebuffers
+*/
+
+static int sm501fb_set_par_common(struct fb_info *info,
+ struct fb_var_screeninfo *var)
+{
+ 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 int mem_type;
+ unsigned int clock_type;
+ unsigned int head_addr;
+
+ dev_dbg(fbi->dev, "%s: %dx%d, bpp = %d, virtual %dx%d\n",
+ __func__, var->xres, var->yres, var->bits_per_pixel,
+ var->xres_virtual, var->yres_virtual);
+
+ switch (par->head) {
+ case HEAD_CRT:
+ mem_type = SM501_MEMF_CRT;
+ clock_type = SM501_CLOCK_V2XCLK;
+ head_addr = SM501_DC_CRT_FB_ADDR;
+ break;
+
+ case HEAD_PANEL:
+ mem_type = SM501_MEMF_PANEL;
+ clock_type = SM501_CLOCK_P2XCLK;
+ head_addr = SM501_DC_PANEL_FB_ADDR;
+ break;
+
+ default:
+ mem_type = 0; /* stop compiler warnings */
+ head_addr = 0;
+ clock_type = 0;
+ }
+
+ switch (var->bits_per_pixel) {
+ case 8:
+ info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+ break;
+
+ case 16:
+ info->fix.visual = FB_VISUAL_DIRECTCOLOR;
+ break;
+
+ case 32:
+ info->fix.visual = FB_VISUAL_TRUECOLOR;
+ break;
+ }
+
+ /* allocate fb memory within 501 */
+ info->fix.line_length = (var->xres_virtual * var->bits_per_pixel)/8;
+ info->fix.smem_len = info->fix.line_length * var->yres_virtual;
+
+ dev_dbg(fbi->dev, "%s: line length = %u\n", __func__,
+ info->fix.line_length);
+
+ if (sm501_alloc_mem(fbi, &par->screen, mem_type,
+ info->fix.smem_len)) {
+ dev_err(fbi->dev, "no memory available\n");
+ return -ENOMEM;
+ }
+
+ info->fix.smem_start = fbi->fbmem_res->start + par->screen.sm_addr;
+
+ info->screen_base = fbi->fbmem + par->screen.sm_addr;
+ info->screen_size = info->fix.smem_len;
+
+ /* set start of framebuffer to the screen */
+
+ writel(par->screen.sm_addr | SM501_ADDR_FLIP, fbi->regs + head_addr);
+
+ /* program CRT clock */
+
+ pixclock = sm501fb_ps_to_hz(var->pixclock);
+
+ sm501pixclock = sm501_set_clock(fbi->dev->parent, clock_type,
+ pixclock);
+
+ /* update fb layer with actual clock used */
+ var->pixclock = sm501fb_hz_to_ps(sm501pixclock);
+
+ dev_dbg(fbi->dev, "%s: pixclock(ps) = %u, pixclock(Hz) = %lu, "
+ "sm501pixclock = %lu, error = %ld%%\n",
+ __func__, var->pixclock, pixclock, sm501pixclock,
+ ((pixclock - sm501pixclock)*100)/pixclock);
+
+ return 0;
+}
+
+/* sm501fb_set_par_geometry
+ *
+ * set the geometry registers for specified framebuffer.
+*/
+
+static void sm501fb_set_par_geometry(struct fb_info *info,
+ struct fb_var_screeninfo *var)
+{
+ struct sm501fb_par *par = info->par;
+ struct sm501fb_info *fbi = par->info;
+ void __iomem *base = fbi->regs;
+ unsigned long reg;
+
+ if (par->head == HEAD_CRT)
+ base += SM501_DC_CRT_H_TOT;
+ else
+ base += SM501_DC_PANEL_H_TOT;
+
+ /* set framebuffer width and display width */
+
+ reg = info->fix.line_length;
+ reg |= ((var->xres * var->bits_per_pixel)/8) << 16;
+
+ writel(reg, fbi->regs + (par->head == HEAD_CRT ?
+ SM501_DC_CRT_FB_OFFSET : SM501_DC_PANEL_FB_OFFSET));
+
+ /* program horizontal total */
+
+ reg = (h_total(var) - 1) << 16;
+ reg |= (var->xres - 1);
+
+ writel(reg, base + SM501_OFF_DC_H_TOT);
+
+ /* program horizontal sync */
+
+ reg = var->hsync_len << 16;
+ reg |= var->xres + var->right_margin - 1;
+
+ writel(reg, base + SM501_OFF_DC_H_SYNC);
+
+ /* program vertical total */
+
+ reg = (v_total(var) - 1) << 16;
+ reg |= (var->yres - 1);
+
+ writel(reg, base + SM501_OFF_DC_V_TOT);
+
+ /* program vertical sync */
+ reg = var->vsync_len << 16;
+ reg |= var->yres + var->lower_margin - 1;
+
+ writel(reg, base + SM501_OFF_DC_V_SYNC);
+}
+
+/* sm501fb_pan_crt
+ *
+ * pan the CRT display output within an virtual framebuffer
+*/
+
+static int sm501fb_pan_crt(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ struct sm501fb_par *par = info->par;
+ struct sm501fb_info *fbi = par->info;
+ unsigned int bytes_pixel = var->bits_per_pixel / 8;
+ unsigned long reg;
+ unsigned long xoffs;
+
+ xoffs = var->xoffset * bytes_pixel;
+
+ reg = readl(fbi->regs + SM501_DC_CRT_CONTROL);
+
+ reg &= ~SM501_DC_CRT_CONTROL_PIXEL_MASK;
+ reg |= ((xoffs & 15) / bytes_pixel) << 4;
+ writel(reg, fbi->regs + SM501_DC_CRT_CONTROL);
+
+ reg = (par->screen.sm_addr + xoffs +
+ var->yoffset * info->fix.line_length);
+ writel(reg | SM501_ADDR_FLIP, fbi->regs + SM501_DC_CRT_FB_ADDR);
+
+ sm501fb_sync_regs(fbi);
+ return 0;
+}
+
+/* sm501fb_pan_pnl
+ *
+ * pan the panel display output within an virtual framebuffer
+*/
+
+static int sm501fb_pan_pnl(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ struct sm501fb_par *par = info->par;
+ struct sm501fb_info *fbi = par->info;
+ unsigned long reg;
+
+ reg = var->xoffset | (var->xres_virtual << 16);
+ writel(reg, fbi->regs + SM501_DC_PANEL_FB_WIDTH);
+
+ reg = var->yoffset | (var->yres_virtual << 16);
+ writel(reg, fbi->regs + SM501_DC_PANEL_FB_HEIGHT);
+
+ sm501fb_sync_regs(fbi);
+ return 0;
+}
+
+/* sm501fb_set_par_crt
+ *
+ * Set the CRT video mode from the fb_info structure
+*/
+
+static int sm501fb_set_par_crt(struct fb_info *info)
+{
+ struct sm501fb_par *par = info->par;
+ struct sm501fb_info *fbi = par->info;
+ struct fb_var_screeninfo *var = &info->var;
+ unsigned long control; /* control register */
+ int ret;
+
+ /* activate new configuration */
+
+ dev_dbg(fbi->dev, "%s(%p)\n", __func__, info);
+
+ /* enable CRT DAC - note 0 is on!*/
+ sm501_misc_control(fbi->dev->parent, 0, SM501_MISC_DAC_POWER);
+
+ control = readl(fbi->regs + SM501_DC_CRT_CONTROL);
+
+ control &= (SM501_DC_CRT_CONTROL_PIXEL_MASK |
+ SM501_DC_CRT_CONTROL_GAMMA |
+ SM501_DC_CRT_CONTROL_BLANK |
+ SM501_DC_CRT_CONTROL_SEL |
+ SM501_DC_CRT_CONTROL_CP |
+ SM501_DC_CRT_CONTROL_TVP);
+
+ /* set the sync polarities before we check data source */
+
+ if ((var->sync & FB_SYNC_HOR_HIGH_ACT) == 0)
+ control |= SM501_DC_CRT_CONTROL_HSP;
+
+ if ((var->sync & FB_SYNC_VERT_HIGH_ACT) == 0)
+ control |= SM501_DC_CRT_CONTROL_VSP;
+
+ if ((control & SM501_DC_CRT_CONTROL_SEL) == 0) {
+ /* the head is displaying panel data... */
+
+ sm501_alloc_mem(fbi, &par->screen, SM501_MEMF_CRT, 0);
+ goto out_update;
+ }
+
+ ret = sm501fb_set_par_common(info, var);
+ if (ret) {
+ dev_err(fbi->dev, "failed to set common parameters\n");
+ return ret;
+ }
+
+ sm501fb_pan_crt(var, info);
+ sm501fb_set_par_geometry(info, var);
+
+ control |= SM501_FIFO_3; /* fill if >3 free slots */
+
+ switch(var->bits_per_pixel) {
+ case 8:
+ control |= SM501_DC_CRT_CONTROL_8BPP;
+ break;
+
+ case 16:
+ control |= SM501_DC_CRT_CONTROL_16BPP;
+ break;
+
+ case 32:
+ control |= SM501_DC_CRT_CONTROL_32BPP;
+ sm501fb_setup_gamma(fbi, SM501_DC_CRT_PALETTE);
+ break;
+
+ default:
+ BUG();
+ }
+
+ control |= SM501_DC_CRT_CONTROL_SEL; /* CRT displays CRT data */
+ control |= SM501_DC_CRT_CONTROL_TE; /* enable CRT timing */
+ control |= SM501_DC_CRT_CONTROL_ENABLE; /* enable CRT plane */
+
+ out_update:
+ dev_dbg(fbi->dev, "new control is %08lx\n", control);
+
+ writel(control, fbi->regs + SM501_DC_CRT_CONTROL);
+ sm501fb_sync_regs(fbi);
+
+ return 0;
+}
+
+static void sm501fb_panel_power(struct sm501fb_info *fbi, int to)
+{
+ unsigned long control;
+ void __iomem *ctrl_reg = fbi->regs + SM501_DC_PANEL_CONTROL;
+
+ control = readl(ctrl_reg);
+
+ if (to && (control & SM501_DC_PANEL_CONTROL_VDD) == 0) {
+ /* enable panel power */
+
+ control |= SM501_DC_PANEL_CONTROL_VDD; /* FPVDDEN */
+ writel(control, ctrl_reg);
+ sm501fb_sync_regs(fbi);
+ mdelay(10);
+
+ control |= SM501_DC_PANEL_CONTROL_DATA; /* DATA */
+ writel(control, ctrl_reg);
+ sm501fb_sync_regs(fbi);
+ mdelay(10);
+
+ control |= SM501_DC_PANEL_CONTROL_BIAS; /* VBIASEN */
+ writel(control, ctrl_reg);
+ sm501fb_sync_regs(fbi);
+ mdelay(10);
+
+ control |= SM501_DC_PANEL_CONTROL_FPEN;
+ writel(control, ctrl_reg);
+
+ } else if (!to && (control & SM501_DC_PANEL_CONTROL_VDD) != 0) {
+ /* disable panel power */
+
+ control &= ~SM501_DC_PANEL_CONTROL_FPEN;
+ writel(control, ctrl_reg);
+ sm501fb_sync_regs(fbi);
+ mdelay(10);
+
+ control &= ~SM501_DC_PANEL_CONTROL_BIAS;
+ writel(control, ctrl_reg);
+ sm501fb_sync_regs(fbi);
+ mdelay(10);
+
+ control &= ~SM501_DC_PANEL_CONTROL_DATA;
+ writel(control, ctrl_reg);
+ sm501fb_sync_regs(fbi);
+ mdelay(10);
+
+ control &= ~SM501_DC_PANEL_CONTROL_VDD;
+ writel(control, ctrl_reg);
+ sm501fb_sync_regs(fbi);
+ mdelay(10);
+ }
+
+ sm501fb_sync_regs(fbi);
+}
+
+/* sm501fb_set_par_pnl
+ *
+ * Set the panel video mode from the fb_info structure
+*/
+
+static int sm501fb_set_par_pnl(struct fb_info *info)
+{
+ struct sm501fb_par *par = info->par;
+ struct sm501fb_info *fbi = par->info;
+ struct fb_var_screeninfo *var = &info->var;
+ unsigned long control;
+ unsigned long reg;
+ int ret;
+
+ dev_dbg(fbi->dev, "%s(%p)\n", __func__, info);
+
+ /* activate this new configuration */
+
+ ret = sm501fb_set_par_common(info, var);
+ if (ret)
+ return ret;
+
+ sm501fb_pan_pnl(var, info);
+ sm501fb_set_par_geometry(info, var);
+
+ /* update control register */
+
+ control = readl(fbi->regs + SM501_DC_PANEL_CONTROL);
+ control &= (SM501_DC_PANEL_CONTROL_GAMMA |
+ SM501_DC_PANEL_CONTROL_VDD |
+ SM501_DC_PANEL_CONTROL_DATA |
+ SM501_DC_PANEL_CONTROL_BIAS |
+ SM501_DC_PANEL_CONTROL_FPEN |
+ SM501_DC_PANEL_CONTROL_CP |
+ SM501_DC_PANEL_CONTROL_CK |
+ SM501_DC_PANEL_CONTROL_HP |
+ SM501_DC_PANEL_CONTROL_VP |
+ SM501_DC_PANEL_CONTROL_HPD |
+ SM501_DC_PANEL_CONTROL_VPD);
+
+ control |= SM501_FIFO_3; /* fill if >3 free slots */
+
+ switch(var->bits_per_pixel) {
+ case 8:
+ control |= SM501_DC_PANEL_CONTROL_8BPP;
+ break;
+
+ case 16:
+ control |= SM501_DC_PANEL_CONTROL_16BPP;
+ break;
+
+ case 32:
+ control |= SM501_DC_PANEL_CONTROL_32BPP;
+ sm501fb_setup_gamma(fbi, SM501_DC_PANEL_PALETTE);
+ break;
+
+ default:
+ BUG();
+ }
+
+ writel(0x0, fbi->regs + SM501_DC_PANEL_PANNING_CONTROL);
+
+ /* panel plane top left and bottom right location */
+
+ writel(0x00, fbi->regs + SM501_DC_PANEL_TL_LOC);
+
+ reg = var->xres - 1;
+ reg |= (var->yres - 1) << 16;
+
+ writel(reg, fbi->regs + SM501_DC_PANEL_BR_LOC);
+
+ /* program panel control register */
+
+ control |= SM501_DC_PANEL_CONTROL_TE; /* enable PANEL timing */
+ control |= SM501_DC_PANEL_CONTROL_EN; /* enable PANEL gfx plane */
+
+ if ((var->sync & FB_SYNC_HOR_HIGH_ACT) == 0)
+ control |= SM501_DC_PANEL_CONTROL_HSP;
+
+ if ((var->sync & FB_SYNC_VERT_HIGH_ACT) == 0)
+ control |= SM501_DC_PANEL_CONTROL_VSP;
+
+ writel(control, fbi->regs + SM501_DC_PANEL_CONTROL);
+ sm501fb_sync_regs(fbi);
+
+ /* power the panel up */
+ sm501fb_panel_power(fbi, 1);
+ return 0;
+}
+
+
+/* chan_to_field
+ *
+ * convert a colour value into a field position
+ *
+ * from pxafb.c
+*/
+
+static inline unsigned int chan_to_field(unsigned int chan,
+ struct fb_bitfield *bf)
+{
+ chan &= 0xffff;
+ chan >>= 16 - bf->length;
+ return chan << bf->offset;
+}
+
+/* sm501fb_setcolreg
+ *
+ * set the colour mapping for modes that support palettised data
+*/
+
+static int sm501fb_setcolreg(unsigned regno,
+ unsigned red, unsigned green, unsigned blue,
+ unsigned transp, struct fb_info *info)
+{
+ struct sm501fb_par *par = info->par;
+ struct sm501fb_info *fbi = par->info;
+ void __iomem *base = fbi->regs;
+ unsigned int val;
+
+ if (par->head == HEAD_CRT)
+ base += SM501_DC_CRT_PALETTE;
+ else
+ base += SM501_DC_PANEL_PALETTE;
+
+ switch (info->fix.visual) {
+ case FB_VISUAL_TRUECOLOR:
+ /* true-colour, use pseuo-palette */
+
+ if (regno < 16) {
+ u32 *pal = par->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;
+
+ case FB_VISUAL_PSEUDOCOLOR:
+ if (regno < 256) {
+ val = (red >> 8) << 16;
+ val |= (green >> 8) << 8;
+ val |= blue >> 8;
+
+ writel(val, base + (regno * 4));
+ }
+
+ break;
+
+ default:
+ return 1; /* unknown type */
+ }
+
+ return 0;
+}
+
+/* sm501fb_blank_pnl
+ *
+ * Blank or un-blank the panel interface
+*/
+
+static int sm501fb_blank_pnl(int blank_mode, struct fb_info *info)
+{
+ struct sm501fb_par *par = info->par;
+ struct sm501fb_info *fbi = par->info;
+
+ dev_dbg(fbi->dev, "%s(mode=%d, %p)\n", __func__, blank_mode, info);
+
+ switch (blank_mode) {
+ case FB_BLANK_POWERDOWN:
+ sm501fb_panel_power(fbi, 0);
+ break;
+
+ case FB_BLANK_UNBLANK:
+ sm501fb_panel_power(fbi, 1);
+ break;
+
+ case FB_BLANK_NORMAL:
+ case FB_BLANK_VSYNC_SUSPEND:
+ case FB_BLANK_HSYNC_SUSPEND:
+ default:
+ return 1;
+ }
+
+ return 0;
+}
+
+/* sm501fb_blank_crt
+ *
+ * Blank or un-blank the crt interface
+*/
+
+static int sm501fb_blank_crt(int blank_mode, struct fb_info *info)
+{
+ struct sm501fb_par *par = info->par;
+ struct sm501fb_info *fbi = par->info;
+ unsigned long ctrl;
+
+ dev_dbg(fbi->dev, "%s(mode=%d, %p)\n", __func__, blank_mode, info);
+
+ ctrl = readl(fbi->regs + SM501_DC_CRT_CONTROL);
+
+ switch (blank_mode) {
+ case FB_BLANK_POWERDOWN:
+ ctrl &= ~SM501_DC_CRT_CONTROL_ENABLE;
+ sm501_misc_control(fbi->dev->parent, SM501_MISC_DAC_POWER, 0);
+
+ case FB_BLANK_NORMAL:
+ ctrl |= SM501_DC_CRT_CONTROL_BLANK;
+ break;
+
+ case FB_BLANK_UNBLANK:
+ ctrl &= ~SM501_DC_CRT_CONTROL_BLANK;
+ ctrl |= SM501_DC_CRT_CONTROL_ENABLE;
+ sm501_misc_control(fbi->dev->parent, 0, SM501_MISC_DAC_POWER);
+ break;
+
+ case FB_BLANK_VSYNC_SUSPEND:
+ case FB_BLANK_HSYNC_SUSPEND:
+ default:
+ return 1;
+
+ }
+
+ writel(ctrl, fbi->regs + SM501_DC_CRT_CONTROL);
+ sm501fb_sync_regs(fbi);
+
+ return 0;
+}
+
+/* sm501fb_cursor
+ *
+ * set or change the hardware cursor parameters
+*/
+
+int sm501fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
+{
+ struct sm501fb_par *par = info->par;
+ struct sm501fb_info *fbi = par->info;
+ void __iomem *base = fbi->regs;
+ unsigned long hwc_addr;
+ unsigned long fg, bg;
+
+ dev_dbg(fbi->dev, "%s(%p,%p)\n", __func__, info, cursor);
+
+ if (par->head == HEAD_CRT)
+ base += SM501_DC_CRT_HWC_BASE;
+ else
+ base += SM501_DC_PANEL_HWC_BASE;
+
+ /* check not being asked to exceed capabilities */
+
+ if (cursor->image.width > 64)
+ return -EINVAL;
+
+ if (cursor->image.height > 64)
+ return -EINVAL;
+
+ if (cursor->image.depth > 1)
+ return -EINVAL;
+
+ hwc_addr = readl(base + SM501_OFF_HWC_ADDR);
+
+ if (cursor->enable)
+ writel(hwc_addr | SM501_HWC_EN, base + SM501_OFF_HWC_ADDR);
+ else
+ writel(hwc_addr & ~SM501_HWC_EN, base + SM501_OFF_HWC_ADDR);
+
+ /* set data */
+ if (cursor->set & FB_CUR_SETPOS) {
+ unsigned int x = cursor->image.dx;
+ unsigned int y = cursor->image.dy;
+
+ if (x >= 2048 || y >= 2048 )
+ return -EINVAL;
+
+ dev_dbg(fbi->dev, "set position %d,%d\n", x, y);
+
+ //y += cursor->image.height;
+
+ writel(x | (y << 16), base + SM501_OFF_HWC_LOC);
+ }
+
+ if (cursor->set & FB_CUR_SETCMAP) {
+ unsigned int bg_col = cursor->image.bg_color;
+ unsigned int fg_col = cursor->image.fg_color;
+
+ dev_dbg(fbi->dev, "%s: update cmap (%08x,%08x)\n",
+ __func__, bg_col, fg_col);
+
+ bg = ((info->cmap.red[bg_col] & 0xF8) << 8) |
+ ((info->cmap.green[bg_col] & 0xFC) << 3) |
+ ((info->cmap.blue[bg_col] & 0xF8) >> 3);
+
+ fg = ((info->cmap.red[fg_col] & 0xF8) << 8) |
+ ((info->cmap.green[fg_col] & 0xFC) << 3) |
+ ((info->cmap.blue[fg_col] & 0xF8) >> 3);
+
+ dev_dbg(fbi->dev, "fgcol %08x, bgcol %08x\n", fg, bg);
+
+ writel(bg, base + SM501_OFF_HWC_COLOR_1_2);
+ writel(fg, base + SM501_OFF_HWC_COLOR_3);
+ }
+
+ if (cursor->set & FB_CUR_SETSIZE ||
+ cursor->set & (FB_CUR_SETIMAGE | FB_CUR_SETSHAPE)) {
+ /* SM501 cursor is a two bpp 64x64 bitmap this routine
+ * clears it to transparent then combines the cursor
+ * shape plane with the colour plane to set the
+ * cursor */
+ int x, y;
+ const unsigned char *pcol = cursor->image.data;
+ const unsigned char *pmsk = cursor->mask;
+ void __iomem *dst = par->cursor.k_addr;
+ unsigned char dcol = 0;
+ unsigned char dmsk = 0;
+ unsigned int op;
+
+ dev_dbg(fbi->dev, "%s: setting shape (%d,%d)\n",
+ __func__, cursor->image.width, cursor->image.height);
+
+ for (op = 0; op < (64*64*2)/8; op+=4)
+ writel(0x0, dst + op);
+
+ for (y = 0; y < cursor->image.height; y++) {
+ for (x = 0; x < cursor->image.width; x++) {
+ if ((x % 8) == 0) {
+ dcol = *pcol++;
+ dmsk = *pmsk++;
+ } else {
+ dcol >>= 1;
+ dmsk >>= 1;
+ }
+
+ if (dmsk & 1) {
+ op = (dcol & 1) ? 1 : 3;
+ op <<= ((x % 4) * 2);
+
+ op |= readb(dst + (x / 4));
+ writeb(op, dst + (x / 4));
+ }
+ }
+ dst += (64*2)/8;
+ }
+ }
+
+ sm501fb_sync_regs(fbi); /* ensure cursor data flushed */
+ return 0;
+}
+
+/* sm501fb_crtsrc_show
+ *
+ * device attribute code to show where the crt output is sourced from
+*/
+
+static ssize_t sm501fb_crtsrc_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct sm501fb_info *info = dev_get_drvdata(dev);
+ unsigned long ctrl;
+
+ ctrl = readl(info->regs + SM501_DC_CRT_CONTROL);
+ ctrl &= SM501_DC_CRT_CONTROL_SEL;
+
+ return snprintf(buf, PAGE_SIZE, "%s\n", ctrl ? "crt" : "panel");
+}
+
+/* sm501fb_crtsrc_show
+ *
+ * device attribute code to set where the crt output is sourced from
+*/
+
+static ssize_t sm501fb_crtsrc_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct sm501fb_info *info = dev_get_drvdata(dev);
+ enum sm501_controller head;
+ unsigned long ctrl;
+
+ if (len < 1)
+ return -EINVAL;
+
+ if (strnicmp(buf, "crt", sizeof("crt")) == 0)
+ head = HEAD_CRT;
+ else if (strnicmp(buf, "panel", sizeof("panel")) == 0)
+ head = HEAD_PANEL;
+ else
+ return -EINVAL;
+
+ dev_info(dev, "setting crt source to head %d\n", head);
+
+ ctrl = readl(info->regs + SM501_DC_CRT_CONTROL);
+
+ if (head == HEAD_CRT) {
+ ctrl |= SM501_DC_CRT_CONTROL_SEL;
+ ctrl |= SM501_DC_CRT_CONTROL_ENABLE;
+ ctrl |= SM501_DC_CRT_CONTROL_TE;
+ } else {
+ ctrl &= ~SM501_DC_CRT_CONTROL_SEL;
+ ctrl &= ~SM501_DC_CRT_CONTROL_ENABLE;
+ ctrl &= ~SM501_DC_CRT_CONTROL_TE;
+ }
+
+ writel(ctrl, info->regs + SM501_DC_CRT_CONTROL);
+ sm501fb_sync_regs(info);
+
+ return (head == HEAD_CRT) ? 3 : 5;
+}
+
+/* Prepare the device_attr for registration with sysfs later */
+static DEVICE_ATTR(crt_src, 0666, sm501fb_crtsrc_show, sm501fb_crtsrc_store);
+
+/* sm501fb_show_regs
+ *
+ * show the primary sm501 registers
+*/
+static int sm501fb_show_regs(struct sm501fb_info *info, char *ptr,
+ unsigned int start, unsigned int len)
+{
+ void __iomem *mem = info->regs;
+ char *buf = ptr;
+ unsigned int reg;
+
+ for (reg = start; reg < (len + start); reg += 4)
+ ptr += sprintf(ptr, "%08x = %08x\n", reg, readl(mem + reg));
+
+ return ptr - buf;
+}
+
+/* sm501fb_debug_show_crt
+ *
+ * show the crt control and cursor registers
+*/
+
+static ssize_t sm501fb_debug_show_crt(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct sm501fb_info *info = dev_get_drvdata(dev);
+ char *ptr = buf;
+
+ ptr += sm501fb_show_regs(info, ptr, SM501_DC_CRT_CONTROL, 0x40);
+ ptr += sm501fb_show_regs(info, ptr, SM501_DC_CRT_HWC_BASE, 0x10);
+
+ return ptr - buf;
+}
+
+static DEVICE_ATTR(fbregs_crt, 0444, sm501fb_debug_show_crt, NULL);
+
+/* sm501fb_debug_show_pnl
+ *
+ * show the panel control and cursor registers
+*/
+
+static ssize_t sm501fb_debug_show_pnl(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct sm501fb_info *info = dev_get_drvdata(dev);
+ char *ptr = buf;
+
+ ptr += sm501fb_show_regs(info, ptr, 0x0, 0x40);
+ ptr += sm501fb_show_regs(info, ptr, SM501_DC_PANEL_HWC_BASE, 0x10);
+
+ return ptr - buf;
+}
+
+static DEVICE_ATTR(fbregs_pnl, 0444, sm501fb_debug_show_pnl, NULL);
+
+/* framebuffer ops */
+
+static struct fb_ops sm501fb_ops_crt = {
+ .owner = THIS_MODULE,
+ .fb_check_var = sm501fb_check_var_crt,
+ .fb_set_par = sm501fb_set_par_crt,
+ .fb_blank = sm501fb_blank_crt,
+ .fb_setcolreg = sm501fb_setcolreg,
+ .fb_pan_display = sm501fb_pan_crt,
+ .fb_cursor = sm501fb_cursor,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+};
+
+static struct fb_ops sm501fb_ops_pnl = {
+ .owner = THIS_MODULE,
+ .fb_check_var = sm501fb_check_var_pnl,
+ .fb_set_par = sm501fb_set_par_pnl,
+ .fb_pan_display = sm501fb_pan_pnl,
+ .fb_blank = sm501fb_blank_pnl,
+ .fb_setcolreg = sm501fb_setcolreg,
+ .fb_cursor = sm501fb_cursor,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+};
+
+/* sm501fb_info_alloc
+ *
+ * creates and initialises an sm501fb_info structure
+*/
+
+static struct sm501fb_info *sm501fb_info_alloc(struct fb_info *fbinfo_crt,
+ struct fb_info *fbinfo_pnl)
+{
+ struct sm501fb_info *info;
+ struct sm501fb_par *par;
+
+ info = kzalloc(sizeof(struct sm501fb_info), GFP_KERNEL);
+ if (info) {
+ /* set the references back */
+
+ par = fbinfo_crt->par;
+ par->info = info;
+ par->head = HEAD_CRT;
+ fbinfo_crt->pseudo_palette = &par->pseudo_palette;
+
+ par = fbinfo_pnl->par;
+ par->info = info;
+ par->head = HEAD_PANEL;
+ fbinfo_pnl->pseudo_palette = &par->pseudo_palette;
+
+ /* store the two fbs into our info */
+ info->fb[HEAD_CRT] = fbinfo_crt;
+ info->fb[HEAD_PANEL] = fbinfo_pnl;
+ }
+
+ return info;
+}
+
+/* sm501_init_cursor
+ *
+ * initialise hw cursor parameters
+*/
+
+int sm501_init_cursor(struct fb_info *fbi, unsigned int reg_base)
+{
+ struct sm501fb_par *par = fbi->par;
+ struct sm501fb_info *info = par->info;
+ int ret;
+
+ par->cursor_regs = info->regs + reg_base;
+
+ ret = sm501_alloc_mem(info, &par->cursor, SM501_MEMF_CURSOR, 1024);
+ if (ret < 0)
+ return ret;
+
+ /* initialise the colour registers */
+
+ writel(par->cursor.sm_addr, par->cursor_regs + SM501_OFF_HWC_ADDR);
+
+ writel(0x00, par->cursor_regs + SM501_OFF_HWC_LOC);
+ writel(0x00, par->cursor_regs + SM501_OFF_HWC_COLOR_1_2);
+ writel(0x00, par->cursor_regs + SM501_OFF_HWC_COLOR_3);
+ sm501fb_sync_regs(info);
+
+ return 0;
+}
+
+/* sm501fb_info_start
+ *
+ * fills the par structure claiming resources and remapping etc.
+*/
+
+static int sm501fb_start(struct sm501fb_info *info,
+ struct platform_device *pdev)
+{
+ struct resource *res;
+ struct device *dev;
+ int ret;
+
+ info->dev = dev = &pdev->dev;
+ platform_set_drvdata(pdev, info);
+
+ info->irq = ret = platform_get_irq(pdev, 0);
+ if (ret < 0) {
+ /* we currently do not use the IRQ */
+ dev_warn(dev, "no irq for device\n");
+ }
+
+ /* allocate, reserve and remap resources for registers */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(dev, "no resource definition for registers\n");
+ ret = -ENOENT;
+ goto err_release;
+ }
+
+ info->regs_res = request_mem_region(res->start,
+ res->end - res->start,
+ pdev->name);
+
+ if (info->regs_res == NULL) {
+ dev_err(dev, "cannot claim registers\n");
+ ret = -ENXIO;
+ goto err_release;
+ }
+
+ info->regs = ioremap(res->start, (res->end - res->start)+1);
+ if (info->regs == NULL) {
+ dev_err(dev, "cannot remap registers\n");
+ ret = -ENXIO;
+ goto err_regs_res;
+ }
+
+ /* allocate, reserve resources for framebuffer */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+ if (res == NULL) {
+ dev_err(dev, "no memory resource defined\n");
+ ret = -ENXIO;
+ goto err_regs_map;
+ }
+
+ info->fbmem_res = request_mem_region(res->start,
+ (res->end - res->start)+1,
+ pdev->name);
+ if (info->fbmem_res == NULL) {
+ dev_err(dev, "cannot claim framebuffer\n");
+ ret = -ENXIO;
+ goto err_regs_map;
+ }
+
+ info->fbmem = ioremap(res->start, (res->end - res->start)+1);
+ if (info->fbmem == NULL) {
+ dev_err(dev, "cannot remap framebuffer\n");
+ goto err_mem_res;
+ }
+
+ info->fbmem_len = (res->end - res->start)+1;
+
+ /* enable display controller */
+ sm501_unit_power(dev->parent, SM501_GATE_DISPLAY, 1);
+
+ /* setup cursors */
+
+ sm501_init_cursor(info->fb[HEAD_CRT], SM501_DC_CRT_HWC_ADDR);
+ sm501_init_cursor(info->fb[HEAD_PANEL], SM501_DC_PANEL_HWC_ADDR);
+
+ return 0; /* everything is setup */
+
+ err_mem_res:
+ release_resource(info->fbmem_res);
+ kfree(info->fbmem_res);
+
+ err_regs_map:
+ iounmap(info->regs);
+
+ err_regs_res:
+ release_resource(info->regs_res);
+ kfree(info->regs_res);
+
+ err_release:
+ return ret;
+}
+
+static void sm501fb_stop(struct sm501fb_info *info)
+{
+ /* disable display controller */
+ sm501_unit_power(info->dev->parent, SM501_GATE_DISPLAY, 0);
+
+ iounmap(info->fbmem);
+ release_resource(info->fbmem_res);
+ kfree(info->fbmem_res);
+
+ iounmap(info->regs);
+ release_resource(info->regs_res);
+ kfree(info->regs_res);
+}
+
+static void sm501fb_info_release(struct sm501fb_info *info)
+{
+ kfree(info);
+}
+
+static int sm501fb_init_fb(struct fb_info *fb,
+ enum sm501_controller head,
+ const char *fbname)
+{
+ struct sm501_platdata_fbsub *pd;
+ struct sm501fb_par *par = fb->par;
+ struct sm501fb_info *info = par->info;
+ unsigned long ctrl;
+ unsigned int enable;
+ int ret;
+
+ switch (head) {
+ case HEAD_CRT:
+ pd = info->pdata->fb_crt;
+ ctrl = readl(info->regs + SM501_DC_CRT_CONTROL);
+ enable = (ctrl & SM501_DC_CRT_CONTROL_ENABLE) ? 1 : 0;
+
+ /* ensure we set the correct source register */
+ if (info->pdata->fb_route != SM501_FB_CRT_PANEL) {
+ ctrl |= SM501_DC_CRT_CONTROL_SEL;
+ writel(ctrl, info->regs + SM501_DC_CRT_CONTROL);
+ }
+
+ break;
+
+ case HEAD_PANEL:
+ pd = info->pdata->fb_pnl;
+ ctrl = readl(info->regs + SM501_DC_PANEL_CONTROL);
+ enable = (ctrl & SM501_DC_PANEL_CONTROL_EN) ? 1 : 0;
+ break;
+
+ default:
+ pd = NULL; /* stop compiler warnings */
+ ctrl = 0;
+ enable = 0;
+ BUG();
+ }
+
+ dev_info(info->dev, "fb %s %sabled at start\n",
+ fbname, enable ? "en" : "dis");
+
+ /* check to see if our routing allows this */
+
+ if (head == HEAD_CRT && info->pdata->fb_route == SM501_FB_CRT_PANEL) {
+ ctrl &= ~SM501_DC_CRT_CONTROL_SEL;
+ writel(ctrl, info->regs + SM501_DC_CRT_CONTROL);
+ enable = 0;
+ }
+
+ strlcpy(fb->fix.id, fbname, sizeof(fb->fix.id));
+
+ memcpy(&par->ops,
+ (head == HEAD_CRT) ? &sm501fb_ops_crt : &sm501fb_ops_pnl,
+ sizeof(struct fb_ops));
+
+ /* update ops dependant on what we've been passed */
+
+ if ((pd->flags & SM501FB_FLAG_USE_HWCURSOR) == 0)
+ par->ops.fb_cursor = NULL;
+
+ fb->fbops = &par->ops;
+ fb->flags = FBINFO_FLAG_DEFAULT |
+ FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN;
+
+ /* fixed data */
+
+ fb->fix.type = FB_TYPE_PACKED_PIXELS;
+ fb->fix.type_aux = 0;
+ fb->fix.xpanstep = 1;
+ fb->fix.ypanstep = 1;
+ fb->fix.ywrapstep = 0;
+ fb->fix.accel = FB_ACCEL_NONE;
+
+ /* screenmode */
+
+ fb->var.nonstd = 0;
+ fb->var.activate = FB_ACTIVATE_NOW;
+ fb->var.accel_flags = 0;
+ fb->var.vmode = FB_VMODE_NONINTERLACED;
+ fb->var.bits_per_pixel = 16;
+
+ if (enable && (pd->flags & SM501FB_FLAG_USE_INIT_MODE) && 0) {
+ /* TODO read the mode from the current display */
+
+ } else {
+ if (pd->def_mode) {
+ dev_info(info->dev, "using supplied mode\n");
+ fb_videomode_to_var(&fb->var, pd->def_mode);
+
+ fb->var.bits_per_pixel = pd->def_bpp ? pd->def_bpp : 8;
+ fb->var.xres_virtual = fb->var.xres;
+ fb->var.yres_virtual = fb->var.yres;
+ } else {
+ ret = fb_find_mode(&fb->var, fb,
+ NULL, NULL, 0, NULL, 8);
+
+ if (ret == 0 || ret == 4) {
+ dev_err(info->dev,
+ "failed to get initial mode\n");
+ return -EINVAL;
+ }
+ }
+ }
+
+ /* initialise and set the palette */
+ fb_alloc_cmap(&fb->cmap, NR_PALETTE, 0);
+ fb_set_cmap(&fb->cmap, fb);
+
+ ret = (fb->fbops->fb_check_var)(&fb->var, fb);
+ if (ret)
+ dev_err(info->dev, "check_var() failed on initial setup?\n");
+
+ /* ensure we've activated our new configuration */
+ (fb->fbops->fb_set_par)(fb);
+
+ return 0;
+}
+
+/* default platform data if none is supplied (ie, PCI device) */
+
+static struct sm501_platdata_fbsub sm501fb_pdata_crt = {
+ .flags = (SM501FB_FLAG_USE_INIT_MODE |
+ SM501FB_FLAG_USE_HWCURSOR |
+ SM501FB_FLAG_USE_HWACCEL |
+ SM501FB_FLAG_DISABLE_AT_EXIT),
+
+};
+
+static struct sm501_platdata_fbsub sm501fb_pdata_pnl = {
+ .flags = (SM501FB_FLAG_USE_INIT_MODE |
+ SM501FB_FLAG_USE_HWCURSOR |
+ SM501FB_FLAG_USE_HWACCEL |
+ SM501FB_FLAG_DISABLE_AT_EXIT),
+};
+
+static struct sm501_platdata_fb sm501fb_def_pdata = {
+ .fb_route = SM501_FB_OWN,
+ .fb_crt = &sm501fb_pdata_crt,
+ .fb_pnl = &sm501fb_pdata_pnl,
+};
+
+static char driver_name_crt[] = "sm501fb-crt";
+static char driver_name_pnl[] = "sm501fb-panel";
+
+static int __init sm501fb_probe(struct platform_device *pdev)
+{
+ struct sm501fb_info *info;
+ struct device *dev = &pdev->dev;
+ struct fb_info *fbinfo_crt;
+ struct fb_info *fbinfo_pnl;
+ int ret;
+
+ /* allocate our framebuffers */
+
+ fbinfo_crt = framebuffer_alloc(sizeof(struct sm501fb_par), dev);
+ if (fbinfo_crt == NULL) {
+ dev_err(dev, "cannot allocate crt framebuffer\n");
+ return -ENOMEM;
+ }
+
+ fbinfo_pnl = framebuffer_alloc(sizeof(struct sm501fb_par), dev);
+ if (fbinfo_pnl == NULL) {
+ dev_err(dev, "cannot allocate panel framebuffer\n");
+ ret = -ENOMEM;
+ goto fbinfo_crt_alloc_fail;
+ }
+
+ info = sm501fb_info_alloc(fbinfo_crt, fbinfo_pnl);
+ if (info == NULL) {
+ dev_err(dev, "cannot allocate par\n");
+ ret = -ENOMEM;
+ goto sm501fb_alloc_fail;
+ }
+
+ if (dev->parent->platform_data) {
+ struct sm501_platdata *pd = dev->parent->platform_data;
+ info->pdata = pd->fb;
+ }
+
+ if (info->pdata == NULL) {
+ dev_info(dev, "using default configuration data\n");
+ info->pdata = &sm501fb_def_pdata;
+ }
+
+ /* start the framebuffers */
+
+ ret = sm501fb_start(info, pdev);
+ if (ret) {
+ dev_err(dev, "cannot initialise SM501\n");
+ goto sm501fb_start_fail;
+ }
+
+ /* CRT framebuffer setup */
+
+ ret = sm501fb_init_fb(fbinfo_crt, HEAD_CRT, driver_name_crt);
+ if (ret) {
+ dev_err(dev, "cannot initialise CRT fb\n");
+ goto sm501fb_start_fail;
+ }
+
+ /* Panel framebuffer setup */
+
+ ret = sm501fb_init_fb(fbinfo_pnl, HEAD_PANEL, driver_name_pnl);
+ if (ret) {
+ dev_err(dev, "cannot initialise Panel fb\n");
+ goto sm501fb_start_fail;
+ }
+
+ /* register framebuffers */
+
+ ret = register_framebuffer(fbinfo_crt);
+ if (ret < 0) {
+ dev_err(dev, "failed to register CRT fb (%d)\n", ret);
+ goto register_crt_fail;
+ }
+
+ ret = register_framebuffer(fbinfo_pnl);
+ if (ret < 0) {
+ dev_err(dev, "failed to register panel fb (%d)\n", ret);
+ goto register_pnl_fail;
+ }
+
+ dev_info(dev, "fb%d: %s frame buffer device\n",
+ fbinfo_crt->node, fbinfo_crt->fix.id);
+
+ dev_info(dev, "fb%d: %s frame buffer device\n",
+ fbinfo_pnl->node, fbinfo_pnl->fix.id);
+
+ /* create device files */
+
+ ret = device_create_file(dev, &dev_attr_crt_src);
+ if (ret)
+ goto crtsrc_fail;
+
+ ret = device_create_file(dev, &dev_attr_fbregs_pnl);
+ if (ret)
+ goto fbregs_pnl_fail;
+
+ ret = device_create_file(dev, &dev_attr_fbregs_crt);
+ if (ret)
+ goto fbregs_crt_fail;
+
+ /* we registered, return ok */
+ return 0;
+
+ fbregs_crt_fail:
+ device_remove_file(dev, &dev_attr_fbregs_pnl);
+
+ fbregs_pnl_fail:
+ device_remove_file(dev, &dev_attr_crt_src);
+
+ crtsrc_fail:
+ unregister_framebuffer(fbinfo_pnl);
+
+ register_pnl_fail:
+ unregister_framebuffer(fbinfo_crt);
+
+ register_crt_fail:
+ sm501fb_stop(info);
+
+ sm501fb_start_fail:
+ sm501fb_info_release(info);
+
+ sm501fb_alloc_fail:
+ framebuffer_release(fbinfo_pnl);
+
+ fbinfo_crt_alloc_fail:
+ framebuffer_release(fbinfo_crt);
+
+ return ret;
+}
+
+
+/*
+ * Cleanup
+ */
+static int sm501fb_remove(struct platform_device *pdev)
+{
+ struct sm501fb_info *info = platform_get_drvdata(pdev);
+ struct fb_info *fbinfo_crt = info->fb[0];
+ struct fb_info *fbinfo_pnl = info->fb[1];
+
+ device_remove_file(&pdev->dev, &dev_attr_fbregs_crt);
+ device_remove_file(&pdev->dev, &dev_attr_fbregs_pnl);
+ device_remove_file(&pdev->dev, &dev_attr_crt_src);
+
+ unregister_framebuffer(fbinfo_crt);
+ unregister_framebuffer(fbinfo_pnl);
+
+ sm501fb_stop(info);
+ sm501fb_info_release(info);
+
+ framebuffer_release(fbinfo_pnl);
+ framebuffer_release(fbinfo_crt);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+
+static int sm501fb_suspend_fb(struct sm501fb_info *info,
+ enum sm501_controller head)
+{
+ struct fb_info *fbi = info->fb[head];
+ struct sm501fb_par *par = fbi->par;
+
+ if (par->screen.size == 0)
+ return 0;
+
+ /* backup copies in case chip is powered down over suspend */
+
+ par->store_fb = vmalloc(par->screen.size);
+ if (par->store_fb == NULL) {
+ dev_err(info->dev, "no memory to store screen\n");
+ return -ENOMEM;
+ }
+
+ par->store_cursor = vmalloc(par->cursor.size);
+ if (par->store_cursor == NULL) {
+ dev_err(info->dev, "no memory to store cursor\n");
+ goto err_nocursor;
+ }
+
+ memcpy_fromio(par->store_fb, par->screen.k_addr, par->screen.size);
+ memcpy_fromio(par->store_cursor, par->cursor.k_addr, par->cursor.size);
+
+ /* blank the relevant interface to ensure unit power minimised */
+ (par->ops.fb_blank)(FB_BLANK_POWERDOWN, fbi);
+
+ return 0;
+
+ err_nocursor:
+ vfree(par->store_fb);
+
+ return -ENOMEM;
+
+}
+
+static void sm501fb_resume_fb(struct sm501fb_info *info,
+ enum sm501_controller head)
+{
+ struct fb_info *fbi = info->fb[head];
+ struct sm501fb_par *par = fbi->par;
+
+ if (par->screen.size == 0)
+ return;
+
+ /* re-activate the configuration */
+
+ (par->ops.fb_set_par)(fbi);
+
+ /* restore the data */
+
+ memcpy_toio(par->screen.k_addr, par->store_fb, par->screen.size);
+ memcpy_toio(par->cursor.k_addr, par->store_cursor, par->cursor.size);
+
+ vfree(par->store_fb);
+ vfree(par->store_cursor);
+}
+
+
+/* suspend and resume support */
+
+static int sm501fb_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct sm501fb_info *info = platform_get_drvdata(pdev);
+
+ sm501fb_suspend_fb(info, HEAD_CRT);
+ sm501fb_suspend_fb(info, HEAD_PANEL);
+
+ /* turn off the clocks, in case the device is not powered down */
+ sm501_unit_power(info->dev->parent, SM501_GATE_DISPLAY, 0);
+
+ return 0;
+}
+
+static int sm501fb_resume(struct platform_device *pdev)
+{
+ struct sm501fb_info *info = platform_get_drvdata(pdev);
+
+ sm501_unit_power(info->dev->parent, SM501_GATE_DISPLAY, 1);
+
+ sm501fb_resume_fb(info, HEAD_CRT);
+ sm501fb_resume_fb(info, HEAD_PANEL);
+
+ return 0;
+}
+
+#else
+#define sm501fb_suspend NULL
+#define sm501fb_resume NULL
+#endif
+
+static struct platform_driver sm501fb_driver = {
+ .probe = sm501fb_probe,
+ .remove = sm501fb_remove,
+ .suspend = sm501fb_suspend,
+ .resume = sm501fb_resume,
+ .driver = {
+ .name = "sm501-fb",
+ .owner = THIS_MODULE,
+ },
+};
+
+int __devinit sm501fb_init(void)
+{
+ return platform_driver_register(&sm501fb_driver);
+}
+
+static void __exit sm501fb_cleanup(void)
+{
+ platform_driver_unregister(&sm501fb_driver);
+}
+
+module_init(sm501fb_init);
+module_exit(sm501fb_cleanup);
+
+MODULE_AUTHOR("Ben Dooks, Vincent Sanders");
+MODULE_DESCRIPTION("SM501 Framebuffer driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/video/sun3fb.c b/drivers/video/sun3fb.c
deleted file mode 100644
index f80356dfa8e..00000000000
--- a/drivers/video/sun3fb.c
+++ /dev/null
@@ -1,702 +0,0 @@
-/*
- * linux/drivers/video/sun3fb.c -- Frame buffer driver for Sun3
- *
- * (C) 1998 Thomas Bogendoerfer
- *
- * This driver is bases on sbusfb.c, which is
- *
- * Copyright (C) 1998 Jakub Jelinek
- *
- * This driver is partly based on the Open Firmware console driver
- *
- * Copyright (C) 1997 Geert Uytterhoeven
- *
- * and SPARC console subsystem
- *
- * Copyright (C) 1995 Peter Zaitcev (zaitcev@yahoo.com)
- * Copyright (C) 1995-1997 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1995-1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
- * Copyright (C) 1996 Dave Redman (djhr@tadpole.co.uk)
- * Copyright (C) 1996-1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
- *
- * 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.
- */
-
-#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/vmalloc.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/fb.h>
-#include <linux/selection.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/kd.h>
-#include <linux/vt_kern.h>
-
-#include <asm/uaccess.h>
-#include <asm/pgtable.h> /* io_remap_page_range() */
-
-#ifdef CONFIG_SUN3
-#include <asm/oplib.h>
-#include <asm/machines.h>
-#include <asm/idprom.h>
-
-#define CGFOUR_OBMEM_ADDR 0x1f300000
-#define BWTWO_OBMEM_ADDR 0x1f000000
-#define BWTWO_OBMEM50_ADDR 0x00100000
-
-#endif
-#ifdef CONFIG_SUN3X
-#include <asm/sun3x.h>
-#endif
-#include <video/sbusfb.h>
-
-#define DEFAULT_CURSOR_BLINK_RATE (2*HZ/5)
-
-#define CURSOR_SHAPE 1
-#define CURSOR_BLINK 2
-
-#define mymemset(x,y) memset(x,0,y)
-
- /*
- * Interface used by the world
- */
-
-int sun3fb_init(void);
-void sun3fb_setup(char *options);
-
-static char fontname[40] __initdata = { 0 };
-static int curblink __initdata = 1;
-
-static int sun3fb_get_fix(struct fb_fix_screeninfo *fix, int con,
- struct fb_info *info);
-static int sun3fb_get_var(struct fb_var_screeninfo *var, int con,
- struct fb_info *info);
-static int sun3fb_set_var(struct fb_var_screeninfo *var, int con,
- struct fb_info *info);
-static int sun3fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
- struct fb_info *info);
-static int sun3fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
- struct fb_info *info);
-static int sun3fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
- u_int transp, struct fb_info *info);
-static int sun3fb_blank(int blank, struct fb_info *info);
-static void sun3fb_cursor(struct display *p, int mode, int x, int y);
-static void sun3fb_clear_margin(struct display *p, int s);
-
- /*
- * Interface to the low level console driver
- */
-
-static int sun3fbcon_switch(int con, struct fb_info *info);
-static int sun3fbcon_updatevar(int con, struct fb_info *info);
-
- /*
- * Internal routines
- */
-
-static int sun3fb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
- u_int *transp, struct fb_info *info);
-
-static struct fb_ops sun3fb_ops = {
- .owner = THIS_MODULE,
- .fb_get_fix = sun3fb_get_fix,
- .fb_get_var = sun3fb_get_var,
- .fb_set_var = sun3fb_set_var,
- .fb_get_cmap = sun3fb_get_cmap,
- .fb_set_cmap = sun3fb_set_cmap,
- .fb_setcolreg = sun3fb_setcolreg,
- .fb_blank = sun3fb_blank,
-};
-
-static void sun3fb_clear_margin(struct display *p, int s)
-{
- struct fb_info_sbusfb *fb = sbusfbinfod(p);
-
- return;
-
- if (fb->switch_from_graph)
- (*fb->switch_from_graph)(fb);
- if (fb->fill) {
- unsigned short rects [16];
-
- rects [0] = 0;
- rects [1] = 0;
- rects [2] = fb->var.xres_virtual;
- rects [3] = fb->y_margin;
- rects [4] = 0;
- rects [5] = fb->y_margin;
- rects [6] = fb->x_margin;
- rects [7] = fb->var.yres_virtual;
- rects [8] = fb->var.xres_virtual - fb->x_margin;
- rects [9] = fb->y_margin;
- rects [10] = fb->var.xres_virtual;
- rects [11] = fb->var.yres_virtual;
- rects [12] = fb->x_margin;
- rects [13] = fb->var.yres_virtual - fb->y_margin;
- rects [14] = fb->var.xres_virtual - fb->x_margin;
- rects [15] = fb->var.yres_virtual;
- (*fb->fill)(fb, p, s, 4, rects);
- } else {
- unsigned char *fb_base = fb->info.screen_base, *q;
- int skip_bytes = fb->y_margin * fb->var.xres_virtual;
- int scr_size = fb->var.xres_virtual * fb->var.yres_virtual;
- int h, he, incr, size;
-
- he = fb->var.yres;
- if (fb->var.bits_per_pixel == 1) {
- fb_base -= (skip_bytes + fb->x_margin) / 8;
- skip_bytes /= 8;
- scr_size /= 8;
- mymemset (fb_base, skip_bytes - fb->x_margin / 8);
- mymemset (fb_base + scr_size - skip_bytes + fb->x_margin / 8, skip_bytes - fb->x_margin / 8);
- incr = fb->var.xres_virtual / 8;
- size = fb->x_margin / 8 * 2;
- for (q = fb_base + skip_bytes - fb->x_margin / 8, h = 0;
- h <= he; q += incr, h++)
- mymemset (q, size);
- } else {
- fb_base -= (skip_bytes + fb->x_margin);
- memset (fb_base, attr_bgcol(p,s), skip_bytes - fb->x_margin);
- memset (fb_base + scr_size - skip_bytes + fb->x_margin, attr_bgcol(p,s), skip_bytes - fb->x_margin);
- incr = fb->var.xres_virtual;
- size = fb->x_margin * 2;
- for (q = fb_base + skip_bytes - fb->x_margin, h = 0;
- h <= he; q += incr, h++)
- memset (q, attr_bgcol(p,s), size);
- }
- }
-}
-
-static void sun3fb_disp_setup(struct display *p)
-{
- struct fb_info_sbusfb *fb = sbusfbinfod(p);
-
- if (fb->setup)
- fb->setup(p);
- sun3fb_clear_margin(p, 0);
-}
-
- /*
- * Get the Fixed Part of the Display
- */
-
-static int sun3fb_get_fix(struct fb_fix_screeninfo *fix, int con,
- struct fb_info *info)
-{
- struct fb_info_sbusfb *fb = sbusfbinfo(info);
-
- memcpy(fix, &fb->fix, sizeof(struct fb_fix_screeninfo));
- return 0;
-}
-
- /*
- * Get the User Defined Part of the Display
- */
-
-static int sun3fb_get_var(struct fb_var_screeninfo *var, int con,
- struct fb_info *info)
-{
- struct fb_info_sbusfb *fb = sbusfbinfo(info);
-
- memcpy(var, &fb->var, sizeof(struct fb_var_screeninfo));
- return 0;
-}
-
- /*
- * Set the User Defined Part of the Display
- */
-
-static int sun3fb_set_var(struct fb_var_screeninfo *var, int con,
- struct fb_info *info)
-{
- struct fb_info_sbusfb *fb = sbusfbinfo(info);
-
- if (var->xres > fb->var.xres || var->yres > fb->var.yres ||
- var->xres_virtual > fb->var.xres_virtual ||
- var->yres_virtual > fb->var.yres_virtual ||
- var->bits_per_pixel != fb->var.bits_per_pixel ||
- var->nonstd ||
- (var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)
- return -EINVAL;
- memcpy(var, &fb->var, sizeof(struct fb_var_screeninfo));
- return 0;
-}
-
- /*
- * Hardware cursor
- */
-
-static unsigned char hw_cursor_cmap[2] = { 0, 0xff };
-
-static void
-sun3fb_cursor_timer_handler(unsigned long dev_addr)
-{
- struct fb_info_sbusfb *fb = (struct fb_info_sbusfb *)dev_addr;
-
- if (!fb->setcursor) return;
-
- if (fb->cursor.mode & CURSOR_BLINK) {
- fb->cursor.enable ^= 1;
- fb->setcursor(fb);
- }
-
- fb->cursor.timer.expires = jiffies + fb->cursor.blink_rate;
- add_timer(&fb->cursor.timer);
-}
-
-static void sun3fb_cursor(struct display *p, int mode, int x, int y)
-{
- struct fb_info_sbusfb *fb = sbusfbinfod(p);
-
- switch (mode) {
- case CM_ERASE:
- fb->cursor.mode &= ~CURSOR_BLINK;
- fb->cursor.enable = 0;
- (*fb->setcursor)(fb);
- break;
-
- case CM_MOVE:
- case CM_DRAW:
- if (fb->cursor.mode & CURSOR_SHAPE) {
- fb->cursor.size.fbx = fontwidth(p);
- fb->cursor.size.fby = fontheight(p);
- fb->cursor.chot.fbx = 0;
- fb->cursor.chot.fby = 0;
- fb->cursor.enable = 1;
- memset (fb->cursor.bits, 0, sizeof (fb->cursor.bits));
- fb->cursor.bits[0][fontheight(p) - 2] = (0xffffffff << (32 - fontwidth(p)));
- fb->cursor.bits[1][fontheight(p) - 2] = (0xffffffff << (32 - fontwidth(p)));
- fb->cursor.bits[0][fontheight(p) - 1] = (0xffffffff << (32 - fontwidth(p)));
- fb->cursor.bits[1][fontheight(p) - 1] = (0xffffffff << (32 - fontwidth(p)));
- (*fb->setcursormap) (fb, hw_cursor_cmap, hw_cursor_cmap, hw_cursor_cmap);
- (*fb->setcurshape) (fb);
- }
- fb->cursor.mode = CURSOR_BLINK;
- if (fontwidthlog(p))
- fb->cursor.cpos.fbx = (x << fontwidthlog(p)) + fb->x_margin;
- else
- fb->cursor.cpos.fbx = (x * fontwidth(p)) + fb->x_margin;
- if (fontheightlog(p))
- fb->cursor.cpos.fby = (y << fontheightlog(p)) + fb->y_margin;
- else
- fb->cursor.cpos.fby = (y * fontheight(p)) + fb->y_margin;
- (*fb->setcursor)(fb);
- break;
- }
-}
-
- /*
- * Get the Colormap
- */
-
-static int sun3fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
- struct fb_info *info)
-{
- if (con == info->currcon) /* current console? */
- return fb_get_cmap(cmap, kspc, sun3fb_getcolreg, info);
- else if (fb_display[con].cmap.len) /* non default colormap? */
- fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
- else
- fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel), cmap, kspc ? 0 : 2);
- return 0;
-}
-
- /*
- * Set the Colormap
- */
-
-static int sun3fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
- struct fb_info *info)
-{
- int err;
-
- if (!fb_display[con].cmap.len) { /* no colormap allocated? */
- if ((err = fb_alloc_cmap(&fb_display[con].cmap, 1<<fb_display[con].var.bits_per_pixel, 0)))
- return err;
- }
- if (con == info->currcon) { /* current console? */
- err = fb_set_cmap(cmap, kspc, info);
- if (!err) {
- struct fb_info_sbusfb *fb = sbusfbinfo(info);
-
- if (fb->loadcmap)
- (*fb->loadcmap)(fb, &fb_display[con], cmap->start, cmap->len);
- }
- return err;
- } else
- fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
- return 0;
-}
-
- /*
- * Setup: parse used options
- */
-
-void __init sun3fb_setup(char *options)
-{
- char *p;
-
- for (p = options;;) {
- if (!strncmp(p, "font=", 5)) {
- int i;
-
- for (i = 0; i < sizeof(fontname) - 1; i++)
- if (p[i+5] == ' ' || !p[i+5])
- break;
- memcpy(fontname, p+5, i);
- fontname[i] = 0;
- } else if (!strncmp(p, "noblink", 7))
- curblink = 0;
- while (*p && *p != ' ' && *p != ',') p++;
- if (*p != ',') break;
- p++;
- }
-
- return;
-}
-
-static int sun3fbcon_switch(int con, struct fb_info *info)
-{
- int x_margin, y_margin;
- struct fb_info_sbusfb *fb = sbusfbinfo(info);
- int lastconsole;
-
- /* Do we have to save the colormap? */
- if (fb_display[info->currcon].cmap.len)
- fb_get_cmap(&fb_display[info->currcon].cmap, 1, sun3fb_getcolreg, info);
-
- if (info->display_fg) {
- lastconsole = info->display_fg->vc_num;
- if (lastconsole != con &&
- (fontwidth(&fb_display[lastconsole]) != fontwidth(&fb_display[con]) ||
- fontheight(&fb_display[lastconsole]) != fontheight(&fb_display[con])))
- fb->cursor.mode |= CURSOR_SHAPE;
- }
- x_margin = (fb_display[con].var.xres_virtual - fb_display[con].var.xres) / 2;
- y_margin = (fb_display[con].var.yres_virtual - fb_display[con].var.yres) / 2;
- if (fb->margins)
- fb->margins(fb, &fb_display[con], x_margin, y_margin);
- if (fb->graphmode || fb->x_margin != x_margin || fb->y_margin != y_margin) {
- fb->x_margin = x_margin; fb->y_margin = y_margin;
- sun3fb_clear_margin(&fb_display[con], 0);
- }
- info->currcon = con;
- /* Install new colormap */
- do_install_cmap(con, info);
- return 0;
-}
-
- /*
- * Update the `var' structure (called by fbcon.c)
- */
-
-static int sun3fbcon_updatevar(int con, struct fb_info *info)
-{
- /* Nothing */
- return 0;
-}
-
- /*
- * Blank the display.
- */
-
-static int sun3fb_blank(int blank, struct fb_info *info)
-{
- struct fb_info_sbusfb *fb = sbusfbinfo(info);
-
- if (blank && fb->blank)
- return fb->blank(fb);
- else if (!blank && fb->unblank)
- return fb->unblank(fb);
- return 0;
-}
-
- /*
- * Read a single color register and split it into
- * colors/transparent. Return != 0 for invalid regno.
- */
-
-static int sun3fb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
- u_int *transp, struct fb_info *info)
-{
- struct fb_info_sbusfb *fb = sbusfbinfo(info);
-
- if (!fb->color_map || regno > 255)
- return 1;
- *red = (fb->color_map CM(regno, 0)<<8) | fb->color_map CM(regno, 0);
- *green = (fb->color_map CM(regno, 1)<<8) | fb->color_map CM(regno, 1);
- *blue = (fb->color_map CM(regno, 2)<<8) | fb->color_map CM(regno, 2);
- *transp = 0;
- return 0;
-}
-
-
- /*
- * 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.
- */
-
-static int sun3fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
- u_int transp, struct fb_info *info)
-{
- struct fb_info_sbusfb *fb = sbusfbinfo(info);
-
- if (!fb->color_map || regno > 255)
- return 1;
- red >>= 8;
- green >>= 8;
- blue >>= 8;
- fb->color_map CM(regno, 0) = red;
- fb->color_map CM(regno, 1) = green;
- fb->color_map CM(regno, 2) = blue;
- return 0;
-}
-
-static int sun3fb_set_font(struct display *p, int width, int height)
-{
- int w = p->var.xres_virtual, h = p->var.yres_virtual;
- int depth = p->var.bits_per_pixel;
- struct fb_info_sbusfb *fb = sbusfbinfod(p);
- int x_margin, y_margin;
-
- if (depth > 8) depth = 8;
- x_margin = (w % width) / 2;
- y_margin = (h % height) / 2;
-
- p->var.xres = w - 2*x_margin;
- p->var.yres = h - 2*y_margin;
-
- fb->cursor.mode |= CURSOR_SHAPE;
-
- if (fb->margins)
- fb->margins(fb, p, x_margin, y_margin);
- if (fb->x_margin != x_margin || fb->y_margin != y_margin) {
- fb->x_margin = x_margin; fb->y_margin = y_margin;
- sun3fb_clear_margin(p, 0);
- }
-
- return 1;
-}
-
-void sun3fb_palette(int enter)
-{
- int i;
- struct display *p;
-
- for (i = 0; i < MAX_NR_CONSOLES; i++) {
- p = &fb_display[i];
- if (p->dispsw && p->dispsw->setup == sun3fb_disp_setup &&
- p->fb_info->display_fg &&
- p->fb_info->display_fg->vc_num == i) {
- struct fb_info_sbusfb *fb = sbusfbinfod(p);
-
- if (fb->restore_palette) {
- if (enter)
- fb->restore_palette(fb);
- else if (vc_cons[i].d->vc_mode != KD_GRAPHICS)
- vc_cons[i].d->vc_sw->con_set_palette(vc_cons[i].d, color_table);
- }
- }
- }
-}
-
- /*
- * Initialisation
- */
-static int __init sun3fb_init_fb(int fbtype, unsigned long addr)
-{
- static struct sbus_dev sdb;
- struct fb_fix_screeninfo *fix;
- struct fb_var_screeninfo *var;
- struct display *disp;
- struct fb_info_sbusfb *fb;
- struct fbtype *type;
- int linebytes, w, h, depth;
- char *p = NULL;
-
- fb = kmalloc(sizeof(struct fb_info_sbusfb), GFP_ATOMIC);
- if (!fb)
- return -ENOMEM;
-
- memset(fb, 0, sizeof(struct fb_info_sbusfb));
- fix = &fb->fix;
- var = &fb->var;
- disp = &fb->disp;
- type = &fb->type;
-
- sdb.reg_addrs[0].phys_addr = addr;
- fb->sbdp = &sdb;
-
- type->fb_type = fbtype;
-
- type->fb_height = h = 900;
- type->fb_width = w = 1152;
-sizechange:
- type->fb_depth = depth = (fbtype == FBTYPE_SUN2BW) ? 1 : 8;
- linebytes = w * depth / 8;
- type->fb_size = PAGE_ALIGN((linebytes) * h);
-/*
- fb->x_margin = (w & 7) / 2;
- fb->y_margin = (h & 15) / 2;
-*/
- fb->x_margin = fb->y_margin = 0;
-
- var->xres_virtual = w;
- var->yres_virtual = h;
- var->xres = w - 2*fb->x_margin;
- var->yres = h - 2*fb->y_margin;
-
- var->bits_per_pixel = depth;
- var->height = var->width = -1;
- var->pixclock = 10000;
- var->vmode = FB_VMODE_NONINTERLACED;
- var->red.length = var->green.length = var->blue.length = 8;
-
- fix->line_length = linebytes;
- fix->smem_len = type->fb_size;
- fix->type = FB_TYPE_PACKED_PIXELS;
- fix->visual = FB_VISUAL_PSEUDOCOLOR;
-
- fb->info.fbops = &sun3fb_ops;
- fb->info.disp = disp;
- fb->info.currcon = -1;
- strcpy(fb->info.fontname, fontname);
- fb->info.changevar = NULL;
- fb->info.switch_con = &sun3fbcon_switch;
- fb->info.updatevar = &sun3fbcon_updatevar;
- fb->info.flags = FBINFO_FLAG_DEFAULT;
-
- fb->cursor.hwsize.fbx = 32;
- fb->cursor.hwsize.fby = 32;
-
- if (depth > 1 && !fb->color_map) {
- if((fb->color_map = kmalloc(256 * 3, GFP_ATOMIC))==NULL)
- return -ENOMEM;
- }
-
- switch(fbtype) {
-#ifdef CONFIG_FB_CGSIX
- case FBTYPE_SUNFAST_COLOR:
- p = cgsixfb_init(fb); break;
-#endif
-#ifdef CONFIG_FB_BWTWO
- case FBTYPE_SUN2BW:
- p = bwtwofb_init(fb); break;
-#endif
-#ifdef CONFIG_FB_CGTHREE
- case FBTYPE_SUN4COLOR:
- case FBTYPE_SUN3COLOR:
- type->fb_size = 0x100000;
- p = cgthreefb_init(fb); break;
-#endif
- }
- fix->smem_start = (unsigned long)fb->info.screen_base; // FIXME
-
- if (!p) {
- kfree(fb);
- return -ENODEV;
- }
-
- if (p == SBUSFBINIT_SIZECHANGE)
- goto sizechange;
-
- disp->dispsw = &fb->dispsw;
- if (fb->setcursor) {
- fb->dispsw.cursor = sun3fb_cursor;
- if (curblink) {
- fb->cursor.blink_rate = DEFAULT_CURSOR_BLINK_RATE;
- init_timer(&fb->cursor.timer);
- fb->cursor.timer.expires = jiffies + fb->cursor.blink_rate;
- fb->cursor.timer.data = (unsigned long)fb;
- fb->cursor.timer.function = sun3fb_cursor_timer_handler;
- add_timer(&fb->cursor.timer);
- }
- }
- fb->cursor.mode = CURSOR_SHAPE;
- fb->dispsw.set_font = sun3fb_set_font;
- fb->setup = fb->dispsw.setup;
- fb->dispsw.setup = sun3fb_disp_setup;
- fb->dispsw.clear_margins = NULL;
-
- disp->var = *var;
- disp->visual = fix->visual;
- disp->type = fix->type;
- disp->type_aux = fix->type_aux;
- disp->line_length = fix->line_length;
-
- if (fb->blank)
- disp->can_soft_blank = 1;
-
- sun3fb_set_var(var, -1, &fb->info);
-
- if (register_framebuffer(&fb->info) < 0) {
- kfree(fb);
- return -EINVAL;
- }
- printk("fb%d: %s\n", fb->info.node, p);
-
- return 0;
-}
-
-
-int __init sun3fb_init(void)
-{
- extern int con_is_present(void);
- unsigned long addr;
- char p4id;
-
- if (!con_is_present()) return -ENODEV;
-#ifdef CONFIG_SUN3
- switch(*(romvec->pv_fbtype))
- {
- case FBTYPE_SUN2BW:
- addr = 0xfe20000;
- return sun3fb_init_fb(FBTYPE_SUN2BW, addr);
- case FBTYPE_SUN3COLOR:
- case FBTYPE_SUN4COLOR:
- if(idprom->id_machtype != (SM_SUN3|SM_3_60)) {
- printk("sun3fb: cgthree/four only supported on 3/60\n");
- return -ENODEV;
- }
-
- addr = CGFOUR_OBMEM_ADDR;
- return sun3fb_init_fb(*(romvec->pv_fbtype), addr);
- default:
- printk("sun3fb: unsupported framebuffer\n");
- return -ENODEV;
- }
-#else
- addr = SUN3X_VIDEO_BASE;
- p4id = *(char *)SUN3X_VIDEO_P4ID;
-
- p4id = (p4id == 0x45) ? p4id : (p4id & 0xf0);
- switch (p4id) {
- case 0x00:
- return sun3fb_init_fb(FBTYPE_SUN2BW, addr);
-#if 0 /* not yet */
- case 0x40:
- return sun3fb_init_fb(FBTYPE_SUN4COLOR, addr);
- break;
- case 0x45:
- return sun3fb_init_fb(FBTYPE_SUN8COLOR, addr);
- break;
-#endif
- case 0x60:
- return sun3fb_init_fb(FBTYPE_SUNFAST_COLOR, addr);
- }
-#endif
-
- return -ENODEV;
-}
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/video/svgalib.c b/drivers/video/svgalib.c
new file mode 100644
index 00000000000..68b30d9eac5
--- /dev/null
+++ b/drivers/video/svgalib.c
@@ -0,0 +1,632 @@
+/*
+ * Common utility functions for VGA-based graphics cards.
+ *
+ * Copyright (c) 2006-2007 Ondrej Zajicek <santiago@crfreenet.org>
+ *
+ * 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.
+ *
+ * Some parts are based on David Boucher's viafb (http://davesdomain.org.uk/viafb/)
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/fb.h>
+#include <linux/svga.h>
+#include <linux/slab.h>
+#include <asm/types.h>
+#include <asm/io.h>
+
+
+/* Write a CRT register value spread across multiple registers */
+void svga_wcrt_multi(const struct vga_regset *regset, u32 value) {
+
+ u8 regval, bitval, bitnum;
+
+ while (regset->regnum != VGA_REGSET_END_VAL) {
+ regval = vga_rcrt(NULL, regset->regnum);
+ bitnum = regset->lowbit;
+ while (bitnum <= regset->highbit) {
+ bitval = 1 << bitnum;
+ regval = regval & ~bitval;
+ if (value & 1) regval = regval | bitval;
+ bitnum ++;
+ value = value >> 1;
+ }
+ vga_wcrt(NULL, regset->regnum, regval);
+ regset ++;
+ }
+}
+
+/* Write a sequencer register value spread across multiple registers */
+void svga_wseq_multi(const struct vga_regset *regset, u32 value) {
+
+ u8 regval, bitval, bitnum;
+
+ while (regset->regnum != VGA_REGSET_END_VAL) {
+ regval = vga_rseq(NULL, regset->regnum);
+ bitnum = regset->lowbit;
+ while (bitnum <= regset->highbit) {
+ bitval = 1 << bitnum;
+ regval = regval & ~bitval;
+ if (value & 1) regval = regval | bitval;
+ bitnum ++;
+ value = value >> 1;
+ }
+ vga_wseq(NULL, regset->regnum, regval);
+ regset ++;
+ }
+}
+
+static unsigned int svga_regset_size(const struct vga_regset *regset)
+{
+ u8 count = 0;
+
+ while (regset->regnum != VGA_REGSET_END_VAL) {
+ count += regset->highbit - regset->lowbit + 1;
+ regset ++;
+ }
+ return 1 << count;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+
+/* Set graphics controller registers to sane values */
+void svga_set_default_gfx_regs(void)
+{
+ /* All standard GFX registers (GR00 - GR08) */
+ vga_wgfx(NULL, VGA_GFX_SR_VALUE, 0x00);
+ vga_wgfx(NULL, VGA_GFX_SR_ENABLE, 0x00);
+ vga_wgfx(NULL, VGA_GFX_COMPARE_VALUE, 0x00);
+ vga_wgfx(NULL, VGA_GFX_DATA_ROTATE, 0x00);
+ vga_wgfx(NULL, VGA_GFX_PLANE_READ, 0x00);
+ vga_wgfx(NULL, VGA_GFX_MODE, 0x00);
+/* vga_wgfx(NULL, VGA_GFX_MODE, 0x20); */
+/* vga_wgfx(NULL, VGA_GFX_MODE, 0x40); */
+ vga_wgfx(NULL, VGA_GFX_MISC, 0x05);
+/* vga_wgfx(NULL, VGA_GFX_MISC, 0x01); */
+ vga_wgfx(NULL, VGA_GFX_COMPARE_MASK, 0x0F);
+ vga_wgfx(NULL, VGA_GFX_BIT_MASK, 0xFF);
+}
+
+/* Set attribute controller registers to sane values */
+void svga_set_default_atc_regs(void)
+{
+ u8 count;
+
+ vga_r(NULL, 0x3DA);
+ vga_w(NULL, VGA_ATT_W, 0x00);
+
+ /* All standard ATC registers (AR00 - AR14) */
+ for (count = 0; count <= 0xF; count ++)
+ svga_wattr(count, count);
+
+ svga_wattr(VGA_ATC_MODE, 0x01);
+/* svga_wattr(VGA_ATC_MODE, 0x41); */
+ svga_wattr(VGA_ATC_OVERSCAN, 0x00);
+ svga_wattr(VGA_ATC_PLANE_ENABLE, 0x0F);
+ svga_wattr(VGA_ATC_PEL, 0x00);
+ svga_wattr(VGA_ATC_COLOR_PAGE, 0x00);
+
+ vga_r(NULL, 0x3DA);
+ vga_w(NULL, VGA_ATT_W, 0x20);
+}
+
+/* Set sequencer registers to sane values */
+void svga_set_default_seq_regs(void)
+{
+ /* Standard sequencer registers (SR01 - SR04), SR00 is not set */
+ vga_wseq(NULL, VGA_SEQ_CLOCK_MODE, VGA_SR01_CHAR_CLK_8DOTS);
+ vga_wseq(NULL, VGA_SEQ_PLANE_WRITE, VGA_SR02_ALL_PLANES);
+ vga_wseq(NULL, VGA_SEQ_CHARACTER_MAP, 0x00);
+/* vga_wseq(NULL, VGA_SEQ_MEMORY_MODE, VGA_SR04_EXT_MEM | VGA_SR04_SEQ_MODE | VGA_SR04_CHN_4M); */
+ vga_wseq(NULL, VGA_SEQ_MEMORY_MODE, VGA_SR04_EXT_MEM | VGA_SR04_SEQ_MODE);
+}
+
+/* Set CRTC registers to sane values */
+void svga_set_default_crt_regs(void)
+{
+ /* Standard CRT registers CR03 CR08 CR09 CR14 CR17 */
+ svga_wcrt_mask(0x03, 0x80, 0x80); /* Enable vertical retrace EVRA */
+ vga_wcrt(NULL, VGA_CRTC_PRESET_ROW, 0);
+ svga_wcrt_mask(VGA_CRTC_MAX_SCAN, 0, 0x1F);
+ vga_wcrt(NULL, VGA_CRTC_UNDERLINE, 0);
+ vga_wcrt(NULL, VGA_CRTC_MODE, 0xE3);
+}
+
+void svga_set_textmode_vga_regs(void)
+{
+ /* svga_wseq_mask(0x1, 0x00, 0x01); */ /* Switch 8/9 pixel per char */
+ vga_wseq(NULL, VGA_SEQ_MEMORY_MODE, VGA_SR04_EXT_MEM);
+ vga_wseq(NULL, VGA_SEQ_PLANE_WRITE, 0x03);
+
+ vga_wcrt(NULL, VGA_CRTC_MAX_SCAN, 0x0f); /* 0x4f */
+ vga_wcrt(NULL, VGA_CRTC_UNDERLINE, 0x1f);
+ svga_wcrt_mask(VGA_CRTC_MODE, 0x23, 0x7f);
+
+ vga_wcrt(NULL, VGA_CRTC_CURSOR_START, 0x0d);
+ vga_wcrt(NULL, VGA_CRTC_CURSOR_END, 0x0e);
+ vga_wcrt(NULL, VGA_CRTC_CURSOR_HI, 0x00);
+ vga_wcrt(NULL, VGA_CRTC_CURSOR_LO, 0x00);
+
+ vga_wgfx(NULL, VGA_GFX_MODE, 0x10); /* Odd/even memory mode */
+ vga_wgfx(NULL, VGA_GFX_MISC, 0x0E); /* Misc graphics register - text mode enable */
+ vga_wgfx(NULL, VGA_GFX_COMPARE_MASK, 0x00);
+
+ vga_r(NULL, 0x3DA);
+ vga_w(NULL, VGA_ATT_W, 0x00);
+
+ svga_wattr(0x10, 0x0C); /* Attribute Mode Control Register - text mode, blinking and line graphics */
+ svga_wattr(0x13, 0x08); /* Horizontal Pixel Panning Register */
+
+ vga_r(NULL, 0x3DA);
+ vga_w(NULL, VGA_ATT_W, 0x20);
+}
+
+#if 0
+void svga_dump_var(struct fb_var_screeninfo *var, int node)
+{
+ pr_debug("fb%d: var.vmode : 0x%X\n", node, var->vmode);
+ pr_debug("fb%d: var.xres : %d\n", node, var->xres);
+ pr_debug("fb%d: var.yres : %d\n", node, var->yres);
+ pr_debug("fb%d: var.bits_per_pixel: %d\n", node, var->bits_per_pixel);
+ pr_debug("fb%d: var.xres_virtual : %d\n", node, var->xres_virtual);
+ pr_debug("fb%d: var.yres_virtual : %d\n", node, var->yres_virtual);
+ pr_debug("fb%d: var.left_margin : %d\n", node, var->left_margin);
+ pr_debug("fb%d: var.right_margin : %d\n", node, var->right_margin);
+ pr_debug("fb%d: var.upper_margin : %d\n", node, var->upper_margin);
+ pr_debug("fb%d: var.lower_margin : %d\n", node, var->lower_margin);
+ pr_debug("fb%d: var.hsync_len : %d\n", node, var->hsync_len);
+ pr_debug("fb%d: var.vsync_len : %d\n", node, var->vsync_len);
+ pr_debug("fb%d: var.sync : 0x%X\n", node, var->sync);
+ pr_debug("fb%d: var.pixclock : %d\n\n", node, var->pixclock);
+}
+#endif /* 0 */
+
+
+/* ------------------------------------------------------------------------- */
+
+
+void svga_settile(struct fb_info *info, struct fb_tilemap *map)
+{
+ const u8 *font = map->data;
+ u8* fb = (u8 *) info->screen_base;
+ int i, c;
+
+ if ((map->width != 8) || (map->height != 16) ||
+ (map->depth != 1) || (map->length != 256)) {
+ printk(KERN_ERR "fb%d: unsupported font parameters: width %d, height %d, depth %d, length %d\n",
+ info->node, map->width, map->height, map->depth, map->length);
+ return;
+ }
+
+ fb += 2;
+ for (c = 0; c < map->length; c++) {
+ for (i = 0; i < map->height; i++) {
+ fb[i * 4] = font[i];
+ }
+ fb += 128;
+ font += map->height;
+ }
+}
+
+/* Copy area in text (tileblit) mode */
+void svga_tilecopy(struct fb_info *info, struct fb_tilearea *area)
+{
+ int dx, dy;
+ /* colstride is halved in this function because u16 are used */
+ int colstride = 1 << (info->fix.type_aux & FB_AUX_TEXT_SVGA_MASK);
+ int rowstride = colstride * (info->var.xres_virtual / 8);
+ u16 *fb = (u16 *) info->screen_base;
+ u16 *src, *dst;
+
+ if ((area->sy > area->dy) ||
+ ((area->sy == area->dy) && (area->sx > area->dx))) {
+ src = fb + area->sx * colstride + area->sy * rowstride;
+ dst = fb + area->dx * colstride + area->dy * rowstride;
+ } else {
+ src = fb + (area->sx + area->width - 1) * colstride
+ + (area->sy + area->height - 1) * rowstride;
+ dst = fb + (area->dx + area->width - 1) * colstride
+ + (area->dy + area->height - 1) * rowstride;
+
+ colstride = -colstride;
+ rowstride = -rowstride;
+ }
+
+ for (dy = 0; dy < area->height; dy++) {
+ u16* src2 = src;
+ u16* dst2 = dst;
+ for (dx = 0; dx < area->width; dx++) {
+ *dst2 = *src2;
+ src2 += colstride;
+ dst2 += colstride;
+ }
+ src += rowstride;
+ dst += rowstride;
+ }
+}
+
+/* Fill area in text (tileblit) mode */
+void svga_tilefill(struct fb_info *info, struct fb_tilerect *rect)
+{
+ int dx, dy;
+ int colstride = 2 << (info->fix.type_aux & FB_AUX_TEXT_SVGA_MASK);
+ int rowstride = colstride * (info->var.xres_virtual / 8);
+ int attr = (0x0F & rect->bg) << 4 | (0x0F & rect->fg);
+ u8 *fb = (u8 *) info->screen_base;
+ fb += rect->sx * colstride + rect->sy * rowstride;
+
+ for (dy = 0; dy < rect->height; dy++) {
+ u8* fb2 = fb;
+ for (dx = 0; dx < rect->width; dx++) {
+ fb2[0] = rect->index;
+ fb2[1] = attr;
+ fb2 += colstride;
+ }
+ fb += rowstride;
+ }
+}
+
+/* Write text in text (tileblit) mode */
+void svga_tileblit(struct fb_info *info, struct fb_tileblit *blit)
+{
+ int dx, dy, i;
+ int colstride = 2 << (info->fix.type_aux & FB_AUX_TEXT_SVGA_MASK);
+ int rowstride = colstride * (info->var.xres_virtual / 8);
+ int attr = (0x0F & blit->bg) << 4 | (0x0F & blit->fg);
+ u8* fb = (u8 *) info->screen_base;
+ fb += blit->sx * colstride + blit->sy * rowstride;
+
+ i=0;
+ for (dy=0; dy < blit->height; dy ++) {
+ u8* fb2 = fb;
+ for (dx = 0; dx < blit->width; dx ++) {
+ fb2[0] = blit->indices[i];
+ fb2[1] = attr;
+ fb2 += colstride;
+ i ++;
+ if (i == blit->length) return;
+ }
+ fb += rowstride;
+ }
+
+}
+
+/* Set cursor in text (tileblit) mode */
+void svga_tilecursor(struct fb_info *info, struct fb_tilecursor *cursor)
+{
+ u8 cs = 0x0d;
+ u8 ce = 0x0e;
+ u16 pos = cursor->sx + (info->var.xoffset / 8)
+ + (cursor->sy + (info->var.yoffset / 16))
+ * (info->var.xres_virtual / 8);
+
+ if (! cursor -> mode)
+ return;
+
+ svga_wcrt_mask(0x0A, 0x20, 0x20); /* disable cursor */
+
+ if (cursor -> shape == FB_TILE_CURSOR_NONE)
+ return;
+
+ switch (cursor -> shape) {
+ case FB_TILE_CURSOR_UNDERLINE:
+ cs = 0x0d;
+ break;
+ case FB_TILE_CURSOR_LOWER_THIRD:
+ cs = 0x09;
+ break;
+ case FB_TILE_CURSOR_LOWER_HALF:
+ cs = 0x07;
+ break;
+ case FB_TILE_CURSOR_TWO_THIRDS:
+ cs = 0x05;
+ break;
+ case FB_TILE_CURSOR_BLOCK:
+ cs = 0x01;
+ break;
+ }
+
+ /* set cursor position */
+ vga_wcrt(NULL, 0x0E, pos >> 8);
+ vga_wcrt(NULL, 0x0F, pos & 0xFF);
+
+ vga_wcrt(NULL, 0x0B, ce); /* set cursor end */
+ vga_wcrt(NULL, 0x0A, cs); /* set cursor start and enable it */
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+
+/*
+ * Compute PLL settings (M, N, R)
+ * F_VCO = (F_BASE * M) / N
+ * F_OUT = F_VCO / (2^R)
+ */
+
+static inline u32 abs_diff(u32 a, u32 b)
+{
+ return (a > b) ? (a - b) : (b - a);
+}
+
+int svga_compute_pll(const struct svga_pll *pll, u32 f_wanted, u16 *m, u16 *n, u16 *r, int node)
+{
+ u16 am, an, ar;
+ u32 f_vco, f_current, delta_current, delta_best;
+
+ pr_debug("fb%d: ideal frequency: %d kHz\n", node, (unsigned int) f_wanted);
+
+ ar = pll->r_max;
+ f_vco = f_wanted << ar;
+
+ /* overflow check */
+ if ((f_vco >> ar) != f_wanted)
+ return -EINVAL;
+
+ /* It is usually better to have greater VCO clock
+ because of better frequency stability.
+ So first try r_max, then r smaller. */
+ while ((ar > pll->r_min) && (f_vco > pll->f_vco_max)) {
+ ar--;
+ f_vco = f_vco >> 1;
+ }
+
+ /* VCO bounds check */
+ if ((f_vco < pll->f_vco_min) || (f_vco > pll->f_vco_max))
+ return -EINVAL;
+
+ delta_best = 0xFFFFFFFF;
+ *m = 0;
+ *n = 0;
+ *r = ar;
+
+ am = pll->m_min;
+ an = pll->n_min;
+
+ while ((am <= pll->m_max) && (an <= pll->n_max)) {
+ f_current = (pll->f_base * am) / an;
+ delta_current = abs_diff (f_current, f_vco);
+
+ if (delta_current < delta_best) {
+ delta_best = delta_current;
+ *m = am;
+ *n = an;
+ }
+
+ if (f_current <= f_vco) {
+ am ++;
+ } else {
+ an ++;
+ }
+ }
+
+ f_current = (pll->f_base * *m) / *n;
+ pr_debug("fb%d: found frequency: %d kHz (VCO %d kHz)\n", node, (int) (f_current >> ar), (int) f_current);
+ pr_debug("fb%d: m = %d n = %d r = %d\n", node, (unsigned int) *m, (unsigned int) *n, (unsigned int) *r);
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+
+/* Check CRT timing values */
+int svga_check_timings(const struct svga_timing_regs *tm, struct fb_var_screeninfo *var, int node)
+{
+ u32 value;
+
+ var->xres = (var->xres+7)&~7;
+ var->left_margin = (var->left_margin+7)&~7;
+ var->right_margin = (var->right_margin+7)&~7;
+ var->hsync_len = (var->hsync_len+7)&~7;
+
+ /* Check horizontal total */
+ value = var->xres + var->left_margin + var->right_margin + var->hsync_len;
+ if (((value / 8) - 5) >= svga_regset_size (tm->h_total_regs))
+ return -EINVAL;
+
+ /* Check horizontal display and blank start */
+ value = var->xres;
+ if (((value / 8) - 1) >= svga_regset_size (tm->h_display_regs))
+ return -EINVAL;
+ if (((value / 8) - 1) >= svga_regset_size (tm->h_blank_start_regs))
+ return -EINVAL;
+
+ /* Check horizontal sync start */
+ value = var->xres + var->right_margin;
+ if (((value / 8) - 1) >= svga_regset_size (tm->h_sync_start_regs))
+ return -EINVAL;
+
+ /* Check horizontal blank end (or length) */
+ value = var->left_margin + var->right_margin + var->hsync_len;
+ if ((value == 0) || ((value / 8) >= svga_regset_size (tm->h_blank_end_regs)))
+ return -EINVAL;
+
+ /* Check horizontal sync end (or length) */
+ value = var->hsync_len;
+ if ((value == 0) || ((value / 8) >= svga_regset_size (tm->h_sync_end_regs)))
+ return -EINVAL;
+
+ /* Check vertical total */
+ value = var->yres + var->upper_margin + var->lower_margin + var->vsync_len;
+ if ((value - 1) >= svga_regset_size(tm->v_total_regs))
+ return -EINVAL;
+
+ /* Check vertical display and blank start */
+ value = var->yres;
+ if ((value - 1) >= svga_regset_size(tm->v_display_regs))
+ return -EINVAL;
+ if ((value - 1) >= svga_regset_size(tm->v_blank_start_regs))
+ return -EINVAL;
+
+ /* Check vertical sync start */
+ value = var->yres + var->lower_margin;
+ if ((value - 1) >= svga_regset_size(tm->v_sync_start_regs))
+ return -EINVAL;
+
+ /* Check vertical blank end (or length) */
+ value = var->upper_margin + var->lower_margin + var->vsync_len;
+ if ((value == 0) || (value >= svga_regset_size (tm->v_blank_end_regs)))
+ return -EINVAL;
+
+ /* Check vertical sync end (or length) */
+ value = var->vsync_len;
+ if ((value == 0) || (value >= svga_regset_size (tm->v_sync_end_regs)))
+ return -EINVAL;
+
+ return 0;
+}
+
+/* Set CRT timing registers */
+void svga_set_timings(const struct svga_timing_regs *tm, struct fb_var_screeninfo *var,
+ u32 hmul, u32 hdiv, u32 vmul, u32 vdiv, u32 hborder, int node)
+{
+ u8 regval;
+ u32 value;
+
+ value = var->xres + var->left_margin + var->right_margin + var->hsync_len;
+ value = (value * hmul) / hdiv;
+ pr_debug("fb%d: horizontal total : %d\n", node, value);
+ svga_wcrt_multi(tm->h_total_regs, (value / 8) - 5);
+
+ value = var->xres;
+ value = (value * hmul) / hdiv;
+ pr_debug("fb%d: horizontal display : %d\n", node, value);
+ svga_wcrt_multi(tm->h_display_regs, (value / 8) - 1);
+
+ value = var->xres;
+ value = (value * hmul) / hdiv;
+ pr_debug("fb%d: horizontal blank start: %d\n", node, value);
+ svga_wcrt_multi(tm->h_blank_start_regs, (value / 8) - 1 + hborder);
+
+ value = var->xres + var->left_margin + var->right_margin + var->hsync_len;
+ value = (value * hmul) / hdiv;
+ pr_debug("fb%d: horizontal blank end : %d\n", node, value);
+ svga_wcrt_multi(tm->h_blank_end_regs, (value / 8) - 1 - hborder);
+
+ value = var->xres + var->right_margin;
+ value = (value * hmul) / hdiv;
+ pr_debug("fb%d: horizontal sync start : %d\n", node, value);
+ svga_wcrt_multi(tm->h_sync_start_regs, (value / 8));
+
+ value = var->xres + var->right_margin + var->hsync_len;
+ value = (value * hmul) / hdiv;
+ pr_debug("fb%d: horizontal sync end : %d\n", node, value);
+ svga_wcrt_multi(tm->h_sync_end_regs, (value / 8));
+
+ value = var->yres + var->upper_margin + var->lower_margin + var->vsync_len;
+ value = (value * vmul) / vdiv;
+ pr_debug("fb%d: vertical total : %d\n", node, value);
+ svga_wcrt_multi(tm->v_total_regs, value - 2);
+
+ value = var->yres;
+ value = (value * vmul) / vdiv;
+ pr_debug("fb%d: vertical display : %d\n", node, value);
+ svga_wcrt_multi(tm->v_display_regs, value - 1);
+
+ value = var->yres;
+ value = (value * vmul) / vdiv;
+ pr_debug("fb%d: vertical blank start : %d\n", node, value);
+ svga_wcrt_multi(tm->v_blank_start_regs, value);
+
+ value = var->yres + var->upper_margin + var->lower_margin + var->vsync_len;
+ value = (value * vmul) / vdiv;
+ pr_debug("fb%d: vertical blank end : %d\n", node, value);
+ svga_wcrt_multi(tm->v_blank_end_regs, value - 2);
+
+ value = var->yres + var->lower_margin;
+ value = (value * vmul) / vdiv;
+ pr_debug("fb%d: vertical sync start : %d\n", node, value);
+ svga_wcrt_multi(tm->v_sync_start_regs, value);
+
+ value = var->yres + var->lower_margin + var->vsync_len;
+ value = (value * vmul) / vdiv;
+ pr_debug("fb%d: vertical sync end : %d\n", node, value);
+ svga_wcrt_multi(tm->v_sync_end_regs, value);
+
+ /* Set horizontal and vertical sync pulse polarity in misc register */
+
+ regval = vga_r(NULL, VGA_MIS_R);
+ if (var->sync & FB_SYNC_HOR_HIGH_ACT) {
+ pr_debug("fb%d: positive horizontal sync\n", node);
+ regval = regval & ~0x80;
+ } else {
+ pr_debug("fb%d: negative horizontal sync\n", node);
+ regval = regval | 0x80;
+ }
+ if (var->sync & FB_SYNC_VERT_HIGH_ACT) {
+ pr_debug("fb%d: positive vertical sync\n", node);
+ regval = regval & ~0x40;
+ } else {
+ pr_debug("fb%d: negative vertical sync\n\n", node);
+ regval = regval | 0x40;
+ }
+ vga_w(NULL, VGA_MIS_W, regval);
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+
+int svga_match_format(const struct svga_fb_format *frm, struct fb_var_screeninfo *var, struct fb_fix_screeninfo *fix)
+{
+ int i = 0;
+
+ while (frm->bits_per_pixel != SVGA_FORMAT_END_VAL)
+ {
+ if ((var->bits_per_pixel == frm->bits_per_pixel) &&
+ (var->red.length <= frm->red.length) &&
+ (var->green.length <= frm->green.length) &&
+ (var->blue.length <= frm->blue.length) &&
+ (var->transp.length <= frm->transp.length) &&
+ (var->nonstd == frm->nonstd)) {
+ var->bits_per_pixel = frm->bits_per_pixel;
+ var->red = frm->red;
+ var->green = frm->green;
+ var->blue = frm->blue;
+ var->transp = frm->transp;
+ var->nonstd = frm->nonstd;
+ if (fix != NULL) {
+ fix->type = frm->type;
+ fix->type_aux = frm->type_aux;
+ fix->visual = frm->visual;
+ fix->xpanstep = frm->xpanstep;
+ }
+ return i;
+ }
+ i++;
+ frm++;
+ }
+ return -EINVAL;
+}
+
+
+EXPORT_SYMBOL(svga_wcrt_multi);
+EXPORT_SYMBOL(svga_wseq_multi);
+
+EXPORT_SYMBOL(svga_set_default_gfx_regs);
+EXPORT_SYMBOL(svga_set_default_atc_regs);
+EXPORT_SYMBOL(svga_set_default_seq_regs);
+EXPORT_SYMBOL(svga_set_default_crt_regs);
+EXPORT_SYMBOL(svga_set_textmode_vga_regs);
+
+EXPORT_SYMBOL(svga_settile);
+EXPORT_SYMBOL(svga_tilecopy);
+EXPORT_SYMBOL(svga_tilefill);
+EXPORT_SYMBOL(svga_tileblit);
+EXPORT_SYMBOL(svga_tilecursor);
+
+EXPORT_SYMBOL(svga_compute_pll);
+EXPORT_SYMBOL(svga_check_timings);
+EXPORT_SYMBOL(svga_set_timings);
+EXPORT_SYMBOL(svga_match_format);
+
+MODULE_AUTHOR("Ondrej Zajicek <santiago@crfreenet.org>");
+MODULE_DESCRIPTION("Common utility functions for VGA-based graphics cards");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/tgafb.c b/drivers/video/tgafb.c
index 4b88fab83b7..7478d0e3e21 100644
--- a/drivers/video/tgafb.c
+++ b/drivers/video/tgafb.c
@@ -13,7 +13,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
@@ -43,8 +42,9 @@ static void tgafb_imageblit(struct fb_info *, const struct fb_image *);
static void tgafb_fillrect(struct fb_info *, const struct fb_fillrect *);
static void tgafb_copyarea(struct fb_info *, const struct fb_copyarea *);
-static int tgafb_pci_register(struct pci_dev *, const struct pci_device_id *);
-static void tgafb_pci_unregister(struct pci_dev *);
+static int __devinit tgafb_pci_register(struct pci_dev *,
+ const struct pci_device_id *);
+static void __devexit tgafb_pci_unregister(struct pci_dev *);
static const char *mode_option = "640x480@60";
@@ -70,9 +70,10 @@ static struct fb_ops tgafb_ops = {
*/
static struct pci_device_id const tgafb_pci_table[] = {
- { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TGA, PCI_ANY_ID, PCI_ANY_ID,
- 0, 0, 0 }
+ { PCI_DEVICE(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TGA) },
+ { }
};
+MODULE_DEVICE_TABLE(pci, tgafb_pci_table);
static struct pci_driver tgafb_driver = {
.name = "tgafb",
@@ -99,6 +100,12 @@ tgafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
if (var->bits_per_pixel != 32)
return -EINVAL;
}
+ var->red.length = var->green.length = var->blue.length = 8;
+ if (var->bits_per_pixel == 32) {
+ var->red.offset = 16;
+ var->green.offset = 8;
+ var->blue.offset = 0;
+ }
if (var->xres_virtual != var->xres || var->yres_virtual != var->yres)
return -EINVAL;
@@ -137,10 +144,10 @@ tgafb_set_par(struct fb_info *info)
0x00000303
};
static unsigned int const mode_presets[4] = {
- 0x00002000,
- 0x00002300,
+ 0x00000000,
+ 0x00000300,
0xffffffff,
- 0x00002300
+ 0x00000300
};
static unsigned int const base_addr_presets[4] = {
0x00000000,
@@ -152,7 +159,7 @@ tgafb_set_par(struct fb_info *info)
struct tga_par *par = (struct tga_par *) info->par;
u32 htimings, vtimings, pll_freq;
u8 tga_type;
- int i, j;
+ int i;
/* Encode video timings. */
htimings = (((info->var.xres/4) & TGA_HORIZ_ACT_LSB)
@@ -190,7 +197,9 @@ tgafb_set_par(struct fb_info *info)
while (TGA_READ_REG(par, TGA_CMD_STAT_REG) & 1) /* wait for not busy */
continue;
mb();
- TGA_WRITE_REG(par, deep_presets[tga_type], TGA_DEEP_REG);
+ TGA_WRITE_REG(par, deep_presets[tga_type] |
+ (par->sync_on_green ? 0x0 : 0x00010000),
+ TGA_DEEP_REG);
while (TGA_READ_REG(par, TGA_CMD_STAT_REG) & 1) /* wait for not busy */
continue;
mb();
@@ -227,8 +236,10 @@ tgafb_set_par(struct fb_info *info)
BT485_WRITE(par, 0x00, BT485_ADDR_PAL_WRITE);
TGA_WRITE_REG(par, BT485_DATA_PAL, TGA_RAMDAC_SETUP_REG);
+#ifdef CONFIG_HW_CONSOLE
for (i = 0; i < 16; i++) {
- j = color_table[i];
+ int j = color_table[i];
+
TGA_WRITE_REG(par, default_red[j]|(BT485_DATA_PAL<<8),
TGA_RAMDAC_REG);
TGA_WRITE_REG(par, default_grn[j]|(BT485_DATA_PAL<<8),
@@ -236,24 +247,27 @@ tgafb_set_par(struct fb_info *info)
TGA_WRITE_REG(par, default_blu[j]|(BT485_DATA_PAL<<8),
TGA_RAMDAC_REG);
}
- for (i = 0; i < 240*3; i += 4) {
- TGA_WRITE_REG(par, 0x55|(BT485_DATA_PAL<<8),
+ for (i = 0; i < 240 * 3; i += 4) {
+#else
+ for (i = 0; i < 256 * 3; i += 4) {
+#endif
+ TGA_WRITE_REG(par, 0x55 | (BT485_DATA_PAL << 8),
TGA_RAMDAC_REG);
- TGA_WRITE_REG(par, 0x00|(BT485_DATA_PAL<<8),
+ TGA_WRITE_REG(par, 0x00 | (BT485_DATA_PAL << 8),
TGA_RAMDAC_REG);
- TGA_WRITE_REG(par, 0x00|(BT485_DATA_PAL<<8),
+ TGA_WRITE_REG(par, 0x00 | (BT485_DATA_PAL << 8),
TGA_RAMDAC_REG);
- TGA_WRITE_REG(par, 0x00|(BT485_DATA_PAL<<8),
+ TGA_WRITE_REG(par, 0x00 | (BT485_DATA_PAL << 8),
TGA_RAMDAC_REG);
}
} else { /* 24-plane or 24plusZ */
- /* Init BT463 registers. */
+ /* Init BT463 RAMDAC registers. */
BT463_WRITE(par, BT463_REG_ACC, BT463_CMD_REG_0, 0x40);
BT463_WRITE(par, BT463_REG_ACC, BT463_CMD_REG_1, 0x08);
BT463_WRITE(par, BT463_REG_ACC, BT463_CMD_REG_2,
- (par->sync_on_green ? 0x80 : 0x40));
+ (par->sync_on_green ? 0xc0 : 0x40));
BT463_WRITE(par, BT463_REG_ACC, BT463_READ_MASK_0, 0xff);
BT463_WRITE(par, BT463_REG_ACC, BT463_READ_MASK_1, 0xff);
@@ -267,26 +281,24 @@ tgafb_set_par(struct fb_info *info)
/* Fill the palette. */
BT463_LOAD_ADDR(par, 0x0000);
- TGA_WRITE_REG(par, BT463_PALETTE<<2, TGA_RAMDAC_REG);
+ TGA_WRITE_REG(par, BT463_PALETTE << 2, TGA_RAMDAC_SETUP_REG);
+#ifdef CONFIG_HW_CONSOLE
for (i = 0; i < 16; i++) {
- j = color_table[i];
- TGA_WRITE_REG(par, default_red[j]|(BT463_PALETTE<<10),
- TGA_RAMDAC_REG);
- TGA_WRITE_REG(par, default_grn[j]|(BT463_PALETTE<<10),
- TGA_RAMDAC_REG);
- TGA_WRITE_REG(par, default_blu[j]|(BT463_PALETTE<<10),
- TGA_RAMDAC_REG);
+ int j = color_table[i];
+
+ TGA_WRITE_REG(par, default_red[j], TGA_RAMDAC_REG);
+ TGA_WRITE_REG(par, default_grn[j], TGA_RAMDAC_REG);
+ TGA_WRITE_REG(par, default_blu[j], TGA_RAMDAC_REG);
}
- for (i = 0; i < 512*3; i += 4) {
- TGA_WRITE_REG(par, 0x55|(BT463_PALETTE<<10),
- TGA_RAMDAC_REG);
- TGA_WRITE_REG(par, 0x00|(BT463_PALETTE<<10),
- TGA_RAMDAC_REG);
- TGA_WRITE_REG(par, 0x00|(BT463_PALETTE<<10),
- TGA_RAMDAC_REG);
- TGA_WRITE_REG(par, 0x00|(BT463_PALETTE<<10),
- TGA_RAMDAC_REG);
+ for (i = 0; i < 512 * 3; i += 4) {
+#else
+ for (i = 0; i < 528 * 3; i += 4) {
+#endif
+ TGA_WRITE_REG(par, 0x55, TGA_RAMDAC_REG);
+ TGA_WRITE_REG(par, 0x00, TGA_RAMDAC_REG);
+ TGA_WRITE_REG(par, 0x00, TGA_RAMDAC_REG);
+ TGA_WRITE_REG(par, 0x00, TGA_RAMDAC_REG);
}
/* Fill window type table after start of vertical retrace. */
@@ -299,15 +311,12 @@ tgafb_set_par(struct fb_info *info)
TGA_WRITE_REG(par, 0x01, TGA_INTR_STAT_REG);
BT463_LOAD_ADDR(par, BT463_WINDOW_TYPE_BASE);
- TGA_WRITE_REG(par, BT463_REG_ACC<<2, TGA_RAMDAC_SETUP_REG);
+ TGA_WRITE_REG(par, BT463_REG_ACC << 2, TGA_RAMDAC_SETUP_REG);
for (i = 0; i < 16; i++) {
- TGA_WRITE_REG(par, 0x00|(BT463_REG_ACC<<10),
- TGA_RAMDAC_REG);
- TGA_WRITE_REG(par, 0x01|(BT463_REG_ACC<<10),
- TGA_RAMDAC_REG);
- TGA_WRITE_REG(par, 0x80|(BT463_REG_ACC<<10),
- TGA_RAMDAC_REG);
+ TGA_WRITE_REG(par, 0x00, TGA_RAMDAC_REG);
+ TGA_WRITE_REG(par, 0x01, TGA_RAMDAC_REG);
+ TGA_WRITE_REG(par, 0x00, TGA_RAMDAC_REG);
}
}
@@ -435,9 +444,16 @@ tgafb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
TGA_WRITE_REG(par, red|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG);
TGA_WRITE_REG(par, green|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG);
TGA_WRITE_REG(par, blue|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG);
- } else if (regno < 16) {
- u32 value = (red << 16) | (green << 8) | blue;
- ((u32 *)info->pseudo_palette)[regno] = value;
+ } else {
+ if (regno < 16) {
+ u32 value = (regno << 16) | (regno << 8) | regno;
+ ((u32 *)info->pseudo_palette)[regno] = value;
+ }
+ BT463_LOAD_ADDR(par, regno);
+ TGA_WRITE_REG(par, BT463_PALETTE << 2, TGA_RAMDAC_SETUP_REG);
+ TGA_WRITE_REG(par, red, TGA_RAMDAC_REG);
+ TGA_WRITE_REG(par, green, TGA_RAMDAC_REG);
+ TGA_WRITE_REG(par, blue, TGA_RAMDAC_REG);
}
return 0;
@@ -885,7 +901,7 @@ copyarea_line_8bpp(struct fb_info *info, u32 dy, u32 sy,
n64 = (height * width) / 64;
- if (dy < sy) {
+ if (sy < dy) {
spos = (sy + height) * width;
dpos = (dy + height) * width;
@@ -933,7 +949,7 @@ copyarea_line_32bpp(struct fb_info *info, u32 dy, u32 sy,
n16 = (height * width) / 16;
- if (dy < sy) {
+ if (sy < dy) {
src = tga_fb + (sy + height) * width * 4;
dst = tga_fb + (dy + height) * width * 4;
@@ -1317,7 +1333,7 @@ tgafb_init_fix(struct fb_info *info)
info->fix.type_aux = 0;
info->fix.visual = (tga_type == TGA_TYPE_8PLANE
? FB_VISUAL_PSEUDOCOLOR
- : FB_VISUAL_TRUECOLOR);
+ : FB_VISUAL_DIRECTCOLOR);
info->fix.line_length = par->xres * (par->bits_per_pixel >> 3);
info->fix.smem_start = (size_t) par->tga_fb_base;
@@ -1342,14 +1358,10 @@ tgafb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
TGA_24PLUSZ_FB_OFFSET
};
- struct all_info {
- struct fb_info info;
- struct tga_par par;
- u32 pseudo_palette[16];
- } *all;
-
void __iomem *mem_base;
unsigned long bar0_start, bar0_len;
+ struct fb_info *info;
+ struct tga_par *par;
u8 tga_type;
int ret;
@@ -1360,13 +1372,14 @@ tgafb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
}
/* Allocate the fb and par structures. */
- all = kmalloc(sizeof(*all), GFP_KERNEL);
- if (!all) {
+ info = framebuffer_alloc(sizeof(struct tga_par), &pdev->dev);
+ if (!info) {
printk(KERN_ERR "tgafb: Cannot allocate memory\n");
return -ENOMEM;
}
- memset(all, 0, sizeof(*all));
- pci_set_drvdata(pdev, all);
+
+ par = info->par;
+ pci_set_drvdata(pdev, info);
/* Request the mem regions. */
bar0_start = pci_resource_start(pdev, 0);
@@ -1386,25 +1399,23 @@ tgafb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Grab info about the card. */
tga_type = (readl(mem_base) >> 12) & 0x0f;
- all->par.pdev = pdev;
- all->par.tga_mem_base = mem_base;
- all->par.tga_fb_base = mem_base + fb_offset_presets[tga_type];
- all->par.tga_regs_base = mem_base + TGA_REGS_OFFSET;
- all->par.tga_type = tga_type;
- pci_read_config_byte(pdev, PCI_REVISION_ID, &all->par.tga_chip_rev);
+ par->pdev = pdev;
+ par->tga_mem_base = mem_base;
+ par->tga_fb_base = mem_base + fb_offset_presets[tga_type];
+ par->tga_regs_base = mem_base + TGA_REGS_OFFSET;
+ par->tga_type = tga_type;
+ pci_read_config_byte(pdev, PCI_REVISION_ID, &par->tga_chip_rev);
/* Setup framebuffer. */
- all->info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_COPYAREA |
- FBINFO_HWACCEL_IMAGEBLIT | FBINFO_HWACCEL_FILLRECT;
- all->info.fbops = &tgafb_ops;
- all->info.screen_base = all->par.tga_fb_base;
- all->info.par = &all->par;
- all->info.pseudo_palette = all->pseudo_palette;
+ info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_COPYAREA |
+ FBINFO_HWACCEL_IMAGEBLIT | FBINFO_HWACCEL_FILLRECT;
+ info->fbops = &tgafb_ops;
+ info->screen_base = par->tga_fb_base;
+ info->pseudo_palette = (void *)(par + 1);
/* This should give a reasonable default video mode. */
- ret = fb_find_mode(&all->info.var, &all->info, mode_option,
- NULL, 0, NULL,
+ ret = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL,
tga_type == TGA_TYPE_8PLANE ? 8 : 32);
if (ret == 0 || ret == 4) {
printk(KERN_ERR "tgafb: Could not find valid video mode\n");
@@ -1412,29 +1423,28 @@ tgafb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
goto err1;
}
- if (fb_alloc_cmap(&all->info.cmap, 256, 0)) {
+ if (fb_alloc_cmap(&info->cmap, 256, 0)) {
printk(KERN_ERR "tgafb: Could not allocate color map\n");
ret = -ENOMEM;
goto err1;
}
- tgafb_set_par(&all->info);
- tgafb_init_fix(&all->info);
+ tgafb_set_par(info);
+ tgafb_init_fix(info);
- all->info.device = &pdev->dev;
- if (register_framebuffer(&all->info) < 0) {
+ if (register_framebuffer(info) < 0) {
printk(KERN_ERR "tgafb: Could not register framebuffer\n");
ret = -EINVAL;
goto err1;
}
printk(KERN_INFO "tgafb: DC21030 [TGA] detected, rev=0x%02x\n",
- all->par.tga_chip_rev);
+ par->tga_chip_rev);
printk(KERN_INFO "tgafb: at PCI bus %d, device %d, function %d\n",
pdev->bus->number, PCI_SLOT(pdev->devfn),
PCI_FUNC(pdev->devfn));
printk(KERN_INFO "fb%d: %s frame buffer device at 0x%lx\n",
- all->info.node, all->info.fix.id, bar0_start);
+ info->node, info->fix.id, bar0_start);
return 0;
@@ -1443,11 +1453,11 @@ tgafb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
iounmap(mem_base);
release_mem_region(bar0_start, bar0_len);
err0:
- kfree(all);
+ framebuffer_release(info);
return ret;
}
-static void __exit
+static void __devexit
tgafb_pci_unregister(struct pci_dev *pdev)
{
struct fb_info *info = pci_get_drvdata(pdev);
@@ -1456,22 +1466,21 @@ tgafb_pci_unregister(struct pci_dev *pdev)
if (!info)
return;
unregister_framebuffer(info);
+ fb_dealloc_cmap(&info->cmap);
iounmap(par->tga_mem_base);
release_mem_region(pci_resource_start(pdev, 0),
pci_resource_len(pdev, 0));
- kfree(info);
+ framebuffer_release(info);
}
-#ifdef MODULE
-static void __exit
+static void __devexit
tgafb_exit(void)
{
pci_unregister_driver(&tgafb_driver);
}
-#endif /* MODULE */
#ifndef MODULE
-int __init
+static int __devinit
tgafb_setup(char *arg)
{
char *this_opt;
@@ -1493,7 +1502,7 @@ tgafb_setup(char *arg)
}
#endif /* !MODULE */
-int __init
+static int __devinit
tgafb_init(void)
{
#ifndef MODULE
@@ -1511,10 +1520,7 @@ tgafb_init(void)
*/
module_init(tgafb_init);
-
-#ifdef MODULE
module_exit(tgafb_exit);
-#endif
MODULE_DESCRIPTION("framebuffer driver for TGA chipset");
MODULE_LICENSE("GPL");
diff --git a/drivers/video/vga16fb.c b/drivers/video/vga16fb.c
index 6aff63d5b29..ec4c7dc54a6 100644
--- a/drivers/video/vga16fb.c
+++ b/drivers/video/vga16fb.c
@@ -70,7 +70,8 @@ struct vga16fb_par {
unsigned char ClockingMode; /* Seq-Controller:01h */
} vga_state;
struct vgastate state;
- atomic_t ref_count;
+ struct mutex open_lock;
+ unsigned int ref_count;
int palette_blanked, vesa_blanked, mode, isVGA;
u8 misc, pel_msk, vss, clkdiv;
u8 crtc[VGA_CRT_C];
@@ -300,28 +301,33 @@ static void vga16fb_clock_chip(struct vga16fb_par *par,
static int vga16fb_open(struct fb_info *info, int user)
{
struct vga16fb_par *par = info->par;
- int cnt = atomic_read(&par->ref_count);
- if (!cnt) {
+ mutex_lock(&par->open_lock);
+ if (!par->ref_count) {
memset(&par->state, 0, sizeof(struct vgastate));
par->state.flags = VGA_SAVE_FONTS | VGA_SAVE_MODE |
VGA_SAVE_CMAP;
save_vga(&par->state);
}
- atomic_inc(&par->ref_count);
+ par->ref_count++;
+ mutex_unlock(&par->open_lock);
+
return 0;
}
static int vga16fb_release(struct fb_info *info, int user)
{
struct vga16fb_par *par = info->par;
- int cnt = atomic_read(&par->ref_count);
- if (!cnt)
+ mutex_lock(&par->open_lock);
+ if (!par->ref_count) {
+ mutex_unlock(&par->open_lock);
return -EINVAL;
- if (cnt == 1)
+ }
+ if (par->ref_count == 1)
restore_vga(&par->state);
- atomic_dec(&par->ref_count);
+ par->ref_count--;
+ mutex_unlock(&par->open_lock);
return 0;
}
@@ -1357,6 +1363,7 @@ static int __init vga16fb_probe(struct platform_device *dev)
printk(KERN_INFO "vga16fb: mapped to 0x%p\n", info->screen_base);
par = info->par;
+ mutex_init(&par->open_lock);
par->isVGA = ORIG_VIDEO_ISVGA;
par->palette_blanked = 0;
par->vesa_blanked = 0;
diff --git a/drivers/video/virgefb.c b/drivers/video/virgefb.c
deleted file mode 100644
index b9fb6fb3600..00000000000
--- a/drivers/video/virgefb.c
+++ /dev/null
@@ -1,2526 +0,0 @@
-/*
- * linux/drivers/video/virgefb.c -- CyberVision64/3D frame buffer device
- *
- * Copyright (C) 1997 André Heynatz
- *
- *
- * This file is based on the CyberVision frame buffer device (cyberfb.c):
- *
- * Copyright (C) 1996 Martin Apel
- * Geert Uytterhoeven
- *
- * Zorro II additions :
- *
- * Copyright (C) 1998-2000 Christian T. Steigies
- *
- * Initialization additions :
- *
- * Copyright (C) 1998-2000 Ken Tyler
- *
- * Parts of the Initialization code are based on Cyberfb.c by Allan Bair,
- * and on the NetBSD CyberVision64 frame buffer driver by Michael Teske who gave
- * permission for its use.
- *
- * Many thanks to Frank Mariak for his assistance with ZORRO 2 access and other
- * mysteries.
- *
- *
- *
- * 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.
- */
-
-#undef VIRGEFBDEBUG
-#undef VIRGEFBDUMP
-
-#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/zorro.h>
-#include <linux/fb.h>
-#include <linux/init.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <asm/amigahw.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <video/fbcon.h>
-#include <video/fbcon-cfb8.h>
-#include <video/fbcon-cfb16.h>
-#include <video/fbcon-cfb32.h>
-
-#include "virgefb.h"
-
-#ifdef VIRGEFBDEBUG
-#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
-#else
-#define DPRINTK(fmt, args...)
-#endif
-
-#ifdef VIRGEFBDUMP
-static void cv64_dump(void);
-#define DUMP cv64_dump()
-#else
-#define DUMP
-#endif
-
-/*
- * Macros for register access and zorro control
- */
-
-static inline void mb_inline(void) { mb(); } /* for use in comma expressions */
-
-/* Set zorro 2 map */
-
-#define SelectIO \
- mb(); \
- if (on_zorro2) { \
- (*(volatile u16 *)((u8 *)(vcode_switch_base + 0x04)) = 0x01); \
- mb(); \
- }
-
-#define SelectMMIO \
- mb(); \
- if (on_zorro2) { \
- (*(volatile u16 *)((u8 *)(vcode_switch_base + 0x04)) = 0x02); \
- mb(); \
- }
-
-#define SelectCFG \
- mb(); \
- if (on_zorro2) { \
- (*(volatile u16 *)((u8 *)(vcode_switch_base + 0x04)) = 0x03); \
- mb(); \
- }
-
-/* Set pass through, 0 = amiga, !=0 = cv64/3d */
-
-#define SetVSwitch(x) \
- mb(); \
- (*(volatile u16 *)((u8 *)(vcode_switch_base)) = \
- (u16)(x ? 0 : 1)); \
- mb();
-
-/* Zorro2 endian 'aperture' */
-
-#define ENDIAN_BYTE 2
-#define ENDIAN_WORD 1
-#define ENDIAN_LONG 0
-
-#define Select_Zorro2_FrameBuffer(x) \
- do { \
- if (on_zorro2) { \
- mb(); \
- (*(volatile u16 *)((u8 *)(vcode_switch_base + 0x08)) = \
- (x * 0x40)); \
- mb(); \
- } \
- } while (0)
-
-/* SetPortVal - only used for interrupt enable (not yet implemented) */
-
-#if 0
-#define SetPortVal(x) \
- mb(); \
- (*(volatile u16 *)((u8 *)(vcode_switch_base + 0x0c)) = \
- (u16)x); \
- mb();
-#endif
-
-/* IO access */
-
-#define byte_access_io(x) (((x) & 0x3ffc) | (((x) & 3)^3) | (((x) & 3) <<14))
-#define byte_access_mmio(x) (((x) & 0xfffc) | (((x) & 3)^3))
-
-/* Write 8 bit VGA register - used once for chip wakeup */
-
-#define wb_vgaio(reg, dat) \
- SelectIO; \
- (*(volatile u8 *)(vgaio_regs + ((u32)byte_access_io(reg) & 0xffff)) = \
- (dat & 0xff)); \
- SelectMMIO;
-
-/* Read 8 bit VGA register - only used in dump (SelectIO not needed on read ?) */
-
-#ifdef VIRGEFBDUMP
-#define rb_vgaio(reg) \
- ({ \
- u8 __zzyzx; \
- SelectIO; \
- __zzyzx = (*(volatile u8 *)((vgaio_regs)+(u32)byte_access_io(reg))); \
- SelectMMIO; \
- __zzyzx; \
- })
-#endif
-
-/* MMIO access */
-
-/* Read 8 bit MMIO register */
-
-#define rb_mmio(reg) \
- (mb_inline(), \
- (*(volatile u8 *)(mmio_regs + 0x8000 + (u32)byte_access_mmio(reg))))
-
-/* Write 8 bit MMIO register */
-
-#define wb_mmio(reg,dat) \
- mb(); \
- (*(volatile u8 *)(mmio_regs + 0x8000 + (byte_access_mmio((reg) & 0xffff))) = \
- (dat & 0xff)); \
- mb();
-
-/* Read 32 bit MMIO register */
-
-#define rl_mmio(reg) \
- (mb_inline(), \
- (*((volatile u32 *)((u8 *)((mmio_regs + (on_zorro2 ? 0x20000 : 0)) + (reg))))))
-
-/* Write 32 bit MMIO register */
-
-#define wl_mmio(reg,dat) \
- mb(); \
- ((*(volatile u32 *)((u8 *)((mmio_regs + (on_zorro2 ? 0x20000 : 0)) + (reg)))) = \
- (u32)(dat)); \
- mb();
-
-/* Write to virge graphics register */
-
-#define wgfx(reg, dat) do { wb_mmio(GCT_ADDRESS, (reg)); wb_mmio(GCT_ADDRESS_W, (dat)); } while (0)
-
-/* Write to virge sequencer register */
-
-#define wseq(reg, dat) do { wb_mmio(SEQ_ADDRESS, (reg)); wb_mmio(SEQ_ADDRESS_W, (dat)); } while (0)
-
-/* Write to virge CRT controller register */
-
-#define wcrt(reg, dat) do { wb_mmio(CRT_ADDRESS, (reg)); wb_mmio(CRT_ADDRESS_W, (dat)); } while (0)
-
-/* Write to virge attribute register */
-
-#define watr(reg, dat) \
- do { \
- volatile unsigned char watr_tmp; \
- watr_tmp = rb_mmio(ACT_ADDRESS_RESET); \
- wb_mmio(ACT_ADDRESS_W, (reg)); \
- wb_mmio(ACT_ADDRESS_W, (dat)); \
- udelay(10); \
- } while (0)
-
-/* end of macros */
-
-struct virgefb_par {
- struct fb_var_screeninfo var;
- __u32 type;
- __u32 type_aux;
- __u32 visual;
- __u32 line_length;
-};
-
-static struct virgefb_par current_par;
-
-static int current_par_valid = 0;
-
-static struct display disp;
-static struct fb_info fb_info;
-
-static union {
-#ifdef FBCON_HAS_CFB16
- u16 cfb16[16];
-#endif
-#ifdef FBCON_HAS_CFB32
- u32 cfb32[16];
-#endif
-} fbcon_cmap;
-
-/*
- * Switch for Chipset Independency
- */
-
-static struct fb_hwswitch {
-
- /* Initialisation */
-
- int (*init)(void);
-
- /* Display Control */
-
- int (*encode_fix)(struct fb_fix_screeninfo *fix, struct virgefb_par *par);
- int (*decode_var)(struct fb_var_screeninfo *var, struct virgefb_par *par);
- int (*encode_var)(struct fb_var_screeninfo *var, struct virgefb_par *par);
- int (*getcolreg)(u_int regno, u_int *red, u_int *green, u_int *blue,
- u_int *transp, struct fb_info *info);
- void (*blank)(int blank);
-} *fbhw;
-
-static unsigned char blit_maybe_busy = 0;
-
-/*
- * Frame Buffer Name
- */
-
-static char virgefb_name[16] = "CyberVision/3D";
-
-/*
- * CyberVision64/3d Graphics Board
- */
-
-static unsigned char virgefb_colour_table [256][3];
-static unsigned long v_ram;
-static unsigned long v_ram_size;
-static volatile unsigned char *mmio_regs;
-static volatile unsigned char *vgaio_regs;
-
-static unsigned long v_ram_phys;
-static unsigned long mmio_regs_phys;
-static unsigned long vcode_switch_base;
-static unsigned char on_zorro2;
-
-/*
- * Offsets from start of video ram to appropriate ZIII aperture
- */
-
-#ifdef FBCON_HAS_CFB8
-#define CYBMEM_OFFSET_8 0x800000 /* BGRX */
-#endif
-#ifdef FBCON_HAS_CFB16
-#define CYBMEM_OFFSET_16 0x400000 /* GBXR */
-#endif
-#ifdef FBCON_HAS_CFB32
-#define CYBMEM_OFFSET_32 0x000000 /* XRGB */
-#endif
-
-/*
- * MEMCLOCK was 32MHz, 64MHz works, 72MHz doesn't (on my board)
- */
-
-#define MEMCLOCK 50000000
-
-/*
- * Predefined Video Modes
- */
-
-static struct {
- const char *name;
- struct fb_var_screeninfo var;
-} virgefb_predefined[] __initdata = {
-#ifdef FBCON_HAS_CFB8
- {
- "640x480-8", { /* Cybervision 8 bpp */
- 640, 480, 640, 480, 0, 0, 8, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 31250, 160, 136, 82, 61, 88, 2,
- 0, FB_VMODE_NONINTERLACED
- }
- }, {
- "768x576-8", { /* Cybervision 8 bpp */
- 768, 576, 768, 576, 0, 0, 8, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 29411, 144, 112, 32, 15, 64, 2,
- 0, FB_VMODE_NONINTERLACED
- }
- }, {
- "800x600-8", { /* Cybervision 8 bpp */
- 800, 600, 800, 600, 0, 0, 8, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 28571, 168, 104, 22, 1, 48, 2,
- 0, FB_VMODE_NONINTERLACED
- }
- }, {
- #if 0
- "1024x768-8", { /* Cybervision 8 bpp */
- 1024, 768, 1024, 768, 0, 0, 8, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 20833, 272, 168, 39, 2, 72, 1,
- 0, FB_VMODE_NONINTERLACED
- }
- #else
- "1024x768-8", {
- 1024, 768, 1024, 768, 0, 0, 8, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- #if 0
- 0, 0, -1, -1, FB_ACCELF_TEXT, 12500, 184, 40, 40, 2, 96, 1,
- FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
- }
- #else
- 0, 0, -1, -1, FB_ACCELF_TEXT, 12699, 176, 16, 28, 1, 96, 3,
- FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
- }
- #endif
- #endif
- }, {
- "1152x886-8", { /* Cybervision 8 bpp */
- 1152, 886, 1152, 886, 0, 0, 8, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 19230, 280, 168, 45, 1, 64, 10,
- 0, FB_VMODE_NONINTERLACED
- }
- }, {
- "1280x1024-8", { /* Cybervision 8 bpp */
- 1280, 1024, 1280, 1024, 0, 0, 8, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- #if 0
- 0, 0, -1, -1, FB_ACCELF_TEXT, 17857, 232, 232, 71, 15, 176, 12,
- }
- #else
- 0, 0, -1, -1, FB_ACCELF_TEXT, 7414, 232, 64, 38, 1, 112, 3,
- FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
- }
- #endif
- }, {
- "1600x1200-8", { /* Cybervision 8 bpp */
- 1600, 1200, 1600, 1200, 0, 0, 8, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- #if 0
- 0, 0, -1, -1, FB_ACCELF_TEXT, 13698, 336, 224, 77, 15, 176, 12,
- 0, FB_VMODE_NONINTERLACED
- }
- #else
- 0, 0, -1, -1, FB_ACCELF_TEXT, 6411, 256, 32, 52, 10, 160, 8,
- FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
- }
- #endif
- },
-#endif
-
-#ifdef FBCON_HAS_CFB16
- {
- "640x480-16", { /* Cybervision 16 bpp */
- 640, 480, 640, 480, 0, 0, 16, 0,
- {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 31250, 152, 144, 82, 61, 88, 2,
- 0, FB_VMODE_NONINTERLACED
- }
- }, {
- "768x576-16", { /* Cybervision 16 bpp */
- 768, 576, 768, 576, 0, 0, 16, 0,
- {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 29411, 144, 112, 32, 15, 64, 2,
- 0, FB_VMODE_NONINTERLACED
- }
- }, {
- "800x600-16", { /* Cybervision 16 bpp */
- 800, 600, 800, 600, 0, 0, 16, 0,
- {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 28571, 168, 104, 22, 1, 48, 2,
- 0, FB_VMODE_NONINTERLACED
- }
- }, {
-#if 0
- "1024x768-16", { /* Cybervision 16 bpp */
- 1024, 768, 1024, 768, 0, 0, 16, 0,
- {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 20833, 272, 168, 39, 2, 72, 1,
- 0, FB_VMODE_NONINTERLACED
- }
-#else
- "1024x768-16", {
- 1024, 768, 1024, 768, 0, 0, 16, 0,
- {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 12500, 184, 40, 40, 2, 96, 1,
- FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
- }
-#endif
- }, {
- "1152x886-16", { /* Cybervision 16 bpp */
- 1152, 886, 1152, 886, 0, 0, 16, 0,
- {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 19230, 280, 168, 45, 1, 64, 10,
- 0, FB_VMODE_NONINTERLACED
- }
- }, {
- "1280x1024-16", { /* Cybervision 16 bpp */
- 1280, 1024, 1280, 1024, 0, 0, 16, 0,
- {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 17857, 232, 232, 71, 15, 176, 12,
- 0, FB_VMODE_NONINTERLACED
- }
- }, {
- "1600x1200-16", { /* Cybervision 16 bpp */
- 1600, 1200, 1600, 1200, 0, 0, 16, 0,
- {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 13698, 336, 224, 77, 15, 176, 12,
- 0, FB_VMODE_NONINTERLACED
- }
- },
-#endif
-
-#ifdef FBCON_HAS_CFB32
- {
- "640x480-32", { /* Cybervision 32 bpp */
- 640, 480, 640, 480, 0, 0, 32, 0,
- {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {24, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 31250, 160, 136, 82, 61, 88, 2,
- 0, FB_VMODE_NONINTERLACED
- }
- }, {
- "768x576-32", { /* Cybervision 32 bpp */
- 768, 576, 768, 576, 0, 0, 32, 0,
- {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {24, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 29411, 144, 112, 32, 15, 64, 2,
- 0, FB_VMODE_NONINTERLACED
- }
- }, {
- "800x600-32", { /* Cybervision 32 bpp */
- 800, 600, 800, 600, 0, 0, 32, 0,
- {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {24, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 28571, 168, 104, 22, 1, 48, 2,
- 0, FB_VMODE_NONINTERLACED
- }
- }, {
- "1024x768-32", { /* Cybervision 32 bpp */
- 1024, 768, 1024, 768, 0, 0, 32, 0,
- {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {24, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 20833, 272, 168, 39, 2, 72, 1,
- 0, FB_VMODE_NONINTERLACED
- }
- }, {
- "1152x886-32", { /* Cybervision 32 bpp */
- 1152, 886, 1152, 886, 0, 0, 32, 0,
- {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {24, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 19230, 280, 168, 45, 1, 64, 10,
- 0, FB_VMODE_NONINTERLACED
- }
- }, {
- "1280x1024-32", { /* Cybervision 32 bpp */
- 1280, 1024, 1280, 1024, 0, 0, 32, 0,
- {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {24, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 17857, 232, 232, 71, 15, 176, 12,
- 0, FB_VMODE_NONINTERLACED
- }
- }, {
- "1600x1200-32", { /* Cybervision 32 bpp */
- 1600, 1200, 1600, 1200, 0, 0, 32, 0,
- {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {24, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 13698, 336, 224, 77, 15, 176, 12,
- 0, FB_VMODE_NONINTERLACED
- }
- },
-#endif
-
-/* interlaced modes */
-
-#ifdef FBCON_HAS_CFB8
- {
- "1024x768-8i", { /* Cybervision 8 bpp */
- 1024, 768, 1024, 768, 0, 0, 8, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 20833, 272, 168, 39, 2, 72, 1,
- 0, FB_VMODE_INTERLACED
- }
- }, {
- "1280x1024-8i", { /* Cybervision 8 bpp */
- 1280, 1024, 1280, 1024, 0, 0, 8, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 17857, 232, 232, 71, 15, 176, 12,
- 0, FB_VMODE_INTERLACED
- }
- }, {
- "1600x1200-8i", { /* Cybervision 8 bpp */
- 1600, 1200, 1600, 1200, 0, 0, 8, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 13698, 336, 224, 77, 15, 176, 12,
- 0, FB_VMODE_INTERLACED
- }
- },
-#endif
-
-#ifdef FBCON_HAS_CFB16
- {
- "1024x768-16i", { /* Cybervision 16 bpp */
- 1024, 768, 1024, 768, 0, 0, 16, 0,
- {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 20833, 272, 168, 39, 2, 72, 1,
- 0, FB_VMODE_INTERLACED
- }
- }, {
- "1280x1024-16i", { /* Cybervision 16 bpp */
- 1280, 1024, 1280, 1024, 0, 0, 16, 0,
- {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 17857, 232, 232, 71, 15, 176, 12,
- 0, FB_VMODE_INTERLACED
- }
- }, {
- "1600x1200-16i", { /* Cybervision 16 bpp */
- 1600, 1200, 1600, 1200, 0, 0, 16, 0,
- {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 13698, 336, 224, 77, 15, 176, 12,
- 0, FB_VMODE_INTERLACED
- }
- },
-#endif
-
-#ifdef FBCON_HAS_CFB32
- {
- "1024x768-32i", { /* Cybervision 32 bpp */
- 1024, 768, 1024, 768, 0, 0, 32, 0,
- {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {24, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 22222, 216, 144, 39, 2, 72, 1,
- 0, FB_VMODE_INTERLACED
- }
- }, {
- "1280x1024-32i", { /* Cybervision 32 bpp */
- 1280, 1024, 1280, 1024, 0, 0, 32, 0,
- {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {23, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 17857, 232, 232, 71, 15, 176, 12,
- 0, FB_VMODE_INTERLACED
- }
- }, {
- "1600x1200-32i", { /* Cybervision 32 bpp */
- 1600, 1200, 1600, 1200, 0, 0, 32, 0,
- {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {24, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 13698, 336, 224, 77, 15, 176, 12,
- 0, FB_VMODE_INTERLACED
- }
- },
-#endif
-
-/* doublescan modes */
-
-#ifdef FBCON_HAS_CFB8
- {
- "320x240-8d", { /* Cybervision 8 bpp */
- 320, 240, 320, 240, 0, 0, 8, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 59259, 80, 80, 45, 26, 32, 1,
- 0, FB_VMODE_DOUBLE
- }
- },
-#endif
-
-#ifdef FBCON_HAS_CFB16
- {
- "320x240-16d", { /* Cybervision 16 bpp */
- 320, 240, 320, 240, 0, 0, 16, 0,
- {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 59259, 80, 80, 45, 26, 32, 1,
- 0, FB_VMODE_DOUBLE
- }
- },
-#endif
-
-#ifdef FBCON_HAS_CFB32
- {
- "320x240-32d", { /* Cybervision 32 bpp */
- 320, 240, 320, 240, 0, 0, 32, 0,
- {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {24, 0, 0},
- 0, 0, -1, -1, FB_ACCELF_TEXT, 59259, 80, 80, 45, 26, 32, 1,
- 0, FB_VMODE_DOUBLE
- }
- },
-#endif
-};
-
-#define NUM_TOTAL_MODES ARRAY_SIZE(virgefb_predefined)
-
-/*
- * Default to 800x600 for video=virge8:, virge16: or virge32:
- */
-
-#ifdef FBCON_HAS_CFB8
-#define VIRGE8_DEFMODE (2)
-#endif
-
-#ifdef FBCON_HAS_CFB16
-#define VIRGE16_DEFMODE (9)
-#endif
-
-#ifdef FBCON_HAS_CFB32
-#define VIRGE32_DEFMODE (16)
-#endif
-
-static struct fb_var_screeninfo virgefb_default;
-static int virgefb_inverse = 0;
-
-/*
- * Interface used by the world
- */
-
-int virgefb_setup(char*);
-static int virgefb_get_fix(struct fb_fix_screeninfo *fix, int con,
- struct fb_info *info);
-static int virgefb_get_var(struct fb_var_screeninfo *var, int con,
- struct fb_info *info);
-static int virgefb_set_var(struct fb_var_screeninfo *var, int con,
- struct fb_info *info);
-static int virgefb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
- struct fb_info *info);
-static int virgefb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
- u_int transp, struct fb_info *info);
-static int virgefb_blank(int blank, struct fb_info *info);
-
-/*
- * Interface to the low level console driver
- */
-
-int virgefb_init(void);
-static int virgefb_switch(int con, struct fb_info *info);
-static int virgefb_updatevar(int con, struct fb_info *info);
-
-/*
- * Text console acceleration
- */
-
-#ifdef FBCON_HAS_CFB8
-static struct display_switch fbcon_virge8;
-#endif
-
-#ifdef FBCON_HAS_CFB16
-static struct display_switch fbcon_virge16;
-#endif
-
-#ifdef FBCON_HAS_CFB32
-static struct display_switch fbcon_virge32;
-#endif
-
-/*
- * Hardware Specific Routines
- */
-
-static int virge_init(void);
-static int virgefb_encode_fix(struct fb_fix_screeninfo *fix,
- struct virgefb_par *par);
-static int virgefb_decode_var(struct fb_var_screeninfo *var,
- struct virgefb_par *par);
-static int virgefb_encode_var(struct fb_var_screeninfo *var,
- struct virgefb_par *par);
-static int virgefb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
- u_int *transp, struct fb_info *info);
-static void virgefb_gfx_on_off(int blank);
-static inline void virgefb_wait_for_idle(void);
-static void virgefb_BitBLT(u_short curx, u_short cury, u_short destx, u_short desty,
- u_short width, u_short height, u_short stride, u_short depth);
-static void virgefb_RectFill(u_short x, u_short y, u_short width, u_short height,
- u_short color, u_short stride, u_short depth);
-
-/*
- * Internal routines
- */
-
-static void virgefb_get_par(struct virgefb_par *par);
-static void virgefb_set_par(struct virgefb_par *par);
-static int virgefb_do_fb_set_var(struct fb_var_screeninfo *var, int isactive);
-static void virgefb_set_disp(int con, struct fb_info *info);
-static int virgefb_get_video_mode(const char *name);
-static void virgefb_set_video(struct fb_var_screeninfo *var);
-
-/*
- * Additions for Initialization
- */
-
-static void virgefb_load_video_mode(struct fb_var_screeninfo *video_mode);
-static int cv3d_has_4mb(void);
-static unsigned short virgefb_compute_clock(unsigned long freq);
-static inline unsigned char rattr(short);
-static inline unsigned char rseq(short);
-static inline unsigned char rcrt(short);
-static inline unsigned char rgfx(short);
-static inline void gfx_on_off(int toggle);
-static void virgefb_pci_init(void);
-
-/* -------------------- Hardware specific routines ------------------------- */
-
-/*
- * Functions for register access
- */
-
-/* Read attribute controller register */
-
-static inline unsigned char rattr(short idx)
-{
- volatile unsigned char rattr_tmp;
-
- rattr_tmp = rb_mmio(ACT_ADDRESS_RESET);
- wb_mmio(ACT_ADDRESS_W, idx);
- return (rb_mmio(ACT_ADDRESS_R));
-}
-
-/* Read sequencer register */
-
-static inline unsigned char rseq(short idx)
-{
- wb_mmio(SEQ_ADDRESS, idx);
- return (rb_mmio(SEQ_ADDRESS_R));
-}
-
-/* Read CRT controller register */
-
-static inline unsigned char rcrt(short idx)
-{
- wb_mmio(CRT_ADDRESS, idx);
- return (rb_mmio(CRT_ADDRESS_R));
-}
-
-/* Read graphics controller register */
-
-static inline unsigned char rgfx(short idx)
-{
- wb_mmio(GCT_ADDRESS, idx);
- return (rb_mmio(GCT_ADDRESS_R));
-}
-
-
-/*
- * Initialization
- */
-
-/* PCI init */
-
-void virgefb_pci_init(void) {
-
- DPRINTK("ENTER\n");
-
- SelectCFG;
-
- if (on_zorro2) {
- *((short *)(vgaio_regs + 0x00000010)) = 0;
- *((long *)(vgaio_regs + 0x00000004)) = 0x02000003;
- } else {
- *((short *)(vgaio_regs + 0x000e0010)) = 0;
- *((long *)(vgaio_regs + 0x000e0004)) = 0x02000003;
- }
-
- /* SelectIO is in wb_vgaio macro */
- wb_vgaio(SREG_VIDEO_SUBS_ENABLE, 0x01);
- /* SelectMMIO is in wb_vgaio macro */
-
- DPRINTK("EXIT\n");
-
- return;
-}
-
-/*
- * Initalize all mode independent regs, find mem size and clear mem
-*/
-
-static int virge_init(void)
-{
- int i;
- unsigned char tmp;
-
- DPRINTK("ENTER\n");
-
- virgefb_pci_init();
-
- wb_mmio(GREG_MISC_OUTPUT_W, 0x07); /* colour, ram enable, clk sel */
-
- wseq(SEQ_ID_UNLOCK_EXT, 0x06); /* unlock extensions */
- tmp = rb_mmio(GREG_MISC_OUTPUT_R);
- wcrt(CRT_ID_REGISTER_LOCK_1, 0x48); /* unlock CR2D to CR3F */
-
- wcrt(CRT_ID_BACKWAD_COMP_1, 0x00); /* irq disable */
-
- wcrt(CRT_ID_REGISTER_LOCK_2, 0xa5); /* unlock CR40 to CRFF and more */
- wcrt(CRT_ID_REGISTER_LOCK,0x00); /* unlock h and v timing */
- wcrt(CRT_ID_SYSTEM_CONFIG, 0x01); /* unlock enhanced programming registers */
-
- wb_mmio(GREG_FEATURE_CONTROL_W, 0x00);
-
- wcrt(CRT_ID_EXT_MISC_CNTL, 0x00); /* b2 = 0 to allow VDAC mmio access */
-#if 0
- /* write strap options ... ? */
- wcrt(CRT_ID_CONFIG_1, 0x08);
- wcrt(CRT_ID_CONFIG_2, 0xff); /* 0x0x2 bit needs to be set ?? */
- wcrt(CRT_ID_CONFIG_3, 0x0f);
- wcrt(CRT_ID_CONFIG_4, 0x1a);
-#endif
- wcrt(CRT_ID_EXT_MISC_CNTL_1, 0x82); /* PCI DE and software reset S3D engine */
- /* EXT_MISC_CNTL_1, CR66 bit 0 should be the same as bit 0 MR_ADVANCED_FUNCTION_CONTROL - check */
- wl_mmio(MR_ADVANCED_FUNCTION_CONTROL, 0x00000011); /* enhanced mode, linear addressing */
-
-/* crtc registers */
-
- wcrt(CRT_ID_PRESET_ROW_SCAN, 0x00);
-
- /* Disable h/w cursor */
-
- wcrt(CRT_ID_CURSOR_START, 0x00);
- wcrt(CRT_ID_CURSOR_END, 0x00);
- wcrt(CRT_ID_START_ADDR_HIGH, 0x00);
- wcrt(CRT_ID_START_ADDR_LOW, 0x00);
- wcrt(CRT_ID_CURSOR_LOC_HIGH, 0x00);
- wcrt(CRT_ID_CURSOR_LOC_LOW, 0x00);
- wcrt(CRT_ID_EXT_MODE, 0x00);
- wcrt(CRT_ID_HWGC_MODE, 0x00);
- wcrt(CRT_ID_HWGC_ORIGIN_X_HI, 0x00);
- wcrt(CRT_ID_HWGC_ORIGIN_X_LO, 0x00);
- wcrt(CRT_ID_HWGC_ORIGIN_Y_HI, 0x00);
- wcrt(CRT_ID_HWGC_ORIGIN_Y_LO, 0x00);
- i = rcrt(CRT_ID_HWGC_MODE);
- wcrt(CRT_ID_HWGC_FG_STACK, 0x00);
- wcrt(CRT_ID_HWGC_FG_STACK, 0x00);
- wcrt(CRT_ID_HWGC_FG_STACK, 0x00);
- wcrt(CRT_ID_HWGC_BG_STACK, 0x00);
- wcrt(CRT_ID_HWGC_BG_STACK, 0x00);
- wcrt(CRT_ID_HWGC_BG_STACK, 0x00);
- wcrt(CRT_ID_HWGC_START_AD_HI, 0x00);
- wcrt(CRT_ID_HWGC_START_AD_LO, 0x00);
- wcrt(CRT_ID_HWGC_DSTART_X, 0x00);
- wcrt(CRT_ID_HWGC_DSTART_Y, 0x00);
-
- wcrt(CRT_ID_UNDERLINE_LOC, 0x00);
-
- wcrt(CRT_ID_MODE_CONTROL, 0xe3);
- wcrt(CRT_ID_BACKWAD_COMP_2, 0x22); /* blank bdr bit 5 blanking only on 8 bit */
-
- wcrt(CRT_ID_EX_SYNC_1, 0x00);
-
- /* memory */
-
- wcrt(CRT_ID_EXT_SYS_CNTL_3, 0x00);
- wcrt(CRT_ID_MEMORY_CONF, 0x08); /* config enhanced map */
- wcrt(CRT_ID_EXT_MEM_CNTL_1, 0x08); /* MMIO Select (0x0c works as well)*/
- wcrt(CRT_ID_EXT_MEM_CNTL_2, 0x02); /* why 02 big endian 00 works ? */
- wcrt(CRT_ID_EXT_MEM_CNTL_4, 0x9f); /* config big endian - 0x00 ? */
- wcrt(CRT_ID_LAW_POS_HI, 0x00);
- wcrt(CRT_ID_LAW_POS_LO, 0x00);
- wcrt(CRT_ID_EXT_MISC_CNTL_1, 0x81);
- wcrt(CRT_ID_MISC_1, 0x90); /* must follow CRT_ID_EXT_MISC_CNTL_1 */
- wcrt(CRT_ID_LAW_CNTL, 0x13); /* force 4 Meg for test */
- if (cv3d_has_4mb()) {
- v_ram_size = 0x00400000;
- wcrt(CRT_ID_LAW_CNTL, 0x13); /* 4 MB */
- } else {
- v_ram_size = 0x00200000;
- wcrt(CRT_ID_LAW_CNTL, 0x12); /* 2 MB */
- }
-
- if (on_zorro2)
- v_ram_size -= 0x60000; /* we need some space for the registers */
-
- wcrt(CRT_ID_EXT_SYS_CNTL_4, 0x00);
- wcrt(CRT_ID_EXT_DAC_CNTL, 0x00); /* 0x10 for X11 cursor mode */
-
-/* sequencer registers */
-
- wseq(SEQ_ID_CLOCKING_MODE, 0x01); /* 8 dot clock */
- wseq(SEQ_ID_MAP_MASK, 0xff);
- wseq(SEQ_ID_CHAR_MAP_SELECT, 0x00);
- wseq(SEQ_ID_MEMORY_MODE, 0x02);
- wseq(SEQ_ID_RAMDAC_CNTL, 0x00);
- wseq(SEQ_ID_SIGNAL_SELECT, 0x00);
- wseq(SEQ_ID_EXT_SEQ_REG9, 0x00); /* MMIO and PIO reg access enabled */
- wseq(SEQ_ID_EXT_MISC_SEQ, 0x00);
- wseq(SEQ_ID_CLKSYN_CNTL_1, 0x00);
- wseq(SEQ_ID_EXT_SEQ, 0x00);
-
-/* graphic registers */
-
- wgfx(GCT_ID_SET_RESET, 0x00);
- wgfx(GCT_ID_ENABLE_SET_RESET, 0x00);
- wgfx(GCT_ID_COLOR_COMPARE, 0x00);
- wgfx(GCT_ID_DATA_ROTATE, 0x00);
- wgfx(GCT_ID_READ_MAP_SELECT, 0x00);
- wgfx(GCT_ID_GRAPHICS_MODE, 0x40);
- wgfx(GCT_ID_MISC, 0x01);
- wgfx(GCT_ID_COLOR_XCARE, 0x0f);
- wgfx(GCT_ID_BITMASK, 0xff);
-
-/* attribute registers */
-
- for(i = 0; i <= 15; i++)
- watr(ACT_ID_PALETTE0 + i, i);
- watr(ACT_ID_ATTR_MODE_CNTL, 0x41);
- watr(ACT_ID_OVERSCAN_COLOR, 0xff);
- watr(ACT_ID_COLOR_PLANE_ENA, 0x0f);
- watr(ACT_ID_HOR_PEL_PANNING, 0x00);
- watr(ACT_ID_COLOR_SELECT, 0x00);
-
- wb_mmio(VDAC_MASK, 0xff);
-
-/* init local cmap as greyscale levels */
-
- for (i = 0; i < 256; i++) {
- virgefb_colour_table [i][0] = i;
- virgefb_colour_table [i][1] = i;
- virgefb_colour_table [i][2] = i;
- }
-
-/* clear framebuffer memory */
-
- memset((char*)v_ram, 0x00, v_ram_size);
-
- DPRINTK("EXIT\n");
- return 0;
-}
-
-
-/*
- * This function should fill in the `fix' structure based on the
- * values in the `par' structure.
- */
-
-static int virgefb_encode_fix(struct fb_fix_screeninfo *fix,
- struct virgefb_par *par)
-{
- DPRINTK("ENTER set video phys addr\n");
-
- memset(fix, 0, sizeof(struct fb_fix_screeninfo));
- strcpy(fix->id, virgefb_name);
- if (on_zorro2)
- fix->smem_start = v_ram_phys;
- switch (par->var.bits_per_pixel) {
-#ifdef FBCON_HAS_CFB8
- case 8:
- if (on_zorro2)
- Select_Zorro2_FrameBuffer(ENDIAN_BYTE);
- else
- fix->smem_start = (v_ram_phys + CYBMEM_OFFSET_8);
- break;
-#endif
-#ifdef FBCON_HAS_CFB16
- case 16:
- if (on_zorro2)
- Select_Zorro2_FrameBuffer(ENDIAN_WORD);
- else
- fix->smem_start = (v_ram_phys + CYBMEM_OFFSET_16);
- break;
-#endif
-#ifdef FBCON_HAS_CFB32
- case 32:
- if (on_zorro2)
- Select_Zorro2_FrameBuffer(ENDIAN_LONG);
- else
- fix->smem_start = (v_ram_phys + CYBMEM_OFFSET_32);
- break;
-#endif
- }
-
- fix->smem_len = v_ram_size;
- fix->mmio_start = mmio_regs_phys;
- fix->mmio_len = 0x10000; /* TODO: verify this for the CV64/3D */
-
- fix->type = FB_TYPE_PACKED_PIXELS;
- fix->type_aux = 0;
- if (par->var.bits_per_pixel == 8)
- fix->visual = FB_VISUAL_PSEUDOCOLOR;
- else
- fix->visual = FB_VISUAL_TRUECOLOR;
-
- fix->xpanstep = 0;
- fix->ypanstep = 0;
- fix->ywrapstep = 0;
- fix->line_length = par->var.xres_virtual*par->var.bits_per_pixel/8;
- fix->accel = FB_ACCEL_S3_VIRGE;
- DPRINTK("EXIT v_ram_phys = 0x%8.8lx\n", (unsigned long)fix->smem_start);
- return 0;
-}
-
-
-/*
- * Fill the `par' structure based on the values in `var'.
- * TODO: Verify and adjust values, return -EINVAL if bad.
- */
-
-static int virgefb_decode_var(struct fb_var_screeninfo *var,
- struct virgefb_par *par)
-{
- DPRINTK("ENTER\n");
- par->var.xres = var->xres;
- par->var.yres = var->yres;
- par->var.xres_virtual = var->xres_virtual;
- par->var.yres_virtual = var->yres_virtual;
- /* roundup and validate */
- par->var.xres = (par->var.xres+7) & ~7;
- par->var.xres_virtual = (par->var.xres_virtual+7) & ~7;
- if (par->var.xres_virtual < par->var.xres)
- par->var.xres_virtual = par->var.xres;
- if (par->var.yres_virtual < par->var.yres)
- par->var.yres_virtual = par->var.yres;
- par->var.xoffset = var->xoffset;
- par->var.yoffset = var->yoffset;
- par->var.bits_per_pixel = var->bits_per_pixel;
- if (par->var.bits_per_pixel <= 8)
- par->var.bits_per_pixel = 8;
- else if (par->var.bits_per_pixel <= 16)
- par->var.bits_per_pixel = 16;
- else
- par->var.bits_per_pixel = 32;
-#ifndef FBCON_HAS_CFB32
- if (par->var.bits_per_pixel == 32)
- par->var.bits_per_pixel = 16;
-#endif
-#ifndef FBCON_HAS_CFB16
- if (par->var.bits_per_pixel == 16)
- par->var.bits_per_pixel = 8;
-#endif
- par->var.grayscale = var->grayscale;
- par->var.red = var->red;
- par->var.green = var->green;
- par->var.blue = var->blue;
- par->var.transp = var->transp;
- par->var.nonstd = var->nonstd;
- par->var.activate = var->activate;
- par->var.height = var->height;
- par->var.width = var->width;
- if (var->accel_flags & FB_ACCELF_TEXT) {
- par->var.accel_flags = FB_ACCELF_TEXT;
- } else {
- par->var.accel_flags = 0;
- }
- par->var.pixclock = var->pixclock;
- par->var.left_margin = var->left_margin;
- par->var.right_margin = var->right_margin;
- par->var.upper_margin = var->upper_margin;
- par->var.lower_margin = var->lower_margin;
- par->var.hsync_len = var->hsync_len;
- par->var.vsync_len = var->vsync_len;
- par->var.sync = var->sync;
- par->var.vmode = var->vmode;
- DPRINTK("EXIT\n");
- return 0;
-}
-
-/*
- * Fill the `var' structure based on the values in `par' and maybe
- * other values read out of the hardware.
- */
-
-static int virgefb_encode_var(struct fb_var_screeninfo *var,
- struct virgefb_par *par)
-{
- DPRINTK("ENTER\n");
- memset(var, 0, sizeof(struct fb_var_screeninfo)); /* need this ? */
- var->xres = par->var.xres;
- var->yres = par->var.yres;
- var->xres_virtual = par->var.xres_virtual;
- var->yres_virtual = par->var.yres_virtual;
- var->xoffset = par->var.xoffset;
- var->yoffset = par->var.yoffset;
- var->bits_per_pixel = par->var.bits_per_pixel;
- var->grayscale = par->var.grayscale;
- var->red = par->var.red;
- var->green = par->var.green;
- var->blue = par->var.blue;
- var->transp = par->var.transp;
- var->nonstd = par->var.nonstd;
- var->activate = par->var.activate;
- var->height = par->var.height;
- var->width = par->var.width;
- var->accel_flags = par->var.accel_flags;
- var->pixclock = par->var.pixclock;
- var->left_margin = par->var.left_margin;
- var->right_margin = par->var.right_margin;
- var->upper_margin = par->var.upper_margin;
- var->lower_margin = par->var.lower_margin;
- var->hsync_len = par->var.hsync_len;
- var->vsync_len = par->var.vsync_len;
- var->sync = par->var.sync;
- var->vmode = par->var.vmode;
- DPRINTK("EXIT\n");
- return 0;
-}
-
-/*
- * 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.
- */
-
-static int virgefb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
- u_int transp, struct fb_info *info)
-{
- DPRINTK("ENTER\n");
- if (((current_par.var.bits_per_pixel==8) && (regno>255)) ||
- ((current_par.var.bits_per_pixel!=8) && (regno>15))) {
- DPRINTK("EXIT\n");
- return 1;
- }
- if (((current_par.var.bits_per_pixel==8) && (regno<256)) ||
- ((current_par.var.bits_per_pixel!=8) && (regno<16))) {
- virgefb_colour_table [regno][0] = red >> 10;
- virgefb_colour_table [regno][1] = green >> 10;
- virgefb_colour_table [regno][2] = blue >> 10;
- }
-
- switch (current_par.var.bits_per_pixel) {
-#ifdef FBCON_HAS_CFB8
- case 8:
- wb_mmio(VDAC_ADDRESS_W, (unsigned char)regno);
- wb_mmio(VDAC_DATA, ((unsigned char)(red >> 10)));
- wb_mmio(VDAC_DATA, ((unsigned char)(green >> 10)));
- wb_mmio(VDAC_DATA, ((unsigned char)(blue >> 10)));
- break;
-#endif
-#ifdef FBCON_HAS_CFB16
- case 16:
- fbcon_cmap.cfb16[regno] =
- ((red & 0xf800) |
- ((green & 0xfc00) >> 5) |
- ((blue & 0xf800) >> 11));
- break;
-#endif
-#ifdef FBCON_HAS_CFB32
- case 32:
- fbcon_cmap.cfb32[regno] =
- /* transp = 0's or 1's ? */
- (((red & 0xff00) << 8) |
- ((green & 0xff00) >> 0) |
- ((blue & 0xff00) >> 8));
- break;
-#endif
- }
- DPRINTK("EXIT\n");
- return 0;
-}
-
-
-/*
- * Read a single color register and split it into
- * colors/transparent. Return != 0 for invalid regno.
- */
-
-static int virgefb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
- u_int *transp, struct fb_info *info)
-{
- int t;
-
- DPRINTK("ENTER\n");
- if (regno > 255) {
- DPRINTK("EXIT\n");
- return 1;
- }
- if (((current_par.var.bits_per_pixel==8) && (regno<256)) ||
- ((current_par.var.bits_per_pixel!=8) && (regno<16))) {
-
- t = virgefb_colour_table [regno][0];
- *red = (t<<10) | (t<<4) | (t>>2);
- t = virgefb_colour_table [regno][1];
- *green = (t<<10) | (t<<4) | (t>>2);
- t = virgefb_colour_table [regno][2];
- *blue = (t<<10) | (t<<4) | (t>>2);
- }
- *transp = 0;
- DPRINTK("EXIT\n");
- return 0;
-}
-
-
-/*
- * (Un)Blank the screen
- */
-
-static void virgefb_gfx_on_off(int blank)
-{
- DPRINTK("ENTER\n");
- gfx_on_off(blank);
- DPRINTK("EXIT\n");
-}
-
-/*
- * CV3D low-level support
- */
-
-
-static inline void wait_3d_fifo_slots(int n) /* WaitQueue */
-{
- do {
- mb();
- } while (((rl_mmio(MR_SUBSYSTEM_STATUS_R) >> 8) & 0x1f) < (n + 2));
-}
-
-static inline void virgefb_wait_for_idle(void) /* WaitIdle */
-{
- while(!(rl_mmio(MR_SUBSYSTEM_STATUS_R) & 0x2000)) ;
- blit_maybe_busy = 0;
-}
-
- /*
- * BitBLT - Through the Plane
- */
-
-static void virgefb_BitBLT(u_short curx, u_short cury, u_short destx, u_short desty,
- u_short width, u_short height, u_short stride, u_short depth)
-{
- unsigned int blitcmd = S3V_BITBLT | S3V_DRAW | S3V_BLT_COPY;
-
- switch (depth) {
-#ifdef FBCON_HAS_CFB8
- case 8 :
- blitcmd |= S3V_DST_8BPP;
- break;
-#endif
-#ifdef FBCON_HAS_CFB16
- case 16 :
- blitcmd |= S3V_DST_16BPP;
- break;
-#endif
-#ifdef FBCON_HAS_CFB32
- case 32 :
- /* 32 bit uses 2 by 16 bit values, see fbcon_virge32_bmove */
- blitcmd |= S3V_DST_16BPP;
- break;
-#endif
- }
-
- /* Set drawing direction */
- /* -Y, X maj, -X (default) */
- if (curx > destx) {
- blitcmd |= (1 << 25); /* Drawing direction +X */
- } else {
- curx += (width - 1);
- destx += (width - 1);
- }
-
- if (cury > desty) {
- blitcmd |= (1 << 26); /* Drawing direction +Y */
- } else {
- cury += (height - 1);
- desty += (height - 1);
- }
-
- wait_3d_fifo_slots(8); /* wait on fifo slots for 8 writes */
-
- if (blit_maybe_busy)
- virgefb_wait_for_idle();
- blit_maybe_busy = 1;
-
- wl_mmio(BLT_PATTERN_COLOR, 1); /* pattern fb color */
- wl_mmio(BLT_MONO_PATTERN_0, ~0);
- wl_mmio(BLT_MONO_PATTERN_1, ~0);
- wl_mmio(BLT_SIZE_X_Y, ((width << 16) | height));
- wl_mmio(BLT_SRC_X_Y, ((curx << 16) | cury));
- wl_mmio(BLT_DEST_X_Y, ((destx << 16) | desty));
- wl_mmio(BLT_SRC_DEST_STRIDE, (((stride << 16) | stride) /* & 0x0ff80ff8 */)); /* why is this needed now ? */
- wl_mmio(BLT_COMMAND_SET, blitcmd);
-}
-
-/*
- * Rectangle Fill Solid
- */
-
-static void virgefb_RectFill(u_short x, u_short y, u_short width, u_short height,
- u_short color, u_short stride, u_short depth)
-{
- unsigned int blitcmd = S3V_RECTFILL | S3V_DRAW |
- S3V_BLT_CLEAR | S3V_MONO_PAT | (1 << 26) | (1 << 25);
-
- switch (depth) {
-#ifdef FBCON_HAS_CFB8
- case 8 :
- blitcmd |= S3V_DST_8BPP;
- break;
-#endif
-#ifdef FBCON_HAS_CFB16
- case 16 :
- blitcmd |= S3V_DST_16BPP;
- break;
-#endif
-#ifdef FBCON_HAS_CFB32
- case 32 :
- /* 32 bit uses 2 times 16 bit values, see fbcon_virge32_clear */
- blitcmd |= S3V_DST_16BPP;
- break;
-#endif
- }
-
- wait_3d_fifo_slots(5); /* wait on fifo slots for 5 writes */
-
- if (blit_maybe_busy)
- virgefb_wait_for_idle();
- blit_maybe_busy = 1;
-
- wl_mmio(BLT_PATTERN_COLOR, (color & 0xff));
- wl_mmio(BLT_SIZE_X_Y, ((width << 16) | height));
- wl_mmio(BLT_DEST_X_Y, ((x << 16) | y));
- wl_mmio(BLT_SRC_DEST_STRIDE, (((stride << 16) | stride) /* & 0x0ff80ff8 */));
- wl_mmio(BLT_COMMAND_SET, blitcmd);
-}
-
-/*
- * Move cursor to x, y
- */
-
-#if 0
-static void virgefb_move_cursor(u_short x, u_short y)
-{
- DPRINTK("Yuck .... MoveCursor on a 3D\n");
- return 0;
-}
-#endif
-
-/* -------------------- Interfaces to hardware functions -------------------- */
-
-static struct fb_hwswitch virgefb_hw_switch = {
- .init = virge_init,
- .encode_fix = virgefb_encode_fix,
- .decode_var = virgefb_decode_var,
- .encode_var = virgefb_encode_var,
- .getcolreg = virgefb_getcolreg,
- .blank = virgefb_gfx_on_off
-};
-
-
-/* -------------------- Generic routines ------------------------------------ */
-
-
-/*
- * Fill the hardware's `par' structure.
- */
-
-static void virgefb_get_par(struct virgefb_par *par)
-{
- DPRINTK("ENTER\n");
- if (current_par_valid) {
- *par = current_par;
- } else {
- fbhw->decode_var(&virgefb_default, par);
- }
- DPRINTK("EXIT\n");
-}
-
-
-static void virgefb_set_par(struct virgefb_par *par)
-{
- DPRINTK("ENTER\n");
- current_par = *par;
- current_par_valid = 1;
- DPRINTK("EXIT\n");
-}
-
-
-static void virgefb_set_video(struct fb_var_screeninfo *var)
-{
-/* Set clipping rectangle to current screen size */
-
- unsigned int clip;
-
- DPRINTK("ENTER\n");
- wait_3d_fifo_slots(4);
- clip = ((0 << 16) | (var->xres - 1));
- wl_mmio(BLT_CLIP_LEFT_RIGHT, clip);
- clip = ((0 << 16) | (var->yres - 1));
- wl_mmio(BLT_CLIP_TOP_BOTTOM, clip);
- wl_mmio(BLT_SRC_BASE, 0); /* seems we need to clear these two */
- wl_mmio(BLT_DEST_BASE, 0);
-
-/* Load the video mode defined by the 'var' data */
-
- virgefb_load_video_mode(var);
- DPRINTK("EXIT\n");
-}
-
-/*
-Merge these two functions, Geert's suggestion.
-static int virgefb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info);
-static int virgefb_do_fb_set_var(struct fb_var_screeninfo *var, int isactive);
-*/
-
-static int virgefb_do_fb_set_var(struct fb_var_screeninfo *var, int isactive)
-{
- int err, activate;
- struct virgefb_par par;
-
- DPRINTK("ENTER\n");
- if ((err = fbhw->decode_var(var, &par))) {
- DPRINTK("EXIT\n");
- return (err);
- }
-
- activate = var->activate;
- if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW && isactive)
- virgefb_set_par(&par);
- fbhw->encode_var(var, &par);
- var->activate = activate;
- if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW && isactive)
- virgefb_set_video(var);
- DPRINTK("EXIT\n");
- return 0;
-}
-
-
-/*
- * Get the Fixed Part of the Display
- */
-
-static int virgefb_get_fix(struct fb_fix_screeninfo *fix, int con,
- struct fb_info *info)
-{
- struct virgefb_par par;
- int error = 0;
-
- DPRINTK("ENTER\n");
- if (con == -1)
- virgefb_get_par(&par);
- else
- error = fbhw->decode_var(&fb_display[con].var, &par);
-
- if (!error)
- error = fbhw->encode_fix(fix, &par);
- DPRINTK("EXIT\n");
- return(error);
-}
-
-
-/*
- * Get the User Defined Part of the Display
- */
-
-static int virgefb_get_var(struct fb_var_screeninfo *var, int con,
- struct fb_info *info)
-{
- struct virgefb_par par;
- int error = 0;
-
- DPRINTK("ENTER\n");
- if (con == -1) {
- virgefb_get_par(&par);
- error = fbhw->encode_var(var, &par);
- disp.var = *var; /* ++Andre: don't know if this is the right place */
- } else {
- *var = fb_display[con].var;
- }
- DPRINTK("EXIT\n");
- return(error);
-}
-
-static void virgefb_set_disp(int con, struct fb_info *info)
-{
- struct fb_fix_screeninfo fix;
- struct display *display;
-
- DPRINTK("ENTER\n");
- if (con >= 0)
- display = &fb_display[con];
- else
- display = &disp; /* used during initialization */
-
- virgefb_get_fix(&fix, con, info);
- if (con == -1)
- con = 0;
- if(on_zorro2) {
- info->screen_base = (char*)v_ram;
- } else {
- switch (display->var.bits_per_pixel) {
-#ifdef FBCON_HAS_CFB8
- case 8:
- info->screen_base = (char*)(v_ram + CYBMEM_OFFSET_8);
- break;
-#endif
-#ifdef FBCON_HAS_CFB16
- case 16:
- info->screen_base = (char*)(v_ram + CYBMEM_OFFSET_16);
- break;
-#endif
-#ifdef FBCON_HAS_CFB32
- case 32:
- info->screen_base = (char*)(v_ram + CYBMEM_OFFSET_32);
- break;
-#endif
- }
- }
- display->visual = fix.visual;
- display->type = fix.type;
- display->type_aux = fix.type_aux;
- display->ypanstep = fix.ypanstep;
- display->ywrapstep = fix.ywrapstep;
- display->can_soft_blank = 1;
- display->inverse = virgefb_inverse;
- display->line_length = display->var.xres_virtual*
- display->var.bits_per_pixel/8;
-
- switch (display->var.bits_per_pixel) {
-#ifdef FBCON_HAS_CFB8
- case 8:
- if (display->var.accel_flags & FB_ACCELF_TEXT) {
- display->dispsw = &fbcon_virge8;
-#warning FIXME: We should reinit the graphics engine here
- } else
- display->dispsw = &fbcon_cfb8;
- break;
-#endif
-#ifdef FBCON_HAS_CFB16
- case 16:
- if (display->var.accel_flags & FB_ACCELF_TEXT) {
- display->dispsw = &fbcon_virge16;
- } else
- display->dispsw = &fbcon_cfb16;
- display->dispsw_data = &fbcon_cmap.cfb16;
- break;
-#endif
-#ifdef FBCON_HAS_CFB32
- case 32:
- if (display->var.accel_flags & FB_ACCELF_TEXT) {
- display->dispsw = &fbcon_virge32;
- } else
- display->dispsw = &fbcon_cfb32;
- display->dispsw_data = &fbcon_cmap.cfb32;
- break;
-#endif
- default:
- display->dispsw = &fbcon_dummy;
- break;
- }
- DPRINTK("EXIT v_ram virt = 0x%8.8lx\n",(unsigned long)display->screen_base);
-}
-
-
-/*
- * Set the User Defined Part of the Display
- */
-
-static int virgefb_set_var(struct fb_var_screeninfo *var, int con,
- struct fb_info *info)
-{
- int err, oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldaccel;
-
- DPRINTK("ENTER\n");
-
- if ((err = virgefb_do_fb_set_var(var, con == info->currcon))) {
- DPRINTK("EXIT\n");
- return(err);
- }
- if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
- oldxres = fb_display[con].var.xres;
- oldyres = fb_display[con].var.yres;
- oldvxres = fb_display[con].var.xres_virtual;
- oldvyres = fb_display[con].var.yres_virtual;
- oldbpp = fb_display[con].var.bits_per_pixel;
- oldaccel = fb_display[con].var.accel_flags;
- fb_display[con].var = *var;
- if (oldxres != var->xres || oldyres != var->yres ||
- oldvxres != var->xres_virtual ||
- oldvyres != var->yres_virtual ||
- oldbpp != var->bits_per_pixel ||
- oldaccel != var->accel_flags) {
- virgefb_set_disp(con, info);
- if (fb_info.changevar)
- (*fb_info.changevar)(con);
- fb_alloc_cmap(&fb_display[con].cmap, 0, 0);
- do_install_cmap(con, info);
- }
- }
- var->activate = 0;
- DPRINTK("EXIT\n");
- return 0;
-}
-
-
-/*
- * Get the Colormap
- */
-
-static int virgefb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
- struct fb_info *info)
-{
- DPRINTK("ENTER\n");
- if (con == info->currcon) { /* current console? */
- DPRINTK("EXIT - console is current console, fb_get_cmap\n");
- return(fb_get_cmap(cmap, kspc, fbhw->getcolreg, info));
- } else if (fb_display[con].cmap.len) { /* non default colormap? */
- DPRINTK("Use console cmap\n");
- fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
- } else {
- DPRINTK("Use default cmap\n");
- fb_copy_cmap(fb_default_cmap(fb_display[con].var.bits_per_pixel==8 ? 256 : 16),
- cmap, kspc ? 0 : 2);
- }
- DPRINTK("EXIT\n");
- return 0;
-}
-
-static struct fb_ops virgefb_ops = {
- .owner = THIS_MODULE,
- .fb_get_fix = virgefb_get_fix,
- .fb_get_var = virgefb_get_var,
- .fb_set_var = virgefb_set_var,
- .fb_get_cmap = virgefb_get_cmap,
- .fb_set_cmap = gen_set_cmap,
- .fb_setcolreg = virgefb_setcolreg,
- .fb_blank = virgefb_blank,
-};
-
-int __init virgefb_setup(char *options)
-{
- char *this_opt;
- fb_info.fontname[0] = '\0';
-
- DPRINTK("ENTER\n");
- if (!options || !*options) {
- DPRINTK("EXIT\n");
- return 0;
- }
-
- while ((this_opt = strsep(&options, ",")) != NULL) {
- if (!*this_opt)
- continue;
- if (!strcmp(this_opt, "inverse")) {
- virgefb_inverse = 1;
- fb_invert_cmaps();
- } else if (!strncmp(this_opt, "font:", 5))
- strcpy(fb_info.fontname, this_opt+5);
-#ifdef FBCON_HAS_CFB8
- else if (!strcmp (this_opt, "virge8")){
- virgefb_default = virgefb_predefined[VIRGE8_DEFMODE].var;
- }
-#endif
-#ifdef FBCON_HAS_CFB16
- else if (!strcmp (this_opt, "virge16")){
- virgefb_default = virgefb_predefined[VIRGE16_DEFMODE].var;
- }
-#endif
-#ifdef FBCON_HAS_CFB32
- else if (!strcmp (this_opt, "virge32")){
- virgefb_default = virgefb_predefined[VIRGE32_DEFMODE].var;
- }
-#endif
- else
- virgefb_get_video_mode(this_opt);
- }
-
- printk(KERN_INFO "mode : xres=%d, yres=%d, bpp=%d\n", virgefb_default.xres,
- virgefb_default.yres, virgefb_default.bits_per_pixel);
- DPRINTK("EXIT\n");
- return 0;
-}
-
-
-/*
- * Get a Video Mode
- */
-
-static int __init virgefb_get_video_mode(const char *name)
-{
- int i;
-
- DPRINTK("ENTER\n");
- for (i = 0; i < NUM_TOTAL_MODES; i++) {
- if (!strcmp(name, virgefb_predefined[i].name)) {
- virgefb_default = virgefb_predefined[i].var;
- DPRINTK("EXIT\n");
- return(i);
- }
- }
- /* ++Andre: set virgefb default mode */
-
-/* prefer 16 bit depth, 8 if no 16, if no 8 or 16 use 32 */
-
-#ifdef FBCON_HAS_CFB32
- virgefb_default = virgefb_predefined[VIRGE32_DEFMODE].var;
-#endif
-#ifdef FBCON_HAS_CFB8
- virgefb_default = virgefb_predefined[VIRGE8_DEFMODE].var;
-#endif
-#ifdef FBCON_HAS_CFB16
- virgefb_default = virgefb_predefined[VIRGE16_DEFMODE].var;
-#endif
- DPRINTK("EXIT\n");
- return 0;
-}
-
-/*
- * Initialization
- */
-
-int __init virgefb_init(void)
-{
- struct virgefb_par par;
- unsigned long board_addr, board_size;
- struct zorro_dev *z = NULL;
-
- DPRINTK("ENTER\n");
-
- z = zorro_find_device(ZORRO_PROD_PHASE5_CYBERVISION64_3D, NULL);
- if (!z)
- return -ENODEV;
-
- board_addr = z->resource.start;
- if (board_addr < 0x01000000) {
-
- /* board running in Z2 space. This includes the video memory
- as well as the S3 register set */
-
- on_zorro2 = 1;
- board_size = 0x00400000;
-
- if (!request_mem_region(board_addr, board_size, "S3 ViRGE"))
- return -ENOMEM;
-
- v_ram_phys = board_addr;
- v_ram = ZTWO_VADDR(v_ram_phys);
- mmio_regs_phys = (unsigned long)(board_addr + 0x003c0000);
- vgaio_regs = (unsigned char *) ZTWO_VADDR(board_addr + 0x003c0000);
- mmio_regs = (unsigned char *)ZTWO_VADDR(mmio_regs_phys);
- vcode_switch_base = (unsigned long) ZTWO_VADDR(board_addr + 0x003a0000);
- printk(KERN_INFO "CV3D detected running in Z2 mode.\n");
-
- } else {
-
- /* board running in Z3 space. Separate video memory (3 apertures)
- and S3 register set */
-
- on_zorro2 = 0;
- board_size = 0x01000000;
-
- if (!request_mem_region(board_addr, board_size, "S3 ViRGE"))
- return -ENOMEM;
-
- v_ram_phys = board_addr + 0x04000000;
- v_ram = (unsigned long)ioremap(v_ram_phys, 0x01000000);
- mmio_regs_phys = board_addr + 0x05000000;
- vgaio_regs = (unsigned char *)ioremap(board_addr +0x0c000000, 0x00100000); /* includes PCI regs */
- mmio_regs = ioremap(mmio_regs_phys, 0x00010000);
- vcode_switch_base = (unsigned long)ioremap(board_addr + 0x08000000, 0x1000);
- printk(KERN_INFO "CV3D detected running in Z3 mode\n");
- }
-
-#if defined (VIRGEFBDEBUG)
- DPRINTK("board_addr : 0x%8.8lx\n",board_addr);
- DPRINTK("board_size : 0x%8.8lx\n",board_size);
- DPRINTK("mmio_regs_phy : 0x%8.8lx\n",mmio_regs_phys);
- DPRINTK("v_ram_phys : 0x%8.8lx\n",v_ram_phys);
- DPRINTK("vgaio_regs : 0x%8.8lx\n",(unsigned long)vgaio_regs);
- DPRINTK("mmio_regs : 0x%8.8lx\n",(unsigned long)mmio_regs);
- DPRINTK("v_ram : 0x%8.8lx\n",v_ram);
- DPRINTK("vcode sw base : 0x%8.8lx\n",vcode_switch_base);
-#endif
- fbhw = &virgefb_hw_switch;
- strcpy(fb_info.modename, virgefb_name);
- fb_info.changevar = NULL;
- fb_info.fbops = &virgefb_ops;
- fb_info.disp = &disp;
- fb_info.currcon = -1;
- fb_info.switch_con = &virgefb_switch;
- fb_info.updatevar = &virgefb_updatevar;
- fb_info.flags = FBINFO_FLAG_DEFAULT;
- fbhw->init();
- fbhw->decode_var(&virgefb_default, &par);
- fbhw->encode_var(&virgefb_default, &par);
- virgefb_do_fb_set_var(&virgefb_default, 1);
- virgefb_get_var(&fb_display[0].var, -1, &fb_info);
- virgefb_set_disp(-1, &fb_info);
- do_install_cmap(0, &fb_info);
-
- if (register_framebuffer(&fb_info) < 0) {
- #warning release resources
- printk(KERN_ERR "virgefb.c: register_framebuffer failed\n");
- DPRINTK("EXIT\n");
- goto out_unmap;
- }
-
- printk(KERN_INFO "fb%d: %s frame buffer device, using %ldK of video memory\n",
- fb_info.node, fb_info.modename, v_ram_size>>10);
-
- /* TODO: This driver cannot be unloaded yet */
-
- DPRINTK("EXIT\n");
- return 0;
-
-out_unmap:
- if (board_addr >= 0x01000000) {
- if (v_ram)
- iounmap((void*)v_ram);
- if (vgaio_regs)
- iounmap(vgaio_regs);
- if (mmio_regs)
- iounmap(mmio_regs);
- if (vcode_switch_base)
- iounmap((void*)vcode_switch_base);
- v_ram = vcode_switch_base = 0;
- vgaio_regs = mmio_regs = NULL;
- }
- return -EINVAL;
-}
-
-
-static int virgefb_switch(int con, struct fb_info *info)
-{
- DPRINTK("ENTER\n");
- /* Do we have to save the colormap? */
- if (fb_display[info->currcon].cmap.len)
- fb_get_cmap(&fb_display[info->currcon].cmap, 1,
- fbhw->getcolreg, info);
- virgefb_do_fb_set_var(&fb_display[con].var, 1);
- info->currcon = con;
- /* Install new colormap */
- do_install_cmap(con, info);
- DPRINTK("EXIT\n");
- return 0;
-}
-
-
-/*
- * Update the `var' structure (called by fbcon.c)
- *
- * This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'.
- * Since it's called by a kernel driver, no range checking is done.
- */
-
-static int virgefb_updatevar(int con, struct fb_info *info)
-{
- DPRINTK("ENTER\n");
- return 0;
- DPRINTK("EXIT\n");
-}
-
-/*
- * Blank the display.
- */
-
-static int virgefb_blank(int blank, struct fb_info *info)
-{
- DPRINTK("ENTER\n");
- fbhw->blank(blank);
- DPRINTK("EXIT\n");
- return 0;
-}
-
-
-/*
- * Text console acceleration
- */
-
-#ifdef FBCON_HAS_CFB8
-static void fbcon_virge8_bmove(struct display *p, int sy, int sx, int dy,
- int dx, int height, int width)
-{
- sx *= 8; dx *= 8; width *= 8;
- virgefb_BitBLT((u_short)sx, (u_short)(sy*fontheight(p)), (u_short)dx,
- (u_short)(dy*fontheight(p)), (u_short)width,
- (u_short)(height*fontheight(p)), (u_short)p->next_line, 8);
-}
-
-static void fbcon_virge8_clear(struct vc_data *conp, struct display *p, int sy,
- int sx, int height, int width)
-{
- unsigned char bg;
-
- sx *= 8; width *= 8;
- bg = attr_bgcol_ec(p,conp);
- virgefb_RectFill((u_short)sx, (u_short)(sy*fontheight(p)),
- (u_short)width, (u_short)(height*fontheight(p)),
- (u_short)bg, (u_short)p->next_line, 8);
-}
-
-static void fbcon_virge8_putc(struct vc_data *conp, struct display *p, int c, int yy,
- int xx)
-{
- if (blit_maybe_busy)
- virgefb_wait_for_idle();
- fbcon_cfb8_putc(conp, p, c, yy, xx);
-}
-
-static void fbcon_virge8_putcs(struct vc_data *conp, struct display *p,
- const unsigned short *s, int count, int yy, int xx)
-{
- if (blit_maybe_busy)
- virgefb_wait_for_idle();
- fbcon_cfb8_putcs(conp, p, s, count, yy, xx);
-}
-
-static void fbcon_virge8_revc(struct display *p, int xx, int yy)
-{
- if (blit_maybe_busy)
- virgefb_wait_for_idle();
- fbcon_cfb8_revc(p, xx, yy);
-}
-
-static void fbcon_virge8_clear_margins(struct vc_data *conp, struct display *p,
- int bottom_only)
-{
- if (blit_maybe_busy)
- virgefb_wait_for_idle();
- fbcon_cfb8_clear_margins(conp, p, bottom_only);
-}
-
-static struct display_switch fbcon_virge8 = {
- .setup = fbcon_cfb8_setup,
- .bmove = fbcon_virge8_bmove,
- .clear = fbcon_virge8_clear,
- .putc = fbcon_virge8_putc,
- .putcs = fbcon_virge8_putcs,
- .revc = fbcon_virge8_revc,
- .clear_margins = fbcon_virge8_clear_margins,
- .fontwidthmask = FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
-};
-#endif
-
-#ifdef FBCON_HAS_CFB16
-static void fbcon_virge16_bmove(struct display *p, int sy, int sx, int dy,
- int dx, int height, int width)
-{
- sx *= 8; dx *= 8; width *= 8;
- virgefb_BitBLT((u_short)sx, (u_short)(sy*fontheight(p)), (u_short)dx,
- (u_short)(dy*fontheight(p)), (u_short)width,
- (u_short)(height*fontheight(p)), (u_short)p->next_line, 16);
-}
-
-static void fbcon_virge16_clear(struct vc_data *conp, struct display *p, int sy,
- int sx, int height, int width)
-{
- unsigned char bg;
-
- sx *= 8; width *= 8;
- bg = attr_bgcol_ec(p,conp);
- virgefb_RectFill((u_short)sx, (u_short)(sy*fontheight(p)),
- (u_short)width, (u_short)(height*fontheight(p)),
- (u_short)bg, (u_short)p->next_line, 16);
-}
-
-static void fbcon_virge16_putc(struct vc_data *conp, struct display *p, int c, int yy,
- int xx)
-{
- if (blit_maybe_busy)
- virgefb_wait_for_idle();
- fbcon_cfb16_putc(conp, p, c, yy, xx);
-}
-
-static void fbcon_virge16_putcs(struct vc_data *conp, struct display *p,
- const unsigned short *s, int count, int yy, int xx)
-{
- if (blit_maybe_busy)
- virgefb_wait_for_idle();
- fbcon_cfb16_putcs(conp, p, s, count, yy, xx);
-}
-
-static void fbcon_virge16_revc(struct display *p, int xx, int yy)
-{
- if (blit_maybe_busy)
- virgefb_wait_for_idle();
- fbcon_cfb16_revc(p, xx, yy);
-}
-
-static void fbcon_virge16_clear_margins(struct vc_data *conp, struct display *p,
- int bottom_only)
-{
- if (blit_maybe_busy)
- virgefb_wait_for_idle();
- fbcon_cfb16_clear_margins(conp, p, bottom_only);
-}
-
-static struct display_switch fbcon_virge16 = {
- .setup = fbcon_cfb16_setup,
- .bmove = fbcon_virge16_bmove,
- .clear = fbcon_virge16_clear,
- .putc = fbcon_virge16_putc,
- .putcs = fbcon_virge16_putcs,
- .revc = fbcon_virge16_revc,
- .clear_margins = fbcon_virge16_clear_margins,
- .fontwidthmask = FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
-};
-#endif
-
-#ifdef FBCON_HAS_CFB32
-static void fbcon_virge32_bmove(struct display *p, int sy, int sx, int dy,
- int dx, int height, int width)
-{
- sx *= 16; dx *= 16; width *= 16; /* doubled these values to do 32 bit blit */
- virgefb_BitBLT((u_short)sx, (u_short)(sy*fontheight(p)), (u_short)dx,
- (u_short)(dy*fontheight(p)), (u_short)width,
- (u_short)(height*fontheight(p)), (u_short)p->next_line, 16);
-}
-
-static void fbcon_virge32_clear(struct vc_data *conp, struct display *p, int sy,
- int sx, int height, int width)
-{
- unsigned char bg;
-
- sx *= 16; width *= 16; /* doubled these values to do 32 bit blit */
- bg = attr_bgcol_ec(p,conp);
- virgefb_RectFill((u_short)sx, (u_short)(sy*fontheight(p)),
- (u_short)width, (u_short)(height*fontheight(p)),
- (u_short)bg, (u_short)p->next_line, 16);
-}
-
-static void fbcon_virge32_putc(struct vc_data *conp, struct display *p, int c, int yy,
- int xx)
-{
- if (blit_maybe_busy)
- virgefb_wait_for_idle();
- fbcon_cfb32_putc(conp, p, c, yy, xx);
-}
-
-static void fbcon_virge32_putcs(struct vc_data *conp, struct display *p,
- const unsigned short *s, int count, int yy, int xx)
-{
- if (blit_maybe_busy)
- virgefb_wait_for_idle();
- fbcon_cfb32_putcs(conp, p, s, count, yy, xx);
-}
-
-static void fbcon_virge32_revc(struct display *p, int xx, int yy)
-{
- if (blit_maybe_busy)
- virgefb_wait_for_idle();
- fbcon_cfb32_revc(p, xx, yy);
-}
-
-static void fbcon_virge32_clear_margins(struct vc_data *conp, struct display *p,
- int bottom_only)
-{
- if (blit_maybe_busy)
- virgefb_wait_for_idle();
- fbcon_cfb32_clear_margins(conp, p, bottom_only);
-}
-
-static struct display_switch fbcon_virge32 = {
- .setup = fbcon_cfb32_setup,
- .bmove = fbcon_virge32_bmove,
- .clear = fbcon_virge32_clear,
- .putc = fbcon_virge32_putc,
- .putcs = fbcon_virge32_putcs,
- .revc = fbcon_virge32_revc,
- .clear_margins = fbcon_virge32_clear_margins,
- .fontwidthmask = FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
-};
-#endif
-
-#ifdef MODULE
-MODULE_LICENSE("GPL");
-
-int init_module(void)
-{
- return virgefb_init();
-}
-#endif /* MODULE */
-
-static int cv3d_has_4mb(void)
-{
- /* cyberfb version didn't work, neither does this (not reliably)
- forced to return 4MB */
-#if 0
- volatile unsigned long *t0, *t2;
-#endif
- DPRINTK("ENTER\n");
-#if 0
- /* write patterns in memory and test if they can be read */
- t0 = (volatile unsigned long *)v_ram;
- t2 = (volatile unsigned long *)(v_ram + 0x00200000);
- *t0 = 0x87654321;
- *t2 = 0x12345678;
-
- if (*t0 != 0x87654321) {
- /* read of first location failed */
- DPRINTK("EXIT - 0MB !\n");
- return 0;
- }
-
- if (*t2 == 0x87654321) {
- /* should read 0x12345678 if 4MB */
- DPRINTK("EXIT - 2MB(a) \n");
- return 0;
- }
-
- if (*t2 != 0x12345678) {
- /* upper 2MB read back match failed */
- DPRINTK("EXIT - 2MB(b)\n");
- return 0;
- }
-
- /* may have 4MB */
-
- *t2 = 0xAAAAAAAA;
-
- if(*t2 != 0xAAAAAAAA) {
- /* upper 2MB read back match failed */
- DPRINTK("EXIT - 2MB(c)\n");
- return 0;
- }
-
- *t2 = 0x55555555;
-
- if(*t2 != 0x55555555) {
- /* upper 2MB read back match failed */
- DPRINTK("EXIT - 2MB(d)\n");
- return 0;
- }
-
-#endif
- DPRINTK("EXIT - 4MB\n");
- return 1;
-}
-
-
-/*
- * Computes M, N, and R pll params for freq arg.
- * Returns 16 bits - hi 0MMMMMM lo 0RRNNNNN
- */
-
-#define REFCLOCK 14318000
-
-static unsigned short virgefb_compute_clock(unsigned long freq)
-{
-
- unsigned char m, n, r, rpwr;
- unsigned long diff, ftry, save = ~0UL;
- unsigned short mnr;
-
- DPRINTK("ENTER\n");
-
- for (r = 0, rpwr = 1 ; r < 4 ; r++, rpwr *= 2) {
- if ((135000000 <= (rpwr * freq)) && ((rpwr * freq) <= 270000000)) {
- for (n = 1 ; n < 32 ; n++) {
- m = ((freq * (n + 2) * rpwr)/REFCLOCK) - 2;
- if (m == 0 || m >127)
- break;
- ftry = ((REFCLOCK / (n + 2)) * (m + 2)) / rpwr;
- if (ftry > freq)
- diff = ftry - freq;
- else
- diff = freq - ftry;
- if (diff < save) {
- save = diff;
- mnr = (m << 8) | (r<<5) | (n & 0x7f);
- }
- }
- }
- }
- if (save == ~0UL)
- printk("Can't compute clock PLL values for %ld Hz clock\n", freq);
- DPRINTK("EXIT\n");
- return(mnr);
-}
-
-static void virgefb_load_video_mode(struct fb_var_screeninfo *video_mode)
-{
- unsigned char lace, dblscan, tmp;
- unsigned short mnr;
- unsigned short HT, HDE, HBS, HBW, HSS, HSW;
- unsigned short VT, VDE, VBS, VBW, VSS, VSW;
- unsigned short SCO;
- int cr11;
- int cr67;
- int hmul;
- int xres, xres_virtual, hfront, hsync, hback;
- int yres, vfront, vsync, vback;
- int bpp;
- int i;
- long freq;
-
- DPRINTK("ENTER : %dx%d-%d\n",video_mode->xres, video_mode->yres,
- video_mode->bits_per_pixel);
-
- bpp = video_mode->bits_per_pixel;
- xres = video_mode->xres;
- xres_virtual = video_mode->xres_virtual;
- hfront = video_mode->right_margin;
- hsync = video_mode->hsync_len;
- hback = video_mode->left_margin;
-
- lace = 0;
- dblscan = 0;
-
- if (video_mode->vmode & FB_VMODE_DOUBLE) {
- yres = video_mode->yres * 2;
- vfront = video_mode->lower_margin * 2;
- vsync = video_mode->vsync_len * 2;
- vback = video_mode->upper_margin * 2;
- dblscan = 1;
- } else if (video_mode->vmode & FB_VMODE_INTERLACED) {
- yres = (video_mode->yres + 1) / 2;
- vfront = (video_mode->lower_margin + 1) / 2;
- vsync = (video_mode->vsync_len + 1) / 2;
- vback = (video_mode->upper_margin + 1) / 2;
- lace = 1;
- } else {
- yres = video_mode->yres;
- vfront = video_mode->lower_margin;
- vsync = video_mode->vsync_len;
- vback = video_mode->upper_margin;
- }
-
- switch (bpp) {
- case 8:
- video_mode->red.offset = 0;
- video_mode->green.offset = 0;
- video_mode->blue.offset = 0;
- video_mode->transp.offset = 0;
- video_mode->red.length = 8;
- video_mode->green.length = 8;
- video_mode->blue.length = 8;
- video_mode->transp.length = 0;
- hmul = 1;
- cr67 = 0x00;
- SCO = xres_virtual / 8;
- break;
- case 16:
- video_mode->red.offset = 11;
- video_mode->green.offset = 5;
- video_mode->blue.offset = 0;
- video_mode->transp.offset = 0;
- video_mode->red.length = 5;
- video_mode->green.length = 6;
- video_mode->blue.length = 5;
- video_mode->transp.length = 0;
- hmul = 2;
- cr67 = 0x50;
- SCO = xres_virtual / 4;
- break;
- case 32:
- video_mode->red.offset = 16;
- video_mode->green.offset = 8;
- video_mode->blue.offset = 0;
- video_mode->transp.offset = 24;
- video_mode->red.length = 8;
- video_mode->green.length = 8;
- video_mode->blue.length = 8;
- video_mode->transp.length = 8;
- hmul = 1;
- cr67 = 0xd0;
- SCO = xres_virtual / 2;
- break;
- }
-
- HT = (((xres + hfront + hsync + hback) / 8) * hmul) - 5;
- HDE = ((xres / 8) * hmul) - 1;
- HBS = (xres / 8) * hmul;
- HSS = ((xres + hfront) / 8) * hmul;
- HSW = (hsync / 8) * hmul;
- HBW = (((hfront + hsync + hback) / 8) * hmul) - 2;
-
- VT = yres + vfront + vsync + vback - 2;
- VDE = yres - 1;
- VBS = yres - 1;
- VSS = yres + vfront;
- VSW = vsync;
- VBW = vfront + vsync + vback - 2;
-
-#ifdef VIRGEFBDEBUG
- DPRINTK("HDE : 0x%4.4x, %4.4d\n", HDE, HDE);
- DPRINTK("HBS : 0x%4.4x, %4.4d\n", HBS, HBS);
- DPRINTK("HSS : 0x%4.4x, %4.4d\n", HSS, HSS);
- DPRINTK("HSW : 0x%4.4x, %4.4d\n", HSW, HSW);
- DPRINTK("HBW : 0x%4.4x, %4.4d\n", HBW, HBW);
- DPRINTK("HSS + HSW : 0x%4.4x, %4.4d\n", HSS+HSW, HSS+HSW);
- DPRINTK("HBS + HBW : 0x%4.4x, %4.4d\n", HBS+HBW, HBS+HBW);
- DPRINTK("HT : 0x%4.4x, %4.4d\n", HT, HT);
- DPRINTK("VDE : 0x%4.4x, %4.4d\n", VDE, VDE);
- DPRINTK("VBS : 0x%4.4x, %4.4d\n", VBS, VBS);
- DPRINTK("VSS : 0x%4.4x, %4.4d\n", VSS, VSS);
- DPRINTK("VSW : 0x%4.4x, %4.4d\n", VSW, VSW);
- DPRINTK("VBW : 0x%4.4x, %4.4d\n", VBW, VBW);
- DPRINTK("VT : 0x%4.4x, %4.4d\n", VT, VT);
-#endif
-
-/* turn gfx off, don't mess up the display */
-
- gfx_on_off(1);
-
-/* H and V sync polarity */
-
- tmp = rb_mmio(GREG_MISC_OUTPUT_R) & 0x2f; /* colour, ram enable, clk sr12/s13 sel */
- if (!(video_mode->sync & FB_SYNC_HOR_HIGH_ACT))
- tmp |= 0x40; /* neg H sync polarity */
- if (!(video_mode->sync & FB_SYNC_VERT_HIGH_ACT))
- tmp |= 0x80; /* neg V sync polarity */
- tmp |= 0x0c; /* clk from sr12/sr13 */
- wb_mmio(GREG_MISC_OUTPUT_W, tmp);
-
-/* clocks */
-
- wseq(SEQ_ID_BUS_REQ_CNTL, 0xc0); /* 2 clk mem wr and /RAS1 */
- wseq(SEQ_ID_CLKSYN_CNTL_2, 0x80); /* b7 is 2 mem clk wr */
- mnr = virgefb_compute_clock(MEMCLOCK);
- DPRINTK("mem clock %d, m %d, n %d, r %d.\n", MEMCLOCK, ((mnr>>8)&0x7f), (mnr&0x1f), ((mnr >> 5)&0x03));
- wseq(SEQ_ID_MCLK_LO, (mnr & 0x7f));
- wseq(SEQ_ID_MCLK_HI, ((mnr & 0x7f00) >> 8));
- freq = (1000000000 / video_mode->pixclock) * 1000; /* pixclock is in ps ... convert to Hz */
- mnr = virgefb_compute_clock(freq);
- DPRINTK("dot clock %ld, m %d, n %d, r %d.\n", freq, ((mnr>>8)&0x7f), (mnr&0x1f), ((mnr>>5)&0x03));
- wseq(SEQ_ID_DCLK_LO, (mnr & 0x7f));
- wseq(SEQ_ID_DCLK_HI, ((mnr & 0x7f00) >> 8));
- wseq(SEQ_ID_CLKSYN_CNTL_2, 0xa0);
- wseq(SEQ_ID_CLKSYN_CNTL_2, 0x80);
- udelay(100);
-
-/* load display parameters into board */
-
- /* not sure about sync and blanking extensions bits in cr5d and cr5 */
-
- wcrt(CRT_ID_EXT_HOR_OVF, /* 0x5d */
- ((HT & 0x100) ? 0x01 : 0x00) |
- ((HDE & 0x100) ? 0x02 : 0x00) |
- ((HBS & 0x100) ? 0x04 : 0x00) |
- /* (((HBS + HBW) & 0x40) ? 0x08 : 0x00) | */
- ((HSS & 0x100) ? 0x10 : 0x00) |
- /* (((HSS + HSW) & 0x20) ? 0x20 : 0x00) | */
- ((HSW >= 0x20) ? 0x20 : 0x00) |
- (((HT-5) & 0x100) ? 0x40 : 0x00));
-
- wcrt(CRT_ID_EXT_VER_OVF, /* 0x5e */
- ((VT & 0x400) ? 0x01 : 0x00) |
- ((VDE & 0x400) ? 0x02 : 0x00) |
- ((VBS & 0x400) ? 0x04 : 0x00) |
- ((VSS & 0x400) ? 0x10 : 0x00) |
- 0x40); /* line compare */
-
- wcrt(CRT_ID_START_VER_RETR, VSS);
- cr11 = rcrt(CRT_ID_END_VER_RETR) | 0x20; /* vert interrupt flag */
- wcrt(CRT_ID_END_VER_RETR, ((cr11 & 0x20) | ((VSS + VSW) & 0x0f))); /* keeps vert irq enable state, also has unlock bit cr0 to 7 */
- wcrt(CRT_ID_VER_DISP_ENA_END, VDE);
- wcrt(CRT_ID_START_VER_BLANK, VBS);
- wcrt(CRT_ID_END_VER_BLANK, VBS + VBW); /* might be +/- 1 out */
- wcrt(CRT_ID_HOR_TOTAL, HT);
- wcrt(CRT_ID_DISPLAY_FIFO, HT - 5);
- wcrt(CRT_ID_BACKWAD_COMP_3, 0x10); /* enable display fifo */
- wcrt(CRT_ID_HOR_DISP_ENA_END, HDE);
- wcrt(CRT_ID_START_HOR_BLANK , HBS);
- wcrt(CRT_ID_END_HOR_BLANK, (HBS + HBW) & 0x1f);
- wcrt(CRT_ID_START_HOR_RETR, HSS);
- wcrt(CRT_ID_END_HOR_RETR, /* cr5 */
- ((HSS + HSW) & 0x1f) |
- (((HBS + HBW) & 0x20) ? 0x80 : 0x00));
- wcrt(CRT_ID_VER_TOTAL, VT);
- wcrt(CRT_ID_OVERFLOW,
- ((VT & 0x100) ? 0x01 : 0x00) |
- ((VDE & 0x100) ? 0x02 : 0x00) |
- ((VSS & 0x100) ? 0x04 : 0x00) |
- ((VBS & 0x100) ? 0x08 : 0x00) |
- 0x10 |
- ((VT & 0x200) ? 0x20 : 0x00) |
- ((VDE & 0x200) ? 0x40 : 0x00) |
- ((VSS & 0x200) ? 0x80 : 0x00));
- wcrt(CRT_ID_MAX_SCAN_LINE,
- (dblscan ? 0x80 : 0x00) |
- 0x40 |
- ((VBS & 0x200) ? 0x20 : 0x00));
- wcrt(CRT_ID_LINE_COMPARE, 0xff);
- wcrt(CRT_ID_LACE_RETR_START, HT / 2); /* (HT-5)/2 ? */
- wcrt(CRT_ID_LACE_CONTROL, (lace ? 0x20 : 0x00));
-
- wcrt(CRT_ID_SCREEN_OFFSET, SCO);
- wcrt(CRT_ID_EXT_SYS_CNTL_2, (SCO >> 4) & 0x30 );
-
- /* wait for vert sync before cr67 update */
-
- for (i=0; i < 10000; i++) {
- udelay(10);
- mb();
- if (rb_mmio(GREG_INPUT_STATUS1_R) & 0x08)
- break;
- }
-
- wl_mmio(0x8200, 0x0000c000); /* fifo control (0x00110400 ?) */
- wcrt(CRT_ID_EXT_MISC_CNTL_2, cr67);
-
-/* enable video */
-
- tmp = rb_mmio(ACT_ADDRESS_RESET);
- wb_mmio(ACT_ADDRESS_W, ((bpp == 8) ? 0x20 : 0x00)); /* set b5, ENB PLT in attr idx reg) */
- tmp = rb_mmio(ACT_ADDRESS_RESET);
-
-/* turn gfx on again */
-
- gfx_on_off(0);
-
-/* pass-through */
-
- SetVSwitch(1); /* cv3d */
-
- DUMP;
- DPRINTK("EXIT\n");
-}
-
-static inline void gfx_on_off(int toggle)
-{
- unsigned char tmp;
-
- DPRINTK("ENTER gfx %s\n", (toggle ? "off" : "on"));
-
- toggle = (toggle & 0x01) << 5;
- tmp = rseq(SEQ_ID_CLOCKING_MODE) & (~(0x01 << 5));
- wseq(SEQ_ID_CLOCKING_MODE, tmp | toggle);
-
- DPRINTK("EXIT\n");
-}
-
-#if defined (VIRGEFBDUMP)
-
-/*
- * Dump board registers
- */
-
-static void cv64_dump(void)
-{
- int i;
- u8 c, b;
- u16 w;
- u32 l;
-
- /* crt, seq, gfx and atr regs */
-
- SelectMMIO;
-
- printk("\n");
- for (i = 0; i <= 0x6f; i++) {
- wb_mmio(CRT_ADDRESS, i);
- printk("crt idx : 0x%2.2x : 0x%2.2x\n", i, rb_mmio(CRT_ADDRESS_R));
- }
- for (i = 0; i <= 0x1c; i++) {
- wb_mmio(SEQ_ADDRESS, i);
- printk("seq idx : 0x%2.2x : 0x%2.2x\n", i, rb_mmio(SEQ_ADDRESS_R));
- }
- for (i = 0; i <= 8; i++) {
- wb_mmio(GCT_ADDRESS, i);
- printk("gfx idx : 0x%2.2x : 0x%2.2x\n", i, rb_mmio(GCT_ADDRESS_R));
- }
- for (i = 0; i <= 0x14; i++) {
- c = rb_mmio(ACT_ADDRESS_RESET);
- wb_mmio(ACT_ADDRESS_W, i);
- printk("atr idx : 0x%2.2x : 0x%2.2x\n", i, rb_mmio(ACT_ADDRESS_R));
- }
-
- /* re-enable video access to palette */
-
- c = rb_mmio(ACT_ADDRESS_RESET);
- udelay(10);
- wb_mmio(ACT_ADDRESS_W, 0x20);
- c = rb_mmio(ACT_ADDRESS_RESET);
- udelay(10);
-
- /* general regs */
-
- printk("0x3cc(w 0x3c2) : 0x%2.2x\n", rb_mmio(0x3cc)); /* GREG_MISC_OUTPUT READ */
- printk("0x3c2(-------) : 0x%2.2x\n", rb_mmio(0x3c2)); /* GREG_INPUT_STATUS 0 READ */
- printk("0x3c3(w 0x3c3) : 0x%2.2x\n", rb_vgaio(0x3c3)); /* GREG_VIDEO_SUBS_ENABLE */
- printk("0x3ca(w 0x3da) : 0x%2.2x\n", rb_vgaio(0x3ca)); /* GREG_FEATURE_CONTROL read */
- printk("0x3da(-------) : 0x%2.2x\n", rb_mmio(0x3da)); /* GREG_INPUT_STATUS 1 READ */
-
- /* engine regs */
-
- for (i = 0x8180; i <= 0x8200; i = i + 4)
- printk("0x%8.8x : 0x%8.8x\n", i, rl_mmio(i));
-
- i = 0x8504;
- printk("0x%8.8x : 0x%8.8x\n", i, rl_mmio(i));
- i = 0x850c;
- printk("0x%8.8x : 0x%8.8x\n", i, rl_mmio(i));
- for (i = 0xa4d4; i <= 0xa50c; i = i + 4)
- printk("0x%8.8x : 0x%8.8x\n", i, rl_mmio(i));
-
- /* PCI regs */
-
- SelectCFG;
-
- for (c = 0; c < 0x08; c = c + 2) {
- w = (*((u16 *)((u32)(vgaio_regs + c + (on_zorro2 ? 0 : 0x000e0000)) ^ 2)));
- printk("pci 0x%2.2x : 0x%4.4x\n", c, w);
- }
- c = 8;
- l = (*((u32 *)((u32)(vgaio_regs + c + (on_zorro2 ? 0 : 0x000e0000)))));
- printk("pci 0x%2.2x : 0x%8.8x\n", c, l);
- c = 0x0d;
- b = (*((u8 *)((u32)(vgaio_regs + c + (on_zorro2 ? 0 : 0x000e0000)) ^ 3)));
- printk("pci 0x%2.2x : 0x%2.2x\n", c, b);
- c = 0x10;
- l = (*((u32 *)((u32)(vgaio_regs + c + (on_zorro2 ? 0 : 0x000e0000)))));
- printk("pci 0x%2.2x : 0x%8.8x\n", c, l);
- c = 0x30;
- l = (*((u32 *)((u32)(vgaio_regs + c + (on_zorro2 ? 0 : 0x000e0000)))));
- printk("pci 0x%2.2x : 0x%8.8x\n", c, l);
- c = 0x3c;
- b = (*((u8 *)((u32)(vgaio_regs + c + (on_zorro2 ? 0 : 0x000e0000)) ^ 3)));
- printk("pci 0x%2.2x : 0x%2.2x\n", c, b);
- c = 0x3d;
- b = (*((u8 *)((u32)(vgaio_regs + c + (on_zorro2 ? 0 : 0x000e0000)) ^ 3)));
- printk("pci 0x%2.2x : 0x%2.2x\n", c, b);
- c = 0x3e;
- w = (*((u16 *)((u32)(vgaio_regs + c + (on_zorro2 ? 0 : 0x000e0000)) ^ 2)));
- printk("pci 0x%2.2x : 0x%4.4x\n", c, w);
- SelectMMIO;
-}
-#endif
diff --git a/drivers/video/virgefb.h b/drivers/video/virgefb.h
deleted file mode 100644
index 157d66deb24..00000000000
--- a/drivers/video/virgefb.h
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- * linux/drivers/video/virgefb.h -- CyberVision64 definitions for the
- * text console driver.
- *
- * Copyright (c) 1998 Alan Bair
- *
- * This file is based on the initial port to Linux of grf_cvreg.h:
- *
- * Copyright (c) 1997 Antonio Santos
- *
- * The original work is from the NetBSD CyberVision 64 framebuffer driver
- * and support files (grf_cv.c, grf_cvreg.h, ite_cv.c):
- * Permission to use the source of this driver was obtained from the
- * author Michael Teske by Alan Bair.
- *
- * Copyright (c) 1995 Michael Teske
- *
- * History:
- *
- *
- *
- * 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.
- */
-
-/* Enhanced register mapping (MMIO mode) */
-
-#define S3_CRTC_ADR 0x03d4
-#define S3_CRTC_DATA 0x03d5
-
-#define S3_REG_LOCK2 0x39
-#define S3_HGC_MODE 0x45
-
-#define S3_HWGC_ORGX_H 0x46
-#define S3_HWGC_ORGX_L 0x47
-#define S3_HWGC_ORGY_H 0x48
-#define S3_HWGC_ORGY_L 0x49
-#define S3_HWGC_DX 0x4e
-#define S3_HWGC_DY 0x4f
-
-#define S3_LAW_CTL 0x58
-
-/**************************************************/
-
-/*
- * Defines for the used register addresses (mw)
- *
- * NOTE: There are some registers that have different addresses when
- * in mono or color mode. We only support color mode, and thus
- * some addresses won't work in mono-mode!
- *
- * General and VGA-registers taken from retina driver. Fixed a few
- * bugs in it. (SR and GR read address is Port + 1, NOT Port)
- *
- */
-
-/* General Registers: */
-#define GREG_MISC_OUTPUT_R 0x03CC
-#define GREG_MISC_OUTPUT_W 0x03C2
-#define GREG_FEATURE_CONTROL_R 0x03CA
-#define GREG_FEATURE_CONTROL_W 0x03DA
-#define GREG_INPUT_STATUS0_R 0x03C2
-#define GREG_INPUT_STATUS1_R 0x03DA
-
-/* Setup Registers: */
-#define SREG_VIDEO_SUBS_ENABLE 0x03C3 /* virge */
-
-/* Attribute Controller: */
-#define ACT_ADDRESS 0x03C0
-#define ACT_ADDRESS_R 0x03C1
-#define ACT_ADDRESS_W 0x03C0
-#define ACT_ADDRESS_RESET 0x03DA
-#define ACT_ID_PALETTE0 0x00
-#define ACT_ID_PALETTE1 0x01
-#define ACT_ID_PALETTE2 0x02
-#define ACT_ID_PALETTE3 0x03
-#define ACT_ID_PALETTE4 0x04
-#define ACT_ID_PALETTE5 0x05
-#define ACT_ID_PALETTE6 0x06
-#define ACT_ID_PALETTE7 0x07
-#define ACT_ID_PALETTE8 0x08
-#define ACT_ID_PALETTE9 0x09
-#define ACT_ID_PALETTE10 0x0A
-#define ACT_ID_PALETTE11 0x0B
-#define ACT_ID_PALETTE12 0x0C
-#define ACT_ID_PALETTE13 0x0D
-#define ACT_ID_PALETTE14 0x0E
-#define ACT_ID_PALETTE15 0x0F
-#define ACT_ID_ATTR_MODE_CNTL 0x10
-#define ACT_ID_OVERSCAN_COLOR 0x11
-#define ACT_ID_COLOR_PLANE_ENA 0x12
-#define ACT_ID_HOR_PEL_PANNING 0x13
-#define ACT_ID_COLOR_SELECT 0x14 /* virge PX_PADD pixel padding register */
-
-/* Graphics Controller: */
-#define GCT_ADDRESS 0x03CE
-#define GCT_ADDRESS_R 0x03CF
-#define GCT_ADDRESS_W 0x03CF
-#define GCT_ID_SET_RESET 0x00
-#define GCT_ID_ENABLE_SET_RESET 0x01
-#define GCT_ID_COLOR_COMPARE 0x02
-#define GCT_ID_DATA_ROTATE 0x03
-#define GCT_ID_READ_MAP_SELECT 0x04
-#define GCT_ID_GRAPHICS_MODE 0x05
-#define GCT_ID_MISC 0x06
-#define GCT_ID_COLOR_XCARE 0x07
-#define GCT_ID_BITMASK 0x08
-
-/* Sequencer: */
-#define SEQ_ADDRESS 0x03C4
-#define SEQ_ADDRESS_R 0x03C5
-#define SEQ_ADDRESS_W 0x03C5
-#define SEQ_ID_RESET 0x00
-#define SEQ_ID_CLOCKING_MODE 0x01
-#define SEQ_ID_MAP_MASK 0x02
-#define SEQ_ID_CHAR_MAP_SELECT 0x03
-#define SEQ_ID_MEMORY_MODE 0x04
-#define SEQ_ID_UNKNOWN1 0x05
-#define SEQ_ID_UNKNOWN2 0x06
-#define SEQ_ID_UNKNOWN3 0x07
-/* S3 extensions */
-#define SEQ_ID_UNLOCK_EXT 0x08
-#define SEQ_ID_EXT_SEQ_REG9 0x09 /* b7 = 1 extended reg access by MMIO only */
-#define SEQ_ID_BUS_REQ_CNTL 0x0A
-#define SEQ_ID_EXT_MISC_SEQ 0x0B
-#define SEQ_ID_UNKNOWN4 0x0C
-#define SEQ_ID_EXT_SEQ 0x0D
-#define SEQ_ID_UNKNOWN5 0x0E
-#define SEQ_ID_UNKNOWN6 0x0F
-#define SEQ_ID_MCLK_LO 0x10
-#define SEQ_ID_MCLK_HI 0x11
-#define SEQ_ID_DCLK_LO 0x12
-#define SEQ_ID_DCLK_HI 0x13
-#define SEQ_ID_CLKSYN_CNTL_1 0x14
-#define SEQ_ID_CLKSYN_CNTL_2 0x15
-#define SEQ_ID_CLKSYN_TEST_HI 0x16 /* reserved for S3 testing of the */
-#define SEQ_ID_CLKSYN_TEST_LO 0x17 /* internal clock synthesizer */
-#define SEQ_ID_RAMDAC_CNTL 0x18
-#define SEQ_ID_MORE_MAGIC 0x1A
-#define SEQ_ID_SIGNAL_SELECT 0x1C /* new for virge */
-
-/* CRT Controller: */
-#define CRT_ADDRESS 0x03D4
-#define CRT_ADDRESS_R 0x03D5
-#define CRT_ADDRESS_W 0x03D5
-#define CRT_ID_HOR_TOTAL 0x00
-#define CRT_ID_HOR_DISP_ENA_END 0x01
-#define CRT_ID_START_HOR_BLANK 0x02
-#define CRT_ID_END_HOR_BLANK 0x03
-#define CRT_ID_START_HOR_RETR 0x04
-#define CRT_ID_END_HOR_RETR 0x05
-#define CRT_ID_VER_TOTAL 0x06
-#define CRT_ID_OVERFLOW 0x07
-#define CRT_ID_PRESET_ROW_SCAN 0x08
-#define CRT_ID_MAX_SCAN_LINE 0x09
-#define CRT_ID_CURSOR_START 0x0A
-#define CRT_ID_CURSOR_END 0x0B
-#define CRT_ID_START_ADDR_HIGH 0x0C
-#define CRT_ID_START_ADDR_LOW 0x0D
-#define CRT_ID_CURSOR_LOC_HIGH 0x0E
-#define CRT_ID_CURSOR_LOC_LOW 0x0F
-#define CRT_ID_START_VER_RETR 0x10
-#define CRT_ID_END_VER_RETR 0x11
-#define CRT_ID_VER_DISP_ENA_END 0x12
-#define CRT_ID_SCREEN_OFFSET 0x13
-#define CRT_ID_UNDERLINE_LOC 0x14
-#define CRT_ID_START_VER_BLANK 0x15
-#define CRT_ID_END_VER_BLANK 0x16
-#define CRT_ID_MODE_CONTROL 0x17
-#define CRT_ID_LINE_COMPARE 0x18
-#define CRT_ID_GD_LATCH_RBACK 0x22
-#define CRT_ID_ACT_TOGGLE_RBACK 0x24
-#define CRT_ID_ACT_INDEX_RBACK 0x26
-/* S3 extensions: S3 VGA Registers */
-#define CRT_ID_DEVICE_HIGH 0x2D
-#define CRT_ID_DEVICE_LOW 0x2E
-#define CRT_ID_REVISION 0x2F
-#define CRT_ID_CHIP_ID_REV 0x30
-#define CRT_ID_MEMORY_CONF 0x31
-#define CRT_ID_BACKWAD_COMP_1 0x32
-#define CRT_ID_BACKWAD_COMP_2 0x33
-#define CRT_ID_BACKWAD_COMP_3 0x34
-#define CRT_ID_REGISTER_LOCK 0x35
-#define CRT_ID_CONFIG_1 0x36
-#define CRT_ID_CONFIG_2 0x37
-#define CRT_ID_REGISTER_LOCK_1 0x38
-#define CRT_ID_REGISTER_LOCK_2 0x39
-#define CRT_ID_MISC_1 0x3A
-#define CRT_ID_DISPLAY_FIFO 0x3B
-#define CRT_ID_LACE_RETR_START 0x3C
-/* S3 extensions: System Control Registers */
-#define CRT_ID_SYSTEM_CONFIG 0x40
-#define CRT_ID_BIOS_FLAG 0x41
-#define CRT_ID_LACE_CONTROL 0x42
-#define CRT_ID_EXT_MODE 0x43
-#define CRT_ID_HWGC_MODE 0x45 /* HWGC = Hardware Graphics Cursor */
-#define CRT_ID_HWGC_ORIGIN_X_HI 0x46
-#define CRT_ID_HWGC_ORIGIN_X_LO 0x47
-#define CRT_ID_HWGC_ORIGIN_Y_HI 0x48
-#define CRT_ID_HWGC_ORIGIN_Y_LO 0x49
-#define CRT_ID_HWGC_FG_STACK 0x4A
-#define CRT_ID_HWGC_BG_STACK 0x4B
-#define CRT_ID_HWGC_START_AD_HI 0x4C
-#define CRT_ID_HWGC_START_AD_LO 0x4D
-#define CRT_ID_HWGC_DSTART_X 0x4E
-#define CRT_ID_HWGC_DSTART_Y 0x4F
-/* S3 extensions: System Extension Registers */
-#define CRT_ID_EXT_SYS_CNTL_1 0x50 /* NOT a virge register */
-#define CRT_ID_EXT_SYS_CNTL_2 0x51
-#define CRT_ID_EXT_BIOS_FLAG_1 0x52
-#define CRT_ID_EXT_MEM_CNTL_1 0x53
-#define CRT_ID_EXT_MEM_CNTL_2 0x54
-#define CRT_ID_EXT_DAC_CNTL 0x55
-#define CRT_ID_EX_SYNC_1 0x56
-#define CRT_ID_EX_SYNC_2 0x57
-#define CRT_ID_LAW_CNTL 0x58 /* LAW = Linear Address Window */
-#define CRT_ID_LAW_POS_HI 0x59
-#define CRT_ID_LAW_POS_LO 0x5A
-#define CRT_ID_GOUT_PORT 0x5C
-#define CRT_ID_EXT_HOR_OVF 0x5D
-#define CRT_ID_EXT_VER_OVF 0x5E
-#define CRT_ID_EXT_MEM_CNTL_3 0x60 /* NOT a virge register */
-#define CRT_ID_EXT_MEM_CNTL_4 0x61
-#define CRT_ID_EX_SYNC_3 0x63 /* NOT a virge register */
-#define CRT_ID_EXT_MISC_CNTL 0x65
-#define CRT_ID_EXT_MISC_CNTL_1 0x66
-#define CRT_ID_EXT_MISC_CNTL_2 0x67
-#define CRT_ID_CONFIG_3 0x68
-#define CRT_ID_EXT_SYS_CNTL_3 0x69
-#define CRT_ID_EXT_SYS_CNTL_4 0x6A
-#define CRT_ID_EXT_BIOS_FLAG_3 0x6B
-#define CRT_ID_EXT_BIOS_FLAG_4 0x6C
-/* S3 virge extensions: more System Extension Registers */
-#define CRT_ID_EXT_BIOS_FLAG_5 0x6D
-#define CRT_ID_EXT_DAC_TEST 0x6E
-#define CRT_ID_CONFIG_4 0x6F
-
-/* Video DAC */
-#define VDAC_ADDRESS 0x03c8
-#define VDAC_ADDRESS_W 0x03c8
-#define VDAC_ADDRESS_R 0x03c7
-#define VDAC_STATE 0x03c7
-#define VDAC_DATA 0x03c9
-#define VDAC_MASK 0x03c6
-
-/* Miscellaneous Registers */
-#define MR_SUBSYSTEM_STATUS_R 0x8504 /* new for virge */
-#define MR_SUBSYSTEM_CNTL_W 0x8504 /* new for virge */
-#define MR_ADVANCED_FUNCTION_CONTROL 0x850C /* new for virge */
-
-/* Blitter */
-#define BLT_COMMAND_SET 0xA500
-#define BLT_SIZE_X_Y 0xA504
-#define BLT_SRC_X_Y 0xA508
-#define BLT_DEST_X_Y 0xA50C
-
-#define BLT_SRC_BASE 0xa4d4
-#define BLT_DEST_BASE 0xa4d8
-#define BLT_CLIP_LEFT_RIGHT 0xa4dc
-#define BLT_CLIP_TOP_BOTTOM 0xa4e0
-#define BLT_SRC_DEST_STRIDE 0xa4e4
-#define BLT_MONO_PATTERN_0 0xa4e8
-#define BLT_MONO_PATTERN_1 0xa4ec
-#define BLT_PATTERN_COLOR 0xa4f4
-
-#define L2D_COMMAND_SET 0xA900
-#define L2D_CLIP_LEFT_RIGHT 0xA8DC
-#define L2D_CLIP_TOP_BOTTOM 0xA8E0
-
-#define P2D_COMMAND_SET 0xAD00
-#define P2D_CLIP_LEFT_RIGHT 0xACDC
-#define P2D_CLIP_TOP_BOTTOM 0xACE0
-
-#define CMD_NOP (0xf << 27) /* %1111 << 27, was 0x07 */
-#define S3V_BITBLT (0x0 << 27)
-#define S3V_RECTFILL (0x2 << 27)
-#define S3V_AUTOEXE 0x01
-#define S3V_HWCLIP 0x02
-#define S3V_DRAW 0x20
-#define S3V_DST_8BPP 0x00
-#define S3V_DST_16BPP 0x04
-#define S3V_DST_24BPP 0x08
-#define S3V_MONO_PAT 0x100
-
-#define S3V_BLT_COPY (0xcc<<17)
-#define S3V_BLT_CLEAR (0x00<<17)
-#define S3V_BLT_SET (0xff<<17)
diff --git a/drivers/w1/slaves/w1_therm.c b/drivers/w1/slaves/w1_therm.c
index b022fffd8c5..732db478004 100644
--- a/drivers/w1/slaves/w1_therm.c
+++ b/drivers/w1/slaves/w1_therm.c
@@ -141,7 +141,7 @@ static inline int w1_convert_temp(u8 rom[9], u8 fid)
{
int i;
- for (i=0; i<sizeof(w1_therm_families)/sizeof(w1_therm_families[0]); ++i)
+ for (i = 0; i < ARRAY_SIZE(w1_therm_families); ++i)
if (w1_therm_families[i].f->fid == fid)
return w1_therm_families[i].convert(rom);
@@ -238,7 +238,7 @@ static int __init w1_therm_init(void)
{
int err, i;
- for (i=0; i<sizeof(w1_therm_families)/sizeof(w1_therm_families[0]); ++i) {
+ for (i = 0; i < ARRAY_SIZE(w1_therm_families); ++i) {
err = w1_register_family(w1_therm_families[i].f);
if (err)
w1_therm_families[i].broken = 1;
@@ -251,7 +251,7 @@ static void __exit w1_therm_fini(void)
{
int i;
- for (i=0; i<sizeof(w1_therm_families)/sizeof(w1_therm_families[0]); ++i)
+ for (i = 0; i < ARRAY_SIZE(w1_therm_families); ++i)
if (!w1_therm_families[i].broken)
w1_unregister_family(w1_therm_families[i].f);
}
diff --git a/drivers/zorro/proc.c b/drivers/zorro/proc.c
index 60b05bc1564..b3ce8859a58 100644
--- a/drivers/zorro/proc.c
+++ b/drivers/zorro/proc.c
@@ -75,7 +75,7 @@ proc_bus_zorro_read(struct file *file, char __user *buf, size_t nbytes, loff_t *
return nbytes;
}
-static struct file_operations proc_bus_zorro_operations = {
+static const struct file_operations proc_bus_zorro_operations = {
.llseek = proc_bus_zorro_lseek,
.read = proc_bus_zorro_read,
};